Update to v101r04 release.

byuu says:

Changelog:

  - pulled the (u)intN type aliases into higan instead of leaving them
    in nall
  - added 68K LINEA, LINEF hooks for illegal instructions
  - filled the rest of the 68K lambda table with generic instance of
    ILLEGAL
  - completed the 68K disassembler effective addressing modes
      - still unsure whether I should use An to decode absolute
        addresses or not
      - pro: way easier to read where accesses are taking place
      - con: requires An to be valid; so as a disassembler it does a
        poor job
      - making it optional: too much work; ick
  - added I/O decoding for the VDP command-port registers
  - added skeleton timing to all five processor cores
  - output at 1280x480 (needed for mixed 256/320 widths; and to handle
    interlace modes)

The VDP, PSG, Z80, YM2612 are all stepping one clock at a time and
syncing; which is the pathological worst case for libco. But they also
have no logic inside of them. With all the above, I'm averaging around
250fps with just the 68K core actually functional, and the VDP doing a
dumb "draw white pixels" loop. Still way too early to tell how this
emulator is going to perform.

Also, the 320x240 mode of the Genesis means that we don't need an aspect
correction ratio. But we do need to ensure the output window is a
multiple 320x240 so that the scale values work correctly. I was
hard-coding aspect correction to stretch the window an additional \*8/7.
But that won't work anymore so ... the main higan window is now 640x480,
960x720, or 1280x960. Toggling aspect correction only changes the video
width inside the window.

It's a bit jarring ... the window is a lot wider, more black space now
for most modes. But for now, it is what it is.
This commit is contained in:
Tim Allen 2016-08-12 11:07:04 +10:00
parent 9b8c3ff8c0
commit 1df2549d18
21 changed files with 579 additions and 355 deletions

View File

@ -4,6 +4,7 @@
#include <nall/vfs.hpp>
using namespace nall;
#include "types.hpp"
#include <libco/libco.h>
#include <audio/audio.hpp>
#include <video/video.hpp>
@ -11,7 +12,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "101.03";
static const string Version = "101.04";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

129
higan/emulator/types.hpp Normal file
View File

@ -0,0 +1,129 @@
using int1 = nall::Integer< 1>;
using int2 = nall::Integer< 2>;
using int3 = nall::Integer< 3>;
using int4 = nall::Integer< 4>;
using int5 = nall::Integer< 5>;
using int6 = nall::Integer< 6>;
using int7 = nall::Integer< 7>;
using int8 = nall::Integer< 8>;
using int9 = nall::Integer< 9>;
using int10 = nall::Integer<10>;
using int11 = nall::Integer<11>;
using int12 = nall::Integer<12>;
using int13 = nall::Integer<13>;
using int14 = nall::Integer<14>;
using int15 = nall::Integer<15>;
using int16 = nall::Integer<16>;
using int17 = nall::Integer<17>;
using int18 = nall::Integer<18>;
using int19 = nall::Integer<19>;
using int20 = nall::Integer<20>;
using int21 = nall::Integer<21>;
using int22 = nall::Integer<22>;
using int23 = nall::Integer<23>;
using int24 = nall::Integer<24>;
using int25 = nall::Integer<25>;
using int26 = nall::Integer<26>;
using int27 = nall::Integer<27>;
using int28 = nall::Integer<28>;
using int29 = nall::Integer<29>;
using int30 = nall::Integer<30>;
using int31 = nall::Integer<31>;
using int32 = nall::Integer<32>;
using int33 = nall::Integer<33>;
using int34 = nall::Integer<34>;
using int35 = nall::Integer<35>;
using int36 = nall::Integer<36>;
using int37 = nall::Integer<37>;
using int38 = nall::Integer<38>;
using int39 = nall::Integer<39>;
using int40 = nall::Integer<40>;
using int41 = nall::Integer<41>;
using int42 = nall::Integer<42>;
using int43 = nall::Integer<43>;
using int44 = nall::Integer<44>;
using int45 = nall::Integer<45>;
using int46 = nall::Integer<46>;
using int47 = nall::Integer<47>;
using int48 = nall::Integer<48>;
using int49 = nall::Integer<49>;
using int50 = nall::Integer<50>;
using int51 = nall::Integer<51>;
using int52 = nall::Integer<52>;
using int53 = nall::Integer<53>;
using int54 = nall::Integer<54>;
using int55 = nall::Integer<55>;
using int56 = nall::Integer<56>;
using int57 = nall::Integer<57>;
using int58 = nall::Integer<58>;
using int59 = nall::Integer<59>;
using int60 = nall::Integer<60>;
using int61 = nall::Integer<61>;
using int62 = nall::Integer<62>;
using int63 = nall::Integer<63>;
using int64 = nall::Integer<64>;
using uint1 = nall::Natural< 1>;
using uint2 = nall::Natural< 2>;
using uint3 = nall::Natural< 3>;
using uint4 = nall::Natural< 4>;
using uint5 = nall::Natural< 5>;
using uint6 = nall::Natural< 6>;
using uint7 = nall::Natural< 7>;
using uint8 = nall::Natural< 8>;
using uint9 = nall::Natural< 9>;
using uint10 = nall::Natural<10>;
using uint11 = nall::Natural<11>;
using uint12 = nall::Natural<12>;
using uint13 = nall::Natural<13>;
using uint14 = nall::Natural<14>;
using uint15 = nall::Natural<15>;
using uint16 = nall::Natural<16>;
using uint17 = nall::Natural<17>;
using uint18 = nall::Natural<18>;
using uint19 = nall::Natural<19>;
using uint20 = nall::Natural<20>;
using uint21 = nall::Natural<21>;
using uint22 = nall::Natural<22>;
using uint23 = nall::Natural<23>;
using uint24 = nall::Natural<24>;
using uint25 = nall::Natural<25>;
using uint26 = nall::Natural<26>;
using uint27 = nall::Natural<27>;
using uint28 = nall::Natural<28>;
using uint29 = nall::Natural<29>;
using uint30 = nall::Natural<30>;
using uint31 = nall::Natural<31>;
using uint32 = nall::Natural<32>;
using uint33 = nall::Natural<33>;
using uint34 = nall::Natural<34>;
using uint35 = nall::Natural<35>;
using uint36 = nall::Natural<36>;
using uint37 = nall::Natural<37>;
using uint38 = nall::Natural<38>;
using uint39 = nall::Natural<39>;
using uint40 = nall::Natural<40>;
using uint41 = nall::Natural<41>;
using uint42 = nall::Natural<42>;
using uint43 = nall::Natural<43>;
using uint44 = nall::Natural<44>;
using uint45 = nall::Natural<45>;
using uint46 = nall::Natural<46>;
using uint47 = nall::Natural<47>;
using uint48 = nall::Natural<48>;
using uint49 = nall::Natural<49>;
using uint50 = nall::Natural<50>;
using uint51 = nall::Natural<51>;
using uint52 = nall::Natural<52>;
using uint53 = nall::Natural<53>;
using uint54 = nall::Natural<54>;
using uint55 = nall::Natural<55>;
using uint56 = nall::Natural<56>;
using uint57 = nall::Natural<57>;
using uint58 = nall::Natural<58>;
using uint59 = nall::Natural<59>;
using uint60 = nall::Natural<60>;
using uint61 = nall::Natural<61>;
using uint62 = nall::Natural<62>;
using uint63 = nall::Natural<63>;
using uint64 = nall::Natural<64>;

