Keyboard Input Routines
and Character Code Output
on the 6800
So we figured out
how to call the keyboard input routine in EXbug on the EXORciser, and now we need to write up some glue that will be easy to use with our
framework, and some test code. While we're at it, we can have our test
routines show us the binary and hexadecimal values for the character codes we
are getting back.
* simple 8-bit keyboard input for 6800 (EXORsim)
* using parameter stack,
* with test frame
* Joel Matthew Rees, October 2024
*
EXP rt_rig03_6800.asm
****************
* Program code:
*
* Essential monitor ROM parameters
* ECHO suppress -- set non-zero before each call to XINCH/XINCHN
* to suppress echo for that call only.
* Not the same address as 6809 EXBUG09.
AECHO EQU $FF53 ; ECHO suppress per-call
*
* Essential monitor ROM routines
XINCH EQU $F012 ; wait for key, return in A, preserves B, X, see AECHO
*
* Wait for input, return character on PSP (and in A:B)
* Call INCHNE for no echo.
INCHNE INC AECHO ; XINCH always clears it.
INCHAR BSR INCHV
TAB
CLRA
JSR PPSHD
RTS
*
INCHV JMP XINCH ; returns with character in A
*
*
PROMPT FCB CR,LF ; Put message at beginning of line
FCC "Type any key, Q to quit. " ;
FCB CR,LF ; Put the prompt on a new line
FCB NUL
KEYCOL FCC "KEY:"
FCB NUL
COLBIN FCB ASCCOL,NUL
COLHEX FCC ": $"
FCB NUL
*
* Duplicate 16-bit word on P stack
PDUP LDX PSP
LDAA 0,X
LDAB 1,X
DEX
DEX
STX PSP
STAA 0,X
STAB 1,X
RTS
*
*
PGSTRT LDX #PROMPT
JSR PPSHX
JSR OUTS
JSR INCHNE ; Hold off echo
JSR PDUP
LDX #KEYCOL
JSR PPSHX
JSR OUTS
JSR OUTC ; output character
JSR PDUP
LDX #COLBIN
JSR PPSHX
JSR OUTS
JSR OUTB8
JSR PDUP ; need it for testing
LDX #COLHEX
JSR PPSHX
JSR OUTS
JSR OUTHX8
JSR OUTNWLN
JSR PPOPD ; balance stack
CMPB #ASCQ
BNE PGSTRT
RTS
*
END ENTRY
Our keyboard input routine has two entry points, so we can call it with or without echo, without having to think about AECHO.
PDUP is a routine for duplicating the top of the stack so we don't lose the value we're working with the first time we give it to a non-low-level function.
Here's the run-time framework/rigging we'll be using this time:
* A simple run-time framework inclusion for 6800
* providing parameter stack and local base
* Version 00.00.03
* Joel Matthew Rees, October 2024
*
* Essential control codes
LF EQU $0A ; line feed
CR EQU $0D ; carriage return
NUL EQU 0
*
* Other essential ASCII codes
ASC0 EQU '0 ; Some assemblers won't handle 'c constants well.
ASC9 EQU '9
ASCA EQU 'A
ASCXGAP EQU ASCA-ASC9-1 ; Gap between '9' and 'A' for hexadecimal
ASCCOL EQU ':
ASCQ EQU 'Q
*
NATWID EQU 2 ; 2 bytes in the CPU's natural integer
*
*
ORG $80 ; MDOS and EXbug docs say it should be okay here.
ENTRY JMP START
NOP ; Just want even addressed pointers for no reason.
*
* These are the page zero context variables that must be
* saved and restored on process context switch.
* They must never be accessed except in leaf routines:
PSP RMB 2 ; parameter stack pointer
LBP RMB 2 ; local static variable base pointer
XSTKWK RMB 2 ; for stashing X during stack work
XWORK RMB 2 ; for stashing X during other very short operations
*
SSAVE RMB 2 ; a place to keep S so we can return clean
* End of page zero context variables.
*
*
ORG $2000 ; MDOS says this is a good place for usr stuff
LOCBAS EQU * ; here pointer, local static base starts here.
NOENTRY JMP START
NOP
RMB 64 ; room for something
RMB 2 ; a little bumper space
* Not much here
*
SSTKLIM RMB 31 ; 16 levels of call, max
SSTKBAS RMB 1 ; 6800 is post-dec (post-store-decrement) push
RMB 2 ; a little bumper space
PSTKLIM RMB 64 ; 16 levels of call at two parameters per call
PSTKBAS RMB 2 ; bumper space -- parameter stack is pre-dec
*
*
INITRT LDX #PSTKBAS ; Set up the run-time environment
STX PSP
LDX #LOCBAS
STX LBP
TSX ; point to return address
LDX 0,X ; return address in X
INS ; drop the return pointer on stack
INS
STS SSAVE ; Save what the monitor gave us.
LDS #SSTKBAS ; Move to our own stack
JMP 0,X ; return via X
*
*
*********************
* Low-level library:
*
* Only alters X
PPOPX LDX PSP
LDX 0,X
STX XSTKWK
LDX PSP
INX
INX
STX PSP
LDX XSTKWK
RTS
* If we didn't mind leaving the popped value in limbo
* beyond the top of the stack, we could avoid the temporary:
*PPOPX LDX PSP
* INX
* INX
* STX PSP
* DEX
* DEX
* LDX 0,X
* RTS
*
* Trashes A,B;
* X points to X value just pushed -- PSP top of stack -- at end
PPSHX STX XSTKWK
LDAA XSTKWK
LDAB XSTKWK+1 ; Falls through
* X points to PSP top of stack at end
PPSHD LDX PSP
DEX
DEX
STX PSP
STAA 0,X
STAB 1,X
RTS
*
*
* X points to PSP top of stack at end
PPOPD LDX PSP
LDAA 0,X
LDAB 1,X
INX
INX
STX PSP
RTS
*
* Load a constant from the instruction stream into A:B,
* continue execution after the constant.
* This is not self-modifying code, even though it feels like a trick
* and is playing with the return stack and instruction stream
* in ways we wouldn't think we wanted to think we should.
* Call it a "necessary" bit of run-time syntactic sugar.
*
* Use it like this:
* JSR LD16I ; load D immediate
* FDB $1234 ; "immediate" 16-bit value to load
* JSR SOMEWHERE ; or some other executable code.
*
LD16I TSX ; point to top of return address stack
LDX 0,X ; point into the instruction stream
LDAA 0,X ; high byte from instruction stream
LDAB 1,X ; low byte from instruction stream
INS ; drop the return address we don't need
INS
JMP 2,X ; return to the byte after the constant.
*
* Essential monitor ROM routine
XOUTCH EQU $F018 ; output ACCM A to debug terminal, preserves B,X
*
* Output an 8-bit byte in hexadecimal,
* byte as a 16-bit parameter on PSP.
OUTHX8 LDX PSP
LDAB 1,X ; get the byte
LSRB
LSRB
LSRB
LSRB
BSR OUTRAD
LDX PSP
LDAB 1,X
ANDB #$0F ; mask it off
BSR OUTRAD
INX
INX
STX PSP
RTS
*
* Convert the value in B to ASCII numeric,
* including hexadecimals and up to base 36 ('Z'+1)
OUTRAD ADDB #ASC0 ; Add the ASCII for '0'
CMPB #ASC9 ; Greater than '9'?
BLS OUTRADD ; no, output as is.
ADDB #ASCXGAP ; Adjust it to 'A' to 'Z'
OUTRADD CLRA
JSR PPSHD
JSR OUTC
RTS
*
* Output the 8-bit number on the stack in binary (base two).
* For consistency, we are passing the byte as the low-order byte
* of a 16-bit word.
OUTB8 LDX PSP ; parameter is at 0,X (low byte at 1,X)
LDAB #8 ; 8 bits (B is preserved in BIOS
OUTB8L LSL 1,X ; Get the leftmost bit.
BCS OUTB81
OUTB80 LDAA #'0
BRA OUTB8B
OUTB81 LDAA #'1
OUTB8B JSR OUTCV
DECB ; count
BNE OUTB8L ; loop if not Zero
INX ; drop parameter bytes
INX
STX PSP
RTS
*
OUTNWLN LDAA #CR ; driver level code to output a new line
BSR OUTCV
LDAA #LF
BSR OUTCV
RTS
*
OUTC JSR PPOPD ; get the character in B
TBA ; put it where XOUTCH wants it.
BSR OUTCV ; output A via monitor ROM
RTS
*
* Preserves B, X.
OUTCV JMP XOUTCH ; driver code for outputting a character
*
OUTS JSR PPOPX ; get the string pointer
OUTSL LDAA 0,X ; get the byte out there
BEQ OUTDN ; if NUL, leave
BSR OUTCV ; use the same call OUTC uses.
INX ; point to the next
BRA OUTSL ; next character
OUTDN RTS
*
*
******************************
* intermediate-level library:
*
* input parameters:
* 16-bit left, right
* output parameter:
* 16-bit sum
ADD16 LDX PSP
LDAB 3,X ; left low
LDAA 2,X ; left high
ADDB 1,X ; right low
ADCA 0,X ; right high, with carry
STAB 3,X ; sum low
STAA 2,X ; sum high
INX ; adjust parameter stack
INX
STX PSP
RTS
*
* input parameters:
* 16-bit left, right
* output parameter:
* 16-bit difference
SUB16 LDX PSP
LDAB 3,X ; left low
LDAA 2,X ; left high
SUBB 1,X ; right low
SBCA 0,X ; right high, with borrow
STAB 3,X ; difference low
STAA 2,X ; difference high
INX ; adjust parameter
INX
STX PSP
RTS
*
*
************************************
* Start run-time, call program.
* Expects program to define PGSTRT:
*
START JSR INITRT
*
JSR PGSTRT
*
DONE LDS SSAVE ; restore the monitor stack pointer
NOP ; remember to set a breakpoint here!
NOP ; landing pad
NOP
NOP
LDX $FFFE ; alternatively, get reset vector
JMP 0,X ; and reboot through it
*
* Anyway, if running in EXORsim,
* Ctrl-C should bring you back to EXORsim monitor,
* but not necessarily to your program in a runnable state.
So you can save those with appropriate names, assemble them with asm68c, get an exorsim monitor session going, at a load command, paste the srecord .x file that the assembler produces in, and give it a spin.
Just to be too helpful, here's the srecord file:
S10700807E217C015C
S10B0084000000000000000070
S105008C00006E
S11320007E217C01000000000000000000000000B0
S113201000000000000000000000000000000000BC
S113202000000000000000000000000000000000AC
S1132030000000000000000000000000000000009C
S109204000000000000096
S11320460000000000000000000000000000000086
S11320560000000000000000000000000000000076
S11320660000000000000000000000000000000066
S11320760000000000000000000000000000000056
S11320860000000000000000000000000000000046
S11320960000000000000000000000000000000036
S10720A60000000032
S11320AACE20A8DF84CE2000DF8630EE0031319FB7
S10920BA8C8E20656E000F
S11220C0DE84EE00DF88DE840808DF84DE8839E2
S10920CFDF889688D68923
S10E20D5DE840909DF84A700E701395D
S10E20E0DE84A600E6010808DF843956
S10E20EB30EE00A600E60131316E0269
S11320F6DE84E601545454548D0DDE84E601C40F87
S10A21068D050808DF843990
S113210DCB30C1392302CB074FBD20D5BD213F397B
S113211DDE84C60868012504863020028631BD217F
S10C212D465A26F00808DF843943
S10C2136860D8D0C860A8D083912
S10A213FBD20E0178D0139FA
S10621467EF0180C
S1102149BD20C0A60027058DF40820F7393D
S1132156DE84E603A602EB01A900E703A70208084A
S1062166DF8439D6
S1132169DE84E603A602E001A200E703A702080849
S1062179DF8439C3
S106217CBD20AAD5
S106217FBD21D3A8
S10E21829E8C01010101FEFFFE6E00B7
S10E218D7CFF538D06164FBD20D53992
S10621987EF012C0
S113219B0D0A5479706520616E79206B65792C205A
S11321AB5120746F20717569742E200D0A004B45F4
S10C21BB593A003A003A202400CC
S11221C4DE84A600E6010909DF84A700E70139DC
S11321D3CE219BBD20CFBD2149BD218DBD21C4CEC0
S11321E321B9BD20CFBD2149BD213FBD21C4CE218D
S11321F3BEBD20CFBD2149BD211DBD21C4CE21C0FB
S1132203BD20CFBD2149BD20F6BD2136BD20E0C18F
S10722135126BD3956
S9032217C3
Watch what happens when you hit control-key combinations.
And, because I'm being too helpful, go ahead and use your imagination, modify the code, play with it a bit.
I'm finding it tempting to put the 6801 and 6809 code in this chapter, but the framework is getting a little long.
So, on, to the 6801, in the next chapter.
No comments:
Post a Comment