Files
2015-09-03 01:20:11 -07:00

724 lines
18 KiB
C

/*
PokeMini - Pokémon-Mini Emulator
Copyright (C) 2009-2012 JustBurn
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef MINXCPU_CORE
#define MINXCPU_CORE
#include <stdio.h>
#include <stdint.h>
#ifdef _BIG_ENDIAN
typedef union {
struct {
uint8_t X;
uint8_t I;
uint8_t H;
uint8_t L;
} B;
struct {
uint16_t H;
uint16_t L;
} W;
uint32_t D;
} MinxRegx;
#else
typedef union {
struct {
uint8_t L;
uint8_t H;
uint8_t I;
uint8_t X;
} B;
struct {
uint16_t L;
uint16_t H;
} W;
uint32_t D;
} MinxRegx;
#endif
#define MINX_FLAG_ZERO 0x01
#define MINX_FLAG_CARRY 0x02
#define MINX_FLAG_OVERFLOW 0x04
#define MINX_FLAG_SIGN 0x08
#define MINX_FLAG_BCD 0x10
#define MINX_FLAG_NIBBLE 0x20
#define MINX_FLAG_INTFLG 0x40
#define MINX_FLAG_INTOFF 0x80
#define MINX_FLAG_SAVE_NUL 0xF0
#define MINX_FLAG_SAVE_O 0xF4
#define MINX_FLAG_SAVE_CO 0xF6
#define MINX_FLAG_SAVE_COS 0xFE
// OnException() reasons
enum {
EXCEPTION_UNKNOWN_INSTRUCTION,
EXCEPTION_CRASH_INSTRUCTION,
EXCEPTION_UNSTABLE_INSTRUCTION,
EXCEPTION_DIVISION_BY_ZERO
};
// OnSleep() reasons
enum {
MINX_SLEEP_HALT,
MINX_SLEEP_STOP
};
// Status reasons
enum {
MINX_STATUS_NORMAL = 0, // Normal operation
MINX_STATUS_HALT = 1, // CPU during HALT
MINX_STATUS_STOP = 2, // CPU during STOP
MINX_STATUS_IRQ = 3, // Delay caused by hardware IRQ
};
// DebugHalt reasons
enum {
MINX_DEBUGHALT_RECEIVE,
MINX_DEBUGHALT_SUSPEND,
MINX_DEBUGHALT_RESUME,
};
#ifndef inline
#define inline __inline
#endif
// Signed 8-Bits to 16-Bits converter
static inline uint16_t S8_TO_16(int8_t a)
{
return (a & 0x80) ? (0xFF00 | a) : a;
}
typedef struct {
// Registers
MinxRegx BA; // Registers A, B
MinxRegx HL; // Registers L, H, I
MinxRegx X; // Registers X, XI
MinxRegx Y; // Registers Y, YI
MinxRegx SP; // Register SP
MinxRegx PC; // Registers PC, V
MinxRegx N; // for [N+#nn], I is written here too
uint8_t U1; // V Shadow 1
uint8_t U2; // V Shadow 2
uint8_t F; // Flags
uint8_t E; // Exception
uint8_t IR; // Last Instruction Register (for open-bus)
uint8_t Shift_U; // Shift U, set to 2 when: U modify, branch, return
uint8_t Status; // CPU Status (0 = Normal, 1 = Halt, 2 = Stoped, 3 = IRQ)
uint8_t IRQ_Vector; // IRQ Vector when Status is IRQ
uint8_t Reserved[28]; // Reserved bytes
} TMinxCPU;
// CPU registers
extern TMinxCPU MinxCPU;
// Callbacks (Must be coded by the user)
uint8_t MinxCPU_OnRead(int cpu, uint32_t addr);
void MinxCPU_OnWrite(int cpu, uint32_t addr, uint8_t data);
void MinxCPU_OnException(int type, uint32_t opc);
void MinxCPU_OnSleep(int type);
void MinxCPU_OnIRQHandle(uint8_t flag, uint8_t shift_u);
void MinxCPU_OnIRQAct(uint8_t intr);
// Functions
int MinxCPU_Create(void); // Create MinxCPU
void MinxCPU_Destroy(void); // Destroy MinxCPU
void MinxCPU_Reset(int hardreset); // Reset CPU
int MinxCPU_LoadState(FILE *fi, uint32_t bsize); // Load State
int MinxCPU_SaveState(FILE *fi); // Save State
int MinxCPU_Exec(void); // Execute 1 CPU instruction
int MinxCPU_CallIRQ(uint8_t IRQ); // Call an IRQ
// Helpers
static inline uint16_t ReadMem16(uint32_t addr)
{
return MinxCPU_OnRead(1, addr) + (MinxCPU_OnRead(1, addr+1) << 8);
}
static inline void WriteMem16(uint32_t addr, uint16_t data)
{
MinxCPU_OnWrite(1, addr, (uint8_t)data);
MinxCPU_OnWrite(1, addr+1, data >> 8);
}
static inline uint8_t Fetch8(void)
{
if (MinxCPU.PC.W.L & 0x8000) {
// Banked area
MinxCPU.IR = MinxCPU_OnRead(1, (MinxCPU.PC.W.L++ & 0x7FFF) | (MinxCPU.PC.B.I << 15));
} else {
// Unbanked area
MinxCPU.IR = MinxCPU_OnRead(1, MinxCPU.PC.W.L++);
}
return MinxCPU.IR;
}
static inline uint16_t Fetch16(void)
{
uint8_t LB = Fetch8();
return (Fetch8() << 8) | LB;
}
static inline void Set_U(uint8_t val)
{
if (val != MinxCPU.U2) MinxCPU.Shift_U = 2;
MinxCPU.U1 = val;
MinxCPU.U2 = MinxCPU.U1;
MinxCPU_OnIRQHandle(MinxCPU.F, MinxCPU.Shift_U);
}
// Instruction exec. prototypes
int MinxCPU_ExecCE(void);
int MinxCPU_ExecCF(void);
int MinxCPU_ExecSPCE(void);
int MinxCPU_ExecSPCF(void);
// Instructions Macros
static inline uint8_t ADD8(uint8_t A, uint8_t B)
{
register uint8_t RES;
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
switch (MinxCPU.F & 0x30) {
case 0x00: // Normal
RES = A + B;
if (RES == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES < A) MinxCPU.F |= MINX_FLAG_CARRY;
if ((((A ^ RES) & 0x80) != 0) && (((A ^ B) & 0x80) == 0)) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (RES & 128) MinxCPU.F |= MINX_FLAG_SIGN;
return RES & 0xFF;
case 0x10: // BCD
if ((uint8_t)((A & 15) + (B & 15)) >= 10) {
RES = A + B + 6;
} else {
RES = A + B;
}
if (RES >= 0xA0) RES += 0x60;
if (RES == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES < A) MinxCPU.F |= MINX_FLAG_CARRY;
return RES & 0xFF;
case 0x20: // Nibble
RES = (A & 15) + (B & 15);
if ((RES & 15) == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES >= 16) MinxCPU.F |= MINX_FLAG_CARRY;
if ((((A ^ RES) & 0x8) != 0) && (((A ^ B) & 0x8) == 0)) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (RES & 8) MinxCPU.F |= MINX_FLAG_SIGN;
return RES & 0x0F;
default: // BCD and Nibble
if ((uint8_t)((A & 15) + (B & 15)) >= 10) {
RES = (A & 15) + (B & 15) + 6;
} else {
RES = (A & 15) + (B & 15);
}
if ((RES & 15) == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES >= 16) MinxCPU.F |= MINX_FLAG_CARRY;
return RES & 0x0F;
}
}
static inline uint16_t ADD16(uint16_t A, uint16_t B)
{
register uint16_t RES;
RES = A + B;
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
if (RES == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES < A) MinxCPU.F |= MINX_FLAG_CARRY;
if ((((A ^ RES) & 0x8000) != 0) && (((A ^ B) & 0x8000) == 0)) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (RES & 0x8000) MinxCPU.F |= MINX_FLAG_SIGN;
return (uint16_t)RES;
}
static inline uint8_t ADC8(uint8_t A, uint8_t B)
{
register uint8_t RES;
register uint8_t CARRY = (MinxCPU.F & MINX_FLAG_CARRY) ? 1 : 0;
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
switch (MinxCPU.F & 0x30) {
case 0x00: // Normal
RES = A + B + CARRY;
if (RES == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES < A) MinxCPU.F |= MINX_FLAG_CARRY;
if ((((A ^ RES) & 0x80) != 0) && (((A ^ B) & 0x80) == 0)) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (RES & 128) MinxCPU.F |= MINX_FLAG_SIGN;
return RES & 0xFF;
case 0x10: // BCD
if ((uint8_t)((A & 15) + (B & 15) + CARRY) >= 10) {
RES = A + B + CARRY + 6;
} else {
RES = A + B + CARRY;
}
if (RES >= 0xA0) RES += 0x60;
if (RES == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES < A) MinxCPU.F |= MINX_FLAG_CARRY;
return RES & 0xFF;
case 0x20: // Nibble
RES = (A & 15) + (B & 15) + CARRY;
if ((RES & 15) == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES >= 16) MinxCPU.F |= MINX_FLAG_CARRY;
if ((((A ^ RES) & 0x8) != 0) && (((A ^ B) & 0x8) == 0)) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (RES & 8) MinxCPU.F |= MINX_FLAG_SIGN;
return RES & 0x0F;
default: // BCD and Nibble
if ((uint8_t)((A & 15) + (B & 15) + CARRY) >= 10) {
RES = (A & 15) + (B & 15) + CARRY + 6;
} else {
RES = (A & 15) + (B & 15) + CARRY;
}
if ((RES & 15) == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES >= 16) MinxCPU.F |= MINX_FLAG_CARRY;
return RES & 0x0F;
}
}
static inline uint16_t ADC16(uint16_t A, uint16_t B)
{
register uint16_t RES;
RES = A + B + ((MinxCPU.F & MINX_FLAG_CARRY) ? 1 : 0);
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
if (RES == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES < A) MinxCPU.F |= MINX_FLAG_CARRY;
if ((((A ^ RES) & 0x8000) != 0) && (((A ^ B) & 0x8000) == 0)) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (RES & 0x8000) MinxCPU.F |= MINX_FLAG_SIGN;
return (uint16_t)RES;
}
static inline uint8_t SUB8(uint8_t A, uint8_t B)
{
register uint8_t RES;
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
switch (MinxCPU.F & 0x30) {
case 0x00: // Normal
RES = A - B;
if (RES == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A < B) MinxCPU.F |= MINX_FLAG_CARRY;
if ((((A ^ RES) & 0x80) != 0) && (((A ^ B) & 0x80) != 0)) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (RES & 128) MinxCPU.F |= MINX_FLAG_SIGN;
return RES & 0xFF;
case 0x10: // BCD
if ((uint8_t)((A & 15) - (B & 15)) >= 10) {
RES = A - B - 6;
} else {
RES = A - B;
}
if (RES >= 0xA0) RES -= 0x60;
if (RES == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A < B) MinxCPU.F |= MINX_FLAG_CARRY;
return RES & 0xFF;
case 0x20: // Nibble
RES = (A & 15) - (B & 15);
if ((RES & 15) == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES >= 16) MinxCPU.F |= MINX_FLAG_CARRY;
if ((((A ^ RES) & 0x8) != 0) && (((A ^ B) & 0x8) != 0)) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (RES & 8) MinxCPU.F |= MINX_FLAG_SIGN;
return RES & 0x0F;
default: // BCD and Nibble
if ((uint8_t)((A & 15) - (B & 15)) >= 10) {
RES = (A & 15) - (B & 15) - 6;
} else {
RES = (A & 15) - (B & 15);
}
if ((RES & 15) == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES >= 16) MinxCPU.F |= MINX_FLAG_CARRY;
return RES & 0x0F;
}
}
static inline uint16_t SUB16(uint16_t A, uint16_t B)
{
register uint16_t RES;
RES = A - B;
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
if (RES == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A < B) MinxCPU.F |= MINX_FLAG_CARRY;
if ((((A ^ RES) & 0x8000) != 0) && (((A ^ B) & 0x8000) != 0)) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (RES & 0x8000) MinxCPU.F |= MINX_FLAG_SIGN;
return (uint16_t)RES;
}
static inline uint8_t SBC8(uint8_t A, uint8_t B)
{
register uint8_t RES;
register uint8_t CARRY = (MinxCPU.F & MINX_FLAG_CARRY) ? 1 : 0;
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
switch (MinxCPU.F & 0x30) {
case 0x00: // Normal
RES = A - B - CARRY;
if (RES == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A < B) MinxCPU.F |= MINX_FLAG_CARRY;
if ((((A ^ RES) & 0x80) != 0) && (((A ^ B) & 0x80) != 0)) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (RES & 128) MinxCPU.F |= MINX_FLAG_SIGN;
return RES & 0xFF;
case 0x10: // BCD
if ((uint8_t)((A & 15) - (B & 15) - CARRY) >= 10) {
RES = A - B - CARRY - 6;
} else {
RES = A - B - CARRY;
}
if (RES >= 0xA0) RES -= 0x60;
if (RES == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A < B) MinxCPU.F |= MINX_FLAG_CARRY;
return RES & 0xFF;
case 0x20: // Nibble
RES = (A & 15) - (B & 15) - CARRY;
if ((RES & 15) == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES >= 16) MinxCPU.F |= MINX_FLAG_CARRY;
if ((((A ^ RES) & 0x8) != 0) && (((A ^ B) & 0x8) != 0)) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (RES & 8) MinxCPU.F |= MINX_FLAG_SIGN;
return RES & 0x0F;
default: // BCD and Nibble
if ((uint8_t)((A & 15) - (B & 15) - CARRY) >= 10) {
RES = (A & 15) - (B & 15) - CARRY - 6;
} else {
RES = (A & 15) - (B & 15) - CARRY;
}
if ((RES & 15) == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (RES >= 16) MinxCPU.F |= MINX_FLAG_CARRY;
return RES & 0x0F;
}
}
static inline uint16_t SBC16(uint16_t A, uint16_t B)
{
register uint16_t RES;
RES = A - B - ((MinxCPU.F & MINX_FLAG_CARRY) ? 1 : 0);
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
if (RES == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A < B) MinxCPU.F |= MINX_FLAG_CARRY;
if ((((A ^ RES) & 0x8000) != 0) && (((A ^ B) & 0x8000) != 0)) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (RES & 0x8000) MinxCPU.F |= MINX_FLAG_SIGN;
return (uint16_t)RES;
}
static inline uint8_t AND8(uint8_t A, uint8_t B)
{
A &= B;
MinxCPU.F &= MINX_FLAG_SAVE_CO;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A & 128) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline uint8_t OR8(uint8_t A, uint8_t B)
{
A |= B;
MinxCPU.F &= MINX_FLAG_SAVE_CO;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A & 128) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline uint8_t XOR8(uint8_t A, uint8_t B)
{
A ^= B;
MinxCPU.F &= MINX_FLAG_SAVE_CO;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A & 128) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline uint8_t INC8(uint8_t A)
{
A++;
MinxCPU.F &= MINX_FLAG_SAVE_COS;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
return A;
}
static inline uint16_t INC16(uint16_t A)
{
A++;
MinxCPU.F &= MINX_FLAG_SAVE_COS;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
return A;
}
static inline uint8_t DEC8(uint8_t A)
{
A--;
MinxCPU.F &= MINX_FLAG_SAVE_COS;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
return A;
}
static inline uint16_t DEC16(uint16_t A)
{
A--;
MinxCPU.F &= MINX_FLAG_SAVE_COS;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
return A;
}
static inline void PUSH(uint8_t A)
{
MinxCPU.SP.W.L--;
MinxCPU_OnWrite(1, MinxCPU.SP.D, A);
}
static inline uint8_t POP(void)
{
register uint8_t data;
data = MinxCPU_OnRead(1, MinxCPU.SP.D);
MinxCPU.SP.W.L++;
return data;
}
static inline void CALLS(uint16_t OFFSET)
{
PUSH(MinxCPU.PC.B.I);
PUSH(MinxCPU.PC.B.H);
PUSH(MinxCPU.PC.B.L);
MinxCPU.PC.B.I = MinxCPU.U1;
MinxCPU.U2 = MinxCPU.U1;
MinxCPU.PC.W.L = MinxCPU.PC.W.L + OFFSET - 1;
}
static inline void JMPS(uint16_t OFFSET)
{
MinxCPU.PC.B.I = MinxCPU.U1;
MinxCPU.U2 = MinxCPU.U1;
MinxCPU.PC.W.L = MinxCPU.PC.W.L + OFFSET - 1;
}
static inline void CALLU(uint16_t ADDR)
{
PUSH(MinxCPU.PC.B.I);
PUSH(MinxCPU.PC.B.H);
PUSH(MinxCPU.PC.B.L);
MinxCPU.PC.B.I = MinxCPU.U1;
MinxCPU.U2 = MinxCPU.U1;
MinxCPU.PC.W.L = ADDR;
}
static inline void JMPU(uint16_t ADDR)
{
MinxCPU.PC.B.I = MinxCPU.U1;
MinxCPU.U2 = MinxCPU.U1;
MinxCPU.PC.W.L = ADDR;
}
static inline void JDBNZ(uint16_t OFFSET)
{
MinxCPU.BA.B.H = DEC8(MinxCPU.BA.B.H);
if (MinxCPU.BA.B.H != 0) {
JMPS(OFFSET);
}
}
static inline uint8_t SWAP(uint8_t A)
{
return (A << 4) | (A >> 4);
}
static inline void RET(void)
{
MinxCPU.PC.B.L = POP();
MinxCPU.PC.B.H = POP();
MinxCPU.PC.B.I = POP();
Set_U(MinxCPU.PC.B.I);
}
static inline void RETI(void)
{
MinxCPU.F = POP();
MinxCPU.PC.B.L = POP();
MinxCPU.PC.B.H = POP();
MinxCPU.PC.B.I = POP();
Set_U(MinxCPU.PC.B.I);
MinxCPU_OnIRQHandle(MinxCPU.F, MinxCPU.Shift_U);
}
static inline void CALLX(uint16_t ADDR)
{
PUSH(MinxCPU.PC.B.I);
PUSH(MinxCPU.PC.B.H);
PUSH(MinxCPU.PC.B.L);
MinxCPU.PC.B.I = MinxCPU.U1;
MinxCPU.U2 = MinxCPU.U1;
MinxCPU.PC.W.L = ReadMem16((MinxCPU.HL.B.I << 16) + ADDR);
}
static inline void CALLI(uint16_t ADDR)
{
PUSH(MinxCPU.PC.B.I);
PUSH(MinxCPU.PC.B.H);
PUSH(MinxCPU.PC.B.L);
PUSH(MinxCPU.F);
MinxCPU.F |= 0xC0;
MinxCPU.PC.B.I = MinxCPU.U1;
MinxCPU.U2 = MinxCPU.U1;
MinxCPU.PC.W.L = ReadMem16(ADDR);
MinxCPU_OnIRQHandle(MinxCPU.F, MinxCPU.Shift_U);
}
static inline void JMPI(uint16_t ADDR)
{
PUSH(MinxCPU.F);
MinxCPU.F |= 0xC0;
MinxCPU.PC.B.I = MinxCPU.U1;
MinxCPU.U2 = MinxCPU.U1;
MinxCPU.PC.W.L = ReadMem16(ADDR);
MinxCPU_OnIRQHandle(MinxCPU.F, MinxCPU.Shift_U);
}
static inline uint8_t SAL(uint8_t A)
{
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_CARRY;
if ((!(A & 0x40)) != (!(A & 0x80))) MinxCPU.F |= MINX_FLAG_OVERFLOW;
A = A << 1;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline uint8_t SHL(uint8_t A)
{
MinxCPU.F &= MINX_FLAG_SAVE_O;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_CARRY;
A = A << 1;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline uint8_t SAR(uint8_t A)
{
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
if (A & 0x01) MinxCPU.F |= MINX_FLAG_CARRY;
A = (A & 0x80) | (A >> 1);
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline uint8_t SHR(uint8_t A)
{
MinxCPU.F &= MINX_FLAG_SAVE_O;
if (A & 0x01) MinxCPU.F |= MINX_FLAG_CARRY;
A = A >> 1;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline uint8_t ROLC(uint8_t A)
{
register uint8_t CARRY = (MinxCPU.F & MINX_FLAG_CARRY) ? 1 : 0;
MinxCPU.F &= MINX_FLAG_SAVE_O;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_CARRY;
A = (A << 1) | CARRY;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline uint8_t ROL(uint8_t A)
{
MinxCPU.F &= MINX_FLAG_SAVE_O;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_CARRY;
A = (A << 1) | (A >> 7);
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline uint8_t RORC(uint8_t A)
{
register uint8_t CARRY = (MinxCPU.F & MINX_FLAG_CARRY) ? 0x80 : 0x00;
MinxCPU.F &= MINX_FLAG_SAVE_O;
if (A & 0x01) MinxCPU.F |= MINX_FLAG_CARRY;
A = (A >> 1) | CARRY;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline uint8_t ROR(uint8_t A)
{
MinxCPU.F &= MINX_FLAG_SAVE_O;
if (A & 0x01) MinxCPU.F |= MINX_FLAG_CARRY;
A = (A >> 1) | (A << 7);
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline uint8_t NOT(uint8_t A)
{
MinxCPU.F &= MINX_FLAG_SAVE_CO;
A = A ^ 0xFF;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline uint8_t NEG(uint8_t A)
{
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
A = -A;
if (A == 0) MinxCPU.F |= MINX_FLAG_ZERO; else MinxCPU.F |= MINX_FLAG_CARRY;
if (A == 0x80) MinxCPU.F |= MINX_FLAG_OVERFLOW;
if (A & 0x80) MinxCPU.F |= MINX_FLAG_SIGN;
return A;
}
static inline void HALT(void)
{
MinxCPU.Status = MINX_STATUS_HALT;
MinxCPU_OnSleep(MINX_SLEEP_HALT);
}
static inline void STOP(void)
{
MinxCPU.Status = MINX_STATUS_STOP;
MinxCPU_OnSleep(MINX_SLEEP_STOP);
}
static inline void MUL(void)
{
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
MinxCPU.HL.W.L = (uint16_t)MinxCPU.HL.B.L * (uint16_t)MinxCPU.BA.B.L;
if (MinxCPU.HL.W.L == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (MinxCPU.HL.W.L & 0x8000) MinxCPU.F |= MINX_FLAG_SIGN;
}
static inline void DIV(void)
{
uint16_t RES;
MinxCPU.F &= MINX_FLAG_SAVE_NUL;
if (MinxCPU.BA.B.L == 0) {
MinxCPU_OnException(EXCEPTION_DIVISION_BY_ZERO, 0);
return;
}
RES = MinxCPU.HL.W.L / MinxCPU.BA.B.L;
if (RES < 256) {
MinxCPU.HL.B.H = MinxCPU.HL.W.L % MinxCPU.BA.B.L;
MinxCPU.HL.B.L = (uint8_t)RES;
if (MinxCPU.HL.B.L == 0) MinxCPU.F |= MINX_FLAG_ZERO;
if (MinxCPU.HL.B.L & 0x80) MinxCPU.F |= MINX_FLAG_SIGN;
} else MinxCPU.F |= (MINX_FLAG_OVERFLOW | MINX_FLAG_SIGN);
}
#endif