View File

@ -9,10 +9,12 @@ auto APU::Enter() -> void {
}
auto APU::main() -> void {
step(system.colorburst());
step(1);
}
auto APU::step(uint clocks) -> void {
Thread::step(clocks);
synchronize(cpu);
}
auto APU::power() -> void {

View File

@ -70,13 +70,19 @@ auto Cartridge::power() -> void {
auto Cartridge::reset() -> void {
}
auto Cartridge::read(bool word, uint24 addr) -> uint16 {
uint16 data = rom.data[addr & rom.mask];
if(!word) return data;
return data << 8 | rom.data[addr + 1 & rom.mask];
auto Cartridge::readByte(uint24 addr) -> uint8 {
return rom.data[addr & rom.mask];
}
auto Cartridge::write(bool word, uint24 addr, uint16 data) -> void {
auto Cartridge::readWord(uint24 addr) -> uint16 {
uint16 data = rom.data[addr + 0 & rom.mask] << 8;
return data | rom.data[addr + 1 & rom.mask] << 0;
}
auto Cartridge::writeByte(uint24 addr, uint8 data) -> void {
}
auto Cartridge::writeWord(uint24 addr, uint16 data) -> void {
}
}

View File

@ -10,8 +10,10 @@ struct Cartridge {
auto power() -> void;
auto reset() -> void;
auto read(bool word, uint24 addr) -> uint16;
auto write(bool word, uint24 addr, uint16 data) -> void;
auto readByte(uint24 addr) -> uint8;
auto readWord(uint24 addr) -> uint16;
auto writeByte(uint24 addr, uint8 data) -> void;
auto writeWord(uint24 addr, uint16 data) -> void;
struct Information {
uint pathID = 0;

View File

@ -10,8 +10,8 @@ auto CPU::Enter() -> void {
}
auto CPU::boot() -> void {
r.a[7] = read(1, 0) << 16 | read(1, 2) << 0;
r.pc = read(1, 4) << 16 | read(1, 6) << 0;
r.a[7] = readWord(0) << 16 | readWord(2) << 0;
r.pc = readWord(4) << 16 | readWord(6) << 0;
}
auto CPU::main() -> void {
@ -20,11 +20,10 @@ auto CPU::main() -> void {
auto CPU::step(uint clocks) -> void {
Thread::step(clocks);
cycles += clocks;
if(cycles >= frequency() / 60) {
cycles = 0;
scheduler.exit(Scheduler::Event::Frame);
}
synchronize(apu);
synchronize(vdp);
synchronize(psg);
synchronize(ym2612);
}
auto CPU::power() -> void {
@ -39,25 +38,34 @@ auto CPU::reset() -> void {
cycles = 0;
}
auto CPU::read(bool word, uint24 addr) -> uint16 {
if(addr < 0x400000) return cartridge.read(word, addr);
if(addr < 0xe00000) return 0x0000;
uint16 data = ram[addr & 65535];
if(word) data = data << 8 | ram[addr + 1 & 65535];
return data;
auto CPU::readByte(uint24 addr) -> uint8 {
if(addr < 0x400000) return cartridge.readByte(addr);
if(addr < 0xc00000) return 0x00;
if(addr < 0xe00000) return vdp.readByte(addr);
return ram[addr & 0xffff];
}
auto CPU::write(bool word, uint24 addr, uint16 data) -> void {
if(addr < 0x400000) return cartridge.write(word, addr, data);
if(addr < 0xe00000) return;
auto CPU::readWord(uint24 addr) -> uint16 {
if(addr < 0x400000) return cartridge.readWord(addr);
if(addr < 0xc00000) return 0x0000;
if(addr < 0xe00000) return vdp.readWord(addr);
uint16 data = ram[addr + 0 & 65535] << 8;
return data | ram[addr + 1 & 65535] << 0;
}
if(!word) {
ram[addr & 65535] = data;
} else {
ram[addr + 0 & 65535] = data >> 8;
ram[addr + 1 & 65535] = data >> 0;
}
auto CPU::writeByte(uint24 addr, uint8 data) -> void {
if(addr < 0x400000) return cartridge.writeByte(addr, data);
if(addr < 0xc00000) return;
if(addr < 0xe00000) return vdp.writeByte(addr, data);
ram[addr & 0xffff] = data;
}
auto CPU::writeWord(uint24 addr, uint16 data) -> void {
if(addr < 0x400000) return cartridge.writeWord(addr, data);
if(addr < 0xc00000) return;
if(addr < 0xe00000) return vdp.writeWord(addr, data);
ram[addr + 0 & 0xffff] = data >> 8;
ram[addr + 1 & 0xffff] = data >> 0;
}
}

View File

@ -9,8 +9,10 @@ struct CPU : Processor::M68K, Thread {
auto power() -> void;
auto reset() -> void;
auto read(bool word, uint24 addr) -> uint16 override;
auto write(bool word, uint24 addr, uint16 data) -> void override;
auto readByte(uint24 addr) -> uint8 override;
auto readWord(uint24 addr) -> uint16 override;
auto writeByte(uint24 addr, uint8 data) -> void override;
auto writeWord(uint24 addr, uint16 data) -> void override;
private:
uint8 ram[64 * 1024];

View File

@ -10,10 +10,10 @@ Interface::Interface() {
information.manufacturer = "Sega";
information.name = "Mega Drive";
information.width = 320; //1280
information.height = 240; // 480
information.width = 320;
information.height = 240;
information.overscan = true;
information.aspectRatio = 4.0 / 3.0;
information.aspectRatio = 1.0;
information.resettable = true;
information.capability.states = false;

View File

@ -9,10 +9,12 @@ auto PSG::Enter() -> void {
}
auto PSG::main() -> void {
step(system.colorburst());
step(1);
}
auto PSG::step(uint clocks) -> void {
Thread::step(clocks);
synchronize(cpu);
}
auto PSG::power() -> void {

View File

@ -6,10 +6,7 @@ System system;
Scheduler scheduler;
auto System::run() -> void {
if(scheduler.enter() == Scheduler::Event::Frame) {
static uint32 output[320 * 240] = {0};
Emulator::video.refresh(output, 320 * sizeof(uint32), 320, 240);
}
if(scheduler.enter() == Scheduler::Event::Frame) vdp.refresh();
}
auto System::load() -> bool {

211
higan/md/vdp/io.cpp Normal file
View File

@ -0,0 +1,211 @@
auto VDP::readByte(uint24 addr) -> uint8 {
return 0x00;
}
auto VDP::readWord(uint24 addr) -> uint16 {
switch(addr & 0xc0001f) {
case 0xc00004: case 0xc00006: {
return readControlPort();
}
}
return 0x0000;
}
auto VDP::writeByte(uint24 addr, uint8 data) -> void {
//print("[VDP] ", hex(addr, 6L), "=", hex(data, 2L), "\n");
}
auto VDP::writeWord(uint24 addr, uint16 data) -> void {
//print("[VDP] ", hex(addr, 6L), "=", hex(data, 4L), "\n");
switch(addr & 0xc0001f) {
//control port
case 0xc00004: case 0xc00006: {
if(!data.bit(15)) return;
return writeControlPort(data.bits(8,14), data.bits(0,7));
}
}
}
//
auto VDP::readControlPort() -> uint16 {
uint16 result = 0b0011'0100'0000'0000;
return result;
}
auto VDP::writeControlPort(uint7 addr, uint8 data) -> void {
//print("[VDPC] ", hex(addr, 2L), "=", hex(data, 2L), "\n");
switch(addr) {
//mode register 1
case 0x00: {
io.displayOverlayEnable = data.bit(0);
io.counterLatch = data.bit(1);
io.horizontalInterruptEnable = data.bit(4);
io.leftColumnBlank = data.bit(5);
return;
}
//mode register 2
case 0x01: {
io.videoMode = data.bit(2);
io.overscan = data.bit(3);
io.dmaEnable = data.bit(4);
io.verticalBlankInterruptEnable = data.bit(5);
io.displayEnable = data.bit(6);
io.externalVRAM = data.bit(7);
return;
}
//plane A name table location
case 0x02: {
io.nametablePlaneA = data.bits(3,6);
return;
}
//window name table location
case 0x03: {
io.nametableWindow = data.bits(1,6);
return;
}
//plane B name table location
case 0x04: {
io.nametablePlaneB = data.bits(0,3);
return;
}
//sprite attribute table location
case 0x05: {
io.attrtableSprite = data.bits(0,7);
return;
}
//sprite pattern base address
case 0x06: {
io.nametableBaseSprite = data.bit(5);
return;
}
//background color
case 0x07: {
io.backgroundIndex = data.bits(0,3);
io.backgroundPalette = data.bits(4,5);
return;
}
//unused
case 0x08: {
return;
}
//unused
case 0x09: {
return;
}
//horizontal interrupt counter
case 0x0a: {
io.horizontalInterruptCounter = data.bits(0,7);
return;
}
//mode register 3
case 0x0b: {
io.horizontalScrollMode = data.bits(0,1);
io.verticalScrollMode = data.bit(2);
io.externalInterruptEnable = data.bit(3);
return;
}
//mode register 4
case 0x0c: {
io.tileWidth = data.bit(0) | data.bit(7) << 1;
io.interlaceMode = data.bits(1,2);
io.shadowHighlightEnable = data.bit(3);
io.externalColorEnable = data.bit(4);
io.horizontalSync = data.bit(5);
io.verticalSync = data.bit(6);
return;
}
//horizontal scroll data location
case 0x0d: {
io.horizontalScrollTable = data.bits(1,6);
return;
}
//nametable pattern base address
case 0x0e: {
io.nametableBasePatternA = data.bit(0);
io.nametableBasePatternB = data.bit(1);
return;
}
//VRAM auto-increment value
case 0x0f: {
io.vramAutoIncrement = data.bits(0,7);
return;
}
//plane size
case 0x10: {
io.horizontalPlaneSize = data.bits(0,1);
io.verticalPlaneSize = data.bits(4,5);
return;
}
//window plane horizontal position
case 0x11: {
io.horizontalWindowPlanePosition = data.bits(0,4);
io.horizontalWindowPlaneRight = data.bit(7);
return;
}
//window plane vertical position
case 0x12: {
io.verticalWindowPlanePosition = data.bits(0,4);
io.verticalWindowPlaneDown = data.bit(7);
return;
}
//DMA length
case 0x13: {
io.dmaLength.bits(0,7) = data.bits(0,7);
return;
}
//DMA length
case 0x14: {
io.dmaLength.bits(8,15) = data.bits(0,7);
return;
}
//DMA source
case 0x15: {
io.dmaSource.bits(0,7) = data.bits(0,7);
return;
}
//DMA source
case 0x16: {
io.dmaSource.bits(8,15) = data.bits(0,7);
return;
}
//DMA source
case 0x17: {
io.dmaSource.bits(16,21) = data.bits(0,5);
io.dmaMode = data.bits(6,7);
return;
}
}
}

View File

@ -6,16 +6,37 @@
namespace MegaDrive {
VDP vdp;
#include "io.cpp"
auto VDP::Enter() -> void {
while(true) scheduler.synchronize(), vdp.main();
}
auto VDP::main() -> void {
step(system.colorburst() * 15.0 / 10.0);
for(uint y : range(262)) {
auto outputLo = buffer + (y * 2 + 0) * 1280;
auto outputHi = buffer + (y * 2 + 1) * 1280;
for(uint x : range(342)) {
if(y < 240 && x < 320) {
for(uint n : range(4)) {
*outputLo++ = 511;
*outputHi++ = 511;
}
}
step(1);
}
if(y == 240) scheduler.exit(Scheduler::Event::Frame);
}
}
auto VDP::step(uint clocks) -> void {
Thread::step(clocks);
synchronize(cpu);
}
auto VDP::refresh() -> void {
Emulator::video.refresh(buffer, 1280 * sizeof(uint32), 1280, 480);
}
auto VDP::power() -> void {
@ -23,6 +44,8 @@ auto VDP::power() -> void {
auto VDP::reset() -> void {
create(VDP::Enter, system.colorburst() * 15.0 / 10.0);
memory::fill(&io, sizeof(IO));
}
}

View File

@ -4,9 +4,101 @@ struct VDP : Thread {
static auto Enter() -> void;
auto main() -> void;
auto step(uint clocks) -> void;
auto refresh() -> void;
auto power() -> void;
auto reset() -> void;
auto readByte(uint24 addr) -> uint8;
auto readWord(uint24 addr) -> uint16;
auto writeByte(uint24 addr, uint8 data) -> void;
auto writeWord(uint24 addr, uint16 data) -> void;
auto readControlPort() -> uint16;
auto writeControlPort(uint7 addr, uint8 data) -> void;
private:
struct IO {
//$00 mode register 1
uint1 displayOverlayEnable;
uint1 counterLatch;
uint1 horizontalInterruptEnable;
uint1 leftColumnBlank;
//$01 mode register 2
uint1 videoMode; //0 = Master System; 1 = Mega Drive
uint1 overscan; //0 = 224 lines; 1 = 240 lines
uint1 dmaEnable;
uint1 verticalBlankInterruptEnable;
uint1 displayEnable;
uint1 externalVRAM;
//$02 plane A name table location
uint4 nametablePlaneA;
//$03 window name table location
uint6 nametableWindow;
//$04 plane B name table location
uint4 nametablePlaneB;
//$05 sprite attribute table location
uint8 attrtableSprite;
//$06 sprite pattern base address
uint1 nametableBaseSprite;
//$07 background color
uint4 backgroundIndex;
uint2 backgroundPalette;
//$0a horizontal interrupt counter
uint8 horizontalInterruptCounter;
//$0b mode register 3
uint2 horizontalScrollMode;
uint1 verticalScrollMode;
uint1 externalInterruptEnable;
//$0c mode register 4
uint2 tileWidth;
uint2 interlaceMode;
uint1 shadowHighlightEnable;
uint1 externalColorEnable;
uint1 horizontalSync;
uint1 verticalSync;
//$0d horizontal scroll data location
uint7 horizontalScrollTable;
//$0e nametable pattern base address
uint1 nametableBasePatternA;
uint1 nametableBasePatternB;
//$0f VRAM auto-increment value
uint8 vramAutoIncrement;
//$10 plane size
uint2 horizontalPlaneSize;
uint2 verticalPlaneSize;
//$11 window plane horizontal position
uint5 horizontalWindowPlanePosition;
uint1 horizontalWindowPlaneRight;
//$12 window plane vertical position
uint5 verticalWindowPlanePosition;
uint1 verticalWindowPlaneDown;
//$13-$14 DMA length
uint16 dmaLength;
//$15-$17 DMA source
uint22 dmaSource;
uint2 dmaMode;
} io;
uint32 buffer[1280 * 480];
};
extern VDP vdp;

View File

@ -9,10 +9,12 @@ auto YM2612::Enter() -> void {
}
auto YM2612::main() -> void {
step(system.colorburst() * 15.0 / 7.0);
step(1);
}
auto YM2612::step(uint clocks) -> void {
Thread::step(clocks);
synchronize(cpu);
}
auto YM2612::power() -> void {

View File

@ -1,9 +1,9 @@
template<> auto M68K::_read<Byte>(uint32 addr) -> uint32 {
return read(0, addr);
return readByte(addr);
}
template<> auto M68K::_read<Word>(uint32 addr) -> uint32 {
return read(1, addr);
return readWord(addr);
}
template<> auto M68K::_read<Long>(uint32 addr) -> uint32 {
@ -17,6 +17,19 @@ template<uint Size> auto M68K::_readPC() -> uint32 {
return clip<Size>(data);
}
auto M68K::_readDisplacement(uint32 base) -> uint32 {
return base + (int16)_readPC<Word>();
}
auto M68K::_readIndex(uint32 base) -> uint32 {
auto extension = readPC<Word>();
auto index = extension & 0x8000
? read(AddressRegister{extension >> 12})
: read(DataRegister{extension >> 12});
if(extension & 0x800) index = (int16)index;
return base + index + (int8)extension;
}
auto M68K::_dataRegister(DataRegister dr) -> string {
return {"d", dr.number};
}
@ -40,11 +53,14 @@ template<uint Size> auto M68K::_effectiveAddress(EffectiveAddress& ea) -> string
if(ea.mode == 2) return {"(", _addressRegister(AddressRegister{ea.reg}), ")"};
if(ea.mode == 3) return {"(", _addressRegister(AddressRegister{ea.reg}), ")+"};
if(ea.mode == 4) return {"-(", _addressRegister(AddressRegister{ea.reg}), ")"};
if(ea.mode == 5) return {"($", hex(read(AddressRegister{ea.reg}) + (int16)_readPC(), 6L), ")"};
if(ea.mode == 5) return {"($", hex(_readDisplacement(read(AddressRegister{ea.reg})), 6L), ")"};
if(ea.mode == 6) return {"($", hex(_readIndex(read(AddressRegister{ea.reg})), 6L), ")"};
if(ea.mode == 7) return {"($", hex((int16)_readPC<Word>(), 6L), ")"};
if(ea.mode == 8) return {"($", hex(_readPC<Long>(), 6L), ")"};
if(ea.mode == 9) return {"($", hex(_readDisplacement(_pc), 6L), ")"};
if(ea.mode == 10) return {"($", hex(_readIndex(_pc), 6L), ")"};
if(ea.mode == 11) return {"#$", hex(_readPC<Size>(), 2 << Size)};
return "???";
return "???"; //should never occur
}
auto M68K::_branch(uint8 displacement) -> string {

View File

@ -1,16 +1,7 @@
auto M68K::trap() -> void {
instructionsExecuted--;
r.pc -= 2;
print("[M68K] unimplemented instruction: ", hex(r.pc, 6L), " = ", hex(opcode, 4L), "\n");
print("[M68K] instructions executed: ", instructionsExecuted, "\n");
while(true) step(5);
}
auto M68K::instruction() -> void {
instructionsExecuted++;
//if(instructionsExecuted >= 2000010) trap();
//if(instructionsExecuted >= 2000000) {
// print(disassembleRegisters(), "\n");
// print(disassemble(r.pc), "\n");
@ -1264,16 +1255,13 @@ M68K::M68K() {
bind(opcode, UNLK, with);
}
//ILLEGAL
for(uint16 opcode : range(65536)) {
if(instructionTable[opcode]) continue;
bind(opcode, ILLEGAL);
}
#undef bind
#undef unbind
#undef pattern
uint unimplemented = 0;
for(uint16 opcode : range(65536)) {
if(instructionTable[opcode]) continue;
instructionTable[opcode] = [=] { trap(); };
disassembleTable[opcode] = [=] { return string{"???"}; };
unimplemented++;
}
print("[M68K] unimplemented opcodes: ", unimplemented, "\n");
}

View File

@ -519,6 +519,8 @@ template<> auto M68K::instructionEXT<Long>(DataRegister with) -> void {
auto M68K::instructionILLEGAL() -> void {
r.pc -= 2;
if(opcode >> 12 == 0xa) return exception(Exception::Illegal, Vector::IllegalLineA);
if(opcode >> 12 == 0xf) return exception(Exception::Illegal, Vector::IllegalLineF);
return exception(Exception::Illegal, Vector::Illegal);
}

View File

@ -40,13 +40,17 @@ struct M68K {
BoundsCheck = 6,
Overflow = 7,
Unprivileged = 8,
IllegalLineA = 10,
IllegalLineF = 11,
};};
M68K();
virtual auto step(uint clocks) -> void = 0;
virtual auto read(bool word, uint24 addr) -> uint16 = 0;
virtual auto write(bool word, uint24 addr, uint16 data) -> void = 0;
virtual auto readByte(uint24 addr) -> uint8 = 0;
virtual auto readWord(uint24 addr) -> uint16 = 0;
virtual auto writeByte(uint24 addr, uint8 data) -> void = 0;
virtual auto writeWord(uint24 addr, uint16 data) -> void = 0;
auto power() -> void;
auto reset() -> void;
@ -99,7 +103,6 @@ struct M68K {
template<uint Size> auto flush(EffectiveAddress& ea, uint32 data) -> void;
//instruction.cpp
auto trap() -> void;
auto instruction() -> void;
//instructions.cpp
@ -245,10 +248,10 @@ struct M68K {
auto disassembleRegisters() -> string;
struct Registers {
uint32 d[8];
uint32 a[8];
uint32 sp;
uint32 pc;
uint32 d[8]; //data registers
uint32 a[8]; //address registers (a7 = s ? ssp : usp)
uint32 sp; //inactive stack pointer (s ? usp : ssp)
uint32 pc; //program counter
bool c; //carry
bool v; //overflow
@ -384,6 +387,8 @@ private:
template<uint Size> auto _read(uint32 addr) -> uint32;
template<uint Size = Word> auto _readPC() -> uint32;
auto _readDisplacement(uint32 base) -> uint32;
auto _readIndex(uint32 base) -> uint32;
auto _dataRegister(DataRegister dr) -> string;
auto _addressRegister(AddressRegister ar) -> string;
template<uint Size> auto _immediate() -> string;

View File

@ -1,78 +1,78 @@
template<> auto M68K::read<Byte>(uint32 addr) -> uint32 {
step(4);
return read(0, addr);
return readByte(addr);
}
template<> auto M68K::read<Word>(uint32 addr) -> uint32 {
step(4);
return read(1, addr);
return readWord(addr);
}
template<> auto M68K::read<Long>(uint32 addr) -> uint32 {
step(4);
uint32 data = read(1, addr + 0) << 16;
uint32 data = readWord(addr + 0) << 16;
step(4);
return data | read(1, addr + 2) << 0;
return data | readWord(addr + 2) << 0;
}
//
template<> auto M68K::write<Byte>(uint32 addr, uint32 data) -> void {
step(4);
return write(0, addr, data);
return writeByte(addr, data);
}
template<> auto M68K::write<Word>(uint32 addr, uint32 data) -> void {
step(4);
return write(1, addr, data);
return writeWord(addr, data);
}
template<> auto M68K::write<Long>(uint32 addr, uint32 data) -> void {
step(4);
write(1, addr + 0, data >> 16);
writeWord(addr + 0, data >> 16);
step(4);
write(1, addr + 2, data >> 0);
writeWord(addr + 2, data >> 0);
}
template<> auto M68K::write<Byte, Reverse>(uint32 addr, uint32 data) -> void {
step(4);
return write(0, addr, data);
return writeByte(addr, data);
}
template<> auto M68K::write<Word, Reverse>(uint32 addr, uint32 data) -> void {
step(4);
return write(1, addr, data);
return writeWord(addr, data);
}
template<> auto M68K::write<Long, Reverse>(uint32 addr, uint32 data) -> void {
step(4);
write(1, addr + 2, data >> 0);
writeWord(addr + 2, data >> 0);
step(4);
write(1, addr + 0, data >> 16);
writeWord(addr + 0, data >> 16);
}
//
template<> auto M68K::readPC<Byte>() -> uint32 {
step(4);
auto data = read(1, r.pc);
auto data = readWord(r.pc);
r.pc += 2;
return (uint8)data;
}
template<> auto M68K::readPC<Word>() -> uint32 {
step(4);
auto data = read(1, r.pc);
auto data = readWord(r.pc);
r.pc += 2;
return data;
}
template<> auto M68K::readPC<Long>() -> uint32 {
step(4);
auto hi = read(1, r.pc);
auto hi = readWord(r.pc);
r.pc += 2;
step(4);
auto lo = read(1, r.pc);
auto lo = readWord(r.pc);
r.pc += 2;
return hi << 16 | lo << 0;
}

View File

@ -215,7 +215,7 @@ auto Presentation::resizeViewport() -> void {
int windowWidth = 0, windowHeight = 0;
if(!fullScreen()) {
windowWidth = 256 * scale * (settings["Video/AspectCorrection"].boolean() ? 8.0 / 7.0 : 1.0);
windowWidth = 320 * scale;
windowHeight = 240 * scale;
} else {
windowWidth = geometry().width();

View File

@ -260,271 +260,7 @@ private:
using boolean = nall::Boolean;
using natural = nall::Natural<sizeof(uint) * 8>;
using integer = nall::Integer<sizeof( int) * 8>;
using integer = nall::Integer<sizeof(int) * 8>;
using real = nall::Real<sizeof(double) * 8>;
using natural1 = nall::Natural< 1>;
using natural2 = nall::Natural< 2>;
using natural3 = nall::Natural< 3>;
using natural4 = nall::Natural< 4>;
using natural5 = nall::Natural< 5>;
using natural6 = nall::Natural< 6>;
using natural7 = nall::Natural< 7>;
using natural8 = nall::Natural< 8>;
using natural9 = nall::Natural< 9>;
using natural10 = nall::Natural<10>;
using natural11 = nall::Natural<11>;
using natural12 = nall::Natural<12>;
using natural13 = nall::Natural<13>;
using natural14 = nall::Natural<14>;
using natural15 = nall::Natural<15>;
using natural16 = nall::Natural<16>;
using natural17 = nall::Natural<17>;
using natural18 = nall::Natural<18>;
using natural19 = nall::Natural<19>;
using natural20 = nall::Natural<20>;
using natural21 = nall::Natural<21>;
using natural22 = nall::Natural<22>;
using natural23 = nall::Natural<23>;
using natural24 = nall::Natural<24>;
using natural25 = nall::Natural<25>;
using natural26 = nall::Natural<26>;
using natural27 = nall::Natural<27>;
using natural28 = nall::Natural<28>;
using natural29 = nall::Natural<29>;
using natural30 = nall::Natural<30>;
using natural31 = nall::Natural<31>;
using natural32 = nall::Natural<32>;
using natural33 = nall::Natural<33>;
using natural34 = nall::Natural<34>;
using natural35 = nall::Natural<35>;
using natural36 = nall::Natural<36>;
using natural37 = nall::Natural<37>;
using natural38 = nall::Natural<38>;
using natural39 = nall::Natural<39>;
using natural40 = nall::Natural<40>;
using natural41 = nall::Natural<41>;
using natural42 = nall::Natural<42>;
using natural43 = nall::Natural<43>;
using natural44 = nall::Natural<44>;
using natural45 = nall::Natural<45>;
using natural46 = nall::Natural<46>;
using natural47 = nall::Natural<47>;
using natural48 = nall::Natural<48>;
using natural49 = nall::Natural<49>;
using natural50 = nall::Natural<50>;
using natural51 = nall::Natural<51>;
using natural52 = nall::Natural<52>;
using natural53 = nall::Natural<53>;
using natural54 = nall::Natural<54>;
using natural55 = nall::Natural<55>;
using natural56 = nall::Natural<56>;
using natural57 = nall::Natural<57>;
using natural58 = nall::Natural<58>;
using natural59 = nall::Natural<59>;
using natural60 = nall::Natural<60>;
using natural61 = nall::Natural<61>;
using natural62 = nall::Natural<62>;
using natural63 = nall::Natural<63>;
using natural64 = nall::Natural<64>;
using integer1 = nall::Integer< 1>;
using integer2 = nall::Integer< 2>;
using integer3 = nall::Integer< 3>;
using integer4 = nall::Integer< 4>;
using integer5 = nall::Integer< 5>;
using integer6 = nall::Integer< 6>;
using integer7 = nall::Integer< 7>;
using integer8 = nall::Integer< 8>;
using integer9 = nall::Integer< 9>;
using integer10 = nall::Integer<10>;
using integer11 = nall::Integer<11>;
using integer12 = nall::Integer<12>;
using integer13 = nall::Integer<13>;
using integer14 = nall::Integer<14>;
using integer15 = nall::Integer<15>;
using integer16 = nall::Integer<16>;
using integer17 = nall::Integer<17>;
using integer18 = nall::Integer<18>;
using integer19 = nall::Integer<19>;
using integer20 = nall::Integer<20>;
using integer21 = nall::Integer<21>;
using integer22 = nall::Integer<22>;
using integer23 = nall::Integer<23>;
using integer24 = nall::Integer<24>;
using integer25 = nall::Integer<25>;
using integer26 = nall::Integer<26>;
using integer27 = nall::Integer<27>;
using integer28 = nall::Integer<28>;
using integer29 = nall::Integer<29>;
using integer30 = nall::Integer<30>;
using integer31 = nall::Integer<31>;
using integer32 = nall::Integer<32>;
using integer33 = nall::Integer<33>;
using integer34 = nall::Integer<34>;
using integer35 = nall::Integer<35>;
using integer36 = nall::Integer<36>;
using integer37 = nall::Integer<37>;
using integer38 = nall::Integer<38>;
using integer39 = nall::Integer<39>;
using integer40 = nall::Integer<40>;
using integer41 = nall::Integer<41>;
using integer42 = nall::Integer<42>;
using integer43 = nall::Integer<43>;
using integer44 = nall::Integer<44>;
using integer45 = nall::Integer<45>;
using integer46 = nall::Integer<46>;
using integer47 = nall::Integer<47>;
using integer48 = nall::Integer<48>;
using integer49 = nall::Integer<49>;
using integer50 = nall::Integer<50>;
using integer51 = nall::Integer<51>;
using integer52 = nall::Integer<52>;
using integer53 = nall::Integer<53>;
using integer54 = nall::Integer<54>;
using integer55 = nall::Integer<55>;
using integer56 = nall::Integer<56>;
using integer57 = nall::Integer<57>;
using integer58 = nall::Integer<58>;
using integer59 = nall::Integer<59>;
using integer60 = nall::Integer<60>;
using integer61 = nall::Integer<61>;
using integer62 = nall::Integer<62>;
using integer63 = nall::Integer<63>;
using integer64 = nall::Integer<64>;
using real32 = nall::Real<32>;
using real64 = nall::Real<64>;
//using real80 = nall::Real<80>;
}
using int1 = nall::Integer< 1>;
using int2 = nall::Integer< 2>;
using int3 = nall::Integer< 3>;
using int4 = nall::Integer< 4>;
using int5 = nall::Integer< 5>;
using int6 = nall::Integer< 6>;
using int7 = nall::Integer< 7>;
using int8 = nall::Integer< 8>;
using int9 = nall::Integer< 9>;
using int10 = nall::Integer<10>;
using int11 = nall::Integer<11>;
using int12 = nall::Integer<12>;
using int13 = nall::Integer<13>;
using int14 = nall::Integer<14>;
using int15 = nall::Integer<15>;
using int16 = nall::Integer<16>;
using int17 = nall::Integer<17>;
using int18 = nall::Integer<18>;
using int19 = nall::Integer<19>;
using int20 = nall::Integer<20>;
using int21 = nall::Integer<21>;
using int22 = nall::Integer<22>;
using int23 = nall::Integer<23>;
using int24 = nall::Integer<24>;
using int25 = nall::Integer<25>;
using int26 = nall::Integer<26>;
using int27 = nall::Integer<27>;
using int28 = nall::Integer<28>;
using int29 = nall::Integer<29>;
using int30 = nall::Integer<30>;
using int31 = nall::Integer<31>;
using int32 = nall::Integer<32>;
using int33 = nall::Integer<33>;
using int34 = nall::Integer<34>;
using int35 = nall::Integer<35>;
using int36 = nall::Integer<36>;
using int37 = nall::Integer<37>;
using int38 = nall::Integer<38>;
using int39 = nall::Integer<39>;
using int40 = nall::Integer<40>;
using int41 = nall::Integer<41>;
using int42 = nall::Integer<42>;
using int43 = nall::Integer<43>;
using int44 = nall::Integer<44>;
using int45 = nall::Integer<45>;
using int46 = nall::Integer<46>;
using int47 = nall::Integer<47>;
using int48 = nall::Integer<48>;
using int49 = nall::Integer<49>;
using int50 = nall::Integer<50>;
using int51 = nall::Integer<51>;
using int52 = nall::Integer<52>;
using int53 = nall::Integer<53>;
using int54 = nall::Integer<54>;
using int55 = nall::Integer<55>;
using int56 = nall::Integer<56>;
using int57 = nall::Integer<57>;
using int58 = nall::Integer<58>;
using int59 = nall::Integer<59>;
using int60 = nall::Integer<60>;
using int61 = nall::Integer<61>;
using int62 = nall::Integer<62>;
using int63 = nall::Integer<63>;
using int64 = nall::Integer<64>;
using uint1 = nall::Natural< 1>;
using uint2 = nall::Natural< 2>;
using uint3 = nall::Natural< 3>;
using uint4 = nall::Natural< 4>;
using uint5 = nall::Natural< 5>;
using uint6 = nall::Natural< 6>;
using uint7 = nall::Natural< 7>;
using uint8 = nall::Natural< 8>;
using uint9 = nall::Natural< 9>;
using uint10 = nall::Natural<10>;
using uint11 = nall::Natural<11>;
using uint12 = nall::Natural<12>;
using uint13 = nall::Natural<13>;
using uint14 = nall::Natural<14>;
using uint15 = nall::Natural<15>;
using uint16 = nall::Natural<16>;
using uint17 = nall::Natural<17>;
using uint18 = nall::Natural<18>;
using uint19 = nall::Natural<19>;
using uint20 = nall::Natural<20>;
using uint21 = nall::Natural<21>;
using uint22 = nall::Natural<22>;
using uint23 = nall::Natural<23>;
using uint24 = nall::Natural<24>;
using uint25 = nall::Natural<25>;
using uint26 = nall::Natural<26>;
using uint27 = nall::Natural<27>;
using uint28 = nall::Natural<28>;
using uint29 = nall::Natural<29>;
using uint30 = nall::Natural<30>;
using uint31 = nall::Natural<31>;
using uint32 = nall::Natural<32>;
using uint33 = nall::Natural<33>;
using uint34 = nall::Natural<34>;
using uint35 = nall::Natural<35>;
using uint36 = nall::Natural<36>;
using uint37 = nall::Natural<37>;
using uint38 = nall::Natural<38>;
using uint39 = nall::Natural<39>;
using uint40 = nall::Natural<40>;
using uint41 = nall::Natural<41>;
using uint42 = nall::Natural<42>;
using uint43 = nall::Natural<43>;
using uint44 = nall::Natural<44>;
using uint45 = nall::Natural<45>;
using uint46 = nall::Natural<46>;
using uint47 = nall::Natural<47>;
using uint48 = nall::Natural<48>;
using uint49 = nall::Natural<49>;
using uint50 = nall::Natural<50>;
using uint51 = nall::Natural<51>;
using uint52 = nall::Natural<52>;
using uint53 = nall::Natural<53>;
using uint54 = nall::Natural<54>;
using uint55 = nall::Natural<55>;
using uint56 = nall::Natural<56>;
using uint57 = nall::Natural<57>;
using uint58 = nall::Natural<58>;
using uint59 = nall::Natural<59>;
using uint60 = nall::Natural<60>;
using uint61 = nall::Natural<61>;
using uint62 = nall::Natural<62>;
using uint63 = nall::Natural<63>;
using uint64 = nall::Natural<64>;