#!/usr/bin/env python3 # # instruction_decode.py # # Risq5 instruction decode phase # # History: # -------- # 09.01.21/KQ Initial version # from migen import * from migen.fhdl.specials import Memory from litex.soc.interconnect.csr import * from litex.soc.integration.doc import AutoDoc, ModuleDoc from libmodules.register_file import Risq5RegisterFile import libmodules.risq5defs as risq5defs class Risq5Decoder(Module): """ Risq5 instruction decode phase logic """ def __init__(self, regs=None, modereg=None, statusreg=None, L1CacheOffset=None, L1CacheSize=32, LU_CacheWait=24, LU_CacheValid=None, LUCache=None, SU_Unit=None, isa_extensions=0x40000100): assert isinstance(regs, Risq5RegisterFile) self.start = Signal() # Start decoding signal self.next = Signal() # Signal readyness ... self.L1Reload = Signal() # Signal L1 cache reload required self.LUReload = Signal() # Signal LU cache reload required self.LUByteID = Signal(3, reset_less=True) # Uneven adressing remainder (0..3=byte, 4..5=halfword, 6=word) self.SUStore = Signal() # Signal SU to store a value self.SUByteID = Signal(3, reset_less=True) # Uneven adressing remainder (0..3=byte, 4..5=halfword, 6=not used/direct write) self.write = Signal() # Do a write (local register) self.L1Below = Signal(reset_less=True) self.L1Beyond = Signal(reset_less=True) # Local cache boundaries (only valid w/ branches!) self.comb += [ # Compensate L1CacheOffset +1! (9-bit->13-bit sign extended!) self.L1Below.eq(((Cat(L1CacheOffset,0,0,0,0) + 2 + (regs.imm_b >> 2)) < 1)), self.L1Beyond.eq((Cat(L1CacheOffset,0,0,0,0) + (regs.imm_b >> 2)) > (L1CacheSize - 1)) ] self.L1BelowJ = Signal(reset_less=True) self.L1BeyondJ = Signal(reset_less=True) # Local cache boundaries (only valid w/ jumps!) self.comb += [ # Compensate L1CacheOffset +1! (9-bit->20-bit sign extended!) self.L1BelowJ.eq(((Cat(L1CacheOffset,0,0,0,0,0,0,0,0,0,0,0) + 2 + (regs.imm_j >> 2)) < 1)), self.L1BeyondJ.eq((Cat(L1CacheOffset,0,0,0,0,0,0,0,0,0,0,0) + (regs.imm_j >> 2)) > (L1CacheSize - 1)) ] self.L1BelowI = Signal(reset_less=True) self.L1BeyondI = Signal(reset_less=True) # Local cache boundaries (only valid w/ jumps!) self.IHelper = Signal((32,True), reset_less=True) # TEST self.comb += [ # Compensate L1CacheOffset +1! (9-bit->32-bit sign extended!) self.IHelper.eq(((regs.xs1u - regs.pc) + regs.imm_i)), # TEST: Jump offset in bytes self.L1BelowI.eq((Cat(L1CacheOffset,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) + 2 + (self.IHelper >> 2)) < 1), self.L1BeyondI.eq((Cat(L1CacheOffset,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) + (self.IHelper >> 2)) > (L1CacheSize - 1)) ] self.sync += [ # Indicate externally cache status ... statusreg.storage[3].eq(self.L1Below), statusreg.storage[4].eq(self.L1Beyond), statusreg.storage[6].eq(self.L1BelowJ), statusreg.storage[7].eq(self.L1BeyondJ), statusreg.storage[8].eq(self.L1BelowI), statusreg.storage[9].eq(self.L1BeyondI) ] 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) DECODE_fsm = FSM(reset_state="DECODE_IDLE") # FSM starts idling ... self.submodules += DECODE_fsm self.DECODE_state = Signal(9, reset_less=True) # Debugging support DECODE_fsm.act("DECODE_IDLE", NextValue(self.DECODE_state, 0), If(self.start, # Do the job when triggered #NextValue(self.next, 0), # Indicate not yet there ... -> Reset @ top level! NextValue(self.start, 0), # Once! 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 NextState("DECODE_READ") ) ) DECODE_fsm.act("DECODE_READ", NextValue(self.DECODE_state, 1), # ------ Actual decoder action ... ---------------------------------------- NextValue(statusreg.storage[2], 0), # Reset illegal instruction flag # 1. Ok, instruction seems to be valid, now to RV32I instruction processing If((regs.op == 0x73) & (regs.f3 == 0x00), # Exceptions If(regs.opcode == 0x30200073, # mret (exception return) If(regs.csr[risq5defs.CSR_mcause] == risq5defs.MCAUSE_MACHINE_EXTERNAL_INTERRUPT, NextValue(statusreg.storage[10], 0), # Edge store reset ).Elif(regs.csr[risq5defs.CSR_mcause] == risq5defs.MCAUSE_MACHINE_TIMER_INTERRUPT, NextValue(statusreg.storage[11], 0), # Edge store reset ), NextValue(regs.csr[risq5defs.CSR_mcause], 0), # Reset machine mode exception indication NextValue(regs.csr[risq5defs.CSR_mstatus][risq5defs.MSTATUS_MPIE], 0), # Reset pending interrupt indication NextValue(regs.csr[risq5defs.CSR_mie], regs.csr[risq5defs.CSR_mip]), # Restore last interrupt flags NextValue(regs.pc, regs.csr[risq5defs.CSR_mepc] - 4), # Restore (former) PC value (+4 will be added autom.!) ).Elif(regs.opcode == 0x00100073, # ebreak (breakpoint) -> Switch to single step, subtract 4 compensation! NextValue(regs.csr[risq5defs.CSR_mcause], risq5defs.MCAUSE_BREAKPOINT), NextValue(modereg.storage[1], 0), # Switch to single step NextValue(regs.pc, regs.pc - 4), # Compensate instruction forwarding (+4) (impossible to exit!) ).Else( # ecall (raise exception), will require exception vector setting! NextValue(regs.csr[risq5defs.CSR_mcause], risq5defs.MCAUSE_MACHINE_SW_INTERRUPT), NextValue(regs.csr[risq5defs.CSR_mstatus][risq5defs.MSTATUS_MPIE], regs.csr[risq5defs.CSR_mstatus][risq5defs.MSTATUS_MIE]), # Store pending interrupt indication NextValue(regs.csr[risq5defs.CSR_mip], regs.csr[risq5defs.CSR_mie]), # Store current interrupt flags NextValue(regs.csr[risq5defs.CSR_mepc], regs.pc), # Store current PC value NextValue(regs.pc, regs.csr[risq5defs.CSR_mtvec] - 4), # Adjust PC to trap vector (w/ compensation) ), NextValue(self.L1Reload, 1), # Enforce cache reload NextValue(self.next, 1), # Next instruction may come now! NextState("DECODE_IDLE") # No write! ).Else( # Regular instructions ... If(regs.op == 0x33, # R-Type If(regs.f3 == 0x00, # add/sub/mul If(regs.f7 == 0x00, # add rd, rs1, rs2 (all indexes prep'd already!) 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 NextValue(regs.rd_wrport.dat_w, regs.rd_mul64s[0:31]), ), ).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) NextValue(regs.rd_wrport.dat_w, regs.rd_mul64s[32:63]), ) ).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) NextValue(regs.rd_wrport.dat_w, regs.rd_mul64us[32:63]), ) ).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) NextValue(regs.rd_wrport.dat_w, regs.rd_mul64u[32:63]), ) ).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 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), ), NextValue(self.write, 1), # Trigger write rd ).Elif(regs.op == 0x63, # B-Type If(((regs.f3 == 0x00) & (regs.xs1s == regs.xs2s)) # beq xs1, xs2, label \ |((regs.f3 == 0x01) & (regs.xs1u != regs.xs2u)) # bne xs1, xs2, label (unsigned) \ |((regs.f3 == 0x04) & (regs.xs1s < regs.xs2s)) # blt xs1, xs2, label (signed) \ |((regs.f3 == 0x05) & (regs.xs1s >= regs.xs2s)) # bge xs1, xs2, label (signed variant) \ |((regs.f3 == 0x06) & (regs.xs1u < regs.xs2u)) # bltu xs1, xs2, label (unsigned) \ |((regs.f3 == 0x07) & (regs.xs1u >= regs.xs2u)), # bgeu xs1, xs2, label (unsigned) NextValue(regs.pc, regs.pc - 4 + regs.imm_b), # jump! # Att.: Compensate L1CacheOffset + 1! If(self.L1Below | self.L1Beyond, # Cache exceeded? NextValue(self.L1Reload, 1) # Enforce cache reload ).Else( # Cache still valid, adjust Offset (-1!) NextValue(L1CacheOffset, L1CacheOffset + (regs.imm_b >> 2) - 1) ) ) ).Elif(regs.op == 0x23, # S-Type If(regs.f3 == 0x00, # sb rs2, imm_offset(xs1) NextValue(SU_Unit.b32Address.storage, (regs.xs1u + regs.imm_s) & 0xFFFFFFFC), # Adjust DRAM target address NextValue(self.SUByteID, (regs.xs1u + regs.imm_s)[0:2]), # Byte offset (type 0-3) NextValue(regs.LUAddress, (regs.xs1u + regs.imm_s) & 0xFFFFFFFC), # But load word first (word aligned) NextValue(self.LUByteID, 6), # Type: Word (loading!) NextValue(self.LUReload, 1), # Enforce cache reload (for now: allways!) ).Elif(regs.f3 == 0x01, # sh rs2, imm_offset(xs1) NextValue(SU_Unit.b32Address.storage, (regs.xs1u + regs.imm_s) & 0xFFFFFFFC), # Adjust DRAM target address NextValue(self.SUByteID, 4+(regs.xs1u + regs.imm_s)[1]), # Half word offset (type 4,5) NextValue(regs.LUAddress, (regs.xs1u + regs.imm_s) & 0xFFFFFFFC), # But load word first (word aligned) NextValue(self.LUByteID, 6), # Type: Word (loading!) NextValue(self.LUReload, 1), # Enforce cache reload (for now: allways!) ).Elif(regs.f3 == 0x02, # sw rs2, imm_offset(xs1) NextValue(SU_Unit.b32Address.storage, regs.xs1u + regs.imm_s), # Adjust DRAM target address NextValue(SU_Unit.bData, regs.xs2u), # Pick actual value to store (from rs2) & load SU NextValue(self.SUByteID, 6), # Type: Word NextValue(self.SUStore, 1), # Enforce store unit engagement (for now: allways!) ) ).Elif(regs.op == 0x03, # I-Type (1) If(regs.f3[0:2] == 0x00, # lb/lbu rd, imm_offset(xs1) NextValue(regs.LUAddress, regs.xs1u + regs.imm_i), # Calculate memory address: [rs1]+offset NextValue(self.LUByteID, (regs.xs1u + regs.imm_i)[0:2]), # TODO: Identify byte offset or fail?! ).Elif(regs.f3[0:2] == 0x01, # lh/lhu rd, imm_offset(xs1) NextValue(regs.LUAddress, regs.xs1u + regs.imm_i), # Calculate memory address: [rs1]+offset NextValue(self.LUByteID, 4+(regs.xs1u + regs.imm_i)[1]), # TODO: 00b,10b,100b => low/high Identify halfword offset or fail?! ).Elif(regs.f3[0:2] == 0x02, # lw/lwu rd, imm_offset(xs1) NextValue(regs.LUAddress, regs.xs1u + regs.imm_i), # Calculate memory address: [rs1]+offset NextValue(self.LUByteID, 6), # Type: Word ), NextValue(self.LUReload, 1), # Enforce cache reload (for now: allways!) ).Elif(regs.op == 0x13, # I-Type (2) If(regs.f3 == 0x00, # addi rd, rs1, imm_i NextValue(regs.rd_wrport.dat_w, regs.xs1s + regs.imm_i), # Calc. result rs1+imm ).Elif(regs.f3 == 0x01, # slli rd, rs1, imm_i NextValue(regs.rd_wrport.dat_w, regs.xs1u << regs.imm_i[0:5]), ).Elif(regs.f3 == 0x02, # slti rd, rs1, imm_i NextValue(regs.rd_wrport.dat_w, regs.xs1s < regs.imm_i), ).Elif(regs.f3 == 0x03, # sltiu rd, rs1, imm_i TODO: Compares unsigned/signed ok? NextValue(regs.rd_wrport.dat_w, regs.xs1u < regs.imm_i), ).Elif(regs.f3 == 0x04, # xori rd, rs1, imm_i NextValue(regs.rd_wrport.dat_w, regs.xs1u ^ regs.imm_i), ).Elif(regs.f3 == 0x05, # srai, srli If(regs.f7[5], # srai rd, rs1, imm_i NextValue(regs.rd_wrport.dat_w, regs.xs1s >> regs.imm_i[0:5]), ).Else( # srli rd, rs1, imm_i NextValue(regs.rd_wrport.dat_w, regs.xs1u >> regs.imm_i[0:5]), ) ).Elif(regs.f3 == 0x06, # ori rd, rs1, imm_i NextValue(regs.rd_wrport.dat_w, regs.xs1u | regs.imm_i), ).Elif(regs.f3 == 0x07, # andi rd, rs1, imm_i NextValue(regs.rd_wrport.dat_w, regs.xs1u & regs.imm_i), ), NextValue(self.write, 1), # Trigger write rd # fence & fence.i memory & i/o read/write ordering observation not implemented/ignored ... ).Elif(regs.op == 0x0F, # I-Type (3) fence/fence.i NextValue(self.DECODE_state, 0x0F), # No action at all! ).Elif((regs.op == 0x73) & (regs.f3 != 0x00), # I-Type (4) CSR access # CSRs: mstatus,mip,mie,mcause,mtvec,mtval,mepc,mscratch (Machine mode [level 3] registers) # misa,mvendorid,marchid,mimpid,mhartid (Identification registers) NextValue(regs.rd_wrport.dat_w, regs.csr[regs.csrindex]), # rd (former value) If(regs.csrindex < risq5defs.CSR_misa, # Write only non-static regs! If(regs.f3 == 0x03, # csrrc rd, csr, rs1 (csr read & clear) NextValue(regs.csr[regs.csrindex], regs.csr[regs.csrindex] & ~regs.xs1u), # csr (new value) ).Elif(regs.f3 == 0x07, # csrrci rd, csr, imm_i4 (csr read & clear immediate) NextValue(regs.csr[regs.csrindex], regs.csr[regs.csrindex] & ~regs.rs1), # csr (new value) ).Elif(regs.f3 == 0x02, # csrrs rd, , rs1 (csr read & set) NextValue(regs.csr[regs.csrindex], regs.csr[regs.csrindex] | regs.xs1u), # csr (new value) ).Elif(regs.f3 == 0x06, # csrrsi rd, csr, imm_i4 (csr read & set immediate) NextValue(regs.csr[regs.csrindex], regs.csr[regs.csrindex] | regs.rs1), # csr (new value) ).Elif(regs.f3 == 0x01, # csrrw rd, csr, rs1 (csr read & write) NextValue(regs.csr[regs.csrindex], regs.xs1u), # csr (new value) ).Elif(regs.f3 == 0x05, # csrrwi rd, csr, imm_i4 (csr read & write immediate) NextValue(regs.csr[regs.csrindex], regs.rs1), # csr (new value) ), ), NextValue(self.write, 1), # Trigger write rd ).Elif(regs.op == 0x37, # U-Type (1): lui rd, imm[31:12] (load unsigned int) NextValue(regs.rd_wrport.dat_w, regs.imm_u << 12), # Shift to upper 12-bit NextValue(self.write, 1), # Trigger write rd ).Elif(regs.op == 0x17, # U-Type (2) auipc rd, imm[31:12] (Add upper imm. to pc) NextValue(regs.rd_wrport.dat_w, regs.pc + (regs.imm_u << 12)), # Shift to upper 12-bit NextValue(self.write, 1), # Trigger write rd ).Elif(regs.op == 0x6F, # J-Type (1) jal rd, offset NextValue(regs.rd_wrport.dat_w, regs.pc + 4), # x[xd] = pc+4 NextValue(self.write, 1), # Trigger write rd NextValue(regs.pc, regs.pc - 4 + regs.imm_j), # jump (w/ compensation!) # Att.: Compensate L1CacheOffset + 1! If(self.L1BelowJ | self.L1BeyondJ, # Cache exceeded? NextValue(self.L1Reload, 1), # Enforce cache reload ).Else( # Cache still valid, adjust Offset (-1!) NextValue(L1CacheOffset, L1CacheOffset + (regs.imm_j >> 2) - 1) ) ).Elif(regs.op == 0x67, # I-Type: jalr rd, imm(rs1) #If(regs.f3 == 0x00, NextValue(regs.rd_wrport.dat_w, regs.pc + 4), # x[xd] = pc+4 NextValue(self.write, 1), # Trigger write rd NextValue(regs.pc, (regs.xs1u - 4 + regs.imm_i) & ~1), # jump (w/ compensation!) # Att.: Compensate L1CacheOffset + 1! If(self.L1BelowI | self.L1BeyondI, # Cache exceeded? NextValue(self.L1Reload, 1), # Enforce cache reload ).Else( # Cache still valid, adjust Offset (-1!) NextValue(L1CacheOffset, L1CacheOffset + (self.IHelper >> 2) - 1) ), #) # TODO: Maybe RISC-V extensions ... ).Else( # Undecodeable operations # Test for illegal instruction -> Illegal instruction trap/halt NextValue(regs.pc, regs.pc - 4), # Stick to current instruction (i.e. compensate)! NextValue(self.L1Reload, 1), # Enforce cache reload NextValue(self.opcode_invalid, 1), # Set invalid opcode indication ), NextState("DECODE_WRITE") # Make sure rd can be written (if nec.) ) ) DECODE_fsm.act("DECODE_WRITE", NextValue(self.DECODE_state, 2), If(self.opcode_invalid, # Invalid opcode detected? #NextValue(regs.csr[risq5defs.CSR_mcause], risq5defs.MCAUSE_ILLEGAL_INSTRUCTION), # TODO: Make use of trap NextValue(statusreg.storage[2], 1), # Indicate illegal instruction (TODO: Remove later!) NextValue(modereg.storage[1], 0), # Reset 'no single stepping' flag! Thus halting ... 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!) NextValue(self.LUReload, 0), # Kill trigger 1st NextValue(LU_CacheValid, 0), # & enforce cache reload (after address has been stored!) NextState("DECODE_MEMWAIT") ).Elif(self.SUStore, # Store unit engaging? NextValue(self.SUStore, 0), # Kill trigger 1st NextValue(SU_Unit.bEnable.storage, 1), # Start writing to DRAM NextState("DECODE_WRITEWAIT") ).Else( # No load no more ... If(self.write & (regs.rd != 0), # Do NOT write to X0 (never! period!) NextValue(regs.rd_wrport.we, 1), # Write value enable (delayed) ), NextState("DECODE_READY") # Have register write being processed before continuing ... ) ) ) DECODE_fsm.act("DECODE_READY", NextValue(regs.rd_wrport.we, 0), # Kill WE enable! NextState("DECODE_READY2") ) DECODE_fsm.act("DECODE_READY2", # ------ Indicate readyness ----------------------------------------------- NextValue(self.next, 1), # Next instruction may come now! NextState("DECODE_IDLE") ) # ---------- Load unit (LU) busy now ------------------------------------------ DECODE_fsm.act("DECODE_MEMWAIT", NextValue(self.DECODE_state, 3), If(LU_CacheValid, # Ok, cache loaded (but wait ...) NextValue(self.DECODE_loaddelay, 0), # Reset load delay NextState("DECODE_MEMWAIT2") ) ) DECODE_fsm.act("DECODE_MEMWAIT2", NextValue(self.DECODE_state,4), If(self.DECODE_loaddelay > LU_CacheWait, # 24 ok (but why?) If(regs.op == 0x23, # Actually for S-Type storing? NextState("DECODE_PREPARESTORE") # Data now avail within LUCache.b32Data.storage ).Else( If(self.LUByteID > 5, # No byte selection, 32-bit word type! If(regs.op == 0x23, # Actually for S-Type storing? NextState("DECODE_PREPARESTORE") # Data now avail within LUCache.b32Data.storage ).Else( NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage), # Load actual value for xd (rd index already set) ) ).Elif(self.LUByteID == 0, # Byte 0 If(regs.f3[2] | ~LUCache.b32Data.storage[7], # Unsigned or positive anyway NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage[0:8]), # Load byte value for xd (rd index already set) ).Else( # Signed & negative NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage[0:8] | 0xFFFFFF00), # Load byte sign-extended ) ).Elif(self.LUByteID == 1, # Byte 1 If(regs.f3[2] | ~LUCache.b32Data.storage[15], # Unsigned or positive anyway NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage[8:16]), # Load byte value for xd (rd index already set) ).Else( # Signed & negative NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage[8:16] | 0xFFFFFF00), # Load byte sign-extended ) ).Elif(self.LUByteID == 2, # Byte 2 If(regs.f3[2] | ~LUCache.b32Data.storage[23], # Unsigned or positive anyway NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage[16:24]), # Load byte value for xd (rd index already set) ).Else( # Signed & negative NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage[16:24] | 0xFFFFFF00), # Load byte sign-extended ) ).Elif(self.LUByteID == 3, # Byte 3 If(regs.f3[2] | ~LUCache.b32Data.storage[31], # Unsigned or positive anyway NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage[24:32]), # Load byte value for xd (rd index already set) ).Else( # Signed & negative NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage[24:32] | 0xFFFFFF00), # Load byte sign-extended ) ).Elif(self.LUByteID == 4, If(regs.f3[2] | ~LUCache.b32Data.storage[15], # Unsigned or positive anyway NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage[0:16]), # Load byte value for xd (rd index already set) ).Else( # Signed & negative NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage[0:16] | 0xFFFF0000), # Load byte sign-extended ) ).Elif(self.LUByteID == 5, If(regs.f3[2] | ~LUCache.b32Data.storage[31], # Unsigned or positive anyway NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage[16:32]), # Load byte value for xd (rd index already set) ).Else( # Signed & negative NextValue(regs.rd_wrport.dat_w, LUCache.b32Data.storage[16:32] | 0xFFFF0000), # Load byte sign-extended ) ), NextValue(self.write, 1), # Indicate WRITE (rd) validity (now ready!) NextState("DECODE_WRITE") # Load delay for opcode cache is next ) ).Else( # Time not yet elapsed ... NextValue(self.DECODE_loaddelay, self.DECODE_loaddelay + 1), ) ) #--------- Store Unit ---------------------------------------- DECODE_fsm.act("DECODE_PREPARESTORE", If(self.SUByteID == 0, # Byte #0 NextValue(SU_Unit.bData, (LUCache.b32Data.storage & 0xFFFFFF00) | regs.xs2u[0:8]), ).Elif(self.SUByteID == 1, # Byte #1 NextValue(SU_Unit.bData, (LUCache.b32Data.storage & 0xFFFF00FF) | (regs.xs2u[0:8] << 8)), ).Elif(self.SUByteID == 2, # Byte #2 NextValue(SU_Unit.bData, (LUCache.b32Data.storage & 0xFF00FFFF) | (regs.xs2u[0:8] << 16)), ).Elif(self.SUByteID == 3, # Byte #3 NextValue(SU_Unit.bData, (LUCache.b32Data.storage & 0x00FFFFFF) | (regs.xs2u[0:8] << 24)), ).Elif(self.SUByteID == 4, # Half word low NextValue(SU_Unit.bData, (LUCache.b32Data.storage & 0xFFFF0000) | regs.xs2u[0:16]), ).Elif(self.SUByteID == 5, # Half word high NextValue(SU_Unit.bData, (LUCache.b32Data.storage & 0x0000FFFF) | (regs.xs2u[0:16] << 16)), ), # Type 6 omitted (can be written straight forward=faster!) NextValue(self.SUStore, 1), # Enforce store unit engagement (for now: allways!) NextState("DECODE_WRITE") # Start writing value ), DECODE_fsm.act("DECODE_WRITEWAIT", NextValue(self.DECODE_state, 5), If(SU_Unit.bValid.storage, # Ok, stored NextValue(SU_Unit.bEnable.storage, 0), # Stop writing to DRAM NextValue(self.next, 1), # Next instruction may come now! NextState("DECODE_IDLE") ) ) def Risq5Decoder_testbench(r5d): print("----- RISQ5 decoder testbench -----") if __name__ == "__main__": r5d = Risq5Decoder() run_simulation(r5d, Risq5Decoder_testbench(r5d, vcd_name="instruction_decode.vcd", clocks={"sys":16}))