/* Z80 emulator Copyright (c) 1996-2003,2004 Alessandro Scotti http://www.ascotti.org/ 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 "z80.h" // Table with parity, sign and zero flags precomputed for each byte value unsigned char Z80::PSZ_[256] = { Zero|Parity, 0, 0, Parity, 0, Parity, Parity, 0, 0, Parity, Parity, 0, Parity, 0, 0, Parity, 0, Parity, Parity, 0, Parity, 0, 0, Parity, Parity, 0, 0, Parity, 0, Parity, Parity, 0, 0, Parity, Parity, 0, Parity, 0, 0, Parity, Parity, 0, 0, Parity, 0, Parity, Parity, 0, Parity, 0, 0, Parity, 0, Parity, Parity, 0, 0, Parity, Parity, 0, Parity, 0, 0, Parity, 0, Parity, Parity, 0, Parity, 0, 0, Parity, Parity, 0, 0, Parity, 0, Parity, Parity, 0, Parity, 0, 0, Parity, 0, Parity, Parity, 0, 0, Parity, Parity, 0, Parity, 0, 0, Parity, Parity, 0, 0, Parity, 0, Parity, Parity, 0, 0, Parity, Parity, 0, Parity, 0, 0, Parity, 0, Parity, Parity, 0, Parity, 0, 0, Parity, Parity, 0, 0, Parity, 0, Parity, Parity, 0, Sign, Sign|Parity, Sign|Parity, Sign, Sign|Parity, Sign, Sign, Sign|Parity, Sign|Parity, Sign, Sign, Sign|Parity, Sign, Sign|Parity, Sign|Parity, Sign, Sign|Parity, Sign, Sign, Sign|Parity, Sign, Sign|Parity, Sign|Parity, Sign, Sign, Sign|Parity, Sign|Parity, Sign, Sign|Parity, Sign, Sign, Sign|Parity, Sign|Parity, Sign, Sign, Sign|Parity, Sign, Sign|Parity, Sign|Parity, Sign, Sign, Sign|Parity, Sign|Parity, Sign, Sign|Parity, Sign, Sign, Sign|Parity, Sign, Sign|Parity, Sign|Parity, Sign, Sign|Parity, Sign, Sign, Sign|Parity, Sign|Parity, Sign, Sign, Sign|Parity, Sign, Sign|Parity, Sign|Parity, Sign, Sign|Parity, Sign, Sign, Sign|Parity, Sign, Sign|Parity, Sign|Parity, Sign, Sign, Sign|Parity, Sign|Parity, Sign, Sign|Parity, Sign, Sign, Sign|Parity, Sign, Sign|Parity, Sign|Parity, Sign, Sign|Parity, Sign, Sign, Sign|Parity, Sign|Parity, Sign, Sign, Sign|Parity, Sign, Sign|Parity, Sign|Parity, Sign, Sign, Sign|Parity, Sign|Parity, Sign, Sign|Parity, Sign, Sign, Sign|Parity, Sign|Parity, Sign, Sign, Sign|Parity, Sign, Sign|Parity, Sign|Parity, Sign, Sign|Parity, Sign, Sign, Sign|Parity, Sign, Sign|Parity, Sign|Parity, Sign, Sign, Sign|Parity, Sign|Parity, Sign, Sign|Parity, Sign, Sign, Sign|Parity }; /* Adds the specified byte op to the accumulator, adding carry. */ void Z80::addByte( unsigned char op, unsigned char cf ) { unsigned x = A + op; if( cf ) x++; // Add carry F = 0; if( !(x & 0xFF) ) F |= Zero; if( x & 0x80 ) F |= Sign; if( x >= 0x100 ) F |= Carry; /* Halfcarry is set on carry from the low order four bits. To see how to compute it, let's take a look at the following table, which shows the binary addition of two binary numbers: A B A+B ----------- 0 0 0 0 1 1 1 0 1 1 1 0 Note that if only the lowest bit is used, then A+B, A-B and A^B yield the same value. If we know A, B and the sum A+B+C, then C is easily derived: C = A+B+C - A - B, that is C = A+B+C ^ A ^ B. For the halfcarry, A and B above are the fifth bit of a byte, which corresponds to the value 0x10. So: Halfcarry = ((accumulator+operand+halfcarry) ^ accumulator ^ operand) & 0x10 Note that masking off all bits but one is important because we have worked all the math by using one bit only. */ if( (A ^ op ^ x) & 0x10 ) F |= Halfcarry; /* The overflow bit is set when the result is too large to fit into the destination register, causing a change in the sign bit. For a sum, we can only have overflow when adding two numbers that are both positive or both negative. For example 0x5E + 0x4B (94 + 75) yields 0xA9 (169), which fits into an 8-bit register only if it is interpreted as an unsigned number. If we consider the result as a signed integer, then 0xA9 corresponds to decimal -87 and we have overflow. Note that if we add two signed numbers of opposite sign then we cannot overflow the destination register, because the absolute value of the result will always fit in 7 bits, leaving the most significant bit free for use as a sign bit. We can code all the above concisely by noting that: ~(A ^ op) & 0x80 is true if and only if A and op have the same sign. Also: (x ^ op) & 0x80 is true if and only if the sum of A and op has taken a sign opposite to that of its operands. Thus the expression: ~(A ^ op) & (x ^ op) & 0x80 reads "A has the same sign as op, and the opposite as x", where x is the sum of A and op (and an optional carry). */ if( ~(A ^ op) & (x ^ op) & 0x80 ) F |= Overflow; A = x; } /* Subtracts the specified byte op from the accumulator, using carry as borrow from a previous operation. */ unsigned char Z80::subByte( unsigned char op, unsigned char cf ) { unsigned char x = A - op; if( cf ) x--; F = Subtraction; if( x == 0 ) F |= Zero; if( x & 0x80 ) F |= Sign; if( (x >= A) && (op | cf)) F |= Carry; // See addByte() for an explanation of the halfcarry bit if( (A ^ op ^ x) & 0x10 ) F |= Halfcarry; // See addByte() for an explanation of the overflow bit. The only difference here // is that for a subtraction we must check that the two operands have different // sign, because in fact A-B is A+(-B). Note however that since subtraction is not // symmetric, we have to use (x ^ A) to get the correct result, whereas for the // addition (x ^ A) is equivalent to (x ^ op) if( (A ^ op) & (x ^ A) & 0x80 ) F |= Overflow; return x; } /* Sets the interrupt mode to IM0, IM1 or IM2. */ void Z80::setInterruptMode( unsigned mode ) { if( mode <= 2 ) { iflags_ = (iflags_ & ~0x03) | mode; } } /* Calls a subroutine at the specified address. */ void Z80::callSub( unsigned addr ) { SP -= 2; writeWord( SP, PC ); // Save current program counter in the stack PC = addr & 0xFFFF; // Jump to the specified address } /* Decrements a byte value by one. Note that this is different from subtracting one from the byte value, because flags behave differently. */ unsigned char Z80::decByte( unsigned char b ) { F = Subtraction | (F & Carry); // Preserve the carry flag if( (b & 0x0F) == 0 ) F |= Halfcarry; --b; if( b == 0x7F ) F |= Overflow; if( b & 0x80 ) F |= Sign; if( b == 0 ) F |= Zero; return b; } /* Increments a byte value by one. Note that this is different from adding one to the byte value, because flags behave differently. */ unsigned char Z80::incByte( unsigned char b ) { ++b; F &= Carry; // Preserve the carry flag if( ! (b & 0x0F) ) F |= Halfcarry; if( b == 0x80 ) F |= Overflow; if( b & 0x80 ) F |= Sign; if( b == 0 ) F |= Zero; return b; } /* Reads one byte from port C, updating flags according to the rules of "IN r,(C)". */ unsigned char Z80::inpReg() { unsigned char r = env_.readPort( C ); F = (F & Carry) | PSZ_[r]; return r; } /* Performs a relative jump to the specified offset. */ void Z80::relJump( unsigned char o ) { int offset = (int)((char)o); PC = (unsigned)((int)PC + offset) & 0xFFFF; cycles_++; } /* Returns from a subroutine, popping the saved Program Counter from the stack. */ void Z80::retFromSub() { PC = readWord( SP ); SP += 2; } /* Rotates left one byte thru the carry flag. */ unsigned char Z80::rotateLeft( unsigned char op ) { unsigned char f = F; F = 0; if( op & 0x80 ) F |= Carry; op <<= 1; if( f & Carry ) op |= 0x01; F |= PSZ_[op]; return op; } /* Rotates left one byte copying the most significant bit (bit 7) in the carry flag. */ unsigned char Z80::rotateLeftCarry( unsigned char op ) { F = 0; if( op & 0x80 ) F |= Carry; op = (op << 1) | (op >> 7); F |= PSZ_[op]; return op; } /* Rotates right one byte thru the carry flag. */ unsigned char Z80::rotateRight( unsigned char op ) { unsigned char f = F; F = 0; if( op & 0x01 ) F |= Carry; op >>= 1; if( f & Carry ) op |= 0x80; F |= PSZ_[op]; return op; } /* Rotates right one byte copying the least significant bit (bit 0) in the carry flag. */ unsigned char Z80::rotateRightCarry( unsigned char op ) { F = 0; if( op & 0x01 ) F |= Carry; op = (op >> 1) | (op << 7); F |= PSZ_[op]; return op; } /* Shifts left one byte. */ unsigned char Z80::shiftLeft( unsigned char op ) { F = 0; if( op & 0x80 ) F |= Carry; op <<= 1; F |= PSZ_[op]; return op; } /* Shifts right one byte, preserving its sign (most significant bit). */ unsigned char Z80::shiftRightArith( unsigned char op ) { F = 0; if( op & 0x01 ) F |= Carry; op = (op >> 1) | (op & 0x80); F |= PSZ_[op]; return op; } /* Shifts right one byte. */ unsigned char Z80::shiftRightLogical( unsigned char op ) { F = 0; if( op & 0x01 ) F |= Carry; op >>= 1; F |= PSZ_[op]; return op; } /* Tests whether the specified bit of op is set. */ void Z80::testBit( unsigned char bit, unsigned char op ) { // Flags for a bit test operation are: // S, P: unknown // Z: set if bit is zero, reset otherwise // N: reset // H: set // C: unaffected // However, it seems that parity is always set like Z, so we emulate that as well. F = (F & (Carry | Sign)) | Halfcarry; if( (op & (1 << bit)) == 0 ) { // Bit is not set, so set the zero flag F |= Zero | Parity; } }