An RV32IMF implementation w/ migen/LiteX
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
Risq5/libmodules/instruction_decode.py

422 lines
30 KiB

#!/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, <csr>, 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}))