Skip to content

Commit b970476

Browse files
committed
Implement scrolling display peripheral
1 parent 21f495a commit b970476

File tree

4 files changed

+222
-4
lines changed

4 files changed

+222
-4
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ debug.json
1111
/src/main.mlog
1212
/src/debugger.mlog
1313
/src/config/*.mlog
14+
/src/peripherals/scrolling_display.mlog
1415

1516
node_modules/
1617

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ ASM_PROGRAMS = $(patsubst asm/%.s,%,$(wildcard asm/*.s))
22

33
RUST_PROGRAMS = $(filter-out webserver,$(patsubst rust/examples/%,%,$(wildcard rust/examples/*)))
44

5-
MLOG_PROGRAMS = $(patsubst src/%.mlog.jinja,%,$(wildcard src/*.mlog.jinja))
5+
MLOG_PROGRAMS = $(patsubst src/%.mlog.jinja,%,$(filter-out src/config/base.mlog.jinja,$(wildcard src/*.mlog.jinja) $(wildcard src/*/*.mlog.jinja)))
66

77
.PHONY: all
88
all: asm rust

python/src/mlogv32/preprocessor/filters.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def wrapper(*args: P.args, **kwargs: P.kwargs):
3737

3838
@make_jinja_exceptions_suck_a_bit_less
3939
@register_filter
40-
def ram_variable(index: int):
40+
def ram_var(index: int):
4141
return VariableFormat.min.get_variable(index)
4242

4343

@@ -48,9 +48,9 @@ def csr(name: str | int):
4848
case str():
4949
if name not in CSRS:
5050
raise KeyError(f"Invalid CSR: {name}")
51-
return ram_variable(CSRS[name])
51+
return ram_var(CSRS[name])
5252
case int():
53-
return ram_variable(name)
53+
return ram_var(name)
5454

5555

5656
@make_jinja_exceptions_suck_a_bit_less
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# display controller for printing text from a UART port, with automatic scrolling
2+
3+
#%# link the lookup tables first, then these blocks in this order, then the display
4+
#% set BUFFER = 'processor17'
5+
#% set INCR = 'processor18'
6+
#% set DECR = 'processor19'
7+
#% set CONFIG = 'processor20'
8+
#% set DISPLAY_POWER = 'switch1'
9+
#% set CPU_POWER = 'switch2'
10+
#% set UART = 'bank1'
11+
#% set LF_CHAR = 10
12+
#% set SPACE_CHAR = 32
13+
#% set TERM_WIDTH_CHARS = 70
14+
#% set TERM_HEIGHT_CHARS = 38
15+
#% set CHAR_WIDTH = 7
16+
#% set CHAR_HEIGHT = 13
17+
#% set BASE_X = 11
18+
#% set BASE_Y = 9
19+
#% set MAX_X = BASE_X + (TERM_WIDTH_CHARS - 1) * CHAR_WIDTH
20+
#% set MAX_Y = BASE_Y + (TERM_HEIGHT_CHARS - 1) * CHAR_HEIGHT
21+
#% set BUFFER_MAX_SIZE = TERM_WIDTH_CHARS * TERM_HEIGHT_CHARS
22+
23+
#% if false
24+
# {% raw %}
25+
set {{DISPLAY_POWER}} null
26+
set {{CPU_POWER}} null
27+
set {{BUFFER}} null
28+
set {{INCR}} null
29+
set {{DECR}} null
30+
set {{CONFIG}} null
31+
set {{UART}} null
32+
set {{LF_CHAR}} null
33+
set {{SPACE_CHAR}} null
34+
set {{TERM_WIDTH_CHARS}} null
35+
set {{CHAR_WIDTH}} null
36+
set {{CHAR_HEIGHT}} null
37+
set {{BASE_X}} null
38+
set {{BASE_Y}} null
39+
set {{MAX_X}} null
40+
set {{MAX_Y}} null
41+
set {{BUFFER_MAX_SIZE}} null
42+
# {% endraw %}
43+
#% endif
44+
45+
# character dimensions: 7x13 px
46+
# screen area: 512x512 px
47+
# borders: 8 px
48+
# safe area: 496x496 px
49+
# terminal size: 70x38 characters
50+
# base offset: 11 9 bottomLeft
51+
52+
# we can only do 256 draw instructions per tick, then the display buffer fills up
53+
54+
# when scrolling, we have to clear the screen, and it will take up to ~10.3 ticks to fully redraw
55+
# so we want to draw the most recently printed line first
56+
# therefore, the routines to fill and print the buffer iterate in opposite directions
57+
58+
reset:
59+
draw clear 0 0 0
60+
drawflush display1
61+
62+
reset_loop:
63+
sensor enabled {{DISPLAY_POWER}} @enabled
64+
jump reset_loop notEqual enabled true
65+
66+
setrate 10000
67+
68+
read UART_FIFO_MODULO {{CONFIG}} "UART_FIFO_MODULO"
69+
70+
# init INCR and DECR
71+
72+
set prev "{{ (BUFFER_MAX_SIZE - 1)|ram_var }}"
73+
set cur "{{ 0|ram_var }}"
74+
set i 1
75+
incr_decr_loop:
76+
op idiv lookup i 260
77+
getlink lookup lookup
78+
op mod next i 260
79+
lookup block next next
80+
sensor next next @name
81+
read next lookup next
82+
83+
write prev {{DECR}} cur
84+
write next {{INCR}} cur
85+
86+
set prev cur
87+
set cur next
88+
op add i i 1
89+
op mod i i {{BUFFER_MAX_SIZE}}
90+
91+
jump incr_decr_loop notEqual cur "{{ 0|ram_var }}"
92+
93+
# init display state
94+
95+
draw reset
96+
draw color 255 255 255 255
97+
draw clear 0 0 0
98+
drawflush display1
99+
100+
# buffer starts at 0, lines are 70-character aligned
101+
set buffer_write "{{ 0|ram_var }}"
102+
set buffer_write_col 0
103+
set buffer_y {{BASE_Y}}
104+
105+
set buffer_read buffer_write
106+
set print_x {{BASE_X}}
107+
set print_y {{MAX_Y}} # don't print anything until the uart reader sets print_y
108+
109+
read rx_read {{UART}} 510
110+
111+
main:
112+
# start each iteration with a new tick
113+
wait 0.0001
114+
115+
# move any new UART data to buffer
116+
read rx_write {{UART}} 511
117+
jump skip_uart_loop equal rx_read rx_write
118+
119+
set should_scroll false
120+
121+
uart_loop:
122+
op add index rx_read 256
123+
read char {{UART}} index
124+
125+
op add rx_read rx_read 1
126+
op mod rx_read rx_read UART_FIFO_MODULO
127+
write rx_read {{UART}} 510
128+
129+
write char {{BUFFER}} buffer_write
130+
read buffer_write {{INCR}} buffer_write
131+
op add buffer_write_col buffer_write_col 1
132+
133+
# if the character is LF, fill the rest of this line with more LF characters so the printer skips them
134+
jump uart_loop__not_lf notEqual char {{LF_CHAR}}
135+
jump uart_loop__not_lf greaterThanEq buffer_write_col {{TERM_WIDTH_CHARS}}
136+
137+
uart_loop__pad_lf:
138+
write char {{BUFFER}} buffer_write
139+
read buffer_write {{INCR}} buffer_write
140+
op add buffer_write_col buffer_write_col 1
141+
jump uart_loop__pad_lf lessThan buffer_write_col {{TERM_WIDTH_CHARS}}
142+
uart_loop__not_lf:
143+
144+
jump uart_loop__same_line lessThan buffer_write_col {{TERM_WIDTH_CHARS}}
145+
op add buffer_y buffer_y {{CHAR_HEIGHT}}
146+
op min buffer_y buffer_y {{MAX_Y}}
147+
set buffer_write_col 0
148+
set should_scroll true
149+
uart_loop__same_line:
150+
jump uart_loop notEqual rx_read rx_write
151+
152+
# if we need to scroll, clear the display
153+
jump uart__no_scroll notEqual should_scroll true
154+
draw clear 0 0 0
155+
uart__no_scroll:
156+
157+
# we received more characters, so redraw the text
158+
read buffer_read {{DECR}} buffer_write
159+
op sub print_x buffer_write_col 1
160+
op mul print_x print_x {{CHAR_WIDTH}}
161+
op add print_x print_x {{BASE_X}}
162+
set print_y {{BASE_Y}}
163+
164+
skip_uart_loop:
165+
166+
jump skip_print_loop greaterThan print_y buffer_y
167+
168+
sensor display_commands display1 @bufferUsage
169+
170+
# hack: if we're at the start of a new line, shift up immediately
171+
jump print_loop__shift_up lessThan print_x {{BASE_X}}
172+
173+
print_loop:
174+
read char {{BUFFER}} buffer_read
175+
read buffer_read {{DECR}} buffer_read
176+
177+
jump print_loop__no_print equal char {{LF_CHAR}}
178+
jump print_loop__no_print equal char {{SPACE_CHAR}}
179+
printchar char
180+
draw print print_x print_y bottomLeft
181+
op add display_commands display_commands 1
182+
print_loop__no_print:
183+
184+
op sub print_x print_x {{CHAR_WIDTH}}
185+
jump print_loop__same_line greaterThanEq print_x {{BASE_X}}
186+
print_loop__shift_up:
187+
set print_x {{MAX_X}}
188+
op add print_y print_y {{CHAR_HEIGHT}}
189+
jump skip_print_loop greaterThan print_y buffer_y
190+
print_loop__same_line:
191+
192+
jump print_loop lessThan display_commands 254
193+
194+
skip_print_loop:
195+
196+
drawflush display1
197+
198+
sensor enabled {{DISPLAY_POWER}} @enabled
199+
jump reset notEqual enabled true
200+
201+
# don't go into wait_for_cpu if we still need to finish printing the rest of the buffer
202+
jump main lessThanEq print_y buffer_y
203+
204+
sensor enabled {{CPU_POWER}} @enabled
205+
jump main equal enabled true
206+
207+
# if the cpu is turned off, wait until it turns back on, then reset the display
208+
wait_for_cpu:
209+
wait 0.0001
210+
211+
sensor enabled {{DISPLAY_POWER}} @enabled
212+
jump reset notEqual enabled true
213+
214+
sensor enabled {{CPU_POWER}} @enabled
215+
jump reset equal enabled true
216+
217+
jump wait_for_cpu always

0 commit comments

Comments
 (0)