Merge pull request #287 from paulusmack/master

Add SD card interface
remove-potato-uart
Michael Neuling 3 years ago committed by GitHub
commit 7f44980611
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -37,6 +37,8 @@ entity core is
wishbone_data_in : in wishbone_slave_out;
wishbone_data_out : out wishbone_master_out;

wb_snoop_in : in wishbone_master_out;

dmi_addr : in std_ulogic_vector(3 downto 0);
dmi_din : in std_ulogic_vector(63 downto 0);
dmi_dout : out std_ulogic_vector(63 downto 0);
@ -241,6 +243,7 @@ begin
stall_out => icache_stall_out,
wishbone_out => wishbone_insn_out,
wishbone_in => wishbone_insn_in,
wb_snoop_in => wb_snoop_in,
log_out => log_data(96 downto 43)
);

@ -423,6 +426,7 @@ begin
stall_out => dcache_stall_out,
wishbone_in => wishbone_data_in,
wishbone_out => wishbone_data_out,
snoop_in => wb_snoop_in,
log_out => log_data(170 downto 151)
);


@ -39,6 +39,8 @@ entity dcache is
m_in : in MmuToDcacheType;
m_out : out DcacheToMmuType;

snoop_in : in wishbone_master_out := wishbone_master_out_init;

stall_out : out std_ulogic;

wishbone_out : out wishbone_master_out;
@ -415,6 +417,11 @@ architecture rtl of dcache is
type tlb_plru_out_t is array(tlb_index_t) of std_ulogic_vector(TLB_WAY_BITS-1 downto 0);
signal tlb_plru_victim : tlb_plru_out_t;

signal snoop_tag_set : cache_tags_set_t;
signal snoop_valid : std_ulogic;
signal snoop_wrtag : cache_tag_t;
signal snoop_index : index_t;

--
-- Helper functions to decode incoming requests
--
@ -528,7 +535,8 @@ begin
assert LINE_SIZE mod ROW_SIZE = 0 report "LINE_SIZE not multiple of ROW_SIZE" severity FAILURE;
assert ispow2(LINE_SIZE) report "LINE_SIZE not power of 2" severity FAILURE;
assert ispow2(NUM_LINES) report "NUM_LINES not power of 2" severity FAILURE;
assert ispow2(ROW_PER_LINE) report "ROW_PER_LINE not power of 2" severity FAILURE;
assert ispow2(ROW_PER_LINE) and ROW_PER_LINE > 1
report "ROW_PER_LINE not power of 2 greater than 1" severity FAILURE;
assert (ROW_BITS = INDEX_BITS + ROW_LINEBITS)
report "geometry bits don't add up" severity FAILURE;
assert (LINE_OFF_BITS = ROW_OFF_BITS + ROW_LINEBITS)
@ -783,6 +791,24 @@ begin
end if;
end process;

-- Cache tag RAM second read port, for snooping
cache_tag_read_2 : process(clk)
variable addr : std_ulogic_vector(REAL_ADDR_BITS - 1 downto 0);
begin
if rising_edge(clk) then
addr := (others => '0');
addr(snoop_in.adr'left downto 0) := snoop_in.adr;
snoop_tag_set <= cache_tags(get_index(addr));
snoop_wrtag <= get_tag(addr);
snoop_index <= get_index(addr);
-- Don't snoop our own cycles
snoop_valid <= '0';
if not (r1.wb.cyc = '1' and wishbone_in.stall = '0') then
snoop_valid <= snoop_in.cyc and snoop_in.stb and snoop_in.we;
end if;
end if;
end process;

-- Cache request parsing and hit detection
dcache_request : process(all)
variable is_hit : std_ulogic;
@ -1293,6 +1319,13 @@ begin
end if;
end if;

-- Do invalidations from snooped stores to memory
for i in way_t loop
if snoop_valid = '1' and read_tag(i, snoop_tag_set) = snoop_wrtag then
cache_valids(snoop_index)(i) <= '0';
end if;
end loop;

if r1.write_tag = '1' then
-- Store new tag in selected way
for i in 0 to NUM_WAYS-1 loop
@ -1425,18 +1458,11 @@ begin
end case;

when RELOAD_WAIT_ACK =>
-- Requests are all sent if stb is 0
stbs_done := r1.wb.stb = '0';

-- If we are still sending requests, was one accepted ?
if wishbone_in.stall = '0' and not stbs_done then
-- That was the last word ? We are done sending. Clear
-- stb and set stbs_done so we can handle an eventual last
-- ack on the same cycle.
--
if wishbone_in.stall = '0' and r1.wb.stb = '1' then
-- That was the last word ? We are done sending. Clear stb.
if is_last_row_addr(r1.wb.adr, r1.end_row_ix) then
r1.wb.stb <= '0';
stbs_done := true;
end if;

-- Calculate the next row address
@ -1467,7 +1493,7 @@ begin
end if;

-- Check for completion
if stbs_done and is_last_row(r1.store_row, r1.end_row_ix) then
if is_last_row(r1.store_row, r1.end_row_ix) then
-- Complete wishbone cycle
r1.wb.cyc <= '0';


@ -72,6 +72,19 @@ set_property IOB true [get_cells -hierarchical -filter {NAME =~*/spi_rxtx/input_
#set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports { pmod_ja_9 }];
#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { pmod_ja_10 }];

# connection to Digilent PmodSD on JA
set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 SLEW FAST PULLUP TRUE } [get_ports { sdcard_data[3] }];
set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 SLEW FAST PULLUP TRUE } [get_ports { sdcard_cmd }];
set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 SLEW FAST PULLUP TRUE } [get_ports { sdcard_data[0] }];
set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 SLEW FAST } [get_ports { sdcard_clk }];
set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 SLEW FAST PULLUP TRUE } [get_ports { sdcard_data[1] }];
set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 SLEW FAST PULLUP TRUE } [get_ports { sdcard_data[2] }];
set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports { sdcard_cd }];
#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { sdcard_wp }];

