6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat May 04, 2024 1:29 am

All times are UTC




Post new topic Reply to topic  [ 7 posts ] 
Author Message
PostPosted: Sun Jul 01, 2012 7:19 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8172
Location: Midwestern USA
The Kowalski 65(c)02 simulator includes an excellent macro-assembler that can be used to generate code for use outside of the simulator. As written, the simulator supports the NMOS 6502 and the Rockwell version of the 65C02. In order to support the WDC version of the 65C02, as well as the 65C816, I devised a set of macros to synthesize the unsupported instructions. I will be making these macros available on my POC website, but am also publishing them here for convenience. I suggest you copy and past the macro list in its entirely into a file named 816macs.65s and INCLUDE that file in your programs.

Worth noting:

  1. If you use JSL to call a subroutine be sure to use RTL to return from it. JSL pushes a 24 bit return address to the stack, and RTL pulls a 24 bit address. Using RTS to return from a subroutine called with JSL will surely cause a major malfunction.

  2. Be sure to correctly set the MPU's register widths before assembling 16 bit immediate mode instructions (e.g., LDAW 1234). A set of macros for that purpose is included in the below listing.

  3. The pseudo-instruction INT N (where N is $00-$FF inclusive) is included for those who plan to use software interrupts for such purposes as calling operating system APIs. The use of INT N rather than BRK followed by a signature byte representing the API number produces some syntax checking that can be modified to suit your particular application.

  4. The WDC instructions COP, STP and WAI are included for completeness. In practice, there is seldom a need to use these instructions, especially STP. I did not include WDM, as that instruction does nothing in the current iteration of the 65C816. COP could be used in place of the BRK instruction in the INT N pseudo-instruction (above) if desired.

Code:
;================================================================================
;
;W65C816S INSTRUCTION MACROS
;
;   —————————————————————————————————————————————————————————
;   These macros implement 65C02 &  most W65C816S native mode
;   instructions that are not recognized by the Kowalski sim-
;   ulator's assembler (e.g., STP & WAI).
;   —————————————————————————————————————————————————————————
;
         .if !.ref(brl)        ;if macros haven't been defined...
;
brl      .macro .ad            ;long relative branch
.ba      =*+3
         .byte $82
         .word .ad-.ba
         .endm
;
cop      .macro .op            ;co-processor
         .if .op > $ff
             .error "MACRO ERROR: "+%0$+": SIGNATURE OUT OF RANGE"
         .endif
         .byte $02,.op
         .endm
;
jml      .macro .ad            ;JML $bbahal (long JMP)
         .byte $dc,<.ad, >.ad,.ad >> 16
         .endm
;
jsl      .macro .ad            ;JSL $bbahal (long JSR)
         .byte $22,<.ad, >.ad,.ad >> 16
         .endm
;
jsx      .macro .ad            ;JSR (<addr>,X)
         .byte $fc,<.ad, >.ad
         .endm
;
mvn      .macro .s,.d          ;move next <sbnk>,<dbnk>
         .if .s > $ff
             .error "MACRO ERROR: "+%0$+": SOURCE BANK OUT OF RANGE"
         .endif
         .if .d > $ff
             .error "MACRO ERROR: "+%0$+": DESTINATION BANK OUT OF RANGE"
         .endif
         .byte $54,.d,.s
         .endm
;
mvp      .macro .s,.d          ;move prev <sbnk>,<dbnk>
         .if .s > $ff
             .error "MACRO ERROR: "+%0$+": SOURCE BANK OUT OF RANGE"
         .endif
         .if .d > $ff
             .error "MACRO ERROR: "+%0$+": DESTINATION BANK OUT OF RANGE"
         .endif
         .byte $44,.d,.s
         .endm
;
pea      .macro .ad            ;pea <addr>
         .byte $f4,<.ad, >.ad
         .endm
;
pei      .macro .ad            ;pei (<dp>)
         .byte $d4,.ad
         .endm
;
per      .macro .ad            ;per <addr>
.ba      =*+3
         .byte $62
         .word .ad-.ba
         .endm
;
phb      .macro                ;push data bank register
         .byte $8b
         .endm
;
phd      .macro                ;push direct page register
         .byte $0b
         .endm
;
phk      .macro                ;push program bank register
         .byte $4b
         .endm
;
plb      .macro                ;pull data bank register
         .byte $ab
         .endm
;
pld      .macro                ;pull direct page register
         .byte $2b
         .endm
;
rep      .macro .op            ;clear status register bits
         .if .op > $ff
             .error "MACRO ERROR: "+%0$+": OPERAND OUT OF RANGE"
         .endif
         .byte $c2,.op
         .endm
;
rtl      .macro                ;return long from subroutine
         .byte $6b
         .endm
;
sep      .macro .op            ;set status register bits
         .if .op > $ff
             .error "MACRO ERROR: "+%0$+": OPERAND OUT OF RANGE"
         .endif
         .byte $e2,.op
         .endm
;
stp      .macro                ;halt MPU
         .byte $db
         .endm
;
tcd      .macro                ;transfer .C to direct page register
         .byte $5b
         .endm
;
tcs      .macro                ;transfer .C to stack pointer
         .byte $1b
         .endm
;
tdc      .macro                ;transfer direct page register to .C
         .byte $7b
         .endm
;
tsc      .macro                ;transfer stack pointer to .C
         .byte $3b
         .endm
;
txy      .macro                ;transfer .X to .Y
         .byte $9b
         .endm
;
tyx      .macro                ;transfer .Y to .X
         .byte $bb
         .endm
;
wai      .macro                ;wait for interrupt
         .byte $cb
         .endm
;
xba      .macro                ;swap B & A accumulators
         .byte $eb
         .endm
;
xce      .macro                ;swap carry & emulation bits
         .byte $fb
         .endm
;
;
;   synthesized long (24 bit) load/store instructions...
;
;   —————————————————————————————————————————————————————————————————————
;   Long load/store instructions take the form ***L or ***LX,  the latter
;   for indexed operations.  *** represents the parent instruction.   The
;   assembled instruction generates a 24 bit operand to the parent instr-
;   uction.   The actual macro names are lower case.    The macro comment
;   indicates the official WDC assembly language syntax for the  instruc-
;   tion being synthesized.  The bb in the addressing mode symbology rep-
;   resents the bank number.   The address parameter is processed as a 24
;   bit value regardless of size.   Hence the instruction LDALX $01 would
;   be assembled as AF 01 00 00, which disassembles as LDA $000001,X.
;   —————————————————————————————————————————————————————————————————————
;
adcl     .macro .ad            ;ADC $bbahal
         .byte $6f,<.ad, >.ad,.ad >> 16
         .endm
;
adclx    .macro .ad            ;ADC $bbahal,X
         .byte $7f,<.ad, >.ad,.ad >> 16
         .endm
;
andl     .macro .ad            ;AND $bbahal
         .byte $2f,<.ad, >.ad,.ad >> 16
         .endm
;
andlx    .macro .ad            ;AND $bbahal,X
         .byte $3f,<.ad, >.ad,.ad >> 16
         .endm
;
cmpl     .macro .ad            ;CMP $bbahal
         .byte $cf,<.ad, >.ad,.ad >> 16
         .endm
;
cmplx    .macro .ad            ;CMP $bbahal,X
         .byte $df,<.ad, >.ad,.ad >> 16
         .endm
;
eorl     .macro .ad            ;EOR $bbahal
         .byte $4f,<.ad, >.ad,.ad >> 16
         .endm
;
eorlx    .macro .ad            ;EOR $bbahal,X
         .byte $5f,<.ad, >.ad,.ad >> 16
         .endm
;
ldal     .macro .ad            ;LDA $bbahal
         .byte $af,<.ad, >.ad,.ad >> 16
         .endm
;
ldalx    .macro .ad            ;LDA $bbahal,X
         .byte $bf,<.ad, >.ad,.ad >> 16
         .endm
;
oral     .macro .ad            ;ORA $bbahal
         .byte $0f,<.ad, >.ad,.ad >> 16
         .endm
;
oralx    .macro .ad            ;ORA $bbahal,X
         .byte $1f,<.ad, >.ad,.ad >> 16
         .endm
;
sbcl     .macro .ad            ;SBC $bbahal
         .byte $ef,<.ad, >.ad,.ad >> 16
         .endm
;
sbclx    .macro .ad            ;SBC $bbahal,X
         .byte $ff,<.ad, >.ad,.ad >> 16
         .endm
;
stal     .macro .ad            ;STA $bbahal
         .byte $8f,<.ad, >.ad,.ad >> 16
         .endm
;
stalx    .macro .ad            ;STA $bbahal,X
         .byte $9f,<.ad, >.ad,.ad >> 16
         .endm
;
;
;
;   synthesized stack-based accumulator instructions...
;
;   —————————————————————————————————————————————————————————————————————
;   Stack-based accumulator instructions take the form ***S or ***SI, the
;   latter for indexed indirect operations.   *** represents  the  parent
;   instruction.  For example, LDAS 1 is equivalent to LDA 1,S &  LDASI 1
;   is the equivalent of LDA (1,S),Y.  The actual macro names  are  lower
;   case.  The macro comment indicates the official WDC assembly language
;   syntax for the instruction being synthesized.
;   —————————————————————————————————————————————————————————————————————
;
adcs     .macro .of            ;ADC <offset>,S
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $63,.of
         .endm
;
adcsi    .macro .of            ;ADC (<offset>,S),Y
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $73,.of
         .endm
