From 1ed801a5655c63382f119365fe50ebeaa82b0429 Mon Sep 17 00:00:00 2001 From: Dennis Date: Wed, 20 Oct 2021 22:34:37 -0700 Subject: [PATCH] Add simple example with 1-D, 2-D, and 3-D registers --- examples/simple_rw_reg/simple_rw_reg.rdl | 27 + .../srdl2sv_out/simple_rw_reg.sv | 500 ++++++++++++++++++ .../srdl2sv_out/srdl2sv_amba3ahblite.sv | 314 +++++++++++ .../srdl2sv_out/srdl2sv_if_pkg.sv | 18 + 4 files changed, 859 insertions(+) create mode 100644 examples/simple_rw_reg/simple_rw_reg.rdl create mode 100644 examples/simple_rw_reg/srdl2sv_out/simple_rw_reg.sv create mode 100644 examples/simple_rw_reg/srdl2sv_out/srdl2sv_amba3ahblite.sv create mode 100644 examples/simple_rw_reg/srdl2sv_out/srdl2sv_if_pkg.sv diff --git a/examples/simple_rw_reg/simple_rw_reg.rdl b/examples/simple_rw_reg/simple_rw_reg.rdl new file mode 100644 index 0000000..c3fd2ef --- /dev/null +++ b/examples/simple_rw_reg/simple_rw_reg.rdl @@ -0,0 +1,27 @@ +// This RDL file contains 4 simple types of registers: +// - A 1-dimensional register +// - A 2-dimensional register +// - A 3-dimensional register +// +// Note that no reset is defined, so none of the registers will be +// resetable. + +addrmap simple_rw_reg { + // 1-D register + reg { + field {sw=rw; hw=rw; we;} f1 [15:0]; + field {sw=rw; hw=rw; we;} f2 [31:16]; + } register_1d; + + // 2-D register + reg { + field {sw=rw; hw=rw; we;} f1 [15:0]; + field {sw=rw; hw=rw; we;} f2 [31:16]; + } register_2d[2]; + + // 3-D register + reg { + field {sw=rw; hw=rw; we;} f1 [15:0]; + field {sw=rw; hw=rw; we;} f2 [31:16]; + } register_3d[2][2]; +}; diff --git a/examples/simple_rw_reg/srdl2sv_out/simple_rw_reg.sv b/examples/simple_rw_reg/srdl2sv_out/simple_rw_reg.sv new file mode 100644 index 0000000..b696e6d --- /dev/null +++ b/examples/simple_rw_reg/srdl2sv_out/simple_rw_reg.sv @@ -0,0 +1,500 @@ +/***************************************************************** + * + * ███████╗██████╗ ██████╗ ██╗ ██████╗ ███████╗██╗ ██╗ + * ██╔════╝██╔══██╗██╔══██╗██║ ╚════██╗██╔════╝██║ ██║ + * ███████╗██████╔╝██║ ██║██║ █████╔╝███████╗██║ ██║ + * ╚════██║██╔══██╗██║ ██║██║ ██╔═══╝ ╚════██║╚██╗ ██╔╝ + * ███████║██║ ██║██████╔╝███████╗███████╗███████║ ╚████╔╝ + * ╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚══════╝╚══════╝ ╚═══╝ + * + * 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 20 2021 22:32:15 + * - Path : /home/dpotter/srdl2sv_second_repo/examples/simple_rw_reg + * - RDL file : ['simple_rw_reg.rdl'] + * - Hostname : ArchXPS + * + * RDL include directories: + * - + * + * Commandline arguments to srdl2sv: + * - Ouput Directory : ./srdl2sv_out + * - Stream Log Level : WARNING + * - File Log Level : INFO + * - Use Real Tabs : False + * - Tab Width : 4 + * - Enums Enabled : True + * - Register Bus Type: amba3ahblite + * - Byte enables : True + * - Descriptions : {'AddrMap': False, 'RegFile': False, 'Memory': False, 'Register': False, 'Field': False} + * + * ===LICENSE OF SIMPLE_RW_REG.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 simple_rw_reg + import srdl2sv_if_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 logic register_1d__f1_hw_wr, + input logic [15:0] register_1d__f1_in , + input logic register_1d__f2_hw_wr, + input logic [15:0] register_1d__f2_in , + input logic register_2d__f1_hw_wr[2], + input logic [15:0] register_2d__f1_in [2], + input logic register_2d__f2_hw_wr[2], + input logic [15:0] register_2d__f2_in [2], + input logic register_3d__f1_hw_wr[2][2], + input logic [15:0] register_3d__f1_in [2][2], + input logic register_3d__f2_hw_wr[2][2], + input logic [15:0] register_3d__f2_in [2][2], + + // Outputs + output HREADYOUT , + output HRESP , + output [32-1:0] HRDATA , + output logic [15:0] register_1d__f1_r, + output logic [15:0] register_1d__f2_r, + output logic [15:0] register_2d__f1_r[2], + output logic [15:0] register_2d__f2_r[2], + output logic [15:0] register_3d__f1_r[2][2], + output logic [15:0] register_3d__f2_r[2][2] +); + + +// Internal signals +b2r_t b2r; +r2b_t r2b; + +/******************************************************************* + * AMBA 3 AHB Lite Widget + * ====================== + * Naming conventions + * - r2b.* -> Signals from registers to bus + * - b2r.* -> Signals from bus to registers + * - H* -> Signals as defined in AMBA3 AHB Lite + * specification + * - clk -> Clock that drives registers and the bus + *******************************************************************/ +srdl2sv_amba3ahblite + #(.FLOP_REGISTER_IF (0), + .BUS_BITS (32), + .NO_BYTE_ENABLE (0)) +srdl2sv_amba3ahblite_inst + (// Outputs to internal logic + .b2r, + + // Inputs from internal logic + .r2b, + + // Bus protocol + .HRESETn, + .HCLK (clk), + .HADDR, + .HWRITE, + .HSIZE, + .HPROT, + .HTRANS, + .HWDATA, + .HSEL, + + .HREADYOUT, + .HRESP, + .HRDATA); + +genvar gv_a, gv_b; + + +/******************************************************************* +/******************************************************************* +/* REGISTER : register_1d +/* DIMENSION : 0 +/* DEPTHS (per dimension): [] +/******************************************************************* +/*******************************************************************/ + +logic register_1d_active ; +logic register_1d_sw_wr ; +logic [31:0] register_1d_data_mux_in; +logic register_1d_rdy_mux_in ; +logic register_1d_err_mux_in ; +logic [15:0] register_1d__f1_q ; +logic [15:0] register_1d__f2_q ; + + +// Register-activation for 'register_1d' +assign register_1d_active = b2r.addr == 0; +assign register_1d_sw_wr = register_1d_active && b2r.w_vld; + +//-----------------FIELD SUMMARY----------------- +// name : f1 (register_1d[15:0]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : {'we', 'sw'} +// external : False +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (register_1d_sw_wr) + begin + if (b2r.byte_en[0]) + register_1d__f1_q[7:0] <= b2r.data[7:0]; + if (b2r.byte_en[1]) + register_1d__f1_q[15:8] <= b2r.data[15:8]; + end + else + if (register_1d__f1_hw_wr) + register_1d__f1_q <= register_1d__f1_in; +end // of register_1d__f1's always_ff + +// Connect register to hardware output port +assign register_1d__f1_r = register_1d__f1_q; + + + +//-----------------FIELD SUMMARY----------------- +// name : f2 (register_1d[31:16]) +// access : hw = rw +// sw = rw (precedence) +// reset : - / - +// flags : {'we', 'sw'} +// external : False +//----------------------------------------------- + +always_ff @(posedge clk) +begin + if (register_1d_sw_wr) + begin + if (b2r.byte_en[2]) + register_1d__f2_q[7:0] <= b2r.data[23:16]; + if (b2r.byte_en[3]) + register_1d__f2_q[15:8] <= b2r.data[31:24]; + end + else + if (register_1d__f2_hw_wr) + register_1d__f2_q <= register_1d__f2_in; +end // of register_1d__f2's always_ff + +// Connect register to hardware output port +assign register_1d__f2_r = register_1d__f2_q; + + + + +/************************************** + * Assign all fields to signal to Mux * + **************************************/ +// Assign all fields. Fields that are not readable are tied to 0. +assign register_1d_data_mux_in = {register_1d__f2_q, register_1d__f1_q}; + +// Internal registers are ready immediately +assign register_1d_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 register_1d_err_mux_in = !((b2r.r_vld && (b2r.byte_en[0] || b2r.byte_en[1] || b2r.byte_en[2] || b2r.byte_en[3])) || (b2r.w_vld && (b2r.byte_en[0] || b2r.byte_en[1] || b2r.byte_en[2] || b2r.byte_en[3]))); + +/******************************************************************* +/******************************************************************* +/* REGISTER : register_2d +/* DIMENSION : 1 +/* DEPTHS (per dimension): [2] +/******************************************************************* +/*******************************************************************/ + +logic register_2d_active [2]; +logic register_2d_sw_wr [2]; +logic [31:0] register_2d_data_mux_in[2]; +logic register_2d_rdy_mux_in [2]; +logic register_2d_err_mux_in [2]; +logic [15:0] register_2d__f1_q [2]; +logic [15:0] register_2d__f2_q [2]; + +generate +for (gv_a = 0; gv_a < 2; gv_a++) +begin + + // Register-activation for 'register_2d' + assign register_2d_active[gv_a] = b2r.addr == 4+(gv_a*4); + assign register_2d_sw_wr[gv_a] = register_2d_active[gv_a] && b2r.w_vld; + + //-----------------FIELD SUMMARY----------------- + // name : f1 (register_2d[15:0]) + // access : hw = rw + // sw = rw (precedence) + // reset : - / - + // flags : {'we', 'sw'} + // external : False + //----------------------------------------------- + + always_ff @(posedge clk) + begin + if (register_2d_sw_wr[gv_a]) + begin + if (b2r.byte_en[0]) + register_2d__f1_q[gv_a][7:0] <= b2r.data[7:0]; + if (b2r.byte_en[1]) + register_2d__f1_q[gv_a][15:8] <= b2r.data[15:8]; + end + else + if (register_2d__f1_hw_wr[gv_a]) + register_2d__f1_q[gv_a] <= register_2d__f1_in[gv_a]; + end // of register_2d__f1's always_ff + + // Connect register to hardware output port + assign register_2d__f1_r[gv_a] = register_2d__f1_q[gv_a]; + + + + //-----------------FIELD SUMMARY----------------- + // name : f2 (register_2d[31:16]) + // access : hw = rw + // sw = rw (precedence) + // reset : - / - + // flags : {'we', 'sw'} + // external : False + //----------------------------------------------- + + always_ff @(posedge clk) + begin + if (register_2d_sw_wr[gv_a]) + begin + if (b2r.byte_en[2]) + register_2d__f2_q[gv_a][7:0] <= b2r.data[23:16]; + if (b2r.byte_en[3]) + register_2d__f2_q[gv_a][15:8] <= b2r.data[31:24]; + end + else + if (register_2d__f2_hw_wr[gv_a]) + register_2d__f2_q[gv_a] <= register_2d__f2_in[gv_a]; + end // of register_2d__f2's always_ff + + // Connect register to hardware output port + assign register_2d__f2_r[gv_a] = register_2d__f2_q[gv_a]; + + + + + /************************************** + * Assign all fields to signal to Mux * + **************************************/ + // Assign all fields. Fields that are not readable are tied to 0. + assign register_2d_data_mux_in[gv_a] = {register_2d__f2_q[gv_a], register_2d__f1_q[gv_a]}; + + // Internal registers are ready immediately + assign register_2d_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 register_2d_err_mux_in[gv_a] = !((b2r.r_vld && (b2r.byte_en[0] || b2r.byte_en[1] || b2r.byte_en[2] || b2r.byte_en[3])) || (b2r.w_vld && (b2r.byte_en[0] || b2r.byte_en[1] || b2r.byte_en[2] || b2r.byte_en[3]))); +end // of for loop with iterator gv_a + +endgenerate + + +/******************************************************************* +/******************************************************************* +/* REGISTER : register_3d +/* DIMENSION : 2 +/* DEPTHS (per dimension): [2][2] +/******************************************************************* +/*******************************************************************/ + +logic register_3d_active [2][2]; +logic register_3d_sw_wr [2][2]; +logic [31:0] register_3d_data_mux_in[2][2]; +logic register_3d_rdy_mux_in [2][2]; +logic register_3d_err_mux_in [2][2]; +logic [15:0] register_3d__f1_q [2][2]; +logic [15:0] register_3d__f2_q [2][2]; + +generate +for (gv_a = 0; gv_a < 2; gv_a++) +begin + for (gv_b = 0; gv_b < 2; gv_b++) + begin + + // Register-activation for 'register_3d' + assign register_3d_active[gv_a][gv_b] = b2r.addr == 12+(gv_a*8+gv_b*4); + assign register_3d_sw_wr[gv_a][gv_b] = register_3d_active[gv_a][gv_b] && b2r.w_vld; + + //-----------------FIELD SUMMARY----------------- + // name : f1 (register_3d[15:0]) + // access : hw = rw + // sw = rw (precedence) + // reset : - / - + // flags : {'we', 'sw'} + // external : False + //----------------------------------------------- + + always_ff @(posedge clk) + begin + if (register_3d_sw_wr[gv_a][gv_b]) + begin + if (b2r.byte_en[0]) + register_3d__f1_q[gv_a][gv_b][7:0] <= b2r.data[7:0]; + if (b2r.byte_en[1]) + register_3d__f1_q[gv_a][gv_b][15:8] <= b2r.data[15:8]; + end + else + if (register_3d__f1_hw_wr[gv_a][gv_b]) + register_3d__f1_q[gv_a][gv_b] <= register_3d__f1_in[gv_a][gv_b]; + end // of register_3d__f1's always_ff + + // Connect register to hardware output port + assign register_3d__f1_r[gv_a][gv_b] = register_3d__f1_q[gv_a][gv_b]; + + + + //-----------------FIELD SUMMARY----------------- + // name : f2 (register_3d[31:16]) + // access : hw = rw + // sw = rw (precedence) + // reset : - / - + // flags : {'we', 'sw'} + // external : False + //----------------------------------------------- + + always_ff @(posedge clk) + begin + if (register_3d_sw_wr[gv_a][gv_b]) + begin + if (b2r.byte_en[2]) + register_3d__f2_q[gv_a][gv_b][7:0] <= b2r.data[23:16]; + if (b2r.byte_en[3]) + register_3d__f2_q[gv_a][gv_b][15:8] <= b2r.data[31:24]; + end + else + if (register_3d__f2_hw_wr[gv_a][gv_b]) + register_3d__f2_q[gv_a][gv_b] <= register_3d__f2_in[gv_a][gv_b]; + end // of register_3d__f2's always_ff + + // Connect register to hardware output port + assign register_3d__f2_r[gv_a][gv_b] = register_3d__f2_q[gv_a][gv_b]; + + + + + /************************************** + * Assign all fields to signal to Mux * + **************************************/ + // Assign all fields. Fields that are not readable are tied to 0. + assign register_3d_data_mux_in[gv_a][gv_b] = {register_3d__f2_q[gv_a][gv_b], register_3d__f1_q[gv_a][gv_b]}; + + // Internal registers are ready immediately + assign register_3d_rdy_mux_in[gv_a][gv_b] = 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 register_3d_err_mux_in[gv_a][gv_b] = !((b2r.r_vld && (b2r.byte_en[0] || b2r.byte_en[1] || b2r.byte_en[2] || b2r.byte_en[3])) || (b2r.w_vld && (b2r.byte_en[0] || b2r.byte_en[1] || b2r.byte_en[2] || b2r.byte_en[3]))); + end // of for loop with iterator gv_b +end // of for loop with iterator gv_a + +endgenerate + + +// Read multiplexer +always_comb +begin + unique case (1'b1) + register_1d_active: + begin + r2b.data = register_1d_data_mux_in; + r2b.err = register_1d_err_mux_in; + r2b.rdy = register_1d_rdy_mux_in; + end + register_2d_active[0]: + begin + r2b.data = register_2d_data_mux_in[0]; + r2b.err = register_2d_err_mux_in[0]; + r2b.rdy = register_2d_rdy_mux_in[0]; + end + register_2d_active[1]: + begin + r2b.data = register_2d_data_mux_in[1]; + r2b.err = register_2d_err_mux_in[1]; + r2b.rdy = register_2d_rdy_mux_in[1]; + end + register_3d_active[0][0]: + begin + r2b.data = register_3d_data_mux_in[0][0]; + r2b.err = register_3d_err_mux_in[0][0]; + r2b.rdy = register_3d_rdy_mux_in[0][0]; + end + register_3d_active[0][1]: + begin + r2b.data = register_3d_data_mux_in[0][1]; + r2b.err = register_3d_err_mux_in[0][1]; + r2b.rdy = register_3d_rdy_mux_in[0][1]; + end + register_3d_active[1][0]: + begin + r2b.data = register_3d_data_mux_in[1][0]; + r2b.err = register_3d_err_mux_in[1][0]; + r2b.rdy = register_3d_rdy_mux_in[1][0]; + end + register_3d_active[1][1]: + begin + r2b.data = register_3d_data_mux_in[1][1]; + r2b.err = register_3d_err_mux_in[1][1]; + r2b.rdy = register_3d_rdy_mux_in[1][1]; + end + default: + begin + // If the address is not found, return an error + r2b.data = 0; + r2b.err = 1; + r2b.rdy = b2r.r_vld || b2r.w_vld; + end + endcase +end +endmodule diff --git a/examples/simple_rw_reg/srdl2sv_out/srdl2sv_amba3ahblite.sv b/examples/simple_rw_reg/srdl2sv_out/srdl2sv_amba3ahblite.sv new file mode 100644 index 0000000..055df5f --- /dev/null +++ b/examples/simple_rw_reg/srdl2sv_out/srdl2sv_amba3ahblite.sv @@ -0,0 +1,314 @@ +/* + * 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 + import srdl2sv_if_pkg::*; +#( + parameter bit FLOP_REGISTER_IF = 0, + parameter BUS_BITS = 32, + parameter NO_BYTE_ENABLE = 0 +) +( + // Outputs to internal logic + output b2r_t b2r, + + // Inputs from internal logic + input r2b_t r2b, + + // 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 +); + + 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 = r2b.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; + + b2r_w_vld_next = 0; + b2r_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 = r2b.rdy; + b2r_w_vld_next = operation_q == WRITE; + b2r_r_vld_next = operation_q == READ; + + if (r2b.err && r2b.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 = r2b.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] b2r_byte_en_next; + logic b2r_w_vld_next; + logic b2r_r_vld_next; + + generate + if (NO_BYTE_ENABLE) + begin + assign b2r_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 + b2r_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 + b2r.w_vld <= 1'b0; + b2r.r_vld <= 1'b0; + end + else + begin + b2r.w_vld <= b2r_w_vld_next; + b2r.r_vld <= b2r_r_vld_next; + end + + always_ff @ (posedge HCLK) + begin + b2r.addr <= {HADDR_q[31:BUS_BYTES_W], {BUS_BYTES_W{1'b0}}}; + b2r.data <= HWDATA << (8*HADDR_q[BUS_BYTES_W-1:0]); + b2r.byte_en <= b2r_byte_en_next; + end + end + else + begin + assign b2r.w_vld = b2r_w_vld_next; + assign b2r.r_vld = b2r_r_vld_next; + assign b2r.addr = {HADDR_q[31:BUS_BYTES_W], {BUS_BYTES_W{1'b0}}}; + assign b2r.data = HWDATA << (8*HADDR_q[BUS_BYTES_W-1:0]); + assign b2r.byte_en = b2r_byte_en_next; + end + endgenerate + +endmodule + diff --git a/examples/simple_rw_reg/srdl2sv_out/srdl2sv_if_pkg.sv b/examples/simple_rw_reg/srdl2sv_out/srdl2sv_if_pkg.sv new file mode 100644 index 0000000..f5434eb --- /dev/null +++ b/examples/simple_rw_reg/srdl2sv_out/srdl2sv_if_pkg.sv @@ -0,0 +1,18 @@ +package srdl2sv_if_pkg; + +typedef struct packed { // .Verilator does not support unpacked structs in packages + logic [31:0] addr; + logic [31:0] data; + logic w_vld; + logic r_vld; + logic [ 3:0] byte_en; +} b2r_t; + +typedef struct packed { // .Verilator does not support unpacked structs in packages + logic [31:0] data; + logic rdy; + logic err; +} r2b_t; + +endpackage +