mirror of
https://github.com/Wiimpathy/HatariWii.git
synced 2024-06-03 00:58:44 +02:00
327 lines
7.9 KiB
C
327 lines
7.9 KiB
C
/*
|
|
Hatari - nvram.c
|
|
|
|
This file is distributed under the GNU General Public License, version 2
|
|
or at your option any later version. Read the file gpl.txt for details.
|
|
|
|
This file is partly based on GPL code taken from the Aranym project.
|
|
- Copyright (c) 2001-2004 Petr Stehlik of ARAnyM dev team
|
|
- Adaption to Hatari (c) 2006 by Thomas Huth
|
|
|
|
Atari TT and Falcon NVRAM/RTC emulation code.
|
|
This is a MC146818A or compatible chip with a non-volatile RAM area.
|
|
|
|
These are the important bytes in the nvram array:
|
|
|
|
Byte: Description:
|
|
|
|
14-15 Preferred operating system (TOS, Unix)
|
|
20 Language
|
|
21 Keyboard layout
|
|
22 Format of date/time
|
|
23 Separator for date
|
|
24 Boot delay
|
|
28-29 Video mode
|
|
30 SCSI-ID in bits 0-2, bus arbitration flag in bit 7 (1=off, 0=on)
|
|
62-63 Checksum
|
|
|
|
All other cells are reserved / unused.
|
|
*/
|
|
const char NvRam_fileid[] = "Hatari nvram.c : " __DATE__ " " __TIME__;
|
|
|
|
#include "main.h"
|
|
#include "configuration.h"
|
|
#include "ioMem.h"
|
|
#include "log.h"
|
|
#include "nvram.h"
|
|
#include "paths.h"
|
|
#include "vdi.h"
|
|
|
|
|
|
// Defs for checksum
|
|
#define CKS_RANGE_START 14
|
|
#define CKS_RANGE_END (14+47)
|
|
#define CKS_RANGE_LEN (CKS_RANGE_END-CKS_RANGE_START+1)
|
|
#define CKS_LOC (14+48)
|
|
|
|
#define NVRAM_START 14
|
|
#define NVRAM_LEN 50
|
|
|
|
static Uint8 nvram[64] = { 48,255,21,255,23,255,1,25,3,33,42,14,112,128,
|
|
0,0,0,0,0,0,0,0,17,46,32,1,255,0,1,10,135,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
|
|
|
|
|
|
static Uint8 nvram_index;
|
|
static char nvram_filename[FILENAME_MAX];
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* Load NVRAM data from file.
|
|
*/
|
|
static bool NvRam_Load(void)
|
|
{
|
|
bool ret = false;
|
|
FILE *f = fopen(nvram_filename, "rb");
|
|
if (f != NULL)
|
|
{
|
|
Uint8 fnvram[NVRAM_LEN];
|
|
if (fread(fnvram, 1, NVRAM_LEN, f) == NVRAM_LEN)
|
|
{
|
|
memcpy(nvram+NVRAM_START, fnvram, NVRAM_LEN);
|
|
LOG_TRACE(TRACE_NVRAM, "NVRAM: loaded from '%s'\n", nvram_filename);
|
|
ret = true;
|
|
}
|
|
else
|
|
{
|
|
Log_Printf(LOG_WARN, "ERROR: NVRAM loading from '%s' failed\n", nvram_filename);
|
|
}
|
|
fclose(f);
|
|
}
|
|
else
|
|
{
|
|
Log_Printf(LOG_INFO, "NVRAM not found at '%s'\n", nvram_filename);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* Save NVRAM data to file
|
|
*/
|
|
static bool NvRam_Save(void)
|
|
{
|
|
bool ret = false;
|
|
FILE *f = fopen(nvram_filename, "wb");
|
|
if (f != NULL)
|
|
{
|
|
if (fwrite(nvram+NVRAM_START, 1, NVRAM_LEN, f) == NVRAM_LEN)
|
|
{
|
|
LOG_TRACE(TRACE_NVRAM, "NVRAM: saved to '%s'\n", nvram_filename);
|
|
ret = true;
|
|
}
|
|
else
|
|
{
|
|
Log_Printf(LOG_WARN, "ERROR: storing NVRAM to '%s' failed\n", nvram_filename);
|
|
}
|
|
fclose(f);
|
|
}
|
|
else
|
|
{
|
|
Log_Printf(LOG_WARN, "ERROR: storing NVRAM to '%s' failed\n", nvram_filename);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* Create NVRAM checksum. The checksum is over all bytes except the
|
|
* checksum bytes themselves; these are at the very end.
|
|
*/
|
|
static void NvRam_SetChecksum(void)
|
|
{
|
|
int i;
|
|
unsigned char sum = 0;
|
|
|
|
for(i = CKS_RANGE_START; i <= CKS_RANGE_END; ++i)
|
|
sum += nvram[i];
|
|
nvram[NVRAM_CHKSUM1] = ~sum;
|
|
nvram[NVRAM_CHKSUM2] = sum;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* NvRam_Reset: Called during init and reset, used for resetting the
|
|
* emulated chip.
|
|
*/
|
|
void NvRam_Reset(void)
|
|
{
|
|
if (bUseVDIRes)
|
|
{
|
|
/* The objective is to start the TOS with a video mode similar
|
|
* to the requested one. This is important for the TOS to initialize
|
|
* the right font height and palette. */
|
|
if (VDIHeight < 400)
|
|
{
|
|
/* This will select the 8x8 system font */
|
|
switch(VDIPlanes)
|
|
{
|
|
/* The case 1 is not handled, because that would result in 0x0000
|
|
* which is an invalide video mode. This does not matter,
|
|
* since any color palette is good for monochrome, anyway. */
|
|
case 2: /* set 320x200x4 colors */
|
|
nvram[NVRAM_VMODE1] = 0x00;
|
|
nvram[NVRAM_VMODE2] = 0x01;
|
|
break;
|
|
case 4: /* set 320x200x16 colors */
|
|
default:
|
|
nvram[NVRAM_VMODE1] = 0x00;
|
|
nvram[NVRAM_VMODE2] = 0x02;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* This will select the 8x16 system font */
|
|
switch(VDIPlanes)
|
|
{
|
|
case 4: /* set 640x400x16 colors */
|
|
nvram[NVRAM_VMODE1] = 0x01;
|
|
nvram[NVRAM_VMODE2] = 0x0a;
|
|
break;
|
|
case 2: /* set 640x400x4 colors */
|
|
nvram[NVRAM_VMODE1] = 0x01;
|
|
nvram[NVRAM_VMODE2] = 0x09;
|
|
break;
|
|
case 1: /* set 640x400x2 colors */
|
|
default:
|
|
nvram[NVRAM_VMODE1] = 0x01;
|
|
nvram[NVRAM_VMODE2] = 0x08;
|
|
}
|
|
}
|
|
NvRam_SetChecksum();
|
|
}
|
|
nvram_index = 0;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* Initialization
|
|
*/
|
|
void NvRam_Init(void)
|
|
{
|
|
const char sBaseName[] = "hatari.nvram";
|
|
const char *psHomeDir;
|
|
|
|
// set up the nvram filename
|
|
psHomeDir = Paths_GetHatariHome();
|
|
if (strlen(psHomeDir)+sizeof(sBaseName)+1 < sizeof(nvram_filename))
|
|
sprintf(nvram_filename, "%s%c%s", psHomeDir, PATHSEP, sBaseName);
|
|
else
|
|
strcpy(nvram_filename, sBaseName);
|
|
|
|
if (!NvRam_Load()) // load NVRAM file automatically
|
|
{
|
|
if (ConfigureParams.Screen.nMonitorType == MONITOR_TYPE_VGA) // VGA ?
|
|
{
|
|
nvram[NVRAM_VMODE1] &= ~0x01; // No doublescan
|
|
nvram[NVRAM_VMODE2] |= 0x10; // VGA mode
|
|
nvram[NVRAM_VMODE2] &= ~0x20; // 60 Hz
|
|
}
|
|
else
|
|
{
|
|
nvram[NVRAM_VMODE1] |= 0x01; // Interlaced
|
|
nvram[NVRAM_VMODE2] &= ~0x10; // TV/RGB mode
|
|
nvram[NVRAM_VMODE2] |= 0x20; // 50 Hz
|
|
}
|
|
NvRam_SetChecksum();
|
|
}
|
|
|
|
NvRam_Reset();
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* De-Initialization
|
|
*/
|
|
void NvRam_UnInit(void)
|
|
{
|
|
NvRam_Save(); // save NVRAM file upon exit automatically (should be conditionalized)
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* Read from RTC/NVRAM offset selection register ($ff8961)
|
|
*/
|
|
void NvRam_Select_ReadByte(void)
|
|
{
|
|
IoMem_WriteByte(0xff8961, nvram_index);
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* Write to RTC/NVRAM offset selection register ($ff8961)
|
|
*/
|
|
void NvRam_Select_WriteByte(void)
|
|
{
|
|
Uint8 value = IoMem_ReadByte(0xff8961);
|
|
|
|
if (value < sizeof(nvram))
|
|
{
|
|
nvram_index = value;
|
|
}
|
|
else
|
|
{
|
|
Log_Printf(LOG_WARN, "NVRAM: trying to set out-of-bound position (%d)\n", value);
|
|
}
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* Read from RTC/NVRAM data register ($ff8963)
|
|
*/
|
|
void NvRam_Data_ReadByte(void)
|
|
{
|
|
Uint8 value = 0;
|
|
|
|
if (nvram_index == NVRAM_SECONDS || nvram_index == NVRAM_MINUTES || nvram_index == NVRAM_HOURS
|
|
|| (nvram_index >=NVRAM_DAY && nvram_index <=NVRAM_YEAR) )
|
|
{
|
|
/* access to RTC? - then read host clock and return its values */
|
|
time_t tim = time(NULL);
|
|
struct tm *curtim = localtime(&tim); /* current time */
|
|
switch(nvram_index)
|
|
{
|
|
case NVRAM_SECONDS: value = curtim->tm_sec; break;
|
|
case NVRAM_MINUTES: value = curtim->tm_min; break;
|
|
case NVRAM_HOURS: value = curtim->tm_hour; break;
|
|
case NVRAM_DAY: value = curtim->tm_mday; break;
|
|
case NVRAM_MONTH: value = curtim->tm_mon+1; break;
|
|
case NVRAM_YEAR: value = curtim->tm_year - 68; break;
|
|
}
|
|
}
|
|
else if (nvram_index == 10)
|
|
{
|
|
static bool rtc_uip = true;
|
|
value = rtc_uip ? 0x80 : 0;
|
|
rtc_uip = !rtc_uip;
|
|
}
|
|
else if (nvram_index == 13)
|
|
{
|
|
value = 0x80; // Valid RAM and Time bit
|
|
}
|
|
else if (nvram_index < 14)
|
|
{
|
|
Log_Printf(LOG_DEBUG, "Read from unsupported RTC/NVRAM register 0x%x.\n", nvram_index);
|
|
value = nvram[nvram_index];
|
|
}
|
|
else
|
|
{
|
|
value = nvram[nvram_index];
|
|
}
|
|
|
|
LOG_TRACE(TRACE_NVRAM, "NVRAM: read data at %d = %d ($%02x)\n", nvram_index, value, value);
|
|
IoMem_WriteByte(0xff8963, value);
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/**
|
|
* Write to RTC/NVRAM data register ($ff8963)
|
|
*/
|
|
|
|
void NvRam_Data_WriteByte(void)
|
|
{
|
|
Uint8 value = IoMem_ReadByte(0xff8963);
|
|
LOG_TRACE(TRACE_NVRAM, "NVRAM: write data at %d = %d ($%02x)\n", nvram_index, value, value);
|
|
nvram[nvram_index] = value;
|
|
}
|