Memory map for the v0.7 lowRISC release

Interchangable socket

Rocket Socket

The Rocket sub-system (which uses TileLink-2, a coherency protocol, internally) is mapped onto AXI by default at the top level CorePlex. This was a precursor of the RISCV UNIX hardware platform.

Ariane Socket

The memory map for the ariane-v0.7 is a modified version of the default memory map that comes with the Ariane FPGA demonstrator. Internally, Ariane uses a series of structs that map onto an AXI-compatible bus, together with a cross-bar that supports Atomics as an extension (but perhaps not in an AXI-5 compatible manner).

Common Socket

The common socket (instantiated as rocket_shell or ariane_shell) when configured for LowRISC, contains:

Function Base Address Size
Debug sub-system 0x0000_0000 0x0000_1000
Core Local Interrupter 0x0200_0000 0x000C_0000
Platform Level Interrupt Controller 0x0C00_0000 0x03FF_FFFF
Non-cached external I/O region 0x4000_0000 0x1000_0000
Cached external DDR memory region 0x8000_0000 0x4000_0000

In the common socket core of the processor, the I/O region is a dummy aperture that may or may not map to real peripherals. The DDR memory region is the maximum DDR size that is possible with any supported FPGA board.

The LowRISC compatible peripherals are then added via a second AXI demux on the external I/O region:

Function Base Address Size
LowRISC specific Boot ROM 0x4000_0000 0x08000
Console UART 0x4100_0000 0x01000
Piton SD-Card accelerator 0x4200_0000 0x10000
Ethernet media access controller 0x4300_0000 0x08000
General-purpose IO / real-time clock 0x4400_0000 0x01000
Human interface device (PS2) 0x4503_0000 0x04000
Human interface device (VGA) 0x4503_8000 0xC8000
Bluetooth Host Command Interface 0x4600_0000 0x01000

This subsystem is the same whichever socket is used. However parameters such as maximum blockram available for graphics may need to be changed.

To allow interchangeability, each CPU also has a host rom made from synthesised elements, the only executable function of which is to jump to the start of the external Boot ROM. This is convenient because it allows the detailed boot behaviour to be customised without having to rebuild the entire FPGA netlist. It may be conveniently bypassed by customising the reset vector.

Slave port

The Rocket Coreplex supports a slave port to allow coherent DMA. Ariane has no such port, therefore the common socket does not support coherent DMA. It would still be possible to support incoherent DMA by configuring the DRAM controller to have a second AXI slave port.

Boot ROM

The boot rom is single-function, and not needed after booting. Despite the name it is still writable from the AXI bus. This is a pragmatic feature which helps development because:

  • The gdb debugger can put breakpoints in ROM, to debug early bring up
  • The Vivado software will try to optimise the ROM using incompatible 36-bit components if it isn’t writable.
  • The ROM is implemented with block ram which is conveniently initialised from the bitstream which is held typically in QSPI memory.
  • The ROM gets copied to the top end of DDR before being used, for compatibility with true mask ROM that an ASIC would have.

Implications for the device tree

The use of a single address space for peripherals means that the device tree blob generated by the Rocket chip build environment (and stored in internal boot rom) will not be sufficiently specific to allow Linux to boot. Hence it needs to be customised and re-generated before the AXI boot rom is generated. The file fpga/src/generic.dts handles this variation according to the build option selected:

  • VENDOR will be replaced with sifive or ethz
  • CPU will be replaced with rocket or ariane
  • MEMSIZE will be replaced with 0x8000000 (on Nexys4-DDR) or 0x20000000 (on Genesys2)
  • BOARD will be replace with nexys4_ddr or genesys2

The Linux boot process will read the device tree blob and find the matching device driver from the “compatible” section and the base address to pass to ioremap and friends. Note that two instances of the UART device driver will be launched with different interrupts and base addresses.

This has the disadvantage that unmapped AXI bus locations will not be trapped with a precise exception within the CPU. However it has the advantage that the designer who wants to add a peripheral does not need to know Chisel or make significant changes if the Rocket netlist is upgraded. In any case a well-conditioned Linux device driver will trap out of range accesses that fail to resolve within the supervisor mode MMU protection ranges.

/dts-v1/;

/ {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "VENDOR,CPU-dev";
        model = "VENDOR,CPU-lowRISC";
        chosen {
          stdout-path = "/soc/uart@41000000:115200";
        };
        L13: cpus {
                #address-cells = <1>;
                #size-cells = <0>;
                timebase-frequency = <500000>; // 0.5 MHz
                L5: cpu@0 {
                        clock-frequency = <50000000>; // 50 MHz
                        device_type = "cpu";
                        next-level-cache = <&L7>;
                        reg = <0>;
                        status = "okay";
                        compatible = "VENDOR,CPU", "riscv";
                        riscv,isa = "rv64imafdc";
                        mmu-type = "riscv,sv39";
                        tlb-split;
                        L3: interrupt-controller {
                                #interrupt-cells = <1>;
                                interrupt-controller;
                                compatible = "riscv,cpu-intc";
                        };
                };
        };
        L7: memory@80000000 {
                device_type = "memory";
                reg = <0x80000000 MEMSIZE>;
        };
        L12: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "VENDOR,CPU-lowRISC-BOARD", "simple-bus";
                ranges;
                L1: clint@2000000 {
                        compatible = "riscv,clint0";
                        interrupts-extended = <&L3 3 &L3 7>;
                        reg = <0x2000000 0x10000>;
                        reg-names = "control";
                };
                L10: error-device@3000 {
                        compatible = "sifive,error0";
                        reg = <0x3000 0x1000>;
                        reg-names = "mem";
                };
                L0: interrupt-controller@c000000 {
                        #interrupt-cells = <1>;
                        compatible = "riscv,plic0";
                        interrupt-controller;
                        interrupts-extended = <&L3 11 &L3 9>;
                        reg = <0xc000000 0x4000000>;
                        reg-names = "control";
                        riscv,max-priority = <7>;
                        riscv,ndev = <5>;
                };
                L8: uart@41000000 {
                  #address-cells = <1>;
                  #size-cells = <1>;
                  compatible = "ns16750";
                  reg = <0x41000000 0x1000>;
                  clock-frequency = <50000000>;
                  current-speed = <115200>;
                  interrupt-parent = <&L0>;
                  interrupts = <1>;
                  reg-shift = <2>; // regs are spaced on 32 bit boundary
                  reg-io-width = <4>; // only 32-bit access are supported
                };
                sd: lowrisc-pitonsd@42000000 {
                  reg = <0x42000000 0x10000>;
                  interrupt-parent = <&L0>;
                  interrupts = <2>;
                  compatible = "lowrisc-pitonsd";
                  };
                eth: lowrisc-eth@43000000 {
                  compatible = "lowrisc-eth";
                  device_type = "network";
                  interrupt-parent = <&L0>;
                  interrupts = <3>;
                  reg = <0x43000000 0x8000>;
                };
                gpio: lowrisc-gpio@44000000 {
                  compatible = "lowrisc-gpio";
                  reg = <0x44000000 0x1000>;
                };
                rtc: lowrisc-rtc@44000000 {
                  compatible = "lowrisc-rtc";
                  reg = <0x44000000 0x1000>;
                };
                bt: lowrisc-bt@46000000 {
                        compatible = "ns16750";
                        reg = <0x46000000 0x1000>;
                        clock-frequency = <50000000>;
                        current-speed = <115200>;
                        interrupt-parent = <&L0>;
                        interrupts = <4>;
                        reg-shift = <2>; // regs are spaced on 32 bit boundary
                        reg-io-width = <4>; // only 32-bit access are supported
                };
                keyb: lowrisc-keyb@45030000 {
                        reg = <0x45030000 0x4000>;
                        reg-io-width = <8>;
                        reg-shift = <3>;
                        compatible = "lowrisc-keyb";
                };
                fb: lowrisc-fb@45038000 {
                        reg = <0x45038000 0xC8000>;
                        reg-io-width = <8>;
                        reg-shift = <3>;
                        compatible = "lowrisc-fb";
                };
        };
};