-
Notifications
You must be signed in to change notification settings - Fork 345
Test SOC Register Map
The Nyuzi core is a component for larger system-on-chip designs and can't do much by itself. To run on FPGA and execute more complex programs, I've created a reference design with some simple peripherals. These are not part of Nyuzi proper.
- SDRAM controller: Single data rate, 128 MB on the DE2-115 board
- VGA controller
- UART
- PS/2 keyboard controller
- LED/HEX display
- SPI/SDMMC controller
There are two buses internally. An AMBA AXI bus connects memory peripherals. The CPU and VGA controller are masters. There are two slaves-- The SDRAM controller and a boot ROM--selected by physical address. A custom I/O bus is used for controlling and configuring peripherals via memory mapped registers. All of these run in a single 50 MHz clock domain.
The CPU starts execution at the beginning of boot ROM region (source code is in software/bootrom). The boot ROM waits for the host computer to load a program over the serial interface into the beginning of SDRAM, then jumps to address 0. It configures the UART for 921600 baud by default.
The timings for the SDRAM are hardcoded as synthesis parameters, so configuration is not necessary at boot. This project utilizes around 70k logic elements for a single core on an Altera Cyclone IV chip.
Physical Address space:
Range | Address |
---|---|
SDRAM (128M) | 00000000 |
07FFFFFF | |
Boot ROM (8k) | FFFEE000 |
FFFEFFFF | |
Device Registers | FFFF0000 |
FFFFFFFF |
The emulator and verilator environments support many of the peripherals on FPGA. In the device register descriptions below, the 'environment' column indicates which environments support it: F = fpga, E = emulator, V = verilator.
Vector | Type | Description |
---|---|---|
0 | edge | Cosimulation interrupt timer (simulation only) |
1 | edge | Programmable timer |
2 | level | UART RX bytes available |
3 | level | PS/2 controller bytes available |
4 | edge | VGA new frame |
Address | r/w | Environment | Description |
---|---|---|---|
ffff0000 | w | F | Set value of red LEDs |
ffff0004 | w | F | Set value of green LEDs |
ffff0008 | w | F | Set value of 7 segment display 0 |
ffff000c | w | F | Set value of 7 segment display 1 |
ffff0010 | w | F | Set value of 7 segment display 2 |
ffff0014 | w | F | Set value of 7 segment display 3 |
ffff0018 | w | E | Sends interrupt to host via pipe in emulator |
ffff001c | w | V | Force loopback UART tx line low 1 |
- When this register is written, the UART loopback TX line will be forced low. This is used by tests to simulate a framing error. This only works in the Verilator environment.
- The cosimulation timer only triggers in the Verilator environment. When it triggers, it causes an interrupt on the processor, but also dumps a cosimulation event. The emulator reads this and triggers a synchronized interrupt on its side. This mechanism allows the interrupt to occur on the same instruction boundary in both environments.
In the verilator environment, the cosimulation timer raises an interrupt and prints a cosimulation event. The emulator will raise the timer when it sees the event. This allows synchronizing the interrupts so they occur at the same instruction boundary in both environments.
Address | r/w | Environment | Description |
---|---|---|---|
ffff0020 | w | V | cosimulation interrupt timer interval |
This is a bidirectional serial port. It is hardcoded for 8 data bits, one stop bit, and no parity. The clock rate is configured by programming the UART divider register, which configures the number of clocks per bit (it should be set to clocks minus one). The UART runs off the 50 MHz system clock, so the value should be:
divider = (50000000 / baud_rate) - 1
Address | r/w | Environment | Description |
---|---|---|---|
ffff0040 | r | FEV | UART status |
ffff0044 | r | F | UART read |
ffff0048 | w | FEV | UART write |
ffff004c | w | F | UART divider |
UART status bits:
Bit | Meaning |
---|---|
0 | Space available in write FIFO |
1 | Bytes in read FIFO |
2 | Receive FIFO overrun |
3 | Receive Framing error |
The overrun and framing error bits are cleared when the UART read register is read.
Serial writes (including printfs from software) print to standard out in Verilator and the emulator.
In the Verilator environment, keyboard scancodes are just an incrementing pattern. For the emulator, they are only returned if the framebuffer window is displayed and in focus. For the FPGA, they come from the PS/2 port on the board.
Address | r/w | Environment | Description |
---|---|---|---|
ffff0080 | r | FEV | PS/2 Keyboard status. 1 indicates there are scancodes in FIFO. |
ffff0084 | r | FEV | PS/2 Keyboard scancode. Remove from FIFO on read. |
SD GPIO and SD SPI are mutually exclusive. SD GPIO is if BITBANG_SDMMC is set in hardware/fpga/de2_115/de2_115_top.sv, SPI otherwise.
The SPI controller is hard coded as a master. When a value is written to the 'write byte' register, it will drive eight clocks and transfer a single byte in each direction. Bit 0 of the SPI status register will be set to 1 while the transfer is occurring. It will go back to zero when the transfer is finished. At this point, the program may read the 'SPI read byte' register.
Address | r/w | Environment | Description |
---|---|---|---|
ffff00c0 | w | FEV | SD SPI write byte |
ffff00c4 | r | FEV | SD SPI read byte |
ffff00c8 | r | FEV | SD SPI status (bit 0: ready) |
ffff00cc | w | FEV | SD SPI control (bit 0: chip select) |
ffff00d0 | w | F V | SD clock divider |
Address | r/w | Environment | Description |
---|---|---|---|
ffff00c0 | w | F | SD GPIO direction |
ffff00c4 | w | F | SD GPIO value |
SD GPIO pins map to the following direction/value register bits:
Bit | Connection |
---|---|
0 | dat[0] |
1 | dat[1] |
2 | dat[2] |
3 | dat[3] |
4 | cmd |
5 | clk |
The loopback UART has its transmit and receive signals connected. It's used by UART unit tests and only exists in the Verilator environment.
Address | r/w | Environment | Description |
---|---|---|---|
ffff0140 | r | V | Loopback UART Status |
ffff0144 | r | V | Loopback UART read |
ffff0148 | w | V | Loopback UART write |
ffff014c | w | V | Loopback UART divider |
The VGA controller is hardcoded for 32 bits per pixel.
Address | r/w | Environment | Description |
---|---|---|---|
ffff0180 | w | FE | VGA sequencer enable |
ffff0184 | w | F | VGA microcode write |
ffff0188 | w | FE | VGA frame buffer base address |
ffff018c | w | F | VGA frame buffer length (total pixels) |
The timing signals are generated by a programmable timing generator that executes microprograms. It executes one instruction per pixel clock, which is hard coded for 25 MHz. The microinstruction is formatted as follows:
+------+-------+----------------+----------+----------+----------+------------+
| op(1)|cntr(1)| immediate (13) | vsync(1) | hsync(1) | frame(1) | visible(1) |
+------+-------+----------------+----------+----------+----------+------------+
- op: Operation. A 0 will load the immediate value into a counter. A 1 will decrement and test the given counter. If it is zero, it will branch to the instruction offset given in immediate field. Otherwise, it will fall through to the next instruction.
- cntr: Which counter this instruction uses. There are two counters: horizontal and vertical, although the hardware doesn't care which counter is used for what.
- immediate: For operation 0, the new counter value. For operation 1, the branch destination
- vsync: Value of vertical sync output when this instruction is executed
- hsync: Value of horizontal sync output when this instruction is executed
- frame: Indicates new frame. This will jump back to the first instruction of the program and restart the DMA engine from the frame buffer base address
- visible: If this is set, this will pull the next pixel out of the DMA FIFO and will configure the analog circuitry to output video signal (it will be at zero volts otherwise to give a valid reference signal)
The processor can load the microprogram into the VGA controller with the following sequence:
- Disable the sequencer by writing zero into the sequencer enable register.
- Write each instruction sequentially to the microcode write register. Each instruction is 18 bits, LSB aligned in the register word.
- Re-enable the sequencer by writing a 1 to the sequencer enable register.
In the emulator environment, the timing generator program is ignored. The frame buffer size is configured using command line parameters. The VGA frame buffer base address/length registers are still used to configure what gets displayed to the frame buffer window.
The programmable interrupt timer is a one shot timer that raises an interrupt when a specified number of clocks have elapsed. The timer is started as a side effect of writing a non-zero value to the interval register.
Address | r/w | Environment | Description |
---|---|---|---|
ffff0240 | w | F V | Timer interval (clocks) |