From 192656fef8e9b86abac0b43089541c9f02940c37 Mon Sep 17 00:00:00 2001 From: Luxferre Date: Sun, 27 Apr 2025 16:53:48 +0300 Subject: [PATCH] added the TI-74 BASIC port and the mu808asm'MU74 export support --- README.md | 58 +++++++++++++++++++++++++++++++++++++++++++++++- mu808.b74 | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++ mu808asm.py | 32 ++++++++++++++++++++++++++- 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 mu808.b74 diff --git a/README.md b/README.md index a1f13b8..7842555 100644 --- a/README.md +++ b/README.md @@ -303,7 +303,10 @@ Reference implementations * [Python 3](mu808asm.py): supports assembling MU8A source files into both plain text (MU8) and binary (MU8B) machine code formats. Also supports disassembling MU8 and MU8B files into their MU8A sources and converting - machine code between MU8 and MU8B formats. + machine code between MU8 and MU8B formats. Additionally, this assembler + implementation provides the `t74` mode to convert plaintext MU8 machine code + into the format suitable for entering into TI-74 BASIC for running on the + TI-74 port of mu808 (see below). These lists are going to be expanded as soon as new reference implementations appear. @@ -331,6 +334,59 @@ keys of the standard phone keypad, the following convention is recommended: * the `#` (pound) key actually confirms entering a single number field, and all instructions are required to contain exactly five numbers. +Retro/minimal platform implementations +-------------------------------------- +Here's the list of known/existing mu808 implementations that adhere to the +specification to most extent and run compatible machine code but cannot +provide full operating environment functionality due to the limits of the +platform itself. + +### TI-74 BASIC + +The [mu808.b74](mu808.b74) file contains a BASIC port of mu808 for the Texas +Instruments TI-74 portable computer (tested on the TI-74S variant). Due to +the resource constraints, the following limitations apply: + +* only 149 program steps and 256 data cells supported (adjustable at line 110), +* no interactive mode (the `RUN` command directly executes the predefined + program in the VM), +* the program itself is entered into the DATA statements in the so-called + MU74 format (see below), +* no support for I/O port 2, tracing or intruction dumping, +* no boundary checks for the addresses inside the program. + +Also, since the VM runs on top of a BASIC interpreter, program execution is +extremely slow most of the time. Keep in mind, this is more of a proof of +concept than a viable solution, and using the "native" TI BASIC is preferred +for any serious computing on that machine. + +In order to store your programs on the device to run via this mu808 VM version, +you need to enter them in DATA statements in two-number pairs starting from +`DATA 0,0` at the BASIC line 5000. The last `DATA` line of the program must be +`DATA -1,0`. In between these two, every program instruction `lno cmd a1 a2 a3` +must be compressed into the form: +``` +[5000+lno] DATA [cmd*10000 + a1], [a2 * 10000 + a3] +``` +This storage format is called MU74. For example, the compound interest +calculator from the official mu808 examples will transform into: +``` +5000 DATA 0,0 +5001 DATA 50100,1 +5002 DATA 40002,30000 +5003 DATA 90002,10004 +5004 DATA 50001,5 +5005 DATA 70005,40005 +5006 DATA 130001,50005 +5007 DATA 70000,30005 +5008 DATA 130000,50005 +5009 DATA 30005,50000 +5010 DATA -1,0 +``` +To make the conversion easier, the official mu808 assembler, `mu808asm.py`, now +supports the `t74` mode that accepts a plain MU8 machine code file and outputs +the same program in the MU74 format. + FAQ --- diff --git a/mu808.b74 b/mu808.b74 new file mode 100644 index 0000000..fe87f40 --- /dev/null +++ b/mu808.b74 @@ -0,0 +1,64 @@ +100 RANDOMIZE:RAD +110 DIM PMEM(300),DMEM(256) +120 RESTORE 5000 +130 I=0 +140 READ PMEM(I), PMEM(I+1) +150 I=I+2 +160 IF PMEM(I-2)>-1 THEN 140 +170 L=1:IAT,V1,V2,V3=0 +180 M=L+L:A=PMEM(M):B=PMEM(M+1) +190 IF A<0 THEN 730 +200 CMD=INT(A/10000) +210 IF IAT=1 THEN 220 ELSE 230 +220 X=INT(V1):Y=INT(V2):Z=INT(V3):IAT=0:GOTO 240 +230 X=A-CMD*10000:Y=INT(B/10000):Z=B-Y*10000 +240 V1,V2,V3=0 +250 IF CMD=5 THEN DMEM(Z)=X+(Y/10000):GOTO 720 +260 V1=DMEM(X):V2=DMEM(Y):V3=DMEM(Z) +270 IF CMD=1 THEN 280 ELSE 420 +280 IF X=0 AND V2=0 THEN L=Z-1:GOTO 720 +290 IF X=1 AND V2>0 THEN L=Z-1:GOTO 720 +300 IF X=2 AND V2<0 THEN L=Z-1:GOTO 720 +310 IF X=3 AND V2>=0 THEN L=Z-1:GOTO 720 +320 IF X=4 AND V2<=0 THEN L=Z-1:GOTO 720 +330 IF X=5 AND V2<>0 THEN L=Z-1:GOTO 720 +340 IF X=6 THEN L=Z-1:GOTO 720 +350 IF X=7 AND V2=0 THEN L=INT(V3)-1:GOTO 720 +360 IF X=8 AND V2>0 THEN L=INT(V3)-1:GOTO 720 +370 IF X=9 AND V2<0 THEN L=INT(V3)-1:GOTO 720 +380 IF X=10 AND V2>=0 THEN L=INT(V3)-1:GOTO 720 +390 IF X=11 AND V2<=0 THEN L=INT(V3)-1:GOTO 720 +400 IF X=12 AND V2<>0 THEN L=INT(V3)-1:GOTO 720 +410 IF X=13 THEN L=INT(V3)-1:GOTO 720 +420 IF CMD=2 THEN IAT=1:GOTO 720 +430 IF CMD=3 THEN 440 ELSE 490 +440 FOR I=X TO Y +450 IF Z=0 THEN PRINT(DMEM(I)):PAUSE +460 IF Z=1 THEN 470 ELSE 480 +470 IF DMEM(I)=10 THEN PAUSE ELSE PRINT(CHR$(INT(DMEM(I)))); +480 NEXT I:GOTO 720 +490 IF CMD=4 THEN 500 ELSE 530 +500 FOR I=X TO Y +510 IF Z=0 THEN INPUT DMEM(I) +520 NEXT I:GOTO 720 +530 IF CMD=6 THEN 540 ELSE 570 +540 IF X=0 THEN DMEM(Z)=Y:GOTO 720 +550 IF X=1 THEN DMEM(Z)=V2:GOTO 720 +560 IF X>1 THEN DMEM(INT(V3))=DMEM(INT(V2)):GOTO 720 +570 IF CMD=7 THEN DMEM(Z)=V1+V2*V3:GOTO 720 +580 IF CMD=8 THEN DMEM(Z)=V1-V2:GOTO 720 +590 IF CMD=9 THEN 600 ELSE 610 +600 IF V2=0 THEN DMEM(Z)=0:GOTO 720 ELSE DMEM(Z)=V1/V2:GOTO 720 +610 IF CMD=10 THEN 620 ELSE 630 +620 IF V2=0 THEN DMEM(Z)=INT(V1):GOTO 720 ELSE DMEM(Z)=V1-V2*INT(V1/V2):GOTO 720 +630 IF CMD=11 THEN DMEM(Z)=ABS(V2):GOTO 720 +640 IF CMD=12 THEN DMEM(Z)=SQR(ABS(V2)):GOTO 720 +650 IF CMD=13 THEN 660 ELSE 670 +660 IF X=0 THEN DMEM(Z)=EXP(V2):GOTO 720 ELSE DMEM(Z)=LN(ABS(V2)):GOTO 720 +670 IF CMD=14 THEN 680 ELSE 710 +680 IF X=0 THEN DMEM(Z)=SIN(V2):GOTO 720 +690 IF X=1 THEN DMEM(Z)=COS(V2):GOTO 720 +700 IF X>1 THEN DMEM(Z)=ATN(V2):GOTO 720 +710 IF CMD=15 THEN DMEM(Z)=INT(V1)+INT(RND*(INT(V2)-INT(V1)+1)) +720 L=L+1:GOTO 180 +730 END diff --git a/mu808asm.py b/mu808asm.py index f63f28f..b93810a 100755 --- a/mu808asm.py +++ b/mu808asm.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # a simple assembler/disassembler for the mu808 VM # supports both text and binary program formats -# usage: mu808asm [at|ab|dt|db|t2b|b2t] file outfile +# usage: mu808asm [at|ab|dt|db|t2b|b2t|t74] file outfile # modes: # at: assemble to plaintext (MU8) machine code # ab: assemble to binary (MU8B) machine code @@ -9,6 +9,7 @@ # db: disassemble binary (MU8B) machine code # t2b: convert from plaintext MU8 to binary MU8B # b2t: convert from binary MU8B to plaintext MU8 +# t74: convert from plaintext MU8 to the TI-74 representation import sys, re, struct @@ -132,6 +133,33 @@ def totext(binrep): out += ' '.join([str(lno), str(cmd), str(x), str(y), str(z)]) + '\n' return out +# converts the MU8 plaintext machine code to the TI-74 DATA statements (MU74) +def ti74data(txtrep:str, baseaddr:int=5000): + instrs = [] # instruction list to store here + vreg = re.compile(r'\s+') + iindex = 0 + instr = [] + for instrpart in vreg.split(txtrep): + if iindex == 5: + instrs.append(instr) + instr = [] + iindex = 0 + if len(instrpart) > 0: + instr.append(int(instrpart)) + iindex += 1 + # now, instrs contains 5-number groups + out = f'{baseaddr} DATA 0,0\n' + maxlno = 0 + for instr in instrs: + lno, cmd, x, y, z = instr + if lno > maxlno: + maxlno = lno + a = cmd*10000 + x + b = y*10000 + z + out += f'{baseaddr + lno} DATA {a},{b}\n' + out += f'{baseaddr + maxlno + 1} DATA -1,0\n' + return out + def main(): if len(sys.argv) < 4: print("Usage: mu808asm [at|ab|dt|db|t2b|b2t] file outfile") @@ -162,6 +190,8 @@ def main(): elif mode == 'db': # disassemble binary srctext = totext(srctext) output = disassemble(srctext) + elif mode == 't74': # convert to TI-74 DATA statements + output = ti74data(srctext) else: # assemble output = assemble(srctext) # default mode if mode == 'ab':