2017-05-14 21:46:41 +00:00
//
// Z80.hpp
// Clock Signal
//
// Created by Thomas Harte on 14/05/2017.
2018-05-13 19:19:52 +00:00
// Copyright 2017 Thomas Harte. All rights reserved.
2017-05-14 21:46:41 +00:00
//
# ifndef Z80_hpp
# define Z80_hpp
2017-08-22 00:43:12 +00:00
# include <cassert>
2017-05-30 01:44:33 +00:00
# include <vector>
2017-09-02 00:50:24 +00:00
# include <cstdint>
2017-05-14 21:46:41 +00:00
2017-05-15 02:15:16 +00:00
# include "../RegisterSizes.hpp"
2017-07-26 00:20:55 +00:00
# include "../../ClockReceiver/ClockReceiver.hpp"
2019-07-17 19:09:26 +00:00
# include "../../ClockReceiver/ForceInline.hpp"
2017-05-15 02:15:16 +00:00
namespace CPU {
2017-05-14 21:46:41 +00:00
namespace Z80 {
/*
The list of registers that can be accessed via @ c set_value_of_register and @ c set_value_of_register .
*/
2019-09-22 16:13:56 +00:00
enum class Register {
2017-05-14 21:46:41 +00:00
ProgramCounter ,
StackPointer ,
A , Flags , AF ,
B , C , BC ,
D , E , DE ,
H , L , HL ,
ADash , FlagsDash , AFDash ,
BDash , CDash , BCDash ,
DDash , EDash , DEDash ,
HDash , LDash , HLDash ,
IXh , IXl , IX ,
IYh , IYl , IY ,
2017-06-04 22:32:23 +00:00
R , I , Refresh ,
2017-05-22 23:14:46 +00:00
2017-07-22 02:31:42 +00:00
IFF1 , IFF2 , IM ,
MemPtr
2017-05-14 21:46:41 +00:00
} ;
/*
2017-09-02 00:50:24 +00:00
Flags as defined on the Z80 ; can be used to decode the result of getting or setting @ c Flags .
2017-05-14 21:46:41 +00:00
*/
enum Flag : uint8_t {
Sign = 0x80 ,
Zero = 0x40 ,
Bit5 = 0x20 ,
HalfCarry = 0x10 ,
Bit3 = 0x08 ,
Parity = 0x04 ,
Overflow = 0x04 ,
Subtract = 0x02 ,
Carry = 0x01
} ;
/*!
2017-09-02 00:50:24 +00:00
Subclasses will be given the task of performing partial machine cycles , allowing them to provide whatever interface they like
between a Z80 and the rest of the system . @ c PartialMachineCycle defines the information they will be handed for each unit
of execution .
2017-05-14 21:46:41 +00:00
*/
2017-06-22 00:38:08 +00:00
struct PartialMachineCycle {
2017-06-18 01:53:45 +00:00
enum Operation {
2017-07-28 00:17:13 +00:00
ReadOpcode = 0 ,
2017-06-22 00:32:08 +00:00
Read ,
Write ,
Input ,
Output ,
2017-06-18 01:53:45 +00:00
Interrupt ,
2017-06-22 00:32:08 +00:00
Refresh ,
Internal ,
2017-06-18 01:53:45 +00:00
BusAcknowledge ,
2017-06-22 00:32:08 +00:00
2017-07-28 00:17:13 +00:00
ReadOpcodeWait ,
2017-06-22 00:32:08 +00:00
ReadWait ,
WriteWait ,
InputWait ,
2017-06-23 00:07:47 +00:00
OutputWait ,
InterruptWait ,
2017-07-28 00:17:13 +00:00
ReadOpcodeStart ,
2017-06-23 00:07:47 +00:00
ReadStart ,
WriteStart ,
InputStart ,
2017-06-22 00:32:08 +00:00
OutputStart ,
2017-07-28 00:17:13 +00:00
InterruptStart ,
2017-08-25 01:32:33 +00:00
} ;
2017-09-02 00:50:24 +00:00
/// The operation being carried out by the Z80. See the various getters below for better classification.
2017-08-25 01:32:33 +00:00
const Operation operation ;
2017-09-02 00:50:24 +00:00
/// The length of this operation.
2017-08-25 01:32:33 +00:00
const HalfCycles length ;
2017-09-02 00:50:24 +00:00
/// The current value of the address bus.
2017-08-25 01:32:33 +00:00
const uint16_t * const address ;
2019-04-19 21:44:52 +00:00
/// If the Z80 is outputting to the data bus, a pointer to that value. Otherwise, a pointer to the location where the current data bus value should be placed.
2017-08-25 01:32:33 +00:00
uint8_t * const value ;
2017-09-02 00:50:24 +00:00
/// @c true if this operation is occurring only because of an external request; @c false otherwise.
2017-08-25 01:32:33 +00:00
const bool was_requested ;
2017-06-22 00:32:08 +00:00
2017-09-02 00:50:24 +00:00
/*!
@ returns @ c true if the processor believes that the bus handler should actually do something with
the content of this PartialMachineCycle ; @ c false otherwise .
*/
2019-07-17 19:09:26 +00:00
forceinline bool expects_action ( ) const {
2017-06-22 00:32:08 +00:00
return operation < = Operation : : Interrupt ;
}
2017-09-02 00:50:24 +00:00
/*!
@ returns @ c true if this partial machine cycle completes one of the documented full machine cycles ;
@ c false otherwise .
*/
2019-07-17 19:09:26 +00:00
forceinline bool is_terminal ( ) const {
2017-06-22 00:32:08 +00:00
return operation < = Operation : : BusAcknowledge ;
}
2017-09-02 00:50:24 +00:00
/*!
@ returns @ c true if this partial machine cycle is a wait cycle ; @ c false otherwise .
*/
2019-07-17 19:09:26 +00:00
forceinline bool is_wait ( ) const {
2017-07-28 01:10:14 +00:00
return operation > = Operation : : ReadOpcodeWait & & operation < = Operation : : InterruptWait ;
2017-06-23 00:07:47 +00:00
}
2017-08-25 01:32:33 +00:00
2017-09-02 00:50:24 +00:00
PartialMachineCycle ( const PartialMachineCycle & rhs ) noexcept ;
PartialMachineCycle ( Operation operation , HalfCycles length , uint16_t * address , uint8_t * value , bool was_requested ) noexcept ;
PartialMachineCycle ( ) noexcept ;
2017-05-16 02:25:52 +00:00
} ;
2017-05-15 02:08:15 +00:00
/*!
2017-09-02 00:50:24 +00:00
A class providing empty implementations of the methods a Z80 uses to access the bus . To wire the Z80 to a bus ,
2019-04-19 21:44:52 +00:00
machines should subclass BusHandler and then declare a realisation of the Z80 template , supplying their bus
2017-09-02 00:50:24 +00:00
handler .
2017-05-15 02:08:15 +00:00
*/
2017-09-02 00:50:24 +00:00
class BusHandler {
2017-05-15 11:59:21 +00:00
public :
2017-05-15 11:55:53 +00:00
/*!
2017-09-02 00:50:24 +00:00
Announces that the Z80 has performed the partial machine cycle defined by @ c cycle .
2017-05-15 11:55:53 +00:00
2017-09-02 00:50:24 +00:00
@ returns The number of additional HalfCycles that passed in objective time while this Z80 operation was ongoing .
On an archetypal machine this will be HalfCycles ( 0 ) but some architectures may choose not to clock the Z80
during some periods or may impose wait states so predictably that it ' s more efficient just to add them
via this mechanism .
2017-05-15 11:55:53 +00:00
*/
2017-07-26 23:42:00 +00:00
HalfCycles perform_machine_cycle ( const PartialMachineCycle & cycle ) {
return HalfCycles ( 0 ) ;
2017-05-16 02:25:52 +00:00
}
2017-05-15 11:55:53 +00:00
/*!
2019-04-19 21:44:52 +00:00
Announces completion of all the cycles supplied to a . run_for request on the Z80 . Intended to allow
2017-09-02 00:50:24 +00:00
bus handlers to perform any deferred output work .
2017-05-15 11:55:53 +00:00
*/
2017-09-02 00:50:24 +00:00
void flush ( ) { }
} ;
2017-05-15 11:55:53 +00:00
2017-09-02 00:50:24 +00:00
# include "Implementation/Z80Storage.hpp"
2017-05-15 11:55:53 +00:00
2017-09-02 00:50:24 +00:00
/*!
A base class from which the Z80 descends ; separated for implementation reasons only .
*/
class ProcessorBase : public ProcessorStorage {
public :
2017-05-15 11:55:53 +00:00
/*!
Gets the value of a register .
@ see set_value_of_register
@ param r The register to set .
@ returns The value of the register . 8 - bit registers will be returned as unsigned .
*/
2017-09-02 00:50:24 +00:00
uint16_t get_value_of_register ( Register r ) ;
2017-05-15 11:55:53 +00:00
/*!
Sets the value of a register .
@ see get_value_of_register
@ param r The register to set .
@ param value The value to set . If the register is only 8 bit , the value will be truncated .
*/
2017-09-02 00:50:24 +00:00
void set_value_of_register ( Register r , uint16_t value ) ;
2017-05-29 15:54:27 +00:00
/*!
Gets the value of the HALT output line .
*/
2017-09-02 00:50:24 +00:00
inline bool get_halt_line ( ) ;
2017-06-01 02:51:32 +00:00
/*!
2017-06-02 00:34:52 +00:00
Sets the logical value of the interrupt line .
2017-06-11 17:31:02 +00:00
@ param offset If called while within perform_machine_cycle this may be a value indicating
how many cycles before now the line changed state . The value may not be longer than the
current machine cycle . If called at any other time , this must be zero .
2017-06-01 02:51:32 +00:00
*/
2017-09-02 00:50:24 +00:00
inline void set_interrupt_line ( bool value , HalfCycles offset = 0 ) ;
2017-06-01 02:51:32 +00:00
2017-09-02 00:50:24 +00:00
/*!
Gets the value of the interrupt line .
*/
inline bool get_interrupt_line ( ) ;
2017-06-23 00:11:19 +00:00
2017-06-01 02:51:32 +00:00
/*!
2017-06-02 00:34:52 +00:00
Sets the logical value of the non - maskable interrupt line .
2017-11-08 03:54:22 +00:00
2017-06-11 17:31:02 +00:00
@ param offset See discussion in set_interrupt_line .
2017-06-01 02:51:32 +00:00
*/
2018-02-24 23:14:38 +00:00
inline void set_non_maskable_interrupt_line ( bool value , HalfCycles offset = 0 ) ;
2017-06-23 00:11:19 +00:00
2017-06-01 02:51:32 +00:00
/*!
2017-09-02 00:50:24 +00:00
Gets the value of the non - maskable interrupt line .
2017-06-01 02:51:32 +00:00
*/
2017-09-02 00:50:24 +00:00
inline bool get_non_maskable_interrupt_line ( ) ;
2017-06-23 00:11:19 +00:00
2017-06-02 01:40:08 +00:00
/*!
Sets the logical value of the reset line .
*/
2017-09-02 00:50:24 +00:00
inline void set_reset_line ( bool value ) ;
2017-06-02 01:40:08 +00:00
2017-06-02 02:31:04 +00:00
/*!
This emulation automatically sets itself up in power - on state at creation , which has the effect of triggering a
reset at the first opportunity . Use @ c reset_power_on to disable that behaviour .
*/
2017-09-02 00:50:24 +00:00
void reset_power_on ( ) ;
} ;
/*!
@ abstact Template providing emulation of a Z80 processor .
@ discussion Users should provide as the first template parameter a subclass of CPU : : Z80 : : BusHandler ; the Z80
will announce its activity via the bus handler , which is responsible for marrying it to a bus . Users
can also nominate whether the processor includes support for the bus request and / or wait lines . Declining to
support either can produce a minor runtime performance improvement .
*/
template < class T , bool uses_bus_request , bool uses_wait_line > class Processor : public ProcessorBase {
public :
Processor ( T & bus_handler ) ;
/*!
Runs the Z80 for a supplied number of cycles .
@ discussion Subclasses must implement @ c perform_machine_cycle ( const PartialMachineCycle & cycle ) .
If it is a read operation then @ c value will be seeded with the value 0xff .
@ param cycles The number of cycles to run for .
*/
void run_for ( const HalfCycles cycles ) ;
2017-06-02 02:31:04 +00:00
2017-06-22 00:32:08 +00:00
/*!
2017-09-02 00:50:24 +00:00
Sets the logical value of the bus request line , having asserted that this Z80 supports the bus request line .
2017-06-22 00:32:08 +00:00
*/
2017-09-02 00:50:24 +00:00
void set_bus_request_line ( bool value ) ;
2017-06-22 00:32:08 +00:00
2017-09-02 00:50:24 +00:00
/*!
Gets the logical value of the bus request line .
*/
bool get_bus_request_line ( ) ;
/*!
Sets the logical value of the wait line , having asserted that this Z80 supports the wait line .
*/
void set_wait_line ( bool value ) ;
/*!
Gets the logical value of the bus request line .
*/
bool get_wait_line ( ) ;
private :
T & bus_handler_ ;
void assemble_page ( InstructionPage & target , InstructionTable & table , bool add_offsets ) ;
void copy_program ( const MicroOp * source , std : : vector < MicroOp > & destination ) ;
2017-05-14 21:46:41 +00:00
} ;
2017-09-02 00:50:24 +00:00
# include "Implementation/Z80Implementation.hpp"
2017-05-15 02:15:16 +00:00
}
2017-05-14 21:46:41 +00:00
}
# endif /* Z80_hpp */