Пример #1
0
    class Johnson(Circuit):
        name = _RegisterName('Johnson', n, 0, ce, r, s)
        IO = ['O', Out(Array(n, Bit))] + ClockInterface(ce, r, s)

        @classmethod
        def definition(johnson):
            ffs = FFs(n, ce=ce, r=r, s=s)
            reg = braid(ffs, scanargs={"I": "O"})
            johnson.O(reg(Not()(reg.O[n - 1])))
            wireclock(johnson, reg)
Пример #2
0
    class Ring(Circuit):
        name = _RegisterName('Ring', n, init, ce, r, s)
        IO = ['O', Out(Array(n, Bit))] + ClockInterface(ce, r, s)

        @classmethod
        def definition(ring):
            ffs = FFs(n, init=init, ce=ce, r=r, s=s)
            reg = braid(ffs, scanargs={"I": "O"})
            reg(reg.O[n - 1])
            wire(reg.O, ring.O)
            wireclock(ring, reg)
Пример #3
0
    class _SISO(Circuit):
        name = _RegisterName('SISO', n, init, ce, r, s)
        IO = ['I', In(Bit), 'O', Out(Bit)] + ClockInterface(ce, r, s)

        @classmethod
        def definition(siso):
            ffs = FFs(n, init=init, ce=ce, r=r, s=s)
            reg = braid(ffs, foldargs={"I": "O"})
            reg(siso.I)
            wire(reg.O, siso.O)
            wireclock(siso, reg)
Пример #4
0
    class _IOPrintIOConn(Circuit):
        name = _RegisterName('IOPrintIOConn', n, init, ce, r, s)

        # fixed input/output to printIO
        IO = ["DTR", In(Bit), "TX", Out(Bit)] + ClockInterface(ce, r, s)

        # per print statement input/output to printIO
        for i in PrintLens:
            IO += ["valid%d" % i, In(Bit)]

        for i in PrintDatas:
            IO += ["data%d" % i, In(Array(len(PrintDatas[i]), Bit))]

        @classmethod
        def definition(printfconn):
            # Create UART and printf and hook it all up
            if connection == "UART":
                conn = UART(1, 0)
                conn()
            else:
                assert (0)

            # Create printf with input length array and hook up RESET/DTR
            printf = IOPrintf([PrintLens[i] for i in range(len(PrintLens))],
                              ce=ce,
                              r=r)
            printf(RESET=printfconn.RESET, DTR=printfconn.DTR)

            # Wire up the valid and data fields to printf
            for i in PrintLens:
                wire(getattr(printfconn, "valid%d" % i),
                     getattr(printf, "valid%d" % i))
                wire(getattr(printfconn, "data%d" % i),
                     getattr(printf, "data%d" % i))

            # Hook printf up to uart connection type
            wire(printf.valid_out, conn.valid)
            wire(printf.data_out, conn.data)
            wire(conn.ready, printf.ready)

            # Wire the UART output to top level
            wire(conn.TX, printfconn.TX)
Пример #5
0
    class _PIPO(Circuit):
        name = _RegisterName('PIPO', n, init, ce, r, s)
        IO = ['SI', In(Bit), 'PI',
              In(T), 'LOAD',
              In(Bit), 'O',
              Out(T)] + ClockInterface(ce, r, s)

        @classmethod
        def definition(pipo):
            def mux2(y):
                return curry(Mux2(), prefix='I')

            mux = braid(col(mux2, n), forkargs=['S'])
            reg = Register(n, init=init, ce=ce, r=r, s=s)

            #si = array(*[pipo.SI] + [reg.O[i] for i in range(n-1)])
            si = concat(array(pipo.SI), reg.O[0:n - 1])
            mux(si, pipo.PI, pipo.LOAD)
            reg(mux)
            wire(reg.O, pipo.O)
            wireclock(pipo, reg)
