Skip to content

Commit

Permalink
Merge pull request emu-russia#460 from ogamespec/main
Browse files Browse the repository at this point in the history
IO Subsystem wip
  • Loading branch information
ogamespec authored Sep 1, 2023
2 parents c8804db + 94522e7 commit 87c0f7a
Show file tree
Hide file tree
Showing 21 changed files with 316 additions and 32 deletions.
54 changes: 52 additions & 2 deletions Breaknes/Breaknes/Build/IOConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
"device_id": 1,
"name": "P1",
"attached": [
"HVC-CPU-01"
{
"board": "HVC-CPU-01",
"port": 0
}
],
"bindings": [
{
Expand All @@ -30,7 +33,10 @@
"device_id": 65539,
"name": "V1",
"attached": [
"NES-001 (PCB rev. -01 to -04)"
{
"board": "NES-001 (PCB rev. -01 to -04)",
"port": 0
}
],
"bindings": [
{
Expand Down Expand Up @@ -66,6 +72,50 @@
"binding": "NES_A"
}
]
},
{
"device_id": 65537,
"name": "Fami1",
"attached": [
{
"board": "HVC-CPU-01",
"port": 0
}
],
"bindings": [
{
"actuator_id": 0,
"binding": "Fami1_Up"
},
{
"actuator_id": 1,
"binding": "Fami1_Down"
},
{
"actuator_id": 2,
"binding": "Fami1_Left"
},
{
"actuator_id": 3,
"binding": "Fami1_Right"
},
{
"actuator_id": 4,
"binding": "Fami1_Select"
},
{
"actuator_id": 5,
"binding": "Fami1_Start"
},
{
"actuator_id": 6,
"binding": "Fami1_B"
},
{
"actuator_id": 7,
"binding": "Fami1_A"
}
]
}
]
}
33 changes: 27 additions & 6 deletions Breaknes/Breaknes/FormIOConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,18 @@ private void PopulateConnectionStatus(IOConfigDevice device)
{
for (int i = 0; i < checkedListBox1.Items.Count; i++)
{
int pos = Array.IndexOf(device.attached, checkedListBox1.Items[i].ToString());
checkedListBox1.SetItemCheckState(i, pos >= 0 ? CheckState.Checked : CheckState.Unchecked);
bool attached = false;

foreach (var port in device.attached)
{
if (port.board == checkedListBox1.Items[i].ToString())
{
attached = true;
break;
}
}

checkedListBox1.SetItemCheckState(i, attached ? CheckState.Checked : CheckState.Unchecked);
}
checkedListBox1.Tag = device;
}
Expand All @@ -181,20 +191,31 @@ private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
if (device == null)
return;

List<string> board_list = device.attached.ToList();
List<IOConfigPort> attached = device.attached.ToList();

string board_name = checkedListBox1.Items[e.Index].ToString();

if (e.CurrentValue == CheckState.Checked)
{
board_list.Remove(board_name);
List<IOConfigPort> new_board_list = new();

foreach (var port in attached)
{
if (port.board != board_name)
new_board_list.Add(port);
}

attached = new_board_list;
}
else
{
board_list.Add(board_name);
IOConfigPort port = new();
port.board = board_name;
port.port = 0; // TODO
attached.Add(port);
}

device.attached = board_list.ToArray();
device.attached = attached.ToArray();
}

private void FormIOConfig_KeyDown(object sender, KeyEventArgs e)
Expand Down
8 changes: 7 additions & 1 deletion Breaknes/Breaknes/IOConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ public class IOConfigInfo
public string descr = "This JSON contains a list of IO devices and their Attach/Detach statuses with Motherboard and Bindings with Input API.";
}

public class IOConfigPort
{
public string board = "";
public int port = -1;
}

public class IOConfigDevice
{
public UInt32 device_id = 0;
public string name = "";
public string[] attached = Array.Empty<string>();
public IOConfigPort[] attached = Array.Empty<IOConfigPort>();
public IOConfigBinding[] bindings = Array.Empty<IOConfigBinding>();
}

Expand Down
10 changes: 9 additions & 1 deletion Breaknes/Breaknes/IOProcessing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace Breaknes
public class AttachedDevice
{
public int handle = -1;
public int port = -1;
public IOConfigDevice device = new();
public object? opaque = null;
}
Expand Down Expand Up @@ -133,11 +134,17 @@ public void AttachDevicesToBoard(string board_name)

