data/full_repos/permissive/447976230/fpga/usrp3/top/x400/cpld/reconfig_engine.v
1: b'%Error: data/full_repos/permissive/447976230/fpga/usrp3/top/x400/cpld/reconfig_engine.v:73: Cannot find include file: regmap/reconfig_regmap_utils.vh\n  `include "regmap/reconfig_regmap_utils.vh" \n           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n        ... Looked in:\n             data/full_repos/permissive/447976230/fpga/usrp3/top/x400/cpld,data/full_repos/permissive/447976230/regmap/reconfig_regmap_utils.vh\n             data/full_repos/permissive/447976230/fpga/usrp3/top/x400/cpld,data/full_repos/permissive/447976230/regmap/reconfig_regmap_utils.vh.v\n             data/full_repos/permissive/447976230/fpga/usrp3/top/x400/cpld,data/full_repos/permissive/447976230/regmap/reconfig_regmap_utils.vh.sv\n             regmap/reconfig_regmap_utils.vh\n             regmap/reconfig_regmap_utils.vh.v\n             regmap/reconfig_regmap_utils.vh.sv\n             obj_dir/regmap/reconfig_regmap_utils.vh\n             obj_dir/regmap/reconfig_regmap_utils.vh.v\n             obj_dir/regmap/reconfig_regmap_utils.vh.sv\n%Error: data/full_repos/permissive/447976230/fpga/usrp3/top/x400/cpld/reconfig_engine.v:74: Cannot find include file: ../../../lib/rfnoc/core/ctrlport.vh\n  `include "../../../lib/rfnoc/core/ctrlport.vh" \n           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n%Error: data/full_repos/permissive/447976230/fpga/usrp3/top/x400/cpld/reconfig_engine.v:90: syntax error, unexpected \'(\', expecting IDENTIFIER\n    ERROR_MAX10_variant_must_be_defined();\n                                        ^\n%Error: Exiting due to 3 error(s)\n'
module reconfig_engine #(
  parameter BASE_ADDRESS  = 0,
  parameter NUM_ADDRESSES = 32,
  parameter MEM_INIT      = 0
) (
  input wire ctrlport_clk,
  input wire ctrlport_rst,


  input  wire        s_ctrlport_req_wr,
  input  wire        s_ctrlport_req_rd,
  input  wire [19:0] s_ctrlport_req_addr,
  input  wire [31:0] s_ctrlport_req_data,

  output reg         s_ctrlport_resp_ack,
  output reg  [ 1:0] s_ctrlport_resp_status,
  output reg  [31:0] s_ctrlport_resp_data,


  output reg         csr_addr,
  output reg         csr_read,
  output reg  [31:0] csr_writedata,
  output reg         csr_write,
  input  wire [31:0] csr_readdata,
  output reg  [16:0] data_addr,
  output reg         data_read,
  output reg  [31:0] data_writedata,
  output reg         data_write,
  input  wire [31:0] data_readdata,
  input  wire        data_waitrequest,
  input  wire        data_readdatavalid
);

  `include "regmap/reconfig_regmap_utils.vh"
  `include "../../../lib/rfnoc/core/ctrlport.vh"


  `ifdef VARIANT_10M04
    localparam FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT = FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT_10M04;
    localparam FLASH_PRIMARY_IMAGE_START_ADDR          = FLASH_PRIMARY_IMAGE_START_ADDR_10M04;
    localparam FLASH_PRIMARY_IMAGE_END_ADDR            = FLASH_PRIMARY_IMAGE_END_ADDR_10M04;
    localparam CFM0_WP_OFFSET_MSB                      = 26;
    localparam CFM0_WP_OFFSET_LSB                      = 24;
  `elsif VARIANT_10M08
    localparam FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT = FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT_10M08;
    localparam FLASH_PRIMARY_IMAGE_START_ADDR          = FLASH_PRIMARY_IMAGE_START_ADDR_10M08;
    localparam FLASH_PRIMARY_IMAGE_END_ADDR            = FLASH_PRIMARY_IMAGE_END_ADDR_10M08;
    localparam CFM0_WP_OFFSET_MSB                      = 27;
    localparam CFM0_WP_OFFSET_LSB                      = 25;
  `else
    ERROR_MAX10_variant_must_be_defined();
    localparam FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT = FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT_10M04;
    localparam FLASH_PRIMARY_IMAGE_START_ADDR          = FLASH_PRIMARY_IMAGE_START_ADDR_10M04;
    localparam FLASH_PRIMARY_IMAGE_END_ADDR            = FLASH_PRIMARY_IMAGE_END_ADDR_10M04;
    localparam CFM0_WP_OFFSET_MSB                      = 26;
    localparam CFM0_WP_OFFSET_LSB                      = 24;
  `endif







  reg [16:0] flash_addr       = 0;
  reg [31:0] flash_write_data = 0;
  reg [31:0] flash_read_data;


  reg       flash_read_stb       = 1'b0;
  reg       flash_write_stb      = 1'b0;
  reg       flash_erase_stb      = 1'b0;
  reg       flash_enable_wp_stb  = 1'b0;
  reg       flash_disable_wp_stb = 1'b0;
  reg [2:0] flash_sector         = 3'b0;


  reg flash_wp_enabled;
  reg flash_read_idle;
  reg flash_write_idle;
  reg flash_erase_idle;
  reg flash_read_err;
  reg flash_write_err;
  reg flash_erase_err;
  reg clear_flash_read_err_stb  = 1'b0;
  reg clear_flash_write_err_stb = 1'b0;
  reg clear_flash_erase_err_stb = 1'b0;





  wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) &&
                          (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES);





  always @(posedge ctrlport_clk) begin

    s_ctrlport_resp_ack <= 1'b0;

    flash_read_stb            <= 1'b0;
    flash_write_stb           <= 1'b0;
    flash_erase_stb           <= 1'b0;
    flash_enable_wp_stb       <= 1'b0;
    flash_disable_wp_stb      <= 1'b0;
    clear_flash_read_err_stb  <= 1'b0;
    clear_flash_write_err_stb <= 1'b0;
    clear_flash_erase_err_stb <= 1'b0;


    if (ctrlport_rst) begin
      s_ctrlport_resp_ack     <= 1'b0;
      s_ctrlport_resp_data    <= {32{1'bx}};
      s_ctrlport_resp_status  <= CTRL_STS_OKAY;


    end else begin
      if (s_ctrlport_req_wr) begin

        s_ctrlport_resp_ack     <= 1'b1;
        s_ctrlport_resp_data    <= {32{1'bx}};
        s_ctrlport_resp_status  <= CTRL_STS_OKAY;

        case (s_ctrlport_req_addr)
          BASE_ADDRESS + FLASH_CONTROL_REG: begin
            flash_read_stb            <= s_ctrlport_req_data[FLASH_READ_STB];
            flash_write_stb           <= s_ctrlport_req_data[FLASH_WRITE_STB];
            flash_erase_stb           <= s_ctrlport_req_data[FLASH_ERASE_STB];
            flash_enable_wp_stb       <= s_ctrlport_req_data[FLASH_ENABLE_WP_STB];
            flash_disable_wp_stb      <= s_ctrlport_req_data[FLASH_DISABLE_WP_STB];
            clear_flash_read_err_stb  <= s_ctrlport_req_data[CLEAR_FLASH_READ_ERROR_STB];
            clear_flash_write_err_stb <= s_ctrlport_req_data[CLEAR_FLASH_WRITE_ERROR_STB];
            clear_flash_erase_err_stb <= s_ctrlport_req_data[CLEAR_FLASH_ERASE_ERROR_STB];
            flash_sector              <= s_ctrlport_req_data[FLASH_ERASE_SECTOR_MSB:FLASH_ERASE_SECTOR];
          end

          BASE_ADDRESS + FLASH_ADDR_REG: begin
            flash_addr <= s_ctrlport_req_data[FLASH_ADDR_MSB:FLASH_ADDR];
          end

          BASE_ADDRESS + FLASH_WRITE_DATA_REG: begin
            flash_write_data <= s_ctrlport_req_data[FLASH_WRITE_DATA_MSB:FLASH_WRITE_DATA];
          end


          default: begin
            if (address_in_range) begin
              s_ctrlport_resp_status <= CTRL_STS_CMDERR;


            end else begin
              s_ctrlport_resp_ack <= 1'b0;
            end
          end
        endcase


      end else if (s_ctrlport_req_rd) begin

        s_ctrlport_resp_ack <= 1'b1;
        s_ctrlport_resp_status <= CTRL_STS_OKAY;

        case (s_ctrlport_req_addr)
          BASE_ADDRESS + FLASH_STATUS_REG: begin
            s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}};
            s_ctrlport_resp_data[FLASH_WP_ENABLED]       <= flash_wp_enabled;
            s_ctrlport_resp_data[FLASH_READ_IDLE]        <= flash_read_idle;
            s_ctrlport_resp_data[FLASH_READ_ERR]         <= flash_read_err;
            s_ctrlport_resp_data[FLASH_ERASE_IDLE]       <= flash_erase_idle;
            s_ctrlport_resp_data[FLASH_ERASE_ERR]        <= flash_erase_err;
            s_ctrlport_resp_data[FLASH_WRITE_IDLE]       <= flash_write_idle;
            s_ctrlport_resp_data[FLASH_WRITE_ERR]        <= flash_write_err;
            s_ctrlport_resp_data[FLASH_MEM_INIT_ENABLED] <= MEM_INIT ? 1'b1 : 1'b0;
          end

          BASE_ADDRESS + FLASH_ADDR_REG: begin
            s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}};
            s_ctrlport_resp_data[FLASH_ADDR_MSB:FLASH_ADDR] <= flash_addr;
          end

          BASE_ADDRESS + FLASH_READ_DATA_REG: begin
            s_ctrlport_resp_data <= flash_read_data;
          end

          BASE_ADDRESS + FLASH_CFM0_START_ADDR_REG: begin
            s_ctrlport_resp_data <= MEM_INIT ? FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT : 
                                               FLASH_PRIMARY_IMAGE_START_ADDR;
          end

          BASE_ADDRESS + FLASH_CFM0_END_ADDR_REG: begin
            s_ctrlport_resp_data <= FLASH_PRIMARY_IMAGE_END_ADDR;
          end


          default: begin
            s_ctrlport_resp_data <= {32{1'bx}};
            if (address_in_range) begin
              s_ctrlport_resp_status <= CTRL_STS_CMDERR;


            end else begin
              s_ctrlport_resp_ack <= 1'b0;
            end
          end
        endcase
      end
    end
  end






  localparam IDLE                     = 4'h0;
  localparam WP_DISABLED              = 4'h1;
  localparam WAIT_FOR_READ_DATA_VALID = 4'h2;
  localparam GET_READ_STATUS          = 4'h3;
  localparam CHECK_READ_STATUS        = 4'h4;
  localparam WAIT_FOR_WRITE_COMPLETE  = 4'h5;
  localparam GET_WRITE_STATUS         = 4'h6;
  localparam CHECK_WRITE_STATUS       = 4'h7;
  localparam ERASE_SECTOR             = 4'h8;
  localparam GET_ERASE_BUSY           = 4'h9;
  localparam CHECK_ERASE_BUSY         = 4'hA;
  localparam GET_ERASE_IDLE           = 4'hB;
  localparam CHECK_ERASE_IDLE         = 4'hC;





  localparam STATUS_REG_ADDR              = 1'b0;
  localparam   STATUS_REG_BUSY_STATUS_MSB = 1;
  localparam   STATUS_REG_BUSY_STATUS_LSB = 0;
  localparam     STATUS_REG_IDLE          = 2'b00;
  localparam     STATUS_REG_ERASE_BUSY    = 2'b01;
  localparam     STATUS_REG_WRITE_BUSY    = 2'b10;
  localparam     STATUS_REG_READ_BUSY     = 2'b11;
  localparam   STATUS_REG_READ_STATUS     = 2;
  localparam   STATUS_REG_WRITE_STATUS    = 3;
  localparam   STATUS_REG_ERASE_STATUS    = 4;
  localparam     OPERATION_FAILED         = 0;

  localparam CONTROL_REG_ADDR        = 1'b1;
  localparam   SECTOR_ERASE_ADDR_MSB = 22;
  localparam   SECTOR_ERASE_ADDR_LSB = 20;

  localparam     ENABLE_WP           = MEM_INIT ? 3'b111 : 3'b100;
  localparam     DISABLE_WP          = 3'b000;





  reg [3:0] state = IDLE;
  wire flash_no_errors_detected;

  assign flash_no_errors_detected = ~(flash_read_err | flash_write_err | flash_erase_err);

  always @(posedge ctrlport_clk) begin
    if (ctrlport_rst) begin
      state <= IDLE;


      flash_wp_enabled <= 1'b1;
      flash_read_idle  <= 1'b1;
      flash_write_idle <= 1'b1;
      flash_erase_idle <= 1'b1;
      flash_read_err   <= 1'b0;
      flash_write_err  <= 1'b0;
      flash_erase_err  <= 1'b0;
      flash_read_data  <= 32'b0;


      csr_addr      <= 1'b0;
      csr_writedata <= {32 {1'b1}};
      csr_read      <= 1'b0;
      csr_write     <= 1'b0;


      data_addr      <= 17'b0;
      data_writedata <= 32'b0;
      data_read      <= 1'b0;
      data_write     <= 1'b0;
    end

    else begin

      csr_read      <= 1'b0;
      csr_write     <= 1'b0;
      csr_addr      <= STATUS_REG_ADDR;
      csr_writedata <= {32 {1'b1}};

      data_read  <= 1'b0;
      data_write <= 1'b0;


      case(state)












        IDLE: begin
          flash_wp_enabled <= 1'b1;

          if (flash_read_stb && flash_no_errors_detected) begin
            state           <= WAIT_FOR_READ_DATA_VALID;
            flash_read_idle <= 1'b0;
            data_read       <= 1'b1;
            data_addr       <= flash_addr;
          end else if (flash_disable_wp_stb && ~flash_enable_wp_stb && flash_no_errors_detected) begin
            state     <= WP_DISABLED;
            csr_write <= 1'b1;
            csr_addr  <= CONTROL_REG_ADDR;
            csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= DISABLE_WP;
          end
        end















        WP_DISABLED: begin
          flash_wp_enabled <= 1'b0;

          if (flash_erase_stb && flash_write_stb) begin
            flash_erase_err <= 1'b1;
            flash_write_err <= 1'b1;
          end

          if (flash_enable_wp_stb || (flash_erase_stb && flash_write_stb)) begin
            state     <= IDLE;
            csr_write <= 1'b1;
            csr_addr  <= CONTROL_REG_ADDR;
            csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= ENABLE_WP;
          end else if (flash_write_stb) begin
            state            <= WAIT_FOR_WRITE_COMPLETE;
            flash_write_idle <= 1'b0;
            data_write       <= 1'b1;
            data_writedata   <= flash_write_data;
            data_addr        <= flash_addr;
          end else if (flash_erase_stb) begin
            state            <= ERASE_SECTOR;
            flash_erase_idle <= 1'b0;
            csr_write        <= 1'b1;
            csr_addr         <= CONTROL_REG_ADDR;
            csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= DISABLE_WP;
            csr_writedata[SECTOR_ERASE_ADDR_MSB:SECTOR_ERASE_ADDR_LSB] <= flash_sector;
          end
        end















        WAIT_FOR_READ_DATA_VALID: begin
          if (data_readdatavalid) begin
            state           <= GET_READ_STATUS;
            flash_read_data <= data_readdata;
            csr_read        <= 1'b1;
          end
        end

















        GET_READ_STATUS: begin
          state <= CHECK_READ_STATUS;


        end
        CHECK_READ_STATUS: begin
          if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin
            state           <= IDLE;
            flash_read_idle <= 1'b1;
            flash_read_err  <= (csr_readdata[STATUS_REG_READ_STATUS] == OPERATION_FAILED) ? 1'b1 : 1'b0;
          end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_READ_BUSY) begin
            state <= GET_READ_STATUS;
            csr_read <= 1'b1;
          end
        end













        WAIT_FOR_WRITE_COMPLETE: begin
          if (~data_waitrequest) begin
            state    <= GET_WRITE_STATUS;
            csr_read <= 1'b1;
          end else begin


            data_write <= 1'b1;
          end
        end

















        GET_WRITE_STATUS: begin
          state <= CHECK_WRITE_STATUS;


        end
        CHECK_WRITE_STATUS: begin
          if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin
            if (csr_readdata[STATUS_REG_WRITE_STATUS] == OPERATION_FAILED) begin
              state     <= IDLE;
              csr_write <= 1'b1;
              csr_addr  <= CONTROL_REG_ADDR;
              csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= ENABLE_WP;
            end else begin
              state <= WP_DISABLED;
            end
            flash_write_idle <= 1'b1;
            flash_write_err <= (csr_readdata[STATUS_REG_WRITE_STATUS] == OPERATION_FAILED) ? 1'b1 : 1'b0;
          end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_WRITE_BUSY) begin
            state <= GET_WRITE_STATUS;
            csr_read <= 1'b1;
          end
        end









        ERASE_SECTOR: begin
          state <= GET_ERASE_BUSY;
          csr_read <= 1'b1;
        end















        GET_ERASE_BUSY: begin
          state <= CHECK_ERASE_BUSY;


        end
        CHECK_ERASE_BUSY: begin
          if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_ERASE_BUSY) begin
            state <= GET_ERASE_IDLE;
            csr_read <= 1'b1;
          end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin
            state <= GET_ERASE_BUSY;
            csr_read <= 1'b1;
          end
        end







        GET_ERASE_IDLE: begin
          state <= CHECK_ERASE_IDLE;


        end
        CHECK_ERASE_IDLE: begin
          if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin
            if (csr_readdata[STATUS_REG_ERASE_STATUS] == OPERATION_FAILED) begin
              state     <= IDLE;
              csr_write <= 1'b1;
              csr_addr  <= CONTROL_REG_ADDR;
              csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= ENABLE_WP;
            end else begin
              state <= WP_DISABLED;
            end
            flash_erase_idle <= 1'b1;
            flash_erase_err  <= (csr_readdata[STATUS_REG_ERASE_STATUS] == OPERATION_FAILED) ? 1'b1 : 1'b0;
          end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_ERASE_BUSY) begin
            state <= GET_ERASE_IDLE;
            csr_read <= 1'b1;
          end
        end


        default: begin
          state <= IDLE;
        end
      endcase


      if (clear_flash_read_err_stb) begin
        flash_read_err <= 1'b0;
      end
      if (clear_flash_write_err_stb) begin
        flash_write_err <= 1'b0;
      end
      if (clear_flash_erase_err_stb) begin
        flash_erase_err <= 1'b0;
      end
    end
  end

endmodule
module reconfig_engine #(
  parameter BASE_ADDRESS  = 0,
  parameter NUM_ADDRESSES = 32,
  parameter MEM_INIT      = 0
) (
  input wire ctrlport_clk,
  input wire ctrlport_rst,


  input  wire        s_ctrlport_req_wr,
  input  wire        s_ctrlport_req_rd,
  input  wire [19:0] s_ctrlport_req_addr,
  input  wire [31:0] s_ctrlport_req_data,

  output reg         s_ctrlport_resp_ack,
  output reg  [ 1:0] s_ctrlport_resp_status,
  output reg  [31:0] s_ctrlport_resp_data,


  output reg         csr_addr,
  output reg         csr_read,
  output reg  [31:0] csr_writedata,
  output reg         csr_write,
  input  wire [31:0] csr_readdata,
  output reg  [16:0] data_addr,
  output reg         data_read,
  output reg  [31:0] data_writedata,
  output reg         data_write,
  input  wire [31:0] data_readdata,
  input  wire        data_waitrequest,
  input  wire        data_readdatavalid
);


  `include "regmap/reconfig_regmap_utils.vh"
  `include "../../../lib/rfnoc/core/ctrlport.vh"


  `ifdef VARIANT_10M04
    localparam FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT = FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT_10M04;
    localparam FLASH_PRIMARY_IMAGE_START_ADDR          = FLASH_PRIMARY_IMAGE_START_ADDR_10M04;
    localparam FLASH_PRIMARY_IMAGE_END_ADDR            = FLASH_PRIMARY_IMAGE_END_ADDR_10M04;
    localparam CFM0_WP_OFFSET_MSB                      = 26;
    localparam CFM0_WP_OFFSET_LSB                      = 24;
  `elsif VARIANT_10M08
    localparam FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT = FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT_10M08;
    localparam FLASH_PRIMARY_IMAGE_START_ADDR          = FLASH_PRIMARY_IMAGE_START_ADDR_10M08;
    localparam FLASH_PRIMARY_IMAGE_END_ADDR            = FLASH_PRIMARY_IMAGE_END_ADDR_10M08;
    localparam CFM0_WP_OFFSET_MSB                      = 27;
    localparam CFM0_WP_OFFSET_LSB                      = 25;
  `else
    ERROR_MAX10_variant_must_be_defined();
    localparam FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT = FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT_10M04;
    localparam FLASH_PRIMARY_IMAGE_START_ADDR          = FLASH_PRIMARY_IMAGE_START_ADDR_10M04;
    localparam FLASH_PRIMARY_IMAGE_END_ADDR            = FLASH_PRIMARY_IMAGE_END_ADDR_10M04;
    localparam CFM0_WP_OFFSET_MSB                      = 26;
    localparam CFM0_WP_OFFSET_LSB                      = 24;
  `endif







  reg [16:0] flash_addr       = 0;
  reg [31:0] flash_write_data = 0;
  reg [31:0] flash_read_data;


  reg       flash_read_stb       = 1'b0;
  reg       flash_write_stb      = 1'b0;
  reg       flash_erase_stb      = 1'b0;
  reg       flash_enable_wp_stb  = 1'b0;
  reg       flash_disable_wp_stb = 1'b0;
  reg [2:0] flash_sector         = 3'b0;


  reg flash_wp_enabled;
  reg flash_read_idle;
  reg flash_write_idle;
  reg flash_erase_idle;
  reg flash_read_err;
  reg flash_write_err;
  reg flash_erase_err;
  reg clear_flash_read_err_stb  = 1'b0;
  reg clear_flash_write_err_stb = 1'b0;
  reg clear_flash_erase_err_stb = 1'b0;





  wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) &&
                          (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES);





  always @(posedge ctrlport_clk) begin

    s_ctrlport_resp_ack <= 1'b0;

    flash_read_stb            <= 1'b0;
    flash_write_stb           <= 1'b0;
    flash_erase_stb           <= 1'b0;
    flash_enable_wp_stb       <= 1'b0;
    flash_disable_wp_stb      <= 1'b0;
    clear_flash_read_err_stb  <= 1'b0;
    clear_flash_write_err_stb <= 1'b0;
    clear_flash_erase_err_stb <= 1'b0;


    if (ctrlport_rst) begin
      s_ctrlport_resp_ack     <= 1'b0;
      s_ctrlport_resp_data    <= {32{1'bx}};
      s_ctrlport_resp_status  <= CTRL_STS_OKAY;


    end else begin
      if (s_ctrlport_req_wr) begin

        s_ctrlport_resp_ack     <= 1'b1;
        s_ctrlport_resp_data    <= {32{1'bx}};
        s_ctrlport_resp_status  <= CTRL_STS_OKAY;

        case (s_ctrlport_req_addr)
          BASE_ADDRESS + FLASH_CONTROL_REG: begin
            flash_read_stb            <= s_ctrlport_req_data[FLASH_READ_STB];
            flash_write_stb           <= s_ctrlport_req_data[FLASH_WRITE_STB];
            flash_erase_stb           <= s_ctrlport_req_data[FLASH_ERASE_STB];
            flash_enable_wp_stb       <= s_ctrlport_req_data[FLASH_ENABLE_WP_STB];
            flash_disable_wp_stb      <= s_ctrlport_req_data[FLASH_DISABLE_WP_STB];
            clear_flash_read_err_stb  <= s_ctrlport_req_data[CLEAR_FLASH_READ_ERROR_STB];
            clear_flash_write_err_stb <= s_ctrlport_req_data[CLEAR_FLASH_WRITE_ERROR_STB];
            clear_flash_erase_err_stb <= s_ctrlport_req_data[CLEAR_FLASH_ERASE_ERROR_STB];
            flash_sector              <= s_ctrlport_req_data[FLASH_ERASE_SECTOR_MSB:FLASH_ERASE_SECTOR];
          end

          BASE_ADDRESS + FLASH_ADDR_REG: begin
            flash_addr <= s_ctrlport_req_data[FLASH_ADDR_MSB:FLASH_ADDR];
          end

          BASE_ADDRESS + FLASH_WRITE_DATA_REG: begin
            flash_write_data <= s_ctrlport_req_data[FLASH_WRITE_DATA_MSB:FLASH_WRITE_DATA];
          end


          default: begin
            if (address_in_range) begin
              s_ctrlport_resp_status <= CTRL_STS_CMDERR;


            end else begin
              s_ctrlport_resp_ack <= 1'b0;
            end
          end
        endcase


      end else if (s_ctrlport_req_rd) begin

        s_ctrlport_resp_ack <= 1'b1;
        s_ctrlport_resp_status <= CTRL_STS_OKAY;

        case (s_ctrlport_req_addr)
          BASE_ADDRESS + FLASH_STATUS_REG: begin
            s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}};
            s_ctrlport_resp_data[FLASH_WP_ENABLED]       <= flash_wp_enabled;
            s_ctrlport_resp_data[FLASH_READ_IDLE]        <= flash_read_idle;
            s_ctrlport_resp_data[FLASH_READ_ERR]         <= flash_read_err;
            s_ctrlport_resp_data[FLASH_ERASE_IDLE]       <= flash_erase_idle;
            s_ctrlport_resp_data[FLASH_ERASE_ERR]        <= flash_erase_err;
            s_ctrlport_resp_data[FLASH_WRITE_IDLE]       <= flash_write_idle;
            s_ctrlport_resp_data[FLASH_WRITE_ERR]        <= flash_write_err;
            s_ctrlport_resp_data[FLASH_MEM_INIT_ENABLED] <= MEM_INIT ? 1'b1 : 1'b0;
          end

          BASE_ADDRESS + FLASH_ADDR_REG: begin
            s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}};
            s_ctrlport_resp_data[FLASH_ADDR_MSB:FLASH_ADDR] <= flash_addr;
          end

          BASE_ADDRESS + FLASH_READ_DATA_REG: begin
            s_ctrlport_resp_data <= flash_read_data;
          end

          BASE_ADDRESS + FLASH_CFM0_START_ADDR_REG: begin
            s_ctrlport_resp_data <= MEM_INIT ? FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT : 
                                               FLASH_PRIMARY_IMAGE_START_ADDR;
          end

          BASE_ADDRESS + FLASH_CFM0_END_ADDR_REG: begin
            s_ctrlport_resp_data <= FLASH_PRIMARY_IMAGE_END_ADDR;
          end


          default: begin
            s_ctrlport_resp_data <= {32{1'bx}};
            if (address_in_range) begin
              s_ctrlport_resp_status <= CTRL_STS_CMDERR;


            end else begin
              s_ctrlport_resp_ack <= 1'b0;
            end
          end
        endcase
      end
    end
  end






  localparam IDLE                     = 4'h0;
  localparam WP_DISABLED              = 4'h1;
  localparam WAIT_FOR_READ_DATA_VALID = 4'h2;
  localparam GET_READ_STATUS          = 4'h3;
  localparam CHECK_READ_STATUS        = 4'h4;
  localparam WAIT_FOR_WRITE_COMPLETE  = 4'h5;
  localparam GET_WRITE_STATUS         = 4'h6;
  localparam CHECK_WRITE_STATUS       = 4'h7;
  localparam ERASE_SECTOR             = 4'h8;
  localparam GET_ERASE_BUSY           = 4'h9;
  localparam CHECK_ERASE_BUSY         = 4'hA;
  localparam GET_ERASE_IDLE           = 4'hB;
  localparam CHECK_ERASE_IDLE         = 4'hC;





  localparam STATUS_REG_ADDR              = 1'b0;
  localparam   STATUS_REG_BUSY_STATUS_MSB = 1;
  localparam   STATUS_REG_BUSY_STATUS_LSB = 0;
  localparam     STATUS_REG_IDLE          = 2'b00;
  localparam     STATUS_REG_ERASE_BUSY    = 2'b01;
  localparam     STATUS_REG_WRITE_BUSY    = 2'b10;
  localparam     STATUS_REG_READ_BUSY     = 2'b11;
  localparam   STATUS_REG_READ_STATUS     = 2;
  localparam   STATUS_REG_WRITE_STATUS    = 3;
  localparam   STATUS_REG_ERASE_STATUS    = 4;
  localparam     OPERATION_FAILED         = 0;

  localparam CONTROL_REG_ADDR        = 1'b1;
  localparam   SECTOR_ERASE_ADDR_MSB = 22;
  localparam   SECTOR_ERASE_ADDR_LSB = 20;

  localparam     ENABLE_WP           = MEM_INIT ? 3'b111 : 3'b100;
  localparam     DISABLE_WP          = 3'b000;





  reg [3:0] state = IDLE;
  wire flash_no_errors_detected;

  assign flash_no_errors_detected = ~(flash_read_err | flash_write_err | flash_erase_err);

  always @(posedge ctrlport_clk) begin
    if (ctrlport_rst) begin
      state <= IDLE;


      flash_wp_enabled <= 1'b1;
      flash_read_idle  <= 1'b1;
      flash_write_idle <= 1'b1;
      flash_erase_idle <= 1'b1;
      flash_read_err   <= 1'b0;
      flash_write_err  <= 1'b0;
      flash_erase_err  <= 1'b0;
      flash_read_data  <= 32'b0;


      csr_addr      <= 1'b0;
      csr_writedata <= {32 {1'b1}};
      csr_read      <= 1'b0;
      csr_write     <= 1'b0;


      data_addr      <= 17'b0;
      data_writedata <= 32'b0;
      data_read      <= 1'b0;
      data_write     <= 1'b0;
    end

    else begin

      csr_read      <= 1'b0;
      csr_write     <= 1'b0;
      csr_addr      <= STATUS_REG_ADDR;
      csr_writedata <= {32 {1'b1}};

      data_read  <= 1'b0;
      data_write <= 1'b0;


      case(state)












        IDLE: begin
          flash_wp_enabled <= 1'b1;

          if (flash_read_stb && flash_no_errors_detected) begin
            state           <= WAIT_FOR_READ_DATA_VALID;
            flash_read_idle <= 1'b0;
            data_read       <= 1'b1;
            data_addr       <= flash_addr;
          end else if (flash_disable_wp_stb && ~flash_enable_wp_stb && flash_no_errors_detected) begin
            state     <= WP_DISABLED;
            csr_write <= 1'b1;
            csr_addr  <= CONTROL_REG_ADDR;
            csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= DISABLE_WP;
          end
        end















        WP_DISABLED: begin
          flash_wp_enabled <= 1'b0;

          if (flash_erase_stb && flash_write_stb) begin
            flash_erase_err <= 1'b1;
            flash_write_err <= 1'b1;
          end

          if (flash_enable_wp_stb || (flash_erase_stb && flash_write_stb)) begin
            state     <= IDLE;
            csr_write <= 1'b1;
            csr_addr  <= CONTROL_REG_ADDR;
            csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= ENABLE_WP;
          end else if (flash_write_stb) begin
            state            <= WAIT_FOR_WRITE_COMPLETE;
            flash_write_idle <= 1'b0;
            data_write       <= 1'b1;
            data_writedata   <= flash_write_data;
            data_addr        <= flash_addr;
          end else if (flash_erase_stb) begin
            state            <= ERASE_SECTOR;
            flash_erase_idle <= 1'b0;
            csr_write        <= 1'b1;
            csr_addr         <= CONTROL_REG_ADDR;
            csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= DISABLE_WP;
            csr_writedata[SECTOR_ERASE_ADDR_MSB:SECTOR_ERASE_ADDR_LSB] <= flash_sector;
          end
        end















        WAIT_FOR_READ_DATA_VALID: begin
          if (data_readdatavalid) begin
            state           <= GET_READ_STATUS;
            flash_read_data <= data_readdata;
            csr_read        <= 1'b1;
          end
        end

















        GET_READ_STATUS: begin
          state <= CHECK_READ_STATUS;


        end
        CHECK_READ_STATUS: begin
          if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin
            state           <= IDLE;
            flash_read_idle <= 1'b1;
            flash_read_err  <= (csr_readdata[STATUS_REG_READ_STATUS] == OPERATION_FAILED) ? 1'b1 : 1'b0;
          end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_READ_BUSY) begin
            state <= GET_READ_STATUS;
            csr_read <= 1'b1;
          end
        end













        WAIT_FOR_WRITE_COMPLETE: begin
          if (~data_waitrequest) begin
            state    <= GET_WRITE_STATUS;
            csr_read <= 1'b1;
          end else begin


            data_write <= 1'b1;
          end
        end

















        GET_WRITE_STATUS: begin
          state <= CHECK_WRITE_STATUS;


        end
        CHECK_WRITE_STATUS: begin
          if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin
            if (csr_readdata[STATUS_REG_WRITE_STATUS] == OPERATION_FAILED) begin
              state     <= IDLE;
              csr_write <= 1'b1;
              csr_addr  <= CONTROL_REG_ADDR;
              csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= ENABLE_WP;
            end else begin
              state <= WP_DISABLED;
            end
            flash_write_idle <= 1'b1;
            flash_write_err <= (csr_readdata[STATUS_REG_WRITE_STATUS] == OPERATION_FAILED) ? 1'b1 : 1'b0;
          end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_WRITE_BUSY) begin
            state <= GET_WRITE_STATUS;
            csr_read <= 1'b1;
          end
        end









        ERASE_SECTOR: begin
          state <= GET_ERASE_BUSY;
          csr_read <= 1'b1;
        end















        GET_ERASE_BUSY: begin
          state <= CHECK_ERASE_BUSY;


        end
        CHECK_ERASE_BUSY: begin
          if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_ERASE_BUSY) begin
            state <= GET_ERASE_IDLE;
            csr_read <= 1'b1;
          end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin
            state <= GET_ERASE_BUSY;
            csr_read <= 1'b1;
          end
        end







        GET_ERASE_IDLE: begin
          state <= CHECK_ERASE_IDLE;


        end
        CHECK_ERASE_IDLE: begin
          if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin
            if (csr_readdata[STATUS_REG_ERASE_STATUS] == OPERATION_FAILED) begin
              state     <= IDLE;
              csr_write <= 1'b1;
              csr_addr  <= CONTROL_REG_ADDR;
              csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= ENABLE_WP;
            end else begin
              state <= WP_DISABLED;
            end
            flash_erase_idle <= 1'b1;
            flash_erase_err  <= (csr_readdata[STATUS_REG_ERASE_STATUS] == OPERATION_FAILED) ? 1'b1 : 1'b0;
          end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_ERASE_BUSY) begin
            state <= GET_ERASE_IDLE;
            csr_read <= 1'b1;
          end
        end


        default: begin
          state <= IDLE;
        end
      endcase


      if (clear_flash_read_err_stb) begin
        flash_read_err <= 1'b0;
      end
      if (clear_flash_write_err_stb) begin
        flash_write_err <= 1'b0;
      end
      if (clear_flash_erase_err_stb) begin
        flash_erase_err <= 1'b0;
      end
    end
  end

endmodule