From 5a00d48c34ebd3c60934943d22bdd4aee57f97a5 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 28 Oct 2021 22:55:28 -0700 Subject: [PATCH] Add RDL example with compiled hierarchical regfiles --- .../hierarchical_regfiles.rdl | 38 + .../srdl2sv_out/hierarchical_regfiles.sv | 779 ++++++++++++++++++ .../srdl2sv_out/srdl2sv_amba3ahblite.sv | 309 +++++++ .../srdl2sv_out/srdl2sv_widget_if.sv | 30 + 4 files changed, 1156 insertions(+) create mode 100644 examples/hierarchical_regfiles/hierarchical_regfiles.rdl create mode 100644 examples/hierarchical_regfiles/srdl2sv_out/hierarchical_regfiles.sv create mode 100644 examples/hierarchical_regfiles/srdl2sv_out/srdl2sv_amba3ahblite.sv create mode 100644 examples/hierarchical_regfiles/srdl2sv_out/srdl2sv_widget_if.sv diff --git a/examples/hierarchical_regfiles/hierarchical_regfiles.rdl b/examples/hierarchical_regfiles/hierarchical_regfiles.rdl new file mode 100644 index 0000000..a5765da --- /dev/null +++ b/examples/hierarchical_regfiles/hierarchical_regfiles.rdl @@ -0,0 +1,38 @@ +addrmap hierarchical_regfiles { + + regfile { + reg { + field {sw=rw; hw=rw; we;} f1 [15:0]; + field {sw=rw; hw=rw; we;} f2 [31:16]; + } reg_a; + + reg { + field {sw=rw; hw=rw; we;} f1 [15:0]; + field {sw=rw; hw=rw; we;} f2 [31:16]; + } reg_b; + } regfile_1; + + regfile { + // Remove we property and set hw=w. + // Set sw=r for one of the properties to generate a simple wire + reg { + field {sw=r; hw=w;} f1 [15:0]; + field {sw=rw; hw=w;} f2 [31:16]; + } reg_c; + + // Another level of regfile-hierarchy + regfile { + // Remove we property, to show yet another type of register + reg { + field {sw=rw; hw=rw;} f1 [15:0]; + field {sw=rw; hw=rw;} f2 [31:16]; + } reg_d; + } regfile_3 [4][2]; + } regfile_2 [2]; + + // Just a plain old register + reg { + field {sw=rw; hw=rw; we;} f1 [15:0]; + field {sw=rw; hw=rw; we;} f2 [31:16]; + } reg_e; +}; diff --git a/examples/hierarchical_regfiles/srdl2sv_out/hierarchical_regfiles.sv b/examples/hierarchical_regfiles/srdl2sv_out/hierarchical_regfiles.sv new file mode 100644 index 0000000..84a1796 --- /dev/null +++ b/examples/hierarchical_regfiles/srdl2sv_out/hierarchical_regfiles.sv @@ -0,0 +1,779 @@ +/***************************************************************** + * + * ███████╗██████╗ ██████╗ ██╗ ██████╗ ███████╗██╗ ██╗ + * ██╔════╝██╔══██╗██╔══██╗██║ ╚════██╗██╔════╝██║ ██║ + * ███████╗██████╔╝██║ ██║██║ █████╔╝███████╗██║ ██║ + * ╚════██║██╔══██╗██║ ██║██║ ██╔═══╝ ╚════██║╚██╗ ██╔╝ + * ███████║██║ ██║██████╔╝███████╗███████╗███████║ ╚████╔╝ + * ╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚══════╝╚══════╝ ╚═══╝ + * + * 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://git.dennispotter.eu/Dennis/srdl2sv/issues + * + * ===GENERATION INFORMATION====================================== + * + * Generation information: + * - User: : dpotter + * - Time : October 28 2021 22:54:43 + * - Path : /home/dpotter/srdl2sv/examples/hierarchical_regfiles + * - RDL file : ['hierarchical_regfiles.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 + * - Register Bus Type: amba3ahblite + * - Address width : 32 + * - Byte enables : True + * - Descriptions : {'AddrMap': False, 'RegFile': False, 'Memory': False, 'Register': False, 'Field': False} + * + * ===LICENSE OF HIERARCHICAL_REGFILES.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 hierarchical_regfiles + +( + // Resets + + + // 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 logic regfile_1__reg_a__f1_hw_wr , + input logic [15:0] regfile_1__reg_a__f1_in , + input logic regfile_1__reg_a__f2_hw_wr , + input logic [15:0] regfile_1__reg_a__f2_in , + input logic regfile_1__reg_b__f1_hw_wr , + input logic [15:0] regfile_1__reg_b__f1_in , + input logic regfile_1__reg_b__f2_hw_wr , + input logic [15:0] regfile_1__reg_b__f2_in , + input logic [15:0] regfile_2__regfile_3__reg_d__f1_in[2][4][2], + input logic [15:0] regfile_2__regfile_3__reg_d__f2_in[2][4][2], + input logic [15:0] regfile_2__reg_c__f1_in [2], + input logic [15:0] regfile_2__reg_c__f2_in [2], + input logic reg_e__f1_hw_wr , + input logic [15:0] reg_e__f1_in , + input logic reg_e__f2_hw_wr , + input logic [15:0] reg_e__f2_in , + + // Outputs + output HREADYOUT , + output HRESP , + output [32-1:0] HRDATA , + output logic [15:0] regfile_1__reg_a__f1_r , + output logic [15:0] regfile_1__reg_a__f2_r , + output logic [15:0] regfile_1__reg_b__f1_r , + output logic [15:0] regfile_1__reg_b__f2_r , + output logic [15:0] regfile_2__regfile_3__reg_d__f1_r[2][4][2], + output logic [15:0] regfile_2__regfile_3__reg_d__f2_r[2][4][2], + output logic [15:0] reg_e__f1_r , + output logic [15:0] reg_e__f2_r +); + + +// 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, gv_b, gv_c; + +/******************************************************************* + ******************************************************************* + * REGFILE : regfile_1 + * DIMENSION : 0 + * DEPTHS (per dimension): [] + ******************************************************************* + *******************************************************************/ + + +/******************************************************************* +/******************************************************************* +/* REGISTER : reg_a +/* DIMENSION : 0 +/* DEPTHS (per dimension): [] +/******************************************************************* +/*******************************************************************/ + +logic regfile_1__reg_a_active ; +logic regfile_1__reg_a_sw_wr ; +logic [31:0] regfile_1__reg_a_data_mux_in; +logic regfile_1__reg_a_rdy_mux_in ; +logic regfile_1__reg_a_err_mux_in ; +logic [15:0] regfile_1__reg_a__f1_q ; +logic [15:0] regfile_1__reg_a__f2_q ; + + +// Register-activation for 'regfile_1__reg_a' +assign regfile_1__reg_a_active = widget_if.addr == 0; +assign regfile_1__reg_a_sw_wr = regfile_1__reg_a_active && widget_if.w_vld; + +//-----------------FIELD SUMMARY----------------- +// name : f1 (regfile_1__reg_a[15:0]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw', 'we'] +// external : False +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (regfile_1__reg_a_sw_wr) + begin + if (widget_if.byte_en[0]) + regfile_1__reg_a__f1_q[7:0] <= widget_if.w_data[7:0]; + if (widget_if.byte_en[1]) + regfile_1__reg_a__f1_q[15:8] <= widget_if.w_data[15:8]; + end + else + if (regfile_1__reg_a__f1_hw_wr) + regfile_1__reg_a__f1_q <= regfile_1__reg_a__f1_in; +end // of regfile_1__reg_a__f1's always_ff + +// Connect register to hardware output port +assign regfile_1__reg_a__f1_r = regfile_1__reg_a__f1_q; + + + +//-----------------FIELD SUMMARY----------------- +// name : f2 (regfile_1__reg_a[31:16]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw', 'we'] +// external : False +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (regfile_1__reg_a_sw_wr) + begin + if (widget_if.byte_en[2]) + regfile_1__reg_a__f2_q[7:0] <= widget_if.w_data[23:16]; + if (widget_if.byte_en[3]) + regfile_1__reg_a__f2_q[15:8] <= widget_if.w_data[31:24]; + end + else + if (regfile_1__reg_a__f2_hw_wr) + regfile_1__reg_a__f2_q <= regfile_1__reg_a__f2_in; +end // of regfile_1__reg_a__f2's always_ff + +// Connect register to hardware output port +assign regfile_1__reg_a__f2_r = regfile_1__reg_a__f2_q; + + + + +/************************************** + * Assign all fields to signal to Mux * + **************************************/ +// Assign all fields. Fields that are not readable are tied to 0. +assign regfile_1__reg_a_data_mux_in = {regfile_1__reg_a__f2_q, regfile_1__reg_a__f1_q}; + +// Internal registers are ready immediately +assign regfile_1__reg_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 regfile_1__reg_a_err_mux_in = !((widget_if.r_vld && (widget_if.byte_en[0] || widget_if.byte_en[1] || widget_if.byte_en[2] || widget_if.byte_en[3])) || (widget_if.w_vld && (widget_if.byte_en[0] || widget_if.byte_en[1] || widget_if.byte_en[2] || widget_if.byte_en[3]))); + +/******************************************************************* +/******************************************************************* +/* REGISTER : reg_b +/* DIMENSION : 0 +/* DEPTHS (per dimension): [] +/******************************************************************* +/*******************************************************************/ + +logic regfile_1__reg_b_active ; +logic regfile_1__reg_b_sw_wr ; +logic [31:0] regfile_1__reg_b_data_mux_in; +logic regfile_1__reg_b_rdy_mux_in ; +logic regfile_1__reg_b_err_mux_in ; +logic [15:0] regfile_1__reg_b__f1_q ; +logic [15:0] regfile_1__reg_b__f2_q ; + + +// Register-activation for 'regfile_1__reg_b' +assign regfile_1__reg_b_active = widget_if.addr == 4; +assign regfile_1__reg_b_sw_wr = regfile_1__reg_b_active && widget_if.w_vld; + +//-----------------FIELD SUMMARY----------------- +// name : f1 (regfile_1__reg_b[15:0]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw', 'we'] +// external : False +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (regfile_1__reg_b_sw_wr) + begin + if (widget_if.byte_en[0]) + regfile_1__reg_b__f1_q[7:0] <= widget_if.w_data[7:0]; + if (widget_if.byte_en[1]) + regfile_1__reg_b__f1_q[15:8] <= widget_if.w_data[15:8]; + end + else + if (regfile_1__reg_b__f1_hw_wr) + regfile_1__reg_b__f1_q <= regfile_1__reg_b__f1_in; +end // of regfile_1__reg_b__f1's always_ff + +// Connect register to hardware output port +assign regfile_1__reg_b__f1_r = regfile_1__reg_b__f1_q; + + + +//-----------------FIELD SUMMARY----------------- +// name : f2 (regfile_1__reg_b[31:16]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw', 'we'] +// external : False +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (regfile_1__reg_b_sw_wr) + begin + if (widget_if.byte_en[2]) + regfile_1__reg_b__f2_q[7:0] <= widget_if.w_data[23:16]; + if (widget_if.byte_en[3]) + regfile_1__reg_b__f2_q[15:8] <= widget_if.w_data[31:24]; + end + else + if (regfile_1__reg_b__f2_hw_wr) + regfile_1__reg_b__f2_q <= regfile_1__reg_b__f2_in; +end // of regfile_1__reg_b__f2's always_ff + +// Connect register to hardware output port +assign regfile_1__reg_b__f2_r = regfile_1__reg_b__f2_q; + + + + +/************************************** + * Assign all fields to signal to Mux * + **************************************/ +// Assign all fields. Fields that are not readable are tied to 0. +assign regfile_1__reg_b_data_mux_in = {regfile_1__reg_b__f2_q, regfile_1__reg_b__f1_q}; + +// Internal registers are ready immediately +assign regfile_1__reg_b_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 regfile_1__reg_b_err_mux_in = !((widget_if.r_vld && (widget_if.byte_en[0] || widget_if.byte_en[1] || widget_if.byte_en[2] || widget_if.byte_en[3])) || (widget_if.w_vld && (widget_if.byte_en[0] || widget_if.byte_en[1] || widget_if.byte_en[2] || widget_if.byte_en[3]))); +/******************************************************************* + ******************************************************************* + * REGFILE : regfile_2 + * DIMENSION : 1 + * DEPTHS (per dimension): [2] + ******************************************************************* + *******************************************************************/ + + +// Variables of register 'reg_d' +logic regfile_2__regfile_3__reg_d_active [2][4][2]; +logic regfile_2__regfile_3__reg_d_sw_wr [2][4][2]; +logic [31:0] regfile_2__regfile_3__reg_d_data_mux_in[2][4][2]; +logic regfile_2__regfile_3__reg_d_rdy_mux_in [2][4][2]; +logic regfile_2__regfile_3__reg_d_err_mux_in [2][4][2]; +logic [15:0] regfile_2__regfile_3__reg_d__f1_q [2][4][2]; +logic [15:0] regfile_2__regfile_3__reg_d__f2_q [2][4][2]; + +// Variables of register 'reg_c' +logic regfile_2__reg_c_active [2]; +logic regfile_2__reg_c_sw_wr [2]; +logic [31:0] regfile_2__reg_c_data_mux_in[2]; +logic regfile_2__reg_c_rdy_mux_in [2]; +logic regfile_2__reg_c_err_mux_in [2]; +logic [15:0] regfile_2__reg_c__f1_q [2]; +logic [15:0] regfile_2__reg_c__f2_q [2]; + +generate +for (gv_a = 0; gv_a < 2; gv_a++) +begin + /******************************************************************* + ******************************************************************* + * REGFILE : regfile_3 + * DIMENSION : 2 + * DEPTHS (per dimension): [4][2] + ******************************************************************* + *******************************************************************/ + + for (gv_b = 0; gv_b < 4; gv_b++) + begin + for (gv_c = 0; gv_c < 2; gv_c++) + begin + + /******************************************************************* + /******************************************************************* + /* REGISTER : reg_d + /* DIMENSION : 0 + /* DEPTHS (per dimension): [] + /******************************************************************* + /*******************************************************************/ + + + // Register-activation for 'regfile_2__regfile_3__reg_d' + assign regfile_2__regfile_3__reg_d_active[gv_a][gv_b][gv_c] = widget_if.addr == 68+(gv_a*36+gv_b*8+gv_c*4); + assign regfile_2__regfile_3__reg_d_sw_wr[gv_a][gv_b][gv_c] = regfile_2__regfile_3__reg_d_active[gv_a][gv_b][gv_c] && widget_if.w_vld; + + //-----------------FIELD SUMMARY----------------- + // name : f1 (regfile_2__regfile_3__reg_d[15:0]) + // access : hw = rw + // sw = rw (precedence) + // reset : - / - + // flags : ['sw'] + // external : False + //----------------------------------------------- + + always_ff @(posedge clk) + begin + if (regfile_2__regfile_3__reg_d_sw_wr[gv_a][gv_b][gv_c]) + begin + if (widget_if.byte_en[0]) + regfile_2__regfile_3__reg_d__f1_q[gv_a][gv_b][gv_c][7:0] <= widget_if.w_data[7:0]; + if (widget_if.byte_en[1]) + regfile_2__regfile_3__reg_d__f1_q[gv_a][gv_b][gv_c][15:8] <= widget_if.w_data[15:8]; + end + else + // we or wel property not set + regfile_2__regfile_3__reg_d__f1_q[gv_a][gv_b][gv_c] <= regfile_2__regfile_3__reg_d__f1_in[gv_a][gv_b][gv_c]; + end // of regfile_2__regfile_3__reg_d__f1's always_ff + + // Connect register to hardware output port + assign regfile_2__regfile_3__reg_d__f1_r[gv_a][gv_b][gv_c] = regfile_2__regfile_3__reg_d__f1_q[gv_a][gv_b][gv_c]; + + + + //-----------------FIELD SUMMARY----------------- + // name : f2 (regfile_2__regfile_3__reg_d[31:16]) + // access : hw = rw + // sw = rw (precedence) + // reset : - / - + // flags : ['sw'] + // external : False + //----------------------------------------------- + + always_ff @(posedge clk) + begin + if (regfile_2__regfile_3__reg_d_sw_wr[gv_a][gv_b][gv_c]) + begin + if (widget_if.byte_en[2]) + regfile_2__regfile_3__reg_d__f2_q[gv_a][gv_b][gv_c][7:0] <= widget_if.w_data[23:16]; + if (widget_if.byte_en[3]) + regfile_2__regfile_3__reg_d__f2_q[gv_a][gv_b][gv_c][15:8] <= widget_if.w_data[31:24]; + end + else + // we or wel property not set + regfile_2__regfile_3__reg_d__f2_q[gv_a][gv_b][gv_c] <= regfile_2__regfile_3__reg_d__f2_in[gv_a][gv_b][gv_c]; + end // of regfile_2__regfile_3__reg_d__f2's always_ff + + // Connect register to hardware output port + assign regfile_2__regfile_3__reg_d__f2_r[gv_a][gv_b][gv_c] = regfile_2__regfile_3__reg_d__f2_q[gv_a][gv_b][gv_c]; + + + + + /************************************** + * Assign all fields to signal to Mux * + **************************************/ + // Assign all fields. Fields that are not readable are tied to 0. + assign regfile_2__regfile_3__reg_d_data_mux_in[gv_a][gv_b][gv_c] = {regfile_2__regfile_3__reg_d__f2_q[gv_a][gv_b][gv_c], regfile_2__regfile_3__reg_d__f1_q[gv_a][gv_b][gv_c]}; + + // Internal registers are ready immediately + assign regfile_2__regfile_3__reg_d_rdy_mux_in[gv_a][gv_b][gv_c] = 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 regfile_2__regfile_3__reg_d_err_mux_in[gv_a][gv_b][gv_c] = !((widget_if.r_vld && (widget_if.byte_en[0] || widget_if.byte_en[1] || widget_if.byte_en[2] || widget_if.byte_en[3])) || (widget_if.w_vld && (widget_if.byte_en[0] || widget_if.byte_en[1] || widget_if.byte_en[2] || widget_if.byte_en[3]))); + end // of for loop with iterator gv_b + end // of for loop with iterator gv_a + + /******************************************************************* + /******************************************************************* + /* REGISTER : reg_c + /* DIMENSION : 0 + /* DEPTHS (per dimension): [] + /******************************************************************* + /*******************************************************************/ + + + // Register-activation for 'regfile_2__reg_c' + assign regfile_2__reg_c_active[gv_a] = widget_if.addr == 64+(gv_a*36); + assign regfile_2__reg_c_sw_wr[gv_a] = regfile_2__reg_c_active[gv_a] && widget_if.w_vld; + + //-----------------FIELD SUMMARY----------------- + // name : f1 (regfile_2__reg_c[15:0]) + // access : hw = w + // sw = r (precedence) + // reset : - / - + // flags : ['sw'] + // external : False + //----------------------------------------------- + + always_ff @(posedge clk) + begin + // we or wel property not set + regfile_2__reg_c__f1_q[gv_a] <= regfile_2__reg_c__f1_in[gv_a]; + end // of regfile_2__reg_c__f1's always_ff + + + + //-----------------FIELD SUMMARY----------------- + // name : f2 (regfile_2__reg_c[31:16]) + // access : hw = w + // sw = rw (precedence) + // reset : - / - + // flags : ['sw'] + // external : False + //----------------------------------------------- + + always_ff @(posedge clk) + begin + if (regfile_2__reg_c_sw_wr[gv_a]) + begin + if (widget_if.byte_en[2]) + regfile_2__reg_c__f2_q[gv_a][7:0] <= widget_if.w_data[23:16]; + if (widget_if.byte_en[3]) + regfile_2__reg_c__f2_q[gv_a][15:8] <= widget_if.w_data[31:24]; + end + else + // we or wel property not set + regfile_2__reg_c__f2_q[gv_a] <= regfile_2__reg_c__f2_in[gv_a]; + end // of regfile_2__reg_c__f2's always_ff + + + + + /************************************** + * Assign all fields to signal to Mux * + **************************************/ + // Assign all fields. Fields that are not readable are tied to 0. + assign regfile_2__reg_c_data_mux_in[gv_a] = {regfile_2__reg_c__f2_q[gv_a], regfile_2__reg_c__f1_q[gv_a]}; + + // Internal registers are ready immediately + assign regfile_2__reg_c_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 regfile_2__reg_c_err_mux_in[gv_a] = !((widget_if.r_vld && (widget_if.byte_en[0] || widget_if.byte_en[1] || widget_if.byte_en[2] || widget_if.byte_en[3])) || (widget_if.w_vld && (widget_if.byte_en[2] || widget_if.byte_en[3]))); +end // of for loop with iterator gv_a +endgenerate + + +/******************************************************************* +/******************************************************************* +/* REGISTER : reg_e +/* DIMENSION : 0 +/* DEPTHS (per dimension): [] +/******************************************************************* +/*******************************************************************/ + +logic reg_e_active ; +logic reg_e_sw_wr ; +logic [31:0] reg_e_data_mux_in; +logic reg_e_rdy_mux_in ; +logic reg_e_err_mux_in ; +logic [15:0] reg_e__f1_q ; +logic [15:0] reg_e__f2_q ; + + +// Register-activation for 'reg_e' +assign reg_e_active = widget_if.addr == 136; +assign reg_e_sw_wr = reg_e_active && widget_if.w_vld; + +//-----------------FIELD SUMMARY----------------- +// name : f1 (reg_e[15:0]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw', 'we'] +// external : False +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (reg_e_sw_wr) + begin + if (widget_if.byte_en[0]) + reg_e__f1_q[7:0] <= widget_if.w_data[7:0]; + if (widget_if.byte_en[1]) + reg_e__f1_q[15:8] <= widget_if.w_data[15:8]; + end + else + if (reg_e__f1_hw_wr) + reg_e__f1_q <= reg_e__f1_in; +end // of reg_e__f1's always_ff + +// Connect register to hardware output port +assign reg_e__f1_r = reg_e__f1_q; + + + +//-----------------FIELD SUMMARY----------------- +// name : f2 (reg_e[31:16]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw', 'we'] +// external : False +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (reg_e_sw_wr) + begin + if (widget_if.byte_en[2]) + reg_e__f2_q[7:0] <= widget_if.w_data[23:16]; + if (widget_if.byte_en[3]) + reg_e__f2_q[15:8] <= widget_if.w_data[31:24]; + end + else + if (reg_e__f2_hw_wr) + reg_e__f2_q <= reg_e__f2_in; +end // of reg_e__f2's always_ff + +// Connect register to hardware output port +assign reg_e__f2_r = reg_e__f2_q; + + + + +/************************************** + * Assign all fields to signal to Mux * + **************************************/ +// Assign all fields. Fields that are not readable are tied to 0. +assign reg_e_data_mux_in = {reg_e__f2_q, reg_e__f1_q}; + +// Internal registers are ready immediately +assign reg_e_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 reg_e_err_mux_in = !((widget_if.r_vld && (widget_if.byte_en[0] || widget_if.byte_en[1] || widget_if.byte_en[2] || widget_if.byte_en[3])) || (widget_if.w_vld && (widget_if.byte_en[0] || widget_if.byte_en[1] || widget_if.byte_en[2] || widget_if.byte_en[3]))); + +// Read multiplexer +always_comb +begin + unique case (1'b1) + regfile_1__reg_a_active: + begin + widget_if.r_data = regfile_1__reg_a_data_mux_in; + widget_if.err = regfile_1__reg_a_err_mux_in; + widget_if.rdy = regfile_1__reg_a_rdy_mux_in; + end + regfile_1__reg_b_active: + begin + widget_if.r_data = regfile_1__reg_b_data_mux_in; + widget_if.err = regfile_1__reg_b_err_mux_in; + widget_if.rdy = regfile_1__reg_b_rdy_mux_in; + end + regfile_2__regfile_3__reg_d_active[0][0][0]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[0][0][0]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[0][0][0]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[0][0][0]; + end + regfile_2__regfile_3__reg_d_active[0][0][1]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[0][0][1]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[0][0][1]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[0][0][1]; + end + regfile_2__regfile_3__reg_d_active[0][1][0]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[0][1][0]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[0][1][0]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[0][1][0]; + end + regfile_2__regfile_3__reg_d_active[0][1][1]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[0][1][1]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[0][1][1]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[0][1][1]; + end + regfile_2__regfile_3__reg_d_active[0][2][0]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[0][2][0]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[0][2][0]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[0][2][0]; + end + regfile_2__regfile_3__reg_d_active[0][2][1]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[0][2][1]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[0][2][1]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[0][2][1]; + end + regfile_2__regfile_3__reg_d_active[0][3][0]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[0][3][0]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[0][3][0]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[0][3][0]; + end + regfile_2__regfile_3__reg_d_active[0][3][1]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[0][3][1]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[0][3][1]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[0][3][1]; + end + regfile_2__regfile_3__reg_d_active[1][0][0]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[1][0][0]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[1][0][0]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[1][0][0]; + end + regfile_2__regfile_3__reg_d_active[1][0][1]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[1][0][1]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[1][0][1]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[1][0][1]; + end + regfile_2__regfile_3__reg_d_active[1][1][0]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[1][1][0]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[1][1][0]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[1][1][0]; + end + regfile_2__regfile_3__reg_d_active[1][1][1]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[1][1][1]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[1][1][1]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[1][1][1]; + end + regfile_2__regfile_3__reg_d_active[1][2][0]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[1][2][0]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[1][2][0]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[1][2][0]; + end + regfile_2__regfile_3__reg_d_active[1][2][1]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[1][2][1]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[1][2][1]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[1][2][1]; + end + regfile_2__regfile_3__reg_d_active[1][3][0]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[1][3][0]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[1][3][0]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[1][3][0]; + end + regfile_2__regfile_3__reg_d_active[1][3][1]: + begin + widget_if.r_data = regfile_2__regfile_3__reg_d_data_mux_in[1][3][1]; + widget_if.err = regfile_2__regfile_3__reg_d_err_mux_in[1][3][1]; + widget_if.rdy = regfile_2__regfile_3__reg_d_rdy_mux_in[1][3][1]; + end + regfile_2__reg_c_active[0]: + begin + widget_if.r_data = regfile_2__reg_c_data_mux_in[0]; + widget_if.err = regfile_2__reg_c_err_mux_in[0]; + widget_if.rdy = regfile_2__reg_c_rdy_mux_in[0]; + end + regfile_2__reg_c_active[1]: + begin + widget_if.r_data = regfile_2__reg_c_data_mux_in[1]; + widget_if.err = regfile_2__reg_c_err_mux_in[1]; + widget_if.rdy = regfile_2__reg_c_rdy_mux_in[1]; + end + reg_e_active: + begin + widget_if.r_data = reg_e_data_mux_in; + widget_if.err = reg_e_err_mux_in; + widget_if.rdy = reg_e_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/hierarchical_regfiles/srdl2sv_out/srdl2sv_amba3ahblite.sv b/examples/hierarchical_regfiles/srdl2sv_out/srdl2sv_amba3ahblite.sv new file mode 100644 index 0000000..52da8c8 --- /dev/null +++ b/examples/hierarchical_regfiles/srdl2sv_out/srdl2sv_amba3ahblite.sv @@ -0,0 +1,309 @@ +/* + * 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 = 1'b0; + + // 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 (widget_if.err && widget_if.rdy) + begin + fsm_next = FSM_ERR_0; + end + else if (HTRANS == BUSY) + begin + // Wait + fsm_next = FSM_TRANS; + 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/hierarchical_regfiles/srdl2sv_out/srdl2sv_widget_if.sv b/examples/hierarchical_regfiles/srdl2sv_out/srdl2sv_widget_if.sv new file mode 100644 index 0000000..b85afc4 --- /dev/null +++ b/examples/hierarchical_regfiles/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 +