352 lines
11 KiB
C
352 lines
11 KiB
C
/* -------------------------------------------------------------------------
|
|
saturn - A poor-man's emulator of some HP calculators
|
|
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with the documentation of this program; if not, write to
|
|
the Free Software Foundation, Inc.,
|
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
For more information, please contact the author, preferably by email,
|
|
at the following address:
|
|
|
|
Ivan Cibrario Bertolotti
|
|
IRITI - National Research Council
|
|
c/o IEN "Galileo Ferraris"
|
|
Strada delle Cacce, 91
|
|
10135 - Torino (ITALY)
|
|
|
|
email: cibrario@iriti.cnr.it
|
|
------------------------------------------------------------------------- */
|
|
|
|
/* +-+ */
|
|
|
|
/* .+
|
|
|
|
.identifier : $Id: cpu.h,v 4.1 2000/12/11 09:54:19 cibrario Rel $
|
|
.context : SATURN, Saturn CPU / HP48 emulator
|
|
.title : $RCSfile: cpu.h,v $
|
|
.kind : C header
|
|
.author : Ivan Cibrario B.
|
|
.site : CSTV-CNR
|
|
.creation : *
|
|
.keywords : *
|
|
.description :
|
|
Main header for the Saturn CPU emulation modules. References:
|
|
|
|
SASM.DOC by HP (HORN disk 4)
|
|
Guide to the Saturn Processor Rev. 0.00f by Matthew Mastracci
|
|
entries.srt by Mika Heiskanen (mheiskan@vipunen.hut.fi)
|
|
x48 source code by Eddie C. Dost (ecd@dressler.de)
|
|
|
|
.include : config.h machdep.h
|
|
|
|
.notes :
|
|
$Log: cpu.h,v $
|
|
Revision 4.1 2000/12/11 09:54:19 cibrario
|
|
Public release.
|
|
|
|
Revision 3.14 2000/11/13 11:31:16 cibrario
|
|
Implemented fast load/save; improved keyboard interface emulation at
|
|
high emulated CPU speed:
|
|
|
|
- Revision number bump with no changes
|
|
|
|
Revision 3.13 2000/11/09 11:27:14 cibrario
|
|
Revised to add file selection box GUI element, CPU halt/run
|
|
requests and emulator's extended functions:
|
|
|
|
- Added new fields:
|
|
struct CpuStatus.halt (number of pending halt requests)
|
|
struct CpuStatus.inner_loop_max (upper limit of inner_loop)
|
|
- New condition codes: CPU_I_HALT, CPU_I_RUN, CPU_E_NO_HALT
|
|
- New prototypes: CpuHaltRequest(), CpuRunRequest(), CpuHaltAllowed()
|
|
|
|
Revision 3.10 2000/10/24 16:14:31 cibrario
|
|
Added/Replaced GPL header
|
|
|
|
Revision 3.8 2000/10/23 13:13:08 cibrario
|
|
Bug fix:
|
|
Adjusted INNER_LOOP_MAX and INNER_LOOP_MED to get closer to
|
|
real CPU speed.
|
|
|
|
Revision 3.5 2000/10/02 09:43:37 cibrario
|
|
Linux support:
|
|
- Added definition of INNER_LOOP_MAX; it is used to give an upper limit
|
|
to the emulated CPU speed on fast machines, when REAL_CPU_SPEED is
|
|
defined.
|
|
|
|
Revision 3.1 2000/09/20 13:42:30 cibrario
|
|
Revised to implement passive CPU shutdown:
|
|
- new status codes CPU_I_TIMER_ST, CPU_I_TIMER_EXP, CPU_I_IDLE_X_LOOP,
|
|
CPU_I_ELAPSED
|
|
|
|
* Revision 2.4 2000/09/12 15:19:47 cibrario
|
|
* Added definition of XAddress (extended address) data type; it is
|
|
* required to implement emulation of Port 1 and 2.
|
|
*
|
|
* Revision 2.1 2000/09/08 14:48:52 cibrario
|
|
* - Declared prototypes of new functions EmulatorInit() and EmulatorExit()
|
|
* - Defined new 'enum ExitOption' data type, used by EmulatorExit()
|
|
*
|
|
* Revision 1.1 1998/02/18 11:50:43 cibrario
|
|
* Initial revision
|
|
*
|
|
|
|
.- */
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Macro/Data type definitions - require machdep.h
|
|
|
|
N_SCRATCH_REGISTER_ALL, used during scratch register space allocation
|
|
is larger than necessary to avoid additional checks on the validity of
|
|
the R register index fields during emulation
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/* General */
|
|
#define NIBBLE_PER_REGISTER 16
|
|
#define N_WORKING_REGISTER 4
|
|
#define N_SCRATCH_REGISTER 5
|
|
#define N_SCRATCH_REGISTER_ALL 8
|
|
#define N_DATA_POINTER_REGISTER 2
|
|
#define RETURN_STACK_SIZE 8
|
|
#define NIBBLE_VALUES 16
|
|
|
|
#define INT_HANDLER_PC ((Address)0x0000F)
|
|
|
|
#define DISASSEMBLE_OB_SIZE 128
|
|
#define DUMP_CPU_STATUS_OB_SIZE 512
|
|
|
|
#define CPU_RCS_INFO "$Revision: 4.1 $ $State: Rel $"
|
|
|
|
|
|
/* Instruction opcode access macros:
|
|
GetFS(f) returns the short field-selector value from the
|
|
given nibble (bits 2..0)
|
|
|
|
GetImmFS(f) returns the immediate-field-selector flag from the
|
|
given nibble (bit 3)
|
|
=0: regular field selector
|
|
!=0: immediate field selector
|
|
|
|
GetOC_1(o) returns the short operation code from the given
|
|
nibble (bits 3..2 >>2)
|
|
|
|
GetOC_2(f, o) returns the long operation code from the given
|
|
nibbles (f bit 3, o bits 3..2)
|
|
|
|
GetOC_3b(o) returns the long operation code from the given
|
|
nibble (bits 2..0)
|
|
|
|
GetRP(o) returns the register-pair identifier from the given
|
|
nibble (bits 1..0)
|
|
|
|
GetRn(r) returns the R register index from the given nibble
|
|
(bits 2..0)
|
|
|
|
GetAC(r) returns the A/C register flag from the given nibble
|
|
(bit 3)
|
|
=0: register A
|
|
!=0: register C
|
|
|
|
GetAS(r) returns the add/subtract flag from the given nibble
|
|
(bit 3)
|
|
=0: add
|
|
!=0: subtract
|
|
*/
|
|
#define GetFS(f) ((f) & 0x7)
|
|
#define GetImmFS(o) ((o) & 0x8)
|
|
#define GetOC_1(o) (((o) & 0xC)>>2)
|
|
#define GetOC_2(f, o) ((((f) & 0x8)>>1) | (((o) & 0xC)>>2))
|
|
#define GetOC_3b(o) ((o) & 0x7)
|
|
#define GetRP(o) ((o) & 0x3)
|
|
#define GetRn(r) ((r) & 0x7)
|
|
#define GetAC(r) ((r) & 0x8)
|
|
#define GetAS(r) ((r) & 0x8)
|
|
|
|
|
|
/* Field selector codes */
|
|
#define FS_P 0
|
|
#define FS_WP 1
|
|
#define FS_XS 2
|
|
#define FS_X 3
|
|
#define FS_S 4
|
|
#define FS_M 5
|
|
#define FS_B 6
|
|
#define FS_W 7
|
|
#define FS_A 15
|
|
#define N_FS 16 /* Total # of FS codes */
|
|
|
|
|
|
/* Register pair codes */
|
|
#define RP_AB 0
|
|
#define RP_BC 1
|
|
#define RP_CA 2
|
|
#define RP_DC 3
|
|
#define N_RP 4 /* Total # of RP codes */
|
|
|
|
|
|
/* Masks */
|
|
#define NIBBLE_MASK ((Nibble)0xF)
|
|
#define ADDRESS_MASK ((Address)0xFFFFF)
|
|
|
|
#define CLRST_MASK ((ProgramStatusRegister)0xF000)
|
|
#define D_S_MASK ((Address)0xF0000)
|
|
#define RETURN_SP_MASK 0x7
|
|
|
|
|
|
typedef int1 Bit;
|
|
typedef int4 Nibble;
|
|
typedef int20 Address;
|
|
typedef int12 OutputRegister;
|
|
typedef int16 InputRegister;
|
|
typedef int16 ProgramStatusRegister;
|
|
typedef Nibble DataRegister[NIBBLE_PER_REGISTER];
|
|
|
|
/* The XAddress data type holds extended addresses used to access Port 2 */
|
|
typedef int32 XAddress;
|
|
|
|
enum IntRequest
|
|
{
|
|
INT_REQUEST_NONE,
|
|
INT_REQUEST_IRQ,
|
|
INT_REQUEST_NMI
|
|
};
|
|
|
|
struct CpuStatus
|
|
{
|
|
DataRegister work[N_WORKING_REGISTER];
|
|
#define A work[0]
|
|
#define B work[1]
|
|
#define C work[2]
|
|
#define D work[3]
|
|
|
|
DataRegister R[N_SCRATCH_REGISTER_ALL];
|
|
#define R0 R[0]
|
|
#define R1 R[1]
|
|
#define R2 R[2]
|
|
#define R3 R[3]
|
|
#define R4 R[4]
|
|
|
|
Address DAT[N_DATA_POINTER_REGISTER];
|
|
#define D0 DAT[0]
|
|
#define D1 DAT[1]
|
|
|
|
Nibble P;
|
|
Address PC;
|
|
InputRegister IN;
|
|
OutputRegister OUT;
|
|
ProgramStatusRegister ST;
|
|
|
|
Nibble HST;
|
|
#define HST_MP_MASK 0x08
|
|
#define HST_SR_MASK 0x04
|
|
#define HST_SB_MASK 0x02
|
|
#define HST_XM_MASK 0x01
|
|
|
|
Address return_stack[RETURN_STACK_SIZE];
|
|
int return_sp;
|
|
|
|
int fs_idx_lo[N_FS];
|
|
int fs_idx_hi[N_FS];
|
|
int hexmode; /* DEC/HEX mode, 1=HEX */
|
|
int carry; /* Carry bit 1=set */
|
|
int shutdn; /* SHUTDN flag, 1=executed */
|
|
int halt; /* 3.13: # of pending Halt */
|
|
int int_enable; /* Int. enable, 1=enabled */
|
|
int int_service; /* Int. service, 1=service */
|
|
enum IntRequest int_pending; /* Pending interrupt request */
|
|
|
|
/* 3.13: inner_loop_max gives the upper limit of the CPU speed if the
|
|
compile-time option REAL_CPU_SPEED is defined. When the CPU is reset
|
|
it has the default value INNER_LOOP_MAX, that should be close to the
|
|
real cpu speed (~4MHz).
|
|
*/
|
|
int inner_loop; /* Inner loop multiplier */
|
|
int inner_loop_max; /* Max value of inner_loop */
|
|
#define INNER_LOOP_MAX 26
|
|
#define INNER_LOOP_MED 13
|
|
#define INNER_LOOP_MIN 2
|
|
|
|
#ifdef CPU_SPIN_LOOP
|
|
int reset_req; /* Reset req. after shutdn */
|
|
#endif
|
|
};
|
|
|
|
enum ExitOption /* 2.1: EmulatorExit() option */
|
|
{
|
|
IMMEDIATE_EXIT,
|
|
SAVE_AND_EXIT
|
|
};
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Global variables
|
|
---------------------------------------------------------------------------*/
|
|
|
|
extern struct CpuStatus cpu_status;
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Chf condition codes
|
|
---------------------------------------------------------------------------*/
|
|
|
|
#define CPU_I_CALLED 101 /* Function %s called */
|
|
#define CPU_I_EXECUTING 102 /* Executing @PC %X */
|
|
#define CPU_I_SHUTDN 103 /* Shutdown */
|
|
#define CPU_I_WAKE 104 /* Wake */
|
|
#define CPU_I_INT 105 /* %s request accepted */
|
|
#define CPU_I_INT_PENDING 106 /* %s request pending */
|
|
#define CPU_I_RTI_LOOP 107 /* RTI loop to service %s */
|
|
#define CPU_I_RTI_END 108 /* RTI returning */
|
|
#define CPU_I_INTON 109 /* INTON servicing %s */
|
|
#define CPU_I_REVISION 110 /* CPU emulation revision: %s */
|
|
#define CPU_I_TIMER1_EX 111 /* Timer 1 expired; ctrl=%x */
|
|
#define CPU_I_TIMER2_EX 112 /* Timer 1 expired; ctrl=%x */
|
|
#define CPU_I_EMULATOR_INT 113 /* Emulator interrupt req. detected */
|
|
#define CPU_I_TIMER_ST 114 /* 3.1: Timer %s st: ctrl %x, val %x */
|
|
#define CPU_I_TIMER_EXP 115 /* 3.1: Timer %s expiration %d ms */
|
|
#define CPU_I_IDLE_X_LOOP 116 /* 3.1: Start idle loop, t/out %d ms */
|
|
#define CPU_I_ELAPSED 117 /* 3.1: Spent %d us in idle loop */
|
|
#define CPU_I_HALT 118 /* 3.13: CPU halted */
|
|
#define CPU_I_RUN 119 /* 3.13: CPU running */
|
|
#define CPU_W_RESETTING 201 /* Resetting CPU */
|
|
#define CPU_W_BAD_MONITOR_CMD 202 /* Bad monitor command: %s */
|
|
#define CPU_E_BAD_OPCODE 301 /* Bad opc. pc=%x, value=%x */
|
|
#define CPU_E_SAVE 302 /* Can't save CPU status */
|
|
#define CPU_E_NO_HALT 303 /* 3.13: Halt/Run not allowed */
|
|
#define CPU_F_INTERR 401 /* Internal error %s */
|
|
#define CPU_F_BAD_SHUTDN 402 /* Unexpected CPU shutdown */
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Function prototypes
|
|
---------------------------------------------------------------------------*/
|
|
|
|
void CpuInit(void);
|
|
void CpuReset(void);
|
|
void CpuSave(void);
|
|
void OneStep(void);
|
|
void CpuIntRequest(enum IntRequest ireq);
|
|
void CpuWake(void);
|
|
void Emulator(void);
|
|
void EmulatorIntRequest(void);
|
|
void EmulatorInit(void); /* 2.1 */
|
|
void EmulatorExit(enum ExitOption opt); /* 2.1 */
|
|
int CpuHaltRequest(void); /* 3.13 */
|
|
int CpuRunRequest(void); /* 3.13 */
|
|
int CpuHaltAllowed(void); /* 3.13 */
|
|
|
|
Address Disassemble(Address pc, char ob[DISASSEMBLE_OB_SIZE]);
|
|
void DumpCpuStatus(char ob[DUMP_CPU_STATUS_OB_SIZE]);
|