# Put registers into IOBs to improve timing
set_property IOB true [get_cells -hierarchical -filter {NAME =~*.litesdcard/sdcard_*}]

################################################################################
# PMOD header JB (high-speed, no protection resisters)
################################################################################
@ -85,6 +98,16 @@ set_property IOB true [get_cells -hierarchical -filter {NAME =~*/spi_rxtx/input_
#set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { pmod_jb_9 }];
#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { pmod_jb_10 }];

# connection to Digilent PmodSD on JB
#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 SLEW FAST PULLUP TRUE } [get_ports { sdcard_data[3] }];
#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 SLEW FAST PULLUP TRUE } [get_ports { sdcard_cmd }];
#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 SLEW FAST PULLUP TRUE } [get_ports { sdcard_data[0] }];
#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 SLEW FAST } [get_ports { sdcard_clk }];
#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 SLEW FAST PULLUP TRUE } [get_ports { sdcard_data[1] }];
#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 SLEW FAST PULLUP TRUE } [get_ports { sdcard_data[2] }];
#set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { sdcard_cd }];
#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { sdcard_wp }];

################################################################################
# PMOD header JC (high-speed, no protection resisters)
################################################################################

@ -26,7 +26,8 @@ entity toplevel is
LOG_LENGTH : natural := 512;
USE_LITEETH : boolean := false;
UART_IS_16550 : boolean := false;
HAS_UART1 : boolean := true
HAS_UART1 : boolean := true;
USE_LITESDCARD : boolean := false
);
port(
ext_clk : in std_ulogic;
@ -74,6 +75,12 @@ entity toplevel is
eth_col : in std_ulogic;
eth_crs : in std_ulogic;

-- SD card
sdcard_data : inout std_ulogic_vector(3 downto 0);
sdcard_cmd : inout std_ulogic;
sdcard_clk : out std_ulogic;
sdcard_cd : in std_ulogic;

-- DRAM wires
ddram_a : out std_ulogic_vector(13 downto 0);
ddram_ba : out std_ulogic_vector(2 downto 0);
@ -110,6 +117,7 @@ architecture behaviour of toplevel is
signal wb_ext_is_dram_csr : std_ulogic;
signal wb_ext_is_dram_init : std_ulogic;
signal wb_ext_is_eth : std_ulogic;
signal wb_ext_is_sdcard : std_ulogic;

-- DRAM main data wishbone connection
signal wb_dram_in : wishbone_master_out;
@ -122,6 +130,16 @@ architecture behaviour of toplevel is
signal ext_irq_eth : std_ulogic;
signal wb_eth_out : wb_io_slave_out := wb_io_slave_out_init;

-- LiteSDCard connection
signal ext_irq_sdcard : std_ulogic := '0';
signal wb_sdcard_out : wb_io_slave_out := wb_io_slave_out_init;
signal wb_sddma_out : wb_io_master_out := wb_io_master_out_init;
signal wb_sddma_in : wb_io_slave_out;
signal wb_sddma_nr : wb_io_master_out;
signal wb_sddma_ir : wb_io_slave_out;
-- for conversion from non-pipelined wishbone to pipelined
signal wb_sddma_stb_sent : std_ulogic;

-- Control/status
signal core_alt_reset : std_ulogic;

@ -184,7 +202,8 @@ begin
LOG_LENGTH => LOG_LENGTH,
HAS_LITEETH => USE_LITEETH,
UART0_IS_16550 => UART_IS_16550,
HAS_UART1 => HAS_UART1
HAS_UART1 => HAS_UART1,
HAS_SD_CARD => USE_LITESDCARD
)
port map (
-- System signals
@ -208,15 +227,24 @@ begin

-- External interrupts
ext_irq_eth => ext_irq_eth,
ext_irq_sdcard => ext_irq_sdcard,

-- DRAM wishbone
wb_dram_in => wb_dram_in,
wb_dram_out => wb_dram_out,

-- IO wishbone
wb_ext_io_in => wb_ext_io_in,
wb_ext_io_out => wb_ext_io_out,
wb_ext_is_dram_csr => wb_ext_is_dram_csr,
wb_ext_is_dram_init => wb_ext_is_dram_init,
wb_ext_is_eth => wb_ext_is_eth,
wb_ext_is_sdcard => wb_ext_is_sdcard,

-- DMA wishbone
wishbone_dma_in => wb_sddma_in,
wishbone_dma_out => wb_sddma_out,

alt_reset => core_alt_reset
);

@ -523,8 +551,113 @@ begin
ext_irq_eth <= '0';
end generate;

-- SD card pmod
has_sdcard : if USE_LITESDCARD generate
component litesdcard_core port (
clk : in std_ulogic;
rst : in std_ulogic;
-- wishbone for accessing control registers
wb_ctrl_adr : in std_ulogic_vector(29 downto 0);
wb_ctrl_dat_w : in std_ulogic_vector(31 downto 0);
wb_ctrl_dat_r : out std_ulogic_vector(31 downto 0);
wb_ctrl_sel : in std_ulogic_vector(3 downto 0);
wb_ctrl_cyc : in std_ulogic;
wb_ctrl_stb : in std_ulogic;
wb_ctrl_ack : out std_ulogic;
wb_ctrl_we : in std_ulogic;
wb_ctrl_cti : in std_ulogic_vector(2 downto 0);
wb_ctrl_bte : in std_ulogic_vector(1 downto 0);
wb_ctrl_err : out std_ulogic;
-- wishbone for SD card core to use for DMA
wb_dma_adr : out std_ulogic_vector(29 downto 0);
wb_dma_dat_w : out std_ulogic_vector(31 downto 0);
wb_dma_dat_r : in std_ulogic_vector(31 downto 0);
wb_dma_sel : out std_ulogic_vector(3 downto 0);
wb_dma_cyc : out std_ulogic;
wb_dma_stb : out std_ulogic;
wb_dma_ack : in std_ulogic;
wb_dma_we : out std_ulogic;
wb_dma_cti : out std_ulogic_vector(2 downto 0);
wb_dma_bte : out std_ulogic_vector(1 downto 0);
wb_dma_err : in std_ulogic;
-- connections to SD card
sdcard_data : inout std_ulogic_vector(3 downto 0);
sdcard_cmd : inout std_ulogic;
sdcard_clk : out std_ulogic;
sdcard_cd : in std_ulogic;
irq : out std_ulogic
);
end component;

signal wb_sdcard_cyc : std_ulogic;
signal wb_sdcard_adr : std_ulogic_vector(29 downto 0);

begin
litesdcard : litesdcard_core
port map (
clk => system_clk,
rst => soc_rst,
wb_ctrl_adr => wb_sdcard_adr,
wb_ctrl_dat_w => wb_ext_io_in.dat,
wb_ctrl_dat_r => wb_sdcard_out.dat,
wb_ctrl_sel => wb_ext_io_in.sel,
wb_ctrl_cyc => wb_sdcard_cyc,
wb_ctrl_stb => wb_ext_io_in.stb,
wb_ctrl_ack => wb_sdcard_out.ack,
wb_ctrl_we => wb_ext_io_in.we,
wb_ctrl_cti => "000",
wb_ctrl_bte => "00",
wb_ctrl_err => open,
wb_dma_adr => wb_sddma_nr.adr,
wb_dma_dat_w => wb_sddma_nr.dat,
wb_dma_dat_r => wb_sddma_ir.dat,
wb_dma_sel => wb_sddma_nr.sel,
wb_dma_cyc => wb_sddma_nr.cyc,
wb_dma_stb => wb_sddma_nr.stb,
wb_dma_ack => wb_sddma_ir.ack,
wb_dma_we => wb_sddma_nr.we,
wb_dma_cti => open,
wb_dma_bte => open,
wb_dma_err => '0',
sdcard_data => sdcard_data,
sdcard_cmd => sdcard_cmd,
sdcard_clk => sdcard_clk,
sdcard_cd => sdcard_cd,
irq => ext_irq_sdcard
);

-- Gate cyc with chip select from SoC
wb_sdcard_cyc <= wb_ext_io_in.cyc and wb_ext_is_sdcard;

wb_sdcard_adr <= x"0000" & wb_ext_io_in.adr(15 downto 2);

wb_sdcard_out.stall <= not wb_sdcard_out.ack;

-- Convert non-pipelined DMA wishbone to pipelined by suppressing
-- non-acknowledged strobes
process(system_clk)
begin
if rising_edge(system_clk) then
wb_sddma_out <= wb_sddma_nr;
if wb_sddma_stb_sent = '1' or
(wb_sddma_out.stb = '1' and wb_sddma_in.stall = '0') then
wb_sddma_out.stb <= '0';
end if;
if wb_sddma_nr.cyc = '0' or wb_sddma_ir.ack = '1' then
wb_sddma_stb_sent <= '0';
elsif wb_sddma_in.stall = '0' then
wb_sddma_stb_sent <= wb_sddma_nr.stb;
end if;
wb_sddma_ir <= wb_sddma_in;
end if;
end process;

end generate;

-- Mux WB response on the IO bus
wb_ext_io_out <= wb_eth_out when wb_ext_is_eth = '1' else wb_dram_ctrl_out;
wb_ext_io_out <= wb_eth_out when wb_ext_is_eth = '1' else
wb_sdcard_out when wb_ext_is_sdcard = '1' else
wb_dram_ctrl_out;

leds_pwm : process(system_clk)
begin

@ -68,6 +68,8 @@ entity icache is
wishbone_out : out wishbone_master_out;
wishbone_in : in wishbone_slave_out;

wb_snoop_in : in wishbone_master_out := wishbone_master_out_init;

log_out : out std_ulogic_vector(53 downto 0)
);
end entity icache;
@ -220,8 +222,13 @@ architecture rtl of icache is
signal plru_victim : plru_out_t;
signal replace_way : way_t;

