Beispiel #1
0
    def verify_btype(self, m):
        sig = self.build_signal(m, "B", [(0, 6, "1001011"), (7, 7, "1"),
                                         (8, 11, "0000"), (12, 14, "001"),
                                         (15, 19, "00010"), (20, 24, "00011"),
                                         (25, 30, "011111"), (31, 31, "1")])
        b = BType("btype")
        b.elaborate(m.d.comb, sig)
        m.d.comb += Assert(b.opcode == Const(0b1001011, 7))
        m.d.comb += Assert(b.funct3 == Const(1, 3))
        m.d.comb += Assert(b.rs1 == Const(2, 5))
        m.d.comb += Assert(b.rs2 == Const(3, 5))
        m.d.comb += Assert(
            b.imm == Cat(Const(0b1101111100000, 13), Repl(1, 19)))

        m.d.comb += Assert(b.match(opcode=0b1001011))
        m.d.comb += Assert(b.match(rs1=2))
        m.d.comb += Assert(b.match(rs2=3))
        m.d.comb += Assert(b.match(funct3=1))
        m.d.comb += Assert(b.match(imm=0b11111111111111111111101111100000))
        m.d.comb += Assert(
            b.match(opcode=0b1001011,
                    funct3=1,
                    rs1=2,
                    rs2=3,
                    imm=0b11111111111111111111101111100000))
        m.d.comb += Assert(~b.match(opcode=0b1001011,
                                    funct3=3,
                                    rs1=1,
                                    rs2=5,
                                    imm=0b11111111111111111111101111100000))

        b_builder_check = Signal(32)
        b_builder_opcode = Signal(7)
        b_builder_f3 = Signal(3)
        b_builder_rs1 = Signal(5)
        b_builder_rs2 = Signal(5)
        b_builder_imm = Signal(13)
        m.d.comb += Assume(b_builder_imm[0] == 0)

        built_btype = BType.build_i32(opcode=b_builder_opcode,
                                      funct3=b_builder_f3,
                                      rs1=b_builder_rs1,
                                      rs2=b_builder_rs2,
                                      imm=b_builder_imm)
        m.d.comb += b_builder_check.eq(built_btype)
        b = BType("btype.build")
        b.elaborate(m.d.comb, built_btype)
        m.d.comb += Assert(b_builder_opcode == b.opcode)
        m.d.comb += Assert(b_builder_imm == Cat(Const(0, 1), b.imm[1:13]))
        m.d.comb += Assert(b.imm[13:32] == Repl(b_builder_imm[12], 32 - 13))

        return [
            b_builder_check, b_builder_opcode, b_builder_f3, b_builder_rs1,
            b_builder_rs2, b_builder_imm
        ]
Beispiel #2
0
    def elaborate(self, platform):
        m = Module()

        # create the byte selector
        with m.Switch(self.x_funct3):
            with m.Case(Funct3.B):
                m.d.comb += self.x_byte_sel.eq(0b0001 << self.x_offset)
            with m.Case(Funct3.H):
                m.d.comb += self.x_byte_sel.eq(0b0011 << self.x_offset)
            with m.Case(Funct3.W):
                m.d.comb += self.x_byte_sel.eq(0b1111)

        # format output data
        with m.Switch(self.x_funct3):
            with m.Case(Funct3.B):
                m.d.comb += self.x_data_w.eq(Repl(self.x_store_data[:8], 4))
            with m.Case(Funct3.H):
                m.d.comb += self.x_data_w.eq(Repl(self.x_store_data[:16], 2))
            with m.Case(Funct3.W):
                m.d.comb += self.x_data_w.eq(self.x_store_data)

        # format input data
        _byte = Signal((8, True))
        _half = Signal((16, True))

        m.d.comb += [
            _byte.eq(self.m_data_r.word_select(self.m_offset, 8)),
            _half.eq(self.m_data_r.word_select(self.m_offset[1], 16)),
        ]

        with m.Switch(self.m_funct3):
            with m.Case(Funct3.B):
                m.d.comb += self.m_load_data.eq(_byte)
            with m.Case(Funct3.BU):
                m.d.comb += self.m_load_data.eq(Cat(_byte,
                                                    0))  # make sign bit = 0
            with m.Case(Funct3.H):
                m.d.comb += self.m_load_data.eq(_half)
            with m.Case(Funct3.HU):
                m.d.comb += self.m_load_data.eq(Cat(_half,
                                                    0))  # make sign bit = 0
            with m.Case(Funct3.W):
                m.d.comb += self.m_load_data.eq(self.m_data_r)

        # misalignment
        with m.Switch(self.x_funct3):
            with m.Case(Funct3.H, Funct3.HU):
                m.d.comb += self.x_misaligned.eq(self.x_offset[0])
            with m.Case(Funct3.W):
                m.d.comb += self.x_misaligned.eq(self.x_offset != 0)

        return m
    def elaborate(self, platform: Platform):
        led1 = platform.request("led", 0)
        led2 = platform.request("led", 1)
        led3 = platform.request("led", 2)
        led4 = platform.request("led", 3)

        ft600_resource = platform.request("ft600")

        m = Module()

        # Connect pseudo power pins for the FT600 and DDR3 banks
        pseudo_power = platform.request("pseudo_power")
        m.d.comb += pseudo_power.ddr.o.eq(Repl(1, len(pseudo_power.ddr)))
        m.d.comb += pseudo_power.ft.o.eq(Repl(1, len(pseudo_power.ft)))

        m.submodules.pll = ECP5PLL(clock_signal_name="pll_clk25",
                                   clock_config=[
                                       ECP5PLLConfig("sync", 25),
                                   ])

        m.domains += ClockDomain("ft600")
        m.d.comb += ClockSignal("ft600").eq(ft600_resource.clk)

        m.submodules.ft600 = ft600 = DomainRenamer("ft600")(FT600(
            ft600_resource, ))

        m.submodules.fifo = fifo = AsyncFIFOBuffered(width=16,
                                                     depth=2048,
                                                     r_domain="ft600",
                                                     w_domain="sync")

        # FT to Write FIFO
        m.d.comb += ft600.input_payload.eq(fifo.r_data)
        m.d.comb += fifo.r_en.eq(ft600.input_ready)
        m.d.comb += ft600.input_valid.eq(fifo.r_rdy)

        # Write data into FIFO
        m.d.comb += fifo.w_data.eq(0xABCD)
        m.d.comb += fifo.w_en.eq(1)

        led_counter = Signal(10)

        with m.If(fifo.w_rdy):
            m.d.sync += led_counter.eq(led_counter + 1)

        # Connect LEDs
        m.d.comb += led1.o.eq(ft600_resource.write)
        m.d.comb += led2.o.eq(ft600_resource.txe)
        m.d.comb += led3.o.eq(fifo.w_level > 2000)
        m.d.comb += led4.o.eq(led_counter[-1])

        return m
