cleanup, now only output.c accesses CPU_state.pc

git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@186 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
marcobaye 2020-05-22 20:55:36 +00:00
parent dfca72688b
commit 0173eaf777
7 changed files with 94 additions and 33 deletions

View File

@ -587,3 +587,41 @@ int main(int argc, const char *argv[])
save_output_file(); save_output_file();
return ACME_finalize(EXIT_SUCCESS); // dump labels, if wanted return ACME_finalize(EXIT_SUCCESS); // dump labels, if wanted
} }
/*
TODO - maybe add a "use version" switch to ease assembling old sources?
relevant changes are:
"0.05"
...would be the syntax before any changes
(how was offset assembly ended? '*' in a line on its own?)
BIT without any arg would output $2c, masking the next two bytes
"0.07"
"leading zeroes" info is now stored in symbols as well
changed argument order of mvp/mvn
!cbm outputs warning to use !ct pet instead
!end changed to !eof
*= is now segment change instead of offset assembly
added !pseudopc/!realpc
"0.86"
!pseudopc/!realpc gives a warning to use !pseudopc{} instead
"0.89"
>> now does ASR everywhere, added >>> as LSR
numbers before mnemonics are no longer interpreted as labels
"0.93"
*= no longer ends offset assembly
"0.94.6"
powerof is now right-associative
"0.94.8"
disabled !cbm
disabled !pseudopc/!realpc
disabled !subzone
"0.94.12"
new !for syntax
"0.95.2"
changed ANC#8 from 0x2b to 0x0b
"future"
backslash escaping (= strings)
TODO: paths should be relative to file, not start dir
TODO: ignore leading zeroes?
*/

View File

@ -2049,6 +2049,8 @@ intval_t ALU_any_int(void) // ACCEPT_UNDEFINED
// EMPTY: complain _seriously_ // EMPTY: complain _seriously_
// UNDEFINED: complain _seriously_ // UNDEFINED: complain _seriously_
// FLOAT: convert to int // FLOAT: convert to int
// FIXME - only very few callers actually _need_ a serious error to be thrown,
// so throw a normal one here and pass ok/fail as return value, so caller can react.
void ALU_defined_int(struct number *intresult) // no ACCEPT constants? void ALU_defined_int(struct number *intresult) // no ACCEPT constants?
{ {
struct expression expression; struct expression expression;

View File

@ -122,4 +122,6 @@ void cputype_passinit(const struct cpu_type *cpu_type)
{ {
// handle cpu type (default is 6502) // handle cpu type (default is 6502)
CPU_state.type = cpu_type ? cpu_type : &cpu_type_6502; CPU_state.type = cpu_type ? cpu_type : &cpu_type_6502;
CPU_state.a_is_long = FALSE; // short accu
CPU_state.xy_are_long = FALSE; // short index regs
} }

View File

@ -783,17 +783,18 @@ static void not_in_bank(intval_t target)
// helper function for branches with 8-bit offset (including bbr0..7/bbs0..7) // helper function for branches with 8-bit offset (including bbr0..7/bbs0..7)
static void near_branch(int preoffset) static void near_branch(int preoffset)
{ {
struct number pc;
struct number target; struct number target;
intval_t offset = 0; // dummy value, to not throw more errors than necessary intval_t offset = 0; // dummy value, to not throw more errors than necessary
vcpu_read_pc(&pc);
get_int_arg(&target, TRUE); get_int_arg(&target, TRUE);
typesystem_want_addr(&target); typesystem_want_addr(&target);
// FIXME - read pc via function call instead! if (pc.flags & target.flags & NUMBER_IS_DEFINED) {
if (CPU_state.pc.flags & target.flags & NUMBER_IS_DEFINED) {
if ((target.val.intval | 0xffff) != 0xffff) { if ((target.val.intval | 0xffff) != 0xffff) {
not_in_bank(target.val.intval); not_in_bank(target.val.intval);
} else { } else {
offset = (target.val.intval - (CPU_state.pc.val.intval + preoffset)) & 0xffff; // clip to 16 bit offset offset = (target.val.intval - (pc.val.intval + preoffset)) & 0xffff; // clip to 16 bit offset
// fix sign // fix sign
if (offset & 0x8000) if (offset & 0x8000)
offset -= 0x10000; offset -= 0x10000;
@ -817,17 +818,18 @@ static void near_branch(int preoffset)
// helper function for relative addressing with 16-bit offset // helper function for relative addressing with 16-bit offset
static void far_branch(int preoffset) static void far_branch(int preoffset)
{ {
struct number pc;
struct number target; struct number target;
intval_t offset = 0; // dummy value, to not throw more errors than necessary intval_t offset = 0; // dummy value, to not throw more errors than necessary
vcpu_read_pc(&pc);
get_int_arg(&target, TRUE); get_int_arg(&target, TRUE);
typesystem_want_addr(&target); typesystem_want_addr(&target);
// FIXME - read pc via function call instead! if (pc.flags & target.flags & NUMBER_IS_DEFINED) {
if (CPU_state.pc.flags & target.flags & NUMBER_IS_DEFINED) {
if ((target.val.intval | 0xffff) != 0xffff) { if ((target.val.intval | 0xffff) != 0xffff) {
not_in_bank(target.val.intval); not_in_bank(target.val.intval);
} else { } else {
offset = (target.val.intval - (CPU_state.pc.val.intval + preoffset)) & 0xffff; offset = (target.val.intval - (pc.val.intval + preoffset)) & 0xffff;
// no further checks necessary, 16-bit branches can access whole bank // no further checks necessary, 16-bit branches can access whole bank
} }
} }

View File

@ -496,8 +496,6 @@ void Output_passinit(void)
CPU_state.pc.flags = 0; // not defined yet CPU_state.pc.flags = 0; // not defined yet
CPU_state.pc.val.intval = 0; // same as output's write_idx on pass init CPU_state.pc.val.intval = 0; // same as output's write_idx on pass init
CPU_state.add_to_pc = 0; // increase PC by this at end of statement CPU_state.add_to_pc = 0; // increase PC by this at end of statement
CPU_state.a_is_long = FALSE; // short accu
CPU_state.xy_are_long = FALSE; // short index regs
} }
@ -630,3 +628,19 @@ void vcpu_end_statement(void)
CPU_state.pc.val.intval = (CPU_state.pc.val.intval + CPU_state.add_to_pc) & 0xffff; CPU_state.pc.val.intval = (CPU_state.pc.val.intval + CPU_state.add_to_pc) & 0xffff;
CPU_state.add_to_pc = 0; CPU_state.add_to_pc = 0;
} }
// start offset assembly
void pseudopc_start(struct pseudopc *buffer, struct number *new_pc)
{
buffer->flags = CPU_state.pc.flags;
buffer->offset = (new_pc->val.intval - CPU_state.pc.val.intval) & 0xffff;
CPU_state.pc.val.intval = new_pc->val.intval;
CPU_state.pc.flags |= NUMBER_IS_DEFINED; // FIXME - remove when allowing undefined!
//new: CPU_state.pc.flags = new_pc->flags & (NUMBER_IS_DEFINED | NUMBER_EVER_UNDEFINED);
}
// end offset assembly
void pseudopc_end(struct pseudopc *buffer)
{
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - buffer->offset) & 0xffff;
CPU_state.pc.flags = buffer->flags;
}

View File

@ -27,6 +27,11 @@ struct vcpu {
boolean a_is_long; boolean a_is_long;
boolean xy_are_long; boolean xy_are_long;
}; };
// buffer to hold outer state while parsing "pseudopc" block
struct pseudopc {
intval_t offset;
int flags;
};
// variables // variables
@ -98,6 +103,10 @@ extern void vcpu_read_pc(struct number *target);
extern int vcpu_get_statement_size(void); extern int vcpu_get_statement_size(void);
// adjust program counter (called at end of each statement) // adjust program counter (called at end of each statement)
extern void vcpu_end_statement(void); extern void vcpu_end_statement(void);
// start offset assembly
extern void pseudopc_start(struct pseudopc *buffer, struct number *new_pc);
// end offset assembly
extern void pseudopc_end(struct pseudopc *buffer);
#endif #endif

View File

@ -540,18 +540,10 @@ static enum eos po_skip(void) // now GotByte = illegal char
// insert byte until PC fits condition // insert byte until PC fits condition
static enum eos po_align(void) static enum eos po_align(void)
{ {
// FIXME - read cpu state via function call!
struct number andresult, struct number andresult,
equalresult; equalresult;
intval_t fill, intval_t fill;
test = CPU_state.pc.val.intval; struct number pc;
// make sure PC is defined.
if ((CPU_state.pc.flags & NUMBER_IS_DEFINED) == 0) {
Throw_error(exception_pc_undefined);
CPU_state.pc.flags |= NUMBER_IS_DEFINED; // do not complain again
return SKIP_REMAINDER;
}
// TODO: // TODO:
// now: !align ANDVALUE, EQUALVALUE [,FILLVALUE] // now: !align ANDVALUE, EQUALVALUE [,FILLVALUE]
@ -565,35 +557,37 @@ static enum eos po_align(void)
fill = ALU_any_int(); fill = ALU_any_int();
else else
fill = CPU_state.type->default_align_value; fill = CPU_state.type->default_align_value;
while ((test++ & andresult.val.intval) != equalresult.val.intval)
// make sure PC is defined
vcpu_read_pc(&pc);
if (!(pc.flags & NUMBER_IS_DEFINED)) {
Throw_error(exception_pc_undefined);
return SKIP_REMAINDER;
}
while ((pc.val.intval++ & andresult.val.intval) != equalresult.val.intval)
output_8(fill); output_8(fill);
return ENSURE_EOS; return ENSURE_EOS;
} }
static const char Error_old_offset_assembly[] = static const char Error_old_offset_assembly[] =
"\"!pseudopc/!realpc\" is obsolete; use \"!pseudopc {}\" instead."; "\"!pseudopc/!realpc\" is obsolete; use \"!pseudopc {}\" instead.";
// start offset assembly // start offset assembly
// FIXME - split in two parts and move backend to output.c?
// TODO - maybe add a label argument to assign the block size afterwards (for assemble-to-end-address) (or add another pseudo opcode) // TODO - maybe add a label argument to assign the block size afterwards (for assemble-to-end-address) (or add another pseudo opcode)
static enum eos po_pseudopc(void) static enum eos po_pseudopc(void)
{ {
// FIXME - read pc using a function call! struct pseudopc buffer;
struct number new_pc_result; struct number new_pc;
intval_t new_offset;
int outer_flags = CPU_state.pc.flags;
// set new // get new value
ALU_defined_int(&new_pc_result); // FIXME - allow for undefined! (complaining about non-addresses would be logical, but annoying) ALU_defined_int(&new_pc); // FIXME - allow for undefined! (complaining about non-addresses would be logical, but annoying)
new_offset = (new_pc_result.val.intval - CPU_state.pc.val.intval) & 0xffff;
CPU_state.pc.val.intval = new_pc_result.val.intval;
CPU_state.pc.flags |= NUMBER_IS_DEFINED; // FIXME - remove when allowing undefined!
// TODO - accept ', name = "section name"' // TODO - accept ', name = "section name"'
// remember old state in buffer, set new state
pseudopc_start(&buffer, &new_pc);
// if there's a block, parse that and then restore old value! // if there's a block, parse that and then restore old value!
if (Parse_optional_block()) { if (Parse_optional_block()) {
// restore old // restore old state
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - new_offset) & 0xffff; pseudopc_end(&buffer);
CPU_state.pc.flags = outer_flags;
} else { } else {
// not using a block is no longer allowed // not using a block is no longer allowed
Throw_error(Error_old_offset_assembly); Throw_error(Error_old_offset_assembly);