Added a macro package for writing self modyfying code. By Christian Krüger.
git-svn-id: svn://svn.cc65.org/cc65/trunk@5536 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
509
asminc/opcodes.inc
Normal file
509
asminc/opcodes.inc
Normal file
@@ -0,0 +1,509 @@
|
|||||||
|
; opcodes.inc
|
||||||
|
; ca65 6502 - opcode definitions, mainly for self modifying code
|
||||||
|
;
|
||||||
|
; Christian Kr<EFBFBD>ger, latest change: 18-Sep-2010
|
||||||
|
;
|
||||||
|
; 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.
|
||||||
|
;
|
||||||
|
|
||||||
|
; Opcode-Table
|
||||||
|
; ------------
|
||||||
|
; Post fix explanation:
|
||||||
|
; imm = #$00
|
||||||
|
; zp = $00
|
||||||
|
; zpx = $00,X
|
||||||
|
; zpy = $00,Y
|
||||||
|
; izp = ($00)
|
||||||
|
; izx = ($00,X)
|
||||||
|
; izy = ($00),Y
|
||||||
|
; abs = $0000
|
||||||
|
; abx = $0000,X
|
||||||
|
; aby = $0000,Y
|
||||||
|
; ind = ($0000)
|
||||||
|
; iax = ($0000,X)
|
||||||
|
; rel = $0000 (PC-relative) (supressed here)
|
||||||
|
|
||||||
|
.macpack cpu
|
||||||
|
|
||||||
|
OPC_BRK = $00
|
||||||
|
OPC_ORA_izx = $01
|
||||||
|
OPC_ORA_zp = $05
|
||||||
|
OPC_ASL_zp = $06
|
||||||
|
OPC_PHP = $08
|
||||||
|
OPC_ORA_imm = $09
|
||||||
|
OPC_ASL = $0A
|
||||||
|
OPC_ORA_abs = $0D
|
||||||
|
OPC_ASL_abs = $0E
|
||||||
|
|
||||||
|
OPC_BPL = $10
|
||||||
|
OPC_ORA_izy = $11
|
||||||
|
OPC_ORA_zpx = $15
|
||||||
|
OPC_ASL_zpx = $16
|
||||||
|
OPC_CLC = $18
|
||||||
|
OPC_ORA_aby = $19
|
||||||
|
OPC_ORA_abx = $1D
|
||||||
|
OPC_ASL_abx = $1E
|
||||||
|
|
||||||
|
OPC_JSR_abs = $20
|
||||||
|
OPC_AND_izx = $21
|
||||||
|
OPC_BIT_zp = $24
|
||||||
|
OPC_AND_zp = $25
|
||||||
|
OPC_ROL_zp = $26
|
||||||
|
OPC_PLP = $28
|
||||||
|
OPC_AND_imm = $29
|
||||||
|
OPC_ROL = $2A
|
||||||
|
OPC_BIT_abs = $2C
|
||||||
|
OPC_AND_abs = $2D
|
||||||
|
OPC_ROL_abs = $2E
|
||||||
|
|
||||||
|
OPC_BMI = $30
|
||||||
|
OPC_AND_izy = $31
|
||||||
|
OPC_AND_zpx = $35
|
||||||
|
OPC_ROL_zpx = $36
|
||||||
|
OPC_SEC = $38
|
||||||
|
OPC_AND_aby = $39
|
||||||
|
OPC_AND_abx = $3D
|
||||||
|
OPC_ROL_abx = $3E
|
||||||
|
|
||||||
|
|
||||||
|
OPC_RTI = $40
|
||||||
|
OPC_EOR_izx = $41
|
||||||
|
OPC_EOR_zp = $45
|
||||||
|
OPC_LSR_zp = $46
|
||||||
|
OPC_PHA = $48
|
||||||
|
OPC_EOR_imm = $49
|
||||||
|
OPC_LSR = $4A
|
||||||
|
OPC_JMP_abs = $4C
|
||||||
|
OPC_EOR_abs = $4D
|
||||||
|
OPC_LSR_abs = $4E
|
||||||
|
|
||||||
|
OPC_BVC = $50
|
||||||
|
OPC_EOR_izy = $51
|
||||||
|
OPC_EOR_zpx = $55
|
||||||
|
OPC_LSR_zpx = $56
|
||||||
|
OPC_CLI = $58
|
||||||
|
OPC_EOR_aby = $59
|
||||||
|
OPC_EOR_abx = $5D
|
||||||
|
OPC_LSR_abx = $5E
|
||||||
|
|
||||||
|
OPC_RTS = $60
|
||||||
|
OPC_ADC_izx = $61
|
||||||
|
OPC_ADC_zp = $65
|
||||||
|
OPC_ROR_zp = $66
|
||||||
|
OPC_PLA = $68
|
||||||
|
OPC_ADC_imm = $69
|
||||||
|
OPC_ROR = $6A
|
||||||
|
OPC_JMP_ind = $6C
|
||||||
|
OPC_ADC_abs = $6D
|
||||||
|
OPC_ROR_abs = $6E
|
||||||
|
|
||||||
|
OPC_BVS = $70
|
||||||
|
OPC_ADC_izy = $71
|
||||||
|
OPC_ADC_zpx = $75
|
||||||
|
OPC_ROR_zpx = $76
|
||||||
|
OPC_SEI = $78
|
||||||
|
OPC_ADC_aby = $79
|
||||||
|
OPC_ADC_abx = $7D
|
||||||
|
OPC_ROR_abx = $7E
|
||||||
|
|
||||||
|
OPC_STA_izx = $81
|
||||||
|
OPC_STY_zp = $84
|
||||||
|
OPC_STA_zp = $85
|
||||||
|
OPC_STX_zp = $86
|
||||||
|
OPC_DEY = $88
|
||||||
|
OPC_TXA = $8A
|
||||||
|
OPC_STY_abs = $8C
|
||||||
|
OPC_STA_abs = $8D
|
||||||
|
OPC_STX_abs = $8E
|
||||||
|
|
||||||
|
OPC_BCC = $90
|
||||||
|
OPC_STA_izy = $91
|
||||||
|
OPC_STY_zpx = $94
|
||||||
|
OPC_STA_zpx = $95
|
||||||
|
OPC_STX_zpy = $96
|
||||||
|
OPC_TYA = $98
|
||||||
|
OPC_STA_aby = $99
|
||||||
|
OPC_TXS = $9A
|
||||||
|
OPC_STA_abx = $9D
|
||||||
|
|
||||||
|
OPC_LDY_imm = $A0
|
||||||
|
OPC_LDA_izx = $A1
|
||||||
|
OPC_LDX_imm = $A2
|
||||||
|
OPC_LDY_zp = $A4
|
||||||
|
OPC_LDA_zp = $A5
|
||||||
|
OPC_LDX_zp = $A6
|
||||||
|
OPC_TAY = $A8
|
||||||
|
OPC_LDA_imm = $A9
|
||||||
|
OPC_TAX = $AA
|
||||||
|
OPC_LDY_abs = $AC
|
||||||
|
OPC_LDA_abs = $AD
|
||||||
|
OPC_LDX_abs = $AE
|
||||||
|
|
||||||
|
OPC_BCS = $B0
|
||||||
|
OPC_LDA_izy = $B1
|
||||||
|
OPC_LDY_zpx = $B4
|
||||||
|
OPC_LDA_zpx = $B5
|
||||||
|
OPC_LDX_zpy = $B6
|
||||||
|
OPC_CLV = $B8
|
||||||
|
OPC_LDA_aby = $B9
|
||||||
|
OPC_TSX = $BA
|
||||||
|
OPC_LDY_abx = $BC
|
||||||
|
OPC_LDA_abx = $BD
|
||||||
|
OPC_LDX_aby = $BE
|
||||||
|
|
||||||
|
OPC_CPY_imm = $C0
|
||||||
|
OPC_CMP_izx = $C1
|
||||||
|
OPC_CPY_zp = $C4
|
||||||
|
OPC_CMP_zp = $C5
|
||||||
|
OPC_DEC_zp = $C6
|
||||||
|
OPC_INY = $C8
|
||||||
|
OPC_CMP_imm = $C9
|
||||||
|
OPC_DEX = $CA
|
||||||
|
OPC_CPY_abs = $CC
|
||||||
|
OPC_CMP_abs = $CD
|
||||||
|
OPC_DEC_abs = $CE
|
||||||
|
|
||||||
|
OPC_BNE = $D0
|
||||||
|
OPC_CMP_izy = $D1
|
||||||
|
OPC_CMP_zpx = $D5
|
||||||
|
OPC_DEC_zpx = $D6
|
||||||
|
OPC_CLD = $D8
|
||||||
|
OPC_CMP_aby = $D9
|
||||||
|
OPC_CMP_abx = $DD
|
||||||
|
OPC_DEC_abx = $DE
|
||||||
|
|
||||||
|
OPC_CPX_imm = $E0
|
||||||
|
OPC_SBC_izx = $E1
|
||||||
|
OPC_CPX_zp = $E4
|
||||||
|
OPC_SBC_zp = $E5
|
||||||
|
OPC_INC_zp = $E6
|
||||||
|
OPC_INX = $E8
|
||||||
|
OPC_SBC_imm = $E9
|
||||||
|
OPC_NOP = $EA
|
||||||
|
OPC_CPX_abs = $EC
|
||||||
|
OPC_SBC_abs = $ED
|
||||||
|
OPC_INC_abs = $EE
|
||||||
|
|
||||||
|
|
||||||
|
OPC_BEQ = $F0
|
||||||
|
OPC_SBC_izy = $F1
|
||||||
|
OPC_SBC_zpx = $F5
|
||||||
|
OPC_INC_zpx = $F6
|
||||||
|
OPC_SED = $F8
|
||||||
|
OPC_SBC_aby = $F9
|
||||||
|
OPC_SBC_abx = $FD
|
||||||
|
OPC_INC_abx = $FE
|
||||||
|
|
||||||
|
|
||||||
|
.if (.cpu .bitand ::CPU_ISET_65SC02)
|
||||||
|
|
||||||
|
; OPC_NOP = $02 ; doublet
|
||||||
|
; OPC_NOP = $03 ; doublet
|
||||||
|
OPC_TSB_zp = $04
|
||||||
|
; OPC_NOP = $0B ; doublet
|
||||||
|
OPC_TSB_abs = $0C
|
||||||
|
|
||||||
|
OPC_ORA_izp = $12
|
||||||
|
; OPC_NOP = $13 ; doublet
|
||||||
|
OPC_TRB_zp = $14
|
||||||
|
OPC_INC = $1A
|
||||||
|
; OPC_NOP = $1B ; doublet
|
||||||
|
OPC_TRB_abs = $1C
|
||||||
|
|
||||||
|
; OPC_NOP = $22 ; doublet
|
||||||
|
; OPC_NOP = $23 ; doublet
|
||||||
|
; OPC_NOP = $2B ; doublet
|
||||||
|
|
||||||
|
OPC_AND_izp = $32
|
||||||
|
; OPC_NOP = $33 ; doublet
|
||||||
|
OPC_BIT_zpx = $34
|
||||||
|
OPC_DEC = $3A
|
||||||
|
; OPC_NOP = $3B ; doublet
|
||||||
|
OPC_BIT_abx = $3C
|
||||||
|
|
||||||
|
; OPC_NOP = $42 ; doublet
|
||||||
|
; OPC_NOP = $43 ; doublet
|
||||||
|
; OPC_NOP = $44 ; doublet
|
||||||
|
; OPC_NOP = $4B ; doublet
|
||||||
|
|
||||||
|
OPC_EOR_izp = $52
|
||||||
|
; OPC_NOP = $53 ; doublet
|
||||||
|
; OPC_NOP = $54 ; doublet
|
||||||
|
; OPC_NOP = $5A ; doublet
|
||||||
|
; OPC_NOP = $5B ; doublet
|
||||||
|
OPC_EOR_abx = $5C
|
||||||
|
|
||||||
|
; OPC_NOP = $62 ; doublet
|
||||||
|
; OPC_NOP = $63 ; doublet
|
||||||
|
OPC_STZ_zp = $64
|
||||||
|
; OPC_NOP = $6B ; doublet
|
||||||
|
|
||||||
|
OPC_ADC_izp = $72
|
||||||
|
; OPC_NOP = $73 ; doublet
|
||||||
|
OPC_STZ_zpx = $74
|
||||||
|
OPC_PLY = $7A
|
||||||
|
; OPC_NOP = $7B ; doublet
|
||||||
|
OPC_JMP_iax = $7C
|
||||||
|
|
||||||
|
OPC_BRA = $80
|
||||||
|
; OPC_NOP = $82 ; doublet
|
||||||
|
; OPC_NOP = $83 ; doublet
|
||||||
|
OPC_BIT_imm = $89
|
||||||
|
; OPC_NOP = $8B ; doublet
|
||||||
|
|
||||||
|
OPC_STA_izp = $92
|
||||||
|
; OPC_NOP = $93 ; doublet
|
||||||
|
; OPC_NOP = $9B ; doublet
|
||||||
|
OPC_STZ_abs = $9C
|
||||||
|
OPC_STZ_abx = $9E
|
||||||
|
|
||||||
|
; OPC_NOP = $A3 ; doublet
|
||||||
|
; OPC_NOP = $AB ; doublet
|
||||||
|
|
||||||
|
OPC_LDA_izp = $B2
|
||||||
|
; OPC_NOP = $B3 ; doublet
|
||||||
|
; OPC_NOP = $BB ; doublet
|
||||||
|
|
||||||
|
; OPC_NOP = $C2 ; doublet
|
||||||
|
; OPC_NOP = $C3 ; doublet
|
||||||
|
; OPC_NOP = $CB ; doublet
|
||||||
|
|
||||||
|
OPC_CMP_izp = $D2
|
||||||
|
; OPC_NOP = $D3 ; doublet
|
||||||
|
; OPC_NOP = $D4 ; doublet
|
||||||
|
OPC_PHX = $DA
|
||||||
|
; OPC_NOP = $DB ; doublet
|
||||||
|
; OPC_NOP = $DC ; doublet
|
||||||
|
|
||||||
|
; OPC_NOP = $E2 ; doublet
|
||||||
|
; OPC_NOP = $E3 ; doublet
|
||||||
|
; OPC_NOP = $EB ; doublet
|
||||||
|
|
||||||
|
OPC_SBC_izp = $F2
|
||||||
|
; OPC_NOP = $F3 ; doublet
|
||||||
|
; OPC_NOP = $F4 ; doublet
|
||||||
|
OPC_PLX = $FA
|
||||||
|
; OPC_NOP = $FB ; doublet
|
||||||
|
; OPC_NOP = $FC ; doublet
|
||||||
|
|
||||||
|
|
||||||
|
.if (.cpu .bitand ::CPU_ISET_65C02)
|
||||||
|
|
||||||
|
; bit instructions for 65C02
|
||||||
|
|
||||||
|
OPC_RMB0 = $07
|
||||||
|
OPC_RMB1 = $17
|
||||||
|
OPC_RMB2 = $27
|
||||||
|
OPC_RMB3 = $37
|
||||||
|
OPC_RMB4 = $47
|
||||||
|
OPC_RMB5 = $57
|
||||||
|
OPC_RMB6 = $67
|
||||||
|
OPC_RMB7 = $77
|
||||||
|
|
||||||
|
OPC_SMB0 = $87
|
||||||
|
OPC_SMB1 = $97
|
||||||
|
OPC_SMB2 = $A7
|
||||||
|
OPC_SMB3 = $B7
|
||||||
|
OPC_SMB4 = $C7
|
||||||
|
OPC_SMB5 = $D7
|
||||||
|
OPC_SMB6 = $E7
|
||||||
|
OPC_SMB7 = $F7
|
||||||
|
|
||||||
|
OPC_BBR0 = $0F
|
||||||
|
OPC_BBR1 = $1F
|
||||||
|
OPC_BBR2 = $2F
|
||||||
|
OPC_BBR3 = $3F
|
||||||
|
OPC_BBR4 = $4F
|
||||||
|
OPC_BBR5 = $5F
|
||||||
|
OPC_BBR6 = $6F
|
||||||
|
OPC_BBR7 = $7F
|
||||||
|
|
||||||
|
OPC_BBS0 = $8F
|
||||||
|
OPC_BBS1 = $9F
|
||||||
|
OPC_BBS2 = $AF
|
||||||
|
OPC_BBS3 = $BF
|
||||||
|
OPC_BBS4 = $CF
|
||||||
|
OPC_BBS5 = $DF
|
||||||
|
OPC_BBS6 = $EF
|
||||||
|
OPC_BBS7 = $FF
|
||||||
|
|
||||||
|
.else
|
||||||
|
|
||||||
|
; no bit instructions for 65SC02
|
||||||
|
|
||||||
|
; OPC_NOP = $07 ; doublet
|
||||||
|
; OPC_NOP = $17 ; doublet
|
||||||
|
; OPC_NOP = $27 ; doublet
|
||||||
|
; OPC_NOP = $37 ; doublet
|
||||||
|
; OPC_NOP = $47 ; doublet
|
||||||
|
; OPC_NOP = $57 ; doublet
|
||||||
|
; OPC_NOP = $67 ; doublet
|
||||||
|
; OPC_NOP = $77 ; doublet
|
||||||
|
; OPC_NOP = $87 ; doublet
|
||||||
|
; OPC_NOP = $97 ; doublet
|
||||||
|
; OPC_NOP = $A7 ; doublet
|
||||||
|
; OPC_NOP = $B7 ; doublet
|
||||||
|
; OPC_NOP = $C7 ; doublet
|
||||||
|
; OPC_NOP = $D7 ; doublet
|
||||||
|
; OPC_NOP = $E7 ; doublet
|
||||||
|
; OPC_NOP = $F7 ; doublet
|
||||||
|
; OPC_NOP = $0F ; doublet
|
||||||
|
; OPC_NOP = $1F ; doublet
|
||||||
|
; OPC_NOP = $2F ; doublet
|
||||||
|
; OPC_NOP = $3F ; doublet
|
||||||
|
; OPC_NOP = $4F ; doublet
|
||||||
|
; OPC_NOP = $5F ; doublet
|
||||||
|
; OPC_NOP = $6F ; doublet
|
||||||
|
; OPC_NOP = $7F ; doublet
|
||||||
|
; OPC_NOP = $8F ; doublet
|
||||||
|
; OPC_NOP = $9F ; doublet
|
||||||
|
; OPC_NOP = $AF ; doublet
|
||||||
|
; OPC_NOP = $BF ; doublet
|
||||||
|
; OPC_NOP = $CF ; doublet
|
||||||
|
; OPC_NOP = $DF ; doublet
|
||||||
|
; OPC_NOP = $EF ; doublet
|
||||||
|
; OPC_NOP = $FF ; doublet
|
||||||
|
|
||||||
|
.endif
|
||||||
|
|
||||||
|
.elseif (.cpu .bitand ::CPU_ISET_6502X)
|
||||||
|
|
||||||
|
; stable, undocumented opcodes
|
||||||
|
|
||||||
|
; OPC_KIL = $02 ; unstable
|
||||||
|
OPC_SLO_izx = $03
|
||||||
|
OPC_NOP_zp = $04
|
||||||
|
OPC_SLO_zp = $07
|
||||||
|
OPC_ANC_imm = $0B
|
||||||
|
OPC_NOP_abs = $0C
|
||||||
|
OPC_SLO_abs = $0F
|
||||||
|
|
||||||
|
; OPC_KIL = $12 ; unstable
|
||||||
|
OPC_SLO_izy = $13
|
||||||
|
OPC_NOP_zpx = $14
|
||||||
|
OPC_SLO_zpx = $17
|
||||||
|
;OPC_NOP = $1A
|
||||||
|
OPC_SLO_aby = $1B
|
||||||
|
OPC_NOP_abx = $1C
|
||||||
|
OPC_SLO_abx = $1F
|
||||||
|
|
||||||
|
; OPC_KIL = $22 ; unstable
|
||||||
|
OPC_RLA_izx = $23
|
||||||
|
OPC_RLA_zp = $27
|
||||||
|
OPC_ANC_imm = $2B
|
||||||
|
OPC_RLA_abs = $2F
|
||||||
|
|
||||||
|
; OPC_KIL = $32 ; unstable
|
||||||
|
OPC_RLA_izy = $33
|
||||||
|
OPC_NOP_zpx = $34
|
||||||
|
OPC_RLA_zpx = $37
|
||||||
|
; OPC_NOP = $3A ; doublet
|
||||||
|
OPC_RLA_aby = $3B
|
||||||
|
OPC_NOP_abx = $3C
|
||||||
|
OPC_RLA_abx = $3F
|
||||||
|
|
||||||
|
; OPC_KIL = $42 ; unstable
|
||||||
|
OPC_SRE_izx = $43
|
||||||
|
OPC_NOP_zp = $44
|
||||||
|
OPC_SRE_zp = $47
|
||||||
|
OPC_ALR_imm = $4B
|
||||||
|
OPC_SRE_abs = $4F
|
||||||
|
|
||||||
|
; OPC_KIL = $52 ; unstable
|
||||||
|
OPC_SRE_izy = $53
|
||||||
|
OPC_NOP_zpx = $54
|
||||||
|
OPC_SRE_zpx = $57
|
||||||
|
; OPC_NOP = $5A ; doublet
|
||||||
|
OPC_SRE_aby = $5B
|
||||||
|
OPC_NOP_abx = $5C
|
||||||
|
OPC_SRE_abx = $5F
|
||||||
|
|
||||||
|
; OPC_KIL = $62
|
||||||
|
OPC_RRA_izx = $63
|
||||||
|
OPC_NOP_zp = $64
|
||||||
|
OPC_RRA_zp = $67
|
||||||
|
OPC_ARR_imm = $6B
|
||||||
|
OPC_RRA_abs = $6F
|
||||||
|
|
||||||
|
; OPC_KIL = $72
|
||||||
|
OPC_RRA_izy = $73
|
||||||
|
OPC_NOP_zpx = $74
|
||||||
|
OPC_RRA_zpx = $77
|
||||||
|
; OPC_NOP = $7A ; doublet
|
||||||
|
OPC_RRA_aby = $7B
|
||||||
|
OPC_NOP_abx = $7C
|
||||||
|
OPC_RRA_abx = $7F
|
||||||
|
|
||||||
|
OPC_NOP_imm = $80
|
||||||
|
; OPC_NOP_imm = $82 ; doublet
|
||||||
|
OPC_SAX_izx = $83
|
||||||
|
OPC_SAX_zp = $87
|
||||||
|
; OPC_NOP_imm = $89 ; doublet
|
||||||
|
; OPC_XAA = $8B ; unstable
|
||||||
|
OPC_SAX_abs = $8F
|
||||||
|
|
||||||
|
; OPC_KIL = $92 ; unstable
|
||||||
|
; OPC_AHX_izy = $93 ; unstable
|
||||||
|
OPC_SAX_zpy = $97
|
||||||
|
; OPC_TAS_aby = $9B ; unstable
|
||||||
|
; OPC_SHY_abx = $9C ; unstable
|
||||||
|
; OPC_SHX_aby = $9E ; unstable
|
||||||
|
; OPC_AHX_aby = $9F ; unstable
|
||||||
|
|
||||||
|
OPC_LAX_izx = $A3
|
||||||
|
OPC_LAX_zp = $A7
|
||||||
|
; OPC_LAX_imm = $AB ; unstable
|
||||||
|
OPC_LAX_abs = $AF
|
||||||
|
|
||||||
|
; OPC_KIL = $B2 ; unstable
|
||||||
|
OPC_LAX_izy = $B3
|
||||||
|
OPC_LAX_zpy = $B7
|
||||||
|
OPC_LAS_aby = $BB
|
||||||
|
OPC_LAX_aby = $BF
|
||||||
|
|
||||||
|
; OPC_NOP_imm = $C2 ; doublet
|
||||||
|
OPC_DCP_izx = $C3
|
||||||
|
OPC_DCP_zp = $C7
|
||||||
|
OPC_AXS_imm = $CB
|
||||||
|
OPC_DCP_abs = $CF
|
||||||
|
|
||||||
|
; OPC_KIL = $D2 ; unstable
|
||||||
|
OPC_DCP_izy = $D3
|
||||||
|
OPC_NOP_zpx = $D4
|
||||||
|
OPC_DCP_zpx = $D7
|
||||||
|
OPC_NOP_DA = $DA
|
||||||
|
OPC_DCP_aby = $DB
|
||||||
|
OPC_NOP_abx = $DC
|
||||||
|
OPC_DCP_abx = $DF
|
||||||
|
|
||||||
|
; OPC_NOP_imm = $E2 ; doublet
|
||||||
|
OPC_ISC_izx = $E3
|
||||||
|
OPC_ISC_zp = $E7
|
||||||
|
; OPC_SBC_imm = $EB ; doublet
|
||||||
|
OPC_ISC_abs = $EF
|
||||||
|
|
||||||
|
; OPC_KIL = $F2 ; unstable
|
||||||
|
OPC_ISC_izy = $F3
|
||||||
|
OPC_NOP_zpx = $F4
|
||||||
|
OPC_ISC_zpx = $F7
|
||||||
|
OPC_NOP_FA = $FA
|
||||||
|
OPC_ISC_aby = $FB
|
||||||
|
OPC_NOP_abx = $FC
|
||||||
|
OPC_ISC_abx = $FF
|
||||||
|
|
||||||
|
.endif
|
||||||
249
asminc/smc.mac
Normal file
249
asminc/smc.mac
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
; smc.mac
|
||||||
|
; ca65 Macro-Pack for Self Modifying Code (SMC)
|
||||||
|
;
|
||||||
|
; (c) Christian Kr<4B>ger, latest change: 09-Nov-2011
|
||||||
|
;
|
||||||
|
; 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)
|
||||||
|
lda #opcode
|
||||||
|
sta _SMCDesignator
|
||||||
|
.elseif .match ({register}, x)
|
||||||
|
ldx #opcode
|
||||||
|
stx _SMCDesignator
|
||||||
|
.elseif .match ({register}, y)
|
||||||
|
ldy #opcode
|
||||||
|
sty _SMCDesignator
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro SMC_LoadOpcode label, register
|
||||||
|
.if .paramcount = 1 .or .match ({register}, a)
|
||||||
|
lda _SMCDesignator
|
||||||
|
.elseif .match ({register}, x)
|
||||||
|
ldx _SMCDesignator
|
||||||
|
.elseif .match ({register}, y)
|
||||||
|
ldy _SMCDesignator
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro SMC_StoreOpcode label, register
|
||||||
|
.if .paramcount = 1 .or .match ({register}, a)
|
||||||
|
sta _SMCDesignator
|
||||||
|
.elseif .match ({register}, x)
|
||||||
|
stx _SMCDesignator
|
||||||
|
.elseif .match ({register}, y)
|
||||||
|
sty _SMCDesignator
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro SMC_ChangeBranch label, destination, register
|
||||||
|
.if .paramcount = 2 .or .match ({register}, a)
|
||||||
|
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
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro SMC_TransferValue label, value, register
|
||||||
|
.if .paramcount = 2 .or .match ({register}, a)
|
||||||
|
lda value
|
||||||
|
sta _SMCDesignator+1
|
||||||
|
.elseif .match ({register}, x)
|
||||||
|
ldx value
|
||||||
|
stx _SMCDesignator+1
|
||||||
|
.elseif .match ({register}, y)
|
||||||
|
ldy value
|
||||||
|
sty _SMCDesignator+1
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro SMC_LoadValue label, register
|
||||||
|
.if .paramcount = 1 .or .match ({register}, a)
|
||||||
|
lda _SMCDesignator+1
|
||||||
|
.elseif .match ({register}, x)
|
||||||
|
ldx _SMCDesignator+1
|
||||||
|
.elseif .match ({register}, y)
|
||||||
|
ldy _SMCDesignator+1
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro SMC_StoreValue label, register
|
||||||
|
.if .paramcount = 1 .or .match ({register}, a)
|
||||||
|
sta _SMCDesignator+1
|
||||||
|
.elseif .match ({register}, x)
|
||||||
|
stx _SMCDesignator+1
|
||||||
|
.elseif .match ({register}, y)
|
||||||
|
sty _SMCDesignator+1
|
||||||
|
.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)
|
||||||
|
lda value
|
||||||
|
sta _SMCDesignator+2
|
||||||
|
.elseif .match ({register}, x)
|
||||||
|
ldx value
|
||||||
|
stx _SMCDesignator+2
|
||||||
|
.elseif .match ({register}, y)
|
||||||
|
ldy value
|
||||||
|
sty _SMCDesignator+2
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro SMC_LoadHighByte label, register
|
||||||
|
.if .paramcount = 1 .or .match ({register}, a)
|
||||||
|
lda _SMCDesignator+2
|
||||||
|
.elseif .match ({register}, x)
|
||||||
|
ldx _SMCDesignator+2
|
||||||
|
.elseif .match ({register}, y)
|
||||||
|
ldy _SMCDesignator+2
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro SMC_StoreHighByte label, register
|
||||||
|
.if .paramcount = 1 .or .match ({register}, a)
|
||||||
|
sta _SMCDesignator+2
|
||||||
|
.elseif .match ({register}, x)
|
||||||
|
stx _SMCDesignator+2
|
||||||
|
.elseif .match ({register}, y)
|
||||||
|
sty _SMCDesignator+2
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
|
||||||
|
.macro SMC_TransferAddressSingle label, address, register
|
||||||
|
.if .paramcount = 2 .or .match ((register), a)
|
||||||
|
.if (.match (.left (1, {adress}), #))
|
||||||
|
; immediate mode
|
||||||
|
lda #<(.right (.tcount ({adress})-1, {adress}))
|
||||||
|
sta _SMCDesignator+1
|
||||||
|
lda #>(.right (.tcount ({adress})-1, {adress}))
|
||||||
|
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, {adress}), #))
|
||||||
|
; immediate mode
|
||||||
|
ldx #<(.right (.tcount ({adress})-1, {adress}))
|
||||||
|
stx _SMCDesignator+1
|
||||||
|
ldx #>(.right (.tcount ({adress})-1, {adress}))
|
||||||
|
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, {adress}), #))
|
||||||
|
; immediate mode
|
||||||
|
ldy #<(.right (.tcount ({adress})-1, {adress}))
|
||||||
|
sty _SMCDesignator+1
|
||||||
|
ldy #>(.right (.tcount ({adress})-1, {adress}))
|
||||||
|
sty _SMCDesignator+2
|
||||||
|
.else
|
||||||
|
; assume absolute or zero page
|
||||||
|
ldy address
|
||||||
|
sty _SMCDesignator+1
|
||||||
|
ldy 1+(address)
|
||||||
|
sty _SMCDesignator+2
|
||||||
|
.endif
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
|
||||||
|
.macro SMC_TransferAddress label, address
|
||||||
|
.if (.match (.left (1, {adress}), #))
|
||||||
|
; immediate mode
|
||||||
|
lda #<(.right (.tcount ({adress})-1, {adress}))
|
||||||
|
sta _SMCDesignator+1
|
||||||
|
ldx #>(.right (.tcount ({adress})-1, {adress}))
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
@@ -49,6 +49,7 @@ SGML = apple2.sgml \
|
|||||||
od65.sgml \
|
od65.sgml \
|
||||||
pet.sgml \
|
pet.sgml \
|
||||||
plus4.sgml \
|
plus4.sgml \
|
||||||
|
smc.sgml \
|
||||||
supervision.sgml\
|
supervision.sgml\
|
||||||
vic20.sgml
|
vic20.sgml
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,10 @@ Main documentation page, contains links to other available stuff.
|
|||||||
<tag><htmlurl url="library.html" name="library.html"></tag>
|
<tag><htmlurl url="library.html" name="library.html"></tag>
|
||||||
An overview over the cc65 runtime and C libraries.
|
An overview over the cc65 runtime and C libraries.
|
||||||
|
|
||||||
|
<tag><htmlurl url="smc.html" name="smc.html"></tag>
|
||||||
|
Describes Christian Krügers macro package for writing self modifying
|
||||||
|
assembler code.
|
||||||
|
|
||||||
<tag><url name="6502 Binary Relocation Format document"
|
<tag><url name="6502 Binary Relocation Format document"
|
||||||
url="http://www.6502.org/users/andre/o65/fileformat.html"></tag>
|
url="http://www.6502.org/users/andre/o65/fileformat.html"></tag>
|
||||||
Describes the o65 file format that is used for dynamically loadable modules
|
Describes the o65 file format that is used for dynamically loadable modules
|
||||||
|
|||||||
596
doc/smc.sgml
Normal file
596
doc/smc.sgml
Normal file
@@ -0,0 +1,596 @@
|
|||||||
|
<!doctype linuxdoc system>
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<title>ca65 Macros for Self Modifying Code
|
||||||
|
<author>Christian Krü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>
|
||||||
|
|
||||||
Reference in New Issue
Block a user