feat(cpu): retain fetch access kinds across instruction execution

This commit is contained in:
0xrsydn 2026-10-06 16:53:05 +07:00
commit 86321f0071
21 changed files with 637 additions and 61 deletions

View file

@ -1,6 +1,9 @@
//! ARM/Thumb instruction buffering. Timing and bus ownership remain separate.
//! ARM/Thumb instruction buffering and the next CPU fetch access kind.
use super::{Cpu, CpuError, InstructionSet};
use crate::memory::{InstructionFetch, Memory, MemoryError};
use crate::{
memory::{InstructionFetch, Memory, MemoryError},
timing::AccessKind,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) struct Pipeline {
@ -9,6 +12,7 @@ pub(super) struct Pipeline {
// Deferred strict-fetch results for the next execute and decode positions.
// Thumb halfwords are zero-extended; their upper bits are not another opcode.
instructions: [Result<u32, MemoryError>; 2],
pub(super) next_access: AccessKind,
}
pub(super) struct Fetched {
@ -21,11 +25,21 @@ pub(super) struct Fetched {
impl Cpu {
/// Discard buffered instructions after debugger code edits or rebinding memory.
/// Ordinary CPU/DMA stores and host inspection must not call this automatically.
/// The next step fills from its current PC/state without adding nominal cycles.
/// The next step uses nominal S startup with no separate fill charge.
/// This also discards the prior CPU fetch kind, but not Memory's DMA override.
pub fn invalidate_pipeline(&mut self) {
self.pipeline = None;
}
/// Cold/debugger entry keeps the existing nominal S startup policy.
/// A mismatched PC/state cannot reuse another sequence's access kind.
pub(super) fn next_fetch_kind(&self) -> AccessKind {
self.pipeline
.as_ref()
.filter(|pipe| pipe.pc == self.pc() && pipe.instruction_set == self.instruction_set)
.map_or(AccessKind::Sequential, |pipe| pipe.next_access)
}
pub(super) fn fetch(&self, memory: &Memory) -> Result<Fetched, CpuError> {
let pc = self.pc();
let instruction_set = self.instruction_set;
@ -53,6 +67,7 @@ impl Cpu {
pc: pc.wrapping_add(width),
instruction_set,
instructions: [decode, fetched.instruction.clone()],
next_access: AccessKind::Sequential, // Set from execution only on success.
},
lookahead: fetched,
fill,
@ -73,6 +88,7 @@ impl Cpu {
pc,
instruction_set,
instructions: fetches.map(|fetch| fetch.instruction),
next_access: AccessKind::Sequential,
});
}
}