1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
//! # [Cpu] trait is defined here.
mod debug;
mod flags;
mod parse;
mod registers;

use crate::host::*;
pub use debug::*;
pub use flags::*;
pub use parse::*;
pub use registers::*;

/// The Cpu trait provides means to execute and debug machine code or change the state of `self` at User's will.
pub trait Cpu: Clone + Default + PartialEq + Eq {
    /// Instantly resets the Cpu to its initial state.
    fn reset(&mut self);
    /// Returns the current value of the program counter.
    fn get_pc(&self) -> u16;
    /// Sets the current value of the program counter.
    fn set_pc(&mut self, pc: u16);
    /// Returns the current value of the stack pointer.
    fn get_sp(&self) -> u16;
    /// Sets the current value of the stack pointer.
    fn set_sp(&mut self, sp: u16);
    /// Returns the Accumulator value as an unsigned 8-bit integer.
    fn get_acc(&self) -> u8;
    /// Sets the Accumulator value from an unsigned 8-bit integer.
    fn set_acc(&mut self, val: u8);
    /// Returns the current state of the Flags register.
    fn get_flags(&self) -> CpuFlags;
    /// Sets the current state of the Flags register.
    fn set_flags(&mut self, flags: CpuFlags);
    /// Increases the memory refresh counter.
    fn inc_r(&mut self);
    /// Adds the arbitrary value to the memory refresh counter.
    /// This can be used to emulate the Cpu in the HALT state without executing the busy loop.
    fn add_r(&mut self, delta: i32);
    /// Returns the current value of the memory refresh register `R`.
    fn get_r(&self) -> u8;
    /// Sets the memory refresh register `R` value.
    fn set_r(&mut self, r: u8);
    /// Returns the current value of the interrupt page `I` register.
    fn get_i(&self) -> u8;
    /// Sets the current value of the interrupt page `I` register.
    fn set_i(&mut self, i: u8);
    /// Returns the current memory refresh address.
    fn get_ir(&self) -> u16;
    /// Returns values of interrupt flip-flops `(iff1, iff2)`.
    fn get_iffs(&self) -> (bool, bool);
    /// Sets the values of interrupt flip-flops.
    fn set_iffs(&mut self, iff1: bool, iff2: bool);
    /// Forces [Cpu] to enter the HALT state. This doesn't involve [Clock] and happens instantly.
    /// This also can be done by executing `HALT` instruction with [Cpu::execute_instruction].
    fn halt(&mut self);
    /// Returns `true` if the [Cpu] is in the HALT state.
    fn is_halt(&self) -> bool;
    /// Returns the current interrupt mode.
    fn get_im(&self) -> InterruptMode;
    /// Sets the interrupt mode.
    fn set_im(&mut self, im: InterruptMode);
    /// Swaps the `AF` register with its alternative counterpart `AF'`.
    fn ex_af_af(&mut self);
    /// Swaps the `BC`, `DE` and `HL` registers with their alternative counterparts `BC'`, `DE'` and `HL'`.
    fn exx(&mut self);
    /// Returns the content of the selected 8-bit register.
    ///
    /// The `reg` argument specifies the register. If the `prefix` argument is 
    /// one of [Prefix::Xdd] or [Prefix::Yfd] and the `reg` is [Reg8::H] or [Reg8::L]
    /// the content of the `IXh`, `IXl` or `IYh`, `IYl` will be returned instead.
    fn get_reg(&self, reg: Reg8, prefix: Option<Prefix>) -> u8;
    /// Sets the content of the selected 8-bit register.
    ///
    /// The `reg` argument specifies the register. If the `prefix` argument is 
    /// one of [Prefix::Xdd] or [Prefix::Yfd] and the `reg` is [Reg8::H] or [Reg8::L]
    /// the content of the `IXh`, `IXl` or `IYh`, `IYl` will be set instead.
    fn set_reg(&mut self, dst: Reg8, prefix: Option<Prefix>, val: u8);
    /// Returns the content of the selected pair of registers as a tuple of 8-bit unsigned integers.
    ///
    /// E.g. for [StkReg16::BC] the content of `(B, C)` will be returned.
    fn get_reg2(&self, src: StkReg16) -> (u8, u8);
    /// Returns the content of the selected pair of alternative registers as a tuple of 8-bit unsigned integers.
    ///
    /// E.g. for [StkReg16::AF] the content of `(A', F')` will be returned.
    fn get_alt_reg2(&self, src: StkReg16) -> (u8, u8);
    /// Returns the content of the selected pair of registers as an unsigned 16-bit integer.
    fn get_reg16(&self, src: StkReg16) -> u16;
    /// Returns the content of the selected pair of alternative registers as an unsigned 16-bit integer.
    fn get_alt_reg16(&self, src: StkReg16) -> u16;
    /// Sets the content of the selected pair of registers.
    ///
    /// E.g. for [StkReg16::BC] register `B` will be set to `hi` and `C` to `lo`.
    fn set_reg2(&mut self, src: StkReg16, hi: u8, lo: u8);
    /// Sets the content of the selected pair of registers as an unsigned 16-bit integer.
    fn set_reg16(&mut self, src: StkReg16, val: u16);
    /// Returns the content of one of the index registers as a tuple of 8-bit unsigned integers.
    ///
    /// Depending on `prefix` this will be:
    /// * [Prefix::Xdd] - `(IXh, IXl)`
    /// * [Prefix::Yfd] - `(IYh, IYl)`
    fn get_index2(&self, prefix: Prefix) -> (u8, u8);
    /// Returns the content of one of the index registers as a 16-bit unsigned integer.
    ///
    /// Depending on `prefix` this will be:
    /// * [Prefix::Xdd] - `IX`
    /// * [Prefix::Yfd] - `IY`
    fn get_index16(&self, prefix: Prefix) -> u16;
    /// Sets the content of one of the index registers.
    ///
    /// Depending on `prefix` this will be:
    /// * [Prefix::Xdd] - `IXh=hi, IXl=lo`
    /// * [Prefix::Yfd] - `IYh=hi, IYl=lo`
    fn set_index2(&mut self, prefix: Prefix, hi: u8, lo: u8);
    /// Sets the content of one of the index registers as a 16-bit unsigned integer.
    ///
    /// Depending on `prefix` this will be:
    /// * [Prefix::Xdd] - `IX`
    /// * [Prefix::Yfd] - `IY`
    fn set_index16(&mut self, prefix: Prefix, val: u16);
    /// Returns true if the Cpu will accept the interrupt request before executing the next opcode.
    fn is_irq_allowed(&self) -> bool;
    /// Returns true if the Cpu will accept the non-maskable interrupt before executing the next opcode.
    fn is_nmi_allowed(&self) -> bool;
    /// Restores the content of the `interrupt flip-flop 1` from the content of the `interrupt flip-flop 2`.
    /// This is what `RETN` instruction usually does.
    fn restore_iff1(&mut self);
    /// Disables the maskable interrupts by resetting both `interrupt flip-flops` to Off.
    ///
    /// This is what `DI` instruction usually does.
    fn disable_interrupts(&mut self);
    /// Enabes the maskable interrupts by setting both `interrupt flip-flops` to On.
    ///
    /// Prevents the interrupts to be allowed before the next command.
    /// This is what `EI` instruction usually does.
    fn enable_interrupts(&mut self);
    /// Returns `true` if the last command executed was `EI`.
    fn is_after_ei(&self) -> bool;
    /// Returns `true` if the last command executed was a `0xDD` or a `0xFD` prefix.
    ///
    /// See [Cpu::execute_instruction] for more information.
    fn is_after_prefix(&self) -> bool;
    /// Returns the prefix value after executing the last command.
    ///
    /// See [Cpu::execute_instruction] for more information.
    fn get_prefix(&self) -> Option<Prefix>;
    /// Requests a maskable interrupt.
    ///
    /// This is the alternative method to invoke the maskable interrupt. Usually while instructions
    /// are being executed the [Cpu] checks via [Io::is_irq] method if the interrrupt from any device is being
    /// requested.
    ///
    /// Returns `None` if the interrupt could not be accepted at this time. In this instance the method performs
    /// no operation.
    ///
    /// Returns `Some(Ok(()))` if an interrupt was accepted and no break was requested by the executed instruction.
    /// In this instance at least one instruction will be executed. Depending on the interrupt mode this would be:
    /// * [InterruptMode::Mode0] an instruction provided via [Io::irq_data].
    /// * [InterruptMode::Mode1] a `RST 38h` instruction.
    /// * [InterruptMode::Mode2] a hypothetical `PUSH pc + JP <vector address>` instruction.
    ///   A debugger will see the `JP` command in this instance.
    ///
    /// The [Clock] is advanced by the `IRQ:6` cycle + optional wait states + cycles specific to the executed
    /// instruction (minus the `M1:4` cycle).
    ///
    /// `Some(Err(BreakCause))` indicates that an instruction requested a break. Currently this may be possible
    /// in the interrupt mode 0 when the `HALT`, `OUT` or `RETI` instruction was executed and the [Io::write_io]
    /// or [Io::reti] requested to break the execution.
    ///
    /// See [Cpu::execute_instruction] for the `debug` argument description.
    ///
    /// # Note
    ///
    /// If the interrupt is being accepted this method resets the `HALT` state before everything else.
    fn irq<M, T, F>(
        &mut self,
        control: &mut M,
        tsc: &mut T,
        debug: Option<F>
    ) -> Option<Result<M::WrIoBreak, M::RetiBreak>>
    where M: Memory<Timestamp=T::Timestamp> + Io<Timestamp=T::Timestamp>,
          T: Clock,
          F: FnOnce(CpuDebug);
    /// Attempts to trigger a non-maskable interrupt.
    ///
    /// Returns `false` if the interrupt could not be accepted at this time. The non-maskable interrupt
    /// is not being accepted in some situations, e.g. right after executing the `EI` instruction or after
    /// one of the `0xDD` and `0xFD` opcode prefixes. In this instance the method performs no operation.
    ///
    /// Returns `true` on success. In this instance no instruction will be executed but the program counter
    /// will be set to `0x0066` and the previous program counter will be pushed on the machine stack.
    /// The `interrupt flip-flop 1` is being set to `false`, while preserving the value of `iff 2` and the
    /// [Clock] advances according to the Z80 NMI cycles: `M1:4 + IR:1 + SP-1:3 + SP-2:3`.
    ///
    /// # Note
    ///
    /// If the interrupt is being accepted this method resets the `HALT` state before everything else.
    fn nmi<M, T>(&mut self, control: &mut M, tsc: &mut T) -> bool
    where M: Memory<Timestamp=T::Timestamp> + Io<Timestamp=T::Timestamp>,
          T: Clock;
    /// Executes a single instruction given as `code`. If the instruction is a first byte of the multi-byte
    /// instruction the rest of the instruction body will be fetched via calls to [Memory::read_opcode].
    ///
    /// The return value `Err(BreakCause)` indicates that an instruction requested a break.
    /// Currently this may be possible when the `HALT` instruction was executed or when the `OUT` family
    /// instruction was executed and the [Io::write_io] requested a break or the `RETI` instruction was
    /// executed and the [Io::reti] requested a break. See also [BreakCause].
    ///
    /// If `debug` argument is `Some(F)`, a closure `F` may be called with [CpuDebug] argument during the
    /// instruction execution. It won't be called if `code` is one of the `0xDD` or `0xFD` prefixes.
    ///
    /// There is no limit of how many of these prefixes can be present before an actual instruction, so
    /// the execution is finished each time one of them is being encountered to prevent the overfeeding the [Clock]
    /// with a huge amount of T-states and to allow for the better synchronization with the emulated side effects.
    /// The user can check with [Cpu::is_after_prefix] method if this is the case after calling one of the
    /// execution methods.
    ///
    /// # Note
    ///
    /// This method resets the `HALT` state and `after EI` state before the instruction is being executed.
    fn execute_instruction<M, T, F>(
        &mut self,
        control: &mut M,
        tsc: &mut T,
        debug: Option<F>,
        code: u8
    ) -> Result<M::WrIoBreak, M::RetiBreak>
    where M: Memory<Timestamp=T::Timestamp> + Io<Timestamp=T::Timestamp>,
          T: Clock,
          F: FnOnce(CpuDebug);
    /// Executes the next instruction present in the [Memory] at the program counter fetched via [Memory::read_opcode].
    ///
    /// If interrupts are allowed, before fetching the instruction, checks if the interrupt request is present
    /// via [Io::is_irq] and enters the interrupted state, instead of fetching and executing the next instruction.
    ///
    /// If the Cpu is in the `HALT` state, increases the memory refresh register and advances the [Clock] only.
    /// If `debug` closure is given, it will not be called in this instance.
    ///
    /// See [Cpu::execute_instruction] and [Cpu::irq] for the returned value and `debug` argument descriptions.
    fn execute_next<M, T, F>(
        &mut self,
        control: &mut M,
        tsc: &mut T,
        debug: Option<F>
    ) -> Result<M::WrIoBreak, M::RetiBreak>
    where M: Memory<Timestamp=T::Timestamp> + Io<Timestamp=T::Timestamp>,
          T: Clock,
          F: FnOnce(CpuDebug);
    /// Executes instructions until [Clock] reaches the given `limit` or when other conditions are met.
    ///
    /// Returns `Ok(())` only when `limit` has been reached and the last executed instruction didn't request a break.
    ///
    /// Returns `Err(BreakCause)` when:
    /// * The `HALT` instruction was encountered. This also implies that the Cpu has entered the `HALT` state.
    /// * An instruction requested a break via [Io::write_io] or [Io::reti].
    ///
    /// See also [BreakCause].
    ///
    /// When interrupts are enabled, before fetching each next instruction, this method checks if the interrupt
    /// has been requested via [Io::is_irq] and executes the interrupt routine without breaking the execution.
    ///
    /// When called while the Cpu was already in the `HALT` state, increases the memory refresh register and
    /// advances the [Clock] until the `limit` has been reached. If interrupts were enabled and an interrupt
    /// was requested via [Io::is_irq], the `HALT` state is being reset and the regular execution of commands
    /// will be resumed.
    fn execute_with_limit<M, T>(
        &mut self,
        control: &mut M,
        tsc: &mut T,
        limit: T::Limit
    ) -> Result<M::WrIoBreak, M::RetiBreak>
    where M: Memory<Timestamp=T::Timestamp> + Io<Timestamp=T::Timestamp>,
          T: Clock;
}