Skip to content

Commit

Permalink
Improve the single stepper
Browse files Browse the repository at this point in the history
- Add dump function to the single stepper
- Improve the instruction print function

Still need to make the pipeline registers print nicely

Closes #107
Closes #59

Signed-off-by: Jason Lowe-Power <jason@lowepower.com>
  • Loading branch information
powerjg committed Jan 3, 2020
1 parent 7de3ad5 commit 8965399
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 35 deletions.
31 changes: 31 additions & 0 deletions src/main/scala/pipelined/cpu.scala
Original file line number Diff line number Diff line change
Expand Up @@ -390,3 +390,34 @@ class PipelinedCPU(implicit val conf: CPUConfig) extends BaseCPU {

if (conf.debug) { printf("---------------------------------------------\n") }
}

/*
* Object to make it easier to print information about the CPU
*/
object PipelinedCPUInfo {
def getModules(): List[String] = {
List(
"control",
"branchCtrl",
"registers",
"aluControl",
"alu",
"immGen",
"pcPlusFour",
"branchAdd",
"forwarding",
"hazard",
)
}
def getPipelineRegs(): List[String] = {
List(
"if_id",
"id_ex",
"id_ex_ctrl",
"ex_mem",
"ex_mem_ctrl",
"mem_wb",
"mem_wb_ctrl"
)
}
}
42 changes: 19 additions & 23 deletions src/main/scala/single-cycle/cpu.scala
Original file line number Diff line number Diff line change
Expand Up @@ -119,28 +119,24 @@ class SingleCycleCPU(implicit val conf: CPUConfig) extends BaseCPU {
next_pc := pcPlusFour.io.result
}

// Debug / pipeline viewer
val structures = List(
(control, "control"),
(registers, "registers"),
(csr, "csr"),
(aluControl, "aluControl"),
(alu, "alu"),
(immGen, "immGen"),
(branchCtrl, "branchCtrl"),
(pcPlusFour, "pcPlusFour"),
(branchAdd, "branchAdd")
)

if (conf.debug) {
printf("DASM(%x)\n", instruction)
printf(p"CYCLE=$cycleCount\n")
printf(p"pc: $pc\n")
for (structure <- structures) {
printf(p"${structure._2}: ${structure._1.io}\n")
}
printf("\n")
}

pc := next_pc
}

/*
* Object to make it easier to print information about the CPU
*/
object SingleCycleCPUInfo {
def getModules(): List[String] = {
List(
"control",
"registers",
"csr",
"aluControl",
"alu",
"immGen",
"branchCtrl",
"pcPlusFour",
"branchAdd"
)
}
}
67 changes: 59 additions & 8 deletions src/main/scala/singlestep.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,31 @@ object singlestep {
val helptext = "usage: singlestep <test name> <CPU type>"

val commands = """Help for the single stepper:
| Note: Registers print the value *stored* in that register. The wires print
| the *current* value on the wire for that cycle.
|
| Printing registers
| ------------------
| print reg <num> : print the value in register
| print regs : print values in all registers
| print pc : print the address in the pc
| print inst [addr]: print the disassembly for the instruction at addr.
| If no addr provided then use the current pc.
|
| Printing module I/O (wires)
| ---------------------------
| dump all : Show all modules and the values of their I/O
| dump list : List the valid modules to dump
| dump [module] : Show values of the I/O on a specific module
|
| Controlling the simulator
| -------------------------
| step [num] : move forward this many cycles, default 1
|
| Other commands
| --------------
| ? : print this help
| print reg <num> : print the value in register
| print regs : print values in all registers
| print pc : print the address in the pc
| print inst : print the disassembly for the current instruction
| q : quit
| step [num] : move forward this many cycles, default 1
|""".stripMargin

def doPrint(tokens: Array[String], driver: CPUTesterDriver): Boolean = {
Expand All @@ -41,13 +59,41 @@ object singlestep {
true
}
case "inst" => {
driver.printInst()
true
if (tokens.length == 2) {
driver.printInst()
true
} else if (tokens.length == 3) {
try {
driver.printInst(tokens(2).toInt)
true
} catch {
case e: NumberFormatException => false
}
} else {
false
}
}
case _ => false
}
}

