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