]> git.sur5r.net Git - cc65/commitdiff
Added a macro package for writing self modyfying code. By Christian Krüger.
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 21 Feb 2012 20:02:20 +0000 (20:02 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 21 Feb 2012 20:02:20 +0000 (20:02 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@5536 b7a2c559-68d2-44c3-8de9-860c34a00d81

asminc/opcodes.inc [new file with mode: 0644]
asminc/smc.mac [new file with mode: 0644]
doc/Makefile
doc/index.sgml
doc/smc.sgml [new file with mode: 0644]

diff --git a/asminc/opcodes.inc b/asminc/opcodes.inc
new file mode 100644 (file)
index 0000000..7c52871
--- /dev/null
@@ -0,0 +1,509 @@
+; opcodes.inc\r
+; ca65 6502 - opcode definitions, mainly for self modifying code\r
+;\r
+; Christian Krüger, latest change: 18-Sep-2010\r
+;\r
+; This software is provided 'as-is', without any expressed or implied      \r
+; warranty.  In no event will the authors be held liable for any damages   \r
+; arising from the use of this software.                                   \r
+;                                                                          \r
+; Permission is granted to anyone to use this software for any purpose,    \r
+; including commercial applications, and to alter it and redistribute it   \r
+; freely, subject to the following restrictions:                           \r
+;                                                                          \r
+; 1. The origin of this software must not be misrepresented; you must not  \r
+;    claim that you wrote the original software. If you use this software  \r
+;    in a product, an acknowledgment in the product documentation would be \r
+;    appreciated but is not required.                                      \r
+; 2. Altered source versions must be plainly marked as such, and must not  \r
+;    be misrepresented as being the original software.                     \r
+; 3. This notice may not be removed or altered from any source             \r
+;    distribution.                                                         \r
+;                                                                          \r
+\r
+; Opcode-Table\r
+; ------------\r
+; Post fix explanation:\r
+; imm = #$00\r
+; zp = $00\r
+; zpx = $00,X\r
+; zpy = $00,Y\r
+; izp = ($00)\r
+; izx = ($00,X)\r
+; izy = ($00),Y\r
+; abs = $0000\r
+; abx = $0000,X\r
+; aby = $0000,Y\r
+; ind = ($0000)\r
+; iax = ($0000,X)\r
+; rel = $0000 (PC-relative) (supressed here)\r
+\r
+.macpack        cpu\r
+\r
+OPC_BRK     = $00\r
+OPC_ORA_izx = $01\r
+OPC_ORA_zp  = $05\r
+OPC_ASL_zp  = $06\r
+OPC_PHP     = $08\r
+OPC_ORA_imm = $09\r
+OPC_ASL     = $0A\r
+OPC_ORA_abs = $0D\r
+OPC_ASL_abs = $0E\r
+\r
+OPC_BPL     = $10\r
+OPC_ORA_izy = $11\r
+OPC_ORA_zpx = $15\r
+OPC_ASL_zpx = $16\r
+OPC_CLC     = $18\r
+OPC_ORA_aby = $19\r
+OPC_ORA_abx = $1D\r
+OPC_ASL_abx = $1E\r
+\r
+OPC_JSR_abs = $20\r
+OPC_AND_izx = $21\r
+OPC_BIT_zp  = $24\r
+OPC_AND_zp  = $25\r
+OPC_ROL_zp  = $26\r
+OPC_PLP     = $28\r
+OPC_AND_imm = $29\r
+OPC_ROL     = $2A\r
+OPC_BIT_abs = $2C\r
+OPC_AND_abs = $2D\r
+OPC_ROL_abs = $2E\r
+\r
+OPC_BMI     = $30\r
+OPC_AND_izy = $31\r
+OPC_AND_zpx = $35\r
+OPC_ROL_zpx = $36\r
+OPC_SEC     = $38\r
+OPC_AND_aby = $39\r
+OPC_AND_abx = $3D\r
+OPC_ROL_abx = $3E\r
+\r
+\r
+OPC_RTI     = $40\r
+OPC_EOR_izx = $41\r
+OPC_EOR_zp  = $45\r
+OPC_LSR_zp  = $46\r
+OPC_PHA     = $48\r
+OPC_EOR_imm = $49\r
+OPC_LSR     = $4A\r
+OPC_JMP_abs = $4C\r
+OPC_EOR_abs = $4D\r
+OPC_LSR_abs = $4E\r
+\r
+OPC_BVC     = $50\r
+OPC_EOR_izy = $51\r
+OPC_EOR_zpx = $55\r
+OPC_LSR_zpx = $56\r
+OPC_CLI     = $58\r
+OPC_EOR_aby = $59\r
+OPC_EOR_abx = $5D\r
+OPC_LSR_abx = $5E\r
+\r
+OPC_RTS     = $60\r
+OPC_ADC_izx = $61\r
+OPC_ADC_zp  = $65\r
+OPC_ROR_zp  = $66\r
+OPC_PLA     = $68\r
+OPC_ADC_imm = $69\r
+OPC_ROR     = $6A\r
+OPC_JMP_ind = $6C\r
+OPC_ADC_abs = $6D\r
+OPC_ROR_abs = $6E\r
+\r
+OPC_BVS     = $70\r
+OPC_ADC_izy = $71\r
+OPC_ADC_zpx = $75\r
+OPC_ROR_zpx = $76\r
+OPC_SEI     = $78\r
+OPC_ADC_aby = $79\r
+OPC_ADC_abx = $7D\r
+OPC_ROR_abx = $7E\r
+\r
+OPC_STA_izx = $81\r
+OPC_STY_zp  = $84\r
+OPC_STA_zp  = $85\r
+OPC_STX_zp  = $86\r
+OPC_DEY     = $88\r
+OPC_TXA     = $8A\r
+OPC_STY_abs = $8C\r
+OPC_STA_abs = $8D\r
+OPC_STX_abs = $8E\r
+\r
+OPC_BCC     = $90\r
+OPC_STA_izy = $91\r
+OPC_STY_zpx = $94\r
+OPC_STA_zpx = $95\r
+OPC_STX_zpy = $96\r
+OPC_TYA     = $98\r
+OPC_STA_aby = $99\r
+OPC_TXS     = $9A\r
+OPC_STA_abx = $9D\r
+\r
+OPC_LDY_imm = $A0\r
+OPC_LDA_izx = $A1\r
+OPC_LDX_imm = $A2\r
+OPC_LDY_zp  = $A4\r
+OPC_LDA_zp  = $A5\r
+OPC_LDX_zp  = $A6\r
+OPC_TAY     = $A8\r
+OPC_LDA_imm = $A9\r
+OPC_TAX     = $AA\r
+OPC_LDY_abs = $AC\r
+OPC_LDA_abs = $AD\r
+OPC_LDX_abs = $AE\r
+\r
+OPC_BCS     = $B0\r
+OPC_LDA_izy = $B1\r
+OPC_LDY_zpx = $B4\r
+OPC_LDA_zpx = $B5\r
+OPC_LDX_zpy = $B6\r
+OPC_CLV     = $B8\r
+OPC_LDA_aby = $B9\r
+OPC_TSX     = $BA\r
+OPC_LDY_abx = $BC\r
+OPC_LDA_abx = $BD\r
+OPC_LDX_aby = $BE\r
+\r
+OPC_CPY_imm = $C0\r
+OPC_CMP_izx = $C1\r
+OPC_CPY_zp  = $C4\r
+OPC_CMP_zp  = $C5\r
+OPC_DEC_zp  = $C6\r
+OPC_INY     = $C8\r
+OPC_CMP_imm = $C9\r
+OPC_DEX     = $CA\r
+OPC_CPY_abs = $CC\r
+OPC_CMP_abs = $CD\r
+OPC_DEC_abs = $CE\r
+\r
+OPC_BNE     = $D0\r
+OPC_CMP_izy = $D1\r
+OPC_CMP_zpx = $D5\r
+OPC_DEC_zpx = $D6\r
+OPC_CLD     = $D8\r
+OPC_CMP_aby = $D9\r
+OPC_CMP_abx = $DD\r
+OPC_DEC_abx = $DE\r
+\r
+OPC_CPX_imm = $E0\r
+OPC_SBC_izx = $E1\r
+OPC_CPX_zp  = $E4\r
+OPC_SBC_zp  = $E5\r
+OPC_INC_zp  = $E6\r
+OPC_INX     = $E8\r
+OPC_SBC_imm = $E9\r
+OPC_NOP     = $EA\r
+OPC_CPX_abs = $EC\r
+OPC_SBC_abs = $ED\r
+OPC_INC_abs = $EE\r
+\r
+\r
+OPC_BEQ     = $F0\r
+OPC_SBC_izy = $F1\r
+OPC_SBC_zpx = $F5\r
+OPC_INC_zpx = $F6\r
+OPC_SED     = $F8\r
+OPC_SBC_aby = $F9\r
+OPC_SBC_abx = $FD\r
+OPC_INC_abx = $FE\r
+\r
+\r
+.if (.cpu .bitand ::CPU_ISET_65SC02)\r
+\r
+; OPC_NOP   = $02               ; doublet\r
+; OPC_NOP   = $03               ; doublet\r
+OPC_TSB_zp  = $04\r
+; OPC_NOP   = $0B               ; doublet\r
+OPC_TSB_abs = $0C\r
+\r
+OPC_ORA_izp = $12\r
+; OPC_NOP   = $13               ; doublet\r
+OPC_TRB_zp  = $14\r
+OPC_INC     = $1A\r
+; OPC_NOP   = $1B               ; doublet\r
+OPC_TRB_abs = $1C\r
+\r
+; OPC_NOP   = $22               ; doublet\r
+; OPC_NOP   = $23               ; doublet\r
+; OPC_NOP   = $2B               ; doublet\r
+\r
+OPC_AND_izp = $32\r
+; OPC_NOP   = $33               ; doublet\r
+OPC_BIT_zpx = $34\r
+OPC_DEC     = $3A\r
+; OPC_NOP   = $3B               ; doublet\r
+OPC_BIT_abx = $3C\r
+\r
+; OPC_NOP   = $42               ; doublet\r
+; OPC_NOP   = $43               ; doublet\r
+; OPC_NOP   = $44               ; doublet\r
+; OPC_NOP   = $4B               ; doublet\r
+\r
+OPC_EOR_izp = $52               \r
+; OPC_NOP   = $53               ; doublet\r
+; OPC_NOP   = $54               ; doublet\r
+; OPC_NOP   = $5A               ; doublet\r
+; OPC_NOP   = $5B               ; doublet\r
+OPC_EOR_abx = $5C\r
+\r
+; OPC_NOP   = $62               ; doublet\r
+; OPC_NOP   = $63               ; doublet\r
+OPC_STZ_zp  = $64\r
+; OPC_NOP   = $6B               ; doublet\r
+\r
+OPC_ADC_izp = $72\r
+; OPC_NOP   = $73               ; doublet\r
+OPC_STZ_zpx = $74\r
+OPC_PLY     = $7A\r
+; OPC_NOP   = $7B               ; doublet\r
+OPC_JMP_iax = $7C\r
+\r
+OPC_BRA     = $80\r
+; OPC_NOP   = $82               ; doublet\r
+; OPC_NOP   = $83               ; doublet\r
+OPC_BIT_imm = $89\r
+; OPC_NOP   = $8B               ; doublet\r
+\r
+OPC_STA_izp = $92\r
+; OPC_NOP   = $93               ; doublet\r
+; OPC_NOP   = $9B               ; doublet\r
+OPC_STZ_abs = $9C\r
+OPC_STZ_abx = $9E\r
+\r
+; OPC_NOP   = $A3               ; doublet\r
+; OPC_NOP   = $AB               ; doublet\r
+\r
+OPC_LDA_izp = $B2\r
+; OPC_NOP   = $B3               ; doublet\r
+; OPC_NOP   = $BB               ; doublet\r
+\r
+; OPC_NOP   = $C2               ; doublet\r
+; OPC_NOP   = $C3               ; doublet\r
+; OPC_NOP   = $CB               ; doublet\r
+\r
+OPC_CMP_izp = $D2\r
+; OPC_NOP   = $D3               ; doublet\r
+; OPC_NOP   = $D4               ; doublet\r
+OPC_PHX     = $DA\r
+; OPC_NOP   = $DB               ; doublet\r
+; OPC_NOP   = $DC               ; doublet\r
+\r
+; OPC_NOP   = $E2               ; doublet\r
+; OPC_NOP   = $E3               ; doublet\r
+; OPC_NOP   = $EB               ; doublet\r
+\r
+OPC_SBC_izp = $F2\r
+; OPC_NOP   = $F3               ; doublet\r
+; OPC_NOP   = $F4               ; doublet\r
+OPC_PLX     = $FA\r
+; OPC_NOP   = $FB               ; doublet\r
+; OPC_NOP   = $FC               ; doublet\r
+\r
+\r
+.if (.cpu .bitand ::CPU_ISET_65C02)\r
+\r
+; bit instructions for 65C02\r
+\r
+OPC_RMB0    = $07\r
+OPC_RMB1    = $17\r
+OPC_RMB2    = $27\r
+OPC_RMB3    = $37\r
+OPC_RMB4    = $47\r
+OPC_RMB5    = $57\r
+OPC_RMB6    = $67\r
+OPC_RMB7    = $77\r
+\r
+OPC_SMB0    = $87\r
+OPC_SMB1    = $97\r
+OPC_SMB2    = $A7\r
+OPC_SMB3    = $B7\r
+OPC_SMB4    = $C7\r
+OPC_SMB5    = $D7\r
+OPC_SMB6    = $E7\r
+OPC_SMB7    = $F7\r
+\r
+OPC_BBR0    = $0F\r
+OPC_BBR1    = $1F\r
+OPC_BBR2    = $2F\r
+OPC_BBR3    = $3F\r
+OPC_BBR4    = $4F\r
+OPC_BBR5    = $5F\r
+OPC_BBR6    = $6F\r
+OPC_BBR7    = $7F\r
+\r
+OPC_BBS0    = $8F\r
+OPC_BBS1    = $9F\r
+OPC_BBS2    = $AF\r
+OPC_BBS3    = $BF\r
+OPC_BBS4    = $CF\r
+OPC_BBS5    = $DF\r
+OPC_BBS6    = $EF\r
+OPC_BBS7    = $FF\r
+\r
+.else\r
+\r
+; no bit instructions for 65SC02\r
+\r
+; OPC_NOP   = $07               ; doublet\r
+; OPC_NOP   = $17               ; doublet\r
+; OPC_NOP   = $27               ; doublet\r
+; OPC_NOP   = $37               ; doublet\r
+; OPC_NOP   = $47               ; doublet\r
+; OPC_NOP   = $57               ; doublet\r
+; OPC_NOP   = $67               ; doublet\r
+; OPC_NOP   = $77               ; doublet\r
+; OPC_NOP   = $87               ; doublet\r
+; OPC_NOP   = $97               ; doublet\r
+; OPC_NOP   = $A7               ; doublet\r
+; OPC_NOP   = $B7               ; doublet\r
+; OPC_NOP   = $C7               ; doublet\r
+; OPC_NOP   = $D7               ; doublet\r
+; OPC_NOP   = $E7               ; doublet\r
+; OPC_NOP   = $F7               ; doublet\r
+; OPC_NOP   = $0F               ; doublet\r
+; OPC_NOP   = $1F               ; doublet\r
+; OPC_NOP   = $2F               ; doublet\r
+; OPC_NOP   = $3F               ; doublet\r
+; OPC_NOP   = $4F               ; doublet\r
+; OPC_NOP   = $5F               ; doublet\r
+; OPC_NOP   = $6F               ; doublet\r
+; OPC_NOP   = $7F               ; doublet\r
+; OPC_NOP   = $8F               ; doublet\r
+; OPC_NOP   = $9F               ; doublet\r
+; OPC_NOP   = $AF               ; doublet\r
+; OPC_NOP   = $BF               ; doublet\r
+; OPC_NOP   = $CF               ; doublet\r
+; OPC_NOP   = $DF               ; doublet\r
+; OPC_NOP   = $EF               ; doublet\r
+; OPC_NOP   = $FF               ; doublet\r
+\r
+.endif\r
+\r
+.elseif (.cpu .bitand ::CPU_ISET_6502X)\r
+\r
+; stable, undocumented opcodes\r
+\r
+; OPC_KIL   = $02               ; unstable\r
+OPC_SLO_izx = $03\r
+OPC_NOP_zp  = $04\r
+OPC_SLO_zp  = $07\r
+OPC_ANC_imm = $0B\r
+OPC_NOP_abs = $0C\r
+OPC_SLO_abs = $0F\r
+\r
+; OPC_KIL   = $12               ; unstable\r
+OPC_SLO_izy = $13\r
+OPC_NOP_zpx = $14\r
+OPC_SLO_zpx = $17\r
+;OPC_NOP    = $1A\r
+OPC_SLO_aby = $1B\r
+OPC_NOP_abx = $1C\r
+OPC_SLO_abx = $1F\r
+\r
+; OPC_KIL   = $22               ; unstable\r
+OPC_RLA_izx = $23\r
+OPC_RLA_zp  = $27\r
+OPC_ANC_imm = $2B\r
+OPC_RLA_abs = $2F\r
+\r
+; OPC_KIL   = $32               ; unstable\r
+OPC_RLA_izy = $33\r
+OPC_NOP_zpx = $34\r
+OPC_RLA_zpx = $37\r
+; OPC_NOP   = $3A               ; doublet\r
+OPC_RLA_aby = $3B\r
+OPC_NOP_abx = $3C\r
+OPC_RLA_abx = $3F\r
+\r
+; OPC_KIL   = $42               ; unstable\r
+OPC_SRE_izx = $43\r
+OPC_NOP_zp  = $44\r
+OPC_SRE_zp  = $47\r
+OPC_ALR_imm = $4B\r
+OPC_SRE_abs = $4F\r
+\r
+; OPC_KIL   = $52               ; unstable\r
+OPC_SRE_izy = $53\r
+OPC_NOP_zpx = $54\r
+OPC_SRE_zpx = $57\r
+; OPC_NOP   = $5A               ; doublet\r
+OPC_SRE_aby = $5B\r
+OPC_NOP_abx = $5C\r
+OPC_SRE_abx = $5F\r
+\r
+; OPC_KIL   = $62\r
+OPC_RRA_izx = $63\r
+OPC_NOP_zp  = $64\r
+OPC_RRA_zp  = $67\r
+OPC_ARR_imm = $6B\r
+OPC_RRA_abs = $6F\r
+\r
+; OPC_KIL   = $72\r
+OPC_RRA_izy = $73\r
+OPC_NOP_zpx = $74\r
+OPC_RRA_zpx = $77\r
+; OPC_NOP   = $7A               ; doublet\r
+OPC_RRA_aby = $7B\r
+OPC_NOP_abx = $7C\r
+OPC_RRA_abx = $7F\r
+\r
+OPC_NOP_imm = $80\r
+; OPC_NOP_imm = $82             ; doublet\r
+OPC_SAX_izx = $83\r
+OPC_SAX_zp  = $87\r
+; OPC_NOP_imm = $89             ; doublet\r
+; OPC_XAA = $8B                 ; unstable\r
+OPC_SAX_abs = $8F\r
+\r
+; OPC_KIL   = $92               ; unstable\r
+; OPC_AHX_izy = $93             ; unstable\r
+OPC_SAX_zpy = $97\r
+; OPC_TAS_aby = $9B             ; unstable\r
+; OPC_SHY_abx = $9C             ; unstable\r
+; OPC_SHX_aby = $9E             ; unstable\r
+; OPC_AHX_aby = $9F             ; unstable\r
+\r
+OPC_LAX_izx = $A3\r
+OPC_LAX_zp  = $A7\r
+; OPC_LAX_imm = $AB             ; unstable\r
+OPC_LAX_abs = $AF\r
+\r
+; OPC_KIL   = $B2               ; unstable\r
+OPC_LAX_izy = $B3\r
+OPC_LAX_zpy = $B7\r
+OPC_LAS_aby = $BB\r
+OPC_LAX_aby = $BF\r
+\r
+; OPC_NOP_imm = $C2             ; doublet\r
+OPC_DCP_izx = $C3\r
+OPC_DCP_zp  = $C7\r
+OPC_AXS_imm = $CB\r
+OPC_DCP_abs = $CF\r
+\r
+; OPC_KIL   = $D2               ; unstable\r
+OPC_DCP_izy = $D3\r
+OPC_NOP_zpx = $D4\r
+OPC_DCP_zpx = $D7\r
+OPC_NOP_DA  = $DA\r
+OPC_DCP_aby = $DB\r
+OPC_NOP_abx = $DC\r
+OPC_DCP_abx = $DF\r
+\r
+; OPC_NOP_imm = $E2             ; doublet\r
+OPC_ISC_izx = $E3\r
+OPC_ISC_zp  = $E7\r
+; OPC_SBC_imm = $EB             ; doublet\r
+OPC_ISC_abs = $EF\r
+\r
+; OPC_KIL   = $F2               ; unstable\r
+OPC_ISC_izy = $F3\r
+OPC_NOP_zpx = $F4\r
+OPC_ISC_zpx = $F7\r
+OPC_NOP_FA  = $FA\r
+OPC_ISC_aby = $FB\r
+OPC_NOP_abx = $FC\r
+OPC_ISC_abx = $FF\r
+\r
+.endif\r
diff --git a/asminc/smc.mac b/asminc/smc.mac
new file mode 100644 (file)
index 0000000..42dcb10
--- /dev/null
@@ -0,0 +1,249 @@
+; smc.mac\r
+; ca65 Macro-Pack for Self Modifying Code (SMC)\r
+;\r
+; (c) Christian Krüger, latest change: 09-Nov-2011\r
+;\r
+; This software is provided 'as-is', without any expressed or implied\r
+; warranty.  In no event will the authors be held liable for any damages\r
+; arising from the use of this software.\r
+;\r
+; Permission is granted to anyone to use this software for any purpose,\r
+; including commercial applications, and to alter it and redistribute it\r
+; freely, subject to the following restrictions:\r
+;\r
+; 1. The origin of this software must not be misrepresented; you must not\r
+;    claim that you wrote the original software. If you use this software\r
+;    in a product, an acknowledgment in the product documentation would be\r
+;    appreciated but is not required.\r
+; 2. Altered source versions must be plainly marked as such, and must not\r
+;    be misrepresented as being the original software.\r
+; 3. This notice may not be removed or altered from any source\r
+;    distribution.\r
+;\r
+\r
+.define _SMCDesignator .mid(0, .tcount(label) - 1, label) .ident(.concat(.string(.right(1, label)), "_SMC"))\r
+.define _SMCAlias .mid(0, .tcount(alias) - 1, alias) .ident(.concat(.string(.right(1, alias)), "_SMC"))\r
+.define SMC_AbsAdr      $FADE\r
+.define SMC_ZpAdr               $00\r
+.define SMC_Opcode      nop\r
+.define SMC_Value               $42\r
+\r
+.macro SMC_OperateOnValue opcode, label\r
+        opcode _SMCDesignator+1\r
+.endmacro\r
+\r
+.macro SMC_OperateOnLowByte opcode, label\r
+        SMC_OperateOnValue opcode, label\r
+.endmacro\r
+\r
+.macro SMC_OperateOnHighByte opcode, label\r
+        opcode _SMCDesignator + 2\r
+.endmacro\r
+\r
+.macro SMC_Import alias\r
+.import _SMCAlias\r
+.endmacro\r
+\r
+.macro SMC_Export alias, label\r
+.export _SMCAlias := _SMCDesignator\r
+.endmacro\r
+\r
+.macro  SMC    label, statement\r
+_SMCDesignator: statement\r
+.endmacro\r
+\r
+.macro SMC_TransferOpcode       label, opcode, register\r
+.if .paramcount = 2 .or .match ({register}, a)\r
+                        lda #opcode\r
+                        sta _SMCDesignator\r
+.elseif .match ({register}, x)\r
+                        ldx #opcode\r
+                        stx _SMCDesignator\r
+.elseif .match ({register}, y)\r
+                        ldy #opcode\r
+                        sty _SMCDesignator\r
+.endif\r
+.endmacro\r
+\r
+.macro SMC_LoadOpcode   label, register\r
+.if .paramcount = 1 .or .match ({register}, a)\r
+                        lda _SMCDesignator\r
+.elseif .match ({register}, x)\r
+                        ldx _SMCDesignator\r
+.elseif .match ({register}, y)\r
+                        ldy _SMCDesignator\r
+.endif\r
+.endmacro\r
+\r
+.macro SMC_StoreOpcode  label, register\r
+.if .paramcount = 1 .or .match ({register}, a)\r
+                        sta _SMCDesignator\r
+.elseif .match ({register}, x)\r
+                        stx _SMCDesignator\r
+.elseif .match ({register}, y)\r
+                        sty _SMCDesignator\r
+.endif\r
+.endmacro\r
+\r
+.macro SMC_ChangeBranch         label, destination, register\r
+.if .paramcount = 2 .or .match ({register}, a)\r
+                        lda #(destination - _SMCDesignator -2)\r
+                        sta _SMCDesignator+1\r
+.elseif .match ({register}, x)\r
+                        ldx #(destination - _SMCDesignator - 2)\r
+                        stx _SMCDesignator+1\r
+.elseif .match ({register}, y)\r
+                        ldy #(destination - _SMCDesignator - 2)\r
+                        sty _SMCDesignator+1\r
+.endif\r
+.endmacro\r
+\r
+.macro SMC_TransferValue        label, value, register\r
+.if .paramcount = 2 .or .match ({register}, a)\r
+                        lda value\r
+                        sta _SMCDesignator+1\r
+.elseif .match ({register}, x)\r
+                        ldx value\r
+                        stx _SMCDesignator+1\r
+.elseif .match ({register}, y)\r
+                        ldy value\r
+                        sty _SMCDesignator+1\r
+.endif\r
+.endmacro\r
+\r
+.macro SMC_LoadValue    label, register\r
+.if .paramcount = 1 .or .match ({register}, a)\r
+                        lda _SMCDesignator+1\r
+.elseif .match ({register}, x)\r
+                        ldx _SMCDesignator+1\r
+.elseif .match ({register}, y)\r
+                        ldy _SMCDesignator+1\r
+.endif\r
+.endmacro\r
+\r
+.macro SMC_StoreValue   label, register\r
+.if .paramcount = 1 .or .match ({register}, a)\r
+                        sta _SMCDesignator+1\r
+.elseif .match ({register}, x)\r
+                        stx _SMCDesignator+1\r
+.elseif .match ({register}, y)\r
+                        sty _SMCDesignator+1\r
+.endif\r
+.endmacro\r
+\r
+\r
+.macro SMC_TransferLowByte      label, value, register\r
+SMC_TransferValue label, value, register\r
+.endmacro\r
+\r
+.macro SMC_LoadLowByte  label, register\r
+SMC_LoadValue label, register\r
+.endmacro\r
+\r
+.macro SMC_StoreLowByte label, register\r
+SMC_StoreValue label, register\r
+.endmacro\r
+\r
+.macro SMC_TransferHighByte     label, value, register\r
+.if .paramcount = 2 .or .match ({register}, a)\r
+                        lda    value\r
+                        sta _SMCDesignator+2\r
+.elseif .match ({register}, x)\r
+                        ldx value\r
+                        stx _SMCDesignator+2\r
+.elseif .match ({register}, y)\r
+                        ldy value\r
+                        sty _SMCDesignator+2\r
+.endif\r
+.endmacro\r
+\r
+.macro SMC_LoadHighByte label, register\r
+.if .paramcount = 1 .or .match ({register}, a)\r
+                        lda _SMCDesignator+2\r
+.elseif .match ({register}, x)\r
+                        ldx _SMCDesignator+2\r
+.elseif .match ({register}, y)\r
+                        ldy _SMCDesignator+2\r
+.endif\r
+.endmacro\r
+\r
+.macro SMC_StoreHighByte        label, register\r
+.if .paramcount = 1 .or .match ({register}, a)\r
+                        sta _SMCDesignator+2\r
+.elseif .match ({register}, x)\r
+                        stx _SMCDesignator+2\r
+.elseif .match ({register}, y)\r
+                        sty _SMCDesignator+2\r
+.endif\r
+.endmacro\r
+\r
+\r
+.macro SMC_TransferAddressSingle        label, address, register\r
+.if .paramcount = 2 .or .match ((register), a)\r
+        .if (.match (.left (1, {adress}), #))\r
+                ; immediate mode\r
+        lda     #<(.right (.tcount ({adress})-1, {adress}))\r
+                sta _SMCDesignator+1\r
+        lda #>(.right (.tcount ({adress})-1, {adress}))\r
+                sta _SMCDesignator+2\r
+    .else\r
+        ; assume absolute or zero page\r
+                lda    address\r
+                sta _SMCDesignator+1\r
+                lda 1+(address)\r
+                sta _SMCDesignator+2\r
+        .endif\r
+.elseif .match ((register), x)\r
+        .if (.match (.left (1, {adress}), #))\r
+                ; immediate mode\r
+        ldx     #<(.right (.tcount ({adress})-1, {adress}))\r
+                stx _SMCDesignator+1\r
+        ldx #>(.right (.tcount ({adress})-1, {adress}))\r
+                stx _SMCDesignator+2\r
+    .else\r
+        ; assume absolute or zero page\r
+                ldx    address\r
+                stx _SMCDesignator+1\r
+                ldx 1+(address)\r
+                stx _SMCDesignator+2\r
+        .endif\r
+.elseif .match ((register), y)\r
+        .if (.match (.left (1, {adress}), #))\r
+                ; immediate mode\r
+        ldy     #<(.right (.tcount ({adress})-1, {adress}))\r
+                sty _SMCDesignator+1\r
+        ldy #>(.right (.tcount ({adress})-1, {adress}))\r
+                sty _SMCDesignator+2\r
+    .else\r
+        ; assume absolute or zero page\r
+                ldy    address\r
+                sty _SMCDesignator+1\r
+                ldy 1+(address)\r
+                sty _SMCDesignator+2\r
+        .endif\r
+.endif\r
+.endmacro\r
+\r
+\r
+.macro SMC_TransferAddress      label, address\r
+.if (.match (.left (1, {adress}), #))\r
+        ; immediate mode\r
+        lda    #<(.right (.tcount ({adress})-1, {adress}))\r
+        sta _SMCDesignator+1\r
+        ldx #>(.right (.tcount ({adress})-1, {adress}))\r
+        stx _SMCDesignator+2\r
+.else\r
+        ; assume absolute or zero page\r
+        lda    {address}\r
+        sta _SMCDesignator+1\r
+        ldx 1+{address}\r
+        stx _SMCDesignator)+2\r
+.endif\r
+.endmacro\r
+\r
+.macro SMC_StoreAddress label\r
+                sta _SMCDesignator+1\r
+                stx _SMCDesignator+2\r
+.endmacro\r
+\r
+\r
index 5534baadde7411af4e9664195e37cdd611916645..169e6438154a58a828e326bef77da8878b4c9074 100644 (file)
@@ -49,6 +49,7 @@ SGML =        apple2.sgml     \
         od65.sgml       \
        pet.sgml        \
        plus4.sgml      \
+        smc.sgml        \
         supervision.sgml\
        vic20.sgml
 
index 0d84a367c77c5e96d77029714415bd662551b7a5..868a4e8591343e97cef2bf9fcd35ef72905e4483 100644 (file)
@@ -94,6 +94,10 @@ Main documentation page, contains links to other available stuff.
   <tag><htmlurl url="library.html" name="library.html"></tag>
   An overview over the cc65 runtime and C libraries.
 
+  <tag><htmlurl url="smc.html" name="smc.html"></tag>
+  Describes Christian Kr&uuml;gers macro package for writing self modifying
+  assembler code.
+
   <tag><url name="6502 Binary Relocation Format document"
         url="http://www.6502.org/users/andre/o65/fileformat.html"></tag>
   Describes the o65 file format that is used for dynamically loadable modules
diff --git a/doc/smc.sgml b/doc/smc.sgml
new file mode 100644 (file)
index 0000000..01a9777
--- /dev/null
@@ -0,0 +1,596 @@
+<!doctype linuxdoc system>
+
+<article>
+<title>ca65 Macros for Self Modifying Code
+<author>Christian Kr&uuml;ger
+<date>2012-02-19
+
+<abstract>
+The 'smc.mac' macro package for ca65 eases the use, increases the safeness and
+self-explanation of 'self-modifying-code' (SMC).
+</abstract>
+
+<!-- Table of contents -->
+<toc>
+
+<!-- Begin the document -->
+
+<sect>Overview<p>
+When reading assembler sources, self modifying code is often hard to identify
+and applying it needs a lot of discipline.
+
+Since the cacheless 6502 is a thankful target of such kind of code, the macro
+package will not only reduce this complexness, but also document the use. The
+resulting source is more self-explanatory and so easier to maintain.
+
+While for general purposes SMC is not a desired form for implementations, it
+can be quite useful for a small range of scenarios. Normally SMC will be
+introduced when optimizing code in respect to:
+
+<itemize>
+<item>speed and/or
+<item>size.
+</itemize>
+
+Please mind that SMC can only be applied for code in RAM, which means that a
+general purpose library with SMC excludes ROM targets!
+
+The ca65 SMC macro package consists of two files:
+
+<itemize>
+<item><tt>smc.mac</tt>
+<item><tt>opcodes.inc</tt>
+</itemize>
+
+The latter is only needed if you also plan to modify opcodes and not only data
+within your code.
+
+<sect>Usage<p>
+The use of the macros is quite simple:
+
+Original:
+
+<tscreen><verb>
+    PHA
+    JSR SUBROUTINE
+    PLA
+</verb></tscreen>
+
+By applying SMC, the speed will now be increased by once cycle:
+
+SMC:
+
+<tscreen><verb>
+    SMC_StoreValue RestoreAccu
+    JSR SUBROUTINE
+SMC RestoreAccu, { LDA #SMC_Value }
+</verb></tscreen>
+
+The first line stores the value of the accu into the '<tt>RestoreAccu</tt>'
+labeled SMC target.
+
+Please note:
+<enum>
+<item>  for all SMC store or transfer operations, a second argument can be
+        given. This determines the register for the operation:
+        '<tt>SMC_StoreValue Label, y</tt>' will store the value of the
+        Y-register.
+
+        If the second argument is missing, the accu will be used automatically.
+
+<item>  The label targets a 'special SMC namespace'. It fits only to
+        destinations which are introduced with the macro '<tt>SMC</tt>'. A
+        normal label '<tt>RestoreAccu</tt>' wouldn't match and could even
+        coexist (even if you should abstain from doing so).
+
+<item>  The macro '<tt>SMC_StoreValue</tt>' takes care, that the store
+        operation will occur on the value-position of a SMC-instruction. As
+        you will see, other macros influence other instruction part positions.
+        There is no consistency check, if the targeted SMC instruction acually
+        contains a value. Storing a 'value' on an immplied SMC instruction
+        would corrupt the following memory cell!
+</enum>
+
+The second line needs no further explanation, this is just a placeholder for
+some code in the example.
+
+The third line is the code line which is about to be modified. It has to start
+with the '<tt>SMC</tt>' macro and must be labeled, so that the modification
+can be designated. Then the unmodified code is given in curly braces.
+
+Please note the usage of the value placeholder 'SMC_Value'. Using such a
+placeholder has two advantages:
+
+<enum>
+<item> The code is better documented. It is clearly visible that the given
+       value is about to be changed.
+<item> When examining an (initial) disassembly (e.g. in a debugger), these
+       placegolders can be better identified: They are fixed and, you may
+       notice that below, quite eye catching defined.
+</enum>
+
+<sect1>Argument placeholders<p>
+
+There are four kinds of placeholders:
+
+<descrip>
+
+  <label id="Address placeholder">
+  <tag><tt>SMC_AbsAdr</tt></tag>
+
+  Used to indicate an address. The value is '<tt>$FADE</tt>'.
+
+  Example: <tt>STA SMC_AbsAdr</tt>
+
+
+  <label id="Zero-Page-Address placeholder">
+  <tag><tt>SMC_ZpAdr</tt></tag>
+
+  Used to indicate a zero-page-address. The value is '<tt>$00</tt>'.
+
+  Example: <tt>LDA SMC_ZpAdr</tt>
+
+
+  <label id="Opcode placeholder">
+  <tag><tt>SMC_Opcode</tt></tag>
+
+  Used to indicate an instruction. The value is '<tt>NOP</tt>'.
+
+  Example: <tt>SMC_Opcode</tt>
+
+
+  <label id="Immediate value placeholder">
+  <tag><tt>SMC_Value</tt></tag>
+
+  Used to indicate a value. The value is '<tt>$42</tt>'.
+
+  Example: <tt>LDX #SMC_Value</tt>
+</descrip>
+
+Attention: Often code is modified after the initial use - where using the
+placeholders does not makes sense. Please mind also, that in very variable
+expressions (e.g. opcode and argument is about to be changed), placeholders
+can lead to unidentifyable code for a debugger/disassembler:
+
+<tt>SMC Example, { SMC_Opcode SMC_AbsAdr } </tt>
+
+Since the opcode is '<tt/NOP/', the value '<tt/$DE/' from '<tt/$FADE/' will
+interpreted as opcode in a disassembler too. This breaks the correct
+disassembly, because '<tt/$DE/' is interpreted as '<tt/DEC abx/'. Establishing
+a valid placeholder instruction may be better:
+
+<tt>SMC Example, { sta SMC_AbsAdr }     ; Note: Opcode will be modified too!</tt>
+
+<sect1>Accessing opcodes<p>
+
+Some macros are designed to access the instruction of a code line. To increase
+readability, please use the opcodes as defined in the '<tt>opcodes.inc</tt>'
+file.
+
+<descrip>
+
+  <label id="Transfer opcode">
+  <tag><tt>SMC_TransferOpcode label, opcode (, register)</tt></tag>
+  Loads and store an opcode to given SMC instruction.
+
+  Example:
+
+<tscreen><verb>
+SMC SumRegister, { LDA #10 }
+    JSR OUTPUT
+    SMC_TransferOpcode SumRegister, OPC_ADC_imm, x
+</verb></tscreen>
+
+The macro above will load the opcode '<tt>ADC #</tt>' into the x - register
+and stores it at the place of the '<tt>LDA #</tt>'.
+
+ <label id="Load opcode">
+  <tag><tt>SMC_LoadOpcode label (, register)</tt></tag>
+  Loads the opcode of a SMC line to the given register.
+
+  Example:
+<tscreen><verb>
+SMC ShiftOrNothing, { LSL }
+    SMC_LoadOpcode ShiftOrNothing, y
+    CPY #OPC_NOP
+    BEQ Exit
+</verb></tscreen>
+
+ <label id="Store opcode">
+  <tag><tt>SMC_StoreOpcode label (, register)</tt></tag>
+  Stores the value of the given register at the opcode place of a SMC line.
+
+  Example:
+<tscreen><verb>
+SetBoldMode:
+    LDA #OPC_INX
+    SMC_StoreOpcode AdaptCharWidth
+    SMC_StoreOpcode AdaptUnderlineWidth
+    RTS
+    ...
+SMC AdaptCharWidth, { NOP }
+    ...
+SMC AdaptUnderlineWidth, { NOP }
+</verb></tscreen>
+
+</descrip>
+
+<sect1>Accessing arguments<p>
+
+These marcos are determined to get, set and change arguments of instructions:
+
+<descrip>
+
+  <label id="Change branch">
+  <tag><tt>SMC_ChangeBranch label, destination (, register)</tt></tag>
+
+  Used to modify the destination of a branch instruction. If the adress offset
+  exceeds the supported range of 8-bit of the 6502, a error will be thrown.
+
+  Example:
+<tscreen><verb>
+Disable Handler:
+    SMC_ChangeBranch BranchToHandler, Exit
+    RTS
+    ...
+    LDA warning
+SMC BranchToHandler, { BNE Handler }
+Exit:
+    RTS
+</verb></tscreen>
+
+
+  <label id="Transfer value">
+  <tag><tt>SMC_TransferValue label, value (, register)</tt></tag>
+
+  Changes the value of a SMC line.
+
+  Example:
+<tscreen><verb>
+ClearDefault:
+    SMC_TransferValue LoadDefault, 0
+    RTS
+    ...
+SMC LoadDefault, { LDX #25 }
+</verb></tscreen>
+
+
+  <label id="Load value">
+  <tag><tt>SMC_LoadValue label (, register)</tt></tag>
+
+  Retreives the value of a SMC line.
+
+  Example:
+<tscreen><verb>
+ShowDefault:
+    SMC_LoadValue LoadDefault
+    JSR PrintValue
+    RTS
+    ...
+SMC LoadDefault, { LDX #25 }
+</verb></tscreen>
+
+
+  <label id="Store value">
+  <tag><tt>SMC_StoreValue label (, register)</tt></tag>
+
+  Stores the value in the register to given SMC line.
+
+  Example:
+<tscreen><verb>
+InitCounters:
+    LDY #0
+    SMC_StoreValue GetI, y
+    SMC_StoreValue GetJ, y
+    SMC_StoreValue GetK, y
+    ...
+SMC GetI, { LDX #SMC_Value      }
+    ...
+SMC GetJ, { LDX #SMC_Value      }
+    ...
+SMC GetK, { LDX #SMC_Value      }
+</verb></tscreen>
+
+
+  <label id="Transfer low-byte">
+  <tag><tt>SMC_TransferLowByte label, value (, register)</tt></tag>
+
+  Does the same as '<tt>SMC_TransferValue</tt>' but should be used for
+  low-bytes of adresses for better readability.
+
+  Example:
+<tscreen><verb>
+ActivateSecondDataSet:
+    SMC_TransferLowByte LoadData, $40
+        RTS
+    ...
+SMC LoadData, { LDA $2000 }
+</verb></tscreen>
+
+
+  <label id="Load low-byte">
+  <tag><tt>SMC_LoadLowByte label (, register)</tt></tag>
+
+  Does the same as '<tt>SMC_LoadValue</tt>' but should be used for low-bytes
+  of adresses for better readability.
+
+  Example:
+<tscreen><verb>
+IsSecondDataSetActive:
+        SMC_LoadLowByte LoadData, y
+        CPY #$40
+        BNE NotActive
+    ...
+SMC LoadData, { LDA $2000 }
+</verb></tscreen>
+
+
+  <label id="Store low-byte">
+  <tag><tt>SMC_StoreLowByte label (, register)</tt></tag>
+
+  Does the same as '<tt>SMC_StoreValue</tt>' but should be used for low-bytes
+  of adresses for better readability.
+
+  Example:
+<tscreen><verb>
+InitStructureBaseAddresses:
+    LDX #0
+    SMC_StoreLowByte GetPlayerGraphic, x
+    SMC_StoreLowByte GetObjectGraphic, x
+    SMC_StoreLowByte StoreCollisionData, x
+    RTS
+    ...
+SMC GetPlayerGraphic, { LDX $2000 }
+    ...
+SMC GetObjectGraphic, { LDA $2100,x }
+    ...
+SMC StoreCollisionData, { STY $2200 }
+</verb></tscreen>
+
+
+  <label id="Transfer high-byte">
+  <tag><tt>SMC_TransferHighByte label, value (, register)</tt></tag>
+
+  Loads and stores the given value via the named register to the high-byte
+  adress portion of an SMC-instruction.
+
+  Example:
+<tscreen><verb>
+PlaySFX:
+SMC GetVolume { LDA $3200,x }
+    STA SoundOut
+    INX
+    BNE PlaySFX
+    ...
+PlayOtherSound:
+    SMC_TransferHighByte GetVolume, $34
+</verb></tscreen>
+
+
+  <label id="Load high-byte">
+  <tag><tt>SMC_LoadHighByte label (, register)</tt></tag>
+
+  Loads the high-byte part of an SMC-instruction adress to the given register.
+
+  Example:
+<tscreen><verb>
+PlaySFX:
+SMC GetVolume { LDA $3200,x }
+    ...
+    SMC_LoadHighByte GetVolume
+    cmp #$34
+    beq OtherSoundPlaying
+    ...
+</verb></tscreen>
+
+
+  <label id="Store high-byte">
+  <tag><tt>SMC_StoreHighByte label (, register)</tt></tag>
+
+  Stores the high-byte adress part of an SMC-instruction from the given
+  register.
+
+  Example:
+<tscreen><verb>
+SetupLevel2:
+    LDX #(>Level2Base)
+    SMC_StoreHighByte GetLevelData, x
+    SMC_StoreHighByte GetScreenData, x
+    SMC_StoreHighByte GetSoundData, x
+    RTS
+    ...
+SMC GetLevelData, { LDA Level1Base+Data }
+    ...
+SMC GetScreenData, { LDA Level1Base+Screen, x }
+    ...
+SMC GetSoundData, { LDA Level1Base+Sound, y }
+</verb></tscreen>
+
+
+  <label id="Transfer single adress">
+  <tag><tt>SMC_TransferAddressSingle label, address (, register)</tt></tag>
+
+  Transfers the contents of the given address via the given register to the
+  designated SMC instruction.
+
+  Example:
+<tscreen><verb>
+PrintHello:
+    SMC_TransferAddressSingle GetChar, #HelloMsg
+    ...
+    LDX #0
+NextChar:
+SMC GetChar, { LDA  SMC_AbsAdr, x }
+    BEQ leave
+    JSR CharOut
+    INX
+    BNE NextChar
+</verb></tscreen>
+
+
+  <label id="Transfer adress">
+  <tag><tt>SMC_TransferAddress label, address</tt></tag>
+
+  Loads contents of given address to A/X and stores the result to SMC
+  instruction. Allows reuse of register contents by using
+  '<tt>SMC_StoreAddress</tt>' for multiple SMC instruction modifications.
+
+  Example:
+<tscreen><verb>
+    SMC_TransferAddress JumpTo, #CloseChannel, Y
+    ...
+SMC JumpTo, { JMP OpenChannel }
+</verb></tscreen>
+
+
+  <label id="Store address">
+  <tag><tt>SMC_StoreAddress label</tt></tag>
+
+  Stores the address value in a/x to a SMC instruction address position.
+
+  Example:
+<tscreen><verb>
+    SMC_StoreAddress GetData
+    ...
+SMC GetData, { LDA SMC_AbsAdr }
+</verb></tscreen>
+
+</descrip>
+
+<sect1>Operational macros<p>
+
+These marcos are determined to let read/modify/write opcodes work on parts of
+SMC instructions.
+
+<descrip>
+
+ <label id="Operate on value">
+  <tag><tt>SMC_OperateOnValue opcode, label</tt></tag>
+
+  Let given opcode work on the value part of a SMC instruction.
+
+  Example:
+<tscreen><verb>
+    SMC_OperateOnValue ASL, LoadMask   ; shift mask to left
+    ...
+SMC LoadMask, { LDA #$20 }
+</verb></tscreen>
+
+  <label id="Operate on low-byte">
+  <tag><tt>SMC_OperateOnLowByte opcode, label</tt></tag>
+
+  Same as '<tt/SMC_OperateOnValue/' but renamed for better readability when
+  accessing low-bytes of address.
+
+  Example:
+<tscreen><verb>
+    SMC_OperateOnLowByte DEC, AccessData
+    ...
+SMC AccessData, { LDX Data }
+</verb></tscreen>
+
+  <label id="Operate on high-byte">
+  <tag><tt>SMC_OperateOnHighByte opcode, label</tt></tag>
+
+  Let the given opcode work on the high-byte part on a SMC-instruction.
+
+  Example:
+<tscreen><verb>
+NextPage:
+    SMC_OperateOnHighByte INC, GetPageData
+    ...
+SMC GetPageData, { LDA SourceData, X }
+</verb></tscreen>
+</descrip>
+
+<sect1>Scope macros<p>
+
+These marcos are determined to export and import SMC labels out of the current
+file scope. Please handle with care! If you cannot abstain from leaving the
+file scope, you should at least document the exported SMC lines very well. On
+import side no checking is available if the SMC line is correct accessed (e.g.
+invalid access to the value of an implied instruction)!
+
+<descrip>
+  <label id="Export SMC line under given name">
+  <tag><tt>SMC_Export alias, label</tt></tag>
+
+  SMC label will be exported under given alias.
+
+  Example:
+<tscreen><verb>
+.proc GetValue
+SMC LoadValue, { LDA #12 }
+    rts
+.endproc
+
+SMC_Export GetValueLoader, GetValue::LoadValue
+</verb></tscreen>
+
+  <label id="Import SMC alias">
+  <tag><tt>SMC_Import alias</tt></tag>
+
+  SMC line is made accessible under given alias.
+
+  Example:
+<tscreen><verb>
+SMC_Import GetValueLoader
+    ...
+    SMC_TransferValue GetValueLoader, #47
+    ...
+</verb></tscreen>
+</descrip>
+
+<sect>A complex example<p>
+Let's have a look on a quite sophisticated example for the usage of SMC. It
+not only modifies code, but also the modification of the code is modified -
+allowing reuse of some instructions.
+
+The code is from my 'memset()'implementation:
+
+<descrip>
+<tscreen><verb>
+ 1:     ...
+ 2:     SMC_StoreAddress StoreAccuFirstSection
+ 3:
+ 4: StoreToFirstSection:
+ 5:     SMC StoreAccuFirstSection, { sta SMC_AbsAdr, Y }
+ 6:             ...
+ 7: RestoreCodeBranchBaseAdr:
+ 8:     SMC FirstIncHighByte, { SMC_OperateOnHighByte inc, StoreAccuFirstSection }             ; code will be overwritten to 'beq RestoreCode' (*)
+ 9:     ...
+10:     SMC_TransferOpcode FirstIncHighByte, OPC_BEQ , x                                       ; change code marked above with (*)
+11:     SMC_TransferValue FirstIncHighByte, #(restoreCode - RestoreCodeBranchBaseAdr-2), x     ; set relative adress to 'RestoreCode'
+12:     ...
+13: restoreCode:
+14:     SMC_TransferOpcode FirstIncHighByte, OPC_INC_abs , x                                   ; restore original code...
+15:     SMC_TransferValue FirstIncHighByte, #(<(StoreToFirstSection+2)), x                     ; (second byte of inc contained low-byte of adress)
+16:             ...
+</verb></tscreen>
+
+Some explanation:
+
+Line 2: The register pair A/X contains an address, which is stored on the
+address location of a SMC line called 'StoreAccuFirstSection'. According to
+cc65's calling convention, the low-byte is in accu while the high-byte is in
+the X-register.
+
+Line 5: The (modified) address is accessed.
+
+Line 8: We have a line here, which is about to be modified (it begins with
+SMC), but itself modifies code. Please note: Contrary to the rest of SMC-line
+modifying macros, the 'OperateOn'-macros just expand their given arguments
+into a single instruction line. These can be changed of course too.
+
+Line 10,11: These lines construct a branch operation for line 8: The
+X-register will be used to change it from 'inc StoreAccuFirstSection+2'
+(high-byte operation) to 'beq restoreCode'. Please note: To calculate the
+relaive branch offset, we introduced a second label
+('RestoreCodeBranchBaseAdr') for to calculate it. Some could also use the
+internal name of the SMC label, but you should abstain to do so - it may be
+changed in the future...
+
+Line 14,15: The original code from line 8 is reestablished.
+</descrip>
+</article>
+