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

#include <stdio.h>

#include "A48.h"
#include "hp48.h"
#include "device.h"
#include "romio.h"
#include "main.h"
#include "mmu.h"

/* #define DEBUG_SERIAL 1 */
/* #define DEBUG_SERIALb 1 */
/* #define DEBUG_DISPLAY 1 */
/* #define DEBUG_IR 1 */
/* #define DEBUG_CONTRAST 1 */
/* #define DEBUG_CARDS 1 */
/* #define DEBUG_BAD_MEM 1 */
/* #define DEBUG_BASE_NIBBLE 1 */
/* #define DEBUG_BANK_SWITCH 1 */

#define INRANGE(n,d) ((d>=saturn_base[n]) && (d<saturn_size[n]))

extern int   device_check;
extern short port1_is_ram;
extern long  port1_mask;
extern short port2_is_ram;
extern long  port2_mask;

static int line_counter = -1;

static int crc_tab[16] = {
  0x0000, 0x1081, 0x2102, 0x3183,
  0x4204, 0x5285, 0x6306, 0x7387,
  0x8408, 0x9489, 0xa50a, 0xb58b,
  0xc60c, 0xd68d, 0xe70e, 0xf78f
};

/******************************************************************/
static inline unsigned char calc_crc(unsigned char nib)
{
saturn_crc = (saturn_crc >> 4) ^ crc_tab[(saturn_crc ^ nib) & 0xf];
/*
saturn_crc = (saturn_crc >> 4) ^ (((char)(saturn_crc & 0xf) ^ (char)nib) * 0x1081);
*/
return nib;
}

/******************************************************************
 * The write_dev_mem functions
 */

static inline void disp_io (int val)
{
if (val != saturn_disp_io) {
	saturn_disp_io = val;
	display_on = val >> 3;
	display_offset = val & 0x7;
	disp_offset = display_offset << 1;
	if (display_offset > 3)
		display_nibs_per_line = (NIBBLES_PER_ROW+saturn_line_offset+2) & 0xfff;
	else
		display_nibs_per_line = (NIBBLES_PER_ROW+saturn_line_offset) & 0xfff;
	display_disp_end = display_nibs_per_line * display_lines;
	device.display_touched = 1;
	}
}

static inline void contr_cont (int val)
{
saturn_contrast_ctrl = val;
display_contrast &= 0xf0;
display_contrast |= val;
device.contrast_touched = 1;
}

static inline void disp_test_0 (int val)
{
display_contrast &= 0x0f;
display_contrast |= ((val & 0x1) << 4);
device.contrast_touched = 1;
saturn_disp_test &= 0xf0;
saturn_disp_test |= val;
/*device.disp_test_touched = 1;*/
}

static inline void disp_test_1 (int val)
{
saturn_disp_test &= 0x0f;
saturn_disp_test |= val << 4;
/*device.disp_test_touched = 1;*/
}

static inline void crc_0 (int val)
{
saturn_crc &= 0xfff0;
saturn_crc |= val;
}

static inline void crc_1 (int val)
{
saturn_crc &= 0xff0f;
saturn_crc |= val << 4;
}

static inline void crc_2 (int val)
{
saturn_crc &= 0xf0ff;
saturn_crc |= val << 8;
}

static inline void crc_3 (int val)
{
saturn_crc &= 0x0fff;
saturn_crc |= val << 12;
}

static inline void pow_stat (int val)
{
/* read only */
/*saturn_power_status = val;*/
/*device.power_status_touched = 1;*/
}

static inline void pow_cont (int val)
{
saturn_power_ctrl = val;
/*device.power_ctrl_touched = 1;*/
}

static inline void mode (int val)
{
saturn_mode = val;
/*device.mode_touched = 1;*/
}

static inline void annunc_0 (int val)
{
saturn_annunc &= 0xf0;
saturn_annunc |= val;
/*display_annunc = saturn_annunc;
device.ann_touched = 1;
*/
draw_annunc();
}

