def go_record(n, name):
- r = Record([('go', n, DIR_FANIN),
- ('rel', n, DIR_FANOUT)], name=name)
- r.go.reset_less = True
- r.rel.reset_less = True
+ r = Record([('go_i', n, DIR_FANIN),
+ ('rel_o', n, DIR_FANOUT)], name=name)
+ r.go_i.reset_less = True
+ r.rel_o.reset_less = True
return r
self.oper_i = subkls(name="oper_i_%s" % name) # operand
# create read/write and other scoreboard signalling
- self.rd = go_record(n_src, name="rd") # read in, req out
- self.wr = go_record(n_dst, name="wr") # write in, req out
- self.rdmaskn = Signal(n_src, reset_less=True) # read mask
- self.wrmask = Signal(n_dst, reset_less=True) # write mask
- self.issue_i = Signal(reset_less=True) # fn issue in
- self.shadown_i = Signal(reset=1) # shadow function, defaults to ON
- self.go_die_i = Signal() # go die (reset)
+ self.rd = go_record(n_src, name="cu_rd") # read in, req out
+ self.wr = go_record(n_dst, name="cu_wr") # write in, req out
+ # read / write mask
+ self.rdmaskn = Signal(n_src, name="cu_rdmaskn_i", reset_less=True)
+ self.wrmask = Signal(n_dst, name="cu_wrmask_o", reset_less=True)
+
+ # fn issue in
+ self.issue_i = Signal(name="cu_issue_i", reset_less=True)
+ # shadow function, defaults to ON
+ self.shadown_i = Signal(name="cu_shadown_i", reset=1)
+ # go die (reset)
+ self.go_die_i = Signal(name="cu_go_die_i")
# output (busy/done)
- self.busy_o = Signal(reset_less=True) # fn busy out
- self.done_o = Signal(reset_less=True)
+ self.busy_o = Signal(name="cu_busy_o", reset_less=True) # fn busy out
+ self.done_o = Signal(name="cu_done_o", reset_less=True)
class MultiCompUnit(RegSpecALUAPI, Elaboratable):
self.wr = cu.wr
self.rdmaskn = cu.rdmaskn
self.wrmask = cu.wrmask
- self.go_rd_i = self.rd.go # temporary naming
- self.go_wr_i = self.wr.go # temporary naming
- self.rd_rel_o = self.rd.rel # temporary naming
- self.req_rel_o = self.wr.rel # temporary naming
+ self.go_rd_i = self.rd.go_i # temporary naming
+ self.go_wr_i = self.wr.go_i # temporary naming
+ self.rd_rel_o = self.rd.rel_o # temporary naming
+ self.req_rel_o = self.wr.rel_o # temporary naming
self.issue_i = cu.issue_i
self.shadown_i = cu.shadown_i
self.go_die_i = cu.go_die_i
# so combine it with go_rd_i. if all bits are set we're good
all_rd = Signal(reset_less=True)
m.d.comb += all_rd.eq(self.busy_o & rok_l.q &
- (((~self.rd.rel) | self.rd.go).all()))
+ (((~self.rd.rel_o) | self.rd.go_i).all()))
# generate read-done pulse
all_rd_dly = Signal(reset_less=True)
# sigh bug where req_l gets both set and reset raised at same time
prev_wr_go = Signal(self.n_dst)
brd = Repl(self.busy_o, self.n_dst)
- m.d.sync += prev_wr_go.eq(self.wr.go & brd)
+ m.d.sync += prev_wr_go.eq(self.wr.go_i & brd)
# write_requests all done
# req_done works because any one of the last of the writes
wr_any = Signal(reset_less=True)
req_done = Signal(reset_less=True)
m.d.comb += self.done_o.eq(self.busy_o &
- ~((self.wr.rel & ~self.wrmask).bool()))
- m.d.comb += wr_any.eq(self.wr.go.bool() | prev_wr_go.bool())
+ ~((self.wr.rel_o & ~self.wrmask).bool()))
+ m.d.comb += wr_any.eq(self.wr.go_i.bool() | prev_wr_go.bool())
m.d.comb += req_done.eq(wr_any & ~self.alu.n.ready_i &
((req_l.q & self.wrmask) == 0))
# argh, complicated hack: if there are no regs to write,
reset_r = Signal(self.n_src, reset_less=True)
m.d.comb += reset.eq(req_done | self.go_die_i)
m.d.comb += rst_r.eq(self.issue_i | self.go_die_i)
- m.d.comb += reset_w.eq(self.wr.go | Repl(self.go_die_i, self.n_dst))
- m.d.comb += reset_r.eq(self.rd.go | Repl(self.go_die_i, self.n_src))
+ m.d.comb += reset_w.eq(self.wr.go_i | Repl(self.go_die_i, self.n_dst))
+ m.d.comb += reset_r.eq(self.rd.go_i | Repl(self.go_die_i, self.n_src))
# read-done,wr-proceed latch
m.d.comb += rok_l.s.eq(self.issue_i) # set up when issue starts
# read-release gated by busy (and read-mask)
bro = Repl(self.busy_o, self.n_src)
- m.d.comb += self.rd.rel.eq(src_l.q & bro & slg & ~self.rdmaskn)
+ m.d.comb += self.rd.rel_o.eq(src_l.q & bro & slg & ~self.rdmaskn)
# write-release gated by busy and by shadow (and write-mask)
brd = Repl(self.busy_o & self.shadown_i, self.n_dst)
- m.d.comb += self.wr.rel.eq(req_l.q & brd & self.wrmask)
+ m.d.comb += self.wr.rel_o.eq(req_l.q & brd & self.wrmask)
# output the data from the latch on go_write
for i in range(self.n_dst):
- with m.If(self.wr.go[i] & self.busy_o):
+ with m.If(self.wr.go_i[i] & self.busy_o):
m.d.comb += self.dest[i].eq(drl[i])
return m
return self.dest[i]
def __iter__(self):
- yield self.rd.go
- yield self.wr.go
+ yield self.rd.go_i
+ yield self.wr.go_i
yield self.issue_i
yield self.shadown_i
yield self.go_die_i
yield self.src1_i
yield self.src2_i
yield self.busy_o
- yield self.rd.rel
- yield self.wr.rel
+ yield self.rd.rel_o
+ yield self.wr.rel_o
yield self.data_o
def ports(self):
# (it really shouldn't be)
self.data_wid = self.dest[0].shape()
- self.go_rd_i = self.rd.go # temporary naming
- self.go_wr_i = self.wr.go # temporary naming
- self.go_ad_i = self.ad.go # temp naming: go address in
- self.go_st_i = self.st.go # temp naming: go store in
+ self.go_rd_i = self.rd.go_i # temporary naming
+ self.go_wr_i = self.wr.go_i # temporary naming
+ self.go_ad_i = self.ad.go_i # temp naming: go address in
+ self.go_st_i = self.st.go_i # temp naming: go store in
- self.rd_rel_o = self.rd.rel # temporary naming
- self.req_rel_o = self.wr.rel # temporary naming
- self.adr_rel_o = self.ad.rel # request address (from mem)
- self.sto_rel_o = self.st.rel # request store (to mem)
+ self.rd_rel_o = self.rd.rel_o # temporary naming
+ self.req_rel_o = self.wr.rel_o # temporary naming
+ self.adr_rel_o = self.ad.rel_o # request address (from mem)
+ self.sto_rel_o = self.st.rel_o # request store (to mem)
self.issue_i = cu.issue_i
self.shadown_i = cu.shadown_i
comb += reset_i.eq(issue_i | self.go_die_i) # various
comb += reset_o.eq(wr_reset | self.go_die_i) # opcode reset
- comb += reset_w.eq(self.wr.go[0] | self.go_die_i) # write reg 1
- comb += reset_u.eq(self.wr.go[1] | self.go_die_i) # update (reg 2)
+ comb += reset_w.eq(self.wr.go_i[0] | self.go_die_i) # write reg 1
+ comb += reset_u.eq(self.wr.go_i[1] | self.go_die_i) # update (reg 2)
comb += reset_s.eq(self.go_st_i | self.go_die_i) # store reset
- comb += reset_r.eq(self.rd.go | Repl(self.go_die_i, self.n_src))
+ comb += reset_r.eq(self.rd.go_i | Repl(self.go_die_i, self.n_src))
comb += reset_a.eq(self.go_ad_i | self.go_die_i)
p_st_go = Signal(reset_less=True)
- sync += p_st_go.eq(self.st.go)
+ sync += p_st_go.eq(self.st.go_i)
##########################
# FSM implemented through sequence of latches. approximately this:
# 2nd operand only needed when immediate is not active
slg = Cat(op_is_z, op_is_imm)
bro = Repl(self.busy_o, self.n_src)
- comb += self.rd.rel.eq(src_l.q & bro & ~slg & ~self.rdmaskn)
+ comb += self.rd.rel_o.eq(src_l.q & bro & ~slg & ~self.rdmaskn)
# note when the address-related read "go" signals are active
- comb += rda_any.eq(self.rd.go[0] | self.rd.go[1])
+ comb += rda_any.eq(self.rd.go_i[0] | self.rd.go_i[1])
# alu input valid when 1st and 2nd ops done (or imm not active)
- comb += alu_valid.eq(busy_o & ~(self.rd.rel[0] | self.rd.rel[1]))
+ comb += alu_valid.eq(busy_o & ~(self.rd.rel_o[0] | self.rd.rel_o[1]))
# 3rd operand only needed when operation is a store
- comb += self.rd.rel[2].eq(src_l.q[2] & busy_o & op_is_st)
+ comb += self.rd.rel_o[2].eq(src_l.q[2] & busy_o & op_is_st)
# all reads done when alu is valid and 3rd operand needed
- comb += rd_done.eq(alu_valid & ~self.rd.rel[2])
+ comb += rd_done.eq(alu_valid & ~self.rd.rel_o[2])
# address release only if addr ready, but Port must be idle
comb += self.adr_rel_o.eq(alu_valid & adr_l.q & busy_o)
# store release when st ready *and* all operands read (and no shadow)
- comb += self.st.rel.eq(sto_l.q & busy_o & rd_done & op_is_st &
+ comb += self.st.rel_o.eq(sto_l.q & busy_o & rd_done & op_is_st &
self.shadown_i)
# request write of LD result. waits until shadow is dropped.
- comb += self.wr.rel[0].eq(rd_done & wri_l.q & busy_o & lod_l.qn &
+ comb += self.wr.rel_o[0].eq(rd_done & wri_l.q & busy_o & lod_l.qn &
op_is_ld & self.shadown_i)
# request write of EA result only in update mode
- comb += self.wr.rel[1].eq(upd_l.q & busy_o & op_is_update & alu_valid &
- self.shadown_i)
+ comb += self.wr.rel_o[1].eq(upd_l.q & busy_o & op_is_update &
+ alu_valid & self.shadown_i)
# provide "done" signal: select req_rel for non-LD/ST, adr_rel for LD/ST
- comb += wr_any.eq(self.st.go | p_st_go | self.wr.go[0] | self.wr.go[1])
+ comb += wr_any.eq(self.st.go_i | p_st_go |
+ self.wr.go_i[0] | self.wr.go_i[1])
comb += wr_reset.eq(rst_l.q & busy_o & self.shadown_i &
- ~(self.st.rel | self.wr.rel[0] | self.wr.rel[1]) &
+ ~(self.st.rel_o | self.wr.rel_o[0] |
+ self.wr.rel_o[1]) &
(lod_l.qn | op_is_st))
comb += self.done_o.eq(wr_reset)
# put the LD-output register directly onto the output bus on a go_write
comb += self.data_o.data.eq(self.dest[0])
- with m.If(self.wr.go[0]):
+ with m.If(self.wr.go_i[0]):
comb += self.dest[0].eq(ldd_r)
# "update" mode, put address out on 2nd go-write
comb += self.addr_o.data.eq(self.dest[1])
- with m.If(op_is_update & self.wr.go[1]):
+ with m.If(op_is_update & self.wr.go_i[1]):
comb += self.dest[1].eq(addr_r)
# need to look like MultiCompUnit: put wrmask out.
stdata_r = byte_reverse(m, 'stdata_r', srl[2], data_len)
comb += pi.st.data.eq(stdata_r)
# store - data goes in based on go_st
- comb += pi.st.ok.eq(self.st.go) # go store signals st data valid
+ comb += pi.st.ok.eq(self.st.go_i) # go store signals st data valid
return m
return self.get_out(i)
def __iter__(self):
- yield self.rd.go
+ yield self.rd.go_i
yield self.go_ad_i
- yield self.wr.go
+ yield self.wr.go_i
yield self.go_st_i
yield self.issue_i
yield self.shadown_i
yield from self.oper_i.ports()
yield from self.src_i
yield self.busy_o
- yield self.rd.rel
+ yield self.rd.rel_o
yield self.adr_rel_o
yield self.sto_rel_o
- yield self.wr.rel
+ yield self.wr.rel_o
yield from self.data_o.ports()
yield from self.addr_o.ports()
yield self.load_mem_o
active_rel = 0b111
# wait for all active rel signals to come up
while True:
- rel = yield dut.rd.rel
+ rel = yield dut.rd.rel_o
if rel == active_rel:
break
yield
# yield dut.ad.go.eq(0)
if update:
- yield from wait_for(dut.wr.rel[1])
+ yield from wait_for(dut.wr.rel_o[1])
yield dut.wr.go.eq(0b10)
yield
addr = yield dut.addr_o
# wait for the operands (RA, RB, or both)
if rd:
yield dut.rd.go.eq(rd)
- yield from wait_for(dut.rd.rel)
+ yield from wait_for(dut.rd.rel_o)
yield dut.rd.go.eq(0)
yield from wait_for(dut.adr_rel_o, False, test1st=True)
# yield dut.ad.go.eq(0)
if update:
- yield from wait_for(dut.wr.rel[1])
+ yield from wait_for(dut.wr.rel_o[1])
yield dut.wr.go.eq(0b10)
yield
addr = yield dut.addr_o
else:
addr = None
- yield from wait_for(dut.wr.rel[0], test1st=True)
+ yield from wait_for(dut.wr.rel_o[0], test1st=True)
yield dut.wr.go.eq(1)
yield
data = yield dut.data_o
yield dut.issue_i.eq(0)
yield
- yield dut.rd.go.eq(0b11)
+ yield dut.rd.go_i.eq(0b11)
while True:
yield
- rd_rel_o = yield dut.rd.rel
+ rd_rel_o = yield dut.rd.rel_o
print("rd_rel", rd_rel_o)
if rd_rel_o:
break
- yield dut.rd.go.eq(0)
+ yield dut.rd.go_i.eq(0)
- req_rel_o = yield dut.wr.rel
+ req_rel_o = yield dut.wr.rel_o
result = yield dut.data_o
print("req_rel", req_rel_o, result)
while True:
- req_rel_o = yield dut.wr.rel
+ req_rel_o = yield dut.wr.rel_o
result = yield dut.data_o
print("req_rel", req_rel_o, result)
if req_rel_o:
break
yield
- yield dut.wr.go[0].eq(1)
+ yield dut.wr.go_i[0].eq(1)
yield Settle()
result = yield dut.data_o
yield
print("result", result)
- yield dut.wr.go[0].eq(0)
+ yield dut.wr.go_i[0].eq(0)
yield
return result
yield dut.issue_i.eq(0)
yield
if not imm_ok or not zero_a:
- yield dut.rd.go.eq(0b11)
+ yield dut.rd.go_i.eq(0b11)
while True:
yield
- rd_rel_o = yield dut.rd.rel
+ rd_rel_o = yield dut.rd.rel_o
print("rd_rel", rd_rel_o)
if rd_rel_o:
break
- yield dut.rd.go.eq(0)
+ yield dut.rd.go_i.eq(0)
else:
print("no go rd")
if len(dut.src_i) == 3:
- yield dut.rd.go.eq(0b100)
+ yield dut.rd.go_i.eq(0b100)
while True:
yield
- rd_rel_o = yield dut.rd.rel
+ rd_rel_o = yield dut.rd.rel_o
print("rd_rel", rd_rel_o)
if rd_rel_o:
break
- yield dut.rd.go.eq(0)
+ yield dut.rd.go_i.eq(0)
else:
print("no 3rd rd")
- req_rel_o = yield dut.wr.rel
+ req_rel_o = yield dut.wr.rel_o
result = yield dut.data_o
print("req_rel", req_rel_o, result)
while True:
- req_rel_o = yield dut.wr.rel
+ req_rel_o = yield dut.wr.rel_o
result = yield dut.data_o
print("req_rel", req_rel_o, result)
if req_rel_o:
break
yield
- yield dut.wr.go[0].eq(1)
+ yield dut.wr.go_i[0].eq(1)
yield Settle()
result = yield dut.data_o
yield
print("result", result)
- yield dut.wr.go[0].eq(0)
+ yield dut.wr.go_i[0].eq(0)
yield
return result
if issue_i:
break
# issue_i has not risen yet, so rd must keep low
- rel = yield self.dut.rd.rel[rd_idx]
+ rel = yield self.dut.rd.rel_o[rd_idx]
assert not rel
yield
return
# issue_i has risen. rel must rise on the next cycle
- rel = yield self.dut.rd.rel[rd_idx]
+ rel = yield self.dut.rd.rel_o[rd_idx]
assert not rel
# stall for additional cycles. Check that rel doesn't fall on its own
for n in range(self.RD_GO_DELAY[rd_idx]):
yield
- rel = yield self.dut.rd.rel[rd_idx]
+ rel = yield self.dut.rd.rel_o[rd_idx]
assert rel
# Before asserting "go", make sure "rel" has risen.
# The use of Settle allows "go" to be set combinatorially,
# rising on the same cycle as "rel".
yield Settle()
- rel = yield self.dut.rd.rel[rd_idx]
+ rel = yield self.dut.rd.rel_o[rd_idx]
assert rel
# assert go for one cycle, passing along the operand value
- yield self.dut.rd.go[rd_idx].eq(1)
+ yield self.dut.rd.go_i[rd_idx].eq(1)
yield self.dut.src_i[rd_idx].eq(self.operands[rd_idx])
# check that the operand was sent to the alu
# TODO: Properly check the alu protocol
yield
# rel must keep high, since go was inactive in the last cycle
- rel = yield self.dut.rd.rel[rd_idx]
+ rel = yield self.dut.rd.rel_o[rd_idx]
assert rel
# finish the go one-clock pulse
- yield self.dut.rd.go[rd_idx].eq(0)
+ yield self.dut.rd.go_i[rd_idx].eq(0)
yield self.dut.src_i[rd_idx].eq(0)
yield
# rel must have gone low in response to go being high
# on the previous cycle
- rel = yield self.dut.rd.rel[rd_idx]
+ rel = yield self.dut.rd.rel_o[rd_idx]
assert not rel
self.rd_complete[rd_idx] = True
rdop = cu.get_in_name(idx)
yield cu.src_i[idx].eq(data)
while True:
- rd_rel_o = yield cu.rd.rel[idx]
+ rd_rel_o = yield cu.rd.rel_o[idx]
print("rd_rel %d wait HI" % idx, rd_rel_o, rdop, hex(data))
if rd_rel_o:
break
yield
- yield cu.rd.go[idx].eq(1)
+ yield cu.rd.go_i[idx].eq(1)
while True:
yield
- rd_rel_o = yield cu.rd.rel[idx]
+ rd_rel_o = yield cu.rd.rel_o[idx]
if rd_rel_o:
break
print("rd_rel %d wait HI" % idx, rd_rel_o)
yield
- yield cu.rd.go[idx].eq(0)
+ yield cu.rd.go_i[idx].eq(0)
yield cu.src_i[idx].eq(0)
"write-operand '%s' Data.ok likely not set (%s)" \
% (code, idx, wrop, hex(wrok))
while True:
- wr_relall_o = yield cu.wr.rel
- wr_rel_o = yield cu.wr.rel[idx]
+ wr_relall_o = yield cu.wr.rel_o
+ wr_rel_o = yield cu.wr.rel_o[idx]
print("wr_rel %d wait" % idx, hex(wr_relall_o), wr_rel_o)
if wr_rel_o:
break
yield
- yield cu.wr.go[idx].eq(1)
+ yield cu.wr.go_i[idx].eq(1)
yield Settle()
result = yield cu.dest[idx]
yield
- yield cu.wr.go[idx].eq(0)
+ yield cu.wr.go_i[idx].eq(0)
print("result", repr(code), idx, wrop, wrok, hex(result))
return result
yield
wrmask = yield cu.wrmask
- wr_rel_o = yield cu.wr.rel
+ wr_rel_o = yield cu.wr.rel_o
print("get_cu_outputs", cu.n_dst, wrmask, wr_rel_o)
# no point waiting (however really should doublecheck wr.rel)
if not wrmask:
return {}
# wait for at least one result
while True:
- wr_rel_o = yield cu.wr.rel
+ wr_rel_o = yield cu.wr.rel_o
if wr_rel_o:
break
yield
for i in range(cu.n_dst):
- wr_rel_o = yield cu.wr.rel[i]
+ wr_rel_o = yield cu.wr.rel_o[i]
if wr_rel_o:
result = yield from get_cu_output(cu, i, code)
wrop = cu.get_out_name(i)
yield Settle()
# set inputs into CU
- rd_rel_o = yield cu.rd.rel
- wr_rel_o = yield cu.wr.rel
+ rd_rel_o = yield cu.rd.rel_o
+ wr_rel_o = yield cu.wr.rel_o
print("before inputs, rd_rel, wr_rel: ",
bin(rd_rel_o), bin(wr_rel_o))
assert wr_rel_o == 0, "wr.rel %s must be zero. "\
"respec %s" % \
(bin(wr_rel_o), cu.rwid[1])
yield from set_cu_inputs(cu, inp)
- rd_rel_o = yield cu.rd.rel
- wr_rel_o = yield cu.wr.rel
+ rd_rel_o = yield cu.rd.rel_o
+ wr_rel_o = yield cu.wr.rel_o
wrmask = yield cu.wrmask
print("after inputs, rd_rel, wr_rel, wrmask: ",
bin(rd_rel_o), bin(wr_rel_o), bin(wrmask))
# get all outputs (one by one, just "because")
res = yield from get_cu_outputs(cu, code)
wrmask = yield cu.wrmask
- rd_rel_o = yield cu.rd.rel
- wr_rel_o = yield cu.wr.rel
+ rd_rel_o = yield cu.rd.rel_o
+ wr_rel_o = yield cu.wr.rel_o
print("after got outputs, rd_rel, wr_rel, wrmask: ",
bin(rd_rel_o), bin(wr_rel_o), bin(wrmask))
# connect request-read to picker input, and output to go-wr
fu_active = fu_bitdict[funame]
- pick = fu.wr.rel[idx] & fu_active # & wrflag
+ pick = fu.wr.rel_o[idx] & fu_active # & wrflag
comb += wrpick.i[pi].eq(pick)
comb += fu.go_wr_i[idx].eq(wrpick.o[pi] & wrpick.en_o)
# connect regfile port to input
# temporary hack: says "go" immediately for both address gen and ST
l0 = core.l0
ldst = core.fus.fus['ldst0']
- m.d.comb += ldst.ad.go.eq(ldst.ad.rel) # link addr-go direct to rel
- m.d.comb += ldst.st.go.eq(ldst.st.rel) # link store-go direct to rel
+ m.d.comb += ldst.ad.go_i.eq(ldst.ad.rel_o) # link addr-go direct to rel
+ m.d.comb += ldst.st.go_i.eq(ldst.st.rel_o) # link store-go direct to rel
# PC and instruction from I-Memory
current_insn = Signal(32) # current fetched instruction (note sync)