home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume15
/
upm
/
part01
/
z80.c
< prev
Wrap
C/C++ Source or Header
|
1990-12-17
|
3KB
|
152 lines
/*
z80.c - Z-80 microprocessor emulator.
Copyright MCMXC - Nick Sayer - All rights reserved.
See COPYRIGHT file for details.
v0.0 - 04/08/90 - epoch
v0.0A0 - 04/13/90 - alpha-test.
v0.0A1 - 08/04/90 - alpha-test 2.
v0.0A2 - 09/04/90 - alpha-test 3.
global data types:
WORD = unsigned short - i.e. an address or register pair.
BYTE = unsigned char - i.e. a memory location or register.
global data:
BYTE z80_mem[65536];
WORD AF,BC,DE,HL,SP,PC,IX,IY,IR,AF2,BC2,DE2,HL2,INT_FLAGS;
global routines:
z80_run();
Start running at addr. PRESUMES PC AND OTHER REGISTERS SET PROPERLY!!!
Returns if Z-80 executes a HALT. Returns with PC set to address of HALT
instruction.
z80_instr();
Execute a single instruction.
wrport(addr,data);
BYTE addr,data;
BYTE rdport(addr);
BYTE addr;
These routines are called by the Z-80 when it wants to read or write
to the port-space.
char INT,NMI,RESET;
Each of these starts at 0. If some event makes any of these true, the
event each represents will take place. Think of them as the coresponding
wires that go into the CPU, except that in the real CPU these wires are
inverse logic.
BYTE int_read();
This routine called on an interrupt. It should return the proper
interrupt acknowledgement cycle data.
KNOWN "FEATURES":
This actually simulates a MOSTEK MK 3880. Whether or not this
device differs from the Zilog product, I don't know. But I
doubt it.
If you single-step using z80_instr(), memory refresh, interrupt
checking, and similar housekeeping will NOT take place.
If the processor is in interrupt mode 0, the int_read()
value MUST be an RST instruction.
Undefined opcode sequences WILL have truely bizarre and twisted
results. Count on it. Especially undefined DD/FD operations.
"Interrupting devices" at this time can't tell when an interrupt
service routine is finished. Normally they monitor the bus
waiting for a RETI instruction. There's no way to do that with
this code yet.
*/
#include "z80.h"
BYTE real_z80_mem[65536];
char STOP_FLAG; /* hack to stop us on HALT */
char INT=0,NMI=0,RESET=0;
WORD AF,BC,DE,HL,PC,SP,IX,IY,IR,AF2,BC2,DE2,HL2,INT_FLAGS;
int TRAPval = -1, lastPC = -1;
z80_run()
{
STOP_FLAG=0;
do
{
/* do an instruction */
if (PC == TRAPval) {
printf("\n\rTrapping at 0x%04x (last=0x%04x)\n\r",PC,lastPC);
debugit();
}
lastPC = PC;
z80_instr();
/* If we did an EI instruction before last, set both IFFs */
if (INT_FLAGS&IFTMP)
{
INT_FLAGS-=0x10;
if (!(INT_FLAGS&IFTMP))
INT_FLAGS|=IFF1|IFF2;
}
/* If an interrupt is pending and they're enabled, do it */
if (INT && INT_FLAGS&IFF1)
{
register WORD operand;
INT_FLAGS&=~(IFF1|IFF2);
push(PC);
switch (INT_FLAGS&IM_STAT)
{
case 0:PC=int_read()&0x38; /* DANGEROUSLY assumes an RST op... */
break;
case 1:PC=0x38; int_read(); /* we have to fetch, then spike it */
break;
case 2:operand=(IR&0xff80)|(int_read()&0xfe);
PC=z80_mem(operand)|(z80_mem(operand+1)<<8);
break;
}
INT=0;
}
/* If an NMI is pending, do it */
if (NMI)
{
INT_FLAGS&=~IFF1;
push(PC);
PC=0x66;
NMI=0;
}
/* if a RESET is pending, that has absolute priority */
if (RESET)
{
INT=0; NMI=0; RESET=0; INT_FLAGS=0; PC=0;
}
/* Now do a "refresh" cycle (really just increment low 7 bits of IR) */
IR=(IR&0xff00)|((IR+1)&0x7f);