;
ands     .macro .of            ;AND <offset>,S
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $23,.of
         .endm
;
andsi    .macro .of            ;AND (<offset>,S),Y
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $33,.of
         .endm
;
cmps     .macro .of            ;CMP <offset>,S
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $c3,.of
         .endm
;
cmpsi    .macro .of            ;CMP (<offset>,S),Y
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $d3,.of
         .endm
;
eors     .macro .of            ;EOR <offset>,S
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $43,.of
         .endm
;
eorsi    .macro .of            ;EOR (<offset>,S),Y
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $53,.of
         .endm
;
ldas     .macro .of            ;LDA <offset>,S
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $a3,.of
         .endm
;
ldasi    .macro .of            ;LDA (<offset>,S),Y
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $b3,.of
         .endm
;
oras     .macro .of            ;ORA <offset>,S
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $03,.of
         .endm
;
orasi    .macro .of            ;ORA (<offset>,S),Y
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $13,.of
         .endm
;
sbcs     .macro .of            ;SBC <offset>,S
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $e3,.of
         .endm
;
sbcsi    .macro .of            ;SBC (<offset>,S),Y
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $f3,.of
         .endm
;
stas     .macro .of            ;STA <offset>,S
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $83,.of
         .endm
;
stasi    .macro .of            ;STA (<offset>,S),Y
         .if .of > $ff
             .error "MACRO ERROR: "+%0$+": OFFSET OUT OF RANGE"
         .endif
         .byte $93,.of
         .endm
;
;
;   16 bit immediate mode instructions...
;
;   ————————————————————————————————————————————————————————————————————
;   Immediate mode instructions that are able to accept 16 bit  operands
;   take the form ***W, where *** is the parent 8 bit  instruction.  For
;   example, ADCW is the 16 bit form of ADC.  The actual macro names are
;   lower case.   It is the responsibility of the  programmer to  assure
;   that MPU register sizes have been correctly configured before  using
;   ***W instructions.  For example:
;
;      LONGA                 ;16 bit .A & memory
;      LDAW $1234            ;assembles as LDA #$1234
;      SHORTA                ;8 bit .A & memory
;      LDAW $1234            ;won't work as expected!!!
;
;   The macro comment indicates the official WDC assembly language  syn-
;   tax for the instruction being synthesized.
;   ————————————————————————————————————————————————————————————————————
;
adcw     .macro .op            ;ADC #<operand>
         adc #<.op
         .byte >.op
         .endm
;
andw     .macro .op            ;AND #<operand>
         and #<.op
         .byte >.op
         .endm
;
bitw     .macro .op            ;BIT #<operand>
         bit #<.op
         .byte >.op
         .endm
;         
cmpw     .macro .op            ;CMP #<operand>
         cmp #<.op
         .byte >.op
         .endm
;
cpxw     .macro .op            ;CPX #<operand>
         cpx #<.op
         .byte >.op
         .endm
;
cpyw     .macro .op            ;CPY #<operand>
         cpy #<.op
         .byte >.op
         .endm
;
eorw     .macro .op            ;EOR #<operand>
         eor #<.op
         .byte >.op
         .endm
;
ldaw     .macro .op            ;LDA #<operand>
         lda #<.op
         .byte >.op
         .endm
;
ldxw     .macro .op            ;LDX #<operand>
         ldx #<.op
         .byte >.op
         .endm
;
ldyw     .macro .op            ;LDY #<operand>
         ldy #<.op
         .byte >.op
         .endm
;
oraw     .macro .op            ;ORA #<operand>
         ora #<.op
         .byte >.op
         .endm
;
sbcw     .macro .op            ;SBC #<operand>
         sbc #<.op
         .byte >.op
         .endm
;
;
;   register size macros...
;
;   ————————————————————————————————————————————————————————————————————
;   These macros are a convenient way to change the MPU's register sizes
;   without having to remember the correct bit pattern for the REP & SEP
;   instructions.  The assembler itself has no awareness of whether 8 or
;   16 bit immediate mode operands are to be used.   Therefore, it is up
;   to the programmer to use the appropriate instructions.
;   ————————————————————————————————————————————————————————————————————
;
longa    .macro                ;16 bit accumulator & memory
         rep $20
         .endm
;
longr    .macro                ;16 bit all registers
         rep $30
         .endm
;
longx    .macro                ;16 bit index registers
         rep $10
         .endm
;
shorta   .macro                ;8 bit accumulator & memory
         sep $20
         .endm
;
shortr   .macro                ;8 bit all registers
         sep $30
         .endm
;
shortx   .macro                ;8 bit index registers
         sep $10
         .endm
;
;
;   INT pseudoinstruction...
;
int      .macro .op            ;INT <int_num>
         .if .op > $ff
             .error "MACRO ERROR: "+%0$+": INTERRUPT NUMBER OUT OF RANGE"
         .endif
         .byte $00,.op
         .endm