-- Memory write snoop signals
signal snoop_valid : std_ulogic;
signal snoop_index : index_t;
signal snoop_hits : cache_way_valids_t;

-- Return the cache line index (tag index) for an address
function get_index(addr: std_ulogic_vector(63 downto 0)) return index_t is
function get_index(addr: std_ulogic_vector) return index_t is
begin
return to_integer(unsigned(addr(SET_SIZE_BITS - 1 downto LINE_OFF_BITS)));
end;
@ -614,7 +621,10 @@ begin
-- Cache miss/reload synchronous machine
icache_miss : process(clk)
variable tagset : cache_tags_set_t;
variable stbs_done : boolean;
variable tag : cache_tag_t;
variable snoop_addr : std_ulogic_vector(REAL_ADDR_BITS - 1 downto 0);
variable snoop_tag : cache_tag_t;
variable snoop_cache_tags : cache_tags_set_t;
begin
if rising_edge(clk) then
-- On reset, clear all valid bits to force misses
@ -633,13 +643,43 @@ begin

-- Not useful normally but helps avoiding tons of sim warnings
r.wb.adr <= (others => '0');

snoop_valid <= '0';
snoop_index <= 0;
snoop_hits <= (others => '0');
else
-- Detect snooped writes and decode address into index and tag
-- Since we never write, any write should be snooped
snoop_valid <= wb_snoop_in.cyc and wb_snoop_in.stb and wb_snoop_in.we;
snoop_addr := (others => '0');
snoop_addr(wb_snoop_in.adr'left downto 0) := wb_snoop_in.adr;
snoop_index <= get_index(snoop_addr);
snoop_cache_tags := cache_tags(get_index(snoop_addr));
snoop_tag := get_tag(snoop_addr, '0');
snoop_hits <= (others => '0');
for i in way_t loop
tag := read_tag(i, snoop_cache_tags);
-- Ignore endian bit in comparison
tag(TAG_BITS - 1) := '0';
if tag = snoop_tag then
snoop_hits(i) <= '1';
end if;
end loop;

-- Process cache invalidations
if inval_in = '1' then
for i in index_t loop
cache_valids(i) <= (others => '0');
end loop;
r.store_valid <= '0';
else
-- Do invalidations from snooped stores to memory, one
-- cycle after the address appears on wb_snoop_in.
for i in way_t loop
if snoop_valid = '1' and snoop_hits(i) = '1' then
cache_valids(snoop_index)(i) <= '0';
end if;
end loop;
end if;

-- Main state machine
@ -697,18 +737,13 @@ begin

r.state <= WAIT_ACK;
end if;
-- Requests are all sent if stb is 0
stbs_done := r.wb.stb = '0';

-- If we are still sending requests, was one accepted ?
if wishbone_in.stall = '0' and not stbs_done then
-- That was the last word ? We are done sending. Clear
-- stb and set stbs_done so we can handle an eventual last
-- ack on the same cycle.
if wishbone_in.stall = '0' and r.wb.stb = '1' then
-- That was the last word ? We are done sending. Clear stb.
--
if is_last_row_addr(r.wb.adr, r.end_row_ix) then
r.wb.stb <= '0';
stbs_done := true;
end if;

-- Calculate the next row address
@ -719,7 +754,7 @@ begin
if wishbone_in.ack = '1' then
r.rows_valid(r.store_row mod ROW_PER_LINE) <= '1';
-- Check for completion
if stbs_done and is_last_row(r.store_row, r.end_row_ix) then
if is_last_row(r.store_row, r.end_row_ix) then
-- Complete wishbone cycle
r.wb.cyc <= '0';


@ -17,6 +17,7 @@
#define DRAM_CTRL_BASE 0xc8000000 /* LiteDRAM control registers */
#define LETH_CSR_BASE 0xc8020000 /* LiteEth CSR registers */
#define LETH_SRAM_BASE 0xc8030000 /* LiteEth MMIO space */
#define LSDC_CSR_BASE 0xc8040000 /* LiteSDCard MMIO space */
#define SPI_FLASH_BASE 0xf0000000 /* SPI Flash memory map */
#define DRAM_INIT_BASE 0xff000000 /* Internal DRAM init firmware */

@ -40,6 +41,7 @@
#define SYS_REG_INFO_HAS_LARGE_SYSCON (1ull << 5)
#define SYS_REG_INFO_HAS_UART1 (1ull << 6)
#define SYS_REG_INFO_HAS_ARTB (1ull << 7)
#define SYS_REG_INFO_HAS_LITESDCARD (1ull << 8)
#define SYS_REG_BRAMINFO 0x10
#define SYS_REG_BRAMINFO_SIZE_MASK 0xfffffffffffffull
#define SYS_REG_DRAMINFO 0x18

@ -0,0 +1,27 @@
#!/usr/bin/python3
from fusesoc.capi2.generator import Generator
import os
import sys
import pathlib

class LiteSDCardGenerator(Generator):
def run(self):
board = self.config.get('board')

# Collect a bunch of directory path
script_dir = os.path.dirname(sys.argv[0])
gen_dir = os.path.join(script_dir, "generated", board)

print("Adding LiteSDCard for board... ", board)

# Add files to fusesoc
files = []
f = os.path.join(gen_dir, "litesdcard_core.v")
files.append({f : {'file_type' : 'verilogSource'}})

self.add_files(files)

g = LiteSDCardGenerator()
g.run()
g.write()

@ -0,0 +1,35 @@
#!/bin/bash

TARGETS=arty

ME=$(realpath $0)
echo ME=$ME
MY_PATH=$(dirname $ME)
echo MYPATH=$MY_PATH
PARENT_PATH=$(realpath $MY_PATH/..)
echo PARENT=$PARENT_PATH
BUILD_PATH=$PARENT_PATH/build
mkdir -p $BUILD_PATH
GEN_PATH=$PARENT_PATH/generated
mkdir -p $GEN_PATH

# Note litesdcard/gen.py doesn't parse a YAML file, instead it takes
# a --vendor=xxx parameter, where xxx = xilinx or lattice. If we
# want to generate litesdcard for ecp5 we'll have to invent a way to
# map arty to xilinx and ecp5 to lattice

for i in $TARGETS
do
TARGET_BUILD_PATH=$BUILD_PATH/$i
TARGET_GEN_PATH=$GEN_PATH/$i
rm -rf $TARGET_BUILD_PATH
rm -rf $TARGET_GEN_PATH
mkdir -p $TARGET_BUILD_PATH
mkdir -p $TARGET_GEN_PATH

echo "Generating $i in $TARGET_BUILD_PATH"
(cd $TARGET_BUILD_PATH && litesdcard_gen)

cp $TARGET_BUILD_PATH/build/gateware/litesdcard_core.v $TARGET_GEN_PATH/
done

File diff suppressed because it is too large Load Diff

@ -0,0 +1,15 @@
CAPI=2:

name : :microwatt:litesdcard:0

generators:
litesdcard_gen:
interpreter: python3
command: fusesoc-add-files.py
description: Generate a litesdcard SD-card controller
usage: |
litesdcard_gen adds the pre-generated LiteX LiteSDCard SD-card controller
based on the board type.

Parameters:
board: The board type (arty)

@ -116,6 +116,9 @@ filesets:
liteeth:
depend : [":microwatt:liteeth"]

litesdcard:
depend : [":microwatt:litesdcard"]

uart16550:
depend : ["::uart16550"]

@ -243,7 +246,7 @@ targets:

arty_a7-35-nodram:
default_tool: vivado
filesets: [core, arty_a7, soc, fpga, debug_xilinx, uart16550, xilinx_specific]
filesets: [core, arty_a7, soc, fpga, debug_xilinx, uart16550, xilinx_specific, litesdcard]
parameters :
- memory_size
- ram_init_file
@ -256,18 +259,20 @@ targets:
- has_uart1
- has_fpu=false
- has_btc=false
- use_litesdcard
tools:
vivado: {part : xc7a35ticsg324-1L}
toplevel : toplevel

arty_a7-35:
default_tool: vivado
filesets: [core, arty_a7, soc, fpga, debug_xilinx, litedram, liteeth, uart16550, xilinx_specific]
filesets: [core, arty_a7, soc, fpga, debug_xilinx, litedram, liteeth, uart16550, xilinx_specific, litesdcard]
parameters :
- memory_size
- ram_init_file
- use_litedram=true
- use_liteeth=true
- use_litesdcard
- disable_flatten_core
- no_bram
- spi_flash_offset=3145728
@ -276,14 +281,14 @@ targets:
- has_uart1
- has_fpu=false
- has_btc=false
generate: [litedram_arty, liteeth_arty]
generate: [litedram_arty, liteeth_arty, litesdcard_arty]
tools:
vivado: {part : xc7a35ticsg324-1L}
toplevel : toplevel

arty_a7-100-nodram:
default_tool: vivado
filesets: [core, arty_a7, soc, fpga, debug_xilinx, uart16550, xilinx_specific]
filesets: [core, arty_a7, soc, fpga, debug_xilinx, uart16550, xilinx_specific, litesdcard]
parameters :
- memory_size
- ram_init_file
@ -296,18 +301,20 @@ targets:
- has_uart1
- has_fpu
- has_btc
- use_litesdcard
tools:
vivado: {part : xc7a100ticsg324-1L}
toplevel : toplevel

arty_a7-100:
default_tool: vivado
filesets: [core, arty_a7, soc, fpga, debug_xilinx, litedram, liteeth, uart16550, xilinx_specific]
filesets: [core, arty_a7, soc, fpga, debug_xilinx, litedram, liteeth, uart16550, xilinx_specific, litesdcard]
parameters:
- memory_size
- ram_init_file
- use_litedram=true
- use_liteeth=true
- use_litesdcard
- disable_flatten_core
- no_bram
- spi_flash_offset=4194304
@ -316,7 +323,7 @@ targets:
- has_uart1
- has_fpu
- has_btc
generate: [litedram_arty, liteeth_arty]
generate: [litedram_arty, liteeth_arty, litesdcard_arty]
tools:
vivado: {part : xc7a100ticsg324-1L}
toplevel : toplevel
@ -354,6 +361,10 @@ generate:
generator: liteeth_gen
parameters: {board : arty}

litesdcard_arty:
generator: litesdcard_gen
parameters: {board : arty}

litedram_nexys_video:
generator: litedram_gen
parameters: {board : nexys-video}
@ -425,6 +436,12 @@ parameters:
paramtype : generic
default : false

use_litesdcard:
datatype : bool
description : Use LiteSDCard
paramtype : generic
default : false

uart_is_16550:
datatype : bool
description : Use 16550-compatible UART from OpenCores

@ -32,6 +32,7 @@ use work.wishbone_types.all;
-- 0xc8000000: LiteDRAM control (CSRs)
-- 0xc8020000: LiteEth CSRs (*)
-- 0xc8030000: LiteEth MMIO (*)
-- 0xc8040000: LiteSDCard CSRs

-- (*) LiteEth must be a single aligned 32KB block as the CSRs and MMIOs
-- are actually decoded as a single wishbone which LiteEth will
@ -45,6 +46,8 @@ use work.wishbone_types.all;
--
-- 0 : UART0
-- 1 : Ethernet
-- 2 : UART1
-- 3 : SD card

entity soc is
generic (
@ -74,7 +77,8 @@ entity soc is
DCACHE_NUM_LINES : natural := 64;
DCACHE_NUM_WAYS : natural := 2;
DCACHE_TLB_SET_SIZE : natural := 64;
DCACHE_TLB_NUM_WAYS : natural := 2
DCACHE_TLB_NUM_WAYS : natural := 2;
HAS_SD_CARD : boolean := false
);
port(
rst : in std_ulogic;
@ -90,9 +94,15 @@ entity soc is
wb_ext_is_dram_csr : out std_ulogic;
wb_ext_is_dram_init : out std_ulogic;
wb_ext_is_eth : out std_ulogic;
wb_ext_is_sdcard : out std_ulogic;

-- external DMA wishbone with 32-bit data/address
wishbone_dma_in : out wb_io_slave_out := wb_io_slave_out_init;
wishbone_dma_out : in wb_io_master_out := wb_io_master_out_init;

-- External interrupts
ext_irq_eth : in std_ulogic := '0';
ext_irq_sdcard : in std_ulogic := '0';

-- UART0 signals:
uart0_txd : out std_ulogic;
@ -121,18 +131,19 @@ architecture behaviour of soc is
signal wishbone_dcore_out : wishbone_master_out;
signal wishbone_icore_in : wishbone_slave_out;
signal wishbone_icore_out : wishbone_master_out;
signal wishbone_debug_in : wishbone_slave_out;
signal wishbone_debug_in : wishbone_slave_out;
signal wishbone_debug_out : wishbone_master_out;

-- Arbiter array (ghdl doesnt' support assigning the array
-- elements in the entity instantiation)
constant NUM_WB_MASTERS : positive := 3;
constant NUM_WB_MASTERS : positive := 4;
signal wb_masters_out : wishbone_master_out_vector(0 to NUM_WB_MASTERS-1);
signal wb_masters_in : wishbone_slave_out_vector(0 to NUM_WB_MASTERS-1);

-- Wishbone master (output of arbiter):
signal wb_master_in : wishbone_slave_out;
signal wb_master_out : wishbone_master_out;
signal wb_snoop : wishbone_master_out;

-- Main "IO" bus, from main slave decoder to the latch
signal wb_io_in : wishbone_master_out;
@ -218,6 +229,37 @@ architecture behaviour of soc is
SLAVE_IO_NONE);
signal slave_io_dbg : slave_io_type;

function wishbone_widen_data(wb : wb_io_master_out) return wishbone_master_out is
variable wwb : wishbone_master_out;
begin
wwb.adr := wb.adr & "00"; -- XXX note wrong adr usage in wishbone_master_out
wwb.dat := wb.dat & wb.dat;
wwb.sel := x"00";
if wwb.adr(2) = '0' then
wwb.sel(3 downto 0) := wb.sel;
else
wwb.sel(7 downto 4) := wb.sel;
end if;
wwb.cyc := wb.cyc;
wwb.stb := wb.stb;
wwb.we := wb.we;
return wwb;
end;

function wishbone_narrow_data(wwbs : wishbone_slave_out; adr : std_ulogic_vector(29 downto 0))
return wb_io_slave_out is
variable wbs : wb_io_slave_out;
begin
wbs.ack := wwbs.ack;
wbs.stall := wwbs.stall;
if adr(0) = '0' then
wbs.dat := wwbs.dat(31 downto 0);
else
wbs.dat := wwbs.dat(63 downto 32);
end if;
return wbs;
end;

-- This is the component exported by the 16550 compatible
-- UART from FuseSoC.
--
@ -242,6 +284,7 @@ architecture behaviour of soc is
dcd_pad_i : in std_ulogic
);
end component;

