XIP on Murax improvements

This commit is contained in:
sebastien-riou 2020-01-12 16:08:14 +01:00
parent b290b25f7a
commit b866dcb07f
10 changed files with 373 additions and 65 deletions

View File

@ -1,19 +1,21 @@
VBASE = ../../..
VNAME = Murax_iCE40_hx8k_breakout_board_xip
VERILOG = ${VBASE}/${VNAME}.v
VERILOG = ../../../Murax_iCE40_hx8k_breakout_board_xip.v
all: prog
generate :
#(cd ../../..; sbt "runMain vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip")
${VERILOG} :
(cd ${VBASE}; sbt "runMain vexriscv.demo.${VNAME}")
../../../Murax_iCE40_hx8k_breakout_board_xip.v :
#(cd ../../..; sbt "runMain vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip")
generate : ${VERILOG}
../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin:
${VERILOG}*.bin:
bin/Murax_iCE40_hx8k_breakout_board_xip.blif : ${VERILOG} ../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin
bin/Murax_iCE40_hx8k_breakout_board_xip.blif : ${VERILOG} ${VERILOG}*.bin
mkdir -p bin
rm -f Murax_iCE40_hx8k_breakout_board_xip.v*.bin
cp ../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin . | true
cp ${VERILOG}*.bin . | true
yosys -v3 -p "synth_ice40 -top Murax_iCE40_hx8k_breakout_board_xip -blif bin/Murax_iCE40_hx8k_breakout_board_xip.blif" ${VERILOG}
bin/Murax_iCE40_hx8k_breakout_board_xip.asc : Murax_iCE40_hx8k_breakout_board_xip.pcf bin/Murax_iCE40_hx8k_breakout_board_xip.blif
@ -28,11 +30,15 @@ time: bin/Murax_iCE40_hx8k_breakout_board_xip.bin
icetime -tmd hx8k bin/Murax_iCE40_hx8k_breakout_board_xip.asc
prog : bin/Murax_iCE40_hx8k_breakout_board_xip.bin
lsusb -d 0403:6010
iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin
sudo-prog : bin/Murax_iCE40_hx8k_breakout_board_xip.bin
sudo lsusb -d 0403:6010
sudo iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin
clean :
rm -rf bin
rm -f Murax_iCE40_hx8k_breakout_board_xip.v*.bin
rm -f ${VERILOG}*.bin
rm -f ${VERILOG}

View File

@ -59,12 +59,29 @@ The process should take around 30 seconds on a reasonable fast computer.
## Programming
Make sure the FPGA board is the only USB peripheral with ID 0403:6010
For example, this is bad:
```
user@lafite:~$ lsusb -d 0403:6010
Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
Bus 001 Device 090: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
```
This is good:
```
user@lafite:~$ lsusb -d 0403:6010
Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
```
After building you should be able to run `make prog`. You may need to run `make
sudo-prog` if root is needed to access your USB devices.
You should get output like the following;
```
iceprog -S bin/toplevel.bin
lsusb -d 0403:6010
Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin
init..
cdone: high
reset..
@ -74,13 +91,115 @@ cdone: high
Bye.
```
After programming the LEDs at the top of the board should start flashing in an
interesting pattern.
WARNING: having this output does NOT guarantee you actually programmed anything in the FPGA!
## Connect
After programming nothing visual will happen, except the LEDs being off.
The bootloader is waiting for a valid content in the flash. "valid content" is
identified by a magic word at 0xE0040000: it shall be 0x12340fb7, which is the
value for the instruction "li x31, 0x12340000".
After programming you should be able to connect to the serial port and have the
output echoed back to you.
## Programming flash image
On Linux you can do this using a command like `screen /dev/ttyUSB1`. Then as
you type you should get back the same characters.
### Connect JTAG
We will use vexrisc JTAG to program the flash, so you need openocd and a
suitable JTAG dongle.
Pin-out:
```
TCK: H16 aka J2.25
TDO: G16 aka J2.26
TDI: G15 aka J2.27
TMS: F15 aka J2.28
```
In addition you need to connect the ground and VTarget aka VIO: J2.2 on the
board.
### Start GDB server / OpenOCD
Make sure to use https://github.com/SpinalHDL/openocd_riscv
Make sure to select the configuration file which match your JTAG dongle.
An example with the dongle "ft2232h_breakout":
```
src/openocd -f tcl/interface/ftdi/ft2232h_breakout.cfg -c "set MURAX_CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/target/murax_xip.cfg
```
You should get an output like below:
```
Open On-Chip Debugger 0.10.0+dev-01214-g0ace94f (2019-10-02-18:23)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
../VexRiscv/cpu0.yaml
adapter speed: 100 kHz
adapter_nsrst_delay: 260
Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
jtag_ntrst_delay: 250
Info : set servers polling period to 50ms
Error: libusb_get_string_descriptor_ascii() failed with LIBUSB_ERROR_INVALID_PARAM
Info : clock speed 100 kHz
Info : JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (<invalid>), part: 0x0001, ver: 0x1)
Info : Listening on port 3333 for gdb connections
requesting target halt and executing a soft reset
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
```
### Loading the flash with telnet
First we connect and stop execution on the device:
```
user@lafite:~/Downloads/vexrisc_full/VexRiscv/src/main/c/murax/xipBootloader$ telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Open On-Chip Debugger
> reset
JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (<invalid>), part: 0x0001, ver: 0x1)
>
```
Now we can safely connect the J7 jumper on the board to be able to access the flash.
After that, we can load the program in flash:
```
> flash erase_sector 0 4 4
erased sectors 4 through 4 on flash bank 0 in 0.872235s
> flash write_bank 0 /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin 0x40000
wrote 48 bytes from file /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin to flash bank 0 at offset 0x00040000 in 0.285539s (0.164 KiB/s)
> flash verify_bank 0 /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin 0x40000
read 48 bytes from file /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin and flash bank 0 at offset 0x00040000 in 0.192036s (0.244 KiB/s)
contents match
> reset
JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (<invalid>), part: 0x0001, ver: 0x1)
> resume
> exit
Connection closed by foreign host.
```
From now the device runs the code from flash, LEDs shall display a dot moving from D9 to D2.
### Loading flash using GDB / eclipse
- ```
src/openocd -f tcl/interface/ftdi/ft2232h_breakout.cfg -c "set MURAX_CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/target/murax_xip.cfg
```
- Make sure J7 is connected.
- Connect to GDB / eclipse as usual.
From there code loading, step, break points works as usual (including software break points in flash).
## Update hardware/bootloader
- Stop any OpenOCD connection
- Remove J7, then:
- ```
make clean prog
```
- Remember to check a single FTDI device is listed in the output. If not:
- Disconnect the other devices
- ```
make prog
```
- Connect J7, flash software shall start executing.
## Flash software
Refer to "Loading the flash with telnet" or "Loading flash using GDB / eclipse".

