/***************************************************************
 *  Alcuin: A HP48 emulator for Amiga Computers
 * 
 *  (C) 1995 Stephan Schupfer (schupfer@sbox.tu-graz.ac.at)
 *
 */

#include "bcd.h"
#include "register.c"


/******************************************************************/
/* RSTK */
static inline word_20 pop (void)
{
word_20 x;

x = saturn_rstk[saturn_rstkp];
saturn_rstk[saturn_rstkp--] = 0;
saturn_rstkp &=0x7;
return x;
/*return saturn_rstk[saturn_rstkp--];*/
}

/******************************************************************/
inline void push (word_20 a)
{
saturn_rstkp++;
saturn_rstkp &=0x7;
saturn_rstk[saturn_rstkp] = a;
/*saturn_rstk[++saturn_rstkp] = a;*/
}

/******************************************************************/
static inline word_20 rti (void)
{
if (saturn_int_pending) {
	saturn_int_pending = 0;
	saturn_intenable = 0;
	saturn_PC = 0xf;
	}
else {
	saturn_intenable = 1;
/*	saturn_PC = saturn_rstk[saturn_rstkp--];*/
	saturn_PC = saturn_rstk[saturn_rstkp];
	saturn_rstk[saturn_rstkp--] = 0;
	saturn_rstkp &=0x7;
	if (adj_time_pending) {
		schedule_event = 0;
		sched_adjtime = 0;
		}
	}
return saturn_PC;
}

/******************************************************************/
/* REG <-> address */
static inline word_20 reg_addr (unsigned char *reg)
{
int i=5;
word_20 addr=0;

while (i--) {
	addr<<=4;
	addr |= reg[i];
	}
return addr;
}

/******************************************************************/
static inline void addr_reg (word_20 addr, unsigned char *reg)
{
int i;

for (i = 0; i < 5; i++) {
	reg[i] = addr & 0xf;
	addr >>= 4;
	}
}

/******************************************************************/
/* ST */
static inline void clr_st (void)
{
saturn_ST &= 0xf000;
}

/******************************************************************/
static inline void move_st_c (void)
{
saturn_C[0]= saturn_ST & 0xf;
saturn_C[1]= (saturn_ST >> 4) & 0xf;
saturn_C[2]= (saturn_ST >> 8) & 0xf;
}

/******************************************************************/
static inline void move_c_st (void)
{
saturn_ST &= 0xf000;
saturn_ST |= saturn_C[0] | (saturn_C[1]<<4) | (saturn_C[2]<<8);
}

/******************************************************************/
static inline void exg_st_c (void)
{
unsigned long tmp;

tmp=saturn_ST;
saturn_ST &= 0xf000;
saturn_ST |= saturn_C[0] | (saturn_C[1] << 4) | (saturn_C[2] << 8);
saturn_C[0]=tmp & 0xf;
tmp>>=4;
saturn_C[1]=tmp & 0xf;
tmp>>=4;
saturn_C[2]=tmp & 0xf;
}

/******************************************************************/
static inline void bclr_st (word_20 con)
{
saturn_ST &= ~(1 << con);
}

/******************************************************************/
static inline void bset_st (word_20 con)
{
saturn_ST |= 1 << con;
}

/******************************************************************/
static inline int b_is_clr_st (word_20 con)
{
return (saturn_ST & (1 << con)) ? 0 : 1;
}

/******************************************************************/
static inline int b_is_set_st (word_20 con)
{
return (saturn_ST & (1 << con)) ? 1 : 0;
}


/******************************************************************/
/* P */
static inline void inc_reg_p (void)
{
saturn_P=inc_nibble[saturn_P];
saturn_CARRY = inc_carry[saturn_P];
}

/******************************************************************/
static inline void dec_reg_p (void)
{
saturn_CARRY = dec_carry[saturn_P];
saturn_P=dec_nibble[saturn_P];
}

/******************************************************************/
static inline void move_con_reg_p (word_20 con)
{
saturn_P = con;
}

/******************************************************************/
static inline void move_c_p (word_20 con)
{
saturn_P = saturn_C[con];
}

/******************************************************************/
static inline void move_p_c (word_20 con)
{
saturn_C[con]=saturn_P;
}

/******************************************************************/
static inline void exg_p_c (word_20 con)
{
unsigned char tmp;

tmp = saturn_P;
saturn_P=saturn_C[con];
saturn_C[con]=tmp;
}

/******************************************************************/
static inline void add_c_p_1 (void)
{
int i;

saturn_CARRY=saturn_P + 1;
for (i=0;i<5;i++) {
	saturn_C[i]+=saturn_CARRY;
	saturn_CARRY=hex_carry[saturn_C[i]];
	saturn_C[i]&=0xf;
	}
}

/******************************************************************/
static inline int ne_reg_p (word_20 con)
{
return (saturn_P != con);
}

/******************************************************************/
static inline int eq_reg_p (word_20 con)
{
return (saturn_P == con);
}

