完成常量和顶层模块编写
This commit is contained in:
2
.scalafmt.conf
Normal file
2
.scalafmt.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
version = "3.7.15"
|
||||||
|
runner.dialect = scala213
|
||||||
73
src/main/scala/common/Consts.scala
Normal file
73
src/main/scala/common/Consts.scala
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
|
||||||
|
object Consts {
|
||||||
|
// 数据宽度和地址
|
||||||
|
val WORD_LEN = 32 // 指令和数据的宽度为32位
|
||||||
|
val START_ADDR = 0.U(WORD_LEN.W) // 起始地址,设为0
|
||||||
|
val BUBBLE = 0x00000000.U(WORD_LEN.W) // 用于冒泡的指令 [NOP]
|
||||||
|
val UNIMP = "x_c0000000".U(WORD_LEN.W) // 未实现指令 [SLL $0, $0, 0]
|
||||||
|
|
||||||
|
// 寄存器地址长度
|
||||||
|
val ADDR_LEN = 5 // rs1、rs2和写回寄存器的地址宽度为5位
|
||||||
|
|
||||||
|
// 执行功能定义
|
||||||
|
val EXE_FUN_LEN = 5 // 执行功能的编码长度为5位
|
||||||
|
val ALU_X = 0.U(EXE_FUN_LEN.W) // 未定义ALU操作
|
||||||
|
val ALU_ADD = 1.U(EXE_FUN_LEN.W) // 加法操作
|
||||||
|
val ALU_SUB = 2.U(EXE_FUN_LEN.W) // 减法操作
|
||||||
|
val ALU_AND = 3.U(EXE_FUN_LEN.W) // 位与操作
|
||||||
|
val ALU_OR = 4.U(EXE_FUN_LEN.W) // 位或操作
|
||||||
|
val ALU_XOR = 5.U(EXE_FUN_LEN.W) // 位异或操作
|
||||||
|
val ALU_SLL = 6.U(EXE_FUN_LEN.W) // 左移操作
|
||||||
|
val ALU_SRL = 7.U(EXE_FUN_LEN.W) // 逻辑右移操作
|
||||||
|
val ALU_SRA = 8.U(EXE_FUN_LEN.W) // 算术右移操作
|
||||||
|
val ALU_SLT = 9.U(EXE_FUN_LEN.W) // 有符号比较小于操作
|
||||||
|
val ALU_SLTU = 10.U(EXE_FUN_LEN.W) // 无符号比较小于操作
|
||||||
|
val BR_BEQ = 11.U(EXE_FUN_LEN.W) // 分支相等
|
||||||
|
val BR_BNE = 12.U(EXE_FUN_LEN.W) // 分支不等
|
||||||
|
val ALU_JALR = 13.U(EXE_FUN_LEN.W) // JALR跳转
|
||||||
|
val ALU_COPY1 = 14.U(EXE_FUN_LEN.W) // 复制操作
|
||||||
|
|
||||||
|
// 操作数选择
|
||||||
|
val OP1_LEN = 2 // 操作数1的选择宽度为2位
|
||||||
|
val OP1_RS1 = 0.U(OP1_LEN.W) // 选择rs1
|
||||||
|
val OP1_PC = 1.U(OP1_LEN.W) // 选择PC
|
||||||
|
val OP1_X = 2.U(OP1_LEN.W) // 未定义操作数1
|
||||||
|
|
||||||
|
val OP2_LEN = 3 // 操作数2的选择宽度为3位
|
||||||
|
val OP2_X = 0.U(OP2_LEN.W) // 未定义操作数2
|
||||||
|
val OP2_RS2 = 1.U(OP2_LEN.W) // 选择rs2
|
||||||
|
val OP2_IMI = 2.U(OP2_LEN.W) // 立即数操作数2(immI)
|
||||||
|
val OP2_IMS = 3.U(OP2_LEN.W) // 立即数操作数2(immS)
|
||||||
|
val OP2_IMJ = 4.U(OP2_LEN.W) // 立即数操作数2(immJ)
|
||||||
|
val OP2_IMU = 5.U(OP2_LEN.W) // 立即数操作数2(immU)
|
||||||
|
|
||||||
|
// 内存访问使能信号
|
||||||
|
val MEN_LEN = 2 // 内存访问控制宽度为2位
|
||||||
|
val MEN_X = 0.U(MEN_LEN.W) // 未定义
|
||||||
|
val MEN_S = 1.U(MEN_LEN.W) // 存储操作
|
||||||
|
|
||||||
|
// 寄存器使能信号
|
||||||
|
val REN_LEN = 2 // 寄存器使能信号宽度为2位
|
||||||
|
val REN_X = 0.U(REN_LEN.W) // 未定义
|
||||||
|
val REN_S = 1.U(REN_LEN.W) // 标量寄存器写回使能
|
||||||
|
|
||||||
|
// 写回选择
|
||||||
|
val WB_SEL_LEN = 3 // 写回选择信号宽度为3位
|
||||||
|
val WB_X = 0.U(WB_SEL_LEN.W) // 未定义
|
||||||
|
val WB_ALU = 1.U(WB_SEL_LEN.W) // ALU结果写回
|
||||||
|
val WB_MEM = 2.U(WB_SEL_LEN.W) // 内存数据写回
|
||||||
|
val WB_PC = 3.U(WB_SEL_LEN.W) // PC写回
|
||||||
|
|
||||||
|
// 内存宽度
|
||||||
|
val MW_LEN = 3 // 内存宽度控制信号宽度为3位
|
||||||
|
val MW_X = 0.U(MW_LEN.W) // 未定义
|
||||||
|
val MW_W = 1.U(MW_LEN.W) // 32位字访问
|
||||||
|
val MW_H = 2.U(MW_LEN.W) // 16位半字访问
|
||||||
|
val MW_B = 3.U(MW_LEN.W) // 8位字节访问
|
||||||
|
val MW_HU = 4.U(MW_LEN.W) // 16位无符号半字访问
|
||||||
|
val MW_BU = 5.U(MW_LEN.W) // 8位无符号字节访问
|
||||||
|
}
|
||||||
47
src/main/scala/common/Instructions.scala
Normal file
47
src/main/scala/common/Instructions.scala
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
|
||||||
|
object Instructions {
|
||||||
|
// * 加载 / 存储
|
||||||
|
val LW = BitPat("b100011????????????0000000000000000") // lw rt, offset(rs)
|
||||||
|
val SW = BitPat("b101011????????????0000000000000000") // sw rt, offset(rs)
|
||||||
|
|
||||||
|
// * 算术运算
|
||||||
|
val ADD = BitPat("b000000???????????????00000100000") // add rd, rs, rt
|
||||||
|
val ADDI = BitPat(
|
||||||
|
"b001000????????????0000000000000000"
|
||||||
|
) // addi rt, rs, immediate
|
||||||
|
val SUB = BitPat("b000000???????????????00000100010") // sub rd, rs, rt
|
||||||
|
|
||||||
|
// * 逻辑运算
|
||||||
|
val AND = BitPat("b000000???????????????00000100100") // and rd, rs, rt
|
||||||
|
val OR = BitPat("b000000???????????????00000100101") // or rd, rs, rt
|
||||||
|
val XOR = BitPat("b000000???????????????00000100110") // xor rd, rs, rt
|
||||||
|
val ANDI = BitPat(
|
||||||
|
"b001100????????????0000000000000000"
|
||||||
|
) // andi rt, rs, immediate
|
||||||
|
val ORI = BitPat(
|
||||||
|
"b001101????????????0000000000000000"
|
||||||
|
) // ori rt, rs, immediate
|
||||||
|
|
||||||
|
// * 比较
|
||||||
|
val SLT = BitPat("b000000???????????????00000101010") // slt rd, rs, rt
|
||||||
|
|
||||||
|
// * 条件分支
|
||||||
|
val BEQ = BitPat("b000100????????????0000000000000000") // beq rs, rt, offset
|
||||||
|
val BNE = BitPat("b000101????????????0000000000000000") // bne rs, rt, offset
|
||||||
|
|
||||||
|
// * 移位
|
||||||
|
val SLL = BitPat("b00000000000??????????????000000") // sll rd, rt, shamt
|
||||||
|
val SRL = BitPat("b00000000000??????????????000010") // srl rd, rt, shamt
|
||||||
|
val SRA = BitPat("b00000000000??????????????000011") // sra rd, rt, shamt
|
||||||
|
|
||||||
|
// * 跳转
|
||||||
|
val JR = BitPat("b000000????????????0000000000001000") // jr rs
|
||||||
|
val JAL = BitPat("b00001100000000000000000000000000") // jal target
|
||||||
|
|
||||||
|
// * 立即数加载
|
||||||
|
val LUI = BitPat("b00111100000????????????0000000000") // lui rt, immediate
|
||||||
|
}
|
||||||
@ -1,73 +0,0 @@
|
|||||||
// See README.md for license details.
|
|
||||||
|
|
||||||
package gcd
|
|
||||||
|
|
||||||
import chisel3._
|
|
||||||
import chisel3.util.Decoupled
|
|
||||||
|
|
||||||
class GcdInputBundle(val w: Int) extends Bundle {
|
|
||||||
val value1 = UInt(w.W)
|
|
||||||
val value2 = UInt(w.W)
|
|
||||||
}
|
|
||||||
|
|
||||||
class GcdOutputBundle(val w: Int) extends Bundle {
|
|
||||||
val value1 = UInt(w.W)
|
|
||||||
val value2 = UInt(w.W)
|
|
||||||
val gcd = UInt(w.W)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute Gcd using subtraction method.
|
|
||||||
* Subtracts the smaller from the larger until register y is zero.
|
|
||||||
* value input register x is then the Gcd.
|
|
||||||
* Unless first input is zero then the Gcd is y.
|
|
||||||
* Can handle stalls on the producer or consumer side
|
|
||||||
*/
|
|
||||||
class DecoupledGcd(width: Int) extends Module {
|
|
||||||
val input = IO(Flipped(Decoupled(new GcdInputBundle(width))))
|
|
||||||
val output = IO(Decoupled(new GcdOutputBundle(width)))
|
|
||||||
|
|
||||||
val xInitial = Reg(UInt())
|
|
||||||
val yInitial = Reg(UInt())
|
|
||||||
val x = Reg(UInt())
|
|
||||||
val y = Reg(UInt())
|
|
||||||
val busy = RegInit(false.B)
|
|
||||||
val resultValid = RegInit(false.B)
|
|
||||||
|
|
||||||
input.ready := ! busy
|
|
||||||
output.valid := resultValid
|
|
||||||
output.bits := DontCare
|
|
||||||
|
|
||||||
when(busy) {
|
|
||||||
when(x > y) {
|
|
||||||
x := x - y
|
|
||||||
}.otherwise {
|
|
||||||
y := y - x
|
|
||||||
}
|
|
||||||
when(x === 0.U || y === 0.U) {
|
|
||||||
when(x === 0.U) {
|
|
||||||
output.bits.gcd := y
|
|
||||||
}.otherwise {
|
|
||||||
output.bits.gcd := x
|
|
||||||
}
|
|
||||||
|
|
||||||
output.bits.value1 := xInitial
|
|
||||||
output.bits.value2 := yInitial
|
|
||||||
resultValid := true.B
|
|
||||||
|
|
||||||
when(output.ready && resultValid) {
|
|
||||||
busy := false.B
|
|
||||||
resultValid := false.B
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.otherwise {
|
|
||||||
when(input.valid) {
|
|
||||||
val bundle = input.deq()
|
|
||||||
x := bundle.value1
|
|
||||||
y := bundle.value2
|
|
||||||
xInitial := bundle.value1
|
|
||||||
yInitial := bundle.value2
|
|
||||||
busy := true.B
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
// See README.md for license details.
|
|
||||||
|
|
||||||
package gcd
|
|
||||||
|
|
||||||
import chisel3._
|
|
||||||
// _root_ disambiguates from package chisel3.util.circt if user imports chisel3.util._
|
|
||||||
import _root_.circt.stage.ChiselStage
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute GCD using subtraction method.
|
|
||||||
* Subtracts the smaller from the larger until register y is zero.
|
|
||||||
* value in register x is then the GCD
|
|
||||||
*/
|
|
||||||
class GCD extends Module {
|
|
||||||
val io = IO(new Bundle {
|
|
||||||
val value1 = Input(UInt(16.W))
|
|
||||||
val value2 = Input(UInt(16.W))
|
|
||||||
val loadingValues = Input(Bool())
|
|
||||||
val outputGCD = Output(UInt(16.W))
|
|
||||||
val outputValid = Output(Bool())
|
|
||||||
})
|
|
||||||
|
|
||||||
val x = Reg(UInt())
|
|
||||||
val y = Reg(UInt())
|
|
||||||
|
|
||||||
when(x > y) { x := x - y }
|
|
||||||
.otherwise { y := y - x }
|
|
||||||
|
|
||||||
when(io.loadingValues) {
|
|
||||||
x := io.value1
|
|
||||||
y := io.value2
|
|
||||||
}
|
|
||||||
|
|
||||||
io.outputGCD := x
|
|
||||||
io.outputValid := y === 0.U
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate Verilog sources and save it in file GCD.v
|
|
||||||
*/
|
|
||||||
object GCD extends App {
|
|
||||||
ChiselStage.emitSystemVerilogFile(
|
|
||||||
new GCD,
|
|
||||||
firtoolOpts = Array("-disable-all-randomization", "-strip-debug-info")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
15
src/main/scala/micore/Core.scala
Normal file
15
src/main/scala/micore/Core.scala
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package micore
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
import common.Consts._
|
||||||
|
import common.Instructions._
|
||||||
|
import os.list
|
||||||
|
|
||||||
|
class Core extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val imem = Flipped(new ImemPortIo)
|
||||||
|
val dmem = Flipped(new DmemPortIo)
|
||||||
|
val exit = Output(Bool())
|
||||||
|
})
|
||||||
|
}
|
||||||
43
src/main/scala/micore/Memory.scala
Normal file
43
src/main/scala/micore/Memory.scala
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package micore
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
import chisel3.util.experimental.loadMemoryFromFileInline
|
||||||
|
import common.Consts._
|
||||||
|
|
||||||
|
class ImemPortIo extends Bundle {
|
||||||
|
val addr = Input(UInt(WORD_LEN.W))
|
||||||
|
val inst = Output(UInt(WORD_LEN.W))
|
||||||
|
}
|
||||||
|
|
||||||
|
class DmemPortIo extends Bundle {
|
||||||
|
val addr = Input(UInt(WORD_LEN.W))
|
||||||
|
val rdata = Output(UInt(WORD_LEN.W))
|
||||||
|
val wen = Input(Bool())
|
||||||
|
val wdata = Input(UInt(WORD_LEN.W))
|
||||||
|
}
|
||||||
|
|
||||||
|
class Memory extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val imem = new ImemPortIo
|
||||||
|
val dmem = new DmemPortIo
|
||||||
|
})
|
||||||
|
|
||||||
|
val mem = Mem(8192, UInt(8.W))
|
||||||
|
|
||||||
|
loadMemoryFromFileInline(mem, "src/hex/mem.hex")
|
||||||
|
|
||||||
|
io.imem.inst := Cat(
|
||||||
|
mem(io.imem.addr),
|
||||||
|
mem(io.imem.addr + 1.U(WORD_LEN.W)),
|
||||||
|
mem(io.imem.addr + 2.U(WORD_LEN.W)),
|
||||||
|
mem(io.imem.addr + 3.U(WORD_LEN.W))
|
||||||
|
)
|
||||||
|
|
||||||
|
when(io.dmem.wen) {
|
||||||
|
mem(io.dmem.addr) := io.dmem.wdata(31, 24)
|
||||||
|
mem(io.dmem.addr + 1.U(WORD_LEN.W)) := io.dmem.wdata(23, 16)
|
||||||
|
mem(io.dmem.addr + 2.U(WORD_LEN.W)) := io.dmem.wdata(15, 8)
|
||||||
|
mem(io.dmem.addr + 3.U(WORD_LEN.W)) := io.dmem.wdata(7, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/main/scala/micore/Top.scala
Normal file
28
src/main/scala/micore/Top.scala
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package micore
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
// _root_ disambiguates from package chisel3.util.circt if user imports chisel3.util._
|
||||||
|
import _root_.circt.stage.ChiselStage
|
||||||
|
import common.Consts._
|
||||||
|
|
||||||
|
class Top extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val exit = Output(Bool())
|
||||||
|
})
|
||||||
|
val core = Module(new Core)
|
||||||
|
val memory = Module(new Memory)
|
||||||
|
|
||||||
|
core.io.imem <> memory.io.imem
|
||||||
|
core.io.dmem <> memory.io.dmem
|
||||||
|
|
||||||
|
io.exit := core.io.exit
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Generate Verilog sources and save it in file
|
||||||
|
*/
|
||||||
|
object Top extends App {
|
||||||
|
ChiselStage.emitSystemVerilogFile(
|
||||||
|
new Top,
|
||||||
|
firtoolOpts = Array("-disable-all-randomization", "-strip-debug-info")
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -1,68 +0,0 @@
|
|||||||
// See README.md for license details.
|
|
||||||
|
|
||||||
package gcd
|
|
||||||
|
|
||||||
import chisel3._
|
|
||||||
import chisel3.experimental.BundleLiterals._
|
|
||||||
import chisel3.simulator.EphemeralSimulator._
|
|
||||||
import org.scalatest.freespec.AnyFreeSpec
|
|
||||||
import org.scalatest.matchers.must.Matchers
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a trivial example of how to run this Specification
|
|
||||||
* From within sbt use:
|
|
||||||
* {{{
|
|
||||||
* testOnly gcd.GCDSpec
|
|
||||||
* }}}
|
|
||||||
* From a terminal shell use:
|
|
||||||
* {{{
|
|
||||||
* sbt 'testOnly gcd.GCDSpec'
|
|
||||||
* }}}
|
|
||||||
* Testing from mill:
|
|
||||||
* {{{
|
|
||||||
* mill %NAME%.test.testOnly gcd.GCDSpec
|
|
||||||
* }}}
|
|
||||||
*/
|
|
||||||
class GCDSpec extends AnyFreeSpec with Matchers {
|
|
||||||
|
|
||||||
"Gcd should calculate proper greatest common denominator" in {
|
|
||||||
simulate(new DecoupledGcd(16)) { dut =>
|
|
||||||
val testValues = for { x <- 0 to 10; y <- 0 to 10} yield (x, y)
|
|
||||||
val inputSeq = testValues.map { case (x, y) => (new GcdInputBundle(16)).Lit(_.value1 -> x.U, _.value2 -> y.U) }
|
|
||||||
val resultSeq = testValues.map { case (x, y) =>
|
|
||||||
(new GcdOutputBundle(16)).Lit(_.value1 -> x.U, _.value2 -> y.U, _.gcd -> BigInt(x).gcd(BigInt(y)).U)
|
|
||||||
}
|
|
||||||
|
|
||||||
dut.reset.poke(true.B)
|
|
||||||
dut.clock.step()
|
|
||||||
dut.reset.poke(false.B)
|
|
||||||
dut.clock.step()
|
|
||||||
|
|
||||||
var sent, received, cycles: Int = 0
|
|
||||||
while (sent != 100 && received != 100) {
|
|
||||||
assert(cycles <= 1000, "timeout reached")
|
|
||||||
|
|
||||||
if (sent < 100) {
|
|
||||||
dut.input.valid.poke(true.B)
|
|
||||||
dut.input.bits.value1.poke(testValues(sent)._1.U)
|
|
||||||
dut.input.bits.value2.poke(testValues(sent)._2.U)
|
|
||||||
if (dut.input.ready.peek().litToBoolean) {
|
|
||||||
sent += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (received < 100) {
|
|
||||||
dut.output.ready.poke(true.B)
|
|
||||||
if (dut.output.valid.peekValue().asBigInt == 1) {
|
|
||||||
dut.output.bits.gcd.expect(BigInt(testValues(received)._1).gcd(testValues(received)._2))
|
|
||||||
received += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step the simulation forward.
|
|
||||||
dut.clock.step()
|
|
||||||
cycles += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
7
src/test/scala/micore/MicoreSpec.scala
Normal file
7
src/test/scala/micore/MicoreSpec.scala
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package micore
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.experimental.BundleLiterals._
|
||||||
|
import chisel3.simulator.EphemeralSimulator._
|
||||||
|
import org.scalatest.freespec.AnyFreeSpec
|
||||||
|
import org.scalatest.matchers.must.Matchers
|
||||||
Reference in New Issue
Block a user