diff --git a/TODO.md b/TODO.md
index 49586e3..47eb721 100644
--- a/TODO.md
+++ b/TODO.md
@@ -103,14 +103,14 @@
- Zicsr Extension Instructions
-
-- [ ] csrrw
-- [ ] csrrs
-- [ ] csrrc
-- [ ] csrrwi
-- [ ] csrrsi
-- [ ] csrrci
+ Zicsr Extension Instructions✅
+
+- [x] csrrw
+- [x] csrrs
+- [x] csrrc
+- [x] csrrwi
+- [x] csrrsi
+- [x] csrrci
diff --git a/docs/update-log.md b/docs/update-log.md
index 7d8a6b6..cb750de 100644
--- a/docs/update-log.md
+++ b/docs/update-log.md
@@ -4,6 +4,7 @@
* ✅ Feat: Remove LSU state machine.
* ✅ Feat: Better build and compile implementation.
* ✅ Feat: Custom cpp & verilator based test workflow.
+* ✅ Feat: Support for basic Zicsr.
* 📚 Docs: Added readme.
🎉 **Version 0.1 Released!** 🎉
@@ -17,8 +18,8 @@
📝 **Previously Unlogged Updates** 📝
-* ✅ Feat: support for Immediate Instructions
-* ✅ Feat: support for Register-Register Instructions
-* ✅ Feat: support for Memory Instructions
-* ✅ Feat: support for Flow Control Instructions
+* ✅ Feat: Support for Immediate Instructions
+* ✅ Feat: Support for Register-Register Instructions
+* ✅ Feat: Support for Memory Instructions
+* ✅ Feat: Support for Flow Control Instructions
* ✅ Feat: Implemented L1 Instruction Cache support
diff --git a/src/main/scala/markorv/ControlStatusRegisters.scala b/src/main/scala/markorv/ControlStatusRegisters.scala
index 4dc4bb5..a5dddc5 100644
--- a/src/main/scala/markorv/ControlStatusRegisters.scala
+++ b/src/main/scala/markorv/ControlStatusRegisters.scala
@@ -3,17 +3,25 @@ package markorv
import chisel3._
import chisel3.util._
+class ControlStatusRegistersIO extends Bundle {
+ val read_addr = Input(UInt(12.W))
+ val write_addr = Input(UInt(12.W))
+ val write_en = Input(Bool())
+
+ val read_data = Output(UInt(64.W))
+ val write_data = Input(UInt(64.W))
+}
+
class ControlStatusRegisters extends Module {
val io = IO(new Bundle {
- val read_addr = Input(UInt(12.W))
- val write_addr = Input(UInt(12.W))
-
- val read_data = Output(UInt(64.W))
- val write_data = Input(UInt(64.W))
- val write_mask = Input(UInt(64.W))
+ val csrio = new ControlStatusRegistersIO
})
// While read write simultaneously shuould return old value.
+ // Machine custom register(MRW)
+ // For Zicsr test.
+ val MCUSTOMTST_ADDR = "h800".U(12.W)
+
// Machine infomations(MRO).
val MVENDORID_ADDR = "hf11".U(12.W)
val MARCHID_ADDR = "hf12".U(12.W)
@@ -30,6 +38,8 @@ class ControlStatusRegisters extends Module {
val MTVEC_ADDR = "h305".U(12.W)
val MCOUNTEREN_ADDR = "h306".U(12.W)
+ val mcustomtst = RegInit("h0000000000000000".U(64.W))
+
val mstatus = RegInit("h0000000000000000".U(64.W))
val misa = RegInit("h8000000000000100".U(64.W))
val medeleg = RegInit("h0000000000000000".U(64.W))
@@ -39,72 +49,82 @@ class ControlStatusRegisters extends Module {
val mcounteren = RegInit("h00000000".U(32.W))
- io.read_data := 0.U
- switch(io.read_addr) {
+ io.csrio.read_data := 0.U
+ switch(io.csrio.read_addr) {
+ is(MCUSTOMTST_ADDR) {
+ io.csrio.read_data := mcustomtst
+ }
+
is(MVENDORID_ADDR) {
// Non-commercial.
- io.read_data := "h0000000000000000".U
+ io.csrio.read_data := "h0000000000000000".U
}
is(MARCHID_ADDR) {
// In development.
- io.read_data := "h0000000000000000".U
+ io.csrio.read_data := "h0000000000000000".U
}
is(MIMPID_ADDR) {
// In development.
- io.read_data := "h0000000000000000".U
+ io.csrio.read_data := "h0000000000000000".U
}
is(MHARTID_ADDR) {
// 0x0
- io.read_data := "h0000000000000000".U
+ io.csrio.read_data := "h0000000000000000".U
}
is(MCONFIGPTR_ADDR) {
// TODO machine config
- io.read_data := "h0000000000000000".U
+ io.csrio.read_data := "h0000000000000000".U
}
is(MSTATUS_ADDR) {
- io.read_data := mstatus
+ io.csrio.read_data := mstatus
}
is(MISA_ADDR) {
// RV64I
- io.read_data := misa
+ io.csrio.read_data := misa
}
is(MEDELEG_ADDR) {
- io.read_data := medeleg
+ io.csrio.read_data := medeleg
}
is(MIDELEG_ADDR) {
- io.read_data := mideleg
+ io.csrio.read_data := mideleg
}
is(MCOUNTEREN_ADDR) {
- io.read_data := mcounteren
+ io.csrio.read_data := mcounteren
}
}
- switch(io.write_addr) {
- is(MSTATUS_ADDR) {
- // write mask shown that which fields is implemented.
- val write_mask = "h0000000000000000".U
- mstatus := write_mask & io.write_data
- }
- is(MISA_ADDR) {
- // Can't write this to switch func for now.
- }
- is(MEDELEG_ADDR) {
- // TODO S mode
- medeleg := io.write_data
- }
- is(MIDELEG_ADDR) {
- // TODO S mode
- mideleg := io.write_data
- }
- is(MTVEC_ADDR) {
- // mtvec mode >= 2 is Reserved
- val write_mask = "hfffffffffffffffd".U
- mtvec := write_mask & io.write_data
- }
- is(MCOUNTEREN_ADDR) {
- // TODO counter
- mcounteren := io.write_data
+ when(io.csrio.write_en) {
+ switch(io.csrio.write_addr) {
+ is(MCUSTOMTST_ADDR) {
+ mcustomtst := io.csrio.write_data
+ }
+
+ is(MSTATUS_ADDR) {
+ // write mask shown that which fields is implemented.
+ val write_mask = "h0000000000000000".U
+ mstatus := write_mask & io.csrio.write_data
+ }
+ is(MISA_ADDR) {
+ // Can't write this to switch func for now.
+ }
+ is(MEDELEG_ADDR) {
+ // TODO S mode
+ medeleg := io.csrio.write_data
+ }
+ is(MIDELEG_ADDR) {
+ // TODO S mode
+ mideleg := io.csrio.write_data
+ }
+ is(MTVEC_ADDR) {
+ // mtvec mode >= 2 is Reserved
+ val write_mask = "hfffffffffffffffd".U
+ mtvec := write_mask & io.csrio.write_data
+ }
+ is(MCOUNTEREN_ADDR) {
+ // TODO counter
+ mcounteren := io.csrio.write_data
+ }
}
}
}
diff --git a/src/main/scala/markorv/TopModule.scala b/src/main/scala/markorv/TopModule.scala
index 713a658..493d81e 100644
--- a/src/main/scala/markorv/TopModule.scala
+++ b/src/main/scala/markorv/TopModule.scala
@@ -38,8 +38,11 @@ class MarkoRvCore extends Module {
val load_store_unit = Module(new LoadStoreUnit)
val arithmetic_logic_unit = Module(new ArithmeticLogicUnit)
val branch_unit = Module(new BranchUnit)
+ val misc_unit = Module(new MiscUnit)
val register_file = Module(new RegFile)
+ val csr_file = Module(new ControlStatusRegisters)
+
val write_back = Module(new WriteBack)
data_cache_warpper.io.cache_write_req <> data_cache.io.write_req
@@ -98,6 +101,7 @@ class MarkoRvCore extends Module {
write_back.io.reg_write <> register_file.io.write_addr
write_back.io.write_data <> register_file.io.write_data
+ csr_file.io.csrio <> misc_unit.io.csrio
register_file.io.flush := branch_unit.io.flush
// Main pipeline.
@@ -127,6 +131,12 @@ class MarkoRvCore extends Module {
load_store_unit.io.outfire,
branch_unit.io.flush
)
+ PipelineConnect(
+ instr_issuer.io.misc_out,
+ misc_unit.io.misc_instr,
+ misc_unit.io.outfire,
+ branch_unit.io.flush
+ )
PipelineConnect(
instr_issuer.io.branch_out,
branch_unit.io.branch_instr,
@@ -153,6 +163,12 @@ class MarkoRvCore extends Module {
write_back.io.outfires(2),
branch_unit.io.flush
)
+ PipelineConnect(
+ misc_unit.io.write_back,
+ write_back.io.write_backs(3),
+ write_back.io.outfires(3),
+ branch_unit.io.flush
+ )
}
object MarkoRvCore extends App {
diff --git a/src/main/scala/markorv/WriteBack.scala b/src/main/scala/markorv/WriteBack.scala
index 3011de7..83fba4c 100644
--- a/src/main/scala/markorv/WriteBack.scala
+++ b/src/main/scala/markorv/WriteBack.scala
@@ -5,9 +5,7 @@ import chisel3.util._
class WriteBack extends Module {
val io = IO(new Bundle {
- val write_backs = Vec(
- 3,
- Flipped(Decoupled(new Bundle {
+ val write_backs = Vec(4, Flipped(Decoupled(new Bundle {
val reg = UInt(5.W)
val data = UInt(64.W)
}))
@@ -16,10 +14,10 @@ class WriteBack extends Module {
val reg_write = Output(UInt(5.W))
val write_data = Output(UInt(64.W))
- val outfires = Vec(3, Output(Bool()))
+ val outfires = Vec(4, Output(Bool()))
})
- for (i <- 0 until 3) {
+ for (i <- 0 until 4) {
io.write_backs(i).ready := true.B
io.outfires(i) := true.B
}
@@ -28,7 +26,7 @@ class WriteBack extends Module {
io.write_data := 0.U
// Impossible to write back multiple times in one cycle.
- for (i <- 0 until 3) {
+ for (i <- 0 until 4) {
when(io.write_backs(i).valid) {
io.reg_write := io.write_backs(i).bits.reg
io.write_data := io.write_backs(i).bits.data
diff --git a/src/main/scala/markorv/backend/MiscUnit.scala b/src/main/scala/markorv/backend/MiscUnit.scala
index f45eeca..2b0bdfb 100644
--- a/src/main/scala/markorv/backend/MiscUnit.scala
+++ b/src/main/scala/markorv/backend/MiscUnit.scala
@@ -3,16 +3,17 @@ package markorv.backend
import chisel3._
import chisel3.util._
+import markorv.ControlStatusRegistersIO
import markorv.frontend.DecoderOutParams
class MiscUnit extends Module {
val io = IO(new Bundle {
// misc_opcode encoding:
- // Bit [4] AMO operate reserved.
- // Bit [3] System operate(ecall ebrack etc) reserved.
- // Bit [2] Fence operate(fence fence.i) reserved.
- // Bit [1] Cache line operate(zicbox) reserved.
- // Bit [0] CSR(zicsr) operate.
+ // Bit [2,0] == 4 AMO operate reserved.
+ // Bit [2,0] == 3 System operate(ecall ebrack etc) reserved.
+ // Bit [2,0] == 2 Fence operate(fence fence.i) reserved.
+ // Bit [2,0] == 1 Cache line operate(zicbox) reserved.
+ // Bit [2,0] == 0 CSR(zicsr) operate. Bit[3] = rs1 == x0 ? 1 : 0.
val misc_instr = Flipped(Decoupled(new Bundle {
val misc_opcode = UInt(5.W)
val params = new DecoderOutParams(64)
@@ -22,6 +23,62 @@ class MiscUnit extends Module {
val reg = Input(UInt(5.W))
val data = Input(UInt(64.W))
})
+
+ val csrio = Flipped(new ControlStatusRegistersIO)
+ val outfire = Output(Bool())
})
+ // M mode when reset.
+ val privilege_reg = RegInit(3.U(2.W))
+ val opcode = io.misc_instr.bits.misc_opcode
+ val params = io.misc_instr.bits.params
+
+ // Immediate shall handle by decoder.
+ val CSRRW = "b01".U
+ val CSRRS = "b10".U
+ val CSRRC = "b11".U
+ io.csrio.write_en := false.B
+ io.csrio.read_addr := 0.U
+ io.csrio.write_addr := 0.U
+ io.csrio.write_data := 0.U
+
+ io.outfire := true.B
+ io.misc_instr.ready := true.B
+ io.write_back.valid := false.B
+ io.write_back.bits.reg := 0.U
+ io.write_back.bits.data := 0.U
+
+ when(io.misc_instr.valid) {
+ when(opcode(2,0) === 0.U) {
+ val csr_src1 = params.source1
+ val csr_addr = params.source2
+ val csr_func = params.immediate
+ // If rs1 == x0 csrrc and csrrs shall not cause any side effect like illegal instruction exceptions.
+ val csr_ro = opcode(3) && csr_func =/= CSRRW
+
+ // Reserved for illegal instruction exceptions.
+ val is_csr_read_only = csr_addr(11, 10) === 3.U
+ val has_privilege = privilege_reg > csr_addr(9, 8)
+
+ io.csrio.read_addr := csr_addr
+ val csr_data = io.csrio.read_data
+
+ io.csrio.write_en := ~csr_ro
+ io.csrio.write_addr := csr_addr
+ switch(csr_func(1, 0)) {
+ is(CSRRW) {
+ io.csrio.write_data := csr_src1
+ }
+ is(CSRRS) {
+ io.csrio.write_data := csr_data | csr_src1
+ }
+ is(CSRRC) {
+ io.csrio.write_data := csr_data & ~csr_src1
+ }
+ }
+ io.write_back.valid := true.B
+ io.write_back.bits.reg := params.rd
+ io.write_back.bits.data := csr_data
+ }
+ }
}
diff --git a/src/main/scala/markorv/frontend/InstrDecoder.scala b/src/main/scala/markorv/frontend/InstrDecoder.scala
index 41f97f7..f27e9f7 100644
--- a/src/main/scala/markorv/frontend/InstrDecoder.scala
+++ b/src/main/scala/markorv/frontend/InstrDecoder.scala
@@ -24,6 +24,7 @@ class IssueTask extends Bundle {
val operate_unit = UInt(2.W)
val alu_opcode = UInt(5.W)
val lsu_opcode = UInt(5.W)
+ val misc_opcode = UInt(5.W)
val branch_opcode = UInt(5.W)
val pred_taken = Bool()
val pred_pc = UInt(64.W)
@@ -44,7 +45,6 @@ class InstrDecoder(data_width: Int = 64, addr_width: Int = 64) extends Module {
val instr = Wire(UInt(32.W))
val pc = Wire(UInt(64.W))
- val opcode = Wire(UInt(7.W))
val valid_instr = Wire(Bool())
// 0 for alu 1 for lsu 2 for branch
val operate_unit = Wire(UInt(2.W))
@@ -54,9 +54,28 @@ class InstrDecoder(data_width: Int = 64, addr_width: Int = 64) extends Module {
0.U.asTypeOf(new RegisterSourceRequests(data_width))
)
+ val OP_LUI = "b0110111".U
+ val OP_AUIPC = "b0010111".U
+ val OP_IMM = "b0010011".U
+ val OP_IMM32 = "b0011011".U
+ val OP = "b0110011".U
+ val OP_32 = "b0111011".U
+ val OP_LOAD = "b0000011".U
+ val OP_STOR = "b0100011".U
+ val OP_JAL = "b1101111".U
+ val OP_JALR = "b1100111".U
+ val OP_BRANCH = "b1100011".U
+ val OP_SYSTEM = "b1110011".U
+
+ val opcode = instr(6, 0)
+ val rd = instr(11, 7)
+ val rs1 = instr(19, 15)
+ val rs2 = instr(24, 20)
+ val funct3 = instr(14, 12)
+ val funct7 = instr(31, 25)
+
instr := io.instr_bundle.bits.instr
pc := io.instr_bundle.bits.pc
- opcode := instr(6, 0)
valid_instr := false.B
operate_unit := 0.U
@@ -75,45 +94,45 @@ class InstrDecoder(data_width: Int = 64, addr_width: Int = 64) extends Module {
when(io.instr_bundle.valid) {
switch(opcode) {
- is("b0110111".U) {
+ is(OP_LUI) {
// lui
issue_task.alu_opcode := 1.U
params.source1 := (instr(31, 12) << 12).asSInt
.pad(64)
.asUInt
params.source2 := 0.U
- params.rd := instr(11, 7)
+ params.rd := rd
valid_instr := true.B
operate_unit := 0.U
}
- is("b0010111".U) {
+ is(OP_AUIPC) {
// auipc
issue_task.alu_opcode := 1.U
params.source1 := (instr(31, 12) << 12).asSInt
.pad(64)
.asUInt
params.source2 := pc
- params.rd := instr(11, 7)
+ params.rd := rd
valid_instr := true.B
operate_unit := 0.U
}
- is("b0010011".U) {
+ is(OP_IMM) {
// addi slti sltiu xori ori andi slli srli srai
- when(instr(14, 12) === "b001".U) {
+ when(funct3 === "b001".U) {
// slli
issue_task.alu_opcode := "b00011".U
params.source2 := (instr(25, 20).asSInt
.pad(64))
.asUInt
- }.elsewhen(instr(14, 12) === "b101".U && instr(30)) {
+ }.elsewhen(funct3 === "b101".U && instr(30)) {
// srai
issue_task.alu_opcode := "b01011".U
params.source2 := (instr(25, 20).asSInt
.pad(64))
.asUInt
- }.elsewhen(instr(14, 12) === "b101".U) {
+ }.elsewhen(funct3 === "b101".U) {
// srli
issue_task.alu_opcode := "b01010".U
params.source2 := (instr(25, 20).asSInt
@@ -122,34 +141,34 @@ class InstrDecoder(data_width: Int = 64, addr_width: Int = 64) extends Module {
}.otherwise {
issue_task.alu_opcode := Cat(
0.U(1.W),
- instr(14, 12),
+ funct3,
1.U(1.W)
)
params.source2 := (instr(31, 20).asSInt
.pad(64))
.asUInt
}
- reg_source_requests.source1 := instr(19, 15)
- params.rd := instr(11, 7)
+ reg_source_requests.source1 := rs1
+ params.rd := rd
valid_instr := true.B
operate_unit := 0.U
}
- is("b0011011".U) {
+ is(OP_IMM32) {
// addiw slliw srliw sraiw
- when(instr(14, 12) === "b001".U) {
+ when(funct3 === "b001".U) {
// slliw
issue_task.alu_opcode := "b10011".U
params.source2 := (instr(25, 20).asSInt
.pad(64))
.asUInt
- }.elsewhen(instr(14, 12) === "b101".U && instr(30)) {
+ }.elsewhen(funct3 === "b101".U && instr(30)) {
// sraiw
issue_task.alu_opcode := "b11011".U
params.source2 := (instr(25, 20).asSInt
.pad(64))
.asUInt
- }.elsewhen(instr(14, 12) === "b101".U) {
+ }.elsewhen(funct3 === "b101".U) {
// srliw
issue_task.alu_opcode := "b11010".U
params.source2 := (instr(25, 20).asSInt
@@ -158,142 +177,169 @@ class InstrDecoder(data_width: Int = 64, addr_width: Int = 64) extends Module {
}.otherwise {
issue_task.alu_opcode := Cat(
1.U(1.W),
- instr(14, 12),
+ funct3,
1.U(1.W)
)
params.source2 := (instr(31, 20).asSInt
.pad(64))
.asUInt
}
- reg_source_requests.source1 := instr(19, 15)
- params.rd := instr(11, 7)
+ reg_source_requests.source1 := rs1
+ params.rd := rd
valid_instr := true.B
operate_unit := 0.U
}
- is("b0110011".U) {
+ is(OP) {
// add sub slt sltu xor or and sll srl sra
- when(instr(14, 12) === "b001".U) {
+ when(funct3 === "b001".U) {
// sll
issue_task.alu_opcode := "b00011".U
- }.elsewhen(instr(14, 12) === "b101".U && instr(30)) {
+ }.elsewhen(funct3 === "b101".U && instr(30)) {
// sra
issue_task.alu_opcode := "b01011".U
- }.elsewhen(instr(14, 12) === "b101".U) {
+ }.elsewhen(funct3 === "b101".U) {
// srl
issue_task.alu_opcode := "b01010".U
- }.elsewhen(instr(14, 12) === "b000".U && instr(30)) {
+ }.elsewhen(funct3 === "b000".U && instr(30)) {
// sub
issue_task.alu_opcode := "b00000".U
}.otherwise {
issue_task.alu_opcode := Cat(
1.U(1.W),
- instr(14, 12),
+ funct3,
1.U(1.W)
)
}
- reg_source_requests.source1 := instr(19, 15)
- reg_source_requests.source2 := instr(24, 20)
- params.rd := instr(11, 7)
+ reg_source_requests.source1 := rs1
+ reg_source_requests.source2 := rs2
+ params.rd := rd
valid_instr := true.B
operate_unit := 0.U
}
- is("b0111011".U) {
+ is(OP_32) {
// addw subw sllw srlw sraw
- when(instr(14, 12) === "b001".U) {
+ when(funct3 === "b001".U) {
// sllw
issue_task.alu_opcode := "b10011".U
- }.elsewhen(instr(14, 12) === "b101".U && instr(30)) {
+ }.elsewhen(funct3 === "b101".U && instr(30)) {
// sraw
issue_task.alu_opcode := "b11011".U
- }.elsewhen(instr(14, 12) === "b101".U) {
+ }.elsewhen(funct3 === "b101".U) {
// srlw
issue_task.alu_opcode := "b11010".U
- }.elsewhen(instr(14, 12) === "b000".U && instr(30)) {
+ }.elsewhen(funct3 === "b000".U && instr(30)) {
// subw
issue_task.alu_opcode := "b10000".U
}.otherwise {
issue_task.alu_opcode := Cat(
1.U(1.W),
- instr(14, 12),
+ funct3,
1.U(1.W)
)
}
- reg_source_requests.source1 := instr(19, 15)
+ reg_source_requests.source1 := rs1
reg_source_requests.source1_read_word := true.B
- reg_source_requests.source2 := instr(24, 20)
- params.rd := instr(11, 7)
+ reg_source_requests.source2 := rs2
+ params.rd := rd
valid_instr := true.B
operate_unit := 0.U
}
- is("b0000011".U) {
+ is(OP_LOAD) {
// Load Memory
- issue_task.lsu_opcode := Cat("b00".U, instr(14, 12))
+ issue_task.lsu_opcode := Cat("b00".U, funct3)
params.immediate := instr(31, 20).asSInt
.pad(64)
.asUInt
- reg_source_requests.source1 := instr(19, 15)
+ reg_source_requests.source1 := rs1
params.source2 := 0.U(data_width.W)
- params.rd := instr(11, 7)
+ params.rd := rd
valid_instr := true.B
operate_unit := 1.U
}
- is("b0100011".U) {
+ is(OP_STOR) {
// Store Memory
- issue_task.lsu_opcode := Cat("b10".U, instr(14, 12))
+ issue_task.lsu_opcode := Cat("b10".U, funct3)
params.immediate := Cat(
instr(31, 25),
instr(11, 7)
).asSInt.pad(64).asUInt
- reg_source_requests.source1 := instr(19, 15)
- reg_source_requests.source2 := instr(24, 20)
+ reg_source_requests.source1 := rs1
+ reg_source_requests.source2 := rs2
valid_instr := true.B
operate_unit := 1.U
}
- is("b1101111".U) {
+ is(OP_JAL) {
// jal
issue_task.branch_opcode := "b00001".U
issue_task.pred_taken := io.instr_bundle.bits.pred_taken
issue_task.recovery_pc := io.instr_bundle.bits.recovery_pc
params.pc := pc
- params.rd := instr(11, 7)
+ params.rd := rd
valid_instr := true.B
- operate_unit := 2.U
+ operate_unit := 3.U
}
- is("b1100111".U) {
+ is(OP_JALR) {
// jalr
issue_task.branch_opcode := "b00011".U
issue_task.pred_taken := io.instr_bundle.bits.pred_taken
issue_task.pred_pc := io.instr_bundle.bits.pred_pc
issue_task.recovery_pc := io.instr_bundle.bits.recovery_pc
params.pc := pc
- params.rd := instr(11, 7)
+ params.rd := rd
- reg_source_requests.source1 := instr(19, 15)
+ reg_source_requests.source1 := rs1
params.immediate := instr(31, 20).asSInt
.pad(64)
.asUInt
valid_instr := true.B
- operate_unit := 2.U
+ operate_unit := 3.U
}
- is("b1100011".U) {
+ is(OP_BRANCH) {
// branch
- issue_task.branch_opcode := Cat(0.U, instr(14, 12), 0.U)
+ issue_task.branch_opcode := Cat(0.U, funct3, 0.U)
issue_task.pred_taken := io.instr_bundle.bits.pred_taken
issue_task.pred_pc := io.instr_bundle.bits.pred_pc
issue_task.recovery_pc := io.instr_bundle.bits.recovery_pc
- reg_source_requests.source1 := instr(19, 15)
- reg_source_requests.source2 := instr(24, 20)
+ reg_source_requests.source1 := rs1
+ reg_source_requests.source2 := rs2
valid_instr := true.B
- operate_unit := 2.U
+ operate_unit := 3.U
+ }
+ is(OP_SYSTEM) {
+ // TODO ecall ebreak xret wfi sfence.vma
+ val func = funct3
+
+ when(func =/= 0.U) {
+ val is_imm = func(2)
+
+ // CSR addr.
+ params.source2 := instr(31, 20)
+ when(rs1 === 0.U && ~is_imm) {
+ // Allow having write side effect.
+ issue_task.misc_opcode := "b01000".U
+ }.otherwise {
+ issue_task.misc_opcode := "b00000".U
+ }
+ when(is_imm) {
+ params.source1 := rs1.pad(64)
+ }.otherwise {
+ reg_source_requests.source1 := rs1
+ }
+ params.immediate := func & "b011".U
+ params.rd := rd
+
+ valid_instr := true.B
+ operate_unit := 2.U
+ }
}
}
}
diff --git a/src/main/scala/markorv/frontend/InstrIssuer.scala b/src/main/scala/markorv/frontend/InstrIssuer.scala
index 002b467..b010909 100644
--- a/src/main/scala/markorv/frontend/InstrIssuer.scala
+++ b/src/main/scala/markorv/frontend/InstrIssuer.scala
@@ -19,6 +19,11 @@ class InstrIssueUnit extends Module {
val params = new DecoderOutParams(64)
})
+ val misc_out = Decoupled(new Bundle {
+ val misc_opcode = UInt(5.W)
+ val params = new DecoderOutParams(64)
+ })
+
val branch_out = Decoupled(new Bundle {
val branch_opcode = UInt(5.W)
val pred_taken = Bool()
@@ -45,16 +50,20 @@ class InstrIssueUnit extends Module {
val occupied_reg = Wire(Bool())
val exec_unit_ready = Wire(Bool())
occupied_reg := false.B
- exec_unit_ready := io.lsu_out.ready && io.alu_out.ready && io.branch_out.ready
+ // Force exec order.
+ exec_unit_ready := io.lsu_out.ready && io.alu_out.ready && io.branch_out.ready && io.misc_out.ready
io.lsu_out.valid := false.B
io.alu_out.valid := false.B
+ io.misc_out.valid := false.B
io.branch_out.valid := false.B
io.lsu_out.bits.lsu_opcode := 0.U
io.lsu_out.bits.params := 0.U.asTypeOf(new DecoderOutParams(64))
io.alu_out.bits.alu_opcode := 0.U
io.alu_out.bits.params := 0.U.asTypeOf(new DecoderOutParams(64))
+ io.misc_out.bits.misc_opcode := 0.U
+ io.misc_out.bits.params := 0.U.asTypeOf(new DecoderOutParams(64))
io.branch_out.bits.branch_opcode := 0.U
io.branch_out.bits.pred_taken := false.B
io.branch_out.bits.pred_pc := 0.U
@@ -101,6 +110,11 @@ class InstrIssueUnit extends Module {
io.lsu_out.bits.lsu_opcode := io.issue_task.bits.lsu_opcode
io.lsu_out.bits.params := params
}.elsewhen(io.issue_task.bits.operate_unit === 2.U && io.acquired) {
+ io.outfire := true.B
+ io.misc_out.valid := true.B
+ io.misc_out.bits.misc_opcode := io.issue_task.bits.misc_opcode
+ io.misc_out.bits.params := params
+ }.elsewhen(io.issue_task.bits.operate_unit === 3.U && io.acquired) {
io.outfire := true.B
io.branch_out.valid := true.B
io.branch_out.bits.branch_opcode := io.issue_task.bits.branch_opcode
diff --git a/tests/asmtst/zicsr.S b/tests/asmtst/zicsr.S
new file mode 100644
index 0000000..a7b048a
--- /dev/null
+++ b/tests/asmtst/zicsr.S
@@ -0,0 +1,12 @@
+li t0, 0x55
+csrrw a0, 0x800, t0
+li t0, 0x0F
+csrrs a0, 0x800, t0
+li t0, 0x0F
+csrrc a0, 0x800, t0
+
+csrrsi a0, 0x800, 0x3
+csrrci a0, 0x800, 0x2
+csrrwi a0, 0x800, 0x1F
+
+csrr a0, 0x800
\ No newline at end of file