From ef98af5257684e5de1027767f24b88f6978ab537 Mon Sep 17 00:00:00 2001 From: Meng Zhang Date: Mon, 15 May 2017 10:59:29 +0800 Subject: [PATCH] MultiCycle Top.scala, ALU.scala TopTests and launcher added --- run-multi.bak.v.sh | 3 + run-multi.sh | 9 +++ run-bak.v.sh => run-single.bak.v.sh | 0 src/main/scala/MultiCycle/ALU.scala | 80 +++++++++++++++++++++ src/main/scala/MultiCycle/Top.scala | 84 +++++++++++++++++++++++ src/test/scala/MultiCycle/Launcher.scala | 52 ++++++++++++++ src/test/scala/MultiCycle/TopTests.scala | 70 +++++++++++++++++++ src/test/scala/SingleCycle/TopTests.scala | 2 +- 8 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 run-multi.bak.v.sh create mode 100755 run-multi.sh rename run-bak.v.sh => run-single.bak.v.sh (100%) create mode 100644 src/main/scala/MultiCycle/ALU.scala create mode 100644 src/main/scala/MultiCycle/Top.scala create mode 100644 src/test/scala/MultiCycle/Launcher.scala create mode 100644 src/test/scala/MultiCycle/TopTests.scala diff --git a/run-multi.bak.v.sh b/run-multi.bak.v.sh new file mode 100644 index 0000000..9e0f705 --- /dev/null +++ b/run-multi.bak.v.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +TESTER_BACKENDS=verilator sbt "test:run-main MultiCycle.Launcher $1" diff --git a/run-multi.sh b/run-multi.sh new file mode 100755 index 0000000..f350113 --- /dev/null +++ b/run-multi.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +# Please run ./run-multi.sh Top or ./run-multi.sh ALU +# DO NOT run ./run-multi.sh, which will test Top and ALU both. + +# Add several blank lines +echo -e "\n\n\n\n\n\n\n\n" + +sbt "test:run-main MultiCycle.Launcher $1" diff --git a/run-bak.v.sh b/run-single.bak.v.sh similarity index 100% rename from run-bak.v.sh rename to run-single.bak.v.sh diff --git a/src/main/scala/MultiCycle/ALU.scala b/src/main/scala/MultiCycle/ALU.scala new file mode 100644 index 0000000..b3e6bbf --- /dev/null +++ b/src/main/scala/MultiCycle/ALU.scala @@ -0,0 +1,80 @@ +//************************************************************************** +//-------------------------------------------------------------------------- +// ercesiMIPS Multi Cycle Processor ALU for 9 instructions +// +// Meng Zhang +// version 0.1 +//-------------------------------------------------------------------------- +//************************************************************************** + +package MultiCycle + +import chisel3._ + + +// For our first sample ALU with 9 Insts +// The supported instruction is following: +// ADD 000000 sssss ttttt ddddd 00000 100000 //R type (signed) +// SUB 000000 sssss ttttt ddddd 00000 100010 //R type (signed) +// OR 000000 sssss ttttt ddddd 00000 100101 //R type (unsigned) +// AND 000000 sssss ttttt ddddd 00000 100100 //R type (unsigned) +// ORI 001101 sssss ttttt iiiii iiiii iiiiii //I type (unsigned) +// ANDI 001100 sssss ttttt iiiii iiiii iiiiii //I type (unsigned) +// LW 100011 sssss ttttt iiiii iiiii iiiiii //I type (signed imm) +// SW 101011 sssss ttttt iiiii iiiii iiiiii //I type (signed imm) +// BEQ 000100 sssss ttttt iiiii iiiii iiiiii //I type (signed imm) +// SLT 000000 sssss ttttt ddddd 00000 101010 //R type (signed) +// JUMP 000010 iiiii iiiii iiiii iiiii iiiiii //J type (signed imm) +// Although 11 instruction implmented in this class, only +// SUB, ADD, AND, OR, and SLT, BEQ in ALU operations +//---------------------------------------------------// + +object ALU +{ + def FN_AND = 0.U(3.W) //0000 + def FN_OR = 1.U(3.W) //0001 + def FN_ADD = 2.U(3.W) //0010 + def FN_SUB = 6.U(3.W) //0110 + def FN_SLT = 7.U(3.W) //0111 + + def FN_BEQ = FN_SUB //0111 + + def isSub(cmd: UInt) = (cmd === FN_SUB) || (cmd === FN_SLT) +} + +import ALU._ + +class ALU extends Module{ + val io = IO(new Bundle{ + val in1 = Input(UInt(32.W)) + val in2 = Input(UInt(32.W)) + val ALUctr = Input(UInt(3.W)) + val ALUout = Output(UInt(32.W)) + val cmp_out = Output(Bool()) + }) + + //val SIntA = SInt(32.W) + //val SIntB = SInt(32.W) + + // ADD, SUB + val in2_inv = Mux(isSub(io.ALUctr), ~io.in2, io.in2) + val in1_xor_in2 = io.in1 ^ io.in2 + val adder_out = io.in1 + in2_inv + isSub(io.ALUctr) + + // SLT and BEQ comparation Output + // For BEQ, cmp_out = (in1_xor_in2 === 0.U) + // For SLT, cmp_out = adder_out(31) if io.in1(31) != io.in2(31) + // Otherwise, cmp_out = adder_out(31) + io.cmp_out := Mux(io.ALUctr === FN_BEQ, in1_xor_in2 === 0.U, + Mux(io.in1(31) != io.in2(31), adder_out(31), + Mux(adder_out(31), true.B, false.B))) + + // AND, OR, however this can also output XOR + val logic_out = Mux(io.ALUctr === FN_OR, in1_xor_in2, 0.U) | + Mux(io.ALUctr === FN_OR || io.ALUctr === FN_AND, io.in1 & io.in2, 0.U) + + val out = Mux(io.ALUctr === FN_ADD || io.ALUctr === FN_SUB, + adder_out, logic_out) + + io.ALUout := out +} diff --git a/src/main/scala/MultiCycle/Top.scala b/src/main/scala/MultiCycle/Top.scala new file mode 100644 index 0000000..5396a9a --- /dev/null +++ b/src/main/scala/MultiCycle/Top.scala @@ -0,0 +1,84 @@ +//************************************************************************** +//-------------------------------------------------------------------------- +// ercesiMIPS Multi Cycle Processor Top +// +// Meng zhang +// version 0.1 +//-------------------------------------------------------------------------- +//************************************************************************** + +package MultiCycle + +import chisel3._ +import chisel3.iotesters.Driver +//import utils.ercesiMIPSRunner +class TopIO extends Bundle() { + val boot = Input(Bool()) +// imem and dmem interface for Tests + val test_im_wr = Input(Bool()) + val test_im_rd = Input(Bool()) + val test_im_addr = Input(UInt(32.W)) + val test_im_in = Input(UInt(32.W)) + val test_im_out = Output(UInt(32.W)) + + val test_dm_wr = Input(Bool()) + val test_dm_rd = Input(Bool()) + val test_dm_addr = Input(UInt(32.W)) + val test_dm_in = Input(UInt(32.W)) + val test_dm_out = Output(UInt(32.W)) + + val valid = Output(Bool()) +} + +class Top extends Module() { + val io = IO(new TopIO())//in chisel3, io must be wrapped in IO(...) + val cpath = Module(new CtlPath()) + val dpath = Module(new DatPath()) + + cpath.io.ctl <> dpath.io.ctl + cpath.io.dat <> dpath.io.dat + io.valid := cpath.io.valid + cpath.io.boot := io.boot + + val imm = Mem(256, UInt(32.W)) + val dmm = Mem(1024, UInt(32.W)) + io.test_dm_out := 0.U + io.test_im_out := 0.U + cpath.io.Inst := 0.U + when (io.boot && io.test_im_wr){ + imm(io.test_im_addr >> 2) := io.test_im_in + cpath.io.Inst := 0.U + } + when (io.boot && io.test_dm_wr){ + dmm(io.test_dm_addr >> 2) := io.test_dm_in + cpath.io.Inst := 0.U + } + when (io.boot && io.test_im_rd){ + io.test_im_out := imm(io.test_im_addr >> 2) + cpath.io.Inst := 0.U + } + when (io.boot && io.test_dm_rd){ + io.test_dm_out := dmm(io.test_dm_addr >> 2) + cpath.io.Inst := 0.U + } + when (!io.boot){ + cpath.io.Inst := Mux(io.boot, 0.U, imm(dpath.io.imem_addr >> 2)) + dpath.io.dmem_datOut := dmm(dpath.io.dmem_addr >> 2) + when (cpath.io.MemWr) { + dmm(dpath.io.dmem_addr >> 2) := dpath.io.dmem_datIn + } + } + + val clk_cnt = RegInit(0.U(32.W)) + clk_cnt := clk_cnt + 1.U + + printf("Cyc=%d, pc=0x%x, Inst=0x%x, boot=%d, dmem_in = 0x%x, rd_dmm=0x%x, dmm=0x%x\n", + clk_cnt, + dpath.io.imem_addr, + cpath.io.Inst, + cpath.io.boot, + dpath.io.dmem_datIn, + io.test_dm_out, + dmm(io.test_dm_addr >> 2)) + //... +} \ No newline at end of file diff --git a/src/test/scala/MultiCycle/Launcher.scala b/src/test/scala/MultiCycle/Launcher.scala new file mode 100644 index 0000000..4792e08 --- /dev/null +++ b/src/test/scala/MultiCycle/Launcher.scala @@ -0,0 +1,52 @@ +// See LICENSE.txt for license details. +//************************************************************************** +//-------------------------------------------------------------------------- +// ercesiMIPS Single Cycle Processor Test Launcher +// +// Meng zhang +// version 0.1 +//-------------------------------------------------------------------------- +//************************************************************************** + +package MultiCycle + +import chisel3._ +import chisel3.iotesters.Driver +import utils.ercesiMIPSRunner + +object Launcher { + val tests = Map( + + "ALU" -> { (backendName: String) => + Driver(() => new ALU(), backendName) { + (c) => new ALUTests(c) + } + }, + "Top" -> { (backendName: String) => + Driver(() => new Top(), backendName) { + (c) => new TopTests(c) + } + } + /*, + "CtlPath" -> { (backendName: String) => + Driver(() => new CtlPath(), backendName) { + (c) => new CtlPathTests(c) + } + }*/ + /*, + "ALU11" -> { (backendName: String) => + Driver(() => new ALU11(), backendName) { + (c) => new ALU11Tests(c) + } + }, + "Top" -> { (backendName: String) => + Driver(() => new Top(), backendName) { + (c) => new TopTests(c) + } + }*/ + ) + + def main(args: Array[String]): Unit = { + ercesiMIPSRunner(tests, args) + } +} diff --git a/src/test/scala/MultiCycle/TopTests.scala b/src/test/scala/MultiCycle/TopTests.scala new file mode 100644 index 0000000..b723dbc --- /dev/null +++ b/src/test/scala/MultiCycle/TopTests.scala @@ -0,0 +1,70 @@ +//************************************************************************** +//-------------------------------------------------------------------------- +// ercesiMIPS Multi Cycle Processor ALU Test +// +// Meng zhang +// version 0.1 +//-------------------------------------------------------------------------- +//************************************************************************** + + +package MultiCycle + +import chisel3.iotesters.PeekPokeTester +import java.io.PrintWriter +import java.io.File +import scala.io.Source + +class TopTests(c: Top) extends PeekPokeTester(c) { + def asUInt(InInt: Int) = (BigInt(InInt >>> 1) << 1) + (InInt & 1) + + // Reset the CPU + def TopBoot() = { + poke(c.io.boot, 1) + poke(c.io.test_im_wr, 0) + poke(c.io.test_dm_wr, 0) + step(1) + } + + // Initialize the IMM content from file "inst.s", + // which could be dumped from MARS. + def WriteImm () = { + val filename = "inst2.s" + var addr = 0 + var Inst = 0 + for (line <- Source.fromFile(filename).getLines){ + Inst = Integer.parseUnsignedInt(line, 16) + poke(c.io.boot, 1) + poke(c.io.test_im_wr, 1) + poke(c.io.test_im_addr, addr*4) + poke(c.io.test_im_in, asUInt(Inst)) + addr = addr + 1 + step(1) + } + } + + // Reset CPU + TopBoot() + + // Init IMM + WriteImm() + + // Run the CPU for 100 cycles + for (i <- 0 until 100){ + poke(c.io.boot, 0) + poke(c.io.test_im_wr, 0) + poke(c.io.test_dm_wr, 0) + expect(c.io.valid, 1) + step(1) + } + + // Check the SW instruction in the DMM + val DmmQ = List(1, 2004, 2004) // The value is decided by "inst.s" + for (i <- 0 until 3){ + poke(c.io.boot, 1) + poke(c.io.test_dm_rd, 1) + poke(c.io.test_dm_addr, i*4) + expect(c.io.test_dm_out, DmmQ(i)) + step(1) + } +} diff --git a/src/test/scala/SingleCycle/TopTests.scala b/src/test/scala/SingleCycle/TopTests.scala index e2d1360..b5cff8d 100644 --- a/src/test/scala/SingleCycle/TopTests.scala +++ b/src/test/scala/SingleCycle/TopTests.scala @@ -55,7 +55,7 @@ class TopTests(c: Top) extends PeekPokeTester(c) { // Initialize the IMM content from file "inst.s", // which could be dumped from MARS. def WriteImm () = { - val filename = "inst.s" + val filename = "inst2.s" var addr = 0 var Inst = 0 for (line <- Source.fromFile(filename).getLines){