static inline void annunc_1 (int val)
{
saturn_annunc &= 0x0f;
saturn_annunc |= val << 4;
/*display_annunc = saturn_annunc;
device.ann_touched = 1;
*/
draw_annunc();
}

static inline void baud (int val)
{
/* [UCK BD2 BD1 BD0] Bit3 is read only */
/* 3 bit - baud {1200,1920,2400,3840,4800,7680,9600,15360} */

saturn_baud |= val & 0x7;
/*device.baud_touched = 1;*/
serial_baud(saturn_baud);
}

static inline void card_cont (int val)
{
saturn_card_ctrl = val;
if (saturn_card_ctrl & 0x01)
	do_interupt();
if (saturn_card_ctrl & 0x02) {
	saturn_HST |= MP;
	do_interupt();
	}
/*device.card_ctrl_touched = 1;*/
}

static inline void card_stat (int val)
{
}

static inline void io_cont (int val) /* serial I/O control */
{
/* Serial I/O Conrol: [SON ETBE ERBF ERBZ] */
/* Serial on, Interrupt on Recv.Buf Empty, Full, Busy] */

saturn_io_ctrl = val;
/*device.ioc_touched = 1;*/
if ((saturn_io_ctrl & 0x02) && (saturn_rcs & 0x01)) do_interupt();
}

static inline void rcs (int val) /* serial receive control/status */
{
saturn_rcs |= val & 0x7;
}

static inline void tcs (int val) /* serial transmit control/status */
{
saturn_tcs = val;
}

static inline void crer (int val) /* serial clear */
{
saturn_rcs &= 0xb;
}

static inline void rbr_0 (int val) /* serial receive buffer register */
{
}

static inline void rbr_1 (int val)
{
}

static inline void tbr_0 (int val) /* serial transmit buffer register */
{
saturn_tbr &= 0xf0;
saturn_tbr |= val;
saturn_tcs |= 0x01;
device.tbr_touched = 1;
transmit_char();
}

static inline void tbr_1 (int val)
{
saturn_tbr &= 0x0f;
saturn_tbr |= val << 4;
saturn_tcs |= 0x01;
device.tbr_touched = 1;
transmit_char();
}

static inline void serv_req_0 (int val) /* service request register */
{
/*(read_only)*/
/*saturn_sreq &= 0xf0;
saturn_sreq |= val;*/
/*device.sreq_touched = 1;*/
}

static inline void serv_req_1 (int val)
{
/*
saturn_sreq &= 0x0f;
saturn_sreq |= val << 4;
device.sreq_touched = 1;
*/
}

static inline void ir_cont (int val) /* IR Control Register */
{
saturn_ir_ctrl |=val & 0x7;
/*device.ir_ctrl_touched = 1;*/
}

static inline void base_nib (int val)
{
/*saturn_base_off = val;
device.base_off_touched = 1;*/
}

static inline void led_cont (int val)
{
saturn_lcr = val;
/*device.lcr_touched = 1;*/
}

static inline void led_buf (int val)
{
saturn_lbr = val & 1;
/*device.lbr_touched = 1;*/
}

static inline void scr_pad (int val)
{
saturn_scratch = val;
/*device.scratch_touched = 1;*/
}

static inline void basenib (int val)
{
saturn_base_nibble = val;
/*device.base_nibble_touched = 1;*/
}

static inline void disp_add_0 (int val)
{
saturn_disp_addr &= 0xfffffff0;
saturn_disp_addr |= val;
if (display_disp_start != (saturn_disp_addr & 0xffffe)) {
	display_disp_start = saturn_disp_addr & 0xffffe;
	display_disp_end = display_nibs_per_line * display_lines;
	device.display_touched = 1;
	}
}

static inline void disp_add_1 (int val)
{
saturn_disp_addr &= 0xffffff0f;
saturn_disp_addr |= val << 4;
if (display_disp_start != (saturn_disp_addr & 0xffffe)) {
	display_disp_start = saturn_disp_addr & 0xffffe;
	display_disp_end = display_nibs_per_line * display_lines;
	device.display_touched = 1;
	}
}

