def test_flip(): """ Test flip interface """ bits_2 = m.Bits[2] a_in = m.In(bits_2) a_out = m.Out(bits_2) print(a_in) print(a_out) assert a_in != ARRAY2 assert a_out != ARRAY2 assert a_in != a_out in_a_out = m.In(a_out) assert in_a_out == a_in print(in_a_out) a_out_flipped = m.Flip(a_out) assert a_out_flipped == a_in out_a_in = m.Out(a_in) assert out_a_in == a_out a_in_flipped = m.Flip(a_in) assert a_in_flipped == a_out print(a_in_flipped)
def make_DatapathIO(x_len): control_decl = make_ControlIO(x_len).decl() control_ports = { k: v for k, v in zip(control_decl[::2], control_decl[1::2]) } return m.IO(host=make_HostIO(x_len), icache=m.Flip(make_CacheIO(x_len)), dcache=m.Flip(make_CacheIO(x_len)), ctrl=m.Flip(m.Product.from_fields("ControlIO", control_ports)))
def __init__(self, x_len: int, data_path_kwargs=None, control_kwargs=None): self.io = m.IO( host=make_HostIO(x_len), icache=m.Flip(make_CacheIO(x_len)), dcache=m.Flip(make_CacheIO(x_len)), ) + m.ClockIO(has_reset=True) if data_path_kwargs is None: data_path_kwargs = m.generator.ParamDict() if control_kwargs is None: control_kwargs = m.generator.ParamDict() data_path = Datapath(x_len, **data_path_kwargs)() control = Control(x_len, **control_kwargs)() m.wire(self.io.host, data_path.host) m.wire(data_path.icache, self.io.icache) m.wire(data_path.dcache, self.io.dcache) for name, value in data_path.ctrl.items(): m.wire(value, getattr(control, name))
def test_val(): """ Test instances of Bits[4] work correctly """ bits_4_in = m.In(m.Bits[4]) bits_4_out = m.Out(m.Bits[4]) assert m.Flip(bits_4_in) == bits_4_out assert m.Flip(bits_4_out) == bits_4_in a_0 = bits_4_out(name='a0') print(a_0) a_1 = bits_4_in(name='a1') print(a_1) a_1.wire(a_0) b_0 = a_1[0] assert b_0 is a_1[0], "getitem failed" a_3 = a_1[0:2] assert a_3 == a_1[0:2], "getitem of slice failed"
def WrapInst(inst): # assert? # add support tuples name = inst.name + 'Wrapped' args = [] wrapped = {} # find all array index arguments (i.e. I0_1_0) for io in inst.IO: argtype = inst.IO.__getitem__(inst.IO, io) if '_' in io: arg = io[:io.find('_')] indices = list(map(int, io[io.find('_') + 1:].split('_'))) if arg not in wrapped: wrapped[arg] = [indices, argtype] else: for i in range(len(indices)): if indices[i] > wrapped[arg][0][i]: wrapped[arg][0][i] = indices[i] else: args += [io, argtype] # add them back as complete arrays for arg in wrapped.keys(): port = wrap(wrapped[arg][0], wrapped[arg][1]) args += [arg, port] new_circuit = {} for i in range(0, len(args), 2): new_circuit[args[i]] = m.Flip(args[i + 1])() # wire original circuit to wrapped version for io in inst.IO: argtype = inst.IO.__getitem__(inst.IO, io) if '_' in io: arg = io[:io.find('_')] indices = list(map(int, io[io.find('_') + 1:].split('_'))) m.wire(getattr(inst, io), nest(new_circuit[arg], indices)) else: m.wire(getattr(inst, io), new_circuit[io]) IO = [] for key, value in new_circuit.items(): IO.extend([key, value]) return m.AnonymousCircuit(*IO)
def wrap_with_disassembler(PE, disassembler, width, layout, inst_type): WrappedIO = [] for key, value in PE.interface.ports.items(): WrappedIO.append(key) if type(value) == m.Out(inst_type): WrappedIO.append(m.In(m.Bits[width])) else: WrappedIO.append(m.Flip(type(value))) def wire_inst_fields(wrapper_inst, pe_inst, layout): if isinstance(wrapper_inst, m.Product): for key, value in layout.items(): begin = value[0] end = value[1] wire_inst_fields(wrapper_inst[begin:end], getattr(pe_inst, key), value[2]) else: for key, value in layout.items(): begin = value[0] end = value[1] region = wrapper_inst[begin:end] field = getattr(pe_inst, key) if isinstance(type(field), m._BitKind): region = m.bit(region) m.wire(region, field) class WrappedPE(m.Circuit): IO = WrappedIO @classmethod def definition(io): pe = PE() for key, value in PE.interface.ports.items(): if type(value) == m.Out(inst_type): wire_inst_fields(getattr(io, key), getattr(pe, key), layout) elif value.isoutput(): getattr(pe, key) <= getattr(io, key) else: getattr(io, key) <= getattr(pe, key) return WrappedPE
def wrap_with_disassembler(PE, disassembler, width, layout, inst_type): WrappedIO = OrderedDict() for key, value in PE.interface.ports.items(): if isinstance(value, m.Out(inst_type)): vtype = m.In(m.Bits[width]) else: vtype = m.Flip(type(value)) WrappedIO[key] = vtype def wire_inst_fields(wrapper_inst, pe_inst, layout): if isinstance(wrapper_inst, m.Product): for key, value in layout.items(): begin = value[0] end = value[1] wire_inst_fields(wrapper_inst[begin:end], getattr(pe_inst, key), value[2]) else: for key, value in layout.items(): begin = value[0] end = value[1] region = wrapper_inst[begin:end] field = getattr(pe_inst, key) if issubclass(type(field), m.Digital): region = m.bit(region) m.wire(region, field) class WrappedPE(m.Circuit): io = m.IO(**WrappedIO) pe = PE() for key, value in PE.interface.ports.items(): if type(value) == m.Out(inst_type): wire_inst_fields(getattr(io, key), getattr(pe, key), layout) elif value.is_output(): m.wire(getattr(pe, key), getattr(io, key)) else: m.wire(getattr(io, key), getattr(pe, key)) return WrappedPE
def __init__(self, x_len): nasti_params = NastiParameters(data_bits=64, addr_bits=x_len, id_bits=5) self.io = m.IO( icache=m.Flip(make_NastiIO(nasti_params)), dcache=m.Flip(make_NastiIO(nasti_params)), nasti=make_NastiIO(nasti_params)) + m.ClockIO(has_reset=True) class State(m.Enum): IDLE = 0 ICACHE_READ = 1 DCACHE_READ = 2 DCACHE_WRITE = 3 DCACHE_ACK = 4 state = m.Register(init=State.IDLE)() # write address self.io.nasti.aw.data @= self.io.dcache.aw.data self.io.nasti.aw.valid @= (self.io.dcache.aw.valid & (state.O == State.IDLE)) self.io.dcache.aw.ready @= (self.io.nasti.aw.ready & (state.O == State.IDLE)) self.io.icache.aw.ready @= 0 # write data self.io.nasti.w.data @= self.io.dcache.w.data self.io.nasti.w.valid @= (self.io.dcache.w.valid & (state.O == State.DCACHE_WRITE)) self.io.dcache.w.ready @= (self.io.nasti.w.ready & (state.O == State.DCACHE_WRITE)) self.io.icache.w.ready @= 0 # write ack self.io.dcache.b.data @= self.io.nasti.b.data self.io.dcache.b.valid @= (self.io.nasti.b.valid & (state.O == State.DCACHE_ACK)) self.io.nasti.b.ready @= (self.io.dcache.b.ready & (state.O == State.DCACHE_ACK)) self.io.icache.b.valid @= 0 self.io.icache.b.data.resp @= 0 self.io.icache.b.data.id @= 0 self.io.icache.b.data.user @= 0 # read address self.io.nasti.ar.data @= NastiReadAddressChannel( nasti_params, m.mux([self.io.icache.ar.data.id, self.io.dcache.ar.data.id], self.io.dcache.ar.valid), m.mux([self.io.icache.ar.data.addr, self.io.dcache.ar.data.addr], self.io.dcache.ar.valid), m.mux([self.io.icache.ar.data.size, self.io.dcache.ar.data.size], self.io.dcache.ar.valid), m.mux( [self.io.icache.ar.data.length, self.io.dcache.ar.data.length], self.io.dcache.ar.valid), ) self.io.nasti.ar.valid @= ( (self.io.icache.ar.valid | self.io.dcache.ar.valid) & ~self.io.nasti.aw.valid.value() & (state.O == State.IDLE)) self.io.dcache.ar.ready @= (self.io.nasti.ar.ready & ~self.io.nasti.aw.valid.value() & (state.O == State.IDLE)) self.io.icache.ar.ready @= (self.io.dcache.ar.ready.value() & ~self.io.dcache.ar.valid) # read data self.io.icache.r.data @= self.io.nasti.r.data self.io.dcache.r.data @= self.io.nasti.r.data self.io.icache.r.valid @= (self.io.nasti.r.valid & (state.O == State.ICACHE_READ)) self.io.dcache.r.valid @= (self.io.nasti.r.valid & (state.O == State.DCACHE_READ)) self.io.nasti.r.ready @= ((self.io.icache.r.ready & (state.O == State.ICACHE_READ)) | (self.io.dcache.r.ready & (state.O == State.DCACHE_READ))) @m.inline_combinational() def logic(): state.I @= state.O if state.O == State.IDLE: if (self.io.dcache.aw.valid & self.io.dcache.aw.ready.value()): state.I @= State.DCACHE_WRITE elif (self.io.dcache.ar.valid & self.io.dcache.ar.ready.value()): state.I @= State.DCACHE_READ elif (self.io.icache.ar.valid & self.io.icache.ar.ready.value()): state.I @= State.ICACHE_READ elif state.O == State.ICACHE_READ: if self.io.nasti.r.fired() & self.io.nasti.r.data.last: state.I @= State.IDLE elif state.O == State.DCACHE_READ: if self.io.nasti.r.fired() & self.io.nasti.r.data.last: state.I @= State.IDLE elif state.O == State.DCACHE_WRITE: if (self.io.dcache.w.valid & self.io.dcache.w.ready.value() & self.io.dcache.w.data.last): state.I @= State.DCACHE_ACK elif state.O == State.DCACHE_ACK: if self.io.nasti.b.fired(): state.I @= State.IDLE
def make_HandshakeData(data_type): in_type = m.Tuple(data=m.In(data_type), valid=m.In(m.Bit), ready=m.Out(m.Bit)) out_type = m.Flip(in_type) return in_type, out_type