begin

resets: process(system_clk)
@ -284,6 +327,7 @@ begin
wishbone_insn_out => wishbone_icore_out,
wishbone_data_in => wishbone_dcore_in,
wishbone_data_out => wishbone_dcore_out,
wb_snoop_in => wb_snoop,
dmi_addr => dmi_addr(3 downto 0),
dmi_dout => dmi_core_dout,
dmi_din => dmi_dout,
@ -296,10 +340,12 @@ begin
-- Wishbone bus master arbiter & mux
wb_masters_out <= (0 => wishbone_dcore_out,
1 => wishbone_icore_out,
2 => wishbone_debug_out);
2 => wishbone_widen_data(wishbone_dma_out),
3 => wishbone_debug_out);
wishbone_dcore_in <= wb_masters_in(0);
wishbone_icore_in <= wb_masters_in(1);
wishbone_debug_in <= wb_masters_in(2);
wishbone_dma_in <= wishbone_narrow_data(wb_masters_in(2), wishbone_dma_out.adr);
wishbone_debug_in <= wb_masters_in(3);
wishbone_arbiter_0: entity work.wishbone_arbiter
generic map(
NUM_MASTERS => NUM_WB_MASTERS
@ -313,6 +359,18 @@ begin
wb_slave_in => wb_master_in
);

