2013年12月29日 星期日

Risc-V on Arty A7 35T - scala design cpu & add instruction & jtag debug

The project fit for Arty A7-35T

1.
install Vivado 2019.2.1
run step 5 in http://fatalfeel.blogspot.com/2013/12/chisel-design-ic-for-risc-v.html
gedit /etc/environment
~add path
/opt/Xilinx/Vivado/2019.2/bin

2.
cd $HOME
mkdir -p riscv_cpu
cd $HOME/riscv_cpu
git clone --recursive https://github.com/SpinalHDL/VexRiscv

3.
cd $HOME/riscv_cpu
git clone https://github.com/riscv/riscv-gnu-toolchain    ###(no --recursive)
cd riscv-gnu-toolchain
git checkout 411d134
git submodule update --init --recursive
mkdir build
cd build
../configure --prefix=/opt/riscv32i --with-arch=rv32i --with-abi=ilp32
make -j8

note:
"I"   Base Integer Instruction Set
"M" Standard Extension for Integer Multiplication and Divison
"A" Standard Extension for Atomic Instructions
"F" Standard Extension for Single-Precision Floating-Point
"D" Standard Extension for Double-Precision Floating-Point
"Q" Standard Extension for Quard-Precision Floating-point
"C" Standard Extension for Compressed Instruction
"G" combination of I, M, A, F and D.

ilp32/ilp32f/ilp32d    int-32bits    long-32bits    pointer-32bits
lp64/lp64f/lp64d      int-32bits    long-64bits    pointer-64bits

4.
cd $HOME/riscv_cpu/VexRiscv/src/main/c/murax/hello_world
gedit ./makefile
DEBUG=no
~change to
DEBUG=yes

SIFIVE_GCC_PACK ?= yes
~change to
SIFIVE_GCC_PACK=no

CFLAGS += -march=$(MARCH)  -mabi=$(MABI) -DNDEBUG
ifeq ($(DEBUG),yes)
CFLAGS += -g3 -O0
endif
ifeq ($(DEBUG),no)
CFLAGS += -g -Os
endif
~change to
ifeq ($(DEBUG),yes)
CFLAGS += -march=$(MARCH) -mabi=$(MABI) -g -O0
else
CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DNDEBUG -g -O3
endif

export PATH=$PATH:/opt/riscv32i/bin
export AR=riscv32-unknown-elf-ar
export AS=riscv32-unknown-elf-as
export CC=riscv32-unknown-elf-gcc
export CXX=riscv32-unknown-elf-g++
export LD=riscv32-unknown-elf-ld
make

https://www.mediafire.com/file/yk0j2nphbbdxr44/muraxhello_makefile

5.
run IntelliJ IDEA
open $HOME/riscv-cpu/VexRiscv
File -> Settings -> Build -> Build Tools -> Maven -> Importing
VM options for importer: -Xmx16384m
JDK for importer: 1.8

File -> Settings -> Build -> Build Tools -> sbt
Maximum heap size, MB: 16384
[checked] Automatically import this project on changes in build script files

File -> Settings -> Build -> Compiler -> Scala Compiler -> Scala Compiler Server
JVM maximum heap size, MB: 16384
JVM options: -server -Xss256m

File -> Settings -> Build -> Debugger
[checked] Friendly display of Scala collections in debugger
[checked] Do not expand Streams and Views
Collection start index: 0
Collection end index:  64

File -> Project Structure -> Project Settings -> Project
Project SDK: 1.8 (your java version)
[OK]

File -> Invalidate Caches / Restart
[Invalidate and Restart]

Build -> Rebuild Project

6.
right click [Murax_arty] in $HOME/riscv-cpu/VexRiscv/src/main/scala/vexriscv/demo/Murax.scala
select run
~generate
Murax.v
Murax.v_toplevel_system_ram_ram_symbol0.bin
Murax.v_toplevel_system_ram_ram_symbol1.bin
Murax.v_toplevel_system_ram_ram_symbol2.bin
Murax.v_toplevel_system_ram_ram_symbol3.bin

