Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/ref/dev_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ Then load the bitstream onto Genesys 2:
openFPGALoader -b genesys2 build/lowrisc_mocha_chip_mocha_genesys2_0/synth-vivado/lowrisc_mocha_chip_mocha_genesys2_0.bit
```

For the SD card tests, you will also need to insert a FAT32-formatted microSD card containing the "lorem.ips" file (see sw/device/tests/spi_host/lorem_text.h).

## Verification

To run block-level verification you can use the following command:
Expand Down
26 changes: 22 additions & 4 deletions hw/top_chip/data/pins_genesys2.xdc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ set_property -dict { PACKAGE_PIN AB25 IOSTANDARD LVCMOS33 } [get_ports { ftdi_r

## GPIO
# Inputs
# User switches
set_property -dict { PACKAGE_PIN G19 IOSTANDARD LVCMOS18 } [get_ports { gpio_i[0] }]; # SW0 (VADJ)
set_property -dict { PACKAGE_PIN G25 IOSTANDARD LVCMOS18 } [get_ports { gpio_i[1] }]; # SW1 (VADJ)
set_property -dict { PACKAGE_PIN H24 IOSTANDARD LVCMOS18 } [get_ports { gpio_i[2] }]; # SW2 (VADJ)
Expand All @@ -20,11 +21,13 @@ set_property -dict { PACKAGE_PIN N19 IOSTANDARD LVCMOS18 } [get_ports { gpio_i
set_property -dict { PACKAGE_PIN P19 IOSTANDARD LVCMOS18 } [get_ports { gpio_i[5] }]; # SW5 (VADJ)
set_property -dict { PACKAGE_PIN P26 IOSTANDARD LVCMOS33 } [get_ports { gpio_i[6] }]; # SW6 (VCC3V3)
set_property -dict { PACKAGE_PIN P27 IOSTANDARD LVCMOS33 } [get_ports { gpio_i[7] }]; # SW7 (VCC3V3)

# Bootstrap pin, should be pulled down during boot to enter bootstrap mode.
set_property -dict { PACKAGE_PIN AB29 IOSTANDARD LVCMOS33 PULLTYPE PULLUP } [get_ports { gpio_i[8] }];
# Bootstrap pin, should be pulled down during boot to enter bootstrap mode.
set_property -dict { PACKAGE_PIN AB29 IOSTANDARD LVCMOS33 PULLTYPE PULLUP } [get_ports { gpio_i[8] }]; # PROG_RXFN
# Micro SD card presence detect line (low = card present)
set_property -dict { PACKAGE_PIN P28 IOSTANDARD LVCMOS33 } [get_ports { gpio_i[9] }]; # SD_CD

# Outputs
# User LEDs
set_property -dict { PACKAGE_PIN T28 IOSTANDARD LVCMOS33 } [get_ports { gpio_o[0] }]; # LED0
set_property -dict { PACKAGE_PIN V19 IOSTANDARD LVCMOS33 } [get_ports { gpio_o[1] }]; # LED1
set_property -dict { PACKAGE_PIN U30 IOSTANDARD LVCMOS33 } [get_ports { gpio_o[2] }]; # LED2
Expand All @@ -33,6 +36,8 @@ set_property -dict { PACKAGE_PIN V20 IOSTANDARD LVCMOS33 } [get_ports { gpio_o
set_property -dict { PACKAGE_PIN V26 IOSTANDARD LVCMOS33 } [get_ports { gpio_o[5] }]; # LED5
set_property -dict { PACKAGE_PIN W24 IOSTANDARD LVCMOS33 } [get_ports { gpio_o[6] }]; # LED6
set_property -dict { PACKAGE_PIN W23 IOSTANDARD LVCMOS33 } [get_ports { gpio_o[7] }]; # LED7
# Micro SD card power (VDD) control (active-low, ext. pull-up)
set_property -dict { PACKAGE_PIN AE24 IOSTANDARD LVCMOS33 } [get_ports { gpio_o[8] }]; # SD_RESET

## UART
set_property -dict { PACKAGE_PIN Y20 IOSTANDARD LVCMOS33 } [get_ports { uart_rx_i }];
Expand All @@ -48,7 +53,7 @@ set_property -dict { PACKAGE_PIN Y23 IOSTANDARD LVCMOS33 } [get_ports { uart_t
set_property -dict { PACKAGE_PIN T26 IOSTANDARD LVCMOS33 PULLTYPE PULLUP } [get_ports { i2c_scl_io }];
set_property -dict { PACKAGE_PIN T27 IOSTANDARD LVCMOS33 PULLTYPE PULLUP } [get_ports { i2c_sda_io }];

## SPI (PMOD Header JD)
## SPI Device (PMOD Header JD)
set_property -dict { PACKAGE_PIN W28 IOSTANDARD LVCMOS33 PULLTYPE PULLDOWN } [get_ports { spi_device_sd_o }];
set_property -dict { PACKAGE_PIN W27 IOSTANDARD LVCMOS33 PULLTYPE PULLDOWN } [get_ports { spi_device_sd_i }];
set_property -dict { PACKAGE_PIN W29 IOSTANDARD LVCMOS33 PULLTYPE PULLUP } [get_ports { spi_device_csb_i }];
Expand All @@ -71,3 +76,16 @@ set_property -dict { PACKAGE_PIN AJ11 IOSTANDARD LVCMOS15 } [get_ports { eth_tx
set_property -dict { PACKAGE_PIN AK10 IOSTANDARD LVCMOS15 } [get_ports { eth_tx_d[3] }];
set_property -dict { PACKAGE_PIN AF12 IOSTANDARD LVCMOS15 } [get_ports { eth_mdc }];
set_property -dict { PACKAGE_PIN AG12 IOSTANDARD LVCMOS15 } [get_ports { eth_mdio }];

## SPI Host (MicroSD card slot)
set_property -dict { PACKAGE_PIN R28 IOSTANDARD LVCMOS33 } [get_ports { spi_host_sck_o }]; # SD_SCLK
set_property -dict { PACKAGE_PIN R26 IOSTANDARD LVCMOS33 } [get_ports { spi_host_sd_i }]; # SD_DAT0
# set_property -dict { PACKAGE_PIN R30 IOSTANDARD LVCMOS33 } [get_ports { microsd_dat1 }]; # SD_DAT1 unused in SPI bus mode
# set_property -dict { PACKAGE_PIN P29 IOSTANDARD LVCMOS33 } [get_ports { microsd_dat2 }]; # SD_DAT2 unused in SPI bus mode
set_property -dict { PACKAGE_PIN T30 IOSTANDARD LVCMOS33 } [get_ports { spi_host_csb_o }]; # SD_DAT3
set_property -dict { PACKAGE_PIN R29 IOSTANDARD LVCMOS33 } [get_ports { spi_host_sd_o }]; # SD_CMD
# SPI Host signal copies for external logic analyser on PMOD "JB"
set_property -dict { PACKAGE_PIN W26 IOSTANDARD LVCMOS33 } [get_ports { spi_host_sck_o_dbg_o }]; # JB2_N (PMOD 4)
set_property -dict { PACKAGE_PIN V25 IOSTANDARD LVCMOS33 } [get_ports { spi_host_sd_i_dbg_o }]; # JB2_P (PMOD 3)
set_property -dict { PACKAGE_PIN V29 IOSTANDARD LVCMOS33 } [get_ports { spi_host_csb_o_dbg_o }]; # JB1_P (PMOD 1)
set_property -dict { PACKAGE_PIN V30 IOSTANDARD LVCMOS33 } [get_ports { spi_host_sd_o_dbg_o }]; # JB1_N (PMOD 2)
1 change: 1 addition & 0 deletions hw/top_chip/dv/verilator/top_chip_verilator.core
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ filesets:
- lowrisc:dv:sw_test_status
- lowrisc:dv:dv_test_status
- lowrisc:sonata:i2cdpi
- lowrisc:sonata:spidevicedpi

files:
- dram_wrapper_sim.sv: { file_type: systemVerilogSource }
Expand Down
59 changes: 39 additions & 20 deletions hw/top_chip/dv/verilator/top_chip_verilator.sv
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,25 @@ module top_chip_verilator (
logic uart_rx;
logic uart_tx;

// SPI signals
// SPI device signals
logic spi_device_sck;
logic spi_device_csb;
logic [3:0] qspi_device_sdo;
logic [3:0] qspi_device_sdo_en;
logic spi_device_sdi;

// SPI host signals
logic spi_host_sck_output, spi_host_csb_output;
logic spi_host_sck_en_output, spi_host_csb_en_output;
logic spi_host_input;
logic [3:0] spi_host_sd_output;
logic [3:0] spi_host_sd_en_output;
logic microsd_det;

// AXI signals
top_pkg::axi_dram_req_t dram_req;
top_pkg::axi_dram_resp_t dram_resp;

logic [3:0] spi_host_sd;
logic [3:0] spi_host_sd_en;

// CHERI Mocha top
top_chip_system #(
.SramInitFile(""),
Expand All @@ -52,7 +57,7 @@ module top_chip_verilator (
.clk_i,
.rst_ni,

.gpio_i (gpio_inputs),
.gpio_i ({gpio_inputs[31:10], microsd_det, gpio_inputs[8:0]}),
.gpio_o (gpio_outputs),
.gpio_en_o (gpio_en_outputs),

Expand All @@ -77,17 +82,15 @@ module top_chip_verilator (
.spi_device_sd_i ({3'h0, spi_device_sdi}), // SPI MOSI = QSPI DQ0
.spi_device_tpm_csb_i ('0),

.spi_host_sck_o ( ),
.spi_host_sck_en_o ( ),
.spi_host_csb_o ( ),
.spi_host_csb_en_o ( ),
.spi_host_sd_o (spi_host_sd),
.spi_host_sd_en_o (spi_host_sd_en),
// Mapping output 0 to input 1 because legacy SPI does not allow
// bi-directional wires.
// This only works in standard mode where sd_o[0]=COPI and
// sd_i[1]=CIPO.
.spi_host_sd_i ({2'b0, spi_host_sd_en[0] ? spi_host_sd[0] : 1'b0, 1'b0}),
.spi_host_sck_o (spi_host_sck_output),
.spi_host_sck_en_o (spi_host_sck_en_output),
.spi_host_csb_o (spi_host_csb_output),
.spi_host_csb_en_o (spi_host_csb_en_output),
.spi_host_sd_o (spi_host_sd_output),
.spi_host_sd_en_o (spi_host_sd_en_output),
// Legacy SPI present in SD cards does not allow bi-directional wires.
// Work in standard mode where sd_o[0]=COPI and sd_i[1]=CIPO.
.spi_host_sd_i ({2'b0, spi_host_input, 1'b0}), // SPI CIPO = QSPI DQ1

.dram_req_o (dram_req),
.dram_resp_i (dram_resp),
Expand All @@ -99,8 +102,7 @@ module top_chip_verilator (
);

// No support for dual or quad SPI in loopback mode right now.
logic unused_spi_host = (|spi_host_sd[3:2]) | spi_host_sd[0] |
(|spi_host_sd_en[3:2]) | spi_host_sd_en[0];
logic unused_spi_host = |{spi_host_sd_output[3:1], spi_host_sd_en_output[3:1]};

// Virtual GPIO
gpiodpi #(
Expand Down Expand Up @@ -152,8 +154,25 @@ module top_chip_verilator (
.spi_device_sck_o (spi_device_sck),
.spi_device_csb_o (spi_device_csb),
.spi_device_sdi_o (spi_device_sdi),
.spi_device_sdo_i (qspi_device_sdo[1]), // SPI MISO = QSPI DQ1
.spi_device_sdo_en_i(qspi_device_sdo_en[1]) // SPI MISO = QSPI DQ1
.spi_device_sdo_i (qspi_device_sdo[1]), // SPI CIPO = QSPI DQ1
.spi_device_sdo_en_i(qspi_device_sdo_en[1]) // SPI CIPO = QSPI DQ1
);

// Virtual SPI Device - model an SD card (in a limited way)
spidevicedpi #(
.ID ("microsd"),
.NDevices (1),
.DataW (1),
.OOB_InW (1),
.OOB_OutW (1)
) u_spidevicedpi_microsd (
.rst_ni,
.sck (spi_host_sck_en_output ? spi_host_sck_output : 1'b0),
.cs (spi_host_csb_en_output ? spi_host_csb_output : 1'b0),
.copi (spi_host_sd_en_output[0] ? spi_host_sd_output[0] : 1'b0), // SPI COPI = QSPI DQ0
.cipo (spi_host_input),
.oob_in ( ), // not used
.oob_out(microsd_det)
);

`define DUT u_top_chip_system
Expand Down
95 changes: 70 additions & 25 deletions hw/top_chip/rtl/chip_mocha_genesys2.sv
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ module chip_mocha_genesys2 #(
input logic ext_rst_ni,
input logic ftdi_rst_ni,