Пример #6
0
    class _UART(Circuit):
        """Construct a UART connection, specifically for FPGA -> CPU sending"""
        """Inputs:  data : BYTE, valid : BIT"""
        """Outputs: TX : BIT, ready : BIT"""
        """We want to abstract away whether the UART is running faster or
    slower than the user, so for maximum generality we currently use a system
    of ACKs to talk around the clock divide"""
        """TODO get rid of some unnecessary arguments here, they don't make sense"""
        name = _RegisterName('UART', n, init, ce, r, s)
        IO = [
            "data",
            In(Array(8, Bit)), "valid",
            In(Bit), "TX",
            Out(Bit), "ready",
            Out(Bit)
        ] + ClockInterface(ce, r, s)

        @classmethod
        def definition(uart):
            baud = 1

            #Convenience
            valid = uart.valid

            #The protocol for handling the baudrate of the UART is as follows:
            # - inputs are immediately latched on the user clock
            # - RequestAck is toggled
            # - When RequestAck != Ack and the UART is ready to print, load the
            #   latched byte into the PISO
            # - After loading the byte into the PISO, Ack is toggled.
            # -- At this point, again, RequestAck == Ack and the process repeats
            #
            #This handshake allows the UART and the user code to be in
            #entirely different clock domains. It is also simpler than reasoning
            #about when to latch a user input based on some ready / done bits.

            #User clock domain
            ready = DFF()
            RequestAck = DFF()

            #UART clock domain (i.e. at baudrate)
            running = DFF(ce=True)
            Ack = DFF(ce=True)

            #"Send" protocol across the clock divide, i.e. latch the printf input and
            #deassert ready
            should_send = LUT2(I0 & I1)(ready, valid)

            #This latches the data @ the user clock. We move this to a PISO below on
            #the next baud cycle after should_send_request goes high.
            data = Register(8, ce=True)
            data(uart.data)
            wire(should_send, data.CE)

            #Send the request one cycle lagged behind should_send just to ward off clock
            #domain problems
            #SHOULD SEND ACK register
            should_send_request = DFF()
            should_send_request(should_send)

            #~ready & (requestAck==Ack) & ~should_send_request
            should_ready = LUT4(~I0 & ~(I1 ^ I2) & ~I3)(ready, RequestAck, Ack,
                                                        should_send_request)

            ready_n = LUT3((I0 & ~I1) | I2)(ready, should_send, should_ready)

            #READY register
            wire(ready_n, ready.I)

            request_ack_n = LUT2(I0 ^ I1)(RequestAck, should_send_request)
            #REQUEST ACK register
            wire(request_ack_n, RequestAck.I)

            # Cycle through UART bit-protocol
            count = Counter(4, ce=True, r=True)

            # TODO decode is heavyweight!
            done = Decode(15, 4)(count)

            #Send the ack one cycle after copying into the piso. Again, this is
            #to ward off clock domain problems.
            should_send_ack = DFF(ce=True)
            wire(baud, should_send_ack.CE)

            #~running & (requestAck != Ack) & ~should_send_ack
            should_run = LUT4(~I0 & (I1 ^ I2) & ~I3)(running, RequestAck, Ack,
                                                     should_send_ack)
            running_n = LUT3((I0 & ~I1) | I2)(running, done, should_run)
            running(running_n)
            wire(baud, running.CE)

            should_send_ack(should_run)

            ack_n = LUT2(I0 ^ I1)(Ack, should_send_ack)
            Ack(ack_n)
            wire(baud, Ack.CE)

            #Load the piso on should_run
            shift = PISO(9, ce=True)
            load = should_run
            shift(
                1,
                array(data.O[7], data.O[6], data.O[5], data.O[4], data.O[3],
                      data.O[2], data.O[1], data.O[0], 0), load)
            wire(baud, shift.CE)

            #Reset count whenever done or not running.
            #Resetting on just ~running is too conservative and wastes a cycle since
            #we can reset on done too
            reset = LUT2(I0 | ~I1)(done, running_n)
            count(CE=baud, RESET=reset)

            # Wire shift output to TX
            wire(shift, uart.TX)
            #wire(ready, uart.ready)
            wire(ready, uart.ready)
Пример #7
0
    class _IOPrintf(Circuit):
        assert n in [1, 2, 4]
        """Construct a printf IO type"""
        """Inputs:  valid : Array(n,Bit), length : Array(n,Array(4,Bit)),
      arg1...N Array(max_len,Array(8,Bit))"""
        """Outputs: TX : BIT, run : BIT, ready : BIT"""
        name = _RegisterName('IOPrintf', n, init, ce, r, s)

        # Limit argument length + header to 4 bytes for now
        logn_max_len = 2
        #max_len      = 1<<logn_max_len

        IO = ["valid", In(Array(n, Bit))]
        IO += ["length0", In(Array(logn_max_len, Bit))]
        IO += [
            "data0_arg0",
            In(Array(8, Bit)), "data0_arg1",
            In(Array(8, Bit)), "data0_arg2",
            In(Array(8, Bit)), "data0_arg3",
            In(Array(8, Bit))
        ]
        if n > 1:
            IO += ["data1", In(Array(1 << logn_max_len, Array(8, Bit)))]
        if n > 2:
            IO += ["data2", In(Array(1 << logn_max_len, Array(8, Bit)))]
        if n > 3:
            IO += ["data3", In(Array(1 << logn_max_len, Array(8, Bit)))]
        IO += ["ready", In(Bit)]
        IO += ["valid_out",
               Out(Bit), "data_out",
               Out(Array(8, Bit))] + ClockInterface(ce, r, s)

        @classmethod
        def definition(printf):

            logn_max_len = 2
            baud = 1
            logn = 2
            done = 1
            valid_idx = 0

            # print over length of arguments
            print_cnt = Counter(logn, ce=True, r=True)

            ### Latch input arguments when printf is idle

            # Latch valid
            valid_latch = Register(n, ce=True)
            valid_latch()
            wire(printf.valid, valid_latch)
            wire(done, valid_latch.CE)

            # Latch args
            arg_latch0 = RAM(
                logn_max_len,
                array(printf.data0_arg0, printf.data0_arg1, printf.data0_arg2,
                      printf.data0_arg3), print_cnt.O)
            #arg_latch0(CE=done)
            if n > 1:
                arg_latch1 = RAM(logn_max_len, printf.data1, print_cnt.O)
                arg_latch1(CE=done)
            if n > 2:
                arg_latch2 = RAM(logn_max_len, printf.data2, print_cnt.O)
                arg_latch2(CE=done)
                arg_latch3 = RAM(logn_max_len, printf.data3, print_cnt.O)
                arg_latch3(CE=done)

            # Special handling for > 1 printf
            if n > 1:
                # Select winner among valid inputs (choose smallest valid index)
                any_valid = OrN(n)
                wire(valid_latch.O[0], any_valid.I[0])
                wire(valid_latch.O[1], any_valid.I[1])
                if n == 2:
                    val_idx = LUT2[0, 0, 1, 0]
                    val_idx(valid[0], valid[1])
                if n == 4:
                    val_idx0 = LUT4[0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0,
                                    1, 0]
                    val_idx1 = LUT4[0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
                                    0, 0]
                    val_idx = array(val_idx1, val_idx0)
                    wire(valid_latch.O[2], any_valid.I[2])
                    wire(valid_latch.O[3], any_valid.I[3])

                # Select arguments to feed to UART based on valid index
                data_mux = Mux(n, 8)
                len_mux = Mux(n, logn_max_len)
                wire(val_idx, data_mux.S)
                wire(val_idx, len_mux.S)

                wire(arg_latch0.O, data_mux.I0)
                wire(arg_latch1.O, data_mux.I1)
                wire(printf.length0, len_mux.I0)
                wire(printf.length1, len_mux.I1)
                if n > 2:
                    wire(arg_latch2.O, data_mux.I2)
                    wire(arg_latch3.O, data_mux.I3)
                    wire(printf.length[2], len_mux.I2)
                    wire(printf.length[3], len_mux.I3)

                # Wire data mux output to data_out
                wire(data_mux.O, printf.data_out)
            else:
                # Just 1 printf defined
                len_mux = Mux(2, logn_max_len)
                wire(printf.length0, len_mux.I0)
                wire(printf.length0, len_mux.I1)
                wire(0, len_mux.S)

                # Wire valid directly to latched valid and data directly to data_out
                any_valid = OrN(2)
                wire(valid_latch.O[0], any_valid.I[0])
                wire(valid_latch.O[0], any_valid.I[1])
                wire(arg_latch0, printf.data_out)

            # Wire 0 or selected length to done comparitor based on any_valid
            done_mux = Mux(2, logn_max_len)
            wire(array(0, 0), done_mux.I0)
            wire(len_mux.O, done_mux.I1)
            wire(any_valid.O, done_mux.S)

            # Counter runs when ~done && UART is ready for data
            done_logic = EQ(logn_max_len)
            not_done = LUT1(~I0)
            not_done(done_logic)
            done_logic(print_cnt.O, done_mux.O)
            busy = OrN(2)
            wire(not_done.O, busy.I[0])
            wire(any_valid.O, busy.I[1])
            wire(busy.O, printf.valid_out)

            # Stall and reset counter based in inputs
            start = AndN(2)
            ready = LUT3((I0 & I1) | I2)
            ready(printf.ready, not_done.O, start.O)
            wire(ready, print_cnt.CE)

            # Start circuit - detect any_valid && done transition
            new_data = LUT2(I0 & I1)
            new_data(any_valid.O, done_logic.O)
            new_dff = DFF()
            new_dff(new_data)
            new_data_inv = LUT1(~I0)
            new_data_inv(new_data)
            wire(new_data_inv.O, start.I[0])
            wire(new_dff.O, start.I[1])

            wire(start.O, print_cnt.RESET)
