Skip to content

Commit fc4f415

Browse files
committed
Implement UART0 and UART1
1 parent 145dd75 commit fc4f415

File tree

30 files changed

+1392
-427
lines changed

30 files changed

+1392
-427
lines changed

.github/.devcontainer/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhisto
2020
# avoid permission issues with cargo if cargo install runs as root
2121
USER ${USERNAME}
2222

23-
RUN rustup toolchain install nightly-2024-11-16
23+
RUN rustup toolchain install nightly-2025-06-10
2424

2525
# NOTE: add the following to rustflags if using riscv32imac, since we don't support compressed instructions
2626
# "-C", "target-feature=-c",
2727
RUN rustup target add riscv32i-unknown-none-elf
2828
RUN rustup target add riscv32im-unknown-none-elf
2929
RUN rustup target add riscv32imac-unknown-none-elf
3030

31-
RUN rustup component add --toolchain nightly-2024-11-16 clippy llvm-tools
31+
RUN rustup component add --toolchain nightly-2025-06-10 clippy llvm-tools
3232

3333
RUN cargo install cargo-binutils

README.md

Lines changed: 99 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,80 @@ RISC-V processor in Mindustry logic. Requires Mindustry build 149+.
88

99
Physical memory consists of three sections. Two are directly accessible by code: ROM (rx) and RAM (rwx). The third section is an instruction cache which is 4x less dense than main memory.
1010

11-
The instruction cache should be initialized at boot using the MLOGSYS instruction. It is also updated whenever an instruction writes to RAM that is covered by the icache. If executing from memory not covered by the icache, the processor manually fetches and decodes the instruction from main memory.
12-
13-
Code begins executing at address `0x00000000` (ie. the start of ROM).
11+
For maximum performance, the instruction cache for ROM can be initialized at boot using the MLOGSYS instruction. It is also updated whenever an instruction writes to RAM that is covered by the icache. If executing from memory not covered by the icache, the processor manually fetches and decodes the instruction from main memory.
1412

1513
The main CPU code is generated from `src/main.mlog.jinja` using a custom Jinja-based preprocessor (`python/src/mlogv32/preprocessor`).
1614

1715
## Memory
1816

19-
| Address | Value |
20-
| ------------ | ----- |
21-
| `0x00000000` | ROM |
22-
| `0x80000000` | RAM |
23-
| `0xf0000000` | MMIO |
17+
| Address | Size | Access Type | Name |
18+
| ------------ | ------------ | ----------- | ----------- |
19+
| `0x00000000` | Configurable | R/X | ROM |
20+
| `0x80000000` | Configurable | R/W/X/A\* | RAM |
21+
| `0xf0000000` | `0x4` | R/W | `mtime` |
22+
| `0xf0000004` | `0x4` | R/W | `mtimeh` |
23+
| `0xf0000008` | `0x4` | R/W | `mtimecmp` |
24+
| `0xf000000c` | `0x4` | R/W | `mtimecmph` |
25+
| `0xf0000010` | `0x20` | R/W | UART0 |
26+
| `0xf0000030` | `0x20` | R/W | UART1 |
27+
| `0xfffffff0` | `0x4` | W | Syscon |
28+
29+
\* Atomic instructions are only supported in RAM.
30+
31+
Code begins executing at address `0x00000000` (ie. the start of ROM).
32+
33+
Addresses `0xf0000000` - `0xffffffff` are reserved for system purposes such as MMIO.
34+
35+
### UART
36+
37+
Addresses `0xf0000010` and `0xf0000030` contain emulated UART 16550 peripherals based on [this datasheet](https://caro.su/msx/ocm_de1/16550.pdf). The UARTs support the following features:
38+
39+
- Configurable FIFO capacity (up to 254 bytes) for TX and RX, stored as a variable in the CONFIG processor.
40+
- Theoretical maximum transfer rate of 121920 bits/sec (254 bytes/tick).
41+
- Line Status Register flags: Transmitter Empty, THR Empty, Overrun Error, Data Ready.
42+
43+
The UART registers have a stride of 4 bytes to simplify some internal logic.
44+
45+
| Offset | Access Type | Register |
46+
| ------ | ----------- | ---------------------------- |
47+
| `0x00` | R | Receiver Holding Register |
48+
| `0x00` | W | Transmitter Holding Register |
49+
| `0x04` | R/W | Interrupt Enable Register |
50+
| `0x08` | R | Interrupt Status Register |
51+
| `0x08` | W | FIFO Control Register |
52+
| `0x0c` | R/W | Line Control Register |
53+
| `0x10` | R/W | Modem Control Register |
54+
| `0x14` | R | Line Status Register |
55+
| `0x18` | R | Modem Status Register |
56+
| `0x1c` | R/W | Scratch Pad Register |
57+
58+
Each UART is implemented as two circular buffers in a memory bank with the following layout. Note that RX refers to data sent to / read by the processor, and TX refers to data sent from / written by the processor.
59+
60+
| Index | Name |
61+
| ----- | ----------------------- |
62+
| 0 | RX buffer start |
63+
| 254 | RX buffer read pointer |
64+
| 255 | RX buffer write pointer |
65+
| 256 | TX buffer start |
66+
| 510 | TX buffer read pointer |
67+
| 511 | TX buffer write pointer |
68+
69+
Read/write pointers are stored modulo `2 * capacity` ([ref 1](https://github.com/hathach/tinyusb/blob/b203d9eaf7d76fd9fec71b4ee327805a80594574/src/common/tusb_fifo.h), [ref 2](https://gist.github.com/mcejp/719d3485b04cfcf82e8a8734957da06a)) to allow using the entire buffer capacity without introducing race conditions.
70+
71+
If the RX buffer is full and more data arrives, producers should discard the new data rather than overwriting old data in the buffer. An overflow may optionally be indicated by advancing the RX write pointer (without writing a value to the buffer) such that the size of the buffer is `capacity + 1`; this must be done atomically (ie. `wait` first) to avoid race conditions.
72+
73+
Note that the processor itself does not prevent code from overflowing the TX buffer. Users are expected to check the Line Status Register and avoid writing too much data at once.
74+
75+
### Syscon
2476

25-
Addresses `0xf0000000` - `0xffffffff` are reserved for MMIO and other system purposes.
77+
Address `0xfffffff0` contains a simple write-only peripheral which can be used to control the system by writing values from the following table. Unsupported values will have no effect if written.
2678

27-
| Address | Value |
28-
| ------------ | --------------------- |
29-
| `0xf0000000` | `mtime` |
30-
| `0xf0000004` | `mtimeh` |
31-
| `0xf0000008` | `mtimecmp` |
32-
| `0xf000000c` | `mtimecmph` |
33-
| `0xfffffffc` | `mtvec` default value |
79+
| Value | Effect |
80+
| ------------ | --------- |
81+
| `0x00000000` | Power off |
82+
| `0x00000001` | Reboot |
3483

35-
The machine trap vector CSR `mtvec` is initialized to `0xfffffffc` at reset. To help catch issues with uninitialized `mtvec`, the processor will halt if code jumps to this address.
84+
Additionally, the machine trap vector CSR `mtvec` is initialized to `0xfffffff0` at reset. To help catch issues with uninitialized `mtvec`, the processor will halt and output an error message if code jumps to this address.
3685

3786
## ISA
3887

@@ -61,41 +110,41 @@ This non-standard extension adds instructions to control the mlogv32 processor's
61110
| funct12 (31:20) | rs1 (19:15) | funct3 (14:12) | rd (11:7) | opcode (6:0) | name |
62111
| --------------- | ----------- | -------------- | --------- | ------------ | -------- |
63112
| funct12 | rs1 | `000` | `00000` | `0001011` | MLOGSYS |
64-
| funct12 | `00000` | `001` | rd | `0001011` | MLOGDRAW |
113+
| funct12 | rs1 | `001` | `00000` | `0001011` | MLOGDRAW |
65114

66115
The MLOG instructions are encoded with an I-type instruction format using the _custom-0_ opcode. The zero-extended immediate is used as a minor opcode (funct12) for implementation reasons.
67116

68-
The MLOGSYS instruction is used for simple system controls, including halt, `printchar`, `printflush`, `drawflush`, sortKB/kbconv integration, and icache initialization.
69-
70-
| funct12 | rd | rs1 | name |
71-
| ------- | ----------------------- | --------- | -------------------------- |
72-
| 0 | `00000` | `00000` | Halt |
73-
| 1 | `00000` | char | `printchar` |
74-
| 2 | `00000` | `00000` | `printflush` |
75-
| 3 | `00000` | `00000` | `drawflush` |
76-
| 4 | char (0 if no new data) | `00000` | Read next char from sortKB |
77-
| 5 | `00000` | \_\_etext | Decode ROM .text section |
78-
79-
The MLOGDRAW instruction is used for drawing graphics using the Mlog `draw` instruction. Arguments are passed to this instruction using registers a0 to a5 as necessary, and any return value is placed in _rd_. If _rd_ is specified as `00000` in the below table, no value will be written to `rd` in any case.
80-
81-
| funct12 | rd | a0 | a1 | a2 | a3 | a4 | a5 | name |
82-
| ------- | ----------------------- | ------- | ----- | --------- | ------ | -------- | -------- | ---------------- |
83-
| 0 | `00000` | red | green | blue | | | | `draw clear` |
84-
| 1 | `00000` | red | green | blue | alpha | | | `draw color` |
85-
| 2 | `00000` | color | | | | | | `draw col` |
86-
| 3 | `00000` | width | | | | | | `draw stroke` |
87-
| 4 | `00000` | x1 | y1 | x2 | y2 | | | `draw line` |
88-
| 5 | `00000` | x | y | width | height | | | `draw rect` |
89-
| 6 | `00000` | x | y | width | height | | | `draw lineRect` |
90-
| 7 | `00000` | x | y | sides | radius | rotation | | `draw poly` |
91-
| 8 | `00000` | x | y | sides | radius | rotation | | `draw linePoly` |
92-
| 9 | `00000` | x1 | y1 | x2 | y2 | x3 | y3 | `draw triangle` |
93-
| 10 | lookup success (1 or 0) | x | y | type | id | size | rotation | `draw image` |
94-
| 11 | `00000` | x | y | alignment | | | | `draw print` |
95-
| 12 | `00000` | x | y | | | | | `draw translate` |
96-
| 13 | `00000` | x | y | | | | | `draw scale` |
97-
| 14 | `00000` | degrees | | | | | | `draw rotate` |
98-
| 15 | `00000` | | | | | | | `draw reset` |
117+
The MLOGSYS instruction is used for simple system controls, including `printchar`, `printflush`, `drawflush`, and icache initialization.
118+
119+
The `mlogsys.icache` instruction uses register _rs1_ as the number of bytes to decode. This can be generated by using a linker script to find the end address of the `.text` section and load it using `li`. The actual number of bytes decoded will be the smallest of _rs1_, the size of the icache, and the size of ROM.
120+
121+
| funct12 | rs1 | name |
122+
| ------- | ------- | --------------------- |
123+
| 0 | length | Initialize ROM icache |
124+
| 1 | char | `printchar` |
125+
| 2 | `00000` | `printflush` |
126+
| 3 | `00000` | `drawflush` |
127+
128+
The MLOGDRAW instruction is used for drawing graphics using the Mlog `draw` instruction. Arguments are passed to this instruction using registers _rs1_, a1, a2, a3, a4, and a5 as necessary.
129+
130+
| funct12 | rs1 | a1 | a2 | a3 | a4 | a5 | name |
131+
| ------- | ------- | ----- | ----- | ------ | -------- | -------- | ---------------- |
132+
| 0 | red | green | blue | | | | `draw clear` |
133+
| 1 | red | green | blue | alpha | | | `draw color` |
134+
| 2 | color | | | | | | `draw col` |
135+
| 3 | width | | | | | | `draw stroke` |
136+
| 4 | x1 | y1 | x2 | y2 | | | `draw line` |
137+
| 5 | x | y | width | height | | | `draw rect` |
138+
| 6 | x | y | width | height | | | `draw lineRect` |
139+
| 7 | x | y | sides | radius | rotation | | `draw poly` |
140+
| 8 | x | y | sides | radius | rotation | | `draw linePoly` |
141+
| 9 | x1 | y1 | x2 | y2 | x3 | y3 | `draw triangle` |
142+
| 10 | x | y | type | id | size | rotation | `draw image` |
143+
| 11 | x | y | | | | | `draw print` |
144+
| 12 | x | y | | | | | `draw translate` |
145+
| 13 | x | y | | | | | `draw scale` |
146+
| 14 | degrees | | | | | | `draw rotate` |
147+
| 15 | `00000` | | | | | | `draw reset` |
99148

100149
#### `draw col`
101150

@@ -118,17 +167,7 @@ Returns 1 if the id was successfully looked up, or 0 if the lookup returned null
118167

119168
#### `draw print`
120169

121-
| Alignment | Value |
122-
| ----------- | ----- |
123-
| bottom | 0 |
124-
| bottomLeft | 1 |
125-
| bottomRight | 2 |
126-
| center | 3 |
127-
| left | 4 |
128-
| right | 5 |
129-
| top | 6 |
130-
| topLeft | 7 |
131-
| topRight | 8 |
170+
Only alignment `topLeft` is supported.
132171

133172
## riscv-arch-test
134173

asm/print.s

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ loop:
1414

1515
.insn i CUSTOM_0, 0, zero, zero, 2 # printflush
1616

17-
.insn i CUSTOM_0, 0, zero, zero, 0 # halt
17+
# halt
18+
li t0, 0xfffffff0
19+
sw zero, 0(t0)
1820

1921
.section .rodata
2022
msg:

asm/trap.s

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ _start:
55

66
ecall
77

8-
.insn i CUSTOM_0, 0, zero, zero, 0 # halt
8+
# halt
9+
li t0, 0xfffffff0
10+
sw zero, 0(t0)
911

1012
trap:
1113
csrr t0, mepc

coremark/mlogv32/core_portme.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,5 +157,6 @@ portable_fini(core_portable *p)
157157
{
158158
p->portable_id = 0;
159159

160-
MLOGSYS_halt();
160+
int volatile * const syscon = (int*) 0xfffffff0;
161+
*syscon = 0;
161162
}

coremark/mlogv32/ee_printf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ ee_printf(const char *fmt, ...)
710710
p++;
711711
}
712712

713-
MLOGDRAW_print(old_print_x, old_print_y, 7);
713+
MLOGDRAW_print(old_print_x, old_print_y);
714714
MLOGSYS_drawflush();
715715

716716
return n;

coremark/mlogv32/entry.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
_start:
55
# initialize icache
66
la t0, __etext
7-
.insn i CUSTOM_0, 0, zero, t0, 5
7+
.insn i CUSTOM_0, 0, zero, t0, 0
88

99
# reset mtime/mcycle/minstret
1010
li t0, 0xf0000000 # mtime

coremark/mlogv32/xmlogsys.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ _create_MLOGDRAW_5(poly, 7)
1212
_create_MLOGDRAW_5(linePoly, 8)
1313
_create_MLOGDRAW_6(triangle, 9)
1414
_create_MLOGDRAW_6(image, 10)
15-
_create_MLOGDRAW_3(print, 11)
15+
_create_MLOGDRAW_2(print, 11)
1616
_create_MLOGDRAW_2(translate, 12)
1717
_create_MLOGDRAW_2(scale, 13)
1818
_create_MLOGDRAW_1(rotate, 14)

coremark/mlogv32/xmlogsys.h

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#define MLOGSYS_halt() asm volatile (".insn i CUSTOM_0, 0, zero, zero, 0" : : )
21
#define MLOGSYS_printchar(c) asm volatile (".insn i CUSTOM_0, 0, zero, %0, 1" : : "r" (c) )
32
#define MLOGSYS_printflush() asm volatile (".insn i CUSTOM_0, 0, zero, zero, 2" : : )
43
#define MLOGSYS_drawflush() asm volatile (".insn i CUSTOM_0, 0, zero, zero, 3" : : )
@@ -23,10 +22,9 @@ void MLOGDRAW_ ## NAME ( \
2322
#define _create_MLOGDRAW_1(NAME, FUNCT12) \
2423
_declare_MLOGDRAW_1(NAME) \
2524
{ \
26-
register ee_ptr_int a0 asm ("a0") = (ee_ptr_int)(arg0); \
27-
asm volatile (".insn i CUSTOM_0, 1, zero, zero, " #FUNCT12 \
25+
asm volatile (".insn i CUSTOM_0, 1, zero, %0, " #FUNCT12 \
2826
: \
29-
: "r" (a0) \
27+
: "r" (arg0) \
3028
:); \
3129
}
3230

@@ -39,11 +37,10 @@ void MLOGDRAW_ ## NAME ( \
3937
#define _create_MLOGDRAW_2(NAME, FUNCT12) \
4038
_declare_MLOGDRAW_2(NAME) \
4139
{ \
42-
register ee_ptr_int a0 asm ("a0") = (ee_ptr_int)(arg0); \
4340
register ee_ptr_int a1 asm ("a1") = (ee_ptr_int)(arg1); \
44-
asm volatile (".insn i CUSTOM_0, 1, zero, zero, " #FUNCT12 \
41+
asm volatile (".insn i CUSTOM_0, 1, zero, %0, " #FUNCT12 \
4542
: \
46-
: "r" (a0), "r" (a1) \
43+
: "r" (arg0), "r" (a1) \
4744
:); \
4845
}
4946

@@ -57,12 +54,11 @@ void MLOGDRAW_ ## NAME ( \
5754
#define _create_MLOGDRAW_3(NAME, FUNCT12) \
5855
_declare_MLOGDRAW_3(NAME) \
5956
{ \
60-
register ee_ptr_int a0 asm ("a0") = (ee_ptr_int)(arg0); \
6157
register ee_ptr_int a1 asm ("a1") = (ee_ptr_int)(arg1); \
6258
register ee_ptr_int a2 asm ("a2") = (ee_ptr_int)(arg2); \
63-
asm volatile (".insn i CUSTOM_0, 1, zero, zero, " #FUNCT12 \
59+
asm volatile (".insn i CUSTOM_0, 1, zero, %0, " #FUNCT12 \
6460
: \
65-
: "r" (a0), "r" (a1), "r" (a2) \
61+
: "r" (arg0), "r" (a1), "r" (a2) \
6662
:); \
6763
}
6864

@@ -77,13 +73,12 @@ void MLOGDRAW_ ## NAME ( \
7773
#define _create_MLOGDRAW_4(NAME, FUNCT12) \
7874
_declare_MLOGDRAW_4(NAME) \
7975
{ \
80-
register ee_ptr_int a0 asm ("a0") = (ee_ptr_int)(arg0); \
8176
register ee_ptr_int a1 asm ("a1") = (ee_ptr_int)(arg1); \
8277
register ee_ptr_int a2 asm ("a2") = (ee_ptr_int)(arg2); \
8378
register ee_ptr_int a3 asm ("a3") = (ee_ptr_int)(arg3); \
84-
asm volatile (".insn i CUSTOM_0, 1, zero, zero, " #FUNCT12 \
79+
asm volatile (".insn i CUSTOM_0, 1, zero, %0, " #FUNCT12 \
8580
: \
86-
: "r" (a0), "r" (a1), "r" (a2), "r" (a3) \
81+
: "r" (arg0), "r" (a1), "r" (a2), "r" (a3) \
8782
:); \
8883
}
8984

@@ -99,14 +94,13 @@ void MLOGDRAW_ ## NAME ( \
9994
#define _create_MLOGDRAW_5(NAME, FUNCT12) \
10095
_declare_MLOGDRAW_5(NAME) \
10196
{ \
102-
register ee_ptr_int a0 asm ("a0") = (ee_ptr_int)(arg0); \
10397
register ee_ptr_int a1 asm ("a1") = (ee_ptr_int)(arg1); \
10498
register ee_ptr_int a2 asm ("a2") = (ee_ptr_int)(arg2); \
10599
register ee_ptr_int a3 asm ("a3") = (ee_ptr_int)(arg3); \
106100
register ee_ptr_int a4 asm ("a4") = (ee_ptr_int)(arg4); \
107-
asm volatile (".insn i CUSTOM_0, 1, zero, zero, " #FUNCT12 \
101+
asm volatile (".insn i CUSTOM_0, 1, zero, %0, " #FUNCT12 \
108102
: \
109-
: "r" (a0), "r" (a1), "r" (a2), "r" (a3), "r" (a4) \
103+
: "r" (arg0), "r" (a1), "r" (a2), "r" (a3), "r" (a4) \
110104
:); \
111105
}
112106

@@ -123,15 +117,14 @@ void MLOGDRAW_ ## NAME ( \
123117
#define _create_MLOGDRAW_6(NAME, FUNCT12) \
124118
_declare_MLOGDRAW_6(NAME) \
125119
{ \
126-
register ee_ptr_int a0 asm ("a0") = (ee_ptr_int)(arg0); \
127120
register ee_ptr_int a1 asm ("a1") = (ee_ptr_int)(arg1); \
128121
register ee_ptr_int a2 asm ("a2") = (ee_ptr_int)(arg2); \
129122
register ee_ptr_int a3 asm ("a3") = (ee_ptr_int)(arg3); \
130123
register ee_ptr_int a4 asm ("a4") = (ee_ptr_int)(arg4); \
131124
register ee_ptr_int a5 asm ("a5") = (ee_ptr_int)(arg5); \
132-
asm volatile (".insn i CUSTOM_0, 1, zero, zero, " #FUNCT12 \
125+
asm volatile (".insn i CUSTOM_0, 1, zero, %0, " #FUNCT12 \
133126
: \
134-
: "r" (a0), "r" (a1), "r" (a2), "r" (a3), "r" (a4), "r" (a5) \
127+
: "r" (arg0), "r" (a1), "r" (a2), "r" (a3), "r" (a4), "r" (a5) \
135128
:); \
136129
}
137130

@@ -146,7 +139,7 @@ _declare_MLOGDRAW_5(poly);
146139
_declare_MLOGDRAW_5(linePoly);
147140
_declare_MLOGDRAW_6(triangle);
148141
_declare_MLOGDRAW_6(image);
149-
_declare_MLOGDRAW_3(print);
142+
_declare_MLOGDRAW_2(print);
150143
_declare_MLOGDRAW_2(translate);
151144
_declare_MLOGDRAW_2(scale);
152145
_declare_MLOGDRAW_1(rotate);

0 commit comments

Comments
 (0)