├── .gitignore ├── README.md ├── ahb3lite_apb_bridge ├── ahb3lite_apb_bridge.core └── files │ ├── 0001-Patch-for-verilator.patch │ └── 0002-Remove-tasks-unsynthesizable-by-yosys.patch ├── ahb3lite_csr ├── ahb3lite_csr.core ├── rtl │ └── ahb3lite_csr.sv └── sw │ ├── ahb3lite_csr.py │ ├── cppwriter.py │ └── verilogwriter.py ├── ahb3lite_debug_bridge ├── ahb3lite_debug_bridge.core └── rtl │ ├── ahb3lite_debug_bridge.sv │ ├── ahb3lite_debug_bridge.sv.bak │ └── ahb3lite_debug_bridge.sv.bak2 ├── ahb3lite_default_slave ├── ahb3lite_default_slave.core └── rtl │ └── ahb3lite_default_slave.sv ├── ahb3lite_host_master ├── ahb3lite_host_master.core └── rtl │ └── ahb3lite_host_master.sv ├── ahb3lite_host_slave ├── ahb3lite_host_slave.core └── rtl │ └── ahb3lite_host_slave.sv ├── ahb3lite_intercon ├── ahb3lite_intercon.core └── files │ ├── 0001-Add-default-route.patch │ ├── 0002-Add-fusesoc-generators.patch │ ├── 0003-Remove-recursive-function-def-for-verilator.patch │ └── 0004-Lint-off-1-delay.patch ├── ahb3lite_intercon_test ├── ahb3lite_intercon_test.core ├── arty-a35t │ └── arty.xdc ├── bench │ └── verilator │ │ ├── #tb.cpp# │ │ └── tb.cpp └── rtl │ └── intercon_test.sv ├── ahb3lite_irq_slave ├── ahb3lite_irq_slave.core └── rtl │ └── ahb3lite_irq_slave.sv ├── ahb3lite_memory ├── ahb3lite_memory.core └── files │ ├── 0001-Remove-async-reset.patch │ ├── 0002-Fix-verilator-linting.patch │ └── 0003-Fix-blocking-assignment.patch ├── ahb3lite_mvec ├── ahb3lite_mvec.core └── rtl │ └── ahb3lite_mvec.sv ├── ahb3lite_pkg └── ahb3lite_pkg.core ├── ahb3lite_remote_bridge ├── ahb3lite_remote_bridge.core └── rtl │ ├── ahb3lite_remote_bridge.sv │ ├── clkdiv.sv │ ├── swd_if.sv │ └── swd_phy.sv ├── ahb3lite_remote_bridge2 ├── ahb3lite_remote_bridge.core ├── bench │ ├── debug_mux_tb.cpp │ ├── jtag_adiv5_tb.cpp │ ├── jtag_phy_tb.cpp │ ├── swd_adiv5_tb.cpp │ └── swd_phy_tb.cpp └── rtl │ ├── debug_clkdiv.sv │ ├── debug_mux.sv │ ├── host_jtag_convert.sv │ ├── jtag_adiv5.sv │ ├── jtag_phy.sv │ ├── swd_adiv5.sv │ └── swd_phy.sv ├── apb4_gpio └── apb4_gpio.core ├── arm_debug ├── arm_debug.core └── rtl │ ├── adiv5_mux.sv │ ├── adiv5_pkg.sv │ ├── jtag_adiv5.sv │ ├── jtag_phy.sv │ ├── swd_adiv5.sv │ └── swd_phy.sv ├── cm3_core ├── cm3_core.core ├── constraints │ └── cm3.sdc ├── rtl │ ├── cm3_core.sv │ └── cm3_excl_mon.sv └── vivado │ └── cm3.tcl ├── cm3_full └── cm3_full.core ├── cm3_min_soc ├── bench │ └── verilator │ │ └── tb.cpp ├── cm3_min_soc.core ├── fw │ ├── blinky.bin │ ├── blinky.hex │ └── blinky_sim.bin ├── rtl │ ├── cm3_min_soc.sv │ └── fpga_top.sv ├── scripts │ └── cortexm3sim.cfg └── vivado │ ├── clocks.xdc │ ├── pins.xdc │ └── vivado.tcl ├── cm3_obs ├── cm3_obs.core └── files │ ├── 0001-Remove-verilator-warnings.patch │ └── 0002-Remove-async-reset.patch ├── fifo_arb ├── fifo_arb.core └── rtl │ └── fifo_arb.sv ├── fifo_arb_rx ├── bench │ ├── fifo_arb_rx_tb.v │ ├── fifo_reader1.v │ └── fifo_tester.v ├── fifo_arb_rx.core └── rtl │ └── fifo_arb_rx.sv ├── fifo_arb_tx ├── bench │ ├── fifo_arb_tx_tb.v │ ├── fifo_reader1.v │ └── fifo_tester.v ├── fifo_arb_tx.core └── rtl │ └── fifo_arb_tx.sv ├── host_fifo_pkg ├── host_fifo_pkg.core └── rtl │ └── host_fifo_pkg.sv ├── roalogic_memory ├── files │ ├── 0001-Remove-verilator-param-lint-error.patch │ └── 0002-Make-RAM-array-verilator-public.patch └── roalogic_memory.core ├── uart_fifo ├── rtl │ ├── rxuartlite.v │ ├── txuartlite.v │ └── uart_fifo.sv └── uart_fifo.core ├── verilator_utils ├── GPIOClient.cpp ├── GPIOClient.h ├── GPIOServer.cpp ├── GPIOServer.h ├── JTAGClient.cpp ├── JTAGClient.h ├── JTAGServer.cpp ├── JTAGServer.h ├── Server.cpp ├── Server.h ├── UARTServer.cpp ├── UARTServer.h ├── atomicops.h ├── err.h ├── readerwriterqueue.h ├── verilator_utils.core ├── verilator_utils.cpp └── verilator_utils.h ├── vivado_ipgen ├── sw │ └── vivado_ipgen.py └── vivado_ipgen.core ├── vivado_probe ├── scripts │ ├── insert_ila.tcl │ ├── instantiate_ila.tcl │ └── setup_ila.tcl └── vivado_probe.core └── xil_dsp48_div ├── rtl └── xil_dsp48_div.sv └── xil_dsp48_div.core /.gitignore: -------------------------------------------------------------------------------- 1 | cm3_full/AT426-BU-98000-r0p1-00rel0/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tinylabs-cores 2 | This repo contains fusesoc compatible cores and a sample ARM Cortex-M3 system on chip (SoC) for the Arty-A35 created from these cores. 3 | ## Dependencies 4 | * [fusesoc](https://fusesoc.readthedocs.io/en/rtd/tutorials/1-getting_started.html)\ 5 | `pip install fusesoc`\ 6 | `fusesoc init` 7 | * Verilator (if running sim)\ 8 | `apt-get install verilator` 9 | * [Vivado](https://www.xilinx.com/support/download.html) (if synthesizing example SoC) 10 | * [ARM AT421 DesignStart Eval (CM3)](https://developer.arm.com/ip-products/designstart/eval)\ 11 | _This is currently mirrored and linked from the fusesoc core so no need to download unless it's taken down_ 12 | * [ARM AT426 DesignStart for FPGA (CM3)](https://developer.arm.com/ip-products/designstart/fpga) - Optional for encrypted CM3 synthesis 13 | ## Preparation 14 | * Create an empty directory\ 15 | `mkdir fusesoc-test; cd fusesoc-test` 16 | * Add the tinylabs-cores library\ 17 | `fusesoc library add tinylabs-cores https://github.com/tinylabs/tinylabs-cores.git` 18 | * Source vivado at login to add path to environment\ 19 | `source /opt/path/to/vivado/settings64.sh` in ~/.profile\ 20 | _Alternatively you can add vivado-settings:path to the .core file_ 21 | ## Building and running the simulation 22 | * Compile and run the verilated model\ 23 | `fusesoc run --target=sim cm3_min_soc && gtkwave ./build/cm3_min_soc_0.1/sim-verilator/sim.vcd`\ 24 | You can inspect the top level GPIO_O signal to see the blinking GPIO 25 | ## Synthesize for the [Arty board (A35T)](https://www.xilinx.com/products/boards-and-kits/arty.html) 26 | There are two targets for synthesis corresponding to the swappable Cortex-M3 cores released by ARM. The AT421 package contains an obsfucated/flattened core which is fully synthesizable but has fixed parameters and cannot be optimized by the EDA tools. We always use this for simulation but it can also be synthesiszed and run on an FPGA. The second core is in the AT426 package which contains encrypted RTL that can only be read by Vivado. Through trial and error I determined the interface was _almost_ identical which means we can blindly instantiate it and allow Vivado to decrypt it during compilation. 27 | ### Building arty (AT421 obsfucated core) 28 | `fusesoc run --target=arty cm3_min_soc`\ 29 | On completion this will flash the Arty board if plugged in. You should see LD4 blinking. 30 | ### Building arty_full (AT426 encrypted core) 31 | * Create empty directory\ 32 | `mkdir AT426; cd AT426` 33 | * Copy core file from tinylabs-cores\ 34 | `wget https://raw.githubusercontent.com/tinylabs/tinylabs-cores/master/cm3_full/cm3_full.core` 35 | * Download and unzip AT426 from ARM (link above) 36 | * Go back to fusesoc-test and add library to fusesoc\ 37 | `cd ../`\ 38 | `fusesoc library add cm3_full $PWD/AT426` 39 | * Synthesize using encrypted CM3\ 40 | `fusesoc run --target=arty_full cm3_min_soc`\ 41 | Again, you should see LD4 blinking 42 | #### AT421 Attributes 43 | * Plaintext interface 44 | * Compatible with Verilator 45 | * IRQ_CNT fixed at 16 46 | * Runs up to 30MHz (in my tests) 47 | * Uses 73% of LUTs 48 | * Synthesizable on non-Xilinx FPGAs 49 | #### AT426 Attributes 50 | * EDA optimizable 51 | * Runs up to 50MHz (in my tests) 52 | * Uses 59% of LUTs 53 | * Up to 240 IRQs supported (not tested) 54 | * Synthesizable ONLY with Vivado 55 | ### Help! Things that need fixing: 56 | * A fusesoc generator for the APB bus would be useful to add additional APB peripherals. 57 | * Additional core targets for popular boards that are supported by the fusesoc (edalize) backend would be great. 58 | * More testing all around. 59 | ## Licensing 60 | My understanding [not a lawyer(TM)] is that the AT426 core is OK for commercial use if used on Xilinx 7-series parts. However, many of the other components from RoaLogic (ahb3lite_interconnect, ahb3lite_memory, ahb3lite_apb_brige, apb4_gpio) have a non-commercial clause. With some work these components could be replaced.\ 61 | \ 62 | Except as represented in this agreement, all work product by TinyLabs is provided ​“AS IS”. Other than as provided in this agreement, TinyLabs makes no other warranties, express or implied, and hereby disclaims all implied warranties, including any warranty of merchantability and warranty of fitness for a particular purpose. 63 | 64 | -------------------------------------------------------------------------------- /ahb3lite_apb_bridge/ahb3lite_apb_bridge.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::ahb3lite_apb_bridge:1.0 3 | description: Bridge AHB3 slave to APB4 master 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - ahb3lite_pkg 9 | files: 10 | - rtl/verilog/ahb3lite_apb_bridge.sv : {file_type : verilogSource} 11 | 12 | license: 13 | files: 14 | - LICENSE.md : {file_type : user} 15 | 16 | targets: 17 | default: 18 | filesets : [rtl, license] 19 | 20 | provider: 21 | name : github 22 | user : RoaLogic 23 | repo : ahb3lite_apb_bridge 24 | patches : [files/0001-Patch-for-verilator.patch] 25 | -------------------------------------------------------------------------------- /ahb3lite_apb_bridge/files/0001-Patch-for-verilator.patch: -------------------------------------------------------------------------------- 1 | From eba3b6f0d802ee2c383e1e7275377fb34b98c225 Mon Sep 17 00:00:00 2001 2 | From: Tiny Labs Inc 3 | Date: Wed, 13 Apr 2022 13:10:54 -0600 4 | Subject: [PATCH] Patch for verilator 5 | 6 | --- 7 | rtl/verilog/ahb3lite_apb_bridge.sv | 70 ++++++++++++++---------------- 8 | 1 file changed, 32 insertions(+), 38 deletions(-) 9 | 10 | diff --git a/rtl/verilog/ahb3lite_apb_bridge.sv b/rtl/verilog/ahb3lite_apb_bridge.sv 11 | index 58d4690..3db1beb 100644 12 | --- a/rtl/verilog/ahb3lite_apb_bridge.sv 13 | +++ b/rtl/verilog/ahb3lite_apb_bridge.sv 14 | @@ -1,3 +1,4 @@ 15 | +/* verilator lint_off CASEINCOMPLETE */ 16 | ///////////////////////////////////////////////////////////////////// 17 | // ,------. ,--. ,--. // 18 | // | .--. ' ,---. ,--,--. | | ,---. ,---. `--' ,---. // 19 | @@ -130,22 +131,15 @@ module ahb3lite_apb_bridge #( 20 | initial 21 | begin 22 | //check if HRDATA/HWDATA/PRDATA/PWDATA are multiples of bytes 23 | - a1: assert (HDATA_SIZE % 8 ==0) 24 | - else $error("HDATA_SIZE must be an integer multiple of bytes (8bits)"); 25 | + a1: assert ((HDATA_SIZE % 8) ==0); 26 | + a2: assert ((PDATA_SIZE % 8) ==0); 27 | 28 | - a2: assert (PDATA_SIZE % 8 ==0) 29 | - else $error("PDATA_SIZE must be an integer multiple of bytes (8bits)"); 30 | 31 | + //Check if PDATA_SIZE <= HDATA_SIZE 32 | + a3: assert (PDATA_SIZE <= HDATA_SIZE); 33 | 34 | - //Check if PDATA_SIZE <= HDATA_SIZE 35 | - a3: assert (PDATA_SIZE <= HDATA_SIZE) 36 | - else $error("PDATA_SIZE must be less than or equal to HDATA_SIZE (PDATA_SIZE <= HDATA_SIZE"); 37 | - 38 | - 39 | - //Check SYNC_DEPTH >= 3 40 | - a4: assert (SYNC_DEPTH >= SYNC_DEPTH_MIN) 41 | - else $warning("SYNC_DEPTH=%0d is less than minimum. Changed to %0d", SYNC_DEPTH, SYNC_DEPTH_CHK); 42 | - 43 | + //Check SYNC_DEPTH >= 3 44 | + a4: assert (SYNC_DEPTH >= SYNC_DEPTH_MIN); 45 | end 46 | 47 | 48 | @@ -220,14 +214,14 @@ module ahb3lite_apb_bridge #( 49 | input [2:0] hsize; 50 | 51 | case (hsize) 52 | - HSIZE_B1024: apb_beats = 1023/PDATA_SIZE; 53 | - HSIZE_B512 : apb_beats = 511/PDATA_SIZE; 54 | - HSIZE_B256 : apb_beats = 255/PDATA_SIZE; 55 | - HSIZE_B128 : apb_beats = 127/PDATA_SIZE; 56 | - HSIZE_DWORD: apb_beats = 63/PDATA_SIZE; 57 | - HSIZE_WORD : apb_beats = 31/PDATA_SIZE; 58 | - HSIZE_HWORD: apb_beats = 15/PDATA_SIZE; 59 | - default : apb_beats = 7/PDATA_SIZE; 60 | + HSIZE_B1024: apb_beats = 7'(1023/PDATA_SIZE); 61 | + HSIZE_B512 : apb_beats = 7'(511/PDATA_SIZE); 62 | + HSIZE_B256 : apb_beats = 7'(255/PDATA_SIZE); 63 | + HSIZE_B128 : apb_beats = 7'(127/PDATA_SIZE); 64 | + HSIZE_DWORD: apb_beats = 7'(63/PDATA_SIZE); 65 | + HSIZE_WORD : apb_beats = 7'(31/PDATA_SIZE); 66 | + HSIZE_HWORD: apb_beats = 7'(15/PDATA_SIZE); 67 | + default : apb_beats = 7'(7/PDATA_SIZE); 68 | endcase 69 | endfunction //apb_beats 70 | 71 | @@ -253,7 +247,7 @@ module ahb3lite_apb_bridge #( 72 | logic [6:0] haddr_masked; 73 | 74 | //Generate masked address 75 | - haddr_masked = haddr & address_mask(HDATA_SIZE); 76 | + haddr_masked = haddr[6:0] & address_mask(HDATA_SIZE); 77 | 78 | //calculate bit-offset 79 | data_offset = 8 * haddr_masked; 80 | @@ -270,13 +264,13 @@ module ahb3lite_apb_bridge #( 81 | //get number of active lanes for a 1024bit databus (max width) for this HSIZE 82 | case (hsize) 83 | HSIZE_B1024: full_pstrb = {128{1'b1}}; 84 | - HSIZE_B512 : full_pstrb = { 64{1'b1}}; 85 | - HSIZE_B256 : full_pstrb = { 32{1'b1}}; 86 | - HSIZE_B128 : full_pstrb = { 16{1'b1}}; 87 | - HSIZE_DWORD: full_pstrb = { 8{1'b1}}; 88 | - HSIZE_WORD : full_pstrb = { 4{1'b1}}; 89 | - HSIZE_HWORD: full_pstrb = { 2{1'b1}}; 90 | - default : full_pstrb = { 1{1'b1}}; 91 | + HSIZE_B512 : full_pstrb = {128{1'b1}}; 92 | + HSIZE_B256 : full_pstrb = {128{1'b1}}; 93 | + HSIZE_B128 : full_pstrb = {128{1'b1}}; 94 | + HSIZE_DWORD: full_pstrb = {128{1'b1}}; 95 | + HSIZE_WORD : full_pstrb = {128{1'b1}}; 96 | + HSIZE_HWORD: full_pstrb = {128{1'b1}}; 97 | + default : full_pstrb = {128{1'b1}}; 98 | endcase 99 | 100 | //generate masked address 101 | @@ -427,12 +421,12 @@ module ahb3lite_apb_bridge #( 102 | apb_fsm <= ST_APB_IDLE; 103 | apb_tack <= 1'b0; 104 | apb_prdata <= 'hx; 105 | - apb_beat_cnt <= 'hx; 106 | - apb_beat_data_offset <= 'hx; 107 | - apb_pslverr <= 1'bx; 108 | + apb_beat_cnt <= 7'hx; 109 | + apb_beat_data_offset <= 10'hx; 110 | + apb_pslverr <= 1'bx; 111 | 112 | PSEL <= 1'b0; 113 | - PPROT <= 1'b0; 114 | + PPROT <= 3'b0; 115 | PADDR <= 'h0; 116 | PWRITE <= 1'b0; 117 | PENABLE <= 1'b0; 118 | @@ -451,11 +445,11 @@ module ahb3lite_apb_bridge #( 119 | 120 | PSEL <= 1'b1; 121 | PENABLE <= 1'b0; 122 | - PPROT <= ((ahb_hprot & HPROT_DATA ) ? PPROT_DATA : PPROT_INSTRUCTION) | 123 | - ((ahb_hprot & HPROT_PRIVILEGED) ? PPROT_PRIVILEGED : PPROT_NORMAL ); 124 | + PPROT <= (~|(ahb_hprot & HPROT_DATA ) ? PPROT_DATA : PPROT_INSTRUCTION) | 125 | + (~|(ahb_hprot & HPROT_PRIVILEGED) ? PPROT_PRIVILEGED : PPROT_NORMAL ); 126 | PADDR <= ahb_haddr[PADDR_SIZE-1:0]; 127 | PWRITE <= ahb_hwrite; 128 | - PWDATA <= ahb_hwdata >> data_offset(ahb_haddr); 129 | + PWDATA <= PDATA_SIZE'(ahb_hwdata >> data_offset(ahb_haddr)); 130 | PSTRB <= {PDATA_SIZE/8{ahb_hwrite}} & pstrb(ahb_hsize,ahb_haddr[PADDR_SIZE-1:0]); 131 | 132 | apb_prdata <= 'h0; //clear prdata 133 | @@ -476,7 +470,7 @@ module ahb3lite_apb_bridge #( 134 | apb_beat_cnt <= apb_beat_cnt -1; 135 | apb_beat_data_offset <= apb_beat_data_offset + PDATA_SIZE; 136 | 137 | - apb_prdata <= (apb_prdata << PDATA_SIZE) | (PRDATA << data_offset(ahb_haddr));//TODO: check/sim 138 | + apb_prdata <= (apb_prdata << PDATA_SIZE) | (HADDR_SIZE'(PRDATA) << data_offset(ahb_haddr));//TODO: check/sim 139 | apb_pslverr <= PSLVERR; 140 | 141 | PENABLE <= 1'b0; 142 | @@ -500,7 +494,7 @@ module ahb3lite_apb_bridge #( 143 | */ 144 | apb_fsm <= ST_APB_SETUP; 145 | 146 | - PADDR <= PADDR + (1 << PDATA_SIZE/8); 147 | + PADDR <= PADDR + (PDATA_SIZE/8); 148 | PWDATA <= ahb_hwdata >> apb_beat_data_offset; 149 | PSTRB <= {PDATA_SIZE/8{ahb_hwrite}} & pstrb(ahb_hsize,PADDR + (1 << ahb_hsize)); 150 | end 151 | -- 152 | 2.32.0 153 | 154 | -------------------------------------------------------------------------------- /ahb3lite_apb_bridge/files/0002-Remove-tasks-unsynthesizable-by-yosys.patch: -------------------------------------------------------------------------------- 1 | From 2d7f887fd8933d4c6b19504371a21ff335b19cfd Mon Sep 17 00:00:00 2001 2 | From: Tiny Labs Inc 3 | Date: Fri, 12 Aug 2022 10:46:15 -0600 4 | Subject: [PATCH] Remove tasks, unsynthesizable by yosys 5 | 6 | --- 7 | rtl/verilog/ahb3lite_apb_bridge.sv | 48 ++++++++++++++---------------- 8 | 1 file changed, 22 insertions(+), 26 deletions(-) 9 | 10 | diff --git a/rtl/verilog/ahb3lite_apb_bridge.sv b/rtl/verilog/ahb3lite_apb_bridge.sv 11 | index 3db1beb..5637366 100644 12 | --- a/rtl/verilog/ahb3lite_apb_bridge.sv 13 | +++ b/rtl/verilog/ahb3lite_apb_bridge.sv 14 | @@ -185,26 +185,6 @@ module ahb3lite_apb_bridge #( 15 | logic [ 9:0] apb_beat_data_offset; 16 | 17 | 18 | - ////////////////////////////////////////////////////////////////// 19 | - // 20 | - // Tasks 21 | - // 22 | - task ahb_no_transfer; 23 | - ahb_fsm <= ST_AHB_IDLE; 24 | - 25 | - HREADYOUT <= 1'b1; 26 | - HRESP <= HRESP_OKAY; 27 | - endtask //ahb_no_transfer 28 | - 29 | - 30 | - task ahb_prep_transfer; 31 | - ahb_fsm <= ST_AHB_TRANSFER; 32 | - 33 | - HREADYOUT <= 1'b0; //hold off master 34 | - HRESP <= HRESP_OKAY; 35 | - ahb_treq <= 1'b1; //request data transfer 36 | - endtask //ahb_prep_transfer 37 | - 38 | 39 | ////////////////////////////////////////////////////////////////// 40 | // 41 | @@ -214,7 +194,7 @@ module ahb3lite_apb_bridge #( 42 | input [2:0] hsize; 43 | 44 | case (hsize) 45 | - HSIZE_B1024: apb_beats = 7'(1023/PDATA_SIZE); 46 | + HSIZE_B1024: apb_beats = 7'(1023/PDATA_SIZE); 47 | HSIZE_B512 : apb_beats = 7'(511/PDATA_SIZE); 48 | HSIZE_B256 : apb_beats = 7'(255/PDATA_SIZE); 49 | HSIZE_B128 : apb_beats = 7'(127/PDATA_SIZE); 50 | @@ -323,13 +303,29 @@ module ahb3lite_apb_bridge #( 51 | * This (slave) is selected ... what kind of transfer is this? 52 | */ 53 | case (HTRANS) 54 | - HTRANS_IDLE : ahb_no_transfer; 55 | - HTRANS_BUSY : ahb_no_transfer; 56 | - HTRANS_NONSEQ: ahb_prep_transfer; 57 | - HTRANS_SEQ : ahb_prep_transfer; 58 | + HTRANS_IDLE : 59 | + HTRANS_BUSY : 60 | + begin 61 | + ahb_fsm <= ST_AHB_IDLE; 62 | + HREADYOUT <= 1'b1; 63 | + HRESP <= HRESP_OKAY; 64 | + end 65 | + HTRANS_NONSEQ: 66 | + HTRANS_SEQ : 67 | + begin 68 | + ahb_fsm <= ST_AHB_TRANSFER; 69 | + HREADYOUT <= 1'b0; //hold off master 70 | + HRESP <= HRESP_OKAY; 71 | + ahb_treq <= 1'b1; //request data transfer 72 | + end 73 | endcase //HTRANS 74 | end 75 | - else ahb_no_transfer; 76 | + else 77 | + begin 78 | + ahb_fsm <= ST_AHB_IDLE; 79 | + HREADYOUT <= 1'b1; 80 | + HRESP <= HRESP_OKAY; 81 | + end 82 | end 83 | 84 | ST_AHB_TRANSFER: 85 | -- 86 | 2.34.1 87 | 88 | -------------------------------------------------------------------------------- /ahb3lite_csr/ahb3lite_csr.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::ahb3lite_csr:0.1 3 | description: Generator for CSR AHB3 slave 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - ahb3lite_pkg 9 | files: 10 | - rtl/ahb3lite_csr.sv 11 | file_type: verilogSource 12 | 13 | targets: 14 | default: 15 | filesets: [rtl] 16 | 17 | generators: 18 | ahb3lite_csr_gen: 19 | interpreter: python3 20 | command: sw/ahb3lite_csr.py 21 | description: Generate AHB3lite CSR slave 22 | -------------------------------------------------------------------------------- /ahb3lite_csr/rtl/ahb3lite_csr.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * Configurable AHB3 CSR slave 3 | * 4 | * All rights reserved. 5 | * Tiny Labs Inc 6 | * 2020 7 | */ 8 | 9 | module ahb3lite_csr 10 | #( 11 | parameter CNT = 2 12 | ) ( 13 | // Global inputs 14 | input CLK, 15 | input RESETn, 16 | 17 | // AHB interface 18 | input HSEL, 19 | input [31:0] HADDR, 20 | input [31:0] HWDATA, 21 | input HWRITE, 22 | input [ 2:0] HSIZE, 23 | input [ 2:0] HBURST, 24 | input [ 3:0] HPROT, 25 | input [ 1:0] HTRANS, 26 | input HREADY, 27 | output logic [31:0] HRDATA, 28 | output logic HREADYOUT, 29 | output logic HRESP, 30 | 31 | // Registers 32 | input [CNT-1:0] [1:0] ACCESS, 33 | input [CNT-1:0] [31:0] REGIN, 34 | output logic [CNT-1:0] [31:0] REGOUT, 35 | output logic [CNT-1:0] STROBE 36 | ); 37 | 38 | // AHB3 defs 39 | import ahb3lite_pkg::*; 40 | 41 | // Internal signals 42 | logic we; // Write enable 43 | logic [3:0] be; // Byte enable 44 | logic [$clog2(CNT)-1:0] sel; // Register select 45 | 46 | // Strobe is delayed by 1 cycle 47 | logic [CNT-1:0] strobeq; 48 | 49 | // No wait states for this core 50 | assign HREADYOUT = 1'b1; 51 | assign HRESP = HRESP_OKAY; 52 | assign sel = HADDR[$clog2(CNT)+1:2]; 53 | 54 | // Generate byte enable 55 | assign be = (HSIZE == HSIZE_WORD) ? 4'hf : 56 | ((HSIZE == HSIZE_HWORD) ? (4'h3 << HADDR[1:0]) : 57 | 4'h1 << HADDR[1:0] 58 | ); 59 | 60 | // Generate new write value 61 | function logic [31:0] wval; 62 | input [31:0] oval, nval; 63 | input [3:0] be; 64 | for (int n=0; n < 4; n++) 65 | wval[n*8 +: 8] = be[n] ? nval[n*8 +: 8] : oval[n*8 +: 8]; 66 | endfunction : wval 67 | 68 | // Generate internal write signal 69 | always @(posedge CLK) 70 | if (HREADY) 71 | we <= HSEL & HWRITE & (HTRANS != HTRANS_BUSY) & (HTRANS != HTRANS_IDLE); 72 | else 73 | we <= 1'b0; 74 | 75 | always @(posedge CLK) 76 | begin 77 | if (~RESETn) 78 | // Allow initialization during reset 79 | for (int n = 0; n < CNT; n++) 80 | REGOUT[n] <= REGIN[n]; 81 | else 82 | begin 83 | 84 | // Strobe on access 85 | if (HSEL & (HTRANS != HTRANS_BUSY) & (HTRANS != HTRANS_IDLE)) 86 | strobeq[sel] <= 1; 87 | else 88 | strobeq[sel] <= 0; 89 | 90 | // Delayed one cycle 91 | STROBE <= strobeq; 92 | 93 | // Handle AHB writes 94 | if (we & (32'(sel) < CNT)) 95 | begin 96 | 97 | // Switch on access mode 98 | case (ACCESS[sel]) 99 | 2'b00: REGOUT[sel] <= wval (REGOUT[sel], HWDATA, be); 100 | 2'b01: ; // RO - do nothing 101 | 2'b10: REGOUT[sel] <= wval (REGOUT[sel], HWDATA, be); 102 | 2'b11: REGOUT[sel] <= REGOUT[sel] & wval (REGOUT[sel], ~HWDATA, be); 103 | endcase // case (ACCESS[sel]) 104 | 105 | end // if (we & (32'(sel) < CNT)) 106 | 107 | // Output = input unless WO or being accessed on bus 108 | for (int n = 0; n < CNT; n++) 109 | if ((ACCESS[n] != 2'b10) & ~((n == 32'(sel)) & we)) 110 | REGOUT[n] <= REGIN[n]; 111 | 112 | // Handle read 113 | if (ACCESS[sel] == 2'b10) // Write only 114 | HRDATA <= 32'h0; 115 | else 116 | HRDATA <= (32'(sel) < CNT) ? REGIN[sel] : 32'hdeadbeef; 117 | 118 | end // if (RESETn) 119 | end // always @ (posedge CLK) 120 | 121 | 122 | 123 | endmodule // ahb3lite_csr 124 | 125 | -------------------------------------------------------------------------------- /ahb3lite_csr/sw/cppwriter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # cppwriter takes a list of fields and generates a cpp header to 4 | # assist in accessing generated CSRs 5 | # 6 | # All rights reserved 7 | # Tiny Labs Inc 8 | # 2020 9 | # 10 | import zlib 11 | from ahb3lite_csr import Field, Reg 12 | 13 | #class FieldIter: 14 | # def __init__(self): 15 | # self. 16 | class CPPWriter: 17 | def __init__(self, name, field): 18 | self.name = name 19 | self.field = field 20 | self.crc = 0 21 | 22 | def header (self, cid): 23 | s = '// This file is autogenerated by csrgen - DO NOT EDIT\n' 24 | s += '#ifndef ' + cid + '\n' 25 | s += '#define ' + cid + '\n' 26 | s += '#include \n\n' 27 | s += 'typedef struct {\n' 28 | s += '\tuint32_t off;\n\tuint32_t sht;\n' 29 | s += '} ' + self.name + '_t;\n\n' 30 | return s 31 | 32 | def footer (self, cid): 33 | s = '#endif /* ' + cid + ' */\n' 34 | return s 35 | 36 | def write(self, filename): 37 | cid = filename.replace ('.', '_').upper () 38 | 39 | #print ("Writing cpp header: " + filename) 40 | with open (filename, 'w') as fh: 41 | 42 | # Write header 43 | fh.write (self.header (cid)) 44 | 45 | # Create host interface 46 | s = '#ifdef HOST_INTERFACE\n\n' 47 | 48 | # Create field defs 49 | for f in self.field: 50 | if f.count == 1: 51 | s += '#define ' + f.offset() + '\t' + str(f.rptr[0].reg.address) + '\n' 52 | s += '#define ' + f.shift() + '\t' + str(f.rptr[0].offset) + '\n' 53 | s += '#define ' + f.mask() + '\t' + hex(2 ** f.width - 1) + '\n' 54 | else: 55 | s += 'static ' + self.name + '_t ' + f.name + '_n[' + str(f.count) + '] = {\n' 56 | for n in range (f.count): 57 | s += '\t{' + str(f.rptr[n].reg.address) + ', ' + str(f.rptr[n].offset) + '},\n' 58 | s += '};\n' 59 | s += '#define ' + f.mask() + '\t' + hex(2 ** f.width - 1) + '\n' 60 | s += '#define ' + f.maximum() + '\t' + str(f.count) + '\n' 61 | 62 | self.crc = zlib.crc32 (str(f).encode('ascii'), self.crc) & 0xffffffff; 63 | 64 | # Store CRC 65 | s += '#define CRC32 ' + hex (self.crc) + '\n' 66 | 67 | # Create class 68 | s += '\nclass ' + self.name + ' {\n' 69 | s += ' private:\n' 70 | s += '\tuint32_t (*read)(uint32_t);\n' 71 | s += '\tvoid (*write)(uint32_t, uint32_t);\n' 72 | s += '\tuint32_t base;\n' 73 | s += ' public:\n' 74 | s += '\t' + self.name + ' (uint32_t base, uint32_t (*read)(uint32_t), void (*write)(uint32_t, uint32_t)) {\n' 75 | s += '\t\tthis->read = read;\n' 76 | s += '\t\tthis->write = write;\n' 77 | s += '\t\tthis->base = base;\n' 78 | s += '\t}\n' 79 | 80 | # Generate field accessors 81 | for f in self.field: 82 | # Read accessor 83 | if f.rtype != 'wo': 84 | if f.count == 1: 85 | s += '\tuint32_t ' + f.name + ' (void) {\n' 86 | s += '\t\treturn (read (base + ' + f.offset() + ') ' 87 | s += '>> ' + f.shift() + ') & ' + f.mask() + ';\n' 88 | s += '\t}\n' 89 | else: 90 | s += '\tuint32_t ' + f.name + ' (uint32_t idx) {\n' 91 | s += '\t\tif (idx >= ' + f.maximum() + ') return 0;\n' 92 | s += '\t\treturn (read (base + ' + f.name + '_n[idx].off) ' 93 | s += '>> ' + f.name + '_n[idx].sht) & ' + f.mask() + ';\n' 94 | s += '\t}\n' 95 | 96 | # Write accesor ie: read/modify/write 97 | if f.rtype != 'ro': 98 | if f.count == 1: 99 | s += '\tvoid ' + f.name + ' (uint32_t val) {\n' 100 | if (f.width != 32) and (f.rtype != 'wo'): 101 | # Read 102 | s += '\t\tuint32_t p = read (base + ' + f.offset() + ');\n' 103 | # Modify 104 | s += '\t\tp &= ~(' + f.mask() + ' << ' + f.shift() + ');\n' 105 | s += '\t\tp |= ((val & ' + f.mask() + ') << ' + f.shift() + ');\n' 106 | # Write 107 | s += '\t\twrite (base + ' + f.offset() + ', p);\n' 108 | s += '\t}\n' 109 | else: 110 | # Write 111 | s += '\t\twrite (base + ' + f.offset() + ', val << ' + f.shift() + ');\n' 112 | s += '\t}\n' 113 | 114 | else: 115 | s += '\tvoid ' + f.name + ' (uint32_t idx, uint32_t val) {\n' 116 | s += '\t\tif (idx >= ' + f.maximum() + ') return;\n' 117 | if (f.width != 32) and (f.rtype != 'wo'): 118 | # Read 119 | s += '\t\tuint32_t p = read (base + ' + f.name + '_n[idx].off);\n' 120 | # Modify 121 | s += '\t\tp &= ~(' + f.mask() + ' << ' + f.name + '_n[idx].sht);\n' 122 | s += '\t\tp |= ((val & ' + f.mask() + ') << ' + f.name + '_n[idx].sht);\n' 123 | # Write 124 | s += '\t\twrite (base + ' + f.name + '_n[idx].off, p);\n' 125 | s += '\t}\n' 126 | else: 127 | # Write 128 | s += '\t\twrite (base + ' + f.name + '_n[idx].off, val << ' + f.name + '_n[idx].sht);\n' 129 | s += '\t}\n' 130 | 131 | 132 | # Close class 133 | s += '};\n\n' 134 | s += '#else /* !HOST_INTERFACE */\n\n' 135 | fh.write (s) 136 | 137 | # Create target interface 138 | s = 'typedef struct {\n' 139 | reg = None 140 | pwidth = 32 141 | for f in self.field: 142 | if f.rptr[0].reg is not reg: 143 | if pwidth != 32: 144 | s += '\tuint32_t :0;\n' 145 | reg = f.rptr[0].reg 146 | pwidth = f.width 147 | if f.count == 1: 148 | s += '\t/* ' + f.rtype + ' */ volatile uint32_t ' + f.name 149 | else: 150 | s += '\t/* ' + f.rtype + ' */ volatile uint32_t ' + f.name + '[' + str(f.count) + ']' 151 | if f.width != 32: 152 | s += ' : ' + str(f.width) + ';\n' 153 | else: 154 | s += ';\n' 155 | s += '} ' + self.name + ';\n\n' 156 | s += '#endif /* !HOST_INTERFACE */\n' 157 | fh.write (s) 158 | 159 | # Write footer 160 | fh.write (self.footer (cid)) 161 | 162 | -------------------------------------------------------------------------------- /ahb3lite_csr/sw/verilogwriter.py: -------------------------------------------------------------------------------- 1 | class Signal(object): 2 | def __init__(self, name, width=0, low=0, asc=False, prepend=''): 3 | self.name = name 4 | self.width=width 5 | self.low = low 6 | self.asc = asc 7 | self.prepend = prepend 8 | 9 | def range(self): 10 | if self.width > 0: 11 | l = self.width+self.low-1 12 | r = self.low 13 | if self.asc: 14 | return '['+str(r)+':'+str(l)+']' 15 | else: 16 | return '['+str(l)+':'+str(r)+']' 17 | return '' 18 | 19 | class Wire(Signal): 20 | def write(self, width): 21 | return 'wire{range} {prepend} {name};\n'.format(range=self.range().rjust(width), name=self.name, prepend=self.prepend) 22 | 23 | class Logic(Signal): 24 | def write(self, width): 25 | return 'logic{range} {name};\n'.format(range=self.range().rjust(width), name=self.name) 26 | 27 | class ModulePort(Signal): 28 | def __init__(self, name, dir, width=0, low=0, asc=False): 29 | super(ModulePort, self).__init__(name, width, low, asc) 30 | self.dir = dir 31 | 32 | def write(self, range_width=0): 33 | return '{dir} {range} {name}'.format(dir=self.dir.ljust(6), range=self.range().rjust(range_width), name=self.name) 34 | 35 | class LocalParam: 36 | def __init__(self, name, val): 37 | self.name = name 38 | self.val = val 39 | def write(self): 40 | return 'localparam {name} = {val};\n'.format (name=self.name, val=self.val) 41 | 42 | class Assign: 43 | def __init__(self, name, val, width=0): 44 | self.name = name 45 | self.val = val 46 | self.width = width 47 | def convert(self): 48 | if self.width: 49 | return '{0}\'h{1}'.format (self.width, hex((self.val + (1 << self.width)) % (1 << self.width))[2:]) 50 | else: 51 | return self.val 52 | def write(self): 53 | return 'assign {name} = {val};\n'.format (name=self.name, val=self.convert()) 54 | 55 | class Instance: 56 | def __init__(self, module, name, parameters, ports): 57 | self.module = module 58 | self.name = name 59 | self.parameters = parameters 60 | self.ports = ports 61 | 62 | def write(self): 63 | s = self.module 64 | if self.parameters: 65 | max_len = max([len(p.name) for p in self.parameters]) 66 | s += '\n #(' 67 | s += ',\n '.join(['.' + p.name.ljust(max_len) +' (' + str(p.value) + ')' for p in self.parameters]) 68 | s += ')\n' 69 | s += ' ' + self.name 70 | 71 | if self.ports: 72 | s += '\n (' 73 | max_len = max([len(p.name) for p in self.ports]) 74 | s += ',\n '.join(['.' + p.name.ljust(max_len) +' (' + str(p.value) + ')' for p in self.ports]) 75 | s += ')' 76 | s += ';\n' 77 | return s 78 | 79 | class VerilogWriter: 80 | def __init__(self, name): 81 | self.name = name 82 | self.instances = [] 83 | self.ports = [] 84 | self.wires = [] 85 | self.lp = [] 86 | self.assign = [] 87 | self.logic = [] 88 | 89 | def add(self, obj): 90 | if isinstance(obj, Instance): 91 | self.instances += [obj] 92 | elif isinstance(obj, ModulePort): 93 | self.ports += [obj] 94 | elif isinstance(obj, Wire): 95 | self.wires += [obj] 96 | elif isinstance(obj, Logic): 97 | self.logic += [obj] 98 | elif isinstance(obj, LocalParam): 99 | self.lp += [obj] 100 | elif isinstance(obj, Assign): 101 | self.assign += [obj] 102 | else: 103 | raise Exception("Invalid type!" + str(obj)) 104 | 105 | def write(self, file=None): 106 | s = ("// THIS FILE IS AUTOGENERATED BY ahb3lite_csr_gen\n" 107 | "// ANY MANUAL CHANGES WILL BE LOST\n") 108 | if self.ports: 109 | s += "module {name}\n".format(name=self.name) 110 | max_len = max([len(p.range()) for p in self.ports]) 111 | s += ' (' 112 | s += ',\n '.join([p.write(max_len) for p in self.ports]) 113 | s += ')' 114 | s += ';\n\n' 115 | if self.lp: 116 | for lp in self.lp: 117 | s += lp.write () 118 | s += '\n' 119 | if self.wires: 120 | max_len = max([len(w.range()) for w in self.wires]) 121 | for w in self.wires: 122 | s += w.write(max_len + 1) 123 | s +='\n' 124 | if self.logic: 125 | max_len = max([len(w.range()) for w in self.logic]) 126 | for w in self.logic: 127 | s += w.write(max_len + 1) 128 | s +='\n' 129 | if self.assign: 130 | for a in self.assign: 131 | s += a.write () 132 | s += '\n' 133 | for i in self.instances: 134 | s += i.write() 135 | s += '\n' 136 | if self.ports: 137 | s += 'endmodule\n' 138 | if file is None: 139 | return s 140 | else: 141 | f = open(file,'w') 142 | f.write(s) 143 | -------------------------------------------------------------------------------- /ahb3lite_debug_bridge/ahb3lite_debug_bridge.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::ahb3lite_debug_bridge:0.1 3 | description: Bridges AHB3lite to external target via ADIv5 SWD/JTAG phy 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - ahb3lite_pkg 9 | - ahb3lite_default_slave 10 | - arm_debug 11 | files: 12 | - rtl/ahb3lite_debug_bridge.sv 13 | file_type : verilogSource 14 | 15 | targets: 16 | default: 17 | filesets : [rtl] 18 | -------------------------------------------------------------------------------- /ahb3lite_default_slave/ahb3lite_default_slave.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::ahb3lite_default_slave:0.1 3 | description: Default slave to return invalid response 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - ahb3lite_pkg 9 | files: 10 | - rtl/ahb3lite_default_slave.sv 11 | file_type : verilogSource 12 | 13 | targets: 14 | default: 15 | filesets : [rtl] 16 | -------------------------------------------------------------------------------- /ahb3lite_default_slave/rtl/ahb3lite_default_slave.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * AHB3lite default slave - Handle non-matching requests and return ERROR. 3 | * 4 | * Tiny Labs Inc 5 | * 2020 6 | */ 7 | 8 | module ahb3lite_default_slave 9 | ( 10 | input CLK, 11 | input RESETn, 12 | // AHB3 interface (not all signals needed) 13 | input HSEL, 14 | input [1:0] HTRANS, 15 | input HREADY, 16 | output logic HREADYOUT, 17 | output logic HRESP, 18 | output logic [31:0] HRDATA 19 | ); 20 | 21 | import ahb3lite_pkg::*; 22 | 23 | logic active; 24 | 25 | /* Simple state machine - just return error according to AHB3 spec */ 26 | always @(posedge CLK) 27 | begin 28 | if (!RESETn) 29 | begin 30 | HREADYOUT <= 1; 31 | HRESP <= HRESP_OKAY; 32 | HRDATA <= 32'h0; 33 | active <= 0; 34 | end 35 | else 36 | begin 37 | if (HREADY & HSEL && (HTRANS != HTRANS_BUSY) && (HTRANS != HTRANS_IDLE)) 38 | begin 39 | HREADYOUT <= 0; 40 | active <= 1; 41 | end 42 | else if (active) 43 | begin 44 | if (HRESP & HREADYOUT) 45 | begin 46 | HRESP <= 0; 47 | active <= 0; 48 | end 49 | else if (HRESP) 50 | HREADYOUT <= 1; 51 | else if (!HREADYOUT) 52 | HRESP <= 1; 53 | end 54 | end 55 | end 56 | 57 | endmodule // ahb3lite_dslave 58 | -------------------------------------------------------------------------------- /ahb3lite_host_master/ahb3lite_host_master.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::ahb3lite_host_master:1.0 3 | 4 | filesets: 5 | rtl: 6 | depend: 7 | - ahb3lite_pkg 8 | - host_fifo_pkg 9 | files: 10 | - rtl/ahb3lite_host_master.sv 11 | file_type : verilogSource 12 | 13 | targets: 14 | default: 15 | description: Host interface to AHB3lite master 16 | filesets : [rtl] 17 | -------------------------------------------------------------------------------- /ahb3lite_host_slave/ahb3lite_host_slave.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::ahb3lite_host_slave:1.0 3 | 4 | filesets: 5 | rtl: 6 | depend: 7 | - host_fifo_pkg 8 | - ahb3lite_pkg 9 | - ahb3lite_default_slave 10 | files: 11 | - rtl/ahb3lite_host_slave.sv 12 | file_type : verilogSource 13 | 14 | targets: 15 | default: 16 | description: Host interface to AHB3lite slave 17 | filesets : [rtl] 18 | -------------------------------------------------------------------------------- /ahb3lite_intercon/ahb3lite_intercon.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::ahb3lite_intercon:1.1-r1 3 | description: Generate AHB3lite interconnect from memory map 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - ahb3lite_pkg 9 | files: 10 | - rtl/verilog/ahb3lite_interconnect.sv 11 | - rtl/verilog/ahb3lite_interconnect_master_port.sv 12 | - rtl/verilog/ahb3lite_interconnect_slave_port.sv 13 | - rtl/verilog/ahb3lite_interconnect_slave_priority.sv 14 | file_type : verilogSource 15 | 16 | license: 17 | files: 18 | - LICENSE.md 19 | file_type : user 20 | 21 | targets: 22 | default: 23 | filesets : [rtl, license] 24 | 25 | generators: 26 | ahb3lite_intercon_gen: 27 | interpreter : python3 28 | command : sw/ahb3lite_intercon.py 29 | description: Generate AHB3lite interconnect from memory map 30 | 31 | provider: 32 | name : github 33 | user : RoaLogic 34 | repo : ahb3lite_interconnect 35 | patches : [files/0001-Add-default-route.patch, 36 | files/0002-Add-fusesoc-generators.patch, 37 | files/0003-Remove-recursive-function-def-for-verilator.patch, 38 | files/0004-Lint-off-1-delay.patch] 39 | -------------------------------------------------------------------------------- /ahb3lite_intercon/files/0001-Add-default-route.patch: -------------------------------------------------------------------------------- 1 | From 420bdc120e365319c77cf69e6d7175ac97537dd2 Mon Sep 17 00:00:00 2001 2 | From: Tiny Labs Inc 3 | Date: Sun, 3 Apr 2022 17:28:52 -0600 4 | Subject: [PATCH] Add default route 5 | 6 | --- 7 | rtl/verilog/ahb3lite_interconnect_master_port.sv | 16 ++++++++++++++-- 8 | 1 file changed, 14 insertions(+), 2 deletions(-) 9 | 10 | diff --git a/rtl/verilog/ahb3lite_interconnect_master_port.sv b/rtl/verilog/ahb3lite_interconnect_master_port.sv 11 | index 2b975b3..4efa4d3 100644 12 | --- a/rtl/verilog/ahb3lite_interconnect_master_port.sv 13 | +++ b/rtl/verilog/ahb3lite_interconnect_master_port.sv 14 | @@ -145,6 +145,8 @@ module ahb3lite_interconnect_master_port #( 15 | 16 | logic [SLAVES -1:0] current_HSEL, //current-cycle addressed slave 17 | pending_HSEL, //pending-cycle addressed slave 18 | + current_HSELx, 19 | + pending_HSELx, 20 | error_masked_HSEL, //generate error when accessing masked slave 21 | error_no_slave; //generate error when accessing non-mapped memory region 22 | logic error_response; //generate error response 23 | @@ -348,10 +350,10 @@ module ahb3lite_interconnect_master_port #( 24 | generate 25 | for (s=0; s 0) 36 | RESET_CTR <= RESET_CTR - 1; 37 | end 38 | 39 | assign RESETn = (RESET_CTR != 0) ? 0 : 1; 40 | end // block: gen_reset_hold 41 | else begin : gen_reset_hold 42 | assign RESETn = RESET; 43 | end 44 | endgenerate 45 | 46 | // Master test vector 47 | ahb3lite_mvec 48 | #( 49 | .SLAVE_ADDR (0), 50 | .SLAVE_SIZE (MEM0_SZ), 51 | .SEED ('hDEADBEEF) 52 | ) u_mvec0 53 | ( 54 | .CLK (CLK), 55 | .RESETn (RESETn), 56 | .HADDR (ahb3_mvec0_HADDR), 57 | .HWDATA (ahb3_mvec0_HWDATA), 58 | .HWRITE (ahb3_mvec0_HWRITE), 59 | .HSIZE (ahb3_mvec0_HSIZE), 60 | .HBURST (ahb3_mvec0_HBURST), 61 | .HPROT (ahb3_mvec0_HPROT), 62 | .HTRANS (ahb3_mvec0_HTRANS), 63 | .HRDATA (ahb3_mvec0_HRDATA), 64 | .HRESP (ahb3_mvec0_HRESP), 65 | .HREADY (ahb3_mvec0_HREADY), 66 | // Outputs 67 | .PASS (pass0), 68 | .FAIL (fail0) 69 | ); 70 | assign ahb3_mvec0_HSEL = 1'b1; 71 | assign ahb3_mvec0_HMASTLOCK = 1'b0; 72 | 73 | // Master test vector 74 | ahb3lite_mvec 75 | #( 76 | .SLAVE_ADDR ('h1000), 77 | .SLAVE_SIZE (MEM1_SZ), 78 | .SEED ('hCAFED00D) 79 | ) u_mvec1 80 | ( 81 | .CLK (CLK), 82 | .RESETn (RESETn), 83 | .HADDR (ahb3_mvec1_HADDR), 84 | .HWDATA (ahb3_mvec1_HWDATA), 85 | .HWRITE (ahb3_mvec1_HWRITE), 86 | .HSIZE (ahb3_mvec1_HSIZE), 87 | .HBURST (ahb3_mvec1_HBURST), 88 | .HPROT (ahb3_mvec1_HPROT), 89 | .HTRANS (ahb3_mvec1_HTRANS), 90 | .HRDATA (ahb3_mvec1_HRDATA), 91 | .HRESP (ahb3_mvec1_HRESP), 92 | .HREADY (ahb3_mvec1_HREADY), 93 | // Outputs 94 | .PASS (pass1), 95 | .FAIL (fail1) 96 | ); 97 | assign ahb3_mvec1_HSEL = 1'b1; 98 | assign ahb3_mvec1_HMASTLOCK = 1'b0; 99 | 100 | 101 | // Delcare peripherals here 102 | ahb3lite_sram1rw 103 | #( 104 | .MEM_SIZE (MEM0_SZ), 105 | .HADDR_SIZE (32), 106 | .HDATA_SIZE (32), 107 | .TECHNOLOGY ("GENERIC"), 108 | .REGISTERED_OUTPUT ("NO") 109 | ) u_mem0 ( 110 | .HCLK (CLK), 111 | .HRESETn (RESETn), 112 | .HSEL (ahb3_bram0_HSEL), 113 | .HADDR (ahb3_bram0_HADDR), 114 | .HWDATA (ahb3_bram0_HWDATA), 115 | .HRDATA (ahb3_bram0_HRDATA), 116 | .HWRITE (ahb3_bram0_HWRITE), 117 | .HSIZE (ahb3_bram0_HSIZE), 118 | .HBURST (ahb3_bram0_HBURST), 119 | .HPROT (ahb3_bram0_HPROT), 120 | .HTRANS (ahb3_bram0_HTRANS), 121 | .HREADYOUT (ahb3_bram0_HREADYOUT), 122 | .HREADY (ahb3_bram0_HREADY), 123 | .HRESP (ahb3_bram0_HRESP) 124 | ); 125 | 126 | ahb3lite_sram1rw 127 | #( 128 | .MEM_SIZE (MEM1_SZ), 129 | .HADDR_SIZE (32), 130 | .HDATA_SIZE (32), 131 | .TECHNOLOGY ("GENERIC"), 132 | .REGISTERED_OUTPUT ("NO") 133 | ) u_mem1 ( 134 | .HCLK (CLK), 135 | .HRESETn (RESETn), 136 | .HSEL (ahb3_bram1_HSEL), 137 | .HADDR (ahb3_bram1_HADDR), 138 | .HWDATA (ahb3_bram1_HWDATA), 139 | .HRDATA (ahb3_bram1_HRDATA), 140 | .HWRITE (ahb3_bram1_HWRITE), 141 | .HSIZE (ahb3_bram1_HSIZE), 142 | .HBURST (ahb3_bram1_HBURST), 143 | .HPROT (ahb3_bram1_HPROT), 144 | .HTRANS (ahb3_bram1_HTRANS), 145 | .HREADYOUT (ahb3_bram1_HREADYOUT), 146 | .HREADY (ahb3_bram1_HREADY), 147 | .HRESP (ahb3_bram1_HRESP) 148 | ); 149 | 150 | endmodule // intercon_test 151 | -------------------------------------------------------------------------------- /ahb3lite_irq_slave/ahb3lite_irq_slave.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::ahb3lite_irq_slave:0.1 3 | 4 | filesets: 5 | rtl: 6 | files: 7 | - rtl/ahb3lite_irq_slave.sv 8 | file_type : verilogSource 9 | 10 | irq_slave_dep: 11 | depend: 12 | - ahb3lite_csr 13 | 14 | generate: 15 | irq_slave: 16 | generator: ahb3lite_csr_gen 17 | parameters: 18 | instance: 19 | registers: 20 | edge: 21 | width: 32 22 | type: rw 23 | count: 8 24 | level: 25 | width: 32 26 | type: rw 27 | count: 8 28 | 29 | targets: 30 | default: 31 | filesets : [irq_slave_dep, rtl] 32 | generate: [irq_slave] 33 | description: AHB3 slave to generate IRQs 34 | 35 | -------------------------------------------------------------------------------- /ahb3lite_irq_slave/rtl/ahb3lite_irq_slave.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * Expose registers to generate IRQs. These registers are split between edge 3 | * IRQs and level IRQs. 4 | * 5 | * uint32_t edge[IRQ_CNT/32]; // WO 6 | * uint32_t level[IRQ_CNT/32]; // RW 7 | * 8 | * All rights reserved. 9 | * Tiny Labs Inc 10 | * 2020 11 | */ 12 | 13 | module ahb3lite_irq_slave 14 | #( 15 | parameter IRQ_CNT = 240 16 | ) ( 17 | input CLK, 18 | input RESETn, 19 | // AHB interface 20 | input HSEL, 21 | input HWRITE, 22 | input HREADY, 23 | input [31:0] HADDR, 24 | input [1:0] HTRANS, 25 | input [2:0] HSIZE, 26 | input [2:0] HBURST, 27 | input [3:0] HPROT, 28 | input [31:0] HWDATA, 29 | output [31:0] HRDATA, 30 | output HRESP, 31 | output HREADYOUT, 32 | // IRQ output 33 | output logic [IRQ_CNT-1:0] IRQ 34 | ); 35 | 36 | // Autogen CSRs 37 | // With empty instance it will connect to default AHB3 interface signals 38 | `include "irq_slave.vh" 39 | 40 | // Maintain IRQ 41 | for (genvar n = 0; n < IRQ_CNT / 32; n++) 42 | begin 43 | assign IRQ[n*32+31:n*32] = level_o[n] | edge_o[n]; 44 | 45 | // Maintain level over time 46 | assign level_i[n] = level_o[n]; 47 | assign edge_i[n] = 32'h0; 48 | end 49 | endmodule // ahb3lite_irq_slave 50 | 51 | 52 | -------------------------------------------------------------------------------- /ahb3lite_memory/ahb3lite_memory.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::ahb3lite_memory:1.0 3 | description: Generate AHB3lite memory 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - ahb3lite_pkg 9 | - roalogic_memory 10 | files: 11 | - rtl/verilog/ahb3lite_sram1rw.sv 12 | file_type : verilogSource 13 | 14 | license: 15 | files: 16 | - LICENSE.md 17 | file_type : user 18 | 19 | targets: 20 | default: 21 | filesets : [rtl, license] 22 | 23 | provider: 24 | name : github 25 | user : RoaLogic 26 | repo : ahb3lite_memory 27 | patches: [files/0001-Remove-async-reset.patch, 28 | files/0002-Fix-verilator-linting.patch, 29 | files/0003-Fix-blocking-assignment.patch] 30 | -------------------------------------------------------------------------------- /ahb3lite_memory/files/0001-Remove-async-reset.patch: -------------------------------------------------------------------------------- 1 | From d5e4f2c0dc4525ce4e3a49ae6c1ceb0c1cc8fef5 Mon Sep 17 00:00:00 2001 2 | From: Tiny Labs Inc 3 | Date: Sun, 3 Apr 2022 16:01:12 -0600 4 | Subject: [PATCH] Remove async reset 5 | 6 | --- 7 | rtl/verilog/ahb3lite_sram1rw.sv | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/rtl/verilog/ahb3lite_sram1rw.sv b/rtl/verilog/ahb3lite_sram1rw.sv 11 | index f2ce91c..6b91f09 100644 12 | --- a/rtl/verilog/ahb3lite_sram1rw.sv 13 | +++ b/rtl/verilog/ahb3lite_sram1rw.sv 14 | @@ -374,7 +374,7 @@ generate 15 | end 16 | else 17 | begin 18 | - always @(posedge HCLK,negedge HRESETn) 19 | + always @(posedge HCLK) 20 | if (!HRESETn ) HREADYOUT <= 1'b1; 21 | else if ( ahb_noseq && ahb_read & HREADYOUT) HREADYOUT <= 1'b0; 22 | else HREADYOUT <= 1'b1; 23 | -- 24 | 2.32.0 25 | 26 | -------------------------------------------------------------------------------- /ahb3lite_memory/files/0002-Fix-verilator-linting.patch: -------------------------------------------------------------------------------- 1 | From c050a4202e0813adc8d79e323bc36799ea937696 Mon Sep 17 00:00:00 2001 2 | From: Tiny Labs Inc 3 | Date: Sun, 3 Apr 2022 17:54:04 -0600 4 | Subject: [PATCH] Fix verilator linting 5 | 6 | --- 7 | rtl/verilog/ahb3lite_sram1rw.sv | 16 ++++++++-------- 8 | 1 file changed, 8 insertions(+), 8 deletions(-) 9 | 10 | diff --git a/rtl/verilog/ahb3lite_sram1rw.sv b/rtl/verilog/ahb3lite_sram1rw.sv 11 | index 6b91f09..d5e2986 100644 12 | --- a/rtl/verilog/ahb3lite_sram1rw.sv 13 | +++ b/rtl/verilog/ahb3lite_sram1rw.sv 14 | @@ -173,17 +173,17 @@ module ahb3lite_sram1rw #( 15 | //get number of active lanes for a 1024bit databus (max width) for this HSIZE 16 | case (hsize) 17 | HSIZE_B1024: full_be = {128{1'b1}}; 18 | - HSIZE_B512 : full_be = { 64{1'b1}}; 19 | - HSIZE_B256 : full_be = { 32{1'b1}}; 20 | - HSIZE_B128 : full_be = { 16{1'b1}}; 21 | - HSIZE_DWORD: full_be = { 8{1'b1}}; 22 | - HSIZE_WORD : full_be = { 4{1'b1}}; 23 | - HSIZE_HWORD: full_be = { 2{1'b1}}; 24 | - default : full_be = { 1{1'b1}}; 25 | + HSIZE_B512 : full_be = {128{1'b1}}; 26 | + HSIZE_B256 : full_be = {128{1'b1}}; 27 | + HSIZE_B128 : full_be = {128{1'b1}}; 28 | + HSIZE_DWORD: full_be = {128{1'b1}}; 29 | + HSIZE_WORD : full_be = {128{1'b1}}; 30 | + HSIZE_HWORD: full_be = {128{1'b1}}; 31 | + default : full_be = {128{1'b1}}; 32 | endcase 33 | 34 | //generate masked address 35 | - haddr_masked = haddr & address_offset(); 36 | + haddr_masked = haddr[6:0] & address_offset(); 37 | 38 | //create byte-enable 39 | gen_be = full_be[BE_SIZE-1:0] << haddr_masked; 40 | -- 41 | 2.32.0 42 | 43 | -------------------------------------------------------------------------------- /ahb3lite_memory/files/0003-Fix-blocking-assignment.patch: -------------------------------------------------------------------------------- 1 | From 99a8906fbd5925167d7f85300498b4d78dc3ce46 Mon Sep 17 00:00:00 2001 2 | From: Tiny Labs Inc 3 | Date: Sun, 3 Apr 2022 17:59:25 -0600 4 | Subject: [PATCH] Fix blocking assignment 5 | 6 | --- 7 | rtl/verilog/ahb3lite_sram1rw.sv | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/rtl/verilog/ahb3lite_sram1rw.sv b/rtl/verilog/ahb3lite_sram1rw.sv 11 | index d5e2986..7c805f8 100644 12 | --- a/rtl/verilog/ahb3lite_sram1rw.sv 13 | +++ b/rtl/verilog/ahb3lite_sram1rw.sv 14 | @@ -368,7 +368,7 @@ module ahb3lite_sram1rw #( 15 | generate 16 | if (REGISTERED_OUTPUT == "NO") 17 | begin 18 | - always_comb HREADYOUT <= 1'b1; 19 | + always_comb HREADYOUT = 1'b1; 20 | 21 | always_comb HRDATA = contention ? dout_local : dout; 22 | end 23 | -- 24 | 2.32.0 25 | 26 | -------------------------------------------------------------------------------- /ahb3lite_mvec/ahb3lite_mvec.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::ahb3lite_mvec:0.1 3 | description: AHB3 master read/write test vector 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - ahb3lite_pkg 9 | files: 10 | - rtl/ahb3lite_mvec.sv 11 | file_type : verilogSource 12 | 13 | targets: 14 | default: 15 | filesets : [rtl] 16 | -------------------------------------------------------------------------------- /ahb3lite_mvec/rtl/ahb3lite_mvec.sv: -------------------------------------------------------------------------------- 1 | // AHB3 master test vector 2 | 3 | module ahb3lite_mvec #( 4 | // LFSR params 5 | parameter WIDTH = 32, 6 | parameter SEED = 32'hdeadbeef, 7 | parameter POLY = 32'h00200007, 8 | // Slave size params 9 | parameter SLAVE_ADDR = 0, 10 | parameter SLAVE_SIZE = 1024 11 | ) 12 | ( 13 | // Global signals 14 | input CLK, 15 | input RESETn, 16 | 17 | // AHB master interface 18 | output logic [31:0] HADDR, 19 | output logic [31:0] HWDATA, 20 | output logic HWRITE, 21 | output logic [2:0] HSIZE, 22 | output logic [2:0] HBURST, 23 | output logic [3:0] HPROT, 24 | output logic [1:0] HTRANS, 25 | input [31:0] HRDATA, 26 | input HRESP, 27 | input HREADY, 28 | 29 | output logic PASS, 30 | output logic FAIL 31 | ); 32 | 33 | import ahb3lite_pkg::*; 34 | 35 | // LFSR state 36 | logic [WIDTH-1:0] lfsr; 37 | 38 | // Slave state 39 | typedef enum { 40 | STATE_WRITE, 41 | STATE_VERIFY 42 | } state_t; 43 | state_t state; 44 | logic [31:0] addr; 45 | 46 | 47 | always @(posedge CLK) 48 | begin 49 | if (!RESETn) 50 | begin 51 | lfsr <= SEED; 52 | addr <= SLAVE_ADDR; 53 | state <= STATE_WRITE; 54 | PASS <= 0; 55 | FAIL <= 0; 56 | HTRANS <= HTRANS_IDLE; 57 | end 58 | else if (!FAIL) 59 | begin 60 | 61 | // Put transaction on bus 62 | if (HREADY && (addr < (SLAVE_ADDR + SLAVE_SIZE))) 63 | begin 64 | HADDR <= addr; 65 | HBURST <= 0; 66 | HPROT <= 3; 67 | HSIZE <= HSIZE_B32; 68 | HTRANS <= HTRANS_NONSEQ; 69 | HWRITE <= (state == STATE_WRITE) ? 1 : 0; 70 | addr <= addr + 4; 71 | end // if (HREADY) 72 | 73 | // Read/write pipelined data 74 | if ((HTRANS != HTRANS_IDLE) & HREADY) 75 | begin 76 | 77 | if (state == STATE_WRITE) 78 | HWDATA <= lfsr; 79 | else if ((HADDR > SLAVE_ADDR) && (HRDATA != lfsr)) 80 | FAIL <= 1; 81 | 82 | // Increment LFSR 83 | if (HREADY && 84 | (state != STATE_VERIFY) || 85 | (addr > (SLAVE_ADDR + 4))) 86 | begin 87 | lfsr[(WIDTH-2):0] <= lfsr[(WIDTH-1):1]; 88 | lfsr[WIDTH-1] <= ^(lfsr & POLY); 89 | end 90 | 91 | // Move to IDLE when complete 92 | if (addr >= (SLAVE_ADDR + SLAVE_SIZE)) 93 | begin 94 | HTRANS <= HTRANS_IDLE; 95 | if (state == STATE_WRITE) 96 | begin 97 | state <= STATE_VERIFY; 98 | addr <= SLAVE_ADDR; 99 | lfsr <= SEED; 100 | end 101 | end 102 | end // if ((HTRANS != HTRANS_IDLE) & HREADY) 103 | 104 | // Success 105 | if ((addr == (SLAVE_ADDR + SLAVE_SIZE)) && 106 | (state == STATE_VERIFY) && 107 | (HTRANS == HTRANS_IDLE)) 108 | PASS <= 1; 109 | 110 | end // else: !if(!RESETn) 111 | end // always @ (posedge CLK) 112 | 113 | endmodule // ahb3lite_mvec 114 | -------------------------------------------------------------------------------- /ahb3lite_pkg/ahb3lite_pkg.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name : ::ahb3lite_pkg:1.0 3 | 4 | filesets: 5 | rtl: 6 | files: 7 | - rtl/verilog/ahb3lite_pkg.sv 8 | file_type : verilogSource 9 | 10 | targets: 11 | default: 12 | filesets : [rtl] 13 | 14 | provider: 15 | name : github 16 | user : RoaLogic 17 | repo : ahb3lite_pkg 18 | -------------------------------------------------------------------------------- /ahb3lite_remote_bridge/ahb3lite_remote_bridge.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::ahb3lite_remote_bridge:0.1 3 | description: Bridges AHB3lite to external target via SWD/JTAG 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - ahb3lite_pkg 9 | - cdc_utils 10 | files: 11 | - rtl/ahb3lite_remote_bridge.sv 12 | - rtl/clkdiv.sv 13 | - rtl/swd_if.sv 14 | - rtl/swd_phy.sv 15 | file_type : verilogSource 16 | 17 | targets: 18 | default: 19 | filesets : [rtl] 20 | -------------------------------------------------------------------------------- /ahb3lite_remote_bridge/rtl/clkdiv.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * CLK divisor for JTAG/SWD 3 | * 4 | * All rights reserved. 5 | * Tiny Labs Inc 6 | * 2020 7 | */ 8 | 9 | module clkdiv 10 | ( 11 | input CLKIN, 12 | input RESETn, 13 | input [4:0] DIV, 14 | output logic CLKOUT 15 | ); 16 | 17 | logic [4:0] ctr; 18 | 19 | // CLKOUT DIVISOR 20 | // 0 = DIV2 21 | // 1 = DIV4 22 | // 2 = DIV6 23 | // 3 = DIV8 24 | // 4 = DIV10 25 | // 5 = DIV12 26 | // 6 = DIV14 27 | // 7 = DIV16 28 | // 8 = DIV18 29 | // 9 = DIV20 30 | // 10 = DIV22 31 | // 11 = DIV24 32 | // 12 = DIV26 33 | // 13 = DIV28 34 | // 14 = DIV30 35 | // 15 = DIV32 36 | // 16 = DIV34 37 | // 17 = DIV36 38 | // 18 = DIV38 39 | // 19 = DIV40 40 | // 20 = DIV42 41 | // 21 = DIV44 42 | // 22 = DIV46 43 | // 23 = DIV48 44 | // 24 = DIV50 45 | // 25 = DIV52 46 | // 26 = DIV54 47 | // 27 = DIV56 48 | // 28 = DIV58 49 | // 29 = DIV60 50 | // 30 = DIV61 51 | // 31 = DIV62 52 | always @(posedge CLKIN) 53 | begin 54 | if (!RESETn) 55 | begin 56 | ctr <= 0; 57 | CLKOUT <= 0; 58 | end 59 | else 60 | begin 61 | 62 | // Flip 63 | if (ctr == DIV) 64 | begin 65 | CLKOUT <= ~CLKOUT; 66 | ctr <= 0; 67 | end 68 | else 69 | // Increment counter 70 | ctr <= ctr + 1; 71 | end 72 | end 73 | endmodule // clkdiv 74 | -------------------------------------------------------------------------------- /ahb3lite_remote_bridge/rtl/swd_phy.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * SWD (serial wire debug) physical interface 3 | * 4 | * All rights reserved. 5 | * Tiny Labs Inc 6 | * 2020 7 | */ 8 | 9 | module swd_phy 10 | ( 11 | // Core signals 12 | input CLK, 13 | input RESETn, 14 | 15 | // Hardware interface 16 | input SWDCLKIN, 17 | output logic SWDCLKOUT, 18 | input SWDIN, 19 | output logic SWDOUT, 20 | output logic SWDOE, 21 | 22 | // Shift register interface 23 | input [5:0] T0, 24 | input [5:0] T1, 25 | input [63:0] SO, 26 | output logic [35:0] SI, 27 | input [5:0] LEN, 28 | // Ready/done flags 29 | input VALID, 30 | output logic READY, 31 | output logic [2:0] ERR 32 | ); 33 | 34 | // Error conditions 35 | typedef enum logic [2:0] { 36 | SUCCESS, // 000 37 | ERR_FAULT, // 001 38 | ERR_WAIT, // 010 39 | ERR_NOCONNECT, // 011 40 | ERR_UNKNOWN = 7 // 111 41 | } err_t; 42 | 43 | // Internal logic 44 | logic [5:0] ctr; 45 | logic [5:0] len; 46 | logic [5:0] t0; 47 | logic [5:0] t1; 48 | logic [63:0] so; 49 | logic check; 50 | logic pclk; 51 | 52 | 53 | // Synchronize slower clock using fast clock 54 | logic qSWDCLKIN; 55 | sync2_pgen clk_sync (.c (CLK), .d (SWDCLKIN), .p (), .q (qSWDCLKIN)); 56 | 57 | // Set flag when we need to check status response 58 | assign check = ((t0 == 8) && (ctr == 12) && !SWDCLKOUT) ? 1'b1 : 1'b0; 59 | 60 | always @(posedge CLK) 61 | begin 62 | // Reset locals if in reset 63 | if (!RESETn) 64 | begin 65 | pclk <= 0; 66 | ctr <= 0; 67 | len <= 0; 68 | t0 <= 0; 69 | t1 <= 0; 70 | SWDOE <= 0; 71 | SWDOUT <= 0; 72 | READY <= 1; 73 | end 74 | else 75 | begin 76 | 77 | // Save previous clock 78 | pclk <= qSWDCLKIN; 79 | 80 | // Check for error conditions 81 | if (check) 82 | begin 83 | case (SI[2:0]) 84 | 3'b001: ERR <= ERR_FAULT; 85 | 3'b010: ERR <= ERR_WAIT; 86 | 3'b100: ERR <= SUCCESS; 87 | 3'b111: ERR <= ERR_NOCONNECT; 88 | default: ERR <= ERR_UNKNOWN; 89 | endcase // casex (SI[2:0]) 90 | 91 | // Start driving if this was a read 92 | if ((SI[2:0] != 3'b100) && (t1 > 12)) 93 | begin 94 | SWDOE <= 1; 95 | t1 <= 0; 96 | so <= {64{1'b0}}; 97 | end 98 | end // if (check) 99 | 100 | // 101 | // RISING edge 102 | // 103 | if (!pclk & qSWDCLKIN) 104 | begin 105 | if (ctr < len) 106 | SWDCLKOUT <= 1; 107 | end // RISING edge 108 | 109 | // 110 | // FALLING edge 111 | // 112 | if (pclk & !qSWDCLKIN) 113 | begin 114 | 115 | // Accept new transactions 116 | if (VALID) 117 | begin 118 | ctr <= 0; 119 | len <= LEN; 120 | so <= SO; 121 | t0 <= T0; 122 | t1 <= T1; 123 | READY <= 0; 124 | ERR <= 0; 125 | SI <= 0; 126 | end 127 | 128 | // Shift when in transaction 129 | if (ctr < len) 130 | begin 131 | 132 | // Switch direction when counter matches 133 | if ((ctr == t0) || (ctr == t1)) 134 | SWDOE <= ~SWDOE; 135 | // Else shift in 136 | else if (!SWDOE) 137 | SI <= {SI[34:0], SWDIN}; 138 | 139 | // Write when SWDOE enabled 140 | if (SWDOE) 141 | begin 142 | SWDOUT <= so[0]; 143 | so <= {1'b0, so[63:1]}; 144 | end 145 | 146 | // Increment counter 147 | ctr <= ctr + 1; 148 | 149 | // Set ready when done 150 | if (ctr == (len - 1)) 151 | READY <= 1; 152 | 153 | // Drive output clock 154 | SWDCLKOUT <= 0; 155 | 156 | end // if (ctr < len) 157 | 158 | end // FALLING edge 159 | 160 | end // else: !if(!RESETn) 161 | end // always @ (posedge CLK) 162 | 163 | endmodule // swd_phy 164 | 165 | -------------------------------------------------------------------------------- /ahb3lite_remote_bridge2/ahb3lite_remote_bridge.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::ahb3lite_remote_bridge2:0.1 3 | description: Bridges AHB3lite to external target via SWD/JTAG 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - ahb3lite_pkg 9 | - fifo 10 | files: 11 | # - rtl/ahb3lite_remote_bridge.sv 12 | - rtl/debug_clkdiv.sv 13 | - rtl/swd_phy.sv 14 | - rtl/jtag_phy.sv 15 | - rtl/jtag_adiv5.sv 16 | - rtl/swd_adiv5.sv 17 | - rtl/debug_mux.sv 18 | - rtl/host_jtag_convert.sv 19 | file_type : verilogSource 20 | 21 | swd_phy: 22 | depend: 23 | - verilator_utils 24 | - fifo 25 | files: 26 | - rtl/swd_phy.sv : {file_type : verilogSource} 27 | - bench/swd_phy_tb.cpp : {file_type : cppSource} 28 | 29 | jtag_phy: 30 | depend: 31 | - verilator_utils 32 | - fifo 33 | files: 34 | - rtl/jtag_phy.sv : {file_type : verilogSource} 35 | - bench/jtag_phy_tb.cpp : {file_type : cppSource} 36 | 37 | debug_mux: 38 | depend: 39 | - verilator_utils 40 | files: 41 | - bench/debug_mux_tb.cpp : {file_type : cppSource} 42 | 43 | targets: 44 | default: 45 | filesets : [rtl] 46 | 47 | sim: &sim 48 | default_tool: verilator 49 | tools: 50 | verilator: 51 | verilator_options: [-sv, --cc, --trace, --clk, CLK] 52 | run_options: [--vcd=sim.vcd, --timeout=20000] 53 | 54 | swd_phy: 55 | <<: *sim 56 | filesets : [swd_phy] 57 | description: Test SWD phy with verilator 58 | toplevel: [swd_phy] 59 | 60 | jtag_phy: 61 | <<: *sim 62 | filesets : [jtag_phy] 63 | description: Test JTAG phy with verilator 64 | toplevel: [jtag_phy] 65 | 66 | debug_mux: 67 | <<: *sim 68 | filesets : [rtl, debug_mux] 69 | description: Debug mux test 70 | toplevel: [debug_mux] 71 | 72 | -------------------------------------------------------------------------------- /ahb3lite_remote_bridge2/bench/jtag_adiv5_tb.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Verilator bench on top of jtag_adiv5.sv - Test JTAG phy 3 | * 4 | * All rights reserved. 5 | * Tiny Labs Inc 6 | * 2020 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Vjtag_adiv5.h" 14 | 15 | #define RESET_TIME 10 16 | static bool done = false; 17 | 18 | 19 | static void INTHandler (int signal) 20 | { 21 | printf("\nCaught ctrl-c\n"); 22 | done = true; 23 | } 24 | 25 | static int parse_opt (int key, char *arg, struct argp_state *state) 26 | { 27 | switch (key) { 28 | case ARGP_KEY_INIT: 29 | state->child_inputs[0] = state->input; 30 | break; 31 | // Add parsing custom options here 32 | } 33 | return 0; 34 | } 35 | 36 | // Response status 37 | typedef enum 38 | { 39 | OK = 4, 40 | WAIT = 2, 41 | FAULT = 1, 42 | NOCONNECT = 7 43 | } stat_t; 44 | 45 | class jtag_adiv5_tb : public VerilatorUtils { 46 | 47 | private: 48 | bool _doCycle (void); 49 | 50 | public: 51 | Vjtag_adiv5 *top; 52 | jtag_adiv5_tb (); 53 | ~jtag_adiv5_tb (); 54 | bool doCycle (void); 55 | 56 | // Helper functions 57 | void Enable (void); 58 | void Disable (void); 59 | 60 | // DP/AP access 61 | void write (uint8_t addr, bool APnDP, bool RnW, uint32_t data); 62 | uint32_t read (void); 63 | uint32_t dp_read (uint8_t addr); 64 | void dp_write (uint8_t addr, uint32_t data); 65 | uint32_t ap_read (uint8_t apsel, uint8_t addr); 66 | void ap_write (uint8_t apsel, uint8_t addr, uint32_t data); 67 | }; 68 | 69 | static int parse_args (int argc, char **argv, jtag_adiv5_tb *tb) 70 | { 71 | struct argp_option options[] = 72 | { 73 | // Add custom options here 74 | { 0 } 75 | }; 76 | struct argp_child child_parsers[] = 77 | { 78 | { &verilator_utils_argp, 0, "", 0 }, 79 | { 0 } 80 | }; 81 | struct argp argp = { options, parse_opt, 0, 0, child_parsers }; 82 | return argp_parse (&argp, argc, argv, 0, 0, tb); 83 | } 84 | 85 | jtag_adiv5_tb::jtag_adiv5_tb (void) : VerilatorUtils (NULL) 86 | { 87 | top = new Vjtag_adiv5; 88 | 89 | // Enable trace 90 | top->trace (tfp, 99); 91 | } 92 | 93 | jtag_adiv5_tb::~jtag_adiv5_tb () 94 | { 95 | delete top; 96 | } 97 | 98 | bool jtag_adiv5_tb::_doCycle (void) 99 | { 100 | uint8_t tdo = 0; 101 | 102 | // Call base function 103 | if (!VerilatorUtils::doCycle() || done) 104 | exit (-1); 105 | 106 | // Control reset 107 | if (getTime () > RESET_TIME) 108 | top->RESETn = 1; 109 | else 110 | top->RESETn = 0; 111 | 112 | // Eval 113 | top->eval (); 114 | 115 | // Flip clocks 116 | top->CLK = !top->CLK; 117 | top->PHY_CLK = !top->PHY_CLK; 118 | 119 | // Call JTAG client function 120 | doJTAGClient (top->TCK, &top->TDO, top->TDI, &top->TMS); 121 | 122 | // Continue 123 | return true; 124 | } 125 | 126 | bool jtag_adiv5_tb::doCycle (void) 127 | { 128 | // Two half cycles 129 | if (!_doCycle ()) return false; 130 | return _doCycle (); 131 | } 132 | 133 | void jtag_adiv5_tb::Enable (void) 134 | { 135 | top->ENABLE = 1; 136 | doCycle (); 137 | } 138 | 139 | void jtag_adiv5_tb::Disable (void) 140 | { 141 | top->ENABLE = 0; 142 | doCycle (); 143 | } 144 | 145 | void jtag_adiv5_tb::write (uint8_t addr, bool APnDP, bool RnW, uint32_t data) 146 | { 147 | // Block if FIFO is full 148 | while (top->WRFULL) 149 | doCycle (); 150 | 151 | // Setup data 152 | top->WRDATA = (uint64_t)data << 4; 153 | top->WRDATA |= (addr & 3) << 2; 154 | if (APnDP) 155 | top->WRDATA |= 1 << 1; 156 | if (RnW) 157 | top->WRDATA |= 1; 158 | 159 | // Set WriteEN 160 | top->WREN = 1; 161 | 162 | // Toggle clock 163 | doCycle (); 164 | 165 | // Clr WriteEN 166 | top->WREN = 0; 167 | } 168 | 169 | uint32_t jtag_adiv5_tb::read (void) 170 | { 171 | // Wait for response 172 | while (top->RDEMPTY) 173 | doCycle (); 174 | 175 | // Read 176 | top->RDEN = 1; 177 | doCycle (); 178 | top->RDEN = 0; 179 | 180 | // Check response 181 | if ((stat_t)(top->RDDATA & 7) != OK) { 182 | int i; 183 | printf ("read failed: %d\n", (int)(top->RDDATA & 7)); 184 | for (i = 0; i < 100; i++) 185 | doCycle (); 186 | done = true; // Bail 187 | } 188 | 189 | // Return data 190 | return (uint32_t)((top->RDDATA >> 3) & 0xffffffff); 191 | } 192 | 193 | void jtag_adiv5_tb::dp_write (uint8_t addr, uint32_t data) 194 | { 195 | write ((addr >> 2) & 3, 0, 0, data); 196 | if (addr != 0xc) 197 | read (); 198 | } 199 | 200 | uint32_t jtag_adiv5_tb::dp_read (uint8_t addr) 201 | { 202 | write ((addr >> 2) & 3, 0, 1, 0); 203 | return read (); 204 | } 205 | 206 | 207 | uint32_t jtag_adiv5_tb::ap_read (uint8_t apsel, uint8_t addr) 208 | { 209 | // Write DP[8] = SELECT 210 | write (2, 0, 0, (apsel << 24) | addr); 211 | read (); 212 | 213 | // Read AP[addr] 214 | write ((addr >> 2) & 3, 1, 1, 0); 215 | 216 | // Get result 217 | return read (); 218 | } 219 | 220 | void jtag_adiv5_tb::ap_write (uint8_t apsel, uint8_t addr, uint32_t data) 221 | { 222 | // Write DP[8] = SELECT 223 | write (2, 0, 0, (apsel << 24) | addr); 224 | read (); 225 | 226 | // Write AP[addr] 227 | write ((addr >> 2) & 3, 1, 0, data); 228 | read (); 229 | } 230 | 231 | 232 | int main (int argc, char **argv) 233 | { 234 | int i; 235 | jtag_adiv5_tb *dut = new jtag_adiv5_tb; 236 | uint32_t val = 0; 237 | 238 | // Parse args 239 | parse_args (argc, argv, dut); 240 | 241 | // Setup interrupt handler 242 | signal (SIGINT, &INTHandler); 243 | 244 | // Run through reset 245 | for (i = 0; i < RESET_TIME * 2; i++) 246 | dut->doCycle (); 247 | 248 | // Enable 249 | dut->Enable (); 250 | 251 | // Reset 252 | dut->dp_write (0xc, 0); 253 | 254 | // Switch to JTAG 255 | dut->dp_write (0xc, 1); 256 | 257 | // Get IDCOde 258 | printf ("IDCODE=%08X\n", dut->dp_read (0)); 259 | 260 | // Enable AP/DBGPWR 261 | dut->dp_write (4, 0x50000000); 262 | 263 | // Read back STAT 264 | val = dut->dp_read (4); 265 | printf ("CTRL/STAT=%08X\n", val); 266 | if ((val & 0xf0000000) == 0xf0000000) 267 | printf ("PWR|DBG enabled\n"); 268 | 269 | // Read IDR 270 | printf ("AP[0]=%08X\n", dut->ap_read (0, 0xfc)); 271 | 272 | // Read BASE 273 | printf ("BASE=%08X\n", dut->ap_read (0, 0xf8)); 274 | 275 | // Write AP[0] = CSW 276 | dut->ap_write (0, 0, 0xA2000002); 277 | 278 | // Write SCB_DHCSR to TAR 279 | dut->ap_write (0, 4, 0xE000EDF0); 280 | 281 | printf ("Halting processor... "); 282 | do { 283 | // Write HALT|DEBUGEN to DRW 284 | dut->ap_write (0, 0xc, 0xA05F0003); 285 | 286 | // Read DHCSR 287 | } while ((dut->ap_read (0, 0xc) & (1 << 17)) == 0); 288 | printf ("OK\n"); 289 | 290 | // TAR = RAM 291 | dut->ap_write (0, 4, 0x20000000); 292 | 293 | // Write to RAM 294 | printf ("RAM test... "); 295 | dut->ap_write (0, 0xc, 0xdeadc0de); 296 | if (dut->ap_read (0, 0xc) == 0xdeadc0de) 297 | printf ("OK\n"); 298 | else 299 | printf ("FAILED\n"); 300 | 301 | // Add padding to end 302 | for (i = 0; i < 200; i++) 303 | dut->doCycle (); 304 | 305 | // Disable interface 306 | dut->Disable (); 307 | 308 | // Add padding to end 309 | for (i = 0; i < 20; i++) 310 | dut->doCycle (); 311 | 312 | // Done 313 | delete dut; 314 | return 0; 315 | } 316 | -------------------------------------------------------------------------------- /ahb3lite_remote_bridge2/bench/swd_adiv5_tb.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Verilator bench on top of swd_adiv5.sv - Test SWD phy 3 | * 4 | * All rights reserved. 5 | * Tiny Labs Inc 6 | * 2020 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Vswd_adiv5.h" 14 | 15 | #define RESET_TIME 10 16 | static bool done = false; 17 | 18 | 19 | static void INTHandler (int signal) 20 | { 21 | printf("\nCaught ctrl-c\n"); 22 | done = true; 23 | } 24 | 25 | static int parse_opt (int key, char *arg, struct argp_state *state) 26 | { 27 | switch (key) { 28 | case ARGP_KEY_INIT: 29 | state->child_inputs[0] = state->input; 30 | break; 31 | // Add parsing custom options here 32 | } 33 | return 0; 34 | } 35 | 36 | // Response status 37 | typedef enum 38 | { 39 | OK = 4, 40 | WAIT = 2, 41 | FAULT = 1, 42 | NOCONNECT = 7 43 | } stat_t; 44 | 45 | class swd_adiv5_tb : public VerilatorUtils { 46 | 47 | private: 48 | bool _doCycle (void); 49 | 50 | public: 51 | Vswd_adiv5 *top; 52 | swd_adiv5_tb (); 53 | ~swd_adiv5_tb (); 54 | bool doCycle (void); 55 | 56 | // Helper functions 57 | void Enable (void); 58 | void Disable (void); 59 | 60 | // DP/AP access 61 | void write (uint8_t addr, bool APnDP, bool RnW, uint32_t data); 62 | uint32_t read (void); 63 | uint32_t dp_read (uint8_t addr); 64 | void dp_write (uint8_t addr, uint32_t data); 65 | uint32_t ap_read (uint8_t apsel, uint8_t addr); 66 | void ap_write (uint8_t apsel, uint8_t addr, uint32_t data); 67 | }; 68 | 69 | static int parse_args (int argc, char **argv, swd_adiv5_tb *tb) 70 | { 71 | struct argp_option options[] = 72 | { 73 | // Add custom options here 74 | { 0 } 75 | }; 76 | struct argp_child child_parsers[] = 77 | { 78 | { &verilator_utils_argp, 0, "", 0 }, 79 | { 0 } 80 | }; 81 | struct argp argp = { options, parse_opt, 0, 0, child_parsers }; 82 | return argp_parse (&argp, argc, argv, 0, 0, tb); 83 | } 84 | 85 | swd_adiv5_tb::swd_adiv5_tb (void) : VerilatorUtils (NULL) 86 | { 87 | top = new Vswd_adiv5; 88 | 89 | // Enable trace 90 | top->trace (tfp, 99); 91 | } 92 | 93 | swd_adiv5_tb::~swd_adiv5_tb () 94 | { 95 | delete top; 96 | } 97 | 98 | bool swd_adiv5_tb::_doCycle (void) 99 | { 100 | uint8_t tdo = 0; 101 | 102 | // Call base function 103 | if (!VerilatorUtils::doCycle() || done) 104 | exit (-1); 105 | 106 | // Control reset 107 | if (getTime () > RESET_TIME) 108 | top->RESETn = 1; 109 | else 110 | top->RESETn = 0; 111 | 112 | // Eval 113 | top->eval (); 114 | 115 | // Flip clocks 116 | top->CLK = !top->CLK; 117 | top->PHY_CLK = !top->PHY_CLK; 118 | 119 | // Call JTAG client function 120 | doJTAGClient (top->TCK, &tdo, 0, top->TMSOE ? &top->TMSOUT : &top->TMSIN, top->TMSOE); 121 | 122 | // Continue 123 | return true; 124 | } 125 | 126 | bool swd_adiv5_tb::doCycle (void) 127 | { 128 | // Two half cycles 129 | if (!_doCycle ()) return false; 130 | return _doCycle (); 131 | } 132 | 133 | void swd_adiv5_tb::Enable (void) 134 | { 135 | top->ENABLE = 1; 136 | doCycle (); 137 | } 138 | 139 | void swd_adiv5_tb::Disable (void) 140 | { 141 | top->ENABLE = 0; 142 | doCycle (); 143 | } 144 | 145 | void swd_adiv5_tb::write (uint8_t addr, bool APnDP, bool RnW, uint32_t data) 146 | { 147 | // Block if FIFO is full 148 | while (top->WRFULL) 149 | doCycle (); 150 | 151 | // Setup data 152 | top->WRDATA = (uint64_t)data << 4; 153 | top->WRDATA |= (addr & 3) << 2; 154 | if (APnDP) 155 | top->WRDATA |= 1 << 1; 156 | if (RnW) 157 | top->WRDATA |= 1; 158 | 159 | // Set WriteEN 160 | top->WREN = 1; 161 | 162 | // Toggle clock 163 | doCycle (); 164 | 165 | // Clr WriteEN 166 | top->WREN = 0; 167 | } 168 | 169 | uint32_t swd_adiv5_tb::read (void) 170 | { 171 | // Wait for response 172 | while (top->RDEMPTY) 173 | doCycle (); 174 | 175 | // Read 176 | top->RDEN = 1; 177 | doCycle (); 178 | top->RDEN = 0; 179 | 180 | // Check response 181 | if ((stat_t)(top->RDDATA & 7) != OK) { 182 | int i; 183 | printf ("read failed: %d\n", (int)(top->RDDATA & 7)); 184 | for (i = 0; i < 100; i++) 185 | doCycle (); 186 | done = true; // Bail 187 | } 188 | 189 | // Return data 190 | return (uint32_t)((top->RDDATA >> 3) & 0xffffffff); 191 | } 192 | 193 | void swd_adiv5_tb::dp_write (uint8_t addr, uint32_t data) 194 | { 195 | write ((addr >> 2) & 3, 0, 0, data); 196 | if (addr != 0xc) 197 | read (); 198 | } 199 | 200 | uint32_t swd_adiv5_tb::dp_read (uint8_t addr) 201 | { 202 | write ((addr >> 2) & 3, 0, 1, 0); 203 | return read (); 204 | } 205 | 206 | 207 | uint32_t swd_adiv5_tb::ap_read (uint8_t apsel, uint8_t addr) 208 | { 209 | // Write DP[8] = SELECT 210 | write (2, 0, 0, (apsel << 24) | addr); 211 | read (); 212 | 213 | // Read AP[addr] 214 | write ((addr >> 2) & 3, 1, 1, 0); 215 | 216 | // Get result 217 | return read (); 218 | } 219 | 220 | void swd_adiv5_tb::ap_write (uint8_t apsel, uint8_t addr, uint32_t data) 221 | { 222 | // Write DP[8] = SELECT 223 | write (2, 0, 0, (apsel << 24) | addr); 224 | read (); 225 | 226 | // Write AP[addr] 227 | write ((addr >> 2) & 3, 1, 0, data); 228 | read (); 229 | } 230 | 231 | 232 | int main (int argc, char **argv) 233 | { 234 | int i; 235 | swd_adiv5_tb *dut = new swd_adiv5_tb; 236 | uint32_t val = 0; 237 | 238 | // Parse args 239 | parse_args (argc, argv, dut); 240 | 241 | // Setup interrupt handler 242 | signal (SIGINT, &INTHandler); 243 | 244 | // Run through reset 245 | for (i = 0; i < RESET_TIME * 2; i++) 246 | dut->doCycle (); 247 | 248 | // Enable 249 | dut->Enable (); 250 | 251 | // Reset 252 | dut->dp_write (0xc, 0); 253 | 254 | // Switch to SWD 255 | dut->dp_write (0xc, 1); 256 | 257 | // Get IDCOde 258 | printf ("IDCODE=%08X\n", dut->dp_read (0)); 259 | 260 | // Enable AP/DBGPWR 261 | dut->dp_write (4, 0x50000000); 262 | 263 | // Read back STAT 264 | val = dut->dp_read (4); 265 | printf ("CTRL/STAT=%08X\n", val); 266 | if ((val & 0xf0000000) == 0xf0000000) 267 | printf ("PWR|DBG enabled\n"); 268 | 269 | // Read IDR 270 | printf ("AP[0]=%08X\n", dut->ap_read (0, 0xfc)); 271 | 272 | // Read BASE 273 | printf ("BASE=%08X\n", dut->ap_read (0, 0xf8)); 274 | 275 | // Write AP[0] = CSW 276 | dut->ap_write (0, 0, 0xA2000002); 277 | 278 | // Write SCB_DHCSR to TAR 279 | dut->ap_write (0, 4, 0xE000EDF0); 280 | 281 | printf ("Halting processor... "); 282 | do { 283 | // Write HALT|DEBUGEN to DRW 284 | dut->ap_write (0, 0xc, 0xA05F0003); 285 | 286 | // Read DHCSR 287 | } while ((dut->ap_read (0, 0xc) & (1 << 17)) == 0); 288 | printf ("OK\n"); 289 | 290 | // TAR = RAM 291 | dut->ap_write (0, 4, 0x20000000); 292 | 293 | // Write to RAM 294 | printf ("RAM test... "); 295 | dut->ap_write (0, 0xc, 0xdeadc0de); 296 | if (dut->ap_read (0, 0xc) == 0xdeadc0de) 297 | printf ("OK\n"); 298 | else 299 | printf ("FAILED\n"); 300 | 301 | // Add padding to end 302 | for (i = 0; i < 200; i++) 303 | dut->doCycle (); 304 | 305 | // Disable interface 306 | dut->Disable (); 307 | 308 | // Add padding to end 309 | for (i = 0; i < 20; i++) 310 | dut->doCycle (); 311 | 312 | // Done 313 | delete dut; 314 | return 0; 315 | } 316 | -------------------------------------------------------------------------------- /ahb3lite_remote_bridge2/rtl/debug_clkdiv.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * CLK divisor for PHY 3 | * 4 | * All rights reserved. 5 | * Tiny Labs Inc 6 | * 2020 7 | */ 8 | 9 | module debug_clkdiv 10 | ( 11 | input CLKIN, 12 | input [3:0] SEL, 13 | output logic CLKOUT 14 | ); 15 | 16 | logic [8:0] ctr; 17 | 18 | `define FLIP(v) begin if (ctr == (v-1)) begin CLKOUT <= ~CLKOUT; ctr <= 0; end else ctr <= ctr + 1; end 19 | 20 | // SEL FREQ DIVISOR 21 | // 0 = 192 MHz 1 22 | // 1 = 96 MHz 2 23 | // 2 = 64 MHz 3 24 | // 3 = 48 MHz 4 25 | // 4 = 32 MHz 6 26 | // 5 = 24 MHz 8 27 | // 6 = 19.2 MHz 10 28 | // 7 = 16 MHz 12 29 | // 8 = 12 MHz 16 30 | // 9 = 8 MHz 24 31 | // 10 = 6 MHz 32 32 | // 11 = 4 MHz 48 33 | // 12 = 3 MHz 64 34 | // 13 = 2 MHz 96 35 | // 14 = 1 MHz 192 36 | // 15 = 500 kHz 384 37 | always @(posedge CLKIN or negedge CLKIN) 38 | begin 39 | case (SEL) 40 | 4'd0: `FLIP (1) 41 | 4'd1: `FLIP (2) 42 | 4'd2: `FLIP (3) 43 | 4'd3: `FLIP (4) 44 | 4'd4: `FLIP (6) 45 | 4'd5: `FLIP (8) 46 | 4'd6: `FLIP (10) 47 | 4'd7: `FLIP (12) 48 | 4'd8: `FLIP (16) 49 | 4'd9: `FLIP (24) 50 | 4'd10: `FLIP (32) 51 | 4'd11: `FLIP (48) 52 | 4'd12: `FLIP (64) 53 | 4'd13: `FLIP (96) 54 | 4'd14: `FLIP (192) 55 | 4'd15: `FLIP (384) 56 | endcase 57 | end 58 | endmodule // debug_clkdiv 59 | 60 | -------------------------------------------------------------------------------- /ahb3lite_remote_bridge2/rtl/host_jtag_convert.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * Convert between HOST FIFO <=> JTAG DIRECT 3 | * 4 | * All rights reserved. 5 | * Tiny Labs Inc 6 | * 2020 7 | */ 8 | 9 | module host_jtag_convert 10 | ( 11 | // System clock and reset 12 | input CLK, 13 | input RESETn, 14 | // ADIv5 FIFO interface 15 | input [7:0] HOST_WRDATA, 16 | input HOST_WREN, 17 | output logic HOST_WRFULL, 18 | output logic [7:0] HOST_RDDATA, 19 | input HOST_RDEN, 20 | output logic HOST_RDEMPTY, 21 | // JTAG direct PHY FIFO interface 22 | input [JTAG_CMD_WIDTH-1:0] JTAG_WRDATA, 23 | input JTAG_WREN, 24 | output JTAG_WRFULL, 25 | output [JTAG_RESP_WIDTH-1:0] JTAG_RDDATA, 26 | input JTAG_RDEN, 27 | output JTAG_RDEMPTY 28 | ); 29 | 30 | 31 | endmodule // host_jtag_convert 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /apb4_gpio/apb4_gpio.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::apb4_gpio:1.0 3 | description: APB4 GPIO interrupt capable peripheral 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - ahb3lite_pkg 9 | files: 10 | - rtl/verilog/apb_gpio.sv : {file_type : verilogSource} 11 | 12 | license: 13 | files: 14 | - LICENSE.md : {file_type : user} 15 | 16 | targets: 17 | default: 18 | filesets : [rtl, license] 19 | 20 | provider: 21 | name : github 22 | user : RoaLogic 23 | repo : apb4_gpio 24 | -------------------------------------------------------------------------------- /arm_debug/arm_debug.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::arm_debug:0.1 3 | description: ARM debug via ADIv5 interface. Supports SWD+JTAG. 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - fifo 9 | files: 10 | - rtl/adiv5_pkg.sv 11 | - rtl/swd_phy.sv 12 | - rtl/jtag_phy.sv 13 | - rtl/jtag_adiv5.sv 14 | - rtl/swd_adiv5.sv 15 | - rtl/adiv5_mux.sv 16 | file_type : verilogSource 17 | 18 | swd_phy: 19 | depend: 20 | - verilator_utils 21 | - fifo 22 | files: 23 | - rtl/swd_phy.sv : {file_type : verilogSource} 24 | - bench/swd_phy_tb.cpp : {file_type : cppSource} 25 | 26 | jtag_phy: 27 | depend: 28 | - verilator_utils 29 | - fifo 30 | files: 31 | - rtl/jtag_phy.sv : {file_type : verilogSource} 32 | - bench/jtag_phy_tb.cpp : {file_type : cppSource} 33 | 34 | debug_mux: 35 | depend: 36 | - verilator_utils 37 | files: 38 | - bench/debug_mux_tb.cpp : {file_type : cppSource} 39 | 40 | targets: 41 | default: 42 | filesets : [rtl] 43 | 44 | sim: &sim 45 | default_tool: verilator 46 | tools: 47 | verilator: 48 | verilator_options: [-sv, --cc, --trace, --clk, CLK] 49 | run_options: [--vcd=sim.vcd, --timeout=20000] 50 | 51 | swd_phy: 52 | <<: *sim 53 | filesets : [swd_phy] 54 | description: Test SWD phy with verilator 55 | toplevel: [swd_phy] 56 | 57 | jtag_phy: 58 | <<: *sim 59 | filesets : [jtag_phy] 60 | description: Test JTAG phy with verilator 61 | toplevel: [jtag_phy] 62 | 63 | debug_mux: 64 | <<: *sim 65 | filesets : [rtl, debug_mux] 66 | description: Debug mux test 67 | toplevel: [debug_mux] 68 | 69 | -------------------------------------------------------------------------------- /arm_debug/rtl/adiv5_mux.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * MUX two ADIv5 cores and provide direct access to jtag_phy 3 | * 4 | * All rights reserved. 5 | * Tiny Labs Inc 6 | * 2020 7 | */ 8 | import adiv5_pkg::*; 9 | 10 | module adiv5_mux #( parameter FIFO_AW = 2 ) 11 | ( 12 | // System clock and reset 13 | input CLK, 14 | input SYS_RESETn, 15 | // PHY clock 16 | input PHY_CLK, 17 | input PHY_CLKn, 18 | input PHY_RESETn, 19 | // Select interface 20 | input JTAGnSWD, 21 | // ADIv5 FIFO interface 22 | input [ADIv5_CMD_WIDTH-1:0] ADIv5_WRDATA, 23 | input ADIv5_WREN, 24 | output logic ADIv5_WRFULL, 25 | output logic [ADIv5_RESP_WIDTH-1:0] ADIv5_RDDATA, 26 | input ADIv5_RDEN, 27 | output logic ADIv5_RDEMPTY, 28 | // PHY signals 29 | output logic TCK, 30 | output logic TDI, 31 | output logic TMSOUT, 32 | output logic TMSOE, 33 | input TMSIN, 34 | input TDO 35 | ); 36 | 37 | // Internal ADIv5 signals 38 | logic jtag_adiv5_WRFULL, swd_adiv5_WRFULL; 39 | logic jtag_adiv5_RDEMPTY, swd_adiv5_RDEMPTY; 40 | logic [ADIv5_RESP_WIDTH-1:0] jtag_adiv5_RDDATA, swd_adiv5_RDDATA; 41 | 42 | // Internal PHY interface 43 | logic [SWD_CMD_WIDTH-1:0] swd_WRDATA; 44 | logic [SWD_RESP_WIDTH-1:0] swd_RDDATA; 45 | logic swd_WREN, swd_RDEN, swd_WRFULL, swd_RDEMPTY; 46 | logic [JTAG_CMD_WIDTH-1:0] jtag_WRDATA; 47 | logic [JTAG_RESP_WIDTH-1:0] jtag_RDDATA; 48 | logic jtag_WREN, jtag_RDEN, jtag_WRFULL, jtag_RDEMPTY; 49 | 50 | // Internal phy signals 51 | logic jtag_TCK, jtag_TMS, jtag_TDI; 52 | logic swd_TCK, swd_TMSOUT, swd_TMSOE; 53 | 54 | // MUX hardware signals 55 | assign TCK = JTAGnSWD ? jtag_TCK : swd_TCK; 56 | assign TDI = JTAGnSWD ? jtag_TDI : 1'b0; 57 | assign TMSOUT = JTAGnSWD ? jtag_TMS : swd_TMSOUT; 58 | assign TMSOE = JTAGnSWD ? 1'b1 : swd_TMSOE; 59 | 60 | // MUX ADIv5 interface 61 | assign ADIv5_WRFULL = JTAGnSWD ? jtag_adiv5_WRFULL : swd_adiv5_WRFULL; 62 | assign ADIv5_RDDATA = JTAGnSWD ? jtag_adiv5_RDDATA : swd_adiv5_RDDATA; 63 | assign ADIv5_RDEMPTY = JTAGnSWD ? jtag_adiv5_RDEMPTY : swd_adiv5_RDEMPTY; 64 | 65 | // Instantiate JTAG phy 66 | jtag_phy #(.FIFO_AW (FIFO_AW + 1)) 67 | u_jtag_phy ( 68 | .CLK (CLK), 69 | .SYS_RESETn (SYS_RESETn & JTAGnSWD), 70 | .PHY_CLK (PHY_CLK), 71 | .PHY_CLKn (PHY_CLKn), 72 | .PHY_RESETn (PHY_RESETn & JTAGnSWD), 73 | .WRDATA (jtag_WRDATA), 74 | .WREN (jtag_WREN), 75 | .WRFULL (jtag_WRFULL), 76 | .RDDATA (jtag_RDDATA), 77 | .RDEN (jtag_RDEN), 78 | .RDEMPTY (jtag_RDEMPTY), 79 | .TCK (jtag_TCK), 80 | .TMS (jtag_TMS), 81 | .TDI (jtag_TDI), 82 | .TDO (TDO) 83 | ); 84 | 85 | // Instantiate SWD phy 86 | swd_phy #(.FIFO_AW (FIFO_AW + 1)) 87 | u_swd_phy ( 88 | .CLK (CLK), 89 | .SYS_RESETn (SYS_RESETn & ~JTAGnSWD), 90 | .PHY_CLK (PHY_CLK), 91 | .PHY_CLKn (PHY_CLKn), 92 | .PHY_RESETn (PHY_RESETn & ~JTAGnSWD), 93 | .WRDATA (swd_WRDATA), 94 | .WREN (swd_WREN), 95 | .WRFULL (swd_WRFULL), 96 | .RDDATA (swd_RDDATA), 97 | .RDEN (swd_RDEN), 98 | .RDEMPTY (swd_RDEMPTY), 99 | .SWDCLK (swd_TCK), 100 | .SWDIN (TMSIN), 101 | .SWDOUT (swd_TMSOUT), 102 | .SWDOE (swd_TMSOE) 103 | ); 104 | 105 | // Instantiate JTAG ADIv5 106 | jtag_adiv5 #(.FIFO_AW (FIFO_AW)) 107 | u_jtag_adiv5 ( 108 | .CLK (CLK), 109 | .RESETn (SYS_RESETn & JTAGnSWD), 110 | .WRDATA (ADIv5_WRDATA), 111 | .WREN (ADIv5_WREN), 112 | .WRFULL (jtag_adiv5_WRFULL), 113 | .RDDATA (jtag_adiv5_RDDATA), 114 | .RDEN (ADIv5_RDEN), 115 | .RDEMPTY (jtag_adiv5_RDEMPTY), 116 | .PHY_WRDATA (jtag_WRDATA), 117 | .PHY_WREN (jtag_WREN), 118 | .PHY_WRFULL (jtag_WRFULL), 119 | .PHY_RDDATA (jtag_RDDATA), 120 | .PHY_RDEN (jtag_RDEN), 121 | .PHY_RDEMPTY (jtag_RDEMPTY) 122 | ); 123 | 124 | // Instantiate SWD ADIv5 125 | swd_adiv5 #(.FIFO_AW (FIFO_AW + 1)) 126 | u_swd_adiv5 ( 127 | .CLK (CLK), 128 | .RESETn (SYS_RESETn & ~JTAGnSWD), 129 | .WRDATA (ADIv5_WRDATA), 130 | .WREN (ADIv5_WREN), 131 | .WRFULL (swd_adiv5_WRFULL), 132 | .RDDATA (swd_adiv5_RDDATA), 133 | .RDEN (ADIv5_RDEN), 134 | .RDEMPTY (swd_adiv5_RDEMPTY), 135 | .PHY_WRDATA (swd_WRDATA), 136 | .PHY_WREN (swd_WREN), 137 | .PHY_WRFULL (swd_WRFULL), 138 | .PHY_RDDATA (swd_RDDATA), 139 | .PHY_RDEN (swd_RDEN), 140 | .PHY_RDEMPTY (swd_RDEMPTY) 141 | ); 142 | 143 | endmodule // debug_mux 144 | 145 | 146 | -------------------------------------------------------------------------------- /arm_debug/rtl/adiv5_pkg.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * Common definitions for connecting IP to host FIFOs. 3 | * 4 | * All rights reserved. 5 | * Tiny Labs Inc 6 | * 2020 7 | */ 8 | 9 | package adiv5_pkg; 10 | 11 | // ADIv5 CMD / RESP 12 | parameter ADIv5_CMD_WIDTH = 36; 13 | parameter ADIv5_RESP_WIDTH = 35; 14 | 15 | // SWD PHY CMD / RESP 16 | parameter SWD_CMD_WIDTH = 82; 17 | parameter SWD_RESP_WIDTH = 43; 18 | 19 | // JTAG PHY CMD / RESP 20 | parameter JTAG_CMD_WIDTH = 79; 21 | parameter JTAG_RESP_WIDTH = 70; 22 | 23 | typedef enum logic [2:0] 24 | { 25 | STAT_FAULT = 3'b001, 26 | STAT_TIMEOUT = 3'b010, 27 | STAT_OK = 3'b100, 28 | STAT_NOCONNECT = 3'b111 29 | } adiv5_stat_t; 30 | 31 | // Command encoding 32 | typedef struct packed { 33 | logic [31:0] data; 34 | logic [1:0] addr; 35 | logic [0:0] APnDP; 36 | logic [0:0] RnW; 37 | } adiv5_cmd_t; 38 | 39 | // Response encoding 40 | typedef struct packed { 41 | logic [31:0] data; 42 | logic [2:0] stat; 43 | } adiv5_resp_t; 44 | 45 | // DP addresses 46 | typedef enum logic [1:0] 47 | { 48 | DP_ADDR_DPIDR_ABRT = 2'b00, 49 | DP_ADDR_CTRL_STAT = 2'b01, 50 | DP_ADDR_SELECT = 2'b10, 51 | DP_ADDR_RDBUF = 2'b11 52 | } adiv5_dp_addr; 53 | 54 | // AP addresses 55 | typedef enum logic [5:0] 56 | { 57 | AP_ADDR_CSW = 6'b000000, // CSW - Control/Status word 58 | AP_ADDR_TAR = 6'b000001, // TAR - Transfer Address register 59 | AP_ADDR_DRW = 6'b000011, // DRW - Data Read/Write 60 | AP_ADDR_BD0 = 6'b000100, // BD0 - Banked data 0 61 | AP_ADDR_BD1 = 6'b000101, // BD1 - Banked data 1 62 | AP_ADDR_BD2 = 6'b000110, // BD2 - Banked data 2 63 | AP_ADDR_BD4 = 6'b000111, // BD3 - Banked data 3 64 | AP_ADDR_MBT = 6'b001000, // MBT - Memory barrier transfer 65 | AP_ADDR_CFG = 6'b111101, // CFG - Configuration register 66 | AP_ADDR_BASE = 6'b111110, // BASE - Debug base register 67 | AP_ADDR_IDR = 6'b111111 // IDR - Identification register 68 | } adiv5_ap_addr; 69 | 70 | // CSW fields 71 | typedef enum logic [1:0] 72 | { 73 | CSW_INC_NONE = 2'b00, 74 | CSW_INC_SINGLE = 2'b01, 75 | CSW_INC_PACKED = 2'b10 76 | } csw_f_inc; 77 | 78 | typedef enum logic [2:0] 79 | { 80 | CSW_WIDTH_BYTE = 3'b000, 81 | CSW_WIDTH_HALF = 3'b001, 82 | CSW_WIDTH_WORD = 3'b010, 83 | CSW_WIDTH_64BIT = 3'b011, 84 | CSW_WIDTH_128BIT = 3'b100, 85 | CSW_WIDTH_256BIT = 3'b101 86 | } csw_f_width; 87 | 88 | // ADIv5 registers 89 | typedef struct packed { 90 | logic [0:0] dbg_enabled; // 31 RW - Always set to 1 91 | logic [6:0] prot; // 30:24 RW - Mem protection - 4 bits defined in ahb3lite_pkg 92 | logic [0:0] spiden; // 23 RO - Secure bus access 93 | logic [6:0] res; // 22:16 - Reserved 94 | logic [0:0] mte; // 15 RW - Memory tagging 95 | logic [2:0] mte_access; // 14:12 RW - Used in conjunction with prot 96 | logic [3:0] mode; // 11:8 RW/RO - Basic = 1 (RO if only one defined) 97 | logic [0:0] tip; // 7 RO - Transfer in progress 98 | logic [0:0] memap_en; // 6 - Enable mem-ap 99 | csw_f_inc autoinc; // 5:4 RW - Auto increment address on success 100 | logic [0:0] res1; // 3 RO Reserved 101 | csw_f_width width; // 2:0 RW - Access width 102 | } adiv5_ap_csw; 103 | 104 | typedef struct packed { 105 | logic [7:0] apsel; 106 | logic [15:0] res; 107 | logic [3:0] apbank; 108 | logic [3:0] dpbank; 109 | } adiv5_dp_sel; 110 | 111 | // Helper functions 112 | function logic [0:0] bank_match(adiv5_dp_sel sel, adiv5_ap_addr addr); 113 | return (addr[5:2] == sel.apbank); 114 | endfunction // bank_match 115 | 116 | // Function for generating ADIv5 commands 117 | function adiv5_cmd_t AP_REG_WRITE(logic [5:0] addr, logic [31:0] data); 118 | AP_REG_WRITE.addr = addr[1:0]; 119 | AP_REG_WRITE.data = data; 120 | AP_REG_WRITE.APnDP = 1; 121 | AP_REG_WRITE.RnW = 0; 122 | endfunction // AP_REG_WRITE 123 | 124 | function adiv5_cmd_t AP_REG_READ(logic [5:0] addr); 125 | AP_REG_READ.addr = addr[1:0]; 126 | AP_REG_READ.APnDP = 1; 127 | AP_REG_READ.RnW = 1; 128 | endfunction // AP_REG_READ 129 | 130 | function adiv5_cmd_t DP_REG_READ(logic [1:0] addr); 131 | DP_REG_READ.addr = addr[1:0]; 132 | DP_REG_READ.APnDP = 0; 133 | DP_REG_READ.RnW = 1; 134 | endfunction // DP_REG_READ 135 | 136 | function adiv5_cmd_t DP_REG_WRITE(logic [1:0] addr, logic [31:0] data); 137 | DP_REG_WRITE.addr = addr[1:0]; 138 | DP_REG_WRITE.data = data; 139 | DP_REG_WRITE.APnDP = 0; 140 | DP_REG_WRITE.RnW = 0; 141 | endfunction // DP_REG_WRITE 142 | 143 | 144 | endpackage 145 | -------------------------------------------------------------------------------- /cm3_core/cm3_core.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::cm3_core:1.0 3 | 4 | filesets: 5 | rtl: 6 | depend: 7 | - cm3_obs 8 | files: 9 | - rtl/cm3_core.sv 10 | - rtl/cm3_excl_mon.sv 11 | file_type : verilogSource 12 | 13 | constraints: 14 | files: 15 | - "tool_vivado? (constraints/cm3.sdc)" : {file_type : SDC} 16 | - "tool_vivado? (vivado/cm3.tcl)" : {file_type : tclSource} 17 | 18 | targets: 19 | default: 20 | filesets: [rtl, constraints] 21 | description: ARM Cortex-M3 core wrapper 22 | -------------------------------------------------------------------------------- /cm3_core/constraints/cm3.sdc: -------------------------------------------------------------------------------- 1 | # 2 | # Internal timing constraints for Cortex-M3 3 | # 4 | 5 | # Get clocks 6 | set cm3_sys [get_property NAME [get_clocks -of [get_nets -hierarchical cm3_sys ]]] 7 | set cm3_dbg [get_property NAME [get_clocks -of [get_nets -hierarchical cm3_dbg ]]] 8 | 9 | # Set JTAG clock as asynchronous 10 | set_clock_groups -asynchronous -group $cm3_dbg -group $cm3_sys 11 | 12 | # Get JTAG Period 13 | #set jtag_period [get_property PERIOD [get_clocks -of [get_nets -hierarchical cm3_dbg ]]] 14 | 15 | # 16 | # BELOW is taken from m3_for_arty_a7 contraints... No idea how it is calculated 17 | # 18 | 19 | # Large input Tsu, as clock insertion delay is a lot shorter than datapath input delay. 20 | #set sw_in_tsu 8 21 | #set sw_in_max_delay [expr {$jtag_period - $sw_in_tsu}] 22 | #set sw_in_th -1 23 | #set sw_out_tsu 5 24 | #set sw_out_th -5 25 | #set debug_od 5.0 26 | #set debug_id 5.0 27 | 28 | # SWDIO is driven at both ends by posedge clk. The clock is sourced from the DAPLink board 29 | # For input signals it could be either side of rising edge 30 | # For output signals need to ensure the whole round trip is less than the period 31 | #set swdio [get_ports *SWDIO* ] 32 | #if {[ llength $swdio ]} { 33 | # set_input_delay -clock $cm3_dbg -add_delay -max $sw_in_max_delay $swdio 34 | # set_input_delay -clock $cm3_dbg -add_delay -min $sw_in_th $swdio 35 | # set_output_delay -clock $cm3_dbg -add_delay -max $sw_out_tsu $swdio 36 | # set_output_delay -clock $cm3_dbg -add_delay -min $sw_out_th $swdio 37 | #} 38 | 39 | # JTAG 40 | # Note, these are optional ports and may be removed from the build 41 | #if {[ llength [get_ports TDI] ]} { 42 | # set_input_delay -clock $cm3_dbg -add_delay $debug_id [get_ports TDI ] 43 | #} 44 | #if {[ llength [get_ports nTRST] ]} { 45 | # set_input_delay -clock $cm3_dbg -add_delay $debug_id [get_ports nTRST ] 46 | #} 47 | #if {[ llength [get_ports TDO] ]} { 48 | # set_output_delay -clock $cm3_dbg -add_delay $debug_id [get_ports TDO ] 49 | #} 50 | #if {[ llength [get_ports TMS] ]} { 51 | # set_output_delay -clock $cm3_dbg -add_delay $debug_id [get_ports TMS ] 52 | #} 53 | -------------------------------------------------------------------------------- /cm3_core/rtl/cm3_excl_mon.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * Cortex-M3 exclusive access monitor - If conditions are not met then prevent write and signal to processor. 3 | * 4 | * Tiny Labs Inc 5 | * 2019 6 | */ 7 | 8 | module cm3_excl_mon ( 9 | /* Clock */ 10 | CLK, 11 | /* Reset */ 12 | RESETn, 13 | /* Processor is halted - stop cycle count */ 14 | HALTED, 15 | /* signal inputs */ 16 | HADDR, HWRITE, EXREQ, 17 | /* signal outputs */ 18 | EXRESP, HWRITEOUT 19 | ); 20 | 21 | input CLK; 22 | input RESETn; 23 | input HALTED; 24 | input [31:0] HADDR; 25 | input HWRITE; 26 | input EXREQ; 27 | output logic EXRESP; 28 | output HWRITEOUT; 29 | 30 | // Allowable cycle delay between read and write in RMW ops 31 | `define EXCL_DELAY 128 32 | 33 | // Store last excl read address 34 | logic [31:0] exaddr; 35 | logic [$clog2(`EXCL_DELAY)-1:0] delay; 36 | logic valid; 37 | 38 | // HWRITEOUT = HWRITE unless !valid & EXREQ 39 | assign HWRITEOUT = ~valid & EXREQ ? 1'b0 : HWRITE; 40 | 41 | always @ (posedge CLK or negedge RESETn) begin 42 | if (~RESETn) 43 | begin 44 | EXRESP <= 1'b1; 45 | exaddr <= 32'h0; 46 | valid <= 1'b0; 47 | end 48 | else 49 | begin 50 | 51 | // Store addr and reset deley on EXCL_READ 52 | if (EXREQ & ~HWRITE) 53 | begin 54 | exaddr <= HADDR; 55 | delay <= 7'h7f; 56 | valid <= 1'b1; 57 | end 58 | 59 | // Ack exclusive accesses 60 | if (valid && (HADDR == exaddr)) 61 | begin 62 | // ACK both read and write 63 | if (EXREQ) 64 | EXRESP <= 1'b0; 65 | // If normal access then invalidate 66 | else 67 | valid <= 1'b0; 68 | 69 | // Clear address if its a write 70 | if (HWRITE) 71 | begin 72 | valid <= 1'b0; 73 | end 74 | end 75 | else 76 | EXRESP <= 1'b1; 77 | 78 | // Count down if valid 79 | if (valid && ~HALTED) 80 | begin 81 | if (|delay) 82 | delay <= delay - 1; 83 | else 84 | begin 85 | valid <= 1'b0; 86 | end 87 | end 88 | end // else: !if(~RESETn) 89 | end // always @ (posedge CLK) 90 | 91 | endmodule // cm3_excl_mon 92 | -------------------------------------------------------------------------------- /cm3_core/vivado/cm3.tcl: -------------------------------------------------------------------------------- 1 | reorder_files -fileset constrs_1 -back [get_files cm3.sdc] 2 | set_property USED_IN_SYNTHESIS false [get_files cm3.sdc] 3 | -------------------------------------------------------------------------------- /cm3_full/cm3_full.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::cm3_full:0.1 3 | description: Cortex-M3 Xilinx encrypted RTL 4 | 5 | filesets: 6 | rtl: 7 | files: 8 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_mpu.v 9 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cortexm3.v 10 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_fpb.v 11 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/models.v 12 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_etm.v 13 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_wic.v 14 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_bus_matrix.v 15 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_dpu.v 16 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_dwt.v 17 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/dapswjdp.v 18 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_tpiu.v 19 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cortexm3_integration.v 20 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_dap_ahb_ap.v 21 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cmsdk.v 22 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_nvic.v 23 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_itm.v 24 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_mpu_defs.vp : {is_include_file : true} 25 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_dpu_defs.vp : {is_include_file : true} 26 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_nvic_defs.vp : {is_include_file : true} 27 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_mtx_undefs.vp : {is_include_file : true} 28 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_nvic_undefs.vp : {is_include_file : true} 29 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_etm_undefs.vp : {is_include_file : true} 30 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_mpu_undefs.vp : {is_include_file : true} 31 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_dap_ahb_ap_defs.vp : {is_include_file : true} 32 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_fpb_undefs.vp : {is_include_file : true} 33 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_dpu_undefs.vp : {is_include_file : true} 34 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_tpiu_defs.vp : {is_include_file : true} 35 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_etm_defs.vp : {is_include_file : true} 36 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_dap_ahb_ap_undefs.vp : {is_include_file : true} 37 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_dwt_defs.vp : {is_include_file : true} 38 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_mtx_defs.vp : {is_include_file : true} 39 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_dwt_undefs.vp : {is_include_file : true} 40 | - AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl/cm3_fpb_defs.vp : {is_include_file : true} 41 | file_type : verilogSource 42 | 43 | targets: 44 | default: 45 | filesets : [rtl] 46 | -------------------------------------------------------------------------------- /cm3_min_soc/bench/verilator/tb.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * mor1kx-generic system Verilator testbench 3 | * 4 | * Author: Olof Kindgren 5 | * Author: Franck Jullien 6 | * 7 | * This program is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU General Public License as published by the 9 | * Free Software Foundation; either version 2 of the License, or (at your 10 | * option) any later version. 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "Vcm3_min_soc__Syms.h" 20 | 21 | static bool done; 22 | 23 | #define RESET_TIME 4 24 | 25 | vluint64_t main_time = 0; // Current simulation time 26 | // This is a 64-bit integer to reduce wrap over issues and 27 | // allow modulus. You can also use a double, if you wish. 28 | 29 | double sc_time_stamp () { // Called by $time in Verilog 30 | return main_time; // converts to double, to match 31 | // what SystemC does 32 | } 33 | 34 | void INThandler(int signal) 35 | { 36 | printf("\nCaught ctrl-c\n"); 37 | done = true; 38 | } 39 | 40 | static int parse_opt(int key, char *arg, struct argp_state *state) 41 | { 42 | switch (key) { 43 | case ARGP_KEY_INIT: 44 | state->child_inputs[0] = state->input; 45 | break; 46 | // Add parsing of custom options here 47 | } 48 | 49 | return 0; 50 | } 51 | 52 | static int parse_args(int argc, char **argv, VerilatorUtils* utils) 53 | { 54 | struct argp_option options[] = { 55 | // Add custom options here 56 | { 0 } 57 | }; 58 | struct argp_child child_parsers[] = { 59 | { &verilator_utils_argp, 0, "", 0 }, 60 | { 0 } 61 | }; 62 | struct argp argp = { options, parse_opt, 0, 0, child_parsers }; 63 | 64 | return argp_parse(&argp, argc, argv, 0, 0, utils); 65 | } 66 | 67 | int main(int argc, char **argv, char **env) 68 | { 69 | uint32_t insn = 0; 70 | uint32_t ex_pc = 0; 71 | 72 | Verilated::commandArgs(argc, argv); 73 | 74 | Vcm3_min_soc* top = new Vcm3_min_soc; 75 | VerilatorUtils* utils = 76 | new VerilatorUtils((uint32_t *)&top->cm3_min_soc->u_rom->ram_inst->genblk1__DOT__ram_inst->mem_array); 77 | 78 | parse_args(argc, argv, utils); 79 | signal(SIGINT, INThandler); 80 | 81 | top->CLK = 0; 82 | top->PORESETn = 0; 83 | top->trace(utils->tfp, 99); 84 | top->IRQ = 0; 85 | 86 | while (utils->doCycle() && !done) { 87 | if (utils->getTime() > RESET_TIME) 88 | top->PORESETn = 1; 89 | 90 | top->eval(); 91 | top->CLK = !top->CLK; 92 | utils->doJTAGServer (&top->TCK, top->TDO, &top->TDI, top->TMSOE ? &top->TMSOUT : &top->TMSIN, &top->PORESETn); 93 | utils->doGPIOServer ((uint64_t *)&top->IRQ, 16, 0, 0); 94 | 95 | } 96 | 97 | delete utils; 98 | exit(0); 99 | } 100 | -------------------------------------------------------------------------------- /cm3_min_soc/cm3_min_soc.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::cm3_min_soc:0.1 3 | description: Minimal SoC using ARM Cortex-M3 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - cm3_core 9 | - ahb3lite_memory 10 | - ahb3lite_apb_bridge 11 | - ahb3lite_default_slave 12 | - apb4_gpio 13 | files: 14 | - rtl/cm3_min_soc.sv : {file_type : verilogSource} 15 | 16 | fpga_top: 17 | files: 18 | - rtl/fpga_top.sv : {file_type : verilogSource} 19 | 20 | cm3_full_dep: 21 | depend: 22 | - cm3_full 23 | 24 | ahb3lite_intercon_dep: 25 | depend: 26 | - ahb3lite_intercon 27 | 28 | verilator_tb: 29 | depend: 30 | - verilator_utils 31 | files: 32 | - bench/verilator/tb.cpp : {file_type : cppSource} 33 | 34 | support: 35 | files: 36 | - scripts/cortexm3sim.cfg 37 | - fw/blinky.bin 38 | - fw/blinky_sim.bin 39 | - fw/blinky.hex 40 | file_type: user 41 | 42 | constraints: 43 | files: 44 | - vivado/clocks.xdc : {file_type : xdc} 45 | - vivado/pins.xdc : {file_type : xdc} 46 | - vivado/vivado.tcl : {file_type : tclSource} 47 | 48 | generate: 49 | soc_intercon: 50 | generator: ahb3lite_intercon_gen 51 | parameters: 52 | masters: 53 | ahb3_cm3_code: 54 | priority: 0 55 | ahb3_cm3_sys: 56 | priority: 0 57 | slaves: 58 | ahb3_rom: 59 | offset: 0 60 | size: 16384 61 | ahb3_ram: 62 | offset: 0x20000000 63 | size: 16384 64 | ahb3_apb_brg: 65 | offset: 0x40000000 66 | size: 64 67 | ahb3_default_slave: 68 | idx: 3 # Force last slave 69 | offset: 0 70 | size: 0xffffffff 71 | 72 | targets: 73 | default: &base 74 | generate: [soc_intercon] 75 | filesets: [ahb3lite_intercon_dep, rtl, support] 76 | parameters: [XILINX_ENC_CM3=0,ROM_SZ,RAM_SZ] 77 | 78 | sim: 79 | <<: *base 80 | description: Simulate CM3 SoC using verilator 81 | default_tool: verilator 82 | filesets_append: [verilator_tb] 83 | parameters: [XILINX_ENC_CM3=0,ROM_SZ=2048,RAM_SZ=2048,ROM_FILE] 84 | toplevel: [cm3_min_soc] 85 | tools: 86 | verilator: 87 | verilator_options: [-sv, --cc, --trace, --clk, CLK] 88 | make_options: [OPT=-O3] 89 | run_options: [--timeout=1] 90 | 91 | arty: 92 | <<: *base 93 | description: Synthesize obsfucated CM3 SoC for Digilent Arty-A35T (30MHz) 94 | default_tool: vivado 95 | filesets_append: [fpga_top, constraints] 96 | parameters: [XILINX_ENC_CM3=0,ROM_SZ,RAM_SZ,ROM_FILE=../src/cm3_min_soc_0.1/fw/blinky.hex] 97 | toplevel: [fpga_top] 98 | tools: 99 | vivado: 100 | part: xc7a35ticsg324-1L 101 | #vivado-settings: /opt/xilinx/Vivado/2020.1/settings64.sh 102 | 103 | arty_full: 104 | <<: *base 105 | description: Synthesize encrypted CM3 SoC for Digilent Arty-A35T (50MHz) 106 | default_tool: vivado 107 | filesets_append: [cm3_full_dep, fpga_top, constraints] 108 | parameters: [XILINX_ENC_CM3=1,ROM_SZ,RAM_SZ,ROM_FILE=../src/cm3_min_soc_0.1/fw/blinky.hex] 109 | toplevel: [fpga_top] 110 | tools: 111 | vivado: 112 | part: xc7a35ticsg324-1L 113 | #vivado-settings: /opt/xilinx/Vivado/2020.1/settings64.sh 114 | 115 | parameters: 116 | XILINX_ENC_CM3: 117 | datatype: int 118 | description: Synthesize encrypted cortex-m3 core in Vivado 119 | paramtype: vlogparam 120 | 121 | ROM_FILE: 122 | datatype: str 123 | description: Boot file in readmemh format (xxd -e | xxd -r | xxd -p -c4) 124 | paramtype: vlogparam 125 | 126 | ROM_SZ: 127 | datatype: int 128 | default: 16384 129 | description: Set size of ROM 130 | paramtype: vlogparam 131 | 132 | RAM_SZ: 133 | datatype: int 134 | default: 16384 135 | description: Set size of RAM 136 | paramtype: vlogparam 137 | -------------------------------------------------------------------------------- /cm3_min_soc/fw/blinky.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinylabs/tinylabs-cores/49a9a106b1f441996626c1a6e88271331244c101/cm3_min_soc/fw/blinky.bin -------------------------------------------------------------------------------- /cm3_min_soc/fw/blinky.hex: -------------------------------------------------------------------------------- 1 | 20004000 2 | 00000159 3 | 00000155 4 | 00000155 5 | 00000155 6 | 00000155 7 | 00000155 8 | 00000155 9 | 00000155 10 | 00000155 11 | 00000155 12 | 00000155 13 | 00000155 14 | 00000155 15 | 00000155 16 | 00000155 17 | 00000045 18 | af00b480 19 | 681b4b22 20 | f00369db 21 | 2b000301 22 | 4b1fd00f 23 | 69da681b 24 | 681b4b1d 25 | 0201f042 26 | 4b1b61da 27 | 689a681b 28 | 681b4b19 29 | 0218f082 30 | 4b17609a 31 | 69db681b 32 | 0302f003 33 | d0232b00 34 | 681b4b13 35 | 4b1269da 36 | f042681b 37 | 61da0202 38 | 781b4b10 39 | b2db3301 40 | 0307f003 41 | 4b0db2da 42 | 4b0b701a 43 | 689a681b 44 | 681b4b09 45 | 02e0f022 46 | 4b07609a 47 | 689a681b 48 | 781b4b06 49 | 4619015b 50 | 681b4b03 51 | 609a430a 52 | 46bdbf00 53 | 4770bc80 54 | 20000000 55 | 20000004 56 | b083b480 57 | 6078af00 58 | 687bbf00 59 | 607a1e5a 60 | d1fa2b00 61 | bf00bf00 62 | 46bd370c 63 | 4770bc80 64 | af00b580 65 | 681b4b11 66 | 605a22fc 67 | 681b4b0f 68 | 611a2203 69 | 681b4b0d 70 | 619a2203 71 | 681b4b0b 72 | 621a2203 73 | 681b4b09 74 | 609a2208 75 | 22014b08 76 | 4b06601a 77 | 689a681b 78 | 681b4b04 79 | 0204f082 80 | 4804609a 81 | ffccf7ff 82 | bf00e7f3 83 | 20000000 84 | e000e100 85 | 0016e360 86 | bffef7ff 87 | 4a1c491b 88 | 1a9b4b1c 89 | 3b04dd03 90 | 50d058c8 91 | 491adcfb 92 | 1a524a1a 93 | f04fd004 94 | 3a040000 95 | dcfc5088 96 | 47804817 97 | 4170f04f 98 | bf0c2800 99 | 22014a15 100 | e7fe600a 101 | f013b410 102 | d0143fff 103 | 3ffff012 104 | 00dbbf14 105 | f013e005 106 | bf040f07 107 | 4b01f812 108 | 08404060 109 | 4048bf28 110 | d0043b01 111 | 3ffff012 112 | e7f6bf08 113 | bc10e7ef 114 | 00004770 115 | 000001e4 116 | 20000000 117 | 20000004 118 | 20000004 119 | 20000008 120 | 000000fd 121 | 00020026 122 | 40000000 123 | -------------------------------------------------------------------------------- /cm3_min_soc/fw/blinky_sim.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinylabs/tinylabs-cores/49a9a106b1f441996626c1a6e88271331244c101/cm3_min_soc/fw/blinky_sim.bin -------------------------------------------------------------------------------- /cm3_min_soc/rtl/fpga_top.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * Top wrapper for FPGA. This is necessary as Verilator doesn't handle INOUT nets currently 3 | * 4 | * Tiny Labs Inc 5 | * 2020 6 | **/ 7 | 8 | module fpga_top 9 | #( 10 | parameter XILINX_ENC_CM3 = 0, 11 | parameter ROM_SZ = 0, 12 | parameter RAM_SZ = 0, 13 | parameter ROM_FILE = "" 14 | )( 15 | input CLK_100M, 16 | input RESET, 17 | // JTAG/SWD pins 18 | input TCK_SWDCLK, 19 | input TDI, 20 | inout TMS_SWDIO, 21 | output TDO, 22 | // GPIO port 23 | inout [7:0] GPIO 24 | ); 25 | 26 | 27 | // Clocks and PLL 28 | logic hclk; 29 | logic pll_locked, pll_feedback; 30 | 31 | generate 32 | if (XILINX_ENC_CM3) begin : gen_pll 33 | 34 | // Full CM3 core PLL timing 35 | PLLE2_BASE #( 36 | .BANDWIDTH ("OPTIMIZED"), 37 | .CLKFBOUT_MULT (10), 38 | .CLKOUT0_DIVIDE(20), // 50MHz 39 | .CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB, (-360-360) 40 | .CLKIN1_PERIOD(10.0), // 100MHz input clock 41 | .CLKOUT0_DUTY_CYCLE(0.5), 42 | .CLKOUT0_PHASE(0.0), 43 | .DIVCLK_DIVIDE(1), // Master division value , (1-56) 44 | .REF_JITTER1(0.0), // Reference input jitter in UI (0.000-0.999) 45 | .STARTUP_WAIT("FALSE") // Delay DONE until PLL Locks, ("TRUE"/"FALSE") 46 | ) u_pll ( 47 | // Clock outputs: 1-bit (each) output 48 | .CLKOUT0(hclk), 49 | .CLKOUT1(), 50 | .CLKOUT2(), 51 | .CLKOUT3(), 52 | .CLKOUT4(), 53 | .CLKOUT5(), 54 | .CLKFBOUT(pll_feedback), // 1-bit output, feedback clock 55 | .LOCKED(pll_locked), 56 | .CLKIN1(CLK_100M), 57 | .PWRDWN(1'b0), 58 | .RST(1'b0), 59 | .CLKFBIN(pll_feedback) // 1-bit input, feedback clock 60 | ); 61 | end // block: gen_pll 62 | else begin : gen_pll 63 | 64 | // Obsfucated CM3 core can only support 32MHz HCLK 65 | PLLE2_BASE #( 66 | .BANDWIDTH ("OPTIMIZED"), 67 | .CLKFBOUT_MULT (16), 68 | .CLKOUT0_DIVIDE(50), // 32MHz 69 | .CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB, (-360-360) 70 | .CLKIN1_PERIOD(10.0), // 100MHz input clock 71 | .CLKOUT0_DUTY_CYCLE(0.5), 72 | .CLKOUT0_PHASE(0.0), 73 | .DIVCLK_DIVIDE(1), // Master division value , (1-56) 74 | .REF_JITTER1(0.0), // Reference input jitter in UI (0.000-0.999) 75 | .STARTUP_WAIT("FALSE") // Delay DONE until PLL Locks, ("TRUE"/"FALSE") 76 | ) u_pll ( 77 | // Clock outputs: 1-bit (each) output 78 | .CLKOUT0(hclk), 79 | .CLKOUT1(), 80 | .CLKOUT2(), 81 | .CLKOUT3(), 82 | .CLKOUT4(), 83 | .CLKOUT5(), 84 | .CLKFBOUT(pll_feedback), // 1-bit output, feedback clock 85 | .LOCKED(pll_locked), 86 | .CLKIN1(CLK_100M), 87 | .PWRDWN(1'b0), 88 | .RST(1'b0), 89 | .CLKFBIN(pll_feedback) // 1-bit input, feedback clock 90 | ); 91 | 92 | end 93 | endgenerate 94 | 95 | // Generate reset logic from pushbutton/pll 96 | logic poreset_n; 97 | logic [7:0] reset_ctr; 98 | always @(posedge hclk) 99 | begin 100 | if (RESET | !pll_locked) 101 | reset_ctr <= 'hff; 102 | else if (reset_ctr) 103 | reset_ctr = reset_ctr - 1; 104 | end 105 | assign poreset_n = reset_ctr ? 1'b0 : 1'b1; 106 | 107 | // Inferred BUFIO on SWDIO 108 | logic swdoe, swdout; 109 | assign TMS_SWDIO = swdoe ? swdout : 1'bz; 110 | 111 | // Inferred BUFIO for gpio 112 | logic [7:0] gpio_o, gpio_oe; 113 | generate 114 | genvar i; 115 | for (i = 0; i < 8; i++) 116 | assign GPIO[i] = gpio_oe[i] ? gpio_o[i] : 1'bz; 117 | endgenerate 118 | 119 | // Instantiate soc 120 | cm3_min_soc 121 | #( 122 | .XILINX_ENC_CM3 (XILINX_ENC_CM3), 123 | .ROM_SZ (ROM_SZ), 124 | .RAM_SZ (RAM_SZ), 125 | .ROM_FILE (ROM_FILE) 126 | ) 127 | u_soc ( 128 | .CLK (hclk), 129 | .PORESETn (poreset_n), 130 | .TCK_SWDCLK (TCK_SWDCLK), 131 | .TDI (TDI), 132 | .TMS_SWDIN (TMS_SWDIO), 133 | .TDO (TDO), 134 | .SWDOUT (swdout), 135 | .SWDOUTEN (swdoe), 136 | .GPIO_O (gpio_o), 137 | .GPIO_I (GPIO), 138 | .GPIO_OE (gpio_oe) 139 | ); 140 | 141 | endmodule // fpga_top 142 | -------------------------------------------------------------------------------- /cm3_min_soc/scripts/cortexm3sim.cfg: -------------------------------------------------------------------------------- 1 | adapter driver remote_bitbang 2 | remote_bitbang_host localhost 3 | remote_bitbang_port 2345 4 | 5 | set _CHIPNAME CortexM3Sim 6 | set _CPUTAPID 0x4BA00477 7 | set _TARGETNAME $_CHIPNAME.cpu 8 | 9 | eval jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID 10 | dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu 11 | target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap 12 | $_TARGETNAME configure -work-area-phys 0x20001000 -work-area-size 0x1000 13 | 14 | reset_config none separate 15 | cortex_m reset_config sysresetreq 16 | 17 | init 18 | reset halt 19 | -------------------------------------------------------------------------------- /cm3_min_soc/vivado/clocks.xdc: -------------------------------------------------------------------------------- 1 | # Setup global configs 2 | set_property CFGBVS Vcco [current_design] 3 | set_property CONFIG_VOLTAGE 3.3 [current_design] 4 | 5 | # System clock 6 | create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports { CLK_100M }]; 7 | 8 | # 4MHz JTAG/SWD clock 9 | create_clock -add -name jtag_clk -period 250.00 -waveform {0 125} [get_ports { TCK_SWDCLK }]; 10 | 11 | # Create virtual clock for IO 12 | create_clock -name slow_clk -period 1000.0 13 | -------------------------------------------------------------------------------- /cm3_min_soc/vivado/pins.xdc: -------------------------------------------------------------------------------- 1 | # Pin placement 2 | set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { CLK_100M }]; 3 | set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { RESET }]; # BTN0 4 | 5 | # JTAG 6 | set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { TCK_SWDCLK }]; # IO13 7 | set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { TDI }]; # IO12 8 | set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { TDO }]; # IO11 9 | set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { TMS_SWDIO }]; # IO10 10 | 11 | # GPIOs 12 | set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { GPIO[0] }]; # BTN2 13 | set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { GPIO[1] }]; # BTN3 14 | set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { GPIO[2] }]; # LED4 15 | set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { GPIO[3] }]; # LED6 16 | set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { GPIO[4] }]; # LED7 17 | set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { GPIO[5] }]; # LED0-blue 18 | set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { GPIO[6] }]; # LED0-grn 19 | set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { GPIO[7] }]; # LED0-red 20 | 21 | 22 | # Ignore timing on async reset 23 | set_false_path -from [get_ports { RESET }] 24 | 25 | # Untimed ports 26 | set untimed_od 0.5 27 | set untimed_id 0.5 28 | set_input_delay -clock [get_clocks hclk] -add_delay $untimed_id [get_ports RESET] 29 | set_input_delay -clock [get_clocks slow_clk] -add_delay $untimed_id [get_ports GPIO*] 30 | set_output_delay -clock [get_clocks slow_clk] -add_delay $untimed_od [get_ports GPIO*] 31 | -------------------------------------------------------------------------------- /cm3_min_soc/vivado/vivado.tcl: -------------------------------------------------------------------------------- 1 | # Ignore message about ignoring assertions 2 | set_msg_config -id {Synth 8-2898} -suppress 3 | # Ignore non-standard IP output 4 | set_msg_config -id {filemgmt 56-3} -suppress 5 | # Ignore unknown vendor 6 | set_msg_config -id {IP_Flow 19-3899} -suppress 7 | # Ignore multiple defs of cm3_code_mux 8 | set_msg_config -id {Synth 8-2490} -suppress 9 | # Async reset used on sys bus on encrypted core - just ignore 10 | set_msg_config -id {DRC REQP-1839} -suppress 11 | # We cannot control the internal DSP pipelining (core is encrypted) ignore 12 | set_msg_config -id {DRC DPIP-1} -suppress 13 | set_msg_config -id {DRC DPOP-1} -suppress 14 | set_msg_config -id {DRC DPOP-2} -suppress 15 | 16 | # Just annoying 17 | set_msg_config -id {Constraints 18-483} -suppress 18 | set_msg_config -id {Vivado 12-584} -suppress 19 | 20 | # Is this needed? 21 | set_property IS_ENABLED 0 [get_drc_checks {DRC REQP-1839}] 22 | set_property IS_ENABLED 0 [get_drc_checks {DRC DPIP-1}] 23 | set_property IS_ENABLED 0 [get_drc_checks {DRC DPOP-1}] 24 | set_property IS_ENABLED 0 [get_drc_checks {DRC DPOP-2}] 25 | 26 | # Make sure top constraint is run first 27 | reorder_files -fileset constrs_1 -front [get_files clocks.xdc] 28 | 29 | # Set flags for files 30 | set_property USED_IN_SYNTHESIS false [get_files pins.xdc] 31 | -------------------------------------------------------------------------------- /cm3_obs/cm3_obs.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::cm3_obs:1.0 3 | description: Cortex-M3 obsfucated synthesizable RTL 4 | 5 | filesets: 6 | rtl: 7 | files: 8 | - m3designstart/logical/cortexm3integration_ds/verilog/cm3_code_mux.v 9 | - m3designstart/logical/cortexm3integration_ds_obs/verilog/cortexm3ds_logic.v 10 | - m3designstart/logical/cortexm3integration_ds_obs/verilog/CORTEXM3INTEGRATIONDS.v 11 | file_type : verilogSource 12 | 13 | targets: 14 | default: 15 | filesets : [rtl] 16 | 17 | provider: 18 | name : github 19 | user : Grekery 20 | repo : AT421-MN-80001-r0p0-02rel0 21 | patches : [files/0001-Remove-verilator-warnings.patch, 22 | files/0002-Remove-async-reset.patch] 23 | -------------------------------------------------------------------------------- /cm3_obs/files/0001-Remove-verilator-warnings.patch: -------------------------------------------------------------------------------- 1 | From f0a3126405bb4bca5f2e27277ca8c25556308c00 Mon Sep 17 00:00:00 2001 2 | From: Elliot Buller 3 | Date: Wed, 17 Jun 2020 14:43:24 -0600 4 | Subject: [PATCH 1/1] Remove verilator warnings 5 | 6 | --- 7 | .../cortexm3integration_ds_obs/verilog/cortexm3ds_logic.v | 5 +++++ 8 | 1 file changed, 5 insertions(+) 9 | 10 | diff --git a/m3designstart/logical/cortexm3integration_ds_obs/verilog/cortexm3ds_logic.v b/m3designstart/logical/cortexm3integration_ds_obs/verilog/cortexm3ds_logic.v 11 | index b5e4b07..9ca5504 100644 12 | --- a/m3designstart/logical/cortexm3integration_ds_obs/verilog/cortexm3ds_logic.v 13 | +++ b/m3designstart/logical/cortexm3integration_ds_obs/verilog/cortexm3ds_logic.v 14 | @@ -24,6 +24,9 @@ 15 | // Cortex-M3 DesignStart processor logic level 16 | //------------------------------------------------------------------------------ 17 | 18 | +/* Disable verilator warnings just for this file */ 19 | +/* verilator lint_off WIDTH */ 20 | +/* verilator lint_off UNOPTFLAT */ 21 | module cortexm3ds_logic 22 | (ISOLATEn, RETAINn, nTRST, SWCLKTCK, SWDITMS, TDI, 23 | PORESETn, SYSRESETn, RSTBYPASS, CGBYPASS, FCLK, HCLK, TRACECLKIN, STCLK, 24 | @@ -94611,3 +94614,5 @@ endmodule 25 | // EOF 26 | //------------------------------------------------------------------------------ 27 | 28 | +/* verilator lint_on UNOPTFLAT */ 29 | +/* verilator lint_on WIDTH */ 30 | -- 31 | 2.20.1 32 | 33 | -------------------------------------------------------------------------------- /cm3_obs/files/0002-Remove-async-reset.patch: -------------------------------------------------------------------------------- 1 | From c92bef2ae756694df15da7ff45cb0dbfb443afc5 Mon Sep 17 00:00:00 2001 2 | From: Elliot Buller 3 | Date: Thu, 25 Jun 2020 10:22:20 -0600 4 | Subject: [PATCH] Remove async reset 5 | 6 | --- 7 | .../logical/cortexm3integration_ds/verilog/cm3_code_mux.v | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/m3designstart/logical/cortexm3integration_ds/verilog/cm3_code_mux.v b/m3designstart/logical/cortexm3integration_ds/verilog/cm3_code_mux.v 11 | index 38ef9ca..e9e96c6 100644 12 | --- a/m3designstart/logical/cortexm3integration_ds/verilog/cm3_code_mux.v 13 | +++ b/m3designstart/logical/cortexm3integration_ds/verilog/cm3_code_mux.v 14 | @@ -114,7 +114,7 @@ module cm3_code_mux ( 15 | assign EXRESPD = d_trans_active_reg & EXRESPC; 16 | 17 | // Registered d_trans_active 18 | - always @ (posedge HCLK or negedge HRESETn) 19 | + always @ (posedge HCLK) 20 | begin 21 | if (!HRESETn) 22 | d_trans_active_reg <= 1'b0; 23 | -- 24 | 2.20.1 25 | 26 | -------------------------------------------------------------------------------- /fifo_arb/fifo_arb.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::fifo_arb:1.0 3 | 4 | filesets: 5 | rtl: 6 | depend: 7 | - fifo_arb_rx 8 | - fifo_arb_tx 9 | files: 10 | - rtl/fifo_arb.sv 11 | file_type : verilogSource 12 | 13 | targets: 14 | default: 15 | description: FIFO bidirectional arbiter 16 | filesets : [rtl] 17 | -------------------------------------------------------------------------------- /fifo_arb/rtl/fifo_arb.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * Bidirectional FIFO arbiter - Two unidirectional fifos connect to a common source/sink 3 | * Two clients connected each have a receive and transmit fifo. 4 | * 5 | * All rights reserved. 6 | * Tiny Labs Inc 7 | * 2020 8 | */ 9 | 10 | module fifo_arb #( 11 | parameter DW = 8, 12 | parameter AW = 3, 13 | parameter SELMASK = 8'h80, 14 | parameter CNTMASK = 8'h70 15 | ) 16 | ( 17 | // Global connections 18 | input CLK, 19 | input RESETn, 20 | 21 | // Common birectional FIFO 22 | output com_rden, 23 | input com_rdempty, 24 | input [DW-1:0] com_rddata, 25 | output com_wren, 26 | input com_wrfull, 27 | output [DW-1:0] com_wrdata, 28 | 29 | // Client 1 30 | input c1_rden, 31 | output c1_rdempty, 32 | output [DW-1:0] c1_rddata, 33 | input c1_wren, 34 | output c1_wrfull, 35 | input [DW-1:0] c1_wrdata, 36 | 37 | // Client 2 38 | input c2_rden, 39 | output c2_rdempty, 40 | output [DW-1:0] c2_rddata, 41 | input c2_wren, 42 | output c2_wrfull, 43 | input [DW-1:0] c2_wrdata 44 | ); 45 | 46 | // Instantiate RX arbiter 47 | fifo_arb_rx #( 48 | .SELMASK (SELMASK), 49 | .CNTMASK (CNTMASK), 50 | .DWIDTH (DW), 51 | .AWIDTH (AW)) 52 | u_arb_rx ( 53 | .CLK (CLK), 54 | .RESETn (RESETn), 55 | // Client 1 56 | .c1_rden (c1_rden), 57 | .c1_rdempty (c1_rdempty), 58 | .c1_rddata (c1_rddata), 59 | // Client 2 60 | .c2_rden (c2_rden), 61 | .c2_rdempty (c2_rdempty), 62 | .c2_rddata (c2_rddata), 63 | // Common 64 | .fifo_rden (com_rden), 65 | .fifo_rdempty (com_rdempty), 66 | .fifo_rddata (com_rddata) 67 | ); 68 | 69 | // Instantiate TX arbiter 70 | fifo_arb_tx #( 71 | .SELMASK (SELMASK), 72 | .CNTMASK (CNTMASK), 73 | .DWIDTH (DW), 74 | .AWIDTH (AW)) 75 | u_arb_tx ( 76 | .CLK (CLK), 77 | .RESETn (RESETn), 78 | // Client 1 79 | .c1_wren (c1_wren), 80 | .c1_wrfull (c1_wrfull), 81 | .c1_wrdata (c1_wrdata), 82 | // Client 2 83 | .c2_wren (c2_wren), 84 | .c2_wrfull (c2_wrfull), 85 | .c2_wrdata (c2_wrdata), 86 | // Common 87 | .fifo_wren (com_wren), 88 | .fifo_wrfull (com_wrfull), 89 | .fifo_wrdata (com_wrdata) 90 | ); 91 | 92 | endmodule // fifo_arb 93 | -------------------------------------------------------------------------------- /fifo_arb_rx/bench/fifo_arb_rx_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | * FIFO testbench 3 | * 4 | * Copyright (C) 2017 Olof Kindgren 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | module fifo_arb_rx_tb 19 | #(parameter data_width = 8, 20 | parameter depth_width = 8); 21 | 22 | localparam DEPTH = 1< 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | module fifo_reader1 19 | #( 20 | parameter WIDTH = 0, 21 | parameter MAX_BLOCK_SIZE = 1024) 22 | ( 23 | input clk, 24 | input [WIDTH-1:0] din, 25 | output reg rden = 1'b0, 26 | input empty); 27 | 28 | task read_word; 29 | output [WIDTH-1:0] data_o; 30 | begin 31 | @(posedge clk); 32 | rden = 1; 33 | @(negedge clk); 34 | rden = 0; 35 | data_o = din; 36 | end 37 | endtask 38 | 39 | endmodule 40 | -------------------------------------------------------------------------------- /fifo_arb_rx/bench/fifo_tester.v: -------------------------------------------------------------------------------- 1 | /* 2 | * FIFO stimuli generator/checker 3 | * 4 | * Copyright (C) 2017 Olof Kindgren 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | module fifo_tester 19 | #(parameter DEPTH = 0, 20 | parameter DW = 0) 21 | ( 22 | input wire rst_i, 23 | input wire wr_clk_i, 24 | output wire wr_en_o, 25 | output wire [DW-1:0] wr_data_o, 26 | input wire full_i, 27 | input wire rd_clk_i, 28 | // Output fifo 1 29 | output wire f1_rd_en_o, 30 | input wire [DW-1:0] f1_rd_data_i, 31 | input wire f1_empty_i, 32 | // Output fifo 2 33 | output wire f2_rd_en_o, 34 | input wire [DW-1:0] f2_rd_data_i, 35 | input wire f2_empty_i 36 | ); 37 | 38 | // Host fifo definitions 39 | import host_fifo_pkg::*; 40 | 41 | function [DW-1:0] randvec; 42 | integer idx; 43 | 44 | for (idx = DW ; idx>0 ; idx=idx-32) 45 | randvec = (randvec << 32) | $urandom; 46 | endfunction 47 | 48 | reg [DW-1:0] mem [0:DEPTH-1]; 49 | 50 | integer seed = 32'hdeadbeef; 51 | 52 | fifo_writer 53 | #(.WIDTH (DW)) 54 | writer 55 | (.clk (wr_clk_i), 56 | .dout (wr_data_o), 57 | .wren (wr_en_o), 58 | .full (full_i)); 59 | 60 | fifo_reader1 61 | #(.WIDTH (DW)) 62 | reader1 63 | (.clk (rd_clk_i), 64 | .din (f1_rd_data_i), 65 | .rden (f1_rd_en_o), 66 | .empty (f1_empty_i)); 67 | 68 | fifo_reader1 69 | #(.WIDTH (DW)) 70 | reader2 71 | (.clk (rd_clk_i), 72 | .din (f2_rd_data_i), 73 | .rden (f2_rd_en_o), 74 | .empty (f2_empty_i)); 75 | 76 | 77 | task fifo_write; 78 | input integer transactions_i; 79 | input real write_rate; 80 | 81 | integer index; 82 | integer tmp; 83 | reg [DW-1:0] data; 84 | integer dw_idx; 85 | 86 | //$urandom (seed); 87 | 88 | begin 89 | //Cap rate to [0.0-1.0] 90 | if(write_rate > 1.0) write_rate = 1.0; 91 | if(write_rate < 0.0) write_rate = 0.0; 92 | writer.rate = write_rate; 93 | 94 | index = 0; 95 | 96 | @(posedge wr_clk_i); 97 | while(index < transactions_i) begin 98 | 99 | data = randvec(); 100 | 101 | mem[index % DEPTH] = data; 102 | writer.write_word(data); 103 | 104 | index = index + 1; 105 | end 106 | end 107 | endtask 108 | 109 | task fifo_verify; 110 | input integer transactions_i; 111 | input real read_rate; 112 | output integer errors; 113 | input [DW-1:0] selmask; 114 | input integer cntshift; 115 | input integer cntmask; 116 | 117 | 118 | integer index; 119 | integer cidx; 120 | 121 | reg [DW-1:0] received; 122 | reg [DW-1:0] expected; 123 | reg [DW-1:0] cmd; 124 | reg [host_fifo_pkg::FIFO_PAYLOAD_WIDTH-1:0] cnt; 125 | 126 | begin 127 | errors = 0; 128 | 129 | index = 0; 130 | @(posedge rd_clk_i); 131 | while (index < transactions_i) 132 | begin 133 | 134 | // Get expected 135 | cmd = mem[index % DEPTH]; 136 | cnt = host_fifo_pkg::fifo_payload ((cmd >> cntshift) & cntmask); 137 | 138 | // Clear idx 139 | cidx = 0; 140 | 141 | // Verify command 142 | if ((cmd & selmask) != 0) 143 | reader1.read_word(received); 144 | else 145 | reader2.read_word(received); 146 | if(cmd !== received) 147 | begin 148 | $display("Error at index %0d. Expected 0x%4x, got 0x%4x", index, expected, received); 149 | errors = errors + 1; 150 | end 151 | index = index + 1; 152 | 153 | // Verify data 154 | while (cidx < cnt) 155 | begin 156 | 157 | // Get expected 158 | expected = mem[index % DEPTH]; 159 | 160 | // Read word 161 | if ((cmd & selmask) != 0) 162 | reader1.read_word(received); 163 | else 164 | reader2.read_word(received); 165 | 166 | // Verify expected 167 | if(expected !== received) 168 | begin 169 | $display("Error at index %0d. Expected 0x%4x, got 0x%4x", index, expected, received); 170 | errors = errors + 1; 171 | end 172 | index = index + 1; 173 | cidx = cidx + 1; 174 | 175 | end // while (cidx < cnt) 176 | end // while (index < transactions_i) 177 | end 178 | 179 | endtask 180 | 181 | endmodule 182 | -------------------------------------------------------------------------------- /fifo_arb_rx/fifo_arb_rx.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::fifo_arb_rx:0.1 3 | description: Arbiter for two clients on one source FIFO 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - fifo 9 | - host_fifo_pkg 10 | files: 11 | - rtl/fifo_arb_rx.sv 12 | file_type : verilogSource 13 | 14 | tb: 15 | depend: 16 | - host_fifo_pkg 17 | - ">=vlog_tb_utils-1.0" 18 | files: 19 | - bench/fifo_arb_rx_tb.v 20 | - bench/fifo_tester.v 21 | - bench/fifo_reader1.v 22 | file_type : verilogSource 23 | 24 | targets: 25 | default: 26 | filesets : [rtl] 27 | 28 | sim: 29 | default_tool : icarus 30 | tools: 31 | icarus: 32 | iverilog_options: [-g2012] 33 | filesets : [rtl, tb] 34 | parameters : [read_rate, write_rate, data_width, depth_width] 35 | toplevel : [fifo_arb_rx_tb] 36 | 37 | parameters: 38 | read_rate: 39 | datatype : str 40 | description : FIFO read rate 41 | paramtype : plusarg 42 | 43 | write_rate: 44 | datatype : str 45 | description : FIFO write rate 46 | paramtype : plusarg 47 | 48 | data_width: 49 | datatype : int 50 | description : FIFO data width 51 | paramtype : vlogparam 52 | 53 | depth_width: 54 | datatype : int 55 | description : 2**(FIFO depth) 56 | paramtype : vlogparam 57 | -------------------------------------------------------------------------------- /fifo_arb_rx/rtl/fifo_arb_rx.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * FIFO rx arbiter - Checks against bitmask and passes signals to one of two clients. 3 | * 4 | * parameters: 5 | * SELMASK - This is a bitmask that when matched will route data to fifo c1 6 | * If not matched data will route to fifo c2. 7 | * CNTMASK - Mask pointing to contiguous CNT bits. Only 3 bits for count currently supported. 8 | * DWIDTH - Data width 9 | * AWIDTH - Address width of instantiated FIFOs. 10 | * 11 | * All rights reserved. 12 | * Tiny Labs Inc 13 | * 2020 14 | */ 15 | 16 | module fifo_arb_rx #( 17 | parameter SELMASK = 8'h80, 18 | parameter CNTMASK = 8'h70, 19 | parameter DWIDTH = 8, 20 | parameter AWIDTH = 3 21 | ) 22 | ( 23 | // Global 24 | input CLK, 25 | input RESETn, 26 | // Output client 1 27 | input c1_rden, 28 | output c1_rdempty, 29 | output [DWIDTH-1:0] c1_rddata, 30 | // Output client 2 31 | input c2_rden, 32 | output c2_rdempty, 33 | output [DWIDTH-1:0] c2_rddata, 34 | // Input FIFO 35 | output fifo_rden, 36 | input fifo_rdempty, 37 | input [DWIDTH-1:0] fifo_rddata 38 | ); 39 | 40 | // Import common definitions 41 | import host_fifo_pkg::*; 42 | 43 | // Calculate count shift 44 | localparam CSHIFT = $clog2 (CNTMASK) - FIFO_CNT_WIDTH; 45 | localparam CMASK = (2**FIFO_CNT_WIDTH) - 1; 46 | 47 | // Internal write logic to each fifo 48 | wire c1_wren, c2_wren; 49 | wire c1_wrfull, c2_wrfull; 50 | wire [DWIDTH-1:0] c1_wrdata, c2_wrdata; 51 | 52 | // Instantiate an internal fifo for each client 53 | fifo #( 54 | .DEPTH_WIDTH (AWIDTH), 55 | .DATA_WIDTH (DWIDTH) 56 | ) u_fifo1 57 | ( 58 | .clk (CLK), 59 | .rst (~RESETn), 60 | .wr_data_i (c1_wrdata), 61 | .wr_en_i (c1_wren), 62 | .rd_data_o (c1_rddata), 63 | .rd_en_i (c1_rden), 64 | .full_o (c1_wrfull), 65 | .empty_o (c1_rdempty) 66 | ); 67 | 68 | // Instantiate an internal fifo for each client 69 | fifo #( 70 | .DEPTH_WIDTH (AWIDTH), 71 | .DATA_WIDTH (DWIDTH) 72 | ) u_fifo2 73 | ( 74 | .clk (CLK), 75 | .rst (~RESETn), 76 | .wr_data_i (c2_wrdata), 77 | .wr_en_i (c2_wren), 78 | .rd_data_o (c2_rddata), 79 | .rd_en_i (c2_rden), 80 | .full_o (c2_wrfull), 81 | .empty_o (c2_rdempty) 82 | ); 83 | 84 | // Internal logic 85 | logic data_valid; 86 | logic [FIFO_PAYLOAD_WIDTH-1:0] dcnt; 87 | wire sel; 88 | logic psel; 89 | wire [DWIDTH-1:0] cmd; 90 | logic [DWIDTH-1:0] pcmd; 91 | 92 | // Mostly combinatorial logic 93 | assign fifo_rden = !fifo_rdempty & !c1_wrfull & !c2_wrfull & !c1_wren & !c2_wren; 94 | assign c1_wrdata = fifo_rddata; 95 | assign c2_wrdata = fifo_rddata; 96 | assign sel = (dcnt != 0) ? psel : 97 | ((cmd & SELMASK) != 0 ? 1 : 0); 98 | assign c1_wren = data_valid & sel & !c1_wrfull ? 1'b1 : 1'b0; 99 | assign c2_wren = data_valid & !sel & !c2_wrfull ? 1'b1 : 1'b0; 100 | assign cmd = (dcnt == 0) & data_valid ? fifo_rddata : pcmd; 101 | 102 | always @(posedge CLK) 103 | begin 104 | if (~RESETn) 105 | begin 106 | data_valid <= 0; 107 | dcnt <= 0; 108 | pcmd <= 0; 109 | psel <= 0; 110 | end 111 | else 112 | begin 113 | 114 | // Decode count field 115 | if (data_valid && (dcnt == 0)) 116 | dcnt <= fifo_payload (FIFO_CNT_WIDTH'((32'(cmd) >> CSHIFT) & CMASK)); 117 | 118 | // data_valid lags by one cycle 119 | if (fifo_rden) 120 | data_valid <= 1; 121 | else 122 | data_valid <= 0; 123 | 124 | // Decrement if data valid 125 | if (data_valid & (dcnt != 0)) 126 | dcnt <= dcnt - 1; 127 | 128 | // Save to prevent feedback 129 | pcmd <= cmd; 130 | psel <= sel; 131 | 132 | end 133 | end 134 | endmodule // fifo_arb_rx 135 | -------------------------------------------------------------------------------- /fifo_arb_tx/bench/fifo_arb_tx_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | * FIFO testbench 3 | * 4 | * Copyright (C) 2017 Olof Kindgren 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | module fifo_arb_tx_tb 19 | #(parameter data_width = 8, 20 | parameter depth_width = 8); 21 | 22 | localparam DEPTH = 1< 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | module fifo_reader1 19 | #( 20 | parameter WIDTH = 0, 21 | parameter MAX_BLOCK_SIZE = 1024) 22 | ( 23 | input clk, 24 | input [WIDTH-1:0] din, 25 | output reg rden = 1'b0, 26 | input empty); 27 | 28 | task read_word; 29 | output [WIDTH-1:0] data_o; 30 | begin 31 | @(posedge clk); 32 | rden = 1; 33 | @(negedge clk); 34 | rden = 0; 35 | data_o = din; 36 | end 37 | endtask 38 | 39 | endmodule 40 | -------------------------------------------------------------------------------- /fifo_arb_tx/bench/fifo_tester.v: -------------------------------------------------------------------------------- 1 | /* 2 | * FIFO stimuli generator/checker 3 | * 4 | * Copyright (C) 2017 Olof Kindgren 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | module fifo_tester 19 | #(parameter DEPTH = 0, 20 | parameter DW = 0, 21 | parameter SELMASK = 0, 22 | parameter CNTSHIFT = 0, 23 | parameter CNTMASK = 0) 24 | ( 25 | input wire rst_i, 26 | input wire wr_clk_i, 27 | input wire rd_clk_i, 28 | // DUT output 29 | input wire [DW-1:0] rd_data_o, 30 | input wire empty_i, 31 | output wire rd_en_o, 32 | // DUT inputs 33 | output wire f1_wr_en_o, 34 | output wire [DW-1:0] f1_wr_data_o, 35 | input wire f1_full_i, 36 | output wire f2_wr_en_o, 37 | output wire [DW-1:0] f2_wr_data_o, 38 | input wire f2_full_i 39 | ); 40 | 41 | function [DW-1:0] randvec; 42 | integer idx; 43 | 44 | for (idx = DW ; idx>0 ; idx=idx-32) 45 | randvec = (randvec << 32) | $urandom; 46 | endfunction 47 | 48 | reg [DW-1:0] mem [0:DEPTH-1]; 49 | 50 | integer seed = 32'hdeadbeef; 51 | 52 | fifo_writer 53 | #(.WIDTH (DW)) 54 | writer1 55 | (.clk (wr_clk_i), 56 | .dout (f1_wr_data_o), 57 | .wren (f1_wr_en_o), 58 | .full (f1_full_i)); 59 | 60 | fifo_writer 61 | #(.WIDTH (DW)) 62 | writer2 63 | (.clk (wr_clk_i), 64 | .dout (f2_wr_data_o), 65 | .wren (f2_wr_en_o), 66 | .full (f2_full_i)); 67 | 68 | fifo_reader1 69 | #(.WIDTH (DW)) 70 | reader 71 | (.clk (rd_clk_i), 72 | .din (rd_data_o), 73 | .rden (rd_en_o), 74 | .empty (empty_i)); 75 | 76 | 77 | task fifo_write; 78 | input integer transactions_i; 79 | input real write_rate; 80 | 81 | integer index; 82 | integer tmp; 83 | reg [DW-1:0] data; 84 | reg [DW-1:0] cmd; 85 | integer dw_idx; 86 | integer cnt; 87 | 88 | //$urandom (seed); 89 | 90 | begin 91 | writer1.rate = 1.0; 92 | writer2.rate = 1.0; 93 | index = 0; 94 | 95 | @(posedge wr_clk_i); 96 | while(index < transactions_i) begin 97 | 98 | cmd = randvec(); 99 | mem[index % DEPTH] = cmd; 100 | tmp = (data >> CNTSHIFT) & CNTMASK; 101 | case (tmp) 102 | 0: cnt = 0; 103 | 1: cnt = 1; 104 | 2: cnt = 2; 105 | 3: cnt = 4; 106 | 4: cnt = 8; 107 | default : cnt = 0; 108 | endcase // case (cnt) 109 | 110 | // Select fifo for command 111 | if (cmd & SELMASK) 112 | writer1.write_word (cmd); 113 | else 114 | writer2.write_word (cmd); 115 | index++; 116 | 117 | // Loop over count index 118 | for (int i = 0; i < cnt; i++) 119 | begin 120 | 121 | // Generate another random word 122 | data = randvec(); 123 | mem[index % DEPTH] = data; 124 | if (cmd & SELMASK) 125 | writer1.write_word (data); 126 | else 127 | writer2.write_word (data); 128 | index = index + 1; 129 | end 130 | end 131 | end 132 | endtask 133 | 134 | task fifo_verify; 135 | input integer transactions_i; 136 | input real read_rate; 137 | output integer errors; 138 | 139 | 140 | integer index; 141 | integer cidx; 142 | 143 | reg [DW-1:0] received; 144 | reg [DW-1:0] expected; 145 | reg [DW-1:0] cmd; 146 | reg [3:0] cnt; 147 | 148 | begin 149 | errors = 0; 150 | 151 | index = 0; 152 | @(posedge rd_clk_i); 153 | while (index < transactions_i) 154 | begin 155 | 156 | reader.read_word(received); 157 | index++; 158 | end // while (index < transactions_i) 159 | end 160 | 161 | endtask 162 | 163 | endmodule 164 | -------------------------------------------------------------------------------- /fifo_arb_tx/fifo_arb_tx.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::fifo_arb_tx:0.1 3 | description: Arbiter for two clients transmitting thru one fifo 4 | 5 | filesets: 6 | rtl: 7 | depend: 8 | - fifo 9 | - host_fifo_pkg 10 | files: 11 | - rtl/fifo_arb_tx.sv 12 | file_type : verilogSource 13 | 14 | tb: 15 | files: 16 | - bench/fifo_arb_tx_tb.v 17 | - bench/fifo_tester.v 18 | - bench/fifo_reader1.v 19 | file_type : verilogSource 20 | depend: [">=vlog_tb_utils-1.0"] 21 | 22 | targets: 23 | default: 24 | filesets : [rtl] 25 | 26 | sim: 27 | default_tool : icarus 28 | tools: 29 | icarus: 30 | iverilog_options: [-g2012] 31 | filesets : [rtl, tb] 32 | parameters : [read_rate, write_rate, data_width, depth_width] 33 | toplevel : [fifo_arb_tx_tb] 34 | 35 | parameters: 36 | read_rate: 37 | datatype : str 38 | description : FIFO read rate 39 | paramtype : plusarg 40 | 41 | write_rate: 42 | datatype : str 43 | description : FIFO write rate 44 | paramtype : plusarg 45 | 46 | data_width: 47 | datatype : int 48 | description : FIFO data width 49 | paramtype : vlogparam 50 | 51 | depth_width: 52 | datatype : int 53 | description : 2**(FIFO depth) 54 | paramtype : vlogparam 55 | -------------------------------------------------------------------------------- /fifo_arb_tx/rtl/fifo_arb_tx.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * FIFO tx arbiter - Muxes input compliant fifos into a single stream by decoding transaction 3 | * 4 | * parameters: 5 | * SELMASK - This is a bitmask that when matched will route data to fifo c1 6 | * If not matched data will route to fifo c2. 7 | * CNTMASK - Mask pointing to contiguous CNT bits. Only 3 bits for count currently supported. 8 | * DWIDTH - Data width 9 | * AWIDTH - Address width of instantiated FIFOs. 10 | * 11 | * All rights reserved. 12 | * Tiny Labs Inc 13 | * 2020 14 | */ 15 | 16 | module fifo_arb_tx #( 17 | parameter SELMASK = 8'h80, 18 | parameter CNTMASK = 8'h70, 19 | parameter DWIDTH = 8, 20 | parameter AWIDTH = 3 21 | ) 22 | ( 23 | // Global 24 | input CLK, 25 | input RESETn, 26 | // Input client 1 27 | input c1_wren, 28 | input [DWIDTH-1:0] c1_wrdata, 29 | output c1_wrfull, 30 | // Input client 2 31 | input c2_wren, 32 | input [DWIDTH-1:0] c2_wrdata, 33 | output c2_wrfull, 34 | // Output FIFO 35 | input fifo_wrfull, 36 | output fifo_wren, 37 | output [DWIDTH-1:0] fifo_wrdata 38 | ); 39 | 40 | // Import common definitions 41 | import host_fifo_pkg::*; 42 | 43 | // Calculate count shift 44 | localparam CSHIFT = $clog2 (CNTMASK) - FIFO_CNT_WIDTH; 45 | localparam CMASK = (2**FIFO_CNT_WIDTH) - 1; 46 | 47 | // Internal write logic to each fifo 48 | wire c1_rden, c2_rden; 49 | wire c1_rdempty, c2_rdempty; 50 | wire [DWIDTH-1:0] c1_rddata, c2_rddata; 51 | 52 | // Instantiate an internal fifo for each client 53 | fifo #( 54 | .DEPTH_WIDTH (AWIDTH), 55 | .DATA_WIDTH (DWIDTH) 56 | ) u_fifo1 57 | ( 58 | .clk (CLK), 59 | .rst (~RESETn), 60 | .wr_en_i (c1_wren), // Client connection 61 | .wr_data_i (c1_wrdata), 62 | .full_o (c1_wrfull), 63 | .rd_data_o (c1_rddata), // Arbiter connection 64 | .rd_en_i (c1_rden), 65 | .empty_o (c1_rdempty) 66 | ); 67 | 68 | // Instantiate an internal fifo for each client 69 | fifo #( 70 | .DEPTH_WIDTH (AWIDTH), 71 | .DATA_WIDTH (DWIDTH) 72 | ) u_fifo2 73 | ( 74 | .clk (CLK), 75 | .rst (~RESETn), 76 | .wr_en_i (c2_wren), // Client connection 77 | .wr_data_i (c2_wrdata), 78 | .full_o (c2_wrfull), 79 | .rd_data_o (c2_rddata), // Arbiter connection 80 | .rd_en_i (c2_rden), 81 | .empty_o (c2_rdempty) 82 | ); 83 | 84 | logic data_valid; 85 | logic c1_prden, c2_prden; 86 | logic c1_psel, c2_psel; 87 | logic [FIFO_PAYLOAD_WIDTH-1:0] dcnt; 88 | wire [DWIDTH-1:0] data; 89 | logic [DWIDTH-1:0] store; // Buffer value if wrfull goes high mid transfer 90 | wire hold; 91 | wire c1_sel, c2_sel; 92 | logic backpressure; 93 | 94 | // Debug only 95 | //wire [DWIDTH-1:0] cmd; 96 | //assign cmd = data_valid && (dcnt == 0) ? data : cmd; 97 | 98 | // Assign hold signals 99 | assign hold = (dcnt == 0) & (((data >> CSHIFT) & CMASK) != 0) ? 1 : 0; 100 | 101 | // FIFO selection 102 | assign c1_sel = (~c2_psel & (~c1_rdempty | (c1_psel & hold) | (c1_psel & (dcnt > 0)))); 103 | assign c2_sel = (~c1_psel & (~c2_rdempty | (c2_psel & hold) | (c2_psel & (dcnt > 0)))); 104 | assign c1_rden = c1_sel & ~c1_rdempty & ~fifo_wrfull & ~backpressure; 105 | assign c2_rden = c2_sel & ~c2_rdempty & ~fifo_wrfull & ~backpressure; 106 | 107 | // Data connected to current selected FIFO 108 | assign data = c1_prden ? c1_rddata : 109 | (c2_prden ? c2_rddata : 0); 110 | 111 | // Write to output fifo 112 | assign fifo_wren = ~fifo_wrfull & (data_valid | backpressure); 113 | assign fifo_wrdata = backpressure ? store : data; 114 | 115 | always @(posedge CLK) 116 | begin 117 | if (~RESETn) 118 | begin 119 | c1_prden <= 0; 120 | c2_prden <= 0; 121 | c1_psel <= 0; 122 | c2_psel <= 0; 123 | data_valid <= 0; 124 | dcnt <= 0; 125 | backpressure <= 0; 126 | end 127 | else 128 | begin 129 | 130 | // Assign cnt 131 | if (data_valid && (dcnt == 0)) 132 | dcnt <= fifo_payload (FIFO_CNT_WIDTH'((32'(data) >> CSHIFT) & CMASK)); 133 | 134 | // Data is valid if either enable was asserted last cycle 135 | if (c1_rden | c2_rden) 136 | data_valid <= 1; 137 | else 138 | data_valid <= 0; 139 | 140 | // Decrement data count 141 | if (data_valid & (dcnt != 0)) 142 | dcnt <= dcnt - 1; 143 | 144 | // Save value if sink buffer full 145 | if (fifo_wrfull & data_valid & ~backpressure) 146 | begin 147 | store <= data; 148 | backpressure <= 1; 149 | end 150 | else if (~fifo_wrfull) 151 | backpressure <= 0; 152 | 153 | // Save previous rden 154 | c1_prden <= c1_rden; 155 | c2_prden <= c2_rden; 156 | c1_psel <= c1_sel; 157 | c2_psel <= c2_sel; 158 | end 159 | end 160 | endmodule // fifo_arb_rx 161 | -------------------------------------------------------------------------------- /host_fifo_pkg/host_fifo_pkg.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::host_fifo_pkg:0.1 3 | 4 | filesets: 5 | rtl: 6 | files: 7 | - rtl/host_fifo_pkg.sv 8 | file_type : verilogSource 9 | 10 | targets: 11 | default: 12 | filesets : [rtl] 13 | 14 | -------------------------------------------------------------------------------- /host_fifo_pkg/rtl/host_fifo_pkg.sv: -------------------------------------------------------------------------------- 1 | /** 2 | * Common definitions for connecting IP to host FIFOs. 3 | * 4 | * All rights reserved. 5 | * Tiny Labs Inc 6 | * 2020 7 | */ 8 | 9 | package host_fifo_pkg; 10 | 11 | parameter FIFO_CNT_WIDTH = 3; 12 | parameter FIFO_PAYLOAD_WIDTH = 5; 13 | 14 | parameter [FIFO_CNT_WIDTH-1:0] 15 | FIFO_D0 = 3'b000, 16 | FIFO_D1 = 3'b001, 17 | FIFO_D2 = 3'b010, 18 | FIFO_D4 = 3'b011, 19 | FIFO_D5 = 3'b100, 20 | FIFO_D6 = 3'b101, 21 | FIFO_D8 = 3'b110, 22 | FIFO_D16 = 3'b111; 23 | 24 | // Calculate bytes from cnt val 25 | function [FIFO_PAYLOAD_WIDTH-1:0] fifo_payload; 26 | input [FIFO_CNT_WIDTH-1:0] val; 27 | 28 | case (val) 29 | FIFO_D0: fifo_payload = 0; 30 | FIFO_D1: fifo_payload = 1; 31 | FIFO_D2: fifo_payload = 2; 32 | FIFO_D4: fifo_payload = 4; 33 | FIFO_D5: fifo_payload = 5; 34 | FIFO_D6: fifo_payload = 6; 35 | FIFO_D8: fifo_payload = 8; 36 | FIFO_D16: fifo_payload = 16; 37 | endcase 38 | endfunction 39 | endpackage 40 | -------------------------------------------------------------------------------- /roalogic_memory/files/0001-Remove-verilator-param-lint-error.patch: -------------------------------------------------------------------------------- 1 | From b65abc1808a21e6f1decff73563b67941bdd3a0c Mon Sep 17 00:00:00 2001 2 | From: Tiny Labs Inc 3 | Date: Sun, 3 Apr 2022 17:42:05 -0600 4 | Subject: [PATCH] Remove verilator param lint error 5 | 6 | --- 7 | rtl/verilog/rl_ram_1r1w.sv | 2 ++ 8 | 1 file changed, 2 insertions(+) 9 | 10 | diff --git a/rtl/verilog/rl_ram_1r1w.sv b/rtl/verilog/rl_ram_1r1w.sv 11 | index 88a2ce6..fa42bbb 100644 12 | --- a/rtl/verilog/rl_ram_1r1w.sv 13 | +++ b/rtl/verilog/rl_ram_1r1w.sv 14 | @@ -102,6 +102,7 @@ module rl_ram_1r1w #( 15 | // 16 | // Module Body 17 | // 18 | +/* verilator lint_off WIDTH */ 19 | generate 20 | if (TECHNOLOGY == "N3XS" || 21 | TECHNOLOGY == "n3xs") 22 | @@ -220,6 +221,7 @@ begin 23 | assign dout_o = contention_reg ? din_dly : mem_dout; 24 | end 25 | endgenerate 26 | +/* verilator lint_on WIDTH */ 27 | 28 | endmodule 29 | 30 | -- 31 | 2.32.0 32 | 33 | -------------------------------------------------------------------------------- /roalogic_memory/files/0002-Make-RAM-array-verilator-public.patch: -------------------------------------------------------------------------------- 1 | From 3bc6d8fd53fb3624e761fd59b0260fc7eabb0abb Mon Sep 17 00:00:00 2001 2 | From: Tiny Labs Inc 3 | Date: Wed, 13 Apr 2022 13:45:58 -0600 4 | Subject: [PATCH] Make RAM array verilator public 5 | 6 | --- 7 | rtl/verilog/rl_ram_1r1w_generic.sv | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/rtl/verilog/rl_ram_1r1w_generic.sv b/rtl/verilog/rl_ram_1r1w_generic.sv 11 | index 6a83fab..0271a94 100644 12 | --- a/rtl/verilog/rl_ram_1r1w_generic.sv 13 | +++ b/rtl/verilog/rl_ram_1r1w_generic.sv 14 | @@ -90,7 +90,7 @@ module rl_ram_1r1w_generic #( 15 | // 16 | genvar i; 17 | 18 | - logic [DBITS-1:0] mem_array [2**ABITS -1:0]; //memory array 19 | + logic [DBITS-1:0] mem_array [2**ABITS -1:0] /* verilator public */; //memory array 20 | 21 | 22 | ////////////////////////////////////////////////////////////////// 23 | -- 24 | 2.32.0 25 | 26 | -------------------------------------------------------------------------------- /roalogic_memory/roalogic_memory.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::roalogic_memory:1.0 3 | description: Generate tech-specific memory 4 | 5 | filesets: 6 | rtl: 7 | files: 8 | - rtl/verilog/rl_queue.sv 9 | - rtl/verilog/rl_ram_1r1w.sv 10 | - rtl/verilog/rl_ram_1r1w_easic_n3x.sv 11 | - rtl/verilog/rl_ram_1r1w_easic_n3xs.sv 12 | - rtl/verilog/rl_ram_1r1w_generic.sv 13 | - rtl/verilog/rl_ram_1rw.sv 14 | - rtl/verilog/rl_ram_1rw_easic_n3x.sv 15 | - rtl/verilog/rl_ram_1rw_generic.sv 16 | file_type : verilogSource 17 | 18 | license: 19 | files: 20 | - LICENSE.txt 21 | file_type : user 22 | 23 | targets: 24 | default: 25 | filesets : [rtl, license] 26 | 27 | provider: 28 | name : github 29 | user : RoaLogic 30 | repo : memory 31 | patches : [files/0001-Remove-verilator-param-lint-error.patch, 32 | files/0002-Make-RAM-array-verilator-public.patch] 33 | -------------------------------------------------------------------------------- /uart_fifo/rtl/uart_fifo.sv: -------------------------------------------------------------------------------- 1 | /* Instantiate simple 8N1 UART receiver/transmitter. Connect to external dual-clock FIFO. 2 | * 3 | * All rights reserved. 4 | * Tiny Labs Inc 5 | * 2020 6 | */ 7 | module uart_fifo 8 | ( 9 | /* Clock */ 10 | input CLK, 11 | input RESETn, 12 | /* Physical pins */ 13 | output TX_PIN, 14 | input RX_PIN, 15 | /* FIFO interface */ 16 | output logic FIFO_WREN, 17 | input FIFO_FULL, 18 | output [7:0] FIFO_DOUT, 19 | output logic FIFO_RDEN, 20 | input FIFO_EMPTY, 21 | input [7:0] FIFO_DIN, 22 | /* Dropped bytes due to FIFO congestion */ 23 | output logic [9:0] DROPPED 24 | ); 25 | 26 | localparam TIMER_BITS = 4; 27 | 28 | // Local logic 29 | logic tx_busy, dvalid, wren; 30 | 31 | // Read when not empty or busy 32 | assign FIFO_RDEN = !FIFO_EMPTY & !dvalid; 33 | 34 | // Write when valid and not full 35 | assign FIFO_WREN = wren & !FIFO_FULL; 36 | 37 | // Data valid on next cycle 38 | always @(posedge CLK) 39 | if (!RESETn) 40 | begin 41 | dvalid <= 0; 42 | DROPPED <= 0; 43 | end 44 | else 45 | begin 46 | if (FIFO_RDEN) 47 | dvalid <= 1; 48 | else if (!tx_busy) 49 | dvalid <= 0; 50 | 51 | if (wren & FIFO_FULL) 52 | DROPPED <= DROPPED + 1; 53 | 54 | end 55 | 56 | // Instantiate receiver 57 | rxuartlite #( 58 | .TIMER_BITS (TIMER_BITS), 59 | .CLOCKS_PER_BAUD (4) // 12Mbaud @ 48MHz 60 | ) 61 | u_uart_rx ( 62 | .i_clk (CLK), 63 | .i_uart_rx (RX_PIN), 64 | .o_wr (wren), 65 | .o_data (FIFO_DOUT) 66 | ); 67 | 68 | // Instantiate transmitter 69 | txuartlite #( 70 | .TIMING_BITS (TIMER_BITS), 71 | .CLOCKS_PER_BAUD (4) // 12Mbaud @ 48MHz 72 | ) 73 | u_uart_tx ( 74 | .i_clk (CLK), 75 | .i_wr (dvalid), 76 | .i_data (FIFO_DIN), 77 | .o_uart_tx (TX_PIN), 78 | .o_busy (tx_busy)); 79 | 80 | endmodule 81 | -------------------------------------------------------------------------------- /uart_fifo/uart_fifo.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::uart_fifo:0.1 3 | 4 | filesets: 5 | rtl: 6 | files: 7 | - rtl/rxuartlite.v 8 | - rtl/txuartlite.v 9 | - rtl/uart_fifo.sv 10 | file_type: verilogSource 11 | 12 | targets: 13 | default: 14 | description: Simple 8N1 UART with external FIFO interface 15 | filesets : [rtl] 16 | -------------------------------------------------------------------------------- /verilator_utils/GPIOClient.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Virtual GPIO client - Connect to another simulator instance running GPIO server. 3 | * shuttle GPIO signals between client and server 4 | * 5 | * All rights reserved. 6 | * Tiny Labs Inc 7 | * 2020 8 | */ 9 | 10 | #include "GPIOClient.h" 11 | #include "err.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | void GPIOClient::Start (uint16_t port) 20 | { 21 | struct sockaddr_in a4; 22 | 23 | // Create socket 24 | gpiosock = socket (AF_INET, SOCK_STREAM, 0); 25 | if (gpiosock < 0) 26 | fail ("Unable to create gpiosock!"); 27 | 28 | int status = fcntl(gpiosock, F_SETFL, fcntl(gpiosock, F_GETFL, 0) | O_NONBLOCK); 29 | if (status == -1) 30 | printf ("Error calling fcntl\n"); 31 | 32 | // Setup address 33 | inet_pton (AF_INET, "127.0.0.1", &a4.sin_addr); 34 | a4.sin_family = AF_INET; 35 | a4.sin_port = htons (port); 36 | 37 | // Connect to server 38 | if (connect (gpiosock, (const sockaddr *)&a4, sizeof (a4)) != 0) 39 | fail ("Failed to connect to localhost:%d", port); 40 | printf ("Connected to remote GPIO :%d\n", port); 41 | } 42 | 43 | void GPIOClient::Stop (void) 44 | { 45 | close (gpiosock); 46 | } 47 | 48 | void GPIOClient::SendOutputs (uint64_t output, size_t output_cnt) 49 | { 50 | int i, idx = 0; 51 | uint8_t data[65]; 52 | 53 | // Check for output changes 54 | if (output != this->output) { 55 | 56 | // Find change 57 | for (i = 0; i < output_cnt; i++) { 58 | if ((output & (1 << i)) != (this->output & (1 << i))) { 59 | 60 | // Generate data output 61 | if (output & (1 << i)) 62 | data[idx++] = (i & 0x7F) | 0x80; 63 | else 64 | data[idx++] = (i & 0x7F); 65 | } 66 | } 67 | 68 | // Add flush 69 | data[idx++] = 0xFF; 70 | 71 | // Send update 72 | if (write (gpiosock, data, idx) != idx) 73 | printf ("Failed to send GPIO %u\n", i); 74 | 75 | // Update cache 76 | this->output = output; 77 | } 78 | } 79 | 80 | 81 | void GPIOClient::doGPIOClient (uint64_t t, 82 | uint64_t *input, size_t input_cnt, 83 | uint64_t output, size_t output_cnt) 84 | 85 | { 86 | uint8_t cmd, off; 87 | static bool init = false; 88 | 89 | // Initialize first run 90 | if (!init) { 91 | int i; 92 | 93 | // Flip all bits to force send 94 | this->output = ~output; 95 | 96 | // Send outputs 97 | SendOutputs (output, output_cnt); 98 | init = true; 99 | } 100 | else { 101 | // Check output differences 102 | SendOutputs (output, output_cnt); 103 | } 104 | 105 | // Non-blocking read 106 | while (read (gpiosock, &cmd, 1) == 1) { 107 | 108 | // Break on flush 109 | if (cmd == 0xFF) 110 | break; 111 | 112 | // Get signal offset 113 | off = cmd & 0x7F; 114 | if (off < input_cnt) { 115 | if (cmd & 0x80) 116 | *input |= (1 << off); 117 | else 118 | *input &= ~(1 << off); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /verilator_utils/GPIOClient.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Virtual GPIO client - Connect to TCP server of GPIO server 3 | * forward local GPIO signals over TCP to remote server. 4 | * 5 | * All rights reserved. 6 | * Tiny Labs Inc 7 | * 2020 8 | */ 9 | #include 10 | #include 11 | 12 | class GPIOClient { 13 | private: 14 | int gpiosock = -1; 15 | uint64_t output; 16 | void SendOutputs (uint64_t output, size_t output_cnt); 17 | 18 | public: 19 | uint32_t period; 20 | GPIOClient (int period) { this->period = period; } 21 | virtual ~GPIOClient () { if (gpiosock != -1) Stop (); } 22 | 23 | // Access functions 24 | void Start (uint16_t port); 25 | void Stop (void); 26 | void doGPIOClient (uint64_t t, 27 | uint64_t *input, size_t input_cnt, 28 | uint64_t output, size_t output_cnt); 29 | }; 30 | -------------------------------------------------------------------------------- /verilator_utils/GPIOServer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Receive GPIO signals over socket. Set received signal for inputs. 3 | * Return outputs if changed. 4 | * 5 | * All rights reserved. 6 | * Tiny Labs Inc 7 | * 2020 8 | */ 9 | 10 | #include "GPIOServer.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | void GPIOServer::SendOutputs (uint64_t output, size_t output_cnt) 17 | { 18 | int i; 19 | 20 | // Check for output changes 21 | if (output != this->output) { 22 | 23 | // Find change 24 | for (i = 0; i < output_cnt; i++) { 25 | 26 | if ((output & (1 << i)) != (this->output & (1 << i))) { 27 | 28 | // Send output 29 | if (output & (1 << i)) { 30 | if (!rx.enqueue ((i & 0x7F) | 0x80)) 31 | printf ("Failed to send GPIO %u\n", i); 32 | } 33 | else { 34 | if (!rx.enqueue (i & 0x7F)) 35 | printf ("Failed to send GPIO %u\n", i); 36 | } 37 | } 38 | } 39 | 40 | // Update cache 41 | this->output = output; 42 | } 43 | } 44 | 45 | int GPIOServer::doGPIOServer (uint64_t t, 46 | uint64_t *input, size_t input_cnt, 47 | uint64_t output, size_t output_cnt) 48 | { 49 | uint8_t cmd, off; 50 | static bool init = false; 51 | 52 | // Return if server not started or odd ticks 53 | if (!running) 54 | return true; 55 | 56 | // Initialize first run 57 | if (!init) { 58 | int i; 59 | 60 | // Flip all bits so everything gets sent 61 | this->output = ~output; 62 | 63 | // Send outputs 64 | SendOutputs (output, output_cnt); 65 | init = true; 66 | } 67 | else 68 | // Check output differences 69 | SendOutputs (output, output_cnt); 70 | 71 | // Check if there are new commands 72 | while (tx.size_approx() && tx.try_dequeue(cmd)) { 73 | 74 | // Stop at flush command 75 | if (cmd == 0xFF) 76 | break; 77 | 78 | // Get signal offset 79 | off = cmd & 0x7F; 80 | if (off < input_cnt) { 81 | if (cmd & 0x80) 82 | *input |= (1 << off); 83 | else 84 | *input &= ~(1 << off); 85 | } 86 | } 87 | 88 | return true; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /verilator_utils/GPIOServer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * TCP server to take GPIO signals from host bridge and send them to host application 3 | * 4 | * All rights reserved. 5 | * Tiny Labs Inc 6 | * 2019 7 | */ 8 | #ifndef GPIOSERVER_H 9 | #define GPIOSERVER_H 10 | 11 | #include "Server.h" 12 | 13 | class GPIOServer : public Server { 14 | 15 | private: 16 | uint64_t output; 17 | void SendOutputs (uint64_t output, size_t output_cnt); 18 | 19 | public: 20 | GPIOServer (uint32_t period, bool debug=0) : Server ("GPIOServer", period, debug) {} 21 | ~GPIOServer () {} 22 | int doGPIOServer (uint64_t t, 23 | uint64_t *input, size_t input_cnt, 24 | uint64_t output, size_t output_cnt); 25 | }; 26 | 27 | #endif /* GPIOSERVER_H */ 28 | -------------------------------------------------------------------------------- /verilator_utils/JTAGClient.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Virtual JTAG client - Connect to another simulator instance running JTAG server. 3 | * Remote local JTAG master signals to remote JTAG client signals over openocd 4 | * bitbang protocol. 5 | * 6 | * All rights reserved. 7 | * Tiny Labs Inc 8 | * 2020 9 | */ 10 | 11 | #include "JTAGClient.h" 12 | #include "err.h" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | void JTAGClient::Start (uint16_t port) 19 | { 20 | struct sockaddr_in a4; 21 | 22 | // Create socket 23 | jtagsock = socket (AF_INET, SOCK_STREAM, 0); 24 | if (jtagsock < 0) 25 | fail ("Unable to create jtagsock!"); 26 | 27 | // Setup address 28 | inet_pton (AF_INET, "127.0.0.1", &a4.sin_addr); 29 | a4.sin_family = AF_INET; 30 | a4.sin_port = htons (port); 31 | 32 | // Connect to server 33 | if (connect (jtagsock, (const sockaddr *)&a4, sizeof (a4)) != 0) 34 | fail ("Failed to connect to localhost:%d", port); 35 | printf ("Connected to remote JTAG :%d\n", port); 36 | } 37 | 38 | void JTAGClient::Stop (void) 39 | { 40 | close (jtagsock); 41 | } 42 | 43 | void JTAGClient::doJTAGClient (uint64_t t, uint8_t tck, uint8_t *tdo, uint8_t tdi, uint8_t *tms, uint8_t tmsoe) 44 | { 45 | uint8_t b; 46 | int rv; 47 | 48 | // Write JTAGIO state 49 | b = '0' | (tck << 2) | (*tms << 1) | tdi; 50 | rv = write (jtagsock, &b, 1); 51 | if (rv != 1) 52 | fail ("JTAGClient IO error"); 53 | 54 | // Query TDO/TMS state 55 | b = 'S'; 56 | rv = write (jtagsock, &b, 1); 57 | if (rv != 1) 58 | fail ("JTAGClient IO error"); 59 | 60 | // Read state 61 | rv = read (jtagsock, &b, 1); 62 | if (rv != 1) 63 | fail ("JTAGClient IO error"); 64 | 65 | // Get TDO 66 | if ((b - '0') & 1) 67 | *tdo = 1; 68 | else 69 | *tdo = 0; 70 | 71 | // Read from remote 72 | if (!tmsoe) { 73 | 74 | // Set tms/SWDIN 75 | if ((b - '0') & 2) 76 | *tms = 1; 77 | else 78 | *tms = 0; 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /verilator_utils/JTAGClient.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Virtual JTAG client - Connect to TCP server of JTAG server 3 | * forward local JTAG signals over TCP to remote server via 4 | * openocd bitbang protocol 5 | * 6 | * All rights reserved. 7 | * Tiny Labs Inc 8 | * 2020 9 | */ 10 | #include 11 | 12 | class JTAGClient { 13 | private: 14 | int jtagsock = -1; 15 | 16 | public: 17 | uint32_t period; 18 | JTAGClient (int period) {this->period = period; } 19 | virtual ~JTAGClient () { if (jtagsock != -1) Stop (); } 20 | 21 | // Access functions 22 | void Start (uint16_t port); 23 | void Stop (void); 24 | void doJTAGClient (uint64_t t, uint8_t tck, uint8_t *tdo, uint8_t tdi, uint8_t *tms, uint8_t tmsoe); 25 | }; 26 | -------------------------------------------------------------------------------- /verilator_utils/JTAGServer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a simple TCP server that takes small bitbang packets 3 | * and toggles the simulation input accordingly. The client is an 4 | * openocd interface which allows full debugging of the 5 | * target with minimal effort on our part. 6 | * 7 | * All rights reserved. 8 | * Tiny Labs Inc 9 | * 2019 10 | */ 11 | 12 | #include "JTAGServer.h" 13 | 14 | int JTAGServer::doJTAGServer (uint64_t t, uint8_t *tck, uint8_t tdo, 15 | uint8_t *tdi, uint8_t *tms, uint8_t *srst) 16 | { 17 | uint8_t cmd; 18 | 19 | // Pull a command off the receive queue 20 | if (tx.size_approx() && tx.try_dequeue (cmd)) { 21 | switch (cmd) { 22 | case '0' ... '7': 23 | *tdi = ((cmd - '0') & 1) ? 1 : 0; 24 | *tms = ((cmd - '0') & 2) ? 1 : 0; 25 | *tck = ((cmd - '0') & 4) ? 1 : 0; 26 | break; 27 | case 'r' ... 'u': 28 | /* Handle system reset - active low*/ 29 | *srst = ((cmd - 'r') & 1) ? 0 : 1; 30 | break; 31 | case 'R': 32 | rx.enqueue (tdo ? '1' : '0'); 33 | break; 34 | case 'S': /* Optional extension for SWD support (not supported in openocd) */ 35 | { 36 | uint8_t c = '0'; 37 | if (tdo) 38 | c += 1; 39 | if (*tms) 40 | c += 2; 41 | rx.enqueue (c); 42 | break; 43 | } 44 | } 45 | } 46 | 47 | return true; 48 | } 49 | -------------------------------------------------------------------------------- /verilator_utils/JTAGServer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a simple TCP server that takes small bitbang packets 3 | * and toggles the simulation input accordingly. The client is a 4 | * custom openocd interface which allows full debugging of the 5 | * target with minimal effort on our part. 6 | * 7 | * All rights reserved. 8 | * Tiny Labs Inc 9 | * 2019 10 | */ 11 | #ifndef JTAGSERVER_H 12 | #define JTAGSERVER_H 13 | 14 | #include "Server.h" 15 | 16 | class JTAGServer : public Server { 17 | 18 | public: 19 | JTAGServer (uint32_t period, bool debug=0) : Server ("JTAGServer", period, debug) {} 20 | ~JTAGServer () {} 21 | int doJTAGServer (uint64_t t, uint8_t *tck, uint8_t tdo, uint8_t *tdi, uint8_t *tms, uint8_t *srst); 22 | }; 23 | 24 | #endif /* JTAGSERVER_H */ 25 | -------------------------------------------------------------------------------- /verilator_utils/Server.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a simple TCP server that takes small bitbang packets 3 | * and toggles the simulation input accordingly. The client is an 4 | * openocd interface which allows full debugging of the 5 | * target with minimal effort on our part. 6 | * 7 | * All rights reserved. 8 | * Tiny Labs Inc 9 | * 2019 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "Server.h" 22 | #include "err.h" 23 | 24 | Server::Server (const char *name, uint32_t period, bool debug) 25 | { 26 | this->name = name; 27 | this->period = period; 28 | this->debug = debug; 29 | } 30 | 31 | Server::~Server () 32 | { 33 | // Wait for server to finish 34 | if (running) { 35 | running = 0; 36 | shutdown (sockfd, SHUT_RDWR); 37 | pthread_join (thread_id, NULL); 38 | } 39 | } 40 | 41 | void Server::Start (uint16_t port) 42 | { 43 | int rv; 44 | 45 | /* Save port */ 46 | this->port = port; 47 | 48 | /* Spawn new thread - Hacky but works... */ 49 | #pragma GCC diagnostic ignored "-Wpmf-conversions" 50 | rv = pthread_create (&thread_id, NULL, (void *(*)(void *))&Server::Listen, this); 51 | if (rv) 52 | fail ("Failed to spawn thread!"); 53 | } 54 | 55 | void Server::Send (int sockfd, char *buf, int len) 56 | { 57 | int rv; 58 | 59 | /* Debug */ 60 | if (debug) { 61 | buf[len] = '\0'; 62 | printf ("resp=[%s]\n", buf); 63 | } 64 | 65 | /* Write a response to the client */ 66 | rv = write (sockfd, buf, len); 67 | if (rv < 0) { 68 | fail ("ERROR writing to socket"); 69 | } 70 | } 71 | 72 | void Server::Listen (void) 73 | { 74 | int nsockfd, n, i, enable = 1; 75 | socklen_t clilen; 76 | char cmd[256], resp[256]; 77 | struct sockaddr_in serv_addr, cli_addr; 78 | 79 | /* Set running */ 80 | running = 1; 81 | 82 | /* First call to socket() function */ 83 | sockfd = socket(AF_INET, SOCK_STREAM, 0); 84 | if (sockfd < 0) { 85 | fail("ERROR opening socket"); 86 | } 87 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) 88 | fail("setsockopt(SO_REUSEADDR) failed"); 89 | 90 | /* Initialize socket structure */ 91 | bzero((char *) &serv_addr, sizeof(serv_addr)); 92 | serv_addr.sin_family = AF_INET; 93 | serv_addr.sin_addr.s_addr = INADDR_ANY; 94 | serv_addr.sin_port = htons(this->port); 95 | 96 | /* Print message */ 97 | printf ("%s listening on port: %u...\n", this->name, this->port); 98 | 99 | /* Now bind the host address using bind() call.*/ 100 | if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { 101 | fail("ERROR on binding"); 102 | } 103 | 104 | /* Now start listening for the clients, here process will 105 | * go in sleep mode and will wait for the incoming connection 106 | */ 107 | listen(sockfd,5); 108 | clilen = sizeof(cli_addr); 109 | 110 | /* Accept actual connection from the client */ 111 | restart_connection: 112 | nsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen); 113 | if (nsockfd < 0) { 114 | fail("ERROR on accept"); 115 | goto done; 116 | } 117 | 118 | // Make socket non-blocking 119 | fcntl(nsockfd, F_SETFL, O_NONBLOCK); 120 | 121 | // Print client is connected 122 | printf ("%s connected.\n", this->name); 123 | 124 | // Continue to listen until connection is broken 125 | while (running) { 126 | 127 | /* If connection is established then start communicating */ 128 | bzero (cmd, sizeof (cmd)); 129 | n = read (nsockfd, cmd, sizeof (cmd) - 1); 130 | 131 | // Otherside closed connection 132 | if (n == 0) { 133 | close (nsockfd); 134 | printf ("Connection closed, restarting...\n"); 135 | goto restart_connection; 136 | } 137 | 138 | /* Process packet */ 139 | if (n > 0) { 140 | 141 | // NULL terminate 142 | if (debug) { 143 | cmd[n] = '\0'; 144 | printf ("Recvd=[%s] len=%d\n", cmd, n); 145 | } 146 | 147 | // Process each command 148 | for (i = 0; i < n; i++) 149 | if (!tx.enqueue (cmd[i])) 150 | printf ("Failed to queue\n"); 151 | } 152 | 153 | // Empty receive buffer 154 | if (rx.size_approx ()) { 155 | uint8_t val; 156 | 157 | // Create response packet 158 | for (i = 0; (i < sizeof (resp)) && rx.try_dequeue (val); i++) 159 | resp[i] = val; 160 | 161 | // Flush to socket 162 | Send (nsockfd, resp, i); 163 | } 164 | } 165 | 166 | done: 167 | printf ("%s terminating.\n", this->name); 168 | } 169 | -------------------------------------------------------------------------------- /verilator_utils/Server.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a simple TCP server that takes small bitbang packets 3 | * and toggles the simulation input accordingly. The client is a 4 | * custom openocd interface which allows full debugging of the 5 | * target with minimal effort on our part. 6 | * 7 | * All rights reserved. 8 | * Tiny Labs Inc 9 | * 2019 10 | */ 11 | #ifndef SERVER_H 12 | #define SERVER_H 13 | 14 | #include 15 | #include 16 | #include "readerwriterqueue.h" 17 | 18 | class Server { 19 | 20 | private: 21 | const char *name; 22 | int sockfd; 23 | uint16_t port; 24 | pthread_t thread_id; 25 | bool debug; 26 | void Listen (void); 27 | void Send (int sockfd, char *buf, int len); 28 | 29 | protected: 30 | bool running; 31 | mc::ReaderWriterQueue rx, tx; 32 | 33 | public: 34 | uint32_t period; 35 | Server (const char *name, uint32_t period, bool debug=0); 36 | virtual ~Server (); 37 | void Start (uint16_t port); 38 | }; 39 | 40 | #endif /* SERVER_H */ 41 | -------------------------------------------------------------------------------- /verilator_utils/UARTServer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Convert host bridge UART transport to TCP for debugging simulation 3 | * 4 | * NOTE: This will only work if (HOST_FREQ/BAUD == 32)! 5 | * 6 | * All rights reserved. 7 | * Tiny Labs Inc 8 | * 2020 9 | */ 10 | 11 | #include "UARTServer.h" 12 | #include 13 | #include 14 | #include 15 | 16 | typedef enum { 17 | STATE_IDLE = 0, 18 | STATE_DATA, 19 | STATE_STOP, 20 | STATE_DONE, 21 | STATE_MAX_ENUM 22 | } state_t; 23 | 24 | int UARTServer::doUARTServer (uint64_t t, uint8_t tx_pin, uint8_t *rx_pin) 25 | { 26 | static state_t tx_state = STATE_IDLE, rx_state = STATE_IDLE; 27 | static uint64_t tx_start = 0, rx_start = 0; 28 | static uint8_t rxc = 0, rcnt = 0; 29 | static uint8_t txc = 0, tcnt = 0; 30 | 31 | // Return if server not started or odd ticks 32 | if (!running || (t & 1)) 33 | return true; 34 | 35 | // TX state machine 36 | if (!tx_start || (((t - tx_start) % (period * 2)) == 0)) { 37 | switch (tx_state) { 38 | 39 | // Look for start bit 40 | case STATE_IDLE: 41 | if (!tx_pin) { 42 | tx_state = STATE_DATA; 43 | tx_start = t; 44 | } 45 | break; 46 | 47 | // Handle data bits 48 | case STATE_DATA: 49 | rxc >>= 1; 50 | if (tx_pin) 51 | rxc |= 0x80; 52 | rcnt++; 53 | if (rcnt == 8) 54 | tx_state = STATE_STOP; 55 | break; 56 | 57 | // Check stop bit 58 | case STATE_STOP: 59 | if (!tx_pin) 60 | printf ("Stop bit error! %" PRIu64 "\n", t); 61 | 62 | // Add to transmit queue 63 | if (!rx.enqueue (rxc)) 64 | printf ("Failed to queue byte\n"); 65 | 66 | // Reset variables 67 | tx_state = STATE_IDLE; 68 | rxc = rcnt = 0; 69 | tx_start = 0; 70 | break; 71 | } 72 | } 73 | 74 | // Receive state machine 75 | if (!rx_start || (((t - rx_start) % (period * 2)) == 0)) { 76 | switch (rx_state) { 77 | 78 | // Check for new data 79 | case STATE_IDLE: 80 | if (tx.size_approx() && tx.try_dequeue (txc)) { 81 | *rx_pin = 0; 82 | rx_state = STATE_DATA; 83 | rx_start = t; 84 | } 85 | break; 86 | 87 | // Transmit data 88 | case STATE_DATA: 89 | if (txc & 1) 90 | *rx_pin = 1; 91 | else 92 | *rx_pin = 0; 93 | txc >>= 1; 94 | tcnt++; 95 | if (tcnt == 8) 96 | rx_state = STATE_STOP; 97 | break; 98 | 99 | // Send stop bit 100 | case STATE_STOP: 101 | *rx_pin = 1; 102 | rx_state = STATE_DONE; 103 | break; 104 | } 105 | } 106 | 107 | // Back to IDLE state 108 | if ((rx_state == STATE_DONE) && (((t - rx_start) % (period * 2)) == ((period * 2) - 2))) { 109 | // Reset state machine 110 | rx_state = STATE_IDLE; 111 | txc = tcnt = 0; 112 | rx_start = 0; 113 | } 114 | 115 | return true; 116 | } 117 | 118 | -------------------------------------------------------------------------------- /verilator_utils/UARTServer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * TCP server to take UART signals from host bridge and send them to host application 3 | * 4 | * All rights reserved. 5 | * Tiny Labs Inc 6 | * 2019 7 | */ 8 | #ifndef UARTSERVER_H 9 | #define UARTSERVER_H 10 | 11 | #include "Server.h" 12 | 13 | class UARTServer : public Server { 14 | 15 | public: 16 | UARTServer (uint32_t period, bool debug=0) : Server ("UARTServer", period, debug) {} 17 | ~UARTServer () {} 18 | int doUARTServer (uint64_t t, uint8_t tx, uint8_t *rx); 19 | }; 20 | 21 | #endif /* UARTSERVER_H */ 22 | -------------------------------------------------------------------------------- /verilator_utils/err.h: -------------------------------------------------------------------------------- 1 | // Helper macro 2 | #ifndef ERR_H 3 | #define ERR_H 4 | 5 | #include 6 | #include 7 | #define fail(fmt, ...) do { \ 8 | printf (fmt "\n", ##__VA_ARGS__); \ 9 | exit (-1); \ 10 | } while (0) 11 | 12 | #endif /* ERR_H */ 13 | -------------------------------------------------------------------------------- /verilator_utils/verilator_utils.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::verilator_utils:0.1 3 | description: Verilator test bench utility class 4 | 5 | filesets: 6 | cpp: 7 | depend: 8 | - elf-loader 9 | files: 10 | - verilator_utils.cpp 11 | - verilator_utils.h : {is_include_file : true} 12 | - JTAGServer.cpp 13 | - JTAGServer.h : {is_include_file : true} 14 | - UARTServer.cpp 15 | - UARTServer.h : {is_include_file : true} 16 | - GPIOServer.cpp 17 | - GPIOServer.h : {is_include_file : true} 18 | - GPIOClient.cpp 19 | - GPIOClient.h : {is_include_file : true} 20 | - JTAGClient.cpp 21 | - JTAGClient.h : {is_include_file : true} 22 | - Server.cpp 23 | - Server.h : {is_include_file : true} 24 | - readerwriterqueue.h : {is_include_file : true} 25 | - atomicops.h : {is_include_file : true} 26 | - err.h : {is_include_file : true} 27 | file_type : cppSource 28 | 29 | targets: 30 | default: 31 | filesets : [cpp] 32 | tools: 33 | verilator: 34 | libs: [-lpthread] 35 | -------------------------------------------------------------------------------- /verilator_utils/verilator_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __VERILATOR_UTILS_H__ 2 | #define __VERILATOR_UTILS_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "JTAGServer.h" 8 | #include "UARTServer.h" 9 | #include "JTAGClient.h" 10 | #include "GPIOServer.h" 11 | #include "GPIOClient.h" 12 | 13 | extern struct argp verilator_utils_argp; 14 | 15 | class VerilatorUtils { 16 | public: 17 | VerilatorUtils(uint32_t *mem=NULL); 18 | ~VerilatorUtils(); 19 | 20 | VerilatedFstC* tfp; 21 | 22 | JTAGServer *jtag_server = NULL; 23 | UARTServer *uart_server = NULL; 24 | JTAGClient *jtag_client = NULL; 25 | GPIOClient *gpio_client = NULL; 26 | GPIOServer *gpio_server = NULL; 27 | 28 | bool doCycle(); 29 | bool doGPIOServer (uint64_t *input, size_t input_cnt, uint64_t output, size_t output_cnt); 30 | bool doGPIOClient (uint64_t *input, size_t input_cnt, uint64_t output, size_t output_cnt); 31 | bool doJTAGServer (uint8_t *tck, uint8_t tdo, uint8_t *tdi, uint8_t *tms, uint8_t *srst=NULL); 32 | bool doUARTServer (uint8_t tx, uint8_t *rx); 33 | bool doJTAGClient (uint8_t tck, uint8_t *tdo, uint8_t tdi, uint8_t *tms, uint8_t tmsoe = true); 34 | uint64_t getTime() { return t; } 35 | uint64_t getTimeout() { return timeout; } 36 | bool getFstDump() { return fstDump; } 37 | uint64_t getFstDumpStart() { return fstDumpStart; } 38 | uint64_t getFstDumpStop() { return fstDumpStop; } 39 | char *getFstFileName() { return fstFileName; } 40 | bool getJtagEnable() { return jtagServerEnable; } 41 | int getJtagPort() { return jtagServerPort; } 42 | 43 | static int parseOpts(int key, char *arg, struct argp_state *state); 44 | 45 | private: 46 | uint64_t t; 47 | uint64_t timeout; 48 | 49 | bool fstDump; 50 | uint64_t fstDumpStart; 51 | uint64_t fstDumpStop; 52 | char *fstFileName; 53 | bool fstDumping; 54 | 55 | bool jtagServerEnable; 56 | int jtagServerPort; 57 | bool uartServerEnable; 58 | int uartServerPort; 59 | bool jtagClientEnable; 60 | int jtagClientPort; 61 | bool gpioServerEnable; 62 | int gpioServerPort; 63 | bool gpioClientEnable; 64 | int gpioClientPort; 65 | 66 | uint32_t *mem; 67 | 68 | bool loadElf(char *fileName); 69 | bool loadBin(char *fileName); 70 | }; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /vivado_ipgen/sw/vivado_ipgen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | from collections import OrderedDict, defaultdict 4 | import yaml 5 | import math 6 | import re 7 | import os 8 | 9 | class IPGen: 10 | def __init__(self, config_file): 11 | d = OrderedDict() 12 | self.field = [] 13 | self.reg = [] 14 | import yaml 15 | 16 | def ordered_load(stream, Loader=yaml.Loader, object_pairs_hook=OrderedDict): 17 | class OrderedLoader(Loader): 18 | pass 19 | def construct_mapping(loader, node): 20 | loader.flatten_mapping(node) 21 | return object_pairs_hook(loader.construct_pairs(node)) 22 | OrderedLoader.add_constructor( 23 | yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, 24 | construct_mapping) 25 | return yaml.load(stream, OrderedLoader) 26 | data = ordered_load(open(config_file)) 27 | 28 | config = data['parameters'] 29 | files_root = data['files_root'] 30 | self.vlnv = data['vlnv'] 31 | 32 | # Generate name 33 | self.name = re.split(r'[-:]+', self.vlnv)[2] 34 | 35 | # Check for vivado install root 36 | if 'root' in config.keys (): 37 | self.root = config['root'] 38 | else: 39 | # Find by path 40 | #print (os.environ['PATH']) 41 | for path in os.environ['PATH'].split (':'): 42 | fpath = os.path.join (path, 'vivado') 43 | if os.path.isfile(fpath) and os.access(fpath, os.X_OK): 44 | self.root = os.path.dirname(os.path.dirname (fpath)) 45 | break 46 | 47 | if not self.root: 48 | raise ValueError ("vivado root not found!") 49 | else: 50 | print ("vivado IPGen: " + self.root) 51 | 52 | # Generate full file paths 53 | self.files = [] 54 | for root, dirs, files in os.walk (self.root): 55 | for f in config['files'].split(): 56 | if f in files: 57 | self.files.append (os.path.join (root, f)) 58 | else: 59 | ValueError (f + " not found!") 60 | 61 | def write(self): 62 | 63 | # Create core file 64 | core_file = self.name + '.core' 65 | vlnv = self.vlnv 66 | with open(core_file, 'w') as f: 67 | f.write('CAPI=2:\n') 68 | files = [] 69 | for fname in self.files: 70 | if fname[-2:] == '.v': 71 | files.append ({fname : {'file_type' : 'verilogSource'}}) 72 | elif fname[-3:] == '.vh': 73 | files.append ({fname : {'is_include_file' : True, 'file_type' : 'verilogSource'}}) 74 | elif fname[-4:] == '.vhd': 75 | files.append ({fname : {'file_type' : 'vhdlSource'}}) 76 | coredata = {'name' : vlnv, 77 | 'targets' : {'default' : {}}, 78 | } 79 | #print (files) 80 | coredata['filesets'] = {'rtl' : {'files' : files}} 81 | coredata['targets']['default']['filesets'] = ['rtl'] 82 | f.write(yaml.dump(coredata)) 83 | 84 | if __name__ == "__main__": 85 | if len(sys.argv) == 4: 86 | name = sys.argv[3] 87 | try: 88 | g = IPGen(sys.argv[1]) 89 | print("="*80) 90 | g.write() 91 | except Error as e: 92 | print("Error: %s" % e) 93 | exit(1) 94 | -------------------------------------------------------------------------------- /vivado_ipgen/vivado_ipgen.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::vivado_ipgen:0.1 3 | description: Takes vivado root (optional) and filenames to generate core file. 4 | 5 | generators: 6 | vivado_ipgen: 7 | interpreter: python 8 | command: sw/vivado_ipgen.py 9 | description: Generate core file for builtin Vivado IP 10 | 11 | -------------------------------------------------------------------------------- /vivado_probe/scripts/instantiate_ila.tcl: -------------------------------------------------------------------------------- 1 | # Create ILA 2 | insert_ila 32768 3 | 4 | -------------------------------------------------------------------------------- /vivado_probe/scripts/setup_ila.tcl: -------------------------------------------------------------------------------- 1 | # Setup ILA 2 | add_files -fileset utils_1 [glob instantiate_ila.tcl] 3 | set_property USED_IN_SYNTHESIS false [get_files insert_ila.tcl] 4 | set_property USED_IN_SYNTHESIS false [get_files instantiate_ila.tcl] 5 | #set_property USED_IN_IMPLEMENTATION false [get_files insert_ila.tcl] 6 | #set_property USED_IN_IMPLEMENTATION false [get_files instantiate_ila.tcl] 7 | set_property USED_IN_SIMULATION false [get_files insert_ila.tcl] 8 | set_property USED_IN_SIMULATION false [get_files instantiate_ila.tcl] 9 | #source [get_files ila.tcl] 10 | set_property STEPS.OPT_DESIGN.TCL.PRE [get_files instantiate_ila.tcl] [get_runs impl_1] 11 | -------------------------------------------------------------------------------- /vivado_probe/vivado_probe.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::vivado_probe:1.0 3 | 4 | filesets: 5 | scripts: 6 | files: 7 | - "tool_vivado? (scripts/instantiate_ila.tcl)" : {file_type : user, copyto : instantiate_ila.tcl} 8 | - "tool_vivado? (scripts/insert_ila.tcl)" : {file_type : SDC} 9 | - "tool_vivado? (scripts/setup_ila.tcl)" : {file_type : tclSource} 10 | 11 | targets: 12 | default: 13 | description: Vivado ILA probe autogen 14 | filesets : [scripts] 15 | -------------------------------------------------------------------------------- /xil_dsp48_div/xil_dsp48_div.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | name: ::xil_dsp48_div:0.1 3 | 4 | filesets: 5 | rtl: 6 | files: 7 | - rtl/xil_dsp48_div.sv 8 | file_type: verilogSource 9 | 10 | targets: 11 | default: 12 | description: Hardware clock divider using Xilinx 7-series DSP48 13 | filesets : [rtl] 14 | --------------------------------------------------------------------------------