right click [GenFull] in $HOME/riscv_cpu/VexRiscv/src/main/scala/vexriscv/demo/GenFull.scala
select run
~generate
VexRiscv.v

7.
cd $HOME/riscv_cpu/VexRiscv/scripts/Murax/arty_a7
make all V=1

The artya7_makefile is a reference: 
https://www.mediafire.com/file/4jgsmf0lvyyid3i/artya7_makefile

note: remove all [-notrace] in $HOME/riscv_cpu/VexRiscv/scripts/Murax/arty_a7 can see how the tcl running, I will do this job on Vivado 2019.2 GUI.

8.
cd $HOME/riscv_cpu/VexRiscv
cp -f ./src/main/c/murax/hello_world/build/hello_world.v ./app.mem

9.
open Vivado 2019.2 IDE
create new project
sources:
$HOME/riscv_cpu/VexRiscv/Murax.v
$HOME/riscv_cpu/VexRiscv/scripts/Murax/arty_a7/toplevel.v
constraints:
$HOME/riscv_cpu/VexRiscv/scripts/Murax/arty_a7/arty_a7.xdc
parts:
xc7a35ticsg324-1L

https://www.mediafire.com/file/2f6gqf0c0vubs04/ArtyA7-35T_Schematic.pdf

10.
[Run Synthesis]
right click Launch Synthesis Run

[Run Implementation]

[Generate Bitstream]

cp -f ./VexRiscv.runs/impl_1/toplevel.bit ./top_latest.bit

11. create mmi file manually
cp -f ~/riscv_cpu/VexRiscv/scripts/Murax/arty_a7/soc_mmi.tcl ~/riscv_cpu/VexRiscv/soc_mmi.tcl
gedit ~/riscv_cpu/VexRiscv/soc_mmi.tcl
~comment section
#if {![info exists mmi_file]} {
#     set mmi_file "soc.mmi"
#}
~add
set mmi_file "~/riscv_cpu/VexRiscv/soc.mmi"

12. in Vivado 2019.2 IDE
[Run Implementation]
~then
Tool -> Run Tcl script: ~/riscv_cpu/VexRiscv/soc_mmi.tcl
~generate soc.mmi

https://www.mediafire.com/file/3sc547ywt6hm34o/soc_mmi.tcl

13. in terminal
cd $HOME/riscv_cpu/VexRiscv
updatemem -force --meminfo soc.mmi --data app.mem --bit ./top_latest.bit --proc dummy --out ./latest_soc_sw.bit
cp -f ./latest_soc_sw.bit ./latest.bit

14. in Vivado 2019.2 IDE
Tools -> Generate Memory Configuration File
Format: MCS
Custom Memory Size: 16
Filename: ~/riscv_cpu/VexRiscv/latest.mcs
Interface: SPIx4
Load Bitstream files: checked
Start address: 0 |  Direction: up | Bitfile: ~/riscv_cpu/VexRiscv/latest.bit
Overwrite: checked
OK
~generate latest.mcs

15. in Vivado 2019.2 IDE
[Open Hardware Manager]
right side window [Hardware]
right click xc7a35t_0 ->  Add Configuration Memory Device
search: s25fl128sxxxxxx0-spi-x1_x2_x4
click result name -> s25fl128sxxxxxx0-spi-x1_x2_x4
OK

refer to chapter 4.2 in https://digilent.com/reference/learn/programmable-logic/tutorials/arty-programming-guide/start
but we use s25fl128sxxxxxx0-spi-x1_x2_x4

16.
right click s25fl128sxxxxxx0-spi-x1_x2_x4 (child node of xc7a35t_0) -> Program Configuration Memory Device
Configuration file: ~/riscv_cpu/VexRiscv/latest.mcs
PRM file: (empty)
State of non-config mem I/O pins: Pull-none
Address Range: Configuration File Only
Erase, Program, Verify checked
OK

