Example #1
0
    def __init__(self, width, depth):
        self.din = Signal(width)
        self.dout = Signal(width)
        self.re = Signal()

        ###

        produce = Signal(max=depth)
        consume = Signal(max=depth)
        storage = Memory(width, depth)
        self.specials += storage

        wrport = storage.get_port(write_capable=True)
        self.specials += wrport
        self.comb += [
            wrport.adr.eq(produce),
            wrport.dat_w.eq(self.din),
            wrport.we.eq(1)
        ]
        self.sync += _inc(produce, depth)

        rdport = storage.get_port(async_read=True)
        self.specials += rdport
        self.comb += [
            rdport.adr.eq(consume),
            self.dout.eq(rdport.dat_r)
        ]
        self.sync += If(self.re, _inc(consume, depth))
Example #2
0
    def __init__(self, width, depth):
        self.din = Signal(width)
        self.dout = Signal(width)
        self.re = Signal()

        ###

        produce = Signal(max=depth)
        consume = Signal(max=depth)
        storage = Memory(width, depth)
        self.specials += storage

        wrport = storage.get_port(write_capable=True)
        self.specials += wrport
        self.comb += [
            wrport.adr.eq(produce),
            wrport.dat_w.eq(self.din),
            wrport.we.eq(1)
        ]
        self.sync += _inc(produce, depth)

        rdport = storage.get_port(async_read=True)
        self.specials += rdport
        self.comb += [rdport.adr.eq(consume), self.dout.eq(rdport.dat_r)]
        self.sync += If(self.re, _inc(consume, depth))
    def __init__(self, width, start_addr, end_addr, port):
        self.submodules.port = HMCPortWriteUnifier(port)
        assert width <= len(self.port.rd_data)
        print("Using memory region {:x} to {:x}".format(start_addr, end_addr))

        self.din = Signal(width)
        self.writable = Signal()
        self.we = Signal()

        self.dout = Signal(width)
        self.readable = Signal()
        self.re = Signal()

        self.full = Signal()
        self.num_writes = Signal(32)
        self.num_reads = Signal(32)
        self.max_level = Signal(32)

        word_offset = log2_int(len(self.port.rd_data)) - 3

        # storage area
        word_start_addr = start_addr >> word_offset
        word_end_addr = end_addr >> word_offset
        mem_area_size = word_end_addr - word_start_addr
        rd_ptr = Signal(len(self.port.addr)-word_offset)
        wr_ptr = Signal(len(self.port.addr)-word_offset)
        level = Signal(max=mem_area_size+1)

        self.comb += [
            self.full.eq(level == mem_area_size)
        ]
        self.sync += [
            If(self.writable & self.we,
                self.num_writes.eq(self.num_writes + 1)
            ),
            If(self.readable & self.re,
                self.num_reads.eq(self.num_reads + 1)
            ),
            If(level > self.max_level,
                self.max_level.eq(level)
            )
        ]

        # tags
        tag_sz = self.port.effective_max_tag_size - 1
        num_tags = min(2**tag_sz, mem_area_size)
        self.tag_in_use = Array(Signal() for _ in range(num_tags))
        tag = Signal(self.port.effective_max_tag_size - 1)
        self.comb += tag.eq(self.port.addr[word_offset:word_offset+tag_sz])

        # reorder buffer for returned results
        self.specials.reorder_buffer = Memory(width, num_tags)
        self.specials.wr_port = wr_port = self.reorder_buffer.get_port(write_capable=True, mode=READ_FIRST)
        self.specials.rd_port = rd_port = self.reorder_buffer.get_port(async_read=True, mode=READ_FIRST)
        reorderbuffer_valid = Array(Signal() for _ in range(num_tags))
        reorder_rd_ptr = Signal(len(rd_port.adr))

        # enforce ordering of accesses to same memory address
        no_hazard = Signal()
        self.comb += no_hazard.eq(~self.tag_in_use[tag])

        # choose read or write; only one port so no simultaneous access
        do_rd = Signal()
        self.sync += do_rd.eq(~do_rd & (level > 0) & ~reorderbuffer_valid[rd_ptr[word_offset:word_offset+tag_sz]] & ~self.tag_in_use[rd_ptr[word_offset:word_offset+tag_sz]]) # read if (a) there is something to read (b) the place to store the return value is free and (c) not going to be filled by an in-flight read

        # issue commands
        self.comb += [
            If(do_rd,
                self.port.cmd.eq(port.HMC_CMD_RD),
                self.port.addr[word_offset:].eq(word_start_addr + rd_ptr),
                self.port.cmd_valid.eq(no_hazard),
                self.writable.eq(0)
            ).Elif(~self.full,
                self.port.cmd.eq(port.HMC_CMD_WR_NP),
                self.port.addr[word_offset:].eq(word_start_addr + wr_ptr),
                self.port.cmd_valid.eq(self.we & no_hazard),
                self.writable.eq(no_hazard & self.port.cmd_ready)
            ).Else(
                self.port.cmd_valid.eq(0),
                self.writable.eq(0)
            ),
            self.port.tag.eq(Cat(do_rd, tag)),
            self.port.wr_data.eq(self.din),
            self.port.size.eq(1)
        ]

        # accounting
        self.sync += [
            If(self.port.cmd_ready & self.port.cmd_valid,
                self.tag_in_use[tag].eq(1),
                If(self.port.cmd == port.HMC_CMD_RD,
                    _inc(rd_ptr, mem_area_size),
                    level.eq(level-1)
                ).Else(
                    _inc(wr_ptr, mem_area_size),
                    level.eq(level+1)
                )
            ),
            If(self.port.rd_data_valid,
                self.tag_in_use[self.port.rd_data_tag[1:]].eq(0),
                If(self.port.rd_data_tag[0],
                    reorderbuffer_valid[self.port.rd_data_tag[1:]].eq(1)
                )
            ),
            If(self.readable & self.re,
                _inc(reorder_rd_ptr, num_tags),
                reorderbuffer_valid[reorder_rd_ptr].eq(0)
            )
        ]

        # fill reorder buffer
        self.comb += [
            self.wr_port.adr.eq(self.port.rd_data_tag[1:]),
            self.wr_port.dat_w.eq(self.port.rd_data),
            self.wr_port.we.eq(self.port.rd_data_valid & self.port.rd_data_tag[0])
        ]

        # read from reorder buffer
        self.comb += [
            self.rd_port.adr.eq(reorder_rd_ptr),
            self.dout.eq(self.rd_port.dat_r),
            self.readable.eq(reorderbuffer_valid[reorder_rd_ptr])
        ]
    def __init__(self, width, start_addr, end_addr, port):
        self.submodules.port = HMCPortWriteUnifier(port)
        assert width <= len(self.port.rd_data)
        print("Using memory region {:x} to {:x}".format(start_addr, end_addr))

        self.din = Signal(width)
        self.writable = Signal()
        self.we = Signal()

        self.dout = Signal(width)
        self.readable = Signal()
        self.re = Signal()

        self.full = Signal()
        self.num_writes = Signal(32)
        self.num_reads = Signal(32)
        self.max_level = Signal(32)

        word_offset = log2_int(len(self.port.rd_data)) - 3

        # storage area
        word_start_addr = start_addr >> word_offset
        word_end_addr = end_addr >> word_offset
        mem_area_size = word_end_addr - word_start_addr
        rd_ptr = Signal(len(self.port.addr) - word_offset)
        wr_ptr = Signal(len(self.port.addr) - word_offset)
        level = Signal(max=mem_area_size + 1)

        self.comb += [self.full.eq(level == mem_area_size)]
        self.sync += [
            If(self.writable & self.we,
               self.num_writes.eq(self.num_writes + 1)),
            If(self.readable & self.re, self.num_reads.eq(self.num_reads + 1)),
            If(level > self.max_level, self.max_level.eq(level))
        ]

        # tags
        tag_sz = self.port.effective_max_tag_size - 1
        num_tags = min(2**tag_sz, mem_area_size)
        self.tag_in_use = Array(Signal() for _ in range(num_tags))
        tag = Signal(self.port.effective_max_tag_size - 1)
        self.comb += tag.eq(self.port.addr[word_offset:word_offset + tag_sz])

        # reorder buffer for returned results
        self.specials.reorder_buffer = Memory(width, num_tags)
        self.specials.wr_port = wr_port = self.reorder_buffer.get_port(
            write_capable=True, mode=READ_FIRST)
        self.specials.rd_port = rd_port = self.reorder_buffer.get_port(
            async_read=True, mode=READ_FIRST)
        reorderbuffer_valid = Array(Signal() for _ in range(num_tags))
        reorder_rd_ptr = Signal(len(rd_port.adr))

        # enforce ordering of accesses to same memory address
        no_hazard = Signal()
        self.comb += no_hazard.eq(~self.tag_in_use[tag])

        # choose read or write; only one port so no simultaneous access
        do_rd = Signal()
        self.sync += do_rd.eq(
            ~do_rd & (level > 0)
            & ~reorderbuffer_valid[rd_ptr[word_offset:word_offset + tag_sz]]
            & ~self.tag_in_use[rd_ptr[word_offset:word_offset + tag_sz]]
        )  # read if (a) there is something to read (b) the place to store the return value is free and (c) not going to be filled by an in-flight read

        # issue commands
        self.comb += [
            If(do_rd, self.port.cmd.eq(port.HMC_CMD_RD),
               self.port.addr[word_offset:].eq(word_start_addr + rd_ptr),
               self.port.cmd_valid.eq(no_hazard), self.writable.eq(0)).Elif(
                   ~self.full, self.port.cmd.eq(port.HMC_CMD_WR_NP),
                   self.port.addr[word_offset:].eq(word_start_addr + wr_ptr),
                   self.port.cmd_valid.eq(self.we & no_hazard),
                   self.writable.eq(no_hazard & self.port.cmd_ready)).Else(
                       self.port.cmd_valid.eq(0), self.writable.eq(0)),
            self.port.tag.eq(Cat(do_rd, tag)),
            self.port.wr_data.eq(self.din),
            self.port.size.eq(1)
        ]

        # accounting
        self.sync += [
            If(
                self.port.cmd_ready & self.port.cmd_valid,
                self.tag_in_use[tag].eq(1),
                If(self.port.cmd == port.HMC_CMD_RD,
                   _inc(rd_ptr, mem_area_size),
                   level.eq(level - 1)).Else(_inc(wr_ptr, mem_area_size),
                                             level.eq(level + 1))),
            If(
                self.port.rd_data_valid,
                self.tag_in_use[self.port.rd_data_tag[1:]].eq(0),
                If(self.port.rd_data_tag[0],
                   reorderbuffer_valid[self.port.rd_data_tag[1:]].eq(1))),
            If(self.readable & self.re, _inc(reorder_rd_ptr, num_tags),
               reorderbuffer_valid[reorder_rd_ptr].eq(0))
        ]

        # fill reorder buffer
        self.comb += [
            self.wr_port.adr.eq(self.port.rd_data_tag[1:]),
            self.wr_port.dat_w.eq(self.port.rd_data),
            self.wr_port.we.eq(self.port.rd_data_valid
                               & self.port.rd_data_tag[0])
        ]

        # read from reorder buffer
        self.comb += [
            self.rd_port.adr.eq(reorder_rd_ptr),
            self.dout.eq(self.rd_port.dat_r),
            self.readable.eq(reorderbuffer_valid[reorder_rd_ptr])
        ]