; smc.mac ; ca65 Macro-Pack for Self Modifying Code (SMC) ; ; (c) Christian Krüger, latest change: 17-Jul-2016 ; ; This software is provided 'as-is', without any expressed or implied ; warranty. In no event will the authors be held liable for any damages ; arising from the use of this software. ; ; Permission is granted to anyone to use this software for any purpose, ; including commercial applications, and to alter it and redistribute it ; freely, subject to the following restrictions: ; ; 1. The origin of this software must not be misrepresented; you must not ; claim that you wrote the original software. If you use this software ; in a product, an acknowledgment in the product documentation would be ; appreciated but is not required. ; 2. Altered source versions must be plainly marked as such, and must not ; be misrepresented as being the original software. ; 3. This notice may not be removed or altered from any source ; distribution. ; .define _SMCDesignator .mid(0, .tcount(label) - 1, label) .ident(.concat(.string(.right(1, label)), "_SMC")) .define _SMCAlias .mid(0, .tcount(alias) - 1, alias) .ident(.concat(.string(.right(1, alias)), "_SMC")) .define SMC_AbsAdr $FADE .define SMC_ZpAdr $00 .define SMC_Opcode nop .define SMC_Value $42 .macro SMC_OperateOnValue opcode, label opcode _SMCDesignator+1 .endmacro .macro SMC_OperateOnLowByte opcode, label SMC_OperateOnValue opcode, label .endmacro .macro SMC_OperateOnHighByte opcode, label opcode _SMCDesignator + 2 .endmacro .macro SMC_Import alias .import _SMCAlias .endmacro .macro SMC_Export alias, label .export _SMCAlias := _SMCDesignator .endmacro .macro SMC label, statement _SMCDesignator: statement .endmacro .macro SMC_TransferOpcode label, opcode, register .if .paramcount = 2 .or .match ({register}, a) .or .match ({register}, ) lda #opcode sta _SMCDesignator .elseif .match ({register}, x) ldx #opcode stx _SMCDesignator .elseif .match ({register}, y) ldy #opcode sty _SMCDesignator .else .error "Invalid usage of macro 'SMC_TransferOpcode'" .endif .endmacro .macro SMC_LoadOpcode label, register .if .paramcount = 1 .or .match ({register}, a) .or .match ({register}, ) lda _SMCDesignator .elseif .match ({register}, x) ldx _SMCDesignator .elseif .match ({register}, y) ldy _SMCDesignator .else .error "Invalid usage of macro 'SMC_LoadOpcode'" .endif .endmacro .macro SMC_StoreOpcode label, register .if .paramcount = 1 .or .match ({register}, a) .or .match ({register}, ) sta _SMCDesignator .elseif .match ({register}, x) stx _SMCDesignator .elseif .match ({register}, y) sty _SMCDesignator .else .error "Invalid usage of macro 'SMC_StoreOpcode'" .endif .endmacro .macro SMC_ChangeBranch label, destination, register .if .paramcount = 2 .or .match ({register}, a) .or .match ({register}, ) lda #(<(destination - _SMCDesignator -2)) sta _SMCDesignator+1 .elseif .match ({register}, x) ldx #(<(destination - _SMCDesignator - 2)) stx _SMCDesignator+1 .elseif .match ({register}, y) ldy #(<(destination - _SMCDesignator - 2)) sty _SMCDesignator+1 .else .error "Invalid usage of macro 'SMC_ChangeBranch'" .endif .endmacro .macro SMC_TransferValue label, value, register .if .paramcount = 2 .or .match ({register}, a) .or .match ({register}, ) lda value sta _SMCDesignator+1 .elseif .match ({register}, x) ldx value stx _SMCDesignator+1 .elseif .match ({register}, y) ldy value sty _SMCDesignator+1 .else .error "Invalid usage of macro 'SMC_TransferValue'" .endif .endmacro .macro SMC_LoadValue label, register .if .paramcount = 1 .or .match ({register}, a) .or .match ({register}, ) lda _SMCDesignator+1 .elseif .match ({register}, x) ldx _SMCDesignator+1 .elseif .match ({register}, y) ldy _SMCDesignator+1 .else .error "Invalid usage of macro 'SMC_LoadValue'" .endif .endmacro .macro SMC_StoreValue label, register .if .paramcount = 1 .or .match ({register}, a) .or .match ({register}, ) sta _SMCDesignator+1 .elseif .match ({register}, x) stx _SMCDesignator+1 .elseif .match ({register}, y) sty _SMCDesignator+1 .else .error "Invalid usage of macro 'SMC_StoreValue'" .endif .endmacro .macro SMC_TransferLowByte label, value, register SMC_TransferValue label, value, register .endmacro .macro SMC_LoadLowByte label, register SMC_LoadValue label, register .endmacro .macro SMC_StoreLowByte label, register SMC_StoreValue label, register .endmacro .macro SMC_TransferHighByte label, value, register .if .paramcount = 2 .or .match ({register}, a) .or .match ({register}, ) lda value sta _SMCDesignator+2 .elseif .match ({register}, x) ldx value stx _SMCDesignator+2 .elseif .match ({register}, y) ldy value sty _SMCDesignator+2 .else .error "Invalid usage of macro 'SMC_TransferHighByte'" .endif .endmacro .macro SMC_LoadHighByte label, register .if .paramcount = 1 .or .match ({register}, a) .or .match ({register}, ) lda _SMCDesignator+2 .elseif .match ({register}, x) ldx _SMCDesignator+2 .elseif .match ({register}, y) ldy _SMCDesignator+2 .else .error "Invalid usage of macro 'SMC_LoadHighByte'" .endif .endmacro .macro SMC_StoreHighByte label, register .if .paramcount = 1 .or .match ({register}, a) .or .match ({register}, ) sta _SMCDesignator+2 .elseif .match ({register}, x) stx _SMCDesignator+2 .elseif .match ({register}, y) sty _SMCDesignator+2 .else .error "Invalid usage of macro 'SMC_StoreHighByte'" .endif .endmacro .macro SMC_TransferAddressSingle label, address, register .if .paramcount = 2 .or .match ((register), a) .or .match ({register}, ) .if (.match (.left (1, {address}), #)) ; immediate mode lda #<(.right (.tcount ({address})-1, {address})) sta _SMCDesignator+1 lda #>(.right (.tcount ({address})-1, {address})) sta _SMCDesignator+2 .else ; assume absolute or zero page lda address sta _SMCDesignator+1 lda 1+(address) sta _SMCDesignator+2 .endif .elseif .match ((register), x) .if (.match (.left (1, {address}), #)) ; immediate mode ldx #<(.right (.tcount ({address})-1, {address})) stx _SMCDesignator+1 ldx #>(.right (.tcount ({address})-1, {address})) stx _SMCDesignator+2 .else ; assume absolute or zero page ldx address stx _SMCDesignator+1 ldx 1+(address) stx _SMCDesignator+2 .endif .elseif .match ((register), y) .if (.match (.left (1, {address}), #)) ; immediate mode ldy #<(.right (.tcount ({address})-1, {address})) sty _SMCDesignator+1 ldy #>(.right (.tcount ({address})-1, {address})) sty _SMCDesignator+2 .else ; assume absolute or zero page ldy address sty _SMCDesignator+1 ldy 1+(address) sty _SMCDesignator+2 .endif .else .error "Invalid usage of macro 'SMC_TransferAddressSingle'" .endif .endmacro .macro SMC_TransferAddress label, address .if (.match (.left (1, {address}), #)) ; immediate mode lda #<(.right (.tcount ({address})-1, {address})) sta _SMCDesignator+1 ldx #>(.right (.tcount ({address})-1, {address})) stx _SMCDesignator+2 .else ; assume absolute or zero page lda {address} sta _SMCDesignator+1 ldx 1+{address} stx _SMCDesignator)+2 .endif .endmacro .macro SMC_StoreAddress label sta _SMCDesignator+1 stx _SMCDesignator+2 .endmacro