Changed BRZ behavior to chomp a test word from stack instead of checking PSW_Z bit.
[ned1] / software / 4func_calculator / calc.asm
CommitLineData
bc5b63cf
AT
1# (c) 2018 Aaron Taylor <ataylor at subgeniuskitty dot com>
2# See LICENSE.txt file for copyright and license details.
3
4# Simple 4-function calculator in NED assembly.
5# 20181128 - Aaron Taylor
6
7calc
8 JSR>calcinit
9
10 calcloop
11 # Refresh the display.
12 JSR>printtopstackentry
13
14 # Get a character/command.
15 JSR>getchar
16
17 # Check for 'zero stack entry' command.
18 LDSP+0
19 JSR>evalzerostackentry
20
21 # Check for 'negate stack entry' command.
22 LDSP+0
23 JSR>evalnegatestackentry
24
25 # Check for stack navigation commands.
26 LDSP+0
27 JSR>evalstacknavigation
28
29 # Check for ASCII digit (append to stack entry) command.
30 LDSP+0
31 JSR>evalasciidigit
32
33 # Check for ASCII 'addition' command.
34 LDSP+0
35 JSR>evalmathaddition
36
37 # Check for ASCII 'subtraction' command.
38 LDSP+0
39 JSR>evalmathsubtraction
40
41 # Check for ASCII 'multiplication' command.
42 LDSP+0
43 JSR>evalmathmultiplication
44
45 # Check for ASCII 'division' command.
46 LDSP+0
47 JSR>evalmathdivision
48
49 # Dump existing character and get the next character.
50 TEST
51 JMP>calcloop
52
53# Should be unreachable.
54HALT
55
56##########################################################################################
57calcinit
58##########################################################################################
59# Description:
60# Initializes stack for calc subroutine.
61# Zeros the Data Stack in RAM.
62# Call Stack:
63# Return PC <-- TOS
64# Return Stack:
65# Data Stack Base Address (=0x40000000)
66# Data Stack Offset (=0) <-- TOS
67##########################################################################################
68 # Setup program stack.
69 WORD_1073741824
70 SWAP
71 IM_0
72 SWAP
73
74 # Prepare to generate Data Stack pointers.
75 LDSP+2 # Data Stack Base Address
76 LDSP+2 # Data Stack Offset
77
78 # Zero the Data Stack.
79 calcinitzeroloop
80
81 # Increment Data Stack Offset, store 0 at location.
82 JSR>incrementstackindex
83 IM_0
84 LDSP+2
85 LDSP+2
86 ADD
87 STORE
88
89 # Check for loop termination
90 LDSP+0
bc5b63cf
AT
91 BRZ>calcinitzeroloopend
92 JMP>calcinitzeroloop
93
94 calcinitzeroloopend
95
96 # Clean up stack and return.
97 TEST
98 TEST
99 RTS
100
101##########################################################################################
102incrementstackindex
103##########################################################################################
104# Description:
105# Increment the Data Stack Offset, wrapping if approriate.
106# Call Stack:
107# Data Stack Offset
108# Return PC <-- TOS
109# Return Stack:
110# Data Stack Offset
111##########################################################################################
112 # Increment the Data Stack Offset
113 SWAP
114 IM_4 # Four bytes per word
115 ADD
116
117 # See if the new Data Stack Offset should wrap. If so, set it to zero.
118 LDSP+0
119 IM_12 # Total of four stack entries (offsets: 0, 4, 8, 12).
120 JSR>subtract
121 TEST
122 IM_12 # Address of PSW register.
123 LOAD
124 IM_2 # Negative bit in PSW
125 AND
bc5b63cf
AT
126 BRZ>incrementstackindexreturn
127 # Negative bit was set, so wrap to start of stack.
128 TEST
129 IM_0
130 incrementstackindexreturn
131 SWAP
132 RTS
133
134##########################################################################################
135decrementstackindex
136##########################################################################################
137# Description:
138# Decrement the Data Stack Offset, wrapping if approriate.
139# Call Stack:
140# Data Stack Offset
141# Return PC <-- TOS
142# Return Stack:
143# Data Stack Offset
144##########################################################################################
145 # Decrement the Data Stack Offset
146 SWAP
147 IM_4
148 SWAP
149 JSR>subtract
150
151 # See if new Data Stack Offset should wrap, indicated by value < 0.
152 # If so, set it to 12 (offsets: 0, 4, 8, 12).
153 LDSP+0
154 TEST
155 IM_12 # Address of PSW register.
156 LOAD
157 IM_2 # Negative bit in PSW register.
158 AND
bc5b63cf
AT
159 BRZ>decrementstackindexreturn
160 # Negative bit was set, so wrap to end of stack.
161 TEST
162 IM_12
163 decrementstackindexreturn
164 SWAP
165 RTS
166
167##########################################################################################
168printstackindex
169##########################################################################################
170# Description:
171# Prints the data stack index in user readable form.
172# Call Stack:
173# Data Stack Offset
174# Return PC <-- TOS
175# Return Stack:
176# <empty>
177##########################################################################################
178 # Put Return PC on bottom of stack.
179 SWAP
180
181 # Put post-number portion of the string on the stack (colon, space, NUL).
182 IM_0 # ASCII NUL
183 SWAP
184 WORD_32 # ASCII ' '
185 SWAP
186 WORD_58 # ASCII ':'
187 SWAP
188
189 # Stack now looks like:
190 # Return PC
191 # ASCII NUL
192 # ASCII ' '
193 # ASCII ':'
194 # Data Stack Offset
195
196 # Divide Data Stack Offset by 4 to generate index since there are 4 bytes per word.
197 IM_4
198 JSR>divide
199 TEST # DROP Remainder
200
201 # Convert index to ASCII and print the string.
202 JSR>itoa
203 JSR>printstring
204 RTS
205
206##########################################################################################
207printbinaryinteger
208##########################################################################################
209# Description:
210# Prints a binary integer to ASCII terminal.
211# Call Stack:
212# Integer
213# Return PC <-- TOS
214# Return Stack:
215# <empty>
216##########################################################################################
217 # Put Return PC on bottom of stack.
218 SWAP
219
220 # Put ASCII NUL on stack as end of string.
221 IM_0
222 SWAP
223
224 # Separate Integer into sign and magnitude.
225 LDSP+0
226 IM_4
227 LOAD
228 AND
229 SWAP
230 JSR>absolutevalue
231
232 # Stack now looks like:
233 # Return PC
234 # ASCII NUL
235 # Sign flag (nonzero for negative result, 0 for positive result)
236 # ABS(Integer)
237
238 # First check if the number is zero and print a single zero if true.
239 LDSP+0
bc5b63cf
AT
240 BRZ>printbinaryintegerloopend
241
242 # Repeatedly divide by ten and push each digit onto the stack in ASCII.
243 printbinaryintegerloop
244
245 # Verify Integer still has digits to print (i.e. Integer != 0)
246 LDSP+0
bc5b63cf
AT
247 BRZ>printbinaryintegerloopend
248
249 # Extract the least significant digit.
250 IM_10
251 JSR>divide
252
253 # Convert to ASCII and add to string on stack.
254 JSR>itoa
255 LDSP+2 # Sign flag
256 SWAP
257 STSP+2
258 SWAP
259
260 # Loop
261 JMP>printbinaryintegerloop
262
263 printbinaryintegerloopend
264 TEST # DROP ABS(Integer)
265
266 # Push a leading ASCII zero onto stack.
267 IM_0
268 JSR>itoa
269 SWAP
270
271 # Stack now looks like:
272 # Return PC
273 # ASCII NUL
274 # ASCII digit
275 # ...
276 # ASCII digit
277 # Sign flag (nonzero for negative result, 0 for positive result)
278
279 # Push sign onto stack as ASCII character.
bc5b63cf
AT
280 BRZ>printbinaryintegerpositive
281
282 # Add ASCII '-' sign to stack
283 WORD_44
284 IM_1
285 ADD
286 JMP>printbinaryintegerend
287
288 printbinaryintegerpositive
289
290 # Add ASCII '+' sign to stack
291 WORD_42
292 IM_1
293 ADD
294
295 printbinaryintegerend
296
297 # Print the string and return
298 JSR>printstring
299 RTS
300
301##########################################################################################
302printtopstackentry
303##########################################################################################
304# Description:
305# Prints the current TOS entry.
306# Call Stack:
307# Data Stack Base Address
308# Data Stack Offset
309# Return PC <-- TOS
310# Return Stack:
311# Data Stack Base Address
312# Data Stack Offset <-- TOS
313##########################################################################################
314 # Prepare the screen and cursor.
315 JSR>ansiescapeclearscreen
316 JSR>ansiescapesetcursorcolumnone
317
318 # Print the data stack index
319 LDSP+1
320 JSR>printstackindex
321
322 # Print the TOS entry from the data stack in human readable form.
323 LDSP+2
324 LDSP+2
325 ADD
326 LOAD
327 JSR>printbinaryinteger
328 RTS
329
330##########################################################################################
331evalzerostackentry
332##########################################################################################
333# Description:
334# If character on TOS is ASCII "'", zero the current data stack entry.
335# Call Stack:
336# Data Stack Base Address
337# Data Stack Offset
338# ASCII character
339# ASCII character
340# Return PC <-- TOS
341# Return Stack:
342# Data Stack Base Address
343# Data Stack Offset
344# ASCII character
345##########################################################################################
346 SWAP
347
348 # Test for ASCII "'".
349 WORD_38 # ASCII "'"
350 IM_1
351 ADD
352 JSR>subtract
bc5b63cf
AT
353 BRZ>evalzerostackentrymatch
354
355 # No match, return from subroutine
356 RTS
357
358 evalzerostackentrymatch
359
360 # Matched, zero the stack entry and return.
361
362 # Stack now looks like:
363 # Data Stack Base Address
364 # Data Stack Offset
365 # ASCII character
366 # Return PC <-- TOS
367
368 IM_0
369 LDSP+4 # Data Stack Base Address
370 LDSP+4 # Data Stack Offset
371 ADD
372 STORE
373 RTS
374
375##########################################################################################
376evalstacknavigation
377##########################################################################################
378# Description:
379# If character on TOS is ASCII '.' or ',', inc/dec Data Stack Offset to next entry.
380# Call Stack:
381# Data Stack Base Address
382# Data Stack Offset
383# ASCII character
384# ASCII character
385# Return PC <-- TOS
386# Return Stack:
387# Data Stack Base Address
388# Data Stack Offset
389# ASCII character
390##########################################################################################
391 SWAP
392 LDSP+0
393
394 # Test for ASCII ','
395 WORD_44 # ASCII ','
396 JSR>subtract
bc5b63cf
AT
397 BRZ>evalstacknavigationprevmatch
398
399 # No match.
400 JMP>evalstacknavigationnexttest
401
402 evalstacknavigationprevmatch
403
404 # Matched, decrement Data Stack Offset.
405
406 # Stack now looks like:
407 # Data Stack Base Address
408 # Data Stack Offset
409 # ASCII character
410 # Return PC <-- TOS
411 # ASCII character
412
413 # Decrement the Data Stack Offset
414 LDSP+3 # Data Stack Offset
415 JSR>decrementstackindex
416 STSP+3
417
418 # Clean up stack and return.
419 TEST
420 RTS
421
422 evalstacknavigationnexttest
423 # Test for ASCII '.'
424 WORD_46 # ASCII '.'
425 JSR>subtract
bc5b63cf
AT
426 BRZ>evalstacknavigationnextmatch
427
428 # No match.
429 RTS
430
431 evalstacknavigationnextmatch
432
433 # Matched, increment Data Stack Offset
434
435 # Increment and return.
436 LDSP+2 # Data Stack Offset
437 JSR>incrementstackindex
438 STSP+2
439 RTS
440
441##########################################################################################
442evalnegatestackentry
443##########################################################################################
444# Description:
445# If character on TOS is ASCII ';', negate the current data stack entry.
446# Call Stack:
447# Data Stack Base Address
448# Data Stack Offset
449# ASCII character
450# ASCII character
451# Return PC <-- TOS
452# Return Stack:
453# Data Stack Base Address
454# Data Stack Offset
455# ASCII character
456##########################################################################################
457 SWAP
458
459 # Test for ASCII ';'
460 WORD_58 # ASCII ';'
461 IM_1
462 ADD
463 JSR>subtract
bc5b63cf
AT
464 BRZ>evalnegatestackentrymatch
465
466 # No match, return from subroutine
467 RTS
468
469 evalnegatestackentrymatch
470
471 # Matched, negate the stack entry and return.
472
473 # Stack now looks like:
474 # Data Stack Base Address
475 # Data Stack Offset
476 # ASCII character
477 # Return PC <-- TOS
478
479 LDSP+3 # Data Stack Base Address
480 LDSP+3 # Data Stack Offset
481 ADD
482 LDSP+0
483 LOAD
484 JSR>negate
485 SWAP
486 STORE
487 RTS
488
489##########################################################################################
490evalmathaddition
491##########################################################################################
492# Description:
493# If character on TOS is ASCII '+', perform addition on TOS and NOS.
494# Call Stack:
495# Data Stack Base Address
496# Data Stack Offset
497# ASCII character
498# ASCII character
499# Return PC <-- TOS
500# Return Stack:
501# Data Stack Base Address
502# Data Stack Offset
503# ASCII character
504##########################################################################################
505 SWAP
506
507 # Test for ASCII '+' (43).
508 IM_30
509 IM_13
510 ADD
511 JSR>subtract
bc5b63cf
AT
512 BRZ>evalmathadditionmatch
513
514 # No match, return from subroutine
515 RTS
516
517 evalmathadditionmatch
518
519 # Matched. Perform addition.
520
521 # Stack now looks like:
522 # Data Stack Base Address
523 # Data Stack Offset
524 # ASCII character
525 # Return PC <-- TOS
526
527 # Fetch the first operand.
528 LDSP+3 # Data Stack Base Address
529 LDSP+3 # Data Stack Offset
530 ADD
531 LOAD
532
533 # Decrement Data Stack Offset.
534 LDSP+3 # Data Stack Offset
535 JSR>decrementstackindex
536 STSP+3
537
538 # Fetch the second operand.
539 LDSP+4 # Data Stack Base Address
540 LDSP+4 # Data Stack Offset
541 ADD
542 LOAD
543
544 # Perform the addition.
545 ADD
546
547 # Store the result.
548 LDSP+4 # Data Stack Base Address
549 LDSP+4 # Data Stack Offset
550 ADD
551 STORE
552
553 # Return
554 RTS
555
556##########################################################################################
557evalmathsubtraction
558##########################################################################################
559# Description:
560# If character on TOS is ASCII '-', perform subtraction NOS-TOS.
561# Call Stack:
562# Data Stack Base Address
563# Data Stack Offset
564# ASCII character
565# ASCII character
566# Return PC <-- TOS
567# Return Stack:
568# Data Stack Base Address
569# Data Stack Offset
570# ASCII character
571##########################################################################################
572 SWAP
573
574 # Test for ASCII '-' (45).
575 IM_30
576 IM_15
577 ADD
578 JSR>subtract
bc5b63cf
AT
579 BRZ>evalmathsubtractionmatch
580
581 # No match, return from subroutine
582 RTS
583
584 evalmathsubtractionmatch
585
586 # Matched. Perform subtraction.
587
588 # Stack now looks like:
589 # Data Stack Base Address
590 # Data Stack Offset
591 # ASCII character
592 # Return PC <-- TOS
593
594 # Fetch the first operand.
595 LDSP+3 # Data Stack Base Address
596 LDSP+3 # Data Stack Offset
597 ADD
598 LOAD
599
600 # Decrement Data Stack Offset.
601 LDSP+3 # Data Stack Offset
602 JSR>decrementstackindex
603 STSP+3
604
605 # Fetch the second operand.
606 LDSP+4 # Data Stack Base Address
607 LDSP+4 # Data Stack Offset
608 ADD
609 LOAD
610
611 # Perform the subtraction.
612 JSR>subtract
613
614 # Store the result.
615 LDSP+4 # Data Stack Base Address
616 LDSP+4 # Data Stack Offset
617 ADD
618 STORE
619
620 # Return
621 RTS
622
623##########################################################################################
624evalmathmultiplication
625##########################################################################################
626# Description:
627# If character on TOS is ASCII '*', perform multiplication on TOS and NOS.
628# Call Stack:
629# Data Stack Base Address
630# Data Stack Offset
631# ASCII character
632# ASCII character
633# Return PC <-- TOS
634# Return Stack:
635# Data Stack Base Address
636# Data Stack Offset
637# ASCII character
638##########################################################################################
639 SWAP
640
641 # Test for ASCII '*' (42).
642 IM_30
643 IM_12
644 ADD
645 JSR>subtract
bc5b63cf
AT
646 BRZ>evalmathmultiplicationmatch
647
648 # No match, return from subroutine
649 RTS
650
651 evalmathmultiplicationmatch
652
653 # Matched. Perform multiplication.
654
655 # Stack now looks like:
656 # Data Stack Base Address
657 # Data Stack Offset
658 # ASCII character
659 # Return PC <-- TOS
660
661 # Fetch the first operand.
662 LDSP+3 # Data Stack Base Address
663 LDSP+3 # Data Stack Offset
664 ADD
665 LOAD
666
667 # Decrement Data Stack Offset.
668 LDSP+3 # Data Stack Offset
669 JSR>decrementstackindex
670 STSP+3
671
672 # Fetch the second operand.
673 LDSP+4 # Data Stack Base Address
674 LDSP+4 # Data Stack Offset
675 ADD
676 LOAD
677
678 # Perform the multiplication.
679 JSR>multiply
680
681 # Store the result.
682 LDSP+4 # Data Stack Base Address
683 LDSP+4 # Data Stack Offset
684 ADD
685 STORE
686
687 # Return
688 RTS
689
690##########################################################################################
691evalmathdivision
692##########################################################################################
693# Description:
694# If character on TOS is ASCII '/', perform division NOS/TOS.
695# Returns quotient on TOS and remainder on NOS.
696# Call Stack:
697# Data Stack Base Address
698# Data Stack Offset
699# ASCII character
700# ASCII character
701# Return PC <-- TOS
702# Return Stack:
703# Data Stack Base Address
704# Data Stack Offset
705# ASCII character
706##########################################################################################
707 SWAP
708
709 # Test for ASCII '/' (47).
710 IM_30
711 IM_17
712 ADD
713 JSR>subtract
bc5b63cf
AT
714 BRZ>evalmathdivisionmatch
715
716 # No match, return from subroutine
717 RTS
718
719 evalmathdivisionmatch
720
721 # Matched. Perform division.
722
723 # Stack now looks like:
724 # Data Stack Base Address
725 # Data Stack Offset
726 # ASCII character
727 # Return PC <-- TOS
728
729 # Fetch the first operand.
730 LDSP+3 # Data Stack Base Address
731 LDSP+3 # Data Stack Offset
732 ADD
733 LOAD
734
735 # Decrement Data Stack Offset.
736 LDSP+3 # Data Stack Offset
737 JSR>decrementstackindex
738 STSP+3
739
740 # Fetch the second operand.
741 LDSP+4 # Data Stack Base Address
742 LDSP+4 # Data Stack Offset
743 ADD
744 LOAD
745
746 # Perform the division.
747 SWAP
748 JSR>divide
749
750 # Store the remainder.
751 LDSP+5 # Data Stack Base Address
752 LDSP+5 # Data Stack Offset
753 ADD
754 STORE
755
756 # Increment the Data Stack Offset
757 LDSP+3 # Data Stack Offset
758 JSR>incrementstackindex
759 STSP+3
760
761 # Store the quotient.
762 LDSP+4 # Data Stack Base Address
763 LDSP+4 # Data Stack Offset
764 ADD
765 STORE
766
767 # Return
768 RTS
769
770##########################################################################################
771evalasciidigit
772##########################################################################################
773# Description:
774# If character on TOS is ASCII digit, append it to current stack entry.
775# Call Stack:
776# Data Stack Base Address
777# Data Stack Offset
778# ASCII character
779# ASCII character
780# Return PC <-- TOS
781# Return Stack:
782# Data Stack Base Address
783# Data Stack Offset
784# ASCII character
785##########################################################################################
786 SWAP
787
788 # Test for ASCII digit.
789 JSR>isasciidigit
bc5b63cf
AT
790 BRZ>evalasciidigitmatch
791
792 # No match, return from subroutine
793 RTS
794
795 evalasciidigitmatch
796
797 # Matched, append result to current stack entry and return.
798
799 # Stack now looks like:
800 # Data Stack Base Address
801 # Data Stack Offset
802 # ASCII digit
803 # Return PC <-- TOS
804
805 # Load the existing entry from top of data stack.
806 LDSP+3 # Data Stack Base Address
807 LDSP+3 # Data Stack Offset
808 ADD
809 LDSP+0
810 LOAD
811
812 # Multiply existing entry by ten and add new digit to least-significant location.
813 IM_10
814 JSR>multiply
815 LDSP+3 # ASCII digit
816 JSR>atoi
817 ADD
818
819 # Put new entry back on top of data stack and return.
820 SWAP
821 STORE
822 RTS
823
824##########################################################################################
825isasciidigit
826##########################################################################################
827# Description:
828# Tests if character is ASCII digit (0..9). Returns 0 if true, 1 if false.
829# Call Stack:
830# ASCII character
831# Return PC <-- TOS
832# Return Stack:
833# <boolean, 0=true, 1=false>
834##########################################################################################
835 # Subtract ASCII '0' value, translating ASCII digit to integer.
836 SWAP
837 WORD_48
838 SWAP
839 JSR>subtract
840 # Copy and test negative result. This would indicate an ASCII character below '0'.
841 LDSP+0
842 TEST
843 IM_12 # Address of PSW register
844 LOAD
845 IM_2
846 AND
bc5b63cf
AT
847 BRZ>isasciidigitcontinued
848 # The result was negative, so clean up stack and return false.
849 IM_1
850 STSP+0
851 SWAP
852 RTS
853 isasciidigitcontinued
854 # Subtract another 10 and check for positive result. This indicates ASCII char > '9'.
855 IM_10
856 SWAP
857 JSR>subtract
858 TEST
859 IM_12
860 LOAD
861 IM_2
862 AND
bc5b63cf
AT
863 BRZ>isasciidigitfalse
864 # The result was true, so clean up stack and return true.
865 IM_0
866 SWAP
867 RTS
868 isasciidigitfalse
869 # The result was false, so clean up stack and return false.
870 IM_1
871 SWAP
872 RTS
873
874##########################################################################################
875generatesignflag
876##########################################################################################
877# Description:
878# Given a pair of twos-complement signed integers X and Y, generates a sign flag.
879# Flag is non-zero if the product of X and Y would be negative, otherwise flag is zero.
880# Call Stack:
881# Y Operand
882# X Operand
883# Return PC <-- TOS
884# Return Stack:
885# Sign Flag <-- TOS
886##########################################################################################
887 # Place Return PC at bottom of stack.
888 LDSP+2
889 LDSP+1
890 STSP+3
891 STSP+0
892
893 # Stack now looks like:
894 # Return PC
895 # X Operand
896 # Y Operand <-- TOS
897
898 IM_4
899 LOAD
900 AND
901 SWAP
902 IM_4
903 LOAD
904 AND
905 XOR
906 SWAP
907 RTS
908
909##########################################################################################
910negate
911##########################################################################################
912# Description:
913# Returns the additive inverse of a twos-complement operand.
914# Call Stack:
915# Operand
916# Return PC <-- TOS
917# Return Stack:
918# Result <-- TOS
919##########################################################################################
920 SWAP
921 NOT
922 IM_1
923 ADD
924 SWAP
925 RTS
926
927##########################################################################################
928absolutevalue
929##########################################################################################
930# Description:
931# Returns the absolute value of a twos-complement operand.
932# Call Stack:
933# Operand
934# Return PC <-- TOS
935# Return Stack:
936# Result <-- TOS
937##########################################################################################
938 SWAP
939 LDSP+0
940 IM_4
941 LOAD
942 AND
bc5b63cf
AT
943 BRZ>absolutevaluereturn
944 JSR>negate
945
946 absolutevaluereturn
947 SWAP
948 RTS
949
950##########################################################################################
951multiply
952##########################################################################################
953# Description:
954# Performs X*Y and returns result on TOS.
955# Call Stack:
956# Y Operand
957# X Operand
958# Return PC <-- TOS
959# Return Stack:
960# Result <-- TOS
961##########################################################################################
962 # Place Return PC at bottom of stack.
963 LDSP+2
964 LDSP+1
965 STSP+3
966 STSP+0
967
968 # Stack now looks like:
969 # Return PC
970 # X Operand
971 # Y Operand <-- TOS
972
973 # Generate a sign flag and store it behind the operands.
974 LDSP+1
975 LDSP+1
976 JSR>generatesignflag
977 LDSP+2
978 SWAP
979 STSP+2
980
981 # Stack now looks like:
982 # Return PC
983 # Sign flag (nonzero for negative result, 0 for positive result)
984 # Y Operand
985 # X Operand <-- TOS
986
987 # Convert both X and Y Operands to absolute value.
988 JSR>absolutevalue
989 SWAP
990 JSR>absolutevalue
991
992 # Stack now looks like:
993 # Return PC
994 # Sign flag (nonzero for negative result, 0 for positive result)
995 # ABS(X Operand)
996 # ABS(Y Operand) <-- TOS
997
998 # Prepare the stack for multiplication algorithm
999 IM_0 # For magnitude of left/right shifts.
1000 LDSP+0 # Sets up stack location to build/store result.
1001
1002 # Check Nth bit of second operand.
1003 testbit
1004 LDSP+2 # Y Operand
1005 LDSP+2 # Shift magnitude
1006 SHIFT
1007 IM_1
1008 AND
bc5b63cf
AT
1009 BRZ>skipadd
1010 # If indicated by a 1 bit, shift and add first operand to result.
1011 LDSP+3 # X Operand
1012 IM_4 # 0x80000000
1013 LOAD
1014 LDSP+3 # Shift magnitude
1015 OR
1016 SHIFT
1017 ADD
1018 skipadd
1019
1020 # Increment shift magnitude counter.
1021 LDSP+1 # Shift magnitude
1022 IM_1
1023 ADD
1024 STSP+1
1025
1026 # Test for completion of multiplication algorithm (31 shifts).
1027 LDSP+1 # Shift magnitude
1028 IM_30
1029 JSR>subtract
bc5b63cf
AT
1030 BRZ>multiplycleanup
1031 JMP>testbit
1032
1033 # Clean up the the stack after performing multiplication.
1034 multiplycleanup
1035 STSP+0
1036 STSP+0
1037 STSP+0
1038
1039 # Stack now looks like:
1040 # Return PC
1041 # Sign flag (nonzero for negative result, 0 for positive result)
1042 # ABS(X*Y) <-- TOS
1043
1044 # Set the sign of the product.
1045 applysign
1046 SWAP
bc5b63cf
AT
1047 BRZ>multiplyreturn
1048 JSR>negate
1049
1050 # Clean up and return.
1051 multiplyreturn
1052 SWAP
1053 RTS
1054
1055##########################################################################################
1056divide
1057##########################################################################################
1058# Description:
1059# Division with remainder.
1060# Halts on zero divisor.
1061# Call Stack:
1062# Dividend
1063# Divisor
1064# Return PC <-- TOS
1065# Return Stack:
1066# Quotient
1067# Remainder <-- TOS
1068##########################################################################################
1069 # Move Return PC to bottom of stack.
1070 LDSP+2
1071 SWAP
1072 STSP+2
1073 SWAP
1074
1075 # Stack now looks like:
1076 # Return PC
1077 # Dividend
1078 # Divisor <-- TOS
1079
1080 # Check for zero divisor
1081 LDSP+0
bc5b63cf
AT
1082 BRZ>divideexception
1083
1084 # Generate a sign flag and store it behind the operands.
1085 LDSP+1
1086 LDSP+1
1087 JSR>generatesignflag
1088 LDSP+2
1089 SWAP
1090 STSP+2
1091
1092 # Stack now looks like:
1093 # Return PC
1094 # Sign flag (nonzero for negative result, 0 for positive result)
1095 # Divisor
1096 # Dividend <-- TOS
1097
1098 # Convert both Dividend and Divisor to absolute value.
1099 JSR>absolutevalue
1100 SWAP
1101 JSR>absolutevalue
1102
1103 # Stack now looks like:
1104 # Return PC
1105 # Sign flag (nonzero for negative result, 0 for positive result)
1106 # ABS(Dividend)
1107 # ABS(Divisor) <-- TOS
1108
1109 # Prepare stack for division algorithm.
1110 IM_31 # Cycle Counter - Loop from n-1 -> 0 where n = 32 bits.
1111 IM_0 # Quotient
1112 IM_0 # Remainder
1113
1114 # Binary long division
1115 divisionloop
1116 # Check Cycle Counter for end-of-loop condition (CC = -1).
1117 LDSP+2 # Cycle Counter
1118 IM_1
1119 ADD
bc5b63cf
AT
1120 BRZ>divisionloopend
1121
1122 # While Cycle Counter >= 0
1123
1124 # Left-shift Remainder by 1 bit.
1125 IM_1
1126 IM_4 # Address of 0x80000000 register
1127 LOAD
1128 OR
1129 SHIFT
1130
1131 # Set LSB of Remainder equal to bit (Cycle Counter) of Dividend.
1132 LDSP+4 # Dividend
1133 LDSP+3 # Cycle Counter
1134 SHIFT
1135 IM_1
1136 AND
1137 OR
1138
1139 # Check if Remainder >= Divisor
1140 LDSP+3 # Divisor
1141 LDSP+1 # Remainder
1142 JSR>subtract
1143 TEST
1144 IM_12 # Address of PSW register
1145 LOAD
1146 IM_2 # Bit for Negative Flag in PSW
1147 AND
1148 IM_2
1149 XOR
bc5b63cf
AT
1150 BRZ>divisionsubloopend
1151
1152 # If Remainder >= Divisor
1153
1154 # Set Remainder = Remainder - Divisor
1155 LDSP+3 # Divisor
1156 SWAP
1157 JSR>subtract
1158
1159 # Set bit (Cycle Counter) of Quotient equal to 1.
1160 SWAP
1161 IM_1
1162 LDSP+3 # Cycle Counter
1163 IM_4
1164 LOAD
1165 OR
1166 SHIFT
1167 OR
1168 SWAP
1169
1170 divisionsubloopend
1171
1172 # Decrement Cycle Counter
1173 IM_1
1174 LDSP+3 # Cycle Counter
1175 JSR>subtract
1176 STSP+2
1177
1178 # Loop over next division cycle
1179 JMP>divisionloop
1180
1181 divisionloopend
1182
1183 # Stack cleanup
1184 STSP+1
1185 STSP+1
1186 STSP+1
1187
1188 # Stack now looks like:
1189 # Return PC
1190 # Sign flag (nonzero for negative result, 0 for positive result)
1191 # Remainder
1192 # Quotient <-- TOS
1193
1194 # Set sign of results.
1195 LDSP+2 # Sign flag
bc5b63cf
AT
1196 BRZ>divisioncleanup
1197 JSR>negate
1198 SWAP
1199 JSR>negate
1200 SWAP
1201
1202 divisioncleanup
1203
1204 # Clean up and return
1205 SWAP
1206 LDSP+3 # Return PC
1207 SWAP
1208 STSP+2
1209 SWAP
1210 STSP+2
1211 RTS
1212
1213 # For now we can only HALT on errors and let the PC inform our debugging.
1214 divideexception
1215 HALT
1216
1217##########################################################################################
1218subtract
1219##########################################################################################
1220# Description:
1221# Performs X-Y and returns result on TOS.
1222# Call Stack:
1223# Y Operand
1224# X Operand
1225# Return PC <-- TOS
1226# Return Stack:
1227# Result <-- TOS
1228##########################################################################################
1229 # Place Return PC at bottom of stack.
1230 LDSP+2
1231 LDSP+1
1232 STSP+3
1233 STSP+0
1234 # Stack now looks like:
1235 # Return PC
1236 # X Operand
1237 # Y Operand <-- TOS
1238
1239 JSR>negate
1240 ADD
1241 SWAP
1242 RTS
1243
1244##########################################################################################
1245atoi
1246##########################################################################################
1247# Description:
1248# Converts an ASCII decimal into the corresponding integer value.
1249# No bounds checks; assumed to already be performed in isasciidigit().
1250# Call Stack:
1251# Operand
1252# Return PC <-- TOS
1253# Return Stack:
1254# Result <-- TOS
1255##########################################################################################
1256 SWAP
1257 WORD_48
1258 SWAP
1259 JSR>subtract
1260 SWAP
1261 RTS
1262
1263##########################################################################################
1264itoa
1265##########################################################################################
1266# Description:
1267# Converts an integer (0..9) into the corresponding ASCII character.
1268# Call Stack:
1269# Operand
1270# Return PC <-- TOS
1271# Return Stack:
1272# Result <-- TOS
1273##########################################################################################
1274 # Copy operand to TOS
1275 LDSP+1
1276 # Verify that operand < 10
1277 IM_10
1278 LDSP+1
1279 JSR>subtract
1280 TEST # Set PSW according to difference.
1281 # Branch if non-negative:
1282 IM_12 # Address of PSW
1283 LOAD
1284 IM_2
1285 AND
bc5b63cf
AT
1286 BRZ>itoahalt
1287 # Verify that operand > -1
1288 LDSP+0
1289 TEST # Set PSW according to operand.
1290 # Branch if negative:
1291 IM_12
1292 LOAD
1293 IM_2
1294 AND
1295 IM_2
1296 XOR
bc5b63cf
AT
1297 BRZ>itoahalt # Branch if operand was negative.
1298 # Convert the integer to its ASCII representation and return to caller.
1299 WORD_48
1300 ADD
1301 STSP+1
1302 RTS
1303 # Halt on error
1304 itoahalt
1305 HALT
1306
1307##########################################################################################
1308putchar
1309##########################################################################################
1310# Description:
1311# Writes one character to the terminal.
1312# Call Stack:
1313# Character to write
1314# Return PC <-- TOS
1315# Return Stack:
1316# <empty>
1317##########################################################################################
1318 WORD_134217728 # XBUF
1319 WORD_134217732 # XCSR
1320 LDSP+3
1321 SWAP
1322 putcharloop
1323 LDSP+0
1324 LOAD
bc5b63cf
AT
1325 BRZ>putcharloop
1326 TEST # Drop XCSR from stack
1327 SWAP
1328 STORE
1329 # Wrote the character. Clean up stack and return.
1330 STSP+0
1331 RTS
1332
1333##########################################################################################
1334getchar
1335##########################################################################################
1336# Description:
1337# Reads one character from the terminal.
1338# Call Stack:
1339# Return PC <-- TOS
1340# Return Stack:
1341# Character <-- TOS
1342##########################################################################################
1343 WORD_134217736 # RBUF
1344 WORD_134217740 # RCSR
1345 getcharloop
1346 LDSP+0
1347 LOAD
bc5b63cf
AT
1348 BRZ>getcharloop
1349 LDSP+1
1350 LOAD
1351 # Found a character. Clean up stack and return.
1352 STSP+0
1353 STSP+0
1354 SWAP
1355 RTS
1356
1357##########################################################################################
1358printstring
1359##########################################################################################
1360# Description:
1361# Prints a null-terminated string located on the stack.
1362# Call Stack:
1363# ASCII NUL
1364# ASCII character
1365# ...
1366# ASCII character
1367# Return PC <-- TOS
1368##########################################################################################
1369 SWAP
418f3fc7 1370 LDSP+0
bc5b63cf
AT
1371 BRZ>printstringreturn
1372 JSR>putchar
1373 JMP>printstring
1374
1375 printstringreturn
1376 TEST
1377 RTS
1378
1379##########################################################################################
1380ansiescapeclearscreen
1381##########################################################################################
1382# Description:
1383# Clears the entire screen.
1384# Call Stack:
1385# Return PC <-- TOS
1386# Return Stack:
1387# <empty>
1388##########################################################################################
1389 # ASCII NUL
1390 WORD_0
1391 # ASCII 'J'
1392 WORD_74
1393 # ASCII '2'
1394 WORD_50
1395 # ASCII '['
1396 WORD_90
1397 IM_1
1398 ADD
1399 # ASCII ESC
1400 WORD_26
1401 IM_1
1402 ADD
1403 # Print string and return
1404 JSR>printstring
1405 RTS
1406
1407##########################################################################################
1408ansiescapesetcursorcolumnone
1409##########################################################################################
1410# Description:
1411# Reset cursor to column 1 of screen.
1412# Call Stack:
1413# Return PC <-- TOS
1414# Return Stack:
1415# <empty>
1416##########################################################################################
1417 # ASCII NUL
1418 WORD_0
1419 # ASCII 'G'
1420 WORD_70
1421 IM_1
1422 ADD
1423 # ASCII '1'
1424 WORD_48
1425 IM_1
1426 ADD
1427 # ASCII '['
1428 WORD_90
1429 IM_1
1430 ADD
1431 # ASCII ESC
1432 WORD_26
1433 IM_1
1434 ADD
1435 # Print string and return
1436 JSR>printstring
1437 RTS