/* -*- 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 "EmRegsEZ.h" #include "EmRegsEZPrv.h" #include "Byteswapping.h" // Canonical #include "EmHAL.h" // EmHAL #include "EmMemory.h" // gMemAccessFlags, EmMem_memcpy #include "EmPixMap.h" // SetSize, SetRowBytes, etc. #include "EmScreen.h" // EmScreenUpdateInfo #include "EmSession.h" // GetDevice #include "EmSPISlave.h" // DoExchange #include "Hordes.h" // Hordes::IsOn #include "Logging.h" // LogAppendMsg #include "Miscellaneous.h" // GetHostTime #include "PreferenceMgr.h" // Preference #include "SessionFile.h" // WriteHwrDBallEZType, etc. #include "UAE.h" // regs, SPCFLAG_INT #include "PalmPack.h" #define NON_PORTABLE #include "HwrMiscFlags.h" // hwrMiscFlagID1 #define hwrEZ328maskID1J83G 0x05 // Some platform-specific -- yet fairly portable -- defines. #define hwrEZPortGIDDetect 0x04 // (L) ID select (drives kbd) #define hwrEZPortDKbdCol0 0x01 // (H) Keyboard Column 0 (aka INT0) #define hwrEZPortDKbdCol1 0x02 // (H) Keyboard Column 1 (aka INT1) #define hwrEZPortDKbdCol2 0x04 // (H) Keyboard Column 2 (aka INT2) #define hwrEZPortDKbdCol3 0x08 // (H) Keyboard Column 3 (aka INT3) #define hwrEZPortDKeyBits 0x0F // (H) All Keyboard Columns #undef NON_PORTABLE #include "PalmPackPop.h" static const uint16 UPSIZ = 0x1800; // Mask to get the unprotected memory size from csDSelect. static const uint16 SIZ = 0x000E; // Mask to get the memory size from csASelect. static const uint16 EN = 0x0001; // Mask to get the enable bit from csASelect. static const uint16 gBaseAddressShift = 13; // Shift to get base address from CSGBx register value #define PRINTF if (1) ; else LogAppendMsg // Values used to initialize the DragonBallEZ registers. static const HwrM68EZ328Type kInitial68EZ328RegisterValues = { 0x1C, // Byte scr; // $000: System Control Register { 0,0,0 }, // Byte ___filler0[0x004-0x001]; hwrEZ328chipIDEZ, // Byte chipID; // $004: Chip ID Register hwrEZ328maskID1J83G, // Byte maskID; // $005: Mask ID Register 0x00, // Word swID; // $006: Software ID Register { }, // Byte ___filler1[0x100-0x008]; 0x0000, // Word csAGroupBase; // $100: Chip Select Group A Base Register 0x0000, // Word csBGroupBase; // $102: Chip Select Group B Base Register 0x0000, // Word csCGroupBase; // $104: Chip Select Group C Base Register 0x0000, // Word csDGroupBase; // $106: Chip Select Group D Base Register { 0,0,0,0,0,0,0,0 }, // Byte ___filler6[0x110-0x108]; 0x00E0, // Word csASelect; // $110: Group A Chip Select Register 0x0000, // Word csBSelect; // $112: Group B Chip Select Register 0x0000, // Word csCSelect; // $114: Group C Chip Select Register 0x0000, // Word csDSelect; // $116: Group D Chip Select Register 0x0060, // Word emuCS; // $118: EMU Chip Select Register { }, // Byte ___filler2[0x200-0x11A]; 0x2430, // Word pllControl; // $200: PLL Control Register 0x0123, // Word pllFreqSel; // $202: PLL Frequency Select Register 0, // !!! ---> Marked as reserved in 1.4 Word pllTest; // $204: PLL Test Register (do not access) 0x00, // Byte ___filler44; 0x1F, // Byte pwrControl; // $207: Power Control Register { }, // Byte ___filler3[0x300-0x208]; 0x00, // Byte intVector; // $300: Interrupt Vector Register 0x00, // Byte ___filler4; 0x0000, // Word intControl; // $302: Interrupt Control Register 0x00FF, // Word intMaskHi; // $304: Interrupt Mask Register/HIGH word 0xFFFF, // Word intMaskLo; // $306: Interrupt Mask Register/LOW word { 0,0,0,0 }, // Byte ___filler7[0x30c-0x308]; 0x0000, // Word intStatusHi; // $30C: Interrupt Status Register/HIGH word 0x0000, // Word intStatusLo; // $30E: Interrupt Status Register/LOW word 0x0000, // Word intPendingHi; // $310: Interrupt Pending Register 0x0000, // Word intPendingLo; // $312: Interrupt Pending Register { }, // Byte ___filler4a[0x400-0x314]; 0x00, // Byte portADir; // $400: Port A Direction Register 0x00, // Byte portAData; // $401: Port A Data Register 0xFF, // Byte portAPullupEn; // $402: Port A Pullup Enable (similar to Select on DB) { 0,0,0,0,0 }, // Byte ___filler8[5]; 0x00, // Byte portBDir; // $408: Port B Direction Register 0x00, // Byte portBData; // $409: Port B Data Register 0xFF, // Byte portBPullupEn; // $40A: Port B Pullup Enable 0xFF, // Byte portBSelect; // $40B: Port B Select Register { 0,0,0,0 }, // Byte ___filler9[4]; 0x00, // Byte portCDir; // $410: Port C Direction Register 0x00, // Byte portCData; // $411: Port C Data Register 0xFF, // Byte portCPulldnEn; // $412: Port C Pulldown Enable 0xFF, // Byte portCSelect; // $413: Port C Select Register { 0,0,0,0 }, // Byte ___filler10[4]; 0x00, // Byte portDDir; // $418: Port D Direction Register 0x00, // Byte portDData; // $419: Port D Data Register 0xFF, // Byte portDPullupEn; // $41A: Port D Pull-up Enable 0xF0, // Byte portDSelect; // $41B: Port D Select Register 0x00, // Byte portDPolarity; // $41C: Port D Polarity Register 0x00, // Byte portDIntReqEn; // $41D: Port D Interrupt Request Enable 0x00, // Byte portDKbdIntEn; // $41E: Port D Keyboard Interrupt Enable 0x00, // Byte portDIntEdge; // $41F: Port D IRQ Edge Register 0x00, // Byte portEDir; // $420: Port E Direction Register 0x00, // Byte portEData; // $421: Port E Data Register 0xFF, // Byte portEPullupEn; // $422: Port E Pull-up Enable 0xFF, // Byte portESelect; // $423: Port E Select Register { 0,0,0,0 }, // Byte ___filler14[4]; 0x00, // Byte portFDir; // $428: Port F Direction Register 0x00, // Byte portFData; // $429: Port F Data Register 0xFF, // Byte portFPullupdnEn; // $42A: Port F Pull-up/down Enable 0x00, // Byte portFSelect; // $42B: Port F Select Register { 0,0,0,0 }, // Byte ___filler16[4]; 0x00, // Byte portGDir; // $430: Port G Direction Register 0x00, // Byte portGData; // $431: Port G Data Register 0x3D, // Byte portGPullupEn; // $432: Port G Pull-up Enable 0x08, // Byte portGSelect; // $433: Port G Select Register { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0 }, // Byte ___filler2000[0x500-0x434]; 0x0020, // Word pwmControl; // $500: PWM Control Register 0x00, // Byte pwmSampleHi; // $502: PWM Sample - high byte 0x00, // Byte pwmSampleLo; // $503: PWM Sample - low byte 0xFE, // Byte pwmPeriod; // $504: PWM Period 0x00, // Byte pwmCounter; // $505: PWM Counter { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0 }, // Byte ___filler24[0x600-0x506]; 0x0000, // Word tmr1Control; // $600: Timer 1 Control Register 0x0000, // Word tmr1Prescaler; // $602: Timer 1 Prescaler Register 0xFFFF, // Word tmr1Compare; // $604: Timer 1 Compare Register 0x0000, // Word tmr1Capture; // $606: Timer 1 Capture Register 0x0000, // Word tmr1Counter; // $608: Timer 1 Counter Register 0x0000, // Word tmr1Status; // $60A: Timer 1 Status Register { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0 }, // Byte ___filler25[0x800-0x61E]; 0x0000, // Word spiMasterData; // $800: SPI Master Data Register 0x0000, // Word spiMasterControl; // $802: SPI Master Control Register { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0 }, // Byte ___filler27[0x900-0x804]; 0x0000, // Word uControl; // $900: Uart Control Register 0x003F, // Word uBaud; // $902: Uart Baud Control Register 0x0000, // Word uReceive; // $904: Uart Receive Register 0x0000, // Word uTransmit; // $906: Uart Transmit Register 0x0000, // Word uMisc; // $908: Uart Miscellaneous Register 0x0000, // Word uNonIntPresc; // $90A: Uart IRDA Non-Integer Prescaler { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0 }, // Byte ___filler28[0xA00-0x90C]; 0x00000000, // DWord lcdStartAddr; // $A00: Screen Starting Address Register 0x00, // Byte ___filler29; 0xFF, // Byte lcdPageWidth; // $A05: Virtual Page Width Register { 0,0 }, // Byte ___filler30[2]; 0x03FF, // Word lcdScreenWidth; // $A08: Screen Width Register 0x01FF, // Word lcdScreenHeight; // $A0A: Screen Height Register { 0,0,0,0,0,0,0,0, 0,0,0,0 }, // Byte ___filler31[0xA18-0xA0C]; 0x0000, // Word lcdCursorXPos; // $A18: Cursor X Position 0x0000, // Word lcdCursorYPos; // $A1A: Cursor Y Position 0x0101, // Word lcdCursorWidthHeight; // $A1C: Cursor Width and Height 0x00, // Byte ___filler32; 0x7F, // Byte lcdBlinkControl; // $A1F: Blink Control Register 0x00, // Byte lcdPanelControl; // $A20: Panel Interface Control Register 0x00, // Byte lcdPolarity; // $A21: Polarity Config Register 0x00, // Byte ___filler33; 0x00, // Byte lcdACDRate; // $A23: ACD (M) Rate Control Register 0x00, // Byte ___filler34; 0x00, // Byte lcdPixelClock; // $A25: Pixel Clock Divider Register 0x00, // Byte ___filler35; 0x40, // Byte lcdClockControl; // $A27: Clocking Control Register 0x00, // Byte ___filler36; 0xFF, // Byte lcdRefreshRateAdj; // $A29: Refresh Rate Adjustment Register { 0,0,0 }, // Byte ___filler2003[0xA2D-0xA2A]; 0x00, // Byte lcdPanningOffset; // $A2D: Panning Offset Register { 0,0,0 }, // Byte ___filler37[0xA31-0xA2E]; 0xB9, // Byte lcdFrameRate; // $A31: Frame Rate Control Modulation Register 0x00, // Byte ___filler2004; 0x84, // Byte lcdGrayPalette; // $A33: Gray Palette Mapping Register 0x00, // Byte lcdReserved; // $A34: Reserved 0x00, // Byte ___filler2005; 0x0000, // Word lcdContrastControlPWM; // $A36: Contrast Control { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, }, // Byte ___filler40[0xB00-0xA38]; 0x00000000, // DWord rtcHourMinSec; // $B00: RTC Hours, Minutes, Seconds Register 0x00000000, // DWord rtcAlarm; // $B04: RTC Alarm Register { 0,0 }, // Byte ___filler2001[0xB0A-0xB08]; 0x0001, // Word rtcWatchDog; // $B0A: RTC Watchdog Timer 0x00, // Word rtcControl; // $B0C: RTC Control Register 0x00, // Word rtcIntStatus; // $B0E: RTC Interrupt Status Register 0x00, // Word rtcIntEnable; // $B10: RTC Interrupt Enable Register 0x00, // Word stopWatch; // $B12: Stopwatch Minutes { 0,0,0,0,0,0 }, // Byte ___filler2002[0xB1A-0xB14]; 0x0000, // Word rtcDay; // $B1A: RTC Day 0x0000, // Word rtcDayAlarm; // $B1C: RTC Day Alarm { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0 }, // Byte ___filler41[0xC00-0xB1E]; 0x0000, // Word dramConfig; // $C00: DRAM Memory Config Register 0x0000, // Word dramControl; // $C02: DRAM Control Register { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0 }, // Byte ___filler42[0xD00-0xC04]; 0x00000000, // DWord emuAddrCompare; // $D00: Emulation Address Compare Register 0x00000000, // DWord emuAddrMask; // $D04: Emulation Address Mask Register 0x0000, // Word emuControlCompare; // $D08: Emulation Control Compare Register 0x0000, // Word emuControlMask; // $D0A: Emulation Control Mask Register 0x0000, // Word emuControl; // $DOC: Emulation Control Register 0x0000 // Word emuStatus; // $D0E: Emulation Status Register }; // --------------------------------------------------------------------------- // ¥ EmRegsEZ::EmRegsEZ // --------------------------------------------------------------------------- EmRegsEZ::EmRegsEZ (void) : EmRegs (), f68EZ328Regs (), fHotSyncButtonDown (0), fKeyBits (0), fLastTmr1Status (0), fPortDEdge (0), fPortDDataCount (0), fHour (0), fMin (0), fSec (0), fTick (0), fCycle (0), fUART (NULL) { } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::~EmRegsEZ // --------------------------------------------------------------------------- EmRegsEZ::~EmRegsEZ (void) { } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::Initialize // --------------------------------------------------------------------------- void EmRegsEZ::Initialize (void) { EmRegs::Initialize (); fUART = new EmUARTDragonball (EmUARTDragonball::kUART_DragonballEZ, 0); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::Reset // --------------------------------------------------------------------------- void EmRegsEZ::Reset (Bool hardwareReset) { EmRegs::Reset (hardwareReset); if (hardwareReset) { f68EZ328Regs = kInitial68EZ328RegisterValues; // Byteswap all the words in the DragonballEZ registers (if necessary). Canonical (f68EZ328Regs); ByteswapWords (&f68EZ328Regs, sizeof(f68EZ328Regs)); fKeyBits = 0; fLastTmr1Status = 0; fPortDEdge = 0; fPortDDataCount = 0; // React to the new data in the UART registers. Bool sendTxData = false; EmRegsEZ::UARTStateChanged (sendTxData); } } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::Save // --------------------------------------------------------------------------- void EmRegsEZ::Save (SessionFile& f) { EmRegs::Save (f); StWordSwapper swapper1 (&f68EZ328Regs, sizeof(f68EZ328Regs)); // StCanonical swapper2 (f68EZ328Regs); f.WriteHwrDBallEZType (f68EZ328Regs); f.FixBug (SessionFile::kBugByteswappedStructs); const long kCurrentVersion = 3; Chunk chunk; EmStreamChunk s (chunk); s << kCurrentVersion; s << fHotSyncButtonDown; s << fKeyBits; s << fLastTmr1Status; s << fPortDEdge; // Added in version 2. s << fHour; s << fMin; s << fSec; s << fTick; s << fCycle; // Added in version 3. s << fPortDDataCount; f.WriteDBallEZState (chunk); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::Load // --------------------------------------------------------------------------- void EmRegsEZ::Load (SessionFile& f) { EmRegs::Load (f); if (f.ReadHwrDBallEZType (f68EZ328Regs)) { // 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 (f68EZ328Regs); } ByteswapWords (&f68EZ328Regs, sizeof(f68EZ328Regs)); // React to the new data in the UART registers. Bool sendTxData = false; EmRegsEZ::UARTStateChanged (sendTxData); // Reset gMemAccessFlags.fProtect_SRAMSet gMemAccessFlags.fProtect_SRAMSet = (READ_REGISTER (csDSelect) & 0x2000) != 0; } else { f.SetCanReload (false); } Chunk chunk; if (f.ReadDBallEZState (chunk)) { long version; EmStreamChunk s (chunk); s >> version; if (version >= 1) { s >> fHotSyncButtonDown; s >> fKeyBits; s >> fLastTmr1Status; s >> fPortDEdge; } if (version >= 2) { s >> fHour; s >> fMin; s >> fSec; s >> fTick; s >> fCycle; } if (version >= 3) { s >> fPortDDataCount; } } else { f.SetCanReload (false); } } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::Dispose // --------------------------------------------------------------------------- void EmRegsEZ::Dispose (void) { delete fUART; fUART = NULL; EmRegs::Dispose (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::SetSubBankHandlers // --------------------------------------------------------------------------- void EmRegsEZ::SetSubBankHandlers (void) { // Install base handlers. EmRegs::SetSubBankHandlers (); // Now add standard/specialized handers for the defined registers. INSTALL_HANDLER (StdRead, StdWrite, scr); INSTALL_HANDLER (StdRead, NullWrite, chipID); INSTALL_HANDLER (StdRead, NullWrite, maskID); INSTALL_HANDLER (StdRead, NullWrite, swID); INSTALL_HANDLER (StdRead, StdWrite, csAGroupBase); INSTALL_HANDLER (StdRead, StdWrite, csBGroupBase); INSTALL_HANDLER (StdRead, StdWrite, csCGroupBase); INSTALL_HANDLER (StdRead, StdWrite, csDGroupBase); 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, pllTest); 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, 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, 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, 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, spiMasterData); INSTALL_HANDLER (StdRead, spiMasterControlWrite, spiMasterControl); INSTALL_HANDLER (uartRead, uartWrite, uControl); INSTALL_HANDLER (uartRead, uartWrite, uBaud); INSTALL_HANDLER (uartRead, uartWrite, uReceive); INSTALL_HANDLER (uartRead, uartWrite, uTransmit); INSTALL_HANDLER (uartRead, uartWrite, uMisc); INSTALL_HANDLER (uartRead, uartWrite, uNonIntPresc); 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 (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, 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); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetRealAddress // --------------------------------------------------------------------------- uint8* EmRegsEZ::GetRealAddress (emuptr address) { uint8* loc = ((uint8*) &f68EZ328Regs) + (address - kMemoryStart); return loc; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetAddressStart // --------------------------------------------------------------------------- emuptr EmRegsEZ::GetAddressStart (void) { return kMemoryStart; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetAddressRange // --------------------------------------------------------------------------- uint32 EmRegsEZ::GetAddressRange (void) { return kMemorySize; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::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 EmRegsEZ::Cycle (Bool sleeping) { #if _DEBUG #define increment 20 #else #define increment 4 #endif // Determine whether timer is enabled. if ((READ_REGISTER (tmr1Control) & hwrEZ328TmrControlEnable) != 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) | hwrEZ328TmrStatusCompare); // If the Free Run/Restart flag is not set, clear the counter. if ((READ_REGISTER (tmr1Control) & hwrEZ328TmrControlFreeRun) == 0) { WRITE_REGISTER (tmr1Counter, 0); } // If the timer interrupt is enabled, post an interrupt. if ((READ_REGISTER (tmr1Control) & hwrEZ328TmrControlEnInterrupt) != 0) { WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) | hwrEZ328IntLoTimer); EmRegsEZ::UpdateInterrupts (); } } } 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; } } } } } } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::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 EmRegsEZ::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) { EmRegsEZ::HotSyncEvent (event.fButtonIsDown); } else { EmRegsEZ::ButtonEvent (event.fButton, event.fButtonIsDown); } } // See if there's anything new ("Put the data on the bus") EmRegsEZ::UpdateUARTState (false); // 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) & hwrEZ328RTCIntEnableAlarm) != 0 && (READ_REGISTER (rtcIntStatus) & hwrEZ328RTCIntStatusAlarm) == 0) { uint32 rtcAlarm = READ_REGISTER (rtcAlarm); long almHour = (rtcAlarm & hwrEZ328RTCAlarmHoursMask) >> hwrEZ328RTCAlarmHoursOffset; long almMin = (rtcAlarm & hwrEZ328RTCAlarmMinutesMask) >> hwrEZ328RTCAlarmMinutesOffset; long almSec = (rtcAlarm & hwrEZ328RTCAlarmSecondsMask) >> hwrEZ328RTCAlarmSecondsOffset; 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) | hwrEZ328RTCIntStatusAlarm); EmRegsEZ::UpdateRTCInterrupts (); } } } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::TurnSoundOff // --------------------------------------------------------------------------- void EmRegsEZ::TurnSoundOff (void) { uint16 pwmControl = READ_REGISTER (pwmControl); WRITE_REGISTER (pwmControl, pwmControl & ~hwrEZ328PWMControlEnable); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::ResetTimer // --------------------------------------------------------------------------- void EmRegsEZ::ResetTimer (void) { WRITE_REGISTER (tmr1Counter, 0); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::ResetRTC // --------------------------------------------------------------------------- void EmRegsEZ::ResetRTC (void) { fHour = 15; fMin = 0; fSec = 0; fTick = 0; fCycle = 0; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetInterruptLevel // --------------------------------------------------------------------------- int32 EmRegsEZ::GetInterruptLevel (void) { uint16 intStatusHi = READ_REGISTER (intStatusHi); uint16 intStatusLo = READ_REGISTER (intStatusLo); // Level 7 = EMUIRQ. if ((intStatusHi & hwrEZ328IntHiEMU) != 0) return 7; // Level 6 = IRQ6, TMR, PWM. if ((intStatusHi & (hwrEZ328IntHiIRQ6)) != 0) return 6; if ((intStatusLo & (hwrEZ328IntLoTimer | hwrEZ328IntLoPWM)) != 0) return 6; // Level 5 = PEN. if ((intStatusHi & hwrEZ328IntHiPen) != 0) return 5; // Level 4 = SPIM, UART, WDT, RTC, RTC Sample, KB, INT0 - INT3. if ((intStatusLo & ( hwrEZ328IntLoSPIM | hwrEZ328IntLoUART | hwrEZ328IntLoWDT | hwrEZ328IntLoRTC | hwrEZ328IntLoKbd | hwrEZ328IntLoInt3 | hwrEZ328IntLoInt2 | hwrEZ328IntLoInt1 | hwrEZ328IntLoInt0)) != 0) return 4; if ((intStatusHi & hwrEZ328IntHiSampleTimer) != 0) return 4; // Level 3 = IRQ3. if ((intStatusHi & hwrEZ328IntHiIRQ3) != 0) return 3; // Level 2 = IRQ2. if ((intStatusHi & hwrEZ328IntHiIRQ2) != 0) return 2; // Level 1 = IRQ1. if ((intStatusHi & hwrEZ328IntHiIRQ1) != 0) return 1; // Level 0. return -1; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetInterruptBase // --------------------------------------------------------------------------- int32 EmRegsEZ::GetInterruptBase (void) { return READ_REGISTER (intVector) & 0xF8; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetLCDHasFrame // --------------------------------------------------------------------------- Bool EmRegsEZ::GetLCDHasFrame (void) { return false; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetLCDBeginEnd // --------------------------------------------------------------------------- void EmRegsEZ::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; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetLCDScanlines // --------------------------------------------------------------------------- void EmRegsEZ::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; emuptr firstLineAddr = baseAddr + (info.fFirstLine * rowBytes); emuptr lastLineAddr = baseAddr + (info.fLastLine * rowBytes); // TODO: probably move to const long hwrEZ328LcdPageSize = 0x00020000; // 128K const long hwrEZ328LcdPageMask = 0xFFFE0000; uint8* dst = ((uint8*) info.fImage.GetBits () + firstLineAddr - baseAddr); emuptr boundaryAddr = ((baseAddr & hwrEZ328LcdPageMask) + hwrEZ328LcdPageSize); if (lastLineAddr <= boundaryAddr) { // Bits don't cross the 128K boundary } else if (firstLineAddr >= boundaryAddr) { // Bits are all beyond the 128K boundary firstLineAddr -= hwrEZ328LcdPageSize; // wrap around lastLineAddr -= hwrEZ328LcdPageSize; } else { // Bits straddle the 128K boundary; // copy the first part here, the wrapped part below EmMem_memcpy ((void*) dst, firstLineAddr, boundaryAddr - firstLineAddr); dst += (boundaryAddr - firstLineAddr); firstLineAddr = boundaryAddr - hwrEZ328LcdPageSize; lastLineAddr -= hwrEZ328LcdPageSize; // wrap around } EmMem_memcpy ((void*) dst, firstLineAddr, lastLineAddr - firstLineAddr); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetUARTDevice // --------------------------------------------------------------------------- // Return what sort of device is hooked up to the given UART. EmUARTDeviceType EmRegsEZ::GetUARTDevice (int /*uartNum*/) { Bool serEnabled = this->GetLineDriverState (kUARTSerial); Bool irEnabled = this->GetLineDriverState (kUARTIR); // It's probably an error to have them both enabled at the same // time. !!! TBD: make this an error message. EmAssert (!(serEnabled && irEnabled)); if (serEnabled) return kUARTSerial; if (irEnabled) return kUARTIR; return kUARTNone; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetDynamicHeapSize // --------------------------------------------------------------------------- int32 EmRegsEZ::GetDynamicHeapSize (void) { int32 result = 0; uint16 csDSelect = READ_REGISTER (csDSelect); switch (csDSelect & UPSIZ) { case 0x0000: result = 32 * 1024L; break; case 0x0800: result = 64 * 1024L; break; case 0x1000: result = 128 * 1024L; break; case 0x1800: result = 256 * 1024L; break; default: EmAssert (false); break; } return result; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetROMSize // --------------------------------------------------------------------------- int32 EmRegsEZ::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 & SIZ) >> 1); if ((csASelect & EN) == 0) { result = 16 * 1024L * 1024L; } return result; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetROMBaseAddress // --------------------------------------------------------------------------- uint32 EmRegsEZ::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 << gBaseAddressShift; return result; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::ChipSelectsConfigured // --------------------------------------------------------------------------- Bool EmRegsEZ::ChipSelectsConfigured (void) { return READ_REGISTER (csASelect) & EN; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetSystemClockFrequency // --------------------------------------------------------------------------- int32 EmRegsEZ::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 * (14 * (PC + 1) + QC + 1); // Divide by the prescaler, if needed. if ((pllControl & 0x0020) != 0) { result /= 2; } // Divide by the system clock scaler, if needed. switch (pllControl & 0x0F00) { case hwrEZ328PLLControlSysDMADiv2: result /= 2; break; case hwrEZ328PLLControlSysDMADiv4: result /= 4; break; case hwrEZ328PLLControlSysDMADiv8: result /= 8; break; case hwrEZ328PLLControlSysDMADiv16: result /= 16; break; } return result; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetCanStop // --------------------------------------------------------------------------- Bool EmRegsEZ::GetCanStop (void) { // Make sure Timer is enabled or the RTC interrupt is enabled. if ((READ_REGISTER (tmr1Control) & hwrEZ328TmrControlEnable) != 0) return true; if ((READ_REGISTER (rtcIntEnable) & hwrEZ328RTCIntEnableAlarm) != 0) return true; return false; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetAsleep // --------------------------------------------------------------------------- Bool EmRegsEZ::GetAsleep (void) { return ((READ_REGISTER (pllControl) & hwrEZ328PLLControlDisable) != 0); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetPortInputValue // --------------------------------------------------------------------------- // Return the GPIO values for the pins on the port. These values are used // if the select pins are high. uint8 EmRegsEZ::GetPortInputValue (int port) { uint8 result = 0; if (port == 'D') { result = this->GetPortInternalValue (port); } return result; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetPortInternalValue // --------------------------------------------------------------------------- // Return the dedicated values for the pins on the port. These values are // used if the select pins are low. uint8 EmRegsEZ::GetPortInternalValue (int port) { uint8 result = 0; if (port == 'D') { // If the ID_DETECT pin is asserted, load the data lines with the // hardware ID. if (EmRegsEZ::IDDetectAsserted ()) { result = EmRegsEZ::GetHardwareID (); } // Otherwise, load the lines with keyboard information. else { // Get the INT bits that need to be set. result = this->GetKeyBits (); } } return result; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::PortDataChanged // --------------------------------------------------------------------------- void EmRegsEZ::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 ("EmRegsEZ::PortDataChanged (D): fPortDEdge = 0x%02lX", (uint32) (uint8) fPortDEdge); PRINTF ("EmRegsEZ::PortDataChanged (D): portDIntEdge = 0x%02lX", (uint32) (uint8) portDIntEdge); PRINTF ("EmRegsEZ::PortDataChanged (D): newValue = 0x%02lX", (uint32) (uint8) newValue); fPortDEdge &= ~(newValue & portDIntEdge); PRINTF ("EmRegsEZ::PortDataChanged (D): fPortDEdge = 0x%02lX", (uint32) (uint8) fPortDEdge); // Set the new interrupt state. EmRegsEZ::UpdatePortDInterrupts (); } } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::pllFreqSelRead // --------------------------------------------------------------------------- uint32 EmRegsEZ::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 EmRegsEZ::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::portXDataRead // --------------------------------------------------------------------------- uint32 EmRegsEZ::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 ("EmRegsEZ::portXDataRead: polarity = 0x%02lX", (uint32) polarity); result ^= polarity; } PRINTF ("EmRegsEZ::port%cDataRead: sel dir output input intFn result", (char) port); PRINTF ("EmRegsEZ::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; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::tmr1StatusRead // --------------------------------------------------------------------------- uint32 EmRegsEZ::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) | hwrEZ328TmrStatusCompare; WRITE_REGISTER (tmr1Status, tmr1Status); // If it's not a free-running timer, reset it to zero. if ((tmr1Control & hwrEZ328TmrControlFreeRun) == 0) { WRITE_REGISTER (tmr1Counter, 0); } } // Remember this guy for later (see EmRegsEZ::tmr1StatusWrite()) fLastTmr1Status |= READ_REGISTER (tmr1Status); // Finish up by doing a standard read. return EmRegsEZ::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::uartRead // --------------------------------------------------------------------------- uint32 EmRegsEZ::uartRead (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") EmRegsEZ::UpdateUARTState (refreshRxData); // Finish up by doing a standard read. return EmRegsEZ::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::rtcHourMinSecRead // --------------------------------------------------------------------------- uint32 EmRegsEZ::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 << hwrEZ328RTCHourMinSecHoursOffset) | (min << hwrEZ328RTCHourMinSecMinutesOffset) | (sec << hwrEZ328RTCHourMinSecSecondsOffset)); // Finish up by doing a standard read. return EmRegsEZ::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::csASelectWrite // --------------------------------------------------------------------------- void EmRegsEZ::csASelectWrite (emuptr address, int size, uint32 value) { // Get the current value. uint16 csASelect = READ_REGISTER (csASelect); // Do a standard update of the register. EmRegsEZ::StdWrite (address, size, value); // Check to see if the unprotected memory range changed. if ((csASelect & SIZ) != (READ_REGISTER (csASelect) & SIZ)) { EmAssert (gSession); gSession->ScheduleResetBanks (); } } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::csDSelectWrite // --------------------------------------------------------------------------- void EmRegsEZ::csDSelectWrite (emuptr address, int size, uint32 value) { // Get the current value. uint16 csDSelect = READ_REGISTER (csDSelect); // Do a standard update of the register. EmRegsEZ::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 & UPSIZ) != (READ_REGISTER (csDSelect) & UPSIZ)) { EmAssert (gSession); gSession->ScheduleResetBanks (); } } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::intMaskHiWrite // --------------------------------------------------------------------------- void EmRegsEZ::intMaskHiWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsEZ::StdWrite (address, size, value); // Respond to the new interrupt state. EmRegsEZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::intMaskLoWrite // --------------------------------------------------------------------------- void EmRegsEZ::intMaskLoWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsEZ::StdWrite (address, size, value); // Respond to the new interrupt state. EmRegsEZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::intStatusHiWrite // --------------------------------------------------------------------------- void EmRegsEZ::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 DragonballEZ 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 (hwrEZ328IntCtlEdge1, hwrEZ328IntHiIRQ1); CLEAR_PENDING_INTERRUPT (hwrEZ328IntCtlEdge2, hwrEZ328IntHiIRQ2); CLEAR_PENDING_INTERRUPT (hwrEZ328IntCtlEdge3, hwrEZ328IntHiIRQ3); CLEAR_PENDING_INTERRUPT (hwrEZ328IntCtlEdge6, hwrEZ328IntHiIRQ6); // IRQ7 is not edge-programmable, so clear it if we're merely writing to it. // !!! Double check this for EZ! if (value & hwrEZ328IntHiEMU) { intPendingHi &= ~(hwrEZ328IntHiEMU); } // 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 |= hwrEZ328IntHiIRQ1; } else { intPendingHi &= ~hwrEZ328IntHiIRQ1; } // 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 &= ~hwrEZ328IntHiIRQ6; WRITE_REGISTER (intPendingHi, intPendingHi); EmRegsEZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::portXDataWrite // --------------------------------------------------------------------------- void EmRegsEZ::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); // Now update the value with a standard write. StdWrite (address, size, value); // Let anyone know that it's changed. int port = GetPort (address); PRINTF ("EmRegsEZ::port%cDataWrite: oldValue = 0x%02lX", (char) port, (uint32) (uint8) oldValue); PRINTF ("EmRegsEZ::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); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::portDIntReqEnWrite // --------------------------------------------------------------------------- void EmRegsEZ::portDIntReqEnWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsEZ::StdWrite (address, size, value); // Set the new interrupt state. EmRegsEZ::UpdatePortDInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::tmr1StatusWrite // --------------------------------------------------------------------------- void EmRegsEZ::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 EmRegsEZ::tmr1StatusRead() WRITE_REGISTER (tmr1Status, tmr1Status); fLastTmr1Status = 0; if ((tmr1Status & hwrEZ328TmrStatusCompare) == 0) { uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwrEZ328IntLoTimer; WRITE_REGISTER (intPendingLo, intPendingLo); // Respond to the new interrupt state. EmRegsEZ::UpdateInterrupts (); } } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::spiMasterControlWrite // --------------------------------------------------------------------------- void EmRegsEZ::spiMasterControlWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsEZ::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 interrupts are enabled. #define BIT_MASK (hwrEZ328SPIMControlExchange | hwrEZ328SPIMControlEnable) 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 & hwrEZ328SPIMControlBitsMask) + 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 |= hwrEZ328SPIMControlIntStatus; spiMasterControl &= ~hwrEZ328SPIMControlExchange; WRITE_REGISTER (spiMasterControl, spiMasterControl); // If hwrEZ328SPIMControlIntEnable is set, trigger an interrupt. if ((spiMasterControl & hwrEZ328SPIMControlIntEnable) != 0) { uint16 intPendingLo = READ_REGISTER (intPendingLo); intPendingLo |= hwrEZ328IntLoSPIM; WRITE_REGISTER (intPendingLo, intPendingLo); this->UpdateInterrupts (); } } } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::uartWrite // --------------------------------------------------------------------------- void EmRegsEZ::uartWrite(emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsEZ::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. EmRegsEZ::UARTStateChanged (sendTxData); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::lcdRegisterWrite // --------------------------------------------------------------------------- void EmRegsEZ::lcdRegisterWrite (emuptr address, int size, uint32 value) { // First, get the old value in case we need to see what changed. uint32 oldValue = EmRegsEZ::StdRead (address, size); // Do a standard update of the register. EmRegsEZ::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)) { // hwrEZ328LcdPanelControlGrayScale is incorrectly defined as 0x01, // so use the hard-coded value of 0x03 here. // if (((value ^ oldValue) & hwrEZ328LcdPanelControlGrayScale) != 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 (); } } } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::rtcControlWrite // --------------------------------------------------------------------------- void EmRegsEZ::rtcControlWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsEZ::StdWrite (address, size, value); // Respond to the new interrupt state. EmRegsEZ::UpdateRTCInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::rtcIntStatusWrite // --------------------------------------------------------------------------- void EmRegsEZ::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. EmRegsEZ::UpdateRTCInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::rtcIntEnableWrite // --------------------------------------------------------------------------- void EmRegsEZ::rtcIntEnableWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegsEZ::StdWrite (address, size, value); // Respond to the new interrupt state. EmRegsEZ::UpdateRTCInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::ButtonEvent // --------------------------------------------------------------------------- // Handles a Palm device button event by updating the appropriate registers. void EmRegsEZ::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 ("EmRegsEZ::ButtonEvent: fKeyBits = 0x%04lX", (uint32) fKeyBits); PRINTF ("EmRegsEZ::ButtonEvent: oldBits = 0x%02lX", (uint32) oldBits); PRINTF ("EmRegsEZ::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 ("EmRegsEZ::ButtonEvent: fPortDEdge = 0x%02lX", (uint32) fPortDEdge); // Set the new interrupt state. EmRegsEZ::UpdatePortDInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::HotSyncEvent // --------------------------------------------------------------------------- // Handles a HotSync button event by updating the appropriate registers. void EmRegsEZ::HotSyncEvent (Bool buttonIsDown) { // If the button changes state, set or clear the HotSync interrupt. uint16 intPendingHi = READ_REGISTER (intPendingHi); if (buttonIsDown) { intPendingHi |= hwrEZ328IntHiIRQ1; fHotSyncButtonDown = true; } else { intPendingHi &= ~hwrEZ328IntHiIRQ1; fHotSyncButtonDown = false; } WRITE_REGISTER (intPendingHi, intPendingHi); EmRegsEZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetKeyBits // --------------------------------------------------------------------------- uint8 EmRegsEZ::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); } } } } UInt8 portFDir = READ_REGISTER (portFDir); UInt8 portFData = READ_REGISTER (portFData); PRINTF ("EmRegsEZ::GetKeyBits: numRows = %d, numCols = %d", numRows, numCols); PRINTF ("EmRegsEZ::GetKeyBits: portFDir = 0x%02lX, portFData = 0x%02lX", (uint32) portFDir, (uint32) portFData); PRINTF ("EmRegsEZ::GetKeyBits: rows[0] = %d, [1] = %d, [2] = %d, [3] = %d", rows[0], rows[1], rows[2], rows[3]); // PRINTF ("EmRegsEZ::GetKeyBits: keyMap[0] = %2d, [1] = %2d, [2] = %2d, [3] = %2d", keyMap[0], keyMap[1], keyMap[2], keyMap[3]); // PRINTF ("EmRegsEZ::GetKeyBits: keyMap[4] = %2d, [5] = %2d, [6] = %2d, [7] = %2d", keyMap[4], keyMap[5], keyMap[6], keyMap[7]); // PRINTF ("EmRegsEZ::GetKeyBits: keyMap[8] = %2d, [9] = %2d, [A] = %2d, [B] = %2d", keyMap[8], keyMap[9], keyMap[10], keyMap[11]); // PRINTF ("EmRegsEZ::GetKeyBits: keyMap[C] = %2d, [D] = %2d, [E] = %2d, [F] = %2d", keyMap[12], keyMap[13], keyMap[14], keyMap[15]); PRINTF ("EmRegsEZ::GetKeyBits: fKeyBits = 0x%04lX", (uint32) fKeyBits); PRINTF ("EmRegsEZ::GetKeyBits: keyData = 0x%02lX", (uint32) keyData); return keyData; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::ButtonToBits // --------------------------------------------------------------------------- uint16 EmRegsEZ::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; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetSPISlave // --------------------------------------------------------------------------- EmSPISlave* EmRegsEZ::GetSPISlave (void) { return NULL; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::UpdateInterrupts // --------------------------------------------------------------------------- // Determines whether an interrupt has occurred by copying the Interrupt // Pending Register to the Interrupt Status Register. void EmRegsEZ::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. f68EZ328Regs.intStatusHi = f68EZ328Regs.intPendingHi & ~f68EZ328Regs.intMaskHi; f68EZ328Regs.intStatusLo = f68EZ328Regs.intPendingLo & ~f68EZ328Regs.intMaskLo; PRINTF ("EmRegsEZ::UpdateInterrupts: intMask = 0x%04lX %04lX", (uint32) f68EZ328Regs.intMaskHi, (uint32) f68EZ328Regs.intMaskLo); PRINTF ("EmRegsEZ::UpdateInterrupts: intPending = 0x%04lX %04lX", (uint32) f68EZ328Regs.intPendingHi, (uint32) f68EZ328Regs.intPendingLo); // If the Interrupt Status Register isn't clear, flag an interrupt. if (f68EZ328Regs.intStatusHi || f68EZ328Regs.intStatusLo) { regs.spcflags |= SPCFLAG_INT; PRINTF ("EmRegsEZ::UpdateInterrupts: intStatus = 0x%04lX %04lX", (uint32) f68EZ328Regs.intStatusHi, (uint32) f68EZ328Regs.intStatusLo); } } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::UpdatePortDInterrupts // --------------------------------------------------------------------------- // Determine what interrupts need to be generated based on the current // settings in portDData and fPortDEdge. void EmRegsEZ::UpdatePortDInterrupts (void) { // Update INT0-INT3 of the Interrupt-Pending register (bits 8-11 of the low word). PRINTF ("EmRegsEZ::UpdatePortDInterrupts:"); // First, get those bits and clear them out. uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwrEZ328IntLoAllKeys; // 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 (pllControl & hwrEZ328PLLControlDisable) { newBits |= portDIntEdge & fPortDEdge & portDPolarity & 0xF0; newBits |= portDIntEdge & 0 & ~portDPolarity & 0xF0; } else { 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 ("EmRegsEZ::UpdatePortDInterrupts: Dir Data Pol Req Edg PDE bits"); PRINTF ("EmRegsEZ::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. uint8 KB = portDData & ~portDDir & portDKbdIntEn; if (KB) intPendingLo |= hwrEZ328IntLoKbd; else intPendingLo &= ~hwrEZ328IntLoKbd; // Merge in the new values and write out the result. intPendingLo |= (((uint16) newBits) << hwrEZ328IntLoInt0Bit) & hwrEZ328IntLoAllKeys; WRITE_REGISTER (intPendingLo, intPendingLo); // Respond to the new interrupt state. EmRegsEZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::UpdateRTCInterrupts // --------------------------------------------------------------------------- // Determine whether to set or clear the RTC bit in the interrupt pending // register based on the current RTC register values. void EmRegsEZ::UpdateRTCInterrupts (void) { // See if the RTC is enabled. Bool rtcEnabled = (READ_REGISTER (rtcControl) & hwrEZ328RTCControlRTCEnable) != 0; // See if there are any RTC events that need to trigger an interrupt. #define BITS_TO_CHECK ( \ hwrEZ328RTCIntEnableSec | \ hwrEZ328RTCIntEnable24Hr | \ hwrEZ328RTCIntEnableAlarm | \ hwrEZ328RTCIntEnableMinute | \ hwrEZ328RTCIntEnableStopWatch ) 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 |= hwrEZ328IntLoRTC; // have events, so set interrupt } else { intPendingLo &= ~hwrEZ328IntLoRTC; // no events, so clear interrupt } // Update the interrupt pending register. WRITE_REGISTER (intPendingLo, intPendingLo); // Respond to the new interrupt state. EmRegsEZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::IDDetectAsserted // --------------------------------------------------------------------------- // cf. HwrIdentifyFeatures and HwrPreRAMInit. Bool EmRegsEZ::IDDetectAsserted (void) { uint8 portGDir = READ_REGISTER(portGDir); uint8 portGData = READ_REGISTER(portGData); uint8 portGPullupEn = READ_REGISTER(portGPullupEn); uint8 portGSelect = READ_REGISTER(portGSelect); const uint8 kMask = hwrEZPortGIDDetect; return (portGDir & kMask) == kMask && (portGData & kMask) == 0 && (portGPullupEn & kMask) == 0 && (portGSelect & kMask) == kMask; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetHardwareID // --------------------------------------------------------------------------- UInt8 EmRegsEZ::GetHardwareID (void) { // Determine the hardware ID. EmAssert (gSession); EmDevice device = gSession->GetDevice (); long miscFlags = device.HardwareID (); // Reverse map the following: // GHwrMiscFlags = 0; // if ((keyState & hwrEZPortDKbdCol0) == 0) GHwrMiscFlags |= hwrMiscFlagID1; // if ((keyState & hwrEZPortDKbdCol1) == 0) GHwrMiscFlags |= hwrMiscFlagID2; // if ((keyState & hwrEZPortDKbdCol2) == 0) GHwrMiscFlags |= hwrMiscFlagID3; // if ((keyState & hwrEZPortDKbdCol3) == 0) GHwrMiscFlags |= hwrMiscFlagID4; UInt8 keyState = ~0; if ((miscFlags & hwrMiscFlagID1) != 0) keyState &= ~hwrEZPortDKbdCol0; if ((miscFlags & hwrMiscFlagID2) != 0) keyState &= ~hwrEZPortDKbdCol1; if ((miscFlags & hwrMiscFlagID3) != 0) keyState &= ~hwrEZPortDKbdCol2; if ((miscFlags & hwrMiscFlagID4) != 0) keyState &= ~hwrEZPortDKbdCol3; return keyState; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::UARTStateChanged // --------------------------------------------------------------------------- void EmRegsEZ::UARTStateChanged (Bool sendTxData) { EmUARTDragonball::State state (EmUARTDragonball::kUART_DragonballEZ); EmRegsEZ::MarshalUARTState (state); fUART->StateChanged (state, sendTxData); EmRegsEZ::UnmarshalUARTState (state); EmRegsEZ::UpdateUARTInterrupts (state); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::UpdateUARTState // --------------------------------------------------------------------------- void EmRegsEZ::UpdateUARTState (Bool refreshRxData) { EmUARTDragonball::State state (EmUARTDragonball::kUART_DragonballEZ); EmRegsEZ::MarshalUARTState (state); fUART->UpdateState (state, refreshRxData); EmRegsEZ::UnmarshalUARTState (state); EmRegsEZ::UpdateUARTInterrupts (state); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::UpdateUARTInterrupts // --------------------------------------------------------------------------- void EmRegsEZ::UpdateUARTInterrupts (const EmUARTDragonball::State& state) { // Generate the appropriate interrupts. 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) | hwrEZ328IntLoUART); } else { // Clear the UART interrupt. WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) & ~hwrEZ328IntLoUART); } // Respond to the new interrupt state. EmRegsEZ::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::MarshalUARTState // --------------------------------------------------------------------------- void EmRegsEZ::MarshalUARTState (EmUARTDragonball::State& state) { uint16 uControl = READ_REGISTER (uControl); uint16 uBaud = READ_REGISTER (uBaud); uint16 uReceive = READ_REGISTER (uReceive); uint16 uTransmit = READ_REGISTER (uTransmit); uint16 uMisc = READ_REGISTER (uMisc); state.UART_ENABLE = (uControl & hwrEZ328UControlUARTEnable) != 0; state.RX_ENABLE = (uControl & hwrEZ328UControlRxEnable) != 0; state.TX_ENABLE = (uControl & hwrEZ328UControlTxEnable) != 0; state.RX_CLK_CONT = (uControl & hwrEZ328UControlRxClock1xSync) != 0; state.PARITY_EN = (uControl & hwrEZ328UControlParityEn) != 0; state.ODD_EVEN = (uControl & hwrEZ328UControlParityOdd) != 0; state.STOP_BITS = (uControl & hwrEZ328UControlStopBits2) != 0; state.CHAR8_7 = (uControl & hwrEZ328UControlDataBits8) != 0; // state.GPIO_DELTA_ENABLE = (uControl & hwr328UControlGPIODeltaEn) != 0; // 68328 only state.OLD_ENABLE = (uControl & hwrEZ328UControlOldDataEn) != 0; // 68EZ328 only state.CTS_DELTA_ENABLE = (uControl & hwrEZ328UControlCTSDeltaEn) != 0; state.RX_FULL_ENABLE = (uControl & hwrEZ328UControlRxFullEn) != 0; state.RX_HALF_ENABLE = (uControl & hwrEZ328UControlRxHalfEn) != 0; state.RX_RDY_ENABLE = (uControl & hwrEZ328UControlRxRdyEn) != 0; state.TX_EMPTY_ENABLE = (uControl & hwrEZ328UControlTxEmptyEn) != 0; state.TX_HALF_ENABLE = (uControl & hwrEZ328UControlTxHalfEn) != 0; state.TX_AVAIL_ENABLE = (uControl & hwrEZ328UControlTxAvailEn) != 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 & hwrEZ328UBaudGPIOSrcBaudGen) != 0; // 68328 only state.UCLK_DIR = (uBaud & hwrEZ328UBaudUCLKDirOut) != 0; // 68EZ328 only state.BAUD_SRC = (uBaud & hwrEZ328UBaudBaudSrcUCLK) != 0; state.DIVIDE = (uBaud & hwrEZ328UBaudDivider) >> hwrEZ328UBaudDivideBitOffset; state.PRESCALER = (uBaud & hwrEZ328UBaudPrescaler); // Receive register bits // These are all input bits; we set them, not the user. state.RX_FIFO_FULL = (uReceive & hwrEZ328UReceiveFIFOFull) != 0; state.RX_FIFO_HALF = (uReceive & hwrEZ328UReceiveFIFOHalf) != 0; state.DATA_READY = (uReceive & hwrEZ328UReceiveDataRdy) != 0; state.OLD_DATA = (uReceive & hwrEZ328UReceiveOldData) != 0; // 68EZ328 only state.OVRUN = (uReceive & hwrEZ328UReceiveOverrunErr) != 0; state.FRAME_ERROR = (uReceive & hwrEZ328UReceiveFrameErr) != 0; state.BREAK = (uReceive & hwrEZ328UReceiveBreakErr) != 0; state.PARITY_ERROR = (uReceive & hwrEZ328UReceiveParityErr) != 0; state.RX_DATA = (uReceive & hwrEZ328UReceiveData); // Transmitter register bits // We set everything except TX_DATA; the user sets that // value and ONLY that value. state.TX_FIFO_EMPTY = (uTransmit & hwrEZ328UTransmitFIFOEmpty) != 0; state.TX_FIFO_HALF = (uTransmit & hwrEZ328UTransmitFIFOHalf) != 0; state.TX_AVAIL = (uTransmit & hwrEZ328UTransmitTxAvail) != 0; state.SEND_BREAK = (uTransmit & hwrEZ328UTransmitSendBreak) != 0; state.IGNORE_CTS = (uTransmit & hwrEZ328UTransmitIgnoreCTS) != 0; state.BUSY = (uTransmit & hwrEZ328UTransmitBusy) != 0; // 68EZ328 only state.CTS_STATUS = (uTransmit & hwrEZ328UTransmitCTSStatus) != 0; state.CTS_DELTA = (uTransmit & hwrEZ328UTransmitCTSDelta) != 0; state.TX_DATA = (uTransmit & hwrEZ328UTransmitData); // Misc register bits // These are all values the user sets; we just look at them. state.BAUD_TEST = (uMisc & hwrEZ328UMiscBaudTest) != 0; // 68EZ328 only state.CLK_SRC = (uMisc & hwrEZ328UMiscClkSrcUCLK) != 0; state.FORCE_PERR = (uMisc & hwrEZ328UMiscForceParityErr) != 0; state.LOOP = (uMisc & hwrEZ328UMiscLoopback) != 0; state.BAUD_RESET = (uMisc & hwrEZ328UMiscBaudReset) != 0; // 68EZ328 only state.IR_TEST = (uMisc & hwrEZ328UMiscIRTestEn) != 0; // 68EZ328 only state.RTS_CONT = (uMisc & hwrEZ328UMiscRTSThruFIFO) != 0; state.RTS = (uMisc & hwrEZ328UMiscRTSOut) != 0; state.IRDA_ENABLE = (uMisc & hwrEZ328UMiscIRDAEn) != 0; state.IRDA_LOOP = (uMisc & hwrEZ328UMiscLoopIRDA) != 0; state.RX_POL = (uMisc & hwrEZ328UMiscRXPolarityInv) != 0; // 68EZ328 only state.TX_POL = (uMisc & hwrEZ328UMiscTXPolarityInv) != 0; // 68EZ328 only } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::UnmarshalUARTState // --------------------------------------------------------------------------- void EmRegsEZ::UnmarshalUARTState (const EmUARTDragonball::State& state) { uint16 uControl = 0; uint16 uBaud = 0; uint16 uReceive = 0; uint16 uTransmit = 0; uint16 uMisc = 0; if (state.UART_ENABLE) uControl |= hwrEZ328UControlUARTEnable; if (state.RX_ENABLE) uControl |= hwrEZ328UControlRxEnable; if (state.TX_ENABLE) uControl |= hwrEZ328UControlTxEnable; if (state.RX_CLK_CONT) uControl |= hwrEZ328UControlRxClock1xSync; if (state.PARITY_EN) uControl |= hwrEZ328UControlParityEn; if (state.ODD_EVEN) uControl |= hwrEZ328UControlParityOdd; if (state.STOP_BITS) uControl |= hwrEZ328UControlStopBits2; if (state.CHAR8_7) uControl |= hwrEZ328UControlDataBits8; // if (state.GPIO_DELTA_ENABLE)uControl |= hwr328UControlGPIODeltaEn; // 68328 only if (state.OLD_ENABLE) uControl |= hwrEZ328UControlOldDataEn; // 68EZ328 only if (state.CTS_DELTA_ENABLE) uControl |= hwrEZ328UControlCTSDeltaEn; if (state.RX_FULL_ENABLE) uControl |= hwrEZ328UControlRxFullEn; if (state.RX_HALF_ENABLE) uControl |= hwrEZ328UControlRxHalfEn; if (state.RX_RDY_ENABLE) uControl |= hwrEZ328UControlRxRdyEn; if (state.TX_EMPTY_ENABLE) uControl |= hwrEZ328UControlTxEmptyEn; if (state.TX_HALF_ENABLE) uControl |= hwrEZ328UControlTxHalfEn; if (state.TX_AVAIL_ENABLE) uControl |= hwrEZ328UControlTxAvailEn; // 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 |= hwrEZ328UBaudUCLKDirOut; // 68EZ328 only if (state.BAUD_SRC) uBaud |= hwrEZ328UBaudBaudSrcUCLK; uBaud |= (state.DIVIDE << hwrEZ328UBaudDivideBitOffset) & hwrEZ328UBaudDivider; uBaud |= (state.PRESCALER) & hwrEZ328UBaudPrescaler; // Receive register bits // These are all input bits; we set them, not the user. if (state.RX_FIFO_FULL) uReceive |= hwrEZ328UReceiveFIFOFull; if (state.RX_FIFO_HALF) uReceive |= hwrEZ328UReceiveFIFOHalf; if (state.DATA_READY) uReceive |= hwrEZ328UReceiveDataRdy; if (state.OLD_DATA) uReceive |= hwrEZ328UReceiveOldData; // 68EZ328 only if (state.OVRUN) uReceive |= hwrEZ328UReceiveOverrunErr; if (state.FRAME_ERROR) uReceive |= hwrEZ328UReceiveFrameErr; if (state.BREAK) uReceive |= hwrEZ328UReceiveBreakErr; if (state.PARITY_ERROR) uReceive |= hwrEZ328UReceiveParityErr; uReceive |= (state.RX_DATA) & hwrEZ328UReceiveData; // Transmitter register bits // We set everything except TX_DATA; the user sets that // value and ONLY that value. if (state.TX_FIFO_EMPTY) uTransmit |= hwrEZ328UTransmitFIFOEmpty; if (state.TX_FIFO_HALF) uTransmit |= hwrEZ328UTransmitFIFOHalf; if (state.TX_AVAIL) uTransmit |= hwrEZ328UTransmitTxAvail; if (state.SEND_BREAK) uTransmit |= hwrEZ328UTransmitSendBreak; if (state.IGNORE_CTS) uTransmit |= hwrEZ328UTransmitIgnoreCTS; if (state.BUSY) uTransmit |= hwrEZ328UTransmitBusy; // 68EZ328 only if (state.CTS_STATUS) uTransmit |= hwrEZ328UTransmitCTSStatus; if (state.CTS_DELTA) uTransmit |= hwrEZ328UTransmitCTSDelta; uTransmit |= (state.TX_DATA) & hwrEZ328UTransmitData; // Misc register bits // These are all values the user sets; we just look at them. if (state.BAUD_TEST) uMisc |= hwrEZ328UMiscBaudTest; // 68EZ328 only if (state.CLK_SRC) uMisc |= hwrEZ328UMiscClkSrcUCLK; if (state.FORCE_PERR) uMisc |= hwrEZ328UMiscForceParityErr; if (state.LOOP) uMisc |= hwrEZ328UMiscLoopback; if (state.BAUD_RESET) uMisc |= hwrEZ328UMiscBaudReset; // 68EZ328 only if (state.IR_TEST) uMisc |= hwrEZ328UMiscIRTestEn; // 68EZ328 only if (state.RTS_CONT) uMisc |= hwrEZ328UMiscRTSThruFIFO; if (state.RTS) uMisc |= hwrEZ328UMiscRTSOut; if (state.IRDA_ENABLE) uMisc |= hwrEZ328UMiscIRDAEn; if (state.IRDA_LOOP) uMisc |= hwrEZ328UMiscLoopIRDA; if (state.RX_POL) uMisc |= hwrEZ328UMiscRXPolarityInv; // 68EZ328 only if (state.TX_POL) uMisc |= hwrEZ328UMiscTXPolarityInv; // 68EZ328 only WRITE_REGISTER (uControl, uControl); WRITE_REGISTER (uBaud, uBaud); WRITE_REGISTER (uReceive, uReceive); WRITE_REGISTER (uTransmit, uTransmit); WRITE_REGISTER (uMisc, uMisc); } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::GetPort // --------------------------------------------------------------------------- // Given an address, return a value indicating what port it is associated with. int EmRegsEZ::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'; } EmAssert (false); return 0; } // --------------------------------------------------------------------------- // ¥ EmRegsEZ::PrvGetPalette // --------------------------------------------------------------------------- void EmRegsEZ::PrvGetPalette (RGBList& thePalette) { // !!! TBD Preference pref1 (kPrefKeyBackgroundColor); Preference pref2 (kPrefKeyHighlightColor); RGBType foreground (0, 0, 0); RGBType background; if (this->GetLCDBacklightOn ()) { if (pref2.Loaded ()) background = *pref2; else background = ::SkinGetHighlightColor (); } else { if (pref1.Loaded ()) background = *pref1; else background = ::SkinGetBackgroundColor (); } long br = ((long) background.fRed); long bg = ((long) background.fGreen); long bb = ((long) background.fBlue); long dr = ((long) foreground.fRed) - ((long) background.fRed); long dg = ((long) foreground.fGreen) - ((long) background.fGreen); long db = ((long) foreground.fBlue) - ((long) background.fBlue); int32 bpp = 1 << (READ_REGISTER (lcdPanelControl) & 0x03); int32 numColors = 1 << bpp; thePalette.resize (numColors); for (int color = 0; color < numColors; ++color) { thePalette[color].fRed = (UInt8) (br + dr * color / (numColors - 1)); thePalette[color].fGreen = (UInt8) (bg + dg * color / (numColors - 1)); thePalette[color].fBlue = (UInt8) (bb + db * color / (numColors - 1)); } }