def doDump(tokens: Array[String], driver: CPUTesterDriver): Boolean = {
tokens(1) match {
case "all" => {
driver.dumpAllModules()
true
}
case "list" => {
driver.listModules()
true
}
case _ => {
driver.dumpModule(tokens(1))
true
}
}
}

def doStep(tokens: Array[String], driver: CPUTesterDriver): Boolean = {
val cycles = try {
if (tokens.length == 2) tokens(1).toInt else 1
Expand Down Expand Up @@ -84,7 +130,7 @@ object singlestep {
println(commands)
var done = false
while (!done) {
val tokens = scala.io.StdIn.readLine("Single stepper > ").split(" ")
val tokens = scala.io.StdIn.readLine("Single stepper> ").split(" ")
if (tokens.length > 0) {
tokens(0) match {
case "?" => println(commands)
Expand All @@ -95,6 +141,11 @@ object singlestep {
if (!doPrint(tokens, driver)) println(commands)
}
}
case "dump" => {
if (tokens.length > 1) {
if (!doDump(tokens, driver)) println(commands)
}
}
case _ => println(commands)
}
}
Expand Down
65 changes: 61 additions & 4 deletions src/main/scala/testing/CPUTesterDriver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package dinocpu.test

import dinocpu._
import dinocpu.pipelined._
import dinocpu.simulate.{build, elfToHex}
import org.scalatest.{FlatSpec, Matchers}
import treadle.TreadleTester
Expand Down Expand Up @@ -88,14 +89,69 @@ class CPUTesterDriver(cpuType: String,
println(s"PC: ${v}")
}

def printInst(): Unit = {
val v = simulator.peek("cpu.io_imem_instruction")
val pc = simulator.peek("cpu.pc")
def printInst(addr: Int = -1): Unit = {
val pc = if (addr < 0) simulator.peek("cpu.pc").toInt else addr
val v = simulator.peekMemory("mem.memory", pc/4)
// Note: the memory is a 32-bit memory
val inst = Disassembler.disassemble(v.longValue())
println(s"${pc.toString().padTo(8, ' ')}: ${inst.padTo(20, ' ')} (0x${v.toInt.toHexString})")
val hex = v.toInt.toHexString.reverse.padTo(8, '0').reverse
println(s"${pc.toString().padTo(8, ' ')}: ${inst.padTo(20, ' ')} (0x${hex})")
}

def dumpAllModules(): Unit = {
val modules = conf.cpuType match {
case "single-cycle" => SingleCycleCPUInfo.getModules()
case "pipelined" => PipelinedCPUInfo.getModules()
case other => {
println(s"Cannot dump info for CPU type ${other}")
List()
}
}
for (name <- modules) {
for ((symbol, name) <- getIO(name)) {
val v = simulator.peek(symbol)
println(s"${name.padTo(30, ' ')} ${v} (0x${v.toInt.toHexString})")
}
}
}

def listModules(): Unit = {
val modules = conf.cpuType match {
case "single-cycle" => SingleCycleCPUInfo.getModules()
case "pipelined" => PipelinedCPUInfo.getModules()
case other => {
println(s"Cannot dump info for CPU type ${other}")
List()
}
}
println("Available modules to dump I/O")
println("-----------------------------")
for (name <- modules) {
println(s"${name}")
}
}

def dumpModule(module: String): Unit = {
val modules: List[String] = conf.cpuType match {
case "single-cycle" => SingleCycleCPUInfo.getModules()
case "pipelined" => PipelinedCPUInfo.getModules()
case other => {
println(s"Cannot dump info for CPU type ${other}")
List()
}
}
for ((symbol, name) <- getIO(module)) {
val v = simulator.peek(symbol)
println(s"${name.padTo(30, ' ')} ${v} (0x${v.toInt.toHexString})")
}
}

def getIO(module: String): Map[String,String] = {
val syms = simulator.engine.validNames.filter(name => name startsWith s"cpu.${module}.io_")
syms map {
sym => sym -> s"${module}.io.${sym.substring(sym.indexOf('_') + 1)}"
} toMap
}

/**
*
Expand Down Expand Up @@ -147,6 +203,7 @@ class CPUTesterDriver(cpuType: String,
simulator.step(1)
cycle += 1
}
println(s"Current cycle: ${cycle}")
}

def run(cycles: Int): Unit = {
Expand Down

0 comments on commit 8965399

Please sign in to comment.