Nice work! I don't understand much of this to be honest as my assembly is limited to a few credits at the University many many years ago and focused on IA32 and MIPS assembly ;)
;;; The following variables get set to '*' or '.' to indicate their ;;; status, but they are never used. I believe the selection on the left (1, 3 and 5) are the "Norwegian Settings" you may enable and the selection on the other side 2, 4 and 6 are the default "US/English" settings. The * and . has a very nice function in the UI as it lets you see what you currently have selected. If you for instance have selected Norwegian TELECOM, English Printer and Norwegian line feed then the display will show: * . * at the bottom when the program is loaded. First time the program is loaded it will show: . . . at the bottom indicating the default "US/English" settings. Regards, Rune On Sun, Apr 5, 2026 at 3:32 PM B 9 <[email protected]> wrote: > I’ve fixed up the source code so it actually assembles properly into a > binary identical to INSTAL.CO. Much of it is straightforward, but there > are still some mysteries I haven't solved, like why is the handler for `RST > 7 18h` (BASIC OPEN statement) being set up? And why do the interrupt > handlers PUSH and POP the A register seemingly needlessly? > > —b9 > > > ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; > INSTAL.ASM:;;;;;; Install charset mapping for TERM and Printer on the;;; > TRS-80 Televerket Modell 100 (Norwegian Model 100);;;;;; Released on tape > by Tandy Radio-Shack in 1984.;;; Recovered from tape by Rune Dalvik.;;; > Disassembled and commented by hackerb9. > ;;; Can be assembled to .CO using 'asmx -b8003h instal.asm'. > ;;; ROM Calls > CLS EQU 0x4231 > MENU EQU 0x5797 ; Main menu > INTRET EQU 0x71f7 ; Interrupt exit routine (pop all regs & RET) > SCANKBD EQU 0x7242 > BSBEEP EQU 0x7662;;; RAM Locations > RS232RxHook EQU 0xf5fc ; RST 6.5 RAM Vector (VUARTH Data Ready) > ; (called on RS232 receive char interrupt) > PrtrOutVector EQU 0xfae4 ; RST 7 jump table, index 0x0A > ; (called when sending a char to printer) > OpenVector EQU 0xfb0a ; RST 7 jump table, index 0x18 > ; (called by BASIC OPEN statement) > ComLF EQU 0xf65a > ParityControl EQU 0xff8d > > CPU 8085 ; Hint for asmx assembler > ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Six > byte .CO header for Kyotronic-85 and kin.;; * START - Where the program is > ORG'd to run from.;; * LENGTH - Size of executable data sans this 6 byte > header.;; * ENTRY - Where the program will be entered (entry point).;; - > Executable data follow, ORG'ed at START. > BEGINP EQU 8003h > ORG BEGINP > DW BEGINP, ENDP-BEGINP, BEGINP > RORG BEGINP > ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; INSTAL > main routine > > InstallStart: > CALL CLS > MVI B,193 ; Menu is 193 chars long > LXI H,MenuText ; "\tDEFINISION AV KARAKTERSETT\n\r..." > ShowMenuText: > MOV A,M > RST 4 ; RST 4 is putchar > DCR B > INX H > JNZ ShowMenuText > XRA A ; Clear Z and C flags > WaitForKey: > CALL SCANKBD > JZ WaitForKey > JC GotSpecial > CPI '1' > CZ SetupRS232Hook ; RS-232 interrupt on byte received > CPI '2' > CZ RemoveRS232Hook > CPI '3' > CZ SetupPrinterHook ; Intercept bytes sent to printer > CPI '4' > CZ RemovePrinterHook > CPI '5' > CZ DisableTxAutoLF > CPI '6' > CZ EnableTxAutoLF > XRA A > CALL BSBEEP > JMP InstallStart > GotSpecial: > CPI 0x7 ; F8 key > CZ MENU > JMP WaitForKey > > RemoveRS232Hook: > MVI A,0xc9 ; C9 is RET > STA (RS232RxHook) ; F5FC is RST6.5 hook, called on Rx interrupt > LXI H,0x0 > SHLD (RS232RxHook+1) > LXI H,0x7ff3 ; Address 7FF3 holds a RET statement > SHLD (OpenVector) > MVI A,'.' > STA (RS232HookStatus) > RET > > DisableTxAutoLF: > MVI A,0x1 > STA (ComLF) ; Do not add a LF after transmitting CR > MVI A,'*' > STA (AutoLFStatus) > RET > > EnableTxAutoLF: > MVI A,0x0 > STA (COMLF) ; Automatically send LF after CR > MVI A,'.' > STA (AutoLFStatus) > RET > > SetupRS232Hook: > MVI A,0xc3 ;C3 is JMP > STA (RS232RxHook) ; 0xf5fc > LXI H,RxHandler ; 0x808d > SHLD (RS232RxHook+1) ; 0xf5fd > LXI H,OpenHandler ; 0x80b8 > SHLD (OpenVector) ; 0xfb0a > MVI A,'*' > STA (RS232HookStatus) > RET > ;;; This handler is called by the RST 6.5 routine (6DAC).;; It replaces RS232 > received [\]{|} with ÆØÅæøå (M100 accents) > RxHandler: > DI ; Disable interrupt while handling RST 6.5 > ; A POP is necessary to discard the caller since we will not RET. > XTHL ; Swap HL with (SP), essentially POP+PUSH HL > PUSH D ; push everything: DE, BC, AF > PUSH B > PUSH PSW > LXI H,INTRET ; 71F7 = Pop all, enable interrupts, and RET > PUSH H ; Make next "RET" jump to 71F7. > IN 0xC8 ; Read byte from UART Receive Buffer > LXI H,ParityControl ; FF8D = RS232 parity control byte > ANA M > ;; The above is how the standard Rx handler at 0x6DAC starts. > ;; Below is where things change. > PUSH PSW ; Why this weird PUSH/POP of A? > LXI H,Mapping ; HL=>mapping = [Æ\Ø]Å{æ|ø}å > RxCheckForBrackets: > POP PSW > CMP M ; [\]{|} > JZ RxReplaceWithAccents > INX H > INX H > PUSH PSW > MOV A,M > CPI 0xff > JNZ RxCheckForBrackets > POP PSW > JMP RxDone > RxReplaceWithAccents: > INX H ; ÆØÅæøå > MOV A,M > RxDone: > EI > JMP 0x6dbd ; Jump back into the standard Rx handler. > ;; Note: The next RET will jump to INTRET (71f7) which will > ;; POP all the registers and reenable interrupts before > ;; actually returning. > ;;; This handler is called by the ROM BSOPEN statement (4CCD).;; It replaces > ÆØÅæøå (M100 accents) with [\]{|}.;; Input and output in register C. > OpenHandler: > DI ; Disable interrupts while in RST 7+18h hook > PUSH H > MOV A,C > PUSH PSW > LXI H,RevMapping ; From M100 to ASCII Æ[Ø\Å]æ{ø|å} > OpenCheckForAccents: > POP PSW > CMP M ; ÆØÅæøå > JZ OpenReplaceWithBrackets > INX H > INX H > PUSH PSW > MOV A,M > CPI 0xff > JNZ OpenCheckForAccents > POP PSW > JMP OpenDone > OpenReplaceWithBrackets: > INX H ; [\]{|} > MOV A,M > OpenDone: > MOV C,A > POP H > EI ; All done with handler, reenable interrupts. > RET > > Mapping: ; From ASCII to M100 [Æ\Ø]Å{æ|ø}å > db '[', D0h > db '\\',D4h > db ']', D2h > db '{', D1h > db '|', D5h > db '}', D3h > db FFh > > RevMapping: ; From M100 to ASCII Æ[Ø\Å]æ{ø|å} > db D0h,'[' > db D4h,'\\' > db D2h,']' > db D1h,'{' > db D5h,'|' > db D3h,'}' > db FFh > ;;; In Norway do they prefer Line Feed, Carriage Return instead of CRLF? > MenuText: > db "\tDEFINISION AV KARAKTERSETT\n\r" > db " 1: norsk telcom 2: engelsk telcom\n\r" > db " 3: norsk skriver 4: engelsk skriver\n\r" > db " 5: CR & LF 6: CR\n\r" > db "\t < F8 > MENY\n\r\n" > db " TAST ",D4h,"NSKET KODE\n\r " > ;;; The following variables get set to '*' or '.' to indicate their;;; > status, but they are never used. > RS232HookStatus: > db ". " > PrinterHookStatus: > db ". " > AutoLFStatus: > db "." > > SetupPrinterHook: > LXI H,PrinterHandler > SHLD (PrtrOutVector) > MVI A,'*' > STA (PrinterHookStatus) > RET > > RemovePrinterHook: > LXI H,0x7ff3 > SHLD (PrtrOutVector) > MVI A,'.' > STA (PrinterHookStatus) > RET > ;; Replace ÆØÅæøå (M100 accents) sent to printer with [\]{|};; This presumes > a Norwegian printer. > PrinterHandler: > PUSH H > PUSH B > PUSH PSW > LXI H,RevMapping ; From M100 to ASCII Æ[Ø\Å]æ{ø|å} > PrtrCheckForAccents: > POP PSW > CMP M > JZ PrtrReplaceWithBrackets > INX H > INX H > PUSH PSW > MOV A,M > CPI 0xff > JNZ PrtrCheckForAccents > POP PSW > JMP PrtrDone > PrtrReplaceWithBrackets: > INX H ; [\]{|} > MOV A,M > PrtrDone: > POP B > POP H > RET > NOP > NOP > > ENDP: > ;;; Note: This program relies on RESRAM having been run first;;; to reserve > 512 bytes in the lower RAM area.;;; The guts of RESRAM are: > ;; 160 BH=PEEK(64193) AND 240;; 190 POKE BH*256,2;; 200 POKE 64193,BH+2;; 210 > CALL 32237 > ;;; Open Question:;;;;;; ??? What is the purpose of the OpenHandler? TELECOM > doesn't use;;; BASIC's OPEN when uploading or downloading files. Is this > for;;; programs that do something like OPEN "COM:88N1E" FOR OUTPUT AS #1?;;; > How would it be helpful?;;;;;; The handler seems to get run only when someone > types 'OPEN "FOO";;; FOR INPUT AS #1', but only _once_, not multiple times as > one would;;; expect for converting a filename or buffer.;;;;;; Register C, > the nominal input and output, seems to be set to the;;; file number, which > doesn't make any sense to transliterate.;;; > > > On Sat, Apr 4, 2026 at 7:17 PM B9 <[email protected]> wrote: > >> On Sat, Apr 4, 2026 at 2:48 AM Rune Devik <[email protected]> wrote: >> >> > [...] I find re-implementing code a sure way to actually understand >> what's >> > going on ;) Sorry about that :D >> > >> >> That's the best way to learn. We don't know what it is that we don't >> know. Trying to articulate our thoughts in code can sometimes reveal those >> blindspots. >> >> >> > [...] It still only handles ASCII though and not CP865 correctly so my >> > ÆØÅ's come out a bit funky but I can live with that :) >> > >> >> Leaving the "high ASCII" as is in strings is the correct thing to do. >> When the .DO file is transferred to an M100, it'll show up with the right >> accents. If you want to view M100 files on a modern computer, you'd convert >> them using a tool like iconv. >> >> By the way, the BASIC program is not actually in CP865, but a special >> character set that I do not think anyone knows the correct name for. It was >> used only on the Tandy/Radio-Shack portables, so some people call it the >> Model 100 charset. It appears your "Modell 100" actually uses a slight >> variant, the same as seen on the Tandy 200 (and later on the Tandy 102). >> >> --b9 >> >> P.S. If anyone has knowledge of where the M100 character set came from or >> what it is actually named, I'd like to hear about it! >> >> -- mvh, Rune Devik