static inline void disp_add_2 (int val)
{
saturn_disp_addr &= 0xfffff0ff;
saturn_disp_addr |= val << 8;
if (display_disp_start != (saturn_disp_addr & 0xffffe)) {
	display_disp_start = saturn_disp_addr & 0xffffe;
	display_disp_end = display_nibs_per_line * display_lines;
	device.display_touched = 1;
	}
}

static inline void disp_add_3 (int val)
{
saturn_disp_addr &= 0xffff0fff;
saturn_disp_addr |= val << 12;
if (display_disp_start != (saturn_disp_addr & 0xffffe)) {
	display_disp_start = saturn_disp_addr & 0xffffe;
	display_disp_end = display_nibs_per_line * display_lines;
	device.display_touched = 1;
	}
}

static inline void disp_add_4 (int val)
{
saturn_disp_addr &= 0xfff0ffff;
saturn_disp_addr |= val << 16;
if (display_disp_start != (saturn_disp_addr & 0xffffe)) {
	display_disp_start = saturn_disp_addr & 0xffffe;
	display_disp_end = display_nibs_per_line * display_lines;
	device.display_touched = 1;
	}
}

static inline void line_off_0 (int val)
{
static int old_line_offset = -1;

saturn_line_offset &= 0xfff0;
saturn_line_offset |= val;
if (saturn_line_offset != old_line_offset) {
	old_line_offset = saturn_line_offset;
	if (display_offset > 3)
		display_nibs_per_line = (NIBBLES_PER_ROW+saturn_line_offset+2) & 0xfff;
	else
		display_nibs_per_line = (NIBBLES_PER_ROW+saturn_line_offset) & 0xfff;
	display_disp_end = display_nibs_per_line * display_lines;
	device.display_touched = 1;
	}
}

static inline void line_off_1 (int val)
{
static int old_line_offset = -1;

saturn_line_offset &= 0xff0f;
saturn_line_offset |= val << 4;
if (saturn_line_offset != old_line_offset) {
	old_line_offset = saturn_line_offset;
	if (display_offset > 3)
		display_nibs_per_line = (NIBBLES_PER_ROW+saturn_line_offset+2) & 0xfff;
	else
		display_nibs_per_line = (NIBBLES_PER_ROW+saturn_line_offset) & 0xfff;
	display_disp_end = display_nibs_per_line * display_lines;
	device.display_touched = 1;
	}
}

static inline void line_off_2 (int val)
{
static int old_line_offset = -1;

saturn_line_offset &= 0xf0ff;
saturn_line_offset |= val << 8;
if (saturn_line_offset != old_line_offset) {
	old_line_offset = saturn_line_offset;
	if (display_offset > 3)
		display_nibs_per_line = (NIBBLES_PER_ROW+saturn_line_offset+2) & 0xfff;
	else
		display_nibs_per_line = (NIBBLES_PER_ROW+saturn_line_offset) & 0xfff;
	display_disp_end = display_nibs_per_line * display_lines;
	device.display_touched = 1;
	}
}

static inline void line_cnt_0 (int val)
{
saturn_line_count &= 0xf0;
saturn_line_count |= val;
line_counter = -1;
if (display_lines != (saturn_line_count & 0x3f)+1) {
	display_lines = (saturn_line_count & 0x3f)+1;
	if (!display_lines) display_lines = 64;
	/*disp_lines = 2 * display_lines;*/
	display_disp_end = display_nibs_per_line * display_lines;
	device.display_touched = 1;
	}
}

static inline void line_cnt_1 (int val)
{
saturn_line_count &= 0x0f;
saturn_line_count |= val << 4;
line_counter = -1;
if (display_lines != (saturn_line_count & 0x3f)+1) {
	display_lines = (saturn_line_count & 0x3f)+1;
	if (!display_lines) display_lines = 64;
	/*disp_lines = 2 * display_lines;*/
	display_disp_end = display_nibs_per_line * display_lines;
	device.display_touched = 1;
	}
}

static inline void no_know_0 (int val)
{
saturn_unknown &= 0xfff0;
saturn_unknown |= val;
/*device.unknown_touched = 1;*/
}

static inline void no_know_1 (int val)
{
saturn_unknown &= 0xff0f;
saturn_unknown |= val << 4;
/*device.unknown_touched = 1;*/
}

static inline void no_know_2 (int val)
{
saturn_unknown &= 0xf0ff;
saturn_unknown |= val << 8;
/*device.unknown_touched = 1;*/
}

static inline void no_know_3 (int val)
{
saturn_unknown &= 0x0fff;
saturn_unknown |= val << 12;
/*device.unknown_touched = 1;*/
}

static inline void t1_cont (int val)
{
saturn_t1_ctrl = val & 0xe;
/*device.t1_ctrl_touched = 1;*/
}

static inline void t2_cont (int val)
{
saturn_t2_ctrl = val;
/*device.t2_ctrl_touched = 1;*/
}

static inline void menu_add_0 (int val)
{
saturn_menu_addr &= 0xfffffff0;
saturn_menu_addr |= val;
device.display_touched = 1;
}

static inline void menu_add_1 (int val)
{
saturn_menu_addr &= 0xffffff0f;
saturn_menu_addr |= val << 4;
device.display_touched = 1;
}

static inline void menu_add_2 (int val)
{
saturn_menu_addr &= 0xfffff0ff;
saturn_menu_addr |= val << 8;
device.display_touched = 1;
}

static inline void menu_add_3 (int val)
{
saturn_menu_addr &= 0xffff0fff;
saturn_menu_addr |= val << 12;
device.display_touched = 1;
}

static inline void menu_add_4 (int val)
{
saturn_menu_addr &= 0xfff0ffff;
saturn_menu_addr |= val << 16;
device.display_touched = 1;
}

static inline void no_know2_0 (int val)
{
saturn_unknown2 &= 0xf0;
saturn_unknown2 |= val;
/*device.unknown2_touched = 1;*/
}

static inline void no_know2_1 (int val)
{
saturn_unknown2 &= 0x0f;
saturn_unknown2 |= val << 4;
/*device.unknown2_touched = 1;*/
}

static inline void t1 (int val)
{
saturn_timer1 = val;
device.t1_touched = 1;
}

static inline void t2_0 (int val)
{
saturn_timer2 &= 0xfffffff0;
saturn_timer2 |= val;
device.t2_touched = 1;
}

static inline void t2_1 (int val)
{
saturn_timer2 &= 0xffffff0f;
saturn_timer2 |= (val<<4);
device.t2_touched = 1;
}

static inline void t2_2 (int val)
{
saturn_timer2 &= 0xfffff0ff;
saturn_timer2 |= (val<<8);
device.t2_touched = 1;
}

static inline void t2_3 (int val)
{
saturn_timer2 &= 0xffff0fff;
saturn_timer2 |= (val<<12);
device.t2_touched = 1;
}

static inline void t2_4 (int val)
{
saturn_timer2 &= 0xfff0ffff;
saturn_timer2 |= (val<<16);
device.t2_touched = 1;
}

static inline void t2_5 (int val)
{
saturn_timer2 &= 0xff0fffff;
saturn_timer2 |= (val<<20);
device.t2_touched = 1;
}

static inline void t2_6 (int val)
{
saturn_timer2 &= 0xf0ffffff;
saturn_timer2 |= (val<<24);
device.t2_touched = 1;
}

static inline void t2_7 (int val)
{
saturn_timer2 &= 0x0fffffff;
saturn_timer2 |= (val<<28);
device.t2_touched = 1;
}


/******************************************************************
 * The read_dev_mem functions
 */

static inline unsigned char r_disp_io()
{
return saturn_disp_io;
}

