Beispiel #1
0
    def __init__(self, x_len: int):
        super().__init__(x_len)
        io = self.io
        sum_ = io.A + m.mux([io.B, -io.B], io.op[0])
        cmp = m.uint(m.mux([m.mux([io.A[-1], io.B[-1]], io.op[1]), sum_[-1]],
                           io.A[-1] == io.B[-1]), x_len)
        shin = m.mux([io.A[::-1], io.A], io.op[3])
        shiftr = m.uint(m.sint(
            m.concat(shin, io.op[0] & shin[x_len - 1])
        ) >> m.sint(m.zext(io.B, 1)))[:x_len]
        shiftl = shiftr[::-1]

        @m.inline_combinational()
        def alu():
            if (io.op == ALUOP.ADD) | (io.op == ALUOP.SUB):
                io.O @= sum_
            elif (io.op == ALUOP.SLT) | (io.op == ALUOP.SLTU):
                io.O @= cmp
            elif (io.op == ALUOP.SRA) | (io.op == ALUOP.SRL):
                io.O @= shiftr
            elif io.op == ALUOP.SLL:
                io.O @= shiftl
            elif io.op == ALUOP.AND:
                io.O @= io.A & io.B
            elif io.op == ALUOP.OR:
                io.O @= io.A | io.B
            elif io.op == ALUOP.XOR:
                io.O @= io.A ^ io.B
            elif io.op == ALUOP.COPY_A:
                io.O @= io.A
            else:
                io.O @= io.B
        io.sum_ @= sum_
Beispiel #2
0
        def alu():
            if io.op == ALUOP.ADD:
                io.O @= io.A + io.B
            elif io.op == ALUOP.SUB:
                io.O @= io.A - io.B
            elif io.op == ALUOP.SRA:
                io.O @= m.uint(m.sint(io.A) >> m.sint(io.B))
            elif io.op == ALUOP.SRL:
                io.O @= io.A >> io.B
            elif io.op == ALUOP.SLL:
                io.O @= io.A << io.B
            elif io.op == ALUOP.SLT:
                io.O @= m.uint(m.sint(io.A) < m.sint(io.B), x_len)
            elif io.op == ALUOP.SLTU:
                io.O @= m.uint(io.A < io.B, x_len)
            elif io.op == ALUOP.AND:
                io.O @= io.A & io.B
            elif io.op == ALUOP.OR:
                io.O @= io.A | io.B
            elif io.op == ALUOP.XOR:
                io.O @= io.A ^ io.B
            elif io.op == ALUOP.COPY_A:
                io.O @= io.A
            else:
                io.O @= io.B

            io.sum_ @= io.A + m.mux([io.B, -io.B], io.op[0])
Beispiel #3
0
    def __init__(self, x_len):
        super().__init__(x_len)
        inst = self.io.inst
        Iimm = m.sext_to(m.sint(inst[20:32]), x_len)
        Simm = m.sext_to(m.sint(m.concat(inst[7:12], inst[25:32])), x_len)
        Bimm = m.sext_to(
            m.sint(
                m.concat(m.bits(0, 1), inst[8:12], inst[25:31], inst[7],
                         inst[31])), x_len)
        Uimm = m.concat(m.bits(0, 12), inst[12:32])
        Jimm = m.sext_to(
            m.sint(
                m.concat(m.bits(0, 1), inst[21:25], inst[25:31], inst[20],
                         inst[12:20], inst[31])), x_len)
        Zimm = m.sint(m.zext_to(inst[15:20], x_len))

        self.io.O @= m.uint(
            m.dict_lookup(
                {
                    IMM_I: Iimm,
                    IMM_S: Simm,
                    IMM_B: Bimm,
                    IMM_U: Uimm,
                    IMM_J: Jimm,
                    IMM_Z: Zimm
                }, self.io.sel, Iimm & -2))
Beispiel #4
0
def test_sext(value):
    in_ = sint(value, 16)
    # TODO(rsetaluri): Ideally, zext(sint) should return an object of type
    # SintType, instead it returns an object of type ArrayType. For now, we wrap
    # the result of zext() in sint().
    out = sint(sext(in_, 16))
    assert len(out.bits()) == 32
    assert int(out) == value
