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