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