static inline unsigned char r_contr_cont()
{
return saturn_contrast_ctrl;
}

static inline unsigned char r_disp_test_0()
{
return (saturn_disp_test) & 0xf;
}

static inline unsigned char r_disp_test_1()
{
return (saturn_disp_test >> 4) & 0xf;
}

static inline unsigned char r_crc_0()
{
return saturn_crc & 0xf;
}

static inline unsigned char r_crc_1()
{
return (saturn_crc>>4) & 0xf;
}

static inline unsigned char r_crc_2()
{
return (saturn_crc>>8) & 0xf;
}

static inline unsigned char r_crc_3()
{
return (saturn_crc>>12) & 0xf;
}

static inline unsigned char r_pow_stat()
{
return saturn_power_status;
}

static inline unsigned char r_pow_cont()
{
return saturn_power_ctrl;
}

static inline unsigned char r_mode()
{
return saturn_mode;
}

static inline unsigned char r_annunc_0()
{
return (saturn_annunc) & 0xf;
}

static inline unsigned char r_annunc_1()
{
return (saturn_annunc >> 4) & 0xf;
}

static inline unsigned char r_baud()
{
return saturn_baud;
}

static inline unsigned char r_card_cont()
{
return saturn_card_ctrl;
}

/* 0f */
static inline unsigned char r_card_stat()
{
return saturn_card_status;
}

static inline unsigned char r_io_cont()
{
return saturn_io_ctrl;
}

static inline unsigned char r_rcs()
{
return saturn_rcs;
}

static inline unsigned char r_tcs()
{
return saturn_tcs;
}

static inline unsigned char r_crer()
{
return 0x00;
}

/*14*/
static inline unsigned char r_rbr_0()
{
saturn_rcs &= 0x0e;
device.rbr_touched = 1;
device_check = 1;
schedule_event = 0;
return (saturn_rbr) & 0xf;
}

/*15*/
static inline unsigned char r_rbr_1()
{
saturn_rcs &= 0x0e;
device.rbr_touched = 1;
device_check = 1;
schedule_event = 0;
return (saturn_rbr >> 4) & 0xf;
}

/*16 - return 3*/
static inline unsigned char r_tbr_0()
{
return 0x00;
}

/*17  - return 3 ???*/
static inline unsigned char r_tbr_1()
{
return 0x00;
}

static inline unsigned char r_serv_req_0()
{
return (saturn_sreq) & 0xf;
}

static inline unsigned char r_serv_req_1()
{
return (saturn_sreq >> 4) & 0xf;
}

static inline unsigned char r_ir_cont()
{
return saturn_ir_ctrl & 0xf;
}

static inline unsigned char r_base_nib()
{
return saturn_base_off & 0xf;
}

static inline unsigned char r_led_cont()
{
return saturn_lcr & 0xf;
}

static inline unsigned char r_led_buf()
{
return saturn_lbr;
}

static inline unsigned char r_scr_pad()
{
return saturn_scratch;
}

static inline unsigned char r_basenib()
{
return saturn_base_nibble & 0xf;
}

static inline unsigned char r_disp_add_0()
{
return (saturn_disp_addr) & 0xf;
}

static inline unsigned char r_disp_add_1()
{
return (saturn_disp_addr >> 4) & 0xf;
}

static inline unsigned char r_disp_add_2()
{
return (saturn_disp_addr >> 8) & 0xf;
}

static inline unsigned char r_disp_add_3()
{
return (saturn_disp_addr >> 12) & 0xf;
}

static inline unsigned char r_disp_add_4()
{
return (saturn_disp_addr >> 16) & 0xf;
}

static inline unsigned char r_line_off_0()
{
return (saturn_line_offset) & 0xf;
}

static inline unsigned char r_line_off_1()
{
return (saturn_line_offset >> 4) & 0xf;
}

static inline unsigned char r_line_off_2()
{
return (saturn_line_offset >> 8) & 0xf;
}