Beispiel #5
0
    class BrCond_DUT(m.Circuit):
        _IGNORE_UNUSED_ = True
        io = m.IO(
            done=m.Out(m.Bit),
            out=m.Out(m.Bit),
            taken=m.Out(m.Bit)
        ) + m.ClockIO()
        br_cond = BrCond(x_len)()
        io.taken @= br_cond.taken

        control = Control(x_len)()
        br_cond.br_type @= control.br_type

        insts = [
            B(Funct3.BEQ, 0, 0, 0),
            B(Funct3.BNE, 0, 0, 0),
            B(Funct3.BLT, 0, 0, 0),
            B(Funct3.BGE, 0, 0, 0),
            B(Funct3.BLTU, 0, 0, 0),
            B(Funct3.BGEU, 0, 0, 0),
        ] * 10

        n = len(insts)
        counter = CounterModM(n, n.bit_length())
        control.inst @= m.mux(insts, counter.O)
        io.done @= counter.COUT

        rs1 = [BV.random(x_len) for _ in range(n)]
        rs2 = [BV.random(x_len) for _ in range(n)]
        br_cond.rs1 @= m.mux(rs1, counter.O)
        br_cond.rs2 @= m.mux(rs2, counter.O)

        eq = [a == b for a, b in zip(rs1, rs2)]
        ne = [a != b for a, b in zip(rs1, rs2)]
        lt = [m.sint(a) < m.sint(b) for a, b in zip(rs1, rs2)]
        ge = [m.sint(a) >= m.sint(b) for a, b in zip(rs1, rs2)]
        ltu = [a < b for a, b in zip(rs1, rs2)]
        geu = [a >= b for a, b in zip(rs1, rs2)]

        @m.inline_combinational()
        def logic():
            if control.br_type == BR_EQ:
                io.out @= m.mux(eq, counter.O)
            elif control.br_type == BR_NE:
                io.out @= m.mux(ne, counter.O)
            elif control.br_type == BR_LT:
                io.out @= m.mux(lt, counter.O)
            elif control.br_type == BR_GE:
                io.out @= m.mux(ge, counter.O)
            elif control.br_type == BR_LTU:
                io.out @= m.mux(ltu, counter.O)
            elif control.br_type == BR_GEU:
                io.out @= m.mux(geu, counter.O)
            else:
                io.out @= False
Beispiel #6
0
def test_array():
    assert isinstance(array(1, 4), ArrayType)
    assert isinstance(array([1, 0, 0, 0]), ArrayType)
    assert isinstance(array(VCC), ArrayType)
    assert isinstance(array(array(1, 4)), ArrayType)
    assert isinstance(array(uint(1, 4)), ArrayType)
    assert isinstance(array(sint(1, 4)), ArrayType)
Beispiel #7
0
def test_bits():
    assert isinstance(bits(1, 4), BitsType)
    assert isinstance(bits([1, 0, 0, 0]), BitsType)
    assert isinstance(bits(VCC), BitsType)
    assert isinstance(bits(array(1, 4)), BitsType)
    assert isinstance(bits(uint(1, 4)), BitsType)
    assert isinstance(bits(sint(1, 4)), BitsType)
Beispiel #8
0
def test_tuple():
    assert isinstance(tuple_(OrderedDict(x=0, y=1)), TupleType)
    assert isinstance(tuple_([0, 1]), TupleType)
    assert isinstance(tuple_(VCC), TupleType)
    assert isinstance(tuple_(array(1, 4)), TupleType)
    assert isinstance(tuple_(bits(1, 4)), TupleType)
    assert isinstance(tuple_(sint(1, 4)), TupleType)
    assert isinstance(tuple_(uint(1, 4)), TupleType)
Beispiel #9
0
 def wrapper(*args, **kwargs):
     retval = fn(*args, **kwargs)
     T = type(args[0])
     if issubclass(T, m.UInt):
         return m.uint(retval)
     elif issubclass(T, m.SInt):
         return m.sint(retval)
     return retval
