From 7575b1e0c2b1c21847ed3103185858d1a512ead6 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 16 Jun 2020 22:42:15 +1000 Subject: [PATCH] uart: Import and hook up opencore 16550 compatible UART This imports via fusesoc a 16550 compatible (ie "standard") UART, and wires it up optionally in the SoC instead of the potato one. This also adds support for a second UART (which is always a 16550) to Arty, wired to JC "bottom" port. Signed-off-by: Benjamin Herrenschmidt --- fpga/arty_a7.xdc | 8 +- fpga/top-arty.vhdl | 20 ++++- fpga/top-generic.vhdl | 6 +- fpga/top-nexys-video.vhdl | 6 +- include/microwatt_soc.h | 53 ++++++++++- microwatt.core | 45 ++++++++-- soc.vhdl | 179 +++++++++++++++++++++++++++++++++----- syscon.vhdl | 62 +++++++++---- 8 files changed, 322 insertions(+), 57 deletions(-) diff --git a/fpga/arty_a7.xdc b/fpga/arty_a7.xdc index 54e0675..faa2a62 100644 --- a/fpga/arty_a7.xdc +++ b/fpga/arty_a7.xdc @@ -13,10 +13,10 @@ set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { uart_mai # Pmod Header JC: UART (bottom) ################################################################################ -#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { uart_pmod_cts_n }]; -#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { uart_pmod_tx }]; -#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { uart_pmod_rx }]; -#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { uart_pmod_rts_n }]; +set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { uart_pmod_cts_n }]; +set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { uart_pmod_tx }]; +set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { uart_pmod_rx }]; +set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { uart_pmod_rts_n }]; ################################################################################ # RGB LEDs diff --git a/fpga/top-arty.vhdl b/fpga/top-arty.vhdl index d38ed76..15e082b 100644 --- a/fpga/top-arty.vhdl +++ b/fpga/top-arty.vhdl @@ -22,7 +22,9 @@ entity toplevel is SPI_FLASH_DEF_CKDV : natural := 1; SPI_FLASH_DEF_QUAD : boolean := true; LOG_LENGTH : natural := 512; - USE_LITEETH : boolean := false + USE_LITEETH : boolean := false; + UART_IS_16550 : boolean := false; + HAS_UART1 : boolean := false ); port( ext_clk : in std_ulogic; @@ -32,6 +34,12 @@ entity toplevel is uart_main_tx : out std_ulogic; uart_main_rx : in std_ulogic; + -- UART1 signals: + uart_pmod_tx : out std_ulogic; + uart_pmod_rx : in std_ulogic; + uart_pmod_cts_n : in std_ulogic; + uart_pmod_rts_n : out std_ulogic; + -- LEDs led0_b : out std_ulogic; led0_g : out std_ulogic; @@ -170,7 +178,9 @@ begin SPI_FLASH_DEF_CKDV => SPI_FLASH_DEF_CKDV, SPI_FLASH_DEF_QUAD => SPI_FLASH_DEF_QUAD, LOG_LENGTH => LOG_LENGTH, - USE_LITEETH => USE_LITEETH + HAS_LITEETH => USE_LITEETH, + UART0_IS_16550 => UART_IS_16550, + HAS_UART1 => HAS_UART1 ) port map ( -- System signals @@ -181,6 +191,10 @@ begin uart0_txd => uart_main_tx, uart0_rxd => uart_main_rx, + -- UART1 signals + uart1_txd => uart_pmod_tx, + uart1_rxd => uart_pmod_rx, + -- SPI signals spi_flash_sck => spi_sck, spi_flash_cs_n => spi_cs_n, @@ -202,6 +216,8 @@ begin alt_reset => core_alt_reset ); + uart_pmod_rts_n <= '0'; + -- SPI Flash -- -- Note: Unlike many other boards, the SPI flash on the Arty has diff --git a/fpga/top-generic.vhdl b/fpga/top-generic.vhdl index 4f9e437..3f27af7 100644 --- a/fpga/top-generic.vhdl +++ b/fpga/top-generic.vhdl @@ -11,7 +11,8 @@ entity toplevel is RESET_LOW : boolean := true; CLK_INPUT : positive := 100000000; CLK_FREQUENCY : positive := 100000000; - DISABLE_FLATTEN_CORE : boolean := false + DISABLE_FLATTEN_CORE : boolean := false; + UART_IS_16550 : boolean := false ); port( ext_clk : in std_ulogic; @@ -67,7 +68,8 @@ begin RAM_INIT_FILE => RAM_INIT_FILE, SIM => false, CLK_FREQ => CLK_FREQUENCY, - DISABLE_FLATTEN_CORE => DISABLE_FLATTEN_CORE + DISABLE_FLATTEN_CORE => DISABLE_FLATTEN_CORE, + UART0_IS_16550 => UART_IS_16550 ) port map ( system_clk => system_clk, diff --git a/fpga/top-nexys-video.vhdl b/fpga/top-nexys-video.vhdl index 67266af..5fc3bab 100644 --- a/fpga/top-nexys-video.vhdl +++ b/fpga/top-nexys-video.vhdl @@ -19,7 +19,8 @@ entity toplevel is DISABLE_FLATTEN_CORE : boolean := false; SPI_FLASH_OFFSET : integer := 10485760; SPI_FLASH_DEF_CKDV : natural := 1; - SPI_FLASH_DEF_QUAD : boolean := true + SPI_FLASH_DEF_QUAD : boolean := true; + UART_IS_16550 : boolean := false; ); port( ext_clk : in std_ulogic; @@ -126,7 +127,8 @@ begin SPI_FLASH_DLINES => 4, SPI_FLASH_OFFSET => SPI_FLASH_OFFSET, SPI_FLASH_DEF_CKDV => SPI_FLASH_DEF_CKDV, - SPI_FLASH_DEF_QUAD => SPI_FLASH_DEF_QUAD + SPI_FLASH_DEF_QUAD => SPI_FLASH_DEF_QUAD, + UART0_IS_16550 => UART_IS_16550 ) port map ( -- System signals diff --git a/include/microwatt_soc.h b/include/microwatt_soc.h index 2d09f74..77d5a58 100644 --- a/include/microwatt_soc.h +++ b/include/microwatt_soc.h @@ -37,6 +37,8 @@ #define SYS_REG_INFO_HAS_BRAM (1ull << 2) #define SYS_REG_INFO_HAS_SPI_FLASH (1ull << 3) #define SYS_REG_INFO_HAS_LITEETH (1ull << 4) +#define SYS_REG_INFO_HAS_LARGE_SYSCON (1ull << 5) +#define SYS_REG_INFO_HAS_UART1 (1ull << 6) #define SYS_REG_BRAMINFO 0x10 #define SYS_REG_BRAMINFO_SIZE_MASK 0xfffffffffffffull #define SYS_REG_DRAMINFO 0x18 @@ -50,7 +52,9 @@ #define SYS_REG_DRAMINITINFO 0x30 #define SYS_REG_SPI_INFO 0x38 #define SYS_REG_SPI_INFO_FLASH_OFF_MASK 0xffffffff - +#define SYS_REG_UART0_INFO 0x40 +#define SYS_REG_UART1_INFO 0x48 +#define SYS_REG_UART_IS_16550 (1ull << 32) /* @@ -66,6 +70,53 @@ #define POTATO_CONSOLE_CLOCK_DIV 0x18 #define POTATO_CONSOLE_IRQ_EN 0x20 +/* + * Register definitionss for our standard (16550 style) UART + */ +#define UART_REG_RX 0x00 +#define UART_REG_TX 0x00 +#define UART_REG_DLL 0x00 +#define UART_REG_IER 0x04 +#define UART_REG_DLM 0x04 +#define UART_REG_IIR 0x08 +#define UART_REG_FCR 0x08 +#define UART_REG_FCR_EN_FIFO 0x01 +#define UART_REG_FCR_CLR_RCVR 0x02 +#define UART_REG_FCR_CLR_XMIT 0x04 +#define UART_REG_FCR_TRIG1 0x00 +#define UART_REG_FCR_TRIG4 0x40 +#define UART_REG_FCR_TRIG8 0x80 +#define UART_REG_FCR_TRIG14 0xc0 +#define UART_REG_LCR 0x0c +#define UART_REG_LCR_5BIT 0x00 +#define UART_REG_LCR_6BIT 0x01 +#define UART_REG_LCR_7BIT 0x02 +#define UART_REG_LCR_8BIT 0x03 +#define UART_REG_LCR_STOP 0x04 +#define UART_REG_LCR_PAR 0x08 +#define UART_REG_LCR_EVEN_PAR 0x10 +#define UART_REG_LCR_STIC_PAR 0x20 +#define UART_REG_LCR_BREAK 0x40 +#define UART_REG_LCR_DLAB 0x80 +#define UART_REG_MCR 0x10 +#define UART_REG_MCR_DTR 0x01 +#define UART_REG_MCR_RTS 0x02 +#define UART_REG_MCR_OUT1 0x04 +#define UART_REG_MCR_OUT2 0x08 +#define UART_REG_MCR_LOOP 0x10 +#define UART_REG_LSR 0x14 +#define UART_REG_LSR_DR 0x01 +#define UART_REG_LSR_OE 0x02 +#define UART_REG_LSR_PE 0x04 +#define UART_REG_LSR_FE 0x08 +#define UART_REG_LSR_BI 0x10 +#define UART_REG_LSR_THRE 0x20 +#define UART_REG_LSR_TEMT 0x40 +#define UART_REG_LSR_FIFOE 0x80 +#define UART_REG_MSR 0x18 +#define UART_REG_SCR 0x1c + + /* * Register definitions for the SPI controller */ diff --git a/microwatt.core b/microwatt.core index 4f9820a..5fb81f5 100644 --- a/microwatt.core +++ b/microwatt.core @@ -103,10 +103,13 @@ filesets: liteeth: depend : [":microwatt:liteeth"] + uart16550: + depend : ["::uart16550"] + targets: nexys_a7: default_tool: vivado - filesets: [core, nexys_a7, soc, fpga, debug_xilinx, xilinx_specific] + filesets: [core, nexys_a7, soc, fpga, debug_xilinx, uart16550, xilinx_specific] parameters : - memory_size - ram_init_file @@ -114,13 +117,15 @@ targets: - clk_frequency - disable_flatten_core - log_length=2048 + - uart_is_16550 + - has_uart1 tools: vivado: {part : xc7a100tcsg324-1} toplevel : toplevel nexys_video-nodram: default_tool: vivado - filesets: [core, nexys_video, soc, fpga, debug_xilinx, xilinx_specific] + filesets: [core, nexys_video, soc, fpga, debug_xilinx, uart16550, xilinx_specific] parameters : - memory_size - ram_init_file @@ -129,13 +134,15 @@ targets: - disable_flatten_core - spi_flash_offset=10485760 - log_length=2048 + - uart_is_16550 + - has_uart1 tools: vivado: {part : xc7a200tsbg484-1} toplevel : toplevel nexys_video: default_tool: vivado - filesets: [core, nexys_video, soc, fpga, debug_xilinx, litedram, xilinx_specific] + filesets: [core, nexys_video, soc, fpga, debug_xilinx, litedram, uart16550, xilinx_specific] parameters: - memory_size - ram_init_file @@ -151,7 +158,7 @@ targets: arty_a7-35-nodram: default_tool: vivado - filesets: [core, arty_a7, soc, fpga, debug_xilinx, xilinx_specific] + filesets: [core, arty_a7, soc, fpga, debug_xilinx, uart16550, xilinx_specific] parameters : - memory_size - ram_init_file @@ -160,13 +167,15 @@ targets: - disable_flatten_core - spi_flash_offset=3145728 - log_length=512 + - uart_is_16550 + - has_uart1 tools: vivado: {part : xc7a35ticsg324-1L} toplevel : toplevel arty_a7-35: default_tool: vivado - filesets: [core, arty_a7, soc, fpga, debug_xilinx, litedram, liteeth, xilinx_specific] + filesets: [core, arty_a7, soc, fpga, debug_xilinx, litedram, liteeth, uart16550, xilinx_specific] parameters : - memory_size - ram_init_file @@ -176,6 +185,8 @@ targets: - no_bram - spi_flash_offset=3145728 - log_length=512 + - uart_is_16550 + - has_uart1 generate: [litedram_arty, liteeth_arty] tools: vivado: {part : xc7a35ticsg324-1L} @@ -183,7 +194,7 @@ targets: arty_a7-100-nodram: default_tool: vivado - filesets: [core, arty_a7, soc, fpga, debug_xilinx, xilinx_specific] + filesets: [core, arty_a7, soc, fpga, debug_xilinx, uart16550, xilinx_specific] parameters : - memory_size - ram_init_file @@ -192,13 +203,15 @@ targets: - disable_flatten_core - spi_flash_offset=4194304 - log_length=2048 + - uart_is_16550 + - has_uart1 tools: vivado: {part : xc7a100ticsg324-1L} toplevel : toplevel arty_a7-100: default_tool: vivado - filesets: [core, arty_a7, soc, fpga, debug_xilinx, litedram, liteeth, xilinx_specific] + filesets: [core, arty_a7, soc, fpga, debug_xilinx, litedram, liteeth, uart16550, xilinx_specific] parameters: - memory_size - ram_init_file @@ -208,6 +221,8 @@ targets: - no_bram - spi_flash_offset=4194304 - log_length=2048 + - uart_is_16550 + - has_uart1 generate: [litedram_arty, liteeth_arty] tools: vivado: {part : xc7a100ticsg324-1L} @@ -215,7 +230,7 @@ targets: cmod_a7-35: default_tool: vivado - filesets: [core, cmod_a7-35, soc, fpga, debug_xilinx, xilinx_specific] + filesets: [core, cmod_a7-35, soc, fpga, debug_xilinx, uart16550, xilinx_specific] parameters : - memory_size - ram_init_file @@ -224,6 +239,8 @@ targets: - clk_frequency - disable_flatten_core - log_length=512 + - uart_is_16550 + - has_uart1 tools: vivado: {part : xc7a35tcpg236-1} toplevel : toplevel @@ -294,6 +311,18 @@ parameters: paramtype : generic default : false + uart_is_16550: + datatype : bool + description : Use 16550-compatible UART from OpenCores + paramtype : generic + default : false + + has_uart1: + datatype : bool + description : Enable second UART (always 16550-compatible) + paramtype : generic + default : false + no_bram: datatype : bool description : No internal block RAM (only DRAM and init code carrying payload) diff --git a/soc.vhdl b/soc.vhdl index 04ac176..6ff52d6 100644 --- a/soc.vhdl +++ b/soc.vhdl @@ -20,6 +20,7 @@ use work.wishbone_types.all; -- IO Bus: -- 0xc0000000: SYSCON -- 0xc0002000: UART0 +-- 0xc0003000: UART1 (if any) -- 0xc0004000: XICS ICP -- 0xc0005000: XICS ICS -- 0xc0006000: SPI Flash controller @@ -61,7 +62,9 @@ entity soc is SPI_FLASH_DEF_CKDV : natural := 2; SPI_FLASH_DEF_QUAD : boolean := false; LOG_LENGTH : natural := 512; - HAS_LITEETH : boolean := false + HAS_LITEETH : boolean := false; + UART0_IS_16550 : boolean := false; + HAS_UART1 : boolean := false ); port( rst : in std_ulogic; @@ -85,6 +88,10 @@ entity soc is uart0_txd : out std_ulogic; uart0_rxd : in std_ulogic := '0'; + -- UART1 signals: + uart1_txd : out std_ulogic; + uart1_rxd : in std_ulogic := '0'; + -- SPI Flash signals spi_flash_sck : out std_ulogic; spi_flash_cs_n : out std_ulogic; @@ -137,6 +144,12 @@ architecture behaviour of soc is signal uart0_dat8 : std_ulogic_vector(7 downto 0); signal uart0_irq : std_ulogic; + -- UART1 signals: + signal wb_uart1_in : wb_io_master_out; + signal wb_uart1_out : wb_io_slave_out; + signal uart1_dat8 : std_ulogic_vector(7 downto 0); + signal uart1_irq : std_ulogic; + -- SPI Flash controller signals: signal wb_spiflash_in : wb_io_master_out; signal wb_spiflash_out : wb_io_slave_out; @@ -188,12 +201,37 @@ architecture behaviour of soc is SLAVE_IO_UART, SLAVE_IO_ICP, SLAVE_IO_ICS, + SLAVE_IO_UART1, SLAVE_IO_SPI_FLASH_REG, SLAVE_IO_SPI_FLASH_MAP, SLAVE_IO_EXTERNAL, SLAVE_IO_NONE); signal slave_io_dbg : slave_io_type; + -- This is the component exported by the 16550 compatible + -- UART from FuseSoC. + -- + component uart_top port ( + wb_clk_i : in std_ulogic; + wb_rst_i : in std_ulogic; + wb_adr_i : in std_ulogic_vector(2 downto 0); + wb_dat_i : in std_ulogic_vector(7 downto 0); + wb_dat_o : out std_ulogic_vector(7 downto 0); + wb_we_i : in std_ulogic; + wb_stb_i : in std_ulogic; + wb_cyc_i : in std_ulogic; + wb_ack_o : out std_ulogic; + int_o : out std_ulogic; + stx_pad_o : out std_ulogic; + srx_pad_i : in std_ulogic; + rts_pad_o : out std_ulogic; + cts_pad_i : in std_ulogic; + dtr_pad_o : out std_ulogic; + dsr_pad_i : in std_ulogic; + ri_pad_i : in std_ulogic; + dcd_pad_i : in std_ulogic + ); + end component; begin resets: process(system_clk) @@ -458,7 +496,7 @@ begin -- IO wishbone slave intercon. -- - slave_io_intercon: process(wb_sio_out, wb_syscon_out, wb_uart0_out, + slave_io_intercon: process(wb_sio_out, wb_syscon_out, wb_uart0_out, wb_uart1_out, wb_ext_io_out, wb_xics_icp_out, wb_xics_ics_out, wb_spiflash_out) variable slave_io : slave_io_type; @@ -478,6 +516,8 @@ begin slave_io := SLAVE_IO_SYSCON; elsif std_match(match, x"C0002") then slave_io := SLAVE_IO_UART; + elsif std_match(match, x"C0003") then + slave_io := SLAVE_IO_UART1; elsif std_match(match, x"C8---") then slave_io := SLAVE_IO_EXTERNAL; elsif std_match(match, x"C0004") then @@ -490,6 +530,8 @@ begin slave_io_dbg <= slave_io; wb_uart0_in <= wb_sio_out; wb_uart0_in.cyc <= '0'; + wb_uart1_in <= wb_sio_out; + wb_uart1_in.cyc <= '0'; wb_spiflash_in <= wb_sio_out; wb_spiflash_in.cyc <= '0'; wb_spiflash_is_reg <= '0'; @@ -559,6 +601,9 @@ begin when SLAVE_IO_ICS => wb_xics_ics_in.cyc <= wb_sio_out.cyc; wb_sio_in <= wb_xics_ics_out; + when SLAVE_IO_UART1 => + wb_uart1_in.cyc <= wb_sio_out.cyc; + wb_sio_in <= wb_uart1_out; when SLAVE_IO_SPI_FLASH_MAP => -- Clear top bits so they don't make their way to the -- fash chip. @@ -586,7 +631,9 @@ begin CLK_FREQ => CLK_FREQ, HAS_SPI_FLASH => HAS_SPI_FLASH, SPI_FLASH_OFFSET => SPI_FLASH_OFFSET, - HAS_LITEETH => HAS_LITEETH + HAS_LITEETH => HAS_LITEETH, + UART0_IS_16550 => UART0_IS_16550, + HAS_UART1 => HAS_UART1 ) port map( clk => system_clk, @@ -598,30 +645,115 @@ begin soc_reset => open -- XXX TODO ); - -- Simulated memory and UART + -- + -- UART0 + -- + -- Either potato (legacy) or 16550 + -- + uart0_pp: if not UART0_IS_16550 generate + uart0: entity work.pp_soc_uart + generic map( + FIFO_DEPTH => 32 + ) + port map( + clk => system_clk, + reset => rst_uart, + txd => uart0_txd, + rxd => uart0_rxd, + irq => uart0_irq, + wb_adr_in => wb_uart0_in.adr(11 downto 0), + wb_dat_in => wb_uart0_in.dat(7 downto 0), + wb_dat_out => uart0_dat8, + wb_cyc_in => wb_uart0_in.cyc, + wb_stb_in => wb_uart0_in.stb, + wb_we_in => wb_uart0_in.we, + wb_ack_out => wb_uart0_out.ack + ); + end generate; + + uart0_16550 : if UART0_IS_16550 generate + signal irq_l : std_ulogic; + begin + uart0: uart_top + port map ( + wb_clk_i => system_clk, + wb_rst_i => rst_uart, + wb_adr_i => wb_uart0_in.adr(4 downto 2), + wb_dat_i => wb_uart0_in.dat(7 downto 0), + wb_dat_o => uart0_dat8, + wb_we_i => wb_uart0_in.we, + wb_stb_i => wb_uart0_in.stb, + wb_cyc_i => wb_uart0_in.cyc, + wb_ack_o => wb_uart0_out.ack, + int_o => irq_l, + stx_pad_o => uart0_txd, + srx_pad_i => uart0_rxd, + rts_pad_o => open, + cts_pad_i => '1', + dtr_pad_o => open, + dsr_pad_i => '1', + ri_pad_i => '0', + dcd_pad_i => '1' + ); + + -- Add a register on the irq out, helps timing + uart0_irq_latch: process(system_clk) + begin + if rising_edge(system_clk) then + uart0_irq <= irq_l; + end if; + end process; + end generate; - -- UART0 wishbone slave - uart0: entity work.pp_soc_uart - generic map( - FIFO_DEPTH => 32 - ) - port map( - clk => system_clk, - reset => rst_uart, - txd => uart0_txd, - rxd => uart0_rxd, - irq => uart0_irq, - wb_adr_in => wb_uart0_in.adr(11 downto 0), - wb_dat_in => wb_uart0_in.dat(7 downto 0), - wb_dat_out => uart0_dat8, - wb_cyc_in => wb_uart0_in.cyc, - wb_stb_in => wb_uart0_in.stb, - wb_we_in => wb_uart0_in.we, - wb_ack_out => wb_uart0_out.ack - ); wb_uart0_out.dat <= x"000000" & uart0_dat8; wb_uart0_out.stall <= not wb_uart0_out.ack; + -- + -- UART1 + -- + -- Always 16550 if it exists + -- + uart1: if HAS_UART1 generate + signal irq_l : std_ulogic; + begin + uart1: uart_top + port map ( + wb_clk_i => system_clk, + wb_rst_i => rst_uart, + wb_adr_i => wb_uart1_in.adr(4 downto 2), + wb_dat_i => wb_uart1_in.dat(7 downto 0), + wb_dat_o => uart1_dat8, + wb_we_i => wb_uart1_in.we, + wb_stb_i => wb_uart1_in.stb, + wb_cyc_i => wb_uart1_in.cyc, + wb_ack_o => wb_uart1_out.ack, + int_o => irq_l, + stx_pad_o => uart1_txd, + srx_pad_i => uart1_rxd, + rts_pad_o => open, + cts_pad_i => '1', + dtr_pad_o => open, + dsr_pad_i => '1', + ri_pad_i => '0', + dcd_pad_i => '1' + ); + -- Add a register on the irq out, helps timing + uart0_irq_latch: process(system_clk) + begin + if rising_edge(system_clk) then + uart1_irq <= irq_l; + end if; + end process; + wb_uart1_out.dat <= x"000000" & uart1_dat8; + wb_uart1_out.stall <= not wb_uart1_out.ack; + end generate; + + no_uart1 : if not HAS_UART1 generate + wb_uart1_out.dat <= x"00000000"; + wb_uart1_out.ack <= wb_uart1_in.cyc and wb_uart1_in.stb; + wb_uart1_out.stall <= '0'; + end generate; + spiflash_gen: if HAS_SPI_FLASH generate spiflash: entity work.spi_flash_ctrl generic map ( @@ -680,6 +812,7 @@ begin int_level_in <= (others => '0'); int_level_in(0) <= uart0_irq; int_level_in(1) <= ext_irq_eth; + int_level_in(2) <= uart1_irq; end process; -- BRAM Memory slave diff --git a/syscon.vhdl b/syscon.vhdl index 86e53ba..05f95a7 100644 --- a/syscon.vhdl +++ b/syscon.vhdl @@ -17,7 +17,9 @@ entity syscon is DRAM_INIT_SIZE : integer; HAS_SPI_FLASH : boolean; SPI_FLASH_OFFSET : integer; - HAS_LITEETH : boolean + HAS_LITEETH : boolean; + UART0_IS_16550 : boolean; + HAS_UART1 : boolean ); port ( clk : in std_ulogic; @@ -37,27 +39,31 @@ end entity syscon; architecture behaviour of syscon is -- Register address bits - constant SYS_REG_BITS : positive := 3; + constant SYS_REG_BITS : positive := 6; -- Register addresses (matches wishbone addr downto 3, ie, 8 bytes per reg) - constant SYS_REG_SIG : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000"; - constant SYS_REG_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001"; - constant SYS_REG_BRAMINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "010"; - constant SYS_REG_DRAMINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "011"; - constant SYS_REG_CLKINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "100"; - constant SYS_REG_CTRL : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "101"; - constant SYS_REG_DRAMINITINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "110"; - constant SYS_REG_SPIFLASHINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "111"; + constant SYS_REG_SIG : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000000"; + constant SYS_REG_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000001"; + constant SYS_REG_BRAMINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000010"; + constant SYS_REG_DRAMINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000011"; + constant SYS_REG_CLKINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000100"; + constant SYS_REG_CTRL : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000101"; + constant SYS_REG_DRAMINITINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000110"; + constant SYS_REG_SPIFLASHINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000111"; + constant SYS_REG_UART0_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001000"; + constant SYS_REG_UART1_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001001"; -- Muxed reg read signal signal reg_out : std_ulogic_vector(63 downto 0); -- INFO register bits - constant SYS_REG_INFO_HAS_UART : integer := 0; - constant SYS_REG_INFO_HAS_DRAM : integer := 1; - constant SYS_REG_INFO_HAS_BRAM : integer := 2; - constant SYS_REG_INFO_HAS_SPIF : integer := 3; - constant SYS_REG_INFO_HAS_LETH : integer := 4; + constant SYS_REG_INFO_HAS_UART : integer := 0; -- Has a UART (always set) + constant SYS_REG_INFO_HAS_DRAM : integer := 1; -- Has DRAM + constant SYS_REG_INFO_HAS_BRAM : integer := 2; -- Has "main" BRAM + constant SYS_REG_INFO_HAS_SPIF : integer := 3; -- Has SPI flash + constant SYS_REG_INFO_HAS_LETH : integer := 4; -- Has LiteEth ethernet + constant SYS_REG_INFO_HAS_LSYS : integer := 5; -- Has 6-bit address syscon + constant SYS_REG_INFO_HAS_URT1 : integer := 6; -- Has second UART -- BRAMINFO contains the BRAM size in the bottom 52 bits -- DRAMINFO contains the DRAM size if any in the bottom 52 bits @@ -76,6 +82,12 @@ architecture behaviour of syscon is -- reserved for the FPGA bitfile if any constant SYS_REG_SPI_INFO_IS_FLASH : integer := 0; + -- UART0/1 info registers bits + -- + -- 0 ..31 : UART clock freq (in HZ) + -- 32 : UART is 16550 (otherwise pp) + -- + -- Ctrl register signal reg_ctrl : std_ulogic_vector(SYS_REG_CTRL_BITS-1 downto 0); signal reg_ctrl_out : std_ulogic_vector(63 downto 0); @@ -87,13 +99,18 @@ architecture behaviour of syscon is signal reg_dramiinfo : std_ulogic_vector(63 downto 0); signal reg_clkinfo : std_ulogic_vector(63 downto 0); signal reg_spiinfo : std_ulogic_vector(63 downto 0); + signal reg_uart0info : std_ulogic_vector(63 downto 0); + signal reg_uart1info : std_ulogic_vector(63 downto 0); signal info_has_dram : std_ulogic; signal info_has_bram : std_ulogic; signal info_has_uart : std_ulogic; signal info_has_spif : std_ulogic; signal info_has_leth : 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); + signal uinfo_16550 : std_ulogic; + signal uinfo_freq : std_ulogic_vector(31 downto 0); -- Wishbone response latch signal wb_rsp : wb_io_slave_out; @@ -110,12 +127,15 @@ 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_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, others => '0'); reg_braminfo <= x"000" & std_ulogic_vector(to_unsigned(BRAM_SIZE, 52)); @@ -133,6 +153,16 @@ begin reg_ctrl_out <= (63 downto SYS_REG_CTRL_BITS => '0', SYS_REG_CTRL_BITS-1 downto 0 => reg_ctrl); + -- UART info registers read composition + uinfo_16550 <= '1' when UART0_IS_16550 else '0'; + uinfo_freq <= std_ulogic_vector(to_unsigned(CLK_FREQ, 32)); + reg_uart0info <= (32 => uinfo_16550, + 31 downto 0 => uinfo_freq, + others => '0'); + reg_uart1info <= (32 => '1', + 31 downto 0 => uinfo_freq, + others => '0'); + -- Wishbone response wb_rsp.ack <= wishbone_in.cyc and wishbone_in.stb; with wishbone_in.adr(SYS_REG_BITS+2 downto 3) select reg_out <= @@ -144,6 +174,8 @@ begin reg_clkinfo when SYS_REG_CLKINFO, reg_ctrl_out when SYS_REG_CTRL, reg_spiinfo when SYS_REG_SPIFLASHINFO, + reg_uart0info when SYS_REG_UART0_INFO, + reg_uart1info when SYS_REG_UART1_INFO, (others => '0') when others; wb_rsp.dat <= reg_out(63 downto 32) when wishbone_in.adr(2) = '1' else reg_out(31 downto 0);