diff --git a/verilog/dv/caravel/mgmt_soc/spi_master/Makefile b/verilog/dv/caravel/mgmt_soc/spi_master/Makefile new file mode 100644 index 00000000..8a2bf169 --- /dev/null +++ b/verilog/dv/caravel/mgmt_soc/spi_master/Makefile @@ -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 + +PDK_PATH = $(PDK_ROOT)/sky130A +VERILOG_PATH = ../../../.. +RTL_PATH = $(VERILOG_PATH)/rtl +BEHAVIOURAL_MODELS = ../../ + +# Temporary: Path to management SoC wrapper repository +MGMT_WRAPPER_PATH = ~/gits/caravel_pico/verilog/rtl + +FIRMWARE_PATH = ../.. +GCC_PATH?=/ef/apps/bin +GCC_PREFIX?=riscv32-unknown-elf + +SIM_DEFINES = -DFUNCTIONAL -DSIM + +SIM?=RTL + +.SUFFIXES: + +PATTERN = spi_master + +all: ${PATTERN:=.vcd} + +hex: ${PATTERN:=.hex} + +%.vvp: %_tb.v %.hex +ifeq ($(SIM),RTL) + iverilog -Ttyp $(SIM_DEFINES) -I $(BEHAVIOURAL_MODELS) \ + -I $(PDK_PATH) -I $(RTL_PATH) -I $(MGMT_WRAPPER_PATH) \ + $< -o $@ +else + iverilog -Ttyp $(SIM_DEFINES) -DGL -I $(BEHAVIOURAL_MODELS) \ + -I $(PDK_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \ + $< -o $@ +endif + +%.vcd: %.vvp + vvp $< + +%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s check-env + ${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $< + +%.hex: %.elf + ${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@ + # to fix flash base address + sed -i 's/@10000000/@00000000/g' $@ + +%.bin: %.elf + ${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@ + +check-env: +ifndef PDK_ROOT + $(error PDK_ROOT is undefined, please export it before running make) +endif +ifeq (,$(wildcard $(PDK_ROOT)/sky130A)) + $(error $(PDK_ROOT)/sky130A not found, please install pdk before running make) +endif +ifeq (,$(wildcard $(GCC_PATH)/$(GCC_PREFIX)-gcc )) + $(error $(GCC_PATH)/$(GCC_PREFIX)-gcc is not found, please export GCC_PATH and GCC_PREFIX before running make) +endif +# check for efabless style installation +ifeq (,$(wildcard $(PDK_ROOT)/sky130A/libs.ref/*/verilog)) +SIM_DEFINES := ${SIM_DEFINES} -DEF_STYLE +endif +# ---- Clean ---- + +clean: + rm -f *.elf *.hex *.bin *.vvp *.vcd *.log + +.PHONY: clean hex all + diff --git a/verilog/dv/caravel/mgmt_soc/spi_master/spi_master.c b/verilog/dv/caravel/mgmt_soc/spi_master/spi_master.c new file mode 100644 index 00000000..8f214170 --- /dev/null +++ b/verilog/dv/caravel/mgmt_soc/spi_master/spi_master.c @@ -0,0 +1,184 @@ +/* + * 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 "../../defs.h" + +// -------------------------------------------------------- + +/* + * SPI master Test + * - Enables SPI master + * - Uses SPI master to talk to external SPI module + */ +void main() +{ + int i; + uint32_t value; + + reg_mprj_datal = 0; + + // For SPI operation, GPIO 1 should be an input, and GPIOs 2 to 4 + // should be outputs. + + reg_mprj_io_34 = GPIO_MODE_MGMT_STD_INPUT_NOPULL; // SDI + reg_mprj_io_35 = GPIO_MODE_MGMT_STD_BIDIRECTIONAL; // SDO + reg_mprj_io_33 = GPIO_MODE_MGMT_STD_OUTPUT; // CSB + reg_mprj_io_32 = GPIO_MODE_MGMT_STD_OUTPUT; // SCK + + // 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: (unused) + + reg_spimaster_config = 0x2002; // Enable, prescaler = 2, + + // Apply stream read (0x40 + 0x03) and read back one byte + + reg_spimaster_config = 0x3002; // Apply stream mode + + reg_spimaster_data = 0xff; // Write 0xff (reset) + reg_spimaster_config = 0x2102; // Release CSB (ends stream mode) + reg_spimaster_config = 0x3002; // Apply stream mode + reg_spimaster_data = 0xab; // Write 0xab (wakeup) + reg_spimaster_config = 0x2102; // Release CSB (ends stream mode) + reg_spimaster_config = 0x3002; // Apply stream mode + reg_spimaster_data = 0x03; // Write 0x03 (read mode) + reg_spimaster_data = 0x00; // Write 0x00 (start address high byte) + reg_spimaster_data = 0x00; // Write 0x00 (start address middle byte) + reg_spimaster_data = 0x04; // Write 0x00 (start address low byte) + + reg_spimaster_data = 0x00; // Write 0x00 for read + value = reg_spimaster_data; // Read back byte + // Write checkpoint + reg_mprj_datal = 0xA0410000 | (value << 8); // 0x93 + + reg_spimaster_data = 0x00; // Write 0x00 for read + value = reg_spimaster_data; // Read back byte + // Write checkpoint + reg_mprj_datal = 0xA0420000 | (value << 8); // 0x01 + + reg_spimaster_data = 0x00; // Write 0x00 for read + value = reg_spimaster_data; // Read back byte + // Write checkpoint + reg_mprj_datal = 0xA0430000 | (value << 8); // 0x00 + + reg_spimaster_config = 0x2102; // Release CSB (ends stream mode) + reg_spimaster_config = 0x3002; // Apply stream mode + reg_spimaster_data = 0x03; // Write 0x03 (read mode) + reg_spimaster_data = 0x00; // Write 0x00 (start address low byte) + reg_spimaster_data = 0x00; // Write 0x00 (start address middle byte) + reg_spimaster_data = 0x08; // Write 0x08 (start address high byte) + + reg_spimaster_data = 0x00; // Write 0x00 for read + value = reg_spimaster_data; // Read back byte + // Write checkpoint + reg_mprj_datal = 0xA0440000 | (value << 8); // 0x13 + + reg_spimaster_data = 0x00; // Write 0x00 for read + value = reg_spimaster_data; // Read back byte + // Write checkpoint + reg_mprj_datal = 0xA0450000 | (value << 8); // 0x02 + + reg_spimaster_config = 0x2102; // Release CSB (ends stream mode) + reg_spimaster_config = 0x3002; // Apply stream mode + reg_spimaster_data = 0x03; // Write 0x03 (read mode) + reg_spimaster_data = 0x00; // Write 0x00 (start address high byte) + reg_spimaster_data = 0x00; // Write 0x00 (start address middle byte) + reg_spimaster_data = 0xa0; // Write 0xa0 (start address low byte) + + reg_spimaster_data = 0x00; // Write 0x00 for read + value = reg_spimaster_data; // Read back byte + // Write checkpoint + reg_mprj_datal = 0xA0460000 | (value << 8); // 0x63 + + reg_spimaster_data = 0x00; // Write 0x00 for read + value = reg_spimaster_data; // Read back byte + // Write checkpoint + reg_mprj_datal = 0xA0470000 | (value << 8); // 0x57 + + reg_spimaster_data = 0x00; // Write 0x00 for read + value = reg_spimaster_data; // Read back byte + // Write checkpoint + reg_mprj_datal = 0xA0480000 | (value << 8); // 0xb5 + + reg_spimaster_data = 0x00; // Write 0x00 for read + value = reg_spimaster_data; // Read back byte + // Write checkpoint + reg_mprj_datal = 0xA0490000 | (value << 8); // 0x00 + + reg_spimaster_data = 0x00; // Write 0x00 for read + value = reg_spimaster_data; // Read back byte + // Write checkpoint + reg_mprj_datal = 0xA04a0000 | (value << 8); // 0x23 + + reg_spimaster_data = 0x00; // Write 0x00 for read + value = reg_spimaster_data; // Read back byte + // Write checkpoint + reg_mprj_datal = 0xA04b0000 | (value << 8); // 0x20 + + reg_spimaster_config = 0x2102; // Release CSB (ends stream mode) + reg_spimaster_config = 0x0002; // Disable the SPI master + + // End test + reg_mprj_datal = 0xA0900000; +} + diff --git a/verilog/dv/caravel/mgmt_soc/spi_master/spi_master_tb.v b/verilog/dv/caravel/mgmt_soc/spi_master/spi_master_tb.v new file mode 100644 index 00000000..e11e6cfc --- /dev/null +++ b/verilog/dv/caravel/mgmt_soc/spi_master/spi_master_tb.v @@ -0,0 +1,236 @@ +// 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 + +`default_nettype none + +`timescale 1 ns / 1 ps + +`include "__uprj_netlists.v" +`include "caravel_netlists.v" +`include "spiflash.v" + +module spi_master_tb; + reg clock; + reg RSTB; + reg power1, power2; + + wire gpio; + wire [15:0] checkbits; + wire [7:0] spivalue; + wire [37:0] mprj_io; + wire flash_csb; + wire flash_clk; + wire flash_io0; + wire flash_io1; + + 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("spi_master.vcd"); + $dumpvars(0, spi_master_tb); + repeat (25) begin + repeat (1000) @(posedge clock); + $display("+1000 cycles"); + end + $display("%c[1;31m",27); + `ifdef GL + $display ("Monitor: Timeout, Test SPI Master (GL) Failed"); + `else + $display ("Monitor: Timeout, Test SPI Master (RTL) Failed"); + `endif + $display("%c[0m",27); + $finish; + end + + // Monitor + initial begin + wait(checkbits == 16'hA040); + `ifdef GL + $display("Monitor: Test SPI Master (GL) Started"); + `else + $display("Monitor: Test SPI Master (RTL) Started"); + `endif + wait(checkbits == 16'hA041); + $display(" SPI value = 0x%x (should be 0x93)", spivalue); + if(spivalue !== 32'h93) begin + $display("Monitor: Test SPI Master Failed"); + $finish; + end + wait(checkbits == 16'hA042); + $display(" SPI value = 0x%x (should be 0x01)", spivalue); + if(spivalue !== 32'h01) begin + $display("Monitor: Test SPI Master Failed"); + $finish; + end + wait(checkbits == 16'hA043); + $display(" SPI value = 0x%x (should be 0x00)", spivalue); + if(spivalue !== 32'h00) begin + $display("Monitor: Test SPI Master Failed"); + $finish; + end + wait(checkbits == 16'hA044); + $display(" SPI value = 0x%x (should be 0x13)", spivalue); + if(spivalue !== 32'h13) begin + $display("Monitor: Test SPI Master Failed"); + $finish; + end + wait(checkbits == 16'hA045); + $display(" SPI value = 0x%x (should be 0x02)", spivalue); + if(spivalue !== 32'h02) begin + $display("Monitor: Test SPI Master Failed"); + $finish; + end + wait(checkbits == 16'hA046); + $display(" SPI value = 0x%x (should be 0x63)", spivalue); + if(spivalue !== 32'h63) begin + $display("Monitor: Test SPI Master Failed"); + $finish; + end + wait(checkbits == 16'hA047); + $display(" SPI value = 0x%x (should be 0x57)", spivalue); + if(spivalue !== 32'h57) begin + $display("Monitor: Test SPI Master Failed"); + $finish; + end + wait(checkbits == 16'hA048); + $display(" SPI value = 0x%x (should be 0xb5)", spivalue); + if(spivalue !== 32'hb5) begin + $display("Monitor: Test SPI Master Failed"); + $finish; + end + wait(checkbits == 16'hA049); + $display(" SPI value = 0x%x (should be 0x00)", spivalue); + if(spivalue !== 32'h00) begin + $display("Monitor: Test SPI Master Failed"); + $finish; + end + wait(checkbits == 16'hA04a); + $display(" SPI value = 0x%x (should be 0x23)", spivalue); + if(spivalue !== 32'h23) begin + $display("Monitor: Test SPI Master Failed"); + $finish; + end + wait(checkbits == 16'hA04b); + $display(" SPI value = 0x%x (should be 0x20)", spivalue); + if(spivalue !== 32'h20) begin + $display("Monitor: Test SPI Master Failed"); + $finish; + end + + wait(checkbits == 16'hA090); + `ifdef GL + $display("Monitor: Test SPI Master (GL) Passed"); + `else + $display("Monitor: Test SPI Master (RTL) Passed"); + `endif + $finish; + end + + initial begin + RSTB <= 1'b0; + #1000; + RSTB <= 1'b1; // Release reset + #2000; + end + + initial begin // Power-up sequence + power1 <= 1'b0; + power2 <= 1'b0; + #200; + power1 <= 1'b1; + #200; + power2 <= 1'b1; + end + + always @(checkbits) begin + #1 $display("GPIO state = %b ", checkbits); + end + + wire VDD3V3; + wire VDD1V8; + wire VSS; + + assign VDD3V3 = power1; + assign VDD1V8 = power2; + assign VSS = 1'b0; + + assign mprj_io[3] = 1'b1; // Keep CSB high + + caravel uut ( + .vddio (VDD3V3), + .vddio_2 (VDD3V3), + .vssio (VSS), + .vssio_2 (VSS), + .vdda (VDD3V3), + .vssa (VSS), + .vccd (VDD1V8), + .vssd (VSS), + .vdda1 (VDD3V3), + .vdda1_2 (VDD3V3), + .vdda2 (VDD3V3), + .vssa1 (VSS), + .vssa1_2 (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("spi_master.hex") + ) spiflash ( + .csb(flash_csb), + .clk(flash_clk), + .io0(flash_io0), + .io1(flash_io1), + .io2(), // not used + .io3() // not used + ); + + /* Instantiate a 2nd SPI flash so the SPI master can talk to it */ + + spiflash #( + .FILENAME("spi_master.hex") + ) test_spi ( + .csb(mprj_io[33]), + .clk(mprj_io[32]), + .io0(mprj_io[35]), + .io1(mprj_io[34]), + .io2(), // not used + .io3() // not used + ); + +endmodule +`default_nettype wire diff --git a/verilog/dv/caravel/mgmt_soc/timer/timer_tb.v b/verilog/dv/caravel/mgmt_soc/timer/timer_tb.v index a5d21c1b..3865bf33 100644 --- a/verilog/dv/caravel/mgmt_soc/timer/timer_tb.v +++ b/verilog/dv/caravel/mgmt_soc/timer/timer_tb.v @@ -84,8 +84,8 @@ module timer_tb; `endif /* Add checks here */ wait(checkbits == 6'h01); - $display(" countbits = 0x%x (should be 0xdcba7cf9)", countbits); - if(countbits !== 32'hdcba7cf9) begin + $display(" countbits = 0x%x (should be 0xdcba7cfb)", countbits); + if(countbits !== 32'hdcba7cfb) begin $display("Monitor: Test Timer Failed"); $finish; end @@ -96,14 +96,14 @@ module timer_tb; $finish; end wait(checkbits == 6'h03); - $display(" countbits = %x (should be 0x0d)", countbits); - if(countbits !== ((32'h0d) | (3'b100))) begin + $display(" countbits = %x (should be 0x0f)", countbits); + if(countbits !== ((32'h0f) | (3'b100))) begin $display("Monitor: Test Timer Failed"); $finish; end wait(checkbits == 6'h04); - $display(" countbits = %x (should be 0x0d)", countbits); - if(countbits !== ((32'h0d) | (3'b100))) begin + $display(" countbits = %x (should be 0x0f)", countbits); + if(countbits !== ((32'h0f) | (3'b100))) begin $display("Monitor: Test Timer Failed"); $finish; end diff --git a/verilog/dv/caravel/mgmt_soc/timer2/timer2_tb.v b/verilog/dv/caravel/mgmt_soc/timer2/timer2_tb.v index 09917738..a53e216d 100644 --- a/verilog/dv/caravel/mgmt_soc/timer2/timer2_tb.v +++ b/verilog/dv/caravel/mgmt_soc/timer2/timer2_tb.v @@ -82,8 +82,8 @@ module timer2_tb; `endif /* Add checks here */ wait(checkbits == 6'h01); - $display(" countbits = 0x%x (should be 0xdcba7cf9)", countbits); - if(countbits !== 32'hdcba7cf9) begin + $display(" countbits = 0x%x (should be 0xdcba7cfb)", countbits); + if(countbits !== 32'hdcba7cfb) begin $display("Monitor: Test Timer2 (RTL) Failed"); $finish; end @@ -94,14 +94,14 @@ module timer2_tb; $finish; end wait(checkbits == 6'h03); - $display(" countbits = %x (should be 0x0d)", countbits); - if(countbits !== 32'h0d) begin + $display(" countbits = %x (should be 0x0f)", countbits); + if(countbits !== 32'h0f) begin $display("Monitor: Test Timer (RTL) Failed"); $finish; end wait(checkbits == 6'h04); - $display(" countbits = %x (should be 0x0d)", countbits); - if(countbits !== 32'h0d) begin + $display(" countbits = %x (should be 0x0f)", countbits); + if(countbits !== 32'h0f) begin $display("Monitor: Test Timer2 (RTL) Failed"); $finish; end @@ -134,8 +134,8 @@ module timer2_tb; end wait(checkbits == 6'h10); - $display(" countbits = %x (should be 0x0008)", countbits); - if(countbits !== 32'h0008) begin + $display(" countbits = %x (should be 0x000a)", countbits); + if(countbits !== 32'h000a) begin $display("Monitor: Test Timer2 (RTL) Failed"); $finish; end diff --git a/verilog/rtl/caravel.v b/verilog/rtl/caravel.v index e1dcb695..98ffa355 100644 --- a/verilog/rtl/caravel.v +++ b/verilog/rtl/caravel.v @@ -87,17 +87,21 @@ module caravel ( * FTDI chip sets these lines to high impedence (input function) at * all times except when holding the chip in reset. * - * JTAG = mprj_io[0] (inout) - * SDO = mprj_io[1] (output) - * SDI = mprj_io[2] (input) - * CSB = mprj_io[3] (input) - * SCK = mprj_io[4] (input) - * ser_rx = mprj_io[5] (input) - * ser_tx = mprj_io[6] (output) - * irq = mprj_io[7] (input) + * JTAG = mprj_io[0] (inout) + * SDO = mprj_io[1] (output) + * SDI = mprj_io[2] (input) + * CSB = mprj_io[3] (input) + * SCK = mprj_io[4] (input) + * ser_rx = mprj_io[5] (input) + * ser_tx = mprj_io[6] (output) + * irq = mprj_io[7] (input) * - * flash_io2 = mprj_io[36] (inout) - * flash_io3 = mprj_io[37] (inout) + * spi_sck = mprj_io[32] (output) + * spi_csb = mprj_io[33] (output) + * spi_sdi = mprj_io[34] (input) + * spi_sdo = mprj_io[35] (output) + * flash_io2 = mprj_io[36] (inout) + * flash_io3 = mprj_io[37] (inout) * * These pins are reserved for any project that wants to incorporate * its own processor and flash controller. While a user project can @@ -168,8 +172,8 @@ module caravel ( wire [`MPRJ_IO_PADS-1:0] mgmt_io_in; /* one- and three-pin data */ wire [`MPRJ_IO_PADS-5:0] mgmt_io_nc; /* no-connects */ - wire [3:0] mgmt_io_out; /* three-pin interface out */ - wire [3:0] mgmt_io_oeb; /* three-pin output enable */ + wire [4:0] mgmt_io_out; /* three-pin interface out */ + wire [4:0] mgmt_io_oeb; /* three-pin output enable */ wire clock_core; @@ -422,6 +426,7 @@ module caravel ( .spi_csb(spi_csb), .spi_sck(spi_sck), .spi_sdo(spi_sdo), + .spi_sdoenb(spi_sdoenb), // Debug .debug_in(debug_in), .debug_out(debug_out), @@ -656,6 +661,7 @@ module caravel ( .spi_csb(spi_csb), .spi_sck(spi_sck), .spi_sdo(spi_sdo), + .spi_sdoenb(spi_sdoenb), .debug_in(debug_in), .debug_out(debug_out), @@ -670,9 +676,9 @@ module caravel ( .serial_data_2(mprj_io_loader_data_2), .mgmt_gpio_in(mgmt_io_in), - .mgmt_gpio_out({mgmt_io_out[3:2], mgmt_io_in[`MPRJ_IO_PADS-3:2], + .mgmt_gpio_out({mgmt_io_out[4:2], mgmt_io_in[`MPRJ_IO_PADS-4:2], mgmt_io_out[1:0]}), - .mgmt_gpio_oeb({mgmt_io_oeb[3:2], mgmt_io_nc[`MPRJ_IO_PADS-5:0], + .mgmt_gpio_oeb({mgmt_io_oeb[4:2], mgmt_io_nc[`MPRJ_IO_PADS-6:0], mgmt_io_oeb[1:0]}), .pwr_ctrl_out(), /* Not used in this version */ @@ -739,7 +745,8 @@ module caravel ( /* First two GPIOs (JTAG and SDO) */ gpio_control_block #( .MGMT_INIT(1'b1), // Management-controlled - .OENB_INIT(1'b1) // Output controlled from bidirectional pin + .OENB_INIT(1'b1), // Output controlled from bidirectional pin + .DM_INIT(3'b110) // Mode is set to ouput, no pullup/pulldown ) gpio_control_bidir_1 [1:0] ( `ifdef USE_POWER_PINS .vccd(vccd_core), @@ -793,7 +800,6 @@ module caravel ( /* Section 1 GPIOs (GPIO 3 to 7) that start up under management control */ gpio_control_block #( - .DM_INIT(3'b001), // Configured as inputs .MGMT_INIT(1'b1), // Management-controlled .OENB_INIT(1'b1) // Output disabled ) gpio_control_in_1a [5:0] ( @@ -893,11 +899,11 @@ module caravel ( ); - /* Last two GPIOs (flash_io2 and flash_io3) */ + /* Last three GPIOs (spi_sdo, flash_io2, and flash_io3) */ gpio_control_block #( .MGMT_INIT(1'b1), // Management-controlled - .OENB_INIT(1'b1) // Output controlled from bidirectional pin - ) gpio_control_bidir_2 [1:0] ( + .OENB_INIT(1'b1) // Output controlled from bidirectional pin + ) gpio_control_bidir_2 [2:0] ( `ifdef USE_POWER_PINS .vccd(vccd_core), .vssd(vssd_core), @@ -907,46 +913,46 @@ module caravel ( // Management Soc-facing signals - .resetn(gpio_resetn_1_shifted[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-2)]), - .serial_clock(gpio_clock_1_shifted[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-2)]), + .resetn(gpio_resetn_1_shifted[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-3)]), + .serial_clock(gpio_clock_1_shifted[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-3)]), - .resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-2)]), - .serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-2)]), + .resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-3)]), + .serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-3)]), - .mgmt_gpio_in(mgmt_io_in[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .mgmt_gpio_out(mgmt_io_out[3:2]), - .mgmt_gpio_oeb(mgmt_io_oeb[3:2]), + .mgmt_gpio_in(mgmt_io_in[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .mgmt_gpio_out(mgmt_io_out[4:2]), + .mgmt_gpio_oeb(mgmt_io_oeb[4:2]), .one(), .zero(), // Serial data chain for pad configuration - .serial_data_in(gpio_serial_link_2_shifted[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-2)]), - .serial_data_out(gpio_serial_link_2[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-2)]), + .serial_data_in(gpio_serial_link_2_shifted[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-3)]), + .serial_data_out(gpio_serial_link_2[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-3)]), // User-facing signals - .user_gpio_out(user_io_out[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .user_gpio_oeb(user_io_oeb[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .user_gpio_in(user_io_in[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), + .user_gpio_out(user_io_out[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .user_gpio_oeb(user_io_oeb[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .user_gpio_in(user_io_in[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), // Pad-facing signals (Pad GPIOv2) - .pad_gpio_inenb(mprj_io_inp_dis[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .pad_gpio_ib_mode_sel(mprj_io_ib_mode_sel[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .pad_gpio_vtrip_sel(mprj_io_vtrip_sel[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .pad_gpio_slow_sel(mprj_io_slow_sel[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .pad_gpio_holdover(mprj_io_holdover[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .pad_gpio_ana_en(mprj_io_analog_en[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .pad_gpio_ana_sel(mprj_io_analog_sel[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .pad_gpio_ana_pol(mprj_io_analog_pol[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .pad_gpio_dm(mprj_io_dm[(`MPRJ_IO_PADS*3-1):(`MPRJ_IO_PADS*3-6)]), - .pad_gpio_outenb(mprj_io_oeb[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .pad_gpio_out(mprj_io_out[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .pad_gpio_in(mprj_io_in[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]) + .pad_gpio_inenb(mprj_io_inp_dis[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .pad_gpio_ib_mode_sel(mprj_io_ib_mode_sel[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .pad_gpio_vtrip_sel(mprj_io_vtrip_sel[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .pad_gpio_slow_sel(mprj_io_slow_sel[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .pad_gpio_holdover(mprj_io_holdover[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .pad_gpio_ana_en(mprj_io_analog_en[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .pad_gpio_ana_sel(mprj_io_analog_sel[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .pad_gpio_ana_pol(mprj_io_analog_pol[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .pad_gpio_dm(mprj_io_dm[(`MPRJ_IO_PADS*3-1):(`MPRJ_IO_PADS*3-9)]), + .pad_gpio_outenb(mprj_io_oeb[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .pad_gpio_out(mprj_io_out[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]), + .pad_gpio_in(mprj_io_in[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-3)]) ); - /* Section 2 GPIOs (GPIO 19 to 37) */ - wire [`MPRJ_IO_PADS_2-3:0] one_loop2; - gpio_control_block gpio_control_in_2 [`MPRJ_IO_PADS_2-3:0] ( + /* Section 2 GPIOs (GPIO 19 to 34) */ + wire [`MPRJ_IO_PADS_2-4:0] one_loop2; + gpio_control_block gpio_control_in_2 [`MPRJ_IO_PADS_2-4:0] ( `ifdef USE_POWER_PINS .vccd(vccd_core), .vssd(vssd_core), @@ -956,41 +962,41 @@ module caravel ( // Management Soc-facing signals - .resetn(gpio_resetn_1_shifted[(`MPRJ_IO_PADS_2-3):0]), - .serial_clock(gpio_clock_1_shifted[(`MPRJ_IO_PADS_2-3):0]), + .resetn(gpio_resetn_1_shifted[(`MPRJ_IO_PADS_2-4):0]), + .serial_clock(gpio_clock_1_shifted[(`MPRJ_IO_PADS_2-4):0]), - .resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_2-3):0]), - .serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_2-3):0]), + .resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_2-4):0]), + .serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_2-4):0]), - .mgmt_gpio_in(mgmt_io_in[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .mgmt_gpio_out(mgmt_io_in[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), + .mgmt_gpio_in(mgmt_io_in[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .mgmt_gpio_out(mgmt_io_in[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), .mgmt_gpio_oeb(one_loop2), .one(one_loop2), .zero(), // Serial data chain for pad configuration - .serial_data_in(gpio_serial_link_2_shifted[(`MPRJ_IO_PADS_2-3):0]), - .serial_data_out(gpio_serial_link_2[(`MPRJ_IO_PADS_2-3):0]), + .serial_data_in(gpio_serial_link_2_shifted[(`MPRJ_IO_PADS_2-4):0]), + .serial_data_out(gpio_serial_link_2[(`MPRJ_IO_PADS_2-4):0]), // User-facing signals - .user_gpio_out(user_io_out[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .user_gpio_oeb(user_io_oeb[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .user_gpio_in(user_io_in[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), + .user_gpio_out(user_io_out[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .user_gpio_oeb(user_io_oeb[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .user_gpio_in(user_io_in[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), // Pad-facing signals (Pad GPIOv2) - .pad_gpio_inenb(mprj_io_inp_dis[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .pad_gpio_ib_mode_sel(mprj_io_ib_mode_sel[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .pad_gpio_vtrip_sel(mprj_io_vtrip_sel[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .pad_gpio_slow_sel(mprj_io_slow_sel[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .pad_gpio_holdover(mprj_io_holdover[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .pad_gpio_ana_en(mprj_io_analog_en[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .pad_gpio_ana_sel(mprj_io_analog_sel[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .pad_gpio_ana_pol(mprj_io_analog_pol[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .pad_gpio_dm(mprj_io_dm[(`MPRJ_IO_PADS*3-7):(`MPRJ_IO_PADS_1*3)]), - .pad_gpio_outenb(mprj_io_oeb[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .pad_gpio_out(mprj_io_out[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]), - .pad_gpio_in(mprj_io_in[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]) + .pad_gpio_inenb(mprj_io_inp_dis[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .pad_gpio_ib_mode_sel(mprj_io_ib_mode_sel[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .pad_gpio_vtrip_sel(mprj_io_vtrip_sel[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .pad_gpio_slow_sel(mprj_io_slow_sel[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .pad_gpio_holdover(mprj_io_holdover[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .pad_gpio_ana_en(mprj_io_analog_en[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .pad_gpio_ana_sel(mprj_io_analog_sel[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .pad_gpio_ana_pol(mprj_io_analog_pol[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .pad_gpio_dm(mprj_io_dm[(`MPRJ_IO_PADS*3-10):(`MPRJ_IO_PADS_1*3)]), + .pad_gpio_outenb(mprj_io_oeb[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .pad_gpio_out(mprj_io_out[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]), + .pad_gpio_in(mprj_io_in[(`MPRJ_IO_PADS-4):(`MPRJ_IO_PADS_1)]) ); user_id_programming #( diff --git a/verilog/rtl/housekeeping.v b/verilog/rtl/housekeeping.v index f0c3b544..92e0756c 100644 --- a/verilog/rtl/housekeeping.v +++ b/verilog/rtl/housekeeping.v @@ -104,6 +104,7 @@ module housekeeping #( input spi_csb, input spi_sck, input spi_sdo, + input spi_sdoenb, // External (originating from SPI and pad) IRQ and reset output [2:0] irq, @@ -258,12 +259,12 @@ module housekeeping #( assign reset = (pass_thru_mgmt_reset) ? 1'b1 : reset_reg; // Handle the management-side control of the GPIO pins. All but the - // first and last two GPIOs (0, 1 and 36, 37) are one-pin interfaces with + // first and last three GPIOs (0, 1 and 35 to 37) are one-pin interfaces with // a single I/O pin whose direction is determined by the local OEB signal. - // The other four are straight-through connections of the 3-wire interface. + // The other five are straight-through connections of the 3-wire interface. - assign mgmt_gpio_out[`MPRJ_IO_PADS-1:`MPRJ_IO_PADS-2] = - mgmt_gpio_out_pre[`MPRJ_IO_PADS-1:`MPRJ_IO_PADS-2]; + assign mgmt_gpio_out[`MPRJ_IO_PADS-1:`MPRJ_IO_PADS-3] = + mgmt_gpio_out_pre[`MPRJ_IO_PADS-1:`MPRJ_IO_PADS-3]; assign mgmt_gpio_out[1:0] = mgmt_gpio_out_pre[1:0]; genvar i; @@ -272,7 +273,7 @@ module housekeeping #( // the first and last two GPIOs so that these pins can be tied together // at the top level to create the single-wire interface on those GPIOs. generate - for (i = 2; i < `MPRJ_IO_PADS-2; i = i + 1) begin + for (i = 2; i < `MPRJ_IO_PADS-3; i = i + 1) begin assign mgmt_gpio_out[i] = mgmt_gpio_oeb[i] ? 1'bz : mgmt_gpio_out_pre[i]; end endgenerate @@ -718,7 +719,7 @@ module housekeeping #( .reset(~porb), .SCK(mgmt_gpio_in[4]), .SDI(mgmt_gpio_in[2]), - .CSB((hkspi_disable) ? 1'b1 : mgmt_gpio_in[3]), + .CSB((spi_is_active) ? mgmt_gpio_in[3] : 1'b1), .SDO(sdo), .sdoenb(sdo_enb), .idata(odata), @@ -750,8 +751,21 @@ module housekeeping #( ~gpio_configure[37][INP_DIS]; assign mgmt_gpio_oeb[36] = (qspi_enabled) ? spimemio_flash_io2_oeb : ~gpio_configure[36][INP_DIS]; + assign mgmt_gpio_oeb[35] = (spi_enabled) ? spi_sdoenb : + ~gpio_configure[35][INP_DIS]; - assign mgmt_gpio_out_pre[35:16] = mgmt_gpio_data[35:16]; + // NOTE: Ignored by spimemio module when QSPI disabled, so they do not + // need any exception when qspi_enabled == 1. + assign spimemio_flash_io3_di = mgmt_gpio_in[37]; + assign spimemio_flash_io2_di = mgmt_gpio_in[36]; + + // SPI master is assigned to the other 4 bits of the data high word. + assign mgmt_gpio_out_pre[32] = (spi_enabled) ? spi_sck : mgmt_gpio_data[32]; + assign mgmt_gpio_out_pre[33] = (spi_enabled) ? spi_csb : mgmt_gpio_data[33]; + assign mgmt_gpio_out_pre[34] = mgmt_gpio_data[34]; + assign mgmt_gpio_out_pre[35] = (spi_enabled) ? spi_sdo : mgmt_gpio_data[35]; + + assign mgmt_gpio_out_pre[31:16] = mgmt_gpio_data[31:16]; assign mgmt_gpio_out_pre[12:11] = mgmt_gpio_data[12:11]; assign mgmt_gpio_out_pre[10] = (pass_thru_user) ? mgmt_gpio_in[2] @@ -763,30 +777,26 @@ module housekeeping #( assign mgmt_gpio_out_pre[7] = mgmt_gpio_data[7]; assign mgmt_gpio_out_pre[6] = (uart_enabled) ? ser_tx : mgmt_gpio_data[6]; - assign mgmt_gpio_out_pre[5] = mgmt_gpio_data[5]; - - assign mgmt_gpio_out_pre[4] = (spi_enabled) ? spi_sck : mgmt_gpio_data[4]; - assign mgmt_gpio_out_pre[3] = (spi_enabled) ? spi_csb : mgmt_gpio_data[3]; - assign mgmt_gpio_out_pre[2] = (spi_enabled) ? spi_sdo : mgmt_gpio_data[2]; + assign mgmt_gpio_out_pre[5:2] = mgmt_gpio_data[5:2]; // In pass-through modes, route SDO from the respective flash (user or // management SoC) to the dedicated SDO pin (GPIO[1]) assign mgmt_gpio_out_pre[1] = (pass_thru_mgmt) ? pad_flash_io1_di : (pass_thru_user) ? mgmt_gpio_in[11] : - (spi_enabled) ? sdo : mgmt_gpio_data[1]; + (spi_is_active) ? sdo : mgmt_gpio_data[1]; assign mgmt_gpio_out_pre[0] = (debug_mode) ? debug_out : mgmt_gpio_data[0]; - assign mgmt_gpio_oeb[1] = (spi_enabled) ? sdo_enb : ~gpio_configure[0][INP_DIS]; + assign mgmt_gpio_oeb[1] = (spi_is_active) ? sdo_enb : ~gpio_configure[0][INP_DIS]; assign mgmt_gpio_oeb[0] = (debug_mode) ? debug_oeb : ~gpio_configure[0][INP_DIS]; assign ser_rx = (uart_enabled) ? mgmt_gpio_in[5] : 1'b0; - assign spi_sdi = (spi_enabled) ? mgmt_gpio_in[1] : 1'b0; + assign spi_sdi = (spi_enabled) ? mgmt_gpio_in[34] : 1'b0; assign debug_in = (debug_mode) ? mgmt_gpio_in[0] : 1'b0; /* These are disconnected, but apply a meaningful signal anyway */ generate - for (i = 2; i < `MPRJ_IO_PADS-2; i = i + 1) begin + for (i = 2; i < `MPRJ_IO_PADS-3; i = i + 1) begin assign mgmt_gpio_oeb[i] = ~gpio_configure[i][INP_DIS]; end endgenerate