// insert byte until PC fits condition static enum eos_t PO_align(void) { intval_t and, equal, fill, test = CPU_pc.intval; // make sure PC is defined. if ((CPU_pc.flags & MVALUE_DEFINED) == 0) { Throw_error(exception_pc_undefined); CPU_pc.flags |= MVALUE_DEFINED; // do not complain again return SKIP_REMAINDER; } and = ALU_defined_int(); if (!Input_accept_comma()) Throw_error(exception_syntax); equal = ALU_defined_int(); if (Input_accept_comma()) fill = ALU_any_int(); else fill = CPU_now->default_align_value; while ((test++ & and) != equal) Output_8b(fill); return ENSURE_EOS; }
// start offset assembly static enum eos_t PO_pseudopc(void) { // future algo: remember outer memaddress and outer pseudopc int outer_state = uses_pseudo_pc; intval_t new_pc, outer_offset = current_offset; int outer_flags = CPU_pc.flags; // set new new_pc = ALU_defined_int(); // FIXME - allow for undefined pseudopc! current_offset = (current_offset + new_pc - CPU_pc.intval) & 0xffff; CPU_pc.intval = new_pc; CPU_pc.flags |= MVALUE_DEFINED; // FIXME - remove! uses_pseudo_pc = TRUE; // if there's a block, parse that and then restore old value! if (Parse_optional_block()) { // restore old uses_pseudo_pc = outer_state; CPU_pc.flags = outer_flags; CPU_pc.intval = (outer_offset + CPU_pc.intval - current_offset) & 0xffff; current_offset = outer_offset; // future algo: new outer pseudopc = (old outer pseudopc + (current memaddress - outer memaddress)) & 0xffff } else { Throw_first_pass_warning(Warning_old_offset_assembly); } return ENSURE_EOS; }
// Looping assembly ("!for"). Has to be re-entrant. static enum eos_t PO_for(void) {// Now GotByte = illegal char input_t loop_input, *outer_input; result_t loop_counter; intval_t maximum; char* loop_body;// pointer to loop's body block label_t* label; zone_t zone; int force_bit, loop_start;// line number of "!for" pseudo opcode if(Input_read_zone_and_keyword(&zone) == 0) // skips spaces before return(SKIP_REMAINDER); // Now GotByte = illegal char force_bit = Input_get_force_bit(); // skips spaces after label = Label_find(zone, force_bit); if(Input_accept_comma() == FALSE) { Throw_error(exception_syntax); return(SKIP_REMAINDER); } maximum = ALU_defined_int(); if(maximum < 0) Throw_serious_error("Loop count is negative."); if(GotByte != CHAR_SOB) Throw_serious_error(exception_no_left_brace); // remember line number of loop pseudo opcode loop_start = Input_now->line_number; // read loop body into DynaBuf and get copy loop_body = Input_skip_or_store_block(TRUE); // changes line number! // switching input makes us lose GotByte. But we know it's '}' anyway! // set up new input loop_input = *Input_now;// copy current input structure into new loop_input.source_is_ram = TRUE; // set new byte source // remember old input outer_input = Input_now; // activate new input // (not yet useable; pointer and line number are still missing) Input_now = &loop_input; // init counter loop_counter.flags = MVALUE_DEFINED | MVALUE_EXISTS; loop_counter.val.intval = 0; // if count == 0, skip loop if(maximum) { do { loop_counter.val.intval++;// increment counter Label_set_value(label, &loop_counter, TRUE); parse_ram_block(loop_start, loop_body); } while(loop_counter.val.intval < maximum); } else Label_set_value(label, &loop_counter, TRUE); // Free memory free(loop_body); // restore previous input: Input_now = outer_input; // GotByte of OuterInput would be '}' (if it would still exist) GetByte(); // fetch next byte return(ENSURE_EOS); }
// Conditional assembly ("!if"). Has to be re-entrant. static enum eos_t PO_if(void) {// Now GotByte = illegal char intval_t cond; cond = ALU_defined_int(); if(GotByte != CHAR_SOB) Throw_serious_error(exception_no_left_brace); parse_block_else_block(!!cond); return(ENSURE_EOS); }
// Reserve space by sending bytes of given value ("!fi" / "!fill" pseudo opcode) static enum eos_t PO_fill(void) { intval_t fill = FILLVALUE_FILL, size = ALU_defined_int(); if(Input_accept_comma()) fill = ALU_any_int(); while(size--) Output_8b(fill); return(ENSURE_EOS); }
// Check a condition expression static bool check_condition(loopcond_t* condition) { intval_t expression; // First, check whether there actually *is* a condition if(condition->body == NULL) return(TRUE); // non-existant conditions are always true // set up input for expression evaluation Input_now->line_number = condition->line; Input_now->src.ram_ptr = condition->body; GetByte(); // proceed with next char expression = ALU_defined_int(); if(GotByte) Throw_serious_error(exception_syntax); if(condition->type == ID_UNTIL) return(!expression); return(!!expression); }
// Start offset assembly static enum eos_t PO_pseudopc(void) { bool outer_state = uses_pseudo_pc; intval_t new_pc, outer_offset = current_offset; int outer_flags = CPU_pc.flags; // set new new_pc = ALU_defined_int(); current_offset = (current_offset + new_pc - CPU_pc.intval) & 0xffff; CPU_pc.intval = new_pc; CPU_pc.flags |= MVALUE_DEFINED | MVALUE_IS_ADDRESS; uses_pseudo_pc = TRUE; // If there's a block, parse that and then restore old value! if(Parse_optional_block()) { // restore old uses_pseudo_pc = outer_state; CPU_pc.flags = outer_flags; CPU_pc.intval = (outer_offset + CPU_pc.intval - current_offset) & 0xffff; current_offset = outer_offset; } else Throw_first_pass_warning(Warning_old_offset_assembly); return(ENSURE_EOS); }