X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Fexperiment%2Fcompalu.py;h=89d2da1a2c8c0210b0733d6a9c5b0f2ef634b92c;hb=619ae1255f5e0f4805e406479c1c67899c81124e;hp=13884c503342095ea7668f8fc9e84e9e24f99e74;hpb=c3f89e72194fd37f122221dc6463951ef96f39a4;p=soc.git diff --git a/src/soc/experiment/compalu.py b/src/soc/experiment/compalu.py index 13884c50..89d2da1a 100644 --- a/src/soc/experiment/compalu.py +++ b/src/soc/experiment/compalu.py @@ -4,8 +4,9 @@ from nmigen import Module, Signal, Mux, Elaboratable from nmutil.latch import SRLatch, latchregister from soc.decoder.power_decoder2 import Data -from soc.decoder.power_enums import InternalOp +from soc.decoder.power_enums import MicrOp +from soc.experiment.alu_hier import CompALUOpSubset """ Computation Unit (aka "ALU Manager"). @@ -39,44 +40,39 @@ from soc.decoder.power_enums import InternalOp register is placed combinatorially onto the output, and (2) the req_l latch is cleared, busy is dropped, and the Comp Unit is back through its revolving door to do another task. - - Notes on oper_i: - - * bits[0:2] are for the ALU, add=0, sub=1, shift=2, mul=3 - * bit[2] are the immediate (bit[2]=1 == immediate mode) """ + class ComputationUnitNoDelay(Elaboratable): - def __init__(self, rwid, e, alu): + def __init__(self, rwid, alu): self.rwid = rwid - self.alu = alu # actual ALU - set as a "submodule" of the CU - self.e = e # decoded instruction + self.alu = alu # actual ALU - set as a "submodule" of the CU self.counter = Signal(4) - self.go_rd_i = Signal(reset_less=True) # go read in - self.go_wr_i = Signal(reset_less=True) # go write in - 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.go_rd_i = Signal(reset_less=True) # go read in + self.go_wr_i = Signal(reset_less=True) # go write in + 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) # operation / data input - self.oper_i = e.insn_type # operand - self.imm_i = e.imm_data # immediate in - self.src1_i = Signal(rwid, reset_less=True) # oper1 in - self.src2_i = Signal(rwid, reset_less=True) # oper2 in + self.oper_i = CompALUOpSubset() # operand + self.src1_i = Signal(rwid, reset_less=True) # oper1 in + self.src2_i = Signal(rwid, reset_less=True) # oper2 in - self.busy_o = Signal(reset_less=True) # fn busy out - self.data_o = Signal(rwid, reset_less=True) # Dest out - self.rd_rel_o = Signal(reset_less=True) # release src1/src2 request - self.req_rel_o = Signal(reset_less=True) # release request out (valid_o) - self.done_o = self.req_rel_o # 'normalise' API + self.busy_o = Signal(reset_less=True) # fn busy out + self.data_o = Signal(rwid, reset_less=True) # Dest out + self.rd_rel_o = Signal(reset_less=True) # release src1/src2 request + # release request out (valid_o) + self.req_rel_o = Signal(reset_less=True) + self.done_o = self.req_rel_o # 'normalise' API def elaborate(self, platform): m = Module() m.submodules.alu = self.alu - m.submodules.src_l = src_l = SRLatch(sync=False) - m.submodules.opc_l = opc_l = SRLatch(sync=False) - m.submodules.req_l = req_l = SRLatch(sync=False) + m.submodules.src_l = src_l = SRLatch(sync=False, name="src") + m.submodules.opc_l = opc_l = SRLatch(sync=False, name="opc") + m.submodules.req_l = req_l = SRLatch(sync=False, name="req") # shadow/go_die reset_w = Signal(reset_less=True) @@ -89,7 +85,7 @@ class ComputationUnitNoDelay(Elaboratable): # latches be set at the same time. # opcode latch (not using go_rd_i) - inverted so that busy resets to 0 - m.d.sync += opc_l.s.eq(self.issue_i) # XXX NOTE: INVERTED FROM book! + m.d.sync += opc_l.s.eq(self.issue_i) # XXX NOTE: INVERTED FROM book! m.d.sync += opc_l.r.eq(reset_w) # XXX NOTE: INVERTED FROM book! # src operand latch (not using go_wr_i) @@ -101,26 +97,24 @@ class ComputationUnitNoDelay(Elaboratable): m.d.sync += req_l.r.eq(reset_w) # create a latch/register for the operand - oper_r = Signal(InternalOp, reset_less=True) # opcode reg - latchregister(m, self.oper_i, oper_r, self.issue_i) + oper_r = CompALUOpSubset() + latchregister(m, self.oper_i, oper_r, self.issue_i, "oper_l") # and one for the output from the ALU - data_r = Signal(self.rwid, reset_less=True) # Dest register - latchregister(m, self.alu.o, data_r, req_l.q) + data_r = Signal(self.rwid, reset_less=True) # Dest register + latchregister(m, self.alu.o, data_r, req_l.q, "data_l") - # get the top 2 bits for the ALU - m.d.comb += self.alu.op.eq(oper_r[0:2]) - - # 3rd bit is whether this is an immediate or not - op_is_imm = Signal(reset_less=True) - m.d.comb += op_is_imm.eq(oper_r[2]) + # pass the operation to the ALU + m.d.comb += self.alu.op.eq(oper_r) # select immediate if opcode says so. however also change the latch # to trigger *from* the opcode latch instead. + op_is_imm = oper_r.imm_data.imm_ok src2_or_imm = Signal(self.rwid, reset_less=True) src_sel = Signal(reset_less=True) - m.d.comb += src_sel.eq(Mux(op_is_imm, opc_l.qn, src_l.q)) - m.d.comb += src2_or_imm.eq(Mux(op_is_imm, self.imm_i, self.src2_i)) + m.d.comb += src_sel.eq(Mux(op_is_imm, opc_l.q, src_l.q)) + m.d.comb += src2_or_imm.eq(Mux(op_is_imm, oper_r.imm_data.imm, + self.src2_i)) # create a latch/register for src1/src2 latchregister(m, self.src1_i, self.alu.a, src_l.q) @@ -132,23 +126,24 @@ class ComputationUnitNoDelay(Elaboratable): # all request signals gated by busy_o. prevents picker problems busy_o = self.busy_o - m.d.comb += busy_o.eq(opc_l.q) # busy out - m.d.comb += self.rd_rel_o.eq(src_l.q & busy_o) # src1/src2 req rel + m.d.comb += busy_o.eq(opc_l.q) # busy out + m.d.comb += self.rd_rel_o.eq(src_l.q & busy_o) # src1/src2 req rel # on a go_read, tell the ALU we're accepting data. # NOTE: this spells TROUBLE if the ALU isn't ready! # go_read is only valid for one clock! with m.If(self.go_rd_i): # src operands ready, GO! with m.If(~self.alu.p_ready_o): # no ACK yet - m.d.comb += self.alu.p_valid_i.eq(1) # so indicate valid + m.d.comb += self.alu.p_valid_i.eq(1) # so indicate valid # only proceed if ALU says its output is valid with m.If(self.alu.n_valid_o): # when ALU ready, write req release out. waits for shadow m.d.comb += self.req_rel_o.eq(req_l.q & busy_o & self.shadown_i) # when output latch is ready, and ALU says ready, accept ALU output - with m.If(self.req_rel_o): - m.d.comb += self.alu.n_ready_i.eq(1) # tells ALU "thanks got it" + with m.If(self.req_rel_o & self.go_wr_i): + # tells ALU "thanks got it" + m.d.comb += self.alu.n_ready_i.eq(1) # output the data from the latch on go_write with m.If(self.go_wr_i): @@ -162,8 +157,7 @@ class ComputationUnitNoDelay(Elaboratable): yield self.issue_i yield self.shadown_i yield self.go_die_i - yield self.oper_i - yield from self.imm_i.ports() + yield from self.oper_i.ports() yield self.src1_i yield self.src2_i yield self.busy_o @@ -175,40 +169,71 @@ class ComputationUnitNoDelay(Elaboratable): return list(self) -def scoreboard_sim(dut): - yield dut.dest_i.eq(1) - yield dut.issue_i.eq(1) - yield +def op_sim(dut, a, b, op, inv_a=0, imm=0, imm_ok=0): yield dut.issue_i.eq(0) yield - yield dut.src1_i.eq(1) + yield dut.src1_i.eq(a) + yield dut.src2_i.eq(b) + yield dut.oper_i.insn_type.eq(op) + yield dut.oper_i.invert_in.eq(inv_a) + yield dut.oper_i.imm_data.imm.eq(imm) + yield dut.oper_i.imm_data.imm_ok.eq(imm_ok) yield dut.issue_i.eq(1) yield - yield - yield yield dut.issue_i.eq(0) yield - yield dut.go_read_i.eq(1) + yield dut.go_rd_i.eq(1) + while True: + yield + rd_rel_o = yield dut.rd_rel_o + print("rd_rel", rd_rel_o) + if rd_rel_o: + break yield - yield dut.go_read_i.eq(0) + yield dut.go_rd_i.eq(0) + req_rel_o = yield dut.req_rel_o + result = yield dut.data_o + print("req_rel", req_rel_o, result) + while True: + req_rel_o = yield dut.req_rel_o + result = yield dut.data_o + print("req_rel", req_rel_o, result) + if req_rel_o: + break + yield + yield dut.go_wr_i.eq(1) yield - yield dut.go_write_i.eq(1) - yield - yield dut.go_write_i.eq(0) + result = yield dut.data_o + print("result", result) + yield dut.go_wr_i.eq(0) yield + return result + + +def scoreboard_sim(dut): + result = yield from op_sim(dut, 5, 2, MicrOp.OP_ADD, inv_a=0, + imm=8, imm_ok=1) + assert result == 13 + + result = yield from op_sim(dut, 5, 2, MicrOp.OP_ADD, inv_a=1) + assert result == 65532 + + result = yield from op_sim(dut, 5, 2, MicrOp.OP_ADD) + assert result == 7 + def test_scoreboard(): from alu_hier import ALU from soc.decoder.power_decoder2 import Decode2ToExecute1Type - e = Decode2ToExecute1Type() alu = ALU(16) - dut = ComputationUnitNoDelay(16, e, alu) + dut = ComputationUnitNoDelay(16, alu) vl = rtlil.convert(dut, ports=dut.ports()) with open("test_compalu.il", "w") as f: f.write(vl) run_simulation(dut, scoreboard_sim(dut), vcd_name='test_compalu.vcd') + if __name__ == '__main__': test_scoreboard()