Пример #8
0
    class _IOPrintf(Circuit):
        """Construct a printf IO type"""
        """Inputs:  valid : Array(n,Bit), length : Array(n,Array(4,Bit)),
      arg1...N Array(max_len,Array(8,Bit))"""
        """Outputs: TX : BIT, run : BIT, ready : BIT"""
        name = _RegisterName('IOPrintf', n, init, ce, r, s)

        #XXX slightly wasteful, we compare against length instead of length - 1 so
        #we take 5 bits to represent a length of 16, for example.
        max_len = max(lengths)
        logn_max_len = log2(max_len)
        if ((1 << logn_max_len) <= max_len):
            logn_max_len = logn_max_len + 1

        assert ((1 << logn_max_len) > max_len)

        IO = []
        #IO += ["length0", In(Array(logn_max_len,Bit))]
        for i in range(n):
            IO += ["valid%d" % i, In(Bit)]
            IO += ["data%d" % i, In(Array(lengths[i] * 8, Bit))]

        #Control bits
        IO += ["ready", In(Bit)]
        IO += ["DTR", In(Bit)]

        #Outputs to I/O primitive
        IO += ["valid_out",
               Out(Bit), "data_out",
               Out(Array(8, Bit))] + ClockInterface(ce, r, s)

        @classmethod
        def definition(printf):
            #Convenience
            logn_max_len = printf.logn_max_len
            baud = 1
            valid_idx = 0

            # Running is true while printing a message. It becomes false when we
            # finish the message and hit done.
            running = DFF(r=True)

            # print_cnt increments on running & the underlying I/O primitive's ready
            print_cnt = Counter(logn_max_len, ce=True, r=True)

            # We are done when print_cnt reaches the length of the message
            done = EQ(logn_max_len)
            if logn_max_len == 1:
                wire(print_cnt.O[0], done.I0)
            else:
                wire(print_cnt.O, done.I0)

            # Need to buffer the reset signal
            resetSignal = DFF()
            resetSignal(printf.RESET if r else 0)

            # States:
            # - While printing a message, we are running
            # - When the message finishes, we become done.
            #   (done and running both hold for one cycle)
            # - We hold done, with running false, until backpressure is cleared for
            # us to reset.
            # This means you cannot accept a new message until both running and done
            # are false.

            # We accept a message by latching the valid bits and the arguments
            # and transitioning to the running state
            printf_valid = array(
                *[getattr(printf, "valid%d" % i) for i in range(n)])
            any_valid = OrN(n)
            any_valid(printf_valid)
            should_accept = LUT3(~I0 & ~I1 & I2)(running, done, any_valid)

            running_n = LUT3((I0 & ~I1) | I2)(running, done, should_accept)
            running(running_n)
            #Reset running on RESET
            wire(resetSignal, running.RESET)

            #Running becomes true when we have data to print
            #So, print whenever running && ~done
            wire(LUT2(I0 & ~I1)(running, done), printf.valid_out)

            # Latch valid
            valid_latch = Register(n, ce=True)
            valid_latch(printf_valid)
            wire(should_accept, valid_latch.CE)

            # Latch args
            # TODO latch the other args too!
            arg_latch = [
                RAM(
                    logn_max_len,
                    pad_garbage(getattr(printf, "data%d" % i),
                                (1 << logn_max_len) * 8), print_cnt.O,
                    should_accept) for i in range(n)
            ]

            #### NOTE: Clean this up with python techniques & add support to 8 statements

            # Special handling for > 1 printf
            if n > 1:
                ceil_n = 1 << (log2((n - 1) * 2))
                # Select winner among valid inputs (choose smallest valid index)
                if n == 2:
                    val_idx = LUT2([0, 0, 1, 0])
                    val_idx(valid_latch.O[0], valid_latch.O[1])
                if n in [3, 4]:
                    val_idx0 = LUT4(
                        [0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0])
                    val_idx1 = LUT4(
                        [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0])
                    val_idx0()
                    val_idx1()
                    for i in range(n):
                        wire(valid_latch.O[i], getattr(val_idx0, "I%d" % i))
                        wire(valid_latch.O[i], getattr(val_idx1, "I%d" % i))
                    for i in range(ceil_n):
                        if i >= n:
                            wire(0, getattr(val_idx0, "I%d" % i))
                            wire(0, getattr(val_idx1, "I%d" % i))
                    val_idx = array(val_idx0.O, val_idx1.O)

                # Select arguments to feed to UART based on valid index
                data_mux = Mux(ceil_n, 8)
                len_mux = Mux(ceil_n, logn_max_len)
                wire(val_idx, data_mux.S)
                wire(val_idx, len_mux.S)

                for i in range(n):
                    wire(arg_latch[i], getattr(data_mux, "I%d" % i))
                    wire(array(*int2seq(lengths[i], logn_max_len)),
                         getattr(len_mux, "I%d" % i))
                # Connect the inputs to ground for unused MUX inputs
                for i in range(ceil_n):
                    if i >= n:
                        zeros = logn_max_len * [0]
                        wire(array(*zeros), getattr(len_mux, "I%d" % i))
                        zeros = 8 * [0]
                        wire(array(*zeros), getattr(data_mux, "I%d" % i))

                # Wire data mux output to data_out
                wire(data_mux.O, printf.data_out)
                length = len_mux.O
            else:
                # Wire valid directly to latched valid and data directly to data_out
                wire(arg_latch[0], printf.data_out)
                length = array(*int2seq(lengths[0], logn_max_len))

            #Use length to determine "done"
            if logn_max_len == 1:
                wire(length[0], done.I1)
            else:
                wire(length, done.I1)

            #TODO we have to push some fake printfs through the pipeline sometimes.
            #Otherwise, the client will stall on a large buffer, and there is a
            #chance that as soon as it times out, we will be mid-printf and break a
            #buffer. To avoid this, periodically send a null message. To save
            #bandwidth, we need only send a null message when the number of sent
            #bytes is not a multiple of the buffer size.

            #If all printfs don't send the same amount, it is possible for a printf
            #to be split between two read buffers. That's OK, we just reconstitute
            #them on the CPU side.

            stream_has_more_space = 1

            #We can make the UART reliable, but it requires some cooperation with the
            #user program. Specifically, the user program must ACK every time it
            #reads a buffer from us, by rising-edge the DTR line
            if (reliable_uart_extension):
                BytesSent = Register(16, r=True, ce=True)
                BytesSent_n = Add(16)
                BytesSent_n(BytesSent, array(*int2seq(1, 16)))
                BytesSent(BytesSent_n.O)
                #See condition for sending a byte below
                wire(
                    LUT4((I0 & ~I1 & I2) | I3)(running, done, printf.ready,
                                               resetSignal), BytesSent.CE)
                wire(resetSignal, BytesSent.RESET)

                #Listen to ACKs via rising edge of DTR register.
                #Can't just compute rising edge as ~DTRbuffer & printf.DTR due to
                #glitches! The rising edge is only correctly detected if we buffer
                #again.
                DTRBuffer = DFF()
                DTRBuffer(printf.DTR)
                DTRBuffer_lag = DFF()
                DTRBuffer_lag(DTRBuffer)
                DTRRising = LUT2(~I0 & I1)(DTRBuffer_lag, DTRBuffer)

                #Each ACK acks this many bytes read from the stream:
                bufferSize = 510 * 8

                BytesAcked = Register(16, r=True, ce=True)
                BytesAcked_n = Add(16)
                BytesAcked_n(BytesAcked, array(*int2seq(bufferSize, 16)))
                BytesAcked(BytesAcked_n.O)
                wire(resetSignal, BytesAcked.RESET)
                wire(LUT2(I0 | I1)(DTRRising, resetSignal), BytesAcked.CE)

                BytesInFlight = Sub(16)
                BytesInFlight(BytesSent, BytesAcked)

                stream_has_more_space = ULT(16)(
                    BytesInFlight.O, array(*int2seq(bufferSize * 2 - 8, 16)))

                #Useful debugging:
                #wire(array(*[BytesInFlight.O[i] for i in range(8)]), printf.data_out)
                #wire(array(*[BytesSent.O[i] for i in range(8)]), printf.data_out)

            reset = LUT3((I0 & I1) | I2)
            reset(done, stream_has_more_space, resetSignal)
            wire(reset, print_cnt.RESET)

            #Advance on (running & ~done) and ready, or reset
            wire(
                LUT4((I0 & ~I1 & I2) | I3)(running, done, printf.ready, reset),
                print_cnt.CE)
