fixed a bug in "unpseudopc" operator "&" and did some cleanup

git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@351 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
marcobaye 2024-03-01 01:12:15 +00:00
parent b04af19d5c
commit a69968dc05
7 changed files with 64 additions and 46 deletions

View File

@ -333,9 +333,9 @@ static void perform_pass(void)
} }
} }
output_endofpass(); // make sure last code segment is closed output_endofpass(); // make sure last code segment is closed
// TODO: atm "--from-to" reads two numbers. if that is changed in the // TODO: atm "--from-to" reads two number literals. if that is changed
// future to two general expressions, this is the point where they would // in the future to two general expressions, this is the point where
// need to be evaluated. // they would need to be evaluated.
if (config.process_verbosity > 8) if (config.process_verbosity > 8)
printf("Found %d undefined expressions.\n", pass.undefined_count); printf("Found %d undefined expressions.\n", pass.undefined_count);
if (pass.error_count) if (pass.error_count)
@ -351,6 +351,11 @@ static void do_actual_work(void)
report = &global_report; // let global pointer point to something report = &global_report; // let global pointer point to something
report_init(report); // we must init struct before doing passes report_init(report); // we must init struct before doing passes
sanity.macro_recursions_left = config.sanity_limit;
sanity.source_recursions_left = config.sanity_limit;
sanity.passes_left = config.sanity_limit;
pass.complain_about_undefined = FALSE; // disable until error pass needed pass.complain_about_undefined = FALSE; // disable until error pass needed
perform_pass(); // first pass perform_pass(); // first pass
// pretend there has been a previous pass, with one more undefined result // pretend there has been a previous pass, with one more undefined result
@ -362,6 +367,7 @@ static void do_actual_work(void)
perform_pass(); perform_pass();
if (--sanity.passes_left < 0) { if (--sanity.passes_left < 0) {
// FIXME - exit with error // FIXME - exit with error
// ...or maybe do one additional pass where all errors are reported, including "not defined" and "value has changed".
//puts("Exceeded maximum number of passes, please check your sources."); //puts("Exceeded maximum number of passes, please check your sources.");
//break; //break;
} }
@ -389,6 +395,7 @@ static void do_actual_work(void)
perform_pass(); // perform pass, but now show "value undefined" perform_pass(); // perform pass, but now show "value undefined"
// FIXME - perform_pass() calls exit() when there were errors, // FIXME - perform_pass() calls exit() when there were errors,
// so if controls returns here, call BUG()! // so if controls returns here, call BUG()!
// (this can be triggered using ifdef/ifndef)
} }
} }
@ -742,10 +749,6 @@ int main(int argc, const char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
sanity.macro_recursions_left = config.sanity_limit;
sanity.source_recursions_left = config.sanity_limit;
sanity.passes_left = config.sanity_limit;
// init output buffer // init output buffer
output_createbuffer(); output_createbuffer();
// do the actual work // do the actual work

View File

@ -159,8 +159,8 @@ static STRUCT_DYNABUF_REF(mnemo_dyna_buf, MNEMO_INITIALSIZE); // for mnemonics
// immediate mode: // immediate mode:
#define IM_FORCE8 0x000 // immediate values are 8 bits (CAUTION - program relies on "no bits set" being the default!) #define IM_FORCE8 0x000 // immediate values are 8 bits (CAUTION - program relies on "no bits set" being the default!)
#define IM_FORCE16 0x100 // immediate value is 16 bits (for 65ce02's PHW#) #define IM_FORCE16 0x100 // immediate value is 16 bits (for 65ce02's PHW#)
#define IM_ACCUMULATOR 0x200 // immediate value depends on accumulator length #define IM_ACCU_LENGTH 0x200 // immediate value depends on accumulator length
#define IM_INDEXREGS 0x300 // immediate value depends on index register length #define IM_REGS_LENGTH 0x300 // immediate value depends on index register length
#define IMMASK 0x300 // mask for immediate mode flags #define IMMASK 0x300 // mask for immediate mode flags
#define PREFIX_NEGNEG 0x400 // output NEG:NEG before actual opcode #define PREFIX_NEGNEG 0x400 // output NEG:NEG before actual opcode
#define LI_PREFIX_NOP 0x800 // when using long indirect addressing, output NOP before actual opcode #define LI_PREFIX_NOP 0x800 // when using long indirect addressing, output NOP before actual opcode
@ -360,20 +360,20 @@ static struct ronode mnemo_stp_wai_tree[] = {
static struct ronode mnemo_65816_tree[] = { static struct ronode mnemo_65816_tree[] = {
PREDEF_START, PREDEF_START,
// CAUTION - these use 6502/65c02 indices, because the opcodes are the same - but I need flags for immediate mode! // CAUTION - these use 6502/65c02 indices, because the opcodes are the same - but I need flags for immediate mode!
PREDEFNODE("ldy", MERGE(GROUP_MISC, IDX_LDY | IM_INDEXREGS)), PREDEFNODE("ldy", MERGE(GROUP_MISC, IDX_LDY | IM_REGS_LENGTH)),
PREDEFNODE("ldx", MERGE(GROUP_MISC, IDX_LDX | IM_INDEXREGS)), PREDEFNODE("ldx", MERGE(GROUP_MISC, IDX_LDX | IM_REGS_LENGTH)),
PREDEFNODE("cpy", MERGE(GROUP_MISC, IDX_CPY | IM_INDEXREGS)), PREDEFNODE("cpy", MERGE(GROUP_MISC, IDX_CPY | IM_REGS_LENGTH)),
PREDEFNODE("cpx", MERGE(GROUP_MISC, IDX_CPX | IM_INDEXREGS)), PREDEFNODE("cpx", MERGE(GROUP_MISC, IDX_CPX | IM_REGS_LENGTH)),
PREDEFNODE("bit", MERGE(GROUP_MISC, IDXcBIT | IM_ACCUMULATOR)), PREDEFNODE("bit", MERGE(GROUP_MISC, IDXcBIT | IM_ACCU_LENGTH)),
// more addressing modes for some mnemonics: // more addressing modes for some mnemonics:
PREDEFNODE("ora", MERGE(GROUP_ACCU, IDX16ORA | IM_ACCUMULATOR)), PREDEFNODE("ora", MERGE(GROUP_ACCU, IDX16ORA | IM_ACCU_LENGTH)),
PREDEFNODE("and", MERGE(GROUP_ACCU, IDX16AND | IM_ACCUMULATOR)), PREDEFNODE("and", MERGE(GROUP_ACCU, IDX16AND | IM_ACCU_LENGTH)),
PREDEFNODE("eor", MERGE(GROUP_ACCU, IDX16EOR | IM_ACCUMULATOR)), PREDEFNODE("eor", MERGE(GROUP_ACCU, IDX16EOR | IM_ACCU_LENGTH)),
PREDEFNODE("adc", MERGE(GROUP_ACCU, IDX16ADC | IM_ACCUMULATOR)), PREDEFNODE("adc", MERGE(GROUP_ACCU, IDX16ADC | IM_ACCU_LENGTH)),
PREDEFNODE("sta", MERGE(GROUP_ACCU, IDX16STA)), PREDEFNODE("sta", MERGE(GROUP_ACCU, IDX16STA)),
PREDEFNODE("lda", MERGE(GROUP_ACCU, IDX16LDA | IM_ACCUMULATOR)), PREDEFNODE("lda", MERGE(GROUP_ACCU, IDX16LDA | IM_ACCU_LENGTH)),
PREDEFNODE("cmp", MERGE(GROUP_ACCU, IDX16CMP | IM_ACCUMULATOR)), PREDEFNODE("cmp", MERGE(GROUP_ACCU, IDX16CMP | IM_ACCU_LENGTH)),
PREDEFNODE("sbc", MERGE(GROUP_ACCU, IDX16SBC | IM_ACCUMULATOR)), PREDEFNODE("sbc", MERGE(GROUP_ACCU, IDX16SBC | IM_ACCU_LENGTH)),
PREDEFNODE("jmp", MERGE(GROUP_ALLJUMPS, IDX16JMP)), PREDEFNODE("jmp", MERGE(GROUP_ALLJUMPS, IDX16JMP)),
PREDEFNODE("jsr", MERGE(GROUP_ALLJUMPS, IDX16JSR)), PREDEFNODE("jsr", MERGE(GROUP_ALLJUMPS, IDX16JSR)),
// //
@ -894,10 +894,10 @@ static unsigned int imm_ops(bits *force_bit, unsigned char opcode, bits immediat
case IM_FORCE16: // currently only for 65ce02's PHW# case IM_FORCE16: // currently only for 65ce02's PHW#
return ((unsigned int) opcode) << 8; // opcode in bits8.15 forces two-byte argument return ((unsigned int) opcode) << 8; // opcode in bits8.15 forces two-byte argument
case IM_ACCUMULATOR: // for 65816 case IM_ACCU_LENGTH: // for 65816
long_register = cpu_a_is_long; long_register = cpu_a_is_long;
break; break;
case IM_INDEXREGS: // for 65816 case IM_REGS_LENGTH: // for 65816
long_register = cpu_xy_are_long; long_register = cpu_xy_are_long;
break; break;
default: default:

View File

@ -39,12 +39,19 @@ struct output {
intval_t max; // highest address segment may use intval_t max; // highest address segment may use
bits flags; // segment flags ("overlay" and "invisible", see header file) bits flags; // segment flags ("overlay" and "invisible", see header file)
struct segment list_head; // head element of doubly-linked ring list struct segment list_head; // head element of doubly-linked ring list
} segment; } segment; // FIXME - rename either this component or "struct segment"!
char xor; // output modifier char xor; // output modifier
}; };
// for offset assembly: // for offset assembly:
static struct pseudopc *pseudopc_current_context; // current struct (NULL when not in pseudopc block - FIXME, will change in future!) // struct to describe a pseudopc context (each label gets a pointer to this)
struct pseudopc {
struct pseudopc *outer; // next layer (to be able to "unpseudopc" labels by more than one level)
intval_t offset; // inner minus outer pc
enum numtype ntype; // type of outer pc (INT/UNDEFINED)
};
static struct pseudopc outermost_pseudopc_context; // dummy struct when "!pseudopc" not in use
static struct pseudopc *pseudopc_current_context = &outermost_pseudopc_context; // current struct
// variables // variables
@ -120,7 +127,7 @@ static void real_output(intval_t byte)
out->highest_written = out->write_idx; out->highest_written = out->write_idx;
// write byte and advance ptrs // write byte and advance ptrs
if (report->fd) if (report->fd)
report_binary(byte & 0xff); // file for reporting, taking also CPU_2add report_binary(byte & 0xff); // file for reporting
out->buffer[out->write_idx++] = (byte & 0xff) ^ out->xor; out->buffer[out->write_idx++] = (byte & 0xff) ^ out->xor;
++statement_size; // count this byte ++statement_size; // count this byte
} }
@ -142,8 +149,10 @@ static void no_output(intval_t byte)
void output_skip(int size) void output_skip(int size)
{ {
if (size < 1) { if (size < 1) {
// FIXME - ok for zero, but why is there no error message // ok for zero, but why is there no error message
// output for negative values? // output for negative values?
// ...because caller should have caught those!
// FIXME - add BUG() for those!
return; return;
} }
@ -239,6 +248,7 @@ void output_createbuffer(void)
out->initvalue_set = TRUE; // "!initmem" generates a warning out->initvalue_set = TRUE; // "!initmem" generates a warning
fill_value = 0xff & config.mem_init_value; fill_value = 0xff & config.mem_init_value;
} }
// FIXME - move both of these to passinit(), needed in future:
// init output buffer (fill memory with initial value) // init output buffer (fill memory with initial value)
fill_completely(fill_value); fill_completely(fill_value);
// init ring list of segments // init ring list of segments
@ -273,7 +283,8 @@ static void link_segment(intval_t start, intval_t length)
// check whether given PC is inside segment. // check whether given PC is inside segment.
// only call in first pass, otherwise too many warnings might be thrown (TODO - still?) // only call in first pass, otherwise too many warnings might be thrown
// FIXME - do it the other way round and only complain if there were no other errors!
static void check_segment(intval_t new_pc) static void check_segment(intval_t new_pc)
{ {
struct segment *test_segment = out->segment.list_head.next; struct segment *test_segment = out->segment.list_head.next;
@ -327,7 +338,12 @@ void output_passinit(void)
statement_size = 0; // increase PC by this at end of statement statement_size = 0; // increase PC by this at end of statement
// pseudopc stuff: // pseudopc stuff:
pseudopc_current_context = NULL; // FIXME - let it point to dummy struct! // init dummy pseudopc struct
outermost_pseudopc_context.outer = NULL;
outermost_pseudopc_context.offset = 0;
outermost_pseudopc_context.ntype = NUMTYPE_UNDEFINED;
// and use it:
pseudopc_current_context = &outermost_pseudopc_context;
// this was moved over from caller - does it make sense to merge into some if/else? // this was moved over from caller - does it make sense to merge into some if/else?
@ -343,7 +359,7 @@ static void end_segment(void)
{ {
intval_t amount; intval_t amount;
// in later passes, ignore completely // in later passes, ignore completely (FIXME - change!)
if (!FIRST_PASS) if (!FIRST_PASS)
return; return;
@ -524,12 +540,6 @@ void output_get_result(const char **ptr, intval_t *size, intval_t *loadaddr)
// pseudopc stuff: // pseudopc stuff:
// struct to describe a pseudopc context
struct pseudopc {
struct pseudopc *outer; // next layer (to be able to "unpseudopc" labels by more than one level)
intval_t offset; // inner minus outer pc
enum numtype ntype; // type of outer pc (INT/UNDEFINED)
};
// start offset assembly // start offset assembly
void pseudopc_start(struct number *new_pc) void pseudopc_start(struct number *new_pc)
{ {
@ -552,16 +562,20 @@ void pseudopc_end(void)
program_counter = (program_counter - pseudopc_current_context->offset) & (config.outbuf_size - 1); // pc might have wrapped around program_counter = (program_counter - pseudopc_current_context->offset) & (config.outbuf_size - 1); // pc might have wrapped around
pc_ntype = pseudopc_current_context->ntype; pc_ntype = pseudopc_current_context->ntype;
pseudopc_current_context = pseudopc_current_context->outer; // go back to outer block pseudopc_current_context = pseudopc_current_context->outer; // go back to outer block
if (pseudopc_current_context == NULL)
BUG("PseudoPCContext", 0);
} }
// un-pseudopc a label value by given number of levels // un-pseudopc a label value by given number of levels
// returns nonzero on error (if level too high) // returns nonzero on error (if level too high)
int pseudopc_unpseudo(struct number *target, struct pseudopc *context, unsigned int levels) int pseudopc_unpseudo(struct number *target, struct pseudopc *context, unsigned int levels)
{ {
while (levels--) { while (levels--) {
//if (target->ntype == NUMTYPE_UNDEFINED) if (target->ntype == NUMTYPE_UNDEFINED)
// return 0; // ok (no sense in trying to unpseudo this, and it might be an unresolved forward ref anyway) return 0; // ok (no sense in trying to unpseudo this, and it might be an unresolved forward ref anyway)
if (context == NULL) { if (context == NULL)
BUG("PseudoPCContext", 1);
if (context == &outermost_pseudopc_context) {
Throw_error("Un-pseudopc operator '&' has no !pseudopc context."); Throw_error("Un-pseudopc operator '&' has no !pseudopc context.");
return 1; // error return 1; // error
} }
@ -571,7 +585,7 @@ int pseudopc_unpseudo(struct number *target, struct pseudopc *context, unsigned
} }
return 0; // ok return 0; // ok
} }
// return pointer to current "pseudopc" struct (may be NULL!) FIXME - not anymore? // return pointer to current "pseudopc" struct
// this gets called when parsing label definitions // this gets called when parsing label definitions
struct pseudopc *pseudopc_get_context(void) struct pseudopc *pseudopc_get_context(void)
{ {
@ -580,5 +594,5 @@ struct pseudopc *pseudopc_get_context(void)
// returns nonzero if "!pseudopc" is in effect, zero otherwise // returns nonzero if "!pseudopc" is in effect, zero otherwise
int pseudopc_isactive(void) int pseudopc_isactive(void)
{ {
return pseudopc_current_context != NULL; // FIXME - compare to dummy struct instead! return pseudopc_current_context != &outermost_pseudopc_context;
} }

View File

@ -79,7 +79,7 @@ extern void pseudopc_end(void);
// returns nonzero on error (if level too high) // returns nonzero on error (if level too high)
extern int pseudopc_unpseudo(struct number *target, struct pseudopc *context, unsigned int levels); extern int pseudopc_unpseudo(struct number *target, struct pseudopc *context, unsigned int levels);
// return pointer to current "pseudopc" struct (may be NULL!) // return pointer to current "pseudopc" struct
// this gets called when parsing label definitions // this gets called when parsing label definitions
extern struct pseudopc *pseudopc_get_context(void); extern struct pseudopc *pseudopc_get_context(void);

View File

@ -9,7 +9,7 @@
#define RELEASE "0.97" // update before release FIXME #define RELEASE "0.97" // update before release FIXME
#define CODENAME "Zem" // update before release #define CODENAME "Zem" // update before release
#define CHANGE_DATE "23 Feb" // update before release FIXME #define CHANGE_DATE "24 Feb" // update before release FIXME
#define CHANGE_YEAR "2024" // update before release #define CHANGE_YEAR "2024" // update before release
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/" //#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME #define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME

View File

@ -1,2 +1,3 @@
;ACME 0.96.5 *=$1000
a = &c label nop
a = &label

View File

@ -1,2 +1,2 @@
;ACME 0.96.5 *=$1000
b = &* b = &*