///////////////////////////add instruction///////////////////////////
1.
gedit $HOME/riscv_cpu/VexRiscv/src/main/scala/vexriscv/demo/Murax.scala
~add
cpuPlugins = ArrayBuffer(new SimdAddPlugin, //---> add this
                                         new IBusSimplePlugin( resetVector = if(withXip)

2.
gedit $HOME/riscv_cpu/VexRiscv/src/main/c/murax/hello_world/src/main.c
~add follows after include
//by dolu
asm(".set abiname_zero,  0");
asm(".set abiname_ra  ,  1");
asm(".set abiname_sp  ,  2");
asm(".set abiname_gp  ,  3");
asm(".set abiname_tp  ,  4");
asm(".set abiname_t0  ,  5");
asm(".set abiname_t1  ,  6");
asm(".set abiname_t2  ,  7");
asm(".set abiname_s0  ,  8");
asm(".set abiname_s1  ,  9");
asm(".set abiname_a0  , 10");
asm(".set abiname_a1  , 11");
asm(".set abiname_a2  , 12");
asm(".set abiname_a3  , 13");
asm(".set abiname_a4  , 14");
asm(".set abiname_a5  , 15");
asm(".set abiname_a6  , 16");
asm(".set abiname_a7  , 17");
asm(".set abiname_s2  , 18");
asm(".set abiname_s3  , 19");
asm(".set abiname_s4  , 20");
asm(".set abiname_s5  , 21");
asm(".set abiname_s6  , 22");
asm(".set abiname_s7  , 23");
asm(".set abiname_s8  , 24");
asm(".set abiname_s9  , 25");
asm(".set abiname_s10 , 26");
asm(".set abiname_s11 , 27");
asm(".set abiname_t3  , 28");
asm(".set abiname_t4  , 29");
asm(".set abiname_t5  , 30");
asm(".set abiname_t6  , 31");

//word func7 rs2 rs1 func3 rd opc
#define RISC_ADD(src1, src2, result) \
__asm__ volatile \
( \
 ".word ((0b0000000 << 25) | (abiname_%2 << 20) | (abiname_%1 << 15) | (0b000 << 12) | (abiname_%0 << 7) | 0b0110011) \n\t" \
 : "=r"(result) \
 : "r" (src1), "r" (src2) \
)

//word func7 rs2 rs1 func3 rd opc
#define SIMD_ADD(src1, src2, result) \
__asm__ volatile \
( \
 ".word ((0b0000011 << 25) | (abiname_%2 << 20) | (abiname_%1 << 15) | (0b000 << 12) | (abiname_%0 << 7) | 0b0110011) \n\t" \
 : "=r"(result) \
 : "r" (src1), "r" (src2) \
)

void main() {
    unsigned int src1     = 0x11111111;
    unsigned int src2     = 0x22222222;
    unsigned int outputa= 0x00000000;
    unsigned int outputb= 0x00000000;
    
    RISC_ADD(src1, src2, outputa);
    SIMD_ADD(src1, src2, outputb);
}

https://www.mediafire.com/file/l0xn2wpteibofa1/muraxhello_main.c

3.
refer to previous step and rebuild latest.mcs
burn latest.mcs to arty-a7-35t
trace uart log from arty-a7-35t's usb
done

///////////////////////////external jtag debug///////////////////////////
refer to:
https://github.com/SpinalHDL/openocd_riscv
https://tomverbeure.github.io/2021/07/18/VexRiscv-OpenOCD-and-Traps.html
https://ithelp.ithome.com.tw/articles/10196583
http://www.mediafire.com/view/ozh1f11zx8s2g5s/BusBlaster_jtag.png#
https://www.mediafire.com/file/2f6gqf0c0vubs04/ArtyA7-35T_Schematic.pdf

1.
~find Jtag pins and connect to BusBlaster, do not connect Vcc.
/$HOME/riscv_cpu/VexRiscv/scripts/Murax/arty_a7/arty_a7.xdc
/$HOME/riscv_cpu/VexRiscv/scripts/Murax/arty_a7/toplevel.v

2.
git config --global http.sslVerify false
apt install libtool automake libusb-1.0.0-dev texinfo libusb-dev libyaml-dev pkg-config

3.
cd /$HOME/riscv_cpu
git clone --recursive https://github.com/SpinalHDL/openocd_riscv.git
cd openocd_riscv
./bootstrap
./configure --prefix=/opt/vexocd --enable-ftdi --enable-dummy
make -j8 && make install

4. all paths are absolute
/opt/vexocd/bin/openocd -f /opt/vexocd/share/openocd/scripts/interface/ftdi/dp_busblaster.cfg -c 'set MURAX_CPU0_YAML /root/riscv_cpu/VexRiscv/cpu0.yaml' -f /opt/vexocd/share/openocd/scripts/target/murax.cfg

5.
/opt/riscv32i/bin/riscv32-unknown-elf-gdb $HOME/riscv_cpu/VexRiscv/src/main/c/murax/hello_world/build/hello_world.elf
target remote localhost:3333
set remotetimeout 60
set arch riscv:rv32
monitor reset halt
load
continue

PS: if you want to show debugging in IDE read [Kernel GUI debug] in this link
https://fatalfeel.blogspot.com/2015/12/openocd-with-eclipse-debug-kernel-of.html

///////////////////////////arty a7 35t internal usb jtag debug///////////////////////////
refer to: 
https://github.com/SpinalHDL/VexRiscv/tree/master/doc/nativeJtag

1. comment [external jtag] and add between [arty internal usb jtag]
gedit $HOME/riscv_cpu/VexRiscv/src/main/scala/vexriscv/demo/Murax.scala

//add import
import spinal.lib.com.jtag.JtagTapInstructionCtrl

val io = new Bundle
{
val asyncReset  = in Bool()
val mainClk       = in Bool()
//val jtag            = slave(Jtag()) //external jtag
val gpioA           = master(TriStateArray(gpioWidth bits))
val uart              = master(Uart())
val xip               = ifGen(genXip)(master(SpiXdrMaster(xipConfig.ctrl.spi)))
}

case plugin : DebugPlugin      => plugin.debugClockDomain
{
resetCtrl.systemReset setWhen(RegNext(plugin.io.resetOut))
//io.jtag       <> plugin.io.bus.fromJtag()   //external jtag
//arty internal usb jtag: start         val jtagCtrl  = JtagTapInstructionCtrl()
val tap         = jtagCtrl.fromXilinxBscane2(userId = 2)
jtagCtrl       <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK))
//arty internal usb jtag: end
}

