Skip to content

Commit

Permalink
Merge pull request emu-russia#449 from ogamespec/main
Browse files Browse the repository at this point in the history
Core IO Api
  • Loading branch information
ogamespec authored Aug 24, 2023
2 parents 59b3d10 + 8c1b8d0 commit d2a7506
Show file tree
Hide file tree
Showing 27 changed files with 651 additions and 90 deletions.
2 changes: 1 addition & 1 deletion Breaknes/Breaknes/FormAbout.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Breaknes/Breaknes/FormAbout.resx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
Expand Down
5 changes: 5 additions & 0 deletions Breaknes/BreaksCore/AbstractBoard.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ namespace Breaknes
Board(APUSim::Revision apu_rev, PPUSim::Revision ppu_rev, Mappers::ConnectorType p1);
virtual ~Board();

/// <summary>
/// IO Subsystem
/// </summary>
IO::IOSubsystem* io = nullptr;

/// <summary>
/// Simulate 1 half cycle of the board. The simulation of the signal edge is not supported, this is overkill.
/// </summary>
Expand Down
60 changes: 60 additions & 0 deletions Breaknes/BreaksCore/CoreApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,4 +263,64 @@ extern "C"
board->GetAllCoreDebugInfo(info);
}
}

DLL_EXPORT size_t IOCreateInstance(uint32_t device_id)
{
if (board != nullptr && board->io != nullptr)
{
return board->io->CreateInstance((IO::DeviceID)device_id);
}
}

DLL_EXPORT void IOAttach(size_t port, size_t handle)
{
if (board != nullptr && board->io != nullptr)
{
board->io->Attach(port, handle);
}
}

DLL_EXPORT void IODetach(size_t port, size_t handle)
{
if (board != nullptr && board->io != nullptr)
{
board->io->Detach(port, handle);
}
}

DLL_EXPORT void IOSetState(size_t handle, size_t io_state, uint32_t value)
{
if (board != nullptr && board->io != nullptr)
{
board->io->SetState(handle, io_state, value);
}
}

DLL_EXPORT uint32_t IOGetState(size_t handle, size_t io_state)
{
if (board != nullptr && board->io != nullptr)
{
return board->io->GetState(handle, io_state);
}
}

DLL_EXPORT size_t IOGetNumStates(size_t handle)
{
if (board != nullptr && board->io != nullptr)
{
return board->io->GetNumStates(handle);
}
}

DLL_EXPORT void IOGetStateName(size_t handle, size_t io_state, char* name, size_t name_size)
{
if (board != nullptr && board->io != nullptr)
{
auto state_name = board->io->GetStateName(handle, io_state);
if (state_name.size() < name_size) {
strncpy(name, state_name.c_str(), name_size);
name[state_name.size()] = 0;
}
}
}
};
37 changes: 35 additions & 2 deletions Breaknes/BreaksCore/CoreApi.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// The top-level API for managed applications.

// TBD: The API will be extended to handle I/O devices (controllers, expansion ports)

#pragma once

#if defined(_WINDOWS) && !defined(BREAKS_CORE_STATIC)
Expand Down Expand Up @@ -162,4 +160,39 @@ extern "C"
/// </summary>
/// <param name="info"></param>
DLL_EXPORT void GetAllCoreDebugInfo(M6502Core::DebugInfo* info);

/// <summary>
/// Create an IO instance of the device with the specified DeviceID. Return handle
/// </summary>
DLL_EXPORT size_t IOCreateInstance(uint32_t device_id);

/// <summary>
/// Connect the device to the port.
/// </summary>
DLL_EXPORT void IOAttach(size_t port, size_t handle);

/// <summary>
/// Disconnect the device from the port.
/// </summary>
DLL_EXPORT void IODetach(size_t port, size_t handle);

/// <summary>
/// Set the IOState state of the device. For example, the state of the controller buttons.
/// </summary>
DLL_EXPORT void IOSetState(size_t handle, size_t io_state, uint32_t value);

/// <summary>
/// Get the state of the specified device IOState.
/// </summary>
DLL_EXPORT uint32_t IOGetState(size_t handle, size_t io_state);