Beispiel #4
0
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        sign_fill   = Signal()
        operand     = Signal(32)
        r_direction = Signal()
        r_result    = Signal(32)

        shdata      = Signal(64)  # temp data

        # pre-invert the value, if needed
        # Direction:  1 = right. 0 = left.
        m.d.comb += [
            operand.eq(Mux(self.direction, self.dat, self.dat[::-1])),
            sign_fill.eq(Mux(self.direction & self.sign_ext, self.dat[-1], 0)),

            shdata.eq(Cat(operand, Repl(sign_fill, 32)))
        ]

        with m.If(~self.stall):
            m.d.sync += [
                r_direction.eq(self.direction),
                r_result.eq(shdata >> self.shamt)
            ]

        m.d.comb += self.result.eq(Mux(r_direction, r_result, r_result[::-1]))
        return m
Beispiel #5
0
 def process_load(self, input_value):
     lh_value = Signal(32)
     comb = self.core.current_module.d.comb
     
     bit_to_replicate=Mux(self.core.itype.funct3[2], Const(0,1), input_value[15])
     comb += lh_value.eq(Cat(input_value[0:16], Repl(bit_to_replicate, 16)))
     return lh_value
Beispiel #6
0
    def elaborate(self, _: Platform) -> Module:
        """Implements the logic for the conditional right-shifter."""
        m = Module()
        N = self._N

        with m.If(self.en):
            # The high N bits get either 0 or the most significant
            # bit in data_in, depending on arithmetic.
            msb = self.data_in[-1]
            w = len(self.data_out)

            # m.d.comb += self.data_out.bit_select(w-N, N).eq(
            #     Mux(self.arithmetic, Repl(msb, N), 0))

            with m.If(self.arithmetic):
                m.d.comb += self.data_out[w - N:].eq(Repl(msb, N))
            with m.Else():
                m.d.comb += self.data_out[w - N:].eq(0)

            # The rest are moved over.
            # m.d.comb += self.data_out.bit_select(0, w-N).eq(
            #     self.data_in.bit_select(N, w-N))

            m.d.comb += self.data_out[:w - N].eq(self.data_in[N:])

        with m.Else():
            m.d.comb += self.data_out.eq(self.data_in)

        return m
Beispiel #7
0
 def elaborate(self, comb: List[Statement], input: Signal):
     comb += self.opcode.eq(input[0:7])
     comb += self.funct3.eq(input[12:15])
     comb += self.rs1.eq(input[15:20])
     comb += self.rs2.eq(input[20:25])
     comb += self.imm.eq(
         Cat(Const(0, 1), input[8:12], input[25:31], input[7],
             Repl(input[31], 20)))
Beispiel #8
0
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        a = Signal(signed(33))
        b = Signal(signed(33))
        result_ll = Signal(32)
        result_lh = Signal(33)
        result_hl = Signal(33)
        result_hh = Signal(33)
        result_3 = Signal(64)
        result_4 = Signal(64)
        active = Signal(5)
        is_signed = Signal()
        a_is_signed = Signal()
        b_is_signed = Signal()
        low = Signal()

        m.d.sync += [
            is_signed.eq(a_is_signed ^ b_is_signed),
            active.eq(Cat(self.valid & (active == 0), active)),
            low.eq(self.op == Funct3.MUL)
        ]
        # ----------------------------------------------------------------------
        # fist state
        m.d.comb += [
            a_is_signed.eq((
                (self.op == Funct3.MULH) | (self.op == Funct3.MULHSU))
                           & self.dat1[-1]),
            b_is_signed.eq((self.op == Funct3.MULH) & self.dat2[-1])
        ]
        m.d.sync += [
            a.eq(Mux(a_is_signed, -Cat(self.dat1, 1), self.dat1)),
            b.eq(Mux(b_is_signed, -Cat(self.dat2, 1), self.dat2)),
        ]
        # ----------------------------------------------------------------------
        # second state
        m.d.sync += [
            result_ll.eq(a[0:16] * b[0:16]),
            result_lh.eq(a[0:16] * b[16:33]),
            result_hl.eq(a[16:33] * b[0:16]),
            result_hh.eq(a[16:33] * b[16:33])
        ]
        # ----------------------------------------------------------------------
        # third state
        m.d.sync += [
            result_3.eq(
                Cat(result_ll, result_hh) +
                Cat(Repl(0, 16), (result_lh + result_hl)))
        ]
        # ----------------------------------------------------------------------
        # fourth state
        m.d.sync += [
            result_4.eq(Mux(is_signed, -result_3, result_3)),
            self.result.eq(Mux(low, result_4[:32], result_4[32:64]))
        ]
        m.d.comb += self.ready.eq(active[-1])

        return m
Beispiel #9
0
    def elaborate(self, platform: Platform):
        led1 = platform.request("led", 0)
        led4 = platform.request("led", 3)

        timer1 = Signal(25)
        fifo_buf = Signal(16)

        m = Module()

        # Connect pseudo power pins for the FT600 and DDR3 banks
        pseudo_power = platform.request("pseudo_power")
        m.d.comb += pseudo_power.ddr.o.eq(Repl(1, len(pseudo_power.ddr)))
        m.d.comb += pseudo_power.ft.o.eq(Repl(1, len(pseudo_power.ft)))

        m.submodules.pll = ECP5PLL(clock_signal_name="pll_clk25",
                                   clock_config=[
                                       ECP5PLLConfig("sync", 25),
                                       ECP5PLLConfig("fast", 100, error=0),
                                       ECP5PLLConfig("fast2", 100, error=0),
                                       ECP5PLLConfig("fast3", 150, error=0),
                                   ])

        m.submodules.fifo = fifo = AsyncFIFOBuffered(width=16,
                                                     depth=1024,
                                                     r_domain="fast",
                                                     w_domain="sync")

        # Write the FIFO using the timer data
        m.d.sync += timer1.eq(timer1 + 1)
        with m.If(fifo.w_rdy):
            m.d.comb += fifo.w_data.eq(timer1[9:25])
        m.d.comb += fifo.w_en.eq(1)

        # Read the FIFO in the `fast` domain, the LEDs should blink at the same time
        with m.If(fifo.r_rdy):
            m.d.fast += fifo_buf.eq(fifo.r_data)

        m.d.comb += fifo.r_en.eq(1)

        # Combinatorial logic
        m.d.comb += led1.o.eq(timer1[-1])
        m.d.comb += led4.o.eq(fifo_buf[-1])

        return m
Beispiel #10
0
    def verify_utype(self, m):
        sig = self.build_signal(m, "U", [(0, 6, "1001011"), (7, 11, "10000"),
                                         (12, 31, "00100010000110111111")])
        u = UType("utype")
        u.elaborate(m.d.comb, sig)
        m.d.comb += Assert(u.opcode == Const(0b1001011, 7))
        m.d.comb += Assert(u.rd == Const(0b10000, 5))
        m.d.comb += Assert(
            u.imm == Const(0b00100010000110111111000000000000, 32))

        m.d.comb += Assert(u.match(opcode=0b1001011))
        m.d.comb += Assert(u.match(rd=0b10000))
        m.d.comb += Assert(u.match(imm=0b00100010000110111111000000000000))

        m.d.comb += Assert(u.match(opcode=0b1011011) == 0)
        m.d.comb += Assert(u.match(rd=0b11000) == 0)
        m.d.comb += Assert(
            u.match(imm=0b10100010000110111111000000000000) == 0)

        m.d.comb += Assert(
            u.match(opcode=0b1001011,
                    rd=0b10000,
                    imm=0b00100010000110111111000000000000))

        u = UType("utype.sign")
        u.elaborate(m.d.comb, Const(0x8000_0000, 32))
        m.d.comb += Assert(u.imm[31] == 1)

        u = UType("utype.trailzero")
        u.elaborate(m.d.comb, Const(0xFFFF_FFFF, 32))
        m.d.comb += Assert(u.imm.bit_select(0, 12) == 0)

        u_builder_check = Signal(32)
        u_builder_opcode = Signal(7)
        u_builder_rd = Signal(5)
        u_builder_imm = Signal(20)
        m.d.comb += Assume(u_builder_imm[0:12] == 0)

        built_utype = UType.build_i32(opcode=u_builder_opcode,
                                      rd=u_builder_rd,
                                      imm=u_builder_imm)
        m.d.comb += u_builder_check.eq(built_utype)
        u = UType("utype.build")
        u.elaborate(m.d.comb, built_utype)
        m.d.comb += Assert(u_builder_opcode == u.opcode)
        m.d.comb += Assert(u_builder_rd == u.rd)
        m.d.comb += Assert(Cat(Repl(0, 12), u_builder_imm[12:32]) == u.imm)

        return [u_builder_check, u_builder_opcode, u_builder_rd, u_builder_imm]
