mirror of
https://github.com/AppleWin/AppleWin.git
synced 2024-12-25 14:31:01 +00:00
Custom No Slot and Thunderclock WIP
This commit is contained in:
parent
00bfa5b2ab
commit
1482abe1b4
119
source/Peripheral_Clock_Generic.cpp
Normal file
119
source/Peripheral_Clock_Generic.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 2008, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin 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.
|
||||||
|
|
||||||
|
AppleWin 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 AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: Generic No-Slot Clock
|
||||||
|
*
|
||||||
|
* Author: Michael Pohoreski
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#pragma hdrstop
|
||||||
|
#include "..\resource\resource.h"
|
||||||
|
// #include "resource.h" // BUG -- wrong resource!!!
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Old:
|
||||||
|
|
||||||
|
File: PRODOS
|
||||||
|
BLOAD PRODOS,TSYS,A$2000
|
||||||
|
CALL-151
|
||||||
|
2F76:60 5F 5E 5D 5C 5C 60
|
||||||
|
File offset $0F76-$0F7C:
|
||||||
|
|
||||||
|
|
||||||
|
ProDOS has a built-in clock driver that queries a clock/calendar card for the date and time. After the routine stores that information in the ProDOS Global Page ($BF90-$BF93), either ProDOS or your own application programs can use it. See Figure 6-1.
|
||||||
|
|
||||||
|
Figure 6-1. ProDOS Date and Time Locations
|
||||||
|
|
||||||
|
49041 ($BF91) 49040 ($BF90)
|
||||||
|
|
||||||
|
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
||||||
|
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
||||||
|
DATE: | year | month | day |
|
||||||
|
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
||||||
|
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
||||||
|
TIME: | hour | | minute |
|
||||||
|
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
49043 ($BF93) 49042 ($BF92)
|
||||||
|
|
||||||
|
|
||||||
|
ProDOS recognizes a clock card if the following bytes are present in
|
||||||
|
the Cn00 ROM:
|
||||||
|
|
||||||
|
$Cn00 = $08
|
||||||
|
$Cn02 = $28
|
||||||
|
$Cn04 = $58
|
||||||
|
$Cn06 = $70
|
||||||
|
|
||||||
|
The address is preceded by a $4C (JMP) if a clock card is recognized,
|
||||||
|
or by a $60 (RTS) if not.
|
||||||
|
|
||||||
|
The ProDOS clock driver uses the following addresses for its I/O to the
|
||||||
|
clock:
|
||||||
|
|
||||||
|
Cn08 - READ entry point
|
||||||
|
Cn0B - WRITE entry point
|
||||||
|
|
||||||
|
The accumulator is loaded with an #A3 before the JSR to the WRITE
|
||||||
|
*/
|
||||||
|
|
||||||
|
tm* Clock_Util_GetTime()
|
||||||
|
{
|
||||||
|
time_t tRawTime;
|
||||||
|
time( &tRawTime );
|
||||||
|
|
||||||
|
tm* pTime = localtime ( &tRawTime );
|
||||||
|
if( pTime ) {
|
||||||
|
mktime( pTime ); // get day of week: tm_wday
|
||||||
|
}
|
||||||
|
return pTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clock_Util_ConvertTimeToProdos( tm *pTime, unsigned char *pProDosBytes4_ )
|
||||||
|
{
|
||||||
|
if( pTime )
|
||||||
|
{
|
||||||
|
BYTE nMonth = pTime->tm_mon + 1;
|
||||||
|
|
||||||
|
BYTE nDate1 = 0
|
||||||
|
| ((pTime->tm_mday & 0x1F) << 0)
|
||||||
|
| ((nMonth & 0x0F) << 5);
|
||||||
|
BYTE nDate2 = 0
|
||||||
|
| ((pTime->tm_year % 100) << 1)
|
||||||
|
| (nMonth >> 3) & 1;
|
||||||
|
BYTE nTime1 = (pTime->tm_min & 0x3F); // 60 = max(64) 0x3F
|
||||||
|
BYTE nTime2 = (pTime->tm_hour & 0x1F); // 24 = max(32) 0x1F
|
||||||
|
pProDosBytes4_[0] = nDate1;
|
||||||
|
pProDosBytes4_[1] = nDate2;
|
||||||
|
pProDosBytes4_[2] = nTime1;
|
||||||
|
pProDosBytes4_[3] = nTime2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clock_Generic_UpdateProDos()
|
||||||
|
{
|
||||||
|
tm* pTime = Clock_Util_GetTime();
|
||||||
|
Clock_Util_ConvertTimeToProdos( pTime, &mem[ 0xBF90 ] ); // ProDos date/time buffer
|
||||||
|
}
|
5
source/Peripheral_Clock_Generic.h
Normal file
5
source/Peripheral_Clock_Generic.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// Util
|
||||||
|
tm* Clock_Util_GetTime();
|
||||||
|
void Clock_Util_ConvertTimeToProdos( tm *pTime, unsigned char *pProdosBytes4_ );
|
||||||
|
|
||||||
|
void Clock_Generic_UpdateProDos();
|
240
source/Peripheral_Clock_ThunderClockPlus.cpp
Normal file
240
source/Peripheral_Clock_ThunderClockPlus.cpp
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 2008, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin 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.
|
||||||
|
|
||||||
|
AppleWin 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 AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: Thunderware ThunderClock+
|
||||||
|
*
|
||||||
|
* Author: Michael Pohoreski
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#pragma hdrstop
|
||||||
|
#include "..\resource\resource.h"
|
||||||
|
// #include "resource.h" // BUG -- wrong resource!!!
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
void LoadRom_Clock_ThunderClockPlus(LPBYTE pCxRomPeripheral, UINT uSlot);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
static BYTE __stdcall Clock_Generic_Read_C0(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft);
|
||||||
|
static BYTE __stdcall Clock_Generic_Write_C0(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft);
|
||||||
|
static BYTE __stdcall Clock_Generic_Read_CX(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft);
|
||||||
|
static BYTE __stdcall Clock_Generic_Write_CX(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft);
|
||||||
|
|
||||||
|
UINT g_uClockInSlot4 = CT_GenericClock;
|
||||||
|
BYTE *g_pGenericClockFirmware = NULL;
|
||||||
|
|
||||||
|
enum ClockCommandEnum
|
||||||
|
{
|
||||||
|
CC_READ = 0x18
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ClockLatchEnum
|
||||||
|
{
|
||||||
|
CL_SEC_0X,
|
||||||
|
CL_SEC_X0,
|
||||||
|
CL_MINS_0X,
|
||||||
|
CL_MINS_X0,
|
||||||
|
CL_HOURS_0X,
|
||||||
|
CL_HOURS_X0,
|
||||||
|
CL_DAY_0X,
|
||||||
|
CL_DAY_X0,
|
||||||
|
CL_DOW_0X,
|
||||||
|
CL_DOW_X0,
|
||||||
|
CL_MONTH
|
||||||
|
};
|
||||||
|
|
||||||
|
int iClockCommand = 0;
|
||||||
|
int iClockLatch = 0;
|
||||||
|
int iClockStrobe = 0;
|
||||||
|
int iClockBit = 0;
|
||||||
|
|
||||||
|
BYTE iClockOutByte = 0;
|
||||||
|
|
||||||
|
static BYTE __stdcall Clock_Generic_Read_C0(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft)
|
||||||
|
{
|
||||||
|
BYTE nOutput = 0;
|
||||||
|
{
|
||||||
|
|
||||||
|
// BCD
|
||||||
|
static int y = 0x2013;
|
||||||
|
static int d = 4; // min
|
||||||
|
static int n = 5;
|
||||||
|
static int w = 6;
|
||||||
|
static int h = 7;
|
||||||
|
static int m = 8;
|
||||||
|
static int s = 9;
|
||||||
|
// int nDOW = pLocalTime->tm_wday + 1;
|
||||||
|
|
||||||
|
switch( iClockLatch )
|
||||||
|
{
|
||||||
|
case CL_MONTH:
|
||||||
|
// nOutput = (pLocalTime->tm_mon << (7 + iClockBit)) & 0x80;
|
||||||
|
nOutput = ((n >> 0) & 0xF) << (7 + iClockBit);
|
||||||
|
break;
|
||||||
|
case CL_DOW_X0:
|
||||||
|
nOutput = ((w >> 4) & 0xF) << (7 + iClockBit);
|
||||||
|
break;
|
||||||
|
case CL_DOW_0X:
|
||||||
|
nOutput = ((w >> 0) & 0xF) << (7 + iClockBit);
|
||||||
|
break;
|
||||||
|
case CL_DAY_X0:
|
||||||
|
nOutput = ((d >> 4) & 0xF) << (7 + iClockBit);
|
||||||
|
break;
|
||||||
|
case CL_DAY_0X:
|
||||||
|
nOutput = ((d >> 0) & 0xF) << (7 + iClockBit);
|
||||||
|
break;
|
||||||
|
case CL_HOURS_X0:
|
||||||
|
nOutput = ((h >> 4) & 0xF) << (7 + iClockBit);
|
||||||
|
break;
|
||||||
|
case CL_HOURS_0X:
|
||||||
|
nOutput = ((h >> 0) & 0xF) << (7 + iClockBit);
|
||||||
|
break;
|
||||||
|
case CL_MINS_X0:
|
||||||
|
nOutput = ((m >> 4) & 0xF) << (7 + iClockBit);
|
||||||
|
break;
|
||||||
|
case CL_MINS_0X:
|
||||||
|
nOutput = ((m >> 0) & 0xF) << (7 + iClockBit);
|
||||||
|
break;
|
||||||
|
case CL_SEC_X0:
|
||||||
|
nOutput = ((s >> 4) & 0xF) << (7 + iClockBit);
|
||||||
|
break;
|
||||||
|
case CL_SEC_0X:
|
||||||
|
nOutput = ((s >> 0) & 0xF) << (7 + iClockBit);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// nOutput = 0xFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
char sText[ 128 ];
|
||||||
|
sprintf( sText, " Read [%d] (%d) = %02X\n", iClockLatch, iClockBit, nOutput );
|
||||||
|
OutputDebugString( sText );
|
||||||
|
|
||||||
|
return nOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BYTE __stdcall Clock_Generic_Write_C0(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft)
|
||||||
|
{
|
||||||
|
int iSlot = (nAddr >> 12) - 0x8;
|
||||||
|
|
||||||
|
if( iSlot > 0 )
|
||||||
|
{
|
||||||
|
if( nValue & 0x02)
|
||||||
|
{
|
||||||
|
iClockBit++;
|
||||||
|
if( iClockBit >= 4 )
|
||||||
|
{
|
||||||
|
iClockBit = 0;
|
||||||
|
iClockLatch++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( nAddr & 0x0F )
|
||||||
|
{
|
||||||
|
case 0x00: // set time format
|
||||||
|
if( nValue == CC_READ )
|
||||||
|
{
|
||||||
|
iClockCommand = nValue;
|
||||||
|
iClockLatch = 0;
|
||||||
|
iClockBit = 0;
|
||||||
|
}
|
||||||
|
// 0x18 = Time Read
|
||||||
|
// get 10 nibbles
|
||||||
|
// 0x1C =
|
||||||
|
// 0x18
|
||||||
|
// 0x04
|
||||||
|
// 0x0C
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char sText[ 128 ];
|
||||||
|
sprintf( sText, " Write: $%04X: %02X Clock: %s Strobe: %s\n"
|
||||||
|
, nAddr, nValue
|
||||||
|
, (nValue & 0x02)
|
||||||
|
? "Raise "
|
||||||
|
: "Drop "
|
||||||
|
, (nValue & 0x04)
|
||||||
|
? "On "
|
||||||
|
: "off"
|
||||||
|
);
|
||||||
|
OutputDebugString( sText );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BYTE __stdcall Clock_Generic_Read_CX(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
// Chain to default...
|
||||||
|
}
|
||||||
|
|
||||||
|
static BYTE __stdcall Clock_Generic_Write_CX(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
// Chain to default...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LoadRom_Clock_ThunderClockPlus(LPBYTE pCxRomPeripheral, UINT uSlot)
|
||||||
|
{
|
||||||
|
HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_THUNDERCLOCKPLUS_FW), "FIRMWARE");
|
||||||
|
if(hResInfo == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DWORD dwResSize = SizeofResource(NULL, hResInfo);
|
||||||
|
if(dwResSize != FIRMWARE_EXPANSION_SIZE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
HGLOBAL hResData = LoadResource(NULL, hResInfo);
|
||||||
|
if(hResData == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BYTE* pData = (BYTE*) LockResource(hResData); // NB. Don't need to unlock resource
|
||||||
|
if(pData == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Slot ROM is a mirror of the 1st page of the firmware
|
||||||
|
memcpy(pCxRomPeripheral + uSlot*256, pData, APPLE_SLOT_SIZE);
|
||||||
|
|
||||||
|
#if _DEBUG
|
||||||
|
if (pCxRomPeripheral[ uSlot*256 + 0 ] != 0x08)
|
||||||
|
MessageBox( NULL, "Bad ThunderClock ROM: 1st byte", NULL, MB_OK );
|
||||||
|
if (pCxRomPeripheral[ uSlot*256 + 2 ] != 0x28)
|
||||||
|
MessageBox( NULL, "Bad ThunderClock ROM: 2nd byte", NULL, MB_OK );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( !g_pGenericClockFirmware )
|
||||||
|
{
|
||||||
|
g_pGenericClockFirmware = new BYTE [FIRMWARE_EXPANSION_SIZE];
|
||||||
|
|
||||||
|
if (g_pGenericClockFirmware)
|
||||||
|
memcpy(g_pGenericClockFirmware, pData, FIRMWARE_EXPANSION_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterIoHandler( uSlot, &Clock_Generic_Read_C0, &Clock_Generic_Write_C0, Clock_Generic_Read_CX, Clock_Generic_Write_CX, NULL, g_pGenericClockFirmware );
|
||||||
|
RegisterIoHandler( uSlot, &Clock_Generic_Read_C0, &Clock_Generic_Write_C0, NULL, NULL, NULL, g_pGenericClockFirmware );
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
Loading…
Reference in New Issue
Block a user