M extension ready & verified (to some extent)

master
kaqu 2 years ago
parent 01d3e372a5
commit 13ba194138
  1. 16
      debugger/dbgeval.py
  2. 6
      debugger/qt5dbg.py
  3. 3
      libmodules/core.py
  4. 140
      libmodules/instruction_decode.py
  5. 9
      software/source/testmultiply.c

@ -100,17 +100,27 @@ def disassemble(opcode, pc):
elif f7 == 0x01: # mulhu
msg = "mulhu {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
elif f3 == 0x04:
msg = "xor {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
if f7 == 0x00:
msg = "xor {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
elif f7 == 0x01: # div
msg = "div {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
elif f3 == 0x05:
if f7 == 0x20:
msg = "sra {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
elif f7 == 0x01: # divu
msg = "divu {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
else:
msg = "srl {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
elif f3 == 0x06:
msg = "or {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
if f7 == 0x00:
msg = "or {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
elif f7 == 0x01: # rem
msg = "rem {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
elif f3 == 0x07:
if f7 == 0x00: # and rd, rs1, rs2
msg = "and {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
msg = "and {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
elif f7 == 0x01: # remu
msg = "remu {0},{1},{2}".format(x_description[rd], x_description[rs1], x_description[rs2])
elif op == 0x63:
if f3 == 0x00:
msg = "beq {0},{1},{2}".format(x_description[rs1], x_description[rs2], hex((pc+imm_b) & 0xFFFFFFFF))

@ -250,14 +250,14 @@ class dbgWindow(QMainWindow):
self.qpbLUCache.setText(msg)
i32mode = self.wb.regs.risq5ext_b32mode.read()
msg = "Mode: 0x{:08X} (0000 0000 0".format(i32mode)
msg = "Mode: 0x{:08X} (---- ---- -".format(i32mode)
msg = msg + flag(i32mode & 64, 'T', '-') + flag(i32mode & 32, 'E', '-') + flag(i32mode & 16, 'P ', '- ')
msg = msg + flag(i32mode & 8, 'B', '-') + flag(i32mode & 4, 'S', '-') + flag(i32mode & 2, 'N', '-') + flag(i32mode & 1, 'R', '-') + ")"
self.qpbMode.setText(msg)
i32status = self.wb.regs.risq5ext_b32status.read()
msg = "Status:0x{:08X} (0000 ".format(i32status)
msg = msg + flag(i32status & 2048, 'T', '-') + flag(i32status & 1024, 'E', '-')
msg = "Status:0x{:08X} (---".format(i32status)
msg = msg + flag(i32status & 4096, '0 ', '- ') + flag(i32status & 2048, 'T', '-') + flag(i32status & 1024, 'E', '-')
msg = msg + flag(i32status & 512, '>', '-') + flag(i32status & 256, '< ', '- ') + flag(i32status & 128,'>', '-') + flag(i32status & 64, '<', '-')
msg = msg + flag(i32status & 32, 'V', '-') + flag(i32status & 16, '>', '-') + " " + flag(i32status & 8, '<', '-') + flag(i32status & 4, 'I', '-') + flag(i32status & 2, 'B', '-') + flag(i32status & 1, 'V', '-') + ")"
self.qpbStatus.setText(msg)