Beispiel #11
0
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        snoop_addr = Record(self.pc_layout)
        snoop_valid = Signal()

        # -------------------------------------------------------------------------
        # Performance counter
        # TODO: connect to CSR's performance counter
        with m.If(~self.s1_stall & self.s1_valid & self.s1_access):
            m.d.sync += self.access_cnt.eq(self.access_cnt + 1)
        with m.If(self.s2_valid & self.s2_miss & ~self.bus_valid
                  & self.s2_access):
            m.d.sync += self.miss_cnt.eq(self.miss_cnt + 1)
        # -------------------------------------------------------------------------

        way_layout = [('data', 32 * self.nwords),
                      ('tag', self.s1_address.tag.shape()), ('valid', 1),
                      ('sel_lru', 1), ('snoop_hit', 1)]
        if self.enable_write:
            way_layout.append(('sel_we', 1))

        ways = Array(
            Record(way_layout, name='way_idx{}'.format(_way))
            for _way in range(self.nways))
        fill_cnt = Signal.like(self.s1_address.offset)

        # Check hit/miss
        way_hit = m.submodules.way_hit = Encoder(self.nways)
        for idx, way in enumerate(ways):
            m.d.comb += way_hit.i[idx].eq((way.tag == self.s2_address.tag)
                                          & way.valid)

        m.d.comb += self.s2_miss.eq(way_hit.n)
        if self.enable_write:
            # Asumiendo que hay un HIT, indicar que la vía que dió hit es en la cual se va a escribir
            m.d.comb += ways[way_hit.o].sel_we.eq(self.s2_we & self.s2_valid)

        # set the LRU
        if self.nways == 1:
            # One way: LRU is useless
            lru = Const(0)  # self.nlines
        else:
            # LRU es un vector de N bits, cada uno indicado el set a reemplazar
            # como NWAY es máximo 2, cada LRU es de un bit
            lru = Signal(self.nlines)
            _lru = lru.bit_select(self.s2_address.line, 1)
            write_ended = self.bus_valid & self.bus_ack & self.bus_last  # err ^ ack = = 1
            access_hit = ~self.s2_miss & self.s2_valid & (way_hit.o == _lru)
            with m.If(write_ended | access_hit):
                m.d.sync += _lru.eq(~_lru)

        # read data from the cache
        m.d.comb += self.s2_rdata.eq(ways[way_hit.o].data.word_select(
            self.s2_address.offset, 32))

        # Internal Snoop
        snoop_use_cache = Signal()
        snoop_tag_match = Signal()
        snoop_line_match = Signal()
        snoop_cancel_refill = Signal()
        if not self.enable_write:
            bits_range = log2_int(self.end_addr - self.start_addr,
                                  need_pow2=False)

            m.d.comb += [
                snoop_addr.eq(self.dcache_snoop.addr),  # aux
                snoop_valid.eq(self.dcache_snoop.we & self.dcache_snoop.valid
                               & self.dcache_snoop.ack),
                snoop_use_cache.eq(snoop_addr[bits_range:] == (
                    self.start_addr >> bits_range)),
                snoop_tag_match.eq(snoop_addr.tag == self.s2_address.tag),
                snoop_line_match.eq(snoop_addr.line == self.s2_address.line),
                snoop_cancel_refill.eq(snoop_use_cache & snoop_valid
                                       & snoop_line_match & snoop_tag_match),
            ]
        else:
            m.d.comb += snoop_cancel_refill.eq(0)

        with m.FSM():
            with m.State('READ'):
                with m.If(self.s2_re & self.s2_miss & self.s2_valid):
                    m.d.sync += [
                        self.bus_addr.eq(self.s2_address),
                        self.bus_valid.eq(1),
                        fill_cnt.eq(self.s2_address.offset - 1)
                    ]
                    m.next = 'REFILL'
            with m.State('REFILL'):
                m.d.comb += self.bus_last.eq(fill_cnt == self.bus_addr.offset)
                with m.If(self.bus_ack):
                    m.d.sync += self.bus_addr.offset.eq(self.bus_addr.offset +
                                                        1)
                with m.If(self.bus_ack & self.bus_last | self.bus_err):
                    m.d.sync += self.bus_valid.eq(0)
                with m.If(~self.bus_valid | self.s1_flush
                          | snoop_cancel_refill):
                    m.next = 'READ'
                    m.d.sync += self.bus_valid.eq(0)

        # mark the way to use (replace)
        m.d.comb += ways[lru.bit_select(self.s2_address.line,
                                        1)].sel_lru.eq(self.bus_valid)

        # generate for N ways
        for way in ways:
            # create the memory structures for valid, tag and data.
            valid = Signal(self.nlines)  # Valid bits

            tag_m = Memory(width=len(way.tag), depth=self.nlines)  # tag memory
            tag_rp = tag_m.read_port()
            snoop_rp = tag_m.read_port()
            tag_wp = tag_m.write_port()
            m.submodules += tag_rp, tag_wp, snoop_rp

            data_m = Memory(width=len(way.data),
                            depth=self.nlines)  # data memory
            data_rp = data_m.read_port()
            data_wp = data_m.write_port(
                granularity=32
            )  # implica que solo puedo escribir palabras de 32 bits.
            m.submodules += data_rp, data_wp

            # handle valid
            with m.If(self.s1_flush & self.s1_valid):  # flush
                m.d.sync += valid.eq(0)
            with m.Elif(way.sel_lru & self.bus_last
                        & self.bus_ack):  # refill ok
                m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(1)
            with m.Elif(way.sel_lru & self.bus_err):  # refill error
                m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(0)
            with m.Elif(self.s2_evict & self.s2_valid
                        & (way.tag == self.s2_address.tag)):  # evict
                m.d.sync += valid.bit_select(self.s2_address.line, 1).eq(0)

            # assignments
            m.d.comb += [
                tag_rp.addr.eq(
                    Mux(self.s1_stall, self.s2_address.line,
                        self.s1_address.line)),
                tag_wp.addr.eq(self.bus_addr.line),
                tag_wp.data.eq(self.bus_addr.tag),
                tag_wp.en.eq(way.sel_lru & self.bus_ack & self.bus_last),
                data_rp.addr.eq(
                    Mux(self.s1_stall, self.s2_address.line,
                        self.s1_address.line)),
                way.data.eq(data_rp.data),
                way.tag.eq(tag_rp.data),
                way.valid.eq(valid.bit_select(self.s2_address.line, 1))
            ]

            # update cache: CPU or Refill
            # El puerto de escritura se multiplexa debido a que la memoria solo puede tener un
            # puerto de escritura.
            if self.enable_write:
                update_addr = Signal(len(data_wp.addr))
                update_data = Signal(len(data_wp.data))
                update_we = Signal(len(data_wp.en))
                aux_wdata = Signal(32)

                with m.If(self.bus_valid):
                    m.d.comb += [
                        update_addr.eq(self.bus_addr.line),
                        update_data.eq(Repl(self.bus_data, self.nwords)),
                        update_we.bit_select(self.bus_addr.offset,
                                             1).eq(way.sel_lru & self.bus_ack),
                    ]
                with m.Else():
                    m.d.comb += [
                        update_addr.eq(self.s2_address.line),
                        update_data.eq(Repl(aux_wdata, self.nwords)),
                        update_we.bit_select(self.s2_address.offset,
                                             1).eq(way.sel_we & ~self.s2_miss)
                    ]
                m.d.comb += [
                    # Aux data: no tengo granularidad de byte en el puerto de escritura. Así que para el
                    # caso en el cual el CPU tiene que escribir, hay que construir el dato (wrord) a reemplazar
                    aux_wdata.eq(
                        Cat(
                            Mux(self.s2_sel[0],
                                self.s2_wdata.word_select(0, 8),
                                self.s2_rdata.word_select(0, 8)),
                            Mux(self.s2_sel[1],
                                self.s2_wdata.word_select(1, 8),
                                self.s2_rdata.word_select(1, 8)),
                            Mux(self.s2_sel[2],
                                self.s2_wdata.word_select(2, 8),
                                self.s2_rdata.word_select(2, 8)),
                            Mux(self.s2_sel[3],
                                self.s2_wdata.word_select(3, 8),
                                self.s2_rdata.word_select(3, 8)))),
                    #
                    data_wp.addr.eq(update_addr),
                    data_wp.data.eq(update_data),
                    data_wp.en.eq(update_we),
                ]
            else:
                m.d.comb += [
                    data_wp.addr.eq(self.bus_addr.line),
                    data_wp.data.eq(Repl(self.bus_data, self.nwords)),
                    data_wp.en.bit_select(self.bus_addr.offset,
                                          1).eq(way.sel_lru & self.bus_ack),
                ]

                # --------------------------------------------------------------
                # intenal snoop
                # for FENCE.i instruction
                _match_snoop = Signal()

                m.d.comb += [
                    snoop_rp.addr.eq(snoop_addr.line),  # read tag memory
                    _match_snoop.eq(snoop_rp.data == snoop_addr.tag),
                    way.snoop_hit.eq(snoop_use_cache & snoop_valid
                                     & _match_snoop
                                     & valid.bit_select(snoop_addr.line, 1)),
                ]
                # check is the snoop match a write from this core
                with m.If(way.snoop_hit):
                    m.d.sync += valid.bit_select(snoop_addr.line, 1).eq(0)
                # --------------------------------------------------------------

        return m
    def requant(mod: Module, sig_i: Signal, QI: dict, QO: dict) -> Signal:
        """
        Change word length of input signal `sig_i` to `WO` bits, using the
        quantization and saturation methods specified by ``QO['quant']`` and
        ``QO['ovfl']``.

        Parameters
        ----------

        mod: Module (nmigen)
            instance of migen module

        sig_i: Signal (nmigen)
            Signal to be requantized

        QI: dict
            Quantization dict for input word, only the keys 'WI' and 'WF' for integer
            and fractional wordlength are evaluated. QI['WI'] = 2 and QI['WF'] = 13
            e.g. define Q-Format '2.13'  with 2 integer, 13 fractional bits and 1 implied
            sign bit = 16 bits total.

        QO: dict
            Quantization dict for output word format; the keys 'WI' and 'WF' for
            integer and fractional wordlength are evaluated as well as the keys 'quant'
            and 'ovfl' describing requantization and overflow behaviour.

        Returns
        -------

        sig_o: Signal (nmigen)
            Requantized signal

        Documentation
        -------------

        **Input and output word are aligned at their binary points.**

        The following shows an example of rescaling an input word from Q2.4 to Q0.3
        using wrap-around and truncation. It's easy to see that for simple wrap-around
        logic, the sign of the result may change.

        ::

        S | WI1 | WI0 * WF0 | WF1 | WF2 | WF3  :  WI = 2, WF = 4, W = 7
        0 |  1  |  0  *  1  |  0  |  1  |  1   =  43 (dec) or 43/16 = 2 + 11/16 (float)
                        *
                |  S  * WF0 | WF1 | WF2        :  WI = 0, WF = 3, W = 4
                    0  *  1  |  0  |  1         =  7 (dec) or 7/8 (float)


        The float or "real (world) value" is calculated by multiplying the integer
        value by 2 ** (-WF).

        For requantizing two numbers to the same WI and WF, imagine both binary numbers
        to be right-aligned. Changes in the number of integer bits `dWI` and fractional
        bits `dWF` are handled separately.

        Fractional Bits
        ---------------

        - For reducing the number of fractional bits by `dWF`, simply right-shift the
        integer number by `dWF`. For rounding, add '1' to the bit below the truncation
        point before right-shifting.

        - Extend the number of fractional bits by left-shifting the integer by `dWF`,
        LSB's are filled with zeros.

        Integer Bits
        ------------

        - For reducing the number of integer bits by `dWI`, simply right-shift the
        integer by `dWI`.

        - The number of fractional bits is SIGN-EXTENDED by filling up the left-most
        bits with the sign bit.

        """
        WI_I = QI['WI']  # number of integer bits (input signal)
        WI_F = QI['WF']  # number of integer bits (output signal)
        WI = WI_I + WI_F + 1  # total word length (input signal)

        WO_I = QO['WI']  # number of integer bits (input signal)
        WO_F = QO['WF']  # number of integer bits (output signal)
        WO = WO_I + WO_F + 1  # total word length (input signal)

        dWF = WI_F - WO_F  # difference of fractional lengths
        dWI = WI_I - WO_I  # difference of integer lengths

        # max. resp. min, output values
        MIN_o = -1 << (WO - 1)
        MAX_o = -MIN_o - 1

        # intermediate signal with requantized fractional part
        sig_i_q = Signal(signed(max(WI, WO)))
        sig_o = Signal(signed(WO))

        # logger.debug(f"rescale: dWI={dWI}, dWF={dWF}, Qu:{QO['quant']}, Ov:{QO['ovfl']}")

        # -----------------------------------------------------------------------
        # Requantize fractional part
        # -----------------------------------------------------------------------
        if dWF <= 0:  # Extend fractional word length of output word by
            # multiplying with 2^dWF
            mod.d.comb += sig_i_q.eq(sig_i << -dWF)  # shift input left by -dWF
        else:  # dWF > 0, reduce fract. word length by dividing by 2^dWF
            # (shift right by dWF)
            if QO['quant'] == 'round':
                # add half an LSB (1 << (dWF - 1)) before right shift
                mod.d.comb += sig_i_q.eq((sig_i + (1 << (dWF - 1))) >> dWF)
            elif QO['quant'] == 'floor':  # just shift right
                mod.d.comb += sig_i_q.eq(sig_i >> dWF)
            elif QO['quant'] == 'fix':
                # add sign bit (sig_i[-1]) as LSB (1 << dWF) before right shift
                mod.d.comb += sig_i_q.eq((sig_i + (sig_i[-1] << dWF)) >> dWF)
            else:
                raise Exception(u'Unknown quantization method "%s"!' %
                                (QI['quant']))

        # -----------------------------------------------------------------------
        # Requantize integer part
        # -----------------------------------------------------------------------
        if dWI < 0:  # WI_I < WO_I, sign extend integer part (prepend copies of sign bit)
            mod.d.comb += sig_o.eq(Cat(sig_i_q, Repl(sig_i_q[-1], -dWI)))
        elif dWI == 0:  # WI = WO, don't change integer part
            mod.d.comb += sig_o.eq(sig_i_q)
        elif QO['ovfl'] == 'sat':
            with mod.If(sig_i_q[-1] == 1):
                with mod.If(sig_i_q < MIN_o):
                    mod.d.comb += sig_o.eq(MIN_o)
                with mod.Else():
                    mod.d.comb += sig_o.eq(sig_i_q)
            with mod.Elif(sig_i_q > MAX_o):  # sig_i_q[-1] == 0
                mod.d.comb += sig_o.eq(MAX_o)
            with mod.Else():
                mod.d.comb += sig_o.eq(sig_i_q)

        elif QO['ovfl'] == 'wrap':  # wrap around (shift left)
            mod.d.comb += sig_o.eq(sig_i_q)

        else:
            raise Exception(u'Unknown overflow method "%s"!' % (QI['ovfl']))

        return sig_o
