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();
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_
// UNDEFINED: complain _seriously_
// 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?
{
struct expression expression;

View File

@ -122,4 +122,6 @@ void cputype_passinit(const struct cpu_type *cpu_type)
{
// handle cpu type (default is 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)
static void near_branch(int preoffset)
{
struct number pc;
struct number target;
intval_t offset = 0; // dummy value, to not throw more errors than necessary
vcpu_read_pc(&pc);
get_int_arg(&target, TRUE);
typesystem_want_addr(&target);
// FIXME - read pc via function call instead!
if (CPU_state.pc.flags & target.flags & NUMBER_IS_DEFINED) {
if (pc.flags & target.flags & NUMBER_IS_DEFINED) {
if ((target.val.intval | 0xffff) != 0xffff) {
not_in_bank(target.val.intval);
} 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
if (offset & 0x8000)
offset -= 0x10000;
@ -817,17 +818,18 @@ static void near_branch(int preoffset)
// helper function for relative addressing with 16-bit offset
static void far_branch(int preoffset)
{
struct number pc;
struct number target;
intval_t offset = 0; // dummy value, to not throw more errors than necessary
vcpu_read_pc(&pc);
get_int_arg(&target, TRUE);
typesystem_want_addr(&target);
// FIXME - read pc via function call instead!
if (CPU_state.pc.flags & target.flags & NUMBER_IS_DEFINED) {
if (pc.flags & target.flags & NUMBER_IS_DEFINED) {
if ((target.val.intval | 0xffff) != 0xffff) {
not_in_bank(target.val.intval);
} 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
}
}

View File

@ -496,8 +496,6 @@ void Output_passinit(void)
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.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.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 xy_are_long;
};
// buffer to hold outer state while parsing "pseudopc" block
struct pseudopc {
intval_t offset;
int flags;
};
// variables
@ -98,6 +103,10 @@ extern void vcpu_read_pc(struct number *target);
extern int vcpu_get_statement_size(void);
// adjust program counter (called at end of each statement)
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

View File

@ -540,18 +540,10 @@ static enum eos po_skip(void) // now GotByte = illegal char
// insert byte until PC fits condition
static enum eos po_align(void)
{
// FIXME - read cpu state via function call!
struct number andresult,
equalresult;
intval_t fill,
test = CPU_state.pc.val.intval;
// 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;
}
intval_t fill;
struct number pc;
// TODO:
// now: !align ANDVALUE, EQUALVALUE [,FILLVALUE]
@ -565,35 +557,37 @@ static enum eos po_align(void)
fill = ALU_any_int();
else
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);
return ENSURE_EOS;
}
static const char Error_old_offset_assembly[] =
"\"!pseudopc/!realpc\" is obsolete; use \"!pseudopc {}\" instead.";
// 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)
static enum eos po_pseudopc(void)
{
// FIXME - read pc using a function call!
struct number new_pc_result;
intval_t new_offset;
int outer_flags = CPU_state.pc.flags;
struct pseudopc buffer;
struct number new_pc;
// set new
ALU_defined_int(&new_pc_result); // 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!
// get new value
ALU_defined_int(&new_pc); // FIXME - allow for undefined! (complaining about non-addresses would be logical, but annoying)
// 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 (Parse_optional_block()) {
// restore old
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - new_offset) & 0xffff;
CPU_state.pc.flags = outer_flags;
// restore old state
pseudopc_end(&buffer);
} else {
// not using a block is no longer allowed
Throw_error(Error_old_offset_assembly);