diff --git a/cores/system/mcu/rtl/mcu_peripherals.v b/cores/system/mcu/rtl/mcu_peripherals.v index d5ea5b9..ec3d61b 100644 --- a/cores/system/mcu/rtl/mcu_peripherals.v +++ b/cores/system/mcu/rtl/mcu_peripherals.v @@ -99,7 +99,8 @@ module mcu_peripherals ( .i_wb_dat(gpio_wbs_dat_w), .i_wb_adr(gpio_wbs_adr), .i_wb_we(gpio_wbs_we), - .i_wb_stb(gpio_wbs_stb & gpio_wbs_cyc), + .i_wb_stb(gpio_wbs_stb), + .i_wb_cyc(gpio_wbs_cyc), .i_wb_sel(gpio_wbs_sel), .o_wb_rdt(gpio_wbs_dat_r), .o_wb_ack(gpio_wbs_ack), @@ -110,9 +111,7 @@ module mcu_peripherals ( assign wbs_dat_r[0*32 +: 32] = gpio_wbs_dat_r; assign wbs_ack[0] = gpio_wbs_ack; - wb_countdown_timer #( - .address(TIMER_BASE_ADDR) - ) timer ( + wb_countdown_timer timer ( .i_clk(i_clk), .i_rst(i_rst), .o_irq(o_timer_irq), diff --git a/cores/wb/formal_checker/formal/formal_wb_slave_checker.v b/cores/wb/formal_checker/formal/formal_wb_slave_checker.v index b1217fb..479bdbc 100644 --- a/cores/wb/formal_checker/formal/formal_wb_slave_checker.v +++ b/cores/wb/formal_checker/formal/formal_wb_slave_checker.v @@ -1,101 +1,219 @@ -`timescale 1ns/1ps +// formal_wb_slave_checker.v +// +// Wishbone Classic slave-side protocol checker (plain Verilog). +// Use when your DUT is a *slave* and the bus/master is the environment. module formal_wb_slave_checker #( - parameter combinatorial_ack = 0, - parameter expect_wait_state = 0 + parameter OPT_USE_ERR = 0, + parameter OPT_USE_RTY = 0, + + // If 1: require slave to only assert responses when STB=1 (stricter profile). + // If 0: allow "ghost" responses with STB=0; termination still only counts when STB=1. + parameter OPT_STRICT_RESP_WITH_STB = 0, + + // If 1: require termination signals to be pulses (1 cycle). + // If 0: allow them to be held. + parameter OPT_PULSE_RESP = 1, + + // If 1: during reset require master to hold CYC/STB low (assumption; common convention). + parameter OPT_STRICT_RESET = 1, + + // If 1: assert read data stable while ACK is held (useful if you allow ACK-hold). + parameter OPT_ASSERT_RDATA_STABLE_DURING_ACK = 1, + + // Optional widths + parameter AW = 32, + parameter DW = 32, + parameter SW = 4 ) ( - input wire i_clk, - input wire i_rst, - input wire i_wb_rst, - input wire [31:0] i_wb_adr, - input wire [31:0] i_wb_dat, - input wire [3:0] i_wb_sel, - input wire i_wb_we, - input wire i_wb_stb, - input wire i_wb_cyc, - input wire [31:0] o_wb_rdt, - input wire o_wb_ack + input wire i_clk, + input wire i_rst, + input wire i_wb_rst, + + // Master -> slave + input wire i_wb_cyc, + input wire i_wb_stb, + input wire i_wb_we, + input wire [AW-1:0] i_wb_adr, + input wire [DW-1:0] i_wb_dat, + input wire [SW-1:0] i_wb_sel, + + // Slave -> master + input wire o_wb_ack, + input wire o_wb_err, + input wire o_wb_rty, + input wire [DW-1:0] o_wb_rdt ); + +`ifdef FORMAL + // ----------------------------- + // Reset combine + // ----------------------------- + wire rst_any; + assign rst_any = i_rst | i_wb_rst; + + // ----------------------------- + // Formal infrastructure + // ----------------------------- reg f_past_valid; - initial f_past_valid = 1'b0; - - always @(posedge i_clk) begin + always @(posedge i_clk) f_past_valid <= 1'b1; - // A1: Reset forces cyc=0, stb=0 - if (i_rst) begin - A1: assume(!i_wb_cyc); - A2: assume(!i_wb_stb); - end + wire f_resp_any; + assign f_resp_any = o_wb_ack + | (OPT_USE_ERR ? o_wb_err : 1'b0) + | (OPT_USE_RTY ? o_wb_rty : 1'b0); - // A3: std->cyc, stb never high without cyc - if(i_wb_stb) - A3: assume(i_wb_cyc); + // Real termination only counts when STB=1 + wire f_terminate; + assign f_terminate = i_wb_cyc && i_wb_stb && f_resp_any; - // A4-A9: once a request starts, hold it stable until the slave responds - if(f_past_valid && $past(i_wb_cyc && i_wb_stb && !o_wb_ack)) begin - A4: assume(i_wb_cyc); - A5: assume(i_wb_stb); - A6: assume(i_wb_adr == $past(i_wb_adr)); - A7: assume(i_wb_dat == $past(i_wb_dat)); - A8: assume(i_wb_sel == $past(i_wb_sel)); - A9: assume(i_wb_we == $past(i_wb_we)); - end + // ----------------------------- + // Outstanding request tracking (Classic) + // ----------------------------- + reg f_pending; + initial f_pending = 1'b0; - // R1: ACK must correspond to either a same-cycle or previous-cycle request - if(o_wb_ack) - R1: assert( - (i_wb_cyc && i_wb_stb) || - (f_past_valid && $past(i_wb_cyc && i_wb_stb)) - ); - - // R2: !CYC->!ACK : no ghost acks - if(!i_wb_cyc) - R2: assert(!o_wb_ack); - - // R3: Reset must leave the slave initialized on the following cycle - if(f_past_valid && $past(i_rst || i_wb_rst)) - R3: assert(!o_wb_ack); - - // R4: once STB has been dropped for a full cycle, ACK must be low - if( - f_past_valid && - !$past(i_wb_stb) && - !i_wb_stb - ) - R4: assert(!o_wb_ack); - - // C1: A request occurs at all - C1: cover(f_past_valid && !i_rst && !i_wb_rst && i_wb_cyc && i_wb_stb); - - // C2-C3: A request with write and with read occur - C2: cover(f_past_valid && !i_rst && !i_wb_rst && i_wb_cyc && i_wb_stb && i_wb_we); - C3: cover(f_past_valid && !i_rst && !i_wb_rst && i_wb_cyc && i_wb_stb && !i_wb_we); - - // C4: ACK happens during a request (basic progress) - C4: cover(f_past_valid && !i_rst && !i_wb_rst && i_wb_cyc && i_wb_stb && o_wb_ack); - - // C5-C7: Exercise the expected ACK timing style for this slave. - if (combinatorial_ack) begin - C5: cover(f_past_valid && !i_rst && !i_wb_rst && - (i_wb_cyc && i_wb_stb) && o_wb_ack); + always @(posedge i_clk or posedge rst_any) begin + if (rst_any) begin + f_pending <= 1'b0; + end else if (!i_wb_cyc) begin + f_pending <= 1'b0; end else begin - C6: cover(f_past_valid && !i_rst && !i_wb_rst && - $past(i_wb_cyc && i_wb_stb) && o_wb_ack); + if (!f_pending && i_wb_stb) + f_pending <= 1'b1; - // C7: Optional wait-state behavior for slaves that intentionally stall. - if (expect_wait_state) - C7: cover(f_past_valid && !i_rst && !i_wb_rst && - $past(i_wb_cyc && i_wb_stb && !o_wb_ack) && - (i_wb_cyc && i_wb_stb && !o_wb_ack)); + if (f_terminate) + f_pending <= 1'b0; end - - // C8: Master ends a cycle (CYC drops) after at least one request - C8: cover(f_past_valid && !i_rst && !i_wb_rst && - $past(i_wb_cyc && i_wb_stb) && !i_wb_cyc); - end - wire unused = &{1'b0, o_wb_rdt}; -endmodule + // ----------------------------- + // Reset rules (recommended) + // ----------------------------- + always @(posedge i_clk) if (f_past_valid) begin + if (rst_any) begin + // R00: Monitor pending state must be cleared during reset + R00: assert(f_pending == 1'b0); + + if (OPT_STRICT_RESET) begin + // A00: During reset, assume the master is not attempting a bus cycle + A00: assume(!i_wb_cyc); + // A01: During reset, assume the master is not strobing + A01: assume(!i_wb_stb); + end + + // R01: Slave should not respond during reset (prevents silly traces) + R01: assert(!o_wb_ack); + if (OPT_USE_ERR) R02: assert(!o_wb_err); + if (OPT_USE_RTY) R03: assert(!o_wb_rty); + end + end + + // ----------------------------- + // Master/environment assumptions (Classic rules) + // ----------------------------- + always @(posedge i_clk) if (f_past_valid && !rst_any) begin + // A10: STB must imply CYC + if (i_wb_stb) begin + A10: assume(i_wb_cyc); + end + + // A11: While pending and not terminated, master holds CYC asserted + if ($past(f_pending) && !$past(f_terminate)) begin + A11: assume(i_wb_cyc); + end + + // A12: While pending and not terminated, master holds STB asserted + if ($past(f_pending) && !$past(f_terminate)) begin + A12: assume(i_wb_stb); + end + + // A13: Address stable while pending and not terminated + if ($past(f_pending) && !$past(f_terminate)) begin + A13: assume(i_wb_adr == $past(i_wb_adr)); + end + + // A14: WE stable while pending and not terminated + if ($past(f_pending) && !$past(f_terminate)) begin + A14: assume(i_wb_we == $past(i_wb_we)); + end + + // A15: SEL stable while pending and not terminated + if ($past(f_pending) && !$past(f_terminate)) begin + A15: assume(i_wb_sel == $past(i_wb_sel)); + end + + // A16: Write data stable while pending and not terminated + if ($past(f_pending) && !$past(f_terminate)) begin + A16: assume(i_wb_dat == $past(i_wb_dat)); + end + end + + // ----------------------------- + // Slave/DUT assertions (response sanity) + // ----------------------------- + always @(posedge i_clk) if (f_past_valid && !rst_any) begin + // R10: Any response must occur only during an active cycle + if (f_resp_any) begin + R10: assert(i_wb_cyc); + end + + // R11: Optional strict profile: response only when STB=1 + if (OPT_STRICT_RESP_WITH_STB && f_resp_any) begin + R11: assert(i_wb_stb); + end + + // R12-R14: Mutual exclusion of termination signals (recommended) + if (o_wb_ack) begin + if (OPT_USE_ERR) R12s1: assert(!o_wb_err); + if (OPT_USE_RTY) R12s2: assert(!o_wb_rty); + end + if (OPT_USE_ERR && o_wb_err) begin + R13s1: assert(!o_wb_ack); + if (OPT_USE_RTY) R13s2: assert(!o_wb_rty); + end + if (OPT_USE_RTY && o_wb_rty) begin + R14s1: assert(!o_wb_ack); + if (OPT_USE_ERR) R14s2: assert(!o_wb_err); + end + + // R15-R17: Optional pulse-only responses + if (OPT_PULSE_RESP) begin + if ($past(o_wb_ack)) begin + R15: assert(!o_wb_ack); + end + if (OPT_USE_ERR && $past(o_wb_err)) begin + R16: assert(!o_wb_err); + end + if (OPT_USE_RTY && $past(o_wb_rty)) begin + R17: assert(!o_wb_rty); + end + end + + // R18: A real termination (STB && response) should only happen when a request is pending. + if (i_wb_stb && f_resp_any) begin + R18: assert(f_pending || $past(f_pending)); + end + + // R19: Optional read-data stability while ACK is held (only relevant if ACK can be held) + if (OPT_ASSERT_RDATA_STABLE_DURING_ACK) begin + if (o_wb_ack && !i_wb_we && $past(o_wb_ack)) begin + R19: assert(o_wb_rdt == $past(o_wb_rdt)); + end + end + + // R20: If no cycle, no responses (strong sanity rule) + if (!i_wb_cyc) begin + R20: assert(!f_resp_any); + end + end + + // ----------------------------- + // Coverage: exercise the slave (useful witness traces) + // ----------------------------- + // TODO + +`endif +endmodule \ No newline at end of file diff --git a/cores/wb/wb_gpio/formal/formal_wb_gpio.v b/cores/wb/wb_gpio/formal/formal_wb_gpio.v index 5a4fdff..035e6b8 100644 --- a/cores/wb/wb_gpio/formal/formal_wb_gpio.v +++ b/cores/wb/wb_gpio/formal/formal_wb_gpio.v @@ -1,35 +1,29 @@ `timescale 1ns/1ps -module formal_wb_gpio #( - parameter [31:0] address = 32'h00000000 -); +module formal_wb_gpio; (* gclk *) reg i_wb_clk; - (* anyseq *) reg i_rst; (* anyseq *) reg i_wb_rst; (* anyseq *) reg [31:0] i_wb_adr; (* anyseq *) reg [31:0] i_wb_dat; (* anyseq *) reg [3:0] i_wb_sel; (* anyseq *) reg i_wb_we; (* anyseq *) reg i_wb_stb; + (* anyseq *) reg i_wb_cyc; (* anyseq *) reg [31:0] i_gpio; wire [31:0] o_wb_rdt; wire o_wb_ack; wire [31:0] o_gpio; - wire i_wb_cyc; reg f_past_valid; - assign i_wb_cyc = i_wb_stb || o_wb_ack; - - wb_gpio #( - .address(address) - ) dut ( - .i_wb_clk(i_wb_clk), - .i_wb_rst(i_wb_rst), + wb_gpio dut ( + .i_clk(i_wb_clk), + .i_rst(i_wb_rst), .i_wb_adr(i_wb_adr), .i_wb_dat(i_wb_dat), .i_wb_sel(i_wb_sel), .i_wb_we(i_wb_we), .i_wb_stb(i_wb_stb), + .i_wb_cyc(i_wb_cyc), .i_gpio(i_gpio), .o_wb_rdt(o_wb_rdt), .o_wb_ack(o_wb_ack), @@ -38,7 +32,7 @@ module formal_wb_gpio #( formal_wb_slave_checker wb_checker ( .i_clk(i_wb_clk), - .i_rst(i_rst), + .i_rst(i_wb_rst), .i_wb_rst(i_wb_rst), .i_wb_adr(i_wb_adr), .i_wb_dat(i_wb_dat), @@ -56,9 +50,13 @@ module formal_wb_gpio #( f_past_valid <= 1'b1; // R1: reads return the sampled GPIO input on the following cycle - if (f_past_valid && !$past(i_wb_rst) && !i_wb_rst && $past(i_wb_stb) && !$past(i_wb_we)) begin + if(f_past_valid && + !i_wb_rst && $past(!i_wb_rst) && + o_wb_ack && + $past(i_wb_sel)==4'hf && i_wb_sel==4'hf && + $past(i_wb_cyc & i_wb_stb & !i_wb_we) && + (i_wb_cyc & i_wb_stb & !i_wb_we)) assert(o_wb_rdt == $past(i_gpio)); - end // R2: reset clears the output register and read data register if (f_past_valid && $past(i_wb_rst)) begin diff --git a/cores/wb/wb_gpio/rtl/wb_gpio.v b/cores/wb/wb_gpio/rtl/wb_gpio.v index da8da52..bb59b8a 100644 --- a/cores/wb/wb_gpio/rtl/wb_gpio.v +++ b/cores/wb/wb_gpio/rtl/wb_gpio.v @@ -1,56 +1,53 @@ -module wb_gpio #( - parameter address = 32'h00000000 -)( - input wire i_wb_clk, - input wire i_wb_rst, // optional; tie low if unused - input wire [31:0] i_wb_adr, // optional; can ignore for single-reg - input wire [31:0] i_wb_dat, - input wire [3:0] i_wb_sel, - input wire i_wb_we, - input wire i_wb_stb, - input wire [31:0] i_gpio, +module wb_gpio ( + input wire i_clk, + input wire i_rst, - output reg [31:0] o_wb_rdt, - output reg o_wb_ack, - output reg [31:0] o_gpio + input wire [31:0] i_wb_adr, + input wire [31:0] i_wb_dat, + output reg [31:0] o_wb_rdt, + input wire [3:0] i_wb_sel, + input wire i_wb_we, + input wire i_wb_cyc, + input wire i_wb_stb, + output wire o_wb_ack, + + input wire [31:0] i_gpio, + output wire [31:0] o_gpio ); + + // Registers + reg [31:0] gpo; + wire [31:0] gpi; + assign o_gpio = gpo; + assign gpi = i_gpio; - initial o_gpio <= 32'h00000000; - initial o_wb_rdt <= 32'h00000000; + reg wb_ack = 0; + assign o_wb_ack = wb_ack & i_wb_cyc & i_wb_stb; - wire addr_check; - assign addr_check = (i_wb_adr == address); + always @(posedge i_clk) begin + if(i_rst) begin + gpo <= 0; + wb_ack <= 0; + o_wb_rdt <= 0; + end else begin + // Ack generation + wb_ack <= i_wb_cyc & i_wb_stb & !wb_ack; - // One-cycle ACK pulse per request (works even if stb stays high) - initial o_wb_ack <= 1'b0; - always @(posedge i_wb_clk) begin - if (i_wb_rst) begin - o_wb_ack <= 1'b0; - end else begin - o_wb_ack <= i_wb_stb & ~o_wb_ack; // pulse while stb asserted - end - end - - // Read data (combinational or registered; registered here) - always @(posedge i_wb_clk) begin - if (i_wb_rst) begin - o_wb_rdt <= 32'h0; - end else if (i_wb_stb && !i_wb_we) begin - o_wb_rdt <= i_gpio; - end - end - - // Write latch (update on the acknowledged cycle) - always @(posedge i_wb_clk) begin - if (i_wb_rst) begin - o_gpio <= 32'h0; - end else if (i_wb_stb && i_wb_we && addr_check && (i_wb_stb & ~o_wb_ack)) begin - // Apply byte enables (so sb works if the master uses sel) - if (i_wb_sel[0]) o_gpio[7:0] <= i_wb_dat[7:0]; - if (i_wb_sel[1]) o_gpio[15:8] <= i_wb_dat[15:8]; - if (i_wb_sel[2]) o_gpio[23:16] <= i_wb_dat[23:16]; - if (i_wb_sel[3]) o_gpio[31:24] <= i_wb_dat[31:24]; - end - end + // Read cycle + if(i_wb_cyc && i_wb_stb && !i_wb_we) begin + if(i_wb_sel[0]) o_wb_rdt[7:0] <= gpi[7:0]; + if(i_wb_sel[1]) o_wb_rdt[15:8] <= gpi[15:8]; + if(i_wb_sel[2]) o_wb_rdt[23:16] <= gpi[23:16]; + if(i_wb_sel[3]) o_wb_rdt[31:24] <= gpi[31:24]; + end + // write cycle + if(i_wb_cyc && i_wb_stb && i_wb_we) begin + if(i_wb_sel[0]) gpo[7:0] <= i_wb_dat[7:0]; + if(i_wb_sel[1]) gpo[15:8] <= i_wb_dat[15:8]; + if(i_wb_sel[2]) gpo[23:16] <= i_wb_dat[23:16]; + if(i_wb_sel[3]) gpo[31:24] <= i_wb_dat[31:24]; + end + end + end endmodule diff --git a/cores/wb/wb_gpio/wb_gpio.core b/cores/wb/wb_gpio/wb_gpio.core index 32e62e0..fa3cc43 100644 --- a/cores/wb/wb_gpio/wb_gpio.core +++ b/cores/wb/wb_gpio/wb_gpio.core @@ -25,8 +25,6 @@ targets: filesets: - rtl toplevel: wb_gpio - parameters: - - address formal: default_tool: symbiyosys @@ -35,11 +33,3 @@ targets: - formal_rtl - formal_cfg toplevel: formal_wb_gpio - parameters: - - address - -parameters: - address: - datatype: int - description: Wishbone address matched by this peripheral - paramtype: vlogparam diff --git a/cores/wb/wb_gpio_banks/formal/formal_wb_gpio_banks.v b/cores/wb/wb_gpio_banks/formal/formal_wb_gpio_banks.v index 505d4c1..658c7d1 100644 --- a/cores/wb/wb_gpio_banks/formal/formal_wb_gpio_banks.v +++ b/cores/wb/wb_gpio_banks/formal/formal_wb_gpio_banks.v @@ -1,31 +1,28 @@ `timescale 1ns/1ps module formal_wb_gpio_banks #( - parameter integer NUM_BANKS = 2, - parameter [31:0] BASE_ADDR = 32'h00000000 + parameter integer num_banks = 2, ); - (* gclk *) reg i_wb_clk; + (* gclk *) reg i_clk; (* anyseq *) reg i_rst; - (* anyseq *) reg i_wb_rst; (* anyseq *) reg [31:0] i_wb_adr; (* anyseq *) reg [31:0] i_wb_dat; (* anyseq *) reg [3:0] i_wb_sel; (* anyseq *) reg i_wb_we; (* anyseq *) reg i_wb_stb; - (* anyseq *) reg [NUM_BANKS*32-1:0] i_gpio; + (* anyseq *) reg [num_banks*32-1:0] i_gpio; wire [31:0] o_wb_rdt; wire o_wb_ack; - wire [NUM_BANKS*32-1:0] o_gpio; + wire [num_banks*32-1:0] o_gpio; wire i_wb_cyc; assign i_wb_cyc = i_wb_stb || o_wb_ack; wb_gpio_banks #( - .NUM_BANKS(NUM_BANKS), - .BASE_ADDR(BASE_ADDR) + .num_banks(num_banks) ) dut ( - .i_wb_clk(i_wb_clk), - .i_wb_rst(i_wb_rst), + .i_clk(i_clk), + .i_rst(i_rst), .i_wb_adr(i_wb_adr), .i_wb_dat(i_wb_dat), .i_wb_sel(i_wb_sel), @@ -38,9 +35,9 @@ module formal_wb_gpio_banks #( ); formal_wb_slave_checker wb_checker ( - .i_clk(i_wb_clk), + .i_clk(i_clk), .i_rst(i_rst), - .i_wb_rst(i_wb_rst), + .i_wb_rst(i_rst), .i_wb_adr(i_wb_adr), .i_wb_dat(i_wb_dat), .i_wb_sel(i_wb_sel), diff --git a/cores/wb/wb_gpio_banks/formal/wb_gpio_banks.sby b/cores/wb/wb_gpio_banks/formal/wb_gpio_banks.sby index be55a8b..e5382b5 100644 --- a/cores/wb/wb_gpio_banks/formal/wb_gpio_banks.sby +++ b/cores/wb/wb_gpio_banks/formal/wb_gpio_banks.sby @@ -16,8 +16,10 @@ cover: smtbmc yices prove: abc pdr [script] +read -formal clog2.vh {{"-formal"|gen_reads}} prep -top {{top_level}} [files] +src/joppeb_util_clog2_1.0/clog2.vh {{files}} diff --git a/cores/wb/wb_gpio_banks/rtl/wb_gpio_banks.v b/cores/wb/wb_gpio_banks/rtl/wb_gpio_banks.v index 48f4936..04476ec 100644 --- a/cores/wb/wb_gpio_banks/rtl/wb_gpio_banks.v +++ b/cores/wb/wb_gpio_banks/rtl/wb_gpio_banks.v @@ -1,63 +1,61 @@ -`default_nettype none +`include "clog2.vh" module wb_gpio_banks #( - parameter integer NUM_BANKS = 4, - parameter [31:0] BASE_ADDR = 32'h8000_0000 -) ( - input wire i_wb_clk, - input wire i_wb_rst, - input wire [31:0] i_wb_adr, - input wire [31:0] i_wb_dat, - input wire [3:0] i_wb_sel, - input wire i_wb_we, - input wire i_wb_stb, - input wire [NUM_BANKS*32-1:0] i_gpio, - output reg [31:0] o_wb_rdt, - output reg o_wb_ack, - output wire [NUM_BANKS*32-1:0] o_gpio + parameter num_banks = 4 +)( + input wire i_clk, + input wire i_rst, + + input wire [31:0] i_wb_adr, + input wire [31:0] i_wb_dat, + output reg [31:0] o_wb_rdt, + input wire [3:0] i_wb_sel, + input wire i_wb_we, + input wire i_wb_cyc, + input wire i_wb_stb, + output wire o_wb_ack, + + input wire [num_banks*32-1:0] i_gpio, + output wire [num_banks*32-1:0] o_gpio ); + localparam sw = `CLOG2(num_banks); + wire [num_banks-1:0] bank_sel; - wire [NUM_BANKS-1:0] bank_sel; - wire [NUM_BANKS-1:0] bank_stb; - wire [NUM_BANKS*32-1:0] bank_rdt; - wire [NUM_BANKS-1:0] bank_ack; + wire [num_banks-1:0] bank_ack; + wire [num_banks*32-1:0] bank_rdt; - genvar gi; - generate - for (gi = 0; gi < NUM_BANKS; gi = gi + 1) begin : gen_gpio - localparam [31:0] BANK_ADDR = BASE_ADDR + (gi * 4); + genvar gi; + generate + for(gi=0; gi