val io = new Bundle
{
  val mainClk  = in  Bool()

  //external jtag
  /*val jtag_tck = in  Bool()
  val jtag_tdi = in  Bool()
  val jtag_tdo = out Bool()
  val jtag_tms = in  Bool()*/

  val uart_txd = out Bool()
  val uart_rxd = in  Bool()

  val mosi = inout(Analog(Bool))
  val miso = inout(Analog(Bool))
  val sclk = out Bool()
  val spis = out Bool()

  val led = out Bits(8 bits)
}

//external jtag
/*val jtagClkBuffer = SB_GB()
jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck
jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck*/

//external jtag
/*murax.io.jtag.tdi <> io.jtag_tdi
murax.io.jtag.tdo <> io.jtag_tdo
murax.io.jtag.tms <> io.jtag_tms*/   

2. comment [external jtag] for rebuild project pass
gedit $HOME/riscv_cpu/VexRiscv/src/test/scala/vexriscv/MuraxSim.scala
val tcpJtag = JtagTcp(
    //jtag = dut.io.jtag,  //external jtag
    jtag = null,
    jtagClkPeriod = jtagClkPeriod
)

3. comment [external jtag]
gedit $HOME/riscv_cpu/VexRiscv/scripts/Murax/arty_a7/toplevel.v

//external jtag start
    /*input  wire tck,
    input  wire tms,
    input  wire tdi,
    input  wire trst,
    output reg  tdo,*/
//external jtag end

//assign io_gpioA_read[11:8]    = {tck,tms,tdi,trst}; //external jtag

//external jtag: start   
  /*reg  tesic_tck,tesic_tms,tesic_tdi;
  wire tesic_tdo;
  reg  soc_tck,soc_tms,soc_tdi;
  wire soc_tdo;*/
//external jtag: end  

//external jtag: start
  /*always @(*) begin
      {soc_tck,  soc_tms,  soc_tdi  } = {tck,tms,tdi};
      tdo = soc_tdo;
  end*/
//external jtag: end

Murax core (
    .io_asyncReset(io_asyncReset),
    .io_mainClk (clk100 ),
//external jtag: start
    /*.io_jtag_tck(soc_tck),
    .io_jtag_tdi(soc_tdi),
    .io_jtag_tdo(soc_tdo),
    .io_jtag_tms(soc_tms),*/
//external jtag: end
    .io_gpioA_read       (io_gpioA_read),
    .io_gpioA_write      (io_gpioA_write),
    .io_gpioA_writeEnable(io_gpioA_writeEnable),
    .io_uart_txd(serial_tx),
    .io_uart_rxd(serial_rx)
);

rebuild Murax_arty

4.
cd $HOME/riscv_cpu/openocd_riscv/tcl/interface

wget https://raw.githubusercontent.com/SpinalHDL/SaxonSoc/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/usb_connect.cfg

wget https://raw.githubusercontent.com/SpinalHDL/SaxonSoc/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/soc_init.cfg

5.
gedit ./soc_init.cfg
set cpu_count $::env(SAXON_CPU_COUNT)
~change to
set cpu_count 1

~comment
/*if {$SPINAL_SIM != "yes"} {
    targets saxon.cpu0
    load_image software/standalone/sdramInit/build/sdramInit.bin 0x10A00000
    puts -nonewline "init SDRAM .."
    resume 0x10A00000
    wait_halt
} else {
    targets saxon.cpu0
    load_image software/standalone/bootloader/build/bootloader_spinal_sim.bin 0x10A00000
    puts -nonewline "init SDRAM .."
    resume 0x10A00000
    after 4000
    halt
}*/

download:
https://www.mediafire.com/file/mv1ca94ji1rdwj0/soc_init.cfg

6.
cd $HOME/riscv_cpu/openocd_riscv
make -j8 && make install

7. run
/opt/vexocd/bin/openocd -f /opt/vexocd/share/openocd/scripts/interface/usb_connect.cfg -c 'set CPU0_YAML /root/riscv_cpu/VexRiscv/cpu0.yaml' -f /opt/vexocd/share/openocd/scripts/interface/soc_init.cfg

8.
eclipse setting for internal usb jtag debugging
https://www.mediafire.com/view/cwqifkpv4d27rgk/artya7-35t_internal_eclipse00.png
https://www.mediafire.com/view/jbd9r7f7rcc3y66/artya7-35t_internal_eclipse01.png
https://www.mediafire.com/view/fo5tlqccr8kijmg/artya7-35t_internal_eclipse02.png
https://www.mediafire.com/view/l81x5g1i4osxr3h/artya7-35t_internal_eclipse03.png

after eclipse setting then start debugging

9. usb log and usb jtag at the same time, when using agent-proxy for console log
git clone git://git.kernel.org/pub/scm/utils/kernel/kgdb/agent-proxy.git
cd agent-proxy
make
./agent-proxy 4440^4441 0 /dev/ttyUSB1,115200

10.
open another terminal
telnet localhost 4440    #now console log connect to target

demo:
https://www.mediafire.com/view/tm67r0tv1vwe4il/artya7-35t_internal_demo00.png
https://www.mediafire.com/view/iua7omk5bittf69/artya7-35t_internal_demo01.png
https://www.mediafire.com/file/ecp5jjy2n6effxc/arty_internal_jtag.mkv

