Update to v106r70 release.

byuu says:

Changelog:

  - Interface::displays() -> vector<Display> → Interface::display() -> Display
  - <Platform::videoRefresh(display>, ...) → <Platform::videoFrame>(...)
  - <Platform::audioSample>(...) → <Platform::audioFrame>(...)
  - higan, icarus: use AboutDialog class instead of ad-hoc
    implementations
      - about dialog is now modal, but now has a clickable website URL
  - icarus: reverted if constexpr for now
  - MSX: implemented basic CPU, VDP support

I took out the multiple displays support thing because it was never
really implemented fully (Emulator::Video and the GUIs both ignored it)
or used anyway. If it ends up necessary in the future, I'll worry about
it then.

There's enough MSX emulation now to run Mr. Do! without sound or input.
I'm shipping higan with C-BIOS 0.29a, although it likely won't be good
enough in the future (eg it can't do BASIC, floppy disk, or cassette
loading.) I have keyboard and (not working) AY-3-8910 support in a
different branch, so that won't take too long to implement. Main problem
is naming all the darned keyboard keys. I think I need to change
settings.bml's input mapping lines so that the key names are values
instead of node names, so that any characters can appear inside of them.

It turns out my MSX set uses .rom for the file extensions ... gods. So,
icarus can't really import them like this. I may have to re-design
icarus' importer to stop caring about the file extension and instead ask
you what kind of games you are importing. There's no way icarus can
heuristically guess what systems the images belong to, because many
systems don't have any standardized magic bytes.

I'm struggling with where to put SG-1000, SC-3000, ColecoVision, Coleco
Adam stuff. I think they need to be split to two separate higan
subfolders (sg and cv, most likely ...) The MS/GG share a very
customized and extended VDP that the other systems don't have. The Sega
and Coleco older hardware share the same TMS9918 as the MSX, yet have
very different memory maps and peripherals that I don't want to mix
together. Especially if we start getting into the computer-variants
more.
This commit is contained in:
Tim Allen 2019-01-03 21:05:20 +11:00
parent cac3858f65
commit 79be6f2355
58 changed files with 522 additions and 187 deletions

View File

@ -64,7 +64,7 @@ auto Audio::process() -> void {
if(balance > 0.0) samples[0] *= 1.0 - balance; if(balance > 0.0) samples[0] *= 1.0 - balance;
} }
platform->audioSample(samples, channels); platform->audioFrame(samples, channels);
} }
} }

View File

@ -30,7 +30,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "106.69"; static const string Version = "106.70";
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/";

View File

@ -54,7 +54,7 @@ struct Interface {
//information //information
virtual auto information() -> Information { return {}; } virtual auto information() -> Information { return {}; }
virtual auto displays() -> vector<Display> { return {}; } virtual auto display() -> Display { return {}; }
virtual auto color(uint32 color) -> uint64 { return 0; } virtual auto color(uint32 color) -> uint64 { return 0; }
//game interface //game interface

View File

@ -16,8 +16,8 @@ struct Platform {
virtual auto path(uint id) -> string { return ""; } virtual auto path(uint id) -> string { return ""; }
virtual auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> vfs::shared::file { return {}; } virtual auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> vfs::shared::file { return {}; }
virtual auto load(uint id, string name, string type, vector<string> options = {}) -> Load { return {}; } virtual auto load(uint id, string name, string type, vector<string> options = {}) -> Load { return {}; }
virtual auto videoRefresh(uint display, const uint32* data, uint pitch, uint width, uint height) -> void {} virtual auto videoFrame(const uint32* data, uint pitch, uint width, uint height) -> void {}
virtual auto audioSample(const double* samples, uint channels) -> void {} virtual auto audioFrame(const double* samples, uint channels) -> void {}
virtual auto inputPoll(uint port, uint device, uint input) -> int16 { return 0; } virtual auto inputPoll(uint port, uint device, uint input) -> int16 { return 0; }
virtual auto inputRumble(uint port, uint device, uint input, bool enable) -> void {} virtual auto inputRumble(uint port, uint device, uint input, bool enable) -> void {}
virtual auto dipSettings(Markup::Node node) -> uint { return 0; } virtual auto dipSettings(Markup::Node node) -> uint { return 0; }

View File

@ -28,7 +28,7 @@ auto Video::setPalette() -> void {
if(!interface) return; if(!interface) return;
delete palette; delete palette;
colors = interface->displays()[0].colors; colors = interface->display().colors;
palette = new uint32[colors]; palette = new uint32[colors];
for(auto index : range(colors)) { for(auto index : range(colors)) {
uint64 color = interface->color(index); uint64 color = interface->color(index);
@ -185,7 +185,7 @@ auto Video::refresh(uint32* input, uint pitch, uint width, uint height) -> void
} }
} }
platform->videoRefresh(0, output, width * sizeof(uint32), width, height); platform->videoFrame(output, width * sizeof(uint32), width, height);
} }
} }

View File

