Joined: Thu May 28, 2009 9:46 pm Posts: 8508 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:
- 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.
- 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.
- 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.
- 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. 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.
|
|