///////////////////////////tutorial///////////////////////////
(a)
in /$HOME/riscv_cpu/VexRiscv/src/main/c/murax/hello_world/src/crt.S
.section .text
.global  trap_entry
.align 5
The .align 5 will cause riscv gcc reserve .text to 0x0000000080000020

(b) disassembler in gdb
/opt/riscv32i/bin/riscv32-unknown-elf-gdb /$HOME/riscv_cpu/VexRiscv/src/main/c/murax/hello_world/build/hello_world.elf
(gdb) disas /r 0x80000000, 0x80000080
Dump of assembler code from 0x80000000 to 0x80000080:
   0x80000000 <crtStart+0>: 37 01 00 80 lui sp,0x80000
   0x80000004 <crtStart+4>: 13 01 01 0b addi sp,sp,176 # 0x800000b0
   0x80000008 <crtStart+8>: e7 00 01 00 jalr sp
   0x8000000c <crtStart+12>: 13 00 00 00 nop
   0x80000010 <crtStart+16>: 00 00 unimp
   0x80000012 <crtStart+18>: 00 00 unimp
   0x80000014 <crtStart+20>: 00 00 unimp
   0x80000016 <crtStart+22>: 00 00 unimp
   0x80000018 <crtStart+24>: 00 00 unimp
   0x8000001a <crtStart+26>: 00 00 unimp
   0x8000001c <crtStart+28>: 00 00 unimp
   0x8000001e <crtStart+30>: 00 00 unimp
   0x80000020 <trap_entry+0>: 23 2e 11 fe sw ra,-4(sp)

(c) hardcode trap_entry 0x80000020 pointer to mtvec
/$HOME/riscv_cpu/VexRiscv/src/main/scala/vexriscv/demo/Murax.scala
new CsrPlugin(CsrPluginConfig.smallest(mtvecInit =  if(withXip)
                                                                                                0xE0040020l
                                                                                              else
                                                                                                0x80000020l))

(d)
asm(".set abiname_t0  ,  5");
mean define abiname_t0 = 5
~and
__asm__ volatile \
( \
 ".word ((0b0000011 << 25) | (abiname_%2 << 20) | (abiname_%1 << 15) | (0b000 << 12) | (abiname_%0 << 7) | 0b0110011) \n\t" \
 : "=r"(result) \
 : "r" (src1), "r" (src2) \
)
%0 means gcc assign a available register name that save result value
%1 means gcc assign a available register name that save src1 value
%2 means gcc assign a available register name that save src2 value

(e) where is Jtag Tap IDcode
in DebugPlugin.scala
def fromJtag(): Jtag =
{
    ...
    val jtagBridge = new JtagBridge(jtagConfig)
    ...
}

~then

SystemDebugger.scala of
~/.ivy2/cache/com.github.spinalhdl/spinalhdl-lib_2.11/srcs/spinalhdl-lib_2.11-1.6.0-sources.jar
class JtagBridge(c: SystemDebuggerConfig) extends Component
{
    ...
    val jtag = ClockDomain(io.jtag.tck)(new Area
    {
        val tap = new JtagTap(io.jtag, 4)
        val idcodeArea = tap.idcode(B"x10001FFF")(1)
        val writeArea = tap.flowFragmentPush(system.cmd,JtagBridge.this.clockDomain)(2)
        val readArea = tap.read(system.rsp.addTag(crossClockDomain))(3)
    })
    ...
}

Tap IDcode = 0x10001FFF

in $HOME/riscv_cpu/VexRiscv/Murax.v can find
_zz_jtag_tap_tdoDr <= 32'h10001fff;

////////////////////////////////////////////////////////////////////////////////////////////////////
full source with patch download:
https://www.mediafire.com/file/b54k6dtpzulxfxn/VexRiscv.tar.gz

1 則留言:

  1. Thanks for posting the useful information to my vision. This is excellent information.
    JTAG

    回覆刪除