View File

@ -42,13 +42,25 @@ crtStart:
li t0, 0x1
sw t0, CTRL_XIP_CONFIG(CTRL)
li t0, XIP_BASE
lw t1, (t0)
li t2, 0x12340fb7
xor t1,t1,t2
bnez t1,retry
jr t0
retry:
li a0, 0x800
call spiWrite
li t1,100000
loop:
addi t1,t1,-1
bnez t1, loop
j crtStart
spiWrite:
sw a0,CTRL_DATA(CTRL)
spiWrite_wait:
lw t0,CTRL_STATUS(CTRL)
srli t0,t0,0x10
slli t0,t0,0x10
beqz t0,spiWrite_wait
ret

View File

@ -7,18 +7,21 @@
crtStart:
li x31, 0x12340000 // magic word expected by bootloader
li x31, GPIO_BASE
li t0, 0x000000FF
sw t0, GPIO_OUTPUT_ENABLE(x31)
li t0,0
li t0,1
redo:
sw t0, GPIO_OUTPUT(x31)
li t1,10000
addi t0,t0,1
slli t0,t0,1
andi t0,t0,0xFF
bnez t0, loop
li t0,1
loop:
addi t1,t1,-1
bnez t1, loop
j redo

View File

@ -4,20 +4,34 @@ LFLAGS= -nostdlib -mcmodel=medany -nostartfiles -ffreestanding -fPIC -fPIE
all: crt.S demo.S
riscv64-unknown-elf-gcc -c $(CFLAGS) -o crt.o crt.S
riscv64-unknown-elf-gcc $(CFLAGS) -o crt.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,crt.map,--print-memory-usage
riscv64-unknown-elf-gcc $(CFLAGS) -o crt.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_rom.ld,-Map,crt.map,--print-memory-usage
riscv64-unknown-elf-objdump -S -d crt.elf > crt.asm
riscv64-unknown-elf-objcopy -O binary crt.elf crt.bin
riscv64-unknown-elf-gcc $(CFLAGS) -o crt_ram.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,crt_ram.map,--print-memory-usage
riscv64-unknown-elf-objdump -S -d crt_ram.elf > crt_ram.asm
riscv64-unknown-elf-objcopy -O binary crt_ram.elf crt_ram.bin
riscv64-unknown-elf-gcc -c $(CFLAGS) -o demo.o demo.S
riscv64-unknown-elf-gcc $(CFLAGS) -o demo.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,demo.map,--print-memory-usage
riscv64-unknown-elf-objdump -S -d demo.elf > demo.asm
riscv64-unknown-elf-objcopy -O binary demo.elf demo.bin
riscv64-unknown-elf-gcc $(CFLAGS) -o demo_rom.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_rom.ld,-Map,demo_rom.map,--print-memory-usage
riscv64-unknown-elf-objdump -S -d demo_rom.elf > demo_rom.asm
riscv64-unknown-elf-objcopy -O binary demo_rom.elf demo_rom.bin
riscv64-unknown-elf-gcc $(CFLAGS) -o demo_xip.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_xip.ld,-Map,demo_xip.map,--print-memory-usage
riscv64-unknown-elf-objdump -S -d demo_xip.elf > demo_xip.asm
riscv64-unknown-elf-objcopy -O binary demo_xip.elf demo_xip.bin
clean:
clean-for-commit:
rm -f *.o
rm -f *.bin
rm -f *.elf
rm -f *.asm
rm -f *.map
rm -f *.map
rm -f *.d
rm demo_rom.bin demo.bin crt_ram.bin
clean: clean-tmp
rm -f *.bin

View File

@ -0,0 +1,96 @@
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
*/
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(crtStart)
MEMORY {
mem : ORIGIN = 0x80000000, LENGTH = 0x00000400
rom : ORIGIN = 0xF001E000, LENGTH = 0x00000400
}
_stack_size = DEFINED(_stack_size) ? _stack_size : 0;
SECTIONS {
.vector : {
*crt.o(.text);
} > rom
.memory : {
*(.text);
end = .;
} > rom
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
} > rom
.ctors :
{
. = ALIGN(4);
_ctors_start = .;
KEEP(*(.init_array*))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
. = ALIGN(4);
_ctors_end = .;
} > rom
.data :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} > rom
.bss (NOLOAD) : {
. = ALIGN(4);
/* This is used by the startup in order to initialize the .bss secion */
_bss_start = .;
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
_bss_end = .;
} > mem
.noinit (NOLOAD) : {
. = ALIGN(4);
*(.noinit .noinit.*)
. = ALIGN(4);
} > mem
._stack (NOLOAD):
{
. = ALIGN(16);
PROVIDE (_stack_end = .);
. = . + _stack_size;
. = ALIGN(16);
PROVIDE (_stack_start = .);
} > mem
}

View File

@ -0,0 +1,96 @@
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
*/
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(crtStart)
MEMORY {
mem : ORIGIN = 0x80000000, LENGTH = 0x00000400
xip : ORIGIN = 0xE0040000, LENGTH = 0x00000400
}
_stack_size = DEFINED(_stack_size) ? _stack_size : 0;
SECTIONS {
.vector : {
*crt.o(.text);
} > xip
.memory : {
*(.text);
end = .;
} > xip
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
} > xip
.ctors :
{
. = ALIGN(4);
_ctors_start = .;
KEEP(*(.init_array*))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
. = ALIGN(4);
_ctors_end = .;
} > xip
.data :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} > xip
.bss (NOLOAD) : {
. = ALIGN(4);
/* This is used by the startup in order to initialize the .bss secion */
_bss_start = .;
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
_bss_end = .;
} > mem
.noinit (NOLOAD) : {
. = ALIGN(4);
*(.noinit .noinit.*)
. = ALIGN(4);
} > mem
._stack (NOLOAD):
{
. = ALIGN(16);
PROVIDE (_stack_end = .);
. = . + _stack_size;
. = ALIGN(16);
PROVIDE (_stack_start = .);
} > mem
}

View File

@ -385,7 +385,8 @@ object Murax_iCE40_hx8k_breakout_board_xip{
val led = out Bits(8 bits)
}
val murax = Murax(MuraxConfig.default(withXip = true))
//val murax = Murax(MuraxConfig.default(withXip = true))
val murax = Murax(MuraxConfig.default(withXip = true).copy(onChipRamSize = 8 kB))
murax.io.asyncReset := False
val mainClkBuffer = SB_GB()
@ -438,45 +439,6 @@ object Murax_iCE40_hx8k_breakout_board_xip{
def main(args: Array[String]) {
SpinalVerilog(Murax_iCE40_hx8k_breakout_board_xip())
/*SpinalVerilog{
val c = Murax(MuraxConfig.default(withXip = true))
c.rework {
c.resetCtrlClockDomain {
c.io.xip.setAsDirectionLess.allowDirectionLessIo.flattenForeach(_.unsetName())
out(RegNext(c.io.xip.ss)).setName("io_xip_ss")
val sclk = SB_IO_SCLK()
sclk.PACKAGE_PIN := inout(Analog(Bool)).setName("io_xip_sclk")
sclk.CLOCK_ENABLE := True
sclk.OUTPUT_CLK := ClockDomain.current.readClockWire
sclk.D_OUT_0 <> c.io.xip.sclk.write(0)
sclk.D_OUT_1 <> RegNext(c.io.xip.sclk.write(1))
for (i <- 0 until c.io.xip.p.dataWidth) {
val data = c.io.xip.data(i)
val bb = SB_IO_DATA()
bb.PACKAGE_PIN := inout(Analog(Bool)).setName(s"io_xip_data_$i" )
bb.CLOCK_ENABLE := True
bb.OUTPUT_CLK := ClockDomain.current.readClockWire
bb.OUTPUT_ENABLE <> data.writeEnable
bb.D_OUT_0 <> data.write(0)
bb.D_OUT_1 <> RegNext(data.write(1))
bb.INPUT_CLK := ClockDomain.current.readClockWire
data.read(0) := bb.D_IN_0
data.read(1) := RegNext(bb.D_IN_1)
}
}
}
c
}*/
}
}