Example #1
0
    def elaborate(self, platform):
        def pat(value, width):
            return Const(value, unsigned(width))

        m = Module()
        h = self.resolution.horizontal
        v = self.resolution.vertical
        h_count = Signal(bits_for(h.active // 16))
        v_count = Signal(bits_for(v.active))
        led = platform.request('led')

        # Always present data to write
        # Since we always have it
        # This only works with the -retime attribute
        # I wonder if there is something odd about a FIFO here
        m.d.sync += self.fifo.w_en.eq(1)
        m.d.sync += self.fifo.w_data.eq(Mux(h_count[2] ^ v_count[6], 0xffff,
                                            0))
        # When data is accepted (w_rdy == 1), then increment counters
        with m.If(self.fifo.w_rdy):
            # Increment h_count
            m.d.sync += h_count.eq(h_count + 1)
            with m.If(h_count == (h.active // 16) - 1):
                m.d.sync += h_count.eq(0)
                m.d.sync += v_count.eq(v_count + 1)
                with m.If(v_count == v.active - 1):
                    m.d.sync += v_count.eq(0)

        return m
Example #2
0
    def __init__(self, freq):  # type: (int) -> None
        min_baud_rate = 9600
        max_baud_rate = 115200
        default_baud_rate = 9600
        self.freq = freq
        baud_rate_div_width = bits_for(freq // min_baud_rate)
        self.baud_rate_div_default = freq // default_baud_rate
        self.baud_rate_div = Signal(baud_rate_div_width, reset=self.baud_rate_div_default)

        self.baud_rate_val = Signal(bits_for(max_baud_rate), reset=default_baud_rate)
        self.baud_rate_idx = Signal(3, reset=0)
        self.baud_rate_update_done = Signal()
        self.baud_rate_update = Signal()
        self.baud_rate_mode_prev = Signal(2)

        self.uart_rx = Signal()
        self.uart_rx_bit = Signal(bits_for(10))
        self.uart_rx_div_cnt = Signal(8)
        self.uart_rx_symbol_act = Signal(reset=0)

        self.uart_rx_time_per_sub_bit = Signal(16, reset=freq * 16 // (default_baud_rate * 16))
        self.uart_rx_time = Signal(32, reset=0)
        self.uart_rx_next_sub_bit_time = Signal(32, reset=0)

        self.uart_rx_pos = Signal(bits_for(16 * 10))
        self.uart_rx_shaped = Signal()
        self.uart_rx_ctrl_word = Signal(8)

        self.rx_bit_time = Signal(32, reset=0)
        self.irda_rx = Signal(reset=1)
        self.irda_rx_pulse_timeout = Signal(baud_rate_div_width)
        self.irda_rx_shaped = Signal(reset=1)

        self.baud_rate_mode = Signal()
Example #3
0
    def __init__(self, n=1, w=320, h=240, dw=8):
        # Parameters
        self.n = n
        self.w = w
        self.h = h
        self.dw = dw

        # Inputs
        self.i_p = Signal(dw)
        self.i_valid = Signal()
        self.i_ready = Signal()
        self.i_reset = Signal()

        # Outputs
        self.o_p = Signal(dw)
        self.o_valid = Signal()
        self.o_ready = Signal()
        self.o_x = Signal(bits_for(w + 2 * n), reset=0)
        self.o_y = Signal(bits_for(h + 2 * n), reset=0)
        self.o_eof = Signal()

        # Diagnostics
        self.bep = Signal()
        self.bl = Signal()
        self.bsp = Signal()
        self.b = Signal()
Example #4
0
    def __init__(self, resolution, double_buffer):
        self.resolution = resolution
        self.db = double_buffer

        # h_count and v_count track progress of display through active area
        self.h_count = Signal(bits_for(resolution.horizontal.active // 16))
        self.v_count = Signal(bits_for(resolution.vertical.active))
        self.f_count = Signal(18)  # enough for more than an hour
Example #5
0
    def elaborate(self, platform):
        m = Module()

        read_input = self.i_valid & self.o_ready
        write_output = self.o_valid & self.i_ready

        # Duplicate input
        x = Signal(bits_for(self.w), reset=0)
        y = Signal(bits_for(self.h), reset=0)
        got = Signal(2, reset=0)

        left_half = (x < (self.w // 2))

        with m.If(self.i_en):
            # Calculate input co-ordinates
            with m.If(read_input):
                m.d.sync += x.eq(x + 1)
                with m.If(x == self.w - 1):
                    m.d.sync += [x.eq(0), y.eq(y + 1)]
                    with m.If(y == self.h - 1):
                        m.d.sync += y.eq(0)

            # We are ready unless we have an output that has been written
            m.d.comb += self.o_ready.eq((got == 0)
                                        | ((got == 1) & self.i_ready))

            # Read input
            with m.If(read_input & left_half):
                m.d.sync += [self.o.eq(self.i), got.eq(2)]

            # Output in valid when got is greater than 0
            m.d.comb += self.o_valid.eq(got > 0)

            # Move on when output is consumed
            with m.If(write_output):
                with m.If((got == 2) | ~left_half | ~self.i_valid):
                    m.d.sync += got.eq(got - 1)

        with m.Else():  # Not enabled
            self.buffer1(m)

        # Update output co-ordinates
        self.out_coords(m, self.w, self.h)

        # Camera reset
        with m.If(self.i_reset):
            m.d.sync += [
                self.o_x.eq(0),
                self.o_y.eq(0),
                x.eq(0),
                y.eq(0),
                got.eq(0)
            ]

        return m
    def __init__(self, n=1, w=320, h=240):
        super().__init__()
        # Parameters
        self.n = n
        self.w = w
        self.h = h

        # Outputs
        self.o_x = Signal(bits_for(w + 2 * n))
        self.o_y = Signal(bits_for(h + 2 * n))
        self.o_eof = Signal()
Example #7
0
    def __init__(self, w=640, h=320):
        super().__init__()

        # Inputs
        self.i_reset = Signal(reset=0)

        # Parameters
        self.w = w
        self.h = h

        # Outputs
        self.o_x = Signal(bits_for(w) - 1, reset=0)
        self.o_y = Signal(bits_for(h) - 1, reset=0)
        self.o_eof = Signal()
Example #8
0
    def __init__(self, w=320, h=240):
        super().__init__()

        # Inputs
        self.i_reset = Signal()
        self.i_en = Signal()

        # Parameters
        self.w = w
        self.h = h

        # Outputs
        self.o_x = Signal(bits_for(w))
        self.o_y = Signal(bits_for(h))
        self.o_eof = Signal()
Example #9
0
    def __init__(self, video_timer, pixel_fifo):
        super().__init__(video_timer)
        self.horizontal_config = video_timer.params.horizontal
        self.fifo = pixel_fifo
        # Inputs from video timer - exposed for debugging
        # 1 clock before next active line
        self.at_active_line_m1 = Signal()
        # In vertical blanking area
        self.vertical_blanking = Signal()

        # Internal
        self.shift_register = Signal(16)
        self.num_pixels = self.horizontal_config.active
        self.pixel_counter = Signal(bits_for(self.num_pixels))
        self.state = Signal(bits_for(PullState.OUTPUTING))
Example #10
0
    def elaborate(self, platform):
        m = Module()

        memory = m.submodules.memory = self.memory

        address_stream = PacketizedStream(bits_for(self.max_packet_size))
        with m.If(~self.done):
            m.d.comb += address_stream.valid.eq(1)
            m.d.comb += address_stream.last.eq(self.read_ptr == self.packet_length)
            m.d.comb += address_stream.payload.eq(self.read_ptr)
            with m.If(address_stream.ready):
                m.d.sync += self.read_ptr.eq(self.read_ptr + 1)
                m.d.sync += self.done.eq(self.read_ptr == self.packet_length)

        reset = Signal()
        m.submodules += FFSynchronizer(self.reset, reset)
        with m.If(Changed(m, reset)):
            m.d.sync += self.read_ptr.eq(0)
            m.d.sync += self.done.eq(0)

        reader = m.submodules.reader = StreamMemoryReader(address_stream, memory)
        buffer = m.submodules.buffer = StreamBuffer(reader.output)
        m.d.comb += self.output.connect_upstream(buffer.output)

        return m
Example #11
0
    def __init__(self,
                 *,
                 divisor,
                 divisor_bits=None,
                 data_bits=8,
                 parity="none",
                 pins=None):
        _check_parity(parity)
        self._parity = parity

        # The clock divisor must be at least 5 to keep the FSM synchronized with the serial input
        # during a DONE->IDLE->BUSY transition.
        _check_divisor(divisor, 5)
        self.divisor = Signal(divisor_bits or bits_for(divisor), reset=divisor)

        self.data = Signal(data_bits)
        self.err = Record([
            ("overflow", 1),
            ("frame", 1),
            ("parity", 1),
        ])
        self.rdy = Signal()
        self.ack = Signal()

        self.i = Signal(reset=1)

        self._pins = pins
Example #12
0
    def __init__(self, address_input: BasicStream, memory: Memory):
        assert len(address_input.payload) == bits_for(memory.depth)
        self.address_input = address_input
        self.memory = memory

        self.output = address_input.clone()
        self.output.payload = Signal(memory.width)
Example #13
0
    def __init__(self, k, sh=0, w=320, h=240, dw=8):
        # Parameters
        self.w = w
        self.h = h
        self.k = k
        self.sh = sh
        self.dw = dw

        # Inputs
        self.i_p = Signal(dw)
        self.i_valid = Signal()

        # Outputs
        self.o_p = Signal(dw)
        self.o_valid = Signal()
        self.o_stall = Signal()
        self.o_x = Signal(bits_for(w), reset=self.w - 1)
        self.o_y = Signal(bits_for(h), reset=self.h - 1)
Example #14
0
    def __init__(self, *, divisor, divisor_bits=None, **kwargs):
        self.divisor = Signal(divisor_bits or bits_for(divisor), reset=divisor)

        self.rx = AsyncSerialRX(divisor=divisor,
                                divisor_bits=divisor_bits,
                                **kwargs)
        self.tx = AsyncSerialTX(divisor=divisor,
                                divisor_bits=divisor_bits,
                                **kwargs)
Example #15
0
    def __init__(self, width=16, depth=32):
        self.rdat = Signal(width)
        self.wdat = Signal(width)
        self.we = Signal()
        self.re = Signal()
        self.pos = Signal(bits_for(depth))  # counter
        self.updown = Signal()
        self.depth = depth

        self.mem = Memory(width=width, depth=depth)
Example #16
0
 def __init__(self, num_steps, restart_value, is_private_call=0):
     """Private use num_steps() or num_bits()"""
     assert is_private_call
     self.num_steps = num_steps
     self.num_bits = max(bits_for(num_steps), 4)
     assert 4 <= self.num_bits <= 32
     self.polynomial = POLYNOMIALS[self.num_bits]
     # Ensure restart_value is in allowed range
     self.restart_value = (((restart_value or 1) - 1) % num_steps) + 1
     # values is a list of all values by step
     self.values = [self.restart_value]
Example #17
0
    def __init__(self, value, *, width=None, signed=None):
        if not isinstance(value, int):
            raise TypeError("Value must be an integer, not {!r}".format(value))
        self._value = value

        if width is None:
            width = bits_for(value)
        if not isinstance(width, int):
            raise TypeError("Width must be an integer, not {!r}".format(width))
        if width < bits_for(value):
            raise ValueError(
                "Width must be greater than or equal to the number of bits needed to"
                " represent {}".format(value))
        self._width = width

        if signed is None:
            signed = value < 0
        if not isinstance(signed, bool):
            raise TypeError(
                "Signedness must be a bool, not {!r}".format(signed))
        self._signed = signed
    def __init__(self, trans_func, kw=3, w=320, h=240, dw=8):
        # Parameters
        self.kw = kw
        self.w = w
        self.h = h
        self.trans_func = trans_func
        self.dw = dw

        # Inputs
        self.i_p = Signal(dw)
        self.i_valid = Signal()
        self.i_ready = Signal()
        self.i_reset = Signal()

        # Outputs
        self.o_p = Signal(dw)
        self.o_valid = Signal(reset=0)
        self.o_ready = Signal()
        self.o_x = Signal(bits_for(w - kw + 1), reset=0)
        self.o_y = Signal(bits_for(h - kw + 1), reset=0)
        self.o_eof = Signal(reset=0)
Example #19
0
    def __init__(self, k, kw=3, sh=0, w=320, h=240, dw=8, same=0):
        # Parameters
        self.kw = kw
        self.w = w
        self.h = h
        self.k = k
        self.sh = sh
        self.dw = dw

        # Inputs
        self.i_p = Signal(dw)
        self.i_valid = Signal()
        self.i_ready = Signal()
        self.i_reset = Signal()

        # Outputs
        self.o_p = Signal(dw)
        self.o_valid = Signal(reset=0)
        self.o_ready = Signal()
        self.o_x = Signal(bits_for(w - self.kw + 1), reset=0)
        self.o_y = Signal(bits_for(h - self.kw + 1), reset=0)
        self.o_eof = Signal(reset=0)
Example #20
0
    def __init__(self, k, kw=3, sh=0, w=320, h=240, dw=8, same=0):
        # Parameters
        self.kw = kw
        self.w = w
        self.h = h
        self.k = k
        self.sh = sh
        self.dw = dw
        self.same = same

        # Inputs
        self.i_p = Signal(dw)
        self.i_valid = Signal()
        self.i_ready = Signal()
        self.i_reset = Signal()

        # Outputs
        self.o_p = Signal(dw)
        self.o_valid = Signal()
        self.o_ready = Signal(reset=1)
        self.o_x = Signal(bits_for(w), reset=self.w - 1)
        self.o_y = Signal(bits_for(h), reset=self.h - 1)
        self.frame_done = Signal()
Example #21
0
    def _compute_addr_range(self, addr, size, step=1, *, alignment, extend):
        if addr is not None:
            if not isinstance(addr, int) or addr < 0:
                raise ValueError(
                    "Address must be a non-negative integer, not {!r}".format(
                        addr))
            if addr % (1 << self.alignment) != 0:
                raise ValueError(
                    "Explicitly specified address {:#x} must be a multiple of "
                    "{:#x} bytes".format(addr, 1 << alignment))
        else:
            addr = self._align_up(self._next_addr, alignment)

        if not isinstance(size, int) or size < 0:
            raise ValueError(
                "Size must be a non-negative integer, not {!r}".format(size))
        size = self._align_up(max(size, 1), alignment)

        if addr > (1 << self.addr_width) or addr + size > (
                1 << self.addr_width):
            if extend:
                self.addr_width = bits_for(addr + size)
            else:
                raise ValueError(
                    "Address range {:#x}..{:#x} out of bounds for memory map spanning "
                    "range {:#x}..{:#x} ({} address bits)".format(
                        addr, addr + size, 0, 1 << self.addr_width,
                        self.addr_width))

        addr_range = range(addr, addr + size, step)
        overlaps = self._ranges.overlaps(addr_range)
        if overlaps:
            overlap_descrs = []
            for overlap in overlaps:
                if id(overlap) in self._resources:
                    _, _, resource_range = self._resources[id(overlap)]
                    overlap_descrs.append(
                        "resource {!r} at {:#x}..{:#x}".format(
                            overlap, resource_range.start,
                            resource_range.stop))
                if id(overlap) in self._windows:
                    _, window_range = self._windows[id(overlap)]
                    overlap_descrs.append("window {!r} at {:#x}..{:#x}".format(
                        overlap, window_range.start, window_range.stop))
            raise ValueError(
                "Address range {:#x}..{:#x} overlaps with {}".format(
                    addr, addr + size, ", ".join(overlap_descrs)))

        return addr_range
Example #22
0
    def __init__(self, x_res=320, y_res=240, fifo_depth=1024):
        super().__init__()
        # Parameters
        self.x_res = x_res
        self.y_res = y_res
        self.fifo_depth = fifo_depth

        # Inputs
        self.i_reset = Signal()

        # Outputs
        self.o_eof = Signal()
        self.o_x = Signal(9)
        self.o_y = Signal(9)
        self.o_level = Signal(bits_for(fifo_depth))
Example #23
0
    def __init__(self,
                 *,
                 divisor,
                 divisor_bits=None,
                 data_bits=8,
                 parity="none",
                 pins=None):
        _check_parity(parity)
        self._parity = parity

        _check_divisor(divisor, 1)
        self.divisor = Signal(divisor_bits or bits_for(divisor), reset=divisor)

        self.data = Signal(data_bits)
        self.rdy = Signal()
        self.ack = Signal()

        self.o = Signal(reset=1)

        self._pins = pins
Example #24
0
 def write_port(self):
     port = Record([("addr", bits_for(self.depth)), ("en", 1),
                    ("data", self.width)])
     self._write_ports.append(port)
     return port
Example #25
0
    def elaborate(self, platform):
        m = Module()

        # Useful constants
        kw1 = self.kw - 1  # One less than kernel width
        #print("kw1:", kw1)
        kw2 = self.kw // 2 + 1  # One more than half the kernel width
        #print("kw2:", kw2)

        # x and y co-ordinates of latest received pixel
        x = Signal(bits_for(self.w), reset=0)
        y = Signal(bits_for(self.h + self.kw), reset=0)

        # x2 is two columns ahead of x with wraparound
        x2 = Signal(bits_for(self.h))
        m.d.comb += x2.eq(Mux(x >= self.w - 2, x + 2 - self.w, x + 2))

        # Indicates if pixel generation has started
        started = Signal(reset=0)

        # Current pixel window signals
        p = Array(
            Array(
                Signal(self.dw, name="p{}{}".format(x, y))
                for y in range(self.kw)) for x in range(self.kw))

        # Bottom right corner of window is combinatorial
        m.d.comb += p[kw1][kw1].eq(
            Mux(x == 0, p[kw1][kw1 - 1],
                Mux(y == self.h, p[kw1 - 1][kw1], self.i_p)))

        # Signals used to retain the previous value read from line buffers
        pd = Array(Signal(self.dw, name="pd{}".format(x)) for x in range(kw1))

        # Line buffers
        r = []
        w = []
        pl = []
        for i in range(kw1):
            # Create line buffer
            mem = Memory(width=self.dw, depth=self.w)
            pl.append(mem)
            rp = mem.read_port()
            m.submodules += rp
            r.append(rp)
            wp = mem.write_port()
            m.submodules += wp
            w.append(wp)
            # Connect addresses
            m.d.comb += wp.addr.eq(x)
            m.d.comb += rp.addr.eq(x2)  # Read 2 ahead with wraparound
            # TODO Correct formula for this
            if (self.kw == 3 and i < 1) or (self.kw > 3 and i < kw2):
                m.d.comb += w[i].en.eq(self.i_valid & self.o_ready & (y != 1))
            else:
                m.d.comb += w[i].en.eq(self.i_valid & self.o_ready)

            if i == kw1 - 1:
                m.d.comb += w[i].data.eq(self.i_p)
            else:
                m.d.comb += w[i].data.eq(Mux(y >= 2, pd[i + 1], self.i_p))

        # For simulation
        if platform is None:
            for i in range(kw1):
                ln = "l{}".format(i)
                self.__dict__[ln] = Signal(self.w * self.dw, name=ln)
                m.d.comb += self.__dict__[ln].eq(
                    Cat([pl[i][self.w - 1 - j] for j in range(self.w)]))

        # Pixel not valid, and frame not done, by default
        m.d.sync += [self.o_valid.eq(0), self.frame_done.eq(0)]

        # New pixel value
        n_p = Signal(self.dw + self.sh + 1)
        m.d.comb += n_p.eq(
            sum([
                sum([
                    p[x][y] * self.k[self.kw * x + y] for x in range(self.kw)
                ]) for y in range(self.kw)
            ]))

        # Process pixel
        with m.If(self.i_reset):
            # Partial reset (e.g. due to camera reset)
            m.d.sync += [
                x.eq(0),
                y.eq(0),
                started.eq(0),
                self.o_ready.eq(1),
                self.o_valid.eq(0),
                self.o_x.eq(0),
                self.o_y.eq(0)
            ]
        with m.Elif(self.i_ready & (self.i_valid | ~self.o_ready)
                    ):  # Valid input pixel or trailing pixels
            # Save last values read for wraparound
            for i in range(kw1):
                m.d.sync += pd[i].eq(r[i].data),

            # Increment x and y (allowing y to go past last line)
            m.d.sync += x.eq(x + 1)
            with m.If(x == self.w - 1):
                m.d.sync += [x.eq(0), y.eq(y + 1)]

            # Test for frame done
            with m.If((y == self.h + 1)):
                m.d.sync += [
                    x.eq(0),
                    y.eq(0),
                    self.o_ready.eq(1),
                    started.eq(0),
                    self.frame_done.eq(1)
                ]

            # Stall for the last row plus 1 pixel, while last pixels flushed
            with m.If((y == self.h - 1) & (x == self.w - 1)):
                m.d.sync += self.o_ready.eq(0)

            # Start generating pixels at bottom right of window
            with m.If((y == kw2 - 1) & (x == kw2 - 2)):
                m.d.sync += started.eq(1)

            # Move window and generate pixel
            with m.If((x == 0) & (y == 0)):
                # Extend edges with closest pixel
                # Top left corner
                for i in range(kw2):
                    for j in range(kw2):
                        m.d.sync += p[i][j].eq(self.i_p)
            with m.Elif((x < kw2) & (y == 0)):
                # Start of top row
                for i in range(kw2):
                    m.d.sync += p[i][x + kw2 - 1].eq(self.i_p)
            with m.Elif((y < kw2) & (x == 0)):
                # First column of top rows
                for j in range(kw2):
                    m.d.sync += p[y + kw2 - 1][j].eq(self.i_p)
            if (self.kw > 3):
                # Fill in rest of starting window for kernels larger than 3
                # TODO fix for kernels larger than 5
                for i in range(1, kw2):
                    with m.Elif((y == 1) & (x == i)):
                        m.d.sync += p[3][i + kw2 - 1].eq(self.i_p)
                with m.Elif((y == 2) & (x == 1)):
                    m.d.sync += p[4][3].eq(self.i_p)
            with m.Elif(started):  # Started generating pixels
                # Move the window
                for i in range(kw1):  # Omit the last row
                    for j in range(self.kw):
                        if j == kw1:
                            # For last column, if at right hand edge, repeat last pixel
                            m.d.sync += p[i][j].eq(
                                Mux(x == self.w - 1, p[i][j], r[i].data))
                        else:
                            # If first column get first pixel rather than shuffling left
                            m.d.sync += p[i][j].eq(
                                Mux(x == kw2 - 2, pd[i], p[i][j + 1]))
                if self.kw == 3:
                    m.d.sync += [
                        # Deal with last row of the window
                        p[kw1][0].eq(
                            Mux(y == self.h,
                                Mux(x == 0, pd[kw1 - 1], p[kw1 - 1][kw1 - 1]),
                                Mux(x == 0, self.i_p, p[kw1][kw1 - 1]))),
                        p[kw1][1].eq(
                            Mux(y == self.h,
                                Mux(x == 0, pd[kw1 - 1], p[kw1 - 1][kw1]),
                                self.i_p))
                    ]
                else:
                    for j in range(kw1):
                        m.d.sync += p[kw1][j].eq(
                            Mux(x == 0, pd[kw1 - 1], p[kw1][j + 1]))

                # Generate the pixel
                m.d.sync += [
                    self.o_valid.eq(1),
                    # Check for overflow
                    self.o_p.eq((Mux(self.same & n_p[-1],
                                     (p[1][1] << self.sh), n_p) >> self.sh))
                ]
                # Generate output pixel co-ordinates
                m.d.sync += self.o_x.eq(self.o_x + 1)
                with m.If(self.o_x == self.w - 1):
                    m.d.sync += [self.o_y.eq(self.o_y + 1), self.o_x.eq(0)]
                    with m.If(self.o_y == self.h - 1):
                        m.d.sync += self.o_y.eq(0)

        return m
Example #26
0
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.current_conditional.__exit__(exc_type, exc_val, exc_tb)

        self.last_stage.width = bits_for(self.stage)
        self.last_stage.value = self.stage
Example #27
0
 def read_port(self):
     port = Record([("addr", bits_for(self.depth)), ("en", 1), ("data", self.width)], name="rp")
     self._read_ports.append(port)
     return port
Example #28
0
    def elaborate(self, platform):
        m = Module()

        # Create line buffer
        mem = Memory(width=16, depth=self.w)
        m.submodules.r = r = mem.read_port()
        m.submodules.w = w = mem.write_port()

        # Conditions for consuming input and output
        read_input = self.i_valid & self.o_ready
        write_output = self.o_valid & self.i_ready

        # Extended pixels for output
        o_r = Signal(7)
        o_g = Signal(8)
        o_b = Signal(7)

        # Save input pixels
        p0 = Rgb565()
        p1 = Rgb565()
        p2 = Rgb565()
        p3 = Rgb565()

        # For simulation
        if platform is None:
            lb = Signal(self.w * 16)
            m.d.comb += lb.eq(Cat([mem[self.w - 1 - j]
                                   for j in range(self.w)]))

            i_r = Signal(5)
            p0_r = Signal(5)
            p1_r = Signal(5)
            p2_r = Signal(5)
            p3_r = Signal(5)

            m.d.comb += [
                i_r.eq(self.i.r),
                p0_r.eq(p0.r),
                p1_r.eq(p1_r),
                p2_r.eq(p2_r),
                p3_r.eq(p3_r)
            ]

        # Toggle between first and second pixel
        first_col = Signal(reset=1)
        first_row = Signal(reset=1)

        # Input x co-ordinate
        x = Signal(bits_for(self.w), reset=0)

        # Connect line buffer
        m.d.comb += [
            w.en.eq(read_input & first_row),
            w.data.eq(self.i.as_data()),
            w.addr.eq(x),
            r.addr.eq(x)
        ]

        # Get p0 and p1 from line buffer
        with m.If(~first_row):
            with m.If(first_col):
                m.d.sync += [
                    p1.r.eq(r.data[11:]),
                    p1.g.eq(r.data[5:11]),
                    p1.b.eq(r.data[:5])
                ]
            with m.Else():
                m.d.sync += [
                    p0.r.eq(r.data[11:]),
                    p0.g.eq(r.data[5:11]),
                    p0.b.eq(r.data[:5])
                ]

        # When input is consumed, save pixel and if second, set output valid
        with m.If(read_input):
            m.d.sync += [x.eq(x + 1), first_col.eq(~first_col)]
            with m.If(x == self.w - 1):
                m.d.sync += [first_row.eq(~first_row), x.eq(0)]
            with m.If(~first_row):
                with m.If(first_col):
                    m.d.sync += p2.eq(self.i)
                with m.Else():
                    m.d.sync += [p3.eq(self.i), self.o_valid.eq(1)]

        # We are always ready for second pixel, but only ready for the first pixel when downstream is ready
        m.d.comb += self.o_ready.eq(first_row | ~first_col | self.i_ready)

        # Calculate output
        m.d.comb += [
            o_r.eq(p0.r + p1.r + p2.r + p3.r + 1),
            o_g.eq(p0.g + p1.g + p2.g + p3.g + 1),
            o_b.eq(p0.b + p1.b + p2.b + p3.b + 1),
            self.o.r.eq(o_r[2:]),
            self.o.g.eq(o_g[2:]),
            self.o.b.eq(o_b[2:])
        ]

        # When output is consumed set not valid
        with m.If(write_output):
            m.d.sync += self.o_valid.eq(0)

        # Calculate output co-ordinates
        self.out_coords(m, self.w // 2, self.h // 2)

        # Camera reset
        with m.If(self.i_reset):
            m.d.sync += [
                self.o_x.eq(0),
                self.o_y.eq(0),
                x.eq(0),
                first_col.eq(1),
                first_row.eq(1)
            ]

        return m
    def elaborate(self, platform):
        m = Module()

        # Consume input condition
        read_input = self.i_valid & self.o_ready

        # x and y co-ordinates of input  pixel
        x = Signal(bits_for(self.w), reset=0)
        y = Signal(bits_for(self.h), reset=0)

        # Line buffer
        mem = Memory(width=16, depth=self.w)
        m.submodules.rp = rp = mem.read_port()
        m.submodules.wp = wp = mem.write_port()

        # Connect line buffer
        m.d.comb += [
            rp.addr.eq(self.o_x - self.n + 1),
            wp.addr.eq(x),
            wp.en.eq(read_input),
            wp.addr.eq(x),
            wp.data.eq(self.i.as_data())
        ]

        # For simulation
        if platform is None:
            # Make the line buffer visible in gtkwave
            l0 = Signal(self.w * 16)
            m.d.comb += l0.eq(Cat([mem[self.w - 1 - i]
                                   for i in range(self.w)]))

        # Save start and end pixel
        s_p = Rgb565()
        e_p = Rgb565()

        # Keep a copy of start and end pixels, and calculate input co-ordinates
        with m.If(read_input):
            m.d.sync += x.eq(x + 1)
            with m.If(x == 0):
                m.d.sync += s_p.eq(self.i)
            with m.If(x == self.w - 1):
                m.d.sync += [e_p.eq(self.i), x.eq(0), y.eq(y + 1)]
                with m.If(y == self.h - 1):
                    m.d.sync += y.eq(0)

        # Determine o_ready
        m.d.comb += self.o_ready.eq((self.o_y < self.h + self.n)
                                    & (self.o_x < self.w + self.n)
                                    & ((self.o_y == 0) | (self.o_y > self.n))
                                    & ((self.o_x == 0) | (self.o_x > self.n)))

        # Determine end of frame
        m.d.comb += self.o_eof.eq(((self.o_x == self.w + self.n * 2 - 1) &
                                   (self.o_y == self.h + self.n * 2 - 1)))

        # Determine the output pixel
        with m.If((self.o_x >= self.h + self.n)):
            m.d.comb += self.o.eq(e_p)  # Saved end pixel
        with m.Elif((self.o_y == 0)
                    | ((self.o_y > self.n) & (self.o_y < self.h + self.n))):
            # Input pixel line
            with m.If((self.o_x > 0) & (self.o_x <= self.n)):
                m.d.comb += self.o.eq(s_p)  # Saved start pixel
            with m.Else():
                m.d.comb += self.o.eq(self.i)  # Input pixel
        with m.Else():
            # Line buffer line
            with m.If(self.o_x < self.n):
                m.d.comb += self.o.eq(s_p)  # Saved start pixel
            with m.Else():
                m.d.comb += [  # From line buffer
                    self.o.r.eq(rp.data[11:]),
                    self.o.g.eq(rp.data[5:11]),
                    self.o.b.eq(rp.data[:5])
                ]

        # Output pixels
        with m.If(self.i_ready):
            # Output pixel always valid, when downstream is ready
            m.d.comb += self.o_valid.eq(1)

            # Set the output co-ordinates
            m.d.sync += self.o_x.eq(self.o_x + 1)
            with m.If(self.o_x == self.w + self.n * 2 - 1):
                m.d.sync += [self.o_y.eq(self.o_y + 1), self.o_x.eq(0)]
                with m.If(self.o_y == self.h + self.n * 2 - 1):
                    m.d.sync += self.o_y.eq(0),

        return m
Example #30
0
    def elaborate(self, platform):
        m = Module()

        # Useful constants
        kw1 = self.kw - 1  # One less than kernel width
        kw2 = self.kw // 2 + 1  # One more than half the kernel width
        n = kw2 - 1  # Width of border

        # Condition to consume input
        read_input = self.i_valid & self.o_ready

        # x and y co-ordinates of input pixel
        x = Signal(bits_for(self.w), reset=0)
        y = Signal(bits_for(self.h + self.kw), reset=0)

        # x1 is one column ahead of x with wraparound
        x1 = Signal(bits_for(self.h))
        m.d.comb += x1.eq(Mux(x >= self.w - 1, x + 1 - self.w, x + 1))

        # Current pixel window signals
        p = Array(
            Array(
                Signal(self.dw, name="p{}{}".format(x, y))
                for y in range(self.kw)) for x in range(self.kw))

        # Line buffers
        r = []
        w = []
        pl = []
        for i in range(self.kw):
            # Create line buffer
            mem = Memory(width=self.dw, depth=self.w, name="m{}".format(i))
            pl.append(mem)
            rp = mem.read_port()
            m.submodules += rp
            r.append(rp)
            wp = mem.write_port()
            m.submodules += wp
            w.append(wp)
            # Connect ports
            m.d.comb += wp.addr.eq(x)
            m.d.comb += rp.addr.eq(x1)
            m.d.comb += wp.en.eq(read_input)
            if i == kw1:
                m.d.comb += wp.data.eq(self.i_p)

        for i in range(kw1):
            m.d.comb += w[i].data.eq(r[i + 1].data)

        # For simulation
        if platform is None:
            for i in range(self.kw):
                ln = "l{}".format(i)
                self.__dict__[ln] = Signal(self.w * self.dw, name=ln)
                m.d.comb += self.__dict__[ln].eq(
                    Cat([pl[i][self.w - 1 - j] for j in range(self.w)]))

        # New pixel value
        n_p = Signal(self.dw + self.sh + 1)
        m.d.comb += n_p.eq(
            sum([
                sum([
                    p[x][y] * self.k[self.kw * x + y] for x in range(self.kw)
                ]) for y in range(self.kw)
            ]))
        m.d.comb += self.o_p.eq(n_p >> self.sh)

        # Ready when output is not valid or downstream is ready
        m.d.comb += self.o_ready.eq(~self.o_valid | self.i_ready)

        with m.If(read_input):
            # Determine input co-ordinates
            m.d.sync += x.eq(x + 1)
            with m.If(x == self.w - 1):
                m.d.sync += [x.eq(0), y.eq(y + 1)]
                with m.If(y == self.h - 1):
                    m.d.sync += y.eq(0)

            # Move window
            for i in range(self.kw):
                for j in range(kw1):
                    m.d.sync += p[i][j].eq(p[i][j + 1])
            for i in range(kw1):
                m.d.sync += p[i][kw1].eq(r[i + 1].data)
            m.d.sync += p[kw1][kw1].eq(self.i_p)

        # Output valid after window of kernel size is reached
        m.d.sync += self.o_valid.eq(((x >= kw1) & (y >= kw1)))

        # Set output co-ordinates
        m.d.sync += [self.o_x.eq(x + n * 2), self.o_y.eq(y + n * 2)]

        # End of frame after end of input
        m.d.sync += self.o_eof.eq((y == self.h - 1) & (x == self.w - 1))

        # Camera reset
        with m.If(self.i_reset):
            # Partial reset (e.g. due to camera reset)
            m.d.sync += [
                x.eq(0),
                y.eq(0),
                self.o_x.eq(0),
                self.o_y.eq(0),
                self.o_eof.eq(0),
                self.o_valid.eq(0)
            ]

        return m