mkweb

PDP-8 Emulator written in Javascipt with HTML5 Canvas based frontend.

/ This program attempts to mimic the functionality of wozmon on the Apple I

BUFINIT=6777

*10
HEAD,   BUFINIT
TAIL,   BUFINIT
MSGPTR, WELMSG-1

*20
ADDR,   0
STADDR, 0
STDATA, 0
LSTADR, 0
BUFRST, BUFINIT
MSGRST, WELMSG-1

NL,     12              / ASCII New Line
BSLSH,  134             / ASCII Back Slash
COLON,  72              / ASCII Colon
SPACE,  40              / ASCII Space
DOT,    56              / ASCII Period
R,      122             / ASCII 'R'
CA8,    7710            / -(ASCII 8)
CA0,    7720            / 000 000 110 000 > 111 111 001 111 > 111 111 010 000 > 7720

PUTNM,  0               / Put number stub. Allows calling from any page
        JMP I PUTNMA    / Jump indirectly to put number address
PUTNMA, PUTNMR

GETNM,  0               / Get number stub. Allows calling from any page
        JMP I GETNMA    / Jump indirectly to get number routine address
GETNMA, GETNMR

PUTCH,  0
        TSF             / Skip if teleprinter flag set
        JMP .-1         / Else jump back and loop
        TLS             / Transfer char in AC, print, clear flag
        JMP I PUTCH     / Return from subroutine

GETCH,  0
        KSF             / Skip if reader flag is set (meaning there is a char available)
        JMP .-1         / Else jumpback and wait
        KRB             / Clear AC, load char, clear flag
        JMP I GETCH     / Return from subroutine

RESET,  0               / Reset subroutine
        CLA             / Clear AC
        TAD BUFRST      / Load starting address of buffer
        DCA HEAD        / Store it in HEAD
        TAD BUFRST      / Load starting address of buffer
        DCA TAIL        / Store it in TAIL
        JMP I RESET     / Return from subroutine

CMD,    0               / Command subroutine dispatches the correct subcommand routine based on the command character
        TAD TAIL        / Load TAIL location into AC
        CMA IAC         / Complement and increment to form two's complement
        TAD HEAD        / Add HEAD location to AC
        SMA             / Skip on -AC, meaning we have more characters in buffer
        JMP READ        / Read is the default action
        
        CLA
        TAD I HEAD      / Load command char into AC
        DCA CDAT        / Save it temporarily

        TAD DOT         / Load value of ascii period
        CMA IAC         / Complement and increment AC to form two's complement
        TAD CDAT        / Add character value
        SNA             / Skip if AC != 0 (not a '.')
        JMP RANGE       / Jump to range command routine

        CLA             / Clear AC
        TAD COLON       / Load value of ascii colon
        CMA IAC         / Complement and increment to form two's complement
        TAD CDAT        / Add character value
        SNA             / Skip if AC != 0 (not a ':')
        JMP WRITE       / Jump to write command routine

        CLA             / Clear AC
        TAD R           / Load value of ascii 'R'
        CMA IAC         / Complement and increment to form two's complement
        TAD CDAT        / Add character value
        SNA             / Skip if AC != 0 (not a 'R')
        JMP RUN       / Jump to run command routine

        JMP ERROR       / Jump to error routine if command not found
        / JMP I CMD       / Return from subroutine
CDAT,   0

READ,   CLA
        TAD STADDR
        JMS PUTNM
        CLA
        TAD COLON
        JMS PUTCH
        CLA
        TAD SPACE
        JMS PUTCH
        CLA
        TAD STDATA
        JMS PUTNM
        JMP I CMD

RANGE,  JMP I RANGEA
RANGEA, RANGER

WRITE,  CLA             / Clear AC
        TAD TAIL        / Load TAIL location into AC
        CMA IAC         / Complement and increment to form two's complement
        TAD HEAD        / Add HEAD location to AC
        SMA             / Skip on -AC, meaning we have more characters in buffer
        JMP ENDWR       / Jump to end of write
        JMS GETNM       / Get write data from command
        DCA I ADDR      / Store new data at address
        TAD SPACE       / Add ascii space value
        CMA IAC         / Complement and increment to form two's complement
        TAD I HEAD      / Add HEAD
        SZA             / Skip if char is space
        JMP ENDWR       / Jump to end of write
        TAD ADDR        / Load address
        IAC             / Increment it
        DCA ADDR        / Store incremented address
        JMP WRITE+1     / Jump back to write next address