static inline unsigned char r_line_cnt_0()
{
line_counter++;
if (line_counter > 0x3f) line_counter = -1;
return ((/*(saturn_line_count & 0xc0) |*/ (line_counter & 0x3f)) & 0x0f);
}

static inline unsigned char r_line_cnt_1()
{
line_counter++;
if (line_counter > 0x3f) line_counter = -1;
return ((/*(saturn_line_count & 0xc0) |*/ (line_counter & 0x3f)) >> 4) & 0x0f;
}

static inline unsigned char r_no_know_0()
{
return (saturn_unknown & 0xf);
}

static inline unsigned char r_no_know_1()
{
return (saturn_unknown >> 4) & 0xf;
}

static inline unsigned char r_no_know_2()
{
return (saturn_unknown >> 8) & 0xf;
}

static inline unsigned char r_no_know_3()
{
return (saturn_unknown >> 12) & 0xf;
}

static inline unsigned char r_t1_cont()
{
return saturn_t1_ctrl;
}

static inline unsigned char r_t2_cont()
{
return saturn_t2_ctrl;
}

static inline unsigned char r_menu_add_0()
{
return saturn_menu_addr & 0xf;
}

static inline unsigned char r_menu_add_1()
{
return (saturn_menu_addr >> 4) & 0xf;
}

static inline unsigned char r_menu_add_2()
{
return (saturn_menu_addr >> 8) & 0xf;
}

static inline unsigned char r_menu_add_3()
{
return (saturn_menu_addr >> 12) & 0xf;
}

static inline unsigned char r_menu_add_4()
{
return (saturn_menu_addr >> 16) & 0xf;
}

static inline unsigned char r_no_know2_0()
{
return (saturn_unknown2 & 0xf);
}

static inline unsigned char r_no_know2_1()
{
return (saturn_unknown2 >> 4) & 0xf;
}

static inline unsigned char r_t1()
{
return saturn_timer1;
}

static inline unsigned char r_t2_0()
{
return (saturn_timer2 & 0xf);
}

static inline unsigned char r_t2_1()
{
return (saturn_timer2 >>4) & 0xf;
}

static inline unsigned char r_t2_2()
{
return (saturn_timer2 >>8) & 0xf;
}

static inline unsigned char r_t2_3()
{
return (saturn_timer2 >>12) & 0xf;
}

static inline unsigned char r_t2_4()
{
return (saturn_timer2 >>16) & 0xf;
}

static inline unsigned char r_t2_5()
{
return (saturn_timer2 >>20) & 0xf;
}

static inline unsigned char r_t2_6()
{
return (saturn_timer2 >>24) & 0xf;
}

static inline unsigned char r_t2_7()
{
return (saturn_timer2 >>28) & 0xf;
}

/******************************************************************/
/* Array functions                                                */
/******************************************************************/
struct hw {
	void (*func) (int);
	}
hardw[] = {
	{disp_io},		{contr_cont},	{disp_test_0},	{disp_test_1},	{crc_0},
	{crc_1},		{crc_2},		{crc_3},		{pow_stat},		{pow_cont},
	{mode},			{annunc_0},		{annunc_1},		{baud},			{card_cont},
	{card_stat},	{io_cont},		{rcs},			{tcs},			{crer},
	{rbr_0},		{rbr_1},		{tbr_0},		{tbr_1},		{serv_req_0},
	{serv_req_1},	{ir_cont},		{base_nib},		{led_cont},		{led_buf},
	{scr_pad},		{basenib},		{disp_add_0},	{disp_add_1},	{disp_add_2},
	{disp_add_3},	{disp_add_4},	{line_off_0},	{line_off_1},	{line_off_2},
	{line_cnt_0},	{line_cnt_1},	{no_know_0},	{no_know_1},	{no_know_2},
	{no_know_3},	{t1_cont},		{t2_cont},		{menu_add_0},	{menu_add_1},
	{menu_add_2},	{menu_add_3},	{menu_add_4},	{no_know2_0},	{no_know2_1},
	{t1},			{t2_0},			{t2_1},			{t2_2},			{t2_3},
	{t2_4},			{t2_5},			{t2_6},			{t2_7}
	};