Пример #9
0
    class _UART(Circuit):
        """Construct a UART connection"""
        """Inputs:  data : BIT, valid : BIT"""
        """Outputs: TX : BIT, run : BIT, ready : BIT"""
        name = _RegisterName('UART', n, init, ce, r, s)
        IO = [
            "data",
            In(Array(8, Bit)), "valid",
            In(Bit), "TX",
            Out(Bit), "ready",
            Out(Bit)
        ] + ClockInterface(ce, r, s)

        @classmethod
        def definition(uart):

            baud = 1
            logn = 4

            # Latch data in at start of each packet and insert head bit (0)
            data_in = Register(9, ce=True)

            # Latch valid in at start of each packet
            valid_in = DFF(ce=True)

            # Cycle through UART packet
            count = Counter(logn, ce=True, r=True)
            done = Decode(15, logn)(count)

            # After 16-bit UART, transition run from 1->0 for 1 cycle and then start next block
            run = DFF(ce=True)
            run_n = LUT3([0, 0, 1, 0, 1, 0, 1, 0])
            run_n(done, valid_in, run)
            run(run_n)
            wire(baud, run.CE)

            # After 16 bits, reset counter to send out next UART packet
            reset = LUT2((I0 & ~I1))(done, run)
            count(CE=baud, RESET=reset)

            # Shift out the 16-bit packet
            shift = PISO(9, ce=True)
            load = LUT2(I0 & ~I1)(valid_in, run)
            shift(1, data_in, load)
            wire(baud, shift.CE)

            # Wire shift output to TX
            wire(shift, uart.TX)

            # Ready is set when UART packet finishes: allow new inputs and data latch
            ready = LUT2(~I0 & I1)(run, baud)
            wire(ready, uart.ready)

            # Only allow new data latch when ready is set
            valid_in(CE=ready)
            wire(uart.valid, valid_in.I)
            data_in(CE=ready)
            wire(
                array(uart.data[7], uart.data[6], uart.data[5], uart.data[4],
                      uart.data[3], uart.data[2], uart.data[1], uart.data[0],
                      0), data_in)