diff --git a/picosoc/Makefile b/picosoc/Makefile index 1a6ac94..decf97a 100644 --- a/picosoc/Makefile +++ b/picosoc/Makefile @@ -53,7 +53,7 @@ firmware.elf: sections.lds start.s firmware.c riscv32-unknown-elf-gcc -Wl,-Bstatic,-T,sections.lds,--strip-debug -ffreestanding -nostdlib -o firmware.elf start.s firmware.c firmware.hex: firmware.elf - riscv32-unknown-elf-objcopy -O verilog firmware.elf /dev/stdout | sed -e '2,65537 d;' > firmware.hex + riscv32-unknown-elf-objcopy -O verilog firmware.elf /dev/stdout | sed -e '1 s/@00000000/@00100000/; 2,65537 d;' > firmware.hex firmware.bin: firmware.elf riscv32-unknown-elf-objcopy -O binary firmware.elf /dev/stdout | tail -c +1048577 > firmware.bin diff --git a/picosoc/README.md b/picosoc/README.md index 2fd558c..b3db5e7 100644 --- a/picosoc/README.md +++ b/picosoc/README.md @@ -38,8 +38,8 @@ and upload them to a connected iCE40-HX8K Breakout Board. | 0x02000008 .. 0x0200000B | UART Send/Recv Data Register | | 0x03000000 .. 0xFFFFFFFF | Memory mapped user peripherals | -The addresses in the internal SRAM region beyond the end of the physical -SRAM map to the corresponding addresses in serial flash. +Reading from the addresses in the internal SRAM region beyond the end of the +physical SRAM will read from the corresponding addresses in serial flash. Reading from the UART Send/Recv Data Register will return the last received byte, or -1 (all 32 bits set) when the receive buffer is empty. @@ -52,15 +52,15 @@ GPIO pins mapped to the 32 bit word at address 0x03000000. | Bit(s) | Description | | -----: | --------------------------------------------------------- | | 31 | MEMIO Enable (reset=1, set to 0 to bit bang SPI commands) | -| 30:20 | Reserved (read 0) | -| 19:16 | IO Output enable bits in bit bang mode | -| 15:14 | Reserved (read 0) | -| 13 | Chip select (CS) line in bit bang mode | -| 12 | Serial clock line in bit bang mode | -| 11:8 | IO data bits in bit bang mode | -| 7 | Reserved (read 0) | -| 6 | DDR Enable bit (reset=0) | -| 5 | QSPI Enable bit (reset=0) | -| 4 | Continous Read Enable bit (reset=0) | -| 3:0 | Number of QSPI dummy cycles (reset=0) | +| 30:23 | Reserved (read 0) | +| 22 | DDR Enable bit (reset=0) | +| 21 | QSPI Enable bit (reset=0) | +| 20 | Continous Read Enable bit (reset=0) | +| 19:16 | Number of QSPI dummy cycles (reset=0) | +| 15:12 | Reserved (read 0) | +| 11:8 | IO Output enable bits in bit bang mode | +| 7:6 | Reserved (read 0) | +| 5 | Chip select (CS) line in bit bang mode | +| 4 | Serial clock line in bit bang mode | +| 3:0 | IO data bits in bit bang mode | diff --git a/picosoc/firmware.c b/picosoc/firmware.c index ce766fc..57d0ece 100644 --- a/picosoc/firmware.c +++ b/picosoc/firmware.c @@ -9,12 +9,26 @@ extern uint32_t sram; #define reg_uart_data (*(volatile uint32_t*)0x02000008) #define reg_leds (*(volatile uint32_t*)0x03000000) +void putchar(char c) +{ + if (c == '\n') + putchar('\r'); + reg_uart_data = c; +} + void print(const char *p) { - while (*p) { - if (*p == '\n') - reg_uart_data = '\r'; - reg_uart_data = *(p++); + while (*p) + putchar(*(p++)); +} + +void print_hex(uint32_t v, int digits) +{ + for (int i = 7; i >= 0; i--) { + char c = "0123456789abcdef"[(v >> (4*i)) & 15]; + if (c == '0' && i >= digits) continue; + putchar(c); + digits = i; } } @@ -63,6 +77,12 @@ void cmd_read_spi_flash_id() *(dst_ptr++) = *(src_ptr++); ((void(*)())&sram)(); + + for (int i = 0; i < 16; i++) { + putchar(' '); + print_hex(((uint8_t*)&sram)[i], 2); + } + putchar('\n'); } // -------------------------------------------------------- @@ -93,7 +113,7 @@ void main() print("Command> "); char cmd = getchar(); if (cmd > 32 && cmd < 127) - reg_uart_data = cmd; + putchar(cmd); print("\n"); switch (cmd) diff --git a/picosoc/spimemio.v b/picosoc/spimemio.v index c7d8cb6..f6b3e0d 100644 --- a/picosoc/spimemio.v +++ b/picosoc/spimemio.v @@ -74,27 +74,27 @@ module spimemio ( reg softreset; reg config_en; // cfgreg[31] - reg [3:0] config_oe; // cfgreg[19:16] - reg config_csb; // cfgreg[13] - reg config_clk; // cfgref[12] - reg [3:0] config_do; // cfgreg[11:8] - reg config_ddr; // cfgreg[6] - reg config_qspi; // cfgreg[5] - reg config_cont; // cfgreg[4] - reg [3:0] config_dummy; // cfgreg[3:0] + reg config_ddr; // cfgreg[22] + reg config_qspi; // cfgreg[21] + reg config_cont; // cfgreg[20] + reg [3:0] config_dummy; // cfgreg[19:16] + reg [3:0] config_oe; // cfgreg[11:8] + reg config_csb; // cfgreg[5] + reg config_clk; // cfgref[4] + reg [3:0] config_do; // cfgreg[3:0] assign cfgreg_do[31] = config_en; - assign cfgreg_do[30:20] = 0; - assign cfgreg_do[19:16] = {flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}; - assign cfgreg_do[15:14] = 0; - assign cfgreg_do[13] = flash_csb; - assign cfgreg_do[12] = flash_clk; - assign cfgreg_do[11:8] = {flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; - assign cfgreg_do[7] = 0; - assign cfgreg_do[6] = config_ddr; - assign cfgreg_do[5] = config_qspi; - assign cfgreg_do[4] = config_cont; - assign cfgreg_do[3:0] = config_dummy; + assign cfgreg_do[30:23] = 0; + assign cfgreg_do[22] = config_ddr; + assign cfgreg_do[21] = config_qspi; + assign cfgreg_do[20] = config_cont; + assign cfgreg_do[19:16] = config_dummy; + assign cfgreg_do[15:12] = 0; + assign cfgreg_do[11:8] = {flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}; + assign cfgreg_do[7:6] = 0; + assign cfgreg_do[5] = flash_csb; + assign cfgreg_do[4] = flash_clk; + assign cfgreg_do[3:0] = {flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; always @(posedge clk) begin softreset <= !config_en || cfgreg_we; @@ -111,18 +111,18 @@ module spimemio ( config_dummy <= 0; end else begin if (cfgreg_we[0]) begin - config_ddr <= cfgreg_di[6]; - config_qspi <= cfgreg_di[5]; - config_cont <= cfgreg_di[4]; - config_dummy <= cfgreg_di[3:0]; + config_csb <= cfgreg_di[5]; + config_clk <= cfgreg_di[4]; + config_do <= cfgreg_di[3:0]; end if (cfgreg_we[1]) begin - config_csb <= cfgreg_di[13]; - config_clk <= cfgreg_di[12]; - config_do <= cfgreg_di[11:8]; + config_oe <= cfgreg_di[11:8]; end if (cfgreg_we[2]) begin - config_oe <= cfgreg_di[19:16]; + config_ddr <= cfgreg_di[22]; + config_qspi <= cfgreg_di[21]; + config_cont <= cfgreg_di[20]; + config_dummy <= cfgreg_di[19:16]; end if (cfgreg_we[3]) begin config_en <= cfgreg_di[31]; @@ -130,6 +130,9 @@ module spimemio ( end end + wire xfer_csb; + wire xfer_clk; + wire xfer_io0_oe; wire xfer_io1_oe; wire xfer_io2_oe; @@ -140,6 +143,9 @@ module spimemio ( wire xfer_io2_do; wire xfer_io3_do; + assign flash_csb = config_en ? xfer_csb : config_csb; + assign flash_clk = config_en ? xfer_clk : config_clk; + assign flash_io0_oe = config_en ? xfer_io0_oe : config_oe[0]; assign flash_io1_oe = config_en ? xfer_io1_oe : config_oe[1]; assign flash_io2_oe = config_en ? xfer_io2_oe : config_oe[2]; @@ -164,16 +170,16 @@ module spimemio ( .dout_valid (dout_valid ), .dout_data (dout_data ), .dout_tag (dout_tag ), - .flash_csb (flash_csb ), - .flash_clk (flash_clk ), - .flash_io0_oe (xfer_io0_oe), - .flash_io1_oe (xfer_io1_oe), - .flash_io2_oe (xfer_io2_oe), - .flash_io3_oe (xfer_io3_oe), - .flash_io0_do (xfer_io0_do), - .flash_io1_do (xfer_io1_do), - .flash_io2_do (xfer_io2_do), - .flash_io3_do (xfer_io3_do), + .flash_csb (xfer_csb ), + .flash_clk (xfer_clk ), + .flash_io0_oe (xfer_io0_oe ), + .flash_io1_oe (xfer_io1_oe ), + .flash_io2_oe (xfer_io2_oe ), + .flash_io3_oe (xfer_io3_oe ), + .flash_io0_do (xfer_io0_do ), + .flash_io1_do (xfer_io1_do ), + .flash_io2_do (xfer_io2_do ), + .flash_io3_do (xfer_io3_do ), .flash_io0_di (flash_io0_di), .flash_io1_di (flash_io1_di), .flash_io2_di (flash_io2_di), diff --git a/picosoc/start.s b/picosoc/start.s index 47312d8..b0c1c70 100644 --- a/picosoc/start.s +++ b/picosoc/start.s @@ -35,27 +35,67 @@ addi x31, zero, 0 li sp, 4*256 call main -j start + +loop: +j loop .global cmd_read_spi_flash_id_worker_begin .global cmd_read_spi_flash_id_worker_end cmd_read_spi_flash_id_worker_begin: -li t0,0x02000008 -li t1,'F' -sw t1,0(t0) -li t1,'I' -sw t1,0(t0) -li t1,'X' -sw t1,0(t0) -li t1,'M' -sw t1,0(t0) -li t1,'E' -sw t1,0(t0) -li t1,'\r' -sw t1,0(t0) -li t1,'\n' -sw t1,0(t0) + +# address of SPI ctrl reg +li t0, 0x02000000 + +# Manual Ctrl +li t1, 0x00 +sb t1, 3(t0) + +# CS high, IO0 is output +li t1, 0x120 +sh t1, 0(t0) + +# CS low +sb zero, 0(t0) + +# Send 0x9F (EDEC-ID Read) +li t2, 0x9F +li t3, 8 +cmd_read_spi_flash_id_worker_L1: +srli t4, t2, 7 +andi t4, t4, 0x01 +sb t4, 0(t0) +ori t4, t4, 0x10 +slli t2, t2, 1 +addi t3, t3, -1 +sb t4, 0(t0) +bnez t3, cmd_read_spi_flash_id_worker_L1 + +# Read 16 bytes and store in zero page +li t3, 0 +li a2, 16 +cmd_read_spi_flash_id_worker_L2: +li a0, 8 +li a1, 0 +cmd_read_spi_flash_id_worker_L3: +sb zero, 0(t0) +li t4, 0x10 +sb t4, 0(t0) +lb t4, 0(t0) +andi t4, t4, 2 +srli t4, t4, 1 +slli a1, a1, 1 +or a1, a1, t4 +addi a0, a0, -1 +bnez a0, cmd_read_spi_flash_id_worker_L3 +sb a1, 0(t3) +addi t3, t3, 1 +bne t3, a2, cmd_read_spi_flash_id_worker_L2 + +# back to MEMIO mode +li t1, 0x80 +sb t1, 3(t0) + ret cmd_read_spi_flash_id_worker_end: