commit f02c6f4bbf463472d3d68e52bd5ededd3c937f58 (HEAD -> master, origin/master, origin/HEAD) Author: Luke Kenneth Casson Leighton Date: Fri Mar 15 12:37:14 2019 +0000 add parallel InputGroup unit test commit b13c8a7a5368a53bedc71e5b8969c721103144c4 Author: Luke Kenneth Casson Leighton Date: Fri Mar 15 10:59:44 2019 +0000 rename BufPipe example to ExampleBufPipe commit a36447fcd4d4f049b7127e1fc02dc1390d05fa75 Author: Luke Kenneth Casson Leighton Date: Fri Mar 15 09:59:07 2019 +0000 instantiate 2 FPGetOp instances and use them. a little awkwardly. commit 092d2d78fa19a5c73863cb89c5d680cbd2afe027 Author: Luke Kenneth Casson Leighton Date: Fri Mar 15 09:33:44 2019 +0000 update comments commit 8989cd3452869d43a8a3655acffd3eb3288f5d9a Author: Luke Kenneth Casson Leighton Date: Fri Mar 15 09:22:58 2019 +0000 remove unnecessary code commit b90c533476affe63a34292bfe54dde62a105bed8 Author: Luke Kenneth Casson Leighton Date: Fri Mar 15 08:47:21 2019 +0000 add extra comment block explaining pipe stage example commit 28a8ede4a797a76e83410fb42a9aaa02b44fb2ef Author: Luke Kenneth Casson Leighton Date: Fri Mar 15 08:37:18 2019 +0000 inverted busy signal and named it "ready" commit 0ebc09c0a7b74e4807ccdb60ca0a10cbb605666a Author: Luke Kenneth Casson Leighton Date: Fri Mar 15 08:29:56 2019 +0000 rename stb to "valid" commit 0bfbc8ff919f0cd9c7f01b4c711b1b91a53ad480 Author: Luke Kenneth Casson Leighton Date: Fri Mar 15 08:28:18 2019 +0000 create classes for STB/BUSY, split in from out commit ca218a65dc9af73965a5c4f105a780ed04b588e0 Author: Luke Kenneth Casson Leighton Date: Fri Mar 15 00:31:30 2019 +0000 add use of FPState, not being used yet commit ce7a1d5c48e987cbfb40236f13b17ffcea55b585 Author: Luke Kenneth Casson Leighton Date: Thu Mar 14 13:32:06 2019 +0000 split pipeline test into 2 functions, one send, one receive commit 481d00c37b31e7908e624235e6e9c93b12baeebb Author: Luke Kenneth Casson Leighton Date: Thu Mar 14 06:33:10 2019 +0000 got fpdiv up and running again commit 286fdefc4bbe8c7b4bb34ae33b513e8bb81b3d7e Author: Luke Kenneth Casson Leighton Date: Thu Mar 14 05:41:02 2019 +0000 forgot to add submodules commit 43c53078d577aa33d28ba0eb2af782b7d348a517 Author: Luke Kenneth Casson Leighton Date: Thu Mar 14 05:09:36 2019 +0000 got rounding working again for fmul commit 892d640f8224e6a52907c6899ab6ab671f5f53af Author: Luke Kenneth Casson Leighton Date: Thu Mar 14 04:42:53 2019 +0000 remove extra arg from old roundz function commit ccd4d65a7bd2985edb5547daf7df623cda5ab9da Author: Luke Kenneth Casson Leighton Date: Thu Mar 14 04:33:01 2019 +0000 make a bit of a mess of the unit tests, getting mul up and running again taking a copy (sigh) of the old version of check_case and get_case commit 9b9732e1c96d085bc9c7b696e7c86dd0c4a4ae49 Author: Luke Kenneth Casson Leighton Date: Thu Mar 14 04:17:28 2019 +0000 get roundz working again, needed for mul stage commit 38452d7fb64752a897b26e1da96a27d3a5979a76 Author: Luke Kenneth Casson Leighton Date: Thu Mar 14 04:16:28 2019 +0000 add new FPNormaliseSingleMod, not tested diff --git a/src/add/example_buf_pipe.py b/src/add/example_buf_pipe.py index 6678a67..00eecc3 100644 --- a/src/add/example_buf_pipe.py +++ b/src/add/example_buf_pipe.py @@ -12,12 +12,12 @@ where data will flow on *every* clock when the conditions are right.  input acceptance conditions are when: - * incoming previous-stage strobe (i_p_stb) is HIGH - * outgoing previous-stage busy (o_p_busy) is LOW + * incoming previous-stage strobe (i.p_valid) is HIGH + * outgoing previous-stage ready (o.p_ready) is LOW  output transmission conditions are when: - * outgoing next-stage strobe (o_n_stb) is HIGH - * outgoing next-stage busy (i_n_busy) is LOW + * outgoing next-stage strobe (o.n_valid) is HIGH + * outgoing next-stage ready (i.n_ready) is LOW  the tricky bit is when the input has valid data and the output is not ready to accept it. if it wasn't for the clock synchronisation, it @@ -33,7 +33,7 @@ we now effectively have *two* possible pieces of data to "choose" from: the buffered data, and the incoming data. the decision as to which to process and output is based on whether we are in "stall" or not. - i.e. when the next stage is no longer busy, the output comes from + i.e. when the next stage is no longer ready, the output comes from the buffer if a stall had previously occurred, otherwise it comes direct from processing the input.  @@ -69,7 +69,17 @@ class ExampleStage:  def __init__(self): """ i_data can be a DIFFERENT type from everything else - o_data, r_data and result must be of the same type + o_data, r_data and result are best of the same type. + however this is not strictly necessary. an intermediate + transformation process could hypothetically be applied, however + it is result and r_data that definitively need to be of the same + (intermediary) type, as it is both result and r_data that + are transferred into o_data: + + i_data -> process() -> result --> o_data + | ^ + | | + +-> r_data -+ """ self.i_data = Signal(16) self.r_data = Signal(16) @@ -83,7 +93,9 @@ class ExampleStage: return self.result.eq(self.i_data + 1)  def update_buffer(self): - """ copies the result into the intermediate register r_data + """ copies the result into the intermediate register r_data, + which will need to be outputted on a subsequent cycle + prior to allowing "normal" operation. """ return self.r_data.eq(self.result)  @@ -100,88 +112,98 @@ class ExampleStage: def ports(self): return [self.i_data, self.o_data]  +class IOAckIn: + + def __init__(self): + self.p_valid = Signal() # >>in - comes in from PREVIOUS stage + self.n_ready = Signal() # in<< - comes in from the NEXT stage + + +class IOAckOut: + + def __init__(self): + self.n_valid = Signal() # out>> - goes out to the NEXT stage + self.p_ready = Signal() # <>in stage o_n_stb out>> stage+1 - stage-1 o_p_busy <>in stage o_data out>> stage+1 + stage-1 i.p_valid >>in stage o.n_valid out>> stage+1 + stage-1 o.p_ready <>in stage o_data out>> stage+1 | | +-------> process | | +-- r_data ---+ """ def __init__(self): - # input: strobe comes in from previous stage, busy comes in from next - #self.i_p_rst = Signal() # >>in - comes in from PREVIOUS stage - self.i_p_stb = Signal() # >>in - comes in from PREVIOUS stage - self.i_n_busy = Signal() # in<< - comes in from the NEXT stage + # input: strobe comes in from previous stage, ready comes in from next + self.i = IOAckIn() + #self.i.p_valid = Signal() # >>in - comes in from PREVIOUS stage + #self.i.n_ready = Signal() # in<< - comes in from the NEXT stage  - # output: strobe goes out to next stage, busy comes in from previous - self.o_n_stb = Signal() # out>> - goes out to the NEXT stage - self.o_p_busy = Signal() # <> - goes out to the NEXT stage + #self.o.p_ready = Signal() # <>in pipe1 o_n_stb out>> i_p_stb >>in pipe2 - o_p_busy <>in pipe1 o_n_valid out>> i_p_valid >>in pipe2 + o_p_ready <>in pipe1 o_data out>> stage.i_data >>in pipe2 """ def __init__(self): - self.pipe1 = BufPipe() - self.pipe2 = BufPipe() + self.pipe1 = ExampleBufPipe() + self.pipe2 = ExampleBufPipe()  # input - self.i_p_stb = Signal() # >>in - comes in from PREVIOUS stage - self.i_n_busy = Signal() # in<< - comes in from the NEXT stage + self.i_p_valid = Signal() # >>in - comes in from PREVIOUS stage + self.i_n_ready = Signal() # in<< - comes in from the NEXT stage self.i_data = Signal(32) # >>in - comes in from the PREVIOUS stage  # output - self.o_n_stb = Signal() # out>> - goes out to the NEXT stage - self.o_p_busy = Signal() # <> - goes out to the NEXT stage + self.o_p_ready = Signal() # <> - goes out to the NEXT stage  def elaborate(self, platform): @@ -194,37 +198,37 @@ class BufPipe2: m.submodules.pipe1 = self.pipe1 m.submodules.pipe2 = self.pipe2  - # connect inter-pipe input/output stb/busy/data - m.d.comb += self.pipe2.i_p_stb.eq(self.pipe1.o_n_stb) - m.d.comb += self.pipe1.i_n_busy.eq(self.pipe2.o_p_busy) + # connect inter-pipe input/output valid/ready/data + m.d.comb += self.pipe2.i.p_valid.eq(self.pipe1.o.n_valid) + m.d.comb += self.pipe1.i.n_ready.eq(self.pipe2.o.p_ready) m.d.comb += self.pipe2.stage.i_data.eq(self.pipe1.stage.o_data)  # inputs/outputs to the module: pipe1 connections here (LHS) - m.d.comb += self.pipe1.i_p_stb.eq(self.i_p_stb) - m.d.comb += self.o_p_busy.eq(self.pipe1.o_p_busy) + m.d.comb += self.pipe1.i.p_valid.eq(self.i_p_valid) + m.d.comb += self.o_p_ready.eq(self.pipe1.o.p_ready) m.d.comb += self.pipe1.stage.i_data.eq(self.i_data)  # now pipe2 connections (RHS) - m.d.comb += self.o_n_stb.eq(self.pipe2.o_n_stb) - m.d.comb += self.pipe2.i_n_busy.eq(self.i_n_busy) + m.d.comb += self.o_n_valid.eq(self.pipe2.o.n_valid) + m.d.comb += self.pipe2.i.n_ready.eq(self.i_n_ready) m.d.comb += self.o_data.eq(self.pipe2.stage.o_data)  return m  if __name__ == '__main__': print ("test 1") - dut = BufPipe() + dut = ExampleBufPipe() run_simulation(dut, testbench(dut), vcd_name="test_bufpipe.vcd")  print ("test 2") - dut = BufPipe2() + dut = ExampleBufPipe2() run_simulation(dut, testbench2(dut), vcd_name="test_bufpipe2.vcd")  print ("test 3") - dut = BufPipe() + dut = ExampleBufPipe() test = Test3(dut) run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe3.vcd")  print ("test 4") - dut = BufPipe2() + dut = ExampleBufPipe2() run_simulation(dut, testbench4(dut), vcd_name="test_bufpipe4.vcd") diff --git a/src/add/test_inputgroup.py b/src/add/test_inputgroup.py index ca8523d..bb68861 100644 --- a/src/add/test_inputgroup.py +++ b/src/add/test_inputgroup.py @@ -99,9 +99,81 @@ def testbench(dut): assert out_mid == 3, "out mid %d" % out_mid   +class InputTest: + def __init__(self, dut): + self.dut = dut + self.di = {} + self.do = {} + self.tlen = 10 + for mid in range(dut.num_rows): + self.di[mid] = {} + self.do[mid] = {} + for i in range(self.tlen): + self.di[mid][i] = randint(0, 100) + self.do[mid][i] = self.di[mid][i] + + def send(self, mid): + for i in range(self.tlen): + op2 = self.di[mid][i] + rs = dut.rs[mid] + ack = yield rs.ack + while not ack: + yield + ack = yield rs.ack + yield rs.in_op[0].eq(i) + yield rs.in_op[1].eq(op2) + yield rs.stb.eq(0b11) # strobe indicate 1st op ready + ack = yield rs.ack + while ack: + yield + ack = yield rs.ack + yield rs.stb.eq(0) + + # wait random period of time before queueing another value + for i in range(randint(0, 12)): + yield + + def recv(self): + while True: + stb = yield dut.out_op.stb + yield dut.out_op.ack.eq(0) + while not stb: + yield + stb = yield dut.out_op.stb + + yield dut.out_op.ack.eq(1) + stb = yield dut.out_op.stb + while stb: + yield + stb = yield dut.out_op.stb + mid = yield dut.mid + out_i = yield dut.out_op.v[0] + out_v = yield dut.out_op.v[1] + + # see if this output has occurred already, delete it if it has + assert out_i in self.do[mid] + assert self.do[mid][out_i] == out_v + del self.do[mid][out_i] + + # check if there's any more outputs + zerolen = True + for (k, v) in self.do.items(): + if v: + zerolen = False + if zerolen: + break + if __name__ == '__main__': dut = InputGroup(width=32) vl = rtlil.convert(dut, ports=dut.ports()) with open("test_inputgroup.il", "w") as f: f.write(vl) run_simulation(dut, testbench(dut), vcd_name="test_inputgroup.vcd") + + dut = InputGroup(width=16) + test = InputTest(dut) + run_simulation(dut, [test.send(3), test.send(2), + test.send(1), test.send(0), + test.recv()], + vcd_name="test_inputgroup_parallel.vcd") +