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
// TODO: atm "--from-to" reads two numbers. if that is changed in the
// future to two general expressions, this is the point where they would
// need to be evaluated.
// TODO: atm "--from-to" reads two number literals. if that is changed
// in the future to two general expressions, this is the point where
// they would need to be evaluated.
if (config.process_verbosity > 8)
printf("Found %d undefined expressions.\n", pass.undefined_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_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
perform_pass(); // first pass
// pretend there has been a previous pass, with one more undefined result
@ -362,6 +367,7 @@ static void do_actual_work(void)
perform_pass();
if (--sanity.passes_left < 0) {
// 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.");
//break;
}
@ -389,6 +395,7 @@ static void do_actual_work(void)
perform_pass(); // perform pass, but now show "value undefined"
// FIXME - perform_pass() calls exit() when there were errors,
// 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);
}
sanity.macro_recursions_left = config.sanity_limit;
sanity.source_recursions_left = config.sanity_limit;
sanity.passes_left = config.sanity_limit;
// init output buffer
output_createbuffer();
// do the actual work

View File

@ -159,8 +159,8 @@ static STRUCT_DYNABUF_REF(mnemo_dyna_buf, MNEMO_INITIALSIZE); // for mnemonics
// immediate mode:
#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_ACCUMULATOR 0x200 // immediate value depends on accumulator length
#define IM_INDEXREGS 0x300 // immediate value depends on index register length
#define IM_ACCU_LENGTH 0x200 // immediate value depends on accumulator length
#define IM_REGS_LENGTH 0x300 // immediate value depends on index register length
#define IMMASK 0x300 // mask for immediate mode flags
#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
@ -360,20 +360,20 @@ static struct ronode mnemo_stp_wai_tree[] = {
static struct ronode mnemo_65816_tree[] = {
PREDEF_START,
// 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("ldx", MERGE(GROUP_MISC, IDX_LDX | IM_INDEXREGS)),
PREDEFNODE("cpy", MERGE(GROUP_MISC, IDX_CPY | IM_INDEXREGS)),
PREDEFNODE("cpx", MERGE(GROUP_MISC, IDX_CPX | IM_INDEXREGS)),
PREDEFNODE("bit", MERGE(GROUP_MISC, IDXcBIT | IM_ACCUMULATOR)),
PREDEFNODE("ldy", MERGE(GROUP_MISC, IDX_LDY | IM_REGS_LENGTH)),
PREDEFNODE("ldx", MERGE(GROUP_MISC, IDX_LDX | IM_REGS_LENGTH)),
PREDEFNODE("cpy", MERGE(GROUP_MISC, IDX_CPY | IM_REGS_LENGTH)),
PREDEFNODE("cpx", MERGE(GROUP_MISC, IDX_CPX | IM_REGS_LENGTH)),
PREDEFNODE("bit", MERGE(GROUP_MISC, IDXcBIT | IM_ACCU_LENGTH)),
// more addressing modes for some mnemonics:
PREDEFNODE("ora", MERGE(GROUP_ACCU, IDX16ORA | IM_ACCUMULATOR)),
PREDEFNODE("and", MERGE(GROUP_ACCU, IDX16AND | IM_ACCUMULATOR)),
PREDEFNODE("eor", MERGE(GROUP_ACCU, IDX16EOR | IM_ACCUMULATOR)),
PREDEFNODE("adc", MERGE(GROUP_ACCU, IDX16ADC | IM_ACCUMULATOR)),
PREDEFNODE("ora", MERGE(GROUP_ACCU, IDX16ORA | IM_ACCU_LENGTH)),
PREDEFNODE("and", MERGE(GROUP_ACCU, IDX16AND | IM_ACCU_LENGTH)),
PREDEFNODE("eor", MERGE(GROUP_ACCU, IDX16EOR | IM_ACCU_LENGTH)),
PREDEFNODE("adc", MERGE(GROUP_ACCU, IDX16ADC | IM_ACCU_LENGTH)),
PREDEFNODE("sta", MERGE(GROUP_ACCU, IDX16STA)),
PREDEFNODE("lda", MERGE(GROUP_ACCU, IDX16LDA | IM_ACCUMULATOR)),
PREDEFNODE("cmp", MERGE(GROUP_ACCU, IDX16CMP | IM_ACCUMULATOR)),
PREDEFNODE("sbc", MERGE(GROUP_ACCU, IDX16SBC | IM_ACCUMULATOR)),
PREDEFNODE("lda", MERGE(GROUP_ACCU, IDX16LDA | IM_ACCU_LENGTH)),
PREDEFNODE("cmp", MERGE(GROUP_ACCU, IDX16CMP | IM_ACCU_LENGTH)),
PREDEFNODE("sbc", MERGE(GROUP_ACCU, IDX16SBC | IM_ACCU_LENGTH)),
PREDEFNODE("jmp", MERGE(GROUP_ALLJUMPS, IDX16JMP)),
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#
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;
break;
case IM_INDEXREGS: // for 65816
case IM_REGS_LENGTH: // for 65816
long_register = cpu_xy_are_long;
break;
default:

View File

@ -39,12 +39,19 @@ struct output {
intval_t max; // highest address segment may use
bits flags; // segment flags ("overlay" and "invisible", see header file)
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
};
// 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
@ -120,7 +127,7 @@ static void real_output(intval_t byte)
out->highest_written = out->write_idx;
// write byte and advance ptrs
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;
++statement_size; // count this byte
}
@ -142,8 +149,10 @@ static void no_output(intval_t byte)
void output_skip(int size)
{
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?
// ...because caller should have caught those!
// FIXME - add BUG() for those!
return;
}
@ -239,6 +248,7 @@ void output_createbuffer(void)
out->initvalue_set = TRUE; // "!initmem" generates a warning
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)
fill_completely(fill_value);
// 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.
// 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)
{
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
// 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?
@ -343,7 +359,7 @@ static void end_segment(void)
{
intval_t amount;
// in later passes, ignore completely
// in later passes, ignore completely (FIXME - change!)
if (!FIRST_PASS)
return;
@ -524,12 +540,6 @@ void output_get_result(const char **ptr, intval_t *size, intval_t *loadaddr)
// 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
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
pc_ntype = pseudopc_current_context->ntype;
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
// returns nonzero on error (if level too high)
int pseudopc_unpseudo(struct number *target, struct pseudopc *context, unsigned int levels)
{
while (levels--) {
//if (target->ntype == NUMTYPE_UNDEFINED)
// return 0; // ok (no sense in trying to unpseudo this, and it might be an unresolved forward ref anyway)
if (target->ntype == NUMTYPE_UNDEFINED)
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.");
return 1; // error
}
@ -571,7 +585,7 @@ int pseudopc_unpseudo(struct number *target, struct pseudopc *context, unsigned
}
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
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
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)
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
extern struct pseudopc *pseudopc_get_context(void);

View File

@ -9,7 +9,7 @@
#define RELEASE "0.97" // update before release FIXME
#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 HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME

View File

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

View File

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