add microwatt console lib and #includes
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 18 Feb 2022 20:11:35 +0000 (20:11 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 18 Feb 2022 20:11:35 +0000 (20:11 +0000)
include/console.h [new file with mode: 0644]
include/io.h [new file with mode: 0644]
include/microwatt_soc.h [new file with mode: 0644]
lib/console.c [new file with mode: 0644]
src/ls2.py

diff --git a/include/console.h b/include/console.h
new file mode 100644 (file)
index 0000000..9d58bb6
--- /dev/null
@@ -0,0 +1,16 @@
+/* This code is directly from Microwatt and is Copyright and Licensed
+   under the same terms as Microwatt source code.
+   https://github.com/antonblanchard/microwatt/blob/master/include/console.h
+*/
+
+#include <stddef.h>
+
+void console_init(void);
+void console_set_irq_en(bool rx_irq, bool tx_irq);
+int getchar(void);
+int putchar(int c);
+int puts(const char *str);
+
+#ifndef __USE_LIBC
+size_t strlen(const char *s);
+#endif
diff --git a/include/io.h b/include/io.h
new file mode 100644 (file)
index 0000000..bf29f49
--- /dev/null
@@ -0,0 +1,58 @@
+/* This code is directly from Microwatt and is Copyright and Licensed
+   under the same terms as Microwatt source code.
+   https://github.com/antonblanchard/microwatt/blob/master/include/io.h
+*/
+
+#ifndef __IO_H
+#define __IO_H
+
+static inline uint8_t readb(unsigned long addr)
+{
+       uint8_t val;
+       __asm__ volatile("sync; lbzcix %0,0,%1" : "=r" (val) : "r" (addr) : "memory");
+       return val;
+}
+
+static inline uint16_t readw(unsigned long addr)
+{
+       uint16_t val;
+       __asm__ volatile("sync; lhzcix %0,0,%1" : "=r" (val) : "r" (addr) : "memory");
+       return val;
+}
+
+static inline uint32_t readl(unsigned long addr)
+{
+       uint32_t val;
+       __asm__ volatile("sync; lwzcix %0,0,%1" : "=r" (val) : "r" (addr) : "memory");
+       return val;
+}
+
+static inline uint64_t readq(unsigned long addr)
+{
+       uint64_t val;
+       __asm__ volatile("sync; ldcix %0,0,%1" : "=r" (val) : "r" (addr) : "memory");
+       return val;
+}
+
+static inline void writeb(uint8_t val, unsigned long addr)
+{
+       __asm__ volatile("sync; stbcix %0,0,%1" : : "r" (val), "r" (addr) : "memory");
+}
+
+static inline void writew(uint16_t val, unsigned long addr)
+{
+       __asm__ volatile("sync; sthcix %0,0,%1" : : "r" (val), "r" (addr) : "memory");
+}
+
+static inline void writel(uint32_t val, unsigned long addr)
+{
+       __asm__ volatile("sync; stwcix %0,0,%1" : : "r" (val), "r" (addr) : "memory");
+}
+
+static inline void writeq(uint64_t val, unsigned long addr)
+{
+       __asm__ volatile("sync; stdcix %0,0,%1" : : "r" (val), "r" (addr) : "memory");
+}
+
+#endif /* __IO_H */
+
diff --git a/include/microwatt_soc.h b/include/microwatt_soc.h
new file mode 100644 (file)
index 0000000..22f8c0d
--- /dev/null
@@ -0,0 +1,165 @@
+/* This code is directly from Microwatt and is Copyright and Licensed
+   under the same terms as Microwatt source code.
+https://github.com/antonblanchard/microwatt/blob/master/include/microwatt_soc.h
+*/
+
+#ifndef __MICROWATT_SOC_H
+#define __MICROWATT_SOC_H
+
+/*
+ * Microwatt SoC memory map
+ */
+
+#define MEMORY_BASE     0x00000000  /* "Main" memory alias, either BRAM or DRAM */
+#define DRAM_BASE       0x40000000  /* DRAM if present */
+#define BRAM_BASE       0x80000000  /* Internal BRAM */
+
+#define SYSCON_BASE    0xc0000000  /* System control regs */
+#define UART_BASE      0xc0002000  /* UART */
+#define XICS_ICP_BASE   0xc0004000  /* Interrupt controller */
+#define XICS_ICS_BASE   0xc0005000  /* Interrupt controller */
+#define SPI_FCTRL_BASE  0xc0006000  /* SPI flash controller registers */
+#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 SPI_FLASH_BASE  0xf0000000  /* SPI Flash memory map */
+#ifdef STANDALONE_MINI_BIOS
+#define DRAM_INIT_BASE  0x00000000  /* alternative, for verilator simulation */
+#else
+#define DRAM_INIT_BASE  0xff000000  /* Internal DRAM init firmware */
+#endif
+
+/*
+ * Interrupt numbers
+ */
+#define IRQ_UART0       0
+#define IRQ_ETHERNET    1
+
+/*
+ * Register definitions for the syscon registers
+ */
+
+#define SYS_REG_SIGNATURE              0x00
+#define SYS_REG_INFO                   0x08
+#define   SYS_REG_INFO_HAS_UART                (1ull << 0)
+#define   SYS_REG_INFO_HAS_DRAM                (1ull << 1)
+#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_INFO_HAS_ARTB                 (1ull << 7)
+#define SYS_REG_BRAMINFO               0x10
+#define   SYS_REG_BRAMINFO_SIZE_MASK           0xfffffffffffffull
+#define SYS_REG_DRAMINFO               0x18
+#define   SYS_REG_DRAMINFO_SIZE_MASK           0xfffffffffffffull
+#define SYS_REG_CLKINFO                        0x20
+#define   SYS_REG_CLKINFO_FREQ_MASK            0xffffffffffull
+#define SYS_REG_CTRL                   0x28
+#define   SYS_REG_CTRL_DRAM_AT_0               (1ull << 0)
+#define   SYS_REG_CTRL_CORE_RESET              (1ull << 1)
+#define   SYS_REG_CTRL_SOC_RESET               (1ull << 2)
+#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 SYS_REG_BRAM_BOOTADDR          0x50
+
+
+/*
+ * Register definitions for the potato UART
+ */
+#define POTATO_CONSOLE_TX              0x00
+#define POTATO_CONSOLE_RX              0x08
+#define POTATO_CONSOLE_STATUS          0x10
+#define   POTATO_CONSOLE_STATUS_RX_EMPTY               0x01
+#define   POTATO_CONSOLE_STATUS_TX_EMPTY               0x02
+#define   POTATO_CONSOLE_STATUS_RX_FULL                        0x04
+#define   POTATO_CONSOLE_STATUS_TX_FULL                        0x08
+#define POTATO_CONSOLE_CLOCK_DIV       0x18
+#define POTATO_CONSOLE_IRQ_EN          0x20
+#define   POTATO_CONSOLE_IRQ_RX                                0x01
+#define   POTATO_CONSOLE_IRQ_TX                                0x02
+
+/*
+ * 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_IER_RDI      0x01
+#define   UART_REG_IER_THRI     0x02
+#define   UART_REG_IER_RLSI     0x04
+#define   UART_REG_IER_MSI      0x08
+#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
+ */
+#define SPI_REG_DATA                   0x00 /* Byte access: single wire transfer */
+#define SPI_REG_DATA_DUAL              0x01 /* Byte access: dual wire transfer */
+#define SPI_REG_DATA_QUAD              0x02 /* Byte access: quad wire transfer */
+#define SPI_REG_CTRL                   0x04 /* Reset and manual mode control */
+#define   SPI_REG_CTRL_RESET                   0x01  /* reset all registers */
+#define   SPI_REG_CTRL_MANUAL_CS               0x02  /* assert CS, enable manual mode */
+#define   SPI_REG_CTRL_CKDIV_SHIFT             8     /* clock div */
+#define   SPI_REG_CTRL_CKDIV_MASK              (0xff << SPI_REG_CTRL_CKDIV_SHIFT)
+#define SPI_REG_AUTO_CFG               0x08 /* Automatic map configuration */
+#define   SPI_REG_AUTO_CFG_CMD_SHIFT           0     /* Command to use for reads */
+#define   SPI_REG_AUTO_CFG_CMD_MASK            (0xff << SPI_REG_AUTO_CFG_CMD_SHIFT)
+#define   SPI_REG_AUTO_CFG_DUMMIES_SHIFT        8     /* # dummy cycles */
+#define   SPI_REG_AUTO_CFG_DUMMIES_MASK         (0x7  << SPI_REG_AUTO_CFG_DUMMIES_SHIFT)
+#define   SPI_REG_AUTO_CFG_MODE_SHIFT           11    /* SPI wire mode */
+#define   SPI_REG_AUTO_CFG_MODE_MASK            (0x3  << SPI_REG_AUTO_CFG_MODE_SHIFT)
+#define     SPI_REG_AUT_CFG_MODE_SINGLE         (0 << 11)
+#define     SPI_REG_AUT_CFG_MODE_DUAL           (2 << 11)
+#define     SPI_REG_AUT_CFG_MODE_QUAD           (3 << 11)
+#define   SPI_REG_AUTO_CFG_ADDR4                (1u << 13) /* 3 or 4 addr bytes */
+#define   SPI_REG_AUTO_CFG_CKDIV_SHIFT          16    /* clock div */
+#define   SPI_REG_AUTO_CFG_CKDIV_MASK           (0xff << SPI_REG_AUTO_CFG_CKDIV_SHIFT)
+#define   SPI_REG_AUTO_CFG_CSTOUT_SHIFT         24    /* CS timeout */
+#define   SPI_REG_AUTO_CFG_CSTOUT_MASK          (0x3f << SPI_REG_AUTO_CFG_CSTOUT_SHIFT)
+
+
+#endif /* __MICROWATT_SOC_H */
diff --git a/lib/console.c b/lib/console.c
new file mode 100644 (file)
index 0000000..b44c024
--- /dev/null
@@ -0,0 +1,228 @@
+/* This code is directly from Microwatt and is Copyright and Licensed
+   under the same terms as Microwatt source code.
+   https://github.com/antonblanchard/microwatt/blob/master/lib/console.c
+*/
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "console.h"
+#include "microwatt_soc.h"
+#include "io.h"
+
+#define UART_BAUDS 115200
+
+/*
+ * Core UART functions to implement for a port
+ */
+
+bool uart_is_std;
+
+static uint64_t uart_base;
+
+static unsigned long uart_divisor(unsigned long uart_freq, unsigned long bauds)
+{
+       return uart_freq / (bauds * 16);
+}
+
+static uint64_t potato_uart_reg_read(int offset)
+{
+       return readq(uart_base + offset);
+}
+
+static void potato_uart_reg_write(int offset, uint64_t val)
+{
+       writeq(val, uart_base + offset);
+}
+
+static int potato_uart_rx_empty(void)
+{
+       uint64_t val;
+
+       val = potato_uart_reg_read(POTATO_CONSOLE_STATUS);
+
+       if (val & POTATO_CONSOLE_STATUS_RX_EMPTY)
+               return 1;
+
+       return 0;
+}
+
+static int potato_uart_tx_full(void)
+{
+       uint64_t val;
+
+       val = potato_uart_reg_read(POTATO_CONSOLE_STATUS);
+
+       if (val & POTATO_CONSOLE_STATUS_TX_FULL)
+               return 1;
+
+       return 0;
+}
+
+static char potato_uart_read(void)
+{
+       uint64_t val;
+
+       val = potato_uart_reg_read(POTATO_CONSOLE_RX);
+
+       return (char)(val & 0x000000ff);
+}
+
+static void potato_uart_write(char c)
+{
+       uint64_t val;
+
+       val = c;
+
+       potato_uart_reg_write(POTATO_CONSOLE_TX, val);
+}
+
+static void potato_uart_init(uint64_t uart_freq)
+{
+       unsigned long div = uart_divisor(uart_freq, UART_BAUDS) - 1;
+       potato_uart_reg_write(POTATO_CONSOLE_CLOCK_DIV, div);
+}
+
+static void potato_uart_set_irq_en(bool rx_irq, bool tx_irq)
+{
+       uint64_t en = 0;
+
+       if (rx_irq)
+               en |= POTATO_CONSOLE_IRQ_RX;
+       if (tx_irq)
+               en |= POTATO_CONSOLE_IRQ_TX;
+       potato_uart_reg_write(POTATO_CONSOLE_IRQ_EN, en);
+}
+
+static bool std_uart_rx_empty(void)
+{
+       return !(readb(uart_base + UART_REG_LSR) & UART_REG_LSR_DR);
+}
+
+static uint8_t std_uart_read(void)
+{
+       return readb(uart_base + UART_REG_RX);
+}
+
+static bool std_uart_tx_full(void)
+{
+       return !(readb(uart_base + UART_REG_LSR) & UART_REG_LSR_THRE);
+}
+
+static void std_uart_write(uint8_t c)
+{
+       writeb(c, uart_base + UART_REG_TX);
+}
+
+static void std_uart_set_irq_en(bool rx_irq, bool tx_irq)
+{
+       uint8_t ier = 0;
+
+       if (tx_irq)
+               ier |= UART_REG_IER_THRI;
+       if (rx_irq)
+               ier |= UART_REG_IER_RDI;
+       writeb(ier, uart_base + UART_REG_IER);
+}
+
+static void std_uart_init(uint64_t uart_freq)
+{
+       unsigned long div = uart_divisor(uart_freq, UART_BAUDS);
+       
+       writeb(UART_REG_LCR_DLAB,     uart_base + UART_REG_LCR);
+       writeb(div & 0xff,            uart_base + UART_REG_DLL);
+       writeb(div >> 8,              uart_base + UART_REG_DLM);
+       writeb(UART_REG_LCR_8BIT,     uart_base + UART_REG_LCR);
+       writeb(UART_REG_MCR_DTR |
+              UART_REG_MCR_RTS,      uart_base + UART_REG_MCR);
+       writeb(UART_REG_FCR_EN_FIFO |
+              UART_REG_FCR_CLR_RCVR |
+              UART_REG_FCR_CLR_XMIT, uart_base + UART_REG_FCR);
+}
+
+int getchar(void)
+{
+       if (uart_is_std) {
+               while (std_uart_rx_empty())
+                       /* Do nothing */ ;
+               return std_uart_read();
+       } else {
+               while (potato_uart_rx_empty())
+                       /* Do nothing */ ;
+               return potato_uart_read();
+       }
+}
+
+int putchar(int c)
+{
+       if (uart_is_std) {
+               while(std_uart_tx_full())
+                       /* Do Nothing */;
+               std_uart_write(c);
+       } else {
+               while (potato_uart_tx_full())
+                       /* Do Nothing */;
+               potato_uart_write(c);
+       }
+       return c;
+}
+
+int puts(const char *str)
+{
+       unsigned int i;
+
+       for (i = 0; *str; i++) {
+               char c = *(str++);
+               if (c == 10)
+                       putchar(13);
+               putchar(c);
+       }
+       return 0;
+}
+
+#ifndef __USE_LIBC
+size_t strlen(const char *s)
+{
+       size_t len = 0;
+
+       while (*s++)
+               len++;
+
+       return len;
+}
+#endif
+
+void console_init(void)
+{
+       uint64_t sys_info;
+       uint64_t proc_freq;
+       uint64_t uart_info = 0;
+       uint64_t uart_freq = 0;
+
+       proc_freq = readq(SYSCON_BASE + SYS_REG_CLKINFO) & SYS_REG_CLKINFO_FREQ_MASK;
+       sys_info  = readq(SYSCON_BASE + SYS_REG_INFO);
+
+       if (sys_info & SYS_REG_INFO_HAS_LARGE_SYSCON) {
+               uart_info = readq(SYSCON_BASE + SYS_REG_UART0_INFO);
+               uart_freq = uart_info & 0xffffffff;
+       }
+       if (uart_freq == 0)
+               uart_freq = proc_freq;
+
+       uart_base = UART_BASE;
+       if (uart_info & SYS_REG_UART_IS_16550) {
+               uart_is_std = true;
+               std_uart_init(proc_freq);
+       } else {
+               uart_is_std = false;
+               potato_uart_init(proc_freq);
+       }
+}
+
+void console_set_irq_en(bool rx_irq, bool tx_irq)
+{
+       if (uart_is_std)
+               std_uart_set_irq_en(rx_irq, tx_irq);
+       else
+               potato_uart_set_irq_en(rx_irq, tx_irq);
+}
index 576ec96ea4a2bba3a9b3d529f089c38a0339d95c..54d4f4d9f7308adee97c2ffcb8723d2d364001c7 100644 (file)
@@ -27,7 +27,7 @@ from soc.bus.syscon import MicrowattSYSCON
 
 from gram.core import gramCore
 from gram.phy.ecp5ddrphy import ECP5DDRPHY
-from gram.modules import MT41K256M16
+from gram.modules import MT41K256M16, MT41K64M16
 from gram.frontend.wishbone import gramWishbone
 
 from nmigen_boards.versa_ecp5 import VersaECP5Platform
@@ -43,6 +43,7 @@ import os
 
 class DDR3SoC(SoC, Elaboratable):
     def __init__(self, *,
+                 dram_cls,
                  uart_pins, ddr_pins,
                  ddrphy_addr, dramcore_addr,
                  ddr_addr, fw_addr=0x0000_0000,
@@ -264,6 +265,11 @@ if __name__ == "__main__":
                  'ulx3s': 'Trellis',
                  'sim': None,
                 }.get(fpga, None)
+    dram_cls = {'arty_a7': None,
+                 'versa_ecp5': MT41K64M16,
+                 'ulx3s': None,
+                 'sim': None,
+                }.get(fpga, None)
     if platform_kls is not None:
         platform = platform_kls(toolchain=toolchain)
     else:
@@ -284,18 +290,19 @@ if __name__ == "__main__":
 
     # get DDR resource pins
     ddr_pins = None
-    if False and platform is not None and fpga in ['versa_ecp5', 'arty_a7']:
+    if platform is not None and fpga in ['versa_ecp5', 'arty_a7']:
         ddr_pins = platform.request("ddr3", 0,
                                     dir={"dq":"-", "dqs":"-"},
                                     xdr={"clk":4, "a":4, "ba":4, "clk_en":4,
                                          "odt":4, "ras":4, "cas":4, "we":4})
 
     # set up the SOC
-    soc = DDR3SoC(ddrphy_addr=0xff000000, # DRAM firmware init base
+    soc = DDR3SoC(dram_cls,
+                  ddrphy_addr=0xff000000, # DRAM firmware init base
                   dramcore_addr=0x80000000,
                   ddr_addr=0x10000000,
-                  #fw_addr=fw_addr,
-                  fw_addr=None,
+                  fw_addr=fw_addr,
+                  #fw_addr=None,
                   ddr_pins=ddr_pins,
                   uart_pins=uart_pins,
                   firmware=firmware,