dakies/OSS_Verilog huggingface dataset:
module Clock_gen
 (// Clock in ports
  input         CLK_IN1,
  // Clock out ports
  output        CLK_OUT1
 );

  // Input buffering
  //------------------------------------
  IBUFG clkin1_buf
   (.O (clkin1),
    .I (CLK_IN1));


  // Clocking primitive
  //------------------------------------
  // Instantiation of the PLL primitive
  //    * Unused inputs are tied off
  //    * Unused outputs are labeled unused
  wire [15:0] do_unused;
  wire        drdy_unused;
  wire        locked_unused;
  wire        clkfbout;
  wire        clkfbout_buf;
  wire        clkout1_unused;
  wire        clkout2_unused;
  wire        clkout3_unused;
  wire        clkout4_unused;
  wire        clkout5_unused;

  PLL_BASE
  #(.BANDWIDTH              ("OPTIMIZED"),
    .CLK_FEEDBACK           ("CLKFBOUT"),
    .COMPENSATION           ("SYSTEM_SYNCHRONOUS"),
    .DIVCLK_DIVIDE          (1),
    .CLKFBOUT_MULT          (4),
    .CLKFBOUT_PHASE         (0.000),
    .CLKOUT0_DIVIDE         (1),
    .CLKOUT0_PHASE          (0.000),
    .CLKOUT0_DUTY_CYCLE     (0.500),
    .CLKIN_PERIOD           (10.0),
    .REF_JITTER             (0.010))
  pll_base_inst
    // Output clocks
   (.CLKFBOUT              (clkfbout),
    .CLKOUT0               (clkout0),
    .CLKOUT1               (clkout1_unused),
    .CLKOUT2               (clkout2_unused),
    .CLKOUT3               (clkout3_unused),
    .CLKOUT4               (clkout4_unused),
    .CLKOUT5               (clkout5_unused),
    .LOCKED                (locked_unused),
    .RST                   (1'b0),
     // Input clock control
    .CLKFBIN               (clkfbout_buf),
    .CLKIN                 (clkin1));


  // Output buffering
  //-----------------------------------
  BUFG clkf_buf
   (.O (clkfbout_buf),
    .I (clkfbout));

  BUFG clkout1_buf
   (.O   (CLK_OUT1),
    .I   (clkout0));




endmodule
module rvsteel_ram #(

  // Memory size in bytes
  parameter MEMORY_SIZE      = 8192,

  // File with program and data
  parameter MEMORY_INIT_FILE = ""

  ) (

  // Global signals

  input   wire          clock,
  input   wire          reset,

  // IO interface

  input  wire   [31:0]  rw_address,
  output reg    [31:0]  read_data,
  input  wire           read_request,
  output reg            read_response,
  input  wire   [31:0]  write_data,
  input  wire   [3:0 ]  write_strobe,
  input  wire           write_request,
  output reg            write_response

  );

  wire                        reset_internal;
  wire [31:0]                 effective_address;
  wire                        invalid_address;

  reg                         reset_reg;
  reg [31:0]                  ram [0:(MEMORY_SIZE/4)-1];

  always @(posedge clock)
    reset_reg <= reset;

  assign reset_internal = reset | reset_reg;
  assign invalid_address = $unsigned(rw_address) >= $unsigned(MEMORY_SIZE);

  integer i;
  initial begin
    for (i = 0; i < MEMORY_SIZE/4; i = i + 1) ram[i] = 32'h00000000;
    if (MEMORY_INIT_FILE != "")
      $readmemh(MEMORY_INIT_FILE,ram);
  end

  assign effective_address =
    $unsigned(rw_address[31:0] >> 2);

  always @(posedge clock) begin
    if (reset_internal | invalid_address)
      read_data <= 32'h00000000;
    else
      read_data <= ram[effective_address];
  end

  always @(posedge clock) begin
    if(write_request) begin
      if(write_strobe[0])
        ram[effective_address][7:0  ] <= write_data[7:0  ];
      if(write_strobe[1])
        ram[effective_address][15:8 ] <= write_data[15:8 ];
      if(write_strobe[2])
        ram[effective_address][23:16] <= write_data[23:16];
      if(write_strobe[3])
        ram[effective_address][31:24] <= write_data[31:24];
    end
  end

  always @(posedge clock) begin
    if (reset_internal) begin
      read_response  <= 1'b0;
      write_response <= 1'b0;
    end
    else begin
      read_response  <= read_request;
      write_response <= write_request;
    end
  end

  // Avoid warnings about intentionally unused pins/wires
  wire unused_ok =
    &{1'b0,
    effective_address[31:11],
    1'b0};

endmodule
module rvsteel_bus #(

  parameter NUM_DEVICES               = 1

  )(

  // Global signals

  input   wire                        clock                 ,
  input   wire                        reset                 ,

  // Interface with the manager device (Processor Core IP)

  input   wire  [31:0]                manager_rw_address    ,
  output  reg   [31:0]                manager_read_data     ,
  input   wire                        manager_read_request  ,
  output  reg                         manager_read_response ,
  input   wire  [31:0]                manager_write_data    ,
  input   wire  [3:0 ]                manager_write_strobe  ,
  input   wire                        manager_write_request ,
  output  reg                         manager_write_response,

  // Interface with the managed devices

  output  wire  [31:0]                device_rw_address     ,
  input   wire  [NUM_DEVICES*32-1:0]  device_read_data      ,
  output  wire  [NUM_DEVICES-1:0]     device_read_request   ,
  input   wire  [NUM_DEVICES-1:0]     device_read_response  ,
  output  wire  [31:0]                device_write_data     ,
  output  wire  [3:0 ]                device_write_strobe   ,
  output  wire  [NUM_DEVICES-1:0]     device_write_request  ,
  input   wire  [NUM_DEVICES-1:0]     device_write_response ,

  // Base addresses and masks of the managed devices

  input   wire  [NUM_DEVICES*32-1:0]  device_start_address  ,
  input   wire  [NUM_DEVICES*32-1:0]  device_region_size

  );

  integer i;

  reg [NUM_DEVICES*32-1:0]      device_mask_address;
  reg [NUM_DEVICES-1:0]         device_sel;
  reg [NUM_DEVICES-1:0]         device_sel_save;

  // Manager request

  assign device_rw_address      = manager_rw_address;
  assign device_read_request    = device_sel & {NUM_DEVICES{manager_read_request}};
  assign device_write_data      = manager_write_data;
  assign device_write_strobe    = manager_write_strobe;
  assign device_write_request   = device_sel & {NUM_DEVICES{manager_write_request}};

  // Device response selection

  always @(*) begin
    for (i = 0; i < NUM_DEVICES; i = i + 1) begin
      device_mask_address[i*32 +:32] = ~(device_region_size[i*32 +:32] - 1);
      if ((manager_rw_address & device_mask_address[i*32 +:32]) == device_start_address[i*32 +:32])
        device_sel[i] = 1'b1;
      else
        device_sel[i] = 1'b0;
    end
  end

  always @(posedge clock) begin
    if (reset)
      device_sel_save <= {NUM_DEVICES{1'b0}};
    else if ((manager_read_request || manager_write_request) && (|device_sel))
      device_sel_save <= device_sel;
    else
      device_sel_save <= {NUM_DEVICES{1'b0}};
  end

  always @(*) begin
    manager_read_data           = 32'b0;
    manager_read_response       = 1'b1;
    manager_write_response      = 1'b1;
    for (i = 0; i < NUM_DEVICES; i = i + 1) begin
      if (device_sel_save[i]) begin
        manager_read_data       = device_read_data[i*32 +: 32];
        manager_read_response   = device_read_response[i];
        manager_write_response  = device_write_response[i];
      end
    end
  end

endmodule
module mcu_sim #(

    // Number of available I/O ports
    parameter GPIO_WIDTH    = 2,
    // Number of CS (Chip Select) pins for the SPI controller
    parameter SPI_NUM_CHIP_SELECT  = 1

  ) (

    input   wire                            clock       ,
    input   wire                            reset       ,
    input   wire                            halt        ,
    input   wire                            uart_rx     ,
    output  wire                            uart_tx     ,
    input   wire  [GPIO_WIDTH-1:0]          gpio_input  ,
    output  wire  [GPIO_WIDTH-1:0]          gpio_oe     ,
    output  wire  [GPIO_WIDTH-1:0]          gpio_output ,
    output  wire                            sclk        ,
    output  wire                            pico        ,
    input   wire                            poci        ,
    output  wire  [SPI_NUM_CHIP_SELECT-1:0] cs
  );

  rvsteel_mcu #(

    .CLOCK_FREQUENCY          (50000000           ),
    .UART_BAUD_RATE           (9600               ),
    .MEMORY_SIZE              (32768              ),
    .MEMORY_INIT_FILE         (""                 ),
    .BOOT_ADDRESS             (32'h00000000       ),
    .GPIO_WIDTH               (GPIO_WIDTH         )

  ) rvsteel_mcu_instance (

    .clock                    (clock              ),
    .reset                    (reset              ),
    .halt                     (halt               ),
    .uart_rx                  (uart_rx            ),
    .uart_tx                  (uart_tx            ),
    .gpio_input               (gpio_input         ),
    .gpio_oe                  (gpio_oe            ),
    .gpio_output              (gpio_output        ),
    .sclk                     (sclk               ),
    .pico                     (pico               ),
    .poci                     (poci               ),
    .cs                       (cs                 )
  );

endmodule
module unit_tests (

  input   wire clock,
  input   wire reset,
  input   wire halt,
  input   wire uart_rx,
  output  wire uart_tx

  );

  localparam SPI_NUM_CHIP_SELECT = 2;

  wire sclk;
  wire pico;
  wire poci;
  wire [SPI_NUM_CHIP_SELECT-1:0] cs;

  // Divides the 100MHz board block by 4
  reg clock_50mhz;
  initial clock_50mhz = 1'b0;
  always @(posedge clock) clock_50mhz <= !clock_50mhz;

  // Buttons debouncing
  reg reset_debounced;
  reg halt_debounced;
  always @(posedge clock_50mhz) begin
    reset_debounced <= reset;
    halt_debounced <= halt;
  end

  rvsteel_mcu #(

    .CLOCK_FREQUENCY          (50000000           ),
    .UART_BAUD_RATE           (9600               ),
    .MEMORY_SIZE              (8192               ),
    .MEMORY_INIT_FILE         ("unit_tests.hex"   ),
    .BOOT_ADDRESS             (32'h00000000       ),
    .SPI_NUM_CHIP_SELECT      (2                  )

  ) rvsteel_mcu_instance (

    .clock                    (clock_50mhz        ),
    .reset                    (reset_debounced    ),
    .halt                     (halt_debounced     ),
    .uart_rx                  (uart_rx            ),
    .uart_tx                  (uart_tx            ),
    .gpio_input               (1'b0               ),
    .gpio_oe                  (                   ),
    .gpio_output              (                   ),
    .sclk                     (sclk               ),
    .pico                     (pico               ),
    .poci                     (poci               ),
    .cs                       (cs                 )

  );

  dummy_spi_peripheral_modes03
  spi_modes03 (

    .sclk                           (sclk                        ),
    .pico                           (pico                        ),
    .poci                           (poci                        ),
    .cs                             (cs[0]                       )

  );

  dummy_spi_peripheral_modes12
  spi_modes12 (

    .sclk                           (sclk                        ),
    .pico                           (pico                        ),
    .poci                           (poci                        ),
    .cs                             (cs[1]                       )

  );

endmodule
module dummy_spi_peripheral_modes03 (

  input wire sclk,
  input wire pico,
  input wire cs,
  output wire poci

  );

  reg [7:0] rx_data = 8'h00;
  reg tx_bit = 1'b0;
  reg [3:0] bit_count = 7;

  always @(posedge sclk) begin
    if (!cs) rx_data <= {rx_data[6:0], pico};
  end

  always @(negedge sclk) begin
    if (!cs) tx_bit <= rx_data[7];
  end

  assign poci = cs ? 1'bZ : tx_bit;

endmodule
module dummy_spi_peripheral_modes12 (

  input wire sclk,
  input wire pico,
  input wire cs,
  output wire poci

  );

  reg [7:0] rx_data = 8'h00;
  reg tx_bit = 1'b0;
  reg [3:0] bit_count = 7;

  always @(negedge sclk) begin
    if (!cs) rx_data <= {rx_data[6:0], pico};
  end

  always @(posedge sclk) begin
    if (!cs) tx_bit <= rx_data[7];
  end

  assign poci = cs ? 1'bZ : tx_bit;

endmodule
module unit_tests #(

    // Memory size in bytes
    parameter MEMORY_SIZE   = 2097152     ,
    parameter BOOT_ADDRESS  = 32'h00000000

  )(
    input   clock ,
    input   reset ,
    input   halt
  );

  wire   [31:0]  rw_address;
  wire   [31:0]  read_data;
  wire           read_request;
  wire           read_response;
  wire   [31:0]  write_data;
  wire   [3:0 ]  write_strobe;
  wire           write_request;
  wire           write_response;

  // Real-time clock (unused)

  wire  [63:0]  real_time_clock;
  assign        real_time_clock = 64'b0;

  // Interrupt signals

  wire  [15:0]  irq_fast;
  wire          irq_external;
  wire          irq_timer;
  wire          irq_software;

  assign        irq_fast      = 16'd0;
  assign        irq_external  = 1'd0;
  assign        irq_timer     = 1'd0;
  assign        irq_software  = 1'd0;

  wire  [15:0]  irq_fast_response;
  wire          irq_external_response;
  wire          irq_timer_response;
  wire          irq_software_response;

  rvsteel_core #(
    .BOOT_ADDRESS(BOOT_ADDRESS)
  ) rvsteel_core_instance (

    // Global signals

    .clock                  (clock                ),
    .reset                  (reset                ),
    .halt                   (halt                 ),

    // IO interface

    .rw_address             (rw_address           ),
    .read_data              (read_data            ),
    .read_request           (read_request         ),
    .read_response          (read_response        ),
    .write_data             (write_data           ),
    .write_strobe           (write_strobe         ),
    .write_request          (write_request        ),
    .write_response         (write_response       ),

    // Interrupt request signals

    .irq_fast               (irq_fast             ),
    .irq_external           (irq_external         ),
    .irq_timer              (irq_timer            ),
    .irq_software           (irq_software         ),

    // Interrupt response signals
    .irq_fast_response      (irq_fast_response    ),
    .irq_external_response  (irq_external_response),
    .irq_timer_response     (irq_timer_response   ),
    .irq_software_response  (irq_software_response),

    // Real Time Clock (hardwire to zero if unused)

    .real_time_clock        (real_time_clock      )
  );

  rvsteel_ram #(
    .MEMORY_SIZE(MEMORY_SIZE)
  ) rvsteel_ram_instance (

    // Global signals

    .clock                  (clock          ),
    .reset                  (reset          ),

    // IO interface

    .rw_address             (rw_address     ),
    .read_data              (read_data      ),
    .read_request           (read_request   ),
    .read_response          (read_response  ),
    .write_data             (write_data     ),
    .write_strobe           (write_strobe   ),
    .write_request          (write_request  ),
    .write_response         (write_response )
  );

  // Avoid warnings about intentionally unused pins/wires
  wire unused_ok =
    &{1'b0,
    irq_fast_response,
    irq_external_response,
    irq_timer_response,
    irq_software_response,
    1'b0};

endmodule
module gpio_cmod_a7 #( 

  parameter GPIO_WIDTH = 3

  )(

  input   wire clock,
  input   wire reset,
  input   wire uart_rx,
  output  wire uart_tx,
  inout   wire [GPIO_WIDTH-1:0] gpio

  );
  
  // GPIO signals
  wire [GPIO_WIDTH-1:0] gpio_input;
  wire [GPIO_WIDTH-1:0] gpio_oe;
  wire [GPIO_WIDTH-1:0] gpio_output;

  genvar i;
  for (i = 0; i < GPIO_WIDTH; i=i+1) begin
    assign gpio_input[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : gpio[i];
    assign gpio[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : 1'bZ;
  end

  // Buttons debouncing
  reg reset_debounced;
  always @(posedge clock) begin
    reset_debounced <= reset;
  end

  rvsteel_mcu #(

    .CLOCK_FREQUENCY          (12000000               ),
    .UART_BAUD_RATE           (9600                   ),
    .MEMORY_SIZE              (131072                 ),
    .MEMORY_INIT_FILE         ("gpio_demo.hex"        ),
    .BOOT_ADDRESS             (32'h00000000           ),
    .GPIO_WIDTH               (3                      )

  ) rvsteel_mcu_instance (

    .clock                    (clock                  ),
    .reset                    (reset_debounced        ),
    .halt                     (1'b0                   ),
    .uart_rx                  (uart_rx                ),
    .uart_tx                  (uart_tx                ),
    .gpio_input               (gpio_input             ),
    .gpio_oe                  (gpio_oe                ),
    .gpio_output              (gpio_output            ),
    .sclk                     (), // unused
    .pico                     (), // unused
    .poci                     (1'b0                   ),
    .cs                       ()  // unused

  );

endmodule
module gpio_arty_a7 #( 

  parameter GPIO_WIDTH = 3

  )(

  input   wire clock,
  input   wire reset,
  input   wire uart_rx,
  output  wire uart_tx,
  inout   wire [GPIO_WIDTH-1:0] gpio

  );
  
  // GPIO signals
  wire [GPIO_WIDTH-1:0] gpio_input;
  wire [GPIO_WIDTH-1:0] gpio_oe;
  wire [GPIO_WIDTH-1:0] gpio_output;

  genvar i;
  for (i = 0; i < GPIO_WIDTH; i=i+1) begin
    assign gpio_input[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : gpio[i];
    assign gpio[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : 1'bZ;
  end

  // Divides the 100MHz board block by 2
  reg clock_50mhz;
  initial clock_50mhz = 1'b0;
  always @(posedge clock) clock_50mhz <= !clock_50mhz;

  // Buttons debouncing
  reg reset_debounced;
  always @(posedge clock_50mhz) begin
    reset_debounced <= reset;
  end

  rvsteel_mcu #(

    .CLOCK_FREQUENCY          (50000000               ),
    .UART_BAUD_RATE           (9600                   ),
    .MEMORY_SIZE              (131072                 ),
    .MEMORY_INIT_FILE         ("gpio_demo.hex"        ),
    .BOOT_ADDRESS             (32'h00000000           ),
    .GPIO_WIDTH               (3                      )

  ) rvsteel_mcu_instance (

    .clock                    (clock_50mhz            ),
    .reset                    (reset_debounced        ),
    .halt                     (1'b0                   ),
    .uart_rx                  (uart_rx                ),
    .uart_tx                  (uart_tx                ),
    .gpio_input               (gpio_input             ),
    .gpio_oe                  (gpio_oe                ),
    .gpio_output              (gpio_output            ),
    .sclk                     (), // unused
    .pico                     (), // unused
    .poci                     (1'b0                   ),
    .cs                       ()  // unused

  );

endmodule
module uart_cmod_a7 #( 

  parameter GPIO_WIDTH = 3

  )(

  input   wire clock,
  input   wire reset,
  input   wire uart_rx,
  output  wire uart_tx,
  inout   wire [GPIO_WIDTH-1:0] gpio

  );
  
  // GPIO signals
  wire [GPIO_WIDTH-1:0] gpio_input;
  wire [GPIO_WIDTH-1:0] gpio_oe;
  wire [GPIO_WIDTH-1:0] gpio_output;

  genvar i;
  for (i = 0; i < GPIO_WIDTH; i=i+1) begin
    assign gpio_input[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : gpio[i];
    assign gpio[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : 1'bZ;
  end

  // Buttons debouncing
  reg reset_debounced;
  always @(posedge clock) begin
    reset_debounced <= reset;
  end

  rvsteel_mcu #(

    .CLOCK_FREQUENCY          (12000000               ),
    .UART_BAUD_RATE           (9600                   ),
    .MEMORY_SIZE              (131072                 ),
    .MEMORY_INIT_FILE         ("uart_demo.hex"        ),
    .BOOT_ADDRESS             (32'h00000000           ),
    .GPIO_WIDTH               (3                      )

  ) rvsteel_mcu_instance (

    .clock                    (clock                  ),
    .reset                    (reset_debounced        ),
    .halt                     (1'b0                   ),
    .uart_rx                  (uart_rx                ),
    .uart_tx                  (uart_tx                ),
    .gpio_input               (gpio_input             ),
    .gpio_oe                  (gpio_oe                ),
    .gpio_output              (gpio_output            ),
    .sclk                     (), // unused
    .pico                     (), // unused
    .poci                     (1'b0                   ),
    .cs                       ()  // unused

  );

endmodule
module uart_arty_a7 #( 

  parameter GPIO_WIDTH = 3

  )(

  input   wire clock,
  input   wire reset,
  input   wire uart_rx,
  output  wire uart_tx,
  inout   wire [GPIO_WIDTH-1:0] gpio

  );
  
  // GPIO signals
  wire [GPIO_WIDTH-1:0] gpio_input;
  wire [GPIO_WIDTH-1:0] gpio_oe;
  wire [GPIO_WIDTH-1:0] gpio_output;

  genvar i;
  for (i = 0; i < GPIO_WIDTH; i=i+1) begin
    assign gpio_input[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : gpio[i];
    assign gpio[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : 1'bZ;
  end

  // Divides the 100MHz board block by 2
  reg clock_50mhz;
  initial clock_50mhz = 1'b0;
  always @(posedge clock) clock_50mhz <= !clock_50mhz;

  // Buttons debouncing
  reg reset_debounced;
  always @(posedge clock_50mhz) begin
    reset_debounced <= reset;
  end

  rvsteel_mcu #(

    .CLOCK_FREQUENCY          (50000000               ),
    .UART_BAUD_RATE           (9600                   ),
    .MEMORY_SIZE              (131072                 ),
    .MEMORY_INIT_FILE         ("uart_demo.hex"        ),
    .BOOT_ADDRESS             (32'h00000000           ),
    .GPIO_WIDTH               (3                      )

  ) rvsteel_mcu_instance (

    .clock                    (clock_50mhz            ),
    .reset                    (reset_debounced        ),
    .halt                     (1'b0                   ),
    .uart_rx                  (uart_rx                ),
    .uart_tx                  (uart_tx                ),
    .gpio_input               (gpio_input             ),
    .gpio_oe                  (gpio_oe                ),
    .gpio_output              (gpio_output            ),
    .sclk                     (), // unused
    .pico                     (), // unused
    .poci                     (1'b0                   ),
    .cs                       ()  // unused

  );

endmodule
module mtimer_cmod_a7 #( 

  parameter GPIO_WIDTH = 3

  )(

  input   wire clock,
  input   wire reset,
  input   wire uart_rx,
  output  wire uart_tx,
  inout   wire [GPIO_WIDTH-1:0] gpio

  );
  
  // GPIO signals
  wire [GPIO_WIDTH-1:0] gpio_input;
  wire [GPIO_WIDTH-1:0] gpio_oe;
  wire [GPIO_WIDTH-1:0] gpio_output;

  genvar i;
  for (i = 0; i < GPIO_WIDTH; i=i+1) begin
    assign gpio_input[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : gpio[i];
    assign gpio[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : 1'bZ;
  end

  // Buttons debouncing
  reg reset_debounced;
  always @(posedge clock) begin
    reset_debounced <= reset;
  end

  rvsteel_mcu #(

    .CLOCK_FREQUENCY          (12000000               ),
    .UART_BAUD_RATE           (9600                   ),
    .MEMORY_SIZE              (131072                 ),
    .MEMORY_INIT_FILE         ("mtimer_demo.hex"      ),
    .BOOT_ADDRESS             (32'h00000000           ),
    .GPIO_WIDTH               (2                      )

  ) rvsteel_mcu_instance (

    .clock                    (clock                  ),
    .reset                    (reset_debounced        ),
    .halt                     (1'b0                   ),
    .uart_rx                  (uart_rx                ),
    .uart_tx                  (uart_tx                ),
    .gpio_input               (gpio_input             ),
    .gpio_oe                  (gpio_oe                ),
    .gpio_output              (gpio_output            ),
    .sclk                     (), // unused
    .pico                     (), // unused
    .poci                     (1'b0                   ),
    .cs                       ()  // unused

  );

endmodule
module mtimer_arty_a7 #( 

  parameter GPIO_WIDTH = 3

  )(

  input   wire clock,
  input   wire reset,
  input   wire uart_rx,
  output  wire uart_tx,
  inout   wire [GPIO_WIDTH-1:0] gpio

  );
  
  // GPIO signals
  wire [GPIO_WIDTH-1:0] gpio_input;
  wire [GPIO_WIDTH-1:0] gpio_oe;
  wire [GPIO_WIDTH-1:0] gpio_output;

  genvar i;
  for (i = 0; i < GPIO_WIDTH; i=i+1) begin
    assign gpio_input[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : gpio[i];
    assign gpio[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : 1'bZ;
  end

  // Divides the 100MHz board block by 2
  reg clock_50mhz;
  initial clock_50mhz = 1'b0;
  always @(posedge clock) clock_50mhz <= !clock_50mhz;

  // Buttons debouncing
  reg reset_debounced;
  always @(posedge clock_50mhz) begin
    reset_debounced <= reset;
  end

  rvsteel_mcu #(

    .CLOCK_FREQUENCY          (50000000               ),
    .UART_BAUD_RATE           (9600                   ),
    .MEMORY_SIZE              (131072                 ),
    .MEMORY_INIT_FILE         ("mtimer_demo.hex"      ),
    .BOOT_ADDRESS             (32'h00000000           ),
    .GPIO_WIDTH               (3                      )

  ) rvsteel_mcu_instance (

    .clock                    (clock_50mhz            ),
    .reset                    (reset_debounced        ),
    .halt                     (1'b0                   ),
    .uart_rx                  (uart_rx                ),
    .uart_tx                  (uart_tx                ),
    .gpio_input               (gpio_input             ),
    .gpio_oe                  (gpio_oe                ),
    .gpio_output              (gpio_output            ),
    .sclk                     (), // unused
    .pico                     (), // unused
    .poci                     (1'b0                   ),
    .cs                       ()  // unused

  );

endmodule
module spi_cmod_a7 #( 

  parameter GPIO_WIDTH = 1,
  parameter SPI_NUM_CHIP_SELECT = 1

  )(

  input   wire clock,
  input   wire reset,
  input   wire uart_rx,
  output  wire uart_tx,
  output  wire sclk,
  output  wire pico,
  input   wire poci,
  output  wire cs

  );

  // Buttons debouncing
  reg reset_debounced;
  always @(posedge clock) begin
    reset_debounced <= reset;
  end

  rvsteel_mcu #(

    .CLOCK_FREQUENCY          (12000000               ),
    .UART_BAUD_RATE           (9600                   ),
    .MEMORY_SIZE              (131072                 ),
    .MEMORY_INIT_FILE         ("spi_demo.hex"         ),
    .BOOT_ADDRESS             (32'h00000000           ),
    .GPIO_WIDTH               (GPIO_WIDTH             ),
    .SPI_NUM_CHIP_SELECT      (SPI_NUM_CHIP_SELECT    )

  ) rvsteel_mcu_instance (

    .clock                    (clock                  ),
    .reset                    (reset_debounced        ),
    .halt                     (1'b0                   ),
    .uart_rx                  (uart_rx                ),
    .uart_tx                  (uart_tx                ),
    .gpio_input               ({GPIO_WIDTH{1'b0}}     ), // pull-down
    .gpio_oe                  (), // unused
    .gpio_output              (), // unused
    .sclk                     (sclk                   ),
    .pico                     (pico                   ),
    .poci                     (poci                   ),
    .cs                       (cs                     )

  );

endmodule
module spi_arty_a7 #( 

  parameter GPIO_WIDTH = 1,
  parameter SPI_NUM_CHIP_SELECT = 1

  )(

  input   wire clock,
  input   wire reset,
  input   wire uart_rx,
  output  wire uart_tx,
  output  wire sclk,
  output  wire pico,
  input   wire poci,
  output  wire cs

  );

  // Divides the 100MHz board block by 2
  reg clock_50mhz;
  initial clock_50mhz = 1'b0;
  always @(posedge clock) clock_50mhz <= !clock_50mhz;

  // Buttons debouncing
  reg reset_debounced;
  always @(posedge clock_50mhz) begin
    reset_debounced <= reset;
  end

  rvsteel_mcu #(

    .CLOCK_FREQUENCY          (50000000               ),
    .UART_BAUD_RATE           (9600                   ),
    .MEMORY_SIZE              (131072                 ),
    .MEMORY_INIT_FILE         ("spi_demo.hex"         ),
    .BOOT_ADDRESS             (32'h00000000           ),
    .GPIO_WIDTH               (GPIO_WIDTH             ),
    .SPI_NUM_CHIP_SELECT      (SPI_NUM_CHIP_SELECT    )

  ) rvsteel_mcu_instance (

    .clock                    (clock_50mhz            ),
    .reset                    (reset_debounced        ),
    .halt                     (1'b0                   ),
    .uart_rx                  (uart_rx                ),
    .uart_tx                  (uart_tx                ),
    .gpio_input               ({GPIO_WIDTH{1'b0}}     ), // pull-down
    .gpio_oe                  (), // unused
    .gpio_output              (), // unused
    .sclk                     (sclk                   ),
    .pico                     (pico                   ),
    .poci                     (poci                   ),
    .cs                       (cs                     )

  );

endmodule
module freertos_cmod_a7 #(
  
  parameter GPIO_WIDTH = 2

  )(

  input   wire clock,
  input   wire reset,
  input   wire halt,
  input   wire uart_rx,
  output  wire uart_tx,
  inout   wire [GPIO_WIDTH-1:0] gpio

  );

  // GPIO signals
  wire [GPIO_WIDTH-1:0] gpio_input;
  wire [GPIO_WIDTH-1:0] gpio_oe;
  wire [GPIO_WIDTH-1:0] gpio_output;

  genvar i;
  for (i = 0; i < GPIO_WIDTH; i=i+1) begin
    assign gpio_input[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : gpio[i];
    assign gpio[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : 1'bZ;
  end

  // Buttons debouncing
  reg reset_debounced;
  reg halt_debounced;
  always @(posedge clock) begin
    reset_debounced <= reset;
    halt_debounced <= halt;
  end

  rvsteel_mcu #(

    .CLOCK_FREQUENCY          (12000000               ),
    .UART_BAUD_RATE           (9600                   ),
    .MEMORY_SIZE              (131072                 ),
    .MEMORY_INIT_FILE         ("freertos_demo.hex"    ),
    .BOOT_ADDRESS             (32'h00000000           ),
    .GPIO_WIDTH               (2                      )

  ) rvsteel_mcu_instance (

    .clock                    (clock                  ),
    .reset                    (reset_debounced        ),
    .halt                     (halt_debounced         ),
    .uart_rx                  (uart_rx                ),
    .uart_tx                  (uart_tx                ),
    .gpio_input               (gpio_input             ),
    .gpio_oe                  (gpio_oe                ),
    .gpio_output              (gpio_output            ),
    .sclk                     (), // unused
    .pico                     (), // unused
    .poci                     (1'b0                   ),
    .cs                       ()  // unused

  );

endmodule
module freertos_arty_a7  #(
  
  parameter GPIO_WIDTH = 2

  )(

  input   wire clock,
  input   wire reset,
  input   wire halt,
  input   wire uart_rx,
  output  wire uart_tx,
  inout   wire [GPIO_WIDTH-1:0] gpio

  );

  // GPIO signals
  wire [GPIO_WIDTH-1:0] gpio_input;
  wire [GPIO_WIDTH-1:0] gpio_oe;
  wire [GPIO_WIDTH-1:0] gpio_output;

  genvar i;
  for (i = 0; i < GPIO_WIDTH; i=i+1) begin
    assign gpio_input[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : gpio[i];
    assign gpio[i] = gpio_oe[i] == 1'b1 ? gpio_output[i] : 1'bZ;
  end

  // Divides the 100MHz board block by 2
  reg clock_50mhz;
  initial clock_50mhz = 1'b0;
  always @(posedge clock) clock_50mhz <= !clock_50mhz;

  // Buttons debouncing
  reg reset_debounced;
  reg halt_debounced;
  always @(posedge clock_50mhz) begin
    reset_debounced <= reset;
    halt_debounced <= halt;
  end

  rvsteel_mcu #(

    .CLOCK_FREQUENCY          (50000000               ),
    .UART_BAUD_RATE           (9600                   ),
    .MEMORY_SIZE              (131072                 ),
    .MEMORY_INIT_FILE         ("freertos_demo.hex"    ),
    .BOOT_ADDRESS             (32'h00000000           ),
    .GPIO_WIDTH               (2                      )

  ) rvsteel_mcu_instance (

    .clock                    (clock_50mhz            ),
    .reset                    (reset_debounced        ),
    .halt                     (halt_debounced         ),
    .uart_rx                  (uart_rx                ),
    .uart_tx                  (uart_tx                ),
    .gpio_input               (gpio_input             ),
    .gpio_oe                  (gpio_oe                ),
    .gpio_output              (gpio_output            ),
    .sclk                     (), // unused
    .pico                     (), // unused
    .poci                     (1'b0                   ),
    .cs                       ()  // unused

  );

endmodule
module hello_world_cmod_a7 (

  input   wire clock,
  input   wire reset,
  output  wire uart_tx

  );

  // Push-button debouncing
  reg reset_debounced;
  always @(posedge clock) begin
    reset_debounced <= reset;
  end

  rvsteel_mcu #(

  // Please adjust these two parameters accordingly

  .CLOCK_FREQUENCY          (12000000                   ),
  .MEMORY_INIT_FILE         ("hello_world.hex"          )

  ) rvsteel_mcu_instance (

  // Note that unused inputs are hardwired to zero,
  // while unused outputs are left open.

  .clock                    (clock                      ),
  .reset                    (reset_debounced            ),
  .halt                     (1'b0                       ),
  .uart_rx                  (/* unused, leave open */   ),
  .uart_tx                  (uart_tx                    ),
  .gpio_input               (1'b0                       ),
  .gpio_oe                  (/* unused, leave open */   ),
  .gpio_output              (/* unused, leave open */   ),
  .sclk                     (/* unused, leave open */   ),
  .pico                     (/* unused, leave open */   ),
  .poci                     (1'b0                       ),
  .cs                       (/* unused, leave open */   )

  );

endmodule
module hello_world_arty_a7 (

  input   wire clock,
  input   wire reset,
  output  wire uart_tx

  );

  // Divides the 100MHz board block by 2
  reg clock_50mhz;
  initial clock_50mhz = 1'b0;
  always @(posedge clock) clock_50mhz <= !clock_50mhz;

  // Push-button debouncing
  reg reset_debounced;
  always @(posedge clock_50mhz) begin
    reset_debounced <= reset;
  end

  rvsteel_mcu #(

  // Please adjust these two parameters accordingly

  .CLOCK_FREQUENCY          (50000000                   ),
  .MEMORY_INIT_FILE         ("hello_world.hex"          )

  ) rvsteel_mcu_instance (

  // Note that unused inputs are hardwired to zero,
  // while unused outputs are left open.

  .clock                    (clock_50mhz                ),
  .reset                    (reset_debounced            ),
  .halt                     (1'b0                       ),
  .uart_rx                  (/* unused, leave open */   ),
  .uart_tx                  (uart_tx                    ),
  .gpio_input               (1'b0                       ),
  .gpio_oe                  (/* unused, leave open */   ),
  .gpio_output              (/* unused, leave open */   ),
  .sclk                     (/* unused, leave open */   ),
  .pico                     (/* unused, leave open */   ),
  .poci                     (1'b0                       ),
  .cs                       (/* unused, leave open */   )

  );

endmodule
module softMC_pcie_app #(
	parameter C_PCI_DATA_WIDTH = 9'd32, DQ_WIDTH = 64
)(
	input clk,
	input rst,
	output CHNL_RX_CLK, 
	input CHNL_RX, 
	output reg CHNL_RX_ACK, 
	input CHNL_RX_LAST, 
	input [31:0] CHNL_RX_LEN, 
	input [30:0] CHNL_RX_OFF, 
	input [C_PCI_DATA_WIDTH-1:0] CHNL_RX_DATA, 
	input CHNL_RX_DATA_VALID, 
	output CHNL_RX_DATA_REN,
	
	output CHNL_TX_CLK, 
	output reg CHNL_TX, 
	input CHNL_TX_ACK, 
	output CHNL_TX_LAST, 
	output reg [31:0] CHNL_TX_LEN, 
	output [30:0] CHNL_TX_OFF, 
	output [C_PCI_DATA_WIDTH-1:0] CHNL_TX_DATA, 
	output reg CHNL_TX_DATA_VALID, 
	input CHNL_TX_DATA_REN,
	
	output  app_en,
	input app_ack,
	output[31:0] app_instr,
	
	//Data read back Interface
	input rdback_fifo_empty,
	output rdback_fifo_rden,
	input[DQ_WIDTH*4 - 1:0] rdback_data
 );
 
 assign CHNL_RX_CLK = clk;
 assign CHNL_TX_CLK = clk;
 assign CHNL_TX_OFF = 0;
 assign CHNL_TX_LAST = 1'd1;
 
 reg app_en_r;
 reg[C_PCI_DATA_WIDTH-1:0] rx_data_r;
 
 reg old_chnl_rx;
 reg pending_ack = 0;
 
 //always acknowledge transaction
 always@(posedge clk) begin
		old_chnl_rx <= CHNL_RX;
		
		if(~old_chnl_rx & CHNL_RX)
			pending_ack <= 1'b1;
		
		if(CHNL_RX_ACK)
			CHNL_RX_ACK <= 1'b0;
		else begin
			if(pending_ack /*& app_ack*/) begin
				CHNL_RX_ACK <= 1'b1;
				pending_ack <= 1'b0;
			end
		end
 end
 
 //register incoming data
 assign CHNL_RX_DATA_REN = ~app_en_r | app_ack;
 always@(posedge clk) begin
	if(~app_en_r | app_ack) begin
		app_en_r <= CHNL_RX_DATA_VALID;
		rx_data_r <= CHNL_RX_DATA;
	end
 end
 
//send to the MC
assign app_en = app_en_r;
assign app_instr = rx_data_r;

//SEND DATA TO HOST
localparam RECV_IDLE = 1'b0;
localparam RECV_BUSY = 1'b1;

reg sender_ack;
reg[DQ_WIDTH*4 - 1:0] send_data_r;

reg recv_state = RECV_IDLE;
assign rdback_fifo_rden = (recv_state == RECV_IDLE);
always@(posedge clk) begin
	if(rst) begin
		recv_state <= RECV_IDLE;
	end
	else begin
		case(recv_state)
			RECV_IDLE: begin
				if(~rdback_fifo_empty) begin
					send_data_r <= rdback_data;
					recv_state <= RECV_BUSY;
				end
			end //RECV_IDLE
			
			RECV_BUSY: begin
				if(sender_ack)
					recv_state <= RECV_IDLE;
			end //RECV_BUSY
		endcase
	end
end

reg[2:0] sender_state = 0; //edit this if DQ_WIDTH or C_PCI_DATA_WIDTH changes
reg[2:0] sender_state_ns;

always@* begin
	sender_ack = 1'b0;
	sender_state_ns = sender_state;
	CHNL_TX = sender_state[2];
	
	CHNL_TX_LEN = 16;
	
	if(recv_state == RECV_BUSY) begin
		CHNL_TX = 1'b1;
		CHNL_TX_DATA_VALID = 1'b1;
		
		if(CHNL_TX_DATA_REN) begin
			sender_state_ns = sender_state + 3'd1;
			
			if(sender_state[1:0] == 2'b11)
				sender_ack = 1'b1;
		end
	end
end

always@(posedge clk) begin
	if(rst) begin
		sender_state <= 0;
	end
	else begin
		sender_state <= sender_state_ns;
	end
end

wire[7:0] offset = {6'd0, sender_state[1:0]} << 6;
assign CHNL_TX_DATA = send_data_r[offset +: 64];

endmodule
module instr_receiver (
	input clk,
	input rst,
	
	input dispatcher_ready,
	
	input app_en,
	output reg app_ack,
	input[31:0] app_instr,
	
	input maint_en,
	output reg maint_ack,
	input[31:0] maint_instr,
	
	output instr0_fifo_en,
	output[31:0] instr0_fifo_data,
	
	output instr1_fifo_en,
	output[31:0] instr1_fifo_data,
	
	output process_iseq
);

reg process_iseq_r = 1'b0, process_iseq_ns;

localparam STATE_IDLE = 2'b00;
localparam STATE_APP = 2'b01;
localparam STATE_MAINT = 2'b10;

reg[1:0] state_ns, state_r;

reg sel_fifo = 1'b0;

reg instr_en_ns, instr_en_r;
reg[31:0] instr_ns, instr_r;

always@* begin
	process_iseq_ns = 1'b0;
	
	state_ns = state_r;
	
	instr_en_ns = 1'b0;
	instr_ns = instr_r;
	
	app_ack = 1'b0;
	maint_ack = 1'b0;
	
	case(state_r)
		STATE_IDLE: begin
			if(dispatcher_ready & ~process_iseq_r) begin
				if(app_en) begin
					state_ns = STATE_APP;
					instr_en_ns = app_en;
					instr_ns = app_instr;
					
					app_ack = 1'b1;
				end
				else if(maint_en) begin
					state_ns = STATE_MAINT;
					instr_en_ns = maint_en;
					instr_ns = maint_instr;
					
					maint_ack = 1'b1;
				end
			end //dispatcher_ready
		end //STATE_IDLE
		
		STATE_APP: begin
			app_ack = 1'b1;
			
			instr_en_ns = app_en;
			instr_ns = app_instr;
			
			if(instr_en_ns & (instr_ns[31:28] == `END_ISEQ)) begin
				process_iseq_ns = 1'b1;
				state_ns = STATE_IDLE;
			end
		end //STATE_APP
		
		STATE_MAINT: begin
			maint_ack = 1'b1;
			
			instr_en_ns = maint_en;
			instr_ns = maint_instr;
			
			if(instr_en_ns & (instr_ns[31:28] == `END_ISEQ)) begin
				instr_en_ns = 1'b0;
				process_iseq_ns = 1'b1;
				state_ns = STATE_IDLE;
			end
		end //STATE_MAINT
	
	endcase //state_r
end //always

assign instr0_fifo_en = ~sel_fifo & instr_en_r;
assign instr0_fifo_data = instr_r;
assign instr1_fifo_en = sel_fifo & instr_en_r;
assign instr1_fifo_data = instr_r;

always@(posedge clk) begin
	if(rst) begin
		process_iseq_r <= 1'b0;
		sel_fifo <= 1'b0;
		state_r <= STATE_IDLE; 
		
		instr_en_r <= 1'b0;
		instr_r <= 0;
	end
	else begin
		state_r <= state_ns;
		process_iseq_r <= process_iseq_ns;
		
		instr_en_r <= instr_en_ns;
		instr_r <= instr_ns;
		
		if(process_iseq_r)
			sel_fifo <= 1'b0;
		else if(instr_en_r)
			sel_fifo <= ~sel_fifo;
	end //!rst
end

assign process_iseq = process_iseq_r;

endmodule
module pipe_reg #(parameter WIDTH = 8) (
        input clk,
        input rst,
        
        input ready_in,
        input valid_in,
        input[WIDTH - 1:0] data_in,
        output valid_out,
        output[WIDTH - 1:0] data_out,
        output ready_out
    );
    
    (* keep = "true" *) reg r_ready, r_valid1, r_valid2;
    (* keep = "true" *) reg[WIDTH - 1:0] r_data1, r_data2;
    
    wire first_buf_ready = ready_in | ~r_valid1;
    
    assign data_out = r_data1;
    assign valid_out = r_valid1;
    assign ready_out = r_ready;
    
    always@(posedge clk)
    begin
        if(rst) begin
            r_data1 <= 0;
            r_data2 <= 0;
            r_ready <= 0;
            r_valid1 <= 0;
            r_valid2 <= 0;
        end
        else begin
            //data acquisition
            if(r_ready) begin
                if(first_buf_ready) begin
                    r_data1 <= data_in;
                    r_valid1 <= valid_in;
                end
                else begin
                    r_data2 <= data_in;
                    r_valid2 <= valid_in;
                end
            end //r_ready
            
            //data shift
            if(~r_ready & ready_in) begin
                r_data1 <= r_data2;
                r_valid1 <= r_valid2;
            end
        end
        
        //control
        r_ready <= first_buf_ready;
    end
endmodule
module instr_decoder #(parameter ROW_WIDTH = 15, BANK_WIDTH = 3, CS_WIDTH = 1)(
	input en,
	input[31:0] instr,
	
	output reg[ROW_WIDTH - 1:0] dfi_address,
	output reg[BANK_WIDTH - 1:0] dfi_bank,
	output reg dfi_cas_n,
	output reg[CS_WIDTH - 1:0] dfi_cs_n,
	output reg dfi_ras_n,
	output reg dfi_we_n
);
	
	localparam LOW = 1'b0;
	localparam HIGH = 1'b1;

	always@* begin
		dfi_address = {ROW_WIDTH{1'bx}};
		dfi_bank = {BANK_WIDTH{1'bx}};
		
		dfi_cas_n = HIGH;
		dfi_cs_n = {CS_WIDTH{HIGH}};
		dfi_ras_n = HIGH;
		dfi_we_n = HIGH;
		
		if(en) begin
			dfi_address = instr[ROW_WIDTH - 1:0];
			dfi_bank = instr[`ROW_OFFSET +: BANK_WIDTH];
			dfi_we_n = instr[`WE_OFFSET];
			dfi_cas_n = instr[`CAS_OFFSET];
			dfi_ras_n = instr[`RAS_OFFSET];
			dfi_cs_n = instr[`CS_OFFSET +: CS_WIDTH];
		end //en
	end
endmodule
module read_capturer #(parameter DQ_WIDTH = 64) (
	input clk,
	input rst,
	
	//DFI Interface
	input  [4*DQ_WIDTH-1:0] dfi_rddata,
	input                   dfi_rddata_valid,
	input							dfi_rddata_valid_even,
	input							dfi_rddata_valid_odd,
	output						dfi_clk_disable,
	
	//FIFO interface
	input rdback_fifo_almost_full,
	input rdback_fifo_full,
	output rdback_fifo_wren,
	output[4*DQ_WIDTH-1:0] rdback_fifo_wrdata
);

	reg[4*DQ_WIDTH-1:0] rd_data_r, rd_data_r2;
	reg rd_data_en_r, rd_data_en_even_r, rd_data_en_odd_r;
	reg rdback_fifo_full_r;
	
	always@(posedge clk) begin
		if(rst) begin
			rd_data_r <= 0;
			rd_data_r2 <= 0;
			rd_data_en_r <= 0;
			rd_data_en_even_r <= 0;
			rd_data_en_odd_r <= 0;
			rdback_fifo_full_r <= 0;
		end
		else begin
			rd_data_r <= dfi_rddata;
			rd_data_r2 <= rd_data_r;
			rd_data_en_r <= dfi_rddata_valid;
			rd_data_en_even_r <= dfi_rddata_valid_even;
			rd_data_en_odd_r <= dfi_rddata_valid_odd;
			
			rdback_fifo_full_r <= rdback_fifo_almost_full | rdback_fifo_full;
		end
	end
	
	assign rdback_fifo_wren = ~rd_data_en_odd_r & rd_data_en_r;
	assign rdback_fifo_wrdata = rd_data_en_even_r ? {rd_data_r[DQ_WIDTH*2 - 1:0], rd_data_r2[DQ_WIDTH*2 +: DQ_WIDTH*2]} : rd_data_r;
	
	assign dfi_clk_disable = rdback_fifo_full_r;

endmodule
module maint_ctrl_top #(parameter RANK_WIDTH = 1, TCQ = 100, tCK = 2500, nCK_PER_CLK = 2, MAINT_PRESCALER_PERIOD = 200000) (
    input clk,
	 input rst,
	 
	 input dfi_init_complete,
	 
	 input periodic_rd_ack,
	 output periodic_rd_req,
	 input zq_ack,
	 output zq_req,
	 
	 //Auto-refresh
	 input autoref_en,
	 input[27:0] autoref_interval,
	 input autoref_ack,
	 output autoref_req
    );
	 
	 /*** MAINTENANCE CONTROLLER ***/
	 wire maint_prescaler_tick;
	 maint_ctrl #(.TCQ(TCQ), .tCK(tCK), .nCK_PER_CLK(nCK_PER_CLK), .MAINT_PRESCALER_PERIOD(MAINT_PRESCALER_PERIOD)) i_maint_ctrl(
		.clk(clk),
		.rst(rst),
	
		.dfi_init_complete(dfi_init_complete),
	
		.maint_prescaler_tick(maint_prescaler_tick)
	);
	 
	 
	 /*** PERIODIC READ CONTROLLER ***/
	 periodic_rd_ctrl #(.tCK(tCK), .nCK_PER_CLK(nCK_PER_CLK), .TCQ(TCQ), .MAINT_PRESCALER_PERIOD(MAINT_PRESCALER_PERIOD)) i_prrd_ctrl(
		.clk(clk),
		.rst(rst),
		
		.maint_prescaler_tick(maint_prescaler_tick),
		.dfi_init_complete(dfi_init_complete),
		
		.periodic_rd_ack(periodic_rd_ack),
		.periodic_rd_req(periodic_rd_req)
	);
	 
	 /*** ZQ CALIBRATION CONTROLLER ***/
	 zq_calib_ctrl #(.TCQ(TCQ), .MAINT_PRESCALER_PERIOD(MAINT_PRESCALER_PERIOD)) i_zq_calib_ctrl(
		.clk(clk),
		.rst(rst),
		
		.maint_prescaler_tick(maint_prescaler_tick),
		.dfi_init_complete(dfi_init_complete),
		
		.zq_ack(zq_ack),
		.zq_request(zq_req)
	);
	
	autoref_ctrl #(.TCQ(TCQ)) i_autoref_ctrl (
		.clk(clk),
		.rst(rst),
		
		.autoref_en(autoref_en),
		.autoref_interval(autoref_interval),
		.maint_prescaler_tick(maint_prescaler_tick),
		.dfi_init_complete(dfi_init_complete),
		
		.autoref_ack(autoref_ack),
		.autoref_req(autoref_req)
	);

endmodule
module maint_ctrl #(parameter TCQ = 100, tCK = 2500, nCK_PER_CLK = 2, MAINT_PRESCALER_PERIOD = 200000) (
	input clk,
	input rst,
	
	input dfi_init_complete,
	
	output maint_prescaler_tick
);

	function integer clogb2 (input integer size); // ceiling logb2
    begin
      size = size - 1;
      for (clogb2=1; size>1; clogb2=clogb2+1)
            size = size >> 1;
    end
	endfunction // clogb2
	
   localparam MAINT_PRESCALER_DIV = MAINT_PRESCALER_PERIOD/(tCK * nCK_PER_CLK);  // Round down.
	localparam MAINT_PRESCALER_WIDTH = clogb2(MAINT_PRESCALER_DIV + 1);
	localparam ONE = 1;
	
	// Maintenance and periodic read prescaler.  Nominally 200 nS.
	reg maint_prescaler_tick_r_lcl;
	reg [MAINT_PRESCALER_WIDTH-1:0] maint_prescaler_r;
	reg [MAINT_PRESCALER_WIDTH-1:0] maint_prescaler_ns;
	
	wire maint_prescaler_tick_ns = (maint_prescaler_r == ONE[MAINT_PRESCALER_WIDTH-1:0]);
	always @(/*AS*/dfi_init_complete or maint_prescaler_r
				or maint_prescaler_tick_ns) begin
		maint_prescaler_ns = maint_prescaler_r;
		if (~dfi_init_complete || maint_prescaler_tick_ns)
			maint_prescaler_ns = MAINT_PRESCALER_DIV[MAINT_PRESCALER_WIDTH-1:0];
		else if (|maint_prescaler_r)
			maint_prescaler_ns = maint_prescaler_r - ONE[MAINT_PRESCALER_WIDTH-1:0];
	end
	
	always @(posedge clk) maint_prescaler_r <= #TCQ maint_prescaler_ns;

	always @(posedge clk) maint_prescaler_tick_r_lcl <= #TCQ maint_prescaler_tick_ns;
								  
	assign maint_prescaler_tick = maint_prescaler_tick_r_lcl;

endmodule
module periodic_rd_ctrl #(parameter tCK = 2500, nCK_PER_CLK = 2, TCQ = 100, MAINT_PRESCALER_PERIOD = 200000) (
		input clk,
		input rst,
		
		input dfi_init_complete,
		input maint_prescaler_tick,
		
		input periodic_rd_ack, //NOTE: this also should be asserted for regular reads
		output periodic_rd_req
	);
	
	function integer clogb2 (input integer size); // ceiling logb2
    begin
      size = size - 1;
      for (clogb2=1; size>1; clogb2=clogb2+1)
            size = size >> 1;
    end
	endfunction // clogb2
	
	localparam tPRDI = 1_000_000;
	localparam PERIODIC_RD_TIMER_DIV = tPRDI/MAINT_PRESCALER_PERIOD;
	localparam PERIODIC_RD_TIMER_WIDTH = clogb2(PERIODIC_RD_TIMER_DIV + /*idle state*/ 1);
	localparam ONE = 1;
	 
	reg [PERIODIC_RD_TIMER_WIDTH-1:0] periodic_rd_timer_r, periodic_rd_timer;
	reg periodic_rd_request_r;
	 
	always @* begin
		periodic_rd_timer = periodic_rd_timer_r;
		
		if(~dfi_init_complete) begin
			periodic_rd_timer = {PERIODIC_RD_TIMER_WIDTH{1'b0}};
		end
		else if (periodic_rd_ack) begin
			periodic_rd_timer = PERIODIC_RD_TIMER_DIV[0+:PERIODIC_RD_TIMER_WIDTH];
		end
		else if (|periodic_rd_timer_r && maint_prescaler_tick) begin
			periodic_rd_timer = periodic_rd_timer_r - ONE[0+:PERIODIC_RD_TIMER_WIDTH];
		end
	end //always
	 
	wire periodic_rd_timer_one = maint_prescaler_tick && (periodic_rd_timer_r == ONE[0+:PERIODIC_RD_TIMER_WIDTH]);
	 
	wire periodic_rd_request = ~rst && (/*((PERIODIC_RD_TIMER_DIV != 0) && ~dfi_init_complete) ||*/
                      (~periodic_rd_ack && (periodic_rd_request_r || periodic_rd_timer_one)));
	 
	always @(posedge clk) begin
		periodic_rd_timer_r <= #TCQ periodic_rd_timer;
		periodic_rd_request_r <= #TCQ periodic_rd_request;
	end //always
	
	assign periodic_rd_req = periodic_rd_request_r;
	
endmodule