/*
 * Copyright 2008-2009 (C) Raster Software Vigo (Sergio Costas)
 * This file is part of Z80Free, with some bits extracted
 * and fixed from libZ80 (from Gabriel Gambetta)
 *
 * Z80Free 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.
 *
 * Z80Free 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 Z80FREE_H
#define Z80FREE_H

#include <endian.h>
#include <stdbool.h>
#include <stdint.h>

extern int Z80free_parityBit[256];

#define F_S     0x80
#define F_Z     0x40
#define F_5     0x20
#define F_H     0x10
#define F_3     0x08
#define F_PV    0x04
#define F_N     0x02
#define F_C     0x01

// enum Z80free_prefix {Z80XX, Z80CB, Z80DD, Z80ED, Z80FD};

typedef union {
	/** Word registers. */
	struct {
		uint16_t AF, BC, DE, HL, IX, IY, SP;
	} wr;

	/** Byte registers. SP can be accessed partially to simplify the load/save code. */

#if __BYTE_ORDER == __LITTLE_ENDIAN
	struct {
		uint8_t F, A, C, B, E, D, L, H, IXl, IXh, IYl, IYh, P, S;
	} br;
#else
	struct {
		uint8_t A, F, B, C, D, E, H, L, IXh, IXl, IYh, IYl, S, P;
	} br;
#endif
} Z80FRegs;

enum Z80Status {
	Z80XX,
	Z80CB,
	Z80DD,
	Z80ED,
	Z80FD,
	Z80INT
};

/** A Z80 execution context. */
typedef struct {
	Z80FRegs       Ra;         /* Alternate register set (R) */
	Z80FRegs       Rm;         /* Main register set (R) */
	uint16_t       PC;         /* Program counter */
	uint8_t        R;          /* Refresh */
	uint8_t        R2;         /* Upper bit for Refresh */
	uint8_t        I;
	uint8_t        IFF1;       /* Interrupt Flipflop 1. If it's 2, decrement it and don't allow INT */
	uint8_t        IFF2;       /* Interrupt Flipflop 2 */
	uint8_t        IM;         /* Interrupt mode */
	uint8_t        HALT;       /* HALT status */
	uint8_t        INT_P;      /* INT pending */
	uint8_t        NMI_P;      /* NMI pending */
	uint8_t        empty_bus;  /* value for empty bus when procesing a maskable int */
	uint16_t       IAddr;      /* address with offset for IX+d and IY+d */
	uint8_t        IAddr_done; /* if 1, IAddr contains a valid data */
	enum Z80Status Status;
	bool           M1;         /* true if the processor is in M1 state */
	uint16_t       subtstates; /* counts the number of tstates since the starting of the instruction */
} Z80FREE;

/* internal Z80 methods */

void Z80free_setFlag(Z80FREE *processor, uint8_t flag);
void Z80free_resFlag(Z80FREE *processor, uint8_t flag);
void Z80free_valFlag(Z80FREE *processor, uint8_t flag, int val);
int Z80free_getFlag(Z80FREE *processor, uint8_t flag);
void Z80free_adjustFlags(Z80FREE *processor, uint8_t val);
void Z80free_adjustFlagSZP(Z80FREE *processor, uint8_t val);
void Z80free_adjustLogicFlag(Z80FREE *processor, int flagH);
uint8_t Z80free_doArithmetic(Z80FREE *processor, uint8_t value1, uint8_t value2, int withCarry, int isSub);
uint16_t Z80free_doArithmetic16(Z80FREE *processor, uint16_t value1, uint16_t value2, int withCarry, int isSub);
void Z80free_doAND(Z80FREE *processor, uint8_t value);
void Z80free_doOR(Z80FREE *processor, uint8_t value);
void Z80free_doXOR(Z80FREE *processor, uint8_t value);
void Z80free_doBIT(Z80FREE *processor, int b, uint8_t val);
uint8_t Z80free_doSetRes(Z80FREE *processor, int bit, int pos, uint8_t val);
uint8_t Z80free_doIncDec(Z80FREE *processor, uint8_t val, int isDec);
uint16_t Z80free_doIncDec16(Z80FREE *processor, uint16_t val, int isDec);
uint8_t Z80free_doRLC(Z80FREE *processor, int adjFlags, uint8_t val);
uint8_t Z80free_doRL(Z80FREE *processor, int adjFlags, uint8_t val);
uint8_t Z80free_doRRC(Z80FREE *processor, int adjFlags, uint8_t val);
uint8_t Z80free_doRR(Z80FREE *processor, int adjFlags, uint8_t val);
uint8_t Z80free_doSL(Z80FREE *processor, int isArith, uint8_t val);
uint8_t Z80free_doSR(Z80FREE *processor, int isArith, uint8_t val);
void Z80free_doPush(Z80FREE *processor, uint16_t val);
uint16_t Z80free_doPop(Z80FREE *processor);
void Z80free_doDAA(Z80FREE *processor);
uint8_t Z80free_readR(Z80FREE *processor);
void Z80free_setR(Z80FREE *processor, uint8_t value);
uint8_t Z80free_readI(Z80FREE *processor);
void Z80free_doRRD(Z80FREE *processor);
void Z80free_doRLD(Z80FREE *processor);

void Z80free_jump_relative(Z80FREE *processor, uint8_t relvar);
uint16_t Z80free_addr_relative(Z80FREE *processor, uint16_t address);
uint16_t Z80free_addr_relativeXDCB(Z80FREE *processor, uint16_t address, uint8_t d1);
uint8_t Z80free_read_param_8(Z80FREE *z80);
uint16_t Z80free_read_param_16(Z80FREE *z80);
uint16_t Z80free_read16(Z80FREE *processor, uint16_t addr);
void Z80free_write16(Z80FREE *processor, uint16_t addr, uint16_t val);

/* external Z80 methods */

void Z80free_reset(Z80FREE *);
int Z80free_step(Z80FREE *);
int Z80free_ustep(Z80FREE *);

void Z80free_INT(Z80FREE *, uint8_t);

void Z80free_INTserved(Z80FREE *);

uint8_t Z80free_Rd_Internal(Z80FREE *processor, uint16_t Addr);
void Z80free_Wr_Internal(Z80FREE *processor, uint16_t Addr, uint8_t Value);
uint8_t Z80free_In_Internal(Z80FREE *processor, uint16_t Port);
void Z80free_Out_Internal(Z80FREE *processor, uint16_t Port, uint8_t Value);

uint8_t Z80free_Rd(uint16_t Addr);
void Z80free_Wr(uint16_t Addr, uint8_t Value);
uint8_t Z80free_In(uint16_t Port);
void Z80free_Out(uint16_t Port, uint8_t Value);

/* Opcode functions */

int Z80free_codes(Z80FREE *processor, uint8_t opcode);
int Z80free_codesCB(Z80FREE *processor, uint8_t opcode);
int Z80free_codesDD(Z80FREE *processor, uint8_t opcode);
int Z80free_codesED(Z80FREE *processor, uint8_t opcode);
int Z80free_codesFD(Z80FREE *processor, uint8_t opcode);
int Z80free_codesDDCB(Z80FREE *processor, uint8_t d1);
int Z80free_codesFDCB(Z80FREE *processor, uint8_t d1);

#endif