;
         .endif
   .end
————————————————————————————————————————————————————————————
  • 2012/07/03: There was an error in the JSL macro that was spotted by teamtempest, who must've read the thing from end to end. :shock: I accidentally got the copy-and-paste messed up. Instead of just fixing JSL, I went ahead and replaced the entire listing with the newest version, which does more extensive parameter checking, and also implements the long (24 bit) load/store instructions, such as LDA $123456 or STA $654321,X.

  • 2012/07/06: This macro set is also available on my SBC website.

  • 2012/07/21: The macro set now includes the PER (push effective relative address) instruction. The only 65C816 instruction not synthesized is WDM, which has no function in the current version of the '816.

  • 2012/08/16: Please note that I will no longer be maintaining this forum post. If you want the most up-to-date version please visit my POC website and browse to Downloads. Or you can get a current copy of the macros on Garth Wilson's website, as he has a link to the source file (scroll down to the math (including hardware coprocessors), algorithms, OSs, programming languages, programmers' info section).

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Last edited by BigDumbDinosaur on Tue Aug 21, 2012 5:12 am, edited 7 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 02, 2012 12:39 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8172
Location: Midwestern USA
If you are going to use INT N for calling an operating system API it would be a good idea to create a macro that calls the API in a more "conversational" way. For example, suppose you want to make an API call that gets data from an active channel (i.e., open file). The required parameters are the channel number, the 16 bit number of bytes to get and the 16 bit address of a buffer in which to store them. You could write the API call as follows:

Code:
          shorta               ;8 bit .A & memory
          longx                ;16 bit .X & .Y
          lda #chan            ;channel number
          ldxw 512             ;bytes to get
          ldyw buffer          ;store them here
          int api_read         ;get data

However, a better way to do it might be to define the following macro:

Code:
read     .macro .ch,.n,.buf    ;read N bytes from channel CH into buffer BUF
         .if .n
             .if .ch > 255
                 .error "MACRO ERROR: "+%0$+": CHANNEL NUMBER OUT OF RANGE"
             .endif
             shorta
             longx
             lda #.ch          ;open channel
             ldxw .n           ;bytes to get
             ldyw .buf         ;where to store them
             int api_read      ;call kernel API, where API_READ is the API number
         .else
             .error "MACRO ERROR: "+%0$+": INVALID NUMBER OF BYTES"
         .endif
         .endm

Later on in your program, you'd execute the read operation as follows:

Code:
;
          read chan,n_bytes,buffer
          bcs error            ;error, possible EOF
;
          ...program continues...

Similar techniques would apply to other kernel APIs or, for that matter, non-API library functions, as the Kowalski assembler's macro parser can support a variable number of macro parameters. It's not quite like writing high level code but not quite as tedious as pure assembly language.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 02, 2012 4:06 am 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 387
Location: Minnesota
Quote:
jsl .macro .bk,.ad ;JSL $bbahal (long JSR)
.byte $22,<.ad, >.ad,.ad >> 16
.endm


I'm curious about this definition. It appears to accept two operands, but only one is used (or needed, IIRC). Is there some reason to define it this way?


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 02, 2012 5:35 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8172
Location: Midwestern USA
teamtempest wrote:
Quote:
Code:
jsl      .macro .bk,.ad        ;JSL $bbahal (long JSR)
         .byte $22,<.ad, >.ad,.ad >> 16
         .endm


I'm curious about this definition. It appears to accept two operands, but only one is used (or needed, IIRC). Is there some reason to define it this way?

Good catch! It was an error from an earlier copy-and-paste session in the text editor. Rather than just fix the error, I replaced the macro source with the latest version, which now includes the 24 bit load/store instructions and better parameter checking. Anyone who might have copied the older version should replace with the above. While the erroneous JSL macro will assemble, an attempt to call the macro with a single address as it should be called (e.g., JSL $04ED13) will cause a missing parameter error.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 03, 2012 7:55 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8172
Location: Midwestern USA
I finally figured out how to get BRL (branch long) to work with forward branches. The macro list has been updated. I also removed error checks on some macro parameters because they could malfunction under certain conditions.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 21, 2012 5:34 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8172
Location: Midwestern USA
I have again updated the macro listing, adding the 65C816 PER instruction. Unless someone discovers an error in it, this should be the final change to the macros.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 17, 2012 4:44 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8172
Location: Midwestern USA
If you want the most up-to-date version of the Kowalski 65C816 macros please visit my POC website and browse to Downloads. Or you can get a current copy of the macros on Garth Wilson's website, as he has a link to the source file (scroll down to the math (including hardware coprocessors), algorithms, OSs, programming languages, programmers' info section).

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron