Created
April 13, 2017 08:52
-
-
Save lihaoyi/7895ee1bb0850d6a64e1d18b3f61a986 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package hello | |
import java.io.ByteArrayOutputStream | |
import chisel3._ | |
import chisel3.iotesters.{Driver, PeekPokeTester} | |
sealed trait Op | |
object Op{ | |
case class GotoIfZero(dest: Byte, valueAddr: Byte) extends Op | |
case class Set(dest: Byte, value: Byte) extends Op | |
case class Add(src1: Byte, src2: Byte, dest: Byte) extends Op | |
case class Sub(src1: Byte, src2: Byte, dest: Byte) extends Op | |
case class Mul(src1: Byte, src2: Byte, dest: Byte) extends Op | |
case class Div(src1: Byte, src2: Byte, dest: Byte) extends Op | |
case class Mod(src1: Byte, src2: Byte, dest: Byte) extends Op | |
case class Ret(valueAddr: Byte) extends Op | |
def serialize(instructions: Seq[Op]) = { | |
val output = new ByteArrayOutputStream() | |
def write(out: Byte*) = { | |
out.foreach(output.write(_)) | |
} | |
instructions.foreach{ | |
case GotoIfZero(dest, valueAddr) => write(0, dest, valueAddr, 0) | |
case Set(dest, value: Byte) => write(1, dest, value, 0) | |
case Add(src1, src2, dest) => write(2, src1, src2, dest) | |
case Sub(src1, src2, dest) => write(3, src1, src2, dest) | |
case Mul(src1, src2, dest) => write(4, src1, src2, dest) | |
case Div(src1, src2, dest) => write(5, src1, src2, dest) | |
case Mod(src1, src2, dest) => write(6, src1, src2, dest) | |
case Ret(valueAddr) => write(7, valueAddr, 0, 0) | |
} | |
output.toByteArray | |
} | |
} | |
class CPU extends Module { | |
val io = IO(new Bundle { | |
val out = Output(UInt(8.W)) | |
val done = Output(Bool()) | |
val mode = Input(Bool()) | |
val in = Input(UInt(8.W)) | |
// val instructionCounter = Output(UInt(8.W)) | |
// val instructions = Output(Vec(Seq.fill(64) { 0.U(8.W) })) | |
// val memory = Output(Vec(Seq.fill(8) { 0.U(8.W) })) | |
// val dbg = Output(UInt(8.W)) | |
}) | |
val instrs = Reg(init = Vec(Seq.fill(64) { 0.U(8.W) })) | |
val memory = Reg(init = Vec(Seq.fill(8) { 0.U(8.W) })) | |
val PC = RegInit(UInt(8.W), 0.U) | |
val previousMode = RegInit(Bool(), 0.U) | |
val done = RegInit(Bool(), 0.U) | |
val result = RegInit(UInt(8.W), 0.U) | |
// io.instructionCounter := PC | |
// io.memory:= memory | |
io.out := result | |
// io.instructions := instrs | |
io.done := done | |
// io.dbg := instrs(PC + 1.U) | |
when(previousMode =/= io.mode){ | |
PC := 0.U | |
previousMode := io.mode | |
}.otherwise{ | |
previousMode := io.mode | |
when(io.mode === 0.U) { | |
instrs(PC) := io.in | |
PC := PC + 1.U | |
}.otherwise{ | |
PC := PC + 4.U | |
when (instrs(PC) === 0.U){ | |
when(memory(instrs(PC + 2.U)) === 0.U) { | |
PC := instrs(PC + 1.U) * 4.U | |
} | |
}.elsewhen(instrs(PC) === 1.U){ | |
memory(instrs(PC + 1.U)) := instrs(PC + 2.U) | |
}.elsewhen(instrs(PC) === 2.U){ | |
memory(instrs(PC + 3.U)) := memory(instrs(PC + 1.U)) + memory(instrs(PC + 2.U)) | |
}.elsewhen(instrs(PC) === 3.U){ | |
memory(instrs(PC + 3.U)) := memory(instrs(PC + 1.U)) - memory(instrs(PC + 2.U)) | |
}.elsewhen(instrs(PC) === 4.U){ | |
memory(instrs(PC + 3.U)) := memory(instrs(PC + 1.U)) * memory(instrs(PC + 2.U)) | |
}.elsewhen(instrs(PC) === 5.U){ | |
memory(instrs(PC + 3.U)) := memory(instrs(PC + 1.U)) / memory(instrs(PC + 2.U)) | |
}.elsewhen(instrs(PC) === 6.U){ | |
memory(instrs(PC + 3.U)) := memory(instrs(PC + 1.U)) % memory(instrs(PC + 2.U)) | |
}.elsewhen(instrs(PC) === 7.U){ | |
done := 1.U | |
result := memory(instrs(PC+1.U)) | |
} | |
} | |
} | |
} | |
class CPUTests(c: CPU | |
) extends PeekPokeTester(c) { | |
import c.io._ | |
poke(mode, 0) | |
val instructions = Seq( | |
/* 0 */ Op.Set(0, 0), | |
/* 1 */ Op.Set(1, 1), | |
/* 2 */ Op.Set(2, 23), // number i want to test if prime | |
/* 3 */ Op.Set(3, 1), // Counter at RAM index 3 | |
/* 4 */ Op.Add(1, 3, 3), | |
/* 5 */ Op.Sub(2, 3, 4), | |
/* 6 */ Op.GotoIfZero(11, 4), // prime | |
/* 7 */ Op.Mod(2, 3, 4), | |
/* 8 */ Op.GotoIfZero(10, 4), // non-prime | |
/* 9 */ Op.GotoIfZero(4, 0), // loop around | |
/* 10 */ Op.Ret(0), | |
/* 11 */ Op.Ret(1) | |
) | |
val bytes = Op.serialize(instructions) | |
for(byte <- bytes){ | |
poke(in, byte) | |
step(1) | |
} | |
// expect(instructionCounter, instructions.length * 4) | |
// peek(c.io.instructions).grouped(4).foreach(x => println(x.toString)) | |
poke(mode, 1) | |
var count = 0 | |
while(peek(done) != 1 && count < 1000){ | |
count += 1 | |
println(count.toString) | |
step(1) | |
// println() | |
// println("PC " + peek(instructionCounter) / 4) | |
// println("Memory " + peek(memory)) | |
// println("Done " + peek(done)) | |
// println("Instr " + peek(c.io.instructions).drop(peek(instructionCounter).toInt).take(4)) | |
} | |
println("is prime " + peek(out)) | |
} | |
object CPU { | |
def main(args: Array[String]): Unit = { | |
if (!Driver(() => new CPU(), backendType = "verilator")(c => | |
new CPUTests(c))) System.exit(1 | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment