-
Notifications
You must be signed in to change notification settings - Fork 0
/
zap.asm
4600 lines (3513 loc) · 78.7 KB
/
zap.asm
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
; GOOD COMPUTER: Z-machine interpreter
; Copyright (c) 2020 Rob Norris
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at https://mozilla.org/MPL/2.0/.
.include "m88def.inc"
; global variable space 240 vars * 2 bytes, 0x0100-0x02e0
; stores in z-machine order (H:L)
.equ z_global_vars = 0x0100
; story file header (first 0x20 bytes)
.equ z_header = 0x02e0
; temp space for separator list during input parsing
.equ separator_buffer = 0x0300
.equ separator_buffer_end = 0x0308
; temp space for expanding current dictionary word during input parsing
.equ word_buffer = 0x0308
.equ word_buffer_end = 0x0320
; debug tracking
.equ z_last_pc_l = 0x320 ; start of last instruction
.equ z_last_pc_h = 0x321 ; /
.equ z_last_opcode = 0x322 ; last opcode
.equ z_last_argtype = 0x323 ; last argtype
; storage for original zstring processing state while processing an abbreviation string
.equ zstring_state_adv_l = 0x0323
.equ zstring_state_adv_h = 0x0324
.equ zstring_state_ram_pos_l = 0x0325
.equ zstring_state_ram_pos_m = 0x0326
.equ zstring_state_ram_pos_h = 0x0327
.equ zstring_state_word_pos = 0x0328
.equ zstring_state_word_l = 0x0329
.equ zstring_state_word_h = 0x032a
.equ zstring_state_lock_alphabet = 0x032b
.equ zstring_state_flags = 0x032c
; z stack. word values are stored in local order (L:H), so H must be pushed first
; SP <-----------
; ... LH LH LH
.equ z_stack_top = 0x047e
.equ rand_l = 0x047e
.equ rand_h = 0x047f
; input buffer
; enough room for 0x44 requested by zork
.equ input_buffer = 0x0480
.equ input_buffer_end = 0x04d0
; zmachine program counter
.def z_pc_l = r24
.def z_pc_h = r25
; pointer to past arg0 on stack for current op
.def z_argp_l = r22
.def z_argp_h = r23
; current op and argtype
.def z_opcode = r20
.def z_argtype = r21
; ram start position, updated by ram_ subs to shadow the internal sram address counter
.def ram_pos_l = r12
.def ram_pos_m = r13
.def ram_pos_h = r14
.cseg
.org 0x0000
rjmp reset
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reset:
; clear reset state and disable watchdog
cli
wdr
in r16, MCUSR
cbr r16, (1<<WDRF)
out MCUSR, r16
lds r16, WDTCSR
lds r16, WDTCSR
sbr r16, (1<<WDCE) | (1<<WDE)
sts WDTCSR, r16
cbr r16, (1<<WDE)
sts WDTCSR, r16
sei
; setup stack pointer
ldi r16, low(RAMEND)
ldi r17, high(RAMEND)
out SPL, r16
out SPH, r17
; usart tx/rx enable
ldi r16, (1<<RXEN0) | (1<<TXEN0)
sts UCSR0B, r16
; usart frame format: 8N1 (8 data bits => UCSZ2:0 = 011, no parity => UPM1:0 = 00, 1 stop bit => USBS = 0)
ldi r16, (1<<UCSZ00) | (1<<UCSZ01)
sts UCSR0C, r16
; usart 38400 baud at 16MHz => UBRR = 25
ldi r16, 25
ldi r17, 0
sts UBRR0L, r16
sts UBRR0H, r17
; output: PB0 = error LED, PB1 = user LED
; PB2 = SPI /SS (SRAM /CS), PB3 = SPI MOSI, PB5 = SPI SCK
; input: PB4 = SPI MISO
; don't care: PB7
ldi r16, (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB5)
out DDRB, r16
; drive SPI /SS high to disable it
ldi r16, (1<<PB2)
out PORTB, r16
; enable SPI, master mode, clock rate fck/4 (4MHz)
ldi r16, (1<<SPE) | (1<<MSTR)
out SPCR, r16
; SPI clock double (8MHz)
ldi r16, (1<<SPI2X)
out SPSR, r16
boot:
; boot prompt
ldi ZL, low(text_boot_prompt*2)
ldi ZH, high(text_boot_prompt*2)
rcall usart_print_static
; wait for key
boot_key:
rcall usart_rx_byte
mov r17, r16
cpi r17, 0xd
breq boot
cpi r17, 'r' ; run
breq main
cpi r17, 'l' ; load
brne boot_key
rcall xmodem_load_ram
rjmp wd_reset
main:
; distance from boot prompt
rcall usart_newline
rcall usart_newline
; reset rng
clr r16
sts rand_h, r16
inc r16
sts rand_l, r16
; zero stack
ldi XL, low(z_stack_top)
ldi XH, high(z_stack_top)
; zero argp as well, sorta meaningless in main but its where we expect it
movw z_argp_l, XL
; load header
clr ram_pos_l
clr ram_pos_m
clr ram_pos_h
rcall ram_read_start
ldi YL, low(z_header)
ldi YH, high(z_header)
ldi r16, 0x20
rcall ram_read_bytes
rcall ram_end
;ldi ZL, low(z_header)
;ldi ZH, high(z_header)
;ldi r16, 0x10
;clr r17
;rcall usart_tx_bytes_hex
; XXX fill header?
; version check
lds r16, z_header
tst r16
breq PC+3
cpi r16, 4 ; no support for v4+
brlo PC+10
ldi ZL, low(text_unsupported_version*2)
ldi ZH, high(text_unsupported_version*2)
rcall usart_print_static
lds r16, z_header
ori r16, 0x30
rcall usart_tx_byte
rcall usart_newline
rjmp wd_reset
; load globals
lds ram_pos_l, z_header+0xd
lds ram_pos_m, z_header+0xc
clr ram_pos_h
rcall ram_read_start
ldi YL, low(z_global_vars)
ldi YH, high(z_global_vars)
clr r16
rcall ram_read_bytes
ldi r16, 0xe0
rcall ram_read_bytes
rcall ram_end
; initialise PC
lds z_pc_l, z_header+0x7
lds z_pc_h, z_header+0x6
; clear string processing state
clr r16
sts zstring_state_flags, r16
; set up to stream from PC
movw ram_pos_l, z_pc_l
clr ram_pos_h
rcall ram_read_start
decode_op:
;movw ZL, XL
;ldi r16, 0x20
;clr r17
;rcall usart_tx_bytes_hex
;ldi ZL, low(z_global_vars)
;ldi ZH, high(z_global_vars)
;ldi r16, 0x40
;ldi r17, 0x2
;rcall usart_tx_bytes_hex
;mov r16, z_pc_h
;rcall usart_tx_byte_hex
;mov r16, z_pc_l
;rcall usart_tx_byte_hex
;ldi r16, ' '
;rcall usart_tx_byte
; note start of instruction for reporting
sts z_last_pc_l, z_pc_l
sts z_last_pc_h, z_pc_h
; get opcode
rcall ram_read_byte
adiw z_pc_l, 1
; record opcode for reporting
sts z_last_opcode, r16
;push r16
;rcall usart_tx_byte_hex
;rcall usart_newline
;pop r16
; instruction decode
; 0 t t xxxxx: long op (2op, 1-bit type)
; 10 tt xxxx: short op (1op/0op, 2-bit type)
; 11 0 xxxxx: variable op (2op, type byte)
; 11 1 xxxxx: variable op (Vop, type byte)
; working towards:
; z_opcode: opcode
; z_argtype: type byte (4x2bits)
; on codepath for lookup for proper instruction type
; 0xxxxxxx: "long" op
tst r16
brpl decode_op_long
; 10xxxxxx: "short" op
sbrs r16, 6
rjmp decode_op_short
; 11axxxxx: "variable" op
; bottom five bits are opcode
mov z_opcode, r16
andi z_opcode, 0x1f
; take optype bit
bst r16, 5
; type byte follows
rcall ram_read_byte
adiw z_pc_l, 1
mov z_argtype, r16
; bit 5 clear=2op, set=vop
brts PC+4
; ready 2op lookup
ldi ZL, low(op_2_table)
ldi ZH, high(op_2_table)
rjmp PC+3
; ready vop lookup
ldi ZL, low(op_v_table)
ldi ZH, high(op_v_table)
; vop, take up to four
; XXX loop and write to ramregs?
mov r17, z_argtype
mov r16, r17
andi r16, 0xc0
cpi r16, 0xc0
breq decode_op_variable_done
rcall decode_arg
movw r2, r0
mov r16, r17
andi r16, 0xc0
cpi r16, 0xc0
breq decode_op_variable_done
rcall decode_arg
movw r4, r0
mov r16, r17
andi r16, 0xc0
cpi r16, 0xc0
breq decode_op_variable_done
rcall decode_arg
movw r6, r0
mov r16, r17
andi r16, 0xc0
cpi r16, 0xc0
breq decode_op_variable_done
rcall decode_arg
movw r8, r0
decode_op_variable_done:
rjmp run_op
decode_op_long:
; bottom five bits are opcode
mov z_opcode, r16
andi z_opcode, 0x1f
; this is a 2op, so %11 for bottom two args
ldi z_argtype, 0xf
; type bit for first arg
bst r16, 6
brts PC+3
; %0 -> %01 (byte constant)
sbr z_argtype, 0x40
rjmp PC+2
; %1 -> %10 (variable number)
sbr z_argtype, 0x80
; type bit for second arg
bst r16, 5
brts PC+3
; %0 -> %01 (byte constant)
sbr z_argtype, 0x10
rjmp PC+2
; %1 -> %10 (variable number)
sbr z_argtype, 0x20
; ready 2op lookup
ldi ZL, low(op_2_table)
ldi ZH, high(op_2_table)
; 2op, take two
mov r17, z_argtype
rcall decode_arg
movw r2, r0
rcall decode_arg
movw r4, r0
rjmp run_op
decode_op_short:
; bottom four bits are opcode
mov z_opcode, r16
andi z_opcode, 0xf
; 1op (or 0op), type in bits 4 & 5, shift up to 6 & 7
lsl r16
lsl r16
; no-arg the remainder
sbr r16, 0x3f
mov z_argtype, r16
; test first arg, none=0op, something=1op
andi r16, 0xc0
cpi r16, 0xc0
brne PC+4
; ready 0op lookup
ldi ZL, low(op_0_table)
ldi ZH, high(op_0_table)
rjmp run_op
; ready 1op lookup
ldi ZL, low(op_1_table)
ldi ZH, high(op_1_table)
; 1op, take one
mov r17, z_argtype
rcall decode_arg
movw r2, r0
rjmp run_op
; take the next arg from PC
; inputs:
; r17: arg type byte, %wwxxyyzz
; top two bytes will be considered
; rotated out, for repeated calls
; outputs:
; r0:r1: decoded arg (low:high)
decode_arg:
; take top two bits
clr r16
lsl r17
rol r16
lsl r17
rol r16
; set bottom two bits, so we always have an end state
sbr r17, 0x3
; %00: word constant
cpi r16, 0x0
breq decode_word_constant
; %01: byte constant
cpi r16, 0x1
breq decode_byte_constant
; %10: variable number
cpi r16, 0x2
breq decode_variable_number
ret
decode_variable_number:
; variable number
rcall ram_read_byte
adiw z_pc_l, 1
push r17
rcall load_variable
pop r17
ret
decode_word_constant:
; word constant, take two bytes
rcall ram_read_byte
mov r1, r16
rcall ram_read_byte
mov r0, r16
adiw z_pc_l, 2
ret
decode_byte_constant:
; byte constant, take one byte
rcall ram_read_byte
mov r0, r16
clr r1
adiw z_pc_l, 1
ret
run_op:
; z_opcode: opcode
; z_argtype: type byte
; Z: op table
; args in r2:r3, r4:r5, r6:r7, r8:r9
; record argtype for reporting
sts z_last_argtype, z_argtype
add ZL, z_opcode
brcc PC+2
inc ZH
ijmp
op_0_table:
rjmp op_rtrue ; rtrue
rjmp op_rfalse ; rfalse
rjmp op_print ; print (literal_string)
rjmp op_print_ret ; print_ret (literal-string)
rjmp decode_op ; nop
rjmp unimpl ; save ?(label) [v4 save -> (result)] [v5 illegal]
rjmp unimpl ; restore ?(label) [v4 restore -> (result)] [v5 illegal]
rjmp unimpl ; restart
rjmp op_ret_popped ; ret_popped
rjmp op_pop ; pop [v5/6 catch -> (result)]
rjmp wd_reset ; quit
rjmp op_new_line ; new_line
rjmp unimpl ; [v3] show_status [v4 illegal]
rjmp unimpl ; [v3] verify ?(label)
rjmp unimpl ; [v5] [extended opcode]
rjmp unimpl ; [v5] piracy ?(label)
op_1_table:
rjmp op_jz ; jz a ?(label)
rjmp op_get_sibling ; get_sibling object -> (result) ?(label)
rjmp op_get_child ; get_child object -> (result) ?(label)
rjmp op_get_parent ; get_parent object -> (result)
rjmp op_get_prop_len ; get_prop_len property-address -> (result)
rjmp op_inc ; inc (variable)
rjmp op_dec ; dec (variable)
rjmp op_print_addr ; print_addr byte-address-of-string
rjmp unimpl ; [v4] call_1s routine -> (result)
rjmp op_remove_obj ; remove_obj object
rjmp op_print_obj ; print_obj object
rjmp op_ret ; ret value
rjmp op_jump ; jump ?(label)
rjmp op_print_paddr ; print_paddr packed-address-of-string
rjmp op_load ; load (variable) -> (result)
rjmp op_not ; not value -> (result) [v5 call_1n routine]
op_2_table:
rjmp unimpl ; [nonexistent]
rjmp op_je ; je a b ?(label)
rjmp op_jl ; jl a b ?(label)
rjmp op_jg ; jg a b ?(label)
rjmp op_dec_chk ; dec_chk (variable) value ?(label)
rjmp op_inc_chk ; inc_chk (variable) value ?(label)
rjmp op_jin ; jin obj1 obj2 ?(label)
rjmp op_test ; test bitmap flags ?(label)
rjmp op_or ; or a b -> (result)
rjmp op_and ; and a b -> (result)
rjmp op_test_attr ; test_attr object attribute ?(label)
rjmp op_set_attr ; set_attr object attribute
rjmp op_clear_attr ; clear_attr object attribute
rjmp op_store ; store (variable) value
rjmp op_insert_obj ; insert_obj object destination
rjmp op_loadw ; loadw array word-index -> (result)
rjmp op_loadb ; loadb array byte-index -> (result)
rjmp op_get_prop ; get_prop object property -> (result)
rjmp op_get_prop_addr ; get_prop_addr object property -> (result)
rjmp op_get_next_prop ; get_next_prop object property -> (result)
rjmp op_add ; add a b -> (result)
rjmp op_sub ; sub a b -> (result)
rjmp op_mul ; mul a b -> (result)
rjmp op_div ; div a b -> (result)
rjmp op_mod ; mod a b -> (result)
rjmp unimpl ; [v4] call_2s routine arg1 -> (result)
rjmp unimpl ; [v5] call_2n routine arg1
rjmp unimpl ; [v5] set_colour foreground background [v6 set_colour foreground background window]
rjmp unimpl ; [v5] throw value stack-frame
rjmp unimpl ; [nonexistent]
rjmp unimpl ; [nonexistent]
rjmp unimpl ; [nonexistent]
op_v_table:
rjmp op_call ; call routine (0..3) -> (result) [v4 call_vs routine (0..3) -> (result)
rjmp op_storew ; storew array word-index value
rjmp op_storeb ; storeb array byte-index value
rjmp op_put_prop ; put_prop object property value
rjmp op_sread ; sread text parse [v4 sread text parse time routing] [v5 aread text parse time routine -> (result)]
rjmp op_print_char ; print_char output-character-code
rjmp op_print_num ; print_num value
rjmp op_random ; random range -> (result)
rjmp op_push ; push value
rjmp op_pull ; pull (variable) [v6 pull stack -> (result)]
rjmp unimpl ; [v3] split_window lines
rjmp unimpl ; [v3] set_window lines
rjmp unimpl ; [v4] call_vs2 routine (0..7) -> (result)
rjmp unimpl ; [v4] erase_window window
rjmp unimpl ; [v4] erase_line value [v6 erase_line pixels]
rjmp unimpl ; [v4] set_cursor line column [v6 set_cursor line column window]
rjmp unimpl ; [v4] get_cursor array
rjmp unimpl ; [v4] set_text_style style
rjmp unimpl ; [v4] buffer_mode flag
rjmp unimpl ; [v3] output_stream number [v5 output_stream number table] [v6 output_stream number table width]
rjmp unimpl ; [v3] input_stream number
rjmp unimpl ; [v5] sound_effect number effect volume routine
rjmp unimpl ; [v4] read_char 1 time routine -> (result)
rjmp unimpl ; [v4] scan_table x table len form -> (result)
rjmp unimpl ; [v5] not value -> (result)
rjmp unimpl ; [v5] call_vn routine (0..3)
rjmp unimpl ; [v5] call_vn2 routine (0..7)
rjmp unimpl ; [v5] tokenise text parse dictionary flag
rjmp unimpl ; [v5] encode_text zscii-text length from coded-text
rjmp unimpl ; [v5] copy_table first second size
rjmp unimpl ; [v5] print_table zscii-text width height skip
rjmp unimpl ; [v5] check_arg_count argument-number
; READING AND WRITING MEMORY
; load (variable) -> (result)
op_load:
; load value
mov r16, r2
rcall load_variable
; copy result to arg0 and store it
movw r2, r0
rjmp store_op_result
; store (variable) value
op_store:
; get variable name
mov r16, r2
; store value there
movw r0, r4
rcall store_variable
rjmp decode_op
; loadw array word-index -> (result)
op_loadw:
; index is a word offset
lsl r4
rol r5
; compute array index address
add r2, r4
adc r3, r5
; close ram
rcall ram_end
; open ram at array cell
movw ram_pos_l, r2
clr ram_pos_h
rcall ram_read_start
; get value
rcall ram_read_pair
mov r3, r16
mov r2, r17
; close ram again
rcall ram_end
; reopen ram at PC
movw ram_pos_l, z_pc_l
clr ram_pos_h
rcall ram_read_start
; done, store value
rjmp store_op_result
; storew array word-index value
op_storew:
; index is a word offset
lsl r4
rol r5
; compute array index address
add r2, r4
adc r3, r5
; close ram
rcall ram_end
; open ram for write at array cell
movw ram_pos_l, r2
clr ram_pos_h
rcall ram_write_start
; write value
mov r16, r7
mov r17, r6
rcall ram_write_pair
; close ram again
rcall ram_end
; reopen ram at PC
movw ram_pos_l, z_pc_l
clr ram_pos_h
rcall ram_read_start
; done!
rjmp decode_op
; loadb array byte-index -> (result)
op_loadb:
; XXX life & share with loadw
; compute array index address
add r2, r4
adc r3, r5
; close ram
rcall ram_end
; open ram at array cell
movw ram_pos_l, r2
clr ram_pos_h
rcall ram_read_start
; get value
rcall ram_read_byte
mov r2, r16
clr r3
; close ram again
rcall ram_end
; reopen ram at PC
movw ram_pos_l, z_pc_l
clr ram_pos_h
rcall ram_read_start
; done, store value
rjmp store_op_result
; storeb array byte-index value
op_storeb:
; compute array index address
add r2, r4
adc r3, r5
; close ram
rcall ram_end
; open ram for write at array cell
movw ram_pos_l, r2
clr ram_pos_h
rcall ram_write_start
; write value
mov r16, r6
rcall ram_write_byte
; close ram again
rcall ram_end
; reopen ram at PC
movw ram_pos_l, z_pc_l
clr ram_pos_h
rcall ram_read_start
; done!
rjmp decode_op
; push value
op_push:
; setup for var 0 (stack push)
clr r16
; store value there
movw r0, r2
rcall store_variable
rjmp decode_op
; pull (variable) [v6 pull stack -> (result)]
op_pull:
; load var 0 (stack pull)
clr r16
rcall load_variable
; store to the named var
mov r16, r2
rcall store_variable
rjmp decode_op
; pop [v5/6 catch -> (result)]
op_pop:
; take top item on stack and drop it
adiw XL, 2
rjmp decode_op
; ARITHMETIC
; add a b -> (result)
op_add:
; add the args
add r2, r4
adc r3, r5
rjmp store_op_result
; sub a b -> (result)
op_sub:
; math up my dudes
sub r2, r4
sbc r3, r5
rjmp store_op_result
; mul a b -> (result)
op_mul:
; just the bottom part of a 16x16 multiply chain, because we don't care about
; the top 16 result bits
mul r2, r4
movw r6, r0
mul r3, r4
add r7, r0
mul r2, r5
add r7, r0
movw r2, r6
rjmp store_op_result
; div a b -> (result)
op_div:
; check divide-by-zero
tst r4
brne PC+4
tst r5
brne PC+2
; I mean, what else can you do?
rjmp fatal
movw r16, r2
movw r18, r4
rcall divide
; move result to arg0 for store
movw r2, r16
rjmp store_op_result
; mod a b -> (result)
op_mod:
; check divide-by-zero
tst r4
brne PC+4
tst r5
brne PC+2
; I mean, what else can you do?
rjmp fatal
movw r16, r2
movw r18, r4
rcall divide
; remainder already in r2:r3
rjmp store_op_result
; inc (variable)
op_inc:
rcall inc_variable
rjmp decode_op
; dec (variable)
op_dec:
rcall dec_variable
rjmp decode_op
; inc_chk (variable) value ?(label)
op_inc_chk:
rcall inc_variable
; compare backwards, for less-than test
clt
cp r4, r0
cpc r5, r1
brpl PC+2
set
; complete branch
rjmp branch_generic
; dec_chk (variable) value ?(label)
op_dec_chk:
rcall dec_variable
; compare
set
cp r0, r4
cpc r1, r5
brmi PC+2
clt
; complete branch
rjmp branch_generic
; and a b -> (result)
op_and:
and r2, r4
and r3, r5
rjmp store_op_result
; or a b -> (result)
op_or:
or r2, r4
or r3, r5
rjmp store_op_result
; not value -> (result) [v5 call_1n routine]
op_not:
; flip those bits
com r2
com r3
rjmp store_op_result
; COMPARISONS AND JUMPS
; jz a ?(label)
op_jz:
clt
tst r2
brne PC+4
tst r3
brne PC+2
set
rjmp branch_generic
; je a b ?(label)
op_je:
; assume no match
clt
; second arg
cp r2, r4
cpc r3, r5