Beispiel #10
0
 def __init__(self, x_len):
     super().__init__(x_len)
     io = self.io
     eq = io.rs1 == io.rs2
     neq = ~eq
     lt = m.sint(io.rs1) < m.sint(io.rs2)
     ge = ~lt
     ltu = io.rs1 < io.rs2
     geu = ~ltu
     io.taken @= (
         ((io.br_type == BR_EQ) & eq) |
         ((io.br_type == BR_NE) & neq) |
         ((io.br_type == BR_LT) & lt) |
         ((io.br_type == BR_GE) & ge) |
         ((io.br_type == BR_LTU) & ltu) |
         ((io.br_type == BR_GEU) & geu)
     )
Beispiel #11
0
 def wrapper(*args, **kwargs):
     retval = fn(*args, **kwargs)
     T = type(args[0])
     if isinstance(T, m.UIntKind):
         return m.uint(retval)
     elif isinstance(T, m.SIntKind):
         return m.sint(retval)
     return retval
Beispiel #12
0
def test_clock():
    assert isinstance(clock(0), ClockType)
    assert isinstance(clock(1), ClockType)
    assert isinstance(clock(VCC), ClockType)
    assert isinstance(clock(GND), ClockType)
    assert isinstance(clock(bit(0)), ClockType)
    assert isinstance(clock(clock(0)), ClockType)
    assert isinstance(clock(reset(0)), ClockType)
    assert isinstance(clock(enable(0)), ClockType)
    assert isinstance(clock(bits(0, 1)), ClockType)
    assert isinstance(clock(uint(0, 1)), ClockType)
    assert isinstance(clock(sint(0, 1)), ClockType)
Beispiel #13
0
def test_reset():
    assert isinstance(reset(0), ResetType)
    assert isinstance(reset(1), ResetType)
    assert isinstance(reset(VCC), ResetType)
    assert isinstance(reset(GND), ResetType)
    assert isinstance(reset(bit(0)), ResetType)
    assert isinstance(reset(clock(0)), ResetType)
    assert isinstance(reset(enable(0)), ResetType)
    assert isinstance(reset(reset(0)), ResetType)
    assert isinstance(reset(bits(0, 1)), ResetType)
    assert isinstance(reset(uint(0, 1)), ResetType)
    assert isinstance(reset(sint(0, 1)), ResetType)
Beispiel #14
0
def test_enable():
    assert isinstance(enable(0), EnableType)
    assert isinstance(enable(1), EnableType)
    assert isinstance(enable(VCC), EnableType)
    assert isinstance(enable(GND), EnableType)
    assert isinstance(enable(bit(0)), EnableType)
    assert isinstance(enable(clock(0)), EnableType)
    assert isinstance(enable(reset(0)), EnableType)
    assert isinstance(enable(enable(0)), EnableType)
    assert isinstance(enable(bits(0, 1)), EnableType)
    assert isinstance(enable(uint(0, 1)), EnableType)
    assert isinstance(enable(sint(0, 1)), EnableType)
