Skip to content

Commit

Permalink
md: various i/o port improvements (#1341)
Browse files Browse the repository at this point in the history
General fixes:
- model data lines separately from output data latches
- update data lines after control register writes
- distinguish between driven and floating data lines
- remove redundant data latch state from devices
- separate host input polling from data line synthesis

6 button/fighting pad fixes:
- reset timeout only on TH 0->1 transitions
- remain in last phase until timeout (don't wrap)
- read back C/B button state along with M/X/Y/Z

Mega mouse:
- remove erroneous thread synchronize on attach which could crash ares

Affected titles:
- Decap Attack (MD)
- Trouble Shooter/Battle Mania (MD)
- WWF Raw (32X)
  • Loading branch information
invertego authored Dec 11, 2023
1 parent b55c501 commit 2950d3f
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 38 deletions.
11 changes: 6 additions & 5 deletions ares/md/controller/control-pad/control-pad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ ControlPad::ControlPad(Node::Port parent) {
start = node->append<Node::Input::Button>("Start");
}

auto ControlPad::readData() -> n8 {
n6 data;

auto ControlPad::poll() -> void {
platform->input(up);
platform->input(down);
platform->input(left);
Expand All @@ -34,6 +32,10 @@ auto ControlPad::readData() -> n8 {
} else if(!xHold) {
xHold = 1, swap(leftLatch, rightLatch);
}
}

auto ControlPad::readData() -> Data {
n6 data;

if(select == 0) {
data.bit(0) = upLatch;
Expand All @@ -51,10 +53,9 @@ auto ControlPad::readData() -> n8 {
}

data = ~data;
return latch << 7 | select << 6 | data;
return {data, 0x3f};
}

auto ControlPad::writeData(n8 data) -> void {
select = data.bit(6);
latch = data.bit(7);
}
4 changes: 2 additions & 2 deletions ares/md/controller/control-pad/control-pad.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ struct ControlPad : Controller {

ControlPad(Node::Port);

auto readData() -> n8 override;
auto poll() -> void override;
auto readData() -> Data override;
auto writeData(n8 data) -> void override;

private:
n1 select = 1;
n1 latch;

b1 yHold;
b1 upLatch;
Expand Down
8 changes: 7 additions & 1 deletion ares/md/controller/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@
struct Controller {
Node::Peripheral node;

struct Data {
n8 value;
n8 mask;
};

virtual ~Controller() = default;

virtual auto readData() -> n8 { return 0xff; }
virtual auto poll() -> void {}
virtual auto readData() -> Data { return {0x7f, 0x7f}; }
virtual auto writeData(n8 data) -> void {}
};

Expand Down
21 changes: 10 additions & 11 deletions ares/md/controller/fighting-pad/fighting-pad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@ FightingPad::~FightingPad() {

auto FightingPad::main() -> void {
if(timeout) {
timeout--;
} else {
counter = 0;
if(!--timeout) counter = 0;
}
Thread::step(1);
Thread::synchronize(cpu);
}

auto FightingPad::readData() -> n8 {
auto FightingPad::poll() -> void {
platform->input(up);
platform->input(down);
platform->input(left);
Expand All @@ -56,7 +54,9 @@ auto FightingPad::readData() -> n8 {
} else if(!xHold) {
xHold = 1, swap(leftLatch, rightLatch);
}
}

auto FightingPad::readData() -> Data {
n6 data;

if(select == 0) {
Expand All @@ -82,29 +82,28 @@ auto FightingPad::readData() -> n8 {
data.bit(1) = downLatch;
data.bit(2) = leftLatch;
data.bit(3) = rightLatch;
data.bit(4) = b->value();
data.bit(5) = c->value();
}

if(counter == 3) {
data.bit(0) = z->value();
data.bit(1) = y->value();
data.bit(2) = x->value();
data.bit(3) = mode->value();
data.bit(4,5) = 0;
}

data.bit(4) = b->value();
data.bit(5) = c->value();
}

data = ~data;
return latch << 7 | select << 6 | data;
return {data, 0x3f};
}

auto FightingPad::writeData(n8 data) -> void {
if(!select && data.bit(6)) { //0->1 transition
if(++counter == 5) counter = 0;
if(counter < 4) ++counter;
timeout = 1600; //~1.6ms
}

select = data.bit(6);
latch = data.bit(7);
timeout = 1600; //~1.6ms
}
4 changes: 2 additions & 2 deletions ares/md/controller/fighting-pad/fighting-pad.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ struct FightingPad : Controller, Thread {
FightingPad(Node::Port);
~FightingPad();
auto main() -> void;
auto readData() -> n8 override;
auto poll() -> void override;
auto readData() -> Data override;
auto writeData(n8 data) -> void override;

private:
n1 select = 1;
n1 latch;
n3 counter;
n32 timeout;

Expand Down
13 changes: 6 additions & 7 deletions ares/md/controller/mega-mouse/mega-mouse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ MegaMouse::MegaMouse(Node::Port parent) {
t_data = 10 * timerfreq / 1000000;

Thread::create(timerfreq, {&MegaMouse::main, this});
Thread::synchronize(cpu);
}

MegaMouse::~MegaMouse() {
Expand Down Expand Up @@ -68,7 +67,7 @@ auto MegaMouse::main() -> void {
Thread::synchronize(cpu);
}

auto MegaMouse::readData() -> n8 {
auto MegaMouse::readData() -> Data {
n8 data;

if (th) {
Expand All @@ -81,14 +80,15 @@ auto MegaMouse::readData() -> n8 {
}

data.bit(4) = tl;
data.bit(5) = tr;
data.bit(6) = th;
data.bit(7) = latch;

return data;
return {data, 0x1f};
}

auto MegaMouse::writeData(n8 data) -> void {
//todo: this check wouldn't be necessary if the logic below was correct.
//this function should only respond to level changes.
if(tr == data.bit(5) && th == data.bit(6)) return;

// Falling TH
if (!data.bit(6) && th) {
// When TH falls low, make sure the second nibble is driven. The
Expand Down Expand Up @@ -142,6 +142,5 @@ auto MegaMouse::writeData(n8 data) -> void {
timeout = t_handshake;
}

latch = data.bit(7);
th = data.bit(6);
}
3 changes: 1 addition & 2 deletions ares/md/controller/mega-mouse/mega-mouse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ struct MegaMouse : Controller, Thread {
~MegaMouse();

auto main() -> void;
auto readData() -> n8 override;
auto readData() -> Data override;
auto writeData(n8 data) -> void override;

private:
n1 th = 1;
n1 tr = 1;
n1 tl = 1;
n1 latch;
n8 index = 0;
n4 status[10];
s16 maxspeed = 255;
Expand Down
12 changes: 12 additions & 0 deletions ares/md/controller/port.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,21 @@ auto ControllerPort::allocate(string name) -> Node::Peripheral {
return {};
}

auto ControllerPort::update() -> void {
auto [inputData, inputMask] = device ? device->readData() : Controller::Data{0x7f, 0x7f};
n8 outputMask = 0x80 | control;
n8 prevLines = dataLines;
dataLines = inputData & inputMask | dataLines & ~inputMask;
dataLines = dataLatch & outputMask | dataLines & ~outputMask;
//todo: gradually pull up floating lines
if(device && prevLines != dataLines) return device->writeData(dataLines);
}

auto ControllerPort::power(bool reset) -> void {
if(!reset) {
control = 0x00;
dataLatch = 0x7f;
dataLines = 0x7f;
serialControl = 0x00;
serialTxBuffer = 0xff;
serialRxBuffer = 0x00;
Expand All @@ -42,6 +53,7 @@ auto ControllerPort::power(bool reset) -> void {
auto ControllerPort::serialize(serializer& s) -> void {
s(control);
s(dataLatch);
s(dataLines);
s(serialControl);
s(serialTxBuffer);
s(serialRxBuffer);
Expand Down
15 changes: 8 additions & 7 deletions ares/md/controller/port.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ struct ControllerPort {
auto connect(Node::Peripheral) -> void;
auto disconnect() -> void { device.reset(); }

auto update() -> void;

auto readControl() -> n8 { return control; }
auto writeControl(n8 data) -> void { control = data; }
auto writeControl(n8 data) -> void { control = data; update(); }

auto readData() -> n8 {
n8 data = device ? device->readData() : n8(~0);
return dataLatch = dataLatch & (0x80 | control) | data & ~(0x80 | control);
}
auto writeData(n8 data) -> void {
dataLatch = dataLatch & ~(0x80 | control) | data & (0x80 | control);
if(device) return device->writeData(dataLatch);
if(device) device->poll();
update();
return dataLines;
}
auto writeData(n8 data) -> void { dataLatch = data; update(); }

// TODO: Implement working serial transfers. This code is mostly placeholder.

Expand Down Expand Up @@ -57,6 +57,7 @@ struct ControllerPort {
const string name;
n8 control; //d0-d6 = PC0-PC6 (0 = input; 1 = output); d7 = TH-INT enable
n8 dataLatch;
n8 dataLines;
n8 serialControl;
n8 serialTxBuffer;
n8 serialRxBuffer;
Expand Down
2 changes: 1 addition & 1 deletion ares/md/system/serialization.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
static const string SerializerVersion = "v133.1";
static const string SerializerVersion = "v134";

auto System::serialize(bool synchronize) -> serializer {
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);
Expand Down

0 comments on commit 2950d3f

Please sign in to comment.