-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontroller.mlog.jinja
More file actions
519 lines (393 loc) · 13.8 KB
/
controller.mlog.jinja
File metadata and controls
519 lines (393 loc) · 13.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
#% from 'worker.mlog.jinja' import fetch_variables with context
#% set UART_START_LINK = 16
#% set REGISTERS = 'cell1'
#% set LABELS = 'cell2'
#% set CSRS = 'processor17'
#% set INCR = 'processor18'
#% set CONFIG = 'processor19'
#% set CSR_LABELS = 'processor20'
#% set ERROR_OUTPUT = 'message1'
#% set POWER_SWITCH = 'switch1'
#% set PAUSE_SWITCH = 'switch2'
#% set SINGLE_STEP_SWITCH = 'switch3'
# we ONLY reset this variable if the controller is rebuilt or manually restarted
set skip_slow_init false
# disable the power switch, then reset
halt:
control enabled {{POWER_SWITCH}} false
control enabled {{PAUSE_SWITCH}} false
control enabled {{SINGLE_STEP_SWITCH}} false
# wait until the power switch is enabled, then reset/start
reset:
setrate 1000
# tell workers to halt
set prev_proc @this
set state "halt"
# load config
read MEMORY_X {{CONFIG}} "MEMORY_X"
read MEMORY_Y {{CONFIG}} "MEMORY_Y"
read MEMORY_WIDTH {{CONFIG}} "MEMORY_WIDTH"
read PROGRAM_ROM_SIZE {{CONFIG}} "PROGRAM_ROM_SIZE"
read DATA_ROM_SIZE {{CONFIG}} "DATA_ROM_SIZE"
read ROM_SIZE {{CONFIG}} "ROM_SIZE"
read RAM_SIZE {{CONFIG}} "RAM_SIZE"
read ICACHE_SIZE {{CONFIG}} "ICACHE_SIZE"
read RAM_END {{CONFIG}} "RAM_END"
read ICACHE_END {{CONFIG}} "ICACHE_END"
read UART_FIFO_MODULO {{CONFIG}} "UART_FIFO_MODULO"
read MTIME_SCALE {{CONFIG}} "MTIME_SCALE"
op idiv RAM_START_PROC ROM_SIZE {{ROM_PROC_BYTES}}
op add END_PROC RAM_SIZE ICACHE_SIZE
op idiv END_PROC END_PROC {{RAM_PROC_BYTES}}
op add END_PROC END_PROC RAM_START_PROC
# loop until the power switch is linked and enabled
sensor enabled {{POWER_SWITCH}} @enabled
jump reset equal enabled false
# initialize CPU
# align to tick
wait 1e-5
# change state from halt to reset, and set prev_proc again in case a worker changed it
set prev_proc @this
set state "reset"
jump end_slow_init equal skip_slow_init true
# disable RAM procs
set i 0
disable_ram:
op mod x i MEMORY_WIDTH
op add x x MEMORY_X
op idiv y i MEMORY_WIDTH
op add y y MEMORY_Y
getblock building ram x y
op lessThan enabled i RAM_START_PROC
control enabled ram enabled
op add i i 1
jump disable_ram lessThan i END_PROC
# initialize INCR and CSR_LABELS
set prev_variable "{{ 0|ram_var }}"
set address 4
init_incr:
# jump to ILLEGAL_OP for all unimplemented CSRs
#% set value = labels['ILLEGAL_OP'] * 1000 + labels['ILLEGAL_OP']
write {{value}} {{CSR_LABELS}} prev_variable
set variable null
op add ret @counter 1
jump lookup_variable lessThan address {{RAM_PROC_BYTES}}
write variable {{INCR}} prev_variable
# if the current variable is the start of a new page, write null to the previous variable
# this ensures the processor doesn't cross into another page while executing cached instructions
op mod page_offset address 4096
jump init_incr__not_null notEqual page_offset 0
write null {{INCR}} prev_variable
init_incr__not_null:
set prev_variable variable
op add address address 4
jump init_incr lessThanEq address {{RAM_PROC_BYTES}}
# initialize label lookup table
#% set ns = namespace(loop=0)
#% for instruction in instructions
#% set ns.i = instruction.address
# {{ instruction.label }}
#%#- unroll the loop if it's equal or better in terms of code size, else generate a loop
#% if instruction.count <= 4
#% for _ in range(instruction.count)
write {{labels[instruction.label]}} {{LABELS}} {{ns.i}}
#% set ns.i = ns.i + instruction.align
#% endfor
#% else
set i {{ns.i}}
#% set ns.i = ns.i + instruction.count * instruction.align
init_labels__loop{{ns.loop}}:
write {{labels[instruction.label]}} {{LABELS}} i
op add i i {{instruction.align}}
jump init_labels__loop{{ns.loop}} lessThan i {{ns.i}}
#% set ns.loop = ns.loop + 1
#% endif
#% endfor
# initialize CSR lookup table
#% for name, csr in csrs.items()
#% set read_label = 'csr_read_' ~ csr.read
#% set write_label = 'csr_write_' ~ csr.write if csr.write is not none else 'ILLEGAL_OP'
#% set value = csr.mask * 1_000_000 + labels[write_label] * 1000 + labels[read_label]
# {{ name }}
# read: {{ read_label }} ({{ labels[read_label] }})
# write: {{ write_label }} ({{ labels[write_label] }})
# mask: {{ csr.mask|bin(32) }}
write {{value}} {{CSR_LABELS}} "{{ name|csr }}"
#% endfor
# ^ all of this only needs to run once, so skip it on subsequent runs to make startup faster
set skip_slow_init true
end_slow_init:
# initialize peripherals
# text output
printflush {{ERROR_OUTPUT}}
# icache
set __etext 0
# debugging
op add ret @counter 1
jump get_breakpoint_address always
# UARTs
set uart_flags 0
set uart_rx_interrupt_ptrs 0xffffffff
set uart_tx_interrupt_ptrs 0xffffffff
op add ret @counter 1
jump update_uart_flags always
# reset hart state as per machine-level ISA
# set privilege mode to M
set privilege_mode 0b11
set effective_privilege_mode privilege_mode
# clear mstatus
# technically we're only supposed to clear MPRV and MIE, but the other bits are explicitly unspecified, so this is allowed
set csr_mstatus 0
# set pc to reset vector
set pc 0
set icache_var null
# set mcause to 0, since we don't distinguish different reset conditions
# use null so the debugger can tell if it's a reset or a misaligned instruction
# also set scause (unspecified)
write null {{CSRS}} "{{ 'mcause'|csr }}"
write null {{CSRS}} "{{ 'scause'|csr }}"
# clear LR/SC reservation set
set reservation_set null
# reset additional (unspecified) hart state
# clear registers
#% for _ in range(32)
write 0 {{REGISTERS}} {{loop.index0}}
#% endfor
# clear timers
set csr_mtime 0
set csr_mtimeh 0
set csr_mtimecmp 0
set csr_mtimecmph 0
set csr_stimecmp 0
set csr_stimecmph 0
set csr_minstret 0
write 0 {{CSRS}} "{{ 'minstreth'|csr }}"
set csr_mcycle 0
write 0 {{CSRS}} "{{ 'mcycleh'|csr }}"
# clear delegated traps
write 0 {{CSRS}} "{{ 'medeleg'|csr }}"
write 0 {{CSRS}} "{{ 'mideleg'|csr }}"
# clear pending/enabled interrupts
set csr_mip 0
set csr_mie 0
# reset mtvec and stvec to implementation-defined value to help catch bugs
write {{SYSCON}} {{CSRS}} "{{ 'mtvec'|csr }}"
write {{SYSCON}} {{CSRS}} "{{ 'stvec'|csr }}"
# clear satp
write 0 {{CSRS}} "{{ 'satp'|csr }}"
# misa
# XLEN=32 --
# 0 ----
# ISA ZYXWVUTSRQPONMLKJIHGFEDCBA
write 0b01000000100101000001000100000001 {{CSRS}} "{{ 'misa'|csr }}"
# mlogv32 only has one hart, so mhartid is required to be zero
write 0 {{CSRS}} "{{ 'mhartid'|csr }}"
# read-only zero CSRs
write 0 {{CSRS}} "{{ 'mvendorid'|csr }}"
write 0 {{CSRS}} "{{ 'marchid'|csr }}"
write 0 {{CSRS}} "{{ 'mimpid'|csr }}"
# default values for writable CSRs
write 0 {{CSRS}} "{{ 'mepc'|csr }}"
write 0 {{CSRS}} "{{ 'mscratch'|csr }}"
write 0 {{CSRS}} "{{ 'mtval'|csr }}"
write 0 {{CSRS}} "{{ 'sepc'|csr }}"
write 0 {{CSRS}} "{{ 'sscratch'|csr }}"
write 0 {{CSRS}} "{{ 'stval'|csr }}"
# align to tick
wait 1e-5
# set mtime reference point
set last_mtime_update @time
# start the workers
set prev_proc @this
set state "running"
next_tick:
wait 1e-5
# fetch current hart state
# note: we DO NOT update prev_proc here if not halting
#{ fetch_variables()
# perform any state transitions requested by the workers
# if halting/resetting, we don't modify the requesting worker's @counter
jump halt equal state "halt"
jump reset equal state "reset"
jump breakpoint equal state "breakpoint"
jump breakpoint equal state "trap_breakpoint"
end_breakpoint:
# poll hardware
sensor enabled {{POWER_SWITCH}} @enabled
jump state->halt equal enabled false
op add ret @counter 1
jump get_breakpoint_address always
write breakpoint_address prev_proc "breakpoint_address"
op add ret @counter 1
jump update_uart_flags always
write uart_flags prev_proc "uart_flags"
# check which CSR we're currently updating, if any
# update mtime
# TODO: handle mtimeh overflow
op sub _delta @time last_mtime_update
op mul _delta _delta MTIME_SCALE
op add csr_mtime csr_mtime _delta
op floor csr_mtime csr_mtime
op shr _overflow csr_mtime 32
op add csr_mtimeh csr_mtimeh _overflow
op mod csr_mtime csr_mtime 0x100000000
write csr_mtime prev_proc "csr_mtime"
write csr_mtimeh prev_proc "csr_mtimeh"
set last_mtime_update @time
# tell the next worker to poll and fire interrupts
op or csr_mip csr_mip 0b11000000000000000000000000000000
write csr_mip prev_proc "csr_mip"
# go to next tick
jump next_tick always
state->halt:
write 0 prev_proc "@counter"
jump halt always
breakpoint:
control enabled {{SINGLE_STEP_SWITCH}} true
control enabled {{PAUSE_SWITCH}} true
breakpoint__loop:
wait 1e-5
sensor enabled {{POWER_SWITCH}} @enabled
jump state->halt equal enabled false
sensor enabled {{SINGLE_STEP_SWITCH}} @enabled
jump breakpoint__end_loop equal enabled false
sensor enabled {{PAUSE_SWITCH}} @enabled
jump breakpoint__loop equal enabled true
breakpoint__end_loop:
control enabled {{PAUSE_SWITCH}} false
read counter prev_proc "@counter"
op add counter counter 1
write counter prev_proc "@counter"
set state "running"
write state prev_proc "state"
# pause timer while at a breakpoint
set last_mtime_update @time
jump end_breakpoint always
# -> breakpoint_address
get_breakpoint_address:
sensor enabled {{SINGLE_STEP_SWITCH}} @enabled
jump get_breakpoint_address__single_step equal enabled true
sensor enabled {{PAUSE_SWITCH}} @enabled
jump get_breakpoint_address__single_step equal enabled true
read breakpoint_address {{CONFIG}} "BREAKPOINT_ADDRESS"
set @counter ret
get_breakpoint_address__single_step:
set breakpoint_address "*"
set @counter ret
update_uart_flags:
set _uart_shift 0
update_uart_flags__loop:
op add _uart _uart_shift {{UART_START_LINK}}
getlink _uart _uart
read _rx_read _uart {{UART_RX_READ}}
read _rx_write _uart {{UART_RX_WRITE}}
read _tx_read _uart {{UART_TX_READ}}
read _tx_write _uart {{UART_TX_WRITE}}
op shl _interrupt_mask 1 _uart_shift
op mul _ptr_shift _uart_shift 8
op shl _clear_ptr_mask 0xff _ptr_shift
op not _clear_ptr_mask _clear_ptr_mask
# RX FIFO became non-empty
# don't generate interrupt if rx is empty
# in that case, set ptr to an invalid value so we don't mask a later interrupt here
set _new_ptr 0xff
jump update_uart_flags__set_rx_ptr equal _rx_read _rx_write
# don't generate interrupt if this is the last ptr we generated one at
set _new_ptr _rx_read
op shr _prev_ptr uart_rx_interrupt_ptrs _ptr_shift
op and _prev_ptr _prev_ptr 0xff
jump update_uart_flags__done_rx equal _prev_ptr _new_ptr
# generate interrupt
op or uart_flags uart_flags _interrupt_mask
update_uart_flags__set_rx_ptr:
op shl _new_ptr _new_ptr _ptr_shift
op and uart_rx_interrupt_ptrs uart_rx_interrupt_ptrs _clear_ptr_mask
op or uart_rx_interrupt_ptrs uart_rx_interrupt_ptrs _new_ptr
update_uart_flags__done_rx:
# TX FIFO became empty
# don't generate interrupt if tx is not empty
# in that case, set ptr to an invalid value so we don't mask a later interrupt here
set _new_ptr 0xff
jump update_uart_flags__set_tx_ptr notEqual _tx_read _tx_write
# don't generate interrupt if this is the last ptr we generated one at
set _new_ptr _tx_write
op shr _prev_ptr uart_tx_interrupt_ptrs _ptr_shift
op and _prev_ptr _prev_ptr 0xff
jump update_uart_flags__done_tx equal _prev_ptr _new_ptr
# generate interrupt
op or uart_flags uart_flags _interrupt_mask
update_uart_flags__set_tx_ptr:
op shl _new_ptr _new_ptr _ptr_shift
op and uart_tx_interrupt_ptrs uart_tx_interrupt_ptrs _clear_ptr_mask
op or uart_tx_interrupt_ptrs uart_tx_interrupt_ptrs _new_ptr
update_uart_flags__done_tx:
# next UART
op add _uart_shift _uart_shift 1
jump update_uart_flags__loop lessThan _uart_shift 4
set @counter ret
# given a value 0 <= address < RAM_PROC_BYTES, resolve that variable in the lookup table
# address -> variable
lookup_variable:
# convert from address (bytes) to index (vars)
op idiv _index address 4
op idiv _lookup _index {{LOOKUP_PROC_SIZE}}
getlink _lookup _lookup
op mod variable _index {{LOOKUP_PROC_SIZE}}
lookup block variable variable
sensor variable variable @name
read variable _lookup variable
set @counter ret
#% if false
# disable mlogls warnings
# {% raw %}
# common preprocessor constants
set {{LOOKUP_PROC_SIZE}} null
set {{ROM_PROC_BYTES}} null
set {{RAM_PROC_BYTES}} null
set {{SYSCON}} null
set {{UART_RX_READ}} null
set {{UART_RX_WRITE}} null
set {{UART_TX_READ}} null
set {{UART_TX_WRITE}} null
# local preprocessor constants
set {{UART_START_LINK}} null
set {{REGISTERS}} null
set {{LABELS}} null
set {{CSRS}} null
set {{INCR}} null
set {{CONFIG}} null
set {{CSR_LABELS}} null
set {{ERROR_OUTPUT}} null
set {{SINGLE_STEP_SWITCH}} null
set {{POWER_SWITCH}} null
set {{PAUSE_SWITCH}} null
set {{labels[instruction.label]}} null
set {{instruction.align}} null
set {{loop.index0}} null
set {{ns.i}} null
set {{value}} null
# unused variables
set _ PROGRAM_ROM_SIZE
set _ DATA_ROM_SIZE
set _ ICACHE_END
set _ UART_FIFO_MODULO
set _ RAM_END
set _ pc
set _ icache_var
set _ __etext
set _ privilege_mode
set _ effective_privilege_mode
set _ reservation_set
set _ csr_mcycle
set _ csr_mtime
set _ csr_mtimeh
set _ csr_mtimecmp
set _ csr_mtimecmph
set _ csr_stimecmp
set _ csr_stimecmph
set _ csr_minstret
set _ csr_mstatus
set _ csr_mip
set _ csr_mie
# {% endraw %}
#% endif