iCE40 USB Trace memory map ========================== Global ------ | Base | Peripheral | Notes |--------------|--------------------|----------------------------------------- | `0x80000000` | Misc | [See below for registers](#misc-peripherals) | `0x81000000` | UART | [See `no2uart` doc](../cores/no2misc/doc/uart_wb.md) | `0x82000000` | RGB Led | [See `no2ice40/ice40_rgb_wb` doc](../cores/no2ice40/doc/ice40_rgb_wb.md) | `0x83000000` | QPI controller | `no2qpimem` but no docs :( | `0x84000000` | USB Device Data | [See below for details](#usb-device-data) | `0x85000000` | USB Device Control | [See `no2usb` doc](../cores/no2usb/doc/mem-map.md) | `0x86000000` | USB DUT Tap | [See below for details](#usb-dut-tap) Misc peripherals ---------------- #### Boot request (Write Only, addr `0x00`) ```text ,-----------------------------------------------------------------------------------------------, |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| |-----------------------------------------------------------------------------------------------| | / |bn| bsel| '-----------------------------------------------------------------------------------------------' * [2] - bn : Boot Now * [1:0] - bsel : Boot select ``` Writing to this register with `bn` set to `1` will trigger a warm reconfiguration to boot image `bsel`. Classic image map for the target platform is : * Image 0 : Boot Stub (i.e. cold boot) * Image 1 : DFU Boot Loader * Image 2 : Main application * Image 3 : n/a USB Device Data --------------- This is subdivided in two zones : * `0x00000 - 0x007ff` : 2k+2k USB RX/TX buffers * `0x10000 - 0x1ffff` : 64k of SRAM The USB buffers for TX and RX are separate but accesses through the same address range. Writes go to the TX buffers and Reads come from the RX buffers. Note that write access should always be done on full aligned words ! The extra 64k of SRAM mapped in this area has a slightly longer access time that the main SRAM zone, but is DMA-capable. Although not used by the firmware in normal operation, it could be used for debug to be able to inspect the external PSRAM content. ( Normally the external PSRAM can only be read by DMA to the USB TX buffers and those can't be read by the SoC ) USB DUT Tap ----------- The USB sniffer peripheral is sub-decomposed in three parts operating concurrently : * The capture engine: It listens to the USB lines, decodes packet and generates a continuous byte streams of the events as described in the "protocol" documentation. * The DMA write engine: This takes the byte stream from the capture engine, slices it into chunks and copies them to external PSRAM * The DMA read engine: This can copy, on request, data from the external PSRAM to the USB transmit buffers. Note that although the DMA write/read engine could technically write/read data in any pattern in the external PSRAM as controller by the SoC, the firmware implements the whole memory as a giant circular buffer. ### Capture [ `0x00` - `0x0f` ] #### CSR (Read/Write, addr `0x00`) ```text ,-----------------------------------------------------------------------------------------------, |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| |-----------------------------------------------------------------------------------------------| | / |en| '-----------------------------------------------------------------------------------------------' * [0] - en : Enable ``` Only a single bit control enabling / disabling the capture. Note that disabling is not "instant", it will finish the current packet if one is in progress so that the generated byte stream is always valid and not cut in the middle. ### DMA write [ `0x20` - `0x2f` ] The DMA writer block has an input FIFO in internal SRAM and when that FIFO reaches a sufficient level, it can read from it and copy data to external PSRAM. This is controlled by DMA descriptors submitted by the SoC. Each descriptor has the burst lenght and the destination address. Once a transfer is done the descriptor is moved to the "complete" queue where the SoC can retrieve it to know that the transfer has been done and the PSRAM has been filled with valid data. By default the transfer will not occur if the input FIFO level is too low to fill the entire descriptor. To still allow to completely flush the input FIFO, a 'flush' mode can be enabled in which the copy will be allowed even if less bytes are available. #### CSR (Read/Write, addr `0x00`) ```text ,-----------------------------------------------------------------------------------------------, |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| |-----------------------------------------------------------------------------------------------| |do| |df|de| lvl |io|iu|if|ie|oo| |of|oe| / |fi|ad|fm|en| '-----------------------------------------------------------------------------------------------' * [31] - do : Data FIFO Overflow (write 1 to clear) * [29] - df : Data FIFO Full * [28] - de : Data FIFO Empty * [27:16] - lvl : Data FIFO level * [15] - ie : Desc In FIFO Overflow (write 1 to clear) * [14] - iu : Desc In FIFO Underflow (write 1 to clear) * [13] - if : Desc In FIFO Full * [12] - ie : Desc In FIFO Empty * [11] - oo : Desc Out FIFO Overflow (write 1 to clear) * [9] - of : Desc Out FIFO Full * [8] - oe : Desc Out FIFO Empty * [3] - fi : Flush Desc In FIFO * [2] - ad : Auto disable on overflow * [1] - fm : Flush mode * [0] - en : Enable/Enabled ``` Note that underflow of the descriptor input FIFO means that there was some data in the input data FIFO and we didn't have any ready descriptor to write that data to external PSRAM. It is not a fault in itself, just a performance warning. If that condition is fixed quick enough, all will be fine. If not, then the Data FIFO will overflow and this is an error as the stream will be corrupted. In that case, there is the "Auto disable on overflow" option that will halt the core automatically since anyway the stream is corrupted and the only recovery possible is to halt everything, flush everything and start over. #### Descriptor Submit (Write Only, addr `0x08`) ```text ,-----------------------------------------------------------------------------------------------, |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| |-----------------------------------------------------------------------------------------------| |//| len | addr | '-----------------------------------------------------------------------------------------------' * [30:24] - len : Length of transfer (in bytes, minus one) * [23: 0] - addr : Destination byte address in external PSRAM ``` Note that length is limited to 128 bytes for now. #### Descriptor Complete (Read Only, addr `0x0c`) ```text ,-----------------------------------------------------------------------------------------------, |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| |-----------------------------------------------------------------------------------------------| |iv| len | addr | '-----------------------------------------------------------------------------------------------' * [31] - iv : Invalid fag. If set, no descriptors are complete * [30:24] - len : Length of transfer (in bytes, minus one) * [23: 0] - addr : Destination byte address in external PSRAM ``` ### DMA read [ `0x30` - `0x3f` ] The DMA reader can only process one command at a time. It copies full 32b words data from any byte address of the external PSRAM (no alignement requirements) to any word aligned address in the [USB Device Data zone](#usb-dev-data). #### Status (Read Only, addr `0x00`) ```text ,-----------------------------------------------------------------------------------------------, |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| |-----------------------------------------------------------------------------------------------| | / |by| '-----------------------------------------------------------------------------------------------' * [0] - by : Busy ``` #### Command Hi-word (Write Only, addr `0x08`) ```text ,-----------------------------------------------------------------------------------------------, |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| |-----------------------------------------------------------------------------------------------| | / | eaddr | '-----------------------------------------------------------------------------------------------' * [23:0] - eaddr : External address (byte address) ``` #### Command Lo-word (Write Only, addr `0x0c`) ```text ,-----------------------------------------------------------------------------------------------, |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| |-----------------------------------------------------------------------------------------------| | / | len | iaddr | '-----------------------------------------------------------------------------------------------' * [23:16] - len : Length in words - 1 * [15: 0] - iaddr : Internal address (word address) ``` Writes to this register also trigger the start of the command.