mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
1067566834
commit
406b6a61a5
|
@ -12,7 +12,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
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 Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
|
|
@ -33,10 +33,8 @@ auto CPU::main() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::step(uint clocks) -> void {
|
auto CPU::step(uint clocks) -> void {
|
||||||
for(auto _ : range(clocks)) {
|
for(auto& dma : this->dma) {
|
||||||
for(auto& dma : this->dma) {
|
dma.waiting = max(0, dma.waiting - (int)clocks);
|
||||||
if(dma.waiting) dma.waiting--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!context.dmaActive) {
|
if(!context.dmaActive) {
|
||||||
|
|
|
@ -73,7 +73,7 @@ struct CPU : Processor::ARM7TDMI, Thread, IO {
|
||||||
uint2 id;
|
uint2 id;
|
||||||
|
|
||||||
boolean active;
|
boolean active;
|
||||||
natural waiting;
|
integer waiting;
|
||||||
|
|
||||||
uint2 targetMode;
|
uint2 targetMode;
|
||||||
uint2 sourceMode;
|
uint2 sourceMode;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
processors := $(call unique,$(processors))
|
processors := $(call unique,$(processors))
|
||||||
|
|
||||||
objects += $(if $(findstring arm,$(processors)),processor-arm)
|
|
||||||
objects += $(if $(findstring arm7tdmi,$(processors)),processor-arm7tdmi)
|
objects += $(if $(findstring arm7tdmi,$(processors)),processor-arm7tdmi)
|
||||||
objects += $(if $(findstring gsu,$(processors)),processor-gsu)
|
objects += $(if $(findstring gsu,$(processors)),processor-gsu)
|
||||||
objects += $(if $(findstring hg51b,$(processors)),processor-hg51b)
|
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 wdc65816,$(processors)),processor-wdc65816)
|
||||||
objects += $(if $(findstring z80,$(processors)),processor-z80)
|
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-arm7tdmi.o: processor/arm7tdmi/arm7tdmi.cpp $(call rwildcard,processor/arm7tdmi/)
|
||||||
obj/processor-gsu.o: processor/gsu/gsu.cpp $(call rwildcard,processor/gsu/)
|
obj/processor-gsu.o: processor/gsu/gsu.cpp $(call rwildcard,processor/gsu/)
|
||||||
obj/processor-hg51b.o: processor/hg51b/hg51b.cpp $(call rwildcard,processor/hg51b/)
|
obj/processor-hg51b.o: processor/hg51b/hg51b.cpp $(call rwildcard,processor/hg51b/)
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
auto disassembleInstructionARM(uint32 pc) -> string;
|
|
||||||
auto disassembleInstructionTHUMB(uint32 pc) -> string;
|
|
||||||
auto disassembleRegisters() -> string;
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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();
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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();
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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; }
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -113,7 +113,7 @@ struct ARM7TDMI {
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
//disassembler.cpp
|
//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;
|
auto disassembleRegisters() -> string;
|
||||||
|
|
||||||
struct GPR {
|
struct GPR {
|
||||||
|
@ -127,17 +127,18 @@ struct ARM7TDMI {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline auto operator=(const GPR& value) -> GPR& {
|
||||||
|
data = value.data;
|
||||||
|
if(modify) modify();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 data;
|
uint32 data;
|
||||||
function<auto () -> void> modify;
|
function<auto () -> void> modify;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PSR {
|
struct PSR {
|
||||||
enum : uint {
|
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
|
USR = 0x10, //user
|
||||||
FIQ = 0x11, //fast interrupt
|
FIQ = 0x11, //fast interrupt
|
||||||
IRQ = 0x12, //interrupt
|
IRQ = 0x12, //interrupt
|
||||||
|
@ -166,14 +167,14 @@ struct ARM7TDMI {
|
||||||
//serialization.cpp
|
//serialization.cpp
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
uint5 m; //mode
|
uint5 m; //mode
|
||||||
uint1 t; //thumb
|
boolean t; //thumb
|
||||||
uint1 f; //fiq
|
boolean f; //fiq
|
||||||
uint1 i; //irq
|
boolean i; //irq
|
||||||
uint1 v; //overflow
|
boolean v; //overflow
|
||||||
uint1 c; //carry
|
boolean c; //carry
|
||||||
uint1 z; //zero
|
boolean z; //zero
|
||||||
uint1 n; //negative
|
boolean n; //negative
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Processor {
|
struct Processor {
|
||||||
|
|
|
@ -11,7 +11,7 @@ static const string _conditions[] = {
|
||||||
#define _comp(mode) (mode >= 8 && mode <= 11)
|
#define _comp(mode) (mode >= 8 && mode <= 11)
|
||||||
#define _math(mode) (mode <= 7 || mode == 12 || mode == 14)
|
#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(!pc) pc = pipeline.execute.address;
|
||||||
if(!thumb) thumb = cpsr().t;
|
if(!thumb) thumb = cpsr().t;
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ auto ARM7TDMI::disassembleRegisters() -> string {
|
||||||
output.append(hex(cpsr().m, 2L));
|
output.append(hex(cpsr().m, 2L));
|
||||||
if(cpsr().m == PSR::USR || cpsr().m == PSR::SYS) return output;
|
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().n ? "N" : "n");
|
||||||
output.append(spsr().z ? "Z" : "z");
|
output.append(spsr().z ? "Z" : "z");
|
||||||
output.append(spsr().c ? "C" : "c");
|
output.append(spsr().c ? "C" : "c");
|
||||||
|
@ -189,7 +189,7 @@ auto ARM7TDMI::armDisassembleMoveMultiple
|
||||||
if(list.bit(index)) registers.append(_r[index], ",");
|
if(list.bit(index)) registers.append(_r[index], ",");
|
||||||
}
|
}
|
||||||
registers.trimRight(",", 1L);
|
registers.trimRight(",", 1L);
|
||||||
return {mode ? "ldm" : "stm",
|
return {mode ? "ldm" : "stm", _c,
|
||||||
up == 0 && pre == 0 ? "da" : "",
|
up == 0 && pre == 0 ? "da" : "",
|
||||||
up == 0 && pre == 1 ? "db" : "",
|
up == 0 && pre == 1 ? "db" : "",
|
||||||
up == 1 && pre == 0 ? "ia" : "",
|
up == 1 && pre == 0 ? "ia" : "",
|
||||||
|
@ -306,12 +306,12 @@ auto ARM7TDMI::thumbDisassembleBranchFarPrefix
|
||||||
uint11 displacementLo = read(Half | Nonsequential, (_pc & ~1) + 2);
|
uint11 displacementLo = read(Half | Nonsequential, (_pc & ~1) + 2);
|
||||||
int22 displacement = displacementHi << 11 | displacementLo << 0;
|
int22 displacement = displacementHi << 11 | displacementLo << 0;
|
||||||
uint32 address = _pc + 4 + displacement * 2;
|
uint32 address = _pc + 4 + displacement * 2;
|
||||||
return {"b 0x", hex(address, 8L)};
|
return {"bl 0x", hex(address, 8L)};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ARM7TDMI::thumbDisassembleBranchFarSuffix
|
auto ARM7TDMI::thumbDisassembleBranchFarSuffix
|
||||||
(uint11 displacement) -> string {
|
(uint11 displacement) -> string {
|
||||||
return {"b (suffix)"};
|
return {"bl (suffix)"};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ARM7TDMI::thumbDisassembleBranchNear
|
auto ARM7TDMI::thumbDisassembleBranchNear
|
||||||
|
|
|
@ -30,8 +30,9 @@ auto ARM7TDMI::instruction() -> void {
|
||||||
fetch();
|
fetch();
|
||||||
|
|
||||||
if(irq && !cpsr().i) {
|
if(irq && !cpsr().i) {
|
||||||
|
bool t = cpsr().t;
|
||||||
interrupt(PSR::IRQ, 0x18);
|
interrupt(PSR::IRQ, 0x18);
|
||||||
if(cpsr().t) r(14).data += 2;
|
if(t) r(14).data += 2;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,10 +284,10 @@ auto ARM7TDMI::armInitialize() -> void {
|
||||||
#undef arguments
|
#undef arguments
|
||||||
|
|
||||||
#define arguments \
|
#define arguments \
|
||||||
opcode.bits( 0, 3), /* d */ \
|
opcode.bits(12,15), /* d */ \
|
||||||
opcode.bit (22) /* mode */
|
opcode.bit (22) /* mode */
|
||||||
for(uint1 mode : range(2)) {
|
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);
|
bind(opcode, MoveToRegisterFromStatus);
|
||||||
}
|
}
|
||||||
#undef arguments
|
#undef arguments
|
||||||
|
|
|
@ -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) {
|
switch(mode) {
|
||||||
case 0: r(target) = BIT(r(source) & data); break; //AND
|
case 0: r(d) = BIT(rn & rm); break; //AND
|
||||||
case 1: r(target) = BIT(r(source) ^ data); break; //EOR
|
case 1: r(d) = BIT(rn ^ rm); break; //EOR
|
||||||
case 2: r(target) = SUB(r(source), data, 1); break; //SUB
|
case 2: r(d) = SUB(rn, rm, 1); break; //SUB
|
||||||
case 3: r(target) = SUB(data, r(source), 1); break; //RSB
|
case 3: r(d) = SUB(rm, rn, 1); break; //RSB
|
||||||
case 4: r(target) = ADD(r(source), data, 0); break; //ADD
|
case 4: r(d) = ADD(rn, rm, 0); break; //ADD
|
||||||
case 5: r(target) = ADD(r(source), data, cpsr().c); break; //ADC
|
case 5: r(d) = ADD(rn, rm, cpsr().c); break; //ADC
|
||||||
case 6: r(target) = SUB(r(source), data, cpsr().c); break; //SBC
|
case 6: r(d) = SUB(rn, rm, cpsr().c); break; //SBC
|
||||||
case 7: r(target) = SUB(data, r(source), cpsr().c); break; //RSC
|
case 7: r(d) = SUB(rm, rn, cpsr().c); break; //RSC
|
||||||
case 8: BIT(r(source) & data); break; //TST
|
case 8: BIT(rn & rm); break; //TST
|
||||||
case 9: BIT(r(source) ^ data); break; //TEQ
|
case 9: BIT(rn ^ rm); break; //TEQ
|
||||||
case 10: SUB(r(source), data, 1); break; //CMP
|
case 10: SUB(rn, rm, 1); break; //CMP
|
||||||
case 11: ADD(r(source), data, 0); break; //CMN
|
case 11: ADD(rn, rm, 0); break; //CMN
|
||||||
case 12: r(target) = BIT(r(source) | data); break; //ORR
|
case 12: r(d) = BIT(rn | rm); break; //ORR
|
||||||
case 13: r(target) = BIT(data); break; //MOV
|
case 13: r(d) = BIT(rm); break; //MOV
|
||||||
case 14: r(target) = BIT(r(source) & ~data); break; //BIC
|
case 14: r(d) = BIT(rn & ~rm); break; //BIC
|
||||||
case 15: r(target) = BIT(~data); break; //MVN
|
case 15: r(d) = BIT(~rm); break; //MVN
|
||||||
}
|
}
|
||||||
|
|
||||||
if(exception() && target == 15 && opcode.bit(20)) {
|
if(exception() && d == 15 && opcode.bit(20)) {
|
||||||
cpsr() = spsr();
|
cpsr() = spsr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +31,7 @@ auto ARM7TDMI::armMoveToStatus(uint4 field, uint1 mode, uint32 data) -> void {
|
||||||
|
|
||||||
if(field.bit(0)) {
|
if(field.bit(0)) {
|
||||||
if(mode || privileged()) {
|
if(mode || privileged()) {
|
||||||
psr.m = 0x10 | data.bits(0,4);
|
psr.m = data.bits(0,4);
|
||||||
psr.t = data.bit (5);
|
psr.t = data.bit (5);
|
||||||
psr.f = data.bit (6);
|
psr.f = data.bit (6);
|
||||||
psr.i = data.bit (7);
|
psr.i = data.bit (7);
|
||||||
|
|
|
@ -12,11 +12,11 @@ auto ARM7TDMI::load(uint mode, uint32 address) -> uint32 {
|
||||||
auto word = get(Load | mode, address);
|
auto word = get(Load | mode, address);
|
||||||
if(mode & Half) {
|
if(mode & Half) {
|
||||||
address &= 1;
|
address &= 1;
|
||||||
word = mode & Signed ? (uint16)(int16)word : (uint16)word;
|
word = mode & Signed ? (uint32)(int16)word : (uint32)(uint16)word;
|
||||||
}
|
}
|
||||||
if(mode & Byte) {
|
if(mode & Byte) {
|
||||||
address &= 0;
|
address &= 0;
|
||||||
word = mode & Signed ? (uint8)(int8)word : (uint8)word;
|
word = mode & Signed ? (uint32)(int8)word : (uint32)(uint8)word;
|
||||||
}
|
}
|
||||||
if(mode & Signed) {
|
if(mode & Signed) {
|
||||||
word = ASR(word, address.bits(0,1) << 3);
|
word = ASR(word, address.bits(0,1) << 3);
|
||||||
|
|
|
@ -47,13 +47,13 @@ auto ARM7TDMI::Processor::serialize(serializer& s) -> void {
|
||||||
|
|
||||||
auto ARM7TDMI::PSR::serialize(serializer& s) -> void {
|
auto ARM7TDMI::PSR::serialize(serializer& s) -> void {
|
||||||
s.integer(m);
|
s.integer(m);
|
||||||
s.integer(t);
|
s.boolean(t);
|
||||||
s.integer(f);
|
s.boolean(f);
|
||||||
s.integer(i);
|
s.boolean(i);
|
||||||
s.integer(v);
|
s.boolean(v);
|
||||||
s.integer(c);
|
s.boolean(c);
|
||||||
s.integer(z);
|
s.boolean(z);
|
||||||
s.integer(n);
|
s.boolean(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ARM7TDMI::Pipeline::serialize(serializer& s) -> void {
|
auto ARM7TDMI::Pipeline::serialize(serializer& s) -> void {
|
||||||
|
|
|
@ -10,11 +10,11 @@ auto V30MZ::parity(uint8 value) const -> bool {
|
||||||
#define mask (size == Byte ? 0xff : 0xffff)
|
#define mask (size == Byte ? 0xff : 0xffff)
|
||||||
#define sign (size == Byte ? 0x80 : 0x8000)
|
#define sign (size == Byte ? 0x80 : 0x8000)
|
||||||
|
|
||||||
auto V30MZ::alAdc(Size size, uint16 x, uint16 y) -> uint16 {
|
auto V30MZ::ADC(Size size, uint16 x, uint16 y) -> uint16 {
|
||||||
return alAdd(size, x, y + r.f.c);
|
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;
|
uint16 result = (x + y) & mask;
|
||||||
r.f.c = x + y > mask;
|
r.f.c = x + y > mask;
|
||||||
r.f.p = parity(result);
|
r.f.p = parity(result);
|
||||||
|
@ -25,7 +25,7 @@ auto V30MZ::alAdd(Size size, uint16 x, uint16 y) -> uint16 {
|
||||||
return result;
|
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;
|
uint16 result = (x & y) & mask;
|
||||||
r.f.c = 0;
|
r.f.c = 0;
|
||||||
r.f.p = parity(result);
|
r.f.p = parity(result);
|
||||||
|
@ -36,7 +36,7 @@ auto V30MZ::alAnd(Size size, uint16 x, uint16 y) -> uint16 {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::alDec(Size size, uint16 x) -> uint16 {
|
auto V30MZ::DEC(Size size, uint16 x) -> uint16 {
|
||||||
uint16 result = (x - 1) & mask;
|
uint16 result = (x - 1) & mask;
|
||||||
r.f.p = parity(result);
|
r.f.p = parity(result);
|
||||||
r.f.h = (x & 0x0f) == 0;
|
r.f.h = (x & 0x0f) == 0;
|
||||||
|
@ -46,14 +46,14 @@ auto V30MZ::alDec(Size size, uint16 x) -> uint16 {
|
||||||
return result;
|
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;
|
if(y == 0) return interrupt(0), 0;
|
||||||
uint32 quotient = x / y;
|
uint32 quotient = x / y;
|
||||||
uint32 remainder = x % y;
|
uint32 remainder = x % y;
|
||||||
return (remainder & mask) << bits | (quotient & mask);
|
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;
|
if(y == 0) return interrupt(0), 0;
|
||||||
x = size == Byte ? (int8_t)x : (int16_t)x;
|
x = size == Byte ? (int8_t)x : (int16_t)x;
|
||||||
y = size == Byte ? (int8_t)y : (int16_t)y;
|
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);
|
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;
|
uint16 result = (x + 1) & mask;
|
||||||
r.f.p = parity(result);
|
r.f.p = parity(result);
|
||||||
r.f.h = (x & 0x0f) == 0x0f;
|
r.f.h = (x & 0x0f) == 0x0f;
|
||||||
|
@ -72,14 +72,14 @@ auto V30MZ::alInc(Size size, uint16 x) -> uint16 {
|
||||||
return result;
|
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;
|
uint32 result = x * y;
|
||||||
r.f.c = result >> bits;
|
r.f.c = result >> bits;
|
||||||
r.f.v = result >> bits;
|
r.f.v = result >> bits;
|
||||||
return result;
|
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;
|
x = size == Byte ? (int8_t)x : (int16_t)x;
|
||||||
y = size == Byte ? (int8_t)y : (int16_t)y;
|
y = size == Byte ? (int8_t)y : (int16_t)y;
|
||||||
uint32 result = x * y;
|
uint32 result = x * y;
|
||||||
|
@ -88,7 +88,7 @@ auto V30MZ::alMuli(Size size, int16 x, int16 y) -> uint32 {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::alNeg(Size size, uint16 x) -> uint16 {
|
auto V30MZ::NEG(Size size, uint16 x) -> uint16 {
|
||||||
uint16 result = (-x) & mask;
|
uint16 result = (-x) & mask;
|
||||||
r.f.c = x;
|
r.f.c = x;
|
||||||
r.f.p = parity(result);
|
r.f.p = parity(result);
|
||||||
|
@ -99,12 +99,12 @@ auto V30MZ::alNeg(Size size, uint16 x) -> uint16 {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::alNot(Size size, uint16 x) -> uint16 {
|
auto V30MZ::NOT(Size size, uint16 x) -> uint16 {
|
||||||
uint16 result = (~x) & mask;
|
uint16 result = (~x) & mask;
|
||||||
return result;
|
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;
|
uint16 result = (x | y) & mask;
|
||||||
r.f.c = 0;
|
r.f.c = 0;
|
||||||
r.f.p = parity(result);
|
r.f.p = parity(result);
|
||||||
|
@ -115,7 +115,7 @@ auto V30MZ::alOr(Size size, uint16 x, uint16 y) -> uint16 {
|
||||||
return result;
|
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;
|
uint16 result = x;
|
||||||
for(uint n = 0; n < y; n++) {
|
for(uint n = 0; n < y; n++) {
|
||||||
bool carry = result & sign;
|
bool carry = result & sign;
|
||||||
|
@ -126,7 +126,7 @@ auto V30MZ::alRcl(Size size, uint16 x, uint5 y) -> uint16 {
|
||||||
return result & mask;
|
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;
|
uint16 result = x;
|
||||||
for(uint n = 0; n < y; n++) {
|
for(uint n = 0; n < y; n++) {
|
||||||
bool carry = result & 1;
|
bool carry = result & 1;
|
||||||
|
@ -137,21 +137,21 @@ auto V30MZ::alRcr(Size size, uint16 x, uint5 y) -> uint16 {
|
||||||
return result & mask;
|
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);
|
r.f.c = (x << y) & (1 << bits);
|
||||||
uint16 result = ((x << y) | (x >> (bits - y))) & mask;
|
uint16 result = ((x << y) | (x >> (bits - y))) & mask;
|
||||||
r.f.v = (x ^ result) & sign;
|
r.f.v = (x ^ result) & sign;
|
||||||
return result;
|
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;
|
r.f.c = (x >> (y - 1)) & 1;
|
||||||
uint16 result = ((x >> y) | (x << (bits - y))) & mask;
|
uint16 result = ((x >> y) | (x << (bits - y))) & mask;
|
||||||
r.f.v = (x ^ result) & sign;
|
r.f.v = (x ^ result) & sign;
|
||||||
return result;
|
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);
|
r.f.c = (x << y) & (1 << bits);
|
||||||
uint16 result = (x << y) & mask;
|
uint16 result = (x << y) & mask;
|
||||||
r.f.p = parity(result);
|
r.f.p = parity(result);
|
||||||
|
@ -161,7 +161,7 @@ auto V30MZ::alSal(Size size, uint16 x, uint5 y) -> uint16 {
|
||||||
return result;
|
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) {
|
if(y & 16) {
|
||||||
r.f.c = x & sign;
|
r.f.c = x & sign;
|
||||||
return 0 - r.f.c;
|
return 0 - r.f.c;
|
||||||
|
@ -176,11 +176,11 @@ auto V30MZ::alSar(Size size, uint16 x, uint5 y) -> uint16 {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::alSbb(Size size, uint16 x, uint16 y) -> uint16 {
|
auto V30MZ::SBB(Size size, uint16 x, uint16 y) -> uint16 {
|
||||||
return alSub(size, x, y + r.f.c);
|
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);
|
r.f.c = (x << y) & (1 << bits);
|
||||||
uint16 result = (x << y) & mask;
|
uint16 result = (x << y) & mask;
|
||||||
r.f.p = parity(result);
|
r.f.p = parity(result);
|
||||||
|
@ -190,7 +190,7 @@ auto V30MZ::alShl(Size size, uint16 x, uint5 y) -> uint16 {
|
||||||
return result;
|
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;
|
r.f.c = (x >> (y - 1)) & 1;
|
||||||
uint16 result = (x >> y) & mask;
|
uint16 result = (x >> y) & mask;
|
||||||
r.f.p = parity(result);
|
r.f.p = parity(result);
|
||||||
|
@ -200,7 +200,7 @@ auto V30MZ::alShr(Size size, uint16 x, uint5 y) -> uint16 {
|
||||||
return result;
|
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;
|
uint16 result = (x - y) & mask;
|
||||||
r.f.c = y > x;
|
r.f.c = y > x;
|
||||||
r.f.p = parity(result);
|
r.f.p = parity(result);
|
||||||
|
@ -211,7 +211,7 @@ auto V30MZ::alSub(Size size, uint16 x, uint16 y) -> uint16 {
|
||||||
return result;
|
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;
|
uint16 result = (x ^ y) & mask;
|
||||||
r.f.c = 0;
|
r.f.c = 0;
|
||||||
r.f.p = parity(result);
|
r.f.p = parity(result);
|
||||||
|
|
|
@ -28,263 +28,267 @@ auto V30MZ::interrupt(uint8 vector) -> void {
|
||||||
r.cs = cs;
|
r.cs = cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__);
|
||||||
|
|
||||||
auto V30MZ::instruction() -> void {
|
auto V30MZ::instruction() -> void {
|
||||||
switch(opcode = fetch()) {
|
switch(opcode = fetch()) {
|
||||||
case 0x00: return opAddMemReg(Byte);
|
op(0x00, AddMemReg, Byte)
|
||||||
case 0x01: return opAddMemReg(Word);
|
op(0x01, AddMemReg, Word)
|
||||||
case 0x02: return opAddRegMem(Byte);
|
op(0x02, AddRegMem, Byte)
|
||||||
case 0x03: return opAddRegMem(Word);
|
op(0x03, AddRegMem, Word)
|
||||||
case 0x04: return opAddAccImm(Byte);
|
op(0x04, AddAccImm, Byte)
|
||||||
case 0x05: return opAddAccImm(Word);
|
op(0x05, AddAccImm, Word)
|
||||||
case 0x06: return opPushReg(r.es);
|
op(0x06, PushReg, r.es)
|
||||||
case 0x07: return opPopReg(r.es);
|
op(0x07, PopReg, r.es)
|
||||||
case 0x08: return opOrMemReg(Byte);
|
op(0x08, OrMemReg, Byte)
|
||||||
case 0x09: return opOrMemReg(Word);
|
op(0x09, OrMemReg, Word)
|
||||||
case 0x0a: return opOrRegMem(Byte);
|
op(0x0a, OrRegMem, Byte)
|
||||||
case 0x0b: return opOrRegMem(Word);
|
op(0x0b, OrRegMem, Word)
|
||||||
case 0x0c: return opOrAccImm(Byte);
|
op(0x0c, OrAccImm, Byte)
|
||||||
case 0x0d: return opOrAccImm(Word);
|
op(0x0d, OrAccImm, Word)
|
||||||
case 0x0e: return opPushReg(r.cs);
|
op(0x0e, PushReg, r.cs)
|
||||||
case 0x0f: return; //pop cs
|
//op(0x0f, ...) //pop cs
|
||||||
case 0x10: return opAdcMemReg(Byte);
|
op(0x10, AdcMemReg, Byte)
|
||||||
case 0x11: return opAdcMemReg(Word);
|
op(0x11, AdcMemReg, Word)
|
||||||
case 0x12: return opAdcRegMem(Byte);
|
op(0x12, AdcRegMem, Byte)
|
||||||
case 0x13: return opAdcRegMem(Word);
|
op(0x13, AdcRegMem, Word)
|
||||||
case 0x14: return opAdcAccImm(Byte);
|
op(0x14, AdcAccImm, Byte)
|
||||||
case 0x15: return opAdcAccImm(Word);
|
op(0x15, AdcAccImm, Word)
|
||||||
case 0x16: return opPushReg(r.ss);
|
op(0x16, PushReg, r.ss)
|
||||||
case 0x17: return opPopReg(r.ss);
|
op(0x17, PopReg, r.ss)
|
||||||
case 0x18: return opSbbMemReg(Byte);
|
op(0x18, SbbMemReg, Byte)
|
||||||
case 0x19: return opSbbMemReg(Word);
|
op(0x19, SbbMemReg, Word)
|
||||||
case 0x1a: return opSbbRegMem(Byte);
|
op(0x1a, SbbRegMem, Byte)
|
||||||
case 0x1b: return opSbbRegMem(Word);
|
op(0x1b, SbbRegMem, Word)
|
||||||
case 0x1c: return opSbbAccImm(Byte);
|
op(0x1c, SbbAccImm, Byte)
|
||||||
case 0x1d: return opSbbAccImm(Word);
|
op(0x1d, SbbAccImm, Word)
|
||||||
case 0x1e: return opPushReg(r.ds);
|
op(0x1e, PushReg, r.ds)
|
||||||
case 0x1f: return opPopReg(r.ds);
|
op(0x1f, PopReg, r.ds)
|
||||||
case 0x20: return opAndMemReg(Byte);
|
op(0x20, AndMemReg, Byte)
|
||||||
case 0x21: return opAndMemReg(Word);
|
op(0x21, AndMemReg, Word)
|
||||||
case 0x22: return opAndRegMem(Byte);
|
op(0x22, AndRegMem, Byte)
|
||||||
case 0x23: return opAndRegMem(Word);
|
op(0x23, AndRegMem, Word)
|
||||||
case 0x24: return opAndAccImm(Byte);
|
op(0x24, AndAccImm, Byte)
|
||||||
case 0x25: return opAndAccImm(Word);
|
op(0x25, AndAccImm, Word)
|
||||||
case 0x26: return opSegment(r.es);
|
op(0x26, Segment, r.es)
|
||||||
case 0x27: return opDecimalAdjust(0); //daa
|
op(0x27, DecimalAdjust, 0) //daa
|
||||||
case 0x28: return opSubMemReg(Byte);
|
op(0x28, SubMemReg, Byte)
|
||||||
case 0x29: return opSubMemReg(Word);
|
op(0x29, SubMemReg, Word)
|
||||||
case 0x2a: return opSubRegMem(Byte);
|
op(0x2a, SubRegMem, Byte)
|
||||||
case 0x2b: return opSubRegMem(Word);
|
op(0x2b, SubRegMem, Word)
|
||||||
case 0x2c: return opSubAccImm(Byte);
|
op(0x2c, SubAccImm, Byte)
|
||||||
case 0x2d: return opSubAccImm(Word);
|
op(0x2d, SubAccImm, Word)
|
||||||
case 0x2e: return opSegment(r.cs);
|
op(0x2e, Segment, r.cs)
|
||||||
case 0x2f: return opDecimalAdjust(1); //das
|
op(0x2f, DecimalAdjust, 1) //das
|
||||||
case 0x30: return opXorMemReg(Byte);
|
op(0x30, XorMemReg, Byte)
|
||||||
case 0x31: return opXorMemReg(Word);
|
op(0x31, XorMemReg, Word)
|
||||||
case 0x32: return opXorRegMem(Byte);
|
op(0x32, XorRegMem, Byte)
|
||||||
case 0x33: return opXorRegMem(Word);
|
op(0x33, XorRegMem, Word)
|
||||||
case 0x34: return opXorAccImm(Byte);
|
op(0x34, XorAccImm, Byte)
|
||||||
case 0x35: return opXorAccImm(Word);
|
op(0x35, XorAccImm, Word)
|
||||||
case 0x36: return opSegment(r.ss);
|
op(0x36, Segment, r.ss)
|
||||||
case 0x37: return opAsciiAdjust(0); //aaa
|
op(0x37, AsciiAdjust, 0) //aaa
|
||||||
case 0x38: return opCmpMemReg(Byte);
|
op(0x38, CmpMemReg, Byte)
|
||||||
case 0x39: return opCmpMemReg(Word);
|
op(0x39, CmpMemReg, Word)
|
||||||
case 0x3a: return opCmpRegMem(Byte);
|
op(0x3a, CmpRegMem, Byte)
|
||||||
case 0x3b: return opCmpRegMem(Word);
|
op(0x3b, CmpRegMem, Word)
|
||||||
case 0x3c: return opCmpAccImm(Byte);
|
op(0x3c, CmpAccImm, Byte)
|
||||||
case 0x3d: return opCmpAccImm(Word);
|
op(0x3d, CmpAccImm, Word)
|
||||||
case 0x3e: return opSegment(r.ds);
|
op(0x3e, Segment, r.ds)
|
||||||
case 0x3f: return opAsciiAdjust(1); //aas
|
op(0x3f, AsciiAdjust, 1) //aas
|
||||||
case 0x40: return opIncReg(r.ax);
|
op(0x40, IncReg, r.ax)
|
||||||
case 0x41: return opIncReg(r.cx);
|
op(0x41, IncReg, r.cx)
|
||||||
case 0x42: return opIncReg(r.dx);
|
op(0x42, IncReg, r.dx)
|
||||||
case 0x43: return opIncReg(r.bx);
|
op(0x43, IncReg, r.bx)
|
||||||
case 0x44: return opIncReg(r.sp);
|
op(0x44, IncReg, r.sp)
|
||||||
case 0x45: return opIncReg(r.bp);
|
op(0x45, IncReg, r.bp)
|
||||||
case 0x46: return opIncReg(r.si);
|
op(0x46, IncReg, r.si)
|
||||||
case 0x47: return opIncReg(r.di);
|
op(0x47, IncReg, r.di)
|
||||||
case 0x48: return opDecReg(r.ax);
|
op(0x48, DecReg, r.ax)
|
||||||
case 0x49: return opDecReg(r.cx);
|
op(0x49, DecReg, r.cx)
|
||||||
case 0x4a: return opDecReg(r.dx);
|
op(0x4a, DecReg, r.dx)
|
||||||
case 0x4b: return opDecReg(r.bx);
|
op(0x4b, DecReg, r.bx)
|
||||||
case 0x4c: return opDecReg(r.sp);
|
op(0x4c, DecReg, r.sp)
|
||||||
case 0x4d: return opDecReg(r.bp);
|
op(0x4d, DecReg, r.bp)
|
||||||
case 0x4e: return opDecReg(r.si);
|
op(0x4e, DecReg, r.si)
|
||||||
case 0x4f: return opDecReg(r.di);
|
op(0x4f, DecReg, r.di)
|
||||||
case 0x50: return opPushReg(r.ax);
|
op(0x50, PushReg, r.ax)
|
||||||
case 0x51: return opPushReg(r.cx);
|
op(0x51, PushReg, r.cx)
|
||||||
case 0x52: return opPushReg(r.dx);
|
op(0x52, PushReg, r.dx)
|
||||||
case 0x53: return opPushReg(r.bx);
|
op(0x53, PushReg, r.bx)
|
||||||
case 0x54: return opPushReg(r.sp);
|
op(0x54, PushReg, r.sp)
|
||||||
case 0x55: return opPushReg(r.bp);
|
op(0x55, PushReg, r.bp)
|
||||||
case 0x56: return opPushReg(r.si);
|
op(0x56, PushReg, r.si)
|
||||||
case 0x57: return opPushReg(r.di);
|
op(0x57, PushReg, r.di)
|
||||||
case 0x58: return opPopReg(r.ax);
|
op(0x58, PopReg, r.ax)
|
||||||
case 0x59: return opPopReg(r.cx);
|
op(0x59, PopReg, r.cx)
|
||||||
case 0x5a: return opPopReg(r.dx);
|
op(0x5a, PopReg, r.dx)
|
||||||
case 0x5b: return opPopReg(r.bx);
|
op(0x5b, PopReg, r.bx)
|
||||||
case 0x5c: return opPopReg(r.sp);
|
op(0x5c, PopReg, r.sp)
|
||||||
case 0x5d: return opPopReg(r.bp);
|
op(0x5d, PopReg, r.bp)
|
||||||
case 0x5e: return opPopReg(r.si);
|
op(0x5e, PopReg, r.si)
|
||||||
case 0x5f: return opPopReg(r.di);
|
op(0x5f, PopReg, r.di)
|
||||||
case 0x60: return opPushAll();
|
op(0x60, PushAll)
|
||||||
case 0x61: return opPopAll();
|
op(0x61, PopAll)
|
||||||
case 0x62: return opBound();
|
op(0x62, Bound)
|
||||||
case 0x63: return;
|
//op(0x63, ...)
|
||||||
case 0x64: return;
|
//op(0x64, ...)
|
||||||
case 0x65: return;
|
//op(0x65, ...)
|
||||||
case 0x66: return;
|
//op(0x66, ...)
|
||||||
case 0x67: return;
|
//op(0x67, ...)
|
||||||
case 0x68: return opPushImm(Word);
|
op(0x68, PushImm, Word)
|
||||||
case 0x69: return opMultiplySignedRegMemImm(Word);
|
op(0x69, MultiplySignedRegMemImm, Word)
|
||||||
case 0x6a: return opPushImm(Byte);
|
op(0x6a, PushImm, Byte)
|
||||||
case 0x6b: return opMultiplySignedRegMemImm(Byte);
|
op(0x6b, MultiplySignedRegMemImm, Byte)
|
||||||
case 0x6c: return opInString(Byte);
|
op(0x6c, InString, Byte)
|
||||||
case 0x6d: return opInString(Word);
|
op(0x6d, InString, Word)
|
||||||
case 0x6e: return opOutString(Byte);
|
op(0x6e, OutString, Byte)
|
||||||
case 0x6f: return opOutString(Word);
|
op(0x6f, OutString, Word)
|
||||||
case 0x70: return opJumpIf(r.f.v == 1);
|
op(0x70, JumpIf, r.f.v == 1)
|
||||||
case 0x71: return opJumpIf(r.f.v == 0);
|
op(0x71, JumpIf, r.f.v == 0)
|
||||||
case 0x72: return opJumpIf(r.f.c == 1);
|
op(0x72, JumpIf, r.f.c == 1)
|
||||||
case 0x73: return opJumpIf(r.f.c == 0);
|
op(0x73, JumpIf, r.f.c == 0)
|
||||||
case 0x74: return opJumpIf(r.f.z == 1);
|
op(0x74, JumpIf, r.f.z == 1)
|
||||||
case 0x75: return opJumpIf(r.f.z == 0);
|
op(0x75, JumpIf, r.f.z == 0)
|
||||||
case 0x76: return opJumpIf(r.f.z == 1 || r.f.c == 1);
|
op(0x76, JumpIf, r.f.z == 1 || r.f.c == 1)
|
||||||
case 0x77: return opJumpIf(r.f.z != 1 && r.f.c != 1);
|
op(0x77, JumpIf, r.f.z != 1 && r.f.c != 1)
|
||||||
case 0x78: return opJumpIf(r.f.s == 1);
|
op(0x78, JumpIf, r.f.s == 1)
|
||||||
case 0x79: return opJumpIf(r.f.s == 0);
|
op(0x79, JumpIf, r.f.s == 0)
|
||||||
case 0x7a: return opJumpIf(r.f.p == 1);
|
op(0x7a, JumpIf, r.f.p == 1)
|
||||||
case 0x7b: return opJumpIf(r.f.p == 0);
|
op(0x7b, JumpIf, r.f.p == 0)
|
||||||
case 0x7c: return opJumpIf(r.f.s != r.f.v && r.f.z == 0);
|
op(0x7c, JumpIf, r.f.s != r.f.v && r.f.z == 0)
|
||||||
case 0x7d: return opJumpIf(r.f.s == r.f.v || r.f.z == 1);
|
op(0x7d, JumpIf, r.f.s == r.f.v || r.f.z == 1)
|
||||||
case 0x7e: return opJumpIf(r.f.s != r.f.v || r.f.z == 1);
|
op(0x7e, JumpIf, r.f.s != r.f.v || r.f.z == 1)
|
||||||
case 0x7f: return opJumpIf(r.f.s == r.f.v && r.f.z == 0);
|
op(0x7f, JumpIf, r.f.s == r.f.v && r.f.z == 0)
|
||||||
case 0x80: return opGroup1MemImm(Byte, 0);
|
op(0x80, Group1MemImm, Byte, 0)
|
||||||
case 0x81: return opGroup1MemImm(Word, 0);
|
op(0x81, Group1MemImm, Word, 0)
|
||||||
case 0x82: return opGroup1MemImm(Byte, 1);
|
op(0x82, Group1MemImm, Byte, 1)
|
||||||
case 0x83: return opGroup1MemImm(Word, 1);
|
op(0x83, Group1MemImm, Word, 1)
|
||||||
case 0x84: return opTestMemReg(Byte);
|
op(0x84, TestMemReg, Byte)
|
||||||
case 0x85: return opTestMemReg(Word);
|
op(0x85, TestMemReg, Word)
|
||||||
case 0x86: return opExchangeMemReg(Byte);
|
op(0x86, ExchangeMemReg, Byte)
|
||||||
case 0x87: return opExchangeMemReg(Word);
|
op(0x87, ExchangeMemReg, Word)
|
||||||
case 0x88: return opMoveMemReg(Byte);
|
op(0x88, MoveMemReg, Byte)
|
||||||
case 0x89: return opMoveMemReg(Word);
|
op(0x89, MoveMemReg, Word)
|
||||||
case 0x8a: return opMoveRegMem(Byte);
|
op(0x8a, MoveRegMem, Byte)
|
||||||
case 0x8b: return opMoveRegMem(Word);
|
op(0x8b, MoveRegMem, Word)
|
||||||
case 0x8c: return opMoveMemSeg();
|
op(0x8c, MoveMemSeg)
|
||||||
case 0x8d: return opLoadEffectiveAddressRegMem();
|
op(0x8d, LoadEffectiveAddressRegMem)
|
||||||
case 0x8e: return opMoveSegMem();
|
op(0x8e, MoveSegMem)
|
||||||
case 0x8f: return opPopMem();
|
op(0x8f, PopMem)
|
||||||
case 0x90: return opNop();
|
op(0x90, Nop)
|
||||||
case 0x91: return opExchange(r.ax, r.cx);
|
op(0x91, Exchange, r.ax, r.cx)
|
||||||
case 0x92: return opExchange(r.ax, r.dx);
|
op(0x92, Exchange, r.ax, r.dx)
|
||||||
case 0x93: return opExchange(r.ax, r.bx);
|
op(0x93, Exchange, r.ax, r.bx)
|
||||||
case 0x94: return opExchange(r.ax, r.sp);
|
op(0x94, Exchange, r.ax, r.sp)
|
||||||
case 0x95: return opExchange(r.ax, r.bp);
|
op(0x95, Exchange, r.ax, r.bp)
|
||||||
case 0x96: return opExchange(r.ax, r.si);
|
op(0x96, Exchange, r.ax, r.si)
|
||||||
case 0x97: return opExchange(r.ax, r.di);
|
op(0x97, Exchange, r.ax, r.di)
|
||||||
case 0x98: return opSignExtendByte();
|
op(0x98, SignExtendByte)
|
||||||
case 0x99: return opSignExtendWord();
|
op(0x99, SignExtendWord)
|
||||||
case 0x9a: return opCallFar();
|
op(0x9a, CallFar)
|
||||||
case 0x9b: return opWait();
|
op(0x9b, Wait)
|
||||||
case 0x9c: return opPushFlags();
|
op(0x9c, PushFlags)
|
||||||
case 0x9d: return opPopFlags();
|
op(0x9d, PopFlags)
|
||||||
case 0x9e: return opStoreFlagsAcc();
|
op(0x9e, StoreFlagsAcc)
|
||||||
case 0x9f: return opLoadAccFlags();
|
op(0x9f, LoadAccFlags)
|
||||||
case 0xa0: return opMoveAccMem(Byte);
|
op(0xa0, MoveAccMem, Byte)
|
||||||
case 0xa1: return opMoveAccMem(Word);
|
op(0xa1, MoveAccMem, Word)
|
||||||
case 0xa2: return opMoveMemAcc(Byte);
|
op(0xa2, MoveMemAcc, Byte)
|
||||||
case 0xa3: return opMoveMemAcc(Word);
|
op(0xa3, MoveMemAcc, Word)
|
||||||
case 0xa4: return opMoveString(Byte);
|
op(0xa4, MoveString, Byte)
|
||||||
case 0xa5: return opMoveString(Word);
|
op(0xa5, MoveString, Word)
|
||||||
case 0xa6: return opCompareString(Byte);
|
op(0xa6, CompareString, Byte)
|
||||||
case 0xa7: return opCompareString(Word);
|
op(0xa7, CompareString, Word)
|
||||||
case 0xa8: return opTestAcc(Byte);
|
op(0xa8, TestAcc, Byte)
|
||||||
case 0xa9: return opTestAcc(Word);
|
op(0xa9, TestAcc, Word)
|
||||||
case 0xaa: return opStoreString(Byte);
|
op(0xaa, StoreString, Byte)
|
||||||
case 0xab: return opStoreString(Word);
|
op(0xab, StoreString, Word)
|
||||||
case 0xac: return opLoadString(Byte);
|
op(0xac, LoadString, Byte)
|
||||||
case 0xad: return opLoadString(Word);
|
op(0xad, LoadString, Word)
|
||||||
case 0xae: return opScanString(Byte);
|
op(0xae, ScanString, Byte)
|
||||||
case 0xaf: return opScanString(Word);
|
op(0xaf, ScanString, Word)
|
||||||
case 0xb0: return opMoveRegImm(r.al);
|
op(0xb0, MoveRegImm, r.al)
|
||||||
case 0xb1: return opMoveRegImm(r.cl);
|
op(0xb1, MoveRegImm, r.cl)
|
||||||
case 0xb2: return opMoveRegImm(r.dl);
|
op(0xb2, MoveRegImm, r.dl)
|
||||||
case 0xb3: return opMoveRegImm(r.bl);
|
op(0xb3, MoveRegImm, r.bl)
|
||||||
case 0xb4: return opMoveRegImm(r.ah);
|
op(0xb4, MoveRegImm, r.ah)
|
||||||
case 0xb5: return opMoveRegImm(r.ch);
|
op(0xb5, MoveRegImm, r.ch)
|
||||||
case 0xb6: return opMoveRegImm(r.dh);
|
op(0xb6, MoveRegImm, r.dh)
|
||||||
case 0xb7: return opMoveRegImm(r.bh);
|
op(0xb7, MoveRegImm, r.bh)
|
||||||
case 0xb8: return opMoveRegImm(r.ax);
|
op(0xb8, MoveRegImm, r.ax)
|
||||||
case 0xb9: return opMoveRegImm(r.cx);
|
op(0xb9, MoveRegImm, r.cx)
|
||||||
case 0xba: return opMoveRegImm(r.dx);
|
op(0xba, MoveRegImm, r.dx)
|
||||||
case 0xbb: return opMoveRegImm(r.bx);
|
op(0xbb, MoveRegImm, r.bx)
|
||||||
case 0xbc: return opMoveRegImm(r.sp);
|
op(0xbc, MoveRegImm, r.sp)
|
||||||
case 0xbd: return opMoveRegImm(r.bp);
|
op(0xbd, MoveRegImm, r.bp)
|
||||||
case 0xbe: return opMoveRegImm(r.si);
|
op(0xbe, MoveRegImm, r.si)
|
||||||
case 0xbf: return opMoveRegImm(r.di);
|
op(0xbf, MoveRegImm, r.di)
|
||||||
case 0xc0: return opGroup2MemImm(Byte);
|
op(0xc0, Group2MemImm, Byte)
|
||||||
case 0xc1: return opGroup2MemImm(Word);
|
op(0xc1, Group2MemImm, Word)
|
||||||
case 0xc2: return opReturnImm();
|
op(0xc2, ReturnImm)
|
||||||
case 0xc3: return opReturn();
|
op(0xc3, Return)
|
||||||
case 0xc4: return opLoadSegmentMem(r.es);
|
op(0xc4, LoadSegmentMem, r.es)
|
||||||
case 0xc5: return opLoadSegmentMem(r.ds);
|
op(0xc5, LoadSegmentMem, r.ds)
|
||||||
case 0xc6: return opMoveMemImm(Byte);
|
op(0xc6, MoveMemImm, Byte)
|
||||||
case 0xc7: return opMoveMemImm(Word);
|
op(0xc7, MoveMemImm, Word)
|
||||||
case 0xc8: return opEnter();
|
op(0xc8, Enter)
|
||||||
case 0xc9: return opLeave();
|
op(0xc9, Leave)
|
||||||
case 0xca: return opReturnFarImm();
|
op(0xca, ReturnFarImm)
|
||||||
case 0xcb: return opReturnFar();
|
op(0xcb, ReturnFar)
|
||||||
case 0xcc: return opInt3();
|
op(0xcc, Int3)
|
||||||
case 0xcd: return opIntImm();
|
op(0xcd, IntImm)
|
||||||
case 0xce: return opInto();
|
op(0xce, Into)
|
||||||
case 0xcf: return opReturnInt();
|
op(0xcf, ReturnInt)
|
||||||
case 0xd0: return opGroup2MemImm(Byte, (uint8)1);
|
op(0xd0, Group2MemImm, Byte, (uint8)1)
|
||||||
case 0xd1: return opGroup2MemImm(Word, (uint8)1);
|
op(0xd1, Group2MemImm, Word, (uint8)1)
|
||||||
case 0xd2: return opGroup2MemImm(Byte, (uint8)r.cl);
|
op(0xd2, Group2MemImm, Byte, (uint8)r.cl)
|
||||||
case 0xd3: return opGroup2MemImm(Word, (uint8)r.cl);
|
op(0xd3, Group2MemImm, Word, (uint8)r.cl)
|
||||||
case 0xd4: return opAdjustAfterMultiply();
|
op(0xd4, AdjustAfterMultiply)
|
||||||
case 0xd5: return opAdjustAfterDivide();
|
op(0xd5, AdjustAfterDivide)
|
||||||
case 0xd6: return;
|
//op(0xd6, ...)
|
||||||
case 0xd7: return opTranslate();
|
op(0xd7, Translate)
|
||||||
case 0xd8: return; //fpo1
|
//op(0xd8, ...) //fpo1
|
||||||
case 0xd9: return; //fpo1
|
//op(0xd9, ...) //fpo1
|
||||||
case 0xda: return; //fpo1
|
//op(0xda, ...) //fpo1
|
||||||
case 0xdb: return; //fpo1
|
//op(0xdb, ...) //fpo1
|
||||||
case 0xdc: return; //fpo1
|
//op(0xdc, ...) //fpo1
|
||||||
case 0xdd: return; //fpo1
|
//op(0xdd, ...) //fpo1
|
||||||
case 0xde: return; //fpo1
|
//op(0xde, ...) //fpo1
|
||||||
case 0xdf: return; //fpo1
|
//op(0xdf, ...) //fpo1
|
||||||
case 0xe0: return opLoopWhile(0); //loopnz
|
op(0xe0, LoopWhile, 0) //loopnz
|
||||||
case 0xe1: return opLoopWhile(1); //loopz
|
op(0xe1, LoopWhile, 1) //loopz
|
||||||
case 0xe2: return opLoop();
|
op(0xe2, Loop)
|
||||||
case 0xe3: return opJumpIf(r.cx == 0);
|
op(0xe3, JumpIf, r.cx == 0)
|
||||||
case 0xe4: return opIn(Byte);
|
op(0xe4, In, Byte)
|
||||||
case 0xe5: return opIn(Word);
|
op(0xe5, In, Word)
|
||||||
case 0xe6: return opOut(Byte);
|
op(0xe6, Out, Byte)
|
||||||
case 0xe7: return opOut(Word);
|
op(0xe7, Out, Word)
|
||||||
case 0xe8: return opCallNear();
|
op(0xe8, CallNear)
|
||||||
case 0xe9: return opJumpNear();
|
op(0xe9, JumpNear)
|
||||||
case 0xea: return opJumpFar();
|
op(0xea, JumpFar)
|
||||||
case 0xeb: return opJumpShort();
|
op(0xeb, JumpShort)
|
||||||
case 0xec: return opInDX(Byte);
|
op(0xec, InDX, Byte)
|
||||||
case 0xed: return opInDX(Word);
|
op(0xed, InDX, Word)
|
||||||
case 0xee: return opOutDX(Byte);
|
op(0xee, OutDX, Byte)
|
||||||
case 0xef: return opOutDX(Word);
|
op(0xef, OutDX, Word)
|
||||||
case 0xf0: return opLock();
|
op(0xf0, Lock)
|
||||||
case 0xf1: return;
|
//op(0xf1, ...)
|
||||||
case 0xf2: return opRepeat(0); //repnz
|
op(0xf2, Repeat, 0) //repnz
|
||||||
case 0xf3: return opRepeat(1); //repz
|
op(0xf3, Repeat, 1) //repz
|
||||||
case 0xf4: return opHalt();
|
op(0xf4, Halt)
|
||||||
case 0xf5: return opComplementCarry();
|
op(0xf5, ComplementCarry)
|
||||||
case 0xf6: return opGroup3MemImm(Byte);
|
op(0xf6, Group3MemImm, Byte)
|
||||||
case 0xf7: return opGroup3MemImm(Word);
|
op(0xf7, Group3MemImm, Word)
|
||||||
case 0xf8: return opClearFlag(r.f.c.bit);
|
op(0xf8, ClearFlag, r.f.c.bit)
|
||||||
case 0xf9: return opSetFlag(r.f.c.bit);
|
op(0xf9, SetFlag, r.f.c.bit)
|
||||||
case 0xfa: return opClearFlag(r.f.i.bit);
|
op(0xfa, ClearFlag, r.f.i.bit)
|
||||||
case 0xfb: return opSetFlag(r.f.i.bit);
|
op(0xfb, SetFlag, r.f.i.bit)
|
||||||
case 0xfc: return opClearFlag(r.f.d.bit);
|
op(0xfc, ClearFlag, r.f.d.bit)
|
||||||
case 0xfd: return opSetFlag(r.f.d.bit);
|
op(0xfd, SetFlag, r.f.d.bit)
|
||||||
case 0xfe: return opGroup4MemImm(Byte);
|
op(0xfe, Group4MemImm, Byte)
|
||||||
case 0xff: return opGroup4MemImm(Word);
|
op(0xff, Group4MemImm, Word)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef op
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
//27 daa
|
auto V30MZ::instructionDecimalAdjust(bool negate) -> void {
|
||||||
//2f das
|
|
||||||
auto V30MZ::opDecimalAdjust(bool negate) {
|
|
||||||
wait(9);
|
wait(9);
|
||||||
uint8 al = r.al;
|
uint8 al = r.al;
|
||||||
if(r.f.h || ((al & 0x0f) > 0x09)) {
|
if(r.f.h || ((al & 0x0f) > 0x09)) {
|
||||||
|
@ -16,9 +14,7 @@ auto V30MZ::opDecimalAdjust(bool negate) {
|
||||||
r.f.p = parity(r.al);
|
r.f.p = parity(r.al);
|
||||||
}
|
}
|
||||||
|
|
||||||
//37 aaa
|
auto V30MZ::instructionAsciiAdjust(bool negate) -> void {
|
||||||
//3f aas
|
|
||||||
auto V30MZ::opAsciiAdjust(bool negate) {
|
|
||||||
wait(8);
|
wait(8);
|
||||||
if(r.f.h || ((r.al & 0x0f) > 0x09)) {
|
if(r.f.h || ((r.al & 0x0f) > 0x09)) {
|
||||||
r.al += negate ? -0x06 : 0x06;
|
r.al += negate ? -0x06 : 0x06;
|
||||||
|
@ -32,8 +28,7 @@ auto V30MZ::opAsciiAdjust(bool negate) {
|
||||||
r.al &= 0x0f;
|
r.al &= 0x0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
//d4 aam,immb
|
auto V30MZ::instructionAdjustAfterMultiply() -> void {
|
||||||
auto V30MZ::opAdjustAfterMultiply() {
|
|
||||||
wait(16);
|
wait(16);
|
||||||
auto imm = fetch();
|
auto imm = fetch();
|
||||||
if(imm == 0) return interrupt(0);
|
if(imm == 0) return interrupt(0);
|
||||||
|
@ -44,8 +39,7 @@ auto V30MZ::opAdjustAfterMultiply() {
|
||||||
r.f.z = r.ax == 0;
|
r.f.z = r.ax == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//d5 aad,immw
|
auto V30MZ::instructionAdjustAfterDivide() -> void {
|
||||||
auto V30MZ::opAdjustAfterDivide() {
|
|
||||||
wait(5);
|
wait(5);
|
||||||
auto imm = fetch();
|
auto imm = fetch();
|
||||||
r.al += r.ah * imm;
|
r.al += r.ah * imm;
|
||||||
|
|
|
@ -1,172 +1,142 @@
|
||||||
//00 addb mem,reg
|
auto V30MZ::instructionAddMemReg(Size size) -> void {
|
||||||
//01 addw mem,reg
|
|
||||||
auto V30MZ::opAddMemReg(Size size) {
|
|
||||||
modRM();
|
modRM();
|
||||||
setMem(size, alAdd(size, getMem(size), getReg(size)));
|
setMem(size, ADD(size, getMem(size), getReg(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//02 addb reg,mem
|
auto V30MZ::instructionAddRegMem(Size size) -> void {
|
||||||
//03 addw reg,mem
|
|
||||||
auto V30MZ::opAddRegMem(Size size) {
|
|
||||||
modRM();
|
modRM();
|
||||||
setReg(size, alAdd(size, getReg(size), getMem(size)));
|
setReg(size, ADD(size, getReg(size), getMem(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//04 add al,#imm
|
auto V30MZ::instructionAddAccImm(Size size) -> void {
|
||||||
//05 add ax,#imm
|
setAcc(size, ADD(size, getAcc(size), fetch(size)));
|
||||||
auto V30MZ::opAddAccImm(Size size) {
|
|
||||||
setAcc(size, alAdd(size, getAcc(size), fetch(size)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//08 orb mem,reg
|
auto V30MZ::instructionOrMemReg(Size size) -> void {
|
||||||
//09 orb mem,reg
|
|
||||||
auto V30MZ::opOrMemReg(Size size) {
|
|
||||||
modRM();
|
modRM();
|
||||||
setMem(size, alOr(size, getMem(size), getReg(size)));
|
setMem(size, OR(size, getMem(size), getReg(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//0a orb reg,mem
|
auto V30MZ::instructionOrRegMem(Size size) -> void {
|
||||||
//0b orb reg,mem
|
|
||||||
auto V30MZ::opOrRegMem(Size size) {
|
|
||||||
modRM();
|
modRM();
|
||||||
setReg(size, alOr(size, getReg(size), getMem(size)));
|
setReg(size, OR(size, getReg(size), getMem(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//0c or al,#imm
|
auto V30MZ::instructionOrAccImm(Size size) -> void {
|
||||||
//0d or ax,#imm
|
setAcc(size, OR(size, getAcc(size), fetch(size)));
|
||||||
auto V30MZ::opOrAccImm(Size size) {
|
|
||||||
setAcc(size, alOr(size, getAcc(size), fetch(size)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opAdcMemReg(Size size) {
|
auto V30MZ::instructionAdcMemReg(Size size) -> void {
|
||||||
modRM();
|
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();
|
modRM();
|
||||||
setReg(size, alAdc(size, getReg(size), getMem(size)));
|
setReg(size, ADC(size, getReg(size), getMem(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opAdcAccImm(Size size) {
|
auto V30MZ::instructionAdcAccImm(Size size) -> void {
|
||||||
setAcc(size, alAdc(size, getAcc(size), fetch(size)));
|
setAcc(size, ADC(size, getAcc(size), fetch(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opSbbMemReg(Size size) {
|
auto V30MZ::instructionSbbMemReg(Size size) -> void {
|
||||||
modRM();
|
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();
|
modRM();
|
||||||
setReg(size, alSbb(size, getReg(size), getMem(size)));
|
setReg(size, SBB(size, getReg(size), getMem(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opSbbAccImm(Size size) {
|
auto V30MZ::instructionSbbAccImm(Size size) -> void {
|
||||||
setAcc(size, alSbb(size, getAcc(size), fetch(size)));
|
setAcc(size, SBB(size, getAcc(size), fetch(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opAndMemReg(Size size) {
|
auto V30MZ::instructionAndMemReg(Size size) -> void {
|
||||||
modRM();
|
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();
|
modRM();
|
||||||
setReg(size, alAnd(size, getReg(size), getMem(size)));
|
setReg(size, AND(size, getReg(size), getMem(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opAndAccImm(Size size) {
|
auto V30MZ::instructionAndAccImm(Size size) -> void {
|
||||||
setAcc(size, alAnd(size, getAcc(size), fetch(size)));
|
setAcc(size, AND(size, getAcc(size), fetch(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opSubMemReg(Size size) {
|
auto V30MZ::instructionSubMemReg(Size size) -> void {
|
||||||
modRM();
|
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();
|
modRM();
|
||||||
setReg(size, alSub(size, getReg(size), getMem(size)));
|
setReg(size, SUB(size, getReg(size), getMem(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opSubAccImm(Size size) {
|
auto V30MZ::instructionSubAccImm(Size size) -> void {
|
||||||
setAcc(size, alSub(size, getAcc(size), fetch(size)));
|
setAcc(size, SUB(size, getAcc(size), fetch(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opXorMemReg(Size size) {
|
auto V30MZ::instructionXorMemReg(Size size) -> void {
|
||||||
modRM();
|
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();
|
modRM();
|
||||||
setReg(size, alXor(size, getReg(size), getMem(size)));
|
setReg(size, XOR(size, getReg(size), getMem(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opXorAccImm(Size size) {
|
auto V30MZ::instructionXorAccImm(Size size) -> void {
|
||||||
setAcc(size, alXor(size, getAcc(size), fetch(size)));
|
setAcc(size, XOR(size, getAcc(size), fetch(size)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opCmpMemReg(Size size) {
|
auto V30MZ::instructionCmpMemReg(Size size) -> void {
|
||||||
modRM();
|
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();
|
modRM();
|
||||||
alSub(size, getReg(size), getMem(size));
|
SUB(size, getReg(size), getMem(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opCmpAccImm(Size size) {
|
auto V30MZ::instructionCmpAccImm(Size size) -> void {
|
||||||
alSub(size, getAcc(size), fetch(size));
|
SUB(size, getAcc(size), fetch(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opTestAcc(Size size) {
|
auto V30MZ::instructionTestAcc(Size size) -> void {
|
||||||
alAnd(size, getAcc(size), fetch(size));
|
AND(size, getAcc(size), fetch(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opTestMemReg(Size size) {
|
auto V30MZ::instructionTestMemReg(Size size) -> void {
|
||||||
modRM();
|
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);
|
wait(2);
|
||||||
modRM();
|
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
|
auto V30MZ::instructionIncReg(uint16_t& reg) -> void {
|
||||||
//41 inc cx
|
reg = INC(Word, reg);
|
||||||
//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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//48 dec ax
|
auto V30MZ::instructionDecReg(uint16_t& reg) -> void {
|
||||||
//49 dec cx
|
reg = DEC(Word, reg);
|
||||||
//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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//98 cbw
|
auto V30MZ::instructionSignExtendByte() -> void {
|
||||||
auto V30MZ::opSignExtendByte() {
|
|
||||||
setAcc(Word, (int8)getAcc(Byte));
|
setAcc(Word, (int8)getAcc(Byte));
|
||||||
}
|
}
|
||||||
|
|
||||||
//99 cwd
|
auto V30MZ::instructionSignExtendWord() -> void {
|
||||||
auto V30MZ::opSignExtendWord() {
|
|
||||||
setAcc(Long, (int16)getAcc(Word));
|
setAcc(Long, (int16)getAcc(Word));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
auto V30MZ::opLoop() {
|
auto V30MZ::instructionLoop() -> void {
|
||||||
wait(1);
|
wait(1);
|
||||||
auto offset = (int8)fetch();
|
auto offset = (int8)fetch();
|
||||||
if(--r.cx) {
|
if(--r.cx) {
|
||||||
|
@ -7,7 +7,7 @@ auto V30MZ::opLoop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opLoopWhile(bool value) {
|
auto V30MZ::instructionLoopWhile(bool value) -> void {
|
||||||
wait(2);
|
wait(2);
|
||||||
auto offset = (int8)fetch();
|
auto offset = (int8)fetch();
|
||||||
if(--r.cx && r.f.z == value) {
|
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);
|
wait(3);
|
||||||
auto offset = (int8)fetch();
|
auto offset = (int8)fetch();
|
||||||
r.ip += offset;
|
r.ip += offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opJumpIf(bool condition) {
|
auto V30MZ::instructionJumpIf(bool condition) -> void {
|
||||||
auto offset = (int8)fetch();
|
auto offset = (int8)fetch();
|
||||||
if(condition) r.ip += offset;
|
if(condition) r.ip += offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opJumpNear() {
|
auto V30MZ::instructionJumpNear() -> void {
|
||||||
wait(3);
|
wait(3);
|
||||||
r.ip += (int16)fetch(Word);
|
r.ip += (int16)fetch(Word);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opJumpFar() {
|
auto V30MZ::instructionJumpFar() -> void {
|
||||||
wait(6);
|
wait(6);
|
||||||
auto ip = fetch(Word);
|
auto ip = fetch(Word);
|
||||||
auto cs = fetch(Word);
|
auto cs = fetch(Word);
|
||||||
|
@ -40,14 +40,14 @@ auto V30MZ::opJumpFar() {
|
||||||
r.ip = ip;
|
r.ip = ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opCallNear() {
|
auto V30MZ::instructionCallNear() -> void {
|
||||||
wait(4);
|
wait(4);
|
||||||
auto offset = (int16)fetch(Word);
|
auto offset = (int16)fetch(Word);
|
||||||
push(r.ip);
|
push(r.ip);
|
||||||
r.ip += offset;
|
r.ip += offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opCallFar() {
|
auto V30MZ::instructionCallFar() -> void {
|
||||||
wait(9);
|
wait(9);
|
||||||
auto ip = fetch(Word);
|
auto ip = fetch(Word);
|
||||||
auto cs = fetch(Word);
|
auto cs = fetch(Word);
|
||||||
|
@ -57,25 +57,25 @@ auto V30MZ::opCallFar() {
|
||||||
r.ip = ip;
|
r.ip = ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opReturn() {
|
auto V30MZ::instructionReturn() -> void {
|
||||||
wait(5);
|
wait(5);
|
||||||
r.ip = pop();
|
r.ip = pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opReturnImm() {
|
auto V30MZ::instructionReturnImm() -> void {
|
||||||
wait(5);
|
wait(5);
|
||||||
auto offset = fetch(Word);
|
auto offset = fetch(Word);
|
||||||
r.ip = pop();
|
r.ip = pop();
|
||||||
r.sp += offset;
|
r.sp += offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opReturnFar() {
|
auto V30MZ::instructionReturnFar() -> void {
|
||||||
wait(7);
|
wait(7);
|
||||||
r.ip = pop();
|
r.ip = pop();
|
||||||
r.cs = pop();
|
r.cs = pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opReturnFarImm() {
|
auto V30MZ::instructionReturnFarImm() -> void {
|
||||||
wait(8);
|
wait(8);
|
||||||
auto offset = fetch(Word);
|
auto offset = fetch(Word);
|
||||||
r.ip = pop();
|
r.ip = pop();
|
||||||
|
@ -83,8 +83,7 @@ auto V30MZ::opReturnFarImm() {
|
||||||
r.sp += offset;
|
r.sp += offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
//cf iret
|
auto V30MZ::instructionReturnInt() -> void {
|
||||||
auto V30MZ::opReturnInt() {
|
|
||||||
wait(9);
|
wait(9);
|
||||||
r.ip = pop();
|
r.ip = pop();
|
||||||
r.cs = pop();
|
r.cs = pop();
|
||||||
|
@ -92,22 +91,22 @@ auto V30MZ::opReturnInt() {
|
||||||
state.poll = false;
|
state.poll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opInt3() {
|
auto V30MZ::instructionInt3() -> void {
|
||||||
wait(8);
|
wait(8);
|
||||||
interrupt(3);
|
interrupt(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opIntImm() {
|
auto V30MZ::instructionIntImm() -> void {
|
||||||
wait(9);
|
wait(9);
|
||||||
interrupt(fetch());
|
interrupt(fetch());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opInto() {
|
auto V30MZ::instructionInto() -> void {
|
||||||
wait(5);
|
wait(5);
|
||||||
interrupt(4);
|
interrupt(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opEnter() {
|
auto V30MZ::instructionEnter() -> void {
|
||||||
wait(7);
|
wait(7);
|
||||||
auto offset = fetch(Word);
|
auto offset = fetch(Word);
|
||||||
auto length = fetch(Byte) & 0x1f;
|
auto length = fetch(Byte) & 0x1f;
|
||||||
|
@ -126,36 +125,33 @@ auto V30MZ::opEnter() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opLeave() {
|
auto V30MZ::instructionLeave() -> void {
|
||||||
wait(1);
|
wait(1);
|
||||||
r.sp = r.bp;
|
r.sp = r.bp;
|
||||||
r.bp = pop();
|
r.bp = pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opPushReg(uint16_t& reg) {
|
auto V30MZ::instructionPushReg(uint16_t& reg) -> void {
|
||||||
push(reg);
|
push(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opPopReg(uint16_t& reg) {
|
auto V30MZ::instructionPopReg(uint16_t& reg) -> void {
|
||||||
reg = pop();
|
reg = pop();
|
||||||
if(® == &r.ss) state.poll = false;
|
if(® == &r.ss) state.poll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//9c pushf
|
auto V30MZ::instructionPushFlags() -> void {
|
||||||
auto V30MZ::opPushFlags() {
|
|
||||||
wait(1);
|
wait(1);
|
||||||
push(r.f);
|
push(r.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
//9d popf
|
auto V30MZ::instructionPopFlags() -> void {
|
||||||
auto V30MZ::opPopFlags() {
|
|
||||||
wait(2);
|
wait(2);
|
||||||
r.f = pop();
|
r.f = pop();
|
||||||
state.poll = false;
|
state.poll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//60 pusha
|
auto V30MZ::instructionPushAll() -> void {
|
||||||
auto V30MZ::opPushAll() {
|
|
||||||
wait(8);
|
wait(8);
|
||||||
auto sp = r.sp;
|
auto sp = r.sp;
|
||||||
push(r.ax);
|
push(r.ax);
|
||||||
|
@ -168,8 +164,7 @@ auto V30MZ::opPushAll() {
|
||||||
push(r.di);
|
push(r.di);
|
||||||
}
|
}
|
||||||
|
|
||||||
//61 popa
|
auto V30MZ::instructionPopAll() -> void {
|
||||||
auto V30MZ::opPopAll() {
|
|
||||||
wait(7);
|
wait(7);
|
||||||
r.di = pop();
|
r.di = pop();
|
||||||
r.si = pop();
|
r.si = pop();
|
||||||
|
@ -182,15 +177,12 @@ auto V30MZ::opPopAll() {
|
||||||
//r.sp is not restored
|
//r.sp is not restored
|
||||||
}
|
}
|
||||||
|
|
||||||
//68 push imm16
|
auto V30MZ::instructionPushImm(Size size) -> void {
|
||||||
//6a push imm8s
|
|
||||||
auto V30MZ::opPushImm(Size size) {
|
|
||||||
if(size == Byte) push((int8)fetch(Byte));
|
if(size == Byte) push((int8)fetch(Byte));
|
||||||
if(size == Word) push(fetch(Word));
|
if(size == Word) push(fetch(Word));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opPopMem() {
|
auto V30MZ::instructionPopMem() -> void {
|
||||||
modRM();
|
modRM();
|
||||||
setMem(Word, pop());
|
setMem(Word, pop());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,24 @@
|
||||||
//9e sahf
|
auto V30MZ::instructionStoreFlagsAcc() -> void {
|
||||||
auto V30MZ::opStoreFlagsAcc() {
|
|
||||||
wait(3);
|
wait(3);
|
||||||
r.f = (r.f & 0xff00) | r.ah;
|
r.f = (r.f & 0xff00) | r.ah;
|
||||||
}
|
}
|
||||||
|
|
||||||
//9f lahf
|
auto V30MZ::instructionLoadAccFlags() -> void {
|
||||||
auto V30MZ::opLoadAccFlags() {
|
|
||||||
wait(1);
|
wait(1);
|
||||||
r.ah = (r.f & 0x00ff);
|
r.ah = (r.f & 0x00ff);
|
||||||
}
|
}
|
||||||
|
|
||||||
//f5 cmc
|
auto V30MZ::instructionComplementCarry() -> void {
|
||||||
auto V30MZ::opComplementCarry() {
|
|
||||||
wait(3);
|
wait(3);
|
||||||
r.f.c = !r.f.c;
|
r.f.c = !r.f.c;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opClearFlag(uint bit) {
|
auto V30MZ::instructionClearFlag(uint bit) -> void {
|
||||||
wait(3);
|
wait(3);
|
||||||
r.f &= ~(1 << bit);
|
r.f &= ~(1 << bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opSetFlag(uint bit) {
|
auto V30MZ::instructionSetFlag(uint bit) -> void {
|
||||||
wait(3);
|
wait(3);
|
||||||
r.f |= 1 << bit;
|
r.f |= 1 << bit;
|
||||||
if(bit == r.f.i.bit) state.poll = false;
|
if(bit == r.f.i.bit) state.poll = false;
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
//80 grp1 memb,immb
|
auto V30MZ::instructionGroup1MemImm(Size size, bool sign) -> void {
|
||||||
//81 grp1 memw,immw
|
|
||||||
//82 grp1 memb,immbs
|
|
||||||
//83 grp1 memw,immbs
|
|
||||||
auto V30MZ::opGroup1MemImm(Size size, bool sign) {
|
|
||||||
modRM();
|
modRM();
|
||||||
auto mem = getMem(size);
|
auto mem = getMem(size);
|
||||||
uint16 imm = 0;
|
uint16 imm = 0;
|
||||||
|
@ -10,24 +6,18 @@ auto V30MZ::opGroup1MemImm(Size size, bool sign) {
|
||||||
else if(size == Byte) imm = fetch();
|
else if(size == Byte) imm = fetch();
|
||||||
else imm = fetch(Word);
|
else imm = fetch(Word);
|
||||||
switch(modrm.reg) {
|
switch(modrm.reg) {
|
||||||
case 0: setMem(size, alAdd(size, mem, imm)); break;
|
case 0: setMem(size, ADD(size, mem, imm)); break;
|
||||||
case 1: setMem(size, alOr (size, mem, imm)); break;
|
case 1: setMem(size, OR (size, mem, imm)); break;
|
||||||
case 2: setMem(size, alAdc(size, mem, imm)); break;
|
case 2: setMem(size, ADC(size, mem, imm)); break;
|
||||||
case 3: setMem(size, alSbb(size, mem, imm)); break;
|
case 3: setMem(size, SBB(size, mem, imm)); break;
|
||||||
case 4: setMem(size, alAnd(size, mem, imm)); break;
|
case 4: setMem(size, AND(size, mem, imm)); break;
|
||||||
case 5: setMem(size, alSub(size, mem, imm)); break;
|
case 5: setMem(size, SUB(size, mem, imm)); break;
|
||||||
case 6: setMem(size, alXor(size, mem, imm)); break;
|
case 6: setMem(size, XOR(size, mem, imm)); break;
|
||||||
case 7: alSub(size, mem, imm); break;
|
case 7: SUB(size, mem, imm); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//c0 grp2 memb,imm8
|
auto V30MZ::instructionGroup2MemImm(Size size, maybe<uint8> imm) -> void {
|
||||||
//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) {
|
|
||||||
modRM();
|
modRM();
|
||||||
auto mem = getMem(size);
|
auto mem = getMem(size);
|
||||||
if(!imm) {
|
if(!imm) {
|
||||||
|
@ -35,46 +25,42 @@ auto V30MZ::opGroup2MemImm(Size size, maybe<uint8> imm) {
|
||||||
imm = fetch();
|
imm = fetch();
|
||||||
}
|
}
|
||||||
switch(modrm.reg) {
|
switch(modrm.reg) {
|
||||||
case 0: setMem(size, alRol(size, mem, *imm)); break;
|
case 0: setMem(size, ROL(size, mem, *imm)); break;
|
||||||
case 1: setMem(size, alRor(size, mem, *imm)); break;
|
case 1: setMem(size, ROR(size, mem, *imm)); break;
|
||||||
case 2: setMem(size, alRcl(size, mem, *imm)); break;
|
case 2: setMem(size, RCL(size, mem, *imm)); break;
|
||||||
case 3: setMem(size, alRcr(size, mem, *imm)); break;
|
case 3: setMem(size, RCR(size, mem, *imm)); break;
|
||||||
case 4: setMem(size, alShl(size, mem, *imm)); break;
|
case 4: setMem(size, SHL(size, mem, *imm)); break;
|
||||||
case 5: setMem(size, alShr(size, mem, *imm)); break;
|
case 5: setMem(size, SHR(size, mem, *imm)); break;
|
||||||
case 6: setMem(size, alSal(size, mem, *imm)); break;
|
case 6: setMem(size, SAL(size, mem, *imm)); break;
|
||||||
case 7: setMem(size, alSar(size, mem, *imm)); break;
|
case 7: setMem(size, SAR(size, mem, *imm)); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//f6 grp3 memb
|
auto V30MZ::instructionGroup3MemImm(Size size) -> void {
|
||||||
//f7 grp3 memw
|
|
||||||
auto V30MZ::opGroup3MemImm(Size size) {
|
|
||||||
modRM();
|
modRM();
|
||||||
auto mem = getMem(size);
|
auto mem = getMem(size);
|
||||||
switch(modrm.reg) {
|
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 1: warning("[V30MZ] GRP3.1"); break;
|
||||||
case 2: wait(2); setMem(size, alNot(size, mem)); break;
|
case 2: wait(2); setMem(size, NOT(size, mem)); break;
|
||||||
case 3: wait(2); setMem(size, alNeg(size, mem)); break;
|
case 3: wait(2); setMem(size, NEG(size, mem)); break;
|
||||||
case 4: wait(2); setAcc(size * 2, alMul(size, getAcc(size), mem)); break;
|
case 4: wait(2); setAcc(size * 2, MUL(size, getAcc(size), mem)); break;
|
||||||
case 5: wait(2); setAcc(size * 2, alMuli(size, getAcc(size), mem)); break; 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, alDiv(size, getAcc(size * 2), mem)); 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, alDivi(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
|
auto V30MZ::instructionGroup4MemImm(Size size) -> void {
|
||||||
//ff grp4 memw
|
|
||||||
auto V30MZ::opGroup4MemImm(Size size) {
|
|
||||||
modRM();
|
modRM();
|
||||||
switch(modrm.reg) {
|
switch(modrm.reg) {
|
||||||
case 0:
|
case 0:
|
||||||
wait(2);
|
wait(2);
|
||||||
setMem(size, alInc(size, getMem(size)));
|
setMem(size, INC(size, getMem(size)));
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
wait(2);
|
wait(2);
|
||||||
setMem(size, alDec(size, getMem(size)));
|
setMem(size, DEC(size, getMem(size)));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if(size == Byte) { warning("[V30MZ] GRP4.2"); break; }
|
if(size == Byte) { warning("[V30MZ] GRP4.2"); break; }
|
||||||
|
|
|
@ -1,17 +1,11 @@
|
||||||
//26 es:
|
auto V30MZ::instructionSegment(uint16 segment) -> void {
|
||||||
//2e cs:
|
|
||||||
//36 ss:
|
|
||||||
//3e ds:
|
|
||||||
auto V30MZ::opSegment(uint16 segment) {
|
|
||||||
if(prefixes.size() >= 7) prefixes.removeRight();
|
if(prefixes.size() >= 7) prefixes.removeRight();
|
||||||
prefixes.prepend(opcode);
|
prefixes.prepend(opcode);
|
||||||
state.prefix = true;
|
state.prefix = true;
|
||||||
state.poll = false;
|
state.poll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//f2 repnz:
|
auto V30MZ::instructionRepeat(bool flag) -> void {
|
||||||
//f3 repz:
|
|
||||||
auto V30MZ::opRepeat(bool flag) {
|
|
||||||
if(prefixes.size() >= 7) prefixes.removeRight();
|
if(prefixes.size() >= 7) prefixes.removeRight();
|
||||||
prefixes.prepend(opcode);
|
prefixes.prepend(opcode);
|
||||||
wait(4);
|
wait(4);
|
||||||
|
@ -19,56 +13,50 @@ auto V30MZ::opRepeat(bool flag) {
|
||||||
state.poll = false;
|
state.poll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//f0 lock:
|
auto V30MZ::instructionLock() -> void {
|
||||||
auto V30MZ::opLock() {
|
|
||||||
if(prefixes.size() >= 7) prefixes.removeRight();
|
if(prefixes.size() >= 7) prefixes.removeRight();
|
||||||
prefixes.prepend(opcode);
|
prefixes.prepend(opcode);
|
||||||
state.prefix = true;
|
state.prefix = true;
|
||||||
state.poll = false;
|
state.poll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//9b wait
|
auto V30MZ::instructionWait() -> void {
|
||||||
auto V30MZ::opWait() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//f4 hlt
|
auto V30MZ::instructionHalt() -> void {
|
||||||
auto V30MZ::opHalt() {
|
|
||||||
wait(8);
|
wait(8);
|
||||||
state.halt = true;
|
state.halt = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//90 nop
|
auto V30MZ::instructionNop() -> void {
|
||||||
auto V30MZ::opNop() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opIn(Size size) {
|
auto V30MZ::instructionIn(Size size) -> void {
|
||||||
wait(5);
|
wait(5);
|
||||||
setAcc(size, in(size, fetch()));
|
setAcc(size, in(size, fetch()));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opOut(Size size) {
|
auto V30MZ::instructionOut(Size size) -> void {
|
||||||
wait(5);
|
wait(5);
|
||||||
out(size, fetch(), getAcc(size));
|
out(size, fetch(), getAcc(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opInDX(Size size) {
|
auto V30MZ::instructionInDX(Size size) -> void {
|
||||||
wait(5);
|
wait(5);
|
||||||
setAcc(size, in(size, r.dx));
|
setAcc(size, in(size, r.dx));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opOutDX(Size size) {
|
auto V30MZ::instructionOutDX(Size size) -> void {
|
||||||
wait(5);
|
wait(5);
|
||||||
out(size, r.dx, getAcc(size));
|
out(size, r.dx, getAcc(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
//d7 xlat
|
auto V30MZ::instructionTranslate() -> void {
|
||||||
auto V30MZ::opTranslate() {
|
|
||||||
wait(4);
|
wait(4);
|
||||||
r.al = read(Byte, segment(r.ds), r.bx + r.al);
|
r.al = read(Byte, segment(r.ds), r.bx + r.al);
|
||||||
}
|
}
|
||||||
|
|
||||||
//62 bound reg,mem,mem
|
auto V30MZ::instructionBound() -> void {
|
||||||
auto V30MZ::opBound() {
|
|
||||||
wait(12);
|
wait(12);
|
||||||
modRM();
|
modRM();
|
||||||
auto lo = getMem(Word, 0);
|
auto lo = getMem(Word, 0);
|
||||||
|
|
|
@ -1,57 +1,55 @@
|
||||||
auto V30MZ::opMoveMemReg(Size size) {
|
auto V30MZ::instructionMoveMemReg(Size size) -> void {
|
||||||
modRM();
|
modRM();
|
||||||
setMem(size, getReg(size));
|
setMem(size, getReg(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opMoveRegMem(Size size) {
|
auto V30MZ::instructionMoveRegMem(Size size) -> void {
|
||||||
modRM();
|
modRM();
|
||||||
setReg(size, getMem(size));
|
setReg(size, getMem(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
//8c mov memw,seg
|
auto V30MZ::instructionMoveMemSeg() -> void {
|
||||||
auto V30MZ::opMoveMemSeg() {
|
|
||||||
modRM();
|
modRM();
|
||||||
setMem(Word, getSeg());
|
setMem(Word, getSeg());
|
||||||
state.poll = false;
|
state.poll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//8e mov seg,memw
|
auto V30MZ::instructionMoveSegMem() -> void {
|
||||||
auto V30MZ::opMoveSegMem() {
|
|
||||||
wait(1);
|
wait(1);
|
||||||
modRM();
|
modRM();
|
||||||
setSeg(getMem(Word));
|
setSeg(getMem(Word));
|
||||||
if((modrm.reg & 3) == 3) state.poll = false;
|
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)));
|
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));
|
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);
|
reg = fetch(Byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opMoveRegImm(uint16_t& reg) {
|
auto V30MZ::instructionMoveRegImm(uint16_t& reg) -> void {
|
||||||
reg = fetch(Word);
|
reg = fetch(Word);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opMoveMemImm(Size size) {
|
auto V30MZ::instructionMoveMemImm(Size size) -> void {
|
||||||
modRM();
|
modRM();
|
||||||
setMem(size, fetch(size));
|
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);
|
wait(2);
|
||||||
uint16 z = x;
|
uint16 z = x;
|
||||||
x = y;
|
x = y;
|
||||||
y = z;
|
y = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opExchangeMemReg(Size size) {
|
auto V30MZ::instructionExchangeMemReg(Size size) -> void {
|
||||||
wait(2);
|
wait(2);
|
||||||
modRM();
|
modRM();
|
||||||
auto mem = getMem(size);
|
auto mem = getMem(size);
|
||||||
|
@ -60,12 +58,12 @@ auto V30MZ::opExchangeMemReg(Size size) {
|
||||||
setReg(size, mem);
|
setReg(size, mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opLoadEffectiveAddressRegMem() {
|
auto V30MZ::instructionLoadEffectiveAddressRegMem() -> void {
|
||||||
modRM();
|
modRM();
|
||||||
setReg(Word, modrm.address);
|
setReg(Word, modrm.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto V30MZ::opLoadSegmentMem(uint16_t& segment) {
|
auto V30MZ::instructionLoadSegmentMem(uint16_t& segment) -> void {
|
||||||
wait(5);
|
wait(5);
|
||||||
modRM();
|
modRM();
|
||||||
setReg(Word, getMem(Word));
|
setReg(Word, getMem(Word));
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
auto V30MZ::opInString(Size size) {
|
auto V30MZ::instructionInString(Size size) -> void {
|
||||||
wait(5);
|
wait(5);
|
||||||
if(!repeat() || r.cx) {
|
if(!repeat() || r.cx) {
|
||||||
auto data = in(size, r.dx);
|
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);
|
wait(6);
|
||||||
if(!repeat() || r.cx) {
|
if(!repeat() || r.cx) {
|
||||||
auto data = read(size, segment(r.ds), r.si);
|
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);
|
wait(4);
|
||||||
if(!repeat() || r.cx) {
|
if(!repeat() || r.cx) {
|
||||||
auto data = read(size, segment(r.ds), r.si);
|
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);
|
wait(5);
|
||||||
if(!repeat() || r.cx) {
|
if(!repeat() || r.cx) {
|
||||||
auto x = read(size, segment(r.ds), r.si);
|
auto x = read(size, segment(r.ds), r.si);
|
||||||
auto y = read(size, r.es, r.di);
|
auto y = read(size, r.es, r.di);
|
||||||
r.si += r.f.d ? -size : size;
|
r.si += r.f.d ? -size : size;
|
||||||
r.di += 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() || !--r.cx) return;
|
||||||
if(repeat() == RepeatWhileZero && r.f.z == 0) 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);
|
wait(2);
|
||||||
if(!repeat() || r.cx) {
|
if(!repeat() || r.cx) {
|
||||||
write(size, r.es, r.di, getAcc(size));
|
write(size, r.es, r.di, getAcc(size));
|
||||||
|
@ -72,9 +72,7 @@ auto V30MZ::opStoreString(Size size) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//ac lodsb
|
auto V30MZ::instructionLoadString(Size size) -> void {
|
||||||
//ad lodsw
|
|
||||||
auto V30MZ::opLoadString(Size size) {
|
|
||||||
wait(2);
|
wait(2);
|
||||||
if(!repeat() || r.cx) {
|
if(!repeat() || r.cx) {
|
||||||
setAcc(size, read(size, segment(r.ds), r.si));
|
setAcc(size, read(size, segment(r.ds), r.si));
|
||||||
|
@ -87,15 +85,13 @@ auto V30MZ::opLoadString(Size size) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//ae scasb
|
auto V30MZ::instructionScanString(Size size) -> void {
|
||||||
//af scasw
|
|
||||||
auto V30MZ::opScanString(Size size) {
|
|
||||||
wait(3);
|
wait(3);
|
||||||
if(!repeat() || r.cx) {
|
if(!repeat() || r.cx) {
|
||||||
auto x = getAcc(size);
|
auto x = getAcc(size);
|
||||||
auto y = read(size, r.es, r.di);
|
auto y = read(size, r.es, r.di);
|
||||||
r.di += 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() || !--r.cx) return;
|
||||||
if(repeat() == RepeatWhileZero && r.f.z == 0) return;
|
if(repeat() == RepeatWhileZero && r.f.z == 0) return;
|
||||||
|
|
|
@ -7,6 +7,7 @@ namespace Processor {
|
||||||
#include "modrm.cpp"
|
#include "modrm.cpp"
|
||||||
#include "memory.cpp"
|
#include "memory.cpp"
|
||||||
#include "algorithms.cpp"
|
#include "algorithms.cpp"
|
||||||
|
#include "instruction.cpp"
|
||||||
#include "instructions-adjust.cpp"
|
#include "instructions-adjust.cpp"
|
||||||
#include "instructions-alu.cpp"
|
#include "instructions-alu.cpp"
|
||||||
#include "instructions-exec.cpp"
|
#include "instructions-exec.cpp"
|
||||||
|
@ -15,7 +16,6 @@ namespace Processor {
|
||||||
#include "instructions-misc.cpp"
|
#include "instructions-misc.cpp"
|
||||||
#include "instructions-move.cpp"
|
#include "instructions-move.cpp"
|
||||||
#include "instructions-string.cpp"
|
#include "instructions-string.cpp"
|
||||||
#include "instruction.cpp"
|
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
#include "disassembler.cpp"
|
#include "disassembler.cpp"
|
||||||
|
|
||||||
|
|
|
@ -63,147 +63,147 @@ struct V30MZ {
|
||||||
|
|
||||||
//algorithms.cpp
|
//algorithms.cpp
|
||||||
auto parity(uint8) const -> bool;
|
auto parity(uint8) const -> bool;
|
||||||
auto alAdc (Size, uint16, uint16) -> uint16;
|
auto ADC (Size, uint16, uint16) -> uint16;
|
||||||
auto alAdd (Size, uint16, uint16) -> uint16;
|
auto ADD (Size, uint16, uint16) -> uint16;
|
||||||
auto alAnd (Size, uint16, uint16) -> uint16;
|
auto AND (Size, uint16, uint16) -> uint16;
|
||||||
auto alDec (Size, uint16 ) -> uint16;
|
auto DEC (Size, uint16 ) -> uint16;
|
||||||
auto alDiv (Size, uint32, uint32) -> uint32;
|
auto DIV (Size, uint32, uint32) -> uint32;
|
||||||
auto alDivi(Size, int32, int32) -> uint32;
|
auto DIVI(Size, int32, int32) -> uint32;
|
||||||
auto alInc (Size, uint16 ) -> uint16;
|
auto INC (Size, uint16 ) -> uint16;
|
||||||
auto alMul (Size, uint16, uint16) -> uint32;
|
auto MUL (Size, uint16, uint16) -> uint32;
|
||||||
auto alMuli(Size, int16, int16) -> uint32;
|
auto MULI(Size, int16, int16) -> uint32;
|
||||||
auto alNeg (Size, uint16 ) -> uint16;
|
auto NEG (Size, uint16 ) -> uint16;
|
||||||
auto alNot (Size, uint16 ) -> uint16;
|
auto NOT (Size, uint16 ) -> uint16;
|
||||||
auto alOr (Size, uint16, uint16) -> uint16;
|
auto OR (Size, uint16, uint16) -> uint16;
|
||||||
auto alRcl (Size, uint16, uint5) -> uint16;
|
auto RCL (Size, uint16, uint5) -> uint16;
|
||||||
auto alRcr (Size, uint16, uint5) -> uint16;
|
auto RCR (Size, uint16, uint5) -> uint16;
|
||||||
auto alRol (Size, uint16, uint4) -> uint16;
|
auto ROL (Size, uint16, uint4) -> uint16;
|
||||||
auto alRor (Size, uint16, uint4) -> uint16;
|
auto ROR (Size, uint16, uint4) -> uint16;
|
||||||
auto alSal (Size, uint16, uint5) -> uint16;
|
auto SAL (Size, uint16, uint5) -> uint16;
|
||||||
auto alSar (Size, uint16, uint5) -> uint16;
|
auto SAR (Size, uint16, uint5) -> uint16;
|
||||||
auto alSbb (Size, uint16, uint16) -> uint16;
|
auto SBB (Size, uint16, uint16) -> uint16;
|
||||||
auto alSub (Size, uint16, uint16) -> uint16;
|
auto SUB (Size, uint16, uint16) -> uint16;
|
||||||
auto alShl (Size, uint16, uint5) -> uint16;
|
auto SHL (Size, uint16, uint5) -> uint16;
|
||||||
auto alShr (Size, uint16, uint5) -> uint16;
|
auto SHR (Size, uint16, uint5) -> uint16;
|
||||||
auto alXor (Size, uint16, uint16) -> uint16;
|
auto XOR (Size, uint16, uint16) -> uint16;
|
||||||
|
|
||||||
//instructions-adjust.cpp
|
//instructions-adjust.cpp
|
||||||
auto opDecimalAdjust(bool);
|
auto instructionDecimalAdjust(bool) -> void;
|
||||||
auto opAsciiAdjust(bool);
|
auto instructionAsciiAdjust(bool) -> void;
|
||||||
auto opAdjustAfterMultiply();
|
auto instructionAdjustAfterMultiply() -> void;
|
||||||
auto opAdjustAfterDivide();
|
auto instructionAdjustAfterDivide() -> void;
|
||||||
|
|
||||||
//instructions-alu.cpp
|
//instructions-alu.cpp
|
||||||
auto opAddMemReg(Size);
|
auto instructionAddMemReg(Size) -> void;
|
||||||
auto opAddRegMem(Size);
|
auto instructionAddRegMem(Size) -> void;
|
||||||
auto opAddAccImm(Size);
|
auto instructionAddAccImm(Size) -> void;
|
||||||
auto opOrMemReg(Size);
|
auto instructionOrMemReg(Size) -> void;
|
||||||
auto opOrRegMem(Size);
|
auto instructionOrRegMem(Size) -> void;
|
||||||
auto opOrAccImm(Size);
|
auto instructionOrAccImm(Size) -> void;
|
||||||
auto opAdcMemReg(Size);
|
auto instructionAdcMemReg(Size) -> void;
|
||||||
auto opAdcRegMem(Size);
|
auto instructionAdcRegMem(Size) -> void;
|
||||||
auto opAdcAccImm(Size);
|
auto instructionAdcAccImm(Size) -> void;
|
||||||
auto opSbbMemReg(Size);
|
auto instructionSbbMemReg(Size) -> void;
|
||||||
auto opSbbRegMem(Size);
|
auto instructionSbbRegMem(Size) -> void;
|
||||||
auto opSbbAccImm(Size);
|
auto instructionSbbAccImm(Size) -> void;
|
||||||
auto opAndMemReg(Size);
|
auto instructionAndMemReg(Size) -> void;
|
||||||
auto opAndRegMem(Size);
|
auto instructionAndRegMem(Size) -> void;
|
||||||
auto opAndAccImm(Size);
|
auto instructionAndAccImm(Size) -> void;
|
||||||
auto opSubMemReg(Size);
|
auto instructionSubMemReg(Size) -> void;
|
||||||
auto opSubRegMem(Size);
|
auto instructionSubRegMem(Size) -> void;
|
||||||
auto opSubAccImm(Size);
|
auto instructionSubAccImm(Size) -> void;
|
||||||
auto opXorMemReg(Size);
|
auto instructionXorMemReg(Size) -> void;
|
||||||
auto opXorRegMem(Size);
|
auto instructionXorRegMem(Size) -> void;
|
||||||
auto opXorAccImm(Size);
|
auto instructionXorAccImm(Size) -> void;
|
||||||
auto opCmpMemReg(Size);
|
auto instructionCmpMemReg(Size) -> void;
|
||||||
auto opCmpRegMem(Size);
|
auto instructionCmpRegMem(Size) -> void;
|
||||||
auto opCmpAccImm(Size);
|
auto instructionCmpAccImm(Size) -> void;
|
||||||
auto opTestMemReg(Size);
|
auto instructionTestMemReg(Size) -> void;
|
||||||
auto opTestAcc(Size);
|
auto instructionTestAcc(Size) -> void;
|
||||||
auto opMultiplySignedRegMemImm(Size);
|
auto instructionMultiplySignedRegMemImm(Size) -> void;
|
||||||
auto opIncReg(uint16_t&);
|
auto instructionIncReg(uint16_t&) -> void;
|
||||||
auto opDecReg(uint16_t&);
|
auto instructionDecReg(uint16_t&) -> void;
|
||||||
auto opSignExtendByte();
|
auto instructionSignExtendByte() -> void;
|
||||||
auto opSignExtendWord();
|
auto instructionSignExtendWord() -> void;
|
||||||
|
|
||||||
//instructions-exec.cpp
|
//instructions-exec.cpp
|
||||||
auto opLoop();
|
auto instructionLoop() -> void;
|
||||||
auto opLoopWhile(bool);
|
auto instructionLoopWhile(bool) -> void;
|
||||||
auto opJumpShort();
|
auto instructionJumpShort() -> void;
|
||||||
auto opJumpIf(bool);
|
auto instructionJumpIf(bool) -> void;
|
||||||
auto opJumpNear();
|
auto instructionJumpNear() -> void;
|
||||||
auto opJumpFar();
|
auto instructionJumpFar() -> void;
|
||||||
auto opCallNear();
|
auto instructionCallNear() -> void;
|
||||||
auto opCallFar();
|
auto instructionCallFar() -> void;
|
||||||
auto opReturn();
|
auto instructionReturn() -> void;
|
||||||
auto opReturnImm();
|
auto instructionReturnImm() -> void;
|
||||||
auto opReturnFar();
|
auto instructionReturnFar() -> void;
|
||||||
auto opReturnFarImm();
|
auto instructionReturnFarImm() -> void;
|
||||||
auto opReturnInt();
|
auto instructionReturnInt() -> void;
|
||||||
auto opInt3();
|
auto instructionInt3() -> void;
|
||||||
auto opIntImm();
|
auto instructionIntImm() -> void;
|
||||||
auto opInto();
|
auto instructionInto() -> void;
|
||||||
auto opEnter();
|
auto instructionEnter() -> void;
|
||||||
auto opLeave();
|
auto instructionLeave() -> void;
|
||||||
auto opPushReg(uint16_t&);
|
auto instructionPushReg(uint16_t&) -> void;
|
||||||
auto opPopReg(uint16_t&);
|
auto instructionPopReg(uint16_t&) -> void;
|
||||||
auto opPushFlags();
|
auto instructionPushFlags() -> void;
|
||||||
auto opPopFlags();
|
auto instructionPopFlags() -> void;
|
||||||
auto opPushAll();
|
auto instructionPushAll() -> void;
|
||||||
auto opPopAll();
|
auto instructionPopAll() -> void;
|
||||||
auto opPushImm(Size);
|
auto instructionPushImm(Size) -> void;
|
||||||
auto opPopMem();
|
auto instructionPopMem() -> void;
|
||||||
|
|
||||||
//instructions-flag.cpp
|
//instructions-flag.cpp
|
||||||
auto opStoreFlagsAcc();
|
auto instructionStoreFlagsAcc() -> void;
|
||||||
auto opLoadAccFlags();
|
auto instructionLoadAccFlags() -> void;
|
||||||
auto opComplementCarry();
|
auto instructionComplementCarry() -> void;
|
||||||
auto opClearFlag(uint);
|
auto instructionClearFlag(uint) -> void;
|
||||||
auto opSetFlag(uint);
|
auto instructionSetFlag(uint) -> void;
|
||||||
|
|
||||||
//instructions-group.cpp
|
//instructions-group.cpp
|
||||||
auto opGroup1MemImm(Size, bool);
|
auto instructionGroup1MemImm(Size, bool) -> void;
|
||||||
auto opGroup2MemImm(Size, maybe<uint8> = {});
|
auto instructionGroup2MemImm(Size, maybe<uint8> = {}) -> void;
|
||||||
auto opGroup3MemImm(Size);
|
auto instructionGroup3MemImm(Size) -> void;
|
||||||
auto opGroup4MemImm(Size);
|
auto instructionGroup4MemImm(Size) -> void;
|
||||||
|
|
||||||
//instructions-misc.cpp
|
//instructions-misc.cpp
|
||||||
auto opSegment(uint16);
|
auto instructionSegment(uint16) -> void;
|
||||||
auto opRepeat(bool);
|
auto instructionRepeat(bool) -> void;
|
||||||
auto opLock();
|
auto instructionLock() -> void;
|
||||||
auto opWait();
|
auto instructionWait() -> void;
|
||||||
auto opHalt();
|
auto instructionHalt() -> void;
|
||||||
auto opNop();
|
auto instructionNop() -> void;
|
||||||
auto opIn(Size);
|
auto instructionIn(Size) -> void;
|
||||||
auto opOut(Size);
|
auto instructionOut(Size) -> void;
|
||||||
auto opInDX(Size);
|
auto instructionInDX(Size) -> void;
|
||||||
auto opOutDX(Size);
|
auto instructionOutDX(Size) -> void;
|
||||||
auto opTranslate();
|
auto instructionTranslate() -> void;
|
||||||
auto opBound();
|
auto instructionBound() -> void;
|
||||||
|
|
||||||
//instructions-move.cpp
|
//instructions-move.cpp
|
||||||
auto opMoveMemReg(Size);
|
auto instructionMoveMemReg(Size) -> void;
|
||||||
auto opMoveRegMem(Size);
|
auto instructionMoveRegMem(Size) -> void;
|
||||||
auto opMoveMemSeg();
|
auto instructionMoveMemSeg() -> void;
|
||||||
auto opMoveSegMem();
|
auto instructionMoveSegMem() -> void;
|
||||||
auto opMoveAccMem(Size);
|
auto instructionMoveAccMem(Size) -> void;
|
||||||
auto opMoveMemAcc(Size);
|
auto instructionMoveMemAcc(Size) -> void;
|
||||||
auto opMoveRegImm(uint8_t&);
|
auto instructionMoveRegImm(uint8_t&) -> void;
|
||||||
auto opMoveRegImm(uint16_t&);
|
auto instructionMoveRegImm(uint16_t&) -> void;
|
||||||
auto opMoveMemImm(Size);
|
auto instructionMoveMemImm(Size) -> void;
|
||||||
auto opExchange(uint16_t&, uint16_t&);
|
auto instructionExchange(uint16_t&, uint16_t&) -> void;
|
||||||
auto opExchangeMemReg(Size);
|
auto instructionExchangeMemReg(Size) -> void;
|
||||||
auto opLoadEffectiveAddressRegMem();
|
auto instructionLoadEffectiveAddressRegMem() -> void;
|
||||||
auto opLoadSegmentMem(uint16_t&);
|
auto instructionLoadSegmentMem(uint16_t&) -> void;
|
||||||
|
|
||||||
//instructions-string.cpp
|
//instructions-string.cpp
|
||||||
auto opInString(Size);
|
auto instructionInString(Size) -> void;
|
||||||
auto opOutString(Size);
|
auto instructionOutString(Size) -> void;
|
||||||
auto opMoveString(Size);
|
auto instructionMoveString(Size) -> void;
|
||||||
auto opCompareString(Size);
|
auto instructionCompareString(Size) -> void;
|
||||||
auto opStoreString(Size);
|
auto instructionStoreString(Size) -> void;
|
||||||
auto opLoadString(Size);
|
auto instructionLoadString(Size) -> void;
|
||||||
auto opScanString(Size);
|
auto instructionScanString(Size) -> void;
|
||||||
|
|
||||||
//serialization.cpp
|
//serialization.cpp
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
//ARMv3 (ARM60)
|
//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 {
|
struct ArmDSP : Processor::ARM7TDMI, Thread {
|
||||||
#include "registers.hpp"
|
#include "registers.hpp"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue