diff --git a/axi.core b/axi.core index eb38359ad..d1a859168 100644 --- a/axi.core +++ b/axi.core @@ -137,11 +137,15 @@ generators: offset (int): Base address for the slave size (int): Size of the allocated memory map for the slave + slaves (list): List of device ports that this host is + connected to. A missing or empty list means + connection to all devices. Example usage: The following config will generate an interconnect wrapper to which two AXI4 master interfaces (dma and ibus) with different id widths are connected, and connects downstream to three AXI4 slaves (rom, gpio, ram) + The ibus port is only allowed to access the rom and ram ports. soc_intercon: generator: axi_intercon_gen @@ -151,6 +155,7 @@ generators: id_width : 1 ibus: id_width : 2 + slaves: [ram, rom] slaves: ram: offset : 0 diff --git a/scripts/axi_intercon_gen.py b/scripts/axi_intercon_gen.py index af5b3a209..9e8e606d5 100644 --- a/scripts/axi_intercon_gen.py +++ b/scripts/axi_intercon_gen.py @@ -200,13 +200,12 @@ def load_dict(self, d): for key, value in d.items(): if key == 'slaves': # Handled in file loading, ignore here - continue - if key == 'id_width': + self.slaves = value + elif key == 'id_width': self.idw = value elif key == 'read_only': self.read_only = value else: - print(key) raise UnknownPropertyError( "Unknown property '%s' in master section '%s'" % ( key, self.name)) @@ -276,7 +275,7 @@ def construct_mapping(loader, node): print("Found slave " + k) self.slaves.append(Slave(k,v)) - self.output_file = config.get('output_file', 'axi_intercon.v') + self.output_file = config.get('output_file', 'axi_intercon.sv') self.atop = config.get('atop', False) def _dump(self): @@ -349,6 +348,7 @@ def write(self): MaxSlvTrans: 6, FallThrough: 1'b0, LatencyMode: axi_pkg::CUT_ALL_AX, + PipelineStages: 0, AxiIdWidthSlvPorts: AxiIdWidthMasters, AxiIdUsedSlvPorts: AxiIdUsed, UniqueIds: 1'b0, @@ -403,7 +403,18 @@ def write(self): raw += " mst_req_t [{}:0] slaves_req;\n".format(ns-1) raw += " mst_resp_t [{}:0] slaves_resp;\n".format(ns-1) - ns = len(self.slaves) + raw += f"\n localparam bit [{nm-1}:0][{ns-1}:0] connectivity = " + '{\n {' + connmap = [] + for master in reversed(self.masters): + connstr = f"{ns}'b" + if master.slaves: + for slave in reversed(self.slaves): + connstr += '1' if slave.name in master.slaves else '0' + else: + connstr += '1'*ns + connmap.append(connstr) + raw += "},\n {".join(connmap) + raw += "}};\n" raw += assigns(w, max_idw, self.masters, self.slaves) @@ -411,6 +422,7 @@ def write(self): parameters = [ Parameter('Cfg' , 'xbar_cfg' ), Parameter('ATOPs' , "1'b"+str(int(self.atop))), + Parameter('Connectivity' , 'connectivity'), Parameter('slv_aw_chan_t', 'aw_chan_mst_t'), Parameter('mst_aw_chan_t', 'aw_chan_slv_t'), Parameter('w_chan_t' , 'w_chan_t' ), @@ -439,14 +451,15 @@ def write(self): _template_ports)) self.verilog_writer.write(file) - self.template_writer.write(file+'h') + template_file = file.split('.')[0]+'.vh' + self.template_writer.write(template_file) core_file = self.vlnv.split(':')[2]+'.core' vlnv = self.vlnv with open(core_file, 'w') as f: f.write('CAPI=2:\n') files = [{file : {'file_type' : 'systemVerilogSource'}}, - {file+'h' : {'is_include_file' : True, + {template_file : {'is_include_file' : True, 'file_type' : 'verilogSource'}} ] coredata = {'name' : vlnv, diff --git a/src/axi_dw_upsizer.sv b/src/axi_dw_upsizer.sv index 9908b7860..6e96e98f4 100644 --- a/src/axi_dw_upsizer.sv +++ b/src/axi_dw_upsizer.sv @@ -359,7 +359,7 @@ module axi_dw_upsizer #( // Initialize r_data r_data = '0; - case (r_state_q) + unique case (r_state_q) R_IDLE : begin // Reset channels r_req_d.ar = '0; @@ -381,7 +381,7 @@ module axi_dw_upsizer #( r_req_d.burst_len = slv_req_i.ar.len ; r_req_d.orig_ar_size = slv_req_i.ar.size; - case (r_req_d.ar.burst) + unique case (r_req_d.ar.burst) axi_pkg::BURST_INCR: begin // Modifiable transaction if (modifiable(r_req_d.ar.cache)) begin @@ -413,6 +413,8 @@ module axi_dw_upsizer #( if (r_req_d.ar.len == '0) r_req_d.ar_throw_error = 1'b0; end + + default: ; endcase end end @@ -439,7 +441,7 @@ module axi_dw_upsizer #( // Default state r_state_d = R_PASSTHROUGH; - case (r_req_d.ar.burst) + unique case (r_req_d.ar.burst) axi_pkg::BURST_INCR: begin // Modifiable transaction if (modifiable(r_req_d.ar.cache)) begin @@ -471,6 +473,8 @@ module axi_dw_upsizer #( if (r_req_d.ar.len == '0) r_req_d.ar_throw_error = 1'b0; end + + default: ; endcase end @@ -499,22 +503,25 @@ module axi_dw_upsizer #( if (slv_r_ready_tran[t]) begin r_req_d.burst_len = r_req_q.burst_len - 1; - case (r_req_q.ar.burst) + unique case (r_req_q.ar.burst) axi_pkg::BURST_INCR: begin r_req_d.ar.addr = aligned_addr(r_req_q.ar.addr, r_req_q.orig_ar_size) + (1 << r_req_q.orig_ar_size); end axi_pkg::BURST_FIXED: begin r_req_d.ar.addr = r_req_q.ar.addr; end + default: ; endcase - case (r_state_q) + unique case (r_state_q) R_PASSTHROUGH: mst_r_ready_tran[t] = 1'b1; R_INCR_UPSIZE: if (r_req_q.burst_len == 0 || (aligned_addr(r_req_d.ar.addr, AxiMstPortMaxSize) != aligned_addr(r_req_q.ar.addr, AxiMstPortMaxSize))) mst_r_ready_tran[t] = 1'b1; + + default: ; endcase if (r_req_q.burst_len == '0) @@ -522,6 +529,8 @@ module axi_dw_upsizer #( end end end + + default: ; endcase end @@ -585,7 +594,7 @@ module axi_dw_upsizer #( w_req_d.aw_throw_error = 1'b0; end - case (w_state_q) + unique case (w_state_q) W_PASSTHROUGH, W_INCR_UPSIZE: begin // Got a grant on the W channel if (mst_req.w_valid && mst_resp.w_ready) begin @@ -617,16 +626,17 @@ module axi_dw_upsizer #( w_req_d.w.last = (w_req_q.burst_len == 0); w_req_d.w.user = slv_req_i.w.user ; - case (w_req_q.aw.burst) + unique case (w_req_q.aw.burst) axi_pkg::BURST_INCR: begin w_req_d.aw.addr = aligned_addr(w_req_q.aw.addr, w_req_q.orig_aw_size) + (1 << w_req_q.orig_aw_size); end axi_pkg::BURST_FIXED: begin w_req_d.aw.addr = w_req_q.aw.addr; end + default: ; endcase - case (w_state_q) + unique case (w_state_q) W_PASSTHROUGH: // Forward data as soon as we can w_req_d.w_valid = 1'b1; @@ -635,6 +645,7 @@ module axi_dw_upsizer #( // Forward when the burst is finished, or after filling up a word if (w_req_q.burst_len == 0 || (aligned_addr(w_req_d.aw.addr, AxiMstPortMaxSize) != aligned_addr(w_req_q.aw.addr, AxiMstPortMaxSize))) w_req_d.w_valid = 1'b1; + default: ; endcase end end @@ -645,6 +656,7 @@ module axi_dw_upsizer #( w_state_d = W_IDLE; end end + default: ; endcase // Can start a new request as soon as w_state_d is W_IDLE @@ -675,7 +687,7 @@ module axi_dw_upsizer #( w_req_d.burst_len = slv_req_i.aw.len ; w_req_d.orig_aw_size = slv_req_i.aw.size; - case (slv_req_i.aw.burst) + unique case (slv_req_i.aw.burst) axi_pkg::BURST_INCR: begin // Modifiable transaction if (modifiable(slv_req_i.aw.cache)) @@ -707,6 +719,8 @@ module axi_dw_upsizer #( if (slv_req_i.aw.len == '0) w_req_d.aw_throw_error = 1'b0; end + + default: ; endcase end end diff --git a/src/axi_id_serialize.sv b/src/axi_id_serialize.sv index 9a787dd25..671b38ad1 100644 --- a/src/axi_id_serialize.sv +++ b/src/axi_id_serialize.sv @@ -66,7 +66,7 @@ module axi_id_serialize #( /// Number of Entries in the explicit ID map (default: None) parameter int unsigned IdMapNumEntries = 32'd0, /// Explicit ID map; index [0] in each entry is the input ID to match, index [1] the output ID. - parameter int unsigned IdMap [IdMapNumEntries-1:0][0:1] = '{default: {32'b0, 32'b0}} + parameter int unsigned IdMap [axi_pkg::iomsb(IdMapNumEntries):0][0:1] = '{default: {32'b0, 32'b0}} ) ( /// Rising-edge clock of both ports input logic clk_i, diff --git a/src/axi_pkg.sv b/src/axi_pkg.sv index 4102be0e8..6e6450bbd 100644 --- a/src/axi_pkg.sv +++ b/src/axi_pkg.sv @@ -532,4 +532,9 @@ package axi_pkg; logic [31:0] end_addr; } xbar_rule_32_t; + // Return either the argument minus 1 or 0 if 0; useful for IO vector width declaration + function automatic integer unsigned iomsb (input integer unsigned width); + return (width != 32'd0) ? unsigned'(width-1) : 32'd0; + endfunction + endpackage