diff --git a/.gitignore b/.gitignore index 1c3eaa82..8b9e9c8f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ *.swp include/riscv_config.sv.bak - +build diff --git a/doc/examples.rst b/doc/examples.rst index f3cc0474..78fb6c36 100644 --- a/doc/examples.rst +++ b/doc/examples.rst @@ -3,7 +3,21 @@ Examples ======== +To make use of Ibex it has to be integrated as described in :ref:`core-integration`. + Tracer Simulation ----------------- How to run a simple testbench to test the tracer is described in ``examples/sim/README.md``. + +FPGA +---- + +A minimal example for the `Arty A7 `_ FPGA Development board is provided. +In this example Ibex is directly linked to a SRAM memory instance. +Four LEDs from the board are connected to the data bus and are updated each time when a word is written. +The memory is separated into a instruction and data section. +The instructions memory is initialized at synthesis time by reading the output from the software build. +The software writes to the data section the complementary lower for bits of a word every second resulting in blinking LEDs. + +Find the description of how to build and program the Arty board in ``examples/fpga/artya7-100/README.md``. diff --git a/examples/fpga/artya7-100/README.md b/examples/fpga/artya7-100/README.md new file mode 100644 index 00000000..c3864a9c --- /dev/null +++ b/examples/fpga/artya7-100/README.md @@ -0,0 +1,48 @@ +# Ibex RISC-V Core SoC Example + +Please see [examples](https://ibex-core.readthedocs.io/en/latest/examples.html "Ibex User Manual") for a description of this example. + +## Requirements + +### Tools + + - RV32 compiler + - srecord + - `fusesoc` and its dependencies + - Xilinx Vivado + +## Build + +### Software + +First the software must be built. Go into `examples/sw/led` and call: + +``` +make CC=/path/to/RISC-V-compiler +``` + +The path to the RV32 compiler `/path/to/RISC-V-compiler` depends on the environment. +For example, it can be `riscv32-unknown-elf-gcc` if the binary is available through the `PATH` environment or `/opt/riscv/bin/riscv-none-embed-gcc` if a specific path is used. + +This should produce a `led.vmem` file which is used in the synthesises to update the SRAM storage. + +### Hardware + +Run the following command at the top level to build the hardware. + +``` +fusesoc --cores-root=. build lowrisc:ibex:top_artya7_100 +``` + +This will create a directory `build` which contains the output files, including +the bitstream. + +## Program + +After the board is connected to the computer it can be programmed with: + +``` +fusesoc --cores-root=. pgm lowrisc:ibex:top_artya7_100 +``` + +LED1/LED3 and LED0/LED2 should alternately be on after the FPGA programming is finished. diff --git a/examples/fpga/artya7-100/data/pins_artya7.xdc b/examples/fpga/artya7-100/data/pins_artya7.xdc new file mode 100644 index 00000000..a43b31bc --- /dev/null +++ b/examples/fpga/artya7-100/data/pins_artya7.xdc @@ -0,0 +1,217 @@ +## Based on https://github.com/Digilent/digilent-xdc/blob/master/Arty-A7-100-Master.xdc +## This file is a general .xdc for the Arty A7-100 Rev. D +## To use it in a project: +## - uncomment the lines corresponding to used pins +## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project + +## Clock signal +set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { IO_CLK }]; #IO_L12P_T1_MRCC_35 Sch=gclk[100] +create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports { IO_CLK }]; + +## Switches +#set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L12N_T1_MRCC_16 Sch=sw[0] +#set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L13P_T2_MRCC_16 Sch=sw[1] +#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L13N_T2_MRCC_16 Sch=sw[2] +#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L14P_T2_SRCC_16 Sch=sw[3] + +## RGB LEDs +#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { led0_b }]; #IO_L18N_T2_35 Sch=led0_b +#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { led0_g }]; #IO_L19N_T3_VREF_35 Sch=led0_g +#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { led0_r }]; #IO_L19P_T3_35 Sch=led0_r +#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { led1_b }]; #IO_L20P_T3_35 Sch=led1_b +#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { led1_g }]; #IO_L21P_T3_DQS_35 Sch=led1_g +#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { led1_r }]; #IO_L20N_T3_35 Sch=led1_r +#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { led2_b }]; #IO_L21N_T3_DQS_35 Sch=led2_b +#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { led2_g }]; #IO_L22N_T3_35 Sch=led2_g +#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { led2_r }]; #IO_L22P_T3_35 Sch=led2_r +#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { led3_b }]; #IO_L23P_T3_35 Sch=led3_b +#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { led3_g }]; #IO_L24P_T3_35 Sch=led3_g +#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { led3_r }]; #IO_L23N_T3_35 Sch=led3_r + +## LEDs +set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { LED[0] }]; #IO_L24N_T3_35 Sch=led[4] +set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { LED[1] }]; #IO_25_35 Sch=led[5] +set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { LED[2] }]; #IO_L24P_T3_A01_D17_14 Sch=led[6] +set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { LED[3] }]; #IO_L24N_T3_A00_D16_14 Sch=led[7] + +## Buttons +#set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { btn[0] }]; #IO_L6N_T0_VREF_16 Sch=btn[0] +#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { btn[1] }]; #IO_L11P_T1_SRCC_16 Sch=btn[1] +#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L11N_T1_SRCC_16 Sch=btn[2] +#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L12P_T1_MRCC_16 Sch=btn[3] + +## Pmod Header JA +#set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_0_15 Sch=ja[1] +#set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L4P_T0_15 Sch=ja[2] +#set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L4N_T0_15 Sch=ja[3] +#set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L6P_T0_15 Sch=ja[4] +#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L6N_T0_VREF_15 Sch=ja[7] +#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L10P_T1_AD11P_15 Sch=ja[8] +#set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L10N_T1_AD11N_15 Sch=ja[9] +#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_25_15 Sch=ja[10] + +## Pmod Header JB +#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L11P_T1_SRCC_15 Sch=jb_p[1] +#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L11N_T1_SRCC_15 Sch=jb_n[1] +#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L12P_T1_MRCC_15 Sch=jb_p[2] +#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L12N_T1_MRCC_15 Sch=jb_n[2] +#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L23P_T3_FOE_B_15 Sch=jb_p[3] +#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L23N_T3_FWE_B_15 Sch=jb_n[3] +#set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_L24P_T3_RS1_15 Sch=jb_p[4] +#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L24N_T3_RS0_15 Sch=jb_n[4] + +## Pmod Header JC +#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L20P_T3_A08_D24_14 Sch=jc_p[1] +#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L20N_T3_A07_D23_14 Sch=jc_n[1] +#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L21P_T3_DQS_14 Sch=jc_p[2] +#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=jc_n[2] +#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { jc[4] }]; #IO_L22P_T3_A05_D21_14 Sch=jc_p[3] +#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { jc[5] }]; #IO_L22N_T3_A04_D20_14 Sch=jc_n[3] +#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L23P_T3_A03_D19_14 Sch=jc_p[4] +#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L23N_T3_A02_D18_14 Sch=jc_n[4] + +## Pmod Header JD +#set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L11N_T1_SRCC_35 Sch=jd[1] +#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L12N_T1_MRCC_35 Sch=jd[2] +#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L13P_T2_MRCC_35 Sch=jd[3] +#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L13N_T2_MRCC_35 Sch=jd[4] +#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L14P_T2_SRCC_35 Sch=jd[7] +#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L14N_T2_SRCC_35 Sch=jd[8] +#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15P_T2_DQS_35 Sch=jd[9] +#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L15N_T2_DQS_35 Sch=jd[10] + +## USB-UART Interface +#set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L19N_T3_VREF_16 Sch=uart_rxd_out +#set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L14N_T2_SRCC_16 Sch=uart_txd_in + +## ChipKit Outer Digital Header +#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io0 }]; #IO_L16P_T2_CSI_B_14 Sch=ck_io[0] +#set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { ck_io1 }]; #IO_L18P_T2_A12_D28_14 Sch=ck_io[1] +#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { ck_io2 }]; #IO_L8N_T1_D12_14 Sch=ck_io[2] +#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { ck_io3 }]; #IO_L19P_T3_A10_D26_14 Sch=ck_io[3] +#set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { ck_io4 }]; #IO_L5P_T0_D06_14 Sch=ck_io[4] +#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ck_io5 }]; #IO_L14P_T2_SRCC_14 Sch=ck_io[5] +#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ck_io6 }]; #IO_L14N_T2_SRCC_14 Sch=ck_io[6] +#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ck_io7 }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=ck_io[7] +#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { ck_io8 }]; #IO_L11P_T1_SRCC_14 Sch=ck_io[8] +#set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { ck_io9 }]; #IO_L10P_T1_D14_14 Sch=ck_io[9] +#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ck_io10 }]; #IO_L18N_T2_A11_D27_14 Sch=ck_io[10] +#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ck_io11 }]; #IO_L17N_T2_A13_D29_14 Sch=ck_io[11] +#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ck_io12 }]; #IO_L12N_T1_MRCC_14 Sch=ck_io[12] +#set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { ck_io13 }]; #IO_L12P_T1_MRCC_14 Sch=ck_io[13] + +## ChipKit Inner Digital Header +#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { ck_io26 }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=ck_io[26] +#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { ck_io27 }]; #IO_L16N_T2_A15_D31_14 Sch=ck_io[27] +#set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { ck_io28 }]; #IO_L6N_T0_D08_VREF_14 Sch=ck_io[28] +#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { ck_io29 }]; #IO_25_14 Sch=ck_io[29] +#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { ck_io30 }]; #IO_0_14 Sch=ck_io[30] +#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { ck_io31 }]; #IO_L5N_T0_D07_14 Sch=ck_io[31] +#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { ck_io32 }]; #IO_L13N_T2_MRCC_14 Sch=ck_io[32] +#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ck_io33 }]; #IO_L13P_T2_MRCC_14 Sch=ck_io[33] +#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { ck_io34 }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=ck_io[34] +#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { ck_io35 }]; #IO_L11N_T1_SRCC_14 Sch=ck_io[35] +#set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { ck_io36 }]; #IO_L8P_T1_D11_14 Sch=ck_io[36] +#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { ck_io37 }]; #IO_L17P_T2_A14_D30_14 Sch=ck_io[37] +#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { ck_io38 }]; #IO_L7N_T1_D10_14 Sch=ck_io[38] +#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { ck_io39 }]; #IO_L7P_T1_D09_14 Sch=ck_io[39] +#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { ck_io40 }]; #IO_L9N_T1_DQS_D13_14 Sch=ck_io[40] +#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { ck_io41 }]; #IO_L9P_T1_DQS_14 Sch=ck_io[41] + +## ChipKit Outer Analog Header - as Single-Ended Analog Inputs +## NOTE: These ports can be used as single-ended analog inputs with voltages from 0-3.3V (ChipKit analog pins A0-A5) or as digital I/O. +## WARNING: Do not use both sets of constraints at the same time! +## NOTE: The following constraints should be used with the XADC IP core when using these ports as analog inputs. +#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vaux4_n }]; #IO_L1N_T0_AD4N_35 Sch=ck_an_n[0] ChipKit pin=A0 +#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vaux4_p }]; #IO_L1P_T0_AD4P_35 Sch=ck_an_p[0] ChipKit pin=A0 +#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vaux5_n }]; #IO_L3N_T0_DQS_AD5N_35 Sch=ck_an_n[1] ChipKit pin=A1 +#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vaux5_p }]; #IO_L3P_T0_DQS_AD5P_35 Sch=ck_an_p[1] ChipKit pin=A1 +#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vaux6_n }]; #IO_L7N_T1_AD6N_35 Sch=ck_an_n[2] ChipKit pin=A2 +#set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { vaux6_p }]; #IO_L7P_T1_AD6P_35 Sch=ck_an_p[2] ChipKit pin=A2 +#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { vaux7_n }]; #IO_L9N_T1_DQS_AD7N_35 Sch=ck_an_n[3] ChipKit pin=A3 +#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { vaux7_p }]; #IO_L9P_T1_DQS_AD7P_35 Sch=ck_an_p[3] ChipKit pin=A3 +#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { vaux15_n }]; #IO_L10N_T1_AD15N_35 Sch=ck_an_n[4] ChipKit pin=A4 +#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { vaux15_p }]; #IO_L10P_T1_AD15P_35 Sch=ck_an_p[4] ChipKit pin=A4 +#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { vaux0_n }]; #IO_L1N_T0_AD0N_15 Sch=ck_an_n[5] ChipKit pin=A5 +#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { vaux0_p }]; #IO_L1P_T0_AD0P_15 Sch=ck_an_p[5] ChipKit pin=A5 +## ChipKit Outer Analog Header - as Digital I/O +## NOTE: The following constraints should be used when using these ports as digital I/O. +#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { ck_a0 }]; #IO_0_35 Sch=ck_a[0] +#set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { ck_a1 }]; #IO_L4P_T0_35 Sch=ck_a[1] +#set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { ck_a2 }]; #IO_L4N_T0_35 Sch=ck_a[2] +#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { ck_a3 }]; #IO_L6P_T0_35 Sch=ck_a[3] +#set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { ck_a4 }]; #IO_L6N_T0_VREF_35 Sch=ck_a[4] +#set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { ck_a5 }]; #IO_L11P_T1_SRCC_35 Sch=ck_a[5] + +## ChipKit Inner Analog Header - as Differential Analog Inputs +## NOTE: These ports can be used as differential analog inputs with voltages from 0-1.0V (ChipKit analog pins A6-A11) or as digital I/O. +## WARNING: Do not use both sets of constraints at the same time! +## NOTE: The following constraints should be used with the XADC core when using these ports as analog inputs. +#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vaux12_p }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] ChipKit pin=A6 +#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vaux12_n }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] ChipKit pin=A7 +#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { vaux13_p }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] ChipKit pin=A8 +#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { vaux13_n }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] ChipKit pin=A9 +#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vaux14_p }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] ChipKit pin=A10 +#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vaux14_n }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] ChipKit pin=A11 +## ChipKit Inner Analog Header - as Digital I/O +## NOTE: The following constraints should be used when using the inner analog header ports as digital I/O. +#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { ck_a6 }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] +#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { ck_a7 }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] +#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { ck_a8 }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] +#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { ck_a9 }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] +#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { ck_a10 }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] +#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { ck_a11 }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] + +## ChipKit SPI +#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L17N_T2_35 Sch=ck_miso +#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L17P_T2_35 Sch=ck_mosi +#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L18P_T2_35 Sch=ck_sck +#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L16N_T2_35 Sch=ck_ss + +## ChipKit I2C +#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L4P_T0_D04_14 Sch=ck_scl +#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L4N_T0_D05_14 Sch=ck_sda +#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports { scl_pup }]; #IO_L9N_T1_DQS_AD3N_15 Sch=scl_pup +#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVCMOS33 } [get_ports { sda_pup }]; #IO_L9P_T1_DQS_AD3P_15 Sch=sda_pup + +## Misc. ChipKit Ports +#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { ck_ioa }]; #IO_L10N_T1_D15_14 Sch=ck_ioa +set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { IO_RST_N }]; #IO_L16P_T2_35 Sch=ck_rst + +## SMSC Ethernet PHY +#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { eth_col }]; #IO_L16N_T2_A27_15 Sch=eth_col +#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { eth_crs }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=eth_crs +#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L14N_T2_SRCC_15 Sch=eth_mdc +#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L17P_T2_A26_15 Sch=eth_mdio +#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { eth_ref_clk }]; #IO_L22P_T3_A17_15 Sch=eth_ref_clk +#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L20P_T3_A20_15 Sch=eth_rstn +#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_clk }]; #IO_L14P_T2_SRCC_15 Sch=eth_rx_clk +#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_dv }]; #IO_L13N_T2_MRCC_15 Sch=eth_rx_dv +#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L21N_T3_DQS_A18_15 Sch=eth_rxd[0] +#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L16P_T2_A28_15 Sch=eth_rxd[1] +#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[2] }]; #IO_L21P_T3_DQS_15 Sch=eth_rxd[2] +#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[3] }]; #IO_L18N_T2_A23_15 Sch=eth_rxd[3] +#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L20N_T3_A19_15 Sch=eth_rxerr +#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_clk }]; #IO_L13P_T2_MRCC_15 Sch=eth_tx_clk +#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_en }]; #IO_L19N_T3_A21_VREF_15 Sch=eth_tx_en +#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L15P_T2_DQS_15 Sch=eth_txd[0] +#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L19P_T3_A22_15 Sch=eth_txd[1] +#set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[2] }]; #IO_L17N_T2_A25_15 Sch=eth_txd[2] +#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[3] }]; #IO_L18P_T2_A24_15 Sch=eth_txd[3] + +## Quad SPI Flash +#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_cs }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_cs +#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] +#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] +#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] +#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] + +## Power Measurements +#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_n }]; #IO_L7N_T1_AD2N_15 Sch=ad_n[2] +#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_p }]; #IO_L7P_T1_AD2P_15 Sch=ad_p[2] +#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_n }]; #IO_L3N_T0_DQS_AD1N_15 Sch=ad_n[1] +#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_p }]; #IO_L3P_T0_DQS_AD1P_15 Sch=ad_p[1] +#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_n }]; #IO_L5N_T0_AD9N_15 Sch=ad_n[9] +#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_p }]; #IO_L5P_T0_AD9P_15 Sch=ad_p[9] +#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_n }]; #IO_L8N_T1_AD10N_15 Sch=ad_n[10] +#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_p }]; #IO_L8P_T1_AD10P_15 Sch=ad_p[10] diff --git a/examples/fpga/artya7-100/rtl/clkgen_xil7series.sv b/examples/fpga/artya7-100/rtl/clkgen_xil7series.sv new file mode 100644 index 00000000..e41b4b02 --- /dev/null +++ b/examples/fpga/artya7-100/rtl/clkgen_xil7series.sv @@ -0,0 +1,79 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +module clkgen_xil7series ( + input IO_CLK, + input IO_RST_N, + output clk_sys, + output rst_sys_n +); + logic locked_pll; + logic io_clk_buf; + logic clk_50_buf; + logic clk_50_unbuf; + logic clk_fb_buf; + logic clk_fb_unbuf; + + // input buffer + IBUF io_clk_ibuf( + .I (IO_CLK), + .O (io_clk_buf) + ); + + PLLE2_ADV #( + .BANDWIDTH ("OPTIMIZED"), + .COMPENSATION ("ZHOLD"), + .STARTUP_WAIT ("FALSE"), + .DIVCLK_DIVIDE (1), + .CLKFBOUT_MULT (12), + .CLKFBOUT_PHASE (0.000), + .CLKOUT0_DIVIDE (24), + .CLKOUT0_PHASE (0.000), + .CLKOUT0_DUTY_CYCLE (0.500) + ) pll ( + .CLKFBOUT (clk_fb_unbuf), + .CLKOUT0 (clk_50_unbuf), + .CLKOUT1 (), + .CLKOUT2 (), + .CLKOUT3 (), + .CLKOUT4 (), + .CLKOUT5 (), + // Input clock control + .CLKFBIN (clk_fb_buf), + .CLKIN1 (io_clk_buf), + .CLKIN2 (1'b0), + // Tied to always select the primary input clock + .CLKINSEL (1'b1), + // Ports for dynamic reconfiguration + .DADDR (7'h0), + .DCLK (1'b0), + .DEN (1'b0), + .DI (16'h0), + .DO (), + .DRDY (), + .DWE (1'b0), + // Other control and status signals + .LOCKED (locked_pll), + .PWRDWN (1'b0), + // Do not reset PLL on external reset, otherwise ILA disconnects at a reset + .RST (1'b0)); + + // output buffering + BUFG clk_fb_bufg ( + .I (clk_fb_unbuf), + .O (clk_fb_buf) + ); + + BUFG clk_50_bufg ( + .I (clk_50_unbuf), + .O (clk_50_buf) + ); + + // outputs + // clock + assign clk_sys = clk_50_buf; + + // reset + assign rst_sys_n = locked_pll & IO_RST_N; +endmodule diff --git a/examples/fpga/artya7-100/rtl/prim_clock_gating.sv b/examples/fpga/artya7-100/rtl/prim_clock_gating.sv new file mode 100644 index 00000000..19d08250 --- /dev/null +++ b/examples/fpga/artya7-100/rtl/prim_clock_gating.sv @@ -0,0 +1,18 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +module prim_clock_gating ( + input clk_i, + input en_i, + input test_en_i, + output logic clk_o +); + + BUFGCE u_clock_gating ( + .I (clk_i), + .CE (en_i | test_en_i), + .O (clk_o) + ); + +endmodule diff --git a/examples/fpga/artya7-100/rtl/ram_1p.sv b/examples/fpga/artya7-100/rtl/ram_1p.sv new file mode 100644 index 00000000..98b56c1e --- /dev/null +++ b/examples/fpga/artya7-100/rtl/ram_1p.sv @@ -0,0 +1,57 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Synchronous dual-port SRAM register model +// This module is for simulation and small size SRAM. +// Implementing ECC should be done inside wrapper not this model. + +module ram_1p #( + parameter int Width = 32, // bit + parameter int Depth = 128, + + // Do not touch + parameter int Aw = $clog2(Depth) +) ( + input clk_i, + input rst_ni, + + input req_i, + input write_i, + input [Aw-1:0] addr_i, + input [Width-1:0] wdata_i, + output logic rvalid_o, + output logic [Width-1:0] rdata_o +); + + logic [Width-1:0] storage [Depth]; + + // Xilinx FPGA specific Dual-port RAM coding style + // using always instead of always_ff to avoid 'ICPD - illegal combination of drivers' error + // thrown due to 'storage' being driven by two always processes below + always @(posedge clk_i) begin + if (req_i) begin + if (write_i) begin + storage[addr_i] <= wdata_i; + end + rdata_o <= storage[addr_i]; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + rvalid_o <= '0; + end else begin + rvalid_o <= req_i && ~write_i; + end + end + + `ifdef SRAM_INIT_FILE + localparam MEM_FILE = `"`SRAM_INIT_FILE`"; + initial begin + $display("Initializing SRAM from %s", MEM_FILE); + $readmemh(MEM_FILE, storage); + end + `endif +endmodule + diff --git a/examples/fpga/artya7-100/rtl/top_artya7_100.sv b/examples/fpga/artya7-100/rtl/top_artya7_100.sv new file mode 100644 index 00000000..388f98f8 --- /dev/null +++ b/examples/fpga/artya7-100/rtl/top_artya7_100.sv @@ -0,0 +1,153 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +module top_artya7_100 ( + input IO_CLK, + input IO_RST_N, + output [3:0] LED +); + + parameter int MEM_SIZE = 64 * 1024; // 64 kB + parameter logic [31:0] MEM_START = 32'h00000000; + parameter logic [31:0] MEM_MASK = MEM_SIZE-1; + + logic clk_sys, rst_sys_n; + + // Instruction connection to SRAM + logic instr_req; + logic instr_gnt; + logic instr_rvalid; + logic [31:0] instr_addr; + logic [31:0] instr_rdata; + + // Data connection to SRAM + logic data_req; + logic data_gnt; + logic data_rvalid; + logic data_we; + logic [31:0] data_addr; + logic [31:0] data_wdata; + logic [31:0] data_rdata; + + // SRAM arbiter + logic [13:0] mem_addr_index; + logic mem_req; + logic mem_write; + logic [31:0] mem_wdata; + logic mem_rvalid; + logic [31:0] mem_rdata; + + + ibex_core #( + .DmHaltAddr(32'h00000000), + .DmExceptionAddr(32'h00000000) + ) u_core ( + .clk_i (clk_sys), + .rst_ni (rst_sys_n), + + .test_en_i ('b0), + + .core_id_i (4'b0), + .cluster_id_i (6'b0), + // First instruction executed is at 0x0 + 0x80 + .boot_addr_i (32'h00000000), + + .instr_req_o (instr_req), + .instr_gnt_i (instr_gnt), + .instr_rvalid_i (instr_rvalid), + .instr_addr_o (instr_addr), + .instr_rdata_i (instr_rdata), + + .data_req_o (data_req), + .data_gnt_i (data_gnt), + .data_rvalid_i (data_rvalid), + .data_we_o (data_we), + // TODO: Byte access needs to be implemented + .data_be_o (), + .data_addr_o (data_addr), + .data_wdata_o (data_wdata), + .data_rdata_i (data_rdata), + .data_err_i ('b0), + + .irq_i ('b0), + .irq_id_i ('b0), + .irq_ack_o (), + .irq_id_o (), + + .debug_req_i ('b0), + + .fetch_enable_i ('b1) + ); + + // Connect Ibex to SRAM + always_comb begin + mem_req = 1'b0; + mem_addr_index = 14'b0; + mem_write = 1'b0; + mem_wdata = 32'b0; + if (instr_req) begin + mem_req = (instr_addr & ~MEM_MASK) == MEM_START; + mem_addr_index = instr_addr[15:2]; + end else if (data_req) begin + mem_req = (data_addr & ~MEM_MASK) == MEM_START; + mem_write = data_we; + mem_addr_index = data_addr[15:2]; + mem_wdata = data_wdata; + end + end + + // SRAM block for instruction and data storage + ram_1p #( + .Width(32), + .Depth(MEM_SIZE / 4) + ) u_ram ( + .clk_i ( clk_sys ), + .rst_ni ( rst_sys_n ), + .req_i ( mem_req ), + .write_i ( mem_write ), + .addr_i ( mem_addr_index ), + .wdata_i ( mem_wdata ), + .rvalid_o ( mem_rvalid ), + .rdata_o ( mem_rdata ) + ); + + // SRAM to Ibex + assign instr_rdata = mem_rdata; + assign data_rdata = mem_rdata; + assign instr_rvalid = mem_rvalid; + always_ff @(posedge clk_sys or negedge rst_sys_n) begin + if (!rst_sys_n) begin + instr_gnt <= 'b0; + data_gnt <= 'b0; + data_rvalid <= 'b0; + end else begin + instr_gnt <= instr_req && mem_req; + data_gnt <= ~instr_req && data_req && mem_req; + data_rvalid <= ~instr_req && data_req && mem_req; + end + end + + // Connect the led output to the lower four bits of a written data word + logic [3:0] leds; + always_ff @(posedge clk_sys or negedge rst_sys_n) begin + if (!rst_sys_n) begin + leds <= 4'b0; + end else begin + if (mem_req && data_req && data_we) begin + leds <= data_wdata[3:0]; + end + end + end + assign LED = leds; + + // Clock and reset + clkgen_xil7series + clkgen( + .IO_CLK, + .IO_RST_N, + .clk_sys, + .rst_sys_n + ); + +endmodule diff --git a/examples/fpga/artya7-100/top_artya7_100.core b/examples/fpga/artya7-100/top_artya7_100.core new file mode 100644 index 00000000..930bac10 --- /dev/null +++ b/examples/fpga/artya7-100/top_artya7_100.core @@ -0,0 +1,47 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:ibex:top_artya7_100:0.1" +description: "Ibex example toplevel for the Arty A7-100 board" +filesets: + files_rtl_artya7: + depend: + - lowrisc:ibex:ibex + files: + - rtl/top_artya7_100.sv + - rtl/ram_1p.sv + - rtl/prim_clock_gating.sv + - rtl/clkgen_xil7series.sv + file_type: systemVerilogSource + + files_constraints: + files: + - data/pins_artya7.xdc + file_type: xdc + +parameters: + # XXX: This parameter needs to be absolute, or relative to the *.runs/synth_1 + # directory. It's best to pass it as absolute path when invoking fusesoc, e.g. + # --SRAM_INIT_FILE=$PWD/sw/led/led.vmem + # XXX: The VMEM file should be added to the sources of the Vivado project to + # make the Vivado dependency tracking work. However this requires changes to + # fusesoc first. + SRAM_INIT_FILE: + datatype: str + description: SRAM initialization file in vmem hex format + default: "../../../../../examples/sw/led/led.vmem" + paramtype: vlogdefine + +targets: + synth: + default_tool: vivado + filesets: + - files_rtl_artya7 + - files_constraints + toplevel: top_artya7_100 + parameters: + - SRAM_INIT_FILE + tools: + vivado: + part: "xc7a100tcsg324-1" # Arty A7-100 diff --git a/examples/sw/led/.gitignore b/examples/sw/led/.gitignore new file mode 100644 index 00000000..ddb86046 --- /dev/null +++ b/examples/sw/led/.gitignore @@ -0,0 +1,6 @@ +*.o +*.bin +*.dis +*.elf +*.vmem +*.d diff --git a/examples/sw/led/Makefile b/examples/sw/led/Makefile new file mode 100644 index 00000000..5b264c58 --- /dev/null +++ b/examples/sw/led/Makefile @@ -0,0 +1,59 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Generate a baremetal application + +PROGRAM ?= led +PROGRAM_CFLAGS = -Wall -g -Os +ARCH = rv32imc +# ARCH = rv32im # to disable compressed instructions +SRCS = $(PROGRAM).c + +CC = /tools/riscv/bin/riscv32-unknown-elf-gcc + +OBJCOPY ?= $(subst gcc,objcopy,$(wordlist 1,1,$(CC))) +OBJDUMP ?= $(subst gcc,objdump,$(wordlist 1,1,$(CC))) + +LINKER_SCRIPT ?= link.ld +CRT ?= crt0.S +CFLAGS ?= -march=$(ARCH) -mabi=ilp32 -static -mcmodel=medany \ + -fvisibility=hidden -nostdlib -nostartfiles $(PROGRAM_CFLAGS) + +OBJS := ${SRCS:.c=.o} ${CRT:.S=.o} +DEPS = $(OBJS:%.o=%.d) + +OUTFILES = $(PROGRAM).elf $(PROGRAM).vmem $(PROGRAM).bin $(PROGRAM).dis + +all: $(OUTFILES) + +$(PROGRAM).elf: $(OBJS) $(LINKER_SCRIPT) + $(CC) $(CFLAGS) -T $(LINKER_SCRIPT) $(OBJS) -o $@ $(LIBS) + +%.dis: %.elf + $(OBJDUMP) -SD $^ > $@ + +# Note: this target requires the srecord package to be installed. +# XXX: This could be replaced by objcopy once +# https://sourceware.org/bugzilla/show_bug.cgi?id=19921 +# is widely available. +# XXX: Currently the start address 0x00000000 is hardcoded. It could/should be +# read from the elf file, but is lost in the bin file. +# Switching to objcopy will resolve that as well. +%.vmem: %.bin + srec_cat $^ -binary -offset 0x0000 -byte-swap 4 -o $@ -vmem + +%.bin: %.elf + $(OBJCOPY) -O binary $^ $@ + +%.o: %.c + $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $< + +%.o: %.S + $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $< + +clean: + $(RM) -f *.o *.d + +distclean: clean + $(RM) -f $(OUTFILES) diff --git a/examples/sw/led/crt0.S b/examples/sw/led/crt0.S new file mode 100644 index 00000000..9f987f7e --- /dev/null +++ b/examples/sw/led/crt0.S @@ -0,0 +1,89 @@ + .section .text + +default_exc_handler: + jal x0, default_exc_handler + +reset_handler: + /* set all registers to zero */ + mv x1, x0 + mv x2, x1 + mv x3, x1 + mv x4, x1 + mv x5, x1 + mv x6, x1 + mv x7, x1 + mv x8, x1 + mv x9, x1 + mv x10, x1 + mv x11, x1 + mv x12, x1 + mv x13, x1 + mv x14, x1 + mv x15, x1 + mv x16, x1 + mv x17, x1 + mv x18, x1 + mv x19, x1 + mv x20, x1 + mv x21, x1 + mv x22, x1 + mv x23, x1 + mv x24, x1 + mv x25, x1 + mv x26, x1 + mv x27, x1 + mv x28, x1 + mv x29, x1 + mv x30, x1 + mv x31, x1 + + /* stack initilization */ + la x2, _stack_start + +_start: + .global _start + + /* clear BSS */ + la x26, _bss_start + la x27, _bss_end + + bge x26, x27, zero_loop_end + +zero_loop: + sw x0, 0(x26) + addi x26, x26, 4 + ble x26, x27, zero_loop +zero_loop_end: + + +main_entry: + /* jump to main program entry point (argc = argv = 0) */ + addi x10, x0, 0 + addi x11, x0, 0 + jal x1, main + +/* =================================================== [ exceptions ] === */ +/* This section has to be down here, since we have to disable rvc for it */ + + .section .vectors, "ax" + .option norvc; + + // external interrupts are handled by the same callback + // until compiler supports IRQ routines + .org 0x00 + .rept 31 + nop + .endr + jal x0, default_exc_handler + + // reset vector + .org 0x80 + jal x0, reset_handler + + // illegal instruction exception + .org 0x84 + jal x0, default_exc_handler + + // ecall handler + .org 0x88 + jal x0, default_exc_handler diff --git a/examples/sw/led/led.c b/examples/sw/led/led.c new file mode 100644 index 00000000..dcb21180 --- /dev/null +++ b/examples/sw/led/led.c @@ -0,0 +1,47 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include +#define CLK_FIXED_FREQ_HZ (50ULL * 1000 * 1000) + +/** + * Delay loop executing within 8 cycles on ibex + */ +static void delay_loop_ibex(unsigned long loops) { + int out; /* only to notify compiler of modifications to |loops| */ + asm volatile( + "1: nop \n" // 1 cycle + " nop \n" // 1 cycle + " nop \n" // 1 cycle + " nop \n" // 1 cycle + " addi %1, %1, -1 \n" // 1 cycle + " bnez %1, 1b \n" // 3 cycles + : "=&r" (out) + : "0" (loops) + ); +} + +static int usleep_ibex(unsigned long usec) { + unsigned long usec_cycles; + usec_cycles = CLK_FIXED_FREQ_HZ * usec / 1000 / 1000 / 8; + + delay_loop_ibex(usec_cycles); + return 0; +} + +static int usleep(unsigned long usec) { + return usleep_ibex(usec); +} + +int main(int argc, char **argv) { + // Any data written to the stack segment will connect the lowest four bits to + // the board leds + volatile uint32_t *var = (volatile uint32_t *) 0x0000c010; + *var = 0xa; + + while (1) { + usleep(1000 * 1000); // 1000 ms + *var = ~(*var); + } +} diff --git a/examples/sw/led/link.ld b/examples/sw/led/link.ld new file mode 100644 index 00000000..1b7fef15 --- /dev/null +++ b/examples/sw/led/link.ld @@ -0,0 +1,105 @@ +OUTPUT_ARCH(riscv) + +/* required to correctly link newlib */ +GROUP( -lc -lgloss -lgcc -lsupc++ ) + +SEARCH_DIR(.) +__DYNAMIC = 0; + +MEMORY +{ + rom : ORIGIN = 0x00000000, LENGTH = 0xC000 /* 48 kB */ + stack : ORIGIN = 0x0000C000, LENGTH = 0x4000 /* 16 kB */ +} + +/* Stack information variables */ +_min_stack = 0x2000; /* 8K - minimum stack space to reserve */ +_stack_len = LENGTH(stack); +_stack_start = ORIGIN(stack) + LENGTH(stack); + +/* We have to align each sector to word boundaries as our current s19->slm + * conversion scripts are not able to handle non-word aligned sections. */ + +SECTIONS +{ + .vectors : + { + . = ALIGN(4); + KEEP(*(.vectors)) + } > rom + + .text : { + . = ALIGN(4); + _stext = .; + *(.text) + *(.text.*) + _etext = .; + __CTOR_LIST__ = .; + LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) + *(.ctors) + LONG(0) + __CTOR_END__ = .; + __DTOR_LIST__ = .; + LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) + *(.dtors) + LONG(0) + __DTOR_END__ = .; + *(.lit) + *(.shdata) + . = ALIGN(4); + _endtext = .; + } > rom + + .rodata : { + . = ALIGN(4); + *(.rodata); + *(.rodata.*) + } > rom + + .shbss : + { + . = ALIGN(4); + *(.shbss) + } > rom + + .data : { + . = ALIGN(4); + sdata = .; + _sdata = .; + *(.data); + *(.data.*) + edata = .; + _edata = .; + } > rom + + .bss : + { + . = ALIGN(4); + _bss_start = .; + *(.bss) + *(.bss.*) + *(.sbss) + *(.sbss.*) + *(COMMON) + _bss_end = .; + } > rom + + /* ensure there is enough room for stack */ + .stack (NOLOAD): { + . = ALIGN(4); + . = . + _min_stack ; + . = ALIGN(4); + stack = . ; + _stack = . ; + } > stack + + .stab 0 (NOLOAD) : + { + [ .stab ] + } + + .stabstr 0 (NOLOAD) : + { + [ .stabstr ] + } +}