2010-06-11 15:38:22 +00:00
/*
AppleWin : An Apple //e emulator for Windows
Copyright ( C ) 1994 - 1996 , Michael O ' Brien
Copyright ( C ) 1999 - 2001 , Oliver Schmidt
Copyright ( C ) 2002 - 2005 , Tom Charlesworth
2014-08-28 18:13:02 +00:00
Copyright ( C ) 2006 - 2014 , Tom Charlesworth , Michael Pohoreski
2010-06-11 15:38:22 +00:00
AppleWin is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
AppleWin is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with AppleWin ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2010-12-18 14:58:43 +00:00
/* Description: Debugger Assembler
2010-06-11 15:38:22 +00:00
*
2010-12-18 14:58:43 +00:00
* Author : Copyright ( C ) 2006 - 2010 Michael Pohoreski
2010-06-11 15:38:22 +00:00
*/
# include "StdAfx.h"
2014-08-13 20:30:35 +00:00
# include "Debug.h"
2020-12-20 15:39:53 +00:00
# include "../Interface.h"
2018-02-24 15:12:40 +00:00
# include "../CPU.h"
# include "../Memory.h"
2014-08-13 20:30:35 +00:00
2010-12-15 16:03:22 +00:00
# define DEBUG_ASSEMBLER 0
2010-06-11 15:38:22 +00:00
// Globals __________________________________________________________________
// Addressing _____________________________________________________________________________________
AddressingMode_t g_aOpmodes [ NUM_ADDRESSING_MODES ] =
2019-12-09 16:27:13 +00:00
{ // Output, but eventually used for Input when Assembler is working.
2010-06-11 15:38:22 +00:00
{ TEXT ( " " ) , 1 , " (implied) " } , // (implied)
{ TEXT ( " " ) , 1 , " n/a 1 " } , // INVALID1
{ TEXT ( " " ) , 2 , " n/a 2 " } , // INVALID2
{ TEXT ( " " ) , 3 , " n/a 3 " } , // INVALID3
{ TEXT ( " %02X " ) , 2 , " Immediate " } , // AM_M // #$%02X -> %02X
{ TEXT ( " %04X " ) , 3 , " Absolute " } , // AM_A
{ TEXT ( " %02X " ) , 2 , " Zero Page " } , // AM_Z
{ TEXT ( " %04X,X " ) , 3 , " Absolute,X " } , // AM_AX // %s,X
{ TEXT ( " %04X,Y " ) , 3 , " Absolute,Y " } , // AM_AY // %s,Y
{ TEXT ( " %02X,X " ) , 2 , " Zero Page,X " } , // AM_ZX // %s,X
{ TEXT ( " %02X,Y " ) , 2 , " Zero Page,Y " } , // AM_ZY // %s,Y
{ TEXT ( " %s " ) , 2 , " Relative " } , // AM_R
{ TEXT ( " (%02X,X) " ) , 2 , " (Zero Page),X " } , // AM_IZX // ($%02X,X) -> %s,X
{ TEXT ( " (%04X,X) " ) , 3 , " (Absolute),X " } , // AM_IAX // ($%04X,X) -> %s,X
{ TEXT ( " (%02X),Y " ) , 2 , " (Zero Page),Y " } , // AM_NZY // ($%02X),Y
{ TEXT ( " (%02X) " ) , 2 , " (Zero Page) " } , // AM_NZ // ($%02X) -> $%02X
{ TEXT ( " (%04X) " ) , 3 , " (Absolute) " } // AM_NA // (%04X) -> %s
} ;
// Assembler ______________________________________________________________________________________
int g_bAssemblerOpcodesHashed = false ;
Hash_t g_aOpcodesHash [ NUM_OPCODES ] ; // for faster mnemonic lookup, for the assembler
bool g_bAssemblerInput = false ;
int g_nAssemblerAddress = 0 ;
const Opcodes_t * g_aOpcodes = NULL ; // & g_aOpcodes65C02[ 0 ];
// Disassembler Data _____________________________________________________________________________
2014-08-14 19:29:01 +00:00
std : : vector < DisasmData_t > g_aDisassemblerData ;
2010-06-11 15:38:22 +00:00
// Instructions / Opcodes _________________________________________________________________________
// @reference: http://www.6502.org/tutorials/compare_instructions.html
// 10 signed: BPL BGE
// B0 unsigned: BCS BGE
# define R_ MEM_R
# define _W MEM_W
# define RW MEM_R | MEM_W
# define _S MEM_S
# define im MEM_IM
# define SW MEM_S | MEM_WI
# define SR MEM_S | MEM_RI
const Opcodes_t g_aOpcodes65C02 [ NUM_OPCODES ] =
{
2017-08-04 19:52:17 +00:00
{ " BRK " , 0 , SW } , { " ORA " , AM_IZX , R_ } , { " nop " , AM_M , im } , { " nop " , 0 , 0 } , // 00 .. 03
2010-06-11 15:38:22 +00:00
{ " TSB " , AM_Z , _W } , { " ORA " , AM_Z , R_ } , { " ASL " , AM_Z , RW } , { " nop " , 0 , 0 } , // 04 .. 07
{ " PHP " , 0 , SW } , { " ORA " , AM_M , im } , { " ASL " , 0 , 0 } , { " nop " , 0 , 0 } , // 08 .. 0B
{ " TSB " , AM_A , _W } , { " ORA " , AM_A , R_ } , { " ASL " , AM_A , RW } , { " nop " , 0 , 0 } , // 0C .. 0F
{ " BPL " , AM_R , 0 } , { " ORA " , AM_NZY , R_ } , { " ORA " , AM_NZ , R_ } , { " nop " , 0 , 0 } , // 10 .. 13
{ " TRB " , AM_Z , _W } , { " ORA " , AM_ZX , R_ } , { " ASL " , AM_ZX , RW } , { " nop " , 0 , 0 } , // 14 .. 17
{ " CLC " , 0 , 0 } , { " ORA " , AM_AY , R_ } , { " INC " , 0 , 0 } , { " nop " , 0 , 0 } , // 18 .. 1B
{ " TRB " , AM_A , _W } , { " ORA " , AM_AX , R_ } , { " ASL " , AM_AX , RW } , { " nop " , 0 , 0 } , // 1C .. 1F
{ " JSR " , AM_A , SW } , { " AND " , AM_IZX , R_ } , { " nop " , AM_M , im } , { " nop " , 0 , 0 } , // 20 .. 23
{ " BIT " , AM_Z , R_ } , { " AND " , AM_Z , R_ } , { " ROL " , AM_Z , RW } , { " nop " , 0 , 0 } , // 24 .. 27
{ " PLP " , 0 , SR } , { " AND " , AM_M , im } , { " ROL " , 0 , 0 } , { " nop " , 0 , 0 } , // 28 .. 2B
{ " BIT " , AM_A , R_ } , { " AND " , AM_A , R_ } , { " ROL " , AM_A , RW } , { " nop " , 0 , 0 } , // 2C .. 2F
{ " BMI " , AM_R , 0 } , { " AND " , AM_NZY , R_ } , { " AND " , AM_NZ , R_ } , { " nop " , 0 , 0 } , // 30 .. 33
{ " BIT " , AM_ZX , R_ } , { " AND " , AM_ZX , R_ } , { " ROL " , AM_ZX , RW } , { " nop " , 0 , 0 } , // 34 .. 37
{ " SEC " , 0 , 0 } , { " AND " , AM_AY , R_ } , { " DEC " , 0 , 0 } , { " nop " , 0 , 0 } , // 38 .. 3B
{ " BIT " , AM_AX , R_ } , { " AND " , AM_AX , R_ } , { " ROL " , AM_AX , RW } , { " nop " , 0 , 0 } , // 3C .. 3F
2019-10-22 20:31:53 +00:00
{ " RTI " , 0 , SR } , { " EOR " , AM_IZX , R_ } , { " nop " , AM_M , im } , { " nop " , 0 , 0 } , // 40 .. 43
2010-06-11 15:38:22 +00:00
{ " nop " , AM_Z , 0 } , { " EOR " , AM_Z , R_ } , { " LSR " , AM_Z , _W } , { " nop " , 0 , 0 } , // 44 .. 47
{ " PHA " , 0 , SW } , { " EOR " , AM_M , im } , { " LSR " , 0 , 0 } , { " nop " , 0 , 0 } , // 48 .. 4B
{ " JMP " , AM_A , 0 } , { " EOR " , AM_A , R_ } , { " LSR " , AM_A , _W } , { " nop " , 0 , 0 } , // 4C .. 4F
{ " BVC " , AM_R , 0 } , { " EOR " , AM_NZY , R_ } , { " EOR " , AM_NZ , R_ } , { " nop " , 0 , 0 } , // 50 .. 53
{ " nop " , AM_ZX , 0 } , { " EOR " , AM_ZX , R_ } , { " LSR " , AM_ZX , _W } , { " nop " , 0 , 0 } , // 54 .. 57
{ " CLI " , 0 , 0 } , { " EOR " , AM_AY , R_ } , { " PHY " , 0 , SW } , { " nop " , 0 , 0 } , // 58 .. 5B
{ " nop " , AM_AX , 0 } , { " EOR " , AM_AX , R_ } , { " LSR " , AM_AX , RW } , { " nop " , 0 , 0 } , // 5C .. 5F
{ " RTS " , 0 , SR } , { " ADC " , AM_IZX , R_ } , { " nop " , AM_M , im } , { " nop " , 0 , 0 } , // 60 .. 63
{ " STZ " , AM_Z , _W } , { " ADC " , AM_Z , R_ } , { " ROR " , AM_Z , RW } , { " nop " , 0 , 0 } , // 64 .. 67
{ " PLA " , 0 , SR } , { " ADC " , AM_M , im } , { " ROR " , 0 , 0 } , { " nop " , 0 , 0 } , // 68 .. 6B
2019-12-09 19:13:24 +00:00
{ " JMP " , AM_NA , R_ } , { " ADC " , AM_A , R_ } , { " ROR " , AM_A , RW } , { " nop " , 0 , 0 } , // 6C .. 6F
2010-06-11 15:38:22 +00:00
{ " BVS " , AM_R , 0 } , { " ADC " , AM_NZY , R_ } , { " ADC " , AM_NZ , R_ } , { " nop " , 0 , 0 } , // 70 .. 73
{ " STZ " , AM_ZX , _W } , { " ADC " , AM_ZX , R_ } , { " ROR " , AM_ZX , RW } , { " nop " , 0 , 0 } , // 74 .. 77
{ " SEI " , 0 , 0 } , { " ADC " , AM_AY , R_ } , { " PLY " , 0 , SR } , { " nop " , 0 , 0 } , // 78 .. 7B
2019-12-09 19:13:24 +00:00
{ " JMP " , AM_IAX , R_ } , { " ADC " , AM_AX , R_ } , { " ROR " , AM_AX , RW } , { " nop " , 0 , 0 } , // 7C .. 7F
2010-06-11 15:38:22 +00:00
{ " BRA " , AM_R , 0 } , { " STA " , AM_IZX , _W } , { " nop " , AM_M , im } , { " nop " , 0 , 0 } , // 80 .. 83
{ " STY " , AM_Z , _W } , { " STA " , AM_Z , _W } , { " STX " , AM_Z , _W } , { " nop " , 0 , 0 } , // 84 .. 87
{ " DEY " , 0 , 0 } , { " BIT " , AM_M , im } , { " TXA " , 0 , 0 } , { " nop " , 0 , 0 } , // 88 .. 8B
{ " STY " , AM_A , _W } , { " STA " , AM_A , _W } , { " STX " , AM_A , _W } , { " nop " , 0 , 0 } , // 8C .. 8F
{ " BCC " , AM_R , 0 } , { " STA " , AM_NZY , _W } , { " STA " , AM_NZ , _W } , { " nop " , 0 , 0 } , // 90 .. 93
{ " STY " , AM_ZX , _W } , { " STA " , AM_ZX , _W } , { " STX " , AM_ZY , _W } , { " nop " , 0 , 0 } , // 94 .. 97
{ " TYA " , 0 , 0 } , { " STA " , AM_AY , _W } , { " TXS " , 0 , 0 } , { " nop " , 0 , 0 } , // 98 .. 9B
{ " STZ " , AM_A , _W } , { " STA " , AM_AX , _W } , { " STZ " , AM_AX , _W } , { " nop " , 0 , 0 } , // 9C .. 9F
{ " LDY " , AM_M , im } , { " LDA " , AM_IZX , R_ } , { " LDX " , AM_M , im } , { " nop " , 0 , 0 } , // A0 .. A3
{ " LDY " , AM_Z , R_ } , { " LDA " , AM_Z , R_ } , { " LDX " , AM_Z , R_ } , { " nop " , 0 , 0 } , // A4 .. A7
{ " TAY " , 0 , 0 } , { " LDA " , AM_M , im } , { " TAX " , 0 , 0 } , { " nop " , 0 , 0 } , // A8 .. AB
{ " LDY " , AM_A , R_ } , { " LDA " , AM_A , R_ } , { " LDX " , AM_A , R_ } , { " nop " , 0 , 0 } , // AC .. AF
{ " BCS " , AM_R , 0 } , { " LDA " , AM_NZY , R_ } , { " LDA " , AM_NZ , R_ } , { " nop " , 0 , 0 } , // B0 .. B3
{ " LDY " , AM_ZX , R_ } , { " LDA " , AM_ZX , R_ } , { " LDX " , AM_ZY , R_ } , { " nop " , 0 , 0 } , // B4 .. B7
{ " CLV " , 0 , 0 } , { " LDA " , AM_AY , R_ } , { " TSX " , 0 , 0 } , { " nop " , 0 , 0 } , // B8 .. BB
{ " LDY " , AM_AX , R_ } , { " LDA " , AM_AX , R_ } , { " LDX " , AM_AY , R_ } , { " nop " , 0 , 0 } , // BC .. BF
{ " CPY " , AM_M , im } , { " CMP " , AM_IZX , R_ } , { " nop " , AM_M , im } , { " nop " , 0 , 0 } , // C0 .. C3
{ " CPY " , AM_Z , R_ } , { " CMP " , AM_Z , R_ } , { " DEC " , AM_Z , RW } , { " nop " , 0 , 0 } , // C4 .. C7
{ " INY " , 0 , 0 } , { " CMP " , AM_M , im } , { " DEX " , 0 , 0 } , { " nop " , 0 , 0 } , // C8 .. CB
{ " CPY " , AM_A , R_ } , { " CMP " , AM_A , R_ } , { " DEC " , AM_A , RW } , { " nop " , 0 , 0 } , // CC .. CF
{ " BNE " , AM_R , 0 } , { " CMP " , AM_NZY , R_ } , { " CMP " , AM_NZ , 0 } , { " nop " , 0 , 0 } , // D0 .. D3
{ " nop " , AM_ZX , 0 } , { " CMP " , AM_ZX , R_ } , { " DEC " , AM_ZX , RW } , { " nop " , 0 , 0 } , // D4 .. D7
2017-08-04 19:52:17 +00:00
{ " CLD " , 0 , 0 } , { " CMP " , AM_AY , R_ } , { " PHX " , 0 , SW } , { " nop " , 0 , 0 } , // D8 .. DB
2010-06-11 15:38:22 +00:00
{ " nop " , AM_AX , 0 } , { " CMP " , AM_AX , R_ } , { " DEC " , AM_AX , RW } , { " nop " , 0 , 0 } , // DC .. DF
{ " CPX " , AM_M , im } , { " SBC " , AM_IZX , R_ } , { " nop " , AM_M , im } , { " nop " , 0 , 0 } , // E0 .. E3
{ " CPX " , AM_Z , R_ } , { " SBC " , AM_Z , R_ } , { " INC " , AM_Z , RW } , { " nop " , 0 , 0 } , // E4 .. E7
{ " INX " , 0 , 0 } , { " SBC " , AM_M , R_ } , { " NOP " , 0 , 0 } , { " nop " , 0 , 0 } , // E8 .. EB
{ " CPX " , AM_A , R_ } , { " SBC " , AM_A , R_ } , { " INC " , AM_A , RW } , { " nop " , 0 , 0 } , // EC .. EF
{ " BEQ " , AM_R , 0 } , { " SBC " , AM_NZY , R_ } , { " SBC " , AM_NZ , 0 } , { " nop " , 0 , 0 } , // F0 .. F3
{ " nop " , AM_ZX , 0 } , { " SBC " , AM_ZX , R_ } , { " INC " , AM_ZX , RW } , { " nop " , 0 , 0 } , // F4 .. F7
2017-08-04 19:52:17 +00:00
{ " SED " , 0 , 0 } , { " SBC " , AM_AY , R_ } , { " PLX " , 0 , SR } , { " nop " , 0 , 0 } , // F8 .. FB
2010-06-11 15:38:22 +00:00
{ " nop " , AM_AX , 0 } , { " SBC " , AM_AX , R_ } , { " INC " , AM_AX , RW } , { " nop " , 0 , 0 } // FF .. FF
} ;
const Opcodes_t g_aOpcodes6502 [ NUM_OPCODES ] =
{ // Should match Cpu.cpp InternalCpuExecute() switch (*(mem+regs.pc++)) !!
/*
Based on : http : //axis.llx.com/~nparker/a2/opcodes.html
If you really want to know what the undocumented - - - ( n / a ) opcodes do , see
CPU . cpp
x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
2017-04-05 14:51:16 +00:00
0 x BRK ORA ( d , X ) - - - - - - tsb z ORA d ASL z - - - PHP ORA # ASL A - - - tsb a ORA a ASL a - - -
1 x BPL r ORA ( d ) , Y ora ( z ) - - - trb d ORA d , X ASL z , X - - - CLC ORA a , Y ina A - - - trb a ORA a , X ASL a , X - - -
2 x JSR a AND ( d , X ) - - - - - - BIT d AND d ROL z - - - PLP AND # ROL A - - - BIT a AND a ROL a - - -
3 x BMI r AND ( d ) , Y and ( z ) - - - bit d , X AND d , X ROL z , X - - - SEC AND a , Y dea A - - - bit a , X AND a , X ROL a , X - - -
4 x RTI EOR ( d , X ) - - - - - - - - - EOR d LSR z - - - PHA EOR # LSR A - - - JMP a EOR a LSR a - - -
5 x BVC r EOR ( d ) , Y eor ( z ) - - - - - - EOR d , X LSR z , X - - - CLI EOR a , Y phy - - - - - - EOR a , X LSR a , X - - -
6 x RTS ADC ( d , X ) - - - - - - stz d ADC d ROR z - - - PLA ADC # ROR A - - - JMP ( a ) ADC a ROR a - - -
7 x BVS r ADC ( d ) , Y adc ( z ) - - - stz d , X ADC d , X ROR z , X - - - SEI ADC a , Y ply - - - jmp ( a , X ) ADC a , X ROR a , X - - -
8 x bra r STA ( d , X ) - - - - - - STY d STA d STX z - - - DEY bit # TXA - - - STY a STA a STX a - - -
9 x BCC r STA ( d ) , Y sta ( z ) - - - STY d , X STA d , X STX z , Y - - - TYA STA a , Y TXS - - - Stz a STA a , X stz a , X - - -
Ax LDY # LDA ( d , X ) LDX # - - - LDY d LDA d LDX z - - - TAY LDA # TAX - - - LDY a LDA a LDX a - - -
Bx BCS r LDA ( d ) , Y lda ( z ) - - - LDY d , X LDA d , X LDX z , Y - - - CLV LDA a , Y TSX - - - LDY a , X LDA a , X LDX a , Y - - -
Cx CPY # CMP ( d , X ) - - - - - - CPY d CMP d DEC z - - - INY CMP # DEX - - - CPY a CMP a DEC a - - -
Dx BNE r CMP ( d ) , Y cmp ( z ) - - - - - - CMP d , X DEC z , X - - - CLD CMP a , Y phx - - - - - - CMP a , X DEC a , X - - -
Ex CPX # SBC ( d , X ) - - - - - - CPX d SBC d INC z - - - INX SBC # NOP - - - CPX a SBC a INC a - - -
Fx BEQ r SBC ( d ) , Y sbc ( z ) - - - - - - SBC d , X INC z , X - - - SED SBC a , Y plx - - - - - - SBC a , X INC a , X - - -
2010-06-11 15:38:22 +00:00
Legend :
2017-04-05 14:51:16 +00:00
- - - illegal instruction
2010-06-11 15:38:22 +00:00
UPPERCASE 6502
lowercase 65 C02
80
12 , 32 , 52 , 72 , 92 , B2 , D2 , F2
04 , 14 , 34 , 64 , 74
89
1 A , 3 A , 5 A , 7 A , DA , FA
0 C , 1 C , 3 C , 7 C , 9 C ;
# Immediate
A Accumulator ( implicit for mnemonic )
a absolute
r Relative
2017-04-05 14:51:16 +00:00
d Destination 16 - bit Address
z Destination Zero Page Address
z , x Base = Zero - Page , Offset = X
2010-06-11 15:38:22 +00:00
d , x
( d , X )
( d ) , Y
*/
2017-08-04 19:52:17 +00:00
{ " BRK " , 0 , SW } , { " ORA " , AM_IZX , R_ } , { " hlt " , 0 , 0 } , { " aso " , AM_IZX , RW } , // 00 .. 03
2010-06-11 15:38:22 +00:00
{ " nop " , AM_Z , R_ } , { " ORA " , AM_Z , R_ } , { " ASL " , AM_Z , RW } , { " aso " , AM_Z , RW } , // 04 .. 07
{ " PHP " , 0 , SW } , { " ORA " , AM_M , im } , { " ASL " , 0 , 0 } , { " anc " , AM_M , im } , // 08 .. 0B
{ " nop " , AM_AX , 0 } , { " ORA " , AM_A , R_ } , { " ASL " , AM_A , RW } , { " aso " , AM_A , RW } , // 0C .. 0F
{ " BPL " , AM_R , 0 } , { " ORA " , AM_NZY , R_ } , { " hlt " , 0 , 0 } , { " aso " , AM_NZY , RW } , // 10 .. 13
{ " nop " , AM_ZX , 0 } , { " ORA " , AM_ZX , R_ } , { " ASL " , AM_ZX , RW } , { " aso " , AM_ZX , RW } , // 14 .. 17
{ " CLC " , 0 , 0 } , { " ORA " , AM_AY , R_ } , { " nop " , 0 , 0 } , { " aso " , AM_AY , RW } , // 18 .. 1B
{ " nop " , AM_AX , 0 } , { " ORA " , AM_AX , R_ } , { " ASL " , AM_AX , RW } , { " aso " , AM_AX , RW } , // 1C .. 1F
{ " JSR " , AM_A , SW } , { " AND " , AM_IZX , R_ } , { " hlt " , 0 , 0 } , { " rla " , AM_IZX , RW } , // 20 .. 23
{ " BIT " , AM_Z , R_ } , { " AND " , AM_Z , R_ } , { " ROL " , AM_Z , RW } , { " rla " , AM_Z , RW } , // 24 .. 27
{ " PLP " , 0 , SR } , { " AND " , AM_M , im } , { " ROL " , 0 , 0 } , { " anc " , AM_M , im } , // 28 .. 2B
{ " BIT " , AM_A , R_ } , { " AND " , AM_A , R_ } , { " ROL " , AM_A , RW } , { " rla " , AM_A , RW } , // 2C .. 2F
{ " BMI " , AM_R , 0 } , { " AND " , AM_NZY , R_ } , { " hlt " , 0 , 0 } , { " rla " , AM_NZY , RW } , // 30 .. 33
{ " nop " , AM_ZX , 0 } , { " AND " , AM_ZX , R_ } , { " ROL " , AM_ZX , RW } , { " rla " , AM_ZX , RW } , // 34 .. 37
{ " SEC " , 0 , 0 } , { " AND " , AM_AY , R_ } , { " nop " , 0 , 0 } , { " rla " , AM_AY , RW } , // 38 .. 3B
{ " nop " , AM_AX , 0 } , { " AND " , AM_AX , R_ } , { " ROL " , AM_AX , RW } , { " rla " , AM_AX , RW } , // 3C .. 3F
2019-10-22 20:31:53 +00:00
{ " RTI " , 0 , SR } , { " EOR " , AM_IZX , R_ } , { " hlt " , 0 , 0 } , { " lse " , AM_IZX , RW } , // 40 .. 43
2010-06-11 15:38:22 +00:00
{ " nop " , AM_Z , 0 } , { " EOR " , AM_Z , R_ } , { " LSR " , AM_Z , RW } , { " lse " , AM_Z , RW } , // 44 .. 47
{ " PHA " , 0 , SW } , { " EOR " , AM_M , im } , { " LSR " , 0 , 0 } , { " alr " , AM_M , im } , // 48 .. 4B
{ " JMP " , AM_A , 0 } , { " EOR " , AM_A , R_ } , { " LSR " , AM_A , RW } , { " lse " , AM_A , RW } , // 4C .. 4F
{ " BVC " , AM_R , 0 } , { " EOR " , AM_NZY , R_ } , { " hlt " , 0 , 0 } , { " lse " , AM_NZY , RW } , // 50 .. 53
{ " nop " , AM_ZX , 0 } , { " EOR " , AM_ZX , R_ } , { " LSR " , AM_ZX , RW } , { " lse " , AM_ZX , RW } , // 54 .. 57
{ " CLI " , 0 , 0 } , { " EOR " , AM_AY , R_ } , { " nop " , 0 , 0 } , { " lse " , AM_AY , RW } , // 58 .. 5B
{ " nop " , AM_AX , 0 } , { " EOR " , AM_AX , R_ } , { " LSR " , AM_AX , RW } , { " lse " , AM_AX , RW } , // 5C .. 5F
{ " RTS " , 0 , SR } , { " ADC " , AM_IZX , R_ } , { " hlt " , 0 , 0 } , { " rra " , AM_IZX , RW } , // 60 .. 63
{ " nop " , AM_Z , 0 } , { " ADC " , AM_Z , R_ } , { " ROR " , AM_Z , RW } , { " rra " , AM_Z , RW } , // 64 .. 67
{ " PLA " , 0 , SR } , { " ADC " , AM_M , im } , { " ROR " , 0 , 0 } , { " arr " , AM_M , im } , // 68 .. 6B
2019-12-09 19:13:24 +00:00
{ " JMP " , AM_NA , R_ } , { " ADC " , AM_A , R_ } , { " ROR " , AM_A , RW } , { " rra " , AM_A , RW } , // 6C .. 6F
2010-06-11 15:38:22 +00:00
{ " BVS " , AM_R , 0 } , { " ADC " , AM_NZY , R_ } , { " hlt " , 0 , 0 } , { " rra " , AM_NZY , RW } , // 70 .. 73
{ " nop " , AM_ZX , 0 } , { " ADC " , AM_ZX , R_ } , { " ROR " , AM_ZX , RW } , { " rra " , AM_ZX , RW } , // 74 .. 77
{ " SEI " , 0 , 0 } , { " ADC " , AM_AY , R_ } , { " nop " , 0 , 0 } , { " rra " , AM_AY , RW } , // 78 .. 7B
{ " nop " , AM_AX , 0 } , { " ADC " , AM_AX , R_ } , { " ROR " , AM_AX , RW } , { " rra " , AM_AX , RW } , // 7C .. 7F
{ " nop " , AM_M , im } , { " STA " , AM_IZX , _W } , { " nop " , AM_M , im } , { " axs " , AM_IZX , _W } , // 80 .. 83
{ " STY " , AM_Z , _W } , { " STA " , AM_Z , _W } , { " STX " , AM_Z , _W } , { " axs " , AM_Z , _W } , // 84 .. 87
{ " DEY " , 0 , 0 } , { " nop " , AM_M , im } , { " TXA " , 0 , 0 } , { " xaa " , AM_M , im } , // 88 .. 8B
{ " STY " , AM_A , _W } , { " STA " , AM_A , _W } , { " STX " , AM_A , _W } , { " axs " , AM_A , _W } , // 8C .. 8F
{ " BCC " , AM_R , 0 } , { " STA " , AM_NZY , _W } , { " hlt " , 0 , 0 } , { " axa " , AM_NZY , _W } , // 90 .. 93
{ " STY " , AM_ZX , _W } , { " STA " , AM_ZX , _W } , { " STX " , AM_ZY , _W } , { " axs " , AM_ZY , _W } , // 94 .. 97
{ " TYA " , 0 , 0 } , { " STA " , AM_AY , _W } , { " TXS " , 0 , 0 } , { " tas " , AM_AY , _W } , // 98 .. 9B
{ " say " , AM_AX , _W } , { " STA " , AM_AX , _W } , { " xas " , AM_AX , _W } , { " axa " , AM_AY , _W } , // 9C .. 9F
{ " LDY " , AM_M , im } , { " LDA " , AM_IZX , R_ } , { " LDX " , AM_M , im } , { " lax " , AM_IZX , R_ } , // A0 .. A3
{ " LDY " , AM_Z , R_ } , { " LDA " , AM_Z , R_ } , { " LDX " , AM_Z , R_ } , { " lax " , AM_Z , R_ } , // A4 .. A7
{ " TAY " , 0 , 0 } , { " LDA " , AM_M , im } , { " TAX " , 0 , 0 } , { " oal " , AM_M , im } , // A8 .. AB
{ " LDY " , AM_A , R_ } , { " LDA " , AM_A , R_ } , { " LDX " , AM_A , R_ } , { " lax " , AM_A , R_ } , // AC .. AF
{ " BCS " , AM_R , 0 } , { " LDA " , AM_NZY , R_ } , { " hlt " , 0 , 0 } , { " lax " , AM_NZY , R_ } , // B0 .. B3
{ " LDY " , AM_ZX , R_ } , { " LDA " , AM_ZX , R_ } , { " LDX " , AM_ZY , R_ } , { " lax " , AM_ZY , 0 } , // B4 .. B7
{ " CLV " , 0 , 0 } , { " LDA " , AM_AY , R_ } , { " TSX " , 0 , 0 } , { " las " , AM_AY , R_ } , // B8 .. BB
{ " LDY " , AM_AX , R_ } , { " LDA " , AM_AX , R_ } , { " LDX " , AM_AY , R_ } , { " lax " , AM_AY , R_ } , // BC .. BF
{ " CPY " , AM_M , im } , { " CMP " , AM_IZX , R_ } , { " nop " , AM_M , im } , { " dcm " , AM_IZX , RW } , // C0 .. C3
{ " CPY " , AM_Z , R_ } , { " CMP " , AM_Z , R_ } , { " DEC " , AM_Z , RW } , { " dcm " , AM_Z , RW } , // C4 .. C7
{ " INY " , 0 , 0 } , { " CMP " , AM_M , im } , { " DEX " , 0 , 0 } , { " sax " , AM_M , im } , // C8 .. CB
{ " CPY " , AM_A , R_ } , { " CMP " , AM_A , R_ } , { " DEC " , AM_A , RW } , { " dcm " , AM_A , RW } , // CC .. CF
{ " BNE " , AM_R , 0 } , { " CMP " , AM_NZY , R_ } , { " hlt " , 0 , 0 } , { " dcm " , AM_NZY , RW } , // D0 .. D3
{ " nop " , AM_ZX , 0 } , { " CMP " , AM_ZX , R_ } , { " DEC " , AM_ZX , RW } , { " dcm " , AM_ZX , RW } , // D4 .. D7
{ " CLD " , 0 , 0 } , { " CMP " , AM_AY , R_ } , { " nop " , 0 , 0 } , { " dcm " , AM_AY , RW } , // D8 .. DB
{ " nop " , AM_AX , 0 } , { " CMP " , AM_AX , R_ } , { " DEC " , AM_AX , RW } , { " dcm " , AM_AX , RW } , // DC .. DF
{ " CPX " , AM_M , im } , { " SBC " , AM_IZX , R_ } , { " nop " , AM_M , im } , { " ins " , AM_IZX , RW } , // E0 .. E3
{ " CPX " , AM_Z , R_ } , { " SBC " , AM_Z , R_ } , { " INC " , AM_Z , RW } , { " ins " , AM_Z , RW } , // E4 .. E7
{ " INX " , 0 , 0 } , { " SBC " , AM_M , im } , { " NOP " , 0 , 0 } , { " sbc " , AM_M , im } , // E8 .. EB
{ " CPX " , AM_A , R_ } , { " SBC " , AM_A , R_ } , { " INC " , AM_A , RW } , { " ins " , AM_A , RW } , // EC .. EF
{ " BEQ " , AM_R , 0 } , { " SBC " , AM_NZY , R_ } , { " hlt " , 0 , 0 } , { " ins " , AM_NZY , RW } , // F0 .. F3
{ " nop " , AM_ZX , 0 } , { " SBC " , AM_ZX , R_ } , { " INC " , AM_ZX , RW } , { " ins " , AM_ZX , RW } , // F4 .. F7
{ " SED " , 0 , 0 } , { " SBC " , AM_AY , R_ } , { " nop " , 0 , 0 } , { " ins " , AM_AY , RW } , // F8 .. FB
{ " nop " , AM_AX , 0 } , { " SBC " , AM_AX , R_ } , { " INC " , AM_AX , RW } , { " ins " , AM_AX , RW } // FF .. FF
} ;
# undef R_
# undef _W
# undef RW
# undef _S
# undef im
# undef SW
# undef SR
// @reference: http://www.textfiles.com/apple/DOCUMENTATION/merlin.docs1
// Private __________________________________________________________________
2010-12-16 06:43:05 +00:00
// NOTE: Keep in sync AsmDirectives_e g_aAssemblerDirectives !
2010-06-11 15:38:22 +00:00
AssemblerDirective_t g_aAssemblerDirectives [ NUM_ASM_DIRECTIVES ] =
{
// NULL n/a
{ " " } ,
2010-12-16 06:43:05 +00:00
// Origin, Target Address, EndProg, Equate, Data, AsciiString,HexString
2010-06-11 15:38:22 +00:00
// Acme
{ " ??? " } ,
// Big Mac
{ " ??? " } ,
// DOS Tool Kit
{ " ??? " } ,
// Lisa
{ " ??? " } ,
// Merlin
{ " ASC " } , // ASC "postive" 'negative'
{ " DDB " } , // Define Double Byte (Define WORD)
{ " DFB " } , // DeFine Byte
2010-12-16 06:43:05 +00:00
{ " DS " } , // Define Storage
2010-06-11 15:38:22 +00:00
{ " HEX " } , // HEX ###### or HEX ##,##,...
{ " ORG " } , // Origin
// MicroSparc
{ " ??? " } ,
// ORCA/M
{ " ??? " } ,
// SC ...
{ " .OR " } , // ORigin
{ " .TA " } , // Target Address
{ " .EN " } , // ENd of program
{ " .EQ " } , // EQuate
{ " .DA " } , // DAta
{ " .AS " } , // Ascii String
{ " .HS " } , // Hex String
// Ted II
{ " ??? " } ,
// Weller
{ " ??? " } ,
2010-12-16 06:43:05 +00:00
// User-Defined
// NOTE: Keep in sync AsmCustomDirective_e g_aAssemblerDirectives !
{ " db " } , // ASM_DEFINE_BYTE
{ " dw " } , // ASM_DEFINE_WORD
{ " da " } , // ASM_DEFINE_ADDRESS_16
// d memory Dump
// da Memory Ascii, Define Address
// ds S = Ascii (Low),
// dt T = Apple (High)
// dm M = Mixed (Low,High=EndofString)
{ " ds " } , // ASM_DEFINE_ASCII_TEXT
{ " dt " } , // ASM_DEFINE_APPLE_TEXT
{ " dm " } , // ASM_DEFINE_TEXT_HI_LO
{ " df " } , // ASM_DEFINE_FLOAT
{ " dfx " } , // ASM_DEFINE_FLOAT_X
} ;
int g_iAssemblerSyntax = ASM_CUSTOM ; // Which assembler syntax to use
int g_aAssemblerFirstDirective [ NUM_ASSEMBLERS ] =
{
FIRST_A_DIRECTIVE ,
FIRST_B_DIRECTIVE ,
FIRST_D_DIRECTIVE ,
FIRST_L_DIRECTIVE ,
FIRST_M_DIRECTIVE ,
FIRST_u_DIRECTIVE ,
FIRST_O_DIRECTIVE ,
FIRST_S_DIRECTIVE ,
FIRST_T_DIRECTIVE ,
FIRST_W_DIRECTIVE ,
FIRST_Z_DIRECTIVE
2010-06-11 15:38:22 +00:00
} ;
// Assemblers
enum AssemblerFlags_e
{
AF_HaveLabel = ( 1 < < 0 ) ,
AF_HaveComma = ( 1 < < 1 ) ,
AF_HaveHash = ( 1 < < 2 ) ,
AF_HaveImmediate = ( 1 < < 3 ) ,
AF_HaveDollar = ( 1 < < 4 ) ,
AF_HaveLeftParen = ( 1 < < 5 ) ,
AF_HaveRightParen = ( 1 < < 6 ) ,
AF_HaveEitherParen = ( 1 < < 7 ) ,
AF_HaveBothParen = ( 1 < < 8 ) ,
AF_HaveRegisterX = ( 1 < < 9 ) ,
AF_HaveRegisterY = ( 1 < < 10 ) ,
AF_HaveZeroPage = ( 1 < < 11 ) ,
AF_HaveTarget = ( 1 < < 12 ) ,
} ;
enum AssemblerState_e
{
AS_GET_MNEMONIC
, AS_GET_MNEMONIC_PARM
, AS_GET_HASH
, AS_GET_TARGET
, AS_GET_PAREN
, AS_GET_INDEX
, AS_DONE
} ;
int m_bAsmFlags ;
2014-08-14 19:29:01 +00:00
std : : vector < int > m_vAsmOpcodes ;
2010-06-11 15:38:22 +00:00
int m_iAsmAddressMode = AM_IMPLIED ;
struct DelayedTarget_t
{
char m_sAddress [ MAX_SYMBOLS_LEN + 1 ] ;
WORD m_nBaseAddress ; // mem address to store symbol at
int m_nOpcode ;
int m_iOpmode ; // AddressingMode_e
} ;
2014-08-14 19:29:01 +00:00
std : : vector < DelayedTarget_t > m_vDelayedTargets ;
2010-06-11 15:38:22 +00:00
bool m_bDelayedTargetsDirty = false ;
int m_nAsmBytes = 0 ;
WORD m_nAsmBaseAddress = 0 ;
WORD m_nAsmTargetAddress = 0 ;
WORD m_nAsmTargetValue = 0 ;
2010-12-16 06:43:05 +00:00
// Private
void AssemblerHashOpcodes ( ) ;
void AssemblerHashDirectives ( ) ;
2010-06-11 15:38:22 +00:00
// Implementation ___________________________________________________________
//===========================================================================
bool _6502_CalcRelativeOffset ( int nOpcode , int nBaseAddress , int nTargetAddress , WORD * pTargetOffset_ )
{
if ( _6502_IsOpcodeBranch ( nOpcode ) )
{
// Branch is
// a) relative to address+2
// b) in 2's compliment
//
// i.e.
// 300: D0 7F -> BNE $381 0x381 - 0x300 = 0x81 +129
// 300: D0 80 -> BNE $282 0x282 - 0x300 = -126
//
// 300: D0 7E BNE $380
// ^ ^ ^ ^
// | | | TargetAddress
// | | TargetOffset
// | Opcode
// BaseAddress
int nDistance = nTargetAddress - nBaseAddress ;
if ( pTargetOffset_ )
* pTargetOffset_ = ( BYTE ) ( nDistance - 2 ) ;
if ( ( nDistance - 2 ) > _6502_BRANCH_POS )
m_iAsmAddressMode = NUM_OPMODES ; // signal bad
if ( ( nDistance - 2 ) < _6502_BRANCH_NEG )
m_iAsmAddressMode = NUM_OPMODES ; // signal bad
return true ;
}
return false ;
}
//===========================================================================
2014-08-28 23:52:41 +00:00
int _6502_GetOpmodeOpbyte ( const int nBaseAddress , int & iOpmode_ , int & nOpbyte_ , const DisasmData_t * * pData_ )
2010-06-11 15:38:22 +00:00
{
# if _DEBUG
if ( ! g_aOpcodes )
{
2021-01-19 20:37:43 +00:00
GetFrame ( ) . FrameMessageBox ( " Debugger not properly initialized " , " ERROR " , MB_OK ) ;
2016-05-17 21:03:45 +00:00
g_aOpcodes = & g_aOpcodes65C02 [ 0 ] ; // Enhanced Apple //e
g_aOpmodes [ AM_2 ] . m_nBytes = 2 ;
g_aOpmodes [ AM_3 ] . m_nBytes = 3 ;
2010-06-11 15:38:22 +00:00
}
# endif
2010-12-19 16:58:40 +00:00
int iOpcode_ = * ( mem + nBaseAddress ) ;
2010-06-11 15:38:22 +00:00
iOpmode_ = g_aOpcodes [ iOpcode_ ] . nAddressMode ;
nOpbyte_ = g_aOpmodes [ iOpmode_ ] . m_nBytes ;
2010-12-19 16:58:40 +00:00
// 2.6.2.25 Fixed: DB DW custom data byte sizes weren't scrolling properly in the disasm view.
// Changed _6502_GetOpmodeOpbyte() to be aware of data bytes.
//
// NOTE: _6502_GetOpmodeOpbyte() needs to (effectively) call Disassembly_GetData()
// a) the CmdCursorLineUp() calls us to calc for -X bytes back up how to reach the cursor (address) line below
// b) The disassembler view needs to know how many bytes each line is.
int nSlack ;
2011-01-04 16:39:08 +00:00
// 2.7.0.0 TODO: FIXME: Opcode length that over-lap data, should be shortened ... if (nOpbyte_ > 1) if Disassembly_IsDataAddress( nBaseAddress + 1 ) nOpbyte_ = 1;
2010-12-19 16:58:40 +00:00
DisasmData_t * pData = Disassembly_IsDataAddress ( nBaseAddress ) ;
if ( pData )
{
2014-08-28 23:52:41 +00:00
if ( pData_ )
* pData_ = pData ;
2014-08-28 18:13:02 +00:00
nSlack = pData - > nEndAddress - pData - > nStartAddress + 1 ; // *inclusive* KEEP IN SYNC: _CmdDefineByteRange() CmdDisasmDataList() _6502_GetOpmodeOpbyte() FormatNopcodeBytes()
2010-12-19 16:58:40 +00:00
2014-08-28 18:13:02 +00:00
// Data Disassembler
// Smart Disassembly - Data Section
// Assemblyer Directives - Psuedo Mnemonics
2010-12-19 16:58:40 +00:00
switch ( pData - > eElementType )
{
case NOP_BYTE_1 : nOpbyte_ = 1 ; iOpmode_ = AM_M ; break ;
case NOP_BYTE_2 : nOpbyte_ = 2 ; iOpmode_ = AM_M ; break ;
case NOP_BYTE_4 : nOpbyte_ = 4 ; iOpmode_ = AM_M ; break ;
case NOP_BYTE_8 : nOpbyte_ = 8 ; iOpmode_ = AM_M ; break ;
case NOP_WORD_1 : nOpbyte_ = 2 ; iOpmode_ = AM_M ; break ;
case NOP_WORD_2 : nOpbyte_ = 4 ; iOpmode_ = AM_M ; break ;
case NOP_WORD_4 : nOpbyte_ = 8 ; iOpmode_ = AM_M ; break ;
2011-01-04 16:39:08 +00:00
case NOP_ADDRESS : nOpbyte_ = 2 ; iOpmode_ = AM_A ; // BUGFIX: 2.6.2.33 Define Address should be shown as Absolute mode, not Indirect Absolute mode. DA BASIC.FPTR D000:D080 // was showing as "da (END-1)" now shows as "da END-1"
2010-12-19 17:10:02 +00:00
pData - > nTargetAddress = * ( LPWORD ) ( mem + nBaseAddress ) ;
break ;
2014-08-28 18:13:02 +00:00
case NOP_STRING_APPLE :
iOpmode_ = AM_DATA ;
nOpbyte_ = nSlack ;
break ;
2010-12-19 17:10:02 +00:00
case NOP_STRING_APPLESOFT :
// TODO: FIXME: scan memory for high byte
nOpbyte_ = 8 ;
2014-08-28 18:13:02 +00:00
iOpmode_ = AM_DATA ;
2010-12-19 17:10:02 +00:00
break ;
2014-08-28 18:13:02 +00:00
default :
# if _DEBUG // not implemented!
int * fatal = 0 ;
* fatal = 0xDEADC0DE ;
# endif
2014-08-28 21:34:25 +00:00
break ;
2010-12-19 16:58:40 +00:00
}
2014-08-28 18:13:02 +00:00
/*
// REMOVED in v1.25 ... because of AppleSoft Basic: DW NEXT1 801 DW LINE1 803
2010-12-19 16:58:40 +00:00
// Check if we are not element aligned ...
nSlack = ( nOpbyte_ > 1 ) ? ( nBaseAddress & nOpbyte_ - 1 ) : 0 ;
if ( nSlack )
{
nOpbyte_ = nSlack ;
iOpmode_ = AM_M ;
}
2014-08-28 18:13:02 +00:00
*/
2010-12-19 16:58:40 +00:00
//iOpcode_ = NUM_OPCODES; // Don't have valid opcodes ... we have data !
// iOpcode_ = (int)( pData ); // HACK: pass pData back to caller ...
2014-12-11 18:00:51 +00:00
iOpcode_ = OPCODE_NOP ;
2010-12-19 16:58:40 +00:00
}
2010-06-11 15:38:22 +00:00
# if _DEBUG
if ( iOpcode_ > = NUM_OPCODES )
{
bool bStop = true ;
}
# endif
return iOpcode_ ;
}
//===========================================================================
void _6502_GetOpcodeOpmodeOpbyte ( int & iOpcode_ , int & iOpmode_ , int & nOpbyte_ )
{
iOpcode_ = _6502_GetOpmodeOpbyte ( regs . pc , iOpmode_ , nOpbyte_ ) ;
}
//===========================================================================
bool _6502_GetStackReturnAddress ( WORD & nAddress_ )
{
unsigned nStack = regs . sp ;
nStack + + ;
if ( nStack < = ( _6502_STACK_END - 1 ) )
{
nAddress_ = ( unsigned ) * ( LPBYTE ) ( mem + nStack ) ;
nStack + + ;
nAddress_ + = ( ( unsigned ) * ( LPBYTE ) ( mem + nStack ) ) < < 8 ;
nAddress_ + + ;
return true ;
}
return false ;
}
//===========================================================================
2019-11-27 22:14:16 +00:00
bool _6502_GetTargets ( WORD nAddress , int * pTargetPartial_ , int * pTargetPartial2_ , int * pTargetPointer_ , int * pTargetBytes_ ,
2019-12-09 20:42:16 +00:00
bool bIgnoreBranch /*= true*/ , bool bIncludeNextOpcodeAddress /*= true*/ )
2010-06-11 15:38:22 +00:00
{
if ( ! pTargetPartial_ )
2019-12-09 20:42:16 +00:00
return false ;
2010-06-11 15:38:22 +00:00
2017-08-04 19:52:17 +00:00
if ( ! pTargetPartial2_ )
2019-12-09 20:42:16 +00:00
return false ;
2017-08-04 19:52:17 +00:00
2010-06-11 15:38:22 +00:00
if ( ! pTargetPointer_ )
2019-12-09 20:42:16 +00:00
return false ;
2010-06-11 15:38:22 +00:00
// if (! pTargetBytes_)
2019-12-09 20:42:16 +00:00
// return false;
2010-06-11 15:38:22 +00:00
* pTargetPartial_ = NO_6502_TARGET ;
2017-08-04 19:52:17 +00:00
* pTargetPartial2_ = NO_6502_TARGET ;
2010-06-11 15:38:22 +00:00
* pTargetPointer_ = NO_6502_TARGET ;
if ( pTargetBytes_ )
* pTargetBytes_ = 0 ;
2017-08-15 21:12:51 +00:00
BYTE nOpcode = mem [ nAddress ] ;
BYTE nTarget8 = mem [ ( nAddress + 1 ) & 0xFFFF ] ;
WORD nTarget16 = ( mem [ ( nAddress + 2 ) & 0xFFFF ] < < 8 ) | nTarget8 ;
2010-06-11 15:38:22 +00:00
int eMode = g_aOpcodes [ nOpcode ] . nAddressMode ;
2010-12-19 16:58:40 +00:00
// We really need to use the values that are code and data assembler
// TODO: FIXME: _6502_GetOpmodeOpbyte( iAddress, iOpmode, nOpbytes );
2010-06-11 15:38:22 +00:00
switch ( eMode )
{
2017-08-04 19:52:17 +00:00
case AM_IMPLIED :
if ( g_aOpcodes [ nOpcode ] . nMemoryAccess & MEM_S ) // Stack R/W?
{
if ( nOpcode = = OPCODE_RTI | | nOpcode = = OPCODE_RTS ) // RTI or RTS?
{
WORD sp = regs . sp ;
if ( nOpcode = = OPCODE_RTI )
{
//*pTargetPartial3_ = _6502_STACK_BEGIN + ((sp+1) & 0xFF); // TODO: PLP
+ + sp ;
}
* pTargetPartial_ = _6502_STACK_BEGIN + ( ( sp + 1 ) & 0xFF ) ;
* pTargetPartial2_ = _6502_STACK_BEGIN + ( ( sp + 2 ) & 0xFF ) ;
nTarget16 = mem [ * pTargetPartial_ ] + ( mem [ * pTargetPartial2_ ] < < 8 ) ;
if ( nOpcode = = OPCODE_RTS )
+ + nTarget16 ;
}
else if ( nOpcode = = OPCODE_BRK ) // BRK?
{
* pTargetPartial_ = _6502_STACK_BEGIN + ( ( regs . sp + 0 ) & 0xFF ) ;
* pTargetPartial2_ = _6502_STACK_BEGIN + ( ( regs . sp - 1 ) & 0xFF ) ;
//*pTargetPartial3_ = _6502_STACK_BEGIN + ((regs.sp-2) & 0xFF); // TODO: PHP
//*pTargetPartial4_ = _6502_BRK_VECTOR + 0; // TODO
//*pTargetPartial5_ = _6502_BRK_VECTOR + 1; // TODO
nTarget16 = * ( LPWORD ) ( mem + _6502_BRK_VECTOR ) ;
}
else // PHn/PLn
{
if ( g_aOpcodes [ nOpcode ] . nMemoryAccess & MEM_WI )
nTarget16 = _6502_STACK_BEGIN + ( ( regs . sp + 0 ) & 0xFF ) ;
else
nTarget16 = _6502_STACK_BEGIN + ( ( regs . sp + 1 ) & 0xFF ) ;
}
2019-12-09 16:27:13 +00:00
if ( bIncludeNextOpcodeAddress | | ( nOpcode ! = OPCODE_RTI & & nOpcode ! = OPCODE_RTS & & nOpcode ! = OPCODE_BRK ) )
* pTargetPointer_ = nTarget16 ;
2017-08-04 19:52:17 +00:00
if ( pTargetBytes_ )
* pTargetBytes_ = 1 ;
}
break ;
2019-12-09 16:27:13 +00:00
case AM_A : // Absolute
2019-12-09 20:42:16 +00:00
if ( nOpcode = = OPCODE_JSR )
2017-08-04 19:52:17 +00:00
{
* pTargetPartial_ = _6502_STACK_BEGIN + ( ( regs . sp + 0 ) & 0xFF ) ;
* pTargetPartial2_ = _6502_STACK_BEGIN + ( ( regs . sp - 1 ) & 0xFF ) ;
}
2019-12-09 20:42:16 +00:00
if ( bIncludeNextOpcodeAddress | | ( nOpcode ! = OPCODE_JSR & & nOpcode ! = OPCODE_JMP_A ) )
2019-12-09 16:27:13 +00:00
* pTargetPointer_ = nTarget16 ;
2010-06-11 15:38:22 +00:00
if ( pTargetBytes_ )
* pTargetBytes_ = 2 ;
break ;
2019-12-09 16:27:13 +00:00
case AM_IAX : // Indexed (Absolute) Indirect - ie. JMP (abs,x)
_ASSERT ( nOpcode = = OPCODE_JMP_IAX ) ;
2010-06-11 15:38:22 +00:00
nTarget16 + = regs . x ;
* pTargetPartial_ = nTarget16 ;
2019-12-09 16:27:13 +00:00
* pTargetPartial2_ = nTarget16 + 1 ;
if ( bIncludeNextOpcodeAddress )
* pTargetPointer_ = * ( LPWORD ) ( mem + nTarget16 ) ;
2010-06-11 15:38:22 +00:00
if ( pTargetBytes_ )
* pTargetBytes_ = 2 ;
break ;
case AM_AX : // Absolute, X
nTarget16 + = regs . x ;
* pTargetPointer_ = nTarget16 ;
if ( pTargetBytes_ )
* pTargetBytes_ = 2 ;
break ;
case AM_AY : // Absolute, Y
nTarget16 + = regs . y ;
* pTargetPointer_ = nTarget16 ;
if ( pTargetBytes_ )
* pTargetBytes_ = 2 ;
break ;
2019-12-09 16:27:13 +00:00
case AM_NA : // Indirect (Absolute) - ie. JMP (abs)
_ASSERT ( nOpcode = = OPCODE_JMP_NA ) ;
2010-06-11 15:38:22 +00:00
* pTargetPartial_ = nTarget16 ;
2019-12-09 16:27:13 +00:00
* pTargetPartial2_ = nTarget16 + 1 ;
if ( bIncludeNextOpcodeAddress )
2021-02-07 16:58:11 +00:00
* pTargetPointer_ = mem [ nTarget16 ] | ( mem [ ( nTarget16 + 1 ) & 0xFFFF ] < < 8 ) ;
2010-06-11 15:38:22 +00:00
if ( pTargetBytes_ )
* pTargetBytes_ = 2 ;
break ;
case AM_IZX : // Indexed (Zeropage Indirect, X)
2021-02-07 16:58:11 +00:00
nTarget8 = ( nTarget8 + regs . x ) & 0xFF ;
2010-06-11 15:38:22 +00:00
* pTargetPartial_ = nTarget8 ;
* pTargetPointer_ = * ( LPWORD ) ( mem + nTarget8 ) ;
if ( pTargetBytes_ )
* pTargetBytes_ = 2 ;
break ;
case AM_NZY : // Indirect (Zeropage) Indexed, Y
* pTargetPartial_ = nTarget8 ;
* pTargetPointer_ = ( ( * ( LPWORD ) ( mem + nTarget8 ) ) + regs . y ) & _6502_MEM_END ; // Bugfix:
if ( pTargetBytes_ )
* pTargetBytes_ = 1 ;
break ;
case AM_NZ : // Indirect (Zeropage)
* pTargetPartial_ = nTarget8 ;
* pTargetPointer_ = * ( LPWORD ) ( mem + nTarget8 ) ;
if ( pTargetBytes_ )
* pTargetBytes_ = 2 ;
break ;
case AM_R :
2019-12-09 16:27:13 +00:00
if ( ! bIgnoreBranch )
2010-06-11 15:38:22 +00:00
{
* pTargetPartial_ = nTarget8 ;
* pTargetPointer_ = nAddress + 2 ;
if ( nTarget8 < = _6502_BRANCH_POS )
* pTargetPointer_ + = nTarget8 ; // +
else
* pTargetPointer_ - = nTarget8 ; // -
* pTargetPointer_ & = _6502_MEM_END ;
if ( pTargetBytes_ )
* pTargetBytes_ = 1 ;
}
break ;
case AM_Z : // Zeropage
* pTargetPointer_ = nTarget8 ;
if ( pTargetBytes_ )
* pTargetBytes_ = 1 ;
break ;
case AM_ZX : // Zeropage, X
* pTargetPointer_ = ( nTarget8 + regs . x ) & 0xFF ; // .21 Bugfix: shouldn't this wrap around? Yes.
if ( pTargetBytes_ )
* pTargetBytes_ = 1 ;
break ;
case AM_ZY : // Zeropage, Y
* pTargetPointer_ = ( nTarget8 + regs . y ) & 0xFF ; // .21 Bugfix: shouldn't this wrap around? Yes.
if ( pTargetBytes_ )
* pTargetBytes_ = 1 ;
break ;
default :
if ( pTargetBytes_ )
* pTargetBytes_ = 0 ;
break ;
}
2019-12-09 20:42:16 +00:00
return true ;
2010-06-11 15:38:22 +00:00
}
//===========================================================================
bool _6502_GetTargetAddress ( const WORD & nAddress , WORD & nTarget_ )
{
int iOpcode ;
int iOpmode ;
int nOpbytes ;
iOpcode = _6502_GetOpmodeOpbyte ( nAddress , iOpmode , nOpbytes ) ;
// Composite string that has the target nAddress
if ( ( iOpmode ! = AM_IMPLIED ) & &
( iOpmode ! = AM_1 ) & &
( iOpmode ! = AM_2 ) & &
( iOpmode ! = AM_3 ) )
{
int nTargetPartial ;
2020-10-01 18:55:29 +00:00
int nTargetPartial2 ;
2010-06-11 15:38:22 +00:00
int nTargetPointer ;
int nTargetBytes ;
2020-10-01 18:55:29 +00:00
_6502_GetTargets ( nAddress , & nTargetPartial , & nTargetPartial2 , & nTargetPointer , & nTargetBytes , false ) ;
2010-06-11 15:38:22 +00:00
// if (nTargetPointer == NO_6502_TARGET)
// {
// if (_6502_IsOpcodeBranch( nOpcode )
// {
// return true;
// }
// }
if ( nTargetPointer ! = NO_6502_TARGET )
// else
{
nTarget_ = nTargetPointer & _6502_MEM_END ;
return true ;
}
}
return false ;
}
//===========================================================================
bool _6502_IsOpcodeBranch ( int iOpcode )
{
// 76543210 Bit
// xxx10000 Branch
if ( iOpcode = = OPCODE_BRA )
return true ;
if ( ( iOpcode & 0x1F ) ! = 0x10 ) // low nibble not zero?
return false ;
if ( ( iOpcode > > 4 ) & 1 )
return true ;
// (nOpcode == 0x10) || // BPL
// (nOpcode == 0x30) || // BMI
// (nOpcode == 0x50) || // BVC
// (nOpcode == 0x70) || // BVS
// (nOpcode == 0x90) || // BCC
// (nOpcode == 0xB0) || // BCS
// (nOpcode == 0xD0) || // BNE
// (nOpcode == 0xF0) || // BEQ
return false ;
}
//===========================================================================
bool _6502_IsOpcodeValid ( int iOpcode )
{
if ( ( iOpcode & 0x3 ) = = 0x3 )
return false ;
if ( islower ( g_aOpcodes6502 [ iOpcode ] . sMnemonic [ 0 ] ) )
return false ;
return true ;
}
// Assembler ________________________________________________________________
//===========================================================================
2020-10-11 16:14:03 +00:00
Hash_t AssemblerHashMnemonic ( const TCHAR * pMnemonic )
2010-06-11 15:38:22 +00:00
{
const TCHAR * pText = pMnemonic ;
2020-10-11 16:14:03 +00:00
Hash_t nMnemonicHash = 0 ;
2010-06-11 15:38:22 +00:00
int iHighBits ;
const int NUM_LOW_BITS = 19 ; // 24 -> 19 prime
const int NUM_MSK_BITS = 5 ; // 4 -> 5 prime
const Hash_t BIT_MSK_HIGH = ( ( 1 < < NUM_MSK_BITS ) - 1 ) < < NUM_LOW_BITS ;
2010-12-15 16:03:22 +00:00
# if DEBUG_ASSEMBLER
2020-10-01 18:55:29 +00:00
int nLen = strlen ( pMnemonic ) ;
2010-12-15 16:03:22 +00:00
static int nMaxLen = 0 ;
if ( nMaxLen < nLen ) {
nMaxLen = nLen ;
2016-09-10 12:46:09 +00:00
char sText [ CONSOLE_WIDTH * 3 ] ;
ConsolePrintFormat ( sText , " New Max Len: %d %s " , nMaxLen , pMnemonic ) ;
2010-12-15 16:03:22 +00:00
}
# endif
while ( * pText )
// for( int iChar = 0; iChar < 4; iChar++ )
2010-06-11 15:38:22 +00:00
{
2010-12-15 16:03:22 +00:00
char c = tolower ( * pText ) ; // TODO: based on ALLOW_INPUT_LOWERCASE ??
nMnemonicHash = ( nMnemonicHash < < NUM_MSK_BITS ) + c ;
2010-06-11 15:38:22 +00:00
iHighBits = ( nMnemonicHash & BIT_MSK_HIGH ) ;
if ( iHighBits )
{
nMnemonicHash = ( nMnemonicHash ^ ( iHighBits > > NUM_LOW_BITS ) ) & ~ BIT_MSK_HIGH ;
}
pText + + ;
}
return nMnemonicHash ;
}
//===========================================================================
void AssemblerHashOpcodes ( )
{
Hash_t nMnemonicHash ;
int iOpcode ;
for ( iOpcode = 0 ; iOpcode < NUM_OPCODES ; iOpcode + + )
{
const TCHAR * pMnemonic = g_aOpcodes65C02 [ iOpcode ] . sMnemonic ;
nMnemonicHash = AssemblerHashMnemonic ( pMnemonic ) ;
g_aOpcodesHash [ iOpcode ] = nMnemonicHash ;
2010-12-15 16:03:22 +00:00
# if DEBUG_ASSEMBLER
2016-09-10 12:46:09 +00:00
//OutputDebugString( "" );
char sText [ 128 ] ;
ConsolePrintFormat ( sText , " %s : %08X " , pMnemonic , nMnemonicHash ) ;
// CLC: 002B864
2010-12-15 16:03:22 +00:00
# endif
2010-06-11 15:38:22 +00:00
}
2010-12-15 16:03:22 +00:00
ConsoleUpdate ( ) ;
2010-06-11 15:38:22 +00:00
}
//===========================================================================
2010-12-16 06:43:05 +00:00
void AssemblerHashDirectives ( )
2010-06-11 15:38:22 +00:00
{
Hash_t nMnemonicHash ;
int iOpcode ;
for ( iOpcode = 0 ; iOpcode < NUM_ASM_M_DIRECTIVES ; iOpcode + + )
{
int iNopcode = FIRST_M_DIRECTIVE + iOpcode ;
//. const TCHAR *pMnemonic = g_aAssemblerDirectivesMerlin[ iOpcode ].m_pMnemonic;
const TCHAR * pMnemonic = g_aAssemblerDirectives [ iNopcode ] . m_pMnemonic ;
nMnemonicHash = AssemblerHashMnemonic ( pMnemonic ) ;
g_aAssemblerDirectives [ iNopcode ] . m_nHash = nMnemonicHash ;
}
}
//===========================================================================
void AssemblerStartup ( )
{
AssemblerHashOpcodes ( ) ;
2010-12-16 06:43:05 +00:00
AssemblerHashDirectives ( ) ;
2010-06-11 15:38:22 +00:00
}
//===========================================================================
void _CmdAssembleHashDump ( )
{
// #if DEBUG_ASM_HASH
2014-08-14 19:29:01 +00:00
std : : vector < HashOpcode_t > vHashes ;
2010-06-11 15:38:22 +00:00
HashOpcode_t tHash ;
TCHAR sText [ CONSOLE_WIDTH ] ;
int iOpcode ;
for ( iOpcode = 0 ; iOpcode < NUM_OPCODES ; iOpcode + + )
{
tHash . m_iOpcode = iOpcode ;
tHash . m_nValue = g_aOpcodesHash [ iOpcode ] ;
vHashes . push_back ( tHash ) ;
}
2014-08-14 19:29:01 +00:00
std : : sort ( vHashes . begin ( ) , vHashes . end ( ) , HashOpcode_t ( ) ) ;
2010-06-11 15:38:22 +00:00
2020-10-01 18:55:29 +00:00
// Hash_t nPrevHash = vHashes.at( 0 ).m_nValue;
2010-06-11 15:38:22 +00:00
Hash_t nThisHash = 0 ;
for ( iOpcode = 0 ; iOpcode < NUM_OPCODES ; iOpcode + + )
{
tHash = vHashes . at ( iOpcode ) ;
Hash_t iThisHash = tHash . m_nValue ;
int nOpcode = tHash . m_iOpcode ;
int nOpmode = g_aOpcodes [ nOpcode ] . nAddressMode ;
2016-09-10 12:46:09 +00:00
ConsoleBufferPushFormat ( sText , " %08X %02X %s %s "
2010-06-11 15:38:22 +00:00
, iThisHash
, nOpcode
, g_aOpcodes65C02 [ nOpcode ] . sMnemonic
, g_aOpmodes [ nOpmode ] . m_sName
) ;
nThisHash + + ;
// if (nPrevHash != iThisHash)
// {
2016-09-10 12:46:09 +00:00
// ConsoleBufferPushFormat( sText, "Total: %d", nThisHash );
2010-06-11 15:38:22 +00:00
// nThisHash = 0;
// }
}
ConsoleUpdate ( ) ;
//#endif
}
//===========================================================================
int AssemblerPokeAddress ( const int Opcode , const int nOpmode , const WORD nBaseAddress , const WORD nTargetOffset )
{
// int nOpmode = g_aOpcodes[ nOpcode ].nAddressMode;
int nOpbytes = g_aOpmodes [ nOpmode ] . m_nBytes ;
// if (nOpbytes != nBytes)
// ConsoleDisplayError( TEXT(" ERROR: Input Opcode bytes differs from actual!" ) );
* ( memdirty + ( nBaseAddress > > 8 ) ) | = 1 ;
// *(mem + nBaseAddress) = (BYTE) nOpcode;
if ( nOpbytes > 1 )
* ( mem + nBaseAddress + 1 ) = ( BYTE ) ( nTargetOffset > > 0 ) ;
if ( nOpbytes > 2 )
* ( mem + nBaseAddress + 2 ) = ( BYTE ) ( nTargetOffset > > 8 ) ;
return nOpbytes ;
}
//===========================================================================
bool AssemblerPokeOpcodeAddress ( const WORD nBaseAddress )
{
int iAddressMode = m_iAsmAddressMode ; // opmode detected from input
int nTargetValue = m_nAsmTargetValue ;
int iOpcode ;
int nOpcodes = m_vAsmOpcodes . size ( ) ;
for ( iOpcode = 0 ; iOpcode < nOpcodes ; iOpcode + + )
{
int nOpcode = m_vAsmOpcodes . at ( iOpcode ) ; // m_iOpcode;
int nOpmode = g_aOpcodes [ nOpcode ] . nAddressMode ;
if ( nOpmode = = iAddressMode )
{
* ( mem + nBaseAddress ) = ( BYTE ) nOpcode ;
int nOpbytes = AssemblerPokeAddress ( nOpcode , nOpmode , nBaseAddress , nTargetValue ) ;
if ( m_bDelayedTargetsDirty )
{
int nDelayedTargets = m_vDelayedTargets . size ( ) ;
DelayedTarget_t * pTarget = & m_vDelayedTargets . at ( nDelayedTargets - 1 ) ;
pTarget - > m_nOpcode = nOpcode ;
pTarget - > m_iOpmode = nOpmode ;
}
g_nAssemblerAddress + = nOpbytes ;
return true ;
}
}
return false ;
}
//===========================================================================
bool TestFlag ( AssemblerFlags_e eFlag )
{
if ( m_bAsmFlags & eFlag )
return true ;
return false ;
}
//===========================================================================
void SetFlag ( AssemblerFlags_e eFlag , bool bValue = true )
{
if ( bValue )
m_bAsmFlags | = eFlag ;
else
m_bAsmFlags & = ~ eFlag ;
}
/*
Output
AM_IMPLIED
AM_M
AM_A
AM_Z
AM_I // indexed or indirect
*/
//===========================================================================
bool AssemblerGetArgs ( int iArg , int nArgs , WORD nBaseAddress )
{
m_iAsmAddressMode = AM_IMPLIED ;
AssemblerState_e eNextState = AS_GET_MNEMONIC ;
m_bAsmFlags = 0 ;
m_nAsmTargetAddress = 0 ;
int nBase = 10 ;
// Sync up to Raw Args for matching mnemonic
// Process them instead of the cooked args, since we need the orginal tokens
Arg_t * pArg = & g_aArgRaw [ iArg ] ;
while ( iArg < g_nArgRaw )
{
int iToken = pArg - > eToken ;
2020-10-01 18:55:29 +00:00
// int iType = pArg->bType;
2010-06-11 15:38:22 +00:00
if ( iToken = = TOKEN_HASH )
{
if ( eNextState ! = AS_GET_MNEMONIC_PARM )
{
ConsoleBufferPush ( TEXT ( " Syntax Error: '#' " ) ) ;
return false ;
}
if ( TestFlag ( AF_HaveHash ) )
{
ConsoleBufferPush ( TEXT ( " Syntax Error: Extra '#' " ) ) ; // No thanks, we already have one
return false ;
}
SetFlag ( AF_HaveHash ) ;
m_iAsmAddressMode = AM_M ; // Immediate
eNextState = AS_GET_TARGET ;
m_nAsmBytes = 1 ;
}
else
if ( iToken = = TOKEN_DOLLAR )
{
if ( TestFlag ( AF_HaveDollar ) )
{
ConsoleBufferPush ( TEXT ( " Syntax Error: Extra '$' " ) ) ; // No thanks, we already have one
return false ;
}
nBase = 16 ; // switch to hex
if ( ! TestFlag ( AF_HaveHash ) )
{
SetFlag ( AF_HaveDollar ) ;
m_iAsmAddressMode = AM_A ; // Absolute
}
eNextState = AS_GET_TARGET ;
m_nAsmBytes = 2 ;
}
else
if ( iToken = = TOKEN_PAREN_L )
{
if ( TestFlag ( AF_HaveLeftParen ) )
{
ConsoleBufferPush ( TEXT ( " Syntax Error: Extra '(' " ) ) ; // No thanks, we already have one
return false ;
}
SetFlag ( AF_HaveLeftParen ) ;
// Indexed or Indirect
m_iAsmAddressMode = AM_I ;
}
else
if ( iToken = = TOKEN_PAREN_R )
{
if ( TestFlag ( AF_HaveRightParen ) )
{
ConsoleBufferPush ( TEXT ( " Syntax Error: Extra ')' " ) ) ; // No thanks, we already have one
return false ;
}
SetFlag ( AF_HaveRightParen ) ;
// Indexed or Indirect
m_iAsmAddressMode = AM_I ;
}
else
if ( iToken = = TOKEN_COMMA )
{
if ( TestFlag ( AF_HaveComma ) )
{
ConsoleBufferPush ( TEXT ( " Syntax Error: Extra ',' " ) ) ; // No thanks, we already have one
return false ;
}
SetFlag ( AF_HaveComma ) ;
eNextState = AS_GET_INDEX ;
// We should have address by now
}
else
if ( iToken = = TOKEN_LESS_THAN )
{
}
else
if ( iToken = = TOKEN_GREATER_THAN )
{
}
else
if ( iToken = = TOKEN_SEMI ) // comment
{
break ;
}
else
if ( iToken = = TOKEN_ALPHANUMERIC )
{
if ( eNextState = = AS_GET_MNEMONIC )
{
eNextState = AS_GET_MNEMONIC_PARM ;
}
else
if ( eNextState = = AS_GET_MNEMONIC_PARM )
{
eNextState = AS_GET_TARGET ;
}
if ( eNextState = = AS_GET_TARGET )
{
SetFlag ( AF_HaveTarget ) ;
ArgsGetValue ( pArg , & m_nAsmTargetAddress , nBase ) ;
// Do Symbol Lookup
WORD nSymbolAddress ;
bool bExists = FindAddressFromSymbol ( pArg - > sArg , & nSymbolAddress ) ;
if ( bExists )
{
m_nAsmTargetAddress = nSymbolAddress ;
if ( m_iAsmAddressMode = = AM_IMPLIED )
m_iAsmAddressMode = AM_A ;
}
else
{
// if valid hex address, don't have delayed target
TCHAR sAddress [ 32 ] ;
wsprintf ( sAddress , " %X " , m_nAsmTargetAddress ) ;
if ( _tcscmp ( sAddress , pArg - > sArg ) )
{
DelayedTarget_t tDelayedTarget ;
tDelayedTarget . m_nBaseAddress = nBaseAddress ;
strncpy ( tDelayedTarget . m_sAddress , pArg - > sArg , MAX_SYMBOLS_LEN ) ;
tDelayedTarget . m_sAddress [ MAX_SYMBOLS_LEN ] = 0 ;
// Flag this target that we need to update it when we have the relevent info
m_bDelayedTargetsDirty = true ;
tDelayedTarget . m_nOpcode = 0 ;
tDelayedTarget . m_iOpmode = m_iAsmAddressMode ;
m_vDelayedTargets . push_back ( tDelayedTarget ) ;
m_nAsmTargetAddress = 0 ;
}
}
if ( ( m_iAsmAddressMode ! = AM_M ) & &
( m_iAsmAddressMode ! = AM_IMPLIED ) & &
( ! m_bDelayedTargetsDirty ) )
{
if ( m_nAsmTargetAddress < = _6502_ZEROPAGE_END )
{
m_iAsmAddressMode = AM_Z ;
m_nAsmBytes = 1 ;
}
}
}
if ( eNextState = = AS_GET_INDEX )
{
if ( pArg - > nArgLen = = 1 )
{
if ( pArg - > sArg [ 0 ] = = ' X ' )
{
if ( ! TestFlag ( AF_HaveComma ) )
{
ConsoleBufferPush ( TEXT ( " Syntax Error: Missing ',' " ) ) ;
return false ;
}
SetFlag ( AF_HaveRegisterX ) ;
}
if ( pArg - > sArg [ 0 ] = = ' Y ' )
{
if ( ! ( TestFlag ( AF_HaveComma ) ) )
{
ConsoleBufferPush ( TEXT ( " Syntax Error: Missing ',' " ) ) ;
return false ;
}
SetFlag ( AF_HaveRegisterY ) ;
}
}
}
}
iArg + + ;
pArg + + ;
}
return true ;
}
//===========================================================================
bool AssemblerUpdateAddressingMode ( )
{
SetFlag ( AF_HaveEitherParen , TestFlag ( AF_HaveLeftParen ) | | TestFlag ( AF_HaveRightParen ) ) ;
SetFlag ( AF_HaveBothParen , TestFlag ( AF_HaveLeftParen ) & & TestFlag ( AF_HaveRightParen ) ) ;
if ( ( TestFlag ( AF_HaveLeftParen ) ) & & ( ! TestFlag ( AF_HaveRightParen ) ) )
{
ConsoleBufferPush ( TEXT ( " Syntax Error: Missing ')' " ) ) ;
return false ;
}
if ( ( ! TestFlag ( AF_HaveLeftParen ) ) & & ( TestFlag ( AF_HaveRightParen ) ) )
{
ConsoleBufferPush ( TEXT ( " Syntax Error: Missing '(' " ) ) ;
return false ;
}
if ( TestFlag ( AF_HaveComma ) )
{
if ( ( ! TestFlag ( AF_HaveRegisterX ) ) & & ( ! TestFlag ( AF_HaveRegisterY ) ) )
{
ConsoleBufferPush ( TEXT ( " Syntax Error: Index 'X' or 'Y' " ) ) ;
return false ;
}
}
if ( TestFlag ( AF_HaveBothParen ) )
{
if ( TestFlag ( AF_HaveComma ) )
{
if ( TestFlag ( AF_HaveRegisterX ) )
{
m_iAsmAddressMode = AM_AX ;
m_nAsmBytes = 2 ;
if ( m_nAsmTargetAddress < = _6502_ZEROPAGE_END )
{
m_iAsmAddressMode = AM_ZX ;
m_nAsmBytes = 1 ;
}
}
if ( TestFlag ( AF_HaveRegisterY ) )
{
m_iAsmAddressMode = AM_AY ;
m_nAsmBytes = 2 ;
if ( m_nAsmTargetAddress < = _6502_ZEROPAGE_END )
{
m_iAsmAddressMode = AM_ZY ;
m_nAsmBytes = 1 ;
}
}
}
}
if ( ( m_iAsmAddressMode = = AM_A ) | | ( m_iAsmAddressMode = = AM_Z ) )
{
if ( ! TestFlag ( AF_HaveEitherParen ) ) // if no paren
{
if ( TestFlag ( AF_HaveComma ) & & TestFlag ( AF_HaveRegisterX ) )
{
if ( m_iAsmAddressMode = = AM_Z )
m_iAsmAddressMode = AM_ZX ;
else
m_iAsmAddressMode = AM_AX ;
}
if ( TestFlag ( AF_HaveComma ) & & TestFlag ( AF_HaveRegisterY ) )
{
if ( m_iAsmAddressMode = = AM_Z )
m_iAsmAddressMode = AM_ZY ;
else
m_iAsmAddressMode = AM_AY ;
}
}
}
if ( m_iAsmAddressMode = = AM_I )
{
if ( ! TestFlag ( AF_HaveEitherParen ) ) // if no paren
{
// Indirect Zero Page
// Indirect Absolute
}
}
m_nAsmTargetValue = m_nAsmTargetAddress ;
int nOpcode = m_vAsmOpcodes . at ( 0 ) ; // branch opcodes don't vary (only 1 Addressing Mode)
if ( _6502_CalcRelativeOffset ( nOpcode , m_nAsmBaseAddress , m_nAsmTargetAddress , & m_nAsmTargetValue ) )
{
if ( m_iAsmAddressMode = = NUM_OPMODES )
return false ;
m_iAsmAddressMode = AM_R ;
}
return true ;
}
//===========================================================================
int AssemblerDelayedTargetsSize ( )
{
int nSize = m_vDelayedTargets . size ( ) ;
return nSize ;
}
// The Assembler was terminated, with Symbol(s) declared, but not (yet) defined.
// i.e.
// A 300
// BNE $DONE
// <enter>
//===========================================================================
void AssemblerProcessDelayedSymols ( )
{
m_bDelayedTargetsDirty = false ; // assembler set signal if new symbol was added
bool bModified = false ;
while ( ! bModified )
{
bModified = false ;
2014-08-14 19:29:01 +00:00
std : : vector < DelayedTarget_t > : : iterator iSymbol ;
2010-06-11 15:38:22 +00:00
for ( iSymbol = m_vDelayedTargets . begin ( ) ; iSymbol ! = m_vDelayedTargets . end ( ) ; + + iSymbol )
{
DelayedTarget_t * pTarget = & ( * iSymbol ) ; // m_vDelayedTargets.at( iSymbol );
WORD nTargetAddress ;
bool bExists = FindAddressFromSymbol ( pTarget - > m_sAddress , & nTargetAddress ) ;
if ( bExists )
{
// TODO: need to handle #<symbol, #>symbol, symbol+n, symbol-n
bModified = true ;
int nOpcode = pTarget - > m_nOpcode ;
int nOpmode = g_aOpcodes [ nOpcode ] . nAddressMode ;
// int nOpbytes = g_aOpmodes[ nOpmode ].m_nBytes;
// 300: D0 7E BNE $380
// ^ ^ ^
// | | TargetAddress
// | TargetValue
// BaseAddress
WORD nTargetValue = nTargetAddress ;
if ( _6502_CalcRelativeOffset ( nOpcode , pTarget - > m_nBaseAddress , nTargetAddress , & nTargetValue ) )
{
if ( m_iAsmAddressMode = = NUM_OPMODES )
{
nTargetValue = 0 ;
bModified = false ;
}
}
if ( bModified )
{
AssemblerPokeAddress ( nOpcode , nOpmode , pTarget - > m_nBaseAddress , nTargetValue ) ;
* ( memdirty + ( pTarget - > m_nBaseAddress > > 8 ) ) | = 1 ;
m_vDelayedTargets . erase ( iSymbol ) ;
// iterators are invalid after the point of deletion
// need to restart enumeration
break ;
}
}
}
if ( ! bModified )
break ;
}
}
bool Assemble ( int iArg , int nArgs , WORD nAddress )
{
bool bGotArgs ;
bool bGotMode ;
bool bGotByte ;
// Since, making 2-passes is not an option,
// we need to buffer the target address fix-ups.
AssemblerProcessDelayedSymols ( ) ;
m_nAsmBaseAddress = nAddress ;
TCHAR * pMnemonic = g_aArgs [ iArg ] . sArg ;
2020-10-11 16:14:03 +00:00
Hash_t nMnemonicHash = AssemblerHashMnemonic ( pMnemonic ) ;
2010-06-11 15:38:22 +00:00
2010-12-15 16:03:22 +00:00
# if DEBUG_ASSEMBLER
2016-09-10 12:46:09 +00:00
char sText [ CONSOLE_WIDTH * 2 ] ;
ConsolePrintFormat ( sText , " %s%04X%s: %s%s%s -> %s%08X " ,
2010-12-15 16:03:22 +00:00
CHC_ADDRESS , nAddress ,
CHC_DEFAULT ,
CHC_STRING , pMnemonic ,
CHC_DEFAULT ,
2016-09-10 12:46:09 +00:00
CHC_NUM_HEX , nMnemonicHash ) ;
2010-12-15 16:03:22 +00:00
# endif
2010-06-11 15:38:22 +00:00
m_vAsmOpcodes . clear ( ) ; // Candiate opcodes
int iOpcode ;
// Ugh! Linear search.
for ( iOpcode = 0 ; iOpcode < NUM_OPCODES ; iOpcode + + )
{
if ( nMnemonicHash = = g_aOpcodesHash [ iOpcode ] )
{
m_vAsmOpcodes . push_back ( iOpcode ) ;
}
}
int nOpcodes = m_vAsmOpcodes . size ( ) ;
if ( ! nOpcodes )
{
// Check for assembler directive
ConsoleBufferPush ( TEXT ( " Syntax Error: Invalid mnemonic " ) ) ;
return false ;
}
else
{
bGotArgs = AssemblerGetArgs ( iArg , nArgs , nAddress ) ;
if ( bGotArgs )
{
bGotMode = AssemblerUpdateAddressingMode ( ) ;
if ( bGotMode )
{
bGotByte = AssemblerPokeOpcodeAddress ( nAddress ) ;
}
}
}
return true ;
}
//===========================================================================
void AssemblerOn ( )
{
g_bAssemblerInput = true ;
g_sConsolePrompt [ 0 ] = g_aConsolePrompt [ PROMPT_ASSEMBLER ] ;
}
//===========================================================================
void AssemblerOff ( )
{
g_bAssemblerInput = false ;
g_sConsolePrompt [ 0 ] = g_aConsolePrompt [ PROMPT_COMMAND ] ;
}