diff options
Diffstat (limited to 'assemble.c')
-rw-r--r-- | assemble.c | 261 |
1 files changed, 156 insertions, 105 deletions
@@ -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; } |