From 83144c79c0913c09ba3aa090676d80b306854c3b Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Mon, 25 Mar 2019 10:35:23 +0000 Subject: [PATCH] example_buf_pipe.py p.o_ready needs to be set as a group, regardless of input mux --- src/add/example_buf_pipe.py | 43 +++++++++++++++----- src/add/test_buf_pipe.py | 80 +++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 10 deletions(-) diff --git a/src/add/example_buf_pipe.py b/src/add/example_buf_pipe.py index 7b14b0a7..c5211975 100644 --- a/src/add/example_buf_pipe.py +++ b/src/add/example_buf_pipe.py @@ -368,6 +368,7 @@ class BufferedPipeline(PipelineBase): # need an array of buffer registers conforming to *output* spec r_data = [] + p_len = len(self.p) for i in range(len(self.p)): r = self.stage.ospec() # output type r_data.append(r) @@ -405,21 +406,30 @@ class BufferedPipeline(PipelineBase): # Flush the [already processed] buffer to the output port. m.d.sync += [self.n[ni].o_valid.eq(1), # declare reg empty eq(self.n[ni].o_data, r_data[ni]), # flush buffer - self.p[pi].o_ready.eq(1), # clear stall ] - # ignore input, since p.o_ready is also false. + for i in range(p_len): + m.d.sync += self.p[i].o_ready.eq(1) # clear stall + # ignore input, since p.o_ready is false (in current clock) # (n.i_ready) is false here: next stage is ready with m.Elif(o_n_validn): # next stage being told "ready" m.d.sync += [self.n[ni].o_valid.eq(p_i_valid), - self.p[pi].o_ready.eq(1), # Keep the buffer empty + self.p[pi].o_ready.eq(1), eq(self.n[ni].o_data, result), # set output data ] + for i in range(p_len): + m.d.sync += self.p[i].o_ready.eq(1) # Keep the buffer empty # (n.i_ready) false and (n.o_valid) true: with m.Elif(i_p_valid_o_p_ready): # If next stage *is* ready, and not stalled yet, accept input - m.d.sync += self.p[pi].o_ready.eq(~(p_i_valid & self.n[ni].o_valid)) + for i in range(p_len): + piv = Signal(reset_less=True) + pnv = Signal(reset_less=True) + m.d.comb += [p_i_valid.eq(self.p[i].i_valid_logic()), + pnv.eq(~(p_i_valid & self.n[ni].o_valid)) + ] + m.d.sync += self.p[i].o_ready.eq(pnv) return m @@ -530,8 +540,10 @@ class UnbufferedPipeline(PipelineBase): SYNCHRONOUSLY. """ - def __init__(self, stage, p_len=1, n_len=1): + def __init__(self, stage, n_len=1, p_len=1, p_mux=None, n_mux=None): PipelineBase.__init__(self, stage, p_len, n_len) + self.p_mux = p_mux + self.n_mux = n_mux self._data_valid = Signal() # set up the input and output data @@ -543,9 +555,13 @@ class UnbufferedPipeline(PipelineBase): def elaborate(self, platform): m = Module() + if self.p_mux: + m.submodules += self.p_mux + # need an array of buffer registers conforming to *input* spec r_data = [] - for i in range(len(self.p)): + p_len = len(self.p) + for i in range(p_len): r = self.stage.ispec() # input type r_data.append(r) if hasattr(self.stage, "setup"): @@ -553,14 +569,21 @@ class UnbufferedPipeline(PipelineBase): if len(r_data) > 1: r_data = Array(r_data) - pi = 0 # TODO: use p_mux to decide which to select ni = 0 # TODO: use n_nux to decide which to select - p_i_valid = Signal(reset_less=True) + if self.p_mux: + pi = self.p_mux.mid + p_i_valid = self.p_mux.valid + else: + pi = 0 + p_i_valid = Signal(reset_less=True) + m.d.comb += p_i_valid.eq(self.p[pi].i_valid_logic()) + m.d.comb += p_i_valid.eq(self.p[pi].i_valid_logic()) m.d.comb += self.n[ni].o_valid.eq(self._data_valid) - m.d.comb += self.p[pi].o_ready.eq(~self._data_valid | \ - self.n[ni].i_ready) + for i in range(p_len): + m.d.comb += self.p[i].o_ready.eq(~self._data_valid | \ + self.n[ni].i_ready) m.d.sync += self._data_valid.eq(p_i_valid | \ (~self.n[ni].i_ready & self._data_valid)) with m.If(self.p[pi].i_valid & self.p[pi].o_ready): diff --git a/src/add/test_buf_pipe.py b/src/add/test_buf_pipe.py index 0811b3a6..441e5d94 100644 --- a/src/add/test_buf_pipe.py +++ b/src/add/test_buf_pipe.py @@ -546,6 +546,86 @@ def data_2op(): data.append(TestInputAdd(randint(0, 1<<16-1), randint(0, 1<<16-1))) return data +class InputPriorityArbiter: + def __init__(self, pipe, num_rows): + self.pipe = pipe + self.num_rows = num_rows + self.mmax = int(log(self.num_rows) / log(2)) + self.mid = Signal(self.mmax, reset_less=True) # multiplex id + self.active = Signal(reset_less=True) + + def elaborate(self, platform): + m = Module() + + assert len(self.pipe.p) == self.num_rows, \ + "must declare input to be same size" + pe = PriorityEncoder(self.num_rows) + m.submodules.selector = pe + + # connect priority encoder + in_ready = [] + for i in range(self.num_rows): + p_i_valid = Signal(reset_less=True) + m.d.comb += p_i_valid.eq(self.pipe[i].i_valid_logic()) + in_ready.append(p_i_valid) + m.d.comb += pe.i.eq(Cat(*in_ready)) # array of input "valids" + m.d.comb += self.active.eq(~pe.n) # encoder active (one input valid) + m.d.comb += self.mid.eq(pe.o) # output one active input + + return m + + def ports(self): + return [self.mid, self.active] + + +class PriorityUnbufferedPipeline(UnbufferedPipeline): + def __init__(self, stage, p_len=4): + p_mux = InputPriorityArbiter(self, p_len) + UnbufferedPipeline.__init__(stage, p_len=p_len, p_mux=p_mux) + + def elaborate(self, platform): + m = Module() + + pe = PriorityEncoder(self.num_rows) + m.submodules.selector = pe + m.submodules.out_op = self.out_op + m.submodules += self.rs + + # connect priority encoder + in_ready = [] + for i in range(self.num_rows): + in_ready.append(self.rs[i].ready) + m.d.comb += pe.i.eq(Cat(*in_ready)) + + active = Signal(reset_less=True) + out_en = Signal(reset_less=True) + m.d.comb += active.eq(~pe.n) # encoder active + m.d.comb += out_en.eq(active & self.out_op.trigger) + + # encoder active: ack relevant input, record MID, pass output + with m.If(out_en): + rs = self.rs[pe.o] + m.d.sync += self.mid.eq(pe.o) + m.d.sync += rs.ack.eq(0) + m.d.sync += self.out_op.stb.eq(0) + for j in range(self.num_ops): + m.d.sync += self.out_op.v[j].eq(rs.out_op[j]) + with m.Else(): + m.d.sync += self.out_op.stb.eq(1) + # acks all default to zero + for i in range(self.num_rows): + m.d.sync += self.rs[i].ack.eq(1) + + return m + + def ports(self): + res = [] + for i in range(self.num_rows): + inop = self.rs[i] + res += inop.in_op + [inop.stb] + return self.out_op.ports() + res + [self.mid] + + num_tests = 100 -- 2.30.2