@ -91,7 +91,8 @@ class Risq5Core(Module, AutoCSR, AutoDoc, ModuleDoc):
CSRField("BeyondCacheI", size=1, description="Bit[9]: Jump beyond L1 cache flag"),
CSRField("MMExternalInterrupt", size=1, description="Bit[10]: Machine external interrupt"),
CSRField("MMTimerInterrupt", size=1, description="Bit[11]: Machine timer interrupt"),
CSRField("NotYetUsed", size=20, description="*Reserved*"),
CSRField("DivByZero", size=1, description="Bit[12]: Division by zero indication"),
CSRField("NotYetUsed", size=19, description="*Reserved*"),
],
description="""
Status word

@ -65,6 +65,15 @@ class Risq5Decoder(Module):
self.DECODE_loaddelay = Signal(32, reset_less=True) # TODO: shorter! Load unit cache data load delay (8-bit: 24 for RAM)
self.opcode_invalid = Signal(reset_less=True)
# M extension: div/divu/rem/remu instruction stores
self.div_a = Signal((33,True), reset_less=True)
self.div_b = Signal((33,True), reset_less=True)
self.div_sign = Signal()
self.div_instruction = Signal(3, reset_less=True)
self.div_scaled_divisor = Signal(32, reset_less=True)
self.div_remain = Signal(32, reset_less=True)
self.div_result = Signal(32, reset_less=True)
self.div_multiple = Signal(32, reset_less=True)
DECODE_fsm = FSM(reset_state="DECODE_IDLE") # FSM starts idling ...
self.submodules += DECODE_fsm
@ -77,6 +86,7 @@ class Risq5Decoder(Module):
NextValue(self.write, 0), # Trigger write rd reset
NextValue(self.SUStore, 0), # Trigger store rs2 reset
NextValue(self.opcode_invalid, 0), # Reset invalid opcode indication
NextValue(self.div_instruction, 0), # M extension divide instruction special
NextState("DECODE_READ")
)
)
@ -118,39 +128,53 @@ class Risq5Decoder(Module):
NextValue(regs.rd_wrport.dat_w, regs.xs1s + regs.xs2s),
).Elif(regs.f7 == 0x20, # sub rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1s - regs.xs2s),
).Elif(regs.f7 == 0x01, # (M extension) mul rd, rs1, rs2
).Elif(regs.f7 == 0x01, # mul rd, rs1, rs2 (M extension)
NextValue(regs.rd_wrport.dat_w, regs.rd_mul64s[0:32]),
),
).Elif(regs.f3 == 0x01, # sll/mulh
If(regs.f7 == 0x00, # sll rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1u << regs.xs2u[0:5]),
).Elif(regs.f7 == 0x01, # mulh rd, rs1, rs2 (both signed)
).Elif(regs.f7 == 0x01, # mulh rd, rs1, rs2 (both signed, M extension)
NextValue(regs.rd_wrport.dat_w, regs.rd_mul64s[32:64]),
)
).Elif(regs.f3 == 0x02, # slt/mulhsu
If(regs.f7 == 0x00, # slt rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1s < regs.xs2s),
).Elif(regs.f7 == 0x01, # mulhsu rd, rs1, rs2 (rs1 signed, rs2 unsigned)
).Elif(regs.f7 == 0x01, # mulhsu rd, rs1, rs2 (rs1 signed, rs2 unsigned, M extension)
NextValue(regs.rd_wrport.dat_w, regs.rd_mul64su[32:64]),
)
).Elif(regs.f3 == 0x03, # sltu/mulhu
If(regs.f7 == 0x00, # sltu rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1u < regs.xs2u), # TODO: Compare unsigned/signed ok?
).Elif(regs.f7 == 0x01, # mulhu rd, rs1, rs2 (both unsigned)
).Elif(regs.f7 == 0x01, # mulhu rd, rs1, rs2 (both unsigned, M extension)
NextValue(regs.rd_wrport.dat_w, regs.rd_mul64u[32:64]),
)
).Elif(regs.f3 == 0x04, # xor rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1u ^ regs.xs2u),
).Elif(regs.f3 == 0x05, # sra
If(regs.f7[5], # sra rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1s >> regs.xs2u[0:5]),
).Else( # srl rd, rs1, rs2
).Elif(regs.f3 == 0x04, # xor/div
If(regs.f7 == 0x00, # xor rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1u ^ regs.xs2u),
).Elif(regs.f7 == 0x01, # div rd, rs1, rs2 (signed, M extension)
NextValue(self.div_instruction, 1)
)
).Elif(regs.f3 == 0x05, # srl/divu/sra
If(regs.f7 == 0x00, # srl rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1u >> regs.xs2u[0:5]),
),
).Elif(regs.f3 == 0x06, # or rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1u | regs.xs2u),
).Elif(regs.f3 == 0x07, # and rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1u & regs.xs2u),
).Elif(regs.f7 == 0x01, # divu rd, rs1, rs2 (unsigned, M extension)
NextValue(self.div_instruction, 2)
).Elif(regs.f7 == 0x20, # sra rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1s >> regs.xs2u[0:5]),
)
).Elif(regs.f3 == 0x06, # or/rem
If(regs.f7 == 0x00, # or rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1u | regs.xs2u),
).Elif(regs.f7 == 0x01, # rem rd, rs1, rs2 (signed, M extension)
NextValue(self.div_instruction, 3)
)
).Elif(regs.f3 == 0x07, # and/remu
If(regs.f7 == 0x00, # and rd, rs1, rs2
NextValue(regs.rd_wrport.dat_w, regs.xs1u & regs.xs2u),
).Elif(regs.f7 == 0x01, # remu rd, rs1, rs2 (unsigned, M extension)
NextValue(self.div_instruction, 4)
)
),
NextValue(self.write, 1), # Trigger write rd
).Elif(regs.op == 0x63, # B-Type
@ -294,7 +318,37 @@ class Risq5Decoder(Module):
NextValue(self.next, 1), # Indicate ready state to ALU
NextState("DECODE_IDLE") # No write!
).Else(
If(self.LUReload, # Load unit engaging? (May also be loading for writing!)
If(self.div_instruction != 0, # M extension divide instruction?
If(regs.xs2s == 0x0, # RISC-V: Doesn't raise exception div/0!
NextValue(statusreg.storage[12], 1), # Indicate division by zero (TODO: Remove later!)
NextValue(self.next, 1), # Next instruction may come now!
NextState("DECODE_IDLE")
).Else( # Operation possible
NextValue(statusreg.storage[12], 0), # Reset division by zero (TODO: Remove later!)
If((self.div_instruction == 1) | (self.div_instruction == 3), # div/rem (signed operations)
If(regs.xs1s[31], # Dividend negative?
NextValue(self.div_a, -regs.xs1s)
).Else( # Positive
NextValue(self.div_a, regs.xs1s)
),
If(regs.xs2s[31], # Divisor negative?
NextValue(self.div_b, -regs.xs2s)
).Else( # Positive
NextValue(self.div_b, regs.xs2s)
),
If((regs.xs1s[31] & ~regs.xs2s[31]) | (~regs.xs1s[31] & regs.xs2s[31]), # Sign tracker ...
NextValue(self.div_sign, 1)
).Else( # Reset if nec.
NextValue(self.div_sign, 0)
)
).Else( # Unsigned operation
NextValue(self.div_a, regs.xs1s),
NextValue(self.div_b, regs.xs2s),
NextValue(self.div_sign, 0)
),
NextState("DECODE_DIV1")
)
).Elif(self.LUReload, # Load unit engaging? (May also be loading for writing!)
NextValue(self.LUReload, 0), # Kill trigger 1st
NextValue(LU_CacheValid, 0), # & enforce cache reload (after address has been stored!)
NextState("DECODE_MEMWAIT")
@ -413,6 +467,60 @@ class Risq5Decoder(Module):
)
)
# M extension: div/divu calculation engine
DECODE_fsm.act("DECODE_DIV1",
If(((self.div_instruction == 1) | (self.div_instruction == 3)) & (self.div_a < self.div_b), # div/rem (signed operations)
NextValue(self.div_result, 0), # Useless to calculate if a < b!
NextValue(self.div_remain, self.div_a),
NextValue(self.div_multiple, 0), # Indicate 'storage only' to DECODE_DIV3 stage
NextState("DECODE_DIV3")
).Else( # Regular calculation (unsigned)
NextValue(self.div_remain, self.div_a[0:32]),
NextValue(self.div_scaled_divisor, self.div_b[0:32]),
NextValue(self.div_result, 0),
NextValue(self.div_multiple, 1),
NextState("DECODE_DIV2")
)
)
DECODE_fsm.act("DECODE_DIV2",
If(~self.div_scaled_divisor[31], # High bit set? Loop!
NextValue(self.div_scaled_divisor, self.div_scaled_divisor + self.div_scaled_divisor),
NextValue(self.div_multiple, self.div_multiple + self.div_multiple),
).Else( # Loop exit
NextState("DECODE_DIV3")
)
)
DECODE_fsm.act("DECODE_DIV3",
If(self.div_multiple != 0, # Loop until ...
If(self.div_remain >= self.div_scaled_divisor,
NextValue(self.div_remain, self.div_remain - self.div_scaled_divisor),
NextValue(self.div_result, self.div_result + self.div_multiple),
),
NextValue(self.div_scaled_divisor, self.div_scaled_divisor >> 1),
NextValue(self.div_multiple, self.div_multiple >> 1),
).Else( # loop exit
If(self.div_instruction == 1, # div (signed)
If(self.div_sign, # Keep sign if nec.
NextValue(regs.rd_wrport.dat_w, -self.div_result),
).Else(
NextValue(regs.rd_wrport.dat_w, self.div_result),
)
).Elif(self.div_instruction == 2, # divu (unsigned)
NextValue(regs.rd_wrport.dat_w, self.div_result),
).Elif(self.div_instruction == 3, # rem (signed)
If(regs.xs1s < 0, # Remainder keeps sign of dividend
NextValue(regs.rd_wrport.dat_w, -self.div_remain), # TODO: Verify!
).Else(
NextValue(regs.rd_wrport.dat_w, self.div_remain),
)
).Elif(self.div_instruction == 4, # remu (unsigned)
NextValue(regs.rd_wrport.dat_w, self.div_remain),
),
NextValue(self.div_instruction, 0), # Indicate processing done, rd prepared ...
NextState("DECODE_WRITE")
)
)
def Risq5Decoder_testbench(r5d):
print("----- RISQ5 decoder testbench -----")

@ -12,11 +12,16 @@ static void start(void)
lui t0,0xFFFFF # 0xffffffff * 0xffffffff \n\
ori t0,t0,-1 # \n\
mv t1,t0 # both are negative \n\
repeat: mulh t2,t0,t1 # => 0xFFFFFFFE/00000001 \n\
repeat: divu t2,t0,t1 # => 0xFFFFFFFE/00000001 \n\
remu t3,t0,t1 # \n\
div t2,t0,t1 # \n\
rem t3,t0,t1 # \n\
beq t3,t3,repeat # \n\
repeat2: mulh t2,t0,t1 # => 0xFFFFFFFE/00000001 \n\
mulhu t2,t0,t1 # \n\
mulhsu t2,t0,t1 # \n\
mul t3,t0,t1 # \n\
beq t3,t3,repeat # \n\
beq t3,t3,repeat2 # \n\
nop # \n\
li t0,0x123 # x = 123 * 2 \n\
li t1,0x2 # ... \n\

Loading…
Cancel
Save