ENDWR,  CLA CMA         / Form a -1 in AC
        TAD HEAD        / Decrement HEAD
        DCA HEAD        / Store it
        JMP READ       / Return from command routine

RUN,    CLA CLL         / Clear AC and Link
        JMP I LSTADR    / Jump to last address

ERROR,  CLA             / Clear AC
        TAD NL          / load value of ascii newline
        JMS PUTCH       / Print character
        CLA
        JMP I RESTRT    / Restart program
RESTRT, START

*200
INIT,   CLA             / Clear AC
        TAD MSGRST      / Load start of string
        DCA MSGPTR      / Store in pointer
        TAD I MSGPTR    / Get next character
        SNA             / Skip if not null
        JMP START       / Return from subroutine
        JMS PUTCH       / Print character
        CLA             / Clear AC
        JMP .-5         / Loop until null is reached
START,  TAD BSLSH       / Add the ASCII value of '\'
        JMS PUTCH       / Print '\'
LOOP,   JMS RESET       / Reset HEAD and TAIL
        TAD NL          / Load the ASCII value of '\n'
        JMS PUTCH       / Print '\n'
        CLA             / Clear AC
        JMS RDLN        / Read command line
        JMS GETNM       / Get the starting address
        DCA ADDR        / Store it for use
        TAD ADDR        / Load it back
        DCA STADDR      / Store it for keeping
        TAD I STADDR    / Get data at address
        DCA STDATA      / Store it for keeping
        TAD NL          / Load an ascii NL
        JMS PUTCH       / Print it
        JMS PUTCH       / Print it
        CLA             / Clear AC
        JMS CMD         / Run command
        CLA             / Clear AC
        TAD STADDR      / Load starting address
        DCA LSTADR      / Save it as last address
        JMP LOOP        / Jump to beginng of loop

RDLN,   0
        JMS GETCH
        DCA CHAR        / Store char
        TAD CHAR        / And load it back
        TAD CCR         / Add the two's complement of '\r' (ascii 13 or 015)
        SNA             / Skip if input not a newline
        JMP I RDLN      / If it is, return from readline subroutine

        CLA             / Clear AC
        TAD CHAR        / And load it back
        TAD CBS         / Add the two's complement of '\b' (ascii 8 or 010)
        SNA             / Skip if input not a backspace
        JMP BSPACE      / If it is, jump to BSPACE subroutine

        CLA             / Clear AC
        TAD CHAR        / And load it back
        JMS PUTCH       / Echo character back
        DCA I TAIL      / Store input char at tail
        JMP RDLN+1      / Read next char
CHAR,   0
CCR,    7763            / Complement of 015 - ASCII Carrige Return
CBS,    7770            / Complement of 010 - ASCII Backspace

BSPACE, CLA CMA         / Set AC to -1
        TAD TAIL        / Remove last char from tail
        DCA TAIL        / Store new value
        TAD BSLSH       / Load backslash
        JMS PUTCH       / Print it
        JMP RDLN+1      / Read next character

*400
        / Put number routine - prints the ascii repr of AC
PUTNMR, RTL             / Rotate left twice, twice
        RTL             / Should put the top octal digit in the lower 3 bits
        DCA PTMPNM      / Store shifted value
        TAD PTMPNM      / Load it back
        AND BOTDIG      / And the lower 3 bits to extract a single digit
        TAD ASCII0      / Add offset to get ASCII char value
        JMS PUTCH       / Print digit
        CLA             / Clear AC
        TAD PTMPNM      / Load temp num into AC
        RAL             / Rotate left once
        RTL             / Rotate left two more times to get the next digit
        DCA PTMPNM      / Store shifted value
        TAD PTMPNM      / Load it back
        AND BOTDIG      / And the lower 3 bits to extract a single digit
        TAD ASCII0      / Add offset to get ASCII char value
        JMS PUTCH       / Print digit
        CLA             / Clear AC
        TAD PTMPNM      / Load temp num into AC
        RAL             / Rotate left once
        RTL             / Rotate left two more times to get the next digit
        DCA PTMPNM      / Store shifted value
        TAD PTMPNM      / Load it back
        AND BOTDIG      / And the lower 3 bits to extract a single digit
        TAD ASCII0      / Add offset to get ASCII char value
        JMS PUTCH       / Print digit
        CLA             / Clear AC
        TAD PTMPNM      / Load temp num into AC
        RAL             / Rotate left once
        RTL             / Rotate left two more times to get the next digit
        DCA PTMPNM      / Store shifted value
        TAD PTMPNM      / Load it back
        AND BOTDIG      / And the lower 3 bits to extract a single digit
        TAD ASCII0      / Add offset to get ASCII char value
        JMS PUTCH       / Print digit
        JMP I PUTNM     / Return from subroutine via zero page stub