Beispiel #15
0
    def __init__(self, x_len, n_ways: int, n_sets: int, b_bytes: int):
        b_bits = b_bytes << 3
        b_len = m.bitutils.clog2(b_bytes)
        s_len = m.bitutils.clog2(n_sets)
        t_len = x_len - (s_len + b_len)
        n_words = b_bits // x_len
        w_bytes = x_len // 8
        byte_offset_bits = m.bitutils.clog2(w_bytes)
        nasti_params = NastiParameters(data_bits=64,
                                       addr_bits=x_len,
                                       id_bits=5)
        data_beats = b_bits // nasti_params.x_data_bits

        class MetaData(m.Product):
            tag = m.UInt[t_len]

        self.io = m.IO(**make_cache_ports(x_len, nasti_params))
        self.io += m.ClockIO()

        class State(m.Enum):
            IDLE = 0
            READ_CACHE = 1
            WRITE_CACHE = 2
            WRITE_BACK = 3
            WRITE_ACK = 4
            REFILL_READY = 5
            REFILL = 6

        state = m.Register(init=State.IDLE)()

        # memory
        v = m.Register(m.UInt[n_sets], has_enable=True)()
        d = m.Register(m.UInt[n_sets], has_enable=True)()
        meta_mem = m.Memory(n_sets,
                            MetaData,
                            read_latency=1,
                            has_read_enable=True)()
        data_mem = [
            ArrayMaskMem(n_sets,
                         w_bytes,
                         m.UInt[8],
                         read_latency=1,
                         has_read_enable=True)() for _ in range(n_words)
        ]

        addr_reg = m.Register(type(self.io.cpu.req.data.addr).undirected_t,
                              has_enable=True)()
        cpu_data = m.Register(type(self.io.cpu.req.data.data).undirected_t,
                              has_enable=True)()
        cpu_mask = m.Register(type(self.io.cpu.req.data.mask).undirected_t,
                              has_enable=True)()

        self.io.nasti.r.ready @= state.O == State.REFILL
        # Counters
        assert data_beats > 0
        if data_beats > 1:
            read_counter = mantle.CounterModM(data_beats,
                                              max(data_beats.bit_length(), 1),
                                              has_ce=True)
            read_counter.CE @= m.enable(self.io.nasti.r.fired())
            read_count, read_wrap_out = read_counter.O, read_counter.COUT

            write_counter = mantle.CounterModM(data_beats,
                                               max(data_beats.bit_length(), 1),
                                               has_ce=True)
            write_count, write_wrap_out = write_counter.O, write_counter.COUT
        else:
            read_count, read_wrap_out = 0, 1
            write_count, write_wrap_out = 0, 1

        refill_buf = m.Register(m.Array[data_beats,
                                        m.UInt[nasti_params.x_data_bits]],
                                has_enable=True)()
        if data_beats == 1:
            refill_buf.I[0] @= self.io.nasti.r.data.data
        else:
            refill_buf.I @= m.set_index(refill_buf.O,
                                        self.io.nasti.r.data.data,
                                        read_count[:-1])
        refill_buf.CE @= m.enable(self.io.nasti.r.fired())

        is_idle = state.O == State.IDLE
        is_read = state.O == State.READ_CACHE
        is_write = state.O == State.WRITE_CACHE
        is_alloc = (state.O == State.REFILL) & read_wrap_out
        # m.display("[%0t]: is_alloc = %x", m.time(), is_alloc)\
        #     .when(m.posedge(self.io.CLK))
        is_alloc_reg = m.Register(m.Bit)()(is_alloc)

        hit = m.Bit(name="hit")
        wen = is_write & (hit | is_alloc_reg) & ~self.io.cpu.abort | is_alloc
        # m.display("[%0t]: wen = %x", m.time(), wen)\
        #     .when(m.posedge(self.io.CLK))
        ren = m.enable(~wen & (is_idle | is_read) & self.io.cpu.req.valid)
        ren_reg = m.enable(m.Register(m.Bit)()(ren))

        addr = self.io.cpu.req.data.addr
        idx = addr[b_len:s_len + b_len]
        tag_reg = addr_reg.O[s_len + b_len:x_len]
        idx_reg = addr_reg.O[b_len:s_len + b_len]
        off_reg = addr_reg.O[byte_offset_bits:b_len]

        rmeta = meta_mem.read(idx, ren)
        rdata = m.concat(*(mem.read(idx, ren) for mem in data_mem))
        rdata_buf = m.Register(type(rdata), has_enable=True)()(rdata,
                                                               CE=ren_reg)

        read = m.mux([
            m.as_bits(m.mux([rdata_buf, rdata], ren_reg)),
            m.as_bits(refill_buf.O)
        ], is_alloc_reg)
        # m.display("is_alloc_reg=%x", is_alloc_reg)\
        #     .when(m.posedge(self.io.CLK))

        hit @= v.O[idx_reg] & (rmeta.tag == tag_reg)

        # read mux
        self.io.cpu.resp.data.data @= m.array(
            [read[i * x_len:(i + 1) * x_len] for i in range(n_words)])[off_reg]
        self.io.cpu.resp.valid @= (is_idle | (is_read & hit) |
                                   (is_alloc_reg & ~cpu_mask.O.reduce_or()))
        m.display("resp.valid=%x", self.io.cpu.resp.valid.value())\
            .when(m.posedge(self.io.CLK))
        m.display("[%0t]: valid = %x", m.time(),
                  self.io.cpu.resp.valid.value())\
            .when(m.posedge(self.io.CLK))
        m.display("[%0t]: is_idle = %x, is_read = %x, hit = %x, is_alloc_reg = "
                  "%x, ~cpu_mask.O.reduce_or() = %x", m.time(), is_idle,
                  is_read, hit, is_alloc_reg, ~cpu_mask.O.reduce_or())\
            .when(m.posedge(self.io.CLK))
        m.display("[%0t]: refill_buf.O=%x, %x", m.time(), *refill_buf.O)\
            .when(m.posedge(self.io.CLK))\
            .if_(self.io.cpu.resp.valid.value() & is_alloc_reg)
        m.display("[%0t]: read=%x", m.time(), read)\
            .when(m.posedge(self.io.CLK))\
            .if_(self.io.cpu.resp.valid.value() & is_alloc_reg)

        addr_reg.I @= addr
        addr_reg.CE @= m.enable(self.io.cpu.resp.valid.value())

        cpu_data.I @= self.io.cpu.req.data.data
        cpu_data.CE @= m.enable(self.io.cpu.resp.valid.value())

        cpu_mask.I @= self.io.cpu.req.data.mask
        cpu_mask.CE @= m.enable(self.io.cpu.resp.valid.value())

        wmeta = MetaData(name="wmeta")
        wmeta.tag @= tag_reg

        offset_mask = (m.zext_to(cpu_mask.O, w_bytes * 8) << m.concat(
            m.bits(0, byte_offset_bits), off_reg))
        wmask = m.mux([m.SInt[w_bytes * 8](-1),
                       m.sint(offset_mask)], ~is_alloc)

        if len(refill_buf.O) == 1:
            wdata_alloc = self.io.nasti.r.data.data
        else:
            wdata_alloc = m.concat(
                # TODO: not sure why they use `init.reverse`
                # https://github.com/ucb-bar/riscv-mini/blob/release/src/main/scala/Cache.scala#L116
                m.concat(*refill_buf.O[:-1]),
                self.io.nasti.r.data.data)
        wdata = m.mux([wdata_alloc,
                       m.as_bits(m.repeat(cpu_data.O, n_words))], ~is_alloc)

        v.I @= m.set_index(v.O, m.bit(True), idx_reg)
        v.CE @= m.enable(wen)
        d.I @= m.set_index(d.O, ~is_alloc, idx_reg)
        d.CE @= m.enable(wen)
        # m.display("[%0t]: refill_buf.O = %x", m.time(),
        #           m.concat(*refill_buf.O)).when(m.posedge(self.io.CLK)).if_(wen)
        # m.display("[%0t]: nasti.r.data.data = %x", m.time(),
        #           self.io.nasti.r.data.data).when(m.posedge(self.io.CLK)).if_(wen)

        meta_mem.write(wmeta, idx_reg, m.enable(wen & is_alloc))
        for i, mem in enumerate(data_mem):
            data = [
                wdata[i * x_len + j * 8:i * x_len + (j + 1) * 8]
                for j in range(w_bytes)
            ]
            mem.write(m.array(data), idx_reg,
                      wmask[i * w_bytes:(i + 1) * w_bytes], m.enable(wen))
            # m.display("[%0t]: wdata = %x, %x, %x, %x", m.time(),
            #           *mem.WDATA.value()).when(m.posedge(self.io.CLK)).if_(wen)
            # m.display("[%0t]: wmask = %x, %x, %x, %x", m.time(),
            #           *mem.WMASK.value()).when(m.posedge(self.io.CLK)).if_(wen)

        tag_and_idx = m.zext_to(m.concat(idx_reg, tag_reg),
                                nasti_params.x_addr_bits)
        self.io.nasti.ar.data @= NastiReadAddressChannel(
            nasti_params, 0, tag_and_idx << m.Bits[len(tag_and_idx)](b_len),
            m.bitutils.clog2(nasti_params.x_data_bits // 8), data_beats - 1)

        rmeta_and_idx = m.zext_to(m.concat(idx_reg, rmeta.tag),
                                  nasti_params.x_addr_bits)
        self.io.nasti.aw.data @= NastiWriteAddressChannel(
            nasti_params, 0,
            rmeta_and_idx << m.Bits[len(rmeta_and_idx)](b_len),
            m.bitutils.clog2(nasti_params.x_data_bits // 8), data_beats - 1)

        self.io.nasti.w.data @= NastiWriteDataChannel(
            nasti_params,
            m.array([
                read[i * nasti_params.x_data_bits:(i + 1) *
                     nasti_params.x_data_bits] for i in range(data_beats)
            ])[write_count[:-1]], None, write_wrap_out)

        is_dirty = v.O[idx_reg] & d.O[idx_reg]

        # TODO: Have to use temporary so we can invoke `fired()`
        aw_valid = m.Bit(name="aw_valid")
        self.io.nasti.aw.valid @= aw_valid

        ar_valid = m.Bit(name="ar_valid")
        self.io.nasti.ar.valid @= ar_valid

        b_ready = m.Bit(name="b_ready")
        self.io.nasti.b.ready @= b_ready

        @m.inline_combinational()
        def logic():
            state.I @= state.O
            aw_valid @= False
            ar_valid @= False
            self.io.nasti.w.valid @= False
            b_ready @= False
            if state.O == State.IDLE:
                if self.io.cpu.req.valid:
                    if self.io.cpu.req.data.mask.reduce_or():
                        state.I @= State.WRITE_CACHE
                    else:
                        state.I @= State.READ_CACHE
            elif state.O == State.READ_CACHE:
                if hit:
                    if self.io.cpu.req.valid:
                        if self.io.cpu.req.data.mask.reduce_or():
                            state.I @= State.WRITE_CACHE
                        else:
                            state.I @= State.READ_CACHE
                    else:
                        state.I @= State.IDLE
                else:
                    aw_valid @= is_dirty
                    ar_valid @= ~is_dirty
                    if self.io.nasti.aw.fired():
                        state.I @= State.WRITE_BACK
                    elif self.io.nasti.ar.fired():
                        state.I @= State.REFILL
            elif state.O == State.WRITE_CACHE:
                if hit | is_alloc_reg | self.io.cpu.abort:
                    state.I @= State.IDLE
                else:
                    aw_valid @= is_dirty
                    ar_valid @= ~is_dirty
                    if self.io.nasti.aw.fired():
                        state.I @= State.WRITE_BACK
                    elif self.io.nasti.ar.fired():
                        state.I @= State.REFILL
            elif state.O == State.WRITE_BACK:
                self.io.nasti.w.valid @= True
                if write_wrap_out:
                    state.I @= State.WRITE_ACK
            elif state.O == State.WRITE_ACK:
                b_ready @= True
                if self.io.nasti.b.fired():
                    state.I @= State.REFILL_READY
            elif state.O == State.REFILL_READY:
                ar_valid @= True
                if self.io.nasti.ar.fired():
                    state.I @= State.REFILL
            elif state.O == State.REFILL:
                if read_wrap_out:
                    if cpu_mask.O.reduce_or():
                        state.I @= State.WRITE_CACHE
                    else:
                        state.I @= State.IDLE

        if data_beats > 1:
            # TODO: Have to do this at the end since the inline comb logic
            # wires up nasti.w
            write_counter.CE @= m.enable(self.io.nasti.w.fired())
Beispiel #16
0
from magma import sint, bits, concat, wire, compile, EndCircuit
from mantle import SLE
from loam.boards.icestick import IceStick

icestick = IceStick()
for i in range(4):
    icestick.J1[i].input().on()
icestick.D1.on()

main = icestick.main()
A = sint(concat(main.J1[0:2], bits(0, 6)))
B = sint(concat(main.J1[2:4], bits(0, 6)))
O = main.D1

sle = SLE(8)
wire(sle(A, B), main.D1)

EndCircuit()
Beispiel #17
0
    def __init__(self,
                 x_len,
                 ALU=ALUArea,
                 ImmGen=ImmGenWire,
                 BrCond=BrCondArea):
        self.io = make_DatapathIO(x_len) + m.ClockIO(has_reset=True)
        csr = CSRGen(x_len)()
        reg_file = RegFile(x_len)()
        alu = ALU(x_len)()
        imm_gen = ImmGen(x_len)()
        br_cond = BrCondArea(x_len)()

        # Fetch / Execute Registers
        fe_inst = m.Register(init=Instructions.NOP, has_enable=True)()
        fe_pc = m.Register(m.UInt[x_len], has_enable=True)()

        # Execute / Write Back Registers
        ew_inst = m.Register(init=Instructions.NOP)()
        ew_pc = m.Register(m.UInt[x_len])()
        ew_alu = m.Register(m.UInt[x_len])()
        csr_in = m.Register(m.UInt[x_len])()

        # Control signals
        st_type = m.Register(type(self.io.ctrl.st_type).undirected_t)()
        ld_type = m.Register(type(self.io.ctrl.ld_type).undirected_t)()
        wb_sel = m.Register(type(self.io.ctrl.wb_sel).undirected_t)()
        wb_en = m.Register(m.Bit)()
        csr_cmd = m.Register(type(self.io.ctrl.csr_cmd).undirected_t)()
        illegal = m.Register(m.Bit)()
        pc_check = m.Register(m.Bit)()

        # Fetch
        started = m.Register(m.Bit)()(m.bit(self.io.RESET))
        stall = ~self.io.icache.resp.valid | ~self.io.dcache.resp.valid
        pc = m.Register(init=UIntVector[x_len](Const.PC_START) -
                        UIntVector[x_len](4))()
        npc = m.mux([
            m.mux([
                m.mux([
                    m.mux([
                        m.mux([pc.O + m.uint(4, x_len), pc.O],
                              self.io.ctrl.pc_sel == PC_0), alu.sum_ >> 1 << 1
                    ], (self.io.ctrl.pc_sel == PC_ALU) | br_cond.taken),
                    csr.epc
                ], self.io.ctrl.pc_sel == PC_EPC), csr.evec
            ], csr.expt), pc.O
        ], stall)

        inst = m.mux([self.io.icache.resp.data.data, Instructions.NOP], started
                     | self.io.ctrl.inst_kill | br_cond.taken | csr.expt)

        pc.I @= npc
        self.io.icache.req.data.addr @= npc
        self.io.icache.req.data.data @= 0
        self.io.icache.req.data.mask @= 0
        self.io.icache.req.valid @= ~stall
        self.io.icache.abort @= False

        fe_pc.I @= pc.O
        fe_pc.CE @= m.enable(~stall)
        fe_inst.I @= inst
        fe_inst.CE @= m.enable(~stall)

        # Execute
        # Decode
        self.io.ctrl.inst @= fe_inst.O

        # reg_file read
        rs1_addr = fe_inst.O[15:20]
        rs2_addr = fe_inst.O[20:25]
        reg_file.raddr1 @= rs1_addr
        reg_file.raddr2 @= rs2_addr

        # gen immediates
        imm_gen.inst @= fe_inst.O
        imm_gen.sel @= self.io.ctrl.imm_sel

        # bypass
        wb_rd_addr = ew_inst.O[7:12]
        rs1_hazard = wb_en.O & rs1_addr.reduce_or() & (rs1_addr == wb_rd_addr)
        rs2_hazard = wb_en.O & rs2_addr.reduce_or() & (rs2_addr == wb_rd_addr)
        rs1 = m.mux([reg_file.rdata1, ew_alu.O],
                    (wb_sel.O == WB_ALU) & rs1_hazard)
        rs2 = m.mux([reg_file.rdata2, ew_alu.O],
                    (wb_sel.O == WB_ALU) & rs2_hazard)

        # ALU operations
        alu.A @= m.mux([fe_pc.O, rs1], self.io.ctrl.A_sel == A_RS1)
        alu.B @= m.mux([imm_gen.O, rs2], self.io.ctrl.B_sel == B_RS2)
        alu.op @= self.io.ctrl.alu_op

        # Branch condition calc
        br_cond.rs1 @= rs1
        br_cond.rs2 @= rs2
        br_cond.br_type @= self.io.ctrl.br_type

        # D$ access
        daddr = m.mux([alu.sum_, ew_alu.O], stall) >> 2 << 2
        w_offset = ((m.bits(alu.sum_[1], x_len) << 4) |
                    (m.bits(alu.sum_[0], x_len) << 3))
        self.io.dcache.req.valid @= ~stall & (self.io.ctrl.st_type.reduce_or()
                                              |
                                              self.io.ctrl.ld_type.reduce_or())
        self.io.dcache.req.data.addr @= daddr
        self.io.dcache.req.data.data @= rs2 << w_offset
        self.io.dcache.req.data.mask @= m.dict_lookup(
            {
                ST_SW: m.bits(0b1111, 4),
                ST_SH: m.bits(0b11, 4) << m.zext(alu.sum_[0:2], 2),
                ST_SB: m.bits(0b1, 4) << m.zext(alu.sum_[0:2], 2),
            }, m.mux([self.io.ctrl.st_type, st_type.O], stall), m.bits(0, 4))

        # Pipelining
        @m.inline_combinational()
        def pipeline_logic():
            ew_pc.I @= ew_pc.O
            ew_inst.I @= ew_inst.O
            ew_alu.I @= ew_alu.O
            csr_in.I @= csr_in.O
            st_type.I @= st_type.O
            ld_type.I @= ld_type.O
            wb_sel.I @= wb_sel.O
            wb_en.I @= wb_en.O
            csr_cmd.I @= csr_cmd.O
            illegal.I @= illegal.O
            pc_check.I @= pc_check.O
            if m.bit(self.io.RESET) | ~stall & csr.expt:
                st_type.I @= 0
                ld_type.I @= 0
                wb_en.I @= 0
                csr_cmd.I @= 0
                illegal.I @= False
                pc_check.I @= False
            elif ~stall & ~csr.expt:
                ew_pc.I @= fe_pc.O
                ew_inst.I @= fe_inst.O
                ew_alu.I @= alu.O
                csr_in.I @= m.mux([rs1, imm_gen.O],
                                  self.io.ctrl.imm_sel == IMM_Z)
                st_type.I @= self.io.ctrl.st_type
                ld_type.I @= self.io.ctrl.ld_type
                wb_sel.I @= self.io.ctrl.wb_sel
                wb_en.I @= self.io.ctrl.wb_en
                csr_cmd.I @= self.io.ctrl.csr_cmd
                illegal.I @= self.io.ctrl.illegal
                pc_check.I @= self.io.ctrl.pc_sel == PC_ALU

        # Load
        l_offset = ((m.uint(ew_alu.O[1], x_len) << 4) |
                    (m.uint(ew_alu.O[0], x_len) << 3))
        l_shift = self.io.dcache.resp.data.data >> l_offset
        load = m.dict_lookup(
            {
                LD_LH: m.sext_to(m.sint(l_shift[0:16]), x_len),
                LD_LHU: m.sint(m.zext_to(l_shift[0:16], x_len)),
                LD_LB: m.sext_to(m.sint(l_shift[0:8]), x_len),
                LD_LBU: m.sint(m.zext_to(l_shift[0:8], x_len))
            }, ld_type.O, m.sint(self.io.dcache.resp.data.data))

        # CSR access
        csr.stall @= stall
        csr.I @= csr_in.O
        csr.cmd @= csr_cmd.O
        csr.inst @= ew_inst.O
        csr.pc @= ew_pc.O
        csr.addr @= ew_alu.O
        csr.illegal @= illegal.O
        csr.pc_check @= pc_check.O
        csr.ld_type @= ld_type.O
        csr.st_type @= st_type.O
        self.io.host @= csr.host

        # Regfile write
        reg_write = m.dict_lookup(
            {
                WB_MEM: m.uint(load),
                WB_PC4: (ew_pc.O + 4),
                WB_CSR: csr.O
            }, wb_sel.O, ew_alu.O)

        reg_file.wen @= m.enable(wb_en.O & ~stall & ~csr.expt)
        reg_file.waddr @= wb_rd_addr
        reg_file.wdata @= reg_write

        # Abort store when there's an exception
        self.io.dcache.abort @= csr.expt
Beispiel #18
0
def test_sint():
    assert isinstance(sint(1, 4), SIntType)
    assert isinstance(sint([1, 0, 0, 0]), SIntType)
    assert isinstance(sint(VCC), SIntType)
    assert isinstance(sint(array(1, 4)), SIntType)
    assert isinstance(sint(bits(1, 4)), SIntType)