/* -*- 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 "EmRegs328.h" #include "EmRegs328Prv.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 "Hordes.h" // Hordes::IsOn #include "Logging.h" // LogAppendMsg #include "Miscellaneous.h" // GetHostTime #include "PreferenceMgr.h" // Preference #include "SessionFile.h" // WriteHwrDBallType, 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 hwrTD1PortENoBacklight 0x80 // (H) high if no backlight present #undef NON_PORTABLE #include "PalmPackPop.h" /* This file controls the emulation of the Dragonball registers. As a subclass of EmRegs, EmRegs328 registers with EmBankRegs for control of the memory range 0xFFFFF000 to 0xFFFFFB14. If an application accesses a memory location in that range, EmBankRegs calls on of the Set/GetLong/Word/Byte methods of this class. EmRegs328 provides handlers when particular memory addresses are accessed. For instance, if the UART TX register is written to, EmRegs328 will arrange for any data byte to be sent out the host computer's serial port. If the UART RX register is read, EmRegs328 will respond with any byte in the buffer that contains data received from the host computer's serial port. Not all Dragonball registers are emulated the same way as on an actual device. Some registers control hardware that exists on the device only, there being no analog on the host computer. For those registers, simple handlers are installed that write the specified value to the register and return that value later when the register is read. Other registers require extensive support. The UART registers are examples of that, as the above text indicates. In the Palm OS source code, the Dragonball registers are represented by th HwrM68328Type data type. We use this same type in Poser to provide the "backing memory" for the registers. That is, if some emulated code writes to a Dragonball register, we store that value in a variable of type HwrM68328Type. (Note that there's really no guarantee that the compiler used to build Poser will lay out the fields of HwrM68328Type in the same way expected by the Palm OS. Poser has a mechanism for creating buffers with fields that have the same layout as Palm OS-defined structs (see EmPalmStructs.h). However, using that mechanism in this module is deadly to performance. In particular, the Cycle method is called after every opcode is executed, and making that method go through the indirection and byteswapping required by the EmPalmStructs facilities totally kills performance. In one test, a Gremlins run increased from 1m 24s to 1m 56s, or by about 30%. With targetted caching of the fields used in Cycle, we can regain most of that performance. However, not all the performance is regained, and the resulting code is not very maintainable.) */ #define hwr328chipID328 0x33 #define hwr328maskID1H58B 0x30 static const uint32 ADDRESS_MASK = 0x0000FFF0; #define PRINTF if (1) ; else LogAppendMsg // Values used to initialize the DragonBall registers. const HwrM68328Type kInitial68328RegisterValues = { 0x0C, // Byte scr; // $000: System Control Register { 0,0,0 }, // Byte ___filler0[0x004-0x001]; // The following ID stuff is not present on earlier chips (before ??) hwr328chipID328, // Byte chipID; // $004: Chip ID Register hwr328maskID1H58B, // Byte maskID; // $005: Mask ID Register 0x00, // Word swID; // $006: Software ID 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 }, // 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 0x0000, // Word csAGroupMask; // $108: Chip Select Group A Mask Register 0x0000, // Word csBGroupMask; // $10A: Chip Select Group B Mask Register 0x0000, // Word csCGroupMask; // $10C: Chip Select Group C Mask Register 0x0000, // Word csDGroupMask; // $10E: Chip Select Group D Mask Register 0x00010006, // DWord csASelect0; // $110: Group A Chip Select 0 Register 0x00010006, // DWord csASelect1; // $114: Group A Chip Select 1 Register 0x00010006, // DWord csASelect2; // $118: Group A Chip Select 2 Register 0x00010006, // DWord csASelect3; // $11C: Group A Chip Select 3 Register 0x00000000, // DWord csBSelect0; // $120: Group B Chip Select 0 Register 0x00000000, // DWord csBSelect1; // $124: Group B Chip Select 1 Register 0x00000000, // DWord csBSelect2; // $128: Group B Chip Select 2 Register 0x00000000, // DWord csBSelect3; // $12C: Group B Chip Select 3 Register 0x00010006, // DWord csCSelect0; // $130: Group C Chip Select 0 Register 0x00010006, // DWord csCSelect1; // $134: Group C Chip Select 1 Register 0x00010006, // DWord csCSelect2; // $138: Group C Chip Select 2 Register 0x00010006, // DWord csCSelect3; // $13C: Group C Chip Select 3 Register 0x00000000, // DWord csDSelect0; // $140: Group D Chip Select 0 Register 0x00000000, // DWord csDSelect1; // $144: Group D Chip Select 1 Register 0x00000000, // DWord csDSelect2; // $148: Group D Chip Select 2 Register 0x00000000, // DWord csDSelect3; // $14C: Group D Chip Select 3 Register 0x0000, // Word csDebug; // $150: Chip Select debug 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 }, // Byte ___filler2[0x200-0x152]; 0x2400, // Word pllControl; // $200: PLL Control Register 0x0123, // Word pllFreqSel; // $202: PLL Frequency Select Register 0x0000, // Word pllTest; // $204: PLL Test Register 0x0000, // Byte __filler44; 0x1F, // Byte pwrControl; // $207: Power 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 }, // 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 0x00FF, // Word intWakeupEnHi; // $308: Interrupt Wakeup Enable Register 0xFFFF, // Word intWakeupEnLo; // $30A: Interrupt Wakeup Enable Register 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 { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,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 ___filler4a[0x400-0x314]; 0x00, // Byte portADir; // $400: Port A Direction Register 0x00, // Byte portAData; // $401: Port A Data Register 0x00, // Byte ___filler5; 0x00, // Byte portASelect; // $403: Port A Select Register { 0,0,0,0 }, // Byte ___filler6[4]; 0x00, // Byte portBDir; // $408: Port B Direction Register 0x00, // Byte portBData; // $409: Port B Data Register 0x00, // Byte ___filler7; 0x00, // Byte portBSelect; // $40B: Port B Select Register { 0,0,0,0 }, // Byte ___filler8[4]; 0x00, // Byte portCDir; // $410: Port C Direction Register 0x00, // Byte portCData; // $411: Port C Data Register 0x00, // Byte ___filler9; 0x00, // 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 0x00, // Byte ___filler11; 0x00, // Byte portDPolarity; // $41C: Port D Polarity Register 0x00, // Byte portDIntReqEn; // $41D: Port D Interrupt Request Enable 0x00, // Byte ___filler12; 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 0x80, // Byte portEPullupEn; // $422: Port E Pull-up Enable 0x80, // 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 portFPullupEn; // $42A: Port F Pull-up Enable 0xFF, // 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 0xFF, // Byte portGPullupEn; // $432: Port G Pull-up Enable 0xFF, // Byte portGSelect; // $433: Port G Select Register { 0,0,0,0 }, // Byte ___filler18[4]; 0x00, // Byte portJDir; // $438: Port J Direction Register 0x00, // Byte portJData; // $439: Port J Data Register 0x00, // Byte ___filler19; 0x00, // Byte portJSelect; // $43B: Port J Select Register { 0,0,0,0 }, // Byte ___filler19a[4]; 0x00, // Byte portKDir; // $440: Port K Direction Register 0x00, // Byte portKData; // $441: Port K Data Register 0x3F, // Byte portKPullupEn; // $442: Port K Pull-up Enable 0x3F, // Byte portKSelect; // $443: Port K Select Register { 0,0,0,0 }, // Byte ___filler21[4]; 0x00, // Byte portMDir; // $448: Port M Direction Register 0x00, // Byte portMData; // $449: Port M Data Register 0xFF, // Byte portMPullupEn; // $44A: Port M Pull-up Enable Register 0x02, // Byte portMSelect; // $44B: Port M Select Register { 0,0,0,0 }, // Byte ___filler22[4]; { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 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 ___filler23[0x500-0x450]; 0x0000, // Word pwmControl; // $500: PWM Control Register 0x0000, // Word pwmPeriod; // $502: PWM Period Register 0x0000, // Word pwmWidth; // $504: PWM Width Register 0x0000, // Word pwmCounter; // $506: 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 }, // Byte ___filler24[0x600-0x508]; 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 0x0000, // Word tmr2Control; // $60C: Timer 2 Control Register 0x0000, // Word tmr2Prescaler; // $60E: Timer 2 Prescaler Register 0xFFFF, // Word tmr2Compare; // $610: Timer 2 Compare Register 0x0000, // Word tmr2Capture; // $612: Timer 2 Capture Register 0x0000, // Word tmr2Counter; // $614: Timer 2 Counter Register 0x0000, // Word tmr2Status; // $616: Timer 2 Status Register 0x0000, // Word wdControl; // $618: Watchdog Control Register 0x0000, // Word wdReference; // $61A: Watchdog Reference Register 0x0000, // Word wdCounter; // $61C: Watchdog 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 }, // Byte ___filler25[0x700-0x61E]; 0x0000, // Word spiSlave; // $700: SPI Slave 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 }, // Byte ___filler26[0x800-0x702]; 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 { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,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-0x90A]; 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; 0x3E, // Byte lcdLastBufferAddr; // $A29: Last Buffer Address Register 0x00, // Byte ___filler37; 0x3F, // Byte lcdOctetTermCount; // $A2B: Octet Terminal Count Register 0x00, // Byte ___filler38; 0x00, // Byte lcdPanningOffset; // $A2D: Panning Offset Register { 0,0,0 }, // Byte ___filler39[3]; 0xB9, // Byte lcdFrameRate; // $A31: Frame Rate Control Modulation Register 0x1073, // Word lcdGrayPalette; // $A32: Gray Palette Mapping Register 0x00, // Byte lcdReserved; // $A34: Reserved { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,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-0xA35]; 0x00000000, // DWord rtcHourMinSec; // $B00: RTC Hours, Minutes, Seconds Register 0x00000000, // DWord rtcAlarm; // $B04: RTC Alarm Register 0x00000000, // DWord rtcReserved; // $B08: RTC Reserved 0x0000, // Word rtcControl; // $B0C: RTC Control Register 0x0000, // Word rtcIntStatus; // $B0E: RTC Interrupt Status Register 0x0000, // Word rtcIntEnable; // $B10: RTC Interrupt Enable Register 0x0000 // Word stopWatch; // $B12: Stopwatch Minutes }; // --------------------------------------------------------------------------- // ¥ EmRegs328::EmRegs328 // --------------------------------------------------------------------------- EmRegs328::EmRegs328 (void) : EmRegs (), f68328Regs (), fHotSyncButtonDown (0), fTmr2CurrentMilliseconds (0), fTmr2StartMilliseconds (0), fKeyBits (0), fLastTmr1Status (0), fLastTmr2Status (0), fPortDEdge (0), fPortDDataCount (0), fHour (0), fMin (0), fSec (0), fTick (0), fCycle (0), fUART (NULL) { } // --------------------------------------------------------------------------- // ¥ EmRegs328::~EmRegs328 // --------------------------------------------------------------------------- EmRegs328::~EmRegs328 (void) { } // --------------------------------------------------------------------------- // ¥ EmRegs328::Initialize // --------------------------------------------------------------------------- void EmRegs328::Initialize (void) { EmRegs::Initialize (); fUART = new EmUARTDragonball (EmUARTDragonball::kUART_Dragonball, 0); } // --------------------------------------------------------------------------- // ¥ EmRegs328::Reset // --------------------------------------------------------------------------- void EmRegs328::Reset (Bool hardwareReset) { EmRegs::Reset (hardwareReset); if (hardwareReset) { f68328Regs = kInitial68328RegisterValues; // Byteswap all the words in the Dragonball registers (if necessary). Canonical (f68328Regs); ByteswapWords (&f68328Regs, sizeof(f68328Regs)); fKeyBits = 0; fLastTmr1Status = 0; fLastTmr2Status = 0; fPortDEdge = 0; fPortDDataCount = 0; // React to the new data in the UART registers. Bool sendTxData = false; EmRegs328::UARTStateChanged (sendTxData); } } // --------------------------------------------------------------------------- // ¥ EmRegs328::Save // --------------------------------------------------------------------------- void EmRegs328::Save (SessionFile& f) { EmRegs::Save (f); StWordSwapper swapper1 (&f68328Regs, sizeof(f68328Regs)); f.WriteHwrDBallType (f68328Regs); f.FixBug (SessionFile::kBugByteswappedStructs); const long kCurrentVersion = 4; Chunk chunk; EmStreamChunk s (chunk); s << kCurrentVersion; s << fHotSyncButtonDown; s << fLastTmr1Status; s << fLastTmr2Status; s << fPortDEdge; // Added in version 2. s << fKeyBits; // Added in version 3. s << fHour; s << fMin; s << fSec; s << fTick; s << fCycle; // Added in version 4. s << fPortDDataCount; f.WriteDBallState (chunk); } // --------------------------------------------------------------------------- // ¥ EmRegs328::Load // --------------------------------------------------------------------------- void EmRegs328::Load (SessionFile& f) { EmRegs::Load (f); if (f.ReadHwrDBallType (f68328Regs)) { // 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 (f68328Regs); } ByteswapWords (&f68328Regs, sizeof(f68328Regs)); // React to the new data in the UART registers. Bool sendTxData = false; EmRegs328::UARTStateChanged (sendTxData); // Reset gMemAccessFlags.fProtect_SRAMSet gMemAccessFlags.fProtect_SRAMSet = (READ_REGISTER (csASelect1) & 0x0008) != 0; } else { f.SetCanReload (false); } Chunk chunk; if (f.ReadDBallState (chunk)) { long version; EmStreamChunk s (chunk); s >> version; if (version >= 1) { s >> fHotSyncButtonDown; s >> fTmr2CurrentMilliseconds; s >> fTmr2StartMilliseconds; s >> fLastTmr1Status; s >> fLastTmr2Status; s >> fPortDEdge; } if (version >= 2) { s >> fKeyBits; } if (version >= 3) { s >> fHour; s >> fMin; s >> fSec; s >> fTick; s >> fCycle; } if (version >= 4) { s >> fPortDDataCount; } } else { f.SetCanReload (false); } } // --------------------------------------------------------------------------- // ¥ EmRegs328::Dispose // --------------------------------------------------------------------------- void EmRegs328::Dispose (void) { delete fUART; fUART = NULL; EmRegs::Dispose (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::SetSubBankHandlers // --------------------------------------------------------------------------- void EmRegs328::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, StdWrite, csAGroupMask); INSTALL_HANDLER (StdRead, StdWrite, csBGroupMask); INSTALL_HANDLER (StdRead, StdWrite, csCGroupMask); INSTALL_HANDLER (StdRead, StdWrite, csDGroupMask); INSTALL_HANDLER (StdRead, StdWrite, csASelect0); INSTALL_HANDLER (StdRead, csASelect1Write, csASelect1); INSTALL_HANDLER (StdRead, StdWrite, csASelect2); INSTALL_HANDLER (StdRead, StdWrite, csASelect3); INSTALL_HANDLER (StdRead, StdWrite, csBSelect0); INSTALL_HANDLER (StdRead, StdWrite, csBSelect1); INSTALL_HANDLER (StdRead, StdWrite, csBSelect2); INSTALL_HANDLER (StdRead, StdWrite, csBSelect3); INSTALL_HANDLER (StdRead, csCSelect0Write, csCSelect0); INSTALL_HANDLER (StdRead, csCSelect1Write, csCSelect1); INSTALL_HANDLER (StdRead, StdWrite, csCSelect2); INSTALL_HANDLER (StdRead, StdWrite, csCSelect3); INSTALL_HANDLER (StdRead, StdWrite, csDSelect0); INSTALL_HANDLER (StdRead, StdWrite, csDSelect1); INSTALL_HANDLER (StdRead, StdWrite, csDSelect2); INSTALL_HANDLER (StdRead, StdWrite, csDSelect3); INSTALL_HANDLER (StdRead, StdWrite, csDebug); 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, StdWrite, intWakeupEnHi); INSTALL_HANDLER (StdRead, StdWrite, intWakeupEnLo); 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, portASelect); INSTALL_HANDLER (StdRead, StdWrite, portBDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portBData); INSTALL_HANDLER (StdRead, StdWrite, portBSelect); INSTALL_HANDLER (StdRead, StdWrite, portCDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portCData); INSTALL_HANDLER (StdRead, StdWrite, portCSelect); INSTALL_HANDLER (StdRead, StdWrite, portDDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portDData); INSTALL_HANDLER (StdRead, StdWrite, portDPullupEn); INSTALL_HANDLER (StdRead, StdWrite, portDPolarity); INSTALL_HANDLER (StdRead, portDIntReqEnWrite, portDIntReqEn); 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, portFPullupEn); 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, portJSelect); INSTALL_HANDLER (StdRead, StdWrite, portKDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portKData); INSTALL_HANDLER (StdRead, StdWrite, portKPullupEn); INSTALL_HANDLER (StdRead, StdWrite, portKSelect); INSTALL_HANDLER (StdRead, StdWrite, portMDir); INSTALL_HANDLER (portXDataRead, portXDataWrite, portMData); INSTALL_HANDLER (StdRead, StdWrite, portMPullupEn); INSTALL_HANDLER (StdRead, StdWrite, portMSelect); INSTALL_HANDLER (StdRead, StdWrite, pwmControl); INSTALL_HANDLER (StdRead, StdWrite, pwmPeriod); INSTALL_HANDLER (StdRead, StdWrite, pwmWidth); 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, 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, wdControl); INSTALL_HANDLER (StdRead, StdWrite, wdReference); INSTALL_HANDLER (StdRead, wdCounterWrite, wdCounter); INSTALL_HANDLER (StdRead, StdWrite, spiSlave); 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 (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, lcdLastBufferAddr); INSTALL_HANDLER (StdRead, StdWrite, lcdOctetTermCount); INSTALL_HANDLER (StdRead, StdWrite, lcdPanningOffset); INSTALL_HANDLER (StdRead, StdWrite, lcdFrameRate); INSTALL_HANDLER (StdRead, StdWrite, lcdGrayPalette); INSTALL_HANDLER (StdRead, StdWrite, lcdReserved); INSTALL_HANDLER (rtcHourMinSecRead, StdWrite, rtcHourMinSec); INSTALL_HANDLER (StdRead, StdWrite, rtcAlarm); INSTALL_HANDLER (StdRead, StdWrite, rtcReserved); INSTALL_HANDLER (StdRead, rtcControlWrite, rtcControl); INSTALL_HANDLER (StdRead, rtcIntStatusWrite, rtcIntStatus); INSTALL_HANDLER (StdRead, rtcIntEnableWrite, rtcIntEnable); INSTALL_HANDLER (StdRead, StdWrite, stopWatch); } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetRealAddress // --------------------------------------------------------------------------- uint8* EmRegs328::GetRealAddress (emuptr address) { uint8* loc = ((uint8*) &f68328Regs) + (address - kMemoryStart); return loc; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetAddressStart // --------------------------------------------------------------------------- emuptr EmRegs328::GetAddressStart (void) { return kMemoryStart; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetAddressRange // --------------------------------------------------------------------------- uint32 EmRegs328::GetAddressRange (void) { COMPILE_TIME_ASSERT (kMemorySize == 0x0B14); return kMemorySize; } // --------------------------------------------------------------------------- // ¥ EmRegs328::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. #if 0 static int calibrated; static int increment; static int timesCalled; static uint32 startingTime; static void PrvCalibrate (uint16 tmrCompare) { // Calibrate the the value by which we increment the counter. // The counter is set up so that it times out after 10 milliseconds // so that it can increment the Palm OS's tick counter 100 times // a second. We would like tmrCounter to surpass tmrCompare // after 10 milliseconds. So figure out by how much we need to // increment it in order for that to happen. // If timer is disabled; reset calibration. if (tmrCompare == 0xFFFF) { startingTime = 0; } // If timer is enabled, restart calibration. else if (startingTime == 0) { startingTime = Platform::GetMilliseconds(); timesCalled = 0; increment = 1; } // If calibration is started, continue it. else { timesCalled++; uint32 now = Platform::GetMilliseconds(); if (now - startingTime > 100) { calibrated = true; increment = tmrCompare / (timesCalled / 10); } } } #endif void EmRegs328::Cycle (Bool sleeping) { #if 0 // Cycle is *very* sensitive to timing issue. With this section // of code, a Gremlins run can slow down by 5%. if (!calibrated) { ::PrvCalibrate (READ_REGISTER (tmr2Compare)); } #else #if _DEBUG #define increment 20 #else #define increment 4 #endif #endif // Determine whether timer 2 is enabled. if ((READ_REGISTER (tmr2Control) & hwr328TmrControlEnable) != 0) { // 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) | hwr328TmrStatusCompare); // If the Free Run/Restart flag is not set, clear the counter. if ((READ_REGISTER (tmr2Control) & hwr328TmrControlFreeRun) == 0) { WRITE_REGISTER (tmr2Counter, 0); } // If the timer interrupt is enabled, post an interrupt. if ((READ_REGISTER (tmr2Control) & hwr328TmrControlEnInterrupt) != 0) { WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) | hwr328IntLoTimer2); EmRegs328::UpdateInterrupts (); } } } if ((fCycle += increment) > READ_REGISTER (tmr2Compare)) { fCycle = 0; if (++fTick >= 100) { fTick = 0; if (++fSec >= 60) { fSec = 0; if (++fMin >= 60) { fMin = 0; if (++fHour >= 24) { fHour = 0; } } } } } } // --------------------------------------------------------------------------- // ¥ EmRegs328::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 EmRegs328::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) { EmRegs328::HotSyncEvent (event.fButtonIsDown); } else { EmRegs328::ButtonEvent (event.fButton, event.fButtonIsDown); } } // See if there's anything new ("Put the data on the bus") EmRegs328::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) & hwr328RTCIntEnableAlarm) != 0 && (READ_REGISTER (rtcIntStatus) & hwr328RTCIntStatusAlarm) == 0) { uint32 rtcAlarm = READ_REGISTER (rtcAlarm); long almHour = (rtcAlarm & hwr328RTCAlarmHoursMask) >> hwr328RTCAlarmHoursOffset; long almMin = (rtcAlarm & hwr328RTCAlarmMinutesMask) >> hwr328RTCAlarmMinutesOffset; long almSec = (rtcAlarm & hwr328RTCAlarmSecondsMask) >> hwr328RTCAlarmSecondsOffset; 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) | hwr328RTCIntStatusAlarm); EmRegs328::UpdateRTCInterrupts (); } } } // --------------------------------------------------------------------------- // ¥ EmRegs328::TurnSoundOff // --------------------------------------------------------------------------- void EmRegs328::TurnSoundOff (void) { uint16 pwmControl = READ_REGISTER (pwmControl); WRITE_REGISTER (pwmControl, pwmControl & ~hwr328PWMControlEnable); } // --------------------------------------------------------------------------- // ¥ EmRegs328::ResetTimer // --------------------------------------------------------------------------- void EmRegs328::ResetTimer (void) { WRITE_REGISTER (tmr2Counter, 0); } // --------------------------------------------------------------------------- // ¥ EmRegs328::ResetRTC // --------------------------------------------------------------------------- void EmRegs328::ResetRTC (void) { fHour = 15; fMin = 0; fSec = 0; fTick = 0; fCycle = 0; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetInterruptLevel // --------------------------------------------------------------------------- int32 EmRegs328::GetInterruptLevel (void) { uint16 intStatusHi = READ_REGISTER (intStatusHi); uint16 intStatusLo = READ_REGISTER (intStatusLo); // Level 7 = IRQ7. if ((intStatusHi & hwr328IntHiNMI) != 0) return 7; // Level 6 = SPIS, TMR1, IRQ6. if ((intStatusHi & (hwr328IntHiTimer1 | hwr328IntHiSPIS | hwr328IntHiIRQ6)) != 0) return 6; // Level 5 = PEN. if ((intStatusHi & hwr328IntHiPen) != 0) return 5; // Level 4 = SPIM, TMR2, UART, WDT, RTC, KB, PWM, INT0 - INT7. if ((intStatusLo & ( hwr328IntLoAllKeys | hwr328IntLoPWM | hwr328IntLoKbd | // hwr328IntLoLCDC | hwr328IntLoRTC | hwr328IntLoWDT | hwr328IntLoTimer2 | hwr328IntLoSPIM)) != 0) return 4; // Level 3 = IRQ3. if ((intStatusHi & hwr328IntHiIRQ3) != 0) return 3; // Level 2 = IRQ2. if ((intStatusHi & hwr328IntHiIRQ2) != 0) return 2; // Level 1 = IRQ1. if ((intStatusHi & hwr328IntHiIRQ1) != 0) return 1; // Level 0. return -1; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetInterruptBase // --------------------------------------------------------------------------- int32 EmRegs328::GetInterruptBase (void) { return READ_REGISTER (intVector) & 0xF8; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetLCDHasFrame // --------------------------------------------------------------------------- Bool EmRegs328::GetLCDHasFrame (void) { return false; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetLCDBeginEnd // --------------------------------------------------------------------------- void EmRegs328::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; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetLCDScanlines // --------------------------------------------------------------------------- void EmRegs328::GetLCDScanlines (EmScreenUpdateInfo& info) { // Get the screen metrics. int32 bpp = 1 << (READ_REGISTER (lcdPanelControl) & 0x01); int32 width = READ_REGISTER (lcdScreenWidth) + 1; 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); } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetUARTDevice // --------------------------------------------------------------------------- // Return what sort of device is hooked up to the given UART. EmUARTDeviceType EmRegs328::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; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetDynamicHeapSize // --------------------------------------------------------------------------- int32 EmRegs328::GetDynamicHeapSize (void) { uint32 result = 0; uint32 csCSelect0 = READ_REGISTER (csCSelect0) & ADDRESS_MASK; uint32 csCSelect1 = READ_REGISTER (csCSelect1) & ADDRESS_MASK; if (csCSelect0 == 0x0000 && csCSelect1 == 0x0000) { result = 0 * 1024L; } else if (csCSelect0 == 0x0070 && csCSelect1 == 0x0000) { result = 32 * 1024L; } else if (csCSelect0 == 0x00F0 && csCSelect1 == 0x0000) { result = 64 * 1024L; } else if (csCSelect0 == 0x0070 && csCSelect1 == 0x0070) { // This one's odd, but the Symbol seems to (temporarily) // set up this configuration when running with 2Meg of RAM. result = 96 * 1024L; } else if (csCSelect0 == 0x00F0 && csCSelect1 == 0x0070) { result = 96 * 1024L; } else if (csCSelect0 == 0x01F0 && csCSelect1 == 0x0000) { result = 128 * 1024L; } else if (csCSelect0 == 0x03F0 && csCSelect1 == 0x0000) { result = 256 * 1024L; } else { EmAssert (false); } if (!ChipSelectsConfigured()) { result = 16 * 1024L * 1024L; } return result; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetROMSize // --------------------------------------------------------------------------- int32 EmRegs328::GetROMSize (void) { uint32 result = 2 * 1024L * 1024L; return result; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetROMBaseAddress // --------------------------------------------------------------------------- emuptr EmRegs328::GetROMBaseAddress (void) { if (!this->ChipSelectsConfigured()) { return 0xFFFFFFFF; } return 0x10C00000; // use known value } // --------------------------------------------------------------------------- // ¥ EmRegs328::ChipSelectsConfigured // --------------------------------------------------------------------------- Bool EmRegs328::ChipSelectsConfigured (void) { return READ_REGISTER (csAGroupBase) & 0x0001; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetSystemClockFrequency // --------------------------------------------------------------------------- int32 EmRegs328::GetSystemClockFrequency (void) { uint16 pllControl = READ_REGISTER (pllControl); uint16 pllFreqSel = READ_REGISTER (pllFreqSel); uint16 PC = (pllFreqSel & 0x00FF); uint16 QC = (pllFreqSel & 0x0F00) >> 8; uint32 result = 32768L * (14 * (PC + 1) + QC + 1); // Divide by the system clock scaler, if needed. switch (pllControl & 0x0F00) { case hwr328PLLControlSysVCODiv2: result /= 2; break; case hwr328PLLControlSysVCODiv4: result /= 4; break; case hwr328PLLControlSysVCODiv8: result /= 8; break; case hwr328PLLControlSysVCODiv16: result /= 16; break; } return result; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetCanStop // --------------------------------------------------------------------------- Bool EmRegs328::GetCanStop (void) { // Make sure Timer 2 is enabled or the RTC interrupt is enabled. if ((READ_REGISTER (tmr2Control) & hwr328TmrControlEnable) != 0) return true; if ((READ_REGISTER (rtcIntEnable) & hwr328RTCIntEnableAlarm) != 0) return true; return false; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetAsleep // --------------------------------------------------------------------------- Bool EmRegs328::GetAsleep (void) { return ((READ_REGISTER (pllControl) & hwr328PLLControlDisable) != 0); } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetPortInputValue // --------------------------------------------------------------------------- // Return the GPIO values for the pins on the port. These values are used // if the select pins are high. uint8 EmRegs328::GetPortInputValue (int port) { uint8 result = 0; if (port == 'D') { result = this->GetPortInternalValue (port); } return result; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetPortInternalValue // --------------------------------------------------------------------------- // Return the dedicated values for the pins on the port. These values are // used if the select pins are low. uint8 EmRegs328::GetPortInternalValue (int port) { uint8 result = 0; if (port == 'C') { // This makes the power on key work. If the signal is not asserted, the // unit will not transition between asleep and awake (cf. HwrSleep, HwrWake). result |= hwr328PortCNMI; } else if (port == 'D') { // If the ID_DETECT pin is asserted, load the data lines with the // hardware ID. if (EmRegs328::IDDetectAsserted ()) { result |= EmRegs328::GetHardwareID (); } // Otherwise, load the lines with keyboard information. else { // Get the INT bits that need to be set. result |= this->GetKeyBits (); } } return result; } // --------------------------------------------------------------------------- // ¥ EmRegs328::PortDataChanged // --------------------------------------------------------------------------- void EmRegs328::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 ("EmRegs328::PortDataChanged (D): fPortDEdge = 0x%02lX", (uint32) (uint8) fPortDEdge); PRINTF ("EmRegs328::PortDataChanged (D): portDIntEdge = 0x%02lX", (uint32) (uint8) portDIntEdge); PRINTF ("EmRegs328::PortDataChanged (D): newValue = 0x%02lX", (uint32) (uint8) newValue); fPortDEdge &= ~(newValue & portDIntEdge); PRINTF ("EmRegs328::PortDataChanged (D): fPortDEdge = 0x%02lX", (uint32) (uint8) fPortDEdge); // Set the new interrupt state. EmRegs328::UpdatePortDInterrupts (); } } // --------------------------------------------------------------------------- // ¥ EmRegs328::pllFreqSelRead // --------------------------------------------------------------------------- uint32 EmRegs328::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 EmRegs328::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegs328::portXDataRead // --------------------------------------------------------------------------- uint32 EmRegs328::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); uint8 xsel = sel; uint8 xdir = dir; uint8 xoutput = output; uint8 xinput = input; uint8 xintFn = intFn; if (port == 'D') { sel = 0xFF; // No "select" bit in low nybble, so set for IO values. // The system will poll portD twice 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 >= 2 * 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 ("EmRegs328::portXDataRead: polarity = 0x%02lX", (uint32) polarity); result ^= polarity; } PRINTF ("EmRegs328::port%cDataRead: sel dir output input intFn result", (char) port); PRINTF ("EmRegs328::port%cDataRead: 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX", (char) port, (uint32) xsel, (uint32) xdir, (uint32) xoutput, (uint32) xinput, (uint32) xintFn, (uint32) result); return result; } // --------------------------------------------------------------------------- // ¥ EmRegs328::tmr1StatusRead // --------------------------------------------------------------------------- uint32 EmRegs328::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) | hwr328TmrStatusCompare; WRITE_REGISTER (tmr1Status, tmr1Status); // If it's not a free-running timer, reset it to zero. if ((tmr1Control & hwr328TmrControlFreeRun) == 0) { WRITE_REGISTER (tmr1Counter, 0); } } // Remember this guy for later (see EmRegs328::tmr1StatusWrite()) fLastTmr1Status |= READ_REGISTER (tmr1Status); // Finish up by doing a standard read. return EmRegs328::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegs328::tmr2StatusRead // --------------------------------------------------------------------------- uint32 EmRegs328::tmr2StatusRead (emuptr address, int size) { #if 0 // (Greg doesn't do this for Timer 2...I wonder why) /* ram_rom.cpp: DBReg::tmr2StatusRead: Hmm, I don't update the TMR2 count value. As with everything else that's missing in my DragonBall emulation, it's probably because I never found anything that needed it. If you know otherwise, by all means implement it. Also, the magic value of 16 counts per status read seemed to be about right for the programmed timer 1 frequency. It isn't likely to be right for timer 2. -- Greg */ 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 (tmr1Status) | hwr328TmrStatusCompare; WRITE_REGISTER (tmr2Status, tmr2Status); // If it's not a free-running timer, reset it to zero. if ( (tmr2Control & hwr328TmrControlFreeRun) == 0 ) WRITE_REGISTER (tmr2Counter, 0); } #endif fLastTmr2Status |= READ_REGISTER (tmr2Status); // remember this guy for later (see EmRegs328::tmr2StatusWrite()) // Finish up by doing a standard read. return EmRegs328::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegs328::uartRead // --------------------------------------------------------------------------- uint32 EmRegs328::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") EmRegs328::UpdateUARTState (refreshRxData); // Finish up by doing a standard read. return EmRegs328::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegs328::rtcHourMinSecRead // --------------------------------------------------------------------------- uint32 EmRegs328::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 << hwr328RTCHourMinSecHoursOffset) | (min << hwr328RTCHourMinSecMinutesOffset) | (sec << hwr328RTCHourMinSecSecondsOffset)); // Finish up by doing a standard read. return EmRegs328::StdRead (address, size); } // --------------------------------------------------------------------------- // ¥ EmRegs328::csASelect1Write // --------------------------------------------------------------------------- void EmRegs328::csASelect1Write (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegs328::StdWrite (address, size, value); // Check its new state and update our ram-protect flag. gMemAccessFlags.fProtect_SRAMSet = (READ_REGISTER (csASelect1) & 0x0008) != 0; } // --------------------------------------------------------------------------- // ¥ EmRegs328::csCSelect0Write // --------------------------------------------------------------------------- void EmRegs328::csCSelect0Write (emuptr address, int size, uint32 value) { uint32 csCSelect0 = READ_REGISTER (csCSelect0); // Do a standard update of the register. EmRegs328::StdWrite (address, size, value); // Check to see if the unprotected memory range changed. if ((csCSelect0 & ADDRESS_MASK) != (READ_REGISTER (csCSelect0) & ADDRESS_MASK)) { EmAssert (gSession); gSession->ScheduleResetBanks (); } } // --------------------------------------------------------------------------- // ¥ EmRegs328::csCSelect1Write // --------------------------------------------------------------------------- void EmRegs328::csCSelect1Write (emuptr address, int size, uint32 value) { uint32 csCSelect1 = READ_REGISTER (csCSelect1); // Do a standard update of the register. EmRegs328::StdWrite (address, size, value); // Check to see if the unprotected memory range changed. if ((csCSelect1 & ADDRESS_MASK) != (READ_REGISTER (csCSelect1) & ADDRESS_MASK)) { EmAssert (gSession); gSession->ScheduleResetBanks (); } } // --------------------------------------------------------------------------- // ¥ EmRegs328::intMaskHiWrite // --------------------------------------------------------------------------- void EmRegs328::intMaskHiWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegs328::StdWrite (address, size, value); // Respond to the new interrupt state. EmRegs328::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::intMaskLoWrite // --------------------------------------------------------------------------- void EmRegs328::intMaskLoWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegs328::StdWrite (address, size, value); // Respond to the new interrupt state. EmRegs328::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::intStatusHiWrite // --------------------------------------------------------------------------- void EmRegs328::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 Dragonball 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 (hwr328IntCtlEdge1, hwr328IntHiIRQ1); CLEAR_PENDING_INTERRUPT (hwr328IntCtlEdge2, hwr328IntHiIRQ2); CLEAR_PENDING_INTERRUPT (hwr328IntCtlEdge3, hwr328IntHiIRQ3); CLEAR_PENDING_INTERRUPT (hwr328IntCtlEdge6, hwr328IntHiIRQ6); // IRQ7 is not edge-programmable, so clear it if we're merely writing to it. if (value & hwr328IntHiNMI) { intPendingHi &= ~(hwr328IntHiNMI); } // 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 |= hwr328IntHiIRQ1; } else { intPendingHi &= ~hwr328IntHiIRQ1; } WRITE_REGISTER (intPendingHi, intPendingHi); EmRegs328::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::portXDataWrite // --------------------------------------------------------------------------- void EmRegs328::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 ("EmRegs328::port%cDataWrite: oldValue = 0x%02lX", (char) port, (uint32) (uint8) oldValue); PRINTF ("EmRegs328::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); } // --------------------------------------------------------------------------- // ¥ EmRegs328::portDIntReqEnWrite // --------------------------------------------------------------------------- void EmRegs328::portDIntReqEnWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegs328::StdWrite (address, size, value); // Set the new interrupt state. EmRegs328::UpdatePortDInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::tmr1StatusWrite // --------------------------------------------------------------------------- void EmRegs328::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 EmRegs328::tmr1StatusRead() WRITE_REGISTER (tmr1Status, tmr1Status); fLastTmr1Status = 0; if ((tmr1Status & hwr328TmrStatusCompare) == 0) { uint16 intPendingHi = READ_REGISTER (intPendingHi) & ~hwr328IntHiTimer1; WRITE_REGISTER (intPendingHi, intPendingHi); // Respond to the new interrupt state. EmRegs328::UpdateInterrupts (); } } // --------------------------------------------------------------------------- // ¥ EmRegs328::tmr2StatusWrite // --------------------------------------------------------------------------- void EmRegs328::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 EmRegs328::tmr2StatusRead() WRITE_REGISTER (tmr2Status, tmr2Status); fLastTmr2Status = 0; if ( (tmr2Status & hwr328TmrStatusCompare) == 0 ) { uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwr328IntLoTimer2; WRITE_REGISTER (intPendingLo, intPendingLo); // Respond to the new interrupt state. EmRegs328::UpdateInterrupts (); } } // --------------------------------------------------------------------------- // ¥ EmRegs328::wdCounterWrite // --------------------------------------------------------------------------- void EmRegs328::wdCounterWrite (emuptr address, int size, uint32 value) { UNUSED_PARAM(address) UNUSED_PARAM(size) UNUSED_PARAM(value) // Always set it to zero (a write to this register always resets it). WRITE_REGISTER (wdCounter, 0); } // --------------------------------------------------------------------------- // ¥ EmRegs328::spiMasterControlWrite // --------------------------------------------------------------------------- void EmRegs328::spiMasterControlWrite (emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegs328::StdWrite (address, size, value); // Get the current value. uint16 spiMasterControl = READ_REGISTER (spiMasterControl); // Check to see if data exchange and interrupts are enabled. #define BIT_MASK (hwr328SPIMControlExchange | hwr328SPIMControlIntEnable) if ((spiMasterControl & BIT_MASK) != 0) { // If so, assert the interrupt and clear the exchange bit. spiMasterControl |= hwr328SPIMControlIntStatus; spiMasterControl &= ~hwr328SPIMControlExchange; WRITE_REGISTER (spiMasterControl, spiMasterControl); /* // If we wanted digitizer data, load it into the SPIM data register. switch (READ_REGISTER (portFData) & hwrTD1PortFPanelMask) { case (hwrTD1PortFPanelCfgXMeas): WRITE_REGISTER (spiMasterData, (0xFF - Hardware::fgPen_HorzLocation) * 2); break; case (hwrTD1PortFPanelCfgYMeas): WRITE_REGISTER (spiMasterData, (0xFF - Hardware::fgPen_VertLocation) * 2); break; } */ } } // --------------------------------------------------------------------------- // ¥ EmRegs328::uartWrite // --------------------------------------------------------------------------- void EmRegs328::uartWrite(emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegs328::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. EmRegs328::UARTStateChanged (sendTxData); } // --------------------------------------------------------------------------- // ¥ EmRegs328::lcdRegisterWrite // --------------------------------------------------------------------------- void EmRegs328::lcdRegisterWrite(emuptr address, int size, uint32 value) { // First, get the old value in case we need to see what changed. uint32 oldValue = EmRegs328::StdRead (address, size); // Do a standard update of the register. EmRegs328::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)) { if (((value ^ oldValue) & hwr328LcdPanelControlGrayScale) != 0) { EmScreen::InvalidateAll (); } } else if (address == addressof (lcdStartAddr)) { // Make sure the low-bit is always zero. uint32 lcdStartAddr = READ_REGISTER (lcdStartAddr) & 0xFFFFFFFE; WRITE_REGISTER (lcdStartAddr, lcdStartAddr); EmScreen::InvalidateAll (); } else if (address == addressof (lcdPageWidth)) { if (value != oldValue) { EmScreen::InvalidateAll (); } } } // --------------------------------------------------------------------------- // ¥ EmRegs328::rtcControlWrite // --------------------------------------------------------------------------- void EmRegs328::rtcControlWrite(emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegs328::StdWrite (address, size, value); // Respond to the new interrupt state. EmRegs328::UpdateRTCInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::rtcIntStatusWrite // --------------------------------------------------------------------------- void EmRegs328::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. EmRegs328::UpdateRTCInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::rtcIntEnableWrite // --------------------------------------------------------------------------- void EmRegs328::rtcIntEnableWrite(emuptr address, int size, uint32 value) { // Do a standard update of the register. EmRegs328::StdWrite (address, size, value); // Respond to the new interrupt state. EmRegs328::UpdateRTCInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::ButtonEvent // --------------------------------------------------------------------------- // Handles a Palm device button event by updating the appropriate registers. void EmRegs328::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 ("EmRegs328::ButtonEvent: fKeyBits = 0x%04lX", (uint32) fKeyBits); PRINTF ("EmRegs328::ButtonEvent: oldBits = 0x%02lX", (uint32) oldBits); PRINTF ("EmRegs328::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 ("EmRegs328::ButtonEvent: fPortDEdge = 0x%02lX", (uint32) fPortDEdge); // Set the new interrupt state. EmRegs328::UpdatePortDInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::HotSyncEvent // --------------------------------------------------------------------------- // Handles a HotSync button event by updating the appropriate registers. void EmRegs328::HotSyncEvent (Bool iButton_IsDown) { // If the button changes state, set or clear the HotSync interrupt. uint16 intPendingHi = READ_REGISTER (intPendingHi); if (iButton_IsDown) { intPendingHi |= hwr328IntHiIRQ1; fHotSyncButtonDown = true; } else { intPendingHi &= ~hwr328IntHiIRQ1; fHotSyncButtonDown = false; } WRITE_REGISTER (intPendingHi, intPendingHi); EmRegs328::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetKeyBits // --------------------------------------------------------------------------- uint8 EmRegs328::GetKeyBits (void) { // Return the key bits uint8 portDPullupEn = READ_REGISTER (portDPullupEn); // Interested where bits are one uint8 keyBits = portDPullupEn & fKeyBits; PRINTF ("EmRegs328::GetKeyBits: keyBits = 0x%02lX", (uint32) keyBits); return keyBits; } // --------------------------------------------------------------------------- // ¥ EmRegs328::ButtonToBits // --------------------------------------------------------------------------- uint16 EmRegs328::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; /* // Symbol-specific case kElement_TriggerLeft: bitNumber = keyBitTrigLeft; break; case kElement_TriggerCenter: bitNumber = keyBitTrigCenter; break; case kElement_TriggerRight: bitNumber = keyBitTrigRight; break; case kElement_UpButtonLeft: bitNumber = keyBitPageUpLeft; break; case kElement_UpButtonRight: bitNumber = keyBitPageUpRight; break; case kElement_DownButtonLeft: bitNumber = keyBitPageDownLeft; break; case kElement_DownButtonRight: bitNumber = keyBitPageDownRight; break; */ default: EmAssert (false); } return bitNumber; } // --------------------------------------------------------------------------- // ¥ EmRegs328::UpdateInterrupts // --------------------------------------------------------------------------- // Determines whether an interrupt has occurred by copying the Interrupt // Pending Register to the Interrupt Status Register. void EmRegs328::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. f68328Regs.intStatusHi = f68328Regs.intPendingHi & ~f68328Regs.intMaskHi; f68328Regs.intStatusLo = f68328Regs.intPendingLo & ~f68328Regs.intMaskLo; PRINTF ("EmRegs328::UpdateInterrupts: intMask = 0x%04lX %04lX", (uint32) f68328Regs.intMaskHi, (uint32) f68328Regs.intMaskLo); PRINTF ("EmRegs328::UpdateInterrupts: intPending = 0x%04lX %04lX", (uint32) f68328Regs.intPendingHi, (uint32) f68328Regs.intPendingLo); // If the Interrupt Status Register isn't clear, flag an interrupt. if (f68328Regs.intStatusHi || f68328Regs.intStatusLo) { regs.spcflags |= SPCFLAG_INT; PRINTF ("EmRegs328::UpdateInterrupts: intStatus = 0x%04lX %04lX", (uint32) f68328Regs.intStatusHi, (uint32) f68328Regs.intStatusLo); } } // --------------------------------------------------------------------------- // ¥ EmRegs328::UpdatePortDInterrupts // --------------------------------------------------------------------------- // Determine what interrupts need to be generated based on the current // settings in portDData and fPortDEdge. void EmRegs328::UpdatePortDInterrupts (void) { // Update INT0-INT7 of the Interrupt-Pending register (bits 8-15 of the low word). // First, get those bits and clear them out. uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwr328IntLoAllKeys; // 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 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. 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 ("EmRegs328::UpdatePortDInterrupts: Dir Data Pol Req Edg PDE bits"); PRINTF ("EmRegs328::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); // Merge in the new values and write out the result. intPendingLo |= (((uint16) newBits) << 8) & hwr328IntLoAllKeys; WRITE_REGISTER (intPendingLo, intPendingLo); // Respond to the new interrupt state. EmRegs328::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::UpdateRTCInterrupts // --------------------------------------------------------------------------- // Determine whether to set or clear the RTC bit in the interrupt pending // register based on the current RTC register values. void EmRegs328::UpdateRTCInterrupts (void) { // See if the RTC is enabled. Bool rtcEnabled = (READ_REGISTER (rtcControl) & hwr328RTCControlRTCEnable) != 0; // See if there are any RTC events that need to trigger an interrupt. #define BITS_TO_CHECK ( \ hwr328RTCIntEnableSec | \ hwr328RTCIntEnable24Hr | \ hwr328RTCIntEnableAlarm | \ hwr328RTCIntEnableMinute | \ hwr328RTCIntEnableStopWatch ) 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 |= hwr328IntLoRTC; // have events, so set interrupt } else { intPendingLo &= ~hwr328IntLoRTC; // no events, so clear interrupt } // Update the interrupt pending register. WRITE_REGISTER (intPendingLo, intPendingLo); // Respond to the new interrupt state. EmRegs328::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::IDDetectAsserted // --------------------------------------------------------------------------- // cf. HwrIdentifyFeatures and HwrPreRAMInit. Bool EmRegs328::IDDetectAsserted (void) { uint8 portEDir = READ_REGISTER (portEDir); uint8 portEData = READ_REGISTER (portEData); uint8 portEPullupEn = READ_REGISTER (portEPullupEn); const uint8 kMask = hwrTD1PortENoBacklight; return (portEDir & kMask) == kMask && (portEData & kMask) == 0 && (portEPullupEn & kMask) == 0; } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetHardwareID // --------------------------------------------------------------------------- UInt8 EmRegs328::GetHardwareID (void) { // Determine the hardware ID. // Note: Because of a Poser bug, I don't think any of the following actually // gets executed. 328 ROMs first check to see if they're on a PalmPilot // by executing the following: // // if (!(baseP->portEData & hwrTD1PortENoBacklight)) { // ...on PalmPilot... // } else { // ...execute ID DETECT... // } // // In Poser, hwrTD1PortENoBacklight is always zero (that's the bug), and // so we always think we're on a PalmPilot, regardless of what 328 device // we selected. EmAssert (gSession); EmDevice device = gSession->GetDevice (); long miscFlags = device.HardwareID (); // Reverse map the following: // GHwrMiscFlags = 0; // if ( (keyState & keyBitHard1) == 0) GHwrMiscFlags |= hwrMiscFlagID1; // if ( (keyState & keyBitHard2) == 0) GHwrMiscFlags |= hwrMiscFlagID2; // if ( (keyState & keyBitHard3) == 0) GHwrMiscFlags |= hwrMiscFlagID3; // if ( (keyState & keyBitHard4) == 0) GHwrMiscFlags |= hwrMiscFlagID4; uint8 keyState = ~0; if ((miscFlags & hwrMiscFlagID1) != 0) keyState &= ~keyBitHard1; if ((miscFlags & hwrMiscFlagID2) != 0) keyState &= ~keyBitHard2; if ((miscFlags & hwrMiscFlagID3) != 0) keyState &= ~keyBitHard3; if ((miscFlags & hwrMiscFlagID4) != 0) keyState &= ~keyBitHard4; return keyState; } // --------------------------------------------------------------------------- // ¥ EmRegs328::UARTStateChanged // --------------------------------------------------------------------------- void EmRegs328::UARTStateChanged (Bool sendTxData) { EmUARTDragonball::State state (EmUARTDragonball::kUART_Dragonball); EmRegs328::MarshalUARTState (state); fUART->StateChanged (state, sendTxData); EmRegs328::UnmarshalUARTState (state); EmRegs328::UpdateUARTInterrupts (state); } // --------------------------------------------------------------------------- // ¥ EmRegs328::UpdateUARTState // --------------------------------------------------------------------------- void EmRegs328::UpdateUARTState (Bool refreshRxData) { EmUARTDragonball::State state (EmUARTDragonball::kUART_Dragonball); EmRegs328::MarshalUARTState (state); fUART->UpdateState (state, refreshRxData); UnmarshalUARTState (state); EmRegs328::UpdateUARTInterrupts (state); } // --------------------------------------------------------------------------- // ¥ EmRegs328::UpdateUARTInterrupts // --------------------------------------------------------------------------- void EmRegs328::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) | hwr328IntLoUART); } else { // Clear the UART interrupt. WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) & ~hwr328IntLoUART); } // Respond to the new interrupt state. EmRegs328::UpdateInterrupts (); } // --------------------------------------------------------------------------- // ¥ EmRegs328::MarshalUARTState // --------------------------------------------------------------------------- void EmRegs328::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 & hwr328UControlUARTEnable) != 0; state.RX_ENABLE = (uControl & hwr328UControlRxEnable) != 0; state.TX_ENABLE = (uControl & hwr328UControlTxEnable) != 0; state.RX_CLK_CONT = (uControl & hwr328UControlRxClock1x) != 0; state.PARITY_EN = (uControl & hwr328UControlParityEn) != 0; state.ODD_EVEN = (uControl & hwr328UControlParityOdd) != 0; state.STOP_BITS = (uControl & hwr328UControlStopBits2) != 0; state.CHAR8_7 = (uControl & hwr328UControlDataBits8) != 0; state.GPIO_DELTA_ENABLE = (uControl & hwr328UControlGPIODeltaEn) != 0; // 68328 only // state.OLD_ENABLE = (uControl & hwrEZ328UControlOldDataEn) != 0; // 68EZ328 only state.CTS_DELTA_ENABLE = (uControl & hwr328UControlCTSDeltaEn) != 0; state.RX_FULL_ENABLE = (uControl & hwr328UControlRxFullEn) != 0; state.RX_HALF_ENABLE = (uControl & hwr328UControlRxHalfEn) != 0; state.RX_RDY_ENABLE = (uControl & hwr328UControlRxRdyEn) != 0; state.TX_EMPTY_ENABLE = (uControl & hwr328UControlTxEmptyEn) != 0; state.TX_HALF_ENABLE = (uControl & hwr328UControlTxHalfEn) != 0; state.TX_AVAIL_ENABLE = (uControl & hwr328UControlTxAvailEn) != 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 & hwr328UBaudGPIOSrcBaudGen) != 0; // 68328 only // state.UCLK_DIR = (uBaud & hwrEZ328UBaudUCLKDirOut) != 0; // 68EZ328 only state.BAUD_SRC = (uBaud & hwr328UBaudBaudSrcGPIO) != 0; state.DIVIDE = (uBaud & hwr328UBaudDivider) >> hwr328UBaudDivideBitOffset; state.PRESCALER = (uBaud & hwr328UBaudPrescaler); // Receive register bits // These are all input bits; we set them, not the user. state.RX_FIFO_FULL = (uReceive & hwr328UReceiveFIFOFull) != 0; state.RX_FIFO_HALF = (uReceive & hwr328UReceiveFIFOHalf) != 0; state.DATA_READY = (uReceive & hwr328UReceiveDataRdy) != 0; // state.OLD_DATA = (uReceive & hwrEZ328UReceiveOldData) != 0; // 68EZ328 only state.OVRUN = (uReceive & hwr328UReceiveOverrunErr) != 0; state.FRAME_ERROR = (uReceive & hwr328UReceiveFrameErr) != 0; state.BREAK = (uReceive & hwr328UReceiveBreakErr) != 0; state.PARITY_ERROR = (uReceive & hwr328UReceiveParityErr) != 0; state.RX_DATA = (uReceive & hwr328UReceiveData); // Transmitter register bits // We set everything except TX_DATA; the user sets that // value and ONLY that value. state.TX_FIFO_EMPTY = (uTransmit & hwr328UTransmitFIFOEmpty) != 0; state.TX_FIFO_HALF = (uTransmit & hwr328UTransmitFIFOHalf) != 0; state.TX_AVAIL = (uTransmit & hwr328UTransmitTxAvail) != 0; state.SEND_BREAK = (uTransmit & hwr328UTransmitSendBreak) != 0; state.IGNORE_CTS = (uTransmit & hwr328UTransmitIgnoreCTS) != 0; // state.BUSY = (uTransmit & hwrEZ328UTransmitBusy) != 0; // 68EZ328 only state.CTS_STATUS = (uTransmit & hwr328UTransmitCTSStatus) != 0; state.CTS_DELTA = (uTransmit & hwr328UTransmitCTSDelta) != 0; state.TX_DATA = (uTransmit & hwr328UTransmitData); // 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 & hwr328UMiscClkSrcGPIO) != 0; state.FORCE_PERR = (uMisc & hwr328UMiscForceParityErr) != 0; state.LOOP = (uMisc & hwr328UMiscLoopback) != 0; // state.BAUD_RESET = (uMisc & hwrEZ328UMiscBaudReset) != 0; // 68EZ328 only // state.IR_TEST = (uMisc & hwrEZ328UMiscIRTestEn) != 0; // 68EZ328 only state.RTS_CONT = (uMisc & hwr328UMiscRTSThruFIFO) != 0; state.RTS = (uMisc & hwr328UMiscRTSOut) != 0; state.IRDA_ENABLE = (uMisc & hwr328UMiscIRDAEn) != 0; state.IRDA_LOOP = (uMisc & hwr328UMiscLoopIRDA) != 0; // state.RX_POL = (uMisc & hwrEZ328UMiscRXPolarityInv) != 0; // 68EZ328 only // state.TX_POL = (uMisc & hwrEZ328UMiscTXPolarityInv) != 0; // 68EZ328 only } // --------------------------------------------------------------------------- // ¥ EmRegs328::UnmarshalUARTState // --------------------------------------------------------------------------- void EmRegs328::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 |= hwr328UControlUARTEnable; if (state.RX_ENABLE) uControl |= hwr328UControlRxEnable; if (state.TX_ENABLE) uControl |= hwr328UControlTxEnable; if (state.RX_CLK_CONT) uControl |= hwr328UControlRxClock1x; if (state.PARITY_EN) uControl |= hwr328UControlParityEn; if (state.ODD_EVEN) uControl |= hwr328UControlParityOdd; if (state.STOP_BITS) uControl |= hwr328UControlStopBits2; if (state.CHAR8_7) uControl |= hwr328UControlDataBits8; if (state.GPIO_DELTA_ENABLE)uControl |= hwr328UControlGPIODeltaEn; // 68328 only // if (state.OLD_ENABLE) uControl |= hwrEZ328UControlOldDataEn; // 68EZ328 only if (state.CTS_DELTA_ENABLE) uControl |= hwr328UControlCTSDeltaEn; if (state.RX_FULL_ENABLE) uControl |= hwr328UControlRxFullEn; if (state.RX_HALF_ENABLE) uControl |= hwr328UControlRxHalfEn; if (state.RX_RDY_ENABLE) uControl |= hwr328UControlRxRdyEn; if (state.TX_EMPTY_ENABLE) uControl |= hwr328UControlTxEmptyEn; if (state.TX_HALF_ENABLE) uControl |= hwr328UControlTxHalfEn; if (state.TX_AVAIL_ENABLE) uControl |= hwr328UControlTxAvailEn; // 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 |= hwr328UBaudBaudSrcGPIO; uBaud |= (state.DIVIDE << hwr328UBaudDivideBitOffset) & hwr328UBaudDivider; uBaud |= (state.PRESCALER) & hwr328UBaudPrescaler; // Receive register bits // These are all input bits; we set them, not the user. if (state.RX_FIFO_FULL) uReceive |= hwr328UReceiveFIFOFull; if (state.RX_FIFO_HALF) uReceive |= hwr328UReceiveFIFOHalf; if (state.DATA_READY) uReceive |= hwr328UReceiveDataRdy; // if (state.OLD_DATA) uReceive |= hwrEZ328UReceiveOldData; // 68EZ328 only if (state.OVRUN) uReceive |= hwr328UReceiveOverrunErr; if (state.FRAME_ERROR) uReceive |= hwr328UReceiveFrameErr; if (state.BREAK) uReceive |= hwr328UReceiveBreakErr; if (state.PARITY_ERROR) uReceive |= hwr328UReceiveParityErr; uReceive |= (state.RX_DATA) & hwr328UReceiveData; // Transmitter register bits // We set everything except TX_DATA; the user sets that // value and ONLY that value. if (state.TX_FIFO_EMPTY) uTransmit |= hwr328UTransmitFIFOEmpty; if (state.TX_FIFO_HALF) uTransmit |= hwr328UTransmitFIFOHalf; if (state.TX_AVAIL) uTransmit |= hwr328UTransmitTxAvail; if (state.SEND_BREAK) uTransmit |= hwr328UTransmitSendBreak; if (state.IGNORE_CTS) uTransmit |= hwr328UTransmitIgnoreCTS; // if (state.BUSY) uTransmit |= hwrEZ328UTransmitBusy; // 68EZ328 only if (state.CTS_STATUS) uTransmit |= hwr328UTransmitCTSStatus; if (state.CTS_DELTA) uTransmit |= hwr328UTransmitCTSDelta; uTransmit |= (state.TX_DATA) & hwr328UTransmitData; // 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 |= hwr328UMiscClkSrcGPIO; if (state.FORCE_PERR) uMisc |= hwr328UMiscForceParityErr; if (state.LOOP) uMisc |= hwr328UMiscLoopback; // if (state.BAUD_RESET) uMisc |= hwrEZ328UMiscBaudReset; // 68EZ328 only // if (state.IR_TEST) uMisc |= hwrEZ328UMiscIRTestEn; // 68EZ328 only if (state.RTS_CONT) uMisc |= hwr328UMiscRTSThruFIFO; if (state.RTS) uMisc |= hwr328UMiscRTSOut; if (state.IRDA_ENABLE) uMisc |= hwr328UMiscIRDAEn; if (state.IRDA_LOOP) uMisc |= hwr328UMiscLoopIRDA; // 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); } // --------------------------------------------------------------------------- // ¥ EmRegs328::GetPort // --------------------------------------------------------------------------- // Given an address, return a value indicating what port it is associated with. int EmRegs328::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; } // --------------------------------------------------------------------------- // ¥ EmRegs328::PrvGetPalette // --------------------------------------------------------------------------- void EmRegs328::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) & 0x01); 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)); } }