Skip to content

Commit 5e4f15e

Browse files
neilberkmanclaude
andcommitted
[#877] Bus: Set IO_MEM_EXECUTABLE_IO for all non-IMapped peripherals
Previously, only ArrayMemory peripherals had the IO_MEM_EXECUTABLE_IO flag set, allowing instruction fetch via I/O callbacks. Any other non-IMapped peripheral (e.g. dynamically compiled C# peripherals) would trigger cpu_abort when the CPU tried to execute code from their address range. Generalize the check from `peripheral is ArrayMemory` to `!(peripheral is IMapped)` in three places: - SystemBus.RegisterInner: set flag when peripheral is first registered - SystemBus.MoveRegistrationWithinContext: preserve flag on re-registration - Machine.PostCreationActions: set flag for peripherals registered before CPU Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3a50186 commit 5e4f15e

File tree

2 files changed

+14
-3
lines changed

2 files changed

+14
-3
lines changed

src/Emulator/Main/Core/Machine.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,10 +1027,11 @@ public void PostCreationActions()
10271027
}
10281028
}
10291029

1030-
// Register io_executable flags for all ArrayMemory peripherals
1030+
// Register io_executable flags for all non-IMapped peripherals so that
1031+
// instruction fetches from them go through I/O callbacks instead of aborting.
10311032
foreach(var context in SystemBus.GetAllContextKeys())
10321033
{
1033-
foreach(var registration in SystemBus.GetRegistrationsForPeripheralType<Peripherals.Memory.ArrayMemory>(context))
1034+
foreach(var registration in SystemBus.GetRegistrationsForPeripheralType<IBusPeripheral>(context).Where(r => !(r.Peripheral is IMapped)))
10341035
{
10351036
var range = registration.RegistrationPoint.Range;
10361037
var perCore = registration.RegistrationPoint.Initiator;

src/Emulator/Main/Peripherals/Bus/SystemBus.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ public void MoveRegistrationWithinContext(IBusPeripheral peripheral, BusRangeReg
12601260
AddMappingsForPeripheral(peripheral, newRegistration, context);
12611261
}
12621262

1263-
if(peripheral is ArrayMemory)
1263+
if(!(peripheral is IMapped))
12641264
{
12651265
foreach(var cpu in GetCPUsForContext<ICPUWithMappedMemory>(context))
12661266
{
@@ -2054,6 +2054,16 @@ private void RegisterInner(IBusPeripheral peripheral, PeripheralAccessMethods me
20542054
});
20552055
// let's add new mappings
20562056
AddMappingsForPeripheral(peripheral, registrationPoint, context);
2057+
// For non-IMapped peripherals, mark the range as executable I/O so that
2058+
// instruction fetches go through I/O callbacks instead of causing cpu_abort.
2059+
if(!(peripheral is IMapped))
2060+
{
2061+
foreach(var cpu in GetCPUsForContext<ICPUWithMappedMemory>(context))
2062+
{
2063+
var range = registrationPoint.Range;
2064+
cpu.RegisterAccessFlags(range.StartAddress, range.Size, isIoMemory: true);
2065+
}
2066+
}
20572067
// After adding new mappings, if the address range is locked, the mappings possibly have to be modified/unmapped on the CPU's side
20582068
// RelockRange to make this happen
20592069
if(IsAddressRangeLocked(registrationPoint.Range, context))

0 commit comments

Comments
 (0)