struct hr {
	unsigned char (*func) ();
	}
hardr[] = {
	{r_disp_io},	{r_contr_cont},	{r_disp_test_0},{r_disp_test_1},{r_crc_0},
	{r_crc_1},		{r_crc_2},		{r_crc_3},		{r_pow_stat},	{r_pow_cont},
	{r_mode},		{r_annunc_0},	{r_annunc_1},	{r_baud},		{r_card_cont},
	{r_card_stat},	{r_io_cont},	{r_rcs},		{r_tcs},		{r_crer},
	{r_rbr_0},		{r_rbr_1},		{r_tbr_0},		{r_tbr_1},		{r_serv_req_0},
	{r_serv_req_1},	{r_ir_cont},	{r_base_nib},	{r_led_cont},	{r_led_buf},
	{r_scr_pad},	{r_basenib},	{r_disp_add_0},	{r_disp_add_1},	{r_disp_add_2},
	{r_disp_add_3},	{r_disp_add_4},	{r_line_off_0},	{r_line_off_1},	{r_line_off_2},
	{r_line_cnt_0},	{r_line_cnt_1},	{r_no_know_0},	{r_no_know_1},	{r_no_know_2},
	{r_no_know_3},	{r_t1_cont},	{r_t2_cont},	{r_menu_add_0},	{r_menu_add_1},
	{r_menu_add_2},	{r_menu_add_3},	{r_menu_add_4},	{r_no_know2_0},	{r_no_know2_1},
	{r_t1},			{r_t2_0},		{r_t2_1},		{r_t2_2},		{r_t2_3},
	{r_t2_4},		{r_t2_5},		{r_t2_6},		{r_t2_7}
	};

/******************************************************************/
static inline void write_dev_mem(long addr, int val)
{
(hardw[addr].func) (val);
}

/******************************************************************/
static inline int read_dev_mem(long addr)
{
return (hardr[addr].func) ();
}

/******************************************************************/
inline void write_nibble(long addr,unsigned char *val,int len)
{
int i;
unsigned int add;

if (!saturn_mem[1])
	if (INRANGE(1,addr)) {
		if (display_on) {
			add=addr-display_disp_start;
			for (i=0;i<len;i++) {
				if (add < display_disp_end)
					disp_draw_nibble(add,val[i]);
				add++;
				}
			add=addr-saturn_menu_addr;
			for (i=0;i<len;i++) {
				if (add < 0x110)
					menu_draw_nibble(add,val[i]);
				add++;
				}
			}
		memcpy(&(saturn_ram[addr-saturn_base[1]]),val,len);
		return;
		}
if (!*saturn_mem)
	if (INRANGE(0,addr)) {
		device_check = 1;
		schedule_event = 0;
		addr&=0xff;
		for (i=0;i<len;i++) write_dev_mem(addr++,val[i]);
		return;
		}
if (saturn_card_status & 5) 
	if (!saturn_mem[5])
		if (INRANGE(3,addr)) {
			memcpy(&(saturn_bank1[addr-saturn_base[3]]),val,len);
			return;
			}
if (saturn_card_status & 0xa)
	if (!saturn_mem[4])
		if (INRANGE(4,addr)) {
			memcpy(&(saturn_bank2[addr-saturn_base[4]]),val,len);
			return;
			}
}

