From c589a17ea5173bf35f552e5e0f2439bf292f6d77 Mon Sep 17 00:00:00 2001 From: Dennis Date: Sat, 6 Nov 2021 18:28:21 -0700 Subject: [PATCH] Add counter-example --- examples/counters/Makefile | 14 + examples/counters/counters.rdl | 77 ++ examples/counters/srdl2sv_out/counters.sv | 808 ++++++++++++++++++ .../srdl2sv_out/srdl2sv_amba3ahblite.sv | 312 +++++++ .../counters/srdl2sv_out/srdl2sv_widget_if.sv | 30 + 5 files changed, 1241 insertions(+) create mode 100644 examples/counters/Makefile create mode 100644 examples/counters/counters.rdl create mode 100644 examples/counters/srdl2sv_out/counters.sv create mode 100644 examples/counters/srdl2sv_out/srdl2sv_amba3ahblite.sv create mode 100644 examples/counters/srdl2sv_out/srdl2sv_widget_if.sv diff --git a/examples/counters/Makefile b/examples/counters/Makefile new file mode 100644 index 0000000..e2cc62a --- /dev/null +++ b/examples/counters/Makefile @@ -0,0 +1,14 @@ +RTL_TARGETS = $(subst .rdl,.sv,srdl2sv_out/$(shell ls *.rdl)) + +.PHONY: clean + +default: verilog_compile + +verilog_compile: $(RTL_TARGETS) + verilator -cc -sv $(shell ls srdl2sv_out/*.sv) + +srdl2sv_out/%.sv: %.rdl $(shell which srdl2sv) + srdl2sv $< --out-dir $(shell dirname $@) --stdout-logging INFO -d 31 + +clean: + rm -rf srdl2sv_out diff --git a/examples/counters/counters.rdl b/examples/counters/counters.rdl new file mode 100644 index 0000000..56cf062 --- /dev/null +++ b/examples/counters/counters.rdl @@ -0,0 +1,77 @@ +addrmap counters { + desc = + "This addressmap shows of different counter properties + that SystemRDL offers and can be used in the register blocks."; + + signal {activelow; async; field_reset;} rst_async_n; + + reg { + field {sw = rw; hw = na;} threshold [31:0] = 32'hffffffff; + } counter_a_threshold; + + reg { + desc = "Saturating counter that can be cleared when software writes to + the field, has a configurable counter, and can increment and + decrement. + + When you want a purely incrementing or decrementing counter, set + incrval/decrval to 0."; + + field { + sw = rw; + onwrite = wclr; + counter = true; + incrsaturate = true; // Counter saturates at 2**32-1 + decrsaturate = true; // Counter saturates at 0 + overflow = true; // Generate a signal that tells if the counter overflows + } cnt [31:0] = 0; + } counter_a; + + // Define a custom threshold value + counter_a.cnt->threshold = counter_a_threshold.threshold; + + + regfile { + desc = "This regfile implements a 64-bit non-saturating counter + that will fire an interrupt as soon as it wraps around."; + + reg { + field { + sw = rw; + onwrite = wclr; + counter = true; + decrvalue = 0; + overflow = true; // Generate a signal that tells if the counter overflows + } cnt [31:0] = 0; + } counter_b_lsb; + + reg { + field { + sw = rw; + onwrite = wclr; + counter = true; + decrvalue = 0; + overflow = true; // Generate a signal that tells if the counter overflows + } cnt [31:0] = 0; + } counter_b_msb; + + // Daisy-chain + counter_b_msb.cnt->incr = counter_b_lsb.cnt->overflow; + } wide_counters [2]; // Mutlidimensionality supported + + reg { + field { + desc = "Interrupt if the msb-part of counter_b[2] overflowed."; + level intr; + } ovrflw_1 = 0; + + field { + desc = "Interrupt if the msb-part of counter_b[2] overflowed."; + level intr; + } ovrflw_0 = 0; + } counter_b_overflow_intr; + + counter_b_overflow_intr.ovrflw_0->next = wide_counters[0].counter_b_msb.cnt->overflow; + counter_b_overflow_intr.ovrflw_1->next = wide_counters[1].counter_b_msb.cnt->overflow; + +}; diff --git a/examples/counters/srdl2sv_out/counters.sv b/examples/counters/srdl2sv_out/counters.sv new file mode 100644 index 0000000..3a6ad38 --- /dev/null +++ b/examples/counters/srdl2sv_out/counters.sv @@ -0,0 +1,808 @@ +/***************************************************************** + * + * ███████╗██████╗ ██████╗ ██╗ ██████╗ ███████╗██╗ ██╗ + * ██╔════╝██╔══██╗██╔══██╗██║ ╚════██╗██╔════╝██║ ██║ + * ███████╗██████╔╝██║ ██║██║ █████╔╝███████╗██║ ██║ + * ╚════██║██╔══██╗██║ ██║██║ ██╔═══╝ ╚════██║╚██╗ ██╔╝ + * ███████║██║ ██║██████╔╝███████╗███████╗███████║ ╚████╔╝ + * ╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚══════╝╚══════╝ ╚═══╝ + * + * The present RTL was generated by srdl2sv v0.01. The RTL and all + * templates the RTL is derived from are licensed under the MIT + * license. The license is shown below. + * + * srdl2sv itself is licensed under GPLv3. + * + * Maintainer : Dennis Potter + * Report Bugs: https://github.com/Silicon1602/srdl2sv/issues + * + * ===GENERATION INFORMATION====================================== + * + * Generation information: + * - User: : dpotter + * - Time : November 06 2021 18:27:58 + * - Path : /home/dpotter/srdl2sv/examples/counters + * - RDL file : ['counters.rdl'] + * - Hostname : ArchXPS + * + * RDL include directories: + * - + * + * Commandline arguments to srdl2sv: + * - Ouput Directory : srdl2sv_out + * - Stream Log Level : INFO + * - File Log Level : NONE + * - Use Real Tabs : False + * - Tab Width : 4 + * - Enums Enabled : True + * - Address Errors : True + * - Unpacked I/Os : True + * - Register Bus Type: amba3ahblite + * - Address width : 32 + * - Byte enables : True + * - Descriptions : {'AddrMap': True, 'RegFile': True, 'Memory': True, 'Register': True, 'Field': True} + * + * ===LICENSE OF COUNTERS.SV===================================== + * + * 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 counters + +( + // Resets + input rst_async_n, + + // Inputs + input clk , + input HRESETn , + input [31:0] HADDR , + input HWRITE , + input [2:0] HSIZE , + input [3:0] HPROT , + input [1:0] HTRANS , + input [32-1:0] HWDATA , + input HSEL , + input wide_counters__counter_b_lsb__cnt_incr[2], + input counter_a__cnt_incr , + input counter_a__cnt_decr , + + // Outputs + output HREADYOUT , + output HRESP , + output [32-1:0] HRDATA , + output [31:0] wide_counters__counter_b_lsb__cnt_r [2], + output wide_counters__counter_b_lsb__cnt_overflow[2], + output [31:0] wide_counters__counter_b_msb__cnt_r [2], + output wide_counters__counter_b_msb__cnt_overflow[2], + output [31:0] counter_a__cnt_r , + output counter_a__cnt_incr_thr , + output counter_a__cnt_overflow , + output counter_b_overflow_intr_intr +); + +/******************************************************************* +/**ADDRMAP DESCRIPTION********************************************** +/******************************************************************* +This addressmap shows of different counter properties +that SystemRDL offers and can be used in the register blocks. +/*******************************************************************/ + +// Internal signals +srdl2sv_widget_if #(.ADDR_W (32), .DATA_W(32)) widget_if; + +/******************************************************************* + * AMBA 3 AHB Lite Widget + * ====================== + * Naming conventions + * - widget_if -> SystemVerilog interface to between widgets + * and the internal srdl2sv registers. + * - H* -> Signals as defined in AMBA3 AHB Lite + * specification + * - clk -> Clock that drives registers and the bus + *******************************************************************/ +srdl2sv_amba3ahblite + #(.FLOP_REGISTER_IF (0), + .BUS_BITS (32), + .NO_BYTE_ENABLE (0)) +srdl2sv_amba3ahblite_inst + (// Bus protocol + .HRESETn, + .HCLK (clk), + .HADDR, + .HWRITE, + .HSIZE, + .HPROT, + .HTRANS, + .HWDATA, + .HSEL, + + .HREADYOUT, + .HRESP, + .HRDATA, + + // Interface to internal logic + .widget_if); + +genvar gv_a; + +/******************************************************************* + ******************************************************************* + * REGFILE : wide_counters + * DIMENSION : 1 + * DEPTHS (per dimension): [2] + ******************************************************************* + *******************************************************************/ + +/**REGFILE DESCRIPTION********************************************** +This regfile implements a 64-bit non-saturating counter +that will fire an interrupt as soon as it wraps around. +/*******************************************************************/ + +// Variables of register 'counter_b_lsb' +logic wide_counters__counter_b_lsb_active [2]; +logic wide_counters__counter_b_lsb_sw_wr [2]; +logic [31:0] wide_counters__counter_b_lsb_data_mux_in[2]; +logic wide_counters__counter_b_lsb_rdy_mux_in [2]; +logic wide_counters__counter_b_lsb_err_mux_in [2]; +logic [31:0] wide_counters__counter_b_lsb__cnt_q [2]; +logic wide_counters__counter_b_lsb__cnt_update_cnt[2]; +logic [31:0] wide_counters__counter_b_lsb__cnt_next [2]; +logic [0:0] wide_counters__counter_b_lsb__cnt_incr_val[2]; +logic [0:0] wide_counters__counter_b_lsb__cnt_decr_val[2]; +logic wide_counters__counter_b_lsb__cnt_decr [2]; +logic wide_counters__counter_b_lsb__cnt_incr_sat[2]; +logic wide_counters__counter_b_lsb__cnt_decr_sat[2]; +logic wide_counters__counter_b_lsb__cnt_overflow_int[2]; + +// Variables of register 'counter_b_msb' +logic wide_counters__counter_b_msb_active [2]; +logic wide_counters__counter_b_msb_sw_wr [2]; +logic [31:0] wide_counters__counter_b_msb_data_mux_in[2]; +logic wide_counters__counter_b_msb_rdy_mux_in [2]; +logic wide_counters__counter_b_msb_err_mux_in [2]; +logic [31:0] wide_counters__counter_b_msb__cnt_q [2]; +logic wide_counters__counter_b_msb__cnt_update_cnt[2]; +logic [31:0] wide_counters__counter_b_msb__cnt_next [2]; +logic [0:0] wide_counters__counter_b_msb__cnt_incr_val[2]; +logic [0:0] wide_counters__counter_b_msb__cnt_decr_val[2]; +logic wide_counters__counter_b_msb__cnt_incr [2]; +logic wide_counters__counter_b_msb__cnt_decr [2]; +logic wide_counters__counter_b_msb__cnt_incr_sat[2]; +logic wide_counters__counter_b_msb__cnt_decr_sat[2]; +logic wide_counters__counter_b_msb__cnt_overflow_int[2]; + +generate +for (gv_a = 0; gv_a < 2; gv_a++) +begin + + /******************************************************************* + /******************************************************************* + /* REGISTER : counter_b_lsb + /* DIMENSION : 0 + /* DEPTHS (per dimension): [] + /******************************************************************* + /*******************************************************************/ + + + // Register-activation for 'wide_counters__counter_b_lsb' + assign wide_counters__counter_b_lsb_active[gv_a] = widget_if.addr == 8+(gv_a*8); + assign wide_counters__counter_b_lsb_sw_wr[gv_a] = wide_counters__counter_b_lsb_active[gv_a] && widget_if.w_vld; + + //-----------------FIELD SUMMARY----------------- + // name : cnt (wide_counters__counter_b_lsb[31:0]) + // access : hw = rw + // sw = rw (precedence) + // reset : active_low / asynchronous + // flags : ['sw', 'onwrite', 'counter', 'decrvalue', 'overflow'] + // external : False + // storage type : StorageType.FLOPS + //----------------------------------------------- + + always_ff @(posedge clk or negedge rst_async_n) + if (!rst_async_n) + begin + wide_counters__counter_b_lsb__cnt_q[gv_a] <= 32'd0; + end + else + begin + if (wide_counters__counter_b_lsb_sw_wr[gv_a]) + begin + if (widget_if.byte_en[0]) // wclr property + wide_counters__counter_b_lsb__cnt_q[gv_a][7:0] <= 8'b0; + if (widget_if.byte_en[1]) // wclr property + wide_counters__counter_b_lsb__cnt_q[gv_a][15:8] <= 8'b0; + if (widget_if.byte_en[2]) // wclr property + wide_counters__counter_b_lsb__cnt_q[gv_a][23:16] <= 8'b0; + if (widget_if.byte_en[3]) // wclr property + wide_counters__counter_b_lsb__cnt_q[gv_a][31:24] <= 8'b0; + end + else + if (wide_counters__counter_b_lsb__cnt_incr[gv_a] || wide_counters__counter_b_lsb__cnt_decr[gv_a]) + wide_counters__counter_b_lsb__cnt_q[gv_a] <= wide_counters__counter_b_lsb__cnt_next[gv_a]; + end // of wide_counters__counter_b_lsb__cnt's always_ff + + // Connect register to hardware output port + assign wide_counters__counter_b_lsb__cnt_r[gv_a] = wide_counters__counter_b_lsb__cnt_q[gv_a]; + + + /*********************** + * Counter Combo Logic * + ***********************/ + assign wide_counters__counter_b_lsb__cnt_incr_val[gv_a] = 1; + assign wide_counters__counter_b_lsb__cnt_decr_val[gv_a] = 0; + assign wide_counters__counter_b_lsb__cnt_decr[gv_a] = 0; + + // Determine whether the counter is saturated + // The signal is tied if the counter is not saturating + // in the respective direction + assign wide_counters__counter_b_lsb__cnt_incr_sat[gv_a] = 1'b0; + assign wide_counters__counter_b_lsb__cnt_decr_sat[gv_a] = 1'b0; + + // Logic to determine occurance of an overflow + assign wide_counters__counter_b_lsb__cnt_overflow_int[gv_a] = {1'b0, wide_counters__counter_b_lsb__cnt_q[gv_a]} + ({33{wide_counters__counter_b_lsb__cnt_incr}} & {32'b0, wide_counters__counter_b_lsb__cnt_incr_val}) - ({33{wide_counters__counter_b_lsb__cnt_decr}} & {32'b0, wide_counters__counter_b_lsb__cnt_decr_val}) > {1'b0, 4294967295}; + assign wide_counters__counter_b_lsb__cnt_overflow[gv_a] = wide_counters__counter_b_lsb__cnt_incr[gv_a] && wide_counters__counter_b_lsb__cnt_overflow_int[gv_a]; + + // Combinational logic that implements counter + // Note that the three branches for all three possibilities + // are implemented but that either the _incr or the _decr value + // might be tied to 0. + always_comb + begin + wide_counters__counter_b_lsb__cnt_next[gv_a] = wide_counters__counter_b_lsb__cnt_q[gv_a]; + + if (wide_counters__counter_b_lsb__cnt_incr[gv_a] && wide_counters__counter_b_lsb__cnt_decr[gv_a]) + begin + if (!wide_counters__counter_b_lsb__cnt_incr_sat[gv_a] && !wide_counters__counter_b_lsb__cnt_decr_sat[gv_a]) + begin + wide_counters__counter_b_lsb__cnt_next[gv_a] += {31'b0, wide_counters__counter_b_lsb__cnt_incr_val[gv_a]}; + wide_counters__counter_b_lsb__cnt_next[gv_a] -= {31'b0, wide_counters__counter_b_lsb__cnt_decr_val[gv_a]}; + end + end + else if (wide_counters__counter_b_lsb__cnt_incr[gv_a]) + begin + if (!wide_counters__counter_b_lsb__cnt_incr_sat[gv_a]) + wide_counters__counter_b_lsb__cnt_next[gv_a] += {31'b0, wide_counters__counter_b_lsb__cnt_incr_val[gv_a]}; + end + else if (wide_counters__counter_b_lsb__cnt_decr[gv_a]) + begin + if (!wide_counters__counter_b_lsb__cnt_decr_sat[gv_a]) + wide_counters__counter_b_lsb__cnt_next[gv_a] -= {31'b0, wide_counters__counter_b_lsb__cnt_decr_val[gv_a]}; + end + end + + + /************************************** + * Assign all fields to signal to Mux * + **************************************/ + // Assign all fields. Fields that are not readable are tied to 0. + assign wide_counters__counter_b_lsb_data_mux_in[gv_a] = {wide_counters__counter_b_lsb__cnt_q[gv_a]}; + + // Internal registers are ready immediately + assign wide_counters__counter_b_lsb_rdy_mux_in[gv_a] = 1'b1; + + // Return an error if *no* read and *no* write was succesful. If some bits + // cannot be read/written but others are succesful, don't return and error + // Hence, as long as one action can be succesful, no error will be returned. + assign wide_counters__counter_b_lsb_err_mux_in[gv_a] = !((widget_if.r_vld && (|widget_if.byte_en[3:0])) || (widget_if.w_vld && (|widget_if.byte_en[3:0]))); + + /******************************************************************* + /******************************************************************* + /* REGISTER : counter_b_msb + /* DIMENSION : 0 + /* DEPTHS (per dimension): [] + /******************************************************************* + /*******************************************************************/ + + + // Register-activation for 'wide_counters__counter_b_msb' + assign wide_counters__counter_b_msb_active[gv_a] = widget_if.addr == 12+(gv_a*8); + assign wide_counters__counter_b_msb_sw_wr[gv_a] = wide_counters__counter_b_msb_active[gv_a] && widget_if.w_vld; + + //-----------------FIELD SUMMARY----------------- + // name : cnt (wide_counters__counter_b_msb[31:0]) + // access : hw = rw + // sw = rw (precedence) + // reset : active_low / asynchronous + // flags : ['sw', 'onwrite', 'counter', 'decrvalue', 'overflow', 'incr'] + // external : False + // storage type : StorageType.FLOPS + //----------------------------------------------- + + always_ff @(posedge clk or negedge rst_async_n) + if (!rst_async_n) + begin + wide_counters__counter_b_msb__cnt_q[gv_a] <= 32'd0; + end + else + begin + if (wide_counters__counter_b_msb_sw_wr[gv_a]) + begin + if (widget_if.byte_en[0]) // wclr property + wide_counters__counter_b_msb__cnt_q[gv_a][7:0] <= 8'b0; + if (widget_if.byte_en[1]) // wclr property + wide_counters__counter_b_msb__cnt_q[gv_a][15:8] <= 8'b0; + if (widget_if.byte_en[2]) // wclr property + wide_counters__counter_b_msb__cnt_q[gv_a][23:16] <= 8'b0; + if (widget_if.byte_en[3]) // wclr property + wide_counters__counter_b_msb__cnt_q[gv_a][31:24] <= 8'b0; + end + else + if (wide_counters__counter_b_msb__cnt_incr[gv_a] || wide_counters__counter_b_msb__cnt_decr[gv_a]) + wide_counters__counter_b_msb__cnt_q[gv_a] <= wide_counters__counter_b_msb__cnt_next[gv_a]; + end // of wide_counters__counter_b_msb__cnt's always_ff + + // Connect register to hardware output port + assign wide_counters__counter_b_msb__cnt_r[gv_a] = wide_counters__counter_b_msb__cnt_q[gv_a]; + + + /*********************** + * Counter Combo Logic * + ***********************/ + assign wide_counters__counter_b_msb__cnt_incr_val[gv_a] = 1; + assign wide_counters__counter_b_msb__cnt_decr_val[gv_a] = 0; + assign wide_counters__counter_b_msb__cnt_incr[gv_a] = wide_counters__counter_b_lsb__cnt_overflow[0]; + assign wide_counters__counter_b_msb__cnt_decr[gv_a] = 0; + + // Determine whether the counter is saturated + // The signal is tied if the counter is not saturating + // in the respective direction + assign wide_counters__counter_b_msb__cnt_incr_sat[gv_a] = 1'b0; + assign wide_counters__counter_b_msb__cnt_decr_sat[gv_a] = 1'b0; + + // Logic to determine occurance of an overflow + assign wide_counters__counter_b_msb__cnt_overflow_int[gv_a] = {1'b0, wide_counters__counter_b_msb__cnt_q[gv_a]} + ({33{wide_counters__counter_b_msb__cnt_incr}} & {32'b0, wide_counters__counter_b_msb__cnt_incr_val}) - ({33{wide_counters__counter_b_msb__cnt_decr}} & {32'b0, wide_counters__counter_b_msb__cnt_decr_val}) > {1'b0, 4294967295}; + assign wide_counters__counter_b_msb__cnt_overflow[gv_a] = wide_counters__counter_b_msb__cnt_incr[gv_a] && wide_counters__counter_b_msb__cnt_overflow_int[gv_a]; + + // Combinational logic that implements counter + // Note that the three branches for all three possibilities + // are implemented but that either the _incr or the _decr value + // might be tied to 0. + always_comb + begin + wide_counters__counter_b_msb__cnt_next[gv_a] = wide_counters__counter_b_msb__cnt_q[gv_a]; + + if (wide_counters__counter_b_msb__cnt_incr[gv_a] && wide_counters__counter_b_msb__cnt_decr[gv_a]) + begin + if (!wide_counters__counter_b_msb__cnt_incr_sat[gv_a] && !wide_counters__counter_b_msb__cnt_decr_sat[gv_a]) + begin + wide_counters__counter_b_msb__cnt_next[gv_a] += {31'b0, wide_counters__counter_b_msb__cnt_incr_val[gv_a]}; + wide_counters__counter_b_msb__cnt_next[gv_a] -= {31'b0, wide_counters__counter_b_msb__cnt_decr_val[gv_a]}; + end + end + else if (wide_counters__counter_b_msb__cnt_incr[gv_a]) + begin + if (!wide_counters__counter_b_msb__cnt_incr_sat[gv_a]) + wide_counters__counter_b_msb__cnt_next[gv_a] += {31'b0, wide_counters__counter_b_msb__cnt_incr_val[gv_a]}; + end + else if (wide_counters__counter_b_msb__cnt_decr[gv_a]) + begin + if (!wide_counters__counter_b_msb__cnt_decr_sat[gv_a]) + wide_counters__counter_b_msb__cnt_next[gv_a] -= {31'b0, wide_counters__counter_b_msb__cnt_decr_val[gv_a]}; + end + end + + + /************************************** + * Assign all fields to signal to Mux * + **************************************/ + // Assign all fields. Fields that are not readable are tied to 0. + assign wide_counters__counter_b_msb_data_mux_in[gv_a] = {wide_counters__counter_b_msb__cnt_q[gv_a]}; + + // Internal registers are ready immediately + assign wide_counters__counter_b_msb_rdy_mux_in[gv_a] = 1'b1; + + // Return an error if *no* read and *no* write was succesful. If some bits + // cannot be read/written but others are succesful, don't return and error + // Hence, as long as one action can be succesful, no error will be returned. + assign wide_counters__counter_b_msb_err_mux_in[gv_a] = !((widget_if.r_vld && (|widget_if.byte_en[3:0])) || (widget_if.w_vld && (|widget_if.byte_en[3:0]))); +end // of for loop with iterator gv_a +endgenerate + + +/******************************************************************* +/******************************************************************* +/* REGISTER : counter_a_threshold +/* DIMENSION : 0 +/* DEPTHS (per dimension): [] +/******************************************************************* +/*******************************************************************/ + +logic counter_a_threshold_active ; +logic counter_a_threshold_sw_wr ; +logic [31:0] counter_a_threshold_data_mux_in ; +logic counter_a_threshold_rdy_mux_in ; +logic counter_a_threshold_err_mux_in ; +logic [31:0] counter_a_threshold__threshold_q; + + +// Register-activation for 'counter_a_threshold' +assign counter_a_threshold_active = widget_if.addr == 0; +assign counter_a_threshold_sw_wr = counter_a_threshold_active && widget_if.w_vld; + +//-----------------FIELD SUMMARY----------------- +// name : threshold (counter_a_threshold[31:0]) +// access : hw = na +// sw = rw (precedence) +// reset : active_low / asynchronous +// flags : ['sw'] +// external : False +// storage type : StorageType.FLOPS +//----------------------------------------------- + +always_ff @(posedge clk or negedge rst_async_n) +if (!rst_async_n) +begin + counter_a_threshold__threshold_q <= 32'd4294967295; +end +else +begin + if (counter_a_threshold_sw_wr) + begin + if (widget_if.byte_en[0]) + counter_a_threshold__threshold_q[7:0] <= widget_if.w_data[7:0]; + if (widget_if.byte_en[1]) + counter_a_threshold__threshold_q[15:8] <= widget_if.w_data[15:8]; + if (widget_if.byte_en[2]) + counter_a_threshold__threshold_q[23:16] <= widget_if.w_data[23:16]; + if (widget_if.byte_en[3]) + counter_a_threshold__threshold_q[31:24] <= widget_if.w_data[31:24]; + end +end // of counter_a_threshold__threshold's always_ff + + + + +/************************************** + * Assign all fields to signal to Mux * + **************************************/ +// Assign all fields. Fields that are not readable are tied to 0. +assign counter_a_threshold_data_mux_in = {counter_a_threshold__threshold_q}; + +// Internal registers are ready immediately +assign counter_a_threshold_rdy_mux_in = 1'b1; + +// Return an error if *no* read and *no* write was succesful. If some bits +// cannot be read/written but others are succesful, don't return and error +// Hence, as long as one action can be succesful, no error will be returned. +assign counter_a_threshold_err_mux_in = !((widget_if.r_vld && (|widget_if.byte_en[3:0])) || (widget_if.w_vld && (|widget_if.byte_en[3:0]))); + +/******************************************************************* +/******************************************************************* +/* REGISTER : counter_a +/* DIMENSION : 0 +/* DEPTHS (per dimension): [] +/******************************************************************* +/*******************************************************************/ + +/**REGISTER DESCRIPTION********************************************* +Saturating counter that can be cleared when software writes to +the field, has a configurable counter, and can increment and +decrement. + +When you want a purely incrementing or decrementing counter, set +incrval/decrval to 0. +/*******************************************************************/ +logic counter_a_active ; +logic counter_a_sw_wr ; +logic [31:0] counter_a_data_mux_in ; +logic counter_a_rdy_mux_in ; +logic counter_a_err_mux_in ; +logic [31:0] counter_a__cnt_q ; +logic counter_a__cnt_update_cnt ; +logic [31:0] counter_a__cnt_next ; +logic [0:0] counter_a__cnt_incr_val ; +logic [0:0] counter_a__cnt_decr_val ; +logic counter_a__cnt_incr_sat ; +logic counter_a__cnt_decr_sat ; +logic counter_a__cnt_overflow_int; + + +// Register-activation for 'counter_a' +assign counter_a_active = widget_if.addr == 4; +assign counter_a_sw_wr = counter_a_active && widget_if.w_vld; + +//-----------------FIELD SUMMARY----------------- +// name : cnt (counter_a[31:0]) +// access : hw = rw +// sw = rw (precedence) +// reset : active_low / asynchronous +// flags : ['sw', 'onwrite', 'counter', 'incrsaturate', 'saturate', 'decrsaturate', 'overflow', 'threshold', 'incrthreshold'] +// external : False +// storage type : StorageType.FLOPS +//----------------------------------------------- + +always_ff @(posedge clk or negedge rst_async_n) +if (!rst_async_n) +begin + counter_a__cnt_q <= 32'd0; +end +else +begin + if (counter_a_sw_wr) + begin + if (widget_if.byte_en[0]) // wclr property + counter_a__cnt_q[7:0] <= 8'b0; + if (widget_if.byte_en[1]) // wclr property + counter_a__cnt_q[15:8] <= 8'b0; + if (widget_if.byte_en[2]) // wclr property + counter_a__cnt_q[23:16] <= 8'b0; + if (widget_if.byte_en[3]) // wclr property + counter_a__cnt_q[31:24] <= 8'b0; + end + else + if (counter_a__cnt_incr || counter_a__cnt_decr) + counter_a__cnt_q <= counter_a__cnt_next; +end // of counter_a__cnt's always_ff + +// Connect register to hardware output port +assign counter_a__cnt_r = counter_a__cnt_q; + + +/*********************** + * Counter Combo Logic * + ***********************/ +assign counter_a__cnt_incr_val = 1; +assign counter_a__cnt_decr_val = 1; + +// Determine whether the counter is saturated +// The signal is tied if the counter is not saturating +// in the respective direction +assign counter_a__cnt_incr_sat = {1'b0, counter_a__cnt_q} + ({33{counter_a__cnt_incr}} & {32'b0, counter_a__cnt_incr_val}) - ({33{counter_a__cnt_decr}} & {32'b0, counter_a__cnt_decr_val}) > {1'b0, 32'd4294967295}; +assign counter_a__cnt_decr_sat = {1'b0, counter_a__cnt_q} + ({33{counter_a__cnt_incr}} & {32'b0, counter_a__cnt_incr_val}) < {1'b0, 32'd0} + ({33{counter_a__cnt_decr}} & {32'b0, counter_a__cnt_decr_val}); + +// Define threshold signals (similar to overflow, but for a user specified value) +assign counter_a__cnt_incr_thr = {1'b0, counter_a__cnt_q} + ({33{counter_a__cnt_incr}} & {32'b0, counter_a__cnt_incr_val}) - ({33{counter_a__cnt_decr}} & {32'b0, counter_a__cnt_decr_val}) >= {1'b0, counter_a_threshold__threshold_q}; + +// Logic to determine occurance of an overflow +assign counter_a__cnt_overflow_int = {1'b0, counter_a__cnt_q} + ({33{counter_a__cnt_incr}} & {32'b0, counter_a__cnt_incr_val}) - ({33{counter_a__cnt_decr}} & {32'b0, counter_a__cnt_decr_val}) > {1'b0, 32'd4294967295}; +assign counter_a__cnt_overflow = counter_a__cnt_incr && counter_a__cnt_overflow_int; + +// Combinational logic that implements counter +// Note that the three branches for all three possibilities +// are implemented but that either the _incr or the _decr value +// might be tied to 0. +always_comb +begin + counter_a__cnt_next = counter_a__cnt_q; + + if (counter_a__cnt_incr && counter_a__cnt_decr) + begin + if (!counter_a__cnt_incr_sat && !counter_a__cnt_decr_sat) + begin + counter_a__cnt_next += {31'b0, counter_a__cnt_incr_val}; + counter_a__cnt_next -= {31'b0, counter_a__cnt_decr_val}; + end + end + else if (counter_a__cnt_incr) + begin + if (!counter_a__cnt_incr_sat) + counter_a__cnt_next += {31'b0, counter_a__cnt_incr_val}; + end + else if (counter_a__cnt_decr) + begin + if (!counter_a__cnt_decr_sat) + counter_a__cnt_next -= {31'b0, counter_a__cnt_decr_val}; + end +end + + +/************************************** + * Assign all fields to signal to Mux * + **************************************/ +// Assign all fields. Fields that are not readable are tied to 0. +assign counter_a_data_mux_in = {counter_a__cnt_q}; + +// Internal registers are ready immediately +assign counter_a_rdy_mux_in = 1'b1; + +// Return an error if *no* read and *no* write was succesful. If some bits +// cannot be read/written but others are succesful, don't return and error +// Hence, as long as one action can be succesful, no error will be returned. +assign counter_a_err_mux_in = !((widget_if.r_vld && (|widget_if.byte_en[3:0])) || (widget_if.w_vld && (|widget_if.byte_en[3:0]))); + +/******************************************************************* +/******************************************************************* +/* REGISTER : counter_b_overflow_intr +/* DIMENSION : 0 +/* DEPTHS (per dimension): [] +/******************************************************************* +/*******************************************************************/ + +logic counter_b_overflow_intr_active ; +logic counter_b_overflow_intr_sw_wr ; +logic [31:0] counter_b_overflow_intr_data_mux_in ; +logic counter_b_overflow_intr_rdy_mux_in ; +logic counter_b_overflow_intr_err_mux_in ; +logic [0:0] counter_b_overflow_intr__ovrflw_1_q ; +logic [0:0] counter_b_overflow_intr__ovrflw_1_sticky_latch; +logic [0:0] counter_b_overflow_intr__ovrflw_0_q ; +logic [0:0] counter_b_overflow_intr__ovrflw_0_sticky_latch; + + +// Register-activation for 'counter_b_overflow_intr' +assign counter_b_overflow_intr_active = widget_if.addr == 24; +assign counter_b_overflow_intr_sw_wr = counter_b_overflow_intr_active && widget_if.w_vld; + +//-----------------FIELD SUMMARY----------------- +// name : ovrflw_1 (counter_b_overflow_intr[0:0]) +// access : hw = rw +// sw = rw (precedence) +// reset : active_low / asynchronous +// flags : ['desc', 'intr', 'intr type', 'next'] +// external : False +// storage type : StorageType.FLOPS +//----------------------------------------------- + +/********************DESCRIPTION***************** +Interrupt if the msb-part of counter_b[2] overflowed. +/************************************************/ +always_ff @(posedge clk or negedge rst_async_n) +if (!rst_async_n) +begin + counter_b_overflow_intr__ovrflw_1_q <= 1'd0; +end +else +begin + if (counter_b_overflow_intr_sw_wr) + begin + if (widget_if.byte_en[0]) + counter_b_overflow_intr__ovrflw_1_q[0:0] <= widget_if.w_data[0:0]; + end + else + begin + for (int i = 0; i < 1; i++) + begin + if (counter_b_overflow_intr__ovrflw_1_sticky_latch[i]) + begin + // Stickybit. Keep value until software clears it + counter_b_overflow_intr__ovrflw_1_q[i] <= 1'b1; + end + end + end +end // of counter_b_overflow_intr__ovrflw_1's always_ff + +// Define signal that causes the interrupt to be set (level-type interrupt) +assign counter_b_overflow_intr__ovrflw_1_sticky_latch = wide_counters__counter_b_msb__cnt_overflow[1]; + + + +//-----------------FIELD SUMMARY----------------- +// name : ovrflw_0 (counter_b_overflow_intr[1:1]) +// access : hw = rw +// sw = rw (precedence) +// reset : active_low / asynchronous +// flags : ['desc', 'intr', 'intr type', 'next'] +// external : False +// storage type : StorageType.FLOPS +//----------------------------------------------- + +/********************DESCRIPTION***************** +Interrupt if the msb-part of counter_b[2] overflowed. +/************************************************/ +always_ff @(posedge clk or negedge rst_async_n) +if (!rst_async_n) +begin + counter_b_overflow_intr__ovrflw_0_q <= 1'd0; +end +else +begin + if (counter_b_overflow_intr_sw_wr) + begin + if (widget_if.byte_en[0]) + counter_b_overflow_intr__ovrflw_0_q[0:0] <= widget_if.w_data[1:1]; + end + else + begin + for (int i = 0; i < 1; i++) + begin + if (counter_b_overflow_intr__ovrflw_0_sticky_latch[i]) + begin + // Stickybit. Keep value until software clears it + counter_b_overflow_intr__ovrflw_0_q[i] <= 1'b1; + end + end + end +end // of counter_b_overflow_intr__ovrflw_0's always_ff + +// Define signal that causes the interrupt to be set (level-type interrupt) +assign counter_b_overflow_intr__ovrflw_0_sticky_latch = wide_counters__counter_b_msb__cnt_overflow[0]; + + +/************************************** + * Register contains interrupts * + **************************************/ +// Register has at least one interrupt field +assign counter_b_overflow_intr_intr = |(counter_b_overflow_intr__ovrflw_1_q) || |(counter_b_overflow_intr__ovrflw_0_q); + + +/************************************** + * Assign all fields to signal to Mux * + **************************************/ +// Assign all fields. Fields that are not readable are tied to 0. +assign counter_b_overflow_intr_data_mux_in = {{30{1'b0}}, counter_b_overflow_intr__ovrflw_0_q, counter_b_overflow_intr__ovrflw_1_q}; + +// Internal registers are ready immediately +assign counter_b_overflow_intr_rdy_mux_in = 1'b1; + +// Return an error if *no* read and *no* write was succesful. If some bits +// cannot be read/written but others are succesful, don't return and error +// Hence, as long as one action can be succesful, no error will be returned. +assign counter_b_overflow_intr_err_mux_in = !((widget_if.r_vld && (widget_if.byte_en[0])) || (widget_if.w_vld && (widget_if.byte_en[0]))); + +// Read multiplexer +always_comb +begin + unique case (1'b1) + wide_counters__counter_b_lsb_active[0]: + begin + widget_if.r_data = wide_counters__counter_b_lsb_data_mux_in[0]; + widget_if.err = wide_counters__counter_b_lsb_err_mux_in[0]; + widget_if.rdy = wide_counters__counter_b_lsb_rdy_mux_in[0]; + end + wide_counters__counter_b_lsb_active[1]: + begin + widget_if.r_data = wide_counters__counter_b_lsb_data_mux_in[1]; + widget_if.err = wide_counters__counter_b_lsb_err_mux_in[1]; + widget_if.rdy = wide_counters__counter_b_lsb_rdy_mux_in[1]; + end + wide_counters__counter_b_msb_active[0]: + begin + widget_if.r_data = wide_counters__counter_b_msb_data_mux_in[0]; + widget_if.err = wide_counters__counter_b_msb_err_mux_in[0]; + widget_if.rdy = wide_counters__counter_b_msb_rdy_mux_in[0]; + end + wide_counters__counter_b_msb_active[1]: + begin + widget_if.r_data = wide_counters__counter_b_msb_data_mux_in[1]; + widget_if.err = wide_counters__counter_b_msb_err_mux_in[1]; + widget_if.rdy = wide_counters__counter_b_msb_rdy_mux_in[1]; + end + counter_a_threshold_active: + begin + widget_if.r_data = counter_a_threshold_data_mux_in; + widget_if.err = counter_a_threshold_err_mux_in; + widget_if.rdy = counter_a_threshold_rdy_mux_in; + end + counter_a_active: + begin + widget_if.r_data = counter_a_data_mux_in; + widget_if.err = counter_a_err_mux_in; + widget_if.rdy = counter_a_rdy_mux_in; + end + counter_b_overflow_intr_active: + begin + widget_if.r_data = counter_b_overflow_intr_data_mux_in; + widget_if.err = counter_b_overflow_intr_err_mux_in; + widget_if.rdy = counter_b_overflow_intr_rdy_mux_in; + end + default: + begin + // If the address is not found, return an error + widget_if.r_data = 0; + widget_if.err = 1; + widget_if.rdy = widget_if.r_vld || widget_if.w_vld; + end + endcase +end +endmodule diff --git a/examples/counters/srdl2sv_out/srdl2sv_amba3ahblite.sv b/examples/counters/srdl2sv_out/srdl2sv_amba3ahblite.sv new file mode 100644 index 0000000..d1598f9 --- /dev/null +++ b/examples/counters/srdl2sv_out/srdl2sv_amba3ahblite.sv @@ -0,0 +1,312 @@ +/* + * 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 srdl2sv_amba3ahblite #( + parameter bit FLOP_REGISTER_IF = 0, + parameter BUS_BITS = 32, + parameter NO_BYTE_ENABLE = 0 +) +( + // Bus protocol + input HCLK, + input HRESETn, + input HSEL, + input [31:0] HADDR, + input HWRITE, + input [ 2:0] HSIZE, + input [ 3:0] HPROT, // Might be used in the future together with an RDL UDP + input [ 1:0] HTRANS, + input [BUS_BITS-1:0] HWDATA, + + output logic HREADYOUT, + output logic HRESP, + output logic [BUS_BITS-1:0] HRDATA, + + // Interface to internal logic + srdl2sv_widget_if.widget widget_if +); + + localparam BUS_BYTES = BUS_BITS/8; + localparam BUS_BYTES_W = $clog2(BUS_BYTES); + + /*********************** + * Define enums + ***********************/ + typedef enum logic [2:0] { + SINGLE = 3'b000, + INCR = 3'b001, + WRAP4 = 3'b010, + INCR4 = 3'b011, + WRAP8 = 3'b100, + INCR8 = 3'b101, + WRAP16 = 3'b110, + INCR16 = 3'b111 + } HBURST_t; + + typedef enum logic [1:0] { + IDLE = 2'b00, + BUSY = 2'b01, + NONSEQ = 2'b10, + SEQ = 2'b11 + } HTRANS_t; + + typedef enum logic { + OKAY = 1'b0, + ERROR = 1'b1 + } HRESP_t; + + typedef enum logic { + READ = 1'b0, + WRITE = 1'b1 + } OP_t; + + typedef enum logic [1:0] { + FSM_IDLE = 2'b00, + FSM_TRANS = 2'b01, + FSM_ERR_0 = 2'b10, + FSM_ERR_1 = 2'b11 + } fsm_t; + + /**************************** + * Determine current address + ****************************/ + logic [31:0] HADDR_q; + logic [2:0] HSIZE_q; + OP_t operation_q; + + wire addr_err = HADDR % (32'b1 << HSIZE) != 32'b0; + + always_ff @ (posedge HCLK) + begin + case (HTRANS) + IDLE: ;// Do nothing + BUSY: ;// Do nothing + NONSEQ: + begin + // When a transfer is extended it has the side-effecxt + // of extending the address phase of the next transfer + if (HREADYOUT) + begin + HADDR_q <= HADDR; + HSIZE_q <= HSIZE; + operation_q <= HWRITE ? WRITE : READ; + end + end + SEQ: + begin + if (HREADYOUT) + begin + HADDR_q <= HADDR; + HSIZE_q <= HSIZE; + end + end + endcase + end + + /**************************** + * Statemachine + ****************************/ + logic [BUS_BITS-1:0] HRDATA_temp; + fsm_t fsm_next, fsm_q; + + always_comb + begin + // Defaults + HREADYOUT = 1'b1; + HRESP = OKAY; + + // When reading back, the data of the bit that was accessed over the bus + // should be at byte 0 of the HRDATA bus and bits that were not accessed + // should be masked with 0s. + HRDATA_temp = widget_if.r_data >> (8*HADDR_q[BUS_BYTES_W-1:0]); + + for (int i = 0; i < BUS_BYTES; i++) + if (i < (1 << HSIZE_q)) + HRDATA[8*(i+1)-1 -: 8] = HRDATA_temp[8*(i+1)-1 -: 8]; + else + HRDATA[8*(i+1)-1 -: 8] = 8'b0; + + widget_if_w_vld_next = 0; + widget_if_r_vld_next = 0; + fsm_next = fsm_q; + + case (fsm_q) + default: // FSM_IDLE + begin + if (HSEL && HTRANS > BUSY) + begin + if (addr_err) + // In case the address is illegal, switch to an error state + fsm_next = FSM_ERR_0; + else if (HTRANS == NONSEQ) + // If NONSEQ, go to NONSEQ state + fsm_next = FSM_TRANS; + else if (HTRANS == SEQ) + // If a SEQ is provided, something is wrong + fsm_next = FSM_ERR_0; + end + end + FSM_TRANS: + begin + HREADYOUT = widget_if.rdy; + widget_if_w_vld_next = operation_q == WRITE; + widget_if_r_vld_next = operation_q == READ; + + if (HTRANS == BUSY) + begin + // Wait + fsm_next = FSM_TRANS; + end + else if (widget_if.err && widget_if.rdy) + begin + HREADYOUT = 0; + HRESP = ERROR; + fsm_next = FSM_ERR_1; + end + else if (HTRANS == NONSEQ) + begin + // Another unrelated access is coming + fsm_next = FSM_TRANS; + end + else if (HTRANS == SEQ) + begin + // Another part of the burst is coming + fsm_next = FSM_TRANS; + end + else if (HTRANS == IDLE) + begin + // All done, wrapping things up! + fsm_next = widget_if.rdy ? FSM_IDLE : FSM_TRANS; + end + end + FSM_ERR_0: + begin + HREADYOUT = 0; + + if (HTRANS == BUSY) + begin + // Slaves must always provide a zero wait state OKAY response + // to BUSY transfers and the transfer must be ignored by the slave. + HRESP = OKAY; + fsm_next = FSM_ERR_0; + end + else + begin + HRESP = ERROR; + fsm_next = FSM_ERR_1; + end + end + FSM_ERR_1: + begin + if (HTRANS == BUSY) + begin + // Slaves must always provide a zero wait state OKAY response + // to BUSY transfers and the transfer must be ignored by the slave. + HREADYOUT = 0; + HRESP = OKAY; + fsm_next = FSM_ERR_0; + end + else + begin + HREADYOUT = 1; + HRESP = ERROR; + + fsm_next = FSM_IDLE; + end + end + endcase + end + + + always_ff @ (posedge HCLK or negedge HRESETn) + if (!HRESETn) + fsm_q <= FSM_IDLE; + else + fsm_q <= fsm_next; + + /*** + * Determine the number of active bytes + ***/ + logic [BUS_BYTES-1:0] HSIZE_bitfielded; + logic [BUS_BYTES-1:0] widget_if_byte_en_next; + logic widget_if_w_vld_next; + logic widget_if_r_vld_next; + + generate + if (NO_BYTE_ENABLE) + begin + assign widget_if_byte_en_next = {BUS_BYTES{1'b1}}; + end + else + begin + always_comb + begin + for (int i = 0; i < BUS_BYTES; i++) + HSIZE_bitfielded[i] = i < (1 << HSIZE_q); + + // Shift if not the full bus is accessed + widget_if_byte_en_next = HSIZE_bitfielded << (HADDR_q % BUS_BYTES); + end + end + endgenerate + + /*** + * Drive interface to registers + ***/ + generate + if (FLOP_REGISTER_IF) + begin + always_ff @ (posedge HCLK or negedge HRESETn) + if (!HRESETn) + begin + widget_if.w_vld <= 1'b0; + widget_if.r_vld <= 1'b0; + end + else + begin + widget_if.w_vld <= widget_if_w_vld_next; + widget_if.r_vld <= widget_if_r_vld_next; + end + + always_ff @ (posedge HCLK) + begin + widget_if.addr <= {HADDR_q[31:BUS_BYTES_W], {BUS_BYTES_W{1'b0}}}; + widget_if.w_data <= HWDATA << (8*HADDR_q[BUS_BYTES_W-1:0]); + widget_if.byte_en <= widget_if_byte_en_next; + end + end + else + begin + assign widget_if.w_vld = widget_if_w_vld_next; + assign widget_if.r_vld = widget_if_r_vld_next; + assign widget_if.addr = {HADDR_q[31:BUS_BYTES_W], {BUS_BYTES_W{1'b0}}}; + assign widget_if.w_data = HWDATA << (8*HADDR_q[BUS_BYTES_W-1:0]); + assign widget_if.byte_en = widget_if_byte_en_next; + end + endgenerate + +endmodule + + diff --git a/examples/counters/srdl2sv_out/srdl2sv_widget_if.sv b/examples/counters/srdl2sv_out/srdl2sv_widget_if.sv new file mode 100644 index 0000000..b85afc4 --- /dev/null +++ b/examples/counters/srdl2sv_out/srdl2sv_widget_if.sv @@ -0,0 +1,30 @@ +interface srdl2sv_widget_if #( + parameter ADDR_W = 32, + parameter DATA_W = 32 +); + + localparam DATA_BYTES = DATA_W >> 3; + + logic [ADDR_W-1:0] addr; + logic [DATA_W-1:0] w_data; + logic w_vld; + logic r_vld; + logic [DATA_BYTES-1:0] byte_en; + + logic [DATA_W-1:0] r_data; + logic rdy; + logic err; + + modport widget ( + output addr, + output w_data, + output w_vld, + output r_vld, + output byte_en, + + input r_data, + input rdy, + input err + ); +endinterface +