foreach (var device in config.devices)
{
if (device.attached.Contains(board_name))
foreach (var port in device.attached)
{
if (port.board != board_name)
continue;
int port_num = port.port;

AttachedDevice attached_device = new();
attached_device.device = device;
attached_device.port = port_num;
attached_device.handle = BreaksCore.IOCreateInstance(device.device_id);
BreaksCore.IOAttach(port_num, attached_device.handle);

// If a virtual device is connected, a modeless dialog must be created

Expand Down Expand Up @@ -199,6 +206,7 @@ public void DetachDevicesFromBoard()
}
}

BreaksCore.IODetach(device.port, device.handle);
BreaksCore.IODisposeInstance(device.handle);
}
}
Expand Down
35 changes: 25 additions & 10 deletions Breaknes/BreaksCore/FamicomBoard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ namespace Breaknes
apu->SetNormalizedOutput(true);

io = new FamicomBoardIO(this);

// Set safe signal values for the IO subsystem (until Expansion Port is implemented)
for (int i = 0; i < 4; i++) {
p2_4017_data[i] = TriState::Z;
}
p2_4016_data = TriState::Z;
}

FamicomBoard::~FamicomBoard()
Expand Down Expand Up @@ -71,7 +77,13 @@ namespace Breaknes
nRDP1 = outputs[(size_t)APUSim::APU_Output::n_IN1];
OUT_0 = outputs[(size_t)APUSim::APU_Output::OUT_0];
OUT_1 = outputs[(size_t)APUSim::APU_Output::OUT_1];
OUT_2 = outputs[(size_t)APUSim::APU_Output::OUT_0];
OUT_2 = outputs[(size_t)APUSim::APU_Output::OUT_2];

// IO

if (io_enabled) {
IOBinding();
}

// pullup (PPU_A[13]); -- wtf?
// no pullup on R/W -- wtf?
Expand Down Expand Up @@ -183,10 +195,6 @@ namespace Breaknes
WRAM_Addr = addr_bus & (wram_size - 1);
wram->sim(WRAM_nCE, CPU_RnW, TriState::Zero, &WRAM_Addr, &data_bus, data_bus_dirty);

// IO

IOBinding();

// Tick

CLK = NOT(CLK);
Expand Down Expand Up @@ -233,11 +241,6 @@ namespace Breaknes

void FamicomBoard::IOBinding()
{
// Quick check
bool any_io_port_active = nRDP0 == TriState::Zero || nRDP1 == TriState::Zero || OUT_0 == TriState::One;
if (!any_io_port_active)
return;

// First you need to simulate 368s in the direction CPU->Ports

p4_inputs[(size_t)BaseBoard::LS368_Input::n_G1] = nRDP0;
Expand Down Expand Up @@ -333,6 +336,18 @@ namespace Breaknes
return 2;
}

std::string FamicomBoardIO::GetPortName(int port)
{
switch (port)
{
case 0: return "Famicom Controller Port 1";
case 1: return "Famicom Controller Port 2";
default:
break;
}
return "";
}

void FamicomBoardIO::GetPortSupportedDevices(int port, std::list<IO::DeviceID>& devices)
{
devices.clear();
Expand Down
1 change: 1 addition & 0 deletions Breaknes/BreaksCore/FamicomBoard.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace Breaknes
FamicomBoardIO(FamicomBoard *board);
virtual ~FamicomBoardIO();
int GetPorts() override;
std::string GetPortName(int port) override;
void GetPortSupportedDevices(int port, std::list<IO::DeviceID>& devices) override;
void sim(int port) override;
};
Expand Down
37 changes: 26 additions & 11 deletions Breaknes/BreaksCore/NESBoard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ namespace Breaknes

io = new NESBoardIO(this);

// Set safe signal values for the IO subsystem (until Expansion Port is implemented)
for (int i = 0; i < 5; i++) {
p4016_data[i] = TriState::Z;
p4017_data[i] = TriState::Z;
}

