1127 lines
20 KiB
C
1127 lines
20 KiB
C
/*
|
|
* This file is part of x48, an emulator of the HP-48sx Calculator.
|
|
* Copyright (C) 1994 Eddie C. Dost (ecd@dressler.de)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
/* $Log: actions.c,v $
|
|
* Revision 1.15 1995/01/11 18:20:01 ecd
|
|
* major update to support HP48 G/GX
|
|
*
|
|
* Revision 1.14 1994/12/07 20:20:50 ecd
|
|
* changed shutdown again: wake on TIMER1CTRL & XTRA
|
|
*
|
|
* Revision 1.14 1994/12/07 20:20:50 ecd
|
|
* changed shutdown again: wake on TIMER1CTRL & XTRA
|
|
*
|
|
* Revision 1.13 1994/11/28 02:00:51 ecd
|
|
* changed do_configure for internal debugging
|
|
*
|
|
* Revision 1.12 1994/11/02 14:40:38 ecd
|
|
* removed call to debug in do_shutdown()
|
|
*
|
|
* Revision 1.11 1994/10/09 20:29:47 ecd
|
|
* no real change, was just fiddling around with the display.
|
|
*
|
|
* Revision 1.10 1994/10/06 16:30:05 ecd
|
|
* added refresh_display()
|
|
*
|
|
* Revision 1.9 1994/10/05 08:36:44 ecd
|
|
* changed shutdown
|
|
*
|
|
* Revision 1.8 1994/10/01 10:12:53 ecd
|
|
* fixed bug in shutdown
|
|
*
|
|
* Revision 1.7 1994/09/30 12:37:09 ecd
|
|
* changed shutdown instruction
|
|
*
|
|
* Revision 1.6 1994/09/18 22:47:20 ecd
|
|
* fixed bug with overflow in timerdiff
|
|
*
|
|
* Revision 1.5 1994/09/18 15:29:22 ecd
|
|
* added SHUTDN implementation,
|
|
* started Real Time support.
|
|
*
|
|
* Revision 1.4 1994/09/13 16:57:00 ecd
|
|
* changed to plain X11
|
|
*
|
|
* Revision 1.3 1994/08/31 18:23:21 ecd
|
|
* changed memory read routines.
|
|
*
|
|
* Revision 1.2 1994/08/27 11:28:59 ecd
|
|
* changed keyboard interrupt handling.
|
|
*
|
|
* Revision 1.1 1994/08/26 11:09:02 ecd
|
|
* Initial revision
|
|
*
|
|
*
|
|
* $Id: actions.c,v 1.15 1995/01/11 18:20:01 ecd Exp ecd $
|
|
*/
|
|
|
|
/* #define DEBUG_INTERRUPT 1 */
|
|
/* #define DEBUG_KBD_INT 1 */
|
|
/* #define DEBUG_SHUTDOWN 1 */
|
|
/* #define DEBUG_CONFIG 1 */
|
|
/* #define DEBUG_ID 1 */
|
|
|
|
#include "global.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#include "hp48.h"
|
|
#include "hp48_emu.h"
|
|
#include "device.h"
|
|
#include "timer.h"
|
|
#include "debugger.h"
|
|
#include "romio.h"
|
|
|
|
static int interrupt_called = 0;
|
|
extern long nibble_masks[16];
|
|
|
|
int got_alarm;
|
|
int first_press = 1;
|
|
int conf_bank1 = 0x00000;
|
|
int conf_bank2 = 0x00000;
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
do_in(void)
|
|
#else
|
|
do_in()
|
|
#endif
|
|
{
|
|
int i, in, out;
|
|
|
|
out = 0;
|
|
for (i = 2; i >= 0; i--) {
|
|
out <<= 4;
|
|
out |= saturn.OUT[i];
|
|
}
|
|
in = 0;
|
|
for (i = 0; i < 9; i++)
|
|
if (out & (1 << i))
|
|
in |= saturn.keybuf.rows[i];
|
|
#ifdef DEBUG_INOUT
|
|
LOGE( "saturn.OUT=%.3x, saturn.IN=%.4x\n", out, in);
|
|
#endif
|
|
|
|
// PATCH http://svn.berlios.de/wsvn/x48?op=comp&compare[]=/trunk@12&compare[]=/trunk@13
|
|
// PAS TERRIBLE VISIBLEMENT
|
|
|
|
if ( saturn.PC == 0x00E31 && !first_press &&
|
|
( (out & 0x10 && in & 0x1 ) || /* keys are Backspace */
|
|
(out & 0x40 && in & 0x7 ) || /* right, left & down */
|
|
(out & 0x80 && in & 0x2 ) ) ) /* up arrows */
|
|
{
|
|
for (i = 0; i < 9; i++)
|
|
if (out & (1 << i))
|
|
saturn.keybuf.rows[i] = 0;
|
|
first_press = 1;
|
|
}
|
|
else
|
|
first_press = 0;
|
|
|
|
// FIN PATCH
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
saturn.IN[i] = in & 0xf;
|
|
in >>= 4;
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
clear_program_stat(int n)
|
|
#else
|
|
clear_program_stat(n)
|
|
int n;
|
|
#endif
|
|
{
|
|
saturn.PSTAT[n] = 0;
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
set_program_stat(int n)
|
|
#else
|
|
set_program_stat(n)
|
|
int n;
|
|
#endif
|
|
{
|
|
saturn.PSTAT[n] = 1;
|
|
}
|
|
|
|
int
|
|
#ifdef __FunctionProto__
|
|
get_program_stat(int n)
|
|
#else
|
|
get_program_stat(n)
|
|
int n;
|
|
#endif
|
|
{
|
|
return saturn.PSTAT[n];
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
register_to_status(unsigned char *r)
|
|
#else
|
|
register_to_status(r)
|
|
unsigned char *r;
|
|
#endif
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 12; i++) {
|
|
saturn.PSTAT[i] = (r[i / 4] >> (i % 4)) & 1;
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
status_to_register(unsigned char *r)
|
|
#else
|
|
status_to_register(r)
|
|
unsigned char *r;
|
|
#endif
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 12; i++) {
|
|
if (saturn.PSTAT[i]) {
|
|
r[i / 4] |= 1 << (i % 4);
|
|
} else {
|
|
r[i / 4] &= ~(1 << (i % 4)) & 0xf;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
swap_register_status(unsigned char *r)
|
|
#else
|
|
swap_register_status(r)
|
|
unsigned char *r;
|
|
#endif
|
|
{
|
|
int i, tmp;
|
|
|
|
for (i = 0; i < 12; i++) {
|
|
tmp = saturn.PSTAT[i];
|
|
saturn.PSTAT[i] = (r[i / 4] >> (i % 4)) & 1;
|
|
if (tmp) {
|
|
r[i / 4] |= 1 << (i % 4);
|
|
} else {
|
|
r[i / 4] &= ~(1 << (i % 4)) & 0xf;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
clear_status(void)
|
|
#else
|
|
clear_status()
|
|
#endif
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 12; i++) {
|
|
saturn.PSTAT[i] = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
set_register_nibble(unsigned char *reg, int n, unsigned char val)
|
|
#else
|
|
set_register_nibble(reg, n, val)
|
|
unsigned char *reg;
|
|
int n;
|
|
unsigned char val;
|
|
#endif
|
|
{
|
|
reg[n] = val;
|
|
}
|
|
|
|
unsigned char
|
|
#ifdef __FunctionProto__
|
|
get_register_nibble(unsigned char *reg, int n)
|
|
#else
|
|
get_register_nibble(reg, n)
|
|
unsigned char *reg;
|
|
int n;
|
|
#endif
|
|
{
|
|
return reg[n];
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
set_register_bit(unsigned char *reg, int n)
|
|
#else
|
|
set_register_bit(reg, n)
|
|
unsigned char *reg;
|
|
int n;
|
|
#endif
|
|
{
|
|
reg[n/4] |= (1 << (n%4));
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
clear_register_bit(unsigned char *reg, int n)
|
|
#else
|
|
clear_register_bit(reg, n)
|
|
unsigned char *reg;
|
|
int n;
|
|
#endif
|
|
{
|
|
reg[n/4] &= ~(1 << (n%4));
|
|
}
|
|
|
|
int
|
|
#ifdef __FunctionProto__
|
|
get_register_bit(unsigned char *reg, int n)
|
|
#else
|
|
get_register_bit(reg, n)
|
|
unsigned char *reg;
|
|
int n;
|
|
#endif
|
|
{
|
|
return ((int)(reg[n/4] & (1 << (n%4))) > 0)?1:0;
|
|
}
|
|
|
|
short conf_tab_sx[] = { 1, 2, 2, 2, 2, 0 };
|
|
short conf_tab_gx[] = { 1, 2, 2, 2, 2, 0 };
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
do_reset(void)
|
|
#else
|
|
do_reset()
|
|
#endif
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (opt_gx)
|
|
saturn.mem_cntl[i].unconfigured = conf_tab_gx[i];
|
|
else
|
|
saturn.mem_cntl[i].unconfigured = conf_tab_sx[i];
|
|
saturn.mem_cntl[i].config[0] = 0x0;
|
|
saturn.mem_cntl[i].config[1] = 0x0;
|
|
}
|
|
|
|
#ifdef DEBUG_CONFIG
|
|
LOGE( "%.5lx: RESET\n", saturn.PC);
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (saturn.mem_cntl[i].unconfigured)
|
|
LOGE( "MEMORY CONTROLLER %d is unconfigured\n", i);
|
|
else
|
|
LOGE( "MEMORY CONTROLLER %d is configured to %.5lx, %.5lx\n",
|
|
i, saturn.mem_cntl[i].config[0], saturn.mem_cntl[i].config[1]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
do_inton(void)
|
|
#else
|
|
do_inton()
|
|
#endif
|
|
{
|
|
saturn.kbd_ien = 1;
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
do_intoff(void)
|
|
#else
|
|
do_intoff()
|
|
#endif
|
|
{
|
|
saturn.kbd_ien = 0;
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
do_return_interupt(void)
|
|
#else
|
|
do_return_interupt()
|
|
#endif
|
|
{
|
|
if (saturn.int_pending) {
|
|
#ifdef DEBUG_INTERRUPT
|
|
LOGE( "PC = %.5lx: RTI SERVICE PENDING INTERRUPT\n",
|
|
saturn.PC);
|
|
#endif
|
|
saturn.int_pending = 0;
|
|
saturn.intenable = 0;
|
|
saturn.PC = 0xf;
|
|
} else {
|
|
#ifdef DEBUG_INTERRUPT
|
|
LOGE( "PC = %.5lx: RETURN INTERRUPT to ", saturn.PC);
|
|
#endif
|
|
saturn.PC = pop_return_addr();
|
|
#ifdef DEBUG_INTERRUPT
|
|
LOGE( "%.5lx\n", saturn.PC);
|
|
#endif
|
|
saturn.intenable = 1;
|
|
|
|
if (adj_time_pending) {
|
|
schedule_event = 0;
|
|
sched_adjtime = 0;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
do_interupt(void)
|
|
#else
|
|
do_interupt()
|
|
#endif
|
|
{
|
|
interrupt_called = 1;
|
|
if (saturn.intenable) {
|
|
#ifdef DEBUG_INTERRUPT
|
|
LOGE( "PC = %.5lx: INTERRUPT\n", saturn.PC);
|
|
#endif
|
|
push_return_addr(saturn.PC);
|
|
saturn.PC = 0xf;
|
|
saturn.intenable = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
do_kbd_int(void)
|
|
#else
|
|
do_kbd_int()
|
|
#endif
|
|
{
|
|
interrupt_called = 1;
|
|
if (saturn.intenable) {
|
|
#ifdef DEBUG_KBD_INT
|
|
LOGE( "PC = %.5lx: KBD INT\n", saturn.PC);
|
|
#endif
|
|
push_return_addr(saturn.PC);
|
|
saturn.PC = 0xf;
|
|
saturn.intenable = 0;
|
|
} else {
|
|
#ifdef DEBUG_KBD_INT
|
|
LOGE( "PC = %.5lx: KBD INT PENDING\n", saturn.PC);
|
|
#endif
|
|
saturn.int_pending = 1;
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
do_reset_interrupt_system(void)
|
|
#else
|
|
do_reset_interrupt_system()
|
|
#endif
|
|
{
|
|
int i, gen_intr;
|
|
|
|
saturn.kbd_ien = 1;
|
|
gen_intr = 0;
|
|
for (i = 0; i < 9; i++) {
|
|
if (saturn.keybuf.rows[i] != 0) {
|
|
gen_intr = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (gen_intr) {
|
|
do_kbd_int();
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
do_unconfigure(void)
|
|
#else
|
|
do_unconfigure()
|
|
#endif
|
|
{
|
|
int i;
|
|
unsigned int conf;
|
|
|
|
conf = 0;
|
|
for (i = 4; i >= 0; i--) {
|
|
conf <<= 4;
|
|
conf |= saturn.C[i];
|
|
}
|
|
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (saturn.mem_cntl[i].config[0] == conf)
|
|
{
|
|
if (opt_gx)
|
|
saturn.mem_cntl[i].unconfigured = conf_tab_gx[i];
|
|
else
|
|
saturn.mem_cntl[i].unconfigured = conf_tab_sx[i];
|
|
saturn.mem_cntl[i].config[0] = 0x0;
|
|
saturn.mem_cntl[i].config[1] = 0x0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_CONFIG
|
|
LOGE( "%.5lx: UNCNFG %.5x:\n", saturn.PC, conf);
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (saturn.mem_cntl[i].unconfigured)
|
|
LOGE( "MEMORY CONTROLLER %d is unconfigured\n", i);
|
|
else
|
|
LOGE( "MEMORY CONTROLLER %d is configured to %.5lx, %.5lx\n",
|
|
i, saturn.mem_cntl[i].config[0], saturn.mem_cntl[i].config[1]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
do_configure(void)
|
|
#else
|
|
do_configure()
|
|
#endif
|
|
{
|
|
int i;
|
|
unsigned long conf;
|
|
|
|
conf = 0;
|
|
for (i = 4; i >= 0; i--) {
|
|
conf <<= 4;
|
|
conf |= saturn.C[i];
|
|
}
|
|
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (saturn.mem_cntl[i].unconfigured)
|
|
{
|
|
saturn.mem_cntl[i].unconfigured--;
|
|
saturn.mem_cntl[i].config[saturn.mem_cntl[i].unconfigured] = conf;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_CONFIG
|
|
LOGE( "%.5lx: CONFIG %.5lx:\n", saturn.PC, conf);
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (saturn.mem_cntl[i].unconfigured)
|
|
LOGE( "MEMORY CONTROLLER %d is unconfigured\n", i);
|
|
else
|
|
LOGE( "MEMORY CONTROLLER %d at %.5lx, %.5lx\n",
|
|
i, saturn.mem_cntl[i].config[0], saturn.mem_cntl[i].config[1]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int
|
|
#ifdef __FunctionProto__
|
|
get_identification(void)
|
|
#else
|
|
get_identification()
|
|
#endif
|
|
{
|
|
int i;
|
|
static int chip_id[]
|
|
= { 0, 0, 0, 0, 0x05, 0xf6, 0x07, 0xf8, 0x01, 0xf2, 0, 0 };
|
|
int id;
|
|
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (saturn.mem_cntl[i].unconfigured)
|
|
break;
|
|
}
|
|
if (i < 6)
|
|
id = chip_id[2 * i + (2 - saturn.mem_cntl[i].unconfigured)];
|
|
else
|
|
id = 0;
|
|
|
|
#ifdef DEBUG_ID
|
|
LOGE( "%.5lx: C=ID, returning: %x\n", saturn.PC, id);
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (saturn.mem_cntl[i].unconfigured == 2)
|
|
LOGE( "MEMORY CONTROLLER %d is unconfigured\n", i);
|
|
else if (saturn.mem_cntl[i].unconfigured == 1)
|
|
{
|
|
if (i == 0)
|
|
LOGE( "MEMORY CONTROLLER %d unconfigured\n", i);
|
|
else
|
|
LOGE( "MEMORY CONTROLLER %d configured to ????? %.5lx\n",
|
|
i, saturn.mem_cntl[i].config[1]);
|
|
}
|
|
else
|
|
LOGE( "MEMORY CONTROLLER %d configured to %.5lx, %.5lx\n",
|
|
i, saturn.mem_cntl[i].config[0], saturn.mem_cntl[i].config[1]);
|
|
}
|
|
#endif
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
saturn.C[i] = id & 0x0f;
|
|
id >>= 4;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
do_shutdown(void)
|
|
#else
|
|
do_shutdown()
|
|
#endif
|
|
{
|
|
int wake, alarms;
|
|
t1_t2_ticks ticks;
|
|
|
|
if (device.display_touched) {
|
|
device.display_touched = 0;
|
|
update_display();
|
|
#ifdef HAVE_XSHM
|
|
if (disp.display_update) refresh_display();
|
|
#endif
|
|
}
|
|
|
|
stop_timer(RUN_TIMER);
|
|
start_timer(IDLE_TIMER);
|
|
|
|
if (is_zero_register(saturn.OUT, OUT_FIELD)) {
|
|
#ifdef DEBUG_SHUTDOWN
|
|
LOGE( "%.5lx: SHUTDN: PC = 0\n", saturn.PC);
|
|
#endif
|
|
saturn.intenable = 1;
|
|
saturn.int_pending = 0;
|
|
}
|
|
|
|
#ifdef DEBUG_SHUTDOWN
|
|
LOGE( "%.5lx:\tSHUTDN: Timer 1 Control = %x, Timer 1 = %d\n",
|
|
saturn.PC, saturn.t1_ctrl, saturn.timer1);
|
|
LOGE( "%.5lx:\tSHUTDN: Timer 2 Control = %x, Timer 2 = %ld\n",
|
|
saturn.PC, saturn.t2_ctrl, saturn.timer2);
|
|
#endif
|
|
|
|
/* if (in_debugger)
|
|
wake = 1;
|
|
else*/
|
|
wake = 0;
|
|
|
|
alarms = 0;
|
|
|
|
// android_refresh_screen();
|
|
|
|
/* do {
|
|
LOGI("---");
|
|
pause();
|
|
LOGI("---");
|
|
if (got_alarm) {
|
|
got_alarm = 0;
|
|
|
|
#ifdef HAVE_XSHM
|
|
if (disp.display_update) refresh_display();
|
|
#endif*/
|
|
|
|
//android_refresh_screen();
|
|
// usleep(50000);
|
|
|
|
do {
|
|
|
|
/* do {
|
|
|
|
(*android_env)->CallVoidMethod(android_env, android_callback, pauseEvent);
|
|
|
|
if (got_alarm) {
|
|
|
|
got_alarm = 0;*/
|
|
|
|
ticks = get_t1_t2();
|
|
if (saturn.t2_ctrl & 0x01) {
|
|
saturn.timer2 = ticks.t2_ticks;
|
|
}
|
|
saturn.timer1 = set_t1 - ticks.t1_ticks;
|
|
set_t1 = ticks.t1_ticks;
|
|
|
|
interrupt_called = 0;
|
|
|
|
|
|
// android_refresh_screen();
|
|
// usleep(50000);
|
|
//LOGI("enter pauseEvent");
|
|
//(*android_env)->CallVoidMethod(android_env, android_callback, pauseEvent);
|
|
// LOGI("exit pauseEvent");
|
|
|
|
blockConditionVariable();
|
|
|
|
if (GetEvent()) {
|
|
if (interrupt_called)
|
|
wake = 1;
|
|
}
|
|
|
|
if (saturn.timer2 <= 0)
|
|
{
|
|
if (saturn.t2_ctrl & 0x04)
|
|
{
|
|
wake = 1;
|
|
}
|
|
if (saturn.t2_ctrl & 0x02)
|
|
{
|
|
wake = 1;
|
|
saturn.t2_ctrl |= 0x08;
|
|
do_interupt();
|
|
}
|
|
}
|
|
|
|
if (saturn.timer1 <= 0)
|
|
{
|
|
saturn.timer1 &= 0x0f;
|
|
if (saturn.t1_ctrl & 0x04)
|
|
{
|
|
wake = 1;
|
|
}
|
|
if (saturn.t1_ctrl & 0x03)
|
|
{
|
|
wake = 1;
|
|
saturn.t1_ctrl |= 0x08;
|
|
do_interupt();
|
|
}
|
|
}
|
|
|
|
if (wake == 0) {
|
|
interrupt_called = 0;
|
|
receive_char();
|
|
if (interrupt_called)
|
|
wake = 1;
|
|
}
|
|
|
|
alarms++;
|
|
|
|
//}
|
|
|
|
} while (wake == 0 && exit_state);
|
|
|
|
|
|
stop_timer(IDLE_TIMER);
|
|
start_timer(RUN_TIMER);
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
set_hardware_stat(int op)
|
|
#else
|
|
set_hardware_stat(op)
|
|
int op;
|
|
#endif
|
|
{
|
|
if (op & 1) saturn.XM = 1;
|
|
if (op & 2) saturn.SB = 1;
|
|
if (op & 4) saturn.SR = 1;
|
|
if (op & 8) saturn.MP = 1;
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
clear_hardware_stat(int op)
|
|
#else
|
|
clear_hardware_stat(op)
|
|
int op;
|
|
#endif
|
|
{
|
|
if (op & 1) saturn.XM = 0;
|
|
if (op & 2) saturn.SB = 0;
|
|
if (op & 4) saturn.SR = 0;
|
|
if (op & 8) saturn.MP = 0;
|
|
}
|
|
|
|
int
|
|
#ifdef __FunctionProto__
|
|
is_zero_hardware_stat(int op)
|
|
#else
|
|
is_zero_hardware_stat(op)
|
|
int op;
|
|
#endif
|
|
{
|
|
if (op & 1) if (saturn.XM != 0) return 0;
|
|
if (op & 2) if (saturn.SB != 0) return 0;
|
|
if (op & 4) if (saturn.SR != 0) return 0;
|
|
if (op & 8) if (saturn.MP != 0) return 0;
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
push_return_addr(long addr)
|
|
#else
|
|
push_return_addr(addr)
|
|
long addr;
|
|
#endif
|
|
{
|
|
int i;
|
|
|
|
if (++saturn.rstkp >= NR_RSTK) {
|
|
#if 0
|
|
LOGE( "%.5lx: RSTK overflow !!!\n", saturn.PC);
|
|
for (i = saturn.rstkp - 1; i >= 0; i--) {
|
|
LOGE( "\tRSTK[%d] %.5lx\n", i, saturn.rstk[i]);
|
|
}
|
|
#endif
|
|
for (i = 1; i < NR_RSTK; i++)
|
|
saturn.rstk[i-1] = saturn.rstk[i];
|
|
saturn.rstkp--;
|
|
}
|
|
saturn.rstk[saturn.rstkp] = addr;
|
|
#ifdef DEBUG_RSTK
|
|
LOGE( "PUSH %.5x:\n", addr);
|
|
for (i = saturn.rstkp; i >= 0; i--) {
|
|
LOGE( "RSTK[%d] %.5x\n", i, saturn.rstk[i]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
long
|
|
#ifdef __FunctionProto__
|
|
pop_return_addr(void)
|
|
#else
|
|
pop_return_addr()
|
|
#endif
|
|
{
|
|
#ifdef DEBUG_RSTK
|
|
int i;
|
|
|
|
for (i = saturn.rstkp; i >= 0; i--) {
|
|
LOGE( "RSTK[%d] %.5x\n", i, saturn.rstk[i]);
|
|
}
|
|
LOGE( "POP %.5x:\n",
|
|
(saturn.rstkp >= 0) ? saturn.rstk[saturn.rstkp]:0);
|
|
#endif
|
|
if (saturn.rstkp < 0)
|
|
return 0;
|
|
return saturn.rstk[saturn.rstkp--];
|
|
}
|
|
|
|
char *
|
|
#ifdef __FunctionProto__
|
|
make_hexstr(long addr, int n)
|
|
#else
|
|
make_hexstr(addr, n)
|
|
long addr;
|
|
int n;
|
|
#endif
|
|
{
|
|
static char str[44];
|
|
int i, t, trunc;
|
|
|
|
trunc = 0;
|
|
if (n > 40) {
|
|
n = 40;
|
|
trunc = 1;
|
|
}
|
|
for (i = 0; i < n; i++) {
|
|
t = read_nibble(addr+i);
|
|
if (t <= 9)
|
|
str[i] = '0' + t;
|
|
else
|
|
str[i] = 'a' + (t - 10);
|
|
}
|
|
str[n] = '\0';
|
|
if (trunc) {
|
|
str[n] = '.';
|
|
str[n+1] = '.';
|
|
str[n+2] = '.';
|
|
str[n+3] = '\0';
|
|
}
|
|
return str;
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
load_constant(unsigned char *reg, int n, long addr)
|
|
#else
|
|
load_constant(reg, n, addr)
|
|
unsigned char *reg;
|
|
int n;
|
|
long addr;
|
|
#endif
|
|
{
|
|
int i, p;
|
|
|
|
p = saturn.P;
|
|
for (i = 0; i < n; i++) {
|
|
reg[p] = read_nibble(addr + i);
|
|
p = (p + 1) & 0xf;
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
load_addr(word_20 *dat, long addr, int n)
|
|
#else
|
|
load_addr(dat, addr, n)
|
|
word_20 *dat;
|
|
long addr;
|
|
int n;
|
|
#endif
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
*dat &= ~nibble_masks[i];
|
|
*dat |= read_nibble(addr + i) << (i * 4);
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
load_address(unsigned char *reg, long addr, int n)
|
|
#else
|
|
load_address(reg, addr, n)
|
|
unsigned char *reg;
|
|
long addr;
|
|
int n;
|
|
#endif
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
reg[i] = read_nibble(addr + i);
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
register_to_address(unsigned char *reg, word_20 *dat, int s)
|
|
#else
|
|
register_to_address(reg, dat, s)
|
|
unsigned char *reg;
|
|
word_20 *dat;
|
|
int s;
|
|
#endif
|
|
{
|
|
int i, n;
|
|
|
|
if (s)
|
|
n = 4;
|
|
else
|
|
n = 5;
|
|
for (i = 0; i < n; i++) {
|
|
*dat &= ~nibble_masks[i];
|
|
*dat |= (reg[i] & 0x0f) << (i * 4);
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
address_to_register(word_20 dat, unsigned char *reg, int s)
|
|
#else
|
|
address_to_register(dat, reg, s)
|
|
word_20 dat;
|
|
unsigned char *reg;
|
|
int s;
|
|
#endif
|
|
{
|
|
int i, n;
|
|
|
|
if (s)
|
|
n = 4;
|
|
else
|
|
n = 5;
|
|
for (i = 0; i < n; i++) {
|
|
reg[i] = dat & 0x0f;
|
|
dat >>= 4;
|
|
}
|
|
}
|
|
|
|
long
|
|
#ifdef __FunctionProto__
|
|
dat_to_addr(unsigned char *dat)
|
|
#else
|
|
dat_to_addr(dat)
|
|
unsigned char *dat;
|
|
#endif
|
|
{
|
|
int i;
|
|
long addr;
|
|
|
|
addr = 0;
|
|
for (i = 4; i >= 0; i--) {
|
|
addr <<= 4;
|
|
addr |= (dat[i] & 0xf);
|
|
}
|
|
return addr;
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
addr_to_dat(long addr, unsigned char *dat)
|
|
#else
|
|
addr_to_dat(addr, dat)
|
|
long addr;
|
|
unsigned char *dat;
|
|
#endif
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
dat[i] = (addr & 0xf);
|
|
addr >>= 4;
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
add_address(word_20 *dat, int add)
|
|
#else
|
|
add_address(dat, add)
|
|
word_20 *dat;
|
|
int add;
|
|
#endif
|
|
{
|
|
*dat += add;
|
|
if (*dat & (word_20)0xfff00000) {
|
|
saturn.CARRY = 1;
|
|
} else {
|
|
saturn.CARRY = 0;
|
|
}
|
|
*dat &= 0xfffff;
|
|
}
|
|
|
|
static int start_fields[] = {
|
|
-1, 0, 2, 0, 15, 3, 0, 0,
|
|
-1, 0, 2, 0, 15, 3, 0, 0,
|
|
0, 0, 0
|
|
};
|
|
|
|
static int end_fields[] = {
|
|
-1, -1, 2, 2, 15, 14, 1, 15,
|
|
-1, -1, 2, 2, 15, 14, 1, 4,
|
|
3, 2, 0
|
|
};
|
|
|
|
static inline int
|
|
#ifdef __FunctionProto__
|
|
get_start(int code)
|
|
#else
|
|
get_start(code)
|
|
int code;
|
|
#endif
|
|
{
|
|
int s;
|
|
|
|
if ((s = start_fields[code]) == -1) {
|
|
s = saturn.P;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
static inline int
|
|
#ifdef __FuntionProto__
|
|
get_end(int code)
|
|
#else
|
|
get_end(code)
|
|
int code;
|
|
#endif
|
|
{
|
|
int e;
|
|
|
|
if ((e = end_fields[code]) == -1) {
|
|
e = saturn.P;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
store(word_20 dat, unsigned char *reg, int code)
|
|
#else
|
|
store(dat, reg, code)
|
|
word_20 dat;
|
|
unsigned char *reg;
|
|
int code;
|
|
#endif
|
|
{
|
|
int i, s, e;
|
|
|
|
s = get_start(code);
|
|
e = get_end(code);
|
|
for (i = s; i <= e; i++) {
|
|
write_nibble(dat++, reg[i]);
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
store_n(word_20 dat, unsigned char *reg, int n)
|
|
#else
|
|
store_n(dat, reg, n)
|
|
word_20 dat;
|
|
unsigned char *reg;
|
|
int n;
|
|
#endif
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
write_nibble(dat++, reg[i]);
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
recall(unsigned char *reg, word_20 dat, int code)
|
|
#else
|
|
recall(reg, dat, code)
|
|
unsigned char *reg;
|
|
word_20 dat;
|
|
int code;
|
|
#endif
|
|
{
|
|
int i, s, e;
|
|
|
|
s = get_start(code);
|
|
e = get_end(code);
|
|
for (i = s; i <= e; i++) {
|
|
reg[i] = read_nibble_crc(dat++);
|
|
}
|
|
}
|
|
|
|
void
|
|
#ifdef __FunctionProto__
|
|
recall_n(unsigned char *reg, word_20 dat, int n)
|
|
#else
|
|
recall_n(reg, dat, n)
|
|
unsigned char *reg;
|
|
word_20 dat;
|
|
int n;
|
|
#endif
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
reg[i] = read_nibble_crc(dat++);
|
|
}
|
|
}
|
|
|