From 08afdfe6569d4a67a13c69a72c6acd58f81269d9 Mon Sep 17 00:00:00 2001 From: mpohoreski Date: Thu, 4 Sep 2008 16:32:21 +0000 Subject: [PATCH] Custom No Slot and Thunderclock WIP --- AppleWin/source/Peripheral_Clock_Generic.cpp | 119 +++++++++ AppleWin/source/Peripheral_Clock_Generic.h | 5 + .../Peripheral_Clock_ThunderClockPlus.cpp | 240 ++++++++++++++++++ 3 files changed, 364 insertions(+) create mode 100644 AppleWin/source/Peripheral_Clock_Generic.cpp create mode 100644 AppleWin/source/Peripheral_Clock_Generic.h create mode 100644 AppleWin/source/Peripheral_Clock_ThunderClockPlus.cpp diff --git a/AppleWin/source/Peripheral_Clock_Generic.cpp b/AppleWin/source/Peripheral_Clock_Generic.cpp new file mode 100644 index 00000000..40292b44 --- /dev/null +++ b/AppleWin/source/Peripheral_Clock_Generic.cpp @@ -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 + +/* + +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 +} diff --git a/AppleWin/source/Peripheral_Clock_Generic.h b/AppleWin/source/Peripheral_Clock_Generic.h new file mode 100644 index 00000000..4a1457de --- /dev/null +++ b/AppleWin/source/Peripheral_Clock_Generic.h @@ -0,0 +1,5 @@ +// Util +tm* Clock_Util_GetTime(); +void Clock_Util_ConvertTimeToProdos( tm *pTime, unsigned char *pProdosBytes4_ ); + +void Clock_Generic_UpdateProDos(); diff --git a/AppleWin/source/Peripheral_Clock_ThunderClockPlus.cpp b/AppleWin/source/Peripheral_Clock_ThunderClockPlus.cpp new file mode 100644 index 00000000..e4c91dbe --- /dev/null +++ b/AppleWin/source/Peripheral_Clock_ThunderClockPlus.cpp @@ -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 + +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 ); +} + +*/