/******************************************************************/
/* PC */
static inline void move_pc (unsigned char *dst)
{
word_20 tmp;

tmp=saturn_PC+4;
dst[0]=tmp & 0xf;
tmp>>=4;
dst[1]=tmp & 0xf;
tmp>>=4;
dst[2]=tmp & 0xf;
tmp>>=4;
dst[3]=tmp & 0xf;
tmp>>=4;
dst[4]=tmp & 0xf;
}

/******************************************************************/
static inline word_20 exg_pc (unsigned char *dst)
{
word_20 tmp,tmp2=0;
int i=5;

while (i--) {
	tmp2<<=4;
	tmp2|=dst[i];
	}
tmp=saturn_PC+4;
dst[0]=tmp & 0xf;
tmp>>=4;
dst[1]=tmp & 0xf;
tmp>>=4;
dst[2]=tmp & 0xf;
tmp>>=4;
dst[3]=tmp & 0xf;
tmp>>=4;
dst[4]=tmp & 0xf;
return tmp2;
}

/******************************************************************/
static inline void bclr (unsigned char *dst, unsigned char bit)
{
dst[bit>>2] &= ~(1 << (bit&3));
}

/******************************************************************/
static inline void bset (unsigned char *dst, word_20 bit)
{
dst[bit>>2] |= (1 << (bit&3));
}

/******************************************************************/
static inline int b_is_clr (unsigned char *dst, unsigned char bit)
{
return ((dst[bit>>2] & (1 << (bit&3)))) ? 0 : 1;
}

/******************************************************************/
static inline int b_is_set (unsigned char *dst, unsigned char bit)
{
return ((dst[bit>>2] & (1 << (bit&3)))) ? 1 : 0;
}

/******************************************************************/
static inline void move_con_dp_2 (word_20 *reg, word_20 con)
{
*reg &= 0xfff00;
*reg |= con & 0xff;
}

/******************************************************************/
static inline void move_con_dp_4 (word_20 *reg, word_20 con)
{
*reg &= 0xf0000;
*reg |= con & 0xffff;
}

/******************************************************************/
static inline void move_con_dp_5 (word_20 *reg, word_20 con)
{
*reg = con;
}

/******************************************************************/
/* IN, OUT */
static inline void kbd_read (void)
{
int i,in = 0;
if (saturn_OUT[0] & 0x1)	in |= saturn_keybuf[0];
if (saturn_OUT[0] & 0x2)	in |= saturn_keybuf[1];
if (saturn_OUT[0] & 0x4)	in |= saturn_keybuf[2];
if (saturn_OUT[0] & 0x8)	in |= saturn_keybuf[3];
if (saturn_OUT[1] & 0x1)	in |= saturn_keybuf[4];
if (saturn_OUT[1] & 0x2)	in |= saturn_keybuf[5];
if (saturn_OUT[1] & 0x4)	in |= saturn_keybuf[6];
if (saturn_OUT[1] & 0x8)	in |= saturn_keybuf[7];
if (saturn_OUT[2] & 0x1)	in |= saturn_keybuf[8];
for (i = 0; i < 4; i++) {
	saturn_IN[i] = in & 0xf;
	in >>= 4;
	}
}

/******************************************************************/
static inline void move_out_1 (void)
{
saturn_OUT[0]=saturn_C[0];
}

/******************************************************************/
static inline void move_out_3 (void)
{
memcpy(saturn_OUT,saturn_C,3);
}

/******************************************************************/
static inline void move_in (unsigned char *dst)
{
memcpy(dst,saturn_IN,4);
}


/******************************************************************/
/* HST */
static inline void clr_hst (word_20 con)
{
saturn_HST &= ~con;
}

/******************************************************************/
static inline int is_clr_hst (word_20 con)
{
return (saturn_HST & con) ? 0 : 1;
}


/******************************************************************/
/* Other */
static inline void config (void)
{
int i=5;
long conf=0;

while (i--) {
	conf <<= 4;
	conf |= saturn_C[i];
	}

for (i = 0; i < 5; i++)
	if (saturn_mem[i]) break;
if (i==5) return;
switch (i) {
	case 0:
		saturn_mem[i]=0;
		saturn_base[i]=conf;
		saturn_size[i]=conf + 0x40;
		break;
	case 1:
	case 2:
	case 3:
	case 4:
		if (saturn_mem[i]==2) {
			saturn_mem[i]=0;
			saturn_size[i]-=saturn_base[i];
			saturn_base[i]=conf;
			saturn_size[i]+=saturn_base[i];
			break;
			}
		saturn_size[i]=saturn_base[i] + (0x100000 - conf);
		saturn_mem[i]=2;
		break;
	default:
		break;
	}
}

/******************************************************************/
static inline void inton (void)
{
saturn_kbd_ien = 1;
}

/******************************************************************/
static inline void intoff (void)
{
saturn_kbd_ien = 0;
}

/******************************************************************/
static inline void sreq (void)
{
saturn_C[0] = 0;
saturn_HST &= ~SR;
}

/******************************************************************/
static inline void buscb (void) {}
static inline void buscc (void) {}
static inline void buscd (void) {}

/******************************************************************/
