Update to v103r31 release.

byuu says:

Changelog:

  - gba/cpu: slight speedup to CPU::step()
  - processor/arm7tdmi: fixed about ten bugs, ST018 and GBA games are
    now playable once again
  - processor/arm: removed core from codebase
  - processor/v30mz: code cleanup (renamed functions; updated
    instruction() for consistency with other cores)

It turns out on my much faster system, the new ARM7TDMI core is very
slightly slower than the old one (by about 2% or so FPS.) But the
CPU::step() improvement basically made it a wash.

So yeah, I'm in really serious trouble with how slow my GBA core is now.
Sigh.

As for higan/processor ... this concludes the first phase of major
cleanups and rewrites.

There will always be work to do, and I have two more phases in mind.

One is that a lot of the instruction disassemblers are very old. One
even uses sprintf still. I'd like to modernize them all. Also, the
ARM7TDMI core (and the ARM core before it) can't really disassemble
because the PC address used for instruction execution is not known prior
to calling instruction(), due to pipeline reload fetches that may occur
inside of said function. I had a nasty hack for debugging the new core,
but I'd like to come up with a clean way to allow tracing the new
ARM7TDMI core.

Another is that I'd still like to rename a lot of instruction function
names in various cores to be more descriptive. I really liked how the
LR35902 core came out there, and would like to get that level of detail
in with the other cores as well.
This commit is contained in:
Tim Allen 2017-08-10 21:26:02 +10:00
parent 1067566834
commit 406b6a61a5
36 changed files with 631 additions and 3144 deletions

View File

@ -12,7 +12,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "103.30";
static const string Version = "103.31";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -33,10 +33,8 @@ auto CPU::main() -> void {
}
auto CPU::step(uint clocks) -> void {
for(auto _ : range(clocks)) {
for(auto& dma : this->dma) {
if(dma.waiting) dma.waiting--;
}
for(auto& dma : this->dma) {
dma.waiting = max(0, dma.waiting - (int)clocks);
}
if(!context.dmaActive) {

View File

@ -73,7 +73,7 @@ struct CPU : Processor::ARM7TDMI, Thread, IO {
uint2 id;
boolean active;
natural waiting;
integer waiting;
uint2 targetMode;
uint2 sourceMode;

View File

@ -1,6 +1,5 @@
processors := $(call unique,$(processors))
objects += $(if $(findstring arm,$(processors)),processor-arm)
objects += $(if $(findstring arm7tdmi,$(processors)),processor-arm7tdmi)
objects += $(if $(findstring gsu,$(processors)),processor-gsu)
objects += $(if $(findstring hg51b,$(processors)),processor-hg51b)
@ -14,7 +13,6 @@ objects += $(if $(findstring v30mz,$(processors)),processor-v30mz)
objects += $(if $(findstring wdc65816,$(processors)),processor-wdc65816)
objects += $(if $(findstring z80,$(processors)),processor-z80)
obj/processor-arm.o: processor/arm/arm.cpp $(call rwildcard,processor/arm/)
obj/processor-arm7tdmi.o: processor/arm7tdmi/arm7tdmi.cpp $(call rwildcard,processor/arm7tdmi/)
obj/processor-gsu.o: processor/gsu/gsu.cpp $(call rwildcard,processor/gsu/)
obj/processor-hg51b.o: processor/hg51b/hg51b.cpp $(call rwildcard,processor/hg51b/)

View File

@ -1,103 +0,0 @@
auto ARM::condition(uint4 condition) -> bool {
switch(condition) {
case 0: return cpsr().z == 1; //EQ (equal)
case 1: return cpsr().z == 0; //NE (not equal)
case 2: return cpsr().c == 1; //CS (carry set)
case 3: return cpsr().c == 0; //CC (carry clear)
case 4: return cpsr().n == 1; //MI (negative)
case 5: return cpsr().n == 0; //PL (positive)
case 6: return cpsr().v == 1; //VS (overflow)
case 7: return cpsr().v == 0; //VC (no overflow)
case 8: return cpsr().c == 1 && cpsr().z == 0; //HI (unsigned higher)
case 9: return cpsr().c == 0 || cpsr().z == 1; //LS (unsigned lower or same)
case 10: return cpsr().n == cpsr().v; //GE (signed greater than or equal)
case 11: return cpsr().n != cpsr().v; //LT (signed less than)
case 12: return cpsr().z == 0 && cpsr().n == cpsr().v; //GT (signed greater than)
case 13: return cpsr().z == 1 || cpsr().n != cpsr().v; //LE (signed less than or equal)
case 14: return true; //AL (always)
case 15: return false; //NV (never)
}
}
auto ARM::bit(uint32 result) -> uint32 {
if(cpsr().t || instruction() & (1 << 20)) {
cpsr().n = result >> 31;
cpsr().z = result == 0;
cpsr().c = carryout();
}
return result;
}
auto ARM::add(uint32 source, uint32 modify, bool carry) -> uint32 {
uint32 result = source + modify + carry;
if(cpsr().t || instruction() & (1 << 20)) {
uint32 overflow = ~(source ^ modify) & (source ^ result);
cpsr().n = result >> 31;
cpsr().z = result == 0;
cpsr().c = (1u << 31) & (overflow ^ source ^ modify ^ result);
cpsr().v = (1u << 31) & (overflow);
}
return result;
}
auto ARM::sub(uint32 source, uint32 modify, bool carry) -> uint32 {
return add(source, ~modify, carry);
}
auto ARM::mul(uint32 product, uint32 multiplicand, uint32 multiplier) -> uint32 {
idle();
if((multiplier & 0xffffff00) != 0x00000000 && (multiplier & 0xffffff00) != 0xffffff00) idle();
if((multiplier & 0xffff0000) != 0x00000000 && (multiplier & 0xffff0000) != 0xffff0000) idle();
if((multiplier & 0xff000000) != 0x00000000 && (multiplier & 0xff000000) != 0xff000000) idle();
product += multiplicand * multiplier;
if(cpsr().t || instruction() & (1 << 20)) {
cpsr().n = product >> 31;
cpsr().z = product == 0;
}
return product;
}
auto ARM::lsl(uint32 source, uint8 shift) -> uint32 {
carryout() = cpsr().c;
if(shift == 0) return source;
carryout() = shift > 32 ? 0 : source & (1 << 32 - shift);
source = shift > 31 ? 0 : source << shift;
return source;
}
auto ARM::lsr(uint32 source, uint8 shift) -> uint32 {
carryout() = cpsr().c;
if(shift == 0) return source;
carryout() = shift > 32 ? 0 : source & (1 << shift - 1);
source = shift > 31 ? 0 : source >> shift;
return source;
}
auto ARM::asr(uint32 source, uint8 shift) -> uint32 {
carryout() = cpsr().c;
if(shift == 0) return source;
carryout() = shift > 32 ? source & (1 << 31) : source & (1 << shift - 1);
source = shift > 31 ? (int32)source >> 31 : (int32)source >> shift;
return source;
}
auto ARM::ror(uint32 source, uint8 shift) -> uint32 {
carryout() = cpsr().c;
if(shift == 0) return source;
if(shift &= 31)
source = source << 32 - shift | source >> shift;
carryout() = source & (1 << 31);
return source;
}
auto ARM::rrx(uint32 source) -> uint32 {
carryout() = source & 1;
return (cpsr().c << 31) | (source >> 1);
}

View File

@ -1,90 +0,0 @@
#include <processor/processor.hpp>
#include "arm.hpp"
namespace Processor {
#include "registers.cpp"
#include "algorithms.cpp"
#include "instructions-arm.cpp"
#include "instructions-thumb.cpp"
#include "step.cpp"
#include "disassembler.cpp"
#include "serialization.cpp"
auto ARM::power() -> void {
processor.power();
interrupt(Processor::Mode::SVC, 0x00);
pipeline.reload = true;
pipeline.nonsequential = true;
crash = false;
r(15).modify = [&] {
pipeline.reload = true;
};
trace = false;
instructions = 0;
}
auto ARM::exec() -> void {
cpsr().t ? stepTHUMB() : stepARM();
}
auto ARM::idle() -> void {
pipeline.nonsequential = true;
return sleep();
}
auto ARM::read(uint mode, uint32 addr) -> uint32 {
return get(mode, addr);
}
auto ARM::load(uint mode, uint32 addr) -> uint32 {
pipeline.nonsequential = true;
uint32 word = get(Load | mode, addr);
if(mode & Half) {
addr &= 1;
word = mode & Signed ? (int16_t)word : (uint16_t)word;
}
if(mode & Byte) {
addr &= 0;
word = mode & Signed ? (int8_t)word : (uint8_t)word;
}
if(mode & Signed) {
word = asr(word, 8 * (addr & 3));
} else {
word = ror(word, 8 * (addr & 3));
}
idle();
return word;
}
auto ARM::write(uint mode, uint32 addr, uint32 word) -> void {
pipeline.nonsequential = true;
return set(mode, addr, word);
}
auto ARM::store(uint mode, uint32 addr, uint32 word) -> void {
pipeline.nonsequential = true;
if(mode & Half) { word &= 0xffff; word |= word << 16; }
if(mode & Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
return set(Store | mode, addr, word);
}
auto ARM::interrupt(Processor::Mode mode, uint32 addr) -> void {
auto psr = cpsr();
processor.setMode(mode);
spsr() = psr;
cpsr().i = 1;
cpsr().f |= mode == Processor::Mode::FIQ;
cpsr().t = 0;
r(14) = pipeline.decode.address;
r(15) = addr;
}
}

View File

@ -1,66 +0,0 @@
#pragma once
namespace Processor {
//Supported Models:
//* ARMv3 (ARM60)
//* ARMv4T (ARM7TDMI)
struct ARM {
enum : uint { //mode flags for bus_read, bus_write:
Nonsequential = 1, //N cycle
Sequential = 2, //S cycle
Prefetch = 4, //instruction fetch (eligible for prefetch)
Byte = 8, //8-bit access
Half = 16, //16-bit access
Word = 32, //32-bit access
Load = 64, //load operation
Store = 128, //store operation
Signed = 256, //sign extend
};
#include "registers.hpp"
#include "instructions-arm.hpp"
#include "instructions-thumb.hpp"
#include "disassembler.hpp"
virtual auto step(uint clocks) -> void = 0;
virtual auto sleep() -> void = 0;
virtual auto get(uint mode, uint32 addr) -> uint32 = 0;
virtual auto set(uint mode, uint32 addr, uint32 word) -> void = 0;
//arm.cpp
auto power() -> void;
auto exec() -> void;
auto idle() -> void;
auto read(uint mode, uint32 addr) -> uint32;
auto load(uint mode, uint32 addr) -> uint32;
auto write(uint mode, uint32 addr, uint32 word) -> void;
auto store(uint mode, uint32 addr, uint32 word) -> void;
auto interrupt(Processor::Mode mode, uint32 addr) -> void;
//algorithms.cpp
auto condition(uint4 condition) -> bool;
auto bit(uint32 result) -> uint32;
auto add(uint32 source, uint32 modify, bool carry) -> uint32;
auto sub(uint32 source, uint32 modify, bool carry) -> uint32;
auto mul(uint32 product, uint32 multiplicand, uint32 multiplier) -> uint32;
auto lsl(uint32 source, uint8 shift) -> uint32;
auto lsr(uint32 source, uint8 shift) -> uint32;
auto asr(uint32 source, uint8 shift) -> uint32;
auto ror(uint32 source, uint8 shift) -> uint32;
auto rrx(uint32 source) -> uint32;
//step.cpp
auto stepPipeline() -> void;
auto stepARM() -> void;
auto stepTHUMB() -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
bool trace = false;
uintmax_t instructions = 0;
};
}

View File

@ -1,777 +0,0 @@
auto ARM::disassembleInstructionARM(uint32 pc) -> string {
static string conditions[] = {
"eq", "ne", "cs", "cc",
"mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt",
"gt", "le", "", "nv",
};
static string opcodes[] = {
"and", "eor", "sub", "rsb",
"add", "adc", "sbc", "rsc",
"tst", "teq", "cmp", "cmn",
"orr", "mov", "bic", "mvn",
};
static string registers[] = {
"r0", "r1", "r2", "r3",
"r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11",
"r12", "sp", "lr", "pc",
};
static string indices[] = {
"da", "ia", "db", "ib",
};
static auto isMove = [](uint4 opcode) { return opcode == 13 || opcode == 15; };
static auto isComp = [](uint4 opcode) { return opcode >= 8 && opcode <= 11; };
static auto isMath = [](uint4 opcode) { return opcode < 8 || opcode == 12 || opcode == 14; };
string output{hex(pc, 8L), " "};
uint32 instruction = read(Word | Nonsequential, pc & ~3);
output.append(hex(instruction, 8L), " ");
//multiply()
//mul{condition}{s} rd,rm,rs
//mla{condition}{s} rd,rm,rs,rn
if((instruction & 0x0fc000f0) == 0x00000090) {
uint4 condition = instruction >> 28;
uint1 accumulate = instruction >> 21;
uint1 save = instruction >> 20;
uint4 rd = instruction >> 16;
uint4 rn = instruction >> 12;
uint4 rs = instruction >> 8;
uint4 rm = instruction;
output.append(accumulate ? "mla" : "mul", conditions[condition], save ? "s " : " ");
output.append(registers[rd], ",", registers[rm], ",", registers[rs]);
if(accumulate) output.append(",", registers[rn]);
return output;
}
//multiply_long()
//(u,s)mull{condition}{s} rdlo,rdhi,rm,rs
//(u,s)mlal{condition}{s} rdlo,rdhi,rm,rs
if((instruction & 0x0f8000f0) == 0x00800090) {
uint4 condition = instruction >> 28;
uint1 signextend = instruction >> 22;
uint1 accumulate = instruction >> 21;
uint1 save = instruction >> 20;
uint4 rdhi = instruction >> 16;
uint4 rdlo = instruction >> 12;
uint4 rs = instruction >> 8;
uint4 rm = instruction;
output.append(signextend ? "s" : "u", accumulate ? "mlal" : "mull", conditions[condition], save ? "s " : " ");
output.append(registers[rdlo], ",", registers[rdhi], ",", registers[rm], ",", registers[rs]);
return output;
}
//memory_swap()
//swp{condition}{b} rd,rm,[rn]
if((instruction & 0x0fb000f0) == 0x01000090) {
uint4 condition = instruction >> 28;
uint1 byte = instruction >> 22;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint4 rm = instruction;
output.append("swp", conditions[condition], byte ? "b " : " ");
output.append(registers[rd], ",", registers[rm], ",[", registers[rn], "]");
return output;
}
//move_half_register()
//(ldr,str){condition}h rd,[rn,rm]{!}
//(ldr,str){condition}h rd,[rn],rm
if((instruction & 0x0e4000f0) == 0x000000b0) {
uint4 condition = instruction >> 28;
uint1 pre = instruction >> 24;
uint1 up = instruction >> 23;
uint1 writeback = instruction >> 21;
uint1 load = instruction >> 20;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint4 rm = instruction;
output.append(load ? "ldr" : "str", conditions[condition], "h ");
output.append(registers[rd], ",[", registers[rn]);
if(pre == 0) output.append("]");
output.append(",", up ? "+" : "-", registers[rm]);
if(pre == 1) output.append("]");
if(pre == 0 || writeback == 1) output.append("!");
return output;
}
//move_half_immediate()
//(ldr,str){condition}h rd,[rd{,+/-offset}]{!}
//(ldr,str){condition}h rd,[rn]{,+/-offset}
if((instruction & 0x0e4000f0) == 0x004000b0) {
uint4 condition = instruction >> 28;
uint1 pre = instruction >> 24;
uint1 up = instruction >> 23;
uint1 writeback = instruction >> 21;
uint1 load = instruction >> 20;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint4 ih = instruction >> 8;
uint4 il = instruction >> 0;
uint8 immediate = (ih << 4) + (il << 0);
output.append(load ? "ldr" : "str", conditions[condition], "h ");
output.append(registers[rd], ",[", registers[rn]);
if(pre == 0) output.append("]");
if(immediate) output.append(",", up ? "+" : "-", "0x", hex(immediate, 2L));
if(pre == 1) output.append("]");
if(pre == 0 || writeback == 1) output.append("!");
if(rn == 15) output.append(" =0x", hex(read(Half | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), 4L));
return output;
}
//load_register()
//ldr{condition}s(h,b) rd,[rn,rm]{!}
//ldr{condition}s(h,b) rd,[rn],rm
if((instruction & 0x0e5000d0) == 0x001000d0) {
uint4 condition = instruction >> 28;
uint1 pre = instruction >> 24;
uint1 up = instruction >> 23;
uint1 writeback = instruction >> 21;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint1 half = instruction >> 5;
uint4 rm = instruction;
output.append("ldr", conditions[condition], half ? "sh " : "sb ");
output.append(registers[rd], ",[", registers[rn]);
if(pre == 0) output.append("]");
output.append(",", up ? "+" : "-", registers[rm]);
if(pre == 1) output.append("]");
if(pre == 0 || writeback == 1) output.append("!");
return output;
}
//load_immediate()
//ldr{condition}s(h,b) rd,[rn{,+/-offset}]{!}
//ldr{condition}s(h,b) rd,[rn]{,+/-offset}
if((instruction & 0x0e5000b0) == 0x005000b0) {
uint4 condition = instruction >> 28;
uint1 pre = instruction >> 24;
uint1 up = instruction >> 23;
uint1 writeback = instruction >> 21;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint4 ih = instruction >> 8;
uint1 half = instruction >> 5;
uint4 il = instruction;
uint8 immediate = (ih << 4) + (il << 0);
output.append("ldr", conditions[condition], half ? "sh " : "sb ");
output.append(registers[rd], ",[", registers[rn]);
if(pre == 0) output.append("]");
if(immediate) output.append(",", up ? "+" : "-", "0x", hex(immediate, 2L));
if(pre == 1) output.append("]");
if(pre == 0 || writeback == 1) output.append("!");
if(rn == 15 && half == 1) output.append(" =0x", hex(read(Half | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), 4L));
if(rn == 15 && half == 0) output.append(" =0x", hex(read(Byte | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), 2L));
return output;
}
//move_to_register_from_status()
//mrs{condition} rd,(c,s)psr
if((instruction & 0x0fb000f0) == 0x01000000) {
uint4 condition = instruction >> 28;
uint1 psr = instruction >> 22;
uint4 rd = instruction >> 12;
output.append("mrs", conditions[condition], " ");
output.append(registers[rd], ",", psr ? "spsr" : "cpsr");
return output;
}
//move_to_status_from_register()
//msr{condition} (c,s)psr:{fields},rm
if((instruction & 0x0fb000f0) == 0x01200000) {
uint4 condition = instruction >> 28;
uint1 psr = instruction >> 22;
uint4 field = instruction >> 16;
uint4 rm = instruction;
output.append("msr", conditions[condition], " ");
output.append(psr ? "spsr:" : "cpsr:");
output.append(
field & 1 ? "c" : "",
field & 2 ? "x" : "",
field & 4 ? "s" : "",
field & 8 ? "f" : ""
);
output.append(",", registers[rm]);
return output;
}
//branch_exchange_register()
//bx{condition} rm
if((instruction & 0x0ff000f0) == 0x01200010) {
uint4 condition = instruction >> 28;
uint4 rm = instruction;
output.append("bx", conditions[condition], " ");
output.append(registers[rm]);
return output;
}
//move_to_status_from_immediate()
//msr{condition} (c,s)psr:{fields},#immediate
if((instruction & 0x0fb00000) == 0x03200000) {
uint4 condition = instruction >> 28;
uint1 psr = instruction >> 22;
uint4 field = instruction >> 16;
uint4 rotate = instruction >> 8;
uint8 immediate = instruction;
uint32 rm = (immediate >> (rotate * 2)) | (immediate << (32 - (rotate * 2)));
output.append("msr", conditions[condition], " ");
output.append(psr ? "spsr:" : "cpsr:");
output.append(
field & 1 ? "c" : "",
field & 2 ? "x" : "",
field & 4 ? "s" : "",
field & 8 ? "f" : ""
);
output.append(",#0x", hex(immediate, 8L));
return output;
}
//data_immediate_shift()
//{opcode}{condition}{s} rd,rm {shift} #immediate
//{opcode}{condition} rn,rm {shift} #immediate
//{opcode}{condition}{s} rd,rn,rm {shift} #immediate
if((instruction & 0x0e000010) == 0x00000000) {
uint4 condition = instruction >> 28;
uint4 opcode = instruction >> 21;
uint1 save = instruction >> 20;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint5 shift = instruction >> 7;
uint2 op = instruction >> 5;
uint4 rm = instruction;
output.append(opcodes[opcode], conditions[condition]);
if(isMove(opcode)) output.append(save ? "s " : " ", registers[rd]);
if(isComp(opcode)) output.append(" ", registers[rn]);
if(isMath(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
output.append(",", registers[rm]);
if(op == 0 && shift != 0) output.append(" lsl #", shift);
if(op == 1) output.append(" lsr #", shift == 0 ? 32u : (uint)shift);
if(op == 2) output.append(" asr #", shift == 0 ? 32u : (uint)shift);
if(op == 3 && shift != 0) output.append(" ror #", shift);
if(op == 3 && shift == 0) output.append(" rrx");
return output;
}
//data_register_shift()
//{opcode}{condition}{s} rd,rm {shift} rs
//{opcode}{condition} rn,rm {shift} rs
//{opcode}{condition}{s} rd,rn,rm {shift} rs
if((instruction & 0x0e000090) == 0x00000010) {
uint4 condition = instruction >> 28;
uint4 opcode = instruction >> 21;
uint1 save = instruction >> 20;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint4 rs = instruction >> 8;
uint2 mode = instruction >> 5;
uint4 rm = instruction;
output.append(opcodes[opcode], conditions[condition]);
if(isMove(opcode)) output.append(save ? "s " : " ", registers[rd], ",");
if(isComp(opcode)) output.append(" ", registers[rn], ",");
if(isMath(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn], ",");
output.append(registers[rm]);
if(mode == 0) output.append(" lsl ");
if(mode == 1) output.append(" lsr ");
if(mode == 2) output.append(" asr ");
if(mode == 3) output.append(" ror ");
output.append(registers[rs]);
return output;
}
//data_immediate()
//{opcode}{condition}{s} rd,#immediate
//{opcode}{condition} rn,#immediate
//{opcode}{condition}{s} rd,rn,#immediate
if((instruction & 0x0e000000) == 0x02000000) {
uint4 condition = instruction >> 28;
uint4 opcode = instruction >> 21;
uint1 save = instruction >> 20;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint4 rotate = instruction >> 8;
uint8 immediate = instruction;
uint32 rm = (immediate >> (rotate << 1)) | (immediate << (32 - (rotate << 1)));
output.append(opcodes[opcode], conditions[condition]);
if(isMove(opcode)) output.append(save ? "s " : " ", registers[rd]);
if(isComp(opcode)) output.append(" ", registers[rn]);
if(isMath(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
output.append(",#0x", hex(rm, 8L));
return output;
}
//move_immediate_offset()
//(ldr,str){condition}{b} rd,[rn{,+/-offset}]{!}
//(ldr,str){condition}{b} rd,[rn]{,+/-offset}
if((instruction & 0x0e000000) == 0x04000000) {
uint4 condition = instruction >> 28;
uint1 pre = instruction >> 24;
uint1 up = instruction >> 23;
uint1 byte = instruction >> 22;
uint1 writeback = instruction >> 21;
uint1 load = instruction >> 20;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint12 immediate = instruction;
output.append(load ? "ldr" : "str", conditions[condition], byte ? "b " : " ");
output.append(registers[rd], ",[", registers[rn]);
if(pre == 0) output.append("]");
if(immediate) output.append(",", up ? "+" : "-", "0x", hex(immediate, 3L));
if(pre == 1) output.append("]");
if(pre == 0 || writeback == 1) output.append("!");
if(rn == 15) output.append(" =0x", hex(read((byte ? Byte : Word) | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), byte ? 2L : 4L));
return output;
}
//move_register_offset()
//(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{1}
//(ldr,str){condition}{b} rd,[rn],rm {mode} #immediate
if((instruction & 0x0e000010) == 0x06000000) {
uint4 condition = instruction >> 28;
uint1 pre = instruction >> 24;
uint1 up = instruction >> 23;
uint1 byte = instruction >> 22;
uint1 writeback = instruction >> 21;
uint1 load = instruction >> 20;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint5 shift = instruction >> 7;
uint2 mode = instruction >> 5;
uint4 rm = instruction;
output.append(load ? "ldr" : "str", conditions[condition], byte ? "b " : " ");
output.append(registers[rd], ",[", registers[rn]);
if(pre == 0) output.append("]");
output.append(",", up ? "+" : "-", registers[rm]);
if(mode == 0 && shift != 0) output.append(" lsl #", shift);
if(mode == 1) output.append(" lsr #", shift == 0 ? 32u : (uint)shift);
if(mode == 2) output.append(" asr #", shift == 0 ? 32u : (uint)shift);
if(mode == 3 && shift != 0) output.append(" ror #", shift);
if(mode == 3 && shift == 0) output.append(" rrx");
if(pre == 1) output.append("]");
if(pre == 0 || writeback == 1) output.append("!");
return output;
}
//move_multiple()
//(ldm,stm) {condition}{mode} rn{!},{r...}{^}
if((instruction & 0x0e000000) == 0x08000000) {
uint4 condition = instruction >> 28;
uint2 index = instruction >> 23;
uint1 s = instruction >> 22;
uint1 writeback = instruction >> 21;
uint1 load = instruction >> 20;
uint4 rn = instruction >> 16;
uint16 list = instruction;
output.append(load ? "ldm" : "stm", conditions[condition], indices[index], " ");
output.append(registers[rn], writeback ? "!" : "", ",{");
for(uint n : range(16)) if(list & (1 << n)) output.append(registers[n], ",");
output.trimRight(",", 1L);
output.append("}", s ? "^" : "");
return output;
}
//branch()
//b{l}{condition} address
if((instruction & 0x0e000000) == 0x0a000000) {
uint4 condition = instruction >> 28;
uint1 link = instruction >> 24;
output.append("b", link ? "l" : "", conditions[condition], " ");
output.append("0x", hex(pc + 8 + (int24)instruction * 4, 8L));
return output;
}
//software_interrupt()
//swi #immediate
if((instruction & 0x0f000000) == 0x0f000000) {
uint24 immediate = instruction;
output.append("swi #0x", hex(immediate, 6L));
return output;
}
output.append("???");
return output;
}
auto ARM::disassembleInstructionTHUMB(uint32 pc) -> string {
static string conditions[] = {
"eq", "ne", "cs", "cc",
"mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt",
"gt", "le", "", "",
};
static string registers[] = {
"r0", "r1", "r2", "r3",
"r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11",
"r12", "sp", "lr", "pc",
};
string output{hex(pc, 8L), " "};
uint16 instruction = read(Half | Nonsequential, pc & ~1);
output.append(hex(instruction, 4L), " ");
//adjust_register()
//(add,sub) rd,rn,rm
if((instruction & 0xfc00) == 0x1800) {
uint1 opcode = instruction >> 9;
uint3 rm = instruction >> 6;
uint3 rn = instruction >> 3;
uint3 rd = instruction >> 0;
output.append(opcode == 0 ? "add" : "sub", " ", registers[rd], ",", registers[rn], ",", registers[rm]);
return output;
}
//adjust_immediate()
//(add,sub) rd,rn,#immediate
if((instruction & 0xfc00) == 0x1c00) {
uint1 opcode = instruction >> 9;
uint3 immediate = instruction >> 6;
uint3 rn = instruction >> 3;
uint3 rd = instruction >> 0;
output.append(opcode == 0 ? "add" : "sub", " ", registers[rd], ",", registers[rn], ",#", hex(immediate, 1L));
return output;
}
//shift_immediate()
//(lsl,lsr,asar) rd,rm,#immmediate
if((instruction & 0xe000) == 0x0000) {
static string opcodes[] = { "lsl", "lsr", "asr", "" };
uint2 opcode = instruction >> 11;
uint5 immediate = instruction >> 6;
uint3 rm = instruction >> 3;
uint3 rd = instruction >> 0;
output.append(opcodes[opcode], " ", registers[rd], ",", registers[rm], ",#", immediate);
return output;
}
//immediate()
//(mov,cmp,add,sub) (rd,rn),#immediate
if((instruction & 0xe000) == 0x2000) {
static string opcodes[] = { "mov", "cmp", "add", "sub" };
uint2 opcode = instruction >> 11;
uint3 rd = instruction >> 8;
uint8 immediate = instruction;
output.append(opcodes[opcode], " ", registers[rd], ",#0x", hex(immediate, 2L));
return output;
}
//alu()
//{opcode} rd,rm
if((instruction & 0xfc00) == 0x4000) {
static string opcodes[] = {
"and", "eor", "lsl", "lsr",
"asr", "adc", "sbc", "ror",
"tst", "neg", "cmp", "cmn",
"orr", "mul", "bic", "mvn",
};
uint4 opcode = instruction >> 6;
uint3 rm = instruction >> 3;
uint3 rd = instruction >> 0;
output.append(opcodes[opcode], " ", registers[rd], ",", registers[rm]);
return output;
}
//branch_exchange()
//bx rm
if((instruction & 0xff80) == 0x4700) {
uint4 rm = instruction >> 3;
output.append("bx ", registers[rm]);
return output;
}
//alu_hi()
//{opcode} rd,rm
if((instruction & 0xfc00) == 0x4400) {
static string opcodes[] = { "add", "sub", "mov", "" };
uint2 opcode = instruction >> 8;
uint4 rm = instruction >> 3;
uint4 rd = ((uint1)(instruction >> 7) << 3) + (uint3)instruction;
if(opcode == 2 && rm == 8 && rd == 8) {
output.append("nop");
return output;
}
output.append(opcodes[opcode], " ", registers[rd], ",", registers[rm]);
return output;
}
//load_literal()
//ldr rd,[pc,#offset]
if((instruction & 0xf800) == 0x4800) {
uint3 rd = instruction >> 8;
uint8 displacement = instruction;
uint rm = ((pc + 4) & ~3) + displacement * 4;
output.append("ldr ", registers[rd], ",[pc,#0x", hex(rm, 8L), "]");
output.append(" =0x", hex(read(Word | Nonsequential, rm), 8L));
return output;
}
//move_register_offset()
//(ld(r,s),str){b,h} rd,[rn,rm]
if((instruction & 0xf000) == 0x5000) {
static string opcodes[] = {
"str", "strh", "strb", "ldsb",
"ldr", "ldrh", "ldrb", "ldsh",
};
uint3 opcode = instruction >> 9;
uint3 rm = instruction >> 6;
uint3 rn = instruction >> 3;
uint3 rd = instruction >> 0;
output.append(opcodes[opcode], " ", registers[rd], ",[", registers[rn], ",", registers[rm], "]");
return output;
}
//move_word_immediate()
//(ldr,str) rd,[rn,#offset]
if((instruction & 0xf000) == 0x6000) {
uint1 load = instruction >> 11;
uint5 offset = instruction >> 6;
uint3 rn = instruction >> 3;
uint3 rd = instruction >> 0;
output.append(load ? "ldr " : "str ", registers[rd], ",[", registers[rn], ",#0x", hex(offset * 4, 2L), "]");
return output;
}
//move_byte_immediate()
//(ldr,str)b rd,[rn,#offset]
if((instruction & 0xf000) == 0x7000) {
uint1 load = instruction >> 11;
uint5 offset = instruction >> 6;
uint3 rn = instruction >> 3;
uint3 rd = instruction >> 0;
output.append(load ? "ldrb " : "strb ", registers[rd], ",[", registers[rn], ",#0x", hex(offset, 2L), "]");
return output;
}
//move_half_immediate()
//(ldr,str)h rd,[rn,#offset]
if((instruction & 0xf000) == 0x8000) {
uint1 load = instruction >> 11;
uint5 offset = instruction >> 6;
uint3 rn = instruction >> 3;
uint3 rd = instruction >> 0;
output.append(load ? "ldrh " : "strh ", registers[rd], ",[", registers[rn], ",#0x", hex(offset * 2, 2L), "]");
return output;
}
//move_stack()
//(ldr,str) rd,[sp,#relative]
if((instruction & 0xf000) == 0x9000) {
uint1 opcode = instruction >> 11;
uint3 rd = instruction >> 8;
uint8 immediate = instruction;
output.append(opcode ? "ldr" : "str", " ", registers[rd], ",[sp,#0x", hex(immediate * 4, 3L), "]");
return output;
}
//add_register_hi()
//add rd,{pc,sp},#immediate
if((instruction & 0xf000) == 0xa000) {
uint1 sp = instruction >> 11;
uint3 rd = instruction >> 8;
uint8 immediate = instruction;
output.append("add ", registers[rd], ",", sp ? "sp" : "pc", ",#0x", hex(immediate, 2L));
return output;
}
//adjust_stack()
//(add,sub) sp,#immediate
if((instruction & 0xff00) == 0xb000) {
uint1 opcode = instruction >> 7;
uint7 immediate = instruction;
output.append(opcode == 0 ? "add" : "sub", " sp,#0x", hex(immediate * 4, 3L));
return output;
}
//stack_multiple()
//push {r...{,lr}}
//pop {r...{,pc}}
if((instruction & 0xf600) == 0xb400) {
uint1 load = instruction >> 11;
uint1 branch = instruction >> 8;
uint8 list = instruction;
output.append(load == 0 ? "push" : "pop", " {");
for(uint l : range(8)) {
if(list & (1 << l)) output.append(registers[l], ",");
}
if(branch) output.append(load == 0 ? "lr," : "pc,");
output.trimRight(",", 1L);
output.append("}");
return output;
}
//move_multiple()
//(ldmia,stmia) rn,{r...}
if((instruction & 0xf000) == 0xc000) {
uint1 load = instruction >> 11;
uint3 rn = instruction >> 8;
uint8 list = instruction;
output.append(load ? "ldmia " : "stmia ", registers[rn], "!,{");
for(uint l : range(8)) {
if(list & (1 << l)) output.append(registers[l], ",");
}
output.trimRight(",", 1L);
output.append("}");
return output;
}
//software_interrupt()
//swi #immediate
if((instruction & 0xff00) == 0xdf00) {
uint8 immediate = instruction;
output.append("swi #0x", hex(immediate, 2L));
return output;
}
//branch_conditional()
//b{condition} address
if((instruction & 0xf000) == 0xd000) {
uint4 condition = instruction >> 8;
int8 displacement = instruction;
uint32 offset = pc + 4 + displacement * 2;
output.append("b", conditions[condition], " 0x", hex(offset, 8L));
return output;
}
//branch_short()
//b address
if((instruction & 0xf800) == 0xe000) {
int11 displacement = instruction;
output.append("b 0x", hex(pc + 4 + displacement * 2, 8L));
return output;
}
//branch_long_prefix()
//bl address
if((instruction & 0xf800) == 0xf000) {
uint11 offsethi = instruction;
instruction = read(Half | Nonsequential, (pc & ~1) + 2);
uint11 offsetlo = instruction;
int22 displacement = (offsethi << 11) | (offsetlo << 0);
output.append("bl 0x", hex(pc + 4 + displacement * 2, 8L));
return output;
}
//branch_long_suffix()
//bl address
if((instruction & 0xf800) == 0xf800) {
output.append("b (suffix)");
return output;
}
output.append("???");
return output;
}
auto ARM::disassembleRegisters() -> string {
string output;
output.append( "r0:", hex(r( 0), 8L), " r1:", hex(r( 1), 8L), " r2:", hex(r( 2), 8L), " r3:", hex(r( 3), 8L), " ");
output.append( "r4:", hex(r( 4), 8L), " r5:", hex(r( 5), 8L), " r6:", hex(r( 6), 8L), " r7:", hex(r( 7), 8L), " ");
output.append("cpsr:", cpsr().n ? "N" : "n", cpsr().z ? "Z" : "z", cpsr().c ? "C" : "c", cpsr().v ? "V" : "v");
output.append("/", cpsr().i ? "I" : "i", cpsr().f ? "F" : "f", cpsr().t ? "T" : "t");
output.append("/", hex(cpsr().m, 2L), "\n");
output.append( "r8:", hex(r( 8), 8L), " r9:", hex(r( 9), 8L), " r10:", hex(r(10), 8L), " r11:", hex(r(11), 8L), " ");
output.append("r12:", hex(r(12), 8L), " sp:", hex(r(13), 8L), " lr:", hex(r(14), 8L), " pc:", hex(r(15), 8L), " ");
output.append("spsr:");
if(mode() == Processor::Mode::USR || mode() == Processor::Mode::SYS) { output.append("----/---/--"); return output; }
output.append( spsr().n ? "N" : "n", spsr().z ? "Z" : "z", spsr().c ? "C" : "c", spsr().v ? "V" : "v");
output.append("/", spsr().i ? "I" : "i", spsr().f ? "F" : "f", spsr().t ? "T" : "t");
output.append("/", hex(spsr().m, 2L));
return output;
}

View File

@ -1,3 +0,0 @@
auto disassembleInstructionARM(uint32 pc) -> string;
auto disassembleInstructionTHUMB(uint32 pc) -> string;
auto disassembleRegisters() -> string;

View File

@ -1,602 +0,0 @@
auto ARM::arm_opcode(uint32 rm) {
uint4 opcode = instruction() >> 21;
uint1 save = instruction() >> 20;
uint4 n = instruction() >> 16;
uint4 d = instruction() >> 12;
uint32 rn = r(n);
switch(opcode) {
case 0: r(d) = bit(rn & rm); break; //AND
case 1: r(d) = bit(rn ^ rm); break; //EOR
case 2: r(d) = sub(rn, rm, 1); break; //SUB
case 3: r(d) = sub(rm, rn, 1); break; //RSB
case 4: r(d) = add(rn, rm, 0); break; //ADD
case 5: r(d) = add(rn, rm, cpsr().c); break; //ADC
case 6: r(d) = sub(rn, rm, cpsr().c); break; //SBC
case 7: r(d) = sub(rm, rn, cpsr().c); break; //RSC
case 8: bit(rn & rm); break; //TST
case 9: bit(rn ^ rm); break; //TEQ
case 10: sub(rn, rm, 1); break; //CMP
case 11: add(rn, rm, 0); break; //CMN
case 12: r(d) = bit(rn | rm); break; //ORR
case 13: r(d) = bit(rm); break; //MOV
case 14: r(d) = bit(rn & ~rm); break; //BIC
case 15: r(d) = bit(~rm); break; //MVN
}
if(exceptionMode() && d == 15 && save) {
cpsr() = spsr();
processor.setMode((Processor::Mode)(uint)cpsr().m);
}
}
auto ARM::arm_move_to_status(uint32 rm) {
uint1 source = instruction() >> 22;
uint4 field = instruction() >> 16;
if(source == 1) {
if(mode() == Processor::Mode::USR) return;
if(mode() == Processor::Mode::SYS) return;
}
PSR &psr = source ? spsr() : cpsr();
if(field & 1) {
if(source == 1 || privilegedMode()) {
psr.i = rm & 0x00000080;
psr.f = rm & 0x00000040;
psr.t = rm & 0x00000020;
psr.m = rm & 0x0000001f;
if(source == 0) processor.setMode((Processor::Mode)(uint)psr.m);
}
}
if(field & 8) {
psr.n = rm & 0x80000000;
psr.z = rm & 0x40000000;
psr.c = rm & 0x20000000;
psr.v = rm & 0x10000000;
}
}
//mul{condition}{s} rd,rm,rs
//mla{condition}{s} rd,rm,rs,rn
//cccc 0000 00as dddd nnnn ssss 1001 mmmm
//c = condition
//a = accumulate
//s = save flags
//d = rd
//n = rn
//s = rs
//m = rm
auto ARM::arm_op_multiply() {
uint1 accumulate = instruction() >> 21;
uint1 save = instruction() >> 20;
uint4 d = instruction() >> 16;
uint4 n = instruction() >> 12;
uint4 s = instruction() >> 8;
uint4 m = instruction();
if(accumulate) idle();
r(d) = mul(accumulate ? r(n) : 0u, r(m), r(s));
}
//(u,s)mull{condition}{s} rdlo,rdhi,rm,rs
//(u,s)mlal{condition}{s} rdlo,rdhi,rm,rs
//cccc 0000 1sas hhhh llll ssss 1001 mmmm
//c = condition
//s = sign-extend
//a = accumulate
//s = save flags
//h = rdhi
//l = rdlo
//s = rs
//m = rm
auto ARM::arm_op_multiply_long() {
uint1 signextend = instruction() >> 22;
uint1 accumulate = instruction() >> 21;
uint1 save = instruction() >> 20;
uint4 dhi = instruction() >> 16;
uint4 dlo = instruction() >> 12;
uint4 s = instruction() >> 8;
uint4 m = instruction();
uint64 rm = r(m);
uint64 rs = r(s);
idle();
idle();
if(accumulate) idle();
//this instruction uses an 8-bit Booth algorithm for multiplication
//this supports short-circuiting, so that smaller numbers multiply faster
//for now, simulate the timing of this operation
if(signextend) {
if(rs >> 8 && (rs >> 8) != 0xffffff) idle();
if(rs >> 16 && (rs >> 16) != 0xffff) idle();
if(rs >> 24 && (rs >> 24) != 0xff) idle();
rm = (int32)rm;
rs = (int32)rs;
} else {
if(rs >> 8) idle();
if(rs >> 16) idle();
if(rs >> 24) idle();
}
uint64 rd = rm * rs;
if(accumulate) rd += ((uint64)r(dhi) << 32) + ((uint64)r(dlo) << 0);
r(dhi) = rd >> 32;
r(dlo) = rd >> 0;
if(save) {
cpsr().n = r(dhi) >> 31;
cpsr().z = r(dhi) == 0 && r(dlo) == 0;
//cpsr().c = 0; //(undefined)
//cpsr().v = 0; //(undefined)
}
}
//swp{condition}{b} rd,rm,[rn]
//cccc 0001 0b00 nnnn dddd ---- 1001 mmmm
//c = condition
//b = byte (0 = word)
//n = rn
//d = rd
//m = rm
auto ARM::arm_op_memory_swap() {
uint1 byte = instruction() >> 22;
uint4 n = instruction() >> 16;
uint4 d = instruction() >> 12;
uint4 m = instruction();
uint32 word = load((byte ? Byte : Word) | Nonsequential, r(n));
store((byte ? Byte : Word) | Nonsequential, r(n), r(m));
r(d) = word;
}
//(ldr,str){condition}h rd,[rn,rm]{!}
//(ldr,str){condition}h rd,[rn],rm
//cccc 000p u0wl nnnn dddd ---- 1011 mmmm
//c = condition
//p = pre (0 = post)
//u = up
//w = writeback
//l = load (0 = save)
//n = rn
//d = rd
//m = rm
auto ARM::arm_op_move_half_register() {
uint1 pre = instruction() >> 24;
uint1 up = instruction() >> 23;
uint1 writeback = instruction() >> 21;
uint1 l = instruction() >> 20;
uint4 n = instruction() >> 16;
uint4 d = instruction() >> 12;
uint4 m = instruction();
uint32 rn = r(n);
uint32 rm = r(m);
uint32 rd = r(d);
if(pre == 1) rn = up ? rn + rm : rn - rm;
if(l == 1) rd = load(Half | Nonsequential, rn);
if(l == 0) store(Half | Nonsequential, rn, rd);
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback == 1) r(n) = rn;
if(l == 1) r(d) = rd;
}
//(ldr,str){condition}h rd,[rn{,+/-offset}]{!}
//(ldr,str){condition}h rd,[rn]{,+/-offset}
//cccc 000p u1wl nnnn dddd iiii 1011 iiii
//c = condition
//p = pre (0 = post)
//u = up
//w = writeback
//l = load (0 = save)
//n = rn
//d = rd
//i = immediate hi
//i = immediate lo
auto ARM::arm_op_move_half_immediate() {
uint1 pre = instruction() >> 24;
uint1 up = instruction() >> 23;
uint1 writeback = instruction() >> 21;
uint1 l = instruction() >> 20;
uint4 n = instruction() >> 16;
uint4 d = instruction() >> 12;
uint4 ih = instruction() >> 8;
uint4 il = instruction();
uint32 rn = r(n);
uint32 rd = r(d);
uint8 immediate = (ih << 4) + (il << 0);
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
if(l == 1) rd = load(Half | Nonsequential, rn);
if(l == 0) store(Half | Nonsequential, rn, rd);
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
if(pre == 0 || writeback == 1) r(n) = rn;
if(l == 1) r(d) = rd;
}
//ldr{condition}s(h,b) rd,[rn,rm]{!}
//ldr{condition}s(h,b) rd,[rn],rm
//cccc 000p u0w1 nnnn dddd ---- 11h1 mmmm
//c = condition
//p = pre (0 = post)
//u = up
//w = writeback
//n = rn
//d = rd
//h = half (0 = byte)
//m = rm
auto ARM::arm_op_load_register() {
uint1 pre = instruction() >> 24;
uint1 up = instruction() >> 23;
uint1 writeback = instruction() >> 21;
uint4 n = instruction() >> 16;
uint4 d = instruction() >> 12;
uint1 half = instruction() >> 5;
uint4 m = instruction();
uint32 rn = r(n);
uint32 rm = r(m);
uint32 rd = r(d);
if(pre == 1) rn = up ? rn + rm : rn - rm;
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback == 1) r(n) = rn;
r(d) = rd;
}
//ldr{condition}s(h,b) rd,[rn{,+/-offset}]{!}
//ldr{condition}s(h,b) rd,[rn]{,+/-offset}
//cccc 000p u1w1 nnnn dddd iiii 11h1 iiii
//c = condition
//p = pre (0 = post)
//u = up
//w = writeback
//n = rn
//d = rd
//i = immediate hi
//h = half (0 = byte)
//i = immediate lo
auto ARM::arm_op_load_immediate() {
uint1 pre = instruction() >> 24;
uint1 up = instruction() >> 23;
uint1 writeback = instruction() >> 21;
uint4 n = instruction() >> 16;
uint4 d = instruction() >> 12;
uint4 ih = instruction() >> 8;
uint1 half = instruction() >> 5;
uint4 il = instruction();
uint32 rn = r(n);
uint32 rd = r(d);
uint8 immediate = (ih << 4) + (il << 0);
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
if(pre == 0 || writeback == 1) r(n) = rn;
r(d) = rd;
}
//mrs{condition} rd,(c,s)psr
//cccc 0001 0r00 ++++ dddd ---- 0000 ----
//c = condition
//r = SPSR (0 = CPSR)
//d = rd
auto ARM::arm_op_move_to_register_from_status() {
uint1 source = instruction() >> 22;
uint4 d = instruction() >> 12;
if(source) {
if(mode() == Processor::Mode::USR) return;
if(mode() == Processor::Mode::SYS) return;
}
r(d) = source ? spsr() : cpsr();
}
//msr{condition} (c,s)psr:{fields},rm
//cccc 0001 0r10 ffff ++++ ---- 0000 mmmm
//c = condition
//r = SPSR (0 = CPSR)
//f = field mask
//m = rm
auto ARM::arm_op_move_to_status_from_register() {
uint4 m = instruction();
arm_move_to_status(r(m));
}
//bx{condition} rm
//cccc 0001 0010 ++++ ++++ ++++ 0001 mmmm
//c = condition
//m = rm
auto ARM::arm_op_branch_exchange_register() {
uint4 m = instruction();
cpsr().t = r(m) & 1;
r(15) = r(m);
}
//msr{condition} (c,s)psr:{fields},#immediate
//cccc 0011 0r10 ffff ++++ rrrr iiii iiii
//c = condition
//r = SPSR (0 = CPSR)
//f = field mask
//r = rotate
//i = immediate
auto ARM::arm_op_move_to_status_from_immediate() {
uint4 rotate = instruction() >> 8;
uint8 immediate = instruction();
uint32 rm = immediate;
if(rotate) rm = ror(rm, 2 * rotate);
arm_move_to_status(rm);
}
//{opcode}{condition}{s} rd,rm {shift} #immediate
//{opcode}{condition} rn,rm {shift} #immediate
//{opcode}{condition}{s} rd,rn,rm {shift} #immediate
//cccc 000o ooos nnnn dddd llll lss0 mmmm
//c = condition
//o = opcode
//s = save flags
//n = rn
//d = rd
//l = shift immediate
//s = shift
//m = rm
auto ARM::arm_op_data_immediate_shift() {
uint1 save = instruction() >> 20;
uint5 shift = instruction() >> 7;
uint2 mode = instruction() >> 5;
uint4 m = instruction();
uint32 rs = shift;
uint32 rm = r(m);
carryout() = cpsr().c;
if(mode == 0) rm = lsl(rm, rs);
if(mode == 1) rm = lsr(rm, rs ? rs : (uint32)32);
if(mode == 2) rm = asr(rm, rs ? rs : (uint32)32);
if(mode == 3) rm = rs ? ror(rm, rs) : rrx(rm);
arm_opcode(rm);
}
//{opcode}{condition}{s} rd,rm {shift} rs
//{opcode}{condition} rn,rm {shift} rs
//{opcode}{condition}{s} rd,rn,rm {shift} rs
//cccc 000o ooos nnnn dddd ssss 0ss1 mmmm
//c = condition
//o = opcode
//s = save flags
//n = rn
//d = rd
//s = rs
//s = shift
//m = rm
auto ARM::arm_op_data_register_shift() {
uint1 save = instruction() >> 20;
uint4 s = instruction() >> 8;
uint2 mode = instruction() >> 5;
uint4 m = instruction();
uint8 rs = r(s) + (s == 15 ? 4 : 0);
uint32 rm = r(m) + (m == 15 ? 4 : 0);
carryout() = cpsr().c;
if(mode == 0 ) rm = lsl(rm, rs < 33 ? rs : (uint8)33);
if(mode == 1 ) rm = lsr(rm, rs < 33 ? rs : (uint8)33);
if(mode == 2 ) rm = asr(rm, rs < 32 ? rs : (uint8)32);
if(mode == 3 && rs) rm = ror(rm, rs & 31 == 0 ? 32 : rs & 31);
arm_opcode(rm);
}
//{opcode}{condition}{s} rd,#immediate
//{opcode}{condition} rn,#immediate
//{opcode}{condition}{s} rd,rn,#immediate
//cccc 001o ooos nnnn dddd ssss iiii iiii
//c = condition
//o = opcode
//s = save flags
//n = rn
//d = rd
//s = shift immediate
//i = immediate
auto ARM::arm_op_data_immediate() {
uint1 save = instruction() >> 20;
uint4 shift = instruction() >> 8;
uint8 immediate = instruction();
uint32 rm = immediate;
carryout() = cpsr().c;
if(shift) rm = ror(immediate, 2 * shift);
arm_opcode(rm);
}
//(ldr,str){condition}{b} rd,[rn{,+/-offset}]{!}
//(ldr,str){condition}{b} rd,[rn]{,+/-offset}
//cccc 010p ubwl nnnn dddd iiii iiii iiii
//c = condition
//p = pre (0 = post-indexed addressing)
//u = up (add/sub offset to base)
//b = byte (1 = word)
//w = writeback
//l = load (0 = save)
//n = rn
//d = rd
//i = immediate
auto ARM::arm_op_move_immediate_offset() {
uint1 pre = instruction() >> 24;
uint1 up = instruction() >> 23;
uint1 byte = instruction() >> 22;
uint1 writeback = instruction() >> 21;
uint1 l = instruction() >> 20;
uint4 n = instruction() >> 16;
uint4 d = instruction() >> 12;
uint12 rm = instruction();
uint32 rn = r(n);
uint32 rd = r(d);
if(pre == 1) rn = up ? rn + rm : rn - rm;
if(l == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn);
if(l == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd);
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback == 1) r(n) = rn;
if(l == 1) r(d) = rd;
}
//(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{!}
//(ldr,str){condition}{b} rd,[rn],rm {mode} #immediate
//cccc 011p ubwl nnnn dddd llll lss0 mmmm
//c = condition
//p = pre (0 = post-indexed addressing)
//u = up
//b = byte (1 = word)
//w = writeback
//l = load (0 = save)
//n = rn
//d = rd
//l = shift immediate
//s = shift mode
//m = rm
auto ARM::arm_op_move_register_offset() {
uint1 pre = instruction() >> 24;
uint1 up = instruction() >> 23;
uint1 byte = instruction() >> 22;
uint1 writeback = instruction() >> 21;
uint1 l = instruction() >> 20;
uint4 n = instruction() >> 16;
uint4 d = instruction() >> 12;
uint5 immediate = instruction() >> 7;
uint2 mode = instruction() >> 5;
uint4 m = instruction();
uint32 rn = r(n);
uint32 rd = r(d);
uint32 rs = immediate;
uint32 rm = r(m);
carryout() = cpsr().c;
if(mode == 0) rm = lsl(rm, rs);
if(mode == 1) rm = lsr(rm, rs ? rs : (uint32)32);
if(mode == 2) rm = asr(rm, rs ? rs : (uint32)32);
if(mode == 3) rm = rs ? ror(rm, rs) : rrx(rm);
if(pre == 1) rn = up ? rn + rm : rn - rm;
if(l == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn);
if(l == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd);
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback == 1) r(n) = rn;
if(l == 1) r(d) = rd;
}
//(ldm,stm){condition}{mode} rn{!},{r...}
//cccc 100p uswl nnnn llll llll llll llll
//c = condition
//p = pre (0 = post-indexed addressing)
//u = up (add/sub offset to base)
//s = spsr copy -or- usr register copy
//w = writeback
//l = load (0 = save)
//n = rn
//l = register list
auto ARM::arm_op_move_multiple() {
uint1 pre = instruction() >> 24;
uint1 up = instruction() >> 23;
uint1 s = instruction() >> 22;
uint1 writeback = instruction() >> 21;
uint1 l = instruction() >> 20;
uint4 n = instruction() >> 16;
uint16 list = instruction();
uint32 rn = r(n);
if(pre == 0 && up == 1) rn = rn + 0; //IA
if(pre == 1 && up == 1) rn = rn + 4; //IB
if(pre == 1 && up == 0) rn = rn - bit::count(list) * 4 + 0; //DB
if(pre == 0 && up == 0) rn = rn - bit::count(list) * 4 + 4; //DA
if(writeback && l == 1) {
if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA, IB
if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA, DB
}
Processor::Mode pmode = mode();
bool usr = false;
if(s && l == 1 && (list & 0x8000) == 0) usr = true;
if(s && l == 0) usr = true;
if(usr) processor.setMode(Processor::Mode::USR);
uint sequential = Nonsequential;
for(uint m : range(16)) {
if(list & 1 << m) {
if(l == 1) r(m) = read(Word | sequential, rn);
if(l == 0) write(Word | sequential, rn, r(m));
rn += 4;
sequential = Sequential;
}
}
if(usr) processor.setMode(pmode);
if(l == 1) {
idle();
if(s && (list & 0x8000)) {
if(mode() != Processor::Mode::USR && mode() != Processor::Mode::SYS) {
cpsr() = spsr();
processor.setMode((Processor::Mode)(uint)cpsr().m);
}
}
} else {
pipeline.nonsequential = true;
}
if(writeback && l == 0) {
if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA, IB
if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA, DB
}
}
//b{l}{condition} address
//cccc 101l dddd dddd dddd dddd dddd dddd
//c = condition
//l = link
//d = displacement (24-bit signed)
auto ARM::arm_op_branch() {
uint1 link = instruction() >> 24;
int24 displacement = instruction();
if(link) r(14) = r(15) - 4;
r(15) += displacement * 4;
}
//swi #immediate
//cccc 1111 iiii iiii iiii iiii iiii iiii
//c = condition
//i = immediate
auto ARM::arm_op_software_interrupt() {
uint24 immediate = instruction();
interrupt(Processor::Mode::SVC, 0x08);
}

View File

@ -1,24 +0,0 @@
auto arm_opcode(uint32 rm);
auto arm_move_to_status(uint32 rm);
auto arm_op_multiply();
auto arm_op_multiply_long();
auto arm_op_memory_swap();
auto arm_op_move_half_register();
auto arm_op_move_half_immediate();
auto arm_op_load_register();
auto arm_op_load_immediate();
auto arm_op_move_to_register_from_status();
auto arm_op_move_to_status_from_register();
auto arm_op_branch_exchange_register();
auto arm_op_move_to_status_from_immediate();
auto arm_op_data_immediate_shift();
auto arm_op_data_register_shift();
auto arm_op_data_immediate();
auto arm_op_move_immediate_offset();
auto arm_op_move_register_offset();
auto arm_op_move_multiple();
auto arm_op_branch();
auto arm_op_software_interrupt();

View File

@ -1,372 +0,0 @@
auto ARM::thumb_opcode(uint4 opcode, uint4 d, uint4 m) {
switch(opcode) {
case 0: r(d) = bit(r(d) & r(m)); break; //AND
case 1: r(d) = bit(r(d) ^ r(m)); break; //EOR
case 2: r(d) = bit(lsl(r(d), r(m))); break; //LSL
case 3: r(d) = bit(lsr(r(d), r(m))); break; //LSR
case 4: r(d) = bit(asr(r(d), r(m))); break; //ASR
case 5: r(d) = add(r(d), r(m), cpsr().c); break; //ADC
case 6: r(d) = sub(r(d), r(m), cpsr().c); break; //SBC
case 7: r(d) = bit(ror(r(d), r(m))); break; //ROR
case 8: bit(r(d) & r(m)); break; //TST
case 9: r(d) = sub(0, r(m), 1); break; //NEG
case 10: sub(r(d), r(m), 1); break; //CMP
case 11: add(r(d), r(m), 0); break; //CMN
case 12: r(d) = bit(r(d) | r(m)); break; //ORR
case 13: r(d) = mul(0, r(m), r(d)); break; //MUL
case 14: r(d) = bit(r(d) & ~r(m)); break; //BIC
case 15: r(d) = bit(~r(m)); break; //MVN
}
}
//(add,sub) rd,rn,rm
//0001 10om mmnn nddd
//o = opcode
//m = rm
//n = rn
//d = rd
auto ARM::thumb_op_adjust_register() {
uint1 opcode = instruction() >> 9;
uint3 m = instruction() >> 6;
uint3 n = instruction() >> 3;
uint3 d = instruction() >> 0;
switch(opcode) {
case 0: r(d) = add(r(n), r(m), 0); break;
case 1: r(d) = sub(r(n), r(m), 1); break;
}
}
//(add,sub) rd,rn,#immediate
//0001 11oi iinn nddd
//o = opcode
//i = immediate
//n = rn
//d = rd
auto ARM::thumb_op_adjust_immediate() {
uint1 opcode = instruction() >> 9;
uint3 immediate = instruction() >> 6;
uint3 n = instruction() >> 3;
uint3 d = instruction() >> 0;
switch(opcode) {
case 0: r(d) = add(r(n), immediate, 0); break;
case 1: r(d) = sub(r(n), immediate, 1); break;
}
}
//(lsl,lsr,asr) rd,rm,#immediate
//000o oiii iimm mddd
//o = opcode
//i = immediate
//m = rm
//d = rd
auto ARM::thumb_op_shift_immediate() {
uint2 opcode = instruction() >> 11;
uint5 immediate = instruction() >> 6;
uint3 m = instruction() >> 3;
uint3 d = instruction() >> 0;
switch(opcode) {
case 0: r(d) = bit(lsl(r(m), immediate)); break;
case 1: r(d) = bit(lsr(r(m), immediate == 0 ? 32u : (uint)immediate)); break;
case 2: r(d) = bit(asr(r(m), immediate == 0 ? 32u : (uint)immediate)); break;
}
}
//(mov,cmp,add,sub) (rd,rn),#immediate
//001o orrr iiii iiii
//o = opcode
//r = (rd,rn)
//i = immediate
auto ARM::thumb_op_immediate() {
uint2 opcode = instruction() >> 11;
uint3 d = instruction() >> 8;
uint8 immediate = instruction();
switch(opcode) {
case 0: r(d) = bit( immediate ); break;
case 1: sub(r(d), immediate, 1); break;
case 2: r(d) = add(r(d), immediate, 0); break;
case 3: r(d) = sub(r(d), immediate, 1); break;
}
}
//{opcode} rd,rm
//0100 00oo oomm mddd
//o = opcode
//m = rm
//d = rd
auto ARM::thumb_op_alu() {
uint4 opcode = instruction() >> 6;
uint3 m = instruction() >> 3;
uint3 d = instruction();
thumb_opcode(opcode, d, m);
}
//bx rm
//0100 0111 0mmm m---
//m = rm
auto ARM::thumb_op_branch_exchange() {
uint4 m = instruction() >> 3;
cpsr().t = r(m) & 1;
r(15) = r(m);
}
//{opcode} rd,rm
//0100 01oo DMmm mddd
//o = opcode
//M:m = rm
//D:d = rd
auto ARM::thumb_op_alu_hi() {
uint2 opcode = instruction() >> 8;
uint4 m = instruction() >> 3;
uint3 dl = instruction();
uint1 dh = instruction() >> 7;
uint4 d = (dh << 3) + (dl << 0);
switch(opcode) {
case 0: r(d) = r(d) + r(m); break; //ADD (does not modify flags)
case 1: sub(r(d), r(m), 1); break; //SUB
case 2: r(d) = r(m); break; //MOV (does not modify flags)
}
}
//ldr rd,[pc,#offset]
//0100 1ddd oooo oooo
//d = rd
//o = offset
auto ARM::thumb_op_load_literal() {
uint3 d = instruction() >> 8;
uint8 displacement = instruction();
uint rm = (r(15) & ~3) + displacement * 4;
r(d) = load(Word | Nonsequential, rm);
}
//(ld(r,s),str){b,h} rd,[rn,rm]
//0101 ooom mmnn nddd
//o = opcode
//m = rm
//n = rn
//d = rd
auto ARM::thumb_op_move_register_offset() {
uint3 opcode = instruction() >> 9;
uint3 m = instruction() >> 6;
uint3 n = instruction() >> 3;
uint3 d = instruction() >> 0;
switch(opcode) {
case 0: store(Word | Nonsequential, r(n) + r(m), r(d)); break; //STR
case 1: store(Half | Nonsequential, r(n) + r(m), r(d)); break; //STRH
case 2: store(Byte | Nonsequential, r(n) + r(m), r(d)); break; //STRB
case 3: r(d) = load(Byte | Nonsequential | Signed, r(n) + r(m)); break; //LDSB
case 4: r(d) = load(Word | Nonsequential, r(n) + r(m)); break; //LDR
case 5: r(d) = load(Half | Nonsequential, r(n) + r(m)); break; //LDRH
case 6: r(d) = load(Byte | Nonsequential, r(n) + r(m)); break; //LDRB
case 7: r(d) = load(Half | Nonsequential | Signed, r(n) + r(m)); break; //LDSH
}
}
//(ldr,str) rd,[rn,#offset]
//0110 looo oonn nddd
//l = load
//o = offset
//n = rn
//d = rd
auto ARM::thumb_op_move_word_immediate() {
uint1 l = instruction() >> 11;
uint5 offset = instruction() >> 6;
uint3 n = instruction() >> 3;
uint3 d = instruction() >> 0;
if(l == 1) r(d) = load(Word | Nonsequential, r(n) + offset * 4);
if(l == 0) store(Word | Nonsequential, r(n) + offset * 4, r(d));
}
//(ldr,str)b rd,[rn,#offset]
//0111 looo oonn nddd
//l = load
//o = offset
//n = rn
//d = rd
auto ARM::thumb_op_move_byte_immediate() {
uint1 l = instruction() >> 11;
uint5 offset = instruction() >> 6;
uint3 n = instruction() >> 3;
uint3 d = instruction() >> 0;
if(l == 1) r(d) = load(Byte | Nonsequential, r(n) + offset);
if(l == 0) store(Byte | Nonsequential, r(n) + offset, r(d));
}
//(ldr,str)h rd,[rn,#offset]
//1000 looo oonn nddd
//l = load
//o = offset
//n = rn
//d = rd
auto ARM::thumb_op_move_half_immediate() {
uint1 l = instruction() >> 11;
uint5 offset = instruction() >> 6;
uint3 n = instruction() >> 3;
uint3 d = instruction() >> 0;
if(l == 1) r(d) = load(Half | Nonsequential, r(n) + offset * 2);
if(l == 0) store(Half | Nonsequential, r(n) + offset * 2, r(d));
}
//(ldr,str) rd,[sp,#immediate]
//1001 oddd iiii iiii
//l = load
//d = rd
//i = immediate
auto ARM::thumb_op_move_stack() {
uint1 l = instruction() >> 11;
uint3 d = instruction() >> 8;
uint8 immediate = instruction();
if(l == 1) r(d) = load(Word | Nonsequential, r(13) + immediate * 4);
if(l == 0) store(Word | Nonsequential, r(13) + immediate * 4, r(d));
}
//add rd,{pc,sp},#immediate
//1010 sddd iiii iiii
//s = sp (0 = pc)
//d = rd
//i = immediate
auto ARM::thumb_op_add_register_hi() {
uint1 sp = instruction() >> 11;
uint3 d = instruction() >> 8;
uint8 immediate = instruction();
if(sp == 0) r(d) = (r(15) & ~2) + immediate * 4;
if(sp == 1) r(d) = r(13) + immediate * 4;
}
//(add,sub) sp,#immediate
//1011 0000 oiii iiii
//o = opcode
//i = immediate
auto ARM::thumb_op_adjust_stack() {
uint1 opcode = instruction() >> 7;
uint7 immediate = instruction();
if(opcode == 0) r(13) += immediate * 4;
if(opcode == 1) r(13) -= immediate * 4;
}
//push {r...{,lr}}
//pop {r...{,pc}}
//1011 o10r llll llll
//o = opcode (0 = push, 1 = pop)
//r = push lr -or- pop pc
//l = register list
auto ARM::thumb_op_stack_multiple() {
uint1 l = instruction() >> 11;
uint1 branch = instruction() >> 8;
uint8 list = instruction();
uint32 sp = 0;
if(l == 1) sp = r(13);
if(l == 0) sp = r(13) - (bit::count(list) + branch) * 4;
uint sequential = Nonsequential;
for(uint m : range(8)) {
if(list & 1 << m) {
if(l == 1) r(m) = read(Word | sequential, sp); //POP
if(l == 0) write(Word | sequential, sp, r(m)); //PUSH
sp += 4;
sequential = Sequential;
}
}
if(branch) {
//note: ARMv5+ POP sets cpsr().t
if(l == 1) r(15) = read(Word | Nonsequential, sp); //POP
if(l == 0) write(Word | Nonsequential, sp, r(14)); //PUSH
sp += 4;
}
if(l == 1) {
idle();
r(13) += (bit::count(list) + branch) * 4;
} else {
pipeline.nonsequential = true;
r(13) -= (bit::count(list) + branch) * 4;
}
}
//(ldmia,stmia) rn!,{r...}
//1100 lnnn llll llll
//l = load (0 = save)
//n = rn
//l = register list
auto ARM::thumb_op_move_multiple() {
uint1 l = instruction() >> 11;
uint3 n = instruction() >> 8;
uint8 list = instruction();
uint32 rn = r(n); //rn may be in register list; so we must cache it
for(uint m : range(8)) {
if(list & 1 << m) {
if(l == 1) r(m) = read(Word | Nonsequential, rn); //LDMIA
if(l == 0) write(Word | Nonsequential, rn, r(m)); //STMIA
rn += 4;
}
}
if(l == 0 || (list & 1 << n) == 0) r(n) = rn; //update rn on save or when not in register list
if(l == 1) idle();
}
//swi #immediate
//1101 1111 iiii iiii
//i = immediate
auto ARM::thumb_op_software_interrupt() {
uint8 immediate = instruction();
interrupt(Processor::Mode::SVC, 0x08);
}
//b{condition}
//1101 cccc dddd dddd
//c = condition
//d = displacement
auto ARM::thumb_op_branch_conditional() {
uint4 flagcondition = instruction() >> 8;
int8 displacement = instruction();
if(condition(flagcondition) == false) return;
r(15) = r(15) + displacement * 2;
}
//b address
//1110 0ooo oooo oooo
//o = offset
auto ARM::thumb_op_branch_short() {
int11 displacement = instruction();
r(15) += displacement * 2;
}
//bl address
//1111 0ooo oooo oooo
//o = offset
auto ARM::thumb_op_branch_long_prefix() {
int11 offsethi = instruction();
r(14) = r(15) + ((offsethi * 2) << 11);
}
//bl address
//1111 1ooo oooo oooo
//o = offset
auto ARM::thumb_op_branch_long_suffix() {
uint11 offsetlo = instruction();
r(15) = r(14) + (offsetlo * 2);
r(14) = pipeline.decode.address | 1;
}

View File

@ -1,24 +0,0 @@
auto thumb_opcode(uint4 opcode, uint4 d, uint4 s);
auto thumb_op_adjust_register();
auto thumb_op_adjust_immediate();
auto thumb_op_shift_immediate();
auto thumb_op_immediate();
auto thumb_op_alu();
auto thumb_op_branch_exchange();
auto thumb_op_alu_hi();
auto thumb_op_load_literal();
auto thumb_op_move_register_offset();
auto thumb_op_move_word_immediate();
auto thumb_op_move_byte_immediate();
auto thumb_op_move_half_immediate();
auto thumb_op_move_stack();
auto thumb_op_add_register_hi();
auto thumb_op_adjust_stack();
auto thumb_op_stack_multiple();
auto thumb_op_move_multiple();
auto thumb_op_software_interrupt();
auto thumb_op_branch_conditional();
auto thumb_op_branch_short();
auto thumb_op_branch_long_prefix();
auto thumb_op_branch_long_suffix();

View File

@ -1,59 +0,0 @@
auto ARM::Processor::power() -> void {
r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = 0;
usr.r8 = usr.r9 = usr.r10 = usr.r11 = usr.r12 = usr.sp = usr.lr = 0;
fiq.r8 = fiq.r9 = fiq.r10 = fiq.r11 = fiq.r12 = fiq.sp = fiq.lr = 0;
irq.sp = irq.lr = 0;
svc.sp = svc.lr = 0;
abt.sp = abt.lr = 0;
und.sp = und.lr = 0;
pc = 0;
carryout = false;
irqline = false;
cpsr = 0;
spsr = nullptr;
fiq.spsr = 0;
irq.spsr = 0;
svc.spsr = 0;
abt.spsr = 0;
und.spsr = 0;
r[0] = &r0;
r[1] = &r1;
r[2] = &r2;
r[3] = &r3;
r[4] = &r4;
r[5] = &r5;
r[6] = &r6;
r[7] = &r7;
r[15] = &pc;
}
auto ARM::Processor::setMode(Mode mode) -> void {
cpsr.m = 0x10 | (uint)mode;
if(mode == Mode::FIQ) {
r[ 8] = &fiq.r8;
r[ 9] = &fiq.r9;
r[10] = &fiq.r10;
r[11] = &fiq.r11;
r[12] = &fiq.r12;
} else {
r[ 8] = &usr.r8;
r[ 9] = &usr.r9;
r[10] = &usr.r10;
r[11] = &usr.r11;
r[12] = &usr.r12;
}
switch(mode) {
case Mode::FIQ: r[13] = &fiq.sp; r[14] = &fiq.lr; spsr = &fiq.spsr; break;
case Mode::IRQ: r[13] = &irq.sp; r[14] = &irq.lr; spsr = &irq.spsr; break;
case Mode::SVC: r[13] = &svc.sp; r[14] = &svc.lr; spsr = &svc.spsr; break;
case Mode::ABT: r[13] = &abt.sp; r[14] = &abt.lr; spsr = &abt.spsr; break;
case Mode::UND: r[13] = &und.sp; r[14] = &und.lr; spsr = &und.spsr; break;
default: r[13] = &usr.sp; r[14] = &usr.lr; spsr = nullptr; break;
}
}

View File

@ -1,126 +0,0 @@
struct GPR {
inline operator uint32_t() const { return data; }
inline auto operator=(uint32_t n) { data = n; if(modify) modify(); return *this; }
inline auto operator=(const GPR& source) { return operator=(source.data); }
inline auto operator &=(uint32_t n) { return operator=(data & n); }
inline auto operator |=(uint32_t n) { return operator=(data | n); }
inline auto operator ^=(uint32_t n) { return operator=(data ^ n); }
inline auto operator +=(uint32_t n) { return operator=(data + n); }
inline auto operator -=(uint32_t n) { return operator=(data - n); }
inline auto operator *=(uint32_t n) { return operator=(data * n); }
inline auto operator /=(uint32_t n) { return operator=(data / n); }
inline auto operator %=(uint32_t n) { return operator=(data % n); }
inline auto operator<<=(uint32_t n) { return operator=(data << n); }
inline auto operator>>=(uint32_t n) { return operator=(data >> n); }
uint32_t data = 0;
function<auto () -> void> modify;
};
struct PSR {
union {
uint32_t data = 0;
BooleanBitField<uint32_t, 31> n; //negative
BooleanBitField<uint32_t, 30> z; //zero
BooleanBitField<uint32_t, 29> c; //carry
BooleanBitField<uint32_t, 28> v; //overflow
BooleanBitField<uint32_t, 7> i; //irq
BooleanBitField<uint32_t, 6> f; //fiq
BooleanBitField<uint32_t, 5> t; //thumb
NaturalBitField<uint32_t, 4, 0> m; //mode
};
PSR() = default;
PSR(const PSR& value) { data = value.data; }
inline operator uint() const { return data & 0xf00000ff; }
inline auto& operator=(uint value) { return data = value, *this; }
inline auto& operator=(const PSR& value) { return data = value.data, *this; }
};
struct Pipeline {
bool reload = false;
bool nonsequential = false;
struct Instruction {
uint32 address = 0;
uint32 instruction = 0;
};
Instruction execute;
Instruction decode;
Instruction fetch;
};
struct Processor {
enum class Mode : uint {
USR26 = 0x00, //26-bit user
FIQ26 = 0x01, //26-bit fast-interrupt
IRQ26 = 0x02, //26-bit interrupt
SVC26 = 0x03, //26-bit service
USR = 0x10, //user
FIQ = 0x11, //fast-interrupt
IRQ = 0x12, //interrupt
SVC = 0x13, //service
ABT = 0x17, //abort
UND = 0x1b, //undefined
SYS = 0x1f, //system
};
GPR r0, r1, r2, r3, r4, r5, r6, r7;
struct USR {
GPR r8, r9, r10, r11, r12, sp, lr;
} usr;
struct FIQ {
GPR r8, r9, r10, r11, r12, sp, lr;
PSR spsr;
} fiq;
struct IRQ {
GPR sp, lr;
PSR spsr;
} irq;
struct SVC {
GPR sp, lr;
PSR spsr;
} svc;
struct ABT {
GPR sp, lr;
PSR spsr;
} abt;
struct UND {
GPR sp, lr;
PSR spsr;
} und;
GPR pc;
PSR cpsr;
bool carryout = false;
bool irqline = false;
GPR* r[16] = {nullptr};
PSR* spsr = nullptr;
auto power() -> void;
auto setMode(Mode) -> void;
};
Processor processor;
Pipeline pipeline;
bool crash = false;
alwaysinline auto r(uint n) -> GPR& { return *processor.r[n]; }
alwaysinline auto cpsr() -> PSR& { return processor.cpsr; }
alwaysinline auto spsr() -> PSR& { return *processor.spsr; }
alwaysinline auto carryout() -> bool& { return processor.carryout; }
alwaysinline auto instruction() -> uint32 { return pipeline.execute.instruction; }
alwaysinline auto mode() -> Processor::Mode { return (Processor::Mode)(uint)processor.cpsr.m; }
alwaysinline auto privilegedMode() const -> bool { return (Processor::Mode)(uint)processor.cpsr.m != Processor::Mode::USR; }
alwaysinline auto exceptionMode() const -> bool { return privilegedMode() && (Processor::Mode)(uint)processor.cpsr.m != Processor::Mode::SYS; }

View File

@ -1,61 +0,0 @@
auto ARM::serialize(serializer& s) -> void {
s.integer(processor.r0.data);
s.integer(processor.r1.data);
s.integer(processor.r2.data);
s.integer(processor.r3.data);
s.integer(processor.r4.data);
s.integer(processor.r5.data);
s.integer(processor.r6.data);
s.integer(processor.r7.data);
s.integer(processor.usr.r8.data);
s.integer(processor.usr.r9.data);
s.integer(processor.usr.r10.data);
s.integer(processor.usr.r11.data);
s.integer(processor.usr.r12.data);
s.integer(processor.usr.sp.data);
s.integer(processor.usr.lr.data);
s.integer(processor.fiq.r8.data);
s.integer(processor.fiq.r9.data);
s.integer(processor.fiq.r10.data);
s.integer(processor.fiq.r11.data);
s.integer(processor.fiq.r12.data);
s.integer(processor.fiq.sp.data);
s.integer(processor.fiq.lr.data);
s.integer(processor.fiq.spsr.data);
s.integer(processor.irq.sp.data);
s.integer(processor.irq.lr.data);
s.integer(processor.irq.spsr.data);
s.integer(processor.svc.sp.data);
s.integer(processor.svc.lr.data);
s.integer(processor.svc.spsr.data);
s.integer(processor.abt.sp.data);
s.integer(processor.abt.lr.data);
s.integer(processor.abt.spsr.data);
s.integer(processor.und.sp.data);
s.integer(processor.und.lr.data);
s.integer(processor.und.spsr.data);
s.integer(processor.pc.data);
s.integer(processor.cpsr.data);
s.integer(processor.carryout);
s.integer(processor.irqline);
s.integer(pipeline.reload);
s.integer(pipeline.nonsequential);
s.integer(pipeline.execute.address);
s.integer(pipeline.execute.instruction);
s.integer(pipeline.decode.address);
s.integer(pipeline.decode.instruction);
s.integer(pipeline.fetch.address);
s.integer(pipeline.fetch.instruction);
s.integer(crash);
processor.setMode((Processor::Mode)(uint)cpsr().m);
}

View File

@ -1,135 +0,0 @@
auto ARM::stepPipeline() -> void {
pipeline.execute = pipeline.decode;
pipeline.decode = pipeline.fetch;
uint sequential = Sequential;
if(pipeline.nonsequential) {
pipeline.nonsequential = false;
sequential = Nonsequential;
}
if(cpsr().t == 0) {
r(15).data += 4;
pipeline.fetch.address = r(15) & ~3;
pipeline.fetch.instruction = read(Prefetch | Word | sequential, pipeline.fetch.address);
} else {
r(15).data += 2;
pipeline.fetch.address = r(15) & ~1;
pipeline.fetch.instruction = read(Prefetch | Half | sequential, pipeline.fetch.address);
}
}
auto ARM::stepARM() -> void {
if(pipeline.reload) {
pipeline.reload = false;
r(15).data &= ~3;
pipeline.fetch.address = r(15) & ~3;
pipeline.fetch.instruction = read(Prefetch | Word | Nonsequential, pipeline.fetch.address);
stepPipeline();
}
stepPipeline();
if(processor.irqline && cpsr().i == 0) {
interrupt(Processor::Mode::IRQ, 0x18);
return;
}
instructions++;
if(trace) {
print(disassembleRegisters(), "\n");
print(disassembleInstructionARM(pipeline.execute.address), "\n");
usleep(100000);
}
if(condition(instruction() >> 28) == false) return;
#define decode(pattern, execute) if( \
(instruction() & std::integral_constant<uint32_t, bit::mask(pattern)>::value) \
== std::integral_constant<uint32_t, bit::test(pattern)>::value \
) return arm_op_ ## execute()
decode("???? 0001 0010 ++++ ++++ ++++ 0001 ????", branch_exchange_register);
decode("???? 0000 00?? ???? ???? ???? 1001 ????", multiply);
decode("???? 0000 1??? ???? ???? ???? 1001 ????", multiply_long);
decode("???? 0001 0?00 ++++ ???? ---- 0000 ----", move_to_register_from_status);
decode("???? 0001 0?00 ???? ???? ---- 1001 ????", memory_swap);
decode("???? 0001 0?10 ???? ++++ ---- 0000 ????", move_to_status_from_register);
decode("???? 0011 0?10 ???? ++++ ???? ???? ????", move_to_status_from_immediate);
decode("???? 000? ?0?1 ???? ???? ---- 11?1 ????", load_register);
decode("???? 000? ?1?1 ???? ???? ???? 11?1 ????", load_immediate);
decode("???? 000? ?0?? ???? ???? ---- 1011 ????", move_half_register);
decode("???? 000? ?1?? ???? ???? ???? 1011 ????", move_half_immediate);
decode("???? 000? ???? ???? ???? ???? ???0 ????", data_immediate_shift);
decode("???? 000? ???? ???? ???? ???? 0??1 ????", data_register_shift);
decode("???? 001? ???? ???? ???? ???? ???? ????", data_immediate);
decode("???? 010? ???? ???? ???? ???? ???? ????", move_immediate_offset);
decode("???? 011? ???? ???? ???? ???? ???0 ????", move_register_offset);
decode("???? 100? ???? ???? ???? ???? ???? ????", move_multiple);
decode("???? 101? ???? ???? ???? ???? ???? ????", branch);
decode("???? 1111 ???? ???? ???? ???? ???? ????", software_interrupt);
#undef decode
crash = true;
}
auto ARM::stepTHUMB() -> void {
if(pipeline.reload) {
pipeline.reload = false;
r(15).data &= ~1;
pipeline.fetch.address = r(15) & ~1;
pipeline.fetch.instruction = read(Prefetch | Half | Nonsequential, pipeline.fetch.address);
stepPipeline();
}
stepPipeline();
if(processor.irqline && cpsr().i == 0) {
interrupt(Processor::Mode::IRQ, 0x18);
r(14).data += 2;
return;
}
instructions++;
if(trace) {
print(disassembleRegisters(), "\n");
print(disassembleInstructionTHUMB(pipeline.execute.address), "\n");
}
#define decode(pattern, execute) if( \
(instruction() & std::integral_constant<uint32_t, bit::mask(pattern)>::value) \
== std::integral_constant<uint32_t, bit::test(pattern)>::value \
) return thumb_op_ ## execute()
decode("0001 10?? ???? ????", adjust_register);
decode("0001 11?? ???? ????", adjust_immediate);
decode("000? ???? ???? ????", shift_immediate);
decode("001? ???? ???? ????", immediate);
decode("0100 00?? ???? ????", alu);
decode("0100 0111 0??? ?---", branch_exchange);
decode("0100 01?? ???? ????", alu_hi);
decode("0100 1??? ???? ????", load_literal);
decode("0101 ???? ???? ????", move_register_offset);
decode("0110 ???? ???? ????", move_word_immediate);
decode("0111 ???? ???? ????", move_byte_immediate);
decode("1000 ???? ???? ????", move_half_immediate);
decode("1001 ???? ???? ????", move_stack);
decode("1010 ???? ???? ????", add_register_hi);
decode("1011 0000 ???? ????", adjust_stack);
decode("1011 ?10? ???? ????", stack_multiple);
decode("1100 ???? ???? ????", move_multiple);
decode("1101 1111 ???? ????", software_interrupt);
decode("1101 ???? ???? ????", branch_conditional);
decode("1110 0??? ???? ????", branch_short);
decode("1111 0??? ???? ????", branch_long_prefix);
decode("1111 1??? ???? ????", branch_long_suffix);
#undef decode
crash = true;
}

View File

@ -113,7 +113,7 @@ struct ARM7TDMI {
auto serialize(serializer&) -> void;
//disassembler.cpp
auto disassemble(maybe<uint32> pc = nothing, maybe<uint1> thumb = nothing) -> string;
auto disassemble(maybe<uint32> pc = nothing, maybe<boolean> thumb = nothing) -> string;
auto disassembleRegisters() -> string;
struct GPR {
@ -127,17 +127,18 @@ struct ARM7TDMI {
return *this;
}
inline auto operator=(const GPR& value) -> GPR& {
data = value.data;
if(modify) modify();
return *this;
}
uint32 data;
function<auto () -> void> modify;
};
struct PSR {
enum : uint {
USR26 = 0x00, //26-bit user
FIQ26 = 0x01, //26-bit fast interrupt
IRQ26 = 0x02, //26-bit interrupt
SVC26 = 0x03, //26-bit service
USR = 0x10, //user
FIQ = 0x11, //fast interrupt
IRQ = 0x12, //interrupt
@ -166,14 +167,14 @@ struct ARM7TDMI {
//serialization.cpp
auto serialize(serializer&) -> void;
uint5 m; //mode
uint1 t; //thumb
uint1 f; //fiq
uint1 i; //irq
uint1 v; //overflow
uint1 c; //carry
uint1 z; //zero
uint1 n; //negative
uint5 m; //mode
boolean t; //thumb
boolean f; //fiq
boolean i; //irq
boolean v; //overflow
boolean c; //carry
boolean z; //zero
boolean n; //negative
};
struct Processor {

View File

@ -11,7 +11,7 @@ static const string _conditions[] = {
#define _comp(mode) (mode >= 8 && mode <= 11)
#define _math(mode) (mode <= 7 || mode == 12 || mode == 14)
auto ARM7TDMI::disassemble(maybe<uint32> pc, maybe<uint1> thumb) -> string {
auto ARM7TDMI::disassemble(maybe<uint32> pc, maybe<boolean> thumb) -> string {
if(!pc) pc = pipeline.execute.address;
if(!thumb) thumb = cpsr().t;
@ -44,7 +44,7 @@ auto ARM7TDMI::disassembleRegisters() -> string {
output.append(hex(cpsr().m, 2L));
if(cpsr().m == PSR::USR || cpsr().m == PSR::SYS) return output;
output.append("spsr:");
output.append(" spsr:");
output.append(spsr().n ? "N" : "n");
output.append(spsr().z ? "Z" : "z");
output.append(spsr().c ? "C" : "c");
@ -189,7 +189,7 @@ auto ARM7TDMI::armDisassembleMoveMultiple
if(list.bit(index)) registers.append(_r[index], ",");
}
registers.trimRight(",", 1L);
return {mode ? "ldm" : "stm",
return {mode ? "ldm" : "stm", _c,
up == 0 && pre == 0 ? "da" : "",
up == 0 && pre == 1 ? "db" : "",
up == 1 && pre == 0 ? "ia" : "",
@ -306,12 +306,12 @@ auto ARM7TDMI::thumbDisassembleBranchFarPrefix
uint11 displacementLo = read(Half | Nonsequential, (_pc & ~1) + 2);
int22 displacement = displacementHi << 11 | displacementLo << 0;
uint32 address = _pc + 4 + displacement * 2;
return {"b 0x", hex(address, 8L)};
return {"bl 0x", hex(address, 8L)};
}
auto ARM7TDMI::thumbDisassembleBranchFarSuffix
(uint11 displacement) -> string {
return {"b (suffix)"};
return {"bl (suffix)"};
}
auto ARM7TDMI::thumbDisassembleBranchNear

View File

@ -30,8 +30,9 @@ auto ARM7TDMI::instruction() -> void {
fetch();
if(irq && !cpsr().i) {
bool t = cpsr().t;
interrupt(PSR::IRQ, 0x18);
if(cpsr().t) r(14).data += 2;
if(t) r(14).data += 2;
return;
}
@ -283,10 +284,10 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bits( 0, 3), /* d */ \
opcode.bits(12,15), /* d */ \
opcode.bit (22) /* mode */
for(uint1 mode : range(2)) {
auto opcode = pattern(".... 0001 0?00 ---- ---- ---- 0000 ????") | mode << 22;
auto opcode = pattern(".... 0001 0?00 ---- ???? ---- 0000 ----") | mode << 22;
bind(opcode, MoveToRegisterFromStatus);
}
#undef arguments

View File

@ -1,24 +1,26 @@
auto ARM7TDMI::armALU(uint4 mode, uint4 target, uint4 source, uint32 data) -> void {
auto ARM7TDMI::armALU(uint4 mode, uint4 d, uint4 n, uint32 rm) -> void {
uint32 rn = r(n);
switch(mode) {
case 0: r(target) = BIT(r(source) & data); break; //AND
case 1: r(target) = BIT(r(source) ^ data); break; //EOR
case 2: r(target) = SUB(r(source), data, 1); break; //SUB
case 3: r(target) = SUB(data, r(source), 1); break; //RSB
case 4: r(target) = ADD(r(source), data, 0); break; //ADD
case 5: r(target) = ADD(r(source), data, cpsr().c); break; //ADC
case 6: r(target) = SUB(r(source), data, cpsr().c); break; //SBC
case 7: r(target) = SUB(data, r(source), cpsr().c); break; //RSC
case 8: BIT(r(source) & data); break; //TST
case 9: BIT(r(source) ^ data); break; //TEQ
case 10: SUB(r(source), data, 1); break; //CMP
case 11: ADD(r(source), data, 0); break; //CMN
case 12: r(target) = BIT(r(source) | data); break; //ORR
case 13: r(target) = BIT(data); break; //MOV
case 14: r(target) = BIT(r(source) & ~data); break; //BIC
case 15: r(target) = BIT(~data); break; //MVN
case 0: r(d) = BIT(rn & rm); break; //AND
case 1: r(d) = BIT(rn ^ rm); break; //EOR
case 2: r(d) = SUB(rn, rm, 1); break; //SUB
case 3: r(d) = SUB(rm, rn, 1); break; //RSB
case 4: r(d) = ADD(rn, rm, 0); break; //ADD
case 5: r(d) = ADD(rn, rm, cpsr().c); break; //ADC
case 6: r(d) = SUB(rn, rm, cpsr().c); break; //SBC
case 7: r(d) = SUB(rm, rn, cpsr().c); break; //RSC
case 8: BIT(rn & rm); break; //TST
case 9: BIT(rn ^ rm); break; //TEQ
case 10: SUB(rn, rm, 1); break; //CMP
case 11: ADD(rn, rm, 0); break; //CMN
case 12: r(d) = BIT(rn | rm); break; //ORR
case 13: r(d) = BIT(rm); break; //MOV
case 14: r(d) = BIT(rn & ~rm); break; //BIC
case 15: r(d) = BIT(~rm); break; //MVN
}
if(exception() && target == 15 && opcode.bit(20)) {
if(exception() && d == 15 && opcode.bit(20)) {
cpsr() = spsr();
}
}
@ -29,7 +31,7 @@ auto ARM7TDMI::armMoveToStatus(uint4 field, uint1 mode, uint32 data) -> void {
if(field.bit(0)) {
if(mode || privileged()) {
psr.m = 0x10 | data.bits(0,4);
psr.m = data.bits(0,4);
psr.t = data.bit (5);
psr.f = data.bit (6);
psr.i = data.bit (7);

View File

@ -12,11 +12,11 @@ auto ARM7TDMI::load(uint mode, uint32 address) -> uint32 {
auto word = get(Load | mode, address);
if(mode & Half) {
address &= 1;
word = mode & Signed ? (uint16)(int16)word : (uint16)word;
word = mode & Signed ? (uint32)(int16)word : (uint32)(uint16)word;
}
if(mode & Byte) {
address &= 0;
word = mode & Signed ? (uint8)(int8)word : (uint8)word;
word = mode & Signed ? (uint32)(int8)word : (uint32)(uint8)word;
}
if(mode & Signed) {
word = ASR(word, address.bits(0,1) << 3);

View File

@ -47,13 +47,13 @@ auto ARM7TDMI::Processor::serialize(serializer& s) -> void {
auto ARM7TDMI::PSR::serialize(serializer& s) -> void {
s.integer(m);
s.integer(t);
s.integer(f);
s.integer(i);
s.integer(v);
s.integer(c);
s.integer(z);
s.integer(n);
s.boolean(t);
s.boolean(f);
s.boolean(i);
s.boolean(v);
s.boolean(c);
s.boolean(z);
s.boolean(n);
}
auto ARM7TDMI::Pipeline::serialize(serializer& s) -> void {

View File

@ -10,11 +10,11 @@ auto V30MZ::parity(uint8 value) const -> bool {
#define mask (size == Byte ? 0xff : 0xffff)
#define sign (size == Byte ? 0x80 : 0x8000)
auto V30MZ::alAdc(Size size, uint16 x, uint16 y) -> uint16 {
return alAdd(size, x, y + r.f.c);
auto V30MZ::ADC(Size size, uint16 x, uint16 y) -> uint16 {
return ADD(size, x, y + r.f.c);
}
auto V30MZ::alAdd(Size size, uint16 x, uint16 y) -> uint16 {
auto V30MZ::ADD(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x + y) & mask;
r.f.c = x + y > mask;
r.f.p = parity(result);
@ -25,7 +25,7 @@ auto V30MZ::alAdd(Size size, uint16 x, uint16 y) -> uint16 {
return result;
}
auto V30MZ::alAnd(Size size, uint16 x, uint16 y) -> uint16 {
auto V30MZ::AND(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x & y) & mask;
r.f.c = 0;
r.f.p = parity(result);
@ -36,7 +36,7 @@ auto V30MZ::alAnd(Size size, uint16 x, uint16 y) -> uint16 {
return result;
}
auto V30MZ::alDec(Size size, uint16 x) -> uint16 {
auto V30MZ::DEC(Size size, uint16 x) -> uint16 {
uint16 result = (x - 1) & mask;
r.f.p = parity(result);
r.f.h = (x & 0x0f) == 0;
@ -46,14 +46,14 @@ auto V30MZ::alDec(Size size, uint16 x) -> uint16 {
return result;
}
auto V30MZ::alDiv(Size size, uint32 x, uint32 y) -> uint32 {
auto V30MZ::DIV(Size size, uint32 x, uint32 y) -> uint32 {
if(y == 0) return interrupt(0), 0;
uint32 quotient = x / y;
uint32 remainder = x % y;
return (remainder & mask) << bits | (quotient & mask);
}
auto V30MZ::alDivi(Size size, int32 x, int32 y) -> uint32 {
auto V30MZ::DIVI(Size size, int32 x, int32 y) -> uint32 {
if(y == 0) return interrupt(0), 0;
x = size == Byte ? (int8_t)x : (int16_t)x;
y = size == Byte ? (int8_t)y : (int16_t)y;
@ -62,7 +62,7 @@ auto V30MZ::alDivi(Size size, int32 x, int32 y) -> uint32 {
return (remainder & mask) << bits | (quotient & mask);
}
auto V30MZ::alInc(Size size, uint16 x) -> uint16 {
auto V30MZ::INC(Size size, uint16 x) -> uint16 {
uint16 result = (x + 1) & mask;
r.f.p = parity(result);
r.f.h = (x & 0x0f) == 0x0f;
@ -72,14 +72,14 @@ auto V30MZ::alInc(Size size, uint16 x) -> uint16 {
return result;
}
auto V30MZ::alMul(Size size, uint16 x, uint16 y) -> uint32 {
auto V30MZ::MUL(Size size, uint16 x, uint16 y) -> uint32 {
uint32 result = x * y;
r.f.c = result >> bits;
r.f.v = result >> bits;
return result;
}
auto V30MZ::alMuli(Size size, int16 x, int16 y) -> uint32 {
auto V30MZ::MULI(Size size, int16 x, int16 y) -> uint32 {
x = size == Byte ? (int8_t)x : (int16_t)x;
y = size == Byte ? (int8_t)y : (int16_t)y;
uint32 result = x * y;
@ -88,7 +88,7 @@ auto V30MZ::alMuli(Size size, int16 x, int16 y) -> uint32 {
return result;
}
auto V30MZ::alNeg(Size size, uint16 x) -> uint16 {
auto V30MZ::NEG(Size size, uint16 x) -> uint16 {
uint16 result = (-x) & mask;
r.f.c = x;
r.f.p = parity(result);
@ -99,12 +99,12 @@ auto V30MZ::alNeg(Size size, uint16 x) -> uint16 {
return result;
}
auto V30MZ::alNot(Size size, uint16 x) -> uint16 {
auto V30MZ::NOT(Size size, uint16 x) -> uint16 {
uint16 result = (~x) & mask;
return result;
}
auto V30MZ::alOr(Size size, uint16 x, uint16 y) -> uint16 {
auto V30MZ::OR(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x | y) & mask;
r.f.c = 0;
r.f.p = parity(result);
@ -115,7 +115,7 @@ auto V30MZ::alOr(Size size, uint16 x, uint16 y) -> uint16 {
return result;
}
auto V30MZ::alRcl(Size size, uint16 x, uint5 y) -> uint16 {
auto V30MZ::RCL(Size size, uint16 x, uint5 y) -> uint16 {
uint16 result = x;
for(uint n = 0; n < y; n++) {
bool carry = result & sign;
@ -126,7 +126,7 @@ auto V30MZ::alRcl(Size size, uint16 x, uint5 y) -> uint16 {
return result & mask;
}
auto V30MZ::alRcr(Size size, uint16 x, uint5 y) -> uint16 {
auto V30MZ::RCR(Size size, uint16 x, uint5 y) -> uint16 {
uint16 result = x;
for(uint n = 0; n < y; n++) {
bool carry = result & 1;
@ -137,21 +137,21 @@ auto V30MZ::alRcr(Size size, uint16 x, uint5 y) -> uint16 {
return result & mask;
}
auto V30MZ::alRol(Size size, uint16 x, uint4 y) -> uint16 {
auto V30MZ::ROL(Size size, uint16 x, uint4 y) -> uint16 {
r.f.c = (x << y) & (1 << bits);
uint16 result = ((x << y) | (x >> (bits - y))) & mask;
r.f.v = (x ^ result) & sign;
return result;
}
auto V30MZ::alRor(Size size, uint16 x, uint4 y) -> uint16 {
auto V30MZ::ROR(Size size, uint16 x, uint4 y) -> uint16 {
r.f.c = (x >> (y - 1)) & 1;
uint16 result = ((x >> y) | (x << (bits - y))) & mask;
r.f.v = (x ^ result) & sign;
return result;
}
auto V30MZ::alSal(Size size, uint16 x, uint5 y) -> uint16 {
auto V30MZ::SAL(Size size, uint16 x, uint5 y) -> uint16 {
r.f.c = (x << y) & (1 << bits);
uint16 result = (x << y) & mask;
r.f.p = parity(result);
@ -161,7 +161,7 @@ auto V30MZ::alSal(Size size, uint16 x, uint5 y) -> uint16 {
return result;
}
auto V30MZ::alSar(Size size, uint16 x, uint5 y) -> uint16 {
auto V30MZ::SAR(Size size, uint16 x, uint5 y) -> uint16 {
if(y & 16) {
r.f.c = x & sign;
return 0 - r.f.c;
@ -176,11 +176,11 @@ auto V30MZ::alSar(Size size, uint16 x, uint5 y) -> uint16 {
return result;
}
auto V30MZ::alSbb(Size size, uint16 x, uint16 y) -> uint16 {
return alSub(size, x, y + r.f.c);
auto V30MZ::SBB(Size size, uint16 x, uint16 y) -> uint16 {
return SUB(size, x, y + r.f.c);
}
auto V30MZ::alShl(Size size, uint16 x, uint5 y) -> uint16 {
auto V30MZ::SHL(Size size, uint16 x, uint5 y) -> uint16 {
r.f.c = (x << y) & (1 << bits);
uint16 result = (x << y) & mask;
r.f.p = parity(result);
@ -190,7 +190,7 @@ auto V30MZ::alShl(Size size, uint16 x, uint5 y) -> uint16 {
return result;
}
auto V30MZ::alShr(Size size, uint16 x, uint5 y) -> uint16 {
auto V30MZ::SHR(Size size, uint16 x, uint5 y) -> uint16 {
r.f.c = (x >> (y - 1)) & 1;
uint16 result = (x >> y) & mask;
r.f.p = parity(result);
@ -200,7 +200,7 @@ auto V30MZ::alShr(Size size, uint16 x, uint5 y) -> uint16 {
return result;
}
auto V30MZ::alSub(Size size, uint16 x, uint16 y) -> uint16 {
auto V30MZ::SUB(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x - y) & mask;
r.f.c = y > x;
r.f.p = parity(result);
@ -211,7 +211,7 @@ auto V30MZ::alSub(Size size, uint16 x, uint16 y) -> uint16 {
return result;
}
auto V30MZ::alXor(Size size, uint16 x, uint16 y) -> uint16 {
auto V30MZ::XOR(Size size, uint16 x, uint16 y) -> uint16 {
uint16 result = (x ^ y) & mask;
r.f.c = 0;
r.f.p = parity(result);

View File

@ -28,263 +28,267 @@ auto V30MZ::interrupt(uint8 vector) -> void {
r.cs = cs;
}
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__);
auto V30MZ::instruction() -> void {
switch(opcode = fetch()) {
case 0x00: return opAddMemReg(Byte);
case 0x01: return opAddMemReg(Word);
case 0x02: return opAddRegMem(Byte);
case 0x03: return opAddRegMem(Word);
case 0x04: return opAddAccImm(Byte);
case 0x05: return opAddAccImm(Word);
case 0x06: return opPushReg(r.es);
case 0x07: return opPopReg(r.es);
case 0x08: return opOrMemReg(Byte);
case 0x09: return opOrMemReg(Word);
case 0x0a: return opOrRegMem(Byte);
case 0x0b: return opOrRegMem(Word);
case 0x0c: return opOrAccImm(Byte);
case 0x0d: return opOrAccImm(Word);
case 0x0e: return opPushReg(r.cs);
case 0x0f: return; //pop cs
case 0x10: return opAdcMemReg(Byte);
case 0x11: return opAdcMemReg(Word);
case 0x12: return opAdcRegMem(Byte);
case 0x13: return opAdcRegMem(Word);
case 0x14: return opAdcAccImm(Byte);
case 0x15: return opAdcAccImm(Word);
case 0x16: return opPushReg(r.ss);
case 0x17: return opPopReg(r.ss);
case 0x18: return opSbbMemReg(Byte);
case 0x19: return opSbbMemReg(Word);
case 0x1a: return opSbbRegMem(Byte);
case 0x1b: return opSbbRegMem(Word);
case 0x1c: return opSbbAccImm(Byte);
case 0x1d: return opSbbAccImm(Word);
case 0x1e: return opPushReg(r.ds);
case 0x1f: return opPopReg(r.ds);
case 0x20: return opAndMemReg(Byte);
case 0x21: return opAndMemReg(Word);
case 0x22: return opAndRegMem(Byte);
case 0x23: return opAndRegMem(Word);
case 0x24: return opAndAccImm(Byte);
case 0x25: return opAndAccImm(Word);
case 0x26: return opSegment(r.es);
case 0x27: return opDecimalAdjust(0); //daa
case 0x28: return opSubMemReg(Byte);
case 0x29: return opSubMemReg(Word);
case 0x2a: return opSubRegMem(Byte);
case 0x2b: return opSubRegMem(Word);
case 0x2c: return opSubAccImm(Byte);
case 0x2d: return opSubAccImm(Word);
case 0x2e: return opSegment(r.cs);
case 0x2f: return opDecimalAdjust(1); //das
case 0x30: return opXorMemReg(Byte);
case 0x31: return opXorMemReg(Word);
case 0x32: return opXorRegMem(Byte);
case 0x33: return opXorRegMem(Word);
case 0x34: return opXorAccImm(Byte);
case 0x35: return opXorAccImm(Word);
case 0x36: return opSegment(r.ss);
case 0x37: return opAsciiAdjust(0); //aaa
case 0x38: return opCmpMemReg(Byte);
case 0x39: return opCmpMemReg(Word);
case 0x3a: return opCmpRegMem(Byte);
case 0x3b: return opCmpRegMem(Word);
case 0x3c: return opCmpAccImm(Byte);
case 0x3d: return opCmpAccImm(Word);
case 0x3e: return opSegment(r.ds);
case 0x3f: return opAsciiAdjust(1); //aas
case 0x40: return opIncReg(r.ax);
case 0x41: return opIncReg(r.cx);
case 0x42: return opIncReg(r.dx);
case 0x43: return opIncReg(r.bx);
case 0x44: return opIncReg(r.sp);
case 0x45: return opIncReg(r.bp);
case 0x46: return opIncReg(r.si);
case 0x47: return opIncReg(r.di);
case 0x48: return opDecReg(r.ax);
case 0x49: return opDecReg(r.cx);
case 0x4a: return opDecReg(r.dx);
case 0x4b: return opDecReg(r.bx);
case 0x4c: return opDecReg(r.sp);
case 0x4d: return opDecReg(r.bp);
case 0x4e: return opDecReg(r.si);
case 0x4f: return opDecReg(r.di);
case 0x50: return opPushReg(r.ax);
case 0x51: return opPushReg(r.cx);
case 0x52: return opPushReg(r.dx);
case 0x53: return opPushReg(r.bx);
case 0x54: return opPushReg(r.sp);
case 0x55: return opPushReg(r.bp);
case 0x56: return opPushReg(r.si);
case 0x57: return opPushReg(r.di);
case 0x58: return opPopReg(r.ax);
case 0x59: return opPopReg(r.cx);
case 0x5a: return opPopReg(r.dx);
case 0x5b: return opPopReg(r.bx);
case 0x5c: return opPopReg(r.sp);
case 0x5d: return opPopReg(r.bp);
case 0x5e: return opPopReg(r.si);
case 0x5f: return opPopReg(r.di);
case 0x60: return opPushAll();
case 0x61: return opPopAll();
case 0x62: return opBound();
case 0x63: return;
case 0x64: return;
case 0x65: return;
case 0x66: return;
case 0x67: return;
case 0x68: return opPushImm(Word);
case 0x69: return opMultiplySignedRegMemImm(Word);
case 0x6a: return opPushImm(Byte);
case 0x6b: return opMultiplySignedRegMemImm(Byte);
case 0x6c: return opInString(Byte);
case 0x6d: return opInString(Word);
case 0x6e: return opOutString(Byte);
case 0x6f: return opOutString(Word);
case 0x70: return opJumpIf(r.f.v == 1);
case 0x71: return opJumpIf(r.f.v == 0);
case 0x72: return opJumpIf(r.f.c == 1);
case 0x73: return opJumpIf(r.f.c == 0);
case 0x74: return opJumpIf(r.f.z == 1);
case 0x75: return opJumpIf(r.f.z == 0);
case 0x76: return opJumpIf(r.f.z == 1 || r.f.c == 1);
case 0x77: return opJumpIf(r.f.z != 1 && r.f.c != 1);
case 0x78: return opJumpIf(r.f.s == 1);
case 0x79: return opJumpIf(r.f.s == 0);
case 0x7a: return opJumpIf(r.f.p == 1);
case 0x7b: return opJumpIf(r.f.p == 0);
case 0x7c: return opJumpIf(r.f.s != r.f.v && r.f.z == 0);
case 0x7d: return opJumpIf(r.f.s == r.f.v || r.f.z == 1);
case 0x7e: return opJumpIf(r.f.s != r.f.v || r.f.z == 1);
case 0x7f: return opJumpIf(r.f.s == r.f.v && r.f.z == 0);
case 0x80: return opGroup1MemImm(Byte, 0);
case 0x81: return opGroup1MemImm(Word, 0);
case 0x82: return opGroup1MemImm(Byte, 1);
case 0x83: return opGroup1MemImm(Word, 1);
case 0x84: return opTestMemReg(Byte);
case 0x85: return opTestMemReg(Word);
case 0x86: return opExchangeMemReg(Byte);
case 0x87: return opExchangeMemReg(Word);
case 0x88: return opMoveMemReg(Byte);
case 0x89: return opMoveMemReg(Word);
case 0x8a: return opMoveRegMem(Byte);
case 0x8b: return opMoveRegMem(Word);
case 0x8c: return opMoveMemSeg();
case 0x8d: return opLoadEffectiveAddressRegMem();
case 0x8e: return opMoveSegMem();
case 0x8f: return opPopMem();
case 0x90: return opNop();
case 0x91: return opExchange(r.ax, r.cx);
case 0x92: return opExchange(r.ax, r.dx);
case 0x93: return opExchange(r.ax, r.bx);
case 0x94: return opExchange(r.ax, r.sp);
case 0x95: return opExchange(r.ax, r.bp);
case 0x96: return opExchange(r.ax, r.si);
case 0x97: return opExchange(r.ax, r.di);
case 0x98: return opSignExtendByte();
case 0x99: return opSignExtendWord();
case 0x9a: return opCallFar();
case 0x9b: return opWait();
case 0x9c: return opPushFlags();
case 0x9d: return opPopFlags();
case 0x9e: return opStoreFlagsAcc();
case 0x9f: return opLoadAccFlags();
case 0xa0: return opMoveAccMem(Byte);
case 0xa1: return opMoveAccMem(Word);
case 0xa2: return opMoveMemAcc(Byte);
case 0xa3: return opMoveMemAcc(Word);
case 0xa4: return opMoveString(Byte);
case 0xa5: return opMoveString(Word);
case 0xa6: return opCompareString(Byte);
case 0xa7: return opCompareString(Word);
case 0xa8: return opTestAcc(Byte);
case 0xa9: return opTestAcc(Word);
case 0xaa: return opStoreString(Byte);
case 0xab: return opStoreString(Word);
case 0xac: return opLoadString(Byte);
case 0xad: return opLoadString(Word);
case 0xae: return opScanString(Byte);
case 0xaf: return opScanString(Word);
case 0xb0: return opMoveRegImm(r.al);
case 0xb1: return opMoveRegImm(r.cl);
case 0xb2: return opMoveRegImm(r.dl);
case 0xb3: return opMoveRegImm(r.bl);
case 0xb4: return opMoveRegImm(r.ah);
case 0xb5: return opMoveRegImm(r.ch);
case 0xb6: return opMoveRegImm(r.dh);
case 0xb7: return opMoveRegImm(r.bh);
case 0xb8: return opMoveRegImm(r.ax);
case 0xb9: return opMoveRegImm(r.cx);
case 0xba: return opMoveRegImm(r.dx);
case 0xbb: return opMoveRegImm(r.bx);
case 0xbc: return opMoveRegImm(r.sp);
case 0xbd: return opMoveRegImm(r.bp);
case 0xbe: return opMoveRegImm(r.si);
case 0xbf: return opMoveRegImm(r.di);
case 0xc0: return opGroup2MemImm(Byte);
case 0xc1: return opGroup2MemImm(Word);
case 0xc2: return opReturnImm();
case 0xc3: return opReturn();
case 0xc4: return opLoadSegmentMem(r.es);
case 0xc5: return opLoadSegmentMem(r.ds);
case 0xc6: return opMoveMemImm(Byte);
case 0xc7: return opMoveMemImm(Word);
case 0xc8: return opEnter();
case 0xc9: return opLeave();
case 0xca: return opReturnFarImm();
case 0xcb: return opReturnFar();
case 0xcc: return opInt3();
case 0xcd: return opIntImm();
case 0xce: return opInto();
case 0xcf: return opReturnInt();
case 0xd0: return opGroup2MemImm(Byte, (uint8)1);
case 0xd1: return opGroup2MemImm(Word, (uint8)1);
case 0xd2: return opGroup2MemImm(Byte, (uint8)r.cl);
case 0xd3: return opGroup2MemImm(Word, (uint8)r.cl);
case 0xd4: return opAdjustAfterMultiply();
case 0xd5: return opAdjustAfterDivide();
case 0xd6: return;
case 0xd7: return opTranslate();
case 0xd8: return; //fpo1
case 0xd9: return; //fpo1
case 0xda: return; //fpo1
case 0xdb: return; //fpo1
case 0xdc: return; //fpo1
case 0xdd: return; //fpo1
case 0xde: return; //fpo1
case 0xdf: return; //fpo1
case 0xe0: return opLoopWhile(0); //loopnz
case 0xe1: return opLoopWhile(1); //loopz
case 0xe2: return opLoop();
case 0xe3: return opJumpIf(r.cx == 0);
case 0xe4: return opIn(Byte);
case 0xe5: return opIn(Word);
case 0xe6: return opOut(Byte);
case 0xe7: return opOut(Word);
case 0xe8: return opCallNear();
case 0xe9: return opJumpNear();
case 0xea: return opJumpFar();
case 0xeb: return opJumpShort();
case 0xec: return opInDX(Byte);
case 0xed: return opInDX(Word);
case 0xee: return opOutDX(Byte);
case 0xef: return opOutDX(Word);
case 0xf0: return opLock();
case 0xf1: return;
case 0xf2: return opRepeat(0); //repnz
case 0xf3: return opRepeat(1); //repz
case 0xf4: return opHalt();
case 0xf5: return opComplementCarry();
case 0xf6: return opGroup3MemImm(Byte);
case 0xf7: return opGroup3MemImm(Word);
case 0xf8: return opClearFlag(r.f.c.bit);
case 0xf9: return opSetFlag(r.f.c.bit);
case 0xfa: return opClearFlag(r.f.i.bit);
case 0xfb: return opSetFlag(r.f.i.bit);
case 0xfc: return opClearFlag(r.f.d.bit);
case 0xfd: return opSetFlag(r.f.d.bit);
case 0xfe: return opGroup4MemImm(Byte);
case 0xff: return opGroup4MemImm(Word);
op(0x00, AddMemReg, Byte)
op(0x01, AddMemReg, Word)
op(0x02, AddRegMem, Byte)
op(0x03, AddRegMem, Word)
op(0x04, AddAccImm, Byte)
op(0x05, AddAccImm, Word)
op(0x06, PushReg, r.es)
op(0x07, PopReg, r.es)
op(0x08, OrMemReg, Byte)
op(0x09, OrMemReg, Word)
op(0x0a, OrRegMem, Byte)
op(0x0b, OrRegMem, Word)
op(0x0c, OrAccImm, Byte)
op(0x0d, OrAccImm, Word)
op(0x0e, PushReg, r.cs)
//op(0x0f, ...) //pop cs
op(0x10, AdcMemReg, Byte)
op(0x11, AdcMemReg, Word)
op(0x12, AdcRegMem, Byte)
op(0x13, AdcRegMem, Word)
op(0x14, AdcAccImm, Byte)
op(0x15, AdcAccImm, Word)
op(0x16, PushReg, r.ss)
op(0x17, PopReg, r.ss)
op(0x18, SbbMemReg, Byte)
op(0x19, SbbMemReg, Word)
op(0x1a, SbbRegMem, Byte)
op(0x1b, SbbRegMem, Word)
op(0x1c, SbbAccImm, Byte)
op(0x1d, SbbAccImm, Word)
op(0x1e, PushReg, r.ds)
op(0x1f, PopReg, r.ds)
op(0x20, AndMemReg, Byte)
op(0x21, AndMemReg, Word)
op(0x22, AndRegMem, Byte)
op(0x23, AndRegMem, Word)
op(0x24, AndAccImm, Byte)
op(0x25, AndAccImm, Word)
op(0x26, Segment, r.es)
op(0x27, DecimalAdjust, 0) //daa
op(0x28, SubMemReg, Byte)
op(0x29, SubMemReg, Word)
op(0x2a, SubRegMem, Byte)
op(0x2b, SubRegMem, Word)
op(0x2c, SubAccImm, Byte)
op(0x2d, SubAccImm, Word)
op(0x2e, Segment, r.cs)
op(0x2f, DecimalAdjust, 1) //das
op(0x30, XorMemReg, Byte)
op(0x31, XorMemReg, Word)
op(0x32, XorRegMem, Byte)
op(0x33, XorRegMem, Word)
op(0x34, XorAccImm, Byte)
op(0x35, XorAccImm, Word)
op(0x36, Segment, r.ss)
op(0x37, AsciiAdjust, 0) //aaa
op(0x38, CmpMemReg, Byte)
op(0x39, CmpMemReg, Word)
op(0x3a, CmpRegMem, Byte)
op(0x3b, CmpRegMem, Word)
op(0x3c, CmpAccImm, Byte)
op(0x3d, CmpAccImm, Word)
op(0x3e, Segment, r.ds)
op(0x3f, AsciiAdjust, 1) //aas
op(0x40, IncReg, r.ax)
op(0x41, IncReg, r.cx)
op(0x42, IncReg, r.dx)
op(0x43, IncReg, r.bx)
op(0x44, IncReg, r.sp)
op(0x45, IncReg, r.bp)
op(0x46, IncReg, r.si)
op(0x47, IncReg, r.di)
op(0x48, DecReg, r.ax)
op(0x49, DecReg, r.cx)
op(0x4a, DecReg, r.dx)
op(0x4b, DecReg, r.bx)
op(0x4c, DecReg, r.sp)
op(0x4d, DecReg, r.bp)
op(0x4e, DecReg, r.si)
op(0x4f, DecReg, r.di)
op(0x50, PushReg, r.ax)
op(0x51, PushReg, r.cx)
op(0x52, PushReg, r.dx)
op(0x53, PushReg, r.bx)
op(0x54, PushReg, r.sp)
op(0x55, PushReg, r.bp)
op(0x56, PushReg, r.si)
op(0x57, PushReg, r.di)
op(0x58, PopReg, r.ax)
op(0x59, PopReg, r.cx)
op(0x5a, PopReg, r.dx)
op(0x5b, PopReg, r.bx)
op(0x5c, PopReg, r.sp)
op(0x5d, PopReg, r.bp)
op(0x5e, PopReg, r.si)
op(0x5f, PopReg, r.di)
op(0x60, PushAll)
op(0x61, PopAll)
op(0x62, Bound)
//op(0x63, ...)
//op(0x64, ...)
//op(0x65, ...)
//op(0x66, ...)
//op(0x67, ...)
op(0x68, PushImm, Word)
op(0x69, MultiplySignedRegMemImm, Word)
op(0x6a, PushImm, Byte)
op(0x6b, MultiplySignedRegMemImm, Byte)
op(0x6c, InString, Byte)
op(0x6d, InString, Word)
op(0x6e, OutString, Byte)
op(0x6f, OutString, Word)
op(0x70, JumpIf, r.f.v == 1)
op(0x71, JumpIf, r.f.v == 0)
op(0x72, JumpIf, r.f.c == 1)
op(0x73, JumpIf, r.f.c == 0)
op(0x74, JumpIf, r.f.z == 1)
op(0x75, JumpIf, r.f.z == 0)
op(0x76, JumpIf, r.f.z == 1 || r.f.c == 1)
op(0x77, JumpIf, r.f.z != 1 && r.f.c != 1)
op(0x78, JumpIf, r.f.s == 1)
op(0x79, JumpIf, r.f.s == 0)
op(0x7a, JumpIf, r.f.p == 1)
op(0x7b, JumpIf, r.f.p == 0)
op(0x7c, JumpIf, r.f.s != r.f.v && r.f.z == 0)
op(0x7d, JumpIf, r.f.s == r.f.v || r.f.z == 1)
op(0x7e, JumpIf, r.f.s != r.f.v || r.f.z == 1)
op(0x7f, JumpIf, r.f.s == r.f.v && r.f.z == 0)
op(0x80, Group1MemImm, Byte, 0)
op(0x81, Group1MemImm, Word, 0)
op(0x82, Group1MemImm, Byte, 1)
op(0x83, Group1MemImm, Word, 1)
op(0x84, TestMemReg, Byte)
op(0x85, TestMemReg, Word)
op(0x86, ExchangeMemReg, Byte)
op(0x87, ExchangeMemReg, Word)
op(0x88, MoveMemReg, Byte)
op(0x89, MoveMemReg, Word)
op(0x8a, MoveRegMem, Byte)
op(0x8b, MoveRegMem, Word)
op(0x8c, MoveMemSeg)
op(0x8d, LoadEffectiveAddressRegMem)
op(0x8e, MoveSegMem)
op(0x8f, PopMem)
op(0x90, Nop)
op(0x91, Exchange, r.ax, r.cx)
op(0x92, Exchange, r.ax, r.dx)
op(0x93, Exchange, r.ax, r.bx)
op(0x94, Exchange, r.ax, r.sp)
op(0x95, Exchange, r.ax, r.bp)
op(0x96, Exchange, r.ax, r.si)
op(0x97, Exchange, r.ax, r.di)
op(0x98, SignExtendByte)
op(0x99, SignExtendWord)
op(0x9a, CallFar)
op(0x9b, Wait)
op(0x9c, PushFlags)
op(0x9d, PopFlags)
op(0x9e, StoreFlagsAcc)
op(0x9f, LoadAccFlags)
op(0xa0, MoveAccMem, Byte)
op(0xa1, MoveAccMem, Word)
op(0xa2, MoveMemAcc, Byte)
op(0xa3, MoveMemAcc, Word)
op(0xa4, MoveString, Byte)
op(0xa5, MoveString, Word)
op(0xa6, CompareString, Byte)
op(0xa7, CompareString, Word)
op(0xa8, TestAcc, Byte)
op(0xa9, TestAcc, Word)
op(0xaa, StoreString, Byte)
op(0xab, StoreString, Word)
op(0xac, LoadString, Byte)
op(0xad, LoadString, Word)
op(0xae, ScanString, Byte)
op(0xaf, ScanString, Word)
op(0xb0, MoveRegImm, r.al)
op(0xb1, MoveRegImm, r.cl)
op(0xb2, MoveRegImm, r.dl)
op(0xb3, MoveRegImm, r.bl)
op(0xb4, MoveRegImm, r.ah)
op(0xb5, MoveRegImm, r.ch)
op(0xb6, MoveRegImm, r.dh)
op(0xb7, MoveRegImm, r.bh)
op(0xb8, MoveRegImm, r.ax)
op(0xb9, MoveRegImm, r.cx)
op(0xba, MoveRegImm, r.dx)
op(0xbb, MoveRegImm, r.bx)
op(0xbc, MoveRegImm, r.sp)
op(0xbd, MoveRegImm, r.bp)
op(0xbe, MoveRegImm, r.si)
op(0xbf, MoveRegImm, r.di)
op(0xc0, Group2MemImm, Byte)
op(0xc1, Group2MemImm, Word)
op(0xc2, ReturnImm)
op(0xc3, Return)
op(0xc4, LoadSegmentMem, r.es)
op(0xc5, LoadSegmentMem, r.ds)
op(0xc6, MoveMemImm, Byte)
op(0xc7, MoveMemImm, Word)
op(0xc8, Enter)
op(0xc9, Leave)
op(0xca, ReturnFarImm)
op(0xcb, ReturnFar)
op(0xcc, Int3)
op(0xcd, IntImm)
op(0xce, Into)
op(0xcf, ReturnInt)
op(0xd0, Group2MemImm, Byte, (uint8)1)
op(0xd1, Group2MemImm, Word, (uint8)1)
op(0xd2, Group2MemImm, Byte, (uint8)r.cl)
op(0xd3, Group2MemImm, Word, (uint8)r.cl)
op(0xd4, AdjustAfterMultiply)
op(0xd5, AdjustAfterDivide)
//op(0xd6, ...)
op(0xd7, Translate)
//op(0xd8, ...) //fpo1
//op(0xd9, ...) //fpo1
//op(0xda, ...) //fpo1
//op(0xdb, ...) //fpo1
//op(0xdc, ...) //fpo1
//op(0xdd, ...) //fpo1
//op(0xde, ...) //fpo1
//op(0xdf, ...) //fpo1
op(0xe0, LoopWhile, 0) //loopnz
op(0xe1, LoopWhile, 1) //loopz
op(0xe2, Loop)
op(0xe3, JumpIf, r.cx == 0)
op(0xe4, In, Byte)
op(0xe5, In, Word)
op(0xe6, Out, Byte)
op(0xe7, Out, Word)
op(0xe8, CallNear)
op(0xe9, JumpNear)
op(0xea, JumpFar)
op(0xeb, JumpShort)
op(0xec, InDX, Byte)
op(0xed, InDX, Word)
op(0xee, OutDX, Byte)
op(0xef, OutDX, Word)
op(0xf0, Lock)
//op(0xf1, ...)
op(0xf2, Repeat, 0) //repnz
op(0xf3, Repeat, 1) //repz
op(0xf4, Halt)
op(0xf5, ComplementCarry)
op(0xf6, Group3MemImm, Byte)
op(0xf7, Group3MemImm, Word)
op(0xf8, ClearFlag, r.f.c.bit)
op(0xf9, SetFlag, r.f.c.bit)
op(0xfa, ClearFlag, r.f.i.bit)
op(0xfb, SetFlag, r.f.i.bit)
op(0xfc, ClearFlag, r.f.d.bit)
op(0xfd, SetFlag, r.f.d.bit)
op(0xfe, Group4MemImm, Byte)
op(0xff, Group4MemImm, Word)
}
}
#undef op

View File

@ -1,6 +1,4 @@
//27 daa
//2f das
auto V30MZ::opDecimalAdjust(bool negate) {
auto V30MZ::instructionDecimalAdjust(bool negate) -> void {
wait(9);
uint8 al = r.al;
if(r.f.h || ((al & 0x0f) > 0x09)) {
@ -16,9 +14,7 @@ auto V30MZ::opDecimalAdjust(bool negate) {
r.f.p = parity(r.al);
}
//37 aaa
//3f aas
auto V30MZ::opAsciiAdjust(bool negate) {
auto V30MZ::instructionAsciiAdjust(bool negate) -> void {
wait(8);
if(r.f.h || ((r.al & 0x0f) > 0x09)) {
r.al += negate ? -0x06 : 0x06;
@ -32,8 +28,7 @@ auto V30MZ::opAsciiAdjust(bool negate) {
r.al &= 0x0f;
}
//d4 aam,immb
auto V30MZ::opAdjustAfterMultiply() {
auto V30MZ::instructionAdjustAfterMultiply() -> void {
wait(16);
auto imm = fetch();
if(imm == 0) return interrupt(0);
@ -44,8 +39,7 @@ auto V30MZ::opAdjustAfterMultiply() {
r.f.z = r.ax == 0;
}
//d5 aad,immw
auto V30MZ::opAdjustAfterDivide() {
auto V30MZ::instructionAdjustAfterDivide() -> void {
wait(5);
auto imm = fetch();
r.al += r.ah * imm;

View File

@ -1,172 +1,142 @@
//00 addb mem,reg
//01 addw mem,reg
auto V30MZ::opAddMemReg(Size size) {
auto V30MZ::instructionAddMemReg(Size size) -> void {
modRM();
setMem(size, alAdd(size, getMem(size), getReg(size)));
setMem(size, ADD(size, getMem(size), getReg(size)));
}
//02 addb reg,mem
//03 addw reg,mem
auto V30MZ::opAddRegMem(Size size) {
auto V30MZ::instructionAddRegMem(Size size) -> void {
modRM();
setReg(size, alAdd(size, getReg(size), getMem(size)));
setReg(size, ADD(size, getReg(size), getMem(size)));
}
//04 add al,#imm
//05 add ax,#imm
auto V30MZ::opAddAccImm(Size size) {
setAcc(size, alAdd(size, getAcc(size), fetch(size)));
auto V30MZ::instructionAddAccImm(Size size) -> void {
setAcc(size, ADD(size, getAcc(size), fetch(size)));
}
//08 orb mem,reg
//09 orb mem,reg
auto V30MZ::opOrMemReg(Size size) {
auto V30MZ::instructionOrMemReg(Size size) -> void {
modRM();
setMem(size, alOr(size, getMem(size), getReg(size)));
setMem(size, OR(size, getMem(size), getReg(size)));
}
//0a orb reg,mem
//0b orb reg,mem
auto V30MZ::opOrRegMem(Size size) {
auto V30MZ::instructionOrRegMem(Size size) -> void {
modRM();
setReg(size, alOr(size, getReg(size), getMem(size)));
setReg(size, OR(size, getReg(size), getMem(size)));
}
//0c or al,#imm
//0d or ax,#imm
auto V30MZ::opOrAccImm(Size size) {
setAcc(size, alOr(size, getAcc(size), fetch(size)));
auto V30MZ::instructionOrAccImm(Size size) -> void {
setAcc(size, OR(size, getAcc(size), fetch(size)));
}
auto V30MZ::opAdcMemReg(Size size) {
auto V30MZ::instructionAdcMemReg(Size size) -> void {
modRM();
setMem(size, alAdc(size, getMem(size), getReg(size)));
setMem(size, ADC(size, getMem(size), getReg(size)));
}
auto V30MZ::opAdcRegMem(Size size) {
auto V30MZ::instructionAdcRegMem(Size size) -> void {
modRM();
setReg(size, alAdc(size, getReg(size), getMem(size)));
setReg(size, ADC(size, getReg(size), getMem(size)));
}
auto V30MZ::opAdcAccImm(Size size) {
setAcc(size, alAdc(size, getAcc(size), fetch(size)));
auto V30MZ::instructionAdcAccImm(Size size) -> void {
setAcc(size, ADC(size, getAcc(size), fetch(size)));
}
auto V30MZ::opSbbMemReg(Size size) {
auto V30MZ::instructionSbbMemReg(Size size) -> void {
modRM();
setMem(size, alSbb(size, getMem(size), getReg(size)));
setMem(size, SBB(size, getMem(size), getReg(size)));
}
auto V30MZ::opSbbRegMem(Size size) {
auto V30MZ::instructionSbbRegMem(Size size) -> void {
modRM();
setReg(size, alSbb(size, getReg(size), getMem(size)));
setReg(size, SBB(size, getReg(size), getMem(size)));
}
auto V30MZ::opSbbAccImm(Size size) {
setAcc(size, alSbb(size, getAcc(size), fetch(size)));
auto V30MZ::instructionSbbAccImm(Size size) -> void {
setAcc(size, SBB(size, getAcc(size), fetch(size)));
}
auto V30MZ::opAndMemReg(Size size) {
auto V30MZ::instructionAndMemReg(Size size) -> void {
modRM();
setMem(size, alAnd(size, getMem(size), getReg(size)));
setMem(size, AND(size, getMem(size), getReg(size)));
}
auto V30MZ::opAndRegMem(Size size) {
auto V30MZ::instructionAndRegMem(Size size) -> void {
modRM();
setReg(size, alAnd(size, getReg(size), getMem(size)));
setReg(size, AND(size, getReg(size), getMem(size)));
}
auto V30MZ::opAndAccImm(Size size) {
setAcc(size, alAnd(size, getAcc(size), fetch(size)));
auto V30MZ::instructionAndAccImm(Size size) -> void {
setAcc(size, AND(size, getAcc(size), fetch(size)));
}
auto V30MZ::opSubMemReg(Size size) {
auto V30MZ::instructionSubMemReg(Size size) -> void {
modRM();
setMem(size, alSub(size, getMem(size), getReg(size)));
setMem(size, SUB(size, getMem(size), getReg(size)));
}
auto V30MZ::opSubRegMem(Size size) {
auto V30MZ::instructionSubRegMem(Size size) -> void {
modRM();
setReg(size, alSub(size, getReg(size), getMem(size)));
setReg(size, SUB(size, getReg(size), getMem(size)));
}
auto V30MZ::opSubAccImm(Size size) {
setAcc(size, alSub(size, getAcc(size), fetch(size)));
auto V30MZ::instructionSubAccImm(Size size) -> void {
setAcc(size, SUB(size, getAcc(size), fetch(size)));
}
auto V30MZ::opXorMemReg(Size size) {
auto V30MZ::instructionXorMemReg(Size size) -> void {
modRM();
setMem(size, alXor(size, getMem(size), getReg(size)));
setMem(size, XOR(size, getMem(size), getReg(size)));
}
auto V30MZ::opXorRegMem(Size size) {
auto V30MZ::instructionXorRegMem(Size size) -> void {
modRM();
setReg(size, alXor(size, getReg(size), getMem(size)));
setReg(size, XOR(size, getReg(size), getMem(size)));
}
auto V30MZ::opXorAccImm(Size size) {
setAcc(size, alXor(size, getAcc(size), fetch(size)));
auto V30MZ::instructionXorAccImm(Size size) -> void {
setAcc(size, XOR(size, getAcc(size), fetch(size)));
}
auto V30MZ::opCmpMemReg(Size size) {
auto V30MZ::instructionCmpMemReg(Size size) -> void {
modRM();
alSub(size, getMem(size), getReg(size));
SUB(size, getMem(size), getReg(size));
}
auto V30MZ::opCmpRegMem(Size size) {
auto V30MZ::instructionCmpRegMem(Size size) -> void {
modRM();
alSub(size, getReg(size), getMem(size));
SUB(size, getReg(size), getMem(size));
}
auto V30MZ::opCmpAccImm(Size size) {
alSub(size, getAcc(size), fetch(size));
auto V30MZ::instructionCmpAccImm(Size size) -> void {
SUB(size, getAcc(size), fetch(size));
}
auto V30MZ::opTestAcc(Size size) {
alAnd(size, getAcc(size), fetch(size));
auto V30MZ::instructionTestAcc(Size size) -> void {
AND(size, getAcc(size), fetch(size));
}
auto V30MZ::opTestMemReg(Size size) {
auto V30MZ::instructionTestMemReg(Size size) -> void {
modRM();
alAnd(size, getMem(size), getReg(size));
AND(size, getMem(size), getReg(size));
}
auto V30MZ::opMultiplySignedRegMemImm(Size size) {
auto V30MZ::instructionMultiplySignedRegMemImm(Size size) -> void {
wait(2);
modRM();
setReg(Word, alMuli(Word, getMem(Word), size == Word ? (int16_t)fetch(Word) : (int8_t)fetch(Byte)));
setReg(Word, MULI(Word, getMem(Word), size == Word ? (int16_t)fetch(Word) : (int8_t)fetch(Byte)));
}
//40 inc ax
//41 inc cx
//42 inc dx
//43 inc bx
//44 inc sp
//45 inc bp
//46 inc si
//47 inc di
auto V30MZ::opIncReg(uint16_t& reg) {
reg = alInc(Word, reg);
auto V30MZ::instructionIncReg(uint16_t& reg) -> void {
reg = INC(Word, reg);
}
//48 dec ax
//49 dec cx
//4a dec dx
//4b dec bx
//4c dec sp
//4d dec bp
//4e dec si
//4f dec di
auto V30MZ::opDecReg(uint16_t& reg) {
reg = alDec(Word, reg);
auto V30MZ::instructionDecReg(uint16_t& reg) -> void {
reg = DEC(Word, reg);
}
//98 cbw
auto V30MZ::opSignExtendByte() {
auto V30MZ::instructionSignExtendByte() -> void {
setAcc(Word, (int8)getAcc(Byte));
}
//99 cwd
auto V30MZ::opSignExtendWord() {
auto V30MZ::instructionSignExtendWord() -> void {
setAcc(Long, (int16)getAcc(Word));
}

View File

@ -1,4 +1,4 @@
auto V30MZ::opLoop() {
auto V30MZ::instructionLoop() -> void {
wait(1);
auto offset = (int8)fetch();
if(--r.cx) {
@ -7,7 +7,7 @@ auto V30MZ::opLoop() {
}
}
auto V30MZ::opLoopWhile(bool value) {
auto V30MZ::instructionLoopWhile(bool value) -> void {
wait(2);
auto offset = (int8)fetch();
if(--r.cx && r.f.z == value) {
@ -16,23 +16,23 @@ auto V30MZ::opLoopWhile(bool value) {
}
}
auto V30MZ::opJumpShort() {
auto V30MZ::instructionJumpShort() -> void {
wait(3);
auto offset = (int8)fetch();
r.ip += offset;
}
auto V30MZ::opJumpIf(bool condition) {
auto V30MZ::instructionJumpIf(bool condition) -> void {
auto offset = (int8)fetch();
if(condition) r.ip += offset;
}
auto V30MZ::opJumpNear() {
auto V30MZ::instructionJumpNear() -> void {
wait(3);
r.ip += (int16)fetch(Word);
}
auto V30MZ::opJumpFar() {
auto V30MZ::instructionJumpFar() -> void {
wait(6);
auto ip = fetch(Word);
auto cs = fetch(Word);
@ -40,14 +40,14 @@ auto V30MZ::opJumpFar() {
r.ip = ip;
}
auto V30MZ::opCallNear() {
auto V30MZ::instructionCallNear() -> void {
wait(4);
auto offset = (int16)fetch(Word);
push(r.ip);
r.ip += offset;
}
auto V30MZ::opCallFar() {
auto V30MZ::instructionCallFar() -> void {
wait(9);
auto ip = fetch(Word);
auto cs = fetch(Word);
@ -57,25 +57,25 @@ auto V30MZ::opCallFar() {
r.ip = ip;
}
auto V30MZ::opReturn() {
auto V30MZ::instructionReturn() -> void {
wait(5);
r.ip = pop();
}
auto V30MZ::opReturnImm() {
auto V30MZ::instructionReturnImm() -> void {
wait(5);
auto offset = fetch(Word);
r.ip = pop();
r.sp += offset;
}
auto V30MZ::opReturnFar() {
auto V30MZ::instructionReturnFar() -> void {
wait(7);
r.ip = pop();
r.cs = pop();
}
auto V30MZ::opReturnFarImm() {
auto V30MZ::instructionReturnFarImm() -> void {
wait(8);
auto offset = fetch(Word);
r.ip = pop();
@ -83,8 +83,7 @@ auto V30MZ::opReturnFarImm() {
r.sp += offset;
}
//cf iret
auto V30MZ::opReturnInt() {
auto V30MZ::instructionReturnInt() -> void {
wait(9);
r.ip = pop();
r.cs = pop();
@ -92,22 +91,22 @@ auto V30MZ::opReturnInt() {
state.poll = false;
}
auto V30MZ::opInt3() {
auto V30MZ::instructionInt3() -> void {
wait(8);
interrupt(3);
}
auto V30MZ::opIntImm() {
auto V30MZ::instructionIntImm() -> void {
wait(9);
interrupt(fetch());
}
auto V30MZ::opInto() {
auto V30MZ::instructionInto() -> void {
wait(5);
interrupt(4);
}
auto V30MZ::opEnter() {
auto V30MZ::instructionEnter() -> void {
wait(7);
auto offset = fetch(Word);
auto length = fetch(Byte) & 0x1f;
@ -126,36 +125,33 @@ auto V30MZ::opEnter() {
}
}
auto V30MZ::opLeave() {
auto V30MZ::instructionLeave() -> void {
wait(1);
r.sp = r.bp;
r.bp = pop();
}
auto V30MZ::opPushReg(uint16_t& reg) {
auto V30MZ::instructionPushReg(uint16_t& reg) -> void {
push(reg);
}
auto V30MZ::opPopReg(uint16_t& reg) {
auto V30MZ::instructionPopReg(uint16_t& reg) -> void {
reg = pop();
if(&reg == &r.ss) state.poll = false;
}
//9c pushf
auto V30MZ::opPushFlags() {
auto V30MZ::instructionPushFlags() -> void {
wait(1);
push(r.f);
}
//9d popf
auto V30MZ::opPopFlags() {
auto V30MZ::instructionPopFlags() -> void {
wait(2);
r.f = pop();
state.poll = false;
}
//60 pusha
auto V30MZ::opPushAll() {
auto V30MZ::instructionPushAll() -> void {
wait(8);
auto sp = r.sp;
push(r.ax);
@ -168,8 +164,7 @@ auto V30MZ::opPushAll() {
push(r.di);
}
//61 popa
auto V30MZ::opPopAll() {
auto V30MZ::instructionPopAll() -> void {
wait(7);
r.di = pop();
r.si = pop();
@ -182,15 +177,12 @@ auto V30MZ::opPopAll() {
//r.sp is not restored
}
//68 push imm16
//6a push imm8s
auto V30MZ::opPushImm(Size size) {
auto V30MZ::instructionPushImm(Size size) -> void {
if(size == Byte) push((int8)fetch(Byte));
if(size == Word) push(fetch(Word));
}
auto V30MZ::opPopMem() {
auto V30MZ::instructionPopMem() -> void {
modRM();
setMem(Word, pop());
}

View File

@ -1,27 +1,24 @@
//9e sahf
auto V30MZ::opStoreFlagsAcc() {
auto V30MZ::instructionStoreFlagsAcc() -> void {
wait(3);
r.f = (r.f & 0xff00) | r.ah;
}
//9f lahf
auto V30MZ::opLoadAccFlags() {
auto V30MZ::instructionLoadAccFlags() -> void {
wait(1);
r.ah = (r.f & 0x00ff);
}
//f5 cmc
auto V30MZ::opComplementCarry() {
auto V30MZ::instructionComplementCarry() -> void {
wait(3);
r.f.c = !r.f.c;
}
auto V30MZ::opClearFlag(uint bit) {
auto V30MZ::instructionClearFlag(uint bit) -> void {
wait(3);
r.f &= ~(1 << bit);
}
auto V30MZ::opSetFlag(uint bit) {
auto V30MZ::instructionSetFlag(uint bit) -> void {
wait(3);
r.f |= 1 << bit;
if(bit == r.f.i.bit) state.poll = false;

View File

@ -1,8 +1,4 @@
//80 grp1 memb,immb
//81 grp1 memw,immw
//82 grp1 memb,immbs
//83 grp1 memw,immbs
auto V30MZ::opGroup1MemImm(Size size, bool sign) {
auto V30MZ::instructionGroup1MemImm(Size size, bool sign) -> void {
modRM();
auto mem = getMem(size);
uint16 imm = 0;
@ -10,24 +6,18 @@ auto V30MZ::opGroup1MemImm(Size size, bool sign) {
else if(size == Byte) imm = fetch();
else imm = fetch(Word);
switch(modrm.reg) {
case 0: setMem(size, alAdd(size, mem, imm)); break;
case 1: setMem(size, alOr (size, mem, imm)); break;
case 2: setMem(size, alAdc(size, mem, imm)); break;
case 3: setMem(size, alSbb(size, mem, imm)); break;
case 4: setMem(size, alAnd(size, mem, imm)); break;
case 5: setMem(size, alSub(size, mem, imm)); break;
case 6: setMem(size, alXor(size, mem, imm)); break;
case 7: alSub(size, mem, imm); break;
case 0: setMem(size, ADD(size, mem, imm)); break;
case 1: setMem(size, OR (size, mem, imm)); break;
case 2: setMem(size, ADC(size, mem, imm)); break;
case 3: setMem(size, SBB(size, mem, imm)); break;
case 4: setMem(size, AND(size, mem, imm)); break;
case 5: setMem(size, SUB(size, mem, imm)); break;
case 6: setMem(size, XOR(size, mem, imm)); break;
case 7: SUB(size, mem, imm); break;
}
}
//c0 grp2 memb,imm8
//c1 grp2 memw,imm8
//d0 grp2 memb,1
//d1 grp2 memw,1
//d2 grp2 memb,cl
//d3 grp2 memw,cl
auto V30MZ::opGroup2MemImm(Size size, maybe<uint8> imm) {
auto V30MZ::instructionGroup2MemImm(Size size, maybe<uint8> imm) -> void {
modRM();
auto mem = getMem(size);
if(!imm) {
@ -35,46 +25,42 @@ auto V30MZ::opGroup2MemImm(Size size, maybe<uint8> imm) {
imm = fetch();
}
switch(modrm.reg) {
case 0: setMem(size, alRol(size, mem, *imm)); break;
case 1: setMem(size, alRor(size, mem, *imm)); break;
case 2: setMem(size, alRcl(size, mem, *imm)); break;
case 3: setMem(size, alRcr(size, mem, *imm)); break;
case 4: setMem(size, alShl(size, mem, *imm)); break;
case 5: setMem(size, alShr(size, mem, *imm)); break;
case 6: setMem(size, alSal(size, mem, *imm)); break;
case 7: setMem(size, alSar(size, mem, *imm)); break;
case 0: setMem(size, ROL(size, mem, *imm)); break;
case 1: setMem(size, ROR(size, mem, *imm)); break;
case 2: setMem(size, RCL(size, mem, *imm)); break;
case 3: setMem(size, RCR(size, mem, *imm)); break;
case 4: setMem(size, SHL(size, mem, *imm)); break;
case 5: setMem(size, SHR(size, mem, *imm)); break;
case 6: setMem(size, SAL(size, mem, *imm)); break;
case 7: setMem(size, SAR(size, mem, *imm)); break;
}
}
//f6 grp3 memb
//f7 grp3 memw
auto V30MZ::opGroup3MemImm(Size size) {
auto V30MZ::instructionGroup3MemImm(Size size) -> void {
modRM();
auto mem = getMem(size);
switch(modrm.reg) {
case 0: alAnd(size, mem, fetch(size)); break;
case 0: AND(size, mem, fetch(size)); break;
case 1: warning("[V30MZ] GRP3.1"); break;
case 2: wait(2); setMem(size, alNot(size, mem)); break;
case 3: wait(2); setMem(size, alNeg(size, mem)); break;
case 4: wait(2); setAcc(size * 2, alMul(size, getAcc(size), mem)); break;
case 5: wait(2); setAcc(size * 2, alMuli(size, getAcc(size), mem)); break; break;
case 6: wait(size == Byte ? 15 : 23); setAcc(size * 2, alDiv(size, getAcc(size * 2), mem)); break;
case 7: wait(size == Byte ? 17 : 24); setAcc(size * 2, alDivi(size, getAcc(size * 2), mem)); break;
case 2: wait(2); setMem(size, NOT(size, mem)); break;
case 3: wait(2); setMem(size, NEG(size, mem)); break;
case 4: wait(2); setAcc(size * 2, MUL(size, getAcc(size), mem)); break;
case 5: wait(2); setAcc(size * 2, MULI(size, getAcc(size), mem)); break; break;
case 6: wait(size == Byte ? 15 : 23); setAcc(size * 2, DIV(size, getAcc(size * 2), mem)); break;
case 7: wait(size == Byte ? 17 : 24); setAcc(size * 2, DIVI(size, getAcc(size * 2), mem)); break;
}
}
//fe grp4 memb
//ff grp4 memw
auto V30MZ::opGroup4MemImm(Size size) {
auto V30MZ::instructionGroup4MemImm(Size size) -> void {
modRM();
switch(modrm.reg) {
case 0:
wait(2);
setMem(size, alInc(size, getMem(size)));
setMem(size, INC(size, getMem(size)));
break;
case 1:
wait(2);
setMem(size, alDec(size, getMem(size)));
setMem(size, DEC(size, getMem(size)));
break;
case 2:
if(size == Byte) { warning("[V30MZ] GRP4.2"); break; }

View File

@ -1,17 +1,11 @@
//26 es:
//2e cs:
//36 ss:
//3e ds:
auto V30MZ::opSegment(uint16 segment) {
auto V30MZ::instructionSegment(uint16 segment) -> void {
if(prefixes.size() >= 7) prefixes.removeRight();
prefixes.prepend(opcode);
state.prefix = true;
state.poll = false;
}
//f2 repnz:
//f3 repz:
auto V30MZ::opRepeat(bool flag) {
auto V30MZ::instructionRepeat(bool flag) -> void {
if(prefixes.size() >= 7) prefixes.removeRight();
prefixes.prepend(opcode);
wait(4);
@ -19,56 +13,50 @@ auto V30MZ::opRepeat(bool flag) {
state.poll = false;
}
//f0 lock:
auto V30MZ::opLock() {
auto V30MZ::instructionLock() -> void {
if(prefixes.size() >= 7) prefixes.removeRight();
prefixes.prepend(opcode);
state.prefix = true;
state.poll = false;
}
//9b wait
auto V30MZ::opWait() {
auto V30MZ::instructionWait() -> void {
}
//f4 hlt
auto V30MZ::opHalt() {
auto V30MZ::instructionHalt() -> void {
wait(8);
state.halt = true;
}
//90 nop
auto V30MZ::opNop() {
auto V30MZ::instructionNop() -> void {
}
auto V30MZ::opIn(Size size) {
auto V30MZ::instructionIn(Size size) -> void {
wait(5);
setAcc(size, in(size, fetch()));
}
auto V30MZ::opOut(Size size) {
auto V30MZ::instructionOut(Size size) -> void {
wait(5);
out(size, fetch(), getAcc(size));
}
auto V30MZ::opInDX(Size size) {
auto V30MZ::instructionInDX(Size size) -> void {
wait(5);
setAcc(size, in(size, r.dx));
}
auto V30MZ::opOutDX(Size size) {
auto V30MZ::instructionOutDX(Size size) -> void {
wait(5);
out(size, r.dx, getAcc(size));
}
//d7 xlat
auto V30MZ::opTranslate() {
auto V30MZ::instructionTranslate() -> void {
wait(4);
r.al = read(Byte, segment(r.ds), r.bx + r.al);
}
//62 bound reg,mem,mem
auto V30MZ::opBound() {
auto V30MZ::instructionBound() -> void {
wait(12);
modRM();
auto lo = getMem(Word, 0);

View File

@ -1,57 +1,55 @@
auto V30MZ::opMoveMemReg(Size size) {
auto V30MZ::instructionMoveMemReg(Size size) -> void {
modRM();
setMem(size, getReg(size));
}
auto V30MZ::opMoveRegMem(Size size) {
auto V30MZ::instructionMoveRegMem(Size size) -> void {
modRM();
setReg(size, getMem(size));
}
//8c mov memw,seg
auto V30MZ::opMoveMemSeg() {
auto V30MZ::instructionMoveMemSeg() -> void {
modRM();
setMem(Word, getSeg());
state.poll = false;
}
//8e mov seg,memw
auto V30MZ::opMoveSegMem() {
auto V30MZ::instructionMoveSegMem() -> void {
wait(1);
modRM();
setSeg(getMem(Word));
if((modrm.reg & 3) == 3) state.poll = false;
}
auto V30MZ::opMoveAccMem(Size size) {
auto V30MZ::instructionMoveAccMem(Size size) -> void {
setAcc(size, read(size, segment(r.ds), fetch(Word)));
}
auto V30MZ::opMoveMemAcc(Size size) {
auto V30MZ::instructionMoveMemAcc(Size size) -> void {
write(size, segment(r.ds), fetch(Word), getAcc(size));
}
auto V30MZ::opMoveRegImm(uint8_t& reg) {
auto V30MZ::instructionMoveRegImm(uint8_t& reg) -> void {
reg = fetch(Byte);
}
auto V30MZ::opMoveRegImm(uint16_t& reg) {
auto V30MZ::instructionMoveRegImm(uint16_t& reg) -> void {
reg = fetch(Word);
}
auto V30MZ::opMoveMemImm(Size size) {
auto V30MZ::instructionMoveMemImm(Size size) -> void {
modRM();
setMem(size, fetch(size));
}
auto V30MZ::opExchange(uint16_t& x, uint16_t& y) {
auto V30MZ::instructionExchange(uint16_t& x, uint16_t& y) -> void {
wait(2);
uint16 z = x;
x = y;
y = z;
}
auto V30MZ::opExchangeMemReg(Size size) {
auto V30MZ::instructionExchangeMemReg(Size size) -> void {
wait(2);
modRM();
auto mem = getMem(size);
@ -60,12 +58,12 @@ auto V30MZ::opExchangeMemReg(Size size) {
setReg(size, mem);
}
auto V30MZ::opLoadEffectiveAddressRegMem() {
auto V30MZ::instructionLoadEffectiveAddressRegMem() -> void {
modRM();
setReg(Word, modrm.address);
}
auto V30MZ::opLoadSegmentMem(uint16_t& segment) {
auto V30MZ::instructionLoadSegmentMem(uint16_t& segment) -> void {
wait(5);
modRM();
setReg(Word, getMem(Word));

View File

@ -1,4 +1,4 @@
auto V30MZ::opInString(Size size) {
auto V30MZ::instructionInString(Size size) -> void {
wait(5);
if(!repeat() || r.cx) {
auto data = in(size, r.dx);
@ -12,7 +12,7 @@ auto V30MZ::opInString(Size size) {
}
}
auto V30MZ::opOutString(Size size) {
auto V30MZ::instructionOutString(Size size) -> void {
wait(6);
if(!repeat() || r.cx) {
auto data = read(size, segment(r.ds), r.si);
@ -26,7 +26,7 @@ auto V30MZ::opOutString(Size size) {
}
}
auto V30MZ::opMoveString(Size size) {
auto V30MZ::instructionMoveString(Size size) -> void {
wait(4);
if(!repeat() || r.cx) {
auto data = read(size, segment(r.ds), r.si);
@ -41,14 +41,14 @@ auto V30MZ::opMoveString(Size size) {
}
}
auto V30MZ::opCompareString(Size size) {
auto V30MZ::instructionCompareString(Size size) -> void {
wait(5);
if(!repeat() || r.cx) {
auto x = read(size, segment(r.ds), r.si);
auto y = read(size, r.es, r.di);
r.si += r.f.d ? -size : size;
r.di += r.f.d ? -size : size;
alSub(size, x, y);
SUB(size, x, y);
if(!repeat() || !--r.cx) return;
if(repeat() == RepeatWhileZero && r.f.z == 0) return;
@ -59,7 +59,7 @@ auto V30MZ::opCompareString(Size size) {
}
}
auto V30MZ::opStoreString(Size size) {
auto V30MZ::instructionStoreString(Size size) -> void {
wait(2);
if(!repeat() || r.cx) {
write(size, r.es, r.di, getAcc(size));
@ -72,9 +72,7 @@ auto V30MZ::opStoreString(Size size) {
}
}
//ac lodsb
//ad lodsw
auto V30MZ::opLoadString(Size size) {
auto V30MZ::instructionLoadString(Size size) -> void {
wait(2);
if(!repeat() || r.cx) {
setAcc(size, read(size, segment(r.ds), r.si));
@ -87,15 +85,13 @@ auto V30MZ::opLoadString(Size size) {
}
}
//ae scasb
//af scasw
auto V30MZ::opScanString(Size size) {
auto V30MZ::instructionScanString(Size size) -> void {
wait(3);
if(!repeat() || r.cx) {
auto x = getAcc(size);
auto y = read(size, r.es, r.di);
r.di += r.f.d ? -size : size;
alSub(size, x, y);
SUB(size, x, y);
if(!repeat() || !--r.cx) return;
if(repeat() == RepeatWhileZero && r.f.z == 0) return;

View File

@ -7,6 +7,7 @@ namespace Processor {
#include "modrm.cpp"
#include "memory.cpp"
#include "algorithms.cpp"
#include "instruction.cpp"
#include "instructions-adjust.cpp"
#include "instructions-alu.cpp"
#include "instructions-exec.cpp"
@ -15,7 +16,6 @@ namespace Processor {
#include "instructions-misc.cpp"
#include "instructions-move.cpp"
#include "instructions-string.cpp"
#include "instruction.cpp"
#include "serialization.cpp"
#include "disassembler.cpp"

View File

@ -63,147 +63,147 @@ struct V30MZ {
//algorithms.cpp
auto parity(uint8) const -> bool;
auto alAdc (Size, uint16, uint16) -> uint16;
auto alAdd (Size, uint16, uint16) -> uint16;
auto alAnd (Size, uint16, uint16) -> uint16;
auto alDec (Size, uint16 ) -> uint16;
auto alDiv (Size, uint32, uint32) -> uint32;
auto alDivi(Size, int32, int32) -> uint32;
auto alInc (Size, uint16 ) -> uint16;
auto alMul (Size, uint16, uint16) -> uint32;
auto alMuli(Size, int16, int16) -> uint32;
auto alNeg (Size, uint16 ) -> uint16;
auto alNot (Size, uint16 ) -> uint16;
auto alOr (Size, uint16, uint16) -> uint16;
auto alRcl (Size, uint16, uint5) -> uint16;
auto alRcr (Size, uint16, uint5) -> uint16;
auto alRol (Size, uint16, uint4) -> uint16;
auto alRor (Size, uint16, uint4) -> uint16;
auto alSal (Size, uint16, uint5) -> uint16;
auto alSar (Size, uint16, uint5) -> uint16;
auto alSbb (Size, uint16, uint16) -> uint16;
auto alSub (Size, uint16, uint16) -> uint16;
auto alShl (Size, uint16, uint5) -> uint16;
auto alShr (Size, uint16, uint5) -> uint16;
auto alXor (Size, uint16, uint16) -> uint16;
auto ADC (Size, uint16, uint16) -> uint16;
auto ADD (Size, uint16, uint16) -> uint16;
auto AND (Size, uint16, uint16) -> uint16;
auto DEC (Size, uint16 ) -> uint16;
auto DIV (Size, uint32, uint32) -> uint32;
auto DIVI(Size, int32, int32) -> uint32;
auto INC (Size, uint16 ) -> uint16;
auto MUL (Size, uint16, uint16) -> uint32;
auto MULI(Size, int16, int16) -> uint32;
auto NEG (Size, uint16 ) -> uint16;
auto NOT (Size, uint16 ) -> uint16;
auto OR (Size, uint16, uint16) -> uint16;
auto RCL (Size, uint16, uint5) -> uint16;
auto RCR (Size, uint16, uint5) -> uint16;
auto ROL (Size, uint16, uint4) -> uint16;
auto ROR (Size, uint16, uint4) -> uint16;
auto SAL (Size, uint16, uint5) -> uint16;
auto SAR (Size, uint16, uint5) -> uint16;
auto SBB (Size, uint16, uint16) -> uint16;
auto SUB (Size, uint16, uint16) -> uint16;
auto SHL (Size, uint16, uint5) -> uint16;
auto SHR (Size, uint16, uint5) -> uint16;
auto XOR (Size, uint16, uint16) -> uint16;
//instructions-adjust.cpp
auto opDecimalAdjust(bool);
auto opAsciiAdjust(bool);
auto opAdjustAfterMultiply();
auto opAdjustAfterDivide();
auto instructionDecimalAdjust(bool) -> void;
auto instructionAsciiAdjust(bool) -> void;
auto instructionAdjustAfterMultiply() -> void;
auto instructionAdjustAfterDivide() -> void;
//instructions-alu.cpp
auto opAddMemReg(Size);
auto opAddRegMem(Size);
auto opAddAccImm(Size);
auto opOrMemReg(Size);
auto opOrRegMem(Size);
auto opOrAccImm(Size);
auto opAdcMemReg(Size);
auto opAdcRegMem(Size);
auto opAdcAccImm(Size);
auto opSbbMemReg(Size);
auto opSbbRegMem(Size);
auto opSbbAccImm(Size);
auto opAndMemReg(Size);
auto opAndRegMem(Size);
auto opAndAccImm(Size);
auto opSubMemReg(Size);
auto opSubRegMem(Size);
auto opSubAccImm(Size);
auto opXorMemReg(Size);
auto opXorRegMem(Size);
auto opXorAccImm(Size);
auto opCmpMemReg(Size);
auto opCmpRegMem(Size);
auto opCmpAccImm(Size);
auto opTestMemReg(Size);
auto opTestAcc(Size);
auto opMultiplySignedRegMemImm(Size);
auto opIncReg(uint16_t&);
auto opDecReg(uint16_t&);
auto opSignExtendByte();
auto opSignExtendWord();
auto instructionAddMemReg(Size) -> void;
auto instructionAddRegMem(Size) -> void;
auto instructionAddAccImm(Size) -> void;
auto instructionOrMemReg(Size) -> void;
auto instructionOrRegMem(Size) -> void;
auto instructionOrAccImm(Size) -> void;
auto instructionAdcMemReg(Size) -> void;
auto instructionAdcRegMem(Size) -> void;
auto instructionAdcAccImm(Size) -> void;
auto instructionSbbMemReg(Size) -> void;
auto instructionSbbRegMem(Size) -> void;
auto instructionSbbAccImm(Size) -> void;
auto instructionAndMemReg(Size) -> void;
auto instructionAndRegMem(Size) -> void;
auto instructionAndAccImm(Size) -> void;
auto instructionSubMemReg(Size) -> void;
auto instructionSubRegMem(Size) -> void;
auto instructionSubAccImm(Size) -> void;
auto instructionXorMemReg(Size) -> void;
auto instructionXorRegMem(Size) -> void;
auto instructionXorAccImm(Size) -> void;
auto instructionCmpMemReg(Size) -> void;
auto instructionCmpRegMem(Size) -> void;
auto instructionCmpAccImm(Size) -> void;
auto instructionTestMemReg(Size) -> void;
auto instructionTestAcc(Size) -> void;
auto instructionMultiplySignedRegMemImm(Size) -> void;
auto instructionIncReg(uint16_t&) -> void;
auto instructionDecReg(uint16_t&) -> void;
auto instructionSignExtendByte() -> void;
auto instructionSignExtendWord() -> void;
//instructions-exec.cpp
auto opLoop();
auto opLoopWhile(bool);
auto opJumpShort();
auto opJumpIf(bool);
auto opJumpNear();
auto opJumpFar();
auto opCallNear();
auto opCallFar();
auto opReturn();
auto opReturnImm();
auto opReturnFar();
auto opReturnFarImm();
auto opReturnInt();
auto opInt3();
auto opIntImm();
auto opInto();
auto opEnter();
auto opLeave();
auto opPushReg(uint16_t&);
auto opPopReg(uint16_t&);
auto opPushFlags();
auto opPopFlags();
auto opPushAll();
auto opPopAll();
auto opPushImm(Size);
auto opPopMem();
auto instructionLoop() -> void;
auto instructionLoopWhile(bool) -> void;
auto instructionJumpShort() -> void;
auto instructionJumpIf(bool) -> void;
auto instructionJumpNear() -> void;
auto instructionJumpFar() -> void;
auto instructionCallNear() -> void;
auto instructionCallFar() -> void;
auto instructionReturn() -> void;
auto instructionReturnImm() -> void;
auto instructionReturnFar() -> void;
auto instructionReturnFarImm() -> void;
auto instructionReturnInt() -> void;
auto instructionInt3() -> void;
auto instructionIntImm() -> void;
auto instructionInto() -> void;
auto instructionEnter() -> void;
auto instructionLeave() -> void;
auto instructionPushReg(uint16_t&) -> void;
auto instructionPopReg(uint16_t&) -> void;
auto instructionPushFlags() -> void;
auto instructionPopFlags() -> void;
auto instructionPushAll() -> void;
auto instructionPopAll() -> void;
auto instructionPushImm(Size) -> void;
auto instructionPopMem() -> void;
//instructions-flag.cpp
auto opStoreFlagsAcc();
auto opLoadAccFlags();
auto opComplementCarry();
auto opClearFlag(uint);
auto opSetFlag(uint);
auto instructionStoreFlagsAcc() -> void;
auto instructionLoadAccFlags() -> void;
auto instructionComplementCarry() -> void;
auto instructionClearFlag(uint) -> void;
auto instructionSetFlag(uint) -> void;
//instructions-group.cpp
auto opGroup1MemImm(Size, bool);
auto opGroup2MemImm(Size, maybe<uint8> = {});
auto opGroup3MemImm(Size);
auto opGroup4MemImm(Size);
auto instructionGroup1MemImm(Size, bool) -> void;
auto instructionGroup2MemImm(Size, maybe<uint8> = {}) -> void;
auto instructionGroup3MemImm(Size) -> void;
auto instructionGroup4MemImm(Size) -> void;
//instructions-misc.cpp
auto opSegment(uint16);
auto opRepeat(bool);
auto opLock();
auto opWait();
auto opHalt();
auto opNop();
auto opIn(Size);
auto opOut(Size);
auto opInDX(Size);
auto opOutDX(Size);
auto opTranslate();
auto opBound();
auto instructionSegment(uint16) -> void;
auto instructionRepeat(bool) -> void;
auto instructionLock() -> void;
auto instructionWait() -> void;
auto instructionHalt() -> void;
auto instructionNop() -> void;
auto instructionIn(Size) -> void;
auto instructionOut(Size) -> void;
auto instructionInDX(Size) -> void;
auto instructionOutDX(Size) -> void;
auto instructionTranslate() -> void;
auto instructionBound() -> void;
//instructions-move.cpp
auto opMoveMemReg(Size);
auto opMoveRegMem(Size);
auto opMoveMemSeg();
auto opMoveSegMem();
auto opMoveAccMem(Size);
auto opMoveMemAcc(Size);
auto opMoveRegImm(uint8_t&);
auto opMoveRegImm(uint16_t&);
auto opMoveMemImm(Size);
auto opExchange(uint16_t&, uint16_t&);
auto opExchangeMemReg(Size);
auto opLoadEffectiveAddressRegMem();
auto opLoadSegmentMem(uint16_t&);
auto instructionMoveMemReg(Size) -> void;
auto instructionMoveRegMem(Size) -> void;
auto instructionMoveMemSeg() -> void;
auto instructionMoveSegMem() -> void;
auto instructionMoveAccMem(Size) -> void;
auto instructionMoveMemAcc(Size) -> void;
auto instructionMoveRegImm(uint8_t&) -> void;
auto instructionMoveRegImm(uint16_t&) -> void;
auto instructionMoveMemImm(Size) -> void;
auto instructionExchange(uint16_t&, uint16_t&) -> void;
auto instructionExchangeMemReg(Size) -> void;
auto instructionLoadEffectiveAddressRegMem() -> void;
auto instructionLoadSegmentMem(uint16_t&) -> void;
//instructions-string.cpp
auto opInString(Size);
auto opOutString(Size);
auto opMoveString(Size);
auto opCompareString(Size);
auto opStoreString(Size);
auto opLoadString(Size);
auto opScanString(Size);
auto instructionInString(Size) -> void;
auto instructionOutString(Size) -> void;
auto instructionMoveString(Size) -> void;
auto instructionCompareString(Size) -> void;
auto instructionStoreString(Size) -> void;
auto instructionLoadString(Size) -> void;
auto instructionScanString(Size) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;

View File

@ -1,5 +1,9 @@
//ARMv3 (ARM60)
//note: this coprocessor uses the ARMv4 (ARM7TDMI) core as its base
//instruction execution forces ARM mode to remove ARMv4 THUMB access
//there is a possibility the ARMv3 supports 26-bit mode; but cannot be verified
struct ArmDSP : Processor::ARM7TDMI, Thread {
#include "registers.hpp"