see https://libre-soc.org/3d_gpu/architecture/regfile/ section on regspecs
"""
from nmigen import Const
-from soc.regfile.regfiles import XERRegs, FastRegs
+from soc.regfile.regfiles import XERRegs, FastRegs, StateRegs
from soc.decoder.power_enums import CryIn
if name == 'xer_ca':
return (e.do.input_carry == CryIn.CA.value) | e.xer_in, CA
+ # STATE regfile
+
+ if regfile == 'STATE':
+ # STATE register numbering is *unary* encoded
+ PC = 1<<StateRegs.PC
+ MSR = 1<<Stateegs.MSR
+ if name in ['cia', 'nia']:
+ return Const(1), PC # TODO: detect read-conditions
+ if name == 'msr':
+ return Const(1), MSR # TODO: detect read-conditions
+
# FAST regfile
if regfile == 'FAST':
# FAST register numbering is *unary* encoded
- PC = 1<<FastRegs.PC
- MSR = 1<<FastRegs.MSR
CTR = 1<<FastRegs.CTR
LR = 1<<FastRegs.LR
TAR = 1<<FastRegs.TAR
SRR0 = 1<<FastRegs.SRR0
SRR1 = 1<<FastRegs.SRR1
- if name in ['cia', 'nia']:
- return Const(1), PC # TODO: detect read-conditions
- if name == 'msr':
- return Const(1), MSR # TODO: detect read-conditions
- # TODO: remap the SPR numbers to FAST regs
if name == 'fast1':
return e.read_fast1.ok, 1<<e.read_fast1.data
if name == 'fast2':
if name == 'xer_ca':
return e.xer_out, CA # hmmm
+ # STATE regfile
+
+ if regfile == 'STATE':
+ # STATE register numbering is *unary* encoded
+ PC = 1<<StateRegs.PC
+ MSR = 1<<StateRegs.MSR
+ if name in ['cia', 'nia']:
+ return None, PC # hmmm
+ if name == 'msr':
+ return None, MSR # hmmm
+
# FAST regfile
if regfile == 'FAST':
# FAST register numbering is *unary* encoded
- PC = 1<<FastRegs.PC
- MSR = 1<<FastRegs.MSR
CTR = 1<<FastRegs.CTR
LR = 1<<FastRegs.LR
TAR = 1<<FastRegs.TAR
SRR0 = 1<<FastRegs.SRR0
SRR1 = 1<<FastRegs.SRR1
- if name in ['cia', 'nia']:
- return None, PC # hmmm
- if name == 'msr':
- return None, MSR # hmmm
- # TODO: remap the SPR numbers to FAST regs
if name == 'fast1':
return e.write_fast1, 1<<e.write_fast1.data
if name == 'fast2':
class BranchOutputData(IntegerData):
regspec = [('FAST', 'fast1', '0:63'),
('FAST', 'fast2', '0:63'),
- ('FAST', 'nia', '0:63')]
+ ('STATE', 'nia', '0:63')]
def __init__(self, pspec):
super().__init__(pspec, True)
class SPRInputData(IntegerData):
regspec = [('INT', 'ra', '0:63'), # RA
('SPR', 'spr1', '0:63'), # SPR (slow)
- ('FAST', 'fast1', '0:63'), # SPR (fast: MSR, LR, CTR etc)
+ ('FAST', 'fast1', '0:63'), # SPR (fast: LR, CTR etc)
('XER', 'xer_so', '32'), # XER bit 32: SO
('XER', 'xer_ov', '33,44'), # XER bit 34/45: CA/CA32
('XER', 'xer_ca', '34,45')] # bit0: ov, bit1: ov32
class SPROutputData(IntegerData):
regspec = [('INT', 'o', '0:63'), # RT
('SPR', 'spr1', '0:63'), # SPR (slow)
- ('FAST', 'fast1', '0:63'), # SPR (fast: MSR, LR, CTR etc)
+ ('FAST', 'fast1', '0:63'), # SPR (fast: LR, CTR etc)
('XER', 'xer_so', '32'), # XER bit 32: SO
('XER', 'xer_ov', '33,44'), # XER bit 34/45: CA/CA32
('XER', 'xer_ca', '34,45')] # bit0: ov, bit1: ov32
('INT', 'rb', '0:63'), # RB/immediate
('FAST', 'fast1', '0:63'), # SRR0
('FAST', 'fast2', '0:63'), # SRR1
+ # note here that neither MSR nor CIA are read as regs: they are
+ # passed in as incoming "State", via the CompTrapOpSubset
]
def __init__(self, pspec):
super().__init__(pspec, False)
regspec = [('INT', 'o', '0:63'), # RA
('FAST', 'fast1', '0:63'), # SRR0 SPR
('FAST', 'fast2', '0:63'), # SRR1 SPR
- ('FAST', 'nia', '0:63'), # NIA (Next PC)
- ('FAST', 'msr', '0:63')] # MSR
+ ('STATE', 'nia', '0:63'), # NIA (Next PC)
+ ('STATE', 'msr', '0:63')] # MSR
def __init__(self, pspec):
super().__init__(pspec, True)
# convenience
* SPR regfile - 110x 64-bit
* CR regfile - CR0-7
* XER regfile - XER.so, XER.ca/ca32, XER.ov/ov32
- * FAST regfile - PC, MSR, CTR, LR, TAR, SRR1, SRR2
+ * FAST regfile - CTR, LR, TAR, SRR1, SRR2
+ * STATE regfile - PC, MSR, (SimpleV VL later)
Note: this should NOT have name conventions hard-coded (dedicated ports per
regname). However it is convenient for now.
from nmigen import Memory, Elaboratable
+# "State" Regfile
+class StateRegs(RegFileArray):
+ """StateRegs
+
+ State regfile - PC, MSR and later SimpleV VL
+
+ * QTY 2of 64-bit registers
+ * 3R2W
+ * Array-based unary-indexed (not binary-indexed)
+ * write-through capability (read on same cycle as write)
+
+ Note: d_wr1 d_rd1 are for use by the decoder, to get at the PC.
+ will probably have to also add one so it can get at the MSR as well.
+ (d_rd2)
+ """
+ PC = 0
+ MSR = 1
+ def __init__(self):
+ super().__init__(64, 2)
+ self.w_ports = {'nia': self.write_port("nia"),
+ 'msr': self.write_port("msr"),
+ 'd_wr1': self.write_port("d_wr1")} # writing PC (issuer)
+ self.r_ports = {'cia': self.read_port("cia"), # reading PC (issuer)
+ 'msr': self.read_port("msr"), # reading MSR (issuer)
+ }
+
+
# Integer Regfile
class IntRegs(RegFileArray):
"""IntRegs
class FastRegs(RegFileArray):
"""FastRegs
- FAST regfile - PC, MSR, CTR, LR, TAR, SRR1, SRR2
+ FAST regfile - CTR, LR, TAR, SRR1, SRR2
- * QTY 8of 64-bit registers
- * 3R2W
+ * QTY 5of 64-bit registers
+ * 2R1W
* Array-based unary-indexed (not binary-indexed)
* write-through capability (read on same cycle as write)
-
- Note: d_wr1 d_rd1 are for use by the decoder, to get at the PC.
- will probably have to also add one so it can get at the MSR as well.
- (d_rd2)
"""
- PC = 0
- MSR = 1
- CTR = 2
- LR = 3
- TAR = 4
- SRR0 = 5
- SRR1 = 6
+ CTR = 0
+ LR = 1
+ TAR = 2
+ SRR0 = 3
+ SRR1 = 4
def __init__(self):
- super().__init__(64, 8)
- self.w_ports = {'nia': self.write_port("nia"),
- 'msr': self.write_port("dest2"),
- 'fast1': self.write_port("dest3"),
+ super().__init__(64, 5)
+ self.w_ports = {'fast1': self.write_port("dest3"),
'fast2': self.write_port("dest4"),
- 'd_wr1': self.write_port("d_wr1")} # writing PC (issuer)
- self.r_ports = {'cia': self.read_port("cia"), # reading PC (issuer)
- 'msr': self.read_port("msr"), # reading MSR (issuer)
- 'fast1': self.read_port("src1"),
+ }
+ self.r_ports = {'fast1': self.read_port("src1"),
}
self.w_ports = {'spr1': self.write_port()}
self.r_ports = {'spr1': self.read_port()}
+ # make read/write ports look like RegFileArray
self.w_ports['spr1'].wen = self.w_ports['spr1'].en
self.w_ports['spr1'].data_i = self.w_ports['spr1'].data
('cr', CRRegs),
('xer', XERRegs),
('fast', FastRegs),
+ ('state', StateRegs),
('spr', SPRRegs),]:
rf = self.rf[name] = kls()
setattr(self, name, rf)
not in any way intended for production use. this runs a FSM that:
-* reads the Program Counter from FastRegs
+* reads the Program Counter from StateRegs
* reads an instruction from a fixed-size Test Memory
* issues it to the Simple Core
* waits for it to complete
from soc.decoder.decode2execute1 import Data
from soc.experiment.testmem import TestMemory # test only for instructions
-from soc.regfile.regfiles import FastRegs
+from soc.regfile.regfiles import StateRegs
from soc.simple.core import NonProductionCore
from soc.config.test.test_loadstore import TestMemPspec
from soc.config.ifetch import ConfigFetchUnit
self.memerr_o = Signal(reset_less=True)
# FAST regfile read /write ports for PC and MSR
- self.fast_r_pc = self.core.regs.rf['fast'].r_ports['cia'] # PC rd
- self.fast_w_pc = self.core.regs.rf['fast'].w_ports['d_wr1'] # PC wr
- self.fast_r_msr = self.core.regs.rf['fast'].r_ports['msr'] # MSR rd
+ self.state_r_pc = self.core.regs.rf['state'].r_ports['cia'] # PC rd
+ self.state_w_pc = self.core.regs.rf['state'].w_ports['d_wr1'] # PC wr
+ self.state_r_msr = self.core.regs.rf['state'].r_ports['msr'] # MSR rd
# DMI interface access
self.int_r = self.core.regs.rf['int'].r_ports['dmi'] # INT read
# hack method of keeping an eye on whether branch/trap set the PC
- self.fast_nia = self.core.regs.rf['fast'].w_ports['nia']
- self.fast_nia.wen.name = 'fast_nia_wen'
+ self.state_nia = self.core.regs.rf['state'].w_ports['nia']
+ self.state_nia.wen.name = 'state_nia_wen'
def elaborate(self, platform):
m = Module()
# incoming override (start from pc_i)
comb += pc.eq(self.pc_i.data)
with m.Else():
- # otherwise read FastRegs regfile for PC
- comb += self.fast_r_pc.ren.eq(1<<FastRegs.PC)
- comb += pc.eq(self.fast_r_pc.data_o)
+ # otherwise read StateRegs regfile for PC
+ comb += self.state_r_pc.ren.eq(1<<StateRegs.PC)
+ comb += pc.eq(self.state_r_pc.data_o)
# connect up debug signals
# TODO comb += core.icache_rst_i.eq(dbg.icache_rst_o)
insn_state = core.pdecode2.state
# don't read msr every cycle
- sync += self.fast_r_msr.ren.eq(0)
+ sync += self.state_r_msr.ren.eq(0)
# actually use a nmigen FSM for the first time (w00t)
# this FSM is perhaps unusual in that it detects conditions
sync += cur_state.pc.eq(pc)
# read MSR, latch it, and put it in decode "state"
- sync += self.fast_r_msr.ren.eq(1<<FastRegs.MSR)
- sync += cur_state.msr.eq(self.fast_r_msr.data_o)
+ sync += self.state_r_msr.ren.eq(1<<StateRegs.MSR)
+ sync += cur_state.msr.eq(self.state_r_msr.data_o)
m.next = "INSN_READ" # move to "wait for bus" phase
comb += core_ivalid_i.eq(1) # instruction is valid
comb += core_opcode_i.eq(ilatch) # actual opcode
comb += insn_state.eq(cur_state) # and MSR and PC
- with m.If(self.fast_nia.wen):
+ with m.If(self.state_nia.wen):
sync += pc_changed.eq(1)
with m.If(~core_busy_o): # instruction done!
# ok here we are not reading the branch unit. TODO
# this just blithely overwrites whatever pipeline
# updated the PC
with m.If(~pc_changed):
- comb += self.fast_w_pc.wen.eq(1<<FastRegs.PC)
- comb += self.fast_w_pc.data_i.eq(nia)
+ comb += self.state_w_pc.wen.eq(1<<StateRegs.PC)
+ comb += self.state_w_pc.data_i.eq(nia)
m.next = "IDLE" # back to idle
# this bit doesn't have to be in the FSM: connect up to read