Skip to content

Instantly share code, notes, and snippets.

@thentenaar
Last active March 27, 2024 14:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thentenaar/275041e638a2145d97f237b42934acd6 to your computer and use it in GitHub Desktop.
Save thentenaar/275041e638a2145d97f237b42934acd6 to your computer and use it in GitHub Desktop.
Simple TI 99/4a XB Little Man Computer + Line Assembler
1 REM Simple XB Little Man Computer + Line Assembler
2 REM Copyright (C) 2021 Tim Hentenaar.
3 REM This code is licenced under the Simplified BSD License.
4 REM https://opensource.org/license/bsd-2-clause
10 DIM MEM(100) ! Mailboxes (memory)
20 DIM MPOS(100,2) ! Screen positions for mailbox values
30 PC,IR,AR,A,N,H,IN,OUT=0
40 GOTO 50 :: I :: K :: S :: OP :: L$ :: CALL CLEAR :: CALL HCHAR :: CALL VCHAR :: CALL KEY :: CALL COLOR :: !@P-
50 FOR I = 0 TO 99
60 MPOS(I+1,1) = 5 + (I - INT(I/20) * 20) ! Row position
70 MPOS(I+1,2) = 5 + 5 * INT(I/20) ! Col position
80 MEM(I+1) = 0
90 NEXT I
100 FOR I=0 TO 14 :: CALL COLOR(I,4,2) :: NEXT I :: I = 0 :: GOSUB 600
110 IR,OP=0 :: CALL CLEAR
120 DISPLAY AT(1,1):"PC" :: DISPLAY AT(1,9):"IR" :: DISPLAY AT(1,17):"AR"
130 DISPLAY AT(2,1):"A" :: DISPLAY AT(2,9):"IN" :: DISPLAY AT(2,17):"OUT"
140 GOSUB 300 ! Draw Register States
150 CALL HCHAR(4,6,95,25)
160 FOR I = 0 TO 4 :: DISPLAY AT(3,5*(I+1)):I*20 :: NEXT I
170 FOR I = 0 TO 19 :: DISPLAY AT(5+I,1):I :: NEXT I
180 FOR I = 3 TO 28 STEP 5 :: CALL VCHAR(5,3+I,124,20) :: NEXT I
190 FOR I = 1 TO 100 :: DISPLAY AT(MPOS,I,1),MPOS(I,2)) SIZE(4):MEM(I) :: NEXT I
200 REM Main Loop: Wait for a key and step/halt
210 ON WARNING NEXT
220 CALL KEY(0,K,S) :: IF S=0 THEN 220
230 IF K=72 OR K=104 THEN 280 ! [H]alt
240 IF H OR (K<>83 AND K<>115) THEN 220 ! [S]tep
250 GOSUB 400 ! Fetch, Decode, Execute
260 IF H THEN DISPLAY AT(1,24) BEEP:"HALT"
270 GOTO 220
280 I = PC :: GOSUB 600 ! Back to monitor mode
290 GOTO 110
300 REM Draw the state of the registers
310 DISPLAY AT (1,4) SIZE(4):PC
320 DISPLAY AT (1,12) SIZE(2):IR
330 DISPLAY AT (1,20) SIZE(2):AR
340 DISPLAY AT (2,4) SIZE(4):A
350 DISPLAY AT (2,12) SIZE(4):IN
360 DISPLAY AT (2,21) SIZE(4):OUT
370 RETURN
400 REM Fetch, Decode, Execute (4xx is undefined / treated as NOP)
410 AR = MEM(PC + 1) ! Fetch instruction
420 IR = INT(AR / 100) ! Decode opcode
430 OP = 1 + AR - (IR * 100) ! Decode operand
440 PC = PC + 1 :: IF PC > 99 THEN PC = PC - 100
450 IF IR=0 THEN 470
460 ON IR GOSUB 510, 520, 530, 595, 540, 550, 560, 570, 580
470 H = IR=0 ! HLT
480 N = -1*((A>999)+(A<0)) ! Set N if an overflow occured
490 IF N=1 THEN A = A + 999 * (A>0+(-1*A<0)) ! Ensure A remains within range
500 GOTO 300 ! Draw register states
510 A = A + MEM(OP) :: RETURN ! 1: ADD
520 A = A - MEM(OP) :: RETURN ! 2: SUB
530 MEM(OP) = A :: DISPLAY AT(MPOS(OP,1),MPOS(OP,2)) SIZE(4):A :: RETURN !3: STA
540 A = MEM(OP) :: RETURN ! 5: LDA
550 PC = OP - 1 :: RETURN ! 6: BRA
560 IF A=0 THEN PC=OP - 1 ! 7: BRZ
565 RETURN
570 IF N=0 THEN PC=OP - 1 ! 8: BRP
575 RETURN
580 IF OP = 2 THEN ACCEPT AT(2,12) BEEP VALIDATE(NUMERIC) SIZE(4):IN :: A=IN ! 9: INP
590 IF OP = 3 THEN OUT = A ! 9: OUT
595 RETURN
600 CALL CLEAR ! Code Entry (assumes I is set on entry)
610 PRINT "LMC Assembler Version 1.0"
620 PRINT "Enter '?' at the prompt for help" :: PRINT
630 I = I + 1 :: IF I > 100 THEN I = I - 100 ! Handle Overflow
640 ON ERROR 850 ! Invalid input, etc.
650 LINPUT STR$(I - 1) & " (" & STR$(MEM(I)) & ") > ":L$
660 IF LEN(L$) = 0 THEN 630 ELSE IR = ASC(SEG$(L$,1,1))
690 IF IR=63 THEN 920 ! ? (Help)
670 IF IR=68 OR IR=100 THEN 860 ! [D]isplay
680 IF IR=71 OR IR=103 THEN 880 ! [G]o
700 IF IR=82 OR IR=114 THEN ON ERROR STOP :: H=0 :: PC=I-1 :: RETURN ! [R]un
710 IF IR=45 OR (IR>47 AND IR<58) THEN 900 ! Number literal -> mailbox
720 IF LEN(L$) > 3 THEN OP = VAL(SEG$(L$,5,2))
730 L$ = SEG$(L$,1,3)
740 IF L$="HLT" OR L$="hlt" THEN MEM(I) = 0 :: GOTO 630 ! 0: HLT
750 IF L$="ADD" OR L$="add" THEN MEM(I) = 100 + OP :: GOTO 630 ! 1: ADD
760 IF L$="SUB" OR L$="sub" THEN MEM(I) = 200 + OP :: GOTO 630 ! 2: SUB
770 IF L$="STA" OR L$="sta" THEN MEM(I) = 300 + OP :: GOTO 630 ! 3: STA
780 IF L$="LDA" OR L$="lda" THEN MEM(I) = 500 + OP :: GOTO 630 ! 5: LDA
790 IF L$="BRA" OR L$="bra" THEN MEM(I) = 600 + OP :: GOTO 630 ! 6: BRA
800 IF L$="BRZ" OR L$="brz" THEN MEM(I) = 700 + OP :: GOTO 630 ! 7: BRZ
810 IF L$="BRP" OR L$="brp" THEN MEM(I) = 800 + OP :: GOTO 630 ! 8: BRP
820 IF L$="INP" OR L$="inp" THEN MEM(I) = 901 :: GOTO 630 ! 9: INP
830 IF L$="OUT" OR L$="out" THEN MEM(I) = 902 :: GOTO 630 ! 9: OUT
840 PRINT "Invalid instruction or command" :: PRINT :: GOTO 640
850 PRINT "Invalid input" :: PRINT :: GOTO 640
860 IR = VAL(SEG$(L$,3,2)) ! [D]isplay
870 IF ((IR<0)*(IR>99))=0 THEN PRINT MEM(IR + 1) :: GOTO 640 ELSE GOTO 850
880 IR = VAL(SEG$(L$,3,2)) ! [G]o
890 IF ((IR<0)*(IR>99))=0 THEN I = IR + 1 :: GOTO 640 ELSE GOTO 850
900 IR = VAL(L$) ! Literal -> Mailbox
910 IF ((IR<-999)*(IR>999))=0 THEN MEM(I) = IR :: GOTO 630 ELSE GOTO 850
920 PRINT "-------- Help --------"
921 PRINT "You can enter a number to store that number in the mailbox given";
922 PRINT "by the prompt. You may also enter a mnemonic instruction to be";
923 PRINT "assembled." :: PRINT
924 PRINT "The following commands are available:"
925 PRINT "D mailbox - Display a mailbox (0 - 99)"
926 PRINT "G mailbox - Move to a mailbox"
927 PRINT "R - Run the program from the current mailbox" :: PRINT
928 PRINT "In run mode, press 'S' to step through the program or";
929 PRINT "'H' to return to the prompt" :: PRINT
930 GOTO 650
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment