X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Fexperiment%2Falu_hier.py;h=29c97d7da3e49a2790f7ef9ddd4a1ff77c42156e;hb=3d9758479d99c0d88d13bcbb04bc0af6670051ba;hp=0172625817333fa225df0311b8eb0aa794ba5c43;hpb=13a86991ab338a331b61a5299cc4802a45773c0a;p=soc.git diff --git a/src/soc/experiment/alu_hier.py b/src/soc/experiment/alu_hier.py index 01726258..29c97d7d 100644 --- a/src/soc/experiment/alu_hier.py +++ b/src/soc/experiment/alu_hier.py @@ -9,89 +9,20 @@ A "real" integer ALU would place the answers onto the output bus after only one cycle (sync) """ -from nmigen import Elaboratable, Signal, Module, Const, Mux +from nmigen import Elaboratable, Signal, Module, Const, Mux, Array from nmigen.hdl.rec import Record, Layout from nmigen.cli import main from nmigen.cli import verilog, rtlil from nmigen.compat.sim import run_simulation -from soc.decoder.power_enums import InternalOp, CryIn +from soc.decoder.power_enums import InternalOp, Function, CryIn + +from soc.fu.alu.alu_input_record import CompALUOpSubset import operator -class CompALUOpSubset(Record): - """CompALUOpSubset - - a copy of the relevant subset information from Decode2Execute1Type - needed for ALU operations. use with eq_from_execute1 (below) to - grab subsets. - """ - def __init__(self): - layout = (('insn_type', InternalOp), - ('nia', 64), - ('imm_data', Layout((("imm", 64), ("imm_ok", 1)))), - #'cr = Signal(32, reset_less=True) # NO: this is from the CR SPR - #'xerc = XerBits() # NO: this is from the XER SPR - ('lk', 1), - ('rc', Layout((("rc", 1), ("rc_ok", 1)))), - ('oe', Layout((("oe", 1), ("oe_ok", 1)))), - ('invert_a', 1), - ('invert_out', 1), - ('input_carry', CryIn), - ('output_carry', 1), - ('input_cr', 1), - ('output_cr', 1), - ('is_32bit', 1), - ('is_signed', 1), - ('byte_reverse', 1), - ('sign_extend', 1)) - - Record.__init__(self, Layout(layout)) - - # grrr. Record does not have kwargs - self.insn_type.reset_less = True - self.nia.reset_less = True - #self.cr = Signal(32, reset_less = True - #self.xerc = XerBits( - self.lk.reset_less = True - self.invert_a.reset_less = True - self.invert_out.reset_less = True - self.input_carry.reset_less = True - self.output_carry.reset_less = True - self.input_cr.reset_less = True - self.output_cr.reset_less = True - self.is_32bit.reset_less = True - self.is_signed.reset_less = True - self.byte_reverse.reset_less = True - self.sign_extend.reset_less = True - - def eq_from_execute1(self, other): - """ use this to copy in from Decode2Execute1Type - """ - res = [] - for fname, sig in self.fields.items(): - eqfrom = other.fields[fname] - res.append(sig.eq(eqfrom) - return res - def ports(self): - return [self.insn_type, - self.nia, - #self.cr, - #self.xerc, - self.lk, - self.invert_a, - self.invert_out, - self.input_carry, - self.output_carry, - self.input_cr, - self.output_cr, - self.is_32bit, - self.is_signed, - self.byte_reverse, - self.sign_extend, - ] class Adder(Elaboratable): def __init__(self, width): @@ -147,19 +78,35 @@ class Shifter(Elaboratable): m.d.comb += self.o.eq(self.a >> btrunc) return m +class Dummy: + pass class ALU(Elaboratable): def __init__(self, width): - self.p_valid_i = Signal() - self.p_ready_o = Signal() - self.n_ready_i = Signal() - self.n_valid_o = Signal() + self.p = Dummy() # make look like nmutil pipeline API + self.p.data_i = Dummy() + self.p.data_i.ctx = Dummy() + self.n = Dummy() # make look like nmutil pipeline API + self.n.data_o = Dummy() + self.p.valid_i = Signal() + self.p.ready_o = Signal() + self.n.ready_i = Signal() + self.n.valid_o = Signal() self.counter = Signal(4) self.op = CompALUOpSubset() - self.a = Signal(width) - self.b = Signal(width) - self.o = Signal(width) + i = [] + i.append(Signal(width, name="i1")) + i.append(Signal(width, name="i2")) + self.i = Array(i) + self.a, self.b = i[0], i[1] + self.out = Array([Signal(width)]) + self.o = self.out[0] self.width = width + # more "look like nmutil pipeline API" + self.p.data_i.ctx.op = self.op + self.p.data_i.a = self.a + self.p.data_i.b = self.b + self.n.data_o.o = self.o def elaborate(self, platform): m = Module() @@ -183,11 +130,11 @@ class ALU(Elaboratable): go_now = Signal(reset_less=True) # testing no-delay ALU - with m.If(self.p_valid_i): + with m.If(self.p.valid_i): # input is valid. next check, if we already said "ready" or not - with m.If(~self.p_ready_o): + with m.If(~self.p.ready_o): # we didn't say "ready" yet, so say so and initialise - m.d.sync += self.p_ready_o.eq(1) + m.d.sync += self.p.ready_o.eq(1) # as this is a "fake" pipeline, just grab the output right now with m.If(self.op.insn_type == InternalOp.OP_ADD): @@ -217,14 +164,14 @@ class ALU(Elaboratable): with m.Else(): # input says no longer valid, so drop ready as well. # a "proper" ALU would have had to sync in the opcode and a/b ops - m.d.sync += self.p_ready_o.eq(0) + m.d.sync += self.p.ready_o.eq(0) # ok so the counter's running: when it gets to 1, fire the output with m.If((self.counter == 1) | go_now): # set the output as valid if the recipient is ready for it - m.d.sync += self.n_valid_o.eq(1) - with m.If(self.n_ready_i & self.n_valid_o): - m.d.sync += self.n_valid_o.eq(0) + m.d.sync += self.n.valid_o.eq(1) + with m.If(self.n.ready_i & self.n.valid_o): + m.d.sync += self.n.valid_o.eq(0) # recipient said it was ready: reset back to known-good. m.d.sync += self.counter.eq(0) # reset the counter m.d.sync += self.o.eq(0) # clear the output for tidiness sake @@ -260,15 +207,19 @@ class BranchOp(Elaboratable): class BranchALU(Elaboratable): def __init__(self, width): - self.p_valid_i = Signal() - self.p_ready_o = Signal() - self.n_ready_i = Signal() - self.n_valid_o = Signal() + self.p.valid_i = Signal() + self.p.ready_o = Signal() + self.n.ready_i = Signal() + self.n.valid_o = Signal() self.counter = Signal(4) self.op = Signal(2) - self.a = Signal(width) - self.b = Signal(width) - self.o = Signal(width) + i = [] + i.append(Signal(width, name="i1")) + i.append(Signal(width, name="i2")) + self.i = Array(i) + self.a, self.b = i[0], i[1] + self.out = Array([Signal(width)]) + self.o = self.out[0] self.width = width def elaborate(self, platform): @@ -289,11 +240,11 @@ class BranchALU(Elaboratable): ] go_now = Signal(reset_less=True) # testing no-delay ALU - with m.If(self.p_valid_i): + with m.If(self.p.valid_i): # input is valid. next check, if we already said "ready" or not - with m.If(~self.p_ready_o): + with m.If(~self.p.ready_o): # we didn't say "ready" yet, so say so and initialise - m.d.sync += self.p_ready_o.eq(1) + m.d.sync += self.p.ready_o.eq(1) # as this is a "fake" pipeline, just grab the output right now with m.Switch(self.op): @@ -305,14 +256,14 @@ class BranchALU(Elaboratable): with m.Else(): # input says no longer valid, so drop ready as well. # a "proper" ALU would have had to sync in the opcode and a/b ops - m.d.sync += self.p_ready_o.eq(0) + m.d.sync += self.p.ready_o.eq(0) # ok so the counter's running: when it gets to 1, fire the output with m.If((self.counter == 1) | go_now): # set the output as valid if the recipient is ready for it - m.d.sync += self.n_valid_o.eq(1) - with m.If(self.n_ready_i & self.n_valid_o): - m.d.sync += self.n_valid_o.eq(0) + m.d.sync += self.n.valid_o.eq(1) + with m.If(self.n.ready_i & self.n.valid_o): + m.d.sync += self.n.valid_o.eq(0) # recipient said it was ready: reset back to known-good. m.d.sync += self.counter.eq(0) # reset the counter m.d.sync += self.o.eq(0) # clear the output for tidiness sake @@ -337,19 +288,19 @@ def run_op(dut, a, b, op, inv_a=0): yield dut.b.eq(b) yield dut.op.insn_type.eq(op) yield dut.op.invert_a.eq(inv_a) - yield dut.n_ready_i.eq(0) - yield dut.p_valid_i.eq(1) + yield dut.n.ready_i.eq(0) + yield dut.p.valid_i.eq(1) yield while True: yield - n_valid_o = yield dut.n_valid_o - if n_valid_o: + n.valid_o = yield dut.n.valid_o + if n.valid_o: break yield result = yield dut.o - yield dut.p_valid_i.eq(0) - yield dut.n_ready_i.eq(0) + yield dut.p.valid_i.eq(0) + yield dut.n.ready_i.eq(0) yield return result