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
|
||||
// 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
|
||||
|
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:
|
||||
#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:
|
||||
|
50
src/output.c
50
src/output.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,2 +1,3 @@
|
||||
;ACME 0.96.5
|
||||
a = &c
|
||||
*=$1000
|
||||
label nop
|
||||
a = &label
|
||||
|
@ -1,2 +1,2 @@
|
||||
;ACME 0.96.5
|
||||
*=$1000
|
||||
b = &*
|
||||
|
Loading…
Reference in New Issue
Block a user