Thank you, you are correct, Rune. I had missed that those variables are just a continuation of the menu text. I hadn’t actually run the program, just examined it and the ROM you shared with us in a disassembler.
I tried replacing Virtual T’s “M102/M102rom.bin” file with the Norwegian ROM and... it works! Or at least, it seems to. The zeroes have dots in them instead of slashes and the keys to the right of L are ø and æ. The only thing that confuses me is that the key to the right of P shows ȧ and I have to use CODE+1 to get å. Is that the way it is on the actual Televerket M100? [image: Virtual T running Televerket Modell 100 ROM] Ken, what’s the best way to switch easily between ROMs which can run on otherwise identical Virtual T machines? I’m pretty sure the British M100 ROM could work just as easily. The NEC PC-8201 (not 8201*A*) and the Japanese Kyotronic-85 would be nice to have as options in Virtual T, too. —b9 On Sun, Apr 5, 2026 at 9:29 AM Rune Devik <[email protected]> wrote: > 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 >