ASCII0, 60
BOTDIG, 7
PTMPNM, 0

/ *400
RANGER, CLA             / Clear AC
        TAD ADDR        / Load address
        JMS PUTNM       / Print number
        CLA             / Clear AC
        TAD COLON       / Load ascii colon value
        JMS PUTCH       / Print it
        CLA             / Clear AC
        JMS GETNM       / Get ending address of range
        CMA             / Form one's complement of it
        DCA ENDADR      / Store ending address
        JMP RDATA       / Print first data
RLOOP,  TAD ADDR        / Load address
        TAD ENDADR      / Subtract ending address
        SNA             / Skip if not equal
        JMP I CMD       / Return from routine

        CLA             / Clear AC
        TAD ADDR        / Load address
        AND BOTDIG      / And with three low bits
        SZA             / Skip if AC == 0 (beginning of row)
        JMP RDATA       / Jump to print data
        TAD NL          / Load ascii NL
        JMS PUTCH       / Print it
        CLA             / Clear AC
        TAD ADDR        / Load address
        JMS PUTNM       / Print number
        CLA             / Clear AC
        TAD COLON       / Load ascii colon value
        JMS PUTCH       / Print it
RDATA,  CLA             / Clear AC
        TAD SPACE       / Load ascii space value
        JMS PUTCH       / Print it
        CLA             / Clear AC
        TAD I ADDR      / Get address contents
        JMS PUTNM       / Print number in AC
        CLA IAC         / Set AC to 1
        TAD ADDR        / Increment address
        DCA ADDR        / Store new address
        JMP RLOOP       / Jump for next address
ENDADR, 0

GETNMR, CLA             / Clear AC
        DCA TNUM        / Clear temp num
        DCA NNUM        / Clear number count
        CLA CLL         / Clear AC and L
        TAD TAIL        / Load TAIL location into AC
        CMA IAC         / Complement and increment to form two's complement
        TAD HEAD        / Add HEAD location to AC
        SMA             / Skip on -AC, meaning we have more characters in buffer
        JMP ENDNM       / Else return from subroutine1

        CLA             / Clear AC
        TAD I HEAD      / Load HEAD into AC
        DCA THEAD       / Store char in THEAD
        TAD THEAD       / Load value back into AC
        TAD CA0         / Load two's complement of ascii 0
        SPA             / Skip on positive ac (AC >= 0) (might be a 0-7)
        JMP ENDCH       / Not a number char - put it back

        CLA             / Clear AC
        TAD THEAD       / Load value of char into AC
        TAD CA8         / Add two's complement of ascii 8
        SMA             / Skip on minus AC (definitely 0-7)
        JMP ENDCH       / Not a number (or out of range) - put it back

        CLA             / Clear AC
        TAD THEAD       / Load value into AC
        TAD CA0         / Add two's complement of ascii 0 to get number value
        DCA THEAD       / Store value
        TAD TNUM        / Load temp number
        CLL RAL         / Clear L and rotate left (shift)
        CLL RAL         / Shift left
        CLL RAL         / Shift left
        TAD THEAD       / Combine new number with working number
        DCA TNUM        / Save new number
        TAD NNUM        / Load number count
        IAC             / Increment count
        DCA NNUM        / Save it
        JMP GETNMR+3     / Jump back for next number

/ Oops! we consumed a char we didn't use
ENDCH,  CLA CMA         / Set AC to -1
        TAD HEAD        / Decrement HEAD
        DCA HEAD        / Store new value
/ Return the current number
ENDNM,  CLA             / Clear AC
        TAD NNUM        / Load number count into AC
        SNA             / Skip if we found at least one number
        JMP ENDLA       / Jump to end - last address subroutine
        CLA             / Clear AC
        TAD TNUM        / Load number into AC
        JMP I GETNM     / Return from subroutine
/ Return the previous address
ENDLA,  CLA             / Clear AC
        TAD LSTADR      / Load last address
        JMP I GETNM     / Return from subroutine

THEAD,  0
TNUM,   0
NNUM,   0

WELMSG, "macmon v0.1.0\n"

$