@ -13,7 +13,7 @@ auto Interface::information() -> Information {
return information; return information;
} }
auto Interface::displays() -> vector<Display> { auto Interface::display() -> Display {
Display display; Display display;
display.type = Display::Type::CRT; display.type = Display::Type::CRT;
display.colors = 1 << 9; display.colors = 1 << 9;
@ -23,7 +23,7 @@ auto Interface::displays() -> vector<Display> {
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); display.refreshRate = system.frequency() / (ppu.vlines() * ppu.rate() * 341.0);
return {display}; return display;
} }
auto Interface::color(uint32 n) -> uint64 { auto Interface::color(uint32 n) -> uint64 {

View File

@ -23,7 +23,7 @@ struct ID {
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
auto information() -> Information override; auto information() -> Information override;
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto loaded() -> bool override; auto loaded() -> bool override;

View File

@ -7,7 +7,7 @@ Settings settings;
#include "game-boy.cpp" #include "game-boy.cpp"
#include "game-boy-color.cpp" #include "game-boy-color.cpp"
auto Interface::displays() -> vector<Display> { auto Interface::display() -> Display {
Display display; Display display;
display.type = Display::Type::LCD; display.type = Display::Type::LCD;
display.colors = Model::GameBoyColor() ? 1 << 15 : 1 << 2; display.colors = Model::GameBoyColor() ? 1 << 15 : 1 << 2;
@ -17,7 +17,7 @@ auto Interface::displays() -> vector<Display> {
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); display.refreshRate = (4.0 * 1024.0 * 1024.0) / (154.0 * 456.0);
return {display}; return display;
} }
auto Interface::loaded() -> bool { auto Interface::loaded() -> bool {

View File

@ -23,7 +23,7 @@ struct ID {
}; };
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
auto displays() -> vector<Display> override; auto display() -> Display override;
auto loaded() -> bool override; auto loaded() -> bool override;
auto hashes() -> vector<string> override; auto hashes() -> vector<string> override;

View File

@ -12,7 +12,7 @@ auto Interface::information() -> Information {
return information; return information;
} }
auto Interface::displays() -> vector<Display> { auto Interface::display() -> Display {
Display display; Display display;
display.type = Display::Type::LCD; display.type = Display::Type::LCD;
display.colors = 1 << 15; display.colors = 1 << 15;
@ -26,7 +26,7 @@ auto Interface::displays() -> vector<Display> {
swap(display.width, display.height); swap(display.width, display.height);
swap(display.internalWidth, display.internalHeight); swap(display.internalWidth, display.internalHeight);
} }
return {display}; return display;
} }
auto Interface::color(uint32 color) -> uint64 { auto Interface::color(uint32 color) -> uint64 {

View File

@ -20,7 +20,7 @@ struct ID {
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
auto information() -> Information override; auto information() -> Information override;
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto loaded() -> bool override; auto loaded() -> bool override;

View File

@ -13,7 +13,7 @@ auto Interface::information() -> Information {
return information; return information;
} }
auto Interface::displays() -> vector<Display> { auto Interface::display() -> Display {
Display display; Display display;
display.type = Display::Type::CRT; display.type = Display::Type::CRT;
display.colors = 3 * (1 << 9); display.colors = 3 * (1 << 9);
@ -23,7 +23,7 @@ auto Interface::displays() -> vector<Display> {
display.internalHeight = 480; display.internalHeight = 480;
display.aspectCorrection = 1.0; display.aspectCorrection = 1.0;
display.refreshRate = (system.frequency() / 2.0) / (vdp.frameHeight() * 1710.0); display.refreshRate = (system.frequency() / 2.0) / (vdp.frameHeight() * 1710.0);
return {display}; return display;
} }
auto Interface::color(uint32 color) -> uint64 { auto Interface::color(uint32 color) -> uint64 {

View File

@ -24,7 +24,7 @@ struct ID {
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
auto information() -> Information override; auto information() -> Information override;
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto loaded() -> bool override; auto loaded() -> bool override;

View File

@ -6,7 +6,7 @@ auto ColecoVisionInterface::information() -> Information {
return information; return information;
} }
auto ColecoVisionInterface::displays() -> vector<Display> { auto ColecoVisionInterface::display() -> Display {
Display display; Display display;
display.type = Display::Type::CRT; display.type = Display::Type::CRT;
display.colors = 1 << 4; display.colors = 1 << 4;
@ -17,7 +17,7 @@ auto ColecoVisionInterface::displays() -> vector<Display> {
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::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); if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
return {display}; return display;
} }
auto ColecoVisionInterface::color(uint32 color) -> uint64 { auto ColecoVisionInterface::color(uint32 color) -> uint64 {

View File

@ -6,7 +6,7 @@ auto GameGearInterface::information() -> Information {
return information; return information;
} }
auto GameGearInterface::displays() -> vector<Display> { auto GameGearInterface::display() -> Display {
Display display; Display display;
display.type = Display::Type::LCD; display.type = Display::Type::LCD;
display.colors = 1 << 12; display.colors = 1 << 12;
@ -16,7 +16,7 @@ auto GameGearInterface::displays() -> vector<Display> {
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); display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
return {display}; return display;
} }
auto GameGearInterface::color(uint32 color) -> uint64 { auto GameGearInterface::color(uint32 color) -> uint64 {

View File

@ -53,7 +53,7 @@ struct Interface : Emulator::Interface {
struct ColecoVisionInterface : Interface { struct ColecoVisionInterface : Interface {
auto information() -> Information override; auto information() -> Information override;
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto ports() -> vector<Port> override; auto ports() -> vector<Port> override;
@ -69,7 +69,7 @@ struct ColecoVisionInterface : Interface {
struct SG1000Interface : Interface { struct SG1000Interface : Interface {
auto information() -> Information override; auto information() -> Information override;
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto ports() -> vector<Port> override; auto ports() -> vector<Port> override;
@ -85,7 +85,7 @@ struct SG1000Interface : Interface {
struct SC3000Interface : Interface { struct SC3000Interface : Interface {
auto information() -> Information override; auto information() -> Information override;
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto ports() -> vector<Port> override; auto ports() -> vector<Port> override;
@ -101,7 +101,7 @@ struct SC3000Interface : Interface {
struct MasterSystemInterface : Interface { struct MasterSystemInterface : Interface {
auto information() -> Information override; auto information() -> Information override;
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto ports() -> vector<Port> override; auto ports() -> vector<Port> override;
@ -117,7 +117,7 @@ struct MasterSystemInterface : Interface {
struct GameGearInterface : Interface { struct GameGearInterface : Interface {
auto information() -> Information override; auto information() -> Information override;
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto ports() -> vector<Port> override; auto ports() -> vector<Port> override;

View File

@ -6,7 +6,7 @@ auto MasterSystemInterface::information() -> Information {
return information; return information;
} }
auto MasterSystemInterface::displays() -> vector<Display> { auto MasterSystemInterface::display() -> Display {
Display display; Display display;
display.type = Display::Type::CRT; display.type = Display::Type::CRT;
display.colors = 1 << 6; display.colors = 1 << 6;
@ -17,7 +17,7 @@ auto MasterSystemInterface::displays() -> vector<Display> {
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::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); if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
return {display}; return display;
} }
auto MasterSystemInterface::color(uint32 color) -> uint64 { auto MasterSystemInterface::color(uint32 color) -> uint64 {

View File

@ -6,7 +6,7 @@ auto SC3000Interface::information() -> Information {
return information; return information;
} }
auto SC3000Interface::displays() -> vector<Display> { auto SC3000Interface::display() -> Display {
Display display; Display display;
display.type = Display::Type::CRT; display.type = Display::Type::CRT;
display.colors = 1 << 4; display.colors = 1 << 4;
@ -17,7 +17,7 @@ auto SC3000Interface::displays() -> vector<Display> {
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::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); if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
return {display}; return display;
} }
auto SC3000Interface::color(uint32 color) -> uint64 { auto SC3000Interface::color(uint32 color) -> uint64 {

View File

@ -6,7 +6,7 @@ auto SG1000Interface::information() -> Information {
return information; return information;
} }
auto SG1000Interface::displays() -> vector<Display> { auto SG1000Interface::display() -> Display {
Display display; Display display;
display.type = Display::Type::CRT; display.type = Display::Type::CRT;
display.colors = 1 << 4; display.colors = 1 << 4;
@ -17,7 +17,7 @@ auto SG1000Interface::displays() -> vector<Display> {
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::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); if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
return {display}; return display;
} }
auto SG1000Interface::color(uint32 color) -> uint64 { auto SG1000Interface::color(uint32 color) -> uint64 {

View File

@ -57,13 +57,8 @@ auto VDP::Background::graphics2(uint8 hoffset, uint9 voffset) -> void {
patternAddress.bits(3,10) = pattern; patternAddress.bits(3,10) = pattern;
if(voffset >= 64 && voffset <= 127) patternAddress.bit(11) = vdp.io.patternTableAddress.bit(0); if(voffset >= 64 && voffset <= 127) patternAddress.bit(11) = vdp.io.patternTableAddress.bit(0);
if(voffset >= 128 && voffset <= 191) patternAddress.bit(12) = vdp.io.patternTableAddress.bit(1); if(voffset >= 128 && voffset <= 191) patternAddress.bit(12) = vdp.io.patternTableAddress.bit(1);
uint14 colorAddress = patternAddress;
patternAddress.bit(13) = vdp.io.patternTableAddress.bit(2); patternAddress.bit(13) = vdp.io.patternTableAddress.bit(2);
uint14 colorAddress;
colorAddress.bits(0, 2) = voffset.bits(0,2);
colorAddress.bits(3,10) = pattern;
if(voffset >= 64 && voffset <= 127) colorAddress.bit(11) = vdp.io.patternTableAddress.bit(0);
if(voffset >= 128 && voffset <= 191) colorAddress.bit(12) = vdp.io.patternTableAddress.bit(1);
colorAddress.bit(13) = vdp.io.colorTableAddress.bit(7); colorAddress.bit(13) = vdp.io.colorTableAddress.bit(7);
uint8 colorMask = vdp.io.colorTableAddress.bits(0,6) << 1 | 1; uint8 colorMask = vdp.io.colorTableAddress.bits(0,6) << 1 | 1;

View File

@ -58,4 +58,11 @@ auto Cartridge::unload() -> void {
auto Cartridge::power() -> void { auto Cartridge::power() -> void {
} }
auto Cartridge::read(uint16 address) -> uint8 {
return rom.read(address);
}
auto Cartridge::write(uint16 address, uint8 data) -> void {
}
} }

View File

@ -12,6 +12,9 @@ struct Cartridge {
auto power() -> void; auto power() -> void;
auto read(uint16 address) -> uint8;
auto write(uint16 address, uint8 data) -> void;
//serialization.cpp //serialization.cpp
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;

View File

@ -11,11 +11,14 @@ auto CPU::Enter() -> void {
} }
auto CPU::main() -> void { auto CPU::main() -> void {
if(io.irqLine) irq(1, 0x0038, 0xff);
instruction(); instruction();
} }
auto CPU::step(uint clocks) -> void { auto CPU::step(uint clocks) -> void {
Thread::step(clocks); Thread::step(clocks);
synchronize(vdp);
synchronize(psg);
} }
auto CPU::synchronizing() const -> bool { auto CPU::synchronizing() const -> bool {
@ -23,6 +26,19 @@ auto CPU::synchronizing() const -> bool {
} }
auto CPU::power() -> void { auto CPU::power() -> void {
Z80::bus = this;
Z80::power();
create(CPU::Enter, system.colorburst());
r.pc = 0x0000; //reset vector address
ram.allocate(0x10000);
io = {};
}
auto CPU::setIRQ(bool line) -> void {
io.irqLine = line;
} }
} }

View File

@ -6,6 +6,7 @@ struct CPU : Processor::Z80, Processor::Z80::Bus, Thread {
auto synchronizing() const -> bool override; auto synchronizing() const -> bool override;
auto power() -> void; auto power() -> void;
auto setIRQ(bool) -> void;
//memory.cpp //memory.cpp
auto read(uint16 address) -> uint8 override; auto read(uint16 address) -> uint8 override;
@ -16,6 +17,14 @@ struct CPU : Processor::Z80, Processor::Z80::Bus, Thread {
//serialization.cpp //serialization.cpp
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
private:
Emulator::Memory::Writable<uint8> ram;
struct IO {
uint1 irqLine;
uint2 slot[4];
} io;
}; };
extern CPU cpu; extern CPU cpu;

View File

@ -1,13 +1,65 @@
auto CPU::read(uint16 address) -> uint8 { auto CPU::read(uint16 address) -> uint8 {
uint2 slot = io.slot[address.bits(14,15)];
if(slot == 0) {
if(!address.bit(15)) return system.bios.read(address);
return 0xff;
}
if(slot == 1) {
return cartridge.read(address);
}
if(slot == 2) {
return ram.read(address);
}
if(slot == 3) {
}
return 0xff; return 0xff;
} }
auto CPU::write(uint16 address, uint8 data) -> void { auto CPU::write(uint16 address, uint8 data) -> void {
uint2 slot = io.slot[address.bits(14,15)];
if(slot == 0) {
return;
}
if(slot == 1) {
return cartridge.write(address, data);
}
if(slot == 2) {
return ram.write(address, data);
}
if(slot == 3) {
return;
}
} }
auto CPU::in(uint8 address) -> uint8 { auto CPU::in(uint8 address) -> uint8 {
switch(address) {
case 0x98: return vdp.data();
case 0x99: return vdp.status();
case 0xa8: return io.slot[0] << 0
| io.slot[1] << 2
| io.slot[2] << 4
| io.slot[3] << 6;
}
return 0xff; return 0xff;
} }
auto CPU::out(uint8 address, uint8 data) -> void { auto CPU::out(uint8 address, uint8 data) -> void {
switch(address) {
case 0x98: return vdp.data(data);
case 0x99: return vdp.control(data);
case 0xa8: io.slot[0] = data.bits(0,1);
io.slot[1] = data.bits(2,3);
io.slot[2] = data.bits(4,5);
io.slot[3] = data.bits(6,7);
break;
}
} }

View File

@ -6,11 +6,11 @@ auto Interface::information() -> Information {
Information information; Information information;
information.manufacturer = ""; information.manufacturer = "";
information.name = "MSX"; information.name = "MSX";
information.extension = ".msx"; information.extension = "msx";
return information; return information;
} }
auto Interface::displays() -> vector<Display> { auto Interface::display() -> Display {
Display display; Display display;
display.type = Display::Type::CRT; display.type = Display::Type::CRT;
display.colors = 1 << 4; display.colors = 1 << 4;
@ -20,40 +20,58 @@ auto Interface::displays() -> vector<Display> {
display.internalHeight = 192; display.internalHeight = 192;
display.aspectCorrection = 1.0; display.aspectCorrection = 1.0;
display.refreshRate = 60.0; //todo: PAL display.refreshRate = 60.0; //todo: PAL
return {display}; return display;
} }
auto Interface::color(uint32 color) -> uint64 { auto Interface::color(uint32 color) -> uint64 {
switch(color.bits(0,3)) { switch(color.bits(0,3)) {
case 0: return 0x0000'0000'0000ull; //transparent
case 1: return 0x0000'0000'0000ull; //black
case 2: return 0x2121'c8c8'4242ull; //medium green
case 3: return 0x5e5e'dcdc'7878ull; //light green
case 4: return 0x5454'5555'ededull; //dark blue
case 5: return 0x7d7d'7676'fcfcull; //light blue
case 6: return 0xd4d4'5252'4d4dull; //dark red
case 7: return 0x4242'ebeb'f5f5ull; //cyan
case 8: return 0xfcfc'5555'5454ull; //medium red
case 9: return 0xffff'7979'7878ull; //light red
case 10: return 0xd4d4'c1c1'5454ull; //dark yellow
case 11: return 0xe6e6'cece'8080ull; //light yellow
case 12: return 0x2121'b0b0'3b3bull; //dark green
case 13: return 0xc9c9'5b5b'babaull; //magenta
case 14: return 0xcccc'cccc'ccccull; //gray
case 15: return 0xffff'ffff'ffffull; //white
} }
return 0; return 0;
} }
auto Interface::loaded() -> bool { auto Interface::loaded() -> bool {
return false; return system.loaded();
} }
auto Interface::hashes() -> vector<string> { auto Interface::hashes() -> vector<string> {
return {}; return {cartridge.hash()};
} }
auto Interface::manifests() -> vector<string> { auto Interface::manifests() -> vector<string> {
return {}; return {cartridge.manifest()};
} }
auto Interface::titles() -> vector<string> { auto Interface::titles() -> vector<string> {
return {}; return {cartridge.title()};
} }
auto Interface::load() -> bool { auto Interface::load() -> bool {
return false; return system.load(this, System::Model::MSX);
} }
auto Interface::save() -> void { auto Interface::save() -> void {
system.save();
} }
auto Interface::unload() -> void { auto Interface::unload() -> void {
save(); save();
system.unload();
} }
auto Interface::ports() -> vector<Port> { return { auto Interface::ports() -> vector<Port> { return {
@ -91,17 +109,20 @@ auto Interface::inputs(uint device) -> vector<Input> {
} }
auto Interface::power() -> void { auto Interface::power() -> void {
system.power();
} }
auto Interface::run() -> void { auto Interface::run() -> void {
system.run();
} }
auto Interface::serialize() -> serializer { auto Interface::serialize() -> serializer {
return {}; system.runToSave();
return system.serialize();
} }
auto Interface::unserialize(serializer& s) -> bool { auto Interface::unserialize(serializer& s) -> bool {
return false; return system.unserialize(s);
} }
} }

View File

@ -25,7 +25,7 @@ struct ID {
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
auto information() -> Information override; auto information() -> Information override;
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto loaded() -> bool override; auto loaded() -> bool override;

View File

@ -29,6 +29,13 @@ auto System::load(Emulator::Interface* interface, Model model) -> bool {
auto document = BML::unserialize(information.manifest); auto document = BML::unserialize(information.manifest);
if(auto memory = document["system/memory(type=ROM,content=BIOS)"]) {
bios.allocate(memory["size"].natural());
if(auto fp = platform->open(ID::System, "bios.rom", File::Read, File::Required)) {
bios.load(fp);
} else return false;
} else return false;
if(!cartridge.load()) return false; if(!cartridge.load()) return false;
if(cartridge.region() == "NTSC") { if(cartridge.region() == "NTSC") {

View File

@ -24,6 +24,8 @@ struct System {
auto serializeAll(serializer&) -> void; auto serializeAll(serializer&) -> void;
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
Emulator::Memory::Readable<uint8> bios;
private: private:
Emulator::Interface* interface = nullptr; Emulator::Interface* interface = nullptr;

View File

@ -0,0 +1,73 @@
auto VDP::background(uint8 hoffset, uint8 voffset) -> void {
if(!io.displayEnable) {
output.color = io.colorBackground;
return;
}
switch(io.videoMode) {
case 0: return graphics1(hoffset, voffset);
//case 1: return text1(hoffset, voffset);
case 2: return graphics2(hoffset, voffset);
case 3: return multicolor(hoffset, voffset);
default: output.color = 8; return; //medium red color to identify unimplemented modes
}
}
auto VDP::text1(uint8 hoffset, uint8 voffset) -> void {
}
auto VDP::graphics1(uint8 hoffset, uint8 voffset) -> void {
uint14 nameAddress;
nameAddress.bits( 0, 4) = hoffset.bits(3,7);
nameAddress.bits( 5, 9) = voffset.bits(3,7);
nameAddress.bits(10,13) = io.nameTableAddress;
uint8 pattern = vram.read(nameAddress);
uint14 patternAddress;
patternAddress.bits( 0, 2) = voffset.bits(0,2);
patternAddress.bits( 3,10) = pattern;
patternAddress.bits(11,13) = io.patternTableAddress;
uint14 colorAddress; //d5 = 0
colorAddress.bits(0, 4) = pattern.bits(3,7);
colorAddress.bits(6,13) = io.colorTableAddress;
uint8 color = vram.read(colorAddress);
uint3 index = hoffset ^ 7;
if(!vram.read(patternAddress).bit(index)) {
output.color = color.bits(0,3);
} else {
output.color = color.bits(4,7);
}
}
auto VDP::graphics2(uint8 hoffset, uint8 voffset) -> void {
uint14 nameAddress;
nameAddress.bits( 0, 4) = hoffset.bits(3,7);
nameAddress.bits( 5, 9) = voffset.bits(3,7);
nameAddress.bits(10,13) = io.nameTableAddress;
uint8 pattern = vram.read(nameAddress);
uint14 patternAddress;
patternAddress.bits(0, 2) = voffset.bits(0,2);
patternAddress.bits(3,10) = pattern;
if(voffset >= 64 && voffset <= 127) patternAddress.bit(11) = io.patternTableAddress.bit(0);
if(voffset >= 128 && voffset <= 191) patternAddress.bit(12) = io.patternTableAddress.bit(1);
uint14 colorAddress = patternAddress;
patternAddress.bit(13) = io.patternTableAddress.bit(2);
colorAddress.bit(13) = io.colorTableAddress.bit(7);
uint8 colorMask = io.colorTableAddress.bits(0,6) << 1 | 1;
uint8 color = vram.read(colorAddress);
uint3 index = hoffset ^ 7;
if(!vram.read(patternAddress).bit(index)) {
output.color = color.bits(0,3);
} else {
output.color = color.bits(4,7);
}
}
auto VDP::multicolor(uint8 hoffset, uint8 voffset) -> void {
}

79
higan/msx/vdp/io.cpp Normal file
View File

@ -0,0 +1,79 @@
auto VDP::status() -> uint8 {
io.controlLatch = 0;
uint8 data = 0x00;
data.bits(0,4) = io.spriteOverflowIndex;
data.bit(5) = io.spriteCollision;
data.bit(6) = io.spriteOverflow;
data.bit(7) = io.irqLine;
io.irqLine = 0;
return data;
}
auto VDP::data() -> uint8 {
io.controlLatch = 0;
uint8 data = io.vramLatch;
uint14 address = io.controlValue.bits(0,13)++;
io.vramLatch = vram.read(address);
return data;
}
auto VDP::data(uint8 data) -> void {
io.controlLatch = 0;
uint14 address = io.controlValue.bits(0,13)++;
vram.write(address, data);
}
auto VDP::control(uint8 data) -> void {
if(io.controlLatch == 0) {
io.controlLatch = 1;
io.controlValue.byte(0) = data;
return;
} else {
io.controlLatch = 0;
io.controlValue.byte(1) = data;
}
if(!io.controlValue.bit(15)) {
if(!io.controlValue.bit(14)) {
uint14 address = io.controlValue.bits(0,13)++;
io.vramLatch = vram.read(address);
}
return;
}
data = io.controlValue.bits(0,7);
switch(io.controlValue.bits(8,10)) {
case 0:
io.externalInput = data.bit(0);
io.videoMode.bit(1) = data.bit(1);
break;
case 1:
io.spriteZoom = data.bit(0);
io.spriteSize = data.bit(1);
io.videoMode.bit(2) = data.bit(3);
io.videoMode.bit(0) = data.bit(4);
io.irqEnable = data.bit(5);
io.displayEnable = data.bit(6);
io.ramMode = data.bit(7);
break;
case 2:
io.nameTableAddress = data.bits(0,3);
break;
case 3:
io.colorTableAddress = data.bits(0,7);
break;
case 4:
io.patternTableAddress = data.bits(0,2);
break;
case 5:
io.spriteAttributeTableAddress = data.bits(0,6);
break;
case 6:
io.spritePatternTableAddress = data.bits(0,2);
break;
case 7:
io.colorBackground = data.bits(0,3);
io.colorForeground = data.bits(4,7);
break;
}
}

58
higan/msx/vdp/sprites.cpp Normal file
View File

@ -0,0 +1,58 @@
auto VDP::sprite(uint8 voffset) -> void {
uint valid = 0;
uint limit = io.spriteSize ? 15 : 7;
for(uint index : range(4)) sprites[index].y = 0xd0;
uint14 attributeAddress;
attributeAddress.bits(7,13) = io.spriteAttributeTableAddress;
for(uint index : range(32)) {
uint8 y = vram.read(attributeAddress++);
if(y == 0xd0) break;
uint8 x = vram.read(attributeAddress++);
uint8 pattern = vram.read(attributeAddress++);
uint8 extra = vram.read(attributeAddress++);
if(extra.bit(7)) x -= 32;
y += 1;
if(voffset < y) continue;
if(voffset > y + limit) continue;
if(limit == 15) pattern.bits(0,1) = 0;
if(valid == 4) {
io.spriteOverflow = true;
io.spriteOverflowIndex = index;
break;
}
sprites[valid++] = {x, y, pattern, extra.bits(0,3)};
}
}
auto VDP::sprite(uint8 hoffset, uint8 voffset) -> void {
uint4 color;
uint limit = io.spriteSize ? 15 : 7;
for(uint n : range(4)) {
auto& o = sprites[n];
if(o.y == 0xd0) continue;
if(hoffset < o.x) continue;
if(hoffset > o.x + limit) continue;
uint x = hoffset - o.x;
uint y = voffset - o.y;
uint14 address;
address.bits( 0,10) = (o.pattern << 3) + (x >> 3 << 4) + (y & limit);
address.bits(11,13) = io.spritePatternTableAddress;
uint3 index = x ^ 7;
if(vram.read(address).bit(index)) {
if(color) { io.spriteCollision = true; break; }
color = o.color;
}
}
if(color) output.color = color;
}

View File

@ -1,10 +1,13 @@
#include <msx/msx.hpp> #include <msx/msx.hpp>
//228 clocks/scanline //456 clocks/scanline
namespace MSX { namespace MSX {
VDP vdp; VDP vdp;
#include "io.cpp"
#include "background.cpp"
#include "sprites.cpp"
#include "serialization.cpp" #include "serialization.cpp"
auto VDP::Enter() -> void { auto VDP::Enter() -> void {
@ -12,11 +15,30 @@ auto VDP::Enter() -> void {
} }
auto VDP::main() -> void { auto VDP::main() -> void {
step(1); if(io.vcounter < 192) {
uint8 y = io.vcounter;
sprite(y);
auto line = buffer + y * 256;
for(uint8 x : range(256)) {
background(x, y);
sprite(x, y);
line[x] = output.color;
step(1);
}
step(200);
} else {
step(456);
}
io.vcounter++;
if(io.vcounter == 262) io.vcounter = 0;
if(io.vcounter == 0) io.irqLine = 0;
if(io.vcounter == 192) io.irqLine = 1, scheduler.exit(Scheduler::Event::Frame);
} }
auto VDP::step(uint clocks) -> void { auto VDP::step(uint clocks) -> void {
Thread::step(clocks); Thread::step(clocks);
synchronize(cpu);
} }
auto VDP::refresh() -> void { auto VDP::refresh() -> void {
@ -24,7 +46,10 @@ auto VDP::refresh() -> void {
} }
auto VDP::power() -> void { auto VDP::power() -> void {
create(VDP::Enter, system.colorburst()); create(VDP::Enter, system.colorburst() * 2);
vram.allocate(0x4000);
io = {};
} }
} }

View File

@ -9,11 +9,70 @@ struct VDP : Thread {
auto power() -> void; auto power() -> void;
//io.cpp
auto status() -> uint8;
auto data() -> uint8;
auto data(uint8) -> void;
auto control(uint8) -> void;
//background.cpp
auto background(uint8 hoffset, uint8 voffset) -> void;
auto text1(uint8 hoffset, uint8 voffset) -> void;
auto graphics1(uint8 hoffset, uint8 voffset) -> void;
auto graphics2(uint8 hoffset, uint8 voffset) -> void;
auto multicolor(uint8 hoffset, uint8 voffset) -> void;
//sprites.cpp
auto sprite(uint8 voffset) -> void;
auto sprite(uint8 hoffset, uint8 voffset) -> void;
//serialization.cpp //serialization.cpp
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
private: private:
uint32 buffer[256 * 192]; uint32 buffer[256 * 192];
Emulator::Memory::Writable<uint8> vram;
struct IO {
uint vcounter = 0;
uint hcounter = 0;
uint1 controlLatch;
uint16 controlValue;
uint8 vramLatch;
uint5 spriteOverflowIndex;
uint1 spriteCollision;
uint1 spriteOverflow;
uint1 irqLine;
uint1 externalInput;
uint3 videoMode;
uint1 spriteZoom;
uint1 spriteSize;
uint1 irqEnable;
uint1 displayEnable;
uint1 ramMode = 1; //0 = 4KB; 1 = 16KB
uint4 nameTableAddress;
uint8 colorTableAddress;
uint3 patternTableAddress;
uint7 spriteAttributeTableAddress;
uint3 spritePatternTableAddress;
uint4 colorBackground;
uint4 colorForeground;
} io;
struct Sprite {
uint8 x;
uint8 y;
uint8 pattern;
uint4 color;
} sprites[4];
struct Output {
uint4 color;
} output;
}; };
extern VDP vdp; extern VDP vdp;

View File

@ -6,7 +6,7 @@ namespace NeoGeoPocket {
#include "neo-geo-pocket-color.cpp" #include "neo-geo-pocket-color.cpp"
//todo: add correct values //todo: add correct values
auto Interface::displays() -> vector<Display> { auto Interface::display() -> Display {
Display display; Display display;
display.type = Display::Type::LCD; display.type = Display::Type::LCD;
display.colors = 1; display.colors = 1;
@ -16,7 +16,7 @@ auto Interface::displays() -> vector<Display> {
display.internalHeight = 240; display.internalHeight = 240;
display.aspectCorrection = 1.0; display.aspectCorrection = 1.0;
display.refreshRate = 60.0; display.refreshRate = 60.0;
return {display}; return display;
} }
auto Interface::color(uint32 color) -> uint64 { auto Interface::color(uint32 color) -> uint64 {

View File

@ -19,7 +19,7 @@ struct ID {
}; };
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto loaded() -> bool override; auto loaded() -> bool override;

View File

@ -7,7 +7,7 @@ Settings settings;
#include "pc-engine.cpp" #include "pc-engine.cpp"
#include "supergrafx.cpp" #include "supergrafx.cpp"
auto Interface::displays() -> vector<Display> { auto Interface::display() -> Display {
Display display; Display display;
display.type = Display::Type::CRT; display.type = Display::Type::CRT;
display.colors = 1 << 9; display.colors = 1 << 9;
@ -17,7 +17,7 @@ auto Interface::displays() -> vector<Display> {
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); display.refreshRate = (system.colorburst() * 6.0) / (262.0 * 1365.0);
return {display}; return display;
} }
auto Interface::color(uint32 color) -> uint64 { auto Interface::color(uint32 color) -> uint64 {

View File

@ -20,7 +20,7 @@ struct ID {
}; };
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto loaded() -> bool override; auto loaded() -> bool override;

View File

@ -14,7 +14,7 @@ auto Interface::information() -> Information {
return information; return information;
} }
auto Interface::displays() -> vector<Display> { auto Interface::display() -> Display {
Display display; Display display;
display.type = Display::Type::CRT; display.type = Display::Type::CRT;
display.colors = 1 << 19; display.colors = 1 << 19;
@ -25,7 +25,7 @@ auto Interface::displays() -> vector<Display> {
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::NTSC()) display.refreshRate = system.cpuFrequency() / (262.0 * 1364.0);
if(Region::PAL()) display.refreshRate = system.cpuFrequency() / (312.0 * 1364.0); if(Region::PAL()) display.refreshRate = system.cpuFrequency() / (312.0 * 1364.0);
return {display}; return display;
} }
auto Interface::color(uint32 color) -> uint64 { auto Interface::color(uint32 color) -> uint64 {

View File

@ -35,7 +35,7 @@ struct ID {
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
auto information() -> Information; auto information() -> Information;
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto loaded() -> bool override; auto loaded() -> bool override;

Binary file not shown.

View File

@ -1 +1,5 @@
system name:MSX system name:MSX
memory
type: ROM
size: 0x8000
content: BIOS

View File

@ -1,26 +0,0 @@
auto AboutWindow::create() -> void {
setTitle({tr("About {0}", "bsnes"), " ..."});
setBackgroundColor({255, 255, 240});
layout.setPadding(10);
auto logo = image{Resource::Logo};
logo.alphaBlend(0xfffff0);
canvas.setIcon(logo);
tableLayout.setFont(Font().setBold());
tableLayout.setSize({2, 4});
tableLayout.column(0).setSpacing(4);
tableLayout.row(0).setSpacing(2);
tableLayout.row(1).setSpacing(2);
tableLayout.row(2).setSpacing(2);
versionLabel.setText({tr("Version"), ":"}).setAlignment(1.0);
versionValue.setText(Emulator::Version);
authorLabel.setText({tr("Author"), ":"}).setAlignment(1.0);
authorValue.setText(Emulator::Author).setToolTip("ビュウ");
licenseLabel.setText({tr("License"), ":"}).setAlignment(1.0);
licenseValue.setText(Emulator::License);
websiteLabel.setText({tr("Website"), ":"}).setAlignment(1.0);
websiteValue.setText(Emulator::Website);
setResizable(false);
setSize(layout.minimumSize());
setDismissable();
}

View File

@ -1,6 +1,4 @@
#include "../bsnes.hpp" #include "../bsnes.hpp"
#include "about.cpp"
AboutWindow aboutWindow;
Presentation presentation; Presentation presentation;
auto Presentation::create() -> void { auto Presentation::create() -> void {
@ -137,7 +135,14 @@ auto Presentation::create() -> void {
invoke("https://doc.byuu.org/bsnes/"); invoke("https://doc.byuu.org/bsnes/");
}); });
about.setIcon(Icon::Prompt::Question).setText({tr("About"), " ..."}).onActivate([&] { about.setIcon(Icon::Prompt::Question).setText({tr("About"), " ..."}).onActivate([&] {
aboutWindow.setCentered(*this).setVisible().setFocused(); AboutDialog()
.setLogo(Resource::Logo)
.setVersion(Emulator::Version)
.setAuthor("byuu")
.setLicense("GPLv3")
.setWebsite("https://byuu.org/")
.setParent(*this)
.show();
}); });
viewport.setDroppable().onDrop([&](vector<string> locations) { viewport.setDroppable().onDrop([&](vector<string> locations) {

View File

@ -1,23 +1,3 @@
struct AboutWindow : Window {
Application::Namespace tr{"AboutWindow"};
auto create() -> void;
VerticalLayout layout{this};
Canvas canvas{&layout, Size{400, 85}, 0};
TableLayout tableLayout{&layout, Size{~0, 0}};
Label versionLabel{&tableLayout, Size{~0, 0}};
Label versionValue{&tableLayout, Size{~0, 0}};
//
Label authorLabel{&tableLayout, Size{~0, 0}};
Label authorValue{&tableLayout, Size{~0, 0}};
//
Label licenseLabel{&tableLayout, Size{~0, 0}};
Label licenseValue{&tableLayout, Size{~0, 0}};
//
Label websiteLabel{&tableLayout, Size{~0, 0}};
Label websiteValue{&tableLayout, Size{~0, 0}};
};
struct Presentation : Window { struct Presentation : Window {
Application::Namespace tr{"Presentation"}; Application::Namespace tr{"Presentation"};
auto create() -> void; auto create() -> void;
@ -117,5 +97,4 @@ struct Presentation : Window {
Label spacerRight{&statusLayout, Size{8, ~0}, 0}; Label spacerRight{&statusLayout, Size{8, ~0}, 0};
}; };
extern AboutWindow aboutWindow;
extern Presentation presentation; extern Presentation presentation;

View File

@ -207,7 +207,7 @@ auto Program::load(uint id, string name, string type, vector<string> options) ->
return {}; return {};
} }
auto Program::videoRefresh(uint display, const uint32* data, uint pitch, uint width, uint height) -> void { auto Program::videoFrame(const uint32* data, uint pitch, uint width, uint height) -> void {
uint32_t* output; uint32_t* output;
uint length; uint length;
@ -255,7 +255,7 @@ auto Program::videoRefresh(uint display, const uint32* data, uint pitch, uint wi
} }
} }
auto Program::audioSample(const double* samples, uint channels) -> void { auto Program::audioFrame(const double* samples, uint channels) -> void {
audio.output(samples); audio.output(samples);
} }

View File

@ -18,7 +18,6 @@ auto Program::create() -> void {
presentation.create(); presentation.create();
presentation.setVisible(); presentation.setVisible();
aboutWindow.create();
settingsWindow.create(); settingsWindow.create();
videoSettings.create(); videoSettings.create();

View File

@ -9,8 +9,8 @@ struct Program : Lock, Emulator::Platform {
//platform.cpp //platform.cpp
auto open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file override; auto open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file override;
auto load(uint id, string name, string type, vector<string> options = {}) -> Emulator::Platform::Load override; auto load(uint id, string name, string type, vector<string> options = {}) -> Emulator::Platform::Load override;
auto videoRefresh(uint display, const uint32* data, uint pitch, uint width, uint height) -> void override; auto videoFrame(const uint32* data, uint pitch, uint width, uint height) -> void override;
auto audioSample(const double* samples, uint channels) -> void override; auto audioFrame(const double* samples, uint channels) -> void override;
auto inputPoll(uint port, uint device, uint input) -> int16 override; auto inputPoll(uint port, uint device, uint input) -> int16 override;
auto inputRumble(uint port, uint device, uint input, bool enable) -> void override; auto inputRumble(uint port, uint device, uint input, bool enable) -> void override;

View File

@ -1,27 +0,0 @@
AboutWindow::AboutWindow() {
aboutWindow = this;
setTitle("About higan ...");
setBackgroundColor({255, 255, 240});
layout.setPadding(10);
auto logo = image{Resource::Logo};
logo.alphaBlend(0xfffff0);
canvas.setIcon(logo);
informationLeft.setFont(Font().setBold()).setAlignment(1.0).setText({
"Version:\n",
"Author:\n",
"License:\n",
"Website:"
});
informationRight.setFont(Font().setBold()).setAlignment(0.0).setText({
Emulator::Version, "\n",
Emulator::Author, "\n",
Emulator::License, "\n",
Emulator::Website
});
setResizable(false);
setSize(layout.minimumSize());
setCentered();
setDismissable();
}

View File

@ -1,6 +1,4 @@
#include "../higan.hpp" #include "../higan.hpp"
#include "about.cpp"
unique_pointer<AboutWindow> aboutWindow;
unique_pointer<Presentation> presentation; unique_pointer<Presentation> presentation;
Presentation::Presentation() { Presentation::Presentation() {
@ -131,7 +129,14 @@ Presentation::Presentation() {
invoke("https://doc.byuu.org/higan/credits/"); invoke("https://doc.byuu.org/higan/credits/");
}); });
about.setIcon(Icon::Prompt::Question).setText("About ...").onActivate([&] { about.setIcon(Icon::Prompt::Question).setText("About ...").onActivate([&] {
aboutWindow->setCentered(*this).setVisible().setFocused(); AboutDialog()
.setLogo(Resource::Logo)
.setVersion(Emulator::Version)
.setAuthor("byuu")
.setLicense("GPLv3")
.setWebsite("https://byuu.org/")
.setParent(*this)
.show();
}); });
viewport.setDroppable().onDrop([&](vector<string> locations) { viewport.setDroppable().onDrop([&](vector<string> locations) {
@ -345,7 +350,7 @@ auto Presentation::resizeViewport() -> void {
uint height = 240; uint height = 240;
if(emulator) { if(emulator) {
auto display = emulator->displays().first(); auto display = emulator->display();
width = display.width; width = display.width;
height = display.height; height = display.height;
if(settings["View/AspectCorrection"].boolean()) width *= display.aspectCorrection; if(settings["View/AspectCorrection"].boolean()) width *= display.aspectCorrection;
@ -412,7 +417,7 @@ auto Presentation::resizeWindow() -> void {
uint statusHeight = settings["View/StatusBar"].boolean() ? StatusHeight : 0; uint statusHeight = settings["View/StatusBar"].boolean() ? StatusHeight : 0;
if(emulator) { if(emulator) {
auto display = emulator->displays().first(); auto display = emulator->display();
width = display.width; width = display.width;
height = display.height; height = display.height;
if(settings["View/AspectCorrection"].boolean()) width *= display.aspectCorrection; if(settings["View/AspectCorrection"].boolean()) width *= display.aspectCorrection;

View File

@ -1,13 +1,3 @@
struct AboutWindow : Window {
AboutWindow();
VerticalLayout layout{this};
Canvas canvas{&layout, Size{399, 95}, 15};
HorizontalLayout informationLayout{&layout, Size{~0, 0}};
Label informationLeft{&informationLayout, Size{~0, 0}, 3};
Label informationRight{&informationLayout, Size{~0, 0}};
};
struct Presentation : Window { struct Presentation : Window {
enum : uint { StatusHeight = 24 }; enum : uint { StatusHeight = 24 };
@ -104,5 +94,4 @@ struct Presentation : Window {
Label spacerRight{&statusLayout, Size{8, ~0}, 0}; Label spacerRight{&statusLayout, Size{8, ~0}, 0};
}; };
extern unique_pointer<AboutWindow> aboutWindow;
extern unique_pointer<Presentation> presentation; extern unique_pointer<Presentation> presentation;

View File

@ -50,14 +50,14 @@ auto Program::load(uint id, string name, string type, vector<string> options) ->
return {pathID, option}; return {pathID, option};
} }
auto Program::videoRefresh(uint displayID, const uint32* data, uint pitch, uint width, uint height) -> void { auto Program::videoFrame(const uint32* data, uint pitch, uint width, uint height) -> void {
uint32_t* output; uint32_t* output;
uint length; uint length;
pitch >>= 2; pitch >>= 2;
if(!settings["View/Overscan"].boolean()) { if(!settings["View/Overscan"].boolean()) {
auto display = emulator->displays()[displayID]; auto display = emulator->display();
if(display.type == Emulator::Interface::Display::Type::CRT) { if(display.type == Emulator::Interface::Display::Type::CRT) {
uint overscanHorizontal = settings["View/Overscan/Horizontal"].natural(); uint overscanHorizontal = settings["View/Overscan/Horizontal"].natural();
uint overscanVertical = settings["View/Overscan/Vertical"].natural(); uint overscanVertical = settings["View/Overscan/Vertical"].natural();
@ -92,7 +92,7 @@ auto Program::videoRefresh(uint displayID, const uint32* data, uint pitch, uint
} }
} }
auto Program::audioSample(const double* samples, uint channels) -> void { auto Program::audioFrame(const double* samples, uint channels) -> void {
if(channels == 1) { if(channels == 1) {
double stereo[] = {samples[0], samples[0]}; double stereo[] = {samples[0], samples[0]};
audio->output(stereo); audio->output(stereo);

View File

@ -103,7 +103,6 @@ Program::Program(Arguments arguments) {
new SettingsManager; new SettingsManager;
new CheatDatabase; new CheatDatabase;
new ToolsManager; new ToolsManager;
new AboutWindow;
updateVideoShader(); updateVideoShader();
updateAudioDriver(); updateAudioDriver();

View File

@ -8,8 +8,8 @@ struct Program : Emulator::Platform {
auto path(uint id) -> string override; auto path(uint id) -> string override;
auto open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file override; auto open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file override;
auto load(uint id, string name, string type, vector<string> options = {}) -> Emulator::Platform::Load override; auto load(uint id, string name, string type, vector<string> options = {}) -> Emulator::Platform::Load override;
auto videoRefresh(uint display, const uint32* data, uint pitch, uint width, uint height) -> void override; auto videoFrame(const uint32* data, uint pitch, uint width, uint height) -> void override;
auto audioSample(const double* samples, uint channels) -> void override; auto audioFrame(const double* samples, uint channels) -> void override;
auto inputPoll(uint port, uint device, uint input) -> int16 override; auto inputPoll(uint port, uint device, uint input) -> int16 override;
auto inputRumble(uint port, uint device, uint input, bool enable) -> void override; auto inputRumble(uint port, uint device, uint input, bool enable) -> void override;
auto dipSettings(Markup::Node node) -> uint override; auto dipSettings(Markup::Node node) -> uint override;

View File

@ -7,7 +7,7 @@ Settings settings;
#include "wonderswan-color.cpp" #include "wonderswan-color.cpp"
#include "pocket-challenge-v2.cpp" #include "pocket-challenge-v2.cpp"
auto Interface::displays() -> vector<Display> { auto Interface::display() -> Display {
Display display; Display display;
display.type = Display::Type::LCD; display.type = Display::Type::LCD;
display.colors = 1 << 12; display.colors = 1 << 12;
@ -21,7 +21,7 @@ auto Interface::displays() -> vector<Display> {
swap(display.width, display.height); swap(display.width, display.height);
swap(display.internalWidth, display.internalHeight); swap(display.internalWidth, display.internalHeight);
} }
return {display}; return display;
} }
//todo: the WonderSwan and PocketChallengeV2 interfaces should be generating grayscale shades //todo: the WonderSwan and PocketChallengeV2 interfaces should be generating grayscale shades

View File

@ -20,7 +20,7 @@ struct ID {
}; };
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
auto displays() -> vector<Display> override; auto display() -> Display override;
auto color(uint32 color) -> uint64 override; auto color(uint32 color) -> uint64 override;
auto ports() -> vector<Port> override; auto ports() -> vector<Port> override;

View File

@ -49,7 +49,9 @@ auto MessageDialog::_run() -> string {
Window window; Window window;
VerticalLayout layout{&window}; VerticalLayout layout{&window};
HorizontalLayout messageLayout{&layout, Size{~0, 0}, 5}; HorizontalLayout messageLayout{&layout, Size{~0, 0}, 5};
Canvas messageIcon{&messageLayout, Size{16, 16}, 5}; VerticalLayout messageIconLayout{&messageLayout, Size{16, ~0}, 5};
Canvas messageIcon{&messageIconLayout, Size{16, 16}, 0};
Widget messageIconSpacer{&messageIconLayout, Size{16, ~0}};
Label messageText{&messageLayout, Size{~0, 0}}; Label messageText{&messageLayout, Size{~0, 0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}}; HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Widget controlSpacer{&controlLayout, Size{~0, 0}}; Widget controlSpacer{&controlLayout, Size{~0, 0}};

View File

@ -131,22 +131,22 @@ auto nall::main(Arguments arguments) -> void {
new ImportDialog; new ImportDialog;
new ErrorDialog; new ErrorDialog;
if constexpr(platform() == Platform::MacOS) { #if defined(PLATFORM_MACOS)
Application::Cocoa::onAbout([&] { Application::Cocoa::onAbout([&] {
MessageDialog().setTitle("About icarus").setText({ MessageDialog().setTitle("About icarus").setText({
"icarus\n\n" "icarus\n\n"
"Author: byuu\n" "Author: byuu\n"
"License: GPLv3\n" "License: GPLv3\n"
"Website: https://byuu.org/\n" "Website: https://byuu.org/\n"
}).information(); }).information();
}); });
Application::Cocoa::onPreferences([&] { Application::Cocoa::onPreferences([&] {
scanDialog->settingsButton.doActivate(); scanDialog->settingsButton.doActivate();
}); });
Application::Cocoa::onQuit([&] { Application::Cocoa::onQuit([&] {
Application::quit(); Application::quit();
}); });
} #endif
scanDialog->show(); scanDialog->show();
Application::run(); Application::run();