Add info about SoC software
This commit is contained in:
parent
f4164ca3f2
commit
287fa0b7ee
1 changed files with 51 additions and 0 deletions
|
@ -177,6 +177,57 @@ Bridging the internal SoC bus with the external peripheral bus requires a few st
|
||||||
|
|
||||||
Due to a mistake in the adapter board layout, the nibbles of the address and data buses are reversed (MSB to LSB are pins 7 to 0 on the FPGA, but 3 to 0 followed by 7 to 4 on the board). Thanks to the completely arbitrary mapping of FPGA pins, this can be mitigated without using any additional resources.
|
Due to a mistake in the adapter board layout, the nibbles of the address and data buses are reversed (MSB to LSB are pins 7 to 0 on the FPGA, but 3 to 0 followed by 7 to 4 on the board). Thanks to the completely arbitrary mapping of FPGA pins, this can be mitigated without using any additional resources.
|
||||||
|
|
||||||
|
\section{Software}
|
||||||
|
|
||||||
|
\subsection{Bootloader}
|
||||||
|
|
||||||
|
The CPU loads its machine code from an FPGA-internal block RAM. The initial value for this RAM is part of the bitstream, and if any changes to it are required, the entire project has to be resynthesized. Because this takes upwards of 5 minutes, a different solution was created: a fixed bootloader is encoded into the block RAM, which is able to read additional program code (the payload) from the UART at runtime and store it to available memory. After the transfer is complete, it simply jumps to the base address of the payload and continues execution from there. When the current payload exits or a hardware reset is actuated, a new program can be loaded instantly.
|
||||||
|
|
||||||
|
Because many subroutines are used in both the loader and the payload, duplicating them in the payload would be a waste of space. Using custom linker scripts and compiler flags, the payload is linked against the functions in the loader. Whenever a loader function is called from the payload, execution jumps to bootloader code, executes the requested actions and then returns to the payload.
|
||||||
|
|
||||||
|
\subsection{Drivers}
|
||||||
|
|
||||||
|
Several components required writing functions to make them easier to use. Some are as simple as writing a value to a specific memory location:
|
||||||
|
|
||||||
|
\begin{lstlisting}[
|
||||||
|
language=c,
|
||||||
|
label={lst:yarm-set-rgb-led},
|
||||||
|
caption={Function to set the colour of an RGB LED on the Arty board}]
|
||||||
|
void set_rgb_led(size_t num, uint32_t color) {
|
||||||
|
((volatile uint32_t*)ADDRESS_RGB_LEDS)[num] = color;
|
||||||
|
}
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
Others, like the function to write a character to the screen are more complicated and use further subroutines:
|
||||||
|
|
||||||
|
\begin{lstlisting}[
|
||||||
|
language=c,
|
||||||
|
label={lst:yarm-vga-putchar},
|
||||||
|
caption={Function to write a character to the screen}]
|
||||||
|
void vga_putchar(screen_t *s, unsigned char c) {
|
||||||
|
switch(c) {
|
||||||
|
case '\n':
|
||||||
|
set_cursor_pos(s, s->row + 1, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\b':
|
||||||
|
// DEL
|
||||||
|
case 0x7F:
|
||||||
|
if (s->col > 0) {
|
||||||
|
set_cursor_pos(s, s->row, s->col - 1);
|
||||||
|
}
|
||||||
|
if (c == 0x7F) {
|
||||||
|
set_curr_char(s, ' ');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
set_curr_char(s, c);
|
||||||
|
set_cursor_pos(s, s->row, s->col + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
\section{Testing}
|
\section{Testing}
|
||||||
|
|
||||||
\subsection{RISC-V Compliance Tests}
|
\subsection{RISC-V Compliance Tests}
|
||||||
|
|
Loading…
Reference in a new issue