-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathos.s
4748 lines (4184 loc) · 82.8 KB
/
os.s
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
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* The universe is made of 12 particles of matter, 4 forces of nature
* # Dice and dfr OS
* This non-deterministic, unjust universe, I cannot accept it.
* "Blast reality. Synapse break. Banishment, this world!"
* "Nature uses only the longest threads to weave her patterns, so that each small piece of her fabric reveals the organization of the entire tapestry."
* Hmmmmmm.
*
* TODO: fork pre-increments process num
* TODO: wait for child
*
* ## Conventions
* - Most registers are callee-saved; I find this easier to work with
* - r0 is zero (hardware)
* - r2 is return (least significant bits) (caller-saved), could be used as temporary register
* - r3 is return (most significant bits) (caller-saved), could be used as temporary register
* - r4-r7 are first 16 bytes of arguments (callee-saved, preferably avoid modifying)
* - r8-r23 (16 registers, 64 bytes) are general purpose (callee-saved)
* - et (r24) is exception temporary (used by the interrupt handler and OS in general)
* - sp (r27) is the stack pointer
* - ea (r29) is exception return address (used by the interrupt handler and OS in general)
* - ra (r31) is return address (callee-saved)
* - Variables start at r8, values (constants) start at r23
* - Heavily comment code (explain "what" and "why")
* - Because system calls cannot be interrupted, the use of `et` in os functions is safe
* - i.e. `et` is a temporary register in os functions. Should not be used in user space
* - also, it follows that `et` and `ea` do not need to be saved accross processes
*
* ## Shoutouts
* - Susan (nasus -> the late game terror -> VM)
* - Skye (editor)
* - The Master
* - The Rational (the rational mind *maps* reality)
* - Romanian innovations (filesystem)
* - bdel (homage -> shell)
* - Vechs (vector -> vec -> vecs)
*
* ## Readings
* - http://www.linusakesson.net/programming/tty/
* - https://github.com/Raekye/bdel_and_dfr_compiler/blob/master/stdlib.txt
* - http://www-ug.eecg.toronto.edu/msl/manuals/DE2_Media_Computer.pdf
* - http://www-ug.eecg.toronto.edu/msl/nios_devices/
*
* ## System calls
* ### At the beginning
* ```
* # disable interrupts
* wrctl ctl0, r0
* # save old value of ctl1
* rdctl et, ctl1
* addi sp, sp, -4
* stw et, 0(sp)
* # interrupts now "were last" disabled
* wrctl ctl1, r0
* ```
*
* ### At the end
* ```
* # get last value of ctl1
* ldw et, 0(sp)
* addi sp, sp, 4
* # update ctl1
* wrctl ctl1, et
* # return and update ctl0
* mov ea, ra
* eret
* ```
*
* ### List
* - memory
* - os_malloc
* - os_free
* - romania
* - os_cp
* - os_rm
* - os_cat
* - os_touch
* - os_mkdir
* - os_fwrite
* - os_fappend
* - os_romania_node_from_name
* - os_romania_name_from_node
* - os_romania_parent
* - os_romania_is_dir
* - processes
* - os_fork
* - os_foreground_delegate
* - os_sleep
* - os_mort
* - os_wait
* - io
* - os_putchar
* - os_putchar_sync
* - os_readchar
*
* ## Romania
* - inodes (16 bytes) * 256 (2 ^ 8) for total 4096 bytes
* - byte 0
* - bit 0: in use
* - bit 1: 0 for directory, 1 for file
* - bits 4-7: upper 4 bits of index of first block
* - byte 1: lower 8 bits of index of first block (range 2 ^ 12 = 4096)
* - byte 2: parent node id
* - bytes 3-15: name, null terminated, max length 12 (excluding null)
* - blocks (256 bytes) * 1024 (2 ^ 8 * 4) for total 262144 bytes
* - common
* - byte 0: 0 for free, 1 for in use
* - byte 1: length of content in block (range 256 - 3)
* - byte 2: next block, 0 for no more blocks
* - directories
* - list of inode indexes, one byte each
* - end of list can be determined by block length
* - files
* - arbitrary contents of file
*
* ## Processes
* - process table structure
* - bytes 0-3: process ID
* - bytes 4-7: pc
* - bytes 8-11: stack offset
* - byte 12: state
* - 0: dead/unused
* - 1: running
* - 2: sleeping
* - 3: waiting IO write (currently UNUSED/uneeded)
* - 4: waiting IO read
* - 5: waiting for child
* - bytes 16-19: parent process id
* - each process has
* - saved registers for context switching (total 128 processes * 32 registers * 4 bytes)
* - dedicated stack area (total 128 processes * 4096 byte stack)
* - additional data
* - 1 byte: executing process ID
* - 1 byte: foreground process ID (which proccess has the terminal, receives stdin)
* - 128 process table entries * 4 bytes: sleep time remaining for processes
* - 128 process table entries * 4 bytes: waiting for child
* - 32 registers * 4 bytes: temporary register save
* - technically, `r0`, and `et` do not need to be saved, but there is space for them for consistency
* - 128 process table entries * 1 byte: data to be written to output
*
* ## Dynamic memory
* - heap block with 4 byte header + `n` bytes data
* - bytes 0-3: size of block (0 if free)
* - bytes 4-`n + 3`: block data (0 if free)
* - on free, 0 bytes
*
* ## Error codes
* - Create a `<func_name>_badness` label that sets the error code in `r4` and `br os_badness`
* 1: no running processes
* 2: pop/shift empty
* 3: out of process table entries
* 4: malloc oom
* 5: bad file name
* 6: out of nodes
* 7: out of blocks
* 8: copy directory
* 9: vechs set/get < 0
* 10: vechs set/get >= size
* 11: foreground delegate to invalid child process
* 12: wait to invalid child process
*/
/*
For a template of saving/restoring registers r8-r23, ra, see os_fork
*/
.global seog_ti_os
.global interrupt_have_byte_for_read
.global ps2_is_shift_down
.global os_fork
.global os_mort
.global os_foreground_delegate
.global os_sleep
.global os_pause
.global os_wait
.global os_supermandive
.global os_getup
.global os_putchar_sync
.global os_printstr_sync
.global os_readchar
.global os_cp
.global os_rm
.global os_cat
.global os_touch
.global os_mkdir
.global os_fwrite
.global os_fappend
.global os_romania_node_from_name
.global os_romania_name_from_node
.global os_romania_parent
.global os_romania_is_dir
.global os_vechs_new
.global os_vechs_delete
.global os_vechs_size
.global os_vechs_get
.global os_vechs_set
.global os_vechs_push
.global os_vechs_pop
.global os_vechs_shift
.global os_vechs_unshift
.global os_vechs_index
.global os_vechs_slice
.global os_vechs_extend
.global os_vechs_dup
.global os_vechs_clear
.global os_malloc
.global os_free
.global os_memset
.global os_memcpy
.global os_strlen
.global os_strcpy
.global os_strcmp
.equ HEAP_BYTES, 65536
.equ ROMANIA_NODES_BYTES, 4096
.equ ROMANIA_BLOCKS_BYTES, 252144
.equ ROMANIA_NODES_MAX, 256
.equ ROMANIA_BLOCKS_MAX, 1024
.equ PROCESS_TABLE_MAX, 128
.equ PROCESS_TABLE_ENTRY_BYTES, 20
.equ PROCESS_TABLE_BYTES, 2560
.equ PROCESS_TABLE_ID, 0
.equ PROCESS_TABLE_PC, 4
.equ PROCESS_TABLE_STACK, 8
.equ PROCESS_TABLE_STATUS, 12
.equ PROCESS_TABLE_PARENT, 16
.equ PROCESS_REGISTERS_BYTES, 16384
.equ PROCESS_STACKS_BYTES, 524288
.equ PROCESS_STACKS_EACH_BYTES, 4096
.equ PROCESS_SLEEPING_BYTES, 512
.equ PROCESS_WAITING_BYTES, 512
.equ PROCESS_IO_OUT_BYTES, 128
.equ PROCESS_REGISTERS_TMP_BYTES, 128
.equ LEDS_RED, 0x10000000
.equ LEDS_GREEN, 0x10000010
.equ JTAG_UART, 0x10001000
.equ JTAG_UART_DATA, 0
.equ JTAG_UART_CTRL, 4
.equ TIMER, 0x10002000
.equ TIMER_STATUS, 0
.equ TIMER_CTRL, 4
.equ TIMER_PERIOD_L, 8
.equ TIMER_PERIOD_H, 12
.equ CYCLES_PER_HUNDRED_MILLISECONDS, 5000000
.equ PS_2, 0x10000100
.equ PS_2_DATA, 0
.equ PS_2_CONTROL, 4
.equ BREAK_IGNORE, 0
/* DATA */
.data
NULL:
.skip 4
HEAP:
.skip HEAP_BYTES
ROMANIA_NODES:
.skip ROMANIA_NODES_BYTES
ROMANIA_BLOCKS:
.skip ROMANIA_BLOCKS_BYTES
PROCESS_TABLE:
.skip PROCESS_TABLE_BYTES
PROCESS_REGISTERS:
.skip PROCESS_REGISTERS_BYTES
PROCESS_STACKS:
.skip PROCESS_STACKS_BYTES
PROCESS_CURRENT:
.skip 4
PROCESS_FOREGROUND:
.skip 4
/*
* 0: Shell process
* 1: Bombadil process
* 2: badness!!!
*/
PROCESS_NUM:
.word 2
PROCESS_SLEEPING:
.skip PROCESS_SLEEPING_BYTES
PROCESS_WAITING:
.skip PROCESS_WAITING_BYTES
PROCESS_IO_OUT:
.skip PROCESS_IO_OUT_BYTES
/*
* In the wise words of N0valey of the Oval, Ender of Ellipses:
* "Yolo is the only strategy"
*/
PROCESS_IO_YOLOQ:
.skip 4
PROCESS_REGISTERS_TMP:
.skip PROCESS_REGISTERS_TMP_BYTES
PS2_LAST_WAS_BREAK:
.word 0
PS2_LAST_MAKE:
.word 0
PS2_SHIFT:
.word 0
STDIN:
.skip 4
EPSILON:
.string ""
FOO:
.string "foo\n"
BUKKITS_OF_FUN:
.string "fun\n"
AYY_LMAO:
.string "a\n"
HMMM:
.string "hmmm\n"
STR_NL:
.string "\n"
# 16 levels
OS_STACK:
.skip 64
/* INTERRUPTS */
.section .exceptions, "ax"
ISR:
# fix pc
addi ea, ea, -4
# save registers
movia et, PROCESS_REGISTERS_TMP
stw r1, 4(et)
stw r2, 8(et)
stw r3, 12(et)
stw r4, 16(et)
stw r5, 20(et)
stw r6, 24(et)
stw r7, 28(et)
stw r8, 32(et)
stw r9, 36(et)
stw r10, 40(et)
stw r11, 44(et)
stw r12, 48(et)
stw r13, 52(et)
stw r14, 56(et)
stw r15, 60(et)
stw r16, 64(et)
stw r17, 68(et)
stw r18, 72(et)
stw r19, 76(et)
stw r20, 80(et)
stw r21, 84(et)
stw r22, 88(et)
stw r23, 92(et)
# NOTE: don't overwrite et
#stw r24, 96(et)
stw r25, 100(et)
stw r26, 104(et)
stw r27, 108(et)
stw r28, 112(et)
stw r29, 116(et)
stw r30, 120(et)
stw r31, 124(et)
# check for PS2
rdctl et, ctl4
andi et, et, 0x80 # bit 7
bne et, r0, ISR_HANDLE_PS2
# check for timer
rdctl et, ctl4
andi et, et, 1
bne et, r0, ISR_HANDLE_TIMER
# check for jtag uart
rdctl et, ctl4
andi et, et, 0x100 # bit 8
bne et, r0, ISR_HANDLE_JTAG_UART
# unknown interrupt
br ISR_EPILOGUE
ISR_HANDLE_TIMER:
call interrupt_handle_timer
# clear status bit
movia et, TIMER
stwio r0, TIMER_STATUS(et)
br ISR_EPILOGUE
ISR_HANDLE_JTAG_UART:
call interrupt_handle_jtag_uart
br ISR_EPILOGUE
ISR_HANDLE_PS2:
call interrupt_handle_ps2
br ISR_EPILOGUE
ISR_EPILOGUE:
movia et, PROCESS_REGISTERS_TMP
ldw r1, 4(et)
ldw r2, 8(et)
ldw r3, 12(et)
ldw r4, 16(et)
ldw r5, 20(et)
ldw r6, 24(et)
ldw r7, 28(et)
ldw r8, 32(et)
ldw r9, 36(et)
ldw r10, 40(et)
ldw r11, 44(et)
ldw r12, 48(et)
ldw r13, 52(et)
ldw r14, 56(et)
ldw r15, 60(et)
ldw r16, 64(et)
ldw r17, 68(et)
ldw r18, 72(et)
ldw r19, 76(et)
ldw r20, 80(et)
ldw r21, 84(et)
ldw r22, 88(et)
ldw r23, 92(et)
# NOTE: don't overwrite et
#ldw r24, 96(et)
ldw r25, 100(et)
ldw r26, 104(et)
ldw r27, 108(et)
ldw r28, 112(et)
# don't overwrite `ea`
#ldw r29, 116(et)
ldw r30, 120(et)
ldw r31, 124(et)
eret
/* TEXT */
.text
/*
*/
interrupt_handle_timer:
addi sp, sp, -4
stw ra, 0(sp)
# tock... did I do good?
call os_tick
# aww yis
call os_schedule
ldw ra, 0(sp)
addi sp, sp, 4
ret
/*
* r4: modified
* r8: jtag uart
* r9: read byte
* r10: used to check which interrupt pending
* r11: foreground process id
* r12: foreground process entry
* r13: foreground process registers
*/
interrupt_handle_jtag_uart:
addi sp, sp, -4
stw ra, 0(sp)
movia r8, JTAG_UART
ldwio r9, JTAG_UART_CTRL(r8)
andi r10, r9, 0x100 # bit 8, read interrupt pending
bne r10, r0, interrupt_handle_jtag_uart_read
br interrupt_handle_jtag_uart_write
interrupt_handle_jtag_uart_read:
# get data
ldbio r4, JTAG_UART_DATA(r8)
# send data
call interrupt_have_byte_for_read
br interrupt_handle_jtag_uart_epilogue
interrupt_handle_jtag_uart_write:
# dequeue io yoloq
# write the byte
# update status byte
# disable write interrupts if queue empty
br interrupt_handle_jtag_uart_epilogue
interrupt_handle_jtag_uart_epilogue:
ldw ra, 0(sp)
addi sp, sp, 4
ret
interrupt_handle_ps2:
addi sp, sp, -4
stw ra, 0(sp)
movia r23, PS_2
movia r22, PS2_LAST_WAS_BREAK
movia r21, PS2_LAST_MAKE
movia r20, PS2_SHIFT
movia r19, 0xf0
movia r18, 0x12
ldw r8, 0(r22)
ldw r9, 0(r21)
movi r10, 1
# read
ldbio r4, PS_2_DATA(r23)
andi r4, r4, 0x00ff # mask
# break code
beq r4, r19, interrupt_handle_ps2_break
# last was break, this is the scan code
bne r8, r0, interrupt_handle_ps2_break_code
# if same make code, ignore
beq r4, r9, interrupt_handle_ps2_epilogue
# shift down
movi r18, 0x12
beq r4, r18, interrupt_handle_ps2_shift
movi r18, 0x59
beq r4, r18, interrupt_handle_ps2_shift
# last_make = data
stw r4, 0(r21)
# decode
call ps2_decode
mov r4, r2
# handle shift
call ps2_shift
# send data
mov r4, r2
call interrupt_have_byte_for_read
br interrupt_handle_ps2_epilogue
interrupt_handle_ps2_break:
# last_was_break = true
stw r10, 0(r22)
movi r3, 0x1F
stw r3, 0(r21)
br interrupt_handle_ps2_epilogue
interrupt_handle_ps2_break_code:
# last_was_break = false
stw r0, 0(r22)
movi r3, 0x1F
stw r3, 0(r21)
# if broke shift
movi r18, 0x12
beq r4, r18, interrupt_handle_ps2_break_shift
movi r18, 0x59
beq r4, r18, interrupt_handle_ps2_break_shift
br interrupt_handle_ps2_epilogue
interrupt_handle_ps2_break_shift:
# shift = false
stw r0, 0(r20)
br interrupt_handle_ps2_epilogue
interrupt_handle_ps2_shift:
# shift = true
stw r10, 0(r20)
br interrupt_handle_ps2_epilogue
interrupt_handle_ps2_same_make:
movi r3, 0x1F
stw r3, 0(r21)
br interrupt_handle_ps2_epilogue
interrupt_handle_ps2_epilogue:
ldw ra, 0(sp)
addi sp, sp, 4
ret
/*
* r4: modified
* r5: modified
* r9: temporary
* r11: foreground process id
* r12: process table entry
* r13: process table registers
* r14: current foreground status
* r15: 4
* r16: process table index
* @param char
*/
interrupt_have_byte_for_read:
addi sp, sp, -40
stw r4, 0(sp)
stw r5, 4(sp)
stw r9, 8(sp)
stw r11, 12(sp)
stw r12, 16(sp)
stw r13, 20(sp)
stw r14, 24(sp)
stw r15, 28(sp)
stw r16, 32(sp)
stw ra, 36(sp)
movia r23, PROCESS_FOREGROUND
movia r22, PROCESS_REGISTERS
movia r21, STDIN
# get foreground process id
ldw r11, 0(r23)
mov r4, r11
# get process table index
call os_process_table_index
mov r16, r2
# get process table entry
mov r4, r16
call os_process_table_entry_from_index
mov r12, r2
# get process table registers
call os_process_table_registers
mov r13, r2
# get current status
ldb r14, PROCESS_TABLE_STATUS(r12)
movi r15, 4
# if foreground waiting for io
beq r14, r15, interrupt_have_byte_for_read_immediate
# then foreground not waiting for io
ldw r4, 0(r21)
# append to stdin buffer
ldw r5, 0(sp)
call os_vechs_push
# done
br interrupt_have_byte_for_read_epilogue
interrupt_have_byte_for_read_immediate:
# update status running
movi r14, 1
stb r14, PROCESS_TABLE_STATUS(r12)
# save data in return register of process
ldw r9, 0(sp)
stw r9, 8(r13)
# done
br interrupt_have_byte_for_read_epilogue
interrupt_have_byte_for_read_epilogue:
ldw r4, 0(sp)
ldw r5, 4(sp)
ldw r9, 8(sp)
ldw r11, 12(sp)
ldw r12, 16(sp)
ldw r13, 20(sp)
ldw r14, 24(sp)
ldw r15, 28(sp)
ldw r16, 32(sp)
ldw ra, 36(sp)
addi sp, sp, 40
ret
/* main */
seog_ti_os:
wrctl ctl0, r0
movia sp, 0x007FFFFC
# clear screen
call tty_clear
# reset heap
movia r4, HEAP
mov r5, r0
movia r6, HEAP_BYTES
call os_memset
# establish country
# the noble empire that is romania (set up root node)
movia r8, ROMANIA_NODES
# upper four bits of block id (0), directory bit (0), in use (1)
movi r9, 1
stb r9, 0(r8)
# lower 8 bits of block id (0)
stb r0, 1(r8)
# parent node id
stb r0, 2(r8)
# name (epsilon)
stb r0, 3(r8)
# set up root block
movia r8, ROMANIA_BLOCKS
# in use
stb r9, 0(r8)
# length
stb r0, 1(r8)
# next block id
sth r0, 2(r8)
# initialize process io queue
movi r4, 16
call os_vechs_new
movia r23, PROCESS_IO_YOLOQ
stw r2, 0(r23)
# initialize stdin buffer
movi r4, 16
call os_vechs_new
movia r23, STDIN
stw r2, 0(r23)
# initialize process table
movia r8, PROCESS_TABLE
movia r10, PROCESS_STACKS
movia r23, PROCESS_STACKS_EACH_BYTES
movia r22, PROCESS_REGISTERS
# stack starts at top address
add r10, r10, r23
# shell process
# process id
stw r0, 0(r8)
# pc
movia r9, os_bdel
stw r9, PROCESS_TABLE_PC(r8)
# stack offset
stw r10, PROCESS_TABLE_STACK(r8)
# status byte
movi r9, 1
stw r9, PROCESS_TABLE_STATUS(r8)
# parent id
stw r0, PROCESS_TABLE_PARENT(r8)
# bombadil process
addi r8, r8, 20
add r11, r10, r23
# process id
movi r9, 1
stw r9, 0(r8)
# pc
movia r9, os_bombadil
stw r9, PROCESS_TABLE_PC(r8)
# stack offset
stw r11, PROCESS_TABLE_STACK(r8)
# status byte
movi r9, 1
stw r9, PROCESS_TABLE_STATUS(r8)
# parent id
stw r0, PROCESS_TABLE_PARENT(r8)
# set sp register
# it is the second entry in the process table
addi r12, r22, 128
stw r11, 108(r12)
# set shell to be running process
movia r23, PROCESS_CURRENT
stw r0, 0(r23)
# set shell as foreground process
movia r23, PROCESS_FOREGROUND
stw r0, 0(r23)
# set stack pointer
mov sp, r10
# enable timer interrupts
movia r8, TIMER
# clear timer
stwio r0, TIMER_STATUS(r8)
movi r9, %hi(CYCLES_PER_HUNDRED_MILLISECONDS)
stwio r9, TIMER_PERIOD_H(r8)
movi r9, %lo(CYCLES_PER_HUNDRED_MILLISECONDS)
stwio r9, TIMER_PERIOD_L(r8)
movi r9, 0x07 # bits 2, 1, 0 (start, continue, enable interrupt)
stwio r9, TIMER_CTRL(r8)
# enable jtag uart interrupts
movia r8, JTAG_UART
movi r9, 0x1 # disable write interrupt, enable read interrupt bits
stwio r9, JTAG_UART_CTRL(r8)
# enable PS2 interrupts
movia r8, PS_2
movi r9, 0x01 # enable read interrupt
stwio r9, PS_2_CONTROL(r8)
# enable irq interrupts
movi r8, 0x181 # bit 8, 7, 0
wrctl ctl3, r8
# enable global interrupts, start shell
movi et, 1
wrctl ctl1, et
movia ea, os_bdel
eret
/* romania */
/*
* @param node id of parent folder
* @param pointer to string name
*/
os_touch:
# disable interrupts
wrctl ctl0, r0
# save old value of ctl1
rdctl et, ctl1
addi sp, sp, -4
stw et, 0(sp)
# interrupts now "were last" disabled
wrctl ctl1, r0
addi sp, sp, -8
stw r6, 0(sp)
stw ra, 4(sp)
# set file bit
movi r6, 1
call os_falloc
ldw r6, 0(sp)
ldw ra, 4(sp)
addi sp, sp, 8
# get last value of ctl1
ldw et, 0(sp)
addi sp, sp, 4
# update ctl1
wrctl ctl1, et
# return and update ctl0
mov ea, ra
eret
/*
* @param node id of parent folder
* @param pointer to string name
*/
os_mkdir:
# disable interrupts
wrctl ctl0, r0
# save old value of ctl1
rdctl et, ctl1
addi sp, sp, -4
stw et, 0(sp)
# interrupts now "were last" disabled
wrctl ctl1, r0
addi sp, sp, -8
stw r6, 0(sp)
stw ra, 4(sp)
# set directory bit
mov r6, r0
call os_falloc
ldw r6, 0(sp)
ldw ra, 4(sp)
addi sp, sp, 8
# get last value of ctl1
ldw et, 0(sp)
addi sp, sp, 4
# update ctl1
wrctl ctl1, et
# return and update ctl0
mov ea, ra
eret
/*
* r8: node id
* r9: node address
* r10: block id
* r11: block address
* r12: temporary register (block id in node structure, others)
* @param node id of parent folder
* @param pointer to string name
* @param 0 for dir, 1 for file
*/
os_falloc:
# disable interrupts
wrctl ctl0, r0
# save old value of ctl1
rdctl et, ctl1
addi sp, sp, -4
stw et, 0(sp)
# interrupts now "were last" disabled
wrctl ctl1, r0
addi sp, sp, -44
stw r4, 0(sp)
stw r5, 4(sp)
stw r6, 8(sp)
stw r8, 12(sp)
stw r9, 16(sp)
stw r10, 20(sp)
stw r11, 24(sp)
stw r12, 28(sp)
stw r22, 32(sp)
stw r23, 36(sp)
stw ra, 40(sp)
# allocate node
call os_romania_allocate_node
mov r8, r2
# get address
mov r4, r2
call os_romania_node_from_id
mov r9, r2
# allocate block
call os_romania_allocate_block
mov r10, r2
# get address
mov r4, r2
call os_romania_block_from_id
mov r11, r2
# create vechs of content to append
movi r4, 1
call os_vechs_new
# add node id
mov r4, r2
mov r5, r8
call os_vechs_push
# append
mov r5, r4
ldw r4, 0(sp)
call os_fappend
# free
mov r4, r5
call os_vechs_delete
# upper 4 bits of block id
srli r12, r10, 8
slli r12, r12, 4
# directory or file bit
slli r6, r6, 1
# directory or file bit, in use bit
ori r6, r6, 1
# set lower bits
or r12, r12, r6
# save directory or file bit, in use bit, upper 4 bits of block id
stb r12, 0(r9)
# save lower 8 bits of block id
stb r10, 1(r9)
# save parent dir
ldw r12, 0(sp)
stb r12, 2(r9)
# check name length
ldw r5, 4(sp)
mov r4, r5
call os_strlen
# 12 is the max name length
movi r12, 12
bgt r2, r12, os_falloc_bad_name
# then valid name
# r5 = node address + name offset
addi r5, r9, 3
call os_strcpy
# set return value
mov r2, r8
br os_falloc_epilogue
os_falloc_bad_name:
movi r4, 5
br os_badness