/*-
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * Copyright (c) 2026 Bryan E. Topp <betopp@betopp.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
 
//zcpu.c
//Z80-style CPU emulator
//Bryan E. Topp <betopp@betopp.com> 2026

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

//Defines a register pair in an emulated processor.
typedef union zcpu_pair_u
{
	//Note that this depends on the endianness of the host.
	struct
	{
		uint8_t l; //Low byte (i.e. C, E, L, F)
		uint8_t h; //High bytes (i.e. B, D, H, A)
	} b;
	uint16_t w; //Access as word
} zcpu_pair_t;

//Defines the state of an emulated processor.
typedef struct zcpu_s
{	
	//Program counter
	zcpu_pair_t pc;

	//Stack pointer
	zcpu_pair_t sp;
	
	//Accumulator and flags
	zcpu_pair_t af;
	
	//Alternates for accumulator and flags (EX AF)
	zcpu_pair_t af_alt;
	
	//General purpose registers
	zcpu_pair_t bc;
	zcpu_pair_t de;
	zcpu_pair_t hl;
	
	//Alternates for general purpose registers (EXX)
	zcpu_pair_t bc_alt;
	zcpu_pair_t de_alt;
	zcpu_pair_t hl_alt;
	
	//Index registers
	zcpu_pair_t ix;
	zcpu_pair_t iy;
	
	//Interrupt page register
	uint8_t i;
	
	//Refresh counter
	uint8_t r;
	
	//Processor flags - interrupt mode, interrupt mask, etc
	uint8_t ctrl;
	
} zcpu_t;

//Storage for virtual machine executing currently
zcpu_t zcpu_state;
uint8_t zcpu_mem[65536];

//Flag definitions
#define Z80_FLAG_S  0x80
#define Z80_FLAG_Z  0x40
#define Z80_FLAG_F5 0x20
#define Z80_FLAG_H  0x10
#define Z80_FLAG_F3 0x08
#define Z80_FLAG_PV 0x04
#define Z80_FLAG_N  0x02
#define Z80_FLAG_C  0x01

//Control bit definitions
#define Z80_CTRL_IM1 0x01
#define Z80_CTRL_IM2 0x02
#define Z80_CTRL_EI  0x04

//Flags that depend solely on the ALU result, excluding parity
static const uint8_t z80resflag_sz53[256] = 
{
	0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 
	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 
	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 
	0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 
	0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 
	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 
	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 
	0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 
	0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 

};

//Flags that depend solely on the ALU result, including parity
static const uint8_t z80resflag_sz53p[256] = 
{
	0x44, 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x00, 0x08, 0x0C, 0x0C, 0x08, 0x0C, 0x08, 0x08, 0x0C, 
	0x00, 0x04, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0C, 0x08, 0x08, 0x0C, 0x08, 0x0C, 0x0C, 0x08, 
	0x20, 0x24, 0x24, 0x20, 0x24, 0x20, 0x20, 0x24, 0x2C, 0x28, 0x28, 0x2C, 0x28, 0x2C, 0x2C, 0x28, 
	0x24, 0x20, 0x20, 0x24, 0x20, 0x24, 0x24, 0x20, 0x28, 0x2C, 0x2C, 0x28, 0x2C, 0x28, 0x28, 0x2C, 
	0x00, 0x04, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0C, 0x08, 0x08, 0x0C, 0x08, 0x0C, 0x0C, 0x08, 
	0x04, 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x00, 0x08, 0x0C, 0x0C, 0x08, 0x0C, 0x08, 0x08, 0x0C, 
	0x24, 0x20, 0x20, 0x24, 0x20, 0x24, 0x24, 0x20, 0x28, 0x2C, 0x2C, 0x28, 0x2C, 0x28, 0x28, 0x2C, 
	0x20, 0x24, 0x24, 0x20, 0x24, 0x20, 0x20, 0x24, 0x2C, 0x28, 0x28, 0x2C, 0x28, 0x2C, 0x2C, 0x28, 
	0x80, 0x84, 0x84, 0x80, 0x84, 0x80, 0x80, 0x84, 0x8C, 0x88, 0x88, 0x8C, 0x88, 0x8C, 0x8C, 0x88, 
	0x84, 0x80, 0x80, 0x84, 0x80, 0x84, 0x84, 0x80, 0x88, 0x8C, 0x8C, 0x88, 0x8C, 0x88, 0x88, 0x8C, 
	0xA4, 0xA0, 0xA0, 0xA4, 0xA0, 0xA4, 0xA4, 0xA0, 0xA8, 0xAC, 0xAC, 0xA8, 0xAC, 0xA8, 0xA8, 0xAC, 
	0xA0, 0xA4, 0xA4, 0xA0, 0xA4, 0xA0, 0xA0, 0xA4, 0xAC, 0xA8, 0xA8, 0xAC, 0xA8, 0xAC, 0xAC, 0xA8, 
	0x84, 0x80, 0x80, 0x84, 0x80, 0x84, 0x84, 0x80, 0x88, 0x8C, 0x8C, 0x88, 0x8C, 0x88, 0x88, 0x8C, 
	0x80, 0x84, 0x84, 0x80, 0x84, 0x80, 0x80, 0x84, 0x8C, 0x88, 0x88, 0x8C, 0x88, 0x8C, 0x8C, 0x88, 
	0xA0, 0xA4, 0xA4, 0xA0, 0xA4, 0xA0, 0xA0, 0xA4, 0xAC, 0xA8, 0xA8, 0xAC, 0xA8, 0xAC, 0xAC, 0xA8, 
	0xA4, 0xA0, 0xA0, 0xA4, 0xA0, 0xA4, 0xA4, 0xA0, 0xA8, 0xAC, 0xAC, 0xA8, 0xAC, 0xA8, 0xA8, 0xAC,
};

//Flags resulting from incrementing the given 8-bit operand (index by the source, not the result).
static const uint8_t z80incflag[256] = 
{
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x30, 
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x30, 
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x10, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x30, 
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x30, 
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x94, 
	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x90, 
	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xB0, 
	0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xB0, 
	0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0x90, 
	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x90, 
	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xB0, 
	0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xB0, 
	0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0x50,
};

//Flags resulting from decrementing the given 8-bit operand (index by the source, not the result)
static const uint8_t z80decflag[256] = 
{
	0xBA, 0x42, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 
	0x1A, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 
	0x1A, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 
	0x3A, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 
	0x3A, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 
	0x1A, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 
	0x1A, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 
	0x3A, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 
	0x3E, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 
	0x9A, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 
	0x9A, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
	0xBA, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
	0xBA, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 
	0x9A, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 
	0x9A, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
	0xBA, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,	
};

//Reads a byte from the given address
#define z80read(addr) (zcpu_mem[(uint16_t)(addr)])

//Writes the given byte to the given address
#define z80write(addr, data) do { zcpu_mem[(uint16_t)(addr)] = (data); } while(0)

//Inputs from an IO port
static inline uint8_t z80in(uint16_t port) { (void)port; return 0xFF; }

//Outputs to an IO port
static inline void z80out(uint16_t port, uint8_t data) { (void)port; (void)data; }

//Helper functions which are local to the emulator

//Performs an IO input and sets flags
static uint8_t z80inwithflags(uint8_t port)
{
	uint8_t readval = z80in(port);
	zcpu_state.af.b.l = z80resflag_sz53p[readval] | (zcpu_state.af.b.l & Z80_FLAG_C);
	return readval;
}

//Reads a 16-bit pair from the given address (low byte) and the following address (high byte)
static inline uint16_t z80readpair(uint16_t addr)
{
	uint16_t retval = z80read(addr);
	retval |= ((uint16_t)z80read(addr+1)) << 8;
	return retval;
}

//Writes a 16-bit pair to the given address (low byte) and the following address (high byte)
static inline void z80writepair(uint16_t addr, uint16_t value)
{
	z80write(addr, value & 0xFF);
	z80write(addr+1, (value >> 8) & 0xFF);
}

//Conditionally sets a flag
static inline void z80alterflag(uint8_t mask, bool value)
{
	if(value)
		zcpu_state.af.b.l |= mask;
	else
		zcpu_state.af.b.l &= ~mask;
}

//Performs an increment and sets flags
static uint8_t z80inc8(uint8_t val)
{
	zcpu_state.af.b.l = z80incflag[val] | (zcpu_state.af.b.l & Z80_FLAG_C);
	return val + 1;
}

//Performs a decrement and sets flags
static uint8_t z80dec8(uint8_t val)
{
	zcpu_state.af.b.l = z80decflag[val] | (zcpu_state.af.b.l & Z80_FLAG_C);
	return val - 1;
}

//Performs a rotate-left and sets flags
static uint8_t z80rl(uint8_t val)
{
	uint8_t newval = val << 1;
	if(zcpu_state.af.b.l & Z80_FLAG_C)
		newval |= 1;
	
	zcpu_state.af.b.l = z80resflag_sz53p[newval];
	if(val & 0x80)
		zcpu_state.af.b.l |= Z80_FLAG_C;

	return newval;
}

//Performs a rotate-left through carry and sets flags
static uint8_t z80rlc(uint8_t val)
{
	uint8_t newval = val << 1;
	if(val & 0x80)
		newval |= 1;
	
	zcpu_state.af.b.l = z80resflag_sz53p[newval];
	if(val & 0x80)
		zcpu_state.af.b.l |= Z80_FLAG_C;

	return newval;	
}

//Performs a rotate-right and sets flags
static uint8_t z80rr(uint8_t val)
{
	uint8_t newval = val >> 1;
	if(zcpu_state.af.b.l & Z80_FLAG_C)
		newval |= 0x80;
	
	zcpu_state.af.b.l = z80resflag_sz53p[newval];
	if(val & 0x01)
		zcpu_state.af.b.l |= Z80_FLAG_C;
	
	return newval;
}

//Performs a rotate-right through carry and sets flags
static uint8_t z80rrc(uint8_t val)
{
	uint8_t newval = val >> 1;
	if(val & 0x01)
		newval |= 0x80;
	
	zcpu_state.af.b.l = z80resflag_sz53p[newval];
	if(val & 0x01)
		zcpu_state.af.b.l |= Z80_FLAG_C;
	
	return newval;	
}

//Performs an arithmetic shift-left and sets flags
static uint8_t z80sla(uint8_t val)
{
	uint8_t newval = val << 1;
	
	zcpu_state.af.b.l = z80resflag_sz53p[newval];
	if(val & 0x80)
		zcpu_state.af.b.l |= Z80_FLAG_C;
	
	return newval;	
}

//Performs a "logical shift left" (invalid op, fills low bit with 1) and sets flags
static uint8_t z80sll(uint8_t val)
{
	uint8_t newval = val << 1;
	newval |= 0x01;
	
	zcpu_state.af.b.l = z80resflag_sz53p[newval];
	if(val & 0x80)
		zcpu_state.af.b.l |= Z80_FLAG_C;
	
	return newval;	
}

//Performs an arithmetic shift-right and sets flags
static uint8_t z80sra(uint8_t val)
{
	uint8_t newval = val >> 1;
	if(val & 0x80)
		newval |= 0x80;
	
	zcpu_state.af.b.l = z80resflag_sz53p[newval];
	if(val & 0x01)
		zcpu_state.af.b.l |= Z80_FLAG_C;
	
	return newval;
}

//Performs a logical shift-right and sets flags
static uint8_t z80srl(uint8_t val)
{
	uint8_t newval = val >> 1;
	
	zcpu_state.af.b.l = z80resflag_sz53p[newval];
	if(val & 0x01)
		zcpu_state.af.b.l |= Z80_FLAG_C;
	
	return newval;	
}


//Performs ALU addition op and sets all flags
static uint8_t z80aluadd(uint8_t a, uint8_t b)
{
	uint16_t result = a + b;
	
	zcpu_state.af.b.l = z80resflag_sz53[result & 0xFF];
	if( (a^b^result) & 0x10 )
		zcpu_state.af.b.l |= Z80_FLAG_H;
	
	if( ((a ^ b) & 0x80) == 0 )
	{
		if( ((result ^ b) & 0x80) )
		{
			zcpu_state.af.b.l |= Z80_FLAG_PV;
		}
	}
	
	if((int)a+(int)b > 255)
	{
		zcpu_state.af.b.l |= Z80_FLAG_C;
	}
	
	return result & 0xFF;
}

//Performs ALU addition with carry op and sets all flags
static uint8_t z80aluadc(uint8_t a, uint8_t b)
{
	uint16_t result = a + b;
	if(zcpu_state.af.b.l & Z80_FLAG_C)
		result++;

	zcpu_state.af.b.l = z80resflag_sz53[result & 0xFF];
	if( (a^b^result) & 0x10 )
		zcpu_state.af.b.l |= Z80_FLAG_H;
	
	if( ((a ^ b) & 0x80) == 0 )
	{
		if( ((result ^ b) & 0x80) )
		{
			zcpu_state.af.b.l |= Z80_FLAG_PV;
		}
	}
	
	if(result & 0x100)
	{
		zcpu_state.af.b.l |= Z80_FLAG_C;
	}
	
	return result & 0xFF;
}

//Performs 16-bit addition and sets flags
static uint16_t z80add16(uint16_t aval, uint16_t bval)
{
	zcpu_pair_t a;
	a.w = aval;
	
	zcpu_pair_t b;
	b.w = bval;
	
	zcpu_pair_t retval;
	retval.w = a.w + b.w;
	
	zcpu_state.af.b.l &= ~(Z80_FLAG_F3 | Z80_FLAG_F5 | Z80_FLAG_H | Z80_FLAG_C | Z80_FLAG_N);
	zcpu_state.af.b.l |= retval.b.h & (Z80_FLAG_F3 | Z80_FLAG_F5);
	zcpu_state.af.b.l |= (retval.b.h ^ a.b.h ^ b.b.h) & Z80_FLAG_H;
	if( (uint32_t)a.w + (uint32_t)b.w >= 65536 )
		zcpu_state.af.b.l |= Z80_FLAG_C;	
	
	return retval.w;
}

//Performs ALU subtraction op and sets all flags
static uint8_t z80alusub(uint8_t a, uint8_t b)
{
	uint8_t result = a - b;
	
	zcpu_state.af.b.l = z80resflag_sz53[result] | Z80_FLAG_N;
	if( (a^b^result) & 0x10 )
		zcpu_state.af.b.l |= Z80_FLAG_H;
	
	if( (result ^ a) & 0x80 )
	{
		if( ((result ^ b) & 0x80) == 0)
		{
			zcpu_state.af.b.l |= Z80_FLAG_PV;
		}
	}
	
	if(b > a)
	{
		zcpu_state.af.b.l |= Z80_FLAG_C;
	}
	

	return result & 0xFF;
}

//Performs ALU subtraction with carry op and sets all flags
static uint8_t z80alusbc(uint8_t a, uint8_t b)
{
	uint16_t result = a - b;
	if(zcpu_state.af.b.l & Z80_FLAG_C)
		result--;
	
	zcpu_state.af.b.l = z80resflag_sz53[result&0xFF] | Z80_FLAG_N;
	if( (a^b^result) & 0x10 )
		zcpu_state.af.b.l |= Z80_FLAG_H;
	
	if( (result ^ a) & 0x80 )
	{
		if( ((result ^ b) & 0x80) == 0)
		{
			zcpu_state.af.b.l |= Z80_FLAG_PV;
		}
	}
	
	if(result & 0x100)
	{
		zcpu_state.af.b.l |= Z80_FLAG_C;
	}
	

	return result & 0xFF;
}

//Performs ALU comparison and sets flags
static void z80alucp(uint8_t a, uint8_t b)
{
	uint8_t result = a - b;
	
	zcpu_state.af.b.l = z80resflag_sz53[result] | Z80_FLAG_N;
	if( (a^b^result) & 0x10 )
		zcpu_state.af.b.l |= Z80_FLAG_H;
	
	if( (result ^ a) & 0x80 )
	{
		if( ((result ^ b) & 0x80) == 0)
		{
			zcpu_state.af.b.l |= Z80_FLAG_PV;
		}
	}
	
	if(b > a)
	{
		zcpu_state.af.b.l |= Z80_FLAG_C;
	}
	
	zcpu_state.af.b.l &= ~(Z80_FLAG_F5 | Z80_FLAG_F3);
	zcpu_state.af.b.l |= b & (Z80_FLAG_F5 | Z80_FLAG_F3);
}

//Performs ALU bitwise AND op and sets all flags
static uint8_t z80aluand(uint8_t a, uint8_t b)
{
	uint8_t result = a & b;
	zcpu_state.af.b.l = z80resflag_sz53p[result] | Z80_FLAG_H;
	return result;
}

//Performs ALU bitwise OR op and sets all flags
static uint8_t z80aluor(uint8_t a, uint8_t b)
{
	uint8_t result = a | b;
	zcpu_state.af.b.l = z80resflag_sz53p[result];
	return result;
}

//Performs ALU bitwise XOR op and sets all flags
static uint8_t z80aluxor(uint8_t a, uint8_t b)
{
	uint8_t result = a ^ b;
	zcpu_state.af.b.l = z80resflag_sz53p[result];
	return result;
}

//Reads memory at address in PC. Advances PC afterwards. Returns byte from memory.
static inline uint8_t z80fetch(void)
{
	//printf("PC fetch from %4.4X ", zcpu_state.pc.w);
	uint8_t fetched = z80read(zcpu_state.pc.w);
	zcpu_state.pc.w++;
	//printf("returns %2.2X\n", fetched);
	return fetched;
}

//Fetches twice to read a pair
static inline uint16_t z80fetchpair(void)
{
	uint16_t fetched = 0;
	fetched |= z80read(zcpu_state.pc.w);
	zcpu_state.pc.w++;
	fetched |= (uint16_t)(z80read(zcpu_state.pc.w)) << 8;
	zcpu_state.pc.w++;
	return fetched;
}

//Decrements SP, stores the high byte of the pair at SP, decrements SP again, and stores the low byte of the pair at SP.
static void z80push(uint16_t value)
{	
	zcpu_state.sp.w--;
	z80write(zcpu_state.sp.w, (value >> 8) & 0xFF);
	zcpu_state.sp.w--;
	z80write(zcpu_state.sp.w, value & 0xFF);
}

//Reads the byte at SP into the low byte of a pair, increments SP, reads into the high byte of the pair, and returns the pair.
static uint16_t z80pop(void)
{
	uint16_t retval = z80read(zcpu_state.sp.w);
	zcpu_state.sp.w++;
	retval |= ((uint16_t)z80read(zcpu_state.sp.w)) << 8;
	zcpu_state.sp.w++;
	return retval;
}

//Subsection of cycle - DD CB or FD CB block, IX/IY-indexed bit instructions
//Assumes the DD/FD and CB bytes have already been read and PC advanced.
static void z80cycle_cbidx(bool useiy)
{
	//All instructions in this block read the operand using displacement.
	//Most also take the 4th, 5th, and 6th bits as a bit-number.
	
	int8_t disp = (int8_t)z80fetch();
	uint8_t opcode3 = z80fetch();
	uint8_t bitnum = (opcode3 >> 3) & 0x7;
	
	uint16_t operand_address = useiy ? (zcpu_state.iy.w + disp) : (zcpu_state.ix.w + disp);
	uint8_t operand = z80read(operand_address);

	switch(opcode3)
	{
		case 0x06: z80write(operand_address, z80rlc(operand)); break; //rlc (ix+*)
		case 0x0E: z80write(operand_address, z80rrc(operand)); break; //rrc (ix+*)
		case 0x16: z80write(operand_address, z80rl(operand));  break; //rl (ix+*)
		case 0x1E: z80write(operand_address, z80rr(operand));  break; //rr (ix+*)
		case 0x26: z80write(operand_address, z80sla(operand)); break; //sla (ix+*)
		case 0x2E: z80write(operand_address, z80sra(operand)); break; //sra (ix+*)
		case 0x36: z80write(operand_address, z80sll(operand)); break; //sll (ix+*)
		case 0x3E: z80write(operand_address, z80srl(operand)); break; //srl (ix+*)
			
		case 0x46: //bit n, (ix+*)
		case 0x4E:
		case 0x56:
		case 0x5E:
		case 0x66:
		case 0x6E:
		case 0x76:
		case 0x7E:
			operand &= (1<<bitnum);
			zcpu_state.af.b.l = (zcpu_state.af.b.l & Z80_FLAG_C) | Z80_FLAG_H;
			if(operand == 0)
			{
				zcpu_state.af.b.l |= Z80_FLAG_Z | Z80_FLAG_PV;
			}
			
			//This is some bullshit right here
			if(operand & 0x80)
			{
				zcpu_state.af.b.l |= Z80_FLAG_S;
			}
			
			//zcpu_state.af.b.l |= (operand_address>>8) & (Z80_FLAG_F3 | Z80_FLAG_F5); //WTF?
			
			z80alterflag(Z80_FLAG_N, false);
			z80alterflag(Z80_FLAG_H, true);
			
			break;
			
		case 0x86: //res n, (ix+*)
		case 0x8E:
		case 0x96:
		case 0x9E:
		case 0xA6:
		case 0xAE:
		case 0xB6:
		case 0xBE:
			operand &= ~(1<<bitnum);
			z80write(operand_address, operand);
			break;
			
		case 0xC6: //set n, (ix+*)
		case 0xCE:
		case 0xD6:
		case 0xDE:
		case 0xE6:
		case 0xEE:
		case 0xF6:
		case 0xFE:
			operand |= (1<<bitnum);
			z80write(operand_address, operand);
			break;
			
		default:
			
			break;
	}
}


//DD block - Pushes and pops

static void z80jt_DDE5(void) { z80push(zcpu_state.ix.w); } //push ix
static void z80jt_DDE1(void) { zcpu_state.ix.w = z80pop(); } //pop ix

//DD block - 8-bit register-to-register load group

static void z80jt_DD44(void){ zcpu_state.bc.b.h = zcpu_state.ix.b.h; }  //ld b, ixh
static void z80jt_DD45(void){ zcpu_state.bc.b.h = zcpu_state.ix.b.l; } //ld b, ixl

static void z80jt_DD54(void){ zcpu_state.de.b.h = zcpu_state.ix.b.h; } //ld d, ixh
static void z80jt_DD55(void){ zcpu_state.de.b.h = zcpu_state.ix.b.l; } //ld d, ixl

static void z80jt_DD60(void){ zcpu_state.ix.b.h = zcpu_state.bc.b.h; } //ld ixh, b
static void z80jt_DD61(void){ zcpu_state.ix.b.h = zcpu_state.bc.b.l; } //ld ixh, c
static void z80jt_DD62(void){ zcpu_state.ix.b.h = zcpu_state.de.b.h; } //ld ixh, d
static void z80jt_DD63(void){ zcpu_state.ix.b.h = zcpu_state.de.b.l; } //ld ixh, e
static void z80jt_DD64(void){ zcpu_state.ix.b.h = zcpu_state.ix.b.h; } //ld ixh, ixh
static void z80jt_DD65(void){ zcpu_state.ix.b.h = zcpu_state.ix.b.l; } //ld ixh, ixl
static void z80jt_DD67(void){ zcpu_state.ix.b.h = zcpu_state.af.b.h; } //ld ixh, a

static void z80jt_DD4C(void){ zcpu_state.bc.b.l = zcpu_state.ix.b.h; } //ld c, ixh
static void z80jt_DD4D(void){ zcpu_state.bc.b.l = zcpu_state.ix.b.l; } //ld c, ixl

static void z80jt_DD5C(void){ zcpu_state.de.b.l = zcpu_state.ix.b.h; } //ld e, ixh
static void z80jt_DD5D(void){ zcpu_state.de.b.l = zcpu_state.ix.b.l; } //ld e, ixl

static void z80jt_DD68(void){ zcpu_state.ix.b.l = zcpu_state.bc.b.h; } //ld ixl, b
static void z80jt_DD69(void){ zcpu_state.ix.b.l = zcpu_state.bc.b.l; } //ld ixl, c
static void z80jt_DD6A(void){ zcpu_state.ix.b.l = zcpu_state.de.b.h; } //ld ixl, d
static void z80jt_DD6B(void){ zcpu_state.ix.b.l = zcpu_state.de.b.l; } //ld ixl, e
static void z80jt_DD6C(void){ zcpu_state.ix.b.l = zcpu_state.ix.b.h; } //ld ixl, ixh
static void z80jt_DD6D(void){ zcpu_state.ix.b.l = zcpu_state.ix.b.l; } //ld ixl, ixl
static void z80jt_DD6F(void){ zcpu_state.ix.b.l = zcpu_state.af.b.h; } //ld ixl, a

static void z80jt_DD7C(void){ zcpu_state.af.b.h = zcpu_state.ix.b.h; } //ld a, ixh
static void z80jt_DD7D(void){ zcpu_state.af.b.h = zcpu_state.ix.b.l; } //ld a, ixl

//DD block - 8-bit loads/stores, indirect through ix+d

static void z80jt_DD70(void){ z80write(zcpu_state.ix.w + (int8_t)z80fetch(), zcpu_state.bc.b.h); } //ld (ix+*), b
static void z80jt_DD71(void){ z80write(zcpu_state.ix.w + (int8_t)z80fetch(), zcpu_state.bc.b.l); } //ld (ix+*), c
static void z80jt_DD72(void){ z80write(zcpu_state.ix.w + (int8_t)z80fetch(), zcpu_state.de.b.h); } //ld (ix+*), d
static void z80jt_DD73(void){ z80write(zcpu_state.ix.w + (int8_t)z80fetch(), zcpu_state.de.b.l); } //ld (ix+*), e
static void z80jt_DD74(void){ z80write(zcpu_state.ix.w + (int8_t)z80fetch(), zcpu_state.hl.b.h); } //ld (ix+*), h
static void z80jt_DD75(void){ z80write(zcpu_state.ix.w + (int8_t)z80fetch(), zcpu_state.hl.b.l); } //ld (ix+*), l
static void z80jt_DD77(void){ z80write(zcpu_state.ix.w + (int8_t)z80fetch(), zcpu_state.af.b.h); } //ld (ix+*), a

static void z80jt_DD46(void){ zcpu_state.bc.b.h = z80read(zcpu_state.ix.w + (int8_t)z80fetch()); } //ld b, (ix+*)
static void z80jt_DD4E(void){ zcpu_state.bc.b.l = z80read(zcpu_state.ix.w + (int8_t)z80fetch()); } //ld c, (ix+*)
static void z80jt_DD56(void){ zcpu_state.de.b.h = z80read(zcpu_state.ix.w + (int8_t)z80fetch()); } //ld d, (ix+*)
static void z80jt_DD5E(void){ zcpu_state.de.b.l = z80read(zcpu_state.ix.w + (int8_t)z80fetch()); } //ld e, (ix+*)
static void z80jt_DD66(void){ zcpu_state.hl.b.h = z80read(zcpu_state.ix.w + (int8_t)z80fetch()); } //ld h, (ix+*)
static void z80jt_DD6E(void){ zcpu_state.hl.b.l = z80read(zcpu_state.ix.w + (int8_t)z80fetch()); } //ld l, (ix+*)
static void z80jt_DD7E(void){ zcpu_state.af.b.h = z80read(zcpu_state.ix.w + (int8_t)z80fetch()); } //ld a, (ix+*)

//DD block - 8-bit immediate loads

static void z80jt_DD26(void){ zcpu_state.ix.b.h = z80fetch(); } //ld ixh, *
static void z80jt_DD2E(void){ zcpu_state.ix.b.l = z80fetch(); } //ld ixl, *

static void z80jt_DD36(void)//ld (ix+*), *
{ 
	int8_t disp = (int8_t)z80fetch();
	uint8_t imm = z80fetch();
	z80write(zcpu_state.ix.w + disp, imm);
}

//DD block - 16-bit immediate loads

static void z80jt_DD21(void){ zcpu_state.ix.w = z80fetchpair(); } //ld ix, **

//DD block - 8-bit register-to-accumulator ALU group

static void z80jt_DD84(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, zcpu_state.ix.b.h); } //add a, ixh
static void z80jt_DD85(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, zcpu_state.ix.b.l); } //add a, ixl
static void z80jt_DD86(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, z80read(zcpu_state.ix.w + (int8_t)z80fetch())); } //add a, (ix+*)

static void z80jt_DD8C(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, zcpu_state.ix.b.h); } //adc a, ixh
static void z80jt_DD8D(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, zcpu_state.ix.b.l); } //adc a, ixl
static void z80jt_DD8E(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, z80read(zcpu_state.ix.w + (int8_t)z80fetch())); } //adc a, (ix+*)

static void z80jt_DD94(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, zcpu_state.ix.b.h); } //sub a, ixh
static void z80jt_DD95(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, zcpu_state.ix.b.l); } //sub a, ixl
static void z80jt_DD96(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, z80read(zcpu_state.ix.w + (int8_t)z80fetch())); } //sub a, (ix+*)

static void z80jt_DD9C(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, zcpu_state.ix.b.h); } //sbc a, ixh
static void z80jt_DD9D(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, zcpu_state.ix.b.l); } //sbc a, ixl
static void z80jt_DD9E(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, z80read(zcpu_state.ix.w + (int8_t)z80fetch())); } //sbc a, (ix+*)

static void z80jt_DDA4(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, zcpu_state.ix.b.h); } //and a, ixh
static void z80jt_DDA5(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, zcpu_state.ix.b.l); } //and a, ixl
static void z80jt_DDA6(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, z80read(zcpu_state.ix.w + (int8_t)z80fetch())); } //and a, (ix+*)

static void z80jt_DDAC(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, zcpu_state.ix.b.h); } //xor a, ixh
static void z80jt_DDAD(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, zcpu_state.ix.b.l); } //xor a, ixl
static void z80jt_DDAE(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, z80read(zcpu_state.ix.w + (int8_t)z80fetch())); } //xor a, (ix+*)

static void z80jt_DDB4(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, zcpu_state.ix.b.h); } //or a, ixh
static void z80jt_DDB5(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, zcpu_state.ix.b.l); } //or a, ixl
static void z80jt_DDB6(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, z80read(zcpu_state.ix.w + (int8_t)z80fetch())); } //or a, (ix+*)

static void z80jt_DDBC(void){ z80alucp(zcpu_state.af.b.h, zcpu_state.ix.b.h); } //cp a, ixh
static void z80jt_DDBD(void){ z80alucp(zcpu_state.af.b.h, zcpu_state.ix.b.l); } //cp a, ixl
static void z80jt_DDBE(void){ z80alucp(zcpu_state.af.b.h, z80read(zcpu_state.ix.w + (int8_t)z80fetch())); } //cp a, (ix+*)

//DD block - 16-bit arithmetic group

static void z80jt_DD09(void){ zcpu_state.ix.w = z80add16(zcpu_state.ix.w, zcpu_state.bc.w); } //add ix, bc
static void z80jt_DD19(void){ zcpu_state.ix.w = z80add16(zcpu_state.ix.w, zcpu_state.de.w); } //add ix, de
static void z80jt_DD29(void){ zcpu_state.ix.w = z80add16(zcpu_state.ix.w, zcpu_state.ix.w); } //add ix, ix
static void z80jt_DD39(void){ zcpu_state.ix.w = z80add16(zcpu_state.ix.w, zcpu_state.sp.w); } //add ix, sp

static void z80jt_DDF9(void){ zcpu_state.sp.w = zcpu_state.ix.w; } //ld sp, ix

//DD block - 8-bit increment/decrement group

static void z80jt_DD24(void){ zcpu_state.ix.b.h = z80inc8(zcpu_state.ix.b.h); } //inc ixh
static void z80jt_DD2C(void){ zcpu_state.ix.b.l = z80inc8(zcpu_state.ix.b.l); } //inc ixl
static void z80jt_DD25(void){ zcpu_state.ix.b.h = z80dec8(zcpu_state.ix.b.h); } //dec ixh
static void z80jt_DD2D(void){ zcpu_state.ix.b.l = z80dec8(zcpu_state.ix.b.l); } //dec ixl
	
static void z80jt_DD34(void)//inc (ix+*)
{ 
	int8_t disp = (int8_t)z80fetch();
	z80write(zcpu_state.ix.w + disp, z80inc8(z80read(zcpu_state.ix.w + disp)));
}
	
static void z80jt_DD35(void)//dec (ix+*)
{ 
	int8_t disp = (int8_t)z80fetch();
	z80write(zcpu_state.ix.w + disp, z80dec8(z80read(zcpu_state.ix.w + disp)));
}

//DD block - 16-bit increment/decrement group

static void z80jt_DD23(void){ zcpu_state.ix.w++; } //inc ix
static void z80jt_DD2B(void){ zcpu_state.ix.w--; } //dec ix

//DD block - Special indirect loads/stores

static void z80jt_DD22(void){ z80writepair(z80fetchpair(), zcpu_state.ix.w); } //ld (**), ix
static void z80jt_DD2A(void){ zcpu_state.ix.w = z80readpair(z80fetchpair()); } //ld ix, (**)

//DD block - Exchanges

static void z80jt_DDE3(void)//ex (sp), ix
{ 
	uint16_t temp = zcpu_state.ix.w;
	zcpu_state.ix.w = z80readpair(zcpu_state.sp.w);
	z80writepair(zcpu_state.sp.w, temp);
}		

//DD block - Other instructions

static void z80jt_DDE9(void){ zcpu_state.pc.w = zcpu_state.ix.w; } //jp (ix)
static void z80jt_DDCB(void){ z80cycle_cbidx(false); } //bit instructions

//Instruction that doesn't change because of the DD prefix
//Put the opcode back, let the next cycle handle it
static void z80jt_DDxx(void){ zcpu_state.pc.w--; }

//Jump table for DD block
typedef void (*z80jt_t)(void);
static const z80jt_t z80jt_ddblock[256] = 
{
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx,
	z80jt_DDxx, z80jt_DD09, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx,
	z80jt_DDxx, z80jt_DD19, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx,
	z80jt_DDxx, z80jt_DD21, z80jt_DD22, z80jt_DD23, z80jt_DD24, z80jt_DD25, z80jt_DD26, z80jt_DDxx,
	z80jt_DDxx, z80jt_DD29, z80jt_DD2A, z80jt_DD2B, z80jt_DD2C, z80jt_DD2D, z80jt_DD2E, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DD34, z80jt_DD35, z80jt_DD36, z80jt_DDxx,
	z80jt_DDxx, z80jt_DD39, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DD44, z80jt_DD45, z80jt_DD46, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DD4C, z80jt_DD4D, z80jt_DD4E, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DD54, z80jt_DD55, z80jt_DD56, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DD5C, z80jt_DD5D, z80jt_DD5E, z80jt_DDxx,
	z80jt_DD60, z80jt_DD61, z80jt_DD62, z80jt_DD63, z80jt_DD64, z80jt_DD65, z80jt_DD66, z80jt_DD67,
	z80jt_DD68, z80jt_DD69, z80jt_DD6A, z80jt_DD6B, z80jt_DD6C, z80jt_DD6D, z80jt_DD6E, z80jt_DD6F,
	z80jt_DD70, z80jt_DD71, z80jt_DD72, z80jt_DD73, z80jt_DD74, z80jt_DD75, z80jt_DDxx, z80jt_DD77,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DD7C, z80jt_DD7D, z80jt_DD7E, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DD84, z80jt_DD85, z80jt_DD86, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DD8C, z80jt_DD8D, z80jt_DD8E, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DD94, z80jt_DD95, z80jt_DD96, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DD9C, z80jt_DD9D, z80jt_DD9E, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDA4, z80jt_DDA5, z80jt_DDA6, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDAC, z80jt_DDAD, z80jt_DDAE, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDB4, z80jt_DDB5, z80jt_DDB6, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDBC, z80jt_DDBD, z80jt_DDBE, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDCB, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDE1, z80jt_DDxx, z80jt_DDE3, z80jt_DDxx, z80jt_DDE5, z80jt_DDxx, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDE9, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx,
	z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, 
	z80jt_DDxx, z80jt_DDF9, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx, z80jt_DDxx
};

//Subsection of cycle - DD block, IX-indexed instructions.
//Assumes the DD byte has already been read and PC advanced.
static void z80cycle_dd(void)
{
	uint8_t opcode2 = z80fetch();
	z80jt_ddblock[opcode2]();
}




//FD block - Pushes and pops

static void z80jt_FDE5(void){ z80push(zcpu_state.iy.w); } //push iy
static void z80jt_FDE1(void){ zcpu_state.iy.w = z80pop(); } //pop iy

//FD block - 8-bit register-to-register load group

static void z80jt_FD44(void){ zcpu_state.bc.b.h = zcpu_state.iy.b.h; }  //ld b, iyh
static void z80jt_FD45(void){ zcpu_state.bc.b.h = zcpu_state.iy.b.l; } //ld b, iyl

static void z80jt_FD54(void){ zcpu_state.de.b.h = zcpu_state.iy.b.h; } //ld d, iyh
static void z80jt_FD55(void){ zcpu_state.de.b.h = zcpu_state.iy.b.l; } //ld d, iyl

static void z80jt_FD60(void){ zcpu_state.iy.b.h = zcpu_state.bc.b.h; } //ld iyh, b
static void z80jt_FD61(void){ zcpu_state.iy.b.h = zcpu_state.bc.b.l; } //ld iyh, c
static void z80jt_FD62(void){ zcpu_state.iy.b.h = zcpu_state.de.b.h; } //ld iyh, d
static void z80jt_FD63(void){ zcpu_state.iy.b.h = zcpu_state.de.b.l; } //ld iyh, e
static void z80jt_FD64(void){ zcpu_state.iy.b.h = zcpu_state.iy.b.h; } //ld iyh, iyh
static void z80jt_FD65(void){ zcpu_state.iy.b.h = zcpu_state.iy.b.l; } //ld iyh, iyl
static void z80jt_FD67(void){ zcpu_state.iy.b.h = zcpu_state.af.b.h; } //ld iyh, a

static void z80jt_FD4C(void){ zcpu_state.bc.b.l = zcpu_state.iy.b.h; } //ld c, iyh
static void z80jt_FD4D(void){ zcpu_state.bc.b.l = zcpu_state.iy.b.l; } //ld c, iyl

static void z80jt_FD5C(void){ zcpu_state.de.b.l = zcpu_state.iy.b.h; } //ld e, iyh
static void z80jt_FD5D(void){ zcpu_state.de.b.l = zcpu_state.iy.b.l; } //ld e, iyl

static void z80jt_FD68(void){ zcpu_state.iy.b.l = zcpu_state.bc.b.h; } //ld iyl, b
static void z80jt_FD69(void){ zcpu_state.iy.b.l = zcpu_state.bc.b.l; } //ld iyl, c
static void z80jt_FD6A(void){ zcpu_state.iy.b.l = zcpu_state.de.b.h; } //ld iyl, d
static void z80jt_FD6B(void){ zcpu_state.iy.b.l = zcpu_state.de.b.l; } //ld iyl, e
static void z80jt_FD6C(void){ zcpu_state.iy.b.l = zcpu_state.iy.b.h; } //ld iyl, iyh
static void z80jt_FD6D(void){ zcpu_state.iy.b.l = zcpu_state.iy.b.l; } //ld iyl, iyl
static void z80jt_FD6F(void){ zcpu_state.iy.b.l = zcpu_state.af.b.h; } //ld iyl, a

static void z80jt_FD7C(void){ zcpu_state.af.b.h = zcpu_state.iy.b.h; } //ld a, iyh
static void z80jt_FD7D(void){ zcpu_state.af.b.h = zcpu_state.iy.b.l; } //ld a, iyl

//FD block - 8-bit loads/stores, indirect through IY+d

static void z80jt_FD70(void){ z80write(zcpu_state.iy.w + (int8_t)z80fetch(), zcpu_state.bc.b.h); } //ld (iy+*), b
static void z80jt_FD71(void){ z80write(zcpu_state.iy.w + (int8_t)z80fetch(), zcpu_state.bc.b.l); } //ld (iy+*), c
static void z80jt_FD72(void){ z80write(zcpu_state.iy.w + (int8_t)z80fetch(), zcpu_state.de.b.h); } //ld (iy+*), d
static void z80jt_FD73(void){ z80write(zcpu_state.iy.w + (int8_t)z80fetch(), zcpu_state.de.b.l); } //ld (iy+*), e
static void z80jt_FD74(void){ z80write(zcpu_state.iy.w + (int8_t)z80fetch(), zcpu_state.hl.b.h); } //ld (iy+*), h
static void z80jt_FD75(void){ z80write(zcpu_state.iy.w + (int8_t)z80fetch(), zcpu_state.hl.b.l); } //ld (iy+*), l
static void z80jt_FD77(void){ z80write(zcpu_state.iy.w + (int8_t)z80fetch(), zcpu_state.af.b.h); } //ld (iy+*), a

static void z80jt_FD46(void){ zcpu_state.bc.b.h = z80read(zcpu_state.iy.w + (int8_t)z80fetch()); } //ld b, (iy+*)
static void z80jt_FD4E(void){ zcpu_state.bc.b.l = z80read(zcpu_state.iy.w + (int8_t)z80fetch()); } //ld c, (iy+*)
static void z80jt_FD56(void){ zcpu_state.de.b.h = z80read(zcpu_state.iy.w + (int8_t)z80fetch()); } //ld d, (iy+*)
static void z80jt_FD5E(void){ zcpu_state.de.b.l = z80read(zcpu_state.iy.w + (int8_t)z80fetch()); } //ld e, (iy+*)
static void z80jt_FD66(void){ zcpu_state.hl.b.h = z80read(zcpu_state.iy.w + (int8_t)z80fetch()); } //ld h, (iy+*)
static void z80jt_FD6E(void){ zcpu_state.hl.b.l = z80read(zcpu_state.iy.w + (int8_t)z80fetch()); } //ld l, (iy+*)
static void z80jt_FD7E(void){ zcpu_state.af.b.h = z80read(zcpu_state.iy.w + (int8_t)z80fetch()); } //ld a, (iy+*)

//FD block - 8-bit immediate loads

static void z80jt_FD26(void){ zcpu_state.iy.b.h = z80fetch(); } //ld iyh, *
static void z80jt_FD2E(void){ zcpu_state.iy.b.l = z80fetch(); } //ld iyl, *

static void z80jt_FD36(void)//ld (iy+*), *
{ 
	int8_t disp = (int8_t)z80fetch();
	uint8_t imm = z80fetch();
	z80write(zcpu_state.iy.w + disp, imm);
}

//FD block - 16-bit immediate loads

static void z80jt_FD21(void){ zcpu_state.iy.w = z80fetchpair(); } //ld iy, **

//FD block - 8-bit register-to-accumulator ALU group

static void z80jt_FD84(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, zcpu_state.iy.b.h); } //add a, iyh
static void z80jt_FD85(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, zcpu_state.iy.b.l); } //add a, iyl
static void z80jt_FD86(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, z80read(zcpu_state.iy.w + (int8_t)z80fetch())); } //add a, (iy+*)

static void z80jt_FD8C(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, zcpu_state.iy.b.h); } //adc a, iyh
static void z80jt_FD8D(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, zcpu_state.iy.b.l); } //adc a, iyl
static void z80jt_FD8E(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, z80read(zcpu_state.iy.w + (int8_t)z80fetch())); } //adc a, (iy+*)

static void z80jt_FD94(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, zcpu_state.iy.b.h); } //sub a, iyh
static void z80jt_FD95(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, zcpu_state.iy.b.l); } //sub a, iyl
static void z80jt_FD96(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, z80read(zcpu_state.iy.w + (int8_t)z80fetch())); } //sub a, (iy+*)

static void z80jt_FD9C(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, zcpu_state.iy.b.h); } //sbc a, iyh
static void z80jt_FD9D(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, zcpu_state.iy.b.l); } //sbc a, iyl
static void z80jt_FD9E(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, z80read(zcpu_state.iy.w + (int8_t)z80fetch())); } //sbc a, (iy+*)

static void z80jt_FDA4(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, zcpu_state.iy.b.h); } //and a, iyh
static void z80jt_FDA5(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, zcpu_state.iy.b.l); } //and a, iyl
static void z80jt_FDA6(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, z80read(zcpu_state.iy.w + (int8_t)z80fetch())); } //and a, (iy+*)

static void z80jt_FDAC(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, zcpu_state.iy.b.h); } //xor a, iyh
static void z80jt_FDAD(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, zcpu_state.iy.b.l); } //xor a, iyl
static void z80jt_FDAE(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, z80read(zcpu_state.iy.w + (int8_t)z80fetch())); } //xor a, (iy+*)

static void z80jt_FDB4(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, zcpu_state.iy.b.h); } //or a, iyh
static void z80jt_FDB5(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, zcpu_state.iy.b.l); } //or a, iyl
static void z80jt_FDB6(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, z80read(zcpu_state.iy.w + (int8_t)z80fetch())); } //or a, (iy+*)

static void z80jt_FDBC(void){ z80alucp(zcpu_state.af.b.h, zcpu_state.iy.b.h); } //cp a, iyh
static void z80jt_FDBD(void){ z80alucp(zcpu_state.af.b.h, zcpu_state.iy.b.l); } //cp a, iyl
static void z80jt_FDBE(void){ z80alucp(zcpu_state.af.b.h, z80read(zcpu_state.iy.w + (int8_t)z80fetch())); } //cp a, (iy+*)

//FD block - 16-bit arithmetic group

static void z80jt_FD09(void){ zcpu_state.iy.w = z80add16(zcpu_state.iy.w, zcpu_state.bc.w); } //add iy, bc
static void z80jt_FD19(void){ zcpu_state.iy.w = z80add16(zcpu_state.iy.w, zcpu_state.de.w); } //add iy, de
static void z80jt_FD29(void){ zcpu_state.iy.w = z80add16(zcpu_state.iy.w, zcpu_state.iy.w); } //add iy, iy
static void z80jt_FD39(void){ zcpu_state.iy.w = z80add16(zcpu_state.iy.w, zcpu_state.sp.w); } //add iy, sp

static void z80jt_FDF9(void){ zcpu_state.sp.w = zcpu_state.iy.w; } //ld sp, iy

//FD block - 8-bit increment/decrement group

static void z80jt_FD24(void){ zcpu_state.iy.b.h = z80inc8(zcpu_state.iy.b.h); } //inc iyh
static void z80jt_FD2C(void){ zcpu_state.iy.b.l = z80inc8(zcpu_state.iy.b.l); } //inc iyl
static void z80jt_FD25(void){ zcpu_state.iy.b.h = z80dec8(zcpu_state.iy.b.h); } //dec iyh
static void z80jt_FD2D(void){ zcpu_state.iy.b.l = z80dec8(zcpu_state.iy.b.l); } //dec iyl
	
static void z80jt_FD34(void)//inc (iy+*)
{ 
	int8_t disp = (int8_t)z80fetch();
	z80write(zcpu_state.iy.w + disp, z80inc8(z80read(zcpu_state.iy.w + disp)));
}
	
static void z80jt_FD35(void)//dec (iy+*)
{ 
	int8_t disp = (int8_t)z80fetch();
	z80write(zcpu_state.iy.w + disp, z80dec8(z80read(zcpu_state.iy.w + disp)));
}

//FD block - 16-bit increment/decrement group

static void z80jt_FD23(void){ zcpu_state.iy.w++; } //inc iy
static void z80jt_FD2B(void){ zcpu_state.iy.w--; } //dec iy

//FD block - Special indirect loads/stores

static void z80jt_FD22(void){ z80writepair(z80fetchpair(), zcpu_state.iy.w); } //ld (**), iy
static void z80jt_FD2A(void){ zcpu_state.iy.w = z80readpair(z80fetchpair()); } //ld iy, (**)

//FD block - Exchanges

static void z80jt_FDE3(void)//ex (sp), iy
{ 
	uint16_t temp = zcpu_state.iy.w;
	zcpu_state.iy.w = z80readpair(zcpu_state.sp.w);
	z80writepair(zcpu_state.sp.w, temp);
}		

//FD block - Other instructions

static void z80jt_FDE9(void){ zcpu_state.pc.w = zcpu_state.iy.w; } //jp (iy)
static void z80jt_FDCB(void){ z80cycle_cbidx(true); } //bit instructions

//Instruction that doesn't change because of the FD prefix
//Put the opcode back, let the next cycle handle it
static void z80jt_FDxx(void){ zcpu_state.pc.w--; }

//Jump table for FD block
static const z80jt_t z80jt_fdblock[256] = 
{
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx,
	z80jt_FDxx, z80jt_FD09, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx,
	z80jt_FDxx, z80jt_FD19, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx,
	z80jt_FDxx, z80jt_FD21, z80jt_FD22, z80jt_FD23, z80jt_FD24, z80jt_FD25, z80jt_FD26, z80jt_FDxx,
	z80jt_FDxx, z80jt_FD29, z80jt_FD2A, z80jt_FD2B, z80jt_FD2C, z80jt_FD2D, z80jt_FD2E, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FD34, z80jt_FD35, z80jt_FD36, z80jt_FDxx,
	z80jt_FDxx, z80jt_FD39, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FD44, z80jt_FD45, z80jt_FD46, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FD4C, z80jt_FD4D, z80jt_FD4E, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FD54, z80jt_FD55, z80jt_FD56, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FD5C, z80jt_FD5D, z80jt_FD5E, z80jt_FDxx,
	z80jt_FD60, z80jt_FD61, z80jt_FD62, z80jt_FD63, z80jt_FD64, z80jt_FD65, z80jt_FD66, z80jt_FD67,
	z80jt_FD68, z80jt_FD69, z80jt_FD6A, z80jt_FD6B, z80jt_FD6C, z80jt_FD6D, z80jt_FD6E, z80jt_FD6F,
	z80jt_FD70, z80jt_FD71, z80jt_FD72, z80jt_FD73, z80jt_FD74, z80jt_FD75, z80jt_FDxx, z80jt_FD77,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FD7C, z80jt_FD7D, z80jt_FD7E, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FD84, z80jt_FD85, z80jt_FD86, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FD8C, z80jt_FD8D, z80jt_FD8E, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FD94, z80jt_FD95, z80jt_FD96, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FD9C, z80jt_FD9D, z80jt_FD9E, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDA4, z80jt_FDA5, z80jt_FDA6, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDAC, z80jt_FDAD, z80jt_FDAE, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDB4, z80jt_FDB5, z80jt_FDB6, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDBC, z80jt_FDBD, z80jt_FDBE, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDCB, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDE1, z80jt_FDxx, z80jt_FDE3, z80jt_FDxx, z80jt_FDE5, z80jt_FDxx, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDE9, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx,
	z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, 
	z80jt_FDxx, z80jt_FDF9, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx, z80jt_FDxx
};

//Subsection of cycle - FD block, IY-indexed instructions.
//Assumes the FD byte has already been read and PC advanced.
static void z80cycle_fd(void)
{
	uint8_t opcode2 = z80fetch();
	z80jt_fdblock[opcode2]();
}


//ED block - Setting interrupt modes

static void z80jt_ED46(void){ zcpu_state.ctrl &= ~Z80_CTRL_IM1; zcpu_state.ctrl &= ~Z80_CTRL_IM2; } //im 0
static void z80jt_ED66(void){ zcpu_state.ctrl &= ~Z80_CTRL_IM1; zcpu_state.ctrl &= ~Z80_CTRL_IM2; }
static void z80jt_ED56(void){ zcpu_state.ctrl |= Z80_CTRL_IM1; zcpu_state.ctrl &= ~Z80_CTRL_IM2; }  //im 1
static void z80jt_ED76(void){ zcpu_state.ctrl |= Z80_CTRL_IM1; zcpu_state.ctrl &= ~Z80_CTRL_IM2; }  //z180 SLEEP (im 1 alias)
static void z80jt_ED4E(void){ zcpu_state.ctrl &= ~Z80_CTRL_IM1; zcpu_state.ctrl |= Z80_CTRL_IM2; }  //im invalid
static void z80jt_ED6E(void){ zcpu_state.ctrl &= ~Z80_CTRL_IM1; zcpu_state.ctrl |= Z80_CTRL_IM2; }  //im invalid
static void z80jt_ED5E(void){ zcpu_state.ctrl |= Z80_CTRL_IM1; zcpu_state.ctrl |= Z80_CTRL_IM2; }   //im 2
static void z80jt_ED7E(void){ zcpu_state.ctrl |= Z80_CTRL_IM1; zcpu_state.ctrl |= Z80_CTRL_IM2; }

//ED block - Block-copy instructions

static void z80jt_EDA0(void)//ldi
{
	uint8_t rb = z80read(zcpu_state.hl.w);
	z80write(zcpu_state.de.w, rb);
	zcpu_state.hl.w++;
	zcpu_state.de.w++;
	zcpu_state.bc.w--;

	//What the flying fuck? Does any program actually depend on this?
	z80alterflag(Z80_FLAG_N, false);
	z80alterflag(Z80_FLAG_H, false);
	z80alterflag(Z80_FLAG_PV, zcpu_state.bc.w != 0);
	z80alterflag(Z80_FLAG_F3, (rb + zcpu_state.af.b.h) & 0x08);
	z80alterflag(Z80_FLAG_F5, (rb + zcpu_state.af.b.h) & 0x02);
}

static void z80jt_EDB0(void)//ldir
{
	do {
		uint8_t rb = z80read(zcpu_state.hl.w);
		z80write(zcpu_state.de.w, rb);
		zcpu_state.hl.w++;
		zcpu_state.de.w++;
		zcpu_state.bc.w--;
		z80alterflag(Z80_FLAG_N, false);
		z80alterflag(Z80_FLAG_H, false);
		z80alterflag(Z80_FLAG_PV, zcpu_state.bc.w != 0);
		z80alterflag(Z80_FLAG_F3, (rb + zcpu_state.af.b.h) & 0x08);
		z80alterflag(Z80_FLAG_F5, (rb + zcpu_state.af.b.h) & 0x02);
	} while(zcpu_state.bc.w != 0);
}

static void z80jt_EDA8(void)//ldd
{
	uint8_t rb = z80read(zcpu_state.hl.w);
	z80write(zcpu_state.de.w, rb);
	zcpu_state.hl.w--;
	zcpu_state.de.w--;
	zcpu_state.bc.w--;
	z80alterflag(Z80_FLAG_N, false);
	z80alterflag(Z80_FLAG_H, false);
	z80alterflag(Z80_FLAG_PV, zcpu_state.bc.w != 0);
	z80alterflag(Z80_FLAG_F3, (rb + zcpu_state.af.b.h) & 0x08);
	z80alterflag(Z80_FLAG_F5, (rb + zcpu_state.af.b.h) & 0x02);
}
	
static void z80jt_EDB8(void)//lddr
{
	do {
		uint8_t rb = z80read(zcpu_state.hl.w);
		z80write(zcpu_state.de.w, rb);
		zcpu_state.hl.w--;
		zcpu_state.de.w--;
		zcpu_state.bc.w--;
		z80alterflag(Z80_FLAG_N, false);
		z80alterflag(Z80_FLAG_H, false);
		z80alterflag(Z80_FLAG_PV, zcpu_state.bc.w != 0);
		z80alterflag(Z80_FLAG_F3, (rb + zcpu_state.af.b.h) & 0x08);
		z80alterflag(Z80_FLAG_F5, (rb + zcpu_state.af.b.h) & 0x02);
	} while(zcpu_state.bc.w != 0);
}
	
static void z80cpgroup(int dec, int rep)
{
	uint8_t oldc = zcpu_state.af.b.l & Z80_FLAG_C;
	
	uint8_t lastdiff = 0;
	do {
		lastdiff = z80alusub(zcpu_state.af.b.h, z80read(zcpu_state.hl.w));
		
		if(dec)
			zcpu_state.hl.w--;
		else
			zcpu_state.hl.w++;
		
		zcpu_state.bc.w--;
	} while(rep && zcpu_state.bc.w != 0 && !(zcpu_state.af.b.l & Z80_FLAG_Z));
	
	z80alterflag(Z80_FLAG_PV, zcpu_state.bc.w != 0);
	z80alterflag(Z80_FLAG_C,  oldc != 0);
	
	//what!? Sean Young gives this definition and it seems to work.
	//but what the fuck is this for?
	lastdiff -= (zcpu_state.af.b.l & Z80_FLAG_H) ? 1 : 0;
	z80alterflag(Z80_FLAG_F3,  (lastdiff & 8) != 0);
	z80alterflag(Z80_FLAG_F5,  (lastdiff & 2) != 0);	
}

static void z80jt_EDA1(void)//cpi
{
	z80cpgroup(0, 0);
}

static void z80jt_EDB1(void)//cpir
{
	z80cpgroup(0, 1);
}
	
static void z80jt_EDA9(void)//cpd
{
	z80cpgroup(1, 0);
}

static void z80jt_EDB9(void)//cpdr
{
	z80cpgroup(1, 1);
}
	
static void z80jt_EDA2(void)//ini
{
	z80write(zcpu_state.hl.w, z80in(zcpu_state.bc.b.l));
	zcpu_state.hl.w++;
	zcpu_state.bc.b.h--;
}

static void z80jt_EDB2(void)//inir
{
	z80write(zcpu_state.hl.w, z80in(zcpu_state.bc.b.l));
	zcpu_state.hl.w++;
	zcpu_state.bc.b.h--;
	if(zcpu_state.bc.b.h != 0)
		zcpu_state.pc.w -= 2;
}
	
static void z80jt_EDAA(void)//ind
{
	z80write(zcpu_state.hl.w, z80in(zcpu_state.bc.b.l));
	zcpu_state.hl.w--;
	zcpu_state.bc.b.h--;
}

static void z80jt_EDBA(void)//indr
{
	z80write(zcpu_state.hl.w, z80in(zcpu_state.bc.b.l));
	zcpu_state.hl.w--;
	zcpu_state.bc.b.h--;
	if(zcpu_state.bc.b.h != 0)
		zcpu_state.pc.w -= 2;
}
	
static void z80jt_EDA3(void)//outi
{
	z80out(zcpu_state.bc.b.l, z80read(zcpu_state.hl.w));
	zcpu_state.hl.w++;
	zcpu_state.bc.b.h--;
}

static void z80jt_EDB3(void)//otir
{
	z80out(zcpu_state.bc.b.l, z80read(zcpu_state.hl.w));
	zcpu_state.hl.w++;
	zcpu_state.bc.b.h--;
	if(zcpu_state.bc.b.h != 0)
		zcpu_state.pc.w -= 2;
}
	
static void z80jt_EDAB(void)//outd
{ 
	z80out(zcpu_state.bc.b.l, z80read(zcpu_state.hl.w));
	zcpu_state.hl.w--;
	zcpu_state.bc.b.h--;
}

static void z80jt_EDBB(void)//otdr
{
	z80out(zcpu_state.bc.b.l, z80read(zcpu_state.hl.w));
	zcpu_state.hl.w--;
	zcpu_state.bc.b.h--;
	if(zcpu_state.bc.b.h != 0)
		zcpu_state.pc.w -= 2;
}


//ED block - 16-bit loads/stores to immediate addresses
	
static void z80jt_ED43(void){ z80writepair(z80fetchpair(), zcpu_state.bc.w); } //ld (**), bc
static void z80jt_ED53(void){ z80writepair(z80fetchpair(), zcpu_state.de.w); } //ld (**), de
static void z80jt_ED63(void){ z80writepair(z80fetchpair(), zcpu_state.hl.w); } //ld (**), hl
static void z80jt_ED73(void){ z80writepair(z80fetchpair(), zcpu_state.sp.w); } //ld (**), sp

static void z80jt_ED4B(void){ zcpu_state.bc.w = z80readpair(z80fetchpair()); } //ld bc, (**)
static void z80jt_ED5B(void){ zcpu_state.de.w = z80readpair(z80fetchpair()); } //ld de, (**)
static void z80jt_ED6B(void){ zcpu_state.hl.w = z80readpair(z80fetchpair()); } //ld hl, (**)
static void z80jt_ED7B(void){ zcpu_state.sp.w = z80readpair(z80fetchpair()); } //ld sp, (**)

//ED block - 16-bit arithmetic with carry

static void z80jt_ED42(void)//sbc hl, bc
{
	zcpu_state.hl.b.l = z80alusbc(zcpu_state.hl.b.l, zcpu_state.bc.b.l);
	zcpu_state.hl.b.h = z80alusbc(zcpu_state.hl.b.h, zcpu_state.bc.b.h);
	z80alterflag(Z80_FLAG_Z, zcpu_state.hl.w == 0);
}
	
static void z80jt_ED52(void)//sbc hl, de
{
	zcpu_state.hl.b.l = z80alusbc(zcpu_state.hl.b.l, zcpu_state.de.b.l);
	zcpu_state.hl.b.h = z80alusbc(zcpu_state.hl.b.h, zcpu_state.de.b.h);
	z80alterflag(Z80_FLAG_Z, zcpu_state.hl.w == 0);
}
	
static void z80jt_ED62(void)//sbc hl, hl
{
	zcpu_state.hl.b.l = z80alusbc(zcpu_state.hl.b.l, zcpu_state.hl.b.l);
	zcpu_state.hl.b.h = z80alusbc(zcpu_state.hl.b.h, zcpu_state.hl.b.h);
	z80alterflag(Z80_FLAG_Z, zcpu_state.hl.w == 0);
}
	
static void z80jt_ED72(void)//sbc hl, sp
{
	zcpu_state.hl.b.l = z80alusbc(zcpu_state.hl.b.l, zcpu_state.sp.b.l);
	zcpu_state.hl.b.h = z80alusbc(zcpu_state.hl.b.h, zcpu_state.sp.b.h);
	z80alterflag(Z80_FLAG_Z, zcpu_state.hl.w == 0);
}
	
static void z80jt_ED4A(void)//adc hl, bc
{
	zcpu_state.hl.b.l = z80aluadc(zcpu_state.hl.b.l, zcpu_state.bc.b.l);
	zcpu_state.hl.b.h = z80aluadc(zcpu_state.hl.b.h, zcpu_state.bc.b.h);
	z80alterflag(Z80_FLAG_Z, zcpu_state.hl.w == 0);
}
	
static void z80jt_ED5A(void)//adc hl, de
{ 
	zcpu_state.hl.b.l = z80aluadc(zcpu_state.hl.b.l, zcpu_state.de.b.l);
	zcpu_state.hl.b.h = z80aluadc(zcpu_state.hl.b.h, zcpu_state.de.b.h);
	z80alterflag(Z80_FLAG_Z, zcpu_state.hl.w == 0);
}
	
static void z80jt_ED6A(void)//adc hl, hl
{
	zcpu_state.hl.b.l = z80aluadc(zcpu_state.hl.b.l, zcpu_state.hl.b.l);
	zcpu_state.hl.b.h = z80aluadc(zcpu_state.hl.b.h, zcpu_state.hl.b.h);
	z80alterflag(Z80_FLAG_Z, zcpu_state.hl.w == 0);
}
	
static void z80jt_ED7A(void)//adc hl, sp
{
	zcpu_state.hl.b.l = z80aluadc(zcpu_state.hl.b.l, zcpu_state.sp.b.l);
	zcpu_state.hl.b.h = z80aluadc(zcpu_state.hl.b.h, zcpu_state.sp.b.h);
	z80alterflag(Z80_FLAG_Z, zcpu_state.hl.w == 0);
}

//ED block - Nibble exchanging

static void z80jt_ED67(void)//rrd
{
	uint8_t templ;
	uint8_t temph;
	
	templ = z80read(zcpu_state.hl.w);
	temph = zcpu_state.af.b.h;
	
	zcpu_state.af.b.h &= 0xF0;
	zcpu_state.af.b.h |= templ & 0x0F;

	templ >>= 4;
	templ |= (temph & 0x0F) << 4;
	
	z80write(zcpu_state.hl.w, templ);
	zcpu_state.af.b.l = z80resflag_sz53p[zcpu_state.af.b.h] | (zcpu_state.af.b.l & Z80_FLAG_C);
}

static void z80jt_ED6F(void)//rld
{
	uint8_t templ;
	uint8_t temph;
	
	templ = z80read(zcpu_state.hl.w);
	temph = zcpu_state.af.b.h;

	zcpu_state.af.b.h &= 0xF0;
	zcpu_state.af.b.h |= (templ >> 4) & 0x0F;

	templ <<= 4;
	templ |= temph & 0x0F;

	z80write(zcpu_state.hl.w, templ);
	zcpu_state.af.b.l = z80resflag_sz53p[zcpu_state.af.b.h] | (zcpu_state.af.b.l & Z80_FLAG_C);
}

//ED block - Negation

static void z80jt_ED44(void){ zcpu_state.af.b.h = z80alusub(0, zcpu_state.af.b.h); } //neg (0x44 is canonical)
static void z80jt_ED54(void){ zcpu_state.af.b.h = z80alusub(0, zcpu_state.af.b.h); } //neg
static void z80jt_ED64(void){ zcpu_state.af.b.h = z80alusub(0, zcpu_state.af.b.h); } //neg
static void z80jt_ED74(void){ zcpu_state.af.b.h = z80alusub(0, zcpu_state.af.b.h); } //neg
static void z80jt_ED4C(void){ zcpu_state.af.b.h = z80alusub(0, zcpu_state.af.b.h); } //neg
static void z80jt_ED5C(void){ zcpu_state.af.b.h = z80alusub(0, zcpu_state.af.b.h); } //neg
static void z80jt_ED6C(void){ zcpu_state.af.b.h = z80alusub(0, zcpu_state.af.b.h); } //neg
static void z80jt_ED7C(void){ zcpu_state.af.b.h = z80alusub(0, zcpu_state.af.b.h); } //neg

//ED block - I/O

static void z80jt_ED40(void){ zcpu_state.bc.b.h = z80inwithflags(zcpu_state.bc.b.l); } //in b, (c)
static void z80jt_ED48(void){ zcpu_state.bc.b.l = z80inwithflags(zcpu_state.bc.b.l); } //in c, (c)
static void z80jt_ED50(void){ zcpu_state.de.b.h = z80inwithflags(zcpu_state.bc.b.l); } //in d, (c)
static void z80jt_ED58(void){ zcpu_state.de.b.l = z80inwithflags(zcpu_state.bc.b.l); } //in e, (c)
static void z80jt_ED60(void){ zcpu_state.hl.b.h = z80inwithflags(zcpu_state.bc.b.l); } //in h, (c)
static void z80jt_ED68(void){ zcpu_state.hl.b.l = z80inwithflags(zcpu_state.bc.b.l); } //in l, (c)
static void z80jt_ED70(void){ (void)z80inwithflags(zcpu_state.bc.b.l); } //in (c)
static void z80jt_ED78(void){ zcpu_state.af.b.h = z80inwithflags(zcpu_state.bc.b.l); } //in a, (c)

static void z80jt_ED41(void){ z80out(zcpu_state.bc.b.l, zcpu_state.bc.b.h); } //out (c), b
static void z80jt_ED49(void){ z80out(zcpu_state.bc.b.l, zcpu_state.bc.b.l); } //out (c), c
static void z80jt_ED51(void){ z80out(zcpu_state.bc.b.l, zcpu_state.de.b.h); } //out (c), d
static void z80jt_ED59(void){ z80out(zcpu_state.bc.b.l, zcpu_state.de.b.l); } //out (c), e
static void z80jt_ED61(void){ z80out(zcpu_state.bc.b.l, zcpu_state.hl.b.h); } //out (c), h
static void z80jt_ED69(void){ z80out(zcpu_state.bc.b.l, zcpu_state.hl.b.l); } //out (c), l
static void z80jt_ED71(void){ z80out(zcpu_state.bc.b.l, 0); } //out (c), 0
static void z80jt_ED79(void){ z80out(zcpu_state.bc.b.l, zcpu_state.af.b.h); } //out (c), a

//ED block - return from interrupts

static void z80jt_ED45(void){ zcpu_state.pc.w = z80pop(); } //retn
static void z80jt_ED55(void){ zcpu_state.pc.w = z80pop(); } //retn
static void z80jt_ED65(void){ zcpu_state.pc.w = z80pop(); } //retn
static void z80jt_ED75(void){ zcpu_state.pc.w = z80pop(); } //retn

static void z80jt_ED4D(void){ zcpu_state.pc.w = z80pop(); } //reti
static void z80jt_ED5D(void){ zcpu_state.pc.w = z80pop(); } //retn
static void z80jt_ED6D(void){ zcpu_state.pc.w = z80pop(); } //retn
static void z80jt_ED7D(void){ zcpu_state.pc.w = z80pop(); } //retn

//ED block - loads with I, R

static void z80jt_ED47(void){ zcpu_state.i = zcpu_state.af.b.h; } //ld i, a
static void z80jt_ED57(void){ zcpu_state.af.b.h = zcpu_state.i; } //ld a, i

static void z80jt_ED4F(void){ zcpu_state.r = zcpu_state.af.b.h; } //ld r, a
static void z80jt_ED5F(void){ zcpu_state.af.b.h = zcpu_state.r; } //ld a, r

//ED block - NOPs

static void z80jt_EDxx(void){ } //non-implemented ED-block instructions are NOPs

//Jump table for ED block instructions
static const z80jt_t z80jt_edblock[256] = 
{
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_ED40, z80jt_ED41, z80jt_ED42, z80jt_ED43, z80jt_ED44, z80jt_ED45, z80jt_ED46, z80jt_ED47,
	z80jt_ED48, z80jt_ED49, z80jt_ED4A, z80jt_ED4B, z80jt_ED4C, z80jt_ED4D, z80jt_ED4E, z80jt_ED4F,
	z80jt_ED50, z80jt_ED51, z80jt_ED52, z80jt_ED53, z80jt_ED54, z80jt_ED55, z80jt_ED56, z80jt_ED57,
	z80jt_ED58, z80jt_ED59, z80jt_ED5A, z80jt_ED5B, z80jt_ED5C, z80jt_ED5D, z80jt_ED5E, z80jt_ED5F,
	z80jt_ED60, z80jt_ED61, z80jt_ED62, z80jt_ED63, z80jt_ED64, z80jt_ED65, z80jt_ED66, z80jt_ED67,
	z80jt_ED68, z80jt_ED69, z80jt_ED6A, z80jt_ED6B, z80jt_ED6C, z80jt_ED6D, z80jt_ED6E, z80jt_ED6F,
	z80jt_ED70, z80jt_ED71, z80jt_ED72, z80jt_ED73, z80jt_ED74, z80jt_ED75, z80jt_ED76, z80jt_EDxx,
	z80jt_ED78, z80jt_ED79, z80jt_ED7A, z80jt_ED7B, z80jt_ED7C, z80jt_ED7D, z80jt_ED7E, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDA0, z80jt_EDA1, z80jt_EDA2, z80jt_EDA3, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDA8, z80jt_EDA9, z80jt_EDAA, z80jt_EDAB, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDB0, z80jt_EDB1, z80jt_EDB2, z80jt_EDB3, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDB8, z80jt_EDB9, z80jt_EDBA, z80jt_EDBB, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
	z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx, z80jt_EDxx,
};

//Subsection of cycle - ED block extended instructions.
//Assumes the ED byte has already been read and PC advanced.
static void z80cycle_ed(void)
{
	uint8_t opcode2 = z80fetch();
	z80jt_edblock[opcode2]();
}


//Subsection of cycle - CB block bit-manipulation instructions.
//Assumes the CB byte has already been read and PC advanced.
static void z80cycle_cb(void)
{
	uint8_t opcode2 = z80fetch();
	
	//Single-bit instructions follow this pattern for bit selection
	uint8_t bitnum = (opcode2 >> 3) & 0x7;
	uint8_t bitmask = (1<<bitnum);
	
	//CB block follows a single pattern for the one operand
	uint8_t operand = 0;
	switch(opcode2 & 0x7)
	{
		case 0: operand = zcpu_state.bc.b.h; break; //b
		case 1: operand = zcpu_state.bc.b.l; break; //c
		case 2: operand = zcpu_state.de.b.h; break; //d
		case 3: operand = zcpu_state.de.b.l; break; //e
		case 4: operand = zcpu_state.hl.b.h; break; //h
		case 5: operand = zcpu_state.hl.b.l; break; //l
		case 6: operand = z80read(zcpu_state.hl.w); break; //(hl)
		case 7: operand = zcpu_state.af.b.h; break; //a
	}
	
	//Disregard operand now, and just switch on the op
	switch(opcode2 >> 3)
	{
		case 0x00: operand = z80rlc(operand); break; //rlc r
		case 0x01: operand = z80rrc(operand); break; //rrc r
		case 0x02: operand = z80rl(operand); break; //rl r
		case 0x03: operand = z80rr(operand); break; //rr r
		case 0x04: operand = z80sla(operand); break; //sla r
		case 0x05: operand = z80sra(operand); break; //sra r
		case 0x06: operand = z80sll(operand); break; //sll r
		case 0x07: operand = z80srl(operand); break; //srl r
		
		case 0x08: //bit 0,r
		case 0x09: //bit 1,r
		case 0x0A: //bit 2,r
		case 0x0B: //bit 3,r
		case 0x0C: //bit 4,r
		case 0x0D: //bit 5,r
		case 0x0E: //bit 6,r
		case 0x0F: //bit 7,r
			
			zcpu_state.af.b.l = (zcpu_state.af.b.l & Z80_FLAG_C) | z80resflag_sz53p[operand & bitmask];
		
			z80alterflag(Z80_FLAG_N, 0);
			z80alterflag(Z80_FLAG_H, 1);
		
			//3/5 flags affected unless load via HL was performed. huh?
			if( (opcode2 & 0x7) != 6 )
			{
				z80alterflag(Z80_FLAG_F3, (operand & Z80_FLAG_F3) != 0);
				z80alterflag(Z80_FLAG_F5, (operand & Z80_FLAG_F5) != 0);
			}
			
			operand &= bitmask;
			
			break;
		
		case 0x10: //res 0,r
		case 0x11: //res 1,r
		case 0x12: //res 2,r
		case 0x13: //res 3,r
		case 0x14: //res 4,r
		case 0x15: //res 5,r
		case 0x16: //res 6,r
		case 0x17: //res 7,r
			operand &= ~bitmask;
			break;
			
		case 0x18: //set 0,r
		case 0x19: //set 1,r
		case 0x1A: //set 2,r
		case 0x1B: //set 3,r
		case 0x1C: //set 4,r
		case 0x1D: //set 5,r
		case 0x1E: //set 6,r
		case 0x1F: //set 7,r
			operand |= bitmask;
			break;
		
		default:
			break;
	}
	
	//All but "bit n, r" cause a store back. "bit n, r" affect flags.
	if((opcode2 & 0xC0) != 0x40)
	{
		switch(opcode2 & 0x7)
		{
			case 0: zcpu_state.bc.b.h = operand; break; //b
			case 1: zcpu_state.bc.b.l = operand; break; //c
			case 2: zcpu_state.de.b.h = operand; break; //d
			case 3: zcpu_state.de.b.l = operand; break; //e
			case 4: zcpu_state.hl.b.h = operand; break; //h
			case 5: zcpu_state.hl.b.l = operand; break; //l
			case 6: z80write(zcpu_state.hl.w, operand); break; //(hl)
			case 7: zcpu_state.af.b.h = operand; break; //a
		}	
	}
		
		
}

//Relative jumps, including DJNZ
		
static void z80jt_10(void)//djnz *
{
	int8_t target = z80fetch();
	zcpu_state.bc.b.h--;
	if(zcpu_state.bc.b.h != 0)
		zcpu_state.pc.w += target;
}
			
static void z80jt_20(void)//jr nz, *
{
	int8_t target = z80fetch();
	if(!(zcpu_state.af.b.l & Z80_FLAG_Z))
		zcpu_state.pc.w += target;
}
	
static void z80jt_30(void)//jr nc, *
{
	int8_t target = z80fetch();
	if(!(zcpu_state.af.b.l & Z80_FLAG_C))
		zcpu_state.pc.w += target;
}
	
static void z80jt_18(void)//jr *
{
	int8_t target = z80fetch();
	zcpu_state.pc.w += target;
}
	
static void z80jt_28(void)//jr z, *
{
	int8_t target = z80fetch();
	if(zcpu_state.af.b.l & Z80_FLAG_Z)
		zcpu_state.pc.w += target;
}
	
static void z80jt_38(void)//jr c, *
{
	int8_t target = z80fetch();
	if(zcpu_state.af.b.l & Z80_FLAG_C)
		zcpu_state.pc.w += target;
}

//Absolute jumps

static void z80jt_C3(void)//jp **
{
	zcpu_state.pc.w = z80fetchpair();
}

static void z80jt_C2(void)//jp nz, **
{
	uint16_t target = z80fetchpair();
	if(!(zcpu_state.af.b.l & Z80_FLAG_Z))
		zcpu_state.pc.w = target;
}
static void z80jt_D2(void)//jp nc, **
{
	uint16_t target = z80fetchpair();
	if(!(zcpu_state.af.b.l & Z80_FLAG_C))
		zcpu_state.pc.w = target;
}
static void z80jt_E2(void)//jp po, **
{
	uint16_t target = z80fetchpair();
	if(!(zcpu_state.af.b.l & Z80_FLAG_PV))
		zcpu_state.pc.w = target;
}
static void z80jt_F2(void)//jp p, **
{
	uint16_t target = z80fetchpair();
	if(!(zcpu_state.af.b.l & Z80_FLAG_S))
		zcpu_state.pc.w = target;
}
	
static void z80jt_CA(void)//jp z, **
{
	uint16_t target = z80fetchpair();
	if(zcpu_state.af.b.l & Z80_FLAG_Z)
		zcpu_state.pc.w = target;
}
static void z80jt_DA(void)//jp c, **
{
	uint16_t target = z80fetchpair();
	if(zcpu_state.af.b.l & Z80_FLAG_C)
		zcpu_state.pc.w = target;
}
static void z80jt_EA(void)//jp pe, **
{
	uint16_t target = z80fetchpair();
	if(zcpu_state.af.b.l & Z80_FLAG_PV)
		zcpu_state.pc.w = target;
}
static void z80jt_FA(void)//jp m, **
{
	uint16_t target = z80fetchpair();
	if(zcpu_state.af.b.l & Z80_FLAG_S)
		zcpu_state.pc.w = target;
}

static void z80jt_E9(void)//jp (hl)
{
	zcpu_state.pc.w = zcpu_state.hl.w;
}

//Absolute calls
	
static void z80jt_CD(void)//call **
{
	uint16_t target = z80fetchpair();
	z80push(zcpu_state.pc.w);
	zcpu_state.pc.w = target;
}
	
static void z80jt_C4(void)//call nz, **
{
	uint16_t target = z80fetchpair();
	if(!(zcpu_state.af.b.l & Z80_FLAG_Z))
	{
		z80push(zcpu_state.pc.w);
		zcpu_state.pc.w = target;
	}
}
static void z80jt_D4(void)//call nc, **
{
	uint16_t target = z80fetchpair();
	if(!(zcpu_state.af.b.l & Z80_FLAG_C))
	{
		z80push(zcpu_state.pc.w);
		zcpu_state.pc.w = target;
	}
}
static void z80jt_E4(void)//call po, **
{
	uint16_t target = z80fetchpair();
	if(!(zcpu_state.af.b.l & Z80_FLAG_PV))
	{
		z80push(zcpu_state.pc.w);
		zcpu_state.pc.w = target;
	}
}
static void z80jt_F4(void)//call p, **
{
	uint16_t target = z80fetchpair();
	if(!(zcpu_state.af.b.l & Z80_FLAG_S))
	{
		z80push(zcpu_state.pc.w);
		zcpu_state.pc.w = target;
	}
}
	
static void z80jt_CC(void)//call z, **
{
	uint16_t target = z80fetchpair();
	if(zcpu_state.af.b.l & Z80_FLAG_Z)
	{
		z80push(zcpu_state.pc.w);
		zcpu_state.pc.w = target;
	}
}
static void z80jt_DC(void)//call c, **
{
	uint16_t target = z80fetchpair();
	if(zcpu_state.af.b.l & Z80_FLAG_C)
	{
		z80push(zcpu_state.pc.w);
		zcpu_state.pc.w = target;
	}
}
static void z80jt_EC(void)//call pe, **
{
	uint16_t target = z80fetchpair();
	if(zcpu_state.af.b.l & Z80_FLAG_PV)
	{
		z80push(zcpu_state.pc.w);
		zcpu_state.pc.w = target;
	}
}
static void z80jt_FC(void)//call m, **
{
	uint16_t target = z80fetchpair();
	if(zcpu_state.af.b.l & Z80_FLAG_S)
	{
		z80push(zcpu_state.pc.w);
		zcpu_state.pc.w = target;
	}
}

//Pushes and pops

static void z80jt_C5(void){ z80push(zcpu_state.bc.w); } //push bc
static void z80jt_D5(void){ z80push(zcpu_state.de.w); } //push de
static void z80jt_E5(void){ z80push(zcpu_state.hl.w); } //push hl
static void z80jt_F5(void){ z80push(zcpu_state.af.w); } //push af
static void z80jt_F1(void){ zcpu_state.af.w = z80pop(); } //pop af
static void z80jt_E1(void){ zcpu_state.hl.w = z80pop(); } //pop hl
static void z80jt_D1(void){ zcpu_state.de.w = z80pop(); } //pop de
static void z80jt_C1(void){ zcpu_state.bc.w = z80pop(); } //pop bc

//8-bit register-to-register load group

static void z80jt_40(void){ zcpu_state.bc.b.h = zcpu_state.bc.b.h; } //ld b, b
static void z80jt_41(void){ zcpu_state.bc.b.h = zcpu_state.bc.b.l; } //ld b, c
static void z80jt_42(void){ zcpu_state.bc.b.h = zcpu_state.de.b.h; } //ld b, d
static void z80jt_43(void){ zcpu_state.bc.b.h = zcpu_state.de.b.l; } //ld b, e
static void z80jt_44(void){ zcpu_state.bc.b.h = zcpu_state.hl.b.h; } //ld b, h
static void z80jt_45(void){ zcpu_state.bc.b.h = zcpu_state.hl.b.l; } //ld b, l
static void z80jt_47(void){ zcpu_state.bc.b.h = zcpu_state.af.b.h; } //ld b, a

static void z80jt_50(void){ zcpu_state.de.b.h = zcpu_state.bc.b.h; } //ld d, b
static void z80jt_51(void){ zcpu_state.de.b.h = zcpu_state.bc.b.l; } //ld d, c
static void z80jt_52(void){ zcpu_state.de.b.h = zcpu_state.de.b.h; } //ld d, d
static void z80jt_53(void){ zcpu_state.de.b.h = zcpu_state.de.b.l; } //ld d, e
static void z80jt_54(void){ zcpu_state.de.b.h = zcpu_state.hl.b.h; } //ld d, h
static void z80jt_55(void){ zcpu_state.de.b.h = zcpu_state.hl.b.l; } //ld d, l
static void z80jt_57(void){ zcpu_state.de.b.h = zcpu_state.af.b.h; } //ld d, a

static void z80jt_60(void){ zcpu_state.hl.b.h = zcpu_state.bc.b.h; } //ld h, b
static void z80jt_61(void){ zcpu_state.hl.b.h = zcpu_state.bc.b.l; } //ld h, c
static void z80jt_62(void){ zcpu_state.hl.b.h = zcpu_state.de.b.h; } //ld h, d
static void z80jt_63(void){ zcpu_state.hl.b.h = zcpu_state.de.b.l; } //ld h, e
static void z80jt_64(void){ zcpu_state.hl.b.h = zcpu_state.hl.b.h; } //ld h, h
static void z80jt_65(void){ zcpu_state.hl.b.h = zcpu_state.hl.b.l; } //ld h, l
static void z80jt_67(void){ zcpu_state.hl.b.h = zcpu_state.af.b.h; } //ld h, a

static void z80jt_48(void){ zcpu_state.bc.b.l = zcpu_state.bc.b.h; } //ld c, b
static void z80jt_49(void){ zcpu_state.bc.b.l = zcpu_state.bc.b.l; } //ld c, c
static void z80jt_4A(void){ zcpu_state.bc.b.l = zcpu_state.de.b.h; } //ld c, d
static void z80jt_4B(void){ zcpu_state.bc.b.l = zcpu_state.de.b.l; } //ld c, e
static void z80jt_4C(void){ zcpu_state.bc.b.l = zcpu_state.hl.b.h; } //ld c, h
static void z80jt_4D(void){ zcpu_state.bc.b.l = zcpu_state.hl.b.l; } //ld c, l
static void z80jt_4F(void){ zcpu_state.bc.b.l = zcpu_state.af.b.h; } //ld c, a

static void z80jt_58(void){ zcpu_state.de.b.l = zcpu_state.bc.b.h; } //ld e, b
static void z80jt_59(void){ zcpu_state.de.b.l = zcpu_state.bc.b.l; } //ld e, c
static void z80jt_5A(void){ zcpu_state.de.b.l = zcpu_state.de.b.h; } //ld e, d
static void z80jt_5B(void){ zcpu_state.de.b.l = zcpu_state.de.b.l; } //ld e, e
static void z80jt_5C(void){ zcpu_state.de.b.l = zcpu_state.hl.b.h; } //ld e, h
static void z80jt_5D(void){ zcpu_state.de.b.l = zcpu_state.hl.b.l; } //ld e, l
static void z80jt_5F(void){ zcpu_state.de.b.l = zcpu_state.af.b.h; } //ld e, a

static void z80jt_68(void){ zcpu_state.hl.b.l = zcpu_state.bc.b.h; } //ld l, b
static void z80jt_69(void){ zcpu_state.hl.b.l = zcpu_state.bc.b.l; } //ld l, c
static void z80jt_6A(void){ zcpu_state.hl.b.l = zcpu_state.de.b.h; } //ld l, d
static void z80jt_6B(void){ zcpu_state.hl.b.l = zcpu_state.de.b.l; } //ld l, e
static void z80jt_6C(void){ zcpu_state.hl.b.l = zcpu_state.hl.b.h; } //ld l, h
static void z80jt_6D(void){ zcpu_state.hl.b.l = zcpu_state.hl.b.l; } //ld l, l
static void z80jt_6F(void){ zcpu_state.hl.b.l = zcpu_state.af.b.h; } //ld l, a

static void z80jt_78(void){ zcpu_state.af.b.h = zcpu_state.bc.b.h; } //ld a, b
static void z80jt_79(void){ zcpu_state.af.b.h = zcpu_state.bc.b.l; } //ld a, c
static void z80jt_7A(void){ zcpu_state.af.b.h = zcpu_state.de.b.h; } //ld a, d
static void z80jt_7B(void){ zcpu_state.af.b.h = zcpu_state.de.b.l; } //ld a, e
static void z80jt_7C(void){ zcpu_state.af.b.h = zcpu_state.hl.b.h; } //ld a, h
static void z80jt_7D(void){ zcpu_state.af.b.h = zcpu_state.hl.b.l; } //ld a, l
static void z80jt_7F(void){ zcpu_state.af.b.h = zcpu_state.af.b.h; } //ld a, a

//8-bit loads/stores, indirect through HL

static void z80jt_70(void){ z80write(zcpu_state.hl.w, zcpu_state.bc.b.h); } //ld (hl), b
static void z80jt_71(void){ z80write(zcpu_state.hl.w, zcpu_state.bc.b.l); } //ld (hl), c
static void z80jt_72(void){ z80write(zcpu_state.hl.w, zcpu_state.de.b.h); } //ld (hl), d
static void z80jt_73(void){ z80write(zcpu_state.hl.w, zcpu_state.de.b.l); } //ld (hl), e
static void z80jt_74(void){ z80write(zcpu_state.hl.w, zcpu_state.hl.b.h); } //ld (hl), h
static void z80jt_75(void){ z80write(zcpu_state.hl.w, zcpu_state.hl.b.l); } //ld (hl), l
static void z80jt_77(void){ z80write(zcpu_state.hl.w, zcpu_state.af.b.h); } //ld (hl), a

static void z80jt_46(void){ zcpu_state.bc.b.h = z80read(zcpu_state.hl.w); } //ld b, (hl)
static void z80jt_4E(void){ zcpu_state.bc.b.l = z80read(zcpu_state.hl.w); } //ld c, (hl)
static void z80jt_56(void){ zcpu_state.de.b.h = z80read(zcpu_state.hl.w); } //ld d, (hl)
static void z80jt_5E(void){ zcpu_state.de.b.l = z80read(zcpu_state.hl.w); } //ld e, (hl)
static void z80jt_66(void){ zcpu_state.hl.b.h = z80read(zcpu_state.hl.w); } //ld h, (hl)
static void z80jt_6E(void){ zcpu_state.hl.b.l = z80read(zcpu_state.hl.w); } //ld l, (hl)
static void z80jt_7E(void){ zcpu_state.af.b.h = z80read(zcpu_state.hl.w); } //ld a, (hl)

//8-bit immediate loads

static void z80jt_06(void){ zcpu_state.bc.b.h = z80fetch(); } //ld b, *
static void z80jt_0E(void){ zcpu_state.bc.b.l = z80fetch(); } //ld c, *
static void z80jt_16(void){ zcpu_state.de.b.h = z80fetch(); } //ld d, *
static void z80jt_1E(void){ zcpu_state.de.b.l = z80fetch(); } //ld e, *
static void z80jt_26(void){ zcpu_state.hl.b.h = z80fetch(); } //ld h, *
static void z80jt_2E(void){ zcpu_state.hl.b.l = z80fetch(); } //ld l, *
static void z80jt_3E(void){ zcpu_state.af.b.h = z80fetch(); } //ld a, *
static void z80jt_36(void){ z80write(zcpu_state.hl.w, z80fetch()); } //ld (hl), *

//16-bit immediate loads
	
static void z80jt_01(void){ zcpu_state.bc.w = z80fetchpair(); } //ld bc, **
static void z80jt_11(void){ zcpu_state.de.w = z80fetchpair(); } //ld de, **
static void z80jt_21(void){ zcpu_state.hl.w = z80fetchpair(); } //ld hl, **
static void z80jt_31(void){ zcpu_state.sp.w = z80fetchpair(); } //ld sp, **		

//8-bit immediate-to-accumulator ALU group

static void z80jt_C6(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, z80fetch()); } //add a, *
static void z80jt_D6(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, z80fetch()); } //sub *
static void z80jt_E6(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, z80fetch()); } //and *
static void z80jt_F6(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, z80fetch()); } //or *
static void z80jt_CE(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, z80fetch()); } //adc a, *
static void z80jt_DE(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, z80fetch()); } //sbc a, *
static void z80jt_EE(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, z80fetch()); } //xor *
static void z80jt_FE(void){ z80alucp(zcpu_state.af.b.h, z80fetch()); } //cp *

//8-bit register-to-accumulator ALU group

static void z80jt_80(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, zcpu_state.bc.b.h); }//add a, b
static void z80jt_81(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, zcpu_state.bc.b.l); } //add a, c
static void z80jt_82(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, zcpu_state.de.b.h); } //add a, d
static void z80jt_83(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, zcpu_state.de.b.l); } //add a, e
static void z80jt_84(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, zcpu_state.hl.b.h); } //add a, h
static void z80jt_85(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, zcpu_state.hl.b.l); } //add a, l
static void z80jt_86(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, z80read(zcpu_state.hl.w)); } //add a, (hl)
static void z80jt_87(void){ zcpu_state.af.b.h = z80aluadd(zcpu_state.af.b.h, zcpu_state.af.b.h); } //add a, a

static void z80jt_88(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, zcpu_state.bc.b.h); } //adc a, b
static void z80jt_89(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, zcpu_state.bc.b.l); } //adc a, c
static void z80jt_8A(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, zcpu_state.de.b.h); } //adc a, d
static void z80jt_8B(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, zcpu_state.de.b.l); } //adc a, e
static void z80jt_8C(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, zcpu_state.hl.b.h); } //adc a, h
static void z80jt_8D(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, zcpu_state.hl.b.l); } //adc a, l
static void z80jt_8E(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, z80read(zcpu_state.hl.w)); } //adc a, (hl)
static void z80jt_8F(void){ zcpu_state.af.b.h = z80aluadc(zcpu_state.af.b.h, zcpu_state.af.b.h); } //adc a, a

static void z80jt_90(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, zcpu_state.bc.b.h); } //sub a, b
static void z80jt_91(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, zcpu_state.bc.b.l); } //sub a, c
static void z80jt_92(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, zcpu_state.de.b.h); } //sub a, d
static void z80jt_93(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, zcpu_state.de.b.l); } //sub a, e
static void z80jt_94(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, zcpu_state.hl.b.h); } //sub a, h
static void z80jt_95(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, zcpu_state.hl.b.l); } //sub a, l
static void z80jt_96(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, z80read(zcpu_state.hl.w)); } //sub a, (hl)
static void z80jt_97(void){ zcpu_state.af.b.h = z80alusub(zcpu_state.af.b.h, zcpu_state.af.b.h); } //sub a, a

static void z80jt_98(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, zcpu_state.bc.b.h); } //sbc a, b
static void z80jt_99(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, zcpu_state.bc.b.l); } //sbc a, c
static void z80jt_9A(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, zcpu_state.de.b.h); } //sbc a, d
static void z80jt_9B(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, zcpu_state.de.b.l); } //sbc a, e
static void z80jt_9C(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, zcpu_state.hl.b.h); } //sbc a, h
static void z80jt_9D(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, zcpu_state.hl.b.l); } //sbc a, l
static void z80jt_9E(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, z80read(zcpu_state.hl.w)); } //sbc a, (hl)
static void z80jt_9F(void){ zcpu_state.af.b.h = z80alusbc(zcpu_state.af.b.h, zcpu_state.af.b.h); } //sbc a, a

static void z80jt_A0(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, zcpu_state.bc.b.h); } //and a, b
static void z80jt_A1(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, zcpu_state.bc.b.l); } //and a, c
static void z80jt_A2(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, zcpu_state.de.b.h); } //and a, d
static void z80jt_A3(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, zcpu_state.de.b.l); } //and a, e
static void z80jt_A4(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, zcpu_state.hl.b.h); } //and a, h
static void z80jt_A5(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, zcpu_state.hl.b.l); } //and a, l
static void z80jt_A6(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, z80read(zcpu_state.hl.w)); } //and a, (hl)
static void z80jt_A7(void){ zcpu_state.af.b.h = z80aluand(zcpu_state.af.b.h, zcpu_state.af.b.h); } //and a, a

static void z80jt_A8(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, zcpu_state.bc.b.h); } //xor a, b
static void z80jt_A9(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, zcpu_state.bc.b.l); } //xor a, c
static void z80jt_AA(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, zcpu_state.de.b.h); } //xor a, d
static void z80jt_AB(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, zcpu_state.de.b.l); } //xor a, e
static void z80jt_AC(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, zcpu_state.hl.b.h); } //xor a, h
static void z80jt_AD(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, zcpu_state.hl.b.l); } //xor a, l
static void z80jt_AE(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, z80read(zcpu_state.hl.w)); } //xor a, (hl)
static void z80jt_AF(void){ zcpu_state.af.b.h = z80aluxor(zcpu_state.af.b.h, zcpu_state.af.b.h); }	 //xor a, a

static void z80jt_B0(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, zcpu_state.bc.b.h); } //or a, b
static void z80jt_B1(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, zcpu_state.bc.b.l); } //or a, c
static void z80jt_B2(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, zcpu_state.de.b.h); } //or a, d
static void z80jt_B3(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, zcpu_state.de.b.l); } //or a, e
static void z80jt_B4(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, zcpu_state.hl.b.h); } //or a, h
static void z80jt_B5(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, zcpu_state.hl.b.l); } //or a, l
static void z80jt_B6(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, z80read(zcpu_state.hl.w)); } //or a, (hl)
static void z80jt_B7(void){ zcpu_state.af.b.h = z80aluor(zcpu_state.af.b.h, zcpu_state.af.b.h); } //or a, a

static void z80jt_B8(void){ z80alucp(zcpu_state.af.b.h, zcpu_state.bc.b.h); } //cp a, b
static void z80jt_B9(void){ z80alucp(zcpu_state.af.b.h, zcpu_state.bc.b.l); } //cp a, c
static void z80jt_BA(void){ z80alucp(zcpu_state.af.b.h, zcpu_state.de.b.h); } //cp a, d
static void z80jt_BB(void){ z80alucp(zcpu_state.af.b.h, zcpu_state.de.b.l); } //cp a, e
static void z80jt_BC(void){ z80alucp(zcpu_state.af.b.h, zcpu_state.hl.b.h); } //cp a, h
static void z80jt_BD(void){ z80alucp(zcpu_state.af.b.h, zcpu_state.hl.b.l); } //cp a, l
static void z80jt_BE(void){ z80alucp(zcpu_state.af.b.h, z80read(zcpu_state.hl.w)); } //cp a, (hl)
static void z80jt_BF(void){ z80alucp(zcpu_state.af.b.h, zcpu_state.af.b.h); } //cp a, a

//16-bit arithmetic group

static void z80jt_09(void){ zcpu_state.hl.w = z80add16(zcpu_state.hl.w, zcpu_state.bc.w); } //add hl, bc
static void z80jt_19(void){ zcpu_state.hl.w = z80add16(zcpu_state.hl.w, zcpu_state.de.w); } //add hl, de
static void z80jt_29(void){ zcpu_state.hl.w = z80add16(zcpu_state.hl.w, zcpu_state.hl.w); } //add hl, hl
static void z80jt_39(void){ zcpu_state.hl.w = z80add16(zcpu_state.hl.w, zcpu_state.sp.w); } //add hl, sp

static void z80jt_F9(void){ zcpu_state.sp.w = zcpu_state.hl.w; } //ld sp, hl

//8-bit increment/decrement group
	
static void z80jt_04(void){ zcpu_state.bc.b.h = z80inc8(zcpu_state.bc.b.h); } //inc b
static void z80jt_14(void){ zcpu_state.de.b.h = z80inc8(zcpu_state.de.b.h); } //inc d
static void z80jt_24(void){ zcpu_state.hl.b.h = z80inc8(zcpu_state.hl.b.h); } //inc h
static void z80jt_34(void){ z80write(zcpu_state.hl.w, z80inc8(z80read(zcpu_state.hl.w))); } //inc (hl)
	
static void z80jt_0C(void){ zcpu_state.bc.b.l = z80inc8(zcpu_state.bc.b.l); } //inc c
static void z80jt_1C(void){ zcpu_state.de.b.l = z80inc8(zcpu_state.de.b.l); } //inc e
static void z80jt_2C(void){ zcpu_state.hl.b.l = z80inc8(zcpu_state.hl.b.l); } //inc l
static void z80jt_3C(void){ zcpu_state.af.b.h = z80inc8(zcpu_state.af.b.h); } //inc a
	
static void z80jt_05(void){ zcpu_state.bc.b.h = z80dec8(zcpu_state.bc.b.h); } //dec b
static void z80jt_15(void){ zcpu_state.de.b.h = z80dec8(zcpu_state.de.b.h); } //dec d
static void z80jt_25(void){ zcpu_state.hl.b.h = z80dec8(zcpu_state.hl.b.h); } //dec h
static void z80jt_35(void){ z80write(zcpu_state.hl.w, z80dec8(z80read(zcpu_state.hl.w))); } //dec (hl)
	
static void z80jt_0D(void){ zcpu_state.bc.b.l = z80dec8(zcpu_state.bc.b.l); } //dec c
static void z80jt_1D(void){ zcpu_state.de.b.l = z80dec8(zcpu_state.de.b.l); } //dec e
static void z80jt_2D(void){ zcpu_state.hl.b.l = z80dec8(zcpu_state.hl.b.l); } //dec l
static void z80jt_3D(void){ zcpu_state.af.b.h = z80dec8(zcpu_state.af.b.h); } //dec a

//16-bit increment/decrement group

static void z80jt_03(void){ zcpu_state.bc.w++; } //inc bc
static void z80jt_13(void){ zcpu_state.de.w++; } //inc de
static void z80jt_23(void){ zcpu_state.hl.w++; } //inc hl
static void z80jt_33(void){ zcpu_state.sp.w++; } //inc sp
static void z80jt_0B(void){ zcpu_state.bc.w--; } //dec bc
static void z80jt_1B(void){ zcpu_state.de.w--; } //dec de
static void z80jt_2B(void){ zcpu_state.hl.w--; } //dec hl
static void z80jt_3B(void){ zcpu_state.sp.w--; } //dec sp

//Special indirect loads/stores

static void z80jt_02(void){ z80write(zcpu_state.bc.w, zcpu_state.af.b.h); } //ld (bc), a
static void z80jt_12(void){ z80write(zcpu_state.de.w, zcpu_state.af.b.h); } //ld (de), a
static void z80jt_22(void){ z80writepair(z80fetchpair(), zcpu_state.hl.w); } //ld (**), hl
static void z80jt_32(void){ z80write(z80fetchpair(), zcpu_state.af.b.h); } //ld (**), a
static void z80jt_0A(void){ zcpu_state.af.b.h = z80read(zcpu_state.bc.w); } //ld a, (bc)
static void z80jt_1A(void){ zcpu_state.af.b.h = z80read(zcpu_state.de.w); } //ld a, (de)
static void z80jt_2A(void){ zcpu_state.hl.w = z80readpair(z80fetchpair()); } //ld hl, (**)
static void z80jt_3A(void){ zcpu_state.af.b.h = z80read(z80fetchpair()); } //ld a, (**)

		
//Shifts/rotates

static void z80jt_07(void)//rlca
{
	//Set aside flags
	uint8_t oldflags = zcpu_state.af.b.l;

	//Do a normal rlc
	zcpu_state.af.b.h = z80rlc(zcpu_state.af.b.h);

	//Restore the original flags, partially
	zcpu_state.af.b.l &= ~(Z80_FLAG_S | Z80_FLAG_Z | Z80_FLAG_PV);
	zcpu_state.af.b.l |= oldflags & (Z80_FLAG_S | Z80_FLAG_Z | Z80_FLAG_PV);
}
	
static void z80jt_17(void)//rla
{
	uint8_t oldflags = zcpu_state.af.b.l;

	zcpu_state.af.b.h = z80rl(zcpu_state.af.b.h);

	zcpu_state.af.b.l &= ~(Z80_FLAG_S | Z80_FLAG_Z | Z80_FLAG_PV);
	zcpu_state.af.b.l |= oldflags & (Z80_FLAG_S | Z80_FLAG_Z | Z80_FLAG_PV);
}
	
static void z80jt_0F(void)//rrca
{
	uint8_t oldflags = zcpu_state.af.b.l;

	zcpu_state.af.b.h = z80rrc(zcpu_state.af.b.h);

	zcpu_state.af.b.l &= ~(Z80_FLAG_S | Z80_FLAG_Z | Z80_FLAG_PV);
	zcpu_state.af.b.l |= oldflags & (Z80_FLAG_S | Z80_FLAG_Z | Z80_FLAG_PV);
}
	
static void z80jt_1F(void)//rra
{
	uint8_t oldflags = zcpu_state.af.b.l;

	zcpu_state.af.b.h = z80rr(zcpu_state.af.b.h);

	zcpu_state.af.b.l &= ~(Z80_FLAG_S | Z80_FLAG_Z | Z80_FLAG_PV);
	zcpu_state.af.b.l |= oldflags & (Z80_FLAG_S | Z80_FLAG_Z | Z80_FLAG_PV);
}

//Exchanges

static void z80jt_EB(void)//ex de, hl
{ 
	uint16_t oldde = zcpu_state.de.w;
	zcpu_state.de.w = zcpu_state.hl.w;
	zcpu_state.hl.w = oldde;
}

static void z80jt_E3(void)//ex (sp), hl
{ 
	uint16_t oldhl = zcpu_state.hl.w;
	zcpu_state.hl.w = z80readpair(zcpu_state.sp.w);
	z80writepair(zcpu_state.sp.w, oldhl);
}

static void z80jt_08(void)//ex af, af'
{
	uint16_t oldaf = zcpu_state.af.w;
	zcpu_state.af.w = zcpu_state.af_alt.w;
	zcpu_state.af_alt.w = oldaf;
}

static void z80jt_D9(void)//exx
{
	uint16_t temp;
	
	temp = zcpu_state.bc.w;
	zcpu_state.bc.w = zcpu_state.bc_alt.w;
	zcpu_state.bc_alt.w = temp;
	
	temp = zcpu_state.de.w;
	zcpu_state.de.w = zcpu_state.de_alt.w;
	zcpu_state.de_alt.w = temp;
	
	temp = zcpu_state.hl.w;
	zcpu_state.hl.w = zcpu_state.hl_alt.w;
	zcpu_state.hl_alt.w = temp;
}

//Returns

static void z80jt_C9(void){ zcpu_state.pc.w = z80pop(); } //ret

static void z80jt_C8(void){ if(zcpu_state.af.b.l & Z80_FLAG_Z) { zcpu_state.pc.w = z80pop(); } } //ret z
static void z80jt_D8(void){ if(zcpu_state.af.b.l & Z80_FLAG_C) { zcpu_state.pc.w = z80pop(); } } //ret c
static void z80jt_E8(void){ if(zcpu_state.af.b.l & Z80_FLAG_PV) { zcpu_state.pc.w = z80pop(); } } //ret pe
static void z80jt_F8(void){ if(zcpu_state.af.b.l & Z80_FLAG_S) { zcpu_state.pc.w = z80pop(); } } //ret m
	
static void z80jt_C0(void){ if(!(zcpu_state.af.b.l & Z80_FLAG_Z)) { zcpu_state.pc.w = z80pop(); } } //ret nz
static void z80jt_D0(void){ if(!(zcpu_state.af.b.l & Z80_FLAG_C)) { zcpu_state.pc.w = z80pop(); } } //ret nc
static void z80jt_E0(void){ if(!(zcpu_state.af.b.l & Z80_FLAG_PV)) { zcpu_state.pc.w = z80pop(); } } //ret po
static void z80jt_F0(void){ if(!(zcpu_state.af.b.l & Z80_FLAG_S)) { zcpu_state.pc.w = z80pop(); } } //ret p

//Resets

static void z80jt_C7(void){ z80push(zcpu_state.pc.w); zcpu_state.pc.w = 0x0000; } //rst 00h
static void z80jt_CF(void){ z80push(zcpu_state.pc.w); zcpu_state.pc.w = 0x0008; } //rst 08h
static void z80jt_D7(void){ z80push(zcpu_state.pc.w); zcpu_state.pc.w = 0x0010; } //rst 10h
static void z80jt_DF(void){ z80push(zcpu_state.pc.w); zcpu_state.pc.w = 0x0018; } //rst 18h
static void z80jt_E7(void){ z80push(zcpu_state.pc.w); zcpu_state.pc.w = 0x0020; } //rst 20h
static void z80jt_EF(void){ z80push(zcpu_state.pc.w); zcpu_state.pc.w = 0x0028; } //rst 28h
static void z80jt_F7(void){ z80push(zcpu_state.pc.w); zcpu_state.pc.w = 0x0030; } //rst 30h
static void z80jt_FF(void){ z80push(zcpu_state.pc.w); zcpu_state.pc.w = 0x0038; } //rst 38h

//Input and output

static void z80jt_D3(void){ z80out(z80fetch(), zcpu_state.af.b.h); } //out (*), a
static void z80jt_DB(void){ zcpu_state.af.b.h = z80in(z80fetch()); } //in (*), a

//Other instructions

static void z80jt_2F(void)//cpl
{ 
	zcpu_state.af.b.h = ~zcpu_state.af.b.h;
	z80alterflag(Z80_FLAG_N, true);
	z80alterflag(Z80_FLAG_H, true);
	zcpu_state.af.b.l &= ~(Z80_FLAG_F3 | Z80_FLAG_F5);
	zcpu_state.af.b.l |= zcpu_state.af.b.h & (Z80_FLAG_F3 | Z80_FLAG_F5);
}

static void z80jt_37(void)//scf
{ 
	z80alterflag(Z80_FLAG_H, false);
	z80alterflag(Z80_FLAG_C, true);
	z80alterflag(Z80_FLAG_N, false);
	zcpu_state.af.b.l &= ~(Z80_FLAG_F3 | Z80_FLAG_F5);
	zcpu_state.af.b.l |= zcpu_state.af.b.h & (Z80_FLAG_F3 | Z80_FLAG_F5);
}

static void z80jt_3F(void)//ccf
{ 
	z80alterflag(Z80_FLAG_H, (zcpu_state.af.b.l & Z80_FLAG_C) != 0);
	z80alterflag(Z80_FLAG_C, (zcpu_state.af.b.l & Z80_FLAG_C) == 0);
	z80alterflag(Z80_FLAG_N, false);
	zcpu_state.af.b.l &= ~(Z80_FLAG_F3 | Z80_FLAG_F5);
	zcpu_state.af.b.l |= zcpu_state.af.b.h & (Z80_FLAG_F3 | Z80_FLAG_F5);
}

static void z80jt_27(void)//daa
{ 
	//set aside negative flag
	uint8_t oldneg = zcpu_state.af.b.l & Z80_FLAG_N;
	uint16_t adjust = zcpu_state.af.b.h;
	if( (zcpu_state.af.b.h & 0x0F) > 0x09 )
	{
		adjust += 0x06;
	}
	if( ((zcpu_state.af.b.h & 0xF0) > 0x90) || (((adjust ^ zcpu_state.af.b.h) & 0x10) != 0) )
	{
		adjust &= 0x0F;
		adjust |= zcpu_state.af.b.h & 0xF0;
		adjust += 0x60;
	}
	
	zcpu_state.af.b.l = z80resflag_sz53p[adjust] | oldneg;
	zcpu_state.af.b.l |= (adjust ^ zcpu_state.af.b.h) & Z80_FLAG_H;
	if(adjust > 0xFF)
		zcpu_state.af.b.l |= Z80_FLAG_C;
}
		
static void z80jt_CB(void){ z80cycle_cb(); } //bit manipulation instructions
static void z80jt_ED(void){ z80cycle_ed(); } //extended instructions		
static void z80jt_DD(void){ z80cycle_dd(); } //IX instructions
static void z80jt_FD(void){ z80cycle_fd(); } //IY instructions
static void z80jt_F3(void){ zcpu_state.ctrl &= ~Z80_CTRL_EI; } //di
static void z80jt_FB(void){ zcpu_state.ctrl |= Z80_CTRL_EI; } //ei
static void z80jt_00(void){ } //nop
static void z80jt_76(void){ } //hlt

//Explicit jump table for main cycle, rather than a switch statement, because SDCC is dumb
static const z80jt_t z80jt_main[256] = 
{
	z80jt_00, z80jt_01, z80jt_02, z80jt_03, z80jt_04, z80jt_05, z80jt_06, z80jt_07,
	z80jt_08, z80jt_09, z80jt_0A, z80jt_0B, z80jt_0C, z80jt_0D, z80jt_0E, z80jt_0F,
	z80jt_10, z80jt_11, z80jt_12, z80jt_13, z80jt_14, z80jt_15, z80jt_16, z80jt_17,
	z80jt_18, z80jt_19, z80jt_1A, z80jt_1B, z80jt_1C, z80jt_1D, z80jt_1E, z80jt_1F,
	z80jt_20, z80jt_21, z80jt_22, z80jt_23, z80jt_24, z80jt_25, z80jt_26, z80jt_27,
	z80jt_28, z80jt_29, z80jt_2A, z80jt_2B, z80jt_2C, z80jt_2D, z80jt_2E, z80jt_2F,
	z80jt_30, z80jt_31, z80jt_32, z80jt_33, z80jt_34, z80jt_35, z80jt_36, z80jt_37,
	z80jt_38, z80jt_39, z80jt_3A, z80jt_3B, z80jt_3C, z80jt_3D, z80jt_3E, z80jt_3F,
	z80jt_40, z80jt_41, z80jt_42, z80jt_43, z80jt_44, z80jt_45, z80jt_46, z80jt_47,
	z80jt_48, z80jt_49, z80jt_4A, z80jt_4B, z80jt_4C, z80jt_4D, z80jt_4E, z80jt_4F,
	z80jt_50, z80jt_51, z80jt_52, z80jt_53, z80jt_54, z80jt_55, z80jt_56, z80jt_57,
	z80jt_58, z80jt_59, z80jt_5A, z80jt_5B, z80jt_5C, z80jt_5D, z80jt_5E, z80jt_5F,
	z80jt_60, z80jt_61, z80jt_62, z80jt_63, z80jt_64, z80jt_65, z80jt_66, z80jt_67,
	z80jt_68, z80jt_69, z80jt_6A, z80jt_6B, z80jt_6C, z80jt_6D, z80jt_6E, z80jt_6F,
	z80jt_70, z80jt_71, z80jt_72, z80jt_73, z80jt_74, z80jt_75, z80jt_76, z80jt_77,
	z80jt_78, z80jt_79, z80jt_7A, z80jt_7B, z80jt_7C, z80jt_7D, z80jt_7E, z80jt_7F,
	z80jt_80, z80jt_81, z80jt_82, z80jt_83, z80jt_84, z80jt_85, z80jt_86, z80jt_87,
	z80jt_88, z80jt_89, z80jt_8A, z80jt_8B, z80jt_8C, z80jt_8D, z80jt_8E, z80jt_8F,
	z80jt_90, z80jt_91, z80jt_92, z80jt_93, z80jt_94, z80jt_95, z80jt_96, z80jt_97,
	z80jt_98, z80jt_99, z80jt_9A, z80jt_9B, z80jt_9C, z80jt_9D, z80jt_9E, z80jt_9F,
	z80jt_A0, z80jt_A1, z80jt_A2, z80jt_A3, z80jt_A4, z80jt_A5, z80jt_A6, z80jt_A7,
	z80jt_A8, z80jt_A9, z80jt_AA, z80jt_AB, z80jt_AC, z80jt_AD, z80jt_AE, z80jt_AF,
	z80jt_B0, z80jt_B1, z80jt_B2, z80jt_B3, z80jt_B4, z80jt_B5, z80jt_B6, z80jt_B7,
	z80jt_B8, z80jt_B9, z80jt_BA, z80jt_BB, z80jt_BC, z80jt_BD, z80jt_BE, z80jt_BF,
	z80jt_C0, z80jt_C1, z80jt_C2, z80jt_C3, z80jt_C4, z80jt_C5, z80jt_C6, z80jt_C7,
	z80jt_C8, z80jt_C9, z80jt_CA, z80jt_CB, z80jt_CC, z80jt_CD, z80jt_CE, z80jt_CF,
	z80jt_D0, z80jt_D1, z80jt_D2, z80jt_D3, z80jt_D4, z80jt_D5, z80jt_D6, z80jt_D7,
	z80jt_D8, z80jt_D9, z80jt_DA, z80jt_DB, z80jt_DC, z80jt_DD, z80jt_DE, z80jt_DF,
	z80jt_E0, z80jt_E1, z80jt_E2, z80jt_E3, z80jt_E4, z80jt_E5, z80jt_E6, z80jt_E7,
	z80jt_E8, z80jt_E9, z80jt_EA, z80jt_EB, z80jt_EC, z80jt_ED, z80jt_EE, z80jt_EF,
	z80jt_F0, z80jt_F1, z80jt_F2, z80jt_F3, z80jt_F4, z80jt_F5, z80jt_F6, z80jt_F7, 
	z80jt_F8, z80jt_F9, z80jt_FA, z80jt_FB, z80jt_FC, z80jt_FD, z80jt_FE, z80jt_FF
};

//Main loop for emulator - fetches the opcode at PC and executes it
static void z80cycle(void)
{		
	uint8_t opcode = z80fetch();
	z80jt_main[opcode]();
}

void zcpu_cycle(uint16_t ncycle)
{
	while(ncycle > 0)
	{
		z80cycle();
		ncycle--;
	}
}

void zcpu_write8 (uint16_t ptr, uint8_t  val)
{
	zcpu_mem[ptr++] = val & 0xFF;
}

void zcpu_write16(uint16_t ptr, uint16_t val)
{
	zcpu_mem[ptr++] = val & 0xFF; val >>= 8;
	zcpu_mem[ptr++] = val & 0xFF;
}

void zcpu_write32(uint16_t ptr, uint32_t val)
{
	zcpu_mem[ptr++] = val & 0xFF; val >>= 8;
	zcpu_mem[ptr++] = val & 0xFF; val >>= 8;
	zcpu_mem[ptr++] = val & 0xFF; val >>= 8;
	zcpu_mem[ptr++] = val & 0xFF;
}

void zcpu_write64(uint16_t ptr, uint64_t val)
{
	zcpu_mem[ptr++] = val & 0xFF; val >>= 8;
	zcpu_mem[ptr++] = val & 0xFF; val >>= 8;
	zcpu_mem[ptr++] = val & 0xFF; val >>= 8;
	zcpu_mem[ptr++] = val & 0xFF; val >>= 8;
	zcpu_mem[ptr++] = val & 0xFF; val >>= 8;
	zcpu_mem[ptr++] = val & 0xFF; val >>= 8;
	zcpu_mem[ptr++] = val & 0xFF; val >>= 8;
	zcpu_mem[ptr++] = val & 0xFF;
}

uint8_t zcpu_read8(uint16_t ptr)
{
	return zcpu_mem[ptr];
}

uint16_t zcpu_read16(uint16_t ptr)
{
	uint16_t retval = 0;
	retval = (retval << 8) | zcpu_mem[(ptr + 1) & 0xFFFF];
	retval = (retval << 8) | zcpu_mem[(ptr + 0) & 0xFFFF];
	return retval;
}

uint32_t zcpu_read32(uint16_t ptr)
{
	uint32_t retval = 0;
	retval = (retval << 8) | zcpu_mem[(ptr + 3) & 0xFFFF];
	retval = (retval << 8) | zcpu_mem[(ptr + 2) & 0xFFFF];
	retval = (retval << 8) | zcpu_mem[(ptr + 1) & 0xFFFF];
	retval = (retval << 8) | zcpu_mem[(ptr + 0) & 0xFFFF];
	return retval;	
}

uint64_t zcpu_read64(uint16_t ptr)
{
	uint64_t retval = 0;
	retval = (retval << 8) | zcpu_mem[(ptr + 7) & 0xFFFF];
	retval = (retval << 8) | zcpu_mem[(ptr + 6) & 0xFFFF];
	retval = (retval << 8) | zcpu_mem[(ptr + 5) & 0xFFFF];
	retval = (retval << 8) | zcpu_mem[(ptr + 4) & 0xFFFF];
	retval = (retval << 8) | zcpu_mem[(ptr + 3) & 0xFFFF];
	retval = (retval << 8) | zcpu_mem[(ptr + 2) & 0xFFFF];
	retval = (retval << 8) | zcpu_mem[(ptr + 1) & 0xFFFF];
	retval = (retval << 8) | zcpu_mem[(ptr + 0) & 0xFFFF];
	return retval;
}
