uart: Import and hook up opencore 16550 compatible UART
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 16 Jun 2020 12:42:15 +0000 (22:42 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 23 Jun 2020 23:53:46 +0000 (09:53 +1000)
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 <benh@kernel.crashing.org>
fpga/arty_a7.xdc
fpga/top-arty.vhdl
fpga/top-generic.vhdl
fpga/top-nexys-video.vhdl
include/microwatt_soc.h
microwatt.core
soc.vhdl
syscon.vhdl

index 54e067556558bc387235c130577c920a93a43b88..faa2a62fb3f64c47f95c86044e070db0e3278f63 100644 (file)
@@ -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
index d38ed7653504c7bd6d4906e1d789c2ad111b7ccb..15e082b5cd35f632fc00916613aaeb8b7f7945f8 100644 (file)
@@ -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
index 4f9e437278feefa15d454a8c0d28bb57ff805182..3f27af72c20532000785b438fecdea2f3cf12c2a 100644 (file)
@@ -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,
index 67266af1a6957349df2379533073d314f7115d65..5fc3bab448ad3a9fa91bd29bd423b1814f0f6215 100644 (file)
@@ -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
index 2d09f747eac5f9a1cba101554d06d9fa2b311026..77d5a58bc13717bc972a876b2bce5cd565ed8c27 100644 (file)
@@ -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)
 
 
 /*
 #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
  */
index 4f9820ab2d0969aa481068d57c46bcb650607704..5fb81f5a06fc7ab824aacd93f3f5727385940711 100644 (file)
@@ -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)
index 04ac1764a846645685af26947b638c577ff3944d..6ff52d6d96ba4af11a36682498e7f954e3d49c7a 100644 (file)
--- 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
index 86e53ba03792babe68d68db6b23a16ff416f06c6..05f95a7eada9529e99d54235c8b0783b0d631465 100644 (file)
@@ -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);