home *** CD-ROM | disk | FTP | other *** search
- From: mrapple@quack.sac.ca.us (Nick Sayer)
- Newsgroups: alt.sources
- Subject: Z-80 emulator in C with CP/M BIOS (part 2/2)
- Message-ID: <kDCdLS0@quack.sac.ca.us>
- Date: 8 Nov 90 17:18:49 GMT
-
-
- #!/bin/sh
- # this is foo.02 (part 2 of a multipart archive)
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file z80.c continued
- #
- if touch 2>&1 | fgrep '[-amc]' > /dev/null
- then TOUCH=touch
- else TOUCH=true
- fi
- if test ! -r shar3_seq_.tmp; then
- echo "Please unpack part 1 first!"
- exit 1
- fi
- (read Scheck
- if test "$Scheck" != 2; then
- echo "Please unpack part $Scheck next!"
- exit 1
- else
- exit 0
- fi
- ) < shar3_seq_.tmp || exit 1
- echo "x - Continuing file z80.c"
- sed 's/^X//' << 'SHAR_EOF' >> z80.c &&
- X
- X/* If last instruction was a HALT, we're out of here - NOT what a real
- X Z-80 does, of course. */
- X
- X }
- X while (!STOP_FLAG);
- X}
- X
- Xz80_instr()
- X{
- X BYTE opcode,op_p1,op_p2,op_p3,op_p13;
- X
- X opcode=z80_mem(PC++);
- X op_p1=opcode&0x7; /* Piece 1 - bottom 3 bits */
- X op_p2=(opcode&0x38)>>3; /* Piece 2 - middle 3 bits */
- X op_p3=(opcode&0xC0)>>6; /* Piece 3 - top 2 bits */
- X op_p13=(opcode&0xC7); /* Piece 1 and 3 OR'ed */
- X
- X/*
- X
- XNow we perform what amounts to just a bunch of ifs...
- X
- XSections noted as Z-80 only are not present on the 8080. To make
- Xan 8080 interpreter, comment these sections out. This is not
- Xstrictly necessary, however, since an 8080 program (e.g. CP/M)
- Xwill run just fine on a Z-80.
- X
- XFirst take care of the multi-byte opcodes. These are Z-80 only.
- X
- X*/
- X
- X if (opcode==0xCB)
- X {
- X dlog("CB:");
- X cb_ops(HL); /* see notes in z80_cbed.c */
- X return;
- X }
- X if (opcode==0xFD || opcode==0xDD)
- X {
- X dlog(opcode==0xFD?"FD:":"DD:");
- X ixy_ops(opcode==0xFD); /* pass 1 if IY */
- X return;
- X }
- X if (opcode==0xED)
- X {
- X dlog("ED:");
- X ed_ops();
- X return;
- X }
- X
- X/*
- X
- XNOP & HALT
- X
- X*/
- X
- X if (opcode==0x00) /* NOP */
- X {
- X dlog("NOP\n");
- X return;
- X }
- X
- X if (opcode==0x76) /* HALT */
- X {
- X STOP_FLAG++;
- X PC--;
- X dlog("HALT\n");
- X return;
- X }
- X
- X/*
- X
- XInterrupt control: EI, DI
- X
- X*/
- X
- X if (opcode==0xFB) /* EI */
- X {
- X INT_FLAGS|=0x20; /* counter decremented after this & next instr */
- X dlog("EI\n");
- X return;
- X }
- X
- X if (opcode==0xF3) /* DI */
- X {
- X INT_FLAGS&=~(IFF1|IFF2);
- X dlog("DI\n");
- X return;
- X }
- X/*
- X
- XExchange group: EX, EXX
- X
- X*/
- X
- X if (opcode==0x08) /* EX AF,AF' [Z-80 only] */
- X {
- X register WORD temp;
- X temp=AF; AF=AF2; AF2=temp;
- X dlog("EX AF,AF'\n");
- X return;
- X }
- X if (opcode==0xEB) /* EX DE,HL */
- X {
- X register WORD temp;
- X temp=DE; DE=HL; HL=temp;
- X dlog("EX DE,HL\n");
- X return;
- X }
- X if (opcode==0xE3) /* EX (SP),HL */
- X {
- X register WORD temp;
- X temp=z80_mem(SP)|(z80_mem(SP+1)<<8);
- X wr_z80_mem(SP,HL&0xff); wr_z80_mem(SP+1,HL>>8);
- X HL=temp;
- X dlog("EX (SP),HL\n");
- X return;
- X }
- X if (opcode==0xD9) /* EXX [Z-80 only] */
- X {
- X register WORD temp;
- X temp=BC; BC=BC2; BC2=temp;
- X temp=DE; DE=DE2; DE2=temp;
- X temp=HL; HL=HL2; HL2=temp;
- X dlog("EXX\n");
- X return;
- X }
- X
- X/*
- X
- XExecution control: JP, JR, CALL, RET, RST
- X
- X*/
- X
- X if (opcode==0xC3) /* JP uncond */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X PC=operand;
- X dlog("JP 0x%04x\n",PC);
- X return;
- X }
- X
- X if (op_p13==0xC2) /* JP conditional */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X switch(op_p2)
- X {
- X case 0: if (~AF&FLAG_Z)
- X PC=operand;
- X break;
- X case 1: if (AF&FLAG_Z)
- X PC=operand;
- X break;
- X case 2: if (~AF&FLAG_C)
- X PC=operand;
- X break;
- X case 3: if (AF&FLAG_C)
- X PC=operand;
- X break;
- X case 4: if (~AF&FLAG_PV)
- X PC=operand;
- X break;
- X case 5: if (AF&FLAG_PV)
- X PC=operand;
- X break;
- X case 6: if (~AF&FLAG_S)
- X PC=operand;
- X break;
- X case 7: if (AF&FLAG_S)
- X PC=operand;
- X }
- X dlog("JP %c%c, 0x%04x\n",
- X "NZ ZNC CPOPE P M"[(op_p2<<1)],
- X "NZ ZNC CPOPE P M"[(op_p2<<1)+1],
- X operand);
- X return;
- X }
- X
- X if (opcode==0xE9) /* JP (HL) */
- X {
- X PC=HL; /* The old 8080 called this instruction "PCHL" */
- X dlog("JP (HL)\n");
- X return;
- X }
- X
- X if (opcode==0x10) /* DJNZ [Z-80 only] */
- X {
- X register BYTE operand;
- X
- X operand=z80_mem(PC++);
- X BC-= 0x100; /* B-- */
- X if ( BC>>8 )
- X DO_JR;
- X dlog("DJNZ 0x%04x\n",PC);
- X return;
- X }
- X
- X if (opcode==0x18) /* JR [Z-80 only] */
- X {
- X register BYTE operand;
- X
- X operand=z80_mem(PC++);
- X DO_JR;
- X dlog("JR 0x%04x\n",PC);
- X return;
- X }
- X
- X if ((opcode&0xE7)==0x20) /* JR cond [Z-80 only] */
- X {
- X register BYTE operand;
- X
- X operand=z80_mem(PC++);
- X
- X/* if the flag in question is false and the 4th bit is false */
- X
- X#define XOR(a,b) ( (a!=0) != (b!=0) ) /* logical XOR, not standard C */
- X
- X if ( XOR ( (AF&((opcode&0x10)?FLAG_C:FLAG_Z)) , !(opcode&0x08) ) )
- X DO_JR;
- X dlog("JR %d,0x%04x\n",opcode,PC);
- X return;
- X }
- X
- X if (opcode==0xCD) /* CALL */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X push(PC);
- X PC=operand;
- X dlog("CALL 0x%04x\n",PC);
- X return;
- X }
- X
- X if (op_p13==0xC4) /* CALL cond */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X
- X switch(op_p2)
- X {
- X case 0:if (~AF&FLAG_Z)
- X {
- X push(PC);
- X PC=operand;
- X }
- X break;
- X case 1:if (AF&FLAG_Z)
- X {
- X push(PC);
- X PC=operand;
- X }
- X break;
- X case 2:if (~AF&FLAG_C)
- X {
- X push(PC);
- X PC=operand;
- X }
- X break;
- X case 3:if (AF&FLAG_C)
- X {
- X push(PC);
- X PC=operand;
- X }
- X break;
- X case 4:if (~AF&FLAG_PV)
- X {
- X push(PC);
- X PC=operand;
- X }
- X break;
- X case 5:if (AF&FLAG_PV)
- X {
- X push(PC);
- X PC=operand;
- X }
- X break;
- X case 6:if (~AF&FLAG_S)
- X {
- X push(PC);
- X PC=operand;
- X }
- X break;
- X case 7:if (AF&FLAG_S)
- X {
- X push(PC);
- X PC=operand;
- X }
- X break;
- X }
- X dlog("CALL %c%c, 0x%04x\n","NZ ZNC CPOPE P M"[(op_p2<<1)],
- X "NZ ZNC CPOPE P M"[(op_p2<<1)+1],
- X PC);
- X return;
- X }
- X
- X if (opcode==0xC9) /* RET */
- X {
- X PC=pop();
- X dlog("RET\n");
- X return;
- X }
- X
- X if (op_p13==0xC0) /* RET cond */
- X {
- X switch(op_p2)
- X {
- X case 0:if (~AF&FLAG_Z)
- X PC=pop();
- X break;
- X case 1:if (AF&FLAG_Z)
- X PC=pop();
- X break;
- X case 2:if (~AF&FLAG_C)
- X PC=pop();
- X break;
- X case 3:if (AF&FLAG_C)
- X PC=pop();
- X break;
- X case 4:if (~AF&FLAG_PV)
- X PC=pop();
- X break;
- X case 5:if (AF&FLAG_PV)
- X PC=pop();
- X break;
- X case 6:if (~AF&FLAG_S)
- X PC=pop();
- X break;
- X case 7:if (AF&FLAG_S)
- X PC=pop();
- X break;
- X }
- X dlog("RET %c%c\n","NZ ZNC CPOPE P M"[op_p2<<1],
- X "NZ ZNC CPOPE P M"[(op_p2<<1)+1]);
- X return;
- X }
- X
- X if (op_p13==0xC7) /* RST ?? */
- X {
- X push(PC);
- X PC=op_p2<<3;
- X dlog("RST 0x%02x\n",PC);
- X return;
- X }
- X
- X/*
- X
- XLD
- X
- X*/
- X
- X if (opcode==0x3A) /* LD A,(imm) */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X AF=(AF&0x00ff)|z80_mem(operand)<<8;
- X dlog("LD A,(0x%04x)\n",operand);
- X return;
- X }
- X if (opcode==0x32) /* LD (imm),A */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X wr_z80_mem(operand,AF>>8);
- X dlog("LD (0x%04x),A\n",operand);
- X return;
- X }
- X if ((opcode&0xEF)==0x0A) /* LD A,(rp) */
- X {
- X AF=(AF&0xff)|z80_mem((opcode&0x10)?DE:BC)<<8;
- X dlog("LD A,(%s)\n",(opcode&0x10)?"DE":"BC");
- X return;
- X }
- X if ((opcode&0xEF)==0x02) /* LD (rp),A */
- X {
- X wr_z80_mem((opcode&0x10)?DE:BC,AF>>8);
- X dlog("LD (%s),A\n",(opcode&0x10)?"DE":"BC");
- X return;
- X }
- X if (op_p3==0x1) /* LD reg,reg [and (HL) too] */
- X {
- X register BYTE value;
- X switch(op_p1)
- X {
- X case 0:value=BC>>8; break;
- X case 1:value=BC&0xff; break;
- X case 2:value=DE>>8; break;
- X case 3:value=DE&0xff; break;
- X case 4:value=HL>>8; break;
- X case 5:value=HL&0xff; break;
- X case 6:value=z80_mem(HL); break;
- X case 7:value=AF>>8; break;
- X }
- X switch(op_p2)
- X {
- X case 0:BC=(BC&0xff)|(value<<8); break;
- X case 1:BC=(BC&0xff00)|value; break;
- X case 2:DE=(DE&0xff)|(value<<8); break;
- X case 3:DE=(DE&0xff00)|value; break;
- X case 4:HL=(HL&0xff)|(value<<8); break;
- X case 5:HL=(HL&0xff00)|value; break;
- X case 6:wr_z80_mem(HL,value); break;
- X case 7:AF=(AF&0xff)|(value<<8); break;
- X }
- X dlog("LD %c,%c\n","BCDEHLMA"[op_p2],"BCDEHLMA"[op_p1]);
- X return;
- X }
- X if (opcode==0x2A) /* LD HL,(imm) */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X HL=z80_mem(operand)|(z80_mem(operand+1)<<8);
- X dlog("LD HL,(0x%04x)\n",operand);
- X return;
- X }
- X if (opcode==0x22) /* LD (imm),HL */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X wr_z80_mem(operand,HL&0xff);
- X wr_z80_mem(operand+1,HL>>8);
- X dlog("LD (0x%04x),HL\n",operand);
- X return;
- X }
- X if (op_p13==0x06) /* LD reg,imm and LD (HL),imm */
- X {
- X register BYTE operand;
- X
- X operand=z80_mem(PC++);
- X
- X switch (op_p2)
- X {
- X case 0:BC=(BC&0xff)|(operand<<8);
- X break;
- X case 1:BC=(BC&0xff00)|operand;
- X break;
- X case 2:DE=(DE&0xff)|(operand<<8);
- X break;
- X case 3:DE=(DE&0xFF00)|operand;
- X break;
- X case 4:HL=(HL&0xff)|(operand<<8);
- X break;
- X case 5:HL=(HL&0xff00)|operand;
- X break;
- X case 6:wr_z80_mem(HL,operand);
- X break;
- X case 7:AF=(AF&0xff)|(operand<<8);
- X break;
- X }
- X dlog("LD %c,0x%x\n","BCDEHLMA"[op_p2],operand);
- X return;
- X }
- X if ((opcode&0xCF)==0x01) /* LD rp,imm */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X
- X switch ((opcode&0x30)>>4)
- X {
- X case 0:BC=operand;
- X dlog("LD BC,");
- X break;
- X case 1:DE=operand;
- X dlog("LD DE,");
- X break;
- X case 2:HL=operand;
- X dlog("LD HL,");
- X break;
- X case 3:SP=operand;
- X dlog("LD SP,");
- X break;
- X }
- X dlog("0x%04x\n",operand);
- X return;
- X }
- X if (opcode==0xF9) /* LD SP,HL */
- X {
- X SP=HL;
- X dlog("LD SP,HL\n");
- X return;
- X }
- X
- X/*
- X
- XPUSH & POP
- X
- X*/
- X
- X if ((opcode&0xCF)==0xC5) /* PUSH rp */
- X {
- X switch ((opcode>>4)&3)
- X {
- X case 0:push(BC); break;
- X case 1:push(DE); break;
- X case 2:push(HL); break;
- X case 3:push(AF); break;
- X break;
- X }
- X dlog("PUSH %c%c\n","BDHA"[(opcode>>4)&3],"CELF"[(opcode>>4)&3]);
- X return;
- X }
- X
- X if ((opcode&0xCF)==0xC1) /* POP rp */
- X {
- X switch ((opcode>>4)&3)
- X {
- X case 0:BC=pop(); break;
- X case 1:DE=pop(); break;
- X case 2:HL=pop(); break;
- X case 3:AF=pop(); break;
- X break;
- X }
- X dlog("POP %c%c\n","BDHA"[(opcode>>4)&3],"CELF"[(opcode>>4)&3]);
- X return;
- X }
- X
- X/*
- X
- XMATH & LOGICAL instructions
- X
- X*/
- X
- X if (op_p13==0x03) /* 16 bit INC/DEC */
- X {
- X switch(op_p2>>1)
- X {
- X case 0:BC+=(op_p2&0x1)?-1:1;
- X break;
- X case 1:DE+=(op_p2&0x1)?-1:1;
- X break;
- X case 2:HL+=(op_p2&0x1)?-1:1;
- X break;
- X case 3:SP+=(op_p2&0x1)?-1:1;
- X break;
- X }
- X dlog("%s %c%c\n",(op_p2&1)?"DEC":"INC","BDHS"[op_p2>>1],"CELP"[op_p2>>1]);
- X return;
- X }
- X
- X if ((op_p13&0xFE)==0x04) /* 8 bit INC/DEC */
- X {
- X char temp;
- X BYTE dir; WORD t;
- X
- X temp=AF&FLAG_C; /* save carry flag */
- X
- X dir=(op_p1&0x1)?~0:1; /* which direction? */
- X
- X switch(op_p2)
- X {
- X case 0:BC=(BC&0xff)|(alu_add(BC>>8,dir)<<8);
- X break;
- X case 1:BC=(BC&0xff00)|alu_add(BC&0xff,dir);
- X break;
- X case 2:DE=(DE&0xff)|(alu_add(DE>>8,dir)<<8);
- X break;
- X case 3:DE=(DE&0xff00)|alu_add(DE&0xff,dir);
- X break;
- X case 4:HL=(HL&0xff)|(alu_add(HL>>8,dir)<<8);
- X break;
- X case 5:HL=(HL&0xff00)|alu_add(HL&0xff,dir);
- X break;
- X case 6:wr_z80_mem(HL,alu_add(z80_mem(HL),dir));
- X break;
- X case 7:t=alu_add(AF>>8,dir); AF&=0xff; AF|=t<<8;
- X break;
- X }
- X AF=(AF&~FLAG_N)|((opcode&1)?FLAG_N:0);
- X AF=(AF&~FLAG_C)|temp; /* restore carry flag */
- X dlog("%s %c\n",(dir==1)?"INC":"DEC","BCDEHLMA"[op_p2]);
- X return;
- X }
- X
- X if (op_p3==0x2) /* 8 bit ADD, ADC, SUB, SBC, AND, OR, XOR, CMP */
- X {
- X WORD t;
- X switch(op_p2)
- X {
- X case 0: /* ADD */
- X switch(op_p1)
- X {
- X case 0:t=alu_add(AF>>8,BC>>8)<<8; AF&=0xff; AF|=t;
- X break;
- X case 1:t=alu_add(AF>>8,BC&0xff)<<8; AF&=0xff; AF|=t;
- X break;
- X case 2:t=alu_add(AF>>8,DE>>8)<<8; AF&=0xff; AF|=t;
- X break;
- X case 3:t=alu_add(AF>>8,DE&0xff)<<8; AF&=0xff; AF|=t;
- X break;
- X case 4:t=alu_add(AF>>8,HL>>8)<<8; AF&=0xff; AF|=t;
- X break;
- X case 5:t=alu_add(AF>>8,HL&0xff)<<8; AF&=0xff; AF|=t;
- X break;
- X case 6:t=alu_add(AF>>8,z80_mem(HL))<<8; AF&=0xff; AF|=t;
- X break;
- X case 7:t=alu_add(AF>>8,AF>>8)<<8; /* Sigh */ AF&=0xff; AF|=t;
- X break;
- X }
- X dlog("ADD %c\n","BCDEHLMA"[op_p1]);
- X break;
- X case 1: /* ADC */
- X switch(op_p1)
- X {
- X case 0:t=alu_adc(AF>>8,BC>>8)<<8; AF&=0xff; AF|=t;
- X break;
- X case 1:t=alu_adc(AF>>8,BC&0xff)<<8; AF&=0xff; AF|=t;
- X break;
- X case 2:t=alu_adc(AF>>8,DE>>8)<<8; AF&=0xff; AF|=t;
- X break;
- X case 3:t=alu_adc(AF>>8,DE&0xff)<<8; AF&=0xff; AF|=t;
- X break;
- X case 4:t=alu_adc(AF>>8,HL>>8)<<8; AF&=0xff; AF|=t;
- X break;
- X case 5:t=alu_adc(AF>>8,HL&0xff)<<8; AF&=0xff; AF|=t;
- X break;
- X case 6:t=alu_adc(AF>>8,z80_mem(HL))<<8; AF&=0xff; AF|=t;
- X break;
- X case 7:t=alu_adc(AF>>8,AF>>8)<<8; /* Sigh */ AF&=0xff; AF|=t;
- X break;
- X }
- X dlog("ADC %c\n","BCDEHLMA"[op_p1]);
- X break;
- X case 2: /* SUB */
- X switch(op_p1)
- X {
- X case 0:t=alu_sub(AF>>8,BC>>8)<<8; AF&=0xff; AF|=t;
- X break;
- X case 1:t=alu_sub(AF>>8,BC&0xff)<<8; AF&=0xff; AF|=t;
- X break;
- X case 2:t=alu_sub(AF>>8,DE>>8)<<8; AF&=0xff; AF|=t;
- X break;
- X case 3:t=alu_sub(AF>>8,DE&0xff)<<8; AF&=0xff; AF|=t;
- X break;
- X case 4:t=alu_sub(AF>>8,HL>>8)<<8; AF&=0xff; AF|=t;
- X break;
- X case 5:t=alu_sub(AF>>8,HL&0xff)<<8; AF&=0xff; AF|=t;
- X break;
- X case 6:t=alu_sub(AF>>8,z80_mem(HL))<<8; AF&=0xff; AF|=t;
- X break;
- X case 7:t=alu_sub(AF>>8,AF>>8)<<8; /* Sigh */ AF&=0xff; AF|=t;
- X break;
- X }
- X dlog("SUB %c\n","BCDEHLMA"[op_p1]);
- X break;
- X case 3: /* SBC */
- X switch(op_p1)
- X {
- X case 0:t=alu_sbc(AF>>8,BC>>8)<<8; AF&=0xff; AF|=t;
- X break;
- X case 1:t=alu_sbc(AF>>8,BC&0xff)<<8; AF&=0xff; AF|=t;
- X break;
- X case 2:t=alu_sbc(AF>>8,DE>>8)<<8; AF&=0xff; AF|=t;
- X break;
- X case 3:t=alu_sbc(AF>>8,DE&0xff)<<8; AF&=0xff; AF|=t;
- X break;
- X case 4:t=alu_sbc(AF>>8,HL>>8)<<8; AF&=0xff; AF|=t;
- X break;
- X case 5:t=alu_sbc(AF>>8,HL&0xff)<<8; AF&=0xff; AF|=t;
- X break;
- X case 6:t=alu_sbc(AF>>8,z80_mem(HL))<<8; AF&=0xff; AF|=t;
- X break;
- X case 7:t=alu_sbc(AF>>8,AF>>8)<<8; /* Sigh */ AF&=0xff; AF|=t;
- X break;
- X }
- X dlog("SBC %c\n","BCDEHLMA"[op_p1]);
- X break;
- X case 4: /* AND */
- X switch (op_p1)
- X {
- X case 0:AF=(AF&0xff)|( ((AF>>8)&(BC>>8)) <<8 ); log_flags(AF>>8);
- X break;
- X case 1:AF=(AF&0xff)|( ((AF>>8)&(BC&0xff)) <<8 ); log_flags(AF>>8);
- X break;
- X case 2:AF=(AF&0xff)|( ((AF>>8)&(DE>>8)) <<8 ); log_flags(AF>>8);
- X break;
- X case 3:AF=(AF&0xff)|( ((AF>>8)&(DE&0xff)) <<8 ); log_flags(AF>>8);
- X break;
- X case 4:AF=(AF&0xff)|( ((AF>>8)&(HL>>8)) <<8 ); log_flags(AF>>8);
- X break;
- X case 5:AF=(AF&0xff)|( ((AF>>8)&(HL&0xff)) <<8 ); log_flags(AF>>8);
- X break;
- X case 6:AF=(AF&0xff)|( ((AF>>8)&(z80_mem(HL))) <<8 );
- X log_flags(AF>>8);
- X break;
- X case 7:AF=(AF&0xff)|( ((AF>>8)&(AF>>8)) <<8 ); log_flags(AF>>8);
- X break;
- X }
- X AF&=~FLAG_C;
- X dlog("AND %c\n","BCDEHLMA"[op_p1]);
- X break;
- X case 5: /* XOR */
- X switch (op_p1)
- X {
- X case 0:AF=(AF&0xff)|( ((AF>>8)^(BC>>8)) <<8 ); log_flags(AF>>8);
- X break;
- X case 1:AF=(AF&0xff)|( ((AF>>8)^(BC&0xff)) <<8 ); log_flags(AF>>8);
- X break;
- X case 2:AF=(AF&0xff)|( ((AF>>8)^(DE>>8)) <<8 ); log_flags(AF>>8);
- X break;
- X case 3:AF=(AF&0xff)|( ((AF>>8)^(DE&0xff)) <<8 ); log_flags(AF>>8);
- X break;
- X case 4:AF=(AF&0xff)|( ((AF>>8)^(HL>>8)) <<8 ); log_flags(AF>>8);
- X break;
- X case 5:AF=(AF&0xff)|( ((AF>>8)^(HL&0xff)) <<8 ); log_flags(AF>>8);
- X break;
- X case 6:AF=(AF&0xff)|( ((AF>>8)^(z80_mem(HL))) <<8 );
- X log_flags(AF>>8);
- X break;
- X case 7:AF=(AF&0xff)|( ((AF>>8)^(AF>>8)) <<8 ); log_flags(AF>>8);
- X break;
- X }
- X dlog("XOR %c\n","BCDEHLMA"[op_p1]);
- X AF&=~FLAG_C;
- X break;
- X case 6: /* OR */
- X switch (op_p1)
- X {
- X case 0:AF=(AF&0xff)|( ((AF>>8)|(BC>>8)) <<8 ); log_flags(AF>>8);
- X break;
- X case 1:AF=(AF&0xff)|( ((AF>>8)|(BC&0xff)) <<8 ); log_flags(AF>>8);
- X break;
- X case 2:AF=(AF&0xff)|( ((AF>>8)|(DE>>8)) <<8 ); log_flags(AF>>8);
- X break;
- X case 3:AF=(AF&0xff)|( ((AF>>8)|(DE&0xff)) <<8 ); log_flags(AF>>8);
- X break;
- X case 4:AF=(AF&0xff)|( ((AF>>8)|(HL>>8)) <<8 ); log_flags(AF>>8);
- X break;
- X case 5:AF=(AF&0xff)|( ((AF>>8)|(HL&0xff)) <<8 ); log_flags(AF>>8);
- X break;
- X case 6:AF=(AF&0xff)|( ((AF>>8)|(z80_mem(HL))) <<8 );
- X log_flags(AF>>8);
- X break;
- X case 7:AF=(AF&0xff)|( ((AF>>8)|(AF>>8)) <<8 ); log_flags(AF>>8);
- X break;
- X }
- X dlog("OR %c\n","BCDEHLMA"[op_p1]);
- X AF&=~FLAG_C;
- X break;
- X case 7: /* CMP */
- X switch(op_p1)
- X {
- X case 0:alu_sub(AF>>8,BC>>8);
- X break;
- X case 1:alu_sub(AF>>8,BC&0xff);
- X break;
- X case 2:alu_sub(AF>>8,DE>>8);
- X break;
- X case 3:alu_sub(AF>>8,DE&0xff);
- X break;
- X case 4:alu_sub(AF>>8,HL>>8);
- X break;
- X case 5:alu_sub(AF>>8,HL&0xff);
- X break;
- X case 6:alu_sub(AF>>8,z80_mem(HL));
- X break;
- X case 7:alu_sub(AF>>8,AF>>8); /* Sigh... What a waste */
- X break;
- X }
- X dlog("CMP %c\n","BCDEHLMA"[op_p1]);
- X }
- X return;
- X }
- X if (op_p13==0xC6) /* 8 bit math with immediate operands. */
- X {
- X register BYTE operand;
- X WORD t;
- X
- X operand=z80_mem(PC++);
- X
- X switch(op_p2)
- X {
- X case 0:t=alu_add(AF>>8,operand)<<8; AF&=0xff; AF|=t;
- X dlog("ADD 0x%02x\n",operand);
- X break;
- X case 1:t=alu_adc(AF>>8,operand)<<8; AF&=0xff; AF|=t;
- X dlog("ADC 0x%02x\n",operand);
- X break;
- X case 2:t=alu_sub(AF>>8,operand)<<8; AF&=0xff; AF|=t;
- X dlog("SUB 0x%02x\n",operand);
- X break;
- X case 3:t=alu_sbc(AF>>8,operand)<<8; AF&=0xff; AF|=t;
- X dlog("SBC 0x%02x\n",operand);
- X break;
- X case 4:AF=(AF&0xff)|( ((AF>>8)&operand) <<8 ); log_flags(AF>>8);
- X AF&=~FLAG_C;
- X dlog("AND 0x%02x\n",operand);
- X break;
- X case 5:AF=(AF&0xff)|( ((AF>>8)|operand) <<8 ); log_flags(AF>>8);
- X AF&=~FLAG_C;
- X dlog("OR 0x%02x\n",operand);
- X break;
- X case 6:AF=(AF&0xff)|( ((AF>>8)^operand) <<8 ); log_flags(AF>>8);
- X AF&=~FLAG_C;
- X dlog("XOR 0x%02x\n",operand);
- X break;
- X case 7:alu_sub(AF>>8,operand);
- X dlog("CMP 0x%02x\n",operand);
- X break;
- X }
- X
- X return;
- X }
- X
- X if ((opcode&0xCF)==0x09) /* ADD HL,rp */
- X {
- X register int temp;
- X
- X switch ((opcode&0x30)>>4)
- X {
- X case 0:temp=HL+BC; break;
- X case 1:temp=HL+DE; break;
- X case 2:temp=HL+HL; break;
- X case 3:temp=HL+SP; break;
- X }
- X HL=(WORD) temp;
- X AF=(AF&~FLAG_C)|((temp>0xffff)?FLAG_C:0);
- X AF&=~FLAG_N;
- X dlog("ADD HL,%c%c\n","BDHS"[op_p2>>1],"CELP"[op_p2>>1]);
- X return;
- X
- X }
- X
- X if (opcode==0x27) /* DAA */
- X {
- X WORD t;
- X if ( (((AF>>8)&0xf)>9) || (AF&FLAG_H) )
- X if (AF&FLAG_N)
- X { t=alu_sbc(AF>>8,6)<<8; AF&=0xff; AF|=t; }
- X else
- X { t=alu_add(AF>>8,6)<<8; AF&=0xff; AF|=t; }
- X if ( (AF&FLAG_C) || (((AF>>8)&0xf0)>0x90) )
- X if (AF&FLAG_N)
- X { t=alu_sbc(AF>>8,0x60)<<8; AF&=0xff; AF|=t; }
- X else
- X { t=alu_add(AF>>8,0x60)<<8; AF&=0xff; AF|=t; }
- X
- X dlog("DAA\n");
- X return;
- X }
- X
- X/*
- X
- XROTATES
- X
- X*/
- X
- X if ((opcode&0xE7)==0x07)
- X {
- X switch ((opcode&0x18)>>3)
- X {
- X case 0:if (AF&0x8000) /* RLCA */
- X {
- X AF=(AF&0xff)|((AF&0x7f00)<<1)|0x100|FLAG_C;
- X }
- X else
- X {
- X AF=(AF&0xff&~FLAG_C)|((AF&0x7f00)<<1);
- X }
- X dlog("RLCA\n");
- X break;
- X case 1:if (AF&0x100) /* RRCA */
- X {
- X AF=(AF&0xff)|((AF&0xfe00)>>1)|0x8000|FLAG_C;
- X }
- X else
- X {
- X AF=(AF&0xff&~FLAG_C)|((AF&0xfe00)>>1);
- X }
- X dlog("RRCA\n");
- X break;
- X case 2:if (AF&FLAG_C) /* RLA */
- X {
- X AF=(AF&~FLAG_C)|((AF&0x8000)?FLAG_C:0);
- X AF=(AF&0xff)|((AF&0x7f00)<<1)|0x100;
- X }
- X else
- X {
- X AF=(AF&~FLAG_C)|((AF&0x8000)?FLAG_C:0);
- X AF=(AF&0xff)|((AF&0x7f00)<<1);
- X }
- X dlog("RLA\n");
- X break;
- X case 3:if (AF&FLAG_C) /* RRA */
- X {
- X /* clr carry then set it if bit 0 set */
- X AF=(AF&~FLAG_C)|((AF&0x100)?FLAG_C:0);
- X /* set A to A>>1, then add in known carry on top */
- X AF=(AF&0xff)|((AF&0xfe00)>>1)|0x8000;
- X }
- X else
- X {
- X AF=(AF&~FLAG_C)|((AF&0x100)?FLAG_C:0);
- X AF=(AF&0xff)|((AF&0xfe00)>>1);
- X }
- X dlog("RRA\n");
- X break;
- X }
- X AF&=~(FLAG_H|FLAG_N); /* according to Z80 prod spec, p. 13 */
- X return;
- X }
- X
- X/*
- X
- XI/O
- X
- X*/
- X
- X if (opcode==0xD3) /* OUT (port),A */
- X {
- X wrport(z80_mem(PC++),AF>>8);
- X dlog("OUT (0x%02x),A\n",z80_mem(PC-1));
- X return;
- X }
- X
- X if (opcode==0xDB) /* IN A,(port) */
- X {
- X AF=(AF&0xff)|rdport(z80_mem(PC++))<<8;
- X dlog("IN A,(0x%02x)\n",z80_mem(PC-1));
- X return;
- X }
- X
- X/*
- X
- Xmisc - xCF, CPL
- X
- X*/
- X
- X if (opcode==0x3f) /* CCF */
- X {
- X AF^=FLAG_C;
- X AF&=~(FLAG_N);
- X dlog("CCF\n");
- X return;
- X }
- X
- X if (opcode==0x37) /* SCF */
- X {
- X AF|=FLAG_C;
- X AF&=~(FLAG_N|FLAG_H);
- X dlog("SCF\n");
- X return;
- X }
- X
- X if (opcode==0x2f) /* CPL */
- X {
- X AF^=0xff00;
- X AF|=FLAG_H|FLAG_N;
- X dlog("CPL\n");
- X return;
- X }
- X
- X/*
- X
- XWE SHOULD NEVER APPEAR HERE!!!!
- X
- XThere is no value of the first opcode byte of a Z-80 instruction that is
- Xinvalid. If we get here, the above code is severely hosed.
- X
- X*/
- X
- X printf("OH NO!!! PARSE ERROR - FIRST OPCODE BYTE!!!!!\n");
- X printf("PC = %4x (PC) = %2x\n\n",PC-1,opcode);
- X exit(99);
- X
- X}
- X
- X/*
- X
- Xadditional routines:
- X
- Xalu_adc takes two bytes and adds them, creating the proper effect
- Xon the flags register. For an add without carry, c=0. S, Z, C and H are
- Xset as defined. P/V is set to indicate overflow.
- X
- XFor 16 bit add, lo=add(lo(a),lo(b)); hi=add(hi(a),hi(b)+((AF&FLAG_C)!=0));
- XTHIS PRESUMES THAT != OPERATIONS ON YOUR COMPILER RETURN 0 OR 1!!!
- X
- X*/
- X
- XBYTE alu_adc(a,b) /* X+Y+c... */
- XWORD a,b;
- X{
- X BYTE answer;
- X answer = alu_add(a,b+((AF&FLAG_C)!=0));
- X return answer;
- X}
- X
- XBYTE alu_add(a,b) /* essentially, X+Y, set FLAG_C as needed */
- XWORD a,b;
- X{
- X
- X register BYTE answer=(a+b)&0xff;
- X register WORD flags=AF&0xff;
- X flags&= ~FLAG_N; /* Addition op */
- X flags=(flags&~FLAG_Z)|((answer==0)?FLAG_Z:0);
- X flags=(flags&~FLAG_S)|((answer&0x80)?FLAG_S:0);
- X
- X/* For the H flag, we chop to 1 nibble each and check LSB of hi nibble
- X for carry. Yuck! */
- X flags=(flags&~FLAG_H)|( (((a&0xf)+(b&0xf))&0x10) ?FLAG_H:0);
- X
- X/* Bring the operands out to WORD size, add and see if the result's too big. */
- X flags=(flags&~FLAG_C)|( ( (((WORD)a)+((WORD)b)) >0xff ) ?FLAG_C:0);
- X
- X/* The next one is complicated. It reads, "if the high bits of the operands
- X are the same, and the high bit of the first operand is different from
- X the high bit of the answer, overflow has occurred." Bleahack!!! */
- X
- X flags=(flags&~FLAG_PV) |(( ((a>0x7f)==(b>0x7f)) && ((a>0x7f)!=(answer>0x7f)))
- X ?FLAG_PV:0);
- X AF &= 0xff00; AF |= flags;
- X return answer;
- X}
- X
- XBYTE alu_sbc(a,b)
- XBYTE a,b;
- X{
- X BYTE answer;
- X AF ^= FLAG_C;
- X answer=alu_adc(a,(~b)&0xff);
- X AF ^= FLAG_C;
- X AF^=FLAG_H; /* same for half-carry */
- X AF|=FLAG_N; /* set for subtract op */
- X return answer;
- X}
- X
- XBYTE alu_sub(a,b)
- XBYTE a,b;
- X{
- X BYTE answer;
- X/* AF ^= FLAG_C; */
- X answer=alu_add(a,(0xff&~b)+1);
- X AF ^= FLAG_C;
- X AF^=FLAG_H; /* same for half-carry */
- X AF|=FLAG_N; /* set for subtract op */
- X return answer;
- X}
- X
- X/*
- X
- Xlog_flags - set flags after a logical operation. N & H =0, P/V set to
- Xindicate parity, S with sign, and Z if zero as expected.
- X
- X*/
- X
- Xlog_flags(a)
- XBYTE a;
- X{
- X char count=0,i;
- X
- X AF&=~(FLAG_N|FLAG_H);
- X AF=(AF&~FLAG_S)|((a&0x80)?FLAG_S:0);
- X AF=(AF&~FLAG_Z)|((a==0)?FLAG_Z:0);
- X
- X/* for(i=0;i<8;i++)
- X {
- X if (a&1)
- X count++;
- X a=a>>1;
- X }
- X AF=(AF&~FLAG_PV)|((count%2)?0:FLAG_PV);
- X*/
- X i = a;
- X i = (i & 0xf0) ^ ( (i&0x0f) << 4);
- X i = (i & 0xc0) ^ ( (i&0x30) << 2);
- X i = (i & 0x80) ^ ( (i&0x40) << 1);
- X AF=(AF&~FLAG_PV)|((0x80==i)?0:FLAG_PV);
- X}
- X
- X/*
- X
- XStack routines
- X
- Xpush & pop do the obvious.
- X
- X*/
- X
- Xpush(a)
- XWORD a;
- X{
- X wr_z80_mem(--SP,a>>8);
- X wr_z80_mem(--SP,a&0xff);
- X}
- X
- XWORD pop()
- X{
- X register WORD temp;
- X temp=z80_mem(SP++);
- X temp|=z80_mem(SP++)<<8;
- X return temp;
- X}
- X
- SHAR_EOF
- echo "File z80.c is complete" &&
- $TOUCH -am 0928182190 z80.c &&
- chmod 0644 z80.c ||
- echo "restore of z80.c failed"
- set `wc -c z80.c`;Wc_c=$1
- if test "$Wc_c" != "27243"; then
- echo original size 27243, current size $Wc_c
- fi
- # ============= z80.h ==============
- echo "x - extracting z80.h (Text)"
- sed 's/^X//' << 'SHAR_EOF' > z80.h &&
- X/*
- X
- Xz80.h - defines for the z80 emulator.
- X
- XCopyright MCMXC - Nick Sayer - All rights reserved.
- X
- XSee COPYRIGHT file for more info.
- X
- X
- XThere's only one configuration option. Some compilers have trouble
- Xwith signed chars, and that's how we do JR, so choose one of these
- Xtwo definitions to be used in the JR instructions
- X
- X*/
- X
- X
- X/* #define DO_JR PC+= (operand>127)?(-(256-operand)):(operand); */
- X#define DO_JR PC+= (char) operand /* */
- X/* #define DO_JR PC+= (operand>127)?256-(operand&0x7f):operand /* */
- X
- X/*
- X
- XGlobal types, data, and routines:
- X
- X*/
- X
- X#define BYTE unsigned char
- X#define WORD unsigned short
- X
- Xextern BYTE real_z80_mem[65536];
- X#define z80_mem(x) real_z80_mem[x]
- X#define wr_z80_mem(x,y) debug_write(x,y)
- Xextern WORD AF,BC,DE,HL,IX,IY,AF2,BC2,DE2,HL2,IR,PC,SP,INT_FLAGS;
- Xextern z80_instr(),z80_run(),wrport();
- Xextern BYTE rdport(),int_read();
- Xextern char INT,NMI,RESET;
- X
- X/*
- X
- Xflag bits - these represent positions within the AF register.
- X
- X*/
- X
- X#define FLAG_C 0x01
- X#define FLAG_N 0x02
- X#define FLAG_PV 0x04
- X#define FLAG_H 0x10
- X#define FLAG_Z 0x40
- X#define FLAG_S 0x80
- X
- X/*
- X
- XThe INT_FLAGS register doesn't really exist, we use it to store the IM status
- Xand the two IFF flags.
- X
- XIFTMP is a counter to allow EI to take effect after the NEXT
- Xinstruction.
- X
- X*/
- X
- X#define IM_STAT 0x03
- X#define IFF1 0x04
- X#define IFF2 0x08
- X#define IFTMP 0x30
- X
- X/*
- X
- XThese routines are internal. We include it here just to keep
- Xz80_cbed.c happy. Don't use 'em!!
- X
- X*/
- X
- XWORD pop();
- XBYTE alu_adc(),alu_sbc(),alu_sub(),alu_add();
- X
- Xint dlogflag;
- Xint debugflag;
- Xint biosflag;
- Xint TRAPval;
- Xint TWRTval;
- X
- X#define dlog if(dlogflag) printf
- X#define bioslog if(biosflag) printf
- X/* static void dlog() { return; } */
- SHAR_EOF
- $TOUCH -am 0928182190 z80.h &&
- chmod 0644 z80.h ||
- echo "restore of z80.h failed"
- set `wc -c z80.h`;Wc_c=$1
- if test "$Wc_c" != "1672"; then
- echo original size 1672, current size $Wc_c
- fi
- # ============= z80_cbed.c ==============
- echo "x - extracting z80_cbed.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > z80_cbed.c &&
- X/*
- X
- Xz80_cbed.c - Z-80 microprocessor emulator, part 2.
- X
- XCopyright MCMXC - Nick Sayer - All rights reserved.
- X
- XSee COPYRIGHT file for details.
- X
- Xv0.0 - 04/08/90 - epoch
- Xv0.0A0 - 04/13/90 - alpha-test.
- Xv0.0A1 - 08/03/90 - alpha-test 2.
- Xv0.0A2 - 09/04/90 - alpha-test 3.
- X
- XCB, ED, and DD/FD ops:
- X
- Xcb_ops(mem);
- XWORD mem;
- X
- Xed_ops();
- X
- Xixy_ops(iy_reg);
- Xchar iy_reg;
- X
- Xcb_ops called if first opcode byte is CB. PC points to byte after the
- XCB. CB is passed the location of the "M" register. See comments before
- Xcb_ops() for details.
- X
- Xed_ops called if first opcode byte is ED.
- X
- Xixy_ops similarly called if first opcode byte is DD or FD. iy_reg true for FD.
- X
- X*/
- X
- X#include "z80.h"
- X
- Xed_ops()
- X{
- X BYTE op2,op2_p1,op2_p2,op2_p3,op2_p13;
- X
- X op2=z80_mem(PC++);
- X op2_p1=op2&0x7;
- X op2_p2=(op2&0x38)>>3;
- X op2_p3=(op2&0xC0)>>6;
- X op2_p13=op2&0xC7;
- X
- X/* Now another horrendous if statement string... */
- X
- X if (op2_p13==0x42) /* SBC/ADC HL,rp */
- X {
- X register WORD temp,temp2,sub_flag=0;
- X
- X switch(op2_p2)
- X {
- X case 0:temp=BC; sub_flag++; break;
- X case 1:temp=BC; break;
- X case 2:temp=DE; sub_flag++; break;
- X case 3:temp=DE; break;
- X case 4:temp=HL; sub_flag++; break;
- X case 5:temp=HL; break;
- X case 6:temp=SP; sub_flag++; break;
- X case 7:temp=SP; break;
- X }
- X if (sub_flag)
- X {
- X temp2=alu_sbc(HL&0xff,temp&0xff);
- X AF^=FLAG_C; /* proper chaining! */
- X HL=temp2|(alu_sbc(HL>>8,(temp>>8))<<8);
- X }
- X else
- X {
- X temp2=alu_adc(HL&0xff,temp&0xff);
- X HL=temp2|(alu_adc(HL>>8,temp>>8)<<8);
- X }
- X return;
- X }
- X
- X if (op2_p13==0x43) /* LD (imm),rp & rp,(imm) */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X switch(op2_p2)
- X {
- X case 0:wr_z80_mem(operand,BC&0xff); wr_z80_mem(operand+1,BC>>8); break;
- X case 1:BC=z80_mem(operand)|(z80_mem(operand+1)<<8); break;
- X case 2:wr_z80_mem(operand,DE&0xff); wr_z80_mem(operand+1,DE>>8); break;
- X case 3:DE=z80_mem(operand)|(z80_mem(operand+1)<<8); break;
- X case 4:wr_z80_mem(operand,HL&0xff); wr_z80_mem(operand+1,HL>>8); break;
- X case 5:HL=z80_mem(operand)|(z80_mem(operand+1)<<8); break;
- X case 6:wr_z80_mem(operand,SP&0xff); wr_z80_mem(operand+1,SP>>8); break;
- X case 7:SP=z80_mem(operand)|(z80_mem(operand+1)<<8); break;
- X }
- X return;
- X }
- X
- X if ((op2&0xF7)==0x67) /* RLD or RRD */
- X {
- X register BYTE temp;
- X
- X if (op2&0x8)
- X {
- X temp=z80_mem(HL)>>4;
- X wr_z80_mem(HL,(z80_mem(HL)<<4)|((AF&0x0f00)>>8));
- X AF=(AF&0xf0ff)|(temp<<8);
- X }
- X else
- X {
- X temp=z80_mem(HL)&0xf;
- X wr_z80_mem(HL,(z80_mem(HL)>>4)|((AF&0x0f00)>>4));
- X AF=(AF&0xf0ff)|(temp<<8);
- X }
- X log_flags(AF>>8);
- X
- X return;
- X }
- X
- X if (op2_p13==0x40) /* IN reg,(C) */
- X {
- X switch (op2_p2)
- X {
- X case 0:BC=(HL&0xff)|(rdport(BC&0xff)<<8); break;
- X case 1:BC=(BC&0xff00)|rdport(BC&0xff); break;
- X case 2:DE=(DE&0xff)|(rdport(BC&0xff)<<8); break;
- X case 3:DE=(DE&0xff00)|rdport(DE&0xff); break;
- X case 4:HL=(HL&0xff)|(rdport(BC&0xff)<<8); break;
- X case 5:HL=(HL&0xff00)|rdport(BC&0xff); break;
- X case 6:wr_z80_mem(HL,rdport(BC&0xff)); break;/* is this REALLY true? */
- X case 7:AF=(AF&0xFF)|(rdport(BC&0xff)<<8); break;
- X }
- X return;
- X }
- X
- X if (op2_p13==0x41) /* OUT (C),reg */
- X {
- X switch (op2_p2)
- X {
- X case 0:wrport(BC&0xff,BC>>8); break;
- X case 1:wrport(BC&0xff,BC&0xff); break;
- X case 2:wrport(BC&0xff,DE>>8); break;
- X case 3:wrport(BC&0xff,DE&0xff); break;
- X case 4:wrport(BC&0xff,HL>>8); break;
- X case 5:wrport(BC&0xff,HL&0xff); break;
- X case 6:wrport(BC&0xff,z80_mem(HL)); break; /* Is this REALLY true? */
- X case 7:wrport(BC&0xff,AF>>8); break;
- X }
- X return;
- X }
- X
- X if (op2==0x44) /* NEG */
- X {
- X WORD t;
- X t=alu_sub(0,AF>>8)<<8; AF&=0xff; AF|=t;
- X return;
- X }
- X
- X if (op2==0x45) /* RETN */
- X {
- X /* restore IFF1 from IFF2 */
- X INT_FLAGS=(INT_FLAGS&~IFF1)|((INT_FLAGS&IFF2)?IFF1:0);
- X PC=pop();
- X return;
- X }
- X
- X if (op2==0x4D) /* RETI */
- X {
- X PC=pop();
- X return;
- X }
- X
- X if ((op2&0xE7)==0x46) /* IM ? */
- X {
- X INT_FLAGS&=~IM_STAT;
- X switch ((op2&0x18)>>3)
- X {
- X case 0: /* IM 0 - we're done! */
- X break;
- X case 2:INT_FLAGS|=1; /* IM 1 - perverse, isn't it? */
- X break;
- X case 3:INT_FLAGS|=2; /* IM 2 */
- X }
- X return;
- X }
- X
- X if ((op2&0xE7)==0x47) /* moves involving I & R */
- X {
- X switch((op2&0x10)>>4) /* which way? */
- X {
- X case 1:switch ((op2&0x8)>>3) /* which reg? */
- X {
- X case 0:AF=(AF&0xff)|(IR&0xff00); break; /* A,I */
- X case 1:AF=(AF&0xff)|(IR<<8); break; /* A,R */
- X }
- X AF=(AF&~(FLAG_H|FLAG_N));
- X AF=(AF&~FLAG_PV)|((INT_FLAGS&IFF1)?FLAG_PV:0);
- X AF=(AF&~FLAG_S)|((AF&0x8000)?FLAG_S:0);
- X AF=(AF&~FLAG_Z)|(((AF>>8)==0)?FLAG_Z:0);
- X break;
- X case 0:switch ((op2&0x8)>>3)
- X {
- X case 0:IR=(IR&0xff)|(AF&0xff00); break; /* I,A */
- X case 1:IR=(IR&0xff00)|(AF>>8); break; /* R,A */
- X }
- X break;
- X }
- X return;
- X }
- X
- X/*
- X
- X{LD,CP,OT,IN}[ID][R] instructions (e.g. LDIR, OTD, etc)
- X
- X*/
- X
- X if ((op2&0xE4)==0xA0)
- X {
- X register BYTE dir;
- X register BYTE repeat;
- X
- X dir=op2&0x8;
- X repeat=op2&0x10;
- X switch (op2&3)
- X {
- X case 0:wr_z80_mem(DE,z80_mem(HL));
- X if (dir)
- X DE--,HL--;
- X else
- X DE++,HL++;
- X BC--;
- X AF=AF&~(FLAG_N|FLAG_H);
- X AF=(AF&FLAG_PV)|((BC==0)?FLAG_PV:0);
- X if (repeat && BC)
- X PC-= 2;
- X break;
- X case 1:alu_sbc(AF>>8,z80_mem(HL));
- X if (dir)
- X HL--;
- X else
- X HL++;
- X BC--;
- X AF=(AF&FLAG_PV)|((BC==0)?FLAG_PV:0);
- X if (repeat && BC && !(AF&FLAG_Z))
- X PC-= 2;
- X break;
- X case 2:wr_z80_mem(HL,rdport(BC&0xff));
- X if (dir)
- X HL--;
- X else
- X HL++;
- X BC-=0x100;
- X AF=FLAG_N|(AF&FLAG_Z)|(((BC>>8)==0)?FLAG_Z:0);
- X if (repeat && (BC>>8))
- X PC-= 2;
- X break;
- X case 3:wrport(BC&0xff,z80_mem(HL));
- X if (dir)
- X HL--;
- X else
- X HL++;
- X BC-= 0x100;
- X AF=FLAG_N|(AF&FLAG_Z)|(((BC>>8)==0)?FLAG_Z:0);
- X if (repeat && (BC>>8))
- X PC-= 2;
- X break;
- X }
- X return;
- X }
- X
- X/* I don't know if there are any unparsable ED ops or not. If
- X we get here, crash'n'burn */
- X
- X printf("OH NO!!!!! PARSE ERROR - 2nd opcode - ED ops\n");
- X printf("PC = %4x (PC) = %2x\n\n",PC-1,op2);
- X exit(99);
- X
- X}
- X
- X/*
- X
- XCB operations can also be activated with index registers, e.g.
- XBIT 0,(IY+5). The opcodes for this are FD CB 05 46. In machine-type
- Xlanguage, this says "use index register IY+5 instead of HL for
- Xthe operation "CB 46". The operation "CB 46" says BIT 6,(HL). This
- Xis in fact how all the index operations work. The opcode after
- XFD/ED relates in some way to (HL). Its just as easy to rewrite
- Xthe small portion of the opcode table relating to index registers
- Xin this file, but for CB ops, it's just easier to pass the
- Xaddress to the CB parser it should use if (HL) is referred to.
- XIf we are parsing a straight CB op, this routine is called
- Xwith the contents of HL. If it's an FD/ED op, we call it with
- XIX/IY + d. Calling this number "mem" is a throwback to the 8080.
- X(HL) was called "M" the meta-register "memory." LD A,(HL) was written
- X"MOV A,M". That sort of thing can be seen all over in the opcode
- Xtable - especially the math and load ops. register "M" was number 6 in
- Xthe numbering scheme (BCDEHLMA).
- X
- XThe problem with doing this is that if we're passed a CB op from the
- XFD/ED parser, and that op doesn't refer to mem, it will act as if the
- Xindex register is not involved. But such an op would have unpredictable
- Xresults on a real Z-80 anyway. fnord.
- X
- X*/
- X
- Xcb_ops(mem)
- XWORD mem;
- X{
- X register BYTE op2,op_typ,op_reg;
- X
- X op2=z80_mem(PC++);
- X op_typ=(op2&0x38)>>3;
- X op_reg=op2&0x7;
- X
- X/* And off we go again... */
- X
- X switch((op2&0xC0)>>6)
- X {
- X case 1: /* BIT */
- X switch(op_reg)
- X {
- X case 0:AF=(AF&~FLAG_Z)|((BC&(1<<(op_typ+8)))?0:FLAG_Z); break;
- X case 1:AF=(AF&~FLAG_Z)|((BC&(1<<op_typ))?0:FLAG_Z); break;
- X case 2:AF=(AF&~FLAG_Z)|((DE&(1<<(op_typ+8)))?0:FLAG_Z); break;
- X case 3:AF=(AF&~FLAG_Z)|((DE&(1<<op_typ))?0:FLAG_Z); break;
- X case 4:AF=(AF&~FLAG_Z)|((HL&(1<<(op_typ+8)))?0:FLAG_Z); break;
- X case 5:AF=(AF&~FLAG_Z)|((HL&(1<<op_typ))?0:FLAG_Z); break;
- X case 6:AF=(AF&~FLAG_Z)|((z80_mem(mem)&(1<<op_typ))?0:FLAG_Z); break;
- X case 7:AF=(AF&~FLAG_Z)|((AF&(1<<(op_typ+8)))?0:FLAG_Z); break;
- X }
- X AF|=FLAG_H;
- X AF&=~FLAG_N;
- X break;
- X case 2: /* RES */
- X switch(op_reg)
- X {
- X case 0:BC&=~(1<<(op_typ+8)); break;
- X case 1:BC&=~(1<<op_typ); break;
- X case 2:DE&=~(1<<(op_typ+8)); break;
- X case 3:DE&=~(1<<op_typ); break;
- X case 4:HL&=~(1<<(op_typ+8)); break;
- X case 5:HL&=~(1<<op_typ); break;
- X case 6:wr_z80_mem(mem,z80_mem(mem)&~(1<<op_typ)); break;
- X case 7:AF&=~(1<<(op_typ+8)); break;
- X }
- X break;
- X case 3: /* SET */
- X switch(op_reg)
- X {
- X case 0:BC|=1<<(op_typ+8); break;
- X case 1:BC|=1<<op_typ; break;
- X case 2:DE|=1<<(op_typ+8); break;
- X case 3:DE|=1<<op_typ; break;
- X case 4:HL|=1<<(op_typ+8); break;
- X case 5:HL|=1<<op_typ; break;
- X case 6:wr_z80_mem(mem,z80_mem(mem)|1<<op_typ); break;
- X case 7:AF|=1<<(op_typ+8); break;
- X }
- X break;
- X case 0: /* Additional rotate/shift section */
- X {
- X register BYTE temp,temp2;
- X
- X switch(op_reg) /* get it out */
- X {
- X case 0:temp=((BC&0xff00)>>8); break;
- X case 1:temp=BC&0xff; break;
- X case 2:temp=((DE&0xff00)>>8); break;
- X case 3:temp=DE&0xff; break;
- X case 4:temp=((HL&0xff00)>>8); break;
- X case 5:temp=HL&0xff; break;
- X case 6:temp=z80_mem(mem); break;
- X case 7:temp=((AF&0xff00)>>8); break;
- X }
- X switch(op_typ)
- X {
- X case 0: /* RLC */
- X temp=(temp<<1)|((temp&0x80)?1:0);
- X log_flags(temp);
- X AF=(AF&~FLAG_C)|((temp&1)?FLAG_C:0);
- X break;
- X case 1: /* RRC */
- X temp=(temp>>1)|((temp&1)?0x80:0);
- X log_flags(temp);
- X AF=(AF&~FLAG_C)|((temp&0x80)?FLAG_C:0);
- X break;
- X case 2: /* RL */
- X temp2=temp&0x80;
- X temp=(temp<<1)|((AF&FLAG_C)?1:0);
- X log_flags(temp);
- X AF=(AF&~FLAG_C)|(temp2?FLAG_C:0);
- X break;
- X case 3: /* RR */
- X temp2=temp&0x1;
- X temp=(temp>>1)|((AF&FLAG_C)?0x80:0);
- X log_flags(temp);
- X AF=(AF&~FLAG_C)|(temp2?FLAG_C:0);
- X break;
- X case 4: /* SLA */
- X AF=(AF&~FLAG_C)|((temp&0x80)?FLAG_C:0);
- X temp=temp<<1;
- X log_flags(temp);
- X break;
- X case 5: /* SRA */
- X AF=(AF&~FLAG_C)|((temp&1)?FLAG_C:0);
- X temp=(temp>>1)|((temp&0x80)?0x80:0);
- X log_flags(temp);
- X break;
- X case 6: /* NOT USED - NOP */
- X break;
- X case 7: /* SRL */
- X AF=(AF&~FLAG_C)|((temp&1)?FLAG_C:0);
- X temp=temp>>1;
- X log_flags(temp);
- X break;
- X }
- X switch(op_reg) /* put it back */
- X {
- X case 0:BC=(BC&0xff)|(temp<<8); break;
- X case 1:BC=(BC&0xff00)|temp; break;
- X case 2:DE=(DE&0xff)|(temp<<8); break;
- X case 3:DE=(DE&0xff00)|temp; break;
- X case 4:HL=(HL&0xff)|(temp<<8); break;
- X case 5:HL=(HL&0xff00)|temp; break;
- X case 6:wr_z80_mem(mem,temp); break;
- X case 7:AF=(AF&0xff)|(temp<<8); break;
- X }
- X }
- X break;
- X }
- X
- X/* This parser is a little different. It's normal to get here. Don't
- X crash'n'burn */
- X
- X return;
- X}
- X
- X/* this'll help \/ */
- X
- X#define INDEX_VALUE ((IY_FLAG)?IY+d:IX+d)
- X
- Xixy_ops(IY_FLAG)
- Xchar IY_FLAG; /* true for IY */
- X{
- X register BYTE op2;
- X register BYTE d;
- X
- X op2=z80_mem(PC++);
- X d=z80_mem(PC++); /* DANGER WILL ROBINSON!!! Better fix this
- X for PUSH, INC et all */
- X
- X/* And away they go!... */
- X
- X if (op2==0xCB) /* CB ops */
- X {
- X cb_ops(INDEX_VALUE);
- X return;
- X }
- X
- X if ((op2&0xC0)==0x40) /* LD (I?+d),reg or reg,(I?+d) */
- X {
- X register BYTE value;
- X switch((op2&0x38)>>3)
- X {
- X case 0:value=BC>>8; break;
- X case 1:value=BC&0xff; break;
- X case 2:value=DE>>8; break;
- X case 3:value=DE&0xff; break;
- X case 4:value=HL>>8; break;
- X case 5:value=HL&0xff; break;
- X case 6:value=z80_mem(INDEX_VALUE); break;
- X case 7:value=AF>>8; break;
- X }
- X switch(op2&0x7)
- X {
- X case 0:BC=(BC&0xff)|(value<<8); break;
- X case 1:BC=(BC&0xff00)|value; break;
- X case 2:DE=(DE&0xff)|(value<<8); break;
- X case 3:DE=(DE&0xff00)|value; break;
- X case 4:HL=(HL&0xff)|(value<<8); break;
- X case 5:HL=(HL&0xff00)|value; break;
- X case 6:wr_z80_mem(INDEX_VALUE,value); break;
- X case 7:AF=(AF&0xff)|(value<<8); break;
- X }
- X
- X return;
- X }
- X
- X if (op2==0x36) /* LD (I?+d),imm */
- X {
- X wr_z80_mem(INDEX_VALUE,z80_mem(PC++));
- X return;
- X }
- X
- X if ((op2&0xFE)==0x34) /* INC/DEC (I?+d) */
- X {
- X switch (op2&1)
- X {
- X case 0:wr_z80_mem(INDEX_VALUE,alu_add(z80_mem(INDEX_VALUE),1));
- X break;
- X case 1:wr_z80_mem(INDEX_VALUE,alu_sub(z80_mem(INDEX_VALUE),1));
- X break;
- X }
- X return;
- X }
- X
- X if ((op2&0xC7)==0x86) /* MATH OPS (I?+d) */
- X {
- X WORD t;
- X switch((op2&0x38)>>3)
- X {
- X case 0:t=alu_add(AF>>8,z80_mem(INDEX_VALUE))<<8; AF&=0xff; AF|=t; /* ADD */
- X break;
- X case 1:t=alu_adc(AF>>8,z80_mem(INDEX_VALUE))<<8; AF&=0xff; AF|=t; /* ADC */
- X break;
- X case 2:t=alu_sub(AF>>8,z80_mem(INDEX_VALUE))<<8; AF&=0xff; AF|=t; /* SUB */
- X break;
- X case 3:t=alu_sbc(AF>>8,z80_mem(INDEX_VALUE))<<8; AF&=0xff; AF|=t; /* SBC */
- X break;
- X case 4:AF=(AF&0xff)|(((AF>>8) & z80_mem(INDEX_VALUE))<<8);
- X log_flags(AF>>8);
- X /* AND */
- X break;
- X case 5:AF=(AF&0xff)|(((AF>>8) ^ z80_mem(INDEX_VALUE))<<8);
- X log_flags(AF>>8);
- X /* XOR */
- X break;
- X case 6:AF=(AF&0xff)|(((AF>>8) | z80_mem(INDEX_VALUE))<<8);
- X log_flags(AF>>8);
- X /* OR */
- X break;
- X case 7:alu_sub(AF>>8,z80_mem(INDEX_VALUE)); /* CMP */
- X break;
- X }
- X
- X return;
- X }
- X
- X/* From here on are ops that don't involve d. For these, we
- X must decrement the PC to make up for the extra increment we did
- X to fetch d in the first place. d must be the opcode for the
- X next instruction. */
- X
- X PC--;
- X d=0; /* this makes our macro work. What a yucky hack! */
- X
- X if (op2==0x21) /* LD I?,imm */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X if (IY_FLAG)
- X IY=operand;
- X else
- X IX=operand;
- X
- X return;
- X }
- X if (op2==0x22) /* LD (imm),I? */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X
- X wr_z80_mem(operand,INDEX_VALUE&0xff);
- X wr_z80_mem(operand+1,INDEX_VALUE>>8);
- X
- X return;
- X }
- X if (op2==0x2A) /* LD I?,(imm) */
- X {
- X register WORD operand;
- X
- X operand=z80_mem(PC++);
- X operand|=z80_mem(PC++)<<8;
- X
- X if (IY_FLAG)
- X IY=z80_mem(operand)|(z80_mem(operand+1)<<8);
- X else
- X IX=z80_mem(operand)|(z80_mem(operand+1)<<8);
- X
- X return;
- X }
- X
- X if ((op2&0xCF)==0x09) /* ADD I?,rp */
- X {
- X register int temp;
- X
- X switch ((op2&0x30)>>4)
- X {
- X case 0:temp=INDEX_VALUE+BC; break;
- X case 1:temp=INDEX_VALUE+DE; break;
- X case 2:temp=INDEX_VALUE+HL; break;
- X case 3:temp=INDEX_VALUE+SP; break;
- X }
- X if (IY_FLAG)
- X IY=(WORD) temp;
- X else
- X IX=(WORD) temp;
- X AF|=((temp>0xffff)?FLAG_C:0);
- X AF&=~FLAG_N;
- X return;
- X }
- X
- X if (op2==0x23) /* INC I? */
- X {
- X if (IY_FLAG)
- X IY++;
- X else
- X IX++;
- X
- X return;
- X }
- X if (op2==0x2B) /* DEC I? */
- X {
- X if (IY_FLAG)
- X IY--;
- X else
- X IX--;
- X
- X return;
- X }
- X if (op2==0xE1) /* POP I? */
- X {
- X if (IY_FLAG)
- X IY=pop();
- X else
- X IX=pop();
- X
- X return;
- X }
- X if (op2==0xE5) /* PUSH I? */
- X {
- X push(INDEX_VALUE);
- X return;
- X }
- X if (op2==0xE9) /* JP (I?) */
- X {
- X PC=INDEX_VALUE;
- X return;
- X }
- X if (op2==0xE3) /* EX (SP),I? */
- X {
- X register WORD temp;
- X
- X temp=z80_mem(SP)|(z80_mem(SP+1)<<8);
- X wr_z80_mem(SP,INDEX_VALUE&0xff);
- X wr_z80_mem(SP+1,INDEX_VALUE>>8);
- X if (IY_FLAG)
- X IY=temp;
- X else
- X IX=temp;
- X
- X return;
- X }
- X if (op2==0xF9) /* LD SP,I? */
- X {
- X SP=INDEX_VALUE;
- X return;
- X }
- X
- X/* There are undefined ED/FD ops. What do we do about it? Good
- X question. My theory says crash-n-burn. */
- X
- X printf("OH NO!!!!! PARSE ERROR 2nd operand, Index ops\n");
- X printf("PC = %4x (PC) = %2x\n\n",PC-1,op2);
- X
- X exit(99);
- X}
- SHAR_EOF
- $TOUCH -am 0928182190 z80_cbed.c &&
- chmod 0644 z80_cbed.c ||
- echo "restore of z80_cbed.c failed"
- set `wc -c z80_cbed.c`;Wc_c=$1
- if test "$Wc_c" != "16492"; then
- echo original size 16492, current size $Wc_c
- fi
- rm -f shar3_seq_.tmp
- echo "You have unpacked the last part"
- exit 0
- --
- Nick Sayer | Disclaimer: "Don't try this at home, | RIP: Mel Blanc
- mrapple@quack.sac.ca.us | kids. This should only be done by | 1908-1989
- N6QQQ [44.2.1.17] | trained, professional idiots." | May he never
- 209-952-5347 (Telebit) | --Plucky Duck | be silenced.
-