summaryrefslogtreecommitdiff
path: root/assemble.c
diff options
context:
space:
mode:
Diffstat (limited to 'assemble.c')
-rw-r--r--assemble.c129
1 files changed, 113 insertions, 16 deletions
diff --git a/assemble.c b/assemble.c
index 1ed4960..b8b377e 100644
--- a/assemble.c
+++ b/assemble.c
@@ -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) {