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). | |
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 | ########################################################################################## | |
135 | decrementstackindex | |
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 | ########################################################################################## | |
168 | printstackindex | |
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 | ########################################################################################## | |
207 | printbinaryinteger | |
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 | ########################################################################################## | |
302 | printtopstackentry | |
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 | ########################################################################################## | |
331 | evalzerostackentry | |
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 | ########################################################################################## | |
376 | evalstacknavigation | |
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 | ########################################################################################## | |
442 | evalnegatestackentry | |
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 | ########################################################################################## | |
490 | evalmathaddition | |
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 | ########################################################################################## | |
557 | evalmathsubtraction | |
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 | ########################################################################################## | |
624 | evalmathmultiplication | |
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 | ########################################################################################## | |
691 | evalmathdivision | |
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 | ########################################################################################## | |
771 | evalasciidigit | |
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 | ########################################################################################## | |
825 | isasciidigit | |
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 | ########################################################################################## | |
875 | generatesignflag | |
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 | ########################################################################################## | |
910 | negate | |
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 | ########################################################################################## | |
928 | absolutevalue | |
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 | ########################################################################################## | |
951 | multiply | |
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 | ########################################################################################## | |
1056 | divide | |
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 | ########################################################################################## | |
1218 | subtract | |
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 | ########################################################################################## | |
1245 | atoi | |
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 | ########################################################################################## | |
1264 | itoa | |
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 | ########################################################################################## | |
1308 | putchar | |
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 | ########################################################################################## | |
1334 | getchar | |
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 | ########################################################################################## | |
1358 | printstring | |
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 | ########################################################################################## | |
1380 | ansiescapeclearscreen | |
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 | ########################################################################################## | |
1408 | ansiescapesetcursorcolumnone | |
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 |