mirror of https://github.com/bsnes-emu/bsnes.git
Update to v106r85 release.
byuu says: The bad instruction was due to the instruction before it fetching one too many bytes. Didn't notice right away as the disassembler got it right. The register map was incorrect on the active 16-bit flags. I fixed and improved some other things along those lines. Hooked up some basic KnGE (VPU) timings, made it print out VRAM and some of the WRAM onto the screen each frame, tried to drive Vblank and Hblank IRQs, but ... I don't know for sure what vector addresses they belong to. MAME says "INT4" for Vblank, and says nothing for Hblank. I am wildly guessing INT4==SWI 4==0xffff10, but ... I have no idea. I'm also not emulating the interrupts properly based on line levels, I'm just firing on the 0→1 transitions. Sounds like Vblank is more nuanced too, but I guess we'll see. Emulation is running further along now, even to the point of it successfully enabling the KnGE IRQs, but VRAM doesn't appear to get much useful stuff written into it yet. I reverted the nall/primitive changes, so request for testing is I guess rescinded, for whatever it was worth.
This commit is contained in:
parent
53843934c0
commit
fbc1571889
|
@ -31,7 +31,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "106.84";
|
static const string Version = "106.85";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "https://byuu.org/";
|
static const string Website = "https://byuu.org/";
|
||||||
|
|
|
@ -24,7 +24,6 @@ struct Interface {
|
||||||
uint internalWidth = 0;
|
uint internalWidth = 0;
|
||||||
uint internalHeight = 0;
|
uint internalHeight = 0;
|
||||||
double aspectCorrection = 0;
|
double aspectCorrection = 0;
|
||||||
double refreshRate = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Port {
|
struct Port {
|
||||||
|
|
|
@ -22,7 +22,6 @@ auto Interface::display() -> Display {
|
||||||
display.internalWidth = 256;
|
display.internalWidth = 256;
|
||||||
display.internalHeight = 240;
|
display.internalHeight = 240;
|
||||||
display.aspectCorrection = 8.0 / 7.0;
|
display.aspectCorrection = 8.0 / 7.0;
|
||||||
display.refreshRate = system.frequency() / (ppu.vlines() * ppu.rate() * 341.0);
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ auto Interface::display() -> Display {
|
||||||
display.internalWidth = 160;
|
display.internalWidth = 160;
|
||||||
display.internalHeight = 144;
|
display.internalHeight = 144;
|
||||||
display.aspectCorrection = 1.0;
|
display.aspectCorrection = 1.0;
|
||||||
display.refreshRate = (4.0 * 1024.0 * 1024.0) / (154.0 * 456.0);
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ auto Interface::display() -> Display {
|
||||||
display.internalWidth = 240;
|
display.internalWidth = 240;
|
||||||
display.internalHeight = 160;
|
display.internalHeight = 160;
|
||||||
display.aspectCorrection = 1.0;
|
display.aspectCorrection = 1.0;
|
||||||
display.refreshRate = system.frequency() / (228.0 * 1232.0);
|
|
||||||
if(settings.rotateLeft) {
|
if(settings.rotateLeft) {
|
||||||
swap(display.width, display.height);
|
swap(display.width, display.height);
|
||||||
swap(display.internalWidth, display.internalHeight);
|
swap(display.internalWidth, display.internalHeight);
|
||||||
|
|
|
@ -22,7 +22,6 @@ auto Interface::display() -> Display {
|
||||||
display.internalWidth = 1280;
|
display.internalWidth = 1280;
|
||||||
display.internalHeight = 480;
|
display.internalHeight = 480;
|
||||||
display.aspectCorrection = 1.0;
|
display.aspectCorrection = 1.0;
|
||||||
display.refreshRate = (system.frequency() / 2.0) / (vdp.frameHeight() * 1710.0);
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,6 @@ auto ColecoVisionInterface::display() -> Display {
|
||||||
display.internalWidth = 256;
|
display.internalWidth = 256;
|
||||||
display.internalHeight = 192;
|
display.internalHeight = 192;
|
||||||
display.aspectCorrection = 1.0;
|
display.aspectCorrection = 1.0;
|
||||||
if(Region::NTSC()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
|
||||||
if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ auto GameGearInterface::display() -> Display {
|
||||||
display.internalWidth = 160;
|
display.internalWidth = 160;
|
||||||
display.internalHeight = 144;
|
display.internalHeight = 144;
|
||||||
display.aspectCorrection = 1.0;
|
display.aspectCorrection = 1.0;
|
||||||
display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,6 @@ auto MasterSystemInterface::display() -> Display {
|
||||||
display.internalWidth = 256;
|
display.internalWidth = 256;
|
||||||
display.internalHeight = 240;
|
display.internalHeight = 240;
|
||||||
display.aspectCorrection = 8.0 / 7.0;
|
display.aspectCorrection = 8.0 / 7.0;
|
||||||
if(Region::NTSC()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
|
||||||
if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,6 @@ auto SC3000Interface::display() -> Display {
|
||||||
display.internalWidth = 256;
|
display.internalWidth = 256;
|
||||||
display.internalHeight = 192;
|
display.internalHeight = 192;
|
||||||
display.aspectCorrection = 1.0;
|
display.aspectCorrection = 1.0;
|
||||||
if(Region::NTSC()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
|
||||||
if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,6 @@ auto SG1000Interface::display() -> Display {
|
||||||
display.internalWidth = 256;
|
display.internalWidth = 256;
|
||||||
display.internalHeight = 192;
|
display.internalHeight = 192;
|
||||||
display.aspectCorrection = 1.0;
|
display.aspectCorrection = 1.0;
|
||||||
if(Region::NTSC()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
|
||||||
if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ auto Interface::display() -> Display {
|
||||||
display.internalWidth = 256;
|
display.internalWidth = 256;
|
||||||
display.internalHeight = 192;
|
display.internalHeight = 192;
|
||||||
display.aspectCorrection = 1.0;
|
display.aspectCorrection = 1.0;
|
||||||
display.refreshRate = 60.0; //todo: PAL
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,7 @@ auto CPU::Enter() -> void {
|
||||||
|
|
||||||
auto CPU::main() -> void {
|
auto CPU::main() -> void {
|
||||||
static uint ctr=0;
|
static uint ctr=0;
|
||||||
if(++ctr < 200) print(disassemble(), "\n");
|
if(++ctr<200) print(disassemble(), "\n");
|
||||||
else return step(1);
|
|
||||||
instruction();
|
instruction();
|
||||||
step(1);
|
step(1);
|
||||||
}
|
}
|
||||||
|
@ -30,6 +29,17 @@ auto CPU::power() -> void {
|
||||||
create(CPU::Enter, system.frequency());
|
create(CPU::Enter, system.frequency());
|
||||||
ram.allocate(0x3000);
|
ram.allocate(0x3000);
|
||||||
r.pc.l.l0 = 0xff1800;
|
r.pc.l.l0 = 0xff1800;
|
||||||
|
io = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::setInterruptHblank(boolean line) -> void {
|
||||||
|
io.irq.hblank = line;
|
||||||
|
//if(line) interrupt(0xffff0c);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::setInterruptVblank(boolean line) -> void {
|
||||||
|
io.irq.vblank = line;
|
||||||
|
if(line) interrupt(0xffff10);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,23 @@ struct CPU : Processor::TLCS900H, Thread {
|
||||||
auto step(uint clocks) -> void override;
|
auto step(uint clocks) -> void override;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
|
auto setInterruptHblank(boolean line) -> void;
|
||||||
|
auto setInterruptVblank(boolean line) -> void;
|
||||||
|
|
||||||
//memory.cpp
|
//memory.cpp
|
||||||
auto read(uint24 address) -> uint8 override;
|
auto read(uint24 address) -> uint8 override;
|
||||||
auto write(uint24 address, uint8 data) -> void override;
|
auto write(uint24 address, uint8 data) -> void override;
|
||||||
|
|
||||||
//serialization.cpp
|
//serialization.cpp
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct IO {
|
||||||
|
struct IRQ {
|
||||||
|
boolean hblank;
|
||||||
|
boolean vblank;
|
||||||
|
} irq;
|
||||||
|
} io;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CPU cpu;
|
extern CPU cpu;
|
||||||
|
|
|
@ -15,7 +15,6 @@ auto Interface::display() -> Display {
|
||||||
display.internalWidth = 160;
|
display.internalWidth = 160;
|
||||||
display.internalHeight = 152;
|
display.internalHeight = 152;
|
||||||
display.aspectCorrection = 1.0;
|
display.aspectCorrection = 1.0;
|
||||||
display.refreshRate = 60.0;
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,34 @@ auto VPU::Enter() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VPU::main() -> void {
|
auto VPU::main() -> void {
|
||||||
step(system.frequency() / 60.0);
|
cpu.setInterruptHblank(0);
|
||||||
scheduler.exit(Scheduler::Event::Frame);
|
for(uint hclock : range(480)) {
|
||||||
|
io.hcounter++;
|
||||||
|
step(1);
|
||||||
|
}
|
||||||
|
if(io.vcounter <= 150) {
|
||||||
|
if(ram[0x0000].bit(6)) cpu.setInterruptHblank(1);
|
||||||
|
}
|
||||||
|
for(uint hclock : range(35)) {
|
||||||
|
io.hcounter++;
|
||||||
|
step(1);
|
||||||
|
}
|
||||||
|
cpu.setInterruptHblank(0);
|
||||||
|
io.hcounter = 0;
|
||||||
|
io.vcounter++;
|
||||||
|
if(io.vcounter == 152) {
|
||||||
|
ram[0x0010].bit(6) = 1;
|
||||||
|
if(ram[0x0000].bit(7)) cpu.setInterruptVblank(1);
|
||||||
|
scheduler.exit(Scheduler::Event::Frame);
|
||||||
|
}
|
||||||
|
if(io.vcounter == 198) {
|
||||||
|
if(ram[0x0000].bit(6)) cpu.setInterruptHblank(1);
|
||||||
|
}
|
||||||
|
if(io.vcounter == 199) {
|
||||||
|
ram[0x0010].bit(6) = 0;
|
||||||
|
cpu.setInterruptVblank(0);
|
||||||
|
io.vcounter = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VPU::step(uint clocks) -> void {
|
auto VPU::step(uint clocks) -> void {
|
||||||
|
@ -20,12 +46,15 @@ auto VPU::step(uint clocks) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VPU::refresh() -> void {
|
auto VPU::refresh() -> void {
|
||||||
|
for(uint address : range(0x4000)) buffer[address] = ram[address];
|
||||||
|
for(uint address : range(0x1f00)) buffer[address + 0x4000] = cpu.ram[address + 0x3000 - 0x1f00];
|
||||||
Emulator::video.refresh(buffer, 160 * sizeof(uint32), 160, 152);
|
Emulator::video.refresh(buffer, 160 * sizeof(uint32), 160, 152);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VPU::power() -> void {
|
auto VPU::power() -> void {
|
||||||
create(VPU::Enter, system.frequency());
|
create(VPU::Enter, system.frequency());
|
||||||
ram.allocate(0x4000);
|
ram.allocate(0x4000);
|
||||||
|
io = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,11 @@ struct VPU : Thread {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32 buffer[160 * 152];
|
uint32 buffer[160 * 152];
|
||||||
|
|
||||||
|
struct IO {
|
||||||
|
uint8 vcounter;
|
||||||
|
uint10 hcounter;
|
||||||
|
} io;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern VPU vpu;
|
extern VPU vpu;
|
||||||
|
|
|
@ -16,7 +16,6 @@ auto Interface::display() -> Display {
|
||||||
display.internalWidth = 1120;
|
display.internalWidth = 1120;
|
||||||
display.internalHeight = 240;
|
display.internalHeight = 240;
|
||||||
display.aspectCorrection = 8.0 / 7.0;
|
display.aspectCorrection = 8.0 / 7.0;
|
||||||
display.refreshRate = (system.colorburst() * 6.0) / (262.0 * 1365.0);
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,10 +98,10 @@ auto TLCS900H::disassemble() -> string {
|
||||||
#define opSize opSizes[fetch.bits(4,5)] //extract the size from the opcode fetch
|
#define opSize opSizes[fetch.bits(4,5)] //extract the size from the opcode fetch
|
||||||
switch(auto fetch = read8()) {
|
switch(auto fetch = read8()) {
|
||||||
case 0x00: name = "nop"; break;
|
case 0x00: name = "nop"; break;
|
||||||
case 0x01: break;
|
case 0x01: break; //"normal" (not present on 900/H)
|
||||||
case 0x02: name = "push"; lhs.text("sr"); break;
|
case 0x02: name = "push"; lhs.text("sr"); break;
|
||||||
case 0x03: name = "pop"; lhs.text("sr"); break;
|
case 0x03: name = "pop"; lhs.text("sr"); break;
|
||||||
case 0x04: break;
|
case 0x04: break; //"max" or "min" (not present on 900/H)
|
||||||
case 0x05: name = "halt"; break;
|
case 0x05: name = "halt"; break;
|
||||||
case 0x06: name = "ei"; lhs.immediate(3, (uint3)read8()); if(lhs.immediate() == 7) name = "di", lhs.null(); break;
|
case 0x06: name = "ei"; lhs.immediate(3, (uint3)read8()); if(lhs.immediate() == 7) name = "di", lhs.null(); break;
|
||||||
case 0x07: name = "reti"; break;
|
case 0x07: name = "reti"; break;
|
||||||
|
|
|
@ -17,7 +17,7 @@ template<typename T> auto TLCS900H::toRegister8(uint8 code) const -> Register<T>
|
||||||
template<typename T> auto TLCS900H::toControlRegister(uint8 code) const -> ControlRegister<T> { return {code}; }
|
template<typename T> auto TLCS900H::toControlRegister(uint8 code) const -> ControlRegister<T> { return {code}; }
|
||||||
template<typename T> auto TLCS900H::toMemory(uint32 address) const -> Memory<T> { return {address}; }
|
template<typename T> auto TLCS900H::toMemory(uint32 address) const -> Memory<T> { return {address}; }
|
||||||
template<typename T> auto TLCS900H::toImmediate(uint32 constant) const -> Immediate<T> { return {constant}; }
|
template<typename T> auto TLCS900H::toImmediate(uint32 constant) const -> Immediate<T> { return {constant}; }
|
||||||
template<typename T> auto TLCS900H::toImmediate3(natural constant) const -> Immediate<T> { return {constant.clip(3).orElse(8)}; }
|
template<typename T> auto TLCS900H::toImmediate3(natural constant) const -> Immediate<T> { return {constant.clip(3) ? constant.clip(3) : 8}; }
|
||||||
|
|
||||||
//note: much of this code is split to multiple statements due to C++ not guaranteeing
|
//note: much of this code is split to multiple statements due to C++ not guaranteeing
|
||||||
//the order of evaluations of function arguments. fetch() ordering is critical.
|
//the order of evaluations of function arguments. fetch() ordering is critical.
|
||||||
|
@ -27,16 +27,16 @@ auto TLCS900H::instruction() -> void {
|
||||||
|
|
||||||
switch(r.prefix = data) {
|
switch(r.prefix = data) {
|
||||||
case 0x00: return instructionNoOperation();
|
case 0x00: return instructionNoOperation();
|
||||||
case 0x01: return (void)Undefined;
|
case 0x01: return (void)Undefined; //NORMAL (not present on 900/H)
|
||||||
case 0x02: return instructionPush(SR);
|
case 0x02: return instructionPush(SR);
|
||||||
case 0x03: return instructionPop(SR);
|
case 0x03: return instructionPop(SR);
|
||||||
case 0x04: return (void)Undefined;
|
case 0x04: return (void)Undefined; //MAX or MIN (not present on 900/H)
|
||||||
case 0x05: return instructionHalt();
|
case 0x05: return instructionHalt();
|
||||||
case 0x06: return instructionSetInterruptFlipFlop((uint3)fetch());
|
case 0x06: return instructionSetInterruptFlipFlop((uint3)fetch());
|
||||||
case 0x07: return instructionReturnInterrupt();
|
case 0x07: return instructionReturnInterrupt();
|
||||||
case 0x08: {
|
case 0x08: {
|
||||||
auto memory = fetchMemory<uint8, uint8>();
|
auto memory = fetchMemory<uint8, uint8>();
|
||||||
return instructionLoad(memory, fetchImmediate<uint16>()); }
|
return instructionLoad(memory, fetchImmediate<uint8>()); }
|
||||||
case 0x09: return instructionPush(fetchImmediate<uint8>());
|
case 0x09: return instructionPush(fetchImmediate<uint8>());
|
||||||
case 0x0a: {
|
case 0x0a: {
|
||||||
auto memory = fetchMemory<uint16, uint8>();
|
auto memory = fetchMemory<uint16, uint8>();
|
||||||
|
|
|
@ -351,7 +351,8 @@ auto TLCS900H::instructionRotateLeftDigit(LHS lhs, RHS rhs) -> void {
|
||||||
template<typename Target, typename Amount>
|
template<typename Target, typename Amount>
|
||||||
auto TLCS900H::instructionRotateLeft(Target target, Amount amount) -> void {
|
auto TLCS900H::instructionRotateLeft(Target target, Amount amount) -> void {
|
||||||
auto result = load(target);
|
auto result = load(target);
|
||||||
for(uint n : range(load(amount).clip(4).orElse(16))) {
|
auto length = load(amount).clip(4);
|
||||||
|
for(uint n : range(length ? length : 16)) {
|
||||||
uint cf = result.bit(-1);
|
uint cf = result.bit(-1);
|
||||||
result = result << 1 | CF;
|
result = result << 1 | CF;
|
||||||
CF = cf;
|
CF = cf;
|
||||||
|
@ -362,7 +363,8 @@ auto TLCS900H::instructionRotateLeft(Target target, Amount amount) -> void {
|
||||||
template<typename Target, typename Amount>
|
template<typename Target, typename Amount>
|
||||||
auto TLCS900H::instructionRotateLeftWithoutCarry(Target target, Amount amount) -> void {
|
auto TLCS900H::instructionRotateLeftWithoutCarry(Target target, Amount amount) -> void {
|
||||||
auto result = load(target);
|
auto result = load(target);
|
||||||
for(uint n : range(load(amount).clip(4).orElse(16))) {
|
auto length = load(amount).clip(4);
|
||||||
|
for(uint n : range(length ? length : 16)) {
|
||||||
CF = result.bit(-1);
|
CF = result.bit(-1);
|
||||||
result = result << 1 | CF;
|
result = result << 1 | CF;
|
||||||
}
|
}
|
||||||
|
@ -389,7 +391,8 @@ auto TLCS900H::instructionRotateRightDigit(LHS lhs, RHS rhs) -> void {
|
||||||
template<typename Target, typename Amount>
|
template<typename Target, typename Amount>
|
||||||
auto TLCS900H::instructionRotateRight(Target target, Amount amount) -> void {
|
auto TLCS900H::instructionRotateRight(Target target, Amount amount) -> void {
|
||||||
auto result = load(target);
|
auto result = load(target);
|
||||||
for(uint n : range(load(amount).clip(4).orElse(16))) {
|
auto length = load(amount).clip(4);
|
||||||
|
for(uint n : range(length ? length : 16)) {
|
||||||
uint cf = result.bit(0);
|
uint cf = result.bit(0);
|
||||||
result = CF << Target::bits - 1 | result >> 1;
|
result = CF << Target::bits - 1 | result >> 1;
|
||||||
CF = cf;
|
CF = cf;
|
||||||
|
@ -400,7 +403,8 @@ auto TLCS900H::instructionRotateRight(Target target, Amount amount) -> void {
|
||||||
template<typename Target, typename Amount>
|
template<typename Target, typename Amount>
|
||||||
auto TLCS900H::instructionRotateRightWithoutCarry(Target target, Amount amount) -> void {
|
auto TLCS900H::instructionRotateRightWithoutCarry(Target target, Amount amount) -> void {
|
||||||
auto result = load(target);
|
auto result = load(target);
|
||||||
for(uint n : range(load(amount).clip(4).orElse(16))) {
|
auto length = load(amount).clip(4);
|
||||||
|
for(uint n : range(length ? length : 16)) {
|
||||||
CF = result.bit(0);
|
CF = result.bit(0);
|
||||||
result = CF << Target::bits - 1 | result >> 1;
|
result = CF << Target::bits - 1 | result >> 1;
|
||||||
}
|
}
|
||||||
|
@ -434,7 +438,8 @@ auto TLCS900H::instructionSetRegisterFilePointer(uint2 value) -> void {
|
||||||
template<typename Target, typename Amount>
|
template<typename Target, typename Amount>
|
||||||
auto TLCS900H::instructionShiftLeftArithmetic(Target target, Amount amount) -> void {
|
auto TLCS900H::instructionShiftLeftArithmetic(Target target, Amount amount) -> void {
|
||||||
auto result = load(target);
|
auto result = load(target);
|
||||||
for(uint n : range(load(amount).clip(4).orElse(16))) {
|
auto length = load(amount).clip(4);
|
||||||
|
for(uint n : range(length ? length : 16)) {
|
||||||
CF = result.bit(-1);
|
CF = result.bit(-1);
|
||||||
result = result << 1;
|
result = result << 1;
|
||||||
}
|
}
|
||||||
|
@ -444,7 +449,8 @@ auto TLCS900H::instructionShiftLeftArithmetic(Target target, Amount amount) -> v
|
||||||
template<typename Target, typename Amount>
|
template<typename Target, typename Amount>
|
||||||
auto TLCS900H::instructionShiftLeftLogical(Target target, Amount amount) -> void {
|
auto TLCS900H::instructionShiftLeftLogical(Target target, Amount amount) -> void {
|
||||||
auto result = load(target);
|
auto result = load(target);
|
||||||
for(uint n : range(load(amount).clip(4).orElse(16))) {
|
auto length = load(amount).clip(4);
|
||||||
|
for(uint n : range(length ? length : 16)) {
|
||||||
CF = result.bit(-1);
|
CF = result.bit(-1);
|
||||||
result = result << 1;
|
result = result << 1;
|
||||||
}
|
}
|
||||||
|
@ -454,7 +460,8 @@ auto TLCS900H::instructionShiftLeftLogical(Target target, Amount amount) -> void
|
||||||
template<typename Target, typename Amount>
|
template<typename Target, typename Amount>
|
||||||
auto TLCS900H::instructionShiftRightArithmetic(Target target, Amount amount) -> void {
|
auto TLCS900H::instructionShiftRightArithmetic(Target target, Amount amount) -> void {
|
||||||
auto result = load(target);
|
auto result = load(target);
|
||||||
for(uint n : range(load(amount).clip(4).orElse(16))) {
|
auto length = load(amount).clip(4);
|
||||||
|
for(uint n : range(length ? length : 16)) {
|
||||||
CF = result.bit(0);
|
CF = result.bit(0);
|
||||||
result = result >> 1;
|
result = result >> 1;
|
||||||
result.bit(-1) = result.bit(-2);
|
result.bit(-1) = result.bit(-2);
|
||||||
|
@ -465,7 +472,8 @@ auto TLCS900H::instructionShiftRightArithmetic(Target target, Amount amount) ->
|
||||||
template<typename Target, typename Amount>
|
template<typename Target, typename Amount>
|
||||||
auto TLCS900H::instructionShiftRightLogical(Target target, Amount amount) -> void {
|
auto TLCS900H::instructionShiftRightLogical(Target target, Amount amount) -> void {
|
||||||
auto result = load(target);
|
auto result = load(target);
|
||||||
for(uint n : range(load(amount).clip(4).orElse(16))) {
|
auto length = load(amount).clip(4);
|
||||||
|
for(uint n : range(length ? length : 16)) {
|
||||||
CF = result.bit(0);
|
CF = result.bit(0);
|
||||||
result = result >> 1;
|
result = result >> 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,8 @@ template<> auto TLCS900H::map(Register<uint16> register) const -> maybe<uint16&>
|
||||||
r(0x38, xde[3].w.w0) r(0x3a, xde[3].w.w1) r(0x3c, xhl[3].w.w0) r(0x3e, xhl[3].w.w1)
|
r(0x38, xde[3].w.w0) r(0x3a, xde[3].w.w1) r(0x3c, xhl[3].w.w0) r(0x3e, xhl[3].w.w1)
|
||||||
r(0xd0, xwa[p].w.w0) r(0xd2, xwa[p].w.w1) r(0xd4, xbc[p].w.w0) r(0xd6, xbc[p].w.w1)
|
r(0xd0, xwa[p].w.w0) r(0xd2, xwa[p].w.w1) r(0xd4, xbc[p].w.w0) r(0xd6, xbc[p].w.w1)
|
||||||
r(0xd8, xde[p].w.w0) r(0xda, xde[p].w.w1) r(0xdc, xhl[p].w.w0) r(0xde, xhl[p].w.w1)
|
r(0xd8, xde[p].w.w0) r(0xda, xde[p].w.w1) r(0xdc, xhl[p].w.w0) r(0xde, xhl[p].w.w1)
|
||||||
r(0xe0, xwa[p].w.w0) r(0xe2, xwa[p].w.w1) r(0xe4, xbc[p].w.w0) r(0xe6, xbc[p].w.w1)
|
r(0xe0, xwa[a].w.w0) r(0xe2, xwa[a].w.w1) r(0xe4, xbc[a].w.w0) r(0xe6, xbc[a].w.w1)
|
||||||
r(0xe8, xde[p].w.w0) r(0xea, xde[p].w.w1) r(0xec, xhl[p].w.w0) r(0xee, xhl[p].w.w1)
|
r(0xe8, xde[a].w.w0) r(0xea, xde[a].w.w1) r(0xec, xhl[a].w.w0) r(0xee, xhl[a].w.w1)
|
||||||
r(0xf0, xix .w.w0) r(0xf2, xix .w.w1) r(0xf4, xiy .w.w0) r(0xf6, xiy .w.w1)
|
r(0xf0, xix .w.w0) r(0xf2, xix .w.w1) r(0xf4, xiy .w.w0) r(0xf6, xiy .w.w1)
|
||||||
r(0xf8, xiz .w.w0) r(0xfa, xiz .w.w1) r(0xfc, xsp .w.w0) r(0xfe, xsp .w.w0)
|
r(0xf8, xiz .w.w0) r(0xfa, xiz .w.w1) r(0xfc, xsp .w.w0) r(0xfe, xsp .w.w0)
|
||||||
#undef r
|
#undef r
|
||||||
|
@ -106,12 +106,13 @@ auto TLCS900H::store(FlagRegister f, uint8 data) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto TLCS900H::load(StatusRegister) const -> uint16 {
|
auto TLCS900H::load(StatusRegister) const -> uint16 {
|
||||||
return load(F) | r.rfp << 8 | 1 << 11 | r.iff << 12 | 1 << 15;
|
//900/H: d10 = RFP2 (always 0); d11 = MAX (always 1); d15 = SYSM (always 1)
|
||||||
|
return load(F) | r.rfp << 8 | 0 << 10 | 1 << 11 | r.iff << 12 | 1 << 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto TLCS900H::store(StatusRegister, uint16 data) -> void {
|
auto TLCS900H::store(StatusRegister, uint16 data) -> void {
|
||||||
store(F, data);
|
store(F, data.bits(0,7));
|
||||||
r.rfp = data.bits( 8, 9);
|
r.rfp = data.bits(8,9);
|
||||||
r.iff = data.bits(12,14);
|
r.iff = data.bits(12,14);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ auto TLCS900H::interrupt(uint24 address) -> void {
|
||||||
|
|
||||||
auto TLCS900H::power() -> void {
|
auto TLCS900H::power() -> void {
|
||||||
r = {};
|
r = {};
|
||||||
|
r.xsp.l.l0 = 0x100;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,14 +191,14 @@ struct TLCS900H {
|
||||||
DataRegister dmam[4];
|
DataRegister dmam[4];
|
||||||
DataRegister intnest; //16-bit
|
DataRegister intnest; //16-bit
|
||||||
|
|
||||||
uint1 c, cp; //carry
|
uint1 c, cp; //carry
|
||||||
uint1 n, np; //negative
|
uint1 n, np; //negative
|
||||||
uint1 v, vp; //overflow or parity
|
uint1 v, vp; //overflow or parity
|
||||||
uint1 h, hp; //half carry
|
uint1 h, hp; //half carry
|
||||||
uint1 z, zp; //zero
|
uint1 z, zp; //zero
|
||||||
uint1 s, sp; //sign
|
uint1 s, sp; //sign
|
||||||
uint2 rfp; //register file pointer
|
uint2 rfp; //register file pointer
|
||||||
uint3 iff = 7; //interrupt mask flip-flop
|
uint3 iff = 7; //interrupt mask flip-flop
|
||||||
|
|
||||||
uint1 halted; //set if halt instruction executed; waits for an interrupt to resume
|
uint1 halted; //set if halt instruction executed; waits for an interrupt to resume
|
||||||
uint8 prefix; //first opcode byte; needed for [CP|LD][ID](R) instructions
|
uint8 prefix; //first opcode byte; needed for [CP|LD][ID](R) instructions
|
||||||
|
|
|
@ -23,8 +23,6 @@ auto Interface::display() -> Display {
|
||||||
display.internalWidth = 512;
|
display.internalWidth = 512;
|
||||||
display.internalHeight = 480;
|
display.internalHeight = 480;
|
||||||
display.aspectCorrection = 8.0 / 7.0;
|
display.aspectCorrection = 8.0 / 7.0;
|
||||||
if(Region::NTSC()) display.refreshRate = system.cpuFrequency() / (262.0 * 1364.0);
|
|
||||||
if(Region::PAL()) display.refreshRate = system.cpuFrequency() / (312.0 * 1364.0);
|
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ auto Interface::display() -> Display {
|
||||||
display.internalWidth = 224;
|
display.internalWidth = 224;
|
||||||
display.internalHeight = 144;
|
display.internalHeight = 144;
|
||||||
display.aspectCorrection = 1.0;
|
display.aspectCorrection = 1.0;
|
||||||
display.refreshRate = 3'072'000.0 / (159.0 * 256.0);
|
|
||||||
if(settings.rotateLeft) {
|
if(settings.rotateLeft) {
|
||||||
swap(display.width, display.height);
|
swap(display.width, display.height);
|
||||||
swap(display.internalWidth, display.internalHeight);
|
swap(display.internalWidth, display.internalHeight);
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
struct Boolean;
|
struct Boolean;
|
||||||
template<uint Precision> struct Natural;
|
template<uint Precision = 64> struct Natural;
|
||||||
template<uint Precision> struct Integer;
|
template<uint Precision = 64> struct Integer;
|
||||||
|
template<uint Precision = 64> struct Real;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <nall/primitives/bit-range.hpp>
|
#include <nall/primitives/bit-range.hpp>
|
||||||
|
|
|
@ -2,15 +2,18 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
|
//warning: so that BitRange can modify the underlying number directly, it must bind a reference.
|
||||||
|
//as a result, auto value = number.bits() will capture by-reference, rather than by-value.
|
||||||
|
|
||||||
template<int Precision> struct BitRange {
|
template<int Precision> struct BitRange {
|
||||||
static_assert(Precision >= 1 && Precision <= 64);
|
static_assert(Precision >= 1 && Precision <= 64);
|
||||||
static inline constexpr auto bits() -> uint { return Precision; }
|
static inline constexpr auto bits() -> uint { return Precision; }
|
||||||
using utype =
|
using utype =
|
||||||
typename conditional<bits() <= 8, uint8_t,
|
conditional_t<bits() <= 8, uint8_t,
|
||||||
typename conditional<bits() <= 16, uint16_t,
|
conditional_t<bits() <= 16, uint16_t,
|
||||||
typename conditional<bits() <= 32, uint32_t,
|
conditional_t<bits() <= 32, uint32_t,
|
||||||
typename conditional<bits() <= 64, uint64_t,
|
conditional_t<bits() <= 64, uint64_t,
|
||||||
void>::type>::type>::type>::type;
|
void>>>>;
|
||||||
static inline constexpr auto mask() -> utype { return ~0ull >> 64 - bits(); }
|
static inline constexpr auto mask() -> utype { return ~0ull >> 64 - bits(); }
|
||||||
|
|
||||||
inline BitRange(utype& source, int lo, int hi) : source(source) {
|
inline BitRange(utype& source, int lo, int hi) : source(source) {
|
||||||
|
@ -22,13 +25,14 @@ template<int Precision> struct BitRange {
|
||||||
}
|
}
|
||||||
inline auto& operator=(BitRange& source) { return set(source.get()); }
|
inline auto& operator=(BitRange& source) { return set(source.get()); }
|
||||||
|
|
||||||
|
inline operator utype() const { return get(); }
|
||||||
|
|
||||||
inline auto operator++(int) { auto value = get(); set(value + 1); return value; }
|
inline auto operator++(int) { auto value = get(); set(value + 1); return value; }
|
||||||
inline auto operator--(int) { auto value = get(); set(value - 1); return value; }
|
inline auto operator--(int) { auto value = get(); set(value - 1); return value; }
|
||||||
|
|
||||||
inline auto& operator++() { return set(get() + 1); }
|
inline auto& operator++() { return set(get() + 1); }
|
||||||
inline auto& operator--() { return set(get() - 1); }
|
inline auto& operator--() { return set(get() - 1); }
|
||||||
|
|
||||||
inline operator utype() const { return get(); }
|
|
||||||
template<typename T> inline auto& operator =(const T& value) { return set( value); }
|
template<typename T> inline auto& operator =(const T& value) { return set( value); }
|
||||||
template<typename T> inline auto& operator *=(const T& value) { return set(get() * value); }
|
template<typename T> inline auto& operator *=(const T& value) { return set(get() * value); }
|
||||||
template<typename T> inline auto& operator /=(const T& value) { return set(get() / value); }
|
template<typename T> inline auto& operator /=(const T& value) { return set(get() / value); }
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace nall {
|
||||||
|
|
||||||
struct Boolean {
|
struct Boolean {
|
||||||
static inline constexpr auto bits() -> uint { return 1; }
|
static inline constexpr auto bits() -> uint { return 1; }
|
||||||
using type = bool;
|
using btype = bool;
|
||||||
|
|
||||||
inline Boolean() : data(false) {}
|
inline Boolean() : data(false) {}
|
||||||
template<typename T> inline Boolean(const T& value) : data(value) {}
|
template<typename T> inline Boolean(const T& value) : data(value) {}
|
||||||
|
@ -23,7 +23,7 @@ struct Boolean {
|
||||||
inline auto serialize(serializer& s) { s(data); }
|
inline auto serialize(serializer& s) { s(data); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
type data;
|
btype data;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<uint Precision = 64> struct Integer {
|
template<uint Precision> struct Integer {
|
||||||
static_assert(Precision >= 1 && Precision <= 64);
|
static_assert(Precision >= 1 && Precision <= 64);
|
||||||
static inline constexpr auto bits() -> uint { return Precision; }
|
static inline constexpr auto bits() -> uint { return Precision; }
|
||||||
using stype =
|
using stype =
|
||||||
|
@ -16,11 +16,10 @@ template<uint Precision = 64> struct Integer {
|
||||||
static inline constexpr auto sign() -> utype { return 1ull << Precision - 1; }
|
static inline constexpr auto sign() -> utype { return 1ull << Precision - 1; }
|
||||||
|
|
||||||
inline Integer() : data(0) {}
|
inline Integer() : data(0) {}
|
||||||
template<int Bits> inline Integer(Integer<Bits> value) { data = mask(value); }
|
template<uint Bits> inline Integer(Integer<Bits> value) { data = mask(value); }
|
||||||
template<typename T> inline Integer(const T& value) { data = mask(value); }
|
template<typename T> inline Integer(const T& value) { data = mask(value); }
|
||||||
|
|
||||||
explicit inline operator bool() const { return data; }
|
inline operator stype() const { return data; }
|
||||||
inline operator int64_t() const { return data; }
|
|
||||||
|
|
||||||
inline auto operator++(int) { auto value = *this; data = mask(data + 1); return value; }
|
inline auto operator++(int) { auto value = *this; data = mask(data + 1); return value; }
|
||||||
inline auto operator--(int) { auto value = *this; data = mask(data - 1); return value; }
|
inline auto operator--(int) { auto value = *this; data = mask(data - 1); return value; }
|
||||||
|
@ -28,29 +27,17 @@ template<uint Precision = 64> struct Integer {
|
||||||
inline auto& operator++() { data = mask(data + 1); return *this; }
|
inline auto& operator++() { data = mask(data + 1); return *this; }
|
||||||
inline auto& operator--() { data = mask(data - 1); return *this; }
|
inline auto& operator--() { data = mask(data - 1); return *this; }
|
||||||
|
|
||||||
inline auto operator!() const { return !data; }
|
template<typename T> inline auto& operator =(const T& value) { data = mask( value); return *this; }
|
||||||
inline auto operator~() const { return Integer<>{mask(~data)}; }
|
template<typename T> inline auto& operator *=(const T& value) { data = mask(data * value); return *this; }
|
||||||
inline auto operator+() const { return Integer<>{+data}; }
|
template<typename T> inline auto& operator /=(const T& value) { data = mask(data / value); return *this; }
|
||||||
inline auto operator-() const { return Integer<>{data == sign() ? data : -data}; }
|
template<typename T> inline auto& operator %=(const T& value) { data = mask(data % value); return *this; }
|
||||||
|
template<typename T> inline auto& operator +=(const T& value) { data = mask(data + value); return *this; }
|
||||||
#define lhs data
|
template<typename T> inline auto& operator -=(const T& value) { data = mask(data - value); return *this; }
|
||||||
#define rhs value
|
template<typename T> inline auto& operator<<=(const T& value) { data = mask(data << value); return *this; }
|
||||||
template<typename T> inline auto& operator =(const T& value) { lhs = mask( rhs); return *this; }
|
template<typename T> inline auto& operator>>=(const T& value) { data = mask(data >> value); return *this; }
|
||||||
template<typename T> inline auto& operator *=(const T& value) { lhs = mask(lhs * rhs); return *this; }
|
template<typename T> inline auto& operator &=(const T& value) { data = mask(data & value); return *this; }
|
||||||
template<typename T> inline auto& operator /=(const T& value) { lhs = mask(lhs / rhs); return *this; }
|
template<typename T> inline auto& operator ^=(const T& value) { data = mask(data ^ value); return *this; }
|
||||||
template<typename T> inline auto& operator %=(const T& value) { lhs = mask(lhs % rhs); return *this; }
|
template<typename T> inline auto& operator |=(const T& value) { data = mask(data | value); return *this; }
|
||||||
template<typename T> inline auto& operator +=(const T& value) { lhs = mask(lhs + rhs); return *this; }
|
|
||||||
template<typename T> inline auto& operator -=(const T& value) { lhs = mask(lhs - rhs); return *this; }
|
|
||||||
template<typename T> inline auto& operator<<=(const T& value) { lhs = mask(lhs << rhs); return *this; }
|
|
||||||
template<typename T> inline auto& operator>>=(const T& value) { lhs = mask(lhs >> rhs); return *this; }
|
|
||||||
template<typename T> inline auto& operator &=(const T& value) { lhs = mask(lhs & rhs); return *this; }
|
|
||||||
template<typename T> inline auto& operator ^=(const T& value) { lhs = mask(lhs ^ rhs); return *this; }
|
|
||||||
template<typename T> inline auto& operator |=(const T& value) { lhs = mask(lhs | rhs); return *this; }
|
|
||||||
#undef lhs
|
|
||||||
#undef rhs
|
|
||||||
|
|
||||||
//warning: this does not and cannot short-circuit; value is always evaluated
|
|
||||||
template<typename T> inline auto orElse(const T& value) { return Integer<>{data ? data : value}; }
|
|
||||||
|
|
||||||
inline auto bits(int lo, int hi) -> BitRange<Precision> { return {(utype&)data, lo, hi}; }
|
inline auto bits(int lo, int hi) -> BitRange<Precision> { return {(utype&)data, lo, hi}; }
|
||||||
inline auto bit(int index) -> BitRange<Precision> { return {(utype&)data, index, index}; }
|
inline auto bit(int index) -> BitRange<Precision> { return {(utype&)data, index, index}; }
|
||||||
|
@ -63,16 +50,16 @@ template<uint Precision = 64> struct Integer {
|
||||||
inline auto slice(int index) const { return Natural<>{bit(index)}; }
|
inline auto slice(int index) const { return Natural<>{bit(index)}; }
|
||||||
inline auto slice(int lo, int hi) const { return Natural<>{bit(lo, hi)}; }
|
inline auto slice(int lo, int hi) const { return Natural<>{bit(lo, hi)}; }
|
||||||
|
|
||||||
inline auto clamp(uint bits) {
|
inline auto clamp(uint bits) -> stype {
|
||||||
const int64_t b = 1ull << (bits - 1);
|
const int64_t b = 1ull << (bits - 1);
|
||||||
const int64_t m = b - 1;
|
const int64_t m = b - 1;
|
||||||
return Integer<>{data > m ? m : data < -b ? -b : data};
|
return data > m ? m : data < -b ? -b : data;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto clip(uint bits) {
|
inline auto clip(uint bits) -> stype {
|
||||||
const uint64_t b = 1ull << (bits - 1);
|
const uint64_t b = 1ull << (bits - 1);
|
||||||
const uint64_t m = b * 2 - 1;
|
const uint64_t m = b * 2 - 1;
|
||||||
return Integer<>{(data & m ^ b) - b};
|
return (data & m ^ b) - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto serialize(serializer& s) { s(data); }
|
inline auto serialize(serializer& s) { s(data); }
|
||||||
|
@ -86,19 +73,4 @@ private:
|
||||||
stype data;
|
stype data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define lhs (int64_t)l
|
|
||||||
#define rhs r
|
|
||||||
template<int LHS, int RHS> inline auto operator *(Integer<LHS> l, Integer<RHS> r) { return Integer{lhs * rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator /(Integer<LHS> l, Integer<RHS> r) { return Integer{lhs / rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator %(Integer<LHS> l, Integer<RHS> r) { return Integer{lhs % rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator +(Integer<LHS> l, Integer<RHS> r) { return Integer{lhs + rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator -(Integer<LHS> l, Integer<RHS> r) { return Integer{lhs - rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator<<(Integer<LHS> l, Integer<RHS> r) { return Integer{lhs << rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator>>(Integer<LHS> l, Integer<RHS> r) { return Integer{lhs >> rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator &(Integer<LHS> l, Integer<RHS> r) { return Integer{lhs & rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator ^(Integer<LHS> l, Integer<RHS> r) { return Integer{lhs ^ rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator |(Integer<LHS> l, Integer<RHS> r) { return Integer{lhs | rhs}; }
|
|
||||||
#undef lhs
|
|
||||||
#undef rhs
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<uint Precision = 64> struct Natural {
|
template<uint Precision> struct Natural {
|
||||||
static_assert(Precision >= 1 && Precision <= 64);
|
static_assert(Precision >= 1 && Precision <= 64);
|
||||||
static inline constexpr auto bits() -> uint { return Precision; }
|
static inline constexpr auto bits() -> uint { return Precision; }
|
||||||
using utype =
|
using utype =
|
||||||
|
@ -14,11 +14,10 @@ template<uint Precision = 64> struct Natural {
|
||||||
static inline constexpr auto mask() -> utype { return ~0ull >> 64 - bits(); }
|
static inline constexpr auto mask() -> utype { return ~0ull >> 64 - bits(); }
|
||||||
|
|
||||||
inline Natural() : data(0) {}
|
inline Natural() : data(0) {}
|
||||||
template<int Bits> inline Natural(Natural<Bits> value) { data = mask(value); }
|
template<uint Bits> inline Natural(Natural<Bits> value) { data = mask(value); }
|
||||||
template<typename T> inline Natural(const T& value) { data = mask(value); }
|
template<typename T> inline Natural(const T& value) { data = mask(value); }
|
||||||
|
|
||||||
explicit inline operator bool() const { return data; }
|
inline operator utype() const { return data; }
|
||||||
inline operator uint64_t() const { return data; }
|
|
||||||
|
|
||||||
inline auto operator++(int) { auto value = *this; data = mask(data + 1); return value; }
|
inline auto operator++(int) { auto value = *this; data = mask(data + 1); return value; }
|
||||||
inline auto operator--(int) { auto value = *this; data = mask(data - 1); return value; }
|
inline auto operator--(int) { auto value = *this; data = mask(data - 1); return value; }
|
||||||
|
@ -26,29 +25,17 @@ template<uint Precision = 64> struct Natural {
|
||||||
inline auto& operator++() { data = mask(data + 1); return *this; }
|
inline auto& operator++() { data = mask(data + 1); return *this; }
|
||||||
inline auto& operator--() { data = mask(data - 1); return *this; }
|
inline auto& operator--() { data = mask(data - 1); return *this; }
|
||||||
|
|
||||||
inline auto operator!() const { return !data; }
|
template<typename T> inline auto& operator =(const T& value) { data = mask( value); return *this; }
|
||||||
inline auto operator~() const { return Natural<>{mask(~data)}; }
|
template<typename T> inline auto& operator *=(const T& value) { data = mask(data * value); return *this; }
|
||||||
inline auto operator+() const { return Natural<>{+data}; }
|
template<typename T> inline auto& operator /=(const T& value) { data = mask(data / value); return *this; }
|
||||||
inline auto operator-() const { return Natural<>{-(uint64_t)data}; }
|
template<typename T> inline auto& operator %=(const T& value) { data = mask(data % value); return *this; }
|
||||||
|
template<typename T> inline auto& operator +=(const T& value) { data = mask(data + value); return *this; }
|
||||||
#define lhs data
|
template<typename T> inline auto& operator -=(const T& value) { data = mask(data - value); return *this; }
|
||||||
#define rhs value
|
template<typename T> inline auto& operator<<=(const T& value) { data = mask(data << value); return *this; }
|
||||||
template<typename T> inline auto& operator =(const T& value) { lhs = mask( rhs); return *this; }
|
template<typename T> inline auto& operator>>=(const T& value) { data = mask(data >> value); return *this; }
|
||||||
template<typename T> inline auto& operator *=(const T& value) { lhs = mask(lhs * rhs); return *this; }
|
template<typename T> inline auto& operator &=(const T& value) { data = mask(data & value); return *this; }
|
||||||
template<typename T> inline auto& operator /=(const T& value) { lhs = mask(lhs / rhs); return *this; }
|
template<typename T> inline auto& operator ^=(const T& value) { data = mask(data ^ value); return *this; }
|
||||||
template<typename T> inline auto& operator %=(const T& value) { lhs = mask(lhs % rhs); return *this; }
|
template<typename T> inline auto& operator |=(const T& value) { data = mask(data | value); return *this; }
|
||||||
template<typename T> inline auto& operator +=(const T& value) { lhs = mask(lhs + rhs); return *this; }
|
|
||||||
template<typename T> inline auto& operator -=(const T& value) { lhs = mask(lhs - rhs); return *this; }
|
|
||||||
template<typename T> inline auto& operator<<=(const T& value) { lhs = mask(lhs << rhs); return *this; }
|
|
||||||
template<typename T> inline auto& operator>>=(const T& value) { lhs = mask(lhs >> rhs); return *this; }
|
|
||||||
template<typename T> inline auto& operator &=(const T& value) { lhs = mask(lhs & rhs); return *this; }
|
|
||||||
template<typename T> inline auto& operator ^=(const T& value) { lhs = mask(lhs ^ rhs); return *this; }
|
|
||||||
template<typename T> inline auto& operator |=(const T& value) { lhs = mask(lhs | rhs); return *this; }
|
|
||||||
#undef lhs
|
|
||||||
#undef rhs
|
|
||||||
|
|
||||||
//warning: this does not and cannot short-circuit; value is always evaluated
|
|
||||||
template<typename T> inline auto orElse(const T& value) { return Natural<>{data ? data : value}; }
|
|
||||||
|
|
||||||
inline auto bits(int lo, int hi) -> BitRange<Precision> { return {(utype&)data, lo, hi}; }
|
inline auto bits(int lo, int hi) -> BitRange<Precision> { return {(utype&)data, lo, hi}; }
|
||||||
inline auto bit(int index) -> BitRange<Precision> { return {(utype&)data, index, index}; }
|
inline auto bit(int index) -> BitRange<Precision> { return {(utype&)data, index, index}; }
|
||||||
|
@ -61,16 +48,16 @@ template<uint Precision = 64> struct Natural {
|
||||||
inline auto slice(int index) const { return Natural<>{bit(index)}; }
|
inline auto slice(int index) const { return Natural<>{bit(index)}; }
|
||||||
inline auto slice(int lo, int hi) const { return Natural<>{bits(lo, hi)}; }
|
inline auto slice(int lo, int hi) const { return Natural<>{bits(lo, hi)}; }
|
||||||
|
|
||||||
inline auto clamp(uint bits) {
|
inline auto clamp(uint bits) -> utype {
|
||||||
const uint64_t b = 1ull << (bits - 1);
|
const uint64_t b = 1ull << (bits - 1);
|
||||||
const uint64_t m = b * 2 - 1;
|
const uint64_t m = b * 2 - 1;
|
||||||
return Natural<>{data < m ? data : m};
|
return data < m ? data : m;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto clip(uint bits) {
|
inline auto clip(uint bits) -> utype {
|
||||||
const uint64_t b = 1ull << (bits - 1);
|
const uint64_t b = 1ull << (bits - 1);
|
||||||
const uint64_t m = b * 2 - 1;
|
const uint64_t m = b * 2 - 1;
|
||||||
return Natural<>{data & m};
|
return data & m;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto serialize(serializer& s) { s(data); }
|
inline auto serialize(serializer& s) { s(data); }
|
||||||
|
@ -84,19 +71,4 @@ private:
|
||||||
utype data;
|
utype data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define lhs (uint64_t)l
|
|
||||||
#define rhs r
|
|
||||||
template<int LHS, int RHS> inline auto operator *(Natural<LHS> l, Natural<RHS> r) { return Natural{lhs * rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator /(Natural<LHS> l, Natural<RHS> r) { return Natural{lhs / rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator %(Natural<LHS> l, Natural<RHS> r) { return Natural{lhs % rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator +(Natural<LHS> l, Natural<RHS> r) { return Natural{lhs + rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator -(Natural<LHS> l, Natural<RHS> r) { return Natural{lhs - rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator<<(Natural<LHS> l, Natural<RHS> r) { return Natural{lhs << rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator>>(Natural<LHS> l, Natural<RHS> r) { return Natural{lhs >> rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator &(Natural<LHS> l, Natural<RHS> r) { return Natural{lhs & rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator ^(Natural<LHS> l, Natural<RHS> r) { return Natural{lhs ^ rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator |(Natural<LHS> l, Natural<RHS> r) { return Natural{lhs | rhs}; }
|
|
||||||
#undef lhs
|
|
||||||
#undef rhs
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<uint Precision = 64> struct Real {
|
template<uint Precision> struct Real {
|
||||||
static_assert(Precision == 32 || Precision == 64);
|
static_assert(Precision == 32 || Precision == 64);
|
||||||
static inline constexpr auto bits() -> uint { return Precision; }
|
static inline constexpr auto bits() -> uint { return Precision; }
|
||||||
using ftype =
|
using ftype =
|
||||||
|
@ -14,8 +14,7 @@ template<uint Precision = 64> struct Real {
|
||||||
template<int Bits> inline Real(Real<Bits> value) : data((ftype)value) {}
|
template<int Bits> inline Real(Real<Bits> value) : data((ftype)value) {}
|
||||||
template<typename T> inline Real(const T& value) : data((ftype)value) {}
|
template<typename T> inline Real(const T& value) : data((ftype)value) {}
|
||||||
|
|
||||||
explicit inline operator bool() const { return data; }
|
inline operator ftype() const { return data; }
|
||||||
inline operator float64_t() const { return data; }
|
|
||||||
|
|
||||||
inline auto operator++(int) { auto value = *this; ++data; return value; }
|
inline auto operator++(int) { auto value = *this; ++data; return value; }
|
||||||
inline auto operator--(int) { auto value = *this; --data; return value; }
|
inline auto operator--(int) { auto value = *this; --data; return value; }
|
||||||
|
@ -36,14 +35,4 @@ private:
|
||||||
ftype data;
|
ftype data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define lhs (float64_t)(typename Real<LHS>::type)l
|
|
||||||
#define rhs (typename Real<RHS>::type)r
|
|
||||||
template<int LHS, int RHS> inline auto operator*(Real<LHS> l, Real<RHS> r) { return Real<>{lhs * rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator/(Real<LHS> l, Real<RHS> r) { return Real<>{lhs / rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator%(Real<LHS> l, Real<RHS> r) { return Real<>{lhs % rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator+(Real<LHS> l, Real<RHS> r) { return Real<>{lhs + rhs}; }
|
|
||||||
template<int LHS, int RHS> inline auto operator-(Real<LHS> l, Real<RHS> r) { return Real<>{lhs - rhs}; }
|
|
||||||
#undef lhs
|
|
||||||
#undef rhs
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue