diff options
Diffstat (limited to 'assemble.c')
-rw-r--r-- | assemble.c | 129 |
1 files changed, 113 insertions, 16 deletions
@@ -22,10 +22,19 @@ uint8_t get_rs(token *t, uint8_t inst, uint8_t dbg) { } } +uint8_t get_of(token *t, uint8_t dbg) { + if (t->id == TOK_OF) { + return t->type; + } else { + return 0xFF; + } +} + uint64_t get_val(token *t, uint64_t addr, uint8_t size, uint8_t dbg) { uint64_t value = 0; uint64_t tmp_val = 0; uint8_t type = EXPR_NONE; + uint8_t isstart = 1; do { if (t->id == TOK_EXPR) { type = t->type; @@ -40,9 +49,10 @@ uint64_t get_val(token *t, uint64_t addr, uint8_t size, uint8_t dbg) { case TOK_LABEL: tmp_val = (t->sym) ? t->sym->val : addr; t = t-> next; break; } switch (type) { - case EXPR_PLUS : value += tmp_val; break; - case EXPR_MINUS: value -= tmp_val; break; + case EXPR_PLUS : (isstart) ? (value = tmp_val) : (value += tmp_val); break; + case EXPR_MINUS: (isstart) ? (value = -tmp_val) : (value -= tmp_val); break; case EXPR_LOW : + value = tmp_val; switch (size) { default: case 2 : value &= 0xFFFFFFFF; break; @@ -51,6 +61,7 @@ uint64_t get_val(token *t, uint64_t addr, uint8_t size, uint8_t dbg) { } break; case EXPR_HIGH : + value = tmp_val; switch (size) { default: case 2 : value >>= 0x20; break; @@ -60,6 +71,7 @@ uint64_t get_val(token *t, uint64_t addr, uint8_t size, uint8_t dbg) { break; case EXPR_NONE : value = tmp_val; break; } + isstart = 0; } while (t && t->id == TOK_EXPR && isexpr(t->type, dbg)); return value; } @@ -166,6 +178,8 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, uint8_t tmp = 0; uint8_t prefix = 0; uint8_t rs = 0; + uint8_t of = 0; + uint8_t tmp_prefix = 0; for (; t; t = t->next) { if (t->id == TOK_OPCODE) { @@ -180,11 +194,24 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, if (t->next) { rs = get_rs(t->next, inst, dbg); t = (rs != 0xFF) ? t->next : t; + if (t->next && t->next->id == TOK_OF) { + of = get_of(t->next, dbg); + t = (of != 0xFF) ? t->next : t; + } } - prefix = (rs != 0xFF) ? ((rs << 4) | 3) : 0; - if (opcodes[inst][IMPL] != 0xFF && (!t->next || t->next->id == TOK_COMMENT)) { + if (rs != 0xFF || of != 0xFF) { + tmp_prefix = (rs != 0xFF) ? (rs << 0) : tmp_prefix; + tmp_prefix |= (of != 0xFF) ? (of << 2) : tmp_prefix; + } + prefix = (tmp_prefix) ? ((tmp_prefix << 4) | 3) : 0; + uint8_t isincdec = (inst == INC || inst == DEC); + uint8_t isimplied = (!t->next || (t->next->id == TOK_COMMENT)); + if (opcodes[inst][IMPL] != 0xFF && isimplied) { type = IMPL; } else { + if (opcodes[inst][REL] != 0xFF) { + type = REL; + } if (t->next) { t = t->next; } @@ -192,7 +219,7 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, } opcode = opcodes[inst][type]; /* Special case for TXS. */ - if (inst == TXS_MNE_ID) { + if (inst == TXS) { if (type == IMM) { rs = 1; } else { @@ -200,40 +227,87 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, opcode = opcodes[inst][IMM]; } } + uint64_t saveaddr = address; switch (type) { case IMPL: + if (prefix) { + if (isasm) { + addr[address] = prefix; + } + address++; + bc->progsize++; + } if (isasm) { addr[address] = opcode; } address++; bc->progsize++; break; + case REL: case IMM: + rs = (rs != 0xFF) ? rs : 0; + tmp = (1 << rs); + if (type == REL) { + uint64_t max_sign = 0; + uint8_t offset = 1; + uint64_t tmp_val; + tmp_val = val.u64; + offset += (prefix != 0); + tmp_val -= offset+tmp; + tmp_val -= address; + switch (rs) { + default: max_sign = (int8_t )(1 << 7); break; + case 1 : max_sign = (int16_t)(1 << 15); break; + case 2 : max_sign = (int32_t)(1 << 31); break; + case 3 : max_sign = (int64_t)((uint64_t)1 << 63); break; + } + if ((int64_t)tmp_val > ~(int64_t)max_sign || (int64_t)tmp_val < (int64_t)max_sign) { + offset += (!rs); + rs += (rs <= 3); + tmp = (1 << rs); + tmp_val = val.u64; + tmp_val -= offset+tmp; + tmp_val -= address; + prefix = ((rs << 4) | 3); + } + val.u64 = tmp_val; + } if (prefix) { if (isasm) { addr[address] = prefix; } address++; + bc->progsize++; } if (isasm) { addr[address] = opcode; } address++; bc->progsize++; - rs = (rs != 0xFF) ? rs : 0; - tmp = (1 << rs); if (isasm) { setreg(addr, +, address, val.u8, +, 0, tmp-1); } break; default: - opsize = (val.u64 > 0x00000000000000FF) ? 2 : opsize; - opsize = (val.u64 > 0x000000000000FFFF) ? 3 : opsize; - opsize = (val.u64 > 0x0000000000FFFFFF) ? 4 : opsize; - opsize = (val.u64 > 0x00000000FFFFFFFF) ? 5 : opsize; - opsize = (val.u64 > 0x000000FFFFFFFFFF) ? 6 : opsize; - opsize = (val.u64 > 0x0000FFFFFFFFFFFF) ? 7 : opsize; - opsize = (val.u64 > 0x00FFFFFFFFFFFFFF) ? 8 : opsize; + if (of != 0xFF) { + uint64_t shift = 1; + uint8_t i = 8; + uint8_t j = 1; + for (; i <= 64; i += 8, j++) { + if ((int64_t)val.u64 >= ~(int64_t)(shift << (i-1)) || (int64_t)val.u64 <= (int64_t)(shift << (i-1))) { + opsize = j; + break; + } + } + } else { + opsize = (val.u64 > 0x00000000000000FF) ? 2 : opsize; + opsize = (val.u64 > 0x000000000000FFFF) ? 3 : opsize; + opsize = (val.u64 > 0x0000000000FFFFFF) ? 4 : opsize; + opsize = (val.u64 > 0x00000000FFFFFFFF) ? 5 : opsize; + opsize = (val.u64 > 0x000000FFFFFFFFFF) ? 6 : opsize; + opsize = (val.u64 > 0x0000FFFFFFFFFFFF) ? 7 : opsize; + opsize = (val.u64 > 0x00FFFFFFFFFFFFFF) ? 8 : opsize; + } if (type == 0xFF) { switch (opsize-1) { case 0: case 2: case 5: case 3: type = ZM ; break; @@ -321,9 +395,32 @@ token *make_token(uint8_t id, uint8_t type, uint64_t value, char *str, symbol *s void assemble(line *ln, bytecount *bc, uint8_t dbg) { uint64_t address = 0; - for (; ln; ln = ln->next) { - address = parse_tokens(ln->tok, bc, 1, address, dbg); + line *l = ln; + for (int i = 0; i < 2; i++) { + l = ln; + for (; l; l = l->next) { + l->addr = address; + token *t = l->tok; + address = parse_tokens(t, bc, 0, address, dbg); + } + l = ln; + for (; l; l = l->next) { + address = l->addr; + token *t = l->tok; + for (; t; t = t->next) { + if (t->id == TOK_LABEL && t->sym->val != address) { + t->sym->val = l->addr; + } + } + } } + l = ln; + bc->progsize = 0; + bc->datasize = 0; + for (; l; l = l->next) { + address = parse_tokens(l->tok, bc, 1, address, dbg); + } + } static inline void free_tokens(token *t) { |