-
Notifications
You must be signed in to change notification settings - Fork 138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Preliminary support for Aleck64 #1758
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
03bf626
mame2bml: print list of drivers used to generate bml
LukeUsher 99fc864
arcade: show machine type in game browser
LukeUsher 66759f6
arcade: import aleck64 romlist
LukeUsher bf0e8ce
mia: add support for aleck64 arcade roms
LukeUsher 8fb9eee
arcade: update database
LukeUsher 2ce2693
n64: preliminary support for aleck64 arcade system
LukeUsher 83b2eb0
cleanup/debug print removal
LukeUsher 5472723
aleck64: add support for Eleven Beat
LukeUsher a750e03
aleck64: fix unity builds
LukeUsher 3e98b38
aleck64: fix legacy build
LukeUsher af27b7c
aleck64: set n64 core options correctly
LukeUsher 394ba63
aleck64: add configs for all games that don't need special hardware
LukeUsher d6066e9
arcade: fix a crash when running multiple arcade games in one session
LukeUsher 74fff88
arcade: resolve parent relationships when loading arcade roms
LukeUsher 10408dd
mame2bml: only write a parent attribute if the game has a parent
LukeUsher 281370e
aleck64: update CMakeLists.txt
LukeUsher a6d15a2
aleck64: mahjong input support (fixes the two Hi Pai games)
LukeUsher 9c0675c
Apply suggestions from code review
LukeUsher d0bd56d
aleck64: fix build after merging changes
LukeUsher d1568e7
aleck64: swap prints for debug()
LukeUsher e80bc16
aleck64: alignment/formatting
LukeUsher 82a805c
aleck64: reduce duplication, partial support for mtetrisc
LukeUsher 11f73fa
aleck64: add serialization
LukeUsher a2a72e3
fix build after rebase
LukeUsher File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#include <n64/n64.hpp> | ||
|
||
namespace ares::Nintendo64 { | ||
Aleck64 aleck64; | ||
|
||
#include "io.cpp" | ||
#include "controls.cpp" | ||
#include "debugger.cpp" | ||
#include "vdp.cpp" | ||
#include "serialization.cpp" | ||
|
||
#include "game-config/11beat.hpp" | ||
#include "game-config/starsldr.hpp" | ||
#include "game-config/doncdoon.hpp" | ||
#include "game-config/kurufev.hpp" | ||
#include "game-config/mayjin3.hpp" | ||
#include "game-config/vivdolls.hpp" | ||
#include "game-config/twrshaft.hpp" | ||
#include "game-config/hipai.hpp" | ||
#include "game-config/hipai2.hpp" | ||
#include "game-config/srmvs.hpp" | ||
#include "game-config/mtetrisc.hpp" | ||
|
||
auto Aleck64::load(Node::Object parent) -> void { | ||
sdram.allocate(4_MiB); | ||
vram.allocate(4_KiB); | ||
pram.allocate(4_KiB); | ||
controls.load(parent); | ||
gameConfig.reset(); | ||
dipSwitchNode = parent->append<Node::Object>("DIP Switches"); | ||
|
||
debugger.load(parent); | ||
} | ||
|
||
auto Aleck64::unload() -> void { | ||
sdram.reset(); | ||
debugger.unload(); | ||
} | ||
|
||
auto Aleck64::save() -> void { | ||
|
||
} | ||
|
||
auto Aleck64::power(bool reset) -> void { | ||
if(!reset) { | ||
dipSwitch[0] = 0xffff'ffff; | ||
dipSwitch[1] = 0xffff'ffff; | ||
|
||
//NOTE: We can't do this at 'load' time because cartridges are not attached yet... | ||
auto name = cartridge.pak->attribute("name"); | ||
|
||
if(name == "11beat" ) gameConfig = new _11beat(); | ||
if(name == "starsldr") gameConfig = new starsldr(); | ||
if(name == "doncdoon") gameConfig = new doncdoon(); | ||
if(name == "kurufev" ) gameConfig = new kurufev(); | ||
if(name == "mayjin3" ) gameConfig = new mayjin3(); | ||
if(name == "vivdolls") gameConfig = new vivdolls(); | ||
if(name == "twrshaft") gameConfig = new twrshaft(); | ||
if(name == "hipai" ) gameConfig = new hipai(); | ||
if(name == "hipai2" ) gameConfig = new hipai2(); | ||
if(name == "srmvs" ) gameConfig = new srmvs(); | ||
if(name == "srmvsa" ) gameConfig = new srmvs(); | ||
if(name == "mtetrisc") gameConfig = new mtetrisc(); | ||
if(!gameConfig) gameConfig = new GameConfig(); //Fallback to default implementation | ||
|
||
gameConfig->dipSwitches(dipSwitchNode); | ||
|
||
sdram.fill(); | ||
vram.fill(); | ||
pram.fill(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
struct Aleck64 { | ||
Node::Object dipSwitchNode; | ||
enum BoardType { E90, E92 }; | ||
|
||
struct Writable : public Memory::Writable { | ||
Aleck64& self; | ||
|
||
Writable(Aleck64& self) : self(self) {} | ||
|
||
template<u32 Size> | ||
auto writeBurst(u32 address, u32 *value, const char *peripheral) -> void { | ||
address = address & 0x00ff'ffff; | ||
if(address >= size) return; | ||
Memory::Writable::write<Word>(address | 0x00, value[0]); | ||
Memory::Writable::write<Word>(address | 0x04, value[1]); | ||
Memory::Writable::write<Word>(address | 0x08, value[2]); | ||
Memory::Writable::write<Word>(address | 0x0c, value[3]); | ||
if(Size == ICache) { | ||
Memory::Writable::write<Word>(address | 0x10, value[4]); | ||
Memory::Writable::write<Word>(address | 0x14, value[5]); | ||
Memory::Writable::write<Word>(address | 0x18, value[6]); | ||
Memory::Writable::write<Word>(address | 0x1c, value[7]); | ||
} | ||
} | ||
|
||
template<u32 Size> | ||
auto readBurst(u32 address, u32 *value, const char *peripheral) -> void { | ||
address = address & 0x00ff'ffff; | ||
if(address >= size) { | ||
value[0] = value[1] = value[2] = value[3] = 0; | ||
if(Size == ICache) | ||
value[4] = value[5] = value[6] = value[7] = 0; | ||
return; | ||
} | ||
value[0] = Memory::Writable::read<Word>(address | 0x00); | ||
value[1] = Memory::Writable::read<Word>(address | 0x04); | ||
value[2] = Memory::Writable::read<Word>(address | 0x08); | ||
value[3] = Memory::Writable::read<Word>(address | 0x0c); | ||
if(Size == ICache) { | ||
value[4] = Memory::Writable::read<Word>(address | 0x10); | ||
value[5] = Memory::Writable::read<Word>(address | 0x14); | ||
value[6] = Memory::Writable::read<Word>(address | 0x18); | ||
value[7] = Memory::Writable::read<Word>(address | 0x1c); | ||
} | ||
} | ||
|
||
} sdram{*this}; | ||
|
||
Memory::Writable vram; | ||
Memory::Writable pram; | ||
|
||
struct Debugger { | ||
Node::Object parent; | ||
//debugger.cpp | ||
auto load(Node::Object) -> void; | ||
auto unload() -> void; | ||
|
||
struct Memory { | ||
Node::Debugger::Memory sdram; | ||
Node::Debugger::Memory vram; | ||
Node::Debugger::Memory pram; | ||
} memory; | ||
} debugger; | ||
|
||
auto load(Node::Object) -> void; | ||
auto unload() -> void; | ||
auto power(bool reset) -> void; | ||
auto save() -> void; | ||
|
||
template<u32 Size> | ||
auto formatRead(u32 address, u32 data) -> u32 { | ||
if constexpr(Size == Byte) {; | ||
switch(address & 3) { | ||
case 0: return data >> 24; | ||
case 1: return data >> 16; | ||
case 2: return data >> 8; | ||
case 3: return data >> 0; | ||
} | ||
} | ||
if constexpr(Size == Half) { | ||
switch(address & 2) { | ||
case 0: return data >> 16; | ||
case 2: return data >> 0; | ||
} | ||
} | ||
if constexpr(Size == Word) { | ||
return data; | ||
} | ||
|
||
unreachable; | ||
} | ||
|
||
template<u32 Size> auto read(u32 address, Thread& thread) -> u32 { | ||
if(address <= 0xc07f'ffff) { | ||
return sdram.read<Size>(address & 0x00ff'ffff); | ||
} | ||
|
||
controls.poll(); | ||
if(address <= 0xc080'0fff) { | ||
n32 value = 0xffff'ffff; | ||
|
||
switch (address & 0xffff'fffc) { | ||
case 0xc080'0000: return formatRead<Size>(address, readPort1()); | ||
case 0xc080'0004: return formatRead<Size>(address, readPort2()); | ||
case 0xc080'0008: return formatRead<Size>(address, readPort3()); | ||
case 0xc080'0100: return formatRead<Size>(address, readPort4()); | ||
} | ||
} | ||
|
||
if(gameConfig->type() == BoardType::E90) { | ||
if(address >= 0xd000'0000 && address <= 0xd000'0fff) return vram.read<Size>(address & 0x0000'0fff); | ||
if(address >= 0xd001'0000 && address <= 0xd001'0fff) return pram.read<Size>(address & 0x0000'0fff); | ||
if(address >= 0xd003'0000 && address <= 0xd003'001f) return formatRead<Size>(address, vdp.readWord(address & 0x0000'001f)); | ||
} else if(gameConfig->type() == BoardType::E92) { | ||
if(address >= 0xd080'0000 && address <= 0xd080'0fff) return vram.read<Size>(address & 0x0000'0fff); | ||
if(address >= 0xd080'1000 && address <= 0xd080'1fff) return pram.read<Size>(address & 0x0000'0fff); | ||
if(address >= 0xd080'2000 && address <= 0xd080'201f) return formatRead<Size>(address, vdp.readWord(address & 0x0000'001f)); | ||
} | ||
|
||
debug(unusual, "[Aleck64::read] Unmapped address: 0x", hex(address, 8L)); | ||
return 0xffffffff; | ||
} | ||
|
||
template<u32 Size> auto write(u32 address, u32 data, Thread& thread) -> void { | ||
if(address <= 0xc07f'ffff) { | ||
return sdram.write<Size>(address & 0x00ff'ffff, data); | ||
} | ||
|
||
if(address <= 0xc080'0fff) { | ||
switch (address & 0xffff'fffc) { | ||
case 0xc080'0008: return writePort3(data); | ||
case 0xc080'0100: return writePort4(data); | ||
} | ||
} | ||
|
||
if(gameConfig->type() == BoardType::E90) { | ||
if(address >= 0xd000'0000 && address <= 0xd000'0fff) return vram.write<Size>(address & 0x0000'0fff, data); | ||
if(address >= 0xd001'0000 && address <= 0xd001'0fff) return pram.write<Size>(address & 0x0000'0fff, data); | ||
if(address >= 0xd003'0000 && address <= 0xd003'001f) return vdp.writeWord (address & 0x0000'001f, data); | ||
} else if(gameConfig->type() == BoardType::E92) { | ||
if(address >= 0xd080'0000 && address <= 0xd080'0fff) return vram.write<Size>(address & 0x0000'0fff, data); | ||
if(address >= 0xd080'1000 && address <= 0xd080'1fff) return pram.write<Size>(address & 0x0000'0fff, data); | ||
if(address >= 0xd080'2000 && address <= 0xd080'201f) return vdp.writeWord (address & 0x0000'001f, data); | ||
} | ||
|
||
debug(unusual, "[Aleck64::write] ", hex(address, 8L), " = ", hex(data, 8L)); | ||
} | ||
|
||
//io.cpp | ||
auto readPort1() -> u32; | ||
auto readPort2() -> u32; | ||
auto readPort3() -> u32; | ||
auto readPort4() -> u32; | ||
auto writePort3(n32 data) -> void; | ||
auto writePort4(n32 data) -> void; | ||
|
||
//serialization.cpp | ||
auto serialize(serializer&) -> void; | ||
|
||
struct Controls { | ||
Aleck64& self; | ||
Node::Object node; | ||
|
||
Node::Input::Button service; | ||
Node::Input::Button test; | ||
|
||
Node::Input::Axis p1x; | ||
Node::Input::Axis p1y; | ||
Node::Input::Button p1up; | ||
Node::Input::Button p1down; | ||
Node::Input::Button p1left; | ||
Node::Input::Button p1right; | ||
Node::Input::Button p1[9]; | ||
Node::Input::Button p1start; | ||
Node::Input::Button p1coin; | ||
|
||
Node::Input::Axis p2x; | ||
Node::Input::Axis p2y; | ||
Node::Input::Button p2up; | ||
Node::Input::Button p2down; | ||
Node::Input::Button p2left; | ||
Node::Input::Button p2right; | ||
Node::Input::Button p2[9]; | ||
Node::Input::Button p2start; | ||
Node::Input::Button p2coin; | ||
|
||
Node::Input::Button mahjongA; | ||
Node::Input::Button mahjongB; | ||
Node::Input::Button mahjongC; | ||
Node::Input::Button mahjongD; | ||
Node::Input::Button mahjongE; | ||
Node::Input::Button mahjongF; | ||
Node::Input::Button mahjongG; | ||
Node::Input::Button mahjongH; | ||
Node::Input::Button mahjongI; | ||
Node::Input::Button mahjongJ; | ||
Node::Input::Button mahjongK; | ||
Node::Input::Button mahjongL; | ||
Node::Input::Button mahjongM; | ||
Node::Input::Button mahjongN; | ||
Node::Input::Button mahjongKan; | ||
Node::Input::Button mahjongPon; | ||
Node::Input::Button mahjongChi; | ||
Node::Input::Button mahjongReach; | ||
Node::Input::Button mahjongRon; | ||
|
||
//controls.cpp | ||
auto load(Node::Object) -> void; | ||
auto poll() -> void; | ||
|
||
auto controllerButton(int playerIndex, string button) -> bool; | ||
auto controllerAxis(int playerIndex, string axis) -> s64; | ||
auto mahjong(n8 row) -> n8; | ||
|
||
} controls{*this}; | ||
|
||
struct VDP { | ||
auto readWord(u32 address) -> u32; | ||
auto writeWord(u32 address, n32 data) -> void; | ||
auto render(Node::Video::Screen screen) -> void; | ||
|
||
struct IO { | ||
n1 enable; | ||
} io; | ||
} vdp; | ||
|
||
n8 dipSwitch[2]; | ||
|
||
struct GameConfig { | ||
virtual ~GameConfig() = default; | ||
virtual auto type() -> BoardType { return BoardType::E92; } | ||
virtual auto dpadDisabled() -> n1 { return 0; } | ||
virtual auto dipSwitches(Node::Object parent) -> void {}; | ||
virtual auto readExpansionPort() -> u32 { return 0xffff'ffff; } | ||
virtual auto writeExpansionPort(n32 data) -> void {}; | ||
}; | ||
|
||
shared_pointer<GameConfig> gameConfig; | ||
}; | ||
|
||
extern Aleck64 aleck64; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we maybe ignore reads from 0x8000'0000 to 0xc000'000?