Added a behavioral model for the ring oscillator, and a testbench for running the PLL (in behavioral mode), specifically for switching to and from PLL bypass mode from the processor itself.
diff --git a/verilog/dv/caravel/mgmt_soc/Makefile b/verilog/dv/caravel/mgmt_soc/Makefile index 2ab8056..f96fe74 100644 --- a/verilog/dv/caravel/mgmt_soc/Makefile +++ b/verilog/dv/caravel/mgmt_soc/Makefile
@@ -3,7 +3,7 @@ .SUFFIXES: .SILENT: clean all -PATTERNS = gpio mem uart perf hkspi sysctrl mprj_ctrl pass_thru timer timer2 +PATTERNS = gpio mem uart perf hkspi sysctrl mprj_ctrl pass_thru timer timer2 pll all: ${PATTERNS} for i in ${PATTERNS}; do \
diff --git a/verilog/dv/caravel/mgmt_soc/pll/Makefile b/verilog/dv/caravel/mgmt_soc/pll/Makefile new file mode 100644 index 0000000..e5215e6 --- /dev/null +++ b/verilog/dv/caravel/mgmt_soc/pll/Makefile
@@ -0,0 +1,40 @@ +FIRMWARE_PATH = ../.. +RTL_PATH = ../../../../rtl +IP_PATH = ../../../../ip +BEHAVIOURAL_MODELS = ../../ + +GCC_PATH=/ef/apps/bin + +.SUFFIXES: + +PATTERN = pll + +all: ${PATTERN:=.vcd} + +hex: ${PATTERN:=.hex} + +%.vvp: %_tb.v %.hex + iverilog -DFUNCTIONAL -I $(BEHAVIOURAL_MODELS)-I $(IP_PATH) -I $(RTL_PATH) \ + $< -o $@ + +%.vcd: %.vvp + vvp $< + +%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s + ${GCC_PATH}/riscv32-unknown-elf-gcc -march=rv32imc -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $< + +%.hex: %.elf + ${GCC_PATH}/riscv32-unknown-elf-objcopy -O verilog $< $@ + # to fix flash base address + sed -i 's/@10000000/@00000000/g' $@ + +%.bin: %.elf + ${GCC_PATH}/riscv32-unknown-elf-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@ + +# ---- Clean ---- + +clean: + rm -f *.elf *.hex *.bin *.vvp *.vcd *.log + +.PHONY: clean hex all +
diff --git a/verilog/dv/caravel/mgmt_soc/pll/pll.c b/verilog/dv/caravel/mgmt_soc/pll/pll.c new file mode 100644 index 0000000..042e41d --- /dev/null +++ b/verilog/dv/caravel/mgmt_soc/pll/pll.c
@@ -0,0 +1,108 @@ +#include "../../defs.h" + +// -------------------------------------------------------- + +/* + * PLL Test (self-switching) + * - Enables SPI master + * - Uses SPI master to internally access the housekeeping SPI + * - Switches PLL bypass + * - Changes PLL divider + * + * Tesbench mostly copied from sysctrl + */ +void main() +{ + int i; + uint32_t value; + + reg_mprj_datal = 0; + + // Configure upper 16 bits of user GPIO for generating testbench + // checkpoints. + + reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT; + + // Configure next 8 bits for writing the SPI value read on GPIO + reg_mprj_io_15 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_14 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_13 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_12 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_11 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_10 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_9 = GPIO_MODE_MGMT_STD_OUTPUT; + reg_mprj_io_8 = GPIO_MODE_MGMT_STD_OUTPUT; + + /* Apply configuration */ + reg_mprj_xfer = 1; + while (reg_mprj_xfer == 1); + + // Start test + reg_mprj_datal = 0xA0400000; + + // 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: Connect to housekeeping SPI (1 = connected) + + reg_spimaster_config = 0xa002; // Enable, prescaler = 2, + // connect to housekeeping SPI + + // Apply stream read (0x40 + 0x03) and read back one byte + + reg_spimaster_config = 0xb002; // Apply stream mode + reg_spimaster_data = 0x80; // Write 0x80 (write mode) + reg_spimaster_data = 0x08; // Write 0x08 (start address) + + reg_spimaster_data = 0x00; // Write 0x00 to turn off DCO mode + reg_spimaster_data = 0x00; // Write 0x00 to clock from PLL + reg_spimaster_config = 0xa102; // Release CSB (ends stream mode) + + // Write checkpoint + reg_mprj_datal = 0xA0410000 | (value << 8); // Mfgr ID (high) + + reg_spimaster_config = 0xb002; // Apply stream mode + reg_spimaster_data = 0x80; // Write 0x80 (write mode) + reg_spimaster_data = 0x12; // Write 0x12 (start address) + + reg_spimaster_data = 0x03; // Write 0x03 to divider (was 0x04) + reg_spimaster_config = 0xa102; // Release CSB (ends stream mode) + + // Write checkpoint + reg_mprj_datal = 0xA0420000 | (value << 8); // PLL enable + + reg_spimaster_config = 0xb002; // Apply stream mode + reg_spimaster_data = 0x80; // Write 0x80 (write mode) + reg_spimaster_data = 0x11; // Write 0x11 (start address) + + reg_spimaster_data = 0x02; // Write 0x02 to PLL select + reg_spimaster_config = 0xa102; // Release CSB (ends stream mode) + + reg_spimaster_config = 0x2102; // Release housekeeping SPI + + // End test + reg_mprj_datal = 0xA0900000; +} +
diff --git a/verilog/dv/caravel/mgmt_soc/pll/pll_tb.v b/verilog/dv/caravel/mgmt_soc/pll/pll_tb.v new file mode 100644 index 0000000..ef684c5 --- /dev/null +++ b/verilog/dv/caravel/mgmt_soc/pll/pll_tb.v
@@ -0,0 +1,125 @@ + +`timescale 1 ns / 1 ps + +`include "caravel.v" +`include "spiflash.v" + +module pll_tb; + reg clock; + reg RSTB; + + wire gpio; + wire [15:0] checkbits; + wire [7:0] spivalue; + wire [36:0] mprj_io; + wire flash_csb; + wire flash_clk; + wire flash_io0; + wire flash_io1; + wire SDO; + + assign checkbits = mprj_io[31:16]; + assign spivalue = mprj_io[15:8]; + + // External clock is used by default. Make this artificially fast for the + // simulation. Normally this would be a slow clock and the digital PLL + // would be the fast clock. + + always #10 clock <= (clock === 1'b0); + + initial begin + clock = 0; + end + + initial begin + $dumpfile("pll_tb.vcd"); + $dumpvars(0, pll_tb); + repeat (25) begin + repeat (1000) @(posedge clock); + $display("+1000 cycles"); + end + $display("%c[1;31m",27); + $display ("Monitor: Timeout, Test GPIO (RTL) Failed"); + $display("%c[0m",27); + $finish; + end + + // Monitor + initial begin + wait(checkbits == 16'hA040); + $display("Monitor: Test PLL (RTL) Started"); + + wait(checkbits == 16'hA041); + // $display(" SPI value = 0x%x (should be 0x04)", spivalue); + // if(spivalue !== 32'h04) begin + // $display("Monitor: Test PLL (RTL) Failed"); + // $finish; + // end + wait(checkbits == 16'hA042); + // $display(" SPI value = 0x%x (should be 0x56)", spivalue); + // if(spivalue !== 32'h56) begin + // $display("Monitor: Test PLL (RTL) Failed"); + // $finish; + // end + + wait(checkbits == 16'hA090); + $display("Monitor: Test PLL (RTL) Passed"); + $finish; + end + + initial begin + RSTB <= 1'b0; + #1000; + RSTB <= 1'b1; // Release reset + #2000; + end + + always @(checkbits) begin + #1 $display("GPIO state = %b ", checkbits); + end + + wire VDD3V3; + wire VDD1V8; + wire VSS; + + assign VSS = 1'b0; + assign VDD1V8 = 1'b1; + assign VDD3V3 = 1'b1; + + caravel uut ( + .vddio (VDD3V3), + .vssio (VSS), + .vdda (VDD3V3), + .vssa (VSS), + .vccd (VDD1V8), + .vssd (VSS), + .vdda1 (VDD3V3), + .vdda2 (VDD3V3), + .vssa1 (VSS), + .vssa2 (VSS), + .vccd1 (VDD1V8), + .vccd2 (VDD1V8), + .vssd1 (VSS), + .vssd2 (VSS), + .clock (clock), + .gpio (gpio), + .mprj_io (mprj_io), + .flash_csb(flash_csb), + .flash_clk(flash_clk), + .flash_io0(flash_io0), + .flash_io1(flash_io1), + .resetb (RSTB) + ); + + spiflash #( + .FILENAME("pll.hex") + ) spiflash ( + .csb(flash_csb), + .clk(flash_clk), + .io0(flash_io0), + .io1(flash_io1), + .io2(), // not used + .io3() // not used + ); + +endmodule
diff --git a/verilog/rtl/digital_pll.v b/verilog/rtl/digital_pll.v index 9754180..d4fe6ff 100644 --- a/verilog/rtl/digital_pll.v +++ b/verilog/rtl/digital_pll.v
@@ -31,12 +31,11 @@ wire [25:0] itrim; // Internally generated trim bits wire [25:0] otrim; // Trim bits applied to the ring oscillator wire [3:0] nint; // Internal divided down clocks - wire reset; // Internal positive sense reset wire resetbb; // Internal buffered negative sense reset wire creset; // Controller reset wire ireset; // Internal reset (external reset OR extclk_sel) - assign ireset = reset | extclk_sel; + assign ireset = ~resetb | extclk_sel; // In DCO mode: Hold controller in reset and apply external trim value assign itrim = (dco == 1'b0) ? otrim : ext_trim;
diff --git a/verilog/rtl/digital_pll_controller.v b/verilog/rtl/digital_pll_controller.v index ddc553d..d4f7a4c 100644 --- a/verilog/rtl/digital_pll_controller.v +++ b/verilog/rtl/digital_pll_controller.v
@@ -99,9 +99,13 @@ if (prep == 3'b111) begin if (sum > div) begin - tval <= tval + 1; + if (tval < 127) begin + tval <= tval + 1; + end end else if (sum < div) begin - tval <= tval - 1; + if (tval > 0) begin + tval <= tval - 1; + end end end end else begin
diff --git a/verilog/rtl/ring_osc2x13.v b/verilog/rtl/ring_osc2x13.v index c0531bd..9bf6252 100644 --- a/verilog/rtl/ring_osc2x13.v +++ b/verilog/rtl/ring_osc2x13.v
@@ -131,8 +131,60 @@ input [25:0] trim; output[1:0] clockp; - wire [12:0] d; +`ifdef FUNCTIONAL // i.e., behavioral model below + + reg [1:0] clockp; + reg hiclock; + integer i; + real delay; + wire [5:0] bcount; + + assign bcount = trim[0] + trim[1] + trim[2] + + trim[3] + trim[4] + trim[5] + trim[6] + trim[7] + + trim[8] + trim[9] + trim[10] + trim[11] + trim[12] + + trim[13] + trim[14] + trim[15] + trim[16] + trim[17] + + trim[18] + trim[19] + trim[20] + trim[21] + trim[22] + + trim[23] + trim[24] + trim[25]; + + initial begin + hiclock <= 1'b0; + delay = 3.0; + end + + // Fastest operation is 214 MHz = 4.67ns + // Delay per trim is 0.02385 + // Run "hiclock" at 2x this rate, then use positive and negative + // edges to derive the 0 and 90 degree phase clocks. + + always #delay begin + hiclock <= (hiclock === 1'b0); + end + + always @(trim) begin + // Implement trim as a variable delay, one delay per trim bit + delay = 1.168 + 0.012 * $itor(bcount); + end + + always @(posedge hiclock or posedge reset) begin + if (reset == 1'b1) begin + clockp[0] <= 1'b0; + end else begin + clockp[0] <= (clockp[0] === 1'b0); + end + end + + always @(negedge hiclock or posedge reset) begin + if (reset == 1'b1) begin + clockp[1] <= 1'b0; + end else begin + clockp[1] <= (clockp[1] === 1'b0); + end + end + +`else // !FUNCTIONAL; i.e., gate level netlist below + wire [1:0] clockp; + wire [12:0] d; wire [1:0] c; // Main oscillator loop stages @@ -176,4 +228,6 @@ .Y(clockp[1]) ); +`endif // !FUNCTIONAL + endmodule