From bdfa747145eda104475698eebfc3ffcae55f52bb Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 15 Oct 2021 21:49:49 -0400 Subject: [PATCH] First major update; current code passes syntax checks in iverilog and simulates, but fails testbench (not surprising at this stage). --- doc/memory_map.txt | 110 ++ verilog/dv/caravel/defs.h | 217 ++++ verilog/dv/caravel/mgmt_soc/gpio/Makefile | 86 ++ verilog/dv/caravel/mgmt_soc/gpio/README | 44 + verilog/dv/caravel/mgmt_soc/gpio/gpio.c | 115 ++ verilog/dv/caravel/mgmt_soc/gpio/gpio_tb.v | 200 ++++ verilog/dv/caravel/sections.lds | 75 ++ verilog/dv/caravel/spiflash.v | 447 +++++++ verilog/dv/caravel/start.s | 174 +++ verilog/rtl/caravel.v | 395 ++++--- verilog/rtl/caravel_netlists.v | 32 +- verilog/rtl/housekeeping.v | 1237 ++++++++++++++++++++ verilog/rtl/housekeeping_spi.v | 317 +---- verilog/rtl/la_wb.v | 305 ----- verilog/rtl/mprj_ctrl.v | 462 -------- verilog/rtl/sysctrl.v | 180 --- 16 files changed, 2934 insertions(+), 1462 deletions(-) create mode 100644 doc/memory_map.txt create mode 100644 verilog/dv/caravel/defs.h create mode 100644 verilog/dv/caravel/mgmt_soc/gpio/Makefile create mode 100644 verilog/dv/caravel/mgmt_soc/gpio/README create mode 100644 verilog/dv/caravel/mgmt_soc/gpio/gpio.c create mode 100644 verilog/dv/caravel/mgmt_soc/gpio/gpio_tb.v create mode 100644 verilog/dv/caravel/sections.lds create mode 100644 verilog/dv/caravel/spiflash.v create mode 100644 verilog/dv/caravel/start.s create mode 100644 verilog/rtl/housekeeping.v delete mode 100644 verilog/rtl/la_wb.v delete mode 100644 verilog/rtl/mprj_ctrl.v delete mode 100644 verilog/rtl/sysctrl.v diff --git a/doc/memory_map.txt b/doc/memory_map.txt new file mode 100644 index 00000000..6c56f07c --- /dev/null +++ b/doc/memory_map.txt @@ -0,0 +1,110 @@ +Caravel memory map vs. SPI register map +---------------------------------------------------------------------------------- +SPI register description signal memory map address +---------------------------------------------------------------------------------- + 00 SPI status (reserved) (undefined) 2e00_0000 + 01 Manufacturer ID (high) mfgr_id[11:8] 2e00_0006 + 02 Manufacturer ID (low) mfgr_id[7:0] 2e00_0005 + 03 Product ID prod_id[7:0] 2e00_0004 + 04 User project ID mask_rev[31:24] 2e00_000b + 05 User project ID mask_rev[23:16] 2e00_000a + 06 User project ID mask_rev[15:8] 2e00_0009 + 07 User project ID mask_rev[7:0] 2e00_0008 + 08 CPU trap state trap 2e00_000c + 09 Power monitor usr1/2_vcc/vdd_pwrgood 2f00_0000 + 0a Output redirect clk1/clk2/trap_output_dest 2f00_0004 + 0b Input redirect irq_8/7_inputsrc 2f00_000c + 0c GPIO[0] configure gpio_configure[0][12:8] 2600_0025 + 0d GPIO[0] configure gpio_configure[0][7:0] 2600_0024 + 0e GPIO[1] configure gpio_configure[1][12:8] 2600_0029 + 0f GPIO[1] configure gpio_configure[1][7:0] 2600_0028 + 10 GPIO[2] configure gpio_configure[2][12:8] 2600_002d + 11 GPIO[2] configure gpio_configure[2][7:0] 2600_002c + 12 GPIO[3] configure gpio_configure[3][12:8] 2600_0031 + 13 GPIO[3] configure gpio_configure[3][7:0] 2600_0030 + 14 GPIO[4] configure gpio_configure[4][12:8] 2600_0035 + 15 GPIO[4] configure gpio_configure[4][7:0] 2600_0034 + 16 GPIO[5] configure gpio_configure[5][12:8] 2600_0039 + 17 GPIO[5] configure gpio_configure[5][7:0] 2600_0038 + 18 GPIO[6] configure gpio_configure[6][12:8] 2600_003d + 19 GPIO[6] configure gpio_configure[6][7:0] 2600_003c + 1a GPIO[7] configure gpio_configure[7][12:8] 2600_0041 + 1b GPIO[7] configure gpio_configure[7][7:0] 2600_0040 + 1c GPIO[8] configure gpio_configure[8][12:8] 2600_0045 + 1d GPIO[8] configure gpio_configure[8][7:0] 2600_0044 + 1e GPIO[9] configure gpio_configure[9][12:8] 2600_0049 + 1f GPIO[9] configure gpio_configure[9][7:0] 2600_0048 + 20 GPIO[10] configure gpio_configure[10][12:8] 2600_004d + 21 GPIO[10] configure gpio_configure[10][7:0] 2600_004c + 22 GPIO[11] configure gpio_configure[11][12:8] 2600_0051 + 23 GPIO[11] configure gpio_configure[11][7:0] 2600_0050 + 24 GPIO[12] configure gpio_configure[12][12:8] 2600_0055 + 25 GPIO[12] configure gpio_configure[12][7:0] 2600_0054 + 26 GPIO[13] configure gpio_configure[13][12:8] 2600_0059 + 27 GPIO[13] configure gpio_configure[13][7:0] 2600_0058 + 28 GPIO[14] configure gpio_configure[14][12:8] 2600_005d + 29 GPIO[14] configure gpio_configure[14][7:0] 2600_005c + 2a GPIO[15] configure gpio_configure[15][12:8] 2600_0061 + 2b GPIO[15] configure gpio_configure[15][7:0] 2600_0060 + 2c GPIO[16] configure gpio_configure[16][12:8] 2600_0065 + 2d GPIO[16] configure gpio_configure[16][7:0] 2600_0064 + 2e GPIO[17] configure gpio_configure[17][12:8] 2600_0069 + 2f GPIO[17] configure gpio_configure[17][7:0] 2600_0068 + 30 GPIO[18] configure gpio_configure[18][12:8] 2600_006d + 31 GPIO[18] configure gpio_configure[18][7:0] 2600_006c + 32 GPIO[19] configure gpio_configure[19][12:8] 2600_0071 + 33 GPIO[19] configure gpio_configure[19][7:0] 2600_0070 + 34 GPIO[20] configure gpio_configure[20][12:8] 2600_0075 + 35 GPIO[20] configure gpio_configure[20][7:0] 2600_0074 + 36 GPIO[21] configure gpio_configure[21][12:8] 2600_0079 + 37 GPIO[21] configure gpio_configure[21][7:0] 2600_0078 + 38 GPIO[22] configure gpio_configure[22][12:8] 2600_007d + 39 GPIO[22] configure gpio_configure[22][7:0] 2600_007c + 3a GPIO[23] configure gpio_configure[23][12:8] 2600_0081 + 3b GPIO[23] configure gpio_configure[23][7:0] 2600_0080 + 3c GPIO[24] configure gpio_configure[24][12:8] 2600_0085 + 3d GPIO[24] configure gpio_configure[24][7:0] 2600_0084 + 3e GPIO[25] configure gpio_configure[25][12:8] 2600_0089 + 3f GPIO[25] configure gpio_configure[25][7:0] 2600_0088 + 40 GPIO[26] configure gpio_configure[26][12:8] 2600_008d + 41 GPIO[26] configure gpio_configure[26][7:0] 2600_008c + 42 GPIO[27] configure gpio_configure[27][12:8] 2600_0091 + 43 GPIO[27] configure gpio_configure[27][7:0] 2600_0090 + 44 GPIO[28] configure gpio_configure[28][12:8] 2600_0095 + 45 GPIO[28] configure gpio_configure[28][7:0] 2600_0094 + 46 GPIO[29] configure gpio_configure[29][12:8] 2600_0099 + 47 GPIO[29] configure gpio_configure[29][7:0] 2600_0098 + 48 GPIO[30] configure gpio_configure[30][12:8] 2600_009d + 49 GPIO[30] configure gpio_configure[30][7:0] 2600_009c + 4a GPIO[31] configure gpio_configure[31][12:8] 2600_00a1 + 4b GPIO[31] configure gpio_configure[31][7:0] 2600_00a0 + 4c GPIO[32] configure gpio_configure[32][12:8] 2600_00a5 + 4d GPIO[32] configure gpio_configure[32][7:0] 2600_00a4 + 4e GPIO[33] configure gpio_configure[33][12:8] 2600_00a9 + 4f GPIO[33] configure gpio_configure[33][7:0] 2600_00a8 + 50 GPIO[34] configure gpio_configure[34][12:8] 2600_00ad + 51 GPIO[34] configure gpio_configure[34][7:0] 2600_00ac + 52 GPIO[35] configure gpio_configure[35][12:8] 2600_00b1 + 53 GPIO[35] configure gpio_configure[35][7:0] 2600_00b0 + 54 GPIO[36] configure gpio_configure[36][12:8] 2600_00b5 + 55 GPIO[36] configure gpio_configure[36][7:0] 2600_00b4 + 56 GPIO[37] configure gpio_configure[37][12:8] 2600_00b9 + 57 GPIO[37] configure gpio_configure[37][7:0] 2600_00b8 + 58 GPIO data mgmt_gpio_in[37:32] 2600_0010 + 59 GPIO data mgmt_gpio_in[31:24] 2600_000f + 5a GPIO data mgmt_gpio_in[23:16] 2600_000e + 5b GPIO data mgmt_gpio_in[15:8] 2600_000d + 5c GPIO data mgmt_gpio_in[7:0] 2600_000c + 5d Power control pwr_ctrl_out[3:0] 2600_0004 + 5e GPIO control serial_resetn/clock/data 2600_0000 + 5f PLL enables pll_dco_ena, pll_ena 2e00_000c + 60 PLL bypass pll_bypass 2e00_0010 + 61 IRQ irq 2e00_0014 + 62 Reset reset 2e00_0018 + 63 PLL trim pll_trim[31:24] 2e00_001f + 64 PLL trim pll_trim[23:16] 2e00_001e + 65 PLL trim pll_trim[15:8] 2e00_001d + 66 PLL trim pll_trim[7:0] 2e00_001c + 67 PLL source pll90_sel[2:0], pll_sel[2:0] 2e00_0020 + 68 PLL divider pll_div[4:0] 2e00_0024 +---------------------------------------------------------------------------------- diff --git a/verilog/dv/caravel/defs.h b/verilog/dv/caravel/defs.h new file mode 100644 index 00000000..d43eeaf5 --- /dev/null +++ b/verilog/dv/caravel/defs.h @@ -0,0 +1,217 @@ +/* + * 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 + */ + +#ifndef _CARAVEL_H_ +#define _CARAVEL_H_ + +#include +#include + +// a pointer to this is a null pointer, but the compiler does not +// know that because "sram" is a linker symbol from sections.lds. +extern uint32_t sram; + +// Pointer to firmware flash routines +extern uint32_t flashio_worker_begin; +extern uint32_t flashio_worker_end; + +// Storage area (MGMT: 0x0100_0000, User: 0x0200_0000) +#define reg_rw_block0 (*(volatile uint32_t*)0x01000000) +#define reg_rw_block1 (*(volatile uint32_t*)0x01100000) +#define reg_ro_block0 (*(volatile uint32_t*)0x02000000) + +// UART (0x2000_0000) +#define reg_uart_clkdiv (*(volatile uint32_t*)0x20000000) +#define reg_uart_data (*(volatile uint32_t*)0x20000004) +#define reg_uart_enable (*(volatile uint32_t*)0x20000008) + +// GPIO (0x2100_0000) +#define reg_gpio_data (*(volatile uint32_t*)0x21000000) +#define reg_gpio_ena (*(volatile uint32_t*)0x21000004) +#define reg_gpio_pu (*(volatile uint32_t*)0x21000008) +#define reg_gpio_pd (*(volatile uint32_t*)0x2100000c) + +// Logic Analyzer (0x2200_0000) +#define reg_la0_data (*(volatile uint32_t*)0x25000000) +#define reg_la1_data (*(volatile uint32_t*)0x25000004) +#define reg_la2_data (*(volatile uint32_t*)0x25000008) +#define reg_la3_data (*(volatile uint32_t*)0x2500000c) + +#define reg_la0_oenb (*(volatile uint32_t*)0x25000010) +#define reg_la1_oenb (*(volatile uint32_t*)0x25000014) +#define reg_la2_oenb (*(volatile uint32_t*)0x25000018) +#define reg_la3_oenb (*(volatile uint32_t*)0x2500001c) + +#define reg_la0_iena (*(volatile uint32_t*)0x25000020) +#define reg_la1_iena (*(volatile uint32_t*)0x25000024) +#define reg_la2_iena (*(volatile uint32_t*)0x25000028) +#define reg_la3_iena (*(volatile uint32_t*)0x2500002c) + +#define reg_la_sample (*(volatile uint32_t*)0x25000030) + +// User Project Control (0x2300_0000) +#define reg_mprj_xfer (*(volatile uint32_t*)0x26000000) +#define reg_mprj_pwr (*(volatile uint32_t*)0x26000004) +#define reg_mprj_irq (*(volatile uint32_t*)0x2e000014) +#define reg_mprj_datal (*(volatile uint32_t*)0x2600000c) +#define reg_mprj_datah (*(volatile uint32_t*)0x26000010) + +#define reg_mprj_io_0 (*(volatile uint32_t*)0x26000024) +#define reg_mprj_io_1 (*(volatile uint32_t*)0x26000028) +#define reg_mprj_io_2 (*(volatile uint32_t*)0x2600002c) +#define reg_mprj_io_3 (*(volatile uint32_t*)0x26000030) +#define reg_mprj_io_4 (*(volatile uint32_t*)0x26000034) +#define reg_mprj_io_5 (*(volatile uint32_t*)0x26000038) +#define reg_mprj_io_6 (*(volatile uint32_t*)0x2600003c) + +#define reg_mprj_io_7 (*(volatile uint32_t*)0x26000040) +#define reg_mprj_io_8 (*(volatile uint32_t*)0x26000044) +#define reg_mprj_io_9 (*(volatile uint32_t*)0x26000048) +#define reg_mprj_io_10 (*(volatile uint32_t*)0x2600004c) + +#define reg_mprj_io_11 (*(volatile uint32_t*)0x26000050) +#define reg_mprj_io_12 (*(volatile uint32_t*)0x26000054) +#define reg_mprj_io_13 (*(volatile uint32_t*)0x26000058) +#define reg_mprj_io_14 (*(volatile uint32_t*)0x2600005c) + +#define reg_mprj_io_15 (*(volatile uint32_t*)0x26000060) +#define reg_mprj_io_16 (*(volatile uint32_t*)0x26000064) +#define reg_mprj_io_17 (*(volatile uint32_t*)0x26000068) +#define reg_mprj_io_18 (*(volatile uint32_t*)0x2600006c) + +#define reg_mprj_io_19 (*(volatile uint32_t*)0x26000070) +#define reg_mprj_io_20 (*(volatile uint32_t*)0x26000074) +#define reg_mprj_io_21 (*(volatile uint32_t*)0x26000078) +#define reg_mprj_io_22 (*(volatile uint32_t*)0x2600007c) + +#define reg_mprj_io_23 (*(volatile uint32_t*)0x26000080) +#define reg_mprj_io_24 (*(volatile uint32_t*)0x26000084) +#define reg_mprj_io_25 (*(volatile uint32_t*)0x26000088) +#define reg_mprj_io_26 (*(volatile uint32_t*)0x2600008c) + +#define reg_mprj_io_27 (*(volatile uint32_t*)0x26000090) +#define reg_mprj_io_28 (*(volatile uint32_t*)0x26000094) +#define reg_mprj_io_29 (*(volatile uint32_t*)0x26000098) +#define reg_mprj_io_30 (*(volatile uint32_t*)0x2600009c) +#define reg_mprj_io_31 (*(volatile uint32_t*)0x260000a0) + +#define reg_mprj_io_32 (*(volatile uint32_t*)0x260000a4) +#define reg_mprj_io_33 (*(volatile uint32_t*)0x260000a8) +#define reg_mprj_io_34 (*(volatile uint32_t*)0x260000ac) +#define reg_mprj_io_35 (*(volatile uint32_t*)0x260000b0) +#define reg_mprj_io_36 (*(volatile uint32_t*)0x260000b4) +#define reg_mprj_io_37 (*(volatile uint32_t*)0x260000b8) + +// User Project Slaves (0x3000_0000) +#define reg_mprj_slave (*(volatile uint32_t*)0x30000000) + +// Flash Control SPI Configuration (2D00_0000) +#define reg_spictrl (*(volatile uint32_t*)0x2d000000) + +// Bit fields for Flash SPI control +#define FLASH_BITBANG_IO0 0x00000001 +#define FLASH_BITBANG_IO1 0x00000002 +#define FLASH_BITBANG_CLK 0x00000010 +#define FLASH_BITBANG_CSB 0x00000020 +#define FLASH_BITBANG_OEB0 0x00000100 +#define FLASH_BITBANG_OEB1 0x00000200 +#define FLASH_ENABLE 0x80000000 + +// Counter-Timer 0 Configuration +#define reg_timer0_config (*(volatile uint32_t*)0x22000000) +#define reg_timer0_value (*(volatile uint32_t*)0x22000004) +#define reg_timer0_data (*(volatile uint32_t*)0x22000008) + +// Counter-Timer 1 Configuration +#define reg_timer1_config (*(volatile uint32_t*)0x23000000) +#define reg_timer1_value (*(volatile uint32_t*)0x23000004) +#define reg_timer1_data (*(volatile uint32_t*)0x23000008) + +// Bit fields for Counter-timer configuration +#define TIMER_ENABLE 0x01 +#define TIMER_ONESHOT 0x02 +#define TIMER_UPCOUNT 0x04 +#define TIMER_CHAIN 0x08 +#define TIMER_IRQ_ENABLE 0x10 + +// SPI Master Configuration +#define reg_spimaster_config (*(volatile uint32_t*)0x24000000) +#define reg_spimaster_data (*(volatile uint32_t*)0x24000004) + +// Bit fields for SPI master configuration +#define SPI_MASTER_DIV_MASK 0x00ff +#define SPI_MASTER_MLB 0x0100 +#define SPI_MASTER_INV_CSB 0x0200 +#define SPI_MASTER_INV_CLK 0x0400 +#define SPI_MASTER_MODE_1 0x0800 +#define SPI_MASTER_STREAM 0x1000 +#define SPI_MASTER_ENABLE 0x2000 +#define SPI_MASTER_IRQ_ENABLE 0x4000 +#define SPI_HOUSEKEEPING_CONN 0x8000 + +// System Area (0x2F00_0000) +#define reg_power_good (*(volatile uint32_t*)0x2F000000) +#define reg_clk_out_dest (*(volatile uint32_t*)0x2F000004) +#define reg_trap_out_dest (*(volatile uint32_t*)0x2F000004) +#define reg_irq_source (*(volatile uint32_t*)0x2F00000C) + +// Bit fields for reg_power_good +#define USER1_VCCD_POWER_GOOD 0x01 +#define USER2_VCCD_POWER_GOOD 0x02 +#define USER1_VDDA_POWER_GOOD 0x04 +#define USER2_VDDA_POWER_GOOD 0x08 + +// Bit fields for reg_clk_out_dest +#define CLOCK1_MONITOR 0x01 +#define CLOCK2_MONITOR 0x02 +#define TRAP_MONITOR 0x04 + +// Bit fields for reg_irq_source +#define IRQ7_SOURCE 0x01 +#define IRQ8_SOURCE 0x02 + +// Individual bit fields for the GPIO pad control +#define MGMT_ENABLE 0x0001 +#define OUTPUT_DISABLE 0x0002 +#define HOLD_OVERRIDE 0x0004 +#define INPUT_DISABLE 0x0008 +#define MODE_SELECT 0x0010 +#define ANALOG_ENABLE 0x0020 +#define ANALOG_SELECT 0x0040 +#define ANALOG_POLARITY 0x0080 +#define SLOW_SLEW_MODE 0x0100 +#define TRIPPOINT_SEL 0x0200 +#define DIGITAL_MODE_MASK 0x1c00 + +// Useful GPIO mode values +#define GPIO_MODE_MGMT_STD_INPUT_NOPULL 0x0403 +#define GPIO_MODE_MGMT_STD_INPUT_PULLDOWN 0x0803 +#define GPIO_MODE_MGMT_STD_INPUT_PULLUP 0x0c03 +#define GPIO_MODE_MGMT_STD_OUTPUT 0x1809 +#define GPIO_MODE_MGMT_STD_BIDIRECTIONAL 0x1801 +#define GPIO_MODE_MGMT_STD_ANALOG 0x000b + +#define GPIO_MODE_USER_STD_INPUT_NOPULL 0x0402 +#define GPIO_MODE_USER_STD_INPUT_PULLDOWN 0x0802 +#define GPIO_MODE_USER_STD_INPUT_PULLUP 0x0c02 +#define GPIO_MODE_USER_STD_OUTPUT 0x1808 +#define GPIO_MODE_USER_STD_BIDIRECTIONAL 0x1800 +#define GPIO_MODE_USER_STD_OUT_MONITORED 0x1802 +#define GPIO_MODE_USER_STD_ANALOG 0x000a + +// -------------------------------------------------------- +#endif diff --git a/verilog/dv/caravel/mgmt_soc/gpio/Makefile b/verilog/dv/caravel/mgmt_soc/gpio/Makefile new file mode 100644 index 00000000..35229bba --- /dev/null +++ b/verilog/dv/caravel/mgmt_soc/gpio/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 = gpio + +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/gpio/README b/verilog/dv/caravel/mgmt_soc/gpio/README new file mode 100644 index 00000000..baadc1f6 --- /dev/null +++ b/verilog/dv/caravel/mgmt_soc/gpio/README @@ -0,0 +1,44 @@ + +------------------------------------------------ +Caravel +gpio testbench +------------------------------------------------ + +This testbench exercises the fundamental use of the Caravel +management SoC to drive the I/O in the user area as general +purpose I/O on startup. + +On startup, all GPIO are configured as input to the management +region (so as to be high impedence to the external world) and +decoupled from the user project area. + +To configure any GPIO as output, the appropriate memory-mapped +location for the I/O must be properly configured. Since the +I/O configuration is stored in two places, in the SoC, but +also locally at each I/O pad, the "transfer" bit must be +applied, which initiates a transfer of the configuration data +around the padframe. + +The testbench takes 16 pins from the user area and checks +functionality by applying input values on 8 of these pins from +the testbench verilog, detecting them in the C program, then +copying the values to the other 8 pins, and detecting those +values in the testbench verilog. + +If any of that does not work, then the testbench will fail. diff --git a/verilog/dv/caravel/mgmt_soc/gpio/gpio.c b/verilog/dv/caravel/mgmt_soc/gpio/gpio.c new file mode 100644 index 00000000..73dd397e --- /dev/null +++ b/verilog/dv/caravel/mgmt_soc/gpio/gpio.c @@ -0,0 +1,115 @@ +/* + * 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" + +// -------------------------------------------------------- + +/* + * GPIO Test + * Tests PU and PD on the lower 8 pins while being driven from outside + * Tests Writing to the upper 8 pins + * Tests reading from the lower 8 pins + */ + +void main() +{ + int i; + + /* Set data out to zero */ + reg_mprj_datal = 0; + + /* Lower 8 pins are input and upper 8 pins are output */ + 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_INPUT_NOPULL; + reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_NOPULL; + reg_mprj_io_21 = GPIO_MODE_MGMT_STD_INPUT_NOPULL; + reg_mprj_io_20 = GPIO_MODE_MGMT_STD_INPUT_NOPULL; + reg_mprj_io_19 = GPIO_MODE_MGMT_STD_INPUT_NOPULL; + reg_mprj_io_18 = GPIO_MODE_MGMT_STD_INPUT_NOPULL; + reg_mprj_io_17 = GPIO_MODE_MGMT_STD_INPUT_NOPULL; + reg_mprj_io_16 = GPIO_MODE_MGMT_STD_INPUT_NOPULL; + + /* Apply configuration */ + reg_mprj_xfer = 1; + while (reg_mprj_xfer == 1); + + // change the pull up and pull down (checked by the TB) + reg_mprj_datal = 0xa0000000; + + reg_mprj_io_23 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; + reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; + reg_mprj_io_21 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; + reg_mprj_io_20 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; + + reg_mprj_io_19 = GPIO_MODE_MGMT_STD_INPUT_PULLUP; + reg_mprj_io_18 = GPIO_MODE_MGMT_STD_INPUT_PULLUP; + reg_mprj_io_17 = GPIO_MODE_MGMT_STD_INPUT_PULLUP; + reg_mprj_io_16 = GPIO_MODE_MGMT_STD_INPUT_PULLUP; + + /* Apply configuration */ + reg_mprj_xfer = 1; + while (reg_mprj_xfer == 1); + + reg_mprj_datal = 0x0b000000; + + reg_mprj_io_23 = GPIO_MODE_MGMT_STD_INPUT_PULLUP; + reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_PULLUP; + reg_mprj_io_21 = GPIO_MODE_MGMT_STD_INPUT_PULLUP; + reg_mprj_io_20 = GPIO_MODE_MGMT_STD_INPUT_PULLUP; + + reg_mprj_io_19 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; + reg_mprj_io_18 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; + reg_mprj_io_17 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; + reg_mprj_io_16 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; + + /* Apply configuration */ + reg_mprj_xfer = 1; + while (reg_mprj_xfer == 1); + + reg_mprj_io_23 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; + reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; + reg_mprj_io_21 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; + reg_mprj_io_20 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN; + + reg_mprj_io_19 = GPIO_MODE_MGMT_STD_INPUT_PULLUP; + reg_mprj_io_18 = GPIO_MODE_MGMT_STD_INPUT_PULLUP; + reg_mprj_io_17 = GPIO_MODE_MGMT_STD_INPUT_PULLUP; + reg_mprj_io_16 = GPIO_MODE_MGMT_STD_INPUT_PULLUP; + + /* Apply configuration */ + reg_mprj_xfer = 1; + while (reg_mprj_xfer == 1); + + // read the lower 8 pins, add 1 then output the result + // checked by the TB + reg_mprj_datal = 0xab000000; + + while (1){ + int x = (reg_mprj_datal & 0xff0000) >> 16; + reg_mprj_datal = (x+1) << 24; + } +} + diff --git a/verilog/dv/caravel/mgmt_soc/gpio/gpio_tb.v b/verilog/dv/caravel/mgmt_soc/gpio/gpio_tb.v new file mode 100644 index 00000000..e475b864 --- /dev/null +++ b/verilog/dv/caravel/mgmt_soc/gpio/gpio_tb.v @@ -0,0 +1,200 @@ +`default_nettype none +/* + * SPDX-FileCopyrightText: 2017 Clifford Wolf, 2018 Tim Edwards + * + * StriVe - A full example SoC using PicoRV32 in SkyWater s8 + * + * Copyright (C) 2017 Clifford Wolf + * Copyright (C) 2018 Tim Edwards + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * SPDX-License-Identifier: ISC + */ + +`timescale 1 ns / 1 ps + +`include "__uprj_netlists.v" +`include "caravel_netlists.v" +`include "spiflash.v" + +// NOTE: Temporary location of management SoC wrapper is a symbolic link +// to the caravel_pico repository verilog/rtl/mgmt_core_wrapper.v +`include "mgmt_core_wrapper.v" + +module gpio_tb; + + reg clock; + reg power1; + reg power2; + + always #10 clock <= (clock === 1'b0); + + initial begin + clock <= 0; + end + + initial begin + $dumpfile("gpio.vcd"); + $dumpvars(0, gpio_tb); + + // Repeat cycles of 1000 clock edges as needed to complete testbench + repeat (25) begin + repeat (1000) @(posedge clock); + $display("+1000 cycles"); + end + $display("%c[1;31m",27); + `ifdef GL + $display ("Monitor: Timeout, Test GPIO (GL) Failed"); + `else + $display ("Monitor: Timeout, Test GPIO (RTL) Failed"); + `endif + $display("%c[0m",27); + $finish; + end + + wire [37:0] mprj_io; // Most of these are no-connects + wire [15:0] checkbits; + reg [7:0] checkbits_lo; + wire [7:0] checkbits_hi; + + assign mprj_io[23:16] = checkbits_lo; + assign checkbits = mprj_io[31:16]; + assign checkbits_hi = checkbits[15:8]; + assign mprj_io[3] = 1'b1; // Force CSB high. + + wire flash_csb; + wire flash_clk; + wire flash_io0; + wire flash_io1; + wire gpio; + + reg RSTB; + + // Transactor + initial begin + checkbits_lo <= {8{1'bz}}; + wait(checkbits_hi == 8'hA0); + checkbits_lo <= 8'hF0; + wait(checkbits_hi == 8'h0B); + checkbits_lo <= 8'h0F; + wait(checkbits_hi == 8'hAB); + checkbits_lo <= 8'h0; + repeat (1000) @(posedge clock); + checkbits_lo <= 8'h1; + repeat (1000) @(posedge clock); + checkbits_lo <= 8'h3; + end + + // Monitor + initial begin + wait(checkbits_hi == 8'hA0); + wait(checkbits[7:0] == 8'hF0); + wait(checkbits_hi == 8'h0B); + wait(checkbits[7:0] == 8'h0F); + wait(checkbits_hi == 8'hAB); + wait(checkbits[7:0] == 8'h00); + wait(checkbits_hi == 8'h01); + wait(checkbits[7:0] == 8'h01); + wait(checkbits_hi == 8'h02); + wait(checkbits[7:0] == 8'h03); + wait(checkbits_hi == 8'h04); + `ifdef GL + $display("Monitor: Test GPIO (GL) Passed"); + `else + $display("Monitor: Test GPIO (RTL) Passed"); + `endif + $finish; + end + + initial begin + RSTB <= 1'b0; + + #1000; + RSTB <= 1'b1; // Release reset + #2000; + end + + initial begin // Power-up + power1 <= 1'b0; + power2 <= 1'b0; + #200; + power1 <= 1'b1; + #200; + power2 <= 1'b1; + end + + + always @(checkbits) begin + #1 $display("GPIO state = %b (%d - %d)", checkbits, + checkbits_hi, checkbits_lo); + end + + wire VDD3V3; + wire VDD1V8; + wire VSS; + + assign VDD3V3 = power1; + assign VDD1V8 = power2; + assign VSS = 1'b0; + + // These are the mappings of mprj_io GPIO pads that are set to + // specific functions on startup: + // + // JTAG = mgmt_gpio_io[0] (inout) + // SDO = mgmt_gpio_io[1] (output) + // SDI = mgmt_gpio_io[2] (input) + // CSB = mgmt_gpio_io[3] (input) + // SCK = mgmt_gpio_io[4] (input) + // ser_rx = mgmt_gpio_io[5] (input) + // ser_tx = mgmt_gpio_io[6] (output) + // irq = mgmt_gpio_io[7] (input) + + 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("gpio.hex") + ) spiflash ( + .csb(flash_csb), + .clk(flash_clk), + .io0(flash_io0), + .io1(flash_io1), + .io2(), // not used + .io3() // not used + ); + +endmodule +`default_nettype wire diff --git a/verilog/dv/caravel/sections.lds b/verilog/dv/caravel/sections.lds new file mode 100644 index 00000000..2d8c048d --- /dev/null +++ b/verilog/dv/caravel/sections.lds @@ -0,0 +1,75 @@ +/* +# 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 +*/ + +MEMORY { + FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 0x400000 /* 4MB */ + RAM(xrw) : ORIGIN = 0x00000000, LENGTH = 0x0400 /* 256 words (1 KB) */ +} + +SECTIONS { + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + *(.srodata) /* .srodata sections (constants, strings, etc.) */ + *(.srodata*) /* .srodata*sections (constants, strings, etc.) */ + . = ALIGN(4); + _etext = .; /* define a global symbol at end of code */ + _sidata = _etext; /* This is used by the startup to initialize data */ + } >FLASH + + /* Initialized data section */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; + _ram_start = .; + . = ALIGN(4); + *(.data) + *(.data*) + *(.sdata) + *(.sdata*) + . = ALIGN(4); + _edata = .; + } >RAM + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss) + *(.bss*) + *(.sbss) + *(.sbss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; + } >RAM + + /* Define the start of the heap */ + .heap : + { + . = ALIGN(4); + _heap_start = .; + } >RAM +} diff --git a/verilog/dv/caravel/spiflash.v b/verilog/dv/caravel/spiflash.v new file mode 100644 index 00000000..6aa29baa --- /dev/null +++ b/verilog/dv/caravel/spiflash.v @@ -0,0 +1,447 @@ +`default_nettype none +/* + * SPDX-FileCopyrightText: 2017 Clifford Wolf + * + * PicoSoC - A simple example SoC using PicoRV32 + * + * Copyright (C) 2017 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * SPDX-License-Identifier: ISC + */ + +`timescale 1 ns / 1 ps + +// +// Simple SPI flash simulation model +// +// This model samples io input signals 1ns before the SPI clock edge and +// updates output signals 1ns after the SPI clock edge. +// +// Supported commands: +// AB, B9, FF, 03, BB, EB, ED +// +// Well written SPI flash data sheets: +// Cypress S25FL064L http://www.cypress.com/file/316661/download +// Cypress S25FL128L http://www.cypress.com/file/316171/download +// + +module spiflash #( + parameter FILENAME = "firmware.hex" +)( + input csb, + input clk, + inout io0, // MOSI + inout io1, // MISO + inout io2, + inout io3 +); + localparam verbose = 0; + localparam integer latency = 8; + + reg [7:0] buffer; + reg [3:0] reset_count = 0; + reg [3:0] reset_monitor = 0; + integer bitcount = 0; + integer bytecount = 0; + integer dummycount = 0; + + reg [7:0] spi_cmd; + reg [7:0] xip_cmd = 0; + reg [23:0] spi_addr; + + reg [7:0] spi_in; + reg [7:0] spi_out; + reg spi_io_vld; + + reg powered_up = 0; + + localparam [3:0] mode_spi = 1; + localparam [3:0] mode_dspi_rd = 2; + localparam [3:0] mode_dspi_wr = 3; + localparam [3:0] mode_qspi_rd = 4; + localparam [3:0] mode_qspi_wr = 5; + localparam [3:0] mode_qspi_ddr_rd = 6; + localparam [3:0] mode_qspi_ddr_wr = 7; + + reg [3:0] mode = 0; + reg [3:0] next_mode = 0; + + reg io0_oe = 0; + reg io1_oe = 0; + reg io2_oe = 0; + reg io3_oe = 0; + + reg io0_dout = 0; + reg io1_dout = 0; + reg io2_dout = 0; + reg io3_dout = 0; + + assign #1 io0 = io0_oe ? io0_dout : 1'bz; + assign #1 io1 = io1_oe ? io1_dout : 1'bz; + assign #1 io2 = io2_oe ? io2_dout : 1'bz; + assign #1 io3 = io3_oe ? io3_dout : 1'bz; + + wire io0_delayed; + wire io1_delayed; + wire io2_delayed; + wire io3_delayed; + + assign #1 io0_delayed = io0; + assign #1 io1_delayed = io1; + assign #1 io2_delayed = io2; + assign #1 io3_delayed = io3; + + // 16 MB (128Mb) Flash + reg [7:0] memory [0:16*1024*1024-1]; + + initial begin + $display("Memory 5 bytes = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", + memory[1048576], memory[1048577], memory[1048578], + memory[1048579], memory[1048580]); + $display("Reading %s", FILENAME); + $readmemh(FILENAME, memory); + $display("%s loaded into memory", FILENAME); + $display("Memory 5 bytes = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", + memory[1048576], memory[1048577], memory[1048578], + memory[1048579], memory[1048580]); + end + + task spi_action; + begin + spi_in = buffer; + + if (bytecount == 1) begin + spi_cmd = buffer; + + if (spi_cmd == 8'h ab) + powered_up = 1; + + if (spi_cmd == 8'h b9) + powered_up = 0; + + if (spi_cmd == 8'h ff) + xip_cmd = 0; + end + + if (powered_up && spi_cmd == 'h 03) begin + if (bytecount == 2) + spi_addr[23:16] = buffer; + + if (bytecount == 3) + spi_addr[15:8] = buffer; + + if (bytecount == 4) + spi_addr[7:0] = buffer; + + if (bytecount >= 4) begin + buffer = memory[spi_addr]; + spi_addr = spi_addr + 1; + end + end + + if (powered_up && spi_cmd == 'h bb) begin + if (bytecount == 1) + mode = mode_dspi_rd; + + if (bytecount == 2) + spi_addr[23:16] = buffer; + + if (bytecount == 3) + spi_addr[15:8] = buffer; + + if (bytecount == 4) + spi_addr[7:0] = buffer; + + if (bytecount == 5) begin + xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00; + mode = mode_dspi_wr; + dummycount = latency; + end + + if (bytecount >= 5) begin + buffer = memory[spi_addr]; + spi_addr = spi_addr + 1; + end + end + + if (powered_up && spi_cmd == 'h eb) begin + if (bytecount == 1) + mode = mode_qspi_rd; + + if (bytecount == 2) + spi_addr[23:16] = buffer; + + if (bytecount == 3) + spi_addr[15:8] = buffer; + + if (bytecount == 4) + spi_addr[7:0] = buffer; + + if (bytecount == 5) begin + xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00; + mode = mode_qspi_wr; + dummycount = latency; + end + + if (bytecount >= 5) begin + buffer = memory[spi_addr]; + spi_addr = spi_addr + 1; + end + end + + if (powered_up && spi_cmd == 'h ed) begin + if (bytecount == 1) + next_mode = mode_qspi_ddr_rd; + + if (bytecount == 2) + spi_addr[23:16] = buffer; + + if (bytecount == 3) + spi_addr[15:8] = buffer; + + if (bytecount == 4) + spi_addr[7:0] = buffer; + + if (bytecount == 5) begin + xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00; + mode = mode_qspi_ddr_wr; + dummycount = latency; + end + + if (bytecount >= 5) begin + buffer = memory[spi_addr]; + spi_addr = spi_addr + 1; + end + end + + spi_out = buffer; + spi_io_vld = 1; + + if (verbose) begin + if (bytecount == 1) + $write(""); + $write("", spi_in, spi_out); + end + + end + endtask + + task ddr_rd_edge; + begin + buffer = {buffer, io3_delayed, io2_delayed, io1_delayed, io0_delayed}; + bitcount = bitcount + 4; + if (bitcount == 8) begin + bitcount = 0; + bytecount = bytecount + 1; + spi_action; + end + end + endtask + + task ddr_wr_edge; + begin + io0_oe = 1; + io1_oe = 1; + io2_oe = 1; + io3_oe = 1; + + io0_dout = buffer[4]; + io1_dout = buffer[5]; + io2_dout = buffer[6]; + io3_dout = buffer[7]; + + buffer = {buffer, 4'h 0}; + bitcount = bitcount + 4; + if (bitcount == 8) begin + bitcount = 0; + bytecount = bytecount + 1; + spi_action; + end + end + endtask + + always @(csb) begin + if (csb) begin + if (verbose) begin + $display(""); + $fflush; + end + buffer = 0; + bitcount = 0; + bytecount = 0; + mode = mode_spi; + io0_oe = 0; + io1_oe = 0; + io2_oe = 0; + io3_oe = 0; + + // Handle MBR. If in XIP continuous mode, the following + // 8 clock cycles are normally not expected to be a command. + // If followed by CSB high, however, if the address bits + // are consistent with io0 == 1 for 8 clk cycles, then an + // MBR has been issued and the system must exit XIP + // continuous mode. + if (xip_cmd == 8'hbb || xip_cmd == 8'heb + || xip_cmd == 8'hed) begin + if (reset_count == 4'h8 && reset_monitor == 4'h8) begin + xip_cmd = 8'h00; + spi_cmd = 8'h03; + end + end + end else + if (xip_cmd) begin + buffer = xip_cmd; + bitcount = 0; + bytecount = 1; + spi_action; + end + end + + always @(posedge clk or posedge csb) begin + if (csb == 1'b1) begin + reset_count = 0; + reset_monitor = 0; + end else begin + if (reset_count < 4'h9) begin + reset_count = reset_count + 1; + if (io0_delayed == 1'b1) begin + reset_monitor = reset_monitor + 1; + end + end + end + end + + always @(csb, clk) begin + spi_io_vld = 0; + if (!csb && !clk) begin + if (dummycount > 0) begin + io0_oe = 0; + io1_oe = 0; + io2_oe = 0; + io3_oe = 0; + end else + case (mode) + mode_spi: begin + io0_oe = 0; + io1_oe = 1; + io2_oe = 0; + io3_oe = 0; + io1_dout = buffer[7]; + end + mode_dspi_rd: begin + io0_oe = 0; + io1_oe = 0; + io2_oe = 0; + io3_oe = 0; + end + mode_dspi_wr: begin + io0_oe = 1; + io1_oe = 1; + io2_oe = 0; + io3_oe = 0; + io0_dout = buffer[6]; + io1_dout = buffer[7]; + end + mode_qspi_rd: begin + io0_oe = 0; + io1_oe = 0; + io2_oe = 0; + io3_oe = 0; + end + mode_qspi_wr: begin + io0_oe = 1; + io1_oe = 1; + io2_oe = 1; + io3_oe = 1; + io0_dout = buffer[4]; + io1_dout = buffer[5]; + io2_dout = buffer[6]; + io3_dout = buffer[7]; + end + mode_qspi_ddr_rd: begin + ddr_rd_edge; + end + mode_qspi_ddr_wr: begin + ddr_wr_edge; + end + endcase + if (next_mode) begin + case (next_mode) + mode_qspi_ddr_rd: begin + io0_oe = 0; + io1_oe = 0; + io2_oe = 0; + io3_oe = 0; + end + mode_qspi_ddr_wr: begin + io0_oe = 1; + io1_oe = 1; + io2_oe = 1; + io3_oe = 1; + io0_dout = buffer[4]; + io1_dout = buffer[5]; + io2_dout = buffer[6]; + io3_dout = buffer[7]; + end + endcase + mode = next_mode; + next_mode = 0; + end + end + end + + always @(posedge clk) begin + if (!csb) begin + if (dummycount > 0) begin + dummycount = dummycount - 1; + end else + case (mode) + mode_spi: begin + buffer = {buffer, io0}; + bitcount = bitcount + 1; + if (bitcount == 8) begin + bitcount = 0; + bytecount = bytecount + 1; + spi_action; + end + end + mode_dspi_rd, mode_dspi_wr: begin + buffer = {buffer, io1, io0}; + bitcount = bitcount + 2; + if (bitcount == 8) begin + bitcount = 0; + bytecount = bytecount + 1; + spi_action; + end + end + mode_qspi_rd, mode_qspi_wr: begin + buffer = {buffer, io3, io2, io1, io0}; + bitcount = bitcount + 4; + if (bitcount == 8) begin + bitcount = 0; + bytecount = bytecount + 1; + spi_action; + end + end + mode_qspi_ddr_rd: begin + ddr_rd_edge; + end + mode_qspi_ddr_wr: begin + ddr_wr_edge; + end + endcase + end + end +endmodule diff --git a/verilog/dv/caravel/start.s b/verilog/dv/caravel/start.s new file mode 100644 index 00000000..287cba2c --- /dev/null +++ b/verilog/dv/caravel/start.s @@ -0,0 +1,174 @@ +# 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 + +.section .text + +start: + +# zero-initialize register file +addi x1, zero, 0 +# x2 (sp) is initialized by reset +addi x3, zero, 0 +addi x4, zero, 0 +addi x5, zero, 0 +addi x6, zero, 0 +addi x7, zero, 0 +addi x8, zero, 0 +addi x9, zero, 0 +addi x10, zero, 0 +addi x11, zero, 0 +addi x12, zero, 0 +addi x13, zero, 0 +addi x14, zero, 0 +addi x15, zero, 0 +addi x16, zero, 0 +addi x17, zero, 0 +addi x18, zero, 0 +addi x19, zero, 0 +addi x20, zero, 0 +addi x21, zero, 0 +addi x22, zero, 0 +addi x23, zero, 0 +addi x24, zero, 0 +addi x25, zero, 0 +addi x26, zero, 0 +addi x27, zero, 0 +addi x28, zero, 0 +addi x29, zero, 0 +addi x30, zero, 0 +addi x31, zero, 0 + +# zero initialize scratchpad memory +# setmemloop: +# sw zero, 0(x1) +# addi x1, x1, 4 +# blt x1, sp, setmemloop + +# copy data section +la a0, _sidata +la a1, _sdata +la a2, _edata +bge a1, a2, end_init_data +loop_init_data: +lw a3, 0(a0) +sw a3, 0(a1) +addi a0, a0, 4 +addi a1, a1, 4 +blt a1, a2, loop_init_data +end_init_data: + +# zero-init bss section +la a0, _sbss +la a1, _ebss +bge a0, a1, end_init_bss +loop_init_bss: +sw zero, 0(a0) +addi a0, a0, 4 +blt a0, a1, loop_init_bss +end_init_bss: + +# call main +call main +loop: +j loop + +.global flashio_worker_begin +.global flashio_worker_end + +.balign 4 + +flashio_worker_begin: +# a0 ... data pointer +# a1 ... data length +# a2 ... optional WREN cmd (0 = disable) + +# address of SPI ctrl reg +li t0, 0x28000000 + +# Set CS high, IO0 is output +li t1, 0x120 +sh t1, 0(t0) + +# Enable Manual SPI Ctrl +sb zero, 3(t0) + +# Send optional WREN cmd +beqz a2, flashio_worker_L1 +li t5, 8 +andi t2, a2, 0xff +flashio_worker_L4: +srli t4, t2, 7 +sb t4, 0(t0) +ori t4, t4, 0x10 +sb t4, 0(t0) +slli t2, t2, 1 +andi t2, t2, 0xff +addi t5, t5, -1 +bnez t5, flashio_worker_L4 +sb t1, 0(t0) + +# SPI transfer +flashio_worker_L1: + +# If byte count is zero, we're done +beqz a1, flashio_worker_L3 + +# Set t5 to count down 32 bits +li t5, 32 +# Load t2 from address a0 (4 bytes) +lw t2, 0(a0) + +flashio_worker_LY: +# Set t6 to count down 8 bits +li t6, 8 + +flashio_worker_L2: +# Clock out the bit (msb first) on IO0 and read bit in from IO1 +srli t4, t2, 31 +sb t4, 0(t0) +ori t4, t4, 0x10 +sb t4, 0(t0) +lbu t4, 0(t0) +andi t4, t4, 2 +srli t4, t4, 1 +slli t2, t2, 1 +or t2, t2, t4 + +# Decrement 32 bit count +addi t5, t5, -1 +bnez t5, flashio_worker_LX + +sw t2, 0(a0) +addi a0, a0, 4 +lw t2, 0(a0) + +flashio_worker_LX: +addi t6, t6, -1 +bnez t6, flashio_worker_L2 +addi a1, a1, -1 +bnez a1, flashio_worker_LY + +beqz t5, flashio_worker_L3 +sw t2, 0(a0) + +flashio_worker_L3: +# Back to MEMIO mode +li t1, 0x80 +sb t1, 3(t0) + +ret +.balign 4 +flashio_worker_end: + diff --git a/verilog/rtl/caravel.v b/verilog/rtl/caravel.v index bb5bd07f..5b5a4c9f 100644 --- a/verilog/rtl/caravel.v +++ b/verilog/rtl/caravel.v @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // SPDX-License-Identifier: Apache-2.0 + /*--------------------------------------------------------------*/ /* caravel, a project harness for the Google/SkyWater sky130 */ /* fabrication process and open source PDK */ @@ -22,10 +23,17 @@ /* and Mohamed Shalan, August 2020 */ /* This file is open source hardware released under the */ /* Apache 2.0 license. See file LICENSE. */ +/* */ +/* Updated 10/15/2021: Revised using the housekeeping module */ +/* from housekeeping.v (refactoring a number of functions from */ +/* the management SoC). */ /* */ /*--------------------------------------------------------------*/ module caravel ( + + // All top-level I/O are package-facing pins + inout vddio, // Common 3.3V padframe/ESD power inout vddio_2, // Common 3.3V padframe/ESD power inout vssio, // Common padframe/ESD ground @@ -47,7 +55,6 @@ module caravel ( inout gpio, // Used for external LDO control inout [`MPRJ_IO_PADS-1:0] mprj_io, - output [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out, input clock, // CMOS core clock input, not a crystal input resetb, // Reset input (sense inverted) @@ -159,12 +166,10 @@ module caravel ( // ser_tx = mprj_io[6] (output) // irq = mprj_io[7] (input) - wire [`MPRJ_IO_PADS-1:0] mgmt_io_in; - wire jtag_out, sdo_out; - wire jtag_outenb, sdo_outenb; - wire gpio_flash_io2_out, gpio_flash_io3_out; - - wire [1:0] mgmt_io_nc; /* no-connects */ + 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 clock_core; @@ -179,14 +184,28 @@ module caravel ( wire rstb_h; wire rstb_l; + // Flash SPI communication (management SoC to housekeeping) wire flash_clk_core, flash_csb_core; wire flash_clk_oeb_core, flash_csb_oeb_core; wire flash_clk_ieb_core, flash_csb_ieb_core; wire flash_io0_oeb_core, flash_io1_oeb_core; wire flash_io2_oeb_core, flash_io3_oeb_core; wire flash_io0_ieb_core, flash_io1_ieb_core; + wire flash_io2_ieb_core, flash_io3_ieb_core; wire flash_io0_do_core, flash_io1_do_core; + wire flash_io2_do_core, flash_io3_do_core; wire flash_io0_di_core, flash_io1_di_core; + wire flash_io2_di_core, flash_io3_di_core; + + // Flash SPI communication ( + wire flash_clk_frame; + wire flash_csb_frame; + wire flash_clk_oeb, flash_csb_oeb; + wire flash_clk_ieb, flash_csb_ieb; + wire flash_io0_oeb, flash_io1_oeb; + wire flash_io0_ieb, flash_io1_ieb; + wire flash_io0_do, flash_io1_do; + wire flash_io0_di, flash_io1_di; chip_io padframe( `ifndef TOP_ROUTING @@ -245,20 +264,20 @@ module caravel ( .gpio_mode1_core(gpio_mode1_core), .gpio_outenb_core(gpio_outenb_core), .gpio_inenb_core(gpio_inenb_core), - .flash_csb_core(flash_csb_core), - .flash_clk_core(flash_clk_core), - .flash_csb_oeb_core(flash_csb_oeb_core), - .flash_clk_oeb_core(flash_clk_oeb_core), - .flash_io0_oeb_core(flash_io0_oeb_core), - .flash_io1_oeb_core(flash_io1_oeb_core), - .flash_csb_ieb_core(flash_csb_ieb_core), - .flash_clk_ieb_core(flash_clk_ieb_core), - .flash_io0_ieb_core(flash_io0_ieb_core), - .flash_io1_ieb_core(flash_io1_ieb_core), - .flash_io0_do_core(flash_io0_do_core), - .flash_io1_do_core(flash_io1_do_core), - .flash_io0_di_core(flash_io0_di_core), - .flash_io1_di_core(flash_io1_di_core), + .flash_csb_core(flash_csb_frame), + .flash_clk_core(flash_clk_frame), + .flash_csb_oeb_core(flash_csb_oeb), + .flash_clk_oeb_core(flash_clk_oeb), + .flash_io0_oeb_core(flash_io0_oeb), + .flash_io1_oeb_core(flash_io1_oeb), + .flash_csb_ieb_core(flash_csb_ieb), + .flash_clk_ieb_core(flash_clk_ieb), + .flash_io0_ieb_core(flash_io0_ieb), + .flash_io1_ieb_core(flash_io1_ieb), + .flash_io0_do_core(flash_io0_do), + .flash_io1_do_core(flash_io1_do), + .flash_io0_di_core(flash_io0_di), + .flash_io1_di_core(flash_io1_di), .mprj_io_in(mprj_io_in), .mprj_io_out(mprj_io_out), .mprj_io_oeb(mprj_io_oeb), @@ -279,19 +298,12 @@ module caravel ( wire caravel_clk2; wire caravel_rstn; - // LA signals - wire [127:0] la_data_in_user; // From CPU to MPRJ - wire [127:0] la_data_in_mprj; // From MPRJ to CPU - wire [127:0] la_data_out_mprj; // From CPU to MPRJ - wire [127:0] la_data_out_user; // From MPRJ to CPU - wire [127:0] la_oenb_user; // From CPU to MPRJ - wire [127:0] la_oenb_mprj; // From CPU to MPRJ - wire [127:0] la_iena_mprj; // From CPU only - wire [2:0] user_irq; // From MRPJ to CPU + wire [2:0] user_irq; // From MRPJ to CPU wire [2:0] user_irq_core; wire [2:0] user_irq_ena; + wire [2:0] irq_spi; // From SPI and external pins - // Exported Wishbone Bus + // Exported Wishbone Bus (processor facing) wire mprj_cyc_o_core; wire mprj_stb_o_core; wire mprj_we_o_core; @@ -301,28 +313,44 @@ module caravel ( wire mprj_ack_i_core; wire [31:0] mprj_dat_i_core; - // Mask revision - wire [31:0] mask_rev; + wire [31:0] hk_dat_i; + wire hk_ack_i; + wire hk_stb_o; - wire mprj_clock; - wire mprj_clock2; - wire mprj_reset; + // Exported Wishbone Bus (user area facing) wire mprj_cyc_o_user; wire mprj_stb_o_user; wire mprj_we_o_user; wire [3:0] mprj_sel_o_user; wire [31:0] mprj_adr_o_user; wire [31:0] mprj_dat_o_user; + + // Mask revision + wire [31:0] mask_rev; + + wire mprj_clock; + wire mprj_clock2; + wire mprj_reset; + + // Power monitoring wire mprj_vcc_pwrgood; wire mprj2_vcc_pwrgood; wire mprj_vdd_pwrgood; wire mprj2_vdd_pwrgood; + // Management processor (wrapper). Any management core + // implementation must match this pinout. + mgmt_core_wrapper soc ( `ifdef USE_POWER_PINS .VPWR(vccd_core), .VGND(vssd_core), `endif + + // Clock and reset + .core_clk(caravel_clk), + .core_rstn(caravel_rstn), + // GPIO (1 pin) .gpio_out_pad(gpio_out_core), .gpio_in_pad(gpio_in_core), @@ -333,31 +361,19 @@ module caravel ( // Primary SPI flash controller .flash_csb(flash_csb_core), - .flash_csb_ieb(flash_csb_ieb_core), - .flash_csb_oeb(flash_csb_oeb_core), .flash_clk(flash_clk_core), - .flash_clk_ieb(flash_clk_ieb_core), - .flash_clk_oeb(flash_clk_oeb_core), - .flash_io0_ieb(flash_io0_ieb_core), - .flash_io0_oeb(flash_io0_oeb_core), - .flash_io0_di(flash_io0_di_core), - .flash_io0_do(flash_io0_do_core), - .flash_io1_ieb(flash_io1_ieb_core), - .flash_io1_oeb(flash_io1_oeb_core), - .flash_io1_di(flash_io1_di_core), - .flash_io1_do(flash_io1_do_core), - .flash_io2_ieb(flash_io2_ieb_core), - .flash_io2_oeb(flash_io2_oeb_core), - .flash_io2_di(flash_io2_di_core), - .flash_io2_do(flash_io2_do_core), - .flash_io3_ieb(flash_io3_ieb_core), - .flash_io3_oeb(flash_io3_oeb_core), - .flash_io3_di(flash_io3_di_core), - .flash_io3_do(flash_io3_do_core), - - // Debug - .jtag_out(jtag_out), - .jtag_outenb(jtag_outenb), + .flash_io0_oeb(flash_io0_oeb), + .flash_io0_di(flash_io0_di), + .flash_io0_do(flash_io0_do), + .flash_io1_oeb(flash_io1_oeb), + .flash_io1_di(flash_io1_di), + .flash_io1_do(flash_io1_do), + .flash_io2_oeb(flash_io2_oeb), + .flash_io2_di(flash_io2_di), + .flash_io2_do(flash_io2_do), + .flash_io3_oeb(flash_io3_oeb), + .flash_io3_di(flash_io3_di), + .flash_io3_do(flash_io3_do), // Exported Wishbone Bus .mprj_cyc_o(mprj_cyc_o_core), @@ -369,17 +385,32 @@ module caravel ( .mprj_ack_i(mprj_ack_i_core), .mprj_dat_i(mprj_dat_i_core), - // Clock and reset - .core_clk(caravel_clk), - .core_rstn(caravel_rstn), + .hk_stb_o(hk_stb_o), + .hk_dat_i(hk_dat_i), + .hk_ack_i(hk_ack_i), // IRQ - .user_irq(user_irq), - .user_irq_ena(user_irq_ena), + .irq({irq_spi, user_irq}), - // Real-time status and control - .hkspi_status(hkspi_status), - .hkspi_control(hkspi_control) + // Module status (these may or may not be implemented) + .qspi_enabled(qspi_enabled), + .uart_enabled(uart_enabled), + .spi_enabled(spi_enabled), + .debug_mode(debug_mode), + + // Module I/O (these may or may not be implemented) + .ser_tx(ser_tx), + .ser_rx(ser_rx), + .spi_sdi(spi_sdi), + .spi_csb(spi_csb), + .spi_sck(spi_sck), + .spi_sdo(spi_sdo), + .debug_in(debug_in), + .debug_out(debug_out), + .debug_oeb(debug_oeb), + + // Trap status + .trap(trap) ); /* Clock and reset to user space are passed through a tristate */ @@ -410,13 +441,6 @@ module caravel ( .mprj_adr_o_core(mprj_adr_o_core), .mprj_dat_o_core(mprj_dat_o_core), .user_irq_core(user_irq_core), - .la_data_out_core(la_data_out_user), - .la_data_out_mprj(la_data_out_mprj), - .la_data_in_core(la_data_in_user), - .la_data_in_mprj(la_data_in_mprj), - .la_oenb_mprj(la_oenb_mprj), - .la_oenb_core(la_oenb_user), - .la_iena_mprj(la_iena_mprj), .user_irq_ena(user_irq_ena), .user_clock(mprj_clock), @@ -435,7 +459,6 @@ module caravel ( .user2_vdd_powergood(mprj2_vdd_pwrgood) ); - /*--------------------------------------------------*/ /* Wrapper module around the user project */ /*--------------------------------------------------*/ @@ -455,7 +478,7 @@ module caravel ( .wb_clk_i(mprj_clock), .wb_rst_i(mprj_reset), - // MGMT SoC Wishbone Slave + // Management SoC Wishbone bus (exported) .wbs_cyc_i(mprj_cyc_o_user), .wbs_stb_i(mprj_stb_o_user), .wbs_we_i(mprj_we_o_user), @@ -464,17 +487,16 @@ module caravel ( .wbs_dat_i(mprj_dat_o_user), .wbs_ack_o(mprj_ack_i_core), .wbs_dat_o(mprj_dat_i_core), - // Logic Analyzer - .la_data_in(la_data_in_user), - .la_data_out(la_data_out_user), - .la_oenb(la_oenb_user), - // IO Pads + + // GPIO pad 3-pin interface (plus analog) .io_in (user_io_in), .io_out(user_io_out), .io_oeb(user_io_oeb), .analog_io(user_analog_io), + // Independent clock .user_clock2(mprj_clock2), + // IRQ .user_irq(user_irq_core) ); @@ -512,6 +534,11 @@ module caravel ( assign gpio_resetn_2_shifted = {mprj_io_loader_resetn, gpio_resetn_2[`MPRJ_IO_PADS_2-1:1]}; + wire [2:0] spi_pll_sel; + wire [2:0] spi_pll90_sel; + wire [4:0] spi_pll_div; + wire [25:0] spi_pll_trim; + // Clocking control caravel_clocking clocking( @@ -527,8 +554,8 @@ module caravel ( .sel(spi_pll_sel), .sel2(spi_pll90_sel), .ext_reset(ext_reset), // From housekeeping SPI - .core_clk(core_clk), - .user_clk(user_clk), + .core_clk(caravel_clk), + .user_clk(caravel_clk2), .resetb_sync(core_rstn) ); @@ -548,86 +575,107 @@ module caravel ( .ext_trim(spi_pll_trim) ); - // Housekeeping SPI interface + // Housekeeping interface - housekeeping_spi housekeeping ( + housekeeping housekeeping ( `ifdef USE_POWER_PINS - .vdd(VPWR), - .vss(VGND), + .vdd(VPWR), + .vss(VGND), `endif - .RSTB(porb), - .SCK((hk_connect) ? mgmt_out_predata[4] : mgmt_in_data[4]), - .SDI((hk_connect) ? mgmt_out_predata[2] : mgmt_in_data[2]), - .CSB((hk_connect) ? mgmt_out_predata[3] : mgmt_in_data[3]), - .SDO(sdo_out_pre), - .sdo_enb(sdo_outenb_pre), + + .wb_clk_i(mprj_clock), + .wb_rst_i(mprj_reset), + + .wb_adr_i(mprj_adr_o_core), + .wb_dat_i(mprj_dat_o_core), + .wb_sel_i(mprj_sel_o_core), + .wb_we_i(mprj_we_o_core), + .wb_cyc_i(mprj_cyc_o_core), + .wb_stb_i(hk_stb_o), + .wb_ack_o(hk_ack_i), + .wb_dat_o(hk_dat_i), + + .porb(porb), + + .pll_ena(spi_pll_ena), .pll_dco_ena(spi_pll_dco_ena), + .pll_div(spi_pll_div), .pll_sel(spi_pll_sel), .pll90_sel(spi_pll90_sel), - .pll_div(spi_pll_div), - .pll_ena(spi_pll_ena), .pll_trim(spi_pll_trim), .pll_bypass(ext_clk_sel), + + .qspi_enabled(qspi_enabled), + .uart_enabled(uart_enabled), + .spi_enabled(spi_enabled), + .debug_mode(debug_mode), + + .ser_tx(ser_tx), + .ser_rx(ser_rx), + + .spi_sdi(spi_sdi), + .spi_csb(spi_csb), + .spi_sck(spi_sck), + .spi_sdo(spi_sdo), + + .debug_in(debug_in), + .debug_out(debug_out), + .debug_oeb(debug_oeb), + .irq(irq_spi), .reset(ext_reset), + + .serial_clock(gpio_clock), + .serial_resetn(gpio_resetn), + .serial_data_1(gpio_data_1), + .serial_data_2(gpio_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_io_out[1:0]}), + .mgmt_gpio_oeb({mgmt_io_oeb[3:2], mgmt_io_nc[`MPRJ_IO_PADS-5:0], + mgmt_io_oeb[1:0]}), + + .pwr_ctrl_out(), /* Not used in this version */ + .trap(trap), + + .user_clock(user_clock), + .mask_rev_in(mask_rev), - .gpio_enable(gpio_enable), - .gpio_resetn(gpio_resetn), - .gpio_clock(gpio_clock), - .gpio_data_1(gpio_data_1), - .gpio_data_2(gpio_data_2), - .sram_clk(hkspi_sram_clk), - .sram_csb(hkspi_sram_csb), - .sram_addr(hkspi_sram_addr), - .sram_rdata(hkspi_sram_rdata), - .pass_thru_mgmt_reset(pass_thru_mgmt), - .pass_thru_user_reset(pass_thru_user), - .pass_thru_mgmt_sck(pass_thru_mgmt_sck), - .pass_thru_mgmt_csb(pass_thru_mgmt_csb), - .pass_thru_mgmt_sdi(pass_thru_mgmt_sdi), - .pass_thru_mgmt_sdo(pass_thru_mgmt_sdo), - .pass_thru_user_sck(pass_thru_user_sck), - .pass_thru_user_csb(pass_thru_user_csb), - .pass_thru_user_sdi(pass_thru_user_sdi), - .pass_thru_user_sdo(mgmt_in_data[11]) - ); - // GPIO control interface + .spimemio_flash_csb(flash_csb_core), + .spimemio_flash_clk(flash_clk_core), + .spimemio_flash_io0_oeb(flash_io0_oeb_core), + .spimemio_flash_io1_oeb(flash_io1_oeb_core), + .spimemio_flash_io2_oeb(flash_io2_oeb_core), + .spimemio_flash_io3_oeb(flash_io3_oeb_core), + .spimemio_flash_io0_do(flash_io0_do_core), + .spimemio_flash_io1_do(flash_io1_do_core), + .spimemio_flash_io2_do(flash_io2_do_core), + .spimemio_flash_io3_do(flash_io3_do_core), + .spimemio_flash_io0_di(flash_io0_di_core), + .spimemio_flash_io1_di(flash_io1_di_core), + .spimemio_flash_io2_di(flash_io2_di_core), + .spimemio_flash_io3_di(flash_io3_di_core), - mprj_ctrl_wb #( - .BASE_ADR(MPRJ_CTRL_ADR) - ) mprj_ctrl ( - .wb_clk_i(wb_clk_i), - .wb_rst_i(wb_rst_i), + .pad_flash_csb(flash_csb_frame), + .pad_flash_csb_oeb(flash_csb_oeb), + .pad_flash_clk(flash_clk_frame), + .pad_flash_clk_oeb(flash_clk_oeb), + .pad_flash_io0_oeb(flash_io0_oeb), + .pad_flash_io1_oeb(flash_io1_oeb), + .pad_flash_io0_ieb(flash_io0_ieb), + .pad_flash_io1_ieb(flash_io1_ieb), + .pad_flash_io0_do(flash_io0_do), + .pad_flash_io1_do(flash_io1_do), + .pad_flash_io0_di(flash_io0_di), + .pad_flash_io1_di(flash_io1_di), - .wb_adr_i(cpu_adr_o), - .wb_dat_i(cpu_dat_o), - .wb_sel_i(cpu_sel_o), - .wb_we_i(cpu_we_o), - .wb_cyc_i(cpu_cyc_o), - .wb_stb_i(mprj_ctrl_stb_i), - .wb_ack_o(mprj_ctrl_ack_o), - .wb_dat_o(mprj_ctrl_dat_o), - - .serial_clock(mprj_io_loader_clock), - .serial_resetn(mprj_io_loader_resetn), - .serial_data_out_1(mprj_io_loader_data_1), - .serial_data_out_2(mprj_io_loader_data_2), - .ext_enable(gpio_enable), - .ext_resetn(gpio_resetn), - .ext_clock(gpio_clock), - .ext_data_1(gpio_data_1), - .ext_data_2(gpio_data_2), - .sdo_oenb_state(sdo_oenb_state), - .jtag_oenb_state(jtag_oenb_state), - .flash_io2_oenb_state(flash_io2_oenb_state), - .flash_io3_oenb_state(flash_io3_oenb_state), - .mgmt_gpio_out(mgmt_out_pre), - .mgmt_gpio_oeb(mgmt_oeb_data), - .mgmt_gpio_in(mgmt_in_data), - .pwr_ctrl_out(pwr_ctrl_out), - .user_irq_ena(user_irq_ena) + .usr1_vcc_pwrgood(mprj_vcc_pwrgood), + .usr2_vcc_pwrgood(mprj2_vcc_pwrgood), + .usr1_vdd_pwrgood(mprj_vdd_pwrgood), + .usr2_vdd_pwrgood(mprj2_vdd_pwrgood) ); // Each control block sits next to an I/O pad in the user area. @@ -665,8 +713,8 @@ module caravel ( .serial_clock_out(gpio_clock_1[1:0]), .mgmt_gpio_in(mgmt_io_in[1:0]), - .mgmt_gpio_out({sdo_out, jtag_out}), - .mgmt_gpio_oeb({sdo_outenb, jtag_outenb}), + .mgmt_gpio_out(mgmt_io_out[1:0]), + .mgmt_gpio_oeb(mgmt_io_oeb[1:0]), .one(), .zero(), @@ -720,9 +768,9 @@ module caravel ( .resetn_out(gpio_resetn_1[7:2]), .serial_clock_out(gpio_clock_1[7:2]), - .mgmt_gpio_in(mgmt_io_in[7:2]), - .mgmt_gpio_out(mgmt_io_in[7:2]), - .mgmt_gpio_oeb(one_loop1[7:2]), + .mgmt_gpio_in(mgmt_io_in[7:2]), + .mgmt_gpio_out(mgmt_io_in[7:2]), + .mgmt_gpio_oeb(one_loop1[7:2]), .one(one_loop1[7:2]), .zero(), @@ -769,9 +817,9 @@ module caravel ( .resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_1-1):8]), .serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_1-1):8]), - .mgmt_gpio_in(mgmt_io_in[(`MPRJ_IO_PADS_1-1):8]), - .mgmt_gpio_out(mgmt_io_in[(`MPRJ_IO_PADS_1-1):8]), - .mgmt_gpio_oeb(one_loop1[(`MPRJ_IO_PADS_1-1):8]), + .mgmt_gpio_in(mgmt_io_in[(`MPRJ_IO_PADS_1-1):8]), + .mgmt_gpio_out(mgmt_io_in[(`MPRJ_IO_PADS_1-1):8]), + .mgmt_gpio_oeb(one_loop1[(`MPRJ_IO_PADS_1-1):8]), .one(one_loop1[(`MPRJ_IO_PADS_1-1):8]), .zero(), @@ -822,8 +870,8 @@ module caravel ( .serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-2)]), .mgmt_gpio_in(mgmt_io_in[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-2)]), - .mgmt_gpio_out({gpio_flash_io3_out, gpio_flash_io2_out}), - .mgmt_gpio_oeb({flash_io3_oeb_core, flash_io2_oeb_core}), + .mgmt_gpio_out(mgmt_io_out[3:2]), + .mgmt_gpio_oeb(mgmt_io_oeb[3:2]), .one(), .zero(), @@ -870,9 +918,9 @@ module caravel ( .resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_2-3):0]), .serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_2-3):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_oeb(one_loop2), + .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_oeb(one_loop2), .one(one_loop2), .zero(), @@ -935,28 +983,5 @@ module caravel ( .X(rstb_l) ); - // Storage area - storage storage( - `ifdef USE_POWER_PINS - .VPWR(vccd_core), - .VGND(vssd_core), - `endif - .mgmt_clk(caravel_clk), - .mgmt_ena(mgmt_ena), - .mgmt_wen(mgmt_wen), - .mgmt_wen_mask(mgmt_wen_mask), - .mgmt_addr(mgmt_addr), - .mgmt_wdata(mgmt_wdata), - .mgmt_rdata(mgmt_rdata), - // Management RO interface - .mgmt_ena_ro(mgmt_ena_ro), - .mgmt_addr_ro(mgmt_addr_ro), - .mgmt_rdata_ro(mgmt_rdata_ro), - .hkspi_sram_clk(hkspi_sram_clk), - .hkspi_sram_csb(hkspi_sram_csb), - .hkspi_sram_addr(hkspi_sram_addr), - .hkspi_sram_rdata(hkspi_sram_rdata) - ); - endmodule // `default_nettype wire diff --git a/verilog/rtl/caravel_netlists.v b/verilog/rtl/caravel_netlists.v index 1330104e..8f9f5cd5 100644 --- a/verilog/rtl/caravel_netlists.v +++ b/verilog/rtl/caravel_netlists.v @@ -61,30 +61,26 @@ `include "gl/sky130_fd_sc_hvl__lsbufhv2lv_1_wrapped.v" `include "gl/caravel.v" `else - `include "mgmt_soc.v" - `include "housekeeping_spi.v" - `include "caravel_clocking.v" - `include "mgmt_core.v" - `include "digital_pll.v" - `include "DFFRAM.v" - `include "DFFRAMBB.v" - `include "storage.v" - `include "user_id_programming.v" - `include "clock_div.v" - `include "storage_bridge_wb.v" - `include "mprj_io.v" - `include "chip_io.v" - `include "mprj_logic_high.v" + + `include "digital_pll.v" + `include "caravel_clocking.v" + `include "user_id_programming.v" + `include "clock_div.v" + `include "mprj_io.v" + `include "chip_io.v" + `include "housekeeping_spi.v" + `include "housekeeping.v" + `include "mprj_logic_high.v" `include "mprj2_logic_high.v" - `include "mgmt_protect.v" + `include "mgmt_protect.v" `include "mgmt_protect_hv.v" - `include "gpio_control_block.v" - `include "gpio_logic_high.v" + `include "gpio_control_block.v" + `include "gpio_logic_high.v" `include "sky130_fd_sc_hvl__lsbufhv2lv_1_wrapped.v" + `include "mgmt_core_wrapper.v" `include "caravel.v" `endif `include "simple_por.v" -`include "sram_1rw1r_32_256_8_sky130.v" `endif diff --git a/verilog/rtl/housekeeping.v b/verilog/rtl/housekeeping.v new file mode 100644 index 00000000..44f51fa0 --- /dev/null +++ b/verilog/rtl/housekeeping.v @@ -0,0 +1,1237 @@ +// 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 + +//----------------------------------------------------------- +// Housekeeping interface for Caravel +//----------------------------------------------------------- +// Written by Tim Edwards +// efabless, inc. September 27, 2020 +//----------------------------------------------------------- + +//----------------------------------------------------------- +// This is a standalone slave SPI for the caravel chip that is +// intended to be independent of the picosoc and independent +// of all IP blocks except the power-on-reset. This SPI has +// register outputs controlling the functions that critically +// affect operation of the picosoc and so cannot be accessed +// from the picosoc itself. This includes the PLL enables, +// mode, and trim. It also has a general reset for the picosoc, +// an IRQ input, a bypass for the entire crystal oscillator +// and PLL chain, the manufacturer and product IDs and product +// revision number. +// +// Updated and revised, 10/13/2021: +// This module now comprises what was previously split into +// the housekeeping SPI, the mprj_ctrl block (control over +// the GPIO), and sysctrl (redirection of certain internal +// signals to the GPIO); and additionally manages the SPI +// flash signals and pass-through mode. Essentially all +// aspects of the system related to the use and configuration +// of the GPIO has been shifted to this module. This allows +// GPIO to be configured from either the management SoC +// through the wishbone interface, or externally through the +// SPI interface. It allows essentially any processor to +// take the place of the PicoRV32 as long as that processor +// can access memory-mapped space via the wishbone bus. +//----------------------------------------------------------- + +//------------------------------------------------------------ +// Caravel defined registers (by SPI address): +// See: doc/memory_map.txt +//------------------------------------------------------------ + +module housekeeping #( + parameter GPIO_BASE_ADR = 32'h2600_0000, + parameter SPI_BASE_ADR = 32'h2e00_0000, + parameter SYS_BASE_ADR = 32'h2f00_0000, + parameter IO_CTRL_BITS = 13 +) ( +`ifdef USE_POWER_PINS + inout vdd, + inout vss, +`endif + + // Wishbone interface to management SoC + input wb_clk_i, + input wb_rst_i, + input [31:0] wb_adr_i, + input [31:0] wb_dat_i, + input [3:0] wb_sel_i, + input wb_we_i, + input wb_cyc_i, + input wb_stb_i, + output wb_ack_o, + output [31:0] wb_dat_o, + + // Primary reset + input porb, + + // Clocking control parameters + output pll_ena, + output pll_dco_ena, + output [4:0] pll_div, + output [2:0] pll_sel, + output [2:0] pll90_sel, + output [25:0] pll_trim, + output pll_bypass, + + // Module enable status from SoC + input qspi_enabled, // Flash SPI is in quad mode + input uart_enabled, // UART is enabled + input spi_enabled, // SPI master is enabled + input debug_mode, // Debug mode enabled + + // UART interface to/from SoC + input ser_tx, + output ser_rx, + + // SPI master interface to/from SoC + output spi_sdi, + input spi_csb, + input spi_sck, + input spi_sdo, + + // External (originating from SPI and pad) IRQ and reset + output [2:0] irq, + output reset, + + // GPIO serial loader programming interface + output serial_clock, + output serial_resetn, + output serial_data_1, + output serial_data_2, + + // GPIO data management (to padframe)---three-pin interface + input [`MPRJ_IO_PADS-1:0] mgmt_gpio_in, + output [`MPRJ_IO_PADS-1:0] mgmt_gpio_out, + output [`MPRJ_IO_PADS-1:0] mgmt_gpio_oeb, + + // Power control output (reserved for future use with LDOs) + output [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out, + + // CPU trap state status (for system monitoring) + input trap, + + // User clock (for system monitoring) + input user_clock, + + // Mask revision/User project ID + input [31:0] mask_rev_in, + + // SPI flash management (management SoC side) + input spimemio_flash_csb, + input spimemio_flash_clk, + input spimemio_flash_io0_oeb, + input spimemio_flash_io1_oeb, + input spimemio_flash_io2_oeb, + input spimemio_flash_io3_oeb, + input spimemio_flash_io0_do, + input spimemio_flash_io1_do, + input spimemio_flash_io2_do, + input spimemio_flash_io3_do, + output spimemio_flash_io0_di, + output spimemio_flash_io1_di, + output spimemio_flash_io2_di, + output spimemio_flash_io3_di, + + // Debug interface (routes to first GPIO) from management SoC + output debug_in, + input debug_out, + input debug_oeb, + + // SPI flash management (padframe side) + // (io2 and io3 are part of GPIO array, not dedicated pads) + output pad_flash_csb, + output pad_flash_csb_oeb, + output pad_flash_clk, + output pad_flash_clk_oeb, + output pad_flash_io0_oeb, + output pad_flash_io1_oeb, + output pad_flash_io0_ieb, + output pad_flash_io1_ieb, + output pad_flash_io0_do, + output pad_flash_io1_do, + input pad_flash_io0_di, + input pad_flash_io1_di, + + // System signal monitoring + input usr1_vcc_pwrgood, + input usr2_vcc_pwrgood, + input usr1_vdd_pwrgood, + input usr2_vdd_pwrgood +); + + localparam OEB = 1; // Offset of output enable (bar) in shift register + localparam INP_DIS = 3; // Offset of input disable in shift register + + reg [25:0] pll_trim; + reg [4:0] pll_div; + reg [2:0] pll_sel; + reg [2:0] pll90_sel; + reg pll_dco_ena; + reg pll_ena; + reg pll_bypass; + reg reset_reg; + reg irq_spi; + reg serial_bb_clock; + reg serial_bb_resetn; + reg serial_bb_data_1; + reg serial_bb_data_2; + reg serial_bb_enable; + reg serial_xfer; + + reg clk1_output_dest; + reg clk2_output_dest; + reg trap_output_dest; + reg irq_1_inputsrc; + reg irq_2_inputsrc; + + reg [IO_CTRL_BITS-1:0] gpio_configure [`MPRJ_IO_PADS-1:0]; + reg [`MPRJ_IO_PADS-1:0] mgmt_gpio_data; + reg [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out; + + wire usr1_vcc_pwrgood; + wire usr2_vcc_pwrgood; + wire usr1_vdd_pwrgood; + wire usr2_vdd_pwrgood; + + wire [7:0] odata; + wire [7:0] idata; + wire [7:0] iaddr; + + wire [2:0] irq; + + wire trap; + wire rdstb; + wire wrstb; + wire pass_thru_mgmt; // Mode detected by housekeeping_spi + wire pass_thru_mgmt_delay; + wire pass_thru_user; // Mode detected by housekeeping_spi + wire pass_thru_user_delay; + wire pass_thru_mgmt_reset; + wire pass_thru_user_reset; + wire sdo; + wire sdo_enb; + + wire [7:0] caddr; // Combination of SPI address and back door address + wire [7:0] cdata; // Combination of SPI data and back door data + wire cwstb; // Combination of SPI write strobe and back door write strobe + wire csclk; // Combination of SPI SCK and back door access trigger + + // Housekeeping side 3-wire interface to GPIOs (see below) + wire [`MPRJ_IO_PADS-1:0] mgmt_gpio_out_pre; + + // Pass-through mode handling. Signals may only be applied when the + // core processor is in reset. + + 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 + // 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. + + 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[1:0] = mgmt_gpio_out_pre[1:0]; + + genvar i; + + // This implements high-impedence buffers on the GPIO outputs other than + // 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 + assign mgmt_gpio_out[i] = mgmt_gpio_oeb[i] ? 1'bz : mgmt_gpio_out_pre[i]; + end + endgenerate + + // Pass-through mode. Housekeeping SPI signals get inserted + // between the management SoC and the flash SPI I/O. + + assign pad_flash_csb = (pass_thru_mgmt) ? mgmt_gpio_in[3] : spimemio_flash_csb; + assign pad_flash_csb_oeb = (pass_thru_mgmt) ? 1'b0 : (~porb ? 1'b1 : 1'b0); + assign pad_flash_clk = (pass_thru_mgmt) ? mgmt_gpio_in[4] : spimemio_flash_clk; + assign pad_flash_clk_oeb = (pass_thru_mgmt) ? 1'b0 : (~porb ? 1'b1 : 1'b0); + assign pad_flash_io0_oeb = (pass_thru_mgmt) ? 1'b0 : spimemio_flash_io0_oeb; + assign pad_flash_io1_oeb = (pass_thru_mgmt) ? 1'b1 : spimemio_flash_io1_oeb; + assign pad_flash_io0_ieb = (pass_thru_mgmt) ? 1'b1 : ~spimemio_flash_io0_oeb; + assign pad_flash_io1_ieb = (pass_thru_mgmt) ? 1'b1 : ~spimemio_flash_io1_oeb; + assign pad_flash_io0_do = (pass_thru_mgmt) ? mgmt_gpio_in[2] : spimemio_flash_io0_do; + assign pad_flash_io1_do = spimemio_flash_io1_do; + assign spimemio_flash_io0_di = (pass_thru_mgmt) ? 1'b0 : pad_flash_io0_di; + assign spimemio_flash_io1_di = (pass_thru_mgmt) ? 1'b0 : pad_flash_io1_di; + + // Wishbone bus "back door" to SPI registers. This section of code + // (1) Maps SPI byte addresses to memory map 32-bit addresses + // (2) Applies signals to the housekeeping SPI to mux in the SPI address, + // clock, and write strobe. This is done carefully and slowly to + // avoid glitching on the SCK line and to avoid forcing the + // housekeeping module to keep up with the core clock timing. + + wire sys_select; // System monitoring memory map address selected + wire gpio_select; // GPIO configuration memory map address selected + wire spi_select; // SPI back door memory map address selected + + // Wishbone Back Door. This is a simple interface making use of the + // housekeeping SPI protocol. The housekeeping SPI uses byte-wide + // data, so this interface will stall the processor by holding wb_ack_o + // low until all bytes have been transferred between the processor and + // housekeeping SPI. + + reg [3:0] wbbd_state; + reg [7:0] wbbd_addr; /* SPI address translated from WB */ + reg [7:0] wbbd_data; /* SPI data translated from WB */ + reg wbbd_sck; /* wishbone access trigger (back-door clock) */ + reg wbbd_write; /* wishbone write trigger (back-door strobe) */ + reg wb_ack_o; /* acknowledge signal back to wishbone bus */ + reg [31:0] wb_dat_o; /* data output to wishbone bus */ + + // This defines a state machine that accesses the SPI registers through + // the back door wishbone interface. The process is relatively slow + // since the SPI data are byte-wide, so four individual accesses are + // made to read 4 bytes from the SPI to fill data on the wishbone bus + // before sending ACK and letting the processor continue. + + `define WBD_IDLE 4'h0 /* Back door access is idle */ + `define WBD_SETUP0 4'h1 /* Apply address and data for byte 1 of 4 */ + `define WBD_RW0 4'h2 /* Latch data for byte 1 of 4 */ + `define WBD_SETUP1 4'h3 /* Apply address and data for byte 2 of 4 */ + `define WBD_RW1 4'h4 /* Latch data for byte 2 of 4 */ + `define WBD_SETUP2 4'h5 /* Apply address and data for byte 3 of 4 */ + `define WBD_RW2 4'h6 /* Latch data for byte 3 of 4 */ + `define WBD_SETUP3 4'h7 /* Apply address and data for byte 4 of 4 */ + `define WBD_RW3 4'h8 /* Latch data for byte 4 of 4 */ + `define WBD_DONE 4'h9 /* Send ACK back to wishbone */ + + assign sys_select = (wb_adr_i[31:8] == SYS_BASE_ADR[31:8]); + assign gpio_select = (wb_adr_i[31:8] == GPIO_BASE_ADR[31:8]); + assign spi_select = (wb_adr_i[31:8] == SPI_BASE_ADR[31:8]); + + /* Register bit to SPI address mapping */ + + function [7:0] fdata(input [7:0] address); + begin + case (address) + /* Housekeeping SPI Protocol */ + 8'h00 : fdata = 8'h00; // SPI status (fixed) + + /* Status and Identification */ + 8'h01 : fdata = {4'h0, mfgr_id[11:8]}; // Manufacturer ID (fixed) + 8'h02 : fdata = mfgr_id[7:0]; // Manufacturer ID (fixed) + 8'h03 : fdata = prod_id; // Product ID (fixed) + 8'h04 : fdata = mask_rev[31:24]; // Mask rev (via programmed) + 8'h05 : fdata = mask_rev[23:16]; // Mask rev (via programmed) + 8'h06 : fdata = mask_rev[15:8]; // Mask rev (via programmed) + 8'h07 : fdata = mask_rev[7:0]; // Mask rev (via programmed) + 8'h08 : fdata = {7'b0000000, trap}; // CPU trap state + + /* System monitoring */ + 8'h09 : fdata = {4'b0000, usr1_vcc_pwrgood, usr2_vcc_pwrgood, + usr1_vdd_pwrgood, usr2_vdd_pwrgood}; + 8'h0a : fdata = {5'b00000, clk1_output_dest, clk2_output_dest, + trap_output_dest}; + 8'h0b : fdata = {6'b000000, irq_2_inputsrc, irq_1_inputsrc}; + + /* GPIO Configuration */ + 8'h0c : fdata = {3'b000, gpio_configure[0][12:8]}; + 8'h0d : fdata = gpio_configure[0][7:0]; + 8'h0e : fdata = {3'b000, gpio_configure[1][12:8]}; + 8'h0f : fdata = gpio_configure[1][7:0]; + 8'h10 : fdata = {3'b000, gpio_configure[2][12:8]}; + 8'h11 : fdata = gpio_configure[2][7:0]; + 8'h12 : fdata = {3'b000, gpio_configure[3][12:8]}; + 8'h13 : fdata = gpio_configure[3][7:0]; + 8'h14 : fdata = {3'b000, gpio_configure[4][12:8]}; + 8'h15 : fdata = gpio_configure[4][7:0]; + 8'h16 : fdata = {3'b000, gpio_configure[5][12:8]}; + 8'h17 : fdata = gpio_configure[5][7:0]; + 8'h18 : fdata = {3'b000, gpio_configure[6][12:8]}; + 8'h19 : fdata = gpio_configure[6][7:0]; + 8'h1a : fdata = {3'b000, gpio_configure[7][12:8]}; + 8'h1b : fdata = gpio_configure[7][7:0]; + 8'h1c : fdata = {3'b000, gpio_configure[8][12:8]}; + 8'h1d : fdata = gpio_configure[8][7:0]; + 8'h1e : fdata = {3'b000, gpio_configure[9][12:8]}; + 8'h1f : fdata = gpio_configure[9][7:0]; + 8'h20 : fdata = {3'b000, gpio_configure[10][12:8]}; + 8'h21 : fdata = gpio_configure[10][7:0]; + 8'h22 : fdata = {3'b000, gpio_configure[11][12:8]}; + 8'h23 : fdata = gpio_configure[11][7:0]; + 8'h24 : fdata = {3'b000, gpio_configure[12][12:8]}; + 8'h25 : fdata = gpio_configure[12][7:0]; + 8'h26 : fdata = {3'b000, gpio_configure[13][12:8]}; + 8'h27 : fdata = gpio_configure[13][7:0]; + 8'h28 : fdata = {3'b000, gpio_configure[14][12:8]}; + 8'h29 : fdata = gpio_configure[14][7:0]; + 8'h2a : fdata = {3'b000, gpio_configure[15][12:8]}; + 8'h2b : fdata = gpio_configure[15][7:0]; + 8'h2c : fdata = {3'b000, gpio_configure[16][12:8]}; + 8'h2d : fdata = gpio_configure[16][7:0]; + 8'h2e : fdata = {3'b000, gpio_configure[17][12:8]}; + 8'h2f : fdata = gpio_configure[17][7:0]; + 8'h30 : fdata = {3'b000, gpio_configure[18][12:8]}; + 8'h31 : fdata = gpio_configure[18][7:0]; + 8'h32 : fdata = {3'b000, gpio_configure[19][12:8]}; + 8'h33 : fdata = gpio_configure[19][7:0]; + 8'h34 : fdata = {3'b000, gpio_configure[20][12:8]}; + 8'h35 : fdata = gpio_configure[20][7:0]; + 8'h36 : fdata = {3'b000, gpio_configure[21][12:8]}; + 8'h37 : fdata = gpio_configure[21][7:0]; + 8'h38 : fdata = {3'b000, gpio_configure[22][12:8]}; + 8'h39 : fdata = gpio_configure[22][7:0]; + 8'h3a : fdata = {3'b000, gpio_configure[23][12:8]}; + 8'h3b : fdata = gpio_configure[23][7:0]; + 8'h3c : fdata = {3'b000, gpio_configure[24][12:8]}; + 8'h3d : fdata = gpio_configure[24][7:0]; + 8'h3e : fdata = {3'b000, gpio_configure[25][12:8]}; + 8'h3f : fdata = gpio_configure[25][7:0]; + 8'h40 : fdata = {3'b000, gpio_configure[26][12:8]}; + 8'h41 : fdata = gpio_configure[26][7:0]; + 8'h42 : fdata = {3'b000, gpio_configure[27][12:8]}; + 8'h43 : fdata = gpio_configure[27][7:0]; + 8'h44 : fdata = {3'b000, gpio_configure[27][12:8]}; + 8'h45 : fdata = gpio_configure[28][7:0]; + 8'h46 : fdata = {3'b000, gpio_configure[29][12:8]}; + 8'h47 : fdata = gpio_configure[29][7:0]; + 8'h48 : fdata = {3'b000, gpio_configure[30][12:8]}; + 8'h49 : fdata = gpio_configure[30][7:0]; + 8'h4a : fdata = {3'b000, gpio_configure[31][12:8]}; + 8'h4b : fdata = gpio_configure[31][7:0]; + 8'h4c : fdata = {3'b000, gpio_configure[32][12:8]}; + 8'h4d : fdata = gpio_configure[32][7:0]; + 8'h4e : fdata = {3'b000, gpio_configure[33][12:8]}; + 8'h4f : fdata = gpio_configure[33][7:0]; + 8'h50 : fdata = {3'b000, gpio_configure[34][12:8]}; + 8'h51 : fdata = gpio_configure[34][7:0]; + 8'h52 : fdata = {3'b000, gpio_configure[35][12:8]}; + 8'h53 : fdata = gpio_configure[35][7:0]; + 8'h54 : fdata = {3'b000, gpio_configure[36][12:8]}; + 8'h55 : fdata = gpio_configure[36][7:0]; + 8'h56 : fdata = {3'b000, gpio_configure[37][12:8]}; + 8'h57 : fdata = gpio_configure[37][7:0]; + + // GPIO Data + 8'h58 : fdata = {2'b00, mgmt_gpio_in[`MPRJ_IO_PADS-1:32]}; + 8'h59 : fdata = mgmt_gpio_in[31:24]; + 8'h5a : fdata = mgmt_gpio_in[23:16]; + 8'h5b : fdata = mgmt_gpio_in[15:8]; + 8'h5c : fdata = mgmt_gpio_in[7:0]; + + // Power Control (reserved) + 8'h5d : fdata = {4'b0000, pwr_ctrl_out}; + + // GPIO Control (bit bang and automatic) + 8'h5e : fdata = {2'b00, serial_data_2, serial_data_1, serial_bb_clock, + serial_bb_resetn, serial_bb_enable, serial_xfer}; + + /* Clocking control */ + 8'h5f : fdata = {6'b000000, pll_dco_ena, pll_ena}; + 8'h60 : fdata = {7'b0000000, pll_bypass}; + 8'h61 : fdata = {7'b0000000, irq_spi}; + 8'h62 : fdata = {7'b0000000, reset}; + 8'h63 : fdata = {6'b000000, pll_trim[25:24]}; + 8'h64 : fdata = pll_trim[23:16]; + 8'h65 : fdata = pll_trim[15:8]; + 8'h66 : fdata = pll_trim[7:0]; + 8'h67 : fdata = {2'b00, pll90_sel, pll_sel}; + 8'h68 : fdata = {3'b000, pll_div}; + + default: fdata = 8'h00; + endcase + end + endfunction + + /* Memory map address to SPI address translation for back door access */ + /* (see doc/memory_map.txt) */ + + function [7:0] spiaddr(input [31:0] wbaddress); + begin + case ({wbaddress[27], wbaddress[24], wbaddress[7:0]}) + 10'h300 : spiaddr = 8'h09; + 10'h304 : spiaddr = 8'h0a; + 10'h304 : spiaddr = 8'h0b; + 10'h025 : spiaddr = 8'h0c; + 10'h024 : spiaddr = 8'h0d; + 10'h029 : spiaddr = 8'h0e; + 10'h028 : spiaddr = 8'h0f; + 10'h02d : spiaddr = 8'h10; + 10'h02c : spiaddr = 8'h11; + 10'h031 : spiaddr = 8'h12; + 10'h030 : spiaddr = 8'h13; + 10'h035 : spiaddr = 8'h14; + 10'h034 : spiaddr = 8'h15; + 10'h039 : spiaddr = 8'h16; + 10'h038 : spiaddr = 8'h17; + 10'h03d : spiaddr = 8'h18; + 10'h03c : spiaddr = 8'h19; + 10'h041 : spiaddr = 8'h1a; + 10'h040 : spiaddr = 8'h1b; + 10'h045 : spiaddr = 8'h1c; + 10'h044 : spiaddr = 8'h1d; + 10'h049 : spiaddr = 8'h1e; + 10'h048 : spiaddr = 8'h1f; + 10'h04d : spiaddr = 8'h20; + 10'h04c : spiaddr = 8'h21; + 10'h051 : spiaddr = 8'h22; + 10'h050 : spiaddr = 8'h23; + 10'h055 : spiaddr = 8'h24; + 10'h054 : spiaddr = 8'h25; + 10'h059 : spiaddr = 8'h26; + 10'h058 : spiaddr = 8'h27; + 10'h05d : spiaddr = 8'h28; + 10'h05c : spiaddr = 8'h29; + 10'h061 : spiaddr = 8'h2a; + 10'h060 : spiaddr = 8'h2b; + 10'h065 : spiaddr = 8'h2c; + 10'h064 : spiaddr = 8'h2d; + 10'h069 : spiaddr = 8'h2e; + 10'h068 : spiaddr = 8'h2f; + 10'h06d : spiaddr = 8'h30; + 10'h06c : spiaddr = 8'h31; + 10'h071 : spiaddr = 8'h32; + 10'h070 : spiaddr = 8'h33; + 10'h075 : spiaddr = 8'h34; + 10'h074 : spiaddr = 8'h35; + 10'h079 : spiaddr = 8'h36; + 10'h078 : spiaddr = 8'h37; + 10'h07d : spiaddr = 8'h38; + 10'h07c : spiaddr = 8'h39; + 10'h081 : spiaddr = 8'h3a; + 10'h080 : spiaddr = 8'h3b; + 10'h085 : spiaddr = 8'h3c; + 10'h084 : spiaddr = 8'h3d; + 10'h089 : spiaddr = 8'h3e; + 10'h088 : spiaddr = 8'h3f; + 10'h08d : spiaddr = 8'h40; + 10'h08c : spiaddr = 8'h41; + 10'h091 : spiaddr = 8'h42; + 10'h090 : spiaddr = 8'h43; + 10'h095 : spiaddr = 8'h44; + 10'h094 : spiaddr = 8'h45; + 10'h099 : spiaddr = 8'h46; + 10'h098 : spiaddr = 8'h47; + 10'h09d : spiaddr = 8'h48; + 10'h09c : spiaddr = 8'h49; + 10'h0a1 : spiaddr = 8'h4a; + 10'h0a0 : spiaddr = 8'h4b; + 10'h0a5 : spiaddr = 8'h4c; + 10'h0a4 : spiaddr = 8'h4d; + 10'h0a9 : spiaddr = 8'h4e; + 10'h0a8 : spiaddr = 8'h4f; + 10'h0ad : spiaddr = 8'h50; + 10'h0ac : spiaddr = 8'h51; + 10'h0b1 : spiaddr = 8'h52; + 10'h0b0 : spiaddr = 8'h53; + 10'h0b5 : spiaddr = 8'h54; + 10'h0b4 : spiaddr = 8'h55; + 10'h0b9 : spiaddr = 8'h56; + 10'h0b8 : spiaddr = 8'h57; + 10'h010 : spiaddr = 8'h58; + 10'h00f : spiaddr = 8'h59; + 10'h00e : spiaddr = 8'h5a; + 10'h00d : spiaddr = 8'h5b; + 10'h00c : spiaddr = 8'h5c; + 10'h000 : spiaddr = 8'h5e; + 10'h004 : spiaddr = 8'h5d; + 10'h00c : spiaddr = 8'h5c; + 10'h00d : spiaddr = 8'h5b; + 10'h00e : spiaddr = 8'h5a; + 10'h00f : spiaddr = 8'h59; + 10'h010 : spiaddr = 8'h58; + 10'h20c : spiaddr = 8'h5f; + 10'h210 : spiaddr = 8'h60; + 10'h214 : spiaddr = 8'h61; + 10'h218 : spiaddr = 8'h62; + 10'h21f : spiaddr = 8'h63; + 10'h21e : spiaddr = 8'h64; + 10'h21d : spiaddr = 8'h65; + 10'h21c : spiaddr = 8'h66; + 10'h220 : spiaddr = 8'h67; + 10'h224 : spiaddr = 8'h68; + default : spiaddr = 8'h00; + endcase + end + endfunction + + /* Wishbone back-door state machine and address translation */ + + always @(posedge wb_clk_i or posedge wb_rst_i) begin + if (wb_rst_i) begin + wbbd_sck <= 1'b0; + wbbd_write <= 1'b0; + wbbd_addr <= 8'd0; + wbbd_data <= 8'd0; + wb_ack_o <= 1'b0; + end else begin + case (wbbd_state) + `WBD_IDLE: begin + if ((|wb_sel_i) && wb_cyc_i && + (sys_select | gpio_select | spi_select)) begin + wb_ack_o <= 1'b1; + wbbd_state <= `WBD_SETUP0; + end + end + `WBD_SETUP0: begin + wbbd_sck <= 1'b0; + if (sys_select) begin + wbbd_addr <= spiaddr(wb_adr_i[7:0]); + end else if (gpio_select) begin + wbbd_addr <= spiaddr(wb_adr_i[7:0]); + end else if (spi_select) begin + wbbd_addr <= spiaddr(wb_adr_i[7:0]); + end + if (wb_sel_i[0] & wb_we_i) begin + wbbd_data <= wb_dat_i[7:0]; + end + wbbd_write <= wb_sel_i[0] & wb_we_i; + wbbd_state <= `WBD_RW0; + end + `WBD_RW0: begin + wbbd_sck <= 1'b1; + wb_dat_o[7:0] <= odata; + wbbd_state <= `WBD_SETUP1; + end + `WBD_SETUP1: begin + wbbd_sck <= 1'b0; + if (sys_select) begin + wbbd_addr <= spiaddr(wb_adr_i[7:0] + 1); + end else if (gpio_select) begin + wbbd_addr <= spiaddr(wb_adr_i[7:0] + 1); + end else if (spi_select) begin + wbbd_addr <= spiaddr(wb_adr_i[7:0] + 1); + end + if (wb_sel_i[1] & wb_we_i) begin + wbbd_data <= wb_dat_i[15:8]; + end + wbbd_write <= wb_sel_i[1] & wb_we_i; + wbbd_state <= `WBD_RW1; + end + `WBD_RW1: begin + wbbd_sck <= 1'b1; + wb_dat_o[15:8] <= odata; + wbbd_state <= `WBD_SETUP2; + end + `WBD_SETUP2: begin + wbbd_sck <= 1'b0; + if (sys_select) begin + wbbd_addr <= spiaddr(wb_adr_i[7:0] + 2); + end else if (gpio_select) begin + wbbd_addr <= spiaddr(wb_adr_i[7:0] + 2); + end else if (spi_select) begin + wbbd_addr <= spiaddr(wb_adr_i[7:0] + 2); + end + if (wb_sel_i[2] & wb_we_i) begin + wbbd_data <= wb_dat_i[23:16]; + end + wbbd_write <= wb_sel_i[2] & wb_we_i; + wbbd_state <= `WBD_RW2; + end + `WBD_RW2: begin + wbbd_sck <= 1'b1; + wb_dat_o[23:16] <= odata; + wbbd_state <= `WBD_SETUP3; + end + `WBD_SETUP3: begin + wbbd_sck <= 1'b0; + if (sys_select) begin + wbbd_addr <= spiaddr(wb_adr_i[7:0] + 3); + end else if (gpio_select) begin + wbbd_addr <= spiaddr(wb_adr_i[7:0] + 3); + end else if (spi_select) begin + wbbd_addr <= spiaddr(wb_adr_i[7:0] + 3); + end + if (wb_sel_i[3] & wb_we_i) begin + wbbd_data <= wb_dat_i[31:24]; + end + wbbd_write <= wb_sel_i[3] & wb_we_i; + wbbd_state <= `WBD_RW3; + end + `WBD_RW3: begin + wbbd_sck <= 1'b1; + wb_dat_o[31:24] <= odata; + wbbd_state <= `WBD_DONE; + end + `WBD_DONE: begin + wbbd_sck <= 1'b0; + wb_ack_o <= 1'b0; // Release hold on wishbone bus + wbbd_state <= `WBD_IDLE; + end + endcase + end + end + + // Instantiate the SPI interface protocol module + + housekeeping_spi hkspi ( + .reset(~porb), + .SCK(mgmt_gpio_in[4]), + .SDI(mgmt_gpio_in[2]), + .CSB(mgmt_gpio_in[3]), + .SDO(sdo), + .sdoenb(sdo_enb), + .idata(odata), + .odata(idata), + .oaddr(iaddr), + .rdstb(rdstb), + .wrstb(wrstb), + .pass_thru_mgmt(pass_thru_mgmt), + .pass_thru_mgmt_delay(pass_thru_mgmt_delay), + .pass_thru_user(pass_thru_user), + .pass_thru_user_delay(pass_thru_user_delay), + .pass_thru_mgmt_reset(pass_thru_mgmt_reset), + .pass_thru_user_reset(pass_thru_user_reset) + ); + + // GPIO data handling to and from the management SoC + + assign mgmt_gpio_out_pre[37] = (qspi_enabled) ? spimemio_flash_io3_do : + mgmt_gpio_data[37]; + assign mgmt_gpio_out_pre[36] = (qspi_enabled) ? spimemio_flash_io2_do : + mgmt_gpio_data[36]; + + assign mgmt_gpio_oeb[37] = (qspi_enabled) ? spimemio_flash_io3_oeb : + ~gpio_configure[37][INP_DIS]; + assign mgmt_gpio_oeb[36] = (qspi_enabled) ? spimemio_flash_io2_oeb : + ~gpio_configure[36][INP_DIS]; + + assign mgmt_gpio_out_pre[35:16] = mgmt_gpio_data[35: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] + : mgmt_gpio_data[10]; + assign mgmt_gpio_out_pre[9] = (pass_thru_user) ? mgmt_gpio_in[4] + : mgmt_gpio_data[9]; + assign mgmt_gpio_out_pre[8] = (pass_thru_user) ? mgmt_gpio_in[3] + : mgmt_gpio_data[8]; + + 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]; + + // 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] : sdo; + assign mgmt_gpio_out_pre[0] = (debug_mode) ? debug_out : mgmt_gpio_data[0]; + + assign mgmt_gpio_oeb[1] = (spi_enabled) ? 1'b1 : sdo_enb; + 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 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 + assign mgmt_gpio_oeb[i] = ~gpio_configure[i][INP_DIS]; + end + endgenerate + + // System monitoring. Multiplex the clock and trap + // signals to the associated pad, and multiplex the irq signals + // from the associated pad, when the redirection is enabled. Note + // that the redirection is upstream of the user/managment multiplexing, + // so the pad being under control of the user area takes precedence + // over the system monitoring function. + + assign mgmt_gpio_out_pre[15] = (clk2_output_dest == 1'b1) ? user_clock + : mgmt_gpio_data[15]; + assign mgmt_gpio_out_pre[14] = (clk1_output_dest == 1'b1) ? wb_clk_i + : mgmt_gpio_data[14]; + assign mgmt_gpio_out_pre[13] = (trap_output_dest == 1'b1) ? trap + : mgmt_gpio_data[13]; + + assign irq[0] = irq_spi; + assign irq[1] = (irq_1_inputsrc == 1'b1) ? mgmt_gpio_in[7] : 1'b0; + assign irq[2] = (irq_2_inputsrc == 1'b1) ? mgmt_gpio_in[12] : 1'b0; + + // GPIO serial loader and GPIO management control + +`define GPIO_IDLE 2'b00 +`define GPIO_START 2'b01 +`define GPIO_XBYTE 2'b10 +`define GPIO_LOAD 2'b11 + + reg [3:0] xfer_count; + reg [4:0] pad_count_1; + reg [4:0] pad_count_2; + reg [1:0] xfer_state; + + reg serial_clock; + reg serial_resetn; + wire serial_data_1; + wire serial_data_2; + reg [IO_CTRL_BITS-1:0] serial_data_staging_1; + reg [IO_CTRL_BITS-1:0] serial_data_staging_2; + + assign serial_data_1 = serial_data_staging_1[IO_CTRL_BITS-1]; + assign serial_data_2 = serial_data_staging_2[IO_CTRL_BITS-1]; + + always @(posedge wb_clk_i or negedge porb) begin + if (!porb == 1'b0) begin + xfer_state <= `GPIO_IDLE; + xfer_count <= 4'd0; + /* NOTE: This assumes that MPRJ_IO_PADS_1 and MPRJ_IO_PADS_2 are + * equal, because they get clocked the same number of cycles by + * the same clock signal. pad_count_2 gates the count for both. + */ + pad_count_1 <= `MPRJ_IO_PADS_1 - 1; + pad_count_2 <= `MPRJ_IO_PADS_1; + serial_resetn <= 1'b0; + serial_clock <= 1'b0; + serial_data_staging_1 <= 0; + serial_data_staging_2 <= 0; + + end else begin + + case (xfer_state) + `GPIO_IDLE: begin + pad_count_1 <= `MPRJ_IO_PADS_1 - 1; + pad_count_2 <= `MPRJ_IO_PADS_1; + serial_resetn <= 1'b1; + serial_clock <= 1'b0; + if (serial_xfer == 1'b1) begin + xfer_state <= `GPIO_START; + end + end + `GPIO_START: begin + serial_resetn <= 1'b1; + serial_clock <= 1'b0; + xfer_count <= 6'd0; + pad_count_1 <= pad_count_1 - 1; + pad_count_2 <= pad_count_2 + 1; + xfer_state <= `GPIO_XBYTE; + serial_data_staging_1 <= gpio_configure[pad_count_1]; + serial_data_staging_2 <= gpio_configure[pad_count_2]; + end + `GPIO_XBYTE: begin + serial_resetn <= 1'b1; + serial_clock <= ~serial_clock; + if (serial_clock == 1'b0) begin + if (xfer_count == IO_CTRL_BITS - 1) begin + if (pad_count_2 == `MPRJ_IO_PADS) begin + xfer_state <= `GPIO_LOAD; + end else begin + xfer_state <= `GPIO_START; + end + end else begin + xfer_count <= xfer_count + 1; + end + end else begin + serial_data_staging_1 <= + {serial_data_staging_1[IO_CTRL_BITS-2:0], 1'b0}; + serial_data_staging_2 <= + {serial_data_staging_2[IO_CTRL_BITS-2:0], 1'b0}; + end + end + `GPIO_LOAD: begin + xfer_count <= xfer_count + 1; + + /* Load sequence: Raise clock for final data shift in; + * Pulse reset low while clock is high + * Set clock back to zero. + * Return to idle mode. + */ + if (xfer_count == 4'd0) begin + serial_clock <= 1'b1; + serial_resetn <= 1'b1; + end else if (xfer_count == 4'd1) begin + serial_clock <= 1'b1; + serial_resetn <= 1'b0; + end else if (xfer_count == 4'd2) begin + serial_clock <= 1'b1; + serial_resetn <= 1'b1; + end else if (xfer_count == 4'd3) begin + serial_resetn <= 1'b1; + serial_clock <= 1'b0; + xfer_state <= `GPIO_IDLE; + end + end + endcase + end + end + + // SPI Identification + + wire [11:0] mfgr_id; + wire [7:0] prod_id; + wire [31:0] mask_rev; + + assign mfgr_id = 12'h456; // Hard-coded + assign prod_id = 8'h11; // Hard-coded + assign mask_rev = mask_rev_in; // Copy in to out. + + // SPI Data transfer protocol + + assign caddr = iaddr | wbbd_addr; + assign csclk = mgmt_gpio_in[4] | wbbd_sck; + assign cdata = idata | wbbd_data; + assign cwstb = wrstb | wbbd_write; + assign odata = fdata(caddr); + + // Register mapping and I/O to SPI interface module + + integer j; + + always @(posedge csclk or negedge porb) begin + if (porb == 1'b0) begin + // Set trim for PLL at (almost) slowest rate (~90MHz). However, + // pll_trim[12] must be set to zero for proper startup. + pll_trim <= 26'b11111111111110111111111111; + pll_sel <= 3'b010; // Default output divider divide-by-2 + pll90_sel <= 3'b010; // Default secondary output divider divide-by-2 + pll_div <= 5'b00100; // Default feedback divider divide-by-8 + pll_dco_ena <= 1'b1; // Default free-running PLL + pll_ena <= 1'b0; // Default PLL turned off + pll_bypass <= 1'b1; // Default bypass mode (don't use PLL) + irq_spi <= 1'b0; + reset_reg <= 1'b0; + + // System monitoring signals + clk1_output_dest <= 1'b0; + clk2_output_dest <= 1'b0; + trap_output_dest <= 1'b0; + irq_1_inputsrc <= 1'b0; + irq_2_inputsrc <= 1'b0; + + // GPIO Configuration, Data, and Control + for (j = 0; j < `MPRJ_IO_PADS; j=j+1) begin + gpio_configure[j] <= 13'd0; + end + mgmt_gpio_data <= 'd0; + serial_bb_enable <= 1'b0; + serial_bb_data_1 <= 1'b0; + serial_bb_data_2 <= 1'b0; + serial_bb_clock <= 1'b0; + serial_bb_resetn <= 1'b0; + serial_xfer <= 1'b0; + + end else if (cwstb == 1'b1) begin + case (caddr) + /* Register 8'h00 is reserved for future use */ + /* Registers 8'h01 to 8'h09 are read-only and cannot be written */ + 8'h0a: begin + clk1_output_dest <= cdata[2]; + clk2_output_dest <= cdata[1]; + trap_output_dest <= cdata[0]; + end + 8'h0b: begin + irq_2_inputsrc <= cdata[1]; + irq_1_inputsrc <= cdata[0]; + end + 8'h0c: begin + gpio_configure[0][12:8] <= cdata[4:0]; + end + 8'h0d: begin + gpio_configure[0][7:0] <= cdata; + end + 8'h0e: begin + gpio_configure[1][12:8] <= cdata[4:0]; + end + 8'h0f: begin + gpio_configure[1][7:0] <= cdata; + end + 8'h10: begin + gpio_configure[2][12:8] <= cdata[4:0]; + end + 8'h11: begin + gpio_configure[2][7:0] <= cdata; + end + 8'h12: begin + gpio_configure[3][12:8] <= cdata[4:0]; + end + 8'h13: begin + gpio_configure[3][7:0] <= cdata; + end + 8'h14: begin + gpio_configure[4][12:8] <= cdata[4:0]; + end + 8'h15: begin + gpio_configure[4][7:0] <= cdata; + end + 8'h16: begin + gpio_configure[5][12:8] <= cdata[4:0]; + end + 8'h17: begin + gpio_configure[5][7:0] <= cdata; + end + 8'h18: begin + gpio_configure[6][12:8] <= cdata[4:0]; + end + 8'h19: begin + gpio_configure[6][7:0] <= cdata; + end + 8'h1a: begin + gpio_configure[7][12:8] <= cdata[4:0]; + end + 8'h1b: begin + gpio_configure[7][7:0] <= cdata; + end + 8'h1c: begin + gpio_configure[8][12:8] <= cdata[4:0]; + end + 8'h1d: begin + gpio_configure[8][7:0] <= cdata; + end + 8'h1e: begin + gpio_configure[9][12:8] <= cdata[4:0]; + end + 8'h1f: begin + gpio_configure[9][7:0] <= cdata; + end + 8'h20: begin + gpio_configure[10][12:8] <= cdata[4:0]; + end + 8'h21: begin + gpio_configure[10][7:0] <= cdata; + end + 8'h22: begin + gpio_configure[11][12:8] <= cdata[4:0]; + end + 8'h23: begin + gpio_configure[11][7:0] <= cdata; + end + 8'h24: begin + gpio_configure[12][12:8] <= cdata[4:0]; + end + 8'h25: begin + gpio_configure[12][7:0] <= cdata; + end + 8'h26: begin + gpio_configure[13][12:8] <= cdata[4:0]; + end + 8'h27: begin + gpio_configure[13][7:0] <= cdata; + end + 8'h28: begin + gpio_configure[14][12:8] <= cdata[4:0]; + end + 8'h29: begin + gpio_configure[14][7:0] <= cdata; + end + 8'h2a: begin + gpio_configure[15][12:8] <= cdata[4:0]; + end + 8'h2b: begin + gpio_configure[15][7:0] <= cdata; + end + 8'h2c: begin + gpio_configure[16][12:8] <= cdata[4:0]; + end + 8'h2d: begin + gpio_configure[16][7:0] <= cdata; + end + 8'h2e: begin + gpio_configure[17][12:8] <= cdata[4:0]; + end + 8'h2f: begin + gpio_configure[17][7:0] <= cdata; + end + 8'h30: begin + gpio_configure[18][12:8] <= cdata[4:0]; + end + 8'h31: begin + gpio_configure[18][7:0] <= cdata; + end + 8'h32: begin + gpio_configure[19][12:8] <= cdata[4:0]; + end + 8'h33: begin + gpio_configure[19][7:0] <= cdata; + end + 8'h34: begin + gpio_configure[20][12:8] <= cdata[4:0]; + end + 8'h35: begin + gpio_configure[20][7:0] <= cdata; + end + 8'h36: begin + gpio_configure[21][12:8] <= cdata[4:0]; + end + 8'h37: begin + gpio_configure[21][7:0] <= cdata; + end + 8'h38: begin + gpio_configure[22][12:8] <= cdata[4:0]; + end + 8'h39: begin + gpio_configure[22][7:0] <= cdata; + end + 8'h3a: begin + gpio_configure[23][12:8] <= cdata[4:0]; + end + 8'h3b: begin + gpio_configure[23][7:0] <= cdata; + end + 8'h3c: begin + gpio_configure[24][12:8] <= cdata[4:0]; + end + 8'h3d: begin + gpio_configure[24][7:0] <= cdata; + end + 8'h3e: begin + gpio_configure[25][12:8] <= cdata[4:0]; + end + 8'h3f: begin + gpio_configure[25][7:0] <= cdata; + end + 8'h40: begin + gpio_configure[26][12:8] <= cdata[4:0]; + end + 8'h41: begin + gpio_configure[26][7:0] <= cdata; + end + 8'h42: begin + gpio_configure[27][12:8] <= cdata[4:0]; + end + 8'h43: begin + gpio_configure[27][7:0] <= cdata; + end + 8'h44: begin + gpio_configure[28][12:8] <= cdata[4:0]; + end + 8'h45: begin + gpio_configure[28][7:0] <= idata; + end + 8'h46: begin + gpio_configure[29][12:8] <= cdata[4:0]; + end + 8'h47: begin + gpio_configure[29][7:0] <= cdata; + end + 8'h48: begin + gpio_configure[30][12:8] <= cdata[4:0]; + end + 8'h49: begin + gpio_configure[30][7:0] <= cdata; + end + 8'h4a: begin + gpio_configure[31][12:8] <= cdata[4:0]; + end + 8'h4b: begin + gpio_configure[31][7:0] <= cdata; + end + 8'h4c: begin + gpio_configure[32][12:8] <= cdata[4:0]; + end + 8'h4d: begin + gpio_configure[32][7:0] <= cdata; + end + 8'h4e: begin + gpio_configure[33][12:8] <= cdata[4:0]; + end + 8'h4f: begin + gpio_configure[33][7:0] <= cdata; + end + 8'h50: begin + gpio_configure[34][12:8] <= cdata[4:0]; + end + 8'h51: begin + gpio_configure[34][7:0] <= cdata; + end + 8'h52: begin + gpio_configure[35][12:8] <= cdata[4:0]; + end + 8'h53: begin + gpio_configure[35][7:0] <= cdata; + end + 8'h54: begin + gpio_configure[36][12:8] <= cdata[4:0]; + end + 8'h55: begin + gpio_configure[36][7:0] <= cdata; + end + 8'h56: begin + gpio_configure[37][12:8] <= cdata[4:0]; + end + 8'h57: begin + gpio_configure[37][7:0] <= cdata; + end + 8'h58: begin + mgmt_gpio_data[37:32] <= cdata[5:0]; + end + 8'h59: begin + mgmt_gpio_data[31:24] <= cdata; + end + 8'h5a: begin + mgmt_gpio_data[23:16] <= cdata; + end + 8'h5b: begin + mgmt_gpio_data[15:8] <= cdata; + end + 8'h5c: begin + mgmt_gpio_data[7:0] <= cdata; + end + 8'h5d: begin + pwr_ctrl_out <= cdata[3:0]; + end + 8'h5e: begin + serial_bb_data_2 <= cdata[5]; + serial_bb_data_1 <= cdata[4]; + serial_bb_clock <= cdata[3]; + serial_bb_resetn <= cdata[2]; + serial_bb_enable <= cdata[1]; + serial_xfer <= cdata[0]; + end + 8'h5f: begin + pll_ena <= cdata[0]; + pll_dco_ena <= cdata[1]; + end + 8'h60: begin + pll_bypass <= cdata[0]; + end + 8'h61: begin + irq_spi <= cdata[0]; + end + 8'h62: begin + reset_reg <= cdata[0]; + end + 8'h63: begin + pll_trim[25:24] <= cdata[1:0]; + end + 8'h64: begin + pll_trim[23:16] <= cdata; + end + 8'h65: begin + pll_trim[15:8] <= cdata; + end + 8'h66: begin + pll_trim[7:0] <= cdata; + end + 8'h67: begin + pll90_sel <= cdata[5:3]; + pll_sel <= cdata[2:0]; + end + 8'h68: begin + pll_div <= cdata[4:0]; + end + endcase // (caddr) + end else begin + serial_xfer <= 1'b0; // Serial transfer is self-resetting + irq_spi <= 1'b0; // IRQ is self-resetting + end + end +endmodule // housekeeping + +`default_nettype wire diff --git a/verilog/rtl/housekeeping_spi.v b/verilog/rtl/housekeeping_spi.v index aea543ca..84645e3e 100644 --- a/verilog/rtl/housekeeping_spi.v +++ b/verilog/rtl/housekeeping_spi.v @@ -14,320 +14,13 @@ // SPDX-License-Identifier: Apache-2.0 `default_nettype none -//------------------------------------- -// SPI controller for Caravel (PicoSoC) -//------------------------------------- -// Written by Tim Edwards -// efabless, inc. September 27, 2020 -//------------------------------------- //----------------------------------------------------------- -// This is a standalone slave SPI for the caravel chip that is -// intended to be independent of the picosoc and independent -// of all IP blocks except the power-on-reset. This SPI has -// register outputs controlling the functions that critically -// affect operation of the picosoc and so cannot be accessed -// from the picosoc itself. This includes the PLL enables -// and trim, and the crystal oscillator enable. It also has -// a general reset for the picosoc, an IRQ input, a bypass for -// the entire crystal oscillator and PLL chain, the -// manufacturer and product IDs and product revision number. -// To be independent of the 1.8V regulator, the slave SPI is -// synthesized with the 3V digital library and runs off of -// the 3V supply. -// -// This module is designed to be decoupled from the chip -// padframe and redirected to the wishbone bus under -// register control from the management SoC, such that the -// contents can be accessed from the management core via the -// SPI master. -// +// SPI controller for Caravel //----------------------------------------------------------- - -//------------------------------------------------------------ -// Caravel defined registers: -// Register 0: SPI status and control (unused & reserved) -// Register 1 and 2: Manufacturer ID (0x0456) (readonly) -// Register 3: Product ID (= 16) (readonly) -// Register 4-7: Mask revision (readonly) --- Externally programmed -// with via programming. Via programmed with a script to match -// each customer ID. -// -// Register 8: PLL enables (2 bits) -// Register 9: PLL bypass (1 bit) -// Register 10: IRQ (1 bit) -// Register 11: reset (1 bit) -// Register 12: trap (1 bit) (readonly) -// Register 13-16: PLL trim (26 bits) -// Register 17: PLL output divider (3 bits) -// Register 18: PLL feedback divider (5 bits) -// Register 19: User GPIO bit-bang control (5 bits) -// Register 20: SRAM read-only control (2 bits) -// Register 21: SRAM read-only address (8 bits) -// Register 22-25: SRAM read-only data (32 bits) -//------------------------------------------------------------ - -module housekeeping_spi( -`ifdef USE_POWER_PINS - vdd, vss, -`endif - RSTB, SCK, SDI, CSB, SDO, sdo_enb, - pll_ena, pll_dco_ena, pll_div, pll_sel, - pll90_sel, pll_trim, pll_bypass, irq, reset, - gpio_clock, gpio_resetn, gpio_data_1, gpio_data_2, gpio_enable, - sram_clk, sram_csb, sram_addr, sram_rdata, - trap, mask_rev_in, - pass_thru_mgmt_reset, pass_thru_user_reset, - pass_thru_mgmt_sck, pass_thru_mgmt_csb, - pass_thru_mgmt_sdi, pass_thru_mgmt_sdo, - pass_thru_user_sck, pass_thru_user_csb, - pass_thru_user_sdi, pass_thru_user_sdo -); - -`ifdef USE_POWER_PINS - inout vdd; // 3.3V supply - inout vss; // common ground -`endif - - input RSTB; // from padframe - - input SCK; // from padframe - input SDI; // from padframe - input CSB; // from padframe - output SDO; // to padframe - output sdo_enb; // to padframe - - output pll_ena; - output pll_dco_ena; - output [4:0] pll_div; - output [2:0] pll_sel; - output [2:0] pll90_sel; - output [25:0] pll_trim; - output pll_bypass; - output irq; - output reset; - input trap; - input [31:0] mask_rev_in; // metal programmed; 3.3V domain - - // Bit-bang control of GPIO serial loader - output gpio_enable; - output gpio_resetn; - output gpio_clock; - output gpio_data_1; - output gpio_data_2; - - // Bit-bang control of SRAM block 2nd read port - output sram_clk; - output sram_csb; - output [7:0] sram_addr; - input [31:0] sram_rdata; - - // Pass-through programming mode for management area SPI flash - output pass_thru_mgmt_reset; - output pass_thru_user_reset; - output pass_thru_mgmt_sck; - output pass_thru_mgmt_csb; - output pass_thru_mgmt_sdi; - input pass_thru_mgmt_sdo; - - // Pass-through programming mode for user area SPI flash - output pass_thru_user_sck; - output pass_thru_user_csb; - output pass_thru_user_sdi; - input pass_thru_user_sdo; - - reg [25:0] pll_trim; - reg [4:0] pll_div; - reg [2:0] pll_sel; - reg [2:0] pll90_sel; - reg pll_dco_ena; - reg pll_ena; - reg pll_bypass; - reg reset_reg; - reg irq; - reg gpio_enable; - reg gpio_clock; - reg gpio_resetn; - reg gpio_data_1; - reg gpio_data_2; - reg sram_clk; - reg sram_csb; - reg [7:0] sram_addr; - - wire [7:0] odata; - wire [7:0] idata; - wire [7:0] iaddr; - - wire trap; - wire rdstb; - wire wrstb; - wire pass_thru_mgmt; // Mode detected by spi_slave - wire pass_thru_mgmt_delay; - wire pass_thru_user; // Mode detected by spi_slave - wire pass_thru_user_delay; - wire loc_sdo; - - // Pass-through mode handling. Signals may only be applied when the - // core processor is in reset. - - assign pass_thru_mgmt_csb = ~pass_thru_mgmt_delay; - assign pass_thru_mgmt_sck = (pass_thru_mgmt ? SCK : 1'b0); - assign pass_thru_mgmt_sdi = (pass_thru_mgmt_delay ? SDI : 1'b0); - - assign pass_thru_user_csb = ~pass_thru_user_delay; - assign pass_thru_user_sck = (pass_thru_user ? SCK : 1'b0); - assign pass_thru_user_sdi = (pass_thru_user_delay ? SDI : 1'b0); - - assign SDO = pass_thru_mgmt ? pass_thru_mgmt_sdo : - pass_thru_user ? pass_thru_user_sdo : loc_sdo; - assign reset = pass_thru_mgmt_reset ? 1'b1 : reset_reg; - - // Instantiate the SPI slave module - - housekeeping_spi_slave U1 ( - .reset(~RSTB), - .SCK(SCK), - .SDI(SDI), - .CSB(CSB), - .SDO(loc_sdo), - .sdoenb(sdo_enb), - .idata(odata), - .odata(idata), - .oaddr(iaddr), - .rdstb(rdstb), - .wrstb(wrstb), - .pass_thru_mgmt(pass_thru_mgmt), - .pass_thru_mgmt_delay(pass_thru_mgmt_delay), - .pass_thru_user(pass_thru_user), - .pass_thru_user_delay(pass_thru_user_delay), - .pass_thru_mgmt_reset(pass_thru_mgmt_reset), - .pass_thru_user_reset(pass_thru_user_reset) - ); - - wire [11:0] mfgr_id; - wire [7:0] prod_id; - wire [31:0] mask_rev; - - assign mfgr_id = 12'h456; // Hard-coded - assign prod_id = 8'h10; // Hard-coded - assign mask_rev = mask_rev_in; // Copy in to out. - - // Send register contents to odata on SPI read command - // All values are 1-4 bits and no shadow registers are required. - - assign odata = - (iaddr == 8'h00) ? 8'h00 : // SPI status (fixed) - (iaddr == 8'h01) ? {4'h0, mfgr_id[11:8]} : // Manufacturer ID (fixed) - (iaddr == 8'h02) ? mfgr_id[7:0] : // Manufacturer ID (fixed) - (iaddr == 8'h03) ? prod_id : // Product ID (fixed) - (iaddr == 8'h04) ? mask_rev[31:24] : // Mask rev (metal programmed) - (iaddr == 8'h05) ? mask_rev[23:16] : // Mask rev (metal programmed) - (iaddr == 8'h06) ? mask_rev[15:8] : // Mask rev (metal programmed) - (iaddr == 8'h07) ? mask_rev[7:0] : // Mask rev (metal programmed) - - (iaddr == 8'h08) ? {6'b000000, pll_dco_ena, pll_ena} : - (iaddr == 8'h09) ? {7'b0000000, pll_bypass} : - (iaddr == 8'h0a) ? {7'b0000000, irq} : - (iaddr == 8'h0b) ? {7'b0000000, reset} : - (iaddr == 8'h0c) ? {7'b0000000, trap} : - (iaddr == 8'h0d) ? pll_trim[7:0] : - (iaddr == 8'h0e) ? pll_trim[15:8] : - (iaddr == 8'h0f) ? pll_trim[23:16] : - (iaddr == 8'h10) ? {6'b000000, pll_trim[25:24]} : - (iaddr == 8'h11) ? {2'b00, pll90_sel, pll_sel} : - (iaddr == 8'h12) ? {3'b000, pll_div} : - (iaddr == 8'h13) ? {3'b000, gpio_data_2, gpio_data_1, gpio_clock, - gpio_resetn, gpio_enable} : - (iaddr == 8'h14) ? {6'b000000, sram_clk, sram_csb} : - (iaddr == 8'h15) ? sram_addr : - (iaddr == 8'h16) ? sram_rdata[7:0] : - (iaddr == 8'h17) ? sram_rdata[15:8] : - (iaddr == 8'h18) ? sram_rdata[23:16] : - (iaddr == 8'h19) ? sram_rdata[31:24] : - 8'h00; // Default - - // Register mapping and I/O to slave module - - always @(posedge SCK or negedge RSTB) begin - if (RSTB == 1'b0) begin - // Set trim for PLL at (almost) slowest rate (~90MHz). However, - // pll_trim[12] must be set to zero for proper startup. - pll_trim <= 26'b11111111111110111111111111; - pll_sel <= 3'b010; // Default output divider divide-by-2 - pll90_sel <= 3'b010; // Default secondary output divider divide-by-2 - pll_div <= 5'b00100; // Default feedback divider divide-by-8 - pll_dco_ena <= 1'b1; // Default free-running PLL - pll_ena <= 1'b0; // Default PLL turned off - pll_bypass <= 1'b1; // Default bypass mode (don't use PLL) - irq <= 1'b0; - reset_reg <= 1'b0; - gpio_enable <= 1'b0; - gpio_data_1 <= 1'b0; - gpio_data_2 <= 1'b0; - gpio_clock <= 1'b0; - gpio_resetn <= 1'b0; - sram_clk <= 1'b0; - sram_csb <= 1'b1; - sram_addr <= 8'd0; - end else if (wrstb == 1'b1) begin - case (iaddr) - 8'h08: begin - pll_ena <= idata[0]; - pll_dco_ena <= idata[1]; - end - 8'h09: begin - pll_bypass <= idata[0]; - end - 8'h0a: begin - irq <= idata[0]; - end - 8'h0b: begin - reset_reg <= idata[0]; - end - // Register 0xc is read-only - 8'h0d: begin - pll_trim[7:0] <= idata; - end - 8'h0e: begin - pll_trim[15:8] <= idata; - end - 8'h0f: begin - pll_trim[23:16] <= idata; - end - 8'h10: begin - pll_trim[25:24] <= idata[1:0]; - end - 8'h11: begin - pll_sel <= idata[2:0]; - pll90_sel <= idata[5:3]; - end - 8'h12: begin - pll_div <= idata[4:0]; - end - 8'h13: begin - gpio_enable <= idata[0]; - gpio_resetn <= idata[1]; - gpio_clock <= idata[2]; - gpio_data_1 <= idata[3]; - gpio_data_2 <= idata[4]; - end - 8'h14: begin - sram_csb <= idata[0]; - sram_clk <= idata[1]; - end - 8'h15: begin - sram_addr <= idata; - end - // Registers 0x16-0x19 are read-only - endcase // (iaddr) - end - end -endmodule // housekeeping_spi - +// housekeeping_spi.v //------------------------------------------------------ -// housekeeping_spi_slave.v -//------------------------------------------------------ -// General purpose SPI slave module for the Caravel chip +// General purpose SPI module for the Caravel chip //------------------------------------------------------ // Written by Tim Edwards // efabless, inc., September 28, 2020 @@ -379,7 +72,7 @@ endmodule // housekeeping_spi `define USERPASS 3'b100 `define MGMTPASS 3'b101 -module housekeeping_spi_slave(reset, SCK, SDI, CSB, SDO, +module housekeeping_spi(reset, SCK, SDI, CSB, SDO, sdoenb, idata, odata, oaddr, rdstb, wrstb, pass_thru_mgmt, pass_thru_mgmt_delay, pass_thru_user, pass_thru_user_delay, @@ -554,5 +247,5 @@ module housekeeping_spi_slave(reset, SCK, SDI, CSB, SDO, end // ! csb_reset end // always @ SCK -endmodule // housekeeping_spi_slave +endmodule // housekeeping_spi `default_nettype wire diff --git a/verilog/rtl/la_wb.v b/verilog/rtl/la_wb.v deleted file mode 100644 index fbbc77cf..00000000 --- a/verilog/rtl/la_wb.v +++ /dev/null @@ -1,305 +0,0 @@ -// 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 -module la_wb # ( - parameter BASE_ADR = 32'h 2200_0000, - parameter LA_DATA_0 = 8'h00, - parameter LA_DATA_1 = 8'h04, - parameter LA_DATA_2 = 8'h08, - parameter LA_DATA_3 = 8'h0c, - parameter LA_OENB_0 = 8'h10, - parameter LA_OENB_1 = 8'h14, - parameter LA_OENB_2 = 8'h18, - parameter LA_OENB_3 = 8'h1c, - parameter LA_IENA_0 = 8'h20, - parameter LA_IENA_1 = 8'h24, - parameter LA_IENA_2 = 8'h28, - parameter LA_IENA_3 = 8'h2c, - parameter LA_SAMPLE = 8'h30 -) ( - input wb_clk_i, - input wb_rst_i, - - input [31:0] wb_dat_i, - input [31:0] wb_adr_i, - input [3:0] wb_sel_i, - input wb_cyc_i, - input wb_stb_i, - input wb_we_i, - - output [31:0] wb_dat_o, - output wb_ack_o, - - input [127:0] la_data_in, // From MPRJ - output [127:0] la_data, - output [127:0] la_oenb, - output [127:0] la_iena -); - - wire resetn; - wire valid; - wire ready; - wire [3:0] iomem_we; - - assign resetn = ~wb_rst_i; - assign valid = wb_stb_i && wb_cyc_i; - - assign iomem_we = wb_sel_i & {4{wb_we_i}}; - assign wb_ack_o = ready; - - la #( - .BASE_ADR(BASE_ADR), - .LA_DATA_0(LA_DATA_0), - .LA_DATA_1(LA_DATA_1), - .LA_DATA_2(LA_DATA_2), - .LA_DATA_3(LA_DATA_3), - .LA_OENB_0(LA_OENB_0), - .LA_OENB_1(LA_OENB_1), - .LA_OENB_2(LA_OENB_2), - .LA_OENB_3(LA_OENB_3), - .LA_IENA_0(LA_IENA_0), - .LA_IENA_1(LA_IENA_1), - .LA_IENA_2(LA_IENA_2), - .LA_IENA_3(LA_IENA_3), - .LA_SAMPLE(LA_SAMPLE) - ) la_ctrl ( - .clk(wb_clk_i), - .resetn(resetn), - .iomem_addr(wb_adr_i), - .iomem_valid(valid), - .iomem_wstrb(iomem_we), - .iomem_wdata(wb_dat_i), - .iomem_rdata(wb_dat_o), - .iomem_ready(ready), - .la_data_in(la_data_in), - .la_data(la_data), - .la_oenb(la_oenb), - .la_iena(la_iena) - ); - -endmodule - -module la #( - parameter BASE_ADR = 32'h 2200_0000, - parameter LA_DATA_0 = 8'h00, - parameter LA_DATA_1 = 8'h04, - parameter LA_DATA_2 = 8'h08, - parameter LA_DATA_3 = 8'h0c, - parameter LA_OENB_0 = 8'h10, - parameter LA_OENB_1 = 8'h14, - parameter LA_OENB_2 = 8'h18, - parameter LA_OENB_3 = 8'h1c, - parameter LA_IENA_0 = 8'h20, - parameter LA_IENA_1 = 8'h24, - parameter LA_IENA_2 = 8'h28, - parameter LA_IENA_3 = 8'h2c, - parameter LA_SAMPLE = 8'h30 -) ( - input clk, - input resetn, - - input [31:0] iomem_addr, - input iomem_valid, - input [3:0] iomem_wstrb, - input [31:0] iomem_wdata, - - output reg [31:0] iomem_rdata, - output reg iomem_ready, - - input [127:0] la_data_in, // From MPRJ - output [127:0] la_data, // To MPRJ - output [127:0] la_oenb, - output [127:0] la_iena -); - - reg [31:0] la_data_0; - reg [31:0] la_data_1; - reg [31:0] la_data_2; - reg [31:0] la_data_3; - - reg [31:0] la_oenb_0; - reg [31:0] la_oenb_1; - reg [31:0] la_oenb_2; - reg [31:0] la_oenb_3; - - reg [31:0] la_iena_0; - reg [31:0] la_iena_1; - reg [31:0] la_iena_2; - reg [31:0] la_iena_3; - - wire [3:0] la_data_sel; - wire [3:0] la_oenb_sel; - wire [3:0] la_iena_sel; - wire la_sample_sel; - - wire [31:0] la_sample_mask_0; - wire [31:0] la_sample_mask_1; - wire [31:0] la_sample_mask_2; - wire [31:0] la_sample_mask_3; - - assign la_data = {la_data_3, la_data_2, la_data_1, la_data_0}; - assign la_oenb = {la_oenb_3, la_oenb_2, la_oenb_1, la_oenb_0}; - assign la_iena = {la_iena_3, la_iena_2, la_iena_1, la_iena_0}; - - assign la_data_sel = { - (iomem_addr[7:0] == LA_DATA_3), - (iomem_addr[7:0] == LA_DATA_2), - (iomem_addr[7:0] == LA_DATA_1), - (iomem_addr[7:0] == LA_DATA_0) - }; - - assign la_oenb_sel = { - (iomem_addr[7:0] == LA_OENB_3), - (iomem_addr[7:0] == LA_OENB_2), - (iomem_addr[7:0] == LA_OENB_1), - (iomem_addr[7:0] == LA_OENB_0) - }; - - assign la_iena_sel = { - (iomem_addr[7:0] == LA_IENA_3), - (iomem_addr[7:0] == LA_IENA_2), - (iomem_addr[7:0] == LA_IENA_1), - (iomem_addr[7:0] == LA_IENA_0) - }; - - assign la_sample_sel = (iomem_addr[7:0] == LA_SAMPLE); - assign la_sample_mask_3 = (la_oenb_3 & la_iena_3); - assign la_sample_mask_2 = (la_oenb_2 & la_iena_2); - assign la_sample_mask_1 = (la_oenb_1 & la_iena_1); - assign la_sample_mask_0 = (la_oenb_0 & la_iena_0); - - always @(posedge clk) begin - if (!resetn) begin - la_data_0 <= 0; - la_data_1 <= 0; - la_data_2 <= 0; - la_data_3 <= 0; - la_oenb_0 <= 32'hFFFF_FFFF; // default is tri-state buff disabled - la_oenb_1 <= 32'hFFFF_FFFF; - la_oenb_2 <= 32'hFFFF_FFFF; - la_oenb_3 <= 32'hFFFF_FFFF; - la_iena_0 <= 32'h0000_0000; // default is grounded input - la_iena_1 <= 32'h0000_0000; - la_iena_2 <= 32'h0000_0000; - la_iena_3 <= 32'h0000_0000; - end else begin - iomem_ready <= 0; - if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin - iomem_ready <= 1'b 1; - - /* NOTE: Data in and out are independent channels */ - - if (la_data_sel[0]) begin - iomem_rdata <= la_data_in[31:0]; - - if (iomem_wstrb[0]) la_data_0[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) la_data_0[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) la_data_0[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) la_data_0[31:24] <= iomem_wdata[31:24]; - - end else if (la_data_sel[1]) begin - iomem_rdata <= la_data_in[63:32]; - - if (iomem_wstrb[0]) la_data_1[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) la_data_1[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) la_data_1[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) la_data_1[31:24] <= iomem_wdata[31:24]; - - end else if (la_data_sel[2]) begin - iomem_rdata <= la_data_in[95:64]; - - if (iomem_wstrb[0]) la_data_2[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) la_data_2[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) la_data_2[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) la_data_2[31:24] <= iomem_wdata[31:24]; - - end else if (la_data_sel[3]) begin - iomem_rdata <= la_data_in[127:96]; - - if (iomem_wstrb[0]) la_data_3[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) la_data_3[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) la_data_3[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) la_data_3[31:24] <= iomem_wdata[31:24]; - end else if (la_oenb_sel[0]) begin - iomem_rdata <= la_oenb_0; - - if (iomem_wstrb[0]) la_oenb_0[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) la_oenb_0[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) la_oenb_0[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) la_oenb_0[31:24] <= iomem_wdata[31:24]; - end else if (la_oenb_sel[1]) begin - iomem_rdata <= la_oenb_1; - - if (iomem_wstrb[0]) la_oenb_1[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) la_oenb_1[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) la_oenb_1[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) la_oenb_1[31:24] <= iomem_wdata[31:24]; - end else if (la_oenb_sel[2]) begin - iomem_rdata <= la_oenb_2; - - if (iomem_wstrb[0]) la_oenb_2[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) la_oenb_2[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) la_oenb_2[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) la_oenb_2[31:24] <= iomem_wdata[31:24]; - end else if (la_oenb_sel[3]) begin - iomem_rdata <= la_oenb_3; - - if (iomem_wstrb[0]) la_oenb_3[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) la_oenb_3[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) la_oenb_3[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) la_oenb_3[31:24] <= iomem_wdata[31:24]; - end else if (la_iena_sel[0]) begin - iomem_rdata <= la_iena_0; - - if (iomem_wstrb[0]) la_iena_0[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) la_iena_0[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) la_iena_0[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) la_iena_0[31:24] <= iomem_wdata[31:24]; - end else if (la_iena_sel[1]) begin - iomem_rdata <= la_iena_1; - - if (iomem_wstrb[0]) la_iena_1[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) la_iena_1[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) la_iena_1[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) la_iena_1[31:24] <= iomem_wdata[31:24]; - end else if (la_iena_sel[2]) begin - iomem_rdata <= la_iena_2; - - if (iomem_wstrb[0]) la_iena_2[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) la_iena_2[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) la_iena_2[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) la_iena_2[31:24] <= iomem_wdata[31:24]; - end else if (la_iena_sel[3]) begin - iomem_rdata <= la_iena_3; - - if (iomem_wstrb[0]) la_iena_3[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) la_iena_3[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) la_iena_3[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) la_iena_3[31:24] <= iomem_wdata[31:24]; - end else if (la_sample_sel) begin - /* Simultaneous data capture: Sample all inputs */ - /* for which input is enabled and output is disabled. */ - la_data_0 <= la_data_in[31:0] & la_sample_mask_0; - la_data_1 <= la_data_in[63:32] & la_sample_mask_1; - la_data_2 <= la_data_in[95:64] & la_sample_mask_2; - la_data_3 <= la_data_in[127:96] & la_sample_mask_3; - end - end - end - end - -endmodule -`default_nettype wire diff --git a/verilog/rtl/mprj_ctrl.v b/verilog/rtl/mprj_ctrl.v deleted file mode 100644 index 4780ffbc..00000000 --- a/verilog/rtl/mprj_ctrl.v +++ /dev/null @@ -1,462 +0,0 @@ -// 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 -module mprj_ctrl_wb #( - parameter BASE_ADR = 32'h 2300_0000, - parameter XFER = 8'h 00, - parameter PWRDATA = 8'h 04, - parameter IRQDATA = 8'h 08, - parameter IODATA = 8'h 0c, // One word per 32 IOs - parameter IOCONFIG = 8'h 24 -)( - input wb_clk_i, - input wb_rst_i, - - input [31:0] wb_dat_i, - input [31:0] wb_adr_i, - input [3:0] wb_sel_i, - input wb_cyc_i, - input wb_stb_i, - input wb_we_i, - - output [31:0] wb_dat_o, - output wb_ack_o, - - // Output is to serial loader - output serial_clock, - output serial_resetn, - output serial_data_out_1, - output serial_data_out_2, - - // Pass state of OEB bit on SDO and JTAG back to the core - // so that the function can be overridden for management output - output sdo_oenb_state, - output jtag_oenb_state, - output flash_io2_oenb_state, - output flash_io3_oenb_state, - - // Read/write data to each GPIO pad from management SoC - input [`MPRJ_IO_PADS-1:0] mgmt_gpio_in, - output [`MPRJ_IO_PADS-1:0] mgmt_gpio_out, - output [`MPRJ_IO_PADS-1:0] mgmt_gpio_oeb, - - // Write data to power controls - output [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out, - - // Enable user project IRQ signals to management SoC - output [2:0] user_irq_ena, - - // External bit-bang controls from the housekeeping SPI - input ext_clock, - input ext_resetn, - input ext_data_1, - input ext_data_2, - input ext_enable -); - wire resetn; - wire valid; - wire ready; - wire [3:0] iomem_we; - - assign resetn = ~wb_rst_i; - assign valid = wb_stb_i && wb_cyc_i; - - assign iomem_we = wb_sel_i & {4{wb_we_i}}; - assign wb_ack_o = ready; - - mprj_ctrl #( - .BASE_ADR(BASE_ADR), - .XFER(XFER), - .PWRDATA(PWRDATA), - .IRQDATA(IRQDATA), - .IODATA(IODATA), - .IOCONFIG(IOCONFIG) - ) mprj_ctrl ( - .clk(wb_clk_i), - .resetn(resetn), - .iomem_addr(wb_adr_i), - .iomem_valid(valid), - .iomem_wstrb(iomem_we[1:0]), - .iomem_wdata(wb_dat_i), - .iomem_rdata(wb_dat_o), - .iomem_ready(ready), - - .serial_clock(serial_clock), - .serial_resetn(serial_resetn), - .serial_data_out_1(serial_data_out_1), - .serial_data_out_2(serial_data_out_2), - .sdo_oenb_state(sdo_oenb_state), - .jtag_oenb_state(jtag_oenb_state), - .flash_io2_oenb_state(flash_io2_oenb_state), - .flash_io3_oenb_state(flash_io3_oenb_state), - // .mgmt_gpio_io(mgmt_gpio_io) - .mgmt_gpio_in(mgmt_gpio_in), - .mgmt_gpio_out(mgmt_gpio_out), - .mgmt_gpio_oeb(mgmt_gpio_oeb), - - // Write data to power controls - .pwr_ctrl_out(pwr_ctrl_out), - // Enable user project IRQ signals to management SoC - .user_irq_ena(user_irq_ena), - - // External bit-bang control from housekeeping SPI - .ext_clock(ext_clock), - .ext_resetn(ext_resetn), - .ext_data_1(ext_data_1), - .ext_data_2(ext_data_2), - .ext_enable(ext_enable) - ); - -endmodule - -module mprj_ctrl #( - parameter BASE_ADR = 32'h 2300_0000, - parameter XFER = 8'h 00, - parameter PWRDATA = 8'h 04, - parameter IRQDATA = 8'h 08, - parameter IODATA = 8'h 0c, - parameter IOCONFIG = 8'h 24, - parameter IO_CTRL_BITS = 13 -)( - input clk, - input resetn, - - input [31:0] iomem_addr, - input iomem_valid, - input [1:0] iomem_wstrb, - input [31:0] iomem_wdata, - output reg [31:0] iomem_rdata, - output reg iomem_ready, - - output serial_clock, - output serial_resetn, - output serial_data_out_1, - output serial_data_out_2, - output sdo_oenb_state, - output jtag_oenb_state, - output flash_io2_oenb_state, - output flash_io3_oenb_state, - input [`MPRJ_IO_PADS-1:0] mgmt_gpio_in, - output [`MPRJ_IO_PADS-1:0] mgmt_gpio_out, - output [`MPRJ_IO_PADS-1:0] mgmt_gpio_oeb, - output [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out, - output [2:0] user_irq_ena, - - input ext_clock, - input ext_resetn, - input ext_data_1, - input ext_data_2, - input ext_enable -); - -`define IDLE 2'b00 -`define START 2'b01 -`define XBYTE 2'b10 -`define LOAD 2'b11 - - localparam IO_WORDS = (`MPRJ_IO_PADS % 32 != 0) + (`MPRJ_IO_PADS / 32); - - localparam IO_BASE_ADR = (BASE_ADR | IOCONFIG); - - localparam OEB = 1; // Offset of output enable in shift register. - localparam INP_DIS = 3; // Offset of input disable in shift register. - - reg [IO_CTRL_BITS-1:0] io_ctrl[`MPRJ_IO_PADS-1:0]; // I/O control, 1 word per gpio pad - reg [`MPRJ_IO_PADS-1:0] mgmt_gpio_out; // I/O write data, 1 bit per gpio pad - reg [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out; // Power write data, 1 bit per power pad - reg [2:0] user_irq_ena; // Enable user to raise IRQs - reg xfer_ctrl; // Transfer control (1 bit) - - wire [IO_WORDS-1:0] io_data_sel; // wishbone selects - wire pwr_data_sel; - wire irq_data_sel; - wire xfer_sel; - wire busy; - wire selected; - wire [`MPRJ_IO_PADS-1:0] io_ctrl_sel; - reg [31:0] iomem_rdata_pre; - - wire [`MPRJ_IO_PADS-1:0] mgmt_gpio_in; - - wire sdo_oenb_state, jtag_oenb_state; - wire flash_io2_oenb_state, flash_io3_oenb_state; - - // JTAG and housekeeping SDO are normally controlled by their respective - // modules with OEB set to the default 1 value. If configured for an - // additional output by setting the OEB bit low, then pass this information - // back to the core so that the default signals can be overridden. - - assign jtag_oenb_state = io_ctrl[0][OEB]; - assign sdo_oenb_state = io_ctrl[1][OEB]; - - // Likewise for the flash_io2 and flash_io3, although they are configured - // as input by default. - assign flash_io2_oenb_state = io_ctrl[(`MPRJ_IO_PADS)-2][OEB]; - assign flash_io3_oenb_state = io_ctrl[(`MPRJ_IO_PADS)-1][OEB]; - - `define wtop (((i+1)*32 > `MPRJ_IO_PADS) ? `MPRJ_IO_PADS-1 : (i+1)*32-1) - `define wbot (i*32) - `define rtop (`wtop - `wbot) - - genvar i; - - // Assign selection bits per address - - assign xfer_sel = (iomem_addr[7:0] == XFER); - assign pwr_data_sel = (iomem_addr[7:0] == PWRDATA); - assign irq_data_sel = (iomem_addr[7:0] == IRQDATA); - - generate - for (i=0; i