Beispiel #13
0
 def elaborate(self, comb: List[Statement], input: Signal):
     comb += self.opcode.eq(input[0:7])
     comb += self.rd.eq(input[7:12])
     comb += self.funct3.eq(input[12:15])
     comb += self.rs1.eq(input[15:20])
     comb += self.imm.eq(Cat(input[20:32], Repl(input[31], 20)))
Beispiel #14
0
 def elaborate(self, comb: List[Statement], input: Signal):
     comb += self.opcode.eq(input[0:7])
     comb += self.rd.eq(input[7:12])
     comb += self.imm.eq(
         Cat(Const(0, 1), input[21:31], input[20], input[12:20],
             Repl(input[31], 12)))
Beispiel #15
0
    def elaborate(self, platform):
        m = Module()

        way_layout = [
            ('data',     32 * self.nwords),
            ('tag',      self.s1_address.tag.shape()),
            ('valid',    1),
            ('sel_lru',  1)
        ]
        if self.enable_write:
            way_layout.append(('sel_we',   1))

        ways     = Array(Record(way_layout) for _way in range(self.nways))
        fill_cnt = Signal.like(self.s1_address.offset)
        # set the LRU
        if self.nways == 1:
            lru = Const(0)  # self.nlines
        else:
            lru = Signal(self.nlines)
            with m.If(self.bus_valid & self.bus_ack & self.bus_last):  # err ^ ack == 1
                _lru = lru.bit_select(self.s2_address.line, 1)
                m.d.sync += lru.bit_select(self.s2_address.line, 1).eq(~_lru)

        # hit/miss
        way_hit = m.submodules.way_hit = Encoder(self.nways)
        for idx, way in enumerate(ways):
            m.d.comb += way_hit.i[idx].eq((way.tag == self.s2_address.tag) & way.valid)

        m.d.comb += self.s2_miss.eq(way_hit.n)
        if self.enable_write:
            m.d.comb += ways[way_hit.o].sel_we.eq(self.s2_we & self.s2_valid)

        # read data
        m.d.comb += self.s2_rdata.eq(ways[way_hit.o].data.word_select(self.s2_address.offset, 32))

        with m.FSM():
            with m.State('READ'):
                with m.If(self.s2_re & self.s2_miss & self.s2_valid):
                    m.d.sync += [
                        self.bus_addr.eq(self.s2_address),  # WARNING extra_bits
                        self.bus_valid.eq(1),
                        fill_cnt.eq(self.s2_address.offset - 1)
                    ]
                    m.next = 'REFILL'
            with m.State('REFILL'):
                m.d.comb += self.bus_last.eq(fill_cnt == self.bus_addr.offset)
                with m.If(self.bus_ack):
                    m.d.sync += self.bus_addr.offset.eq(self.bus_addr.offset + 1)
                with m.If(self.bus_ack & self.bus_last | self.bus_err):
                    m.d.sync += self.bus_valid.eq(0)
                with m.If(~self.bus_valid | self.s1_flush):
                    # in case of flush, abort ongoing refill.
                    m.next = 'READ'
                    m.d.sync += self.bus_valid.eq(0)

        # mark the way to use (replace)
        m.d.comb += ways[lru.bit_select(self.s2_address.line, 1)].sel_lru.eq(self.bus_valid)

        # generate for N ways
        for way in ways:
            # create the memory structures for valid, tag and data.
            valid = Signal(self.nlines)

            tag_m  = Memory(width=len(way.tag), depth=self.nlines)
            tag_rp = tag_m.read_port()
            tag_wp = tag_m.write_port()
            m.submodules += tag_rp, tag_wp

            data_m  = Memory(width=len(way.data), depth=self.nlines)
            data_rp = data_m.read_port()
            data_wp = data_m.write_port(granularity=32)
            m.submodules += data_rp, data_wp

            # handle valid
            with m.If(self.s1_flush & self.s1_valid):  # flush
                m.d.sync += valid.eq(0)
            with m.Elif(way.sel_lru & self.bus_last & self.bus_ack):  # refill ok
                m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(1)
            with m.Elif(way.sel_lru & self.bus_err):  # refill error
                m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(0)
            with m.Elif(self.s2_evict & self.s2_valid & (way.tag == self.s2_address.tag)):  # evict
                m.d.sync += valid.bit_select(self.s2_address.line, 1).eq(0)

            # assignments
            m.d.comb += [
                tag_rp.addr.eq(Mux(self.s1_stall, self.s2_address.line, self.s1_address.line)),
                tag_wp.addr.eq(self.bus_addr.line),
                tag_wp.data.eq(self.bus_addr.tag),
                tag_wp.en.eq(way.sel_lru & self.bus_ack & self.bus_last),

                data_rp.addr.eq(Mux(self.s1_stall, self.s2_address.line, self.s1_address.line)),

                way.data.eq(data_rp.data),
                way.tag.eq(tag_rp.data),
                way.valid.eq(valid.bit_select(self.s2_address.line, 1))
            ]

            # update cache: CPU or Refill
            if self.enable_write:
                update_addr = Signal(len(data_wp.addr))
                update_data = Signal(len(data_wp.data))
                update_we   = Signal(len(data_wp.en))
                aux_wdata   = Signal(32)

                with m.If(self.bus_valid):
                    m.d.comb += [
                        update_addr.eq(self.bus_addr.line),
                        update_data.eq(Repl(self.bus_data, self.nwords)),
                        update_we.bit_select(self.bus_addr.offset, 1).eq(way.sel_lru & self.bus_ack),
                    ]
                with m.Else():
                    m.d.comb += [
                        update_addr.eq(self.s2_address.line),
                        update_data.eq(Repl(aux_wdata, self.nwords)),
                        update_we.bit_select(self.s2_address.offset, 1).eq(way.sel_we & ~self.s2_miss)
                    ]
                m.d.comb += [
                    aux_wdata.eq(Cat(
                        Mux(self.s2_sel[0], self.s2_wdata.word_select(0, 8), self.s2_rdata.word_select(0, 8)),
                        Mux(self.s2_sel[1], self.s2_wdata.word_select(1, 8), self.s2_rdata.word_select(1, 8)),
                        Mux(self.s2_sel[2], self.s2_wdata.word_select(2, 8), self.s2_rdata.word_select(2, 8)),
                        Mux(self.s2_sel[3], self.s2_wdata.word_select(3, 8), self.s2_rdata.word_select(3, 8))
                    )),
                    #
                    data_wp.addr.eq(update_addr),
                    data_wp.data.eq(update_data),
                    data_wp.en.eq(update_we),
                ]
            else:
                m.d.comb += [
                    data_wp.addr.eq(self.bus_addr.line),
                    data_wp.data.eq(Repl(self.bus_data, self.nwords)),
                    data_wp.en.bit_select(self.bus_addr.offset, 1).eq(way.sel_lru & self.bus_ack),
                ]

        return m