/// <summary>
/// Get the number of IO device states. For example, the number of buttons of the controller.
/// </summary>
DLL_EXPORT size_t IOGetNumStates(size_t handle);

/// <summary>
/// Return the IOState name of the device.
/// </summary>
DLL_EXPORT void IOGetStateName(size_t handle, size_t io_state, char* name, size_t name_size);
};
58 changes: 58 additions & 0 deletions Breaknes/BreaksCore/FamicomBoard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ namespace Breaknes
vram = new BaseBoard::SRAM("VRAM", vram_bits);

apu->SetNormalizedOutput(true);

io = new FamicomBoardIO();
}

FamicomBoard::~FamicomBoard()
{
delete io;
delete vram;
delete wram;
delete ppu;
Expand Down Expand Up @@ -75,6 +78,7 @@ namespace Breaknes
// DMX (Bus Master)

// In real CPU in reset mode M2 goes to `Z` state, it does not suit us
// TODO: The pull-up is inside the DMX chip. Soon Famicom will come to disassemble, we will see what is in the chip and make LS139(DMX) properly
Pullup(M2); // HACK

// The demultiplexer stages are mixed up in the Famicom. I'm not sure it makes sense to simulate it so accurately, but let it be
Expand Down Expand Up @@ -212,4 +216,58 @@ namespace Breaknes
*sample = (aux.normalized.a * 0.4f /* 20k resistor */ + aux.normalized.b /* 12k resistor */ + cart_snd.normalized /* levels pls, someone? */) / 3.0f;
}
}

#pragma region "Fami IO"

FamicomBoardIO::FamicomBoardIO() : IO::IOSubsystem()
{
}

FamicomBoardIO::~FamicomBoardIO()
{
}

int FamicomBoardIO::GetPorts()
{
// Only controller ports so far
return 2;
}

void FamicomBoardIO::GetPortSupportedDevices(int port, std::list<IO::DeviceID>& devices)
{
devices.clear();

switch (port)
{
case 0:
devices.push_back(IO::DeviceID::FamiController_1);
break;

case 1:
devices.push_back(IO::DeviceID::FamiController_2);
break;

default:
break;
}
}

void FamicomBoardIO::sim(int port, BaseLogic::TriState inputs[], BaseLogic::TriState outputs[])
{
for (auto it = devices.begin(); it != devices.end(); ++it) {

IO::IOMapped* mapped = *it;

if (mapped->port == port && mapped->handle >= 0) {

// TODO: Assign input signals to the simulated IO device

mapped->device->sim(inputs, outputs);

// TODO: Process the output signals from the device and distribute them across the board
}
}
}

#pragma endregion "Fami IO"
}
15 changes: 11 additions & 4 deletions Breaknes/BreaksCore/FamicomBoard.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@

