/* -*- mode: C++; tab-width: 4 -*- */ /* ===================================================================== *\ Copyright (c) 2000-2001 Palm, Inc. or its subsidiaries. All rights reserved. This file is part of the Palm OS Emulator. 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. \* ===================================================================== */ #include "EmCommon.h" #include "EmRegsVZ.h" #include "EmRegsVZPrv.h" #include "Byteswapping.h" // Canonical #include "EmDevice.h" #include "EmHAL.h" // EmHAL #include "EmMemory.h" // gMemAccessFlags, EmMem_memcpy #include "EmPixMap.h" // SetSize, SetRowBytes, etc. #include "EmScreen.h" // EmScreenUpdateInfo #include "EmSession.h" // gSession #include "EmSPISlave.h" // DoExchange #include "Hordes.h" // Hordes::IsOn #include "Logging.h" // LogAppendMsg #include "Miscellaneous.h" // GetHostTime #include "PreferenceMgr.h" // Preference #include "SessionFile.h" // WriteHwrDBallVZType, etc. #include "UAE.h" // regs, SPCFLAG_INT #include "PalmPack.h" #define NON_PORTABLE #include "HwrMiscFlags.h" // hwrMiscFlagID1 // Some platform-specific -- yet fairly portable -- defines. #define hwrVZPortDKbdCol0 0x01 // (H) Keyboard Column 0 (aka INT0) #define hwrVZPortDKbdCol1 0x02 // (H) Keyboard Column 1 (aka INT1) #define hwrVZPortDKbdCol2 0x04 // (H) Keyboard Column 2 (aka INT2) #define hwrVZPortDKbdCol3 0x08 // (H) Keyboard Column 3 (aka INT3) #define hwrVZPortDKeyBits 0x0F // All Keyboard Columns #undef NON_PORTABLE #include "PalmPackPop.h" static const uint16 UPSIZMask = 0x1800; // Mask to get the unprotected memory size from csDSelect. static const uint16 DRAMMask = 0x0200; static const uint16 SIZMask = 0x000E; // Mask to get the memory size from csASelect. static const uint16 ENMask = 0x0001; // Mask to get the enable bit from csASelect. static const int UPSIZShift = 11; static const int SIZShift = 1; static const int ENShift = 0; static const uint16 BUPS2Mask = 0x0001; static const uint16 CUPS2Mask = 0x0004; static const uint16 DUPS2Mask = 0x0010; static const uint16 DSIZ3Mask = 0x0040; static const uint16 EUPENMask = 0x4000; static const int BUPS2Shift = 0; static const int CUPS2Shift = 2; static const int DUPS2Shift = 4; static const int kBaseAddressShift = 13; // Shift to get base address from CSGBx register value #define PRINTF if (1) ; else LogAppendMsg // Values used to initialize the DragonBallVZ registers. static const HwrM68VZ328Type kInitial68VZ328RegisterValues = { 0x1C, // UInt8 scr; // $000: System Control Register { 0 }, // UInt8 ___filler0[0x003-0x001]; 0x00, // UInt8 pcr; // $003: Peripheral Control Register 0x56, // UInt8 chipID; // $004: Chip ID Register 0x01, // UInt8 maskID; // $005: Mask ID Register 0x0000, // UInt16 swID; // $006: Software ID Register 0x1FFF, // UInt16 ioDriveControl; // $008: I/O Drive Control Register { 0 }, // UInt8 ___filler1[0x100-0x00A]; 0x0000, // UInt16 csAGroupBase; // $100: Chip Select Group A Base Register 0x0000, // UInt16 csBGroupBase; // $102: Chip Select Group B Base Register 0x0000, // UInt16 csCGroupBase; // $104: Chip Select Group C Base Register 0x0000, // UInt16 csDGroupBase; // $106: Chip Select Group D Base Register 0x0000, // UInt16 csUGroupBase; // $108: Chip Select Upper Group Base Register 0x0000, // UInt16 csControl1; // $10A: Chip Select Control Register 0x0000, // UInt16 csControl2; // $10C: Chip Select Control Register { 0 }, // UInt8 ___filler2[0x110-0x10c]; 0x00B0, // UInt16 csASelect; // $110: Group A Chip Select Register 0x0000, // UInt16 csBSelect; // $112: Group B Chip Select Register 0x0000, // UInt16 csCSelect; // $114: Group C Chip Select Register 0x0200, // UInt16 csDSelect; // $116: Group D Chip Select Register 0x0060, // UInt16 emuCS; // $118: EMU Chip Select Register { 0 }, // UInt8 ___filler3[0x200-0x11A]; 0x0000, // UInt16 csControl3; // $150: Chip Select Control Register { 0 }, // UInt8 ___filler3[0x200-0x11A]; 0x24B3, // UInt16 pllControl; // $200: PLL Control Register 0x0123, // UInt16 pllFreqSel; // $202: CGM Frequency Select Register { 0 }, // UInt8 ___filler4[0x207-0x204]; 0x1F, // UInt8 pwrControl; // $207: Power Control Register { 0 }, // UInt8 ___filler5[0x300-0x208]; 0x00, // UInt8 intVector; // $300: Interrupt Vector Register 0x00, // UInt8 ___filler6; 0x0000, // UInt16 intControl; // $302: Interrupt Control Register 0x00FF, // UInt16 intMaskHi; // $304: Interrupt Mask Register/HIGH word 0xFFFF, // UInt16 intMaskLo; // $306: Interrupt Mask Register/LOW word { 0 }, // UInt8 ___filler7[0x30c-0x308]; 0x0000, // UInt16 intStatusHi; // $30C: Interrupt Status Register/HIGH word 0x0000, // UInt16 intStatusLo; // $30E: Interrupt Status Register/LOW word 0x0000, // UInt16 intPendingHi; // $310: Interrupt Pending Register/HIGH word 0x0000, // UInt16 intPendingLo; // $312: Interrupt Pending Register/LOW word 0x6533, // UInt16 intLevelControl; // $314: Interrupt Level Control Register { 0 }, // UInt8 ___filler4a[0x400-0x316]; 0x00, // UInt8 portADir; // $400: Port A Direction Register 0x00, // UInt8 portAData; // $401: Port A Data Register 0xFF, // UInt8 portAPullupEn; // $402: Port A Pullup Enable { 0 }, // UInt8 ___filler8[5]; 0x00, // UInt8 portBDir; // $408: Port B Direction Register 0x00, // UInt8 portBData; // $409: Port B Data Register 0xFF, // UInt8 portBPullupEn; // $40A: Port B Pullup Enable 0xFF, // UInt8 portBSelect; // $40B: Port B Select Register { 0 }, // UInt8 ___filler9[4]; 0x00, // UInt8 portCDir; // $410: Port C Direction Register 0x00, // UInt8 portCData; // $411: Port C Data Register 0xFF, // UInt8 portCPulldnEn; // $412: Port C Pulldown Enable 0xFF, // UInt8 portCSelect; // $413: Port C Select Register { 0 }, // UInt8 ___filler10[4]; 0x00, // UInt8 portDDir; // $418: Port D Direction Register 0x00, // UInt8 portDData; // $419: Port D Data Register 0xFF, // UInt8 portDPullupEn; // $41A: Port D Pull-up Enable 0xFF, // UInt8 portDSelect; // $41B: Port D Select Register 0x00, // UInt8 portDPolarity; // $41C: Port D Polarity Register 0x00, // UInt8 portDIntReqEn; // $41D: Port D Interrupt Request Enable 0x00, // UInt8 portDKbdIntEn; // $41E: Port D Keyboard Interrupt Enable 0x00, // UInt8 portDIntEdge; // $41F: Port D IRQ Edge Register 0x00, // UInt8 portEDir; // $420: Port E Direction Register 0x00, // UInt8 portEData; // $421: Port E Data Register 0xFF, // UInt8 portEPullupEn; // $422: Port E Pull-up Enable 0xFF, // UInt8 portESelect; // $423: Port E Select Register { 0 }, // UInt8 ___filler14[4]; 0x00, // UInt8 portFDir; // $428: Port F Direction Register 0x00, // UInt8 portFData; // $429: Port F Data Register 0xFF, // UInt8 portFPullupdnEn; // $42A: Port F Pull-up/down Enable 0x8F, // UInt8 portFSelect; // $42B: Port F Select Register { 0 }, // UInt8 ___filler16[4]; 0x00, // UInt8 portGDir; // $430: Port G Direction Register 0x00, // UInt8 portGData; // $431: Port G Data Register 0x3D, // UInt8 portGPullupEn; // $432: Port G Pull-up Enable 0x08, // UInt8 portGSelect; // $433: Port G Select Register { 0 }, // UInt8 ___filler17[0x438-0x434]; 0x00, // UInt8 portJDir; // $438: Port J Direction Register 0x00, // UInt8 portJData; // $439: Port J Data Register 0xFF, // UInt8 portJPullupEn; // $43A: Port J Pull-up Enable 0xEF, // UInt8 portJSelect; // $43B: Port J Select Register { 0 }, // UInt8 ___filler18[0x440-0x43C]; 0x00, // UInt8 portKDir; // $440: Port K Direction Register 0x00, // UInt8 portKData; // $441: Port K Data Register 0xFF, // UInt8 portKPullupdnEn; // $442: Port K Pull-up/down Enable 0xFF, // UInt8 portKSelect; // $443: Port K Select Register { 0 }, // UInt8 ___filler19[0x448-0x444]; 0x00, // UInt8 portMDir; // $448: Port M Direction Register 0x00, // UInt8 portMData; // $449: Port M Data Register 0x3F, // UInt8 portMPullupdnEn; // $44A: Port M Pull-up/down Enable 0x3F, // UInt8 portMSelect; // $44B: Port M Select Register { 0 }, // UInt8 ___filler20[0x500-0x44C]; 0x0020, // UInt16 pwmControl; // $500: PWM 1 Control Register (PWM 1 is the same as the single PWM in EZ) 0x00, // UInt8 pwmSampleHi; // $502: PWM 1 Sample - high byte 0x00, // UInt8 pwmSampleLo; // $503: PWM 1 Sample - low byte 0xFE, // UInt8 pwmPeriod; // $504: PWM 1 Period 0x00, // UInt8 pwmCounter; // $505: PWM 1 Counter { 0 }, // UInt8 ___filler22[0x510-0x506]; 0x0000, // UInt16 pwm2Control; // $510: PWM 2 Control Register 0x0000, // UInt16 pwm2Period; // $512: PWM 2 Period 0x0000, // UInt16 pwm2Width; // $514: PWM 2 Width 0x0000, // UInt16 pwm2Counter; // $516: PWM 2 Counter { 0 }, // UInt8 ___filler23[0x600-0x518]; 0x0000, // UInt16 tmr1Control; // $600: Timer 1 Control Register 0x0000, // UInt16 tmr1Prescaler; // $602: Timer 1 Prescaler Register 0xFFFF, // UInt16 tmr1Compare; // $604: Timer 1 Compare Register 0x0000, // UInt16 tmr1Capture; // $606: Timer 1 Capture Register 0x0000, // UInt16 tmr1Counter; // $608: Timer 1 Counter Register 0x0000, // UInt16 tmr1Status; // $60A: Timer 1 Status Register { 0 }, // UInt8 ___filler24[0x610-0x60C]; 0x0000, // UInt16 tmr2Control; // $610: Timer 2 Control Register 0x0000, // UInt16 tmr2Prescaler; // $612: Timer 2 Prescaler Register 0xFFFF, // UInt16 tmr2Compare; // $614: Timer 2 Compare Register 0x0000, // UInt16 tmr2Capture; // $616: Timer 2 Capture Register 0x0000, // UInt16 tmr2Counter; // $618: Timer 2 Counter Register 0x0000, // UInt16 tmr2Status; // $61A: Timer 2 Status Register { 0 }, // UInt8 ___filler25[0x700-0x61C]; 0x0000, // UInt16 spiRxD; // $700: SPI Unit 1 Receive Data Register 0x0000, // UInt16 spiTxD; // $702: SPI Unit 1 Transmit Data Register 0x0000, // UInt16 spiCont1; // $704: SPI Unit 1 Control/Status Register 0x0000, // UInt16 spiIntCS; // $706: SPI Unit 1 Interrupt control/Status Register 0x0000, // UInt16 spiTest; // $708: SPI Unit 1 Test Register 0x0000, // UInt16 spiSpc; // $70A: SPI Unit 1 Sample period counter register { 0 }, // UInt8 ___filler26[0x800-0x706]; 0x0000, // UInt16 spiMasterData; // $800: SPI Unit 2 Data Register (SPI 2 is the same as the single SPI Master in EZ) 0x0000, // UInt16 spiMasterControl; // $802: SPI Unit 2 Control/Status Register { 0 }, // UInt8 ___filler27[0x900-0x804]; 0x0000, // UInt16 uControl; // $900: Uart 1 Status/Control Register (Uart 1 is the same as the single Uart in EZ) 0x003F, // UInt16 uBaud; // $902: Uart 1 Baud Control Register 0x0000, // UInt16 uReceive; // $904: Uart 1 Receive Register 0x0000, // UInt16 uTransmit; // $906: Uart 1 Transmit Register 0x0000, // UInt16 uMisc; // $908: Uart 1 Miscellaneous Register 0x0000, // UInt16 uNonIntPresc; // $90A: Uart 1 Non-Integer Prescaler { 0 }, // UInt8 ___filler28[0x910-0x90C]; 0x0000, // UInt16 u2Control; // $910: Uart 2 Status/Control Register 0x003F, // UInt16 u2Baud; // $912: Uart 2 Baud Control Register 0x0000, // UInt16 u2Receive; // $914: Uart 2 Receiver Register 0x0000, // UInt16 u2Transmit; // $916: Uart 2 Transmitter Register 0x0000, // UInt16 u2Misc; // $918: Uart 2 Miscellaneous Register 0x0000, // UInt16 u2NonIntPresc; // $91A: Uart 2 Non-Integer Prescaler 0x0000, // UInt16 u2FIFOHMark; // $91C: Uart 2 Half Mark FIFO Register { 0 }, // UInt8 ___filler28a[0xA00-0x91E]; 0x00000000, // UInt32 lcdStartAddr; // $A00: Screen Starting Address Register { 0 }, // UInt8 ___filler29; 0xFF, // UInt8 lcdPageWidth; // $A05: Virtual Page Width Register { 0 }, // UInt8 ___filler30[2]; 0x03F0, // UInt16 lcdScreenWidth; // $A08: Screen Width Register 0x01FF, // UInt16 lcdScreenHeight; // $A0A: Screen Height Register { 0 }, // UInt8 ___filler31[0xA18-0xA0C]; 0x0000, // UInt16 lcdCursorXPos; // $A18: Cursor X Position 0x0000, // UInt16 lcdCursorYPos; // $A1A: Cursor Y Position 0x0101, // UInt16 lcdCursorWidthHeight; // $A1C: Cursor Width and Height { 0 }, // UInt8 ___filler32; 0x7F, // UInt8 lcdBlinkControl; // $A1F: Blink Control Register 0x00, // UInt8 lcdPanelControl; // $A20: Panel Interface Configuration Register 0x00, // UInt8 lcdPolarity; // $A21: Polarity Config Register { 0 }, // UInt8 ___filler33; 0x00, // UInt8 lcdACDRate; // $A23: ACD (M) Rate Control Register { 0 }, // UInt8 ___filler34; 0x00, // UInt8 lcdPixelClock; // $A25: Pixel Clock Divider Register { 0 }, // UInt8 ___filler35; 0x00, // UInt8 lcdClockControl; // $A27: Clocking Control Register 0x00FF, // UInt16 lcdRefreshRateAdj; // $A28: Refresh Rate Adjustment Register { 0 }, // UInt8 ___filler37; 0x00, // UInt8 lcdReserved1; // $A2B: Reserved { 0 }, // UInt8 ___filler38; 0x00, // UInt8 lcdPanningOffset; // $A2D: Panning Offset Register { 0 }, // UInt8 ___filler39[0xA31-0xA2E]; 0x00, // UInt8 lcdFrameRate; // $A31: Frame Rate Control Modulation Register { 0 }, // UInt8 ___filler2004; 0x84, // UInt8 lcdGrayPalette; // $A33: Gray Palette Mapping Register 0x00, // UInt8 lcdReserved2; // $A34: Reserved { 0 }, // UInt8 ___filler2005; 0x0000, // UInt16 lcdContrastControlPWM; // $A36: Contrast Control 0x00, // UInt8 lcdRefreshModeControl; // $A38: Refresh Mode Control Register 0x62, // UInt8 lcdDMAControl; // $A39: DMA Control Register { 0 }, // UInt8 ___filler40[0xB00-0xA3a]; 0x00000000, // UInt32 rtcHourMinSec; // $B00: RTC Hours, Minutes, Seconds Register 0x00000000, // UInt32 rtcAlarm; // $B04: RTC Alarm Register { 0 }, // UInt8 ___filler2001[0xB0A-0xB08]; 0x0001, // UInt16 rtcWatchDog; // $B0A: RTC Watchdog Timer 0x0080, // UInt16 rtcControl; // $B0C: RTC Control Register 0x0000, // UInt16 rtcIntStatus; // $B0E: RTC Interrupt Status Register 0x0000, // UInt16 rtcIntEnable; // $B10: RTC Interrupt Enable Register 0x003F, // UInt16 stopWatch; // $B12: Stopwatch Minutes { 0 }, // UInt8 ___filler2002[0xB1A-0xB14]; 0x0000, // UInt16 rtcDay; // $B1A: RTC Day 0x0000, // UInt16 rtcDayAlarm; // $B1C: RTC Day Alarm { 0 }, // UInt8 ___filler41[0xC00-0xB1E]; 0x0000, // UInt16 dramConfig; // $C00: DRAM Memory Config Register 0x003C, // UInt16 dramControl; // $C02: DRAM Control Register 0x0000, // UInt16 sdramControl; // $C04: SDRAM Control Register 0x0000, // UInt16 sdramPwDn; // $C06: SDRAM Power Down Register { 0 }, // UInt8 ___filler42[0xD00-0xC08]; 0x00000000, // UInt32 emuAddrCompare; // $D00: Emulation Address Compare Register 0x00000000, // UInt32 emuAddrMask; // $D04: Emulation Address Mask Register 0x0000, // UInt16 emuControlCompare; // $D08: Emulation Control Compare Register 0x0000, // UInt16 emuControlMask; // $D0A: Emulation Control Mask Register 0x0000, // UInt16 emuControl; // $DOC: Emulation Control Register 0x0000 // UInt16 emuStatus; // $D0E: Emulation Status Register }; // --------------------------------------------------------------------------- // ¥ EmRegsVZ::EmRegsVZ // --------------------------------------------------------------------------- EmRegsVZ::EmRegsVZ (void) : EmRegs (), f68VZ328Regs (), fHotSyncButtonDown (0), fKeyBits (0), fLastTmr1Status (0), fLastTmr2Status (0), fPortDEdge (0), fPortDDataCount (0), fHour (0), fMin (0), fSec (0), fTick (0), fCycle (0) { fUART[0] = NULL; fUART[1] = NULL; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::~EmRegsVZ // --------------------------------------------------------------------------- EmRegsVZ::~EmRegsVZ (void) { } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::Initialize // --------------------------------------------------------------------------- void EmRegsVZ::Initialize (void) { EmRegs::Initialize (); fUART[0] = new EmUARTDragonball (EmUARTDragonball::kUART_DragonballVZ, 0); fUART[1] = new EmUARTDragonball (EmUARTDragonball::kUART_DragonballVZ, 1); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::Reset // --------------------------------------------------------------------------- void EmRegsVZ::Reset (Bool hardwareReset) { EmRegs::Reset (hardwareReset); if (hardwareReset) { f68VZ328Regs = kInitial68VZ328RegisterValues; // Byteswap all the words in the DragonballVZ registers (if necessary). Canonical (f68VZ328Regs); ByteswapWords (&f68VZ328Regs, sizeof(f68VZ328Regs)); fKeyBits = 0; fLastTmr1Status = 0; fLastTmr2Status = 0; fPortDEdge = 0; fPortDDataCount = 0; // React to the new data in the UART registers. Bool sendTxData = false; EmRegsVZ::UARTStateChanged (sendTxData, 0); EmRegsVZ::UARTStateChanged (sendTxData, 1); } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::Save // --------------------------------------------------------------------------- void EmRegsVZ::Save (SessionFile& f) { EmRegs::Save (f); StWordSwapper swapper (&f68VZ328Regs, sizeof(f68VZ328Regs)); f.WriteHwrDBallVZType (f68VZ328Regs); f.FixBug (SessionFile::kBugByteswappedStructs); const long kCurrentVersion = 3; Chunk chunk; EmStreamChunk s (chunk); s << kCurrentVersion; s << fHotSyncButtonDown; s << fKeyBits; s << fLastTmr1Status; s << fLastTmr2Status; s << fPortDEdge; // Added in version 2. s << fHour; s << fMin; s << fSec; s << fTick; s << fCycle; // Added in version 3. s << fPortDDataCount; f.WriteDBallVZState (chunk); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::Load // --------------------------------------------------------------------------- void EmRegsVZ::Load (SessionFile& f) { EmRegs::Load (f); if (f.ReadHwrDBallVZType (f68VZ328Regs)) { // The Windows version of Poser 2.1d29 and earlier did not write // out structs in the correct format. The fields of the struct // were written out in Little-Endian format, not Big-Endian. To // address this problem, the bug has been fixed, and a new field // is added to the file format indicating that the bug has been // fixed. With the new field (the "bug bit"), Poser can identify // old files from new files and read them in accordingly. // // With the bug fixed, the .psf files should now be interchangeable // across platforms (modulo other bugs...). if (!f.IncludesBugFix (SessionFile::kBugByteswappedStructs)) { Canonical (f68VZ328Regs); } ByteswapWords (&f68VZ328Regs, sizeof(f68VZ328Regs)); // React to the new data in the UART registers. Bool sendTxData = false; EmRegsVZ::UARTStateChanged (sendTxData, 0); EmRegsVZ::UARTStateChanged (sendTxData, 1); // Reset gMemAccessFlags.fProtect_SRAMSet gMemAccessFlags.fProtect_SRAMSet = (READ_REGISTER (csDSelect) & 0x2000) != 0; } else { f.SetCanReload (false); } Chunk chunk; if (f.ReadDBallVZState (chunk)) { long version; EmStreamChunk s (chunk); s >> version; if (version >= 1) { s >> fHotSyncButtonDown; s >> fKeyBits; s >> fLastTmr1Status; s >> fLastTmr2Status; s >> fPortDEdge; } if (version >= 2) { s >> fHour; s >> fMin; s >> fSec; s >> fTick; s >> fCycle; } if (version >= 3) { s >> fPortDDataCount; } } else { f.SetCanReload (false); } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::Dispose // --------------------------------------------------------------------------- void EmRegsVZ::Dispose (void) { delete fUART[0]; fUART[0] = NULL; delete fUART[1]; fUART[1] = NULL; EmRegs::Dispose (); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::SetSubBankHandlers // --------------------------------------------------------------------------- void EmRegsVZ::SetSubBankHandlers (void) { // Install base handlers. EmRegs::SetSubBankHandlers (); // Now add standard/specialized handers for the defined registers. INSTALL_HANDLER (StdRead, StdWrite, scr); INSTALL_HANDLER (StdRead, StdWrite, pcr); INSTALL_HANDLER (StdRead, NullWrite, chipID); INSTALL_HANDLER (StdRead, NullWrite, maskID); INSTALL_HANDLER (StdRead, NullWrite, swID); INSTALL_HANDLER (StdRead, StdWrite, ioDriveControl); INSTALL_HANDLER (StdRead, StdWrite, csAGroupBase); INSTALL_HANDLER (StdRead, StdWrite, csBGroupBase); INSTALL_HANDLER (StdRead, StdWrite, csCGroupBase); INSTALL_HANDLER (StdRead, StdWrite, csDGroupBase); INSTALL_HANDLER (StdRead, StdWrite, csUGroupBase); INSTALL_HANDLER (StdRead, csControl1Write, csControl1); INSTALL_HANDLER (StdRead, StdWrite, csControl2); INSTALL_HANDLER (StdRead, StdWrite, csControl3); INSTALL_HANDLER (StdRead, csASelectWrite, csASelect); INSTALL_HANDLER (StdRead, StdWrite, csBSelect); INSTALL_HANDLER (StdRead, StdWrite, csCSelect); INSTALL_HANDLER (StdRead, csDSelectWrite, csDSelect); INSTALL_HANDLER (StdRead, StdWrite, emuCS); INSTALL_HANDLER (StdRead, StdWrite, pllControl); INSTALL_HANDLER (pllFreqSelRead, StdWrite, pllFreqSel); INSTALL_HANDLER (StdRead, StdWrite, pwrControl); INSTALL_HANDLER (StdRead, StdWrite, intVector); INSTALL_HANDLER (StdRead, StdWrite, intControl); INSTALL_HANDLER (StdRead, intMaskHiWrite, intMaskHi); INSTALL_HANDLER (StdRead, intMaskLoWrite, intMaskLo); INSTALL_HANDLER (StdRead, intStatusHiWrite, intStatusHi); INSTALL_HANDLER (StdRead, NullWrite, intStatusLo); INSTALL_HANDLER (StdRead, NullWrite, intPendingHi); INSTALL_HANDLER (StdRead, NullWrite, intPendingLo); INSTALL_HANDLER (StdRead, StdWrite, intLevelControl); INSTALL_HANDLER (StdRead, StdWrite, portADir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portAData); INSTALL_HANDLER (StdRead, StdWrite, portAPullupEn); INSTALL_HANDLER (StdRead, StdWrite, portBDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portBData); INSTALL_HANDLER (StdRead, StdWrite, portBPullupEn); INSTALL_HANDLER (StdRead, StdWrite, portBSelect); INSTALL_HANDLER (StdRead, StdWrite, portCDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portCData); INSTALL_HANDLER (StdRead, StdWrite, portCPulldnEn); INSTALL_HANDLER (StdRead, StdWrite, portCSelect); INSTALL_HANDLER (StdRead, StdWrite, portDDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portDData); INSTALL_HANDLER (StdRead, StdWrite, portDPullupEn); INSTALL_HANDLER (StdRead, StdWrite, portDSelect); INSTALL_HANDLER (StdRead, StdWrite, portDPolarity); INSTALL_HANDLER (StdRead, portDIntReqEnWrite, portDIntReqEn); INSTALL_HANDLER (StdRead, StdWrite, portDKbdIntEn); INSTALL_HANDLER (StdRead, StdWrite, portDIntEdge); INSTALL_HANDLER (StdRead, StdWrite, portEDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portEData); INSTALL_HANDLER (StdRead, StdWrite, portEPullupEn); INSTALL_HANDLER (StdRead, StdWrite, portESelect); INSTALL_HANDLER (StdRead, StdWrite, portFDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portFData); INSTALL_HANDLER (StdRead, StdWrite, portFPullupdnEn); INSTALL_HANDLER (StdRead, StdWrite, portFSelect); INSTALL_HANDLER (StdRead, StdWrite, portGDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portGData); INSTALL_HANDLER (StdRead, StdWrite, portGPullupEn); INSTALL_HANDLER (StdRead, StdWrite, portGSelect); INSTALL_HANDLER (StdRead, StdWrite, portJDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portJData); INSTALL_HANDLER (StdRead, StdWrite, portJPullupEn); INSTALL_HANDLER (StdRead, StdWrite, portJSelect); INSTALL_HANDLER (StdRead, StdWrite, portKDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portKData); INSTALL_HANDLER (StdRead, StdWrite, portKPullupdnEn); INSTALL_HANDLER (StdRead, StdWrite, portKSelect); INSTALL_HANDLER (StdRead, StdWrite, portMDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portMData); INSTALL_HANDLER (StdRead, StdWrite, portMPullupdnEn); INSTALL_HANDLER (StdRead, StdWrite, portMSelect); INSTALL_HANDLER (StdRead, StdWrite, pwmControl); INSTALL_HANDLER (StdRead, StdWrite, pwmSampleHi); INSTALL_HANDLER (StdRead, StdWrite, pwmSampleLo); INSTALL_HANDLER (StdRead, StdWrite, pwmPeriod); INSTALL_HANDLER (StdRead, NullWrite, pwmCounter); INSTALL_HANDLER (StdRead, StdWrite, pwm2Control); INSTALL_HANDLER (StdRead, StdWrite, pwm2Period); INSTALL_HANDLER (StdRead, StdWrite, pwm2Width); INSTALL_HANDLER (StdRead, NullWrite, pwm2Counter); INSTALL_HANDLER (StdRead, StdWrite, tmr1Control); INSTALL_HANDLER (StdRead, StdWrite, tmr1Prescaler); INSTALL_HANDLER (StdRead, StdWrite, tmr1Compare); INSTALL_HANDLER (StdRead, StdWrite, tmr1Capture); INSTALL_HANDLER (StdRead, NullWrite, tmr1Counter); INSTALL_HANDLER (tmr1StatusRead, tmr1StatusWrite, tmr1Status); INSTALL_HANDLER (StdRead, StdWrite, tmr2Control); INSTALL_HANDLER (StdRead, StdWrite, tmr2Prescaler); INSTALL_HANDLER (StdRead, StdWrite, tmr2Compare); INSTALL_HANDLER (StdRead, StdWrite, tmr2Capture); INSTALL_HANDLER (StdRead, NullWrite, tmr2Counter); INSTALL_HANDLER (tmr2StatusRead, tmr2StatusWrite, tmr2Status); INSTALL_HANDLER (StdRead, StdWrite, spiRxD); INSTALL_HANDLER (StdRead, StdWrite, spiTxD); INSTALL_HANDLER (StdRead, spiCont1Write, spiCont1); INSTALL_HANDLER (StdRead, StdWrite, spiIntCS); INSTALL_HANDLER (StdRead, StdWrite, spiTest); INSTALL_HANDLER (StdRead, StdWrite, spiSpc); INSTALL_HANDLER (StdRead, StdWrite, spiMasterData); INSTALL_HANDLER (StdRead, spiMasterControlWrite, spiMasterControl); INSTALL_HANDLER (uart1Read, uart1Write, uControl); INSTALL_HANDLER (uart1Read, uart1Write, uBaud); INSTALL_HANDLER (uart1Read, uart1Write, uReceive); INSTALL_HANDLER (uart1Read, uart1Write, uTransmit); INSTALL_HANDLER (uart1Read, uart1Write, uMisc); INSTALL_HANDLER (uart1Read, uart1Write, uNonIntPresc); INSTALL_HANDLER (uart2Read, uart2Write, u2Control); INSTALL_HANDLER (uart2Read, uart2Write, u2Baud); INSTALL_HANDLER (uart2Read, uart2Write, u2Receive); INSTALL_HANDLER (uart2Read, uart2Write, u2Transmit); INSTALL_HANDLER (uart2Read, uart2Write, u2Misc); INSTALL_HANDLER (uart2Read, uart2Write, u2NonIntPresc); INSTALL_HANDLER (uart2Read, uart2Write, u2FIFOHMark); INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdStartAddr); INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdPageWidth); INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdScreenWidth); INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdScreenHeight); INSTALL_HANDLER (StdRead, StdWrite, lcdCursorXPos); INSTALL_HANDLER (StdRead, StdWrite, lcdCursorYPos); INSTALL_HANDLER (StdRead, StdWrite, lcdCursorWidthHeight); INSTALL_HANDLER (StdRead, StdWrite, lcdBlinkControl); INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdPanelControl); INSTALL_HANDLER (StdRead, StdWrite, lcdPolarity); INSTALL_HANDLER (StdRead, StdWrite, lcdACDRate); INSTALL_HANDLER (StdRead, StdWrite, lcdPixelClock); INSTALL_HANDLER (StdRead, StdWrite, lcdClockControl); INSTALL_HANDLER (StdRead, StdWrite, lcdRefreshRateAdj); INSTALL_HANDLER (StdRead, StdWrite, lcdPanningOffset); INSTALL_HANDLER (StdRead, StdWrite, lcdFrameRate); INSTALL_HANDLER (StdRead, StdWrite, lcdGrayPalette); INSTALL_HANDLER (StdRead, StdWrite, lcdContrastControlPWM); INSTALL_HANDLER (StdRead, StdWrite, lcdRefreshModeControl); INSTALL_HANDLER (StdRead, StdWrite, lcdDMAControl); INSTALL_HANDLER (rtcHourMinSecRead, StdWrite, rtcHourMinSec); INSTALL_HANDLER (StdRead, StdWrite, rtcAlarm); INSTALL_HANDLER (StdRead, StdWrite, rtcWatchDog); INSTALL_HANDLER (StdRead, rtcControlWrite, rtcControl); INSTALL_HANDLER (StdRead, rtcIntStatusWrite, rtcIntStatus); INSTALL_HANDLER (StdRead, rtcIntEnableWrite, rtcIntEnable); INSTALL_HANDLER (StdRead, StdWrite, stopWatch); INSTALL_HANDLER (StdRead, StdWrite, rtcDay); INSTALL_HANDLER (StdRead, StdWrite, rtcDayAlarm); INSTALL_HANDLER (StdRead, StdWrite, dramConfig); INSTALL_HANDLER (StdRead, StdWrite, dramControl); INSTALL_HANDLER (StdRead, StdWrite, sdramControl); INSTALL_HANDLER (StdRead, StdWrite, sdramPwDn); INSTALL_HANDLER (StdRead, StdWrite, emuAddrCompare); INSTALL_HANDLER (StdRead, StdWrite, emuAddrMask); INSTALL_HANDLER (StdRead, StdWrite, emuControlCompare); INSTALL_HANDLER (StdRead, StdWrite, emuControlMask); INSTALL_HANDLER (StdRead, StdWrite, emuControl); INSTALL_HANDLER (StdRead, StdWrite, emuStatus); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetRealAddress // --------------------------------------------------------------------------- uint8* EmRegsVZ::GetRealAddress (emuptr address) { uint8* loc = ((uint8*) &f68VZ328Regs) + (address - kMemoryStart); return loc; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetAddressStart // --------------------------------------------------------------------------- emuptr EmRegsVZ::GetAddressStart (void) { return kMemoryStart; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetAddressRange // --------------------------------------------------------------------------- uint32 EmRegsVZ::GetAddressRange (void) { return kMemorySize; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::Cycle // --------------------------------------------------------------------------- // Handles periodic events that need to occur when the processor cycles (like // updating timer registers). This function is called in two places from // Emulator::Execute. Interestingly, the loop runs 3% FASTER if this function // is in its own separate function instead of being inline. void EmRegsVZ::Cycle (Bool sleeping) { #if _DEBUG #define increment 20 #else #define increment 4 #endif // ===== Handle Timer 1 ===== // Determine whether timer is enabled. if ((READ_REGISTER (tmr1Control) & hwrVZ328TmrControlEnable) != 0) { // If so, increment the timer. WRITE_REGISTER (tmr1Counter, READ_REGISTER (tmr1Counter) + (sleeping ? 1 : increment)); // Determine whether the timer has reached the specified count. if (sleeping || READ_REGISTER (tmr1Counter) > READ_REGISTER (tmr1Compare)) { // Flag the occurrence of the successful comparison. WRITE_REGISTER (tmr1Status, READ_REGISTER (tmr1Status) | hwrVZ328TmrStatusCompare); // If the Free Run/Restart flag is not set, clear the counter. if ((READ_REGISTER (tmr1Control) & hwrVZ328TmrControlFreeRun) == 0) { WRITE_REGISTER (tmr1Counter, 0); } // If the timer interrupt is enabled, post an interrupt. if ((READ_REGISTER (tmr1Control) & hwrVZ328TmrControlEnInterrupt) != 0) { WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) | hwrVZ328IntLoTimer); EmRegsVZ::UpdateInterrupts (); } } } // ===== Handle Timer 2 ===== // ===== (Same code, just the name have been changed) ===== // Determine whether timer is enabled. #if 1 if ((READ_REGISTER (tmr2Control) & hwrVZ328TmrControlEnable) != 0) { // Divide by the prescale amount. We do this by decrementing // a prescaler counter. Only when this counter reaches zero // do we increment the timer counter. static int prescaleCounter; if ((prescaleCounter -= (sleeping ? (increment * 1024) : increment)) <= 0) { prescaleCounter = READ_REGISTER (tmr2Prescaler) * 1024; // If so, increment the timer. WRITE_REGISTER (tmr2Counter, READ_REGISTER (tmr2Counter) + (sleeping ? 1 : increment)); // Determine whether the timer has reached the specified count. if (sleeping || READ_REGISTER (tmr2Counter) > READ_REGISTER (tmr2Compare)) { // Flag the occurrence of the successful comparison. WRITE_REGISTER (tmr2Status, READ_REGISTER (tmr2Status) | hwrVZ328TmrStatusCompare); // If the Free Run/Restart flag is not set, clear the counter. if ((READ_REGISTER (tmr2Control) & hwrVZ328TmrControlFreeRun) == 0) { WRITE_REGISTER (tmr2Counter, 0); } // If the timer interrupt is enabled, post an interrupt. if ((READ_REGISTER (tmr2Control) & hwrVZ328TmrControlEnInterrupt) != 0) { WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) | hwrVZ328IntLoTimer2); EmRegsVZ::UpdateInterrupts (); } } } } #endif // ===== Handle time increment (used when running Gremlins) ===== if ((fCycle += increment) > READ_REGISTER (tmr1Compare)) { fCycle = 0; if (++fTick >= 100) { fTick = 0; if (++fSec >= 60) { fSec = 0; if (++fMin >= 60) { fMin = 0; if (++fHour >= 24) { fHour = 0; } } } } } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::CycleSlowly // --------------------------------------------------------------------------- // Handles periodic events that need to occur when the processor cycles (like // updating timer registers). This function is called in two places from // Emulator::Execute. Interestingly, the loop runs 3% FASTER if this function // is in its own separate function instead of being inline. void EmRegsVZ::CycleSlowly (Bool sleeping) { UNUSED_PARAM(sleeping) // See if a hard button is pressed. EmAssert (gSession); if (gSession->HasButtonEvent ()) { EmButtonEvent event = gSession->GetButtonEvent (); if (event.fButton == kElement_CradleButton) { EmRegsVZ::HotSyncEvent (event.fButtonIsDown); } else { EmRegsVZ::ButtonEvent (event.fButton, event.fButtonIsDown); } } // See if there's anything new ("Put the data on the bus") EmRegsVZ::UpdateUARTState (false, 0); EmRegsVZ::UpdateUARTState (false, 1); // Check to see if the RTC alarm is ready to go off. First see // if the RTC is enabled, and that the alarm event isn't already // registered (the latter check is just an optimization). if ((READ_REGISTER (rtcIntEnable) & hwrVZ328RTCIntEnableAlarm) != 0 && (READ_REGISTER (rtcIntStatus) & hwrVZ328RTCIntStatusAlarm) == 0) { uint32 rtcAlarm = READ_REGISTER (rtcAlarm); long almHour = (rtcAlarm & hwrVZ328RTCAlarmHoursMask) >> hwrVZ328RTCAlarmHoursOffset; long almMin = (rtcAlarm & hwrVZ328RTCAlarmMinutesMask) >> hwrVZ328RTCAlarmMinutesOffset; long almSec = (rtcAlarm & hwrVZ328RTCAlarmSecondsMask) >> hwrVZ328RTCAlarmSecondsOffset; long almInSeconds = (almHour * 60 * 60) + (almMin * 60) + almSec; long nowHour; long nowMin; long nowSec; ::GetHostTime (&nowHour, &nowMin, &nowSec); long nowInSeconds = (nowHour * 60 * 60) + (nowMin * 60) + nowSec; if (almInSeconds <= nowInSeconds) { WRITE_REGISTER (rtcIntStatus, READ_REGISTER (rtcIntStatus) | hwrVZ328RTCIntStatusAlarm); EmRegsVZ::UpdateRTCInterrupts (); } } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::TurnSoundOff // --------------------------------------------------------------------------- void EmRegsVZ::TurnSoundOff (void) { uint16 pwmControl = READ_REGISTER (pwmControl); WRITE_REGISTER (pwmControl, pwmControl & ~hwrVZ328PWMControlEnable); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::ResetTimer // --------------------------------------------------------------------------- void EmRegsVZ::ResetTimer (void) { WRITE_REGISTER (tmr1Counter, 0); WRITE_REGISTER (tmr2Counter, 0); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::ResetRTC // --------------------------------------------------------------------------- void EmRegsVZ::ResetRTC (void) { fHour = 15; fMin = 0; fSec = 0; fTick = 0; fCycle = 0; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetInterruptLevel // --------------------------------------------------------------------------- int32 EmRegsVZ::GetInterruptLevel (void) { /* From the DragonBall VZ manual, Chapter 9: * EMUIRQ or hardware breakpoint interrupt (level 7) * IRQ6 external interrupt (level 6) * Timer unit 1 (level 6) * Timer unit 2 (configurable from level 1 to 6) * Pulse-width modulator unit 1 (level 6) * Pulse-width modulator unit 2 (configurable from level 1 to 6) * IRQ5 external interrupt-pen (level 5) * Serial peripheral interface unit 1 (configurable from level 1 to 6) * Serial peripheral interface unit 2 (level 4) * UART unit 1 (level 4) * UART unit 2 (configurable from level 1 to 6) * Software watchdog timer interrupt (level 4) * Real-time clock (level 4) * Real-time interrupt (level 4) * Keyboard interrupt (level 4) * General-purpose interrupt INT[3:0] (level 4)-these pins can be used as keyboard interrupts * IRQ3 external interrupt (level 3) * IRQ2 external interrupt (level 2) * IRQ1 external interrupt (level 1) */ static int8 intLevel[32] = { 4, // 0x00 - hwrVZ328IntLoSPIM 6, // 0x01 - hwrVZ328IntLoTimer 4, // 0x02 - hwrVZ328IntLoUART 4, // 0x03 - hwrVZ328IntLoWDT 4, // 0x04 - hwrVZ328IntLoRTC 0, // 0x05 - hwrVZ328IntLoTimer2 (configurable - 3 by default, reprogrammed to level 6) 4, // 0x06 - hwrVZ328IntLoKbd 6, // 0x07 - hwrVZ328IntLoPWM 4, // 0x08 - hwrVZ328IntLoInt0 4, // 0x09 - hwrVZ328IntLoInt1 4, // 0x0A - hwrVZ328IntLoInt2 4, // 0x0B - hwrVZ328IntLoInt3 0, // 0x0C - hwrVZ328IntLoUART2 (configurable - 5 by default, reprogrammed to level 4) 0, // 0x0D - PWM2 (configurable - 3 by default) -2, // 0x0E - -2, // 0x0F - 1, // 0x10 - hwrVZ328IntHiIRQ1 2, // 0x11 - hwrVZ328IntHiIRQ2 3, // 0x12 - hwrVZ328IntHiIRQ3 6, // 0x13 - hwrVZ328IntHiIRQ6 5, // 0x14 - hwrVZ328IntHiPen 0, // 0x15 - SPI1 (configurable - 6 by default) 4, // 0x16 - hwrVZ328IntHiSampleTimer 7, // 0x17 - hwrVZ328IntHiEMU -2, // 0x18 - -2, // 0x19 - -2, // 0x1A - -2, // 0x1B - -2, // 0x1C - -2, // 0x1D - -2, // 0x1E - -2 // 0x1F - }; // Load in the configurable interrupt levels. uint16 intLevelControl = READ_REGISTER (intLevelControl); intLevel[0x15] = (intLevelControl >> 12) & 0x000F; intLevel[0x0C] = (intLevelControl >> 8) & 0x000F; intLevel[0x0D] = (intLevelControl >> 4) & 0x000F; intLevel[0x05] = (intLevelControl >> 0) & 0x000F; // !!! HACK: Skywalker sets the interrupt level to zero in order // to clear it out before setting it to six. Zero is not allowed, // so mask the problem by replacing it with six. if (intLevel[0x05] == 0) intLevel[0x05] = 6; #ifndef NDEBUG for (int ii = 0; ii < 32; ++ii) { EmAssert (intLevel[ii] != 0); EmAssert (intLevel[ii] != 7 || ii == 0x17); } #endif // Find the highest interrupt level. int8 result = -1; int index = 0; uint16 intStatusHi = READ_REGISTER (intStatusHi); uint16 intStatusLo = READ_REGISTER (intStatusLo); uint32 intStatus = (((uint32) intStatusHi) << 16) | intStatusLo; while (intStatus) { if (intStatus & 1) { // Make sure no undefined bits are set. EmAssert (intLevel[index] >= 0); if (result < intLevel[index]) { result = intLevel[index]; } } intStatus >>= 1; index++; } return result; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetInterruptBase // --------------------------------------------------------------------------- int32 EmRegsVZ::GetInterruptBase (void) { return READ_REGISTER (intVector) & 0xF8; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetLCDHasFrame // --------------------------------------------------------------------------- Bool EmRegsVZ::GetLCDHasFrame (void) { return false; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetLCDBeginEnd // --------------------------------------------------------------------------- void EmRegsVZ::GetLCDBeginEnd (emuptr& begin, emuptr& end) { emuptr baseAddr = READ_REGISTER (lcdStartAddr); int rowBytes = READ_REGISTER (lcdPageWidth) * 2; int height = READ_REGISTER (lcdScreenHeight) + 1; begin = baseAddr; end = baseAddr + rowBytes * height; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetLCDScanlines // --------------------------------------------------------------------------- void EmRegsVZ::GetLCDScanlines (EmScreenUpdateInfo& info) { // Get the screen metrics. int32 bpp = 1 << (READ_REGISTER (lcdPanelControl) & 0x03); int32 width = READ_REGISTER (lcdScreenWidth); int32 height = READ_REGISTER (lcdScreenHeight) + 1; int32 rowBytes = READ_REGISTER (lcdPageWidth) * 2; emuptr baseAddr = READ_REGISTER (lcdStartAddr); info.fLeftMargin = READ_REGISTER (lcdPanningOffset) & 0x0F; EmPixMapFormat format = bpp == 1 ? kPixMapFormat1 : bpp == 2 ? kPixMapFormat2 : bpp == 4 ? kPixMapFormat4 : kPixMapFormat8; RGBList colorTable; this->PrvGetPalette (colorTable); // Set format, size, and color table of EmPixMap. info.fImage.SetSize (EmPoint (width, height)); info.fImage.SetFormat (format); info.fImage.SetRowBytes (rowBytes); info.fImage.SetColorTable (colorTable); // Determine first and last scanlines to fetch, and fetch them. info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes; info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1; long firstLineOffset = info.fFirstLine * rowBytes; long lastLineOffset = info.fLastLine * rowBytes; EmMem_memcpy ( (void*) ((uint8*) info.fImage.GetBits () + firstLineOffset), baseAddr + firstLineOffset, lastLineOffset - firstLineOffset); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetDynamicHeapSize // --------------------------------------------------------------------------- int32 EmRegsVZ::GetDynamicHeapSize (void) { int32 result = 0; uint16 csControl = READ_REGISTER (csControl1); uint16 csDSelect = READ_REGISTER (csDSelect); uint16 csDUPSIZ = (csDSelect & UPSIZMask) >> UPSIZShift; uint16 csDSIZ = (csDSelect & SIZMask) >> SIZShift; if ((csControl & EUPENMask) != 0) { // Unprotected size = Chip-select Size/2^(7-upsize) // Determine upsize. // Merge in the extended bit. UPSIZ contains [1:0]. The bit // in DUPS2 extends this to [2:0]. csDUPSIZ |= ((csControl & DUPS2Mask) >> DUPS2Shift) << 2; // Determine Chip-select Size. long chip_select_size = (32 * 1024L) << csDSIZ; if ((csControl & DSIZ3Mask) != 0 && (csDSelect & DRAMMask) != 0 && csDSIZ <= 0x01) { chip_select_size = (8 * 1024L * 1024L) << csDSIZ; } result = chip_select_size / (1 << (7 - csDUPSIZ)); } else { result = (32 * 1024L) << csDUPSIZ; } return result; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetROMSize // --------------------------------------------------------------------------- int32 EmRegsVZ::GetROMSize (void) { /* SIZ Chip-Select Size This field determines the memory range of the chip-select. For CSA and CSB, chip-select size is between 128K and 16M. For CSC and CSD, chip-select size is between 32K and 4M. 000 = 128K (32K for CSC and CSD). 001 = 256K (64K for CSC and CSD). 010 = 512K (128K for CSC and CSD). 011 = 1M (256K for CSC and CSD). 100 = 2M (512K for CSC and CSD). 101 = 4M (1M for CSC and CSD). 110 = 8M (2M for CSC and CSD). 111 = 16M (4M for CSC and CSD). */ uint16 csASelect = READ_REGISTER (csASelect); uint32 result = (128 * 1024L) << ((csASelect & SIZMask) >> SIZShift); if ((csASelect & ENMask) == 0) { result = 16 * 1024L * 1024L; } return result; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetROMBaseAddress // --------------------------------------------------------------------------- uint32 EmRegsVZ::GetROMBaseAddress (void) { /* csAGroupBase: Chip-select Group Base Address register The csAGroupBase register stores the base address (bits 14-28 of the address) in the top 15 bits. The low bit is always zero. Shifting this value by 13 gives the ROM base address. E.g: If the base address is 0x10C00000, then csAGroupBase will contain 0x10C00000 >> 13 (base 10) = 0x8600. If the enable bit of the CSA register is low, the chip selects have not yet been set up. In this case, return an invalid value. */ if (!this->ChipSelectsConfigured()) { return 0xFFFFFFFF; } uint16 csAGroupBase = READ_REGISTER (csAGroupBase); uint32 result = csAGroupBase << kBaseAddressShift; return result; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::ChipSelectsConfigured // --------------------------------------------------------------------------- Bool EmRegsVZ::ChipSelectsConfigured (void) { return READ_REGISTER (csASelect) & ENMask; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetSystemClockFrequency // --------------------------------------------------------------------------- int32 EmRegsVZ::GetSystemClockFrequency (void) { uint16 pllControl = READ_REGISTER (pllControl); uint16 pllFreqSel = READ_REGISTER (pllFreqSel); // Convert the 32.768KHz clock (CLK32) into the PLLCLK frequency. uint16 PC = (pllFreqSel & 0x00FF); uint16 QC = (pllFreqSel & 0x0F00) >> 8; uint32 result = 32768L * 2 * (14 * (PC + 1) + QC + 1); // Divide by the first prescaler, if needed. if ((pllControl & hwrVZ328PLLControlPreSc1Div2) != 0) { result /= 2; } // Divide by the second prescaler, if needed. if ((pllControl & hwrVZ328PLLControlPreSc2Div2) != 0) { result /= 2; } // Divide by the system clock scaler, if needed. switch (pllControl & 0x0F00) { case hwrVZ328PLLControlSysDMADiv2: result /= 2; break; case hwrVZ328PLLControlSysDMADiv4: result /= 4; break; case hwrVZ328PLLControlSysDMADiv8: result /= 8; break; case hwrVZ328PLLControlSysDMADiv16: result /= 16; break; } return result; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetCanStop // --------------------------------------------------------------------------- Bool EmRegsVZ::GetCanStop (void) { // Make sure Timer is enabled or the RTC interrupt is enabled. if ((READ_REGISTER (tmr1Control) & hwrVZ328TmrControlEnable) != 0) return true; if ((READ_REGISTER (tmr2Control) & hwrVZ328TmrControlEnable) != 0) return true; if ((READ_REGISTER (rtcIntEnable) & hwrVZ328RTCIntEnableAlarm) != 0) return true; return false; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetAsleep // --------------------------------------------------------------------------- Bool EmRegsVZ::GetAsleep (void) { return ((READ_REGISTER (pllControl) & hwrVZ328PLLControlDisable) != 0); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetPortInputValue // --------------------------------------------------------------------------- // Return the GPIO values for the pins on the port. These values are used // if the select pins are high. uint8 EmRegsVZ::GetPortInputValue (int port) { uint8 result = 0; if (port == 'D') { result = this->GetPortInternalValue (port); } return result; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetPortInternalValue // --------------------------------------------------------------------------- // Return the dedicated values for the pins on the port. These values are // used if the select pins are low. uint8 EmRegsVZ::GetPortInternalValue (int port) { uint8 result = 0; if (port == 'D') { // Get the INT bits that need to be set. result = this->GetKeyBits (); } return result; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::PortDataChanged // --------------------------------------------------------------------------- void EmRegsVZ::PortDataChanged (int port, uint8, uint8 newValue) { if (port == 'D') { // Clear the interrupt bits that are having a 1 written to them. // Only clear them if they're configured as edge-senstive. uint8 portDIntEdge = READ_REGISTER (portDIntEdge); PRINTF ("EmRegsVZ::PortDataChanged (D): fPortDEdge = 0x%02lX", (uint32) (uint8) fPortDEdge); PRINTF ("EmRegsVZ::PortDataChanged (D): portDIntEdge = 0x%02lX", (uint32) (uint8) portDIntEdge); PRINTF ("EmRegsVZ::PortDataChanged (D): newValue = 0x%02lX", (uint32) (uint8) newValue); fPortDEdge &= ~(newValue & portDIntEdge); PRINTF ("EmRegsVZ::PortDataChanged (D): fPortDEdge = 0x%02lX", (uint32) (uint8) fPortDEdge); // Set the new interrupt state. EmRegsVZ::UpdatePortDInterrupts (); } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::pllFreqSelRead // --------------------------------------------------------------------------- uint32 EmRegsVZ::pllFreqSelRead (emuptr address, int size) { // Simulate the rising and falling of the CLK32 signal so that functions // like HwrPreRAMInit, HwrShutDownPLL, PrvSetPLL, and PrvShutDownPLL // won't hang. uint16 pllFreqSel = READ_REGISTER (pllFreqSel) ^ 0x8000; WRITE_REGISTER (pllFreqSel, pllFreqSel); // Finish up by doing a standard read. return EmRegsVZ::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::portXDataRead // --------------------------------------------------------------------------- uint32 EmRegsVZ::portXDataRead (emuptr address, int) { // The value read can come from three different places: // // - the value what was written to the data register // - any dedicated inputs // - any GPIO inputs // // The value returned depends on the settings of the SEL and DIR // registers. So let's get those settings, the values from the three // input sources, and build up a return value based on those. int port = GetPort (address); uint8 sel = StdRead (address + 2, 1); uint8 dir = StdRead (address - 1, 1); uint8 output = StdRead (address + 0, 1); uint8 input = EmHAL::GetPortInputValue (port); uint8 intFn = EmHAL::GetPortInternalValue (port); if (port == 'D') { sel |= 0x0F; // No "select" bit in low nybble, so set for IO values. // The system will poll portD 18 times in KeyBootKeys to see // if any keys are down. Wait at least that long before // letting up any boot keys maintained by the session. When we // do call ReleaseBootKeys, set our counter to -1 as a flag not // to call it any more. if (fPortDDataCount != 0xFFFFFFFF && ++fPortDDataCount >= 18 * 2) { fPortDDataCount = 0xFFFFFFFF; gSession->ReleaseBootKeys (); } } // Use the internal chip function bits if the "sel" bits are zero. intFn &= ~sel; // Otherwise, use the I/O bits. output &= sel & dir; // Use the output bits if the "dir" is one. input &= sel & ~dir; // Use the input bits if the "dir" is zero. // Assert that there are no overlaps. EmAssert ((output & input) == 0); EmAssert ((output & intFn) == 0); EmAssert ((input & intFn) == 0); // Mush everything together. uint8 result = output | input | intFn; // If this is port D, flip the bits if the POLARITY register says to. // (!!! Does this inversion apply only to input bits? That is, the // bits where the "dir" register has 0 bits?) if (0 && port == 'D') { uint8 polarity = READ_REGISTER (portDPolarity); PRINTF ("EmRegsVZ::portXDataRead: polarity = 0x%02lX", (uint32) polarity); result ^= polarity; } PRINTF ("EmRegsVZ::port%cDataRead: sel dir output input intFn result", (char) port); PRINTF ("EmRegsVZ::port%cDataRead: 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX", (char) port, (uint32) sel, (uint32) dir, (uint32) output, (uint32) input, (uint32) intFn, (uint32) result); return result; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::tmr1StatusRead // --------------------------------------------------------------------------- uint32 EmRegsVZ::tmr1StatusRead (emuptr address, int size) { uint16 tmr1Counter = READ_REGISTER (tmr1Counter) + 16; uint16 tmr1Compare = READ_REGISTER (tmr1Compare); uint16 tmr1Control = READ_REGISTER (tmr1Control); // Increment the timer. WRITE_REGISTER (tmr1Counter, tmr1Counter); // If the timer has passed the specified value... if ((tmr1Counter - tmr1Compare) < 16) { // Set the flag saying the timer timed out. uint16 tmr1Status = READ_REGISTER (tmr1Status) | hwrVZ328TmrStatusCompare; WRITE_REGISTER (tmr1Status, tmr1Status); // If it's not a free-running timer, reset it to zero. if ((tmr1Control & hwrVZ328TmrControlFreeRun) == 0) { WRITE_REGISTER (tmr1Counter, 0); } } // Remember this guy for later (see EmRegsVZ::tmr1StatusWrite()) fLastTmr1Status |= READ_REGISTER (tmr1Status); // Finish up by doing a standard read. return EmRegsVZ::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::tmr2StatusRead // --------------------------------------------------------------------------- uint32 EmRegsVZ::tmr2StatusRead (emuptr address, int size) { uint16 tmr2Counter = READ_REGISTER (tmr2Counter) + 16; uint16 tmr2Compare = READ_REGISTER (tmr2Compare); uint16 tmr2Control = READ_REGISTER (tmr2Control); // Increment the timer. WRITE_REGISTER (tmr2Counter, tmr2Counter); // If the timer has passed the specified value... if ((tmr2Counter - tmr2Compare) < 16) { // Set the flag saying the timer timed out. uint16 tmr2Status = READ_REGISTER (tmr2Status) | hwrVZ328TmrStatusCompare; WRITE_REGISTER (tmr2Status, tmr2Status); // If it's not a free-running timer, reset it to zero. if ((tmr2Control & hwrVZ328TmrControlFreeRun) == 0) { WRITE_REGISTER (tmr2Counter, 0); } } // Remember this guy for later (see EmRegsVZ::tmr2StatusWrite()) fLastTmr2Status |= READ_REGISTER (tmr2Status); // Finish up by doing a standard read. return EmRegsVZ::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::uart1Read // --------------------------------------------------------------------------- uint32 EmRegsVZ::uart1Read (emuptr address, int size) { // If this is a full read, get the next byte from the FIFO. Bool refreshRxData = (address == addressof (uReceive)) && (size == 2); // See if there's anything new ("Put the data on the bus") EmRegsVZ::UpdateUARTState (refreshRxData, 0); // Finish up by doing a standard read. return EmRegsVZ::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::uart2Read // --------------------------------------------------------------------------- uint32 EmRegsVZ::uart2Read (emuptr address, int size) { // If this is a full read, get the next byte from the FIFO. Bool refreshRxData = (address == addressof (u2Receive)) && (size == 2); // See if there's anything new ("Put the data on the bus") EmRegsVZ::UpdateUARTState (refreshRxData, 1); // Finish up by doing a standard read. return EmRegsVZ::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::rtcHourMinSecRead // --------------------------------------------------------------------------- uint32 EmRegsVZ::rtcHourMinSecRead (emuptr address, int size) { // Get the desktop machine's time. long hour, min, sec; if (Hordes::IsOn ()) { hour = fHour; min = fMin; sec = fSec; } else { ::GetHostTime (&hour, &min, &sec); } // Update the register. WRITE_REGISTER (rtcHourMinSec, (hour << hwrVZ328RTCHourMinSecHoursOffset) | (min << hwrVZ328RTCHourMinSecMinutesOffset) | (sec << hwrVZ328RTCHourMinSecSecondsOffset)); // Finish up by doing a standard read. return EmRegsVZ::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::csControl1Write // --------------------------------------------------------------------------- void EmRegsVZ::csControl1Write (emuptr address, int size, uint32 value) { // Get the current value. uint16 csControl = READ_REGISTER (csControl1); // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // Check to see if the unprotected memory range changed. const uint16 bits = EUPENMask | DSIZ3Mask | DUPS2Mask; if ((csControl & bits) != (READ_REGISTER (csControl1) & bits)) { EmAssert (gSession); gSession->ScheduleResetBanks (); } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::csASelectWrite // --------------------------------------------------------------------------- void EmRegsVZ::csASelectWrite (emuptr address, int size, uint32 value) { // Get the current value. uint16 csASelect = READ_REGISTER (csASelect); // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // Check to see if the unprotected memory range changed. if ((csASelect & SIZMask) != (READ_REGISTER (csASelect) & SIZMask)) { EmAssert (gSession); gSession->ScheduleResetBanks (); } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::csDSelectWrite // --------------------------------------------------------------------------- void EmRegsVZ::csDSelectWrite (emuptr address, int size, uint32 value) { // Get the current value. uint16 csDSelect = READ_REGISTER (csDSelect); // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // Check its new state and update our ram-protect flag. gMemAccessFlags.fProtect_SRAMSet = (READ_REGISTER (csDSelect) & 0x2000) != 0; // Check to see if the unprotected memory range changed. if ((csDSelect & UPSIZMask) != (READ_REGISTER (csDSelect) & UPSIZMask)) { EmAssert (gSession); gSession->ScheduleResetBanks (); } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::intMaskHiWrite // --------------------------------------------------------------------------- void EmRegsVZ::intMaskHiWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // Respond to the new interrupt state. EmRegsVZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::intMaskLoWrite // --------------------------------------------------------------------------- void EmRegsVZ::intMaskLoWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // Respond to the new interrupt state. EmRegsVZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::intStatusHiWrite // --------------------------------------------------------------------------- void EmRegsVZ::intStatusHiWrite (emuptr address, int size, uint32 value) { // IRQ1, IRQ2, IRQ3, IRQ6 and IRQ7 are cleared by writing to their // respective status bits. We handle those there. Since there are // no interrupt status bits like this in intStatusLo, we don't need // a handler for that register; we only handle intStatusHi. // Even though this is a 16-bit register as defined by the Palm headers, // it's a 32-bit register according to DragonballVZ docs, and is in fact // accessed that way in the kernal files (cf. HwrIRQ4Handler). In those // cases, we're still only interested in access to the IRQ# bits, so we // can turn 4-byte accesses into 2-byte accesses. if (size == 4) value >>= 16; // Take into account the possibility of 1-byte accesses, too. If we're // accessing the upper byte, just return. If we're accessing the lower // byte, we can treat it as a 2-byte access. else if (size == 1 && address == addressof (intStatusHi)) return; // Now we can treat the rest of this function as a word-write to intStatusHi. uint16 intPendingHi = READ_REGISTER (intPendingHi); // For each interrupt: // If we're writing to that interrupt's status bit and its edge bit is set: // - clear the interrupt's pending bit // - respond to the new interrupt state. #undef CLEAR_PENDING_INTERRUPT #define CLEAR_PENDING_INTERRUPT(edge, irq) \ if ((READ_REGISTER (intControl) & edge) && (value & (irq))) \ { \ intPendingHi &= ~(irq); \ } CLEAR_PENDING_INTERRUPT (hwrVZ328IntCtlEdge1, hwrVZ328IntHiIRQ1); CLEAR_PENDING_INTERRUPT (hwrVZ328IntCtlEdge2, hwrVZ328IntHiIRQ2); CLEAR_PENDING_INTERRUPT (hwrVZ328IntCtlEdge3, hwrVZ328IntHiIRQ3); CLEAR_PENDING_INTERRUPT (hwrVZ328IntCtlEdge6, hwrVZ328IntHiIRQ6); // IRQ7 is not edge-programmable, so clear it if we're merely writing to it. // !!! Double check this for VZ! if (value & hwrVZ328IntHiEMU) { intPendingHi &= ~(hwrVZ328IntHiEMU); } // If we're emulating the user pressing the hotsync button, make sure the // interrupt stays asserted. (!!! Should we use the same technique for // other buttons, too? It doesn't seem to be needed right now, but doing // that may more closely mirror the hardware.) if (fHotSyncButtonDown) { intPendingHi |= hwrVZ328IntHiIRQ1; } else { intPendingHi &= ~hwrVZ328IntHiIRQ1; } // This makes the power on key work. If the signal is asserted, the // unit will not transition between asleep and awake (cf. HwrSleep, HwrWake). intPendingHi &= ~hwrVZ328IntHiIRQ6; WRITE_REGISTER (intPendingHi, intPendingHi); EmRegsVZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::portXDataWrite // --------------------------------------------------------------------------- void EmRegsVZ::portXDataWrite (emuptr address, int size, uint32 value) { // Get the old value before updating it. uint8 oldValue = StdRead (address, size); // Take a snapshot of the line driver states. Bool driverStates[kUARTEnd]; EmHAL::GetLineDriverStates (driverStates); // Take a snapshot of the DTR pin. Bool dtrOn = EmHAL::GetDTR (1); // Now update the value with a standard write. StdWrite (address, size, value); // Let anyone know that it's changed. int port = GetPort (address); PRINTF ("EmRegsVZ::port%cDataWrite: oldValue = 0x%02lX", (char) port, (uint32) (uint8) oldValue); PRINTF ("EmRegsVZ::port%cDataWrite: newValue = 0x%02lX", (char) port, (uint32) (uint8) value); EmHAL::PortDataChanged (port, oldValue, value); // Respond to any changes in the line driver states. EmHAL::CompareLineDriverStates (driverStates); // Respond to any change in the DTR pin. if (EmHAL::GetDTR (1) != dtrOn) { EmHAL::DTRChanged (1); } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::portDIntReqEnWrite // --------------------------------------------------------------------------- void EmRegsVZ::portDIntReqEnWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // Set the new interrupt state. EmRegsVZ::UpdatePortDInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::tmr1StatusWrite // --------------------------------------------------------------------------- void EmRegsVZ::tmr1StatusWrite (emuptr address, int size, uint32 value) { UNUSED_PARAM(address) UNUSED_PARAM(size) EmAssert (size == 2); // This function's a hell of a lot easier to write if // we assume only full-register access. // Get the current value. uint16 tmr1Status = READ_REGISTER (tmr1Status); // If the user had previously read the status bits while they // were set, then it's OK for them to be clear now. Otherwise, // we have to merge any set status bits back in. tmr1Status &= value | ~fLastTmr1Status; // fLastTmr1Status was set in EmRegsVZ::tmr1StatusRead() WRITE_REGISTER (tmr1Status, tmr1Status); fLastTmr1Status = 0; if ((tmr1Status & hwrVZ328TmrStatusCompare) == 0) { uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwrVZ328IntLoTimer; WRITE_REGISTER (intPendingLo, intPendingLo); // Respond to the new interrupt state. EmRegsVZ::UpdateInterrupts (); } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::tmr2StatusWrite // --------------------------------------------------------------------------- void EmRegsVZ::tmr2StatusWrite (emuptr address, int size, uint32 value) { UNUSED_PARAM(address) UNUSED_PARAM(size) EmAssert (size == 2); // This function's a hell of a lot easier to write if // we assume only full-register access. // Get the current value. uint16 tmr2Status = READ_REGISTER (tmr2Status); // If the user had previously read the status bits while they // were set, then it's OK for them to be clear now. Otherwise, // we have to merge any set status bits back in. tmr2Status &= value | ~fLastTmr2Status; // fLastTmr2Status was set in EmRegsVZ::tmr2StatusRead() WRITE_REGISTER (tmr2Status, tmr2Status); fLastTmr2Status = 0; if ((tmr2Status & hwrVZ328TmrStatusCompare) == 0) { uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwrVZ328IntLoTimer2; WRITE_REGISTER (intPendingLo, intPendingLo); // Respond to the new interrupt state. EmRegsVZ::UpdateInterrupts (); } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::spiCont1Write // --------------------------------------------------------------------------- void EmRegsVZ::spiCont1Write (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // Get the current value. uint16 spiCont1 = READ_REGISTER (spiCont1); // Check to see if data exchange and enable are enabled. #define BIT_MASK (hwrVZ328SPIMControlExchange | hwrVZ328SPIMControlEnable) if ((spiCont1 & BIT_MASK) == BIT_MASK) { // Clear the exchange bit. spiCont1 &= ~hwrVZ328SPIMControlExchange; WRITE_REGISTER (spiCont1, spiCont1); } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::spiMasterControlWrite // --------------------------------------------------------------------------- void EmRegsVZ::spiMasterControlWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // Get the current value. uint16 spiMasterData = READ_REGISTER (spiMasterData); uint16 spiMasterControl = READ_REGISTER (spiMasterControl); // Check to see if data exchange and enable are enabled. #define BIT_MASK (hwrVZ328SPIMControlExchange | hwrVZ328SPIMControlEnable) if ((spiMasterControl & BIT_MASK) == BIT_MASK) { // If the SPI is hooked up to something, talk with it. EmSPISlave* spiSlave = this->GetSPISlave (); if (spiSlave) { // Write out the old data, read in the new data. uint16 newData = spiSlave->DoExchange (spiMasterControl, spiMasterData); // Shift in the new data. uint16 numBits = (spiMasterControl & hwrVZ328SPIMControlBitsMask) + 1; uint16 oldBitsMask = ~0 << numBits; uint16 newBitsMask = ~oldBitsMask; spiMasterData = /*((spiMasterData << numBits) & oldBitsMask) | */ (newData & newBitsMask); WRITE_REGISTER (spiMasterData, spiMasterData); } // Assert the interrupt and clear the exchange bit. spiMasterControl |= hwrVZ328SPIMControlIntStatus; spiMasterControl &= ~hwrVZ328SPIMControlExchange; WRITE_REGISTER (spiMasterControl, spiMasterControl); // If hwrVZ328SPIMControlIntEnable is set, trigger an interrupt. if ((spiMasterControl & hwrVZ328SPIMControlIntEnable) != 0) { uint16 intPendingLo = READ_REGISTER (intPendingLo); intPendingLo |= hwrVZ328IntLoSPIM; WRITE_REGISTER (intPendingLo, intPendingLo); this->UpdateInterrupts (); } } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::uart1Write // --------------------------------------------------------------------------- void EmRegsVZ::uart1Write(emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // If this write included the TX_DATA field, signal that it needs to // be transmitted. Bool sendTxData = ((address == addressof (uTransmit)) && (size == 2)) || ((address == addressof (uTransmit) + 1) && (size == 1)); // React to any changes. EmRegsVZ::UARTStateChanged (sendTxData, 0); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::uart2Write // --------------------------------------------------------------------------- void EmRegsVZ::uart2Write(emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // If this write included the TX_DATA field, signal that it needs to // be transmitted. Bool sendTxData = ((address == addressof (u2Transmit)) && (size == 2)) || ((address == addressof (u2Transmit) + 1) && (size == 1)); // React to any changes. EmRegsVZ::UARTStateChanged (sendTxData, 1); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::lcdRegisterWrite // --------------------------------------------------------------------------- void EmRegsVZ::lcdRegisterWrite (emuptr address, int size, uint32 value) { // First, get the old value in case we need to see what changed. uint32 oldValue = EmRegsVZ::StdRead (address, size); // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // Note what changed. if (address == addressof (lcdScreenWidth)) { EmScreen::InvalidateAll (); } else if (address == addressof (lcdScreenHeight)) { EmScreen::InvalidateAll (); } else if (address == addressof (lcdPanelControl)) { // hwrVZ328LcdPanelControlGrayScale is incorrectly defined as 0x01, // so use the hard-coded value of 0x03 here. // if (((value ^ oldValue) & hwrVZ328LcdPanelControlGrayScale) != 0) if (((value ^ oldValue) & 0x03) != 0) { EmScreen::InvalidateAll (); } } else if (address == addressof (lcdStartAddr)) { // Make sure the low-bit is always zero. // Make sure bits 31-29 are always zero. uint32 lcdStartAddr = READ_REGISTER (lcdStartAddr) & 0x1FFFFFFE; WRITE_REGISTER (lcdStartAddr, lcdStartAddr); EmScreen::InvalidateAll (); } else if (address == addressof (lcdPageWidth)) { if (value != oldValue) { EmScreen::InvalidateAll (); } } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::rtcControlWrite // --------------------------------------------------------------------------- void EmRegsVZ::rtcControlWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // Respond to the new interrupt state. EmRegsVZ::UpdateRTCInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::rtcIntStatusWrite // --------------------------------------------------------------------------- void EmRegsVZ::rtcIntStatusWrite (emuptr address, int size, uint32 value) { // Status bits are cleared by writing ones to them. // If we're doing a byte-write to the upper byte, shift the byte // so that we can treat the operation as a word write. If we're // doing a byte-write to the lower byte, this extension will happen // automatically. if (address == addressof (rtcIntStatus) && size == 1) value <<= 8; // Get the current value. uint16 rtcIntStatus = READ_REGISTER (rtcIntStatus); // Clear the requested bits. rtcIntStatus &= ~value; // Update the register. WRITE_REGISTER (rtcIntStatus, rtcIntStatus); // Respond to the new interrupt state. EmRegsVZ::UpdateRTCInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::rtcIntEnableWrite // --------------------------------------------------------------------------- void EmRegsVZ::rtcIntEnableWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsVZ::StdWrite (address, size, value); // Respond to the new interrupt state. EmRegsVZ::UpdateRTCInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::ButtonEvent // --------------------------------------------------------------------------- // Handles a Palm device button event by updating the appropriate registers. void EmRegsVZ::ButtonEvent (SkinElementType button, Bool buttonIsDown) { uint16 bitNumber = this->ButtonToBits (button); // Get the bits that should have been set with the previous set // of pressed keys. We use this old value to update the port D interrupts. uint8 oldBits = this->GetKeyBits (); // Update the set of keys that are currently pressed. if (buttonIsDown) { fKeyBits |= bitNumber; // Remember the key bit } else { fKeyBits &= ~bitNumber; // Forget the key bit } // Now get the new set of bits that should be set. uint8 newBits = this->GetKeyBits (); PRINTF ("EmRegsVZ::ButtonEvent: fKeyBits = 0x%04lX", (uint32) fKeyBits); PRINTF ("EmRegsVZ::ButtonEvent: oldBits = 0x%02lX", (uint32) oldBits); PRINTF ("EmRegsVZ::ButtonEvent: newBits = 0x%02lX", (uint32) newBits); // Set the interrupt bits for the bits that went from off to on. // These get cleared when portDData is written to. fPortDEdge |= newBits & ~oldBits; PRINTF ("EmRegsVZ::ButtonEvent: fPortDEdge = 0x%02lX", (uint32) fPortDEdge); // Set the new interrupt state. EmRegsVZ::UpdatePortDInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::HotSyncEvent // --------------------------------------------------------------------------- // Handles a HotSync button event by updating the appropriate registers. void EmRegsVZ::HotSyncEvent (Bool buttonIsDown) { // If the button changes state, set or clear the HotSync interrupt. uint16 intPendingHi = READ_REGISTER (intPendingHi); if (buttonIsDown) { intPendingHi |= hwrVZ328IntHiIRQ1; fHotSyncButtonDown = true; } else { intPendingHi &= ~hwrVZ328IntHiIRQ1; fHotSyncButtonDown = false; } WRITE_REGISTER (intPendingHi, intPendingHi); EmRegsVZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetKeyBits // --------------------------------------------------------------------------- uint8 EmRegsVZ::GetKeyBits (void) { // "Keys" (that is, buttons) are read from the Port D Data register. // There are 7 or 8 keys that can be pressed, but only 4 bits are // available in the Port D Data register for reporting pressed keys. // Therefore, the keys are organized into a matrix, one row or which // can be requested and reported at a time. This function determines // what row is being requested, and sets the appropriate Port D Data // bits for the keys are are currently pressed. int numRows; int numCols; uint16 keyMap[16]; Bool rows[4]; this->GetKeyInfo (&numRows, &numCols, keyMap, rows); uint8 keyData = 0; // Walk the rows, looking for one that is requested. for (int row = 0; row < numRows; ++row) { if (rows[row]) { // Walk the columns, looking for ones that have a pressed key. for (int col = 0; col < numCols; ++col) { // Get the key corresponding to this row and column. // If we've recorded (in fKeyBits) that this key is // pressed, then set its column bit. uint16 key = keyMap[row * numCols + col]; if ((key & fKeyBits) != 0) { keyData |= (1 << col); } } } } return keyData; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::ButtonToBits // --------------------------------------------------------------------------- uint16 EmRegsVZ::ButtonToBits (SkinElementType button) { uint16 bitNumber = 0; switch (button) { case kElement_None: break; case kElement_PowerButton: bitNumber = keyBitPower; break; case kElement_UpButton: bitNumber = keyBitPageUp; break; case kElement_DownButton: bitNumber = keyBitPageDown; break; case kElement_App1Button: bitNumber = keyBitHard1; break; case kElement_App2Button: bitNumber = keyBitHard2; break; case kElement_App3Button: bitNumber = keyBitHard3; break; case kElement_App4Button: bitNumber = keyBitHard4; break; case kElement_CradleButton: bitNumber = keyBitCradle; break; case kElement_Antenna: bitNumber = keyBitAntenna; break; case kElement_ContrastButton: bitNumber = keyBitContrast; break; default: EmAssert (false); } return bitNumber; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetSPISlave // --------------------------------------------------------------------------- EmSPISlave* EmRegsVZ::GetSPISlave (void) { return NULL; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::UpdateInterrupts // --------------------------------------------------------------------------- // Determines whether an interrupt has occurred by copying the Interrupt // Pending Register to the Interrupt Status Register. void EmRegsVZ::UpdateInterrupts (void) { // Copy the Interrupt Pending Register to the Interrupt Status // Register, but ignore interrupts that are being masked. // Note: this function is not sensitive to the byte ordering of the registers, // so their contents don't need to be accessed via READ_REGISTER or WRITE_REGISTER. f68VZ328Regs.intStatusHi = f68VZ328Regs.intPendingHi & ~f68VZ328Regs.intMaskHi; f68VZ328Regs.intStatusLo = f68VZ328Regs.intPendingLo & ~f68VZ328Regs.intMaskLo; PRINTF ("EmRegsVZ::UpdateInterrupts: intMask = 0x%04lX %04lX", (uint32) f68VZ328Regs.intMaskHi, (uint32) f68VZ328Regs.intMaskLo); PRINTF ("EmRegsVZ::UpdateInterrupts: intPending = 0x%04lX %04lX", (uint32) f68VZ328Regs.intPendingHi, (uint32) f68VZ328Regs.intPendingLo); // If the Interrupt Status Register isn't clear, flag an interrupt. if (f68VZ328Regs.intStatusHi || f68VZ328Regs.intStatusLo) { regs.spcflags |= SPCFLAG_INT; PRINTF ("EmRegsVZ::UpdateInterrupts: intStatus = 0x%04lX %04lX", (uint32) f68VZ328Regs.intStatusHi, (uint32) f68VZ328Regs.intStatusLo); } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::UpdatePortDInterrupts // --------------------------------------------------------------------------- // Determine what interrupts need to be generated based on the current // settings in portDData and fPortDEdge. void EmRegsVZ::UpdatePortDInterrupts (void) { // Update INT0-INT3 of the Interrupt-Pending register (bits 8-11 of the low word). // First, get those bits and clear them out. uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwrVZ328IntLoAllKeys; // Initialize the variable to hold the new interrupt settings. uint8 newBits = 0; // Get some other values we're going to need: uint8 portDDir = READ_REGISTER (portDDir); // Interrupt on inputs only (when pin is low) uint8 portDData = EmHAL::GetPortInputValue ('D'); uint8 portDPolarity = READ_REGISTER (portDPolarity); uint8 portDIntReqEn = READ_REGISTER (portDIntReqEn); uint8 portDKbdIntEn = READ_REGISTER (portDKbdIntEn); uint8 portDIntEdge = READ_REGISTER (portDIntEdge); // We have a line-level interrupt if: // // - line-level interrupts are requested // - the GPIO bit matches the polarity bit newBits |= ~portDIntEdge & portDData & portDPolarity; newBits |= ~portDIntEdge & ~portDData & ~portDPolarity; // We have an edge interrupt if: // // - edge interrupts are requested // - an edge has been recorded // // Note that we should distinguish between rising and falling edges. // For historical reasons, that's not done, and the Palm OS doesn't // look for them, so it's OK for now. // // Edge interrupts on INT[3:0] should not wake up a sleeping device. uint16 pllControl = READ_REGISTER (pllControl); #if 0 if ((pllControl & hwrVZ328PLLControlDisable) && !(gSession->GetDevice ().EdgeHack ())) { newBits |= portDIntEdge & fPortDEdge & portDPolarity & 0xF0; newBits |= portDIntEdge & 0 & ~portDPolarity & 0xF0; } else #endif { newBits |= portDIntEdge & fPortDEdge & portDPolarity; newBits |= portDIntEdge & 0 & ~portDPolarity; } // Only have interrupts if they're enabled and the pin is configured for input. newBits &= portDIntReqEn & ~portDDir; PRINTF ("EmRegsVZ::UpdatePortDInterrupts: Dir Data Pol Req Edg PDE bits"); PRINTF ("EmRegsVZ::UpdatePortDInterrupts: 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX", (uint32) portDDir, (uint32) portDData, (uint32) portDPolarity, (uint32) portDIntReqEn, (uint32) portDIntEdge, (uint32) fPortDEdge, (uint32) newBits); // Determine if the KB interrupt needs to be asserted. It is if: // // A Port D Data bit is on. // The bit is configured for input (?) // The bit is configured to be OR'd into the interrupt. if (!gSession->GetDevice ().EdgeHack ()) { uint8 KB = portDData & ~portDDir & portDKbdIntEn; if (KB) intPendingLo |= hwrVZ328IntLoKbd; else intPendingLo &= ~hwrVZ328IntLoKbd; } // Merge in the new values and write out the result. intPendingLo |= (((uint16) newBits) << hwrVZ328IntLoInt0Bit) & hwrVZ328IntLoAllKeys; WRITE_REGISTER (intPendingLo, intPendingLo); // Respond to the new interrupt state. EmRegsVZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::UpdateRTCInterrupts // --------------------------------------------------------------------------- // Determine whether to set or clear the RTC bit in the interrupt pending // register based on the current RTC register values. void EmRegsVZ::UpdateRTCInterrupts (void) { // See if the RTC is enabled. Bool rtcEnabled = (READ_REGISTER (rtcControl) & hwrVZ328RTCControlRTCEnable) != 0; // See if there are any RTC events that need to trigger an interrupt. #define BITS_TO_CHECK ( \ hwrVZ328RTCIntEnableSec | \ hwrVZ328RTCIntEnable24Hr | \ hwrVZ328RTCIntEnableAlarm | \ hwrVZ328RTCIntEnableMinute | \ hwrVZ328RTCIntEnableStopWatch ) uint16 rtcIntStatus = READ_REGISTER (rtcIntStatus); uint16 rtcIntEnable = READ_REGISTER (rtcIntEnable); uint16 rtcIntPending = rtcIntStatus & rtcIntEnable & BITS_TO_CHECK; Bool havePendingEvents = rtcIntPending != 0; // If the RTC is enabled and there are pending events, set the interrupt. // Otherwise, clear the interrupt. uint16 intPendingLo = READ_REGISTER (intPendingLo); if (rtcEnabled && havePendingEvents) { intPendingLo |= hwrVZ328IntLoRTC; // have events, so set interrupt } else { intPendingLo &= ~hwrVZ328IntLoRTC; // no events, so clear interrupt } // Update the interrupt pending register. WRITE_REGISTER (intPendingLo, intPendingLo); // Respond to the new interrupt state. EmRegsVZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::UARTStateChanged // --------------------------------------------------------------------------- void EmRegsVZ::UARTStateChanged (Bool sendTxData, int uartNum) { EmUARTDragonball::State state (EmUARTDragonball::kUART_DragonballVZ); EmRegsVZ::MarshalUARTState (state, uartNum); fUART[uartNum]->StateChanged (state, sendTxData); EmRegsVZ::UnmarshalUARTState (state, uartNum); EmRegsVZ::UpdateUARTInterrupts (state, uartNum); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::UpdateUARTState // --------------------------------------------------------------------------- void EmRegsVZ::UpdateUARTState (Bool refreshRxData, int uartNum) { EmUARTDragonball::State state (EmUARTDragonball::kUART_DragonballVZ); EmRegsVZ::MarshalUARTState (state, uartNum); fUART[uartNum]->UpdateState (state, refreshRxData); EmRegsVZ::UnmarshalUARTState (state, uartNum); EmRegsVZ::UpdateUARTInterrupts (state, uartNum); } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::UpdateUARTInterrupts // --------------------------------------------------------------------------- void EmRegsVZ::UpdateUARTInterrupts (const EmUARTDragonball::State& state, int uartNum) { // Generate the appropriate interrupts. uint16 whichBit = uartNum == 0 ? hwrVZ328IntLoUART : hwrVZ328IntLoUART2; #if 0 LogAppendMsg ("UpdateUARTInterrupts for UART %d.", uartNum + 1); if (uartNum == 1) { LogAppendMsg ("RX_FIFO_FULL: %s RX_FIFO_HALF: %s DATA_READY: %s", state.RX_FIFO_FULL ? "ON " : "off", state.RX_FIFO_HALF ? "ON " : "off", state.DATA_READY ? "ON " : "off"); LogAppendMsg ("RX_FULL_ENABLE: %s RX_HALF_ENABLE: %s RX_RDY_ENABLE: %s", state.RX_FULL_ENABLE ? "ON " : "off", state.RX_HALF_ENABLE ? "ON " : "off", state.RX_RDY_ENABLE ? "ON " : "off"); LogAppendMsg ("TX_FIFO_EMPTY: %s TX_FIFO_HALF: %s TX_AVAIL: %s", state.TX_FIFO_EMPTY ? "ON " : "off", state.TX_FIFO_HALF ? "ON " : "off", state.TX_AVAIL ? "ON " : "off"); LogAppendMsg ("TX_EMPTY_ENABLE: %s TX_HALF_ENABLE: %s TX_AVAIL_ENABLE: %s", state.TX_EMPTY_ENABLE ? "ON " : "off", state.TX_HALF_ENABLE ? "ON " : "off", state.TX_AVAIL_ENABLE ? "ON " : "off"); } #endif if (state.RX_FULL_ENABLE && state.RX_FIFO_FULL || state.RX_HALF_ENABLE && state.RX_FIFO_HALF || state.RX_RDY_ENABLE && state.DATA_READY || state.TX_EMPTY_ENABLE && state.TX_FIFO_EMPTY || state.TX_HALF_ENABLE && state.TX_FIFO_HALF || state.TX_AVAIL_ENABLE && state.TX_AVAIL) { // Set the UART interrupt. WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) | whichBit); #if 0 if (uartNum == 1) { LogAppendMsg ("Setting UART %d interrupt.", uartNum + 1); } #endif } else { // Clear the UART interrupt. WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) & ~whichBit); #if 0 if (uartNum == 1) { LogAppendMsg ("Clearing UART %d interrupt.", uartNum + 1); } #endif } // Respond to the new interrupt state. EmRegsVZ::UpdateInterrupts (); #if 0 if (uartNum == 1) { LogAppendMsg ("intPending = 0x%04lX %04lX", (uint32) f68VZ328Regs.intPendingHi, (uint32) f68VZ328Regs.intPendingLo); LogAppendMsg ("intMask = 0x%04lX %04lX", (uint32) f68VZ328Regs.intMaskHi, (uint32) f68VZ328Regs.intMaskLo); LogAppendMsg ("intStatus = 0x%04lX %04lX", (uint32) f68VZ328Regs.intStatusHi, (uint32) f68VZ328Regs.intStatusLo); } #endif } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::MarshalUARTState // --------------------------------------------------------------------------- void EmRegsVZ::MarshalUARTState (EmUARTDragonball::State& state, int uartNum) { uint16 uControl; uint16 uBaud; uint16 uReceive; uint16 uTransmit; uint16 uMisc; uint16 uLevel; if (uartNum == 0) { uControl = READ_REGISTER (uControl); uBaud = READ_REGISTER (uBaud); uReceive = READ_REGISTER (uReceive); uTransmit = READ_REGISTER (uTransmit); uMisc = READ_REGISTER (uMisc); uLevel = 0; } else { uControl = READ_REGISTER (u2Control); uBaud = READ_REGISTER (u2Baud); uReceive = READ_REGISTER (u2Receive); uTransmit = READ_REGISTER (u2Transmit); uMisc = READ_REGISTER (u2Misc); uLevel = READ_REGISTER (u2FIFOHMark); } state.UART_ENABLE = (uControl & hwrVZ328UControlUARTEnable) != 0; state.RX_ENABLE = (uControl & hwrVZ328UControlRxEnable) != 0; state.TX_ENABLE = (uControl & hwrVZ328UControlTxEnable) != 0; state.RX_CLK_CONT = (uControl & hwrVZ328UControlRxClock1xSync) != 0; state.PARITY_EN = (uControl & hwrVZ328UControlParityEn) != 0; state.ODD_EVEN = (uControl & hwrVZ328UControlParityOdd) != 0; state.STOP_BITS = (uControl & hwrVZ328UControlStopBits2) != 0; state.CHAR8_7 = (uControl & hwrVZ328UControlDataBits8) != 0; // state.GPIO_DELTA_ENABLE = (uControl & hwr328UControlGPIODeltaEn) != 0; // 68328 only state.OLD_ENABLE = (uControl & hwrVZ328UControlOldDataEn) != 0; // 68VZ328 only state.CTS_DELTA_ENABLE = (uControl & hwrVZ328UControlCTSDeltaEn) != 0; state.RX_FULL_ENABLE = (uControl & hwrVZ328UControlRxFullEn) != 0; state.RX_HALF_ENABLE = (uControl & hwrVZ328UControlRxHalfEn) != 0; state.RX_RDY_ENABLE = (uControl & hwrVZ328UControlRxRdyEn) != 0; state.TX_EMPTY_ENABLE = (uControl & hwrVZ328UControlTxEmptyEn) != 0; state.TX_HALF_ENABLE = (uControl & hwrVZ328UControlTxHalfEn) != 0; state.TX_AVAIL_ENABLE = (uControl & hwrVZ328UControlTxAvailEn) != 0; // Baud control register bits // These are all values the user sets; we just look at them. // state.GPIO_DELTA = (uBaud & hwr328UBaudGPIODelta) != 0; // 68328 only // state.GPIO = (uBaud & hwr328UBaudGPIOData) != 0; // 68328 only // state.GPIO_DIR = (uBaud & hwr328UBaudGPIODirOut) != 0; // 68328 only // state.GPIO_SRC = (uBaud & hwrVZ328UBaudGPIOSrcBaudGen) != 0; // 68328 only state.UCLK_DIR = (uBaud & hwrVZ328UBaudUCLKDirOut) != 0; // 68VZ328 only state.BAUD_SRC = (uBaud & hwrVZ328UBaudBaudSrcUCLK) != 0; state.DIVIDE = (uBaud & hwrVZ328UBaudDivider) >> hwrVZ328UBaudDivideBitOffset; state.PRESCALER = (uBaud & hwrVZ328UBaudPrescaler); // Receive register bits // These are all input bits; we set them, not the user. state.RX_FIFO_FULL = (uReceive & hwrVZ328UReceiveFIFOFull) != 0; state.RX_FIFO_HALF = (uReceive & hwrVZ328UReceiveFIFOHalf) != 0; state.DATA_READY = (uReceive & hwrVZ328UReceiveDataRdy) != 0; state.OLD_DATA = (uReceive & hwrVZ328UReceiveOldData) != 0; // 68VZ328 only state.OVRUN = (uReceive & hwrVZ328UReceiveOverrunErr) != 0; state.FRAME_ERROR = (uReceive & hwrVZ328UReceiveFrameErr) != 0; state.BREAK = (uReceive & hwrVZ328UReceiveBreakErr) != 0; state.PARITY_ERROR = (uReceive & hwrVZ328UReceiveParityErr) != 0; state.RX_DATA = (uReceive & hwrVZ328UReceiveData); // Transmitter register bits // We set everything except TX_DATA; the user sets that // value and ONLY that value. state.TX_FIFO_EMPTY = (uTransmit & hwrVZ328UTransmitFIFOEmpty) != 0; state.TX_FIFO_HALF = (uTransmit & hwrVZ328UTransmitFIFOHalf) != 0; state.TX_AVAIL = (uTransmit & hwrVZ328UTransmitTxAvail) != 0; state.SEND_BREAK = (uTransmit & hwrVZ328UTransmitSendBreak) != 0; state.IGNORE_CTS = (uTransmit & hwrVZ328UTransmitIgnoreCTS) != 0; state.BUSY = (uTransmit & hwrVZ328UTransmitBusy) != 0; // 68VZ328 only state.CTS_STATUS = (uTransmit & hwrVZ328UTransmitCTSStatus) != 0; state.CTS_DELTA = (uTransmit & hwrVZ328UTransmitCTSDelta) != 0; state.TX_DATA = (uTransmit & hwrVZ328UTransmitData); // Misc register bits // These are all values the user sets; we just look at them. state.BAUD_TEST = (uMisc & hwrVZ328UMiscBaudTest) != 0; // 68VZ328 only state.CLK_SRC = (uMisc & hwrVZ328UMiscClkSrcUCLK) != 0; state.FORCE_PERR = (uMisc & hwrVZ328UMiscForceParityErr) != 0; state.LOOP = (uMisc & hwrVZ328UMiscLoopback) != 0; state.BAUD_RESET = (uMisc & hwrVZ328UMiscBaudReset) != 0; // 68VZ328 only state.IR_TEST = (uMisc & hwrVZ328UMiscIRTestEn) != 0; // 68VZ328 only state.RTS_CONT = (uMisc & hwrVZ328UMiscRTSThruFIFO) != 0; state.RTS = (uMisc & hwrVZ328UMiscRTSOut) != 0; state.IRDA_ENABLE = (uMisc & hwrVZ328UMiscIRDAEn) != 0; state.IRDA_LOOP = (uMisc & hwrVZ328UMiscLoopIRDA) != 0; state.RX_POL = (uMisc & hwrVZ328UMiscRXPolarityInv) != 0; // 68VZ328 only state.TX_POL = (uMisc & hwrVZ328UMiscTXPolarityInv) != 0; // 68VZ328 only // Level Marker Interrupt state.TXFIFO_LEVEL_MARKER = ((uLevel >> 8) & 0x0F); // 68VZ328 only state.RXFIFO_LEVEL_MARKER = ((uLevel >> 0) & 0x0F); // 68VZ328 only } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::UnmarshalUARTState // --------------------------------------------------------------------------- void EmRegsVZ::UnmarshalUARTState (const EmUARTDragonball::State& state, int uartNum) { uint16 uControl = 0; uint16 uBaud = 0; uint16 uReceive = 0; uint16 uTransmit = 0; uint16 uMisc = 0; uint16 uLevel = 0; if (state.UART_ENABLE) uControl |= hwrVZ328UControlUARTEnable; if (state.RX_ENABLE) uControl |= hwrVZ328UControlRxEnable; if (state.TX_ENABLE) uControl |= hwrVZ328UControlTxEnable; if (state.RX_CLK_CONT) uControl |= hwrVZ328UControlRxClock1xSync; if (state.PARITY_EN) uControl |= hwrVZ328UControlParityEn; if (state.ODD_EVEN) uControl |= hwrVZ328UControlParityOdd; if (state.STOP_BITS) uControl |= hwrVZ328UControlStopBits2; if (state.CHAR8_7) uControl |= hwrVZ328UControlDataBits8; // if (state.GPIO_DELTA_ENABLE)uControl |= hwr328UControlGPIODeltaEn; // 68328 only if (state.OLD_ENABLE) uControl |= hwrVZ328UControlOldDataEn; // 68VZ328 only if (state.CTS_DELTA_ENABLE) uControl |= hwrVZ328UControlCTSDeltaEn; if (state.RX_FULL_ENABLE) uControl |= hwrVZ328UControlRxFullEn; if (state.RX_HALF_ENABLE) uControl |= hwrVZ328UControlRxHalfEn; if (state.RX_RDY_ENABLE) uControl |= hwrVZ328UControlRxRdyEn; if (state.TX_EMPTY_ENABLE) uControl |= hwrVZ328UControlTxEmptyEn; if (state.TX_HALF_ENABLE) uControl |= hwrVZ328UControlTxHalfEn; if (state.TX_AVAIL_ENABLE) uControl |= hwrVZ328UControlTxAvailEn; // Baud control register bits // These are all values the user sets; we just look at them. // if (state.GPIO_DELTA) uBaud |= hwr328UBaudGPIODelta; // 68328 only // if (state.GPIO) uBaud |= hwr328UBaudGPIOData; // 68328 only // if (state.GPIO_DIR) uBaud |= hwr328UBaudGPIODirOut; // 68328 only // if (state.GPIO_SRC) uBaud |= hwr328UBaudGPIOSrcBaudGen; // 68328 only if (state.UCLK_DIR) uBaud |= hwrVZ328UBaudUCLKDirOut; // 68VZ328 only if (state.BAUD_SRC) uBaud |= hwrVZ328UBaudBaudSrcUCLK; uBaud |= (state.DIVIDE << hwrVZ328UBaudDivideBitOffset) & hwrVZ328UBaudDivider; uBaud |= (state.PRESCALER) & hwrVZ328UBaudPrescaler; // Receive register bits // These are all input bits; we set them, not the user. if (state.RX_FIFO_FULL) uReceive |= hwrVZ328UReceiveFIFOFull; if (state.RX_FIFO_HALF) uReceive |= hwrVZ328UReceiveFIFOHalf; if (state.DATA_READY) uReceive |= hwrVZ328UReceiveDataRdy; if (state.OLD_DATA) uReceive |= hwrVZ328UReceiveOldData; // 68VZ328 only if (state.OVRUN) uReceive |= hwrVZ328UReceiveOverrunErr; if (state.FRAME_ERROR) uReceive |= hwrVZ328UReceiveFrameErr; if (state.BREAK) uReceive |= hwrVZ328UReceiveBreakErr; if (state.PARITY_ERROR) uReceive |= hwrVZ328UReceiveParityErr; uReceive |= (state.RX_DATA) & hwrVZ328UReceiveData; // Transmitter register bits // We set everything except TX_DATA; the user sets that // value and ONLY that value. if (state.TX_FIFO_EMPTY) uTransmit |= hwrVZ328UTransmitFIFOEmpty; if (state.TX_FIFO_HALF) uTransmit |= hwrVZ328UTransmitFIFOHalf; if (state.TX_AVAIL) uTransmit |= hwrVZ328UTransmitTxAvail; if (state.SEND_BREAK) uTransmit |= hwrVZ328UTransmitSendBreak; if (state.IGNORE_CTS) uTransmit |= hwrVZ328UTransmitIgnoreCTS; if (state.BUSY) uTransmit |= hwrVZ328UTransmitBusy; // 68VZ328 only if (state.CTS_STATUS) uTransmit |= hwrVZ328UTransmitCTSStatus; if (state.CTS_DELTA) uTransmit |= hwrVZ328UTransmitCTSDelta; uTransmit |= (state.TX_DATA) & hwrVZ328UTransmitData; // Misc register bits // These are all values the user sets; we just look at them. if (state.BAUD_TEST) uMisc |= hwrVZ328UMiscBaudTest; // 68VZ328 only if (state.CLK_SRC) uMisc |= hwrVZ328UMiscClkSrcUCLK; if (state.FORCE_PERR) uMisc |= hwrVZ328UMiscForceParityErr; if (state.LOOP) uMisc |= hwrVZ328UMiscLoopback; if (state.BAUD_RESET) uMisc |= hwrVZ328UMiscBaudReset; // 68VZ328 only if (state.IR_TEST) uMisc |= hwrVZ328UMiscIRTestEn; // 68VZ328 only if (state.RTS_CONT) uMisc |= hwrVZ328UMiscRTSThruFIFO; if (state.RTS) uMisc |= hwrVZ328UMiscRTSOut; if (state.IRDA_ENABLE) uMisc |= hwrVZ328UMiscIRDAEn; if (state.IRDA_LOOP) uMisc |= hwrVZ328UMiscLoopIRDA; if (state.RX_POL) uMisc |= hwrVZ328UMiscRXPolarityInv; // 68VZ328 only if (state.TX_POL) uMisc |= hwrVZ328UMiscTXPolarityInv; // 68VZ328 only // Level Marker Interrupt uLevel |= (state.TXFIFO_LEVEL_MARKER) << 8; uLevel |= (state.RXFIFO_LEVEL_MARKER) << 0; if (uartNum == 0) { WRITE_REGISTER (uControl, uControl); WRITE_REGISTER (uBaud, uBaud); WRITE_REGISTER (uReceive, uReceive); WRITE_REGISTER (uTransmit, uTransmit); WRITE_REGISTER (uMisc, uMisc); } else { WRITE_REGISTER (u2Control, uControl); WRITE_REGISTER (u2Baud, uBaud); WRITE_REGISTER (u2Receive, uReceive); WRITE_REGISTER (u2Transmit, uTransmit); WRITE_REGISTER (u2Misc, uMisc); WRITE_REGISTER (u2FIFOHMark, uLevel); } } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::GetPort // --------------------------------------------------------------------------- // Given an address, return a value indicating what port it is associated with. int EmRegsVZ::GetPort (emuptr address) { const long MASK = 0x00000FF8; switch (address & MASK) { case 0x0400: return 'A'; case 0x0408: return 'B'; case 0x0410: return 'C'; case 0x0418: return 'D'; case 0x0420: return 'E'; case 0x0428: return 'F'; case 0x0430: return 'G'; case 0x0438: return 'J'; case 0x0440: return 'K'; case 0x0448: return 'M'; } EmAssert (false); return 0; } // --------------------------------------------------------------------------- // ¥ EmRegsVZ::PrvGetPalette // --------------------------------------------------------------------------- void EmRegsVZ::PrvGetPalette (RGBList& thePalette) { // !!! TBD Preference pref1 (kPrefKeyBackgroundColor); Preference pref2 (kPrefKeyHighlightColor); RGBType foreground (0, 0, 0); RGBType background; if (this->GetLCDBacklightOn ()) { if (pref2.Loaded ()) background = *pref2; else background = ::SkinGetHighlightColor (); } else { if (pref1.Loaded ()) background = *pref1; else background = ::SkinGetBackgroundColor (); } long br = ((long) background.fRed); long bg = ((long) background.fGreen); long bb = ((long) background.fBlue); long dr = ((long) foreground.fRed) - ((long) background.fRed); long dg = ((long) foreground.fGreen) - ((long) background.fGreen); long db = ((long) foreground.fBlue) - ((long) background.fBlue); int32 bpp = 1 << (READ_REGISTER (lcdPanelControl) & 0x03); int32 numColors = 1 << bpp; thePalette.resize (numColors); for (int color = 0; color < numColors; ++color) { thePalette[color].fRed = (UInt8) (br + dr * color / (numColors - 1)); thePalette[color].fGreen = (UInt8) (bg + dg * color / (numColors - 1)); thePalette[color].fBlue = (UInt8) (bb + db * color / (numColors - 1)); } }