2015-09-29 22:07:04 -07:00
//
2015-10-13 19:38:13 -07:00
// x65.cpp
2015-09-29 22:07:04 -07:00
//
//
// Created by Carl-Henrik Skårstedt on 9/23/15.
//
//
// A simple 6502 assembler
//
//
// The MIT License (MIT)
//
// Copyright (c) 2015 Carl-Henrik Skårstedt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
2015-10-13 19:38:13 -07:00
// Details, source and documentation at https://github.com/Sakrac/x65.
2015-10-02 20:57:50 -07:00
//
// "struse.h" can be found at https://github.com/Sakrac/struse, only the header file is required.
2015-09-29 22:07:04 -07:00
//
# define _CRT_SECURE_NO_WARNINGS // Windows shenanigans
# define STRUSE_IMPLEMENTATION // include implementation of struse in this file
2015-10-02 20:57:50 -07:00
# include "struse.h" // https://github.com/Sakrac/struse/blob/master/struse.h
2015-09-29 22:07:04 -07:00
# include <vector>
# include <stdio.h>
# include <stdlib.h>
2016-03-12 11:39:53 -08:00
# include <inttypes.h>
2015-09-29 22:07:04 -07:00
// if the number of resolved labels exceed this in one late eval then skip
// checking for relevance and just eval all unresolved expressions.
# define MAX_LABELS_EVAL_ALL 16
// Max number of nested scopes (within { and })
# define MAX_SCOPE_DEPTH 32
2015-10-01 23:16:36 -07:00
// Max number of nested conditional expressions
# define MAX_CONDITIONAL_DEPTH 64
2015-09-29 22:07:04 -07:00
// The maximum complexity of expressions to be evaluated
# define MAX_EVAL_VALUES 32
# define MAX_EVAL_OPER 64
2015-10-01 23:16:36 -07:00
// Max capacity of each label pool
2016-12-24 13:23:01 -08:00
# define MAX_POOL_BYTES 255
2015-10-01 23:16:36 -07:00
2015-10-18 19:48:03 -07:00
// Max number of exported binary files from a single source
# define MAX_EXPORT_FILES 64
2015-10-24 15:02:12 -07:00
// Maximum number of opcodes, aliases and directives
2015-10-23 22:44:56 -07:00
# define MAX_OPCODES_DIRECTIVES 320
2015-10-24 15:02:12 -07:00
// minor variation of 6502
# define NUM_ILLEGAL_6502_OPS 21
// minor variation of 65C02
# define NUM_WDC_65C02_SPECIFIC_OPS 18
2015-11-01 15:08:38 -08:00
2015-10-10 15:25:08 -07:00
// To simplify some syntax disambiguation the preferred
// ruleset can be specified on the command line.
enum AsmSyntax {
SYNTAX_SANE ,
SYNTAX_MERLIN
} ;
2015-09-29 22:07:04 -07:00
// Internal status and error type
enum StatusCode {
STATUS_OK , // everything is fine
2015-10-10 15:25:08 -07:00
STATUS_RELATIVE_SECTION , // value is relative to a single section
2015-09-29 22:07:04 -07:00
STATUS_NOT_READY , // label could not be evaluated at this time
2015-10-30 22:30:16 -07:00
STATUS_XREF_DEPENDENT , // evaluated but relied on an XREF label to do so
2015-10-04 14:05:38 -07:00
STATUS_NOT_STRUCT , // return is not a struct.
2015-11-08 18:06:45 -08:00
STATUS_EXPORT_NO_CODE_OR_DATA_SECTION ,
2015-10-10 15:25:08 -07:00
FIRST_ERROR ,
ERROR_UNDEFINED_CODE = FIRST_ERROR ,
2015-09-29 22:07:04 -07:00
ERROR_UNEXPECTED_CHARACTER_IN_EXPRESSION ,
ERROR_TOO_MANY_VALUES_IN_EXPRESSION ,
ERROR_TOO_MANY_OPERATORS_IN_EXPRESSION ,
ERROR_UNBALANCED_RIGHT_PARENTHESIS ,
ERROR_EXPRESSION_OPERATION ,
ERROR_EXPRESSION_MISSING_VALUES ,
ERROR_INSTRUCTION_NOT_ZP ,
2015-10-18 12:42:10 -07:00
ERROR_INVALID_ADDRESSING_MODE ,
2015-09-29 22:07:04 -07:00
ERROR_BRANCH_OUT_OF_RANGE ,
ERROR_LABEL_MISPLACED_INTERNAL ,
ERROR_BAD_ADDRESSING_MODE ,
ERROR_UNEXPECTED_CHARACTER_IN_ADDRESSING_MODE ,
ERROR_UNEXPECTED_LABEL_ASSIGMENT_FORMAT ,
ERROR_MODIFYING_CONST_LABEL ,
2015-10-01 23:16:36 -07:00
ERROR_OUT_OF_LABELS_IN_POOL ,
ERROR_INTERNAL_LABEL_POOL_ERROR ,
ERROR_POOL_RANGE_EXPRESSION_EVAL ,
ERROR_LABEL_POOL_REDECLARATION ,
ERROR_POOL_LABEL_ALREADY_DEFINED ,
2015-10-04 14:05:38 -07:00
ERROR_STRUCT_ALREADY_DEFINED ,
ERROR_REFERENCED_STRUCT_NOT_FOUND ,
ERROR_BAD_TYPE_FOR_DECLARE_CONSTANT ,
2015-10-04 16:06:45 -07:00
ERROR_REPT_COUNT_EXPRESSION ,
2015-10-06 22:42:22 -07:00
ERROR_HEX_WITH_ODD_NIBBLE_COUNT ,
ERROR_DS_MUST_EVALUATE_IMMEDIATELY ,
2015-10-13 19:38:13 -07:00
ERROR_NOT_AN_X65_OBJECT_FILE ,
2015-10-20 22:28:53 -07:00
ERROR_COULD_NOT_INCLUDE_FILE ,
2015-10-04 14:05:38 -07:00
2015-09-29 22:07:04 -07:00
ERROR_STOP_PROCESSING_ON_HIGHER , // errors greater than this will stop execution
2015-10-23 22:44:56 -07:00
2015-09-29 22:07:04 -07:00
ERROR_TARGET_ADDRESS_MUST_EVALUATE_IMMEDIATELY ,
ERROR_TOO_DEEP_SCOPE ,
ERROR_UNBALANCED_SCOPE_CLOSURE ,
ERROR_BAD_MACRO_FORMAT ,
ERROR_ALIGN_MUST_EVALUATE_IMMEDIATELY ,
ERROR_OUT_OF_MEMORY_FOR_MACRO_EXPANSION ,
2016-03-17 00:05:36 -07:00
ERROR_MACRO_ARGUMENT ,
2015-10-01 23:16:36 -07:00
ERROR_CONDITION_COULD_NOT_BE_RESOLVED ,
ERROR_ENDIF_WITHOUT_CONDITION ,
ERROR_ELSE_WITHOUT_IF ,
2015-10-04 14:05:38 -07:00
ERROR_STRUCT_CANT_BE_ASSEMBLED ,
2015-10-06 22:42:22 -07:00
ERROR_ENUM_CANT_BE_ASSEMBLED ,
2015-10-04 14:05:38 -07:00
ERROR_UNTERMINATED_CONDITION ,
2015-10-04 16:06:45 -07:00
ERROR_REPT_MISSING_SCOPE ,
2015-10-10 15:25:08 -07:00
ERROR_LINKER_MUST_BE_IN_FIXED_ADDRESS_SECTION ,
ERROR_LINKER_CANT_LINK_TO_DUMMY_SECTION ,
2015-10-11 12:04:49 -07:00
ERROR_UNABLE_TO_PROCESS ,
2015-10-15 20:58:17 -07:00
ERROR_SECTION_TARGET_OFFSET_OUT_OF_RANGE ,
2015-10-18 19:48:03 -07:00
ERROR_CPU_NOT_SUPPORTED ,
ERROR_CANT_APPEND_SECTION_TO_TARGET ,
2015-11-07 18:23:57 -08:00
ERROR_ZEROPAGE_SECTION_OUT_OF_RANGE ,
2015-11-08 18:06:45 -08:00
ERROR_NOT_A_SECTION ,
ERROR_CANT_REASSIGN_FIXED_SECTION ,
ERROR_CANT_LINK_ZP_AND_NON_ZP ,
2015-11-15 21:14:46 -08:00
ERROR_OUT_OF_MEMORY ,
ERROR_CANT_WRITE_TO_FILE ,
ERROR_ABORTED ,
2015-12-01 21:21:00 -08:00
ERROR_CONDITION_TOO_NESTED ,
2015-10-01 23:16:36 -07:00
STATUSCODE_COUNT
2015-09-29 22:07:04 -07:00
} ;
// The following strings are in the same order as StatusCode
2015-10-01 23:16:36 -07:00
const char * aStatusStrings [ STATUSCODE_COUNT ] = {
2015-09-29 22:07:04 -07:00
" ok " ,
2015-10-10 15:25:08 -07:00
" relative section " ,
2015-09-29 22:07:04 -07:00
" not ready " ,
2015-10-30 22:30:16 -07:00
" XREF dependent result " ,
2015-10-04 14:05:38 -07:00
" name is not a struct " ,
2015-11-08 18:06:45 -08:00
" Exporting binary without code or data section " ,
2015-10-10 15:25:08 -07:00
" Undefined code " ,
2015-09-29 22:07:04 -07:00
" Unexpected character in expression " ,
" Too many values in expression " ,
" Too many operators in expression " ,
" Unbalanced right parenthesis in expression " ,
" Expression operation " ,
" Expression missing values " ,
" Instruction can not be zero page " ,
2015-10-18 12:42:10 -07:00
" Invalid addressing mode for instruction " ,
2015-09-29 22:07:04 -07:00
" Branch out of range " ,
" Internal label organization mishap " ,
" Bad addressing mode " ,
" Unexpected character in addressing mode " ,
" Unexpected label assignment format " ,
" Changing value of label that is constant " ,
2015-10-01 23:16:36 -07:00
" Out of labels in pool " ,
" Internal label pool release confusion " ,
" Label pool range evaluation failed " ,
" Label pool was redeclared within its scope " ,
" Pool label already defined " ,
2015-10-04 14:05:38 -07:00
" Struct already defined " ,
" Referenced struct not found " ,
" Declare constant type not recognized (dc.?) " ,
2015-10-04 16:06:45 -07:00
" rept count expression could not be evaluated " ,
2015-10-06 22:42:22 -07:00
" hex must be followed by an even number of hex numbers " ,
" DS directive failed to evaluate immediately " ,
2015-10-13 19:38:13 -07:00
" File is not a valid x65 object file " ,
2015-10-20 22:28:53 -07:00
" Failed to read include file " ,
2015-10-04 16:06:45 -07:00
2015-09-29 22:07:04 -07:00
" Errors after this point will stop execution " ,
2015-10-04 16:06:45 -07:00
2015-09-29 22:07:04 -07:00
" Target address must evaluate immediately for this operation " ,
" Scoping is too deep " ,
" Unbalanced scope closure " ,
" Unexpected macro formatting " ,
" Align must evaluate immediately " ,
" Out of memory for macro expansion " ,
2016-03-17 00:05:36 -07:00
" Problem with macro argument " ,
2015-10-01 23:16:36 -07:00
" Conditional could not be resolved " ,
" #endif encountered outside conditional block " ,
" #else or #elif outside conditional block " ,
2015-10-04 14:05:38 -07:00
" Struct can not be assembled as is " ,
2015-10-06 22:42:22 -07:00
" Enum can not be assembled as is " ,
2015-10-04 14:05:38 -07:00
" Conditional assembly (#if/#ifdef) was not terminated in file or macro " ,
2015-10-04 16:06:45 -07:00
" rept is missing a scope ('{ ... }') " ,
2015-10-10 15:25:08 -07:00
" Link can only be used in a fixed address section " ,
" Link can not be used in dummy sections " ,
2015-10-11 12:04:49 -07:00
" Can not process this line " ,
2015-10-15 20:58:17 -07:00
" Unexpected target offset for reloc or late evaluation " ,
2015-10-18 19:48:03 -07:00
" CPU is not supported " ,
" Can't append sections " ,
2015-11-07 18:23:57 -08:00
" Zero page / Direct page section out of range " ,
2015-11-08 18:06:45 -08:00
" Attempting to assign an address to a non-existent section " ,
" Attempting to assign an address to a fixed address section " ,
" Can not link a zero page section with a non-zp section " ,
2015-11-15 21:14:46 -08:00
" Out of memory while building " ,
" Can not write to file " ,
" Assembly aborted " ,
2015-12-01 21:21:00 -08:00
" Condition too deeply nested " ,
2015-09-29 22:07:04 -07:00
} ;
2015-10-02 20:57:50 -07:00
// Assembler directives
enum AssemblerDirective {
2015-10-18 19:48:03 -07:00
AD_CPU , // CPU: Assemble for this target,
2015-10-02 20:57:50 -07:00
AD_ORG , // ORG: Assemble as if loaded at this address
2015-10-18 19:48:03 -07:00
AD_EXPORT , // EXPORT: export this section or disable export
2015-10-02 20:57:50 -07:00
AD_LOAD , // LOAD: If applicable, instruct to load at this address
2015-10-10 15:25:08 -07:00
AD_SECTION , // SECTION: Enable code that will be assigned a start address during a link step
2017-01-08 16:30:30 -08:00
AD_MERGE , // MERGE: Merge named sections in order listed
2015-10-10 15:25:08 -07:00
AD_LINK , // LINK: Put sections with this name at this address (must be ORG / fixed address section)
2015-10-30 22:30:16 -07:00
AD_XDEF , // XDEF: Externally declare a symbol
AD_XREF , // XREF: Reference an external symbol
2015-10-13 19:38:13 -07:00
AD_INCOBJ , // INCOBJ: Read in an object file saved from a previous build
2015-10-02 20:57:50 -07:00
AD_ALIGN , // ALIGN: Add to address to make it evenly divisible by this
AD_MACRO , // MACRO: Create a macro
AD_EVAL , // EVAL: Print expression to stdout during assemble
AD_BYTES , // BYTES: Add 8 bit values to output
AD_WORDS , // WORDS: Add 16 bit values to output
2015-10-04 14:05:38 -07:00
AD_DC , // DC.B/DC.W: Declare constant (same as BYTES/WORDS)
2015-10-02 20:57:50 -07:00
AD_TEXT , // TEXT: Add text to output
AD_INCLUDE , // INCLUDE: Load and assemble another file at this address
AD_INCBIN , // INCBIN: Load and directly insert another file at this address
2015-10-25 14:29:41 -07:00
AD_IMPORT , // IMPORT: Include or Incbin or Incobj or Incsym
2015-11-26 13:10:58 -08:00
AD_CONST , // CONST: Prevent a label from mutating during assemble
2015-10-02 20:57:50 -07:00
AD_LABEL , // LABEL: Create a mutable label (optional)
2015-11-26 13:10:58 -08:00
AD_STRING , // STRING: Declare a string symbol
AD_UNDEF , // UNDEF: remove a string or a label
2015-10-02 20:57:50 -07:00
AD_INCSYM , // INCSYM: Reference labels from another assemble
AD_LABPOOL , // POOL: Create a pool of addresses to assign as labels dynamically
AD_IF , // #IF: Conditional assembly follows based on expression
AD_IFDEF , // #IFDEF: Conditional assembly follows based on label defined or not
AD_ELSE , // #ELSE: Otherwise assembly
AD_ELIF , // #ELIF: Otherwise conditional assembly follows
AD_ENDIF , // #ENDIF: End a block of #IF/#IFDEF
2015-10-04 14:05:38 -07:00
AD_STRUCT , // STRUCT: Declare a set of labels offset from a base address
2015-10-06 22:42:22 -07:00
AD_ENUM , // ENUM: Declare a set of incremental labels
2015-10-04 16:06:45 -07:00
AD_REPT , // REPT: Repeat the assembly of the bracketed code a number of times
2015-10-05 22:45:42 -07:00
AD_INCDIR , // INCDIR: Add a folder to search for include files
2015-10-23 22:44:56 -07:00
AD_A16 , // A16: Set 16 bit accumulator mode
AD_A8 , // A8: Set 8 bit accumulator mode
AD_XY16 , // A16: Set 16 bit index register mode
AD_XY8 , // A8: Set 8 bit index register mode
2015-10-06 22:42:22 -07:00
AD_HEX , // HEX: LISA assembler data block
2015-11-15 21:14:46 -08:00
AD_ABORT , // ABORT: stop assembler and error
2015-10-06 22:42:22 -07:00
AD_EJECT , // EJECT: Page break for printing assembler code, ignore
AD_LST , // LST: Controls symbol listing
AD_DUMMY , // DUM: Start a dummy section (increment address but don't write anything???)
AD_DUMMY_END , // DEND: End a dummy section
AD_DS , // DS: Define section, zero out # bytes or rewind the address if negative
2015-10-07 22:27:03 -07:00
AD_USR , // USR: MERLIN user defined pseudo op, runs some code at a hard coded address on apple II, on PC does nothing.
2015-10-21 22:34:01 -07:00
AD_SAV , // SAV: MERLIN version of export but contains full filename, not an appendable name
2015-10-23 22:44:56 -07:00
AD_XC , // XC: MERLIN version of setting CPU
AD_MX , // MX: MERLIN control accumulator 16 bit mode
2015-10-26 20:50:26 -07:00
AD_LNK , // LNK: MERLIN load object and link
AD_ADR , // ADR: MERLIN store 3 byte word
AD_ADRL , // ADRL: MERLIN store 4 byte word
AD_ENT , // ENT: MERLIN extern this address label
2015-10-31 14:34:45 -07:00
AD_EXT , // EXT: MERLIN reference this address label from a different file
AD_CYC , // CYC: MERLIN start / stop cycle timer
2015-10-02 20:57:50 -07:00
} ;
2015-09-29 22:07:04 -07:00
// Operators are either instructions or directives
enum OperationType {
OT_NONE ,
OT_MNEMONIC ,
OT_DIRECTIVE
} ;
2015-10-11 12:04:49 -07:00
// These are expression tokens in order of precedence (last is highest precedence)
enum EvalOperator {
EVOP_NONE ,
2015-10-23 22:44:56 -07:00
EVOP_VAL = ' a ' , // a, value => read from value queue
2015-10-25 23:48:35 -07:00
EVOP_EQU , // b, 1 if left equal to right otherwise 0
EVOP_LT , // c, 1 if left less than right otherwise 0
EVOP_GT , // d, 1 if left greater than right otherwise 0
EVOP_LTE , // e, 1 if left less than or equal to right otherwise 0
EVOP_GTE , // f, 1 if left greater than or equal to right otherwise 0
2015-10-26 20:50:26 -07:00
EVOP_LOB , // g, low byte of 16 bit value
EVOP_HIB , // h, high byte of 16 bit value
EVOP_BAB , // i, bank byte of 24 bit value
EVOP_LPR , // j, left parenthesis
EVOP_RPR , // k, right parenthesis
EVOP_ADD , // l, +
EVOP_SUB , // m, -
EVOP_MUL , // n, * (note: if not preceded by value or right paren this is current PC)
EVOP_DIV , // o, /
EVOP_AND , // p, &
EVOP_OR , // q, |
EVOP_EOR , // r, ^
EVOP_SHL , // s, <<
EVOP_SHR , // t, >>
2015-12-02 22:16:31 -08:00
EVOP_NEG , // u, negate value
EVOP_STP , // v, Unexpected input, should stop and evaluate what we have
EVOP_NRY , // w, Not ready yet
EVOP_XRF , // x, value from XREF label
EVOP_EXP , // y, sub expression
EVOP_ERR , // z, Error
2015-10-11 12:04:49 -07:00
} ;
2015-09-29 22:07:04 -07:00
// Opcode encoding
2016-03-12 11:39:53 -08:00
typedef struct sOPLookup {
uint32_t op_hash ;
uint8_t index ; // ground index
2017-08-06 16:07:41 -07:00
uint8_t type ; // mnemonic or
2015-10-23 22:44:56 -07:00
} OPLookup ;
2015-09-29 22:07:04 -07:00
2015-10-18 12:42:10 -07:00
enum AddrMode {
2015-10-21 22:34:01 -07:00
// address mode bit index
2015-10-23 22:44:56 -07:00
// 6502
2015-10-21 22:34:01 -07:00
AMB_ZP_REL_X , // 0 ($12,x)
2015-10-19 22:44:02 -07:00
AMB_ZP , // 1 $12
AMB_IMM , // 2 #$12
AMB_ABS , // 3 $1234
AMB_ZP_Y_REL , // 4 ($12),y
AMB_ZP_X , // 5 $12,x
AMB_ABS_Y , // 6 $1234,y
AMB_ABS_X , // 7 $1234,x
AMB_REL , // 8 ($1234)
AMB_ACC , // 9 A
AMB_NON , // a
2015-10-23 22:44:56 -07:00
// 65C02
2015-10-19 22:44:02 -07:00
AMB_ZP_REL , // b ($12)
AMB_REL_X , // c ($1234,x)
AMB_ZP_ABS , // d $12, *+$12
2015-10-23 22:44:56 -07:00
// 65816
AMB_ZP_REL_L , // e [$02]
AMB_ZP_REL_Y_L , // f [$00],y
AMB_ABS_L , // 10 $bahilo
AMB_ABS_L_X , // 11 $123456,x
AMB_STK , // 12 $12,s
AMB_STK_REL_Y , // 13 ($12,s),y
AMB_REL_L , // 14 [$1234]
AMB_BLK_MOV , // 15 $12,$34
2015-10-18 12:42:10 -07:00
AMB_COUNT ,
2015-10-23 22:44:56 -07:00
AMB_FLIPXY = AMB_COUNT , // 16 (indexing index using y treat as x address mode)
AMB_BRANCH , // 17 (relative address 8 bit)
AMB_BRANCH_L , // 18 (relative address 16 bit)
AMB_IMM_DBL_A , // 19 (immediate mode can be doubled in 16 bit mode)
AMB_IMM_DBL_XY , // 1a (immediate mode can be doubled in 16 bit mode)
AMB_ILL , // 1b illegal address mode
2015-10-21 22:34:01 -07:00
// address mode masks
2015-10-18 12:42:10 -07:00
AMM_NON = 1 < < AMB_NON ,
AMM_IMM = 1 < < AMB_IMM ,
AMM_ABS = 1 < < AMB_ABS ,
AMM_REL = 1 < < AMB_REL ,
AMM_ACC = 1 < < AMB_ACC ,
AMM_ZP = 1 < < AMB_ZP ,
AMM_ABS_X = 1 < < AMB_ABS_X ,
AMM_ABS_Y = 1 < < AMB_ABS_Y ,
AMM_ZP_X = 1 < < AMB_ZP_X ,
AMM_ZP_REL_X = 1 < < AMB_ZP_REL_X ,
AMM_ZP_Y_REL = 1 < < AMB_ZP_Y_REL ,
2015-10-21 22:34:01 -07:00
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
2015-10-23 22:44:56 -07:00
AMM_ZP_REL_L = 1 < < AMB_ZP_REL_L , // e [$02]
AMM_ZP_REL_Y_L = 1 < < AMB_ZP_REL_Y_L , // f [$00],y
AMM_ABS_L = 1 < < AMB_ABS_L , // 10 $bahilo
AMM_ABS_L_X = 1 < < AMB_ABS_L_X , // 11 $123456,x
AMM_STK = 1 < < AMB_STK , // 12 $12,s
AMM_STK_REL_Y = 1 < < AMB_STK_REL_Y , // 13 ($12,s),y
AMM_REL_L = 1 < < AMB_REL_L , // 14 [$1234]
AMM_BLK_MOV = 1 < < AMB_BLK_MOV , // 15 $12,$34
2015-10-18 12:42:10 -07:00
AMM_FLIPXY = 1 < < AMB_FLIPXY ,
AMM_BRANCH = 1 < < AMB_BRANCH ,
2015-10-23 22:44:56 -07:00
AMM_BRANCH_L = 1 < < AMB_BRANCH_L ,
AMM_IMM_DBL_A = 1 < < AMB_IMM_DBL_A ,
AMM_IMM_DBL_XY = 1 < < AMB_IMM_DBL_XY ,
2015-10-18 12:42:10 -07:00
2015-10-21 22:34:01 -07:00
// instruction group specific masks
2015-10-18 12:42:10 -07:00
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_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_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.
2015-10-21 22:34:01 -07:00
AMM_STY = AMM_ZP | AMM_ZP_X | AMM_ABS ,
AMM_LDY = AMM_IMM | AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_X ,
2015-10-18 12:42:10 -07:00
AMM_DEC = AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_X ,
AMM_BIT = AMM_ZP | AMM_ABS ,
AMM_JMP = AMM_ABS | AMM_REL ,
AMM_CPY = AMM_IMM | AMM_ZP | AMM_ABS ,
2015-10-21 22:34:01 -07:00
2015-10-24 15:02:12 -07:00
// 6502 illegal modes
AMM_SLO = AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_Y | AMM_ABS_X | AMM_ZP_REL_X | AMM_ZP_Y_REL ,
AMM_SAX = AMM_FLIPXY | AMM_ZP | AMM_ZP_X | AMM_ZP_REL_X | AMM_ABS ,
2019-09-08 00:27:10 -07:00
AMM_LAX = AMM_FLIPXY | AMM_ZP | AMM_ZP_X | AMM_ZP_REL_X | AMM_ABS | AMM_ABS_X | AMM_ZP_Y_REL ,
2015-10-24 15:02:12 -07:00
AMM_AHX = AMM_FLIPXY | AMM_ZP_REL_X | AMM_ABS_X ,
AMM_SHY = AMM_ABS_X ,
AMM_SHX = AMM_ABS_Y ,
2015-10-21 22:34:01 -07:00
// 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 ,
2015-10-23 22:44:56 -07:00
// 65816 groups
2015-10-26 20:50:26 -07:00
AM8_JSR = AMM_ABS | AMM_ABS_L | AMM_REL_X ,
2015-10-23 22:44:56 -07:00
AM8_JSL = AMM_ABS_L ,
AM8_BIT = AMM_IMM_DBL_A | AMC_BIT ,
AM8_ORA = AMM_IMM_DBL_A | AMC_ORA | AMM_STK | AMM_ZP_REL_L | AMM_ABS_L | AMM_STK_REL_Y | AMM_ZP_REL_Y_L | AMM_ABS_L_X ,
AM8_STA = AMC_STA | AMM_STK | AMM_ZP_REL_L | AMM_ABS_L | AMM_STK_REL_Y | AMM_ZP_REL_Y_L | AMM_ABS_L_X ,
AM8_ORL = AMM_ABS_L | AMM_ABS_L_X ,
AM8_STL = AMM_ABS_L | AMM_ABS_L_X ,
AM8_LDX = AMM_IMM_DBL_XY | AMM_LDX ,
AM8_LDY = AMM_IMM_DBL_XY | AMM_LDY ,
AM8_CPY = AMM_IMM_DBL_XY | AMM_CPY ,
2015-10-26 20:50:26 -07:00
AM8_JMP = AMC_JMP | AMM_REL_L | AMM_ABS_L | AMM_REL_X ,
AM8_JML = AMM_REL_L | AMM_ABS_L ,
2015-10-23 22:44:56 -07:00
AM8_BRL = AMM_BRANCH_L | AMM_ABS ,
AM8_MVN = AMM_BLK_MOV ,
AM8_PEI = AMM_ZP_REL ,
AM8_PER = AMM_BRANCH_L | AMM_ABS ,
AM8_REP = AMM_IMM | AMM_ZP , // Merlin allows this to look like a zp access
2015-10-18 12:42:10 -07:00
} ;
struct mnem {
const char * instr ;
2016-03-12 11:39:53 -08:00
uint32_t modes ;
uint8_t aCodes [ AMB_COUNT ] ;
2015-10-18 12:42:10 -07:00
} ;
2015-09-29 22:07:04 -07:00
2015-10-18 12:42:10 -07:00
struct mnem opcodes_6502 [ ] = {
// nam modes (zp,x) zp # $0000 (zp),y zp,x abs,y abs,x (xx) A empty
{ " brk " , AMM_NON , { 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 } } ,
{ " rti " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x40 } } ,
{ " rts " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x60 } } ,
{ " ora " , AMM_ORA , { 0x01 , 0x05 , 0x09 , 0x0d , 0x11 , 0x15 , 0x19 , 0x1d , 0x00 , 0x00 , 0x00 } } ,
{ " and " , AMM_ORA , { 0x21 , 0x25 , 0x29 , 0x2d , 0x31 , 0x35 , 0x39 , 0x3d , 0x00 , 0x00 , 0x00 } } ,
{ " eor " , AMM_ORA , { 0x41 , 0x45 , 0x49 , 0x4d , 0x51 , 0x55 , 0x59 , 0x5d , 0x00 , 0x00 , 0x00 } } ,
{ " adc " , AMM_ORA , { 0x61 , 0x65 , 0x69 , 0x6d , 0x71 , 0x75 , 0x79 , 0x7d , 0x00 , 0x00 , 0x00 } } ,
{ " sta " , AMM_STA , { 0x81 , 0x85 , 0x00 , 0x8d , 0x91 , 0x95 , 0x99 , 0x9d , 0x00 , 0x00 , 0x00 } } ,
{ " lda " , AMM_ORA , { 0xa1 , 0xa5 , 0xa9 , 0xad , 0xb1 , 0xb5 , 0xb9 , 0xbd , 0x00 , 0x00 , 0x00 } } ,
{ " cmp " , AMM_ORA , { 0xc1 , 0xc5 , 0xc9 , 0xcd , 0xd1 , 0xd5 , 0xd9 , 0xdd , 0x00 , 0x00 , 0x00 } } ,
{ " sbc " , AMM_ORA , { 0xe1 , 0xe5 , 0xe9 , 0xed , 0xf1 , 0xf5 , 0xf9 , 0xfd , 0x00 , 0x00 , 0x00 } } ,
{ " asl " , AMM_ASL , { 0x00 , 0x06 , 0x00 , 0x0e , 0x00 , 0x16 , 0x00 , 0x1e , 0x00 , 0x0a , 0x0a } } ,
{ " rol " , AMM_ASL , { 0x00 , 0x26 , 0x00 , 0x2e , 0x00 , 0x36 , 0x00 , 0x3e , 0x00 , 0x2a , 0x2a } } ,
{ " lsr " , AMM_ASL , { 0x00 , 0x46 , 0x00 , 0x4e , 0x00 , 0x56 , 0x00 , 0x5e , 0x00 , 0x4a , 0x4a } } ,
{ " ror " , AMM_ASL , { 0x00 , 0x66 , 0x00 , 0x6e , 0x00 , 0x76 , 0x00 , 0x7e , 0x00 , 0x6a , 0x6a } } ,
{ " stx " , AMM_STX , { 0x00 , 0x86 , 0x00 , 0x8e , 0x00 , 0x96 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " ldx " , AMM_LDX , { 0x00 , 0xa6 , 0xa2 , 0xae , 0x00 , 0xb6 , 0x00 , 0xbe , 0x00 , 0x00 , 0x00 } } ,
{ " dec " , AMM_DEC , { 0x00 , 0xc6 , 0x00 , 0xce , 0x00 , 0xd6 , 0x00 , 0xde , 0x00 , 0x00 , 0x00 } } ,
{ " inc " , AMM_DEC , { 0x00 , 0xe6 , 0x00 , 0xee , 0x00 , 0xf6 , 0x00 , 0xfe , 0x00 , 0x00 , 0x00 } } ,
{ " php " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x08 } } ,
{ " plp " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x28 } } ,
{ " pha " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x48 } } ,
{ " pla " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x68 } } ,
{ " dey " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x88 } } ,
{ " tay " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xa8 } } ,
{ " iny " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xc8 } } ,
{ " inx " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xe8 } } ,
// nam modes (zp,x) zp # $0000 (zp),y zp,x abs,y abs,x (xx) A empty
{ " bpl " , AMM_BRA , { 0x00 , 0x00 , 0x00 , 0x10 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " bmi " , AMM_BRA , { 0x00 , 0x00 , 0x00 , 0x30 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " bvc " , AMM_BRA , { 0x00 , 0x00 , 0x00 , 0x50 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " bvs " , AMM_BRA , { 0x00 , 0x00 , 0x00 , 0x70 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " bcc " , AMM_BRA , { 0x00 , 0x00 , 0x00 , 0x90 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " bcs " , AMM_BRA , { 0x00 , 0x00 , 0x00 , 0xb0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " bne " , AMM_BRA , { 0x00 , 0x00 , 0x00 , 0xd0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " beq " , AMM_BRA , { 0x00 , 0x00 , 0x00 , 0xf0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " clc " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x18 } } ,
{ " sec " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x38 } } ,
{ " cli " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x58 } } ,
{ " sei " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x78 } } ,
{ " tya " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x98 } } ,
{ " clv " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xb8 } } ,
{ " cld " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xd8 } } ,
{ " sed " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xf8 } } ,
{ " bit " , AMM_BIT , { 0x00 , 0x24 , 0x00 , 0x2c , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " jmp " , AMM_JMP , { 0x00 , 0x00 , 0x00 , 0x4c , 0x00 , 0x00 , 0x00 , 0x00 , 0x6c , 0x00 , 0x00 } } ,
{ " sty " , AMM_STY , { 0x00 , 0x84 , 0x00 , 0x8c , 0x00 , 0x94 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " ldy " , AMM_LDY , { 0x00 , 0xa4 , 0xa0 , 0xac , 0x00 , 0xb4 , 0x00 , 0xbc , 0x00 , 0x00 , 0x00 } } ,
{ " cpy " , AMM_CPY , { 0x00 , 0xc4 , 0xc0 , 0xcc , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " cpx " , AMM_CPY , { 0x00 , 0xe4 , 0xe0 , 0xec , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " txa " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x8a } } ,
{ " txs " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x9a } } ,
{ " tax " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xaa } } ,
{ " tsx " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xba } } ,
{ " dex " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xca } } ,
2015-10-24 15:02:12 -07:00
{ " nop " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xea } } ,
// 21 ILLEGAL 6502 OPCODES (http://www.oxyron.de/html/opcodes02.html)
// NOTE: If adding or removing, update NUM_ILLEGAL_6502_OPS
// nam modes (zp,x) zp # $0000 (zp),y zp,x abs,y abs,x (xx) A empty
{ " slo " , AMM_SLO , { 0x03 , 0x07 , 0x00 , 0x0f , 0x13 , 0x17 , 0x1b , 0x1f , 0x00 , 0x00 , 0x00 } } ,
{ " rla " , AMM_SLO , { 0x23 , 0x27 , 0x00 , 0x2f , 0x33 , 0x37 , 0x3b , 0x3f , 0x00 , 0x00 , 0x00 } } ,
{ " sre " , AMM_SLO , { 0x43 , 0x47 , 0x00 , 0x4f , 0x53 , 0x57 , 0x5b , 0x5f , 0x00 , 0x00 , 0x00 } } ,
{ " rra " , AMM_SLO , { 0x63 , 0x67 , 0x00 , 0x6f , 0x73 , 0x77 , 0x7b , 0x7f , 0x00 , 0x00 , 0x00 } } ,
{ " sax " , AMM_SAX , { 0x83 , 0x87 , 0x00 , 0x8f , 0x00 , 0x97 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " lax " , AMM_LAX , { 0xa3 , 0xa7 , 0x00 , 0xaf , 0xb3 , 0xb7 , 0x00 , 0xbf , 0x00 , 0x00 , 0x00 } } ,
{ " dcp " , AMM_SLO , { 0xc3 , 0xc7 , 0x00 , 0xcf , 0xd3 , 0xd7 , 0xdb , 0xdf , 0x00 , 0x00 , 0x00 } } ,
{ " isc " , AMM_SLO , { 0xe3 , 0xe7 , 0x00 , 0xef , 0xf3 , 0xf7 , 0xfb , 0xff , 0x00 , 0x00 , 0x00 } } ,
{ " anc " , AMM_IMM , { 0x00 , 0x00 , 0x0b , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " aac " , AMM_IMM , { 0x00 , 0x00 , 0x2b , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " alr " , AMM_IMM , { 0x00 , 0x00 , 0x4b , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " arr " , AMM_IMM , { 0x00 , 0x00 , 0x6b , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " xaa " , AMM_IMM , { 0x00 , 0x00 , 0x8b , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " lax2 " , AMM_IMM , { 0x00 , 0x00 , 0xab , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " axs " , AMM_IMM , { 0x00 , 0x00 , 0xcb , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " sbi " , AMM_IMM , { 0x00 , 0x00 , 0xeb , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " ahx " , AMM_AHX , { 0x93 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x9f , 0x00 , 0x00 , 0x00 } } ,
{ " shy " , AMM_SHY , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x9c , 0x00 , 0x00 , 0x00 } } ,
{ " shx " , AMM_SHX , { 0x00 , 0x00 , 0x00 , 0x00 , 0x93 , 0x00 , 0x9e , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " tas " , AMM_SHX , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x9b , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " las " , AMM_SHX , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xbb , 0x00 , 0x00 , 0x00 , 0x00 } } ,
2015-09-29 22:07:04 -07:00
} ;
2015-10-24 13:41:11 -07:00
const char * aliases_6502 [ ] = {
2015-10-23 22:44:56 -07:00
" bcc " , " blt " ,
2015-10-24 13:41:11 -07:00
" bcs " , " bge " ,
2015-10-23 22:44:56 -07:00
nullptr , nullptr
} ;
2016-03-12 11:39:53 -08:00
uint8_t timing_6502 [ ] = {
2015-10-30 22:30:16 -07:00
0x0e , 0x0c , 0xff , 0xff , 0xff , 0x06 , 0x0a , 0xff , 0x06 , 0x04 , 0x04 , 0xff , 0xff , 0x08 , 0x0c , 0xff , 0x05 , 0x0b , 0xff , 0xff , 0xff , 0x08 , 0x0c , 0xff , 0x04 , 0x09 , 0xff , 0xff , 0xff , 0x09 , 0x0e , 0xff ,
0x0c , 0x0c , 0xff , 0xff , 0x06 , 0x06 , 0x0a , 0xff , 0x08 , 0x04 , 0x04 , 0xff , 0x08 , 0x08 , 0x0c , 0xff , 0x05 , 0x0b , 0xff , 0xff , 0xff , 0x08 , 0x0c , 0xff , 0x04 , 0x09 , 0xff , 0xff , 0xff , 0x09 , 0x0e , 0xff ,
0x0c , 0x0c , 0xff , 0xff , 0xff , 0x06 , 0x0a , 0xff , 0x06 , 0x04 , 0x04 , 0xff , 0x06 , 0x08 , 0x0c , 0xff , 0x05 , 0x0b , 0xff , 0xff , 0xff , 0x08 , 0x0c , 0xff , 0x04 , 0x09 , 0xff , 0xff , 0xff , 0x09 , 0x0e , 0xff ,
0x0c , 0x0c , 0xff , 0xff , 0xff , 0x06 , 0x0a , 0xff , 0x08 , 0x04 , 0x04 , 0xff , 0x0a , 0x08 , 0x0c , 0xff , 0x05 , 0x0b , 0xff , 0xff , 0xff , 0x08 , 0x0c , 0xff , 0x04 , 0x09 , 0xff , 0xff , 0xff , 0x09 , 0x0e , 0xff ,
0xff , 0x0c , 0xff , 0xff , 0x06 , 0x06 , 0x06 , 0xff , 0x04 , 0xff , 0x04 , 0xff , 0x08 , 0x08 , 0x08 , 0xff , 0x05 , 0x0c , 0xff , 0xff , 0x08 , 0x08 , 0x08 , 0xff , 0x04 , 0x0a , 0x04 , 0xff , 0xff , 0x0a , 0xff , 0xff ,
0x04 , 0x0c , 0x04 , 0xff , 0x06 , 0x06 , 0x06 , 0xff , 0x04 , 0x04 , 0x04 , 0xff , 0x08 , 0x08 , 0x08 , 0xff , 0x05 , 0x0b , 0xff , 0xff , 0x08 , 0x08 , 0x08 , 0xff , 0x04 , 0x09 , 0x04 , 0xff , 0x09 , 0x09 , 0x09 , 0xff ,
0x04 , 0x0c , 0xff , 0xff , 0x06 , 0x06 , 0x0a , 0xff , 0x04 , 0x04 , 0x04 , 0xff , 0x08 , 0x08 , 0x0c , 0xff , 0x05 , 0x0b , 0xff , 0xff , 0xff , 0x08 , 0x0c , 0xff , 0x04 , 0x09 , 0xff , 0xff , 0xff , 0x09 , 0x0e , 0xff ,
0x04 , 0x0c , 0xff , 0xff , 0x06 , 0x06 , 0x0a , 0xff , 0x04 , 0x04 , 0x04 , 0xff , 0x08 , 0x08 , 0x0c , 0xff , 0x05 , 0x0b , 0xff , 0xff , 0xff , 0x08 , 0x0c , 0xff , 0x04 , 0x09 , 0xff , 0xff , 0xff , 0x09 , 0x0e , 0xff
} ;
2015-10-18 12:42:10 -07:00
static const int num_opcodes_6502 = sizeof ( opcodes_6502 ) / sizeof ( opcodes_6502 [ 0 ] ) ;
2015-10-21 22:34:01 -07:00
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 } } ,
2015-10-23 22:44:56 -07:00
{ " dea " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xde , 0x00 , 0x00 , 0x3a , 0x00 , 0x00 , 0x00 } } ,
{ " ina " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xfe , 0x00 , 0x00 , 0x1a , 0x00 , 0x00 , 0x00 } } ,
2015-10-21 22:34:01 -07:00
{ " 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 } } ,
2015-10-23 22:44:56 -07:00
// WDC specific (18 instructions)
2015-10-21 22:34:01 -07:00
// nam modes (zp,x) zp # $0000 (zp),y zp,x abs,y abs,x (xx) A empty (zp)(abs,x)zp,abs
{ " 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 } } ,
2015-10-23 22:44:56 -07:00
{ " 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 } } ,
} ;
2015-10-24 13:41:11 -07:00
const char * aliases_65C02 [ ] = {
2015-10-23 22:44:56 -07:00
" bcc " , " blt " ,
2015-10-24 13:41:11 -07:00
" bcs " , " bge " ,
2015-10-23 22:44:56 -07:00
nullptr , nullptr
2015-10-21 22:34:01 -07:00
} ;
static const int num_opcodes_65C02 = sizeof ( opcodes_65C02 ) / sizeof ( opcodes_65C02 [ 0 ] ) ;
2015-10-23 22:44:56 -07:00
struct mnem opcodes_65816 [ ] = {
// nam modes (zp,x) zp # $0000 (zp),y zp,x abs,y abs,x (xx) A empty (zp)(abs,x)zp,abs [zp] [zp],y absl absl,x b,s (b,s),y[$000] b,b
{ " brk " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
2015-10-26 20:50:26 -07:00
{ " jsr " , AM8_JSR , { 0x00 , 0x00 , 0x00 , 0x20 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xfc , 0x00 , 0x00 , 0x00 , 0x22 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
2015-10-23 22:44:56 -07:00
{ " jsl " , AM8_JSL , { 0x00 , 0x00 , 0x00 , 0x20 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x22 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " rti " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x40 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " rts " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x60 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
2015-11-27 18:01:53 -08:00
{ " rtl " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x6b , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
2015-10-23 22:44:56 -07:00
{ " ora " , AM8_ORA , { 0x01 , 0x05 , 0x09 , 0x0d , 0x11 , 0x15 , 0x19 , 0x1d , 0x00 , 0x00 , 0x00 , 0x12 , 0x00 , 0x00 , 0x07 , 0x17 , 0x0f , 0x1f , 0x03 , 0x13 , 0x00 , 0x00 } } ,
{ " and " , AM8_ORA , { 0x21 , 0x25 , 0x29 , 0x2d , 0x31 , 0x35 , 0x39 , 0x3d , 0x00 , 0x00 , 0x00 , 0x32 , 0x00 , 0x00 , 0x27 , 0x37 , 0x2f , 0x3f , 0x23 , 0x33 , 0x00 , 0x00 } } ,
{ " eor " , AM8_ORA , { 0x41 , 0x45 , 0x49 , 0x4d , 0x51 , 0x55 , 0x59 , 0x5d , 0x00 , 0x00 , 0x00 , 0x52 , 0x00 , 0x00 , 0x47 , 0x57 , 0x4f , 0x5f , 0x43 , 0x53 , 0x00 , 0x00 } } ,
{ " adc " , AM8_ORA , { 0x61 , 0x65 , 0x69 , 0x6d , 0x71 , 0x75 , 0x79 , 0x7d , 0x00 , 0x00 , 0x00 , 0x72 , 0x00 , 0x00 , 0x67 , 0x77 , 0x6f , 0x7f , 0x63 , 0x73 , 0x00 , 0x00 } } ,
{ " sta " , AM8_STA , { 0x81 , 0x85 , 0x00 , 0x8d , 0x91 , 0x95 , 0x99 , 0x9d , 0x00 , 0x00 , 0x00 , 0x92 , 0x00 , 0x00 , 0x87 , 0x97 , 0x8f , 0x9f , 0x83 , 0x93 , 0x00 , 0x00 } } ,
{ " lda " , AM8_ORA , { 0xa1 , 0xa5 , 0xa9 , 0xad , 0xb1 , 0xb5 , 0xb9 , 0xbd , 0x00 , 0x00 , 0x00 , 0xb2 , 0x00 , 0x00 , 0xa7 , 0xb7 , 0xaf , 0xbf , 0xa3 , 0xb3 , 0x00 , 0x00 } } ,
{ " cmp " , AM8_ORA , { 0xc1 , 0xc5 , 0xc9 , 0xcd , 0xd1 , 0xd5 , 0xd9 , 0xdd , 0x00 , 0x00 , 0x00 , 0xd2 , 0x00 , 0x00 , 0xc7 , 0xd7 , 0xcf , 0xdf , 0xc3 , 0xd3 , 0x00 , 0x00 } } ,
{ " sbc " , AM8_ORA , { 0xe1 , 0xe5 , 0xe9 , 0xed , 0xf1 , 0xf5 , 0xf9 , 0xfd , 0x00 , 0x00 , 0x00 , 0xf2 , 0x00 , 0x00 , 0xe7 , 0xf7 , 0xef , 0xff , 0xe3 , 0xf3 , 0x00 , 0x00 } } ,
{ " oral " , AM8_ORL , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x0f , 0x1f , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " andl " , AM8_ORL , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x2f , 0x3f , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " eorl " , AM8_ORL , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x4f , 0x5f , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " adcl " , AM8_ORL , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x6f , 0x7f , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " stal " , AM8_STL , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x8f , 0x9f , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " ldal " , AM8_ORL , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xaf , 0xbf , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " cmpl " , AM8_ORL , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xcf , 0xdf , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " sbcl " , AM8_ORL , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xef , 0xff , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " asl " , AMM_ASL , { 0x00 , 0x06 , 0x00 , 0x0e , 0x00 , 0x16 , 0x00 , 0x1e , 0x00 , 0x0a , 0x0a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " rol " , AMM_ASL , { 0x00 , 0x26 , 0x00 , 0x2e , 0x00 , 0x36 , 0x00 , 0x3e , 0x00 , 0x2a , 0x2a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " lsr " , AMM_ASL , { 0x00 , 0x46 , 0x00 , 0x4e , 0x00 , 0x56 , 0x00 , 0x5e , 0x00 , 0x4a , 0x4a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " ror " , AMM_ASL , { 0x00 , 0x66 , 0x00 , 0x6e , 0x00 , 0x76 , 0x00 , 0x7e , 0x00 , 0x6a , 0x6a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " stx " , AMM_STX , { 0x00 , 0x86 , 0x00 , 0x8e , 0x00 , 0x96 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " ldx " , AM8_LDX , { 0x00 , 0xa6 , 0xa2 , 0xae , 0x00 , 0xb6 , 0x00 , 0xbe , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " dec " , AMC_DEC , { 0x00 , 0xc6 , 0x00 , 0xce , 0x00 , 0xd6 , 0x00 , 0xde , 0x00 , 0x3a , 0x3a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " inc " , AMC_DEC , { 0x00 , 0xe6 , 0x00 , 0xee , 0x00 , 0xf6 , 0x00 , 0xfe , 0x00 , 0x1a , 0x1a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " dea " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xde , 0x00 , 0x00 , 0x3a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " ina " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xfe , 0x00 , 0x00 , 0x1a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " php " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x08 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " plp " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x28 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " pha " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x48 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 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 [zp] [zp],y absl absl,x b,s (b,s),y[$0000]b,b
{ " pla " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x68 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " phy " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x5a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " ply " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x7a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " phx " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xda , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " plx " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xfa , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " dey " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x88 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " tay " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xa8 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " iny " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xc8 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " inx " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xe8 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " bpl " , AMM_BRA , { 0x00 , 0x00 , 0x00 , 0x10 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 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 , 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 , 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 , 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 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " brl " , AM8_BRL , { 0x00 , 0x00 , 0x00 , 0x82 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 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 , 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 , 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 , 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 , 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 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " sec " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x38 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " cli " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x58 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " sei " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x78 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " tya " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x98 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " clv " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xb8 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " cld " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xd8 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " sed " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xf8 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " bit " , AM8_BIT , { 0x00 , 0x24 , 0x89 , 0x2c , 0x00 , 0x34 , 0x00 , 0x3c , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " stz " , AMC_STZ , { 0x00 , 0x64 , 0x00 , 0x9c , 0x00 , 0x74 , 0x00 , 0x9e , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " trb " , AMC_TRB , { 0x00 , 0x14 , 0x00 , 0x1c , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 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 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 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 [zp] [zp],y absl absl,x b,s (b,s),y[$0000]b,b
2015-10-26 20:50:26 -07:00
{ " jmp " , AM8_JMP , { 0x00 , 0x00 , 0x00 , 0x4c , 0x00 , 0x00 , 0x00 , 0x00 , 0x6c , 0x00 , 0x00 , 0x00 , 0x7c , 0x00 , 0x00 , 0x00 , 0x5c , 0x00 , 0x00 , 0x00 , 0xdc , 0x00 } } ,
{ " jml " , AM8_JML , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x5c , 0x00 , 0x00 , 0x00 , 0xdc , 0x00 } } ,
2015-10-23 22:44:56 -07:00
{ " sty " , AMM_STY , { 0x00 , 0x84 , 0x00 , 0x8c , 0x00 , 0x94 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " ldy " , AM8_LDY , { 0x00 , 0xa4 , 0xa0 , 0xac , 0x00 , 0xb4 , 0x00 , 0xbc , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " cpy " , AM8_CPY , { 0x00 , 0xc4 , 0xc0 , 0xcc , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " cpx " , AM8_CPY , { 0x00 , 0xe4 , 0xe0 , 0xec , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 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 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " txs " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x9a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " tax " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xaa , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " tsx " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xba , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " dex " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xca , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " nop " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xea , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " cop " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " wdm " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x42 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " mvp " , AM8_MVN , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x44 } } ,
{ " mvn " , AM8_MVN , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x54 } } ,
{ " pea " , AMM_ABS , { 0x00 , 0x00 , 0x00 , 0xf4 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " pei " , AM8_PEI , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xd4 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " per " , AM8_PER , { 0x00 , 0x00 , 0x00 , 0x62 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " rep " , AM8_REP , { 0x00 , 0xc2 , 0xc2 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " sep " , AM8_REP , { 0x00 , 0xe2 , 0xe2 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " phd " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x0B , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " tcs " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x1B , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " pld " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x2B , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " tsc " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x3B , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " phk " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x4B , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " tcd " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x5B , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " tdc " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x7B , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " phb " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x8B , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " txy " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x9B , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " plb " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xAB , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " tyx " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xBB , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " wai " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xcb , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " stp " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xdb , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " xba " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xeB , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ " xce " , AMM_NON , { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xfB , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
} ;
2015-10-24 13:41:11 -07:00
const char * aliases_65816 [ ] = {
2015-10-23 22:44:56 -07:00
" bcc " , " blt " ,
2015-10-24 13:41:11 -07:00
" bcs " , " bge " ,
2015-10-23 22:44:56 -07:00
" tcs " , " tas " ,
" tsc " , " tsa " ,
" xba " , " swa " ,
" tcd " , " tad " ,
" tdc " , " tda " ,
nullptr , nullptr
} ;
static const int num_opcodes_65816 = sizeof ( opcodes_65816 ) / sizeof ( opcodes_65816 [ 0 ] ) ;
2016-03-12 11:39:53 -08:00
uint8_t timing_65816 [ ] = {
2015-11-01 15:08:38 -08:00
0x4e , 0x1c , 0x4e , 0x28 , 0x3a , 0x26 , 0x3a , 0x1c , 0x46 , 0x24 , 0x44 , 0x48 , 0x4c , 0x28 , 0x5c , 0x2a ,
0x44 , 0x1a , 0x1a , 0x2e , 0x3a , 0x18 , 0x6c , 0x1c , 0x44 , 0x28 , 0x44 , 0x44 , 0x4c , 0x28 , 0x5e , 0x2a ,
0x4c , 0x1c , 0x50 , 0x28 , 0x16 , 0x26 , 0x3a , 0x1c , 0x48 , 0x24 , 0x44 , 0x4a , 0x28 , 0x28 , 0x4c , 0x2a ,
0x44 , 0x1a , 0x1a , 0x2e , 0x18 , 0x18 , 0x3c , 0x1c , 0x44 , 0x28 , 0x44 , 0x44 , 0x28 , 0x28 , 0x4e , 0x2a ,
0x4c , 0x1c , 0x42 , 0x28 , 0x42 , 0x16 , 0x6a , 0x1c , 0x26 , 0x24 , 0x44 , 0x46 , 0x46 , 0x28 , 0x5c , 0x2a ,
0x44 , 0x1a , 0x1a , 0x2e , 0x42 , 0x18 , 0x6c , 0x1c , 0x44 , 0x28 , 0x76 , 0x44 , 0x48 , 0x28 , 0x5e , 0x2a ,
0x4c , 0x1c , 0x4c , 0x28 , 0x16 , 0x26 , 0x3a , 0x1c , 0x28 , 0x24 , 0x44 , 0x4c , 0x4a , 0x28 , 0x4c , 0x2a ,
0x44 , 0x1a , 0x1a , 0x2e , 0x28 , 0x18 , 0x3c , 0x1c , 0x44 , 0x28 , 0x78 , 0x44 , 0x4c , 0x28 , 0x4e , 0x2a ,
0x46 , 0x1c , 0x48 , 0x28 , 0x86 , 0x16 , 0x86 , 0x1c , 0x44 , 0x24 , 0x44 , 0x46 , 0x78 , 0x28 , 0x78 , 0x2a ,
0x44 , 0x1c , 0x1a , 0x2e , 0x88 , 0x18 , 0x88 , 0x1c , 0x44 , 0x2a , 0x44 , 0x44 , 0x28 , 0x2a , 0x2a , 0x2a ,
0x74 , 0x1c , 0x74 , 0x28 , 0x86 , 0x16 , 0x86 , 0x1c , 0x44 , 0x24 , 0x44 , 0x48 , 0x78 , 0x28 , 0x78 , 0x2a ,
0x44 , 0x1a , 0x1a , 0x2e , 0x88 , 0x18 , 0x88 , 0x1c , 0x44 , 0x28 , 0x44 , 0x44 , 0x78 , 0x28 , 0x78 , 0x2a ,
0x74 , 0x1c , 0x46 , 0x28 , 0x86 , 0x16 , 0x6a , 0x1c , 0x44 , 0x24 , 0x44 , 0x26 , 0x78 , 0x28 , 0x5c , 0x2a ,
0x44 , 0x1a , 0x1a , 0x2e , 0x4c , 0x18 , 0x6c , 0x1c , 0x44 , 0x28 , 0x76 , 0x46 , 0x4c , 0x28 , 0x5e , 0x2a ,
0x74 , 0x3c , 0x46 , 0x48 , 0x86 , 0x36 , 0x6a , 0x3c , 0x44 , 0x44 , 0x44 , 0x46 , 0x78 , 0x48 , 0x5c , 0x4a ,
0x44 , 0x3a , 0x3a , 0x4e , 0x4a , 0x38 , 0x6c , 0x3c , 0x44 , 0x48 , 0x78 , 0x44 , 0x50 , 0x48 , 0x5e , 0x4a
} ;
// m=0, i=0, dp!=0
2016-03-12 11:39:53 -08:00
uint8_t timing_65816_plus [ 9 ] [ 3 ] = {
2015-11-01 15:08:38 -08:00
{ 0 , 0 , 0 } , // 6502 plus timing check bit 0
{ 1 , 0 , 1 } , // acc 16 bit + dp!=0
{ 1 , 0 , 0 } , // acc 16 bit
{ 0 , 0 , 1 } , // dp != 0
{ 0 , 0 , 0 } , // no plus
{ 2 , 0 , 0 } , // acc 16 bit yields 2+
{ 2 , 0 , 1 } , // acc 16 bit yields 2+ + dp!=0
{ 0 , 1 , 0 } , // idx 16 bit
{ 0 , 1 , 1 } // idx 16 bit + dp!=0
} ;
2015-10-21 22:34:01 -07:00
2015-10-19 22:44:02 -07:00
// 65C02
// http://6502.org/tutorials/65c02opcodes.html
// http://www.oxyron.de/html/opcodesc02.html
// 65816
2015-10-23 22:44:56 -07:00
// http://wiki.superfamicom.org/snes/show/65816+Reference#fn:14
2015-10-19 22:44:02 -07:00
// http://softpixel.com/~cwright/sianse/docs/65816NFO.HTM
2015-10-23 22:44:56 -07:00
// http://www.oxyron.de/html/opcodes816.html
2015-10-19 22:44:02 -07:00
2015-09-29 22:07:04 -07:00
// How instruction argument is encoded
enum CODE_ARG {
CA_NONE , // single byte instruction
CA_ONE_BYTE , // instruction carries one byte
CA_TWO_BYTES , // instruction carries two bytes
2015-10-23 22:44:56 -07:00
CA_THREE_BYTES , // instruction carries three bytes
CA_BRANCH , // instruction carries an 8 bit relative address
CA_BRANCH_16 , // instruction carries a 16 bit relative address
CA_BYTE_BRANCH , // instruction carries one byte and one branch
CA_TWO_ARG_BYTES , // two separate values
} ;
enum CPUIndex {
CPU_6502 ,
2015-10-26 20:50:26 -07:00
CPU_6502_ILLEGAL ,
2015-10-23 22:44:56 -07:00
CPU_65C02 ,
CPU_65C02_WDC ,
CPU_65816
} ;
// CPU by index
struct CPUDetails {
mnem * opcodes ;
int num_opcodes ;
2015-10-24 13:41:11 -07:00
const char * name ;
const char * * aliases ;
2016-03-12 11:39:53 -08:00
const uint8_t * timing ;
2015-10-23 22:44:56 -07:00
} aCPUs [ ] = {
2015-10-30 22:30:16 -07:00
{ opcodes_6502 , num_opcodes_6502 - NUM_ILLEGAL_6502_OPS , " 6502 " , aliases_6502 , timing_6502 } ,
{ opcodes_6502 , num_opcodes_6502 , " 6502ill " , aliases_6502 , timing_6502 } ,
{ opcodes_65C02 , num_opcodes_65C02 - NUM_WDC_65C02_SPECIFIC_OPS , " 65C02 " , aliases_65C02 , nullptr } ,
{ opcodes_65C02 , num_opcodes_65C02 , " 65C02WDC " , aliases_65C02 , nullptr } ,
2015-11-01 15:08:38 -08:00
{ opcodes_65816 , num_opcodes_65816 , " 65816 " , aliases_65816 , timing_65816 } ,
2015-09-29 22:07:04 -07:00
} ;
2015-10-23 22:44:56 -07:00
static const int nCPUs = sizeof ( aCPUs ) / sizeof ( aCPUs [ 0 ] ) ;
2015-10-01 23:16:36 -07:00
// hardtexted strings
2015-09-29 22:07:04 -07:00
static const strref c_comment ( " // " ) ;
2015-10-01 23:16:36 -07:00
static const strref word_char_range ( " !0-9a-zA-Z_@$!# " ) ;
2015-10-11 12:04:49 -07:00
static const strref label_end_char_range ( " !0-9a-zA-Z_@$!. " ) ;
2015-10-19 22:44:02 -07:00
static const strref label_end_char_range_merlin ( " !0-9a-zA-Z_@$]:? " ) ;
2015-10-13 19:38:13 -07:00
static const strref filename_end_char_range ( " !0-9a-zA-Z_!@#$%&() / \ \ - . " ) ;
2015-09-29 22:07:04 -07:00
static const strref keyword_equ ( " equ " ) ;
2015-10-01 23:16:36 -07:00
static const strref str_label ( " label " ) ;
static const strref str_const ( " const " ) ;
2015-10-04 14:05:38 -07:00
static const strref struct_byte ( " byte " ) ;
static const strref struct_word ( " word " ) ;
2015-10-25 14:29:41 -07:00
static const strref import_source ( " source " ) ;
static const strref import_binary ( " binary " ) ;
static const strref import_c64 ( " c64 " ) ;
static const strref import_text ( " text " ) ;
static const strref import_object ( " object " ) ;
static const strref import_symbols ( " symbols " ) ;
2016-12-24 13:23:01 -08:00
static const strref pool_subpool ( " pool " ) ;
2015-10-18 12:42:10 -07:00
static const char * aAddrModeFmt [ ] = {
2015-10-23 22:44:56 -07:00
" %s ($%02x,x) " , // 00
" %s $%02x " , // 01
" %s #$%02x " , // 02
" %s $%04x " , // 03
" %s ($%02x),y " , // 04
" %s $%02x,x " , // 05
" %s $%04x,y " , // 06
" %s $%04x,x " , // 07
" %s ($%04x) " , // 08
" %s A " , // 09
" %s " , // 0a
" %s ($%02x) " , // 0b
" %s ($%04x,x) " , // 0c
" %s $%02x, $%04x " , // 0d
" %s [$%02x] " , // 0e
" %s [$%02x],y " , // 0f
" %s $%06x " , // 10
" %s $%06x,x " , // 11
" %s $%02x,s " , // 12
" %s ($%02x,s),y " , // 13
" %s [$%04x] " , // 14
" %s $%02x,$%02x " , // 15
} ;
2015-11-08 18:06:45 -08:00
static const char * str_section_type [ ] = {
" UNDEFINED " , // not set
" CODE " , // default type
" DATA " , // data section (matters for GS/OS OMF)
" BSS " , // uninitialized data section
" ZEROPAGE " // ununitialized data section in zero page / direct page
} ;
static const int num_section_type_str = sizeof ( str_section_type ) / sizeof ( str_section_type [ 0 ] ) ;
2015-10-23 22:44:56 -07:00
2016-03-12 11:39:53 -08:00
typedef struct sDirectiveName {
2015-10-23 22:44:56 -07:00
const char * name ;
AssemblerDirective directive ;
} DirectiveName ;
DirectiveName aDirectiveNames [ ] {
{ " CPU " , AD_CPU } ,
{ " PROCESSOR " , AD_CPU } ,
{ " PC " , AD_ORG } ,
{ " ORG " , AD_ORG } ,
{ " LOAD " , AD_LOAD } ,
{ " EXPORT " , AD_EXPORT } ,
{ " SECTION " , AD_SECTION } ,
{ " SEG " , AD_SECTION } , // DASM version of SECTION
2015-11-05 21:23:38 -08:00
{ " SEGMENT " , AD_SECTION } , // CA65 version of SECTION
2017-01-08 16:30:30 -08:00
{ " MERGE " , AD_MERGE } ,
2015-10-23 22:44:56 -07:00
{ " LINK " , AD_LINK } ,
{ " XDEF " , AD_XDEF } ,
2015-10-30 22:30:16 -07:00
{ " XREF " , AD_XREF } ,
2015-10-23 22:44:56 -07:00
{ " INCOBJ " , AD_INCOBJ } ,
{ " ALIGN " , AD_ALIGN } ,
{ " MACRO " , AD_MACRO } ,
2015-11-23 22:34:30 -08:00
{ " MAC " , AD_MACRO } , // MERLIN
2015-10-23 22:44:56 -07:00
{ " EVAL " , AD_EVAL } ,
{ " PRINT " , AD_EVAL } ,
2015-11-08 18:06:45 -08:00
{ " ECHO " , AD_EVAL } , // DASM version of EVAL/PRINT
2015-10-23 22:44:56 -07:00
{ " BYTE " , AD_BYTES } ,
{ " BYTES " , AD_BYTES } ,
{ " WORD " , AD_WORDS } ,
{ " WORDS " , AD_WORDS } ,
2015-11-01 15:08:38 -08:00
{ " LONG " , AD_ADRL } ,
2015-10-23 22:44:56 -07:00
{ " DC " , AD_DC } ,
2015-11-15 21:14:46 -08:00
{ " DV " , AD_DC } , // DASM variation of DC which allows expressions
2015-10-23 22:44:56 -07:00
{ " TEXT " , AD_TEXT } ,
{ " INCLUDE " , AD_INCLUDE } ,
{ " INCBIN " , AD_INCBIN } ,
2015-10-25 14:29:41 -07:00
{ " IMPORT " , AD_IMPORT } ,
2015-10-23 22:44:56 -07:00
{ " CONST " , AD_CONST } ,
{ " LABEL " , AD_LABEL } ,
2015-11-26 13:10:58 -08:00
{ " STRING " , AD_STRING } ,
{ " UNDEF " , AD_UNDEF } ,
2015-10-23 22:44:56 -07:00
{ " INCSYM " , AD_INCSYM } ,
{ " LABPOOL " , AD_LABPOOL } ,
{ " POOL " , AD_LABPOOL } ,
{ " IF " , AD_IF } ,
{ " IFDEF " , AD_IFDEF } ,
{ " ELSE " , AD_ELSE } ,
{ " ELIF " , AD_ELIF } ,
{ " ENDIF " , AD_ENDIF } ,
{ " STRUCT " , AD_STRUCT } ,
{ " ENUM " , AD_ENUM } ,
{ " REPT " , AD_REPT } ,
2015-10-25 14:29:41 -07:00
{ " REPEAT " , AD_REPT } , // ca65 version of rept
2015-10-23 22:44:56 -07:00
{ " INCDIR " , AD_INCDIR } ,
{ " A16 " , AD_A16 } , // A16: Set 16 bit accumulator mode
{ " A8 " , AD_A8 } , // A8: Set 8 bit accumulator mode
{ " XY16 " , AD_XY16 } , // XY16: Set 16 bit index register mode
{ " XY8 " , AD_XY8 } , // XY8: Set 8 bit index register mode
{ " I16 " , AD_XY16 } , // I16: Set 16 bit index register mode
{ " I8 " , AD_XY8 } , // I8: Set 8 bit index register mode
2015-10-25 14:29:41 -07:00
{ " DUMMY " , AD_DUMMY } ,
{ " DUMMY_END " , AD_DUMMY_END } ,
{ " DS " , AD_DS } , // Define space
2015-11-15 21:14:46 -08:00
{ " ABORT " , AD_ABORT } ,
{ " ERR " , AD_ABORT } , // DASM version of ABORT
2015-10-25 14:29:41 -07:00
} ;
// Merlin specific directives separated from regular directives to avoid confusion
DirectiveName aDirectiveNamesMerlin [ ] {
{ " MX " , AD_MX } , // MERLIN
2015-10-26 20:50:26 -07:00
{ " STR " , AD_LNK } , // MERLIN
2015-10-23 22:44:56 -07:00
{ " DA " , AD_WORDS } , // MERLIN
{ " DW " , AD_WORDS } , // MERLIN
{ " ASC " , AD_TEXT } , // MERLIN
{ " PUT " , AD_INCLUDE } , // MERLIN
{ " DDB " , AD_WORDS } , // MERLIN
{ " DB " , AD_BYTES } , // MERLIN
{ " DFB " , AD_BYTES } , // MERLIN
{ " HEX " , AD_HEX } , // MERLIN
{ " DO " , AD_IF } , // MERLIN
{ " FIN " , AD_ENDIF } , // MERLIN
{ " EJECT " , AD_EJECT } , // MERLIN
{ " OBJ " , AD_EJECT } , // MERLIN
{ " TR " , AD_EJECT } , // MERLIN
2015-10-26 20:50:26 -07:00
{ " END " , AD_EJECT } , // MERLIN
{ " REL " , AD_EJECT } , // MERLIN
2015-10-23 22:44:56 -07:00
{ " USR " , AD_USR } , // MERLIN
{ " DUM " , AD_DUMMY } , // MERLIN
{ " DEND " , AD_DUMMY_END } , // MERLIN
{ " LST " , AD_LST } , // MERLIN
{ " LSTDO " , AD_LST } , // MERLIN
{ " LUP " , AD_REPT } , // MERLIN
{ " SAV " , AD_SAV } , // MERLIN
2015-10-26 20:50:26 -07:00
{ " DSK " , AD_SAV } , // MERLIN
{ " LNK " , AD_LNK } , // MERLIN
2015-10-23 22:44:56 -07:00
{ " XC " , AD_XC } , // MERLIN
2015-10-26 20:50:26 -07:00
{ " ENT " , AD_ENT } , // MERLIN (xdef, but label on same line)
2015-10-31 14:34:45 -07:00
{ " EXT " , AD_EXT } , // MERLIN (xref, which are implied in x65 object files)
2015-10-26 20:50:26 -07:00
{ " ADR " , AD_ADR } , // ADR: MERLIN store 3 byte word
{ " ADRL " , AD_ADRL } , // ADRL: MERLIN store 4 byte word
2015-10-31 14:34:45 -07:00
{ " CYC " , AD_CYC } , // MERLIN: Start and stop cycle counter
2015-10-21 22:34:01 -07:00
} ;
2015-10-18 12:42:10 -07:00
2015-10-23 22:44:56 -07:00
static const int nDirectiveNames = sizeof ( aDirectiveNames ) / sizeof ( aDirectiveNames [ 0 ] ) ;
2015-10-25 14:29:41 -07:00
static const int nDirectiveNamesMerlin = sizeof ( aDirectiveNamesMerlin ) / sizeof ( aDirectiveNamesMerlin [ 0 ] ) ;
2015-10-02 20:57:50 -07:00
2015-10-04 14:05:38 -07:00
// Binary search over an array of unsigned integers, may contain multiple instances of same key
2016-03-12 11:39:53 -08:00
uint32_t FindLabelIndex ( uint32_t hash , uint32_t * table , uint32_t count )
2015-10-04 14:05:38 -07:00
{
2016-03-12 11:39:53 -08:00
uint32_t max = count ;
uint32_t first = 0 ;
2015-10-04 14:05:38 -07:00
while ( count ! = first ) {
int index = ( first + count ) / 2 ;
2016-03-12 11:39:53 -08:00
uint32_t read = table [ index ] ;
2015-10-04 14:05:38 -07:00
if ( hash = = read ) {
while ( index & & table [ index - 1 ] = = hash )
index - - ; // guarantee first identical index returned on match
return index ;
} else if ( hash > read )
first = index + 1 ;
else
count = index ;
}
if ( count < max & & table [ count ] < hash )
count + + ;
else if ( count & & table [ count - 1 ] > hash )
count - - ;
return count ;
}
2015-10-02 20:57:50 -07:00
//
//
// ASSEMBLER STATE
//
//
2015-10-04 14:05:38 -07:00
2015-10-02 20:57:50 -07:00
// pairArray is basically two vectors sharing a size without constructors on growth or insert
2015-09-29 22:07:04 -07:00
template < class H , class V > class pairArray {
protected :
H * keys ;
V * values ;
2016-03-12 11:39:53 -08:00
uint32_t _count ;
uint32_t _capacity ;
2015-09-29 22:07:04 -07:00
public :
pairArray ( ) : keys ( nullptr ) , values ( nullptr ) , _count ( 0 ) , _capacity ( 0 ) { }
2016-03-12 11:39:53 -08:00
void reserve ( uint32_t size ) {
2015-09-29 22:07:04 -07:00
if ( size > _capacity ) {
H * new_keys = ( H * ) malloc ( sizeof ( H ) * size ) ; if ( ! new_keys ) { return ; }
V * new_values = ( V * ) malloc ( sizeof ( V ) * size ) ; if ( ! new_values ) { free ( new_keys ) ; return ; }
if ( keys & & values ) {
memcpy ( new_keys , keys , sizeof ( H ) * _count ) ;
memcpy ( new_values , values , sizeof ( V ) * _count ) ;
free ( keys ) ; free ( values ) ;
}
keys = new_keys ;
values = new_values ;
_capacity = size ;
}
}
2016-03-12 11:39:53 -08:00
bool insert ( uint32_t pos ) {
2015-09-29 22:07:04 -07:00
if ( pos > _count )
return false ;
if ( _count = = _capacity )
reserve ( _capacity + 64 ) ;
if ( pos < _count ) {
memmove ( keys + pos + 1 , keys + pos , sizeof ( H ) * ( _count - pos ) ) ;
memmove ( values + pos + 1 , values + pos , sizeof ( V ) * ( _count - pos ) ) ;
}
memset ( keys + pos , 0 , sizeof ( H ) ) ;
memset ( values + pos , 0 , sizeof ( V ) ) ;
_count + + ;
return true ;
}
2016-03-12 11:39:53 -08:00
bool insert ( uint32_t pos , H key ) {
2015-10-17 12:13:23 -07:00
if ( insert ( pos ) & & keys ) {
2015-09-29 22:07:04 -07:00
keys [ pos ] = key ;
return true ;
}
return false ;
}
2016-03-12 11:39:53 -08:00
void remove ( uint32_t pos ) {
2015-09-29 22:07:04 -07:00
if ( pos < _count ) {
_count - - ;
if ( pos < _count ) {
memmove ( keys + pos , keys + pos + 1 , sizeof ( H ) * ( _count - pos ) ) ;
memmove ( values + pos , values + pos + 1 , sizeof ( V ) * ( _count - pos ) ) ;
}
}
}
H * getKeys ( ) { return keys ; }
2016-03-12 11:39:53 -08:00
H & getKey ( uint32_t pos ) { return keys [ pos ] ; }
2015-09-29 22:07:04 -07:00
V * getValues ( ) { return values ; }
2016-03-12 11:39:53 -08:00
V & getValue ( uint32_t pos ) { return values [ pos ] ; }
uint32_t count ( ) const { return _count ; }
uint32_t capacity ( ) const { return _capacity ; }
2015-09-29 22:07:04 -07:00
void clear ( ) {
if ( keys ! = nullptr )
free ( keys ) ;
keys = nullptr ;
if ( values ! = nullptr )
free ( values ) ;
values = nullptr ;
_capacity = 0 ;
_count = 0 ;
}
} ;
2015-10-10 15:25:08 -07:00
// relocs are cheaper than full expressions and work with
2015-10-24 13:41:11 -07:00
// local labels for relative sections which would otherwise
2015-10-10 15:25:08 -07:00
// be out of scope at link time.
struct Reloc {
int base_value ;
int section_offset ; // offset into this section
int target_section ; // which section does this reloc target?
2016-03-12 11:39:53 -08:00
int8_t bytes ; // number of bytes to write
int8_t shift ; // number of bits to shift to get value
2015-10-10 15:25:08 -07:00
2015-11-05 21:23:38 -08:00
Reloc ( ) : base_value ( 0 ) , section_offset ( - 1 ) , target_section ( - 1 ) , bytes ( 0 ) , shift ( 0 ) { }
2016-03-12 11:39:53 -08:00
Reloc ( int base , int offs , int sect , int8_t num_bytes , int8_t bit_shift ) :
2015-11-05 21:23:38 -08:00
base_value ( base ) , section_offset ( offs ) , target_section ( sect ) , bytes ( num_bytes ) , shift ( bit_shift ) { }
2015-10-10 15:25:08 -07:00
} ;
typedef std : : vector < struct Reloc > relocList ;
2015-10-18 12:42:10 -07:00
// For assembly listing this remembers the location of each line
struct ListLine {
2015-10-31 14:34:45 -07:00
enum Flags {
MNEMONIC = 0x01 ,
KEYWORD = 0x02 ,
CYCLES_START = 0x04 ,
CYCLES_STOP = 0x08 ,
} ;
2015-10-19 22:44:02 -07:00
strref source_name ; // source file index name
strref code ; // line of code this represents
2015-10-18 12:42:10 -07:00
int address ; // start address of this line
int size ; // number of bytes generated for this line
int line_offs ; // offset into code
2015-10-31 14:34:45 -07:00
int flags ; // only output code if generated by code
bool wasMnemonic ( ) const { return ! ! ( flags & MNEMONIC ) ; }
bool startClock ( ) const { return ! ! ( flags & CYCLES_START ) ; }
bool stopClock ( ) const { return ! ! ( flags & CYCLES_STOP ) ; }
2015-10-18 12:42:10 -07:00
} ;
typedef std : : vector < struct ListLine > Listing ;
2019-09-06 18:02:18 -07:00
// Source level debugging info that can be saved into linkable object files, this is close to ListLine so possibly combinable.
// this belongs in each section so it can be saved with that into the x65 files or generated if linked
struct SourceDebugEntry {
int source_file_index ; // index into Assembler::source_file vector
int address ; // local address in section
int size ;
int source_file_offset ; // can be converted into line/column while linking
} ;
typedef std : : vector < struct SLDEntry > SourceDebug ;
2016-03-12 11:39:53 -08:00
enum SectionType : int8_t { // enum order indicates fixed address linking priority
2015-11-06 22:48:50 -08:00
ST_UNDEFINED , // not set
ST_CODE , // default type
ST_DATA , // data section (matters for GS/OS OMF)
ST_BSS , // uninitialized data section
2015-11-15 21:14:46 -08:00
ST_ZEROPAGE , // uninitialized data section in zero page / direct page
ST_REMOVED // removed, don't export to object file
2015-11-06 22:48:50 -08:00
} ;
2017-01-08 16:30:30 -08:00
// String data
typedef struct sStringSymbols {
public :
strref string_name ; // name of the string
strref string_const ; // string contents if source reference
strovl string_value ; // string contents if modified, initialized to null string
StatusCode Append ( strref append ) ;
StatusCode ParseLine ( strref line ) ;
strref get ( ) { return string_value . valid ( ) ? string_value . get_strref ( ) : string_const ; }
void clear ( ) {
if ( string_value . cap ( ) ) {
free ( string_value . charstr ( ) ) ;
string_value . invalidate ( ) ;
string_value . clear ( ) ;
}
string_const . clear ( ) ;
}
} StringSymbol ;
2015-10-10 15:25:08 -07:00
// start of data section support
2015-10-24 13:41:11 -07:00
// Default is a relative section
2015-10-10 15:25:08 -07:00
// Whenever org or dum with address is encountered => new section
// If org is fixed and < $200 then it is a dummy section Otherwise clear dummy section
typedef struct Section {
// section name, same named section => append
strref name ; // name of section for comparison
2015-10-18 19:48:03 -07:00
strref export_append ; // append this name to export of file
2015-11-08 18:06:45 -08:00
strref include_from ; // which file did this section originate from?
2015-10-10 15:25:08 -07:00
// generated address status
int load_address ; // if assigned a load address
int start_address ;
int address ; // relative or absolute PC
2015-10-18 19:48:03 -07:00
int align_address ; // for relative sections that needs alignment
2015-10-10 15:25:08 -07:00
// merged sections
2017-08-06 16:07:41 -07:00
int merged_at ; // merged into a section at this offset
int merged_into ; // -1 if not merged otherwise section merged into
int merged_size ; // how many bytes were merged in
2015-10-10 15:25:08 -07:00
// data output
2016-03-12 11:39:53 -08:00
uint8_t * output ; // memory for this section
uint8_t * curr ; // current pointer for this section
2015-10-10 15:25:08 -07:00
size_t output_capacity ; // current output capacity
// reloc data
relocList * pRelocs ; // link time resolve (not all sections need this)
2015-10-18 12:42:10 -07:00
Listing * pListing ; // if list output
2019-09-06 18:02:18 -07:00
SourceDebug * pSrcDbg ; // if source level debugging info generated
2015-10-18 12:42:10 -07:00
2015-11-08 18:06:45 -08:00
// grouped sections
int next_group ; // next section of a group of relative sections or -1
int first_group ; // >=0 if another section is grouped with this section
2015-10-18 12:42:10 -07:00
bool address_assigned ; // address is absolute if assigned
2015-10-10 15:25:08 -07:00
bool dummySection ; // true if section does not generate data, only labels
2015-11-06 22:48:50 -08:00
SectionType type ; // distinguishing section type for relocatable output
2015-10-10 15:25:08 -07:00
2015-10-19 22:44:02 -07:00
void reset ( ) { // explicitly cleaning up sections, not called from Section destructor
2015-11-08 18:06:45 -08:00
name . clear ( ) ; export_append . clear ( ) ; include_from . clear ( ) ;
2015-11-06 22:48:50 -08:00
start_address = address = load_address = 0x0 ; type = ST_CODE ;
2015-10-10 15:25:08 -07:00
address_assigned = false ; output = nullptr ; curr = nullptr ;
2017-08-06 16:07:41 -07:00
dummySection = false ; output_capacity = 0 ;
merged_at = - 1 ; merged_into = - 1 ; merged_size = 0 ;
2015-10-18 19:48:03 -07:00
align_address = 1 ; if ( pRelocs ) delete pRelocs ;
2015-11-08 18:06:45 -08:00
next_group = first_group = - 1 ;
2015-10-18 12:42:10 -07:00
pRelocs = nullptr ;
if ( pListing ) delete pListing ;
pListing = nullptr ;
2015-10-10 15:25:08 -07:00
}
void Cleanup ( ) { if ( output ) free ( output ) ; reset ( ) ; }
2017-08-06 16:07:41 -07:00
bool empty ( ) const { return type ! = ST_REMOVED & & curr = = output ; }
2015-11-09 22:15:14 -08:00
bool unused ( ) const { return ! address_assigned & & address = = start_address ; }
2015-10-10 15:25:08 -07:00
2015-10-13 19:38:13 -07:00
int DataOffset ( ) const { return int ( curr - output ) ; }
2015-11-15 21:14:46 -08:00
int size ( ) const { return ( int ) ( curr - output ) ; }
int addr_size ( ) const { return address - start_address ; }
2016-03-12 11:39:53 -08:00
const uint8_t * get ( ) { return output ; }
2015-10-10 15:25:08 -07:00
int GetPC ( ) const { return address ; }
void AddAddress ( int value ) { address + = value ; }
void SetLoadAddress ( int addr ) { load_address = addr ; }
int GetLoadAddress ( ) const { return load_address ; }
2015-11-09 22:15:14 -08:00
void SetDummySection ( bool enable ) { dummySection = enable ; type = ST_BSS ; }
2015-10-23 22:44:56 -07:00
bool IsDummySection ( ) const { return dummySection ; }
2015-10-10 15:25:08 -07:00
bool IsRelativeSection ( ) const { return address_assigned = = false ; }
2017-08-06 16:07:41 -07:00
bool IsMergedSection ( ) const { return false ; }
2016-03-12 11:39:53 -08:00
void AddReloc ( int base , int offset , int section , int8_t bytes , int8_t shift ) ;
2015-10-10 15:25:08 -07:00
2015-10-18 12:42:10 -07:00
Section ( ) : pRelocs ( nullptr ) , pListing ( nullptr ) { reset ( ) ; }
2015-10-24 13:41:11 -07:00
Section ( strref _name , int _address ) : pRelocs ( nullptr ) , pListing ( nullptr ) {
2015-10-23 22:44:56 -07:00
reset ( ) ; name = _name ; start_address = load_address = address = _address ;
address_assigned = true ;
}
Section ( strref _name ) : pRelocs ( nullptr ) , pListing ( nullptr ) {
reset ( ) ; name = _name ;
start_address = load_address = address = 0 ; address_assigned = false ;
}
2015-10-19 22:44:02 -07:00
~ Section ( ) { }
2015-10-10 15:25:08 -07:00
2015-10-24 13:41:11 -07:00
// Append data to a section
2016-03-12 11:39:53 -08:00
StatusCode CheckOutputCapacity ( uint32_t addSize ) ;
2015-10-10 15:25:08 -07:00
void AddByte ( int b ) ;
void AddWord ( int w ) ;
2015-10-23 22:44:56 -07:00
void AddTriple ( int l ) ;
2016-03-12 11:39:53 -08:00
void AddBin ( const uint8_t * p , int size ) ;
2015-10-25 14:29:41 -07:00
void AddText ( strref line , strref text_prefix ) ;
2017-01-08 16:30:30 -08:00
void AddIndexText ( StringSymbol * strSym , strref text ) ;
2016-05-25 22:44:17 -07:00
void SetByte ( size_t offs , int b ) { output [ offs ] = ( uint8_t ) b ; }
void SetWord ( size_t offs , int w ) { output [ offs ] = ( uint8_t ) w ; output [ offs + 1 ] = uint8_t ( w > > 8 ) ; }
void SetTriple ( size_t offs , int w ) { output [ offs ] = ( uint8_t ) w ; output [ offs + 1 ] = uint8_t ( w > > 8 ) ; output [ offs + 2 ] = uint8_t ( w > > 16 ) ; }
void SetQuad ( size_t offs , int w ) { output [ offs ] = ( uint8_t ) w ; output [ offs + 1 ] = uint8_t ( w > > 8 ) ; output [ offs + 2 ] = uint8_t ( w > > 16 ) ; output [ offs + 3 ] = uint8_t ( w > > 24 ) ; }
2015-10-10 15:25:08 -07:00
} Section ;
2015-10-11 14:55:55 -07:00
// Symbol list entry (in order of parsing)
struct MapSymbol {
2015-10-23 22:44:56 -07:00
strref name ; // string name
2015-10-27 20:57:14 -07:00
int value ;
2016-03-12 11:39:53 -08:00
int16_t section ;
2015-10-23 22:44:56 -07:00
bool local ; // local variables
2015-10-11 14:55:55 -07:00
} ;
typedef std : : vector < struct MapSymbol > MapSymbolArray ;
2015-09-29 22:07:04 -07:00
// Data related to a label
2016-03-12 11:39:53 -08:00
typedef struct sLabel {
2015-09-29 22:07:04 -07:00
public :
strref label_name ; // the name of this label
2015-10-10 20:08:30 -07:00
strref pool_name ; // name of the pool that this label is related to
2015-09-29 22:07:04 -07:00
int value ;
2015-10-10 15:25:08 -07:00
int section ; // rel section address labels belong to a section, -1 if fixed address or assigned
2015-10-23 22:44:56 -07:00
int mapIndex ; // index into map symbols in case of late resolve
2015-09-29 22:07:04 -07:00
bool evaluated ; // a value may not yet be evaluated
bool pc_relative ; // this is an inline label describing a point in the code
bool constant ; // the value of this label can not change
2015-10-13 19:38:13 -07:00
bool external ; // this label is globally accessible
2015-10-30 22:30:16 -07:00
bool reference ; // this label is accessed from external and can't be used for evaluation locally
2015-09-29 22:07:04 -07:00
} Label ;
2015-11-26 13:10:58 -08:00
2015-09-29 22:07:04 -07:00
// If an expression can't be evaluated immediately, this is required
// to reconstruct the result when it can be.
2016-03-12 11:39:53 -08:00
typedef struct sLateEval {
2015-10-02 20:57:50 -07:00
enum Type { // When an expression is evaluated late, determine how to encode the result
LET_LABEL , // this evaluation applies to a label and not memory
LET_ABS_REF , // calculate an absolute address and store at 0, +1
2015-10-23 22:44:56 -07:00
LET_ABS_L_REF , // calculate a bank + absolute address and store at 0, +1, +2
2015-10-26 20:50:26 -07:00
LET_ABS_4_REF , // calculate a 32 bit number
2015-10-02 20:57:50 -07:00
LET_BRANCH , // calculate a branch offset and store at this address
2015-10-23 22:44:56 -07:00
LET_BRANCH_16 , // calculate a branch offset of 16 bits and store at this address
2015-10-02 20:57:50 -07:00
LET_BYTE , // calculate a byte and store at this address
} ;
2015-10-16 20:27:56 -07:00
int target ; // offset into output buffer
2015-09-29 22:07:04 -07:00
int address ; // current pc
int scope ; // scope pc
2015-11-03 20:57:06 -08:00
int scope_depth ; // relevant for scope end
2016-03-12 11:39:53 -08:00
int16_t section ; // which section to apply to.
int16_t rept ; // value of rept
2015-10-16 20:27:56 -07:00
int file_ref ; // -1 if current or xdef'd otherwise index of file for label
2015-09-29 22:07:04 -07:00
strref label ; // valid if this is not a target but another label
strref expression ;
strref source_file ;
2015-10-02 20:57:50 -07:00
Type type ;
2015-09-29 22:07:04 -07:00
} LateEval ;
// A macro is a text reference to where it was defined
2016-03-12 11:39:53 -08:00
typedef struct sMacro {
2015-09-29 22:07:04 -07:00
strref name ;
strref macro ;
strref source_name ; // source file name (error output)
strref source_file ; // entire source file (req. for line #)
2015-10-20 22:28:53 -07:00
bool params_first_line ; // the first line of this macro are parameters
2015-09-29 22:07:04 -07:00
} Macro ;
2015-10-01 23:16:36 -07:00
// All local labels are removed when a global label is defined but some when a scope ends
2016-03-12 11:39:53 -08:00
typedef struct sLocalLabelRecord {
2015-10-01 23:16:36 -07:00
strref label ;
int scope_depth ;
bool scope_reserve ; // not released for global label, only scope
} LocalLabelRecord ;
2016-12-24 13:23:01 -08:00
2015-10-01 23:16:36 -07:00
// Label pools allows C like stack frame label allocation
2016-03-12 11:39:53 -08:00
typedef struct sLabelPool {
2015-10-01 23:16:36 -07:00
strref pool_name ;
2016-03-12 11:39:53 -08:00
int16_t numRanges ; // normally 1 range, support multiple for ease of use
2017-01-08 16:30:30 -08:00
int16_t depth ; // Required for scope closure cleanup
uint16_t start ;
uint16_t end ;
uint16_t scopeUsed [ MAX_SCOPE_DEPTH ] [ 2 ] ; // last address assigned + scope depth
StatusCode Reserve ( uint16_t numBytes , uint16_t & ret_addr , uint16_t scope ) ;
void ExitScope ( uint16_t scope ) ;
2015-10-01 23:16:36 -07:00
} LabelPool ;
2015-10-04 14:05:38 -07:00
// One member of a label struct
struct MemberOffset {
2016-03-12 11:39:53 -08:00
uint16_t offset ;
uint32_t name_hash ;
2015-10-04 14:05:38 -07:00
strref name ;
strref sub_struct ;
} ;
// Label struct
2016-03-12 11:39:53 -08:00
typedef struct sLabelStruct {
2015-10-04 14:05:38 -07:00
strref name ;
2016-03-12 11:39:53 -08:00
uint16_t first_member ;
uint16_t numMembers ;
uint16_t size ;
2015-10-04 14:05:38 -07:00
} LabelStruct ;
2015-10-16 20:27:56 -07:00
// object file labels that are not xdef'd end up here
struct ExtLabels {
2016-03-12 11:39:53 -08:00
pairArray < uint32_t , Label > labels ;
2015-10-16 20:27:56 -07:00
} ;
2015-10-25 14:29:41 -07:00
// EvalExpression needs a location reference to work out some addresses
2015-10-16 20:27:56 -07:00
struct EvalContext {
int pc ; // current address at point of eval
int scope_pc ; // current scope open at point of eval
int scope_end_pc ; // late scope closure after eval
2015-11-03 20:57:06 -08:00
int scope_depth ; // scope depth for eval (must match current for scope_end_pc to eval)
2015-10-16 20:27:56 -07:00
int relative_section ; // return can be relative to this section
int file_ref ; // can access private label from this file or -1
2015-11-03 20:57:06 -08:00
int rept_cnt ; // current repeat counter
EvalContext ( ) { }
EvalContext ( int _pc , int _scope , int _close , int _sect , int _rept_cnt ) :
pc ( _pc ) , scope_pc ( _scope ) , scope_end_pc ( _close ) , scope_depth ( - 1 ) ,
relative_section ( _sect ) , file_ref ( - 1 ) , rept_cnt ( _rept_cnt ) { }
2015-10-16 20:27:56 -07:00
} ;
2015-10-04 16:06:45 -07:00
// Source context is current file (include file, etc.) or current macro.
2016-03-12 11:39:53 -08:00
typedef struct sSourceContext {
2015-10-04 16:06:45 -07:00
strref source_name ; // source file name (error output)
strref source_file ; // entire source file (req. for line #)
strref code_segment ; // the segment of the file for this context
strref read_source ; // current position/length in source file
strref next_source ; // next position/length in source file
2016-03-12 11:39:53 -08:00
int16_t repeat ; // how many times to repeat this code segment
2016-03-13 18:16:43 -07:00
int16_t repeat_total ; // initial number of repeats for this code segment
2016-03-12 11:39:53 -08:00
int16_t conditional_ctx ; // conditional depth at root of this context
2015-10-04 16:06:45 -07:00
void restart ( ) { read_source = code_segment ; }
bool complete ( ) { repeat - - ; return repeat < = 0 ; }
} SourceContext ;
2015-10-01 23:16:36 -07:00
// Context stack is a stack of currently processing text
2015-09-29 22:07:04 -07:00
class ContextStack {
private :
2016-03-11 14:12:32 -08:00
std : : vector < SourceContext > stack ; // stack of contexts
SourceContext * currContext ; // current context
2015-09-29 22:07:04 -07:00
public :
ContextStack ( ) : currContext ( nullptr ) { stack . reserve ( 32 ) ; }
SourceContext & curr ( ) { return * currContext ; }
2015-11-03 20:57:06 -08:00
const SourceContext & curr ( ) const { return * currContext ; }
2015-10-23 22:44:56 -07:00
void push ( strref src_name , strref src_file , strref code_seg , int rept = 1 ) {
2015-10-04 14:05:38 -07:00
if ( currContext )
currContext - > read_source = currContext - > next_source ;
2015-09-29 22:07:04 -07:00
SourceContext context ;
context . source_name = src_name ;
context . source_file = src_file ;
context . code_segment = code_seg ;
context . read_source = code_seg ;
2015-10-04 14:05:38 -07:00
context . next_source = code_seg ;
2016-05-25 22:44:17 -07:00
context . repeat = ( int16_t ) rept ;
context . repeat_total = ( int16_t ) rept ;
2015-09-29 22:07:04 -07:00
stack . push_back ( context ) ;
currContext = & stack [ stack . size ( ) - 1 ] ;
}
void pop ( ) { stack . pop_back ( ) ; currContext = stack . size ( ) ? & stack [ stack . size ( ) - 1 ] : nullptr ; }
bool has_work ( ) { return currContext ! = nullptr ; }
2019-03-13 12:08:21 -07:00
bool empty ( ) const { return stack . size ( ) = = 0 ; }
2015-09-29 22:07:04 -07:00
} ;
2015-10-02 20:57:50 -07:00
// The state of the assembler
2015-09-29 22:07:04 -07:00
class Asm {
public :
2016-03-12 11:39:53 -08:00
pairArray < uint32_t , Label > labels ;
pairArray < uint32_t , StringSymbol > strings ;
pairArray < uint32_t , Macro > macros ;
pairArray < uint32_t , LabelPool > labelPools ;
pairArray < uint32_t , LabelStruct > labelStructs ;
pairArray < uint32_t , strref > xdefs ; // labels matching xdef names will be marked as external
2015-10-02 20:57:50 -07:00
2019-09-06 18:02:18 -07:00
std : : vector < char * > source_files ; // all source files encountered while assembling. referenced by source level debugging
2015-09-29 22:07:04 -07:00
std : : vector < LateEval > lateEval ;
2015-10-02 20:57:50 -07:00
std : : vector < LocalLabelRecord > localLabels ;
2015-10-24 13:41:11 -07:00
std : : vector < char * > loadedData ; // free when assembler is completed
2015-10-04 14:05:38 -07:00
std : : vector < MemberOffset > structMembers ; // labelStructs refer to sets of structMembers
2015-10-05 22:45:42 -07:00
std : : vector < strref > includePaths ;
2015-10-10 15:25:08 -07:00
std : : vector < Section > allSections ;
2015-10-24 13:41:11 -07:00
std : : vector < ExtLabels > externals ; // external labels organized by object file
2015-10-23 22:44:56 -07:00
MapSymbolArray map ;
2015-10-21 22:34:01 -07:00
// CPU target
struct mnem * opcode_table ;
int opcode_count ;
2015-10-23 22:44:56 -07:00
CPUIndex cpu , list_cpu ;
OPLookup aInstructions [ MAX_OPCODES_DIRECTIVES ] ;
int num_instructions ;
2015-11-09 00:07:55 -08:00
int default_org ;
2015-10-23 22:44:56 -07:00
2015-09-29 22:07:04 -07:00
// context for macros / include files
ContextStack contextStack ;
2015-10-23 22:44:56 -07:00
2015-10-20 22:28:53 -07:00
// Current section
2015-10-10 15:25:08 -07:00
Section * current_section ;
2015-09-29 22:07:04 -07:00
2015-10-10 15:25:08 -07:00
// Special syntax rules
AsmSyntax syntax ;
// Conditional assembly vars
2015-12-01 21:21:00 -08:00
int conditional_depth ; // conditional depth / base depth for context
2015-10-25 14:29:41 -07:00
strref conditional_source [ MAX_CONDITIONAL_DEPTH ] ; // start of conditional for error report
2016-03-12 11:39:53 -08:00
int8_t conditional_nesting [ MAX_CONDITIONAL_DEPTH ] ;
2015-10-01 23:16:36 -07:00
bool conditional_consumed [ MAX_CONDITIONAL_DEPTH ] ;
2015-10-10 15:25:08 -07:00
// Scope info
int scope_address [ MAX_SCOPE_DEPTH ] ;
int scope_depth ;
2017-01-08 16:30:30 -08:00
int brace_depth ; // scope depth defined only by braces, not files
2015-10-10 15:25:08 -07:00
2015-10-23 22:44:56 -07:00
// Eval relative result (only valid if EvalExpression returns STATUS_RELATIVE_SECTION)
2015-10-10 15:25:08 -07:00
int lastEvalSection ;
2015-10-10 17:53:15 -07:00
int lastEvalValue ;
2016-03-12 11:39:53 -08:00
int8_t lastEvalShift ;
2015-10-10 15:25:08 -07:00
2015-10-25 14:29:41 -07:00
strref export_base_name ; // binary output name if available
strref last_label ; // most recently defined label for Merlin macro
2016-03-12 11:39:53 -08:00
int8_t list_flags ; // listing flags accumulating for each line
2015-10-25 14:29:41 -07:00
bool accumulator_16bit ; // 65816 specific software dependent immediate mode
bool index_reg_16bit ; // -"-
2016-03-12 11:39:53 -08:00
int8_t cycle_counter_level ; // merlin toggles the cycle counter rather than hierarchically evals
2015-10-30 22:30:16 -07:00
bool error_encountered ; // if any error encountered, don't export binary
2015-10-25 14:29:41 -07:00
bool list_assembly ; // generate assembler listing
bool end_macro_directive ; // whether to use { } or macro / endmacro for macro scope
2015-09-29 22:07:04 -07:00
// Convert source to binary
2015-10-13 19:38:13 -07:00
void Assemble ( strref source , strref filename , bool obj_target ) ;
2015-09-29 22:07:04 -07:00
2015-12-01 21:21:00 -08:00
// Push a new context and handle enter / exit of context
StatusCode PushContext ( strref src_name , strref src_file , strref code_seg , int rept = 1 ) ;
StatusCode PopContext ( ) ;
2015-10-18 12:42:10 -07:00
// Generate assembler listing if requested
bool List ( strref filename ) ;
2019-09-03 17:10:48 -07:00
// Mimic TASS listing
bool ListTassStyle ( strref filename ) ;
2015-10-24 13:41:11 -07:00
// Generate source for all valid instructions and addressing modes for current CPU
2015-10-18 12:42:10 -07:00
bool AllOpcodes ( strref filename ) ;
2015-10-02 20:57:50 -07:00
// Clean up memory allocations, reset assembler state
2015-09-29 22:07:04 -07:00
void Cleanup ( ) ;
2015-10-23 22:44:56 -07:00
2015-09-29 22:07:04 -07:00
// Make sure there is room to write more code
2016-03-12 11:39:53 -08:00
StatusCode CheckOutputCapacity ( uint32_t addSize ) ;
2015-09-29 22:07:04 -07:00
2015-10-10 15:25:08 -07:00
// Operations on current section
void SetSection ( strref name , int address ) ; // fixed address section
2015-10-25 14:29:41 -07:00
void SetSection ( strref name ) ; // relative address section
2015-11-08 18:06:45 -08:00
void LinkLabelsToAddress ( int section_id , int section_new , int section_address ) ;
StatusCode LinkRelocs ( int section_id , int section_new , int section_address ) ;
StatusCode AssignAddressToSection ( int section_id , int address ) ;
2015-10-25 14:29:41 -07:00
StatusCode LinkSections ( strref name ) ; // link relative address sections with this name here
2015-11-15 21:14:46 -08:00
StatusCode MergeSections ( int section_id , int section_merge ) ; // Combine the result of a section onto another
StatusCode MergeSectionsByName ( int first_section ) ;
StatusCode MergeAllSections ( int first_section ) ;
2015-10-25 14:29:41 -07:00
void DummySection ( int address ) ; // non-data section (fixed)
void DummySection ( ) ; // non-data section (relative)
void EndSection ( ) ; // pop current section
2015-10-10 15:25:08 -07:00
Section & CurrSection ( ) { return * current_section ; }
2015-11-09 22:15:14 -08:00
void AssignAddressToGroup ( ) ; // Merlin LNK support
2016-03-12 11:39:53 -08:00
uint8_t * BuildExport ( strref append , int & file_size , int & addr ) ;
2015-10-18 19:48:03 -07:00
int GetExportNames ( strref * aNames , int maxNames ) ;
2015-11-07 18:23:57 -08:00
StatusCode LinkZP ( ) ;
2015-10-10 15:25:08 -07:00
int SectionId ( ) { return int ( current_section - & allSections [ 0 ] ) ; }
2015-11-15 21:14:46 -08:00
int SectionId ( Section & s ) { return ( int ) ( & s - & allSections [ 0 ] ) ; }
2015-10-10 15:25:08 -07:00
void AddByte ( int b ) { CurrSection ( ) . AddByte ( b ) ; }
void AddWord ( int w ) { CurrSection ( ) . AddWord ( w ) ; }
2015-10-23 22:44:56 -07:00
void AddTriple ( int l ) { CurrSection ( ) . AddTriple ( l ) ; }
2016-03-12 11:39:53 -08:00
void AddBin ( const uint8_t * p , int size ) { CurrSection ( ) . AddBin ( p , size ) ; }
2015-10-10 15:25:08 -07:00
2015-10-13 19:38:13 -07:00
// Object file handling
2015-10-25 14:29:41 -07:00
StatusCode WriteObjectFile ( strref filename ) ; // write x65 object file
2015-11-09 22:15:14 -08:00
StatusCode ReadObjectFile ( strref filename , int link_to_section = - 1 ) ; // read x65 object file
2015-10-13 19:38:13 -07:00
2015-11-15 21:14:46 -08:00
// Apple II GS OMF
StatusCode WriteA2GS_OMF ( strref filename , bool full_collapse ) ;
2015-10-25 23:48:35 -07:00
// Scope management
StatusCode EnterScope ( ) ;
StatusCode ExitScope ( ) ;
2015-10-02 20:57:50 -07:00
// Macro management
2015-10-04 14:05:38 -07:00
StatusCode AddMacro ( strref macro , strref source_name , strref source_file , strref & left ) ;
2015-09-29 22:07:04 -07:00
StatusCode BuildMacro ( Macro & m , strref arg_list ) ;
2015-10-04 14:05:38 -07:00
// Structs
StatusCode BuildStruct ( strref name , strref declaration ) ;
StatusCode EvalStruct ( strref name , int & value ) ;
2015-10-06 22:42:22 -07:00
StatusCode BuildEnum ( strref name , strref declaration ) ;
2015-10-04 14:05:38 -07:00
2015-09-29 22:07:04 -07:00
// Calculate a value based on an expression.
2015-10-16 20:27:56 -07:00
EvalOperator RPNToken_Merlin ( strref & expression , const struct EvalContext & etx ,
2016-03-12 11:39:53 -08:00
EvalOperator prev_op , int16_t & section , int & value ) ;
2015-10-16 20:27:56 -07:00
EvalOperator RPNToken ( strref & expression , const struct EvalContext & etx ,
2016-03-12 11:39:53 -08:00
EvalOperator prev_op , int16_t & section , int & value , strref & subexp ) ;
2015-10-16 20:27:56 -07:00
StatusCode EvalExpression ( strref expression , const struct EvalContext & etx , int & result ) ;
2015-11-03 20:57:06 -08:00
void SetEvalCtxDefaults ( struct EvalContext & etx ) ;
int ReptCnt ( ) const ;
2015-09-29 22:07:04 -07:00
// Access labels
Label * GetLabel ( strref label ) ;
2015-10-16 20:27:56 -07:00
Label * GetLabel ( strref label , int file_ref ) ;
2016-03-12 11:39:53 -08:00
Label * AddLabel ( uint32_t hash ) ;
2015-10-16 20:27:56 -07:00
bool MatchXDEF ( strref label ) ;
2015-09-29 22:07:04 -07:00
StatusCode AssignLabel ( strref label , strref line , bool make_constant = false ) ;
StatusCode AddressLabel ( strref label ) ;
2015-10-23 22:44:56 -07:00
void LabelAdded ( Label * pLabel , bool local = false ) ;
2015-11-26 13:10:58 -08:00
StatusCode IncludeSymbols ( strref line ) ;
// Strings
StringSymbol * GetString ( strref string_name ) ;
StringSymbol * AddString ( strref string_name , strref string_value ) ;
StatusCode StringAction ( StringSymbol * pStr , strref line ) ;
StatusCode ParseStringOp ( StringSymbol * pStr , strref line ) ;
2015-09-29 22:07:04 -07:00
2015-10-01 23:16:36 -07:00
// Manage locals
void MarkLabelLocal ( strref label , bool scope_label = false ) ;
2015-10-21 22:34:01 -07:00
StatusCode FlushLocalLabels ( int scope_exit = - 1 ) ;
2015-10-23 22:44:56 -07:00
2015-10-01 23:16:36 -07:00
// Label pools
LabelPool * GetLabelPool ( strref pool_name ) ;
StatusCode AddLabelPool ( strref name , strref args ) ;
StatusCode AssignPoolLabel ( LabelPool & pool , strref args ) ;
2015-09-29 22:07:04 -07:00
// Late expression evaluation
2015-10-13 19:38:13 -07:00
void AddLateEval ( int target , int pc , int scope_pc , strref expression ,
2015-10-10 15:25:08 -07:00
strref source_file , LateEval : : Type type ) ;
2015-09-29 22:07:04 -07:00
void AddLateEval ( strref label , int pc , int scope_pc ,
2015-10-02 20:57:50 -07:00
strref expression , LateEval : : Type type ) ;
2015-10-30 22:30:16 -07:00
StatusCode CheckLateEval ( strref added_label = strref ( ) , int scope_end = - 1 , bool missing_is_error = false ) ;
2015-09-29 22:07:04 -07:00
2015-10-20 22:28:53 -07:00
// Assembler Directives
2015-09-29 22:07:04 -07:00
StatusCode ApplyDirective ( AssemblerDirective dir , strref line , strref source_file ) ;
2016-05-25 22:44:17 -07:00
StatusCode Directive_Rept ( strref line ) ;
StatusCode Directive_Macro ( strref line ) ;
2015-11-26 13:10:58 -08:00
StatusCode Directive_String ( strref line ) ;
StatusCode Directive_Undef ( strref line ) ;
2015-10-25 14:29:41 -07:00
StatusCode Directive_Include ( strref line ) ;
StatusCode Directive_Incbin ( strref line , int skip = 0 , int len = 0 ) ;
StatusCode Directive_Import ( strref line ) ;
2015-10-26 20:50:26 -07:00
StatusCode Directive_ORG ( strref line ) ;
StatusCode Directive_LOAD ( strref line ) ;
2017-01-08 16:30:30 -08:00
StatusCode Directive_MERGE ( strref line ) ;
2015-10-26 20:50:26 -07:00
StatusCode Directive_LNK ( strref line ) ;
StatusCode Directive_XDEF ( strref line ) ;
2015-10-31 14:34:45 -07:00
StatusCode Directive_XREF ( strref label ) ;
2015-11-08 18:06:45 -08:00
StatusCode Directive_DC ( strref line , int width , strref source_file ) ;
2015-11-15 21:14:46 -08:00
StatusCode Directive_DS ( strref line ) ;
StatusCode Directive_ALIGN ( strref line ) ;
StatusCode Directive_EVAL ( strref line ) ;
StatusCode Directive_HEX ( strref line ) ;
StatusCode Directive_ENUM_STRUCT ( strref line , AssemblerDirective dir ) ;
2015-10-20 22:28:53 -07:00
// Assembler steps
2016-03-12 11:39:53 -08:00
StatusCode GetAddressMode ( strref line , bool flipXY , uint32_t validModes ,
2015-10-25 23:48:35 -07:00
AddrMode & addrMode , int & len , strref & expression ) ;
2015-10-18 12:42:10 -07:00
StatusCode AddOpcode ( strref line , int index , strref source_file ) ;
2015-10-23 22:44:56 -07:00
StatusCode BuildLine ( strref line ) ;
StatusCode BuildSegment ( ) ;
2015-10-04 14:05:38 -07:00
// Display error in stderr
2017-01-28 13:29:42 -08:00
void PrintError ( strref line , StatusCode error , strref file = strref ( ) ) ;
2015-09-29 22:07:04 -07:00
2015-10-02 20:57:50 -07:00
// Conditional Status
bool ConditionalAsm ( ) ; // Assembly is currently enabled
bool NewConditional ( ) ; // Start a new conditional block
void CloseConditional ( ) ; // Close a conditional block
void CheckConditionalDepth ( ) ; // Check if this conditional will nest the assembly (a conditional is already consumed)
void ConsumeConditional ( ) ; // This conditional block is going to be assembled, mark it as consumed
bool ConditionalConsumed ( ) ; // Has a block of this conditional already been assembled?
void SetConditional ( ) ; // This conditional block is not going to be assembled so mark that it is nesting
bool ConditionalAvail ( ) ; // Returns true if this conditional can be consumed
2015-10-02 21:52:55 -07:00
void ConditionalElse ( ) ; // Conditional else that does not enable block
2015-10-02 20:57:50 -07:00
void EnableConditional ( bool enable ) ; // This conditional block is enabled and the prior wasn't
// Conditional statement evaluation (A==B? A?)
StatusCode EvalStatement ( strref line , bool & result ) ;
2015-10-23 22:44:56 -07:00
2015-10-05 22:45:42 -07:00
// Add include folder
void AddIncludeFolder ( strref path ) ;
char * LoadText ( strref filename , size_t & size ) ;
char * LoadBinary ( strref filename , size_t & size ) ;
2015-10-02 20:57:50 -07:00
2015-10-23 22:44:56 -07:00
// Change CPU
void SetCPU ( CPUIndex CPU ) ;
2016-03-11 14:12:32 -08:00
// Syntax
bool Merlin ( ) const { return syntax = = SYNTAX_MERLIN ; }
2015-09-29 22:07:04 -07:00
// constructor
2015-10-23 22:44:56 -07:00
Asm ( ) : opcode_table ( opcodes_6502 ) , opcode_count ( num_opcodes_6502 ) , num_instructions ( 0 ) ,
cpu ( CPU_6502 ) , list_cpu ( CPU_6502 ) {
2015-10-21 22:34:01 -07:00
Cleanup ( ) ; localLabels . reserve ( 256 ) ; loadedData . reserve ( 16 ) ; lateEval . reserve ( 64 ) ; }
2015-09-29 22:07:04 -07:00
} ;
// Clean up work allocations
void Asm : : Cleanup ( ) {
2015-10-17 12:13:23 -07:00
for ( std : : vector < char * > : : iterator i = loadedData . begin ( ) ; i ! = loadedData . end ( ) ; + + i ) {
if ( char * data = * i )
free ( data ) ;
}
2015-10-23 22:44:56 -07:00
map . clear ( ) ;
2015-10-01 23:16:36 -07:00
labelPools . clear ( ) ;
2015-09-29 22:07:04 -07:00
loadedData . clear ( ) ;
labels . clear ( ) ;
macros . clear ( ) ;
2015-10-10 15:25:08 -07:00
allSections . clear ( ) ;
2016-03-12 11:39:53 -08:00
for ( uint32_t i = 0 ; i < strings . count ( ) ; + + i ) {
2015-11-26 13:10:58 -08:00
StringSymbol & str = strings . getValue ( i ) ;
if ( str . string_value . cap ( ) )
free ( str . string_value . charstr ( ) ) ;
}
strings . clear ( ) ;
2015-10-16 20:27:56 -07:00
for ( std : : vector < ExtLabels > : : iterator exti = externals . begin ( ) ; exti ! = externals . end ( ) ; + + exti )
exti - > labels . clear ( ) ;
externals . clear ( ) ;
2015-10-24 13:41:11 -07:00
// this section is relocatable but is assigned address $1000 if exporting without directives
2015-11-23 22:34:30 -08:00
SetSection ( strref ( " default,code " ) ) ;
2015-10-10 15:25:08 -07:00
current_section = & allSections [ 0 ] ;
syntax = SYNTAX_SANE ;
2015-11-09 00:07:55 -08:00
default_org = 0x1000 ;
2015-10-01 23:16:36 -07:00
scope_depth = 0 ;
2017-01-08 16:30:30 -08:00
brace_depth = 0 ;
2015-10-01 23:16:36 -07:00
conditional_depth = 0 ;
conditional_nesting [ 0 ] = 0 ;
conditional_consumed [ 0 ] = false ;
2015-10-30 22:30:16 -07:00
error_encountered = false ;
2015-10-18 12:42:10 -07:00
list_assembly = false ;
2015-10-20 22:28:53 -07:00
end_macro_directive = false ;
2015-10-26 20:50:26 -07:00
accumulator_16bit = false ; // default 65816 8 bit immediate mode
index_reg_16bit = false ; // other CPUs won't be affected.
2015-10-31 14:34:45 -07:00
cycle_counter_level = 0 ;
2015-10-23 22:44:56 -07:00
}
int sortHashLookup ( const void * A , const void * B ) {
const OPLookup * _A = ( const OPLookup * ) A ;
const OPLookup * _B = ( const OPLookup * ) B ;
return _A - > op_hash > _B - > op_hash ? 1 : - 1 ;
}
2016-05-25 22:44:17 -07:00
int BuildInstructionTable ( OPLookup * pInstr , struct mnem * opcodes ,
2015-10-25 14:29:41 -07:00
int count , const char * * aliases , bool merlin )
2015-10-23 22:44:56 -07:00
{
// create an instruction table (mnemonic hash lookup)
int numInstructions = 0 ;
for ( int i = 0 ; i < count ; i + + ) {
OPLookup & op = pInstr [ numInstructions + + ] ;
op . op_hash = strref ( opcodes [ i ] . instr ) . fnv1a_lower ( ) ;
2016-05-25 22:44:17 -07:00
op . index = ( uint8_t ) i ;
2015-10-23 22:44:56 -07:00
op . type = OT_MNEMONIC ;
}
2015-10-24 13:41:11 -07:00
// add instruction aliases
if ( aliases ) {
while ( * aliases ) {
strref orig ( * aliases + + ) ;
strref alias ( * aliases + + ) ;
for ( int o = 0 ; o < count ; o + + ) {
if ( orig . same_str_case ( opcodes [ o ] . instr ) ) {
OPLookup & op = pInstr [ numInstructions + + ] ;
op . op_hash = alias . fnv1a_lower ( ) ;
2016-05-25 22:44:17 -07:00
op . index = ( uint8_t ) o ;
2015-10-24 13:41:11 -07:00
op . type = OT_MNEMONIC ;
break ;
}
}
}
}
2015-10-23 22:44:56 -07:00
// add assembler directives
for ( int d = 0 ; d < nDirectiveNames ; d + + ) {
OPLookup & op_hash = pInstr [ numInstructions + + ] ;
op_hash . op_hash = strref ( aDirectiveNames [ d ] . name ) . fnv1a_lower ( ) ;
2016-03-12 11:39:53 -08:00
op_hash . index = ( uint8_t ) aDirectiveNames [ d ] . directive ;
2015-10-23 22:44:56 -07:00
op_hash . type = OT_DIRECTIVE ;
}
2015-10-24 13:41:11 -07:00
2015-10-25 14:29:41 -07:00
if ( merlin ) {
for ( int d = 0 ; d < nDirectiveNamesMerlin ; d + + ) {
OPLookup & op_hash = pInstr [ numInstructions + + ] ;
op_hash . op_hash = strref ( aDirectiveNamesMerlin [ d ] . name ) . fnv1a_lower ( ) ;
2016-03-12 11:39:53 -08:00
op_hash . index = ( uint8_t ) aDirectiveNamesMerlin [ d ] . directive ;
2015-10-25 14:29:41 -07:00
op_hash . type = OT_DIRECTIVE ;
}
}
2015-10-23 22:44:56 -07:00
// sort table by hash for binary search lookup
qsort ( pInstr , numInstructions , sizeof ( OPLookup ) , sortHashLookup ) ;
return numInstructions ;
}
// Change the instruction set
void Asm : : SetCPU ( CPUIndex CPU ) {
cpu = CPU ;
if ( cpu > list_cpu )
list_cpu = cpu ;
opcode_table = aCPUs [ CPU ] . opcodes ;
opcode_count = aCPUs [ CPU ] . num_opcodes ;
2016-05-25 22:44:17 -07:00
num_instructions = BuildInstructionTable ( aInstructions , opcode_table ,
2016-03-11 14:12:32 -08:00
opcode_count , aCPUs [ CPU ] . aliases , Merlin ( ) ) ;
2015-09-29 22:07:04 -07:00
}
2015-10-05 22:45:42 -07:00
// Read in text data (main source, include, etc.)
char * Asm : : LoadText ( strref filename , size_t & size ) {
strown < 512 > file ( filename ) ;
std : : vector < strref > : : iterator i = includePaths . begin ( ) ;
2015-10-23 22:44:56 -07:00
for ( ; ; ) {
2015-10-24 13:41:11 -07:00
if ( FILE * f = fopen ( file . c_str ( ) , " rb " ) ) { // rb is intended here since OS
fseek ( f , 0 , SEEK_END ) ; // eol conversion can do ugly things
2015-10-05 22:45:42 -07:00
size_t _size = ftell ( f ) ;
fseek ( f , 0 , SEEK_SET ) ;
if ( char * buf = ( char * ) calloc ( _size , 1 ) ) {
2015-10-06 22:42:22 -07:00
fread ( buf , _size , 1 , f ) ;
2015-10-05 22:45:42 -07:00
fclose ( f ) ;
size = _size ;
return buf ;
}
fclose ( f ) ;
}
if ( i = = includePaths . end ( ) )
break ;
file . copy ( * i ) ;
if ( file . get_last ( ) ! = ' / ' & & file . get_last ( ) ! = ' \\ ' )
file . append ( ' / ' ) ;
file . append ( filename ) ;
+ + i ;
}
size = 0 ;
return nullptr ;
}
// Read in binary data (incbin)
char * Asm : : LoadBinary ( strref filename , size_t & size ) {
strown < 512 > file ( filename ) ;
std : : vector < strref > : : iterator i = includePaths . begin ( ) ;
2015-10-23 22:44:56 -07:00
for ( ; ; ) {
2015-10-05 22:45:42 -07:00
if ( FILE * f = fopen ( file . c_str ( ) , " rb " ) ) {
fseek ( f , 0 , SEEK_END ) ;
size_t _size = ftell ( f ) ;
fseek ( f , 0 , SEEK_SET ) ;
if ( char * buf = ( char * ) malloc ( _size ) ) {
fread ( buf , _size , 1 , f ) ;
fclose ( f ) ;
size = _size ;
return buf ;
}
fclose ( f ) ;
}
if ( i = = includePaths . end ( ) )
break ;
file . copy ( * i ) ;
if ( file . get_last ( ) ! = ' / ' & & file . get_last ( ) ! = ' \\ ' )
file . append ( ' / ' ) ;
file . append ( filename ) ;
2015-10-13 19:38:13 -07:00
# ifdef WIN32
file . replace ( ' / ' , ' \\ ' ) ;
# endif
2015-10-05 22:45:42 -07:00
+ + i ;
}
size = 0 ;
return nullptr ;
}
2015-10-24 13:41:11 -07:00
// Create a new section with a fixed address
2017-01-08 16:30:30 -08:00
void Asm : : SetSection ( strref name , int address ) {
2015-10-10 15:25:08 -07:00
if ( name ) {
for ( std : : vector < Section > : : iterator i = allSections . begin ( ) ; i ! = allSections . end ( ) ; + + i ) {
if ( i - > name & & name . same_str ( i - > name ) ) {
current_section = & * i ;
return ;
}
}
}
2017-01-08 16:30:30 -08:00
if ( allSections . size ( ) = = allSections . capacity ( ) ) { allSections . reserve ( allSections . size ( ) + 16 ) ; }
2015-10-10 15:25:08 -07:00
Section newSection ( name , address ) ;
2017-01-08 16:30:30 -08:00
// don't compile over zero page and stack frame (may be bad assumption)
2018-10-20 18:33:19 -07:00
if ( address < 0x200 ) {
newSection . SetDummySection ( true ) ; }
2015-10-10 15:25:08 -07:00
allSections . push_back ( newSection ) ;
current_section = & allSections [ allSections . size ( ) - 1 ] ;
}
2017-01-08 16:30:30 -08:00
void Asm : : SetSection ( strref line ) {
if ( allSections . size ( ) & & CurrSection ( ) . unused ( ) ) { allSections . erase ( allSections . begin ( ) + SectionId ( ) ) ; }
if ( allSections . size ( ) = = allSections . capacity ( ) ) { allSections . reserve ( allSections . size ( ) + 16 ) ; }
2015-11-06 22:48:50 -08:00
SectionType type = ST_UNDEFINED ;
2017-01-08 16:30:30 -08:00
if ( line . get_first ( ) = = ' . ' ) { // SEG.U etc.
2015-11-06 22:48:50 -08:00
+ + line ;
switch ( strref : : tolower ( line . get_first ( ) ) ) {
case ' u ' : type = ST_BSS ; break ;
case ' z ' : type = ST_ZEROPAGE ; break ;
case ' d ' : type = ST_DATA ; break ;
case ' c ' : type = ST_CODE ; break ;
}
}
line . trim_whitespace ( ) ;
2015-10-18 19:48:03 -07:00
int align = 1 ;
2015-11-06 22:48:50 -08:00
strref name ;
while ( strref arg = line . split_token_any_trim ( " ,: " ) ) {
2016-05-20 22:48:13 -07:00
if ( arg . get_first ( ) = = ' $ ' ) { + + arg ; align = ( int ) arg . ahextoui ( ) ; }
2017-01-08 16:30:30 -08:00
else if ( arg . is_number ( ) ) { align = ( int ) arg . atoi ( ) ; }
else if ( arg . get_first ( ) = = ' " ' ) { name = ( arg + 1 ) . before_or_full ( ' " ' ) ; }
else if ( ! name ) { name = arg ; }
else if ( arg . same_str ( " code " ) ) { type = ST_CODE ; }
else if ( arg . same_str ( " data " ) ) { type = ST_DATA ; }
else if ( arg . same_str ( " bss " ) ) { type = ST_BSS ; }
else if ( arg . same_str ( " zp " ) | | arg . same_str ( " dp " ) | |
arg . same_str ( " zeropage " ) | | arg . same_str ( " direct " ) ) { type = ST_ZEROPAGE ; }
2015-11-06 22:48:50 -08:00
}
if ( type = = ST_UNDEFINED ) {
2017-01-08 16:30:30 -08:00
if ( name . find ( " code " ) > = 0 ) { type = ST_CODE ; }
else if ( name . find ( " data " ) > = 0 ) { type = ST_DATA ; }
2016-05-25 22:44:17 -07:00
else if ( name . find ( " bss " ) > = 0 | | name . same_str ( " directpage_stack " ) ) type = ST_BSS ;
2017-01-08 16:30:30 -08:00
else if ( name . find ( " zp " ) > = 0 | | name . find ( " zeropage " ) > = 0 | | name . find ( " direct " ) > = 0 ) { type = ST_ZEROPAGE ; }
else { type = ST_CODE ; }
2015-11-06 22:48:50 -08:00
}
Section newSection ( name ) ;
2015-10-18 19:48:03 -07:00
newSection . align_address = align ;
2015-11-06 22:48:50 -08:00
newSection . type = type ;
2015-10-10 15:25:08 -07:00
allSections . push_back ( newSection ) ;
current_section = & allSections [ allSections . size ( ) - 1 ] ;
}
2015-10-26 20:50:26 -07:00
// Fixed address dummy section
void Asm : : DummySection ( int address ) {
2017-01-08 16:30:30 -08:00
if ( allSections . size ( ) = = allSections . capacity ( ) ) { allSections . reserve ( allSections . size ( ) + 16 ) ; }
2015-10-10 15:25:08 -07:00
Section newSection ( strref ( ) , address ) ;
newSection . SetDummySection ( true ) ;
allSections . push_back ( newSection ) ;
current_section = & allSections [ allSections . size ( ) - 1 ] ;
}
// Current address dummy section
void Asm : : DummySection ( ) {
DummySection ( CurrSection ( ) . GetPC ( ) ) ;
}
2015-10-05 22:45:42 -07:00
2015-10-10 15:25:08 -07:00
void Asm : : EndSection ( ) {
2015-11-15 21:14:46 -08:00
int section = SectionId ( ) ;
2017-01-08 16:30:30 -08:00
if ( section ) { current_section = & allSections [ section - 1 ] ; }
2015-10-10 15:25:08 -07:00
}
2015-11-09 22:15:14 -08:00
// Iterate through the current group of sections and assign addresses if this section is fixed
// This is to handle the special linking of Merlin where sections are brought together pre-export
2017-01-08 16:30:30 -08:00
void Asm : : AssignAddressToGroup ( ) {
2015-11-09 22:15:14 -08:00
Section & curr = CurrSection ( ) ;
2017-01-08 16:30:30 -08:00
if ( ! curr . address_assigned ) { return ; }
2015-11-09 22:15:14 -08:00
// Put in all the sections cared about into either the fixed sections or the relative sections
std : : vector < Section * > FixedExport ;
std : : vector < Section * > RelativeExport ;
int seg = SectionId ( ) ;
while ( seg > = 0 ) {
Section & s = allSections [ seg ] ;
if ( s . address_assigned & & s . type ! = ST_ZEROPAGE & & s . start_address > = curr . start_address ) {
bool inserted = false ;
for ( std : : vector < Section * > : : iterator i = FixedExport . begin ( ) ; i ! = FixedExport . end ( ) ; + + i ) {
if ( s . start_address < ( * i ) - > start_address ) {
FixedExport . insert ( i , & s ) ;
inserted = true ;
break ;
}
}
2017-01-08 16:30:30 -08:00
if ( ! inserted ) { FixedExport . push_back ( & s ) ; }
2015-11-09 22:15:14 -08:00
} else if ( ! s . address_assigned & & s . type ! = ST_ZEROPAGE ) {
RelativeExport . push_back ( & s ) ;
s . export_append = curr . export_append ;
}
seg = allSections [ seg ] . next_group ;
}
// in this case each block should be added individually in order of code / data / bss
for ( int type = ST_CODE ; type < = ST_BSS ; type + + ) {
std : : vector < Section * > : : iterator i = RelativeExport . begin ( ) ;
while ( i ! = RelativeExport . end ( ) ) {
Section * pSec = * i ;
if ( pSec - > type = = type ) {
int bytes = pSec - > address - pSec - > start_address ;
size_t insert_after = FixedExport . size ( ) - 1 ;
for ( size_t p = 0 ; p < insert_after ; p + + ) {
int end_prev = FixedExport [ p ] - > address ;
int start_next = FixedExport [ p + 1 ] - > start_address ;
int avail = start_next - end_prev ;
if ( avail > = bytes ) {
int addr = end_prev ;
addr + = pSec - > align_address < = 1 ? 0 :
( pSec - > align_address - ( addr % pSec - > align_address ) ) % pSec - > align_address ;
if ( ( addr + bytes ) < = start_next ) {
insert_after = p ;
break ;
}
}
}
int address = FixedExport [ insert_after ] - > address ;
address + = pSec - > align_address < = 1 ? 0 :
( pSec - > align_address - ( address % pSec - > align_address ) ) % pSec - > align_address ;
2015-11-15 21:14:46 -08:00
AssignAddressToSection ( SectionId ( * pSec ) , address ) ;
2015-11-09 22:15:14 -08:00
FixedExport . insert ( ( FixedExport . begin ( ) + insert_after + 1 ) , pSec ) ;
i = RelativeExport . erase ( i ) ;
2017-01-08 16:30:30 -08:00
} else { + + i ; }
2015-11-09 22:15:14 -08:00
}
}
}
2015-10-18 19:48:03 -07:00
// list all export append names
// for each valid export append name build a binary fixed address code
// - find lowest and highest address
// - alloc & 0 memory
// - any matching relative sections gets linked in after
// - go through all section that matches export_append in order and copy over memory
2017-01-08 16:30:30 -08:00
uint8_t * Asm : : BuildExport ( strref append , int & file_size , int & addr ) {
2015-10-18 19:48:03 -07:00
int start_address = 0x7fffffff ;
int end_address = 0 ;
bool has_relative_section = false ;
bool has_fixed_section = false ;
2015-11-08 18:06:45 -08:00
int first_link_section = - 1 ;
std : : vector < Section * > FixedExport ;
2015-10-18 19:48:03 -07:00
2017-01-08 16:30:30 -08:00
// automatically merge sections with the same name and type if one is relative and other is fixed
for ( size_t section_id = 0 ; section_id ! = allSections . size ( ) ; + + section_id ) {
const Section & section = allSections [ section_id ] ;
if ( ! section . IsMergedSection ( ) & & ! section . IsRelativeSection ( ) ) {
for ( size_t section_merge_id = 0 ; section_merge_id ! = allSections . size ( ) ; + + section_merge_id ) {
const Section & section_merge = allSections [ section_merge_id ] ;
if ( ! section_merge . IsMergedSection ( ) & & section_merge . IsRelativeSection ( ) & &
section_merge . type = = section . type & & section . name . same_str_case ( section_merge . name ) ) {
MergeSections ( ( int ) section_id , ( int ) section_merge_id ) ;
}
}
}
}
// link any relocs to sections that are fixed
for ( size_t section_id = 0 ; section_id ! = allSections . size ( ) ; + + section_id ) {
const Section & section = allSections [ section_id ] ;
if ( ! section . IsMergedSection ( ) & & ! section . IsRelativeSection ( ) ) {
LinkRelocs ( ( int ) section_id , - 1 , section . start_address ) ;
}
}
2015-10-18 19:48:03 -07:00
// find address range
while ( ! has_relative_section & & ! has_fixed_section ) {
int section_id = 0 ;
for ( std : : vector < Section > : : iterator i = allSections . begin ( ) ; i ! = allSections . end ( ) ; + + i ) {
2015-11-07 18:23:57 -08:00
if ( ( ( ! append & & ! i - > export_append ) | | append . same_str_case ( i - > export_append ) ) & & i - > type ! = ST_ZEROPAGE ) {
2015-10-18 19:48:03 -07:00
if ( ! i - > IsMergedSection ( ) ) {
2015-11-08 18:06:45 -08:00
if ( i - > IsRelativeSection ( ) ) {
2015-11-09 22:15:14 -08:00
// prioritize code over data, local code over included code for initial binary segment
2015-11-08 18:06:45 -08:00
if ( ( i - > type = = ST_CODE | | i - > type = = ST_DATA ) & & i - > first_group < 0 & &
( first_link_section < 0 | | ( i - > type = = ST_CODE & &
( allSections [ first_link_section ] . type = = ST_DATA | |
( ! i - > include_from & & allSections [ first_link_section ] . include_from ) ) ) ) )
2015-11-15 21:14:46 -08:00
first_link_section = SectionId ( * i ) ;
2015-10-18 19:48:03 -07:00
has_relative_section = true ;
2017-01-08 16:30:30 -08:00
} else if ( i - > start_address > = 0x100 & & ( i - > size ( ) > 0 | | i - > addr_size ( ) > 0 ) ) {
2015-10-18 19:48:03 -07:00
has_fixed_section = true ;
2015-11-08 18:06:45 -08:00
bool inserted = false ;
for ( std : : vector < Section * > : : iterator f = FixedExport . begin ( ) ; f ! = FixedExport . end ( ) ; + + f ) {
if ( ( * f ) - > start_address > i - > start_address ) {
FixedExport . insert ( f , & * i ) ;
inserted = true ;
break ;
}
}
if ( ! inserted )
FixedExport . push_back ( & * i ) ;
2015-10-18 19:48:03 -07:00
if ( i - > start_address < start_address )
start_address = i - > start_address ;
if ( ( i - > start_address + ( int ) i - > size ( ) ) > end_address ) {
end_address = i - > start_address + ( int ) i - > size ( ) ;
}
}
}
}
section_id + + ;
}
2015-10-23 22:44:56 -07:00
if ( ! has_relative_section & & ! has_fixed_section )
return nullptr ;
2015-10-18 19:48:03 -07:00
if ( has_relative_section ) {
if ( ! has_fixed_section ) {
2015-11-08 18:06:45 -08:00
// there is not a fixed section so go through and assign addresses to all sections
// starting with the first reasonable section
2015-11-09 00:07:55 -08:00
start_address = default_org ;
2017-01-08 16:30:30 -08:00
if ( first_link_section < 0 ) { return nullptr ; }
2015-11-08 18:06:45 -08:00
while ( first_link_section > = 0 ) {
FixedExport . push_back ( & allSections [ first_link_section ] ) ;
AssignAddressToSection ( first_link_section , start_address ) ;
start_address = allSections [ first_link_section ] . address ;
first_link_section = allSections [ first_link_section ] . next_group ;
}
2015-10-18 19:48:03 -07:00
}
2015-11-08 18:06:45 -08:00
// First link code sections, then data sections, then BSS sections
for ( int sectype = ST_CODE ; sectype < = ST_BSS ; sectype + + ) {
// there are fixed sections so fit all relative sections after or inbetween fixed sections in export group
for ( std : : vector < Section > : : iterator i = allSections . begin ( ) ; i ! = allSections . end ( ) ; + + i ) {
if ( sectype = = i - > type & & ( ( ! append & & ! i - > export_append ) | | append . same_str_case ( i - > export_append ) ) ) {
int id = ( int ) ( & * i - & allSections [ 0 ] ) ;
if ( i - > IsRelativeSection ( ) & & i - > first_group < 0 ) {
2015-11-09 22:15:14 -08:00
// try to fit this section in between existing sections if possible
2015-11-08 18:06:45 -08:00
int insert_after = ( int ) FixedExport . size ( ) - 1 ;
for ( int f = 0 ; f < insert_after ; f + + ) {
int start_block = FixedExport [ f ] - > address ;
int end_block = FixedExport [ f + 1 ] - > start_address ;
if ( ( end_block - start_block ) > = ( i - > address - i - > start_address ) ) {
2016-12-23 13:56:57 -08:00
int addr_block = start_block ;
2015-11-08 18:06:45 -08:00
int sec = id ;
while ( sec > = 0 ) {
Section & s = allSections [ sec ] ;
2016-12-23 13:56:57 -08:00
addr_block + = s . align_address < = 1 ? 0 :
( s . align_address - ( addr_block % s . align_address ) ) % s . align_address ;
addr_block + = s . address - s . start_address ;
2015-11-08 18:06:45 -08:00
sec = s . next_group ;
}
2016-12-23 13:56:57 -08:00
if ( addr_block < = end_block ) {
2015-11-08 18:06:45 -08:00
insert_after = f ;
break ;
}
}
}
int sec = id ;
start_address = FixedExport [ insert_after ] - > address ;
while ( sec > = 0 ) {
insert_after + + ;
2017-01-08 16:30:30 -08:00
if ( insert_after < ( int ) FixedExport . size ( ) ) {
FixedExport . insert ( FixedExport . begin ( ) + insert_after , & allSections [ sec ] ) ;
} else {
2015-11-08 18:06:45 -08:00
FixedExport . push_back ( & allSections [ sec ] ) ;
2017-01-08 16:30:30 -08:00
}
2015-11-08 18:06:45 -08:00
AssignAddressToSection ( sec , start_address ) ;
start_address = allSections [ sec ] . address ;
sec = allSections [ sec ] . next_group ;
}
}
2015-10-18 19:48:03 -07:00
}
}
}
}
2015-10-10 20:08:30 -07:00
}
2015-10-18 19:48:03 -07:00
// get memory for output buffer
2015-11-08 18:06:45 -08:00
start_address = FixedExport [ 0 ] - > start_address ;
int last_data_export = ( int ) ( FixedExport . size ( ) - 1 ) ;
2017-01-08 16:30:30 -08:00
while ( last_data_export > 0 & & FixedExport [ last_data_export ] - > type = = ST_BSS ) { last_data_export - - ; }
2015-11-08 18:06:45 -08:00
end_address = FixedExport [ last_data_export ] - > address ;
2016-03-12 11:39:53 -08:00
uint8_t * output = ( uint8_t * ) calloc ( 1 , end_address - start_address ) ;
2015-10-18 19:48:03 -07:00
// copy over in order
for ( std : : vector < Section > : : iterator i = allSections . begin ( ) ; i ! = allSections . end ( ) ; + + i ) {
2017-08-06 16:07:41 -07:00
if ( i - > type = = ST_REMOVED ) { continue ; }
2015-11-09 00:07:55 -08:00
if ( ( ( ! append & & ! i - > export_append ) | | append . same_str_case ( i - > export_append ) ) & & i - > type ! = ST_ZEROPAGE ) {
2018-10-20 18:33:19 -07:00
if ( i - > size ( ) > 0 ) {
2017-01-08 16:30:30 -08:00
memcpy ( output + i - > start_address - start_address , i - > output , i - > size ( ) ) ;
}
2015-10-18 19:48:03 -07:00
}
2015-10-12 00:05:06 -07:00
}
2017-09-24 22:36:42 -07:00
2015-11-08 18:06:45 -08:00
printf ( " Linker export + \" " STRREF_FMT " \" summary: \n " , STRREF_ARG ( append ) ) ;
for ( std : : vector < Section * > : : iterator f = FixedExport . begin ( ) ; f ! = FixedExport . end ( ) ; + + f ) {
if ( ( * f ) - > include_from ) {
printf ( " * $%04x-$%04x: " STRREF_FMT " (%d) included from " STRREF_FMT " \n " , ( * f ) - > start_address ,
( * f ) - > address , STRREF_ARG ( ( * f ) - > name ) , ( int ) ( * f - & allSections [ 0 ] ) , STRREF_ARG ( ( * f ) - > include_from ) ) ;
} else {
printf ( " * $%04x-$%04x: " STRREF_FMT " (%d) \n " , ( * f ) - > start_address ,
( * f ) - > address , STRREF_ARG ( ( * f ) - > name ) , ( int ) ( * f - & allSections [ 0 ] ) ) ;
}
}
2015-10-18 19:48:03 -07:00
// return the result
file_size = end_address - start_address ;
addr = start_address ;
return output ;
}
// Collect all the export names
2017-01-08 16:30:30 -08:00
int Asm : : GetExportNames ( strref * aNames , int maxNames ) {
2015-10-18 19:48:03 -07:00
int count = 0 ;
for ( std : : vector < Section > : : iterator i = allSections . begin ( ) ; i ! = allSections . end ( ) ; + + i ) {
if ( ! i - > IsMergedSection ( ) ) {
bool found = false ;
2016-03-12 11:39:53 -08:00
uint32_t hash = i - > export_append . fnv1a_lower ( ) ;
2015-10-18 19:48:03 -07:00
for ( int n = 0 ; n < count ; n + + ) {
if ( aNames [ n ] . fnv1a_lower ( ) = = hash ) {
found = true ;
break ;
}
}
2017-01-08 16:30:30 -08:00
if ( ! found & & count < maxNames ) { aNames [ count + + ] = i - > export_append ; }
2015-10-18 19:48:03 -07:00
}
}
return count ;
2015-10-10 20:08:30 -07:00
}
2015-11-07 18:23:57 -08:00
// Collect all unassigned ZP sections and link them
2017-01-08 16:30:30 -08:00
StatusCode Asm : : LinkZP ( ) {
2016-03-12 11:39:53 -08:00
uint8_t min_addr = 0xff , max_addr = 0x00 ;
2015-11-07 18:23:57 -08:00
int num_addr = 0 ;
bool has_assigned = false , has_unassigned = false ;
int first_unassigned = - 1 ;
// determine if any zeropage section has been asseigned
2017-01-08 16:30:30 -08:00
for ( std : : vector < Section > : : iterator s = allSections . begin ( ) ; s ! = allSections . end ( ) ; + + s ) {
if ( s - > type = = ST_ZEROPAGE & & ! s - > IsMergedSection ( ) ) {
2015-11-07 18:23:57 -08:00
if ( s - > address_assigned ) {
has_assigned = true ;
2017-01-08 16:30:30 -08:00
if ( s - > start_address < ( int ) min_addr ) {
2016-05-25 22:44:17 -07:00
min_addr = ( uint8_t ) s - > start_address ;
2017-01-08 16:30:30 -08:00
} else if ( ( int ) s - > address > max_addr ) {
2016-05-25 22:44:17 -07:00
max_addr = ( uint8_t ) s - > address ;
2017-01-08 16:30:30 -08:00
}
2015-11-07 18:23:57 -08:00
} else {
has_unassigned = true ;
2017-01-08 16:30:30 -08:00
first_unassigned = first_unassigned > = 0 ? first_unassigned : ( int ) ( & * s - & allSections [ 0 ] ) ;
2015-11-07 18:23:57 -08:00
}
2017-01-08 16:30:30 -08:00
num_addr + = s - > address - s - > start_address ;
2015-11-07 18:23:57 -08:00
}
}
2017-01-08 16:30:30 -08:00
if ( num_addr > 0x100 ) { return ERROR_ZEROPAGE_SECTION_OUT_OF_RANGE ; }
2015-11-07 18:23:57 -08:00
// no unassigned zp section, nothing to fix
2017-01-08 16:30:30 -08:00
if ( ! has_unassigned ) { return STATUS_OK ; }
2015-11-07 18:23:57 -08:00
2015-11-08 18:06:45 -08:00
StatusCode status = STATUS_OK ;
2017-01-08 16:30:30 -08:00
if ( ! has_assigned ) { // no section assigned => fit together at end
2015-11-07 18:23:57 -08:00
int address = 0x100 - num_addr ;
2015-11-08 18:06:45 -08:00
for ( std : : vector < Section > : : iterator s = allSections . begin ( ) ; status = = STATUS_OK & & s ! = allSections . end ( ) ; + + s ) {
2015-11-07 18:23:57 -08:00
if ( s - > type = = ST_ZEROPAGE & & ! s - > IsMergedSection ( ) ) {
2015-11-08 18:06:45 -08:00
status = AssignAddressToSection ( ( int ) ( & * s - & allSections [ 0 ] ) , address ) ;
address = s - > address ;
2015-11-07 18:23:57 -08:00
}
}
} else { // find first fit neighbouring an address assigned zero page section
for ( std : : vector < Section > : : iterator s = allSections . begin ( ) ; s ! = allSections . end ( ) ; + + s ) {
if ( s - > type = = ST_ZEROPAGE & & ! s - > IsMergedSection ( ) & & ! s - > address_assigned ) {
int size = s - > address - s - > start_address ;
bool found = false ;
// find any assigned address section and try to place before or after
for ( std : : vector < Section > : : iterator sa = allSections . begin ( ) ; sa ! = allSections . end ( ) ; + + sa ) {
if ( sa - > type = = ST_ZEROPAGE & & ! sa - > IsMergedSection ( ) & & sa - > address_assigned ) {
for ( int e = 0 ; e < 2 ; + + e ) {
int start = e ? sa - > start_address - size : sa - > address ;
2015-11-08 18:06:45 -08:00
int align_size = s - > align_address < = 1 ? 0 :
( s - > align_address - ( start % s - > align_address ) ) % s - > align_address ;
start + = align_size ;
2015-11-07 18:23:57 -08:00
int end = start + size ;
if ( start > = 0 & & end < = 0x100 ) {
for ( std : : vector < Section > : : iterator sc = allSections . begin ( ) ; ! found & & sc ! = allSections . end ( ) ; + + sc ) {
found = true ;
if ( & * sa ! = & * sc & & sc - > type = = ST_ZEROPAGE & & ! sc - > IsMergedSection ( ) & & sc - > address_assigned ) {
if ( start < = sc - > address & & sc - > start_address < = end )
found = false ;
}
}
}
2017-01-08 16:30:30 -08:00
if ( found ) { AssignAddressToSection ( ( int ) ( & * s - & allSections [ 0 ] ) , start ) ; }
2015-11-07 18:23:57 -08:00
}
}
}
2017-01-08 16:30:30 -08:00
if ( ! found ) { return ERROR_ZEROPAGE_SECTION_OUT_OF_RANGE ; }
2015-11-07 18:23:57 -08:00
}
}
}
2015-11-08 18:06:45 -08:00
return status ;
2015-11-07 18:23:57 -08:00
}
2015-11-08 18:06:45 -08:00
// Apply labels assigned to addresses in a relative section a fixed address or as part of another section
2017-01-08 16:30:30 -08:00
void Asm : : LinkLabelsToAddress ( int section_id , int section_new , int section_address ) {
2015-10-13 19:38:13 -07:00
Label * pLabels = labels . getValues ( ) ;
int numLabels = labels . count ( ) ;
for ( int l = 0 ; l < numLabels ; l + + ) {
if ( pLabels - > section = = section_id ) {
pLabels - > value + = section_address ;
2015-11-08 18:06:45 -08:00
pLabels - > section = section_new ;
2015-10-13 19:38:13 -07:00
if ( pLabels - > mapIndex > = 0 & & pLabels - > mapIndex < ( int ) map . size ( ) ) {
struct MapSymbol & msym = map [ pLabels - > mapIndex ] ;
msym . value = pLabels - > value ;
2016-05-25 22:44:17 -07:00
msym . section = ( int16_t ) section_new ;
2015-10-13 19:38:13 -07:00
}
CheckLateEval ( pLabels - > label_name ) ;
}
+ + pLabels ;
}
}
2015-10-15 20:58:17 -07:00
// go through relocs in all sections to see if any targets this section
// relocate section to address!
2017-01-08 16:30:30 -08:00
StatusCode Asm : : LinkRelocs ( int section_id , int section_new , int section_address ) {
2015-10-15 20:58:17 -07:00
for ( std : : vector < Section > : : iterator j = allSections . begin ( ) ; j ! = allSections . end ( ) ; + + j ) {
Section & s2 = * j ;
if ( s2 . pRelocs ) {
relocList * pList = s2 . pRelocs ;
relocList : : iterator i = pList - > end ( ) ;
while ( i ! = pList - > begin ( ) ) {
- - i ;
if ( i - > target_section = = section_id ) {
Section * trg_sect = & s2 ;
size_t output_offs = 0 ;
2015-11-08 18:06:45 -08:00
// only finalize the target value if fixed address
if ( section_new = = - 1 | | allSections [ section_new ] . address_assigned ) {
2016-03-12 11:39:53 -08:00
uint8_t * trg = trg_sect - > output + output_offs + i - > section_offset ;
2015-11-08 18:06:45 -08:00
int value = i - > base_value + section_address ;
if ( i - > shift < 0 )
value > > = - i - > shift ;
else if ( i - > shift )
value < < = i - > shift ;
for ( int b = 0 ; b < i - > bytes ; b + + )
2016-03-12 11:39:53 -08:00
* trg + + = ( uint8_t ) ( value > > ( b * 8 ) ) ;
2015-11-08 18:06:45 -08:00
i = pList - > erase ( i ) ;
if ( i ! = pList - > end ( ) )
+ + i ;
2015-10-15 20:58:17 -07:00
}
}
}
if ( pList - > empty ( ) ) {
free ( pList ) ;
s2 . pRelocs = nullptr ;
}
}
}
return STATUS_OK ;
}
2015-11-08 18:06:45 -08:00
// Append one section to the end of another
2017-01-08 16:30:30 -08:00
StatusCode Asm : : AssignAddressToSection ( int section_id , int address ) {
if ( section_id < 0 | | section_id > = ( int ) allSections . size ( ) ) { return ERROR_NOT_A_SECTION ; }
2015-11-08 18:06:45 -08:00
Section & s = allSections [ section_id ] ;
if ( s . address_assigned )
return ERROR_CANT_REASSIGN_FIXED_SECTION ;
// fix up the alignment of the address
2017-01-08 16:30:30 -08:00
int align_size = s . align_address < = 1 ? 0 : ( s . align_address - ( address % s . align_address ) ) % s . align_address ;
2015-11-08 18:06:45 -08:00
address + = align_size ;
s . start_address = address ;
s . address + = address ;
s . address_assigned = true ;
LinkLabelsToAddress ( section_id , - 1 , s . start_address ) ;
return LinkRelocs ( section_id , - 1 , s . start_address ) ;
}
2015-10-18 12:42:10 -07:00
// Link sections with a specific name at this point
2015-11-08 18:06:45 -08:00
// Relative sections will just be appeneded to a grouping list
// Fixed address sections will be merged together
2015-10-10 15:25:08 -07:00
StatusCode Asm : : LinkSections ( strref name ) {
2017-01-08 16:30:30 -08:00
if ( CurrSection ( ) . IsDummySection ( ) ) { return ERROR_LINKER_CANT_LINK_TO_DUMMY_SECTION ; }
2015-11-08 18:06:45 -08:00
int last_section_group = CurrSection ( ) . next_group ;
while ( last_section_group > - 1 & & allSections [ last_section_group ] . next_group > - 1 )
last_section_group = allSections [ last_section_group ] . next_group ;
2015-10-10 15:25:08 -07:00
for ( std : : vector < Section > : : iterator i = allSections . begin ( ) ; i ! = allSections . end ( ) ; + + i ) {
2015-10-12 00:05:06 -07:00
if ( ( ! name | | i - > name . same_str_case ( name ) ) & & i - > IsRelativeSection ( ) & & ! i - > IsMergedSection ( ) ) {
2015-11-08 18:06:45 -08:00
// it is ok to link other sections with the same name to this section
2017-01-08 16:30:30 -08:00
if ( & * i = = & CurrSection ( ) ) { continue ; }
2015-11-07 18:23:57 -08:00
// Zero page sections can only be linked with zero page sections
if ( i - > type ! = ST_ZEROPAGE | | CurrSection ( ) . type = = ST_ZEROPAGE ) {
2015-11-09 22:15:14 -08:00
i - > export_append = CurrSection ( ) . export_append ;
if ( ! i - > address_assigned ) {
2015-11-08 18:06:45 -08:00
if ( i - > first_group < 0 ) {
int prev = last_section_group > = 0 ? last_section_group : SectionId ( ) ;
int curr = ( int ) ( & * i - & allSections [ 0 ] ) ;
allSections [ prev ] . next_group = curr ;
2017-09-24 22:36:42 -07:00
i - > first_group = CurrSection ( ) . first_group > = 0 ? CurrSection ( ) . first_group : SectionId ( ) ;
2015-11-08 18:06:45 -08:00
last_section_group = curr ;
}
}
2017-01-08 16:30:30 -08:00
} else { return ERROR_CANT_LINK_ZP_AND_NON_ZP ; }
2015-10-10 15:25:08 -07:00
}
}
return STATUS_OK ;
}
2015-11-15 21:14:46 -08:00
StatusCode Asm : : MergeSections ( int section_id , int section_merge ) {
2017-01-08 16:30:30 -08:00
if ( section_id = = section_merge | | section_id < 0 | | section_merge < 0 ) { return STATUS_OK ; }
2015-11-15 21:14:46 -08:00
Section & s = allSections [ section_id ] ;
Section & m = allSections [ section_merge ] ;
// merging section needs to be relative to be appended
2017-01-08 16:30:30 -08:00
if ( ! m . IsRelativeSection ( ) ) { return ERROR_CANT_APPEND_SECTION_TO_TARGET ; }
2015-11-15 21:14:46 -08:00
// if merging section is aligned and target section is not aligned to that or multiple of then can't merge
2017-01-08 16:30:30 -08:00
if ( m . align_address > 1 & & ( ! s . IsRelativeSection ( ) | | ( s . align_address % m . align_address ) ! = 0 ) ) {
2015-11-15 21:14:46 -08:00
return ERROR_CANT_APPEND_SECTION_TO_TARGET ;
2017-01-08 16:30:30 -08:00
}
2015-11-15 21:14:46 -08:00
2017-08-06 16:07:41 -07:00
m . merged_size = m . address - m . start_address ;
2015-11-15 21:14:46 -08:00
// append the binary to the target..
int addr_start = s . address ;
int align = m . align_address < = 1 ? 0 : ( m . align_address - ( addr_start % m . align_address ) ) % m . align_address ;
if ( m . size ( ) ) {
if ( s . CheckOutputCapacity ( m . size ( ) + align ) = = STATUS_OK ) {
2017-01-08 16:30:30 -08:00
for ( int a = 0 ; a < align ; a + + ) { s . AddByte ( 0 ) ; }
2015-11-15 21:14:46 -08:00
s . AddBin ( m . output , m . size ( ) ) ;
}
} else if ( m . addr_size ( ) & & s . type ! = ST_BSS & & s . type ! = ST_ZEROPAGE & & ! s . dummySection ) {
if ( s . CheckOutputCapacity ( m . address - m . start_address ) = = STATUS_OK ) {
2017-01-08 16:30:30 -08:00
for ( int a = ( m . start_address - align ) ; a < m . address ; a + + ) { s . AddByte ( 0 ) ; }
2015-11-15 21:14:46 -08:00
}
2017-01-08 16:30:30 -08:00
} else if ( m . addr_size ( ) ) { s . AddAddress ( align + m . addr_size ( ) ) ; }
addr_start + = align - s . start_address ;
2015-11-15 21:14:46 -08:00
2017-08-06 16:07:41 -07:00
// append info for result output
m . merged_at = addr_start ;
m . merged_into = section_id ;
2015-11-15 21:14:46 -08:00
// move the relocs from the merge section to the keep section
if ( m . pRelocs ) {
2017-01-08 16:30:30 -08:00
if ( ! s . pRelocs ) { s . pRelocs = new relocList ; }
if ( s . pRelocs - > capacity ( ) < ( s . pRelocs - > size ( ) + m . pRelocs - > size ( ) ) ) {
s . pRelocs - > reserve ( s . pRelocs - > size ( ) + m . pRelocs - > size ( ) ) ;
}
for ( relocList : : iterator r = m . pRelocs - > begin ( ) ; r ! = m . pRelocs - > end ( ) ; + + r ) {
2015-11-15 21:14:46 -08:00
struct Reloc rel = * r ;
rel . section_offset + = addr_start ;
s . pRelocs - > push_back ( rel ) ;
}
delete m . pRelocs ;
m . pRelocs = nullptr ;
}
// go through all the relocs referring to merging section and replace
for ( std : : vector < Section > : : iterator i = allSections . begin ( ) ; i ! = allSections . end ( ) ; + + i ) {
if ( relocList * pReloc = i - > pRelocs ) {
for ( relocList : : iterator r = pReloc - > begin ( ) ; r ! = pReloc - > end ( ) ; + + r ) {
if ( r - > target_section = = section_merge ) {
r - > base_value + = addr_start ;
r - > target_section = section_id ;
}
}
}
}
2017-01-08 16:30:30 -08:00
if ( ! s . IsRelativeSection ( ) ) { LinkLabelsToAddress ( section_merge , - 1 , m . start_address ) ; }
2015-11-15 21:14:46 -08:00
// go through all labels referencing merging section
2016-03-12 11:39:53 -08:00
for ( uint32_t i = 0 ; i < labels . count ( ) ; i + + ) {
2015-11-15 21:14:46 -08:00
Label & lab = labels . getValue ( i ) ;
if ( lab . section = = section_merge & & lab . evaluated ) {
lab . value + = addr_start ;
lab . section = section_id ;
}
}
// go through map symbols
for ( MapSymbolArray : : iterator i = map . begin ( ) ; i ! = map . end ( ) ; + + i ) {
if ( i - > section = = section_merge ) {
i - > value + = addr_start ;
2016-05-25 22:44:17 -07:00
i - > section = ( int16_t ) section_id ;
2015-11-15 21:14:46 -08:00
}
}
// go through all late evals referencing this section
for ( std : : vector < LateEval > : : iterator i = lateEval . begin ( ) ; i ! = lateEval . end ( ) ; + + i ) {
if ( i - > section = = section_merge ) {
2016-05-25 22:44:17 -07:00
i - > section = ( int16_t ) section_id ;
2017-01-08 16:30:30 -08:00
if ( i - > target > = 0 ) { i - > target + = addr_start ; }
2015-11-15 21:14:46 -08:00
i - > address + = addr_start ;
2017-01-08 16:30:30 -08:00
if ( i - > scope > = 0 ) { i - > scope + = addr_start ; }
2015-11-15 21:14:46 -08:00
}
}
// go through listing
if ( m . pListing ) {
2017-01-08 16:30:30 -08:00
if ( ! s . pListing ) { s . pListing = new Listing ; }
if ( s . pListing - > capacity ( ) < ( m . pListing - > size ( ) + s . pListing - > size ( ) ) ) {
s . pListing - > reserve ( ( m . pListing - > size ( ) + s . pListing - > size ( ) ) ) ;
}
2015-11-15 21:14:46 -08:00
for ( Listing : : iterator i = m . pListing - > begin ( ) ; i ! = m . pListing - > end ( ) ; + + i ) {
ListLine l = * i ;
l . address + = addr_start ;
s . pListing - > push_back ( l ) ;
}
delete m . pListing ;
m . pListing = nullptr ;
}
m . type = ST_REMOVED ;
return STATUS_OK ;
}
// Go through sections and merge same name sections together
2017-01-08 16:30:30 -08:00
StatusCode Asm : : MergeSectionsByName ( int first_section ) {
2015-11-15 21:14:46 -08:00
int first_code_seg = - 1 ;
StatusCode status = STATUS_OK ;
for ( std : : vector < Section > : : iterator i = allSections . begin ( ) ; i ! = allSections . end ( ) ; + + i ) {
if ( i - > type ! = ST_REMOVED ) {
if ( first_code_seg < 0 & & i - > type = = ST_CODE )
first_code_seg = ( int ) ( & * i - & allSections [ 0 ] ) ;
std : : vector < Section > : : iterator n = i ;
+ + n ;
while ( n ! = allSections . end ( ) ) {
if ( n - > name . same_str_case ( i - > name ) & & n - > type = = i - > type ) {
int sk = ( int ) ( & * i - & allSections [ 0 ] ) ;
int sm = ( int ) ( & * n - & allSections [ 0 ] ) ;
if ( sm = = first_section | | ( n - > align_address > i - > align_address ) ) {
2017-01-08 16:30:30 -08:00
if ( n - > align_address < i - > align_address ) { n - > align_address = i - > align_address ; }
2015-11-15 21:14:46 -08:00
status = MergeSections ( sm , sk ) ;
2017-01-08 16:30:30 -08:00
} else { status = MergeSections ( sk , sm ) ; }
if ( status ! = STATUS_OK ) { return status ; }
2015-11-15 21:14:46 -08:00
}
+ + n ;
}
}
}
return STATUS_OK ;
}
// Merge all sections in order of code, data, bss and make sure a specific section remains first
# define MERGE_ORDER_CNT (ST_BSS - ST_CODE+1)
StatusCode Asm : : MergeAllSections ( int first_section )
{
StatusCode status = STATUS_OK ;
// combine all sections by type first
for ( int t = ST_CODE ; t < ST_ZEROPAGE & & status = = STATUS_OK ; t + + ) {
for ( int i = 0 ; i < ( int ) allSections . size ( ) & & status = = STATUS_OK ; + + i ) {
if ( allSections [ i ] . type = = t ) {
for ( int j = i + 1 ; j < ( int ) allSections . size ( ) & & status = = STATUS_OK ; + + j ) {
if ( allSections [ j ] . type = = t ) {
if ( j = = first_section | | ( t ! = ST_CODE & & allSections [ i ] . align_address < allSections [ j ] . align_address ) ) {
2017-01-08 16:30:30 -08:00
if ( allSections [ i ] . align_address > allSections [ j ] . align_address ) {
2015-11-15 21:14:46 -08:00
allSections [ i ] . align_address = allSections [ j ] . align_address ;
2017-01-08 16:30:30 -08:00
}
2015-11-15 21:14:46 -08:00
status = MergeSections ( j , i ) ;
} else
status = MergeSections ( i , j ) ;
}
}
}
}
}
// then combine by category except zero page
int merge_order [ MERGE_ORDER_CNT ] = { - 1 } ;
for ( int t = ST_CODE ; t < = ST_BSS ; t + + ) {
for ( int i = 0 ; i < ( int ) allSections . size ( ) ; + + i ) {
if ( allSections [ i ] . type = = t ) {
merge_order [ t - ST_CODE ] = i ;
break ;
}
}
}
for ( int n = 1 ; n < MERGE_ORDER_CNT ; n + + ) {
if ( merge_order [ n ] = = - 1 ) {
for ( int m = n + 1 ; m < MERGE_ORDER_CNT ; m + + )
merge_order [ m - 1 ] = merge_order [ m ] ;
}
}
2017-01-08 16:30:30 -08:00
if ( merge_order [ 0 ] = = - 1 ) { return ERROR_NOT_A_SECTION ; }
2015-11-15 21:14:46 -08:00
for ( int o = 1 ; o < MERGE_ORDER_CNT ; o + + ) {
if ( merge_order [ o ] ! = - 1 & & status = = STATUS_OK ) {
2017-01-08 16:30:30 -08:00
if ( allSections [ merge_order [ 0 ] ] . align_address < allSections [ merge_order [ o ] ] . align_address ) {
2015-11-15 21:14:46 -08:00
allSections [ merge_order [ 0 ] ] . align_address = allSections [ merge_order [ o ] ] . align_address ;
2017-01-08 16:30:30 -08:00
}
2015-11-15 21:14:46 -08:00
status = MergeSections ( merge_order [ 0 ] , merge_order [ o ] ) ;
}
}
return status ;
}
2015-10-10 15:25:08 -07:00
// Section based output capacity
2015-09-29 22:07:04 -07:00
// Make sure there is room to assemble in
2016-03-12 11:39:53 -08:00
StatusCode Section : : CheckOutputCapacity ( uint32_t addSize ) {
2017-01-08 16:30:30 -08:00
if ( dummySection | | type = = ST_ZEROPAGE | | type = = ST_BSS ) { return STATUS_OK ; }
2015-09-29 22:07:04 -07:00
size_t currSize = curr - output ;
if ( ( addSize + currSize ) > = output_capacity ) {
size_t newSize = currSize * 2 ;
2017-01-08 16:30:30 -08:00
if ( newSize < 64 * 1024 ) { newSize = 64 * 1024 ; }
if ( ( addSize + currSize ) > newSize ) { newSize + = newSize ; }
2016-03-12 11:39:53 -08:00
if ( uint8_t * new_output = ( uint8_t * ) malloc ( newSize ) ) {
2015-11-15 21:14:46 -08:00
memcpy ( new_output , output , size ( ) ) ;
curr = new_output + ( curr - output ) ;
free ( output ) ;
output = new_output ;
output_capacity = newSize ;
2017-01-08 16:30:30 -08:00
} else { return ERROR_OUT_OF_MEMORY ; }
2015-09-29 22:07:04 -07:00
}
2015-11-15 21:14:46 -08:00
return STATUS_OK ;
2015-09-29 22:07:04 -07:00
}
2015-10-18 12:42:10 -07:00
// Add one byte to a section
2015-10-10 15:25:08 -07:00
void Section : : AddByte ( int b ) {
2015-11-07 18:23:57 -08:00
if ( ! dummySection & & type ! = ST_ZEROPAGE & & type ! = ST_BSS ) {
2017-01-08 16:30:30 -08:00
if ( CheckOutputCapacity ( 1 ) = = STATUS_OK ) { * curr + + = ( uint8_t ) b ; }
2015-10-10 15:25:08 -07:00
}
address + + ;
}
2015-10-18 12:42:10 -07:00
// Add a 16 bit word to a section
2015-10-10 15:25:08 -07:00
void Section : : AddWord ( int w ) {
2015-11-07 18:23:57 -08:00
if ( ! dummySection & & type ! = ST_ZEROPAGE & & type ! = ST_BSS ) {
2015-11-15 21:14:46 -08:00
if ( CheckOutputCapacity ( 2 ) = = STATUS_OK ) {
2016-03-12 11:39:53 -08:00
* curr + + = ( uint8_t ) ( w & 0xff ) ;
* curr + + = ( uint8_t ) ( w > > 8 ) ;
2015-11-15 21:14:46 -08:00
}
2015-10-10 15:25:08 -07:00
}
address + = 2 ;
}
2015-10-23 22:44:56 -07:00
// Add a 24 bit word to a section
void Section : : AddTriple ( int l ) {
2015-11-07 18:23:57 -08:00
if ( ! dummySection & & type ! = ST_ZEROPAGE & & type ! = ST_BSS ) {
2015-11-15 21:14:46 -08:00
if ( CheckOutputCapacity ( 3 ) = = STATUS_OK ) {
2016-03-12 11:39:53 -08:00
* curr + + = ( uint8_t ) ( l & 0xff ) ;
* curr + + = ( uint8_t ) ( l > > 8 ) ;
* curr + + = ( uint8_t ) ( l > > 16 ) ;
2015-11-15 21:14:46 -08:00
}
2015-10-23 22:44:56 -07:00
}
address + = 3 ;
}
2015-10-18 12:42:10 -07:00
// Add arbitrary length data to a section
2016-03-12 11:39:53 -08:00
void Section : : AddBin ( const uint8_t * p , int size ) {
2015-11-07 18:23:57 -08:00
if ( ! dummySection & & type ! = ST_ZEROPAGE & & type ! = ST_BSS ) {
2015-11-15 21:14:46 -08:00
if ( CheckOutputCapacity ( size ) = = STATUS_OK ) {
memcpy ( curr , p , size ) ;
curr + = size ;
}
2015-10-10 15:25:08 -07:00
}
address + = size ;
}
2015-10-25 14:29:41 -07:00
// Add text data to a section
void Section : : AddText ( strref line , strref text_prefix ) {
// https://en.wikipedia.org/wiki/PETSCII
// ascii: no change
// shifted: a-z => $41.. A-Z => $61..
// unshifted: a-z, A-Z => $41
2016-05-20 22:48:13 -07:00
if ( CheckOutputCapacity ( ( uint32_t ) line . get_len ( ) ) = = STATUS_OK ) {
2015-10-25 14:29:41 -07:00
if ( ! text_prefix | | text_prefix . same_str ( " ascii " ) ) {
2016-05-20 22:48:13 -07:00
AddBin ( ( const uint8_t * ) line . get ( ) , ( int ) line . get_len ( ) ) ;
2015-10-25 14:29:41 -07:00
} else if ( text_prefix . same_str ( " petscii " ) ) {
while ( line ) {
char c = line [ 0 ] ;
AddByte ( ( c > = ' a ' & & c < = ' z ' ) ? ( c - ' a ' + ' A ' ) : ( c > 0x60 ? ' ' : line [ 0 ] ) ) ;
+ + line ;
}
} else if ( text_prefix . same_str ( " petscii_shifted " ) ) {
while ( line ) {
char c = line [ 0 ] ;
AddByte ( ( c > = ' a ' & & c < = ' z ' ) ? ( c - ' a ' + 0x61 ) :
( ( c > = ' A ' & & c < = ' Z ' ) ? ( c - ' A ' + 0x61 ) : ( c > 0x60 ? ' ' : line [ 0 ] ) ) ) ;
+ + line ;
}
}
}
}
2017-01-08 16:30:30 -08:00
void Section : : AddIndexText ( StringSymbol * strSym , strref text ) {
if ( CheckOutputCapacity ( ( uint32_t ) text . get_len ( ) ) = = STATUS_OK ) {
const strref lookup = strSym - > get ( ) ;
while ( text ) {
char c = text . pop_first ( ) ;
AddByte ( lookup . find ( c ) ) ;
}
}
}
2015-10-18 12:42:10 -07:00
// Add a relocation marker to a section
2016-03-12 11:39:53 -08:00
void Section : : AddReloc ( int base , int offset , int section , int8_t bytes , int8_t shift )
2015-10-10 15:25:08 -07:00
{
2017-01-08 16:30:30 -08:00
if ( ! pRelocs ) { pRelocs = new relocList ; }
if ( pRelocs - > size ( ) = = pRelocs - > capacity ( ) ) {
pRelocs - > reserve ( pRelocs - > size ( ) + 32 ) ;
}
2015-11-05 21:23:38 -08:00
pRelocs - > push_back ( Reloc ( base , offset , section , bytes , shift ) ) ;
2015-10-10 15:25:08 -07:00
}
// Make sure there is room to assemble in
2016-03-12 11:39:53 -08:00
StatusCode Asm : : CheckOutputCapacity ( uint32_t addSize ) {
2015-11-15 21:14:46 -08:00
return CurrSection ( ) . CheckOutputCapacity ( addSize ) ;
2015-10-10 15:25:08 -07:00
}
2015-10-25 23:48:35 -07:00
//
//
// SCOPE MANAGEMENT
//
//
2017-01-08 16:30:30 -08:00
StatusCode Asm : : EnterScope ( ) {
if ( scope_depth > = ( MAX_SCOPE_DEPTH - 1 ) ) { return ERROR_TOO_DEEP_SCOPE ; }
2015-10-25 23:48:35 -07:00
scope_address [ + + scope_depth ] = CurrSection ( ) . GetPC ( ) ;
return STATUS_OK ;
}
StatusCode Asm : : ExitScope ( )
{
CheckLateEval ( strref ( ) , CurrSection ( ) . GetPC ( ) ) ;
2016-03-11 17:08:44 -08:00
StatusCode error = FlushLocalLabels ( scope_depth ) ;
2017-01-08 16:30:30 -08:00
if ( error > = FIRST_ERROR ) { return error ; }
2015-10-25 23:48:35 -07:00
- - scope_depth ;
2017-01-08 16:30:30 -08:00
if ( scope_depth < 0 ) { return ERROR_UNBALANCED_SCOPE_CLOSURE ; }
2015-10-25 23:48:35 -07:00
return STATUS_OK ;
}
2015-12-01 21:21:00 -08:00
//
//
// CONTEXT ISOLATION
//
//
StatusCode Asm : : PushContext ( strref src_name , strref src_file , strref code_seg , int rept )
{
2017-01-08 16:30:30 -08:00
if ( conditional_depth > = ( MAX_CONDITIONAL_DEPTH - 1 ) ) { return ERROR_CONDITION_TOO_NESTED ; }
2015-12-01 21:21:00 -08:00
conditional_depth + + ;
conditional_nesting [ conditional_depth ] = 0 ;
conditional_consumed [ conditional_depth ] = false ;
contextStack . push ( src_name , src_file , code_seg , rept ) ;
2016-05-25 22:44:17 -07:00
contextStack . curr ( ) . conditional_ctx = ( int16_t ) conditional_depth ;
2017-01-08 16:30:30 -08:00
if ( scope_depth > = ( MAX_SCOPE_DEPTH - 1 ) ) {
2016-03-13 18:16:43 -07:00
return ERROR_TOO_DEEP_SCOPE ;
2017-01-08 16:30:30 -08:00
} else {
2016-03-13 18:16:43 -07:00
scope_address [ + + scope_depth ] = CurrSection ( ) . GetPC ( ) ;
2017-01-08 16:30:30 -08:00
}
2015-12-01 21:21:00 -08:00
return STATUS_OK ;
}
2017-01-08 16:30:30 -08:00
StatusCode Asm : : PopContext ( ) {
2016-03-13 18:16:43 -07:00
if ( scope_depth ) {
2015-12-01 21:21:00 -08:00
StatusCode ret = ExitScope ( ) ;
2017-01-08 16:30:30 -08:00
if ( ret ! = STATUS_OK ) { return ret ; }
2015-12-01 21:21:00 -08:00
}
2017-01-08 16:30:30 -08:00
if ( ! ConditionalAsm ( ) | | ConditionalConsumed ( ) | |
conditional_depth ! = contextStack . curr ( ) . conditional_ctx ) {
2015-12-01 21:21:00 -08:00
return ERROR_UNTERMINATED_CONDITION ;
2017-01-08 16:30:30 -08:00
}
2015-12-01 21:21:00 -08:00
conditional_depth = contextStack . curr ( ) . conditional_ctx - 1 ;
contextStack . pop ( ) ;
return STATUS_OK ;
}
2015-10-02 20:57:50 -07:00
//
//
// MACROS
//
//
2015-09-29 22:07:04 -07:00
// add a custom macro
2015-10-04 14:05:38 -07:00
StatusCode Asm : : AddMacro ( strref macro , strref source_name , strref source_file , strref & left )
2015-10-20 22:28:53 -07:00
{ //
2015-10-24 13:41:11 -07:00
// Recommended macro syntax:
2015-10-20 22:28:53 -07:00
// macro name(optional params) { actual macro }
2015-10-24 13:41:11 -07:00
//
// -endm option macro syntax:
2015-11-15 21:14:46 -08:00
// macro name arg
// actual macro
// endmacro
2015-10-20 22:28:53 -07:00
//
2015-10-24 13:41:11 -07:00
// Merlin macro syntax: (TODO: ignore arguments and use ]1, ]2, etc.)
2015-11-15 21:14:46 -08:00
// name mac arg1 arg2
// actual macro
// [<<<]/[EOM]
2015-10-20 22:28:53 -07:00
//
strref name ;
bool params_first_line = false ;
2016-03-11 14:12:32 -08:00
if ( Merlin ( ) ) {
2015-10-20 22:28:53 -07:00
if ( Label * pLastLabel = GetLabel ( last_label ) ) {
2016-03-12 11:39:53 -08:00
labels . remove ( ( uint32_t ) ( pLastLabel - labels . getValues ( ) ) ) ;
2015-10-20 22:28:53 -07:00
name = last_label ;
last_label . clear ( ) ;
macro . skip_whitespace ( ) ;
2017-01-08 16:30:30 -08:00
if ( macro . get_first ( ) = = ' ; ' | | macro . has_prefix ( c_comment ) ) {
2015-10-20 22:28:53 -07:00
macro . line ( ) ;
2017-01-08 16:30:30 -08:00
} else {
2015-10-20 22:28:53 -07:00
params_first_line = true ;
2017-01-08 16:30:30 -08:00
}
} else { return ERROR_BAD_MACRO_FORMAT ; }
2015-10-20 22:28:53 -07:00
} else {
2015-12-02 22:16:31 -08:00
name = macro . split_range ( label_end_char_range ) ;
macro . skip_whitespace ( ) ;
2015-10-20 22:28:53 -07:00
strref left_line = macro . get_line ( ) ;
left_line . skip_whitespace ( ) ;
left_line = left_line . before_or_full ( ' ; ' ) . before_or_full ( c_comment ) ;
2017-01-08 16:30:30 -08:00
if ( left_line & & left_line [ 0 ] ! = ' ( ' & & left_line [ 0 ] ! = ' { ' ) {
2015-10-20 22:28:53 -07:00
params_first_line = true ;
2017-01-08 16:30:30 -08:00
}
2015-10-20 22:28:53 -07:00
}
2016-03-12 11:39:53 -08:00
uint32_t hash = name . fnv1a ( ) ;
uint32_t ins = FindLabelIndex ( hash , macros . getKeys ( ) , macros . count ( ) ) ;
2015-09-29 22:07:04 -07:00
Macro * pMacro = nullptr ;
while ( ins < macros . count ( ) & & macros . getKey ( ins ) = = hash ) {
if ( name . same_str_case ( macros . getValue ( ins ) . name ) ) {
pMacro = macros . getValues ( ) + ins ;
break ;
}
+ + ins ;
}
if ( ! pMacro ) {
macros . insert ( ins , hash ) ;
pMacro = macros . getValues ( ) + ins ;
}
pMacro - > name = name ;
2016-03-11 14:12:32 -08:00
if ( Merlin ( ) ) {
2015-10-20 22:28:53 -07:00
strref source = macro ;
while ( strref next_line = macro . line ( ) ) {
next_line = next_line . before_or_full ( ' ; ' ) ;
next_line = next_line . before_or_full ( c_comment ) ;
int term = next_line . find ( " <<< " ) ;
2017-01-08 16:30:30 -08:00
if ( term < 0 ) { term = next_line . find ( " EOM " ) ; }
2015-10-20 22:28:53 -07:00
if ( term > = 0 ) {
strl_t macro_len = strl_t ( next_line . get ( ) + term - source . get ( ) ) ;
source = source . get_substr ( 0 , macro_len ) ;
break ;
}
}
left = macro ;
pMacro - > macro = source ;
source . skip_whitespace ( ) ;
} else if ( end_macro_directive ) {
int f = - 1 ;
const strref endm ( " endm " ) ;
for ( ; ; ) {
f = macro . find ( endm , f + 1 ) ;
2017-01-08 16:30:30 -08:00
if ( f < 0 ) { return ERROR_BAD_MACRO_FORMAT ; }
if ( f = = 0 | | strref : : is_ws ( macro [ f - 1 ] ) ) { break ; }
2015-10-20 22:28:53 -07:00
}
pMacro - > macro = macro . get_substr ( 0 , f ) ;
macro + = f ;
macro . line ( ) ;
left = macro ;
} else {
int pos_bracket = macro . find ( ' { ' ) ;
if ( pos_bracket < 0 ) {
pMacro - > macro = strref ( ) ;
return ERROR_BAD_MACRO_FORMAT ;
}
strref source = macro + pos_bracket ;
strref macro_body = source . scoped_block_skip ( ) ;
pMacro - > macro = strref ( macro . get ( ) , pos_bracket + macro_body . get_len ( ) + 2 ) ;
source . skip_whitespace ( ) ;
left = source ;
2015-09-29 22:07:04 -07:00
}
pMacro - > source_name = source_name ;
pMacro - > source_file = source_file ;
2015-10-20 22:28:53 -07:00
pMacro - > params_first_line = params_first_line ;
2015-09-29 22:07:04 -07:00
return STATUS_OK ;
}
2015-10-02 20:57:50 -07:00
// Compile in a macro
2017-01-08 16:30:30 -08:00
StatusCode Asm : : BuildMacro ( Macro & m , strref arg_list ) {
2015-10-25 23:48:35 -07:00
strref macro_src = m . macro , params ;
if ( m . params_first_line ) {
2017-01-08 16:30:30 -08:00
if ( end_macro_directive | | Merlin ( ) ) {
2015-10-25 23:48:35 -07:00
params = macro_src . line ( ) ;
2017-01-08 16:30:30 -08:00
} else {
2015-10-25 23:48:35 -07:00
params = macro_src . before ( ' { ' ) ;
macro_src + = params . get_len ( ) ;
}
}
2017-01-08 16:30:30 -08:00
else { params = ( macro_src [ 0 ] = = ' ( ' ? macro_src . scoped_block_skip ( ) : strref ( ) ) ; }
2015-10-02 20:57:50 -07:00
params . trim_whitespace ( ) ;
arg_list . trim_whitespace ( ) ;
2016-03-11 14:12:32 -08:00
if ( Merlin ( ) ) {
2015-10-25 14:29:41 -07:00
// need to include comment field because separator is ;
if ( contextStack . curr ( ) . read_source . is_substr ( arg_list . get ( ) ) )
arg_list = ( contextStack . curr ( ) . read_source +
strl_t ( arg_list . get ( ) - contextStack . curr ( ) . read_source . get ( ) )
) . line ( ) ;
2015-10-25 23:48:35 -07:00
arg_list = arg_list . before_or_full ( c_comment ) . get_trimmed_ws ( ) ;
2015-10-25 14:29:41 -07:00
strref arg = arg_list ;
strown < 16 > tag ;
int t_max = 16 ;
int dSize = 0 ;
for ( int t = 1 ; t < t_max ; t + + ) {
tag . sprintf ( " ]%d " , t ) ;
strref a = arg . split_token_trim ( ' ; ' ) ;
if ( ! a ) {
t_max = t ;
break ;
}
int count = macro_src . substr_case_count ( tag . get_strref ( ) ) ;
dSize + = count * ( ( int ) a . get_len ( ) - ( int ) tag . get_len ( ) ) ;
}
2016-05-20 22:48:13 -07:00
int mac_size = ( int ) macro_src . get_len ( ) + dSize + 32 ;
2015-10-25 14:29:41 -07:00
if ( char * buffer = ( char * ) malloc ( mac_size ) ) {
loadedData . push_back ( buffer ) ;
strovl macexp ( buffer , mac_size ) ;
macexp . copy ( macro_src ) ;
arg = arg_list ;
2015-11-09 00:07:55 -08:00
if ( tag ) {
2016-03-17 00:05:36 -07:00
strref match ( " ]*{0-9} " ) ;
strl_t pos = 0 ;
2016-12-23 13:56:57 -08:00
while ( strref tag_mac = macexp . find_wildcard ( match , pos ) ) {
2016-03-17 00:05:36 -07:00
bool success = false ;
2016-12-23 13:56:57 -08:00
strl_t offs = strl_t ( tag_mac . get ( ) - macexp . get ( ) ) ;
2016-03-17 00:05:36 -07:00
if ( ! offs | | ! strref : : is_valid_label ( macexp [ offs ] ) ) {
2016-12-23 13:56:57 -08:00
int t = ( int ) ( tag_mac + 1 ) . atoi ( ) ;
2016-03-17 00:05:36 -07:00
strref args = arg ;
if ( t > 0 ) {
for ( int skip = 1 ; skip < t ; skip + + )
args . split_token_trim ( ' ; ' ) ;
strref a = args . split_token_trim ( ' ; ' ) ;
2016-12-23 13:56:57 -08:00
macexp . exchange ( offs , tag_mac . get_len ( ) , a ) ;
2016-03-17 00:07:15 -07:00
pos + = a . get_len ( ) ;
2016-03-17 00:05:36 -07:00
success = true ;
}
}
2017-01-08 16:30:30 -08:00
if ( ! success ) { return ERROR_MACRO_ARGUMENT ; }
2015-11-09 00:07:55 -08:00
}
2015-10-25 14:29:41 -07:00
}
2015-12-01 21:21:00 -08:00
PushContext ( m . source_name , macexp . get_strref ( ) , macexp . get_strref ( ) ) ;
2015-10-25 14:29:41 -07:00
return STATUS_OK ;
2017-01-08 16:30:30 -08:00
} else { return ERROR_OUT_OF_MEMORY_FOR_MACRO_EXPANSION ; }
2015-10-25 14:29:41 -07:00
} else if ( params ) {
2015-10-20 22:28:53 -07:00
if ( arg_list [ 0 ] = = ' ( ' )
arg_list = arg_list . scoped_block_skip ( ) ;
2015-10-02 20:57:50 -07:00
strref pchk = params ;
strref arg = arg_list ;
int dSize = 0 ;
2015-10-20 22:28:53 -07:00
char token = arg_list . find ( ' , ' ) > = 0 ? ' , ' : ' ' ;
char token_macro = m . params_first_line & & params . find ( ' , ' ) < 0 ? ' ' : ' , ' ;
while ( strref param = pchk . split_token_trim ( token_macro ) ) {
strref a = arg . split_token_trim ( token ) ;
2015-10-02 20:57:50 -07:00
if ( param . get_len ( ) < a . get_len ( ) ) {
int count = macro_src . substr_case_count ( param ) ;
dSize + = count * ( ( int ) a . get_len ( ) - ( int ) param . get_len ( ) ) ;
2015-09-29 22:07:04 -07:00
}
}
2016-05-20 22:48:13 -07:00
int mac_size = ( int ) macro_src . get_len ( ) + dSize + 32 ;
2015-10-02 20:57:50 -07:00
if ( char * buffer = ( char * ) malloc ( mac_size ) ) {
loadedData . push_back ( buffer ) ;
strovl macexp ( buffer , mac_size ) ;
macexp . copy ( macro_src ) ;
2015-10-20 22:28:53 -07:00
while ( strref param = params . split_token_trim ( token_macro ) ) {
strref a = arg_list . split_token_trim ( token ) ;
2015-10-25 23:48:35 -07:00
macexp . replace_bookend ( param , a , label_end_char_range ) ;
2015-10-02 20:57:50 -07:00
}
2015-12-01 21:21:00 -08:00
PushContext ( m . source_name , macexp . get_strref ( ) , macexp . get_strref ( ) ) ;
2015-10-25 14:29:41 -07:00
return STATUS_OK ;
2017-01-08 16:30:30 -08:00
} else { return ERROR_OUT_OF_MEMORY_FOR_MACRO_EXPANSION ; }
2015-09-29 22:07:04 -07:00
}
2015-12-01 21:21:00 -08:00
PushContext ( m . source_name , m . source_file , macro_src ) ;
2015-10-25 14:29:41 -07:00
return STATUS_OK ;
2015-09-29 22:07:04 -07:00
}
2015-10-04 14:05:38 -07:00
//
//
// STRUCTS AND ENUMS
//
//
2015-10-06 22:42:22 -07:00
// Enums are Structs in disguise
2017-01-08 16:30:30 -08:00
StatusCode Asm : : BuildEnum ( strref name , strref declaration ) {
2016-03-12 11:39:53 -08:00
uint32_t hash = name . fnv1a ( ) ;
uint32_t ins = FindLabelIndex ( hash , labelStructs . getKeys ( ) , labelStructs . count ( ) ) ;
2015-10-06 22:42:22 -07:00
LabelStruct * pEnum = nullptr ;
while ( ins < labelStructs . count ( ) & & labelStructs . getKey ( ins ) = = hash ) {
if ( name . same_str_case ( labelStructs . getValue ( ins ) . name ) ) {
pEnum = labelStructs . getValues ( ) + ins ;
break ;
}
+ + ins ;
}
2017-01-08 16:30:30 -08:00
if ( pEnum ) { return ERROR_STRUCT_ALREADY_DEFINED ; }
2015-10-06 22:42:22 -07:00
labelStructs . insert ( ins , hash ) ;
pEnum = labelStructs . getValues ( ) + ins ;
pEnum - > name = name ;
2016-03-12 11:39:53 -08:00
pEnum - > first_member = ( uint16_t ) structMembers . size ( ) ;
2015-10-06 22:42:22 -07:00
pEnum - > numMembers = 0 ;
pEnum - > size = 0 ; // enums are 0 sized
int value = 0 ;
2015-11-03 20:57:06 -08:00
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
2015-10-06 22:42:22 -07:00
while ( strref line = declaration . line ( ) ) {
line = line . before_or_full ( ' , ' ) ;
line . trim_whitespace ( ) ;
2016-12-23 13:56:57 -08:00
strref member_name = line . split_token_trim ( ' = ' ) ;
2015-10-31 00:35:25 -07:00
line = line . before_or_full ( ' ; ' ) . before_or_full ( c_comment ) . get_trimmed_ws ( ) ;
2015-10-06 22:42:22 -07:00
if ( line ) {
2015-10-16 20:27:56 -07:00
StatusCode error = EvalExpression ( line , etx , value ) ;
2017-01-08 16:30:30 -08:00
if ( error = = STATUS_NOT_READY | | error = = STATUS_XREF_DEPENDENT ) {
2015-10-06 22:42:22 -07:00
return ERROR_ENUM_CANT_BE_ASSEMBLED ;
2017-01-08 16:30:30 -08:00
} else if ( error ! = STATUS_OK ) { return error ; }
2015-10-06 22:42:22 -07:00
}
struct MemberOffset member ;
2016-05-25 22:44:17 -07:00
member . offset = ( uint16_t ) value ;
2016-12-23 13:56:57 -08:00
member . name = member_name ;
2015-10-06 22:42:22 -07:00
member . name_hash = member . name . fnv1a ( ) ;
member . sub_struct = strref ( ) ;
structMembers . push_back ( member ) ;
+ + value ;
pEnum - > numMembers + + ;
}
return STATUS_OK ;
}
2017-01-08 16:30:30 -08:00
StatusCode Asm : : BuildStruct ( strref name , strref declaration ) {
2016-03-12 11:39:53 -08:00
uint32_t hash = name . fnv1a ( ) ;
uint32_t ins = FindLabelIndex ( hash , labelStructs . getKeys ( ) , labelStructs . count ( ) ) ;
2015-10-04 14:05:38 -07:00
LabelStruct * pStruct = nullptr ;
while ( ins < labelStructs . count ( ) & & labelStructs . getKey ( ins ) = = hash ) {
if ( name . same_str_case ( labelStructs . getValue ( ins ) . name ) ) {
pStruct = labelStructs . getValues ( ) + ins ;
break ;
}
+ + ins ;
}
2017-01-08 16:30:30 -08:00
if ( pStruct ) { return ERROR_STRUCT_ALREADY_DEFINED ; }
2015-10-04 14:05:38 -07:00
labelStructs . insert ( ins , hash ) ;
pStruct = labelStructs . getValues ( ) + ins ;
pStruct - > name = name ;
2016-03-12 11:39:53 -08:00
pStruct - > first_member = ( uint16_t ) structMembers . size ( ) ;
2015-10-04 14:05:38 -07:00
2016-03-12 11:39:53 -08:00
uint32_t byte_hash = struct_byte . fnv1a ( ) ;
uint32_t word_hash = struct_word . fnv1a ( ) ;
uint16_t size = 0 ;
uint16_t member_count = 0 ;
2015-10-23 22:44:56 -07:00
2015-10-04 14:05:38 -07:00
while ( strref line = declaration . line ( ) ) {
line . trim_whitespace ( ) ;
strref type = line . split_label ( ) ;
2017-01-08 16:30:30 -08:00
if ( ! type ) { continue ; }
2015-10-04 14:05:38 -07:00
line . skip_whitespace ( ) ;
2016-03-12 11:39:53 -08:00
uint32_t type_hash = type . fnv1a ( ) ;
uint16_t type_size = 0 ;
2015-10-04 14:05:38 -07:00
LabelStruct * pSubStruct = nullptr ;
2017-01-08 16:30:30 -08:00
if ( type_hash = = byte_hash & & struct_byte . same_str_case ( type ) ) {
2015-10-04 14:05:38 -07:00
type_size = 1 ;
2017-01-08 16:30:30 -08:00
} else if ( type_hash = = word_hash & & struct_word . same_str_case ( type ) ) {
2015-10-04 14:05:38 -07:00
type_size = 2 ;
2017-01-08 16:30:30 -08:00
} else {
2016-03-12 11:39:53 -08:00
uint32_t index = FindLabelIndex ( type_hash , labelStructs . getKeys ( ) , labelStructs . count ( ) ) ;
2015-10-04 14:05:38 -07:00
while ( index < labelStructs . count ( ) & & labelStructs . getKey ( index ) = = type_hash ) {
if ( type . same_str_case ( labelStructs . getValue ( index ) . name ) ) {
pSubStruct = labelStructs . getValues ( ) + index ;
break ;
}
+ + index ;
}
if ( ! pSubStruct ) {
labelStructs . remove ( ins ) ;
return ERROR_REFERENCED_STRUCT_NOT_FOUND ;
}
type_size = pSubStruct - > size ;
}
2015-10-23 22:44:56 -07:00
2015-10-04 14:05:38 -07:00
// add the new member, don't grow vectors one at a time.
2017-01-08 16:30:30 -08:00
if ( structMembers . size ( ) = = structMembers . capacity ( ) ) {
structMembers . reserve ( structMembers . size ( ) + 64 ) ;
}
2015-10-04 14:05:38 -07:00
struct MemberOffset member ;
member . offset = size ;
member . name = line . get_label ( ) ;
member . name_hash = member . name . fnv1a ( ) ;
member . sub_struct = pSubStruct ? pSubStruct - > name : strref ( ) ;
structMembers . push_back ( member ) ;
size + = type_size ;
member_count + + ;
}
2017-01-08 16:30:30 -08:00
{ // add a trailing member of 0 bytes to access the size of the structure
2016-01-04 20:55:32 -08:00
struct MemberOffset bytes_member ;
bytes_member . offset = size ;
bytes_member . name = " bytes " ;
bytes_member . name_hash = bytes_member . name . fnv1a ( ) ;
bytes_member . sub_struct = strref ( ) ;
structMembers . push_back ( bytes_member ) ;
member_count + + ;
}
2015-10-04 14:05:38 -07:00
pStruct - > numMembers = member_count ;
pStruct - > size = size ;
return STATUS_OK ;
}
// Evaluate a struct offset as if it was a label
2017-01-08 16:30:30 -08:00
StatusCode Asm : : EvalStruct ( strref name , int & value ) {
2015-10-04 14:05:38 -07:00
LabelStruct * pStruct = nullptr ;
2016-03-12 11:39:53 -08:00
uint16_t offset = 0 ;
2015-10-04 14:05:38 -07:00
while ( strref struct_seg = name . split_token ( ' . ' ) ) {
strref sub_struct = struct_seg ;
2016-03-12 11:39:53 -08:00
uint32_t seg_hash = struct_seg . fnv1a ( ) ;
2015-10-04 14:05:38 -07:00
if ( pStruct ) {
struct MemberOffset * member = & structMembers [ pStruct - > first_member ] ;
bool found = false ;
2015-10-23 22:44:56 -07:00
for ( int i = 0 ; i < pStruct - > numMembers ; i + + ) {
2015-10-04 14:05:38 -07:00
if ( member - > name_hash = = seg_hash & & member - > name . same_str_case ( struct_seg ) ) {
offset + = member - > offset ;
sub_struct = member - > sub_struct ;
found = true ;
break ;
}
+ + member ;
}
2017-01-08 16:30:30 -08:00
if ( ! found ) { return ERROR_REFERENCED_STRUCT_NOT_FOUND ; }
2015-10-04 14:05:38 -07:00
}
if ( sub_struct ) {
2016-03-12 11:39:53 -08:00
uint32_t hash = sub_struct . fnv1a ( ) ;
uint32_t index = FindLabelIndex ( hash , labelStructs . getKeys ( ) , labelStructs . count ( ) ) ;
2015-10-04 14:05:38 -07:00
while ( index < labelStructs . count ( ) & & labelStructs . getKey ( index ) = = hash ) {
if ( sub_struct . same_str_case ( labelStructs . getValue ( index ) . name ) ) {
pStruct = labelStructs . getValues ( ) + index ;
break ;
}
+ + index ;
}
2017-01-08 16:30:30 -08:00
} else if ( name ) { return STATUS_NOT_STRUCT ; }
2015-10-04 14:05:38 -07:00
}
2017-01-08 16:30:30 -08:00
if ( pStruct = = nullptr ) { return STATUS_NOT_STRUCT ; }
2015-10-04 14:05:38 -07:00
value = offset ;
return STATUS_OK ;
}
2015-10-02 20:57:50 -07:00
//
//
// EXPRESSIONS AND LATE EVALUATION
//
//
2017-01-08 16:30:30 -08:00
int Asm : : ReptCnt ( ) const {
2015-11-03 20:57:06 -08:00
return contextStack . curr ( ) . repeat_total - contextStack . curr ( ) . repeat ;
}
2017-01-08 16:30:30 -08:00
void Asm : : SetEvalCtxDefaults ( struct EvalContext & etx ) {
2015-11-03 20:57:06 -08:00
etx . pc = CurrSection ( ) . GetPC ( ) ; // current address at point of eval
etx . scope_pc = scope_address [ scope_depth ] ; // current scope open at point of eval
etx . scope_end_pc = - 1 ; // late scope closure after eval
etx . scope_depth = scope_depth ; // scope depth for eval (must match current for scope_end_pc to eval)
etx . relative_section = - 1 ; // return can be relative to this section
etx . file_ref = - 1 ; // can access private label from this file or -1
2019-03-13 12:08:21 -07:00
etx . rept_cnt = contextStack . empty ( ) ? 0 : ReptCnt ( ) ; // current repeat counter
2015-11-03 20:57:06 -08:00
}
2015-10-10 15:25:08 -07:00
// Get a single token from a merlin expression
2017-01-08 16:30:30 -08:00
EvalOperator Asm : : RPNToken_Merlin ( strref & expression , const struct EvalContext & etx , EvalOperator prev_op , int16_t & section , int & value ) {
2015-10-10 15:25:08 -07:00
char c = expression . get_first ( ) ;
switch ( c ) {
2016-05-20 22:48:13 -07:00
case ' $ ' : + + expression ; value = ( int ) expression . ahextoui_skip ( ) ; return EVOP_VAL ;
2015-10-10 15:25:08 -07:00
case ' - ' : + + expression ; return EVOP_SUB ;
case ' + ' : + + expression ; return EVOP_ADD ;
case ' * ' : // asterisk means both multiply and current PC, disambiguate!
+ + expression ;
2017-01-08 16:30:30 -08:00
if ( expression [ 0 ] = = ' * ' ) return EVOP_STP ; // double asterisks indicates comment
else if ( prev_op = = EVOP_VAL | | prev_op = = EVOP_RPR ) return EVOP_MUL ;
2016-05-25 22:44:17 -07:00
value = etx . pc ; section = int16_t ( CurrSection ( ) . IsRelativeSection ( ) ? SectionId ( ) : - 1 ) ; return EVOP_VAL ;
2015-10-10 15:25:08 -07:00
case ' / ' : + + expression ; return EVOP_DIV ;
2017-01-08 16:30:30 -08:00
case ' > ' : if ( expression . get_len ( ) > = 2 & & expression [ 1 ] = = ' > ' ) { expression + = 2 ; return EVOP_SHR ; }
2015-10-23 22:44:56 -07:00
+ + expression ; return EVOP_HIB ;
2017-01-08 16:30:30 -08:00
case ' < ' : if ( expression . get_len ( ) > = 2 & & expression [ 1 ] = = ' < ' ) { expression + = 2 ; return EVOP_SHL ; }
2015-10-23 22:44:56 -07:00
+ + expression ; return EVOP_LOB ;
2015-10-10 15:25:08 -07:00
case ' % ' : // % means both binary and scope closure, disambiguate!
2017-01-08 16:30:30 -08:00
if ( expression [ 1 ] = = ' 0 ' | | expression [ 1 ] = = ' 1 ' ) {
+ + expression ; value = ( int ) expression . abinarytoui_skip ( ) ; return EVOP_VAL ;
}
if ( etx . scope_end_pc < 0 | | scope_depth ! = etx . scope_depth ) return EVOP_NRY ;
2016-05-25 22:44:17 -07:00
+ + expression ; value = etx . scope_end_pc ;
section = int16_t ( CurrSection ( ) . IsRelativeSection ( ) ? SectionId ( ) : - 1 ) ;
return EVOP_VAL ;
2015-10-10 15:25:08 -07:00
case ' | ' :
case ' . ' : + + expression ; return EVOP_OR ; // MERLIN: . is or, | is not used
2017-01-08 16:30:30 -08:00
case ' ^ ' : if ( prev_op = = EVOP_VAL | | prev_op = = EVOP_RPR ) { + + expression ; return EVOP_EOR ; }
2015-10-23 22:44:56 -07:00
+ + expression ; return EVOP_BAB ;
2015-10-10 15:25:08 -07:00
case ' & ' : + + expression ; return EVOP_AND ;
case ' ( ' : if ( prev_op ! = EVOP_VAL ) { + + expression ; return EVOP_LPR ; } return EVOP_STP ;
case ' ) ' : + + expression ; return EVOP_RPR ;
2017-01-08 16:30:30 -08:00
case ' " ' : if ( expression [ 2 ] = = ' " ' ) { value = expression [ 1 ] ; expression + = 3 ; return EVOP_VAL ; } return EVOP_STP ;
case ' \' ' : if ( expression [ 2 ] = = ' \' ' ) { value = expression [ 1 ] ; expression + = 3 ; return EVOP_VAL ; } return EVOP_STP ;
2015-10-10 15:25:08 -07:00
case ' , ' :
2017-01-08 16:30:30 -08:00
case ' ? ' : return EVOP_STP ;
}
if ( c = = ' ! ' & & ( prev_op = = EVOP_VAL | | prev_op = = EVOP_RPR ) ) { + + expression ; return EVOP_EOR ; }
else if ( c = = ' ! ' & & ! ( expression + 1 ) . len_label ( ) ) {
if ( etx . scope_pc < 0 ) return EVOP_NRY ; // ! by itself is current scope, !+label char is a local label
+ + expression ; value = etx . scope_pc ;
section = int16_t ( CurrSection ( ) . IsRelativeSection ( ) ? SectionId ( ) : - 1 ) ; return EVOP_VAL ;
} else if ( expression . match_chars_str ( " 0-9 " , " !a-zA-Z_ " ) ) {
if ( prev_op = = EVOP_VAL ) return EVOP_STP ; // value followed by value doesn't make sense, stop
value = expression . atoi_skip ( ) ; return EVOP_VAL ;
} else if ( c = = ' ! ' | | c = = ' ] ' | | c = = ' : ' | | strref : : is_valid_label ( c ) ) {
if ( prev_op = = EVOP_VAL ) return EVOP_STP ; // a value followed by a value does not make sense, probably start of a comment (ORCA/LISA?)
char e0 = expression [ 0 ] ;
int start_pos = ( e0 = = ' ] ' | | e0 = = ' : ' | | e0 = = ' ! ' | | e0 = = ' . ' ) ? 1 : 0 ;
strref label = expression . split_range_trim ( label_end_char_range_merlin , start_pos ) ;
Label * pLabel = pLabel = GetLabel ( label , etx . file_ref ) ;
if ( ! pLabel ) {
StatusCode ret = EvalStruct ( label , value ) ;
if ( ret = = STATUS_OK ) { return EVOP_VAL ; }
if ( ret ! = STATUS_NOT_STRUCT ) { return EVOP_ERR ; } // partial struct
2015-10-10 15:25:08 -07:00
}
2017-01-08 16:30:30 -08:00
if ( ! pLabel & & label . same_str ( " rept " ) ) { value = etx . rept_cnt ; return EVOP_VAL ; }
if ( ! pLabel | | ! pLabel - > evaluated ) { return EVOP_NRY ; } // this label could not be found (yet)
value = pLabel - > value ; section = int16_t ( pLabel - > section ) ; return EVOP_VAL ;
2015-10-10 15:25:08 -07:00
}
2017-01-08 16:30:30 -08:00
return EVOP_ERR ;
2015-10-10 15:25:08 -07:00
}
// Get a single token from most non-apple II assemblers
2016-03-12 11:39:53 -08:00
EvalOperator Asm : : RPNToken ( strref & exp , const struct EvalContext & etx , EvalOperator prev_op , int16_t & section , int & value , strref & subexp )
2015-10-10 15:25:08 -07:00
{
2015-10-25 23:48:35 -07:00
char c = exp . get_first ( ) ;
2015-10-10 15:25:08 -07:00
switch ( c ) {
2016-05-20 22:48:13 -07:00
case ' $ ' : + + exp ; value = ( int ) exp . ahextoui_skip ( ) ; return EVOP_VAL ;
2015-10-25 23:48:35 -07:00
case ' - ' : + + exp ; return EVOP_SUB ;
case ' + ' : + + exp ; return EVOP_ADD ;
2015-10-10 15:25:08 -07:00
case ' * ' : // asterisk means both multiply and current PC, disambiguate!
2015-10-25 23:48:35 -07:00
+ + exp ;
if ( exp [ 0 ] = = ' * ' ) return EVOP_STP ; // double asterisks indicates comment
2015-10-10 15:25:08 -07:00
else if ( prev_op = = EVOP_VAL | | prev_op = = EVOP_RPR ) return EVOP_MUL ;
2016-05-25 22:44:17 -07:00
value = etx . pc ; section = int16_t ( CurrSection ( ) . IsRelativeSection ( ) ? SectionId ( ) : - 1 ) ; return EVOP_VAL ;
2015-10-25 23:48:35 -07:00
case ' / ' : + + exp ; return EVOP_DIV ;
case ' = ' : if ( exp [ 1 ] = = ' = ' ) { exp + = 2 ; return EVOP_EQU ; } return EVOP_STP ;
case ' > ' : if ( exp . get_len ( ) > = 2 & & exp [ 1 ] = = ' > ' ) { exp + = 2 ; return EVOP_SHR ; }
if ( prev_op = = EVOP_VAL | | prev_op = = EVOP_RPR ) { + + exp ;
if ( exp [ 0 ] = = ' = ' ) { + + exp ; return EVOP_GTE ; } return EVOP_GT ; }
+ + exp ; return EVOP_HIB ;
2015-11-01 15:08:38 -08:00
case ' < ' : if ( exp . get_len ( ) > = 2 & & exp [ 1 ] = = ' < ' ) { exp + = 2 ; return EVOP_SHL ; }
2015-10-25 23:48:35 -07:00
if ( prev_op = = EVOP_VAL | | prev_op = = EVOP_RPR ) { + + exp ;
if ( exp [ 0 ] = = ' = ' ) { + + exp ; return EVOP_LTE ; } return EVOP_LT ; }
+ + exp ; return EVOP_LOB ;
2015-10-10 15:25:08 -07:00
case ' % ' : // % means both binary and scope closure, disambiguate!
2016-05-20 22:48:13 -07:00
if ( exp [ 1 ] = = ' 0 ' | | exp [ 1 ] = = ' 1 ' ) { + + exp ; value = ( int ) exp . abinarytoui_skip ( ) ; return EVOP_VAL ; }
2015-11-03 20:57:06 -08:00
if ( etx . scope_end_pc < 0 | | scope_depth ! = etx . scope_depth ) return EVOP_NRY ;
2016-05-25 22:44:17 -07:00
+ + exp ; value = etx . scope_end_pc ; section = int16_t ( CurrSection ( ) . IsRelativeSection ( ) ? SectionId ( ) : - 1 ) ; return EVOP_VAL ;
2015-10-25 23:48:35 -07:00
case ' | ' : + + exp ; return EVOP_OR ;
case ' ^ ' : if ( prev_op = = EVOP_VAL | | prev_op = = EVOP_RPR ) { + + exp ; return EVOP_EOR ; }
+ + exp ; return EVOP_BAB ;
case ' & ' : + + exp ; return EVOP_AND ;
case ' ( ' : if ( prev_op ! = EVOP_VAL ) { + + exp ; return EVOP_LPR ; } return EVOP_STP ;
case ' ) ' : + + exp ; return EVOP_RPR ;
2015-10-10 15:25:08 -07:00
case ' , ' :
2018-10-15 00:16:44 -07:00
case ' ? ' : return EVOP_STP ;
case ' \' ' : if ( exp [ 2 ] = = ' \' ' ) { value = exp [ 1 ] ; exp + = 3 ; return EVOP_VAL ; } return EVOP_STP ;
2017-01-08 16:30:30 -08:00
}
// ! by itself is current scope, !+label char is a local label
if ( c = = ' ! ' & & ! ( exp + 1 ) . len_label ( ) ) {
if ( etx . scope_pc < 0 ) return EVOP_NRY ;
+ + exp ; value = etx . scope_pc ;
section = int16_t ( CurrSection ( ) . IsRelativeSection ( ) ? SectionId ( ) : - 1 ) ; return EVOP_VAL ;
} else if ( exp . match_chars_str ( " 0-9 " , " !a-zA-Z_ " ) ) {
if ( prev_op = = EVOP_VAL ) return EVOP_STP ; // value followed by value doesn't make sense, stop
value = exp . atoi_skip ( ) ; return EVOP_VAL ;
} else if ( c = = ' ! ' | | c = = ' : ' | | c = = ' . ' | | c = = ' @ ' | | strref : : is_valid_label ( c ) ) {
if ( prev_op = = EVOP_VAL ) return EVOP_STP ; // a value followed by a value does not make sense, probably start of a comment (ORCA/LISA?)
char e0 = exp [ 0 ] ;
int start_pos = ( e0 = = ' : ' | | e0 = = ' ! ' | | e0 = = ' . ' ) ? 1 : 0 ;
strref label = exp . split_range_trim ( label_end_char_range , start_pos ) ;
Label * pLabel = pLabel = GetLabel ( label , etx . file_ref ) ;
if ( ! pLabel ) {
StatusCode ret = EvalStruct ( label , value ) ;
if ( ret = = STATUS_OK ) { return EVOP_VAL ; }
if ( ret ! = STATUS_NOT_STRUCT ) { return EVOP_ERR ; } // partial struct
2015-10-10 15:25:08 -07:00
}
2017-01-08 16:30:30 -08:00
if ( ! pLabel & & label . same_str ( " rept " ) ) { value = etx . rept_cnt ; return EVOP_VAL ; }
if ( ! pLabel ) { if ( StringSymbol * pStr = GetString ( label ) ) { subexp = pStr - > get ( ) ; return EVOP_EXP ; } }
if ( ! pLabel | | ! pLabel - > evaluated ) return EVOP_NRY ; // this label could not be found (yet)
value = pLabel - > value ; section = int16_t ( pLabel - > section ) ; return pLabel - > reference ? EVOP_XRF : EVOP_VAL ;
2015-10-10 15:25:08 -07:00
}
2017-01-08 16:30:30 -08:00
return EVOP_ERR ;
2015-10-10 15:25:08 -07:00
}
2015-09-29 22:07:04 -07:00
//
// EvalExpression
// Uses the Shunting Yard algorithm to convert to RPN first
// which makes the actual calculation trivial and avoids recursion.
// https://en.wikipedia.org/wiki/Shunting-yard_algorithm
//
// Return:
// STATUS_OK means value is completely evaluated
// STATUS_NOT_READY means value could not be evaluated right now
// ERROR_* means there is an error in the expression
//
2015-10-10 15:25:08 -07:00
// Max number of unresolved sections to evaluate in a single expression
# define MAX_EVAL_SECTIONS 4
2015-11-05 21:23:38 -08:00
// determine if a scalar can be a shift
2017-01-08 16:30:30 -08:00
static int mul_as_shift ( int scalar ) {
2015-11-05 21:23:38 -08:00
int shift = 0 ;
while ( scalar > 1 & & ( scalar & 1 ) = = 0 ) {
shift + + ;
scalar > > = 1 ;
}
return scalar = = 1 ? shift : 0 ;
}
2015-11-26 13:10:58 -08:00
# define MAX_EXPR_STACK 2
2015-10-16 20:27:56 -07:00
StatusCode Asm : : EvalExpression ( strref expression , const struct EvalContext & etx , int & result )
2015-09-29 22:07:04 -07:00
{
int numValues = 0 ;
int numOps = 0 ;
2015-11-26 13:10:58 -08:00
strref expression_stack [ MAX_EXPR_STACK ] ;
int exp_sp = 0 ;
2015-09-29 22:07:04 -07:00
char ops [ MAX_EVAL_OPER ] ; // RPN expression
int values [ MAX_EVAL_VALUES ] ; // RPN values (in order of RPN EVOP_VAL operations)
2016-03-12 11:39:53 -08:00
int16_t section_ids [ MAX_EVAL_SECTIONS ] ; // local index of each referenced section
int16_t section_val [ MAX_EVAL_VALUES ] = { 0 } ; // each value can be assigned to one section, or -1 if fixed
int16_t num_sections = 0 ; // number of sections in section_ids (normally 0 or 1, can be up to MAX_EVAL_SECTIONS)
2015-10-30 22:30:16 -07:00
bool xrefd = false ;
2015-10-04 14:05:38 -07:00
values [ 0 ] = 0 ; // Initialize RPN if no expression
2015-10-10 15:25:08 -07:00
{
int sp = 0 ;
char op_stack [ MAX_EVAL_OPER ] ;
EvalOperator prev_op = EVOP_NONE ;
expression . trim_whitespace ( ) ;
2015-11-26 13:10:58 -08:00
while ( expression | | exp_sp ) {
2015-10-10 15:25:08 -07:00
int value = 0 ;
2016-03-12 11:39:53 -08:00
int16_t section = - 1 , index_section = - 1 ;
2015-10-10 15:25:08 -07:00
EvalOperator op = EVOP_NONE ;
2015-11-26 13:10:58 -08:00
strref subexp ;
if ( ! expression & & exp_sp ) {
expression = expression_stack [ - - exp_sp ] ;
op = EVOP_RPR ;
2017-01-08 16:30:30 -08:00
} else if ( Merlin ( ) ) {
2015-10-16 20:27:56 -07:00
op = RPNToken_Merlin ( expression , etx , prev_op , section , value ) ;
2017-01-08 16:30:30 -08:00
} else {
2015-11-26 13:10:58 -08:00
op = RPNToken ( expression , etx , prev_op , section , value , subexp ) ;
2017-01-08 16:30:30 -08:00
}
if ( op = = EVOP_ERR ) { return ERROR_UNEXPECTED_CHARACTER_IN_EXPRESSION ; }
else if ( op = = EVOP_NRY ) { return STATUS_NOT_READY ; }
2015-11-26 13:10:58 -08:00
else if ( op = = EVOP_EXP ) {
2017-01-08 16:30:30 -08:00
if ( exp_sp > = MAX_EXPR_STACK ) { return ERROR_TOO_MANY_VALUES_IN_EXPRESSION ; }
2015-11-26 13:10:58 -08:00
expression_stack [ exp_sp + + ] = expression ;
expression = subexp ;
op = EVOP_LPR ;
} else if ( op = = EVOP_XRF ) {
2015-10-30 22:30:16 -07:00
xrefd = true ;
op = EVOP_VAL ;
}
2015-10-10 15:25:08 -07:00
if ( section > = 0 ) {
2015-10-10 17:53:15 -07:00
for ( int s = 0 ; s < num_sections & & index_section < 0 ; s + + ) {
2017-01-08 16:30:30 -08:00
if ( section_ids [ s ] = = section ) { index_section = ( int16_t ) s ; }
2015-10-10 17:53:15 -07:00
}
if ( index_section < 0 ) {
2017-01-08 16:30:30 -08:00
if ( num_sections < = MAX_EVAL_SECTIONS ) {
2015-10-10 17:53:15 -07:00
section_ids [ index_section = num_sections + + ] = section ;
2017-01-08 16:30:30 -08:00
} else { return STATUS_NOT_READY ; }
2015-10-06 22:42:22 -07:00
}
2015-10-10 15:25:08 -07:00
}
// this is the body of the shunting yard algorithm
if ( op = = EVOP_VAL ) {
section_val [ numValues ] = index_section ; // only value operators can be section specific
values [ numValues + + ] = value ;
2016-05-25 22:44:17 -07:00
ops [ numOps + + ] = ( char ) op ;
2015-10-10 15:25:08 -07:00
} else if ( op = = EVOP_LPR ) {
2016-05-25 22:44:17 -07:00
op_stack [ sp + + ] = ( char ) op ;
2015-10-10 15:25:08 -07:00
} else if ( op = = EVOP_RPR ) {
while ( sp & & op_stack [ sp - 1 ] ! = EVOP_LPR ) {
sp - - ;
ops [ numOps + + ] = op_stack [ sp ] ;
2015-10-06 22:42:22 -07:00
}
2015-10-10 15:25:08 -07:00
// check that there actually was a left parenthesis
2017-01-08 16:30:30 -08:00
if ( ! sp | | op_stack [ sp - 1 ] ! = EVOP_LPR ) { return ERROR_UNBALANCED_RIGHT_PARENTHESIS ; }
2015-10-10 15:25:08 -07:00
sp - - ; // skip open paren
} else if ( op = = EVOP_STP ) {
2015-09-29 22:07:04 -07:00
break ;
2015-10-10 15:25:08 -07:00
} else {
2015-12-02 22:16:31 -08:00
bool skip = false ;
if ( ( prev_op > = EVOP_EQU & & prev_op < = EVOP_GTE ) | | ( prev_op = = EVOP_HIB | | prev_op = = EVOP_LOB ) ) {
2017-01-08 16:30:30 -08:00
if ( op = = EVOP_SUB ) { op = EVOP_NEG ; }
else if ( op = = EVOP_ADD ) { skip = true ; }
2015-12-02 22:16:31 -08:00
}
2017-01-08 16:30:30 -08:00
if ( op = = EVOP_SUB & & sp & & prev_op = = EVOP_SUB ) {
2015-10-10 15:25:08 -07:00
sp - - ;
2017-01-08 16:30:30 -08:00
} else {
2015-12-02 22:16:31 -08:00
while ( sp & & ! skip ) {
EvalOperator p = ( EvalOperator ) op_stack [ sp - 1 ] ;
2017-01-08 16:30:30 -08:00
if ( p = = EVOP_LPR | | op > p ) { break ; }
2016-05-25 22:44:17 -07:00
ops [ numOps + + ] = ( char ) p ;
2015-12-02 22:16:31 -08:00
sp - - ;
}
2016-05-25 22:44:17 -07:00
op_stack [ sp + + ] = ( char ) op ;
2015-10-10 15:25:08 -07:00
}
2015-09-29 22:07:04 -07:00
}
2015-10-10 15:25:08 -07:00
// check for out of bounds or unexpected input
2017-01-08 16:30:30 -08:00
if ( numValues = = MAX_EVAL_VALUES ) { return ERROR_TOO_MANY_VALUES_IN_EXPRESSION ; }
else if ( numOps = = MAX_EVAL_OPER | | sp = = MAX_EVAL_OPER ) {
2015-10-10 15:25:08 -07:00
return ERROR_TOO_MANY_OPERATORS_IN_EXPRESSION ;
2017-01-08 16:30:30 -08:00
}
2015-10-10 15:25:08 -07:00
prev_op = op ;
expression . skip_whitespace ( ) ;
2015-09-29 22:07:04 -07:00
}
2015-10-10 15:25:08 -07:00
while ( sp ) {
sp - - ;
ops [ numOps + + ] = op_stack [ sp ] ;
2015-09-29 22:07:04 -07:00
}
}
2015-10-30 22:30:16 -07:00
// Check if dependent on XREF'd symbol
2017-01-08 16:30:30 -08:00
if ( xrefd ) { return STATUS_XREF_DEPENDENT ; }
2015-10-30 22:30:16 -07:00
2015-10-02 20:57:50 -07:00
// processing the result RPN will put the completed expression into values[0].
// values is used as both the queue and the stack of values since reads/writes won't
// exceed itself.
2015-10-10 15:25:08 -07:00
{
int valIdx = 0 ;
int ri = 0 ; // RPN index (value)
2015-11-05 21:23:38 -08:00
int prev_val = values [ 0 ] ;
int shift_bits = 0 ; // special case for relative reference to low byte / high byte
2016-03-12 11:39:53 -08:00
int16_t section_counts [ MAX_EVAL_SECTIONS ] [ MAX_EVAL_VALUES ] = { 0 } ;
2015-10-10 15:25:08 -07:00
for ( int o = 0 ; o < numOps ; o + + ) {
EvalOperator op = ( EvalOperator ) ops [ o ] ;
2015-11-05 21:23:38 -08:00
shift_bits = 0 ;
prev_val = ri ? values [ ri - 1 ] : prev_val ;
2017-01-08 16:30:30 -08:00
if ( op ! = EVOP_VAL & & op ! = EVOP_LOB & & op ! = EVOP_HIB & & op ! = EVOP_BAB & & op ! = EVOP_SUB & & ri < 2 ) {
2015-10-10 15:25:08 -07:00
break ; // ignore suffix operations that are lacking values
2017-01-08 16:30:30 -08:00
}
2015-10-10 15:25:08 -07:00
switch ( op ) {
case EVOP_VAL : // value
2017-01-08 16:30:30 -08:00
for ( int i = 0 ; i < num_sections ; i + + ) { section_counts [ i ] [ ri ] = i = = section_val [ ri ] ? 1 : 0 ; }
2015-10-10 15:25:08 -07:00
values [ ri + + ] = values [ valIdx + + ] ; break ;
2015-10-25 23:48:35 -07:00
case EVOP_EQU : // ==
ri - - ;
values [ ri - 1 ] = values [ ri - 1 ] = = values [ ri ] ;
break ;
case EVOP_GT : // >
ri - - ;
values [ ri - 1 ] = values [ ri - 1 ] > values [ ri ] ;
break ;
case EVOP_LT : // <
ri - - ;
values [ ri - 1 ] = values [ ri - 1 ] < values [ ri ] ;
break ;
case EVOP_GTE : // >=
ri - - ;
values [ ri - 1 ] = values [ ri - 1 ] > = values [ ri ] ;
break ;
case EVOP_LTE : // >=
ri - - ;
values [ ri - 1 ] = values [ ri - 1 ] < = values [ ri ] ;
break ;
2015-10-10 15:25:08 -07:00
case EVOP_ADD : // +
ri - - ;
2017-01-08 16:30:30 -08:00
for ( int i = 0 ; i < num_sections ; i + + ) { section_counts [ i ] [ ri - 1 ] + = section_counts [ i ] [ ri ] ; }
2015-10-10 15:25:08 -07:00
values [ ri - 1 ] + = values [ ri ] ; break ;
case EVOP_SUB : // -
2017-01-08 16:30:30 -08:00
if ( ri = = 1 ) {
2015-10-20 22:28:53 -07:00
values [ ri - 1 ] = - values [ ri - 1 ] ;
2017-01-08 16:30:30 -08:00
} else if ( ri > 1 ) {
2015-10-20 22:28:53 -07:00
ri - - ;
2017-01-08 16:30:30 -08:00
for ( int i = 0 ; i < num_sections ; i + + ) { section_counts [ i ] [ ri - 1 ] - = section_counts [ i ] [ ri ] ; }
2015-10-20 22:28:53 -07:00
values [ ri - 1 ] - = values [ ri ] ;
} break ;
2015-12-02 22:16:31 -08:00
case EVOP_NEG :
2017-01-08 16:30:30 -08:00
if ( ri > = 1 ) { values [ ri - 1 ] = - values [ ri - 1 ] ; }
2015-12-02 22:16:31 -08:00
break ;
2015-10-10 15:25:08 -07:00
case EVOP_MUL : // *
ri - - ;
2017-01-08 16:30:30 -08:00
for ( int i = 0 ; i < num_sections ; i + + ) {
2015-10-10 15:25:08 -07:00
section_counts [ i ] [ ri - 1 ] | = section_counts [ i ] [ ri ] ;
2017-01-08 16:30:30 -08:00
}
2015-11-05 21:23:38 -08:00
shift_bits = mul_as_shift ( values [ ri ] ) ;
prev_val = values [ ri - 1 ] ;
2015-10-10 15:25:08 -07:00
values [ ri - 1 ] * = values [ ri ] ; break ;
case EVOP_DIV : // /
ri - - ;
2017-01-08 16:30:30 -08:00
for ( int i = 0 ; i < num_sections ; i + + ) {
2015-10-10 15:25:08 -07:00
section_counts [ i ] [ ri - 1 ] | = section_counts [ i ] [ ri ] ;
2017-01-08 16:30:30 -08:00
}
2015-11-05 21:23:38 -08:00
shift_bits = - mul_as_shift ( values [ ri ] ) ;
prev_val = values [ ri - 1 ] ;
values [ ri - 1 ] / = values [ ri ] ; break ;
2015-10-10 15:25:08 -07:00
case EVOP_AND : // &
ri - - ;
2017-01-08 16:30:30 -08:00
for ( int i = 0 ; i < num_sections ; i + + ) {
2015-10-10 15:25:08 -07:00
section_counts [ i ] [ ri - 1 ] | = section_counts [ i ] [ ri ] ;
2017-01-08 16:30:30 -08:00
}
2015-10-10 15:25:08 -07:00
values [ ri - 1 ] & = values [ ri ] ; break ;
case EVOP_OR : // |
ri - - ;
2017-01-08 16:30:30 -08:00
for ( int i = 0 ; i < num_sections ; i + + ) {
2015-10-10 15:25:08 -07:00
section_counts [ i ] [ ri - 1 ] | = section_counts [ i ] [ ri ] ;
2017-01-08 16:30:30 -08:00
}
2015-10-10 15:25:08 -07:00
values [ ri - 1 ] | = values [ ri ] ; break ;
case EVOP_EOR : // ^
ri - - ;
2017-01-08 16:30:30 -08:00
for ( int i = 0 ; i < num_sections ; i + + ) {
2015-10-10 15:25:08 -07:00
section_counts [ i ] [ ri - 1 ] | = section_counts [ i ] [ ri ] ;
2017-01-08 16:30:30 -08:00
}
2015-10-10 15:25:08 -07:00
values [ ri - 1 ] ^ = values [ ri ] ; break ;
case EVOP_SHL : // <<
ri - - ;
2017-01-08 16:30:30 -08:00
for ( int i = 0 ; i < num_sections ; i + + ) {
2015-10-10 15:25:08 -07:00
section_counts [ i ] [ ri - 1 ] | = section_counts [ i ] [ ri ] ;
2017-01-08 16:30:30 -08:00
}
2015-11-05 21:23:38 -08:00
shift_bits = values [ ri ] ;
prev_val = values [ ri - 1 ] ;
values [ ri - 1 ] < < = values [ ri ] ; break ;
2015-10-10 15:25:08 -07:00
case EVOP_SHR : // >>
ri - - ;
2017-01-08 16:30:30 -08:00
for ( int i = 0 ; i < num_sections ; i + + ) {
2015-10-10 15:25:08 -07:00
section_counts [ i ] [ ri - 1 ] | = section_counts [ i ] [ ri ] ;
2017-01-08 16:30:30 -08:00
}
2015-11-05 21:23:38 -08:00
shift_bits = - values [ ri ] ;
prev_val = values [ ri - 1 ] ;
values [ ri - 1 ] > > = values [ ri ] ; break ;
2015-10-10 15:25:08 -07:00
case EVOP_LOB : // low byte
2017-01-08 16:30:30 -08:00
if ( ri ) { values [ ri - 1 ] & = 0xff ; }
2015-11-05 21:23:38 -08:00
break ;
2015-10-10 15:25:08 -07:00
case EVOP_HIB :
2015-10-17 12:13:23 -07:00
if ( ri ) {
2015-11-05 21:23:38 -08:00
shift_bits = - 8 ;
values [ ri - 1 ] = values [ ri - 1 ] > > 8 ;
2015-10-17 12:13:23 -07:00
} break ;
2015-10-23 22:44:56 -07:00
case EVOP_BAB :
2015-11-05 21:23:38 -08:00
if ( ri ) {
shift_bits = - 16 ;
values [ ri - 1 ] = ( values [ ri - 1 ] > > 16 ) ;
}
2015-10-23 22:44:56 -07:00
break ;
2015-10-10 15:25:08 -07:00
default :
return ERROR_EXPRESSION_OPERATION ;
break ;
}
2017-01-08 16:30:30 -08:00
if ( shift_bits = = 0 & & ri ) { prev_val = values [ ri - 1 ] ; }
2015-10-10 15:25:08 -07:00
}
int section_index = - 1 ;
bool curr_relative = false ;
// If relative to any section unless specifically interested in a relative value then return not ready
for ( int i = 0 ; i < num_sections ; i + + ) {
if ( section_counts [ i ] [ 0 ] ) {
2017-01-08 16:30:30 -08:00
if ( section_counts [ i ] [ 0 ] ! = 1 | | section_index > = 0 ) {
2015-10-10 15:25:08 -07:00
return STATUS_NOT_READY ;
2017-01-08 16:30:30 -08:00
} else if ( etx . relative_section = = section_ids [ i ] ) {
2015-10-10 15:25:08 -07:00
curr_relative = true ;
2017-01-08 16:30:30 -08:00
} else if ( etx . relative_section > = 0 ) { return STATUS_NOT_READY ; }
2015-10-10 15:25:08 -07:00
section_index = i ;
}
}
result = values [ 0 ] ;
if ( section_index > = 0 & & ! curr_relative ) {
lastEvalSection = section_ids [ section_index ] ;
2015-11-05 21:23:38 -08:00
lastEvalValue = prev_val ;
2016-05-25 22:44:17 -07:00
lastEvalShift = ( int8_t ) shift_bits ;
2015-10-10 15:25:08 -07:00
return STATUS_RELATIVE_SECTION ;
2015-10-02 20:57:50 -07:00
}
}
return STATUS_OK ;
}
// if an expression could not be evaluated, add it along with
// the action to perform if it can be evaluated later.
2017-01-08 16:30:30 -08:00
void Asm : : AddLateEval ( int target , int pc , int scope_pc , strref expression , strref source_file , LateEval : : Type type ) {
2015-10-02 20:57:50 -07:00
LateEval le ;
le . address = pc ;
le . scope = scope_pc ;
2015-11-03 20:57:06 -08:00
le . scope_depth = scope_depth ;
2015-10-13 19:38:13 -07:00
le . target = target ;
2016-05-25 22:44:17 -07:00
le . section = ( int16_t ) ( & CurrSection ( ) - & allSections [ 0 ] ) ;
2015-11-02 23:14:01 -08:00
le . rept = contextStack . curr ( ) . repeat_total - contextStack . curr ( ) . repeat ;
2015-10-16 20:27:56 -07:00
le . file_ref = - 1 ; // current or xdef'd
2015-10-02 20:57:50 -07:00
le . label . clear ( ) ;
le . expression = expression ;
le . source_file = source_file ;
le . type = type ;
2015-10-13 19:38:13 -07:00
2015-10-02 20:57:50 -07:00
lateEval . push_back ( le ) ;
}
2017-01-08 16:30:30 -08:00
void Asm : : AddLateEval ( strref label , int pc , int scope_pc , strref expression , LateEval : : Type type ) {
2015-10-02 20:57:50 -07:00
LateEval le ;
le . address = pc ;
le . scope = scope_pc ;
2015-11-03 20:57:06 -08:00
le . scope_depth = scope_depth ;
2015-11-15 21:14:46 -08:00
le . target = - 1 ;
2015-10-02 20:57:50 -07:00
le . label = label ;
2016-05-25 22:44:17 -07:00
le . section = ( int16_t ) ( & CurrSection ( ) - & allSections [ 0 ] ) ;
2015-11-02 23:14:01 -08:00
le . rept = contextStack . curr ( ) . repeat_total - contextStack . curr ( ) . repeat ;
2015-10-16 20:27:56 -07:00
le . file_ref = - 1 ; // current or xdef'd
2015-10-02 20:57:50 -07:00
le . expression = expression ;
le . source_file . clear ( ) ;
le . type = type ;
2015-10-23 22:44:56 -07:00
2015-10-02 20:57:50 -07:00
lateEval . push_back ( le ) ;
}
// When a label is defined or a scope ends check if there are
// any related late label evaluators that can now be evaluated.
2017-01-08 16:30:30 -08:00
StatusCode Asm : : CheckLateEval ( strref added_label , int scope_end , bool print_missing_reference_errors ) {
2015-10-02 20:57:50 -07:00
bool evaluated_label = true ;
strref new_labels [ MAX_LABELS_EVAL_ALL ] ;
int num_new_labels = 0 ;
2017-01-08 16:30:30 -08:00
if ( added_label ) { new_labels [ num_new_labels + + ] = added_label ; }
2015-10-12 00:05:06 -07:00
bool all = ! added_label ;
2015-10-02 20:57:50 -07:00
while ( evaluated_label ) {
evaluated_label = false ;
2015-11-15 21:14:46 -08:00
std : : vector < LateEval > : : iterator i = lateEval . begin ( ) ;
2015-10-02 20:57:50 -07:00
while ( i ! = lateEval . end ( ) ) {
int value = 0 ;
// check if this expression is related to the late change (new label or end of scope)
2015-10-12 00:05:06 -07:00
bool check = all | | num_new_labels = = MAX_LABELS_EVAL_ALL ;
2015-10-23 22:44:56 -07:00
for ( int l = 0 ; l < num_new_labels & & ! check ; l + + )
2015-10-02 20:57:50 -07:00
check = i - > expression . find ( new_labels [ l ] ) > = 0 ;
if ( ! check & & scope_end > 0 ) {
int gt_pos = 0 ;
while ( gt_pos > = 0 & & ! check ) {
gt_pos = i - > expression . find_at ( ' % ' , gt_pos ) ;
if ( gt_pos > = 0 ) {
2017-01-08 16:30:30 -08:00
if ( i - > expression [ gt_pos + 1 ] = = ' % ' ) { gt_pos + + ; }
else { check = true ; }
2015-10-02 20:57:50 -07:00
gt_pos + + ;
}
}
}
if ( check ) {
2015-10-16 20:27:56 -07:00
struct EvalContext etx ( i - > address , i - > scope , scope_end ,
2015-11-03 20:57:06 -08:00
i - > type = = LateEval : : LET_BRANCH ? SectionId ( ) : - 1 , i - > rept ) ;
etx . scope_depth = i - > scope_depth ;
2015-10-16 20:27:56 -07:00
etx . file_ref = i - > file_ref ;
StatusCode ret = EvalExpression ( i - > expression , etx , value ) ;
2015-10-12 00:05:06 -07:00
if ( ret = = STATUS_OK | | ret = = STATUS_RELATIVE_SECTION ) {
2015-10-10 15:25:08 -07:00
// Check if target section merged with another section
2015-10-13 19:38:13 -07:00
int trg = i - > target ;
2015-10-10 15:25:08 -07:00
int sec = i - > section ;
if ( i - > type ! = LateEval : : LET_LABEL ) {
}
2015-10-12 00:05:06 -07:00
bool resolved = true ;
2015-10-02 20:57:50 -07:00
switch ( i - > type ) {
case LateEval : : LET_BYTE :
2015-10-12 00:05:06 -07:00
if ( ret = = STATUS_RELATIVE_SECTION ) {
2017-01-08 16:30:30 -08:00
if ( i - > section < 0 ) {
2015-10-12 00:05:06 -07:00
resolved = false ;
2017-01-08 16:30:30 -08:00
} else {
2015-11-05 21:23:38 -08:00
allSections [ sec ] . AddReloc ( lastEvalValue , trg , lastEvalSection , 1 , lastEvalShift ) ;
2015-10-12 00:05:06 -07:00
value = 0 ;
}
}
2017-01-08 16:30:30 -08:00
if ( trg > = allSections [ sec ] . size ( ) ) {
2015-10-15 20:58:17 -07:00
return ERROR_SECTION_TARGET_OFFSET_OUT_OF_RANGE ;
2017-01-08 16:30:30 -08:00
}
2015-10-10 15:25:08 -07:00
allSections [ sec ] . SetByte ( trg , value ) ;
2015-10-02 20:57:50 -07:00
break ;
2015-10-24 13:41:11 -07:00
2015-10-02 20:57:50 -07:00
case LateEval : : LET_ABS_REF :
2015-10-12 00:05:06 -07:00
if ( ret = = STATUS_RELATIVE_SECTION ) {
2017-01-08 16:30:30 -08:00
if ( i - > section < 0 ) {
2015-10-12 00:05:06 -07:00
resolved = false ;
2017-01-08 16:30:30 -08:00
} else {
2015-11-05 21:23:38 -08:00
allSections [ sec ] . AddReloc ( lastEvalValue , trg , lastEvalSection , 2 , lastEvalShift ) ;
2015-10-12 00:05:06 -07:00
value = 0 ;
}
}
2017-01-08 16:30:30 -08:00
if ( ( trg + 1 ) > = allSections [ sec ] . size ( ) ) {
2015-10-15 20:58:17 -07:00
return ERROR_SECTION_TARGET_OFFSET_OUT_OF_RANGE ;
2017-01-08 16:30:30 -08:00
}
2015-10-10 15:25:08 -07:00
allSections [ sec ] . SetWord ( trg , value ) ;
2015-10-02 20:57:50 -07:00
break ;
2015-10-24 13:41:11 -07:00
2015-10-23 22:44:56 -07:00
case LateEval : : LET_ABS_L_REF :
if ( ret = = STATUS_RELATIVE_SECTION ) {
2017-01-08 16:30:30 -08:00
if ( i - > section < 0 ) {
2015-10-23 22:44:56 -07:00
resolved = false ;
2017-01-08 16:30:30 -08:00
} else {
2015-11-05 21:23:38 -08:00
allSections [ sec ] . AddReloc ( lastEvalValue , trg , lastEvalSection , 3 , lastEvalShift ) ;
2015-10-23 22:44:56 -07:00
value = 0 ;
}
}
2017-01-08 16:30:30 -08:00
if ( ( trg + 2 ) > = allSections [ sec ] . size ( ) ) {
2015-10-23 22:44:56 -07:00
return ERROR_SECTION_TARGET_OFFSET_OUT_OF_RANGE ;
2017-01-08 16:30:30 -08:00
}
2015-10-23 22:44:56 -07:00
allSections [ sec ] . SetTriple ( trg , value ) ;
break ;
2015-10-24 13:41:11 -07:00
2015-10-26 20:50:26 -07:00
case LateEval : : LET_ABS_4_REF :
if ( ret = = STATUS_RELATIVE_SECTION ) {
2017-01-08 16:30:30 -08:00
if ( i - > section < 0 ) {
2015-10-26 20:50:26 -07:00
resolved = false ;
2017-01-08 16:30:30 -08:00
} else {
2015-11-05 21:23:38 -08:00
allSections [ sec ] . AddReloc ( lastEvalValue , trg , lastEvalSection , 4 , lastEvalShift ) ;
2015-10-26 20:50:26 -07:00
value = 0 ;
}
}
2017-01-08 16:30:30 -08:00
if ( ( trg + 3 ) > = allSections [ sec ] . size ( ) ) {
2015-10-26 20:50:26 -07:00
return ERROR_SECTION_TARGET_OFFSET_OUT_OF_RANGE ;
2017-01-08 16:30:30 -08:00
}
2015-10-26 20:50:26 -07:00
allSections [ sec ] . SetQuad ( trg , value ) ;
break ;
2015-10-24 13:41:11 -07:00
case LateEval : : LET_BRANCH :
value - = i - > address + 1 ;
if ( value < - 128 | | value > 127 ) {
i = lateEval . erase ( i ) ;
return ERROR_BRANCH_OUT_OF_RANGE ;
2017-01-08 16:30:30 -08:00
} if ( trg > = allSections [ sec ] . size ( ) ) {
2015-10-24 13:41:11 -07:00
return ERROR_SECTION_TARGET_OFFSET_OUT_OF_RANGE ;
2017-01-08 16:30:30 -08:00
}
2015-10-24 13:41:11 -07:00
allSections [ sec ] . SetByte ( trg , value ) ;
break ;
case LateEval : : LET_BRANCH_16 :
value - = i - > address + 2 ;
2017-01-08 16:30:30 -08:00
if ( trg > = allSections [ sec ] . size ( ) ) {
2015-10-24 13:41:11 -07:00
return ERROR_SECTION_TARGET_OFFSET_OUT_OF_RANGE ;
2017-01-08 16:30:30 -08:00
}
2015-10-24 13:41:11 -07:00
allSections [ sec ] . SetWord ( trg , value ) ;
break ;
2015-10-02 20:57:50 -07:00
case LateEval : : LET_LABEL : {
2015-10-16 20:27:56 -07:00
Label * label = GetLabel ( i - > label , i - > file_ref ) ;
2017-01-08 16:30:30 -08:00
if ( ! label ) { return ERROR_LABEL_MISPLACED_INTERNAL ; }
2015-10-02 20:57:50 -07:00
label - > value = value ;
label - > evaluated = true ;
2015-11-02 23:14:01 -08:00
label - > section = ret = = STATUS_RELATIVE_SECTION ? i - > section : - 1 ;
2017-01-08 16:30:30 -08:00
if ( num_new_labels < MAX_LABELS_EVAL_ALL ) {
2015-10-02 20:57:50 -07:00
new_labels [ num_new_labels + + ] = label - > label_name ;
2017-01-08 16:30:30 -08:00
}
2015-10-02 20:57:50 -07:00
evaluated_label = true ;
char f = i - > label [ 0 ] , l = i - > label . get_last ( ) ;
2015-10-06 22:42:22 -07:00
LabelAdded ( label , f = = ' . ' | | f = = ' ! ' | | f = = ' @ ' | | f = = ' : ' | | l = = ' $ ' ) ;
2015-10-02 20:57:50 -07:00
break ;
}
default :
break ;
}
2017-01-08 16:30:30 -08:00
if ( resolved ) { i = lateEval . erase ( i ) ; }
2015-10-30 22:30:16 -07:00
} else {
if ( print_missing_reference_errors & & ret ! = STATUS_XREF_DEPENDENT ) {
2017-01-28 13:29:42 -08:00
PrintError ( i - > expression , ret , i - > source_file ) ;
2015-10-30 22:30:16 -07:00
error_encountered = true ;
}
2015-10-02 20:57:50 -07:00
+ + i ;
2015-10-30 22:30:16 -07:00
}
2017-01-08 16:30:30 -08:00
} else { + + i ; }
2015-10-02 20:57:50 -07:00
}
2015-10-12 00:05:06 -07:00
all = false ;
2015-10-02 20:57:50 -07:00
added_label . clear ( ) ;
}
return STATUS_OK ;
}
//
//
// LABELS
//
//
2015-10-13 19:38:13 -07:00
// Get a label record if it exists
2017-01-08 16:30:30 -08:00
Label * Asm : : GetLabel ( strref label ) {
2016-03-12 11:39:53 -08:00
uint32_t label_hash = label . fnv1a ( ) ;
uint32_t index = FindLabelIndex ( label_hash , labels . getKeys ( ) , labels . count ( ) ) ;
2015-10-02 20:57:50 -07:00
while ( index < labels . count ( ) & & label_hash = = labels . getKey ( index ) ) {
2017-01-08 16:30:30 -08:00
if ( label . same_str ( labels . getValue ( index ) . label_name ) ) {
return labels . getValues ( ) + index ;
}
2015-10-02 20:57:50 -07:00
index + + ;
2015-09-29 22:07:04 -07:00
}
2015-10-02 20:57:50 -07:00
return nullptr ;
}
2015-09-29 22:07:04 -07:00
2015-10-16 20:27:56 -07:00
// Get a protected label record from a file if it exists
2017-01-08 16:30:30 -08:00
Label * Asm : : GetLabel ( strref label , int file_ref ) {
2015-10-16 20:27:56 -07:00
if ( file_ref > = 0 & & file_ref < ( int ) externals . size ( ) ) {
ExtLabels & labs = externals [ file_ref ] ;
2016-03-12 11:39:53 -08:00
uint32_t label_hash = label . fnv1a ( ) ;
uint32_t index = FindLabelIndex ( label_hash , labs . labels . getKeys ( ) , labs . labels . count ( ) ) ;
2015-10-16 20:27:56 -07:00
while ( index < labs . labels . count ( ) & & label_hash = = labs . labels . getKey ( index ) ) {
2017-01-08 16:30:30 -08:00
if ( label . same_str ( labs . labels . getValue ( index ) . label_name ) ) {
return labs . labels . getValues ( ) + index ;
}
2015-10-16 20:27:56 -07:00
index + + ;
}
}
return GetLabel ( label ) ;
}
2015-10-02 20:57:50 -07:00
// If exporting labels, append this label to the list
2017-01-08 16:30:30 -08:00
void Asm : : LabelAdded ( Label * pLabel , bool local ) {
2015-10-18 19:48:03 -07:00
if ( pLabel & & pLabel - > evaluated ) {
2017-01-08 16:30:30 -08:00
if ( map . size ( ) = = map . capacity ( ) ) {
map . reserve ( map . size ( ) + 256 ) ;
}
2015-10-23 22:44:56 -07:00
MapSymbol sym ;
sym . name = pLabel - > label_name ;
2016-05-25 22:44:17 -07:00
sym . section = ( int16_t ) ( pLabel - > section ) ;
2015-10-23 22:44:56 -07:00
sym . value = pLabel - > value ;
sym . local = local ;
2015-10-27 20:57:14 -07:00
pLabel - > mapIndex = pLabel - > evaluated ? - 1 : ( int ) map . size ( ) ;
2015-10-23 22:44:56 -07:00
map . push_back ( sym ) ;
2015-09-29 22:07:04 -07:00
}
}
// Add a label entry
2016-03-12 11:39:53 -08:00
Label * Asm : : AddLabel ( uint32_t hash ) {
uint32_t index = FindLabelIndex ( hash , labels . getKeys ( ) , labels . count ( ) ) ;
2015-09-29 22:07:04 -07:00
labels . insert ( index , hash ) ;
return labels . getValues ( ) + index ;
}
2015-10-01 23:16:36 -07:00
// mark a label as a local label
2017-01-08 16:30:30 -08:00
void Asm : : MarkLabelLocal ( strref label , bool scope_reserve ) {
2015-10-01 23:16:36 -07:00
LocalLabelRecord rec ;
rec . label = label ;
rec . scope_depth = scope_depth ;
rec . scope_reserve = scope_reserve ;
localLabels . push_back ( rec ) ;
}
// find all local labels or up to given scope level and remove them
2017-01-08 16:30:30 -08:00
StatusCode Asm : : FlushLocalLabels ( int scope_exit ) {
2015-10-21 22:34:01 -07:00
StatusCode status = STATUS_OK ;
2015-10-01 23:16:36 -07:00
// 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 ( ) ;
while ( i ! = localLabels . begin ( ) ) {
- - i ;
2017-01-08 16:30:30 -08:00
if ( i - > scope_depth < scope_depth ) { break ; }
2015-10-01 23:16:36 -07:00
strref label = i - > label ;
2015-10-21 22:34:01 -07:00
StatusCode this_status = CheckLateEval ( label ) ;
2017-01-08 16:30:30 -08:00
if ( this_status > FIRST_ERROR ) { status = this_status ; }
2015-10-01 23:16:36 -07:00
if ( ! i - > scope_reserve | | i - > scope_depth < = scope_exit ) {
2016-03-12 11:39:53 -08:00
uint32_t index = FindLabelIndex ( label . fnv1a ( ) , labels . getKeys ( ) , labels . count ( ) ) ;
2015-10-01 23:16:36 -07:00
while ( index < labels . count ( ) ) {
if ( label . same_str_case ( labels . getValue ( index ) . label_name ) ) {
labels . remove ( index ) ;
break ;
}
+ + index ;
}
i = localLabels . erase ( i ) ;
}
}
2015-10-21 22:34:01 -07:00
return status ;
2015-10-01 23:16:36 -07:00
}
// Get a label pool by name
2017-01-08 16:30:30 -08:00
LabelPool * Asm : : GetLabelPool ( strref pool_name ) {
2016-03-12 11:39:53 -08:00
uint32_t pool_hash = pool_name . fnv1a ( ) ;
uint32_t ins = FindLabelIndex ( pool_hash , labelPools . getKeys ( ) , labelPools . count ( ) ) ;
2015-10-01 23:16:36 -07:00
while ( ins < labelPools . count ( ) & & pool_hash = = labelPools . getKey ( ins ) ) {
if ( pool_name . same_str ( labelPools . getValue ( ins ) . pool_name ) ) {
return & labelPools . getValue ( ins ) ;
}
ins + + ;
}
return nullptr ;
}
// Add a label pool
2017-01-08 16:30:30 -08:00
StatusCode Asm : : AddLabelPool ( strref name , strref args ) {
2016-03-12 11:39:53 -08:00
uint32_t pool_hash = name . fnv1a ( ) ;
uint32_t ins = FindLabelIndex ( pool_hash , labelPools . getKeys ( ) , labelPools . count ( ) ) ;
uint32_t index = ins ;
2015-10-01 23:16:36 -07:00
while ( index < labelPools . count ( ) & & pool_hash = = labelPools . getKey ( index ) ) {
2017-01-08 16:30:30 -08:00
if ( name . same_str ( labelPools . getValue ( index ) . pool_name ) ) {
2015-10-01 23:16:36 -07:00
return ERROR_LABEL_POOL_REDECLARATION ;
2017-01-08 16:30:30 -08:00
}
2015-10-01 23:16:36 -07:00
index + + ;
}
// check that there is at least one valid address
int ranges = 0 ;
int num32 = 0 ;
2016-03-12 11:39:53 -08:00
uint16_t aRng [ 256 ] ;
2015-11-03 20:57:06 -08:00
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
2015-10-01 23:16:36 -07:00
while ( strref arg = args . split_token_trim ( ' , ' ) ) {
strref start = arg [ 0 ] = = ' ( ' ? arg . scoped_block_skip ( ) : arg . split_token_trim ( ' - ' ) ;
int addr0 = 0 , addr1 = 0 ;
2017-01-08 16:30:30 -08:00
if ( STATUS_OK ! = EvalExpression ( start , etx , addr0 ) ) {
2015-10-01 23:16:36 -07:00
return ERROR_POOL_RANGE_EXPRESSION_EVAL ;
2017-01-08 16:30:30 -08:00
}
if ( STATUS_OK ! = EvalExpression ( arg , etx , addr1 ) ) {
2015-10-01 23:16:36 -07:00
return ERROR_POOL_RANGE_EXPRESSION_EVAL ;
2017-01-08 16:30:30 -08:00
}
if ( addr1 < = addr0 | | addr0 < 0 ) {
2015-10-01 23:16:36 -07:00
return ERROR_POOL_RANGE_EXPRESSION_EVAL ;
2017-01-08 16:30:30 -08:00
}
2016-05-25 22:44:17 -07:00
aRng [ ranges + + ] = ( uint16_t ) addr0 ;
aRng [ ranges + + ] = ( uint16_t ) addr1 ;
2015-10-01 23:16:36 -07:00
num32 + = ( addr1 - addr0 + 15 ) > > 4 ;
2017-01-08 16:30:30 -08:00
if ( ranges > 2 | | num32 > ( ( MAX_POOL_BYTES + 15 ) > > 4 ) ) {
2015-10-01 23:16:36 -07:00
return ERROR_POOL_RANGE_EXPRESSION_EVAL ;
2017-01-08 16:30:30 -08:00
}
2015-10-01 23:16:36 -07:00
}
2017-01-08 16:30:30 -08:00
if ( ! ranges ) { return ERROR_POOL_RANGE_EXPRESSION_EVAL ; }
2015-10-01 23:16:36 -07:00
LabelPool pool ;
pool . pool_name = name ;
2016-05-25 22:44:17 -07:00
pool . numRanges = ( int16_t ) ( ranges > > 1 ) ;
2017-01-08 16:30:30 -08:00
pool . depth = 0 ;
pool . start = aRng [ 0 ] ;
pool . end = aRng [ 1 ] ;
2015-10-01 23:16:36 -07:00
labelPools . insert ( ins , pool_hash ) ;
LabelPool & poolValue = labelPools . getValue ( ins ) ;
poolValue = pool ;
return STATUS_OK ;
}
2016-12-24 13:23:01 -08:00
2017-01-08 16:30:30 -08:00
StatusCode Asm : : AssignPoolLabel ( LabelPool & pool , strref label ) {
if ( pool_subpool . is_prefix_word ( label ) ) { // declaring a pool within another pool?
2016-12-24 13:23:01 -08:00
label + = pool_subpool . get_len ( ) ;
label . skip_whitespace ( ) ;
strref size = label ;
label = size . split_label ( ) ;
if ( strref : : is_number ( size . get_first ( ) ) ) {
2017-01-08 16:30:30 -08:00
uint16_t bytes = ( uint16_t ) size . atoi ( ) ;
2016-12-24 13:23:01 -08:00
if ( ! bytes ) { return ERROR_POOL_RANGE_EXPRESSION_EVAL ; }
if ( ! GetLabelPool ( label ) ) {
2017-01-08 16:30:30 -08:00
uint16_t addr ;
StatusCode error = pool . Reserve ( bytes , addr , ( uint16_t ) brace_depth ) ;
2016-12-24 13:23:01 -08:00
if ( error = = STATUS_OK ) {
2017-01-08 16:30:30 -08:00
// permanently remove this chunk from the parent pool
pool . end = addr ;
pool . depth = 0 ;
2016-12-24 13:23:01 -08:00
uint32_t pool_hash = label . fnv1a ( ) ;
uint32_t ins = FindLabelIndex ( pool_hash , labelPools . getKeys ( ) , labelPools . count ( ) ) ;
labelPools . insert ( ins , pool_hash ) ;
LabelPool & subPool = labelPools . getValue ( ins ) ;
subPool . pool_name = label ;
subPool . numRanges = 1 ;
2017-01-08 16:30:30 -08:00
subPool . depth = 0 ;
subPool . start = addr ;
subPool . end = addr + bytes ;
2016-12-24 13:23:01 -08:00
}
return error ;
} else { return ERROR_LABEL_POOL_REDECLARATION ; }
}
return ERROR_POOL_RANGE_EXPRESSION_EVAL ;
}
2015-10-01 23:16:36 -07:00
strref type = label ;
2017-01-08 16:30:30 -08:00
uint16_t bytes = 1 ;
2016-12-23 13:56:57 -08:00
int sz = label . find_at ( ' . ' , 1 ) ;
if ( sz > 0 ) {
label = type . split ( sz ) ;
+ + type ;
2016-12-24 13:23:01 -08:00
if ( strref : : is_number ( type . get_first ( ) ) ) {
2017-01-08 16:30:30 -08:00
bytes = ( uint16_t ) type . atoi ( ) ;
2016-12-24 13:23:01 -08:00
} else {
switch ( strref : : tolower ( type . get_first ( ) ) ) {
case ' l ' : bytes = 4 ; break ;
case ' t ' : bytes = 3 ; break ;
case ' d ' :
case ' w ' : bytes = 2 ; break ;
}
2016-12-23 13:56:57 -08:00
}
}
if ( GetLabel ( label ) ) { return ERROR_POOL_LABEL_ALREADY_DEFINED ; }
2017-01-08 16:30:30 -08:00
uint16_t addr ;
StatusCode error = pool . Reserve ( bytes , addr , ( uint16_t ) brace_depth ) ;
if ( error ! = STATUS_OK ) { return error ; }
2015-10-01 23:16:36 -07:00
Label * pLabel = AddLabel ( label . fnv1a ( ) ) ;
pLabel - > label_name = label ;
2015-10-10 20:08:30 -07:00
pLabel - > pool_name = pool . pool_name ;
2015-10-01 23:16:36 -07:00
pLabel - > evaluated = true ;
2015-10-10 15:25:08 -07:00
pLabel - > section = - 1 ; // pool labels are section-less
2015-10-01 23:16:36 -07:00
pLabel - > value = addr ;
pLabel - > pc_relative = true ;
pLabel - > constant = true ;
2015-10-13 19:38:13 -07:00
pLabel - > external = false ;
2015-10-30 22:30:16 -07:00
pLabel - > reference = false ;
2017-01-08 16:30:30 -08:00
bool local = false ;
2015-10-01 23:16:36 -07:00
2016-12-23 13:56:57 -08:00
if ( label [ 0 ] = = ' . ' | | label [ 0 ] = = ' @ ' | | label [ 0 ] = = ' ! ' | | label [ 0 ] = = ' : ' | | label . get_last ( ) = = ' $ ' ) {
2017-01-08 16:30:30 -08:00
local = true ;
2016-12-23 13:56:57 -08:00
MarkLabelLocal ( label , true ) ;
}
2017-01-08 16:30:30 -08:00
LabelAdded ( pLabel , local ) ;
2015-10-01 23:16:36 -07:00
return error ;
}
// Request a label from a pool
2017-01-08 16:30:30 -08:00
StatusCode LabelPool : : Reserve ( uint16_t numBytes , uint16_t & ret_addr , uint16_t scope ) {
if ( numBytes > ( end - start ) | | depth = = MAX_SCOPE_DEPTH ) { return ERROR_OUT_OF_LABELS_IN_POOL ; }
if ( ! depth | | scope ! = scopeUsed [ depth - 1 ] [ 1 ] ) {
scopeUsed [ depth ] [ 0 ] = end ;
scopeUsed [ depth ] [ 1 ] = scope ;
+ + depth ;
}
end - = numBytes ;
ret_addr = end ;
2016-12-24 13:23:01 -08:00
return STATUS_OK ;
2015-10-01 23:16:36 -07:00
}
// Release a label from a pool (at scope closure)
2017-01-08 16:30:30 -08:00
void LabelPool : : ExitScope ( uint16_t scope ) {
if ( depth & & scopeUsed [ depth - 1 ] [ 1 ] = = scope ) {
end = scopeUsed [ - - depth ] [ 0 ] ;
2015-10-01 23:16:36 -07:00
}
}
2015-10-16 20:27:56 -07:00
// Check if a label is marked as an xdef
2017-01-08 16:30:30 -08:00
bool Asm : : MatchXDEF ( strref label ) {
2016-03-12 11:39:53 -08:00
uint32_t hash = label . fnv1a ( ) ;
uint32_t pos = FindLabelIndex ( hash , xdefs . getKeys ( ) , xdefs . count ( ) ) ;
2015-10-16 20:27:56 -07:00
while ( pos < xdefs . count ( ) & & xdefs . getKey ( pos ) = = hash ) {
2017-01-08 16:30:30 -08:00
if ( label . same_str_case ( xdefs . getValue ( pos ) ) ) { return true ; }
2015-10-16 20:27:56 -07:00
+ + pos ;
}
return false ;
}
2015-10-04 14:05:38 -07:00
// assignment of label (<label> = <expression>)
2017-01-08 16:30:30 -08:00
StatusCode Asm : : AssignLabel ( strref label , strref line , bool make_constant ) {
2015-10-04 14:05:38 -07:00
line . trim_whitespace ( ) ;
int val = 0 ;
2015-11-03 20:57:06 -08:00
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
2015-10-17 12:13:23 -07:00
StatusCode status = EvalExpression ( line , etx , val ) ;
2017-01-08 16:30:30 -08:00
if ( status ! = STATUS_NOT_READY & & status ! = STATUS_OK & & status ! = STATUS_RELATIVE_SECTION ) {
2015-10-04 14:05:38 -07:00
return status ;
2017-01-08 16:30:30 -08:00
}
2015-10-04 14:05:38 -07:00
Label * pLabel = GetLabel ( label ) ;
if ( pLabel ) {
2017-01-08 16:30:30 -08:00
if ( pLabel - > constant & & pLabel - > evaluated & & val ! = pLabel - > value ) {
return ( status = = STATUS_NOT_READY ) ? STATUS_OK : ERROR_MODIFYING_CONST_LABEL ;
}
} else { pLabel = AddLabel ( label . fnv1a ( ) ) ; }
2015-10-23 22:44:56 -07:00
2015-10-04 14:05:38 -07:00
pLabel - > label_name = label ;
2015-10-10 20:08:30 -07:00
pLabel - > pool_name . clear ( ) ;
2015-11-09 00:07:55 -08:00
pLabel - > evaluated = status = = STATUS_OK | | status = = STATUS_RELATIVE_SECTION ;
pLabel - > section = status = = STATUS_RELATIVE_SECTION ? lastEvalSection : - 1 ; // assigned labels are section-less
2015-10-04 14:05:38 -07:00
pLabel - > value = val ;
2015-10-23 22:44:56 -07:00
pLabel - > mapIndex = - 1 ;
2015-10-04 14:05:38 -07:00
pLabel - > pc_relative = false ;
pLabel - > constant = make_constant ;
2015-10-16 20:27:56 -07:00
pLabel - > external = MatchXDEF ( label ) ;
2015-10-30 22:30:16 -07:00
pLabel - > reference = false ;
2015-10-13 19:38:13 -07:00
2015-10-06 22:42:22 -07:00
bool local = label [ 0 ] = = ' . ' | | label [ 0 ] = = ' @ ' | | label [ 0 ] = = ' ! ' | | label [ 0 ] = = ' : ' | | label . get_last ( ) = = ' $ ' ;
2017-01-08 16:30:30 -08:00
if ( ! pLabel - > evaluated ) {
2015-10-10 15:25:08 -07:00
AddLateEval ( label , CurrSection ( ) . GetPC ( ) , scope_address [ scope_depth ] , line , LateEval : : LET_LABEL ) ;
2017-01-08 16:30:30 -08:00
} else {
if ( local ) { MarkLabelLocal ( label ) ; }
2015-10-04 14:05:38 -07:00
LabelAdded ( pLabel , local ) ;
return CheckLateEval ( label ) ;
}
return STATUS_OK ;
}
// Adding a fixed address label
StatusCode Asm : : AddressLabel ( strref label )
{
2015-10-21 22:34:01 -07:00
StatusCode status = STATUS_OK ;
2015-10-04 14:05:38 -07:00
Label * pLabel = GetLabel ( label ) ;
bool constLabel = false ;
2017-01-08 16:30:30 -08:00
if ( ! pLabel ) {
2015-10-04 14:05:38 -07:00
pLabel = AddLabel ( label . fnv1a ( ) ) ;
2017-01-08 16:30:30 -08:00
} else if ( pLabel - > constant & & pLabel - > value ! = CurrSection ( ) . GetPC ( ) ) {
2015-10-04 14:05:38 -07:00
return ERROR_MODIFYING_CONST_LABEL ;
2017-01-08 16:30:30 -08:00
} else { constLabel = pLabel - > constant ; }
2015-10-23 22:44:56 -07:00
2015-10-04 14:05:38 -07:00
pLabel - > label_name = label ;
2015-10-10 20:08:30 -07:00
pLabel - > pool_name . clear ( ) ;
2015-10-10 15:25:08 -07:00
pLabel - > section = CurrSection ( ) . IsRelativeSection ( ) ? SectionId ( ) : - 1 ; // address labels are based on section
pLabel - > value = CurrSection ( ) . GetPC ( ) ;
2015-10-04 14:05:38 -07:00
pLabel - > evaluated = true ;
pLabel - > pc_relative = true ;
2015-10-16 20:27:56 -07:00
pLabel - > external = MatchXDEF ( label ) ;
2015-10-30 22:30:16 -07:00
pLabel - > reference = false ;
2015-10-04 14:05:38 -07:00
pLabel - > constant = constLabel ;
2015-10-20 22:28:53 -07:00
last_label = label ;
2015-10-06 22:42:22 -07:00
bool local = label [ 0 ] = = ' . ' | | label [ 0 ] = = ' @ ' | | label [ 0 ] = = ' ! ' | | label [ 0 ] = = ' : ' | | label . get_last ( ) = = ' $ ' ;
2015-10-04 14:05:38 -07:00
LabelAdded ( pLabel , local ) ;
2017-01-08 16:30:30 -08:00
if ( local ) { MarkLabelLocal ( label ) ; }
2015-10-21 22:34:01 -07:00
status = CheckLateEval ( label ) ;
if ( ! local & & label [ 0 ] ! = ' ] ' ) { // MERLIN: Variable label does not invalidate local labels
StatusCode this_status = FlushLocalLabels ( ) ;
2017-01-08 16:30:30 -08:00
if ( status < FIRST_ERROR & & this_status > = FIRST_ERROR ) {
2015-10-21 22:34:01 -07:00
status = this_status ;
2017-01-08 16:30:30 -08:00
}
2015-10-21 22:34:01 -07:00
}
return status ;
2015-10-04 14:05:38 -07:00
}
// include symbols listed from a .sym file or all if no listing
2017-01-08 16:30:30 -08:00
StatusCode Asm : : IncludeSymbols ( strref line ) {
2015-10-04 14:05:38 -07:00
strref symlist = line . before ( ' " ' ) . get_trimmed_ws ( ) ;
line = line . between ( ' " ' , ' " ' ) ;
size_t size ;
if ( char * buffer = LoadText ( line , size ) ) {
strref symfile ( buffer , strl_t ( size ) ) ;
while ( symfile ) {
symfile . skip_whitespace ( ) ;
2016-02-14 12:36:01 -08:00
strref symstart = symfile ;
if ( strref symline = symfile . line ( ) ) {
int scope_start = symline . find ( ' { ' ) ;
2016-02-15 21:11:10 -08:00
if ( scope_start ! = 0 ) {
2016-02-14 12:36:01 -08:00
strref symdef = symline . get_substr ( 0 , scope_start ) ;
symdef . clip_trailing_whitespace ( ) ;
strref symtype = symdef . split_token ( ' ' ) ;
strref label = symdef . split_token_trim ( ' = ' ) ;
bool constant = symtype . same_str ( " .const " ) ; // first word is either .label or .const
if ( symlist ) {
strref symchk = symlist ;
while ( strref symwant = symchk . split_token_trim ( ' , ' ) ) {
if ( symwant . same_str_case ( label ) ) {
AssignLabel ( label , symdef , constant ) ;
break ;
}
2015-10-04 14:05:38 -07:00
}
2016-02-14 12:36:01 -08:00
} else
AssignLabel ( label , symdef , constant ) ;
}
if ( scope_start > = 0 ) {
symfile = symstart + scope_start ;
symfile . scoped_block_skip ( ) ;
}
2015-10-04 14:05:38 -07:00
}
}
loadedData . push_back ( buffer ) ;
2015-11-26 13:10:58 -08:00
} else
return ERROR_COULD_NOT_INCLUDE_FILE ;
return STATUS_OK ;
}
// Get a string record if it exists
StringSymbol * Asm : : GetString ( strref string_name )
{
2016-03-12 11:39:53 -08:00
uint32_t string_hash = string_name . fnv1a ( ) ;
uint32_t index = FindLabelIndex ( string_hash , strings . getKeys ( ) , strings . count ( ) ) ;
2015-11-26 13:10:58 -08:00
while ( index < strings . count ( ) & & string_hash = = strings . getKey ( index ) ) {
if ( string_name . same_str ( strings . getValue ( index ) . string_name ) )
return strings . getValues ( ) + index ;
index + + ;
}
return nullptr ;
}
// Add or modify a string record
StringSymbol * Asm : : AddString ( strref string_name , strref string_value )
{
StringSymbol * pStr = GetString ( string_name ) ;
if ( pStr = = nullptr ) {
2016-03-12 11:39:53 -08:00
uint32_t string_hash = string_name . fnv1a ( ) ;
uint32_t index = FindLabelIndex ( string_hash , strings . getKeys ( ) , strings . count ( ) ) ;
2015-11-26 13:10:58 -08:00
strings . insert ( index , string_hash ) ;
pStr = strings . getValues ( ) + index ;
pStr - > string_name = string_name ;
pStr - > string_value . invalidate ( ) ;
pStr - > string_value . clear ( ) ;
}
if ( pStr - > string_value . cap ( ) ) {
free ( pStr - > string_value . charstr ( ) ) ;
pStr - > string_value . invalidate ( ) ;
pStr - > string_value . clear ( ) ;
2015-10-04 14:05:38 -07:00
}
2015-11-26 13:10:58 -08:00
pStr - > string_const = string_value ;
return pStr ;
2015-10-04 14:05:38 -07:00
}
2015-11-26 13:10:58 -08:00
// append a string to another string
StatusCode StringSymbol : : Append ( strref append )
{
if ( ! append )
return STATUS_OK ;
2015-10-01 23:16:36 -07:00
2015-11-26 13:10:58 -08:00
strl_t add_len = append . get_len ( ) ;
if ( ! string_value . cap ( ) ) {
strl_t new_len = ( add_len + 0xff ) & ( ~ ( strl_t ) 0xff ) ;
char * buf = ( char * ) malloc ( new_len ) ;
if ( ! buf )
return ERROR_OUT_OF_MEMORY ;
string_value . set_overlay ( buf , new_len ) ;
string_value . copy ( string_const ) ;
} else if ( string_value . cap ( ) < ( string_value . get_len ( ) + add_len ) ) {
strl_t new_len = ( string_value . get_len ( ) + add_len + 0xff ) & ( ~ ( strl_t ) 0xff ) ;
char * buf = ( char * ) malloc ( new_len ) ;
if ( ! buf )
return ERROR_OUT_OF_MEMORY ;
strovl ovl ( buf , new_len ) ;
ovl . copy ( string_value . get_strref ( ) ) ;
free ( string_value . charstr ( ) ) ;
string_value . set_overlay ( buf , new_len ) ;
}
string_const . clear ( ) ;
string_value . append ( append ) ;
return STATUS_OK ;
}
StatusCode Asm : : ParseStringOp ( StringSymbol * pStr , strref line )
{
line . skip_whitespace ( ) ;
if ( line [ 0 ] = = ' + ' )
+ + line ;
for ( ; ; ) {
line . skip_whitespace ( ) ;
if ( line [ 0 ] = = ' " ' ) {
strref substr = line . between ( ' " ' , ' " ' ) ;
line + = substr . get_len ( ) + 2 ;
pStr - > Append ( substr ) ;
} else {
2016-03-11 14:12:32 -08:00
strref label = line . split_range ( Merlin ( ) ?
2015-11-26 13:10:58 -08:00
label_end_char_range_merlin : label_end_char_range ) ;
if ( StringSymbol * pStr2 = GetString ( label ) )
pStr - > Append ( pStr2 - > get ( ) ) ;
else if ( Label * pLabel = GetLabel ( label ) ) {
if ( ! pLabel - > evaluated )
return ERROR_TARGET_ADDRESS_MUST_EVALUATE_IMMEDIATELY ;
strown < 32 > lblstr ;
lblstr . sprintf ( " $%x " , pLabel - > value ) ;
pStr - > Append ( lblstr . get_strref ( ) ) ;
} else
break ;
}
line . skip_whitespace ( ) ;
if ( ! line | | line [ 0 ] ! = ' + ' )
break ;
+ + line ;
line . skip_whitespace ( ) ;
}
return STATUS_OK ;
}
StatusCode Asm : : StringAction ( StringSymbol * pStr , strref line )
{
line . skip_whitespace ( ) ;
if ( line [ 0 ] = = ' + ' & & line [ 1 ] = = ' = ' ) { // append strings
line + = 2 ;
line . skip_whitespace ( ) ;
return ParseStringOp ( pStr , line ) ;
} else if ( line [ 0 ] = = ' = ' ) {
+ + line ;
line . skip_whitespace ( ) ;
pStr - > clear ( ) ;
return ParseStringOp ( pStr , line ) ;
}
2017-01-08 16:30:30 -08:00
strref str = pStr - > string_value . valid ( ) ?
pStr - > string_value . get_strref ( ) : pStr - > string_const ;
if ( ! str ) { return STATUS_OK ; }
char * macro = ( char * ) malloc ( str . get_len ( ) ) ;
strovl mac ( macro , str . get_len ( ) ) ;
mac . copy ( str ) ;
mac . replace ( " \\ n " , " \n " ) ;
loadedData . push_back ( macro ) ;
PushContext ( contextStack . curr ( ) . source_name , mac . get_strref ( ) , mac . get_strref ( ) ) ;
2015-11-26 13:10:58 -08:00
return STATUS_OK ;
}
2015-10-01 23:16:36 -07:00
2015-10-02 20:57:50 -07:00
//
//
// CONDITIONAL ASSEMBLY
//
//
// Encountered #if or #ifdef, return true if assembly is enabled
bool Asm : : NewConditional ( ) {
if ( conditional_nesting [ conditional_depth ] ) {
conditional_nesting [ conditional_depth ] + + ;
return false ;
}
return true ;
}
// Encountered #endif, close out the current conditional
void Asm : : CloseConditional ( ) {
2015-12-01 21:21:00 -08:00
if ( conditional_depth > contextStack . curr ( ) . conditional_ctx )
2015-10-02 20:57:50 -07:00
conditional_depth - - ;
else
conditional_consumed [ conditional_depth ] = false ;
}
// Check if this conditional will nest the assembly (a conditional is already consumed)
void Asm : : CheckConditionalDepth ( ) {
if ( conditional_consumed [ conditional_depth ] ) {
conditional_depth + + ;
2015-10-19 22:44:02 -07:00
conditional_source [ conditional_depth ] = contextStack . curr ( ) . read_source . get_line ( ) ;
2015-10-02 20:57:50 -07:00
conditional_consumed [ conditional_depth ] = false ;
conditional_nesting [ conditional_depth ] = 0 ;
}
}
// This conditional block is going to be assembled, mark it as consumed
void Asm : : ConsumeConditional ( )
{
2015-10-19 22:44:02 -07:00
conditional_source [ conditional_depth ] = contextStack . curr ( ) . read_source . get_line ( ) ;
2015-10-02 20:57:50 -07:00
conditional_consumed [ conditional_depth ] = true ;
}
// This conditional block is not going to be assembled so mark that it is nesting
void Asm : : SetConditional ( )
{
2015-10-19 22:44:02 -07:00
conditional_source [ conditional_depth ] = contextStack . curr ( ) . read_source . get_line ( ) ;
2015-10-02 20:57:50 -07:00
conditional_nesting [ conditional_depth ] = 1 ;
}
// Returns true if assembly is currently enabled
bool Asm : : ConditionalAsm ( ) {
return conditional_nesting [ conditional_depth ] = = 0 ;
}
// Returns true if this conditional has a block that has already been assembled
bool Asm : : ConditionalConsumed ( ) {
return conditional_consumed [ conditional_depth ] ;
}
// Returns true if this conditional can be consumed
bool Asm : : ConditionalAvail ( ) {
return conditional_nesting [ conditional_depth ] = = 1 & &
! conditional_consumed [ conditional_depth ] ;
}
// This conditional block is enabled and the prior wasn't
void Asm : : EnableConditional ( bool enable ) {
if ( enable ) {
conditional_nesting [ conditional_depth ] = 0 ;
conditional_consumed [ conditional_depth ] = true ;
}
}
// Conditional else that does not enable block
2015-10-02 21:52:55 -07:00
void Asm : : ConditionalElse ( ) {
if ( conditional_consumed [ conditional_depth ] )
2015-10-02 20:57:50 -07:00
conditional_nesting [ conditional_depth ] + + ;
}
// Conditional statement evaluation (true/false)
StatusCode Asm : : EvalStatement ( strref line , bool & result )
{
2015-11-03 20:57:06 -08:00
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
2015-12-02 22:16:31 -08:00
bool invert = line . get_first ( ) = = ' ! ' ;
if ( invert )
+ + line ;
int value ;
if ( STATUS_OK ! = EvalExpression ( line , etx , value ) )
return ERROR_CONDITION_COULD_NOT_BE_RESOLVED ;
result = ( value ! = 0 & & ! invert ) | | ( value = = 0 & & invert ) ;
2015-10-02 20:57:50 -07:00
return STATUS_OK ;
}
2015-10-05 22:45:42 -07:00
// Add a folder for including files
void Asm : : AddIncludeFolder ( strref path )
{
if ( ! path )
return ;
2015-10-23 22:44:56 -07:00
for ( std : : vector < strref > : : const_iterator i = includePaths . begin ( ) ; i ! = includePaths . end ( ) ; + + i ) {
2015-10-05 22:45:42 -07:00
if ( path . same_str ( * i ) )
return ;
}
if ( includePaths . size ( ) = = includePaths . capacity ( ) )
includePaths . reserve ( includePaths . size ( ) + 16 ) ;
includePaths . push_back ( path ) ;
}
2015-10-02 20:57:50 -07:00
2015-09-29 22:07:04 -07:00
// unique key binary search
2016-03-12 11:39:53 -08:00
int LookupOpCodeIndex ( uint32_t hash , OPLookup * lookup , int count )
2015-09-29 22:07:04 -07:00
{
int first = 0 ;
while ( count ! = first ) {
int index = ( first + count ) / 2 ;
2016-03-12 11:39:53 -08:00
uint32_t read = lookup [ index ] . op_hash ;
2015-09-29 22:07:04 -07:00
if ( hash = = read ) {
return index ;
} else if ( hash > read )
first = index + 1 ;
else
count = index ;
}
return - 1 ; // index not found
}
2015-10-24 13:41:11 -07:00
// Encountered a REPT or LUP
2016-05-25 22:44:17 -07:00
StatusCode Asm : : Directive_Rept ( strref line )
2015-10-20 22:28:53 -07:00
{
SourceContext & ctx = contextStack . curr ( ) ;
strref read_source = ctx . read_source ;
if ( read_source . is_substr ( line . get ( ) ) ) {
read_source . skip ( strl_t ( line . get ( ) - read_source . get ( ) ) ) ;
strref expression ;
2016-03-11 14:12:32 -08:00
if ( Merlin ( ) | | end_macro_directive ) {
2015-10-20 22:28:53 -07:00
expression = line ; // Merlin repeat body begins next line
read_source . line ( ) ;
} else {
int block = read_source . find ( ' { ' ) ;
if ( block < 0 )
return ERROR_REPT_MISSING_SCOPE ;
expression = read_source . get_substr ( 0 , block ) ;
read_source + = block ;
read_source . skip_whitespace ( ) ;
}
expression . trim_whitespace ( ) ;
int count ;
2015-11-03 20:57:06 -08:00
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
2015-10-20 22:28:53 -07:00
if ( STATUS_OK ! = EvalExpression ( expression , etx , count ) )
return ERROR_REPT_COUNT_EXPRESSION ;
strref recur ;
2016-03-11 14:12:32 -08:00
if ( Merlin ( ) | | end_macro_directive ) {
2015-10-20 22:28:53 -07:00
recur = read_source ; // Merlin repeat body ends at "--^"
while ( strref next_line = read_source . line ( ) ) {
next_line = next_line . before_or_full ( ' ; ' ) ;
next_line = next_line . before_or_full ( c_comment ) ;
2015-10-25 14:29:41 -07:00
int term = next_line . find ( end_macro_directive ? " endr " : " --^ " ) ;
2015-10-20 22:28:53 -07:00
if ( term > = 0 ) {
recur = recur . get_substr ( 0 , strl_t ( next_line . get ( ) + term - recur . get ( ) ) ) ;
break ;
}
}
} else
recur = read_source . scoped_block_skip ( ) ;
ctx . next_source = read_source ;
2015-12-01 21:21:00 -08:00
PushContext ( ctx . source_name , ctx . source_file , recur , count ) ;
2015-10-20 22:28:53 -07:00
}
return STATUS_OK ;
}
// macro: create an assembler macro
2016-05-25 22:44:17 -07:00
StatusCode Asm : : Directive_Macro ( strref line )
2015-10-20 22:28:53 -07:00
{
2016-03-11 14:12:32 -08:00
strref read_source = contextStack . curr ( ) . read_source . get_skip_ws ( ) ;
if ( ! Merlin ( ) & & read_source . is_substr ( line . get ( ) ) )
2016-03-11 17:55:32 -08:00
read_source . skip ( strl_t ( line . get ( ) - read_source . get ( ) ) ) ;
2016-03-11 14:12:32 -08:00
if ( read_source ) {
2015-10-20 22:28:53 -07:00
StatusCode error = AddMacro ( read_source , contextStack . curr ( ) . source_name ,
2015-10-23 22:44:56 -07:00
contextStack . curr ( ) . source_file , read_source ) ;
2015-10-20 22:28:53 -07:00
contextStack . curr ( ) . next_source = read_source ;
return error ;
}
return STATUS_OK ;
}
2015-11-26 13:10:58 -08:00
// string: create a symbolic string
StatusCode Asm : : Directive_String ( strref line )
{
line . skip_whitespace ( ) ;
strref string_name = line . split_range_trim ( word_char_range , line [ 0 ] = = ' . ' ? 1 : 0 ) ;
if ( line [ 0 ] = = ' = ' | | keyword_equ . is_prefix_word ( line ) ) {
line . next_word_ws ( ) ;
strref substr = line ;
if ( line [ 0 ] = = ' " ' ) {
substr = line . between ( ' " ' , ' " ' ) ;
line + = substr . get_len ( ) + 2 ;
StringSymbol * pStr = AddString ( string_name , substr ) ;
if ( pStr = = nullptr )
return ERROR_OUT_OF_MEMORY ;
line . skip_whitespace ( ) ;
if ( line [ 0 ] = = ' + ' )
return ParseStringOp ( pStr , line ) ;
} else {
StringSymbol * pStr = AddString ( string_name , strref ( ) ) ;
return ParseStringOp ( pStr , line ) ;
}
} else {
if ( ! AddString ( string_name , strref ( ) ) )
return ERROR_OUT_OF_MEMORY ;
}
return STATUS_OK ;
}
StatusCode Asm : : Directive_Undef ( strref line )
{
2016-03-11 14:12:32 -08:00
strref name = line . split_range_trim ( Merlin ( ) ? label_end_char_range_merlin : label_end_char_range ) ;
2016-03-12 11:39:53 -08:00
uint32_t name_hash = name . fnv1a ( ) ;
uint32_t index = FindLabelIndex ( name_hash , labels . getKeys ( ) , labels . count ( ) ) ;
2015-11-26 13:10:58 -08:00
while ( index < labels . count ( ) & & name_hash = = labels . getKey ( index ) ) {
if ( name . same_str ( labels . getValue ( index ) . label_name ) ) {
labels . remove ( index ) ;
return STATUS_OK ;
}
index + + ;
}
index = FindLabelIndex ( name_hash , strings . getKeys ( ) , strings . count ( ) ) ;
while ( index < strings . count ( ) & & name_hash = = strings . getKey ( index ) ) {
if ( name . same_str ( strings . getValue ( index ) . string_name ) ) {
StringSymbol str = strings . getValue ( index ) ;
if ( str . string_value . cap ( ) ) {
free ( str . string_value . charstr ( ) ) ;
str . string_value . invalidate ( ) ;
}
strings . remove ( index ) ;
return STATUS_OK ;
}
index + + ;
}
return STATUS_OK ;
}
2015-10-25 14:29:41 -07:00
// include: read in a source file and assemble at this point
StatusCode Asm : : Directive_Include ( strref line )
{
strref file = line . between ( ' " ' , ' " ' ) ;
if ( ! file ) // MERLIN: No quotes around PUT filenames
file = line . split_range ( filename_end_char_range ) ;
size_t size = 0 ;
2016-05-25 22:44:17 -07:00
char * buffer = LoadText ( file , size ) ;
if ( buffer ) {
2015-10-25 14:29:41 -07:00
loadedData . push_back ( buffer ) ;
strref src ( buffer , strl_t ( size ) ) ;
2015-12-01 21:21:00 -08:00
PushContext ( file , src , src ) ;
2016-03-11 14:12:32 -08:00
} else if ( Merlin ( ) ) {
2015-10-25 14:29:41 -07:00
// MERLIN include file name rules
2016-05-25 22:44:17 -07:00
if ( file [ 0 ] > = ' ! ' & & file [ 0 ] < = ' & ' )
buffer = LoadText ( file + 1 , size ) ;
if ( buffer ) {
2015-10-25 14:29:41 -07:00
loadedData . push_back ( buffer ) ; // MERLIN: prepend with !-& to not auto-prepend with T.
strref src ( buffer , strl_t ( size ) ) ;
2015-12-01 21:21:00 -08:00
PushContext ( file + 1 , src , src ) ;
2015-10-25 14:29:41 -07:00
} else {
strown < 512 > fileadd ( file [ 0 ] > = ' ! ' & & file [ 0 ] < = ' & ' ? ( file + 1 ) : file ) ;
fileadd . append ( " .s " ) ;
2016-05-25 22:44:17 -07:00
buffer = LoadText ( fileadd . get_strref ( ) , size ) ;
if ( buffer ) {
2015-10-25 14:29:41 -07:00
loadedData . push_back ( buffer ) ; // MERLIN: !+filename appends .S to filenames
strref src ( buffer , strl_t ( size ) ) ;
2015-12-01 21:21:00 -08:00
PushContext ( file , src , src ) ;
2015-10-25 14:29:41 -07:00
} else {
fileadd . copy ( " T. " ) ; // MERLIN: just filename prepends T. to filenames
fileadd . append ( file [ 0 ] > = ' ! ' & & file [ 0 ] < = ' & ' ? ( file + 1 ) : file ) ;
2016-05-25 22:44:17 -07:00
buffer = LoadText ( fileadd . get_strref ( ) , size ) ;
if ( buffer ) {
2015-10-25 14:29:41 -07:00
loadedData . push_back ( buffer ) ;
strref src ( buffer , strl_t ( size ) ) ;
2015-12-01 21:21:00 -08:00
PushContext ( file , src , src ) ;
2015-10-25 14:29:41 -07:00
}
}
}
}
if ( ! size )
return ERROR_COULD_NOT_INCLUDE_FILE ;
return STATUS_OK ;
}
// incbin: import binary data in place
StatusCode Asm : : Directive_Incbin ( strref line , int skip , int len )
{
line = line . between ( ' " ' , ' " ' ) ;
strown < 512 > filename ( line ) ;
size_t size = 0 ;
if ( char * buffer = LoadBinary ( line , size ) ) {
int bin_size = ( int ) size - skip ;
2016-02-13 16:41:33 -08:00
if ( len & & bin_size > len )
2015-10-25 14:29:41 -07:00
bin_size = len ;
if ( bin_size > 0 )
2016-03-12 11:39:53 -08:00
AddBin ( ( const uint8_t * ) buffer + skip , bin_size ) ;
2015-10-25 14:29:41 -07:00
free ( buffer ) ;
return STATUS_OK ;
}
return ERROR_COULD_NOT_INCLUDE_FILE ;
}
// import is a catch-all file reference
StatusCode Asm : : Directive_Import ( strref line )
{
line . skip_whitespace ( ) ;
int skip = 0 ; // binary import skip this amount
int len = 0 ; // binary import load up to this amount
strref param ; // read out skip & max len parameters
int q = line . find ( ' " ' ) ;
if ( q > = 0 ) {
param = line + q ;
2018-02-20 13:30:32 -08:00
param . split_lang ( ) ;
2015-10-25 14:29:41 -07:00
param . trim_whitespace ( ) ;
if ( param [ 0 ] = = ' , ' ) {
+ + param ;
param . skip_whitespace ( ) ;
if ( param ) {
2015-11-03 20:57:06 -08:00
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
2015-10-25 14:29:41 -07:00
EvalExpression ( param . split_token_trim ( ' , ' ) , etx , skip ) ;
2017-01-08 16:30:30 -08:00
if ( param ) { EvalExpression ( param , etx , len ) ; }
2015-10-25 14:29:41 -07:00
}
}
}
if ( line [ 0 ] = = ' " ' )
2018-02-20 13:30:32 -08:00
return Directive_Incbin ( line , skip , len ) ;
2015-10-25 14:29:41 -07:00
else if ( import_source . is_prefix_word ( line ) ) {
line + = import_source . get_len ( ) ;
line . skip_whitespace ( ) ;
return Directive_Include ( line ) ;
} else if ( import_binary . is_prefix_word ( line ) ) {
line + = import_binary . get_len ( ) ;
line . skip_whitespace ( ) ;
return Directive_Incbin ( line , skip , len ) ;
} else if ( import_c64 . is_prefix_word ( line ) ) {
line + = import_c64 . get_len ( ) ;
line . skip_whitespace ( ) ;
return Directive_Incbin ( line , 2 + skip , len ) ; // 2 = load address skip size
} else if ( import_text . is_prefix_word ( line ) ) {
line + = import_text . get_len ( ) ;
line . skip_whitespace ( ) ;
strref text_type = " petscii " ;
2015-11-26 13:10:58 -08:00
while ( line [ 0 ] ! = ' " ' ) {
strref word = line . get_word_ws ( ) ;
if ( word . same_str ( " petscii " ) | | word . same_str ( " petscii_shifted " ) ) {
text_type = line . get_word_ws ( ) ;
line + = text_type . get_len ( ) ;
line . skip_whitespace ( ) ;
} else if ( StringSymbol * pStr = GetString ( line . get_word_ws ( ) ) ) {
line = pStr - > get ( ) ;
break ;
}
2015-10-25 14:29:41 -07:00
}
CurrSection ( ) . AddText ( line , text_type ) ;
return STATUS_OK ;
} else if ( import_object . is_prefix_word ( line ) ) {
line + = import_object . get_len ( ) ;
line . trim_whitespace ( ) ;
return ReadObjectFile ( line [ 0 ] = = ' " ' ? line . between ( ' " ' , ' " ' ) : line ) ;
} else if ( import_symbols . is_prefix_word ( line ) ) {
line + = import_symbols . get_len ( ) ;
line . skip_whitespace ( ) ;
2015-11-26 13:10:58 -08:00
return IncludeSymbols ( line ) ;
2015-10-25 14:29:41 -07:00
}
return STATUS_OK ;
}
2015-10-26 20:50:26 -07:00
// org / pc: current address of code
StatusCode Asm : : Directive_ORG ( strref line )
{
int addr ;
if ( line [ 0 ] = = ' = ' )
+ + line ;
else if ( keyword_equ . is_prefix_word ( line ) ) // optional '=' or equ
line . next_word_ws ( ) ;
line . skip_whitespace ( ) ;
2015-11-03 20:57:06 -08:00
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
2015-10-26 20:50:26 -07:00
StatusCode error = EvalExpression ( line , etx , addr ) ;
2015-10-30 22:30:16 -07:00
if ( error ! = STATUS_OK )
return ( error = = STATUS_NOT_READY | | error = = STATUS_XREF_DEPENDENT ) ?
ERROR_TARGET_ADDRESS_MUST_EVALUATE_IMMEDIATELY : error ;
2015-10-26 20:50:26 -07:00
// Section immediately followed by ORG reassigns that section to be fixed
2017-01-08 16:30:30 -08:00
Section & currSection = CurrSection ( ) ;
if ( currSection . size ( ) = = 0 & & ! currSection . IsDummySection ( ) & & ! currSection . address_assigned ) {
if ( currSection . type = = ST_ZEROPAGE & & addr > = 0x100 )
2015-11-07 18:23:57 -08:00
return ERROR_ZEROPAGE_SECTION_OUT_OF_RANGE ;
2015-11-08 18:06:45 -08:00
AssignAddressToSection ( SectionId ( ) , addr ) ;
2015-10-26 20:50:26 -07:00
} else
SetSection ( strref ( ) , addr ) ;
return STATUS_OK ;
}
// load: address for target to load code at
StatusCode Asm : : Directive_LOAD ( strref line )
{
int addr ;
if ( line [ 0 ] = = ' = ' | | keyword_equ . is_prefix_word ( line ) )
line . next_word_ws ( ) ;
2015-11-03 20:57:06 -08:00
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
2015-10-26 20:50:26 -07:00
StatusCode error = EvalExpression ( line , etx , addr ) ;
if ( error ! = STATUS_OK )
2015-10-30 22:30:16 -07:00
return ( error = = STATUS_NOT_READY | | error = = STATUS_XREF_DEPENDENT ) ?
ERROR_TARGET_ADDRESS_MUST_EVALUATE_IMMEDIATELY : error ;
2015-10-26 20:50:26 -07:00
CurrSection ( ) . SetLoadAddress ( addr ) ;
return STATUS_OK ;
}
2017-01-08 16:30:30 -08:00
StatusCode Asm : : Directive_MERGE ( strref line )
{
int first_section = - 1 ;
strref section_name = line . split_label ( ) ;
// get the first section that matches the first name and has an assigned address
for ( size_t section_id = 0 ; section_id ! = allSections . size ( ) ; + + section_id ) {
const Section & section = allSections [ section_id ] ;
if ( ! section . IsMergedSection ( ) & & section . name . same_str ( section_name ) ) {
if ( first_section < 0 | | ! allSections [ first_section ] . IsRelativeSection ( ) ) {
first_section = ( int ) section_id ;
}
}
}
if ( first_section < 0 ) { return ERROR_NOT_A_SECTION ; }
// merge all sections as defined by the line
while ( section_name ) {
for ( size_t section_id = 0 ; section_id ! = allSections . size ( ) ; + + section_id ) {
const Section & section = allSections [ section_id ] ;
if ( section_id ! = first_section & & ! section . IsMergedSection ( ) & & section . IsRelativeSection ( ) ) {
if ( section . name . same_str ( section_name ) ) {
StatusCode result = MergeSections ( first_section , ( int ) section_id ) ;
if ( result ! = STATUS_OK ) { return result ; }
}
}
}
if ( line [ 0 ] = = ' , ' ) { + + line ; }
section_name = line . split_label ( ) ;
}
return STATUS_OK ;
}
2015-10-26 20:50:26 -07:00
// MERLIN version of AD_LINK, which is more like AD_INCOBJ + link to current section
StatusCode Asm : : Directive_LNK ( strref line )
{
strref file = line . between ( ' " ' , ' " ' ) ;
if ( ! file ) // MERLIN: No quotes around include filenames
file = line . split_range ( filename_end_char_range ) ;
2015-11-09 22:15:14 -08:00
int section_id = SectionId ( ) ;
StatusCode error = ReadObjectFile ( file , SectionId ( ) ) ;
// restore current section
current_section = & allSections [ section_id ] ;
2015-10-26 20:50:26 -07:00
return error ;
}
// this stores a string that when matched with a label will make that label external
StatusCode Asm : : Directive_XDEF ( strref line )
{
line . trim_whitespace ( ) ;
2016-03-11 14:12:32 -08:00
if ( strref xdef = line . split_range ( Merlin ( ) ?
2015-10-26 20:50:26 -07:00
label_end_char_range_merlin : label_end_char_range ) ) {
char f = xdef . get_first ( ) ;
char e = xdef . get_last ( ) ;
if ( f ! = ' . ' & & f ! = ' ! ' & & f ! = ' @ ' & & e ! = ' $ ' ) {
2016-03-12 11:39:53 -08:00
uint32_t hash = xdef . fnv1a ( ) ;
uint32_t pos = FindLabelIndex ( hash , xdefs . getKeys ( ) , xdefs . count ( ) ) ;
2015-10-26 20:50:26 -07:00
while ( pos < xdefs . count ( ) & & xdefs . getKey ( pos ) = = hash ) {
if ( xdefs . getValue ( pos ) . same_str_case ( xdef ) )
return STATUS_OK ;
+ + pos ;
}
xdefs . insert ( pos , hash ) ;
xdefs . getValues ( ) [ pos ] = xdef ;
}
}
return STATUS_OK ;
}
2015-10-25 14:29:41 -07:00
2015-10-31 14:34:45 -07:00
StatusCode Asm : : Directive_XREF ( strref label )
{
// XREF already defined label => no action
if ( ! GetLabel ( label ) ) {
Label * pLabelXREF = AddLabel ( label . fnv1a ( ) ) ;
pLabelXREF - > label_name = label ;
pLabelXREF - > pool_name . clear ( ) ;
pLabelXREF - > section = - 1 ; // address labels are based on section
pLabelXREF - > value = 0 ;
pLabelXREF - > evaluated = true ;
pLabelXREF - > pc_relative = true ;
pLabelXREF - > external = false ;
pLabelXREF - > constant = false ;
pLabelXREF - > reference = true ;
}
return STATUS_OK ;
}
2015-11-08 18:06:45 -08:00
// dc.b, dc.w, dc.t, dc.l, ADR, ADRL, bytes, words, long
StatusCode Asm : : Directive_DC ( strref line , int width , strref source_file )
{
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
line . trim_whitespace ( ) ;
while ( strref exp_dc = line . split_token_trim ( ' , ' ) ) {
int value = 0 ;
if ( ! CurrSection ( ) . IsDummySection ( ) ) {
2016-03-11 14:12:32 -08:00
if ( Merlin ( ) & & exp_dc . get_first ( ) = = ' # ' ) // MERLIN allows for an immediate declaration on data
2015-11-08 18:06:45 -08:00
+ + exp_dc ;
StatusCode error = EvalExpression ( exp_dc , etx , value ) ;
if ( error > STATUS_XREF_DEPENDENT )
break ;
else if ( error = = STATUS_NOT_READY | | error = = STATUS_XREF_DEPENDENT )
AddLateEval ( CurrSection ( ) . DataOffset ( ) , CurrSection ( ) . GetPC ( ) , scope_address [ scope_depth ] , exp_dc , source_file ,
width = = 1 ? LateEval : : LET_BYTE : ( width = = 2 ? LateEval : : LET_ABS_REF : ( width = = 3 ? LateEval : : LET_ABS_L_REF : LateEval : : LET_ABS_4_REF ) ) ) ;
else if ( error = = STATUS_RELATIVE_SECTION ) {
value = 0 ;
2016-05-25 22:44:17 -07:00
CurrSection ( ) . AddReloc ( lastEvalValue , CurrSection ( ) . DataOffset ( ) , lastEvalSection , ( int8_t ) width , ( int8_t ) lastEvalShift ) ;
2015-11-08 18:06:45 -08:00
}
}
2016-03-12 11:39:53 -08:00
uint8_t bytes [ 4 ] = {
( uint8_t ) value , ( uint8_t ) ( value > > 8 ) ,
( uint8_t ) ( value > > 16 ) , ( uint8_t ) ( value > > 24 ) } ;
2015-11-08 18:06:45 -08:00
AddBin ( bytes , width ) ;
}
return STATUS_OK ;
}
2015-11-15 21:14:46 -08:00
// ds/ds.b/ds.w/ds.t/ds.l
StatusCode Asm : : Directive_DS ( strref line )
{
int width = 1 ;
int value ;
if ( line . get_first ( ) = = ' . ' & & strref : : is_alphabetic ( line [ 1 ] ) ) {
switch ( strref : : tolower ( line [ 1 ] ) ) {
case ' b ' : break ;
case ' w ' : width = 2 ; break ;
case ' t ' : width = 3 ; break ;
case ' l ' : width = 4 ; break ;
}
line + = 2 ;
line . skip_whitespace ( ) ;
}
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
strref size = line . split_token_trim ( ' , ' ) ;
if ( STATUS_OK ! = EvalExpression ( size , etx , value ) )
return ERROR_DS_MUST_EVALUATE_IMMEDIATELY ;
int fill = 0 ;
if ( line & & STATUS_OK ! = EvalExpression ( line , etx , fill ) )
return ERROR_DS_MUST_EVALUATE_IMMEDIATELY ;
value * = width ;
if ( value > 0 ) {
for ( int n = 0 ; n < value ; n + + )
AddByte ( fill ) ;
} else if ( value ) {
CurrSection ( ) . AddAddress ( value ) ;
if ( CurrSection ( ) . type = = ST_ZEROPAGE & & CurrSection ( ) . address > 0x100 )
return ERROR_ZEROPAGE_SECTION_OUT_OF_RANGE ;
}
return STATUS_OK ;
}
StatusCode Asm : : Directive_ALIGN ( strref line )
{
if ( line ) {
if ( line [ 0 ] = = ' = ' | | keyword_equ . is_prefix_word ( line ) )
line . next_word_ws ( ) ;
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
int value ;
int status = EvalExpression ( line , etx , value ) ;
if ( status = = STATUS_NOT_READY | | status = = STATUS_XREF_DEPENDENT )
return ERROR_ALIGN_MUST_EVALUATE_IMMEDIATELY ;
if ( status = = STATUS_OK & & value > 0 ) {
if ( CurrSection ( ) . address_assigned ) {
int add = ( CurrSection ( ) . GetPC ( ) + value - 1 ) % value ;
for ( int a = 0 ; a < add ; a + + )
AddByte ( 0 ) ;
} else
CurrSection ( ) . align_address = value ;
}
}
return STATUS_OK ;
}
StatusCode Asm : : Directive_EVAL ( strref line )
{
int value = 0 ;
strref description = line . find ( ' : ' ) > = 0 ? line . split_token_trim ( ' : ' ) : strref ( ) ;
line . trim_whitespace ( ) ;
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
2015-11-26 13:10:58 -08:00
strref lab1 = line ;
2016-03-11 14:12:32 -08:00
lab1 = lab1 . split_token_any_trim ( Merlin ( ) ? label_end_char_range_merlin : label_end_char_range ) ;
2015-11-26 13:10:58 -08:00
StringSymbol * pStr = line . same_str_case ( lab1 ) ? GetString ( lab1 ) : nullptr ;
2015-11-15 21:14:46 -08:00
if ( line & & EvalExpression ( line , etx , value ) = = STATUS_OK ) {
if ( description ) {
2015-11-26 13:10:58 -08:00
if ( pStr ! = nullptr ) {
printf ( " EVAL(%d): " STRREF_FMT " : \" " STRREF_FMT " \" = \" " STRREF_FMT " \" = $%x \n " ,
contextStack . curr ( ) . source_file . count_lines ( description ) + 1 , STRREF_ARG ( description ) , STRREF_ARG ( line ) , STRREF_ARG ( pStr - > get ( ) ) , value ) ;
} else {
printf ( " EVAL(%d): " STRREF_FMT " : \" " STRREF_FMT " \" = $%x \n " ,
contextStack . curr ( ) . source_file . count_lines ( description ) + 1 , STRREF_ARG ( description ) , STRREF_ARG ( line ) , value ) ;
}
2015-11-15 21:14:46 -08:00
} else {
2015-11-26 13:10:58 -08:00
if ( pStr ! = nullptr ) {
printf ( " EVAL(%d): \" " STRREF_FMT " \" = \" " STRREF_FMT " \" = $%x \n " ,
contextStack . curr ( ) . source_file . count_lines ( line ) + 1 , STRREF_ARG ( line ) , STRREF_ARG ( pStr - > get ( ) ) , value ) ;
} else {
printf ( " EVAL(%d): \" " STRREF_FMT " \" = $%x \n " ,
contextStack . curr ( ) . source_file . count_lines ( line ) + 1 , STRREF_ARG ( line ) , value ) ;
}
2015-11-15 21:14:46 -08:00
}
} else if ( description ) {
2015-11-26 13:10:58 -08:00
if ( pStr ! = nullptr ) {
printf ( " EVAL(%d): " STRREF_FMT " : \" " STRREF_FMT " \" = \" " STRREF_FMT " \" \n " ,
contextStack . curr ( ) . source_file . count_lines ( description ) + 1 , STRREF_ARG ( description ) , STRREF_ARG ( line ) , STRREF_ARG ( pStr - > get ( ) ) ) ;
} else {
printf ( " EVAL(%d): \" " STRREF_FMT " : " STRREF_FMT " \" \n " ,
contextStack . curr ( ) . source_file . count_lines ( description ) + 1 , STRREF_ARG ( description ) , STRREF_ARG ( line ) ) ;
}
2015-11-15 21:14:46 -08:00
} else {
2015-11-26 13:10:58 -08:00
if ( pStr ! = nullptr ) {
printf ( " EVAL(%d): \" " STRREF_FMT " \" = \" " STRREF_FMT " \" \n " ,
contextStack . curr ( ) . source_file . count_lines ( line ) + 1 , STRREF_ARG ( line ) , STRREF_ARG ( pStr - > get ( ) ) ) ;
} else {
printf ( " EVAL(%d): \" " STRREF_FMT " \" \n " ,
contextStack . curr ( ) . source_file . count_lines ( line ) + 1 , STRREF_ARG ( line ) ) ;
}
2015-11-15 21:14:46 -08:00
}
return STATUS_OK ;
}
StatusCode Asm : : Directive_HEX ( strref line )
{
2016-03-12 11:39:53 -08:00
uint8_t b = 0 , v = 0 ;
2015-11-15 21:14:46 -08:00
while ( line ) { // indeterminable length, can't read hex to int
char c = * line . get ( ) ;
+ + line ;
if ( c = = ' , ' ) {
if ( b ) // probably an error but seems safe
AddByte ( v ) ;
b = 0 ;
line . skip_whitespace ( ) ;
} else {
if ( c > = ' 0 ' & & c < = ' 9 ' ) v = ( v < < 4 ) + ( c - ' 0 ' ) ;
else if ( c > = ' A ' & & c < = ' Z ' ) v = ( v < < 4 ) + ( c - ' A ' + 10 ) ;
else if ( c > = ' a ' & & c < = ' z ' ) v = ( v < < 4 ) + ( c - ' a ' + 10 ) ;
else break ;
b ^ = 1 ;
if ( ! b )
AddByte ( v ) ;
}
}
if ( b )
return ERROR_HEX_WITH_ODD_NIBBLE_COUNT ;
return STATUS_OK ;
}
StatusCode Asm : : Directive_ENUM_STRUCT ( strref line , AssemblerDirective dir )
{
strref read_source = contextStack . curr ( ) . read_source ;
if ( read_source . is_substr ( line . get ( ) ) ) {
strref struct_name = line . get_word ( ) ;
line . skip ( struct_name . get_len ( ) ) ;
line . skip_whitespace ( ) ;
read_source . skip ( strl_t ( line . get ( ) - read_source . get ( ) ) ) ;
if ( read_source [ 0 ] = = ' { ' ) {
if ( dir = = AD_STRUCT )
BuildStruct ( struct_name , read_source . scoped_block_skip ( ) ) ;
else
BuildEnum ( struct_name , read_source . scoped_block_skip ( ) ) ;
} else
return dir = = AD_STRUCT ? ERROR_STRUCT_CANT_BE_ASSEMBLED :
ERROR_ENUM_CANT_BE_ASSEMBLED ;
contextStack . curr ( ) . next_source = read_source ;
} else
return ERROR_STRUCT_CANT_BE_ASSEMBLED ;
return STATUS_OK ;
}
2015-10-04 14:05:38 -07:00
// Action based on assembler directive
StatusCode Asm : : ApplyDirective ( AssemblerDirective dir , strref line , strref source_file )
2015-09-29 22:07:04 -07:00
{
2015-10-04 14:05:38 -07:00
StatusCode error = STATUS_OK ;
if ( ! ConditionalAsm ( ) ) { // If conditionally blocked from assembling only check conditional directives
if ( dir ! = AD_IF & & dir ! = AD_IFDEF & & dir ! = AD_ELSE & & dir ! = AD_ELIF & & dir ! = AD_ELSE & & dir ! = AD_ENDIF )
return STATUS_OK ;
}
2015-11-03 20:57:06 -08:00
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
2015-10-04 14:05:38 -07:00
switch ( dir ) {
2015-10-18 19:48:03 -07:00
case AD_CPU :
2015-10-23 22:44:56 -07:00
for ( int c = 0 ; c < nCPUs ; c + + ) {
if ( line . same_str ( aCPUs [ c ] . name ) ) {
2015-10-24 13:41:11 -07:00
if ( c ! = cpu )
SetCPU ( ( CPUIndex ) c ) ;
return STATUS_OK ;
2015-10-23 22:44:56 -07:00
}
}
return ERROR_CPU_NOT_SUPPORTED ;
2015-10-18 19:48:03 -07:00
case AD_EXPORT :
line . trim_whitespace ( ) ;
CurrSection ( ) . export_append = line . split_label ( ) ;
break ;
2015-10-23 22:44:56 -07:00
2015-10-26 20:50:26 -07:00
case AD_ORG :
return Directive_ORG ( line ) ;
2015-10-10 15:25:08 -07:00
2015-10-26 20:50:26 -07:00
case AD_LOAD :
return Directive_LOAD ( line ) ;
2015-10-30 22:30:16 -07:00
2015-10-10 15:25:08 -07:00
case AD_SECTION :
2015-11-06 22:48:50 -08:00
SetSection ( line ) ;
2015-10-10 15:25:08 -07:00
break ;
2017-01-08 16:30:30 -08:00
case AD_MERGE :
return Directive_MERGE ( line ) ;
2015-10-10 15:25:08 -07:00
case AD_LINK :
2015-10-26 20:50:26 -07:00
return LinkSections ( line . get_trimmed_ws ( ) ) ;
case AD_LNK :
return Directive_LNK ( line ) ;
2015-10-10 15:25:08 -07:00
2015-10-13 19:38:13 -07:00
case AD_INCOBJ : {
strref file = line . between ( ' " ' , ' " ' ) ;
2015-10-26 20:50:26 -07:00
if ( ! file ) // MERLIN: No quotes around include filenames
2015-10-13 19:38:13 -07:00
file = line . split_range ( filename_end_char_range ) ;
error = ReadObjectFile ( file ) ;
break ;
}
2015-10-26 20:50:26 -07:00
case AD_XDEF :
return Directive_XDEF ( line . get_trimmed_ws ( ) ) ;
2015-10-31 14:34:45 -07:00
case AD_XREF :
Directive_XREF ( line . split_range_trim (
2016-03-11 14:12:32 -08:00
Merlin ( ) ? label_end_char_range_merlin : label_end_char_range ) ) ;
2015-10-30 22:30:16 -07:00
break ;
2015-10-26 20:50:26 -07:00
case AD_ENT : // MERLIN version of xdef, makes most recently defined label external
if ( Label * pLastLabel = GetLabel ( last_label ) )
pLastLabel - > external = true ;
2015-10-13 19:38:13 -07:00
break ;
2015-10-31 14:34:45 -07:00
case AD_EXT :
Directive_XREF ( last_label ) ;
break ;
2015-09-29 22:07:04 -07:00
case AD_ALIGN : // align: align address to multiple of value, fill space with 0
2015-11-15 21:14:46 -08:00
return Directive_ALIGN ( line ) ;
case AD_EVAL : // eval: display the result of an expression in stdout
return Directive_EVAL ( line ) ;
2015-09-29 22:07:04 -07:00
case AD_BYTES : // bytes: add bytes by comma separated values/expressions
2015-11-08 18:06:45 -08:00
return Directive_DC ( line , 1 , source_file ) ;
2015-09-29 22:07:04 -07:00
case AD_WORDS : // words: add words (16 bit values) by comma separated values
2015-11-08 18:06:45 -08:00
return Directive_DC ( line , 2 , source_file ) ;
2015-10-26 20:50:26 -07:00
case AD_ADR : // ADR: MERLIN store 3 byte word
2015-11-08 18:06:45 -08:00
return Directive_DC ( line , 3 , source_file ) ;
case AD_ADRL : // ADRL: MERLIN store 4 byte word
return Directive_DC ( line , 4 , source_file ) ;
2015-10-26 20:50:26 -07:00
2015-10-04 14:05:38 -07:00
case AD_DC : {
2015-11-08 18:06:45 -08:00
int width = 1 ;
2015-10-04 14:05:38 -07:00
if ( line [ 0 ] = = ' . ' ) {
+ + line ;
2015-11-08 18:06:45 -08:00
switch ( strref : : tolower ( line . get_first ( ) ) ) {
case ' b ' : width = 1 ; break ;
case ' w ' : width = 2 ; break ;
case ' t ' : width = 3 ; break ;
case ' l ' : width = 4 ; break ;
default :
return ERROR_BAD_TYPE_FOR_DECLARE_CONSTANT ;
2015-10-04 14:05:38 -07:00
}
2015-11-08 18:06:45 -08:00
+ + line ;
2015-10-04 14:05:38 -07:00
}
2015-11-08 18:06:45 -08:00
return Directive_DC ( line , width , source_file ) ;
2015-10-04 14:05:38 -07:00
}
2015-10-26 20:50:26 -07:00
2015-11-15 21:14:46 -08:00
case AD_HEX :
return Directive_HEX ( line ) ;
2015-10-06 22:42:22 -07:00
case AD_EJECT :
line . clear ( ) ;
break ;
2015-10-07 22:27:03 -07:00
case AD_USR :
line . clear ( ) ;
break ;
2015-10-31 14:34:45 -07:00
case AD_CYC :
list_flags | = cycle_counter_level ? ListLine : : CYCLES_STOP : ListLine : : CYCLES_START ;
cycle_counter_level = ! ! cycle_counter_level ;
break ;
2015-10-26 20:50:26 -07:00
2015-10-21 22:34:01 -07:00
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 ( ) ;
2015-11-09 22:15:14 -08:00
AssignAddressToGroup ( ) ;
2015-10-21 22:34:01 -07:00
break ;
2015-10-26 20:50:26 -07:00
2015-10-23 22:44:56 -07:00
case AD_XC : // XC: MERLIN version of setting CPU
if ( strref ( " off " ) . is_prefix_word ( line ) )
SetCPU ( CPU_6502 ) ;
else if ( strref ( " xc " ) . is_prefix_word ( line ) )
SetCPU ( CPU_65816 ) ;
else if ( cpu = = CPU_65C02 )
SetCPU ( CPU_65816 ) ;
else
SetCPU ( CPU_65C02 ) ;
break ;
2015-10-26 20:50:26 -07:00
2015-09-29 22:07:04 -07:00
case AD_TEXT : { // text: add text within quotes
2015-11-26 13:10:58 -08:00
strref text_prefix ;
2017-01-08 16:30:30 -08:00
if ( line [ 0 ] = = ' [ ' ) {
strref str = line . scoped_block_skip ( ) . get_trimmed_ws ( ) ;
if ( StringSymbol * StringSym = GetString ( str ) ) {
line . skip_whitespace ( ) ;
if ( line [ 0 ] = = ' " ' )
line = line . between ( ' " ' , ' " ' ) ;
CurrSection ( ) . AddIndexText ( StringSym , line ) ;
break ;
}
}
2015-11-26 13:10:58 -08:00
while ( line [ 0 ] ! = ' " ' ) {
strref word = line . get_word_ws ( ) ;
if ( word . same_str ( " petscii " ) | | word . same_str ( " petscii_shifted " ) ) {
text_prefix = line . get_word_ws ( ) ;
line + = text_prefix . get_len ( ) ;
line . skip_whitespace ( ) ;
} else if ( StringSymbol * pStr = GetString ( line . get_word_ws ( ) ) ) {
line = pStr - > get ( ) ;
break ;
}
}
if ( line [ 0 ] = = ' " ' )
line = line . between ( ' " ' , ' " ' ) ;
2015-10-25 14:29:41 -07:00
CurrSection ( ) . AddText ( line , text_prefix ) ;
2015-09-29 22:07:04 -07:00
break ;
}
2015-10-20 22:28:53 -07:00
case AD_MACRO :
2016-05-25 22:44:17 -07:00
error = Directive_Macro ( line ) ;
2015-09-29 22:07:04 -07:00
break ;
2015-10-20 22:28:53 -07:00
2015-10-25 14:29:41 -07:00
case AD_INCLUDE : // assemble another file in place
return Directive_Include ( line ) ;
case AD_INCBIN :
return Directive_Incbin ( line ) ;
case AD_IMPORT :
return Directive_Import ( line ) ;
2015-09-29 22:07:04 -07:00
case AD_LABEL :
case AD_CONST : {
line . trim_whitespace ( ) ;
strref label = line . split_range_trim ( word_char_range , line [ 0 ] = = ' . ' ? 1 : 0 ) ;
if ( line [ 0 ] = = ' = ' | | keyword_equ . is_prefix_word ( line ) ) {
line . next_word_ws ( ) ;
AssignLabel ( label , line , dir = = AD_CONST ) ;
} else
error = ERROR_UNEXPECTED_LABEL_ASSIGMENT_FORMAT ;
break ;
}
2015-11-26 13:10:58 -08:00
case AD_STRING :
return Directive_String ( line ) ;
2015-10-25 14:29:41 -07:00
2015-11-26 13:10:58 -08:00
case AD_UNDEF :
return Directive_Undef ( line ) ;
2015-10-25 14:29:41 -07:00
case AD_INCSYM :
2015-11-26 13:10:58 -08:00
return IncludeSymbols ( line ) ;
2015-10-26 20:50:26 -07:00
2015-10-28 21:08:23 -07:00
case AD_LABPOOL : {
strref name = line . split_range_trim ( word_char_range , line [ 0 ] = = ' . ' ? 1 : 0 ) ;
AddLabelPool ( name , line ) ;
2015-10-01 23:16:36 -07:00
break ;
2015-10-28 21:08:23 -07:00
}
2015-10-25 14:29:41 -07:00
2015-10-02 20:57:50 -07:00
case AD_IF :
if ( NewConditional ( ) ) { // Start new conditional block
CheckConditionalDepth ( ) ; // Check if nesting
2015-10-01 23:16:36 -07:00
bool conditional_result ;
error = EvalStatement ( line , conditional_result ) ;
if ( conditional_result )
2015-10-02 20:57:50 -07:00
ConsumeConditional ( ) ;
2015-10-01 23:16:36 -07:00
else
2015-10-02 20:57:50 -07:00
SetConditional ( ) ;
2015-10-01 23:16:36 -07:00
}
break ;
2015-10-25 14:29:41 -07:00
2015-10-01 23:16:36 -07:00
case AD_IFDEF :
2015-10-02 20:57:50 -07:00
if ( NewConditional ( ) ) { // Start new conditional block
CheckConditionalDepth ( ) ; // Check if nesting
bool conditional_result ;
error = EvalStatement ( line , conditional_result ) ;
2015-11-26 13:10:58 -08:00
strref name = line . get_trimmed_ws ( ) ;
if ( GetLabel ( name ) ! = nullptr | | GetString ( name ) ! = nullptr )
2015-10-02 20:57:50 -07:00
ConsumeConditional ( ) ;
2015-10-01 23:16:36 -07:00
else
2015-10-02 20:57:50 -07:00
SetConditional ( ) ;
2015-10-01 23:16:36 -07:00
}
break ;
2015-10-25 14:29:41 -07:00
2015-10-01 23:16:36 -07:00
case AD_ELSE :
2015-10-02 20:57:50 -07:00
if ( ConditionalAsm ( ) ) {
if ( ConditionalConsumed ( ) )
2015-10-02 21:52:55 -07:00
ConditionalElse ( ) ;
else
error = ERROR_ELSE_WITHOUT_IF ;
2015-10-02 20:57:50 -07:00
} else if ( ConditionalAvail ( ) )
EnableConditional ( true ) ;
2015-10-01 23:16:36 -07:00
break ;
2015-10-25 14:29:41 -07:00
2015-10-01 23:16:36 -07:00
case AD_ELIF :
2015-10-02 20:57:50 -07:00
if ( ConditionalAsm ( ) ) {
if ( ConditionalConsumed ( ) )
2015-10-02 21:52:55 -07:00
ConditionalElse ( ) ;
else
error = ERROR_ELSE_WITHOUT_IF ;
2015-10-23 22:44:56 -07:00
} else if ( ConditionalAvail ( ) ) {
2015-10-01 23:16:36 -07:00
bool conditional_result ;
error = EvalStatement ( line , conditional_result ) ;
2015-10-02 20:57:50 -07:00
EnableConditional ( conditional_result ) ;
2015-10-01 23:16:36 -07:00
}
break ;
2015-10-25 14:29:41 -07:00
2015-10-01 23:16:36 -07:00
case AD_ENDIF :
2015-10-02 20:57:50 -07:00
if ( ConditionalAsm ( ) ) {
if ( ConditionalConsumed ( ) )
CloseConditional ( ) ;
else
error = ERROR_ENDIF_WITHOUT_CONDITION ;
} else {
2015-10-01 23:16:36 -07:00
conditional_nesting [ conditional_depth ] - - ;
2015-10-02 20:57:50 -07:00
if ( ConditionalAsm ( ) )
CloseConditional ( ) ;
}
break ;
2015-10-25 14:29:41 -07:00
2015-10-06 22:42:22 -07:00
case AD_ENUM :
2015-11-15 21:14:46 -08:00
case AD_STRUCT :
return Directive_ENUM_STRUCT ( line , dir ) ;
2015-10-25 14:29:41 -07:00
2015-10-23 22:44:56 -07:00
case AD_REPT :
2016-05-25 22:44:17 -07:00
return Directive_Rept ( line ) ;
2015-10-20 22:28:53 -07:00
2015-10-05 22:45:42 -07:00
case AD_INCDIR :
AddIncludeFolder ( line . between ( ' " ' , ' " ' ) ) ;
break ;
2015-10-25 14:29:41 -07:00
2015-10-23 22:44:56 -07:00
case AD_A16 : // A16: Set 16 bit accumulator mode
accumulator_16bit = true ;
break ;
2015-10-25 14:29:41 -07:00
2015-10-23 22:44:56 -07:00
case AD_A8 : // A8: Set 8 bit accumulator mode
accumulator_16bit = false ;
break ;
2015-10-25 14:29:41 -07:00
2015-10-23 22:44:56 -07:00
case AD_XY16 : // A16: Set 16 bit accumulator mode
index_reg_16bit = true ;
break ;
2015-10-25 14:29:41 -07:00
2015-10-23 22:44:56 -07:00
case AD_XY8 : // A8: Set 8 bit accumulator mode
index_reg_16bit = false ;
break ;
2015-10-25 14:29:41 -07:00
2015-10-23 22:44:56 -07:00
case AD_MX :
if ( line ) {
line . trim_whitespace ( ) ;
int value = 0 ;
error = EvalExpression ( line , etx , value ) ;
2015-10-26 20:50:26 -07:00
index_reg_16bit = ! ( value & 1 ) ;
accumulator_16bit = ! ( value & 2 ) ;
2015-10-23 22:44:56 -07:00
}
break ;
2015-11-15 21:14:46 -08:00
case AD_ABORT :
line . trim_whitespace ( ) ;
if ( line )
printf ( " Assembler aborted: " STRREF_FMT " \n " , STRREF_ARG ( line ) ) ;
return ERROR_ABORTED ;
2015-10-25 14:29:41 -07:00
2015-10-06 22:42:22 -07:00
case AD_LST :
line . clear ( ) ;
break ;
2015-10-25 14:29:41 -07:00
2015-10-06 22:42:22 -07:00
case AD_DUMMY :
2015-10-07 22:27:03 -07:00
line . trim_whitespace ( ) ;
if ( line ) {
int reorg ;
2015-10-16 20:27:56 -07:00
if ( STATUS_OK = = EvalExpression ( line , etx , reorg ) ) {
2015-10-10 15:25:08 -07:00
DummySection ( reorg ) ;
break ;
}
2015-10-07 22:27:03 -07:00
}
2015-10-10 15:25:08 -07:00
DummySection ( ) ;
2015-10-06 22:42:22 -07:00
break ;
2015-10-25 14:29:41 -07:00
2015-10-06 22:42:22 -07:00
case AD_DUMMY_END :
2015-10-19 22:44:02 -07:00
while ( CurrSection ( ) . IsDummySection ( ) ) {
2015-10-10 15:25:08 -07:00
EndSection ( ) ;
2015-10-19 22:44:02 -07:00
if ( SectionId ( ) = = 0 )
break ;
}
2015-10-06 22:42:22 -07:00
break ;
2015-10-25 14:29:41 -07:00
2015-11-15 21:14:46 -08:00
case AD_DS :
return Directive_DS ( line ) ;
2015-09-29 22:07:04 -07:00
}
return error ;
}
2015-10-24 13:41:11 -07:00
// Make an educated guess at the intended address mode from an opcode argument
2016-03-12 11:39:53 -08:00
StatusCode Asm : : GetAddressMode ( strref line , bool flipXY , uint32_t validModes , AddrMode & addrMode , int & len , strref & expression )
2015-10-04 14:05:38 -07:00
{
bool force_zp = false ;
2015-10-23 22:44:56 -07:00
bool force_24 = false ;
2015-10-25 23:48:35 -07:00
bool force_abs = false ;
2015-10-04 14:05:38 -07:00
bool need_more = true ;
strref arg , deco ;
2015-10-23 22:44:56 -07:00
len = 0 ;
2015-10-04 14:05:38 -07:00
while ( need_more ) {
need_more = false ;
2016-03-12 11:39:53 -08:00
uint8_t c = line . get_first ( ) ;
2015-10-25 23:48:35 -07:00
if ( ! c )
addrMode = AMB_NON ;
else if ( ! force_abs & & ( c = = ' [ ' | | ( c = = ' ( ' & &
2015-11-27 18:01:53 -08:00
( validModes & ( AMM_REL | AMM_REL_X | AMM_ZP_REL | AMM_ZP_REL_X | AMM_ZP_Y_REL ) ) ) ) ) {
2015-10-25 23:48:35 -07:00
deco = line . scoped_block_skip ( ) ;
line . skip_whitespace ( ) ;
expression = deco . split_token_trim ( ' , ' ) ;
addrMode = c = = ' [ ' ? ( force_zp ? AMB_ZP_REL_L : AMB_REL_L ) : ( force_zp ? AMB_ZP_REL : AMB_REL ) ;
if ( strref : : tolower ( deco [ 0 ] ) = = ' x ' )
addrMode = c = = ' [ ' ? AMB_ILL : AMB_ZP_REL_X ;
else if ( line [ 0 ] = = ' , ' ) {
+ + line ;
2015-10-04 14:05:38 -07:00
line . skip_whitespace ( ) ;
2015-10-25 23:48:35 -07:00
if ( strref : : tolower ( line [ 0 ] ) = = ' y ' ) {
if ( strref : : tolower ( deco [ 0 ] ) = = ' s ' )
addrMode = AMB_STK_REL_Y ;
else
addrMode = c = = ' [ ' ? AMB_ZP_REL_Y_L : AMB_ZP_Y_REL ;
2015-10-04 14:05:38 -07:00
+ + line ;
}
2015-10-25 23:48:35 -07:00
}
} else if ( c = = ' # ' ) {
+ + line ;
addrMode = AMB_IMM ;
expression = line ;
} else if ( line ) {
if ( line [ 0 ] = = ' . ' & & strref : : is_ws ( line [ 2 ] ) ) {
switch ( strref : : tolower ( line [ 1 ] ) ) {
case ' z ' : force_zp = true ; line + = 3 ; need_more = true ; len = 1 ; break ;
case ' b ' : line + = 3 ; need_more = true ; len = 1 ; break ;
case ' w ' : line + = 3 ; need_more = true ; len = 2 ; break ;
case ' l ' : force_24 = true ; line + = 3 ; need_more = true ; len = 3 ; break ;
case ' a ' : force_abs = true ; line + = 3 ; need_more = true ; break ;
}
}
if ( ! need_more ) {
if ( strref ( " A " ) . is_prefix_word ( line ) ) {
addrMode = AMB_ACC ;
} else { // absolute (zp, offs x, offs y)
addrMode = force_24 ? AMB_ABS_L : ( force_zp ? AMB_ZP : AMB_ABS ) ;
expression = line . split_token_trim ( ' , ' ) ;
if ( line & & ( line [ 0 ] = = ' s ' | | line [ 0 ] = = ' S ' ) )
addrMode = AMB_STK ;
else {
bool relX = line & & ( line [ 0 ] = = ' x ' | | line [ 0 ] = = ' X ' ) ;
bool relY = line & & ( line [ 0 ] = = ' y ' | | line [ 0 ] = = ' Y ' ) ;
if ( ( flipXY & & relY ) | | ( ! flipXY & & relX ) )
addrMode = force_24 ? AMB_ABS_L_X : ( force_zp ? AMB_ZP_X : AMB_ABS_X ) ;
else if ( ( flipXY & & relX ) | | ( ! flipXY & & relY ) ) {
2017-01-08 16:30:30 -08:00
if ( force_zp ) { return ERROR_INSTRUCTION_NOT_ZP ; }
2015-10-25 23:48:35 -07:00
addrMode = AMB_ABS_Y ;
2015-10-04 14:05:38 -07:00
}
}
}
}
}
}
2015-10-23 22:44:56 -07:00
return STATUS_OK ;
2015-10-04 14:05:38 -07:00
}
2015-10-24 13:41:11 -07:00
// Push an opcode to the output buffer in the current section
2017-01-08 16:30:30 -08:00
StatusCode Asm : : AddOpcode ( strref line , int index , strref source_file ) {
2015-09-29 22:07:04 -07:00
StatusCode error = STATUS_OK ;
strref expression ;
2015-10-21 22:34:01 -07:00
// allowed modes
2016-03-12 11:39:53 -08:00
uint32_t validModes = opcode_table [ index ] . modes ;
2015-10-21 22:34:01 -07:00
2015-10-23 22:44:56 -07:00
// instruction parameter length override
int op_param = 0 ;
2015-09-29 22:07:04 -07:00
// Get the addressing mode and the expression it refers to
2015-10-21 22:34:01 -07:00
AddrMode addrMode ;
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 ;
2015-10-23 22:44:56 -07:00
case AMM_ACC :
case ( AMM_ACC | AMM_NON ) :
2015-10-21 22:34:01 -07:00
case AMM_NON :
addrMode = AMB_NON ;
break ;
2015-10-23 22:44:56 -07:00
case AMM_BLK_MOV :
addrMode = AMB_BLK_MOV ;
2015-10-25 14:29:41 -07:00
expression = line . before_or_full ( ' , ' ) ;
2015-10-23 22:44:56 -07:00
break ;
2015-10-21 22:34:01 -07:00
default :
2015-10-25 23:48:35 -07:00
error = GetAddressMode ( line , ! ! ( validModes & AMM_FLIPXY ) , validModes , addrMode , op_param , expression ) ;
2015-10-21 22:34:01 -07:00
break ;
}
2015-10-23 22:44:56 -07:00
2015-09-29 22:07:04 -07:00
int value = 0 ;
2015-10-10 15:25:08 -07:00
int target_section = - 1 ;
2015-10-10 17:53:15 -07:00
int target_section_offs = - 1 ;
2016-03-12 11:39:53 -08:00
int8_t target_section_shift = 0 ;
2015-09-29 22:07:04 -07:00
bool evalLater = false ;
if ( expression ) {
2015-11-03 20:57:06 -08:00
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
if ( validModes & ( AMM_BRANCH | AMM_BRANCH_L ) )
etx . relative_section = SectionId ( ) ;
2015-10-17 12:13:23 -07:00
error = EvalExpression ( expression , etx , value ) ;
2015-10-30 22:30:16 -07:00
if ( error = = STATUS_NOT_READY | | error = = STATUS_XREF_DEPENDENT ) {
2015-09-29 22:07:04 -07:00
evalLater = true ;
error = STATUS_OK ;
2015-10-10 17:53:15 -07:00
} else if ( error = = STATUS_RELATIVE_SECTION ) {
2015-10-10 15:25:08 -07:00
target_section = lastEvalSection ;
2015-10-10 17:53:15 -07:00
target_section_offs = lastEvalValue ;
2015-11-05 21:23:38 -08:00
target_section_shift = lastEvalShift ;
2015-10-10 17:53:15 -07:00
} else if ( error ! = STATUS_OK )
2015-09-29 22:07:04 -07:00
return error ;
}
2015-10-23 22:44:56 -07:00
2015-09-29 22:07:04 -07:00
// check if address is in zero page range and should use a ZP mode instead of absolute
2015-11-07 18:23:57 -08:00
if ( ! evalLater & & value > = 0 & & value < 0x100 & & ( error ! = STATUS_RELATIVE_SECTION | |
( target_section > = 0 & & allSections [ target_section ] . type = = ST_ZEROPAGE ) ) ) {
2015-09-29 22:07:04 -07:00
switch ( addrMode ) {
2015-10-18 12:42:10 -07:00
case AMB_ABS :
2015-10-21 22:34:01 -07:00
if ( validModes & AMM_ZP )
2015-10-18 12:42:10 -07:00
addrMode = AMB_ZP ;
2015-10-23 22:44:56 -07:00
else if ( validModes & AMM_ABS_L )
addrMode = AMB_ABS_L ;
2015-09-29 22:07:04 -07:00
break ;
2015-10-18 12:42:10 -07:00
case AMB_ABS_X :
2015-10-21 22:34:01 -07:00
if ( validModes & AMM_ZP_X )
2015-10-18 12:42:10 -07:00
addrMode = AMB_ZP_X ;
2015-10-23 22:44:56 -07:00
else if ( validModes & AMM_ABS_L_X )
addrMode = AMB_ABS_L_X ;
2015-09-29 22:07:04 -07:00
break ;
default :
break ;
}
}
2015-10-23 22:44:56 -07:00
// Check if an explicit 24 bit address
if ( expression [ 0 ] = = ' $ ' & & ( expression + 1 ) . len_hex ( ) > 4 ) {
2017-01-08 16:30:30 -08:00
if ( addrMode = = AMB_ABS & & ( validModes & AMM_ABS_L ) ) {
2015-10-23 22:44:56 -07:00
addrMode = AMB_ABS_L ;
2017-01-08 16:30:30 -08:00
} else if ( addrMode = = AMB_ABS_X & & ( validModes & AMM_ABS_L_X ) ) {
2015-10-23 22:44:56 -07:00
addrMode = AMB_ABS_L_X ;
2017-01-08 16:30:30 -08:00
}
2015-10-23 22:44:56 -07:00
}
2015-10-24 13:41:11 -07:00
if ( ! ( validModes & ( 1 < < addrMode ) ) ) {
2017-01-08 16:30:30 -08:00
if ( addrMode = = AMB_ZP_REL_X & & ( validModes & AMM_REL_X ) ) {
2015-10-21 22:34:01 -07:00
addrMode = AMB_REL_X ;
2017-01-08 16:30:30 -08:00
} else if ( addrMode = = AMB_REL & & ( validModes & AMM_ZP_REL ) ) {
2015-10-21 22:34:01 -07:00
addrMode = AMB_ZP_REL ;
2017-01-08 16:30:30 -08:00
} else if ( addrMode = = AMB_ABS & & ( validModes & AMM_ABS_L ) ) {
2015-10-23 22:44:56 -07:00
addrMode = AMB_ABS_L ;
2017-01-08 16:30:30 -08:00
} else if ( addrMode = = AMB_ABS_X & & ( validModes & AMM_ABS_L_X ) ) {
2015-10-23 22:44:56 -07:00
addrMode = AMB_ABS_L_X ;
2017-01-08 16:30:30 -08:00
} else if ( addrMode = = AMB_REL_L & & ( validModes & AMM_ZP_REL_L ) ) {
2015-10-23 22:44:56 -07:00
addrMode = AMB_ZP_REL_L ;
2017-01-08 16:30:30 -08:00
} else if ( Merlin ( ) & & addrMode = = AMB_IMM & & validModes = = AMM_ABS ) {
2015-10-26 20:50:26 -07:00
addrMode = AMB_ABS ; // Merlin seems to allow this
2017-01-08 16:30:30 -08:00
} else if ( Merlin ( ) & & addrMode = = AMB_ABS & & validModes = = AMM_ZP_REL ) {
2015-10-26 20:50:26 -07:00
addrMode = AMB_ZP_REL ; // Merlin seems to allow this
2017-01-08 16:30:30 -08:00
} else { return ERROR_INVALID_ADDRESSING_MODE ; }
2015-10-21 22:34:01 -07:00
}
2015-10-18 12:42:10 -07:00
2015-10-21 22:34:01 -07:00
// Add the instruction and argument to the code
if ( error = = STATUS_OK | | error = = STATUS_RELATIVE_SECTION ) {
2016-03-12 11:39:53 -08:00
uint8_t opcode = opcode_table [ index ] . aCodes [ addrMode ] ;
2015-11-15 21:14:46 -08:00
StatusCode cap_status = CheckOutputCapacity ( 4 ) ;
if ( cap_status ! = STATUS_OK )
return error ;
2015-10-21 22:34:01 -07:00
AddByte ( opcode ) ;
CODE_ARG codeArg = CA_NONE ;
2015-10-23 22:44:56 -07:00
if ( validModes & AMM_BRANCH_L )
codeArg = CA_BRANCH_16 ;
else if ( validModes & AMM_BRANCH )
2015-09-29 22:07:04 -07:00
codeArg = CA_BRANCH ;
2015-10-23 22:44:56 -07:00
else {
switch ( addrMode ) {
case AMB_ZP_REL_X : // 0 ($12:x)
case AMB_ZP : // 1 $12
case AMB_ZP_Y_REL : // 4 ($12),y
case AMB_ZP_X : // 5 $12,x
case AMB_ZP_REL : // b ($12)
case AMB_ZP_REL_L : // e [$02]
case AMB_ZP_REL_Y_L : // f [$00],y
case AMB_STK : // 12 $12,s
case AMB_STK_REL_Y : // 13 ($12,s),y
codeArg = CA_ONE_BYTE ;
break ;
case AMB_ABS_Y : // 6 $1234,y
case AMB_ABS_X : // 7 $1234,x
case AMB_ABS : // 3 $1234
case AMB_REL : // 8 ($1234)
case AMB_REL_X : // c ($1234,x)
case AMB_REL_L : // 14 [$1234]
codeArg = CA_TWO_BYTES ;
break ;
case AMB_ABS_L : // 10 $e00001
case AMB_ABS_L_X : // 11 $123456,x
codeArg = CA_THREE_BYTES ;
break ;
case AMB_ZP_ABS : // d $12, label
codeArg = CA_BYTE_BRANCH ;
break ;
case AMB_BLK_MOV : // 15 $12,$34
codeArg = CA_TWO_ARG_BYTES ;
break ;
case AMB_IMM : // 2 #$12
if ( op_param & & ( validModes & ( AMM_IMM_DBL_A | AMM_IMM_DBL_XY ) ) )
codeArg = op_param = = 2 ? CA_TWO_BYTES : CA_ONE_BYTE ;
2015-10-25 14:29:41 -07:00
else if ( ( validModes & ( AMM_IMM_DBL_A | AMM_IMM_DBL_XY ) ) & &
expression [ 0 ] = = ' $ ' & & ( expression + 1 ) . len_hex ( ) = = 4 )
codeArg = CA_TWO_BYTES ;
else if ( ( ( validModes & AMM_IMM_DBL_A ) & & accumulator_16bit ) | |
2015-10-23 22:44:56 -07:00
( ( validModes & AMM_IMM_DBL_XY ) & & index_reg_16bit ) )
codeArg = CA_TWO_BYTES ;
else
codeArg = CA_ONE_BYTE ;
break ;
2015-10-24 13:41:11 -07:00
case AMB_ACC : // 9 A
case AMB_NON : // a
default :
break ;
2015-10-23 22:44:56 -07:00
}
}
2015-09-29 22:07:04 -07:00
switch ( codeArg ) {
2015-10-24 13:41:11 -07:00
case CA_ONE_BYTE :
if ( evalLater )
AddLateEval ( CurrSection ( ) . DataOffset ( ) , CurrSection ( ) . GetPC ( ) , scope_address [ scope_depth ] , expression , source_file , LateEval : : LET_BYTE ) ;
else if ( error = = STATUS_RELATIVE_SECTION )
2015-11-05 21:23:38 -08:00
CurrSection ( ) . AddReloc ( target_section_offs , CurrSection ( ) . DataOffset ( ) , target_section , 1 , target_section_shift ) ;
2015-10-24 13:41:11 -07:00
AddByte ( value ) ;
break ;
case CA_TWO_BYTES :
if ( evalLater )
AddLateEval ( CurrSection ( ) . DataOffset ( ) , CurrSection ( ) . GetPC ( ) , scope_address [ scope_depth ] , expression , source_file , LateEval : : LET_ABS_REF ) ;
else if ( error = = STATUS_RELATIVE_SECTION ) {
2015-11-05 21:23:38 -08:00
CurrSection ( ) . AddReloc ( target_section_offs , CurrSection ( ) . DataOffset ( ) , target_section , 2 , target_section_shift ) ;
2015-10-24 13:41:11 -07:00
value = 0 ;
}
AddWord ( value ) ;
break ;
case CA_THREE_BYTES :
if ( evalLater )
AddLateEval ( CurrSection ( ) . DataOffset ( ) , CurrSection ( ) . GetPC ( ) , scope_address [ scope_depth ] , expression , source_file , LateEval : : LET_ABS_L_REF ) ;
else if ( error = = STATUS_RELATIVE_SECTION ) {
2015-11-05 21:23:38 -08:00
CurrSection ( ) . AddReloc ( target_section_offs , CurrSection ( ) . DataOffset ( ) , target_section , 3 , target_section_shift ) ;
2015-10-24 13:41:11 -07:00
value = 0 ;
}
AddTriple ( value ) ;
break ;
2015-11-27 18:01:53 -08:00
case CA_TWO_ARG_BYTES : {
2015-10-21 22:34:01 -07:00
if ( evalLater )
AddLateEval ( CurrSection ( ) . DataOffset ( ) , CurrSection ( ) . GetPC ( ) , scope_address [ scope_depth ] , expression , source_file , LateEval : : LET_BYTE ) ;
else if ( error = = STATUS_RELATIVE_SECTION ) {
2015-11-05 21:23:38 -08:00
CurrSection ( ) . AddReloc ( target_section_offs , CurrSection ( ) . DataOffset ( ) , target_section , 1 , target_section_shift ) ;
2015-10-21 22:34:01 -07:00
}
AddByte ( value ) ;
2015-11-03 20:57:06 -08:00
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
etx . pc = CurrSection ( ) . GetPC ( ) - 2 ;
2015-10-24 13:41:11 -07:00
line . split_token_trim ( ' , ' ) ;
2015-10-21 22:34:01 -07:00
error = EvalExpression ( line , etx , value ) ;
2015-10-30 22:30:16 -07:00
if ( error = = STATUS_NOT_READY | | error = = STATUS_XREF_DEPENDENT )
2015-10-24 13:41:11 -07:00
AddLateEval ( CurrSection ( ) . DataOffset ( ) , CurrSection ( ) . GetPC ( ) , scope_address [ scope_depth ] , line , source_file , LateEval : : LET_BYTE ) ;
AddByte ( value ) ;
2015-10-21 22:34:01 -07:00
break ;
}
2015-09-29 22:07:04 -07:00
case CA_BRANCH :
2015-10-10 15:25:08 -07:00
if ( evalLater )
2015-10-13 19:38:13 -07:00
AddLateEval ( CurrSection ( ) . DataOffset ( ) , CurrSection ( ) . GetPC ( ) , scope_address [ scope_depth ] , expression , source_file , LateEval : : LET_BRANCH ) ;
2015-10-21 22:34:01 -07:00
else if ( ( ( int ) value - ( int ) CurrSection ( ) . GetPC ( ) - 1 ) < - 128 | | ( ( int ) value - ( int ) CurrSection ( ) . GetPC ( ) - 1 ) > 127 )
2015-10-10 15:25:08 -07:00
error = ERROR_BRANCH_OUT_OF_RANGE ;
2016-03-12 11:39:53 -08:00
AddByte ( evalLater ? 0 : ( uint8_t ) ( ( int ) value - ( int ) CurrSection ( ) . GetPC ( ) ) - 1 ) ;
2015-09-29 22:07:04 -07:00
break ;
2015-10-24 13:41:11 -07:00
2015-10-23 22:44:56 -07:00
case CA_BRANCH_16 :
if ( evalLater )
AddLateEval ( CurrSection ( ) . DataOffset ( ) , CurrSection ( ) . GetPC ( ) , scope_address [ scope_depth ] , expression , source_file , LateEval : : LET_BRANCH_16 ) ;
AddWord ( evalLater ? 0 : ( value - ( CurrSection ( ) . GetPC ( ) + 2 ) ) ) ;
break ;
2015-10-24 13:41:11 -07:00
case CA_BYTE_BRANCH : {
2015-10-23 22:44:56 -07:00
if ( evalLater )
AddLateEval ( CurrSection ( ) . DataOffset ( ) , CurrSection ( ) . GetPC ( ) , scope_address [ scope_depth ] , expression , source_file , LateEval : : LET_BYTE ) ;
2015-11-05 21:23:38 -08:00
else if ( error = = STATUS_RELATIVE_SECTION )
CurrSection ( ) . AddReloc ( target_section_offs , CurrSection ( ) . DataOffset ( ) , target_section , 1 , target_section_shift ) ;
2015-10-23 22:44:56 -07:00
AddByte ( value ) ;
2015-11-03 20:57:06 -08:00
struct EvalContext etx ;
SetEvalCtxDefaults ( etx ) ;
etx . pc = CurrSection ( ) . GetPC ( ) - 2 ;
etx . relative_section = SectionId ( ) ;
2015-10-23 22:44:56 -07:00
error = EvalExpression ( line , etx , value ) ;
2015-10-30 22:30:16 -07:00
if ( error = = STATUS_NOT_READY | | error = = STATUS_XREF_DEPENDENT )
2015-10-24 13:41:11 -07:00
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 ;
2015-10-30 22:30:16 -07:00
AddByte ( ( error = = STATUS_NOT_READY | | error = = STATUS_XREF_DEPENDENT ) ?
2016-03-12 11:39:53 -08:00
0 : ( uint8_t ) ( ( int ) value - ( int ) CurrSection ( ) . GetPC ( ) ) - 1 ) ;
2015-09-29 22:07:04 -07:00
break ;
2015-10-23 22:44:56 -07:00
}
2015-09-29 22:07:04 -07:00
case CA_NONE :
break ;
}
}
return error ;
}
2015-10-04 14:05:38 -07:00
// Build a line of code
2017-01-28 13:29:42 -08:00
void Asm : : PrintError ( strref line , StatusCode error , strref source ) {
2015-10-04 14:05:38 -07:00
strown < 512 > errorText ;
if ( contextStack . has_work ( ) ) {
errorText . sprintf ( " Error " STRREF_FMT " (%d): " , STRREF_ARG ( contextStack . curr ( ) . source_name ) ,
contextStack . curr ( ) . source_file . count_lines ( line ) + 1 ) ;
2017-01-28 13:29:42 -08:00
} else if ( source ) { errorText . sprintf_append ( " Error (%d): " , source . count_lines ( line ) ) ; }
else { errorText . append ( " Error: " ) ; }
2015-10-04 14:05:38 -07:00
errorText . append ( aStatusStrings [ error ] ) ;
errorText . append ( " \" " ) ;
errorText . append ( line . get_trimmed_ws ( ) ) ;
errorText . append ( " \" \n " ) ;
errorText . c_str ( ) ;
fwrite ( errorText . get ( ) , errorText . get_len ( ) , 1 , stderr ) ;
2015-10-30 22:30:16 -07:00
error_encountered = true ;
2015-09-29 22:07:04 -07:00
}
2015-10-04 14:05:38 -07:00
// Build a line of code
2017-01-08 16:30:30 -08:00
StatusCode Asm : : BuildLine ( strref line ) {
2015-09-29 22:07:04 -07:00
StatusCode error = STATUS_OK ;
2015-10-10 15:25:08 -07:00
// MERLIN: First char of line is * means comment
2017-01-08 16:30:30 -08:00
if ( Merlin ( ) & & line [ 0 ] = = ' * ' ) { return STATUS_OK ; }
2015-10-10 15:25:08 -07:00
2015-10-18 12:42:10 -07:00
// remember for listing
int start_section = SectionId ( ) ;
int start_address = CurrSection ( ) . address ;
strref code_line = line ;
2015-10-31 14:34:45 -07:00
list_flags = 0 ;
2016-03-11 14:12:32 -08:00
2015-10-04 14:05:38 -07:00
while ( line & & error = = STATUS_OK ) {
strref line_start = line ;
2015-10-23 22:44:56 -07:00
char char0 = line [ 0 ] ; // first char including white space
line . skip_whitespace ( ) ; // skip to first character
line = line . before_or_full ( ' ; ' ) ; // clip any line comments
2015-10-04 14:05:38 -07:00
line = line . before_or_full ( c_comment ) ;
line . clip_trailing_whitespace ( ) ;
2017-01-08 16:30:30 -08:00
if ( line [ 0 ] = = ' : ' & & ! Merlin ( ) ) { + + line ; } // Kick Assembler macro prefix (incompatible with merlin)
2015-10-07 22:27:03 -07:00
strref line_nocom = line ;
2016-03-11 14:12:32 -08:00
strref operation = line . split_range ( Merlin ( ) ? label_end_char_range_merlin : label_end_char_range ) ;
2015-10-10 15:25:08 -07:00
char char1 = operation [ 0 ] ; // first char of first word
char charE = operation . get_last ( ) ; // end char of first word
2015-10-06 22:42:22 -07:00
line . trim_whitespace ( ) ;
2015-10-10 15:25:08 -07:00
bool force_label = charE = = ' : ' | | charE = = ' $ ' ;
2017-01-08 16:30:30 -08:00
if ( ! force_label & & Merlin ( ) & & ( line | | operation ) ) { // MERLIN fixes and PoP does some naughty stuff like 'and = 0'
force_label = ( ! strref : : is_ws ( char0 ) & & char0 ! = ' { ' & & char0 ! = ' } ' ) | | char1 = = ' ] ' | | charE = = ' ? ' ;
} else if ( ! Merlin ( ) & & line [ 0 ] = = ' : ' ) { force_label = true ; }
2015-10-07 22:27:03 -07:00
if ( ! operation & & ! force_label ) {
2015-10-04 14:05:38 -07:00
if ( ConditionalAsm ( ) ) {
// scope open / close
switch ( line [ 0 ] ) {
case ' { ' :
2015-10-25 23:48:35 -07:00
error = EnterScope ( ) ;
2017-01-08 16:30:30 -08:00
brace_depth + + ;
2015-10-31 14:34:45 -07:00
list_flags | = ListLine : : CYCLES_START ;
2015-10-25 23:48:35 -07:00
if ( error = = STATUS_OK ) {
2015-09-29 22:07:04 -07:00
+ + line ;
line . skip_whitespace ( ) ;
2015-10-04 14:05:38 -07:00
}
break ;
case ' } ' :
// check for late eval of anything with an end scope
2015-10-25 23:48:35 -07:00
error = ExitScope ( ) ;
2017-01-08 16:30:30 -08:00
for ( LabelPool * pool = labelPools . getValues ( ) , * end = pool + labelPools . count ( ) ; pool ! = end ; pool + + ) {
pool - > ExitScope ( ( uint16_t ) brace_depth ) ;
}
brace_depth - - ;
2015-10-31 14:34:45 -07:00
list_flags | = ListLine : : CYCLES_STOP ;
2015-10-25 23:48:35 -07:00
if ( error = = STATUS_OK ) {
+ + line ;
line . skip_whitespace ( ) ;
}
2015-10-04 14:05:38 -07:00
break ;
2015-10-06 22:42:22 -07:00
case ' * ' :
// if first char is '*' this seems like a line comment on some assemblers
line . clear ( ) ;
break ;
case 127 :
+ + line ; // bad character?
break ;
2015-09-29 22:07:04 -07:00
}
2017-01-08 16:30:30 -08:00
} else { line . clear ( ) ; }
2015-10-23 22:44:56 -07:00
} else {
2015-10-04 14:05:38 -07:00
// ignore leading period for instructions and directives - not for labels
2015-10-07 22:27:03 -07:00
strref label = operation ;
2017-01-08 16:30:30 -08:00
if ( ( ! Merlin ( ) & & operation [ 0 ] = = ' : ' ) | | operation [ 0 ] = = ' . ' ) { + + operation ; }
2015-10-07 22:27:03 -07:00
operation = operation . before_or_full ( ' . ' ) ;
2015-10-23 22:44:56 -07:00
int op_idx = LookupOpCodeIndex ( operation . fnv1a_lower ( ) , aInstructions , num_instructions ) ;
if ( op_idx > = 0 & & ! force_label & & ( aInstructions [ op_idx ] . type = = OT_DIRECTIVE | | line [ 0 ] ! = ' = ' ) ) {
if ( line_nocom . is_substr ( operation . get ( ) ) ) {
line = line_nocom + strl_t ( operation . get ( ) + operation . get_len ( ) - line_nocom . get ( ) ) ;
line . skip_whitespace ( ) ;
}
if ( aInstructions [ op_idx ] . type = = OT_DIRECTIVE ) {
error = ApplyDirective ( ( AssemblerDirective ) aInstructions [ op_idx ] . index , line , contextStack . curr ( ) . source_file ) ;
2015-10-31 14:34:45 -07:00
list_flags | = ListLine : : KEYWORD ;
2015-10-23 22:44:56 -07:00
} else if ( ConditionalAsm ( ) & & aInstructions [ op_idx ] . type = = OT_MNEMONIC ) {
error = AddOpcode ( line , aInstructions [ op_idx ] . index , contextStack . curr ( ) . source_file ) ;
2015-10-31 14:34:45 -07:00
list_flags | = ListLine : : MNEMONIC ;
2015-10-19 22:44:02 -07:00
}
2015-10-04 14:05:38 -07:00
line . clear ( ) ;
} else if ( ! ConditionalAsm ( ) ) {
line . clear ( ) ; // do nothing if conditional nesting so clear the current line
} else if ( line . get_first ( ) = = ' = ' ) {
+ + line ;
error = AssignLabel ( label , line ) ;
line . clear ( ) ;
2015-10-31 14:34:45 -07:00
list_flags | = ListLine : : KEYWORD ;
}
else if ( keyword_equ . is_prefix_word ( line ) ) {
2015-10-06 22:42:22 -07:00
line + = keyword_equ . get_len ( ) ;
line . skip_whitespace ( ) ;
error = AssignLabel ( label , line ) ;
line . clear ( ) ;
2015-10-31 14:34:45 -07:00
list_flags | = ListLine : : KEYWORD ;
}
else {
2016-03-12 11:39:53 -08:00
uint32_t nameHash = label . fnv1a ( ) ;
uint32_t macro = FindLabelIndex ( nameHash , macros . getKeys ( ) , macros . count ( ) ) ;
2015-10-04 14:05:38 -07:00
bool gotConstruct = false ;
while ( macro < macros . count ( ) & & nameHash = = macros . getKey ( macro ) ) {
if ( macros . getValue ( macro ) . name . same_str_case ( label ) ) {
error = BuildMacro ( macros . getValue ( macro ) , line ) ;
gotConstruct = true ;
line . clear ( ) ; // don't process codes from here
break ;
2015-09-29 22:07:04 -07:00
}
2015-10-04 14:05:38 -07:00
macro + + ;
}
if ( ! gotConstruct ) {
2016-03-12 11:39:53 -08:00
uint32_t labPool = FindLabelIndex ( nameHash , labelPools . getKeys ( ) , labelPools . count ( ) ) ;
2015-10-04 14:05:38 -07:00
gotConstruct = false ;
while ( labPool < labelPools . count ( ) & & nameHash = = labelPools . getKey ( labPool ) ) {
if ( labelPools . getValue ( labPool ) . pool_name . same_str_case ( label ) ) {
error = AssignPoolLabel ( labelPools . getValue ( labPool ) , line ) ;
2015-10-01 23:16:36 -07:00
gotConstruct = true ;
2015-09-29 22:07:04 -07:00
line . clear ( ) ; // don't process codes from here
break ;
}
2015-10-04 14:05:38 -07:00
labPool + + ;
2015-09-29 22:07:04 -07:00
}
2015-10-01 23:16:36 -07:00
if ( ! gotConstruct ) {
2015-11-26 13:10:58 -08:00
if ( StringSymbol * pStr = GetString ( label ) ) {
StringAction ( pStr , line ) ;
line . clear ( ) ;
2016-03-11 14:12:32 -08:00
} else if ( Merlin ( ) & & strref : : is_ws ( line_start [ 0 ] ) ) {
2015-10-10 15:25:08 -07:00
error = ERROR_UNDEFINED_CODE ;
2017-01-08 16:30:30 -08:00
} else if ( label [ 0 ] = = ' $ ' ) {
2015-10-10 15:25:08 -07:00
line . clear ( ) ;
2017-01-08 16:30:30 -08:00
} else {
if ( label . get_last ( ) = = ' : ' ) { label . clip ( 1 ) ; }
2015-10-10 15:25:08 -07:00
error = AddressLabel ( label ) ;
line = line_start + int ( label . get ( ) + label . get_len ( ) - line_start . get ( ) ) ;
2017-01-08 16:30:30 -08:00
if ( line [ 0 ] = = ' : ' | | line [ 0 ] = = ' ? ' ) { + + line ; } // there may be codes after the label
2015-10-31 14:34:45 -07:00
list_flags | = ListLine : : KEYWORD ;
2015-10-10 15:25:08 -07:00
}
2015-09-29 22:07:04 -07:00
}
}
}
}
2015-10-04 14:05:38 -07:00
// Check for unterminated condition in source
if ( ! contextStack . curr ( ) . next_source & &
2015-12-01 21:21:00 -08:00
( ! ConditionalAsm ( ) | | ConditionalConsumed ( ) | | ! conditional_depth ) ) {
2016-03-11 14:12:32 -08:00
if ( Merlin ( ) ) { // this isn't a listed feature,
2015-10-19 22:44:02 -07:00
conditional_nesting [ 0 ] = 0 ; // some files just seem to get away without closing
conditional_consumed [ 0 ] = 0 ;
conditional_depth = 0 ;
} else {
2015-12-01 21:21:00 -08:00
PrintError ( conditional_source [ conditional_depth ] , ERROR_UNTERMINATED_CONDITION ) ;
2015-10-19 22:44:02 -07:00
return ERROR_UNTERMINATED_CONDITION ;
}
2015-10-04 14:05:38 -07:00
}
2017-01-08 16:30:30 -08:00
if ( line . same_str_case ( line_start ) ) {
2015-10-11 12:04:49 -07:00
error = ERROR_UNABLE_TO_PROCESS ;
2017-01-08 16:30:30 -08:00
} else if ( CurrSection ( ) . type = = ST_ZEROPAGE & & CurrSection ( ) . address > 0x100 ) {
2015-11-07 18:23:57 -08:00
error = ERROR_ZEROPAGE_SECTION_OUT_OF_RANGE ;
2017-01-08 16:30:30 -08:00
}
if ( error > STATUS_XREF_DEPENDENT ) {
2015-10-04 14:05:38 -07:00
PrintError ( line_start , error ) ;
2017-01-08 16:30:30 -08:00
}
2015-10-23 22:44:56 -07:00
2015-10-04 14:05:38 -07:00
// dealt with error, continue with next instruction unless too broken
2017-01-08 16:30:30 -08:00
if ( error < ERROR_STOP_PROCESSING_ON_HIGHER ) {
2015-10-04 14:05:38 -07:00
error = STATUS_OK ;
2017-01-08 16:30:30 -08:00
}
2015-09-29 22:07:04 -07:00
}
2015-10-18 12:42:10 -07:00
// update listing
if ( error = = STATUS_OK & & list_assembly ) {
if ( SectionId ( ) = = start_section ) {
2015-10-26 20:50:26 -07:00
Section & curr = CurrSection ( ) ;
2017-01-08 16:30:30 -08:00
if ( ! curr . pListing ) { curr . pListing = new Listing ; }
if ( curr . pListing & & curr . pListing - > size ( ) = = curr . pListing - > capacity ( ) ) {
curr . pListing - > reserve ( curr . pListing - > size ( ) + 256 ) ;
}
2015-10-31 14:34:45 -07:00
if ( ( ( list_flags & ( ListLine : : KEYWORD | ListLine : : CYCLES_START | ListLine : : CYCLES_STOP ) ) | |
( curr . address ! = start_address & & curr . size ( ) ) ) & & ! curr . IsDummySection ( ) ) {
2015-10-19 22:44:02 -07:00
struct ListLine lst ;
lst . address = start_address - curr . start_address ;
lst . size = curr . address - start_address ;
lst . code = contextStack . curr ( ) . source_file ;
lst . source_name = contextStack . curr ( ) . source_name ;
lst . line_offs = int ( code_line . get ( ) - lst . code . get ( ) ) ;
2015-10-31 14:34:45 -07:00
lst . flags = list_flags ;
2015-10-18 12:42:10 -07:00
curr . pListing - > push_back ( lst ) ;
2015-10-19 22:44:02 -07:00
}
2015-10-18 12:42:10 -07:00
}
}
2015-10-04 14:05:38 -07:00
return error ;
}
// Build a segment of code (file or macro)
2017-01-08 16:30:30 -08:00
StatusCode Asm : : BuildSegment ( ) {
2015-10-04 14:05:38 -07:00
StatusCode error = STATUS_OK ;
while ( contextStack . curr ( ) . read_source ) {
contextStack . curr ( ) . next_source = contextStack . curr ( ) . read_source ;
2015-10-23 22:44:56 -07:00
error = BuildLine ( contextStack . curr ( ) . next_source . line ( ) ) ;
2017-01-08 16:30:30 -08:00
if ( error > ERROR_STOP_PROCESSING_ON_HIGHER ) { break ; }
2015-10-04 14:05:38 -07:00
contextStack . curr ( ) . read_source = contextStack . curr ( ) . next_source ;
}
2017-01-08 16:30:30 -08:00
if ( error = = STATUS_OK ) { error = CheckLateEval ( strref ( ) , CurrSection ( ) . GetPC ( ) ) ; }
2015-09-29 22:07:04 -07:00
return error ;
}
2015-10-18 12:42:10 -07:00
// Produce the assembler listing
2015-10-31 14:34:45 -07:00
# define MAX_DEPTH_CYCLE_COUNTER 64
2015-11-01 15:08:38 -08:00
struct cycleCnt {
int base ;
2016-03-12 11:39:53 -08:00
int16_t plus , a16 , x16 , dp ;
2015-11-01 15:08:38 -08:00
void clr ( ) { base = 0 ; plus = a16 = x16 = dp = 0 ; }
2016-03-12 11:39:53 -08:00
void add ( uint8_t c ) {
2015-11-01 15:08:38 -08:00
if ( c ! = 0xff ) {
base + = ( c > > 1 ) & 7 ;
plus + = c & 1 ;
if ( c & 0xf0 ) {
int i = c > > 4 ;
if ( i < = 8 ) {
a16 + = timing_65816_plus [ i ] [ 0 ] ;
x16 + = timing_65816_plus [ i ] [ 1 ] ;
dp + = timing_65816_plus [ i ] [ 2 ] ;
}
}
}
}
2017-01-08 16:30:30 -08:00
int plus_acc ( ) { return plus + a16 + x16 + dp ; }
2015-11-01 15:08:38 -08:00
void combine ( const struct cycleCnt & o ) {
base + = o . base ; plus + = o . plus ; a16 + = o . a16 ; x16 + = o . x16 ; dp + = o . dp ;
}
bool complex ( ) const { return a16 ! = 0 | | x16 ! = 0 | | dp ! = 0 ; }
2017-01-08 16:30:30 -08:00
static int get_base ( uint8_t c ) { return ( c & 0xf ) > > 1 ; }
2016-03-12 11:39:53 -08:00
static int sum_plus ( uint8_t c ) {
2017-01-08 16:30:30 -08:00
if ( c = = 0xff ) { return 0 ; }
2015-11-01 15:08:38 -08:00
int i = c > > 4 ;
2017-01-08 16:30:30 -08:00
if ( i ) {
return i < = 8 ? ( timing_65816_plus [ i ] [ 0 ] + timing_65816_plus [ i ] [ 1 ] + timing_65816_plus [ i ] [ 2 ] ) : 0 ;
}
2015-11-01 15:08:38 -08:00
return c & 1 ;
}
} ;
2019-09-03 17:10:48 -07:00
bool Asm : : ListTassStyle ( strref filename ) {
// NOTE: This file needs more information to be useful for things
FILE * f = stdout ;
bool opened = false ;
if ( filename ) {
f = fopen ( strown < 512 > ( filename ) . c_str ( ) , " w " ) ;
if ( ! f ) { return false ; }
opened = true ;
}
// ensure that the greatest instruction set referenced is used for listing
if ( list_cpu ! = cpu ) { SetCPU ( list_cpu ) ; }
// Build a disassembly lookup table
uint8_t mnemonic [ 256 ] ;
uint8_t addrmode [ 256 ] ;
memset ( mnemonic , 255 , sizeof ( mnemonic ) ) ;
memset ( addrmode , 255 , sizeof ( addrmode ) ) ;
for ( int i = 0 ; i < opcode_count ; i + + ) {
for ( int j = AMB_COUNT - 1 ; j > = 0 ; j - - ) {
if ( opcode_table [ i ] . modes & ( 1 < < j ) ) {
uint8_t op = opcode_table [ i ] . aCodes [ j ] ;
if ( addrmode [ op ] = = 255 ) {
mnemonic [ op ] = ( uint8_t ) i ;
addrmode [ op ] = ( uint8_t ) j ;
}
}
}
}
strref first_src ;
for ( std : : vector < Section > : : iterator si = allSections . begin ( ) ; si ! = allSections . end ( ) & & ! first_src ; + + si ) {
if ( ! si - > pListing )
continue ;
for ( auto & li : * si - > pListing ) {
if ( li . source_name ) { first_src = li . source_name ; break ; }
}
}
fprintf ( f , " ;6502/65C02/65816/CPU64/DTV Turbo Assembler V1.4x listing file of \" " STRREF_FMT " \" \n ;done on WkDay Month Date Time \n \n " , STRREF_ARG ( first_src ) ) ;
fprintf ( f , " ;Offset \t ;Hex \t \t ;Monitor \t ;Source \n \n " ) ;
for ( auto & si : allSections ) {
if ( ! si . pListing | | si . type = = ST_REMOVED | | ! si . pListing ) { continue ; }
for ( const struct ListLine & lst : * si . pListing ) {
/*if( lst.size && lst.wasMnemonic() )*/ {
strown < 256 > out ;
/*if( lst.size )*/ { out . sprintf_append ( " .%04x \t " , lst . address + si . start_address ) ; }
int s = lst . wasMnemonic ( ) ? ( lst . size < 4 ? lst . size : 4 ) : ( lst . size < 8 ? lst . size : 8 ) ;
if ( si . output & & si . output_capacity > = size_t ( lst . address + s ) ) {
for ( int b = 0 ; b < s ; + + b ) {
out . sprintf_append ( " %02x " , si . output [ lst . address + b ] ) ;
}
}
out . append ( " \t \t " ) ;
if ( lst . size & & lst . wasMnemonic ( ) ) {
//out.pad_to(' ', 21);
uint8_t * buf = si . output + lst . address ;
uint8_t op = mnemonic [ * buf ] ;
uint8_t am = addrmode [ * buf ] ;
if ( op ! = 255 & & am ! = 255 & & am < ( sizeof ( aAddrModeFmt ) / sizeof ( aAddrModeFmt [ 0 ] ) ) ) {
const char * fmt = aAddrModeFmt [ am ] ;
if ( opcode_table [ op ] . modes & AMM_FLIPXY ) {
if ( am = = AMB_ZP_X ) fmt = " %s $%02x,y " ;
else if ( am = = AMB_ABS_X ) fmt = " %s $%04x,y " ;
}
if ( opcode_table [ op ] . modes & AMM_ZP_ABS ) {
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 ( opcode_table [ op ] . modes & AMM_BRANCH_L ) {
out . sprintf_append ( fmt , opcode_table [ op ] . instr , ( int16_t ) ( buf [ 1 ] | ( buf [ 2 ] < < 8 ) ) + lst . address + si . start_address + 3 ) ;
} else if ( am = = AMB_NON | | am = = AMB_ACC ) {
out . sprintf_append ( fmt , opcode_table [ op ] . instr ) ;
} else if ( am = = AMB_ABS | | am = = AMB_ABS_X | | am = = AMB_ABS_Y | | am = = AMB_REL | | am = = AMB_REL_X | | am = = AMB_REL_L ) {
out . sprintf_append ( fmt , opcode_table [ op ] . instr , buf [ 1 ] | ( buf [ 2 ] < < 8 ) ) ;
} else if ( am = = AMB_ABS_L | | am = = AMB_ABS_L_X ) {
out . sprintf_append ( fmt , opcode_table [ op ] . instr , buf [ 1 ] | ( buf [ 2 ] < < 8 ) | ( buf [ 3 ] < < 16 ) ) ;
} else if ( am = = AMB_BLK_MOV ) {
out . sprintf_append ( fmt , opcode_table [ op ] . instr , buf [ 1 ] , buf [ 2 ] ) ;
} else if ( am = = AMB_IMM & & lst . size = = 3 ) {
out . sprintf_append ( " %s #$%04x " , opcode_table [ op ] . instr , buf [ 1 ] | ( buf [ 2 ] < < 8 ) ) ;
} else {
out . sprintf_append ( fmt , opcode_table [ op ] . instr , buf [ 1 ] ) ;
}
}
} else { out . append ( ' \t ' ) ; }
// out.pad_to( ' ', 36 );
out . append ( ' \t ' ) ;
strref line = lst . code . get_skipped ( lst . line_offs ) . get_line ( ) ;
line . clip_trailing_whitespace ( ) ;
strown < 128 > line_fix ( line ) ;
for ( strl_t pos = 0 ; pos < line_fix . len ( ) ; + + pos ) {
if ( line_fix [ pos ] = = ' \t ' )
line_fix . exchange ( pos , 1 , pos & 1 ? strref ( " " ) : strref ( " " ) ) ;
}
out . append ( line_fix . get_strref ( ) ) ;
fprintf ( f , STRREF_FMT " \n " , STRREF_ARG ( out ) ) ;
}
}
}
fprintf ( f , " \n ;****** end of code \n " ) ;
if ( opened ) { fclose ( f ) ; }
return true ;
}
2017-01-08 16:30:30 -08:00
bool Asm : : List ( strref filename ) {
2015-10-18 12:42:10 -07:00
FILE * f = stdout ;
bool opened = false ;
if ( filename ) {
f = fopen ( strown < 512 > ( filename ) . c_str ( ) , " w " ) ;
2017-01-08 16:30:30 -08:00
if ( ! f ) { return false ; }
2015-10-18 12:42:10 -07:00
opened = true ;
}
2015-10-23 22:44:56 -07:00
// ensure that the greatest instruction set referenced is used for listing
2017-01-08 16:30:30 -08:00
if ( list_cpu ! = cpu ) { SetCPU ( list_cpu ) ; }
2015-10-23 22:44:56 -07:00
2015-10-18 12:42:10 -07:00
// Build a disassembly lookup table
2016-03-12 11:39:53 -08:00
uint8_t mnemonic [ 256 ] ;
uint8_t addrmode [ 256 ] ;
2015-10-18 12:42:10 -07:00
memset ( mnemonic , 255 , sizeof ( mnemonic ) ) ;
memset ( addrmode , 255 , sizeof ( addrmode ) ) ;
2015-10-21 22:34:01 -07:00
for ( int i = 0 ; i < opcode_count ; i + + ) {
2015-10-23 22:44:56 -07:00
for ( int j = AMB_COUNT - 1 ; j > = 0 ; j - - ) {
2015-10-21 22:34:01 -07:00
if ( opcode_table [ i ] . modes & ( 1 < < j ) ) {
2016-03-12 11:39:53 -08:00
uint8_t op = opcode_table [ i ] . aCodes [ j ] ;
2015-10-23 22:44:56 -07:00
if ( addrmode [ op ] = = 255 ) {
2016-05-25 22:44:17 -07:00
mnemonic [ op ] = ( uint8_t ) i ;
addrmode [ op ] = ( uint8_t ) j ;
2015-10-23 22:44:56 -07:00
}
2015-10-18 12:42:10 -07:00
}
}
}
2015-11-01 15:08:38 -08:00
struct cycleCnt cycles [ MAX_DEPTH_CYCLE_COUNTER ] ;
2016-03-12 11:39:53 -08:00
int16_t cycles_depth = 0 ;
2015-11-01 15:08:38 -08:00
memset ( cycles , 0 , sizeof ( cycles ) ) ;
2015-10-31 14:34:45 -07:00
2017-08-06 16:07:41 -07:00
// show merged sections
for ( size_t i = 0 , n = allSections . size ( ) ; i < n ; + + i )
{
Section & s = allSections [ i ] ;
if ( s . type ! = ST_REMOVED ) {
if ( s . include_from ) {
fprintf ( f , " Section " STRREF_FMT " from " STRREF_FMT " $%04x - $%04x ($%04x) \n " ,
STRREF_ARG ( s . name ) , STRREF_ARG ( s . include_from ) , s . start_address , s . address , s . address - s . start_address ) ;
} else {
fprintf ( f , " Section " STRREF_FMT " $%04x - $%04x ($%04x) \n " ,
STRREF_ARG ( s . name ) , s . start_address , s . address , s . address - s . start_address ) ;
}
for ( size_t j = 0 ; j < n ; + + j )
{
Section & s2 = allSections [ j ] ;
if ( s2 . type = = ST_REMOVED & & s2 . merged_into > = 0 )
{
int offset = s2 . merged_at ;
int parent = s2 . merged_into ;
while ( parent ! = i & & parent > = 0 ) {
offset + = allSections [ parent ] . merged_at ;
parent = allSections [ parent ] . merged_into ;
}
if ( parent = = i ) {
if ( s2 . include_from ) {
fprintf ( f , " + " STRREF_FMT " from " STRREF_FMT " $%04x - $%04x ($%04x) at offset 0x%04x \n " ,
STRREF_ARG ( s2 . name ) , STRREF_ARG ( s2 . include_from ) , s2 . merged_at + s . start_address ,
s2 . merged_at + s . start_address + s2 . merged_size , s2 . merged_size , s2 . merged_at ) ;
} else {
fprintf ( f , " + " STRREF_FMT " $%04x - $%04x ($%04x) at offset 0x%04x \n " ,
STRREF_ARG ( s2 . name ) , s2 . merged_at + s . start_address ,
s2 . merged_at + s . start_address + s2 . merged_size , s2 . merged_size , s2 . merged_at ) ;
}
}
}
}
}
}
2015-10-18 12:42:10 -07:00
strref prev_src ;
int prev_offs = 0 ;
for ( std : : vector < Section > : : iterator si = allSections . begin ( ) ; si ! = allSections . end ( ) ; + + si ) {
2017-08-06 16:07:41 -07:00
if ( si - > merged_into > = 0 ) {
fprintf ( f , STRREF_FMT " from " STRREF_FMT " merged into " STRREF_FMT " at offset 0x%04x \n " ,
STRREF_ARG ( si - > name ) , STRREF_ARG ( si - > include_from ) , STRREF_ARG ( allSections [ si - > merged_into ] . name ) , si - > merged_at ) ; }
2017-01-08 16:30:30 -08:00
if ( si - > type = = ST_REMOVED ) { continue ; }
2015-11-08 18:06:45 -08:00
if ( si - > address_assigned )
fprintf ( f , " Section " STRREF_FMT " (%d, %s): $%04x-$%04x \n " , STRREF_ARG ( si - > name ) ,
2015-11-09 00:07:55 -08:00
( int ) ( & * si - & allSections [ 0 ] ) , si - > type > = 0 & & si - > type < num_section_type_str ?
str_section_type [ si - > type ] : " ??? " , si - > start_address , si - > address ) ;
2015-11-08 18:06:45 -08:00
else
fprintf ( f , " Section " STRREF_FMT " (%d, %s) (relocatable) \n " , STRREF_ARG ( si - > name ) ,
( int ) ( & * si - & allSections [ 0 ] ) , str_section_type [ si - > type ] ) ;
2015-10-18 12:42:10 -07:00
if ( ! si - > pListing )
continue ;
for ( Listing : : iterator li = si - > pListing - > begin ( ) ; li ! = si - > pListing - > end ( ) ; + + li ) {
strown < 256 > out ;
const struct ListLine & lst = * li ;
if ( prev_src . fnv1a ( ) ! = lst . source_name . fnv1a ( ) | | lst . line_offs < prev_offs ) {
fprintf ( f , STRREF_FMT " (%d): \n " , STRREF_ARG ( lst . source_name ) , lst . code . count_lines ( lst . line_offs ) ) ;
prev_src = lst . source_name ;
2015-10-23 22:44:56 -07:00
} else {
2015-10-18 12:42:10 -07:00
strref prvline = lst . code . get_substr ( prev_offs , lst . line_offs - prev_offs ) ;
prvline . next_line ( ) ;
if ( prvline . count_lines ( ) < 5 ) {
while ( strref space_line = prvline . line ( ) ) {
space_line . clip_trailing_whitespace ( ) ;
strown < 128 > line_fix ( space_line ) ;
for ( strl_t pos = 0 ; pos < line_fix . len ( ) ; + + pos ) {
2017-01-08 16:30:30 -08:00
if ( line_fix [ pos ] = = ' \t ' ) {
line_fix . exchange ( pos , 1 , pos & 1 ? strref ( " " ) : strref ( " " ) ) ;
}
2015-10-18 12:42:10 -07:00
}
2016-12-23 13:56:57 -08:00
out . pad_to ( ' ' , aCPUs [ cpu ] . timing ? 40 : 33 ) ;
2015-10-18 12:42:10 -07:00
out . append ( line_fix . get_strref ( ) ) ;
fprintf ( f , STRREF_FMT " \n " , STRREF_ARG ( out ) ) ;
out . clear ( ) ;
}
2015-10-23 22:44:56 -07:00
} else {
2015-10-18 12:42:10 -07:00
fprintf ( f , STRREF_FMT " (%d): \n " , STRREF_ARG ( lst . source_name ) , lst . code . count_lines ( lst . line_offs ) ) ;
}
}
2017-01-08 16:30:30 -08:00
if ( lst . size ) { out . sprintf_append ( " $%04x " , lst . address + si - > start_address ) ; }
2015-10-31 14:34:45 -07:00
int s = lst . wasMnemonic ( ) ? ( lst . size < 4 ? lst . size : 4 ) : ( lst . size < 8 ? lst . size : 8 ) ;
2015-11-23 22:34:30 -08:00
if ( si - > output & & si - > output_capacity > = size_t ( lst . address + s ) ) {
2017-01-08 16:30:30 -08:00
for ( int b = 0 ; b < s ; + + b ) {
out . sprintf_append ( " %02x " , si - > output [ lst . address + b ] ) ;
}
2015-10-18 12:42:10 -07:00
}
2015-10-31 14:34:45 -07:00
if ( lst . startClock ( ) & & cycles_depth < MAX_DEPTH_CYCLE_COUNTER ) {
2015-11-01 15:08:38 -08:00
cycles_depth + + ; cycles [ cycles_depth ] . clr ( ) ;
2016-12-23 13:56:57 -08:00
out . pad_to ( ' ' , 6 ) ; out . sprintf_append ( " c>%d " , cycles_depth ) ;
2015-10-31 14:34:45 -07:00
}
if ( lst . stopClock ( ) ) {
2016-12-23 13:56:57 -08:00
out . pad_to ( ' ' , 6 ) ;
2017-01-08 16:30:30 -08:00
if ( cycles [ cycles_depth ] . complex ( ) ) {
2015-11-15 21:14:46 -08:00
out . sprintf_append ( " c<%d = %d + m%d + i%d + d%d " , cycles_depth ,
2017-01-08 16:30:30 -08:00
cycles [ cycles_depth ] . base , cycles [ cycles_depth ] . a16 ,
cycles [ cycles_depth ] . x16 , cycles [ cycles_depth ] . dp ) ;
} else {
2015-11-15 21:14:46 -08:00
out . sprintf_append ( " c<%d = %d + %d " , cycles_depth ,
2017-01-08 16:30:30 -08:00
cycles [ cycles_depth ] . base , cycles [ cycles_depth ] . plus_acc ( ) ) ;
}
2015-10-31 14:34:45 -07:00
if ( cycles_depth ) {
2015-11-01 15:08:38 -08:00
cycles_depth - - ;
cycles [ cycles_depth ] . combine ( cycles [ cycles_depth + 1 ] ) ;
2015-10-31 14:34:45 -07:00
}
}
if ( lst . size & & lst . wasMnemonic ( ) ) {
2016-12-23 13:56:57 -08:00
out . pad_to ( ' ' , 18 ) ;
2016-03-12 11:39:53 -08:00
uint8_t * buf = si - > output + lst . address ;
uint8_t op = mnemonic [ * buf ] ;
uint8_t am = addrmode [ * buf ] ;
2015-10-21 22:34:01 -07:00
if ( op ! = 255 & & am ! = 255 & & am < ( sizeof ( aAddrModeFmt ) / sizeof ( aAddrModeFmt [ 0 ] ) ) ) {
2015-10-18 12:42:10 -07:00
const char * fmt = aAddrModeFmt [ am ] ;
2015-10-21 22:34:01 -07:00
if ( opcode_table [ op ] . modes & AMM_FLIPXY ) {
2015-10-18 12:42:10 -07:00
if ( am = = AMB_ZP_X ) fmt = " %s $%02x,y " ;
else if ( am = = AMB_ABS_X ) fmt = " %s $%04x,y " ;
}
2017-01-08 16:30:30 -08:00
if ( opcode_table [ op ] . modes & AMM_ZP_ABS ) {
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 ( opcode_table [ op ] . modes & AMM_BRANCH_L ) {
out . sprintf_append ( fmt , opcode_table [ op ] . instr , ( int16_t ) ( buf [ 1 ] | ( buf [ 2 ] < < 8 ) ) + lst . address + si - > start_address + 3 ) ;
} else if ( am = = AMB_NON | | am = = AMB_ACC ) {
2015-10-21 22:34:01 -07:00
out . sprintf_append ( fmt , opcode_table [ op ] . instr ) ;
2017-01-08 16:30:30 -08:00
} else if ( am = = AMB_ABS | | am = = AMB_ABS_X | | am = = AMB_ABS_Y | | am = = AMB_REL | | am = = AMB_REL_X | | am = = AMB_REL_L ) {
out . sprintf_append ( fmt , opcode_table [ op ] . instr , buf [ 1 ] | ( buf [ 2 ] < < 8 ) ) ;
} else if ( am = = AMB_ABS_L | | am = = AMB_ABS_L_X ) {
out . sprintf_append ( fmt , opcode_table [ op ] . instr , buf [ 1 ] | ( buf [ 2 ] < < 8 ) | ( buf [ 3 ] < < 16 ) ) ;
} else if ( am = = AMB_BLK_MOV ) {
2015-10-23 22:44:56 -07:00
out . sprintf_append ( fmt , opcode_table [ op ] . instr , buf [ 1 ] , buf [ 2 ] ) ;
2017-01-08 16:30:30 -08:00
} else if ( am = = AMB_IMM & & lst . size = = 3 ) {
out . sprintf_append ( " %s #$%04x " , opcode_table [ op ] . instr , buf [ 1 ] | ( buf [ 2 ] < < 8 ) ) ;
} else {
2015-10-21 22:34:01 -07:00
out . sprintf_append ( fmt , opcode_table [ op ] . instr , buf [ 1 ] ) ;
2017-01-08 16:30:30 -08:00
}
2015-10-30 22:30:16 -07:00
if ( aCPUs [ cpu ] . timing ) {
2015-11-01 15:08:38 -08:00
cycles [ cycles_depth ] . add ( aCPUs [ cpu ] . timing [ * buf ] ) ;
2016-12-23 13:56:57 -08:00
out . pad_to ( ' ' , 33 ) ;
2017-01-08 16:30:30 -08:00
if ( cycleCnt : : sum_plus ( aCPUs [ cpu ] . timing [ * buf ] ) = = 1 ) {
2015-11-01 15:08:38 -08:00
out . sprintf_append ( " %d+ " , cycleCnt : : get_base ( aCPUs [ cpu ] . timing [ * buf ] ) ) ;
2017-01-08 16:30:30 -08:00
} else if ( cycleCnt : : sum_plus ( aCPUs [ cpu ] . timing [ * buf ] ) ) {
2015-11-01 15:08:38 -08:00
out . sprintf_append ( " %d+%d " , cycleCnt : : get_base ( aCPUs [ cpu ] . timing [ * buf ] ) , cycleCnt : : sum_plus ( aCPUs [ cpu ] . timing [ * buf ] ) ) ;
2017-01-08 16:30:30 -08:00
} else {
2015-11-01 15:08:38 -08:00
out . sprintf_append ( " %d " , cycleCnt : : get_base ( aCPUs [ cpu ] . timing [ * buf ] ) ) ;
2017-01-08 16:30:30 -08:00
}
2015-10-30 22:30:16 -07:00
}
2015-10-18 12:42:10 -07:00
}
}
2015-10-31 14:34:45 -07:00
2016-12-23 13:56:57 -08:00
out . pad_to ( ' ' , aCPUs [ cpu ] . timing ? 40 : 33 ) ;
2015-10-18 12:42:10 -07:00
strref line = lst . code . get_skipped ( lst . line_offs ) . get_line ( ) ;
line . clip_trailing_whitespace ( ) ;
strown < 128 > line_fix ( line ) ;
for ( strl_t pos = 0 ; pos < line_fix . len ( ) ; + + pos ) {
if ( line_fix [ pos ] = = ' \t ' )
line_fix . exchange ( pos , 1 , pos & 1 ? strref ( " " ) : strref ( " " ) ) ;
}
out . append ( line_fix . get_strref ( ) ) ;
fprintf ( f , STRREF_FMT " \n " , STRREF_ARG ( out ) ) ;
prev_offs = lst . line_offs ;
}
}
2017-01-08 16:30:30 -08:00
if ( opened ) { fclose ( f ) ; }
2015-10-18 12:42:10 -07:00
return true ;
}
// Create a listing of all valid instructions and addressing modes
2017-01-08 16:30:30 -08:00
bool Asm : : AllOpcodes ( strref filename ) {
2015-10-18 12:42:10 -07:00
FILE * f = stdout ;
bool opened = false ;
if ( filename ) {
f = fopen ( strown < 512 > ( filename ) . c_str ( ) , " w " ) ;
2017-01-08 16:30:30 -08:00
if ( ! f ) { return false ; }
2015-10-18 12:42:10 -07:00
opened = true ;
}
2015-10-21 22:34:01 -07:00
for ( int i = 0 ; i < opcode_count ; i + + ) {
2016-03-12 11:39:53 -08:00
uint32_t modes = opcode_table [ i ] . modes ;
2015-10-18 12:42:10 -07:00
for ( int a = 0 ; a < AMB_COUNT ; a + + ) {
2017-01-08 16:30:30 -08:00
if ( modes & ( 1 < < a ) ) {
2015-10-18 12:42:10 -07:00
const char * fmt = aAddrModeFmt [ a ] ;
2015-10-21 22:34:01 -07:00
fputs ( " \t " , f ) ;
2017-01-08 16:30:30 -08:00
if ( opcode_table [ i ] . modes & AMM_BRANCH ) {
2015-10-21 22:34:01 -07:00
fprintf ( f , " %s *+%d " , opcode_table [ i ] . instr , 5 ) ;
2017-01-08 16:30:30 -08:00
} else if ( a = = AMB_ZP_ABS ) {
2015-10-21 22:34:01 -07:00
fprintf ( f , " %s $%02x,*+%d " , opcode_table [ i ] . instr , 0x23 , 13 ) ;
2017-01-08 16:30:30 -08:00
} else {
2015-10-21 22:34:01 -07:00
if ( opcode_table [ i ] . modes & AMM_FLIPXY ) {
2015-10-18 12:42:10 -07:00
if ( a = = AMB_ZP_X ) fmt = " %s $%02x,y " ;
else if ( a = = AMB_ABS_X ) fmt = " %s $%04x,y " ;
}
2015-10-23 22:44:56 -07:00
if ( a = = AMB_ABS_L | | a = = AMB_ABS_L_X ) {
2017-01-08 16:30:30 -08:00
if ( ( modes & ~ ( AMM_ABS_L | AMM_ABS_L_X ) ) ) {
2015-10-23 22:44:56 -07:00
fprintf ( f , a = = AMB_ABS_L ? " %s.l $%06x " : " %s.l $%06x,x " , opcode_table [ i ] . instr , 0x222120 ) ;
2017-01-08 16:30:30 -08:00
} else {
2015-10-23 22:44:56 -07:00
fprintf ( f , fmt , opcode_table [ i ] . instr , 0x222120 ) ;
2017-01-08 16:30:30 -08:00
}
} else if ( a = = AMB_ABS | | a = = AMB_ABS_X | | a = = AMB_ABS_Y | | a = = AMB_REL | | a = = AMB_REL_X | | a = = AMB_REL_L ) {
2015-10-21 22:34:01 -07:00
fprintf ( f , fmt , opcode_table [ i ] . instr , 0x2120 ) ;
2017-01-08 16:30:30 -08:00
} else if ( a = = AMB_IMM & & ( modes & ( AMM_IMM_DBL_A | AMM_IMM_DBL_XY ) ) ) {
2015-10-23 22:44:56 -07:00
fprintf ( f , " %s.b #$%02x \n " , opcode_table [ i ] . instr , 0x21 ) ;
fprintf ( f , " \t %s.w #$%04x " , opcode_table [ i ] . instr , 0x2322 ) ;
2017-01-08 16:30:30 -08:00
} else {
2015-10-21 22:34:01 -07:00
fprintf ( f , fmt , opcode_table [ i ] . instr , 0x21 , 0x20 , 0x1f ) ;
2015-10-23 22:44:56 -07:00
}
2017-01-08 16:30:30 -08:00
}
2015-10-18 12:42:10 -07:00
fputs ( " \n " , f ) ;
}
}
}
2017-01-08 16:30:30 -08:00
if ( opened ) { fclose ( f ) ; }
2015-10-18 12:42:10 -07:00
return true ;
}
2015-09-29 22:07:04 -07:00
// create an instruction table (mnemonic hash lookup + directives)
2017-01-08 16:30:30 -08:00
void Asm : : Assemble ( strref source , strref filename , bool obj_target ) {
2015-10-24 13:41:11 -07:00
SetCPU ( cpu ) ;
2015-09-29 22:07:04 -07:00
StatusCode error = STATUS_OK ;
2015-12-01 21:21:00 -08:00
PushContext ( filename , source , source ) ;
2015-10-10 15:25:08 -07:00
scope_address [ scope_depth ] = CurrSection ( ) . GetPC ( ) ;
2015-12-01 21:21:00 -08:00
while ( contextStack . has_work ( ) & & error = = STATUS_OK ) {
2015-10-23 22:44:56 -07:00
error = BuildSegment ( ) ;
2017-01-08 16:30:30 -08:00
if ( contextStack . curr ( ) . complete ( ) ) {
2015-12-01 21:21:00 -08:00
error = PopContext ( ) ;
2017-01-08 16:30:30 -08:00
} else {
2016-03-11 17:08:44 -08:00
error = FlushLocalLabels ( scope_depth ) ;
2017-01-08 16:30:30 -08:00
if ( error > = FIRST_ERROR ) { break ; }
2015-10-04 16:06:45 -07:00
contextStack . curr ( ) . restart ( ) ;
2016-03-11 17:08:44 -08:00
error = STATUS_OK ;
2016-03-11 16:58:24 -08:00
}
2015-09-29 22:07:04 -07:00
}
2017-01-08 16:30:30 -08:00
if ( error = = STATUS_OK ) {
if ( ! obj_target ) { LinkZP ( ) ; }
2015-09-29 22:07:04 -07:00
error = CheckLateEval ( ) ;
2017-01-08 16:30:30 -08:00
if ( error > STATUS_XREF_DEPENDENT ) {
2015-09-29 22:07:04 -07:00
strown < 512 > errorText ;
errorText . copy ( " Error: " ) ;
errorText . append ( aStatusStrings [ error ] ) ;
fwrite ( errorText . get ( ) , errorText . get_len ( ) , 1 , stderr ) ;
2017-01-08 16:30:30 -08:00
} else { CheckLateEval ( strref ( ) , - 1 , true ) ; } // output any missing xref's
2015-10-01 23:16:36 -07:00
2015-10-13 19:38:13 -07:00
if ( ! obj_target ) {
for ( std : : vector < LateEval > : : iterator i = lateEval . begin ( ) ; i ! = lateEval . end ( ) ; + + i ) {
strown < 512 > errorText ;
int line = i - > source_file . count_lines ( i - > expression ) ;
errorText . sprintf ( " Error (%d): " , line + 1 ) ;
errorText . append ( " Failed to evaluate label \" " ) ;
errorText . append ( i - > expression ) ;
if ( line > = 0 ) {
errorText . append ( " \" : \" " ) ;
errorText . append ( i - > source_file . get_line ( line ) . get_trimmed_ws ( ) ) ;
}
errorText . append ( " \" \n " ) ;
fwrite ( errorText . get ( ) , errorText . get_len ( ) , 1 , stderr ) ;
2015-09-29 22:07:04 -07:00
}
}
2017-01-08 16:30:30 -08:00
} else {
2015-12-01 21:21:00 -08:00
PrintError ( & contextStack . curr ( ) ?
2017-01-08 16:30:30 -08:00
contextStack . curr ( ) . read_source . get_line ( ) : strref ( ) , error ) ;
}
2015-09-29 22:07:04 -07:00
}
2015-10-13 19:38:13 -07:00
//
//
// OBJECT FILE HANDLING
//
//
struct ObjFileHeader {
2016-03-12 11:39:53 -08:00
int16_t id ; // 'x6'
int16_t sections ;
int16_t relocs ;
int16_t labels ;
int16_t late_evals ;
int16_t map_symbols ;
uint32_t stringdata ;
2015-10-13 19:38:13 -07:00
int bindata ;
} ;
struct ObjFileStr {
int offs ; // offset into string table
} ;
struct ObjFileSection {
enum SectionFlags {
OFS_DUMMY ,
OFS_FIXED ,
OFS_MERGED ,
} ;
struct ObjFileStr name ;
2015-10-18 19:48:03 -07:00
struct ObjFileStr exp_app ;
2015-10-13 19:38:13 -07:00
int start_address ;
2015-11-08 18:06:45 -08:00
int end_address ; // address size
2015-10-13 19:38:13 -07:00
int output_size ; // assembled binary size
2015-10-18 19:48:03 -07:00
int align_address ;
2016-03-12 11:39:53 -08:00
int16_t next_group ; // next section of group
int16_t first_group ; // first section of group
int16_t relocs ;
2015-11-06 22:48:50 -08:00
SectionType type ;
2016-03-12 11:39:53 -08:00
int8_t flags ;
2015-10-13 19:38:13 -07:00
} ;
struct ObjFileReloc {
int base_value ;
int section_offset ;
2016-03-12 11:39:53 -08:00
int16_t target_section ;
int8_t bytes ;
int8_t shift ;
2015-10-13 19:38:13 -07:00
} ;
struct ObjFileLabel {
enum LabelFlags {
2016-03-12 11:39:53 -08:00
OFL_EVAL = ( 1 < < 15 ) , // Evaluated (may still be relative)
OFL_ADDR = ( 1 < < 14 ) , // Address or Assign
OFL_CNST = ( 1 < < 13 ) , // Constant
OFL_XDEF = OFL_CNST - 1 // External (index into file array)
2015-10-13 19:38:13 -07:00
} ;
struct ObjFileStr name ;
int value ;
2016-03-12 11:39:53 -08:00
int flags ; // 1<<(LabelFlags)
int16_t section ; // -1 if resolved, file section # if section rel
int16_t mapIndex ; // -1 if resolved, index into map if relative
2015-10-13 19:38:13 -07:00
} ;
struct ObjFileLateEval {
struct ObjFileStr label ;
struct ObjFileStr expression ;
2016-03-12 11:39:53 -08:00
int address ; // PC relative to section or fixed
int target ; // offset into section memory
int16_t section ; // section to target
int16_t rept ; // value of rept for this late eval
int16_t scope ; // PC start of scope
int16_t type ; // label, byte, branch, word (LateEval::Type)
2015-10-13 19:38:13 -07:00
} ;
struct ObjFileMapSymbol {
2016-03-12 11:39:53 -08:00
struct ObjFileStr name ; // symbol name
2015-10-13 19:38:13 -07:00
int value ;
2016-03-12 11:39:53 -08:00
int16_t section ;
bool local ; // local labels are probably needed
2015-10-13 19:38:13 -07:00
} ;
// Simple string pool, converts strref strings to zero terminated strings and returns the offset to the string in the pool.
2017-01-08 16:30:30 -08:00
static int _AddStrPool ( const strref str , pairArray < uint32_t , int > * pLookup , char * * strPool , uint32_t & strPoolSize , uint32_t & strPoolCap ) {
if ( ! str . get ( ) | | ! str . get_len ( ) ) { return - 1 ; } // empty string
2015-10-26 20:50:26 -07:00
2016-03-12 11:39:53 -08:00
uint32_t hash = str . fnv1a ( ) ;
uint32_t index = FindLabelIndex ( hash , pLookup - > getKeys ( ) , pLookup - > count ( ) ) ;
2017-01-08 16:30:30 -08:00
if ( index < pLookup - > count ( ) & & str . same_str_case ( * strPool + pLookup - > getValue ( index ) ) ) {
2015-10-13 19:38:13 -07:00
return pLookup - > getValue ( index ) ;
2017-01-08 16:30:30 -08:00
}
2015-10-24 13:41:11 -07:00
int strOffs = strPoolSize ;
if ( ( strOffs + str . get_len ( ) + 1 ) > strPoolCap ) {
2016-05-20 22:48:13 -07:00
strPoolCap = strOffs + ( uint32_t ) str . get_len ( ) + 4096 ;
2015-10-13 19:38:13 -07:00
char * strPoolGrow = ( char * ) malloc ( strPoolCap ) ;
2015-10-24 13:41:11 -07:00
if ( strPoolGrow ) {
if ( * strPool ) {
memcpy ( strPoolGrow , * strPool , strPoolSize ) ;
free ( * strPool ) ;
}
* strPool = strPoolGrow ;
2017-01-08 16:30:30 -08:00
} else { return - 1 ; }
2015-10-13 19:38:13 -07:00
}
2015-10-24 13:41:11 -07:00
2015-10-17 12:13:23 -07:00
if ( * strPool ) {
char * dest = * strPool + strPoolSize ;
memcpy ( dest , str . get ( ) , str . get_len ( ) ) ;
dest [ str . get_len ( ) ] = 0 ;
2016-05-20 22:48:13 -07:00
strPoolSize + = ( uint32_t ) str . get_len ( ) + 1 ;
2015-10-17 12:13:23 -07:00
pLookup - > insert ( index , hash ) ;
2015-10-24 13:41:11 -07:00
pLookup - > getValues ( ) [ index ] = strOffs ;
2015-10-17 12:13:23 -07:00
}
2015-10-24 13:41:11 -07:00
return strOffs ;
2015-10-13 19:38:13 -07:00
}
2017-01-08 16:30:30 -08:00
StatusCode Asm : : WriteObjectFile ( strref filename ) {
2015-11-15 22:15:34 -08:00
if ( allSections . size ( ) = = 0 )
return ERROR_NOT_A_SECTION ;
2015-10-13 19:38:13 -07:00
if ( FILE * f = fopen ( strown < 512 > ( filename ) . c_str ( ) , " wb " ) ) {
struct ObjFileHeader hdr = { 0 } ;
2015-11-05 21:23:38 -08:00
hdr . id = 0x7836 ;
2016-03-12 11:39:53 -08:00
hdr . sections = ( int16_t ) allSections . size ( ) ;
2015-10-13 19:38:13 -07:00
hdr . relocs = 0 ;
hdr . bindata = 0 ;
2015-11-15 22:15:34 -08:00
2015-10-13 19:38:13 -07:00
for ( std : : vector < Section > : : iterator s = allSections . begin ( ) ; s ! = allSections . end ( ) ; + + s ) {
2015-11-15 21:14:46 -08:00
if ( s - > type ! = ST_REMOVED ) {
2017-01-08 16:30:30 -08:00
if ( s - > pRelocs ) { hdr . relocs + = int16_t ( s - > pRelocs - > size ( ) ) ; }
2015-11-15 21:14:46 -08:00
hdr . bindata + = s - > size ( ) ;
}
2015-10-13 19:38:13 -07:00
}
2016-03-12 11:39:53 -08:00
hdr . late_evals = ( int16_t ) lateEval . size ( ) ;
hdr . map_symbols = ( int16_t ) map . size ( ) ;
2015-10-13 19:38:13 -07:00
hdr . stringdata = 0 ;
2015-10-30 22:30:16 -07:00
// labels don't include XREF labels
hdr . labels = 0 ;
2016-03-12 11:39:53 -08:00
for ( uint32_t l = 0 ; l < labels . count ( ) ; l + + ) {
2017-01-08 16:30:30 -08:00
if ( ! labels . getValue ( l ) . reference ) { hdr . labels + + ; }
2015-10-30 22:30:16 -07:00
}
2016-03-12 11:39:53 -08:00
int16_t * aRemapSects = hdr . sections ? ( int16_t * ) malloc ( sizeof ( int16_t ) * hdr . sections ) : nullptr ;
2015-11-15 22:15:34 -08:00
if ( ! aRemapSects ) {
fclose ( f ) ;
return ERROR_OUT_OF_MEMORY ;
}
2015-10-30 22:30:16 -07:00
2015-10-16 20:27:56 -07:00
// include space for external protected labels
2017-01-08 16:30:30 -08:00
for ( std : : vector < ExtLabels > : : iterator el = externals . begin ( ) ; el ! = externals . end ( ) ; + + el ) {
2016-05-25 22:44:17 -07:00
hdr . labels + = ( int16_t ) el - > labels . count ( ) ;
2017-01-08 16:30:30 -08:00
}
2015-10-13 19:38:13 -07:00
char * stringPool = nullptr ;
2016-03-12 11:39:53 -08:00
uint32_t stringPoolCap = 0 ;
pairArray < uint32_t , int > stringArray ;
2015-10-13 19:38:13 -07:00
stringArray . reserve ( hdr . labels * 2 + hdr . sections + hdr . late_evals * 2 ) ;
struct ObjFileSection * aSects = hdr . sections ? ( struct ObjFileSection * ) calloc ( hdr . sections , sizeof ( struct ObjFileSection ) ) : nullptr ;
struct ObjFileReloc * aRelocs = hdr . relocs ? ( struct ObjFileReloc * ) calloc ( hdr . relocs , sizeof ( struct ObjFileReloc ) ) : nullptr ;
struct ObjFileLabel * aLabels = hdr . labels ? ( struct ObjFileLabel * ) calloc ( hdr . labels , sizeof ( struct ObjFileLabel ) ) : nullptr ;
struct ObjFileLateEval * aLateEvals = hdr . late_evals ? ( struct ObjFileLateEval * ) calloc ( hdr . late_evals , sizeof ( struct ObjFileLateEval ) ) : nullptr ;
struct ObjFileMapSymbol * aMapSyms = hdr . map_symbols ? ( struct ObjFileMapSymbol * ) calloc ( hdr . map_symbols , sizeof ( struct ObjFileMapSymbol ) ) : nullptr ;
int sect = 0 , reloc = 0 , labs = 0 , late = 0 , map_sym = 0 ;
2016-03-12 11:39:53 -08:00
memset ( aRemapSects , 0xff , sizeof ( int16_t ) * hdr . sections ) ;
2015-11-15 21:14:46 -08:00
// discard the removed sections by making a table of skipped indices
for ( std : : vector < Section > : : iterator si = allSections . begin ( ) ; si ! = allSections . end ( ) ; + + si ) {
if ( si - > type ! = ST_REMOVED )
2016-05-25 22:44:17 -07:00
aRemapSects [ & * si - & allSections [ 0 ] ] = ( int16_t ) sect + + ;
2015-11-15 21:14:46 -08:00
}
2015-11-15 22:15:34 -08:00
2015-11-15 21:14:46 -08:00
sect = 0 ;
2015-10-13 19:38:13 -07:00
// write out sections and relocs
2015-10-17 12:13:23 -07:00
if ( hdr . sections ) {
for ( std : : vector < Section > : : iterator si = allSections . begin ( ) ; si ! = allSections . end ( ) ; + + si ) {
2015-11-15 21:14:46 -08:00
if ( si - > type = = ST_REMOVED )
continue ;
2015-10-17 12:13:23 -07:00
struct ObjFileSection & s = aSects [ sect + + ] ;
s . name . offs = _AddStrPool ( si - > name , & stringArray , & stringPool , hdr . stringdata , stringPoolCap ) ;
2015-10-18 19:48:03 -07:00
s . exp_app . offs = _AddStrPool ( si - > export_append , & stringArray , & stringPool , hdr . stringdata , stringPoolCap ) ;
2015-11-15 21:14:46 -08:00
s . output_size = si - > size ( ) ;
2015-10-18 19:48:03 -07:00
s . align_address = si - > align_address ;
2015-11-15 21:14:46 -08:00
s . next_group = si - > next_group > = 0 ? aRemapSects [ si - > next_group ] : - 1 ;
s . first_group = si - > first_group > = 0 ? aRemapSects [ si - > first_group ] : - 1 ;
2016-03-12 11:39:53 -08:00
s . relocs = si - > pRelocs ? ( int16_t ) ( si - > pRelocs - > size ( ) ) : 0 ;
2015-10-17 12:13:23 -07:00
s . start_address = si - > start_address ;
2015-11-08 18:06:45 -08:00
s . end_address = si - > address ;
2015-11-06 22:48:50 -08:00
s . type = si - > type ;
2015-10-17 12:13:23 -07:00
s . flags =
2015-10-18 19:48:03 -07:00
( si - > IsDummySection ( ) ? ( 1 < < ObjFileSection : : OFS_DUMMY ) : 0 ) |
( si - > IsMergedSection ( ) ? ( 1 < < ObjFileSection : : OFS_MERGED ) : 0 ) |
( si - > address_assigned ? ( 1 < < ObjFileSection : : OFS_FIXED ) : 0 ) ;
2015-11-01 15:08:38 -08:00
if ( si - > pRelocs & & si - > pRelocs - > size ( ) & & aRelocs ) {
2015-10-17 12:13:23 -07:00
for ( relocList : : iterator ri = si - > pRelocs - > begin ( ) ; ri ! = si - > pRelocs - > end ( ) ; + + ri ) {
struct ObjFileReloc & r = aRelocs [ reloc + + ] ;
r . base_value = ri - > base_value ;
r . section_offset = ri - > section_offset ;
2015-11-15 21:14:46 -08:00
r . target_section = ri - > target_section > = 0 ? aRemapSects [ ri - > target_section ] : - 1 ;
2015-11-05 21:23:38 -08:00
r . bytes = ri - > bytes ;
r . shift = ri - > shift ;
2015-10-17 12:13:23 -07:00
}
2015-10-13 19:38:13 -07:00
}
}
}
2016-05-25 22:44:17 -07:00
hdr . sections = ( int16_t ) sect ;
2015-10-13 19:38:13 -07:00
// write out labels
2015-10-17 12:13:23 -07:00
if ( hdr . labels ) {
2016-03-12 11:39:53 -08:00
for ( uint32_t li = 0 ; li < labels . count ( ) ; li + + ) {
2015-10-17 12:13:23 -07:00
Label & lo = labels . getValue ( li ) ;
2015-10-30 22:30:16 -07:00
if ( ! lo . reference ) {
struct ObjFileLabel & l = aLabels [ labs + + ] ;
l . name . offs = _AddStrPool ( lo . label_name , & stringArray , & stringPool , hdr . stringdata , stringPoolCap ) ;
l . value = lo . value ;
2015-11-15 21:14:46 -08:00
l . section = lo . section > = 0 ? aRemapSects [ lo . section ] : - 1 ;
2016-05-25 22:44:17 -07:00
l . mapIndex = ( int16_t ) lo . mapIndex ;
2015-10-30 22:30:16 -07:00
l . flags =
( lo . constant ? ObjFileLabel : : OFL_CNST : 0 ) |
( lo . pc_relative ? ObjFileLabel : : OFL_ADDR : 0 ) |
( lo . evaluated ? ObjFileLabel : : OFL_EVAL : 0 ) |
( lo . external ? ObjFileLabel : : OFL_XDEF : 0 ) ;
}
2015-10-17 12:13:23 -07:00
}
}
2015-10-23 22:44:56 -07:00
2015-10-17 12:13:23 -07:00
// protected labels included from other object files
if ( hdr . labels ) {
int file_index = 1 ;
for ( std : : vector < ExtLabels > : : iterator el = externals . begin ( ) ; el ! = externals . end ( ) ; + + el ) {
2016-03-12 11:39:53 -08:00
for ( uint32_t li = 0 ; li < el - > labels . count ( ) ; + + li ) {
2015-10-17 12:13:23 -07:00
Label & lo = el - > labels . getValue ( li ) ;
struct ObjFileLabel & l = aLabels [ labs + + ] ;
l . name . offs = _AddStrPool ( lo . label_name , & stringArray , & stringPool , hdr . stringdata , stringPoolCap ) ;
l . value = lo . value ;
2015-11-15 21:14:46 -08:00
l . section = lo . section > = 0 ? aRemapSects [ lo . section ] : - 1 ;
2016-05-25 22:44:17 -07:00
l . mapIndex = ( int16_t ) lo . mapIndex ;
2015-10-17 12:13:23 -07:00
l . flags =
2015-10-18 12:42:10 -07:00
( lo . constant ? ObjFileLabel : : OFL_CNST : 0 ) |
( lo . pc_relative ? ObjFileLabel : : OFL_ADDR : 0 ) |
( lo . evaluated ? ObjFileLabel : : OFL_EVAL : 0 ) |
file_index ;
2015-10-17 12:13:23 -07:00
}
file_index + + ;
2015-10-16 20:27:56 -07:00
}
2015-10-13 19:38:13 -07:00
}
// write out late evals
2015-10-17 12:13:23 -07:00
if ( aLateEvals ) {
for ( std : : vector < LateEval > : : iterator lei = lateEval . begin ( ) ; lei ! = lateEval . end ( ) ; + + lei ) {
struct ObjFileLateEval & le = aLateEvals [ late + + ] ;
le . label . offs = _AddStrPool ( lei - > label , & stringArray , & stringPool , hdr . stringdata , stringPoolCap ) ;
le . expression . offs = _AddStrPool ( lei - > expression , & stringArray , & stringPool , hdr . stringdata , stringPoolCap ) ;
2015-11-15 21:14:46 -08:00
le . section = lei - > section > = 0 ? aRemapSects [ lei - > section ] : - 1 ;
2015-11-02 23:14:01 -08:00
le . rept = lei - > rept ;
2016-03-12 11:39:53 -08:00
le . target = ( int16_t ) lei - > target ;
2015-10-17 12:13:23 -07:00
le . address = lei - > address ;
2016-05-25 22:44:17 -07:00
le . scope = ( int16_t ) lei - > scope ;
le . type = ( int16_t ) lei - > type ;
2015-10-17 12:13:23 -07:00
}
2015-10-13 19:38:13 -07:00
}
// write out map symbols
2015-10-17 12:13:23 -07:00
if ( aMapSyms ) {
for ( MapSymbolArray : : iterator mi = map . begin ( ) ; mi ! = map . end ( ) ; + + mi ) {
struct ObjFileMapSymbol & ms = aMapSyms [ map_sym + + ] ;
ms . name . offs = _AddStrPool ( mi - > name , & stringArray , & stringPool , hdr . stringdata , stringPoolCap ) ;
ms . value = mi - > value ;
ms . local = mi - > local ;
2015-11-15 21:14:46 -08:00
ms . section = mi - > section > = 0 ? aRemapSects [ mi - > section ] : - 1 ;
2015-10-17 12:13:23 -07:00
}
2015-10-13 19:38:13 -07:00
}
// write out the file
fwrite ( & hdr , sizeof ( hdr ) , 1 , f ) ;
fwrite ( aSects , sizeof ( aSects [ 0 ] ) , sect , f ) ;
fwrite ( aRelocs , sizeof ( aRelocs [ 0 ] ) , reloc , f ) ;
fwrite ( aLabels , sizeof ( aLabels [ 0 ] ) , labs , f ) ;
fwrite ( aLateEvals , sizeof ( aLateEvals [ 0 ] ) , late , f ) ;
fwrite ( aMapSyms , sizeof ( aMapSyms [ 0 ] ) , map_sym , f ) ;
fwrite ( stringPool , hdr . stringdata , 1 , f ) ;
for ( std : : vector < Section > : : iterator si = allSections . begin ( ) ; si ! = allSections . end ( ) ; + + si ) {
2017-01-08 16:30:30 -08:00
if ( ! si - > IsDummySection ( ) & & ! si - > IsMergedSection ( ) & & si - > size ( ) ! = 0 & & si - > type ! = ST_REMOVED ) {
2015-10-13 19:38:13 -07:00
fwrite ( si - > output , si - > size ( ) , 1 , f ) ;
2017-01-08 16:30:30 -08:00
}
2015-10-13 19:38:13 -07:00
}
// done with I/O
fclose ( f ) ;
2017-01-08 16:30:30 -08:00
if ( aRemapSects ) { free ( aRemapSects ) ; }
if ( stringPool ) { free ( stringPool ) ; }
if ( aMapSyms ) { free ( aMapSyms ) ; }
if ( aLateEvals ) { free ( aLateEvals ) ; }
if ( aLabels ) { free ( aLabels ) ; }
if ( aRelocs ) { free ( aRelocs ) ; }
if ( aSects ) { free ( aSects ) ; }
2015-10-13 19:38:13 -07:00
stringArray . clear ( ) ;
}
return STATUS_OK ;
}
2015-11-09 22:15:14 -08:00
StatusCode Asm : : ReadObjectFile ( strref filename , int link_to_section )
2015-10-13 19:38:13 -07:00
{
size_t size ;
2015-10-26 20:50:26 -07:00
strown < 512 > file ;
file . copy ( filename ) ; // Merlin mostly uses extension-less files, append .x65 as a default
2016-03-11 14:12:32 -08:00
if ( ( Merlin ( ) & & ! file . has_suffix ( " .x65 " ) ) | | filename . find ( ' . ' ) < 0 )
2015-10-26 20:50:26 -07:00
file . append ( " .x65 " ) ;
2015-10-16 20:27:56 -07:00
int file_index = ( int ) externals . size ( ) ;
2015-10-26 20:50:26 -07:00
if ( char * data = LoadBinary ( file . get_strref ( ) , size ) ) {
2015-10-13 19:38:13 -07:00
struct ObjFileHeader & hdr = * ( struct ObjFileHeader * ) data ;
size_t sum = sizeof ( hdr ) + hdr . sections * sizeof ( struct ObjFileSection ) +
hdr . relocs * sizeof ( struct ObjFileReloc ) + hdr . labels * sizeof ( struct ObjFileLabel ) +
hdr . late_evals * sizeof ( struct ObjFileLateEval ) +
hdr . map_symbols * sizeof ( struct ObjFileMapSymbol ) + hdr . stringdata + hdr . bindata ;
2015-11-05 21:23:38 -08:00
if ( hdr . id = = 0x7836 & & sum = = size ) {
2015-10-13 19:38:13 -07:00
struct ObjFileSection * aSect = ( struct ObjFileSection * ) ( & hdr + 1 ) ;
struct ObjFileReloc * aReloc = ( struct ObjFileReloc * ) ( aSect + hdr . sections ) ;
struct ObjFileLabel * aLabels = ( struct ObjFileLabel * ) ( aReloc + hdr . relocs ) ;
struct ObjFileLateEval * aLateEval = ( struct ObjFileLateEval * ) ( aLabels + hdr . labels ) ;
struct ObjFileMapSymbol * aMapSyms = ( struct ObjFileMapSymbol * ) ( aLateEval + hdr . late_evals ) ;
const char * str_orig = ( const char * ) ( aMapSyms + hdr . map_symbols ) ;
const char * bin_data = str_orig + hdr . stringdata ;
char * str_pool = ( char * ) malloc ( hdr . stringdata ) ;
memcpy ( str_pool , str_orig , hdr . stringdata ) ;
loadedData . push_back ( str_pool ) ;
int prevSection = SectionId ( ) ;
2016-03-12 11:39:53 -08:00
int16_t * aSctRmp = ( int16_t * ) malloc ( hdr . sections * sizeof ( int16_t ) ) ;
2015-11-09 22:15:14 -08:00
int last_linked_section = link_to_section ;
2017-01-08 16:30:30 -08:00
while ( last_linked_section > = 0 & & allSections [ last_linked_section ] . next_group > = 0 ) {
2015-11-09 22:15:14 -08:00
last_linked_section = allSections [ last_linked_section ] . next_group ;
2017-01-08 16:30:30 -08:00
}
2015-10-13 19:38:13 -07:00
// sections
for ( int si = 0 ; si < hdr . sections ; si + + ) {
2016-03-12 11:39:53 -08:00
int16_t f = aSect [ si ] . flags ;
2015-10-13 19:38:13 -07:00
if ( f & ( 1 < < ObjFileSection : : OFS_MERGED ) )
continue ;
if ( f & ( 1 < < ObjFileSection : : OFS_DUMMY ) ) {
2015-11-08 18:06:45 -08:00
if ( f & ( 1 < < ObjFileSection : : OFS_FIXED ) ) {
2015-10-13 19:38:13 -07:00
DummySection ( aSect [ si ] . start_address ) ;
2015-11-08 18:06:45 -08:00
CurrSection ( ) . AddBin ( nullptr , aSect [ si ] . end_address - aSect [ si ] . start_address ) ;
} else {
2015-10-13 19:38:13 -07:00
DummySection ( ) ;
2015-11-08 18:06:45 -08:00
CurrSection ( ) . AddBin ( nullptr , aSect [ si ] . end_address - aSect [ si ] . start_address ) ;
}
2015-10-13 19:38:13 -07:00
} else {
2017-01-08 16:30:30 -08:00
if ( f & ( 1 < < ObjFileSection : : OFS_FIXED ) ) {
SetSection ( aSect [ si ] . name . offs > = 0 ? strref ( str_pool + aSect [ si ] . name . offs ) : strref ( ) , aSect [ si ] . start_address ) ;
} else {
SetSection ( aSect [ si ] . name . offs > = 0 ? strref ( str_pool + aSect [ si ] . name . offs ) : strref ( ) ) ;
}
2015-11-08 18:06:45 -08:00
Section & s = CurrSection ( ) ;
s . include_from = filename ;
s . export_append = aSect [ si ] . exp_app . offs > = 0 ? strref ( str_pool + aSect [ si ] . name . offs ) : strref ( ) ;
s . align_address = aSect [ si ] . align_address ;
s . address = aSect [ si ] . end_address ;
s . type = aSect [ si ] . type ;
2015-10-13 19:38:13 -07:00
if ( aSect [ si ] . output_size ) {
2016-03-12 11:39:53 -08:00
s . output = ( uint8_t * ) malloc ( aSect [ si ] . output_size ) ;
2015-11-08 18:06:45 -08:00
memcpy ( s . output , bin_data , aSect [ si ] . output_size ) ;
s . curr = s . output + aSect [ si ] . output_size ;
s . output_capacity = aSect [ si ] . output_size ;
2015-10-13 19:38:13 -07:00
bin_data + = aSect [ si ] . output_size ;
}
2015-11-09 22:15:14 -08:00
if ( last_linked_section > = 0 ) {
allSections [ last_linked_section ] . next_group = SectionId ( ) ;
s . first_group = allSections [ last_linked_section ] . first_group > = 0 ? allSections [ last_linked_section ] . first_group : last_linked_section ;
last_linked_section = SectionId ( ) ;
}
2015-10-13 19:38:13 -07:00
}
2016-03-12 11:39:53 -08:00
aSctRmp [ si ] = ( int16_t ) allSections . size ( ) - 1 ;
2015-10-13 19:38:13 -07:00
}
2015-11-08 18:06:45 -08:00
// fix up groups and relocs
int curr_reloc = 0 ;
2015-10-13 19:38:13 -07:00
for ( int si = 0 ; si < hdr . sections ; si + + ) {
2015-11-08 18:06:45 -08:00
Section & s = allSections [ aSctRmp [ si ] ] ;
if ( aSect [ si ] . first_group > = 0 )
s . first_group = aSctRmp [ aSect [ si ] . first_group ] ;
if ( aSect [ si ] . next_group > = 0 )
s . first_group = aSctRmp [ aSect [ si ] . next_group ] ;
for ( int ri = 0 ; ri < aSect [ si ] . relocs ; ri + + ) {
int r = ri + curr_reloc ;
2015-10-27 20:57:14 -07:00
struct ObjFileReloc & rs = aReloc [ r ] ;
2015-11-05 21:23:38 -08:00
allSections [ aSctRmp [ si ] ] . AddReloc ( rs . base_value , rs . section_offset , aSctRmp [ rs . target_section ] , rs . bytes , rs . shift ) ;
2015-10-13 19:38:13 -07:00
}
2015-11-08 18:06:45 -08:00
curr_reloc + = aSect [ si ] . relocs ;
2015-10-13 19:38:13 -07:00
}
2015-10-16 20:27:56 -07:00
for ( int mi = 0 ; mi < hdr . map_symbols ; mi + + ) {
struct ObjFileMapSymbol & m = aMapSyms [ mi ] ;
2017-01-08 16:30:30 -08:00
if ( map . size ( ) = = map . capacity ( ) ) {
map . reserve ( map . size ( ) + 256 ) ;
}
2015-10-16 20:27:56 -07:00
MapSymbol sym ;
sym . name = m . name . offs > = 0 ? strref ( str_pool + m . name . offs ) : strref ( ) ;
2015-10-19 22:44:02 -07:00
sym . section = m . section > = 0 ? aSctRmp [ m . section ] : m . section ;
2015-10-16 20:27:56 -07:00
sym . value = m . value ;
sym . local = m . local ;
map . push_back ( sym ) ;
}
2015-10-13 19:38:13 -07:00
for ( int li = 0 ; li < hdr . labels ; li + + ) {
struct ObjFileLabel & l = aLabels [ li ] ;
strref name = l . name . offs > = 0 ? strref ( str_pool + l . name . offs ) : strref ( ) ;
Label * lbl = GetLabel ( name ) ;
2016-05-25 22:44:17 -07:00
int16_t f = ( int16_t ) l . flags ;
2015-11-01 15:08:38 -08:00
int external = f & ObjFileLabel : : OFL_XDEF ;
if ( external = = ObjFileLabel : : OFL_XDEF ) {
2017-01-08 16:30:30 -08:00
if ( ! lbl ) { lbl = AddLabel ( name . fnv1a ( ) ) ; } // insert shared label
else if ( ! lbl - > reference ) { continue ; }
2015-11-01 15:08:38 -08:00
} else { // insert protected label
while ( ( file_index + external ) > = ( int ) externals . size ( ) ) {
2017-01-08 16:30:30 -08:00
if ( externals . size ( ) = = externals . capacity ( ) ) {
externals . reserve ( externals . size ( ) + 32 ) ;
}
2015-11-01 15:08:38 -08:00
externals . push_back ( ExtLabels ( ) ) ;
2015-10-16 20:27:56 -07:00
}
2016-03-12 11:39:53 -08:00
uint32_t hash = name . fnv1a ( ) ;
uint32_t index = FindLabelIndex ( hash , externals [ file_index ] . labels . getKeys ( ) , externals [ file_index ] . labels . count ( ) ) ;
2015-11-01 15:08:38 -08:00
externals [ file_index ] . labels . insert ( index , hash ) ;
lbl = externals [ file_index ] . labels . getValues ( ) + index ;
2015-10-13 19:38:13 -07:00
}
2015-11-01 15:08:38 -08:00
lbl - > label_name = name ;
lbl - > pool_name . clear ( ) ;
lbl - > value = l . value ;
2015-11-01 23:02:03 -08:00
lbl - > section = l . section > = 0 ? aSctRmp [ l . section ] : l . section ;
lbl - > mapIndex = l . mapIndex > = 0 ? ( l . mapIndex + ( int ) map . size ( ) ) : - 1 ;
2015-11-01 15:08:38 -08:00
lbl - > evaluated = ! ! ( f & ObjFileLabel : : OFL_EVAL ) ;
lbl - > pc_relative = ! ! ( f & ObjFileLabel : : OFL_ADDR ) ;
2015-11-01 23:02:03 -08:00
lbl - > constant = ! ! ( f & ObjFileLabel : : OFL_CNST ) ;
2015-11-01 15:08:38 -08:00
lbl - > external = external = = ObjFileLabel : : OFL_XDEF ;
lbl - > reference = false ;
2015-10-13 19:38:13 -07:00
}
2017-01-08 16:30:30 -08:00
// no protected labels => don't track as separate file
if ( file_index = = ( int ) externals . size ( ) ) { file_index = - 1 ; }
2015-10-16 20:27:56 -07:00
2015-10-13 19:38:13 -07:00
for ( int li = 0 ; li < hdr . late_evals ; + + li ) {
struct ObjFileLateEval & le = aLateEval [ li ] ;
strref name = le . label . offs > = 0 ? strref ( str_pool + le . label . offs ) : strref ( ) ;
Label * pLabel = GetLabel ( name ) ;
if ( pLabel ) {
if ( pLabel - > evaluated ) {
AddLateEval ( name , le . address , le . scope , strref ( str_pool + le . expression . offs ) , ( LateEval : : Type ) le . type ) ;
2015-10-16 20:27:56 -07:00
LateEval & last = lateEval [ lateEval . size ( ) - 1 ] ;
last . section = le . section > = 0 ? aSctRmp [ le . section ] : le . section ;
2015-11-02 23:14:01 -08:00
last . rept = le . rept ;
2015-10-26 20:50:26 -07:00
last . source_file = strref ( ) ;
2015-10-16 20:27:56 -07:00
last . file_ref = file_index ;
2015-10-13 19:38:13 -07:00
}
} else {
2015-10-26 20:50:26 -07:00
AddLateEval ( le . target , le . address , le . scope , strref ( str_pool + le . expression . offs ) , strref ( ) , ( LateEval : : Type ) le . type ) ;
2015-10-16 20:27:56 -07:00
LateEval & last = lateEval [ lateEval . size ( ) - 1 ] ;
2015-11-02 23:14:01 -08:00
last . section = le . section > = 0 ? aSctRmp [ le . section ] : le . section ;
last . rept = le . rept ;
2015-10-16 20:27:56 -07:00
last . file_ref = file_index ;
2015-10-13 19:38:13 -07:00
}
}
free ( aSctRmp ) ;
// restore previous section
current_section = & allSections [ prevSection ] ;
2017-01-08 16:30:30 -08:00
} else { return ERROR_NOT_AN_X65_OBJECT_FILE ; }
2015-10-13 19:38:13 -07:00
}
return STATUS_OK ;
}
2015-11-15 21:14:46 -08:00
// number of section types that can be merged
enum OMFRecCode {
OMFR_END = 0 ,
OMFR_RELOC = 0xe2 , // bytes.b, bitshift.b, offset.l, value.l
OMFR_INTERSEG = 0xe3 , // bytes.b, bitshift.b, offset.l, filenum.w, segnum.w, offsref.l
OMFR_LCONST = 0xf2 , // bytes.b, b,b,b, data.b[bytes]
OMFR_cRELOC = 0xf5 , // bytes.b, bitshift.b, offset.w, value.w
OMFR_cINTERSEG = 0xf6 , // bytes.b, bitshift.b, offset.w, segnum.b, offsref.w
OMFR_SUPER = 0xf7 ,
} ;
struct OMFSegHdr {
2016-03-12 11:39:53 -08:00
uint8_t SegTotal [ 4 ] ; // + Segment Segment Header size Body size
uint8_t ResSpc [ 4 ] ; // Number of 0x00 to add to the end of Body
uint8_t Length [ 4 ] ; // Memory Size Segment
uint8_t pad1 [ 1 ] ;
uint8_t LabLen [ 1 ] ; // Length Names: 10
uint8_t NumLen [ 1 ] ; // Size = 4 numbers uint8s
uint8_t Version [ 1 ] ; // OMF Version: 2
uint8_t BankSize [ 4 ] ; // Size of a Bank: 64 KB code if, between 0 and 64 KB for Data
uint8_t Kind [ 2 ] ; // Type Segment
uint8_t pad2 [ 2 ] ;
uint8_t Org [ 4 ] ;
uint8_t Align [ 4 ] ; // Alignment: 0, 64 or 256 KB
uint8_t NumSEx [ 1 ] ; // Little Endian: 0 for IIgs
uint8_t pad3 [ 1 ] ;
uint8_t SegNum [ 2 ] ; // Segment Number: 1-> N
uint8_t EntryPointOffset [ 4 ] ; // Entry point in the Segment
uint8_t DispNameOffset [ 2 ] ; // Where the offset is located LoadName
uint8_t DispDataOffset [ 2 ] ; // Offset begins the Body Segment
uint8_t tempOrg [ 4 ] ; //
2015-11-15 21:14:46 -08:00
} ;
// write a number of bytes of a value
2016-03-12 11:39:53 -08:00
static void _writeNBytes ( uint8_t * dest , int bytes , int value ) {
2015-11-15 21:14:46 -08:00
while ( bytes - - ) {
2016-03-12 11:39:53 -08:00
* dest + + = ( uint8_t ) value ;
2015-11-15 21:14:46 -08:00
value > > = 8 ;
}
}
// sort relocs before writing GS OS reloc instructions
static int sortRelocByOffs ( const void * A , const void * B ) {
return ( ( const Reloc * ) A ) - > section_offset - ( ( const Reloc * ) B ) - > section_offset ;
}
// Export an Apple II GS relocatable executable
2017-01-08 16:30:30 -08:00
StatusCode Asm : : WriteA2GS_OMF ( strref filename , bool full_collapse ) {
2015-11-15 21:14:46 -08:00
// determine the section with startup code - either first loaded object file or current file
int first_section = 0 ;
for ( int s = 1 ; s < ( int ) allSections . size ( ) ; s + + ) {
if ( allSections [ s ] . type = = ST_CODE & & ( allSections [ first_section ] . type ! = ST_CODE | |
( ! allSections [ s ] . include_from & & allSections [ first_section ] . include_from ) ) )
first_section = s ;
}
// collapse all section together that share the same name
StatusCode status = MergeSectionsByName ( first_section ) ;
2017-01-08 16:30:30 -08:00
if ( status ! = STATUS_OK ) { return status ; }
2015-11-17 23:47:35 -08:00
// Zero page section for x65 implies addresses, OMF direct-page/stack seg implies size of direct page + stack
// so resolve the zero page sections first
status = LinkZP ( ) ;
2017-01-08 16:30:30 -08:00
if ( status ! = STATUS_OK ) { return status ; }
2015-11-15 21:14:46 -08:00
// full collapse means that all sections gets merged into one
// code+data section and one bss section which will be appended
2015-11-17 23:47:35 -08:00
if ( full_collapse ) {
2015-11-15 21:14:46 -08:00
status = MergeAllSections ( first_section ) ;
2017-01-08 16:30:30 -08:00
if ( status ! = STATUS_OK ) { return status ; }
2015-11-17 23:47:35 -08:00
}
2015-11-15 21:14:46 -08:00
2015-11-17 23:47:35 -08:00
// determine if there is a direct page stack
int DP_Stack_Size = 0 ; // 0 => default size (don't include)
for ( std : : vector < Section > : : iterator s = allSections . begin ( ) ; s ! = allSections . end ( ) ; + + s ) {
2017-01-08 16:30:30 -08:00
if ( s - > type = = ST_ZEROPAGE ) { s - > type = ST_REMOVED ; }
2015-11-17 23:47:35 -08:00
if ( s - > type = = ST_BSS & & s - > name . same_str ( " directpage_stack " ) ) {
DP_Stack_Size + = s - > addr_size ( ) ;
s - > type = ST_REMOVED ;
}
}
2015-11-15 21:14:46 -08:00
std : : vector < int > SegNum ; // order of valid segments
std : : vector < int > SegLookup ; // inverse of SegNum
SegNum . reserve ( allSections . size ( ) ) ;
SegLookup . reserve ( allSections . size ( ) ) ;
2015-11-15 22:15:34 -08:00
int reloc_max = 1 ;
2015-11-15 21:14:46 -08:00
// OMF super instructions work by incremental addresses, sort relocs to simplify output
for ( std : : vector < Section > : : iterator s = allSections . begin ( ) ; s ! = allSections . end ( ) ; + + s ) {
2017-01-08 16:30:30 -08:00
if ( first_section = = SectionId ( * s ) ) {
2015-11-15 21:14:46 -08:00
SegNum . insert ( SegNum . begin ( ) , SectionId ( * s ) ) ;
2017-01-08 16:30:30 -08:00
} else if ( s - > type ! = ST_REMOVED ) {
2015-11-15 21:14:46 -08:00
SegNum . push_back ( SectionId ( * s ) ) ;
2017-01-08 16:30:30 -08:00
}
2015-11-15 21:14:46 -08:00
SegLookup . push_back ( - 1 ) ;
if ( ( s - > type = = ST_CODE | | s - > type = = ST_DATA ) & & s - > pRelocs & & s - > pRelocs - > size ( ) > 1 ) {
qsort ( & ( * s - > pRelocs ) [ 0 ] , s - > pRelocs - > size ( ) , sizeof ( Reloc ) , sortRelocByOffs ) ;
2017-01-08 16:30:30 -08:00
if ( ( int ) s - > pRelocs - > size ( ) > reloc_max ) {
2015-11-15 21:14:46 -08:00
reloc_max = ( int ) s - > pRelocs - > size ( ) ;
2017-01-08 16:30:30 -08:00
}
2015-11-15 21:14:46 -08:00
}
}
2016-03-11 17:08:44 -08:00
// reloc_max needs to greater than zero
2017-01-08 16:30:30 -08:00
if ( reloc_max < 1 ) { return ERROR_ABORTED ; }
2015-11-15 21:14:46 -08:00
2017-01-08 16:30:30 -08:00
for ( std : : vector < int > : : iterator i = SegNum . begin ( ) ; i ! = SegNum . end ( ) ; + + i ) {
SegLookup [ * i ] = ( int ) ( & * i - & SegNum [ 0 ] ) ;
}
2016-03-12 11:39:53 -08:00
uint8_t * instructions = ( uint8_t * ) malloc ( reloc_max * 16 ) ;
2017-01-08 16:30:30 -08:00
if ( ! instructions ) { return ERROR_OUT_OF_MEMORY ; }
2015-11-15 22:15:34 -08:00
2015-11-15 21:14:46 -08:00
// open a file for writing
FILE * f = fopen ( strown < 512 > ( filename ) . c_str ( ) , " wb " ) ;
2015-11-15 22:15:34 -08:00
if ( ! f ) {
free ( instructions ) ;
2015-11-15 21:14:46 -08:00
return ERROR_CANT_WRITE_TO_FILE ;
2015-11-15 22:15:34 -08:00
}
2015-11-15 21:14:46 -08:00
// consume all the relocs
struct OMFSegHdr hdr = { 0 } ; // initialize segment header
hdr . NumLen [ 0 ] = 4 ; // numbers are 4 bytes under GS OS
hdr . Version [ 0 ] = 2 ; // version is 2 for GS OS
hdr . BankSize [ 2 ] = 1 ; // 64k banks
_writeNBytes ( hdr . DispNameOffset , 2 , sizeof ( hdr ) ) ; // start of file name (10 chars)
2015-11-17 23:47:35 -08:00
strref fileBase = export_base_name ;
char segfile [ 10 ] ;
memset ( segfile , ' ' , 10 ) ;
memcpy ( segfile , fileBase . get ( ) , fileBase . get_len ( ) > 10 ? 10 : fileBase . get_len ( ) ) ;
2015-11-15 21:14:46 -08:00
for ( std : : vector < int > : : iterator i = SegNum . begin ( ) ; i ! = SegNum . end ( ) ; + + i ) {
Section & s = allSections [ * i ] ;
strref segName = s . name ? s . name : ( s . type = = ST_CODE ? strref ( " CODE " ) : strref ( " DATA " ) ) ;
// support zero bytes at end of block
int num_zeroes_at_end = s . addr_size ( ) - s . size ( ) ;
int num_bytes_file = s . size ( ) ;
while ( num_bytes_file & & s . output [ num_bytes_file - 1 ] = = 0 ) {
num_zeroes_at_end + + ;
num_bytes_file - - ;
}
_writeNBytes ( hdr . SegNum , 2 , SegLookup [ * i ] + 1 ) ;
_writeNBytes ( hdr . Kind , 2 , s . type = = ST_CODE ? 0x1000 : ( s . type = = ST_ZEROPAGE ? 0x12 : 0x1001 ) ) ;
2016-05-20 22:48:13 -07:00
_writeNBytes ( hdr . DispDataOffset , 2 , sizeof ( hdr ) + 10 + 1 + ( int ) segName . get_len ( ) ) ;
2015-11-15 21:14:46 -08:00
_writeNBytes ( hdr . Length , 4 , num_bytes_file + num_zeroes_at_end ) ;
_writeNBytes ( hdr . ResSpc , 4 , num_zeroes_at_end ) ;
_writeNBytes ( hdr . Align , 4 , s . align_address > 1 ? 256 : 0 ) ;
// instruction list starts with a LCONST + Length(4) + binary, the relocs begin after that
int instruction_offs = 0 ;
instructions [ instruction_offs + + ] = OMFR_LCONST ;
_writeNBytes ( instructions + instruction_offs , 4 , num_bytes_file ) ;
instruction_offs + = 4 ;
if ( s . pRelocs & & s . pRelocs - > size ( ) ) {
// insert all SUPER_RELOC2 / SUPER_RELOC3
for ( int b = 0 ; b < = 1 ; b + + ) {
int count_offs = - 1 ;
int prev_page = 0 ;
int inst_curr = instruction_offs ;
instructions [ inst_curr + + ] = OMFR_SUPER ;
int len_offs = inst_curr ;
inst_curr + = 4 ;
2016-05-25 22:44:17 -07:00
instructions [ inst_curr + + ] = ( uint8_t ) b ; // SUPER_RELOC2 / SUPER_RELOC3
2015-11-15 21:14:46 -08:00
// try all SUPER_RELOC2 (2 bytes self reference, no shift)
relocList : : iterator r = s . pRelocs - > begin ( ) ;
while ( r ! = s . pRelocs - > end ( ) ) {
if ( r - > shift = = 0 & & r - > bytes = = ( b + 2 ) & & r - > target_section = = SectionId ( s ) ) {
if ( ( r - > section_offset > > 8 ) ! = prev_page ) {
2016-05-25 22:44:17 -07:00
instructions [ inst_curr + + ] = uint8_t ( 0x80 | ( ( r - > section_offset > > 8 ) - prev_page - 1 ) ) ;
2015-11-15 21:14:46 -08:00
count_offs = - 1 ;
} // update patch counter for current page or add a new counter
2016-03-11 17:08:44 -08:00
if ( count_offs < 0 ) {
count_offs = inst_curr ;
instructions [ inst_curr + + ] = 0 ;
} else
instructions [ count_offs ] + + ;
2015-11-15 21:14:46 -08:00
prev_page = r - > section_offset > > 8 ;
2016-03-12 11:39:53 -08:00
instructions [ inst_curr + + ] = ( uint8_t ) r - > section_offset ; // write patch offset into binary
2015-11-15 21:14:46 -08:00
_writeNBytes ( s . output + r - > section_offset , b + 2 , r - > base_value ) ; // patch binary with base value
r = s . pRelocs - > erase ( r ) ;
} else
+ + r ;
}
2015-11-15 22:15:34 -08:00
if ( inst_curr > ( instruction_offs + 6 ) ) {
2015-11-15 21:14:46 -08:00
_writeNBytes ( instructions + len_offs , 4 , inst_curr - instruction_offs - 5 ) ;
instruction_offs = inst_curr ;
}
}
// insert all other records as they are encountered
relocList : : iterator r = s . pRelocs - > begin ( ) ;
while ( r ! = s . pRelocs - > end ( ) ) {
if ( r - > target_section = = SectionId ( s ) ) {
// this is a reloc, check if cRELOC is ok or if need RELOC
bool cRELOC = r - > section_offset < 0x10000 & & r - > base_value < 0x10000 ;
2016-05-25 22:44:17 -07:00
instructions [ instruction_offs + + ] = uint8_t ( cRELOC ? OMFR_cRELOC : OMFR_RELOC ) ;
2015-11-15 21:14:46 -08:00
instructions [ instruction_offs + + ] = r - > bytes ;
instructions [ instruction_offs + + ] = r - > shift ;
_writeNBytes ( instructions + instruction_offs , cRELOC ? 2 : 4 , r - > section_offset ) ;
instruction_offs + = cRELOC ? 2 : 4 ;
_writeNBytes ( instructions + instruction_offs , cRELOC ? 2 : 4 , r - > base_value ) ;
instruction_offs + = cRELOC ? 2 : 4 ;
} else {
// this is an interseg
bool cINTERSEG = r - > section_offset < 0x10000 & & r - > base_value < 0x10000 ;
2016-05-25 22:44:17 -07:00
instructions [ instruction_offs + + ] = uint8_t ( cINTERSEG ? OMFR_cINTERSEG : OMFR_INTERSEG ) ;
2015-11-15 21:14:46 -08:00
instructions [ instruction_offs + + ] = r - > bytes ;
instructions [ instruction_offs + + ] = r - > shift ;
_writeNBytes ( instructions + instruction_offs , cINTERSEG ? 2 : 4 , r - > section_offset ) ;
instruction_offs + = cINTERSEG ? 2 : 4 ;
_writeNBytes ( instructions + instruction_offs , cINTERSEG ? 0 : 2 , 1 ) ; // file number = 1
instruction_offs + = cINTERSEG ? 0 : 2 ;
_writeNBytes ( instructions + instruction_offs , cINTERSEG ? 1 : 2 , SegLookup [ r - > target_section ] + 1 ) ; // segment number starting from 1
instruction_offs + = cINTERSEG ? 1 : 2 ;
_writeNBytes ( instructions + instruction_offs , cINTERSEG ? 2 : 4 , r - > base_value ) ;
instruction_offs + = cINTERSEG ? 2 : 4 ;
}
r = s . pRelocs - > erase ( r ) ;
}
}
instructions [ instruction_offs + + ] = OMFR_END ;
// size of seg = file header + 10 bytes file name + 1 byte seg name length + seg nameh + seg.addr_size() + instruction_size
2016-05-20 22:48:13 -07:00
int segSize = sizeof ( hdr ) + 10 + 1 + ( int ) segName . get_len ( ) + num_bytes_file + instruction_offs ;
2017-01-08 16:30:30 -08:00
if ( num_bytes_file = = 0 ) { segSize - = 5 ; }
2015-11-15 21:14:46 -08:00
_writeNBytes ( hdr . SegTotal , 4 , segSize ) ;
2016-03-12 11:39:53 -08:00
uint8_t lenSegName = ( uint8_t ) segName . get_len ( ) ;
2015-11-15 21:14:46 -08:00
fwrite ( & hdr , sizeof ( hdr ) , 1 , f ) ;
fwrite ( segfile , 10 , 1 , f ) ;
fwrite ( & lenSegName , 1 , 1 , f ) ;
fwrite ( segName . get ( ) , segName . get_len ( ) , 1 , f ) ;
if ( num_bytes_file ) {
fwrite ( instructions , 5 , 1 , f ) ; // $f2 + 4 bytes data size
fwrite ( s . output , num_bytes_file , 1 , f ) ; // segment data
}
if ( instruction_offs > 5 )
fwrite ( instructions + 5 , instruction_offs - 5 , 1 , f ) ; // reloc instructions
}
2015-11-17 23:47:35 -08:00
// if there is a size of the direct page & stack, write it
if ( DP_Stack_Size ) {
strref segName ( " DPStack " ) ;
2016-05-20 22:48:13 -07:00
char lenSegName = ( char ) segName . get_len ( ) ;
2015-11-17 23:47:35 -08:00
_writeNBytes ( hdr . SegNum , 2 , ( int ) SegNum . size ( ) + 1 ) ;
_writeNBytes ( hdr . Kind , 2 , 0x12 ) ;
2016-05-20 22:48:13 -07:00
_writeNBytes ( hdr . DispDataOffset , 2 , sizeof ( hdr ) + 10 + 1 + ( int ) segName . get_len ( ) ) ;
2015-11-17 23:47:35 -08:00
_writeNBytes ( hdr . Length , 4 , DP_Stack_Size ) ;
_writeNBytes ( hdr . ResSpc , 4 , DP_Stack_Size ) ;
_writeNBytes ( hdr . Align , 4 , 256 ) ;
2016-05-20 22:48:13 -07:00
int segSize = sizeof ( hdr ) + 10 + 1 + ( int ) segName . get_len ( ) + 1 ;
2015-11-17 23:47:35 -08:00
_writeNBytes ( hdr . SegTotal , 4 , segSize ) ;
instructions [ 0 ] = 0 ;
fwrite ( & hdr , sizeof ( hdr ) , 1 , f ) ;
fwrite ( segfile , 10 , 1 , f ) ;
fwrite ( & lenSegName , 1 , 1 , f ) ;
fwrite ( segName . get ( ) , segName . get_len ( ) , 1 , f ) ;
fwrite ( instructions , 1 , 1 , f ) ; // end instruction
}
2015-11-15 22:15:34 -08:00
free ( instructions ) ;
2015-11-15 21:14:46 -08:00
fclose ( f ) ;
return STATUS_OK ;
}
2017-01-08 16:30:30 -08:00
int main ( int argc , char * * argv ) {
2015-10-18 12:42:10 -07:00
const strref listing ( " lst " ) ;
2019-09-03 17:10:48 -07:00
const strref tass_listing ( " tsl " ) ;
const strref tass_labels ( " tl " ) ;
2015-10-18 12:42:10 -07:00
const strref allinstr ( " opcodes " ) ;
2015-10-20 22:28:53 -07:00
const strref endmacro ( " endm " ) ;
2015-10-21 22:34:01 -07:00
const strref cpu ( " cpu " ) ;
2015-10-25 23:48:35 -07:00
const strref acc ( " acc " ) ;
const strref xy ( " xy " ) ;
2015-11-09 00:07:55 -08:00
const strref org ( " org " ) ;
2015-10-02 21:52:55 -07:00
int return_value = 0 ;
2015-10-07 22:27:03 -07:00
bool load_header = true ;
bool size_header = false ;
2015-10-13 19:38:13 -07:00
bool info = false ;
2015-10-18 12:42:10 -07:00
bool gen_allinstr = false ;
2015-11-15 21:14:46 -08:00
bool gs_os_reloc = false ;
bool force_merge_sections = false ;
2019-09-03 17:10:48 -07:00
bool list_output = false ;
bool tass_list_output = false ;
2015-10-05 22:45:42 -07:00
Asm assembler ;
2015-10-02 21:52:55 -07:00
2015-10-13 19:38:13 -07:00
const char * source_filename = nullptr , * obj_out_file = nullptr ;
const char * binary_out_name = nullptr ;
2019-09-03 17:10:48 -07:00
const char * sym_file = nullptr , * vs_file = nullptr , * tass_labels_file = nullptr ;
2015-10-18 12:42:10 -07:00
strref list_file , allinstr_file ;
2019-09-03 17:10:48 -07:00
strref tass_list_file ;
2015-10-23 22:44:56 -07:00
for ( int a = 1 ; a < argc ; a + + ) {
2017-01-08 16:30:30 -08:00
if ( argv [ a ] [ 0 ] = = ' - ' ) {
2016-05-25 22:44:17 -07:00
strref arg ( argv [ a ] + 1 ) ;
2017-01-08 16:30:30 -08:00
if ( arg . get_first ( ) = = ' i ' ) { assembler . AddIncludeFolder ( arg + 1 ) ; }
else if ( arg . same_str ( " merlin " ) ) { assembler . syntax = SYNTAX_MERLIN ; }
else if ( arg . get_first ( ) = = ' D ' | | arg . get_first ( ) = = ' d ' ) {
2015-10-05 22:45:42 -07:00
+ + arg ;
2017-01-08 16:30:30 -08:00
if ( arg . find ( ' = ' ) > 0 ) {
2015-10-05 22:45:42 -07:00
assembler . AssignLabel ( arg . before ( ' = ' ) , arg . after ( ' = ' ) ) ;
2017-01-08 16:30:30 -08:00
} else {
2015-10-05 22:45:42 -07:00
assembler . AssignLabel ( arg , " 1 " ) ;
2017-01-08 16:30:30 -08:00
}
2015-10-07 22:27:03 -07:00
} else if ( arg . same_str ( " c64 " ) ) {
load_header = true ;
size_header = false ;
} else if ( arg . same_str ( " a2b " ) ) {
2015-11-15 21:14:46 -08:00
assembler . default_org = 0x0803 ;
2015-10-07 22:27:03 -07:00
load_header = true ;
size_header = true ;
} else if ( arg . same_str ( " bin " ) ) {
load_header = false ;
size_header = false ;
2015-11-15 21:14:46 -08:00
} else if ( arg . same_str ( " a2p " ) ) {
assembler . default_org = 0x2000 ;
load_header = false ;
size_header = false ;
} else if ( arg . same_str ( " a2o " ) ) {
gs_os_reloc = true ;
} else if ( arg . same_str ( " mrg " ) ) {
force_merge_sections = true ;
2017-01-08 16:30:30 -08:00
} else if ( arg . same_str ( " sect " ) ) {
2015-10-13 19:38:13 -07:00
info = true ;
2017-01-08 16:30:30 -08:00
} else if ( arg . same_str ( endmacro ) ) {
2015-10-20 22:28:53 -07:00
assembler . end_macro_directive = true ;
2017-01-08 16:30:30 -08:00
} else if ( arg . has_prefix ( listing ) & & ( arg . get_len ( ) = = listing . get_len ( ) | | arg [ listing . get_len ( ) ] = = ' = ' ) ) {
2015-10-18 12:42:10 -07:00
assembler . list_assembly = true ;
2019-09-03 17:10:48 -07:00
list_output = true ;
list_file = arg . after ( ' = ' ) ;
} else if ( arg . has_prefix ( tass_listing ) & & ( arg . get_len ( ) = = listing . get_len ( ) | | arg [ listing . get_len ( ) ] = = ' = ' ) ) {
assembler . list_assembly = true ;
tass_list_output = true ;
tass_list_file = arg . after ( ' = ' ) ;
2017-01-08 16:30:30 -08:00
} else if ( arg . has_prefix ( allinstr ) & & ( arg . get_len ( ) = = allinstr . get_len ( ) | | arg [ allinstr . get_len ( ) ] = = ' = ' ) ) {
2015-10-18 12:42:10 -07:00
gen_allinstr = true ;
allinstr_file = arg . after ( ' = ' ) ;
2015-11-09 00:07:55 -08:00
} else if ( arg . has_prefix ( org ) ) {
arg = arg . after ( ' = ' ) ;
2017-01-08 16:30:30 -08:00
if ( arg & & arg . get_first ( ) = = ' $ ' & & arg . get_len ( ) > 1 ) {
assembler . default_org = ( int ) ( arg + 1 ) . ahextoui ( ) ;
} else if ( arg . is_number ( ) ) { assembler . default_org = ( int ) arg . atoi ( ) ; }
2016-03-11 16:58:24 -08:00
// force the current section to be org'd
assembler . AssignAddressToSection ( assembler . SectionId ( ) , assembler . default_org ) ;
2017-01-08 16:30:30 -08:00
} else if ( arg . has_prefix ( acc ) & & arg [ acc . get_len ( ) ] = = ' = ' ) {
assembler . accumulator_16bit = arg . after ( ' = ' ) . atoi ( ) = = 16 ;
} else if ( arg . has_prefix ( xy ) & & arg [ xy . get_len ( ) ] = = ' = ' ) {
assembler . index_reg_16bit = arg . after ( ' = ' ) . atoi ( ) = = 16 ;
} else if ( arg . has_prefix ( cpu ) & & ( arg . get_len ( ) = = cpu . get_len ( ) | | arg [ cpu . get_len ( ) ] = = ' = ' ) ) {
2015-10-21 22:34:01 -07:00
arg . split_token_trim ( ' = ' ) ;
2015-10-25 23:48:35 -07:00
bool found = false ;
2015-10-23 22:44:56 -07:00
for ( int c = 0 ; c < nCPUs ; c + + ) {
if ( arg ) {
if ( arg . same_str ( aCPUs [ c ] . name ) ) {
assembler . SetCPU ( ( CPUIndex ) c ) ;
2015-10-25 23:48:35 -07:00
found = true ;
2015-10-23 22:44:56 -07:00
break ;
}
2017-01-08 16:30:30 -08:00
} else { printf ( " %s \n " , aCPUs [ c ] . name ) ; }
2015-10-21 22:34:01 -07:00
}
2015-10-25 23:48:35 -07:00
if ( ! found & & arg ) {
printf ( " ERROR: UNKNOWN CPU " STRREF_FMT " \n " , STRREF_ARG ( arg ) ) ;
return 1 ;
}
2017-01-08 16:30:30 -08:00
if ( ! arg ) { return 0 ; }
} else if ( arg . same_str ( " sym " ) & & ( a + 1 ) < argc ) {
2015-10-23 22:44:56 -07:00
sym_file = argv [ + + a ] ;
2017-01-08 16:30:30 -08:00
} else if ( arg . same_str ( " obj " ) & & ( a + 1 ) < argc ) {
2015-10-23 22:44:56 -07:00
obj_out_file = argv [ + + a ] ;
2017-01-08 16:30:30 -08:00
} else if ( arg . same_str ( " vice " ) & & ( a + 1 ) < argc ) {
2015-10-23 22:44:56 -07:00
vs_file = argv [ + + a ] ;
2019-09-03 17:10:48 -07:00
} else if ( arg . same_str ( tass_labels ) & & ( a + 1 ) < argc ) {
tass_labels_file = argv [ + + a ] ;
2017-01-08 16:30:30 -08:00
} else { printf ( " Unexpected option " STRREF_FMT " \n " , STRREF_ARG ( arg ) ) ; }
} else if ( ! source_filename ) { source_filename = argv [ a ] ; }
else if ( ! binary_out_name ) { binary_out_name = argv [ a ] ; }
2015-10-18 12:42:10 -07:00
}
2016-05-25 22:44:17 -07:00
for ( int a = 1 ; a < argc ; a + + ) {
strref arg ( argv [ a ] ) ;
printf ( STRREF_FMT " \n " , STRREF_ARG ( arg ) ) ;
}
2015-10-18 12:42:10 -07:00
if ( gen_allinstr ) {
assembler . AllOpcodes ( allinstr_file ) ;
} else if ( ! source_filename ) {
2015-10-23 22:44:56 -07:00
puts ( " Usage: \n "
" x65 filename.s code.prg [options] \n "
" * -i(path) : Add include path \n "
2015-11-05 21:23:38 -08:00
" * -D(label)[=value] : Define a label with an optional value (otherwise defined as 1) \n "
2015-10-24 13:41:11 -07:00
" * -cpu=6502/65c02/65c02wdc/65816: assemble with opcodes for a different cpu \n "
2015-11-05 21:23:38 -08:00
" * -acc=8/16: set the accumulator mode for 65816 at start, default is 8 bits \n "
" * -xy=8/16: set the index register mode for 65816 at start, default is 8 bits \n "
2016-03-11 16:58:24 -08:00
" * -org = $2000 or - org = 4096: force fixed address code at address \n "
2015-11-05 21:23:38 -08:00
" * -obj (file.x65) : generate object file for later linking \n "
2015-10-23 22:44:56 -07:00
" * -bin : Raw binary \n "
" * -c64 : Include load address(default) \n "
" * -a2b : Apple II Dos 3.3 Binary \n "
2015-11-15 21:14:46 -08:00
" * -a2p : Apple II ProDos Binary \n "
" * -a2o : Apple II GS OS executable (relocatable) \n "
" * -mrg : Force merge all sections (use with -a2o) \n "
2015-11-05 21:23:38 -08:00
" * -sym (file.sym) : symbol file \n "
2015-10-23 22:44:56 -07:00
" * -lst / -lst = (file.lst) : generate disassembly text from result(file or stdout) \n "
" * -opcodes / -opcodes = (file.s) : dump all available opcodes(file or stdout) \n "
" * -sect: display sections loaded and built \n "
2015-11-05 21:23:38 -08:00
" * -vice (file.vs) : export a vice symbol file \n "
2015-10-24 13:41:11 -07:00
" * -merlin: use Merlin syntax \n "
2015-10-23 22:44:56 -07:00
" * -endm : macros end with endm or endmacro instead of scoped('{' - '}') \n " ) ;
2015-09-29 22:07:04 -07:00
return 0 ;
}
2015-10-18 12:42:10 -07:00
2015-09-29 22:07:04 -07:00
// Load source
if ( source_filename ) {
size_t size = 0 ;
2015-10-07 22:27:03 -07:00
strref srcname ( source_filename ) ;
2015-11-15 21:14:46 -08:00
assembler . export_base_name =
strref ( binary_out_name ) . after_last_or_full ( ' / ' , ' \\ ' ) . before_or_full ( ' . ' ) ;
2015-10-21 22:34:01 -07:00
2015-10-07 22:27:03 -07:00
if ( char * buffer = assembler . LoadText ( srcname , size ) ) {
// if source_filename contains a path add that as a search path for include files
assembler . AddIncludeFolder ( srcname . before_last ( ' / ' , ' \\ ' ) ) ;
2015-10-19 22:44:02 -07:00
assembler . Assemble ( strref ( buffer , strl_t ( size ) ) , srcname , obj_out_file ! = nullptr ) ;
2017-01-08 16:30:30 -08:00
if ( assembler . error_encountered ) {
2015-10-05 22:45:42 -07:00
return_value = 1 ;
2017-01-08 16:30:30 -08:00
} else {
2015-11-15 21:14:46 -08:00
// export object file (this can be done at the same time as building a binary)
2017-01-08 16:30:30 -08:00
if ( obj_out_file ) { assembler . WriteObjectFile ( obj_out_file ) ; }
2015-10-13 19:38:13 -07:00
2015-11-15 21:14:46 -08:00
// if exporting binary or relocatable executable, complete the build
2015-10-18 19:48:03 -07:00
if ( binary_out_name & & ! srcname . same_str ( binary_out_name ) ) {
2015-11-15 21:14:46 -08:00
if ( gs_os_reloc )
assembler . WriteA2GS_OMF ( binary_out_name , force_merge_sections ) ;
else {
strref binout ( binary_out_name ) ;
strref ext = binout . after_last ( ' . ' ) ;
2017-01-08 16:30:30 -08:00
if ( ext ) { binout . clip ( ext . get_len ( ) + 1 ) ; }
2015-11-15 21:14:46 -08:00
strref aAppendNames [ MAX_EXPORT_FILES ] ;
StatusCode err = assembler . LinkZP ( ) ; // link zero page sections
if ( err > FIRST_ERROR ) {
assembler . PrintError ( strref ( ) , err ) ;
return_value = 1 ;
}
int numExportFiles = assembler . GetExportNames ( aAppendNames , MAX_EXPORT_FILES ) ;
for ( int e = 0 ; e < numExportFiles ; e + + ) {
strown < 512 > file ( binout ) ;
file . append ( aAppendNames [ e ] ) ;
file . append ( ' . ' ) ;
file . append ( ext ) ;
2016-12-23 13:56:57 -08:00
int size_export ;
2015-11-15 21:14:46 -08:00
int addr ;
2016-12-23 13:56:57 -08:00
if ( uint8_t * buf = assembler . BuildExport ( aAppendNames [ e ] , size_export , addr ) ) {
2015-11-15 21:14:46 -08:00
if ( FILE * f = fopen ( file . c_str ( ) , " wb " ) ) {
if ( load_header ) {
2016-03-12 11:39:53 -08:00
uint8_t load_addr [ 2 ] = { ( uint8_t ) addr , ( uint8_t ) ( addr > > 8 ) } ;
2015-11-15 21:14:46 -08:00
fwrite ( load_addr , 2 , 1 , f ) ;
}
if ( size_header ) {
2016-12-23 13:56:57 -08:00
uint8_t byte_size [ 2 ] = { ( uint8_t ) size_export , ( uint8_t ) ( size_export > > 8 ) } ;
2015-11-15 21:14:46 -08:00
fwrite ( byte_size , 2 , 1 , f ) ;
}
2016-12-23 13:56:57 -08:00
fwrite ( buf , size_export , 1 , f ) ;
2015-11-15 21:14:46 -08:00
fclose ( f ) ;
2015-10-18 19:48:03 -07:00
}
2015-11-15 21:14:46 -08:00
free ( buf ) ;
2015-10-18 19:48:03 -07:00
}
}
}
}
2015-10-10 15:25:08 -07:00
2015-10-18 19:48:03 -07:00
// print encountered sections info
2015-10-13 19:38:13 -07:00
if ( info ) {
printf ( " SECTIONS SUMMARY \n ================ \n " ) ;
for ( size_t i = 0 ; i < assembler . allSections . size ( ) ; + + i ) {
Section & s = assembler . allSections [ i ] ;
2015-10-18 19:48:03 -07:00
if ( s . address > s . start_address ) {
printf ( " Section %d: \" " STRREF_FMT " \" Dummy: %s Relative: %s Merged: %s Start: 0x%04x End: 0x%04x \n " ,
2015-10-23 22:44:56 -07:00
( int ) i , STRREF_ARG ( s . name ) , s . dummySection ? " yes " : " no " ,
s . IsRelativeSection ( ) ? " yes " : " no " , s . IsMergedSection ( ) ? " yes " : " no " , s . start_address , s . address ) ;
2015-10-18 19:48:03 -07:00
if ( s . pRelocs ) {
2016-12-23 13:56:57 -08:00
for ( relocList : : iterator rel = s . pRelocs - > begin ( ) ; rel ! = s . pRelocs - > end ( ) ; + + rel )
printf ( " \t Reloc value $%x at offs $%x section %d \n " , rel - > base_value , rel - > section_offset , rel - > target_section ) ;
2015-10-18 19:48:03 -07:00
}
2015-10-13 19:38:13 -07:00
}
2015-10-10 15:25:08 -07:00
}
}
2015-10-18 19:48:03 -07:00
// listing after export since addresses are now resolved
2019-09-03 17:10:48 -07:00
if ( list_output )
2015-10-18 19:48:03 -07:00
assembler . List ( list_file ) ;
2019-09-03 17:10:48 -07:00
if ( tass_list_output )
assembler . ListTassStyle ( tass_list_file ) ;
2015-10-11 14:55:55 -07:00
// export .sym file
if ( sym_file & & ! srcname . same_str ( sym_file ) & & ! assembler . map . empty ( ) ) {
2015-10-05 22:45:42 -07:00
if ( FILE * f = fopen ( sym_file , " w " ) ) {
2015-10-23 22:44:56 -07:00
bool wasLocal = false ;
for ( MapSymbolArray : : iterator i = assembler . map . begin ( ) ; i ! = assembler . map . end ( ) ; + + i ) {
2017-09-24 22:36:42 -07:00
uint32_t value = ( uint32_t ) i - > value ;
if ( size_t ( i - > section ) < assembler . allSections . size ( ) ) { value + = assembler . allSections [ i - > section ] . start_address ; }
2015-10-25 23:48:35 -07:00
fprintf ( f , " %s.label " STRREF_FMT " = $%04x " , wasLocal = = i - > local ? " \n " :
( i - > local ? " { \n " : " \n } \n " ) , STRREF_ARG ( i - > name ) , value ) ;
2015-10-19 22:44:02 -07:00
wasLocal = i - > local ;
2015-10-23 22:44:56 -07:00
}
fputs ( wasLocal ? " \n } \n " : " \n " , f ) ;
2015-10-05 22:45:42 -07:00
fclose ( f ) ;
}
}
2015-10-18 19:48:03 -07:00
2016-03-01 18:34:20 -08:00
// export vice monitor commands
2015-10-11 14:55:55 -07:00
if ( vs_file & & ! srcname . same_str ( vs_file ) & & ! assembler . map . empty ( ) ) {
2015-10-05 22:45:42 -07:00
if ( FILE * f = fopen ( vs_file , " w " ) ) {
2015-10-23 22:44:56 -07:00
for ( MapSymbolArray : : iterator i = assembler . map . begin ( ) ; i ! = assembler . map . end ( ) ; + + i ) {
2017-09-24 22:36:42 -07:00
uint32_t value = ( uint32_t ) i - > value ;
if ( size_t ( i - > section ) < assembler . allSections . size ( ) ) { value + = assembler . allSections [ i - > section ] . start_address ; }
2017-01-08 16:30:30 -08:00
if ( i - > name . same_str ( " debugbreak " ) ) {
2015-12-02 22:16:31 -08:00
fprintf ( f , " break $%04x \n " , value ) ;
2017-01-08 16:30:30 -08:00
} else {
2015-12-02 22:16:31 -08:00
fprintf ( f , " al $%04x %s " STRREF_FMT " \n " , value , i - > name [ 0 ] = = ' . ' ? " " : " . " ,
2017-01-08 16:30:30 -08:00
STRREF_ARG ( i - > name ) ) ;
}
2015-10-23 22:44:56 -07:00
}
2015-10-05 22:45:42 -07:00
fclose ( f ) ;
}
2015-09-29 22:07:04 -07:00
}
2019-09-03 17:10:48 -07:00
// export tass labels
if ( tass_labels_file & & ! srcname . same_str ( tass_labels_file ) & & ! assembler . map . empty ( ) ) {
if ( FILE * f = fopen ( tass_labels_file , " w " ) ) {
for ( MapSymbolArray : : iterator i = assembler . map . begin ( ) ; i ! = assembler . map . end ( ) ; + + i ) {
uint32_t value = ( uint32_t ) i - > value ;
if ( size_t ( i - > section ) < assembler . allSections . size ( ) ) { value + = assembler . allSections [ i - > section ] . start_address ; }
if ( i - > name . same_str ( " debugbreak " ) ) { }
else {
strown < 256 > line ;
line . append ( i - > name ) ;
line . sprintf_append ( " \t = $%04x \n " , value ) ;
fprintf ( f , line . c_str ( ) ) ;
}
}
fclose ( f ) ;
}
}
2015-09-29 22:07:04 -07:00
}
// free some memory
assembler . Cleanup ( ) ;
}
}
2015-10-02 21:52:55 -07:00
return return_value ;
2015-09-29 22:07:04 -07:00
}