namespace Breaknes
{
class FamicomBoardIO : public IO::IOSubsystem
{
public:
FamicomBoardIO();
virtual ~FamicomBoardIO();
int GetPorts() override;
void GetPortSupportedDevices(int port, std::list<IO::DeviceID>& devices) override;
void sim(int port, BaseLogic::TriState inputs[], BaseLogic::TriState outputs[]) override;
};

class FamicomBoard : public Board
{
BaseBoard::SRAM* wram = nullptr;
Expand Down Expand Up @@ -55,12 +65,9 @@ namespace Breaknes
BaseLogic::TriState VRAM_nCE = BaseLogic::TriState::X;
BaseLogic::TriState PPU_nA13 = BaseLogic::TriState::X; // To save millions of inverters inside the cartridges

// Famicom Board specific ⚠️
// I/O -- TBD :(

// Famicom Board specific I/O ⚠️
BaseBoard::LS368 P4_IO;
BaseBoard::LS368 P5_IO;

BaseLogic::TriState nOE1 = BaseLogic::TriState::X; // aka nRDP0 from cpu
BaseLogic::TriState nOE2 = BaseLogic::TriState::X; // aka nRDP1 from cpu
BaseLogic::TriState OUT_0 = BaseLogic::TriState::X;
Expand Down
58 changes: 58 additions & 0 deletions Breaknes/BreaksCore/NESBoard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ namespace Breaknes

apu->SetNormalizedOutput(true);

io = new NESBoardIO();

AddBoardMemDescriptors();
AddDebugInfoProviders();
}

NESBoard::~NESBoard()
{
delete io;
delete vram;
delete wram;
delete ppu;
Expand Down Expand Up @@ -80,6 +83,7 @@ namespace Breaknes
// DMX (Bus Master)

// In real CPU in reset mode M2 goes to `Z` state, it does not suit us
// TODO: The pull-up is inside the DMX chip. Soon Famicom will come to disassemble, we will see what is in the chip and make LS139(DMX) properly
Pullup(M2); // HACK

DMX.sim(
Expand Down Expand Up @@ -229,4 +233,58 @@ namespace Breaknes
printf("Write PPU %d=0x%02X, phi2: %d, phi counter: 0x%llx\n", reg_sel, data_bus, apu->GetPHI2(), GetPHICounter());
}
}

#pragma region "NES IO"

NESBoardIO::NESBoardIO() : IO::IOSubsystem()
{
}

NESBoardIO::~NESBoardIO()
{
}

int NESBoardIO::GetPorts()
{
// Only controller ports so far
return 2;
}

void NESBoardIO::GetPortSupportedDevices(int port, std::list<IO::DeviceID>& devices)
{
devices.clear();

switch (port)
{
case 0:
devices.push_back(IO::DeviceID::NESController);
break;

case 1:
devices.push_back(IO::DeviceID::NESController);
break;

default:
break;
}
}

void NESBoardIO::sim(int port, BaseLogic::TriState inputs[], BaseLogic::TriState outputs[])
{
for (auto it = devices.begin(); it != devices.end(); ++it) {

IO::IOMapped* mapped = *it;

if (mapped->port == port && mapped->handle >= 0) {

// TODO: Assign input signals to the simulated IO device

mapped->device->sim(inputs, outputs);

// TODO: Process the output signals from the device and distribute them across the board
}
}
}

#pragma endregion "NES IO"
}
15 changes: 11 additions & 4 deletions Breaknes/BreaksCore/NESBoard.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

namespace Breaknes
{
class NESBoardIO : public IO::IOSubsystem
{
public:
NESBoardIO();
virtual ~NESBoardIO();
int GetPorts() override;
void GetPortSupportedDevices(int port, std::list<IO::DeviceID>& devices) override;
void sim(int port, BaseLogic::TriState inputs[], BaseLogic::TriState outputs[]) override;
};

struct NESBoardDebugInfo
{
uint32_t CLK;
Expand Down Expand Up @@ -60,12 +70,9 @@ namespace Breaknes
BaseLogic::TriState VRAM_nCE = BaseLogic::TriState::X;
BaseLogic::TriState PPU_nA13 = BaseLogic::TriState::X; // To save millions of inverters inside the cartridges

// NES Board specific ⚠️
// I/O -- TBD :(

// NES Board specific I/O ⚠️
BaseBoard::LS368 P4_IO;
BaseBoard::LS368 P5_IO;

BaseLogic::TriState nOE1 = BaseLogic::TriState::X; // aka nRDP0 from cpu
BaseLogic::TriState nOE2 = BaseLogic::TriState::X; // aka nRDP1 from cpu
BaseLogic::TriState OUT_0 = BaseLogic::TriState::X;
Expand Down
5 changes: 5 additions & 0 deletions Breaknes/BreaksCore/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <iostream>
#include <string>
#include <list>
#include <map>
#include <cassert>
#include <memory.h>
#include <cstddef>
Expand Down Expand Up @@ -42,6 +43,10 @@

#include "../../Mappers/Mappers.h"

// IO Subsystem

#include "../../IO/IO.h"

// Boards

#include "RegDumpEmitter.h"
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ add_executable (breaknes
IO/DendyController.cpp
IO/FamiController.cpp
IO/NESController.cpp
IO/UM6582.cpp

Breaknes/BreaksCore/AbstractBoard.cpp
Breaknes/BreaksCore/APUPlayerBoard.cpp
Expand Down
Loading

0 comments on commit d2a7506

Please sign in to comment.