diff --git a/verilog/dv/cocotb/caravel_tests.py b/verilog/dv/cocotb/caravel_tests.py index 4df2b34a..05d2dea7 100644 --- a/verilog/dv/cocotb/caravel_tests.py +++ b/verilog/dv/cocotb/caravel_tests.py @@ -26,6 +26,7 @@ from tests.bitbang.bitbang_tests import * from tests.bitbang.bitbang_tests_cpu import * from tests.housekeeping.housekeeping_regs.housekeeping_regs_tests import * from tests.housekeeping.housekeeping_spi.user_pass_thru import * +from tests.housekeeping.general.pll import * from tests.temp_partial_test.partial import * from tests.hello_world.helloWorld import * from tests.cpu.cpu_stress import * diff --git a/verilog/dv/cocotb/tests.json b/verilog/dv/cocotb/tests.json index 20412fd3..93baf8a3 100644 --- a/verilog/dv/cocotb/tests.json +++ b/verilog/dv/cocotb/tests.json @@ -207,5 +207,13 @@ "GL":["r_gl","nightly","weekly","tape_out"], "GL_SDF":["r_sdf","weekly","tape_out"], "description":"use the housekeeping spi in user pass thru mode to read from external mem"} + + + ,"pll" :{"level":0, + "SW":true, + "RTL":["r_rtl","setup","nightly","weekly","tape_out"], + "GL":["r_gl","nightly","weekly","tape_out"], + "GL_SDF":["r_sdf","weekly","tape_out"], + "description":"Check pll diffrent configuration"} } } \ No newline at end of file diff --git a/verilog/dv/cocotb/tests/housekeeping/general/pll.c b/verilog/dv/cocotb/tests/housekeeping/general/pll.c new file mode 100644 index 00000000..a30629f6 --- /dev/null +++ b/verilog/dv/cocotb/tests/housekeeping/general/pll.c @@ -0,0 +1,152 @@ +/* + * 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; + + reg_wb_enable =1; // for enable writing to reg_debug_1 and reg_debug_2 + 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 == 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/tests/housekeeping/general/pll.py b/verilog/dv/cocotb/tests/housekeeping/general/pll.py new file mode 100644 index 00000000..e7dbc1be --- /dev/null +++ b/verilog/dv/cocotb/tests/housekeeping/general/pll.py @@ -0,0 +1,86 @@ +import random +import cocotb +from cocotb.triggers import FallingEdge,RisingEdge,ClockCycles +import cocotb.log +from cpu import RiskV +from defsParser import Regs +from cocotb.result import TestSuccess +from tests.common_functions.test_functions import * +from tests.bitbang.bitbang_functions import * +from caravel import GPIO_MODE +from cocotb.binary import BinaryValue + +reg = Regs() +caravel_clock = 0 +user_clock = 0 +@cocotb.test() +@repot_test +async def pll(dut): + caravelEnv,clock = await test_configure(dut,timeout_cycles=264012) + cpu = RiskV(dut) + cpu.cpu_force_reset() + cpu.cpu_release_reset() + error_margin = 0.1 + + await wait_reg1(cpu,caravelEnv,0xA1) + + await cocotb.start(calculate_clk_period(dut.bin14_monitor,"caravel clock")) + await cocotb.start(calculate_clk_period(dut.bin15_monitor,"user clock")) + await wait_reg1(cpu,caravelEnv,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.bin14_monitor,"caravel clock")) + await cocotb.start(calculate_clk_period(dut.bin15_monitor,"user clock")) + await wait_reg1(cpu,caravelEnv,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.bin14_monitor,"caravel clock")) + await cocotb.start(calculate_clk_period(dut.bin15_monitor,"user clock")) + await wait_reg1(cpu,caravelEnv,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.bin14_monitor,"caravel clock")) + await cocotb.start(calculate_clk_period(dut.bin15_monitor,"user clock ")) + await wait_reg1(cpu,caravelEnv,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.bin14_monitor,"caravel clock")) + await cocotb.start(calculate_clk_period(dut.bin15_monitor,"user clock")) + await wait_reg1(cpu,caravelEnv,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 \ No newline at end of file