mirror of
https://github.com/uffejakobsen/acme.git
synced 2024-11-22 03:30:46 +00:00
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:
parent
b04af19d5c
commit
a69968dc05
17
src/acme.c
17
src/acme.c
@ -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
|
||||||
|
32
src/mnemo.c
32
src/mnemo.c
@ -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:
|
||||||
|
50
src/output.c
50
src/output.c
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
;ACME 0.96.5
|
*=$1000
|
||||||
a = &c
|
label nop
|
||||||
|
a = &label
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
;ACME 0.96.5
|
*=$1000
|
||||||
b = &*
|
b = &*
|
||||||
|
Loading…
Reference in New Issue
Block a user