First major update; current code passes syntax checks in iverilog

and simulates, but fails testbench (not surprising at this stage).
This commit is contained in:
Tim Edwards 2021-10-15 21:49:49 -04:00
parent f1909cab52
commit bdfa747145
16 changed files with 2934 additions and 1462 deletions

110
doc/memory_map.txt Normal file
View File

@ -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
----------------------------------------------------------------------------------

217
verilog/dv/caravel/defs.h Normal file
View File

@ -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 <stdint.h>
#include <stdbool.h>
// 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

View File

@ -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

View File

@ -0,0 +1,44 @@
<!---
# SPDX-FileCopyrightText: 2020 Efabless Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
-->
------------------------------------------------
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.

View File

@ -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;
}
}

View File

@ -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 <clifford@clifford.at>
* Copyright (C) 2018 Tim Edwards <tim@efabless.com>
*
* 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

View File

@ -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
}

View File

@ -0,0 +1,447 @@
`default_nettype none
/*
* SPDX-FileCopyrightText: 2017 Clifford Wolf
*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* 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("<SPI-START>");
$write("<SPI:%02x:%02x>", 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

174
verilog/dv/caravel/start.s Normal file
View File

@ -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:

View File

@ -13,6 +13,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* caravel, a project harness for the Google/SkyWater sky130 */ /* caravel, a project harness for the Google/SkyWater sky130 */
/* fabrication process and open source PDK */ /* fabrication process and open source PDK */
@ -22,10 +23,17 @@
/* and Mohamed Shalan, August 2020 */ /* and Mohamed Shalan, August 2020 */
/* This file is open source hardware released under the */ /* This file is open source hardware released under the */
/* Apache 2.0 license. See file LICENSE. */ /* 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 ( module caravel (
// All top-level I/O are package-facing pins
inout vddio, // Common 3.3V padframe/ESD power inout vddio, // Common 3.3V padframe/ESD power
inout vddio_2, // Common 3.3V padframe/ESD power inout vddio_2, // Common 3.3V padframe/ESD power
inout vssio, // Common padframe/ESD ground inout vssio, // Common padframe/ESD ground
@ -47,7 +55,6 @@ module caravel (
inout gpio, // Used for external LDO control inout gpio, // Used for external LDO control
inout [`MPRJ_IO_PADS-1:0] mprj_io, 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 clock, // CMOS core clock input, not a crystal
input resetb, // Reset input (sense inverted) input resetb, // Reset input (sense inverted)
@ -159,12 +166,10 @@ module caravel (
// ser_tx = mprj_io[6] (output) // ser_tx = mprj_io[6] (output)
// irq = mprj_io[7] (input) // irq = mprj_io[7] (input)
wire [`MPRJ_IO_PADS-1:0] mgmt_io_in; wire [`MPRJ_IO_PADS-1:0] mgmt_io_in; /* one- and three-pin data */
wire jtag_out, sdo_out; wire [`MPRJ_IO_PADS-5:0] mgmt_io_nc; /* no-connects */
wire jtag_outenb, sdo_outenb; wire [3:0] mgmt_io_out; /* three-pin interface out */
wire gpio_flash_io2_out, gpio_flash_io3_out; wire [3:0] mgmt_io_oeb; /* three-pin output enable */
wire [1:0] mgmt_io_nc; /* no-connects */
wire clock_core; wire clock_core;
@ -179,14 +184,28 @@ module caravel (
wire rstb_h; wire rstb_h;
wire rstb_l; wire rstb_l;
// Flash SPI communication (management SoC to housekeeping)
wire flash_clk_core, flash_csb_core; wire flash_clk_core, flash_csb_core;
wire flash_clk_oeb_core, flash_csb_oeb_core; wire flash_clk_oeb_core, flash_csb_oeb_core;
wire flash_clk_ieb_core, flash_csb_ieb_core; wire flash_clk_ieb_core, flash_csb_ieb_core;
wire flash_io0_oeb_core, flash_io1_oeb_core; wire flash_io0_oeb_core, flash_io1_oeb_core;
wire flash_io2_oeb_core, flash_io3_oeb_core; wire flash_io2_oeb_core, flash_io3_oeb_core;
wire flash_io0_ieb_core, flash_io1_ieb_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_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_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( chip_io padframe(
`ifndef TOP_ROUTING `ifndef TOP_ROUTING
@ -245,20 +264,20 @@ module caravel (
.gpio_mode1_core(gpio_mode1_core), .gpio_mode1_core(gpio_mode1_core),
.gpio_outenb_core(gpio_outenb_core), .gpio_outenb_core(gpio_outenb_core),
.gpio_inenb_core(gpio_inenb_core), .gpio_inenb_core(gpio_inenb_core),
.flash_csb_core(flash_csb_core), .flash_csb_core(flash_csb_frame),
.flash_clk_core(flash_clk_core), .flash_clk_core(flash_clk_frame),
.flash_csb_oeb_core(flash_csb_oeb_core), .flash_csb_oeb_core(flash_csb_oeb),
.flash_clk_oeb_core(flash_clk_oeb_core), .flash_clk_oeb_core(flash_clk_oeb),
.flash_io0_oeb_core(flash_io0_oeb_core), .flash_io0_oeb_core(flash_io0_oeb),
.flash_io1_oeb_core(flash_io1_oeb_core), .flash_io1_oeb_core(flash_io1_oeb),
.flash_csb_ieb_core(flash_csb_ieb_core), .flash_csb_ieb_core(flash_csb_ieb),
.flash_clk_ieb_core(flash_clk_ieb_core), .flash_clk_ieb_core(flash_clk_ieb),
.flash_io0_ieb_core(flash_io0_ieb_core), .flash_io0_ieb_core(flash_io0_ieb),
.flash_io1_ieb_core(flash_io1_ieb_core), .flash_io1_ieb_core(flash_io1_ieb),
.flash_io0_do_core(flash_io0_do_core), .flash_io0_do_core(flash_io0_do),
.flash_io1_do_core(flash_io1_do_core), .flash_io1_do_core(flash_io1_do),
.flash_io0_di_core(flash_io0_di_core), .flash_io0_di_core(flash_io0_di),
.flash_io1_di_core(flash_io1_di_core), .flash_io1_di_core(flash_io1_di),
.mprj_io_in(mprj_io_in), .mprj_io_in(mprj_io_in),
.mprj_io_out(mprj_io_out), .mprj_io_out(mprj_io_out),
.mprj_io_oeb(mprj_io_oeb), .mprj_io_oeb(mprj_io_oeb),
@ -279,19 +298,12 @@ module caravel (
wire caravel_clk2; wire caravel_clk2;
wire caravel_rstn; wire caravel_rstn;
// LA signals wire [2:0] user_irq; // From MRPJ to CPU
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_core; wire [2:0] user_irq_core;
wire [2:0] user_irq_ena; 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_cyc_o_core;
wire mprj_stb_o_core; wire mprj_stb_o_core;
wire mprj_we_o_core; wire mprj_we_o_core;
@ -301,28 +313,44 @@ module caravel (
wire mprj_ack_i_core; wire mprj_ack_i_core;
wire [31:0] mprj_dat_i_core; wire [31:0] mprj_dat_i_core;
// Mask revision wire [31:0] hk_dat_i;
wire [31:0] mask_rev; wire hk_ack_i;
wire hk_stb_o;
wire mprj_clock; // Exported Wishbone Bus (user area facing)
wire mprj_clock2;
wire mprj_reset;
wire mprj_cyc_o_user; wire mprj_cyc_o_user;
wire mprj_stb_o_user; wire mprj_stb_o_user;
wire mprj_we_o_user; wire mprj_we_o_user;
wire [3:0] mprj_sel_o_user; wire [3:0] mprj_sel_o_user;
wire [31:0] mprj_adr_o_user; wire [31:0] mprj_adr_o_user;
wire [31:0] mprj_dat_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 mprj_vcc_pwrgood;
wire mprj2_vcc_pwrgood; wire mprj2_vcc_pwrgood;
wire mprj_vdd_pwrgood; wire mprj_vdd_pwrgood;
wire mprj2_vdd_pwrgood; wire mprj2_vdd_pwrgood;
// Management processor (wrapper). Any management core
// implementation must match this pinout.
mgmt_core_wrapper soc ( mgmt_core_wrapper soc (
`ifdef USE_POWER_PINS `ifdef USE_POWER_PINS
.VPWR(vccd_core), .VPWR(vccd_core),
.VGND(vssd_core), .VGND(vssd_core),
`endif `endif
// Clock and reset
.core_clk(caravel_clk),
.core_rstn(caravel_rstn),
// GPIO (1 pin) // GPIO (1 pin)
.gpio_out_pad(gpio_out_core), .gpio_out_pad(gpio_out_core),
.gpio_in_pad(gpio_in_core), .gpio_in_pad(gpio_in_core),
@ -333,31 +361,19 @@ module caravel (
// Primary SPI flash controller // Primary SPI flash controller
.flash_csb(flash_csb_core), .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(flash_clk_core),
.flash_clk_ieb(flash_clk_ieb_core), .flash_io0_oeb(flash_io0_oeb),
.flash_clk_oeb(flash_clk_oeb_core), .flash_io0_di(flash_io0_di),
.flash_io0_ieb(flash_io0_ieb_core), .flash_io0_do(flash_io0_do),
.flash_io0_oeb(flash_io0_oeb_core), .flash_io1_oeb(flash_io1_oeb),
.flash_io0_di(flash_io0_di_core), .flash_io1_di(flash_io1_di),
.flash_io0_do(flash_io0_do_core), .flash_io1_do(flash_io1_do),
.flash_io1_ieb(flash_io1_ieb_core), .flash_io2_oeb(flash_io2_oeb),
.flash_io1_oeb(flash_io1_oeb_core), .flash_io2_di(flash_io2_di),
.flash_io1_di(flash_io1_di_core), .flash_io2_do(flash_io2_do),
.flash_io1_do(flash_io1_do_core), .flash_io3_oeb(flash_io3_oeb),
.flash_io2_ieb(flash_io2_ieb_core), .flash_io3_di(flash_io3_di),
.flash_io2_oeb(flash_io2_oeb_core), .flash_io3_do(flash_io3_do),
.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),
// Exported Wishbone Bus // Exported Wishbone Bus
.mprj_cyc_o(mprj_cyc_o_core), .mprj_cyc_o(mprj_cyc_o_core),
@ -369,17 +385,32 @@ module caravel (
.mprj_ack_i(mprj_ack_i_core), .mprj_ack_i(mprj_ack_i_core),
.mprj_dat_i(mprj_dat_i_core), .mprj_dat_i(mprj_dat_i_core),
// Clock and reset .hk_stb_o(hk_stb_o),
.core_clk(caravel_clk), .hk_dat_i(hk_dat_i),
.core_rstn(caravel_rstn), .hk_ack_i(hk_ack_i),
// IRQ // IRQ
.user_irq(user_irq), .irq({irq_spi, user_irq}),
.user_irq_ena(user_irq_ena),
// Real-time status and control // Module status (these may or may not be implemented)
.hkspi_status(hkspi_status), .qspi_enabled(qspi_enabled),
.hkspi_control(hkspi_control) .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 */ /* 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_adr_o_core(mprj_adr_o_core),
.mprj_dat_o_core(mprj_dat_o_core), .mprj_dat_o_core(mprj_dat_o_core),
.user_irq_core(user_irq_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_irq_ena(user_irq_ena),
.user_clock(mprj_clock), .user_clock(mprj_clock),
@ -435,7 +459,6 @@ module caravel (
.user2_vdd_powergood(mprj2_vdd_pwrgood) .user2_vdd_powergood(mprj2_vdd_pwrgood)
); );
/*--------------------------------------------------*/ /*--------------------------------------------------*/
/* Wrapper module around the user project */ /* Wrapper module around the user project */
/*--------------------------------------------------*/ /*--------------------------------------------------*/
@ -455,7 +478,7 @@ module caravel (
.wb_clk_i(mprj_clock), .wb_clk_i(mprj_clock),
.wb_rst_i(mprj_reset), .wb_rst_i(mprj_reset),
// MGMT SoC Wishbone Slave // Management SoC Wishbone bus (exported)
.wbs_cyc_i(mprj_cyc_o_user), .wbs_cyc_i(mprj_cyc_o_user),
.wbs_stb_i(mprj_stb_o_user), .wbs_stb_i(mprj_stb_o_user),
.wbs_we_i(mprj_we_o_user), .wbs_we_i(mprj_we_o_user),
@ -464,17 +487,16 @@ module caravel (
.wbs_dat_i(mprj_dat_o_user), .wbs_dat_i(mprj_dat_o_user),
.wbs_ack_o(mprj_ack_i_core), .wbs_ack_o(mprj_ack_i_core),
.wbs_dat_o(mprj_dat_i_core), .wbs_dat_o(mprj_dat_i_core),
// Logic Analyzer
.la_data_in(la_data_in_user), // GPIO pad 3-pin interface (plus analog)
.la_data_out(la_data_out_user),
.la_oenb(la_oenb_user),
// IO Pads
.io_in (user_io_in), .io_in (user_io_in),
.io_out(user_io_out), .io_out(user_io_out),
.io_oeb(user_io_oeb), .io_oeb(user_io_oeb),
.analog_io(user_analog_io), .analog_io(user_analog_io),
// Independent clock // Independent clock
.user_clock2(mprj_clock2), .user_clock2(mprj_clock2),
// IRQ // IRQ
.user_irq(user_irq_core) .user_irq(user_irq_core)
); );
@ -512,6 +534,11 @@ module caravel (
assign gpio_resetn_2_shifted = {mprj_io_loader_resetn, assign gpio_resetn_2_shifted = {mprj_io_loader_resetn,
gpio_resetn_2[`MPRJ_IO_PADS_2-1:1]}; 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 // Clocking control
caravel_clocking clocking( caravel_clocking clocking(
@ -527,8 +554,8 @@ module caravel (
.sel(spi_pll_sel), .sel(spi_pll_sel),
.sel2(spi_pll90_sel), .sel2(spi_pll90_sel),
.ext_reset(ext_reset), // From housekeeping SPI .ext_reset(ext_reset), // From housekeeping SPI
.core_clk(core_clk), .core_clk(caravel_clk),
.user_clk(user_clk), .user_clk(caravel_clk2),
.resetb_sync(core_rstn) .resetb_sync(core_rstn)
); );
@ -548,86 +575,107 @@ module caravel (
.ext_trim(spi_pll_trim) .ext_trim(spi_pll_trim)
); );
// Housekeeping SPI interface // Housekeeping interface
housekeeping_spi housekeeping ( housekeeping housekeeping (
`ifdef USE_POWER_PINS `ifdef USE_POWER_PINS
.vdd(VPWR), .vdd(VPWR),
.vss(VGND), .vss(VGND),
`endif `endif
.RSTB(porb),
.SCK((hk_connect) ? mgmt_out_predata[4] : mgmt_in_data[4]), .wb_clk_i(mprj_clock),
.SDI((hk_connect) ? mgmt_out_predata[2] : mgmt_in_data[2]), .wb_rst_i(mprj_reset),
.CSB((hk_connect) ? mgmt_out_predata[3] : mgmt_in_data[3]),
.SDO(sdo_out_pre), .wb_adr_i(mprj_adr_o_core),
.sdo_enb(sdo_outenb_pre), .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_dco_ena(spi_pll_dco_ena),
.pll_div(spi_pll_div),
.pll_sel(spi_pll_sel), .pll_sel(spi_pll_sel),
.pll90_sel(spi_pll90_sel), .pll90_sel(spi_pll90_sel),
.pll_div(spi_pll_div),
.pll_ena(spi_pll_ena),
.pll_trim(spi_pll_trim), .pll_trim(spi_pll_trim),
.pll_bypass(ext_clk_sel), .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), .irq(irq_spi),
.reset(ext_reset), .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), .trap(trap),
.user_clock(user_clock),
.mask_rev_in(mask_rev), .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 #( .pad_flash_csb(flash_csb_frame),
.BASE_ADR(MPRJ_CTRL_ADR) .pad_flash_csb_oeb(flash_csb_oeb),
) mprj_ctrl ( .pad_flash_clk(flash_clk_frame),
.wb_clk_i(wb_clk_i), .pad_flash_clk_oeb(flash_clk_oeb),
.wb_rst_i(wb_rst_i), .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), .usr1_vcc_pwrgood(mprj_vcc_pwrgood),
.wb_dat_i(cpu_dat_o), .usr2_vcc_pwrgood(mprj2_vcc_pwrgood),
.wb_sel_i(cpu_sel_o), .usr1_vdd_pwrgood(mprj_vdd_pwrgood),
.wb_we_i(cpu_we_o), .usr2_vdd_pwrgood(mprj2_vdd_pwrgood)
.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)
); );
// Each control block sits next to an I/O pad in the user area. // 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]), .serial_clock_out(gpio_clock_1[1:0]),
.mgmt_gpio_in(mgmt_io_in[1:0]), .mgmt_gpio_in(mgmt_io_in[1:0]),
.mgmt_gpio_out({sdo_out, jtag_out}), .mgmt_gpio_out(mgmt_io_out[1:0]),
.mgmt_gpio_oeb({sdo_outenb, jtag_outenb}), .mgmt_gpio_oeb(mgmt_io_oeb[1:0]),
.one(), .one(),
.zero(), .zero(),
@ -720,9 +768,9 @@ module caravel (
.resetn_out(gpio_resetn_1[7:2]), .resetn_out(gpio_resetn_1[7:2]),
.serial_clock_out(gpio_clock_1[7:2]), .serial_clock_out(gpio_clock_1[7:2]),
.mgmt_gpio_in(mgmt_io_in[7:2]), .mgmt_gpio_in(mgmt_io_in[7:2]),
.mgmt_gpio_out(mgmt_io_in[7:2]), .mgmt_gpio_out(mgmt_io_in[7:2]),
.mgmt_gpio_oeb(one_loop1[7:2]), .mgmt_gpio_oeb(one_loop1[7:2]),
.one(one_loop1[7:2]), .one(one_loop1[7:2]),
.zero(), .zero(),
@ -769,9 +817,9 @@ module caravel (
.resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_1-1):8]), .resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_1-1):8]),
.serial_clock_out(gpio_clock_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_in(mgmt_io_in[(`MPRJ_IO_PADS_1-1):8]),
.mgmt_gpio_out(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_oeb(one_loop1[(`MPRJ_IO_PADS_1-1):8]),
.one(one_loop1[(`MPRJ_IO_PADS_1-1):8]), .one(one_loop1[(`MPRJ_IO_PADS_1-1):8]),
.zero(), .zero(),
@ -822,8 +870,8 @@ module caravel (
.serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-2)]), .serial_clock_out(gpio_clock_1[(`MPRJ_IO_PADS_2-1):(`MPRJ_IO_PADS_2-2)]),
.mgmt_gpio_in(mgmt_io_in[(`MPRJ_IO_PADS-1):(`MPRJ_IO_PADS-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_out(mgmt_io_out[3:2]),
.mgmt_gpio_oeb({flash_io3_oeb_core, flash_io2_oeb_core}), .mgmt_gpio_oeb(mgmt_io_oeb[3:2]),
.one(), .one(),
.zero(), .zero(),
@ -870,9 +918,9 @@ module caravel (
.resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_2-3):0]), .resetn_out(gpio_resetn_1[(`MPRJ_IO_PADS_2-3):0]),
.serial_clock_out(gpio_clock_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_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_out(mgmt_io_in[(`MPRJ_IO_PADS-3):(`MPRJ_IO_PADS_1)]),
.mgmt_gpio_oeb(one_loop2), .mgmt_gpio_oeb(one_loop2),
.one(one_loop2), .one(one_loop2),
.zero(), .zero(),
@ -935,28 +983,5 @@ module caravel (
.X(rstb_l) .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 endmodule
// `default_nettype wire // `default_nettype wire

View File

@ -61,30 +61,26 @@
`include "gl/sky130_fd_sc_hvl__lsbufhv2lv_1_wrapped.v" `include "gl/sky130_fd_sc_hvl__lsbufhv2lv_1_wrapped.v"
`include "gl/caravel.v" `include "gl/caravel.v"
`else `else
`include "mgmt_soc.v"
`include "housekeeping_spi.v" `include "digital_pll.v"
`include "caravel_clocking.v" `include "caravel_clocking.v"
`include "mgmt_core.v" `include "user_id_programming.v"
`include "digital_pll.v" `include "clock_div.v"
`include "DFFRAM.v" `include "mprj_io.v"
`include "DFFRAMBB.v" `include "chip_io.v"
`include "storage.v" `include "housekeeping_spi.v"
`include "user_id_programming.v" `include "housekeeping.v"
`include "clock_div.v" `include "mprj_logic_high.v"
`include "storage_bridge_wb.v"
`include "mprj_io.v"
`include "chip_io.v"
`include "mprj_logic_high.v"
`include "mprj2_logic_high.v" `include "mprj2_logic_high.v"
`include "mgmt_protect.v" `include "mgmt_protect.v"
`include "mgmt_protect_hv.v" `include "mgmt_protect_hv.v"
`include "gpio_control_block.v" `include "gpio_control_block.v"
`include "gpio_logic_high.v" `include "gpio_logic_high.v"
`include "sky130_fd_sc_hvl__lsbufhv2lv_1_wrapped.v" `include "sky130_fd_sc_hvl__lsbufhv2lv_1_wrapped.v"
`include "mgmt_core_wrapper.v"
`include "caravel.v" `include "caravel.v"
`endif `endif
`include "simple_por.v" `include "simple_por.v"
`include "sram_1rw1r_32_256_8_sky130.v"
`endif `endif

1237
verilog/rtl/housekeeping.v Normal file

File diff suppressed because it is too large Load Diff

View File

@ -14,320 +14,13 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
`default_nettype none `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 // SPI controller for Caravel
// 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.
//
//----------------------------------------------------------- //-----------------------------------------------------------
// housekeeping_spi.v
//------------------------------------------------------------
// 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_slave.v // General purpose SPI module for the Caravel chip
//------------------------------------------------------
// General purpose SPI slave module for the Caravel chip
//------------------------------------------------------ //------------------------------------------------------
// Written by Tim Edwards // Written by Tim Edwards
// efabless, inc., September 28, 2020 // efabless, inc., September 28, 2020
@ -379,7 +72,7 @@ endmodule // housekeeping_spi
`define USERPASS 3'b100 `define USERPASS 3'b100
`define MGMTPASS 3'b101 `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, sdoenb, idata, odata, oaddr, rdstb, wrstb,
pass_thru_mgmt, pass_thru_mgmt_delay, pass_thru_mgmt, pass_thru_mgmt_delay,
pass_thru_user, pass_thru_user_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 // ! csb_reset
end // always @ SCK end // always @ SCK
endmodule // housekeeping_spi_slave endmodule // housekeeping_spi
`default_nettype wire `default_nettype wire

View File

@ -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

View File

@ -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<IO_WORDS; i=i+1) begin
assign io_data_sel[i] = (iomem_addr[7:0] == (IODATA + i*4));
end
for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4));
assign mgmt_gpio_oeb[i] = ~io_ctrl[i][INP_DIS];
end
endgenerate
// Set selection and iomem_rdata_pre
assign selected = xfer_sel || pwr_data_sel || irq_data_sel || (|io_data_sel) || (|io_ctrl_sel);
wire [31:0] io_data_arr[0:IO_WORDS-1];
wire [31:0] io_ctrl_arr[0:`MPRJ_IO_PADS-1];
generate
for (i=0; i<IO_WORDS; i=i+1) begin
assign io_data_arr[i] = {{(31-`rtop){1'b0}}, mgmt_gpio_in[`wtop:`wbot]};
end
for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
assign io_ctrl_arr[i] = {{(32-IO_CTRL_BITS){1'b0}}, io_ctrl[i]};
end
endgenerate
integer j;
always @ * begin
iomem_rdata_pre = 'b0;
if (xfer_sel) begin
iomem_rdata_pre = {31'b0, busy};
end else if (pwr_data_sel) begin
iomem_rdata_pre = {{(32-`MPRJ_PWR_PADS){1'b0}}, pwr_ctrl_out};
end else if (irq_data_sel) begin
iomem_rdata_pre = {29'b0, user_irq_ena};
end else if (|io_data_sel) begin
for (j=0; j<IO_WORDS; j=j+1) begin
if (io_data_sel[j]) begin
iomem_rdata_pre = io_data_arr[j];
end
end
end else begin
for (j=0; j<`MPRJ_IO_PADS; j=j+1) begin
if (io_ctrl_sel[j]) begin
iomem_rdata_pre = io_ctrl_arr[j];
end
end
end
end
// General I/O transfer
always @(posedge clk) begin
if (!resetn) begin
iomem_rdata <= 0;
iomem_ready <= 0;
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;
if (selected) begin
iomem_rdata <= iomem_rdata_pre;
end
end
end
end
// I/O write of xfer bit. Also handles iomem_ready signal and power data.
always @(posedge clk) begin
if (!resetn) begin
xfer_ctrl <= 0;
pwr_ctrl_out <= 0;
user_irq_ena <= 0;
end else begin
if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
if (xfer_sel) begin
if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[0];
end else if (pwr_data_sel) begin
if (iomem_wstrb[0]) pwr_ctrl_out <= iomem_wdata[`MPRJ_PWR_PADS-1:0];
end else if (irq_data_sel) begin
if (iomem_wstrb[0]) user_irq_ena <= iomem_wdata[2:0];
end
end else begin
xfer_ctrl <= 1'b0; // Immediately self-resetting
end
end
end
// I/O transfer of gpio data to/from user project region under management
// SoC control
generate
for (i=0; i<IO_WORDS; i=i+1) begin
always @(posedge clk) begin
if (!resetn) begin
mgmt_gpio_out[`wtop:`wbot] <= 'd0;
end else begin
if (iomem_valid && !iomem_ready && iomem_addr[31:8] ==
BASE_ADR[31:8]) begin
if (io_data_sel[i]) begin
if (iomem_wstrb[0]) begin
mgmt_gpio_out[`wtop:`wbot] <= iomem_wdata[`rtop:0];
end
end
end
end
end
end
for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
always @(posedge clk) begin
if (!resetn) begin
// NOTE: This initialization must match the defaults passed
// to the control blocks. Specifically, 0x1803 is for a
// bidirectional pad, and 0x0403 is for a simple input pad
if ((i < 2) || (i >= `MPRJ_IO_PADS - 2)) begin
io_ctrl[i] <= 'h1803;
end else begin
io_ctrl[i] <= 'h0403;
end
end else begin
if (iomem_valid && !iomem_ready &&
iomem_addr[31:8] == BASE_ADR[31:8]) begin
if (io_ctrl_sel[i]) begin
// NOTE: Byte-wide write to io_ctrl is prohibited
if (iomem_wstrb[0])
io_ctrl[i] <= iomem_wdata[IO_CTRL_BITS-1:0];
end
end
end
end
end
endgenerate
reg [3:0] xfer_count;
reg [4:0] pad_count_1;
reg [5:0] pad_count_2;
reg [1:0] xfer_state;
reg serial_clock;
reg serial_resetn;
reg [IO_CTRL_BITS-1:0] serial_data_staging_1;
reg [IO_CTRL_BITS-1:0] serial_data_staging_2;
wire serial_data_out_1;
wire serial_data_out_2;
assign serial_data_out_1 = (ext_enable == 1'b1) ? ext_data_1 :
serial_data_staging_1[IO_CTRL_BITS-1];
assign serial_data_out_2 = (ext_enable == 1'b1) ? ext_data_2 :
serial_data_staging_2[IO_CTRL_BITS-1];
assign busy = (xfer_state != `IDLE);
always @(posedge clk or negedge resetn) begin
if (resetn == 1'b0) begin
xfer_state <= `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
if (ext_enable == 1'b1) begin
serial_clock <= ext_clock;
serial_resetn <= ext_resetn;
end else if (xfer_state == `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 (xfer_ctrl == 1'b1) begin
xfer_state <= `START;
end
end else if (xfer_state == `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 <= `XBYTE;
serial_data_staging_1 <= io_ctrl[pad_count_1];
serial_data_staging_2 <= io_ctrl[pad_count_2];
end else if (xfer_state == `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 <= `LOAD;
end else begin
xfer_state <= `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 else if (xfer_state == `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 <= `IDLE;
end
end
end
end
endmodule
`default_nettype wire

View File

@ -1,180 +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 sysctrl_wb #(
parameter BASE_ADR = 32'h2F00_0000,
parameter PWRGOOD = 8'h00,
parameter CLK_OUT = 8'h04,
parameter TRAP_OUT = 8'h08,
parameter IRQ_SRC = 8'h0c
) (
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 usr1_vcc_pwrgood,
input usr2_vcc_pwrgood,
input usr1_vdd_pwrgood,
input usr2_vdd_pwrgood,
output clk1_output_dest,
output clk2_output_dest,
output trap_output_dest,
output irq_7_inputsrc,
output irq_8_inputsrc
);
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;
sysctrl #(
.BASE_ADR(BASE_ADR),
.PWRGOOD(PWRGOOD),
.CLK_OUT(CLK_OUT),
.TRAP_OUT(TRAP_OUT),
.IRQ_SRC(IRQ_SRC)
) sysctrl (
.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),
.usr1_vcc_pwrgood(usr1_vcc_pwrgood),
.usr2_vcc_pwrgood(usr2_vcc_pwrgood),
.usr1_vdd_pwrgood(usr1_vdd_pwrgood),
.usr2_vdd_pwrgood(usr2_vdd_pwrgood),
.clk1_output_dest(clk1_output_dest),
.clk2_output_dest(clk2_output_dest),
.trap_output_dest(trap_output_dest),
.irq_8_inputsrc(irq_8_inputsrc),
.irq_7_inputsrc(irq_7_inputsrc)
);
endmodule
module sysctrl #(
parameter BASE_ADR = 32'h2300_0000,
parameter PWRGOOD = 8'h00,
parameter CLK_OUT = 8'h04,
parameter TRAP_OUT = 8'h08,
parameter IRQ_SRC = 8'h0c
) (
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 usr1_vcc_pwrgood,
input usr2_vcc_pwrgood,
input usr1_vdd_pwrgood,
input usr2_vdd_pwrgood,
output clk1_output_dest,
output clk2_output_dest,
output trap_output_dest,
output irq_7_inputsrc,
output irq_8_inputsrc
);
reg clk1_output_dest;
reg clk2_output_dest;
reg trap_output_dest;
reg irq_7_inputsrc;
reg irq_8_inputsrc;
wire usr1_vcc_pwrgood;
wire usr2_vcc_pwrgood;
wire usr1_vdd_pwrgood;
wire usr2_vdd_pwrgood;
wire pwrgood_sel;
wire clk_out_sel;
wire trap_out_sel;
wire irq_sel;
assign pwrgood_sel = (iomem_addr[7:0] == PWRGOOD);
assign clk_out_sel = (iomem_addr[7:0] == CLK_OUT);
assign trap_out_sel = (iomem_addr[7:0] == TRAP_OUT);
assign irq_sel = (iomem_addr[7:0] == IRQ_SRC);
always @(posedge clk) begin
if (!resetn) begin
clk1_output_dest <= 0;
clk2_output_dest <= 0;
trap_output_dest <= 0;
irq_7_inputsrc <= 0;
irq_8_inputsrc <= 0;
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;
if (pwrgood_sel) begin
iomem_rdata <= {28'd0, usr2_vdd_pwrgood, usr1_vdd_pwrgood,
usr2_vcc_pwrgood, usr1_vcc_pwrgood};
// These are read-only bits; no write behavior on wstrb.
end else if (clk_out_sel) begin
iomem_rdata <= {30'd0, clk2_output_dest, clk1_output_dest};
if (iomem_wstrb[0]) begin
clk1_output_dest <= iomem_wdata[0];
clk2_output_dest <= iomem_wdata[1];
end
end else if (trap_out_sel) begin
iomem_rdata <= {31'd0, trap_output_dest};
if (iomem_wstrb[0])
trap_output_dest <= iomem_wdata[0];
end else if (irq_sel) begin
iomem_rdata <= {30'd0, irq_8_inputsrc, irq_7_inputsrc};
if (iomem_wstrb[0]) begin
irq_7_inputsrc <= iomem_wdata[0];
irq_8_inputsrc <= iomem_wdata[1];
end
end
end
end
end
endmodule
`default_nettype wire