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/register_file.py

158 lines
9.2 KiB

#!/usr/bin/env python3
#
# register_file.py
#
# Risq5 The RISC-V register file
#
# 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
import libmodules.risq5defs as risq5defs # CSR register defs.
class Risq5RegisterFile(Module):
"""
Risq5 The RISC-V register file
"""
def __init__(self):
# Register file ----------------------------------------------------------------------------
WORDSIZE = 32
self.pc = Signal(WORDSIZE, reset=0) # Program counter (RISC-V start @0!)
self.opcode = Signal(WORDSIZE, reset_less=True) # Loaded from instruction fetch
# Instruction decode, 32 bit opcode parts --------------------------------------------------
self.op = Signal(7, reset_less=True) # [6:0] Instruction type
self.rd = Signal(5, reset_less=True) # [11:7] Destination register
self.f3 = Signal(3, reset_less=True) # [14:12] Instruction type modifier
self.rs1 = Signal(5, reset_less=True) # [19:15] source register #1
self.rs2 = Signal(5, reset_less=True) # [24:20] source register #2
self.f7 = Signal(7, reset_less=True) # [31:25] Instruction type modifier
self.imm_i = Signal((12, True), reset_less=True) # Immediates (usually: signed) & CSR(!)
self.imm_s = Signal((12, True), reset_less=True)
self.imm_b = Signal((13, True), reset_less=True)
self.imm_u = Signal(20, reset_less=True)
self.imm_j = Signal((20, True), reset_less=True)
self.comb += [ # Opcode relay
# Common parts
self.op.eq(self.opcode[0:7]),
self.rd.eq(self.opcode[7:12]),
self.f3.eq(self.opcode[12:15]),
self.rs1.eq(self.opcode[15:20]),
self.rs2.eq(self.opcode[20:25]),
# R-type
self.f7.eq(self.opcode[25:32]),
# I-type immediate (12 bits)
self.imm_i.eq(self.opcode[20:32]),
# S-type immediate (12 bits)
self.imm_s.eq(Cat(self.rd, self.f7)), # Concatenate bits from lower to higher bits
# B-type immediate (12 bits << 1 )
self.imm_b.eq(Cat(0, self.opcode[8:12], self.opcode[25:31], self.opcode[7], self.opcode[31])),
# U-type immediate (20 bits)
self.imm_u.eq(self.opcode[12:32]),
# J-type immediate (19 bits << 1 )
# op[21..30] -> imm[1..10]
# op[20] -> imm[11]
# op[12..19] -> imm[12..19]
# op[31] -> imm[20]
self.imm_j.eq(Cat(0,self.opcode[21:31], self.opcode[20], self.opcode[12:20], self.opcode[31])),
]
self.read_ext_index = Signal(5, reset_less=True) # External read access (index)
self.write_ext_index = Signal(5, reset_less=True) # External write access (index)
self.xs1u = Signal(32, reset_less=True) # Value of source register #1 (unsigned)
self.xs2u = Signal(32, reset_less=True) # Value of source register #2 (unsigned)
self.xs1s = Signal((32,True), reset_less=True) # Signed register #1
self.xs2s = Signal((32,True), reset_less=True) # Signed register #2
self.xs1_64u = Signal(65, reset_less=True) # Register #1 (M extension)
self.xs2_64u = Signal(65, reset_less=True) # Register #2 (M extension)
self.rd_mul64u = Signal(65, reset_less=True) # M extension multiply result (unsigned)
self.xs1_64s = Signal((64,True), reset_less=True) # Signed register #1 (M extension)
self.xs2_64s = Signal((64,True), reset_less=True) # Signed register #2 (M extension)
self.rd_mul64s = Signal((64,True), reset_less=True) # M extension multiply result (signed)
self.rd_mul64us = Signal((64,True), reset_less=True) # M extension multiply result (mixed)
self.ext_x = Signal(32, reset_less=True) # Value to be read externally
self.LUAddress = Signal(32, reset_less=True) # Load unit address to use
self.SUAddress = Signal(32, reset_less=True) # Store unit address to use
regs = Memory(WORDSIZE, 32) # 32-bit, 32 elements -> x0 .. x31
self.specials += regs
# rd -> index register to write
self.rd_wrport = regs.get_port(write_capable=True) # Internal register file access
self.specials += self.rd_wrport
self.ext_wrport = regs.get_port(write_capable=True)
self.specials += self.ext_wrport
self.comb += [ # Write to memory
self.rd_wrport.adr.eq(self.rd), # Index local memory for WRITE (destination register)
#rd_wrport.dat_w.eq(<value>),
#rd_wrport.we.eq(1) # Write
self.ext_wrport.adr.eq(self.write_ext_index), # Index local memory for WRITE (destination register)
#ext_wrport.dat_w.eq(<value>),
#ext_wrport.we.eq(1) # Write
]
# rs1, rs2 -> index registers to read
rs1_rdport = regs.get_port() # use .dat_r to pick up data
self.specials += rs1_rdport
rs2_rdport = regs.get_port()
self.specials += rs2_rdport
ext_rdport = regs.get_port() # External read port
self.specials += ext_rdport
self.comb += [ # Read from memory
rs1_rdport.adr.eq(self.rs1), # Read source register #1
self.xs1u.eq(rs1_rdport.dat_r), # Unsigned
self.xs1s.eq(rs1_rdport.dat_r), # Signed
rs2_rdport.adr.eq(self.rs2), # Read source register #2
self.xs2u.eq(rs2_rdport.dat_r), # Unsigned
self.xs2s.eq(rs2_rdport.dat_r), # Signed
ext_rdport.adr.eq(self.read_ext_index), # Read from external
self.ext_x.eq(ext_rdport.dat_r),
]
self.comb += [ # M extension (TODO: Improve brutal implementation ...)
self.xs1_64u.eq(rs1_rdport.dat_r),
self.xs2_64u.eq(rs2_rdport.dat_r),
self.rd_mul64u.eq(self.xs1_64u * self.xs2_64u), # Continuously calculate 64-bit mul (unsigned)
self.xs1_64s.eq(rs1_rdport.dat_r),
self.xs2_64s.eq(rs2_rdport.dat_r),
self.rd_mul64s.eq(self.xs1_64s * self.xs2_64s), # Continuously calculate 64-bit mul (signed)
self.rd_mul64us.eq(self.xs1_64s * self.xs2_64u) # Continuously calculate 64-bit mul (mixed)
]
# ------------------------- CSRs ----------------------------------------------------
self.csr = Array(Signal(32) for _ in range(15)) # csr[0..12]
# Translate CSR ID codes -> Index
self.csrindex = Signal(4, reset_less=True) # 0..15
self.comb += [
If( self.imm_i == risq5defs.CSR_mstatus_id, self.csrindex.eq(risq5defs.CSR_mstatus) # mstatus (Interrupt enable & stati)
).Elif(self.imm_i == risq5defs.CSR_mip_id, self.csrindex.eq(risq5defs.CSR_mip) # mip (Machine interrupt pending)
).Elif(self.imm_i == risq5defs.CSR_mie_id, self.csrindex.eq(risq5defs.CSR_mie) # mie (Machine interrupt enable)
).Elif(self.imm_i == risq5defs.CSR_mcause_id, self.csrindex.eq(risq5defs.CSR_mcause) # mcause (Machine exception cause)
).Elif(self.imm_i == risq5defs.CSR_mtvec_id, self.csrindex.eq(risq5defs.CSR_mtvec) # mtvec (Machine trap vector)
).Elif(self.imm_i == risq5defs.CSR_mtval_id, self.csrindex.eq(risq5defs.CSR_mtval) # mtval (Machine trap value)
).Elif(self.imm_i == risq5defs.CSR_mepc_id, self.csrindex.eq(risq5defs.CSR_mepc) # mepc (Machine exception pc)
).Elif(self.imm_i == risq5defs.CSR_mscratch_id, self.csrindex.eq(risq5defs.CSR_mscratch) # mscratch (Machine scratch)
# Statics start here (=> Index >= CSR_misa, no write then)
).Elif(self.imm_i == risq5defs.CSR_misa_id, self.csrindex.eq(risq5defs.CSR_misa) # misa (Machine ISA)
# Signed->Unsigned (cut off hi-bit ;)
).Elif(self.imm_i[0:11] == risq5defs.CSR_mvendorid_id, self.csrindex.eq(risq5defs.CSR_mvendorid) # mvendorid (Machine vendor ID)
).Elif(self.imm_i[0:11] == risq5defs.CSR_marchid_id, self.csrindex.eq(risq5defs.CSR_marchid) # marchid (Machine base microarchitecture)
).Elif(self.imm_i[0:11] == risq5defs.CSR_mimpid_id, self.csrindex.eq(risq5defs.CSR_mimpid) # mimpid (Machine base microarchitecture version)
).Elif(self.imm_i[0:11] == risq5defs.CSR_mhartid_id, self.csrindex.eq(risq5defs.CSR_mhartid) # mhartid (Machine hardware thread ('core') ID)
).Elif(self.imm_i[0:11] == risq5defs.CSR_0xBC0_id, self.csrindex.eq(risq5defs.CSR_0xBC0) # Custom shadow register (for vex?!)
).Elif(self.imm_i[0:11] == risq5defs.CSR_0xFC0_id, self.csrindex.eq(risq5defs.CSR_0xFC0) # Custom shadow register (for vex?!)
).Else(self.csrindex.eq(risq5defs.CSR_dummy)), # Dummy bit bucket ...
]
if __name__ == "__main__":
print("***** Register file is passive ... ;) *****")