// // Copyright 2021 Ettus Research, A National Instruments Brand // // SPDX-License-Identifier: LGPL-3.0-or-later // // Module: reconfig_engine // // Description: // // This file implements the registers and the state machine to interface with // Intel's IP for the Max 10 FPGA that allows in-field updates to the primary // FPGA image. This state machine has been designed to provide a level of // abstraction between the register interface provided to user and the // details of interfacing with Intel's On-Chip Flash IP block. The user // simply needs to instruct this state machine to enable/disable write // protection and perform read/write/erase operations accordingly to load and // verify a new primary FPGA image. Since the purpose of this file is to // allow modification to an FPGA image care has been taken to mitigate data // corruption. // // The interface to Intel's On-Chip Flash IP block implemented in this file // is based on the information found in the Max 10 User Flash Memory User // Guide found at the link below. // // https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/hb/max-10/ug_m10_ufm.pdf // // Parameters: // // BASE_ADDRESS : Base address for CtrlPort registers. // NUM_ADDRESSES : Number of bytes of address space to use. // MEM_INIT : Memory initialization enabled. Set to 0 if MAX10 internal // configuration set to single compressed image. Set to 1 if // MAX10 internal configuration set to single compressed // image with memory initialization. // `default_nettype none module reconfig_engine #( parameter BASE_ADDRESS = 0, parameter NUM_ADDRESSES = 32, parameter MEM_INIT = 0 ) ( input wire ctrlport_clk, input wire ctrlport_rst, /// Request 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, // Response output reg s_ctrlport_resp_ack, output reg [ 1:0] s_ctrlport_resp_status, output reg [31:0] s_ctrlport_resp_data, // Interface to On-Chip Flash IP 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" // Check MAX10 variant target (10M04 or 10M08) `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; // From Max 10 Flash Memory User Guide. localparam CFM0_WP_OFFSET_LSB = 24; // From Max 10 Flash Memory User Guide. `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; // From Max 10 Flash Memory User Guide. localparam CFM0_WP_OFFSET_LSB = 25; // From Max 10 Flash Memory User Guide. `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; // From Max 10 Flash Memory User Guide. localparam CFM0_WP_OFFSET_LSB = 24; // From Max 10 Flash Memory User Guide. `endif //---------------------------------------------------------- // Flash Interface between Registers and State Machine //---------------------------------------------------------- // Flash Data Interface reg [16:0] flash_addr = 0; reg [31:0] flash_write_data = 0; reg [31:0] flash_read_data; // Flash Control Interface - Control 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; // Flash Control Interface - Status 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; //---------------------------------------------------------- // Address Calculation //---------------------------------------------------------- wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) && (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES); //---------------------------------------------------------- // Handling of ControlPort Requests //---------------------------------------------------------- always @(posedge ctrlport_clk) begin // Default assignments 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; // Do not acknowledge on reset if (ctrlport_rst) begin s_ctrlport_resp_ack <= 1'b0; s_ctrlport_resp_data <= {32{1'bx}}; s_ctrlport_resp_status <= CTRL_STS_OKAY; // Write requests end else begin if (s_ctrlport_req_wr) begin // Always issue an ack and no data 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 // Error on undefined address default: begin if (address_in_range) begin s_ctrlport_resp_status <= CTRL_STS_CMDERR; // No response if out of range end else begin s_ctrlport_resp_ack <= 1'b0; end end endcase // Read request end else if (s_ctrlport_req_rd) begin // Default assumption: valid request 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 // Error on undefined address default: begin s_ctrlport_resp_data <= {32{1'bx}}; if (address_in_range) begin s_ctrlport_resp_status <= CTRL_STS_CMDERR; // No response if out of range end else begin s_ctrlport_resp_ack <= 1'b0; end end endcase end end end //---------------------------------------------------------- // State Machine Constants //---------------------------------------------------------- // Local state 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; // The Intel on-chip flash control interface has two registers, a Status // Register at address 0 and a Control Register at address 1. The constants // defined below identify fields and values of interest in each register. // These are taken directly from the Max 10 Flash Memory User Guide. 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; // CFM0_WP_OFFSET_MSB and CFM0_WP_OFFSET_LSB are MAX10 variant dependent. localparam ENABLE_WP = MEM_INIT ? 3'b111 : 3'b100; localparam DISABLE_WP = 3'b000; //---------------------------------------------------------- // State Machine //---------------------------------------------------------- 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; // Signals to config registers 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; // Signals to flash control interface csr_addr <= 1'b0; csr_writedata <= {32 {1'b1}}; csr_read <= 1'b0; csr_write <= 1'b0; // Signals to flash data interface data_addr <= 17'b0; data_writedata <= 32'b0; data_read <= 1'b0; data_write <= 1'b0; end // Rising edge clock else begin // Default values 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; // State handling case(state) // When in IDLE: // * No operations are in progress and write protection is enabled. // * Allowed transitions are to either read data from flash or // disable write protection. // * Transitions are only allowed if no error bits are asserted. // * In the event both the *read_stb and *disable_wp_stb bits are // asserted read operations take priority as these do not open the // flash to modification. // * Attempts to both enable and disable write protection // simultaneously result in the state machine remaining in IDLE // write protection enabled. 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 // Transition from WP_DISABLED when write protection is enabled or when // write/erase operations are initiated. A few things to note: // * Enabling write protection takes priority, regardless of what // other control bits may be asserted simultaneously, followed by // writes, and lastly erases. // * The user should not strobe both the *write_stb and *erase_stb // bits simultaneously, but if they do the state machine returns to // IDLE (thereby enabling write protection) and the *write_err and // *erase_err bits are asserted. // * Performing a write or erase operation is only allowed from // WP_DISABLED. This allows some mitigation against data corruption // as multiple steps are required to change the data in the flash. // First write protection must be disabled, and only then can the // flash be erased or written. 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 // Read Flash // -------------- // Per Intel's Max 10 User Flash Memory User Guide, the Read bit of the // flash data interface should be pulsed for one clock cycle to start // the read process from flash. This pulse occurs upon transition from // IDLE to WAIT_FOR_READ_DATA_VALID. The state machine then waits in // WAIT_FOR_READ_DATA_VALID until the flash data interface // data_readdatavalid signal asserts, indicating the data is now valid. // Intel's documentation does not provide guidance on the expected time // for data_readdatavalid to assert. From simulation, however, // data_readdatavalid asserts four clock cycles after the Read pulse // ends. The data_readdatavalid signal from the flash data interface // pulses for one clock cycle. Only during this pulse is the data valid. 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 // The data_readdatavalid signal determines when the read operation has // completed in the flash data interface, but Intel's documentation // does not indicate the relation of this bit to the 'busy' field in // the flash control interface Status Register. To verify that the read // operation is complete, the StatusRegister is polled until the 'busy' // field indicates the flash is idle. This polling operation is // implemented with CHECK_READ_STATUS below. GET_READ_STATUS exists to // set the address of the flash control interface to the Status // Register and pulse the read bit of the flash control interface. // CHECK_READ_STATUS evaluates the resulting Status Register data and // steer the state machine accordingly. See Figure 6 in Intel's Max 10 // User Flash Memory User Guide for a waveform on this request and // check mechanism. Successful read operations result in the state // machine returning to IDLE. Failing read operations assert the // flash_read_err bit before returning to IDLE. From simulation, the // 'busy' field returns to IDLE on the third read. GET_READ_STATUS: begin state <= CHECK_READ_STATUS; // csr_read set in transactions into this state // CSR address set as default assignment 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 // Write Flash //--------------- // Per Intel's Max 10 User Flash Memory User Guide, the Write bit of // the flash data interface should be asserted while maintaining // address and data until the flash interface deasserts the // data_waitrequest bit. Transition from WP_DISABLED to // WAIT_FOR_WRITE_COMPLETE causes the write bit to assert and address // and data to be set. The state machine remains in this state until // the data_waitrequest bit deasserts. Per Intel's Max 10 User Flash // Memory User Guide, the data_waitrequest signal is expected to // deassert within 555 usec. WAIT_FOR_WRITE_COMPLETE: begin if (~data_waitrequest) begin state <= GET_WRITE_STATUS; csr_read <= 1'b1; end else begin // Flash writes require asserting the Write bit of the flash data // interface until the write is complete. data_write <= 1'b1; end end // The data_waitrequest signal determines when the write operation has // completed in the flash data interface, but Intel's documentation does // not indicate the relation of this bit to the 'busy' field in the flash // control interface Status Register. To verify that the write operation // is complete the StatusRegister is polled until the 'busy' field // indicates the flash is idle. This polling operation is implemented with // GET_WRITE_STATUS and CHECK_WRITE_STATUS below, and follows the same // methodology as the polling operation for reads described above with the // following two changes: // * Upon successful completion of a write operation the state // machine returns to WP_DISABLED. This allows repeated writes of // new data without having to disable/enable for each write. // * When a failure is detected the state machine transitions to to // IDLE thereby enabling write protection. Failure of a write is // not expected. Write protection is enabled in the event of a // failure to mitigate further data corruption. GET_WRITE_STATUS: begin state <= CHECK_WRITE_STATUS; // csr_read set in transactions into this state // CSR address set as default assignment 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 // SUCCESS 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 Flash //------------- // Erasing the primary configuration image requires a single write to // the flash control interface Control Register. Only one sector needs // to be erased to erase the entire primary configuration image. // Transition from WP_DISABLED to ERASE_SECTOR causes data to be // written to the Control Register to erase this sector and pulse the // flash control interface write bit. ERASE_SECTOR: begin state <= GET_ERASE_BUSY; csr_read <= 1'b1; end // There is some latency between writing the Control Register and the // 'busy' field of the flash control interface Status Register // indicating the erase operation is in progress. After initiating the // erase operation, GET_ERASE_BUSY and CHECK_ERASE_BUSY implement a // polling operation to determine when the erase operation has started. // GET_ERASE_BUSY exists to set the address of the flash control // interface to the Status Register and pulse the read bit of the flash // control interface. CHECK_ERASE_BUSY exists to evaluate the resulting // Status Register data and steer the state machine accordingly. The // polling operation continues until the 'busy' field indicates the // erase operation is in progress. Intel's documentation does not // indicate how long it takes for the Status Register to indicate the // erase is in progress, but simulation shows the erase is in progress // after the second read. GET_ERASE_BUSY: begin state <= CHECK_ERASE_BUSY; // csr_read set in transactions into this state // CSR address set as default assignment 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 // Once the erase operation is in progress a second polling operation // defined by GET_ERASE_IDLE and CHECK_ERASE_IDLE is implemented to // determine when the operation has completed. This polling operation // follows the same methodology as the polling operation for erase busy // described above. Intel's documentation indicates that erase // operations take a maximum of 350 msec. GET_ERASE_IDLE: begin state <= CHECK_ERASE_IDLE; // csr_read set in transactions into this state // CSR address set as default assignment 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 // SUCCESS 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 to IDLE in other cases default: begin state <= IDLE; end endcase // Reset errors 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 `default_nettype wire //XmlParse xml_on // // // // These registers are used to upload and verify a new primary image to the // Max 10 FPGA on-chip flash when configured to support dual configuration // images. The steps below outline the process of verifying/preparing the // new image to be written, erasing the current image, writing the new // image, and verifying the new image was successfully written. // {p}{b}Prepare the data...{/b} // {ol}{li}{p}The Max 10 FPGA build should generate a *cfm0_auto.rpd // file The *.rpd file is a "raw programming // data" file holding all data related to the // configuration image (CFM0). There are two // important items to note regarding the addresses. // First the *rpd data uses {b}byte{/b} addresses. // Second, the start/end addresses defined by // FLASH_PRIMARY_IMAGE_ADDR_ENUM are 32-bit word addresses{/p}{/li} // {li}{p}As a sanity check, verify the size of the raw // programming data for CFM0 correspond to the address // range of FLASH_PRIMARY_IMAGE_ADDR_ENUM. Do this by // reading the values from FLASH_CFM0_START_ADDR_REG and // FLASH_CFM0_END_ADDR, subtract both values, add one and // multiply by four. // {/p}{/li} // {li}{p}Having passed the sanity check the *.rpd data must // now be manipulated into the form required by Altera's // on-chip flash IP. Two operations must be performed. // First the data must be converted from bytes to 32-bit // words. Second the bit order must be reversed. This is // illustrated in in the following table which shows byte // address and data from the *.rpd file compared to the // word address and data to be written to the on-chip // flash. // {table border=1} // {tr}{td}.Map Addr{/td}{td}.Map Data{/td}{td}Flash Addr{/td}{td}Flash Data{/td}{/tr} // {tr}{td}0x2B800{/td}{td}0x01{/td}{td rowspan=4}0xAC00{/td}{td rowspan=4}0x8040C020{/td}{/tr} // {tr}{td}0x2B801{/td}{td}0x02{/td}{/tr} // {tr}{td}0x2B802{/td}{td}0x03{/td}{/tr} // {tr}{td}0x2B803{/td}{td}0x04{/td}{/tr} // {tr}{td}0x2B804{/td}{td}0x05{/td}{td rowspan=4}0xAC01{/td}{td rowspan=4}0xA060E010{/td}{/tr} // {tr}{td}0x2B805{/td}{td}0x06{/td}{/tr} // {tr}{td}0x2B806{/td}{td}0x07{/td}{/tr} // {tr}{td}0x2B807{/td}{td}0x08{/td}{/tr} // {/table} // {/p}{/li} // {li}{p}The resulting set of flash address data pairs should // be used when writing FLASH_ADDR_REG and // FLASH_WRITE_DATA_REG to update the CFM0 image. // However, prior to writing the new image the old image // must be erased. // {/p}{/li} // {/ol} // {/p} // {p}{b}Erase the current primary flash image...{/b} // {ol}{p}{li}Read FLASH_STATUS_REG and verify no error bits are // asserted and that all read, write, and erase operations // are idle.{/p}{/li} // {p}{li}Disable write protection of the flash by strobing the // FLASH_DISABLE_WP_STB bit of FLASH_CONTROL_REG. // {/p}{/li} // {p}{li}Verify write protection is disabled and no errors are // present by reading FLASH_STATUS_REG.{/p}{/li} // {p}{li}Initiate the erase operation by setting // @.FLASH_ERASE_SECTOR and strobing FLASH_ERASE_STB of // FLASH_CONTROL_REG.{/p}{/li} // {p}{li}Poll the FLASH_ERASE_IDLE bit of // FLASH_STATUS_REG until it de-asserts indicating the // erase operation is complete, then verify the operation // was successful by checking that the FLASH_ERASE_ERR // bit is de-asserted. Erase operations are expected to // take a maximum of 350 msec. Upon completion of the erase // operation write protection will remain disabled. // {/p}{/li} // {p}{li}Erase additional sectors as required (see // @.FLASH_ERASE_SECTOR for details) by restarting with first // step.{/p}{/li} // {/ol} // {/p} // {p}{b}Write the new primary flash image...{/b} // {ol}{p}{li}Read FLASH_STATUS_REG and verify no error bits are // asserted, all read, write, and erase operations are // idle, and write protection is disabled.{/li} // {p}{li}Set the target address for the write to the Max 10 // on-chip flash by writing value from // FLASH_CFM0_START_ADDR_REG to FLASH_ADDR_REG.{/li}{/p} // {p}{li}Set the data to be written to this address by writing // the new 32-bit word of the new image to // FLASH_WRITE_DATA_REG.{/li}{/p} // {p}{li}Initiate the write by strobing FLASH_WRITE_STB of // FLASH_CONTROL_REG.{/li}{/p} // {p}{li}Poll the FLASH_WRITE_IDLE bit of // FLASH_STATUS_REG until it de-asserts indicating the // write operation is complete, then verify the operation // was successful by checking that the FLASH_WRITE_ERR // bit is de-asserted. Write operations are expected to // take a maximum of 550 usec.{/li}{/p} // {p}{li}Upon completion of the write operation return to step // 2, incrementing the target address by one, and writing // the next 32-bit word to Max10FlashWriteDatReg. If this // was the last write, indicated by writing to // FLASH_PRIMARY_IMAGE_END_ADDR, proceed to the next step // to enable write protection.{/li}{/p} // {p}{li}After writing the new image enable write protection // by strobing the FLASH_ENABLE_WP_STB bit of // FLASH_CONTROL_REG.{/li}{/p} // {/ol} // {/p} // {p}{b}Verify the new primary flash image...{/b} // {ol}{p}{li}Read FLASH_STATUS_REG and verify no error bits are // asserted and that all read, write, and erase operations // are idle.{/li}{/p} // {p}{li}Set the target address for the read in the Max 10 // on-chip flash by writing value from // FLASH_CFM0_START_ADDR_REG to FLASH_ADDR_REG.{/li}{/p} // {p}{li}Initiate the read by strobing FLASH_READ_STB of // FLASH_CONTROL_REG.{/li}{/p} // {p}{li}Poll the FLASH_READ_IDLE bit of // FLASH_STATUS_REG until it de-asserts indicating the // read operation is complete, then verify the operation // was successful by checking that the FLASH_READ_ERR // bit is de-asserted. There is no guidance on exactly how // long reads take to complete, but they are expected to be // fairly quick. A very conservative timeout on this // polling would be similar to that used for write // operations.{/li}{/p} // {p}{li}Upon completion of the read operation the resulting // data returned by the on-chip flash will be available in // Max10FlashReadDatReg. Read this register, compare to // expected value previously written, and ensure they // match.{/li}{/p} // {p}{li}Return to step 2, incrementing the target // address by one. If this was the last read verification // is complete and no further action is required.{/li}{/p} // {/ol} // {/p} // {p}After the flash has been erased, programmed, and verified, a power // cycle is required for the new image to become active. // {/p} // // // // These values are the start and end address of the CFM image flash // sector from Intel's On-Chip Flash IP Generator. // Be aware that three different values exist per each of the two // supported MAX10 variants: 10M04 and 10M08 // Note that the values given in the IP generator are byte based where // the values of this enum are U32 based (divided by 4). // // // // // // // // // // // // // This bit is asserted when the flash is write protected and // de-asserted when write protection is disabled. // {li}Write protection must be enabled prior to performing read // operations.{/li} // {li}Write protection must be disabled prior to performing write and // erase operations.{/li} // // // // // This bit is de-asserted when a read operation is in progress. Poll // this bit after strobing the FLASH_READ_STB bit of // FLASH_CONTROL_REG to determine when the read operation has // completed, then check the FLASH_READ_ERR bit to verify the // operation was successful. // // // // // This bit is asserted when a read operation fails. Clear this error // by strobing the CLEAR_FLASH_READ_ERROR_STB of this register. In the // event of a read error... // {li}the data in FLASH_READ_DATA_REG is invalid.{/li} // {li}attempts to disable write protection will be ignored.{/li} // {li}attempts to read/write/erase the flash will be ignored.{/li} // // // // // This bit is de-asserted when an erase operation is in progress. Poll // this bit after strobing the FLASH_ERASE_STB bit of // FLASH_CONTROL_REG to determine when the erase operation has // completed, then check the FLASH_ERASE_ERR bit to verify the // operation was successful. // // // // // This bit is asserted when an erase operation fails. Clear this // error by strobing CLEAR_FLASH_ERASE_ERROR_STB of this register. In // the event of an erase error... // {li}{b}the primary configuration image may be corrupted,{/b} and // power cycling the board may result in unknown behavior.{/li} // {li}write protection of the flash will automatically be // re-enabled.{/li} // {li}attempts to disable write protection will be ignored.{/li} // {li}attempts to read/write/erase the flash will be ignored.{/li} // // // // // This bit is de-asserted when a write operation is in progress. Poll // this bit after strobing the FLASH_WRITE_STB bit of // FLASH_CONTROL_REG to determine when the write operation has // completed, then check the FLASH_WRITE_ERR bit to verify the // operation was successful. // // // // // This bit is asserted when write operation fails. Clear this error // by strobing the CLEAR_FLASH_WRITE_ERROR_STB bit of this register. In // the event of a write error... // {li}{b}the primary configuration image may be corrupted,{/b} and // power cycling the board may result unknown behavior.{/li} // {li}write protection of the flash will automatically be // re-enabled.{/li} // {li}attempts to disable write protection will be ignored.{/li} // {li}attempts to read/write/erase the flash will be ignored.{/li} // // // // // This bit is asserted when the flash can hold an image with memory // initialization. // // // // // // // Strobe this bit to enable write protection to the section of the // Max 10 on-chip flash storing the primary configuration image // (CFM0). // {li}Read the FLASH_WP_ENABLED bit of FLASH_STATUS_REG to // determine the current state of write protection.{/li} // {li}Prior to strobing this bit verify no write or erase operations // are in progress and no error bits are asserted by reading // FLASH_STATUS_REG.{/li} // {li}Attempts to enable write protection while erase or write // operations are in progress will be ignored.{/li} // {li}Write protection must be enabled prior to performing // read operations.{/li} // {li}Write protection should be enabled after completing // write or erase operations to prevent data corruption.{/li} // // // // // Strobe this bit to disable write protection to the section of the // Max 10 on-chip flash storing the primary configuration image // (CFM0). // {li}Read the FLASH_WP_ENABLED bit of FLASH_STATUS_REG to // determine the current state of write protection.{/li} // {li}Prior to strobing this bit verify no read operations are in // progress and no error bits are asserted by reading // FLASH_STATUS_REG.{/li} // {li}Attempts to disable write protection while a read is in // progress will be ignored.{/li} // {li}Attempts to disable write protection will be ignored if // this bit is strobed simultaneously with either FLASH_READ_STB // or FLASH_ENABLE_WP_STB.{/li} // {li}Write protection must be disabled prior to performing erase or // write operations.{/li} // {li}Upon completion of erase/write operations write protection // will remain disabled. When not actively erasing or writing a new // image write protection should be enabled to avoid data // corruption.{/li} // // // // // Strobe this bit to read data from the flash address identified in // FLASH_ADDR_REG. // {li}Prior to strobing this bit verify no read, write, or erase // operations are in progress, no error bits are asserted, and // write protection is enabled by reading FLASH_STATUS_REG.{/li} // {li}Attempts to read data while other operations are in progress // or while write protection is disabled will be ignored.{/li} // {li}After strobing this bit poll the FLASH_READ_IDLE and // FLASH_READ_ERR bits of FLASH_STATUS_REG to determine when // the read operation is complete and if it was successful.{/li} // {li}Upon successful completion the data read from flash will be // available in FLASH_READ_DATA_REG.{/li} // // // // // Strobe this bit to write the data contained in // FLASH_WRITE_DATA_REG to the flash address identified in // FLASH_ADDR_REG. // {li}The flash must be erased before writing new data.{/li} // {li}Prior to strobing this bit verify write protection is // disabled, no other write or erase operations are in progress, and // no error bits are asserted by reading FLASH_STATUS_REG.{/li} // {li}Attempts to write data while other write or erase operations // are in progress will be ignored.{/li} // {li}Attempts to write data with write protection enabled will be // ignored.{/li} // {li}Strobing this bit and FLASH_ERASE_STB simultaneously will // result in both the write and erase operation being ignored, // both corresponding error bits being set, and write protection // being re-enabled.{/li} // {li}After strobing this bit poll theMax10FlashWriteIdle and // FLASH_WRITE_ERR bits of FLASH_STATUS_REG to determine when // the write operation is complete and if it was successful.{/li} // // // // // Strobe this bit to erase the primary Max10 configuration image // (CFM0). // {li}Prior to strobing this bit verify no other write or erase // operations are in progress, write protection is disabled, and no // error bits are asserted by reading FLASH_STATUS_REG.{/li} // {li}Attempts to erase the primary image while other write or erase // operations are in progress will be ignored. // {li}Attempts to erase the primary image when write protection is // enabled will be ignored.{/li} // {li}Strobing this bit and FLASH_WRITE_STB simultaneously will // result both the erase and the write operation being ignored, both // corresponding error bits being set, and write protection being // re-enabled.{/li} // {li}After strobing this bit poll the FLASH_ERASE_IDLE and // FLASH_ERASE_ERR bits of FLASH_STATUS_REG to determine when // the erase operation is complete and if it was successful.{/li} // // // // // Defines the sector to be erased. Has to be set latest with the // write access which starts the erase operation by strobing // @.FLASH_ERASE_STB.{br} // With 10M04 variants, if the flash is configured to support memory // initialization (see @.FLASH_MEM_INIT_ENABLED flag) the sectors 2 // to 4 have to be erased. If the flag is not asserted only sector 4 // has to be erased. // With 10M08 variants, the sectors to be erased are 3 to 5 when // using memory initialization or only sector 5 otherwise. // // // // // Strobe this bit to clear a read error. // // // // // Strobe this bit to clear a write error. // // // // // Strobe this bit to clear an erase error. // // // // // // // This field holds the target address for the next read or // write operation. Set this field prior to strobing the // FLASH_WRITE_STB and FLASH_READ_STB bits of // FLASH_CONTROL_REG. Valid addresses are defined by the // FLASH_PRIMARY_IMAGE_ADDR_ENUM enumeration. // // // // // // // Data in this register will be written to the flash at the address // identified in FLASH_ADDR_REG when a successful write operation // is executed. // // // // // // // This register contains data read from the flash address identified // in FLASH_ADDR_REG after a successful read operation is executed. // // // // // // // Start address of CFM0 image within flash memory (as defined in FLASH_PRIMARY_IMAGE_ADDR_ENUM). // // // // // // // Last address of CFM0 image within flash memory (as defined in FLASH_PRIMARY_IMAGE_ADDR_ENUM). // // // // // //XmlParse xml_off