AddBoardMemDescriptors();
AddDebugInfoProviders();
}
Expand Down Expand Up @@ -70,12 +76,18 @@ namespace Breaknes
nRDP1 = outputs[(size_t)APUSim::APU_Output::n_IN1];
OUT_0 = outputs[(size_t)APUSim::APU_Output::OUT_0];
OUT_1 = outputs[(size_t)APUSim::APU_Output::OUT_1];
OUT_2 = outputs[(size_t)APUSim::APU_Output::OUT_0];
OUT_2 = outputs[(size_t)APUSim::APU_Output::OUT_2];

Pullup(nRDP0);
Pullup(nRDP1);
Pullup(OUT_0);

// IO

if (io_enabled) {
IOBinding();
}

// pullup (PPU_A[13]); -- wtf?
// no pullup on R/W -- wtf?
Pullup(CPU_RnW);
Expand Down Expand Up @@ -107,7 +119,7 @@ namespace Breaknes
TriState ppu_outputs[(size_t)PPUSim::OutputPad::Max]{};

ppu_inputs[(size_t)PPUSim::InputPad::CLK] = CLK;
ppu_inputs[(size_t)PPUSim::InputPad::n_RES] = pendingReset_PPU ? TriState::Zero : TriState::One;; // NES Board specific ⚠️
ppu_inputs[(size_t)PPUSim::InputPad::n_RES] = pendingReset_PPU ? TriState::Zero : TriState::One; // NES Board specific ⚠️
ppu_inputs[(size_t)PPUSim::InputPad::RnW] = CPU_RnW;
ppu_inputs[(size_t)PPUSim::InputPad::RS0] = FromByte((addr_bus >> 0) & 1);
ppu_inputs[(size_t)PPUSim::InputPad::RS1] = FromByte((addr_bus >> 1) & 1);
Expand Down Expand Up @@ -187,10 +199,6 @@ namespace Breaknes
WRAM_Addr = addr_bus & (wram_size - 1);
wram->sim(WRAM_nCE, CPU_RnW, TriState::Zero, &WRAM_Addr, &data_bus, data_bus_dirty);

// IO

IOBinding();

// Tick

CLK = NOT(CLK);
Expand Down Expand Up @@ -242,11 +250,6 @@ namespace Breaknes

void NESBoard::IOBinding()
{
// Quick check
bool any_io_port_active = nRDP0 == TriState::Zero || nRDP1 == TriState::Zero || OUT_0 == TriState::One;
if (!any_io_port_active)
return;

// There is no need to simulate 368s on input, they only work in the Port->CPU direction

// Call the IO subsystem and it will simulate the controllers and other I/O devices if they are connected
Expand Down Expand Up @@ -332,6 +335,18 @@ namespace Breaknes
return 2;
}

std::string NESBoardIO::GetPortName(int port)
{
switch (port)
{
case 0: return "NES Controller Port 1";
case 1: return "NES Controller Port 2";
default:
break;
}
return "";
}

void NESBoardIO::GetPortSupportedDevices(int port, std::list<IO::DeviceID>& devices)
{
devices.clear();
Expand Down
1 change: 1 addition & 0 deletions Breaknes/BreaksCore/NESBoard.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Breaknes
NESBoardIO(NESBoard *board);
virtual ~NESBoardIO();
int GetPorts() override;
std::string GetPortName(int port) override;
void GetPortSupportedDevices(int port, std::list<IO::DeviceID>& devices) override;
void sim(int port) override;
};
Expand Down
8 changes: 8 additions & 0 deletions BreaksAPU/APUSim/pads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,19 @@ namespace APUSim
{
from_pad = NOT(in_latch.nget());
}
else
{
from_pad = TriState::Z;
}

if (NOT(rd) == TriState::One)
{
pad_out = NOT(NOR(out_latch.get(), rd));
}
else
{
pad_out = TriState::Z;
}
}

void BIDIR::sim_Input(TriState pad_in, TriState& from_pad, TriState rd)
Expand Down
2 changes: 2 additions & 0 deletions IO/CD4021.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ namespace IO
BaseLogic::TriState PAR_SER,
BaseLogic::TriState SER_IN, uint8_t PAR_IN,
BaseLogic::TriState &Q5, BaseLogic::TriState& Q6, BaseLogic::TriState& Q7 );

uint8_t get() { return dff; }
};
}
Loading

0 comments on commit 87c0f7a

Please sign in to comment.