Beispiel #16
0
    def decode_imm_chips(self, m: Module):
        mux = IC_mux32(N=6, faster=True)
        gal = IC_GAL_imm_format_decoder()

        m.submodules += mux
        m.submodules += gal

        m.d.comb += gal.opcode.eq(self._opcode)
        m.d.comb += mux.n_sel[0].eq(gal.i_n_oe)
        m.d.comb += mux.n_sel[1].eq(gal.s_n_oe)
        m.d.comb += mux.n_sel[2].eq(gal.u_n_oe)
        m.d.comb += mux.n_sel[3].eq(gal.b_n_oe)
        m.d.comb += mux.n_sel[4].eq(gal.j_n_oe)
        m.d.comb += mux.n_sel[5].eq(gal.sys_n_oe)

        instr = self.state._instr

        # Format I
        m.d.comb += [
            mux.a[0][0:12].eq(instr[20:]),
            mux.a[0][12:].eq(Repl(instr[31], 32)),  # sext
        ]

        # Format S
        m.d.comb += [
            mux.a[1][0:5].eq(instr[7:]),
            mux.a[1][5:11].eq(instr[25:]),
            mux.a[1][11:].eq(Repl(instr[31], 32)),  # sext
        ]

        # Format U
        m.d.comb += [
            mux.a[2][0:12].eq(0),
            mux.a[2][12:].eq(instr[12:]),
        ]

        # Format B
        m.d.comb += [
            mux.a[3][0].eq(0),
            mux.a[3][1:5].eq(instr[8:]),
            mux.a[3][5:11].eq(instr[25:]),
            mux.a[3][11].eq(instr[7]),
            mux.a[3][12:].eq(Repl(instr[31], 32)),  # sext
        ]

        # Format J
        m.d.comb += [
            mux.a[4][0].eq(0),
            mux.a[4][1:11].eq(instr[21:]),
            mux.a[4][11].eq(instr[20]),
            mux.a[4][12:20].eq(instr[12:]),
            mux.a[4][20:].eq(Repl(instr[31], 32)),  # sext
        ]

        # Format SYS
        m.d.comb += [
            mux.a[5][0:5].eq(instr[15:]),
            mux.a[5][5:].eq(0),
        ]

        m.d.comb += self._imm.eq(mux.y)