diff options
Diffstat (limited to 'fpga/usrp3/top/x400/cpld/reconfig_engine.v')
-rw-r--r-- | fpga/usrp3/top/x400/cpld/reconfig_engine.v | 1024 |
1 files changed, 1024 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/cpld/reconfig_engine.v b/fpga/usrp3/top/x400/cpld/reconfig_engine.v new file mode 100644 index 000000000..a7c94b4a2 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/reconfig_engine.v @@ -0,0 +1,1024 @@ +// +// 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" + + //---------------------------------------------------------- + // 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; + localparam CFM0_WP_OFFSET_MSB = 26; + localparam CFM0_WP_OFFSET_LSB = 24; + 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 +//<regmap name="RECONFIG_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true"> +// <group name="RECONFIG_REGS"> +// <info> +// 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} +// </info> +// <enumeratedtype name="FLASH_PRIMARY_IMAGE_ADDR_ENUM" showhexvalue="true"> +// <info> +// Those values are the start and end address of the CFM image flash +// sector from Intel's On-Chip Flash IP Generator. Note that the values +// given in the IP generator are byte based where the values of this enum +// are U32 based (divided by 4). +// </info> +// <value name="FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT" +// integer="4096"/> +// <value name="FLASH_PRIMARY_IMAGE_START_ADDR" +// integer="39936"/> +// <value name="FLASH_PRIMARY_IMAGE_END_ADDR" +// integer="75775"/> +// </enumeratedtype> +// <register name="FLASH_STATUS_REG" offset="0x000" size="32" +// attributes="Readable"> +// <bitfield name="FLASH_WP_ENABLED" range="0"> +// <info> +// 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} +// </info> +// </bitfield> +// <bitfield name="FLASH_READ_IDLE" range="4"> +// <info> +// 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. +// </info> +// </bitfield> +// <bitfield name="FLASH_READ_ERR" range="5"> +// <info> +// 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} +// </info> +// </bitfield> +// <bitfield name="FLASH_ERASE_IDLE" range="8"> +// <info> +// 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. +// </info> +// </bitfield> +// <bitfield name="FLASH_ERASE_ERR" range="9"> +// <info> +// 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} +// </info> +// </bitfield> +// <bitfield name="FLASH_WRITE_IDLE" range="12"> +// <info> +// 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. +// </info> +// </bitfield> +// <bitfield name="FLASH_WRITE_ERR" range="13"> +// <info> +// 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} +// </info> +// </bitfield> +// <bitfield name="FLASH_MEM_INIT_ENABLED" range="16"> +// <info> +// This bit is asserted when the flash can hold an image with memory +// initialization. +// </info> +// </bitfield> +// </register> +// <register name="FLASH_CONTROL_REG" offset="0x04" size="32" +// attributes="Writable"> +// <bitfield name="FLASH_ENABLE_WP_STB" range="0" +// attributes="strobe"> +// <info> +// 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} +// </info> +// </bitfield> +// <bitfield name="FLASH_DISABLE_WP_STB" range="1" +// attributes="strobe"> +// <info> +// 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} +// </info> +// </bitfield> +// <bitfield name="FLASH_READ_STB" range="2" +// attributes="strobe"> +// <info> +// 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} +// </info> +// </bitfield> +// <bitfield name="FLASH_WRITE_STB" range="3" +// attributes="strobe"> +// <info> +// 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} +// </info> +// </bitfield> +// <bitfield name="FLASH_ERASE_STB" range="4" +// attributes="strobe"> +// <info> +// 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} +// </info> +// </bitfield> +// <bitfield name="FLASH_ERASE_SECTOR" range="7..5" +// attributes="strobe"> +// <info> +// 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} +// 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. +// </info> +// </bitfield> +// <bitfield name="CLEAR_FLASH_READ_ERROR_STB" range="8" +// attributes="strobe"> +// <info> +// Strobe this bit to clear a read error. +// </info> +// </bitfield> +// <bitfield name="CLEAR_FLASH_WRITE_ERROR_STB" range="9" +// attributes="strobe"> +// <info> +// Strobe this bit to clear a write error. +// </info> +// </bitfield> +// <bitfield name="CLEAR_FLASH_ERASE_ERROR_STB" range="10" +// attributes="strobe"> +// <info> +// Strobe this bit to clear an erase error. +// </info> +// </bitfield> +// </register> +// <register name="FLASH_ADDR_REG" offset="0x08" size="32" +// attributes="Readable|Writable"> +// <bitfield name="FLASH_ADDR" range="16..0"> +// <info> +// 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. +// </info> +// </bitfield> +// </register> +// <register name="FLASH_WRITE_DATA_REG" offset="0x0C" size="32" +// attributes="Writable"> +// <bitfield name="FLASH_WRITE_DATA" range="31..0"> +// <info> +// 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. +// </info> +// </bitfield> +// </register> +// <register name="FLASH_READ_DATA_REG" offset="0x10" size="32" +// attributes="Readable"> +// <bitfield name="FLASH_READ_DATA" range="31..0"> +// <info> +// This register contains data read from the flash address identified +// in FLASH_ADDR_REG after a successful read operation is executed. +// </info> +// </bitfield> +// </register> +// <register name="FLASH_CFM0_START_ADDR_REG" offset="0x14" size="32" +// attributes="Readable"> +// <bitfield name="FLASH_CFM0_START_ADDR" range="31..0"> +// <info> +// Start address of CFM0 image within flash memory (as defined in FLASH_PRIMARY_IMAGE_ADDR_ENUM). +// </info> +// </bitfield> +// </register> +// <register name="FLASH_CFM0_END_ADDR_REG" offset="0x18" size="32" +// attributes="Readable"> +// <bitfield name="FLASH_CFM0_END_ADDR" range="31..0"> +// <info> +// Last address of CFM0 image within flash memory (as defined in FLASH_PRIMARY_IMAGE_ADDR_ENUM). +// </info> +// </bitfield> +// </register> +// </group> +//</regmap> +//XmlParse xml_off |