Commit 6fdd001b authored by Andrey Filippov's avatar Andrey Filippov
Browse files

Created Python script (with AHCI documentation) that generates BRAM...

Created Python script (with AHCI documentation) that generates BRAM initializaion for AHCI memory registers
parent 8db8ea19
Loading
Loading
Loading
Loading
+362 −31

File changed.

Preview size limit exceeded, changes collapsed.

+6 −0
Original line number Diff line number Diff line
, .INIT_00 (256'h0000000000000000000000000001030100000001000000008000000000240020)
, .INIT_08 (256'h000000000024000600000000000000000000000080000C000000000080000800)
, .INIT_09 (256'h000000000000000000000000000000000000000000000000FFFFFFFF00000000)
, .INIT_0C (256'h000000000000000000000000000000000000000001010001001000000001FFFE)
, .INIT_0D (256'h000001000000000000000040000000000001FFFE000000008000000000000000)
, .INIT_0E (256'h0000000000000000000000000000000000000000000000000000000040000001)

includes/ahci_types.vh

0 → 100644
+10 −0
Original line number Diff line number Diff line
, .INIT_00 (256'h0000000000000000AAAAAAAAAAAAAAAA00000000000000070000000000000000)
, .INIT_10 (256'h0000000000000000555555555555000000000000000000005555555555500000)
, .INIT_11 (256'h000000000000000055054004000001C15551400000000455AAA28000000008AA)
, .INIT_12 (256'h0000000000550000000000000000000000000000000000000000000000000000)
, .INIT_13 (256'h00000000AAAAAAAAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF002AAAAA00AA0008)
, .INIT_14 (256'h000000000000000000000000000000000001555555555550000000000055000D)
, .INIT_17 (256'h5555555555555555555555555555555555555555555555555555555555555555)
, .INIT_18 (256'h00000000000055550000000000000000AA820000001000140000000000000000)
, .INIT_1B (256'h0000000000005555000000000000000000000000000000000000000000000000)
, .INIT_1C (256'h0000000000000000000000000000000000000000800100050000000000000000)
+57 −41
Original line number Diff line number Diff line
@@ -25,7 +25,8 @@


module  axi_ahci_regs#(
    parameter ADDRESS_BITS = 8 // number of memory address bits
//    parameter ADDRESS_BITS = 8 // number of memory address bits
    parameter ADDRESS_BITS = 10 // number of memory address bits - now fixed. Low half - RO/RW/RWC,RW1 (2-cycle write), 2-nd just RW (single-cycle)
)(
    input             aclk,    // clock - should be buffered
    input             arst,     // @aclk sync reset, active high
@@ -84,7 +85,7 @@ module axi_ahci_regs#(
    output             [31:0] hba_dout
);
    wire   [ADDRESS_BITS-1:0] bram_waddr;
    wire   [ADDRESS_BITS-1:0] pre_awaddr;
//    wire   [ADDRESS_BITS-1:0] pre_awaddr;
    wire   [ADDRESS_BITS-1:0] bram_raddr;
    wire               [31:0] bram_rdata;
    wire                      pre_bram_wen; // one cycle ahead of bram_wen, nut not masked by dev_ready
@@ -101,12 +102,17 @@ module axi_ahci_regs#(
    wire                   write_busy_w = write_busy_r || write_start_burst;
    reg             [31:0] bram_wdata_r;
    reg             [31:0] bram_rdata_r;
    reg          bram_wen_d;
//    reg                    bram_wen_d;
    wire            [63:0] regbit_type;
    wire            [31:0] ahci_regs_di;
    wire  [31:0] wmask = {{8{bram_wstb[3]}},{8{bram_wstb[2]}},{8{bram_wstb[1]}},{8{bram_wstb[0]}}};
    
    assign bram_addr = bram_ren[0] ? bram_raddr : (bram_wen ? bram_waddr : pre_awaddr);
    reg             [ 3:0] bram_wstb_r;
    reg                    bram_wen_r;
//    wire  [31:0] wmask = {{8{bram_wstb[3]}},{8{bram_wstb[2]}},{8{bram_wstb[1]}},{8{bram_wstb[0]}}};
    wire            [31:0] wmask = {{8{bram_wstb_r[3]}},{8{bram_wstb_r[2]}},{8{bram_wstb_r[1]}},{8{bram_wstb_r[0]}}};
    reg [ADDRESS_BITS-1:0] bram_waddr_r;
    wire                   high_sel = bram_waddr_r[ADDRESS_BITS-1]; // high addresses - use single-cycle writes without read-modify-write
//    assign bram_addr = bram_ren[0] ? bram_raddr : (bram_wen ? bram_waddr : pre_awaddr);
    assign bram_addr = bram_ren[0] ? bram_raddr : (bram_wen_r ? bram_waddr_r : bram_waddr);
    always @(posedge aclk) begin
        if      (arst)              write_busy_r <= 0;
        else if (write_start_burst) write_busy_r <= 1;
@@ -115,18 +121,24 @@ module axi_ahci_regs#(
        if (bram_wen)               bram_wdata_r <= bram_wdata;
        
        if (bram_ren[1])            bram_rdata_r <= bram_rdata;
        bram_wen_d <= bram_wen;
        
        bram_wstb_r <= {4{bram_wen}} & bram_wstb;
        
        bram_wen_r <= bram_wen;
        
        if (bram_wen) bram_waddr_r <= bram_waddr;
        
    end

    generate
        genvar i;
        for (i=0; i < 32; i=i+1) begin: bit_type_block
            assign ahci_regs_di[i] = (regbit_type[2*i+1] && wmask[i])?
            assign ahci_regs_di[i] = (regbit_type[2*i+1] && wmask[i] && !high_sel)?
                                       ((regbit_type[2*i] && wmask[i])?
                                          (bram_rdata[i] || bram_wdata_r[i]):   // 3: RW1
                                          (bram_rdata[i] && !bram_wdata_r[i])): // 2: RWC
                                       ((regbit_type[2*i] && wmask[i])?
                                          (bram_wdata_r[i]):                    // 1: RW write new data
                                       (((regbit_type[2*i] && wmask[i]) || high_sel)?
                                          (bram_wdata_r[i]):                    // 1: RW write new data - get here for high_sel
                                          (bram_rdata[i]));                     // 0: R0 (keep old data)
        end
    endgenerate    
@@ -153,7 +165,7 @@ module axi_ahci_regs#(
        .bready      (bready),                   // input
        .bid         (bid),                      // output[11:0] 
        .bresp       (bresp),                    // output[1:0] 
        .pre_awaddr  (pre_awaddr),               // output[9:0] 
        .pre_awaddr  (), //pre_awaddr),          // output[9:0] 
        .start_burst (write_start_burst),        // output
//        .dev_ready   (!nowrite && !bram_ren[0]), // input
        .dev_ready   (!bram_wen),                // input   There will be no 2 bram_wen in a row
@@ -193,33 +205,37 @@ module axi_ahci_regs#(
        .bram_rdata  (bram_rdata_r)              // input[31:0] 
    );

   wire               [ 9:0] hba_addr_ext =  (ADDRESS_BITS == 10)? hba_addr: {{(10-ADDRESS_BITS){1'b0}}, hba_addr} ;
   wire               [ 9:0] bram_addr_ext = (ADDRESS_BITS == 10)? bram_addr: {{(10-ADDRESS_BITS){1'b0}}, bram_addr} ;
   wire               [ 8:0] brom_addr_ext = (ADDRESS_BITS == 9)? bram_addr: {{(9-ADDRESS_BITS){1'b0}}, bram_addr} ;
    // Register memory, lower half uses read-modify-write using bit type from ahci_regs_type_i ROM, 2 aclk cycles/per write and
    // high addresses half are just plain write registers, they heve single-cycle write
    // Only low registers write generates cross-clock writes over the FIFO.
    // All registers can be accessed in byte/word/dword mode over the AXI
    
    // Lower registers are used as AHCI memory registers, high - for AHCI command list(s), to eliminate the need to update transfer count
    // in the system memory.

    ramt_var_w_var_r #(
    ramt_var_wb_var_r #(
        .REGISTERS_A (0),
        .REGISTERS_B (1),
        .LOG2WIDTH_A (5),
        .LOG2WIDTH_B (5),
        .WRITE_MODE_A("NO_CHANGE"),
        .WRITE_MODE_B("NO_CHANGE")
        // TODO:  include here init (default values)
        `include "includes/ahci_defaults.vh" 
    ) ahci_regs_i (
        .clk_a        (aclk),                        // input
        .addr_a       (bram_addr_ext),               // input[9:0] 
        .addr_a       (bram_addr),                   // input[9:0] 
        .en_a         (bram_ren[0] || write_busy_w), // input
        .regen_a      (1'b0),                 // input
//        .we_a         (write_busy_r && !nowrite),    // input
        .we_a         (bram_wen_d),                  // input
        .we_a         (bram_wstb_r), //bram_wen_d),  // input[3:0]
//        
        .data_out_a   (bram_rdata),                  // output[31:0] 
        .data_in_a    (ahci_regs_di),                // input[31:0] 
        .clk_b        (hba_clk),                     // input
        .addr_b       (hba_addr_ext),                // input[9:0] 
        .addr_b       (hba_addr),                    // input[9:0] 
        .en_b         (hba_we || hba_re[0]),         // input
        .regen_b      (hba_re[1]),                   // input
        .we_b         (hba_we),                      // input
        .we_b         ({4{hba_we}}),                      // input
        .data_out_b   (hba_dout),                    // output[31:0] 
        .data_in_b    (hba_din)                      // input[31:0] 
    );
@@ -229,11 +245,11 @@ module axi_ahci_regs#(
        .LOG2WIDTH_WR (6),
        .LOG2WIDTH_RD (6),
        .DUMMY(0)
        // TODO:  include here init (register bit types (RO, RW, RWC, RW1)
        `include "includes/ahci_types.vh" 
    ) ahci_regs_type_i (
        .rclk         (aclk),                       // input
        .raddr        (brom_addr_ext), // input[8:0] 
        .ren          (bram_wen),      // input
        .raddr        (bram_addr[8:0]),             // input[8:0] 
        .ren          (bram_wen && !bram_addr[9]),  // input
        .regen        (1'b0),                       // input
        .data_out     (regbit_type),                // output[63:0] 
        .wclk         (1'b0),                       // input
@@ -252,7 +268,7 @@ module axi_ahci_regs#(
        .wrst       (arst),                              // input
        .rclk       (hba_clk),                           // input
        .wclk       (aclk),                              // input
        .we         (bram_wen_d),                        // input
        .we         (bram_wen_r && !high_sel),           // input
        .re         (soft_write_en),                     // input
        .data_in    ({bram_addr, ahci_regs_di}),         // input[15:0] 
        .data_out   ({soft_write_addr,soft_write_data}), // output[15:0] 
+215 −0
Original line number Diff line number Diff line
/*******************************************************************************
 * Module: ramt_var_wb_var_r
 * Date:2015-05-29  
 * Author: Andrey Filippov     
 * Description:  Dual port memory wrapper, with variable width write (with mask) and variable
 * width read,  using "TDP" mode of RAMB36E1. Same R/W widths in each port.
 * Does not use parity bits to increase total data width, width down to 1 are valid.
 *
 * Copyright (c) 2015 Elphel, Inc.
 * ramt_var_wb_var_r.v is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  ramt_var_wb_var_r.v is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/> .
 *
 * Additional permission under GNU GPL version 3 section 7:
 * If you modify this Program, or any covered work, by linking or combining it
 * with independent modules provided by the FPGA vendor only (this permission
 * does not extend to any 3-rd party modules, "soft cores" or macros) under
 * different license terms solely for the purpose of generating binary "bitstream"
 * files and/or simulating the code, the copyright holders of this Program give
 * you the right to distribute the covered work without those independent modules
 * as long as the source code for them is available from the FPGA vendor free of
 * charge, and there is no dependence on any encrypted modules for simulating of
 * the combined code. This permission applies to you if the distributed code
 * contains all the components and scripts required to completely simulate it
 * with at least one of the Free Software programs.
 *******************************************************************************/
`timescale 1ns/1ps
`include "system_defines.vh" 
/*
   Address/data widths
   Connect unused data to 1b0, unused addresses - to 1'b1
   
   RAMB18E1 in True Dual Port (TDP) Mode - each port individually
   +-----------+---------+---------+---------+
   |Data Width | Address |   Data  | Parity  |
   +-----------+---------+---------+---------+
   |     1     | A[13:0] | D[0]    |  ---    |
   |     2     | A[13:1] | D[1:0]  |  ---    |
   |     4     | A[13:2] | D[3:0[  |  ---    |
   |     9     | A[13:3] | D[7:0]  | DP[0]   |
   |    18     | A[13:4] | D[15:0] | DP[1:0] |
   +-----------+---------+---------+---------+

   RAMB18E1 in Simple Dual Port (SDP) Mode
   one of the ports (r or w) - 32/36 bits, other - variable 
   +------------+---------+---------+---------+
   |Data Widths | Address |   Data  | Parity  |
   +------------+---------+---------+---------+
   |   32/  1   | A[13:0] | D[0]    |  ---    |
   |   32/  2   | A[13:1] | D[1:0]  |  ---    |
   |   32/  4   | A[13:2] | D[3:0[  |  ---    |
   |   36/  9   | A[13:3] | D[7:0]  | DP[0]   |
   |   36/ 18   | A[13:4] | D[15:0] | DP[1:0] |
   |   36/ 36   | A[13:5] | D[31:0] | DP[3:0] |
   +------------+---------+---------+---------+
   
   RAMB36E1 in True Dual Port (TDP) Mode - each port individually
   +-----------+---------+---------+---------+
   |Data Width | Address |   Data  | Parity  |
   +-----------+---------+---------+---------+
   |     1     | A[14:0] | D[0]    |  ---    |
   |     2     | A[14:1] | D[1:0]  |  ---    |
   |     4     | A[14:2] | D[3:0[  |  ---    |
   |     9     | A[14:3] | D[7:0]  | DP[0]   |
   |    18     | A[14:4] | D[15:0] | DP[1:0] |
   |    36     | A[14:5] | D[31:0] | DP[3:0] |
   |1(Cascade) | A[15:0] | D[0]    |  ---    |
   +-----------+---------+---------+---------+

   RAMB36E1 in Simple Dual Port (SDP) Mode
   one of the ports (r or w) - 64/72 bits, other - variable 
   +------------+---------+---------+---------+
   |Data Widths | Address |   Data  | Parity  |
   +------------+---------+---------+---------+
   |   64/  1   | A[14:0] | D[0]    |  ---    |
   |   64/  2   | A[14:1] | D[1:0]  |  ---    |
   |   64/  4   | A[14:2] | D[3:0[  |  ---    |
   |   64/  9   | A[14:3] | D[7:0]  | DP[0]   |
   |   64/ 18   | A[14:4] | D[15:0] | DP[1:0] |
   |   64/ 36   | A[14:5] | D[31:0] | DP[3:0] |
   |   64/ 72   | A[14:6] | D[63:0] | DP[7:0] |
   +------------+---------+---------+---------+
*/

module  ramt_var_wb_var_r
#(
  parameter integer REGISTERS_A = 0, // 1 - registered output
  parameter integer REGISTERS_B = 0, // 1 - registered output
  parameter integer LOG2WIDTH_A = 5,  // WIDTH= 9  << (LOG2WIDTH - 3)
  parameter integer LOG2WIDTH_B = 5,  // WIDTH= 9  << (LOG2WIDTH - 3)
  parameter WRITE_MODE_A =        "NO_CHANGE", //Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
  parameter WRITE_MODE_B =        "NO_CHANGE"  //Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
`ifdef PRELOAD_BRAMS
    ,
    `include "includes/ram36_declare_init.vh"
`endif
 )(
      input                               clk_a,     // clock for port A
      input            [14-LOG2WIDTH_A:0] addr_a,    // address port A
      input                               en_a,      // enable port A (read and write)
      input                               regen_a,   // output register enable port A
//      input  [((LOG2WIDTH_A > 3)? (LOG2WIDTH_A-3):0):0] we_a,      // write port enable port A
      input  [((LOG2WIDTH_A > 3)? ((LOG2WIDTH_A > 4)?3:1):0):0] we_a,      // write port enable port A
      output     [(1 << LOG2WIDTH_A)-1:0] data_out_a,// data out port A
      input      [(1 << LOG2WIDTH_A)-1:0] data_in_a, // data in port A
      
      input                               clk_b,     // clock for port BA
      input            [14-LOG2WIDTH_B:0] addr_b,    // address port B
      input                               en_b,      // read enable port B
      input                               regen_b,   // output register enable port B
//      input  [((LOG2WIDTH_B > 3)? (LOG2WIDTH_B-3):0):0] we_b,      // write port enable port B
      input  [((LOG2WIDTH_B > 3)? ((LOG2WIDTH_B > 4)?3:1):0):0] we_b,      // write port enable port B

      output     [(1 << LOG2WIDTH_B)-1:0] data_out_b,// data out port B
      input      [(1 << LOG2WIDTH_B)-1:0] data_in_b  // data in port B
);
    localparam  PWIDTH_A = (LOG2WIDTH_A > 2)? (9 << (LOG2WIDTH_A - 3)): (1 << LOG2WIDTH_A);
    localparam  PWIDTH_B = (LOG2WIDTH_B > 2)? (9 << (LOG2WIDTH_B - 3)): (1 << LOG2WIDTH_B);
    localparam  WIDTH_A  = 1 << LOG2WIDTH_A;
    localparam  WIDTH_B  = 1 << LOG2WIDTH_B;
    
    wire          [31:0] data_out32_a;
    assign data_out_a=data_out32_a[WIDTH_A-1:0];

    wire          [31:0] data_out32_b;
    assign data_out_b=data_out32_b[WIDTH_B-1:0];


    wire [WIDTH_A+31:0] data_in_ext_a =  {32'b0,data_in_a[WIDTH_A-1:0]};
    wire         [31:0] data_in32_a =    data_in_ext_a[31:0];

    wire [WIDTH_B+31:0] data_in_ext_b =  {32'b0,data_in_b[WIDTH_B-1:0]};
    wire         [31:0] data_in32_b =    data_in_ext_b[31:0];
    
    wire [3:0] we_a4= (LOG2WIDTH_A > 3)? ((LOG2WIDTH_A > 4)? we_a : {2{we_a}} ):{4{we_a}};
    wire [3:0] we_b4= (LOG2WIDTH_B > 3)? ((LOG2WIDTH_B > 4)? we_a : {2{we_b}} ):{4{we_b}};

    RAMB36E1
    #(
    .RSTREG_PRIORITY_A         ("RSTREG"),       // Valid: "RSTREG" or "REGCE"
    .RSTREG_PRIORITY_B         ("RSTREG"),       // Valid: "RSTREG" or "REGCE"
    .DOA_REG                   (REGISTERS_A),    // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
    .DOB_REG                   (REGISTERS_B),    // Valid: 0 (no output registers) and 1 - one output register (in SDP - to lower 36)
    .RAM_EXTENSION_A           ("NONE"),         // Cascading, valid: "NONE","UPPER", LOWER"
    .RAM_EXTENSION_B           ("NONE"),         // Cascading, valid: "NONE","UPPER", LOWER"
    .READ_WIDTH_A              (PWIDTH_A),       // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
    .READ_WIDTH_B              (PWIDTH_B),       // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
    .WRITE_WIDTH_A             (PWIDTH_A),              // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
    .WRITE_WIDTH_B             (PWIDTH_B),       // Valid: 0,1,2,4,9,18,36 and in SDP mode - 72 (should be 0 if port is not used)
    .RAM_MODE                  ("TDP"),          // Valid "TDP" (true dual-port) and "SDP" - simple dual-port
    .WRITE_MODE_A              (WRITE_MODE_A),   // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
    .WRITE_MODE_B              (WRITE_MODE_B),   // Valid: "WRITE_FIRST", "READ_FIRST", "NO_CHANGE"
    .RDADDR_COLLISION_HWCONFIG ("DELAYED_WRITE"),// Valid: "DELAYED_WRITE","PERFORMANCE" (no access to the same page)
    .SIM_COLLISION_CHECK       ("ALL"),          // Valid: "ALL", "GENERATE_X_ONLY", "NONE", and "WARNING_ONLY"
    .INIT_FILE                 ("NONE"),         // "NONE" or filename with initialization data
    .SIM_DEVICE                ("7SERIES"),      // Simulation device family - "VIRTEX6", "VIRTEX5" and "7_SERIES" // "7SERIES"

    .EN_ECC_READ               ("FALSE"),        // Valid:"FALSE","TRUE" (ECC decoder circuitry)
    .EN_ECC_WRITE              ("FALSE")         // Valid:"FALSE","TRUE" (ECC decoder circuitry)
`ifdef PRELOAD_BRAMS
    `include "includes/ram36_pass_init.vh"
`endif
    
    ) RAMB36E1_i
    (
        // Port A (Read port in SDP mode):
        .DOADO           (data_out32_a),    // Port A data/LSB data[31:0], output
        .DOPADOP         (),                // Port A parity/LSB parity[3:0], output
        .DIADI           (data_in32_a),     // Port A data/LSB data[31:0], input
        .DIPADIP         (4'b0),            // Port A parity/LSB parity[3:0], input
        .ADDRARDADDR     ({1'b1,addr_a,{LOG2WIDTH_A{1'b1}}}),  // Port A (read port in SDP) address [15:0]. used from [14] down, unused should be high, input
        .CLKARDCLK       (clk_a),           // Port A (read port in SDP) clock, input
        .ENARDEN         (en_a),            // Port A (read port in SDP) Enable, input
        .REGCEAREGCE     (regen_a),         // Port A (read port in SDP) register enable, input
        .RSTRAMARSTRAM   (1'b0),            // Port A (read port in SDP) set/reset, input
        .RSTREGARSTREG   (1'b0),            // Port A (read port in SDP) register set/reset, input
        .WEA             (we_a4),           // Port A (read port in SDP) Write Enable[3:0], input
        // Port B
        .DOBDO           (data_out32_b),    // Port B data/MSB data[31:0], output
        .DOPBDOP         (),                // Port B parity/MSB parity[3:0], output
        .DIBDI           (data_in32_b),     // Port B data/MSB data[31:0], input
        .DIPBDIP         (4'b0),            // Port B parity/MSB parity[3:0], input
        .ADDRBWRADDR     ({1'b1,addr_b,{LOG2WIDTH_B{1'b1}}}), // Port B (write port in SDP) address [15:0]. used from [14] down, unused should be high, input
        .CLKBWRCLK       (clk_b),           // Port B (write port in SDP) clock, input
        .ENBWREN         (en_b),            // Port B (write port in SDP) Enable, input
        .REGCEB          (regen_b),         // Port B (write port in SDP) register enable, input
        .RSTRAMB         (1'b0),            // Port B (write port in SDP) set/reset, input
        .RSTREGB         (1'b0),            // Port B (write port in SDP) register set/reset, input
        .WEBWE           ({4'b0,we_b4}),// Port B (write port in SDP) Write Enable[7:0], input
        // Error correction circuitry
        .SBITERR         (),                // Single bit error status, output
        .DBITERR         (),                // Double bit error status, output
        .ECCPARITY       (),                // Genearted error correction parity [7:0], output
        .RDADDRECC       (),                // ECC read address[8:0], output
        .INJECTSBITERR   (1'b0),            // inject a single-bit error, input
        .INJECTDBITERR   (1'b0),            // inject a double-bit error, input
        // Cascade signals to create 64Kx1
        .CASCADEOUTA     (),                // A-port cascade, output   
        .CASCADEOUTB     (),                // B-port cascade, output
        .CASCADEINA      (1'b0),            // A-port cascade, input
        .CASCADEINB      (1'b0)             // B-port cascade, input
    );


endmodule