summaryrefslogtreecommitdiff
path: root/assemble.c
diff options
context:
space:
mode:
Diffstat (limited to 'assemble.c')
-rw-r--r--assemble.c261
1 files changed, 156 insertions, 105 deletions
diff --git a/assemble.c b/assemble.c
index 8d7eb85..297be87 100644
--- a/assemble.c
+++ b/assemble.c
@@ -1,5 +1,13 @@
#include "asmmon.h"
+#define AM_ADDR (AM_ZM | AM_ZMX | AM_ZMY | \
+ AM_IND | AM_INDX | AM_INDY | \
+ AM_ABS | AM_ABX | AM_ABY | \
+ AM_AIND | AM_AINDX | AM_AINDY | \
+ AM_INDX2 | AM_ZM2)
+
+static const uint64_t mem_size = 0x04000000; /* Size of address space. */
+
token *tok_global;
uint8_t isexpr(uint8_t type, uint8_t dbg) {
@@ -58,6 +66,38 @@ uint8_t get_ind(uint8_t mne, uint8_t am, uint8_t dbg) {
return base_idx + offset;
}
+uint8_t get_eind(uint8_t mne, uint8_t dbg) {
+ switch (mne) {
+ case DEC: return DEC_EIND;
+ case INC: return INC_EIND;
+ case STY: return STY_EIND;
+ case STA: return STA_EIND;
+ case STB: return STB_EIND;
+ case LDX: return LDX_EIND;
+ case STX: return STX_EIND;
+ case CPB: return CPB_EIND;
+ case CPX: return CPX_EIND;
+ case CPY: return CPY_EIND;
+ }
+ return 0xFF;
+}
+
+static void write_value(uint64_t value, uint64_t address, uint8_t size) {
+ if (address < mem_size) {
+ size = (size > 7) ? 7 : size;
+ #if 1
+ if (size < 7) {
+ uint64_t mask = (-(uint64_t)1 >> ((7 - size) * 8));
+ *(uint64_t *)(addr+address) = (*(uint64_t *)(addr+address) & ~mask) | (value & mask);
+ } else {
+ *(uint64_t *)(addr+address) = value;
+ }
+ #else
+ memcpy(addr+address, &value, size+1);
+ #endif
+ }
+}
+
uint64_t get_val(token *t, uint64_t addr, uint8_t size, uint8_t dbg) {
uint64_t value = 0;
uint64_t tmp_val = 0;
@@ -232,34 +272,14 @@ uint64_t handle_directive(token *t, bytecount *bc, uint8_t isasm, uint64_t addre
case TOK_LABEL:
val.u64 = get_val(t, tmpaddr, get_directivesize(type, dbg), dbg);
switch (type) {
- case DIR_QWORD: /* Falls through. */
- if (isasm) {
- addr[tmpaddr+7] = val.u8[7];
- addr[tmpaddr+6] = val.u8[6];
- addr[tmpaddr+5] = val.u8[5];
- addr[tmpaddr+4] = val.u8[4];
- }
- tmp += 4;
- case DIR_DWORD: /* Falls through. */
- if (isasm) {
- addr[tmpaddr+3] = val.u8[3];
- addr[tmpaddr+2] = val.u8[2];
- }
- tmp += 2;
- case DIR_WORD: /* Falls through. */
- if (isasm) {
- addr[tmpaddr+1] = val.u8[1];
- }
- tmp++;
- case DIR_BYTE:
- if (isasm) {
- addr[tmpaddr ] = val.u8[0];
- }
- tmp++;
- tmpaddr += tmp;
- bc->datasize += tmp;
- break;
+ case DIR_QWORD: tmp = 8; break;
+ case DIR_DWORD: tmp = 4; break;
+ case DIR_WORD : tmp = 2; break;
+ case DIR_BYTE : tmp = 1; break;
}
+ write_value(val.u64, tmpaddr, tmp-1);
+ tmpaddr += tmp;
+ bc->datasize += tmp;
if (t->next && t->next->id == TOK_EXPR && isexpr(t->next->type, dbg)) {
t = skip_expr(t, dbg);
}
@@ -303,21 +323,47 @@ uint64_t handle_directive(token *t, bytecount *bc, uint8_t isasm, uint64_t addre
return tmpaddr;
}
+static uint8_t write_inst(uint8_t prefix, uint8_t ext_prefix, uint8_t opcode, uint64_t value, uint64_t address, uint8_t size, uint8_t isasm, uint8_t dbg) {
+ uint8_t inst_size = 0;
+ union reg ins;
+ if (prefix & 3) {
+ ins.u8[inst_size++] = prefix;
+ }
+ if ((ext_prefix & 0x0D) == 0x0D) {
+ ins.u8[inst_size++] = ext_prefix;
+ }
+ ins.u8[inst_size++] = opcode;
+ if (isasm) {
+ write_value(ins.u64, address, inst_size-1);
+ if (size) {
+ write_value(value, address+inst_size, size-1);
+ }
+ }
+ inst_size += size;
+ return inst_size;
+}
+
uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, uint8_t dbg) {
union reg val;
uint8_t opsize;
+ uint8_t id;
uint8_t instr;
uint8_t opcode;
+ uint8_t ext_prefix = 0;
uint8_t type;
- uint16_t am = 0;
+ uint32_t am = 0;
uint8_t tmp = 0;
uint8_t prefix = 0;
uint8_t rs = 0;
uint8_t of = 0;
uint8_t tmp_prefix = 0;
+ uint8_t inst_size = 0;
+ val.u64 = 0;
+ instruction ins;
for (; t; t = t->next) {
- if (t->id == TOK_OPCODE) {
+ if (t->id == TOK_OPCODE || t->id == TOK_EXTOP) {
+ id = t->id;
instr = t->byte;
type = t->type;
} else {
@@ -340,51 +386,47 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address,
}
prefix = (tmp_prefix) ? ((tmp_prefix << 4) | 3) : 0;
uint8_t isincdec = (instr == INC || instr == DEC);
- uint8_t isimplied = (!t->next || (t->next->id == TOK_COMMENT));
- am = inst[instr].am;
+ uint8_t isimplied = ((!t->next || (t->next->id == TOK_COMMENT)) && type == 0xFF);
+ ins = (id == TOK_OPCODE) ? inst[instr] : ext_inst[instr];
+ am = ins.am;
+ if (id == TOK_EXTOP || (id == TOK_OPCODE && type == EIND)) {
+ ext_prefix = 0x0D;
+ }
if ((am & AM_IMPL) && isimplied) {
type = IMPL;
} else {
- if (inst[instr].am & AM_REL) {
+ if (ins.am & AM_REL) {
type = REL;
}
if (t->next) {
t = t->next;
}
- val.u64 = get_val(t, address, (rs != 0xFF) ? rs : 0, dbg);
- }
- /* Special case for TXS. */
- if (instr == TXS) {
- if (type == IMM) {
- rs = 1;
- } else {
- type = IMPL;
+ if (type != BREG && type != EIND) {
+ val.u64 = get_val(t, address, (rs != 0xFF) ? rs : 0, dbg);
}
}
- opcode = inst[instr].op;
+ opcode = ins.op;
uint64_t saveaddr = address;
uint64_t max_val = 0;
uint8_t i = 0;
uint8_t j = 1;
+ uint8_t type2 = 0xFF;
switch (type) {
case BREG:
case IMPL:
- if (instr == CPS) {
+ case EIND:
+ if (id == TOK_OPCODE && instr == CPS) {
rs = 0;
}
- if ((am & (AM_IMPL|AM_BREG))) {
- if ((am & AM_IMPL) && (prefix)) {
- if (isasm) {
- addr[address] = prefix;
+ if ((am & (AM_IMPL|AM_BREG|AM_EIND|AM_EIND2))) {
+ if ((type == EIND) && (am & AM_EIND|AM_EIND2)) {
+ int eind_type = ((am & AM_EIND2) != 0);
+ switch (eind_type) {
+ case 0: opcode = (id == TOK_EXTOP) ? opcode+0x14 : opcode+0x10; break;
+ case 1: opcode = (id == TOK_EXTOP) ? opcode+0x01 : eind_base_ops[get_eind(instr, dbg)]; break;
}
- address++;
- bc->progsize++;
}
- if (isasm) {
- addr[address] = (am & AM_BREG) ? opcode+0x14 : opcode;
- }
- address++;
- bc->progsize++;
+ opcode = (am & AM_BREG) ? opcode+0x14 : opcode;
}
break;
case REL:
@@ -417,21 +459,6 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address,
}
val.u64 = tmp_val;
}
- if (prefix) {
- if (isasm) {
- addr[address] = prefix;
- }
- address++;
- bc->progsize++;
- }
- if (isasm) {
- addr[address] = opcode;
- }
- address++;
- bc->progsize++;
- if (isasm) {
- setreg(addr, +, address, val.u8, +, 0, tmp-1);
- }
}
break;
default:
@@ -453,14 +480,32 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address,
}
}
}
- if (type == 0xFF) {
+ type2 = type;
+ if (type == 0xFF || (id == TOK_EXTOP && type2 != 0xFF)) {
switch (opsize-1) {
case 0: case 2: case 5: case 3: type = ZM ; break;
case 1: case 4: case 6: case 7: type = ABS; break;
}
}
+ switch (type2) {
+ case ZMX : type = (type == ABS) ? ABSX : type2; break;
+ case ZMY : type = (type == ABS) ? ABSY : type2; break;
+ case IND : type = (type == ABS) ? AIND : type2; break;
+ case INDX: type = (type == ABS) ? AINDX : type2; break;
+ case INDY: type = (type == ABS) ? AINDY : type2; break;
+ }
if (opsize) {
- if (type != ABS) {
+ uint8_t is_abs = 0;
+ switch (type) {
+ case ABS :
+ case ABSX :
+ case ABSY :
+ case AIND :
+ case AINDX:
+ case AINDY: is_abs = 1; break;
+
+ }
+ if (!is_abs || (type2 != 0xFF && type == type2)) {
switch (opsize) {
case 2: opsize = 3; break;
case 5: opsize = 6; break;
@@ -468,7 +513,7 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address,
}
prefix |= amp[opsize-1];
}
- if (am & (AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_INDX2|AM_ZM2)) {
+ if (am & AM_ADDR) {
switch (type) {
case ZM:
if (am & AM_ZM) {
@@ -479,7 +524,7 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address,
break;
case ZMX:
if (am & AM_ZMX) {
- opcode += 0x06;
+ opcode += (id == TOK_OPCODE) ? 0x06 : 0x54;
}
break;
case ZMY:
@@ -487,54 +532,59 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address,
opcode += 0x14;
}
break;
- case ABS:
- if (am & AM_ABS) {
- opcode += 0x10;
- }
- break;
case INDX:
if (am & AM_INDX) {
- opcode += 0x16;
+ opcode += (id == TOK_OPCODE) ? 0x16 : 0x94;
break;
}
/* Falls Through. */
case IND:
case INDY:
- if (am & (AM_IND|AM_INDY|AM_INDX2)) {
+ if ((id == TOK_OPCODE) && (am & (AM_IND|AM_INDY|AM_INDX2))) {
opcode = ind_ops[get_ind(instr, type, dbg)];
+ } else {
+ opcode += (type == IND) ? 0x44 : 0x84;
}
break;
- }
- if (prefix) {
- if (isasm) {
- addr[address] = prefix;
- }
- address++;
- bc->progsize++;
- }
- if (isasm) {
- addr[address] = opcode;
- }
- address++;
- bc->progsize++;
- if (isasm) {
- switch (opsize-1) {
- case 7: addr[address+7] = val.u8[7];
- case 6: addr[address+6] = val.u8[6];
- case 5: addr[address+5] = val.u8[5];
- case 4: addr[address+4] = val.u8[4];
- case 3: addr[address+3] = val.u8[3];
- case 2: addr[address+2] = val.u8[2];
- case 1: addr[address+1] = val.u8[1];
- case 0: addr[address ] = val.u8[0];
- }
+ case ABS:
+ if (am & AM_ABS) {
+ opcode += 0x10;
+ }
+ break;
+ case ABSX:
+ if (am & AM_ABX) {
+ opcode += 0x50;
+ }
+ break;
+ case ABSY:
+ if (am & AM_ABY) {
+ opcode += 0x00;
+ }
+ break;
+ case AIND:
+ if (am & AM_AIND) {
+ opcode += 0x40;
+ }
+ break;
+ case AINDX:
+ if (am & AM_AINDX) {
+ opcode += 0x90;
+ }
+ break;
+ case AINDY:
+ if (am & AM_AINDY) {
+ opcode += 0x80;
+ }
+ break;
+
}
tmp = opsize;
}
break;
}
- address += tmp;
- bc->progsize += tmp;
+ inst_size = write_inst(prefix, ext_prefix, opcode, val.u64, address, tmp, isasm, dbg);
+ address += inst_size;
+ bc->progsize += inst_size;
}
return address;
}
@@ -554,6 +604,7 @@ uint64_t parse_tokens(token *t, line **l, bytecount *bc, uint8_t isasm, uint64_t
case DIR_QWORD: address = handle_directive(t, bc, isasm, address, dbg); break;
}
break;
+ case TOK_EXTOP :
case TOK_OPCODE: address = handle_opcode(t, bc, isasm, address, dbg); break;
case TOK_COMMENT: break;
}