📄 cpu.c
字号:
/* Z80Sim - A simulator/debugger for the Zilog Z80 processor Copyright (C) 2003 Lorenzo J. Lucchini 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include "types.h"#include "sizes.h"#include "cpu.h"#include "opcodes.h"#include "symbols.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#define METACALL_QUIT 0x00#define METACALL_PUTCHARACTER 0x01#define METACALL_GETCLOCK 0x02#define METACALL_ENTER 0x03#define METACALL_EXIT 0x04#define METACALL_ENTERLEAF 0x05#define METACALL_DUMPREGS 0x06#define METACALL_PUTWORD 0x07#define METACALL_WRITEPROTECT 0x08#define METACALL_READPROTECT 0x09#define METACALL_RWPROTECT 0x0a#define METACALL_UNPROTECT 0x0b#define PROTECT_WRITE 1<<0#define PROTECT_READ 1<<1typedef union { word Word; struct { byte L; byte H; } Bytes;} reg;inline byte ReadMemory(word Address);void WriteMemory(word Address, byte Value);void Push(word);void Pop(word*);byte Memory[SIZE_MEMORY];short Protections[SIZE_MEMORY];byte IR;reg AF, SP, PC;reg BC, DE;reg HL, IX, IY;reg AF1;reg BC1, DE1;reg HL1;logic InterruptRequest;logic EnableInterrupts;logic IFF1, IFF2;logic FlagZ, FlagNZ;logic FlagC, FlagNC;logic FlagPO, FlagPE;logic FlagM, FlagP;logic FlagN, FlagH;logic Flag3, Flag5;unsigned long TStates;unsigned long InstructionsExecuted;logic UsefulInstruction;logic Indexing;logic IndirectMemoryWrite;logic MemoryWrite;byte MemoryData;word MemoryAddress;reg* PointerReg;byte Index;trap Exception;#warning FIXME: DOES NOT GIVE THE RIGHT T-STATES, SHOULD BE MOVED OUT OF OperandR AND THE RESTint PHLOverhead;// Protect a zone of the main memory as specified by Flagsvoid ProtectRange(word Start, word End, short Flags) { int i; for(i=Start; i<=End; i++) { Protections[i]=Flags; }}// Return the bit specifying the sign in a 2's complement value of type 'byte'.inline logic SignBit(byte Value) { if(Value&0x80) return TRUE; else return FALSE;}// Return TRUE if the parity of Byte is even, otherwise FALSE.inline logic Parity(byte Byte) { byte Temp; Temp=Byte; Temp=Temp^(Temp>>4); Temp=Temp^(Temp>>2); Temp=Temp^(Temp>>1); return ((Temp&1)!=0?FALSE:TRUE);}// Copy the contents of the Flag* logic variables into the actual F register.void StoreFlags() { assert(FlagZ==!FlagNZ); assert(FlagC==!FlagNC); assert(FlagPE==!FlagPO); assert(FlagP==!FlagM); AF.Bytes.L=( (FlagC?(1<<0):0) | (FlagN?(1<<1):0) | (FlagPE?(1<<2):0)| (Flag3?(1<<3):0) | (FlagH?(1<<4):0) | (Flag5?(1<<5):0) | (FlagZ?(1<<6):0) | (FlagM?(1<<7):0) );}// Set the Flag* variables depending on the contents of Datum, except those// that cannot be inferred from it alone. Don't set the actual F register.// Also calculate parity and store it into FlagPE/FlagPO if GiveParity==TRUE.void SetFlags(byte Datum) { Flag3=(Datum&0x08)!=0; Flag5=(Datum&0x20)!=0; if(Datum==0) FlagZ=1; else FlagZ=0; FlagNZ=!FlagZ; FlagP=!SignBit(Datum); FlagM=!FlagP; FlagPE=Parity(Datum); FlagPO=!FlagPE;}// Add Operand to *Register, and store the result into *Register. Set the Flag*// variables accordingly.void AddByte(byte* Register, byte Operand) { byte Op1=*Register, Op2=Operand; long Sum; Sum=Op1+Op2; *Register=(byte)Sum; SetFlags(*Register); if((Op1&0x08)^(Op2&0x08)^(Sum&0x08)) FlagH=1; else FlagH=0; if(Sum>(word)0xFF) FlagNC=!(FlagC=1); else FlagC=!(FlagNC=1); if(SignBit(Op1)==SignBit(Op2) && SignBit(Sum)!=SignBit(Op1)) FlagPO=!(FlagPE=1); else FlagPO=!(FlagPE=0); FlagN=0; TStates+=4;}// Subtract Operand from *Register, and store the result into *Register. Set the Flag*// variables accordingly.void SubByte(byte* Register, byte Operand) { byte Op1=*Register, Op2=-Operand; long Sum; Sum=Op1+Op2; *Register=(byte)Sum; SetFlags(*Register); if((Op1&0x08)^(Op2&0x08)^(Sum&0x08)) FlagH=0; else FlagH=1; if(Sum>(word)0xFF) FlagNC=!(FlagC=0); else FlagC=!(FlagNC=0); if(SignBit(Op1)==SignBit(Op2) && SignBit(Sum)!=SignBit(Op1)) FlagPO=!(FlagPE=1); else FlagPO=!(FlagPE=0); FlagN=0; TStates+=4;}// As per AddByte(), but do it for two words, and only set the flags required by// a word addition.void AddWord(word* Register, word Operand) { long Sum; Sum=*Register+Operand; if(((*Register)&0x0F00)+(Operand&0x0F00)>0x0F00) FlagH=1; else FlagH=0; *Register=(word)Sum; if(Sum>0xFFFF) FlagNC=!(FlagC=1); else FlagC=!(FlagNC=1); FlagN=0; TStates+=11;}// Logical And of two bytes, store result into *Register and set the Flag*s.void And(byte* Register, byte Operand) { *Register=*Register&Operand; // Flags should be correct SetFlags(*Register); FlagNC=!(FlagC=0); FlagN=0; //StoreFlags(); TStates+=4;}// Logical exclusive Or of two bytes, store result into *Register and set the Flag*s.void XOr(byte* Register, byte Operand) { *Register=*Register^Operand; // Flags should be correct, but aren't SetFlags(*Register); FlagNC=!(FlagC=0); FlagN=0; FlagH=0; //StoreFlags(); TStates+=4;}// Logical Or of two bytes, store result into *Register and set the Flag*s.void Or(byte* Register, byte Operand) { *Register=*Register|Operand; // Flags should be correct SetFlags(*Register); FlagNC=!(FlagC=0); FlagN=0; //StoreFlags(); TStates+=4;}// Subtract Operand to *Register; don't store the result anywhere, only set the Flag*s.void Compare(byte* Register, byte Operand) { byte Temp=*Register; SubByte(&Temp, Operand); FlagN=1; TStates+=4;}// Fetch a direct operand of the length of a word (16 bits).word GetWordOperand() { reg WordOperand; WordOperand.Bytes.L=ReadMemory(PC.Word++); WordOperand.Bytes.H=ReadMemory(PC.Word++); return WordOperand.Word;}// Branch to NewAddress.void JumpAbsolute(word NewAddress) { PC.Word=NewAddress; TStates+=10; UsefulInstruction=TRUE;}// Branch to PC+Index.void JumpRelative(byte Index) { PC.Word+=(word)(sbyte)Index; TStates+=12; UsefulInstruction=TRUE;}// Store PC into the stack, then branch to ProcAddress.void Call(word ProcAddress) { Push(PC.Word); JumpAbsolute(ProcAddress); TStates-=4;}// Push Register into the stack.void Push(word Register) { WriteMemory(SP.Word-2, (Register&0x00FF)>>0); WriteMemory(SP.Word-1, (Register&0xFF00)>>8); SP.Word-=2; TStates+=11;}// Pop a value from the stack and store it into *Register.void Pop(word* Register) { *Register=ReadMemory(SP.Word++); (*Register)|=ReadMemory(SP.Word++)<<8; if(Register==&AF.Word) { FlagNC=!(FlagC=(AF.Bytes.L>>0)&1); FlagNZ=!(FlagZ=(AF.Bytes.L>>6)&1); FlagPO=!(FlagPE=(AF.Bytes.L>>2)&1); FlagP=!(FlagM=(AF.Bytes.L>>7)&1); FlagN=(AF.Bytes.L>>1)&1; FlagH=(AF.Bytes.L>>4)&1; Flag3=(AF.Bytes.L>>3)&1; Flag5=(AF.Bytes.L>>5)&1; } TStates+=10;}// Swap two words.void Swap(word* Reg1, word* Reg2) { word Temp; Temp=*Reg1; *Reg1=*Reg2; *Reg2=Temp;}// Return the address of the register specified in Opcode, with Opcode being// a Z80 opcode whose bits 3..5 specify a register.byte* OperandR(byte Opcode) { if(OPARG_R_A(Opcode)) return &AF.Bytes.H; if(OPARG_R_B(Opcode)) return &BC.Bytes.H; if(OPARG_R_C(Opcode)) return &BC.Bytes.L; if(OPARG_R_D(Opcode)) return &DE.Bytes.H; if(OPARG_R_E(Opcode)) return &DE.Bytes.L; if(OPARG_R_H(Opcode)) return &HL.Bytes.H; if(OPARG_R_L(Opcode)) return &HL.Bytes.L; if(OPARG_R_PHL(Opcode)) { TStates+=PHLOverhead; IndirectMemoryWrite=TRUE; MemoryData=ReadMemory(PointerReg->Word+(word)(sbyte)Index); return &MemoryData; } fprintf(stdout, "ERROR: Unrecognized destination register\n"); return &AF.Bytes.H;}// Return the address of the register specified in Opcode, with Opcode being// a Z80 opcode whose bits 0..2 specify a register.byte* OperandS(byte Opcode) { if(OPARG_S_A(Opcode)) return &AF.Bytes.H; if(OPARG_S_B(Opcode)) return &BC.Bytes.H; if(OPARG_S_C(Opcode)) return &BC.Bytes.L; if(OPARG_S_D(Opcode)) return &DE.Bytes.H; if(OPARG_S_E(Opcode)) return &DE.Bytes.L; if(OPARG_S_H(Opcode)) return &HL.Bytes.H; if(OPARG_S_L(Opcode)) return &HL.Bytes.L; if(OPARG_S_PHL(Opcode)) { TStates+=PHLOverhead; MemoryData=ReadMemory(PointerReg->Word+(word)(sbyte)Index); return &MemoryData; } fprintf(stdout, "ERROR: Unrecognized source register\n"); return &AF.Bytes.H;}// Return the address of the register pair specified in Opcode, with Opcode// being a Z80 opcode whose bits 4 and 5 specify a register pair.word* OperandP(byte Opcode) { if(OPARG_P_BC(Opcode)) return &BC.Word; if(OPARG_P_DE(Opcode)) return &DE.Word; if(OPARG_P_HL(Opcode)) return &(PointerReg->Word); if(OPARG_P_SP(Opcode)) return &SP.Word; return NULL;}// Return the address of a Flag* variable as specified in Opcode, with// Opcode being a z80 opcode whose bits 3..5 specify a flag.logic* OperandF(byte Opcode) { if(OPARG_F_NZ(Opcode)) return &FlagNZ; if(OPARG_F_Z(Opcode)) return &FlagZ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -