#define MASTER_CLK_RATE 100000000 // 100 MHz
////////////////////////////////////////////////////////////////
//
// Memory map for embedded wishbone bus
//
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
// Main RAM, Slave 0
#define RAM_BASE 0x0000
////////////////////////////////////////////////////////////////
// Buffer Pool RAM, Slave 1
//
// The buffers themselves are located in Slave 1, Buffer Pool RAM.
// The status registers are in Slave 5, Buffer Pool Status.
// The control register is in Slave 7, Settings Bus.
#define BUFFER_POOL_RAM_BASE 0x8000
#define NBUFFERS 8
#define BP_NLINES 0x0200 // number of 32-bit lines in a buffer
#define BP_LAST_LINE (BP_NLINES - 1) // last line in a buffer
#define buffer_pool_ram \
((uint32_t *) BUFFER_POOL_RAM_BASE)
#define buffer_ram(n) (&buffer_pool_ram[(n) * BP_NLINES])
/////////////////////////////////////////////////////
// SPI Core, Slave 2. See core docs for more info
#define SPI_BASE 0xC000 // Base address (16-bit)
typedef struct {
volatile uint32_t txrx0;
volatile uint32_t txrx1;
volatile uint32_t txrx2;
volatile uint32_t txrx3;
volatile uint32_t ctrl;
volatile uint32_t div;
volatile uint32_t ss;
} spi_regs_t;
#define spi_regs ((spi_regs_t *) SPI_BASE)
// Masks for controlling different peripherals
#define SPI_SS_AD9510 1
#define SPI_SS_AD9777 2
#define SPI_SS_RX_DAC 4
#define SPI_SS_RX_ADC 8
#define SPI_SS_RX_DB 16
#define SPI_SS_TX_DAC 32
#define SPI_SS_TX_ADC 64
#define SPI_SS_TX_DB 128
// Masks for different parts of CTRL reg
#define SPI_CTRL_ASS (1<<13)
#define SPI_CTRL_IE (1<<12)
#define SPI_CTRL_LSB (1<<11)
#define SPI_CTRL_TXNEG (1<<10)
#define SPI_CTRL_RXNEG (1<< 9)
#define SPI_CTRL_GO_BSY (1<< 8)
#define SPI_CTRL_CHAR_LEN_MASK 0x7F
////////////////////////////////////////////////
// I2C, Slave 3
// See Wishbone I2C-Master Core Specification.
#define I2C_BASE 0xC400
typedef struct {
volatile uint32_t prescaler_lo; // r/w
volatile uint32_t prescaler_hi; // r/w
volatile uint32_t ctrl; // r/w
volatile uint32_t data; // wr = transmit reg; rd = receive reg
volatile uint32_t cmd_status; // wr = command reg; rd = status reg
} i2c_regs_t;
#define i2c_regs ((i2c_regs_t *) I2C_BASE)
#define I2C_CTRL_EN (1 << 7) // core enable
#define I2C_CTRL_IE (1 << 6) // interrupt enable
//
// STA, STO, RD, WR, and IACK bits are cleared automatically
//
#define I2C_CMD_START (1 << 7) // generate (repeated) start condition
#define I2C_CMD_STOP (1 << 6) // generate stop condition
#define I2C_CMD_RD (1 << 5) // read from slave
#define I2C_CMD_WR (1 << 4) // write to slave
#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1)
#define I2C_CMD_RSVD_2 (1 << 2) // reserved
#define I2C_CMD_RSVD_1 (1 << 1) // reserved
#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt
#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK)
#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected
#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration
#define I2C_ST_RSVD_4 (1 << 4) // reserved
#define I2C_ST_RSVD_3 (1 << 3) // reserved
#define I2C_ST_RSVD_2 (1 << 2) // reserved
#define I2C_ST_TIP (1 << 1) // Transfer-in-progress
#define I2C_ST_IP (1 << 0) // Interrupt pending
////////////////////////////////////////////////
// GPIO, Slave 4
//
// These go to the daughterboard i/o pins
#define GPIO_BASE 0xC800
typedef struct {
volatile uint32_t io; // tx data in high 16, rx in low 16
volatile uint32_t ddr; // 32 bits, 1 means output. tx in high 16, rx in low 16
volatile uint32_t tx_sel; // 16 2-bit fields select which source goes to TX DB
volatile uint32_t rx_sel; // 16 2-bit fields select which source goes to RX DB
} gpio_regs_t;
// each 2-bit sel field is layed out this way
#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg
#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic
#define GPIO_SEL_DEBUG_0 2 // if pin is an output, debug lines from FPGA fabric
#define GPIO_SEL_DEBUG_1 3 // if pin is an output, debug lines from FPGA fabric
#define gpio_base ((gpio_regs_t *) GPIO_BASE)
///////////////////////////////////////////////////
// Buffer Pool Status, Slave 5
//
// The buffers themselves are located in Slave 1, Buffer Pool RAM.
// The status registers are in Slave 5, Buffer Pool Status.
// The control register is in Slave 7, Settings Bus.
#define BUFFER_POOL_STATUS_BASE 0xCC00
typedef struct {
volatile uint32_t last_line[NBUFFERS]; // last line xfer'd in buffer
volatile uint32_t status; // error and done flags
volatile uint32_t hw_config; // see below
} buffer_pool_status_t;
#define buffer_pool_status ((buffer_pool_status_t *) BUFFER_POOL_STATUS_BASE)
/*
* Buffer n's xfer is done.
* Clear this bit by issuing bp_clear_buf(n)
*/
#define BPS_DONE(n) (0x00000001 << (n))
#define BPS_DONE_0 BPS_DONE(0)
#define BPS_DONE_1 BPS_DONE(1)
#define BPS_DONE_2 BPS_DONE(2)
#define BPS_DONE_3 BPS_DONE(3)
#define BPS_DONE_4 BPS_DONE(4)
#define BPS_DONE_5 BPS_DONE(5)
#define BPS_DONE_6 BPS_DONE(6)
#define BPS_DONE_7 BPS_DONE(7)
/*
* Buffer n's xfer had an error.
* Clear this bit by issuing bp_clear_buf(n)
*/
#define BPS_ERROR(n) (0x00000100 << (n))
#define BPS_ERROR_0 BPS_ERROR(0)
#define BPS_ERROR_1 BPS_ERROR(1)
#define BPS_ERROR_2 BPS_ERROR(2)
#define BPS_ERROR_3 BPS_ERROR(3)
#define BPS_ERROR_4 BPS_ERROR(4)
#define BPS_ERROR_5 BPS_ERROR(5)
#define BPS_ERROR_6 BPS_ERROR(6)
#define BPS_ERROR_7 BPS_ERROR(7)
/*
* Buffer n is idle. A buffer is idle if it's not
* DONE, ERROR, or processing a transaction. If it's
* IDLE, it's safe to start a new transaction.
*
* Clear this bit by starting a xfer with
* bp_send_from_buf or bp_receive_to_buf.
*/
#define BPS_IDLE(n) (0x00010000 << (n))
#define BPS_IDLE_0 BPS_IDLE(0)
#define BPS_IDLE_1 BPS_IDLE(1)
#define BPS_IDLE_2 BPS_IDLE(2)
#define BPS_IDLE_3 BPS_IDLE(3)
#define BPS_IDLE_4 BPS_IDLE(4)
#define BPS_IDLE_5 BPS_IDLE(5)
#define BPS_IDLE_6 BPS_IDLE(6)
#define BPS_IDLE_7 BPS_IDLE(7)
/*
* Buffer n has a "slow path" packet in it.
* This bit is orthogonal to the bits above and indicates that
* the FPGA ethernet rx protocol engine has identified this packet
* as one requiring firmware intervention.
*/
#define BPS_SLOWPATH(n) (0x01000000 << (n))
#define BPS_SLOWPATH_0 BPS_SLOWPATH(0)
#define BPS_SLOWPATH_1 BPS_SLOWPATH(1)
#define BPS_SLOWPATH_2 BPS_SLOWPATH(2)
#define BPS_SLOWPATH_3 BPS_SLOWPATH(3)
#define BPS_SLOWPATH_4 BPS_SLOWPATH(4)
#define BPS_SLOWPATH_5 BPS_SLOWPATH(5)
#define BPS_SLOWPATH_6 BPS_SLOWPATH(6)
#define BPS_SLOWPATH_7 BPS_SLOWPATH(7)
#define BPS_DONE_ALL 0x000000ff // mask of all dones
#define BPS_ERROR_ALL 0x0000ff00 // mask of all errors
#define BPS_IDLE_ALL 0x00ff0000 // mask of all idles
#define BPS_SLOWPATH_ALL 0xff000000 // mask of all slowpaths
// The hw_config register
#define HWC_SIMULATION 0x80000000
#define HWC_WB_CLK_DIV_MASK 0x0000000f
/*!
* \brief return non-zero if we're running under the simulator
*/
inline static int
hwconfig_simulation_p(void)
{
return buffer_pool_status->hw_config & HWC_SIMULATION;
}
/*!
* \brief Return Wishbone Clock divisor.
* The processor runs at the Wishbone Clock rate which is MASTER_CLK_RATE / divisor.
*/
inline static int
hwconfig_wishbone_divisor(void)
{
return buffer_pool_status->hw_config & HWC_WB_CLK_DIV_MASK;
}
///////////////////////////////////////////////////
// Ethernet Core, Slave 6
#define ETH_BASE 0xD000
#include "eth_mac_regs.h"
#define eth_mac ((eth_mac_regs_t *) ETH_BASE)
////////////////////////////////////////////////////
// Settings Bus, Slave #7, Not Byte Addressable!
//
// Output-only from processor point-of-view.
// 1KB of address space (== 256 32-bit write-only regs)
#define MISC_OUTPUT_BASE 0xD400
#define TX_PROTOCOL_ENGINE_BASE 0xD480
#define RX_PROTOCOL_ENGINE_BASE 0xD4C0
#define BUFFER_POOL_CTRL_BASE 0xD500
#define DSP_TX_BASE 0xD600
#define DSP_RX_BASE 0xD680
#define LAST_SETTING_REG 0xD7FC // last valid setting register
// --- buffer pool control regs ---
typedef struct {
volatile uint32_t ctrl;
} buffer_pool_ctrl_t;
// buffer pool ports
#define PORT_SERDES 0 // serial/deserializer
#define PORT_DSP 1 // DSP tx or rx pipeline
#define PORT_ETH 2 // ethernet tx or rx
#define PORT_RAM 3 // RAM tx or rx
// the buffer pool ctrl register fields
#define BPC_BUFFER(n) (((n) & 0xf) << 28)
#define BPC_BUFFER_MASK BPC_BUFFER(~0)
#define BPC_BUFFER_0 BPC_BUFFER(0)
#define BPC_BUFFER_1 BPC_BUFFER(1)
#define BPC_BUFFER_2 BPC_BUFFER(2)
#define BPC_BUFFER_3 BPC_BUFFER(3)
#define BPC_BUFFER_4 BPC_BUFFER(4)
#define BPC_BUFFER_5 BPC_BUFFER(5)
#define BPC_BUFFER_6 BPC_BUFFER(6)
#define BPC_BUFFER_7 BPC_BUFFER(7)
#define BPC_BUFFER_NIL BPC_BUFFER(0x8) // disable
#define BPC_PORT(n) (((n) & 0x7) << 25)
#define BPC_PORT_MASK BPC_PORT(~0)
#define BPC_PORT_SERDES BPC_PORT(PORT_SERDES)
#define BPC_PORT_DSP BPC_PORT(PORT_DSP)
#define BPC_PORT_ETH BPC_PORT(PORT_ETH)
#define BPC_PORT_RAM BPC_PORT(PORT_RAM)
#define BPC_PORT_NIL BPC_PORT(0x4) // disable
#define BPC_CLR (1 << 24) // mutually excl commands
#define BPC_READ (1 << 23)
#define BPC_WRITE (1 << 22)
#define BPC_STEP(step) (((step) & 0xf) << 18)
#define BPC_STEP_MASK BPC_STEP(~0)
#define BPC_LAST_LINE(line) (((line) & 0x1ff) << 9)
#define BPC_LAST_LINE_MASK BPC_LAST_LINE(~0)
#define BPC_FIRST_LINE(line) (((line) & 0x1ff) << 0)
#define BPC_FIRST_LINE_MASK BPC_FIRST_LINE(~0)
#define buffer_pool_ctrl ((buffer_pool_ctrl_t *) BUFFER_POOL_CTRL_BASE)
// --- misc outputs ---
typedef struct {
volatile uint32_t clk_ctrl;
volatile uint32_t serdes_ctrl;
volatile uint32_t adc_ctrl;
volatile uint32_t leds;
volatile uint32_t phy_ctrl; // LSB is reset line to eth phy
volatile uint32_t debug_mux_ctrl;
volatile uint32_t ram_page; // FIXME should go somewhere else...
volatile uint32_t flush_icache; // Flush the icache
volatile uint32_t led_src; // HW or SW control for LEDs
} output_regs_t;
#define SERDES_ENABLE 8
#define SERDES_PRBSEN 4
#define SERDES_LOOPEN 2
#define SERDES_RXEN 1
#define ADC_CTRL_ON 0x0F
#define ADC_CTRL_OFF 0x00
// crazy order that matches the labels on the case
#define LED_A (1 << 4)
#define LED_B (1 << 1)
#define LED_C (1 << 3)
#define LED_D (1 << 0)
#define LED_E (1 << 2)
// LED_F // controlled by CPLD
#define LED_RJ45 (1 << 5)
#define output_regs ((output_regs_t *) MISC_OUTPUT_BASE)
// --- dsp tx regs ---
#define MIN_CIC_INTERP 1
#define MAX_CIC_INTERP 128
typedef struct {
volatile int32_t freq;
volatile uint32_t scale_iq; // {scale_i,scale_q}
volatile uint32_t interp_rate;
volatile uint32_t clear_state; // clears out state machine, fifos,
// NOT freq, scale, interp
/*!
* \brief output mux configuration.
*
*
* 3 2 1
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-------------------------------+-------+-------+-------+-------+
* | | DAC1 | DAC0 |
* +-------------------------------+-------+-------+-------+-------+
*
* There are N DUCs (1 now) with complex inputs and outputs.
* There are two DACs.
*
* Each 4-bit DACx field specifies the source for the DAC
* Each subfield is coded like this:
*
* 3 2 1 0
* +-------+
* | N |
* +-------+
*
* N specifies which DUC output is connected to this DAC.
*
* N which interp output
* --- -------------------
* 0 DUC 0 I
* 1 DUC 0 Q
* 2 DUC 1 I
* 3 DUC 1 Q
* F All Zeros
*
* The default value is 0x10
*
*/
volatile uint32_t tx_mux;
} dsp_tx_regs_t;
#define dsp_tx_regs ((dsp_tx_regs_t *) DSP_TX_BASE)
// --- dsp rx regs ---
#define T_NOW (-1)
#define MIN_CIC_DECIM 1
#define MAX_CIC_DECIM 128
typedef struct {
volatile int32_t freq;
volatile uint32_t scale_iq; // {scale_i,scale_q}
volatile uint32_t decim_rate;
volatile uint32_t rx_time; // when to begin reception
volatile uint32_t rx_command; // {now, chain, num_lines(21), lines_per_frame(9)
volatile uint32_t clear_state; // clears out state machine, fifos,
// cmd queue, NOT freq, scale, decim
volatile uint32_t dcoffset_i; // Bit 31 high sets fixed offset mode, using lower 14 bits,
// otherwise it is automatic
volatile uint32_t dcoffset_q; // Bit 31 high sets fixed offset mode, using lower 14 bits
/*!
* \brief input mux configuration.
*
* This determines which ADC (or constant zero) is connected to
* each DDC input. There are N DDCs (1 now). Each has two inputs.
*
*
* Mux value:
*
* 3 2 1
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-------+-------+-------+-------+-------+-------+-------+-------+
* | |Q0 |I0 |
* +-------+-------+-------+-------+-------+-------+-------+-------+
*
* Each 2-bit I field is either 00 (A/D A), 01 (A/D B) or 1X (const zero)
* Each 2-bit Q field is either 00 (A/D A), 01 (A/D B) or 1X (const zero)
*
* The default value is 0x4
*
*/
volatile uint32_t rx_mux; // called adc_mux in dsp_core_rx.v
} dsp_rx_regs_t;
#define dsp_rx_regs ((dsp_rx_regs_t *) DSP_RX_BASE)
#define MK_RX_CMD(num_lines, lines_per_frame, now, chain) \
(((num_lines) << 9) | ((lines_per_frame) & 0x1ff) \
| (((now) & 0x1) << 31) | (((chain) & 0x1) << 30))
/*
* --- ethernet tx protocol engine regs (write only) ---
*
* These registers control the transmit portion of the ethernet
* protocol engine (out of USRP2). The protocol engine handles fifo
* status and sequence number insertion in outgoing packets, and
* automagically generates status packets when required to inform the
* host of changes in fifo availability.
*
* All outgoing packets have their fifo_status field set to the number
* of 32-bit lines of fifo available in the ethernet Rx fifo (see
* usrp2_eth_packet.h). Seqno's are set if FIXME, else 0.
*
* FIXME clean this up once we know how it's supposed to behave.
*/
typedef struct {
volatile uint32_t flags; // not yet fully defined (channel?)
volatile uint32_t mac_dst0123; // 4 bytes of destination mac addr
volatile uint32_t mac_dst45src01; // 2 bytes of dest mac addr; 2 bytes of src mac addr
volatile uint32_t mac_src2345; // 4 bytes of destination mac addr
volatile uint32_t seqno; // Write to init seqno. It autoincs on match
} tx_proto_engine_regs_t;
#define tx_proto_engine ((tx_proto_engine_regs_t *) TX_PROTOCOL_ENGINE_BASE)
/*
* --- ethernet rx protocol engine regs (write only) ---
*
* These registers control the receive portion of the ethernet
* protocol engine (into USRP2). The protocol engine offloads common
* packet inspection operations so that firmware has less to do on
* "fast path" packets.
*
* The registers define conditions which must be matched for a packet
* to be considered a "fast path" packet. If a received packet
* matches the src and dst mac address, ethertype, flags field, and
* expected seqno number it is considered a "fast path" packet, and
* the expected seqno is updated. If the packet fails to satisfy any
* of the above conditions it's a "slow path" packet, and the
* corresponding SLOWPATH flag will be set buffer_status register.
*/
typedef struct {
volatile uint32_t flags; // not yet fully defined (channel?)
volatile uint32_t mac_dst0123; // 4 bytes of destination mac addr
volatile uint32_t mac_dst45src01; // 2 bytes of dest mac addr; 2 bytes of src mac addr
volatile uint32_t mac_src2345; // 4 bytes of destination mac addr
volatile uint32_t ethertype_pad; // ethertype in high 16-bits
} rx_proto_engine_regs_t;
#define rx_proto_engine ((rx_proto_engine_regs_t *) RX_PROTOCOL_ENGINE_BASE)
///////////////////////////////////////////////////
// Simple Programmable Interrupt Controller, Slave 8
#define PIC_BASE 0xD800
// Interrupt request lines
// Bit numbers (LSB == 0) that correpond to interrupts into PIC
#define IRQ_BUFFER 0 // buffer manager
#define IRQ_TIMER 1
#define IRQ_SPI 2
#define IRQ_I2C 3
#define IRQ_PHY 4 // ethernet PHY
#define IRQ_UNDERRUN 5
#define IRQ_OVERRUN 6
#define IRQ_PPS 7 // pulse per second
#define IRQ_UART_RX 8
#define IRQ_UART_TX 9
#define IRQ_SERDES 10
#define IRQ_CLKSTATUS 11
#define IRQ_TO_MASK(x) (1 << (x))
#define PIC_BUFFER_INT IRQ_TO_MASK(IRQ_BUFFER)
#define PIC_TIMER_INT IRQ_TO_MASK(IRQ_TIMER)
#define PIC_SPI_INT IRQ_TO_MASK(IRQ_SPI)
#define PIC_I2C_INT IRQ_TO_MASK(IRQ_I2C)
#define PIC_PHY_INT IRQ_TO_MASK(IRQ_PHY)
#define PIC_UNDERRUN_INT IRQ_TO_MASK(IRQ_UNDERRUN)
#define PIC_OVERRUN_INT IRQ_TO_MASK(IRQ_OVERRUN)
#define PIC_PPS_INT IRQ_TO_MASK(IRQ_PPS)
#define PIC_UART_RX_INT IRQ_TO_MASK(IRQ_UART_RX)
#define PIC_UART_TX_INT IRQ_TO_MASK(IRQ_UART_TX)
#define PIC_SERDES IRQ_TO_MASK(IRQ_SERDES)
#define PIC_CLKSTATUS IRQ_TO_MASK(IRQ_CLKSTATUS)
typedef struct {
volatile uint32_t edge_enable; // mask: 1 -> edge triggered, 0 -> level
volatile uint32_t polarity; // mask: 1 -> rising edge
volatile uint32_t mask; // mask: 1 -> disabled
volatile uint32_t pending; // mask: 1 -> pending; write 1's to clear pending ints
} pic_regs_t;
#define pic_regs ((pic_regs_t *) PIC_BASE)
///////////////////////////////////////////////////
// Timer, Slave 9
#define TIMER_BASE 0xDC00
typedef struct {
volatile uint32_t time; // R: current, W: set time to interrupt
} timer_regs_t;
#define timer_regs ((timer_regs_t *) TIMER_BASE)
///////////////////////////////////////////////////
// UART, Slave 10
#define UART_BASE 0xE000
typedef struct {
// All elements are 8 bits except for clkdiv (16), but we use uint32 to make
// the hardware for decoding easier
volatile uint32_t clkdiv; // Set to 50e6 divided by baud rate (no x16 factor)
volatile uint32_t txlevel; // Number of spaces in the FIFO for writes
volatile uint32_t rxlevel; // Number of available elements in the FIFO for reads
volatile uint32_t txchar; // Write characters to be sent here
volatile uint32_t rxchar; // Read received characters here
} uart_regs_t;
#define uart_regs ((uart_regs_t *) UART_BASE)
///////////////////////////////////////////////////
// ATR Controller, Slave 11
#define ATR_BASE 0xE400
typedef struct {
volatile uint32_t v[16];
} atr_regs_t;
#define ATR_IDLE 0x0 // indicies into v
#define ATR_TX 0x1
#define ATR_RX 0x2
#define ATR_FULL 0x3
#define atr_regs ((atr_regs_t *) ATR_BASE)
///////////////////////////////////////////////////
// Time Sync Controller, Slave 12
#define TIMESYNC_BASE 0xE800
typedef struct {
/*!
* \brief Time sync configuration.
*
*
*
* 3 2 1
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-----------------------------------------------------+-+-+-+-+-+
* | |T|G|X|I|S|
* +-----------------------------------------------------+-+-+-+-+-+
*
* S - Tick source (0 = free run, 1 = pps, default=0)
* I - Tick interrupt enable (not implemented)
* X - Use external sync source (default=1)
* G - PPS edge selection (0=negedge, 1=posedge, default=0)
* T - Trigger sync every pps edge (default=0)
*
*
*/
volatile uint32_t tick_control;
volatile uint32_t tick_interval;
volatile uint32_t delta_time;
volatile uint32_t sync_on_next_pps;
} timesync_regs_t;
#define timesync_regs ((timesync_regs_t *) TIMESYNC_BASE)
#define TSC_SOURCE (1 << 0)
#define TSC_IENABLE (1 << 1)
#define TSC_EXTSYNC (1 << 2)
#define TSC_PPSEDGE (1 << 3)
#define TSC_EVERYPPS (1 << 4)
///////////////////////////////////////////////////
// SD Card SPI interface, Slave 13
// All regs are 8 bits wide, but are accessed as if they are 32 bits
#define SDSPI_BASE 0xEC00
typedef struct {
volatile uint32_t status; // Write a 1 or 0 for controlling CS
volatile uint32_t clkdiv;
volatile uint32_t send_dat;
volatile uint32_t receive_dat;
} sdspi_regs_t;
#define sdspi_regs ((sdspi_regs_t *) SDSPI_BASE)
///////////////////////////////////////////////////
// External RAM interface, Slave 14
// Pages are 1K. Page is 10 bits, set by a control register
// output_regs->ram_page
#define EXTRAM_BASE 0xF000
#define extram ((volatile uint32_t *) EXTRAM_BASE)
///////////////////////////////////////////////////
#endif