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!
>
>
instal.co
Description: Binary data
instal.asm
Description: Binary data
