From 0b3f3056d3ab8905ad534f548a33fdba18499ca9 Mon Sep 17 00:00:00 2001 From: Passant Date: Mon, 16 Oct 2023 02:44:30 -0700 Subject: [PATCH] [wip] add cocotb tests --- verilog/dv/cocotb/.gitignore | 4 + verilog/dv/cocotb/README.md | 30 + verilog/dv/cocotb/all_tests/PoR/PoR.c | 52 ++ verilog/dv/cocotb/all_tests/PoR/PoR.py | 76 +++ .../all_tests/bitbang/bitbang_cpu_all_i.c | 38 ++ .../all_tests/bitbang/bitbang_cpu_all_o.c | 40 ++ .../cocotb/all_tests/bitbang/bitbang_no_cpu.c | 10 + .../all_tests/bitbang/bitbang_no_cpu_all_i.c | 10 + .../all_tests/bitbang/bitbang_no_cpu_all_o.c | 9 + .../bitbang/bitbang_no_cpu_functions.py | 240 ++++++++ .../cocotb/all_tests/bitbang/bitbang_spi_i.c | 45 ++ .../cocotb/all_tests/bitbang/bitbang_spi_o.c | 42 ++ .../cocotb/all_tests/bitbang/bitbang_tests.py | 443 ++++++++++++++ .../all_tests/bitbang/bitbang_tests_cpu.py | 72 +++ .../all_tests/check_defaults/check_defaults.c | 21 + .../check_defaults/check_defaults.py | 310 ++++++++++ verilog/dv/cocotb/all_tests/common/bitbang.py | 107 ++++ .../dv/cocotb/all_tests/common/read_hex.py | 28 + verilog/dv/cocotb/all_tests/cpu/cpu_reset.c | 16 + verilog/dv/cocotb/all_tests/cpu/cpu_reset.py | 74 +++ verilog/dv/cocotb/all_tests/cpu/cpu_stress.c | 157 +++++ verilog/dv/cocotb/all_tests/cpu/cpu_stress.py | 42 ++ verilog/dv/cocotb/all_tests/debug/README.md | 48 ++ verilog/dv/cocotb/all_tests/debug/debug.c | 44 ++ verilog/dv/cocotb/all_tests/debug/debug.py | 113 ++++ verilog/dv/cocotb/all_tests/debug/debug_swd.c | 20 + .../dv/cocotb/all_tests/debug/debug_swd.py | 116 ++++ .../dv/cocotb/all_tests/flash_clk/flash_clk.c | 155 +++++ .../cocotb/all_tests/flash_clk/flash_clk.py | 22 + verilog/dv/cocotb/all_tests/gpio/gpio.py | 40 ++ .../all_tests/gpio/gpio_all_bidir_user.c | 66 ++ verilog/dv/cocotb/all_tests/gpio/gpio_all_i.c | 37 ++ .../dv/cocotb/all_tests/gpio/gpio_all_i_pd.c | 13 + .../all_tests/gpio/gpio_all_i_pd_user.c | 16 + .../dv/cocotb/all_tests/gpio/gpio_all_i_pu.c | 14 + .../all_tests/gpio/gpio_all_i_pu_user.c | 18 + .../cocotb/all_tests/gpio/gpio_all_i_user.c | 42 ++ verilog/dv/cocotb/all_tests/gpio/gpio_all_o.c | 41 ++ .../cocotb/all_tests/gpio/gpio_all_o_user.c | 44 ++ verilog/dv/cocotb/all_tests/gpio/gpio_seq.py | 438 +++++++++++++ verilog/dv/cocotb/all_tests/gpio/gpio_user.py | 293 +++++++++ .../all_tests/gpio_caravan/gpio_user.py | 578 ++++++++++++++++++ .../cocotb/all_tests/hello_world/helloWorld.c | 32 + .../all_tests/hello_world/helloWorld.py | 12 + .../housekeeping/general/clock_redirect.c | 16 + .../housekeeping/general/hk_disable.c | 14 + .../all_tests/housekeeping/general/pll.c | 156 +++++ .../all_tests/housekeeping/general/pll.py | 103 ++++ .../housekeeping/general/sys_ctrl.py | 176 ++++++ .../housekeeping_regs/hk_regs_rst_spi.c | 12 + .../housekeeping_regs/hk_regs_wr_spi.c | 12 + .../housekeeping_regs/hk_regs_wr_wb.c | 12 + .../housekeeping_regs/hk_regs_wr_wb_cpu.c | 254 ++++++++ .../housekeeping_regs_tests.py | 254 ++++++++ .../housekeeping_spi/mgmt_pass_thru.py | 36 ++ .../housekeeping_spi/mgmt_pass_thru_rd.c | 29 + .../housekeeping/housekeeping_spi/spi.py | 85 +++ .../housekeeping/housekeeping_spi/spi_rd_wr.c | 12 + .../housekeeping_spi/spi_rd_wr_nbyte.c | 12 + .../housekeeping/housekeeping_spi/test_data | 3 + .../housekeeping_spi/user_pass_thru.py | 120 ++++ .../user_pass_thru_connection.c | 45 ++ .../housekeeping_spi/user_pass_thru_rd.c | 47 ++ .../dv/cocotb/all_tests/irq/IRQ_external.c | 86 +++ .../dv/cocotb/all_tests/irq/IRQ_external.py | 78 +++ .../dv/cocotb/all_tests/irq/IRQ_external2.c | 86 +++ .../dv/cocotb/all_tests/irq/IRQ_external2.py | 79 +++ verilog/dv/cocotb/all_tests/irq/IRQ_spi.c | 68 +++ verilog/dv/cocotb/all_tests/irq/IRQ_spi.py | 71 +++ verilog/dv/cocotb/all_tests/irq/IRQ_timer.c | 68 +++ verilog/dv/cocotb/all_tests/irq/IRQ_timer.py | 58 ++ verilog/dv/cocotb/all_tests/irq/IRQ_uart.c | 64 ++ verilog/dv/cocotb/all_tests/irq/IRQ_uart.py | 77 +++ verilog/dv/cocotb/all_tests/irq/IRQ_uart_rx.c | 66 ++ .../dv/cocotb/all_tests/irq/IRQ_uart_rx.py | 84 +++ verilog/dv/cocotb/all_tests/irq/user0_irq.c | 67 ++ verilog/dv/cocotb/all_tests/irq/user1_irq.c | 67 ++ verilog/dv/cocotb/all_tests/irq/user2_irq.c | 67 ++ verilog/dv/cocotb/all_tests/irq/user_irq.py | 88 +++ .../.vscode/c_cpp_properties.json | 16 + .../dv/cocotb/all_tests/logicAnalyzer/la.c | 165 +++++ .../dv/cocotb/all_tests/logicAnalyzer/la.py | 47 ++ verilog/dv/cocotb/all_tests/mem/mem_dff2_B.c | 34 ++ verilog/dv/cocotb/all_tests/mem/mem_dff2_HW.c | 34 ++ verilog/dv/cocotb/all_tests/mem/mem_dff2_W.c | 49 ++ verilog/dv/cocotb/all_tests/mem/mem_dff_B.c | 34 ++ verilog/dv/cocotb/all_tests/mem/mem_dff_HW.c | 33 + verilog/dv/cocotb/all_tests/mem/mem_dff_W.c | 46 ++ verilog/dv/cocotb/all_tests/mem/mem_sram_B.c | 42 ++ verilog/dv/cocotb/all_tests/mem/mem_sram_HW.c | 43 ++ verilog/dv/cocotb/all_tests/mem/mem_sram_W.c | 43 ++ .../dv/cocotb/all_tests/mem/mem_sram_smoke.c | 64 ++ verilog/dv/cocotb/all_tests/mem/mem_stress.py | 255 ++++++++ .../cocotb/all_tests/mgmt_gpio/mgmt_gpio.py | 243 ++++++++ .../all_tests/mgmt_gpio/mgmt_gpio_bidir.c | 52 ++ .../all_tests/mgmt_gpio/mgmt_gpio_disable.c | 57 ++ .../cocotb/all_tests/mgmt_gpio/mgmt_gpio_in.c | 57 ++ .../all_tests/mgmt_gpio/mgmt_gpio_out.c | 54 ++ .../all_tests/mgmt_gpio/mgmt_gpio_pu_pd.c | 54 ++ .../all_tests/shifting/serial_shifting_0011.c | 38 ++ .../all_tests/shifting/serial_shifting_01.c | 26 + .../all_tests/shifting/serial_shifting_10.c | 26 + .../all_tests/shifting/serial_shifting_1100.c | 38 ++ .../dv/cocotb/all_tests/shifting/shifting.py | 518 ++++++++++++++++ .../dv/cocotb/all_tests/spi_master/SPI_VIP.py | 94 +++ .../cocotb/all_tests/spi_master/spi_master.py | 137 +++++ .../all_tests/spi_master/spi_master_rd.c | 263 ++++++++ .../all_tests/spi_master/spi_master_temp.c | 85 +++ .../dv/cocotb/all_tests/spi_master/test_data | 17 + verilog/dv/cocotb/all_tests/temp/temp.c | 51 ++ verilog/dv/cocotb/all_tests/temp/temp.py | 27 + verilog/dv/cocotb/all_tests/testlist.yaml | 11 + verilog/dv/cocotb/all_tests/timer/timer.py | 114 ++++ .../cocotb/all_tests/timer/timer0_oneshot.c | 61 ++ .../cocotb/all_tests/timer/timer0_periodic.c | 64 ++ verilog/dv/cocotb/all_tests/uart/uart.py | 154 +++++ .../dv/cocotb/all_tests/uart/uart_loopback.c | 63 ++ verilog/dv/cocotb/all_tests/uart/uart_rx.c | 54 ++ .../dv/cocotb/all_tests/uart/uart_rx_msg.c | 36 ++ verilog/dv/cocotb/all_tests/uart/uart_tx.c | 50 ++ .../user_project/user_address_space.c | 55 ++ .../user_project/user_address_space.py | 113 ++++ .../cocotb/all_tests/user_project/user_ram.c | 57 ++ .../cocotb/all_tests/user_project/user_ram.py | 40 ++ verilog/dv/cocotb/cocotb_tests.py | 36 ++ verilog/dv/cocotb/design_info.yaml | 37 ++ .../dv/cocotb/models/cpu_model/cpu_model.py | 117 ++++ .../dv/cocotb/models/cpu_model/cpu_monitor.py | 57 ++ .../cocotb/models/gpio_model/gpio_coverage.py | 154 +++++ .../dv/cocotb/models/gpio_model/gpio_model.py | 100 +++ .../cocotb/models/gpio_model/gpio_monitor.py | 143 +++++ .../models/housekeeping_model/hk_coverage.py | 113 ++++ .../models/housekeeping_model/hk_model.py | 177 ++++++ .../models/housekeeping_model/hk_monitor.py | 63 ++ .../models/housekeeping_model/hk_regs.py | 95 +++ .../models/housekeeping_model/hk_regs.yaml | 458 ++++++++++++++ .../cocotb/models/soc_model/soc_coverage.py | 155 +++++ .../dv/cocotb/models/soc_model/soc_model.py | 211 +++++++ .../dv/cocotb/models/soc_model/soc_monitor.py | 116 ++++ .../user_project_model/user_coverage.py | 80 +++ .../models/user_project_model/user_model.py | 120 ++++ .../models/user_project_model/user_monitor.py | 73 +++ .../dv/cocotb/regression/all_gl_sky130.yaml | 65 ++ .../regression/all_gl_sky130_caravan.yaml | 52 ++ verilog/dv/cocotb/regression/all_rtl.yaml | 74 +++ .../dv/cocotb/regression/all_rtl_sky130.yaml | 68 +++ .../regression/all_rtl_sky130_caravan.yaml | 52 ++ .../dv/cocotb/regression/all_rtl_swift2.yaml | 69 +++ .../dv/cocotb/regression/all_sdf_gf180.yaml | 72 +++ .../dv/cocotb/regression/all_sdf_sky130.yaml | 68 +++ .../regression/all_sdf_sky130_caravan.yaml | 51 ++ .../dv/cocotb/regression/all_spi_tests.yaml | 19 + verilog/dv/cocotb/user_design.py | 175 ++++++ verilog/dv/cocotb/user_monitor_driver.py | 79 +++ .../includes.gl+sdf.caravel_user_project | 7 +- .../includes/includes.gl.caravel_user_project | 54 ++ 156 files changed, 13462 insertions(+), 2 deletions(-) create mode 100644 verilog/dv/cocotb/.gitignore create mode 100644 verilog/dv/cocotb/README.md create mode 100644 verilog/dv/cocotb/all_tests/PoR/PoR.c create mode 100644 verilog/dv/cocotb/all_tests/PoR/PoR.py create mode 100644 verilog/dv/cocotb/all_tests/bitbang/bitbang_cpu_all_i.c create mode 100644 verilog/dv/cocotb/all_tests/bitbang/bitbang_cpu_all_o.c create mode 100644 verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu.c create mode 100644 verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu_all_i.c create mode 100644 verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu_all_o.c create mode 100644 verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu_functions.py create mode 100644 verilog/dv/cocotb/all_tests/bitbang/bitbang_spi_i.c create mode 100644 verilog/dv/cocotb/all_tests/bitbang/bitbang_spi_o.c create mode 100644 verilog/dv/cocotb/all_tests/bitbang/bitbang_tests.py create mode 100644 verilog/dv/cocotb/all_tests/bitbang/bitbang_tests_cpu.py create mode 100644 verilog/dv/cocotb/all_tests/check_defaults/check_defaults.c create mode 100644 verilog/dv/cocotb/all_tests/check_defaults/check_defaults.py create mode 100644 verilog/dv/cocotb/all_tests/common/bitbang.py create mode 100644 verilog/dv/cocotb/all_tests/common/read_hex.py create mode 100644 verilog/dv/cocotb/all_tests/cpu/cpu_reset.c create mode 100644 verilog/dv/cocotb/all_tests/cpu/cpu_reset.py create mode 100644 verilog/dv/cocotb/all_tests/cpu/cpu_stress.c create mode 100644 verilog/dv/cocotb/all_tests/cpu/cpu_stress.py create mode 100644 verilog/dv/cocotb/all_tests/debug/README.md create mode 100644 verilog/dv/cocotb/all_tests/debug/debug.c create mode 100644 verilog/dv/cocotb/all_tests/debug/debug.py create mode 100644 verilog/dv/cocotb/all_tests/debug/debug_swd.c create mode 100644 verilog/dv/cocotb/all_tests/debug/debug_swd.py create mode 100644 verilog/dv/cocotb/all_tests/flash_clk/flash_clk.c create mode 100644 verilog/dv/cocotb/all_tests/flash_clk/flash_clk.py create mode 100644 verilog/dv/cocotb/all_tests/gpio/gpio.py create mode 100644 verilog/dv/cocotb/all_tests/gpio/gpio_all_bidir_user.c create mode 100644 verilog/dv/cocotb/all_tests/gpio/gpio_all_i.c create mode 100644 verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pd.c create mode 100644 verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pd_user.c create mode 100644 verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pu.c create mode 100644 verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pu_user.c create mode 100644 verilog/dv/cocotb/all_tests/gpio/gpio_all_i_user.c create mode 100644 verilog/dv/cocotb/all_tests/gpio/gpio_all_o.c create mode 100644 verilog/dv/cocotb/all_tests/gpio/gpio_all_o_user.c create mode 100644 verilog/dv/cocotb/all_tests/gpio/gpio_seq.py create mode 100644 verilog/dv/cocotb/all_tests/gpio/gpio_user.py create mode 100644 verilog/dv/cocotb/all_tests/gpio_caravan/gpio_user.py create mode 100644 verilog/dv/cocotb/all_tests/hello_world/helloWorld.c create mode 100644 verilog/dv/cocotb/all_tests/hello_world/helloWorld.py create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/general/clock_redirect.c create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/general/hk_disable.c create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/general/pll.c create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/general/pll.py create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/general/sys_ctrl.py create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_rst_spi.c create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_wr_spi.c create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_wr_wb.c create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_wr_wb_cpu.c create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/housekeeping_regs_tests.py create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/mgmt_pass_thru.py create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/mgmt_pass_thru_rd.c create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/spi.py create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/spi_rd_wr.c create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/spi_rd_wr_nbyte.c create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/test_data create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/user_pass_thru.py create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/user_pass_thru_connection.c create mode 100644 verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/user_pass_thru_rd.c create mode 100644 verilog/dv/cocotb/all_tests/irq/IRQ_external.c create mode 100644 verilog/dv/cocotb/all_tests/irq/IRQ_external.py create mode 100644 verilog/dv/cocotb/all_tests/irq/IRQ_external2.c create mode 100644 verilog/dv/cocotb/all_tests/irq/IRQ_external2.py create mode 100644 verilog/dv/cocotb/all_tests/irq/IRQ_spi.c create mode 100644 verilog/dv/cocotb/all_tests/irq/IRQ_spi.py create mode 100644 verilog/dv/cocotb/all_tests/irq/IRQ_timer.c create mode 100644 verilog/dv/cocotb/all_tests/irq/IRQ_timer.py create mode 100644 verilog/dv/cocotb/all_tests/irq/IRQ_uart.c create mode 100644 verilog/dv/cocotb/all_tests/irq/IRQ_uart.py create mode 100644 verilog/dv/cocotb/all_tests/irq/IRQ_uart_rx.c create mode 100644 verilog/dv/cocotb/all_tests/irq/IRQ_uart_rx.py create mode 100644 verilog/dv/cocotb/all_tests/irq/user0_irq.c create mode 100644 verilog/dv/cocotb/all_tests/irq/user1_irq.c create mode 100644 verilog/dv/cocotb/all_tests/irq/user2_irq.c create mode 100644 verilog/dv/cocotb/all_tests/irq/user_irq.py create mode 100644 verilog/dv/cocotb/all_tests/logicAnalyzer/.vscode/c_cpp_properties.json create mode 100644 verilog/dv/cocotb/all_tests/logicAnalyzer/la.c create mode 100644 verilog/dv/cocotb/all_tests/logicAnalyzer/la.py create mode 100644 verilog/dv/cocotb/all_tests/mem/mem_dff2_B.c create mode 100644 verilog/dv/cocotb/all_tests/mem/mem_dff2_HW.c create mode 100644 verilog/dv/cocotb/all_tests/mem/mem_dff2_W.c create mode 100644 verilog/dv/cocotb/all_tests/mem/mem_dff_B.c create mode 100644 verilog/dv/cocotb/all_tests/mem/mem_dff_HW.c create mode 100644 verilog/dv/cocotb/all_tests/mem/mem_dff_W.c create mode 100644 verilog/dv/cocotb/all_tests/mem/mem_sram_B.c create mode 100644 verilog/dv/cocotb/all_tests/mem/mem_sram_HW.c create mode 100644 verilog/dv/cocotb/all_tests/mem/mem_sram_W.c create mode 100644 verilog/dv/cocotb/all_tests/mem/mem_sram_smoke.c create mode 100644 verilog/dv/cocotb/all_tests/mem/mem_stress.py create mode 100644 verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio.py create mode 100644 verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_bidir.c create mode 100644 verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_disable.c create mode 100644 verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_in.c create mode 100644 verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_out.c create mode 100644 verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_pu_pd.c create mode 100644 verilog/dv/cocotb/all_tests/shifting/serial_shifting_0011.c create mode 100644 verilog/dv/cocotb/all_tests/shifting/serial_shifting_01.c create mode 100644 verilog/dv/cocotb/all_tests/shifting/serial_shifting_10.c create mode 100644 verilog/dv/cocotb/all_tests/shifting/serial_shifting_1100.c create mode 100644 verilog/dv/cocotb/all_tests/shifting/shifting.py create mode 100644 verilog/dv/cocotb/all_tests/spi_master/SPI_VIP.py create mode 100644 verilog/dv/cocotb/all_tests/spi_master/spi_master.py create mode 100644 verilog/dv/cocotb/all_tests/spi_master/spi_master_rd.c create mode 100644 verilog/dv/cocotb/all_tests/spi_master/spi_master_temp.c create mode 100644 verilog/dv/cocotb/all_tests/spi_master/test_data create mode 100644 verilog/dv/cocotb/all_tests/temp/temp.c create mode 100644 verilog/dv/cocotb/all_tests/temp/temp.py create mode 100644 verilog/dv/cocotb/all_tests/testlist.yaml create mode 100644 verilog/dv/cocotb/all_tests/timer/timer.py create mode 100644 verilog/dv/cocotb/all_tests/timer/timer0_oneshot.c create mode 100644 verilog/dv/cocotb/all_tests/timer/timer0_periodic.c create mode 100644 verilog/dv/cocotb/all_tests/uart/uart.py create mode 100644 verilog/dv/cocotb/all_tests/uart/uart_loopback.c create mode 100644 verilog/dv/cocotb/all_tests/uart/uart_rx.c create mode 100644 verilog/dv/cocotb/all_tests/uart/uart_rx_msg.c create mode 100644 verilog/dv/cocotb/all_tests/uart/uart_tx.c create mode 100644 verilog/dv/cocotb/all_tests/user_project/user_address_space.c create mode 100644 verilog/dv/cocotb/all_tests/user_project/user_address_space.py create mode 100644 verilog/dv/cocotb/all_tests/user_project/user_ram.c create mode 100644 verilog/dv/cocotb/all_tests/user_project/user_ram.py create mode 100644 verilog/dv/cocotb/cocotb_tests.py create mode 100644 verilog/dv/cocotb/design_info.yaml create mode 100644 verilog/dv/cocotb/models/cpu_model/cpu_model.py create mode 100644 verilog/dv/cocotb/models/cpu_model/cpu_monitor.py create mode 100644 verilog/dv/cocotb/models/gpio_model/gpio_coverage.py create mode 100644 verilog/dv/cocotb/models/gpio_model/gpio_model.py create mode 100644 verilog/dv/cocotb/models/gpio_model/gpio_monitor.py create mode 100644 verilog/dv/cocotb/models/housekeeping_model/hk_coverage.py create mode 100644 verilog/dv/cocotb/models/housekeeping_model/hk_model.py create mode 100644 verilog/dv/cocotb/models/housekeeping_model/hk_monitor.py create mode 100644 verilog/dv/cocotb/models/housekeeping_model/hk_regs.py create mode 100644 verilog/dv/cocotb/models/housekeeping_model/hk_regs.yaml create mode 100644 verilog/dv/cocotb/models/soc_model/soc_coverage.py create mode 100644 verilog/dv/cocotb/models/soc_model/soc_model.py create mode 100644 verilog/dv/cocotb/models/soc_model/soc_monitor.py create mode 100644 verilog/dv/cocotb/models/user_project_model/user_coverage.py create mode 100644 verilog/dv/cocotb/models/user_project_model/user_model.py create mode 100644 verilog/dv/cocotb/models/user_project_model/user_monitor.py create mode 100644 verilog/dv/cocotb/regression/all_gl_sky130.yaml create mode 100644 verilog/dv/cocotb/regression/all_gl_sky130_caravan.yaml create mode 100644 verilog/dv/cocotb/regression/all_rtl.yaml create mode 100644 verilog/dv/cocotb/regression/all_rtl_sky130.yaml create mode 100644 verilog/dv/cocotb/regression/all_rtl_sky130_caravan.yaml create mode 100644 verilog/dv/cocotb/regression/all_rtl_swift2.yaml create mode 100644 verilog/dv/cocotb/regression/all_sdf_gf180.yaml create mode 100644 verilog/dv/cocotb/regression/all_sdf_sky130.yaml create mode 100644 verilog/dv/cocotb/regression/all_sdf_sky130_caravan.yaml create mode 100644 verilog/dv/cocotb/regression/all_spi_tests.yaml create mode 100644 verilog/dv/cocotb/user_design.py create mode 100644 verilog/dv/cocotb/user_monitor_driver.py diff --git a/verilog/dv/cocotb/.gitignore b/verilog/dv/cocotb/.gitignore new file mode 100644 index 000000000..fe104e164 --- /dev/null +++ b/verilog/dv/cocotb/.gitignore @@ -0,0 +1,4 @@ +sim/ +*.log +*.vcd +*.pyc \ No newline at end of file diff --git a/verilog/dv/cocotb/README.md b/verilog/dv/cocotb/README.md new file mode 100644 index 000000000..08fe48574 --- /dev/null +++ b/verilog/dv/cocotb/README.md @@ -0,0 +1,30 @@ +Overview +======== +This directory contain tests to verify the example user project 16 bit counter and 2 other simple tests as examples. + +directory hierarchy +===================== + +# counter_tests + +contain tests for 16 bit counter for more info refer to [counter_tests](counter_tests/README.md) + + # hello_world + + Example test with empty firmware that only power and reset caravel the print "Hello World" + + # hello_world_uart + + Example test That uses the firmware to send "Hello World" using UART TX + + # cocotb_includes.py + + Read only file that imports cocotb based APIs. needed to be imported on the test to use the cocotb based APIs. + + +# cocotb_tests.py + +Module that should import all the tests used to be seen for cocotb as a test + + + diff --git a/verilog/dv/cocotb/all_tests/PoR/PoR.c b/verilog/dv/cocotb/all_tests/PoR/PoR.c new file mode 100644 index 000000000..8bc6daea9 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/PoR/PoR.c @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ +#include + + + +// -------------------------------------------------------- + +/* + * Management SoC GPIO Pin Test + * Tests writing to the GPIO pin. + */ + +void main(){ + enable_debug(); + enableHkSpi(0); + ManagmentGpio_inputEnable(); + int num_blinks = 0; + set_debug_reg1(0XAA); // start of the test + while (1) { + ManagmentGpio_wait(0); + ManagmentGpio_wait(1); + num_blinks++; + if (get_debug_reg1() == 0xFF) + break; + } + ManagmentGpio_outputEnable(); + for (int i = 0; i < num_blinks; i++) { + /* Fast blink for simulation */ + ManagmentGpio_write(1); + dummyDelay(10); + ManagmentGpio_write(0); + dummyDelay(10); + } + set_debug_reg2(0XFF); //finish test + dummyDelay(10000000); +} + diff --git a/verilog/dv/cocotb/all_tests/PoR/PoR.py b/verilog/dv/cocotb/all_tests/PoR/PoR.py new file mode 100644 index 000000000..b5da47eb4 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/PoR/PoR.py @@ -0,0 +1,76 @@ +import random +import cocotb +from cocotb.triggers import ClockCycles, Timer +import cocotb.log +from caravel_cocotb.caravel_interfaces import report_test +from caravel_cocotb.caravel_interfaces import Caravel_env +from caravel_cocotb.interfaces.common_functions.test_functions import max_num_error +from caravel_cocotb.interfaces.common_functions.test_functions import read_config_file +from cocotb.binary import BinaryValue +from caravel_cocotb.interfaces.common_functions.test_functions import Timeout +from all_tests.mgmt_gpio.mgmt_gpio import blink_counter +from user_design import configure_userdesign +from cocotb.clock import Clock + + +@cocotb.test() +@report_test +async def PoR(dut): + # configurations + caravelEnv = Caravel_env(dut) + Timeout(clk=caravelEnv.clk, cycle_num=1904502, precision=0.2) + cocotb.scheduler.add(max_num_error(10, caravelEnv.clk)) + clock = Clock( + caravelEnv.clk, read_config_file()["clock"], units="ns" + ) # Create a 25ns period clock on port clk + cocotb.start_soon(clock.start()) # Start the clock + # drive reset with 1 + await caravelEnv.disable_csb() # + caravelEnv.dut.resetb_tb.value = BinaryValue(value=1, n_bits=1) + await caravelEnv.power_up() + await Timer(530, "ns") + # await caravelEnv.reset() # + await caravelEnv.disable_bins() + debug_regs = await configure_userdesign(caravelEnv) + + # start test + cocotb.log.info("[TEST] Start mgmt_gpio_bidir test") + + await debug_regs.wait_reg1(0xAA) + num_blinks = random.randint(1, 20) + cocotb.log.info(f"[TEST] start send {num_blinks} blinks") + for i in range(num_blinks): + if i == num_blinks - 1: # last iteration + debug_regs.write_debug_reg1_backdoor(0xFF) + caravelEnv.drive_mgmt_gpio(1) + await ClockCycles(caravelEnv.clk, 30000) + caravelEnv.drive_mgmt_gpio(0) + if i != num_blinks - 1: # not last iteration + await ClockCycles(caravelEnv.clk, 30000) + else: + # caravelEnv.drive_mgmt_gpio('z') + await ClockCycles(caravelEnv.clk, 1) + + # caravelEnv.drive_mgmt_gpio('z') + cocotb.log.info(f"[TEST] finish sending {num_blinks} blinks ") + + cocotb.log.info(f"[TEST] waiting for {num_blinks} blinks ") + counter = [0] # list to pass by ref + # forked + await cocotb.start(blink_counter(caravelEnv.get_mgmt_gpi_hdl(), counter)) + await debug_regs.wait_reg2(0xFF) + recieved_blinks = counter[0] + if recieved_blinks == num_blinks: + cocotb.log.info(f"[TEST] recieved the correct number of blinks {num_blinks}") + else: + cocotb.log.error( + f"[TEST] recieved the incorrect number of blinks recieved = {recieved_blinks} expected = {num_blinks}" + ) + cocotb.log.info(f"[TEST] counter = {counter}") + + if recieved_blinks == num_blinks: + cocotb.log.info(f"[TEST] recieved the correct number of blinks {num_blinks}") + else: + cocotb.log.error( + f"[TEST] recieved the incorrect number of blinks recieved = {recieved_blinks} expected = {num_blinks}" + ) diff --git a/verilog/dv/cocotb/all_tests/bitbang/bitbang_cpu_all_i.c b/verilog/dv/cocotb/all_tests/bitbang/bitbang_cpu_all_i.c new file mode 100644 index 000000000..f93586d46 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/bitbang/bitbang_cpu_all_i.c @@ -0,0 +1,38 @@ +#include + +#include + +void main(){ + enable_debug(); + enableHkSpi(0); + bb_configureAllGpios(GPIO_MODE_MGMT_STD_INPUT_NOPULL); + // low + wait_over_input_l(0xAA,0xFFFFFFFF); + wait_over_input_l(0XBB,0xAAAAAAAA); + wait_over_input_l(0XCC,0x55555555); + wait_over_input_l(0XDD,0x0); + // high + wait_over_input_h(0XD1,0x3F); + wait_over_input_h(0XD2,0x0); + wait_over_input_h(0XD3,0x15); + wait_over_input_h(0XD4,0x2A); + + // trying to inject error by sending data to gpio by firmware where gpios configured as input + set_debug_reg1(0XD5); + set_debug_reg1(0XD5); // for delay insertion for release + GPIOs_writeLow(0x5AE1FFB8); // random number + GPIOs_writeHigh(0x1E); // random number + set_debug_reg2(0xFF); +} + +void wait_over_input_l(unsigned int start_code, unsigned int exp_val){ + set_debug_reg1(start_code); // configuration done wait environment to send exp_val to reg_mprj_datal + GPIOs_waitLow(exp_val); + set_debug_reg2(GPIOs_readLow()); + +} +void wait_over_input_h(unsigned int start_code, unsigned int exp_val){ + set_debug_reg1(start_code); + GPIOs_waitHigh(exp_val); + set_debug_reg2(GPIOs_readHigh()); +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/bitbang/bitbang_cpu_all_o.c b/verilog/dv/cocotb/all_tests/bitbang/bitbang_cpu_all_o.c new file mode 100644 index 000000000..54becc8e0 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/bitbang/bitbang_cpu_all_o.c @@ -0,0 +1,40 @@ +#include + +#include +void main(){ + unsigned int i,i_temp, j, active_gpio_num,num_high_gpio; + enable_debug(); + enableHkSpi(0); + bb_configureAllGpios(GPIO_MODE_MGMT_STD_OUTPUT); + set_debug_reg1(0xAA); // finish configuration + GPIOs_writeLow(0x0); + GPIOs_writeHigh(0x0); + active_gpio_num = get_active_gpios_num(); + num_high_gpio = (active_gpio_num - 32); + i = 0x1 << num_high_gpio; + i_temp = i; + for (j = 0; j <= num_high_gpio; j++) { + GPIOs_writeHigh(i); + set_debug_reg2(active_gpio_num+1-j); + wait_debug_reg1(0xD1); // wait until wait until test read 1 + GPIOs_writeHigh(0x0); + set_debug_reg2(0); + wait_debug_reg1(0xD0);// wait until test read 0 + i >>=1; + i |= i_temp; + } + i = 0x80000000; + for (j = 0; j < 32; j++) { + GPIOs_writeHigh(0x3f); + GPIOs_writeLow(i); + set_debug_reg2(32-j); + wait_debug_reg1(0xD1); // wait until test read 1 + GPIOs_writeHigh(0x00); + GPIOs_writeLow(0x0); + set_debug_reg2(0); + wait_debug_reg1(0xD0);// wait until test read 0 + i >>=1; + i |= 0x80000000; + } + set_debug_reg1(0XFF); // configuration done wait environment to send 0xFFA88C5A to reg_mprj_datal +} diff --git a/verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu.c b/verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu.c new file mode 100644 index 000000000..1aa21f5b0 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu.c @@ -0,0 +1,10 @@ +#include +#include + +// Empty C code + +void main() +{ + return; +} + diff --git a/verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu_all_i.c b/verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu_all_i.c new file mode 100644 index 000000000..1aa21f5b0 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu_all_i.c @@ -0,0 +1,10 @@ +#include +#include + +// Empty C code + +void main() +{ + return; +} + diff --git a/verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu_all_o.c b/verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu_all_o.c new file mode 100644 index 000000000..59a806feb --- /dev/null +++ b/verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu_all_o.c @@ -0,0 +1,9 @@ +#include +#include + +// Empty C code + +void main() +{ + return; +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu_functions.py b/verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu_functions.py new file mode 100644 index 000000000..624db0616 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/bitbang/bitbang_no_cpu_functions.py @@ -0,0 +1,240 @@ +from caravel_cocotb.interfaces.defsParser import Regs + +reg = Regs() + + +""" +reg_mprj_xfer contain +bit 0 : busy +bit 1 : bitbang enable +bit 2 : bitbang reset active low +bit 3 : bitbang load registers +bit 4 : bitbang clock +bit 5 : serial data 1 +bit 6 : serial data 2 +""" + +"""shift the 2 registers with 2 ones""" + + +async def clock11(cpu): + reg_mprj_xfer_addr = reg.get_addr("reg_mprj_xfer") + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x66) # 0110_0110 + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x76) # 0111_0110 + + +"""shift the 2 registers with 2 zeros""" + + +async def clock00(cpu): + reg_mprj_xfer_addr = reg.get_addr("reg_mprj_xfer") + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x06) # 0000_0110 + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x16) # 0001_0110 + + +"""shift the 2 registers with 1 in the left side and zero in right side""" + + +async def clock01(cpu): + reg_mprj_xfer_addr = reg.get_addr("reg_mprj_xfer") + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x26) # 0010_0110 + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x36) # 0011_0110 + + +"""shift the 2 registers with 1 in the left side and zero in right side""" + + +async def clock10(cpu): + reg_mprj_xfer_addr = reg.get_addr("reg_mprj_xfer") + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x46) # 0100_0110 + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x56) # 0101_0110 + + +"""enable the serial loader bit to load registers""" + + +async def load(cpu): + reg_mprj_xfer_addr = reg.get_addr("reg_mprj_xfer") + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x06) # enable bit bang + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x0E) # enable loader + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x06) # enable bit bang + + +"""Enable bit-bang mode and clear registers""" + + +async def clear_registers(cpu): + reg_mprj_xfer_addr = reg.get_addr("reg_mprj_xfer") + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x06) # enable bit bang + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x04) # reset + await cpu.drive_data2address(reg_mprj_xfer_addr, 0x06) # enable bit bang + + +""" +-------------------------------------------------------- +Clock in an input + output configuration. The value +passed in "ddhold" is the number of data-dependent hold +violations up to this point. +-------------------------------------------------------- + + * Clock in data on the left side. Assume standard hold + * violation, so clock in 12 times and assume that the + * next data to be clocked will start with "1", enforced + * by the code. + * + * Left side = GPIOs 37 to 19 + """ + + +async def clock_in_left_short(cpu, ddhold): + await clock10(cpu) + await clock10(cpu) + + for i in range(9): + if ddhold != 0: + await clock10(cpu) + ddhold -= 1 + else: + await clock00(cpu) + + await clock00(cpu) + + +async def clock_in_right_short(cpu, ddhold): + await clock01(cpu) + await clock01(cpu) + + for i in range(9): + if ddhold != 0: + await clock01(cpu) + ddhold -= 1 + else: + await clock00(cpu) + + await clock00(cpu) + + +async def clock_in_left_standard(cpu, ddhold): + await clock10(cpu) + await clock10(cpu) + + for i in range(7): + if ddhold != 0: + await clock10(cpu) + ddhold -= 1 + else: + await clock00(cpu) + + await clock10(cpu) + await clock00(cpu) + await clock00(cpu) + await clock10(cpu) + + +"""right output left input""" + + +async def clock_in_right_o_left_i_standard(cpu): + if sky: + await clock11(cpu) + await clock11(cpu) + for i in range(7): + await clock00(cpu) + await clock10(cpu) + await clock00(cpu) + await clock01(cpu) + await clock11(cpu) + else: + for i in range(6): + await clock00(cpu) + await clock10(cpu) + await clock01(cpu) + await clock11(cpu) + await clock11(cpu) + + +"""right input left output""" + + +async def clock_in_right_i_left_o_standard(cpu): + if sky: + await clock11(cpu) + await clock11(cpu) + for i in range(7): + await clock00(cpu) + await clock01(cpu) + await clock00(cpu) + await clock10(cpu) + await clock11(cpu) + else: + for i in range(6): + await clock00(cpu) + await clock01(cpu) + await clock10(cpu) + await clock11(cpu) + await clock11(cpu) + + +"""right input left output""" + + +async def clock_in_right_i_left_i_standard(cpu): + if sky: + await clock11(cpu) + await clock11(cpu) + for i in range(7): + await clock00(cpu) + await clock00(cpu) + await clock00(cpu) + await clock11(cpu) + await clock11(cpu) + else: + for i in range(6): + await clock00(cpu) + await clock00(cpu) + await clock11(cpu) + await clock11(cpu) + await clock11(cpu) + + +"""right output left output""" + + +async def clock_in_right_o_left_o_standard(cpu): + if sky: + await clock11(cpu) + await clock11(cpu) + for i in range(7): + await clock00(cpu) + await clock11(cpu) + await clock00(cpu) + await clock00(cpu) + await clock11(cpu) + else: + for i in range(6): + await clock00(cpu) + await clock11(cpu) + await clock00(cpu) + await clock11(cpu) + await clock11(cpu) + + +async def clock_in_end_output(cpu): + # Right side: GPIO 0 configured disabled + # /Left side: GPIO 37 configured as output + await clock11(cpu) + await clock11(cpu) + await clock00(cpu) + await clock00(cpu) + await clock00(cpu) + await clock00(cpu) + await clock00(cpu) + await clock00(cpu) + await clock00(cpu) + await clock00(cpu) + await clock00(cpu) + await clock01(cpu) + await clock11(cpu) + await load(cpu) + reg_mprj_io_37_addr = reg.get_addr("reg_mprj_io_37") + await cpu.drive_data2address(reg_mprj_io_37_addr, 0x1809) diff --git a/verilog/dv/cocotb/all_tests/bitbang/bitbang_spi_i.c b/verilog/dv/cocotb/all_tests/bitbang/bitbang_spi_i.c new file mode 100644 index 000000000..fb5fad24d --- /dev/null +++ b/verilog/dv/cocotb/all_tests/bitbang/bitbang_spi_i.c @@ -0,0 +1,45 @@ +#include + + + +// Empty C code + +void main() +{ + enable_debug(); + // GPIOs_configureAll(GPIO_MODE_MGMT_STD_INPUT_NOPULL); + // GPIOs_loadConfigs(); + set_debug_reg1(0xAA); // finish configuration + wait_debug_reg2(0xDD); + // low + wait_over_input_l(0xAA,0xFFFFFFFF); + wait_over_input_l(0XBB,0xAAAAAAAA); + wait_over_input_l(0XCC,0x55555555); + wait_over_input_l(0XDD,0x0); + // high + wait_over_input_h(0XD1,0x3F); + wait_over_input_h(0XD2,0x0); + wait_over_input_h(0XD3,0x15); + wait_over_input_h(0XD4,0x2A); + + // trying to inject error by sending data to gpio by firmware where gpios configured as input + set_debug_reg1(0XD5); + set_debug_reg1(0XD5); // for delay insertion for release + GPIOs_writeLow(0x5AE1FFB8); // random number + GPIOs_writeHigh(0x1E); // random number + set_debug_reg2(0xFF); + +} + + +void wait_over_input_l(unsigned int start_code, unsigned int exp_val){ + set_debug_reg1(start_code); // configuration done wait environment to send exp_val to reg_mprj_datal + GPIOs_waitLow(exp_val); + set_debug_reg2(GPIOs_readLow()); + +} +void wait_over_input_h(unsigned int start_code, unsigned int exp_val){ + set_debug_reg1(start_code); + GPIOs_waitHigh(exp_val); + set_debug_reg2(GPIOs_readHigh()); +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/bitbang/bitbang_spi_o.c b/verilog/dv/cocotb/all_tests/bitbang/bitbang_spi_o.c new file mode 100644 index 000000000..c60ef3e69 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/bitbang/bitbang_spi_o.c @@ -0,0 +1,42 @@ +#include + + +void main(){ + unsigned int i,i_temp, j, active_gpio_num,num_high_gpio; + enable_debug(); + // GPIOs_configureAll(GPIO_MODE_MGMT_STD_OUTPUT); + // GPIOs_loadConfigs(); + set_debug_reg1(0xAA); // finish configuration + wait_debug_reg2(0xDD); + enableHkSpi(0); + GPIOs_writeLow(0x0); + GPIOs_writeHigh(0x0); + active_gpio_num = get_active_gpios_num(); + num_high_gpio = (active_gpio_num - 32); + i = 0x1 << num_high_gpio; + i_temp = i; + for (j = 0; j <= num_high_gpio; j++) { + GPIOs_writeHigh(i); + set_debug_reg2(active_gpio_num+1-j); + wait_debug_reg1(0xD1); // wait until wait until test read 1 + GPIOs_writeHigh(0x0); + set_debug_reg2(0); + wait_debug_reg1(0xD0);// wait until test read 0 + i >>=1; + i |= i_temp; + } + i = 0x80000000; + for (j = 0; j < 32; j++) { + GPIOs_writeHigh(0x3f); + GPIOs_writeLow(i); + set_debug_reg2(32-j); + wait_debug_reg1(0xD1); // wait until test read 1 + GPIOs_writeHigh(0x00); + GPIOs_writeLow(0x0); + set_debug_reg2(0); + wait_debug_reg1(0xD0);// wait until test read 0 + i >>=1; + i |= 0x80000000; + } + set_debug_reg1(0XFF); // configuration done wait environment to send 0xFFA88C5A to reg_mprj_datal +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/bitbang/bitbang_tests.py b/verilog/dv/cocotb/all_tests/bitbang/bitbang_tests.py new file mode 100644 index 000000000..3f88adbab --- /dev/null +++ b/verilog/dv/cocotb/all_tests/bitbang/bitbang_tests.py @@ -0,0 +1,443 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.interfaces.cpu import RiskV +from caravel_cocotb.interfaces.defsParser import Regs +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test + +from caravel_cocotb.caravel_interfaces import GPIO_MODE + +reg = Regs() + + +@cocotb.test() +@report_test +async def bitbang_no_cpu_all_o(dut): + caravelEnv = await test_configure(dut, timeout_cycles=119373) + cpu = RiskV(dut) + cpu.cpu_force_reset() + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_37"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_36"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_35"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_34"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_33"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_32"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_31"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_30"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_29"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_28"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_27"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_26"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_25"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_24"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_23"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_22"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_21"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_20"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_19"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_18"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_17"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_16"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_15"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_14"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_13"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_12"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_11"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_10"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_9"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_8"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_7"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_6"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_5"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_4"), GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_3"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_2"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_1"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_0"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_0"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + + # Configure all as output except reg_mprj_io_3 + await clear_registers(cpu) + await clock_in_right_o_left_o_standard(cpu) # 18 and 19 + await clock_in_right_o_left_o_standard(cpu) # 17 and 20 + await clock_in_right_o_left_o_standard(cpu) # 16 and 21 + await clock_in_right_o_left_o_standard(cpu) # 15 and 22 + await clock_in_right_o_left_o_standard(cpu) # 14 and 23 + await clock_in_right_o_left_o_standard(cpu) # 13 and 24 + await clock_in_right_o_left_o_standard(cpu) # 12 and 25 + await clock_in_right_o_left_o_standard(cpu) # 11 and 26 + await clock_in_right_o_left_o_standard(cpu) # 10 and 27 + await clock_in_right_o_left_o_standard(cpu) # 9 and 28 + await clock_in_right_o_left_o_standard(cpu) # 8 and 29 + await clock_in_right_o_left_o_standard(cpu) # 7 and 30 + await clock_in_right_o_left_o_standard(cpu) # 6 and 31 + await clock_in_right_o_left_o_standard(cpu) # 5 and 32 + await clock_in_right_o_left_o_standard(cpu) # 4 and 33 + await clock_in_right_o_left_i_standard(cpu) # 3 and 34 + await clock_in_right_o_left_i_standard(cpu) # 2 and 35 + await clock_in_right_o_left_i_standard(cpu) # 1 and 36 + await clock_in_right_o_left_i_standard(cpu) # 0 and 37 + await load(cpu) # load + + await caravelEnv.release_csb() + await cpu.drive_data2address(reg.get_addr("reg_mprj_datal"), 0x0) + await cpu.drive_data2address(reg.get_addr("reg_mprj_datah"), 0x0) + + i = 0x20 + for j in range(5): + await cpu.drive_data2address(reg.get_addr("reg_mprj_datah"), i) + # cocotb.log.info(f'[Test] gpio out = {caravelEnv.monitor_gpio((37,4))} int {caravelEnv.monitor_gpio((37,4)).integer} i = {i}') + if caravelEnv.monitor_gpio((37, 4)).integer != i << 28: + cocotb.log.error( + f"[TEST] Wrong gpio high bits output {caravelEnv.monitor_gpio((37,4))} instead of {bin(i << 28)}" + ) + # for k in range(250): + await cpu.drive_data2address(reg.get_addr("reg_mprj_datah"), 0) + if caravelEnv.monitor_gpio((37, 4)).integer != 0: + cocotb.log.error( + f"[TEST] Wrong gpio output {caravelEnv.monitor_gpio((37,4))} instead of {bin(0x00000)}" + ) + + i = i >> 1 + i |= 0x20 + await ClockCycles(caravelEnv.clk, 1) + + i = 0x80000000 + for j in range(32): + await cpu.drive_data2address(reg.get_addr("reg_mprj_datah"), 0x3F) + await cpu.drive_data2address(reg.get_addr("reg_mprj_datal"), i) + if caravelEnv.monitor_gpio((37, 32)).integer != 0x3F: + cocotb.log.error( + f"[TEST] Wrong gpio high bits output {caravelEnv.monitor_gpio((37,32))} instead of {bin(0x3f)}" + ) + if caravelEnv.monitor_gpio((31, 4)).integer != i >> 4: + cocotb.log.error( + f"[TEST] Wrong gpio low bits output {caravelEnv.monitor_gpio((31,4))} instead of {i>>4}" + ) + cocotb.log.info( + f"[Test] gpio out = {caravelEnv.monitor_gpio((37,4))} type {int(caravelEnv.monitor_gpio((37,4)))} i = {i}" + ) + await ClockCycles(caravelEnv.clk, 1) + + # await cpu.drive_data2address(reg.get_addr('reg_mprj_datah'),0x0) + await cpu.drive_data2address(reg.get_addr("reg_mprj_datah"), 0x0) + await cpu.drive_data2address(reg.get_addr("reg_mprj_datal"), 0x0) + await ClockCycles(caravelEnv.clk, 1) + + if caravelEnv.monitor_gpio((37, 4)).integer != 0: + cocotb.log.error( + f"Wrong gpio output {caravelEnv.monitor_gpio((37,4))} instead of {bin(0x00000)}" + ) + + i = i >> 1 + i |= 0x80000000 + + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def bitbang_no_cpu_all_i(dut): + caravelEnv = await test_configure(dut, timeout_cycles=117351) + cpu = RiskV(dut) + cpu.cpu_force_reset() + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_37"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_36"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_35"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_34"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_33"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_32"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_31"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_30"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_29"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_28"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_27"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_26"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_25"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_24"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_23"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_22"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_21"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_20"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_19"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_18"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_17"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_16"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_15"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_14"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_13"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_12"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_11"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_10"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_9"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_8"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_7"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_6"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_5"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_4"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_3"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_2"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_1"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_0"), GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value + ) + + # Configure all as input except reg_mprj_io_3 + await clear_registers(cpu) + await clock_in_right_i_left_i_standard(cpu) # 18 and 19 + await clock_in_right_i_left_i_standard(cpu) # 17 and 20 + await clock_in_right_i_left_i_standard(cpu) # 16 and 21 + await clock_in_right_i_left_i_standard(cpu) # 15 and 22 + await clock_in_right_i_left_i_standard(cpu) # 14 and 23 + await clock_in_right_i_left_i_standard(cpu) # 13 and 24 + await clock_in_right_i_left_i_standard(cpu) # 12 and 25 + await clock_in_right_i_left_i_standard(cpu) # 11 and 26 + await clock_in_right_i_left_i_standard(cpu) # 10 and 27 + await clock_in_right_i_left_i_standard(cpu) # 9 and 28 + await clock_in_right_i_left_i_standard(cpu) # 8 and 29 + await clock_in_right_i_left_i_standard(cpu) # 7 and 30 + await clock_in_right_i_left_i_standard(cpu) # 6 and 31 + await clock_in_right_i_left_i_standard(cpu) # 5 and 32 + await clock_in_right_i_left_i_standard(cpu) # 4 and 33 + await clock_in_right_i_left_i_standard(cpu) # 3 and 34 + await clock_in_right_i_left_i_standard(cpu) # 2 and 35 + await clock_in_right_i_left_i_standard(cpu) # 1 and 36 + await clock_in_right_i_left_i_standard(cpu) # 0 and 37 + await load(cpu) # load + + caravelEnv.drive_gpio_in((31, 0), 0x8F66FD7B) + await ClockCycles(caravelEnv.clk, 100) + reg_mprj_datal = await cpu.read_address(reg.get_addr("reg_mprj_datal")) + # value_masked = reg_mprj_datal & mask_input + if reg_mprj_datal == 0x8F66FD7B: + cocotb.log.info("[TEST] Passed with value 0x8F66FD7B") + else: + cocotb.log.error( + f"[TEST] fail with value mprj = {bin(reg_mprj_datal)} instead of {bin(0x8F66FD7B)}" + ) + await ClockCycles(caravelEnv.clk, 100) + await cpu.drive_data2address(reg.get_addr("reg_mprj_datah"), 0x1B) + x = caravelEnv.monitor_gpio((37, 32)) + print(f"xxxxxxxx {x}") + await ClockCycles(caravelEnv.clk, 100) + + caravelEnv.drive_gpio_in((31, 0), 0xFFA88C5A) + await ClockCycles(caravelEnv.clk, 100) + reg_mprj_datal = await cpu.read_address(reg.get_addr("reg_mprj_datal")) + # value_masked = reg_mprj_datal & mask_input + if reg_mprj_datal == 0xFFA88C5A: + cocotb.log.info("[TEST] Passed with value 0xFFA88C5A") + else: + cocotb.log.error( + f"[TEST] fail with value mprj = {bin(reg_mprj_datal)} instead of {bin(0xFFA88C5A)}" + ) + + await cpu.drive_data2address(reg.get_addr("reg_mprj_datah"), 0x2B) + await ClockCycles(caravelEnv.clk, 100) + + caravelEnv.drive_gpio_in((31, 0), 0xC9536346) + await ClockCycles(caravelEnv.clk, 100) + reg_mprj_datal = await cpu.read_address(reg.get_addr("reg_mprj_datal")) + # value_masked = reg_mprj_datal & mask_input + if reg_mprj_datal == 0xC9536346: + cocotb.log.info("[TEST] Passed with value 0xC9536346") + else: + cocotb.log.error( + f"[TEST] fail with value mprj = {bin(reg_mprj_datal)} instead of {bin(0xC9536346)}" + ) + await cpu.drive_data2address(reg.get_addr("reg_mprj_datah"), 0x3B) + await ClockCycles(caravelEnv.clk, 100) + + +"""Testbench of GPIO configuration through bit-bang method using the housekeeping SPI.""" + + +@cocotb.test() +@report_test +async def io_ports(dut): + cpu = RiskV(dut) + cpu.cpu_force_reset() + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_0"), GPIO_MODE.GPIO_MODE_USER_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_1"), GPIO_MODE.GPIO_MODE_USER_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_2"), GPIO_MODE.GPIO_MODE_USER_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_3"), GPIO_MODE.GPIO_MODE_USER_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_4"), GPIO_MODE.GPIO_MODE_USER_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_5"), GPIO_MODE.GPIO_MODE_USER_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_6"), GPIO_MODE.GPIO_MODE_USER_STD_OUTPUT.value + ) + await cpu.drive_data2address( + reg.get_addr("reg_mprj_io_7"), GPIO_MODE.GPIO_MODE_USER_STD_OUTPUT.value + ) + + # Apply configuration + await cpu.drive_data2address(reg.get_addr("reg_mprj_xfer"), 1) + + while True: + if await cpu.read_address(reg.get_addr("reg_mprj_xfer")) != 1: + break diff --git a/verilog/dv/cocotb/all_tests/bitbang/bitbang_tests_cpu.py b/verilog/dv/cocotb/all_tests/bitbang/bitbang_tests_cpu.py new file mode 100644 index 000000000..df7ccd2ff --- /dev/null +++ b/verilog/dv/cocotb/all_tests/bitbang/bitbang_tests_cpu.py @@ -0,0 +1,72 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.interfaces.defsParser import Regs +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from caravel_cocotb.caravel_interfaces import GPIO_MODE +from all_tests.gpio.gpio_seq import gpio_all_o_seq +from all_tests.gpio.gpio_seq import gpio_all_i_seq +from all_tests.common.bitbang import bb_configure_all_gpios +from caravel_cocotb.caravel_interfaces import SPI +from user_design import configure_userdesign + +reg = Regs() + + +@cocotb.test() +@report_test +async def bitbang_cpu_all_o(dut): + caravelEnv = await test_configure(dut, timeout_cycles=5004275) + debug_regs = await configure_userdesign(caravelEnv) + await gpio_all_o_seq(dut, caravelEnv, debug_regs) + + +@cocotb.test() +@report_test +async def bitbang_cpu_all_i(dut): + caravelEnv = await test_configure(dut, timeout_cycles=3311179) + debug_regs = await configure_userdesign(caravelEnv) + await gpio_all_i_seq(dut, caravelEnv, debug_regs) + + +"""Testbench of GPIO configuration through bit-bang method using the housekeeping SPI configure all gpio as output.""" + + +@cocotb.test() +@report_test +async def bitbang_spi_o(dut): + caravelEnv = await test_configure(dut, timeout_cycles=2008592) + debug_regs = await configure_userdesign(caravelEnv) + await gpio_all_o_seq(dut, caravelEnv, debug_regs, bitbang_spi_o_configure) + + +"""Testbench of GPIO configuration through bit-bang method using the housekeeping SPI configure all gpio as input.""" + + +@cocotb.test() +@report_test +async def bitbang_spi_i(dut): + caravelEnv = await test_configure(dut, timeout_cycles=316406) + debug_regs = await configure_userdesign(caravelEnv) + await gpio_all_i_seq(dut, caravelEnv, debug_regs, bitbang_spi_i_configure) + + +async def bitbang_spi_i_configure(caravelEnv, debug_regs): + spi_master = SPI(caravelEnv) + await caravelEnv.disable_csb() + await bb_configure_all_gpios( + GPIO_MODE.GPIO_MODE_MGMT_STD_INPUT_NOPULL.value, spi_master + ) + + # disable Housekeeping SPI + await spi_master.write_reg_spi( 0x6F, 0x1) + await ClockCycles(caravelEnv.clk, 1) + debug_regs.write_debug_reg2_backdoor(0xDD) + + +async def bitbang_spi_o_configure(caravelEnv, debug_regs): + spi_master = SPI(caravelEnv) + await caravelEnv.disable_csb() + await bb_configure_all_gpios(GPIO_MODE.GPIO_MODE_MGMT_STD_OUTPUT.value, spi_master) + debug_regs.write_debug_reg2_backdoor(0xDD) diff --git a/verilog/dv/cocotb/all_tests/check_defaults/check_defaults.c b/verilog/dv/cocotb/all_tests/check_defaults/check_defaults.c new file mode 100644 index 000000000..8b7f775cb --- /dev/null +++ b/verilog/dv/cocotb/all_tests/check_defaults/check_defaults.c @@ -0,0 +1,21 @@ + +#include + +void main(){ + enable_debug(); + enableHkSpi(0); + ManagmentGpio_outputEnable(); + while (true){ + GPIOs_writeLow(0x0); + GPIOs_writeHigh(0x0); + // write input to the user project + int gpio_l = GPIOs_readLow(); + int gpio_h = GPIOs_readHigh(); + set_debug_reg1(gpio_l); + set_debug_reg2(gpio_h); + ManagmentGpio_write(0); + GPIOs_writeLow(0xFFFFFFFF); + GPIOs_writeHigh(0x3F); + ManagmentGpio_write(1); + } +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/check_defaults/check_defaults.py b/verilog/dv/cocotb/all_tests/check_defaults/check_defaults.py new file mode 100644 index 000000000..f650d5592 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/check_defaults/check_defaults.py @@ -0,0 +1,310 @@ +import random +from cocotb.triggers import ClockCycles +import cocotb +from cocotb.queue import Queue +from cocotb.triggers import Combine +from user_design import configure_userdesign +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from user_monitor_driver import UserPins + +@cocotb.test() +@report_test +async def check_defaults(dut): + caravelEnv = await test_configure(dut, timeout_cycles=1145328) + debug_regs = await configure_userdesign(caravelEnv) + user_pins = UserPins(caravelEnv) + gpio_test = GPIOsDefaultTests(caravelEnv, user_pins, debug_regs) + # read gpios config from file user_define_temp.txt + user_project_root = cocotb.plusargs["USER_PROJECT_ROOT"].replace('"', "") + configs = read_config_file(f"{user_project_root}/verilog/rtl/user_define_temp.txt") + mgmt_out = [gpio for gpio, type in enumerate(configs) if type in ("GPIO_MODE_MGMT_STD_OUTPUT")] + user_out = [gpio for gpio, type in enumerate(configs) if type in ("GPIO_MODE_USER_STD_OUTPUT", "GPIO_MODE_USER_STD_OUT_MONITORED")] + mgmt_in = [gpio for gpio, type in enumerate(configs) if type in ("GPIO_MODE_MGMT_STD_INPUT_NOPULL")] + user_in = [gpio for gpio, type in enumerate(configs) if type in ("GPIO_MODE_USER_STD_INPUT_NOPULL")] + mgmt_in_pu = [gpio for gpio, type in enumerate(configs) if type in ("GPIO_MODE_MGMT_STD_INPUT_PULLUP")] + user_in_pu = [gpio for gpio, type in enumerate(configs) if type in ("GPIO_MODE_USER_STD_INPUT_PULLUP")] + mgmt_in_pd = [gpio for gpio, type in enumerate(configs) if type in ("GPIO_MODE_MGMT_STD_INPUT_PULLDOWN")] + user_in_pd = [gpio for gpio, type in enumerate(configs) if type in ("GPIO_MODE_USER_STD_INPUT_PULLDOWN")] + user_bidirect = [gpio for gpio, type in enumerate(configs) if type in ("GPIO_MODE_USER_STD_BIDIRECTIONAL")] + user_configs = {"user_in": user_in, "user_in_pu": user_in_pu, "user_in_pd": user_in_pd, "user_out": user_out, "user_bidirect": user_bidirect} + await ClockCycles(caravelEnv.clk, 10) + # initialize user oeb and pull up down + gpio_test.configure_io_oeb(user_configs) + gpio_test.configure_pull_up_pd(user_configs) + # drive all with 1 initialy + caravelEnv.drive_gpio_in((37,0), 0x3FFFFFFFFF) + await ClockCycles(caravelEnv.clk, 1) + all_out = mgmt_out + user_out + for gpio in all_out: + caravelEnv.release_gpio(gpio) + del all_out + await ClockCycles(caravelEnv.clk, 1) + + all_modes_tests = [] + # test mgmt_out + all_modes_tests.append(await cocotb.start(gpio_test.test_mgmt_out(mgmt_out))) + + # test mgmt_in + all_modes_tests.append(await cocotb.start(gpio_test.test_mgmt_in(mgmt_in))) + + # test mgmt_in_pu + all_modes_tests.append(await cocotb.start(gpio_test.test_mgmt_in_pull(mgmt_in_pu, pull_mode="up"))) + + # # test mgmt_in_pd + all_modes_tests.append(await cocotb.start(gpio_test.test_mgmt_in_pull(mgmt_in_pd, pull_mode="down"))) + + # # test user_out + all_modes_tests.append(await cocotb.start(gpio_test.test_user_out(user_out))) + + # test user_in + all_modes_tests.append(await cocotb.start(gpio_test.test_user_in(user_in))) + + # test user_in_pu + all_modes_tests.append(await cocotb.start(gpio_test.test_user_in_pull(user_in_pu, pull_mode="up"))) + # test user_in_pd + all_modes_tests.append(await cocotb.start(gpio_test.test_user_in_pull(user_in_pd, pull_mode="pd"))) + + # test user_bidirectional + # all_modes_tests.append(await cocotb.start(test_user_bidirectional(caravelEnv, user_bidirect, user_pins))) + + await Combine(*all_modes_tests) + + +def read_config_file(filename): + gpio_configs = [] + with open(filename, 'r') as f: + for line in f: + gpio_configs.append(line.strip()) + return gpio_configs + + +class GPIOsDefaultTests: + def __init__(self, caravelEnv, user_pins, debug_regs): + self.caravelEnv = caravelEnv + self.user_pins = user_pins + self.debug_regs = debug_regs + + def configure_io_oeb(self, user_configs): + combined_all_o_eanble = user_configs["user_out"] + user_configs["user_in_pu"] + user_configs["user_in_pd"] + for i in range(38): + if i in combined_all_o_eanble: + self.user_pins.drive_io_oeb(i, 0) + else: + self.user_pins.drive_io_oeb(i, 1) + + def configure_pull_up_pd(self, user_configs): + for i in range(38): + if i in user_configs["user_in_pu"]: + self.user_pins.drive_io_out(i, 1) + elif i in user_configs["user_in_pd"]: + self.user_pins.drive_io_out(i, 0) + + async def test_user_out(self, gpios): + cocotb.log.info(f"[TEST] gpios configured as user output = {gpios}") + queue = Queue() + await cocotb.start(self.drive_output(queue, gpios)) + for i in range(random.randint(10, 100)): + data = await queue.get() + await ClockCycles(self.caravelEnv.clk, 1) + for index, gpio in enumerate(gpios): + val = self.caravelEnv.monitor_gpio(gpio).integer + if val != data[index]: + cocotb.log.error(f"[TEST][test_user_out] gpio {gpio} is incorrect expected {data[index]} received {val}") + else: + cocotb.log.debug(f"[TEST][test_user_out] gpio {gpio} is correct received {val}") + cocotb.log.info(f"[TEST] done with test_user_out") + + async def drive_output(self, queue, gpios): + while True: + data = [] + for gpio in gpios: + random_val = random.randint(0, 1) + self.user_pins.drive_io_out(gpio, random_val) + data.append(random_val) + await queue.put(data) + await ClockCycles(self.caravelEnv.clk, random.randint(10, 20)) + + + async def test_user_in(self, gpios): + cocotb.log.info(f"[TEST] gpios configured as user input = {gpios}") + for i in range(random.randint(5, 10)): + await self.caravelEnv.wait_mgmt_gpio(1) + rand_values = dict() + for gpio in gpios: + val = random.randint(0, 1) + rand_values[gpio] = val + self.caravelEnv.drive_gpio_in(gpio, val) + await self.caravelEnv.wait_mgmt_gpio(0) + for gpio in gpios: + val = self.user_pins.monitor_io_in(gpio) + if val != rand_values[gpio]: + cocotb.log.error(f"[TEST][test_user_in] gpio {gpio} is not {rand_values[gpio]}") + else: + cocotb.log.debug(f"[TEST][test_user_in] gpio {gpio} is {rand_values[gpio]}") + cocotb.log.info(f"[TEST] done with test_user_in") + + async def test_user_in_pull(self, gpios, pull_mode="up"): + cocotb.log.info(f"[TEST] gpios configured as user input pull{pull_mode} = {gpios}") + for i in range(random.randint(5, 10)): + await self.caravelEnv.wait_mgmt_gpio(1) + rand_values = dict() + for gpio in gpios: + val = random.choice([1, 0, 'z']) + rand_values[gpio] = val + if val == 'z': + self.caravelEnv.release_gpio(gpio) + else: + self.caravelEnv.drive_gpio_in(gpio, val) + await self.caravelEnv.wait_mgmt_gpio(0) + for gpio in gpios: + val = self.user_pins.monitor_io_in(gpio) + rand_val = rand_values[gpio] if rand_values[gpio] != 'z' else 1 if pull_mode == "up" else 0 + if val != rand_val: + cocotb.log.error(f"[TEST][test_user_in_pull] pull {pull_mode} gpio {gpio} is not {rand_val} drived by {rand_values[gpio]}") + else: + cocotb.log.debug(f"[TEST][test_user_in_pull] pull {pull_mode} gpio {gpio} is {rand_val} drived by {rand_values[gpio]}") + cocotb.log.info("[TEST] done with test_user_in_pull") + + async def test_user_bidirectional(self, caravelEnv, gpios): + cocotb.log.info(f"[TEST] gpios configured as user bidirectional = {gpios}") + queue = Queue() + configure_bidirectional = await cocotb.start(self.configure_bidirectional(queue, gpios)) + for i in range(random.randint(10, 100)): + configurations = await queue.get() + # release all gpios + for gpio in gpios: + caravelEnv.release_gpio(gpio) + cocotb.log.debug(f"[TEST][test_user_bidirectional] configurations = {configurations}") + await ClockCycles(caravelEnv.clk, 1) + # check output + drived_value = 0 if configurations[0] == "input" else 1 + for index, configuration in enumerate(configurations): + if configuration == "output": + cocotb.log.debug(f"[TEST][test_user_bidirectional] gpio {gpios[index]} is output") + val = caravelEnv.monitor_gpio(gpios[index]).integer + if val != drived_value: + cocotb.log.error(f"[TEST][test_user_bidirectional] gpio {gpios[index]} is incorrect expected {drived_value} received {val}") + else: + cocotb.log.debug(f"[TEST][test_user_bidirectional] gpio {gpios[index]} is correct received {val}") + # check input + rand_values = dict() + for index, configuration in enumerate(configurations): + if configuration == "input": + cocotb.log.debug(f"[TEST][test_user_bidirectional] gpio {gpios[index]} is input") + val = random.randint(0, 1) + rand_values[gpios[index]] = val + caravelEnv.drive_gpio_in(gpios[index], val) + await ClockCycles(caravelEnv.clk, 1) + for index, configuration in enumerate(configurations): + if configuration == "input": + val = self.user_pins.monitor_io_in(gpios[index]) + rand_val = rand_values[gpios[index]] + if val != rand_val: + cocotb.log.error(f"[TEST][test_user_bidirectional] gpio {gpios[index]} is not {rand_val} drived by {rand_values[gpios[index]]}") + else: + cocotb.log.debug(f"[TEST][test_user_bidirectional] gpio {gpios[index]} is {rand_val} drived by {rand_values[gpios[index]]}") + configure_bidirectional.kill() + cocotb.log.info("[TEST] done with test_user_bidirectional") + + async def configure_bidirectional(self, queue, gpios): + while True: + # configure bidirectional as input or output + configurations = [] + for gpio in gpios: + random_val = random.randint(0, 1) + self.user_pins.drive_io_oeb(gpio, random_val) + configurations.append("input" if random_val else "output") + await queue.put(configurations) + # if first configurations is input drive with 0 else drive with 1 + if configurations[0] == "input": + for index, gpio in enumerate(gpios): + if configurations[index] == "output": + cocotb.log.info(f"[TEST] gpio {gpio} configured as output drive with 0") + self.user_pins.drive_io_out(gpio, 0) + else: + for index, gpio in enumerate(gpios): + if configurations[index] == "output": + cocotb.log.info(f"[TEST] gpio {gpio} configured as output drive with 1") + self.user_pins.drive_io_out(gpio, 1) + await ClockCycles(self.caravelEnv.clk, random.randint(10, 20)) + + async def test_mgmt_out(self, gpios): + cocotb.log.info(f"[TEST] gpios configured as mgmt output = {gpios}") + for i in range(random.randint(5, 10)): + await self.caravelEnv.wait_mgmt_gpio(1) + for gpio in gpios: + val = self.caravelEnv.monitor_gpio(gpio).integer + if val == 0: + cocotb.log.error(f"[TEST][test_mgmt_out] gpio {gpio} is not 1") + else: + cocotb.log.debug(f"[TEST][test_mgmt_out] gpio {gpio} is 1") + await self.caravelEnv.wait_mgmt_gpio(0) + for gpio in gpios: + val = self.caravelEnv.monitor_gpio(gpio).integer + if val == 1: + cocotb.log.error(f"[TEST][test_mgmt_out] gpio {gpio} is not 0") + else: + cocotb.log.debug(f"[TEST][test_mgmt_out] gpio {gpio} is 0") + cocotb.log.info("[TEST] done with test_mgmt_out") + + async def test_mgmt_in(self, gpios): + cocotb.log.info(f"[TEST] gpios configured as mgmt input = {gpios}") + for i in range(random.randint(5, 10)): + await self.caravelEnv.wait_mgmt_gpio(1) + rand_values = dict() + for gpio in gpios: + val = random.randint(0, 1) + rand_values[gpio] = val + self.caravelEnv.drive_gpio_in(gpio, val) + await self.caravelEnv.wait_mgmt_gpio(0) + gpio_high_reg = self.debug_regs.read_debug_reg2() + gpio_low_reg = self.debug_regs.read_debug_reg1() + for gpio in gpios: + if gpio < 32: + val = self.get_bit_from_reg(gpio_low_reg, gpio) + if val != rand_values[gpio]: + cocotb.log.error(f"[TEST][test_mgmt_in] gpio {gpio} is not {rand_values[gpio]}") + else: + cocotb.log.debug(f"[TEST][test_mgmt_in] gpio {gpio} is {rand_values[gpio]}") + else: + val = self.get_bit_from_reg(gpio_high_reg, gpio-32) + if val != rand_values[gpio]: + cocotb.log.error(f"[TEST][test_mgmt_in] gpio {gpio} is not {rand_values[gpio]}") + else: + cocotb.log.debug(f"[TEST][test_mgmt_in] gpio {gpio} is {rand_values[gpio]}") + cocotb.log.info("[TEST] done with test_mgmt_in") + + async def test_mgmt_in_pull(self, gpios, pull_mode="up"): + cocotb.log.info(f"[TEST] gpios configured as mgmt input pull{pull_mode} = {gpios}") + for i in range(random.randint(5, 10)): + await self.caravelEnv.wait_mgmt_gpio(1) + rand_values = dict() + for gpio in gpios: + val = random.choice([1, 0, 'z']) + rand_values[gpio] = val + if val == 'z': + self.caravelEnv.release_gpio(gpio) + else: + self.caravelEnv.drive_gpio_in(gpio, val) + await self.caravelEnv.wait_mgmt_gpio(0) + gpio_high_reg = self.debug_regs.read_debug_reg2() + gpio_low_reg = self.debug_regs.read_debug_reg1() + for gpio in gpios: + rand_val = rand_values[gpio] if rand_values[gpio] != 'z' else 1 if pull_mode == "up" else 0 + if gpio < 32: + val = self.get_bit_from_reg(gpio_low_reg, gpio) + if val != rand_val: + cocotb.log.error(f"[TEST][test_mgmt_in_pull] pull {pull_mode} gpio {gpio} is not {rand_values[gpio]}") + else: + cocotb.log.debug(f"[TEST][test_mgmt_in_pull] pull {pull_mode} gpio {gpio} is {rand_values[gpio]}") + else: + val = self.get_bit_from_reg(gpio_high_reg, gpio-32) + if val != rand_val: + cocotb.log.error(f"[TEST][test_mgmt_in_pull] pull {pull_mode} gpio {gpio} is not {rand_val} drived by {rand_values[gpio]}") + else: + cocotb.log.debug(f"[TEST][test_mgmt_in_pull] pull {pull_mode} gpio {gpio} is {rand_val} drived by {rand_values[gpio]}") + cocotb.log.info("[TEST] done with test_mgmt_in_pull") + + def get_bit_from_reg(self, reg, gpio): + return (reg & (1 << gpio)) >> gpio diff --git a/verilog/dv/cocotb/all_tests/common/bitbang.py b/verilog/dv/cocotb/all_tests/common/bitbang.py new file mode 100644 index 000000000..a4ff7f71e --- /dev/null +++ b/verilog/dv/cocotb/all_tests/common/bitbang.py @@ -0,0 +1,107 @@ + +""" +reg_mprj_xfer contain +bit 0 : busy +bit 1 : bitbang enable +bit 2 : bitbang reset active low +bit 3 : bitbang load registers +bit 4 : bitbang clock +bit 5 : serial data 1 +bit 6 : serial data 2 +""" + +reg_mprj_xfer = 0x13 + + +async def bb_clock11_spi(spi_master): + await spi_master.write_reg_spi(address=reg_mprj_xfer, data=0x66) + await spi_master.write_reg_spi(address=reg_mprj_xfer, data=0x76) + + +async def bb_clock00_spi(spi_master): + await spi_master.write_reg_spi(address=reg_mprj_xfer, data=0x06) + await spi_master.write_reg_spi(address=reg_mprj_xfer, data=0x16) + + +async def bb_clock01_spi(spi_master): + await spi_master.write_reg_spi(address=reg_mprj_xfer, data=0x26) + await spi_master.write_reg_spi(address=reg_mprj_xfer, data=0x36) + + +async def bb_clock10_spi(spi_master): + await spi_master.write_reg_spi(address=reg_mprj_xfer, data=0x46) + await spi_master.write_reg_spi(address=reg_mprj_xfer, data=0x56) + + +async def bb_load_spi(spi_master): + await spi_master.write_reg_spi(address=reg_mprj_xfer, data=0x0E) + # await spi_master.write_reg_spi(address=reg_mprj_xfer, data=0x06) + +async def bb_reset_spi(spi_master): + await spi_master.write_reg_spi(address=reg_mprj_xfer, data=0x04) + await spi_master.write_reg_spi(address=reg_mprj_xfer, data=0x06) + +# configure the GPIO in the left chain with configL and the GPIO in +# the right chain with configR +# left | right +# 18 & 19 +# 17 & 20 +# 16 & 21 +# 15 & 22 +# 14 & 23 +# 13 & 24 +# 12 & 25 +# 11 & 26 +# 10 & 27 +# 9 & 28 +# 8 & 29 +# 7 & 30 +# 6 & 31 +# 5 & 32 +# 4 & 33 +# 3 & 34 +# 2 & 35 +# 1 & 36 +# 0 & 37 +async def bb_configure_2_gpios_spi(configL, configR, spi_master): + num_bits = 13 + mask = 0x1 << num_bits - 1 + for i in reversed(range(num_bits)): + left = (configL & mask) >> i + right = (configR & mask) >> i + mask = mask >> 1 + if left: + if right: + await bb_clock11_spi(spi_master) + else: + await bb_clock10_spi(spi_master) + + else: + if right: + await bb_clock01_spi(spi_master) + else: + await bb_clock00_spi(spi_master) + + +async def bb_configure_all_gpios(config, spi_master): + await bb_reset_spi(spi_master) + await bb_configure_2_gpios_spi(config, config, spi_master) # 18 & 19 + await bb_configure_2_gpios_spi(config, config, spi_master) # 17 & 20 + await bb_configure_2_gpios_spi(config, config, spi_master) # 16 & 21 + await bb_configure_2_gpios_spi(config, config, spi_master) # 15 & 22 + await bb_configure_2_gpios_spi(config, config, spi_master) # 14 & 23 + await bb_configure_2_gpios_spi(config, config, spi_master) # 13 & 24 + await bb_configure_2_gpios_spi(config, config, spi_master) # 12 & 25 + await bb_configure_2_gpios_spi(config, config, spi_master) # 11 & 26 + await bb_configure_2_gpios_spi(config, config, spi_master) # 10 & 27 + await bb_configure_2_gpios_spi(config, config, spi_master) # 9 & 28 + await bb_configure_2_gpios_spi(config, config, spi_master) # 8 & 29 + await bb_configure_2_gpios_spi(config, config, spi_master) # 7 & 30 + await bb_configure_2_gpios_spi(config, config, spi_master) # 6 & 31 + await bb_configure_2_gpios_spi(config, config, spi_master) # 5 & 32 + await bb_configure_2_gpios_spi(config, config, spi_master) # 4 & 33 + await bb_configure_2_gpios_spi(config, config, spi_master) # 3 & 34 + await bb_configure_2_gpios_spi(config, config, spi_master) # 2 & 35 + await bb_configure_2_gpios_spi(config, config, spi_master) # 1 & 36 + await bb_configure_2_gpios_spi(config, config, spi_master) # 0 & 37 + await bb_load_spi(spi_master) diff --git a/verilog/dv/cocotb/all_tests/common/read_hex.py b/verilog/dv/cocotb/all_tests/common/read_hex.py new file mode 100644 index 000000000..1082c09fa --- /dev/null +++ b/verilog/dv/cocotb/all_tests/common/read_hex.py @@ -0,0 +1,28 @@ + + +class ReadHex(): + def __init__(self, file_name): + self.file_name = file_name + + def hex_to_list(self, hex_string): + hex_string = hex_string.replace("\n", " ").replace("@", "").strip() + hex_values = hex_string.split() + return [int(hex_value, 16) for hex_value in hex_values] + + def read_hex(self): + hex_dict = {} + with open(self.file_name, 'r') as file: + current_key = None + current_data = [] + + for line in file: + if line.startswith("@"): + if current_key is not None: + hex_dict[current_key] = self.hex_to_list(" ".join(current_data)) + current_key = int(line.strip().replace("@", ""), 16) + current_data = [] + else: + current_data.append(line.strip()) + if current_key is not None: + hex_dict[current_key] = self.hex_to_list(" ".join(current_data)) + return hex_dict diff --git a/verilog/dv/cocotb/all_tests/cpu/cpu_reset.c b/verilog/dv/cocotb/all_tests/cpu/cpu_reset.c new file mode 100644 index 000000000..5d0904afd --- /dev/null +++ b/verilog/dv/cocotb/all_tests/cpu/cpu_reset.c @@ -0,0 +1,16 @@ +#include + + + +void main() +{ + enable_debug(); + set_debug_reg1(0x0); + set_debug_reg1(0x1); + set_debug_reg1(0x2); + set_debug_reg1(0x3); + set_debug_reg1(0x4); + set_debug_reg1(0x5); + while(get_debug_reg2() == 0x0); + reg_hkspi_reset = 1; +} diff --git a/verilog/dv/cocotb/all_tests/cpu/cpu_reset.py b/verilog/dv/cocotb/all_tests/cpu/cpu_reset.py new file mode 100644 index 000000000..9d2c18ac9 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/cpu/cpu_reset.py @@ -0,0 +1,74 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from caravel_cocotb.caravel_interfaces import SPI +from user_design import configure_userdesign + + +@cocotb.test() +@report_test +async def cpu_reset(dut): + caravelEnv = await test_configure(dut, timeout_cycles=121372) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start cpu_reset test") + # wait for CPU to write 5 at debug_reg1 + while True: + if debug_regs.read_debug_reg1() == 5: + cocotb.log.info("[TEST] debug reg 1 = 5") + break + await ClockCycles(caravelEnv.clk, 1) + + # put the cpu under reset using spi + cocotb.log.info("[TEST] asserting cpu reset register using SPI") + await spi_master.write_reg_spi(0xB, 1) + + await ClockCycles(caravelEnv.clk, 1000) + if debug_regs.read_debug_reg1() == 0: + cocotb.log.info( + "[TEST] asserting cpu reset register using SPI successfully rest the cpu" + ) + else: + cocotb.log.error( + "[TEST] asserting cpu reset register using SPI successfully doesn't rest the cpu" + ) + + cocotb.log.info("[TEST] deasserting cpu reset register using SPI") + await spi_master.write_reg_spi(0xB, 0) + watchdog = 50000 + while True: + if debug_regs.read_debug_reg1() == 5: + cocotb.log.info( + "[TEST] deasserting cpu reset register using SPI wakes the cpu up" + ) + break + watchdog -= 1 + if watchdog < 0: + cocotb.log.error( + "[TEST] deasserting cpu reset register using SPI doesn't wake the cpu up" + ) + break + + await ClockCycles(caravelEnv.clk, 1) + + cocotb.log.info("[TEST] asserting cpu reset register using firmware") + debug_regs.write_debug_reg2_backdoor(0xAA) + await ClockCycles(caravelEnv.clk, 10000) + + watchdog = 8000 + while True: + if debug_regs.read_debug_reg1() == 0: + cocotb.log.info( + "[TEST] asserting cpu reset register using firmware successfully rest the cpu" + ) + break + watchdog -= 1 + if watchdog < 0: + cocotb.log.error( + "[TEST] asserting cpu reset register using firmware successfully doesn't rest the cpu" + ) + break + + await ClockCycles(caravelEnv.clk, 100) diff --git a/verilog/dv/cocotb/all_tests/cpu/cpu_stress.c b/verilog/dv/cocotb/all_tests/cpu/cpu_stress.c new file mode 100644 index 000000000..375417df6 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/cpu/cpu_stress.c @@ -0,0 +1,157 @@ +#include + + + +int A[]={1, 40, 2, 5, 22, 11, 90, 200, 10, 20, 25}; + +// int factorial(int n) { +// int fac=1; +// for(int i=1; i<=n;++i){ +// fac = fac * i; +// } +// return fac; +// } + +int fibbonacci(int n) { + if(n == 0){ + return 0; + } else if(n == 1) { + return 1; + } else { + return (fibbonacci(n-1) + fibbonacci(n-2)); + } +} + +void recursiveInsertionSort(int arr[], int n){ + if (n <= 1) + return; + recursiveInsertionSort( arr, n-1 ); + int nth = arr[n-1]; + int j = n-2; + while (j >= 0 && arr[j] > nth){ + arr[j+1] = arr[j]; + j--; + } + arr[j+1] = nth; +} + + +void quick_sort(int number[],int first,int last){ + int i, j, pivot, temp; + + if(firstnumber[pivot]) + j--; + if(i 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) diff --git a/verilog/dv/cocotb/all_tests/debug/README.md b/verilog/dv/cocotb/all_tests/debug/README.md new file mode 100644 index 000000000..d6bf7006f --- /dev/null +++ b/verilog/dv/cocotb/all_tests/debug/README.md @@ -0,0 +1,48 @@ +## Introduction + +The UART Debug feature is a hardware-based design element in the System-on-Chip (SOC) that allows developers to access and manipulate registers within the SOC area without utilizing the firmware CPU. This feature proves to be incredibly valuable during debugging and testing phases of SOC development, as it offers a direct interface for interacting with various internal components. + +The UART Debug feature is enabled by asserting GPIO 0, and it employs GPIO 5 as the UART RX (Receiver) and GPIO 6 as the UART TX (Transmitter). By using a UART interface, developers can communicate with the SOC, read and write register values, and gain insights into the internal state of the SOC in real-time. + +## How to Enable UART Debug + +To enable the UART Debug feature, follow the steps below: + +2. Set GPIO 0 to a logic high (1) state. This assertion indicates that the UART Debug feature is active and ready for use. +3. Write 1 to housekeeping register debug mode + +## UART Configuration + +The UART Debug feature uses GPIO 5 as the UART RX (Receiver) and GPIO 6 as the UART TX (Transmitter). The UART communication parameters are as follows: + +- Baud Rate: 115200 +- Data Bits: 8 bits +- Parity: None +- Stop Bits: 1 + +Ensure that your communication terminal or software is configured to match these settings to successfully establish a connection with the SOC. + +## Register Access Commands + +Once UART Debug is enabled, you can access various registers inside the SOC area using specific commands. The command structure for register access is as follows: + +[Read/Write command][size][Register Address][Data (if Write operation)] + +- **Read/Write command**: Use '0x40 to read from the register and 0x80 to write to the register. +- **size** : use 0x80 for reading/writing 1 address +- **Register Address**: the normal address of register logically shifted right by 2 (address >> 2). +- **Data (if Write operation)**: If performing a write operation, provide the data to be written to the register in hexadecimal format. + +## Examples + +1. **Reading from a Register**: + +To read the contents of a register with the address 0x1234, send the following command via UART: +0x40 0x80 0x48D +The SOC will respond with the contents of the register at address 0x1234. + +2. **Writing to a Register**: + +To write the value 0xAB to a register with the address 0x5678, send the following command via UART: +0x80 0x80 0x159E 0xAB +The SOC will process the write operation, updating the register at address 0x5678 with the value 0xAB. diff --git a/verilog/dv/cocotb/all_tests/debug/debug.c b/verilog/dv/cocotb/all_tests/debug/debug.c new file mode 100644 index 000000000..cd18da729 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/debug/debug.c @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ +#include + + + + +// -------------------------------------------------------- + +void main() +{ + + enable_debug(); + GPIOs_configure(6,GPIO_MODE_MGMT_STD_OUTPUT); + GPIOs_configure(5,GPIO_MODE_MGMT_STD_INPUT_NOPULL); + GPIOs_configure(0,GPIO_MODE_MGMT_STD_INPUT_NOPULL); + GPIOs_loadConfigs(); + #ifndef ARM + + (*(volatile uint32_t*) CSR_DEBUG_MODE_OUT_ADDR ) = 1; // enable debug mode + #endif + + // start of the test + set_debug_reg1(0xAA); + + // very long wait + dummyDelay(1500); + + +} diff --git a/verilog/dv/cocotb/all_tests/debug/debug.py b/verilog/dv/cocotb/all_tests/debug/debug.py new file mode 100644 index 000000000..03520e8a8 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/debug/debug.py @@ -0,0 +1,113 @@ +import random +import cocotb +from cocotb.triggers import Timer +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from user_design import configure_userdesign + +bit_time_ns = 0 + + +@cocotb.test() +@report_test +async def debug(dut): + caravelEnv = await test_configure(dut, timeout_cycles=81933) + debug_regs = await configure_userdesign(caravelEnv) + # calculate bit time + clock = caravelEnv.get_clock_obj() + clk = clock.period / 1000 + global bit_time_ns + bit_time_ns = round(10**5 * clk / (1152)) + cocotb.log.info(f"[TEST] bit time in nano second = {bit_time_ns}") + caravelEnv.drive_gpio_in( + (0, 0), 1 + ) # IO[0] affects the uart selecting btw system and debug + caravelEnv.drive_gpio_in((5, 5), 1) + # wait for start of sending + await debug_regs.wait_reg1(0xAA) + # caravelEnv.drive_gpio_in((0,0),1) # IO[0] affects the uart selecting btw system and debug + cocotb.log.info("[TEST] Start debug test") + # send random data to address 30'h00400024 and expect to recieve the same data back it back + dff_address = random.randint(0x00000400, 0x00000600) & 0xFFFFFFFC + data = random.getrandbits(32) + address = dff_address >> 2 # address has to be shifted + # data = 0xFFFFFFF0 + cocotb.log.info( + f"[TEST] Executing DFF2 write address={hex(dff_address)} data = {hex(data)}" + ) + await wb_write(caravelEnv, address, data) + receieved_data = await wb_read(caravelEnv, address) + if data != receieved_data: + cocotb.log.error( + f"[TEST] DFF2 reading failed from address {hex(address)} expected data = {hex(data)} recieved data = {hex(receieved_data)}" + ) + else: + cocotb.log.info( + f"[TEST] PASS: DFF2 reading right value {hex(data)} from {hex(address)} " + ) + + +async def start_of_tx(caravelEnv): + while True: # wait for the start of the transimission it 1 then 0 + if caravelEnv.monitor_gpio((6, 6)).integer == 0: + break + await Timer(bit_time_ns, units="ns") + await Timer(bit_time_ns, units="ns") + + +async def uart_send_char(caravelEnv, char): + cocotb.log.info(f"[uart_send_char] start sending on uart {char}") + # send start bit + caravelEnv.drive_gpio_in((5, 5), 0) + await Timer(bit_time_ns, units="ns") + # send bits + for i in range(8): + caravelEnv.drive_gpio_in((5, 5), char[i]) + await Timer(bit_time_ns, units="ns") + + # stop of frame + caravelEnv.drive_gpio_in((5, 5), 1) + await Timer(bit_time_ns, units="ns") + + +async def uart_get_char(caravelEnv): + await start_of_tx(caravelEnv) + char = "" + for i in range(8): + char = caravelEnv.monitor_gpio((6, 6)).binstr + char + await Timer(bit_time_ns, units="ns") + cocotb.log.info(f"[uart_get_char] recieving {char} from uart") + + return char + + +async def wb_write(caravelEnv, addr, data): + addr_bits = bin(addr)[2:].zfill(32)[::-1] + data_bits = bin(data)[2:].zfill(32)[::-1] + cocotb.log.debug(f"[TEST] address bits = {addr_bits} {type(addr_bits)}") + await uart_send_char(caravelEnv, "10000000") # write cmd + await uart_send_char(caravelEnv, "10000000") # size + await uart_send_char(caravelEnv, addr_bits[24:32]) + await uart_send_char(caravelEnv, addr_bits[16:24]) + await uart_send_char(caravelEnv, addr_bits[8:16]) + await uart_send_char(caravelEnv, addr_bits[0:8]) + await uart_send_char(caravelEnv, data_bits[24:32]) + await uart_send_char(caravelEnv, data_bits[16:24]) + await uart_send_char(caravelEnv, data_bits[8:16]) + await uart_send_char(caravelEnv, data_bits[0:8]) + + +async def wb_read(caravelEnv, addr): + addr_bits = bin(addr)[2:].zfill(32)[::-1] + await uart_send_char(caravelEnv, "01000000") # read cmd + await uart_send_char(caravelEnv, "10000000") # size + await uart_send_char(caravelEnv, addr_bits[24:32]) + await uart_send_char(caravelEnv, addr_bits[16:24]) + await uart_send_char(caravelEnv, addr_bits[8:16]) + await uart_send_char(caravelEnv, addr_bits[0:8]) + data_bits = await uart_get_char(caravelEnv) + data_bits += await uart_get_char(caravelEnv) + data_bits += await uart_get_char(caravelEnv) + data_bits += await uart_get_char(caravelEnv) + return int(data_bits, 2) diff --git a/verilog/dv/cocotb/all_tests/debug/debug_swd.c b/verilog/dv/cocotb/all_tests/debug/debug_swd.c new file mode 100644 index 000000000..d5cfe87cb --- /dev/null +++ b/verilog/dv/cocotb/all_tests/debug/debug_swd.c @@ -0,0 +1,20 @@ + + +#include + + + + +// -------------------------------------------------------- + +void main() +{ + + enable_debug(); + mgmt_debug_enable(); + set_debug_reg1(0xAA); + // very long wait + dummyDelay(150000000); + + +} diff --git a/verilog/dv/cocotb/all_tests/debug/debug_swd.py b/verilog/dv/cocotb/all_tests/debug/debug_swd.py new file mode 100644 index 000000000..5dfe0c2fa --- /dev/null +++ b/verilog/dv/cocotb/all_tests/debug/debug_swd.py @@ -0,0 +1,116 @@ +import random +import cocotb +from cocotb.triggers import FallingEdge, RisingEdge, ClockCycles, Timer +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from collections import namedtuple +from cocotb.handle import Force +from cocotb.clock import Clock +from user_design import configure_userdesign + + +bit_time_ns = 0 + +Operation = namedtuple( + "Operation", ["start", "APnDP", "RnW", "A2", "A3", "parity", "stop", "park"] +) +ACK = {int("100", 2): "OK", int("010", 2): "WAIT", int("001", 2): "FAULT"} + + +@cocotb.test() +@report_test +async def debug_swd(dut): + dut._id(f"gpio{35}", False).value = 0 + dut._id(f"gpio{35}_en", False).value = Force(1) + caravelEnv = await test_configure(dut, timeout_cycles=1131011) + debug_regs = await configure_userdesign(caravelEnv) + caravelEnv.drive_gpio_in(0, 1) + caravelEnv.drive_gpio_in(35, 0) + + await debug_regs.wait_reg1(0xAA) + swd = SWD_vip(caravelEnv, 100) + op = Operation(1, 0, 1, 0, 0, 1, 0, 1) # read ID + await swd.reset_swd() + await swd.write_op(op) + await swd.turnaround() + ack = await swd.read_ack() + if ack == "OK": + response = await swd.read_response() + if response != 0xBB11477: + cocotb.log.error("returned wrong ID ") + else: + cocotb.log.info("returned right ID ") + else: + cocotb.log.error("returned unexpected ack value") + + +class SWD_vip: + def __init__(self, caravelEnv, period): + self.caravelEnv = caravelEnv + self.setup_clock(period) + + def setup_clock(self, period): + self.drive_dio(1) + self.clk = self.caravelEnv.dut._id("gpio35", False) + self.caravelEnv.dut._id("gpio35_en", False).value = 1 + clock = Clock(self.clk, period, units="ns") + cocotb.start_soon(clock.start()) # Start the clock + cocotb.log.info(f"[SWD_vip] setup clock for swd with period {period}") + return clock + + def drive_dio(self, data): + cocotb.log.info(f"[SWD_vip] drive dio with {data}") + self.caravelEnv.drive_gpio_in(0, data) + + def release_dio(self): + cocotb.log.info("[SWD_vip] release dio") + self.caravelEnv.release_gpio(0) + + def monitor_dio(self): + val = self.caravelEnv.monitor_gpio((0, 0)) + cocotb.log.info(f"[SWD_vip] Monitor dio val = {val}") + return f"{val}" + + # for reset do has to be asserted for at least 50 cycles + async def reset_swd(self): + cocotb.log.info("[SWD_vip] reset swd") + self.drive_dio(1) + await ClockCycles(self.clk, random.randint(50, 100)) + self.drive_dio(0) + await ClockCycles(self.clk, 2) + # self.release_dio() + + # turn around is a number of idele clock cycles between changing the do io for input to output or vice versa + # depends on the design but here it's only 1 + async def turnaround(self): + cocotb.log.info("[SWD_vip] turnaround swd") + await Timer(8, "ns") + self.release_dio() + await ClockCycles(self.clk, 1) + + async def write_op(self, op): + cocotb.log.info(f"[SWD_vip] write op : {op}") + for i in range(8): + await FallingEdge(self.clk) + self.drive_dio(op[i]) + await RisingEdge(self.clk) + + async def read_ack(self): + cocotb.log.info("[SWD_vip] start reading ACK ") + ack = "" + for i in range(3): + await RisingEdge(self.clk) + ack += self.monitor_dio() + cocotb.log.info("[SWD_vip] returned ack = {ack} = {ACK[int(ack,2)]} ") + return ACK[int(ack, 2)] + + async def read_response(self): + cocotb.log.info("[SWD_vip] start reading response ") + data = "" + for i in range(32): + await RisingEdge(self.clk) + data += self.monitor_dio() + data = int(data[::-1], 2) + cocotb.log.info(f"[SWD_vip] returned response = {data}({hex(data)})") + return data diff --git a/verilog/dv/cocotb/all_tests/flash_clk/flash_clk.c b/verilog/dv/cocotb/all_tests/flash_clk/flash_clk.c new file mode 100644 index 000000000..53b22dd2a --- /dev/null +++ b/verilog/dv/cocotb/all_tests/flash_clk/flash_clk.c @@ -0,0 +1,155 @@ +#include + +int A[]={1, 40, 2, 5, 22, 11, 90, 200, 10, 20, 25}; + +// int factorial(int n) { +// int fac=1; +// for(int i=1; i<=n;++i){ +// fac = fac * i; +// } +// return fac; +// } + +int fibbonacci(int n) { + if(n == 0){ + return 0; + } else if(n == 1) { + return 1; + } else { + return (fibbonacci(n-1) + fibbonacci(n-2)); + } +} + +void recursiveInsertionSort(int arr[], int n){ + if (n <= 1) + return; + recursiveInsertionSort( arr, n-1 ); + int nth = arr[n-1]; + int j = n-2; + while (j >= 0 && arr[j] > nth){ + arr[j+1] = arr[j]; + j--; + } + arr[j+1] = nth; +} + + +void quick_sort(int number[],int first,int last){ + int i, j, pivot, temp; + + if(firstnumber[pivot]) + j--; + if(i + +void main(){ + unsigned int i,i_temp, j, active_gpio_num,num_high_gpio; + enable_debug(); + enableHkSpi(0); + GPIOs_configureAll(GPIO_MODE_USER_STD_BIDIRECTIONAL); + GPIOs_loadConfigs(); + set_debug_reg1(0x1A); // finish configuration + + // // try as output + // output_enable_all_gpio_user(1); + // active_gpio_num = get_active_gpios_num(); + // num_high_gpio = (active_gpio_num - 32); + // i = 0x1 << num_high_gpio; + // i_temp = i; + // for (j = 0; j < num_high_gpio; j++) { + // set_gpio_user_h(i); + // set_debug_reg2(active_gpio_num-j); + // wait_debug_reg1(0xD1); // wait until wait until test read 1 + // set_gpio_user_h(0x0); + // set_debug_reg2(0); + // wait_debug_reg1(0xD0);// wait until test read 0 + // i >>=1; + // i |= i_temp; + // } + // i = 0x80000000; + // for (j = 0; j < 32; j++) { + // set_gpio_user_h(0x3f); + // set_gpio_user_l(i); + // set_debug_reg2(32-j); + // wait_debug_reg1(0xD1); // wait until test read 1 + // set_gpio_user_h(0x00); + // set_gpio_user_l(0x0); + // set_debug_reg2(0); + // wait_debug_reg1(0xD0);// wait until test read 0 + // i >>=1; + // i |= 0x80000000; + // } + // // try as input + // output_enable_all_gpio_user(0); + // // low + // wait_over_input_l(0xAA,0xFFFFFFFF); + // wait_over_input_l(0XBB,0xAAAAAAAA); + // wait_over_input_l(0XCC,0x55555555); + // wait_over_input_l(0XDD,0x0); + // // high + // wait_over_input_h(0XD1,0x3F); + // wait_over_input_h(0XD2,0x0); + // wait_over_input_h(0XD3,0x15); + // wait_over_input_h(0XD4,0x2A); + // set_debug_reg2(0xFF); +} + + +void wait_over_input_l(unsigned int start_code, unsigned int exp_val){ + set_debug_reg1(start_code); // configuration done wait environment to send exp_val to reg_mprj_datal + wait_gpio_user_l(exp_val); + set_debug_reg2(get_gpio_user_l()); + +} +void wait_over_input_h(unsigned int start_code, unsigned int exp_val){ + set_debug_reg1(start_code); + wait_gpio_user_h(exp_val); + set_debug_reg2(get_gpio_user_h()); +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/gpio/gpio_all_i.c b/verilog/dv/cocotb/all_tests/gpio/gpio_all_i.c new file mode 100644 index 000000000..8bf216d2f --- /dev/null +++ b/verilog/dv/cocotb/all_tests/gpio/gpio_all_i.c @@ -0,0 +1,37 @@ +#include + +void main(){ + enable_debug(); + enableHkSpi(0); + GPIOs_configureAll(GPIO_MODE_MGMT_STD_INPUT_NOPULL); + GPIOs_loadConfigs(); + // low + wait_over_input_l(0xAA,0xFFFFFFFF); + wait_over_input_l(0XBB,0xAAAAAAAA); + wait_over_input_l(0XCC,0x55555555); + wait_over_input_l(0XDD,0x0); + // high + wait_over_input_h(0XD1,0x3F); + wait_over_input_h(0XD2,0x0); + wait_over_input_h(0XD3,0x15); + wait_over_input_h(0XD4,0x2A); + + // trying to inject error by sending data to gpio by firmware where gpios configured as input + set_debug_reg1(0XD5); + set_debug_reg1(0XD5); // for delay insertion for release + GPIOs_writeLow(0x5AE1FFB8); // random number + GPIOs_writeHigh(0x1E); // random number + set_debug_reg2(0xFF); +} + +void wait_over_input_l(unsigned int start_code, unsigned int exp_val){ + set_debug_reg1(start_code); // configuration done wait environment to send exp_val to reg_mprj_datal + GPIOs_waitLow(exp_val); + set_debug_reg2(GPIOs_readLow()); + +} +void wait_over_input_h(unsigned int start_code, unsigned int exp_val){ + set_debug_reg1(start_code); + GPIOs_waitHigh(exp_val); + set_debug_reg2(GPIOs_readHigh()); +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pd.c b/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pd.c new file mode 100644 index 000000000..ee5f7bdcc --- /dev/null +++ b/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pd.c @@ -0,0 +1,13 @@ +#include + + +void main(){ + enable_debug(); + enableHkSpi(0); + GPIOs_configureAll(GPIO_MODE_MGMT_STD_INPUT_PULLDOWN); + GPIOs_loadConfigs(); + set_debug_reg1(0xAA); // finish configuration + //print("adding a very very long delay because cpu produces X's when code finish and this break the simulation"); + for(int i=0; i<100000000; i++); + while (1); +} diff --git a/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pd_user.c b/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pd_user.c new file mode 100644 index 000000000..4f75144bd --- /dev/null +++ b/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pd_user.c @@ -0,0 +1,16 @@ +#include + + + +void main(){ + enable_debug(); + enableHkSpi(0); + // output_enable_all_gpio_user(1); + GPIOs_configureAll(GPIO_MODE_USER_STD_INPUT_PULLDOWN); + GPIOs_loadConfigs(); + set_debug_reg1(0xAA); // finish configuration + //print("adding a very very long delay because cpu produces X's when code finish and this break the simulation"); + for(int i=0; i<100000000; i++); + + while (1); +} diff --git a/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pu.c b/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pu.c new file mode 100644 index 000000000..4956ac83d --- /dev/null +++ b/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pu.c @@ -0,0 +1,14 @@ +#include + + + +void main(){ + enable_debug(); + enableHkSpi(0);; + GPIOs_configureAll(GPIO_MODE_MGMT_STD_INPUT_PULLUP); + GPIOs_loadConfigs(); + set_debug_reg1(0xAA); // finish configuration + //print("adding a very very long delay because cpu produces X's when code finish and this break the simulation"); + for(int i=0; i<100000000; i++); + while (1); +} diff --git a/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pu_user.c b/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pu_user.c new file mode 100644 index 000000000..a042299a3 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_pu_user.c @@ -0,0 +1,18 @@ +#include + + + +void main(){ + enable_debug(); + enableHkSpi(0); + // output_enable_all_gpio_user(1); + // set_gpio_user_l(0xFFFFFFFF); + // set_gpio_user_h(0x3F); + GPIOs_configureAll(GPIO_MODE_USER_STD_INPUT_PULLUP); + GPIOs_loadConfigs(); + set_debug_reg1(0xAA); // finish configuration + //print("adding a very very long delay because cpu produces X's when code finish and this break the simulation"); + for(int i=0; i<100000000; i++); + + while (1); +} diff --git a/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_user.c b/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_user.c new file mode 100644 index 000000000..13bd097b3 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/gpio/gpio_all_i_user.c @@ -0,0 +1,42 @@ +#include + + + +void main(){ + enable_debug(); + enableHkSpi(0); + GPIOs_configureAll(GPIO_MODE_USER_STD_INPUT_NOPULL); + GPIOs_loadConfigs(); + set_debug_reg2(0x77); + + // output_enable_all_gpio_user(0); + // // low + // wait_over_input_l(0xAA,0xFFFFFFFF); + // wait_over_input_l(0XBB,0xAAAAAAAA); + // wait_over_input_l(0XCC,0x55555555); + // wait_over_input_l(0XDD,0x0); + // // high + // wait_over_input_h(0XD1,0x3F); + // wait_over_input_h(0XD2,0x00); + // wait_over_input_h(0XD3,0x15); + // wait_over_input_h(0XD4,0x2A); + + // // trying to inject error by sending data to gpio by firmware where gpios configured as input + // set_debug_reg1(0XD5); + // set_debug_reg1(0XD5); // for delay insertion for release + // GPIOs_writeLow(0x5AE1FFB8); // random number + // GPIOs_writeHigh(0x1E); // random number + // set_debug_reg2(0xFF); +} + +void wait_over_input_l(unsigned int start_code, unsigned int exp_val){ + set_debug_reg1(start_code); // configuration done wait environment to send exp_val to reg_mprj_datal + wait_gpio_user_l(exp_val); + set_debug_reg2(get_gpio_user_l()); + +} +void wait_over_input_h(unsigned int start_code, unsigned int exp_val){ + set_debug_reg1(start_code); + wait_gpio_user_h(exp_val); + set_debug_reg2(get_gpio_user_h()); +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/gpio/gpio_all_o.c b/verilog/dv/cocotb/all_tests/gpio/gpio_all_o.c new file mode 100644 index 000000000..61c4517d7 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/gpio/gpio_all_o.c @@ -0,0 +1,41 @@ +#include + + +void main(){ + unsigned int i,i_temp, j, active_gpio_num,num_high_gpio; + enable_debug(); + enableHkSpi(0); + GPIOs_configureAll(GPIO_MODE_MGMT_STD_OUTPUT); + GPIOs_loadConfigs(); + set_debug_reg1(0xAA); // finish configuration + GPIOs_writeLow(0x0); + GPIOs_writeHigh(0x0); + active_gpio_num = get_active_gpios_num(); + num_high_gpio = (active_gpio_num - 32); + i = 0x1 << num_high_gpio; + i_temp = i; + for (j = 0; j <= num_high_gpio; j++) { + GPIOs_writeHigh(i); + set_debug_reg2(active_gpio_num+1-j); + wait_debug_reg1(0xD1); // wait until wait until test read 1 + GPIOs_writeHigh(0x0); + set_debug_reg2(0); + wait_debug_reg1(0xD0);// wait until test read 0 + i >>=1; + i |= i_temp; + } + i = 0x80000000; + for (j = 0; j < 32; j++) { + GPIOs_writeHigh(0x3f); + GPIOs_writeLow(i); + set_debug_reg2(32-j); + wait_debug_reg1(0xD1); // wait until test read 1 + GPIOs_writeHigh(0x00); + GPIOs_writeLow(0x0); + set_debug_reg2(0); + wait_debug_reg1(0xD0);// wait until test read 0 + i >>=1; + i |= 0x80000000; + } + set_debug_reg1(0XFF); // configuration done wait environment to send 0xFFA88C5A to reg_mprj_datal +} diff --git a/verilog/dv/cocotb/all_tests/gpio/gpio_all_o_user.c b/verilog/dv/cocotb/all_tests/gpio/gpio_all_o_user.c new file mode 100644 index 000000000..f35104e34 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/gpio/gpio_all_o_user.c @@ -0,0 +1,44 @@ +#include + + + +void main(){ + unsigned int i,i_temp, j, active_gpio_num,num_high_gpio; + enable_debug(); + enableHkSpi(0); + GPIOs_configureAll(GPIO_MODE_USER_STD_OUTPUT); + GPIOs_loadConfigs(); + set_debug_reg1(0xAA); // finish configuration + // output_enable_all_gpio_user(1); + // set_gpio_user_l(0x0); + // set_gpio_user_h(0x0); + // active_gpio_num = get_active_gpios_num(); + // num_high_gpio = (active_gpio_num - 32); + // i = 0x1 << num_high_gpio; + // i_temp = i; + // for (j = 0; j <= num_high_gpio; j++) { + // set_gpio_user_h(i); + // set_debug_reg2(active_gpio_num+1-j); + // wait_debug_reg1(0xD1); // wait until wait until test read 1 + // set_gpio_user_h(0x0); + // set_debug_reg2(0); + // wait_debug_reg1(0xD0);// wait until test read 0 + // i >>=1; + // i |= i_temp; + // } + // i = 0x80000000; + // for (j = 0; j < 32; j++) { + // set_gpio_user_h(0x3f); + // set_gpio_user_l(i); + // set_debug_reg2(32-j); + // wait_debug_reg1(0xD1); // wait until test read 1 + // set_gpio_user_h(0x00); + // set_gpio_user_l(0x0); + // set_debug_reg2(0); + // wait_debug_reg1(0xD0);// wait until test read 0 + // i >>=1; + // i |= 0x80000000; + // } + // set_debug_reg1(0XFF); // configuration done wait environment to send 0xFFA88C5A to reg_mprj_datal +} + diff --git a/verilog/dv/cocotb/all_tests/gpio/gpio_seq.py b/verilog/dv/cocotb/all_tests/gpio/gpio_seq.py new file mode 100644 index 000000000..fe3db07ea --- /dev/null +++ b/verilog/dv/cocotb/all_tests/gpio/gpio_seq.py @@ -0,0 +1,438 @@ +import cocotb +from cocotb.triggers import ClockCycles, NextTimeStep +import cocotb.log +from user_design import configure_userdesign + + +async def gpio_all_i_seq(dut, caravelEnv, debug_regs, after_config_callback=None): + active_gpios_num = caravelEnv.active_gpios_num-1 + caravelEnv.drive_gpio_in((active_gpios_num, 0), 0) + await debug_regs.wait_reg1(0xAA) + cocotb.log.info("[TEST] configuration finished") + if after_config_callback is not None: + await after_config_callback(caravelEnv, debug_regs) + data_in = 0xFFFFFFFF + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xBB) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0xAAAAAAAA + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xCC) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x55555555 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xDD) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x0 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xD1) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x3F + data_in = int(bin(data_in).replace("0b", "")[31 - active_gpios_num:], 2) + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[{active_gpios_num}:32]") + caravelEnv.drive_gpio_in((active_gpios_num, 32), data_in) + await debug_regs.wait_reg1(0xD2) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[{active_gpios_num}:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x0 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[{active_gpios_num}:32]") + caravelEnv.drive_gpio_in((active_gpios_num, 32), data_in) + await debug_regs.wait_reg1(0xD3) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[{active_gpios_num}:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x15 + data_in = int(bin(data_in).replace("0b", "")[31 - active_gpios_num:], 2) + + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[{active_gpios_num}:32]") + caravelEnv.drive_gpio_in((active_gpios_num, 32), data_in) + await debug_regs.wait_reg1(0xD4) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[{active_gpios_num}:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x2A + data_in = int(bin(data_in).replace("0b", "")[31 - active_gpios_num:], 2) + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[{active_gpios_num}:32]") + caravelEnv.drive_gpio_in((active_gpios_num, 32), data_in) + await debug_regs.wait_reg1(0xD5) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[{active_gpios_num}:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + return + caravelEnv.release_gpio((active_gpios_num, 0)) + await debug_regs.wait_reg2(0xFF) + if caravelEnv.monitor_gpio((active_gpios_num, 0)).binstr != "".join( + ["z" * (active_gpios_num + 1)] + ): + cocotb.log.error( + f"[TEST] ERROR: firmware can write to the gpios while they are configured as input_nopull gpio= {caravelEnv.monitor_gpio((active_gpios_num,0))}" + ) + else: + cocotb.log.info( + f"[TEST] [TEST] PASS: firmware cannot write to the gpios while they are configured as input_nopull gpio= {caravelEnv.monitor_gpio((active_gpios_num,0))}" + ) + cocotb.log.info("[TEST] finish") + + +async def gpio_all_o_seq(dut, caravelEnv, debug_regs, after_config_callback=None): + active_gpios_num = caravelEnv.active_gpios_num-1 + await debug_regs.wait_reg1(0xAA) + if after_config_callback is not None: + await after_config_callback(caravelEnv, debug_regs) + await caravelEnv.release_csb() + cocotb.log.info("[TEST] finish configuring output") + i = 0x1 << (active_gpios_num - 32) + i_temp = i + for j in range(active_gpios_num - 31): + await debug_regs.wait_reg2(active_gpios_num + 1 - j) + cocotb.log.info( + f"[Test] gpio out = {caravelEnv.monitor_gpio((active_gpios_num,0))} j = {j}" + ) + if caravelEnv.monitor_gpio((active_gpios_num, 0)).integer != i << 32: + cocotb.log.error( + f"[TEST] Wrong gpio high bits output {caravelEnv.monitor_gpio((active_gpios_num,0))} instead of {bin(i<<32)}" + ) + debug_regs.write_debug_reg1_backdoor(0xD1) # finsh reading 1 + await debug_regs.wait_reg2(0) + if caravelEnv.monitor_gpio((active_gpios_num, 0)).integer != 0: + cocotb.log.error( + f"[TEST] Wrong gpio output {caravelEnv.monitor_gpio((active_gpios_num,0))} instead of {bin(0x00000)}" + ) + debug_regs.write_debug_reg1_backdoor(0xD0) # finsh reading 0 + i = i >> 1 + i |= i_temp + + i = 0x80000000 + for j in range(32): + await debug_regs.wait_reg2(32 - j) + cocotb.log.info( + f"[Test] gpio out = {caravelEnv.monitor_gpio((active_gpios_num,0))} j = {j}" + ) + high_gpio_val = 0x3F + if "CPU_TYPE_ARM" in caravelEnv.design_macros._asdict(): + high_gpio_val = 0x7 # with ARM the last 3 gpios are not configurable + if caravelEnv.monitor_gpio((active_gpios_num, 32)).integer != high_gpio_val: + cocotb.log.error( + f"[TEST] Wrong gpio high bits output {caravelEnv.monitor_gpio((active_gpios_num,32))} instead of {bin(high_gpio_val)} " + ) + if caravelEnv.monitor_gpio((31, 0)).integer != i: + cocotb.log.error( + f"[TEST] Wrong gpio low bits output {caravelEnv.monitor_gpio((31,0))} instead of {bin(i)}" + ) + debug_regs.write_debug_reg1_backdoor(0xD1) # finsh reading 1 + await debug_regs.wait_reg2(0) + if caravelEnv.monitor_gpio((active_gpios_num, 0)).integer != 0: + cocotb.log.error( + f"Wrong gpio output {caravelEnv.monitor_gpio((active_gpios_num,0))} instead of {bin(0x00000)}" + ) + debug_regs.write_debug_reg1_backdoor(0xD0) # finsh reading 0 + i = i >> 1 + i |= 0x80000000 + + await debug_regs.wait_reg1(0xFF) + await ClockCycles(caravelEnv.clk, 10) + + +async def gpio_all_i_pd_seq(dut, caravelEnv, debug_regs): + active_gpios_num = caravelEnv.active_gpios_num-1 + await debug_regs.wait_reg1(0xAA) + await caravelEnv.release_csb() + # monitor the output of padframe module it suppose to be all ones when no input is applied + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and float" + ) + await ClockCycles(caravelEnv.clk, 100) + # drive gpios with zero + data_in = 0x0 + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and drived with 0" + ) + await ClockCycles(caravelEnv.clk, 100) + # drive gpios with ones + data_in = 0x3FFFFFFFFF + data_in = int(bin(data_in).replace("0b", "")[-active_gpios_num - 1:], 2) + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pulldown and drived with 1" + ) + await ClockCycles(caravelEnv.clk, 100) + # drive odd half gpios with zeros and float other half + data_in = 0x0 + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + for i in range(0, 38, 2): + caravelEnv.release_gpio(i) # release even gpios + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and drived with odd half with 0" + ) + + await ClockCycles(caravelEnv.clk, 100) + # drive even half gpios with zeros and float other half + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + for i in range(1, 38, 2): + caravelEnv.release_gpio(i) # release odd gpios + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and drived with even half with 0" + ) + await ClockCycles(caravelEnv.clk, 100) + # drive odd half gpios with ones and float other half + data_in = 0x3FFFFFFFFF + data_in = int(bin(data_in).replace("0b", "")[-active_gpios_num - 1:], 2) + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + for i in range(0, 38, 2): + caravelEnv.release_gpio(i) # release even gpios + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if i % 2 == 0: # even + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pulldown and drived with odd half with 1" + ) + else: + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and drived with odd half with 1" + ) + + await ClockCycles(caravelEnv.clk, 100) + # drive even half gpios with zeros and float other half + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + for i in range(1, 38, 2): + caravelEnv.release_gpio(i) # release odd gpios + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if i % 2 == 1: # odd + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pulldown and drived with odd half with 1" + ) + else: + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and drived with odd half with 1" + ) + + await ClockCycles(caravelEnv.clk, 100) + + # drive with ones then release all gpio + data_in = 0x3FFFFFFFFF + data_in = int(bin(data_in).replace("0b", "")[-active_gpios_num - 1:], 2) + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + await ClockCycles(caravelEnv.clk, 100) + caravelEnv.release_gpio((active_gpios_num, 0)) + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and all released" + ) + await ClockCycles(caravelEnv.clk, 100) + + +async def gpio_all_i_pu_seq(dut, caravelEnv, debug_regs): + active_gpios_num = caravelEnv.active_gpios_num-1 + await debug_regs.wait_reg1(0xAA) + await caravelEnv.release_csb() + # monitor the output of padframe module it suppose to be all ones when no input is applied + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {i} instead of 1 while configured as input pullup and float" + ) + await ClockCycles(caravelEnv.clk, 100) + # drive gpios with zero + data_in = 0x0 + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pullup and drived with 0" + ) + await ClockCycles(caravelEnv.clk, 100) + # drive gpios with ones + data_in = 0x3FFFFFFFFF + data_in = int(bin(data_in).replace("0b", "")[-active_gpios_num - 1:], 2) + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and drived with 1" + ) + await ClockCycles(caravelEnv.clk, 100) + # drive odd half gpios with zeros and float other half + data_in = 0x0 + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + for i in range(0, active_gpios_num + 1, 2): + caravelEnv.release_gpio(i) # release even gpios + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if i % 2 == 1: # odd + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and drived with odd half with 0" + ) + else: + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pullup and drived with odd half with 0" + ) + await ClockCycles(caravelEnv.clk, 100) + # drive even half gpios with zeros and float other half + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + for i in range(1, active_gpios_num + 1, 2): + caravelEnv.release_gpio(i) # release odd gpios + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if i % 2 == 1: # odd + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pullup and drived with even half with 0" + ) + else: + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and drived with even half with 0" + ) + await ClockCycles(caravelEnv.clk, 100) + # drive odd half gpios with ones and float other half + data_in = 0x3FFFFFFFFF + data_in = int(bin(data_in).replace("0b", "")[-active_gpios_num - 1:], 2) + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + for i in range(0, active_gpios_num + 1, 2): + caravelEnv.release_gpio(i) # release even gpios + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and drived with odd half with 1" + ) + + await ClockCycles(caravelEnv.clk, 100) + # drive even half gpios with zeros and float other half + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + for i in range(1, active_gpios_num + 1, 2): + caravelEnv.release_gpio(i) # release odd gpios + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and drived with even half with 1" + ) + + await ClockCycles(caravelEnv.clk, 100) + + # drive with zeros then release all gpio + data_in = 0x0 + caravelEnv.drive_gpio_in((active_gpios_num, 0), data_in) + await ClockCycles(caravelEnv.clk, 100) + caravelEnv.release_gpio((active_gpios_num, 0)) + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr[::-1] + cocotb.log.info(f"mprj value seen = {gpio}") + for i in range(active_gpios_num + 1): + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and all released" + ) + await ClockCycles(caravelEnv.clk, 100) diff --git a/verilog/dv/cocotb/all_tests/gpio/gpio_user.py b/verilog/dv/cocotb/all_tests/gpio/gpio_user.py new file mode 100644 index 000000000..5a8a016a1 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/gpio/gpio_user.py @@ -0,0 +1,293 @@ +import cocotb +from cocotb.triggers import ClockCycles, Edge +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from all_tests.gpio.gpio_seq import gpio_all_o_seq +from all_tests.gpio.gpio_seq import gpio_all_i_seq +from all_tests.gpio.gpio_seq import gpio_all_i_pu_seq +from all_tests.gpio.gpio_seq import gpio_all_i_pd_seq +from user_design import configure_userdesign + + +@cocotb.test() +@report_test +async def gpio_all_o_user(dut): + caravelEnv = await test_configure(dut, timeout_cycles=2010463) + debug_regs = await configure_userdesign(caravelEnv, gpio_test=gpio_all_o_vip) + await gpio_all_o_seq(dut, caravelEnv, debug_regs) + +async def gpio_all_o_vip(caravelEnv, debug_regs, IOs): + cocotb.log.debug("[gpio_all_o_vip] start gpio gpio_all_o_vip") + IOs["oeb"].value = 0 + IOs["out"].value = 0 + active_gpios_num = caravelEnv.active_gpios_num-1 + i = 0x2000000000 + await debug_regs.wait_reg1(0xAA) + for j in range(active_gpios_num + 1, 0, -1): + IOs["out"].value = i + await ClockCycles(caravelEnv.clk, 1) + debug_regs.write_debug_reg2_backdoor(j) + await debug_regs.wait_reg1(0xD1) # wait until wait until test read 1 + IOs["out"].value = 0 + await ClockCycles(caravelEnv.clk, 1) + debug_regs.write_debug_reg2_backdoor(0) + await debug_regs.wait_reg1(0xD0) # wait until wait until test read 0 + i >>= 1 + i |= 0x2000000000 + debug_regs.write_debug_reg1_backdoor(0xFF) + + + +@cocotb.test() +@report_test +async def gpio_all_i_user(dut): + caravelEnv = await test_configure(dut, timeout_cycles=287465) + debug_regs = await configure_userdesign(caravelEnv, gpio_test=gpio_all_i_vip) + await gpio_all_i_seq(dut, caravelEnv, debug_regs) + + +async def gpio_all_i_vip(caravelEnv, debug_regs, IOs): + cocotb.log.debug("[gpio_all_o_vip] start gpio gpio_all_i_vip") + IOs["oeb"].value = 1 + await debug_regs.wait_reg2(0x77) + await wait_over_input(0xAA, 0xFFFFFFFF, debug_regs, IOs["in"]) + await wait_over_input(0XBB, 0xAAAAAAAA, debug_regs, IOs["in"]) + await wait_over_input(0XCC, 0x55555555, debug_regs, IOs["in"]) + await wait_over_input(0XDD, 0x0, debug_regs, IOs["in"]) + #high + await wait_over_input(0XD1, 0x3F, debug_regs, IOs["in"], high=True) + await wait_over_input(0XD2, 0x00, debug_regs, IOs["in"], high=True) + await wait_over_input(0XD3, 0x15, debug_regs, IOs["in"], high=True) + await wait_over_input(0XD4, 0x2A, debug_regs, IOs["in"], high=True) + debug_regs.write_debug_reg1_backdoor(0xD5) + + +async def wait_over_input(start_code, exp_val, debug_regs, io_in, high=False): + debug_regs.write_debug_reg1_backdoor(start_code) + while True: + io_in_val = io_in.value.integer if not high else io_in.value.integer >> 32 + if io_in_val == exp_val: + break + await Edge(io_in) + debug_regs.write_debug_reg2_backdoor(io_in_val) + + + +@cocotb.test() +@report_test +async def gpio_all_i_pu_user(dut): + caravelEnv = await test_configure(dut, timeout_cycles=86252) + debug_regs = await configure_userdesign(caravelEnv, gpio_test=gpio_all_pu_vip) + await gpio_all_i_pu_seq(dut, caravelEnv, debug_regs) + + +async def gpio_all_pu_vip(caravelEnv, debug_regs, IOs): + cocotb.log.debug("[gpio_all_o_vip] start gpio_all_pu_vip") + IOs["oeb"].value = 0 + IOs["out"].value = 0x3FFFFFFFFF + + +@cocotb.test() +@report_test +async def gpio_all_i_pd_user(dut): + caravelEnv = await test_configure(dut, timeout_cycles=76198) + debug_regs = await configure_userdesign(caravelEnv, gpio_test=gpio_all_pd_vip) + await gpio_all_i_pd_seq(dut, caravelEnv, debug_regs) + + +async def gpio_all_pd_vip(caravelEnv, debug_regs, IOs): + cocotb.log.info("[gpio_all_o_vip] start gpio_all_pu_vip") + IOs["oeb"].value = 0 + IOs["out"].value = 0 + + +@cocotb.test() +@report_test +async def gpio_all_bidir_user(dut): + caravelEnv = await test_configure(dut, timeout_cycles=2259813) + active_gpios_num = caravelEnv.active_gpios_num -1 + debug_regs = await configure_userdesign(caravelEnv, gpio_test=gpio_all_bidir_vip) + await debug_regs.wait_reg1(0x1A) + await caravelEnv.release_csb() + cocotb.log.info("[TEST] finish configuring ") + i = 0x1 << (active_gpios_num - 32) + i_temp = i + for j in range(active_gpios_num - 31): + await debug_regs.wait_reg2(active_gpios_num + 1 - j) + cocotb.log.info( + f"[Test] gpio out = {caravelEnv.monitor_gpio((active_gpios_num,0))} j = {j}" + ) + if caravelEnv.monitor_gpio((active_gpios_num, 0)).integer != i << 32: + cocotb.log.error( + f"[TEST] Wrong gpio high bits output {caravelEnv.monitor_gpio((active_gpios_num,0))} instead of {bin(i<<32)}" + ) + debug_regs.write_debug_reg1_backdoor(0xD1) # finsh reading 1 + await debug_regs.wait_reg2(0) + if caravelEnv.monitor_gpio((active_gpios_num, 0)).integer != 0: + cocotb.log.error( + f"[TEST] Wrong gpio output {caravelEnv.monitor_gpio((active_gpios_num,0))} instead of {bin(0x00000)}" + ) + debug_regs.write_debug_reg1_backdoor(0xD0) # finsh reading 0 + i = i >> 1 + i |= i_temp + + i = 0x80000000 + for j in range(32): + await debug_regs.wait_reg2(32 - j) + cocotb.log.info( + f"[Test] gpio out = {caravelEnv.monitor_gpio((active_gpios_num,0))} j = {j}" + ) + high_gpio_val = 0x3F + if "CPU_TYPE_ARM" in caravelEnv.design_macros._asdict(): + high_gpio_val = 0x7 # with ARM the last 3 gpios are not configurable + if caravelEnv.monitor_gpio((active_gpios_num, 32)).integer != high_gpio_val: + cocotb.log.error( + f"[TEST] Wrong gpio high bits output {caravelEnv.monitor_gpio((active_gpios_num,32))} instead of {bin(high_gpio_val)} " + ) + if caravelEnv.monitor_gpio((31, 0)).integer != i: + cocotb.log.error( + f"[TEST] Wrong gpio low bits output {caravelEnv.monitor_gpio((31,0))} instead of {bin(i)}" + ) + debug_regs.write_debug_reg1_backdoor(0xD1) # finsh reading 1 + await debug_regs.wait_reg2(0) + if caravelEnv.monitor_gpio((active_gpios_num, 0)).integer != 0: + cocotb.log.error( + f"Wrong gpio output {caravelEnv.monitor_gpio((active_gpios_num,0))} instead of {bin(0x00000)}" + ) + debug_regs.write_debug_reg1_backdoor(0xD0) # finsh reading 0 + i = i >> 1 + i |= 0x80000000 + cocotb.log.info("[TEST] finish output") + # input + caravelEnv.release_gpio((active_gpios_num, 0)) + await ClockCycles(caravelEnv.clk, 1) + caravelEnv.drive_gpio_in((active_gpios_num, 0), 0) + await ClockCycles(caravelEnv.clk, 1) + await debug_regs.wait_reg1(0xAA) + data_in = 0xFFFFFFFF + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xBB) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0xAAAAAAAA + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xCC) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x55555555 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xDD) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x0 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xD1) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x3F + data_in = int(bin(data_in).replace("0b", "")[31 - active_gpios_num:], 2) + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[{active_gpios_num}:32]") + caravelEnv.drive_gpio_in((active_gpios_num, 32), data_in) + await debug_regs.wait_reg1(0xD2) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[{active_gpios_num}:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x0 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[{active_gpios_num}:32]") + caravelEnv.drive_gpio_in((active_gpios_num, 32), data_in) + await debug_regs.wait_reg1(0xD3) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[{active_gpios_num}:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x15 + data_in = int(bin(data_in).replace("0b", "")[31 - active_gpios_num:], 2) + + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[{active_gpios_num}:32]") + caravelEnv.drive_gpio_in((active_gpios_num, 32), data_in) + await debug_regs.wait_reg1(0xD4) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[{active_gpios_num}:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x2A + data_in = int(bin(data_in).replace("0b", "")[31 - active_gpios_num:], 2) + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[{active_gpios_num}:32]") + caravelEnv.drive_gpio_in((active_gpios_num, 32), data_in) + await debug_regs.wait_reg2(0xFF) + cocotb.log.info("[TEST] finish") + +async def gpio_all_bidir_vip(caravelEnv, debug_regs, IOs): + IOs["oeb"].value = 0 + IOs["out"].value = 0 + active_gpios_num = caravelEnv.active_gpios_num-1 + i = 0x2000000000 + await debug_regs.wait_reg1(0x1A) + for j in range(active_gpios_num + 1, 0, -1): + IOs["out"].value = i + await ClockCycles(caravelEnv.clk, 1) + debug_regs.write_debug_reg2_backdoor(j) + await debug_regs.wait_reg1(0xD1) # wait until wait until test read 1 + IOs["out"].value = 0 + await ClockCycles(caravelEnv.clk, 1) + debug_regs.write_debug_reg2_backdoor(0) + await debug_regs.wait_reg1(0xD0) # wait until wait until test read 0 + i >>= 1 + i |= 0x2000000000 + cocotb.log.info("[TEST] finish output vip") + IOs["oeb"].value = 0X3FFFFFFFFF + await ClockCycles(caravelEnv.clk, 10) + # input + await wait_over_input(0xAA, 0xFFFFFFFF, debug_regs, IOs["in"]) + await wait_over_input(0XBB, 0xAAAAAAAA, debug_regs, IOs["in"]) + await wait_over_input(0XCC, 0x55555555, debug_regs, IOs["in"]) + await wait_over_input(0XDD, 0x0, debug_regs, IOs["in"]) + # high + await wait_over_input(0XD1, 0x3F, debug_regs, IOs["in"], high=True) + await wait_over_input(0XD2, 0x00, debug_regs, IOs["in"], high=True) + await wait_over_input(0XD3, 0x15, debug_regs, IOs["in"], high=True) + await wait_over_input(0XD4, 0x2A, debug_regs, IOs["in"], high=True) + debug_regs.write_debug_reg2_backdoor(0xFF) + \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/gpio_caravan/gpio_user.py b/verilog/dv/cocotb/all_tests/gpio_caravan/gpio_user.py new file mode 100644 index 000000000..b2eb1df7f --- /dev/null +++ b/verilog/dv/cocotb/all_tests/gpio_caravan/gpio_user.py @@ -0,0 +1,578 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from user_design import configure_userdesign + + +@cocotb.test() +@report_test +async def gpio_all_o_user(dut): + caravelEnv = await test_configure(dut, timeout_cycles=1850952) + debug_regs = await configure_userdesign(caravelEnv) + await debug_regs.wait_reg1(0xAA) + await caravelEnv.release_csb() + cocotb.log.info("[TEST] finish configuring as user output") + i = 0x20 + for j in range(5): + await debug_regs.wait_reg2(37 - j) + cocotb.log.info(f"[Test] gpio out = {caravelEnv.monitor_gpio((37,0))} j = {j}") + if caravelEnv.monitor_gpio((37, 0)).integer != i << 32: + cocotb.log.error( + f"[TEST] Wrong gpio high bits output {caravelEnv.monitor_gpio((37,0))} instead of {bin(i<<32)}" + ) + await debug_regs.wait_reg2(0) + if caravelEnv.monitor_gpio((37, 0)).integer != 0: + cocotb.log.error( + f"[TEST] Wrong gpio output {caravelEnv.monitor_gpio((37,0))} instead of {bin(0x00000)}" + ) + i = i >> 1 + i |= 0x20 + + i = 0x80000000 + for j in range(32): + await debug_regs.wait_reg2(32 - j) + cocotb.log.info(f"[Test] gpio out = {caravelEnv.monitor_gpio((37,0))} j = {j}") + if caravelEnv.monitor_gpio((37, 32)).integer != 0x3F: + cocotb.log.error( + f"[TEST] Wrong gpio high bits output {caravelEnv.monitor_gpio((37,32))} instead of {bin(0x3f)} " + ) + if caravelEnv.monitor_gpio((31, 0)).integer != i: + cocotb.log.error( + f"[TEST] Wrong gpio low bits output {caravelEnv.monitor_gpio((31,0))} instead of {bin(i)}" + ) + await debug_regs.wait_reg2(0) + if caravelEnv.monitor_gpio((37, 0)).integer != 0: + cocotb.log.error( + f"Wrong gpio output {caravelEnv.monitor_gpio((37,0))} instead of {bin(0x00000)}" + ) + + i = i >> 1 + i |= 0x80000000 + + await debug_regs.wait_reg1(0xBB) + data_in = 0x8F66FD7B + cocotb.log.info(f"[TEST] try send {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + reg2 = 0 + await debug_regs.wait_reg1(0xFF) + try: + reg2 = debug_regs.read_debug_reg2() + if reg2 == data_in: + cocotb.log.error( + f"[TEST] Error: data {hex(data_in)} driven on gpio[31:0] is seen by firmware while gpios are configured as output" + ) + else: + cocotb.log.info( + f"[TEST] driven data {hex(data_in)} sent can't be sent to gpio[31:0] when it configure as output it can see {reg2}" + ) + except Exception: + cocotb.log.info( + f"[TEST] driven data {hex(data_in)} sent can't be sent to gpio[31:0] when it configure as output" + ) + return + + await ClockCycles(caravelEnv.clk, 10) + + +@cocotb.test() +@report_test +async def gpio_all_i_user(dut): + caravelEnv = await test_configure(dut, timeout_cycles=258608) + debug_regs = await configure_userdesign(caravelEnv) + await debug_regs.wait_reg1(0xAA) + cocotb.log.info("[TEST] configuration finished") + data_in = 0xFFFFFFFF + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xBB) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0xAAAAAAAA + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xCC) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x55555555 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xDD) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x0 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xD1) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x3F + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[37:32]") + caravelEnv.drive_gpio_in((37, 32), data_in) + await debug_regs.wait_reg1(0xD2) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[37:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x0 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[37:32]") + caravelEnv.drive_gpio_in((37, 32), data_in) + await debug_regs.wait_reg1(0xD3) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[37:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x15 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[37:32]") + caravelEnv.drive_gpio_in((37, 32), data_in) + await debug_regs.wait_reg1(0xD4) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[37:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x2A + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[37:32]") + caravelEnv.drive_gpio_in((37, 32), data_in) + await debug_regs.wait_reg1(0xD5) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[37:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + caravelEnv.release_gpio((37, 0)) + await debug_regs.wait_reg2(0xFF) + if ( + caravelEnv.monitor_gpio((37, 0)).binstr != "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + ): + cocotb.log.error( + f"[TEST] ERROR: firmware can write to the gpios while they are configured as input_nopull gpio= {caravelEnv.monitor_gpio((37,0))}" + ) + else: + cocotb.log.info( + f"[TEST] [TEST] PASS: firmware cannot write to the gpios while they are configured as input_nopull gpio= {caravelEnv.monitor_gpio((37,0))}" + ) + cocotb.log.info("[TEST] finish") + + +@cocotb.test() +@report_test +async def gpio_all_i_pu_user(dut): + caravelEnv = await test_configure(dut, timeout_cycles=75919, num_error=2000) + debug_regs = await configure_userdesign(caravelEnv) + await debug_regs.wait_reg1(0xAA) + await caravelEnv.release_csb() + # monitor the output of padframe module it suppose to be all ones when no input is applied + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and float" + ) + await ClockCycles(caravelEnv.clk, 1000) + # drive gpios with zero + data_in = 0x0 + caravelEnv.drive_gpio_in((37, 0), data_in) + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pullup and drived with 0" + ) + await ClockCycles(caravelEnv.clk, 1000) + # drive gpios with ones + data_in = 0x3FFFFFFFFF + caravelEnv.drive_gpio_in((37, 0), data_in) + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and drived with 1" + ) + await ClockCycles(caravelEnv.clk, 1000) + # drive odd half gpios with zeros and float other half + data_in = 0x0 + caravelEnv.drive_gpio_in((37, 0), data_in) + for i in range(0, 38, 2): + caravelEnv.release_gpio(i) # release even gpios + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if i % 2 == 1: # odd + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and drived with odd half with 0" + ) + else: + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pullup and drived with odd half with 0" + ) + await ClockCycles(caravelEnv.clk, 1000) + # drive even half gpios with zeros and float other half + caravelEnv.drive_gpio_in((37, 0), data_in) + for i in range(1, 38, 2): + caravelEnv.release_gpio(i) # release odd gpios + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if i % 2 == 1: # odd + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pullup and drived with even half with 0" + ) + else: + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and drived with even half with 0" + ) + await ClockCycles(caravelEnv.clk, 1000) + # drive odd half gpios with ones and float other half + data_in = 0x3FFFFFFFFF + caravelEnv.drive_gpio_in((37, 0), data_in) + for i in range(0, 38, 2): + caravelEnv.release_gpio(i) # release even gpios + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and drived with odd half with 1" + ) + + await ClockCycles(caravelEnv.clk, 1000) + # drive even half gpios with zeros and float other half + caravelEnv.drive_gpio_in((37, 0), data_in) + for i in range(1, 38, 2): + caravelEnv.release_gpio(i) # release odd gpios + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and drived with even half with 1" + ) + + await ClockCycles(caravelEnv.clk, 1000) + + # drive with zeros then release all gpio + data_in = 0x0 + caravelEnv.drive_gpio_in((37, 0), data_in) + await ClockCycles(caravelEnv.clk, 1000) + caravelEnv.release_gpio((37, 0)) + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pullup and all released" + ) + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def gpio_all_i_pd_user(dut): + caravelEnv = await test_configure(dut, timeout_cycles=1158961, num_error=2000) + debug_regs = await configure_userdesign(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + await debug_regs.wait_reg1(0xAA) + await caravelEnv.release_csb() + # monitor the output of padframe module it suppose to be all ones when no input is applied + await ClockCycles(caravelEnv.clk, 100) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and float" + ) + await ClockCycles(caravelEnv.clk, 1000) + # drive gpios with zero + data_in = 0x0 + caravelEnv.drive_gpio_in((37, 0), data_in) + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and drived with 0" + ) + await ClockCycles(caravelEnv.clk, 1000) + # drive gpios with ones + data_in = 0x3FFFFFFFFF + caravelEnv.drive_gpio_in((37, 0), data_in) + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pulldown and drived with 1" + ) + await ClockCycles(caravelEnv.clk, 1000) + # drive odd half gpios with zeros and float other half + data_in = 0x0 + caravelEnv.drive_gpio_in((37, 0), data_in) + for i in range(0, 38, 2): + caravelEnv.release_gpio(i) # release even gpios + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and drived with odd half with 0" + ) + + await ClockCycles(caravelEnv.clk, 1000) + # drive even half gpios with zeros and float other half + caravelEnv.drive_gpio_in((37, 0), data_in) + for i in range(1, 38, 2): + caravelEnv.release_gpio(i) # release odd gpios + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and drived with even half with 0" + ) + await ClockCycles(caravelEnv.clk, 1000) + # drive odd half gpios with ones and float other half + data_in = 0x3FFFFFFFFF + caravelEnv.drive_gpio_in((37, 0), data_in) + for i in range(0, 38, 2): + caravelEnv.release_gpio(i) # release even gpios + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if i % 2 == 0: # even + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pulldown and drived with odd half with 1" + ) + else: + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and drived with odd half with 1" + ) + + await ClockCycles(caravelEnv.clk, 1000) + # drive even half gpios with zeros and float other half + caravelEnv.drive_gpio_in((37, 0), data_in) + for i in range(1, 38, 2): + caravelEnv.release_gpio(i) # release odd gpios + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if i % 2 == 1: # odd + if gpio[i] != "1": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 1 while configured as input pulldown and drived with odd half with 1" + ) + else: + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and drived with odd half with 1" + ) + + await ClockCycles(caravelEnv.clk, 1000) + + # drive with ones then release all gpio + data_in = 0x3FFFFFFFFF + caravelEnv.drive_gpio_in((37, 0), data_in) + await ClockCycles(caravelEnv.clk, 1000) + caravelEnv.release_gpio((37, 0)) + await ClockCycles(caravelEnv.clk, 1000) + gpio = dut.uut.padframe.mprj_io_in.value.binstr + for i in range(38): + if gpio[i] != "0": + cocotb.log.error( + f"[TEST] gpio[{i}] is having wrong value {gpio[i]} instead of 0 while configured as input pulldown and all released" + ) + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def gpio_all_bidir_user(dut): + caravelEnv = await test_configure(dut, timeout_cycles=2001341) + debug_regs = await configure_userdesign(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + await debug_regs.wait_reg1(0x1A) + await caravelEnv.release_csb() + cocotb.log.info("[TEST] finish configuring ") + i = 0x20 + for j in range(5): + await debug_regs.wait_reg2(37 - j) + cocotb.log.info(f"[Test] gpio out = {caravelEnv.monitor_gpio((37,0))} j = {j}") + if caravelEnv.monitor_gpio((37, 0)).integer != i << 32: + cocotb.log.error( + f"[TEST] Wrong gpio high bits output {caravelEnv.monitor_gpio((37,0))} instead of {bin(i << 32)}" + ) + await debug_regs.wait_reg2(0) + if caravelEnv.monitor_gpio((37, 0)).integer != 0: + cocotb.log.error( + f"[TEST] Wrong gpio output {caravelEnv.monitor_gpio((37,0))} instead of {bin(0x00000)}" + ) + i = i >> 1 + i |= 0x20 + + i = 0x80000000 + for j in range(32): + await debug_regs.wait_reg2(32 - j) + cocotb.log.info(f"[Test] gpio out = {caravelEnv.monitor_gpio((37,0))} j = {j}") + if caravelEnv.monitor_gpio((37, 32)).integer != 0x3F: + cocotb.log.error( + f"[TEST] Wrong gpio high bits output {caravelEnv.monitor_gpio((37,32))} instead of {bin(0x3f)} " + ) + if caravelEnv.monitor_gpio((31, 0)).integer != i: + cocotb.log.error( + f"[TEST] Wrong gpio low bits output {caravelEnv.monitor_gpio((31,0))} instead of {bin(i)}" + ) + await debug_regs.wait_reg2(0) + if caravelEnv.monitor_gpio((37, 0)).integer != 0: + cocotb.log.error( + f"Wrong gpio output {caravelEnv.monitor_gpio((37,0))} instead of {bin(0x00000)}" + ) + + i = i >> 1 + i |= 0x80000000 + caravelEnv.release_gpio((37, 0)) + await ClockCycles(caravelEnv.clk, 10) + caravelEnv.drive_gpio_in((31, 0), 0) + await ClockCycles(caravelEnv.clk, 10) + await debug_regs.wait_reg1(0xAA) + cocotb.log.info("[TEST] configuration finished") + data_in = 0xFFFFFFFF + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xBB) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0xAAAAAAAA + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xCC) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x55555555 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xDD) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x0 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[31:0]") + caravelEnv.drive_gpio_in((31, 0), data_in) + await debug_regs.wait_reg1(0xD1) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[31:0]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datal has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x3F + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[37:32]") + caravelEnv.drive_gpio_in((37, 32), data_in) + await debug_regs.wait_reg1(0xD2) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[37:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x0 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[37:32]") + caravelEnv.drive_gpio_in((37, 32), data_in) + await debug_regs.wait_reg1(0xD3) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[37:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x15 + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[37:32]") + caravelEnv.drive_gpio_in((37, 32), data_in) + await debug_regs.wait_reg1(0xD4) + if debug_regs.read_debug_reg2() == data_in: + cocotb.log.info( + f"[TEST] data {hex(data_in)} sent successfully through gpio[37:32]" + ) + else: + cocotb.log.error( + f"[TEST] Error: reg_mprj_datah has recieved wrong data {debug_regs.read_debug_reg2()} instead of {data_in}" + ) + data_in = 0x2A + cocotb.log.info(f"[TEST] drive {hex(data_in)} to gpio[37:32]") + caravelEnv.drive_gpio_in((37, 32), data_in) + await debug_regs.wait_reg1(0xD5) + + await debug_regs.wait_reg2(0xFF) + + cocotb.log.info("[TEST] finish") + await ClockCycles(caravelEnv.clk, 10) diff --git a/verilog/dv/cocotb/all_tests/hello_world/helloWorld.c b/verilog/dv/cocotb/all_tests/hello_world/helloWorld.c new file mode 100644 index 000000000..d85075900 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/hello_world/helloWorld.c @@ -0,0 +1,32 @@ +#include + + +int main(){ + enable_debug(); + unsigned int j = 0x77; + set_debug_reg1(0x66); + set_debug_reg1(j); + // set_debug_reg1(1); + // set_debug_reg1(j); + // set_debug_reg1(1); + // set_debug_reg1(j); + // (*(volatile uint32_t*)0x0 ) = 0x11; + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x8 ) = (*(volatile uint32_t*)0x4 ); + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x4 ) = 0x88888888; + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x4 ) = 0x17; + // (*(volatile uint32_t*)0x2 ) = 0x14; + + return 0; +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/hello_world/helloWorld.py b/verilog/dv/cocotb/all_tests/hello_world/helloWorld.py new file mode 100644 index 000000000..afc78b63f --- /dev/null +++ b/verilog/dv/cocotb/all_tests/hello_world/helloWorld.py @@ -0,0 +1,12 @@ +import cocotb +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from cocotb.triggers import ClockCycles + + +@cocotb.test() +@report_test +async def helloWorld(dut): + caravelEnv = await test_configure(dut) + cocotb.log.info("[Test] Hello world") + await ClockCycles(caravelEnv.clk, 100000) diff --git a/verilog/dv/cocotb/all_tests/housekeeping/general/clock_redirect.c b/verilog/dv/cocotb/all_tests/housekeeping/general/clock_redirect.c new file mode 100644 index 000000000..e98f0e869 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/general/clock_redirect.c @@ -0,0 +1,16 @@ +#include + + +// -------------------------------------------------------- + +void main(){ + enable_debug(); + /* Monitor pins must be set to output */ + GPIOs_configure(14,GPIO_MODE_MGMT_STD_OUTPUT); + GPIOs_configure(15,GPIO_MODE_MGMT_STD_OUTPUT); + /* Apply configuration */ + GPIOs_loadConfigs(); + set_debug_reg1(0xAA); + dummyDelay(100000000); + return; +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/housekeeping/general/hk_disable.c b/verilog/dv/cocotb/all_tests/housekeeping/general/hk_disable.c new file mode 100644 index 000000000..dba514704 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/general/hk_disable.c @@ -0,0 +1,14 @@ +#include + + +// -------------------------------------------------------- + +void main(){ + enable_debug(); + set_debug_reg2(0xBB); + wait_debug_reg1(0xAA); + enableHkSpi(1); + reg_hkspi_pll_ena =0; + set_debug_reg1(0xBB); + dummyDelay(100000000); +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/housekeeping/general/pll.c b/verilog/dv/cocotb/all_tests/housekeeping/general/pll.c new file mode 100644 index 000000000..8f8e40324 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/general/pll.c @@ -0,0 +1,156 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +// -------------------------------------------------------- + +/* + * PLL Test (self-switching) + * - Switches PLL bypass in housekeeping + * - Changes PLL divider in housekeeping + * + */ +void main() +{ + int i; + + #ifdef ARM // ARM use dirrent location + reg_wb_enable =0x8; // for enable writing to reg_debug_1 and reg_debug_2 + #else + reg_wb_enable =1; // for enable writing to reg_debug_1 and reg_debug_2 + #endif + reg_debug_1 = 0x0; + reg_debug_2 = 0x0; + + /* Monitor pins must be set to output */ + reg_mprj_io_15 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_14 = GPIO_MODE_MGMT_STD_OUTPUT; + /* Apply configuration */ + reg_mprj_xfer = 1; + while ((reg_mprj_xfer&0x1) == 1); + + // Start test + + /* + *------------------------------------------------------------- + * Register 2610_000c reg_hkspi_pll_ena + * SPI address 0x08 = PLL enables + * bit 0 = PLL enable, bit 1 = DCO enable + * + * Register 2610_0010 reg_hkspi_pll_bypass + * SPI address 0x09 = PLL bypass + * bit 0 = PLL bypass + * + * Register 2610_0020 reg_hkspi_pll_source + * SPI address 0x11 = PLL source + * bits 0-2 = phase 0 divider, bits 3-5 = phase 90 divider + * + * Register 2610_0024 reg_hkspi_pll_divider + * SPI address 0x12 = PLL divider + * bits 0-4 = feedback divider + * + * Register 2620_0004 reg_clk_out_dest + * SPI address 0x1b = Output redirect + * bit 0 = trap to mprj_io[13] + * bit 1 = clk to mprj_io[14] + * bit 2 = clk2 to mprj_io[15] + *------------------------------------------------------------- + */ + + // Monitor the core clock and user clock on mprj_io[14] and mprj_io[15] + // reg_clk_out_dest = 0x6 to turn on, 0x0 to turn off + + // Write checkpoint for clock counting (PLL bypassed) + reg_debug_1 = 0xA1; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x0; + reg_debug_1 = 0xA2; + + // Set PLL enable, no DCO mode + reg_hkspi_pll_ena = 0x1; + + // Set PLL output divider to 0x03 + reg_hkspi_pll_source = 0x3; + + // Write checkpoint for clock counting (PLL bypassed) + reg_debug_1 = 0xA3; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x0; + reg_debug_1 = 0xA4; + + // Disable PLL bypass + reg_hkspi_pll_bypass = 0x0; + + // Write checkpoint for clock counting + reg_debug_1 = 0xA5; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x0; + reg_debug_1 = 0xA6; + + // Write 0x03 to feedback divider (was 0x04) + reg_hkspi_pll_divider = 0x3; + + // Write checkpoint + reg_debug_1 = 0xA7; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x0; + reg_debug_1 = 0xA8; + + // Write 0x04 to PLL output divider + reg_hkspi_pll_source = 0x4; + + // Write checkpoint + reg_debug_1 = 0xA9; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x6; + reg_clk_out_dest = 0x0; + reg_debug_1 = 0xAa; + + // End test + reg_mprj_datal = 0xA0900000; +} + diff --git a/verilog/dv/cocotb/all_tests/housekeeping/general/pll.py b/verilog/dv/cocotb/all_tests/housekeeping/general/pll.py new file mode 100644 index 000000000..fdfa848ed --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/general/pll.py @@ -0,0 +1,103 @@ +import cocotb +from cocotb.triggers import RisingEdge, ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test + +from user_design import configure_userdesign + +caravel_clock = 0 +user_clock = 0 + + +@cocotb.test() +@report_test +async def pll(dut): + caravelEnv = await test_configure(dut, timeout_cycles=1147279) + debug_regs = await configure_userdesign(caravelEnv) + error_margin = 0.1 + debug_regs = await configure_userdesign(caravelEnv) + + await debug_regs.wait_reg1(0xA1) + + await cocotb.start(calculate_clk_period(dut.gpio14_monitor, "caravel clock")) + await cocotb.start(calculate_clk_period(dut.gpio15_monitor, "user clock")) + await debug_regs.wait_reg1(0xA3) + if abs(caravel_clock - user_clock) > error_margin * caravel_clock: + cocotb.log.error( + f"[TEST] Error: clocks should be equal in phase 1 but caravel clock = {round(1000000/caravel_clock,2)} MHz user clock = {round(1000000/user_clock,2)} MHz" + ) + else: + cocotb.log.info( + f"[TEST] pass phase 1 caravel clock = {round(1000000/caravel_clock,2)} MHz user clock = {round(1000000/user_clock,2)} MHz" + ) + await cocotb.start(calculate_clk_period(dut.gpio14_monitor, "caravel clock")) + await cocotb.start(calculate_clk_period(dut.gpio15_monitor, "user clock")) + await debug_regs.wait_reg1(0xA5) + if abs(caravel_clock - user_clock) > error_margin * caravel_clock: + cocotb.log.error( + f"[TEST] Error: clocks should be equal in phase 2 but caravel clock = {round(1000000/caravel_clock,2)} MHz user clock = {round(1000000/user_clock,2)} MHz" + ) + else: + cocotb.log.info( + f"[TEST] pass phase 2 caravel clock = {round(1000000/caravel_clock,2)} MHz user clock = {round(1000000/user_clock,2)} MHz" + ) + await cocotb.start(calculate_clk_period(dut.gpio14_monitor, "caravel clock")) + await cocotb.start(calculate_clk_period(dut.gpio15_monitor, "user clock")) + await debug_regs.wait_reg1(0xA7) + if abs(caravel_clock - user_clock * 3) > error_margin * caravel_clock: + cocotb.log.error( + f"[TEST] Error: user clock shoud be 3 times caravel clock in phase 3 but caravel clock = {round(1000000/caravel_clock,2)} MHz user clock = {round(1000000/user_clock,2)} MHz" + ) + else: + cocotb.log.info( + f"[TEST] pass phase 3 caravel clock = {round(1000000/caravel_clock,2)} MHz user clock = {round(1000000/user_clock,2)} MHz" + ) + await cocotb.start(calculate_clk_period(dut.gpio14_monitor, "caravel clock")) + await cocotb.start(calculate_clk_period(dut.gpio15_monitor, "user clock ")) + await debug_regs.wait_reg1(0xA9) + if abs(caravel_clock - user_clock * 3) > error_margin * caravel_clock: + cocotb.log.error( + f"[TEST] Error: user clock shoud be 3 times caravel clock in phase 4 but caravel clock = {round(1000000/caravel_clock,2)} MHz user clock = {round(1000000/user_clock,2)} MHz" + ) + else: + cocotb.log.info( + f"[TEST] pass phase 4 caravel clock = {round(1000000/caravel_clock,2)} MHz user clock = {round(1000000/user_clock,2)} MHz" + ) + await cocotb.start(calculate_clk_period(dut.gpio14_monitor, "caravel clock")) + await cocotb.start(calculate_clk_period(dut.gpio15_monitor, "user clock")) + await debug_regs.wait_reg1(0xAA) + if abs(caravel_clock - user_clock * 4) > error_margin * caravel_clock: + cocotb.log.error( + f"[TEST] Error: user clock shoud be 4 times caravel clock in phase 5 but caravel clock = {round(1000000/caravel_clock,2)} MHz user clock = {round(1000000/user_clock,2)} MHz" + ) + else: + cocotb.log.info( + f"[TEST] pass phase 5 caravel clock = {round(1000000/caravel_clock,2)} MHz user clock = {round(1000000/user_clock,2)} MHz" + ) + await ClockCycles(caravelEnv.clk, 10000) + + # for i in range(1000): + # await ClockCycles(caravelEnv.clk,10000) + # cocotb.log.info(f"time = {cocotb.simulator.get_sim_time()}") + + +async def calculate_clk_period(clk, name): + await RisingEdge(clk) + initial_time = cocotb.simulator.get_sim_time() + initial_time = (initial_time[0] << 32) | (initial_time[1]) + for i in range(100): + await RisingEdge(clk) + end_time = cocotb.simulator.get_sim_time() + end_time = (end_time[0] << 32) | (end_time[1]) + val = (end_time - initial_time) / 100 + cocotb.log.debug(f"[TEST] clock of {name} is {val}") + if name == "caravel clock": + global caravel_clock + caravel_clock = val + elif name == "user clock": + global user_clock + user_clock = val + + val = str(val) + return val diff --git a/verilog/dv/cocotb/all_tests/housekeeping/general/sys_ctrl.py b/verilog/dv/cocotb/all_tests/housekeeping/general/sys_ctrl.py new file mode 100644 index 000000000..2ea9ac433 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/general/sys_ctrl.py @@ -0,0 +1,176 @@ +import cocotb +from cocotb.triggers import RisingEdge, ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from caravel_cocotb.caravel_interfaces import SPI +from user_design import configure_userdesign + + +caravel_clock = 0 +user_clock = 0 +core_clock = 0 + + +@cocotb.test() +@report_test +async def clock_redirect(dut): + caravelEnv = await test_configure(dut, timeout_cycles=55565) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + error_margin = 0.1 + # calculate core clock + await cocotb.start(calculate_clk_period(dut.uut.clock, "core clock")) + await ClockCycles(caravelEnv.clk, 110) + cocotb.log.info( + f"[TEST] core clock requency = {round(1000000/core_clock,2)} MHz period = {core_clock}ps" + ) + await debug_regs.wait_reg1(0xAA) + # check clk redirect working + # user clock + clock_name = "user clock" + await spi_master.write_reg_spi(0x1B, 0x0) # disable user clock output redirect + await cocotb.start(calculate_clk_period(dut.gpio15_monitor, clock_name)) + await ClockCycles(caravelEnv.clk, 110) + if user_clock != 0: + cocotb.log.error( + f"[TEST] Error: {clock_name} is directed while clk2_output_dest is disabled" + ) + else: + cocotb.log.info( + f"[TEST] Pass: {clock_name} has not directed when reg clk2_output_dest is disabled" + ) + + await spi_master.write_reg_spi(0x1B, 0x2) # enable user clock output redirect + await cocotb.start(calculate_clk_period(dut.gpio15_monitor, clock_name)) + await ClockCycles(caravelEnv.clk, 110) + if abs(user_clock - core_clock) > (error_margin * core_clock): + cocotb.log.error( + f"[TEST] Error: {clock_name} is directed with wrong value {clock_name} period = {user_clock} and core clock = {core_clock}" + ) + else: + cocotb.log.info(f"[TEST] Pass: {clock_name} has directed successfully") + + # caravel clock + clock_name = "caravel clock" + await spi_master.write_reg_spi(0x1B, 0x0) # disable caravel clock output redirect + await cocotb.start(calculate_clk_period(dut.gpio14_monitor, clock_name)) + await ClockCycles(caravelEnv.clk, 110) + if caravel_clock != 0: + cocotb.log.error( + f"[TEST] Error: {clock_name} is directed while clk2_output_dest is disabled" + ) + else: + cocotb.log.info( + f"[TEST] Pass: {clock_name} has not directed when reg clk2_output_dest is disabled" + ) + + await spi_master.write_reg_spi(0x1B, 0x4) # enable caravel clock output redirect + await cocotb.start(calculate_clk_period(dut.gpio15_monitor, clock_name)) + await ClockCycles(caravelEnv.clk, 110) + if abs(caravel_clock - core_clock) > error_margin * core_clock: + cocotb.log.error( + f"[TEST] Error: {clock_name} is directed with wrong value {clock_name} period = {caravel_clock} and core clock = {core_clock}" + ) + else: + cocotb.log.info(f"[TEST] Pass: {clock_name} has directed successfully") + + +async def calculate_clk_period(clk, name): + await RisingEdge(clk) + initial_time = cocotb.simulator.get_sim_time() + initial_time = (initial_time[0] << 32) | (initial_time[1]) + for i in range(100): + await RisingEdge(clk) + end_time = cocotb.simulator.get_sim_time() + end_time = (end_time[0] << 32) | (end_time[1]) + val = (end_time - initial_time) / 100 + cocotb.log.debug(f"[TEST] clock of {name} is {val}") + if name == "caravel clock": + global caravel_clock + caravel_clock = val + elif name == "user clock": + global user_clock + user_clock = val + elif name == "core clock": + global core_clock + core_clock = val + return val + + +@cocotb.test() +@report_test +async def hk_disable(dut): + caravelEnv = await test_configure(dut, timeout_cycles=51474) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + try: + hk_hdl = dut.uut.chip_core.housekeeping + except AttributeError: + hk_hdl = dut.uut.chip_core.housekeeping_alt + # check spi working by writing to PLL enables + old_pll_enable = hk_hdl.pll_ena.value.integer + cocotb.log.info(f"[TEST] pll_enable = {old_pll_enable}") + await spi_master.write_reg_spi(0x8, 1 - old_pll_enable) + + pll_enable = hk_hdl.pll_ena.value.integer + cocotb.log.info(f"[TEST] pll_enable = {pll_enable}") + if pll_enable == 1 - old_pll_enable: + cocotb.log.info( + f"[TEST] Pass: SPI swap pll_enable value from {old_pll_enable} to {pll_enable}" + ) + else: + cocotb.log.error( + f"[TEST] Error: SPI isn't working correctly it cant change pll from {old_pll_enable} to {1-old_pll_enable}" + ) + old_pll_enable = hk_hdl.pll_ena.value.integer + cocotb.log.info(f"[TEST] pll_enable = {old_pll_enable}") + await spi_master.write_reg_spi(0x8, 1 - old_pll_enable) + pll_enable = hk_hdl.pll_ena.value.integer + cocotb.log.info(f"[TEST] pll_enable = {pll_enable}") + if pll_enable == 1 - old_pll_enable: + cocotb.log.info( + f"[TEST] Pass: SPI swap pll_enable value from {old_pll_enable} to {pll_enable}" + ) + else: + cocotb.log.error( + f"[TEST] Error: SPI isn't working correctly it cant change pll from {old_pll_enable} to {1-old_pll_enable}" + ) + + # disable Housekeeping SPIca + await spi_master.write_reg_spi(0x6F, 0x1) + + # try to change pll_en + old_pll_enable = hk_hdl.pll_ena.value.integer + cocotb.log.debug(f"[TEST] pll_enable = {old_pll_enable}") + await spi_master.write_reg_spi(0x8, 1 - old_pll_enable) + pll_enable = hk_hdl.pll_ena.value.integer + cocotb.log.debug(f"[TEST] pll_enable = {pll_enable}") + if pll_enable == 1 - old_pll_enable: + cocotb.log.error( + f"[TEST] Error: SPI swap pll_enable value from {old_pll_enable} to {pll_enable} while housekeeping spi is disabled" + ) + else: + cocotb.log.info( + "[TEST] pass: SPI isn't working when SPI housekeeping is disabled" + ) + + # enable SPI housekeeping through firmware + await debug_regs.wait_reg2(0xBB) # start waiting on reg1 AA + debug_regs.write_debug_reg1_backdoor(0xAA) + await debug_regs.wait_reg1(0xBB) # enabled the housekeeping + + old_pll_enable = hk_hdl.pll_ena.value.integer + cocotb.log.debug(f"[TEST] pll_enable = {old_pll_enable}") + await spi_master.write_reg_spi(0x8, 1 - old_pll_enable) + pll_enable = hk_hdl.pll_ena.value.integer + cocotb.log.debug(f"[TEST] pll_enable = {pll_enable}") + if pll_enable == 1 - old_pll_enable: + cocotb.log.info( + "[TEST] Pass: Housekeeping SPI has been enabled correctly through firmware" + ) + else: + cocotb.log.error( + "[TEST] Error: Housekeeping SPI failed to be enabled through firmware" + ) diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_rst_spi.c b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_rst_spi.c new file mode 100644 index 000000000..a22b85d10 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_rst_spi.c @@ -0,0 +1,12 @@ +#include + + + +// Empty C code + +void main() +{ + dummyDelay(100000000); + return; +} + diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_wr_spi.c b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_wr_spi.c new file mode 100644 index 000000000..a22b85d10 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_wr_spi.c @@ -0,0 +1,12 @@ +#include + + + +// Empty C code + +void main() +{ + dummyDelay(100000000); + return; +} + diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_wr_wb.c b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_wr_wb.c new file mode 100644 index 000000000..a22b85d10 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_wr_wb.c @@ -0,0 +1,12 @@ +#include + + + +// Empty C code + +void main() +{ + dummyDelay(100000000); + return; +} + diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_wr_wb_cpu.c b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_wr_wb_cpu.c new file mode 100644 index 000000000..14add8c4f --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/hk_regs_wr_wb_cpu.c @@ -0,0 +1,254 @@ +#include + + + +// access all housekeeping registers that can be access through firmware and change it's value +void main(){ + enable_debug(); + enableHkSpi(0); + // store RO value regs + int old_reg_hkspi_status = reg_hkspi_status; + int old_reg_hkspi_chip_id = reg_hkspi_chip_id; + int old_reg_hkspi_user_id = reg_hkspi_user_id; + #if TRAP_SUP + int old_reg_hkspi_trap = reg_hkspi_trap; + #endif + int old_reg_hkspi_irq = reg_hkspi_irq; + unsigned int data_in = 0x55555555; + // write 10 ones to all registers + wr_all_gpio_ctrl_regs(data_in); + // house keeping + reg_hkspi_status = data_in; + reg_hkspi_chip_id = data_in; + reg_hkspi_user_id = data_in; + #if PLL_SUP + reg_hkspi_pll_ena = data_in; + reg_hkspi_pll_bypass = data_in; + #endif //pll sup + reg_hkspi_irq = data_in; + // reg_hkspi_reset = data_in; can't write 1 to it cpu would be reset + #if TRAP_SUP + reg_hkspi_trap = data_in; + #endif + reg_hkspi_pll_trim = data_in; + reg_hkspi_pll_source = data_in; + reg_hkspi_pll_divider= data_in; + // sys + reg_clk_out_dest = data_in; + reg_hkspi_disable = data_in; + + // read ones that has been written + check_all_gpio_ctrl_regs(data_in); + // housekeeping + if (reg_hkspi_status!= old_reg_hkspi_status) // RO + set_debug_reg1(0x27); + if (reg_hkspi_chip_id!= old_reg_hkspi_chip_id) // RO + set_debug_reg1(0x28); + if (reg_hkspi_user_id!= old_reg_hkspi_user_id) // RO + set_debug_reg1(0x29); + #if PLL_SUP + if (reg_hkspi_pll_ena!= 0x1) // size =2 + set_debug_reg1(0x2a); + if (reg_hkspi_pll_bypass != 0x1) // size = 1 + set_debug_reg1(0x2b); + #endif //pll sup + if (reg_hkspi_irq!= old_reg_hkspi_irq) // RO + set_debug_reg1(0x2c); + #if TRAP_SUP + if (reg_hkspi_trap!= old_reg_hkspi_trap) // RO + set_debug_reg1(0x2d); + #endif + if (reg_hkspi_pll_trim!= 0x1555555) // size 26 + set_debug_reg1(0x2f); + if (reg_hkspi_pll_source!= 0x15) // size 6 bits 0-2 = phase 0 divider, bits 3-5 = phase 90 divider + set_debug_reg1(0x2f); + if (reg_hkspi_pll_divider!= 0x15) // size 5 -> PLL output divider, PLL output divider2 , PLL feedback divider + set_debug_reg1(0x30); + if (reg_hkspi_disable!= 0x1) // size 1 + set_debug_reg1(0x31); + if (reg_clk_out_dest!= 0x5) // trap and clocks redirect + set_debug_reg1(0x32); + // // write 01 to all registers + data_in = 0xAAAAAAAA; + wr_all_gpio_ctrl_regs(data_in); + // house keeping + reg_hkspi_status = data_in; + reg_hkspi_chip_id = data_in; + reg_hkspi_user_id = data_in; + #if PLL_SUP + reg_hkspi_pll_ena = data_in; + reg_hkspi_pll_bypass = data_in; + #endif // pll sup + reg_hkspi_irq = data_in; + reg_hkspi_reset = data_in; + #if TRAP_SUP + reg_hkspi_trap = data_in; + #endif // TRAP_SUP + reg_hkspi_pll_trim = data_in; + reg_hkspi_pll_source = data_in; + reg_hkspi_pll_divider= data_in; + // sys + reg_clk_out_dest = data_in; + reg_hkspi_disable = data_in; + + // // read zeros that has been written + check_all_gpio_ctrl_regs(data_in); + + + // housekeeping + if (reg_hkspi_status!= old_reg_hkspi_status) // RO + set_debug_reg2(0x27); + if (reg_hkspi_chip_id!= old_reg_hkspi_chip_id) // RO + set_debug_reg2(0x28); + if (reg_hkspi_user_id!= old_reg_hkspi_user_id) // RO + set_debug_reg2(0x29); + #if PLL_SUP + if (reg_hkspi_pll_ena!= 0x2) // size =2 + set_debug_reg2(0x2a); + if (reg_hkspi_pll_bypass != 0x0) // size = 1 + set_debug_reg2(0x2b); + if (reg_hkspi_irq!= old_reg_hkspi_irq) // RO + set_debug_reg2(0x2c); + #endif // pll sup + #if TRAP_SUP + if (reg_hkspi_trap!= old_reg_hkspi_trap) // RO + set_debug_reg2(0x2d); + #endif + if (reg_hkspi_pll_trim!= 0x2AAAAAA) // size 26 + set_debug_reg2(0x2f); + if (reg_hkspi_pll_source!= 0x2A) // size 6 bits 0-2 = phase 0 divider, bits 3-5 = phase 90 divider + set_debug_reg2(0x2f); + if (reg_hkspi_pll_divider!= 0xA)// size 5 -> PLL output divider, PLL output divider2 , PLL feedback divider + set_debug_reg2(0x30); + if (reg_hkspi_disable!= 0x0) // size 1 + set_debug_reg2(0x31); + if (reg_clk_out_dest!= 0x2) // trap and clocks redirect + set_debug_reg2(0x32); + + set_debug_reg2(0xFF); +} + +void wr_all_gpio_ctrl_regs(unsigned int data_in){ + reg_mprj_io_0 = data_in; + reg_mprj_io_1 = data_in; + reg_mprj_io_2 = data_in; + reg_mprj_io_3 = data_in; + reg_mprj_io_4 = data_in; + reg_mprj_io_5 = data_in; + reg_mprj_io_6 = data_in; + reg_mprj_io_7 = data_in; + reg_mprj_io_8 = data_in; + reg_mprj_io_9 = data_in; + reg_mprj_io_10 = data_in; + reg_mprj_io_11 = data_in; + reg_mprj_io_12 = data_in; + reg_mprj_io_13 = data_in; + reg_mprj_io_14 = data_in; + reg_mprj_io_15 = data_in; + reg_mprj_io_16 = data_in; + reg_mprj_io_17 = data_in; + reg_mprj_io_18 = data_in; + reg_mprj_io_19 = data_in; + reg_mprj_io_20 = data_in; + reg_mprj_io_21 = data_in; + reg_mprj_io_22 = data_in; + reg_mprj_io_23 = data_in; + reg_mprj_io_24 = data_in; + reg_mprj_io_25 = data_in; + reg_mprj_io_26 = data_in; + reg_mprj_io_27 = data_in; + reg_mprj_io_28 = data_in; + reg_mprj_io_29 = data_in; + reg_mprj_io_30 = data_in; + reg_mprj_io_31 = data_in; + reg_mprj_io_32 = data_in; + reg_mprj_io_33 = data_in; + reg_mprj_io_34 = data_in; + reg_mprj_io_35 = data_in; + reg_mprj_io_36 = data_in; + reg_mprj_io_37 = data_in; +} +void check_all_gpio_ctrl_regs(unsigned int data_in){ + unsigned int mask = 0; + for (int i = 0; i < CTRL_BITS_SIZE; i++){ + mask = mask << 1; + mask = mask | 0x1; + } + unsigned int data_exp = data_in & mask; + if (reg_mprj_io_0 != data_exp) + set_debug_reg1(0x1); + if (reg_mprj_io_1 != data_exp) + set_debug_reg1(0x2); + if (reg_mprj_io_2 != data_exp) + set_debug_reg1(0x3); + if (reg_mprj_io_3 != data_exp) + set_debug_reg1(0x4); + if (reg_mprj_io_4 != data_exp) + set_debug_reg1(0x5); + if (reg_mprj_io_5 != data_exp) + set_debug_reg1(0x6); + if (reg_mprj_io_6 != data_exp) + set_debug_reg1(0x7); + if (reg_mprj_io_7 != data_exp) + set_debug_reg1(0x8); + if (reg_mprj_io_8 != data_exp) + set_debug_reg1(0x9); + if (reg_mprj_io_9 != data_exp) + set_debug_reg1(0xa); + if (reg_mprj_io_10!= data_exp) + set_debug_reg1(0xb); + if (reg_mprj_io_11!= data_exp) + set_debug_reg1(0xc); + if (reg_mprj_io_12!= data_exp) + set_debug_reg1(0xd); + if (reg_mprj_io_13!= data_exp) + set_debug_reg1(0xe); + if (reg_mprj_io_14!= data_exp) + set_debug_reg1(0xf); + if (reg_mprj_io_15!= data_exp) + set_debug_reg1(0x10); + if (reg_mprj_io_16!= data_exp) + set_debug_reg1(0x11); + if (reg_mprj_io_17!= data_exp) + set_debug_reg1(0x12); + if (reg_mprj_io_18!= data_exp) + set_debug_reg1(0x13); + if (reg_mprj_io_19!= data_exp) + set_debug_reg1(0x14); + if (reg_mprj_io_20!= data_exp) + set_debug_reg1(0x15); + if (reg_mprj_io_21!= data_exp) + set_debug_reg1(0x16); + if (reg_mprj_io_22!= data_exp) + set_debug_reg1(0x17); + if (reg_mprj_io_23!= data_exp) + set_debug_reg1(0x18); + if (reg_mprj_io_24!= data_exp) + set_debug_reg1(0x19); + if (reg_mprj_io_25!= data_exp) + set_debug_reg1(0x1a); + if (reg_mprj_io_26!= data_exp) + set_debug_reg1(0x1b); + if (reg_mprj_io_27!= data_exp) + set_debug_reg1(0x1c); + if (reg_mprj_io_28!= data_exp) + set_debug_reg1(0x1d); + if (reg_mprj_io_29!= data_exp) + set_debug_reg1(0x1e); + if (reg_mprj_io_30!= data_exp) + set_debug_reg1(0x1f); + if (reg_mprj_io_31!= data_exp) + set_debug_reg1(0x20); + if (reg_mprj_io_32!= data_exp) + set_debug_reg1(0x21); + if (reg_mprj_io_33!= data_exp) + set_debug_reg1(0x22); + if (reg_mprj_io_34!= data_exp) + set_debug_reg1(0x23); + if (reg_mprj_io_35!= data_exp) + set_debug_reg1(0x24); + if (reg_mprj_io_36!= data_exp) + set_debug_reg1(0x25); + if (reg_mprj_io_37!= data_exp) + set_debug_reg1(0x26); +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/housekeeping_regs_tests.py b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/housekeeping_regs_tests.py new file mode 100644 index 000000000..571f1674f --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_regs/housekeeping_regs_tests.py @@ -0,0 +1,254 @@ +from json.encoder import INFINITY +import random +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.interfaces.cpu import RiskV +from caravel_cocotb.interfaces.defsParser import Regs +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from caravel_cocotb.caravel_interfaces import SPI +from caravel_cocotb.caravel_interfaces import SPI +import json +from user_design import configure_userdesign +reg = Regs() +from models.housekeeping_model.hk_regs import HK_Registers + + +"""randomly write then read housekeeping regs through wishbone""" + + +@cocotb.test() +@report_test +async def hk_regs_wr_wb(dut): + caravelEnv = await test_configure(dut, timeout_cycles=111678, num_error=INFINITY) + cpu = RiskV(dut) + cpu.cpu_force_reset() + hk_file = f'{cocotb.plusargs["MAIN_PATH"]}/models/housekeepingWB/HK_regs.json' + if "gf180" in caravelEnv.design_macros._asdict(): + hk_file = ( + f'{cocotb.plusargs["MAIN_PATH"]}/models/housekeepingWB/HK_regs_gf.json' + ) + with open(hk_file) as f: + regs = json.load(f) + await ClockCycles(caravelEnv.clk, 10) + # write then read + for i in range(random.randint(7, 20)): + bits_num = 32 + mem = random.choice( + ["GPIO"] + ) # can't access 'SPI' and 'sys' register from interfaces.cpu / read or write + key = random.choice(list(regs[mem].keys())) + if key == "base_addr": + continue + key_num = int(key, 16) & 0xFC + key = generate_key_from_num(key_num) + address = int(key, 16) + regs[mem]["base_addr"][1] + if address in [ + 0x26000010, + 0x2600000C, + ]: # skip testing reg_mprj_datal and reg_mprj_datah because when reading them it's getting the gpio input value + continue + data_in = random.getrandbits(bits_num) + cocotb.log.info( + f"[TEST] Writing {bin(data_in)} to {regs[mem][key][0][0]} address {hex(address)} through wishbone" + ) + await cpu.drive_data2address(address, data_in) + # calculate the expected value for each bit + data_exp = "" + keys = [ + generate_key_from_num(key_num + 3), + generate_key_from_num(key_num + 2), + generate_key_from_num(key_num + 1), + generate_key_from_num(key_num), + ] + for count, k in enumerate(keys): + for i in range( + int(bits_num / len(keys)) * (count), + int(bits_num / len(keys)) * (count + 1), + ): + bit_exist = False + if k in regs[mem].keys(): + for field in regs[mem][k]: + field_shift = field[2] + field_size = field[3] + field_access = field[4] + i_temp = (bits_num - 1 - i) % (bits_num / 4) + if field_shift <= i_temp and i_temp <= ( + field_shift + field_size - 1 + ): + if field_access == "RW": + data_exp += bin(data_in)[2:].zfill(bits_num)[i] + bit_exist = True + break + if not bit_exist: + data_exp += "0" + await ClockCycles(caravelEnv.clk, 10) + + cocotb.log.info(f"[TEST] expected data calculated = {data_exp}") + data_out = await cpu.read_address(address) + cocotb.log.info( + f"[TEST] Read {bin(data_out)} from {regs[mem][key][0][0]} address {hex(address)} through wishbone" + ) + if data_out != int(data_exp, 2): + cocotb.log.error( + f"[TEST] wrong read from {regs[mem][key][0][0]} address {hex(address)} retuned val= {bin(data_out)[2:].zfill(bits_num)} expected = {data_exp}" + ) + else: + cocotb.log.info( + f"[TEST] read the right value {hex(data_out)} from {regs[mem][key][0][0]} address {hex(address)} " + ) + + +"""randomly write then read housekeeping regs through wishbone""" + + +@cocotb.test() +@report_test +async def hk_regs_wr_wb_cpu(dut): + caravelEnv = await test_configure(dut, timeout_cycles=294366) + debug_regs = await configure_userdesign(caravelEnv) + reg1 = 0 # buffer + reg2 = 0 + regs_list = ( + "reg_hkspi_status", + "reg_hkspi_chip_id", + "reg_hkspi_user_id", + "reg_hkspi_pll_ena", + "reg_hkspi_pll_bypass", + "reg_hkspi_irq", + "reg_hkspi_trap", + "reg_hkspi_pll_trim", + "reg_hkspi_pll_source", + "reg_hkspi_pll_divide", + "reg_clk_out_des", + "reg_hkspi_disable", + ) + while True: + if debug_regs.read_debug_reg2() == 0xFF: # test finish + break + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 < 38: + cocotb.log.error( + f"[TEST] error while writing 0xFFFFFFFF to reg_mprj_io_{reg1-1}" + ) + else: + cocotb.log.error( + f"[TEST] error while writing 0xFFFFFFFF to {regs_list[reg1-39]}" + ) + if reg2 != debug_regs.read_debug_reg2(): + reg2 = debug_regs.read_debug_reg2() + if reg1 < 38: + cocotb.log.error( + f"[TEST] error while writing 0x0 to reg_mprj_io_{reg2-1}" + ) + else: + cocotb.log.error( + f"[TEST] error while writing 0x0 to {regs_list[reg1-39]}" + ) + await ClockCycles(caravelEnv.clk, 1) + + +"""randomly write then read housekeeping regs through SPI""" + + +@cocotb.test() +@report_test +async def hk_regs_wr_spi(dut): + caravelEnv = await test_configure(dut, timeout_cycles=20681, num_error=0) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + regs = HK_Registers(caravelEnv).regs_spi + for reg in regs.values(): + cocotb.log.debug(f"[TEST] reg {reg}") + address = reg.spi_addr + expected_data = reg.reset + if reg.name in ["housekeeping_disable", "gpio_configure_3"]: + cocotb.log.debug(f"[TEST] skipping writing to {reg.name} as to keep housekeeping spi running") + continue + if "w" not in reg.access_type: + cocotb.log.warning(f"[TEST] skipping writting for {reg.name} as it has access attribute: {reg.access_type}") + continue + if isinstance(address, list): + data_in = random.getrandbits(8 * len(address)) + data_list = [(data_in & (0xFF << i)) >> i for i in range(len(address))] + cocotb.log.info(f"[TEST] start writing register {reg.name} addresses {[hex(a) for a in address]}") + await spi_master.write_reg_spi_nbytes(address=address[0], data=data_list, n_bytes=len(data_list)) + reg.write(data_in) + else: + data_in = random.getrandbits(8) + cocotb.log.info(f"[TEST] start writing {hex(data_in)} to register {reg.name} address {hex(address)}") + await spi_master.write_reg_spi(address=address, data=data_in) + reg.write(data_in) + + for reg in regs.values(): + cocotb.log.debug(f"[TEST] reg {reg}") + address = reg.spi_addr + expected_data = reg.read() + if "r" not in reg.access_type or "w" not in reg.access_type: + cocotb.log.warning(f"[TEST] skipping check for {reg.name} as it has access attribute: {reg.access_type}") + continue + if isinstance(address, list): + cocotb.log.info(f"[TEST] start reading register {reg.name} addresses {[hex(a) for a in address]}") + data_out_list = await spi_master.read_reg_spi_nbytes(address=address[0], n_bytes=len(address)) + data_out = 0 + cocotb.log.debug(f"[TEST] list of data read from {reg.name} data {[hex(a) for a in data_out_list]} ") + for i in range(len(data_out_list)): + cocotb.log.debug(f"[TEST] data_out {hex(data_out)} = data_out_list[{i}] {hex(data_out_list[i])} << (8*{i}) = {hex(data_out_list[i] << (8 * i))}") + data_out |= data_out_list[i] << (8 * i) + else: + data_out = await spi_master.read_reg_spi(address=address) + if data_out != expected_data: + cocotb.log.error( + f"[TEST] wrong read from {reg.name} address {hex(address)} retuned val= {hex(data_out)} expected = {hex(expected_data)}" + ) + else: + cocotb.log.info( + f"[TEST] read the right value {hex(data_out)} from {reg.name} address {hex(address)} " + ) + +"""check reset value of house keeping register""" + +@cocotb.test() +@report_test +async def hk_regs_rst_spi(dut): + caravelEnv = await test_configure(dut, timeout_cycles=20681, num_error=INFINITY) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + regs = HK_Registers(caravelEnv).regs_spi + for reg in regs.values(): + cocotb.log.debug(f"[TEST] reg {reg}") + address = reg.spi_addr + expected_data = reg.reset + if "r" not in reg.access_type: + cocotb.log.warning(f"[TEST] skipping check for {reg.name} as it has access attribute: {reg.access_type}") + continue + if isinstance(address, list): + cocotb.log.info(f"[TEST] start reading register {reg.name} addresses {[hex(a) for a in address]}") + data_out_list = await spi_master.read_reg_spi_nbytes(address=address[0], n_bytes=len(address)) + data_out = 0 + cocotb.log.debug(f"[TEST] list of data read from {reg.name} data {[hex(a) for a in data_out_list]} ") + for i in range(len(data_out_list)): + cocotb.log.debug(f"[TEST] data_out {hex(data_out)} = data_out_list[{i}] {hex(data_out_list[i])} << (8*{i}) = {hex(data_out_list[i] << (8 * i))}") + data_out |= data_out_list[i] << (8 * i) + if data_out != expected_data: + cocotb.log.error(f"[TEST] wrong read from {reg.name} address {[hex(a) for a in address]} retuned val= {bin(data_out)[2:].zfill(32)} expected = {bin(expected_data)[2:].zfill(32)}") + else: + cocotb.log.info(f"[TEST] read the right reset value {hex(data_out)} from {reg.name} address {[hex(a) for a in address]} ") + else: + cocotb.log.info(f"[TEST] start reading register {reg.name} address {hex(address)}") + data_out = await spi_master.read_reg_spi(address=address) + if data_out != expected_data: + cocotb.log.error(f"[TEST] wrong read from {reg.name} address {hex(address)} retuned val= {bin(data_out)[2:].zfill(32)} expected = {bin(expected_data)[2:].zfill(32)}") + else: + cocotb.log.info(f"[TEST] read the right reset value {hex(data_out)} from {reg.name} address {hex(address)} ") + + +def generate_key_from_num(num): + hex_string = hex(num) + hex_list = [i for i in hex_string] + if len(hex_list) == 3: + hex_list.insert(2, "0") + hex_string = "".join(hex_list) + return hex_string diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/mgmt_pass_thru.py b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/mgmt_pass_thru.py new file mode 100644 index 000000000..8d74601fd --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/mgmt_pass_thru.py @@ -0,0 +1,36 @@ +import cocotb +from cocotb.triggers import FallingEdge, RisingEdge +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from caravel_cocotb.caravel_interfaces import SPI +from random import randrange +from user_design import configure_userdesign +from all_tests.common.read_hex import ReadHex +import random + +bit_time_ns = 0 + + +@cocotb.test() +@report_test +async def mgmt_pass_thru_rd(dut): + caravelEnv = await test_configure(dut, timeout_cycles=37247) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + hex_path = f"{cocotb.plusargs['SIM_DIR']}/{cocotb.plusargs['FTESTNAME']}/firmware.hex".replace('"', "") + hex_dict = ReadHex(hex_path).read_hex() + # check 10 read random address with diffrent read bytes numbers + for _ in range(10): + rand_key = random.choice(list(hex_dict.keys())) + rand_address = random.choice(hex_dict[rand_key]) + address = rand_key + rand_address + bytes_num = random.randint(1, 4) + try: + expected_val = [hex_dict[rand_key][rand_address+i] for i in range(bytes_num)] + except IndexError: + continue + val = await spi_master.reg_spi_mgmt_pass_thru_read(address, bytes_num) + if val != expected_val: + cocotb.log.error(f"[TEST] wrong read from hex file, address {hex(address)} expected value= {expected_val}, recieved value {val}") + else: + cocotb.log.info(f"[TEST] correct read from hex file, address {hex(address)} expected value= {expected_val}, recieved value {val}") \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/mgmt_pass_thru_rd.c b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/mgmt_pass_thru_rd.c new file mode 100644 index 000000000..e53ba1d12 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/mgmt_pass_thru_rd.c @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +void main(){ + enable_debug(); + ManagmentGpio_write(0); + ManagmentGpio_outputEnable(); + // Start test + set_debug_reg1(0xbb); + ManagmentGpio_write(1); + dummyDelay(100000000); +} + diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/spi.py b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/spi.py new file mode 100644 index 000000000..052543ff4 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/spi.py @@ -0,0 +1,85 @@ +import random +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from caravel_cocotb.caravel_interfaces import SPI +from user_design import configure_userdesign + + + +@cocotb.test() +@report_test +async def spi_rd_wr_nbyte(dut): + caravelEnv = await test_configure(dut, timeout_cycles=112763) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] start spi_rd_wr_nbyte test") + nbytes_limits = 7 + # writing to the random number(1 to 8) of bits after 0x1E (gpio_configure[4]) address avoid changing gpio 3 + for j in range(30): + address = random.randint(0x26, 0x67 - nbytes_limits) + n_bytes = random.randint(1, nbytes_limits) + await spi_master.write_reg_spi_nbytes(address, [0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3], nbytes_limits) + await spi_master.write_reg_spi_nbytes(address, [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0], n_bytes) + data_8_bytes = await spi_master.read_reg_spi_nbytes(address, nbytes_limits) + data = await spi_master.read_reg_spi_nbytes(address, n_bytes) + cocotb.log.info(f"[TEST] n_bytes = {n_bytes} address = {address} data_8_bytes = {data_8_bytes}") + for i in range(nbytes_limits): + if i >= n_bytes: + if data_8_bytes[i] != 0x3: + cocotb.log.error( + f"[TEST] register {i} has returned value {data_8_bytes[i]} while it should return value 0x3 n_bytes = {n_bytes}" + ) + else: + cocotb.log.info( + f"[TEST] successful read 0 from register {i} n_bytes = {n_bytes}" + ) + else: + if data_8_bytes[i] != data[i]: + cocotb.log.error(f"[TEST] register {i} has returned value {data_8_bytes[i]} in 8 bytes reading while it should return value {data[i]} in {n_bytes} reading") + if data_8_bytes[i] != 0: + cocotb.log.error( + f"[TEST] register number {i} has returned value {data_8_bytes[i]} > 0 while it should return value == 0 n_bytes = {n_bytes}" + ) + else: + cocotb.log.info( + f"[TEST] successful read {data_8_bytes[i]} from register {i} n_bytes = {n_bytes}" + ) + await ClockCycles(caravelEnv.clk, 5) + + +@cocotb.test() +@report_test +async def spi_rd_wr(dut): + caravelEnv = await test_configure(dut, timeout_cycles=11571) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] start spi_rd_wr test") + # writing to the random number(1 to 8) of bits after 0x1E (gpio_configure[4]) address avoid changing gpio 3 + for j in range(7): + address = random.randrange(0x26, 0x68, 2) + data_in = random.getrandbits(8) + data = await spi_master.read_write_reg_spi(address, data_in) + cocotb.log.info(f"{j}: address {hex(address)} reading {hex(data)} and writing {hex(data_in)}") + data = await spi_master.read_write_reg_spi(address, data_in) + cocotb.log.info(f"{j}: address {hex(address)} reading {hex(data)} and writing {hex(data_in)}") + if data != data_in: + cocotb.log.error( + f"[TEST] error address {hex(address)} data_out = {hex(data)}({bin(data)}) expected = {hex(data_in)}({bin(data_in)})" + ) + nbytes_limits = 7 + for j in range(30): + address = random.randint(0x26, 0x67 - nbytes_limits) + n_bytes = random.randint(1, nbytes_limits) + data_in = [random.getrandbits(4) for i in range(n_bytes)] + data = await spi_master.read_write_reg_nbytes(address, data_in, n_bytes) + cocotb.log.info(f"{j}: address {hex(address)} reading {data} and writing {data_in}") + data = await spi_master.read_write_reg_nbytes(address, data_in, n_bytes) + cocotb.log.info(f"{j}: address {hex(address)} reading {data} and writing {data_in}") + if data != data_in: + cocotb.log.error( + f"[TEST] error address {hex(address)} data_out = {(data)} expected = {data_in}" + ) + await ClockCycles(caravelEnv.clk, 5) diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/spi_rd_wr.c b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/spi_rd_wr.c new file mode 100644 index 000000000..a22b85d10 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/spi_rd_wr.c @@ -0,0 +1,12 @@ +#include + + + +// Empty C code + +void main() +{ + dummyDelay(100000000); + return; +} + diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/spi_rd_wr_nbyte.c b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/spi_rd_wr_nbyte.c new file mode 100644 index 000000000..a22b85d10 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/spi_rd_wr_nbyte.c @@ -0,0 +1,12 @@ +#include + + + +// Empty C code + +void main() +{ + dummyDelay(100000000); + return; +} + diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/test_data b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/test_data new file mode 100644 index 000000000..287a0cf9a --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/test_data @@ -0,0 +1,3 @@ +@00000000 +6F 00 00 0B 93 01 00 00 13 02 63 57 b5 00 23 20 +13 00 00 00 13 00 00 00 13 00 00 00 13 00 00 00 diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/user_pass_thru.py b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/user_pass_thru.py new file mode 100644 index 000000000..5f55f0020 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/user_pass_thru.py @@ -0,0 +1,120 @@ +import cocotb +from cocotb.triggers import FallingEdge, RisingEdge +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from all_tests.spi_master.SPI_VIP import read_mem, SPI_VIP +from caravel_cocotb.caravel_interfaces import SPI +from random import randrange +from user_design import configure_userdesign + + +bit_time_ns = 0 + + +@cocotb.test() +@report_test +async def user_pass_thru_rd(dut): + caravelEnv = await test_configure(dut, timeout_cycles=89712) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] start spi_master_rd test") + file_name = f"{cocotb.plusargs['USER_PROJECT_ROOT']}/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/test_data" + file_name = file_name.replace('"', '') + mem = read_mem(file_name) + await cocotb.start( + SPI_VIP( + dut.gpio8_monitor, + dut.gpio9_monitor, + dut.gpio10_monitor, + (dut.gpio11_en, dut.gpio11), + mem, remove_clk=1 + ) + ) # fork for SPI + await debug_regs.wait_reg1(0xAA) + cocotb.log.info("[TEST] Configuration finished") + # start reading from memory + address = 0x00.to_bytes(3, "big") + + data_received = await spi_master.reg_spi_user_pass_thru(send_data=[0x03, address[0], address[1], address[2]], read_byte_num=8) + address = int.from_bytes(address, "big") + for data in data_received: + if data != mem[address]: + cocotb.log.error( + f"[TEST] reading incorrect value from address {hex(address)} expected = {hex(mem[address])} returened = {hex(data)}" + ) + else: + cocotb.log.info( + f"[TEST] reading correct value {hex(data)} from address {hex(address)} " + ) + address += 1 + await spi_master.disable_csb() + + # Wait for processor to restart + await debug_regs.wait_reg1(0xBB) + cocotb.log.info("[TEST] processor has restarted successfully") + + +@cocotb.test() +@report_test +async def user_pass_thru_connection(dut): + caravelEnv = await test_configure(dut, timeout_cycles=86033) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + await debug_regs.wait_reg1(0xAA) + await spi_master.enable_csb() + await spi_master._hk_write_byte(spi_master.SPI_COMMAND.USER_PASS_THRU.value) + await FallingEdge(spi_master.clk) + spi_master._kill_spi_clk() + caravelEnv.drive_gpio_in(4, 0) # finish the clock cycle + await RisingEdge(caravelEnv.clk) + # check sdo and clk are following the spi + for i in range(randrange(10, 50)): + clk = randrange(0, 2) # drive random value from 0 to 3 to clk and SDO + sdo = randrange(0, 2) # drive random value from 0 to 3 to clk and SDO + caravelEnv.drive_gpio_in(4, clk) + caravelEnv.drive_gpio_in(2, sdo) + await RisingEdge(caravelEnv.clk) + expected = int(f"0b{sdo}{clk}0", 2) + if caravelEnv.monitor_gpio((10, 8)).integer != expected: + cocotb.log.error( + f"[TEST] checker 1 error the value seen at user pass through didn't match the value passed to SPI returend = {bin(caravelEnv.monitor_gpio((10,8)).integer)} expected = {bin(expected)}" + ) + + # check sdo and clk are not following the spi when enable but command 0xc2 isn't passed + await spi_master.disable_csb() + await spi_master.enable_csb() + await spi_master._hk_write_byte(spi_master.SPI_COMMAND.NO_OP.value) + spi_master._kill_spi_clk() + for i in range(randrange(10, 50)): + clk = randrange(0, 2) # drive random value from 0 to 3 to clk and SDO + sdo = randrange(0, 2) # drive random value from 0 to 3 to clk and SDO + await RisingEdge(caravelEnv.clk) + caravelEnv.drive_gpio_in(4, clk) + caravelEnv.drive_gpio_in(2, sdo) + await FallingEdge(caravelEnv.clk) + await FallingEdge(caravelEnv.clk) + expected = int("0b0", 2) + if caravelEnv.monitor_gpio((10, 8)).integer != expected: + cocotb.log.error( + f"[TEST] checker 2 error the value seen at user pass through didn't match the value passed to SPI returend = {bin(caravelEnv.monitor_gpio((10,8)).integer)} expected = {bin(expected)}" + ) + + # check SDI + await spi_master.disable_csb() + await spi_master.enable_csb() + await spi_master._hk_write_byte(spi_master.SPI_COMMAND.USER_PASS_THRU.value) + await FallingEdge(spi_master.clk) + spi_master._kill_spi_clk() + caravelEnv.drive_gpio_in(4, 0) # finish the clock cycle + await RisingEdge(caravelEnv.clk) + caravelEnv.drive_gpio_in(4, 1) # finish the clock cycle + for i in range(randrange(10, 50)): + sdi = randrange(0, 2) # drive random value from 0 to 3 to clk and SDO + caravelEnv.drive_gpio_in(11, sdi) + await RisingEdge(caravelEnv.clk) + expected = sdi + if caravelEnv.monitor_gpio((1, 1)).integer != expected: + cocotb.log.error( + f"[TEST] checker 3 error the value seen at user pass through didn't match the value passed to SPI returend = {bin(caravelEnv.monitor_gpio((1,1)).integer)} expected = {bin(expected)}" + ) diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/user_pass_thru_connection.c b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/user_pass_thru_connection.c new file mode 100644 index 000000000..c26459a7b --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/user_pass_thru_connection.c @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ +#include + + + +void main() +{ + // This program is just to keep the processor busy while the + // housekeeping SPI is being accessed. to show that the + // processor is halted while the SPI is accessing the + // flash SPI in pass-through mode. + + enable_debug(); + + // Management needs to apply output on these pads to access the user area SPI flash + GPIOs_configure(11 ,GPIO_MODE_MGMT_STD_INPUT_NOPULL); // SDI + GPIOs_configure(10 ,GPIO_MODE_MGMT_STD_OUTPUT); // SDO + GPIOs_configure(9 ,GPIO_MODE_MGMT_STD_OUTPUT); // clk + GPIOs_configure(8 ,GPIO_MODE_MGMT_STD_OUTPUT); // csb + GPIOs_configure(1 ,GPIO_MODE_MGMT_STD_OUTPUT); // SDI housekeeping spi + + GPIOs_loadConfigs(); + + // Start test + set_debug_reg1(0xAA); + dummyDelay(100000000); + + +} + diff --git a/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/user_pass_thru_rd.c b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/user_pass_thru_rd.c new file mode 100644 index 000000000..681cda626 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/housekeeping/housekeeping_spi/user_pass_thru_rd.c @@ -0,0 +1,47 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + + + + +void main() +{ + // This program is just to keep the processor busy while the + // housekeeping SPI is being accessed. to show that the + // processor is halted while the SPI is accessing the + // flash SPI in pass-through mode. + enable_debug(); + + // Management needs to apply output on these pads to access the user area SPI flash + GPIOs_configure(11 ,GPIO_MODE_MGMT_STD_INPUT_NOPULL); // SDI + GPIOs_configure(10 ,GPIO_MODE_MGMT_STD_OUTPUT); // SDO + GPIOs_configure(9 ,GPIO_MODE_MGMT_STD_OUTPUT); // clk + GPIOs_configure(8 ,GPIO_MODE_MGMT_STD_OUTPUT); // csb + GPIOs_configure(1 ,GPIO_MODE_MGMT_STD_OUTPUT); // SDI housekeeping spi + + GPIOs_loadConfigs(); + + + // Start test + set_debug_reg1(0xAA); + set_debug_reg1(0xBB); + dummyDelay(100000000); +} + diff --git a/verilog/dv/cocotb/all_tests/irq/IRQ_external.c b/verilog/dv/cocotb/all_tests/irq/IRQ_external.c new file mode 100644 index 000000000..0fc7b1220 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/IRQ_external.c @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +/* +Testing timer interrupts +Enable interrupt for IRQ external pin mprj_io[7] -> should be drived to 1 by the environment +**NOTE** housekeeping SPI should used to update register irq_1_inputsrc to 1 see verilog code + + @wait for environment to make mprj[7] high + send 0xAA + + @received interrupt correctly test pass + send 0x1B + + @ timeout test fail + send 0x1E + + @ end test + send 0xFF +*/ + + +void main(){ + enable_debug(); + // setting bit 7 as input + GPIOs_configure(7,GPIO_MODE_MGMT_STD_INPUT_NOPULL); + + GPIOs_loadConfigs(); + IRQ_enableExternal1(1); + + // test interrrupt happen when mprj[7] is asserted + IRQ_clearFlag(); + set_debug_reg2(0xAA); //wait for environment to make mprj[7] high + // Loop, waiting for the interrupt to change reg_mprj_datah + char is_pass = 0; + int timeout = 40; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x1B); //test pass irq sent at mprj 7 + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x1E); // timeout + } + + // test interrupt doesn't happened when mprj[7] is deasserted + set_debug_reg2(0xBB); + IRQ_enableExternal1(0); + IRQ_enableExternal1(1); + // Loop, waiting for the interrupt to change reg_mprj_datah + is_pass = 0; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x2E); //test fail interrupt isn't suppose to happened + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x2B); // test pass + } + + // test finish + set_debug_reg2(0xFF); +} diff --git a/verilog/dv/cocotb/all_tests/irq/IRQ_external.py b/verilog/dv/cocotb/all_tests/irq/IRQ_external.py new file mode 100644 index 000000000..94b6bcf21 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/IRQ_external.py @@ -0,0 +1,78 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from user_design import configure_userdesign +from caravel_cocotb.caravel_interfaces import SPI + + +"""Testbench of GPIO configuration through bit-bang method using the StriVe housekeeping SPI.""" + + +@cocotb.test() +@report_test +async def IRQ_external(dut): + caravelEnv = await test_configure(dut, timeout_cycles=426012) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start IRQ_external test") + pass_list = (0x1B, 0x2B) + fail_list = (0x1E, 0x2E) + phases_fails = 2 + phases_passes = 0 + reg1 = 0 # buffer + reg2 = 0 # buffer + + while True: + if reg2 != debug_regs.read_debug_reg2(): + reg2 = debug_regs.read_debug_reg2() + if reg2 == 0xFF: # test finish + break + if reg2 == 0xAA: # assert mprj 7 + caravelEnv.drive_gpio_in((7, 7), 0) + await spi_master.write_reg_spi(0x1C, 1) + # cocotb.log.info( + # f"irq 1 = {dut.uut.chip_core.housekeeping.irq_1_inputsrc.value}" + # ) + caravelEnv.drive_gpio_in((7, 7), 1) + await ClockCycles(caravelEnv.clk, 10) + caravelEnv.drive_gpio_in((7, 7), 0) + + # if reg2 == 0xBB: # deassert mprj 7 + # caravelEnv.drive_gpio_in((7,7),0) + + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + phases_passes += 1 + phases_fails -= 1 + if reg1 == 0x1B: + cocotb.log.info( + "[TEST] Pass interrupt is detected when mprj 7 asserted" + ) + elif reg1 == 0x2B: + cocotb.log.info( + "[TEST] Pass interrupt isn't detected when mprj 7 deasserted" + ) + elif reg1 in fail_list: # pass phase + if reg1 == 0x1E: + cocotb.log.error( + "[TEST] Failed interrupt isn't detected when mprj 7 asserted" + ) + elif reg1 == 0x2E: + cocotb.log.error( + "[TEST] Failed interrupt is detected when mprj 7 deasserted" + ) + else: + cocotb.log.error("[TEST] debug register 1 has illegal value") + await ClockCycles(caravelEnv.clk, 1) + + if phases_fails != 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) diff --git a/verilog/dv/cocotb/all_tests/irq/IRQ_external2.c b/verilog/dv/cocotb/all_tests/irq/IRQ_external2.c new file mode 100644 index 000000000..e63385dae --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/IRQ_external2.c @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +/* +Testing timer interrupts +Enable interrupt for IRQ external pin mprj_io[12] -> should be drived to 1 by the environment +**NOTE** housekeeping SPI should used to update register irq_1_inputsrc to 1 see verilog code + + @wait for environment to make mprj[12] high + send 0xAA + + @received interrupt correctly test pass + send 0x1B + + @ timeout test fail + send 0x1E + + @ end test + send 0xFF +*/ + + +void main(){ + enable_debug(); + // setting bit 12 as input + GPIOs_configure(12,GPIO_MODE_MGMT_STD_INPUT_NOPULL); + + GPIOs_loadConfigs(); + IRQ_enableExternal2(1); + + // test interrrupt happen when mprj[12] is asserted + IRQ_clearFlag(); + set_debug_reg2(0xAA); //wait for environment to make mprj[12] high + // Loop, waiting for the interrupt to change reg_mprj_datah + char is_pass = 0; + int timeout = 40; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x1B); //test pass irq sent at mprj 12 + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x1E); // timeout + } + + // test interrupt doesn't happened when mprj[12] is deasserted + set_debug_reg2(0xBB); + IRQ_enableExternal2(0); + IRQ_enableExternal2(1); + // Loop, waiting for the interrupt to change reg_mprj_datah + is_pass = 0; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x2E); //test fail interrupt isn't suppose to happened + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x2B); // test pass + } + + // test finish + set_debug_reg2(0xFF); +} diff --git a/verilog/dv/cocotb/all_tests/irq/IRQ_external2.py b/verilog/dv/cocotb/all_tests/irq/IRQ_external2.py new file mode 100644 index 000000000..d187be05b --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/IRQ_external2.py @@ -0,0 +1,79 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.interfaces.defsParser import Regs +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from caravel_cocotb.caravel_interfaces import SPI +from user_design import configure_userdesign + +reg = Regs() +"""Testbench of GPIO configuration through bit-bang method using the StriVe housekeeping SPI.""" + + +@cocotb.test() +@report_test +async def IRQ_external2(dut): + caravelEnv = await test_configure(dut, timeout_cycles=428337) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start IRQ_external2 test") + pass_list = (0x1B, 0x2B) + fail_list = (0x1E, 0x2E) + phases_fails = 2 + phases_passes = 0 + reg1 = 0 # buffer + reg2 = 0 # buffer + + while True: + if reg2 != debug_regs.read_debug_reg2(): + reg2 = debug_regs.read_debug_reg2() + if reg2 == 0xFF: # test finish + break + if reg2 == 0xAA: # assert mprj 12 + caravelEnv.drive_gpio_in((12, 12), 0) + await spi_master.write_reg_spi(0x1C, 2) + # cocotb.log.info( + # f"irq 2 = {dut.uut.chip_core.housekeeping.irq_2_inputsrc.value}" + # ) + caravelEnv.drive_gpio_in((12, 12), 1) + await ClockCycles(caravelEnv.clk, 10) + caravelEnv.drive_gpio_in((12, 12), 0) + + # if reg2 == 0xBB: # deassert mprj 12 + # caravelEnv.drive_gpio_in((12,12),0) + + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + phases_passes += 1 + phases_fails -= 1 + if reg1 == 0x1B: + cocotb.log.info( + "[TEST] Pass interrupt is detected when mprj 12 asserted" + ) + elif reg1 == 0x2B: + cocotb.log.info( + "[TEST] Pass interrupt isn't detected when mprj 12 deasserted" + ) + elif reg1 in fail_list: # pass phase + if reg1 == 0x1E: + cocotb.log.error( + "[TEST] Failed interrupt isn't detected when mprj 12 asserted" + ) + elif reg1 == 0x2E: + cocotb.log.error( + "[TEST] Failed interrupt is detected when mprj 12 deasserted" + ) + else: + cocotb.log.error("[TEST] debug register 1 has illegal value") + await ClockCycles(caravelEnv.clk, 1) + + if phases_fails != 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) diff --git a/verilog/dv/cocotb/all_tests/irq/IRQ_spi.c b/verilog/dv/cocotb/all_tests/irq/IRQ_spi.c new file mode 100644 index 000000000..e28e5069b --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/IRQ_spi.c @@ -0,0 +1,68 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +/* +Testing spi interrupt +*/ + + +void main(){ + enable_debug(); + IRQ_hkSpi(1); + + // test interrrupt happen when spi_irq reg got set + IRQ_clearFlag(); + set_debug_reg2(0xAA); //wait for environment to make spi_irq high + // Loop, waiting for the interrupt to change reg_mprj_datah + char is_pass = 0; + int timeout = 40; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x1B); //test pass irq sent at mprj 7 + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x1E); // timeout + } + + // test interrupt doesn't happened when spi_irq is deasserted + set_debug_reg2(0xBB); + IRQ_hkSpi(0); + IRQ_hkSpi(1); + // Loop, waiting for the interrupt to change reg_mprj_datah + is_pass = 0; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x2E); //test fail interrupt isn't suppose to happened + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x2B); // test pass + } + + // test finish + set_debug_reg2(0xFF); +} diff --git a/verilog/dv/cocotb/all_tests/irq/IRQ_spi.py b/verilog/dv/cocotb/all_tests/irq/IRQ_spi.py new file mode 100644 index 000000000..6054409b8 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/IRQ_spi.py @@ -0,0 +1,71 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from caravel_cocotb.caravel_interfaces import SPI +from user_design import configure_userdesign + + +"""Testbench of GPIO configuration through bit-bang method using the StriVe housekeeping SPI.""" + + +@cocotb.test() +@report_test +async def IRQ_spi(dut): + caravelEnv = await test_configure(dut, timeout_cycles=412992) + spi_master = SPI(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start IRQ_spi test") + pass_list = (0x1B, 0x2B) + fail_list = (0x1E, 0x2E) + phases_fails = 2 + phases_passes = 0 + reg1 = 0 # buffer + reg2 = 0 # buffer + + while True: + if reg2 != debug_regs.read_debug_reg2(): + reg2 = debug_regs.read_debug_reg2() + if reg2 == 0xFF: # test finish + break + if reg2 == 0xAA: # assert spi_irq + # write one to the IRQ spi + await spi_master.write_reg_spi(0xA, 1) + # reading any housekeeping reg is required to self reset irq_reg + await spi_master.read_reg_spi( 0xA) + + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + phases_passes += 1 + phases_fails -= 1 + if reg1 == 0x1B: + cocotb.log.info( + "[TEST] Pass interrupt is detected when spi_irq asserted" + ) + elif reg1 == 0x2B: + cocotb.log.info( + "[TEST] Pass interrupt isn't detected when spi_irq deasserted" + ) + elif reg1 in fail_list: # pass phase + if reg1 == 0x1E: + cocotb.log.error( + "[TEST] Failed interrupt isn't detected when spi_irq asserted" + ) + elif reg1 == 0x2E: + cocotb.log.error( + "[TEST] Failed interrupt is detected when spi_irq deasserted" + ) + else: + cocotb.log.error("[TEST] debug register 1 has illegal value") + await ClockCycles(caravelEnv.clk, 1) + + if phases_fails != 0: + cocotb.log.error( + "[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + "[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) diff --git a/verilog/dv/cocotb/all_tests/irq/IRQ_timer.c b/verilog/dv/cocotb/all_tests/irq/IRQ_timer.c new file mode 100644 index 000000000..7fc0ccb71 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/IRQ_timer.c @@ -0,0 +1,68 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +void main(){ + enable_debug(); + + set_debug_reg2(0xAA); //wait for timer to send irq + + IRQ_clearFlag(); + /* Configure timer for a single-shot countdown */ + IRQ_enableTimer(1); + timer0_configureOneShot(500); + // Loop, waiting for the interrupt to change reg_mprj_datah + char is_pass = 0; + int timeout = 50; + unsigned int x; + for (x = 0; x < timeout; x++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x1B); //test pass irq sent at timer0 + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x1E); // timeout + } + IRQ_enableTimer(0); + IRQ_enableTimer(1); + // test interrupt doesn't happened when timer isnt used + set_debug_reg2(0xBB); + timer0_enable(0); // disable counter + IRQ_clearFlag(); + // Loop, waiting for the interrupt to change reg_mprj_datah + is_pass = 0; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x2E); //test fail interrupt isn't suppose to happened + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x2B); // test pass + } + + // test finish + set_debug_reg2(0xFF); + +} + diff --git a/verilog/dv/cocotb/all_tests/irq/IRQ_timer.py b/verilog/dv/cocotb/all_tests/irq/IRQ_timer.py new file mode 100644 index 000000000..72f4d29ce --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/IRQ_timer.py @@ -0,0 +1,58 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from user_design import configure_userdesign + +"""Testbench of GPIO configuration through bit-bang method using the StriVe housekeeping SPI.""" + + +@cocotb.test() +@report_test +async def IRQ_timer(dut): + caravelEnv = await test_configure(dut, timeout_cycles=579003) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start IRQ_timer test") + pass_list = (0x1B, 0x2B) + fail_list = (0x1E, 0x2E) + phases_fails = 2 + phases_passes = 0 + reg1 = 0 # buffer + while True: + if debug_regs.read_debug_reg2() == 0xFF: # test finish + break + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + phases_passes += 1 + phases_fails -= 1 + if reg1 == 0x1B: + cocotb.log.info( + "[TEST] Pass interrupt is detected when timer is used" + ) + elif reg1 == 0x2B: + cocotb.log.info( + "[TEST] Pass interrupt isn't detected when timer isnt used" + ) + elif reg1 in fail_list: # pass phase + if reg1 == 0x1E: + cocotb.log.info( + "[TEST] Failed interrupt isn't detected when timer is used" + ) + elif reg1 == 0x2E: + cocotb.log.error( + "[TEST] Failed interrupt is detected when timer isnt used" + ) + else: + cocotb.log.error("[TEST] debug register 1 has illegal value") + await ClockCycles(caravelEnv.clk, 1) + + if phases_fails != 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) diff --git a/verilog/dv/cocotb/all_tests/irq/IRQ_uart.c b/verilog/dv/cocotb/all_tests/irq/IRQ_uart.c new file mode 100644 index 000000000..6aaf477f5 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/IRQ_uart.c @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ +#include + + +void main(){ + enable_debug(); + IRQ_clearFlag(); + GPIOs_configure(6,GPIO_MODE_MGMT_STD_OUTPUT); + GPIOs_loadConfigs(); + IRQ_enableUartTx(1); + + set_debug_reg2(0xAA); //start sending data through the uart + print("M"); + + // Loop, waiting for the interrupt to change reg_mprj_datah + char is_pass = 0; + int timeout = 100; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x1B); //test pass irq sent + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x1E); // timeout + } + // test interrupt doesn't happened nothing sent at uart + set_debug_reg2(0xBB); + IRQ_enableUartTx(0); + IRQ_enableUartTx(1); + // Loop, waiting for the interrupt to change reg_mprj_datah + is_pass = 0; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x2E); //test fail interrupt isn't suppose to happened + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x2B); // test pass + } + // test finish + set_debug_reg2(0xFF); +} + diff --git a/verilog/dv/cocotb/all_tests/irq/IRQ_uart.py b/verilog/dv/cocotb/all_tests/irq/IRQ_uart.py new file mode 100644 index 000000000..9dda8b964 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/IRQ_uart.py @@ -0,0 +1,77 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.interfaces.defsParser import Regs +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from user_design import configure_userdesign + + +async def write_reg_spi(caravelEnv, address, data): + await caravelEnv.enable_csb() + await caravelEnv.hk_write_byte(0x80) # Write stream command + await caravelEnv.hk_write_byte( + address + ) # Address (register 19 = GPIO bit-bang control) + await caravelEnv.hk_write_byte(data) # Data = 0x01 (enable bit-bang mode) + await caravelEnv.disable_csb() + + +reg = Regs() +"""Testbench of GPIO configuration through bit-bang method using the StriVe housekeeping SPI.""" + + +@cocotb.test() +@report_test +async def IRQ_uart(dut): + caravelEnv = await test_configure(dut, timeout_cycles=896457) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start IRQ_uart test") + pass_list = (0x1B, 0x2B) + fail_list = (0x1E, 0x2E) + phases_fails = 2 + phases_passes = 0 + reg1 = 0 # buffer + reg2 = 0 # buffer + while True: + if reg2 != debug_regs.read_debug_reg2(): + reg2 = debug_regs.read_debug_reg2() + if reg2 == 0xFF: # test finish + break + if reg2 == 0xAA: + cocotb.log.info("[TEST] start sending through uart") + + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + phases_passes += 1 + phases_fails -= 1 + if reg1 == 0x1B: + cocotb.log.info( + "[TEST] Pass interrupt is detected when uart is sending data" + ) + elif reg1 == 0x2B: + cocotb.log.info( + "[TEST] Pass interrupt isn't detected when uart isnt sending data" + ) + elif reg1 in fail_list: # pass phase + if reg1 == 0x1E: + cocotb.log.info( + "[TEST] Failed interrupt isn't detected uart is sending data" + ) + elif reg1 == 0x2E: + cocotb.log.error( + "[TEST] Failed interrupt is detected uart isnt sending data" + ) + else: + cocotb.log.error("[TEST] debug register 1 has illegal value") + await ClockCycles(caravelEnv.clk, 1) + + if phases_fails != 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) diff --git a/verilog/dv/cocotb/all_tests/irq/IRQ_uart_rx.c b/verilog/dv/cocotb/all_tests/irq/IRQ_uart_rx.c new file mode 100644 index 000000000..526004dfb --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/IRQ_uart_rx.c @@ -0,0 +1,66 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ +#include + + +void main(){ + enable_debug(); + IRQ_clearFlag(); + enableHkSpi(0); + GPIOs_configure(6,GPIO_MODE_MGMT_STD_OUTPUT); + GPIOs_configure(5,GPIO_MODE_MGMT_STD_INPUT_NOPULL); + GPIOs_loadConfigs(); + UART_enableRX(1); + IRQ_enableUartRx(1); + + set_debug_reg2(0xAA); //start sending data through the uart + + // Loop, waiting for the interrupt to change reg_mprj_datah + char is_pass = 0; + int timeout = 50; + UART_readChar(); + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x1B); //test pass irq sent + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x1E); // timeout + } + // test interrupt doesn't happened nothing sent at uart + set_debug_reg2(0xBB); + IRQ_enableUartRx(0); + IRQ_enableUartRx(1); + // Loop, waiting for the interrupt to change reg_mprj_datah + is_pass = 0; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x2E); //test fail interrupt isn't suppose to happened + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x2B); // test pass + } + // test finish + set_debug_reg2(0xFF); +} + diff --git a/verilog/dv/cocotb/all_tests/irq/IRQ_uart_rx.py b/verilog/dv/cocotb/all_tests/irq/IRQ_uart_rx.py new file mode 100644 index 000000000..a68d65cc2 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/IRQ_uart_rx.py @@ -0,0 +1,84 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.interfaces.defsParser import Regs +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from caravel_cocotb.caravel_interfaces import UART +from user_design import configure_userdesign + + +async def write_reg_spi(caravelEnv, address, data): + await caravelEnv.enable_csb() + await caravelEnv.hk_write_byte(0x80) # Write stream command + await caravelEnv.hk_write_byte( + address + ) # Address (register 19 = GPIO bit-bang control) + await caravelEnv.hk_write_byte(data) # Data = 0x01 (enable bit-bang mode) + await caravelEnv.disable_csb() + + +reg = Regs() +"""Testbench of GPIO configuration through bit-bang method using the StriVe housekeeping SPI.""" + + +@cocotb.test() +@report_test +async def IRQ_uart_rx(dut): + caravelEnv = await test_configure(dut, timeout_cycles=659797) + debug_regs = await configure_userdesign(caravelEnv) + uart = UART(caravelEnv) + cocotb.log.info("[TEST] Start IRQ_uart_rx test") + pass_list = (0x1B, 0x2B) + fail_list = (0x1E, 0x2E) + phases_fails = 2 + phases_passes = 0 + reg1 = 0 # buffer + reg2 = 0 # buffer + + # IO[0] affects the uart selecting btw system and debug + caravelEnv.drive_gpio_in((0, 0), 0) + caravelEnv.drive_gpio_in((5, 5), 1) + while True: + if reg2 != debug_regs.read_debug_reg2(): + reg2 = debug_regs.read_debug_reg2() + if reg2 == 0xFF: # test finish + break + if reg2 == 0xAA: + cocotb.log.info("[TEST] start sending through uart") + await cocotb.start(uart.uart_send_char("B")) + + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + phases_passes += 1 + phases_fails -= 1 + if reg1 == 0x1B: + cocotb.log.info( + "[TEST] Pass interrupt is detected when uart is sending data" + ) + elif reg1 == 0x2B: + cocotb.log.info( + "[TEST] Pass interrupt isn't detected when uart isnt sending data" + ) + elif reg1 in fail_list: # pass phase + if reg1 == 0x1E: + cocotb.log.info( + "[TEST] Failed interrupt isn't detected uart is sending data" + ) + elif reg1 == 0x2E: + cocotb.log.error( + "[TEST] Failed interrupt is detected uart isnt sending data" + ) + else: + cocotb.log.error("[TEST] debug register 1 has illegal value") + await ClockCycles(caravelEnv.clk, 1) + + if phases_fails != 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) diff --git a/verilog/dv/cocotb/all_tests/irq/user0_irq.c b/verilog/dv/cocotb/all_tests/irq/user0_irq.c new file mode 100644 index 000000000..0eaea7aa0 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/user0_irq.c @@ -0,0 +1,67 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + + + +void main(){ + enable_debug(); + + GPIOs_loadConfigs(); + IRQ_enableUser0(1); + + // test interrrupt happen when mprj[7] is asserted + IRQ_clearFlag(); + set_debug_reg2(0xAA); //wait for environment to make irq[1] high + // Loop, waiting for the interrupt to change reg_mprj_datah + char is_pass = 0; + int timeout = 40; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x1B); //test pass irq sent at mprj 7 + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x1E); // timeout + } + + // test interrupt doesn't happened when mprj[7] is deasserted + set_debug_reg2(0xBB); + IRQ_enableUser0(0); + IRQ_enableUser0(1); + // Loop, waiting for the interrupt to change reg_mprj_datah + is_pass = 0; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x2E); //test fail interrupt isn't suppose to happened + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x2B); // test pass + } + + // test finish + set_debug_reg2(0xFF); +} diff --git a/verilog/dv/cocotb/all_tests/irq/user1_irq.c b/verilog/dv/cocotb/all_tests/irq/user1_irq.c new file mode 100644 index 000000000..57e956046 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/user1_irq.c @@ -0,0 +1,67 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + + + +void main(){ + enable_debug(); + + GPIOs_loadConfigs(); + IRQ_enableUser1(1); + + // test interrrupt happen when mprj[7] is asserted + IRQ_clearFlag(); + set_debug_reg2(0xAA); //wait for environment to make irq[1] high + // Loop, waiting for the interrupt to change reg_mprj_datah + char is_pass = 0; + int timeout = 40; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x1B); //test pass irq sent at mprj 7 + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x1E); // timeout + } + + // test interrupt doesn't happened when mprj[7] is deasserted + set_debug_reg2(0xBB); + IRQ_enableUser1(0); + IRQ_enableUser1(1); + // Loop, waiting for the interrupt to change reg_mprj_datah + is_pass = 0; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x2E); //test fail interrupt isn't suppose to happened + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x2B); // test pass + } + + // test finish + set_debug_reg2(0xFF); +} diff --git a/verilog/dv/cocotb/all_tests/irq/user2_irq.c b/verilog/dv/cocotb/all_tests/irq/user2_irq.c new file mode 100644 index 000000000..88f9235f3 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/user2_irq.c @@ -0,0 +1,67 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + + + +void main(){ + enable_debug(); + + GPIOs_loadConfigs(); + IRQ_enableUser2(1); + + // test interrrupt happen when mprj[7] is asserted + IRQ_clearFlag(); + set_debug_reg2(0xAA); //wait for environment to make irq[1] high + // Loop, waiting for the interrupt to change reg_mprj_datah + char is_pass = 0; + int timeout = 40; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x1B); //test pass irq sent at mprj 7 + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x1E); // timeout + } + + // test interrupt doesn't happened when mprj[7] is deasserted + set_debug_reg2(0xBB); + IRQ_enableUser2(0); + IRQ_enableUser2(1); + // Loop, waiting for the interrupt to change reg_mprj_datah + is_pass = 0; + + for (int i = 0; i < timeout; i++){ + if (IRQ_getFlag() == 1){ + set_debug_reg1(0x2E); //test fail interrupt isn't suppose to happened + is_pass = 1; + break; + } + } + if (!is_pass){ + set_debug_reg1(0x2B); // test pass + } + + // test finish + set_debug_reg2(0xFF); +} diff --git a/verilog/dv/cocotb/all_tests/irq/user_irq.py b/verilog/dv/cocotb/all_tests/irq/user_irq.py new file mode 100644 index 000000000..e152d5839 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/irq/user_irq.py @@ -0,0 +1,88 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from user_design import configure_userdesign + +"""Testbench of GPIO configuration through bit-bang method using the StriVe housekeeping SPI.""" + + +@cocotb.test() +@report_test +async def user0_irq(dut): + await user_irq(dut, 0) + +@cocotb.test() +@report_test +async def user1_irq(dut): + await user_irq(dut, 1) + +@cocotb.test() +@report_test +async def user2_irq(dut): + await user_irq(dut, 2) + + +async def user_irq(dut, irq_num): + caravelEnv = await test_configure(dut, timeout_cycles=295956) + debug_regs = await configure_userdesign(caravelEnv) + caravelEnv.user_hdl.irq0.value = 0 + caravelEnv.user_hdl.irq1.value = 0 + caravelEnv.user_hdl.irq2.value = 0 + cocotb.log.info("[TEST] Start user0_irq test") + pass_list = (0x1B, 0x2B) + fail_list = (0x1E, 0x2E) + phases_fails = 2 + phases_passes = 0 + reg1 = 0 # buffer + reg2 = 0 # buffer + while True: + if reg2 != debug_regs.read_debug_reg2(): + reg2 = debug_regs.read_debug_reg2() + if reg2 == 0xFF: # test finish + break + if reg2 == 0xAA: # trigger irq + if irq_num == 0: + caravelEnv.user_hdl.irq0.value = 1 + elif irq_num == 1: + caravelEnv.user_hdl.irq1.value = 1 + elif irq_num == 2: + caravelEnv.user_hdl.irq2.value = 1 + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + phases_passes += 1 + phases_fails -= 1 + if reg1 == 0x1B: + cocotb.log.info( + "[TEST] Pass interrupt is detected when user irq1 triggered" + ) + caravelEnv.user_hdl.irq0.value = 0 + caravelEnv.user_hdl.irq1.value = 0 + caravelEnv.user_hdl.irq2.value = 0 + elif reg1 == 0x2B: + cocotb.log.info( + "[TEST] Pass interrupt isn't detected user irq1 cleared" + ) + elif reg1 in fail_list: # pass phase + if reg1 == 0x1E: + cocotb.log.error( + "[TEST] Failed interrupt isn't when user irq1 triggered" + ) + elif reg1 == 0x2E: + cocotb.log.error( + "[TEST] Failed interrupt is detected user irq1 cleared" + ) + else: + cocotb.log.error("[TEST] debug register 1 has illegal value") + await ClockCycles(caravelEnv.clk, 1) + + if phases_fails != 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/logicAnalyzer/.vscode/c_cpp_properties.json b/verilog/dv/cocotb/all_tests/logicAnalyzer/.vscode/c_cpp_properties.json new file mode 100644 index 000000000..862aed879 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/logicAnalyzer/.vscode/c_cpp_properties.json @@ -0,0 +1,16 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "gnu17", + "cppStandard": "gnu++14", + "intelliSenseMode": "linux-gcc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/logicAnalyzer/la.c b/verilog/dv/cocotb/all_tests/logicAnalyzer/la.c new file mode 100644 index 000000000..ce510fd11 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/logicAnalyzer/la.c @@ -0,0 +1,165 @@ + +#include + + +/* +user exmple +assign la0 to la1 if la0 output enable +assign la1 to la0 if la1 output enable +assign la2 to la3 if la2 output enable +assign la3 to la2 if la3 output enable +*/ +void main(){ + enable_debug(); + enableHkSpi(0); + + // Configure LA probes [63:32] and [127:96] as inputs to the cpu + // Configure LA probes [31:0] and [63:32] as outputs from the cpu + // 0 as input + LogicAnalyzer_inputEnable(0,0xFFFFFFFF); + LogicAnalyzer_outputEnable(0,0x0); + // 1 as output + LogicAnalyzer_inputEnable(1,0x0); + LogicAnalyzer_outputEnable(1,0xFFFFFFFF); + // 2 as input + LogicAnalyzer_inputEnable(2,0xFFFFFFFF); + LogicAnalyzer_outputEnable(2,0x0); + // 3 as output + LogicAnalyzer_inputEnable(3,0x0); + LogicAnalyzer_outputEnable(3,0xFFFFFFFF); + // set LA 0,2 + LogicAnalyzer_write(0,0xAAAAAAAA); + LogicAnalyzer_write(2,0xAAAAAAAA); + + #if LA_SIZE >= 64 + set_debug_reg2(LogicAnalyzer_read(1)); + if (LogicAnalyzer_read(1) != 0xAAAAAAAA) + set_debug_reg1(0x1E); + else + set_debug_reg1(0x1B); + #endif + + #if LA_SIZE >= 128 + set_debug_reg2(LogicAnalyzer_read(3)); + if (LogicAnalyzer_read(3) != 0xAAAAAAAA) + set_debug_reg1(0x2E); + else + set_debug_reg1(0x2B); + #endif + + // set LA 0,2 + LogicAnalyzer_write(0,0x55555555); + LogicAnalyzer_write(2,0x55555555); + + #if LA_SIZE >= 64 + set_debug_reg2(LogicAnalyzer_read(1)); + if (LogicAnalyzer_read(1) != 0x55555555) + set_debug_reg1(0x3E); + else + set_debug_reg1(0x3B); + #endif + + #if LA_SIZE >= 128 + set_debug_reg2(LogicAnalyzer_read(3)); + if (LogicAnalyzer_read(3) != 0x55555555) + set_debug_reg1(0x4E); + else + set_debug_reg1(0x4B); + #endif + + // to make sure all transations from 1 to 0 happen + LogicAnalyzer_write(0,0xAAAAAAAA); + LogicAnalyzer_write(2,0xAAAAAAAA); + + #if LA_SIZE >= 64 + set_debug_reg2(LogicAnalyzer_read(1)); + if (LogicAnalyzer_read(1) != 0xAAAAAAAA) + set_debug_reg1(0x5E); + else + set_debug_reg1(0x5B); + #endif + + #if LA_SIZE >= 128 + set_debug_reg2(LogicAnalyzer_read(3)); + if (LogicAnalyzer_read(3) != 0xAAAAAAAA) + set_debug_reg1(0x6E); + else + set_debug_reg1(0x6B); + #endif + // Configure LA probes [31:0] and [63:32] as inputs to the cpu + // Configure LA probes [63:32] and [127:96] as outputs from the cpu + // 0 as output + LogicAnalyzer_inputEnable(0,0x0); + LogicAnalyzer_outputEnable(0,0xFFFFFFFF); + // 1 as input + LogicAnalyzer_inputEnable(1,0xFFFFFFFF); + LogicAnalyzer_outputEnable(1,0x0); + // 2 as output + LogicAnalyzer_inputEnable(2,0x0); + LogicAnalyzer_outputEnable(2,0xFFFFFFFF); + // 3 as input + LogicAnalyzer_inputEnable(3,0xFFFFFFFF); + LogicAnalyzer_outputEnable(3,0x0); + + // set LA 1,3 + LogicAnalyzer_write(1,0xAAAAAAAA); + LogicAnalyzer_write(3,0xAAAAAAAA); + + #if LA_SIZE >= 64 + set_debug_reg2(LogicAnalyzer_read(0)); + if (LogicAnalyzer_read(0) != 0xAAAAAAAA) + set_debug_reg1(0x7E); + else + set_debug_reg1(0x7B); + #endif + #if LA_SIZE >= 128 + set_debug_reg2(LogicAnalyzer_read(2)); + if (LogicAnalyzer_read(2) != 0xAAAAAAAA) + set_debug_reg1(0x8E); + else + set_debug_reg1(0x8B); + #endif + + LogicAnalyzer_write(1,0x55555555); + LogicAnalyzer_write(3,0x55555555); + #if LA_SIZE >= 64 + set_debug_reg2(LogicAnalyzer_read(0)); + if (LogicAnalyzer_read(0) != 0x55555555) + set_debug_reg1(0x9E); + else + set_debug_reg1(0x9B); + #endif + + #if LA_SIZE >= 128 + set_debug_reg2(LogicAnalyzer_read(2)); + if (LogicAnalyzer_read(2) != 0x55555555) + set_debug_reg1(0xaE); + else + set_debug_reg1(0xaB); + #endif + + // to make sure all transations from 1 to 0 happen + LogicAnalyzer_write(1,0xAAAAAAAA); + LogicAnalyzer_write(3,0xAAAAAAAA); + #if LA_SIZE >= 64 + set_debug_reg2(LogicAnalyzer_read(0)); + if (LogicAnalyzer_read(0) != 0xAAAAAAAA) + set_debug_reg1(0xbE); + else + set_debug_reg1(0xbB); + #endif + + #if LA_SIZE >= 128 + set_debug_reg2(LogicAnalyzer_read(2)); + if (LogicAnalyzer_read(2) != 0xAAAAAAAA) + set_debug_reg1(0xcE); + else + set_debug_reg1(0xcB); + #endif + + + set_debug_reg2(0xFF); + + dummyDelay(100000000); + +} diff --git a/verilog/dv/cocotb/all_tests/logicAnalyzer/la.py b/verilog/dv/cocotb/all_tests/logicAnalyzer/la.py new file mode 100644 index 000000000..f583751cf --- /dev/null +++ b/verilog/dv/cocotb/all_tests/logicAnalyzer/la.py @@ -0,0 +1,47 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from user_design import configure_userdesign + + +@cocotb.test() +@report_test +async def la(dut): + caravelEnv = await test_configure(dut, timeout_cycles=321175) + debug_regs = await configure_userdesign(caravelEnv, la_test=True) + pass_list = (0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0x8B, 0x9B, 0xaB, 0xbB, 0xcB) + fail_list = (0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, 0x8E, 0x9E, 0xaE, 0xbE, 0xcE) + phases_fails = 12 + if int(caravelEnv.design_macros.LA_SIZE) < 128: + phases_fails = 4 + phases_passes = 0 + reg1 = 0 # buffer + # await ClockCycles(caravelEnv.clk,11200) + while True: + if debug_regs.read_debug_reg2() == 0xFF: # test finish + break + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + phases_passes += 1 + phases_fails -= 1 + cocotb.log.info(f"[TEST] test passes phase {hex(reg1)[2]}") + elif reg1 in fail_list: # fail phase + cocotb.log.error( + f"[TEST] test fails phase {hex(reg1)[2]} incorrect value recieved {hex(debug_regs.read_debug_reg2())}" + ) + + await ClockCycles(caravelEnv.clk, 1) + + if phases_fails != 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + + await ClockCycles(caravelEnv.clk, 100) diff --git a/verilog/dv/cocotb/all_tests/mem/mem_dff2_B.c b/verilog/dv/cocotb/all_tests/mem/mem_dff2_B.c new file mode 100644 index 000000000..37f0c64bf --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mem/mem_dff2_B.c @@ -0,0 +1,34 @@ +#include + + +void main(){ + enable_debug(); + unsigned char *dff2_start_address = (unsigned char *) DFF2_START_ADDR; + unsigned int dff2_size = DFF2_SIZE; + unsigned char data = 0x55; + for (unsigned int i = 0; i < dff2_size; i++){ + *(dff2_start_address+i) = data; + } + for (unsigned int i = 0; i < dff2_size; i++){ + if (data != *(dff2_start_address+i)){ + set_debug_reg2(dff2_start_address + i); + set_debug_reg1(0x1E); + return; + } + } + + data = 0xAA; + for (unsigned int i = 0; i < dff2_size; i++){ + *(dff2_start_address+i) = data; + } + for (unsigned int i = 0; i < dff2_size; i++){ + if (data != *(dff2_start_address+i)){ + set_debug_reg2(dff2_start_address + i); + set_debug_reg1(0x1E); + return; + } + } + + set_debug_reg1(0x1B); + +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/mem/mem_dff2_HW.c b/verilog/dv/cocotb/all_tests/mem/mem_dff2_HW.c new file mode 100644 index 000000000..8b7a87455 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mem/mem_dff2_HW.c @@ -0,0 +1,34 @@ +#include + + +void main(){ + enable_debug(); + unsigned short *dff2_start_address = (unsigned short *) DFF2_START_ADDR; + unsigned int dff2_size = DFF2_SIZE / 2; + unsigned short data = 0x5555; + for (unsigned int i = 0; i < dff2_size; i++){ + *(dff2_start_address+i) = data; + } + for (unsigned int i = 0; i < dff2_size; i++){ + if (data != *(dff2_start_address+i)){ + set_debug_reg2(dff2_start_address + i); + set_debug_reg1(0x1E); + return; + } + } + + data = 0xAAAA; + for (unsigned int i = 0; i < dff2_size; i++){ + *(dff2_start_address+i) = data; + } + for (unsigned int i = 0; i < dff2_size; i++){ + if (data != *(dff2_start_address+i)){ + set_debug_reg2(dff2_start_address + i); + set_debug_reg1(0x1E); + return; + } + } + + set_debug_reg1(0x1B); + +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/mem/mem_dff2_W.c b/verilog/dv/cocotb/all_tests/mem/mem_dff2_W.c new file mode 100644 index 000000000..686f05d9f --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mem/mem_dff2_W.c @@ -0,0 +1,49 @@ +#include + + +void main(){ + enable_debug(); + unsigned int *dff2_start_address = (unsigned int *) DFF2_START_ADDR; + unsigned int dff2_size = DFF2_SIZE / 4; + unsigned int data = 0x55555555; + unsigned int mask = 0xFFFFFFFF; + unsigned int shifting =0; + unsigned int data_used = 0; + for (unsigned int i = 0; i < dff2_size; i++){ + shifting = mask - (0x1 << i%32); + data_used = data & shifting; + data_used = data_used | i; // to dectect if rollover to the address happened before size reached + *(dff2_start_address+i) = data_used; + } + for (unsigned int i = 0; i < dff2_size; i++){ + shifting = mask - (0x1 << i%32); + data_used = data & shifting; + data_used = data_used | i; // to dectect if rollover to the address happened before size reached + if (data_used != *(dff2_start_address+i)){ + set_debug_reg2(dff2_start_address + i); + set_debug_reg1(0x1E); + return; + } + } + + data = 0xAAAAAAAA; + for (unsigned int i = 0; i < dff2_size; i++){ + shifting = mask - (0x1 << i%32); + data_used = data & shifting; + data_used = data_used | i; // to dectect if rollover to the address happened before size reached + *(dff2_start_address+i) = data_used; + } + for (unsigned int i = 0; i < dff2_size; i++){ + shifting = mask - (0x1 << i%32); + data_used = data & shifting; + data_used = data_used | i; // to dectect if rollover to the address happened before size reached + if (data_used != *(dff2_start_address+i)){ + set_debug_reg2(dff2_start_address + i); + set_debug_reg1(0x1E); + return; + } + } + + set_debug_reg1(0x1B); + +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/mem/mem_dff_B.c b/verilog/dv/cocotb/all_tests/mem/mem_dff_B.c new file mode 100644 index 000000000..6f4b3ab1a --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mem/mem_dff_B.c @@ -0,0 +1,34 @@ +#include + + +void main(){ + enable_debug(); + unsigned char *dff_start_address = (unsigned char *) DFF1_START_ADDR; + unsigned int dff_size = DFF1_SIZE; + unsigned char data = 0x55; + for (unsigned int i = 0; i < dff_size; i++){ + *(dff_start_address+i) = data; + } + for (unsigned int i = 0; i < dff_size; i++){ + if (data != *(dff_start_address+i)){ + set_debug_reg2(dff_start_address + i); + set_debug_reg1(0x1E); + return; + } + } + + data = 0xAA; + for (unsigned int i = 0; i < dff_size; i++){ + *(dff_start_address+i) = data; + } + for (unsigned int i = 0; i < dff_size; i++){ + if (data != *(dff_start_address+i)){ + set_debug_reg2(dff_start_address + i); + set_debug_reg1(0x1E); + return; + } + } + + set_debug_reg1(0x1B); +} + diff --git a/verilog/dv/cocotb/all_tests/mem/mem_dff_HW.c b/verilog/dv/cocotb/all_tests/mem/mem_dff_HW.c new file mode 100644 index 000000000..c25deaed0 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mem/mem_dff_HW.c @@ -0,0 +1,33 @@ +#include + + +void main(){ + enable_debug(); + unsigned short *dff_start_address = (unsigned short *) DFF1_START_ADDR; + unsigned int dff_size = DFF1_SIZE / 2; + unsigned short data = 0x5555; + for (unsigned int i = 0; i < dff_size; i++){ + *(dff_start_address+i) = data; + } + for (unsigned int i = 0; i < dff_size; i++){ + if (data != *(dff_start_address+i)){ + set_debug_reg2(dff_start_address + i); + set_debug_reg1(0x1E); + return; + } + } + + data = 0xAAAA; + for (unsigned int i = 0; i < dff_size; i++){ + *(dff_start_address+i) = data; + } + for (unsigned int i = 0; i < dff_size; i++){ + if (data != *(dff_start_address+i)){ + set_debug_reg2(dff_start_address + i); + set_debug_reg1(0x1E); + return; + } + } + + set_debug_reg1(0x1B); +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/mem/mem_dff_W.c b/verilog/dv/cocotb/all_tests/mem/mem_dff_W.c new file mode 100644 index 000000000..7dd44a52f --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mem/mem_dff_W.c @@ -0,0 +1,46 @@ +#include + + +void main(){ + enable_debug(); + #define dff_start_address (*(unsigned int*)0x0) + dff_start_address = DFF1_START_ADDR; + #define dff_size (*(unsigned int*)0x4) + dff_size = DFF1_SIZE /4; + + #define shifting (*(unsigned int*)0x8) + #define data_used (*(unsigned int*)0xC) + #define i (*(volatile uint32_t*)0x10) + + for (i = 0x14; i < dff_size; i++){ + shifting = 0xFFFFFFFF - (0x1 << i%32); + data_used = 0x55555555 & shifting; + *((unsigned int *) dff_start_address+i) = data_used; + } + for (i = 0x14; i < dff_size; i++){ + shifting = 0xFFFFFFFF - (0x1 << i%32); + data_used = 0x55555555 & shifting; + if (data_used != *((unsigned int *) dff_start_address+i)){ + set_debug_reg2(dff_start_address+ i); + set_debug_reg1(0x1E); + return; + } + } + + for (i = 0x14; i < dff_size; i++){ + shifting = 0xFFFFFFFF - (0x1 << i%32); + data_used = 0xAAAAAAAA & shifting; + *((unsigned int *)dff_start_address+i) = data_used; + } + for (i = 0x14; i < dff_size; i++){ + shifting = 0xFFFFFFFF - (0x1 << i%32); + data_used = 0xAAAAAAAA & shifting; + if (data_used != *((unsigned int *)dff_start_address+i)){ + set_debug_reg2((unsigned int *)dff_start_address+ i); + set_debug_reg1(0x1E); + return; + } + } + + set_debug_reg1(0x1B); +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/mem/mem_sram_B.c b/verilog/dv/cocotb/all_tests/mem/mem_sram_B.c new file mode 100644 index 000000000..06a745b65 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mem/mem_sram_B.c @@ -0,0 +1,42 @@ +#include + +void main() +{ + #ifdef ARM // ARM use dirrent location + reg_wb_enable =0x8; // for enable writing to reg_debug_1 and reg_debug_2 + #else + reg_wb_enable =1; // for enable writing to reg_debug_1 and reg_debug_2 + #endif + reg_debug_1 = 0x0; + reg_debug_2 = 0x0; + #define dff_size (*(volatile uint32_t*)0x0) + #define iterator (*(volatile uint32_t*)0x4) // first address in the ram store the iterator + dff_size = 0x800; + for (iterator = 8; iterator < dff_size; iterator++){ + // reg_debug_2 = iterator; + *((unsigned char *) 0x00000000+iterator) = 0x55; + } + for (iterator = 8; iterator < dff_size; iterator++){ + // reg_debug_2 = iterator; + if (*((unsigned char *) 0x00000000+iterator) != 0x55){ + reg_debug_2 = iterator; + reg_debug_1 = 0x1E; + return; + } + } + + for (iterator = 8; iterator < dff_size; iterator++){ + // reg_debug_2 = iterator; + *((unsigned char *) 0x00000000+iterator) = 0xAA; + } + for (iterator = 8; iterator < dff_size; iterator++){ + // reg_debug_2 = iterator; + if (*((unsigned char *) 0x00000000+iterator) != 0xAA){ + // reg_debug_2 = iterator; + reg_debug_1 = 0x1E; + return; + } + } + + reg_debug_1 = 0x1B; +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/mem/mem_sram_HW.c b/verilog/dv/cocotb/all_tests/mem/mem_sram_HW.c new file mode 100644 index 000000000..7f871fe95 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mem/mem_sram_HW.c @@ -0,0 +1,43 @@ +#include + +void main() +{ + #ifdef ARM // ARM use dirrent location + reg_wb_enable =0x8; // for enable writing to reg_debug_1 and reg_debug_2 + #else + reg_wb_enable =1; // for enable writing to reg_debug_1 and reg_debug_2 + #endif + reg_debug_1 = 0x0; + reg_debug_2 = 0x0; + #define dff_size (*(volatile uint32_t*)0x0) + #define iterator (*(volatile uint32_t*)0x4) // first address in the ram store the iterator + dff_size = 0x400; + for (iterator = 8; iterator < dff_size; iterator++){ + // reg_debug_2 = iterator; + *((unsigned short *) 0x00000000+iterator) = 0x5555; + + } + for (iterator = 8; iterator < dff_size; iterator++){ + // reg_debug_2 = iterator; + if (*((unsigned short *) 0x00000000+iterator) != 0x5555){ + reg_debug_2 = iterator; + reg_debug_1 = 0x1E; + return; + } + } + + for (iterator = 8; iterator < dff_size; iterator++){ + // reg_debug_2 = iterator; + *((unsigned short *) 0x00000000+iterator) = 0xAAAA; + } + for (iterator = 8; iterator < dff_size; iterator++){ + // reg_debug_2 = iterator; + if (*((unsigned short *) 0x00000000+iterator) != 0xAAAA){ + // reg_debug_2 = iterator; + reg_debug_1 = 0x1E; + return; + } + } + + reg_debug_1 = 0x1B; +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/mem/mem_sram_W.c b/verilog/dv/cocotb/all_tests/mem/mem_sram_W.c new file mode 100644 index 000000000..448e43766 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mem/mem_sram_W.c @@ -0,0 +1,43 @@ +#include + +void main() +{ + #ifdef ARM // ARM use dirrent location + reg_wb_enable =0x8; // for enable writing to reg_debug_1 and reg_debug_2 + #else + reg_wb_enable =1; // for enable writing to reg_debug_1 and reg_debug_2 + #endif + reg_debug_1 = 0; + reg_debug_2 = 0; + + #define dff_size (*(volatile uint32_t*)0x0) + dff_size = 0x200; + #define iterator (*(volatile uint32_t*)0x4) // first address in the ram store the iterator + iterator = 0; + for (iterator = 8; iterator < dff_size; iterator++ ){ + // reg_debug_2 = iterator; + *((unsigned int *) 0x00000000 + iterator) = 0x55555555; + } + for (iterator = 8; iterator < dff_size; iterator++ ){ + // reg_debug_2 = iterator; + if (*((unsigned int *) 0x00000000 + iterator) != 0x55555555){ + reg_debug_2 = iterator; + reg_debug_1 = 0x1E; + return; + } + } + for (iterator = 8; iterator < dff_size; iterator++ ){ + // reg_debug_2 = iterator; + *((unsigned int *) 0x00000000 + iterator) = 0xAAAAAAAA; + } + for (iterator = 8; iterator < dff_size; iterator++ ){ + // reg_debug_2 = iterator; + if (*((unsigned int *) 0x00000000 + iterator) != 0xAAAAAAAA){ + // reg_debug_2 = iterator; + reg_debug_1 = 0x1E; + return; + } + } + + reg_debug_1 = 0x1B; +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/mem/mem_sram_smoke.c b/verilog/dv/cocotb/all_tests/mem/mem_sram_smoke.c new file mode 100644 index 000000000..408d49c48 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mem/mem_sram_smoke.c @@ -0,0 +1,64 @@ +#include + +void main() +{ + #ifdef ARM // ARM use dirrent location + reg_wb_enable =0x8; // for enable writing to reg_debug_1 and reg_debug_2 + #else + reg_wb_enable =1; // for enable writing to reg_debug_1 and reg_debug_2 + #endif + reg_debug_1 = 0; + reg_debug_2 = 0; + + #define dff_size (*(volatile uint32_t*)0x0) + dff_size = 0x70; + #define iterator (*(volatile uint32_t*)0x4) // first address in the ram store the iterator + iterator = 0; + // word access + for (iterator = 8; iterator < dff_size; iterator+=7 ){ + // reg_debug_2 = iterator; + *((unsigned int *) 0x00000000+iterator) = 0x55555555; + } + for (iterator = 8; iterator < dff_size; iterator+=7 ){ + // reg_debug_2 = iterator; + if (*((unsigned int *) 0x00000000+iterator) != 0x55555555){ + reg_debug_2 = iterator; + reg_debug_1 = 0x1E; + return; + } + } + + // half word + dff_size = 0x210; + for (iterator = 0x140; iterator < dff_size; iterator+=7 ){ + // reg_debug_2 = iterator; + *((unsigned short *) 0x00000000+iterator) = 0xAAAA; + } + for (iterator = 0x140; iterator < dff_size; iterator+=7 ){ + // reg_debug_2 = iterator; + if (*((unsigned short *) 0x00000000+iterator) != 0xAAAA){ + // reg_debug_2 = iterator; + reg_debug_1 = 0x1E; + return; + } + } + + // byte + + dff_size = 0x630; + for (iterator = 0x560; iterator < dff_size; iterator+=7){ + // reg_debug_2 = iterator; + *((unsigned char *) 0x00000000+iterator) = 0x55; + } + for (iterator = 0x560; iterator < dff_size; iterator+=7){ + // reg_debug_2 = iterator; + if (*((unsigned char *) 0x00000000+iterator) != 0x55){ + reg_debug_2 = iterator; + reg_debug_1 = 0x1E; + return; + } + } + + + reg_debug_1 = 0x1B; +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/mem/mem_stress.py b/verilog/dv/cocotb/all_tests/mem/mem_stress.py new file mode 100644 index 000000000..8022a2dae --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mem/mem_stress.py @@ -0,0 +1,255 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from user_design import configure_userdesign + + +@cocotb.test() +@report_test +async def mem_dff2_W(dut): + caravelEnv = await test_configure(dut, timeout_cycles=3478259) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start mem dff2 word access stress test") + pass_list = [0x1B] + fail_list = [0x1E] + reg1 = 0 # buffer + while True: + if debug_regs.read_debug_reg1() == 0xFF: # test finish + break + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + cocotb.log.info("[TEST] pass writing and reading all dff2 memory ") + break + elif reg1 in fail_list: # pass phase + cocotb.log.error( + f"[TEST] failed access address {hex(debug_regs.read_debug_reg2())}" + ) + break + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def mem_dff2_HW(dut): + caravelEnv = await test_configure(dut, timeout_cycles=3931459) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start mem dff2 half word access stress test") + pass_list = [0x1B] + fail_list = [0x1E] + reg1 = 0 # buffer + while True: + if debug_regs.read_debug_reg1() == 0xFF: # test finish + break + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + cocotb.log.info("[TEST] pass writing and reading all dff2 memory ") + break + elif reg1 in fail_list: # pass phase + cocotb.log.error( + f"[TEST] failed access address {hex(debug_regs.read_debug_reg2())}" + ) + break + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def mem_dff2_B(dut): + caravelEnv = await test_configure(dut, timeout_cycles=5333959) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start mem dff2 Byte access stress test") + pass_list = [0x1B] + fail_list = [0x1E] + reg1 = 0 # buffer + while True: + if debug_regs.read_debug_reg1() == 0xFF: # test finish + break + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + cocotb.log.info("[TEST] pass writing and reading all dff2 memory ") + break + elif reg1 in fail_list: # pass phase + cocotb.log.error( + f"[TEST] failed access address {hex(debug_regs.read_debug_reg2())}" + ) + break + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def mem_dff_W(dut): + caravelEnv = await test_configure(dut, timeout_cycles=7219359) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start mem dff word access stress test") + pass_list = [0x1B] + fail_list = [0x1E] + reg1 = 0 # buffer + while True: + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + cocotb.log.info("[TEST] pass writing and reading all dff memory ") + break + elif reg1 in fail_list: # pass phase + cocotb.log.error( + f"[TEST] failed access address {hex(debug_regs.read_debug_reg2())}" + ) + break + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def mem_dff_HW(dut): + caravelEnv = await test_configure(dut, timeout_cycles=7817759) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start mem dff half word access stress test") + pass_list = [0x1B] + fail_list = [0x1E] + reg1 = 0 # buffer + while True: + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + cocotb.log.info("[TEST] pass writing and reading all dff memory ") + break + elif reg1 in fail_list: # pass phase + cocotb.log.error( + f"[TEST] failed access address {hex(debug_regs.read_debug_reg2())}" + ) + break + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def mem_dff_B(dut): + caravelEnv = await test_configure(dut, timeout_cycles=10640359) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start mem dff Byte access stress test") + pass_list = [0x1B] + fail_list = [0x1E] + reg1 = 0 # buffer + while True: + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + cocotb.log.info("[TEST] pass writing and reading all dff memory ") + break + elif reg1 in fail_list: # pass phase + cocotb.log.error( + f"[TEST] failed access address {hex(debug_regs.read_debug_reg2())}" + ) + break + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def mem_sram_W(dut): + caravelEnv = await test_configure(dut, timeout_cycles=118083081) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start sram word access stress test") + pass_list = [0x1B] + fail_list = [0x1E] + reg1 = 0 # buffer + reg2 = 0 + while True: + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + cocotb.log.info("[TEST] pass writing and reading all sram memory") + break + elif reg1 in fail_list: # pass phase + cocotb.log.error( + f"[TEST] failed access address {hex(debug_regs.read_debug_reg2())}" + ) + break + if reg2 != debug_regs.read_debug_reg2(): + reg2 = debug_regs.read_debug_reg2() + cocotb.log.info(f"[TEST] iterator = {hex(reg2)} ") + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def mem_sram_HW(dut): + caravelEnv = await test_configure(dut, timeout_cycles=1116274181) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start sram halfword access stress test") + pass_list = [0x1B] + fail_list = [0x1E] + reg1 = 0 # buffer + while True: + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + cocotb.log.info("[TEST] pass writing and reading all srram memory") + break + elif reg1 in fail_list: # pass phase + cocotb.log.error( + f"[TEST] failed access address {hex(debug_regs.read_debug_reg2())}" + ) + break + # if reg2 != debug_regs.read_debug_reg2(): + # reg2 = debug_regs.read_debug_reg2() + # cocotb.log.info(f"[TEST] iterator = {hex(reg2)} ") + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def mem_sram_B(dut): + caravelEnv = await test_configure(dut, timeout_cycles=1128500231) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start sram byte access stress test") + pass_list = [0x1B] + fail_list = [0x1E] + reg1 = 0 # buffer + while True: + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + cocotb.log.info("[TEST] pass writing and reading all sram memory ") + break + elif reg1 in fail_list: # pass phase + cocotb.log.error( + "[TEST] failed access address {hex(debug_regs.read_debug_reg2())}" + ) + break + # if reg2 != debug_regs.read_debug_reg2(): + # reg2 = debug_regs.read_debug_reg2() + # cocotb.log.info(f"[TEST] iterator = {hex(reg2)} ") + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def mem_sram_smoke(dut): + caravelEnv = await test_configure(dut, timeout_cycles=11655541) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start sram smoke test") + pass_list = [0x1B] + fail_list = [0x1E] + reg1 = 0 # buffer + while True: + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + cocotb.log.info("[TEST] pass writing and reading all sram memory ") + break + elif reg1 in fail_list: # pass phase + cocotb.log.error( + f"[TEST] failed access address {hex(debug_regs.read_debug_reg2())}" + ) + break + # if reg2 != debug_regs.read_debug_reg2(): + # reg2 = debug_regs.read_debug_reg2() + # cocotb.log.info(f"[TEST] iterator = {hex(reg2)} ") + await ClockCycles(caravelEnv.clk, 1000) diff --git a/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio.py b/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio.py new file mode 100644 index 000000000..a55fe8c0a --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio.py @@ -0,0 +1,243 @@ +import random +import cocotb +from cocotb.triggers import ClockCycles, Edge +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test + +from user_design import configure_userdesign + +"""Testbench of GPIO configuration through bit-bang method using the StriVe housekeeping SPI.""" + + +@cocotb.test() +@report_test +async def mgmt_gpio_out(dut): + caravelEnv = await test_configure(dut, timeout_cycles=431562) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start mgmt_gpio_out test") + phases_fails = 3 + phases_passes = 0 + reg1 = 0 # buffer + reg2 = 0 # buffer + + while True: + if reg2 != debug_regs.read_debug_reg2(): + reg2 = debug_regs.read_debug_reg2() + if reg2 == 0xFF: # test finish + break + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + cocotb.log.info(f"[TEST] waiting for {reg1} blinks") + for i in range(reg1): + while True: + if caravelEnv.monitor_mgmt_gpio() == "0": + break + if reg1 != debug_regs.read_debug_reg1(): + cocotb.log.error( + f"[TEST] error failing to catch all blinking received: {i} expected: {reg1}" + ) + return + await ClockCycles(caravelEnv.clk, 1) + + while True: + if caravelEnv.monitor_mgmt_gpio() == "1": + break + if reg1 != debug_regs.read_debug_reg1(): + cocotb.log.error( + f"[TEST] error failing to catch all blinking received: {i} expected: {reg1}" + ) + return + await ClockCycles(caravelEnv.clk, 1) + cocotb.log.info(f"[TEST] passing sending {reg1} blinks ") + phases_fails -= 1 + phases_passes += 1 + await ClockCycles(caravelEnv.clk, 10) + + if phases_fails != 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + + +@cocotb.test() +@report_test +async def mgmt_gpio_in(dut): + caravelEnv = await test_configure(dut, timeout_cycles=1119535) + caravelEnv.drive_mgmt_gpio(0) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start mgmt_gpio_in test") + phases_fails = 3 + phases_passes = 0 + pass_list = (0x1B, 0x2B, 0xFF) + fail_list = tuple([0xEE]) + reg1 = 0 # buffer + reg2 = 0 # buffer + debug_regs = await configure_userdesign(caravelEnv) + + while True: + if reg2 != debug_regs.read_debug_reg2(): + reg2 = debug_regs.read_debug_reg2() + if reg2 in pass_list: + cocotb.log.info(f"[TEST] reg2 = {reg2}") + phases_passes += 1 + phases_fails -= 1 + if reg2 == 0xFF: # test finish + break + elif reg2 == 0x1B: + cocotb.log.info("[TEST] pass sending 10 blink ") + elif reg2 == 0x2B: + cocotb.log.info("[TEST] pass sending 20 blink ") + if reg2 in fail_list: + cocotb.log.error("[TEST] gpio change without sending anything") + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + cocotb.log.info(f"[TEST] start sending {reg1} blinks") + for i in range(reg1): + caravelEnv.drive_mgmt_gpio(1) + await debug_regs.wait_reg2(0xAA) + caravelEnv.drive_mgmt_gpio(0) + await debug_regs.wait_reg2(0xBB) + cocotb.log.info(f"[TEST] finish sending {reg1} blinks ") + await ClockCycles(caravelEnv.clk, 10) + + if phases_fails != 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + + +@cocotb.test() +@report_test +async def mgmt_gpio_bidir(dut): + caravelEnv = await test_configure(dut, timeout_cycles=1904514) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start mgmt_gpio_bidir test") + debug_regs = await configure_userdesign(caravelEnv) + await debug_regs.wait_reg1(0xAA) + num_blinks = random.randint(1, 20) + cocotb.log.info(f"[TEST] start send {num_blinks} blinks") + for i in range(num_blinks): + if i == num_blinks - 1: # last iteration + debug_regs.write_debug_reg1_backdoor(0xFF) + caravelEnv.drive_mgmt_gpio(1) + await ClockCycles(caravelEnv.clk, 30000) + caravelEnv.drive_mgmt_gpio(0) + if i != num_blinks - 1: # not last iteration + await ClockCycles(caravelEnv.clk, 30000) + else: + # caravelEnv.drive_mgmt_gpio('z') + await ClockCycles(caravelEnv.clk, 1) + + # caravelEnv.drive_mgmt_gpio('z') + cocotb.log.info(f"[TEST] finish sending {num_blinks} blinks ") + + cocotb.log.info(f"[TEST] waiting for {num_blinks} blinks ") + counter = [0] # list to pass by ref + await cocotb.start(blink_counter(caravelEnv.get_mgmt_gpi_hdl(), counter)) # forked + await debug_regs.wait_reg2(0xFF) + recieved_blinks = counter[0] + if recieved_blinks == num_blinks: + cocotb.log.info(f"[TEST] recieved the correct number of blinks {num_blinks}") + else: + cocotb.log.error( + f"[TEST] recieved the incorrect number of blinks recieved = {recieved_blinks} expected = {num_blinks}" + ) + cocotb.log.info(f"[TEST] counter = {counter}") + + +async def blink_counter(hdl, counter): + cocotb.log.info(f"[TEST] start Edge[{counter}]") + while True: + await Edge(hdl) + await Edge(hdl) + counter[0] += 1 + + +@cocotb.test() +@report_test +async def mgmt_gpio_pu_pd(dut): + caravelEnv = await test_configure(dut, timeout_cycles=66129) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start mgmt_gpio_pu_pd test") + debug_regs = await configure_userdesign(caravelEnv) + + await debug_regs.wait_reg1(0x1B) + # caravelEnv.drive_mgmt_gpio('z') + await ClockCycles(caravelEnv.clk, 1) + gpio_in = dut.uut.chip_core.soc.core.gpio_in_pad + if gpio_in.value.binstr != "1": + cocotb.log.error( + f"[TEST] mgmt gpio pull up didn't work correctly reading {gpio_in} instead of 1" + ) + + await debug_regs.wait_reg1(0x2B) + # caravelEnv.drive_mgmt_gpio('z') + await ClockCycles(caravelEnv.clk, 1) + if gpio_in.value.binstr != "0": + cocotb.log.error( + f"[TEST] mgmt gpio pull down didn't work correctly reading {gpio_in} instead of 0" + ) + + await debug_regs.wait_reg1(0x3B) + # caravelEnv.drive_mgmt_gpio('z') + await ClockCycles(caravelEnv.clk, 1) + if gpio_in.value.binstr != "x": + cocotb.log.error( + f"[TEST] mgmt gpio no pull didn't work correctly reading {gpio_in} instead of x" + ) + + +@cocotb.test() +@report_test +async def mgmt_gpio_disable(dut): + caravelEnv = await test_configure(dut, timeout_cycles=117797) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start mgmt_gpio_disable test") + phases_fails = 2 + phases_passes = 0 + pass_list = (0x1B, 0x2B) + fail_list = (0x1E, 0x2E) + reg2 = 0 # buffer + caravelEnv.drive_mgmt_gpio(1) + debug_regs = await configure_userdesign(caravelEnv) + while True: + caravelEnv.drive_mgmt_gpio(1) + if reg2 != debug_regs.read_debug_reg2(): + cocotb.log.info(f"[TEST] reg2 = {hex(reg2)}") + reg2 = debug_regs.read_debug_reg2() + if reg2 == 0xFF: # test finish + break + if reg2 in pass_list: + cocotb.log.info(f"[TEST] pass = {hex(reg2)}") + phases_passes += 1 + phases_fails -= 1 + if reg2 in fail_list: + cocotb.log.error(f"[TEST] fail = {hex(reg2)}") + await ClockCycles(caravelEnv.clk, 1) + caravelEnv.drive_mgmt_gpio("z") + + if phases_fails != 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + + await debug_regs.wait_reg1(0x1A) + if caravelEnv.monitor_mgmt_gpio() != "1": + cocotb.log.error("[TEST] mgmt gpio output enable but output isn't working") + + await debug_regs.wait_reg1(0x2A) + if caravelEnv.monitor_mgmt_gpio() == "1": + cocotb.log.error("[TEST] mgmt gpio disabled but output is working") diff --git a/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_bidir.c b/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_bidir.c new file mode 100644 index 000000000..8bc6daea9 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_bidir.c @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ +#include + + + +// -------------------------------------------------------- + +/* + * Management SoC GPIO Pin Test + * Tests writing to the GPIO pin. + */ + +void main(){ + enable_debug(); + enableHkSpi(0); + ManagmentGpio_inputEnable(); + int num_blinks = 0; + set_debug_reg1(0XAA); // start of the test + while (1) { + ManagmentGpio_wait(0); + ManagmentGpio_wait(1); + num_blinks++; + if (get_debug_reg1() == 0xFF) + break; + } + ManagmentGpio_outputEnable(); + for (int i = 0; i < num_blinks; i++) { + /* Fast blink for simulation */ + ManagmentGpio_write(1); + dummyDelay(10); + ManagmentGpio_write(0); + dummyDelay(10); + } + set_debug_reg2(0XFF); //finish test + dummyDelay(10000000); +} + diff --git a/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_disable.c b/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_disable.c new file mode 100644 index 000000000..e43ef6150 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_disable.c @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include + + +// -------------------------------------------------------- + +/* + * Management SoC GPIO Pin Test + * Tests writing to the GPIO pin. + */ + +void main() +{ + enable_debug(); + enableHkSpi(0); + // enable input + ManagmentGpio_inputEnable(); + if (ManagmentGpio_read() == 1) + set_debug_reg2(0x1B); + else + set_debug_reg2(0x1E); + // disable input + ManagmentGpio_disable(); + if (ManagmentGpio_read() == 0) + set_debug_reg2(0x2B); + else + set_debug_reg2(0x2E); + set_debug_reg2(0xFF); + + // enable output + ManagmentGpio_outputEnable(); + ManagmentGpio_write(1); + set_debug_reg1(0x1A); + + // disable output + ManagmentGpio_inputEnable(); + ManagmentGpio_write(1); + set_debug_reg1(0x2A); +} + diff --git a/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_in.c b/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_in.c new file mode 100644 index 000000000..ae5b1f607 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_in.c @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +// -------------------------------------------------------- + +/* + * Management SoC GPIO Pin Test + * Tests writing to the GPIO pin. + */ + +void main(){ + enable_debug(); + enableHkSpi(0); + ManagmentGpio_inputEnable(); + set_debug_reg1(10); // wait for 10 blinks + // dummyDelay(250); + for (int i = 0; i < 10; i++) { + ManagmentGpio_wait(0); + set_debug_reg2(0XAA); // 1 is recieved + ManagmentGpio_wait(1); + set_debug_reg2(0XBB); // 0 is recieved + } + set_debug_reg2(0x1B); + set_debug_reg1(20); + for (int i = 0; i < 20; i++) { + ManagmentGpio_wait(0); + set_debug_reg2(0XAA); // 1 is recieved + ManagmentGpio_wait(1); + set_debug_reg2(0XBB); // 0 is recieved + } + set_debug_reg2(0x2B); + int temp_in = ManagmentGpio_read(); + set_debug_reg1(0); + for (int i =0; i<50;i++){ // timeout + if (temp_in != ManagmentGpio_read()) + set_debug_reg2(0xEE); //finish test + } + set_debug_reg2(0xFF); //finish test +} + diff --git a/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_out.c b/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_out.c new file mode 100644 index 000000000..ac8fcd57c --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_out.c @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + + +// -------------------------------------------------------- + +/* + * Management SoC GPIO Pin Test + * Tests writing to the GPIO pin. + */ + +void main() +{ + enable_debug(); + enableHkSpi(0); + ManagmentGpio_outputEnable(); + set_debug_reg1(10); + for (int i = 0; i < 10; i++) { + /* Fast blink for simulation */ + ManagmentGpio_write(1); + ManagmentGpio_write(0); + } + set_debug_reg1(20); + for (int i = 0; i < 20; i++) { + /* Fast blink for simulation */ + ManagmentGpio_write(1); + ManagmentGpio_write(0); + } + set_debug_reg1(0); + set_debug_reg1(0); // for more delay + set_debug_reg1(0); + + set_debug_reg2(0xFF); //finish test + + +} + diff --git a/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_pu_pd.c b/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_pu_pd.c new file mode 100644 index 000000000..66034cda4 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/mgmt_gpio/mgmt_gpio_pu_pd.c @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + + +// -------------------------------------------------------- + +/* + * Management SoC GPIO Pin Test + * Tests writing to the GPIO pin. + */ + +void main() +{ + enable_debug(); + enableHkSpi(0); + ManagmentGpio_ioEnable(); + + // pull up + ManagmentGpio_write(1); + set_debug_reg1(0x1B); + + // pull down + ManagmentGpio_write(0); + set_debug_reg1(0x2B); + + // no pull + #ifndef REG_GPIO_INVERTED + reg_gpio_oe = 0; + #else + reg_gpio_oe = 1; + #endif + set_debug_reg1(0x3B); + + + +} + diff --git a/verilog/dv/cocotb/all_tests/shifting/serial_shifting_0011.c b/verilog/dv/cocotb/all_tests/shifting/serial_shifting_0011.c new file mode 100644 index 000000000..307d6da8b --- /dev/null +++ b/verilog/dv/cocotb/all_tests/shifting/serial_shifting_0011.c @@ -0,0 +1,38 @@ +#include + + +void main(){ + enable_debug(); + enableHkSpi(0); + int counter = 0; + for (int i =0;i<19;i++){ + if(counter == 0) + GPIOs_configure(i,0x1999); + else if (counter == 1) + GPIOs_configure(i,0x1333); + else if (counter == 2) + GPIOs_configure(i,0x666); + else if (counter == 3) + GPIOs_configure(i,0xCCC); + counter++; + counter %= 4; + } + counter =0; + for (int i =37;i>=19;i--){ + if(counter == 0) + GPIOs_configure(i,0x1999); + else if (counter == 1) + GPIOs_configure(i,0x1333); + else if (counter == 2) + GPIOs_configure(i,0x666); + else if (counter == 3) + GPIOs_configure(i,0xCCC); + counter++; + counter %= 4; + } + GPIOs_loadConfigs(); + dummyDelay(10); + set_debug_reg1(0XFF); // finish configuration + dummyDelay(10000); +} + diff --git a/verilog/dv/cocotb/all_tests/shifting/serial_shifting_01.c b/verilog/dv/cocotb/all_tests/shifting/serial_shifting_01.c new file mode 100644 index 000000000..5e1a17267 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/shifting/serial_shifting_01.c @@ -0,0 +1,26 @@ +#include + + + +void main(){ + enable_debug(); + enableHkSpi(0); + // write 01 + for (int i =0;i<19;i++){ + if(i % 2 == 0) + GPIOs_configure(i,0x1555); + else + GPIOs_configure(i,0xAAA); + } + for (int i =37;i>=19;i--){ + if(i % 2 != 0) + GPIOs_configure(i,0x1555); + else + GPIOs_configure(i,0xAAA); + } + GPIOs_loadConfigs(); + dummyDelay(10); + set_debug_reg1(0XFF); // finish configuration + dummyDelay(10000); +} + diff --git a/verilog/dv/cocotb/all_tests/shifting/serial_shifting_10.c b/verilog/dv/cocotb/all_tests/shifting/serial_shifting_10.c new file mode 100644 index 000000000..5f9857f78 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/shifting/serial_shifting_10.c @@ -0,0 +1,26 @@ +#include + + + +void main(){ + enable_debug(); + enableHkSpi(0); + // write 10 + for (int i =0;i<19;i++){ + if(i % 2 != 0) + GPIOs_configure(i,0x1555); + else + GPIOs_configure(i,0xAAA); + } + for (int i =37;i>=19;i--){ + if(i % 2 == 0) + GPIOs_configure(i,0x1555); + else + GPIOs_configure(i,0xAAA); + } + GPIOs_loadConfigs(); + dummyDelay(10); + set_debug_reg1(0XFF); // finish configuration + dummyDelay(10000); +} + diff --git a/verilog/dv/cocotb/all_tests/shifting/serial_shifting_1100.c b/verilog/dv/cocotb/all_tests/shifting/serial_shifting_1100.c new file mode 100644 index 000000000..682feb9d3 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/shifting/serial_shifting_1100.c @@ -0,0 +1,38 @@ +#include + + + +void main(){ + enable_debug(); + enableHkSpi(0); + int counter = 0; + for (int i =0;i<19;i++){ + if(counter == 0) + GPIOs_configure(i,0x666); + else if (counter == 1) + GPIOs_configure(i,0xccc); + else if (counter == 2) + GPIOs_configure(i,0x1999); + else if (counter == 3) + GPIOs_configure(i,0x1333); + counter++; + counter %= 4; + } + counter =0; + for (int i =37;i>=19;i--){ + if(counter == 0) + GPIOs_configure(i,0x666); + else if (counter == 1) + GPIOs_configure(i,0xccc); + else if (counter == 2) + GPIOs_configure(i,0x1999); + else if (counter == 3) + GPIOs_configure(i,0x1333); + counter++; + counter %= 4; + } + GPIOs_loadConfigs(); + dummyDelay(10); + set_debug_reg1(0XFF); // finish configuration + dummyDelay(10000); +} diff --git a/verilog/dv/cocotb/all_tests/shifting/shifting.py b/verilog/dv/cocotb/all_tests/shifting/shifting.py new file mode 100644 index 000000000..602802e77 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/shifting/shifting.py @@ -0,0 +1,518 @@ +import cocotb +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from user_design import configure_userdesign + + +def shift(gpio, shift_type, caravelEnv): + bit_size = int(caravelEnv.design_macros.IO_CTRL_BITS) + if shift_type: + bits = "0101010101010" + if bit_size != 13: + bits = bits[0:bit_size-1] + else: + bits = "1010101010101" + if bit_size != 13: + bits = bits[0:bit_size-1] + fail = False + gpio_to_skip = () + + if "CPU_TYPE_ARM" in caravelEnv.design_macros._asdict(): + gpio_to_skip = ( + "gpio_control_bidir_2[0]", + "gpio_control_bidir_2[1]", + "gpio_control_bidir_2[2]", + ) + + if str(gpio).split(".")[-1] in gpio_to_skip: + return + + if 'GL' not in caravelEnv.design_macros._asdict(): + cocotb.log.info( + f"[TEST] gpio {gpio} shift {gpio._id(f'shift_register',False).value} expected {bits}" + ) + for i in range(bit_size): + if 'GL' not in caravelEnv.design_macros._asdict(): + shift_register = gpio._id("shift_register", False).value.binstr[i] + else: + shift_register = ( + gpio[0] + ._id(f"\\{gpio[1]}.shift_register[{bit_size-1-i}] ", False) + .value.binstr + ) + if shift_register != bits[i]: + fail = True + cocotb.log.error(f"[TEST] wrong shift register {i} in {gpio}") + if not fail: + if 'GL' not in caravelEnv.design_macros._asdict(): + cocotb.log.info(f"[TEST] gpio {gpio} passed") + else: + cocotb.log.info(f"[TEST] gpio {gpio[1]} passed") + + +@cocotb.test() +@report_test +async def serial_shifting_10(dut): + caravelEnv = await test_configure(dut, timeout_cycles=540110) + debug_regs = await configure_userdesign(caravelEnv) + uut = dut.uut.chip_core + debug_regs = await configure_userdesign(caravelEnv) + await debug_regs.wait_reg1(0xFF) + gpios_l = ( + "gpio_control_bidir_1[0]", + "gpio_control_bidir_1[1]", + "gpio_control_in_1a[0]", + "gpio_control_in_1a[1]", + "gpio_control_in_1a[2]", + "gpio_control_in_1a[3]", + "gpio_control_in_1a[4]", + "gpio_control_in_1a[5]", + "gpio_control_in_1[0]", + "gpio_control_in_1[1]", + "gpio_control_in_1[2]", + "gpio_control_in_1[3]", + "gpio_control_in_1[4]", + "gpio_control_in_1[5]", + "gpio_control_in_1[6]", + "gpio_control_in_1[7]", + "gpio_control_in_1[8]", + "gpio_control_in_1[9]", + "gpio_control_in_1[10]", + ) + if 'CARAVAN' in caravelEnv.design_macros._asdict(): + gpios_l = ( + "gpio_control_bidir_1[0]", + "gpio_control_bidir_1[1]", + "gpio_control_in_1a[0]", + "gpio_control_in_1a[1]", + "gpio_control_in_1a[2]", + "gpio_control_in_1a[3]", + "gpio_control_in_1a[4]", + "gpio_control_in_1a[5]", + "gpio_control_in_1[0]", + "gpio_control_in_1[1]", + "gpio_control_in_1[2]", + "gpio_control_in_1[3]", + "gpio_control_in_1[4]", + "gpio_control_in_1[5]", + ) + + gpios_h = ( + "gpio_control_in_2[0]", + "gpio_control_in_2[1]", + "gpio_control_in_2[2]", + "gpio_control_in_2[3]", + "gpio_control_in_2[4]", + "gpio_control_in_2[5]", + "gpio_control_in_2[6]", + "gpio_control_in_2[7]", + "gpio_control_in_2[8]", + "gpio_control_in_2[9]", + "gpio_control_in_2[10]", + "gpio_control_in_2[11]", + "gpio_control_in_2[12]", + "gpio_control_in_2[13]", + "gpio_control_in_2[14]", + "gpio_control_in_2[15]", + "gpio_control_bidir_2[0]", + "gpio_control_bidir_2[1]", + "gpio_control_bidir_2[2]", + ) + if 'CARAVAN' in caravelEnv.design_macros._asdict(): + gpios_h = ( + "gpio_control_in_2[0]", + "gpio_control_in_2[1]", + "gpio_control_in_2[2]", + "gpio_control_in_2[3]", + "gpio_control_in_2[4]", + "gpio_control_in_2[5]", + "gpio_control_in_2[6]", + "gpio_control_in_2[7]", + "gpio_control_in_2[8]", + "gpio_control_in_2[9]", + "gpio_control_bidir_2[0]", + "gpio_control_bidir_2[1]", + "gpio_control_bidir_2[2]", + ) + + type = True # type of shifting 01 or 10 + for gpio in gpios_l: + if 'GL' not in caravelEnv.design_macros._asdict(): + shift(uut._id(gpio, False), type, caravelEnv) + else: + shift((uut, gpio), type, caravelEnv) + type = not type + type = True # type of shifting 01 or 10 + for gpio in reversed(gpios_h): + if 'GL' not in caravelEnv.design_macros._asdict(): + shift(uut._id(gpio, False), type, caravelEnv) + else: + shift((uut, gpio), type, caravelEnv) + type = not type + + +@cocotb.test() +@report_test +async def serial_shifting_01(dut): + caravelEnv = await test_configure(dut, timeout_cycles=541278) + debug_regs = await configure_userdesign(caravelEnv) + uut = dut.uut.chip_core + debug_regs = await configure_userdesign(caravelEnv) + await debug_regs.wait_reg1(0xFF) + gpios_l = ( + "gpio_control_bidir_1[0]", + "gpio_control_bidir_1[1]", + "gpio_control_in_1a[0]", + "gpio_control_in_1a[1]", + "gpio_control_in_1a[2]", + "gpio_control_in_1a[3]", + "gpio_control_in_1a[4]", + "gpio_control_in_1a[5]", + "gpio_control_in_1[0]", + "gpio_control_in_1[1]", + "gpio_control_in_1[2]", + "gpio_control_in_1[3]", + "gpio_control_in_1[4]", + "gpio_control_in_1[5]", + "gpio_control_in_1[6]", + "gpio_control_in_1[7]", + "gpio_control_in_1[8]", + "gpio_control_in_1[9]", + "gpio_control_in_1[10]", + ) + if 'CARAVAN' in caravelEnv.design_macros._asdict(): + gpios_l = ( + "gpio_control_bidir_1[0]", + "gpio_control_bidir_1[1]", + "gpio_control_in_1a[0]", + "gpio_control_in_1a[1]", + "gpio_control_in_1a[2]", + "gpio_control_in_1a[3]", + "gpio_control_in_1a[4]", + "gpio_control_in_1a[5]", + "gpio_control_in_1[0]", + "gpio_control_in_1[1]", + "gpio_control_in_1[2]", + "gpio_control_in_1[3]", + "gpio_control_in_1[4]", + "gpio_control_in_1[5]", + ) + + gpios_h = ( + "gpio_control_in_2[0]", + "gpio_control_in_2[1]", + "gpio_control_in_2[2]", + "gpio_control_in_2[3]", + "gpio_control_in_2[4]", + "gpio_control_in_2[5]", + "gpio_control_in_2[6]", + "gpio_control_in_2[7]", + "gpio_control_in_2[8]", + "gpio_control_in_2[9]", + "gpio_control_in_2[10]", + "gpio_control_in_2[11]", + "gpio_control_in_2[12]", + "gpio_control_in_2[13]", + "gpio_control_in_2[14]", + "gpio_control_in_2[15]", + "gpio_control_bidir_2[0]", + "gpio_control_bidir_2[1]", + "gpio_control_bidir_2[2]", + ) + if 'CARAVAN' in caravelEnv.design_macros._asdict(): + gpios_h = ( + "gpio_control_in_2[0]", + "gpio_control_in_2[1]", + "gpio_control_in_2[2]", + "gpio_control_in_2[3]", + "gpio_control_in_2[4]", + "gpio_control_in_2[5]", + "gpio_control_in_2[6]", + "gpio_control_in_2[7]", + "gpio_control_in_2[8]", + "gpio_control_in_2[9]", + "gpio_control_bidir_2[0]", + "gpio_control_bidir_2[1]", + "gpio_control_bidir_2[2]", + ) + + type = False # type of shifting 01 or 10 + for gpio in gpios_l: + if 'GL' not in caravelEnv.design_macros._asdict(): + shift(uut._id(gpio, False), type, caravelEnv) + else: + shift((uut, gpio), type, caravelEnv) + type = not type + type = False # type of shifting 01 or 10 + for gpio in reversed(gpios_h): + if 'GL' not in caravelEnv.design_macros._asdict(): + shift(uut._id(gpio, False), type, caravelEnv) + else: + shift((uut, gpio), type, caravelEnv) + type = not type + + +@cocotb.test() +@report_test +async def serial_shifting_0011(dut): + caravelEnv = await test_configure(dut, timeout_cycles=700516) + debug_regs = await configure_userdesign(caravelEnv) + uut = dut.uut.chip_core + debug_regs = await configure_userdesign(caravelEnv) + await debug_regs.wait_reg1(0xFF) + gpios_l = ( + "gpio_control_bidir_1[0]", + "gpio_control_bidir_1[1]", + "gpio_control_in_1a[0]", + "gpio_control_in_1a[1]", + "gpio_control_in_1a[2]", + "gpio_control_in_1a[3]", + "gpio_control_in_1a[4]", + "gpio_control_in_1a[5]", + "gpio_control_in_1[0]", + "gpio_control_in_1[1]", + "gpio_control_in_1[2]", + "gpio_control_in_1[3]", + "gpio_control_in_1[4]", + "gpio_control_in_1[5]", + "gpio_control_in_1[6]", + "gpio_control_in_1[7]", + "gpio_control_in_1[8]", + "gpio_control_in_1[9]", + "gpio_control_in_1[10]", + ) + if 'CARAVAN' in caravelEnv.design_macros._asdict(): + gpios_l = ( + "gpio_control_bidir_1[0]", + "gpio_control_bidir_1[1]", + "gpio_control_in_1a[0]", + "gpio_control_in_1a[1]", + "gpio_control_in_1a[2]", + "gpio_control_in_1a[3]", + "gpio_control_in_1a[4]", + "gpio_control_in_1a[5]", + "gpio_control_in_1[0]", + "gpio_control_in_1[1]", + "gpio_control_in_1[2]", + "gpio_control_in_1[3]", + "gpio_control_in_1[4]", + "gpio_control_in_1[5]", + ) + + gpios_h = ( + "gpio_control_in_2[0]", + "gpio_control_in_2[1]", + "gpio_control_in_2[2]", + "gpio_control_in_2[3]", + "gpio_control_in_2[4]", + "gpio_control_in_2[5]", + "gpio_control_in_2[6]", + "gpio_control_in_2[7]", + "gpio_control_in_2[8]", + "gpio_control_in_2[9]", + "gpio_control_in_2[10]", + "gpio_control_in_2[11]", + "gpio_control_in_2[12]", + "gpio_control_in_2[13]", + "gpio_control_in_2[14]", + "gpio_control_in_2[15]", + "gpio_control_bidir_2[0]", + "gpio_control_bidir_2[1]", + "gpio_control_bidir_2[2]", + ) + if 'CARAVAN' in caravelEnv.design_macros._asdict(): + gpios_h = ( + "gpio_control_in_2[0]", + "gpio_control_in_2[1]", + "gpio_control_in_2[2]", + "gpio_control_in_2[3]", + "gpio_control_in_2[4]", + "gpio_control_in_2[5]", + "gpio_control_in_2[6]", + "gpio_control_in_2[7]", + "gpio_control_in_2[8]", + "gpio_control_in_2[9]", + "gpio_control_bidir_2[0]", + "gpio_control_bidir_2[1]", + "gpio_control_bidir_2[2]", + ) + + type = 2 # type of shifting 01 or 10 + for gpio in gpios_l: + if 'GL' not in caravelEnv.design_macros._asdict(): + shift_2(uut._id(gpio, False), type, caravelEnv) + else: + shift_2((uut, gpio), type, caravelEnv) + type = (type + 1) % 4 + type = 2 # type of shifting 01 or 10 + for gpio in reversed(gpios_h): + if 'GL' not in caravelEnv.design_macros._asdict(): + shift_2(uut._id(gpio, False), type, caravelEnv) + else: + shift_2((uut, gpio), type, caravelEnv) + type = (type + 1) % 4 + + +@cocotb.test() +@report_test +async def serial_shifting_1100(dut): + caravelEnv = await test_configure(dut, timeout_cycles=700331) + debug_regs = await configure_userdesign(caravelEnv) + uut = dut.uut.chip_core + debug_regs = await configure_userdesign(caravelEnv) + await debug_regs.wait_reg1(0xFF) + gpios_l = ( + "gpio_control_bidir_1[0]", + "gpio_control_bidir_1[1]", + "gpio_control_in_1a[0]", + "gpio_control_in_1a[1]", + "gpio_control_in_1a[2]", + "gpio_control_in_1a[3]", + "gpio_control_in_1a[4]", + "gpio_control_in_1a[5]", + "gpio_control_in_1[0]", + "gpio_control_in_1[1]", + "gpio_control_in_1[2]", + "gpio_control_in_1[3]", + "gpio_control_in_1[4]", + "gpio_control_in_1[5]", + "gpio_control_in_1[6]", + "gpio_control_in_1[7]", + "gpio_control_in_1[8]", + "gpio_control_in_1[9]", + "gpio_control_in_1[10]", + ) + if 'CARAVAN' in caravelEnv.design_macros._asdict(): + gpios_l = ( + "gpio_control_bidir_1[0]", + "gpio_control_bidir_1[1]", + "gpio_control_in_1a[0]", + "gpio_control_in_1a[1]", + "gpio_control_in_1a[2]", + "gpio_control_in_1a[3]", + "gpio_control_in_1a[4]", + "gpio_control_in_1a[5]", + "gpio_control_in_1[0]", + "gpio_control_in_1[1]", + "gpio_control_in_1[2]", + "gpio_control_in_1[3]", + "gpio_control_in_1[4]", + "gpio_control_in_1[5]", + ) + + gpios_h = ( + "gpio_control_in_2[0]", + "gpio_control_in_2[1]", + "gpio_control_in_2[2]", + "gpio_control_in_2[3]", + "gpio_control_in_2[4]", + "gpio_control_in_2[5]", + "gpio_control_in_2[6]", + "gpio_control_in_2[7]", + "gpio_control_in_2[8]", + "gpio_control_in_2[9]", + "gpio_control_in_2[10]", + "gpio_control_in_2[11]", + "gpio_control_in_2[12]", + "gpio_control_in_2[13]", + "gpio_control_in_2[14]", + "gpio_control_in_2[15]", + "gpio_control_bidir_2[0]", + "gpio_control_bidir_2[1]", + "gpio_control_bidir_2[2]", + ) + if 'CARAVAN' in caravelEnv.design_macros._asdict(): + gpios_h = ( + "gpio_control_in_2[0]", + "gpio_control_in_2[1]", + "gpio_control_in_2[2]", + "gpio_control_in_2[3]", + "gpio_control_in_2[4]", + "gpio_control_in_2[5]", + "gpio_control_in_2[6]", + "gpio_control_in_2[7]", + "gpio_control_in_2[8]", + "gpio_control_in_2[9]", + "gpio_control_bidir_2[0]", + "gpio_control_bidir_2[1]", + "gpio_control_bidir_2[2]", + ) + type = 0 # type of shifting 01 or 10 + for gpio in gpios_l: + if 'GL' not in caravelEnv.design_macros._asdict(): + shift_2(uut._id(gpio, False), type, caravelEnv) + else: + shift_2((uut, gpio), type, caravelEnv) + type = (type + 1) % 4 + type = 0 # type of shifting 01 or 10 + for gpio in reversed(gpios_h): + if 'GL' not in caravelEnv.design_macros._asdict(): + shift_2(uut._id(gpio, False), type, caravelEnv) + else: + shift_2((uut, gpio), type, caravelEnv) + type = (type + 1) % 4 + + +def shift_2(gpio, shift_type, caravelEnv): + bit_size = int(caravelEnv.design_macros.IO_CTRL_BITS) + if shift_type == 0: + bits = "0011001100110" + if bit_size != 13: + bits = bits[0:bit_size-1] + elif shift_type == 1: + bits = "0110011001100" + if bit_size != 13: + bits = bits[0:bit_size-1] + elif shift_type == 2: + bits = "1100110011001" + if bit_size != 13: + bits = bits[0:bit_size-1] + elif shift_type == 3: + bits = "1001100110011" + if bit_size != 13: + bits = bits[0:bit_size-1] + gpio_to_skip = () + if "CPU_TYPE_ARM" in caravelEnv.design_macros._asdict(): + gpio_to_skip = ( + "gpio_control_bidir_2[0]", + "gpio_control_bidir_2[1]", + "gpio_control_bidir_2[2]", + ) + + if str(gpio).split(".")[-1] in gpio_to_skip: + return + + fail = False + if 'GL' not in caravelEnv.design_macros._asdict(): + cocotb.log.info( + f"[TEST] gpio {gpio} shift {hex(int(gpio._id(f'shift_register',False).value.binstr,2))}({gpio._id(f'shift_register',False).value.binstr}) expected {hex(int(bits,2))}({bits})" + ) + else: + shift_reg = "" + for i in range(bit_size): + shift_reg += ( + gpio[0] + ._id(f"\\{gpio[1]}.shift_register[{bit_size-1-i}] ", False) + .value.binstr + ) + cocotb.log.info( + f"[TEST] gpio {gpio[0]}.{gpio[1]}.shift_register shift {hex(int(shift_reg,2))}({shift_reg}) expected {hex(int(bits,2))}({bits})" + ) + for i in range(bit_size): + if 'GL' not in caravelEnv.design_macros._asdict(): + shift_register = gpio._id("shift_register", False).value.binstr[i] + else: + shift_register = ( + gpio[0] + ._id(f"\\{gpio[1]}.shift_register[{bit_size-1-i}] ", False) + .value.binstr + ) + if shift_register != bits[i]: + fail = True + cocotb.log.error(f"[TEST] wrong shift register {i} in {gpio}") + if not fail: + if 'GL' not in caravelEnv.design_macros._asdict(): + cocotb.log.info(f"[TEST] gpio {gpio} passed") + else: + cocotb.log.info(f"[TEST] gpio {gpio[1]} passed") diff --git a/verilog/dv/cocotb/all_tests/spi_master/SPI_VIP.py b/verilog/dv/cocotb/all_tests/spi_master/SPI_VIP.py new file mode 100644 index 000000000..9d5dd98c9 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/spi_master/SPI_VIP.py @@ -0,0 +1,94 @@ +import cocotb +from cocotb.triggers import FallingEdge, RisingEdge +import cocotb.log +# VIP for SPI +""" + support commands + 00000000 -> No operation + 00000011 -> Read in streaming mode +""" + + +async def SPI_VIP(csb, clk, SDI, SDO, mem, remove_clk=0): + while True: + await FallingEdge(csb) + cocotb.log.info("[SPI_VIP] CSB is asserted operation has begin ") + op = await cocotb.start(SPI_op(clk, SDI, SDO, mem, remove_clk)) + await csb_watcher(csb, op) + cocotb.log.info("[SPI_VIP] CSB is deasserted operation has been killed") + + +# watch the csb and when it's diable kill the SPI_op thread +async def csb_watcher(csb, thread): + cocotb.log.info("[csb_watcher] start CSB watching") + await RisingEdge(csb) + thread.kill() + + +# detect command and address and apply the command +async def SPI_op(clk, SDI, SDO, mem, remove_clk=0): + address = "" + command = "" + await RisingEdge(clk) + SDO[0].value = 1 + SDO[1].value = 0 + # command + for i in range(8): + command = command + SDI.value.binstr + await RisingEdge(clk) + cocotb.log.info(f"[SPI_VIP] [SPI_op] command = {command}") + # address + address = "" + for i in range(8 * 3): # address is 3 parts each part are 8 bits + address = address + SDI.value.binstr + if i != 23: # skip last cycle wait + await RisingEdge(clk) + cocotb.log.info(f"[SPI_VIP] [SPI_op] address = {address}") + address = int(address, 2) + # data + if command == "10000000" and False: # not sure about the read command + for i in range(8): + pass + # TODO: Add logic for reading + # data_in += SDI + # await RisingEdge(clk) + elif command == "00000011": + if not remove_clk: + await FallingEdge(clk) + while True: + data = bin(mem[address])[2:].zfill(8) + for i in range(8): + SDO[0].value = 1 # enable + SDO[1].value = int(data[i], 2) # bin + cocotb.log.debug(f"[SPI_VIP] [SPI_op] SDO = {data[i]} ") + await FallingEdge(clk) + SDO[0].value = 0 # enable + + cocotb.log.info( + f"[SPI_VIP] [SPI_op] finish reading address {hex(address) } data = {hex(int(data,2))} " + ) + if address < 0xFF: + address += 1 + + +def read_mem(file_name): + with open(file_name, "r") as file: + lines = file.readlines() + mem = dict() + for line in lines: + if line[0] == "@": + address = int(line[1:], 16) + cocotb.log.debug(f" found line = {line} address = {hex(address)} ") + else: + line_no_space = line.strip().replace(" ", "") + for i in range(0, len(line_no_space), 2): + cocotb.log.debug( + f" i = {i} ine_no_space[{i}:{i+2}] = {line_no_space[i:i+2]} address = {hex(address)}" + ) + mem[address] = int(line_no_space[i:i + 2], 16) + address += 1 + cocotb.log.debug( + f" found line = {line} line_no_space = {line_no_space} size = {len(line_no_space)}" + ) + cocotb.log.info(f"[read_mem] SPI mem = {mem}") + return mem diff --git a/verilog/dv/cocotb/all_tests/spi_master/spi_master.py b/verilog/dv/cocotb/all_tests/spi_master/spi_master.py new file mode 100644 index 000000000..1bf1f9b33 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/spi_master/spi_master.py @@ -0,0 +1,137 @@ +import cocotb +from cocotb.triggers import FallingEdge, RisingEdge, ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from all_tests.spi_master.SPI_VIP import read_mem, SPI_VIP +from user_design import configure_userdesign + + +@cocotb.test() +@report_test +async def spi_master_rd(dut): + """the firmware is configured to always send clk to spi so I can't insert alot of logics reading values + + the method of testing used can't work if 2 addresses Consecutive have the same address + """ + + caravelEnv = await test_configure(dut, timeout_cycles=1362179) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] start spi_master_rd test") + file_name = f'{cocotb.plusargs["USER_PROJECT_ROOT"]}/verilog/dv/cocotb/all_tests/spi_master/test_data'.replace('"', '') + mem = read_mem(file_name) + CSB = dut.gpio33_monitor + SCK = dut.gpio32_monitor + # SDO = dut.uut.chip_core.spi_sdo + SDO = dut.gpio35_monitor + SDI = (dut.gpio34_en, dut.gpio34) + await cocotb.start(SPI_VIP(CSB, SCK, SDO, SDI, mem)) # fork for SPI + + addresses_to_read = ( + 0x04, + 0x05, + 0x18, + 0x19, + 0x22, + 0x23, + 0x37, + 0x38, + 0x41, + 0x42, + 0x5f, + 0x60, + 0x64, + 0x70, + 0x8c, + 0x94, + 0xaa, + 0xb3, + 0xc7, + 0xd8, + 0xeb, + 0xff, + ) # the addresses that the firmware read from mem file + await debug_regs.wait_reg2(0xAA) + cocotb.log.info( + "[TEST] GPIO configuration finished ans start reading from mememory" + ) + val = 0 + for address in addresses_to_read: + # await debug_regs.wait_reg2(0x55) # value is ready to be read + # wait until value change + while True: + if val != debug_regs.read_debug_reg1(): + break + await ClockCycles(caravelEnv.clk, 100) + + expected_val = mem[address] + val = debug_regs.read_debug_reg1() + if val == expected_val: + cocotb.log.info( + f"[TEST] correct read of value {hex(val)} from address {hex(address)} " + ) + else: + cocotb.log.error( + f"[TEST] wrong read from address {hex(address)} expected value = {hex(expected_val)} value {hex(val)} " + ) + # debug_regs.write_debug_reg2_backdoor(0xCC) + + await ClockCycles(caravelEnv.clk, 1000) + + +@cocotb.test() +@report_test +async def spi_master_temp(dut): + """the firmware is configured to always send clk to spi so I can't insert alot of logics reading values + + the method of testing used can't work if 2 addresses Consecutive have the same address + """ + caravelEnv = await test_configure(dut, timeout_cycles=114548) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] start spi_master_temp test") + CSB = dut.gpio33_monitor + SCK = dut.gpio32_monitor + # SDO = dut.uut.chip_core.housekeeping.spi_sdo + SDO = dut.gpio35_monitor + # SDI = (dut.gpio34_en, dut.gpio34) + await RisingEdge(CSB) + await FallingEdge(CSB) + await RisingEdge(SCK) + a = "" + b = "" + # first value + for i in range(8): + a = a + SDO.value.binstr + cocotb.log.info(f" [TEST] SDO = {SDO.value.binstr}") + await RisingEdge(SCK) + cocotb.log.info(f" [TEST] a = {a} = {int(a,2)}") + + # second val + for i in range(8): + b = b + SDO.value.binstr + cocotb.log.info(f" [TEST] SDO = {SDO.value.binstr}") + if i != 7: # skip last cycle wait + await RisingEdge(SCK) + cocotb.log.info(f" [TEST] b = {b} = {int(b,2)}") + + s = int(a, 2) + int(b, 2) + s_bin = bin(s)[2:].zfill(8) + cocotb.log.info(f" [TEST] sending sum of {int(a,2)} + {int(b,2)} = {s} = {s_bin}") + await FallingEdge(SCK) + for i in range(8): + dut.gpio34_en.value = 1 + dut.gpio34.value = int(s_bin[i], 2) # bin + cocotb.log.debug(f"[SPI_VIP] [SPI_op] SDO = {s_bin[i]} ") + await FallingEdge(SCK) + dut.gpio34_en.value = 0 # enable + while True: + if debug_regs.read_debug_reg1() == 0xBB: + cocotb.log.info(f" [TEST] firmware recieve the right value {s}") + break + elif debug_regs.read_debug_reg1() == 0xEE: + cocotb.log.error( + f" [TEST] firmware recieve the incorrect value {debug_regs.read_debug_reg2()} instead of {s}" + ) + break + + await ClockCycles(caravelEnv.clk, 10) diff --git a/verilog/dv/cocotb/all_tests/spi_master/spi_master_rd.c b/verilog/dv/cocotb/all_tests/spi_master/spi_master_rd.c new file mode 100644 index 000000000..e1a628673 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/spi_master/spi_master_rd.c @@ -0,0 +1,263 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + + +// -------------------------------------------------------- + +/* + * SPI master Test + * - Enables SPI master + * - Uses SPI master to talk to external SPI module + */ + +void main(){ + enable_debug(); + enableHkSpi(0); + + GPIOs_configure(34,GPIO_MODE_MGMT_STD_INPUT_NOPULL); // SDI + GPIOs_configure(35,GPIO_MODE_MGMT_STD_OUTPUT); // SDO + GPIOs_configure(33,GPIO_MODE_MGMT_STD_OUTPUT); // CSB + GPIOs_configure(32,GPIO_MODE_MGMT_STD_OUTPUT); // SCK + + // Now, apply the configuration + GPIOs_loadConfigs(); + + set_debug_reg2(0xAA); + + MSPI_enable(1); + + + // For SPI operation, GPIO 1 should be an input, and GPIOs 2 to 4 + // should be outputs. + + // Start test + + // Enable SPI master + // SPI master configuration bits: + // bits 7-0: Clock prescaler value (default 2) + // bit 8: MSB/LSB first (0 = MSB first, 1 = LSB first) + // bit 9: CSB sense (0 = inverted, 1 = noninverted) + // bit 10: SCK sense (0 = noninverted, 1 = inverted) + // bit 11: mode (0 = read/write opposite edges, 1 = same edges) + // bit 12: stream (1 = CSB ends transmission) + // bit 13: enable (1 = enabled) + // bit 14: IRQ enable (1 = enabled) + // bit 15: (unused) + + + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0x04); // Write 0x04 (start address low byte) + + unsigned int value = MSPI_read(); // 0x93 + set_debug_reg1(value); + + value = MSPI_read(); // 0x01 + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0x18); // Write 0x18 (start address low byte) + + value = MSPI_read(); // 0x44 + set_debug_reg1(value); + + value = MSPI_read(); // 0x33 + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0x22); // Write 0x22 (start address low byte) + + value = MSPI_read(); // 0xC3 + set_debug_reg1(value); + + value = MSPI_read(); // 0xD0 + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0x37); // Write 0x37 (start address low byte) + + value = MSPI_read(); // 0x89 + set_debug_reg1(value); + + value = MSPI_read(); // 0xa3 + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0x41); // Write 0x41 (start address low byte) + + value = MSPI_read(); // 0x6B + set_debug_reg1(value); + + value = MSPI_read(); // 0x8a + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0x5f); // Write 0x5f (start address low byte) + + value = MSPI_read(); // 0x77 + set_debug_reg1(value); + + value = MSPI_read(); // 0x5B + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0x64); // Write 0x64 (start address low byte) + + value = MSPI_read(); // 0xC7 + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0x70); // Write 0x70 (start address low byte) + + value = MSPI_read(); // 0xB3 + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0x8c); // Write 0x8c (start address low byte) + + value = MSPI_read(); // 0x48 + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0x94); // Write 0x94 (start address low byte) + + value = MSPI_read(); // 0xE7 + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0xaa); // Write 0xaa (start address low byte) + + value = MSPI_read(); // 0x6F + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0xb3); // Write 0xb3 (start address low byte) + + value = MSPI_read(); // 0x30 + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0xc7); // Write 0xc7 (start address low byte) + + value = MSPI_read(); // 0x2F + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0xd8); // Write 0xd8 (start address low byte) + + value = MSPI_read(); // 0x1C + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0xeb); // Write 0xeb (start address low byte) + + value = MSPI_read(); // 0xA0 + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + MSPI_write(0x03); // Write 0x03 (read mode) + MSPI_write(0x00); // Write 0x00 (start address high byte) + MSPI_write(0x00); // Write 0x00 (start address middle byte) + MSPI_write(0xff); // Write 0xff (start address low byte) + + value = MSPI_read(); // 0xFF + set_debug_reg1(value); + + MSPI_enableCS(0); // release CS + MSPI_enableCS(1); // sel=0, manual CS + + + dummyDelay(100000000); +} + diff --git a/verilog/dv/cocotb/all_tests/spi_master/spi_master_temp.c b/verilog/dv/cocotb/all_tests/spi_master/spi_master_temp.c new file mode 100644 index 000000000..41277dca9 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/spi_master/spi_master_temp.c @@ -0,0 +1,85 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include + + + +// -------------------------------------------------------- + +/* + * SPI master Test + * - Enables SPI master + * - Uses SPI master to talk to external SPI module + */ + + +void main(){ + enable_debug(); + enableHkSpi(0); + + GPIOs_configure(34,GPIO_MODE_MGMT_STD_INPUT_NOPULL); // SDI + GPIOs_configure(35,GPIO_MODE_MGMT_STD_OUTPUT); // SDO + GPIOs_configure(33,GPIO_MODE_MGMT_STD_OUTPUT); // CSB + GPIOs_configure(32,GPIO_MODE_MGMT_STD_OUTPUT); // SCK + + // Now, apply the configuration + GPIOs_loadConfigs(); + set_debug_reg2(0xAA); + MSPI_enable(1); + + + // For SPI operation, GPIO 1 should be an input, and GPIOs 2 to 4 + // should be outputs. + + // Start test + + // Enable SPI master + // SPI master configuration bits: + // bits 7-0: Clock prescaler value (default 2) + // bit 8: MSB/LSB first (0 = MSB first, 1 = LSB first) + // bit 9: CSB sense (0 = inverted, 1 = noninverted) + // bit 10: SCK sense (0 = noninverted, 1 = inverted) + // bit 11: mode (0 = read/write opposite edges, 1 = same edges) + // bit 12: stream (1 = CSB ends transmission) + // bit 13: enable (1 = enabled) + // bit 14: IRQ enable (1 = enabled) + // bit 15: (unused) + + // reg_spimaster_clk_divider = 0x4E20; + MSPI_enableCS(1); // sel=0, manual CS + MSPI_write(0x08); // Write 0x03 (read mode) + MSPI_write(0x05); // Write 0x00 (start address high byte) + unsigned int value = MSPI_read(); // 0x93 + if (value == 0xD) + set_debug_reg1(0xBB); // get correct value + else { + set_debug_reg2(value); + set_debug_reg1(0xEE); // get wrong value + } + + MSPI_enableCS(0); // release CS + // reg_spimaster_clk_divider = 0x4E00; + + MSPI_enableCS(1); // sel=0, manual CS + MSPI_write(0x08); // Write 0x03 (read mode) + MSPI_write(0x05); // Write 0x00 (start address high byte) + + dummyDelay(100000000); +} + diff --git a/verilog/dv/cocotb/all_tests/spi_master/test_data b/verilog/dv/cocotb/all_tests/spi_master/test_data new file mode 100644 index 000000000..f7af1c563 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/spi_master/test_data @@ -0,0 +1,17 @@ +@00000000 +6F 4D B9 0B 93 01 71 33 13 32 63 57 b5 44 23 80 +13 01 13 17 13 45 AA 89 44 33 9A 01 13 99 2C 11 +4E A1 C3 D0 1A F2 B3 1D 10 72 11 B5 09 13 90 20 +02 D4 8D 23 1B 6A AA 89 a3 1B 9A 01 13 99 2C 11 +5F 6B 8A D0 6A 8B 4C 1A 78 02 C6 F3 4D 0A 76 11 +8C 6B D8 40 D6 05 B9 1E 83 99 61 22 E4 29 CC 77 +5B B1 51 83 C7 F2 8B E9 2F A2 D3 46 E1 2A 8F 49 +B3 A4 94 80 F8 13 E7 B4 F2 2E 6D A0 1F 2C 01 10 +32 C0 B7 D9 A6 E0 4F A2 39 2F 0E 02 48 C5 7B 0C +14 3E 46 98 E7 C1 92 48 18 71 20 7A F6 3A 28 5F +D1 82 6A F0 0F F3 59 3E 0C 94 00 9A 84 09 E3 11 +02 E1 E8 30 0B 7C 69 58 1F 47 96 3D 0A B1 57 2A +A0 A1 C3 5F 2D F7 D2 2F 17 42 1D 33 D0 7A 2F 01 +B2 8C C8 75 1C B0 5A 0B 1C 2A F6 1F D4 0E 4D 31 +67 C3 23 80 3B 39 A3 04 D0 26 67 A0 1F 2C 01 10 +7F 53 B1 51 1E 92 98 48 18 71 20 7A F6 3A 28 FF diff --git a/verilog/dv/cocotb/all_tests/temp/temp.c b/verilog/dv/cocotb/all_tests/temp/temp.c new file mode 100644 index 000000000..bc6cebbbf --- /dev/null +++ b/verilog/dv/cocotb/all_tests/temp/temp.c @@ -0,0 +1,51 @@ +#include + +void set_registers(){ + for (int i = 0; i < 38; i++){ + if (i<19){ + GPIOs_configure(i, GPIO_MODE_MGMT_STD_INPUT_PULLUP); + + }else{ + GPIOs_configure(i, GPIO_MODE_MGMT_STD_OUTPUT); + } + } +} +/* +@ finish configuration + send packet with size 1 + +GPIO[0:18] is configured as input pull up and mapped to GPIO[19:37] + +input value send to gpio[0:18] suppose to be received as output at GPIO[19:37] +*/ +void main(){ + enable_debug(); + enableHkSpi(0); + ManagmentGpio_write(0); + ManagmentGpio_outputEnable(); + set_registers(); + GPIOs_writeHigh(0); + GPIOs_writeLow(0); + GPIOs_loadConfigs(); + int mask = 0x7FFFF; + int mask_h = 0x7E000; + int i_val = 0; + int o_val_l; + int o_val_h; + while (true){ + ManagmentGpio_write(1); + set_debug_reg2(0xDEADBEEF); + i_val = GPIOs_readLow() & mask; + set_debug_reg2(i_val); + set_debug_reg2(0xDEADBEEF); + o_val_l = i_val << 19; + set_debug_reg2(o_val_l); + set_debug_reg2(0xDEADBEEF); + o_val_h = i_val & mask_h; + o_val_h = o_val_h >> 13; + set_debug_reg2(o_val_h); + GPIOs_writeHigh(o_val_h); + GPIOs_writeLow(o_val_l); + ManagmentGpio_write(0); + } +} diff --git a/verilog/dv/cocotb/all_tests/temp/temp.py b/verilog/dv/cocotb/all_tests/temp/temp.py new file mode 100644 index 000000000..309a8573f --- /dev/null +++ b/verilog/dv/cocotb/all_tests/temp/temp.py @@ -0,0 +1,27 @@ +import cocotb +from cocotb.triggers import RisingEdge, ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test + + +@cocotb.test() +@report_test +async def temp(dut): + caravelEnv = await test_configure(dut, timeout_cycles=1137599) + cocotb.log.info("[TEST] start temp") + caravelEnv.release_csb() + await caravelEnv.wait_mgmt_gpio(1) # wait for gpio configuration to happened + cocotb.log.info("[TEST] finish configuration") + caravelEnv.drive_gpio_in(2,0) + await caravelEnv.wait_mgmt_gpio(0) # wait for gpio configuration to happened + await caravelEnv.wait_mgmt_gpio(1) # wait for gpio configuration to happened + caravelEnv.release_gpio(2) + await caravelEnv.wait_mgmt_gpio(0) # wait for gpio configuration to happened + await caravelEnv.wait_mgmt_gpio(1) # wait for gpio configuration to happened + caravelEnv.drive_gpio_in(2,1) + await ClockCycles(caravelEnv.clk,1000) + await caravelEnv.wait_mgmt_gpio(0) # wait for gpio configuration to happened + await caravelEnv.wait_mgmt_gpio(1) # wait for gpio configuration to happened + caravelEnv.drive_gpio_in(2,0) + await ClockCycles(caravelEnv.clk,100000) diff --git a/verilog/dv/cocotb/all_tests/testlist.yaml b/verilog/dv/cocotb/all_tests/testlist.yaml new file mode 100644 index 000000000..e3c57c570 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/testlist.yaml @@ -0,0 +1,11 @@ +--- +# yaml file contain general design information that would mostly need to be updated in the first run only +# example +## tests: [debug,clock_redirect] +## sim: [RTL,RTL] +Tests: + - {name: debug_swd, sim: RTL} + - {name: clock_redirect, sim: RTL} + +includes: + - ../testlist2.yaml diff --git a/verilog/dv/cocotb/all_tests/timer/timer.py b/verilog/dv/cocotb/all_tests/timer/timer.py new file mode 100644 index 000000000..2546df0da --- /dev/null +++ b/verilog/dv/cocotb/all_tests/timer/timer.py @@ -0,0 +1,114 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from user_design import configure_userdesign + + +"""Testbench of GPIO configuration through bit-bang method using the StriVe housekeeping SPI.""" + + +@cocotb.test() +@report_test +async def timer0_oneshot(dut): + caravelEnv = await test_configure(dut, timeout_cycles=159867) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start timer0_oneshot test") + cocotb.log.info("[TEST] Configure timer as oneshot") + pass_list = (0x1B, 0x2B, 0x3B) + fail_list = (0x1E, 0x2E) + phases_fails = 3 + phases_passes = 0 + reg1 = 0 # buffer + while True: + if debug_regs.read_debug_reg2() == 0xFF: # test finish + break + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + phases_passes += 1 + phases_fails -= 1 + if reg1 == 0x1B: + cocotb.log.info("[TEST] Pass timer0 value is decreasing") + elif reg1 == 0x2B: + cocotb.log.info("[TEST] Pass timer0 value reach 0") + elif reg1 == 0x3B: + cocotb.log.info( + "[TEST] Pass timer0 isn't changing after it reachs 0" + ) + elif reg1 in fail_list: # pass phase + if reg1 == 0x1E: + cocotb.log.info( + "[TEST] Failed timer0 value increasing not decresing in oneshot mode" + ) + elif reg1 == 0x2E: + cocotb.log.error( + "[TEST] Failed timer0 is changing before it reachs 0 in oneshot mode" + ) + else: + cocotb.log.error("[TEST] debug register 1 has illegal value") + await ClockCycles(caravelEnv.clk, 10) + + if phases_fails != 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + + +@cocotb.test() +@report_test +async def timer0_periodic(dut): + caravelEnv = await test_configure(dut, timeout_cycles=296520) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start timer0_periodic test") + cocotb.log.info("[TEST] Configure timer as periodic") + pass_list = (0x1B, 0x2B, 0x3B, 0x4B) + fail_list = 0xEE + phases_fails = 4 + phases_passes = 0 + reg1 = 0 # buffer + fourB_happened = False + while True: + if debug_regs.read_debug_reg2() == 0xFF: # test finish + break + if reg1 != debug_regs.read_debug_reg1(): + reg1 = debug_regs.read_debug_reg1() + if reg1 in pass_list: # pass phase + phases_passes += 1 + phases_fails -= 1 + if reg1 == 0x1B: + cocotb.log.info("[TEST] Pass timer0 first rollover") + elif reg1 == 0x2B: + cocotb.log.info("[TEST] Pass timer0 second rollover") + elif reg1 == 0x3B: + cocotb.log.info("[TEST] Pass timer0 third rollover") + elif reg1 == 0x4B: + if fourB_happened: # this phase happened one time before + phases_passes -= 1 + phases_fails += 1 + else: + cocotb.log.info("[TEST] Pass timer0 counter value decreases") + fourB_happened = True + elif reg1 in fail_list: # pass phase + if reg1 == 0xEE: + cocotb.log.info( + "[TEST] Failed timer0 value hasn't rollovered in periodic mode" + ) + else: + cocotb.log.error("[TEST] debug register 1 has illegal value") + + await ClockCycles(caravelEnv.clk, 1) + + if phases_fails != 0: + cocotb.log.error( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) + else: + cocotb.log.info( + f"[TEST] finish with {phases_passes} phases passes and {phases_fails} phases fails" + ) diff --git a/verilog/dv/cocotb/all_tests/timer/timer0_oneshot.c b/verilog/dv/cocotb/all_tests/timer/timer0_oneshot.c new file mode 100644 index 000000000..8a987217d --- /dev/null +++ b/verilog/dv/cocotb/all_tests/timer/timer0_oneshot.c @@ -0,0 +1,61 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include + + + +void main(){ + unsigned int value; + unsigned int old_value; + enable_debug(); + enableHkSpi(0); + + /* Configure timer for a single-shot countdown */ + timer0_configureOneShot(0xF300); + + // test path if counter value stop updated after reach 0 and also the value is always decrementing + timer0_updateValue(); // update reg_timer0_value with new counter value + old_value = timer0_readValue(); + // value us decrementing until it reachs zero + while (1) { + timer0_updateValue(); // update reg_timer0_value with new counter value + value = timer0_readValue(); + if (value < old_value && value != 0){ + set_debug_reg1(0x1B); // value decrease + } + else if (value == 0){ + set_debug_reg1(0x2B); // value reach 0 + break; + }else{ + set_debug_reg1(0x1F); // value updated incorrectly + } + old_value = value; + } + // check 10 times that value don't change from 0 + dummyDelay(10); + timer0_updateValue(); // update reg_timer0_value with new counter value + + if (timer0_readValue() == 0){ + set_debug_reg1(0x3B); //timer updated correctly + }else{ + set_debug_reg1(0x2F); //timer updated incorrectly + } + set_debug_reg2(0xFF); // finish test +} + diff --git a/verilog/dv/cocotb/all_tests/timer/timer0_periodic.c b/verilog/dv/cocotb/all_tests/timer/timer0_periodic.c new file mode 100644 index 000000000..070d5caef --- /dev/null +++ b/verilog/dv/cocotb/all_tests/timer/timer0_periodic.c @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + + +void main(){ + unsigned int value; + unsigned int old_value; + enable_debug(); + enableHkSpi(0); + + /* Configure timer for a periodic countdown */ + timer0_configurePeriodic(0x300); + + // Loop, waiting for the interrupt to change reg_mprj_datah + // test path if counter value stop updated after reach 0 and also the value is always decrementing + timer0_updateValue(); // update reg_timer0_value with new counter value + old_value = timer0_readValue(); + // value us decrementing until it reachs zero and rollover to 0x300 (initial value) + int rollover = 0; + int timeout = 400; + for (int i = 0; i < timeout; i++){ + timer0_updateValue(); // update reg_timer0_value with new counter value + value = timer0_readValue(); + if (value > old_value){ + rollover++; + if (rollover==1) + set_debug_reg1(0x1B); // timer rollover + else if (rollover==2) + set_debug_reg1(0x2B); //timer rollover second time + else if (rollover==3){ + set_debug_reg1(0x3B); //timer rollover third time + break; + } + } + if (value < old_value){ + set_debug_reg1(0x4B); // value decreases + } + old_value = value; + } + + if (rollover ==0){ + set_debug_reg1(0xEE); // counter didn't rollover + } + set_debug_reg2(0xFF); // finish test + +} + diff --git a/verilog/dv/cocotb/all_tests/uart/uart.py b/verilog/dv/cocotb/all_tests/uart/uart.py new file mode 100644 index 000000000..a1da09233 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/uart/uart.py @@ -0,0 +1,154 @@ +import cocotb +from cocotb.triggers import ClockCycles, Edge +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from caravel_cocotb.caravel_interfaces import UART +from user_design import configure_userdesign + + +@cocotb.test() +@report_test +async def uart_tx(dut): + caravelEnv = await test_configure(dut, timeout_cycles=444465) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start uart test") + expected_msg = "Monitor: Test UART (RTL) passed" + uart = UART(caravelEnv) + # wait for start of sending + await debug_regs.wait_reg1(0xAA) + msg = await uart.get_line() + if msg == expected_msg: + cocotb.log.info(f"[TEST] Pass recieve the full expected msg '{msg}'") + else: + cocotb.log.error( + f"[TEST] recieved wrong msg from uart msg recieved:'{msg}' expected '{expected_msg}'" + ) + + +@cocotb.test() +@report_test +async def uart_rx(dut): + caravelEnv = await test_configure(dut, timeout_cycles=188729) + debug_regs = await configure_userdesign(caravelEnv) + uart = UART(caravelEnv) + cocotb.log.info("[TEST] Start uart test") + # IO[0] affects the uart selecting btw system and debug + caravelEnv.drive_gpio_in((0, 0), 0) + caravelEnv.drive_gpio_in((5, 5), 1) + # send first char + await debug_regs.wait_reg1(0xAA) + await uart.uart_send_char("B") + await uart_check_char_recieved(caravelEnv, debug_regs) + # send second char + await debug_regs.wait_reg1(0xBB) + await uart.uart_send_char("M") + await uart_check_char_recieved(caravelEnv, debug_regs) + # send third char + await debug_regs.wait_reg1(0xCC) + await uart.uart_send_char("A") + await uart_check_char_recieved(caravelEnv, debug_regs) + + +async def uart_check_char_recieved(caravelEnv, debug_regs): + # check cpu recieved the correct character + while True: + if 'GL' not in caravelEnv.design_macros._asdict(): + if 'CPU_TYPE_ARM' in caravelEnv.design_macros._asdict(): + reg_uart_data = ( + caravelEnv.caravel_hdl.soc.core.AHB.APB_S3.S3_UART.reg_rx_buf.value.binstr + ) + else: + reg_uart_data = caravelEnv.caravel_hdl.soc.core.uart_rxtx_w.value.binstr + else: + reg_uart_data = "1001110" + + reg2 = debug_regs.read_debug_reg2() + cocotb.log.debug(f"[TEST] reg2 = {hex(reg2)}") + if reg2 == 0x1B: + cocotb.log.info( + f"[TEST] Pass cpu has recieved the correct character {chr(int(reg_uart_data,2))}({reg_uart_data})" + ) + return + if reg2 == 0x1E: + cocotb.log.error( + f"[TEST] Failed cpu has recieved the wrong character {chr(int(reg_uart_data,2))}({reg_uart_data})" + ) + return + + await ClockCycles(caravelEnv.clk, 1) + + +@cocotb.test() +@report_test +async def uart_loopback(dut): + caravelEnv = await test_configure(dut, timeout_cycles=216759) + debug_regs = await configure_userdesign(caravelEnv) + cocotb.log.info("[TEST] Start uart test") + debug_regs = await configure_userdesign(caravelEnv) + await cocotb.start(connect_5_6(dut, caravelEnv)) # short gpio 6 and 5 + caravelEnv.drive_gpio_in( + (0, 0), 0 + ) # IO[0] affects the uart selecting btw system and debug + + # setup watcher loopback results + await cocotb.start(uart_check_char_recieved_loopback(caravelEnv, debug_regs)) + + await ClockCycles(caravelEnv.clk, 197000) + + +async def connect_5_6(dut, caravelEnv): + while True: + caravelEnv.drive_gpio_in(5, dut.gpio6_monitor.value) + await Edge(dut.gpio6_monitor) + + +async def uart_check_char_recieved_loopback(caravelEnv, debug_regs): + # check cpu recieved the correct character + while True: + if 'GL' not in caravelEnv.design_macros._asdict(): + if 'CPU_TYPE_ARM' in caravelEnv.design_macros._asdict(): + reg_uart_data = ( + caravelEnv.caravel_hdl.soc.core.AHB.APB_S3.S3_UART.reg_rx_buf.value.binstr + ) + else: + reg_uart_data = caravelEnv.caravel_hdl.soc.core.uart_rxtx_w.value.binstr + else: + reg_uart_data = "1001110" + + reg2 = debug_regs.read_debug_reg2() + cocotb.log.debug(f"[TEST] reg2 = {hex(reg2)}") + if reg2 == 0x1B: + cocotb.log.info( + f"[TEST] Pass cpu has sent and recieved the correct character {chr(int(reg_uart_data,2))}" + ) + await debug_regs.wait_reg2(0) + + if reg2 == 0x1E: + cocotb.log.error( + f"[TEST] Failed cpu has sent and recieved the wrong character {chr(int(reg_uart_data,2))}" + ) + await debug_regs.wait_reg2(0) + + await ClockCycles(caravelEnv.clk, 1) + +@cocotb.test() +@report_test +async def uart_rx_msg(dut): + caravelEnv = await test_configure(dut, timeout_cycles=111154409) + uart = UART(caravelEnv) + debug_regs = await configure_userdesign(caravelEnv) + # IO[0] affects the uart selecting btw system and debug + caravelEnv.drive_gpio_in((0, 0), 0) + caravelEnv.drive_gpio_in((5, 5), 1) + await debug_regs.wait_reg1(0xAA) + await ClockCycles(caravelEnv.clk, 30) + msg = "Hello+World; " + await uart.uart_send_line(msg) + msg_received = await uart.get_line() + if msg_received != msg: + cocotb.log.error( + f"[TEST] recieved wrong msg from uart msg recieved:'{msg_received}' expected '{msg}'" + ) + else: + cocotb.log.info(f"[TEST] Pass recieve the full expected msg '{msg}'") \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/uart/uart_loopback.c b/verilog/dv/cocotb/all_tests/uart/uart_loopback.c new file mode 100644 index 000000000..16ada277d --- /dev/null +++ b/verilog/dv/cocotb/all_tests/uart/uart_loopback.c @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +// -------------------------------------------------------- + +#include + + +// -------------------------------------------------------- + +void wait_for_char(char *c){ + + if (UART_readChar() == *c){ + set_debug_reg2(0x1B); // recieved the correct character + }else{ + set_debug_reg2(0x1E); // timeout didn't recieve the character + } + UART_popChar(); + set_debug_reg2(0); +} + +void main(){ + enable_debug(); + enableHkSpi(0); + GPIOs_configure(6,GPIO_MODE_MGMT_STD_OUTPUT); + GPIOs_configure(5,GPIO_MODE_MGMT_STD_INPUT_NOPULL); + + // Now, apply the configuration + GPIOs_loadConfigs(); + + UART_enableRX(1); + UART_enableTX(1); + + print("M"); + wait_for_char("M"); + + print("B"); + wait_for_char("B"); + + print("A"); + wait_for_char("A"); + + print("5"); + wait_for_char("5"); + + print("o"); + wait_for_char("o"); + +} diff --git a/verilog/dv/cocotb/all_tests/uart/uart_rx.c b/verilog/dv/cocotb/all_tests/uart/uart_rx.c new file mode 100644 index 000000000..aae7918f9 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/uart/uart_rx.c @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +// -------------------------------------------------------- + +void wait_for_char(char *c){ + + if (UART_readChar() == *c){ + set_debug_reg2(0x1B); // recieved the correct character + }else{ + set_debug_reg2(0x1E); // timeout didn't recieve the character + } + UART_popChar(); +} + +void main(){ + enable_debug(); + enableHkSpi(0); + GPIOs_configure(6,GPIO_MODE_MGMT_STD_OUTPUT); + GPIOs_configure(5,GPIO_MODE_MGMT_STD_INPUT_NOPULL); + + // Now, apply the configuration + GPIOs_loadConfigs(); + + + UART_enableRX(1); + + set_debug_reg1(0xAA); // start sending B + wait_for_char("B"); + + set_debug_reg1(0xBB); // start sending M + wait_for_char("M"); + + set_debug_reg1(0xCC); // start sending A + wait_for_char("A"); + +} diff --git a/verilog/dv/cocotb/all_tests/uart/uart_rx_msg.c b/verilog/dv/cocotb/all_tests/uart/uart_rx_msg.c new file mode 100644 index 000000000..e668171d8 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/uart/uart_rx_msg.c @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +void main(){ + enable_debug(); + enableHkSpi(0); + GPIOs_configure(6,GPIO_MODE_MGMT_STD_OUTPUT); + GPIOs_configure(5,GPIO_MODE_MGMT_STD_INPUT_NOPULL); + + // Now, apply the configuration + GPIOs_loadConfigs(); + UART_enableTX(1); + UART_enableRX(1); + + set_debug_reg1(0xAA); // configuration finished + char* msg = UART_readLine(); + print(msg); + +} diff --git a/verilog/dv/cocotb/all_tests/uart/uart_tx.c b/verilog/dv/cocotb/all_tests/uart/uart_tx.c new file mode 100644 index 000000000..89f11bfba --- /dev/null +++ b/verilog/dv/cocotb/all_tests/uart/uart_tx.c @@ -0,0 +1,50 @@ +/* + * SPDX-FileCopyrightText: 2020 Efabless Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + + +// -------------------------------------------------------- + +void main(){ + enable_debug(); + enableHkSpi(0); + GPIOs_configure(6,GPIO_MODE_MGMT_STD_OUTPUT); + + // Set clock to 64 kbaud and enable the UART. It is important to do this + // before applying the configuration, or else the Tx line initializes as + // zero, which indicates the start of a byte to the receiver. + + + // Now, apply the configuration + GPIOs_loadConfigs(); + +// reg_uart_clkdiv = 625; + UART_enableTX(1); + + set_debug_reg1(0xAA); + + // This should appear at the output, received by the testbench UART. + // (Makes simulation time long.) +// print("test msg\n"); + print("Monitor: Test UART (RTL) passed\n"); + + // Allow transmission to complete before signalling that the program + // has ended. + dummyDelay(160); +} diff --git a/verilog/dv/cocotb/all_tests/user_project/user_address_space.c b/verilog/dv/cocotb/all_tests/user_project/user_address_space.c new file mode 100644 index 000000000..f14b00bd8 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/user_project/user_address_space.c @@ -0,0 +1,55 @@ +#include + + + +// -------------------------------------------------------- + +void main() +{ + User_enableIF(); + // first 2 addresses + (*(volatile unsigned int*) (USER_SPACE_ADDR )) = 0x0314DFE1; + (*(volatile unsigned int*) (USER_SPACE_ADDR +0x4 )) = 0x3704E836; + + // last 2 addresses + (*(volatile unsigned int*) (USER_SPACE_ADDR + USER_SPACE_SIZE -0x4 )) = 0x5208E431; + (*(volatile unsigned int*) (USER_SPACE_ADDR + USER_SPACE_SIZE)) = 0x77748E32; + + + // random addresses inside the user space + (*(volatile unsigned int*) (USER_SPACE_ADDR + 0x344F4)) = 0x89158A64; + (*(volatile unsigned int*) (USER_SPACE_ADDR + 0x4F750)) = 0xAE603480; + (*(volatile unsigned int*) (USER_SPACE_ADDR + 0x6CE0C)) = 0xD24B086A; + (*(volatile unsigned int*) (USER_SPACE_ADDR + 0x8FEE8)) = 0xE50B1442; + (*(volatile unsigned int*) (USER_SPACE_ADDR + 0xB767C)) = 0xB23D7EFD; + (*(volatile unsigned int*) (USER_SPACE_ADDR + 0xD0A00)) = 0x41C35871; + (*(volatile unsigned int*) (USER_SPACE_ADDR + 0xF11D0)) = 0xC0E1638A; + (*(volatile unsigned int*) (USER_SPACE_ADDR + 0xC5E54)) = 0x8E16CDA9; + (*(volatile unsigned int*) (USER_SPACE_ADDR + 0xE9028)) = 0x42EB0C85; + (*(volatile unsigned int*) (USER_SPACE_ADDR + 0x023BC)) = 0xBF9E7B2E; + // random read + int temp; + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR )); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + 0x4)); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + USER_SPACE_SIZE - 0x4)); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + USER_SPACE_SIZE)); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + 0x344F4)); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + 0x4F750)); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + 0x6CE0C)); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + 0x8FEE8)); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + 0xB767C)); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + 0xD0A00)); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + 0xF11D0)); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + 0xC5E54)); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + 0xE9028)); + temp = (*(volatile unsigned int*) (USER_SPACE_ADDR + 0x023BC)); + + // addresses outside user space - injecting error if user project ack is affected + GPIOs_configure(14,GPIO_MODE_MGMT_STD_OUTPUT); + GPIOs_configure(15,GPIO_MODE_MGMT_STD_OUTPUT); + + // finish with writing last address with Fs + (*(volatile unsigned int*)(USER_SPACE_ADDR + USER_SPACE_SIZE)) = 0xFFFFFFFF; + + +} diff --git a/verilog/dv/cocotb/all_tests/user_project/user_address_space.py b/verilog/dv/cocotb/all_tests/user_project/user_address_space.py new file mode 100644 index 000000000..23944747f --- /dev/null +++ b/verilog/dv/cocotb/all_tests/user_project/user_address_space.py @@ -0,0 +1,113 @@ +import cocotb +from cocotb.triggers import RisingEdge, NextTimeStep +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test +from user_design import configure_userdesign + + +@cocotb.test() +@report_test +async def user_address_space(dut): + caravelEnv = await test_configure(dut, timeout_cycles=31776) + cocotb.log.info("[TEST] Start user_address_space test") + ack_hdl = caravelEnv.caravel_hdl.mprj.wbs_ack_o + addr_hdl = caravelEnv.caravel_hdl.mprj.wbs_adr_i + data_o_hdl = caravelEnv.caravel_hdl.mprj.wbs_dat_o + data_i_hdl = caravelEnv.caravel_hdl.mprj.wbs_dat_i + we_hdl = caravelEnv.caravel_hdl.mprj.wbs_we_i + + start_addr = int(caravelEnv.design_macros.USER_SPACE_ADDR) + print(f"user space adddress = {start_addr}") + user_size = int(caravelEnv.design_macros.USER_SPACE_SIZE) + addr_arr = ( + start_addr, + start_addr + 4, + start_addr + user_size - 4, + start_addr + user_size, + start_addr + 0x344F4, + start_addr + 0x4F750, + start_addr + 0x6CE0C, + start_addr + 0x8FEE8, + start_addr + 0xB767C, + start_addr + 0xD0A00, + start_addr + 0xF11D0, + start_addr + 0xC5E54, + start_addr + 0xE9028, + start_addr + 0x023BC, + #read + start_addr, + start_addr + 4, + start_addr + user_size - 4, + start_addr + user_size, + start_addr + 0x344F4, + start_addr + 0x4F750, + start_addr + 0x6CE0C, + start_addr + 0x8FEE8, + start_addr + 0xB767C, + start_addr + 0xD0A00, + start_addr + 0xF11D0, + start_addr + 0xC5E54, + start_addr + 0xE9028, + start_addr + 0x023BC, + start_addr + user_size + ) + data_arr = ( + 0x0314DFE1, + 0x3704E836, + 0x5208E431, + 0x77748E32, + 0x89158A64, + 0xAE603480, + 0xD24B086A, + 0xE50B1442, + 0xB23D7EFD, + 0x41C35871, + 0xC0E1638A, + 0x8E16CDA9, + 0x42EB0C85, + 0xBF9E7B2E, + #read + 0x0314DFE1, + 0x3704E836, + 0x5208E431, + 0x77748E32, + 0x89158A64, + 0xAE603480, + 0xD24B086A, + 0xE50B1442, + 0xB23D7EFD, + 0x41C35871, + 0xC0E1638A, + 0x8E16CDA9, + 0x42EB0C85, + 0xBF9E7B2E + ) + await configure_userdesign(caravelEnv, used_addr=addr_arr) + print([hex(i) for i in addr_arr]) + for addr, data in zip(addr_arr, data_arr): + await RisingEdge(ack_hdl) + await NextTimeStep() + if addr_hdl.value.integer != addr: + cocotb.log.error( + f"[TEST] seeing unexpected address {hex(addr_hdl.value.integer)} expected {hex(addr)}" + ) + elif we_hdl.value.integer == 1:# write + if data_i_hdl.value.integer != data: + cocotb.log.error( + f"[TEST] seeing unexpected write data {hex(data_i_hdl.value.integer)} expected {hex(data)} address {hex(addr)}" + ) + else: + cocotb.log.info( + f"[TEST] seeing the correct data {hex(data)} from address {hex(addr)}" + ) + elif we_hdl.value.integer == 0:# read + if data_o_hdl.value.integer != data: + cocotb.log.error( + f"[TEST] seeing unexpected read data {hex(data_o_hdl.value.integer)} expected {hex(data)} address {hex(addr)}" + ) + + else: + cocotb.log.info( + f"[TEST] seeing the correct data {hex(data)} from address {hex(addr)}" + ) diff --git a/verilog/dv/cocotb/all_tests/user_project/user_ram.c b/verilog/dv/cocotb/all_tests/user_project/user_ram.c new file mode 100644 index 000000000..c21b504a1 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/user_project/user_ram.c @@ -0,0 +1,57 @@ +#include + + +/* +This test is developed for testing RAM used inside the user area by swift 2 release +*/ + +void main(){ + enable_debug(); + enableHkSpi(0); + GPIOs_configureAll(GPIO_MODE_MGMT_STD_OUTPUT); + GPIOs_loadConfigs(); + GPIOs_writeLow(0); + unsigned int *dff_start_address = (unsigned int *) AHB_EXT_BASE_ADDR; + unsigned int dff_size = 2048/4; + unsigned int data = 0x55555555; + unsigned int mask = 0xFFFFFFFF; + unsigned int shifting =0; + unsigned int data_used = 0; + for (unsigned int i = 0; i < dff_size; i++){ + shifting = mask - (0x1 << i%32); + data_used = data & shifting; + data_used = data_used | i; // to dectect if rollover to the address happened before size reached + *(dff_start_address+i) = data_used; + } + + for (unsigned int i = 0; i < dff_size; i++){ + shifting = mask - (0x1 << i %32); + data_used = data & shifting; + data_used = data_used | i; + if (data_used != *(dff_start_address+i)){ + // set_debug_reg2(i+dff_start_address); + GPIOs_writeLow(0x1E); + return; + } + } + + data = 0xAAAAAAAA; + for (unsigned int i = 0; i < dff_size; i++){ + shifting = mask - (0x1 << i%32); + data_used = data & shifting; + data_used = data_used | i; + *(dff_start_address+i) = data_used; + } + for (unsigned int i = 0; i < dff_size; i++){ + shifting = mask - (0x1 << i %32); + data_used = data & shifting; + data_used = data_used | i; + if (data_used != *(dff_start_address+i)){ + // set_debug_reg2(i+dff_start_address); + GPIOs_writeLow(0x1E); + return; + } + } + + GPIOs_writeLow(0x1B); +} \ No newline at end of file diff --git a/verilog/dv/cocotb/all_tests/user_project/user_ram.py b/verilog/dv/cocotb/all_tests/user_project/user_ram.py new file mode 100644 index 000000000..5996f1099 --- /dev/null +++ b/verilog/dv/cocotb/all_tests/user_project/user_ram.py @@ -0,0 +1,40 @@ +import cocotb +from cocotb.triggers import ClockCycles +import cocotb.log +from caravel_cocotb.caravel_interfaces import test_configure +from caravel_cocotb.caravel_interfaces import report_test + + +@cocotb.test() +@report_test +async def user_ram(dut): + caravelEnv = await test_configure(dut, timeout_cycles=1167331) + cocotb.log.info("[TEST] Start user RAM word access stress test") + pass_list = [0x1B] + fail_list = [0x1E] + reg1 = 0 # buffer + await wait_configure(caravelEnv) + while True: + if caravelEnv.monitor_gpio((31, 0)).integer == 0xFF: # test finish + break + if reg1 != caravelEnv.monitor_gpio((31, 0)).integer: + reg1 = caravelEnv.monitor_gpio((31, 0)).integer + if reg1 in pass_list: # pass phase + cocotb.log.info("[TEST] pass writing and reading all dff2 memory ") + break + elif reg1 in fail_list: # pass phase + cocotb.log.error("[TEST] failed access address") + break + await ClockCycles(caravelEnv.clk, 1000) + + +async def wait_configure(caravelEnv): + serial_load = caravelEnv.caravel_hdl.housekeeping.serial_load + while True: + if serial_load.value: + cocotb.log.info(f"serial load is asserted serial_load = {serial_load}") + break + await ClockCycles(caravelEnv.clk, 1) + await ClockCycles(caravelEnv.clk, 10) + await caravelEnv.release_csb() + await ClockCycles(caravelEnv.clk, 10) diff --git a/verilog/dv/cocotb/cocotb_tests.py b/verilog/dv/cocotb/cocotb_tests.py new file mode 100644 index 000000000..51aa84aed --- /dev/null +++ b/verilog/dv/cocotb/cocotb_tests.py @@ -0,0 +1,36 @@ +from all_tests.gpio.gpio import * +from all_tests.bitbang.bitbang_tests import * +from all_tests.bitbang.bitbang_tests_cpu import * +from all_tests.housekeeping.housekeeping_regs.housekeeping_regs_tests import * +from all_tests.housekeeping.housekeeping_spi.user_pass_thru import * +from all_tests.housekeeping.housekeeping_spi.mgmt_pass_thru import * +from all_tests.housekeeping.housekeeping_spi.spi import * +from all_tests.housekeeping.general.pll import * +from all_tests.housekeeping.general.sys_ctrl import * +from all_tests.hello_world.helloWorld import * +from all_tests.cpu.cpu_stress import * +from all_tests.mem.mem_stress import * +from all_tests.irq.user_irq import * +from all_tests.irq.IRQ_external import * +from all_tests.irq.IRQ_external2 import * +from all_tests.irq.IRQ_timer import * +from all_tests.irq.IRQ_uart import * +from all_tests.irq.IRQ_uart_rx import * +from all_tests.irq.IRQ_spi import * +from all_tests.gpio_caravan.gpio_caravan import * +from all_tests.gpio.gpio_user import * +from all_tests.mgmt_gpio.mgmt_gpio import * +from all_tests.timer.timer import * +from all_tests.uart.uart import * +from all_tests.spi_master.spi_master import * +from all_tests.logicAnalyzer.la import * +from all_tests.debug.debug import * +from all_tests.debug.debug_swd import * +from all_tests.cpu.cpu_reset import * +from all_tests.user_project.user_address_space import * +from all_tests.shifting.shifting import * +from all_tests.PoR.PoR import * +from all_tests.user_project.user_ram import * +from all_tests.temp.temp import * +from all_tests.flash_clk.flash_clk import * +from all_tests.check_defaults.check_defaults import * diff --git a/verilog/dv/cocotb/design_info.yaml b/verilog/dv/cocotb/design_info.yaml new file mode 100644 index 000000000..8150aec9f --- /dev/null +++ b/verilog/dv/cocotb/design_info.yaml @@ -0,0 +1,37 @@ +# yaml file contain general design information that would mostly need to be updated in the first run only + +#eg CARAVEL_ROOT: "/usr/Desktop/caravel_project/caravel/" +#like repo https://github.com/efabless/caravel + +CARAVEL_ROOT: /home/passant/caravel-gf180mcu + +#eg MCW_ROOT: "/usr/Desktop/caravel_project/caravel_mgmt_soc_litex/" +#like repo https://github.com/efabless/caravel_mgmt_soc_litex + +MCW_ROOT: "/home/passant/caravel_mgmt_soc_gf180mcu/" + +#eg USER_PROJECT_ROOT: "/usr/Desktop/caravel_project/caravel_user_project/" +#like repo https://github.com/efabless/caravel_user_project +USER_PROJECT_ROOT: /home/passant/gf180_upw/ + +# USER_PROJECT_ROOT: None +# USER_PROJECT_ROOT: None + + + +#eg PDK_ROOT: "/usr/Desktop/caravel_project/pdk/" +#exported by volare +PDK_ROOT: "/home/passant/OpenLane/pdks" + +#eg PDK: "sky130A" +PDK: gf180mcuD +#PDK: gf180mcuC + +#clock in ns +clk: 30 + +# true when caravan are simulated instead of caravel +caravan: false + +# optional email address to send the results to +emailto: [bassant.hassan@efabless.com,None] \ No newline at end of file diff --git a/verilog/dv/cocotb/models/cpu_model/cpu_model.py b/verilog/dv/cocotb/models/cpu_model/cpu_model.py new file mode 100644 index 000000000..07b09ce25 --- /dev/null +++ b/verilog/dv/cocotb/models/cpu_model/cpu_model.py @@ -0,0 +1,117 @@ +import cocotb +from models.cpu_model.cpu_monitor import CPU_Monitor +from cocotb.queue import Queue +from collections import namedtuple +import logging +from tabulate import tabulate + + +SPI_Operation = namedtuple("SPI_Operation", ["command", "address", "data_in", "data_out"]) + + +class CPU_Model(): + def __init__(self, caravelEnv) -> None: + self.caravelEnv = caravelEnv + dbus_queue = Queue() + ibus_queue = Queue() + CPU_Monitor(self.caravelEnv, dbus_queue, ibus_queue) + Dbus_Model(dbus_queue) + Ibus_Model(ibus_queue) + + +class AbstractModelCPU(): + def __init__(self, queue) -> None: + self._thread = cocotb.scheduler.add(self._model(queue)) + + async def _model(self, queue): + pass + + async def _get_transactions(self, queue): + transaction = await queue.get() + cocotb.log.debug(f"[{__class__.__name__}][_get_transactions] getting transaction {transaction} from monitor") + return transaction + + def configure_logger(self, logger_name="logger", logger_file="log.txt"): + self.model_logger = logging.getLogger(logger_name) + + # Configure the logger + self.model_logger.setLevel(logging.INFO) + + # Create a FileHandler to log to a file + file_handler = logging.FileHandler(logger_file) + file_handler.setLevel(logging.INFO) + + # # Create a StreamHandler to log to the console (optional) + # console_handler = logging.StreamHandler() + # console_handler.setLevel(logging.DEBUG) + + # Add the handlers to the logger + self.model_logger.addHandler(file_handler) + # Create a NullHandler for the console to suppress output + + # self.model_logger.addHandler(console_handler) # Optional: Log to console + # Remove the console handler to avoid logging to console + + # log the header + self.log_operation(None, header_logged=True) + + def log_operation(self, transaction, header_logged): + pass + + +class Dbus_Model(AbstractModelCPU): + def __init__(self, queue) -> None: + self.configure_logger(logger_name="CPU_DBUS_LOG", logger_file="cpu_dbus.log") + super().__init__(queue) + + async def _model(self, queue): + while True: + transaction = await self._get_transactions(queue) + cocotb.log.debug(f"[{__class__.__name__}][_model] {transaction}") + self.log_operation(transaction) + + def log_operation(self, transaction, header_logged=False): + if header_logged: + # Log the header + header = tabulate([], headers=["Time", "Type", "Address", "Select", "Data"], tablefmt="grid") + self.model_logger.info(header) + # Mark that the header has been logged + else: + table_data = [( + f"{cocotb.utils.get_sim_time(units='ns')} ns", + "read" if transaction.write == 0 else "wrote", + hex(transaction.address<<2), + hex(transaction.select), + transaction.data if "x" in transaction.data.binstr else hex(transaction.data.integer) + )] + table = tabulate(table_data, tablefmt="grid") + self.model_logger.info(table) + + +class Ibus_Model(AbstractModelCPU): + def __init__(self, queue) -> None: + self.configure_logger(logger_name="CPU_IBUS_LOG", logger_file="cpu_ibus.log") + super().__init__(queue) + + async def _model(self, queue): + while True: + transaction = await self._get_transactions(queue) + cocotb.log.debug(f"[{__class__.__name__}][_model] {transaction}") + self.log_operation(transaction) + + def log_operation(self, transaction, header_logged=False): + if header_logged: + # Log the header + header = tabulate([], headers=["Time", "Type", "Address", "Select", "Data"], tablefmt="grid") + self.model_logger.info(header) + # Mark that the header has been logged + else: + table_data = [( + f"{cocotb.utils.get_sim_time(units='ns')} ns", + "read" if transaction.write == 0 else "wrote", + hex(transaction.address<<2), + hex(transaction.select), + transaction.data if "x" in transaction.data.binstr else hex(transaction.data.integer) + )] + table = tabulate(table_data, tablefmt="grid") + self.model_logger.info(table) diff --git a/verilog/dv/cocotb/models/cpu_model/cpu_monitor.py b/verilog/dv/cocotb/models/cpu_model/cpu_monitor.py new file mode 100644 index 000000000..9244524ce --- /dev/null +++ b/verilog/dv/cocotb/models/cpu_model/cpu_monitor.py @@ -0,0 +1,57 @@ +import cocotb +from cocotb.triggers import RisingEdge +from collections import namedtuple + +WB_Transaction = namedtuple("WB_Transaction", ["address", "write", "data", "select"]) + + +class CPU_Monitor(): + def __init__(self, Caravel_env, dbus_queue, ibus_queue): + self.cpu_hdl = Caravel_env.caravel_hdl.soc.core.VexRiscv + self._dbus_fork = cocotb.scheduler.add(self._dbus_monitor(dbus_queue)) + self._ibus_fork = cocotb.scheduler.add(self._ibus_monitor(ibus_queue)) + + async def _dbus_monitor(self, queue): + self._dbus_hdls() + while True: + # valid transaction only happened if ack is sent + await RisingEdge(self.dbus_ack_hdl) + is_write = self.dbus_we_hdl.value.integer + transaction = WB_Transaction(address=self.dbus_adr_hdl.value.integer, write=is_write, data=self.dbus_data_write_hdl.value if is_write else self.dbus_data_read_hdl.value, select=self.dbus_sel_hdl.value.integer) + queue.put_nowait(transaction) + cocotb.log.debug(f"[{__class__.__name__}][_dbus_monitor] sending transaction {transaction} to queuq") + + async def _ibus_monitor(self, queue): + self._ibus_hdls() + while True: + # valid transaction only happened if ack is sent + await RisingEdge(self.ibus_ack_hdl) + is_write = self.ibus_we_hdl.value.integer + transaction = WB_Transaction(address=self.ibus_adr_hdl.value.integer, write=is_write, data=self.ibus_data_write_hdl.value if is_write else self.ibus_data_read_hdl.value, select=self.ibus_sel_hdl.value.integer) + queue.put_nowait(transaction) + cocotb.log.debug(f"[{__class__.__name__}][_ibus_monitor] sending transaction {transaction} to queuq") + + def _dbus_hdls(self): + self.dbus_clk_hdl = self.cpu_hdl.clk + self.dbus_rst_hdl = self.cpu_hdl.reset + self.dbus_adr_hdl = self.cpu_hdl.dBusWishbone_ADR + self.dbus_data_read_hdl = self.cpu_hdl.dBusWishbone_DAT_MISO + self.dbus_sel_hdl = self.cpu_hdl.dBusWishbone_SEL + self.dbus_we_hdl = self.cpu_hdl.dBusWishbone_WE + self.dbus_cyc_hdl = self.cpu_hdl.dBusWishbone_CYC + self.dbus_stb_hdl = self.cpu_hdl.dBusWishbone_STB + self.dbus_ack_hdl = self.cpu_hdl.dBusWishbone_ACK + self.dbus_data_write_hdl = self.cpu_hdl.dBusWishbone_DAT_MOSI + + def _ibus_hdls(self): + self.ibus_clk_hdl = self.cpu_hdl.clk + self.ibus_rst_hdl = self.cpu_hdl.reset + self.ibus_adr_hdl = self.cpu_hdl.iBusWishbone_ADR + self.ibus_data_read_hdl = self.cpu_hdl.iBusWishbone_DAT_MISO + self.ibus_sel_hdl = self.cpu_hdl.iBusWishbone_SEL + self.ibus_we_hdl = self.cpu_hdl.iBusWishbone_WE + self.ibus_cyc_hdl = self.cpu_hdl.iBusWishbone_CYC + self.ibus_stb_hdl = self.cpu_hdl.iBusWishbone_STB + self.ibus_ack_hdl = self.cpu_hdl.iBusWishbone_ACK + self.ibus_data_write_hdl = self.cpu_hdl.iBusWishbone_DAT_MOSI + diff --git a/verilog/dv/cocotb/models/gpio_model/gpio_coverage.py b/verilog/dv/cocotb/models/gpio_model/gpio_coverage.py new file mode 100644 index 000000000..201ddf85a --- /dev/null +++ b/verilog/dv/cocotb/models/gpio_model/gpio_coverage.py @@ -0,0 +1,154 @@ +from cocotb_coverage.coverage import CoverPoint, CoverCross, CoverageDB +import cocotb + + +class GPIOs_Coverage(): + def __init__(self) -> None: + # initialize coverage no covearge happened just sample nothing so the coverge is initialized + self.gpios_cov = dict() + for gpio_num in range(38): + for ty in ["configured", "default"]: + self.gpios_cov[(gpio_num, ty)] = GPIO_coverage(gpio_num, ty) + + def gpio_cov(self, operation, do_sampling=True): + gpio_num = operation.gpio_number + ty = operation.config_type + self.gpios_cov[(gpio_num, ty)].gpio_config_cov(operation, do_sampling) + + def io_cov(self, operation, do_sampling=True): + gpio_num = operation.gpio_number + ty = "configured" + self.gpios_cov[(gpio_num, ty)].gpio_io_cov(operation, do_sampling) + + +class GPIO_coverage(): + def __init__(self, gpio_number, config_type) -> None: + self.gpio_number = gpio_number + self.config_type = config_type + self.control_list = ["user", "managment"] + self.input_list = ["input enabled", "input disabled"] + self.output_list = ["output enabled", "output disabled"] + self.dm_list = ["no pull", "pull up", "pull down", "float", "analog"] + self.config_valid_ignore = [(i, j, "input disabled", k) for i in self.control_list for j in self.output_list for k in ['pull down', 'pull up']] + [(i, 'output disabled', 'input enabled', j) for i in self.control_list for j in ["pull down", "pull up"]] + [(i, j, 'input disabled', "no pull") for i in self.control_list for j in self.output_list] + [(i, 'output enabled', 'input enabled', 'no pull') for i in self.control_list] + [(i, 'output disabled', j, 'float') for i in self.control_list for j in self.input_list] + [(i, 'output enabled', j, 'analog') for i in self.control_list for j in self.input_list] + [(i, j, "input enabled", 'analog') for i in self.control_list for j in self.output_list] + [('managment', 'output enabled', 'input enabled', 'float')] + # initialize coverage no covearge happened just sample nothing so the coverge is initialized + self.gpio_config_cov(None, do_sampling=False) + self.gpio_io_cov(None, do_sampling=False) + + def gpio_io_cov(self, operation, do_sampling=True): + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.IO.managment", + xf=lambda operation: operation, + bins=[("mgmt", "input", "0"), ("mgmt", "input", "1"), ("mgmt", "output", "0"), ("mgmt", "output", "1")], + bins_labels=[ "input 0", "input 1", "output 0", "output 1"], + rel=lambda val, b: val.control == b[0] and val.io == b[1] and val.value == b[2] + ) + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.IO.user", + xf=lambda operation: operation, + bins=[("user", "input", "0"), ("user", "input", "1"), ("user", "output", "0"), ("user", "output", "1")], + bins_labels=["input 0", "input 1", "output 0", "output 1"], + rel=lambda val, b: val.control == b[0] and val.io == b[1] and val.value == b[2] + ) + @CoverCross( + f"top.caravel.gpios.GPIO{self.gpio_number}.IO.in_out_user_configs", + items=[ + f"top.caravel.gpios.GPIO{self.gpio_number}.IO.user", + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.controlled_by", + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.output", + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.input", + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.dm" + ], + ign_bins=[(i, valid[0], valid[1], valid[2], valid[3]) for i in ["input 0", "input 1", "output 0", "output 1"] for valid in self.config_valid_ignore] + [(i, 'managment', j, k, l) for i in ["input 0", "input 1", "output 0", "output 1"] for j in self.output_list for k in self.input_list for l in self.dm_list] + [(i,'user', j, 'input disabled', k) for i in ["input 0", "input 1"] for j in self.output_list for k in self.dm_list if k != "analog"] + [(i, 'user', 'output disabled', j, k) for i in ["output 0", "output 1"] for j in self.input_list for k in self.dm_list if k != "analog"] + [(i, 'user', j, k, l) for i in ["output 0", "output 1"] for j in self.output_list for k in self.input_list for l in ["pull down", "pull up", "no pull"]] + ) + @CoverCross( + f"top.caravel.gpios.GPIO{self.gpio_number}.IO.in_out_mgmt_configs", + items=[ + f"top.caravel.gpios.GPIO{self.gpio_number}.IO.managment", + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.controlled_by", + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.output", + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.input", + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.dm" + ], + ign_bins=[(i, valid[0], valid[1], valid[2], valid[3]) for i in ["input 0", "input 1", "output 0", "output 1"] for valid in self.config_valid_ignore] + [(i, 'user', j, k, l) for i in ["input 0", "input 1", "output 0", "output 1"] for j in self.output_list for k in self.input_list for l in self.dm_list] + [(i,'managment', j, 'input disabled', k) for i in ["input 0", "input 1"] for j in self.output_list for k in self.dm_list if k != "analog"] + [(i, 'managment', 'output disabled', j, k) for i in ["output 0", "output 1"] for j in self.input_list for k in self.dm_list if k != "analog"] + [(i, 'managment', j, k, l) for i in ["output 0", "output 1"] for j in self.output_list for k in self.input_list for l in ["pull down", "pull up", "no pull"]] + ) + def sample(operation): + # if self.gpio_number == 0: + # cocotb.log.info(f"[COV] io_user = {CoverageDB()[f'top.caravel.gpios.GPIO{self.gpio_number}.IO.user'].detailed_coverage}") + # cocotb.log.info(f"[COV] valid = {CoverageDB()[f'top.caravel.gpios.GPIO{self.gpio_number}.configured.valid_configs'].detailed_coverage}") + pass + if do_sampling: + sample(operation) + def gpio_config_cov(self, operation, do_sampling=True): + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.controlled_by", + xf=lambda operation: operation.mgmt_en, + bins=[0, 1], + bins_labels=self.control_list, + ) + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.output", + xf=lambda operation: operation.outenb, + bins=[0, 1], + bins_labels=self.output_list, + ) + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.input", + xf=lambda operation: operation.inenb, + bins=[0, 1], + bins_labels=self.input_list, + ) + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.dm", + xf=lambda operation: operation.dm, + bins=[0x1, 0x2, 0x3, 0x6, 0x0], + bins_labels=self.dm_list + ) + @CoverCross( + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.valid_configs", + items=[ + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.controlled_by", + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.output", + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.input", + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.dm", + ], + ign_bins=self.config_valid_ignore + ) + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.hold_override_val", + xf=lambda operation: operation.holdover, + bins=[0x0], # TODO: update it when the bit functionality is implemented + ) + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.IB_mode_select", + xf=lambda operation: operation.ib_sel, + bins=[0x0], # TODO: update it when the bit functionality is implemented + ) + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.analog_bus_en", + xf=lambda operation: operation.ana_en, + bins=[0x0], # TODO: update it when the bit functionality is implemented + ) + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.analog_bus_select", + xf=lambda operation: operation.ana_sel, + bins=[0x0], # TODO: update it when the bit functionality is implemented + ) + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.analog_bus_polarity", + xf=lambda operation: operation.ana_pol, + bins=[0x0], # TODO: update it when the bit functionality is implemented + ) + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.slow_slew", + xf=lambda operation: operation.slow_selw, + bins=[0x0], # TODO: update it when the bit functionality is implemented + ) + @CoverPoint( + f"top.caravel.gpios.GPIO{self.gpio_number}.{self.config_type}.voltage_trip_select", + xf=lambda operation: operation.vtrip, + bins=[0x0], # TODO: update it when the bit functionality is implemented + ) + def sample(operation): + pass + if do_sampling: + sample(operation) \ No newline at end of file diff --git a/verilog/dv/cocotb/models/gpio_model/gpio_model.py b/verilog/dv/cocotb/models/gpio_model/gpio_model.py new file mode 100644 index 000000000..5b72cc4e1 --- /dev/null +++ b/verilog/dv/cocotb/models/gpio_model/gpio_model.py @@ -0,0 +1,100 @@ +from cocotb.queue import Queue +import cocotb +import logging +from tabulate import tabulate +from models.gpio_model.gpio_monitor import GPIOs_Monitor +from models.gpio_model.gpio_coverage import GPIOs_Coverage + + +class GPIOs_Model(): + def __init__(self, caravelEnv) -> None: + self.caravelEnv = caravelEnv + config_queue = Queue() + io_queue = Queue() + GPIOs_Monitor(self.caravelEnv, config_queue, io_queue) + gpios_cov = GPIOs_Coverage() + ConfigModel(config_queue, gpios_cov) + IO_Model(io_queue, gpios_cov) + +class AbstractModelGPIO(): + def __init__(self, queue) -> None: + self._thread = cocotb.scheduler.add(self._model(queue)) + + async def _model(self, queue): + pass + + async def _get_transactions(self, queue): + transaction = await queue.get() + cocotb.log.debug(f"[{__class__.__name__}][_get_transactions] getting transaction {transaction} from monitor") + return transaction + + def configure_logger(self, logger_name="logger", logger_file="log.txt"): + self.spi_logger = logging.getLogger(logger_name) + + # Configure the logger + self.spi_logger.setLevel(logging.INFO) + + # Create a FileHandler to log to a file + file_handler = logging.FileHandler(logger_file) + file_handler.setLevel(logging.INFO) + + # # Create a StreamHandler to log to the console (optional) + # console_handler = logging.StreamHandler() + # console_handler.setLevel(logging.DEBUG) + + # Add the handlers to the logger + self.spi_logger.addHandler(file_handler) + # Create a NullHandler for the console to suppress output + + # self.spi_logger.addHandler(console_handler) # Optional: Log to console + # Remove the console handler to avoid logging to console + + # log the header + self.log_operation(None, header_logged=True) + + def log_operation(self, transaction, header_logged): + pass + + +class ConfigModel(AbstractModelGPIO): + def __init__(self, queue, gpios_cov) -> None: + self.configure_logger(logger_name="GPIO_config_LOG", logger_file="gpio_config.log") + self.gpios_cov = gpios_cov + super().__init__(queue) + + async def _model(self, queue): + while True: + transaction = await self._get_transactions(queue) + cocotb.log.debug(f"[{__class__.__name__}][_model] {transaction}") + self.log_operation(transaction) + self.gpios_cov.gpio_cov(transaction) + + def log_operation(self, transaction, header_logged=False): + if header_logged: + # Log the header + header = tabulate([], headers=["Time", "GPIO","config Type", "controlled by", "in/out", "dm"], tablefmt="grid") + self.spi_logger.info(header) + # Mark that the header has been logged + else: + table_data = [( + f"{cocotb.utils.get_sim_time(units='ns')} ns", + f"GPIO{transaction.gpio_number}", + transaction.config_type, + "Managment" if transaction.mgmt_en == 1 else "User", + "bi-directional" if transaction.inenb == 0 and transaction.outenb == 0 else "output" if transaction.outenb == 0 else "input" if transaction.inenb == 0 else "unknown", + "no_pull" if transaction.dm == 0x1 else "pull up" if transaction.dm == 0x2 else "pull down" if transaction.dm == 0x3 else "float" if transaction.dm == 0x6 else "analog" if transaction.dm == 0x0 else transaction.dm + )] + table = tabulate(table_data, tablefmt="grid") + self.spi_logger.info(table) + + +class IO_Model(AbstractModelGPIO): + def __init__(self, queue, gpios_cov) -> None: + self.gpios_cov = gpios_cov + super().__init__(queue) + + async def _model(self, queue): + while True: + transaction = await self._get_transactions(queue) + cocotb.log.debug(f"[{__class__.__name__}][_model] {transaction}") + self.gpios_cov.io_cov(transaction) diff --git a/verilog/dv/cocotb/models/gpio_model/gpio_monitor.py b/verilog/dv/cocotb/models/gpio_model/gpio_monitor.py new file mode 100644 index 000000000..095f3b5ec --- /dev/null +++ b/verilog/dv/cocotb/models/gpio_model/gpio_monitor.py @@ -0,0 +1,143 @@ +import cocotb +from cocotb.triggers import RisingEdge, Edge, First, NextTimeStep +from collections import namedtuple + +GPIO_Config = namedtuple("GPIO_Config", ["gpio_number", "config_type", "mgmt_en", "outenb", "holdover", "inenb", "ib_sel", "ana_en", "ana_sel", "ana_pol", "slow_selw", "vtrip", "dm"]) +GPIO_IO = namedtuple("GPIO_IO", ["gpio_number", "control", "io", "value"]) + + +class GPIOs_Monitor(): + def __init__(self, Caravel_env, config_queue, io_queue): + self.caravel_hdl = Caravel_env.caravel_hdl + self.config_queue = config_queue + self.io_queue = io_queue + self.gpio_mapping = { + 0: "gpio_control_bidir_1[0]", + 1: "gpio_control_bidir_1[1]", + 2: "gpio_control_in_1a[0]", + 3: "gpio_control_in_1a[1]", + 4: "gpio_control_in_1a[2]", + 5: "gpio_control_in_1a[3]", + 6: "gpio_control_in_1a[4]", + 7: "gpio_control_in_1a[5]", + 8: "gpio_control_in_1[0]", + 9: "gpio_control_in_1[1]", + 10: "gpio_control_in_1[2]", + 11: "gpio_control_in_1[3]", + 12: "gpio_control_in_1[4]", + 13: "gpio_control_in_1[5]", + 14: "gpio_control_in_1[6]", + 15: "gpio_control_in_1[7]", + 16: "gpio_control_in_1[8]", + 17: "gpio_control_in_1[9]", + 18: "gpio_control_in_1[10]", + 19: "gpio_control_in_2[0]", + 20: "gpio_control_in_2[1]", + 21: "gpio_control_in_2[2]", + 22: "gpio_control_in_2[3]", + 23: "gpio_control_in_2[4]", + 24: "gpio_control_in_2[5]", + 25: "gpio_control_in_2[6]", + 26: "gpio_control_in_2[7]", + 27: "gpio_control_in_2[8]", + 28: "gpio_control_in_2[9]", + 29: "gpio_control_in_2[10]", + 30: "gpio_control_in_2[11]", + 31: "gpio_control_in_2[12]", + 32: "gpio_control_in_2[13]", + 33: "gpio_control_in_2[14]", + 34: "gpio_control_in_2[15]", + 35: "gpio_control_bidir_2[0]", + 36: "gpio_control_bidir_2[1]", + 37: "gpio_control_bidir_2[2]"} + self._config_monitor() + + def _config_monitor(self): + for key, item in self.gpio_mapping.items(): + gpio_hdl = self.caravel_hdl._id(item, False) + GPIO_Monitor(config_queue=self.config_queue, io_queue=self.io_queue, gpio_hdl=gpio_hdl, gpio_num=key) + + +class GPIO_Monitor(): + def __init__(self, config_queue, io_queue, gpio_hdl, gpio_num) -> None: + self.gpio_hdl = gpio_hdl + self.gpio_num = gpio_num + self._config_fork = cocotb.scheduler.add(self._config_monitor(config_queue)) + self._input_fork = cocotb.scheduler.add(self._input_monitor(io_queue)) + self._input_fork = cocotb.scheduler.add(self._output_monitor(io_queue)) + + async def _config_monitor(self, queue): + self._control_block_hdls() + config = GPIO_Config(gpio_number=self.gpio_num, config_type="default", mgmt_en=self.mgmt_ena.value.integer, outenb=self.gpio_outenb.value.integer, holdover=self.gpio_holdover.value.integer, inenb=self.gpio_inenb.value.integer, ib_sel=self.gpio_ib_mode_sel.value.integer, ana_en=self.gpio_ana_en.value.integer, ana_sel=self.gpio_ana_sel.value.integer, ana_pol=self.gpio_ana_pol.value.integer, slow_selw=self.gpio_slow_sel.value.integer, vtrip=self.gpio_vtrip_sel.value.integer, dm=self.gpio_dm.value.integer) + queue.put_nowait(config) + cocotb.log.debug(f"[{__class__.__name__}][_config_monitor] sending config {config} to queue") + while True: + await RisingEdge(self.serial_load) + await NextTimeStep() + config = GPIO_Config(gpio_number=self.gpio_num, config_type="configured", mgmt_en=self.mgmt_ena.value.integer, outenb=self.gpio_outenb.value.integer, holdover=self.gpio_holdover.value.integer, inenb=self.gpio_inenb.value.integer, ib_sel=self.gpio_ib_mode_sel.value.integer, ana_en=self.gpio_ana_en.value.integer, ana_sel=self.gpio_ana_sel.value.integer, ana_pol=self.gpio_ana_pol.value.integer, slow_selw=self.gpio_slow_sel.value.integer, vtrip=self.gpio_vtrip_sel.value.integer, dm=self.gpio_dm.value.integer) + queue.put_nowait(config) + cocotb.log.debug(f"[{__class__.__name__}][_config_monitor] sending config {config} to queue") + + async def _input_monitor(self, queue): + self._ios_hdls() + old_mgmt_in = self.mgmt_in.value.binstr + old_user_in = self.user_in.value.binstr + mgmt_in_edge = Edge(self.mgmt_in) + user_in_edge = Edge(self.user_in) + while True: + await First(mgmt_in_edge, user_in_edge) + await NextTimeStep() + if self.mgmt_in.value.binstr != old_mgmt_in: + transaction = GPIO_IO(gpio_number=self.gpio_num, control="mgmt", io="input", value=self.mgmt_in.value.binstr) + cocotb.log.debug(f"[{__class__.__name__}][_input_monitor] sending transaction {transaction} to queue") + old_mgmt_in = self.mgmt_in.value.binstr + queue.put_nowait(transaction) + if self.user_in.value.binstr != old_user_in: + transaction = GPIO_IO(gpio_number=self.gpio_num, control="user", io="input", value=self.user_in.value.binstr) + cocotb.log.debug(f"[{__class__.__name__}][_input_monitor] sending transaction {transaction} to queue") + old_user_in = self.user_in.value.binstr + queue.put_nowait(transaction) + + async def _output_monitor(self, queue): + self._ios_hdls() + old_mgmt_out = self.mgmt_out.value.binstr + old_user_out = self.user_out.value.binstr + mgmt_out_edge = Edge(self.mgmt_out) + user_out_edge = Edge(self.user_out) + mgmt_oeb_edge = Edge(self.mgmt_oeb) + user_oeb_edge = Edge(self.user_oeb) + while True: + await First(mgmt_out_edge, user_out_edge, mgmt_oeb_edge, user_oeb_edge) + await NextTimeStep() + if self.mgmt_out.value.binstr != old_mgmt_out: + transaction = GPIO_IO(gpio_number=self.gpio_num, control="mgmt", io="output", value=self.mgmt_out.value.binstr) + cocotb.log.debug(f"[{__class__.__name__}][_output_monitor] sending transaction {transaction} to queue") + old_mgmt_out = self.mgmt_out.value.binstr + queue.put_nowait(transaction) + if self.user_out.value.binstr != old_user_out: + transaction = GPIO_IO(gpio_number=self.gpio_num, control="user", io="output", value=self.user_out.value.binstr) + cocotb.log.debug(f"[{__class__.__name__}][_output_monitor] sending transaction {transaction} to queue") + old_user_out = self.user_out.value.binstr + queue.put_nowait(transaction) + + def _control_block_hdls(self): + self.mgmt_ena = self.gpio_hdl.mgmt_ena + self.gpio_holdover = self.gpio_hdl.pad_gpio_holdover + self.gpio_slow_sel = self.gpio_hdl.pad_gpio_slow_sel + self.gpio_vtrip_sel = self.gpio_hdl.pad_gpio_vtrip_sel + self.gpio_ib_mode_sel = self.gpio_hdl.pad_gpio_ib_mode_sel + self.gpio_inenb = self.gpio_hdl.pad_gpio_inenb + self.gpio_outenb = self.gpio_hdl.gpio_outenb + self.gpio_dm = self.gpio_hdl.pad_gpio_dm + self.gpio_ana_en = self.gpio_hdl.pad_gpio_ana_en + self.gpio_ana_sel = self.gpio_hdl.pad_gpio_ana_sel + self.gpio_ana_pol = self.gpio_hdl.pad_gpio_ana_pol + self.serial_load = self.gpio_hdl.serial_load + + def _ios_hdls(self): + self.mgmt_in = self.gpio_hdl.mgmt_gpio_in + self.mgmt_out = self.gpio_hdl.mgmt_gpio_out + self.mgmt_oeb = self.gpio_hdl.mgmt_gpio_oeb + self.user_in = self.gpio_hdl.user_gpio_in + self.user_out = self.gpio_hdl.user_gpio_out + self.user_oeb = self.gpio_hdl.user_gpio_oeb diff --git a/verilog/dv/cocotb/models/housekeeping_model/hk_coverage.py b/verilog/dv/cocotb/models/housekeeping_model/hk_coverage.py new file mode 100644 index 000000000..30ab427ab --- /dev/null +++ b/verilog/dv/cocotb/models/housekeeping_model/hk_coverage.py @@ -0,0 +1,113 @@ +import cocotb +from cocotb_coverage.coverage import CoverPoint, CoverCross +from collections import namedtuple + + +class SPI_Coverage(): + def __init__(self) -> None: + self.command_mapping = { + "10000000": "write stream", + "01000000": "read stream", + "11000000": "write read stream", + "11000100": "Pass-through management", + "00000010": "Pass-through user", + } + self.command_mapping.update({f"10{format(n, '03b')}000": f"write {n}-bytes" for n in range(1,8)}) + self.command_mapping.update({f"01{format(n, '03b')}000": f"read {n}-bytes" for n in range(1,8)}) + self.command_mapping.update({f"11{format(n, '03b')}000": f"write read {n}-bytes" for n in range(1,8)}) + # initialize coverage no covearge happened just sample nothing so the coverge is initialized + temp = namedtuple('temp', ['command', 'address', 'data_in', 'data_out']) + self.spi_cov(None, do_sampling=False) + + def command_to_text(self, command): + cocotb.log.debug(f"[{__class__.__name__}][command_to_text] command = {command}") + if command in self.command_mapping: + return self.command_mapping[command] + else: + return "invalid command" + + def spi_cov(self, spi_operation, do_sampling=True): + @CoverPoint( + "top.caravel.housekeeping.spi.modes", + xf=lambda spi_operation: spi_operation.command, + bins=[x for x in self.command_mapping.values()], + weight=1 + ) + @CoverPoint( + "top.caravel.housekeeping.spi.address", + xf=lambda spi_operation: int(spi_operation.address, 16), + bins=[(0, 0x10), (0x11, 0x20), (0x21, 0x30), (0x31, 0x40), (0x41, 0x50), (0x51, 0x60), (0x61, 0x6D)], + bins_labels=["0 to 16", "17 to 32", "33 to 48", "49 to 64", "65 to 80", "81 to 96", "97 to 109"], + rel=lambda val, b: b[0] <= val <= b[1], + weight=1 + ) + def sample_command(spi_operation): + pass + + @CoverPoint( + "top.caravel.housekeeping.spi.data_write", + xf=lambda data: int(data, 16), + bins=[(0x00, 0x0F), (0x10, 0x1F), (0x20, 0x2F), (0x30, 0x3F), (0x40, 0x4F), (0x50, 0x5F), (0x60, 0x6F), (0x70, 0x7F), (0x80, 0x8F), (0x90, 0x9F), (0xA0, 0xAF), (0xB0, 0xBF), (0xC0, 0xCF), (0xD0, 0xDF), (0xE0, 0xEF), (0xF0, 0xFF)], + bins_labels=["0x0 to 0x0F", "0x10 to 0x1F", "0x20 to 0x2F", "0x30 to 0x3F", "0x40 to 0x4F", "0x50 to 0x5F", "0x60 to 0x6F", "0x70 to 0x7F", "0x80 to 0x8F", "0x90 to 0x9F", "0xA0 to 0xAF", "0xB0 to 0xBF", "0xC0 to 0xCF", "0xD0 to 0xDF", "0xE0 to 0xEF", "0xF0 to 0xFF"], + rel=lambda val, b: b[0] <= val <= b[1], + ) + def sample_write(data): + pass + + @CoverPoint( + "top.caravel.housekeeping.spi.data_read", + xf=lambda data: int(data, 16), + bins=[(0x00, 0x3F), (0x40, 0x7F), (0x80, 0xFF)], + bins_labels=["0x00 to 0x3F", "0x40 to 0x7F", "0x80 to 0xFF"], + rel=lambda val, b: b[0] <= val <= b[1], + ) + def sample_read(data): + pass + if do_sampling: + sample_command(spi_operation) + for data in spi_operation.data_in: + sample_write(data) + for data in spi_operation.data_out: + sample_read(data) + + +class WB_Coverage(): + def __init__(self) -> None: + # initialize coverage no covearge happened just sample nothing so the coverge is initialized + + self.wb_cov(None, do_sampling=False) + + def wb_cov(self, wb_operation, do_sampling=True): + @CoverPoint( + "top.caravel.housekeeping.wishbone.access_type", + xf=lambda wb_operation: wb_operation.write, + bins=[0, 1], + bins_labels=["read", "write"], + weight=1 + ) + @CoverPoint( + "top.caravel.housekeeping.wishbone.address", + xf=lambda wb_operation: wb_operation.address, + bins=[(0x26100000, 0x26100028), (0x26000000, 0x260000b8), (0x26200000, 0x26200010)], + bins_labels=["spi address", "gpio address", "system address"], + rel=lambda val, b: b[0] <= val <= b[1], + weight=1 + ) + @CoverPoint( + "top.caravel.housekeeping.wishbone.write_data", + xf=lambda wb_operation: wb_operation.write_data, + bins=[(0x00000000, 0x5FFFFFFF), (0x60000000, 0xBFFFFFFF), (0xC0000000, 0xFFFFFFFF)], + bins_labels=["0 to 0x5FFFFFFF", "0x60000000 to 0xBFFFFFFF", "0xC0000000 to 0xFFFFFFFF"], + rel=lambda val, b: b[0] <= val <= b[1], + ) + @CoverPoint( + "top.caravel.housekeeping.wishbone.read_data", + xf=lambda wb_operation: wb_operation.read_data, + bins=[(0x00000000, 0x5FFFFFFF), (0x60000000, 0xBFFFFFFF), (0xC0000000, 0xFFFFFFFF)], + bins_labels=["0 to 0x5FFFFFFF", "0x60000000 to 0xBFFFFFFF", "0xC0000000 to 0xFFFFFFFF"], + rel=lambda val, b: b[0] <= val <= b[1], + ) + def sample(wb_operation): + pass + if do_sampling: + sample(wb_operation) diff --git a/verilog/dv/cocotb/models/housekeeping_model/hk_model.py b/verilog/dv/cocotb/models/housekeeping_model/hk_model.py new file mode 100644 index 000000000..b761dcee3 --- /dev/null +++ b/verilog/dv/cocotb/models/housekeeping_model/hk_model.py @@ -0,0 +1,177 @@ +import cocotb +from models.housekeeping_model.hk_monitor import HK_Monitor +from models.housekeeping_model.hk_coverage import SPI_Coverage +from models.housekeeping_model.hk_coverage import WB_Coverage +from models.housekeeping_model.hk_regs import HK_Registers +from cocotb.queue import Queue +from collections import namedtuple +import logging +from tabulate import tabulate + + +SPI_Operation = namedtuple("SPI_Operation", ["command", "address", "data_in", "data_out"]) + + +class HK_Model(): + def __init__(self, caravelEnv) -> None: + self.caravelEnv = caravelEnv + spi_queue = Queue() + wb_queue = Queue() + HK_Monitor(self.caravelEnv, spi_queue, wb_queue) + hk_regs = HK_Registers(caravelEnv) + SPI_Model(spi_queue, hk_regs) + WB_Model(wb_queue, hk_regs) + + +class AbstractModelHK(): + def __init__(self, queue) -> None: + self._thread = cocotb.scheduler.add(self._model(queue)) + + async def _model(self, queue): + pass + + async def _get_transactions(self, queue): + transaction = await queue.get() + cocotb.log.debug(f"[{__class__.__name__}][_get_transactions] getting transaction {transaction} from monitor") + return transaction + + def configure_logger(self, logger_name="logger", logger_file="log.txt"): + self.spi_logger = logging.getLogger(logger_name) + + # Configure the logger + self.spi_logger.setLevel(logging.INFO) + + # Create a FileHandler to log to a file + file_handler = logging.FileHandler(logger_file) + file_handler.setLevel(logging.INFO) + + # # Create a StreamHandler to log to the console (optional) + # console_handler = logging.StreamHandler() + # console_handler.setLevel(logging.DEBUG) + + # Add the handlers to the logger + self.spi_logger.addHandler(file_handler) + # Create a NullHandler for the console to suppress output + + # self.spi_logger.addHandler(console_handler) # Optional: Log to console + # Remove the console handler to avoid logging to console + + # log the header + self.log_operation(None, header_logged=True) + + def log_operation(self, transaction, header_logged): + pass + + +class WB_Model(AbstractModelHK): + def __init__(self, queue, hk_regs) -> None: + self.configure_logger(logger_name="HK_WB_LOG", logger_file="hk_wb.log") + super().__init__(queue) + self.hk_regs = hk_regs + + async def _model(self, queue): + wb_cov = WB_Coverage() + while True: + transaction = await self._get_transactions(queue) + cocotb.log.debug(f"[{__class__.__name__}][_model] {transaction}") + self.log_operation(transaction) + wb_cov.wb_cov(transaction) + if transaction.write == 1: + self.hk_regs.cov_register_write(transaction.address, interface="wb") + else: + self.hk_regs.cov_register_read(transaction.address, interface="wb") + + def log_operation(self, transaction, header_logged=False): + if header_logged: + # Log the header + header = tabulate([], headers=["Time", "Type", "Address", "Select", "Data"], tablefmt="grid") + self.spi_logger.info(header) + # Mark that the header has been logged + else: + table_data = [( + f"{cocotb.utils.get_sim_time(units='ns')} ns", + "read" if transaction.write == 0 else "write", + hex(transaction.address), + hex(transaction.select), + hex(transaction.write_data) if transaction.write == 1 else hex(transaction.read_data) + )] + table = tabulate(table_data, tablefmt="grid") + self.spi_logger.info(table) + + +class SPI_Model(AbstractModelHK): + def __init__(self, queue, hk_regs) -> None: + self.configure_logger(logger_name="HK_SPI_LOG", logger_file="hk_spi.log") + super().__init__(queue) + self.hk_regs = hk_regs + + async def _model(self, queue): + spi_cov = SPI_Coverage() + bits_counter = -1 + command = address = data_write = data_read = "" + data_in = [] + data_out = [] + while True: + transaction = await self._get_transactions(queue) + bits_counter += 1 + if transaction.cs == 1: + bits_counter = -1 + command = address = data_write = data_read = "" + data_in = [] + data_out = [] + continue + elif bits_counter < 8: + command += str(transaction.sdi) + if bits_counter == 7: + command = spi_cov.command_to_text(command) + elif bits_counter < 16: + address += str(transaction.sdi) + if bits_counter == 15 and "Pass-through" not in command: + address = hex(int(address, 2)) + else: + if "read" in command: + data_read += str(transaction.sdo) + if "write" in command: + data_write += str(transaction.sdi) + if "Pass-through" in command: + if bits_counter < 40: + address += str(transaction.sdi) + if bits_counter == 39: + address = hex(int(address, 2)) + else: + data_read += str(transaction.sdo) + data_write += str(transaction.sdi) + + if (bits_counter - 15) % 8 == 0: # if it's multiple of 8 bits + if "Pass-through" in command and bits_counter < 40: + continue + if data_write != "": + data_in.append(hex(int(data_write, 2))) + if data_read != "": + data_out.append(hex(int(data_read, 2))) + spi_operation = SPI_Operation(command=command, address=address, data_in=data_in, data_out=data_out) + spi_cov.spi_cov(spi_operation) + if "read" in command: + self.hk_regs.cov_register_read(int(address,16)) + if "write" in command: + self.hk_regs.cov_register_write(int(address,16)) + self.log_operation(spi_operation) + cocotb.log.debug(f"[{__class__.__name__}][_housekeeping] {spi_operation} ") + + # Function to log SPI operations + def log_operation(self, transaction, header_logged=False): + if header_logged: + # Log the header + header = tabulate([], headers=["Time", "Command", "Address", "Data In", "Data Out"], tablefmt="grid") + self.spi_logger.info(header) + # Mark that the header has been logged + else: + table_data = [( + f"{cocotb.utils.get_sim_time(units='ns')} ns", + transaction.command, + transaction.address, + transaction.data_in, + transaction.data_out + )] + table = tabulate(table_data, tablefmt="grid") + self.spi_logger.info(table) diff --git a/verilog/dv/cocotb/models/housekeeping_model/hk_monitor.py b/verilog/dv/cocotb/models/housekeeping_model/hk_monitor.py new file mode 100644 index 000000000..257ed94c9 --- /dev/null +++ b/verilog/dv/cocotb/models/housekeeping_model/hk_monitor.py @@ -0,0 +1,63 @@ +import cocotb +from cocotb.triggers import Timer, RisingEdge, ReadOnly, Edge +from collections import namedtuple + +SPI_Transaction = namedtuple("SPI_Transaction", ["cs", "sdi", "sdo"]) +WB_Transaction = namedtuple("WB_Transaction", ["address", "write", "write_data", "read_data", "select"]) + + +class HK_Monitor(): + def __init__(self, Caravel_env, spi_queue, wb_queue): + self.hk_hdl = Caravel_env.hk_hdl + self._spi_fork = cocotb.scheduler.add(self._hk_spi_monitor(spi_queue)) + self._wb_fork = cocotb.scheduler.add(self._wb_monitor(wb_queue)) + + async def _hk_spi_monitor(self, queue): + self._spi_hdls() + while True: + if self.spi_is_enable_hdl.value.integer == 0: + await Edge(self.spi_is_enable_hdl) # wait until spi is enabled + monitor_fork = await cocotb.start(self._spi_monitoring(queue)) + await Edge(self.spi_is_enable_hdl) # wait until spi is disabled + monitor_fork.kill() + + async def _wb_monitor(self, queue): + self._wb_hdls() + while True: + # valid transaction only happened if ack is sent + await RisingEdge(self.wb_ack_hdl) + read_data = int(self.wb_dato_hdl.value.binstr.replace("x", "0"), 2) + transaction = WB_Transaction(address=self.wb_adr_hdl.value.integer, write=self.wb_we_hdl.value.integer, write_data=self.wb_datai_hdl.value.integer, read_data=read_data, select=self.wb_sel_hdl.value.integer) + queue.put_nowait(transaction) + cocotb.log.debug(f"[{__class__.__name__}][_spi_monitoring] sending transaction {transaction} to queuq") + + async def _spi_monitoring(self, queue): + while True: + if self.cs_hdl.value.integer == 1: + transaction = SPI_Transaction(cs=1, sdi=0, sdo=0) + queue.put_nowait(transaction) + cocotb.log.debug(f"[{__class__.__name__}][_spi_monitoring] sending transaction {transaction} to queuq") + await Edge(self.cs_hdl) # wait until cs is low + await RisingEdge(self.clk_hdl) + transaction = SPI_Transaction(cs=self.cs_hdl.value, sdi=self.sdi_hdl.value, sdo=self.sdo_hdl.value) + queue.put_nowait(transaction) + cocotb.log.debug(f"[{__class__.__name__}][_spi_monitoring] sending transaction {transaction} to queuq") + + def _spi_hdls(self): + self.cs_hdl = self.hk_hdl.mgmt_gpio_in[3] + self.clk_hdl = self.hk_hdl.mgmt_gpio_in[4] + self.sdi_hdl = self.hk_hdl.mgmt_gpio_in[2] + self.sdo_hdl = self.hk_hdl.mgmt_gpio_out[1] + self.spi_is_enable_hdl = self.hk_hdl.spi_is_enabled + + def _wb_hdls(self): + self.wb_clk_hdl = self.hk_hdl.wb_clk_i + self.wb_rst_hdl = self.hk_hdl.wb_rstn_i + self.wb_adr_hdl = self.hk_hdl.wb_adr_i + self.wb_datai_hdl = self.hk_hdl.wb_dat_i + self.wb_sel_hdl = self.hk_hdl.wb_sel_i + self.wb_we_hdl = self.hk_hdl.wb_we_i + self.wb_cyc_hdl = self.hk_hdl.wb_cyc_i + self.wb_stb_hdl = self.hk_hdl.wb_stb_i + self.wb_ack_hdl = self.hk_hdl.wb_ack_o + self.wb_dato_hdl = self.hk_hdl.wb_dat_o diff --git a/verilog/dv/cocotb/models/housekeeping_model/hk_regs.py b/verilog/dv/cocotb/models/housekeeping_model/hk_regs.py new file mode 100644 index 000000000..92e1cf506 --- /dev/null +++ b/verilog/dv/cocotb/models/housekeeping_model/hk_regs.py @@ -0,0 +1,95 @@ +import cocotb +import yaml +from cocotb_coverage.coverage import CoverPoint + + +class HK_Registers(): + def __init__(self, caravelEnv) -> None: + self.regs_spi = dict() + self.regs_wb = dict() + self.get_regs() + + def get_regs(self): + file_name = f"{cocotb.plusargs['USER_PROJECT_ROOT']}/verilog/dv/cocotb/models/housekeeping_model/hk_regs.yaml" + file_name = file_name.replace('"', '') + with open(file_name, "r") as file: + regs = yaml.safe_load(file)["registers"] + for reg in regs: + register = HK_Register(reg["name"], reg["spi_address"], reg["wb_addr"], reg["width"], reg["reset"], reg["access_type"], reg["backdoor_hdl"]) + if isinstance(reg["spi_address"], list): + for spi_addr in reg["spi_address"]: + self.regs_spi[int(spi_addr)] = register + else: + self.regs_spi[int(reg["spi_address"])] = register + if isinstance(reg["wb_addr"], list): + for wb_addr in reg["wb_addr"]: + self.regs_wb[int(wb_addr)] = register + else: + self.regs_wb[int(reg["wb_addr"])] = register + + def cov_register_write(self, address, interface="spi"): + if interface == "spi": + if address in self.regs_spi: + self.regs_spi[address].sample_write("write") + elif interface == "wb": + if address in self.regs_wb: + self.regs_wb[address].sample_write("write", interface) + + def cov_register_read(self, address, interface="spi"): + if interface == "spi": + if address in self.regs_spi: + self.regs_spi[address].sample_read("read") + elif interface == "wb": + if address in self.regs_wb: + self.regs_wb[address].sample_read("read", interface) + + +class HK_Register(): + def __init__(self, name, spi_addr, wb_addr, width, reset=0, access_type="rw", backdoor_hdl=None) -> None: + self.name = name + self.spi_addr = spi_addr + self.wb_addr = wb_addr + self.width = width + self.access_type = access_type + self.reset = reset + self.value = reset + self.backdoor_hdl = backdoor_hdl + self.mask = (1 << width) - 1 + cocotb.log.debug(f"[{__class__.__name__}][__init__] Create register {name} at wishbone address {wb_addr}, spi address {spi_addr} with width {width} reset {reset} access_type {access_type}") + # initialize coverage no covearge happened just sample nothing so the coverge is initialized + self.sample_write("null") + self.sample_read("null") + self.sample_write("null", interface="wb") + self.sample_read("null", interface="wb") + + def __str__(self): + return f"Housekeeping register {self.name} at address spi address {self.spi_addr}, wb address {hex(self.wb_addr)} with width {hex(self.width)}, reset {hex(self.reset)}, access_type {self.access_type}, backdoor_hdl {self.backdoor_hdl}" + def write(self, data): + self.value = data & self.mask + cocotb.log.debug(f"[{__class__.__name__}][write] write {self.value} to register {self.name}") + + def read(self): + cocotb.log.debug(f"[{__class__.__name__}][read] read {self.value} from register {self.name}") + return self.value + + def reset(self): + cocotb.log.debug(f"[{__class__.__name__}][reset] reset {self.name}") + self.write(self.reset) + + def sample_write(self, data, interface="spi"): + @CoverPoint( + f"top.caravel.housekeeping.registers.{self.name}.{interface}_write", + bins=["write" if "w" in self.access_type else "null"], + ) + def sample(data): + pass + sample(data) + + def sample_read(self, data, interface="spi"): + @CoverPoint( + f"top.caravel.housekeeping.registers.{self.name}.{interface}_read", + bins=["read" if "r" in self.access_type else "null"], + ) + def sample(data): + pass + sample(data) diff --git a/verilog/dv/cocotb/models/housekeeping_model/hk_regs.yaml b/verilog/dv/cocotb/models/housekeeping_model/hk_regs.yaml new file mode 100644 index 000000000..ac487f6cb --- /dev/null +++ b/verilog/dv/cocotb/models/housekeeping_model/hk_regs.yaml @@ -0,0 +1,458 @@ +registers: +# spi registers + - name: spi_status + spi_address: 0x0 + wb_addr: 0x26100000 + width: 8 + reset: 0 + access_type: ro + backdoor_hdl: null + + - name: Chip_ID + spi_address: [0x1,0x2,0x3] + wb_addr: 0x26100004 + width: 20 + reset: 0x115604 + access_type: ro + backdoor_hdl: null + + - name: User_project_ID + spi_address: [0x4,0x5,0x6,0x7] + wb_addr: 0x26100008 + width: 8 + reset: 0x0 + access_type: ro + backdoor_hdl: null + + - name: PLL_enable + spi_address: 0x8 + wb_addr: 0x2610000c + width: 2 + reset: 0x2 + access_type: rw + backdoor_hdl: null + + - name: PLL_bypass + spi_address: 0x9 + wb_addr: 0x26100010 + width: 1 + reset: 0x1 + access_type: rw + backdoor_hdl: null + + - name: CPU_IRQ + spi_address: 0xa + wb_addr: 0x26100014 + width: 1 + reset: 0x0 + access_type: NA + backdoor_hdl: null + + - name: CPU_reset + spi_address: 0xb + wb_addr: 0x26100018 + width: 1 + reset: 0x0 + access_type: rw + backdoor_hdl: null + + - name: CPU_trap + spi_address: 0xc + wb_addr: 0x26100028 + width: 1 + reset: 0x0 + access_type: ro + backdoor_hdl: null + + - name: DCO_trim + spi_address: [0xd,0xe,0xf,0x10] + wb_addr: 0x2610001c + width: 26 + reset: 0x3FFEFFF + access_type: rw + backdoor_hdl: null + + - name: PLL_divider + spi_address: 0x11 + wb_addr: 0x26100020 + width: 6 + reset: 0x12 + access_type: rw + backdoor_hdl: null + + - name: PLL_feedback + spi_address: 0x12 + wb_addr: 0x26100024 + width: 5 + reset: 0x4 + access_type: rw + backdoor_hdl: null +# gpio registers + - name: xfer_bitbang_control + spi_address: 0x13 + wb_addr: 0x26000000 + width: 8 + reset: 0x0 + access_type: NA + backdoor_hdl: null + + - name: power_control + spi_address: 0x6e + wb_addr: 0x26000004 + width: 4 + reset: 0x0 + access_type: rw + backdoor_hdl: null + + - name: GPIO_data_low + spi_address: [0x6a, 0x6b, 0x6c, 0x6d] + wb_addr: 0x2600000c + width: 32 + reset: 0x0 + access_type: NA + backdoor_hdl: null + + - name: GPIO_data_high + spi_address: [0x69] + wb_addr: 0x26000010 + width: 6 + reset: 0x0 + access_type: NA + backdoor_hdl: null + + - name: gpio_configure_0 + spi_address: [0x1d, 0x1e] + wb_addr: 0x26000024 + width: 1 + reset: 0x318 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_1 + spi_address: [0x1f, 0x20] + wb_addr: 0x26000028 + width: 1 + reset: 0x318 + access_type: rw + backdoor_hdl: null + + - name : gpio_configure_2 + spi_address: [0x21, 0x22] + wb_addr: 0x2600002c + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_3 + spi_address: [0x23, 0x24] + wb_addr: 0x26000030 + width: 1 + reset: 0x108 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_4 + spi_address: [0x25, 0x26] + wb_addr: 0x26000034 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_5 + spi_address: [0x27, 0x28] + wb_addr: 0x26000038 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_6 + spi_address: [0x29, 0x2a] + wb_addr: 0x2600003c + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_7 + spi_address: [0x2b, 0x2c] + wb_addr: 0x26000040 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_8 + spi_address: [0x2d, 0x2e] + wb_addr: 0x26000044 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_9 + spi_address: [0x2f, 0x30] + wb_addr: 0x26000048 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_10 + spi_address: [0x31, 0x32] + wb_addr: 0x2600004c + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_11 + spi_address: [0x33, 0x34] + wb_addr: 0x26000050 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_12 + spi_address: [0x35, 0x36] + wb_addr: 0x26000054 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_13 + spi_address: [0x37, 0x38] + wb_addr: 0x26000058 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_14 + spi_address: [0x39, 0x3a] + wb_addr: 0x2600005c + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_15 + spi_address: [0x3b, 0x3c] + wb_addr: 0x26000060 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_16 + spi_address: [0x3d, 0x3e] + wb_addr: 0x26000064 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_17 + spi_address: [0x3f, 0x40] + wb_addr: 0x26000068 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_18 + spi_address: [0x41, 0x42] + wb_addr: 0x2600006c + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_19 + spi_address: [0x43, 0x44] + wb_addr: 0x26000070 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_20 + spi_address: [0x45, 0x46] + wb_addr: 0x26000074 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_21 + spi_address: [0x47, 0x48] + wb_addr: 0x26000078 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_22 + spi_address: [0x49, 0x4a] + wb_addr: 0x2600007c + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_23 + spi_address: [0x4b, 0x4c] + wb_addr: 0x26000080 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_24 + spi_address: [0x4d, 0x4e] + wb_addr: 0x26000084 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_25 + spi_address: [0x4f, 0x50] + wb_addr: 0x26000088 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_26 + spi_address: [0x51, 0x52] + wb_addr: 0x2600008c + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_27 + spi_address: [0x53, 0x54] + wb_addr: 0x26000090 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_28 + spi_address: [0x55, 0x56] + wb_addr: 0x26000094 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_29 + spi_address: [0x57, 0x58] + wb_addr: 0x26000098 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_30 + spi_address: [0x59, 0x5a] + wb_addr: 0x2600009c + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_31 + spi_address: [0x5b, 0x5c] + wb_addr: 0x260000a0 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_32 + spi_address: [0x5d, 0x5e] + wb_addr: 0x260000a4 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_33 + spi_address: [0x5f, 0x60] + wb_addr: 0x260000a8 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_34 + spi_address: [0x61, 0x62] + wb_addr: 0x260000ac + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_35 + spi_address: [0x63, 0x64] + wb_addr: 0x260000b0 + width: 1 + reset: 0x304 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_36 + spi_address: [0x65, 0x66] + wb_addr: 0x260000b4 + width: 1 + reset: 0x318 + access_type: rw + backdoor_hdl: null + + - name: gpio_configure_37 + spi_address: [0x67, 0x68] + wb_addr: 0x260000b8 + width: 1 + reset: 0x318 + access_type: rw + backdoor_hdl: null + +# system monitoring registers + - name: user_power_good + spi_address: 0x1a + wb_addr: 0x26200000 + width: 4 + reset: 0xF + access_type: ro + backdoor_hdl: null + + - name: trap_clock_redirect + spi_address: 0x1b + wb_addr: 0x26200004 + width: 3 + reset: 0x0 + access_type: rw + backdoor_hdl: null + + - name: irq_redirect + spi_address: 0x1c + wb_addr: 0x2620000C + width: 2 + reset: 0x0 + access_type: rw + backdoor_hdl: null + + - name: housekeeping_disable + spi_address: 0x6f + wb_addr: 0x26200010 + width: 1 + reset: 0x0 + access_type: rw + backdoor_hdl: null diff --git a/verilog/dv/cocotb/models/soc_model/soc_coverage.py b/verilog/dv/cocotb/models/soc_model/soc_coverage.py new file mode 100644 index 000000000..10db02c71 --- /dev/null +++ b/verilog/dv/cocotb/models/soc_model/soc_coverage.py @@ -0,0 +1,155 @@ +from cocotb_coverage.coverage import CoverPoint, CoverCross +from collections import namedtuple +import cocotb + +class UART_Coverage(): + def __init__(self) -> None: + # initialize coverage no covearge happened just sample nothing so the coverge is initialized + self.uart_cov(None, do_sampling=False) + + def uart_cov(self, operation, do_sampling=True): + @CoverPoint( + "top.caravel.soc.uart.type", + xf=lambda operation: operation.type, + bins=["rx", "tx"] + ) + @CoverPoint( + "top.caravel.soc.uart.char", + xf=lambda operation: ord(operation.char), + bins=[(0x0, 0x10), (0x10, 0x20), (0x20, 0x30), (0x30, 0x40), (0x40, 0x50), (0x50, 0x60), (0x60, 0x70), (0x70, 0x80)], + bins_labels=["0 to 0x10", "0x10 to 0x20", "0x20 to 0x30", "0x30 to 0x40", "0x40 to 0x50", "0x50 to 0x60", "0x60 to 0x70", "0x70 to 0x80"], + rel=lambda val, b: b[0] <= val <= b[1] + ) + @CoverCross( + "top.caravel.soc.uart.char_type", + items=[ + "top.caravel.soc.uart.char", + "top.caravel.soc.uart.type", + ], + ) + def sample(operation): + pass + if do_sampling: + sample(operation) + + +class MSPI_Coverage(): + def __init__(self) -> None: + # initialize coverage no covearge happened just sample nothing so the coverge is initialized + self.spi_cov(None, do_sampling=False) + + def spi_cov(self, operation, do_sampling=True): + @CoverPoint( + "top.caravel.soc.master_spi.spi_write_byte", + xf=lambda operation: int(operation.data_write, 2), + bins=[(0, 0x0F), (0x10, 0x1F), (0x20, 0x2F), (0x30, 0x3F), (0x40, 0x4F), (0x50, 0x5F), (0x60, 0x6F), (0x70, 0x7F), (0x80, 0x8F), (0x90, 0x9F), (0xA0, 0xAF), (0xB0, 0xBF), (0xC0, 0xCF), (0xD0, 0xDF), (0xE0, 0xEF), (0xF0, 0xFF)], + bins_labels=["0x0, 0x0F", "0x10, 0x1F", "0x20, 0x2F", "0x30, 0x3F", "0x40, 0x4F", "0x50, 0x5F", "0x60, 0x6F", "0x70, 0x7F", "0x80, 0x8F", "0x90, 0x9F", "0xA0, 0xAF", "0xB0, 0xBF", "0xC0, 0xCF", "0xD0, 0xDF", "0xE0, 0xEF", "0xF0, 0xFF"], + rel=lambda val, b: b[0] <= val <= b[1], + ) + @CoverPoint( + "top.caravel.soc.master_spi.spi_read_byte", + xf=lambda operation: int(operation.data_read, 2), + bins=[(0, 0x0F), (0x10, 0x1F), (0x20, 0x2F), (0x30, 0x3F), (0x40, 0x4F), (0x50, 0x5F), (0x60, 0x6F), (0x70, 0x7F), (0x80, 0x8F), (0x90, 0x9F), (0xA0, 0xAF), (0xB0, 0xBF), (0xC0, 0xCF), (0xD0, 0xDF), (0xE0, 0xEF), (0xF0, 0xFF)], + bins_labels=["0x0, 0x0F", "0x10, 0x1F", "0x20, 0x2F", "0x30, 0x3F", "0x40, 0x4F", "0x50, 0x5F", "0x60, 0x6F", "0x70, 0x7F", "0x80, 0x8F", "0x90, 0x9F", "0xA0, 0xAF", "0xB0, 0xBF", "0xC0, 0xCF", "0xD0, 0xDF", "0xE0, 0xEF", "0xF0, 0xFF"], + rel=lambda val, b: b[0] <= val <= b[1], + ) + def sample(operation): + pass + if do_sampling: + sample(operation) + + +class Debug_Coverage(): + def __init__(self) -> None: + # initialize coverage no covearge happened just sample nothing so the coverge is initialized + self.debug_cov(None, do_sampling=False) + + def debug_cov(self, operation, do_sampling=True): + @CoverPoint( + "top.caravel.soc.debug_if.type", + xf=lambda operation: operation.type, + bins=["rx", "tx"] + ) + @CoverPoint( + "top.caravel.soc.debug_if.values", + xf=lambda operation: int(operation.char, 16), + bins=[(0x0, 0x0F)], + bins_labels=["0x0, 0x0F"], + rel=lambda val, b: b[0] <= val <= b[1], + at_least=5 + ) + def sample(operation): + pass + if do_sampling: + sample(operation) + + +class IRQ_Coverage(): + def __init__(self) -> None: + # initialize coverage no covearge happened just sample nothing so the coverge is initialized + self.irq_cov(None, do_sampling=False) + pass + + def irq_cov(self, data, do_sampling=True): + @CoverPoint( + "top.caravel.soc.irq.timer", + xf=lambda data: data, + bins=[("timer_interrupt", "clear"), ("timer_interrupt", "interrupt")], + rel=lambda data, b: data[0] == b[0] and data[1] == b[1], + bins_labels=["clear", "interrupt"] + ) + @CoverPoint( + "top.caravel.soc.irq.uart", + xf=lambda data: data, + bins=[("uart_interrupt", "clear"), ("uart_interrupt", "interrupt")], + rel=lambda data, b: data[0] == b[0] and data[1] == b[1], + bins_labels=["clear", "interrupt"] + ) + @CoverPoint( + "top.caravel.soc.irq.user0", + xf=lambda data: data, + bins=[("user0_interrupt", "clear"), ("user0_interrupt", "interrupt")], + rel=lambda data, b: data[0] == b[0] and data[1] == b[1], + bins_labels=["clear", "interrupt"] + ) + @CoverPoint( + "top.caravel.soc.irq.user1", + xf=lambda data: data, + bins=[("user1_interrupt", "clear"), ("user1_interrupt", "interrupt")], + rel=lambda data, b: data[0] == b[0] and data[1] == b[1], + bins_labels=["clear", "interrupt"] + ) + @CoverPoint( + "top.caravel.soc.irq.user2", + xf=lambda data: data, + bins=[("user2_interrupt", "clear"), ("user2_interrupt", "interrupt")], + rel=lambda data, b: data[0] == b[0] and data[1] == b[1], + bins_labels=["clear", "interrupt"] + ) + @CoverPoint( + "top.caravel.soc.irq.housekeeping", + xf=lambda data: data, + bins=[("housekeeping_interrupt", "clear"), ("housekeeping_interrupt", "interrupt")], + rel=lambda data, b: data[0] == b[0] and data[1] == b[1], + bins_labels=["clear", "interrupt"] + ) + @CoverPoint( + "top.caravel.soc.irq.external1", + xf=lambda data: data, + bins=[("external1_interrupt", "clear"), ("external1_interrupt", "interrupt")], + rel=lambda data, b: data[0] == b[0] and data[1] == b[1], + bins_labels=["clear", "interrupt"], + ) + @CoverPoint( + "top.caravel.soc.irq.external2", + xf=lambda data: data, + bins=[("external2_interrupt", "clear"), ("external2_interrupt", "interrupt")], + rel=lambda data, b: data[0] == b[0] and data[1] == b[1], + bins_labels=["clear", "interrupt"], + ) + def sample(data): + pass + if do_sampling: + sample(data) + + diff --git a/verilog/dv/cocotb/models/soc_model/soc_model.py b/verilog/dv/cocotb/models/soc_model/soc_model.py new file mode 100644 index 000000000..0667d8f8b --- /dev/null +++ b/verilog/dv/cocotb/models/soc_model/soc_model.py @@ -0,0 +1,211 @@ +import cocotb +from cocotb.queue import Queue +from models.soc_model.soc_monitor import SOC_Monitor +from models.soc_model.soc_coverage import UART_Coverage +from models.soc_model.soc_coverage import MSPI_Coverage +from models.soc_model.soc_coverage import Debug_Coverage +from models.soc_model.soc_coverage import IRQ_Coverage +import logging +from collections import namedtuple +from tabulate import tabulate + +MSPI_Operation = namedtuple("MSPI_Operation", ["data_write", "data_read"]) + +class SOC_Model(): + def __init__(self, caravelEnv) -> None: + self.caravelEnv = caravelEnv + uart_queue = Queue() + mspi_queue = Queue() + debug_queue = Queue() + irq_queue = Queue() + SOC_Monitor(self.caravelEnv, spi_queue=mspi_queue, uart_queue=uart_queue, debug_queue=debug_queue, irq_queue=irq_queue) + UART_Model(uart_queue) + MSPI_Model(mspi_queue) + Debug_Model(debug_queue) + IRQ_Model(irq_queue) + +class AbstractModelSOC(): + def __init__(self, queue) -> None: + self._thread = cocotb.scheduler.add(self._model(queue)) + + async def _model(self, queue): + pass + + async def _get_transactions(self, queue): + transaction = await queue.get() + cocotb.log.debug(f"[{__class__.__name__}][_get_transactions] getting transaction {transaction} from monitor") + return transaction + + def configure_logger(self, logger_name="logger", logger_file="log.txt"): + self.spi_logger = logging.getLogger(logger_name) + + # Configure the logger + self.spi_logger.setLevel(logging.INFO) + + # Create a FileHandler to log to a file + file_handler = logging.FileHandler(logger_file) + file_handler.setLevel(logging.INFO) + + # # Create a StreamHandler to log to the console (optional) + # console_handler = logging.StreamHandler() + # console_handler.setLevel(logging.DEBUG) + + # Add the handlers to the logger + self.spi_logger.addHandler(file_handler) + # Create a NullHandler for the console to suppress output + + # self.spi_logger.addHandler(console_handler) # Optional: Log to console + # Remove the console handler to avoid logging to console + + # log the header + self.log_operation(None, header_logged=True) + + def log_operation(self, transaction, header_logged): + pass + + +class UART_Model(AbstractModelSOC): + def __init__(self, queue) -> None: + self.configure_logger(logger_name="SOC_UART_LOG", logger_file="soc_uart.log") + super().__init__(queue) + + async def _model(self, queue): + uart_cov = UART_Coverage() + while True: + transaction = await self._get_transactions(queue) + self.log_operation(transaction) + uart_cov.uart_cov(transaction) + + def log_operation(self, transaction, header_logged=False): + if header_logged: + # Log the header + header = tabulate([], headers=["Time","Type", "character"], tablefmt="grid") + self.spi_logger.info(header) + # Mark that the header has been logged + else: + table_data = [( + f"{cocotb.utils.get_sim_time(units='ns')} ns", + transaction.type, + transaction.char + )] + table = tabulate(table_data, tablefmt="grid") + self.spi_logger.info(table) + + +class MSPI_Model(AbstractModelSOC): + def __init__(self, queue) -> None: + self.configure_logger(logger_name="SOC_SPI_LOG", logger_file="soc_spi.log") + super().__init__(queue) + + async def _model(self, queue): + spi_cov = MSPI_Coverage() + bits_counter = -1 + data_write = data_read = "" + while True: + transaction = await self._get_transactions(queue) + bits_counter += 1 + if transaction.cs == 1: + bits_counter = -1 + data_write = data_read = "" + continue + else: + data_write += str(transaction.sdo) + data_read += str(transaction.sdi) + if bits_counter == 7: + command = MSPI_Operation(data_write, data_read) + bits_counter = -1 + data_write = data_read = "" + self.log_operation(command) + spi_cov.spi_cov(command) + + def log_operation(self, transaction, header_logged=False): + cocotb.log.debug(f"[{__class__.__name__}][log_operation] {transaction}") + if header_logged: + # Log the header + header = tabulate([], headers=["Time", "data_write", "data_read"], tablefmt="grid") + self.spi_logger.info(header) + # Mark that the header has been logged + else: + table_data = [( + f"{cocotb.utils.get_sim_time(units='ns')} ns", + hex(int(transaction.data_write, 2)), + hex(int(transaction.data_read, 2)) + )] + table = tabulate(table_data, tablefmt="grid") + self.spi_logger.info(table) + + +class Debug_Model(AbstractModelSOC): + def __init__(self, queue) -> None: + self.configure_logger(logger_name="SOC_DEBUG_IF_LOG", logger_file="soc_debug_if.log") + super().__init__(queue) + + async def _model(self, queue): + debug_cov = Debug_Coverage() + while True: + transaction = await self._get_transactions(queue) + self.log_operation(transaction) + debug_cov.debug_cov(transaction) + + def log_operation(self, transaction, header_logged=False): + if header_logged: + # Log the header + header = tabulate([], headers=["Time","Type", "character"], tablefmt="grid") + self.spi_logger.info(header) + # Mark that the header has been logged + else: + table_data = [( + f"{cocotb.utils.get_sim_time(units='ns')} ns", + transaction.type, + transaction.char + )] + table = tabulate(table_data, tablefmt="grid") + self.spi_logger.info(table) + + +class IRQ_Model(AbstractModelSOC): + def __init__(self, queue) -> None: + self.configure_logger(logger_name="SOC_IRQ_LOG", logger_file="soc_irqs.log") + super().__init__(queue) + + async def _model(self, queue): + irq_cov = IRQ_Coverage() + while True: + transaction = await self._get_transactions(queue) + interrupts = [] + for interrupt in transaction: + if interrupt[0] == 0: + interrupts.append(("timer_interrupt", interrupt[1])) + elif interrupt[0] == 1: + interrupts.append(("uart_interrupt", interrupt[1])) + elif interrupt[0] == 2: + interrupts.append(("user0_interrupt", interrupt[1])) + elif interrupt[0] == 3: + interrupts.append(("user1_interrupt", interrupt[1])) + elif interrupt[0] == 4: + interrupts.append(("user2_interrupt", interrupt[1])) + elif interrupt[0] == 5: + interrupts.append(("housekeeping_interrupt", interrupt[1])) + elif interrupt[0] == 6: + interrupts.append(("external1_interrupt", interrupt[1])) + elif interrupt[0] == 7: + interrupts.append(("external2_interrupt", interrupt[1])) + for interrupt in interrupts: + self.log_operation(interrupt) + irq_cov.irq_cov(interrupt) + + def log_operation(self, transaction, header_logged=False): + if header_logged: + # Log the header + header = tabulate([], headers=["Time","interface", "type"], tablefmt="grid") + self.spi_logger.info(header) + # Mark that the header has been logged + else: + table_data = [( + f"{cocotb.utils.get_sim_time(units='ns')} ns", + transaction[0], + transaction[1] + )] + table = tabulate(table_data, tablefmt="grid") + self.spi_logger.info(table) + diff --git a/verilog/dv/cocotb/models/soc_model/soc_monitor.py b/verilog/dv/cocotb/models/soc_model/soc_monitor.py new file mode 100644 index 000000000..4a07ee814 --- /dev/null +++ b/verilog/dv/cocotb/models/soc_model/soc_monitor.py @@ -0,0 +1,116 @@ +import cocotb +from cocotb.triggers import RisingEdge, Edge, FallingEdge, ClockCycles, NextTimeStep +from collections import namedtuple + +UART_Transaction = namedtuple("UART_Transaction", ["type", "char"]) +SPI_Transaction = namedtuple("SPI_Transaction", ["cs", "sdi", "sdo"]) + + +class SOC_Monitor(): + def __init__(self, Caravel_env, spi_queue, uart_queue, debug_queue, irq_queue): + self.clk = Caravel_env.clk + self.soc_hdl = Caravel_env.caravel_hdl.soc + self._uart_fork = cocotb.scheduler.add(self._soc_uart_monitor(uart_queue, 9600)) + self._spi_fork = cocotb.scheduler.add(self._soc_spi_monitoring(spi_queue)) + self._debug_fork = cocotb.scheduler.add(self._soc_debug_monitor(debug_queue, 115200)) + self._irq_fork = cocotb.scheduler.add(self._soc_irq_monitor(irq_queue)) + + async def _soc_spi_monitoring(self, queue): + self._spi_hdls() + while True: + if self.cs_hdl.value.integer == 1: + transaction = SPI_Transaction(cs=1, sdi=0, sdo=0) + queue.put_nowait(transaction) + cocotb.log.debug(f"[{__class__.__name__}][_soc_spi_monitoring] sending transaction {transaction} to queuq") + await Edge(self.cs_hdl) # wait until cs is low + await RisingEdge(self.clk_hdl) + transaction = SPI_Transaction(cs=self.cs_hdl.value, sdi=self.sdi_hdl.value.binstr if self.sdi_hdl.value.binstr != "x" else "0", sdo=self.sdo_hdl.value) + queue.put_nowait(transaction) + cocotb.log.debug(f"[{__class__.__name__}][_soc_spi_monitoring] sending transaction {transaction} to queuq") + + async def _soc_uart_monitor(self, queue, baudrate): + self._uart_hdls() + bit_cycles = round(1.01 * 10**7 / (baudrate)) + cocotb.log.debug(f"[{__class__.__name__}][_soc_uart_monitor] bit_cycles: {bit_cycles}") + while True: + if self.wb_uart_en_hdl.value.integer == 0: + await Edge(self.wb_uart_en_hdl) # wait until uart is enabled + rx_fork = await cocotb.start(self._soc_uart_rx_monitor(queue, bit_cycles)) + tx_fork = await cocotb.start(self._soc_uart_tx_monitor(queue, bit_cycles)) + await Edge(self.wb_uart_en_hdl) # wait until uart is disabled + rx_fork.kill() + tx_fork.kill() + + async def _soc_debug_monitor(self, queue, baudrate): + self._debug_hdls() + bit_cycles = round(1.01 * 10**7 / (baudrate)) + cocotb.log.debug(f"[{__class__.__name__}][_soc_debug_monitor] bit_cycles: {bit_cycles}") + while True: + if self.wb_debug_mode_hdl.value.integer == 0: + await Edge(self.wb_debug_mode_hdl) # wait until uart is enabled + rx_fork = await cocotb.start(self._soc_uart_rx_monitor(queue, bit_cycles, not_ascii=True)) + tx_fork = await cocotb.start(self._soc_uart_tx_monitor(queue, bit_cycles, not_ascii=True)) + await Edge(self.wb_debug_mode_hdl) # wait until uart is disabled + rx_fork.kill() + tx_fork.kill() + + async def _soc_uart_rx_monitor(self, queue, bit_cycles, not_ascii=False): + while True: + char = "" + await FallingEdge(self.wb_uart_rx_hdl) # start of char + await ClockCycles(self.clk, bit_cycles+1) + await NextTimeStep() + for i in range(8): + char = self.wb_uart_rx_hdl.value.binstr + char + await ClockCycles(self.clk, bit_cycles+1) + await NextTimeStep() + transaction = UART_Transaction( + type="rx", char=chr(int(char, 2)) if not not_ascii else hex(int(char, 2))) + queue.put_nowait(transaction) + cocotb.log.debug(f"[{__class__.__name__}][_soc_uart_rx_monitor] sending transaction {transaction} to queue") + + async def _soc_uart_tx_monitor(self, queue, bit_cycles, not_ascii=False): + while True: + char = "" + await FallingEdge(self.wb_uart_tx_hdl) + await ClockCycles(self.clk, bit_cycles) + for i in range(8): + char = self.wb_uart_tx_hdl.value.binstr + char + await ClockCycles(self.clk, bit_cycles) + transaction = UART_Transaction( + type="tx", char=chr(int(char, 2)) if not not_ascii else hex(int(char, 2))) + queue.put_nowait(transaction) + cocotb.log.debug(f"[{__class__.__name__}][_soc_uart_tx_monitor] sending transaction {transaction} to queue") + + async def _soc_irq_monitor(self, queue): + self._irq_hdls() + irq_arr_old = "00000000000000000000000000000000" + transaction = [] # list of changed bits + while True: + await Edge(self.irq_arr_hdl) + irq_arr = self.irq_arr_hdl.value.binstr[::-1] + for i in range(32): + if irq_arr[i] != irq_arr_old[i]: + transaction.append((i, "interrupt" if irq_arr[i] == "1" else "clear")) + irq_arr_old = irq_arr + queue.put_nowait(transaction) + cocotb.log.debug(f"[{__class__.__name__}][_soc_irq_monitor] sending transaction {transaction} to queue ") + + def _uart_hdls(self): + self.wb_uart_en_hdl = self.soc_hdl.uart_enabled + self.wb_uart_rx_hdl = self.soc_hdl.ser_rx + self.wb_uart_tx_hdl = self.soc_hdl.ser_tx + + def _debug_hdls(self): + self._uart_hdls() + self.wb_debug_mode_hdl = self.soc_hdl.debug_mode + + def _spi_hdls(self): + self.cs_hdl = self.soc_hdl.spi_csb + self.clk_hdl = self.soc_hdl.spi_sck + self.sdi_hdl = self.soc_hdl.spi_sdi + self.sdo_hdl = self.soc_hdl.spi_sdo + self.sdo_enb_hdl = self.soc_hdl.spi_sdoenb + + def _irq_hdls(self): + self.irq_arr_hdl = self.soc_hdl.core.VexRiscv.externalInterruptArray diff --git a/verilog/dv/cocotb/models/user_project_model/user_coverage.py b/verilog/dv/cocotb/models/user_project_model/user_coverage.py new file mode 100644 index 000000000..33b51a3ac --- /dev/null +++ b/verilog/dv/cocotb/models/user_project_model/user_coverage.py @@ -0,0 +1,80 @@ +from cocotb_coverage.coverage import CoverPoint, CoverCross + + +class WB_Coverage(): + def __init__(self) -> None: + # initialize coverage no covearge happened just sample nothing so the coverge is initialized + self.wb_cov(None, do_sampling=False) + + def wb_cov(self, wb_operation, do_sampling=True): + @CoverPoint( + "top.caravel.user.wishbone.access_type", + xf=lambda wb_operation: wb_operation.write, + bins=[0, 1], + bins_labels=["read", "write"], + weight=1 + ) + @CoverPoint( + "top.caravel.user.wishbone.address", + xf=lambda wb_operation: wb_operation.address, + bins=[(0x30000000, 0x30020000), (0x30020001, 0x30040000), (0x30040001, 0x30060000), (0x30060001, 0x30080000), (0x30080001, 0x300A0000), (0x300A0001, 0x300C0000), (0x300C0001, 0x300E0000), (0x300E0001, 0x30100000)], + bins_labels=["0x30000000 to 0x30020000", "0x30020001 to 0x30040000", "0x30040001 to 0x30060000", "0x30060001 to 0x30080000", "0x30080001 to 0x300A0000", "0x300A0001 to 0x300C0000", "0x300C0001 to 0x300E0000", "0x300E0001 to 0x30100000"], + rel=lambda val, b: b[0] <= val <= b[1], + weight=1 + ) + @CoverPoint( + "top.caravel.user.wishbone.write_data", + xf=lambda wb_operation: wb_operation.write_data, + bins=[(0x00000000, 0x1FFFFFFF), (0x20000000, 0x3FFFFFFF), (0x40000000, 0x5FFFFFFF), (0x60000000, 0x7FFFFFFF), (0x80000000, 0x9FFFFFFF), (0xA0000000, 0xBFFFFFFF), (0xC0000000, 0xDFFFFFFF), (0xE0000000, 0xFFFFFFFF)], + bins_labels=["0 to 0x1FFFFFFF", "0x20000000 to 0x3FFFFFFF", "0x40000000 to 0x5FFFFFFF", "0x60000000 to 0x7FFFFFFF", "0x80000000 to 0x9FFFFFFF", "0xA0000000 to 0xBFFFFFFF", "0xC0000000 to 0xDFFFFFFF", "0xE0000000 to 0xFFFFFFFF"], + rel=lambda val, b: b[0] <= val <= b[1], + ) + @CoverPoint( + "top.caravel.user.wishbone.read_data", + xf=lambda wb_operation: wb_operation.read_data, + bins=[(0x00000000, 0x1FFFFFFF), (0x20000000, 0x3FFFFFFF), (0x40000000, 0x5FFFFFFF), (0x60000000, 0x7FFFFFFF), (0x80000000, 0x9FFFFFFF), (0xA0000000, 0xBFFFFFFF), (0xC0000000, 0xDFFFFFFF), (0xE0000000, 0xFFFFFFFF)], + bins_labels=["0 to 0x1FFFFFFF", "0x20000000 to 0x3FFFFFFF", "0x40000000 to 0x5FFFFFFF", "0x60000000 to 0x7FFFFFFF", "0x80000000 to 0x9FFFFFFF", "0xA0000000 to 0xBFFFFFFF", "0xC0000000 to 0xDFFFFFFF", "0xE0000000 to 0xFFFFFFFF"], + rel=lambda val, b: b[0] <= val <= b[1], + ) + def sample(wb_operation): + pass + if do_sampling: + sample(wb_operation) + +class LA_Coverage(): + def __init__(self, la_number) -> None: + # initialize coverage no covearge happened just sample nothing so the coverge is initialized + self.la_number = la_number + self.bits_cov = dict() + for i in range(la_number): + self.bits_cov[i] = LA_Bit_Coverage(i) + + def la_cov(self, operation, do_sampling=True): + self.bits_cov[operation[0]].la_cov(operation, do_sampling) + + +class LA_Bit_Coverage(): + def __init__(self, bit) -> None: + # initialize coverage no covearge happened just sample nothing so the coverge is initialized + self.bit = bit + self.la_cov(None, do_sampling=False) + + def la_cov(self, operation, do_sampling=True): + @CoverPoint( + f"top.caravel.user.logic_analyser.bit{self.bit}.in", + xf=lambda operation: operation, + bins=[(1, "in"), (0, "in")], + bins_labels=["0 to 1", "1 to 0"], + rel=lambda val, b: val[1] == b[0] and val[2] == b[1] + ) + @CoverPoint( + f"top.caravel.user.logic_analyser.bit{self.bit}.out", + xf=lambda operation: operation, + bins=[(1, "out"), (0, "out")], + bins_labels=["0 to 1", "1 to 0"], + rel=lambda val, b: val[1] == b[0] and val[2] == b[1] + ) + def sample(operation): + pass + if do_sampling: + sample(operation) diff --git a/verilog/dv/cocotb/models/user_project_model/user_model.py b/verilog/dv/cocotb/models/user_project_model/user_model.py new file mode 100644 index 000000000..023b377d4 --- /dev/null +++ b/verilog/dv/cocotb/models/user_project_model/user_model.py @@ -0,0 +1,120 @@ +from cocotb.queue import Queue +import cocotb +import logging +from tabulate import tabulate +from models.user_project_model.user_coverage import WB_Coverage +from models.user_project_model.user_coverage import LA_Coverage +from models.user_project_model.user_monitor import UserMonitor + + +class UserModel(): + def __init__(self, caravelEnv) -> None: + self.caravelEnv = caravelEnv + wb_queue = Queue() + la_queue = Queue() + la_number = 128 + UserMonitor(self.caravelEnv, wb_queue=wb_queue, la_queue=la_queue, la_number=la_number) + WB_Model(wb_queue) + LA_Model(la_queue, la_number=la_number) + + +class AbstractModelUser(): + def __init__(self, queue) -> None: + self._thread = cocotb.scheduler.add(self._model(queue)) + + async def _model(self, queue): + pass + + async def _get_transactions(self, queue): + transaction = await queue.get() + cocotb.log.debug(f"[{__class__.__name__}][_get_transactions] getting transaction {transaction} from monitor") + return transaction + + def configure_logger(self, logger_name="logger", logger_file="log.txt"): + self.spi_logger = logging.getLogger(logger_name) + + # Configure the logger + self.spi_logger.setLevel(logging.INFO) + + # Create a FileHandler to log to a file + file_handler = logging.FileHandler(logger_file) + file_handler.setLevel(logging.INFO) + + # # Create a StreamHandler to log to the console (optional) + # console_handler = logging.StreamHandler() + # console_handler.setLevel(logging.DEBUG) + + # Add the handlers to the logger + self.spi_logger.addHandler(file_handler) + # Create a NullHandler for the console to suppress output + + # self.spi_logger.addHandler(console_handler) # Optional: Log to console + # Remove the console handler to avoid logging to console + + # log the header + self.log_operation(None, header_logged=True) + + def log_operation(self, transaction, header_logged): + pass + + +class WB_Model(AbstractModelUser): + def __init__(self, queue) -> None: + self.configure_logger(logger_name="User_WB_LOG", logger_file="user_wb.log") + super().__init__(queue) + + async def _model(self, queue): + wb_cov = WB_Coverage() + while True: + transaction = await self._get_transactions(queue) + cocotb.log.debug(f"[{__class__.__name__}][_model] {transaction}") + self.log_operation(transaction) + wb_cov.wb_cov(transaction) + + def log_operation(self, transaction, header_logged=False): + if header_logged: + # Log the header + header = tabulate([], headers=["Time", "Type", "Address", "Select", "Data"], tablefmt="grid") + self.spi_logger.info(header) + # Mark that the header has been logged + else: + table_data = [( + f"{cocotb.utils.get_sim_time(units='ns')} ns", + "read" if transaction.write == 0 else "write", + hex(transaction.address), + hex(transaction.select), + hex(transaction.write_data) if transaction.write == 1 else hex(transaction.read_data) + )] + table = tabulate(table_data, tablefmt="grid") + self.spi_logger.info(table) + + +class LA_Model(AbstractModelUser): + def __init__(self, queue, la_number=128) -> None: + self.configure_logger(logger_name="User_LA_LOG", logger_file="user_la.log") + self.la_number = la_number + super().__init__(queue) + + async def _model(self, queue): + la_cov = LA_Coverage(self.la_number) + while True: + transaction = await self._get_transactions(queue) + cocotb.log.debug(f"[{__class__.__name__}][_model] {transaction}") + self.log_operation(transaction) + la_cov.la_cov(transaction) + + def log_operation(self, transaction, header_logged=False): + if header_logged: + # Log the header + header = tabulate([], headers=["Time", "direction", "la_bit", "changed to"], tablefmt="grid") + self.spi_logger.info(header) + # Mark that the header has been logged + else: + table_data = [( + f"{cocotb.utils.get_sim_time(units='ns')} ns", + transaction[2], + transaction[0], + transaction[1] + )] + table = tabulate(table_data, tablefmt="grid") + self.spi_logger.info(table) diff --git a/verilog/dv/cocotb/models/user_project_model/user_monitor.py b/verilog/dv/cocotb/models/user_project_model/user_monitor.py new file mode 100644 index 000000000..75950a6a4 --- /dev/null +++ b/verilog/dv/cocotb/models/user_project_model/user_monitor.py @@ -0,0 +1,73 @@ +import cocotb +from cocotb.triggers import Timer, RisingEdge, NextTimeStep, Edge, First +from collections import namedtuple +WB_Transaction = namedtuple("WB_Transaction", ["address", "write", "write_data", "read_data", "select"]) + + +class UserMonitor(): + def __init__(self, Caravel_env, wb_queue, la_queue, la_number=128): + self.user_hdl = Caravel_env.user_hdl + self._wb_fork = cocotb.scheduler.add(self._wb_monitor(wb_queue)) + self._la_fork = cocotb.scheduler.add(self._la_monitor(la_queue, la_number)) + + async def _wb_monitor(self, queue): + self._wb_hdls() + while True: + # valid transaction only happened if ack is sent + await RisingEdge(self.wb_ack_hdl) + await NextTimeStep() + read_data = 0 if self.wb_we_hdl.value.integer == 1 else self.wb_dato_hdl.value.integer + transaction = WB_Transaction(address=self.wb_adr_hdl.value.integer, write=self.wb_we_hdl.value.integer, write_data=self.wb_datai_hdl.value.integer, read_data=read_data, select=self.wb_sel_hdl.value.integer) + queue.put_nowait(transaction) + cocotb.log.debug(f"[{__class__.__name__}][_wb_monitor] sending transaction {transaction} to queue") + + async def _la_monitor(self, queue, la_number=128): + self._la_hdls() + for i in range(la_number): + await cocotb.start(self._la_in_bit_monitor(i, queue, la_number)) + await cocotb.start(self._la_out_bit_monitor(i, queue, la_number)) + + async def _la_in_bit_monitor(self, bit, queue, la_number=128): + old_data = self.la_in.value[bit].integer + la_in_edge = Edge(self.la_in) + la_oenb_edge = Edge(self.la_oenb) + while True: + await First(la_in_edge, la_oenb_edge) + await NextTimeStep() + if self.la_oenb.value[bit].integer == 0: + if old_data != self.la_in.value[bit].integer: + transaction = (la_number-bit-1, self.la_in.value[bit], "in") + cocotb.log.debug(f"[{__class__.__name__}][_la_in_bit_monitor] sending transaction {transaction} to queue") + queue.put_nowait(transaction) + old_data = self.la_in.value[bit].integer + + async def _la_out_bit_monitor(self, bit, queue, la_number=128): + old_data = self.la_out.value[bit].integer + la_in_edge = Edge(self.la_in) + la_oenb_edge = Edge(self.la_oenb) + while True: + await First(la_in_edge, la_oenb_edge) + await NextTimeStep() + if self.la_oenb.value[bit].integer == 1: + if old_data != self.la_out.value[bit].integer: + transaction = (la_number-bit-1, self.la_out.value[bit], "out") + cocotb.log.debug(f"[{__class__.__name__}][_la_out_bit_monitor] sending transaction {transaction} to queue") + queue.put_nowait(transaction) + old_data = self.la_out.value[bit].integer + + def _wb_hdls(self): + self.wb_clk_hdl = self.user_hdl.wb_clk_i + self.wb_rst_hdl = self.user_hdl.wb_rst_i + self.wb_adr_hdl = self.user_hdl.wbs_adr_i + self.wb_datai_hdl = self.user_hdl.wbs_dat_i + self.wb_sel_hdl = self.user_hdl.wbs_sel_i + self.wb_we_hdl = self.user_hdl.wbs_we_i + self.wb_cyc_hdl = self.user_hdl.wbs_cyc_i + self.wb_stb_hdl = self.user_hdl.wbs_stb_i + self.wb_ack_hdl = self.user_hdl.wbs_ack_o + self.wb_dato_hdl = self.user_hdl.wbs_dat_o + + def _la_hdls(self): + self.la_in = self.user_hdl.la_data_in + self.la_oenb = self.user_hdl.la_oenb + self.la_out = self.user_hdl.la_data_out diff --git a/verilog/dv/cocotb/regression/all_gl_sky130.yaml b/verilog/dv/cocotb/regression/all_gl_sky130.yaml new file mode 100644 index 000000000..ef3cac863 --- /dev/null +++ b/verilog/dv/cocotb/regression/all_gl_sky130.yaml @@ -0,0 +1,65 @@ +--- +# Regression with all tests run in GL mode + +Tests: + - {name: gpio_all_i, sim: GL} + - {name: uart_rx, sim: GL} + - {name: hk_regs_rst_spi, sim: GL} + - {name: gpio_all_i_user, sim: GL} + - {name: gpio_all_i_pu, sim: GL} + - {name: gpio_all_i_pu_user, sim: GL} + - {name: gpio_all_i_pd, sim: GL} + - {name: gpio_all_i_pd_user, sim: GL} + - {name: gpio_all_bidir_user, sim: GL} + - {name: gpio_all_o, sim: GL} + - {name: gpio_all_o_user, sim: GL} + - {name: hk_regs_wr_wb_cpu, sim: GL} + - {name: IRQ_timer, sim: GL} + - {name: bitbang_cpu_all_i, sim: GL} + - {name: bitbang_spi_o, sim: GL} + - {name: mgmt_gpio_out, sim: GL} + - {name: bitbang_spi_i, sim: GL} + - {name: IRQ_external, sim: GL} + - {name: IRQ_uart, sim: GL} + - {name: mgmt_gpio_in, sim: GL} + - {name: timer0_oneshot, sim: GL} + - {name: uart_loopback, sim: GL} + - {name: timer0_periodic, sim: GL} + - {name: uart_tx, sim: GL} + - {name: debug, sim: GL} + - {name: spi_master_rd, sim: GL} + - {name: user_pass_thru_rd, sim: GL} + - {name: mgmt_gpio_bidir, sim: GL} + - {name: la, sim: GL} + # - {name: pll, sim: GL} + - {name: spi_master_temp, sim: GL} + - {name: bitbang_cpu_all_o, sim: GL} + - {name: mem_dff_W, sim: GL} + - {name: serial_shifting_01, sim: GL} + - {name: mem_dff2_W, sim: GL} + - {name: serial_shifting_10, sim: GL} + - {name: serial_shifting_1100, sim: GL} + - {name: serial_shifting_0011, sim: GL} + - {name: cpu_stress, sim: GL} + - {name: spi_rd_wr_nbyte, sim: GL} + - {name: cpu_reset, sim: GL} + - {name: user_address_space, sim: GL} + - {name: mem_dff2_HW, sim: GL} + - {name: mem_dff_HW, sim: GL} + - {name: mem_dff2_B, sim: GL} + - {name: mem_dff_B, sim: GL} + - {name: mgmt_gpio_disable, sim: GL} + - {name: user_pass_thru_connection, sim: GL} + - {name: spi_rd_wr, sim: GL} + - {name: PoR, sim: GL} + - {name: IRQ_spi, sim: GL} + - {name: IRQ_external2, sim: GL} + - {name: IRQ_uart_rx, sim: GL} + - {name: uart_rx_msg, sim: GL} + - {name: user0_irq, sim: GL} + - {name: user1_irq, sim: GL} + - {name: user2_irq, sim: GL} + - {name: mgmt_pass_thru_rd, sim: GL} + + + diff --git a/verilog/dv/cocotb/regression/all_gl_sky130_caravan.yaml b/verilog/dv/cocotb/regression/all_gl_sky130_caravan.yaml new file mode 100644 index 000000000..132ecd070 --- /dev/null +++ b/verilog/dv/cocotb/regression/all_gl_sky130_caravan.yaml @@ -0,0 +1,52 @@ +--- +# Regression with all tests run in GL mode + +Tests: + - {name: gpio_all_i_caravan, sim: GL} + - {name: uart_rx, sim: GL} + - {name: hk_regs_rst_spi, sim: GL} + - {name: gpio_all_i_pu_caravan, sim: GL} + - {name: gpio_all_i_pd_caravan, sim: GL} + - {name: gpio_all_o_caravan, sim: GL} + - {name: IRQ_timer, sim: GL} + - {name: mgmt_gpio_out, sim: GL} + - {name: hk_regs_wr_spi, sim: GL} + - {name: IRQ_external, sim: GL} + - {name: IRQ_uart, sim: GL} + - {name: mgmt_gpio_in, sim: GL} + - {name: timer0_oneshot, sim: GL} + - {name: uart_loopback, sim: GL} + - {name: timer0_periodic, sim: GL} + - {name: uart_tx, sim: GL} + - {name: debug, sim: GL} + - {name: spi_master_rd, sim: GL} + - {name: user_pass_thru_rd, sim: GL} + - {name: mgmt_gpio_bidir, sim: GL} + - {name: mem_dff_W, sim: GL} + - {name: serial_shifting_01, sim: GL} + - {name: mem_dff2_W, sim: GL} + - {name: serial_shifting_10, sim: GL} + - {name: serial_shifting_1100, sim: GL} + - {name: serial_shifting_0011, sim: GL} + - {name: cpu_stress, sim: GL} + - {name: spi_rd_wr_nbyte, sim: GL} + - {name: cpu_reset, sim: GL} + - {name: mem_dff2_HW, sim: GL} + - {name: mem_dff_HW, sim: GL} + - {name: mem_dff2_B, sim: GL} + - {name: mem_dff_B, sim: GL} + - {name: mgmt_gpio_disable, sim: GL} + - {name: user_pass_thru_connection, sim: GL} + - {name: spi_rd_wr, sim: GL} + - {name: PoR, sim: GL} + - {name: IRQ_spi, sim: GL} + - {name: IRQ_external2, sim: GL} + - {name: IRQ_uart_rx, sim: GL} + - {name: user0_irq, sim: GL} + - {name: user1_irq, sim: GL} + - {name: user2_irq, sim: GL} + - {name: mgmt_pass_thru_rd, sim: GL} + + + + diff --git a/verilog/dv/cocotb/regression/all_rtl.yaml b/verilog/dv/cocotb/regression/all_rtl.yaml new file mode 100644 index 000000000..4d6c401ae --- /dev/null +++ b/verilog/dv/cocotb/regression/all_rtl.yaml @@ -0,0 +1,74 @@ +--- +# Regression with all tests run in RTL mode + +Tests: + - {name: gpio_all_i, sim: RTL} + - {name: hk_disable, sim: RTL} + - {name: uart_rx, sim: RTL} + - {name: hk_regs_rst_spi, sim: RTL} + - {name: gpio_all_i_user, sim: RTL} + - {name: gpio_all_i_pu, sim: RTL} + - {name: gpio_all_i_pu_user, sim: RTL} + - {name: gpio_all_i_pd, sim: RTL} + - {name: gpio_all_i_pd_user, sim: RTL} + - {name: gpio_all_bidir_user, sim: RTL} + - {name: gpio_all_o, sim: RTL} + - {name: gpio_all_o_user, sim: RTL} + - {name: hk_regs_wr_wb_cpu, sim: RTL} + - {name: IRQ_timer, sim: RTL} + - {name: bitbang_cpu_all_i, sim: RTL} + - {name: bitbang_spi_o, sim: RTL} + - {name: mgmt_gpio_out, sim: RTL} + - {name: bitbang_spi_i, sim: RTL} + - {name: hk_regs_wr_spi, sim: RTL} + - {name: IRQ_external, sim: RTL} + - {name: IRQ_uart, sim: RTL} + - {name: mgmt_gpio_in, sim: RTL} + - {name: timer0_oneshot, sim: RTL} + - {name: uart_loopback, sim: RTL} + - {name: timer0_periodic, sim: RTL} + - {name: uart_tx, sim: RTL} + - {name: debug, sim: RTL} + - {name: debug_swd, sim: RTL} + - {name: spi_master_rd, sim: RTL} + - {name: user_pass_thru_rd, sim: RTL} + - {name: clock_redirect, sim: RTL} + - {name: mgmt_gpio_bidir, sim: RTL} + - {name: la, sim: RTL} + # - {name: pll, sim: RTL} + - {name: spi_master_temp, sim: RTL} + - {name: bitbang_cpu_all_o, sim: RTL} + - {name: mem_dff_W, sim: RTL} + - {name: serial_shifting_01, sim: RTL} + - {name: mem_dff2_W, sim: RTL} + - {name: serial_shifting_10, sim: RTL} + - {name: serial_shifting_1100, sim: RTL} + - {name: serial_shifting_0011, sim: RTL} + - {name: cpu_stress, sim: RTL} + - {name: spi_rd_wr_nbyte, sim: RTL} + - {name: cpu_reset, sim: RTL} + - {name: user_address_space, sim: RTL} + - {name: mem_dff2_HW, sim: RTL} + - {name: mem_dff_HW, sim: RTL} + - {name: mem_dff2_B, sim: RTL} + - {name: mem_dff_B, sim: RTL} + # - {name: mem_sram_smoke, sim: RTL} # gf180 only + # - {name: mem_sram_W, sim: RTL} # gf180 only + # - {name: mem_sram_HW, sim: RTL} # gf180 only + # - {name: mem_sram_B, sim: RTL} # gf180 only + - {name: mgmt_gpio_pu_pd, sim: RTL} + - {name: mgmt_gpio_disable, sim: RTL} + - {name: user_pass_thru_connection, sim: RTL} + - {name: spi_rd_wr, sim: RTL} + - {name: PoR, sim: RTL} + - {name: IRQ_spi, sim: RTL} + - {name: IRQ_external2, sim: RTL} + - {name: IRQ_uart_rx, sim: RTL} + - {name: uart_rx_msg, sim: RTL} + - {name: user0_irq, sim: RTL} + - {name: user1_irq, sim: RTL} + - {name: user2_irq, sim: RTL} + - {name: mgmt_pass_thru_rd, sim: RTL} + + + diff --git a/verilog/dv/cocotb/regression/all_rtl_sky130.yaml b/verilog/dv/cocotb/regression/all_rtl_sky130.yaml new file mode 100644 index 000000000..229b697f9 --- /dev/null +++ b/verilog/dv/cocotb/regression/all_rtl_sky130.yaml @@ -0,0 +1,68 @@ +--- +# Regression with all tests run in RTL mode + +Tests: + - {name: gpio_all_i, sim: RTL} + - {name: hk_disable, sim: RTL} + - {name: uart_rx, sim: RTL} + - {name: hk_regs_rst_spi, sim: RTL} + - {name: gpio_all_i_user, sim: RTL} + - {name: gpio_all_i_pu, sim: RTL} + - {name: gpio_all_i_pu_user, sim: RTL} + - {name: gpio_all_i_pd, sim: RTL} + - {name: gpio_all_i_pd_user, sim: RTL} + - {name: gpio_all_bidir_user, sim: RTL} + - {name: gpio_all_o, sim: RTL} + - {name: gpio_all_o_user, sim: RTL} + - {name: hk_regs_wr_wb_cpu, sim: RTL} + - {name: IRQ_timer, sim: RTL} + - {name: bitbang_cpu_all_i, sim: RTL} + - {name: bitbang_spi_o, sim: RTL} + - {name: mgmt_gpio_out, sim: RTL} + - {name: bitbang_spi_i, sim: RTL} + - {name: hk_regs_wr_spi, sim: RTL} + - {name: IRQ_external, sim: RTL} + - {name: IRQ_uart, sim: RTL} + - {name: mgmt_gpio_in, sim: RTL} + - {name: timer0_oneshot, sim: RTL} + - {name: uart_loopback, sim: RTL} + - {name: timer0_periodic, sim: RTL} + - {name: uart_tx, sim: RTL} + - {name: debug, sim: RTL} + - {name: spi_master_rd, sim: RTL} + - {name: user_pass_thru_rd, sim: RTL} + - {name: clock_redirect, sim: RTL} + - {name: mgmt_gpio_bidir, sim: RTL} + - {name: la, sim: RTL} + # - {name: pll, sim: RTL} + - {name: spi_master_temp, sim: RTL} + - {name: bitbang_cpu_all_o, sim: RTL} + - {name: mem_dff_W, sim: RTL} + - {name: serial_shifting_01, sim: RTL} + - {name: mem_dff2_W, sim: RTL} + - {name: serial_shifting_10, sim: RTL} + - {name: serial_shifting_1100, sim: RTL} + - {name: serial_shifting_0011, sim: RTL} + - {name: cpu_stress, sim: RTL} + - {name: spi_rd_wr_nbyte, sim: RTL} + - {name: cpu_reset, sim: RTL} + - {name: user_address_space, sim: RTL} + - {name: mem_dff2_HW, sim: RTL} + - {name: mem_dff_HW, sim: RTL} + - {name: mem_dff2_B, sim: RTL} + - {name: mem_dff_B, sim: RTL} + - {name: mgmt_gpio_disable, sim: RTL} + - {name: user_pass_thru_connection, sim: RTL} + - {name: spi_rd_wr, sim: RTL} + - {name: PoR, sim: RTL} + - {name: IRQ_spi, sim: RTL} + - {name: IRQ_external2, sim: RTL} + - {name: IRQ_uart_rx, sim: RTL} + - {name: uart_rx_msg, sim: RTL} + - {name: user0_irq, sim: RTL} + - {name: user1_irq, sim: RTL} + - {name: user2_irq, sim: RTL} + - {name: mgmt_pass_thru_rd, sim: RTL} + + + diff --git a/verilog/dv/cocotb/regression/all_rtl_sky130_caravan.yaml b/verilog/dv/cocotb/regression/all_rtl_sky130_caravan.yaml new file mode 100644 index 000000000..bcdb587d7 --- /dev/null +++ b/verilog/dv/cocotb/regression/all_rtl_sky130_caravan.yaml @@ -0,0 +1,52 @@ +--- +# Regression with all tests run in RTL mode + +Tests: + - {name: gpio_all_i_caravan, sim: RTL} + - {name: hk_disable, sim: RTL} + - {name: uart_rx, sim: RTL} + - {name: hk_regs_rst_spi, sim: RTL} + - {name: gpio_all_i_pu_caravan, sim: RTL} + - {name: gpio_all_i_pd_caravan, sim: RTL} + - {name: gpio_all_o_caravan, sim: RTL} + - {name: IRQ_timer, sim: RTL} + - {name: mgmt_gpio_out, sim: RTL} + - {name: hk_regs_wr_spi, sim: RTL} + - {name: IRQ_external, sim: RTL} + - {name: IRQ_uart, sim: RTL} + - {name: mgmt_gpio_in, sim: RTL} + - {name: timer0_oneshot, sim: RTL} + - {name: uart_loopback, sim: RTL} + - {name: timer0_periodic, sim: RTL} + - {name: uart_tx, sim: RTL} + - {name: debug, sim: RTL} + - {name: spi_master_rd, sim: RTL} + - {name: user_pass_thru_rd, sim: RTL} + - {name: mgmt_gpio_bidir, sim: RTL} + - {name: mem_dff_W, sim: RTL} + - {name: serial_shifting_01, sim: RTL} + - {name: mem_dff2_W, sim: RTL} + - {name: serial_shifting_10, sim: RTL} + - {name: serial_shifting_1100, sim: RTL} + - {name: serial_shifting_0011, sim: RTL} + - {name: cpu_stress, sim: RTL} + - {name: spi_rd_wr_nbyte, sim: RTL} + - {name: cpu_reset, sim: RTL} + - {name: mem_dff2_HW, sim: RTL} + - {name: mem_dff_HW, sim: RTL} + - {name: mem_dff2_B, sim: RTL} + - {name: mem_dff_B, sim: RTL} + - {name: mgmt_gpio_disable, sim: RTL} + - {name: user_pass_thru_connection, sim: RTL} + - {name: spi_rd_wr, sim: RTL} + - {name: PoR, sim: RTL} + - {name: IRQ_spi, sim: RTL} + - {name: IRQ_external2, sim: RTL} + - {name: IRQ_uart_rx, sim: RTL} + - {name: user0_irq, sim: RTL} + - {name: user1_irq, sim: RTL} + - {name: user2_irq, sim: RTL} + - {name: mgmt_pass_thru_rd, sim: RTL} + + + diff --git a/verilog/dv/cocotb/regression/all_rtl_swift2.yaml b/verilog/dv/cocotb/regression/all_rtl_swift2.yaml new file mode 100644 index 000000000..f050f456d --- /dev/null +++ b/verilog/dv/cocotb/regression/all_rtl_swift2.yaml @@ -0,0 +1,69 @@ +--- +# Regression with all tests run in RTL mode + +Tests: + - {name: gpio_all_i, sim: RTL} + - {name: hk_disable, sim: RTL} + - {name: uart_rx, sim: RTL} + - {name: hk_regs_rst_spi, sim: RTL} + - {name: gpio_all_i_user, sim: RTL} + - {name: gpio_all_i_pu, sim: RTL} + - {name: gpio_all_i_pu_user, sim: RTL} + - {name: gpio_all_i_pd, sim: RTL} + - {name: gpio_all_i_pd_user, sim: RTL} + - {name: gpio_all_bidir_user, sim: RTL} + - {name: gpio_all_o, sim: RTL} + - {name: gpio_all_o_user, sim: RTL} + - {name: hk_regs_wr_wb_cpu, sim: RTL} + - {name: IRQ_timer, sim: RTL} + - {name: bitbang_cpu_all_i, sim: RTL} + - {name: bitbang_spi_o, sim: RTL} + - {name: mgmt_gpio_out, sim: RTL} + - {name: bitbang_spi_i, sim: RTL} + - {name: hk_regs_wr_spi, sim: RTL} + - {name: IRQ_external, sim: RTL} + - {name: IRQ_uart, sim: RTL} + - {name: mgmt_gpio_in, sim: RTL} + - {name: timer0_oneshot, sim: RTL} + - {name: uart_loopback, sim: RTL} + - {name: timer0_periodic, sim: RTL} + - {name: uart_tx, sim: RTL} + - {name: debug_swd, sim: RTL} + # - {name: spi_master_rd, sim: RTL} + - {name: user_pass_thru_rd, sim: RTL} + - {name: clock_redirect, sim: RTL} + - {name: mgmt_gpio_bidir, sim: RTL} + - {name: la, sim: RTL} + # - {name: pll, sim: RTL} + # - {name: spi_master_temp, sim: RTL} + - {name: bitbang_cpu_all_o, sim: RTL} + - {name: mem_dff_W, sim: RTL} + - {name: serial_shifting_01, sim: RTL} + - {name: mem_dff2_W, sim: RTL} + - {name: serial_shifting_10, sim: RTL} + - {name: serial_shifting_1100, sim: RTL} + - {name: serial_shifting_0011, sim: RTL} + - {name: cpu_stress, sim: RTL} + - {name: spi_rd_wr_nbyte, sim: RTL} + - {name: cpu_reset, sim: RTL} + - {name: user_address_space, sim: RTL} + - {name: mem_dff2_HW, sim: RTL} + - {name: mem_dff_HW, sim: RTL} + - {name: mem_dff2_B, sim: RTL} + - {name: mem_dff_B, sim: RTL} + - {name: mgmt_gpio_pu_pd, sim: RTL} + - {name: mgmt_gpio_disable, sim: RTL} + - {name: user_pass_thru_connection, sim: RTL} + - {name: spi_rd_wr, sim: RTL} + - {name: PoR, sim: RTL} + - {name: IRQ_spi, sim: RTL} + - {name: IRQ_external2, sim: RTL} + - {name: IRQ_uart_rx, sim: RTL} + - {name: uart_rx_msg, sim: RTL} + - {name: user0_irq, sim: RTL} + - {name: user1_irq, sim: RTL} + - {name: user2_irq, sim: RTL} + - {name: mgmt_pass_thru_rd, sim: RTL} + + + diff --git a/verilog/dv/cocotb/regression/all_sdf_gf180.yaml b/verilog/dv/cocotb/regression/all_sdf_gf180.yaml new file mode 100644 index 000000000..3d4e53fa0 --- /dev/null +++ b/verilog/dv/cocotb/regression/all_sdf_gf180.yaml @@ -0,0 +1,72 @@ +--- +# Regression with all tests run in GL_SDF mode + +Tests: + - {name: gpio_all_i, sim: GL_SDF} + - {name: hk_disable, sim: GL_SDF} + - {name: uart_rx, sim: GL_SDF} + - {name: hk_regs_rst_spi, sim: GL_SDF} + - {name: gpio_all_i_user, sim: GL_SDF} + - {name: gpio_all_i_pu, sim: GL_SDF} + - {name: gpio_all_i_pu_user, sim: GL_SDF} + - {name: gpio_all_i_pd, sim: GL_SDF} + - {name: gpio_all_i_pd_user, sim: GL_SDF} + - {name: gpio_all_bidir_user, sim: GL_SDF} + - {name: gpio_all_o, sim: GL_SDF} + - {name: gpio_all_o_user, sim: GL_SDF} + - {name: hk_regs_wr_wb_cpu, sim: GL_SDF} + - {name: IRQ_timer, sim: GL_SDF} + - {name: bitbang_cpu_all_i, sim: GL_SDF} + - {name: bitbang_spi_o, sim: GL_SDF} + - {name: mgmt_gpio_out, sim: GL_SDF} + - {name: bitbang_spi_i, sim: GL_SDF} + - {name: hk_regs_wr_spi, sim: GL_SDF} + - {name: IRQ_external, sim: GL_SDF} + - {name: IRQ_uart, sim: GL_SDF} + - {name: mgmt_gpio_in, sim: GL_SDF} + - {name: timer0_oneshot, sim: GL_SDF} + - {name: uart_loopback, sim: GL_SDF} + - {name: timer0_periodic, sim: GL_SDF} + - {name: uart_tx, sim: GL_SDF} + - {name: debug, sim: GL_SDF} + - {name: spi_master_rd, sim: GL_SDF} + - {name: user_pass_thru_rd, sim: GL_SDF} + - {name: clock_redirect, sim: GL_SDF} + - {name: mgmt_gpio_bidir, sim: GL_SDF} + - {name: la, sim: GL_SDF} + # - {name: pll, sim: GL_SDF} + - {name: spi_master_temp, sim: GL_SDF} + - {name: bitbang_cpu_all_o, sim: GL_SDF} + - {name: mem_dff_W, sim: GL_SDF} + - {name: serial_shifting_01, sim: GL_SDF} + - {name: mem_dff2_W, sim: GL_SDF} + - {name: serial_shifting_10, sim: GL_SDF} + - {name: serial_shifting_1100, sim: GL_SDF} + - {name: serial_shifting_0011, sim: GL_SDF} + - {name: cpu_stress, sim: GL_SDF} + - {name: spi_rd_wr_nbyte, sim: GL_SDF} + - {name: cpu_reset, sim: GL_SDF} + - {name: user_address_space, sim: GL_SDF} + - {name: mem_sram_smoke, sim: GL_SDF} # gf180 only + - {name: mem_sram_W, sim: GL_SDF} # gf180 only + - {name: mem_sram_HW, sim: GL_SDF} # gf180 only + - {name: mem_sram_B, sim: GL_SDF} # gf180 only + # - {name: mem_dff2_HW, sim: GL_SDF} + # - {name: mem_dff_HW, sim: GL_SDF} + # - {name: mem_dff2_B, sim: GL_SDF} + # - {name: mem_dff_B, sim: GL_SDF} + - {name: mgmt_gpio_disable, sim: GL_SDF} + - {name: user_pass_thru_connection, sim: GL_SDF} + - {name: spi_rd_wr, sim: GL_SDF} + - {name: PoR, sim: GL_SDF} + - {name: IRQ_spi, sim: GL_SDF} + - {name: IRQ_external2, sim: GL_SDF} + - {name: IRQ_uart_rx, sim: GL_SDF} + - {name: uart_rx_msg, sim: GL_SDF} + - {name: user0_irq, sim: GL_SDF} + - {name: user1_irq, sim: GL_SDF} + - {name: user2_irq, sim: GL_SDF} + - {name: mgmt_pass_thru_rd, sim: GL_SDF} + + + diff --git a/verilog/dv/cocotb/regression/all_sdf_sky130.yaml b/verilog/dv/cocotb/regression/all_sdf_sky130.yaml new file mode 100644 index 000000000..b9aa14f91 --- /dev/null +++ b/verilog/dv/cocotb/regression/all_sdf_sky130.yaml @@ -0,0 +1,68 @@ +--- +# Regression with all tests run in GL_SDF mode + +Tests: + - {name: gpio_all_i, sim: GL_SDF} + - {name: hk_disable, sim: GL_SDF} + - {name: uart_rx, sim: GL_SDF} + - {name: hk_regs_rst_spi, sim: GL_SDF} + - {name: gpio_all_i_user, sim: GL_SDF} + - {name: gpio_all_i_pu, sim: GL_SDF} + - {name: gpio_all_i_pu_user, sim: GL_SDF} + - {name: gpio_all_i_pd, sim: GL_SDF} + - {name: gpio_all_i_pd_user, sim: GL_SDF} + - {name: gpio_all_bidir_user, sim: GL_SDF} + - {name: gpio_all_o, sim: GL_SDF} + - {name: gpio_all_o_user, sim: GL_SDF} + - {name: hk_regs_wr_wb_cpu, sim: GL_SDF} + - {name: IRQ_timer, sim: GL_SDF} + - {name: bitbang_cpu_all_i, sim: GL_SDF} + - {name: bitbang_spi_o, sim: GL_SDF} + - {name: mgmt_gpio_out, sim: GL_SDF} + - {name: bitbang_spi_i, sim: GL_SDF} + - {name: hk_regs_wr_spi, sim: GL_SDF} + - {name: IRQ_external, sim: GL_SDF} + - {name: IRQ_uart, sim: GL_SDF} + - {name: mgmt_gpio_in, sim: GL_SDF} + - {name: timer0_oneshot, sim: GL_SDF} + - {name: uart_loopback, sim: GL_SDF} + - {name: timer0_periodic, sim: GL_SDF} + - {name: uart_tx, sim: GL_SDF} + - {name: debug, sim: GL_SDF} + - {name: spi_master_rd, sim: GL_SDF} + - {name: user_pass_thru_rd, sim: GL_SDF} + - {name: clock_redirect, sim: GL_SDF} + - {name: mgmt_gpio_bidir, sim: GL_SDF} + - {name: la, sim: GL_SDF} + # - {name: pll, sim: GL_SDF} + - {name: spi_master_temp, sim: GL_SDF} + - {name: bitbang_cpu_all_o, sim: GL_SDF} + - {name: mem_dff_W, sim: GL_SDF} + - {name: serial_shifting_01, sim: GL_SDF} + - {name: mem_dff2_W, sim: GL_SDF} + - {name: serial_shifting_10, sim: GL_SDF} + - {name: serial_shifting_1100, sim: GL_SDF} + - {name: serial_shifting_0011, sim: GL_SDF} + - {name: cpu_stress, sim: GL_SDF} + - {name: spi_rd_wr_nbyte, sim: GL_SDF} + - {name: cpu_reset, sim: GL_SDF} + - {name: user_address_space, sim: GL_SDF} + - {name: mem_dff2_HW, sim: GL_SDF} + - {name: mem_dff_HW, sim: GL_SDF} + - {name: mem_dff2_B, sim: GL_SDF} + - {name: mem_dff_B, sim: GL_SDF} + - {name: mgmt_gpio_disable, sim: GL_SDF} + - {name: user_pass_thru_connection, sim: GL_SDF} + - {name: spi_rd_wr, sim: GL_SDF} + - {name: PoR, sim: GL_SDF} + - {name: IRQ_spi, sim: GL_SDF} + - {name: IRQ_external2, sim: GL_SDF} + - {name: IRQ_uart_rx, sim: GL_SDF} + - {name: uart_rx_msg, sim: GL_SDF} + - {name: user0_irq, sim: GL_SDF} + - {name: user1_irq, sim: GL_SDF} + - {name: user2_irq, sim: GL_SDF} + - {name: mgmt_pass_thru_rd, sim: GL_SDF} + + + diff --git a/verilog/dv/cocotb/regression/all_sdf_sky130_caravan.yaml b/verilog/dv/cocotb/regression/all_sdf_sky130_caravan.yaml new file mode 100644 index 000000000..49d5ef176 --- /dev/null +++ b/verilog/dv/cocotb/regression/all_sdf_sky130_caravan.yaml @@ -0,0 +1,51 @@ +--- +# Regression with all tests run in GL_SDF mode + +Tests: + - {name: gpio_all_i_caravan, sim: GL_SDF} + - {name: uart_rx, sim: GL_SDF} + - {name: hk_regs_rst_spi, sim: GL_SDF} + - {name: gpio_all_i_pu_caravan, sim: GL_SDF} + - {name: gpio_all_i_pd_caravan, sim: GL_SDF} + - {name: gpio_all_o_caravan, sim: GL_SDF} + - {name: IRQ_timer, sim: GL_SDF} + - {name: mgmt_gpio_out, sim: GL_SDF} + - {name: hk_regs_wr_spi, sim: GL_SDF} + - {name: IRQ_external, sim: GL_SDF} + - {name: IRQ_uart, sim: GL_SDF} + - {name: mgmt_gpio_in, sim: GL_SDF} + - {name: timer0_oneshot, sim: GL_SDF} + - {name: uart_loopback, sim: GL_SDF} + - {name: timer0_periodic, sim: GL_SDF} + - {name: uart_tx, sim: GL_SDF} + - {name: debug, sim: GL_SDF} + - {name: spi_master_rd, sim: GL_SDF} + - {name: user_pass_thru_rd, sim: GL_SDF} + - {name: mgmt_gpio_bidir, sim: GL_SDF} + - {name: mem_dff_W, sim: GL_SDF} + - {name: serial_shifting_01, sim: GL_SDF} + - {name: mem_dff2_W, sim: GL_SDF} + - {name: serial_shifting_10, sim: GL_SDF} + - {name: serial_shifting_1100, sim: GL_SDF} + - {name: serial_shifting_0011, sim: GL_SDF} + - {name: cpu_stress, sim: GL_SDF} + - {name: spi_rd_wr_nbyte, sim: GL_SDF} + - {name: cpu_reset, sim: GL_SDF} + - {name: mem_dff2_HW, sim: GL_SDF} + - {name: mem_dff_HW, sim: GL_SDF} + - {name: mem_dff2_B, sim: GL_SDF} + - {name: mem_dff_B, sim: GL_SDF} + - {name: mgmt_gpio_disable, sim: GL_SDF} + - {name: user_pass_thru_connection, sim: GL_SDF} + - {name: spi_rd_wr, sim: GL_SDF} + - {name: PoR, sim: GL_SDF} + - {name: IRQ_spi, sim: GL_SDF} + - {name: IRQ_external2, sim: GL_SDF} + - {name: IRQ_uart_rx, sim: GL_SDF} + - {name: user0_irq, sim: GL_SDF} + - {name: user1_irq, sim: GL_SDF} + - {name: user2_irq, sim: GL_SDF} + - {name: mgmt_pass_thru_rd, sim: GL_SDF} + + + diff --git a/verilog/dv/cocotb/regression/all_spi_tests.yaml b/verilog/dv/cocotb/regression/all_spi_tests.yaml new file mode 100644 index 000000000..57152307e --- /dev/null +++ b/verilog/dv/cocotb/regression/all_spi_tests.yaml @@ -0,0 +1,19 @@ +--- +# Regression with all tests run in RTL mode + +Tests: + - {name: hk_disable, sim: RTL} + - {name: hk_regs_rst_spi, sim: RTL} + - {name: bitbang_spi_i, sim: RTL} + - {name: hk_regs_wr_spi, sim: RTL} + - {name: IRQ_external, sim: RTL} + - {name: user_pass_thru_rd, sim: RTL} + - {name: spi_rd_wr_nbyte, sim: RTL} + - {name: user_pass_thru_connection, sim: RTL} + - {name: spi_rd_wr, sim: RTL} + - {name: IRQ_spi, sim: RTL} + - {name: mgmt_pass_thru_rd, sim: RTL} + - {name: IRQ_external2, sim: RTL} + - {name: bitbang_spi_o, sim: RTL} + + diff --git a/verilog/dv/cocotb/user_design.py b/verilog/dv/cocotb/user_design.py new file mode 100644 index 000000000..37c07e3f1 --- /dev/null +++ b/verilog/dv/cocotb/user_design.py @@ -0,0 +1,175 @@ +import cocotb +from caravel_cocotb.vip import WishboneInterface +from caravel_cocotb.vip import RegisterFile +from cocotb.triggers import Edge, First, ClockCycles +from models.housekeeping_model.hk_model import HK_Model +from models.soc_model.soc_model import SOC_Model +from models.user_project_model.user_model import UserModel +from models.gpio_model.gpio_model import GPIOs_Model +from models.cpu_model.cpu_model import CPU_Model + + +class UserDesign: + def __init__(self, caravelEnv, used_addr=None, gpio_test=None, la_test=False): + self.caravelEnv = caravelEnv + inputs, outputs, IOs, LAs = self.get_hdls(caravelEnv) + self._initalize_outputs([outputs["ack"], outputs["data"], LAs["out"], IOs["out"]]) + self.debug_regs = DebugRegs(caravelEnv) + regfile = self.debug_regs.get_regs() + if used_addr is not None: + regfile = FullAddrSpaceRegs(used_addr).get_regs() + self.wb = WishboneInterface(inputs, outputs, regfile) + self.la_test = la_test + self.la_testing = LA_Testing(LAs) + self.gpio_test = GPIO_Testing(caravelEnv, gpio_test, self.debug_regs, IOs) + + def get_hdls(self, caravelEnv): + inputs = {"clk": caravelEnv.user_hdl.wb_clk_i, "rst": caravelEnv.user_hdl.wb_rst_i, "stb": caravelEnv.user_hdl.wbs_stb_i, "we": self.caravelEnv.user_hdl.wbs_we_i, "cyc": caravelEnv.user_hdl.wbs_cyc_i, "sel": caravelEnv.user_hdl.wbs_sel_i, "addr": caravelEnv.user_hdl.wbs_adr_i, "data": caravelEnv.user_hdl.wbs_dat_i} + + outputs = {"ack": caravelEnv.user_hdl.wbs_ack_o, "data": caravelEnv.user_hdl.wbs_dat_o} + + IOs = {"out": caravelEnv.user_hdl.io_out, "oeb": caravelEnv.user_hdl.io_oeb, "in": caravelEnv.user_hdl.io_in} + + LAs = {"in": caravelEnv.user_hdl.la_data_in, "out": caravelEnv.user_hdl.la_data_out, "oeb":caravelEnv.user_hdl.la_oenb} + + return inputs, outputs, IOs, LAs + + def _initalize_outputs(self, outputs: list): + for output in outputs: + output.value = 0 + + async def start(self): + cocotb.log.info("[UserDesign][start] start user design") + await cocotb.start(self.wb.start()) + await cocotb.start(self.gpio_test.start()) + if self.la_test: + await cocotb.start(self.la_testing.start()) + + await ClockCycles(self.caravelEnv.clk, 1) + if cocotb.plusargs['SIM'] == "\"RTL\"" and "VCS" in cocotb.plusargs: + self.coverage_models() + + def coverage_models(self): + self.hk_model = HK_Model(self.caravelEnv) + self.SOC_model = SOC_Model(self.caravelEnv) + self.user_model = UserModel(self.caravelEnv) + self.gpios_model = GPIOs_Model(self.caravelEnv) + self.cpu_model = CPU_Model(self.caravelEnv) + cocotb.plusargs["COVERAGE_COLLECT"] = True + + +class DebugRegs(): + def __init__(self, caravelEnv, addr_1=0x300FFFF8, addr_2=0x300FFFFC): + """by default use the last two registers in user space""" + self.reg_file = RegisterFile() + self.reg_file.add_register("debug_reg_1", addr_1) + self.reg_file.add_register("debug_reg_2", addr_2) + self.caravelEnv = caravelEnv + self.addr_1 = addr_1 + self.addr_2 = addr_2 + + def get_regs(self): + return self.reg_file + + async def wait_reg1(self, data): + while True: + if self.read_debug_reg1() == data: + return + await ClockCycles(self.caravelEnv.clk, 1) + + async def wait_reg2(self, data): + while True: + if self.read_debug_reg2() == data: + return + await ClockCycles(self.caravelEnv.clk, 1) + + def read_debug_reg1(self): + return self.reg_file.read(self.addr_1) + + def read_debug_reg2(self): + return self.reg_file.read(self.addr_2) + + def read_debug_reg1_str(self): + return bin(self.reg_file.read(self.addr_1))[2:] + + def read_debug_reg2_str(self): + return bin(self.reg_file.read(self.addr_2))[2:] + + # writing debug registers using backdoor because in GL + # cpu can't be disabled for now because of different netlist names + def write_debug_reg1_backdoor(self, data): + self.reg_file.write(self.addr_1, data) + + def write_debug_reg2_backdoor(self, data): + self.reg_file.write(self.addr_2, data) + + +class FullAddrSpaceRegs(): + def __init__(self, used_addr): + """ add register in the whole address space""" + self.reg_file = RegisterFile() + unique_elements_set = set(used_addr) + for address in unique_elements_set: + self.reg_file.add_register(f"reg_{hex(address)[2:]}", address, reset_val=0x777) + + def get_regs(self): + return self.reg_file + + +class GPIO_Testing: + def __init__(self, caravelEnv, test, debug_regs, IOs): + self.caravelEnv = caravelEnv + self.test = test + self.debug_regs = debug_regs + self.IOs = IOs + + async def start(self): + if self.test is not None: + cocotb.log.info("[GPIO_Testing][start] start gpio testing") + await cocotb.start(self.test(self.caravelEnv, self.debug_regs, self.IOs)) + + +class LA_Testing: + def __init__(self, LAs): + self.la_in = LAs["in"] + self.la_out = LAs["out"] + self.la_oeb = LAs["oeb"] + + async def drive_out(self): + """drive the la_out based on the value of la_in and la_oeb""" + la_in_edge = Edge(self.la_in) + la_oeb_edge = Edge(self.la_oeb) + # wait over any change in la in or la out + while True: + await First(la_in_edge, la_oeb_edge) + cocotb.log.debug(f"[LA_Testing][drive_out] la_in = {self.la_in.value.binstr}, la_oeb = {self.la_oeb.value.binstr}") + la_oeb_binary = self.la_oeb.value.binstr[::-1] + la_in_binary = self.la_in.value.binstr[::-1] + for i, oeb in enumerate(la_oeb_binary): + if i < 32: + if oeb == "1": + cocotb.log.debug(f"[LA_Testing][drive_out] drive la_out[{i}] = {la_in_binary[i+32]}") + self.la_out[i].value = int(la_in_binary[i+32]) + elif i < 64: + if oeb == "1": + cocotb.log.debug(f"[LA_Testing][drive_out] drive la_out[{i}] = {la_in_binary[i-32]}") + self.la_out[i].value = int(la_in_binary[i-32]) + elif i < 96: + if oeb == "1": + cocotb.log.debug(f"[LA_Testing][drive_out] drive la_out[{i}] = {la_in_binary[i+32]}") + self.la_out[i].value = int(la_in_binary[i+32]) + elif i < 128: + if oeb == "1": + cocotb.log.debug(f"[LA_Testing][drive_out] drive la_out[{i}] = {la_in_binary[i-32]}") + self.la_out[i].value = int(la_in_binary[i-32]) + + async def start(self): + cocotb.log.info("[LA_Testing][start] start la testing") + await cocotb.start(self.drive_out) + + +async def configure_userdesign(caravelEnv, used_addr=None, gpio_test=None, la_test=False): + user_design = UserDesign(caravelEnv, used_addr, gpio_test, la_test) + await cocotb.start(user_design.start()) + debug_regs = user_design.debug_regs + return debug_regs diff --git a/verilog/dv/cocotb/user_monitor_driver.py b/verilog/dv/cocotb/user_monitor_driver.py new file mode 100644 index 000000000..10552628a --- /dev/null +++ b/verilog/dv/cocotb/user_monitor_driver.py @@ -0,0 +1,79 @@ +import cocotb +from cocotb.binary import BinaryValue +from collections.abc import Iterable + + +class UserPins: + def __init__(self, caravelEnv) -> None: + self.user_hdl = caravelEnv.user_hdl + pass + + def hdls(self): + self.io_in = self.user_hdl.io_in + self.io_out = self.user_hdl.io_out + self.io_oeb = self.user_hdl.io_oeb + self.la_data_in = self.user_hdl.la_data_in + self.la_data_out = self.user_hdl.la_data_out + self.la_oenb = self.user_hdl.la_oenb + self.irq0 = self.user_hdl.irq0 + self.irq1 = self.user_hdl.irq1 + self.irq2 = self.user_hdl.irq2 + + def drive_io_out(self, bits, data): + data_bits = [] + is_list = isinstance(bits, (list, tuple)) + if is_list: + cocotb.log.debug( + f"[UserPins] [drive_io_out] start bits[1] = {bits[1]} bits[0]= {bits[0]}" + ) + data_bits = BinaryValue( + value=data, n_bits=bits[0] - bits[1] + 1, bigEndian=(bits[0] < bits[1]) + ) + for i, bits2 in enumerate(range(bits[1], bits[0] + 1)): + self.user_hdl._id(f"io_out{bits2}", False).value = data_bits[i] + cocotb.log.debug( + f"[UserPins] [drive_io_out] drive gpio{bits2} with {data_bits[i]}" + ) + else: + self.user_hdl._id(f"io_out{bits}", False).value = data + cocotb.log.debug( + f"[UserPins] [drive_io_out] drive gpio{bits} with {data} and gpio{bits}_en with 1" + ) + + def drive_io_oeb(self, bits, data): + data_bits = [] + is_list = isinstance(bits, (list, tuple)) + if is_list: + cocotb.log.debug( + f"[UserPins] [drive_io_oeb] start bits[1] = {bits[1]} bits[0]= {bits[0]}" + ) + data_bits = BinaryValue( + value=data, n_bits=bits[0] - bits[1] + 1, bigEndian=(bits[0] < bits[1]) + ) + for i, bits2 in enumerate(range(bits[1], bits[0] + 1)): + self.user_hdl._id(f"io_oeb{bits2}", False).value = data_bits[i] + cocotb.log.debug( + f"[UserPins] [drive_io_oeb] drive gpio{bits2} with {data_bits[i]}" + ) + else: + self.user_hdl._id(f"io_oeb{bits}", False).value = data + cocotb.log.debug( + f"[UserPins] [drive_io_oeb] drive gpio{bits} with {data} and gpio{bits}_en with 1" + ) + + def monitor_io_in(self, h_bit, l_bit=None) -> cocotb.binary.BinaryValue: + mprj = self.user_hdl.io_in.value + size = mprj.n_bits - 1 # size of pins array + if isinstance(h_bit, Iterable): + l_bit = h_bit[1] + h_bit = h_bit[0] + if l_bit is None: + l_bit = h_bit + mprj_out = self.user_hdl.io_in.value[size - h_bit: size - l_bit] + if mprj_out.is_resolvable: + cocotb.log.debug( + f" [UserPins] Monitor : mprj[{h_bit}:{l_bit}] = {hex(mprj_out)}" + ) + else: + cocotb.log.debug(f" [caravel] Monitor : mprj[{h_bit}:{l_bit}] = {mprj_out}") + return mprj_out \ No newline at end of file diff --git a/verilog/includes/includes.gl+sdf.caravel_user_project b/verilog/includes/includes.gl+sdf.caravel_user_project index 284a97cbb..451c4e24d 100644 --- a/verilog/includes/includes.gl+sdf.caravel_user_project +++ b/verilog/includes/includes.gl+sdf.caravel_user_project @@ -1,3 +1,6 @@ // Caravel user project includes -$USER_PROJECT_VERILOG/gl/user_project_wrapper.v -$USER_PROJECT_VERILOG/gl/user_proj_example.v +// -v $(USER_PROJECT_VERILOG)/vip/user_vip_flash_spi.v +-v $(USER_PROJECT_VERILOG)/rtl/user_defines.v + +-v $(USER_PROJECT_VERILOG)/gl/user_project_wrapper.v +-v $(USER_PROJECT_VERILOG)/gl/user_proj_example.v diff --git a/verilog/includes/includes.gl.caravel_user_project b/verilog/includes/includes.gl.caravel_user_project index f5047d527..76a606a26 100644 --- a/verilog/includes/includes.gl.caravel_user_project +++ b/verilog/includes/includes.gl.caravel_user_project @@ -1,3 +1,57 @@ +########################################################### +## VIP +########################################################### +-v $(VERILOG_PATH)/dv/vip/tbuart.v +-v $(VERILOG_PATH)/dv/vip/spiflash.v +-v $(VERILOG_PATH)/dv/vip/wb_rw_test.v +-v $(VERILOG_PATH)/gl/gf180_ram_512x8_wrapper.v + +########################################################### +## Must stay in RTL regardless of the type of simulation +########################################################### + +-v $(CARAVEL_PATH)/rtl/defines.v +-v $(VERILOG_PATH)/rtl/defines.v +-v $(CARAVEL_PATH)/rtl/user_defines.v +-v $(CARAVEL_PATH)/rtl/simple_por.v + +########################################################### +## These blocks are either synthesized or STD cell based +## Manually designed blocks +########################################################### +-v $(CARAVEL_PATH)/gl/gpio_defaults_block.v +-v $(CARAVEL_PATH)/gl/spare_logic_block.v +-v $(CARAVEL_PATH)/gl/housekeeping.v +-v $(CARAVEL_PATH)/gl/user_id_programming.v +-v $(CARAVEL_PATH)/gl/mprj_io_buffer.v +-v $(CARAVEL_PATH)/gl/caravel.v +-v $(CARAVEL_PATH)/gl/caravel_core.v + +########################################################### +## These blocks are manually designed +########################################################### +-v $(CARAVEL_PATH)/gl/chip_io.v +-v $(CARAVEL_PATH)/gl/gpio_defaults_block_007.v +-v $(CARAVEL_PATH)/gl/gpio_defaults_block_087.v +-v $(CARAVEL_PATH)/gl/gpio_defaults_block_009.v + # Caravel user project includes +-v $(USER_PROJECT_VERILOG)/rtl/user_defines.v + -v $(USER_PROJECT_VERILOG)/gl/user_project_wrapper.v -v $(USER_PROJECT_VERILOG)/gl/user_proj_example.v + +## copy right files +-v $(CARAVEL_PATH)/rtl/copyright_block.v +-v $(CARAVEL_PATH)/rtl/user_id_textblock.v +-v $(CARAVEL_PATH)/rtl/caravel_logo.v +-v $(CARAVEL_PATH)/rtl/caravel_motto.v +-v $(CARAVEL_PATH)/rtl/open_source.v + +########################################################### +# STD CELLS - they need to be below the defines.v files +########################################################### + -v $(PDK_ROOT)/$(PDK)/libs.ref/gf180mcu_fd_io/verilog/gf180mcu_fd_io.v + -v $(PDK_ROOT)/$(PDK)/libs.ref/gf180mcu_fd_sc_mcu7t5v0/verilog/primitives.v + -v $(PDK_ROOT)/$(PDK)/libs.ref/gf180mcu_fd_sc_mcu7t5v0/verilog/gf180mcu_fd_sc_mcu7t5v0.v + -v $(PDK_ROOT)/$(PDK)/libs.ref/gf180mcu_fd_ip_sram/verilog/gf180mcu_fd_ip_sram__sram512x8m8wm1.v \ No newline at end of file