if regfile == 'INT':
# Int register numbering is *unary* encoded
if name == 'ra': # RA
- return e.read_reg1.ok, 1<<e.read_reg1.data
+ return e.read_reg1.ok, e.read_reg1.data
if name == 'rb': # RB
- return e.read_reg2.ok, 1<<e.read_reg2.data
+ return e.read_reg2.ok, e.read_reg2.data
if name == 'rc': # RS
- return e.read_reg3.ok, 1<<e.read_reg3.data
+ return e.read_reg3.ok, e.read_reg3.data
# CR regfile
if regfile == 'INT':
# Int register numbering is *unary* encoded
if name == 'o': # RT
- return e.write_reg, 1<<e.write_reg.data
+ return e.write_reg, e.write_reg.data
if name == 'o1': # RA (update mode: LD/ST EA)
- return e.write_ea, 1<<e.write_ea.data
+ return e.write_ea, e.write_ea.data
# CR regfile
if regfile == 'FAST':
# FAST register numbering is *unary* encoded
- CTR = 1<<FastRegs.CTR
- LR = 1<<FastRegs.LR
- TAR = 1<<FastRegs.TAR
- SRR0 = 1<<FastRegs.SRR0
- SRR1 = 1<<FastRegs.SRR1
if name == 'fast1':
return e.write_fast1, 1<<e.write_fast1.data
if name == 'fast2':
from nmigen import Cat, Const, Array, Signal, Elaboratable, Module
from nmutil.iocontrol import RecordObject
from nmutil.util import treereduce
+from nmigen.utils import log2_int
from nmigen import Memory
from math import log
class RegFileMem(Elaboratable):
unary = False
def __init__(self, width, depth):
+ self.width, self.depth = width, depth
self.memory = Memory(width=width, depth=depth)
self._rdports = {}
self._wrports = {}
def read_port(self, name=None):
- port = self._rdports[name] = self.memory.read_port()
+ bsz = log2_int(self.depth, False)
+ port = RecordObject([("addr", bsz),
+ ("ren", 1),
+ ("data_o", self.width)], name=name)
+ self._rdports[name] = (port, self.memory.read_port(domain="comb"))
return port
def write_port(self, name=None):
- port = self._wrports[name] = self.memory.write_port()
+ bsz = log2_int(self.depth, False)
+ port = RecordObject([("addr", bsz),
+ ("wen", 1),
+ ("data_i", self.width)], name=name)
+ self._wrports[name] = (port, self.memory.write_port())
return port
def elaborate(self, platform):
m = Module()
- for name, rp in self._rdports.items():
- setattr(m.submodules, "rp_"+name, rp)
- for name, wp in self._wrports.items():
+ comb = m.d.comb
+
+ # read ports. has write-through detection (returns data written)
+ for name, (rp, rport) in self._rdports.items():
+ setattr(m.submodules, "rp_"+name, rport)
+ wr_detect = Signal(reset_less=False)
+ comb += rport.addr.eq(rp.addr)
+ with m.If(rp.ren):
+ m.d.comb += wr_detect.eq(0)
+ for _, (wp, wport) in self._wrports.items():
+ addrmatch = Signal(reset_less=False)
+ m.d.comb += addrmatch.eq(wp.addr == rp.addr)
+ with m.If(wp.wen & addrmatch):
+ m.d.comb += rp.data_o.eq(wp.data_i)
+ m.d.comb += wr_detect.eq(1)
+ with m.If(~wr_detect):
+ m.d.comb += rp.data_o.eq(rport.data)
+
+ # write ports, delayed by one cycle (in the memory itself)
+ for name, (port, wp) in self._wrports.items():
setattr(m.submodules, "wp_"+name, wp)
+ comb += wp.addr.eq(port.addr)
+ comb += wp.en.eq(port.wen)
+ comb += wp.data.eq(port.data_i)
+
return m
def read_port(self, name=None):
bsz = int(log(self.width) / log(2))
- port = RecordObject([("raddr", bsz),
+ port = RecordObject([("addr", bsz),
("ren", 1),
("data_o", self.width)], name=name)
self._rdports.append(port)
def write_port(self, name=None):
bsz = int(log(self.width) / log(2))
- port = RecordObject([("waddr", bsz),
+ port = RecordObject([("addr", bsz),
("wen", 1),
("data_i", self.width)], name=name)
self._wrports.append(port)
m.d.comb += wr_detect.eq(0)
for wp in self._wrports:
addrmatch = Signal(reset_less=False)
- m.d.comb += addrmatch.eq(wp.waddr == rp.raddr)
+ m.d.comb += addrmatch.eq(wp.addr == rp.addr)
with m.If(wp.wen & addrmatch):
m.d.comb += rp.data_o.eq(wp.data_i)
m.d.comb += wr_detect.eq(1)
with m.If(~wr_detect):
- m.d.comb += rp.data_o.eq(regs[rp.raddr])
+ m.d.comb += rp.data_o.eq(regs[rp.addr])
# write ports, delayed by one cycle
for wp in self._wrports:
with m.If(wp.wen):
- m.d.sync += regs[wp.waddr].eq(wp.data_i)
+ m.d.sync += regs[wp.addr].eq(wp.data_i)
return m
def regfile_sim(dut, rp, wp):
- yield wp.waddr.eq(1)
+ yield wp.addr.eq(1)
yield wp.data_i.eq(2)
yield wp.wen.eq(1)
yield
yield wp.wen.eq(0)
+ yield wp.addr.eq(0)
+ yield
+ yield
yield rp.ren.eq(1)
- yield rp.raddr.eq(1)
+ yield rp.addr.eq(1)
yield Settle()
data = yield rp.data_o
print(data)
+ yield
+ data = yield rp.data_o
+ print(data)
+ yield
+ data2 = yield rp.data_o
+ print(data2)
assert data == 2
yield
- yield wp.waddr.eq(5)
- yield rp.raddr.eq(5)
+ yield wp.addr.eq(5)
+ yield rp.addr.eq(5)
yield rp.ren.eq(1)
yield wp.wen.eq(1)
yield wp.data_i.eq(6)
- yield Settle()
+ yield
data = yield rp.data_o
print(data)
assert data == 6
yield
yield wp.wen.eq(0)
yield rp.ren.eq(0)
- yield Settle()
+ yield
data = yield rp.data_o
print(data)
assert data == 0
dut = RegFile(32, 8)
rp = dut.read_port()
wp = dut.write_port()
- vl = rtlil.convert(dut, ports=dut.ports())
+ vl = rtlil.convert(dut)#, ports=dut.ports())
with open("test_regfile.il", "w") as f:
f.write(vl)
run_simulation(dut, regfile_sim(dut, rp, wp), vcd_name='test_regfile.vcd')
+ dut = RegFileMem(32, 8)
+ rp = dut.read_port("rp1")
+ wp = dut.write_port("wp1")
+ vl = rtlil.convert(dut)#, ports=dut.ports())
+ with open("test_regmem.il", "w") as f:
+ f.write(vl)
+
+ run_simulation(dut, regfile_sim(dut, rp, wp), vcd_name='test_regmem.vcd')
+
dut = RegFileArray(32, 8)
rp1 = dut.read_port("read1")
rp2 = dut.read_port("read2")
# Integer Regfile
-class IntRegs(RegFileArray):
+class IntRegs(RegFileMem): #class IntRegs(RegFileArray):
"""IntRegs
* QTY 32of 64-bit registers
self.w_ports = {'spr1': self.write_port("spr1")}
self.r_ports = {'spr1': self.read_port("spr1")}
- # 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
-
- self.r_ports['spr1'].ren = self.w_ports['spr1'].en
- self.r_ports['spr1'].data_o = self.w_ports['spr1'].data
-
# class containing all regfiles: int, cr, xer, fast, spr
class RegFiles:
rpidx = regname
# select the required read port. these are pre-defined sizes
- print(rpidx, regfile, regs.rf.keys())
- rport = regs.rf[regfile.lower()].r_ports[rpidx]
+ rfile = regs.rf[regfile.lower()]
+ rport = rfile.r_ports[rpidx]
+ print("read regfile", rpidx, regfile, regs.rf.keys(),
+ rfile, rfile.unary)
fspecs = fspec
if not isinstance(fspecs, list):
setattr(m.submodules, "rdpick_%s_%s" % (regfile, rpidx), rdpick)
rens = []
+ addrs = []
for i, fspec in enumerate(fspecs):
(rf, read, write, wid, fuspec) = fspec
# connect up the FU req/go signals, and the reg-read to the FU
comb += fu.go_rd_i[idx].eq(rdpick.o[pi])
# if picked, select read-port "reg select" number to port
- read_en = Signal.like(reads[i])
- comb += read_en.eq(Mux(rdpick.o[pi] & rdpick.en_o, reads[i], 0))
- rens.append(read_en)
+ name = "%s_%s_%s_%i" % (regfile, rpidx, funame, pi)
+ addr_en = Signal.like(reads[i])
+ rp = Signal(name="rp_"+name)
+ addr_en.name = "addr_en_"+name
+ comb += rp.eq(rdpick.o[pi] & rdpick.en_o)
+ comb += addr_en.eq(Mux(rp, reads[i], 0))
+ if rfile.unary:
+ rens.append(addr_en)
+ else:
+ addrs.append(addr_en)
+ rens.append(rp)
- with m.If(rdpick.o[pi] & rdpick.en_o):
- # connect regfile port to input, creating a Broadcast Bus
+ with m.If(rp):
+ # connect regfile port to input, creating fan-out Bus
print("reg connect widths",
regfile, regname, pi, funame,
src.shape(), rport.data_o.shape())
comb += src.eq(rport.data_o)
# or-reduce the muxed read signals
- comb += rport.ren.eq(ortreereduce_sig(rens))
+ if rfile.unary:
+ # for unary-addressed
+ comb += rport.ren.eq(ortreereduce_sig(rens))
+ else:
+ # for binary-addressed
+ comb += rport.addr.eq(ortreereduce_sig(addrs))
+ comb += rport.ren.eq(Cat(*rens).bool())
+ print ("binary", regfile, rpidx, rport, rport.ren, rens, addrs)
def connect_rdports(self, m, fu_bitdict):
"""connect read ports
# select the required write port. these are pre-defined sizes
print(regfile, regs.rf.keys())
- wport = regs.rf[regfile.lower()].w_ports[rpidx]
+ rfile = regs.rf[regfile.lower()]
+ wport = rfile.w_ports[rpidx]
fspecs = fspec
if not isinstance(fspecs, list):
wsigs = []
wens = []
+ addrs = []
for i, fspec in enumerate(fspecs):
# connect up the FU req/go signals and the reg-read to the FU
# these are arbitrated by Data.ok signals
# connect the regspec write "reg select" number to this port
# only if one FU actually requests (and is granted) the port
# will the write-enable be activated
- write_en = Signal.like(write)
- comb += write_en.eq(Mux(wr_pick & wrpick.en_o, write, 0))
- wens.append(write_en)
+ addr_en = Signal.like(write)
+ wp = Signal()
+ comb += wp.eq(wr_pick & wrpick.en_o)
+ comb += addr_en.eq(Mux(wp, write, 0))
+ if rfile.unary:
+ wens.append(addr_en)
+ else:
+ addrs.append(addr_en)
+ wens.append(wp)
# connect regfile port to input
print("reg connect widths",
# here is where we create the Write Broadcast Bus. simple, eh?
comb += wport.data_i.eq(ortreereduce_sig(wsigs))
- comb += wport.wen.eq(ortreereduce_sig(wens))
+ if rfile.unary:
+ # for unary-addressed
+ comb += wport.wen.eq(ortreereduce_sig(wens))
+ else:
+ # for binary-addressed
+ comb += wport.addr.eq(ortreereduce_sig(addrs))
+ comb += wport.wen.eq(ortreereduce_sig(wens))
def connect_wrports(self, m, fu_bitdict):
"""connect write ports
with m.If(d_reg.req): # request for regfile access being made
# TODO: error-check this
# XXX should this be combinatorial? sync better?
- comb += self.int_r.ren.eq(1<<d_reg.addr)
+ if hasattr(self.int_r, "ren"):
+ comb += self.int_r.ren.eq(1<<d_reg.addr)
+ else:
+ comb += self.int_r.addr.eq(d_reg.addr)
+ comb += self.int_r.en.eq(1)
comb += d_reg.data.eq(self.int_r.data_o)
comb += d_reg.ack.eq(1)
# set up INT regfile, "direct" write (bypass rd/write ports)
intregs = core.regs.int
for i in range(32):
- yield intregs.regs[i].reg.eq(test.regs[i])
+ if intregs.unary:
+ yield intregs.regs[i].reg.eq(test.regs[i])
+ else:
+ yield intregs.memory._array[i].eq(test.regs[i])
+ yield Settle()
# set up CR regfile, "direct" write across all CRs
cr = test.cr
# int regs
intregs = []
for i in range(32):
- rval = yield core.regs.int.regs[i].reg
+ if core.regs.int.unary:
+ rval = yield core.regs.int.regs[i].reg
+ else:
+ rval = yield core.regs.int.memory._array[i]
intregs.append(rval)
print("int regs", list(map(hex, intregs)))
for i in range(32):
from soc.debug.dmi import DBGCore, DBGCtrl, DBGStat
# test with ALU data and Logical data
-#from soc.fu.alu.test.test_pipe_caller import ALUTestCase
+from soc.fu.alu.test.test_pipe_caller import ALUTestCase
from soc.fu.div.test.test_pipe_caller import DivTestCases
from soc.fu.logical.test.test_pipe_caller import LogicalTestCase
#from soc.fu.shift_rot.test.test_pipe_caller import ShiftRotTestCase
# suite.addTest(TestRunner(CRTestCase().test_data))
# suite.addTest(TestRunner(ShiftRotTestCase.test_data))
suite.addTest(TestRunner(LogicalTestCase().test_data))
- # suite.addTest(TestRunner(ALUTestCase.test_data))
+ suite.addTest(TestRunner(ALUTestCase().test_data))
# suite.addTest(TestRunner(BranchTestCase.test_data))
# suite.addTest(TestRunner(SPRTestCase.test_data))