diff options
Diffstat (limited to 'SrcShared/Hardware/EmRegsVZ.cpp')
-rw-r--r-- | SrcShared/Hardware/EmRegsVZ.cpp | 3116 |
1 files changed, 3116 insertions, 0 deletions
diff --git a/SrcShared/Hardware/EmRegsVZ.cpp b/SrcShared/Hardware/EmRegsVZ.cpp new file mode 100644 index 0000000..f646b5b --- /dev/null +++ b/SrcShared/Hardware/EmRegsVZ.cpp @@ -0,0 +1,3116 @@ +/* -*- 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 - <Unused> + -2, // 0x0F - <Unused> + + 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 - <Unused> + -2, // 0x19 - <Unused> + -2, // 0x1A - <Unused> + -2, // 0x1B - <Unused> + -2, // 0x1C - <Unused> + -2, // 0x1D - <Unused> + -2, // 0x1E - <Unused> + -2 // 0x1F - <Unused> + }; + + // 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<RGBType> pref1 (kPrefKeyBackgroundColor); + Preference<RGBType> 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)); + } +} |