From 5e4a954a0c0150dc40c2a89e7400a89ec96d552e Mon Sep 17 00:00:00 2001 From: Dennis Date: Sun, 22 Aug 2021 20:38:56 -0700 Subject: [PATCH] Add _very incomplete_ AMBA 3 AHB Lite widget This is just a start on the first widget. It is still very limited and not yet functional in any way. --- srdl2sv/components/addrmap.py | 12 +- srdl2sv/components/templates/addrmap.yaml | 8 +- srdl2sv/components/templates/fields.yaml | 28 +-- srdl2sv/components/templates/regs.yaml | 12 +- srdl2sv/components/widgets/amba3ahblite.sv | 181 ++++++++++++++++-- srdl2sv/components/widgets/amba3ahblite.yaml | 53 ++--- .../components/widgets/srdl2sv_widget_pkg.sv | 17 ++ srdl2sv/main.py | 19 +- 8 files changed, 252 insertions(+), 78 deletions(-) create mode 100644 srdl2sv/components/widgets/srdl2sv_widget_pkg.sv diff --git a/srdl2sv/components/addrmap.py b/srdl2sv/components/addrmap.py index a645cd5..aa235ba 100644 --- a/srdl2sv/components/addrmap.py +++ b/srdl2sv/components/addrmap.py @@ -130,7 +130,14 @@ class AddrMap(Component): # Remove comma from last port entry output_ports_rtl[-1] = output_ports_rtl[-1].rstrip(',') - import_package_list = [] + # Define packages to be included. Always include the + # b2w and w2b defines. + import_package_list = [ + AddrMap.templ_dict['import_package']['rtl'].format( + name = 'srdl2sv_widget'), + '\n' + ] + try: for x in self.get_package_names(): import_package_list.append( @@ -139,9 +146,10 @@ class AddrMap(Component): import_package_list.append('\n') - import_package_list.pop() except IndexError: pass + + import_package_list.pop() import getpass import socket diff --git a/srdl2sv/components/templates/addrmap.yaml b/srdl2sv/components/templates/addrmap.yaml index ea55da6..9e51fe5 100644 --- a/srdl2sv/components/templates/addrmap.yaml +++ b/srdl2sv/components/templates/addrmap.yaml @@ -69,8 +69,6 @@ module_declaration: <> // Clock & Resets input reg_clk, - input bus_clk, - input bus_rst_n, {resets} // Inputs @@ -115,13 +113,13 @@ read_mux: // Read multiplexer always_comb begin - case(addr) + case(b2r.addr) {list_of_cases} endcase end default_mux_case: rtl: |- - default: sw_rd_bus = 0; + default: r2b.data = 0; list_of_mux_cases: rtl: |- - 32'd{}: sw_rd_bus = {}; + 32'd{}: r2b.data = {}; diff --git a/srdl2sv/components/templates/fields.yaml b/srdl2sv/components/templates/fields.yaml index 591a937..32cbc12 100644 --- a/srdl2sv/components/templates/fields.yaml +++ b/srdl2sv/components/templates/fields.yaml @@ -29,9 +29,9 @@ sw_access_field_swwel: begin sw_access_byte: rtl: |- - if (byte_enable[{i}]) + if (b2r.byte_en[{i}]) <> - {path}_q{genvars}[{msb_field}:{lsb_field}] <= sw_wr_bus[{msb_bus}:{lsb_bus}]; + {path}_q{genvars}[{msb_field}:{lsb_field}] <= b2r.data[{msb_bus}:{lsb_bus}]; <> signals: - name: '{path}_q' @@ -114,33 +114,33 @@ end_field_ff: end // of {path}'s always_ff OnWriteType.woset: rtl: |- - if (byte_enable[{i}]) // woset property + if (b2r.byte_en[{i}]) // woset property begin - {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] | sw_wr_bus[{msb_bus}:{lsb_bus}]; + {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] | b2r.data[{msb_bus}:{lsb_bus}]; end OnWriteType.woclr: rtl: |- - if (byte_enable[{i}]) // woclr property + if (b2r.byte_en[{i}]) // woclr property begin - {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] & ~sw_wr_bus[{msb_bus}:{lsb_bus}]; + {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] & ~b2r.data[{msb_bus}:{lsb_bus}]; end OnWriteType.wot: rtl: |- - if (byte_enable[{i}]) // wot property + if (b2r.byte_en[{i}]) // wot property begin - {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] ^ sw_wr_bus[{msb_bus}:{lsb_bus}]; + {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] ^ b2r.data[{msb_bus}:{lsb_bus}]; end OnWriteType.wzs: rtl: |- - if (byte_enable[{i}]) // wzs property + if (b2r.byte_en[{i}]) // wzs property begin - {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] & sw_wr_bus[{msb_bus}:{lsb_bus}]; + {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] & b2r.data[{msb_bus}:{lsb_bus}]; end OnWriteType.wzt: rtl: |- - if (byte_enable[{i}]) // wzt property + if (b2r.byte_en[{i}]) // wzt property begin - {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] ~^ sw_wr_bus[{msb_bus}:{lsb_bus}]; + {path}_q{genvars}[{msb_field}:{lsb_field}] <= {path}_q{genvars}[{msb_field}:{lsb_field}] ~^ b2r.data[{msb_bus}:{lsb_bus}]; end OnWriteType.wclr: rtl: |- @@ -210,7 +210,7 @@ swacc_assign: rtl: |- // Combinational block to generate swacc-output signals - assign {path}_swacc{genvars} = ({path_wo_field}__any_alias_sw_wr{genvars} || {path_wo_field}__any_alias_sw_rd{genvars}) && |byte_enable[{msbyte}:{lsbyte}]; + assign {path}_swacc{genvars} = ({path_wo_field}__any_alias_sw_wr{genvars} || {path_wo_field}__any_alias_sw_rd{genvars}) && |b2r.byte_en[{msbyte}:{lsbyte}]; output_ports: - name: '{path}_swacc' signal_type: 'logic' @@ -228,7 +228,7 @@ swmod_always_comb: signal_type: 'logic' swmod_assign: rtl: |- - {path}_swmod{genvars} |= {path_wo_field}__any_alias_sw_{rd_wr}{genvars} && |byte_enable[{msbyte}:{lsbyte}]; + {path}_swmod{genvars} |= {path_wo_field}__any_alias_sw_{rd_wr}{genvars} && |b2r.byte_en[{msbyte}:{lsbyte}]; output_ports: - name: '{path}_swmod' signal_type: 'logic' diff --git a/srdl2sv/components/templates/regs.yaml b/srdl2sv/components/templates/regs.yaml index 706fbff..423d180 100644 --- a/srdl2sv/components/templates/regs.yaml +++ b/srdl2sv/components/templates/regs.yaml @@ -3,9 +3,9 @@ rw_wire_assign_1_dim: rtl: | // Register-activation for '{path}' {alias} - assign {path}_accss = addr == {addr}; - assign {path}_sw_wr = {path}_accss && r_vld; - assign {path}_sw_rd = {path}_accss && w_vld; + assign {path}_accss = b2r.addr == {addr}; + assign {path}_sw_wr = {path}_accss && b2r.r_vld; + assign {path}_sw_rd = {path}_accss && b2r.w_vld; signals: - name: '{path}_sw_wr' signal_type: 'logic' @@ -17,9 +17,9 @@ rw_wire_assign_multi_dim: rtl: |- // Register-activation for '{path}' {alias} - assign {path}_accss{genvars} = addr == {addr}+({genvars_sum}); - assign {path}_sw_wr{genvars} = {path}_accss{genvars} && r_vld; - assign {path}_sw_rd{genvars} = {path}_accss{genvars} && w_vld; + assign {path}_accss{genvars} = b2r.addr == {addr}+({genvars_sum}); + assign {path}_sw_wr{genvars} = {path}_accss{genvars} && b2r.r_vld; + assign {path}_sw_rd{genvars} = {path}_accss{genvars} && b2r.w_vld; signals: - name: '{path}_sw_wr' signal_type: 'logic' diff --git a/srdl2sv/components/widgets/amba3ahblite.sv b/srdl2sv/components/widgets/amba3ahblite.sv index 49aaffc..c910fa5 100644 --- a/srdl2sv/components/widgets/amba3ahblite.sv +++ b/srdl2sv/components/widgets/amba3ahblite.sv @@ -1,35 +1,174 @@ +/* + * Copyright 2021 Dennis Potter + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + module amba3ahblite_widget + import srdl2sv_widget_pkg::*; +#( + parameter FLOP_IN = 0, // Set to '1' to flop input from the AHB bus. This is meant + // to help meet timing. Don't use this to synchronize the input. + parameter SYNC_IO = 0 // Set to '1' to in case HCLK and bus_clk are asynchronous + // By default, mainly for it to directly work in simulations, + // it will double-flops based on always_ff-blocks. To replace + // this module with a proper MTBF-optimized double flop cell, + // the contents of the synchronizer module `srdl2sv_sync.sv` + // shall be updated +) ( // Register clock - input bus_clk, - input bus_rst_n, + input reg_clk, // Outputs to internal logic - output [31:0] addr, - output w_vld, - output r_vld, - output [ 3:0] byte_enable, - output [31:0] sw_wr_bus, + output b2r_t b2r, // Inputs from internal logic - input [31:0] sw_rd_bus, + input r2b_t r2b, // Bus protocol - input HRESETn, - input HCLK, - input [31:0] HADDR, - input HWRITE, - input [ 2:0] HSIZE, - input [ 2:0] HBURST, - input [ 3:0] HPROT, - input [ 1:0] HTRANS, - input HMASTLOCK, - input HREADY, + input HRESETn, + input HCLK, + input HSEL, + input [31:0] HADDR, + input HWRITE, + input [ 2:0] HSIZE, + input [ 2:0] HBURST, + input [ 3:0] HPROT, + input [ 1:0] HTRANS, + input [31:0] HWDATA, + input HREADY, - output HREADYOUT, - output HRESP, - output [31:0] HRDATA + output logic HREADYOUT, + output logic HRESP, + output logic [31:0] HRDATA ); + // TODO: Add synchronizer logic + + /*** + * Translate HWRITE & HSEL into a write/read operation for the register logic + ***/ + logic r_vld_next; + logic w_vld_next; + + always_comb + begin + w_vld_next = 1'b0; + r_vld_next = 1'b0; + + if (HWRITE) + w_vld_next = HSEL; + else + r_vld_next = HSEL; + end + + /*** + * Determine the number of active bytes + ***/ + logic [3:0] b2r_byte_en_next; + + always_comb + begin + case (HTRANS) + 3'b000 : b2r_byte_en_next = 4'b0001; + 3'b001 : b2r_byte_en_next = 4'b0011; + 3'b010 : b2r_byte_en_next = 4'b1111; + // TODO: Implement larger sizes + default: b2r_byte_en_next = 4'b1111; + endcase + end + + /*** + * Flop or sync input if required + ***/ + generate + if (FLOP_IN) + begin + always_ff @(posedge HCLK or negedge HRESETn) + if (!HRESETn) + begin + b2r.r_vld <= 1'b0; + b2r.w_vld <= 1'b0; + end + else + begin + b2r.r_vld <= r_vld_next; + b2r.w_vld <= w_vld_next; + end + + always_ff @(posedge HCLK) + if (HWRITE) + begin + b2r.data <= HWDATA; + b2r.byte_en <= b2r_byte_en_next; + end + end + else + begin + assign b2r.r_vld = r_vld_next; + assign b2r.w_vld = w_vld_next; + assign b2r.data = HWDATA; + end + endgenerate + + /*** + * Keep track of an ungoing transaction + ***/ + logic reg_busy_q; + + always_ff @(posedge HCLK or negedge HRESETn) + if (!HRESETn) + reg_busy_q <= 1'b0; + else if ((b2r.r_vld || b2r.w_vld) && !r2b.rdy) + reg_busy_q <= 1'b1; + else if (r2b.rdy) + reg_busy_q <= 1'b0; + + assign HREADYOUT = !reg_busy_q; + + /*** + * Return to AHB bus once the register block is ready + ***/ + // Return actual data + logic ongoing_read_q; + + always_ff @(posedge HCLK or negedge HRESETn) + if (!HRESETn) + ongoing_read_q <= 1'b0; + else if (b2r.r_vld && !r2b.rdy) + ongoing_read_q <= 1'b1; + else if (r2b.rdy) + ongoing_read_q <= 1'b0; + + always_ff @(posedge HCLK) + if ((b2r.r_vld || ongoing_read_q) && r2b.rdy) + HRDATA <= r2b.data; + + // Did an error occur while reading? + always_ff @(posedge HCLK or negedge HRESETn) + if (!HRESETn) + HRESP <= 1'b0; + else + HRESP <= r2b.err; endmodule diff --git a/srdl2sv/components/widgets/amba3ahblite.yaml b/srdl2sv/components/widgets/amba3ahblite.yaml index 14d6382..52a13c3 100644 --- a/srdl2sv/components/widgets/amba3ahblite.yaml +++ b/srdl2sv/components/widgets/amba3ahblite.yaml @@ -1,24 +1,30 @@ # This file only contains the instantiation of the module module_instantiation: rtl: |- - /**************************** + /******************************************************************* * AMBA 3 AHB Lite Widget - ****************************/ + * ====================== + * Naming conventions + * - r2b.* -> Signals from registers to bus + * - b2r.* -> Signals from bus to registers + * - H* -> Signals as defined in AMBA3 AHB Lite + * specification + * - bus_clk -> Clock that that drives signals on bus + * - reg_clk -> Clock that drives register flops + * - bus_rst_n -> Asynchronous reset that resets only the bus (but + * (not the registers). The deassertion of this + * reset shall be synchronized to bus_clk + *******************************************************************/ amba3ahblite_widget amba3ahblite_widget_inst - (// Clocks & Resets - .bus_clk, - .bus_rst_n, + (// Register clock + .reg_clk, // Outputs to internal logic - .addr, - .w_vld, - .r_vld, - .byte_enable, - .sw_wr_bus, + .b2r, // Inputs from internal logic - .sw_rd_bus, + .r2b, // Bus protocol .HRESETn, @@ -29,25 +35,18 @@ module_instantiation: .HBURST, .HPROT, .HTRANS, - .HMASTLOCK, + .HWDATA, .HREADY, + .HSEL, .HREADYOUT, .HRESP, .HRDATA); signals: - - name: 'addr' - signal_type: 'logic [31:0]' - - name: 'w_vld' - signal_type: 'logic' - - name: 'r_vld' - signal_type: 'logic' - - name: 'byte_enable' - signal_type: 'logic [ 3:0]' - - name: 'sw_wr_bus' - signal_type: 'logic [31:0]' - - name: 'sw_rd_bus' - signal_type: 'logic [31:0]' + - name: 'b2r' + signal_type: 'b2r_t' + - name: 'r2b' + signal_type: 'r2b_t' input_ports: - name: 'HRESETn' signal_type: '' @@ -65,10 +64,12 @@ module_instantiation: signal_type: '[3:0]' - name: 'HTRANS' signal_type: '[1:0]' - - name: 'HMASTLOCK' - signal_type: '' + - name: 'HWDATA' + signal_type: '[31:0]' - name: 'HREADY' signal_type: '' + - name: 'HSEL' + signal_type: '' output_ports: - name: 'HREADYOUT' signal_type: '' diff --git a/srdl2sv/components/widgets/srdl2sv_widget_pkg.sv b/srdl2sv/components/widgets/srdl2sv_widget_pkg.sv new file mode 100644 index 0000000..e938dec --- /dev/null +++ b/srdl2sv/components/widgets/srdl2sv_widget_pkg.sv @@ -0,0 +1,17 @@ +package srdl2sv_widget_pkg; + +typedef struct { + logic [31:0] addr; + logic [31:0] data; + logic w_vld; + logic r_vld; + logic [ 3:0] byte_en; +} b2r_t; + +typedef struct { + logic [31:0] data; + logic rdy; + logic err; +} r2b_t; + +endpackage diff --git a/srdl2sv/main.py b/srdl2sv/main.py index e9f2b17..ddd7618 100755 --- a/srdl2sv/main.py +++ b/srdl2sv/main.py @@ -58,11 +58,12 @@ if __name__ == "__main__": out_addrmap_file = "{}/{}.sv".format(config['output_dir'], addrmap.name) with open(out_addrmap_file, 'w') as file: - file.write( + print( addrmap.get_rtl( tab_width=config['tab_width'], real_tabs=config['real_tabs'] - ) + ), + file=file ) logger.info('Succesfully created "{}"'.format(out_addrmap_file)) @@ -75,7 +76,7 @@ if __name__ == "__main__": ).items(): if value: with open('{}/{}_pkg.sv'.format(config['output_dir'], key), 'w') as file: - file.write(value) + print(value, file=file) # Copy over widget RTL from widget directory widget_rtl = pkg_resources.read_text(widgets, '{}.sv'.format(config['bus'])) @@ -83,9 +84,19 @@ if __name__ == "__main__": out_widget_file = "{}/{}.sv".format(config['output_dir'], config['bus']) with open(out_widget_file, 'w') as file: - file.write(widget_rtl) + print(widget_rtl, file=file) logger.info("Selected, implemented, and copied '{}' widget".format(config['bus'])) + # Copy over generic srdl2sv_widget_pkg + widget_if_rtl = pkg_resources.read_text(widgets, 'srdl2sv_widget_pkg.sv') + + out_widget_if_file = "{}/srdl2sv_widget_pkg.sv".format(config['output_dir']) + + with open(out_widget_if_file, 'w') as file: + print(widget_if_rtl,file=file) + + logger.info("Copied 'srdl2sv_widget_pkg.sv") + # Print elapsed time logger.info("Elapsed time: %f seconds", time.time() - start)