mirror of
https://github.com/ksherlock/x65.git
synced 2024-09-29 13:54:54 +00:00
65C02 CPU added
- Added SAV as a Merlin directive - cpu command line option to switch CPU target
This commit is contained in:
parent
fbade4eb06
commit
cc99faed16
29
README.md
29
README.md
@ -48,6 +48,7 @@ x65 [-DLabel] [-iIncDir] (source.s) (dest.prg) [-lst[=file.lst]] [-opcodes[=file
|
|||||||
x65 filename.s code.prg [options]
|
x65 filename.s code.prg [options]
|
||||||
* -i(path): Add include path
|
* -i(path): Add include path
|
||||||
* -D(label)[=(value)]: Define a label with an optional value (otherwise defined as 1)
|
* -D(label)[=(value)]: Define a label with an optional value (otherwise defined as 1)
|
||||||
|
* -cpu=6502/65c02: assemble with opcodes for a different cpu
|
||||||
* -obj (file.x65): generate object file for later linking
|
* -obj (file.x65): generate object file for later linking
|
||||||
* -bin: Raw binary
|
* -bin: Raw binary
|
||||||
* -c64: Include load address (default)
|
* -c64: Include load address (default)
|
||||||
@ -516,6 +517,10 @@ A variation of **INCLUDE** that applies an oddball set of filename rules. These
|
|||||||
|
|
||||||
In Merlin USR calls a function at a fixed address in memory, x65 safely avoids this. If there is a requirement for a user defined macro you've got the source code to do it in.
|
In Merlin USR calls a function at a fixed address in memory, x65 safely avoids this. If there is a requirement for a user defined macro you've got the source code to do it in.
|
||||||
|
|
||||||
|
**SAV**
|
||||||
|
|
||||||
|
SAV causes Merlin to save the result it has generated so far, which is somewhat similar to the [EXPORT](#export) directive. If the SAV name is different than the source name the section will have a different EXPORT name appended and exported to a separate binary file.
|
||||||
|
|
||||||
## <a name="expressions">Expression syntax
|
## <a name="expressions">Expression syntax
|
||||||
|
|
||||||
Expressions contain values, such as labels or raw numbers and operators including +, -, \*, /, & (and), | (or), ^ (eor), << (shift left), >> (shift right) similar to how expressions work in C. Parenthesis are supported for managing order of operations where C style precedence needs to be overrided. In addition there are some special characters supported:
|
Expressions contain values, such as labels or raw numbers and operators including +, -, \*, /, & (and), | (or), ^ (eor), << (shift left), >> (shift right) similar to how expressions work in C. Parenthesis are supported for managing order of operations where C style precedence needs to be overrided. In addition there are some special characters supported:
|
||||||
@ -636,7 +641,7 @@ FindFirstSpace
|
|||||||
Currently the assembler is in an early revision and while features are tested individually it is fairly certain that untested combinations of features will indicate flaws and certain features are not in a complete state.
|
Currently the assembler is in an early revision and while features are tested individually it is fairly certain that untested combinations of features will indicate flaws and certain features are not in a complete state.
|
||||||
|
|
||||||
**TODO**
|
**TODO**
|
||||||
* 65c02
|
* 65C02 enabled through directives (PROCESSOR/CPU/XC)
|
||||||
* 65816
|
* 65816
|
||||||
* Macro parameters should replace only whole words instead of any substring
|
* Macro parameters should replace only whole words instead of any substring
|
||||||
* Add 'import' directive as a catch-all include/incbin/etc. alternative
|
* Add 'import' directive as a catch-all include/incbin/etc. alternative
|
||||||
@ -644,6 +649,7 @@ Currently the assembler is in an early revision and while features are tested in
|
|||||||
* boolean operators (==, <, >, etc.) for better conditional expressions
|
* boolean operators (==, <, >, etc.) for better conditional expressions
|
||||||
|
|
||||||
**FIXED**
|
**FIXED**
|
||||||
|
* 65c02 (currently only through command line, not as a directive)
|
||||||
* Now accepts negative numbers, Merlin LUP and MAC keyword support
|
* Now accepts negative numbers, Merlin LUP and MAC keyword support
|
||||||
* Merlin syntax fixes (no '!' in labels, don't skip ':' if first character of label), symbol file fix for included object files with resolved labels for relative sections. List output won't disassemble lines that wasn't built from source code.
|
* Merlin syntax fixes (no '!' in labels, don't skip ':' if first character of label), symbol file fix for included object files with resolved labels for relative sections. List output won't disassemble lines that wasn't built from source code.
|
||||||
* Export full memory of fixed sections instead of a single section
|
* Export full memory of fixed sections instead of a single section
|
||||||
@ -668,18 +674,9 @@ Currently the assembler is in an early revision and while features are tested in
|
|||||||
* TEXT directive converts ascii to petscii (respect uppercase or lowercase petscii) (simplistic)
|
* TEXT directive converts ascii to petscii (respect uppercase or lowercase petscii) (simplistic)
|
||||||
|
|
||||||
Revisions:
|
Revisions:
|
||||||
* 2015-10-20 Fixed negative numbers, Merlin macros and 'endmacro' alternative, merlin LUP directive
|
* 6 - 65C02 support
|
||||||
* 2015-10-18 Fixed exporting binary files
|
* 5 - Merlin syntax
|
||||||
* 2015-10-18 Added list file output which is disassembly with inline source that generated the code.
|
* 4 - Object files, relative sections and linking
|
||||||
* 2015-10-16 XDEF and file protected symbols added for better recursive object file assembling
|
* 3 - 6502 full support
|
||||||
* 2015-10-15 Object file reading, additional bugs debugged.
|
* 2 - Moved file out of struse samples
|
||||||
* 2015-10-10 Relative Sections and Link support, adding -merlin command line to clean up code
|
* 1 - Built a sample of a simple assembler within struse
|
||||||
* 2015-10-06 Added ENUM and MERLIN / LISA assembler directives (EJECT, DUM, DEND, DS, DB, DFB, DDB, IF, ENDIF, etc.)
|
|
||||||
* 2015-10-05 Added INCDIR, some command line options (-D, -i, -vice)
|
|
||||||
* 2015-10-04 Added [REPT](#rept) directive
|
|
||||||
* 2015-10-04 Added [STRUCT](#struct) directive, sorted functions by grouping a bit more, bug fixes
|
|
||||||
* 2015-10-02 Cleanup hid an error (#else without #if), exit with nonzero if error was encountered
|
|
||||||
* 2015-10-02 General cleanup, wrapping [conditional assembly](#conditional) in functions
|
|
||||||
* 2015-10-01 Added [Label Pools](#pool) and conditional assembly
|
|
||||||
* 2015-09-29 Moved Asm6502 out of Struse Samples.
|
|
||||||
* 2015-09-28 First commit
|
|
||||||
|
354
x65.cpp
354
x65.cpp
@ -225,6 +225,7 @@ enum AssemblerDirective {
|
|||||||
AD_DUMMY_END, // DEND: End a dummy section
|
AD_DUMMY_END, // DEND: End a dummy section
|
||||||
AD_DS, // DS: Define section, zero out # bytes or rewind the address if negative
|
AD_DS, // DS: Define section, zero out # bytes or rewind the address if negative
|
||||||
AD_USR, // USR: MERLIN user defined pseudo op, runs some code at a hard coded address on apple II, on PC does nothing.
|
AD_USR, // USR: MERLIN user defined pseudo op, runs some code at a hard coded address on apple II, on PC does nothing.
|
||||||
|
AD_SAV, // SAV: MERLIN version of export but contains full filename, not an appendable name
|
||||||
};
|
};
|
||||||
|
|
||||||
// Operators are either instructions or directives
|
// Operators are either instructions or directives
|
||||||
@ -264,7 +265,8 @@ typedef struct {
|
|||||||
} OP_ID;
|
} OP_ID;
|
||||||
|
|
||||||
enum AddrMode {
|
enum AddrMode {
|
||||||
AMB_ZP_REL_X, // 0 ($12,x) address mode bit index
|
// address mode bit index
|
||||||
|
AMB_ZP_REL_X, // 0 ($12,x)
|
||||||
AMB_ZP, // 1 $12
|
AMB_ZP, // 1 $12
|
||||||
AMB_IMM, // 2 #$12
|
AMB_IMM, // 2 #$12
|
||||||
AMB_ABS, // 3 $1234
|
AMB_ABS, // 3 $1234
|
||||||
@ -282,7 +284,7 @@ enum AddrMode {
|
|||||||
|
|
||||||
AMB_FLIPXY = AMB_COUNT, // e
|
AMB_FLIPXY = AMB_COUNT, // e
|
||||||
AMB_BRANCH, // f
|
AMB_BRANCH, // f
|
||||||
// address mode masks
|
// address mode masks
|
||||||
AMM_NON = 1<<AMB_NON,
|
AMM_NON = 1<<AMB_NON,
|
||||||
AMM_IMM = 1<<AMB_IMM,
|
AMM_IMM = 1<<AMB_IMM,
|
||||||
AMM_ABS = 1<<AMB_ABS,
|
AMM_ABS = 1<<AMB_ABS,
|
||||||
@ -294,22 +296,36 @@ enum AddrMode {
|
|||||||
AMM_ZP_X = 1<<AMB_ZP_X,
|
AMM_ZP_X = 1<<AMB_ZP_X,
|
||||||
AMM_ZP_REL_X = 1<<AMB_ZP_REL_X,
|
AMM_ZP_REL_X = 1<<AMB_ZP_REL_X,
|
||||||
AMM_ZP_Y_REL = 1<<AMB_ZP_Y_REL,
|
AMM_ZP_Y_REL = 1<<AMB_ZP_Y_REL,
|
||||||
|
AMM_ZP_REL = 1<<AMB_ZP_REL, // b ($12)
|
||||||
|
AMM_REL_X = 1<<AMB_REL_X, // c ($1234,x)
|
||||||
|
AMM_ZP_ABS = 1<<AMB_ZP_ABS, // d $12, *+$12
|
||||||
AMM_FLIPXY = 1<<AMB_FLIPXY,
|
AMM_FLIPXY = 1<<AMB_FLIPXY,
|
||||||
AMM_BRANCH = 1<<AMB_BRANCH,
|
AMM_BRANCH = 1<<AMB_BRANCH,
|
||||||
|
|
||||||
// instruction group specific masks
|
// instruction group specific masks
|
||||||
AMM_BRA = AMM_BRANCH | AMM_ABS,
|
AMM_BRA = AMM_BRANCH | AMM_ABS,
|
||||||
AMM_ORA = AMM_IMM | AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_Y | AMM_ABS_X | AMM_ZP_REL_X | AMM_ZP_Y_REL,
|
AMM_ORA = AMM_IMM | AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_Y | AMM_ABS_X | AMM_ZP_REL_X | AMM_ZP_Y_REL,
|
||||||
AMM_STA = AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_Y | AMM_ABS_X | AMM_ZP_REL_X | AMM_ZP_Y_REL,
|
AMM_STA = AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_Y | AMM_ABS_X | AMM_ZP_REL_X | AMM_ZP_Y_REL,
|
||||||
AMM_ASL = AMM_ACC | AMM_NON | AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_X,
|
AMM_ASL = AMM_ACC | AMM_NON | AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_X,
|
||||||
AMM_STX = AMM_FLIPXY | AMM_ZP | AMM_ZP_X | AMM_ABS, // note: for x ,x/,y flipped for this instr.
|
AMM_STX = AMM_FLIPXY | AMM_ZP | AMM_ZP_X | AMM_ABS, // note: for x ,x/,y flipped for this instr.
|
||||||
AMM_LDX = AMM_FLIPXY | AMM_IMM | AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_X, // note: for x ,x/,y flipped for this instr.
|
AMM_LDX = AMM_FLIPXY | AMM_IMM | AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_X, // note: for x ,x/,y flipped for this instr.
|
||||||
AMM_STY = AMM_ZP | AMM_ZP_X | AMM_ABS, // note: for x ,x/,y flipped for this instr.
|
AMM_STY = AMM_ZP | AMM_ZP_X | AMM_ABS,
|
||||||
AMM_LDY = AMM_IMM | AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_X, // note: for x ,x/,y flipped for this instr.
|
AMM_LDY = AMM_IMM | AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_X,
|
||||||
AMM_DEC = AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_X,
|
AMM_DEC = AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_X,
|
||||||
AMM_BIT = AMM_ZP | AMM_ABS,
|
AMM_BIT = AMM_ZP | AMM_ABS,
|
||||||
AMM_JMP = AMM_ABS | AMM_REL,
|
AMM_JMP = AMM_ABS | AMM_REL,
|
||||||
AMM_CPY = AMM_IMM | AMM_ZP | AMM_ABS,
|
AMM_CPY = AMM_IMM | AMM_ZP | AMM_ABS,
|
||||||
|
|
||||||
|
|
||||||
|
// 65C02 groups
|
||||||
|
AMC_ORA = AMM_ORA | AMM_ZP_REL,
|
||||||
|
AMC_STA = AMM_STA | AMM_ZP_REL,
|
||||||
|
AMC_BIT = AMM_BIT | AMM_IMM | AMM_ZP_X | AMM_ABS_X,
|
||||||
|
AMC_DEC = AMM_DEC | AMM_NON | AMM_ACC,
|
||||||
|
AMC_JMP = AMM_JMP | AMM_REL_X,
|
||||||
|
AMC_STZ = AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_X,
|
||||||
|
AMC_TRB = AMM_ZP | AMM_ABS,
|
||||||
|
AMC_BBR = AMM_ZP_ABS,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mnem {
|
struct mnem {
|
||||||
@ -381,6 +397,100 @@ struct mnem opcodes_6502[] = {
|
|||||||
|
|
||||||
static const int num_opcodes_6502 = sizeof(opcodes_6502) / sizeof(opcodes_6502[0]);
|
static const int num_opcodes_6502 = sizeof(opcodes_6502) / sizeof(opcodes_6502[0]);
|
||||||
|
|
||||||
|
struct mnem opcodes_65C02[] = {
|
||||||
|
// nam modes (zp,x) zp # $0000 (zp),y zp,x abs,y abs,x (xx) A empty (zp)(abs,x)zp,abs
|
||||||
|
{ "brk", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "jsr", AMM_ABS, { 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "rti", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "rts", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "ora", AMC_ORA, { 0x01, 0x05, 0x09, 0x0d, 0x11, 0x15, 0x19, 0x1d, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00 } },
|
||||||
|
{ "and", AMC_ORA, { 0x21, 0x25, 0x29, 0x2d, 0x31, 0x35, 0x39, 0x3d, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00 } },
|
||||||
|
{ "eor", AMC_ORA, { 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00 } },
|
||||||
|
{ "adc", AMC_ORA, { 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00 } },
|
||||||
|
{ "sta", AMC_STA, { 0x81, 0x85, 0x00, 0x8d, 0x91, 0x95, 0x99, 0x9d, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00 } },
|
||||||
|
{ "lda", AMC_ORA, { 0xa1, 0xa5, 0xa9, 0xad, 0xb1, 0xb5, 0xb9, 0xbd, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00 } },
|
||||||
|
{ "cmp", AMC_ORA, { 0xc1, 0xc5, 0xc9, 0xcd, 0xd1, 0xd5, 0xd9, 0xdd, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00 } },
|
||||||
|
{ "sbc", AMC_ORA, { 0xe1, 0xe5, 0xe9, 0xed, 0xf1, 0xf5, 0xf9, 0xfd, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x00 } },
|
||||||
|
{ "asl", AMM_ASL, { 0x00, 0x06, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x1e, 0x00, 0x0a, 0x0a, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "rol", AMM_ASL, { 0x00, 0x26, 0x00, 0x2e, 0x00, 0x36, 0x00, 0x3e, 0x00, 0x2a, 0x2a, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "lsr", AMM_ASL, { 0x00, 0x46, 0x00, 0x4e, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x4a, 0x4a, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "ror", AMM_ASL, { 0x00, 0x66, 0x00, 0x6e, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x6a, 0x6a, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "stx", AMM_STX, { 0x00, 0x86, 0x00, 0x8e, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "ldx", AMM_LDX, { 0x00, 0xa6, 0xa2, 0xae, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "dec", AMC_DEC, { 0x00, 0xc6, 0x00, 0xce, 0x00, 0xd6, 0x00, 0xde, 0x00, 0x3a, 0x3a, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "inc", AMC_DEC, { 0x00, 0xe6, 0x00, 0xee, 0x00, 0xf6, 0x00, 0xfe, 0x00, 0x1a, 0x1a, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "php", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "plp", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "pha", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "pla", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "phy", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "ply", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "phx", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "plx", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "dey", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "tay", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "iny", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "inx", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00 } },
|
||||||
|
// nam modes (zp,x) zp # $0000 (zp),y zp,x abs,y abs,x (xx) A empty (zp)(abs,x)zp,abs
|
||||||
|
{ "bpl", AMM_BRA, { 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "bmi", AMM_BRA, { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "bvc", AMM_BRA, { 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "bvs", AMM_BRA, { 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "bra", AMM_BRA, { 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "bcc", AMM_BRA, { 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "bcs", AMM_BRA, { 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "bne", AMM_BRA, { 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "beq", AMM_BRA, { 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "clc", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "sec", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "cli", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "sei", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "tya", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "clv", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "cld", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "sed", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "bit", AMC_BIT, { 0x00, 0x24, 0x89, 0x2c, 0x00, 0x34, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "stz", AMC_STZ, { 0x00, 0x64, 0x00, 0x9c, 0x00, 0x74, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "trb", AMC_TRB, { 0x00, 0x14, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "tsb", AMC_TRB, { 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "jmp", AMC_JMP, { 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x7c, 0x00 } },
|
||||||
|
{ "sty", AMM_STY, { 0x00, 0x84, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "ldy", AMM_LDY, { 0x00, 0xa4, 0xa0, 0xac, 0x00, 0xb4, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "cpy", AMM_CPY, { 0x00, 0xc4, 0xc0, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "cpx", AMM_CPY, { 0x00, 0xe4, 0xe0, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "txa", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "txs", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "tax", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "tsx", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "dex", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "nop", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00 } },
|
||||||
|
|
||||||
|
// WDC specific
|
||||||
|
// nam modes (zp,x) zp # $0000 (zp),y zp,x abs,y abs,x (xx) A empty (zp)(abs,x)zp,abs
|
||||||
|
|
||||||
|
{"bbr0", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f } },
|
||||||
|
{"bbr1", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f } },
|
||||||
|
{"bbr2", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f } },
|
||||||
|
{"bbr3", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f } },
|
||||||
|
{"bbr4", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f } },
|
||||||
|
{"bbr5", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f } },
|
||||||
|
{"bbr6", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f } },
|
||||||
|
{"bbr7", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f } },
|
||||||
|
{"bbs0", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f } },
|
||||||
|
{"bbs1", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f } },
|
||||||
|
{"bbs2", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf } },
|
||||||
|
{"bbs3", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf } },
|
||||||
|
{"bbs4", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf } },
|
||||||
|
{"bbs5", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf } },
|
||||||
|
{"bbs6", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef } },
|
||||||
|
{"bbs7", AMC_BBR, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0xff } },
|
||||||
|
{ "stp", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00 } },
|
||||||
|
{ "wai", AMM_NON, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00 } },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int num_opcodes_65C02 = sizeof(opcodes_65C02) / sizeof(opcodes_65C02[0]);
|
||||||
|
|
||||||
|
|
||||||
// 65C02
|
// 65C02
|
||||||
// http://6502.org/tutorials/65c02opcodes.html
|
// http://6502.org/tutorials/65c02opcodes.html
|
||||||
// http://www.oxyron.de/html/opcodesc02.html
|
// http://www.oxyron.de/html/opcodesc02.html
|
||||||
@ -394,7 +504,8 @@ enum CODE_ARG {
|
|||||||
CA_NONE, // single byte instruction
|
CA_NONE, // single byte instruction
|
||||||
CA_ONE_BYTE, // instruction carries one byte
|
CA_ONE_BYTE, // instruction carries one byte
|
||||||
CA_TWO_BYTES, // instruction carries two bytes
|
CA_TWO_BYTES, // instruction carries two bytes
|
||||||
CA_BRANCH // instruction carries a relative address
|
CA_BRANCH, // instruction carries a relative address
|
||||||
|
CA_BYTE_BRANCH // instruction carries one byte and one branch
|
||||||
};
|
};
|
||||||
|
|
||||||
// hardtexted strings
|
// hardtexted strings
|
||||||
@ -409,17 +520,21 @@ static const strref str_const("const");
|
|||||||
static const strref struct_byte("byte");
|
static const strref struct_byte("byte");
|
||||||
static const strref struct_word("word");
|
static const strref struct_word("word");
|
||||||
static const char* aAddrModeFmt[] = {
|
static const char* aAddrModeFmt[] = {
|
||||||
"%s ($%02x,x)",
|
"%s ($%02x,x)",
|
||||||
"%s $%02x",
|
"%s $%02x",
|
||||||
"%s #$%02x",
|
"%s #$%02x",
|
||||||
"%s $%04x",
|
"%s $%04x",
|
||||||
"%s ($%02x),y",
|
"%s ($%02x),y",
|
||||||
"%s $%02x,x",
|
"%s $%02x,x",
|
||||||
"%s $%04x,y",
|
"%s $%04x,y",
|
||||||
"%s $%04x,x",
|
"%s $%04x,x",
|
||||||
"%s ($%04x)",
|
"%s ($%04x)",
|
||||||
"%s A",
|
"%s A",
|
||||||
"%s " };
|
"%s ",
|
||||||
|
"%s ($%02x)",
|
||||||
|
"%s ($%04x,x)",
|
||||||
|
"%s $%02x, $%04x",
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Binary search over an array of unsigned integers, may contain multiple instances of same key
|
// Binary search over an array of unsigned integers, may contain multiple instances of same key
|
||||||
@ -794,6 +909,10 @@ public:
|
|||||||
std::vector<Section> allSections;
|
std::vector<Section> allSections;
|
||||||
std::vector<ExtLabels> externals; // external labels organized by object file
|
std::vector<ExtLabels> externals; // external labels organized by object file
|
||||||
MapSymbolArray map;
|
MapSymbolArray map;
|
||||||
|
|
||||||
|
// CPU target
|
||||||
|
struct mnem *opcode_table;
|
||||||
|
int opcode_count;
|
||||||
|
|
||||||
// context for macros / include files
|
// context for macros / include files
|
||||||
ContextStack contextStack;
|
ContextStack contextStack;
|
||||||
@ -819,6 +938,7 @@ public:
|
|||||||
int lastEvalValue;
|
int lastEvalValue;
|
||||||
Reloc::Type lastEvalPart;
|
Reloc::Type lastEvalPart;
|
||||||
|
|
||||||
|
strref export_base_name;
|
||||||
strref last_label;
|
strref last_label;
|
||||||
bool errorEncountered;
|
bool errorEncountered;
|
||||||
bool list_assembly;
|
bool list_assembly;
|
||||||
@ -889,7 +1009,7 @@ public:
|
|||||||
|
|
||||||
// Manage locals
|
// Manage locals
|
||||||
void MarkLabelLocal(strref label, bool scope_label = false);
|
void MarkLabelLocal(strref label, bool scope_label = false);
|
||||||
void FlushLocalLabels(int scope_exit = -1);
|
StatusCode FlushLocalLabels(int scope_exit = -1);
|
||||||
|
|
||||||
// Label pools
|
// Label pools
|
||||||
LabelPool* GetLabelPool(strref pool_name);
|
LabelPool* GetLabelPool(strref pool_name);
|
||||||
@ -940,7 +1060,8 @@ public:
|
|||||||
char* LoadBinary(strref filename, size_t &size);
|
char* LoadBinary(strref filename, size_t &size);
|
||||||
|
|
||||||
// constructor
|
// constructor
|
||||||
Asm() { Cleanup(); localLabels.reserve(256); loadedData.reserve(16); lateEval.reserve(64); }
|
Asm() : opcode_table(opcodes_6502), opcode_count(num_opcodes_6502) {
|
||||||
|
Cleanup(); localLabels.reserve(256); loadedData.reserve(16); lateEval.reserve(64); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Clean up work allocations
|
// Clean up work allocations
|
||||||
@ -1554,14 +1675,12 @@ StatusCode Asm::BuildMacro(Macro &m, strref arg_list)
|
|||||||
macexp.replace(param, a);
|
macexp.replace(param, a);
|
||||||
}
|
}
|
||||||
contextStack.push(m.source_name, macexp.get_strref(), macexp.get_strref());
|
contextStack.push(m.source_name, macexp.get_strref(), macexp.get_strref());
|
||||||
FlushLocalLabels();
|
return FlushLocalLabels();
|
||||||
return STATUS_OK;
|
|
||||||
} else
|
} else
|
||||||
return ERROR_OUT_OF_MEMORY_FOR_MACRO_EXPANSION;
|
return ERROR_OUT_OF_MEMORY_FOR_MACRO_EXPANSION;
|
||||||
}
|
}
|
||||||
contextStack.push(m.source_name, m.source_file, macro_src);
|
contextStack.push(m.source_name, m.source_file, macro_src);
|
||||||
FlushLocalLabels();
|
return FlushLocalLabels();
|
||||||
return STATUS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2153,9 +2272,10 @@ StatusCode Asm::CheckLateEval(strref added_label, int scope_end)
|
|||||||
switch (i->type) {
|
switch (i->type) {
|
||||||
case LateEval::LET_BRANCH:
|
case LateEval::LET_BRANCH:
|
||||||
value -= i->address+1;
|
value -= i->address+1;
|
||||||
if (value<-128 || value>127)
|
if (value<-128 || value>127) {
|
||||||
|
i = lateEval.erase(i);
|
||||||
return ERROR_BRANCH_OUT_OF_RANGE;
|
return ERROR_BRANCH_OUT_OF_RANGE;
|
||||||
if (trg >= allSections[sec].size())
|
} if (trg >= allSections[sec].size())
|
||||||
return ERROR_SECTION_TARGET_OFFSET_OUT_OF_RANGE;
|
return ERROR_SECTION_TARGET_OFFSET_OUT_OF_RANGE;
|
||||||
allSections[sec].SetByte(trg, value);
|
allSections[sec].SetByte(trg, value);
|
||||||
break;
|
break;
|
||||||
@ -2288,8 +2408,9 @@ void Asm::MarkLabelLocal(strref label, bool scope_reserve)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// find all local labels or up to given scope level and remove them
|
// find all local labels or up to given scope level and remove them
|
||||||
void Asm::FlushLocalLabels(int scope_exit)
|
StatusCode Asm::FlushLocalLabels(int scope_exit)
|
||||||
{
|
{
|
||||||
|
StatusCode status = STATUS_OK;
|
||||||
// iterate from end of local label records and early out if the label scope is lower than the current.
|
// iterate from end of local label records and early out if the label scope is lower than the current.
|
||||||
std::vector<LocalLabelRecord>::iterator i = localLabels.end();
|
std::vector<LocalLabelRecord>::iterator i = localLabels.end();
|
||||||
while (i!=localLabels.begin()) {
|
while (i!=localLabels.begin()) {
|
||||||
@ -2297,6 +2418,9 @@ void Asm::FlushLocalLabels(int scope_exit)
|
|||||||
if (i->scope_depth < scope_depth)
|
if (i->scope_depth < scope_depth)
|
||||||
break;
|
break;
|
||||||
strref label = i->label;
|
strref label = i->label;
|
||||||
|
StatusCode this_status = CheckLateEval(label);
|
||||||
|
if (this_status>FIRST_ERROR)
|
||||||
|
status = this_status;
|
||||||
if (!i->scope_reserve || i->scope_depth<=scope_exit) {
|
if (!i->scope_reserve || i->scope_depth<=scope_exit) {
|
||||||
unsigned int index = FindLabelIndex(label.fnv1a(), labels.getKeys(), labels.count());
|
unsigned int index = FindLabelIndex(label.fnv1a(), labels.getKeys(), labels.count());
|
||||||
while (index<labels.count()) {
|
while (index<labels.count()) {
|
||||||
@ -2315,6 +2439,7 @@ void Asm::FlushLocalLabels(int scope_exit)
|
|||||||
i = localLabels.erase(i);
|
i = localLabels.erase(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a label pool by name
|
// Get a label pool by name
|
||||||
@ -2549,6 +2674,7 @@ StatusCode Asm::AssignLabel(strref label, strref line, bool make_constant)
|
|||||||
// Adding a fixed address label
|
// Adding a fixed address label
|
||||||
StatusCode Asm::AddressLabel(strref label)
|
StatusCode Asm::AddressLabel(strref label)
|
||||||
{
|
{
|
||||||
|
StatusCode status = STATUS_OK;
|
||||||
Label *pLabel = GetLabel(label);
|
Label *pLabel = GetLabel(label);
|
||||||
bool constLabel = false;
|
bool constLabel = false;
|
||||||
if (!pLabel)
|
if (!pLabel)
|
||||||
@ -2571,9 +2697,13 @@ StatusCode Asm::AddressLabel(strref label)
|
|||||||
LabelAdded(pLabel, local);
|
LabelAdded(pLabel, local);
|
||||||
if (local)
|
if (local)
|
||||||
MarkLabelLocal(label);
|
MarkLabelLocal(label);
|
||||||
else if (label[0]!=']') // MERLIN: Variable label does not invalidate local labels
|
status = CheckLateEval(label);
|
||||||
FlushLocalLabels();
|
if (!local && label[0]!=']') { // MERLIN: Variable label does not invalidate local labels
|
||||||
return CheckLateEval(label);
|
StatusCode this_status = FlushLocalLabels();
|
||||||
|
if (status<FIRST_ERROR && this_status>=FIRST_ERROR)
|
||||||
|
status = this_status;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// include symbols listed from a .sym file or all if no listing
|
// include symbols listed from a .sym file or all if no listing
|
||||||
@ -2822,6 +2952,7 @@ DirectiveName aDirectiveNames[] {
|
|||||||
{ "DS", AD_DS }, // MERLIN
|
{ "DS", AD_DS }, // MERLIN
|
||||||
{ "LUP", AD_REPT }, // MERLIN
|
{ "LUP", AD_REPT }, // MERLIN
|
||||||
{ "MAC", AD_MACRO }, // MERLIN
|
{ "MAC", AD_MACRO }, // MERLIN
|
||||||
|
{ "SAV", AD_SAV }, // MERLIN
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int nDirectiveNames = sizeof(aDirectiveNames) / sizeof(aDirectiveNames[0]);
|
static const int nDirectiveNames = sizeof(aDirectiveNames) / sizeof(aDirectiveNames[0]);
|
||||||
@ -3121,6 +3252,13 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
|
|||||||
case AD_USR:
|
case AD_USR:
|
||||||
line.clear();
|
line.clear();
|
||||||
break;
|
break;
|
||||||
|
case AD_SAV:
|
||||||
|
line.trim_whitespace();
|
||||||
|
if (line.has_prefix(export_base_name))
|
||||||
|
line.skip(export_base_name.get_len());
|
||||||
|
if (line)
|
||||||
|
CurrSection().export_append = line.split_label();
|
||||||
|
break;
|
||||||
case AD_TEXT: { // text: add text within quotes
|
case AD_TEXT: { // text: add text within quotes
|
||||||
// for now just copy the windows ascii. TODO: Convert to petscii.
|
// for now just copy the windows ascii. TODO: Convert to petscii.
|
||||||
// https://en.wikipedia.org/wiki/PETSCII
|
// https://en.wikipedia.org/wiki/PETSCII
|
||||||
@ -3349,13 +3487,13 @@ int sortHashLookup(const void *A, const void *B) {
|
|||||||
return _A->op_hash > _B->op_hash ? 1 : -1;
|
return _A->op_hash > _B->op_hash ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BuildInstructionTable(OP_ID *pInstr, int maxInstructions)
|
int BuildInstructionTable(OP_ID *pInstr, int maxInstructions, struct mnem *opcodes, int count)
|
||||||
{
|
{
|
||||||
// create an instruction table (mnemonic hash lookup)
|
// create an instruction table (mnemonic hash lookup)
|
||||||
int numInstructions = 0;
|
int numInstructions = 0;
|
||||||
for (int i = 0; i < num_opcodes_6502; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
OP_ID &op = pInstr[numInstructions++];
|
OP_ID &op = pInstr[numInstructions++];
|
||||||
op.op_hash = strref(opcodes_6502[i].instr).fnv1a_lower();
|
op.op_hash = strref(opcodes[i].instr).fnv1a_lower();
|
||||||
op.index = i;
|
op.index = i;
|
||||||
op.type = OT_MNEMONIC;
|
op.type = OT_MNEMONIC;
|
||||||
}
|
}
|
||||||
@ -3364,7 +3502,6 @@ int BuildInstructionTable(OP_ID *pInstr, int maxInstructions)
|
|||||||
for (int d=0; d<nDirectiveNames; d++) {
|
for (int d=0; d<nDirectiveNames; d++) {
|
||||||
OP_ID &op_hash = pInstr[numInstructions++];
|
OP_ID &op_hash = pInstr[numInstructions++];
|
||||||
op_hash.op_hash = strref(aDirectiveNames[d].name).fnv1a_lower();
|
op_hash.op_hash = strref(aDirectiveNames[d].name).fnv1a_lower();
|
||||||
// op_hash.group = 0xff;
|
|
||||||
op_hash.index = (unsigned char)aDirectiveNames[d].directive;
|
op_hash.index = (unsigned char)aDirectiveNames[d].directive;
|
||||||
op_hash.type = OT_DIRECTIVE;
|
op_hash.type = OT_DIRECTIVE;
|
||||||
}
|
}
|
||||||
@ -3446,10 +3583,30 @@ StatusCode Asm::AddOpcode(strref line, int index, strref source_file)
|
|||||||
{
|
{
|
||||||
StatusCode error = STATUS_OK;
|
StatusCode error = STATUS_OK;
|
||||||
strref expression;
|
strref expression;
|
||||||
|
|
||||||
|
// allowed modes
|
||||||
|
unsigned int validModes = opcode_table[index].modes;
|
||||||
|
|
||||||
// Get the addressing mode and the expression it refers to
|
// Get the addressing mode and the expression it refers to
|
||||||
AddrMode addrMode = GetAddressMode(line,
|
AddrMode addrMode;
|
||||||
!!(opcodes_6502[index].modes & AMM_FLIPXY), error, expression);
|
switch (validModes) {
|
||||||
|
case AMC_BBR:
|
||||||
|
addrMode = AMB_ZP_ABS;
|
||||||
|
expression = line.split_token_trim(',');
|
||||||
|
if (!expression || !line)
|
||||||
|
return ERROR_INVALID_ADDRESSING_MODE;
|
||||||
|
break;
|
||||||
|
case AMM_BRA:
|
||||||
|
addrMode = AMB_ABS;
|
||||||
|
expression = line;
|
||||||
|
break;
|
||||||
|
case AMM_NON:
|
||||||
|
addrMode = AMB_NON;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
addrMode = GetAddressMode(line, !!(validModes & AMM_FLIPXY), error, expression);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
int value = 0;
|
int value = 0;
|
||||||
int target_section = -1;
|
int target_section = -1;
|
||||||
@ -3458,7 +3615,7 @@ StatusCode Asm::AddOpcode(strref line, int index, strref source_file)
|
|||||||
bool evalLater = false;
|
bool evalLater = false;
|
||||||
if (expression) {
|
if (expression) {
|
||||||
struct EvalContext etx(CurrSection().GetPC(), scope_address[scope_depth], -1,
|
struct EvalContext etx(CurrSection().GetPC(), scope_address[scope_depth], -1,
|
||||||
!!(opcodes_6502[index].modes & AMM_BRA) ? SectionId() : -1);
|
!!(validModes & AMM_BRANCH) ? SectionId() : -1);
|
||||||
error = EvalExpression(expression, etx, value);
|
error = EvalExpression(expression, etx, value);
|
||||||
if (error == STATUS_NOT_READY) {
|
if (error == STATUS_NOT_READY) {
|
||||||
evalLater = true;
|
evalLater = true;
|
||||||
@ -3475,11 +3632,11 @@ StatusCode Asm::AddOpcode(strref line, int index, strref source_file)
|
|||||||
if (!evalLater && value>=0 && value<0x100 && error != STATUS_RELATIVE_SECTION) {
|
if (!evalLater && value>=0 && value<0x100 && error != STATUS_RELATIVE_SECTION) {
|
||||||
switch (addrMode) {
|
switch (addrMode) {
|
||||||
case AMB_ABS:
|
case AMB_ABS:
|
||||||
if (opcodes_6502[index].modes & AMM_ZP)
|
if (validModes & AMM_ZP)
|
||||||
addrMode = AMB_ZP;
|
addrMode = AMB_ZP;
|
||||||
break;
|
break;
|
||||||
case AMB_ABS_X:
|
case AMB_ABS_X:
|
||||||
if (opcodes_6502[index].modes & AMM_ZP_X)
|
if (validModes & AMM_ZP_X)
|
||||||
addrMode = AMB_ZP_X;
|
addrMode = AMB_ZP_X;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -3487,35 +3644,61 @@ StatusCode Asm::AddOpcode(strref line, int index, strref source_file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CODE_ARG codeArg = CA_NONE;
|
bool valid_addressing_mode = !!(validModes & (1 << addrMode));
|
||||||
unsigned char opcode = opcodes_6502[index].aCodes[addrMode];
|
|
||||||
|
|
||||||
if (!(opcodes_6502[index].modes & (1 << addrMode)))
|
if (!valid_addressing_mode) {
|
||||||
error = ERROR_INVALID_ADDRESSING_MODE;
|
if (addrMode==AMB_ZP_REL_X && (validModes & AMM_REL_X)) {
|
||||||
else {
|
addrMode = AMB_REL_X;
|
||||||
if (opcodes_6502[index].modes & AMM_BRANCH)
|
valid_addressing_mode = true;
|
||||||
|
} else if (addrMode==AMB_REL && (validModes & AMM_ZP_REL)) {
|
||||||
|
addrMode = AMB_ZP_REL;
|
||||||
|
valid_addressing_mode = true;
|
||||||
|
} else
|
||||||
|
error = ERROR_INVALID_ADDRESSING_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the instruction and argument to the code
|
||||||
|
if (error == STATUS_OK || error == STATUS_RELATIVE_SECTION) {
|
||||||
|
unsigned char opcode = opcode_table[index].aCodes[addrMode];
|
||||||
|
CheckOutputCapacity(4);
|
||||||
|
AddByte(opcode);
|
||||||
|
|
||||||
|
CODE_ARG codeArg = CA_NONE;
|
||||||
|
if (validModes & AMM_BRANCH)
|
||||||
codeArg = CA_BRANCH;
|
codeArg = CA_BRANCH;
|
||||||
else if (addrMode == AMB_ABS || addrMode == AMB_REL || addrMode == AMB_ABS_X || addrMode == AMB_ABS_Y)
|
else if (addrMode == AMB_ABS || addrMode == AMB_REL || addrMode == AMB_ABS_X || addrMode == AMB_ABS_Y)
|
||||||
codeArg = CA_TWO_BYTES;
|
codeArg = CA_TWO_BYTES;
|
||||||
|
else if (addrMode == AMB_ZP_ABS)
|
||||||
|
codeArg = CA_BYTE_BRANCH;
|
||||||
else if (addrMode != AMB_NON && addrMode != AMB_ACC)
|
else if (addrMode != AMB_NON && addrMode != AMB_ACC)
|
||||||
codeArg = CA_ONE_BYTE;
|
codeArg = CA_ONE_BYTE;
|
||||||
}
|
|
||||||
// Add the instruction and argument to the code
|
|
||||||
if (error == STATUS_OK || error == STATUS_RELATIVE_SECTION) {
|
|
||||||
CheckOutputCapacity(4);
|
|
||||||
switch (codeArg) {
|
switch (codeArg) {
|
||||||
|
case CA_BYTE_BRANCH: {
|
||||||
|
if (evalLater)
|
||||||
|
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], expression, source_file, LateEval::LET_BYTE);
|
||||||
|
else if (error == STATUS_RELATIVE_SECTION) {
|
||||||
|
CurrSection().AddReloc(target_section_offs, CurrSection().DataOffset(), target_section,
|
||||||
|
target_section_type == Reloc::HI_BYTE ? Reloc::HI_BYTE : Reloc::LO_BYTE);
|
||||||
|
}
|
||||||
|
AddByte(value);
|
||||||
|
struct EvalContext etx(CurrSection().GetPC()-2, scope_address[scope_depth], -1, SectionId());
|
||||||
|
error = EvalExpression(line, etx, value);
|
||||||
|
if (error==STATUS_NOT_READY)
|
||||||
|
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], line, source_file, LateEval::LET_BRANCH);
|
||||||
|
else if (((int)value - (int)CurrSection().GetPC() - 1) < -128 || ((int)value - (int)CurrSection().GetPC() - 1) > 127)
|
||||||
|
error = ERROR_BRANCH_OUT_OF_RANGE;
|
||||||
|
AddByte(error == STATUS_NOT_READY ? 0 : (unsigned char)((int)value - (int)CurrSection().GetPC()) - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case CA_BRANCH:
|
case CA_BRANCH:
|
||||||
AddByte(opcode);
|
|
||||||
if (evalLater)
|
if (evalLater)
|
||||||
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], expression, source_file, LateEval::LET_BRANCH);
|
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], expression, source_file, LateEval::LET_BRANCH);
|
||||||
else if (((int)value - (int)CurrSection().GetPC()-1) < -128 || ((int)value - (int)CurrSection().GetPC()-1) > 127) {
|
else if (((int)value - (int)CurrSection().GetPC()-1) < -128 || ((int)value - (int)CurrSection().GetPC()-1) > 127)
|
||||||
error = ERROR_BRANCH_OUT_OF_RANGE;
|
error = ERROR_BRANCH_OUT_OF_RANGE;
|
||||||
break;
|
|
||||||
}
|
|
||||||
AddByte(evalLater ? 0 : (unsigned char)((int)value - (int)CurrSection().GetPC()) - 1);
|
AddByte(evalLater ? 0 : (unsigned char)((int)value - (int)CurrSection().GetPC()) - 1);
|
||||||
break;
|
break;
|
||||||
case CA_ONE_BYTE:
|
case CA_ONE_BYTE:
|
||||||
AddByte(opcode);
|
|
||||||
if (evalLater)
|
if (evalLater)
|
||||||
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], expression, source_file, LateEval::LET_BYTE);
|
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], expression, source_file, LateEval::LET_BYTE);
|
||||||
else if (error == STATUS_RELATIVE_SECTION)
|
else if (error == STATUS_RELATIVE_SECTION)
|
||||||
@ -3524,7 +3707,6 @@ StatusCode Asm::AddOpcode(strref line, int index, strref source_file)
|
|||||||
AddByte(value);
|
AddByte(value);
|
||||||
break;
|
break;
|
||||||
case CA_TWO_BYTES:
|
case CA_TWO_BYTES:
|
||||||
AddByte(opcode);
|
|
||||||
if (evalLater)
|
if (evalLater)
|
||||||
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], expression, source_file, LateEval::LET_ABS_REF);
|
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], expression, source_file, LateEval::LET_ABS_REF);
|
||||||
else if (error == STATUS_RELATIVE_SECTION) {
|
else if (error == STATUS_RELATIVE_SECTION) {
|
||||||
@ -3535,7 +3717,6 @@ StatusCode Asm::AddOpcode(strref line, int index, strref source_file)
|
|||||||
AddWord(value);
|
AddWord(value);
|
||||||
break;
|
break;
|
||||||
case CA_NONE:
|
case CA_NONE:
|
||||||
AddByte(opcode);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3780,10 +3961,10 @@ bool Asm::List(strref filename)
|
|||||||
unsigned char addrmode[256];
|
unsigned char addrmode[256];
|
||||||
memset(mnemonic, 255, sizeof(mnemonic));
|
memset(mnemonic, 255, sizeof(mnemonic));
|
||||||
memset(addrmode, 255, sizeof(addrmode));
|
memset(addrmode, 255, sizeof(addrmode));
|
||||||
for (int i = 0; i < num_opcodes_6502; i++) {
|
for (int i = 0; i < opcode_count; i++) {
|
||||||
for (int j = 0; j < AMB_COUNT; j++) {
|
for (int j = 0; j < AMB_COUNT; j++) {
|
||||||
if (opcodes_6502[i].modes & (1 << j)) {
|
if (opcode_table[i].modes & (1 << j)) {
|
||||||
unsigned char op = opcodes_6502[i].aCodes[j];
|
unsigned char op = opcode_table[i].aCodes[j];
|
||||||
mnemonic[op] = i;
|
mnemonic[op] = i;
|
||||||
addrmode[op] = j;
|
addrmode[op] = j;
|
||||||
}
|
}
|
||||||
@ -3835,23 +4016,25 @@ bool Asm::List(strref filename)
|
|||||||
unsigned char *buf = si->output + lst.address;
|
unsigned char *buf = si->output + lst.address;
|
||||||
unsigned char op = mnemonic[*buf];
|
unsigned char op = mnemonic[*buf];
|
||||||
unsigned char am = addrmode[*buf];
|
unsigned char am = addrmode[*buf];
|
||||||
if (op != 255 && am != 255) {
|
if (op != 255 && am != 255 && am<(sizeof(aAddrModeFmt)/sizeof(aAddrModeFmt[0]))) {
|
||||||
const char *fmt = aAddrModeFmt[am];
|
const char *fmt = aAddrModeFmt[am];
|
||||||
if (opcodes_6502[op].modes & AMM_FLIPXY) {
|
if (opcode_table[op].modes & AMM_FLIPXY) {
|
||||||
if (am == AMB_ZP_X) fmt = "%s $%02x,y";
|
if (am == AMB_ZP_X) fmt = "%s $%02x,y";
|
||||||
else if (am == AMB_ABS_X) fmt = "%s $%04x,y";
|
else if (am == AMB_ABS_X) fmt = "%s $%04x,y";
|
||||||
}
|
}
|
||||||
if (opcodes_6502[op].modes & AMM_BRANCH)
|
if (opcode_table[op].modes & AMM_ZP_ABS)
|
||||||
out.sprintf_append(fmt, opcodes_6502[op].instr, (char)buf[1] + lst.address + si->start_address + 2);
|
out.sprintf_append(fmt, opcode_table[op].instr, buf[1], (char)buf[2] + lst.address + si->start_address + 3);
|
||||||
|
else if (opcode_table[op].modes & AMM_BRANCH)
|
||||||
|
out.sprintf_append(fmt, opcode_table[op].instr, (char)buf[1] + lst.address + si->start_address + 2);
|
||||||
else if (am == AMB_NON || am == AMB_ACC)
|
else if (am == AMB_NON || am == AMB_ACC)
|
||||||
out.sprintf_append(fmt, opcodes_6502[op].instr);
|
out.sprintf_append(fmt, opcode_table[op].instr);
|
||||||
else if (am == AMB_ABS || am == AMB_ABS_X || am == AMB_ABS_Y || am == AMB_REL)
|
else if (am == AMB_ABS || am == AMB_ABS_X || am == AMB_ABS_Y || am == AMB_REL || am == AMB_REL_X)
|
||||||
out.sprintf_append(fmt, opcodes_6502[op].instr, buf[1] | (buf[2] << 8));
|
out.sprintf_append(fmt, opcode_table[op].instr, buf[1] | (buf[2] << 8));
|
||||||
else
|
else
|
||||||
out.sprintf_append(fmt, opcodes_6502[op].instr, buf[1]);
|
out.sprintf_append(fmt, opcode_table[op].instr, buf[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.append_to(' ', 30);
|
out.append_to(' ', 33);
|
||||||
strref line = lst.code.get_skipped(lst.line_offs).get_line();
|
strref line = lst.code.get_skipped(lst.line_offs).get_line();
|
||||||
line.clip_trailing_whitespace();
|
line.clip_trailing_whitespace();
|
||||||
strown<128> line_fix(line);
|
strown<128> line_fix(line);
|
||||||
@ -3881,21 +4064,24 @@ bool Asm::AllOpcodes(strref filename)
|
|||||||
return false;
|
return false;
|
||||||
opened = true;
|
opened = true;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < num_opcodes_6502; i++) {
|
for (int i = 0; i < opcode_count; i++) {
|
||||||
for (int a = 0; a < AMB_COUNT; a++) {
|
for (int a = 0; a < AMB_COUNT; a++) {
|
||||||
if (opcodes_6502[i].modes & (1 << a)) {
|
if (opcode_table[i].modes & (1 << a)) {
|
||||||
const char *fmt = aAddrModeFmt[a];
|
const char *fmt = aAddrModeFmt[a];
|
||||||
if (opcodes_6502[i].modes & AMM_BRANCH)
|
fputs("\t", f);
|
||||||
fprintf(f, "%s *+%d", opcodes_6502[i].instr, 5);
|
if (opcode_table[i].modes & AMM_BRANCH)
|
||||||
|
fprintf(f, "%s *+%d", opcode_table[i].instr, 5);
|
||||||
|
else if (a==AMB_ZP_ABS)
|
||||||
|
fprintf(f, "%s $%02x,*+%d", opcode_table[i].instr, 0x23, 13);
|
||||||
else {
|
else {
|
||||||
if (opcodes_6502[i].modes & AMM_FLIPXY) {
|
if (opcode_table[i].modes & AMM_FLIPXY) {
|
||||||
if (a == AMB_ZP_X) fmt = "%s $%02x,y";
|
if (a == AMB_ZP_X) fmt = "%s $%02x,y";
|
||||||
else if (a == AMB_ABS_X) fmt = "%s $%04x,y";
|
else if (a == AMB_ABS_X) fmt = "%s $%04x,y";
|
||||||
}
|
}
|
||||||
if (a==AMB_ABS || a==AMB_ABS_X || a==AMB_ABS_Y || a==AMB_REL)
|
if (a == AMB_ABS || a == AMB_ABS_X || a == AMB_ABS_Y || a == AMB_REL || a == AMB_REL_X)
|
||||||
fprintf(f, fmt, opcodes_6502[i].instr, 0x2120);
|
fprintf(f, fmt, opcode_table[i].instr, 0x2120);
|
||||||
else
|
else
|
||||||
fprintf(f, fmt, opcodes_6502[i].instr, 0x21, 0x20, 0x1f);
|
fprintf(f, fmt, opcode_table[i].instr, 0x21, 0x20, 0x1f);
|
||||||
}
|
}
|
||||||
fputs("\n", f);
|
fputs("\n", f);
|
||||||
}
|
}
|
||||||
@ -3910,7 +4096,7 @@ bool Asm::AllOpcodes(strref filename)
|
|||||||
void Asm::Assemble(strref source, strref filename, bool obj_target)
|
void Asm::Assemble(strref source, strref filename, bool obj_target)
|
||||||
{
|
{
|
||||||
OP_ID *pInstr = new OP_ID[256];
|
OP_ID *pInstr = new OP_ID[256];
|
||||||
int numInstructions = BuildInstructionTable(pInstr, 256);
|
int numInstructions = BuildInstructionTable(pInstr, 256, opcode_table, opcode_count);
|
||||||
|
|
||||||
StatusCode error = STATUS_OK;
|
StatusCode error = STATUS_OK;
|
||||||
contextStack.push(filename, source, source);
|
contextStack.push(filename, source, source);
|
||||||
@ -4365,6 +4551,7 @@ int main(int argc, char **argv)
|
|||||||
const strref listing("lst");
|
const strref listing("lst");
|
||||||
const strref allinstr("opcodes");
|
const strref allinstr("opcodes");
|
||||||
const strref endmacro("endm");
|
const strref endmacro("endm");
|
||||||
|
const strref cpu("cpu");
|
||||||
int return_value = 0;
|
int return_value = 0;
|
||||||
bool load_header = true;
|
bool load_header = true;
|
||||||
bool size_header = false;
|
bool size_header = false;
|
||||||
@ -4409,6 +4596,15 @@ int main(int argc, char **argv)
|
|||||||
} else if (arg.has_prefix(allinstr) && (arg.get_len() == allinstr.get_len() || arg[allinstr.get_len()] == '=')) {
|
} else if (arg.has_prefix(allinstr) && (arg.get_len() == allinstr.get_len() || arg[allinstr.get_len()] == '=')) {
|
||||||
gen_allinstr = true;
|
gen_allinstr = true;
|
||||||
allinstr_file = arg.after('=');
|
allinstr_file = arg.after('=');
|
||||||
|
} else if (arg.has_prefix(cpu) && (arg.get_len() == cpu.get_len() || arg[cpu.get_len()] == '=')) {
|
||||||
|
arg.split_token_trim('=');
|
||||||
|
if (arg.same_str("6502")) {
|
||||||
|
assembler.opcode_table = opcodes_6502;
|
||||||
|
assembler.opcode_count = num_opcodes_6502;
|
||||||
|
} else if (arg.same_str("65c02")) {
|
||||||
|
assembler.opcode_table = opcodes_65C02;
|
||||||
|
assembler.opcode_count = num_opcodes_65C02;
|
||||||
|
}
|
||||||
} else if (arg.same_str("sym") && (a + 1) < argc)
|
} else if (arg.same_str("sym") && (a + 1) < argc)
|
||||||
sym_file = argv[++a];
|
sym_file = argv[++a];
|
||||||
else if (arg.same_str("obj") && (a + 1) < argc)
|
else if (arg.same_str("obj") && (a + 1) < argc)
|
||||||
@ -4428,6 +4624,7 @@ int main(int argc, char **argv)
|
|||||||
" x65 filename.s code.prg [options]\n"
|
" x65 filename.s code.prg [options]\n"
|
||||||
" * -i(path) : Add include path\n"
|
" * -i(path) : Add include path\n"
|
||||||
" * -D(label)[=<value>] : Define a label with an optional value(otherwise defined as 1)\n"
|
" * -D(label)[=<value>] : Define a label with an optional value(otherwise defined as 1)\n"
|
||||||
|
" * -cpu=6502/65c02: assemble with opcodes for a different cpu\n"
|
||||||
" * -obj(file.x65) : generate object file for later linking\n"
|
" * -obj(file.x65) : generate object file for later linking\n"
|
||||||
" * -bin : Raw binary\n"
|
" * -bin : Raw binary\n"
|
||||||
" * -c64 : Include load address(default)\n"
|
" * -c64 : Include load address(default)\n"
|
||||||
@ -4446,6 +4643,9 @@ int main(int argc, char **argv)
|
|||||||
if (source_filename) {
|
if (source_filename) {
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
strref srcname(source_filename);
|
strref srcname(source_filename);
|
||||||
|
|
||||||
|
assembler.export_base_name = strref(binary_out_name).after_last_or_full('/', '\\').before_or_full('.');
|
||||||
|
|
||||||
if (char *buffer = assembler.LoadText(srcname, size)) {
|
if (char *buffer = assembler.LoadText(srcname, size)) {
|
||||||
// if source_filename contains a path add that as a search path for include files
|
// if source_filename contains a path add that as a search path for include files
|
||||||
assembler.AddIncludeFolder(srcname.before_last('/', '\\'));
|
assembler.AddIncludeFolder(srcname.before_last('/', '\\'));
|
||||||
|
Loading…
Reference in New Issue
Block a user