Binary Output on the 6809,
Left-to-right;
Framework-by-include
(LWTools)
We've done binary output on the 6801, so let's do it on the 6809. Sure it's getting monotonous, but that's what it takes to understand the differences between the processors. More to the point, I don't know any other way to explain the discipline I'm using, except in steps.
The binary output routines in their less-optimized form don't make a lot of obvious use of the 6809's unique features; at least, they don't stand out until you consider how things are being done directly by the 6809's native instructions rather than subroutines:
* simple 8-bit binary output for 6809
* using parameter stack,
* with test frame
* Joel Matthew Rees, October 2024
*
OPT 6809
INCLUDE rt_rig6809.asm
****************
* Program code:
*
* Output a 0
OUT0 LDB #'0
OUT01 PSHU D
LBSR OUTC
RTS
*
* Output a 1
OUT1 LDB #'1
BRA OUT01
* Rob code, shave a couple of bytes, waste a few cycles.
*
* Output the 8-bit binary (base two) number on the stack.
* For consistency, we are passing the byte in the low-order byte
* of a 16-bit word.
OUTB8 LDB #8 ; 8 bits
STB 0,U ; Borrow the upper byte of the parameter.
OUTB8L LSL 1,U ; Get the leftmost bit of the lower byte.
BCS OUTB81
OUTB80 BSR OUT0
BRA OUTB8D
OUTB81 BSR OUT1
OUTB8D DEC ,U
BNE OUTB8L ; loop if not Zero
LEAU 2,U ; drop parameter bytes
RTS
*
HEADLN FCB CR,LF ; Put message at beginning of line
FCC "Outputting $5A in binary:" ;
FCB CR,LF,NUL ; Put the binary output on a new line
*
*
*
*
PGSTRT LEAX HEADLN,PCR
PSHU X
LBSR OUTS
LDD #$5A ; byte to output
PSHU D
LBSR OUTB8
LBSR OUTNWLN
RTS
*
END ENTRY
You'll want to save that as something like
outb8_6809.asm
You'll note that the inclusion directive is now INCLUDE, not EXP. We won't be using asm68c on the 6809 source. I never got that far, and Lost Wizard does a really good job with LWTools, anyway.
(William Astle kept OPT as a synonym for PRAGMA, to help compatibility with
other assemblers.)
As was somewhat the case with the 6801, the framework rigging makes much more
clear use of the 6809's features:
* A simple run-time framework inclusion for 6809
* providing parameter stack and local base
* Version 00.00.00
* Joel Matthew Rees, October 2024
*
* Essential control codes
LF EQU $0A ; line feed
CR EQU $0D ; carriage return
NUL EQU 0
*
*
* Essential monitor ROM routines
XOUTCH EQU $F018
*
NATWID EQU 2 ; 2 bytes in the CPU's natural integer
*
*
ORG $2000 ; MDOS says this is a good place for usr stuff
SETDP $20 ; some other assemblers
* SETDP $2000 ; EXORsim
LOCBAS EQU * ; here pointer, local static base starts here.
ENTRY JMP START
NOP
SSAVE RMB 2 ; a place to keep S so we can return clean
DPSAVE RMB 2 ; a place to keep DP so we can return clean
* room for something
* Not much here
*
SETDP 0 ; Not yet set up
ORG $2100 ; Give the DP room.
RMB 2 ; a little bumper space
SSTKLIM RMB 31 ; 16 levels of call, max
* ; 6809 is pre-dec (decrement-before-store) push
SSTKBAS 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 TFR DP,A
CLRB
TFR D,Y ; save old DP base for a moment
LEAX LOCBAS,PCR ; Set up new DP base
TFR X,D
TFR A,DP ; Now we can access DP variables correctly.
SETDP $20 ; some other assemblers
* SETDP $2000 ; EXORsim
STY <DPSAVE ; technically only need to save high byte
LEAU PSTKBAS,PCR ; Set up the parameter stack
PULS X ; get return address
STS <SSAVE ; Save what the monitor gave us.
LEAS SSTKBAS,PCR ; Move to our own stack
JMP ,X ; return via X
*
*
OUTNWLN LDA #CR ; driver level code to output a new line
BSR OUTCV
LDA #LF
BSR OUTCV
RTS
*
* No need for PPOPD, PPUSHD, PPOPX, or PPUSHX in 6809 code.
*
* We can handle the parameter stack directly.
* Preserves B.
OUTC LDA 1,U ; Get the character in A where XOUTCH wants it.
LEAU 2,U ; Got it in A, now drop it from the stack.
BSR OUTCV ; output via monitor ROM
RTS
*
OUTCV JMP XOUTCH ; driver code for outputting a character
*
* And we can handle the parameter stack directly here, too.
OUTS PULU X ; get the string pointer
OUTSL LDA ,X+ ; get the byte, update the pointer
BEQ OUTDN ; if NUL, leave
BSR OUTCV ; use the same call OUTC uses.
BRA OUTSL ; next character
OUTDN RTS
*
*
******************************
* intermediate-level library:
*
* We often will not need these, but we'll go ahead and define them:
*
* input parameters:
* 16-bit left, right
* output parameter:
* 16-bit sum
ADD16 LDD 2,U ; left
ADDD ,U++ ; right
STD ,U ; sum (N, Z, & C flags should be correct)
RTS
* Flags: Specifically,
* N and Z get set correctly by the final store double;
* C should make it through manipulating X and storing D.
* V gets cleared.
*
* input parameters:
* 16-bit left, right
* output parameter:
* 16-bit difference
SUB16 LDD 2,U ; left
SUBD ,U++ ; right
STD ,U ; difference (N, Z, & C flags should be correct)
RTS
* Flags: Specifically,
* N and Z get set correctly by the final store double;
* C should make it through manipulating X and storing D.
* V gets cleared.
*
*
************************************
* Start run-time, call program.
* Expects program to define PGSTRT:
*
START LBSR INITRT
*
LBSR PGSTRT
*
DONE LDS <SSAVE ; restore the monitor stack pointer
LDD <DPSAVE ; restore the monitor DP
TFR A,DP
SETDP 0 ; For lack of a better way to set it.
NOP ; remember to set a breakpoint here!
NOP ; landing pad
NOP
NOP
JMP [$FFFE] ; alternatively, jmp through reset vector
*
* Anyway, if running in EXORsim,
* Ctrl-C should bring you back to EXORsim monitor,
* but not necessarily to your program in a runnable state.
Save this in the same directory as
rt_rig6809.asm
since that's what the inclusion directive says it is.
Since asm68c won't assemble that, we'll need something else. I recommend William Astle's very professional LWTools, as I mentioned above, found here:
Instructions to build it are on that page, and there are links to the
manual as well.
Building it is straightforward, and it supports standard techniques for changing the install directory. I was able to tell it to install the executables to my user-local executables directory without fuss.
When you get through the install with no errors, you should be able to give it the command
$ lwasm --help
and it should list out various ways to call it.
You can use the command line
$ lwasm outb8_6809.asm
to assemble the code, and the object code, if there were no errors in copying, will be saved as
a.out
in a format that EXORsim doesn't recognize. And you won't get a listing. To
get s1-s9 (srec) object code and listing to the terminal, use
$ lwasm --format=srec -o outb8_6809.s19 --list outb8_6809.asm
I find it useful to put the symbol table in the listing with the "-s" option
and save the listing to a file, so I use the command line
$ lwasm --format=srec -o outb8_6809.s19 --list=outb8_6809.list -s
outb8_6809.asm
If you get a clean assembly, you can open the object file
outb8_6809.s19
in a text editor and select ...
Okay, this is a little tricky. EXORsim doesn't accept the S0 header record (first line) or the S5 count record (second to last line), so we have to delete those lines before we can select all of the rest to paste it in.
No big deal, right?
Again, you may have to hit return again at the end, to bring it back to the %
prompt:
$ ./exor09 --mon
Load facts file 'facts09'
'exbug09.bin' loaded.
EXBUG09-2.1 detected
'mdos09.dsk' opened for drive 0 (double sided)
OSLOAD...
Hit Ctrl-C for simulator command line. Starting simulation...
> 0 A=00 B=00 X=0000 Y=0000 U=0000 S=00FF P=00 -------- 0020: 86 10 LDA #$10
6809 Monitor: Ctrl-C to exit, 'c' to continue, or type 'help'
% l
S10720007E21AF1278
S10D21661FB85F1F02308DFE911FA9
S1132170101F8B109F06338CEB351010DF04328C4C
S1132180A06E84860D8D0C860A8D0839A6413342D3
S11321908D01397EF0183710A68027048DF520F8BC
S11321A039EC42E3C1EDC439EC42A3C1EDC43917A3
S11321B0FFB417004E10DE04DC061F8B121212123D
S11321C06E9FFFFEC630360617FFC139C63120F6B2
S11321D0C608E740684125048DEA20028DEE6AC4F2
S11321E026F23342390D0A4F757470757474696E32
S11321F0672024354120696E2062696E6172793AE4
S11322000D0A00308CDF361017FF8BCC005A3606CF
S10A221017FFBD17FF6D3934
S9032000DC
PC set to 2000
181 bytes loaded
No checksum errors.
%
Refer to the listing file, look around, step through a bit, set a breakpoint, and run it:
% u 21AF
21AF: 17 FFB4 LBSR $2166
21B2: 17 004E LBSR $2203
21B5: 10DE 04 LDS $04
21B8: DC 06 LDD $06
21BA: 1F 8B TFR A,DP
21BC: 12 NOP
21BD: 12 NOP
21BE: 12 NOP
21BF: 12 NOP
21C0: 6E 9F FFFE JMP [$fffe]
21C4: C6 30 LDB #$30
21C6: 36 PSHU B,A
21C8: 17 FFC1 LBSR $218c
21CB: 39 RTS
21CC: C6 31 LDB #$31
21CE: 20 F6 BRA $21c6
21D0: C6 08 LDB #$08
21D2: E7 40 STB 0,U
21D4: 68 41 ASL 1,U
21D6: 25 04 BCS $21dc
21D8: 8D EA BSR $21c4
21DA: 20 02 BRA $21de
% b 21BD
Breakpoint set at 21BD
% s 2000
0 A=00 B=00 X=0000 Y=0000 U=0000 S=00FF P=00 -------- 2000: 7E 21AF JMP $21af
> 1 A=00 B=00 X=0000 Y=0000 U=0000 S=00FF P=00 -------- 21AF: 17 FFB4 LBSR $2166
6809 Monitor: Ctrl-C to exit, 'c' to continue, or type 'help'
% r
PC=21AF A=00 B=00 X=0000 Y=0000 U=0000 SP=FF DP=00 CC=00
% c
Breakpoint!
Outputting $5A in binary:
01011010
1323 A=00 B=00 X=2203 Y=0000 U=2164 S=00FF P=00 -----Z-- 21BC: 12 NOP
> 1324 A=00 B=00 X=2203 Y=0000 U=2164 S=00FF P=00 -----Z-- 21BD: 12 NOP
6809 Monitor: Ctrl-C to exit, 'c' to continue, or type 'help'
%
The same optimization that we made for the 6800 and 6801 will work here.
except you have to edit LDAA to LDA, etc., remove the references to PSP and
trade them for ,U, etc. I should leave that for you to figure out, but, maybe
not:
* Output the 8-bit binary (base two) number on the stack.
* For consistency, we are passing the byte in the low-order byte
* of a 16-bit word.
OUTB8 LDB #8 ; 8 bits
STB ,U ; Borrow the upper byte of the parameter.
OUTB8L LSL 1,U ; Get the leftmost bit of the lower byte.
BCS OUTB81
OUTB80 LDA #'0
BRA OUTB8B
OUTB81 LDA #'1
OUTB8B JSR OUTCV
DEC ,U
BNE OUTB8L ; loop if not Zero
LEAU 2,U ; drop parameter bytes
RTS
Doesn't having U to reference the parameter stack and make references to parameters (and variables) clear without having to dodge the return address and look through stack frames make it so much easier to see what you're doing?
I'm getting excited again. Sorry.
Stack frames. I guess I'll have to show you how those work, but not yet.
The 68000 code should be just different enough that we don't fall asleep getting there.
No comments:
Post a Comment