From a871e9a90662a8b4ee0eca3d921c00a7461c3df4 Mon Sep 17 00:00:00 2001 From: Dennis Date: Sun, 31 Oct 2021 13:59:51 -0700 Subject: [PATCH] Add example to show handling of SystemRDL enums --- examples/enums/enums.rdl | 56 ++ examples/enums/srdl2sv_out/enums.sv | 550 ++++++++++++++++++ .../enums/srdl2sv_out/enums__regfile_1_pkg.sv | 8 + examples/enums/srdl2sv_out/enums_pkg.sv | 18 + .../enums/srdl2sv_out/srdl2sv_amba3ahblite.sv | 312 ++++++++++ .../enums/srdl2sv_out/srdl2sv_widget_if.sv | 30 + 6 files changed, 974 insertions(+) create mode 100644 examples/enums/enums.rdl create mode 100644 examples/enums/srdl2sv_out/enums.sv create mode 100644 examples/enums/srdl2sv_out/enums__regfile_1_pkg.sv create mode 100644 examples/enums/srdl2sv_out/enums_pkg.sv create mode 100644 examples/enums/srdl2sv_out/srdl2sv_amba3ahblite.sv create mode 100644 examples/enums/srdl2sv_out/srdl2sv_widget_if.sv diff --git a/examples/enums/enums.rdl b/examples/enums/enums.rdl new file mode 100644 index 0000000..47c71e5 --- /dev/null +++ b/examples/enums/enums.rdl @@ -0,0 +1,56 @@ +addrmap enums { + desc = + "This example demonstrates how enumerations are translated to Systemverilog, how enumerations are handled when the same enumeration is redefined in different scopes, and hence how enumerations can be re-used in the RTL that surrounds the register block. + + It is not mandatory to use enums in RTL when defining enums in SystemRDL. By providing the command-line argument `--no-enums` all I/O will be defined as flat wires."; + + enum first_enum { + val_1 = 2'b10; + val_2 = 2'b01; + }; + + enum second_enum { + val_3 = 2'b10; + val_4 = 2'b01; + }; + + reg { + field {sw=rw; hw=rw;} f1 [1:0]; + field {sw=rw; hw=rw;} f2 [9:8]; + + f1->encode = first_enum; + } reg_a; + + reg { + field {sw=rw; hw=rw;} f1 [1:0]; + field {sw=rw; hw=rw;} f2 [9:8]; + + f1->encode = second_enum; + } reg_b; + + enum third_enum { + val_5 = 2'b10; + val_6 = 2'b01; + }; + + regfile { + enum fourth_enum { + val_7 = 2'b10; + val_8 = 2'b01; + }; + + reg { + field {sw=rw; hw=rw;} f1 [1:0]; + field {sw=rw; hw=rw;} f2 [9:8]; + + f1->encode = third_enum; + } reg_c; + + reg { + field {sw=rw; hw=rw;} f1 [1:0]; + field {sw=rw; hw=rw;} f2 [9:8]; + + f1->encode = fourth_enum; + } reg_d; + } regfile_1; +}; diff --git a/examples/enums/srdl2sv_out/enums.sv b/examples/enums/srdl2sv_out/enums.sv new file mode 100644 index 0000000..0c290bd --- /dev/null +++ b/examples/enums/srdl2sv_out/enums.sv @@ -0,0 +1,550 @@ +/***************************************************************** + * + * ███████╗██████╗ ██████╗ ██╗ ██████╗ ███████╗██╗ ██╗ + * ██╔════╝██╔══██╗██╔══██╗██║ ╚════██╗██╔════╝██║ ██║ + * ███████╗██████╔╝██║ ██║██║ █████╔╝███████╗██║ ██║ + * ╚════██║██╔══██╗██║ ██║██║ ██╔═══╝ ╚════██║╚██╗ ██╔╝ + * ███████║██║ ██║██████╔╝███████╗███████╗███████║ ╚████╔╝ + * ╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚══════╝╚══════╝ ╚═══╝ + * + * 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 : October 31 2021 13:59:16 + * - Path : /home/dpotter/srdl2sv/examples/enums + * - RDL file : ['enums.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 ENUMS.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 enums + import enums_pkg::*; + import enums__regfile_1_pkg::*; +( + // 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 enums_pkg::third_enum regfile_1__reg_c__f1_in, + input logic [1:0] regfile_1__reg_c__f2_in, + input enums__regfile_1_pkg::fourth_enum regfile_1__reg_d__f1_in, + input logic [1:0] regfile_1__reg_d__f2_in, + input enums_pkg::first_enum reg_a__f1_in , + input logic [1:0] reg_a__f2_in , + input enums_pkg::second_enum reg_b__f1_in , + input logic [1:0] reg_b__f2_in , + + // Outputs + output HREADYOUT , + output HRESP , + output [32-1:0] HRDATA , + output enums_pkg::third_enum regfile_1__reg_c__f1_r, + output logic [1:0] regfile_1__reg_c__f2_r, + output enums__regfile_1_pkg::fourth_enum regfile_1__reg_d__f1_r, + output logic [1:0] regfile_1__reg_d__f2_r, + output enums_pkg::first_enum reg_a__f1_r , + output logic [1:0] reg_a__f2_r , + output enums_pkg::second_enum reg_b__f1_r , + output logic [1:0] reg_b__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); +/******************************************************************* + ******************************************************************* + * REGFILE : regfile_1 + * DIMENSION : 0 + * DEPTHS (per dimension): [] + ******************************************************************* + *******************************************************************/ + + +/******************************************************************* +/******************************************************************* +/* REGISTER : reg_c +/* DIMENSION : 0 +/* DEPTHS (per dimension): [] +/******************************************************************* +/*******************************************************************/ + +logic regfile_1__reg_c_active ; +logic regfile_1__reg_c_sw_wr ; +logic [31:0] regfile_1__reg_c_data_mux_in; +logic regfile_1__reg_c_rdy_mux_in ; +logic regfile_1__reg_c_err_mux_in ; +enums_pkg::third_enum regfile_1__reg_c__f1_q ; +logic [1:0] regfile_1__reg_c__f2_q ; + + +// Register-activation for 'regfile_1__reg_c' +assign regfile_1__reg_c_active = widget_if.addr == 8; +assign regfile_1__reg_c_sw_wr = regfile_1__reg_c_active && widget_if.w_vld; + +//-----------------FIELD SUMMARY----------------- +// name : f1 (regfile_1__reg_c[1:0]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw', 'encode'] +// external : False +// storage type : StorageType.FLOPS +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (regfile_1__reg_c_sw_wr) + begin + if (widget_if.byte_en[0]) + regfile_1__reg_c__f1_q[1:0] <= widget_if.w_data[1:0]; + end + else + // we or wel property not set + regfile_1__reg_c__f1_q <= regfile_1__reg_c__f1_in; +end // of regfile_1__reg_c__f1's always_ff + +// Connect register to hardware output port +assign regfile_1__reg_c__f1_r = regfile_1__reg_c__f1_q; + + + +//-----------------FIELD SUMMARY----------------- +// name : f2 (regfile_1__reg_c[9:8]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw'] +// external : False +// storage type : StorageType.FLOPS +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (regfile_1__reg_c_sw_wr) + begin + if (widget_if.byte_en[1]) + regfile_1__reg_c__f2_q[1:0] <= widget_if.w_data[9:8]; + end + else + // we or wel property not set + regfile_1__reg_c__f2_q <= regfile_1__reg_c__f2_in; +end // of regfile_1__reg_c__f2's always_ff + +// Connect register to hardware output port +assign regfile_1__reg_c__f2_r = regfile_1__reg_c__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_c_data_mux_in = {{22{1'b0}}, regfile_1__reg_c__f2_q, {6{1'b0}}, regfile_1__reg_c__f1_q}; + +// Internal registers are ready immediately +assign regfile_1__reg_c_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_c_err_mux_in = !((widget_if.r_vld && (widget_if.byte_en[0] || widget_if.byte_en[1])) || (widget_if.w_vld && (widget_if.byte_en[0] || widget_if.byte_en[1]))); + +/******************************************************************* +/******************************************************************* +/* REGISTER : reg_d +/* DIMENSION : 0 +/* DEPTHS (per dimension): [] +/******************************************************************* +/*******************************************************************/ + +logic regfile_1__reg_d_active ; +logic regfile_1__reg_d_sw_wr ; +logic [31:0] regfile_1__reg_d_data_mux_in; +logic regfile_1__reg_d_rdy_mux_in ; +logic regfile_1__reg_d_err_mux_in ; +enums__regfile_1_pkg::fourth_enum regfile_1__reg_d__f1_q ; +logic [1:0] regfile_1__reg_d__f2_q ; + + +// Register-activation for 'regfile_1__reg_d' +assign regfile_1__reg_d_active = widget_if.addr == 12; +assign regfile_1__reg_d_sw_wr = regfile_1__reg_d_active && widget_if.w_vld; + +//-----------------FIELD SUMMARY----------------- +// name : f1 (regfile_1__reg_d[1:0]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw', 'encode'] +// external : False +// storage type : StorageType.FLOPS +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (regfile_1__reg_d_sw_wr) + begin + if (widget_if.byte_en[0]) + regfile_1__reg_d__f1_q[1:0] <= widget_if.w_data[1:0]; + end + else + // we or wel property not set + regfile_1__reg_d__f1_q <= regfile_1__reg_d__f1_in; +end // of regfile_1__reg_d__f1's always_ff + +// Connect register to hardware output port +assign regfile_1__reg_d__f1_r = regfile_1__reg_d__f1_q; + + + +//-----------------FIELD SUMMARY----------------- +// name : f2 (regfile_1__reg_d[9:8]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw'] +// external : False +// storage type : StorageType.FLOPS +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (regfile_1__reg_d_sw_wr) + begin + if (widget_if.byte_en[1]) + regfile_1__reg_d__f2_q[1:0] <= widget_if.w_data[9:8]; + end + else + // we or wel property not set + regfile_1__reg_d__f2_q <= regfile_1__reg_d__f2_in; +end // of regfile_1__reg_d__f2's always_ff + +// Connect register to hardware output port +assign regfile_1__reg_d__f2_r = regfile_1__reg_d__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_d_data_mux_in = {{22{1'b0}}, regfile_1__reg_d__f2_q, {6{1'b0}}, regfile_1__reg_d__f1_q}; + +// Internal registers are ready immediately +assign regfile_1__reg_d_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_d_err_mux_in = !((widget_if.r_vld && (widget_if.byte_en[0] || widget_if.byte_en[1])) || (widget_if.w_vld && (widget_if.byte_en[0] || widget_if.byte_en[1]))); + +/******************************************************************* +/******************************************************************* +/* REGISTER : reg_a +/* DIMENSION : 0 +/* DEPTHS (per dimension): [] +/******************************************************************* +/*******************************************************************/ + +logic reg_a_active ; +logic reg_a_sw_wr ; +logic [31:0] reg_a_data_mux_in; +logic reg_a_rdy_mux_in ; +logic reg_a_err_mux_in ; +enums_pkg::first_enum reg_a__f1_q ; +logic [1:0] reg_a__f2_q ; + + +// Register-activation for 'reg_a' +assign reg_a_active = widget_if.addr == 0; +assign reg_a_sw_wr = reg_a_active && widget_if.w_vld; + +//-----------------FIELD SUMMARY----------------- +// name : f1 (reg_a[1:0]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw', 'encode'] +// external : False +// storage type : StorageType.FLOPS +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (reg_a_sw_wr) + begin + if (widget_if.byte_en[0]) + reg_a__f1_q[1:0] <= widget_if.w_data[1:0]; + end + else + // we or wel property not set + reg_a__f1_q <= reg_a__f1_in; +end // of reg_a__f1's always_ff + +// Connect register to hardware output port +assign reg_a__f1_r = reg_a__f1_q; + + + +//-----------------FIELD SUMMARY----------------- +// name : f2 (reg_a[9:8]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw'] +// external : False +// storage type : StorageType.FLOPS +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (reg_a_sw_wr) + begin + if (widget_if.byte_en[1]) + reg_a__f2_q[1:0] <= widget_if.w_data[9:8]; + end + else + // we or wel property not set + reg_a__f2_q <= reg_a__f2_in; +end // of reg_a__f2's always_ff + +// Connect register to hardware output port +assign reg_a__f2_r = reg_a__f2_q; + + + + +/************************************** + * Assign all fields to signal to Mux * + **************************************/ +// Assign all fields. Fields that are not readable are tied to 0. +assign reg_a_data_mux_in = {{22{1'b0}}, reg_a__f2_q, {6{1'b0}}, reg_a__f1_q}; + +// Internal registers are ready immediately +assign 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 reg_a_err_mux_in = !((widget_if.r_vld && (widget_if.byte_en[0] || widget_if.byte_en[1])) || (widget_if.w_vld && (widget_if.byte_en[0] || widget_if.byte_en[1]))); + +/******************************************************************* +/******************************************************************* +/* REGISTER : reg_b +/* DIMENSION : 0 +/* DEPTHS (per dimension): [] +/******************************************************************* +/*******************************************************************/ + +logic reg_b_active ; +logic reg_b_sw_wr ; +logic [31:0] reg_b_data_mux_in; +logic reg_b_rdy_mux_in ; +logic reg_b_err_mux_in ; +enums_pkg::second_enum reg_b__f1_q ; +logic [1:0] reg_b__f2_q ; + + +// Register-activation for 'reg_b' +assign reg_b_active = widget_if.addr == 4; +assign reg_b_sw_wr = reg_b_active && widget_if.w_vld; + +//-----------------FIELD SUMMARY----------------- +// name : f1 (reg_b[1:0]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw', 'encode'] +// external : False +// storage type : StorageType.FLOPS +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (reg_b_sw_wr) + begin + if (widget_if.byte_en[0]) + reg_b__f1_q[1:0] <= widget_if.w_data[1:0]; + end + else + // we or wel property not set + reg_b__f1_q <= reg_b__f1_in; +end // of reg_b__f1's always_ff + +// Connect register to hardware output port +assign reg_b__f1_r = reg_b__f1_q; + + + +//-----------------FIELD SUMMARY----------------- +// name : f2 (reg_b[9:8]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : ['sw'] +// external : False +// storage type : StorageType.FLOPS +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (reg_b_sw_wr) + begin + if (widget_if.byte_en[1]) + reg_b__f2_q[1:0] <= widget_if.w_data[9:8]; + end + else + // we or wel property not set + reg_b__f2_q <= reg_b__f2_in; +end // of reg_b__f2's always_ff + +// Connect register to hardware output port +assign reg_b__f2_r = reg_b__f2_q; + + + + +/************************************** + * Assign all fields to signal to Mux * + **************************************/ +// Assign all fields. Fields that are not readable are tied to 0. +assign reg_b_data_mux_in = {{22{1'b0}}, reg_b__f2_q, {6{1'b0}}, reg_b__f1_q}; + +// Internal registers are ready immediately +assign 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 reg_b_err_mux_in = !((widget_if.r_vld && (widget_if.byte_en[0] || widget_if.byte_en[1])) || (widget_if.w_vld && (widget_if.byte_en[0] || widget_if.byte_en[1]))); + +// Read multiplexer +always_comb +begin + unique case (1'b1) + regfile_1__reg_c_active: + begin + widget_if.r_data = regfile_1__reg_c_data_mux_in; + widget_if.err = regfile_1__reg_c_err_mux_in; + widget_if.rdy = regfile_1__reg_c_rdy_mux_in; + end + regfile_1__reg_d_active: + begin + widget_if.r_data = regfile_1__reg_d_data_mux_in; + widget_if.err = regfile_1__reg_d_err_mux_in; + widget_if.rdy = regfile_1__reg_d_rdy_mux_in; + end + reg_a_active: + begin + widget_if.r_data = reg_a_data_mux_in; + widget_if.err = reg_a_err_mux_in; + widget_if.rdy = reg_a_rdy_mux_in; + end + reg_b_active: + begin + widget_if.r_data = reg_b_data_mux_in; + widget_if.err = reg_b_err_mux_in; + widget_if.rdy = reg_b_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/enums/srdl2sv_out/enums__regfile_1_pkg.sv b/examples/enums/srdl2sv_out/enums__regfile_1_pkg.sv new file mode 100644 index 0000000..0d4b1db --- /dev/null +++ b/examples/enums/srdl2sv_out/enums__regfile_1_pkg.sv @@ -0,0 +1,8 @@ +package enums__regfile_1_pkg; + +typedef enum logic [1:0] { + val_7 = 2'd2, + val_8 = 2'd1 +} fourth_enum; + +endpackage diff --git a/examples/enums/srdl2sv_out/enums_pkg.sv b/examples/enums/srdl2sv_out/enums_pkg.sv new file mode 100644 index 0000000..e0a49d0 --- /dev/null +++ b/examples/enums/srdl2sv_out/enums_pkg.sv @@ -0,0 +1,18 @@ +package enums_pkg; + +typedef enum logic [1:0] { + val_1 = 2'd2, + val_2 = 2'd1 +} first_enum; + +typedef enum logic [1:0] { + val_3 = 2'd2, + val_4 = 2'd1 +} second_enum; + +typedef enum logic [1:0] { + val_5 = 2'd2, + val_6 = 2'd1 +} third_enum; + +endpackage diff --git a/examples/enums/srdl2sv_out/srdl2sv_amba3ahblite.sv b/examples/enums/srdl2sv_out/srdl2sv_amba3ahblite.sv new file mode 100644 index 0000000..d1598f9 --- /dev/null +++ b/examples/enums/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/enums/srdl2sv_out/srdl2sv_widget_if.sv b/examples/enums/srdl2sv_out/srdl2sv_widget_if.sv new file mode 100644 index 0000000..b85afc4 --- /dev/null +++ b/examples/enums/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 +