• Intellec8/MOD 80 Monitor (1/2)

    From Mr. Emmanuel Roche, France@21:1/5 to All on Tue Aug 31 23:26:45 2021
    ; MOD80MON.ASM
    ; ------------
    ;
    ; Intellec8/MOD 80 Monitor, Version 3.0, 14 April 1975
    ; Intel 98-0007C
    ;
    ; (Retyped by Emmanuel ROCHE.)
    ;
    ; Copyright (C) 1973, 1974, 1975
    ; Intel Corporation
    ; 3065 Bowers Avenue
    ; Santa Clara, California 95051
    ;
    ; <legal command> ::= <assign I/O command>
    ; <BNPF punch command>
    ; <compare command>
    ; <display memory command>
    ; <endfile command>
    ; <fill memory command>
    ; <program execute command>
    ; <hexadecimal arithmetic command>
    ; <load BNPF command>
    ; <move memory command>
    ; <leader command>
    ; <program command>
    ; <read hexadecimal file command>
    ; <substitute memory command>
    ; <transfer command>
    ; <write hexadecimal record command>
    ; <register modify command>
    ;
    ; <assign I/O command> ::= A<logical device>=<physical device>
    ;
    ; <BNPF punch command> ::= B<number>,<number>
    ;
    ; <compare command> ::= C<number>
    ;
    ; <display memory command> ::= D<number>,<number>
    ;
    ; <endfile command> ::= E<number>
    ;
    ; <fill memory command> ::= F<number>,<number>,<number>
    ;
    ; <program execute command> ::= G<number>,<number>,<number>
    ;
    ; <hexadecimal arithmetic command> ::= H<number>,<number>
    ;
    ; <load BNPF command> ::= L<number>,<number>
    ;
    ; <move memory command> ::= M<number>,<number>,<number>
    ;
    ; <leader command> ::= N
    ;
    ; <program command> ::= P<number>,<number>,<number>
    ;
    ; <read hexadecimal file command> ::= R<number>
    ;
    ; <substitute memory command> ::= S<number>
    ;
    ; <transfer command> ::= T<numbr>
    ;
    ; <write hexadecimal record command> ::= W<number>,<number>
    ;
    ; <register modify command> ::= X<register identifier>
    ;
    ; <logical device> ::= console|reader|list|punch
    ;
    ; <physical device> ::= CRT|TTY|PTR|PTP|BATCH|1|2
    ;
    ; <register identifier> ::= A|B|C|D|E|F|H|L|M|P|S
    ;
    ; <number> ::= <hex digit>
    ; <number><hex digit>
    ;
    ; <hex digit> ::= 0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F
    ;
    ; System signs on with <CR><LF><.>

    ver EQU 30 ; Version 3.0

    TITLE ' Intellec8/Mod 80 Monitor, Version 3.0, 14 April 1975 '

    ; I/O device ouput Command port 1 (TTC) bit values
    ;
    ; Bit Rest Mnemonic Description
    ; --- ---- -------- -----------
    ; 0 0 RBIT TTY reader go/no go
    ; 1 0 PCMD PTP go/no go
    ; 2 0 RCMD PTR go/no go
    ; 3 1 DSB PROM enable/disable, DSB=1
    ; 4 0 Data in T/C
    ; 5 0 Data out T/C
    ; 6 0 PBIT 1702 PROM prog. go/no go
    ; 7 0 PBITA 1702A PROM prog. go/no go

    ; I/O device input Status port 1 (TTS) bit values
    ;
    ; Bit Rest Mnemonic Description
    ; --- ---- -------- -----------
    ; 0 1 TTYDA If TTYDA=0 input is ready
    ; 1 1 Overrun error
    ; 2 0 TTYBE If TTYBE=0 output is ready
    ; 3 1 Framing error
    ; 4 1 Parity error
    ; 5 0 PTRDA If PTRDA=1 PTR has char.
    ; 6 1 PRDY If PRDY=1 PTP is ready
    ; 7 Unassigned

    ; I/O device input Status port 5 (CRTS) bit values
    ;
    ; Bit Rest Mnemonic Description
    ; --- ---- -------- -----------
    ; 0 1 CRTDA If CRTDA=0 input is ready
    ; 1 1 Overrun error
    ; 2 0 CRTBE If CRTBE=0 output is ready
    ; 3 1 Framing error
    ; 4 1 Parity error
    ; 5 Unassigned
    ; 6 Unassigned
    ; 7 Unassigned

    ; I/O command constants
    ;
    RBIT EQU 1
    PCMD EQU 2
    RCMD EQU 4
    DSB EQU 8
    PBITA EQU 80H

    ; TTY I/O constants
    ;
    TTI EQU 0 ; TTY Input data port
    TTO EQU 0 ; TTY Output data port
    TTS EQU 1 ; TTY input Status port
    TTC EQU 1 ; TTY ouput Command port
    TTYGO EQU RBIT OR DSB ; Start TTY reader
    TTYNO EQU DSB ; Stop TTY reader
    TTYDA EQU 1 ; Data Available
    TTYBE EQU 4 ; Transmit Buffer Empty

    ; CRT I/O constants
    ;
    CRTI EQU 4 ; CRT Input data port
    CRTO EQU 4 ; CRT Output data port
    CRTS EQU 5 ; CRT input Status port
    CRTDA EQU 1 ; Data Available
    CRTBE EQU 4 ; Transmit Buffer Empty

    ; PTR I/O constants
    ;
    PTRI EQU 3 ; PTR Input data port (not inverted)
    PTRS EQU TTS ; PTR input Status port
    PTRC EQU TTC ; PTR Output command port
    PTRGO EQU RCMD OR DSB ; Start reader
    PTRNO EQU TTYNO ; Stop reader
    PTRDA EQU 20H ; PTR Data Available

    ; PTP I/O constants
    ;
    PTPO EQU 3 ; PTP Output data port
    PTPS EQU TTS ; PTP input Status port
    PTPC EQU TTC ; PTP output Command port
    PRDY EQU 40H ; Punch ReaDY status
    PTPGO EQU PCMD OR DSB ; Start punch
    PTPNO EQU TTYNO ; Stop punch

    ; PROM programmer I/O constants
    ;
    PAD EQU 2 ; PROM ADdress output port
    PDO EQU PTPO ; PROM Data Output port
    PDI EQU 2 ; PROM Data Input port
    PROMC EQU TTC ; Programming pulse output port
    PROGO EQU PBITA ; Start programming
    PRONO EQU 0 ; Stop programming
    ENB EQU 0 ; ENaBle programmer

    ; Conditional assembly switches
    ;
    false EQU 0
    true EQU NOT false

    debug EQU false ; Debug mode -
    ; Modify certain code sections,
    ; so that Version 2.0 may be
    ; debugged by Version 1.0.

    ; Global constants
    ;
    TOUT EQU 250 ; 250 ms. counter for reader TimeOUT
    LDLY EQU 20 ; Counter for 20 ms. DeLaY

    IF debug
    DLY EQU 111 ; Counter for 1.0 ms. delay in RAM
    ENDIF

    IF NOT debug
    DLY EQU 84 ; Counter for 1.0 ms. delay in PROM
    ENDIF

    ; ASCII characters used
    ;
    CR EQU 0DH ; Carriage Return
    LF EQU 0AH ; Line Feed
    space EQU 20H ; ' '
    dollar EQU 24H ; '$' PROM error flag
    star EQU 2AH ; '*'
    comma EQU 2CH ; ','
    dash EQU 2DH ; '-'
    dot EQU 2EH ; '.'
    zero EQU 30H ; '0'
    colon EQU 3AH ; ':' HEX file 1st char
    equal EQU 3DH ; '='
    upA EQU 41H ; 'A'
    upB EQU 42H ; 'B'
    upF EQU 46H ; 'F'
    upN EQU 4EH ; 'N'
    upP EQU 50H ; 'P'
    upX EQU 58H ; 'X'

    ; Macro definition
    ;
    fetch MACRO value ;; Fetch the address
    lxi h,value ;; of a value
    dad sp ;; in the stack.
    ENDM

    ; I/O status byte masks and values
    ;
    CMSK EQU 11111100B ; Mask for Console I/O
    RMSK EQU 11110011B ; Mask for Reader input
    PMSK EQU 11001111B ; Mask for Punch output
    LMSK EQU 00111111B ; Mask for List output

    CTTY EQU 00000000B ; Console I/O = TTY
    CCRT EQU 00000001B ; Console I/O = CRT
    BATCH EQU 00000010B ; Batch mode -
    ; input = reader, output = list.
    CUSE EQU 00000011B ; User-defined console I/O

    RTTY EQU 00000000B ; Reader = TTY
    RPTR EQU 00000100B ; Reader = PTR
    RUSE1 EQU 00001000B ; User-defined Reader (1)
    RUSE2 EQU 00001100B ; User-defined Reader (2)

    PTTY EQU 00000000B ; Punch = TTY
    PPTP EQU 00010000B ; Punch = PTP
    PUSE1 EQU 00100000B ; User-defined Punch (1)
    PUSE2 EQU 00110000B ; User-defined Punch (2)

    LTTY EQU 00000000B ; List = TTY
    LCRT EQU 01000000B ; List = CRT
    LUSE1 EQU 10000000B ; List = LPT
    LUSE2 EQU 11000000B ; User-defined List

    ; User-defined device entry points
    ;
    CILOC EQU 3700H ; User Console Input
    COLOC EQU 3703H ; User Console Output
    R1LOC EQU 3706H ; User Reader (1)
    R2LOC EQU 3709H ; User Reader (2)
    P1LOC EQU 370CH ; User Punch (1)
    P2LOC EQU 370FH ; User Punch (2)
    L1LOC EQU 3712H ; User List (1)
    L2LOC EQU 3715H ; User List (2)
    CSLOC EQU 3718H ; User Console Status

    IF debug
    ORG 800H ; Locate in RAM for debug
    ENDIF

    IF NOT debug
    ORG 3800H ; Locate in top 8 ROMs in 16K
    ENDIF

    ;--------------------------------
    ; Branch table for I/O system

    jmp begin ; Reset entry point
    jmp ci ; Console Input
    jmp ri ; Reader Input
    jmp co ; Console Output
    jmp po ; Punch Output
    jmp lo ; List Output
    jmp csts ; Console input STatuS
    jmp iochk ; I/O system status
    jmp ioset ; Set I/O configuration
    jmp memck ; Compute size of memory

    ;--------------------------------

    ; Pointers to RAM
    ;
    RS1 EQU 8 ; Restart 1 logic

    ; Status byte for I/O system

    IF NOT debug
    iobyt EQU 3 ; Use location 0003H
    ENDIF

    IF debug
    iobyt EQU 4 ; Use location 0004H
    ENDIF

    init EQU 000000B ; Initially,
    ; ------00 Console = TTY,
    ; ----00-- Reader = TTY,
    ; --00---- Punch = TTY,
    ; 00------ List = TTY.

    vers db cr, lf, '8080 V'

    IF NOT debug
    db ver/10+'0','.',ver MOD 10+'0'
    ENDIF

    IF debug
    db 'X.X'
    ENDIF

    Lver EQU $-vers ; Length of sign-on message

    ;--------------------------------
    ; Program entry point
    ;
    ; Compute the top of RAM memory available in this system,
    ; and locate the user register save area, exit template,
    ; and monitor stack at the top of RAM.

    begin: lxi h,iobyt ; Point HL at IOBYT
    mvi m,init ; Initial value of I/O
    mvi l,0ffh ; Find end of memory
    bg0: dcr h
    mov a,m ; Fetch contents of memory
    cma ; Invert it
    mov m,a ; Attempt to write into memory
    cmp m ; Is location Read/Write?
    cma ; Invert again
    mov m,a ; Write data back
    jnz bg0 ; Yes: continue
    inx h ; No: point to first non-RAM location

    IF debug
    mvi h,2 ; Set stack at 200H for debug
    ENDIF

    mvi b,endx-exit ; Move exit template to RAM
    lxi d,endx
    bg1: dcx d
    ldax d
    dcx h
    mov m,a
    dcr b
    jnz bg1
    sphl ; Set stack
    lxi h,0100H
    push h
    mvi h,00h
    push h ; Push registers on stack
    push h
    push h

    IF NOT debug ; If in debug mode, don't set traps
    mvi a,jmp
    sta rs1
    lxi h,restart ; Set up Restart 1 for breakpoint
    shld rs1+1 ; logic.
    ENDIF

    ; Type sign-on
    ;
    lxi h,vers ; Address of message
    mvi d,Lver ; Length of message
    ver0: mov c,m
    inx h
    call co
    dcr d
    jnz ver0

    ; Main command loop
    ;
    ; This loop is the starting point of all command sequences.
    ; In this code, interrupts are enabled, all I/O devices are
    ; initialized, a Carriage Return and Line Feed are typed,
    ; along with the prompt character, '.'. When a character is
    ; entered from the console keyboard, it is checked for validity,
    ; then a branch to the proper processing routine is computed.

    start: ei ; Enable interrupts
    mvi a,ttyno ; Reset TTY, PTR, PTP,
    out ttc ; and PROM programmer.
    call crlf ; Type <CR>,<LF>
    mvi c,dot
    call co ; Output a period
    call ti ; Get a character
    sui upA ; Test for A-X
    jm start ; LT A, error
    cpi upX-upA+1
    jp Ler ; GT X, error
    add a ; * 2
    lxi h,tbl ; Address of table
    add l
    mov l,a ; Compute table address, put in HL
    mov a,m ; Get LSB of address
    inx h ; Point to next address
    mov h,m ; Get MSB of address
    mov l,a ; LSB to A
    mvi c,02h ; C is set for 2-param commands
    pchl ; Branch to routine

    ; Command branch table
    ;
    ; This table contains the addresses of the entry points of
    ; all the command processing routines. Note that an entry to
    ; 'LER' is an error condition, i.e., no command corresponding
    ; to that character exists.

    tbl: dw assign ; A - assign I/O units
    dw bnpf ; B - punch BNPF
    dw comp ; C - compare PROM with memory
    dw disp ; D - display RAM memory
    dw eof ; E - endfile a HEX file
    dw fill ; F - fill memory
    dw goto ; G - go to memory address
    dw hexn ; H - hexadecimal sum and difference
    dw Ler ; I -
    dw Ler ; J -
    dw Ler ; K -
    dw Load ; L - load BNPF tape
    dw move ; M - move memory
    dw null ; N - punch NULLs for leader
    dw Ler ; O -
    dw prog ; P - program a 1702A PROM
    dw Ler ; Q -
    dw read ; R - read HEX file
    dw subs ; S - substitute memory
    dw tran ; T - transfera PROM to memory
    dw Ler ; U -
    dw Ler ; V -
    dw write ; W - write HEX file
    dw x ; X - examine and modify registers

    ;--------------------------------
    ; Process I/O device assignments commands
    ;--------------------------------
    ; This routine maps symbolic device identifiers to bits
    ; in the I/O status byte (IOBYT) to allow for console
    ; modification of system I/O configuration.

    assign: call ti ; Get logical device character
    lxi h,Ltbl ; Address of master table
    mvi c,04h ; Maximum of 4 entries
    as0: cmp m ; Test for identifying character
    inx h
    jz as1 ; Found it
    inx h ; Point to next entry
    inx h
    inx h
    dcr c ; Decrement loop count
    jnz as0 ; Try next entry
    jmp Ler ; No match: error

    as1: mov b,m ; Get select bit mask
    inx h
    mov e,m ; Get physical device table
    inx h
    mov d,m
    xchg
    as2: call ti ; Scan until '=' is found
    cpi equal
    jnz as2
    as3: call ti ; Deblank
    cpi space
    jz as3
    mvi c,04h ; Set table length
    as4: ; Index through physical unit table
    cmp m ; Compare device char. with legal values
    inx h
    jz as5 ; Return with HL -> device select bits
    inx h
    dcr c
    jnz as4 ; Continue lookup
    jmp Ler ; Error return

    as5: call ti
    cpi cr
    jnz as5 ; Loop until CR encountered
    mov c,m ; Get device select bits
    lxi h,iobyt ; Get I/O status
    mov a,m
    ana b ; Clear field
    ora c ; Set new status
    mov m,a ; Return to memory
    jmp start

    ;--------------------------------
    ; Punch a BNPF tape
    ;
    ; This routine expects 2 hexadecimal parameter to
    ; be entered from the keyboard, and interprets them
    ; as the bounds of a memory area to be punched on
    ; the assigned punch device in BNPF format. The tape
    ; produced is formatted with 4 BNPF 8-bit words per
    ; line, with a reference address in decimal preceding
    ; each line.

    bnpf: call expr ; Get 2 addresses
    call crlf
    call lead
    pop d ; Get high address
    pop h ; Get low address
    bn0: push h
    push d
    call peol ; Punch CR,LF
    mvi b,space ; Zero suppression character
    lxi d,10000 ; Punch address in decimal
    call digit
    lxi d,1000
    call digit
    lxi d,100
    call digit
    mvi e,10
    call digit
    mvi e,1
    mvi b,zero ; Force at least 1 zero
    call digit
    mvi c,space
    call po
    pop d
    pop h
    bn1: call encode ; Encode a memory byte into BNPF
    call hilo
    jc null ; All done, punch trailer and return
    mov a,l
    ani 03h ; Punch CR,LF,Address on multiple of 4
    jnz bn1
    jmp bn0

    ;--------------------------------
    ; Compare PROM with memory
    ;
    ; This routine expects 1 hexadecimal parameter which
    ; it interprets as a memory address. The routine
    ; compares the PROM in the Front Panel socket with a
    ; 256-byte area of memory pointed to be the input parameter.
    ; All differences between the PROM and the memory are
    ; are displayed in the following format:
    ;
    ; <mem address> <mem contents> <corresponding PROM contents>

    comp: dcr c
    call expr ; Get one address
    pop h ; Load HL
    mvi e,00h ; Count/PROM address
    cm0: mvi a,enb
    out promc ; Enable PROM programmer
    mov a,e ; Set PROM address
    cma ; Invert address
    out pad
    call delay ; Wait for imm6-76 board to latch data
    in pdi ; Get PROM data
    cma
    cmp m ; Compare with memory
    jz cm1 ; Compare
    push psw
    call crlf
    call Ladr ; Print memory address
    call blk
    mov a,m
    call Lbyte ; Print RAM data
    call blk
    pop psw ; Retrieve data
    call Lbyte ; Print PROM data
    cm1: inx h
    inr e ; Adjust PROM address
    jnz cm0
    jmp start

    ;--------------------------------
    ; Display memory in hex on console device
    ;
    ; This routine expects 2 hexadecimal parameters specifying
    ; the bounds of a memory area to be displayed on the
    ; console device. The memory area is displayed 16 bytes
    ; per line, with the memory address of the first byte
    ; printed for reference. All lines are blocked into integral
    ; multiples of 16 for clarity, so that the first and last
    ; lines may be less than 16 bytes, in order to synchronize
    ; the display.

    disp: call expr ; Get 2 addresses
    pop d ; Get high address
    pop h ; Get low address
    di0: call crlf
    call Ladr ; Print memory address
    di1: call blk ; Print space
    mov a,m
    call Lbyte ; Print data
    call hilo ; Test for completion
    jc start
    mov a,l
    ani 00001111B ; Print CR,LF,Address on multiple of 16
    jnz di1
    jmp di0

    ;--------------------------------
    ; End of file command
    ;
    ; This routine produces a termination record which properly
    ; completes a HEX file created by 'W' commands. It
    ; expects 1 hexadecimal parameter which is encoded in the
    ; termination record in the load address field, and specifies
    ; the entry point of the file created. A subsequent 'R' command
    ; will load the file created and transfer control to the
    ; entry point specified if it is non-zero.

    eof: dcr c ; Get 1 parameter
    call expr
    call peol ; Punch CR,LF
    mvi c,colon
    call po ; Punch HEX file 1st char.
    xra a ; Clear checksum
    mov d,a
    call pbyte ; Output record length
    pop h
    call padr ; Punch execution address
    mvi a,01h ; Record type 1
    call pbyte
    xra a
    sub d ; Output checksum
    call pbyte
    jmp null ; Punch trailer and return

    ;--------------------------------
    ; Fill RAM memory block with constant
    ;
    ; The routine expects 3 hexadecimal parameters. The
    ; first and second (16 bits) are interpreted as the bounds
    ; of a memory area to be initialized to a constant value.
    ; The third parameter (8 bits) is that value.

    fill: inr c ; Get 3 parameters
    call expr
    pop b ; Get data in C
    pop d ; Get high address
    pop h ; Get low address
    fi0: mov m,c ; Store constant in memory
    call hilo ; Test for completion
    jnc fi0 ; Continue looping
    jmp start

    ;--------------------------------
    ; Go to <address>, optionally set breakpoints
    ;
    ; The G command is used for transferring control from
    ; the Monitor to a user program. It has several modes
    ; of operation.
    ;
    ; If one hexadecimal parameter is entered, it is interpreted
    ; as the entry point of the user program and a transfer to
    ; that location is executed.
    ;
    ; If additional (up to 2) parameters are entered, these
    ; are considered 'breakpoints', i.e., locations where
    ; control is to be returned to the Monitor, if they are
    ; encountered.
    ;
    ; If the first parameter is not entered, the stored value
    ; of the user's Program Counter (register P) is used as
    ; the user program entry point.

    goto: call pchk ; Get a character
    jc go3 ; CR entered: exit
    jz go0 ; Don't modify PC
    call exp ; Get new PC value
    pop d
    fetch Ploc
    mov m,d ; Store modified PC in RAM
    dcx h
    mov m,e
    mov a,b ; Retrieve delimiter character
    cpi cr
    jz go3 ; No traps to be set
    go0: mvi d,02h ; Set maximum of 2 traps
    fetch Tloc
    go1: push h ; Save address of trap area
    mvi c,01h
    call expr ; Get a trap address
    mov e,b ; Save delimiter character
    pop b ; Get address in BC
    pop h
    mov a,b
    ora c
    jz go2 ; Don't allow a trap at 0
    mov m,c ; Put trap address away
    inx h
    mov m,b
    inx h
    ldax b ; Fetch opcode
    mov m,a ; Put in trap area
    inx h
    mvi a,RST ; Restart 1
    stax b ; Set trap in memory
    go2: mov a,e ; Test delimiter character
    cpi cr
    jz go3 ; All done
    dcr d
    jnz go1 ; Go get newt trap
    go3: call crlf
    fetch 8
    pchl ; Take the branch

    ;--------------------------------
    ; Compute hexadecimal sum and difference
    ;
    ; This routine expects 2 hexadecimal parameters.
    ; It computes the sum and difference of the 2 values
    ; and displays them on the console device as follows:
    ;
    ; <p1+p2> <p1-p2>

    hexn: call expr ; Get 2 numbers
    pop d
    pop h
    call crlf
    push h
    dad d ; Compute HL+DE
    call Ladr ; Display sum
    call blk ; Type a space
    pop h
    mov a,l ; Compute HL-DE
    sub e
    mov l,a
    mov a,h
    sbb d
    mov h,a
    call Ladr ; Display difference
    jmp start

    ;--------------------------------
    ; Load a BNPF tape into RAM memory
    ;
    ; This routine expects 2 hexadecimal parameters, and
    ; interprets them as bounds of a memory area to be
    ; loaded by BNPF data to be read from the reader.
    ; It is assumed that enough data is available in the
    ; tape to be read to satisfy the memory bounds entered.
    ; If end of tape is encountered before the memory bounds
    ; are satisfied, this routine will terminate on an error
    ; condition (see RIX), but all data read before the end
    ; of tape was encountered will be loaded.

    Load: call expr ; Get 2 addresses
    call crlf
    pop d ; Get high address
    pop h ; Get low address
    Lo0: call decode ; Convert BNPF, store in memory
    call hilo ; Test for completion
    jnc Lo0 ; Keep going
    jmp start

    ;--------------------------------
    ; Move a block of memory
    ;
    ; This routine expects 3 hexadecimal parameters from the
    ; console. The first and second parameters are the bounds of
    ; the memory area to be moved, the third parameter is the
    ; starting address of the destination area.

    move: inr c ; Get 3 addresses
    call expr
    pop b ; Destination
    pop d ; Source end
    pop h ; Source begin
    mv0: mov a,m ; Get a data byte
    stax b ; Store at destination
    inx b ; Move destination pointer
    call hilo ; Test for completion
    jnc mv0
    jmp start

    ;--------------------------------
    ; Punch leader or trailer
    ;
    ; This routine punches 60 NULL ASCII characters on the
    ; device assigned as the punch. It is branched to by
    ; the 'B' and 'E' commands, as well as being invoked
    ; by the 'N' command.

    null: call lead
    jmp start

    ;--------------------------------
    ; Program a 1702A PROM with fast algorithm
    ; (20.46 to 409.6 seconds)
    ;
    ; This routine expects 3 hexadecimal parameters from the
    ; console. The first and second are the bounds of a
    ; memory area to be reproduced in the 1702A PROM in the
    ; Front Panel socket. The third parameter is the address
    ; in the PROM (8 bits) where the duplication is to commence.
    ; The algorithm used in this routine takes advantage of the
    ; fact that most PROMs may be programmed in a small fraction
    ; of the time that it would take under worst case conditions,
    ; therefore greatly reducing programming time for most PROMs.
    ; The wide variation in times quoted is due to the allowable
    ; range between best and worst case programming times.

    prog: inr c
    call expr ; HL = top after return
    call crlf
    pop b ; C <- PROM address
    pop d ; High address
    pop h ; Low address
    pr0: mvi a,enb
    out promc ; Enable PROM programmer
    mov a,c
    out 0ffh ; Display address
    cma
    out pad ; PROM address
    in pdi
    cma
    cmp m
    jz pr4 ; Don't have to program the loc
    mvi b,-16 ; Set max tries = 16
    pr1: call pgrm ; Pulse and delay 16 ms.
    in pdi ; Read value
    cma
    cmp m ; Compare with desired
    jz pr2 ; Got it, now pulse 4*N more times
    inr b ; Increment count
    jnz pr1 ; Keep going
    push b ; Error out
    mvi c,dollar
    call co ; Print error flag
    call blk
    pop b ; Restore PROM address in C
    mov a,c
    call Lbyte ; Display it
    jmp Ler ; Error exit
    pr2: mov a,b ; Move count residue to A
    adi 17 ; Actual count of tries required
    add a ; Count = count * 2
    add a ; Count = count * 4
    mov b,a
    pr3: ; Overprogram 4*N times
    call pgrm
    dcr b
    jnz pr3
    pr4: inr c ; Increment PROM address
    call hilo
    jnc pr0 ; Continue
    jmp start ; All done

    ;--------------------------------
    ; Read HEX file routine
    ;
    ; This routine reads a HEX file from the assigned reader
    ; device and loads it into memory. One hexadecimal
    ; parameter is expected. This parameter is a bias address
    ; to be added to the memory address of each data byte
    ; encountered. In this way, HEX files may be loaded into
    ; memory in areas others than that for which they were
    ; assembled or compiled. All records read are checksummed
    ; and compared against the checksum in the record. If a
    ; checksum error (or tape read error) occurs, the routine
    ; takes an error exit. Normal loading is terminated when
    ; a record of length 0 is encountered. This is interpreted
    ; as an end-of-file record, and the load address field of
    ; that record is taken to be the entry point of the program
    ; (if it is non-zero).

    read: dcr c ; Get 1 address
    call expr
    red0: pop h ; Get bias address
    push h
    call rix
    mvi b,colon
    sub b
    jnz red0 ; Scan to record mark
    mov d,a ; Clear checksum
    call byte
    jz red2 ; Zero record length, all done
    mov e,a ; E <- record length
    call byte ; Get MSB of load address
    push psw ; Save it
    call byte ; Get LSB of load address
    pop b ; Retrieve MSB, put in B
    mov c,a
    dad b ; Bias address + load address -> HL
    call byte ; Record type
    red1: call byte ; Read data
    mov m,a ; Put in memory
    inx h
    dcr e
    jnz red1 ; Loop until done
    call byte ; Read checksum
    jnz Ler ; Checksum error
    jmp red0 ; Get another record

    red2: call byte ; Get MSB of transfer address
    mov h,a
    call byte
    mov l,a
    ora h
    jz red3 ; If transfer address=0, return to KB
    pchl

    red3: pop h
    jmp start

    ;--------------------------------
    ; Substitute memory contents routine
    ;
    ; This routine expects 1 parameter from the console,
    ; followed by a space. The parameter is interpreted
    ; as a memory location, and the routine will display
    ; the contents of that location, followed by a dash (-).
    ; To modify memory, type in the new data followed by
    ; a space or a Carriage Return. If no modification of
    ; the location is required, type only a space or
    ; Carriage Return. If a space was last typed, the next
    ; memory location will be displayed and modification
    ; of it is allowed. If a Carriage Return was entered,
    ; the command is terminated.

    subs: dcr c
    call expr ; Get 1 address
    call p2c
    jc Ler
    pop h
    su0: mov a,m
    call Lbyte ; Display data
    mvi c,dash
    call co
    call pchk
    jc start ; CR entered, return to command mode
    jz su1 ; Space entered, space by
    push h ; Save memory address
    call exp ; Get new value
    pop d ; E = value
    pop h ; Restore memory address
    mov m,e ; Store new value
    mov a,b ; Test delimiter
    cpi cr
    jz start ; CR entered after last substitution
    su1: inx h
    jmp su0

    ;--------------------------------
    ; Transfer contents of a PROM to memory
    ;
    ; This routine expects 1 hexadecimal parameter which is
    ; interpreted as the location in memory where a copy of
    ; the PROM in the Front Panel socket is to be stored.
    ; This copy is always 256 bytes in length.

    tran: dcr c
    call expr ; Get 1 address
    pop h ; HL = mem adr
    mvi e,00h ; Count/PROM address
    tr0: mvi a,enb
    out promc ; Enable PROM programmer
    mov a,e
    cma ; Invert address
    out pad ; Set PROM address
    call delay ; Wait for imm6-76 board to latch data
    in pdi ; Get PROM data
    cma
    mov m,a ; Put in memory
    inx h ; Bump memory pointer
    inr e ; Bump PROM pointer
    jnz tr0 ; Get another byte
    jmp start

    ;--------------------------------
    ; Write HEX file routine
    ;
    ; This routine expects 2 hexadecimal parameters which are
    ; interpreted as the bounds of a memory area to be encoded
    ; into HEX file format, and punched on the assigned punch
    ; device.

    write: call expr ; Get 2 addresses
    call crlf
    pop d ; Get high address
    pop h ; Get low address
    wri0: mov a,l
    adi 16
    mov c,a
    mov a,h
    aci 00h
    mov b,a
    mov a,e
    sub c
    mov c,a
    mov a,d
    sbb b
    jc wri1 ; Record length = 16
    mvi a,16
    jmp wri2

    wri1: mov a,c ; Last record
    adi 17
    wri2: ora a
    jz start
    push d ; Save high address
    mov e,a ; E = length
    mvi d,00h ; Clear checksum
    call peol ; Punch CR,LF
    mvi c,colon
    call po
    mov a,e
    call pbyte ; Punch length
    call padr ; Punch address
    xra a
    call pbyte ; Punch record type
    wri3: mov a,m
    inx h
    call pbyte ; Punch data
    dcr e ; Decrement length
    jnz wri3 ; Continue looping
    xra a
    sub d
    call pbyte ; Punch checksum
    pop d ; Restore high address
    jmp wri0

    ;--------------------------------
    ; Examine and modify CPU registers
    ;
    ; This routine allows the operator to examine and/or
    ; modify the contents of the user program's registers.
    ; The register values were stored as a result of a
    ; previous breakpoint, and will be restored to the
    ; user program during a subsequent 'G' command.

    x: call ti ; Get register identifier
    lxi h,actbl ; Point to access table
    cpi cr
    jz x6 ; Full register display
    x0: cmp m
    jz x1
    push psw ; Save the character
    mov a,m
    ora a ; Test for end of table
    jm Ler
    inx h
    inx h
    inx h
    pop psw
    jmp x0

    x1: call blk
    x2: inx h
    mov a,m ; Displacement
    xchg ; Save HL in DE (HL = pointer to ACTBL)
    mov l,a
    mvi h,00H
    dad sp
    xchg ; Restore HL
    inx h
    mov b,m ; Precision
    inx h ; Point at next register identifier
    ldax d ; 8/16-bit display and modification
    call Lbyte ; MSB of 16-bit reg., all of 8-bit reg.
    dcr b
    jz x3 ; 8-bit display
    dcx d
    ldax d
    call Lbyte ; LSB of 16-bit reg.
    x3: inr b
    mvi c,dash
    call co
    call pchk ; Skip if null entry
    jc start ; CR entered, return to command mode
    jz x5
    push h ; Save pointer to ACTBL
    push b ; Save precision
    call exp ; Get new reg value
    pop h
    pop psw ; A = precision
    push b ; B = delimiter char
    push psw ; A = precision
    mov a,l
    stax d ; Store LSB in register area
    pop b ; Retrieve precision
    dcr b
    jz x4 ; 8 bits only
    inx d
    mov a,h
    stax d ; Store MSB in register area
    x4: pop b ; Retrieve delimiter char
    pop h
    x5: mov a,m ; Test for end of table
    ora a
    jm start
    mov a,b ; Test delimiter
    cpi cr
    jz start
    jmp x2

    x6: ; Full register display
    call crlf
    x7: call blk ; Output a space
    mov a,m ; Get the character
    inx h ; Point at displacement
    ora a ; Set condition codes
    jm start ; All done
    mov c,a
    call co ; Print character
    mvi c,equal
    call co ; Print equal sign
    mov a,m ; Fetch displacement
    inx h ; Point at precision
    xchg ; Save HL in DE
    mov l,a
    mvi h,00h
    dad sp ; Compute address of value
    xchg ; HL = current table address
    ; DE = memory address
    mov b,m ; Fetch precision
    inx h ; Point to next display
    ldax d ; Get LSB of data
    call Lbyte ; Display it
    dcr b
    jz x7 ; 8-bit precision, all done
    dcx d ; Point to MSB of 16-bit value
    ldax d ; Fetch it
    call Lbyte ; Display it
    jmp x7 ; Continue

    ;--------------------------------
    ; Error exit
    ;
    ; This abnormal exit is executed for all Monitor error
    ; conditions. The Stack Pointer value is recomputed
    ; because of the unknown state of the processor
    ; as the result of a command or data error.

    Ler: call MemSiz ; Compute top of memory
    lxi d,-8
    dad d
    sphl ; Reset Stack Pointer on error return
    mvi c,star
    call co
    jmp start

    ;--------------------------------
    ; Subroutines
    ;--------------------------------
    ; Print a blank

    blk: mvi c,space

    ; - - - - - - - - - - - - - - - -
    ; Externally-referenced routine
    ;
    ; Console Output code, value expected in C
    ; A, Flags, C modified
    ; Stack usage: 2 bytes

    co: lda iobyt ; Get status byte
    ani LOW NOT Cmsk ; Get console bits
    jnz co0 ; Test for CRT
    TTYout: in tts ; Console = TTY
    ani ttybe
    jnz TTYout ; Loop until ready
    mov a,c
    cma
    out tto ; Output character
    ret ; Return

    co0: cpi ccrt ; Console = CRT?
    jnz co1 ; Test for batch
    CRTout: in crts ; Console = CRT
    ani crtbe
    jnz CRTout ; Loop until ready
    mov a,c
    cma
    out crto
    ret

    co1: cpi batch
    jz lo ; Batch mode, output = list
    jmp coloc ; Branch to user console output

    ;--------------------------------
    ; Read 2 ASCII characters, decode into 8 bits binary

    byte: call rix ; Read char from tape
    call nibble ; Convert ASCII to hex
    rlc ; Shift 4 places
    rlc
    rlc
    rlc
    mov c,a
    call rix
    call nibble ; Get lower nibble
    ora c
    mov c,a
    add d ; Update checksum
    mov d,a
    mov a,c
    ret ; Return

    ;--------------------------------
    ; Externally-referenced routine
    ;
    ; Console Input code, value returned in A
    ; A, Flags modified
    ; Stack usage: 2 bytes

    ci: lda iobyt ; Get status byte
    ani LOW NOT Cmsk ; Get console bits
    jnz ci1 ; Test for CRT
    ttyin: in tts ; TTY Status port
    ani ttyda ; Check for Data Available
    jnz ttyin
    in tti ; Read the character
    ci0: cma
    ret ; Return

    ci1: cpi ccrt ; Console = CRT?
    jnz ci2 ; Test for batch
    crtin: in crts ; CRT Status port
    ani crtda ; Check for Data Available
    jnz crtin ; Not ready: continue looping
    in crti ; Read the character
    jmp ci0

    ci2: cpi batch
    jz ri ; Batch mode, input = Reader
    jmp ciloc ; Console = user device

    ;--------------------------------
    ; Convert 4-bit value to ASCII character
    ; Input = 0-0FH
    ; Output = 30H-39H, 41H-46H (0-9, A-F)

    conv: adi 10010000B ; Set up A so that A-F cause Carry
    daa
    aci 01000000B ; Add in Carry and adjust upper nibble
    daa
    mov c,a
    ret ; Return

    ;--------------------------------
    ; Type Carriage Return and Line Feed on console

    crlf: mvi c,cr ; <CR>
    call co
    mvi c,lf ; <LF>
    jmp co

    ;--------------------------------
    ; Externally-referenced routine
    ;
    ; Console input STatuS code
    ; A, Flags modified
    ; Stack usage: 2 bytes

    csts: lda iobyt ; Get status byte
    ani LOW NOT Cmsk ; Console = TTY?
    jnz cs0 ; Console = CRT
    in tts ; Get TTY Status
    jmp cs1

    cs0: cpi ccrt
    jnz cs3
    in crts ; Get CRT Status
    cs1: ani ttyda
    mvi a,false ; Return FALSE if no Data Available
    cs2: rnz
    cma
    ret ; Return

    cs3: cpi batch
    mvi a,true
    jz cs2
    jmp CSloc

    ;--------------------------------
    ; Read BNPF tape record, build byte, store in memory.
    ; If error, abort command.

    decode: call rix ; Read tape
    cpi upB ; Scan for 'B'
    jnz decode
    mvi m,01h ; Initialize memory
    dc0: call rix ; Get data
    cpi upN ; Check for 'N'
    jnz dc2 ; No: check for 'P'
    ; Carry = 0
    dc1: mov a,m ; Shift in data bit
    ral
    mov m,a
    jnc dc0 ; If Carry is set, 8-bits read
    call rix ; Test for required 'F'
    cpi upF
    jnz Ler
    ret ; Return

    dc2: adi -upP
    jnz Ler ; Error
    jmp dc1 ; Carry is set

    ;--------------------------------
    ; 1.0 ms. delay

    delay: push b
    mvi b,dly
    dl0: dcr b
    jnz dl0
    pop b
    ret ; Return

    ;--------------------------------

    [continued in next message]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr. Emmanuel Roche, France@21:1/5 to All on Tue Sep 14 06:51:35 2021
    As usual, "the Devil is in the details". Many thanks for the persons who wrote me (Yes, I am still alive!) and especially to the one (Hello, Dwight!) who found *ONE* character wrong!

    In 1978, Intel was naming those "documents", so change the line "Intel 98-0007C" to "Intel document 98-0007C" (later, they changed the "-" into another "0").

    Several of my correspondents noticed a problem with the word "file". Indeed, this Monitor obliges the operator to produce, manually, an "end of file" (called a "Termination Record" in others papers) after producing (one or more) HEX "records", exactly
    like CP/M's ASCII files need a CP/M "End-Of-File" character. So, change the summary of the E, R and W commands likewise:

    <end of HEX file command>
    <read HEX file command>
    <write HEX record command>

    <end of HEX file command> ::= E<number>
    <read HEX file command> ::= R<number>
    <transfer command> ::= T<number>
    <write HEX record command> ::= W<number>,<number>

    (...) DSB PROM enable/DiSaBle, DSB=1

    (...) PRDY If PRDY=1 PTR is ready

    PTRC EQU TTC ; PTR output Command port

    (command branch table)

    B - punch BNPF tape
    E - end of HEX file
    T - transfer a PROM to memory
    W - write HEX record

    ; End of HEX file command

    ; Write HEX record routine

    ; into HEX record format, (...)

    Ladr: the last instruction (Jmp Lbyte) jumps... to the next byte!

    Lbyte: if the HXD routine was following "inline", there would be no need to jump to it...

    Padr: the last instruction (Jmp Pbyte) jumps... to the next byte!

    ( Exit code template)

    ; db SPU SPHL

    Conclusion: So, if you are still using an Intellec8/MOD 80, you can improve this 1975 Monitor! (I was told that several persons want to use this Monitor with modern Do-It-Yourself CP/M micros, just for the fun of playing with paper tapes! BNPF tapes,
    however, have much less success...)

    "If debugging is the process of removing software bugs, then programming must be the process of putting them in." Edsger W. Dijkstra

    Yours Sincerely,
    Mr. Emmanuel Roche, France

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mr. Emmanuel Roche, France@21:1/5 to All on Tue Sep 14 11:38:15 2021
    Eagle-eyed Dwight found another improvement. (With friends like him, I have nothing to do!)

    ; TEST FOR NULL INPUT PARAMETER

    0100 CD3412 PCHK: CALL TI ; GET A CHARACTER
    0103 FE20 P2C: CPI SPACE
    0105 C8 RZ
    0106 FE2C CPI COMMA
    0108 C8 RZ
    0109 FE0D CPI CR
    010B 37 STC
    010C 3F CMC
    010D C0 RNZ
    010E 37 STC
    010F C9 RET

    He fells that the code, after CPI CR, is repetitive: there are two STCs... (Yes, this is code written by Intel! The creators of this microprocessor...)

    So, he suggests:

    0110 FE0D CPI CR
    0112 37 STC
    0113 C8 RZ
    0114 3F CMC
    0115 C9 RET

    which is one byte shorter.

    So, overal, this is already 10 bytes shorter, and most people will not need the BNPF tape routines!

    (I was forgetting: in English, that means: if CR then Z flag = 1 & Carry = 1. (Previously, if space then Z flag = 1 & Carry = 0. If comma then Z flag = 1 & Carry = 0.) Else, if none of the 3 characters, then Z flag = 0 & Carry = 0.)

    As you can see, it is quite fun to debug 1975 code! Many thanks, Dwight!

    Yours Sincerely,
    Mr. Emmanuel Roche, France

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From dott.Piergiorgio@21:1/5 to France on Fri Sep 24 11:12:23 2021
    On 14/09/21 20:38, Mr. Emmanuel Roche, France wrote:
    Eagle-eyed Dwight found another improvement. (With friends like him, I have nothing to do!)

    why not working on the ALGOL-M retyping ? ;)

    Best regards from Italy,
    dott. Piergiorgio.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)