/******************************************************************/
inline void read_nibble(long addr,word_20 *con20)
{
int len=5;

if (!saturn_mem[1])
	if (INRANGE(1,addr)) {
		addr-=saturn_base[1];
		while (len--) {
			*con20<<=4;
			*con20|=saturn_ram[addr--];
			}
		return;
		}
if (saturn_card_status & 1)
	if (!saturn_mem[3]) 
		if (INRANGE(3,addr)) {
			addr-=saturn_base[3];
			while (len--) {
				*con20<<=4;
				*con20|=saturn_bank1[addr--];
				}
			return;
			}
if (saturn_card_status & 2)
	if (!saturn_mem[4]) 
		if (INRANGE(4,addr)) {
			addr-=saturn_base[4];
			while (len--) {
				*con20<<=4;
				*con20|=saturn_bank2[addr--];
				}
			return;
			}
while (len--) {
	*con20<<=4;
	*con20|=saturn_rom[addr--];
	}
}

/******************************************************************/
static inline void bank_switch(int bank)
{
if (bank<32) saturn_bank1=saturn_port1+(long)(bank*262144);
else {
	bank-=32;
	saturn_bank2=saturn_port2+(long)(bank*262144);
	}
}

/******************************************************************/
inline void read_nibble_crc(long addr,unsigned char *val,int len)
{
int i;

if (!*saturn_mem) 
	if (INRANGE(0,addr)) {
		addr&=0xff;
		for (i=0;i<len;i++) val[i]=read_dev_mem(addr++);
		return;
		}
if (!saturn_mem[1]) 
	if (INRANGE(1,addr)) {
		addr-=saturn_base[1];
		for (i=0;i<len;i++) val[i]=calc_crc(saturn_ram[addr++]);
		return;
		}
if (!saturn_mem[2]) 
	if (INRANGE(2,addr)) {
		addr-=saturn_base[2];
		for (i=0;i<len;i++) {
			bank_switch((int)(addr++/2));
			val[i]=0x7;
			}
		return;
		}
if (!saturn_mem[3]) 
	if (saturn_card_status & 1)
		if (INRANGE(3,addr)) {
			addr-=saturn_base[3];
			for (i=0;i<len;i++) val[i]=calc_crc(saturn_bank1[addr++]);
			return;
			}
if (!saturn_mem[4]) 
	if (saturn_card_status & 2)
		if (INRANGE(4,addr)) {
			addr-=saturn_base[4];
			for (i=0;i<len;i++) val[i]=calc_crc(saturn_bank2[addr++]);
			return;
			}
for (i=0;i<len;i++) val[i]=calc_crc(saturn_rom[addr++]);
}

/******************************************************************/
inline void read_instr(long addr,unsigned char *val)
{
if (addr<0x7E000) {
		memcpy(val,&(saturn_rom[addr]),21);
		return;
		}
if (!saturn_mem[1]) 
	if (INRANGE(1,addr)) {
		memcpy(val,&(saturn_ram[addr-saturn_base[1]]),21);
		return;
		}
if (saturn_card_status & 1)
	if (!saturn_mem[3]) 
		if (INRANGE(3,addr)) {
			memcpy(val,&(saturn_bank1[addr-saturn_base[3]]),21);
			return;
			}
if (saturn_card_status & 2)
	if (!saturn_mem[4]) 
		if (INRANGE(4,addr)) {
			memcpy(val,&(saturn_bank2[addr-saturn_base[4]]),21);
			return;
			}
memcpy(val,&(saturn_rom[addr]),21);
}

/******************************************************************/
inline void read_disp(long addr,unsigned char *val)
{
if (!saturn_mem[1]) 
	if (INRANGE(1,addr)) {
		memcpy(val,&(saturn_ram[addr-saturn_base[1]]),33);
		return;
		}
if (saturn_card_status & 1)
	if (!saturn_mem[3]) 
		if (INRANGE(3,addr)) {
			memcpy(val,&(saturn_bank1[addr-saturn_base[3]]),33);
			return;
			}
if (saturn_card_status & 2)
	if (!saturn_mem[4]) 
		if (INRANGE(4,addr)) {
			memcpy(val,&(saturn_bank2[addr-saturn_base[4]]),33);
			return;
			}
memcpy(val,&(saturn_rom[addr]),33);
}

/******************************************************************/
void dev_memory_init(void)
{
memset(&device, 0, sizeof(device));
}

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