/* 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 ); } */