// GPIO - enough for the user switches and LEDs as a starting point
input logic [8:0] gpio_i,
output logic [7:0] gpio_o,
// GPIO
input logic [9:0] gpio_i,
output logic [8:0] gpio_o,

// UART
input logic uart_rx_i,
Expand All @@ -26,13 +26,24 @@ module chip_mocha_genesys2 #(
inout logic i2c_scl_io,
inout logic i2c_sda_io,

// SPI
// SPI Device
input logic spi_device_sck_i,
input logic spi_device_csb_i,
input logic spi_device_sd_i,
output logic spi_device_sd_o,
output logic spien,

// SPI Host
output logic spi_host_sck_o,
output logic spi_host_csb_o,
input logic spi_host_sd_i,
output logic spi_host_sd_o,
// SPI Host signal copies for external logic analyser on PMOD "JB"
output logic spi_host_sck_o_dbg_o,
output logic spi_host_csb_o_dbg_o,
output logic spi_host_sd_i_dbg_o,
output logic spi_host_sd_o_dbg_o,

// DDR3
inout wire [31:0] ddr3_dq,
inout wire [ 3:0] ddr3_dqs_n,
Expand Down Expand Up @@ -116,9 +127,10 @@ module chip_mocha_genesys2 #(
logic i2c_scl_en_output, i2c_sda_en_output;
logic [3:0] qspi_device_sdo;
logic [3:0] qspi_device_sdo_en;