-- Snoop bus going to caches.
-- Gate stb with stall so the caches don't see the stalled strobes.
-- That way if the caches see a strobe when their wishbone is stalled,
-- they know it is an access by another master.
process(all)
begin
wb_snoop <= wb_master_out;
if wb_master_in.stall = '1' then
wb_snoop.stb <= '0';
end if;
end process;

-- Top level Wishbone slaves address decoder & mux
--
-- From CPU to BRAM, DRAM, IO, selected on top 3 bits and dram_at_0
@ -575,6 +633,7 @@ begin
wb_ext_is_dram_csr <= '0';
wb_ext_is_dram_init <= '0';
wb_ext_is_eth <= '0';
wb_ext_is_sdcard <= '0';

-- Default response, ack & return all 1's
wb_sio_in.dat <= (others => '1');
@ -602,6 +661,9 @@ begin
elsif wb_sio_out.adr(23 downto 16) = x"03" and HAS_LITEETH then
wb_ext_is_eth <= '1';
ext_valid := true;
elsif wb_sio_out.adr(23 downto 16) = x"04" and HAS_SD_CARD then
wb_ext_is_sdcard <= '1';
ext_valid := true;
end if;
if ext_valid then
wb_ext_io_in.cyc <= wb_sio_out.cyc;
@ -651,6 +713,7 @@ begin
HAS_SPI_FLASH => HAS_SPI_FLASH,
SPI_FLASH_OFFSET => SPI_FLASH_OFFSET,
HAS_LITEETH => HAS_LITEETH,
HAS_SD_CARD => HAS_SD_CARD,
UART0_IS_16550 => UART0_IS_16550,
HAS_UART1 => HAS_UART1
)
@ -834,6 +897,7 @@ begin
int_level_in(0) <= uart0_irq;
int_level_in(1) <= ext_irq_eth;
int_level_in(2) <= uart1_irq;
int_level_in(3) <= ext_irq_sdcard;
end process;

-- BRAM Memory slave

@ -18,6 +18,7 @@ entity syscon is
HAS_SPI_FLASH : boolean;
SPI_FLASH_OFFSET : integer;
HAS_LITEETH : boolean;
HAS_SD_CARD : boolean;
UART0_IS_16550 : boolean;
HAS_UART1 : boolean
);
@ -65,6 +66,7 @@ architecture behaviour of syscon is
constant SYS_REG_INFO_HAS_LSYS : integer := 5; -- Has 6-bit address syscon
constant SYS_REG_INFO_HAS_URT1 : integer := 6; -- Has second UART
constant SYS_REG_INFO_HAS_ARTB : integer := 7; -- Has architected TB frequency
constant SYS_REG_INFO_HAS_SDCARD : integer := 8; -- Has LiteSDCard SD-card interface

-- BRAMINFO contains the BRAM size in the bottom 52 bits
-- DRAMINFO contains the DRAM size if any in the bottom 52 bits
@ -107,6 +109,7 @@ architecture behaviour of syscon is
signal info_has_uart : std_ulogic;
signal info_has_spif : std_ulogic;
signal info_has_leth : std_ulogic;
signal info_has_lsdc : std_ulogic;
signal info_has_urt1 : std_ulogic;
signal info_clk : std_ulogic_vector(39 downto 0);
signal info_fl_off : std_ulogic_vector(31 downto 0);
@ -128,15 +131,17 @@ begin
info_has_bram <= '1' when BRAM_SIZE /= 0 else '0';
info_has_spif <= '1' when HAS_SPI_FLASH else '0';
info_has_leth <= '1' when HAS_LITEETH else '0';
info_has_lsdc <= '1' when HAS_SD_CARD else '0';
info_has_urt1 <= '1' when HAS_UART1 else '0';
info_clk <= std_ulogic_vector(to_unsigned(CLK_FREQ, 40));
reg_info <= (SYS_REG_INFO_HAS_UART => info_has_uart,
SYS_REG_INFO_HAS_DRAM => info_has_dram,
SYS_REG_INFO_HAS_BRAM => info_has_bram,
SYS_REG_INFO_HAS_SPIF => info_has_spif,
SYS_REG_INFO_HAS_LETH => info_has_leth,
SYS_REG_INFO_HAS_LSYS => '1',
SYS_REG_INFO_HAS_URT1 => info_has_urt1,
reg_info <= (SYS_REG_INFO_HAS_UART => info_has_uart,
SYS_REG_INFO_HAS_DRAM => info_has_dram,
SYS_REG_INFO_HAS_BRAM => info_has_bram,
SYS_REG_INFO_HAS_SPIF => info_has_spif,
SYS_REG_INFO_HAS_LETH => info_has_leth,
SYS_REG_INFO_HAS_SDCARD => info_has_lsdc,
SYS_REG_INFO_HAS_LSYS => '1',
SYS_REG_INFO_HAS_URT1 => info_has_urt1,
others => '0');

reg_braminfo <= x"000" & std_ulogic_vector(to_unsigned(BRAM_SIZE, 52));

@ -44,6 +44,8 @@ package wishbone_types is
stb : std_ulogic;
we : std_ulogic;
end record;
constant wb_io_master_out_init : wb_io_master_out := (adr => (others => '0'), dat => (others => '0'),
sel => "0000", cyc => '0', stb => '0', we => '0');

type wb_io_slave_out is record
dat : std_ulogic_vector(31 downto 0);

Loading…
Cancel
Save