def definition(io): PSEL = getattr(io.apb, f"PSEL{apb_slave_id}") registers = [ mantle.Register(data_width, init=reg.init, has_ce=True, has_reset=True, name=reg.name) for reg in reg_list ] is_write = io.apb.PENABLE & io.apb.PWRITE & PSEL ready = None for i, reg in enumerate(registers): reg.I <= mantle.mux( [getattr(io, reg.name + "_d"), io.apb.PWDATA], is_write) getattr(io, reg.name + "_q") <= reg.O reg.CLK <= io.apb.PCLK reg.RESET <= ~m.bit(io.apb.PRESETn) ce = is_write & (io.apb.PADDR == i) if reg_list[i].has_ce: reg.CE <= ce | m.bit(getattr(io, reg.name + "_en")) else: reg.CE <= ce if ready is not None: ready |= ce else: ready = ce is_read = io.apb.PENABLE & ~io.apb.PWRITE & PSEL io.apb.PREADY <= ready | is_read io.apb.PRDATA <= mantle.mux([reg.O for reg in registers], io.apb.PADDR) io.apb.PSLVERR <= 0 # Unused CorebitTerm().I <= io.apb.PPROT Term(len(io.apb.PSTRB)).I <= io.apb.PSTRB
def definition(io): reg = DefineCoreirReg(n, init, has_async_reset, _type)() I = io.I if has_reset: I = mantle.mux([io.I, m.bits(init, n)], io.RESET) if has_ce: I = mantle.mux([reg.O, I], io.CE) m.wire(I, reg.I) m.wire(io.O, reg.O)
def __init__(self, regs, data_width, apb_slave_id=0): #起名,用到regs的信息 self.name = "RegFile_" + "_".join(reg.name for reg in regs) self.io = io = make_reg_file_interface(regs, data_width, apb_slave_id) for name, port in io.ports.items(): print(f"port_name = \"{name}\"") print(f"port_type = ", end="") m.util.pretty_print_type(type(port)) print() PSEL = getattr(io.apb, f"PSEL{apb_slave_id}") #这里又用了mantle.Register,这个东西能声明成design内部的reg,有五个signal,I,O,CLK,CE,RESET #所以有了后面的reg.I怎么怎么样 registers = [ mantle.Register(data_width, init=reg.init, has_ce=True, has_reset=True, name=reg.name) for reg in regs ] #is_write应该是一个内部的状态 is_write = io.apb.PENABLE & io.apb.PWRITE & PSEL ready = None for i, reg in enumerate(registers): reg.I @= mantle.mux([getattr(io, reg.name + "_d"), io.apb.PWDATA], is_write) getattr(io, reg.name + "_q") <= reg.O reg.CLK @= io.apb.PCLK reg.RESET @= ~m.bit(io.apb.PRESETn) ce = is_write & (io.apb.PADDR == i) if regs[i].has_ce: reg.CE @= ce | m.bit(getattr(io, reg.name + "_en")) else: reg.CE @= ce if ready is not None: ready |= ce else: ready = ce is_read = io.apb.PENABLE & ~io.apb.PWRITE & PSEL io.apb.PREADY @= ready | is_read io.apb.PRDATA @= mantle.mux([reg.O for reg in registers], io.apb.PADDR) io.apb.PSLVERR.undriven() io.apb.PPROT.unused() io.apb.PSTRB.unused()
def __init__(self, ARES_design_type, depth): #这个self.name 和self.io必须得有 #self.name = "ARES_FIFO_DESIGN" self.io = io = m.IO(ARES_design = ARES_design_type) #io += m.ClockIO() addr_width = m.bitutils.clog2(depth) print ("ARES addr width : " + str(addr_width) ) buffer = mantle.RAM(2**addr_width, io.ARES_design.WData.flat_length()) buffer.WDATA @= m.as_bits(io.ARES_design.WData) io.ARES_design.RData @= buffer.RDATA read_pointer = mantle.Register(addr_width + 1) write_pointer = mantle.Register(addr_width + 1) buffer.RADDR @= read_pointer.O[:addr_width] buffer.WADDR @= write_pointer.O[:addr_width] reset = io.ARES_design.RESET full = \ (read_pointer.O[:addr_width] == write_pointer.O[:addr_width]) \ & \ (read_pointer.O[addr_width] != write_pointer.O[addr_width]) empty = read_pointer.O == write_pointer.O write_valid = io.ARES_design.Write & ~full read_valid = io.ARES_design.Read & ~empty io.ARES_design.Full @= full buffer.WE @= write_valid write_p = mantle.mux([ write_pointer.O, m.uint(write_pointer.O) + 1 ], write_valid) write_pointer.I @= mantle.mux([ write_p, 0 ], reset) io.ARES_design.Empty @= empty read_p = mantle.mux([ read_pointer.O, m.uint(read_pointer.O) + 1 ], read_valid) read_pointer.I @= mantle.mux([ read_p, 0 ], reset)
def definition(io): opcode = ConfigReg(name="config_reg")(io.config_data, CE=io.config_en) io.c <= mantle.mux( # udiv not implemented # [io.a + io.b, io.a - io.b, io.a * io.b, io.a / io.b], opcode) # use arbitrary fourth op [io.a + io.b, io.a - io.b, io.a * io.b, io.b - io.a], opcode)
class FIFO(m.Circuit): io = m.IO(ARES_design = ARES_design_type) #io += m.ClockIO() addr_width = m.bitutils.clog2(depth) buffer = mantle.RAM(2**addr_width, io.ARES_design.WData.flat_length()) buffer.WDATA @= m.as_bits(io.ARES_design.WData) io.ARES_design.RData @= buffer.RDATA read_pointer = mantle.Register(addr_width + 1) write_pointer = mantle.Register(addr_width + 1) buffer.RADDR @= read_pointer.O[:addr_width] buffer.WADDR @= write_pointer.O[:addr_width] reset = io.ARES_design.RESET full = \ (read_pointer.O[:addr_width] == write_pointer.O[:addr_width]) \ & \ (read_pointer.O[addr_width] != write_pointer.O[addr_width]) empty = read_pointer.O == write_pointer.O write_valid = io.ARES_design.Write & ~full read_valid = io.ARES_design.Read & ~empty io.ARES_design.Full @= full buffer.WE @= write_valid write_p = mantle.mux([ write_pointer.O, m.uint(write_pointer.O) + 1 ], write_valid) write_pointer.I @= mantle.mux([ write_p, 0 ], reset) io.ARES_design.Empty @= empty read_p = mantle.mux([ read_pointer.O, m.uint(read_pointer.O) + 1 ], read_valid) read_pointer.I @= mantle.mux([ read_p, 0 ], reset)
def definition(io): regs = [ mantle.Register(data_width, init=int(init[i])) for i in range(1 << addr_width) ] for reg in regs: reg.I <= reg.O io.RDATA <= mantle.mux([reg.O for reg in regs], io.RADDR)
def generate_mux(inputs, sel, default=None): if default is None: height = len(inputs) mux_inputs = [i for i in inputs] else: height = 2**m.bitutils.clog2(len(inputs)) mux_inputs = [i for i in inputs] mux_inputs += [default for _ in range(height - len(inputs))] return mantle.mux(mux_inputs, sel)
def definition(io): regs = [ mantle.Register(data_width, init=int(init[i]), has_ce=True, has_reset=True) for i in range(1 << addr_width) ] for i, reg in enumerate(regs): reg.I <= io.WDATA reg.CE <= (io.WADDR == m.bits(i, addr_width)) & io.WE io.RDATA <= mantle.mux([reg.O for reg in regs], io.RADDR)
class SimpleALU(m.Circuit): io = m.IO(a=m.In(m.UInt[16]), b=m.In(m.UInt[16]), c=m.Out(m.UInt[16]), config_data=m.In(m.Bits[2]), config_en=m.In(m.Enable), ) + m.ClockIO() opcode = ConfigReg(name="config_reg")(io.config_data, CE=io.config_en) io.c @= mantle.mux( [io.a + io.b, io.a - io.b, io.a * io.b, io.a ^ io.b], opcode)
class ROM(m.Circuit): io = m.IO( RADDR=m.In(m.Bits[addr_width]), RDATA=m.Out(m.Bits[data_width]), CLK=m.In(m.Clock) ) regs = [mantle.Register(data_width, init=int(init[i])) for i in range(1 << addr_width)] for reg in regs: reg.I <= reg.O io.RDATA <= mantle.mux([reg.O for reg in regs], io.RADDR)
class Register(m.Circuit): name = f"Register_has_ce_{has_ce}_has_reset_{has_reset}_" \ f"has_async_reset_{has_async_reset}_" \ f"has_async_resetn_{has_async_resetn}_" \ f"type_{_type.__name__}_n_{n}" io = m.IO(I=m.In(T), O=m.Out(T)) io += m.ClockIO(has_ce=has_ce, has_reset=has_reset, has_async_reset=has_async_reset, has_async_resetn=has_async_resetn) reg = DefineCoreirReg(n, init, has_async_reset, has_async_resetn, _type)(name="value") I = io.I O = reg.O if n is None: O = O[0] if has_reset and has_ce: if reset_priority: I = mantle.mux([O, I], io.CE, name="enable_mux") I = mantle.mux([I, m.bits(init, n)], io.RESET) else: I = mantle.mux([I, m.bits(init, n)], io.RESET) I = mantle.mux([O, I], io.CE, name="enable_mux") elif has_ce: I = mantle.mux([O, I], io.CE, name="enable_mux") elif has_reset: I = mantle.mux([I, m.bits(init, n)], io.RESET) if n is None: m.wire(I, reg.I[0]) else: m.wire(I, reg.I) m.wire(io.O, O)
def definition(io): addr_width = m.bitutils.clog2(depth) buffer = mantle.RAM(addr_width, flat_length(io.data_in.data)) # pack data into bits buffer.WDATA <= flatten_fields_to_bits(io.data_in.data) # unpack bits into tuple io.data_out.data <= unflatten_bits_to_fields( io.data_out.data, buffer.RDATA) read_pointer = mantle.Register(addr_width + 1) write_pointer = mantle.Register(addr_width + 1) buffer.RADDR <= read_pointer.O[:addr_width] buffer.WADDR <= write_pointer.O[:addr_width] full = \ (read_pointer.O[:addr_width] == write_pointer.O[:addr_width]) \ & \ (read_pointer.O[addr_width] != write_pointer.O[addr_width]) empty = read_pointer == write_pointer write_valid = io.data_in.valid & ~full read_valid = io.data_out.ready & ~empty io.data_in.ready <= ~full buffer.WE <= write_valid write_pointer.I <= mantle.mux( [write_pointer.O, m.uint(write_pointer.O) + 1], write_valid) io.data_out.valid <= read_valid read_pointer.I <= mantle.mux( [read_pointer.O, m.uint(read_pointer.O) + 1], read_valid)
class SimpleALU(m.Circuit): io = m.IO( a=m.In(m.UInt[16]), b=m.In(m.UInt[16]), c=m.Out(m.UInt[16]), config_data=m.In(m.Bits[2]), config_en=m.In(m.Enable), ) + m.ClockIO() opcode = ConfigReg(name="config_reg")(io.config_data, CE=io.config_en) io.c @= mantle.mux( # udiv not implemented # [io.a + io.b, io.a - io.b, io.a * io.b, io.a / io.b], opcode) # use arbitrary fourth op [io.a + io.b, io.a - io.b, io.a * io.b, io.b - io.a], opcode)
class RAM(m.Circuit): io = m.IO( RADDR=m.In(m.Bits[addr_width]), RDATA=m.Out(m.Bits[data_width]), WADDR=m.In(m.Bits[addr_width]), WDATA=m.In(m.Bits[data_width]), WE=m.In(m.Bit), CLK=m.In(m.Clock), RESET=m.In(m.Reset) ) regs = [mantle.Register(data_width, init=int(init[i]), has_ce=True, has_reset=True) for i in range(1 << addr_width)] for i, reg in enumerate(regs): reg.I <= io.WDATA reg.CE <= (io.WADDR == m.bits(i, addr_width)) & io.WE io.RDATA <= mantle.mux([reg.O for reg in regs], io.RADDR)
def definition(io): dmas = [DMA(name=f"dma{i}") for i in range(2)] if mode == "pack": regs = [ Register(name + str(i)) for i in range(2) for name in fields ] reg_file = DefineRegFile(regs, data_width=32)(name="reg_file") for i in range(2): for name in fields: m.wire(getattr(reg_file, name + str(i) + "_q"), getattr(dmas[i], name)) m.wire(io.apb, reg_file.apb) for i in range(2): for name in fields: m.wire(getattr(reg_file, name + str(i) + "_q"), getattr(reg_file, name + str(i) + "_d")) else: apb_outputs = {} for key, type_ in APBBase(addr_width, data_width).items(): if type_.isinput(): apb_outputs[key] = [] for i in range(2): regs = [Register(name) for name in fields] reg_file = DefineRegFile( regs, data_width=32, apb_slave_id=i)(name=f"reg_file{i}") for name in fields: m.wire(getattr(reg_file, name + "_q"), getattr(dmas[i], name)) for key, type_ in APBBase(addr_width, data_width).items(): if type_.isoutput(): m.wire(getattr(io.apb, key), getattr(reg_file.apb, key)) else: apb_outputs[key].append(getattr(reg_file.apb, key)) m.wire(getattr(io.apb, f"PSEL{i}"), getattr(reg_file.apb, f"PSEL{i}")) for name in fields: m.wire(getattr(reg_file, name + "_q"), getattr(reg_file, name + "_d")) for key, values in apb_outputs.items(): m.wire(getattr(io.apb, key), mantle.mux(values, io.apb.PSEL1))
def definition(io): config = mantle.Register(CONFIG_DATA_WIDTH, init=config_reset, has_ce=True, has_async_reset=True) config_addr_zero = m.bits(0, 8) == io.config_addr[24:32] config(io.config_data, CE=(m.bit(io.config_en) & config_addr_zero)) # If the top 8 bits of config_addr are 0, then read_data is equal # to the value of the config register, otherwise it is 0. m.wire( io.read_data, mantle.mux([m.uint(0, CONFIG_DATA_WIDTH), config.O], config_addr_zero)) # NOTE: This is not robust in the case that the mux which needs more # than 32 select bits (i.e. >= 2^32 inputs). This is unlikely to # happen, but this code is not general. out = generate_mux(io.I, config.O[:sel_bits], m.uint(0, width)) m.wire(out, io.O)
def definition(io): # Assumes opcode is equal to index in `ops` list, would be nice to # generalize this for different encodings (or opcode orderings) O = mantle.mux([op(io.I0, io.I1) for op in ops], io.opcode) m.wire(O, io.O)
def __init__(self, mode="pack"): """ Simple example that instances two stub DMA modules and is paramtrizable over distributed versus packed register file """ if mode not in ["pack", "distribute"]: raise ValueError(f"Unexpected mode {mode}") fields = ["csr", "src_addr", "dst_addr", "txfr_len"] data_width = 32 if mode == "pack": addr_width = math.ceil(math.log2(len(fields) * 2)) else: addr_width = math.ceil(math.log2(len(fields))) self.name = "Top_" + mode if mode == "pack": self.io = io = m.IO(apb=APBSlave(addr_width, data_width, 0)) else: self.io = io = m.IO(apb=APBSlave(addr_width, data_width, [0, 1])) dmas = [DMA(name=f"dma{i}") for i in range(2)] if mode == "pack": regs = tuple( Register(name + str(i)) for i in range(2) for name in fields) reg_file = RegisterFileGenerator(regs, data_width=32)(name="reg_file") for i in range(2): for name in fields: m.wire(getattr(reg_file, name + str(i) + "_q"), getattr(dmas[i], name)) m.wire(io.apb, reg_file.apb) for i in range(2): for name in fields: m.wire(getattr(reg_file, name + str(i) + "_q"), getattr(reg_file, name + str(i) + "_d")) else: apb_outputs = {} for key, type_ in APBBase(addr_width, data_width).items(): if type_.is_input(): apb_outputs[key] = [] for i in range(2): regs = tuple(Register(name) for name in fields) reg_file = RegisterFileGenerator( regs, data_width=32, apb_slave_id=i)(name=f"reg_file{i}") for name in fields: m.wire(getattr(reg_file, name + "_q"), getattr(dmas[i], name)) for key, type_ in APBBase(addr_width, data_width).items(): if type_.is_output(): m.wire(getattr(io.apb, key), getattr(reg_file.apb, key)) else: apb_outputs[key].append(getattr(reg_file.apb, key)) m.wire(getattr(io.apb, f"PSEL{i}"), getattr(reg_file.apb, f"PSEL{i}")) for name in fields: m.wire(getattr(reg_file, name + "_q"), getattr(reg_file, name + "_d")) for key, values in apb_outputs.items(): m.wire(getattr(io.apb, key), mantle.mux(values, io.apb.PSEL1))
class AXI(m.Circuit): interface = make_HandshakeData(data_type) io = m.IO(ARES_design=interface) addr_width = m.bitutils.clog2(depth) reset = io.ARES_design.RESET #data_buffer #=============================================================== buffer = mantle.RAM(2**addr_width, io.ARES_design.W_data.flat_length()) #WReq 操作 #=============================================================== WReq_size_reg = mantle.Register(32) WReq_addr_reg = mantle.Register(32) #不要改! 这个have_WReq_signal 代表我现在有一个WReq要处理 have_WReq_signal = ~(WReq_size_reg.O == 0) #不要改! 有WReq就不能再接新的了!所以WReq_ready要为0 io.ARES_design.WReq_ready @= mantle.mux([~have_WReq_signal, 1], reset) WReq_valid_signal = io.ARES_design.WReq_valid & ~have_WReq_signal receive_WReq_size_signal = mantle.mux( [m.uint(0, 32), io.ARES_design.WReq_size], WReq_valid_signal) receive_WReq_addr_signal = mantle.mux( [m.uint(0, 32), io.ARES_design.WReq_addr], WReq_valid_signal) #这个是真Write_valid 这个东西的意思就是,我用have_WReq_signal代表W_ready。假如W_valid为1,那就是握手完成 #本来应该放在Write 操作里的,我放在这里是要reduce WReq_size W_valid_signal = io.ARES_design.W_valid & have_WReq_signal reduce_WReq_size_signal = mantle.mux( [WReq_size_reg.O, m.uint(WReq_size_reg.O) - 1], W_valid_signal) #有WReq则处理size,没有则准备好从外面拿 WReq_size_signal = mantle.mux( [receive_WReq_size_signal, reduce_WReq_size_signal], have_WReq_signal) WReq_size_reg.I @= mantle.mux([WReq_size_signal, m.uint(0, 32)], reset) #有WReq则保留addr,没有则准备好从外面拿 WReq_addr_signal = mantle.mux( [receive_WReq_addr_signal, WReq_addr_reg.O], have_WReq_signal) WReq_addr_reg.I @= mantle.mux([WReq_addr_signal, m.uint(0, 32)], reset) #Write 操作 #=============================================================== #W_ready io.ARES_design.W_ready @= mantle.mux([have_WReq_signal, 0], reset) #W_size_reg W_size_reg = mantle.Register(32) W_size_reg_increase_signal = mantle.mux( [W_size_reg.O, m.uint(W_size_reg.O) + 1], W_valid_signal) W_size_signal = mantle.mux([m.uint(0, 32), W_size_reg_increase_signal], have_WReq_signal) W_size_reg.I @= mantle.mux([W_size_signal, 0], reset) #buffer buffer.WDATA @= io.ARES_design.W_data buffer.WADDR @= mantle.add(WReq_addr_reg.O[:addr_width], W_size_reg.O[:addr_width]) #have_WReq_signal 就是W_ready,这意味着W_valid和W_ready 同时为1 buffer.WE @= W_valid_signal #RReq 操作 #=============================================================== RReq_size_reg = mantle.Register(32) RReq_addr_reg = mantle.Register(32) #不要改! 这个have_RReq_signal 代表我现在有一个WReq要处理 have_RReq_signal = ~(RReq_size_reg.O == 0) #TODO 关于RReq,我现在的办法是从reset起我就能接受RReq,外面随便发读请求,但是读出什么来不好说,大不了就是X io.ARES_design.RReq_ready @= mantle.mux([~have_RReq_signal, 1], reset) RReq_valid_signal = io.ARES_design.RReq_valid & ~have_RReq_signal receive_RReq_size_signal = mantle.mux( [m.uint(0, 32), io.ARES_design.RReq_size], RReq_valid_signal) receive_RReq_addr_signal = mantle.mux( [m.uint(0, 32), io.ARES_design.RReq_addr], RReq_valid_signal) #这个是真.R_valid。这个东西的意思就是,我用have_RReq_signal代表R_valid。假如R_ready为1,那就是握手完成 #其实这个信号应该放在Read操作里,但是由于我要用R_valid_signal来让RReq_size减少,所以放在这弄 R_valid_signal = io.ARES_design.R_ready & have_RReq_signal #减少RReq_size reduce_RReq_size_signal = mantle.mux( [RReq_size_reg.O, m.uint(RReq_size_reg.O) - 1], R_valid_signal) #有RReq则处理size,没有则准备好从外面拿 RReq_size_signal = mantle.mux( [receive_RReq_size_signal, reduce_RReq_size_signal], have_RReq_signal) RReq_size_reg.I @= mantle.mux([RReq_size_signal, m.uint(0, 32)], reset) #有RReq则保留addr,没有则准备好从外面拿 RReq_addr_signal = mantle.mux( [receive_RReq_addr_signal, RReq_addr_reg.O], have_RReq_signal) RReq_addr_reg.I @= mantle.mux([RReq_addr_signal, m.uint(0, 32)], reset) #Read操作 #=============================================================== io.ARES_design.R_valid @= mantle.mux([have_RReq_signal, 0], reset) #R_size_reg R_size_reg = mantle.Register(32) R_size_reg_increase_signal = mantle.mux( [R_size_reg.O, m.uint(R_size_reg.O) + 1], R_valid_signal) R_size_signal = mantle.mux([m.uint(0, 32), R_size_reg_increase_signal], have_RReq_signal) R_size_reg.I @= mantle.mux([R_size_signal, 0], reset) buffer.RADDR @= mantle.add(RReq_addr_reg.O[:addr_width], R_size_reg.O[:addr_width]) io.ARES_design.R_data @= buffer.RDATA
def definition(io): io.O <= mantle.mux([io.I0, io.I1], io.S, name="my_mux")
def definition(io): opcode = ConfigReg(name="config_reg")(io.config_data, CE=io.config_en) io.c <= mantle.mux( [io.a + io.b, io.a - io.b, io.a * io.b, io.a ^ io.b], opcode)
def __init__(self, regs, data_width, apb_slave_id=0): """ regs : tuple of Register instances """ self.name = "RegFile_" + "_".join(reg.name for reg in regs) self.io = io = make_reg_file_interface(regs, data_width, apb_slave_id) # Get the concrete PSEL signal based on the `apb_slave_id` # parameter PSEL = getattr(io.apb, f"PSEL{apb_slave_id}") # Create a list of Register instances (parametrized by the members # of `regs`) registers = [ mantle.Register(data_width, init=reg.init, has_ce=True, has_reset=True, name=reg.name) for reg in regs ] is_write = io.apb.PENABLE & io.apb.PWRITE & PSEL ready = None for i, reg in enumerate(registers): # Register input is from `<reg_name>_d` port by default # and PWDATA when handling an APB write reg.I @= mantle.mux([getattr(io, reg.name + "_d"), io.apb.PWDATA], is_write) # Wire up register output to `<reg_name>_q` interface port getattr(io, reg.name + "_q") <= reg.O # Wire the clock signals reg.CLK @= io.apb.PCLK reg.RESET @= ~m.bit(io.apb.PRESETn) # Clock enable is based on write signal and PADDR value # For now, a register's address is defined by its index in # `regs` ce = is_write & (io.apb.PADDR == i) if regs[i].has_ce: # If has a clock enable, `or` the enable signal with the IO # input reg.CE @= ce | m.bit(getattr(io, reg.name + "_en")) else: reg.CE @= ce # Set ready high if a register is being written to if ready is not None: ready |= ce else: ready = ce is_read = io.apb.PENABLE & ~io.apb.PWRITE & PSEL # PREADY is high if a write or read is being performed io.apb.PREADY @= ready | is_read # Select PRDATA based on PADDR io.apb.PRDATA @= mantle.mux([reg.O for reg in registers], io.apb.PADDR) # Stub out the rest of the signals for now, CoreIR does not allow # unconnected signals, so we wire them up to the CoreIR `Term` # module which is a stub module that takes a single input and no # output (effectively "casting" the unwired port so the compiler # does not complain) io.apb.PSLVERR.undriven() io.apb.PPROT.unused() io.apb.PSTRB.unused()