logic [3:0] spi_host_sd;
logic [3:0] spi_host_sd_en;
logic spi_host_sck_output, spi_host_csb_output;
logic spi_host_sck_en_output, spi_host_csb_en_output;
logic [3:0] spi_host_sd_output;
logic [3:0] spi_host_sd_en_output;

// AXI signals
// Tag controller to CDC FIFO, synchronous to u_top_chip_system.clkmgr_clocks.clk_main_infra
Expand Down Expand Up @@ -213,7 +225,7 @@ module chip_mocha_genesys2 #(
.rst_ni (rst_n_sync_50m),

// GPIO
.gpio_i ({23'd0, gpio_i}),
.gpio_i (32'(gpio_i)),
.gpio_o (gpio_outputs),
.gpio_en_o (gpio_en_outputs),

Expand All @@ -239,21 +251,17 @@ module chip_mocha_genesys2 #(
.spi_device_csb_i (spi_device_csb_i),
.spi_device_sd_o (qspi_device_sdo),
.spi_device_sd_en_o (qspi_device_sdo_en),
.spi_device_sd_i ({3'h0, spi_device_sd_i}), // SPI MOSI = QSPI DQ0
.spi_device_sd_i ({3'h0, spi_device_sd_i}), // SPI COPI = QSPI DQ0
.spi_device_tpm_csb_i ('0),

// SPI host
.spi_host_sck_o ( ),
.spi_host_sck_en_o ( ),
.spi_host_csb_o ( ),
.spi_host_csb_en_o ( ),
.spi_host_sd_o (spi_host_sd),
.spi_host_sd_en_o (spi_host_sd_en),
// Mapping output 0 to input 1 because legacy SPI does not allow
// bi-directional wires.
// This only works in standard mode where sd_o[0]=COPI and
// sd_i[1]=CIPO.
.spi_host_sd_i ({2'b0, spi_host_sd_en[0] ? spi_host_sd[0] : 1'b0, 1'b0}),
.spi_host_sck_o (spi_host_sck_output),
.spi_host_sck_en_o (spi_host_sck_output_en),
.spi_host_csb_o (spi_host_csb_output),
.spi_host_csb_en_o (spi_host_csb_output_en),
.spi_host_sd_o (spi_host_sd_output),
.spi_host_sd_en_o (spi_host_sd_en_output),
.spi_host_sd_i ({2'b00, spi_host_sd_i, 1'b0}), // SPI CIPO = QSPI DQ1

// DRAM
.dram_req_o (dram_req),
Expand All @@ -269,7 +277,7 @@ module chip_mocha_genesys2 #(

// GPIO tri-state output drivers
// Instantiate for only the outputs connected to an FPGA pin
for (genvar ii = 0; ii < 8; ii++) begin : gen_gpio_o
for (genvar ii = 0; ii < $bits(gpio_o); ii++) begin : gen_gpio_o
OBUFT obuft (
.I(gpio_outputs[ii]),
.T(~gpio_en_outputs[ii]),
Expand All @@ -291,13 +299,50 @@ module chip_mocha_genesys2 #(
.O (i2c_sda_input)
);

// SPI tri-state output driver
OBUFT spi_obuft (
.I(qspi_device_sdo[1]), // SPI MISO = QSPI DQ1
.T(~qspi_device_sdo_en[1]), // SPI MISO = QSPI DQ1
// SPI device tri-state output driver
OBUFT spi_device_obuft (
.I(qspi_device_sdo[1]), // SPI CIPO = QSPI DQ1
.T(~qspi_device_sdo_en[1]), // SPI CIPO = QSPI DQ1
.O(spi_device_sd_o)
);

// SPI host tri-state output drivers
OBUFT spi_host_sck_obuft (
.I(spi_host_sck_output),
.T(~spi_host_sck_output_en),
.O(spi_host_sck_o)
);
OBUFT spi_host_csb_obuft (
.I(spi_host_csb_output),
.T(~spi_host_csb_output_en),
.O(spi_host_csb_o)
);
// Legacy SPI present in SD cards does not allow bi-directional wires.
// Work in standard mode where sd_o[0]=COPI and sd_i[1]=CIPO.
// Other data outputs are unused.
OBUFT spi_host_sd_obuft (
.I(spi_host_sd_output[0]), // SPI COPI = QSPI DQ0
.T(~spi_host_sd_en_output[0]), // SPI COPI = QSPI DQ0
.O(spi_host_sd_o)
);
// SPI Host signal copies for external logic analyser on PMOD "JB"
assign spi_host_sd_i_dbg_o = spi_host_sd_i;
OBUFT spi_host_sck_obuft_dbg (
.I(spi_host_sck_output),
.T(~spi_host_sck_output_en),
.O(spi_host_sck_o_dbg_o)
);
OBUFT spi_host_csb_obuft_dbg (
.I(spi_host_csb_output),
.T(~spi_host_csb_output_en),
.O(spi_host_csb_o_dbg_o)
);
OBUFT spi_host_sd_obuft_dbg (
.I(spi_host_sd_output[0]), // SPI COPI = QSPI DQ0
.T(~spi_host_sd_en_output[0]), // SPI COPI = QSPI DQ0
.O(spi_host_sd_o_dbg_o)
);

// Async AXI FIFO from tag controller to MIG
axi_cdc #(
.aw_chan_t (top_pkg::axi_dram_aw_chan_t),
Expand Down
9 changes: 8 additions & 1 deletion sw/device/lib/hal/spi_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,24 @@
#define SPI_HOST_CONTROL_SPIEN_MASK (1u << 31)
#define SPI_HOST_CONTROL_OUTPUTEN_MASK (1u << 29)
#define SPI_HOST_STATUS_REG (0x14)
#define SPI_HOST_STATUS_READY_MASK (1u << 31)
#define SPI_HOST_STATUS_ACTIVE_MASK (1u << 30)
#define SPI_HOST_STATUS_TXFULL_MASK (1u << 29)
#define SPI_HOST_STATUS_RXEMPTY_MASK (1u << 24)
#define SPI_HOST_CONFIGOPTS_REG (0x18)
#define SPI_HOST_CSID_REG (0x1C)
#define SPI_HOST_COMMAND_REG (0x20)
#define SPI_HOST_COMMAND_CSAAT_OFFSET (0)
#define SPI_HOST_COMMAND_DIRECTION_OFFSET (3)
#define SPI_HOST_COMMAND_DIRECTION_RECEIVE (1 << SPI_HOST_COMMAND_DIRECTION_OFFSET)
#define SPI_HOST_COMMAND_DIRECTION_TRANSMIT (2 << SPI_HOST_COMMAND_DIRECTION_OFFSET)
#define SPI_HOST_COMMAND_DIRECTION_BIDIRECTIONAL (3 << SPI_HOST_COMMAND_DIRECTION_OFFSET)
#define SPI_HOST_COMMAND_LEN_OFF (5)
#define SPI_HOST_COMMAND_LEN_MASK (0xFFFFF << SPI_HOST_COMMAND_LEN_OFF)
#define SPI_HOST_COMMAND_LEN_MAX (0xFFFFF)
#define SPI_HOST_COMMAND_LEN_MASK (SPI_HOST_COMMAND_LEN_MAX << SPI_HOST_COMMAND_LEN_OFF)
#define SPI_HOST_RXDATA_REG (0x24)
#define SPI_HOST_TXDATA_REG (0x28)
#define SPI_HOST_ERROR_STATUS_REG (0x30)

typedef void *spi_host_t;

Expand Down
25 changes: 25 additions & 0 deletions sw/device/lib/hal/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "hal/uart.h"
#include "hal/mmio.h"
#include "hal/mocha.h"
#include <stddef.h>
#include <stdint.h>

void uart_init(uart_t uart)
Expand Down Expand Up @@ -106,3 +107,27 @@ void uart_puts(uart_t uart, const char *str)
uart_putchar(uart, *str++);
}
}

// Dump out a sequence of bytes as hexadecimal and ASCII text.
void uart_dump_bytes(uart_t uart, const uint8_t buf[], size_t len)
{
for (size_t off = 0u; off < len; ++off) {
uart_putchar(uart, '0' + (buf[off] >> 4));
uart_putchar(uart, '0' + (buf[off] & 0xfu));
if ((off & 0xfu) == 0xfu) {
uart_puts(uart, " : ");
for (size_t aoff = (off & ~0xfu); aoff <= off; aoff++) {
char text[2];
text[0] = buf[aoff];
if (text[0] < ' ' || '~' < text[0]) { // non-printable
text[0] = '.';
}
text[1] = '\0';
uart_puts(uart, text);
}
uart_putchar(uart, '\n');
} else {
uart_putchar(uart, ' ');
}
}
}
Loading
Loading