From 0a4432a1936bf201af7257cb797d20ceb1af8248 Mon Sep 17 00:00:00 2001 From: Gwenhael Le Moine Date: Fri, 25 Oct 2024 09:22:54 +0200 Subject: [PATCH] 2024-09-25: Updated to version 1.67 Signed-off-by: Gwenhael Le Moine --- DEBUGGER.TXT | 8 +- Emu48.exe | Bin 323584 -> 323584 bytes Emu48.htm | 30 +- PROBLEMS.TXT | 4 +- Sources/Cardcopy/{cardcopy.c => CARDCOPY.C} | 382 +- Sources/Cardcopy/{types.h => TYPES.H} | 206 +- Sources/Convert/{main.c => MAIN.C} | 802 +- Sources/Emu48/CHANGES.TXT | 86 + Sources/Emu48/{color.h => COLOR.H} | 54 +- Sources/Emu48/{cursor.c => CURSOR.C} | 178 +- Sources/Emu48/{ddeserv.c => DDESERV.C} | 364 +- Sources/Emu48/{debugger.c => DEBUGGER.C} | 8055 ++++++++++--------- Sources/Emu48/{debugger.h => DEBUGGER.H} | 78 +- Sources/Emu48/{disasm.c => DISASM.C} | 3694 ++++----- Sources/Emu48/{dismem.c => DISMEM.C} | 442 +- Sources/Emu48/{display.c => DISPLAY.C} | 2074 ++--- Sources/Emu48/{disrpl.c => DISRPL.C} | 3208 ++++---- Sources/Emu48/{disrpl.h => DISRPL.H} | 50 +- Sources/Emu48/{emu48.c => EMU48.C} | 4669 ++++++----- Sources/Emu48/{emu48.h => EMU48.H} | 909 +-- Sources/Emu48/EMU48.RC | 26 +- Sources/Emu48/EMU48.sln | 4 +- Sources/Emu48/{engine.c => ENGINE.C} | 1282 +-- Sources/Emu48/Emu48.vcxproj | 8 +- Sources/Emu48/FETCH.C | 778 ++ Sources/Emu48/{files.c => FILES.C} | 5642 ++++++------- Sources/Emu48/{i28f160.c => I28F160.C} | 1508 ++-- Sources/Emu48/{i28f160.h => I28F160.H} | 80 +- Sources/Emu48/{io.h => IO.H} | 308 +- Sources/Emu48/{keyboard.c => KEYBOARD.C} | 262 +- Sources/Emu48/{keymacro.c => KEYMACRO.C} | 674 +- Sources/Emu48/{kml.c => KML.C} | 5408 ++++++------- Sources/Emu48/{kml.h => KML.H} | 266 +- Sources/Emu48/{lodepng.c => LODEPNG.C} | 18 +- Sources/Emu48/{lodepng.h => LODEPNG.H} | 2 +- Sources/Emu48/{lowbat.c => LOWBAT.C} | 244 +- Sources/Emu48/{mops.c => MOPS.C} | 3660 ++++----- Sources/Emu48/{mru.c => MRU.C} | 760 +- Sources/Emu48/{opcodes.c => OPCODES.C} | 4878 +++++------ Sources/Emu48/{opcodes.h => OPCODES.H} | 886 +- Sources/Emu48/{ops.h => OPS.H} | 924 +-- Sources/Emu48/{pch.c => PCH.C} | 10 +- Sources/Emu48/{pch.h => PCH.H} | 224 +- Sources/Emu48/{pngcrc.c => PNGCRC.C} | 114 +- Sources/Emu48/{redeye.c => REDEYE.C} | 354 +- Sources/Emu48/{resource.h => RESOURCE.H} | 531 +- Sources/Emu48/{romcrc.c => ROMCRC.C} | 500 +- Sources/Emu48/{rpl.c => RPL.C} | 906 +-- Sources/Emu48/{serial.c => SERIAL.C} | 801 +- Sources/Emu48/{settings.c => SETTINGS.C} | 618 +- Sources/Emu48/{snddef.h => SNDDEF.H} | 204 +- Sources/Emu48/{sndenum.c => SNDENUM.C} | 512 +- Sources/Emu48/{sound.c => SOUND.C} | 1098 +-- Sources/Emu48/{stack.c => STACK.C} | 1785 ++-- Sources/Emu48/{symbfile.c => SYMBFILE.C} | 514 +- Sources/Emu48/{timer.c => TIMER.C} | 864 +- Sources/Emu48/{types.h => TYPES.H} | 206 +- Sources/Emu48/{udp.c => UDP.C} | 151 +- Sources/Emu48/fetch.c | 778 -- Sources/GCCPatch/EMU48GCC.RC | 12 +- Sources/GCCPatch/{pch.h => PCH.H} | 126 +- Sources/GCCPatch/README.TXT | 2 +- Sources/MkShared/{mkshared.c => MKSHARED.C} | 532 +- Sources/MkShared/{resource.h => RESOURCE.H} | 64 +- Sources/Mke48/{mke48.c => MKE48.C} | 240 +- Sources/Mke48/{types.h => TYPES.H} | 206 +- uninst.exe | Bin 66820 -> 66820 bytes 67 files changed, 32277 insertions(+), 31986 deletions(-) rename Sources/Cardcopy/{cardcopy.c => CARDCOPY.C} (96%) rename Sources/Cardcopy/{types.h => TYPES.H} (96%) rename Sources/Convert/{main.c => MAIN.C} (95%) rename Sources/Emu48/{color.h => COLOR.H} (96%) rename Sources/Emu48/{cursor.c => CURSOR.C} (97%) rename Sources/Emu48/{ddeserv.c => DDESERV.C} (96%) rename Sources/Emu48/{debugger.c => DEBUGGER.C} (93%) rename Sources/Emu48/{debugger.h => DEBUGGER.H} (96%) rename Sources/Emu48/{disasm.c => DISASM.C} (95%) rename Sources/Emu48/{dismem.c => DISMEM.C} (95%) rename Sources/Emu48/{display.c => DISPLAY.C} (96%) rename Sources/Emu48/{disrpl.c => DISRPL.C} (95%) rename Sources/Emu48/{disrpl.h => DISRPL.H} (97%) rename Sources/Emu48/{emu48.c => EMU48.C} (96%) rename Sources/Emu48/{emu48.h => EMU48.H} (96%) rename Sources/Emu48/{engine.c => ENGINE.C} (96%) create mode 100644 Sources/Emu48/FETCH.C rename Sources/Emu48/{files.c => FILES.C} (96%) rename Sources/Emu48/{i28f160.c => I28F160.C} (96%) rename Sources/Emu48/{i28f160.h => I28F160.H} (97%) rename Sources/Emu48/{io.h => IO.H} (97%) rename Sources/Emu48/{keyboard.c => KEYBOARD.C} (96%) rename Sources/Emu48/{keymacro.c => KEYMACRO.C} (95%) rename Sources/Emu48/{kml.c => KML.C} (95%) rename Sources/Emu48/{kml.h => KML.H} (95%) rename Sources/Emu48/{lodepng.c => LODEPNG.C} (99%) rename Sources/Emu48/{lodepng.h => LODEPNG.H} (99%) rename Sources/Emu48/{lowbat.c => LOWBAT.C} (95%) rename Sources/Emu48/{mops.c => MOPS.C} (96%) rename Sources/Emu48/{mru.c => MRU.C} (95%) rename Sources/Emu48/{opcodes.c => OPCODES.C} (94%) rename Sources/Emu48/{opcodes.h => OPCODES.H} (97%) rename Sources/Emu48/{ops.h => OPS.H} (94%) rename Sources/Emu48/{pch.c => PCH.C} (86%) rename Sources/Emu48/{pch.h => PCH.H} (96%) rename Sources/Emu48/{pngcrc.c => PNGCRC.C} (98%) rename Sources/Emu48/{redeye.c => REDEYE.C} (95%) rename Sources/Emu48/{resource.h => RESOURCE.H} (74%) rename Sources/Emu48/{romcrc.c => ROMCRC.C} (95%) rename Sources/Emu48/{rpl.c => RPL.C} (96%) rename Sources/Emu48/{serial.c => SERIAL.C} (95%) rename Sources/Emu48/{settings.c => SETTINGS.C} (84%) rename Sources/Emu48/{snddef.h => SNDDEF.H} (97%) rename Sources/Emu48/{sndenum.c => SNDENUM.C} (96%) rename Sources/Emu48/{sound.c => SOUND.C} (96%) rename Sources/Emu48/{stack.c => STACK.C} (81%) rename Sources/Emu48/{symbfile.c => SYMBFILE.C} (95%) rename Sources/Emu48/{timer.c => TIMER.C} (94%) rename Sources/Emu48/{types.h => TYPES.H} (96%) rename Sources/Emu48/{udp.c => UDP.C} (92%) delete mode 100644 Sources/Emu48/fetch.c rename Sources/GCCPatch/{pch.h => PCH.H} (95%) rename Sources/MkShared/{mkshared.c => MKSHARED.C} (96%) rename Sources/MkShared/{resource.h => RESOURCE.H} (97%) rename Sources/Mke48/{mke48.c => MKE48.C} (96%) rename Sources/Mke48/{types.h => TYPES.H} (96%) diff --git a/DEBUGGER.TXT b/DEBUGGER.TXT index e34fce8..4c49fa9 100644 --- a/DEBUGGER.TXT +++ b/DEBUGGER.TXT @@ -342,11 +342,13 @@ NCE3 | nc. | RAM 128KB | nc. | Slt2 32KB-4MB | RAM 128KB - Load Memory Data... -The "Load Memory Data" dialog box allows loading memory dump files to the specified address inside the Saturn address area. The specified address must point to RAM, writing into ROM areas isn't possible. The memory dump file must be in packed data format, meaning each byte in file contain two Saturn data nibbles with the low nibble containing the even and the high nibble the following odd address. The disadvantage of packed files is that you cannot load memory files with an odd number of data nibbles, but the advantage is that you can directly load an assembler output to memory. +The "Load Memory Data" dialog box allows loading memory dump files to the specified address inside the Saturn address area. The specified address must point to RAM, writing into ROM areas isn't possible. The memory dump file maybe in packed data format (8-bit), meaning each byte in file contain two Saturn data nibbles with the low nibble containing the even and the high nibble the following odd address or in unpacked data format (4-bit) with 4-bit in each byte. + +The Auto mode tries to detect the packed or unpacked data format automatically. This may fail, when the memory dump only contain 00-Bytes, then all upper 4 bit are always zero which is an indicator for an unpacked data format. If you're not sure if the Auto detection will work, use the manual data format selection please. - Save Memory Data... -The "Save Memory Data" dialog box allows saving the data of the specified Saturn address area into a memory dump file. The memory dump file contain the data in packed data format, meaning each byte in file contain two Saturn data nibbles with the low nibble containing the even and the high nibble the following odd address. +The "Save Memory Data" dialog box allows saving the data of the specified Saturn address area into a memory dump file. The memory dump file may contain the data in packed data format (8-bit), meaning each byte in file contain two Saturn data nibbles with the low nibble containing the even and the high nibble the following odd address or in unpacked data format (4-bit) with 4-bit in each byte. - RPL Object Viewer... @@ -393,4 +395,4 @@ The Miscellaneous window show you the internal state of the interrupt flag, the You can change the values by pressing the left mouse button over the old content. -08/12/19 (c) by Christoph Gießelink +04/19/24 (c) by Christoph Gießelink diff --git a/Emu48.exe b/Emu48.exe index 0b79d1a5385cd8f72cd16832bf2e3e15f325ca7a..9de2eb7f1a2b192c9bbf872c7f2d2456f0e24956 100755 GIT binary patch delta 83019 zcmbTf3tUvi`#*l>u&XGni^>WpAj+zEM*$T91w}=}T<)0H%4{Vwt6lH4&_cN$De7pa z`gCzW)TgqWpDtdy7zhfQdC7a(=c8tI6in=5TIT-W&z#*A%0A!U>yOU4%ro=MGtWHp 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 HKZ^Zd#;?;& delta 82045 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 z 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 diff --git a/Emu48.htm b/Emu48.htm index 5137606..a92784c 100644 --- a/Emu48.htm +++ b/Emu48.htm @@ -526,10 +526,10 @@ h3 { color:red; font-size:1.1em; } "String" object in stack level 1 to the clipboard. On all other objects, the command will be ignored. This prevents sending binary objects to the clipboard.

-

The decimal point (radix mark) of "Real Numbers" in the - clipboard is equal to the calculator setting. This is important when - you try to paste the numbers into a program using the locale settings - of the host operating system.

+

The decimal point of "Real Numbers" in the clipboard is + equal to the calculator setting. This is important when you try to + paste the numbers into a program using the locale settings of the host + operating system.

9.5 Paste Stack

This menu item is enabled for the HP48SX, HP48GX and the HP49G emulation.

@@ -539,14 +539,18 @@ h3 { color:red; font-size:1.1em; } object. Is the content a complex number object, the number will be saved as "Complex Number" object, otherwise cases as "String" object.

-

To import "Real or Complex Numbers" from the clipboard, the - decimal point (radix mark) of the clipboard and calculator must - match. A real or complex number is only detected in the case of valid - real number characters in the clipboard. Especially heading and tailing - white spaces aren't valid number characters also.

-

Complex numbers must be in the form (a,b) when using the point - radix mark or in the form (a;b) when using the comma radix mark. - The Cartesian or algebraic form a+bi is not supported.

+

To import "Real Numbers" from the clipboard, the decimal + point character of the clipboard and calculator must not match any + more. There's an auto detection for decoding the thousands separator and + decimal point character. The thousands separator is removed at decoding. + A real number is detected in the case of valid real number characters in + the clipboard.

+

"Complex Numbers" must be in the form (a,b) when + using the decimal point or in the form (a;b) when using the decimal + comma. Using a thousands separator is not allowed in complex number + strings because in decimal point mode, the comma is used as separator + between real and imaginary part of the number. The Cartesian or algebraic + form a+bi is not supported.

9.6 Reset Calculator

This emulates the Reset pin of the internal CPU.

9.7 Backup

@@ -636,7 +640,7 @@ h3 { color:red; font-size:1.1em; }

14. License

Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator
- Copyright (C) 2022 Christoph Gießelink

+ Copyright (C) 2024 Christoph Gießelink

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) diff --git a/PROBLEMS.TXT b/PROBLEMS.TXT index f4913cc..e4f4dd1 100644 --- a/PROBLEMS.TXT +++ b/PROBLEMS.TXT @@ -1,4 +1,4 @@ -Known bugs and restrictions of Emu48 V1.66 +Known bugs and restrictions of Emu48 V1.67 ------------------------------------------ - the following I/O bits aren't emulated (incomplete) @@ -47,4 +47,4 @@ Known bugs and restrictions of Emu48 V1.66 - quitting the emulator while programming the flash isn't allowed, because the content of flash state machine isn't saved so far -06/20/23 (c) by Christoph Gießelink, c dot giesselink at gmx dot de +09/23/24 (c) by Christoph Gießelink, c dot giesselink at gmx dot de diff --git a/Sources/Cardcopy/cardcopy.c b/Sources/Cardcopy/CARDCOPY.C similarity index 96% rename from Sources/Cardcopy/cardcopy.c rename to Sources/Cardcopy/CARDCOPY.C index 20f3d1b..23546bf 100644 --- a/Sources/Cardcopy/cardcopy.c +++ b/Sources/Cardcopy/CARDCOPY.C @@ -1,191 +1,191 @@ -/* - * cardcopy, (c) 2000 Christoph Giesselink (cgiess@swol.de) - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. - */ - -#define WIN32_LEAN_AND_MEAN -#define WIN32_EXTRA_LEAN -#include -#include -#include -#include "types.h" - -#define VERSION "2.1" - -#define FT_ERR 0 // illegal format -#define FT_NEW 1 // empty file -#define FT_SXGX 2 // Emu48 HP48SX/GX state file - -#define _KB(n) ((n)*1024*2) // KB in state file -#define HP48SIG "Emu48 Document\xFE" // HP48 state file signature - - -UINT CheckType(char *lpszFileName) -{ - BYTE pbyFileSignature[16]; - HANDLE hFile; - DWORD FileSizeHigh,FileSizeLow; - - UINT nType = FT_ERR; - - hFile = CreateFile(lpszFileName,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL); - if (hFile == INVALID_HANDLE_VALUE) - return FT_NEW; - - // check filesize - FileSizeLow = GetFileSize(hFile,&FileSizeHigh); - if (FileSizeHigh == 0 && (FileSizeLow == _KB(32) || FileSizeLow == _KB(128))) - nType = FileSizeLow; // return card size - - // Read and Compare signature - ReadFile(hFile,pbyFileSignature,sizeof(pbyFileSignature),&FileSizeLow,NULL); - if (FileSizeLow == sizeof(pbyFileSignature) && strcmp(pbyFileSignature,HP48SIG) == 0) - nType = FT_SXGX; - - CloseHandle(hFile); - return nType; -} - -BOOL SeekData(HANDLE hFile,UINT *nPortSize) -{ - BYTE byBuffer[16]; - CHIPSET *pChipset; - UINT i; - DWORD lBytes; - - SetFilePointer(hFile,0,NULL,FILE_BEGIN); - - // read and check signature - ReadFile(hFile,byBuffer,sizeof(byBuffer),&lBytes,NULL); - if (lBytes != sizeof(HP48SIG) || strcmp(byBuffer,HP48SIG) != 0) return TRUE; - - // read KML file length - ReadFile(hFile,&i,sizeof(i),&lBytes,NULL); - if (lBytes != sizeof(i)) return TRUE; - - // skip KML file name - SetFilePointer(hFile,i,NULL,FILE_CURRENT); - - // read CHIPSET structure length - ReadFile(hFile,&i,sizeof(i),&lBytes,NULL); - if (lBytes != sizeof(i)) return TRUE; - - // read CHIPSET structure - if ((pChipset = LocalAlloc(LMEM_FIXED,i)) == NULL) - return TRUE; - - ReadFile(hFile,pChipset,i,&lBytes,NULL); - if (lBytes != i) { LocalFree(pChipset); return TRUE; } - - // skip port0 - SetFilePointer(hFile,_KB(pChipset->Port0Size),NULL,FILE_CURRENT); - - *nPortSize = _KB(pChipset->Port1Size); // expected filesize - - LocalFree(pChipset); - return FALSE; -} - -BOOL CopyData(HANDLE hFileSource,HANDLE hFileDest,UINT nSize) -{ - BYTE byBuffer[16]; - INT i; - DWORD lBytes; - - assert(nSize % sizeof(byBuffer) == 0); - for (i = nSize / sizeof(byBuffer); i > 0; --i) - { - ReadFile(hFileSource,byBuffer,sizeof(byBuffer),&lBytes,NULL); - if (lBytes != sizeof(byBuffer)) return TRUE; - - WriteFile(hFileDest,byBuffer,sizeof(byBuffer),&lBytes,NULL); - if (lBytes != sizeof(byBuffer)) return TRUE; - } - return FALSE; -} - -UINT main(int argc, char *argv[]) -{ - HANDLE hFileSource,hFileDest; - UINT nSourceType,nDestType; - UINT nError = 0; - - printf("HP48 Port1 Import/Export Tool for Emu48 V" VERSION "\n"); - if (argc != 3) - { - printf("\nUsage:\n\t%s \n\n", argv[0]); - return 1; - } - - // check source file type - nSourceType = CheckType(argv[1]); - if (nSourceType == FT_ERR || nSourceType == FT_NEW) - { - printf("Error: Illegal source file type\n"); - return 2; - } - - // check destination file type - nDestType = CheckType(argv[2]); - if (nDestType == FT_ERR) - { - printf("Error: Illegal destination file type\n"); - return 3; - } - - // open source file - hFileSource = CreateFile(argv[1],GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL); - if (hFileSource != INVALID_HANDLE_VALUE) - { - hFileDest = CreateFile(argv[2],GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_ALWAYS,0,NULL); - if (hFileDest != INVALID_HANDLE_VALUE) - { - BOOL bFormatErr = FALSE; - - if (nSourceType == FT_SXGX) bFormatErr |= SeekData(hFileSource,&nSourceType); - if (nDestType == FT_SXGX) bFormatErr |= SeekData(hFileDest,&nDestType); - - if (!bFormatErr && (nSourceType == nDestType || nDestType == FT_NEW)) - { - assert(nSourceType > FT_SXGX); - CopyData(hFileSource,hFileDest,nSourceType); - puts("Copy successful."); - } - else - { - printf("Error: Non matching file size or format\n"); - nError = 4; - } - - CloseHandle(hFileDest); - } - else - { - printf("Error: Can't open destination file %s\n",argv[2]); - nError = 5; - } - - CloseHandle(hFileSource); - } - else - { - printf("Error: Can't open source file %s\n",argv[1]); - nError = 6; - } - - return nError; -} +/* + * cardcopy, (c) 2000 Christoph Giesselink (cgiess@swol.de) + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#define WIN32_LEAN_AND_MEAN +#define WIN32_EXTRA_LEAN +#include +#include +#include +#include "types.h" + +#define VERSION "2.1" + +#define FT_ERR 0 // illegal format +#define FT_NEW 1 // empty file +#define FT_SXGX 2 // Emu48 HP48SX/GX state file + +#define _KB(n) ((n)*1024*2) // KB in state file +#define HP48SIG "Emu48 Document\xFE" // HP48 state file signature + + +UINT CheckType(char *lpszFileName) +{ + BYTE pbyFileSignature[16]; + HANDLE hFile; + DWORD FileSizeHigh,FileSizeLow; + + UINT nType = FT_ERR; + + hFile = CreateFile(lpszFileName,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL); + if (hFile == INVALID_HANDLE_VALUE) + return FT_NEW; + + // check filesize + FileSizeLow = GetFileSize(hFile,&FileSizeHigh); + if (FileSizeHigh == 0 && (FileSizeLow == _KB(32) || FileSizeLow == _KB(128))) + nType = FileSizeLow; // return card size + + // Read and Compare signature + ReadFile(hFile,pbyFileSignature,sizeof(pbyFileSignature),&FileSizeLow,NULL); + if (FileSizeLow == sizeof(pbyFileSignature) && strcmp(pbyFileSignature,HP48SIG) == 0) + nType = FT_SXGX; + + CloseHandle(hFile); + return nType; +} + +BOOL SeekData(HANDLE hFile,UINT *nPortSize) +{ + BYTE byBuffer[16]; + CHIPSET *pChipset; + UINT i; + DWORD lBytes; + + SetFilePointer(hFile,0,NULL,FILE_BEGIN); + + // read and check signature + ReadFile(hFile,byBuffer,sizeof(byBuffer),&lBytes,NULL); + if (lBytes != sizeof(HP48SIG) || strcmp(byBuffer,HP48SIG) != 0) return TRUE; + + // read KML file length + ReadFile(hFile,&i,sizeof(i),&lBytes,NULL); + if (lBytes != sizeof(i)) return TRUE; + + // skip KML file name + SetFilePointer(hFile,i,NULL,FILE_CURRENT); + + // read CHIPSET structure length + ReadFile(hFile,&i,sizeof(i),&lBytes,NULL); + if (lBytes != sizeof(i)) return TRUE; + + // read CHIPSET structure + if ((pChipset = LocalAlloc(LMEM_FIXED,i)) == NULL) + return TRUE; + + ReadFile(hFile,pChipset,i,&lBytes,NULL); + if (lBytes != i) { LocalFree(pChipset); return TRUE; } + + // skip port0 + SetFilePointer(hFile,_KB(pChipset->Port0Size),NULL,FILE_CURRENT); + + *nPortSize = _KB(pChipset->Port1Size); // expected filesize + + LocalFree(pChipset); + return FALSE; +} + +BOOL CopyData(HANDLE hFileSource,HANDLE hFileDest,UINT nSize) +{ + BYTE byBuffer[16]; + INT i; + DWORD lBytes; + + assert(nSize % sizeof(byBuffer) == 0); + for (i = nSize / sizeof(byBuffer); i > 0; --i) + { + ReadFile(hFileSource,byBuffer,sizeof(byBuffer),&lBytes,NULL); + if (lBytes != sizeof(byBuffer)) return TRUE; + + WriteFile(hFileDest,byBuffer,sizeof(byBuffer),&lBytes,NULL); + if (lBytes != sizeof(byBuffer)) return TRUE; + } + return FALSE; +} + +UINT main(int argc, char *argv[]) +{ + HANDLE hFileSource,hFileDest; + UINT nSourceType,nDestType; + UINT nError = 0; + + printf("HP48 Port1 Import/Export Tool for Emu48 V" VERSION "\n"); + if (argc != 3) + { + printf("\nUsage:\n\t%s \n\n", argv[0]); + return 1; + } + + // check source file type + nSourceType = CheckType(argv[1]); + if (nSourceType == FT_ERR || nSourceType == FT_NEW) + { + printf("Error: Illegal source file type\n"); + return 2; + } + + // check destination file type + nDestType = CheckType(argv[2]); + if (nDestType == FT_ERR) + { + printf("Error: Illegal destination file type\n"); + return 3; + } + + // open source file + hFileSource = CreateFile(argv[1],GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL); + if (hFileSource != INVALID_HANDLE_VALUE) + { + hFileDest = CreateFile(argv[2],GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_ALWAYS,0,NULL); + if (hFileDest != INVALID_HANDLE_VALUE) + { + BOOL bFormatErr = FALSE; + + if (nSourceType == FT_SXGX) bFormatErr |= SeekData(hFileSource,&nSourceType); + if (nDestType == FT_SXGX) bFormatErr |= SeekData(hFileDest,&nDestType); + + if (!bFormatErr && (nSourceType == nDestType || nDestType == FT_NEW)) + { + assert(nSourceType > FT_SXGX); + CopyData(hFileSource,hFileDest,nSourceType); + puts("Copy successful."); + } + else + { + printf("Error: Non matching file size or format\n"); + nError = 4; + } + + CloseHandle(hFileDest); + } + else + { + printf("Error: Can't open destination file %s\n",argv[2]); + nError = 5; + } + + CloseHandle(hFileSource); + } + else + { + printf("Error: Can't open source file %s\n",argv[1]); + nError = 6; + } + + return nError; +} diff --git a/Sources/Cardcopy/types.h b/Sources/Cardcopy/TYPES.H similarity index 96% rename from Sources/Cardcopy/types.h rename to Sources/Cardcopy/TYPES.H index c14d725..456c1aa 100644 --- a/Sources/Cardcopy/types.h +++ b/Sources/Cardcopy/TYPES.H @@ -1,103 +1,103 @@ -/* - * types.h - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ - -// HST bits -#define XM 1 -#define SB 2 -#define SR 4 -#define MP 8 - -#define SWORD SHORT // signed 16 Bit variable -#define QWORD ULONGLONG // unsigned 64 Bit variable - -#define CHIPSET Chipset_t -typedef struct -{ - SWORD nPosX; // position of window - SWORD nPosY; - BYTE type; // calculator type - - DWORD Port0Size; // real size of module in KB - DWORD Port1Size; // real size of module in KB - DWORD Port2Size; // real size of module in KB (HP49G only) - LPBYTE Port0; - LPBYTE Port1; - LPBYTE Port2; - - DWORD pc; - DWORD d0; - DWORD d1; - DWORD rstkp; - DWORD rstk[8]; - BYTE A[16]; - BYTE B[16]; - BYTE C[16]; - BYTE D[16]; - BYTE R0[16]; - BYTE R1[16]; - BYTE R2[16]; - BYTE R3[16]; - BYTE R4[16]; - BYTE ST[4]; - BYTE HST; - BYTE P; - WORD out; - WORD in; - BOOL SoftInt; - BOOL Shutdn; - BOOL mode_dec; - BOOL inte; // interrupt status flag (FALSE = int in service) - BOOL intk; // 1 ms keyboard scan flag (TRUE = enable) - BOOL intd; // keyboard interrupt pending (TRUE = int pending) - BOOL carry; - - WORD crc; - WORD wPort2Crc; // fingerprint of port2 - WORD wRomCrc; // fingerprint of ROM -#if defined _USRDLL // DLL version - QWORD cycles; // oscillator cycles -#else // EXE version - DWORD cycles; // oscillator cycles - DWORD cycles_reserved; // reserved for MSB of oscillator cycles -#endif - DWORD dwKdnCycles; // cpu cycles at start of 1ms key handler - - UINT Bank_FF; // save state of HP48GX port2 or state of HP49G ROM FF - UINT FlashRomState; // WSM state of flash memory (unused) - BYTE cards_status; - BYTE IORam[64]; // I/O hardware register - UINT IOBase; // address of I/O modules page - BOOL IOCfig; // I/O module configuration flag - BYTE P0Base, BSBase, P1Base, P2Base; // address of modules first 2KB page - BYTE P0Size, BSSize, P1Size, P2Size; // mapped size of module in 2KB - BYTE P0End, BSEnd, P1End, P2End; // address of modules last 2KB page - BOOL P0Cfig, BSCfig, P1Cfig, P2Cfig; // module address configuration flag - BOOL P0Cfg2, BSCfg2, P1Cfg2, P2Cfg2; // module size configuration flag - - BYTE t1; - DWORD t2; - - BOOL bShutdnWake; // flag for wake up from SHUTDN mode - - BYTE Keyboard_Row[9]; - WORD IR15X; - UINT Keyboard_State; // not used - - signed short loffset; - signed int width; - UINT boffset; - UINT lcounter; - UINT sync; // not used - BYTE contrast; - BOOL dispon; - DWORD start1; - DWORD start12; - DWORD end1; - DWORD start2, end2; -} Chipset_t; +/* + * types.h + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ + +// HST bits +#define XM 1 +#define SB 2 +#define SR 4 +#define MP 8 + +#define SWORD SHORT // signed 16 Bit variable +#define QWORD ULONGLONG // unsigned 64 Bit variable + +#define CHIPSET Chipset_t +typedef struct +{ + SWORD nPosX; // position of window + SWORD nPosY; + BYTE type; // calculator type + + DWORD Port0Size; // real size of module in KB + DWORD Port1Size; // real size of module in KB + DWORD Port2Size; // real size of module in KB (HP49G only) + LPBYTE Port0; + LPBYTE Port1; + LPBYTE Port2; + + DWORD pc; + DWORD d0; + DWORD d1; + DWORD rstkp; + DWORD rstk[8]; + BYTE A[16]; + BYTE B[16]; + BYTE C[16]; + BYTE D[16]; + BYTE R0[16]; + BYTE R1[16]; + BYTE R2[16]; + BYTE R3[16]; + BYTE R4[16]; + BYTE ST[4]; + BYTE HST; + BYTE P; + WORD out; + WORD in; + BOOL SoftInt; + BOOL Shutdn; + BOOL mode_dec; + BOOL inte; // interrupt status flag (FALSE = int in service) + BOOL intk; // 1 ms keyboard scan flag (TRUE = enable) + BOOL intd; // keyboard interrupt pending (TRUE = int pending) + BOOL carry; + + WORD crc; + WORD wPort2Crc; // fingerprint of port2 + WORD wRomCrc; // fingerprint of ROM +#if defined _USRDLL // DLL version + QWORD cycles; // oscillator cycles +#else // EXE version + DWORD cycles; // oscillator cycles + DWORD cycles_reserved; // reserved for MSB of oscillator cycles +#endif + DWORD dwKdnCycles; // cpu cycles at start of 1ms key handler + + UINT Bank_FF; // save state of HP48GX port2 or state of HP49G ROM FF + UINT FlashRomState; // WSM state of flash memory (unused) + BYTE cards_status; + BYTE IORam[64]; // I/O hardware register + UINT IOBase; // address of I/O modules page + BOOL IOCfig; // I/O module configuration flag + BYTE P0Base, BSBase, P1Base, P2Base; // address of modules first 2KB page + BYTE P0Size, BSSize, P1Size, P2Size; // mapped size of module in 2KB + BYTE P0End, BSEnd, P1End, P2End; // address of modules last 2KB page + BOOL P0Cfig, BSCfig, P1Cfig, P2Cfig; // module address configuration flag + BOOL P0Cfg2, BSCfg2, P1Cfg2, P2Cfg2; // module size configuration flag + + BYTE t1; + DWORD t2; + + BOOL bShutdnWake; // flag for wake up from SHUTDN mode + + BYTE Keyboard_Row[9]; + WORD IR15X; + UINT Keyboard_State; // not used + + signed short loffset; + signed int width; + UINT boffset; + UINT lcounter; + UINT sync; // not used + BYTE contrast; + BOOL dispon; + DWORD start1; + DWORD start12; + DWORD end1; + DWORD start2, end2; +} Chipset_t; diff --git a/Sources/Convert/main.c b/Sources/Convert/MAIN.C similarity index 95% rename from Sources/Convert/main.c rename to Sources/Convert/MAIN.C index c3b33e4..461673d 100644 --- a/Sources/Convert/main.c +++ b/Sources/Convert/MAIN.C @@ -1,401 +1,401 @@ -#define WIN32_LEAN_AND_MEAN -#define WIN32_EXTRA_LEAN -#include -#include -#include -#include -#include - -#define HP38G 0 -#define HP48S 1 -#define HP48G 2 - -LPBYTE pRom; -WORD wCRC; -WORD wType; - -static WORD crc_table[16] = -{ - 0x0000, 0x1081, 0x2102, 0x3183, 0x4204, 0x5285, 0x6306, 0x7387, - 0x8408, 0x9489, 0xA50A, 0xB58B, 0xC60C, 0xD68D, 0xE70E, 0xF78F -}; -static __inline VOID CRC(BYTE nib) -{ - wCRC = (WORD)((wCRC>>4)^crc_table[(wCRC^nib)&0xf]); -} - -BOOL CheckCRC() -{ - DWORD dwD0, dwD1; - WORD wRomCRC; - UINT i; - DWORD dwBase = 0x00000; - UINT nPass = 0; - UINT nPasses = (wType != HP48S)?2:1; - -again: - - wRomCRC = pRom[dwBase+0x7FFFC] - |(pRom[dwBase+0x7FFFD]<<4) - |(pRom[dwBase+0x7FFFE]<<8) - |(pRom[dwBase+0x7FFFF]<<12); - - wCRC = 0x0000; - dwD0 = dwBase + 0x00000; - dwD1 = dwBase + 0x40000; - do - { - for (i=0; i<16; i++) CRC(pRom[dwD0+i]); - for (i=0; i<16; i++) CRC(pRom[dwD1+i]); - dwD0 += 16; - dwD1 += 16; - } while (dwD0&0x3FFFF); - - if (wCRC==0xFFFF) - { - printf("CRC%i: %04X Ok\n", nPass, wRomCRC); - } - else - { - printf("CRC%i: %04X Failed (%04X)\n", nPass, wRomCRC, wCRC); - return FALSE; - } - - if (++nPass == nPasses) return TRUE; - - dwBase += 0x80000; - goto again; - -} - -static BYTE Asc2Nib(char c) -{ - if (c<'0') return 0; - if (c<='9') return c-'0'; - if (c<'A') return 0; - if (c<='F') return c-'A'+10; - if (c<'a') return 0; - if (c<='f') return c-'a'+10; - return 0; -} - -static DWORD Asc2Nib5(LPBYTE lpBuf) -{ - return ( - ((DWORD)Asc2Nib(lpBuf[0])<<16) - |((DWORD)Asc2Nib(lpBuf[1])<<12) - |((DWORD)Asc2Nib(lpBuf[2])<<8) - |((DWORD)Asc2Nib(lpBuf[3])<<4) - |((DWORD)Asc2Nib(lpBuf[4]))); -} - -static BOOL IsHP(DWORD dwAddress) -{ - char cH = (pRom[dwAddress + 1] << 4) | pRom[dwAddress]; - char cP = (pRom[dwAddress + 3] << 4) | pRom[dwAddress + 2]; - return cH == 'H' && cP == 'P'; -} - -UINT main(int argc, char *argv[]) -{ - HANDLE hFile; - HANDLE hMap; - HANDLE hOut; - LPBYTE pIn; - DWORD dwSizeLo; - BYTE szVersion[16]; - UINT i,uLen; - DWORD dwAddress; - - DWORD dwAddrOffset = 0x00000; - - BOOL bFormatDetected = FALSE; - - BOOL bUnpack = FALSE; - BOOL bSwap = FALSE; - BOOL bText = FALSE; - BOOL bDA19 = FALSE; - BOOL bPack = FALSE; - - int iArg = 1; // first argument - - if (argc < 2 || argc > 4) - { - printf("Usage:\n\t%s [-p] []\n", argv[0]); - return 1; - } - - while (*argv[iArg] == '-') // an option - { - if (strcmp(argv[iArg],"-p") == 0) // option "-p", pack result ROM image - { - bPack = TRUE; // pack target ROM image - --argc; // option is not an argument - } - ++iArg; // first file argument - } - - pRom = (LPBYTE) malloc(512*1024*2); - if (pRom == NULL) - { - printf("Memory Allocation Failed !"); - return 1; - } - - hFile = CreateFile(argv[iArg],GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); - if (hFile == INVALID_HANDLE_VALUE) - { - free(pRom); - printf("Cannot open file %s.\n", argv[iArg]); - return 1; - } - dwSizeLo = GetFileSize(hFile, NULL); - hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); - if (hMap == NULL) - { - free(pRom); - CloseHandle(hFile); - puts("CreateFileMapping failed."); - return 1; - } - pIn = (LPBYTE) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); - if (pIn == NULL) - { - free(pRom); - CloseHandle(hMap); - CloseHandle(hFile); - puts("MapViewOfFile failed.\n"); - return 1; - } - - for (i = 0; i < 2 && !bFormatDetected; ++i) - { - switch (pIn[0+dwAddrOffset]) - { - case '0': - if (pIn[1+dwAddrOffset]!='0') break; - if (pIn[2+dwAddrOffset]!='0') break; - if (pIn[3+dwAddrOffset]!='0') break; - if (pIn[4+dwAddrOffset]!='0') break; - if (pIn[5+dwAddrOffset]!=':') break; - bText = TRUE; - bFormatDetected = TRUE; - break; - case 0x23: - bUnpack = TRUE; - bSwap = TRUE; - bFormatDetected = TRUE; - break; - case 0x32: - bUnpack = TRUE; - bFormatDetected = TRUE; - break; - case 0x03: - bSwap = TRUE; - case 0x02: - if (pIn[1+dwAddrOffset] == (bSwap ? 0x02 : 0x03)) - { - bFormatDetected = TRUE; - break; - } - bSwap = FALSE; - default: - dwAddrOffset = dwSizeLo / 2; - bDA19 = TRUE; - break; - } - } - - if (!bFormatDetected) - { - free(pRom); - UnmapViewOfFile(pIn); - CloseHandle(hMap); - CloseHandle(hFile); - printf("Stopped, unknown format.\n"); - return 1; - } - - if (bUnpack) printf("Unpacking nibbles.\n"); - if (bSwap) printf("Swapping nibbles.\n"); - if (bText) printf("Reading text file.\n"); - if (bDA19) printf("Swapping banks.\n"); - - if (bText) - { - DWORD i = 0; - while (i>4; - pRom[(i<<1)+1] = byC&0xF; - } - } - else - { - DWORD i; - for (i=0; i>4; - } - } - } - else - { - if (bSwap) - { - DWORD i; - for (i=0; i +#include +#include +#include +#include + +#define HP38G 0 +#define HP48S 1 +#define HP48G 2 + +LPBYTE pRom; +WORD wCRC; +WORD wType; + +static WORD crc_table[16] = +{ + 0x0000, 0x1081, 0x2102, 0x3183, 0x4204, 0x5285, 0x6306, 0x7387, + 0x8408, 0x9489, 0xA50A, 0xB58B, 0xC60C, 0xD68D, 0xE70E, 0xF78F +}; +static __inline VOID CRC(BYTE nib) +{ + wCRC = (WORD)((wCRC>>4)^crc_table[(wCRC^nib)&0xf]); +} + +BOOL CheckCRC() +{ + DWORD dwD0, dwD1; + WORD wRomCRC; + UINT i; + DWORD dwBase = 0x00000; + UINT nPass = 0; + UINT nPasses = (wType != HP48S)?2:1; + +again: + + wRomCRC = pRom[dwBase+0x7FFFC] + |(pRom[dwBase+0x7FFFD]<<4) + |(pRom[dwBase+0x7FFFE]<<8) + |(pRom[dwBase+0x7FFFF]<<12); + + wCRC = 0x0000; + dwD0 = dwBase + 0x00000; + dwD1 = dwBase + 0x40000; + do + { + for (i=0; i<16; i++) CRC(pRom[dwD0+i]); + for (i=0; i<16; i++) CRC(pRom[dwD1+i]); + dwD0 += 16; + dwD1 += 16; + } while (dwD0&0x3FFFF); + + if (wCRC==0xFFFF) + { + printf("CRC%i: %04X Ok\n", nPass, wRomCRC); + } + else + { + printf("CRC%i: %04X Failed (%04X)\n", nPass, wRomCRC, wCRC); + return FALSE; + } + + if (++nPass == nPasses) return TRUE; + + dwBase += 0x80000; + goto again; + +} + +static BYTE Asc2Nib(char c) +{ + if (c<'0') return 0; + if (c<='9') return c-'0'; + if (c<'A') return 0; + if (c<='F') return c-'A'+10; + if (c<'a') return 0; + if (c<='f') return c-'a'+10; + return 0; +} + +static DWORD Asc2Nib5(LPBYTE lpBuf) +{ + return ( + ((DWORD)Asc2Nib(lpBuf[0])<<16) + |((DWORD)Asc2Nib(lpBuf[1])<<12) + |((DWORD)Asc2Nib(lpBuf[2])<<8) + |((DWORD)Asc2Nib(lpBuf[3])<<4) + |((DWORD)Asc2Nib(lpBuf[4]))); +} + +static BOOL IsHP(DWORD dwAddress) +{ + char cH = (pRom[dwAddress + 1] << 4) | pRom[dwAddress]; + char cP = (pRom[dwAddress + 3] << 4) | pRom[dwAddress + 2]; + return cH == 'H' && cP == 'P'; +} + +UINT main(int argc, char *argv[]) +{ + HANDLE hFile; + HANDLE hMap; + HANDLE hOut; + LPBYTE pIn; + DWORD dwSizeLo; + BYTE szVersion[16]; + UINT i,uLen; + DWORD dwAddress; + + DWORD dwAddrOffset = 0x00000; + + BOOL bFormatDetected = FALSE; + + BOOL bUnpack = FALSE; + BOOL bSwap = FALSE; + BOOL bText = FALSE; + BOOL bDA19 = FALSE; + BOOL bPack = FALSE; + + int iArg = 1; // first argument + + if (argc < 2 || argc > 4) + { + printf("Usage:\n\t%s [-p] []\n", argv[0]); + return 1; + } + + while (*argv[iArg] == '-') // an option + { + if (strcmp(argv[iArg],"-p") == 0) // option "-p", pack result ROM image + { + bPack = TRUE; // pack target ROM image + --argc; // option is not an argument + } + ++iArg; // first file argument + } + + pRom = (LPBYTE) malloc(512*1024*2); + if (pRom == NULL) + { + printf("Memory Allocation Failed !"); + return 1; + } + + hFile = CreateFile(argv[iArg],GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + free(pRom); + printf("Cannot open file %s.\n", argv[iArg]); + return 1; + } + dwSizeLo = GetFileSize(hFile, NULL); + hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if (hMap == NULL) + { + free(pRom); + CloseHandle(hFile); + puts("CreateFileMapping failed."); + return 1; + } + pIn = (LPBYTE) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); + if (pIn == NULL) + { + free(pRom); + CloseHandle(hMap); + CloseHandle(hFile); + puts("MapViewOfFile failed.\n"); + return 1; + } + + for (i = 0; i < 2 && !bFormatDetected; ++i) + { + switch (pIn[0+dwAddrOffset]) + { + case '0': + if (pIn[1+dwAddrOffset]!='0') break; + if (pIn[2+dwAddrOffset]!='0') break; + if (pIn[3+dwAddrOffset]!='0') break; + if (pIn[4+dwAddrOffset]!='0') break; + if (pIn[5+dwAddrOffset]!=':') break; + bText = TRUE; + bFormatDetected = TRUE; + break; + case 0x23: + bUnpack = TRUE; + bSwap = TRUE; + bFormatDetected = TRUE; + break; + case 0x32: + bUnpack = TRUE; + bFormatDetected = TRUE; + break; + case 0x03: + bSwap = TRUE; + case 0x02: + if (pIn[1+dwAddrOffset] == (bSwap ? 0x02 : 0x03)) + { + bFormatDetected = TRUE; + break; + } + bSwap = FALSE; + default: + dwAddrOffset = dwSizeLo / 2; + bDA19 = TRUE; + break; + } + } + + if (!bFormatDetected) + { + free(pRom); + UnmapViewOfFile(pIn); + CloseHandle(hMap); + CloseHandle(hFile); + printf("Stopped, unknown format.\n"); + return 1; + } + + if (bUnpack) printf("Unpacking nibbles.\n"); + if (bSwap) printf("Swapping nibbles.\n"); + if (bText) printf("Reading text file.\n"); + if (bDA19) printf("Swapping banks.\n"); + + if (bText) + { + DWORD i = 0; + while (i>4; + pRom[(i<<1)+1] = byC&0xF; + } + } + else + { + DWORD i; + for (i=0; i>4; + } + } + } + else + { + if (bSwap) + { + DWORD i; + for (i=0; i= sizeof(DWORD)) - { - dwIndex = *(LPDWORD) lpData; // object length - - if (dwIndex <= dwSize - sizeof(DWORD)) - { - // reserve unpacked object length memory - LPBYTE pbyMem = (LPBYTE) malloc(dwIndex * 2); - - if (pbyMem != NULL) - { - // copy data and write to stack - CopyMemory(pbyMem+dwIndex,lpData+sizeof(DWORD),dwIndex); - bSuccess = (WriteStack(nStkLvl,pbyMem,dwIndex) == S_ERR_NO); - free(pbyMem); // free memory - } - } - } - - DdeUnaccessData(hData); - - SwitchToState(SM_RUN); // run state - while (nState!=nNextState) Sleep(0); - _ASSERT(nState==SM_RUN); - - if (bSuccess == FALSE) - { - hReturn = DDE_FNOTPROCESSED; - goto cancel; - } - - KeyboardEvent(TRUE,0,0x8000); - Sleep(dwWakeupDelay); - KeyboardEvent(FALSE,0,0x8000); - // wait for sleep mode - while (Chipset.Shutdn == FALSE) Sleep(0); - hReturn = (HDDEDATA) DDE_FACK; - -cancel: - bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control - ResumeDebugger(); - return hReturn; - - case XTYP_REQUEST: - // quit on models without stack or illegal data format or not in running state - if (!bStackEnable || iFmt != uCF_HpObj || nState != SM_RUN) - return NULL; - - // get item name - DdeQueryString(idDdeInst,hsz2,szBuffer,ARRAYSIZEOF(szBuffer),0); - nStkLvl = _tcstoul(szBuffer,&psz,10); - if (*psz != 0 || nStkLvl < 1) // invalid number format - return NULL; - - if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state - return NULL; - - while (nState!=nNextState) Sleep(0); - _ASSERT(nState==SM_SLEEP); - - dwAddress = RPL_Pick(nStkLvl); // pick address of stack level "item" object - if (dwAddress == 0) - { - SwitchToState(SM_RUN); // run state - return NULL; - } - dwLoop = dwSize = (RPL_SkipOb(dwAddress) - dwAddress + 1) / 2; - - lpHeader = (Chipset.type != 'X') ? (LPBYTE) BINARYHEADER48 : (LPBYTE) BINARYHEADER49; - - // length of binary header - dwIndex = (DWORD) strlen((LPCSTR) lpHeader); - - // size of objectsize + header + object - dwSize += dwIndex + sizeof(DWORD); - - // reserve memory - if ((lpData = (LPBYTE) malloc(dwSize)) == NULL) - { - SwitchToState(SM_RUN); // run state - return NULL; - } - - // save data length - *(DWORD *)lpData = dwLoop + dwIndex; - - // copy header - memcpy(lpData + sizeof(DWORD),lpHeader,dwIndex); - - // copy data - for (dwIndex += sizeof(DWORD);dwLoop--;++dwIndex,dwAddress += 2) - lpData[dwIndex] = Read2(dwAddress); - - // write data - hReturn = DdeCreateDataHandle(idDdeInst,lpData,dwSize,0,hsz2,iFmt,0); - free(lpData); - - SwitchToState(SM_RUN); // run state - while (nState!=nNextState) Sleep(0); - _ASSERT(nState==SM_RUN); - - return hReturn; - } - return NULL; - UNREFERENCED_PARAMETER(hConv); - UNREFERENCED_PARAMETER(dwData1); - UNREFERENCED_PARAMETER(dwData2); -} +/* + * DdeServ.c + * + * This file is part of Emu48 + * + * Copyright (C) 1998 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" +#include "io.h" + +HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv, + HSZ hsz1,HSZ hsz2,HDDEDATA hData, + DWORD dwData1,DWORD dwData2) +{ + TCHAR *psz,szBuffer[32]; + HDDEDATA hReturn; + LPBYTE lpData,lpHeader; + DWORD dwAddress,dwSize,dwLoop,dwIndex; + UINT nStkLvl; + BOOL bSuccess; + + // disable stack loading items on HP38G, HP39/40G + BOOL bStackEnable = cCurrentRomType!='6' && cCurrentRomType!='A' && cCurrentRomType!='E'; + + switch (iType) + { + case XTYP_CONNECT: + // get service name + DdeQueryString(idDdeInst,hsz2,szBuffer,ARRAYSIZEOF(szBuffer),0); + if (0 != lstrcmp(szBuffer,szAppName)) + return (HDDEDATA) FALSE; + // get topic name + DdeQueryString(idDdeInst,hsz1,szBuffer,ARRAYSIZEOF(szBuffer),0); + return (HDDEDATA) (INT_PTR) (0 == lstrcmp(szBuffer,szTopic)); + + case XTYP_POKE: + // quit on models without stack or illegal data format or not in running state + if (!bStackEnable || iFmt != uCF_HpObj || nState != SM_RUN) + return (HDDEDATA) DDE_FNOTPROCESSED; + + // get item name + DdeQueryString(idDdeInst,hsz2,szBuffer,ARRAYSIZEOF(szBuffer),0); + nStkLvl = _tcstoul(szBuffer,&psz,10); + if (*psz != 0 || nStkLvl < 1) // invalid number format + return (HDDEDATA) DDE_FNOTPROCESSED; + + SuspendDebugger(); // suspend debugger + bDbgAutoStateCtrl = FALSE; // disable automatic debugger state control + + if (!(Chipset.IORam[BITOFFSET]&DON)) // HP off + { + // turn on HP + KeyboardEvent(TRUE,0,0x8000); + Sleep(dwWakeupDelay); + KeyboardEvent(FALSE,0,0x8000); + } + + if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state + { + hReturn = DDE_FNOTPROCESSED; + goto cancel; + } + + while (nState!=nNextState) Sleep(0); + _ASSERT(nState==SM_SLEEP); + + bSuccess = FALSE; + + // get data and size + lpData = DdeAccessData(hData,&dwSize); + + // has object length header + if (lpData && dwSize >= sizeof(DWORD)) + { + dwIndex = *(LPDWORD) lpData; // object length + + if (dwIndex <= dwSize - sizeof(DWORD)) + { + // reserve unpacked object length memory + LPBYTE pbyMem = (LPBYTE) malloc(dwIndex * 2); + + if (pbyMem != NULL) + { + // copy data and write to stack + CopyMemory(pbyMem+dwIndex,lpData+sizeof(DWORD),dwIndex); + bSuccess = (WriteStack(nStkLvl,pbyMem,dwIndex) == S_ERR_NO); + free(pbyMem); // free memory + } + } + } + + DdeUnaccessData(hData); + + SwitchToState(SM_RUN); // run state + while (nState!=nNextState) Sleep(0); + _ASSERT(nState==SM_RUN); + + if (bSuccess == FALSE) + { + hReturn = DDE_FNOTPROCESSED; + goto cancel; + } + + KeyboardEvent(TRUE,0,0x8000); + Sleep(dwWakeupDelay); + KeyboardEvent(FALSE,0,0x8000); + // wait for sleep mode + while (Chipset.Shutdn == FALSE) Sleep(0); + hReturn = (HDDEDATA) DDE_FACK; + +cancel: + bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control + ResumeDebugger(); + return hReturn; + + case XTYP_REQUEST: + // quit on models without stack or illegal data format or not in running state + if (!bStackEnable || iFmt != uCF_HpObj || nState != SM_RUN) + return NULL; + + // get item name + DdeQueryString(idDdeInst,hsz2,szBuffer,ARRAYSIZEOF(szBuffer),0); + nStkLvl = _tcstoul(szBuffer,&psz,10); + if (*psz != 0 || nStkLvl < 1) // invalid number format + return NULL; + + if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state + return NULL; + + while (nState!=nNextState) Sleep(0); + _ASSERT(nState==SM_SLEEP); + + dwAddress = RPL_Pick(nStkLvl); // pick address of stack level "item" object + if (dwAddress == 0) + { + SwitchToState(SM_RUN); // run state + return NULL; + } + dwLoop = dwSize = (RPL_SkipOb(dwAddress) - dwAddress + 1) / 2; + + lpHeader = (Chipset.type != 'X') ? (LPBYTE) BINARYHEADER48 : (LPBYTE) BINARYHEADER49; + + // length of binary header + dwIndex = (DWORD) strlen((LPCSTR) lpHeader); + + // size of objectsize + header + object + dwSize += dwIndex + sizeof(DWORD); + + // reserve memory + if ((lpData = (LPBYTE) malloc(dwSize)) == NULL) + { + SwitchToState(SM_RUN); // run state + return NULL; + } + + // save data length + *(DWORD *)lpData = dwLoop + dwIndex; + + // copy header + memcpy(lpData + sizeof(DWORD),lpHeader,dwIndex); + + // copy data + for (dwIndex += sizeof(DWORD);dwLoop--;++dwIndex,dwAddress += 2) + lpData[dwIndex] = Read2(dwAddress); + + // write data + hReturn = DdeCreateDataHandle(idDdeInst,lpData,dwSize,0,hsz2,iFmt,0); + free(lpData); + + SwitchToState(SM_RUN); // run state + while (nState!=nNextState) Sleep(0); + _ASSERT(nState==SM_RUN); + + return hReturn; + } + return NULL; + UNREFERENCED_PARAMETER(hConv); + UNREFERENCED_PARAMETER(dwData1); + UNREFERENCED_PARAMETER(dwData2); +} diff --git a/Sources/Emu48/debugger.c b/Sources/Emu48/DEBUGGER.C similarity index 93% rename from Sources/Emu48/debugger.c rename to Sources/Emu48/DEBUGGER.C index 27261e3..a3afd9f 100644 --- a/Sources/Emu48/debugger.c +++ b/Sources/Emu48/DEBUGGER.C @@ -1,3989 +1,4066 @@ -/* - * debugger.c - * - * This file is part of Emu48 - * - * Copyright (C) 1999 Christoph Gießelink - * - */ -#include "pch.h" -#include "resource.h" -#include "emu48.h" -#include "opcodes.h" -#include "ops.h" -#include "color.h" -#include "disrpl.h" -#include "debugger.h" - -#define MAXCODELINES 15 // number of lines in code window -#define MAXMEMLINES 6 // number of lines in memory window -#define MAXMEMITEMS 16 // number of address items in a memory window line -#define MAXBREAKPOINTS 256 // max. number of breakpoints - -#define REG_START IDC_REG_A // first register in register update table -#define REG_STOP IDC_MISC_BS // last register in register update table -#define REG_SIZE (REG_STOP-REG_START+1) // size of register update table - -// assert for register update -#define _ASSERTREG(r) _ASSERT(r >= REG_START && r <= REG_STOP) - -#define WM_UPDATE (WM_USER+0x1000) // update debugger dialog box - -#define MEMWNDMAX (sizeof(nCol) / sizeof(nCol[0])) - -#define RT_TOOLBAR MAKEINTRESOURCE(241) // MFC toolbar resource type - -#define CODELABEL 0x80000000 // label in code window - -// trace log file modes -enum TRACE_MODE { TRACE_FILE_NEW = 0, TRACE_FILE_APPEND }; - -typedef struct CToolBarData -{ - WORD wVersion; - WORD wWidth; - WORD wHeight; - WORD wItemCount; - WORD aItems[1]; -} CToolBarData; - -typedef struct // type of breakpoint table -{ - BOOL bEnable; // breakpoint enabled - UINT nType; // breakpoint type - DWORD dwAddr; // breakpoint address -} BP_T; - -static CONST int nCol[] = -{ - IDC_DEBUG_MEM_COL0, IDC_DEBUG_MEM_COL1, IDC_DEBUG_MEM_COL2, IDC_DEBUG_MEM_COL3, - IDC_DEBUG_MEM_COL4, IDC_DEBUG_MEM_COL5, IDC_DEBUG_MEM_COL6, IDC_DEBUG_MEM_COL7 -}; - -static CONST TCHAR cHex[] = { _T('0'),_T('1'),_T('2'),_T('3'), - _T('4'),_T('5'),_T('6'),_T('7'), - _T('8'),_T('9'),_T('A'),_T('B'), - _T('C'),_T('D'),_T('E'),_T('F') }; - -static INT nDbgPosX = 0; // position of debugger window -static INT nDbgPosY = 0; - -static WORD wBreakpointCount = 0; // number of breakpoints -static BP_T sBreakpoint[MAXBREAKPOINTS]; // breakpoint table - -static WORD wBackupBreakpointCount = 0; // number of breakpoints -static BP_T sBackupBreakpoint[MAXBREAKPOINTS]; // breakpoint table - -static INT nRplBreak; // RPL breakpoint - -static DWORD dwAdrLine[MAXCODELINES]; // addresses of disassember lines in code window -static DWORD dwAdrMem = 0; // start address of memory window - -static UINT uIDFol = ID_DEBUG_MEM_FNONE; // follow mode -static DWORD dwAdrMemFol = 0; // follow address memory window - -static UINT uIDMap = ID_DEBUG_MEM_MAP; // current memory view mode - -static BOOL bDbgTrace = FALSE; // enable trace output -static HANDLE hLogFile = NULL; // log file handle -static TCHAR szTraceFilename[MAX_PATH] = _T("trace.log"); // filename for trace file -static UINT uTraceMode = TRACE_FILE_NEW; // trace log file mode -static BOOL bTraceReg = TRUE; // enable register logging -static BOOL bTraceMmu = FALSE; // disable MMU logging -static BOOL bTraceOpc = TRUE; // enable opcode logging - -static LONG lCharWidth; // width of a character (is a fix font) - -static HMENU hMenuCode,hMenuMem,hMenuStack;// handle of context menues -static HWND hWndToolbar; // toolbar handle - -static DWORD dwDbgRefCycles; // cpu cycles counter from last opcode - -static CHIPSET OldChipset; // old chipset content -static BOOL bRegUpdate[REG_SIZE]; // register update table - -static HBITMAP hBmpCheckBox; // checked and unchecked bitmap -static HFONT hFontBold; // bold font for symbol labels in code window - -// function prototypes -static BOOL OnMemFind(HWND hDlg); -static BOOL OnProfile(HWND hDlg); -static VOID UpdateRplObjViewWnd(HWND hDlg, DWORD dwAddr); -static BOOL OnRplObjView(HWND hDlg); -static BOOL OnSettings(HWND hDlg); -static INT_PTR OnNewValue(LPTSTR lpszValue); -static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue); -static BOOL OnEditBreakpoint(HWND hDlg); -static BOOL OnInfoIntr(HWND hDlg); -static BOOL OnInfoWoRegister(HWND hDlg); -static VOID UpdateProfileWnd(HWND hDlg); -static BOOL OnMemLoadData(HWND hDlg); -static BOOL OnMemSaveData(HWND hDlg); -static VOID StartTrace(VOID); -static VOID StopTrace(VOID); -static VOID FlushTrace(VOID); -static VOID OutTrace(VOID); -static BOOL OnTraceSettings(HWND hDlg); -static BOOL OnTraceEnable(HWND hDlg); - -//################ -//# -//# Low level subroutines -//# -//################ - -// -// load external rpl symbol table -// -static BOOL LoadSymbTable(VOID) -{ - TCHAR szSymbFilename[MAX_PATH]; - TCHAR szItemname[16]; - - wsprintf(szItemname,_T("Symb%c"),(TCHAR) cCurrentRomType); - ReadSettingsString(_T("Disassembler"),szItemname,_T(""),szSymbFilename,ARRAYSIZEOF(szSymbFilename)); - - if (*szSymbFilename == 0) // no reference table defined - return FALSE; // no success - - return RplLoadTable(szSymbFilename); // load external reference table -} - -// -// disable menu keys -// -static VOID DisableMenuKeys(HWND hDlg) -{ - HMENU hMenu = GetMenu(hDlg); - - EnableMenuItem(hMenu,ID_DEBUG_RUN,MF_GRAYED); - EnableMenuItem(hMenu,ID_DEBUG_RUNCURSOR,MF_GRAYED); - EnableMenuItem(hMenu,ID_DEBUG_STEP,MF_GRAYED); - EnableMenuItem(hMenu,ID_DEBUG_STEPOVER,MF_GRAYED); - EnableMenuItem(hMenu,ID_DEBUG_STEPOUT,MF_GRAYED); - EnableMenuItem(hMenu,ID_INFO_LASTINSTRUCTIONS,MF_GRAYED); - EnableMenuItem(hMenu,ID_INFO_WRITEONLYREG,MF_GRAYED); - - SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUN,MAKELONG((FALSE),0)); - SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_BREAK,MAKELONG((TRUE),0)); - SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUNCURSOR,MAKELONG((FALSE),0)); - SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEP,MAKELONG((FALSE),0)); - SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOVER,MAKELONG((FALSE),0)); - SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOUT,MAKELONG((FALSE),0)); - return; -} - -// -// read edit control and decode content as hex number or if enabled as symbol name -// -static BOOL GetAddr(HWND hDlg,INT nID,DWORD *pdwAddr,DWORD dwMaxAddr,BOOL bSymbEnable) -{ - TCHAR szBuffer[48]; - INT i; - BOOL bSucc = TRUE; - - HWND hWnd = GetDlgItem(hDlg,nID); - - GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer)); - - if (*szBuffer != 0) - { - // if address is not a symbol name decode number - if ( !bSymbEnable || szBuffer[0] != _T('=') - || RplGetAddr(&szBuffer[1],pdwAddr)) - { - // test if valid hex address - for (i = 0; bSucc && i < (LONG) lstrlen(szBuffer); ++i) - { - bSucc = (_istxdigit(szBuffer[i]) != 0); - } - - if (bSucc) // valid characters - { - // convert string to number - *pdwAddr = _tcstoul(szBuffer,NULL,16); - } - } - - // inside address range? - bSucc = bSucc && (*pdwAddr <= dwMaxAddr); - - if (!bSucc) // invalid address - { - SendMessage(hWnd,EM_SETSEL,0,-1); - SetFocus(hWnd); // focus to edit control - } - } - return bSucc; -} - -// -// set mapping menu -// -static VOID SetMappingMenu(HWND hDlg,UINT uID) -{ - enum MEM_MAPPING eMode; - LPTSTR szCaption; - - UINT uEnable = MF_GRAYED; // disable Memory Data menu items - - CheckMenuItem(hMenuMem,uIDMap,MF_UNCHECKED); - - switch (uID) - { - case ID_DEBUG_MEM_MAP: - szCaption = _T("Memory"); - eMode = MEM_MMU; - uEnable = MF_ENABLED; // enable Memory Data menu items - break; - case ID_DEBUG_MEM_NCE1: - szCaption = _T("Memory (NCE1)"); - eMode = MEM_NCE1; - break; - case ID_DEBUG_MEM_NCE2: - szCaption = _T("Memory (NCE2)"); - eMode = MEM_NCE2; - break; - case ID_DEBUG_MEM_CE1: - szCaption = _T("Memory (CE1)"); - eMode = MEM_CE1; - break; - case ID_DEBUG_MEM_CE2: - szCaption = _T("Memory (CE2)"); - eMode = MEM_CE2; - break; - case ID_DEBUG_MEM_NCE3: - szCaption = _T("Memory (NCE3)"); - eMode = MEM_NCE3; - break; - default: _ASSERT(0); - } - - VERIFY(SetMemMapType(eMode)); - - if (uIDMap != uID) dwAdrMem = 0; // view from address 0 - - uIDMap = uID; - CheckMenuItem(hMenuMem,uIDMap,MF_CHECKED); - - EnableMenuItem(hMenuMem,ID_DEBUG_MEM_LOAD,uEnable); - EnableMenuItem(hMenuMem,ID_DEBUG_MEM_SAVE,uEnable); - - SetDlgItemText(hDlg,IDC_STATIC_MEMORY,szCaption); - return; -}; - -// -// get address of cursor in memory window -// -static DWORD GetMemCurAddr(HWND hDlg) -{ - INT i,nPos; - DWORD dwAddr = dwAdrMem; - DWORD dwMapDataMask = GetMemDataMask(); - - for (i = 0; i < MEMWNDMAX; ++i) // scan all memory cols - { - // column has cursor - if ((nPos = (INT) SendDlgItemMessage(hDlg,nCol[i],LB_GETCURSEL,0,0)) != LB_ERR) - { - dwAddr += (DWORD) (nPos * MEMWNDMAX + i) * 2; - dwAddr &= dwMapDataMask; - break; - } - } - return dwAddr; -} - -// -// set/reset breakpoint -// -static __inline VOID ToggleBreakpoint(DWORD dwAddr) -{ - INT i; - - for (i = 0; i < wBreakpointCount; ++i) // scan all breakpoints - { - // code breakpoint found - if (sBreakpoint[i].nType == BP_EXEC && sBreakpoint[i].dwAddr == dwAddr) - { - if (!sBreakpoint[i].bEnable) // breakpoint disabled - { - sBreakpoint[i].bEnable = TRUE; - return; - } - - while (++i < wBreakpointCount) // purge breakpoint - sBreakpoint[i-1] = sBreakpoint[i]; - --wBreakpointCount; - return; - } - } - - // breakpoint not found - if (wBreakpointCount >= MAXBREAKPOINTS) // breakpoint buffer full - { - AbortMessage(_T("Reached maximum number of breakpoints !")); - return; - } - - sBreakpoint[wBreakpointCount].bEnable = TRUE; - sBreakpoint[wBreakpointCount].nType = BP_EXEC; - sBreakpoint[wBreakpointCount].dwAddr = dwAddr; - ++wBreakpointCount; - return; -} - -// -// init memory mapping table and mapping menu entry -// -static __inline VOID InitMemMap(HWND hDlg) -{ - BOOL bActive; - - SetMemRomType(cCurrentRomType); // set current model - - _ASSERT(hMenuMem); - - // enable menu mappings - EnableMenuItem(hMenuMem,ID_DEBUG_MEM_NCE1,GetMemAvail(MEM_NCE1) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenuMem,ID_DEBUG_MEM_NCE2,GetMemAvail(MEM_NCE2) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenuMem,ID_DEBUG_MEM_CE1, GetMemAvail(MEM_CE1) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenuMem,ID_DEBUG_MEM_CE2, GetMemAvail(MEM_CE2) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenuMem,ID_DEBUG_MEM_NCE3,GetMemAvail(MEM_NCE3) ? MF_ENABLED : MF_GRAYED); - - bActive = (ID_DEBUG_MEM_NCE1 == uIDMap && GetMemAvail(MEM_NCE1)) - || (ID_DEBUG_MEM_NCE2 == uIDMap && GetMemAvail(MEM_NCE2)) - || (ID_DEBUG_MEM_CE1 == uIDMap && GetMemAvail(MEM_CE1)) - || (ID_DEBUG_MEM_CE2 == uIDMap && GetMemAvail(MEM_CE2)) - || (ID_DEBUG_MEM_NCE3 == uIDMap && GetMemAvail(MEM_NCE3)); - - SetMappingMenu(hDlg,bActive ? uIDMap : ID_DEBUG_MEM_MAP); - return; -} - -// -// init bank switcher area -// -static __inline VOID InitBsArea(HWND hDlg) -{ - // HP39/40G, HP48GX, HP49G - if (cCurrentRomType=='E' || cCurrentRomType=='G' || cCurrentRomType=='X') - { - EnableWindow(GetDlgItem(hDlg,IDC_MISC_BS_TXT),TRUE); - EnableWindow(GetDlgItem(hDlg,IDC_MISC_BS),TRUE); - } - return; -} - -// -// convert nibble register to string -// -static LPTSTR RegToStr(BYTE *pReg, WORD wNib) -{ - static TCHAR szBuffer[32]; - - WORD i; - - for (i = 0;i < wNib;++i) - szBuffer[i] = cHex[pReg[wNib-i-1]]; - szBuffer[i] = 0; - - return szBuffer; -} - -// -// convert string to nibble register -// -static VOID StrToReg(BYTE *pReg, WORD wNib, LPTSTR lpszValue) -{ - int i,nValuelen; - - nValuelen = lstrlen(lpszValue); - for (i = wNib - 1;i >= 0;--i) - { - if (i >= nValuelen) // no character in string - { - pReg[i] = 0; // fill with zero - } - else - { - // convert to number - pReg[i] = _totupper(*lpszValue) - _T('0'); - if (pReg[i] > 9) pReg[i] -= _T('A') - _T('9') - 1; - ++lpszValue; - } - } - return; -} - -// -// write code window -// -static INT ViewCodeWnd(HWND hWnd, DWORD dwAddress) -{ - enum MEM_MAPPING eMapMode; - LPCTSTR lpszName; - TCHAR szAddress[64]; - DWORD dwNxtAddr; - INT i,j,nLinePC; - - nLinePC = -1; // PC not shown (no selection) - - eMapMode = GetMemMapType(); // get current map mode - SetMemMapType(MEM_MMU); // disassemble in mapped mode - - dwAddress &= 0xFFFFF; // adjust to Saturn address range - SendMessage(hWnd,WM_SETREDRAW,FALSE,0); - SendMessage(hWnd,LB_RESETCONTENT,0,0); - for (i = 0; i < MAXCODELINES; ++i) - { - // entry has a name - if (disassembler_symb && (lpszName = RplGetName(dwAddress)) != NULL) - { - // save address as label - dwAdrLine[i] = dwAddress | CODELABEL; - - szAddress[0] = _T('='); - lstrcpyn(&szAddress[1],lpszName,ARRAYSIZEOF(szAddress)-1); - SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szAddress); - if (++i == MAXCODELINES) break; - } - - // remember line of PC - if (dwAddress == Chipset.pc) nLinePC = i; - - dwAdrLine[i] = dwAddress; - j = wsprintf(szAddress, - (dwAddress == Chipset.pc) ? _T("%05lX-%c ") : _T("%05lX "), - dwAddress,nRplBreak ? _T('R') : _T('>')); - - dwNxtAddr = (dwAddress + 5) & 0xFFFFF; - - // check if address content is a PCO (Primitive Code Object) - // make sure when the PC points to such an address that it's - // interpreted as opcode - if ((dwAddress != Chipset.pc) && (Read5(dwAddress) == dwNxtAddr)) - { - if (disassembler_mode == HP_MNEMONICS) - { - _tcscat(&szAddress[j],_T("CON(5) (*)+5")); - } - else - { - wsprintf(&szAddress[j],_T("dcr.5 $%05x"),dwNxtAddr); - } - dwAddress = dwNxtAddr; - } - else - { - dwAddress = disassemble(dwAddress,&szAddress[j]); - } - SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szAddress); - } - SendMessage(hWnd,WM_SETREDRAW,TRUE,0); - SetMemMapType(eMapMode); // switch back to old map mode - return nLinePC; -} - -// -// write memory window -// -static VOID ViewMemWnd(HWND hDlg, DWORD dwAddress) -{ - #define TEXTOFF 32 - - INT i,j; - TCHAR szBuffer[16],szItem[4]; - DWORD dwMapDataMask; - BYTE cChar; - - szItem[2] = 0; // end of string - dwAdrMem = dwAddress; // save start address of memory window - dwMapDataMask = GetMemDataMask(); // size mask of data mapping - - // purge all list boxes - SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_ADDR,LB_RESETCONTENT,0,0); - SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_TEXT,LB_RESETCONTENT,0,0); - for (j = 0; j < MEMWNDMAX; ++j) - SendDlgItemMessage(hDlg,nCol[j],LB_RESETCONTENT,0,0); - - for (i = 0; i < MAXMEMLINES; ++i) - { - BYTE byLineData[MAXMEMITEMS]; - - if (ID_DEBUG_MEM_MAP == uIDMap) // mapped memory content - { - wsprintf(szBuffer,_T("%05lX"),dwAddress); - } - else // module memory content - { - wsprintf(szBuffer,_T("%06lX"),dwAddress); - } - SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_ADDR,LB_ADDSTRING,0,(LPARAM) szBuffer); - - // fetch data line - GetMemPeek(byLineData, dwAddress, MAXMEMITEMS); - - for (j = 0; j < MAXMEMITEMS; ++j) - { - // read from fetched data line - szItem[j&0x1] = cHex[byLineData[j]]; - // characters are saved in LBS, MSB order - cChar = (cChar >> 4) | (byLineData[j] << 4); - - if ((j&0x1) != 0) - { - // byte field - _ASSERT(j/2 < MEMWNDMAX); - SendDlgItemMessage(hDlg,nCol[j/2],LB_ADDSTRING,0,(LPARAM) szItem); - - // text field - szBuffer[j/2] = (isprint(cChar) != 0) ? cChar : _T('.'); - } - } - szBuffer[j/2] = 0; // end of text string - SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_TEXT,LB_ADDSTRING,0,(LPARAM) szBuffer); - - dwAddress = (dwAddress + MAXMEMITEMS) & dwMapDataMask; - } - return; - #undef TEXTOFF -} - - -//################ -//# -//# High level Window draw routines -//# -//################ - -// -// update code window with scrolling -// -static VOID UpdateCodeWnd(HWND hDlg) -{ - DWORD dwAddress,dwPriorAddr; - INT i,j; - - HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE); - - j = (INT) SendMessage(hWnd,LB_GETCOUNT,0,0); // no. of items in table - - // seach for actual address in code area - for (i = 0; i < j; ++i) - { - if (dwAdrLine[i] == Chipset.pc) // found new pc address line - break; - } - - // redraw code window - dwAddress = dwAdrLine[0]; // redraw list box with modified pc - if (i == j) // address not found - { - dwAddress = Chipset.pc; // begin with actual pc - - // check if current pc is the begin of a PCO, show PCO address - dwPriorAddr = (dwAddress - 5) & 0xFFFFF; - if (Read5(dwPriorAddr) == dwAddress) - dwAddress = dwPriorAddr; - } - else - { - if (i > 10) // cursor near bottom line - { - j = 10; // pc to line 11 - - // new address line is label - if ((dwAdrLine[i-11] & CODELABEL) != 0) - --j; // pc to line 10 - - dwAddress = dwAdrLine[i-j]; // move that pc is in line 11 - } - } - - i = ViewCodeWnd(hWnd,dwAddress); // init code area - SendMessage(hWnd,LB_SETCURSEL,i,0); // set cursor on actual pc - return; -} - -// -// update register window -// -static VOID UpdateRegisterWnd(HWND hDlg) -{ - TCHAR szBuffer[64]; - - _ASSERTREG(IDC_REG_A); - bRegUpdate[IDC_REG_A-REG_START] = memcmp(Chipset.A, OldChipset.A, sizeof(Chipset.A)) != 0; - wsprintf(szBuffer,_T("A= %s"),RegToStr(Chipset.A,16)); - SetDlgItemText(hDlg,IDC_REG_A,szBuffer); - _ASSERTREG(IDC_REG_B); - bRegUpdate[IDC_REG_B-REG_START] = memcmp(Chipset.B, OldChipset.B, sizeof(Chipset.B)) != 0; - wsprintf(szBuffer,_T("B= %s"),RegToStr(Chipset.B,16)); - SetDlgItemText(hDlg,IDC_REG_B,szBuffer); - _ASSERTREG(IDC_REG_C); - bRegUpdate[IDC_REG_C-REG_START] = memcmp(Chipset.C, OldChipset.C, sizeof(Chipset.C)) != 0; - wsprintf(szBuffer,_T("C= %s"),RegToStr(Chipset.C,16)); - SetDlgItemText(hDlg,IDC_REG_C,szBuffer); - _ASSERTREG(IDC_REG_D); - bRegUpdate[IDC_REG_D-REG_START] = memcmp(Chipset.D, OldChipset.D, sizeof(Chipset.D)) != 0; - wsprintf(szBuffer,_T("D= %s"),RegToStr(Chipset.D,16)); - SetDlgItemText(hDlg,IDC_REG_D,szBuffer); - _ASSERTREG(IDC_REG_R0); - bRegUpdate[IDC_REG_R0-REG_START] = memcmp(Chipset.R0, OldChipset.R0, sizeof(Chipset.R0)) != 0; - wsprintf(szBuffer,_T("R0=%s"),RegToStr(Chipset.R0,16)); - SetDlgItemText(hDlg,IDC_REG_R0,szBuffer); - _ASSERTREG(IDC_REG_R1); - bRegUpdate[IDC_REG_R1-REG_START] = memcmp(Chipset.R1, OldChipset.R1, sizeof(Chipset.R1)) != 0; - wsprintf(szBuffer,_T("R1=%s"),RegToStr(Chipset.R1,16)); - SetDlgItemText(hDlg,IDC_REG_R1,szBuffer); - _ASSERTREG(IDC_REG_R2); - bRegUpdate[IDC_REG_R2-REG_START] = memcmp(Chipset.R2, OldChipset.R2, sizeof(Chipset.R2)) != 0; - wsprintf(szBuffer,_T("R2=%s"),RegToStr(Chipset.R2,16)); - SetDlgItemText(hDlg,IDC_REG_R2,szBuffer); - _ASSERTREG(IDC_REG_R3); - bRegUpdate[IDC_REG_R3-REG_START] = memcmp(Chipset.R3, OldChipset.R3, sizeof(Chipset.R3)) != 0; - wsprintf(szBuffer,_T("R3=%s"),RegToStr(Chipset.R3,16)); - SetDlgItemText(hDlg,IDC_REG_R3,szBuffer); - _ASSERTREG(IDC_REG_R4); - bRegUpdate[IDC_REG_R4-REG_START] = memcmp(Chipset.R4, OldChipset.R4, sizeof(Chipset.R4)) != 0; - wsprintf(szBuffer,_T("R4=%s"),RegToStr(Chipset.R4,16)); - SetDlgItemText(hDlg,IDC_REG_R4,szBuffer); - _ASSERTREG(IDC_REG_D0); - bRegUpdate[IDC_REG_D0-REG_START] = Chipset.d0 != OldChipset.d0; - wsprintf(szBuffer,_T("D0=%05X"),Chipset.d0); - SetDlgItemText(hDlg,IDC_REG_D0,szBuffer); - _ASSERTREG(IDC_REG_D1); - bRegUpdate[IDC_REG_D1-REG_START] = Chipset.d1 != OldChipset.d1; - wsprintf(szBuffer,_T("D1=%05X"),Chipset.d1); - SetDlgItemText(hDlg,IDC_REG_D1,szBuffer); - _ASSERTREG(IDC_REG_P); - bRegUpdate[IDC_REG_P-REG_START] = Chipset.P != OldChipset.P; - wsprintf(szBuffer,_T("P=%X"),Chipset.P); - SetDlgItemText(hDlg,IDC_REG_P,szBuffer); - _ASSERTREG(IDC_REG_PC); - bRegUpdate[IDC_REG_PC-REG_START] = Chipset.pc != OldChipset.pc; - wsprintf(szBuffer,_T("PC=%05X"),Chipset.pc); - SetDlgItemText(hDlg,IDC_REG_PC,szBuffer); - _ASSERTREG(IDC_REG_OUT); - bRegUpdate[IDC_REG_OUT-REG_START] = Chipset.out != OldChipset.out; - wsprintf(szBuffer,_T("OUT=%03X"),Chipset.out); - SetDlgItemText(hDlg,IDC_REG_OUT,szBuffer); - _ASSERTREG(IDC_REG_IN); - bRegUpdate[IDC_REG_IN-REG_START] = Chipset.in != OldChipset.in; - wsprintf(szBuffer,_T("IN=%04X"),Chipset.in); - SetDlgItemText(hDlg,IDC_REG_IN,szBuffer); - _ASSERTREG(IDC_REG_ST); - bRegUpdate[IDC_REG_ST-REG_START] = memcmp(Chipset.ST, OldChipset.ST, sizeof(Chipset.ST)) != 0; - wsprintf(szBuffer,_T("ST=%s"),RegToStr(Chipset.ST,4)); - SetDlgItemText(hDlg,IDC_REG_ST,szBuffer); - _ASSERTREG(IDC_REG_CY); - bRegUpdate[IDC_REG_CY-REG_START] = Chipset.carry != OldChipset.carry; - wsprintf(szBuffer,_T("CY=%d"),Chipset.carry); - SetDlgItemText(hDlg,IDC_REG_CY,szBuffer); - _ASSERTREG(IDC_REG_MODE); - bRegUpdate[IDC_REG_MODE-REG_START] = Chipset.mode_dec != OldChipset.mode_dec; - wsprintf(szBuffer,_T("Mode=%c"),Chipset.mode_dec ? _T('D') : _T('H')); - SetDlgItemText(hDlg,IDC_REG_MODE,szBuffer); - _ASSERTREG(IDC_REG_MP); - bRegUpdate[IDC_REG_MP-REG_START] = ((Chipset.HST ^ OldChipset.HST) & MP) != 0; - wsprintf(szBuffer,_T("MP=%d"),(Chipset.HST & MP) != 0); - SetDlgItemText(hDlg,IDC_REG_MP,szBuffer); - _ASSERTREG(IDC_REG_SR); - bRegUpdate[IDC_REG_SR-REG_START] = ((Chipset.HST ^ OldChipset.HST) & SR) != 0; - wsprintf(szBuffer,_T("SR=%d"),(Chipset.HST & SR) != 0); - SetDlgItemText(hDlg,IDC_REG_SR,szBuffer); - _ASSERTREG(IDC_REG_SB); - bRegUpdate[IDC_REG_SB-REG_START] = ((Chipset.HST ^ OldChipset.HST) & SB) != 0; - wsprintf(szBuffer,_T("SB=%d"),(Chipset.HST & SB) != 0); - SetDlgItemText(hDlg,IDC_REG_SB,szBuffer); - _ASSERTREG(IDC_REG_XM); - bRegUpdate[IDC_REG_XM-REG_START] = ((Chipset.HST ^ OldChipset.HST) & XM) != 0; - wsprintf(szBuffer,_T("XM=%d"),(Chipset.HST & XM) != 0); - SetDlgItemText(hDlg,IDC_REG_XM,szBuffer); - return; -} - -// -// update memory window -// -static VOID UpdateMemoryWnd(HWND hDlg) -{ - // check follow mode setting for memory window - switch(uIDFol) - { - case ID_DEBUG_MEM_FNONE: break; - case ID_DEBUG_MEM_FADDR: dwAdrMem = Read5(dwAdrMemFol); break; - case ID_DEBUG_MEM_FPC: dwAdrMem = Chipset.pc; break; - case ID_DEBUG_MEM_FD0: dwAdrMem = Chipset.d0; break; - case ID_DEBUG_MEM_FD1: dwAdrMem = Chipset.d1; break; - default: _ASSERT(FALSE); - } - - ViewMemWnd(hDlg,dwAdrMem); - return; -} - -// -// update stack window -// -static VOID UpdateStackWnd(HWND hDlg) -{ - UINT i; - LONG nPos; - TCHAR szBuffer[64]; - - HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK); - - SendMessage(hWnd,WM_SETREDRAW,FALSE,0); - nPos = (LONG) SendMessage(hWnd,LB_GETTOPINDEX,0,0); - SendMessage(hWnd,LB_RESETCONTENT,0,0); - for (i = 1; i <= ARRAYSIZEOF(Chipset.rstk); ++i) - { - INT j; - - wsprintf(szBuffer,_T("%d: %05X"), i, Chipset.rstk[(Chipset.rstkp-i)&7]); - j = (INT) SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); - SendMessage(hWnd,LB_SETITEMDATA,j,Chipset.rstk[(Chipset.rstkp-i)&7]); - } - SendMessage(hWnd,LB_SETTOPINDEX,nPos,0); - SendMessage(hWnd,WM_SETREDRAW,TRUE,0); - return; -} - -// -// update MMU window -// -static VOID UpdateMmuWnd(HWND hDlg) -{ - TCHAR szBuffer[64]; - - if (Chipset.IOCfig) - wsprintf(szBuffer,_T("%05X"),Chipset.IOBase); - else - lstrcpy(szBuffer,_T("-----")); - SetDlgItemText(hDlg,IDC_MMU_IO_A,szBuffer); - if (Chipset.P0Cfig) - wsprintf(szBuffer,_T("%05X"),Chipset.P0Base<<12); - else - lstrcpy(szBuffer,_T("-----")); - SetDlgItemText(hDlg,IDC_MMU_NCE2_A,szBuffer); - if (Chipset.P0Cfg2) - wsprintf(szBuffer,_T("%05X"),(Chipset.P0Size^0xFF)<<12); - else - lstrcpy(szBuffer,_T("-----")); - SetDlgItemText(hDlg,IDC_MMU_NCE2_S,szBuffer); - if (Chipset.P1Cfig) - wsprintf(szBuffer,_T("%05X"),Chipset.P1Base<<12); - else - lstrcpy(szBuffer,_T("-----")); - SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE1_A : IDC_MMU_CE2_A,szBuffer); - if (Chipset.P1Cfg2) - wsprintf(szBuffer,_T("%05X"),(Chipset.P1Size^0xFF)<<12); - else - lstrcpy(szBuffer,_T("-----")); - SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE1_S : IDC_MMU_CE2_S,szBuffer); - if (Chipset.P2Cfig) - wsprintf(szBuffer,_T("%05X"),Chipset.P2Base<<12); - else - lstrcpy(szBuffer,_T("-----")); - SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE2_A : IDC_MMU_NCE3_A,szBuffer); - if (Chipset.P2Cfg2) - wsprintf(szBuffer,_T("%05X"),(Chipset.P2Size^0xFF)<<12); - else - lstrcpy(szBuffer,_T("-----")); - SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE2_S : IDC_MMU_NCE3_S,szBuffer); - if (Chipset.BSCfig) - wsprintf(szBuffer,_T("%05X"),Chipset.BSBase<<12); - else - lstrcpy(szBuffer,_T("-----")); - SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_NCE3_A : IDC_MMU_CE1_A,szBuffer); - if (Chipset.BSCfg2) - wsprintf(szBuffer,_T("%05X"),(Chipset.BSSize^0xFF)<<12); - else - lstrcpy(szBuffer,_T("-----")); - SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_NCE3_S : IDC_MMU_CE1_S,szBuffer); - return; -} - -// -// update miscellaneous window -// -static VOID UpdateMiscWnd(HWND hDlg) -{ - _ASSERTREG(IDC_MISC_INT); - bRegUpdate[IDC_MISC_INT-REG_START] = Chipset.inte != OldChipset.inte; - SetDlgItemText(hDlg,IDC_MISC_INT,Chipset.inte ? _T("On ") : _T("Off")); - - _ASSERTREG(IDC_MISC_KEY); - bRegUpdate[IDC_MISC_KEY-REG_START] = Chipset.intk != OldChipset.intk; - SetDlgItemText(hDlg,IDC_MISC_KEY,Chipset.intk ? _T("On ") : _T("Off")); - - _ASSERTREG(IDC_MISC_BS); - bRegUpdate[IDC_MISC_BS-REG_START] = FALSE; - - // HP39/40G, HP48GX, HP49G - if (cCurrentRomType=='E' || cCurrentRomType=='G' || cCurrentRomType=='X') - { - TCHAR szBuffer[64]; - - bRegUpdate[IDC_MISC_BS-REG_START] = (Chipset.Bank_FF & 0x7F) != (OldChipset.Bank_FF & 0x7F); - wsprintf(szBuffer,_T("%02X"),Chipset.Bank_FF & 0x7F); - SetDlgItemText(hDlg,IDC_MISC_BS,szBuffer); - } - return; -} - -// -// update complete debugger dialog -// -VOID OnUpdate(HWND hDlg) -{ - nDbgState = DBG_STEPINTO; // state "step into" - dwDbgStopPC = -1; // disable "cursor stop address" - - // enable debug buttons - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_RUN,MF_ENABLED); - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_RUNCURSOR,MF_ENABLED); - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEP,MF_ENABLED); - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEPOVER,MF_ENABLED); - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEPOUT,MF_ENABLED); - EnableMenuItem(GetMenu(hDlg),ID_INFO_LASTINSTRUCTIONS,MF_ENABLED); - EnableMenuItem(GetMenu(hDlg),ID_INFO_WRITEONLYREG,MF_ENABLED); - - // enable toolbar buttons - SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUN,MAKELONG((TRUE),0)); - SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_BREAK,MAKELONG((FALSE),0)); - SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUNCURSOR,MAKELONG((TRUE),0)); - SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEP,MAKELONG((TRUE),0)); - SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOVER,MAKELONG((TRUE),0)); - SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOUT,MAKELONG((TRUE),0)); - - // update windows - UpdateCodeWnd(hDlg); // update code window - UpdateRegisterWnd(hDlg); // update registers window - UpdateMemoryWnd(hDlg); // update memory window - UpdateStackWnd(hDlg); // update stack window - UpdateMmuWnd(hDlg); // update MMU window - UpdateMiscWnd(hDlg); // update bank switcher window - UpdateProfileWnd(hDlgProfile); // update profiler dialog - ShowWindow(hDlg,SW_RESTORE); // pop up if minimized - SetFocus(hDlg); // set focus to debugger - return; -} - - -//################ -//# -//# Virtual key handler -//# -//################ - -// -// toggle breakpoint key handler (F2) -// -static BOOL OnKeyF2(HWND hDlg) -{ - HWND hWnd; - RECT rc; - LONG i; - - hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE); - i = (LONG) SendMessage(hWnd,LB_GETCURSEL,0,0); // get selected item - ToggleBreakpoint(dwAdrLine[i]); // toggle breakpoint at address - // update region of toggled item - SendMessage(hWnd,LB_GETITEMRECT,i,(LPARAM)&rc); - InvalidateRect(hWnd,&rc,TRUE); - return -1; // call windows default handler -} - -// -// run key handler (F5) -// -static BOOL OnKeyF5(HWND hDlg) -{ - HWND hWnd; - INT i,nPos; - TCHAR szBuf[64]; - - if (nDbgState != DBG_RUN) // emulation stopped - { - DisableMenuKeys(hDlg); // disable menu keys - - hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE); - nPos = (INT) SendMessage(hWnd,LB_GETCURSEL,0,0); - - // clear "->" in code window - for (i = 0; i < MAXCODELINES; ++i) - { - if (dwAdrLine[i] == Chipset.pc) // PC in window - { - SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuf); - szBuf[5] = szBuf[6] = _T(' '); - SendMessage(hWnd,LB_DELETESTRING,i,0); - SendMessage(hWnd,LB_INSERTSTRING,i,(LPARAM) szBuf); - break; - } - } - SendMessage(hWnd,LB_SETCURSEL,nPos,0); - - nDbgState = DBG_RUN; // state "run" - OldChipset = Chipset; // save chipset values - SetEvent(hEventDebug); // run emulation - } - return -1; // call windows default handler - UNREFERENCED_PARAMETER(hDlg); -} - -// -// step cursor key handler (F6) -// -static BOOL OnKeyF6(HWND hDlg) -{ - if (nDbgState != DBG_RUN) // emulation stopped - { - // get address of selected item - INT nPos = (INT) SendDlgItemMessage(hDlg,IDC_DEBUG_CODE,LB_GETCURSEL,0,0); - dwDbgStopPC = dwAdrLine[nPos]; - - OnKeyF5(hDlg); // run emulation - } - return -1; // call windows default handler -} - -// -// step into key handler (F7) -// -static BOOL OnKeyF7(HWND hDlg) -{ - if (nDbgState != DBG_RUN) // emulation stopped - { - if (bDbgSkipInt) // skip code in interrupt handler - DisableMenuKeys(hDlg); // disable menu keys - - nDbgState = DBG_STEPINTO; // state "step into" - OldChipset = Chipset; // save chipset values - SetEvent(hEventDebug); // run emulation - } - return -1; // call windows default handler - UNREFERENCED_PARAMETER(hDlg); -} - -// -// step over key handler (F8) -// -static BOOL OnKeyF8(HWND hDlg) -{ - if (nDbgState != DBG_RUN) // emulation stopped - { - LPBYTE I = FASTPTR(Chipset.pc); - - if (bDbgSkipInt) // skip code in interrupt handler - DisableMenuKeys(hDlg); // disable menu keys - - dwDbgRstkp = Chipset.rstkp; // save stack level - - // GOSUB 7aaa, GOSUBL 8Eaaaa, GOSBVL 8Faaaaa - if (I[0] == 0x7 || (I[0] == 0x8 && (I[1] == 0xE || I[1] == 0xF))) - { - nDbgState = DBG_STEPOVER; // state "step over" - } - else - { - nDbgState = DBG_STEPINTO; // state "step into" - } - OldChipset = Chipset; // save chipset values - SetEvent(hEventDebug); // run emulation - } - return -1; // call windows default handler - UNREFERENCED_PARAMETER(hDlg); -} - -// -// step out key handler (F9) -// -static BOOL OnKeyF9(HWND hDlg) -{ - if (nDbgState != DBG_RUN) // emulation stopped - { - DisableMenuKeys(hDlg); // disable menu keys - dwDbgRstkp = (Chipset.rstkp-1)&7; // save stack data - dwDbgRstk = Chipset.rstk[dwDbgRstkp]; - nDbgState = DBG_STEPOUT; // state "step out" - OldChipset = Chipset; // save chipset values - SetEvent(hEventDebug); // run emulation - } - return -1; // call windows default handler - UNREFERENCED_PARAMETER(hDlg); -} - -// -// break key handler (F11) -// -static BOOL OnKeyF11(HWND hDlg) -{ - nDbgState = DBG_STEPINTO; // state "step into" - if (Chipset.Shutdn) // cpu thread stopped - SetEvent(hEventShutdn); // goto debug session - return -1; // call windows default handler - UNREFERENCED_PARAMETER(hDlg); -} - -// -// view of given address in disassembler window -// -static BOOL OnCodeGoAdr(HWND hDlg) -{ - DWORD dwAddress = -1; // no address given - - OnEnterAddress(hDlg, &dwAddress); - if (dwAddress != -1) - { - HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE); - ViewCodeWnd(hWnd,dwAddress); - SendMessage(hWnd,LB_SETCURSEL,0,0); - } - return -1; // call windows default handler -} - -// -// view pc in disassembler window -// -static BOOL OnCodeGoPC(HWND hDlg) -{ - UpdateCodeWnd(hDlg); - return 0; -} - -// -// set pc to selection -// -static BOOL OnCodeSetPcToSelection(HWND hDlg) -{ - Chipset.pc = dwAdrLine[SendDlgItemMessage(hDlg,IDC_DEBUG_CODE,LB_GETCURSEL,0,0)]; - return OnCodeGoPC(hDlg); -} - -// -// find PCO object in code window -// -static BOOL OnCodeFindPCO(HWND hDlg,DWORD dwAddr,INT nSearchDir) -{ - DWORD dwCnt; - BOOL bMatch; - - // searching upwards / downwards - _ASSERT(nSearchDir == 1 || nSearchDir == -1); - - dwAddr += nSearchDir; // start address for search - - // scan mapped address area until PCO found - for (dwCnt = 0; dwCnt <= 0xFFFFF; ++dwCnt) - { - // is this a PCO? - bMatch = (Read5(dwAddr & 0xFFFFF) == ((dwAddr + 5) & 0xFFFFF)); - - if (bMatch) - { - // update code window - ViewCodeWnd(GetDlgItem(hDlg,IDC_DEBUG_CODE),dwAddr); - break; - } - - dwAddr += nSearchDir; - } - return 0; -} - -// -// view from address in memory window -// -static BOOL OnMemGoDx(HWND hDlg, DWORD dwAddress) -{ - HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_MEM_COL0); - - ViewMemWnd(hDlg, dwAddress); - SendMessage(hWnd,LB_SETCURSEL,0,0); - SetFocus(hWnd); - return -1; // call windows default handler -} - -// -// view of given address in memory window -// -static BOOL OnMemGoAdr(HWND hDlg) -{ - DWORD dwAddress = -1; // no address given - - OnEnterAddress(hDlg, &dwAddress); - if (dwAddress != -1) // not Cancel key - OnMemGoDx(hDlg,dwAddress & GetMemDataMask()); - return -1; // call windows default handler -} - -// -// view from address in memory window -// -static BOOL OnMemFollow(HWND hDlg,UINT uID) -{ - if (ID_DEBUG_MEM_FADDR == uID) // ask for follow address - { - DWORD dwAddress = -1; // no address given - - OnEnterAddress(hDlg, &dwAddress); - if (dwAddress == -1) return -1; // return at cancel button - - dwAdrMemFol = dwAddress; - } - - CheckMenuItem(hMenuMem,uIDFol,MF_UNCHECKED); - uIDFol = uID; - CheckMenuItem(hMenuMem,uIDFol,MF_CHECKED); - UpdateMemoryWnd(hDlg); // update memory window - return -1; // call windows default handler -} - -// -// clear all breakpoints -// -static BOOL OnClearAll(HWND hDlg) -{ - wBreakpointCount = 0; - // redraw code window - InvalidateRect(GetDlgItem(hDlg,IDC_DEBUG_CODE),NULL,TRUE); - return 0; -} - -// -// toggle menu selection -// -static BOOL OnToggleMenuItem(HWND hDlg,UINT uIDCheckItem,BOOL *bCheck) -{ - *bCheck = !*bCheck; // toggle flag - CheckMenuItem(GetMenu(hDlg),uIDCheckItem,*bCheck ? MF_CHECKED : MF_UNCHECKED); - return 0; -} - -// -// change memory window mapping style -// -static BOOL OnMemMapping(HWND hDlg,UINT uID) -{ - if (uID == uIDMap) return -1; // same view, call windows default handler - - SetMappingMenu(hDlg,uID); // update menu settings - UpdateMemoryWnd(hDlg); // update memory window - return 0; -} - -// -// push value on hardware stack -// -static BOOL OnStackPush(HWND hDlg) -{ - TCHAR szBuffer[] = _T("00000"); - DWORD dwAddr; - HWND hWnd; - UINT i,j; - - if (nDbgState != DBG_STEPINTO) // not in single step mode - return TRUE; - - hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK); - - i = (UINT) SendMessage(hWnd,LB_GETCURSEL,0,0); - if (LB_ERR == (INT) i) return TRUE; // no selection - - if (IDOK != OnNewValue(szBuffer)) // canceled function - return TRUE; - _stscanf(szBuffer,_T("%5X"),&dwAddr); - - // push stack element - for (j = ARRAYSIZEOF(Chipset.rstk); j > i + 1; --j) - { - Chipset.rstk[(Chipset.rstkp-j)&7] = Chipset.rstk[(Chipset.rstkp-j+1)&7]; - } - Chipset.rstk[(Chipset.rstkp-j)&7] = dwAddr; - - UpdateStackWnd(hDlg); // update stack window - SendMessage(hWnd,LB_SETCURSEL,i,0); // restore cursor postion - return 0; -} - -// -// pop value from hardware stack -// -static BOOL OnStackPop(HWND hDlg) -{ - HWND hWnd; - UINT i,j; - - if (nDbgState != DBG_STEPINTO) // not in single step mode - return TRUE; - - hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK); - - i = (UINT) SendMessage(hWnd,LB_GETCURSEL,0,0); - if (LB_ERR == (INT) i) return TRUE; // no selection - - // pop stack element - for (j = i + 1; j < ARRAYSIZEOF(Chipset.rstk); ++j) - { - Chipset.rstk[(Chipset.rstkp-j)&7] = Chipset.rstk[(Chipset.rstkp-j-1)&7]; - } - Chipset.rstk[Chipset.rstkp] = 0; - - UpdateStackWnd(hDlg); // update stack window - SendMessage(hWnd,LB_SETCURSEL,i,0); // restore cursor postion - return 0; -} - -// modify value on hardware stack -static BOOL OnStackModify(HWND hDlg) -{ - TCHAR szBuffer[16]; - HWND hWnd; - INT i; - - if (nDbgState != DBG_STEPINTO) // not in single step mode - return TRUE; - - hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK); - - i = (INT) SendMessage(hWnd,LB_GETCURSEL,0,0); - if (LB_ERR == i) return TRUE; // no selection - - SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuffer); - OnNewValue(&szBuffer[3]); - _stscanf(&szBuffer[3],_T("%5X"),&Chipset.rstk[(Chipset.rstkp-i-1)&7]); - - UpdateStackWnd(hDlg); // update stack window - SendMessage(hWnd,LB_SETCURSEL,i,0); // restore cursor postion - return 0; -} - -// -// new register setting -// -static BOOL OnLButtonUp(HWND hDlg, LPARAM lParam) -{ - TCHAR szBuffer[64]; - POINT pt; - HWND hWnd; - INT nId; - - if (nDbgState != DBG_STEPINTO) // not in single step mode - return TRUE; - - POINTSTOPOINT(pt,MAKEPOINTS(lParam)); - - // handle of selected window - hWnd = ChildWindowFromPointEx(hDlg,pt,CWP_SKIPDISABLED); - nId = GetDlgCtrlID(hWnd); // control ID of window - - GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer)); - switch (nId) - { - case IDC_REG_A: // A - OnNewValue(&szBuffer[3]); - StrToReg(Chipset.A,16,&szBuffer[3]); - break; - case IDC_REG_B: // B - OnNewValue(&szBuffer[3]); - StrToReg(Chipset.B,16,&szBuffer[3]); - break; - case IDC_REG_C: // C - OnNewValue(&szBuffer[3]); - StrToReg(Chipset.C,16,&szBuffer[3]); - break; - case IDC_REG_D: // D - OnNewValue(&szBuffer[3]); - StrToReg(Chipset.D,16,&szBuffer[3]); - break; - case IDC_REG_R0: // R0 - OnNewValue(&szBuffer[3]); - StrToReg(Chipset.R0,16,&szBuffer[3]); - break; - case IDC_REG_R1: // R1 - OnNewValue(&szBuffer[3]); - StrToReg(Chipset.R1,16,&szBuffer[3]); - break; - case IDC_REG_R2: // R2 - OnNewValue(&szBuffer[3]); - StrToReg(Chipset.R2,16,&szBuffer[3]); - break; - case IDC_REG_R3: // R3 - OnNewValue(&szBuffer[3]); - StrToReg(Chipset.R3,16,&szBuffer[3]); - break; - case IDC_REG_R4: // R4 - OnNewValue(&szBuffer[3]); - StrToReg(Chipset.R4,16,&szBuffer[3]); - break; - case IDC_REG_D0: // D0 - OnNewValue(&szBuffer[3]); - _stscanf(&szBuffer[3],_T("%5X"),&Chipset.d0); - break; - case IDC_REG_D1: // D1 - OnNewValue(&szBuffer[3]); - _stscanf(&szBuffer[3],_T("%5X"),&Chipset.d1); - break; - case IDC_REG_P: // P - OnNewValue(&szBuffer[2]); - Chipset.P = _totupper(szBuffer[2]) - _T('0'); - if (Chipset.P > 9) Chipset.P -= 7; - PCHANGED; - break; - case IDC_REG_PC: // PC - OnNewValue(&szBuffer[3]); - _stscanf(&szBuffer[3],_T("%5X"),&Chipset.pc); - break; - case IDC_REG_OUT: // OUT - OnNewValue(&szBuffer[4]); - Chipset.out = (WORD) _tcstoul(&szBuffer[4],NULL,16); - break; - case IDC_REG_IN: // IN - OnNewValue(&szBuffer[3]); - Chipset.in = (WORD) _tcstoul(&szBuffer[3],NULL,16); - break; - case IDC_REG_ST: // ST - OnNewValue(&szBuffer[3]); - StrToReg(Chipset.ST,4,&szBuffer[3]); - break; - case IDC_REG_CY: // CY - Chipset.carry = !Chipset.carry; - break; - case IDC_REG_MODE: // MODE - Chipset.mode_dec = !Chipset.mode_dec; - break; - case IDC_REG_MP: // MP - Chipset.HST ^= MP; - break; - case IDC_REG_SR: // SR - Chipset.HST ^= SR; - break; - case IDC_REG_SB: // SB - Chipset.HST ^= SB; - break; - case IDC_REG_XM: // XM - Chipset.HST ^= XM; - break; - case IDC_MISC_INT: // interrupt status - Chipset.inte = !Chipset.inte; - UpdateMiscWnd(hDlg); // update miscellaneous window - break; - case IDC_MISC_KEY: // 1ms keyboard scan - Chipset.intk = !Chipset.intk; - UpdateMiscWnd(hDlg); // update miscellaneous window - break; - case IDC_MISC_BS: // Bank switcher setting - OnNewValue(szBuffer); - Chipset.Bank_FF = _tcstoul(szBuffer,NULL,16); - Chipset.Bank_FF &= 0x7F; - RomSwitch(Chipset.Bank_FF); // update memory mapping - - UpdateCodeWnd(hDlg); // update code window - UpdateMemoryWnd(hDlg); // update memory window - UpdateMiscWnd(hDlg); // update miscellaneous window - break; - } - UpdateRegisterWnd(hDlg); // update register - return TRUE; -} - -// -// double click in list box area -// -static BOOL OnDblClick(HWND hWnd, WORD wId) -{ - HWND hDlg,hWndCode; - TCHAR szBuffer[4]; - BYTE byData; - INT i; - DWORD dwAddress; - - hDlg = GetParent(hWnd); // dialog window handle - hWndCode = GetDlgItem(hDlg,IDC_DEBUG_CODE); - - if (wId == IDC_DEBUG_STACK) // stack list box - { - // get cpu address of selected item - i = (INT) SendMessage(hWnd,LB_GETCURSEL,0,0); - dwAddress = (DWORD) SendMessage(hWnd,LB_GETITEMDATA,i,0); - - ViewCodeWnd(hWndCode,dwAddress); // show code of this address - return TRUE; - } - - for (i = 0; i < MEMWNDMAX; ++i) // scan all Id's - if (nCol[i] == wId) // found ID - break; - - // not IDC_DEBUG_MEM window or module mode -> default handler - if (i == MEMWNDMAX || ID_DEBUG_MEM_MAP != uIDMap) - return FALSE; - - // calculate address of byte - dwAddress = i * 2; - i = (INT) SendMessage(hWnd,LB_GETCARETINDEX,0,0); - dwAddress += MAXMEMITEMS * i + dwAdrMem; - - // enter new value - SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuffer); - OnNewValue(szBuffer); - byData = (BYTE) _tcstoul(szBuffer,NULL,16); - byData = (byData >> 4) | (byData << 4); // change nibbles for writing - - Write2(dwAddress,byData); // write data - ViewCodeWnd(hWndCode,dwAdrLine[0]); // update code window - ViewMemWnd(hDlg,dwAdrMem); // update memory window - SendMessage(hWnd,LB_SETCURSEL,i,0); - return FALSE; -} - -// -// request for context menu -// -static VOID OnContextMenu(HWND hDlg, LPARAM lParam, WPARAM wParam) -{ - POINT pt; - INT nId; - - POINTSTOPOINT(pt,MAKEPOINTS(lParam)); // mouse position - - if (pt.x == -1 && pt.y == -1) // VK_APPS - { - RECT rc; - - GetWindowRect((HWND) wParam,&rc); // get position of active window - pt.x = rc.left + 5; - pt.y = rc.top + 5; - } - - nId = GetDlgCtrlID((HWND) wParam); // control ID of window - - switch(nId) - { - case IDC_DEBUG_CODE: // handle code window - TrackPopupMenu(hMenuCode,0,pt.x,pt.y,0,hDlg,NULL); - break; - - case IDC_DEBUG_MEM_COL0: - case IDC_DEBUG_MEM_COL1: - case IDC_DEBUG_MEM_COL2: - case IDC_DEBUG_MEM_COL3: - case IDC_DEBUG_MEM_COL4: - case IDC_DEBUG_MEM_COL5: - case IDC_DEBUG_MEM_COL6: - case IDC_DEBUG_MEM_COL7: // handle memory window - TrackPopupMenu(hMenuMem,0,pt.x,pt.y,0,hDlg,NULL); - break; - - case IDC_DEBUG_STACK: // handle stack window - TrackPopupMenu(hMenuStack,0,pt.x,pt.y,0,hDlg,NULL); - break; - } - return; -} - -// -// mouse setting for capturing window -// -static BOOL OnSetCursor(HWND hDlg) -{ - // debugger not active but cursor is over debugger window - if (bActFollowsMouse && GetActiveWindow() != hDlg) - { - // force debugger window to foreground - ForceForegroundWindow(GetLastActivePopup(hDlg)); - } - return FALSE; -} - -//################ -//# -//# Dialog handler -//# -//################ - -// -// handle right/left keys in memory window -// -static __inline BOOL OnKeyRightLeft(HWND hWnd, WPARAM wParam) -{ - HWND hWndNew; - WORD wX; - INT nId; - - nId = GetDlgCtrlID(hWnd); // control ID of window - - for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's - if (nCol[wX] == nId) // found ID - break; - - if (wX == MEMWNDMAX) return -1; // not IDC_DEBUG_MEM window, default handler - - // new position - wX = ((LOWORD(wParam) == VK_RIGHT) ? (wX + 1) : (wX + MEMWNDMAX - 1)) % MEMWNDMAX; - - // set new focus - hWndNew = GetDlgItem(GetParent(hWnd),nCol[wX]); - SendMessage(hWndNew,LB_SETCURSEL,HIWORD(wParam),0); - SetFocus(hWndNew); - return -2; -} - -// -// handle (page) up/down keys in memory window -// -static __inline BOOL OnKeyUpDown(HWND hWnd, WPARAM wParam) -{ - INT wX, wY; - INT nId; - - nId = GetDlgCtrlID(hWnd); // control ID of window - - for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's - if (nCol[wX] == nId) // found ID - break; - - if (wX == MEMWNDMAX) return -1; // not IDC_DEBUG_MEM window, default handler - - wY = HIWORD(wParam); // get old focus - - switch(LOWORD(wParam)) - { - case VK_NEXT: - dwAdrMem = (dwAdrMem + MAXMEMITEMS * MAXMEMLINES) & GetMemDataMask(); - ViewMemWnd(GetParent(hWnd),dwAdrMem); - SendMessage(hWnd,LB_SETCURSEL,wY,0); - return -2; - - case VK_PRIOR: - dwAdrMem = (dwAdrMem - MAXMEMITEMS * MAXMEMLINES) & GetMemDataMask(); - ViewMemWnd(GetParent(hWnd),dwAdrMem); - SendMessage(hWnd,LB_SETCURSEL,wY,0); - return -2; - - case VK_DOWN: - if (wY+1 >= MAXMEMLINES) - { - dwAdrMem = (dwAdrMem + MAXMEMITEMS) & GetMemDataMask(); - ViewMemWnd(GetParent(hWnd),dwAdrMem); - SendMessage(hWnd,LB_SETCURSEL,wY,0); - return -2; - } - break; - - case VK_UP: - if (wY == 0) - { - dwAdrMem = (dwAdrMem - MAXMEMITEMS) & GetMemDataMask(); - ViewMemWnd(GetParent(hWnd),dwAdrMem); - SendMessage(hWnd,LB_SETCURSEL,wY,0); - return -2; - } - break; - } - return -1; -} - -// -// handle (page) +/- keys in memory window -// -static __inline BOOL OnKeyPlusMinus(HWND hWnd, WPARAM wParam) -{ - INT wX, wY; - INT nId; - - nId = GetDlgCtrlID(hWnd); // control ID of window - - for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's - if (nCol[wX] == nId) // found ID - break; - - if (wX == MEMWNDMAX) return -1; // not IDC_DEBUG_MEM window, default handler - - wY = HIWORD(wParam); // get focus - - if (LOWORD(wParam) == VK_ADD) // move start address of memory view - dwAdrMem++; - else - dwAdrMem--; - dwAdrMem &= GetMemDataMask(); - - ViewMemWnd(GetParent(hWnd),dwAdrMem); // redraw memory view - SendMessage(hWnd,LB_SETCURSEL,wY,0); // set focus at old position - return -1; -} - -// -// handle keys in code window -// -static __inline BOOL OnKeyCodeWnd(HWND hDlg, WPARAM wParam) -{ - HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE); - WORD wKey = LOWORD(wParam); - WORD wItem = HIWORD(wParam); - - // down key on last line - if ((wKey == VK_DOWN || wKey == VK_NEXT) && wItem == MAXCODELINES - 1) - { - WORD i = ((dwAdrLine[0] & CODELABEL) != 0) ? 2 : 1; - - ViewCodeWnd(hWnd,dwAdrLine[i]); - SendMessage(hWnd,LB_SETCURSEL,wItem-i,0); - } - // up key on first line - if ((wKey == VK_UP || wKey == VK_PRIOR) && wItem == 0) - { - ViewCodeWnd(hWnd,dwAdrLine[0]-1); - } - - if (wKey == _T('G')) return OnCodeGoAdr(GetParent(hWnd)); // goto new address - - return -1; // process key -} - -// -// handle drawing in code window -// -static __inline BOOL OnDrawCodeWnd(LPDRAWITEMSTRUCT lpdis) -{ - TCHAR szBuf[64]; - COLORREF crBkColor; - COLORREF crTextColor; - HFONT hFont; - BOOL bBrk,bPC,bLabel; - - if (lpdis->itemID == -1) // no item in list box - return TRUE; - - // get item text - SendMessage(lpdis->hwndItem,LB_GETTEXT,lpdis->itemID,(LPARAM) szBuf); - - // line is a label - bLabel = ((dwAdrLine[lpdis->itemID] & CODELABEL) != 0); - - if (!bLabel) - { - // check for codebreakpoint - bBrk = CheckBreakpoint(dwAdrLine[lpdis->itemID],1,BP_EXEC); - bPC = szBuf[5] != _T(' '); // check if line of program counter - - crTextColor = COLOR_WHITE; // standard text color - - if (lpdis->itemState & ODS_SELECTED) // cursor line - { - if (bPC) // PC line - { - crBkColor = bBrk ? COLOR_DKGRAY : COLOR_TEAL; - } - else // normal line - { - crBkColor = bBrk ? COLOR_PURPLE : COLOR_NAVY; - } - } - else // not cursor line - { - if (bPC) // PC line - { - crBkColor = bBrk ? COLOR_OLIVE : COLOR_GREEN; - } - else // normal line - { - if (bBrk) - { - crBkColor = COLOR_MAROON; - } - else - { - crBkColor = COLOR_WHITE; - crTextColor = COLOR_BLACK; - } - } - } - } - else // label - { - crBkColor = COLOR_WHITE; - crTextColor = COLOR_NAVY; - hFont = (HFONT) SelectObject(lpdis->hDC,hFontBold); - } - - // write Text - crBkColor = SetBkColor(lpdis->hDC,crBkColor); - crTextColor = SetTextColor(lpdis->hDC,crTextColor); - - ExtTextOut(lpdis->hDC,(int)(lpdis->rcItem.left)+2,(int)(lpdis->rcItem.top), - ETO_OPAQUE,(LPRECT)&lpdis->rcItem,szBuf,lstrlen(szBuf),NULL); - - SetBkColor(lpdis->hDC,crBkColor); - SetTextColor(lpdis->hDC,crTextColor); - - if (bLabel) SelectObject(lpdis->hDC,hFont); - - if (lpdis->itemState & ODS_FOCUS) // redraw focus - DrawFocusRect(lpdis->hDC,&lpdis->rcItem); - - return TRUE; // focus handled here -} - -// -// detect changed register -// -static __inline BOOL OnCtlColorStatic(HWND hWnd) -{ - BOOL bError = FALSE; // not changed - - int nId = GetDlgCtrlID(hWnd); - if (nId >= REG_START && nId <= REG_STOP) // in register area - bError = bRegUpdate[nId-REG_START]; // register changed? - return bError; -} - - -//################ -//# -//# Public functions -//# -//################ - -// -// handle upper 32 bit of cpu cycle counter -// -VOID UpdateDbgCycleCounter(VOID) -{ - // update 64 bit cpu cycle counter - if (Chipset.cycles < dwDbgRefCycles) ++Chipset.cycles_reserved; - dwDbgRefCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF); - return; -} - -// -// check for breakpoints -// -BOOL CheckBreakpoint(DWORD dwAddr, DWORD dwRange, UINT nType) -{ - INT i; - - for (i = 0; i < wBreakpointCount; ++i) // scan all breakpoints - { - // check address range and type - if ( sBreakpoint[i].bEnable - && sBreakpoint[i].dwAddr >= dwAddr && sBreakpoint[i].dwAddr < dwAddr + dwRange - && (sBreakpoint[i].nType & nType) != 0) - return TRUE; - } - return FALSE; -} - -// -// notify debugger that emulation stopped -// -VOID NotifyDebugger(INT nType) // update registers -{ - nRplBreak = nType; // save breakpoint type - FlushTrace(); // flush trace buffer - _ASSERT(hDlgDebug); // debug dialog box open - PostMessage(hDlgDebug,WM_UPDATE,0,0); - return; -} - -// -// disable debugger -// -VOID DisableDebugger(VOID) -{ - if (hDlgDebug) // debugger running - DestroyWindow(hDlgDebug); // then close debugger to renter emulation - return; -} - - -//################ -//# -//# Debugger Message loop -//# -//################ - -// -// ID_TOOL_DEBUG -// -static __inline HWND CreateToolbar(HWND hWnd) -{ - HRSRC hRes; - HGLOBAL hGlobal; - CToolBarData *pData; - TBBUTTON *ptbb; - INT i,j; - - HWND hWndToolbar = NULL; // toolbar window - - InitCommonControls(); // ensure that common control DLL is loaded - - if ((hRes = FindResource(hApp,MAKEINTRESOURCE(IDR_DEBUG_TOOLBAR),RT_TOOLBAR)) == NULL) - goto quit; - - if ((hGlobal = LoadResource(hApp,hRes)) == NULL) - goto quit; - - if ((pData = (CToolBarData*) LockResource(hGlobal)) == NULL) - goto unlock; - - _ASSERT(pData->wVersion == 1); // toolbar resource version - - // alloc memory for TBBUTTON stucture - if (!(ptbb = (TBBUTTON *) malloc(pData->wItemCount*sizeof(TBBUTTON)))) - goto unlock; - - // fill TBBUTTON stucture with resource data - for (i = j = 0; i < pData->wItemCount; ++i) - { - if (pData->aItems[i]) - { - ptbb[i].iBitmap = j++; - ptbb[i].fsStyle = TBSTYLE_BUTTON; - } - else - { - ptbb[i].iBitmap = 5; // separator width - ptbb[i].fsStyle = TBSTYLE_SEP; - } - ptbb[i].idCommand = pData->aItems[i]; - ptbb[i].fsState = TBSTATE_ENABLED; - ptbb[i].dwData = 0; - ptbb[i].iString = j; - } - - hWndToolbar = CreateToolbarEx(hWnd,WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS, - IDR_DEBUG_TOOLBAR,j,hApp,IDR_DEBUG_TOOLBAR,ptbb,pData->wItemCount, - pData->wWidth,pData->wHeight,pData->wWidth,pData->wHeight, - sizeof(TBBUTTON)); - - free(ptbb); - -unlock: - FreeResource(hGlobal); -quit: - return hWndToolbar; -} - -static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - static HMENU hMenuMainCode,hMenuMainMem,hMenuMainStack; - - WINDOWPLACEMENT wndpl; - TEXTMETRIC tm; - HDC hDC; - HFONT hFont; - HMENU hSysMenu; - HMENU hDbgMenu; - INT i; - - switch (message) - { - case WM_INITDIALOG: - SetWindowLocation(hDlg,nDbgPosX,nDbgPosY); - if (bAlwaysOnTop) SetWindowPos(hDlg,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); - SendMessage(hDlg,WM_SETICON,ICON_BIG,(LPARAM) LoadIcon(hApp,MAKEINTRESOURCE(IDI_EMU48))); - - bDbgTrace = FALSE; // disable file trace - - // load file trace settings - ReadSettingsString(_T("Debugger"),_T("TraceFile"),szTraceFilename,szTraceFilename,ARRAYSIZEOF(szTraceFilename)); - uTraceMode = ReadSettingsInt(_T("Debugger"),_T("TraceFileMode"),uTraceMode); - bTraceReg = ReadSettingsInt(_T("Debugger"),_T("TraceRegister"),bTraceReg); - bTraceMmu = ReadSettingsInt(_T("Debugger"),_T("TraceMMU"),bTraceMmu); - bTraceOpc = ReadSettingsInt(_T("Debugger"),_T("TraceOpcode"),bTraceOpc); - - // add Settings item to sysmenu - _ASSERT((IDM_DEBUG_SETTINGS & 0xFFF0) == IDM_DEBUG_SETTINGS); - _ASSERT(IDM_DEBUG_SETTINGS < 0xF000); - if ((hSysMenu = GetSystemMenu(hDlg,FALSE)) != NULL) - { - VERIFY(AppendMenu(hSysMenu,MF_SEPARATOR,0,NULL)); - VERIFY(AppendMenu(hSysMenu,MF_STRING,IDM_DEBUG_SETTINGS,_T("Debugger Settings..."))); - } - - hDbgMenu = GetMenu(hDlg); // menu of debugger dialog - hWndToolbar = CreateToolbar(hDlg); // add toolbar - - CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_NOP3, bDbgNOP3 ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_DOCODE,bDbgCode ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_RPL, bDbgRPL ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hDbgMenu,ID_INTR_STEPOVERINT, bDbgSkipInt ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hDbgMenu,ID_TRACE_ENABLE, bDbgTrace ? MF_CHECKED : MF_UNCHECKED); - - EnableMenuItem(hDbgMenu,ID_TRACE_SETTINGS,bDbgTrace ? MF_GRAYED : MF_ENABLED); - - hDlgDebug = hDlg; // handle for debugger dialog - hEventDebug = CreateEvent(NULL,FALSE,FALSE,NULL); - if (hEventDebug == NULL) - { - AbortMessage(_T("Event creation failed !")); - return TRUE; - } - hMenuMainCode = LoadMenu(hApp,MAKEINTRESOURCE(IDR_DEBUG_CODE)); - _ASSERT(hMenuMainCode); - hMenuCode = GetSubMenu(hMenuMainCode, 0); - _ASSERT(hMenuCode); - hMenuMainMem = LoadMenu(hApp,MAKEINTRESOURCE(IDR_DEBUG_MEM)); - _ASSERT(hMenuMainMem); - hMenuMem = GetSubMenu(hMenuMainMem, 0); - _ASSERT(hMenuMem); - hMenuMainStack = LoadMenu(hApp,MAKEINTRESOURCE(IDR_DEBUG_STACK)); - _ASSERT(hMenuMainStack); - hMenuStack = GetSubMenu(hMenuMainStack, 0); - _ASSERT(hMenuStack); - - // bold font for symbol labels in code window - hDC = GetDC(hDlg); - VERIFY(hFontBold = CreateFont(-MulDiv(8,GetDeviceCaps(hDC,LOGPIXELSY),72),0,0,0,FW_BOLD,0,0,0,ANSI_CHARSET, - OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Arial"))); - ReleaseDC(hDlg,hDC); - - // font settings - SendDlgItemMessage(hDlg,IDC_STATIC_CODE, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_STATIC_REGISTERS,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_STATIC_MEMORY, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_STATIC_STACK, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_STATIC_MMU, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_STATIC_MISC, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - - // init last instruction circular buffer - pdwInstrArray = (DWORD *) malloc(wInstrSize*sizeof(*pdwInstrArray)); - wInstrWp = wInstrRp = 0; // write/read pointer - - // init "Follow" menu entry in debugger "Memory" context menu - CheckMenuItem(hMenuMem,uIDFol,MF_CHECKED); - - LoadSymbTable(); // load external rpl symbol table - - InitMemMap(hDlg); // init memory mapping table - InitBsArea(hDlg); // init bank switcher list box - DisableMenuKeys(hDlg); // set debug menu keys into run state - - fnOutTrace = OutTrace; // function for file trace - RplReadNibble = GetMemNib; // get nibble function for RPL object viewer - - dwDbgStopPC = -1; // no stop address for goto cursor - dwDbgRplPC = -1; // no stop address for RPL breakpoint - - // init reference cpu cycle counter for 64 bit debug cycle counter - dwDbgRefCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF); - - nDbgState = DBG_STEPINTO; // state "step into" - if (Chipset.Shutdn) // cpu thread stopped - SetEvent(hEventShutdn); // goto debug session - - OldChipset = Chipset; // save chipset values - return TRUE; - - case WM_DESTROY: - // SetHP48Time(); // update time & date - nDbgState = DBG_OFF; // debugger inactive - StopTrace(); // finish trace - bInterrupt = TRUE; // exit opcode loop - SetEvent(hEventDebug); - if (pdwInstrArray) // free last instruction circular buffer - { - EnterCriticalSection(&csDbgLock); - { - free(pdwInstrArray); - pdwInstrArray = NULL; - } - LeaveCriticalSection(&csDbgLock); - } - CloseHandle(hEventDebug); - wndpl.length = sizeof(wndpl); // save debugger window position - GetWindowPlacement(hDlg, &wndpl); - nDbgPosX = wndpl.rcNormalPosition.left; - nDbgPosY = wndpl.rcNormalPosition.top; - - // save file trace settings - WriteSettingsString(_T("Debugger"),_T("TraceFile"),szTraceFilename); - WriteSettingsInt(_T("Debugger"),_T("TraceFileMode"),uTraceMode); - WriteSettingsInt(_T("Debugger"),_T("TraceRegister"),bTraceReg); - WriteSettingsInt(_T("Debugger"),_T("TraceMMU"),bTraceMmu); - WriteSettingsInt(_T("Debugger"),_T("TraceOpcode"),bTraceOpc); - - RplDeleteTable(); // delete rpl symbol table - DeleteObject(hFontBold); // delete bold font - DestroyMenu(hMenuMainCode); - DestroyMenu(hMenuMainMem); - DestroyMenu(hMenuMainStack); - hDlgDebug = NULL; // debugger windows closed - break; - - case WM_CLOSE: - DestroyWindow(hDlg); - break; - - case WM_UPDATE: - OnUpdate(hDlg); - return TRUE; - - case WM_SYSCOMMAND: - if ((wParam & 0xFFF0) == IDM_DEBUG_SETTINGS) - { - return OnSettings(hDlg); - } - break; - - case WM_COMMAND: - switch (HIWORD(wParam)) - { - case LBN_DBLCLK: - return OnDblClick((HWND) lParam, LOWORD(wParam)); - - case LBN_SETFOCUS: - i = (INT) SendMessage((HWND) lParam,LB_GETCARETINDEX,0,0); - SendMessage((HWND) lParam,LB_SETCURSEL,i,0); - return TRUE; - - case LBN_KILLFOCUS: - SendMessage((HWND) lParam,LB_SETCURSEL,-1,0); - return TRUE; - } - - switch (LOWORD(wParam)) - { - case ID_BREAKPOINTS_SETBREAK: return OnKeyF2(hDlg); - case ID_DEBUG_RUN: return OnKeyF5(hDlg); - case ID_DEBUG_RUNCURSOR: return OnKeyF6(hDlg); - case ID_DEBUG_STEP: return OnKeyF7(hDlg); - case ID_DEBUG_STEPOVER: return OnKeyF8(hDlg); - case ID_DEBUG_STEPOUT: return OnKeyF9(hDlg); - case ID_DEBUG_BREAK: return OnKeyF11(hDlg); - case ID_DEBUG_CODE_GOADR: return OnCodeGoAdr(hDlg); - case ID_DEBUG_CODE_GOPC: return OnCodeGoPC(hDlg); - case ID_DEBUG_CODE_SETPCTOSELECT: return OnCodeSetPcToSelection(hDlg); - case ID_DEBUG_CODE_PREVPCO: return OnCodeFindPCO(hDlg,dwAdrLine[0],-1); - case ID_DEBUG_CODE_NEXTPCO: return OnCodeFindPCO(hDlg,dwAdrLine[0],1); - case ID_BREAKPOINTS_CODEEDIT: return OnEditBreakpoint(hDlg); - case ID_BREAKPOINTS_CLEARALL: return OnClearAll(hDlg); - case ID_BREAKPOINTS_NOP3: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgNOP3); - case ID_BREAKPOINTS_DOCODE: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgCode); - case ID_BREAKPOINTS_RPL: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgRPL); - case ID_TRACE_SETTINGS: return OnTraceSettings(hDlg); - case ID_TRACE_ENABLE: return OnTraceEnable(hDlg); - case ID_INFO_LASTINSTRUCTIONS: return OnInfoIntr(hDlg); - case ID_INFO_PROFILE: return OnProfile(hDlg); - case ID_INFO_WRITEONLYREG: return OnInfoWoRegister(hDlg); - case ID_INTR_STEPOVERINT: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgSkipInt); - case ID_DEBUG_MEM_GOADR: return OnMemGoAdr(hDlg); - case ID_DEBUG_MEM_GOPC: return OnMemGoDx(hDlg,Chipset.pc); - case ID_DEBUG_MEM_GOD0: return OnMemGoDx(hDlg,Chipset.d0); - case ID_DEBUG_MEM_GOD1: return OnMemGoDx(hDlg,Chipset.d1); - case ID_DEBUG_MEM_GOSTACK: return OnMemGoDx(hDlg,Chipset.rstk[(Chipset.rstkp-1)&7]); - case ID_DEBUG_MEM_FNONE: - case ID_DEBUG_MEM_FADDR: - case ID_DEBUG_MEM_FPC: - case ID_DEBUG_MEM_FD0: - case ID_DEBUG_MEM_FD1: return OnMemFollow(hDlg,LOWORD(wParam)); - case ID_DEBUG_MEM_FIND: return OnMemFind(hDlg); - case ID_DEBUG_MEM_MAP: - case ID_DEBUG_MEM_NCE1: - case ID_DEBUG_MEM_NCE2: - case ID_DEBUG_MEM_CE1: - case ID_DEBUG_MEM_CE2: - case ID_DEBUG_MEM_NCE3: return OnMemMapping(hDlg,LOWORD(wParam)); - case ID_DEBUG_MEM_LOAD: return OnMemLoadData(hDlg); - case ID_DEBUG_MEM_SAVE: return OnMemSaveData(hDlg); - case ID_DEBUG_MEM_RPLVIEW: return OnRplObjView(hDlg); - case ID_DEBUG_STACK_PUSH: return OnStackPush(hDlg); - case ID_DEBUG_STACK_POP: return OnStackPop(hDlg); - case ID_DEBUG_STACK_MODIFY: return OnStackModify(hDlg); - case ID_DEBUG_CANCEL: DestroyWindow(hDlg); return TRUE; - } - break; - - case WM_VKEYTOITEM: - switch (LOWORD(wParam)) // always valid - { - case VK_F2: return OnKeyF2(hDlg); // toggle breakpoint - case VK_F5: return OnKeyF5(hDlg); // key run - case VK_F6: return OnKeyF6(hDlg); // key step cursor - case VK_F7: return OnKeyF7(hDlg); // key step into - case VK_F8: return OnKeyF8(hDlg); // key step over - case VK_F9: return OnKeyF9(hDlg); // key step out - case VK_F11: return OnKeyF11(hDlg); // key break - } - - switch(GetDlgCtrlID((HWND) lParam)) // calling window - { - // handle code window - case IDC_DEBUG_CODE: - return OnKeyCodeWnd(hDlg, wParam); - - // handle memory window - case IDC_DEBUG_MEM_COL0: - case IDC_DEBUG_MEM_COL1: - case IDC_DEBUG_MEM_COL2: - case IDC_DEBUG_MEM_COL3: - case IDC_DEBUG_MEM_COL4: - case IDC_DEBUG_MEM_COL5: - case IDC_DEBUG_MEM_COL6: - case IDC_DEBUG_MEM_COL7: - switch (LOWORD(wParam)) - { - case _T('G'): return OnMemGoAdr(GetParent((HWND) lParam)); - case _T('F'): return OnMemFind(GetParent((HWND) lParam)); - case VK_RIGHT: - case VK_LEFT: return OnKeyRightLeft((HWND) lParam, wParam); - case VK_NEXT: - case VK_PRIOR: - case VK_DOWN: - case VK_UP: return OnKeyUpDown((HWND) lParam, wParam); - case VK_ADD: - case VK_SUBTRACT: return OnKeyPlusMinus((HWND) lParam, wParam); - } - break; - } - return -1; // default action - - case WM_LBUTTONUP: - return OnLButtonUp(hDlg, lParam); - - case WM_CONTEXTMENU: - OnContextMenu(hDlg, lParam, wParam); - break; - - case WM_SETCURSOR: - return OnSetCursor(hDlg); - - case WM_CTLCOLORSTATIC: // register color highlighting - // highlight text? - if (OnCtlColorStatic((HWND) lParam)) - { - SetTextColor((HDC) wParam, COLOR_RED); - SetBkColor((HDC) wParam, GetSysColor(COLOR_BTNFACE)); - return (INT_PTR) GetStockObject(NULL_BRUSH); // transparent brush - } - break; - - case WM_NOTIFY: - // tooltip for toolbar - if (((LPNMHDR) lParam)->code == TTN_GETDISPINFO) - { - ((LPTOOLTIPTEXT) lParam)->hinst = hApp; - ((LPTOOLTIPTEXT) lParam)->lpszText = MAKEINTRESOURCE(((LPTOOLTIPTEXT) lParam)->hdr.idFrom); - break; - } - break; - - case WM_DRAWITEM: - if (wParam == IDC_DEBUG_CODE) return OnDrawCodeWnd((LPDRAWITEMSTRUCT) lParam); - break; - - case WM_MEASUREITEM: - hDC = GetDC(hDlg); - - // GetTextMetrics from "Courier New 8" font - hFont = CreateFont(-MulDiv(8,GetDeviceCaps(hDC, LOGPIXELSY),72),0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, - OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Courier New")); - - hFont = (HFONT) SelectObject(hDC,hFont); - GetTextMetrics(hDC,&tm); - hFont = (HFONT) SelectObject(hDC,hFont); - DeleteObject(hFont); - - ((LPMEASUREITEMSTRUCT) lParam)->itemHeight = tm.tmHeight; - lCharWidth = tm.tmAveCharWidth; - - ReleaseDC(hDlg,hDC); - return TRUE; - } - return FALSE; -} - -LRESULT OnToolDebug(VOID) // debugger dialogbox call -{ - if ((hDlgDebug = CreateDialog(hApp,MAKEINTRESOURCE(IDD_DEBUG),NULL, - (DLGPROC)Debugger)) == NULL) - AbortMessage(_T("Debugger Dialog Box Creation Error !")); - return 0; -} - - -//################ -//# -//# Find dialog box -//# -//################ - -static __inline BOOL OnFindOK(HWND hDlg,BOOL bASCII,DWORD *pdwAddrLast,INT nSearchDir) -{ - HWND hWnd; - BYTE *lpbySearch; - INT i,j; - DWORD dwCnt,dwAddr,dwMapDataMask; - BOOL bMatch; - - // searching upwards / downwards - _ASSERT(nSearchDir == 1 || nSearchDir == -1); - - hWnd = GetDlgItem(hDlg,IDC_FIND_DATA); - - dwMapDataMask = GetMemDataMask(); // size mask of data mapping - - i = GetWindowTextLength(hWnd) + 1; // text length incl. EOS - j = bASCII ? 2 : sizeof(*(LPTSTR)0); // buffer width - - // allocate search buffer - if ((lpbySearch = (LPBYTE) malloc(i * j)) != NULL) - { - // get search text and real length - i = GetWindowText(hWnd,(LPTSTR) lpbySearch,i); - - // add string to combo box - if (SendMessage(hWnd,CB_FINDSTRINGEXACT,0,(LPARAM) lpbySearch) == CB_ERR) - SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) lpbySearch); - - #if defined _UNICODE - { - // Unicode to byte translation - LPTSTR szTmp = DuplicateString((LPCTSTR) lpbySearch); - if (szTmp != NULL) - { - WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, - szTmp, -1, - (LPSTR) lpbySearch, i+1, NULL, NULL); - free(szTmp); - } - } - #endif - - // convert input format to nibble based format - if (bASCII) // ASCII input - { - // convert ASCII to number - for (j = i - 1; j >= 0; --j) - { - // order LSB, MSB - lpbySearch[j * 2 + 1] = lpbySearch[j] >> 4; - lpbySearch[j * 2] = lpbySearch[j] & 0xF; - } - i *= 2; // no. of nibbles - } - else // hex number input - { - // convert HEX to number - for (i = 0, j = 0; lpbySearch[j] != 0; ++j) - { - if (lpbySearch[j] == ' ') // skip space - continue; - - if (isxdigit(lpbySearch[j])) - { - lpbySearch[i] = toupper(lpbySearch[j]) - '0'; - if (lpbySearch[i] > 9) lpbySearch[i] -= 'A' - '9' - 1; - } - else - { - i = 0; // wrong format, no match - break; - } - ++i; // inc, no. of nibbles - } - } - - bMatch = FALSE; // no match - dwAddr = dwAdrMem; // calculate search start address - if (*pdwAddrLast == dwAddr) - dwAddr += nSearchDir; - - // scan mapping/module until match - for (dwCnt = 0; i && !bMatch && dwCnt <= dwMapDataMask; ++dwCnt) - { - BYTE byC; - - // i = no. of nibbles that have to match - for (bMatch = TRUE, j = 0;bMatch && j < i; ++j) - { - GetMemPeek(&byC,(dwAddr + j) & dwMapDataMask,1); - bMatch = (byC == lpbySearch[j]); - } - dwAddr += nSearchDir; - } - free(lpbySearch); - - // check match result - if (bMatch) - { - // matching address - dwAddr = (dwAddr - nSearchDir) & dwMapDataMask; - - // update memory window - OnMemGoDx(GetParent(hDlg),dwAddr); - - // update rpl obj view dialog - UpdateRplObjViewWnd(hDlgRplObjView,dwAddr); - - *pdwAddrLast = dwAddr; // last matching address - } - else - { - MessageBox(hDlg,_T("Search string not found!"),_T("Find"), - MB_APPLMODAL|MB_OK|MB_ICONEXCLAMATION|MB_SETFOREGROUND); - } - } - return TRUE; -} - -// -// enter find dialog -// -static INT_PTR CALLBACK Find(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - static DWORD dwAddrEntry; - static BOOL bASCII = FALSE; - - switch (message) - { - case WM_INITDIALOG: - CheckDlgButton(hDlg,IDC_FIND_ASCII,bASCII); - dwAddrEntry = -1; - return TRUE; - - case WM_DESTROY: - hDlgFind = NULL; - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDC_FIND_ASCII: bASCII = !bASCII; return TRUE; - case IDC_FIND_PREV: return OnFindOK(hDlg,bASCII,&dwAddrEntry,-1); - case IDC_FIND_NEXT: return OnFindOK(hDlg,bASCII,&dwAddrEntry,1); - case IDCANCEL: DestroyWindow(hDlg); return TRUE; - } - break; - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -static BOOL OnMemFind(HWND hDlg) -{ - if (hDlgFind == NULL) // no find dialog, create it - { - if ((hDlgFind = CreateDialog(hApp,MAKEINTRESOURCE(IDD_FIND),hDlg, - (DLGPROC)Find)) == NULL) - AbortMessage(_T("Find Dialog Box Creation Error !")); - } - else - { - SetFocus(hDlgFind); // set focus on find dialog - } - return -1; // call windows default handler -} - - -//################ -//# -//# Profile dialog box -//# -//################ - -// -// update profiler dialog content -// -static VOID UpdateProfileWnd(HWND hDlg) -{ - #define CPU_FREQ 524288 // base CPU frequency - #define SX_RATE 0x0E - #define GX_RATE 0x1B - - LPCTSTR pcUnit[] = { _T("s"),_T("ms"),_T("us"),_T("ns") }; - - QWORD lVar; - TCHAR szBuffer[64]; - UINT i; - DWORD dwFreq, dwEndFreq; - - if (hDlg == NULL) return; // dialog not open - - // 64 bit cpu cycle counter - lVar = *(QWORD *)&Chipset.cycles - *(QWORD *)&OldChipset.cycles; - - // cycle counts - _sntprintf(szBuffer,ARRAYSIZEOF(szBuffer),_T("%I64u"),lVar); - SetDlgItemText(hDlg,IDC_PROFILE_LASTCYCLES,szBuffer); - - // CPU frequency - dwFreq = (cCurrentRomType=='S') - ? ((SX_RATE + 1) * CPU_FREQ / 4) - : ((GX_RATE + 1) * CPU_FREQ / 4); - dwEndFreq = ((999 * 2 - 1) * dwFreq) / (2 * 1000); - - // search for ENG unit - for (i = 0; i < ARRAYSIZEOF(pcUnit) - 1 && lVar <= dwEndFreq; ++i) - { - lVar *= 1000; // next ENG unit - } - - // calculate rounded time - lVar = (2 * lVar + dwFreq) / (2 * dwFreq); - - _ASSERT(i < ARRAYSIZEOF(pcUnit)); - _sntprintf(szBuffer,ARRAYSIZEOF(szBuffer),_T("%I64u %s"),lVar,pcUnit[i]); - SetDlgItemText(hDlg,IDC_PROFILE_LASTTIME,szBuffer); - return; - #undef SX_CLK - #undef GX_CLK - #undef CPU_FREQ -} - -// -// enter profile dialog -// -static INT_PTR CALLBACK Profile(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_INITDIALOG: - UpdateProfileWnd(hDlg); - return TRUE; - - case WM_DESTROY: - hDlgProfile = NULL; - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDCANCEL: DestroyWindow(hDlg); return TRUE; - } - break; - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -static BOOL OnProfile(HWND hDlg) -{ - if (hDlgProfile == NULL) // no profile dialog, create it - { - if ((hDlgProfile = CreateDialog(hApp,MAKEINTRESOURCE(IDD_PROFILE),hDlg, - (DLGPROC)Profile)) == NULL) - AbortMessage(_T("Profile Dialog Box Creation Error !")); - } - else - { - SetFocus(hDlgProfile); // set focus on profile dialog - } - return -1; // call windows default handler -} - - -//################ -//# -//# RPL object viewer dialog box -//# -//################ - -// -// update rpl obj view dialog content -// -static VOID UpdateRplObjViewWnd(HWND hDlg, DWORD dwAddr) -{ - LPTSTR szObjList; - - if (hDlg == NULL) return; // dialog not open - - // show entry point name only in mapped mode - bRplViewName = (GetMemMapType() == MEM_MMU); - - // create view string - szObjList = RplCreateObjView(dwAddr,GetMemDataSize(),TRUE); - SetDlgItemText(hDlg,IDC_RPLVIEW_DATA,szObjList); - free(szObjList); - return; -} - -// -// enter RPL object viewer dialog -// -static INT_PTR CALLBACK RplObjView(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_INITDIALOG: - switch (cCurrentRomType) - { - case 'S': // HP48SX - dwRplPlatform = RPL_P3; // Charlemagne platform - break; - case '6': // HP38G (64K RAM version) - case 'A': // HP38G - case 'G': // HP48GX - dwRplPlatform = RPL_P4; // Alcuin platform - break; - case 'E': // HP39G/40G - case 'X': // HP49G - dwRplPlatform = RPL_P5; // V'ger platform - break; - default: - _ASSERT(FALSE); - } - - bRplViewAddr = TRUE; // show address - bRplViewBin = TRUE; // show binary data - return TRUE; - - case WM_DESTROY: - hDlgRplObjView = NULL; - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDCANCEL: DestroyWindow(hDlg); return TRUE; - } - break; - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -static BOOL OnRplObjView(HWND hDlg) -{ - // get cursor address of memory view - DWORD dwAddr = GetMemCurAddr(hDlg); - - if (hDlgRplObjView == NULL) // no rpl obj view dialog, create it - { - if ((hDlgRplObjView = CreateDialog(hApp,MAKEINTRESOURCE(IDD_RPLVIEW),hDlg, - (DLGPROC)RplObjView)) == NULL) - AbortMessage(_T("RPL Object View Dialog Box Creation Error !")); - } - - UpdateRplObjViewWnd(hDlgRplObjView,dwAddr); - return -1; // call windows default handler -} - - -//################ -//# -//# Settings dialog box -//# -//################ - -// -// copy edit box content to current combox box selection -// -static VOID CopyEditToCombo(HWND hDlg,HWND hWndComboBox) -{ - TCHAR szSymbFilename[MAX_PATH]; - INT i; - - // get current selection - if ((i = (INT) SendMessage(hWndComboBox,CB_GETCURSEL,0,0)) != CB_ERR) - { - // delete associated name - free((LPVOID) SendMessage(hWndComboBox,CB_GETITEMDATA,i,0)); - - // append actual name - GetDlgItemText(hDlg,IDC_DEBUG_SET_FILE,szSymbFilename,ARRAYSIZEOF(szSymbFilename)); - SendMessage(hWndComboBox,CB_SETITEMDATA,i,(LPARAM) DuplicateString(szSymbFilename)); - } - return; -} - -// -// copy edit box content to current combox box selection -// -static VOID CopyComboToEdit(HWND hDlg,HWND hWndComboBox) -{ - HWND hWnd; - INT i; - - // get current selection - if ((i = (INT) SendMessage(hWndComboBox,CB_GETCURSEL,0,0)) != CB_ERR) - { - // update file edit box - hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_FILE); - SetWindowText(hWnd,(LPTSTR) SendMessage(hWndComboBox,CB_GETITEMDATA,i,0)); - SendMessage(hWnd,EM_SETSEL,0,-1); - } - return; -} - -// -// settings browse dialog -// -static BOOL OnBrowseSettings(HWND hDlg, HWND hWndFilename) -{ - TCHAR szBuffer[MAX_PATH]; - OPENFILENAME ofn; - - ZeroMemory(&ofn, sizeof(OPENFILENAME)); - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = hDlg; - ofn.lpstrFilter = - _T("HP-Tools Linker File (*.O)\0*.O\0") - _T("All Files (*.*)\0*.*\0"); - ofn.lpstrDefExt = _T("O"); - ofn.nFilterIndex = 1; - ofn.lpstrFile = szBuffer; - ofn.lpstrFile[0] = 0; - ofn.nMaxFile = ARRAYSIZEOF(szBuffer); - ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST; - if (GetOpenFileName(&ofn)) - { - SetWindowText(hWndFilename,szBuffer); - SendMessage(hWndFilename,EM_SETSEL,0,-1); - } - return 0; -} - -// -// enter settings dialog -// -static INT_PTR CALLBACK Settings(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - HWND hWnd; - TCHAR szSymbFilename[MAX_PATH]; - TCHAR szItemname[16]; - INT i,nMax; - - switch (message) - { - case WM_INITDIALOG: - // set disassembler mode - CheckDlgButton(hDlg,(disassembler_mode == HP_MNEMONICS) ? IDC_DISASM_HP : IDC_DISASM_CLASS,BST_CHECKED); - // set symbolic enable check button - CheckDlgButton(hDlg,IDC_DEBUG_SET_SYMB,disassembler_symb); - // fill model combo box and corresponding file edit box - { - LPCTSTR lpszModels; - TCHAR cModel[] = _T(" "); - - // fill model combo box - hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_MODEL); - for (lpszModels = _T(MODELS); *lpszModels != 0; ++lpszModels) - { - cModel[0] = *lpszModels; // string with model character - i = (INT) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) cModel); - - // get filename - wsprintf(szItemname,_T("Symb%c"),cModel[0]); - ReadSettingsString(_T("Disassembler"),szItemname,_T(""),szSymbFilename,ARRAYSIZEOF(szSymbFilename)); - - // append filename to model - SendMessage(hWnd,CB_SETITEMDATA,i,(LPARAM) DuplicateString(szSymbFilename)); - } - - // select for actual model - cModel[0] = (TCHAR) cCurrentRomType; - if ((i = (INT) SendMessage(hWnd,CB_SELECTSTRING,0,(LPARAM) cModel)) != CB_ERR) - { - LPTSTR lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0); - - // fill file edit box - hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_FILE); - SetWindowText(hWnd,lpszFilename); - SendMessage(hWnd,EM_SETSEL,0,-1); - } - } - return TRUE; - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDC_DEBUG_SET_MODEL: - // combo box changing item - if (HIWORD(wParam) == CBN_SETFOCUS) - { - // update associated name with file edit box - CopyEditToCombo(hDlg,(HWND) lParam); - } - // new combo box item selected - if (HIWORD(wParam) == CBN_SELENDOK) - { - // update file edit box with associated name - CopyComboToEdit(hDlg,(HWND) lParam); - } - break; - case IDC_DEBUG_SET_BROWSE: - return OnBrowseSettings(hDlg,GetDlgItem(hDlg,IDC_DEBUG_SET_FILE)); - case IDOK: - // set disassembler mode - disassembler_mode = IsDlgButtonChecked(hDlg,IDC_DISASM_HP) ? HP_MNEMONICS : CLASS_MNEMONICS; - // set symbolic enable check button - disassembler_symb = IsDlgButtonChecked(hDlg,IDC_DEBUG_SET_SYMB); - // update associated name with file edit box - hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_MODEL); - CopyEditToCombo(hDlg,hWnd); - // write all symbol filenames to registry - nMax = (INT) SendMessage(hWnd,CB_GETCOUNT,0,0); - for (i = 0; i < nMax; ++i) - { - LPTSTR lpszFilename; - - SendMessage(hWnd,CB_GETLBTEXT,i,(LPARAM) szSymbFilename); - wsprintf(szItemname,_T("Symb%c"),szSymbFilename[0]); - lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0); - if (*lpszFilename == 0) // empty - { - DelSettingsKey(_T("Disassembler"),szItemname); - } - else - { - WriteSettingsString(_T("Disassembler"),szItemname,lpszFilename); - } - } - RplDeleteTable(); // delete rpl symbol table - LoadSymbTable(); // reload external rpl symbol table - // redraw debugger code view - ViewCodeWnd(GetDlgItem(GetParent(hDlg),IDC_DEBUG_CODE),dwAdrLine[0]); - // no break - case IDCANCEL: - // free combo box items - hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_MODEL); - nMax = (INT) SendMessage(hWnd,CB_GETCOUNT,0,0); - for (i = 0; i < nMax; ++i) - { - LPTSTR lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0); - if (lpszFilename != NULL) - { - free(lpszFilename); - } - } - EndDialog(hDlg,LOWORD(wParam)); - return TRUE; - } - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -static BOOL OnSettings(HWND hDlg) -{ - if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_SETTINGS), hDlg, (DLGPROC)Settings) == -1) - AbortMessage(_T("Settings Dialog Box Creation Error !")); - return 0; -} - - -//################ -//# -//# New Value dialog box -//# -//################ - -// -// enter new value dialog -// -static INT_PTR CALLBACK NewValue(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - static LPTSTR lpszBuffer; // handle of buffer - static int nBufferlen; // length of buffer - - HWND hWnd; - TCHAR szBuffer[64]; - LONG i; - - switch (message) - { - case WM_INITDIALOG: - lpszBuffer = (LPTSTR) lParam; - // length with zero string terminator - nBufferlen = lstrlen(lpszBuffer)+1; - _ASSERT(ARRAYSIZEOF(szBuffer) >= nBufferlen); - SetDlgItemText(hDlg,IDC_NEWVALUE,lpszBuffer); - return TRUE; - case WM_COMMAND: - wParam = LOWORD(wParam); - switch(wParam) - { - case IDOK: - hWnd = GetDlgItem(hDlg,IDC_NEWVALUE); - GetWindowText(hWnd,szBuffer,nBufferlen); - // test if valid hex address - for (i = 0; i < (LONG) lstrlen(szBuffer); ++i) - { - if (_istxdigit(szBuffer[i]) == 0) - { - SendMessage(hWnd,EM_SETSEL,0,-1); - SetFocus(hWnd); // focus to edit control - return FALSE; - } - } - lstrcpy(lpszBuffer,szBuffer); // copy valid value - // no break - case IDCANCEL: - EndDialog(hDlg,wParam); - return TRUE; - } - } - return FALSE; -} - -static INT_PTR OnNewValue(LPTSTR lpszValue) -{ - INT_PTR nResult; - - if ((nResult = DialogBoxParam(hApp, - MAKEINTRESOURCE(IDD_NEWVALUE), - hDlgDebug, - (DLGPROC)NewValue, - (LPARAM)lpszValue) - ) == -1) - AbortMessage(_T("Input Dialog Box Creation Error !")); - return nResult; -} - - -//################ -//# -//# Goto Address dialog box -//# -//################ - -// -// enter goto address dialog -// -static INT_PTR CALLBACK EnterAddr(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_INITDIALOG: - SetWindowLongPtr(hDlg,GWLP_USERDATA,(LONG_PTR) lParam); - return TRUE; - case WM_COMMAND: - wParam = LOWORD(wParam); - switch(wParam) - { - case IDOK: - if (!GetAddr(hDlg, - IDC_ENTERADR, - (DWORD *) GetWindowLongPtr(hDlg,GWLP_USERDATA), - 0xFFFFFFFF, - disassembler_symb)) - return FALSE; - // no break - case IDCANCEL: - EndDialog(hDlg,wParam); - return TRUE; - } - } - return FALSE; -} - -static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue) -{ - if (DialogBoxParam(hApp, MAKEINTRESOURCE(IDD_ENTERADR), hDlg, (DLGPROC)EnterAddr, (LPARAM)dwValue) == -1) - AbortMessage(_T("Address Dialog Box Creation Error !")); -} - - -//################ -//# -//# Breakpoint dialog box -//# -//################ - -// -// enter breakpoint dialog -// -static INT_PTR CALLBACK EnterBreakpoint(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - static BP_T *sBp; - - switch (message) - { - case WM_INITDIALOG: - sBp = (BP_T *) lParam; - sBp->bEnable = TRUE; - sBp->nType = BP_EXEC; - SendDlgItemMessage(hDlg,IDC_BPCODE,BM_SETCHECK,1,0); - return TRUE; - case WM_COMMAND: - wParam = LOWORD(wParam); - switch(wParam) - { - case IDC_BPCODE: sBp->nType = BP_EXEC; return TRUE; - case IDC_BPRPL: sBp->nType = BP_RPL; return TRUE; - case IDC_BPACCESS: sBp->nType = BP_ACCESS; return TRUE; - case IDC_BPREAD: sBp->nType = BP_READ; return TRUE; - case IDC_BPWRITE: sBp->nType = BP_WRITE; return TRUE; - case IDOK: - if (!GetAddr(hDlg,IDC_ENTERADR,&sBp->dwAddr,0xFFFFF,disassembler_symb)) - return FALSE; - // no break - case IDCANCEL: - EndDialog(hDlg,wParam); - return TRUE; - } - } - return FALSE; -} - -static VOID OnEnterBreakpoint(HWND hDlg, BP_T *sValue) -{ - if (DialogBoxParam(hApp, MAKEINTRESOURCE(IDD_ENTERBREAK), hDlg, (DLGPROC)EnterBreakpoint, (LPARAM)sValue) == -1) - AbortMessage(_T("Breakpoint Dialog Box Creation Error !")); -} - - -//################ -//# -//# Edit breakpoint dialog box -//# -//################ - -// -// handle drawing in breakpoint window -// -static __inline BOOL OnDrawBreakWnd(LPDRAWITEMSTRUCT lpdis) -{ - TCHAR szBuf[64]; - COLORREF crBkColor,crTextColor; - HDC hdcMem; - HBITMAP hBmpOld; - - if (lpdis->itemID == -1) // no item in list box - return TRUE; - - crBkColor = GetBkColor(lpdis->hDC); // save actual color settings - crTextColor = GetTextColor(lpdis->hDC); - - if (lpdis->itemState & ODS_SELECTED) // cursor line - { - SetBkColor(lpdis->hDC,GetSysColor(COLOR_HIGHLIGHT)); - SetTextColor(lpdis->hDC,GetSysColor(COLOR_HIGHLIGHTTEXT)); - } - - // write Text - SendMessage(lpdis->hwndItem,LB_GETTEXT,lpdis->itemID,(LPARAM) szBuf); - ExtTextOut(lpdis->hDC,(int)(lpdis->rcItem.left)+17,(int)(lpdis->rcItem.top), - ETO_OPAQUE,(LPRECT)&lpdis->rcItem,szBuf,lstrlen(szBuf),NULL); - - SetBkColor(lpdis->hDC,crBkColor); // restore color settings - SetTextColor(lpdis->hDC,crTextColor); - - // draw checkbox - hdcMem = CreateCompatibleDC(lpdis->hDC); - _ASSERT(hBmpCheckBox); - hBmpOld = (HBITMAP) SelectObject(hdcMem,hBmpCheckBox); - - BitBlt(lpdis->hDC,lpdis->rcItem.left+2,lpdis->rcItem.top+2, - 11,lpdis->rcItem.bottom - lpdis->rcItem.top, - hdcMem,sBreakpoint[lpdis->itemData].bEnable ? 0 : 10,0,SRCCOPY); - - SelectObject(hdcMem,hBmpOld); - DeleteDC(hdcMem); - - if (lpdis->itemState & ODS_FOCUS) // redraw focus - DrawFocusRect(lpdis->hDC,&lpdis->rcItem); - - return TRUE; // focus handled here -} - -// -// toggle breakpoint drawing -// -static BOOL ToggleBreakpointItem(HWND hWnd, INT nItem) -{ - RECT rc; - - // get breakpoint number - INT i = (INT) SendMessage(hWnd,LB_GETITEMDATA,nItem,0); - - sBreakpoint[i].bEnable = !sBreakpoint[i].bEnable; - // update region of toggled item - SendMessage(hWnd,LB_GETITEMRECT,nItem,(LPARAM)&rc); - InvalidateRect(hWnd,&rc,TRUE); - return TRUE; -} - -// -// draw breakpoint type -// -static VOID DrawBreakpoint(HWND hWnd, INT i) -{ - TCHAR *szText,szBuffer[32]; - INT nItem; - - switch(sBreakpoint[i].nType) - { - case BP_EXEC: // code breakpoint - szText = _T("Code"); - break; - case BP_RPL: // RPL breakpoint - szText = _T("RPL"); - break; - case BP_READ: // read memory breakpoint - szText = _T("Memory Read"); - break; - case BP_WRITE: // write memory breakpoint - szText = _T("Memory Write"); - break; - case BP_ACCESS: // memory breakpoint - szText = _T("Memory Access"); - break; - default: // unknown breakpoint type - szText = _T("unknown"); - _ASSERT(0); - } - wsprintf(szBuffer,_T("%05X (%s)"),sBreakpoint[i].dwAddr,szText); - nItem = (INT) SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); - SendMessage(hWnd,LB_SETITEMDATA,nItem,i); - return; -} - -// -// enter edit breakpoint dialog -// -static INT_PTR CALLBACK EditBreakpoint(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - TEXTMETRIC tm; - - HWND hWnd; - HDC hDC; - HFONT hFont; - BP_T sBp; - INT i,nItem; - - switch (message) - { - case WM_INITDIALOG: - // font settings - SendDlgItemMessage(hDlg,IDC_STATIC_BREAKPOINT,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_BREAKEDIT_ADD, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_BREAKEDIT_DELETE, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDCANCEL, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - - hBmpCheckBox = LoadBitmap(hApp,MAKEINTRESOURCE(IDB_CHECKBOX)); - _ASSERT(hBmpCheckBox); - - hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND); - SendMessage(hWnd,WM_SETREDRAW,FALSE,0); - SendMessage(hWnd,LB_RESETCONTENT,0,0); - for (i = 0; i < wBreakpointCount; ++i) - DrawBreakpoint(hWnd,i); - SendMessage(hWnd,WM_SETREDRAW,TRUE,0); - return TRUE; - - case WM_DESTROY: - DeleteObject(hBmpCheckBox); - return TRUE; - - case WM_COMMAND: - hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND); - switch (HIWORD(wParam)) - { - case LBN_DBLCLK: - if (LOWORD(wParam) == IDC_BREAKEDIT_WND) - { - if ((nItem = (INT) SendMessage(hWnd,LB_GETCURSEL,0,0)) == LB_ERR) - return FALSE; - - return ToggleBreakpointItem(hWnd,nItem); - } - } - - switch(LOWORD(wParam)) - { - case IDC_BREAKEDIT_ADD: - sBp.dwAddr = -1; // no breakpoint given - OnEnterBreakpoint(hDlg, &sBp); - if (sBp.dwAddr != -1) - { - for (i = 0; i < wBreakpointCount; ++i) - { - if (sBreakpoint[i].dwAddr == sBp.dwAddr) - { - // tried to add used code breakpoint - if (sBreakpoint[i].bEnable && (sBreakpoint[i].nType & sBp.nType & (BP_EXEC | BP_RPL)) != 0) - return FALSE; - - // only modify memory breakpoints - if ( ( sBreakpoint[i].bEnable == FALSE - && (sBreakpoint[i].nType & sBp.nType & (BP_EXEC | BP_RPL)) != 0) - || ((sBreakpoint[i].nType & BP_ACCESS) && (sBp.nType & BP_ACCESS))) - { - // replace breakpoint type - sBreakpoint[i].bEnable = TRUE; - sBreakpoint[i].nType = sBp.nType; - - // redaw breakpoint list - SendMessage(hWnd,WM_SETREDRAW,FALSE,0); - SendMessage(hWnd,LB_RESETCONTENT,0,0); - for (i = 0; i < wBreakpointCount; ++i) - DrawBreakpoint(hWnd,i); - SendMessage(hWnd,WM_SETREDRAW,TRUE,0); - return FALSE; - } - } - } - - // check for breakpoint buffer full - if (wBreakpointCount >= MAXBREAKPOINTS) - { - AbortMessage(_T("Reached maximum number of breakpoints !")); - return FALSE; - } - - sBreakpoint[wBreakpointCount].bEnable = sBp.bEnable; - sBreakpoint[wBreakpointCount].nType = sBp.nType; - sBreakpoint[wBreakpointCount].dwAddr = sBp.dwAddr; - - DrawBreakpoint(hWnd,wBreakpointCount); - - ++wBreakpointCount; - } - return TRUE; - - case IDC_BREAKEDIT_DELETE: - // scan all breakpoints from top - for (nItem = wBreakpointCount-1; nItem >= 0; --nItem) - { - // item selected - if (SendMessage(hWnd,LB_GETSEL,nItem,0) > 0) - { - INT j; - - // get breakpoint index - i = (INT) SendMessage(hWnd,LB_GETITEMDATA,nItem,0); - SendMessage(hWnd,LB_DELETESTRING,nItem,0); - --wBreakpointCount; - - // update remaining list box references - for (j = 0; j < wBreakpointCount; ++j) - { - INT k = (INT) SendMessage(hWnd,LB_GETITEMDATA,j,0); - if (k > i) SendMessage(hWnd,LB_SETITEMDATA,j,k-1); - } - - // remove breakpoint from breakpoint table - while (++i <= wBreakpointCount) - sBreakpoint[i-1] = sBreakpoint[i]; - } - } - return TRUE; - - case IDCANCEL: - EndDialog(hDlg,IDCANCEL); - return TRUE; - } - - case WM_VKEYTOITEM: - if (LOWORD(wParam) == VK_SPACE) - { - hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND); - for (nItem = 0; nItem < wBreakpointCount; ++nItem) - { - // item selected - if (SendMessage(hWnd,LB_GETSEL,nItem,0) > 0) - ToggleBreakpointItem(hWnd,nItem); - } - return -2; - } - return -1; // default action - - case WM_DRAWITEM: - if (wParam == IDC_BREAKEDIT_WND) return OnDrawBreakWnd((LPDRAWITEMSTRUCT) lParam); - break; - - case WM_MEASUREITEM: - hDC = GetDC(hDlg); - - // GetTextMetrics from "Courier New 8" font - hFont = CreateFont(-MulDiv(8,GetDeviceCaps(hDC, LOGPIXELSY),72),0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, - OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Courier New")); - - hFont = (HFONT) SelectObject(hDC,hFont); - GetTextMetrics(hDC,&tm); - hFont = (HFONT) SelectObject(hDC,hFont); - DeleteObject(hFont); - - ((LPMEASUREITEMSTRUCT) lParam)->itemHeight = tm.tmHeight; - - ReleaseDC(hDlg,hDC); - return TRUE; - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -static BOOL OnEditBreakpoint(HWND hDlg) -{ - if (DialogBox(hApp, MAKEINTRESOURCE(IDD_BREAKEDIT), hDlg, (DLGPROC)EditBreakpoint) == -1) - AbortMessage(_T("Edit Breakpoint Dialog Box Creation Error !")); - - // update code window - InvalidateRect(GetDlgItem(hDlg,IDC_DEBUG_CODE),NULL,TRUE); - return -1; -} - - -//################ -//# -//# Last Instruction dialog box -//# -//################ - -// -// view last instructions -// -static INT_PTR CALLBACK InfoIntr(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - HWND hWnd; - TCHAR szBuffer[64]; - LONG lIndex; - WORD i,j; - - switch (message) - { - case WM_INITDIALOG: - // font settings - SendDlgItemMessage(hDlg,IDC_INSTR_TEXT, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_INSTR_CLEAR, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_INSTR_COPY, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDCANCEL, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - - lIndex = 0; // init lIndex - hWnd = GetDlgItem(hDlg,IDC_INSTR_CODE); - SendMessage(hWnd,WM_SETREDRAW,FALSE,0); - SendMessage(hWnd,LB_RESETCONTENT,0,0); - for (i = wInstrRp; i != wInstrWp; i = (i + 1) % wInstrSize) - { - LPCTSTR lpszName; - - // entry has a name - if (disassembler_symb && (lpszName = RplGetName(pdwInstrArray[i])) != NULL) - { - szBuffer[0] = _T('='); - lstrcpyn(&szBuffer[1],lpszName,ARRAYSIZEOF(szBuffer)-1); - SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); - } - - j = wsprintf(szBuffer,_T("%05lX "),pdwInstrArray[i]); - disassemble(pdwInstrArray[i],&szBuffer[j]); - lIndex = (LONG) SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); - } - SendMessage(hWnd,WM_SETREDRAW,TRUE,0); - SendMessage(hWnd,LB_SETCARETINDEX,lIndex,TRUE); - return TRUE; - case WM_COMMAND: - hWnd = GetDlgItem(hDlg,IDC_INSTR_CODE); - switch(LOWORD(wParam)) - { - case IDC_INSTR_COPY: - CopyItemsToClipboard(hWnd); // copy selected items to clipboard - return TRUE; - case IDC_INSTR_CLEAR: // clear instruction buffer - wInstrRp = wInstrWp; - SendMessage(hWnd,LB_RESETCONTENT,0,0); - return TRUE; - case IDCANCEL: - EndDialog(hDlg,IDCANCEL); - return TRUE; - } - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -static BOOL OnInfoIntr(HWND hDlg) -{ - if (DialogBox(hApp, MAKEINTRESOURCE(IDD_INSTRUCTIONS), hDlg, (DLGPROC)InfoIntr) == -1) - AbortMessage(_T("Last Instructions Dialog Box Creation Error !")); - return 0; -} - -// -// view write only I/O registers -// -static INT_PTR CALLBACK InfoWoRegister(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - TCHAR szBuffer[8]; - - switch (message) - { - case WM_INITDIALOG: - wsprintf(szBuffer,_T("%05X"),Chipset.start1); - SetDlgItemText(hDlg,IDC_ADDR20_24,szBuffer); - wsprintf(szBuffer,_T("%03X"),Chipset.loffset); - SetDlgItemText(hDlg,IDC_ADDR25_27,szBuffer); - wsprintf(szBuffer,_T("%02X"),Chipset.lcounter); - SetDlgItemText(hDlg,IDC_ADDR28_29,szBuffer); - wsprintf(szBuffer,_T("%05X"),Chipset.start2); - SetDlgItemText(hDlg,IDC_ADDR30_34,szBuffer); - return TRUE; - case WM_COMMAND: - if ((LOWORD(wParam) == IDCANCEL)) - { - EndDialog(hDlg,IDCANCEL); - return TRUE; - } - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -static BOOL OnInfoWoRegister(HWND hDlg) -{ - if (DialogBox(hApp, MAKEINTRESOURCE(IDD_WRITEONLYREG), hDlg, (DLGPROC)InfoWoRegister) == -1) - AbortMessage(_T("Write-Only Register Dialog Box Creation Error !")); - return 0; -} - - -//################ -//# -//# Breakpoint list operations -//# -//################ - -// -// load breakpoint list -// -VOID LoadBreakpointList(HANDLE hFile) // NULL = clear breakpoint list -{ - DWORD lBytesRead = 0; - - // read number of breakpoints - if (hFile) ReadFile(hFile, &wBreakpointCount, sizeof(wBreakpointCount), &lBytesRead, NULL); - - // breakpoints found - if (lBytesRead == sizeof(wBreakpointCount) && wBreakpointCount < ARRAYSIZEOF(sBreakpoint)) - { - WORD wBreakpointSize; - - // read size of one breakpoint - ReadFile(hFile, &wBreakpointSize, sizeof(wBreakpointSize), &lBytesRead, NULL); - if (lBytesRead == sizeof(wBreakpointSize) && wBreakpointSize == sizeof(sBreakpoint[0])) - { - // read breakpoints - ReadFile(hFile, sBreakpoint, wBreakpointCount * sizeof(sBreakpoint[0]), &lBytesRead, NULL); - _ASSERT(lBytesRead == wBreakpointCount * sizeof(sBreakpoint[0])); - } - else // changed breakpoint structure - { - wBreakpointCount = 0; // clear breakpoint list - } - } - else // no breakpoints or breakpoint buffer too small - { - wBreakpointCount = 0; // clear breakpoint list - } - return; -} - -// -// save breakpoint list -// -VOID SaveBreakpointList(HANDLE hFile) -{ - if (wBreakpointCount) // defined breakpoints - { - DWORD lBytesWritten; - - WORD wBreakpointSize = sizeof(sBreakpoint[0]); - - _ASSERT(hFile); // valid file pointer? - - // write number of breakpoints - WriteFile(hFile, &wBreakpointCount, sizeof(wBreakpointCount), &lBytesWritten, NULL); - _ASSERT(lBytesWritten == sizeof(wBreakpointCount)); - - // write size of one breakpoint - WriteFile(hFile, &wBreakpointSize, sizeof(wBreakpointSize), &lBytesWritten, NULL); - _ASSERT(lBytesWritten == sizeof(wBreakpointSize)); - - // write breakpoints - WriteFile(hFile, sBreakpoint, wBreakpointCount * sizeof(sBreakpoint[0]), &lBytesWritten, NULL); - _ASSERT(lBytesWritten == wBreakpointCount * sizeof(sBreakpoint[0])); - } - return; -} - -// -// create a copy of the breakpoint list -// -VOID CreateBackupBreakpointList(VOID) -{ - _ASSERT(sizeof(sBackupBreakpoint) == sizeof(sBreakpoint)); - - wBackupBreakpointCount = wBreakpointCount; - - if (wBreakpointCount > 0) // list not empty - { - CopyMemory(sBackupBreakpoint,sBreakpoint,sizeof(sBackupBreakpoint)); - } - return; -} - -// -// restore the breakpoint list from the copy -// -VOID RestoreBackupBreakpointList(VOID) -{ - _ASSERT(sizeof(sBackupBreakpoint) == sizeof(sBreakpoint)); - - wBreakpointCount = wBackupBreakpointCount; - - if (wBreakpointCount > 0) // list not empty - { - CopyMemory(sBreakpoint,sBackupBreakpoint,sizeof(sBreakpoint)); - } - return; -} - - -//################ -//# -//# Load/Save Memory Data -//# -//################ - -static BOOL OnBrowseLoadMem(HWND hDlg) -{ - TCHAR szBuffer[MAX_PATH]; - OPENFILENAME ofn; - - ZeroMemory(&ofn, sizeof(OPENFILENAME)); - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = hDlg; - ofn.lpstrFilter = - _T("Memory Dump Files (*.MEM)\0*.MEM\0") - _T("All Files (*.*)\0*.*\0"); - ofn.lpstrDefExt = _T("MEM"); - ofn.nFilterIndex = 1; - ofn.lpstrFile = szBuffer; - ofn.lpstrFile[0] = 0; - ofn.nMaxFile = ARRAYSIZEOF(szBuffer); - ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST; - if (GetOpenFileName(&ofn)) - { - SetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szBuffer); - } - return 0; -} - -static BOOL OnBrowseSaveMem(HWND hDlg) -{ - TCHAR szBuffer[MAX_PATH]; - OPENFILENAME ofn; - - ZeroMemory(&ofn, sizeof(OPENFILENAME)); - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = hDlg; - ofn.lpstrFilter = - _T("Memory Dump Files (*.MEM)\0*.MEM\0") - _T("All Files (*.*)\0*.*\0"); - ofn.lpstrDefExt = _T("MEM"); - ofn.nFilterIndex = 1; - ofn.lpstrFile = szBuffer; - ofn.lpstrFile[0] = 0; - ofn.nMaxFile = ARRAYSIZEOF(szBuffer); - ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT; - if (GetSaveFileName(&ofn)) - { - SetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szBuffer); - } - return 0; -} - -// -// write file to memory -// -static BOOL LoadMemData(LPCTSTR lpszFilename,DWORD dwStartAddr) -{ - HANDLE hFile; - DWORD dwRead; - BYTE byData; - - hFile = CreateFile(lpszFilename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL); - if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file - return FALSE; - - while (dwStartAddr <= 0xFFFFF) // read until EOF or end of Saturn address space - { - ReadFile(hFile,&byData,sizeof(byData),&dwRead,NULL); - if (dwRead == 0) break; // EOF - - if (dwStartAddr < 0xFFFFF) - { - Write2(dwStartAddr,byData); // write byte in map mode - dwStartAddr += 2; - } - else // special handling to avoid address wrap around - { - byData &= 0xF; - Nwrite(&byData,dwStartAddr,1); // write nibble in map mode - ++dwStartAddr; - } - } - - CloseHandle(hFile); - return TRUE; -} - -// -// write memory data to file -// -static BOOL SaveMemData(LPCTSTR lpszFilename,DWORD dwStartAddr,DWORD dwEndAddr) -{ - HANDLE hFile; - DWORD dwAddr,dwWritten; - BYTE byData; - - hFile = CreateFile(lpszFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); - if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file - return FALSE; - - for (dwAddr = dwStartAddr; dwAddr <= dwEndAddr; dwAddr += 2) - { - _ASSERT(dwAddr <= 0xFFFFF); - byData = Read2(dwAddr); // read byte in map mode - WriteFile(hFile,&byData,sizeof(byData),&dwWritten,NULL); - } - - CloseHandle(hFile); - return TRUE; -} - -// -// memory load data -// -static INT_PTR CALLBACK DebugMemLoad(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - TCHAR szFilename[MAX_PATH]; - DWORD dwStartAddr; - - switch (message) - { - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDC_DEBUG_DATA_BUT: - return OnBrowseLoadMem(hDlg); - - case IDOK: - dwStartAddr = -1; // no address given - - // get filename - GetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szFilename,ARRAYSIZEOF(szFilename)); - - // decode address field - if ( !GetAddr(hDlg,IDC_DEBUG_DATA_STARTADDR,&dwStartAddr,0xFFFFF,FALSE) - || dwStartAddr == -1) - return FALSE; - - _ASSERT(dwStartAddr <= 0xFFFFF); - - // load memory dump file - if (!LoadMemData(szFilename,dwStartAddr)) - return FALSE; - - // update memory window - UpdateMemoryWnd(GetParent(hDlg)); - - // no break - case IDCANCEL: - EndDialog(hDlg,LOWORD(wParam)); - return TRUE; - } - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -static BOOL OnMemLoadData(HWND hDlg) -{ - if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_MEMLOAD), hDlg, (DLGPROC)DebugMemLoad) == -1) - AbortMessage(_T("DebugLoad Dialog Box Creation Error !")); - return -1; -} - -// -// memory save data -// -static INT_PTR CALLBACK DebugMemSave(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - TCHAR szFilename[MAX_PATH]; - DWORD dwStartAddr,dwEndAddr; - - switch (message) - { - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDC_DEBUG_DATA_BUT: - return OnBrowseSaveMem(hDlg); - - case IDOK: - dwStartAddr = dwEndAddr = -1; // no address given - - // get filename - GetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szFilename,ARRAYSIZEOF(szFilename)); - - // decode address fields - if ( !GetAddr(hDlg,IDC_DEBUG_DATA_STARTADDR,&dwStartAddr,0xFFFFF,FALSE) - || dwStartAddr == -1) - return FALSE; - if ( !GetAddr(hDlg,IDC_DEBUG_DATA_ENDADDR,&dwEndAddr,0xFFFFF,FALSE) - || dwEndAddr == -1) - return FALSE; - - _ASSERT(dwStartAddr <= 0xFFFFF); - _ASSERT(dwEndAddr <= 0xFFFFF); - - // save memory dump file - if (!SaveMemData(szFilename,dwStartAddr,dwEndAddr)) - return FALSE; - - // no break - case IDCANCEL: - EndDialog(hDlg,LOWORD(wParam)); - return TRUE; - } - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -static BOOL OnMemSaveData(HWND hDlg) -{ - if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_MEMSAVE), hDlg, (DLGPROC)DebugMemSave) == -1) - AbortMessage(_T("DebugSave Dialog Box Creation Error !")); - return -1; -} - - -//################ -//# -//# Trace Log -//# -//################ - -static VOID StartTrace(VOID) -{ - if (hLogFile == NULL) - { - SetCurrentDirectory(szEmuDirectory); - hLogFile = CreateFile( - szTraceFilename, - GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ, - NULL, - (uTraceMode == TRACE_FILE_NEW) ? CREATE_ALWAYS : OPEN_ALWAYS, - 0, - NULL); - SetCurrentDirectory(szCurrentDirectory); - if (hLogFile == INVALID_HANDLE_VALUE) - { - InfoMessage(_T("Unable to create trace log file.")); - hLogFile = NULL; - return; - } - - // goto end of file - SetFilePointer(hLogFile,0L,NULL,FILE_END); - } - return; -} - -static VOID StopTrace(VOID) -{ - if (hLogFile != NULL) - { - CloseHandle(hLogFile); - } - hLogFile = NULL; - return; -} - -static VOID FlushTrace(VOID) -{ - if (hLogFile != NULL) - { - VERIFY(FlushFileBuffers(hLogFile)); - } - return; -} - -static __inline void __cdecl PrintTrace(LPCTSTR lpFormat, ...) -{ - TCHAR cOutput[1024]; - DWORD dwWritten, dwRead; - va_list arglist; - - va_start(arglist,lpFormat); - dwWritten = (DWORD) wvsprintf(cOutput,lpFormat,arglist); - va_end(arglist); - #if defined _UNICODE - { - // Unicode to byte translation - LPTSTR szTmp = DuplicateString(cOutput); - if (szTmp != NULL) - { - WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, - szTmp, -1, - (LPSTR) cOutput, sizeof(cOutput), NULL, NULL); - free(szTmp); - } - } - #endif - WriteFile(hLogFile,cOutput,dwWritten,&dwRead,NULL); - return; -} - -static VOID OutTrace(VOID) -{ - enum MEM_MAPPING eMapMode; - LPCTSTR lpszName; - LPTSTR s,d; - TCHAR szBuffer[128]; - TCHAR szOpc[8]; - DWORD dwNxtAddr,dwOpcAddr; - UINT i; - - if (hLogFile != NULL) // log file opened - { - if (bTraceReg) // show regs - { - INT nPos; - - nPos = wsprintf(szBuffer,_T("\r\n A=%s"),RegToStr(Chipset.A,16)); - nPos += wsprintf(&szBuffer[nPos],_T(" B=%s"),RegToStr(Chipset.B,16)); - nPos += wsprintf(&szBuffer[nPos],_T(" C=%s"),RegToStr(Chipset.C,16)); - wsprintf(&szBuffer[nPos],_T(" D=%s\r\n"),RegToStr(Chipset.D,16)); - PrintTrace(szBuffer); - - nPos = wsprintf(szBuffer,_T(" R0=%s"),RegToStr(Chipset.R0,16)); - nPos += wsprintf(&szBuffer[nPos],_T(" R1=%s"),RegToStr(Chipset.R1,16)); - nPos += wsprintf(&szBuffer[nPos],_T(" R2=%s"),RegToStr(Chipset.R2,16)); - wsprintf(&szBuffer[nPos],_T(" R3=%s\r\n"),RegToStr(Chipset.R3,16)); - PrintTrace(szBuffer); - - PrintTrace(_T(" R4=%s D0=%05X D1=%05X P=%X CY=%d Mode=%c OUT=%03X IN=%04X\r\n"), - RegToStr(Chipset.R4,16),Chipset.d0,Chipset.d1,Chipset.P,Chipset.carry, - Chipset.mode_dec ? _T('D') : _T('H'),Chipset.out,Chipset.in); - - PrintTrace(_T(" ST=%s MP=%d SR=%d SB=%d XM=%d IntrEn=%d KeyScan=%d BS=%02X\r\n"), - RegToStr(Chipset.ST,4), - (Chipset.HST & MP) != 0,(Chipset.HST & SR) != 0,(Chipset.HST & SB) != 0,(Chipset.HST & XM) != 0, - Chipset.inte,Chipset.intk,Chipset.Bank_FF & 0x7F); - - // hardware stack content - PrintTrace(_T(" Stack=")); - for (i = 1; i <= ARRAYSIZEOF(Chipset.rstk); ++i) - { - PrintTrace(_T(" %05X"), Chipset.rstk[(Chipset.rstkp-i)&7]); - } - PrintTrace(_T("\r\n")); - } - - if (bTraceMmu) // show MMU - { - TCHAR szSize[8],szAddr[8]; - - if (!bTraceReg) // no regs - { - PrintTrace(_T("\r\n")); // add separator line - } - - wsprintf(szAddr, Chipset.IOCfig ? _T("%05X") : _T("-----"),Chipset.IOBase); - PrintTrace(_T(" I/O=%s"),szAddr); - - wsprintf(szSize, Chipset.P0Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P0Size^0xFF)<<12); - wsprintf(szAddr, Chipset.P0Cfig ? _T("%05X") : _T("-----"),Chipset.P0Base<<12); - PrintTrace(_T(" NCE2=%s/%s"),szSize,szAddr); - - if (cCurrentRomType=='S') - { - wsprintf(szSize, Chipset.P1Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P1Size^0xFF)<<12); - wsprintf(szAddr, Chipset.P1Cfig ? _T("%05X") : _T("-----"),Chipset.P1Base<<12); - } - else - { - wsprintf(szSize, Chipset.BSCfg2 ? _T("%05X") : _T("-----"),(Chipset.BSSize^0xFF)<<12); - wsprintf(szAddr, Chipset.BSCfig ? _T("%05X") : _T("-----"),Chipset.BSBase<<12); - } - PrintTrace(_T(" CE1=%s/%s"),szSize,szAddr); - - if (cCurrentRomType=='S') - { - wsprintf(szSize, Chipset.P2Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P2Size^0xFF)<<12); - wsprintf(szAddr, Chipset.P2Cfig ? _T("%05X") : _T("-----"),Chipset.P2Base<<12); - } - else - { - wsprintf(szSize, Chipset.P1Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P1Size^0xFF)<<12); - wsprintf(szAddr, Chipset.P1Cfig ? _T("%05X") : _T("-----"),Chipset.P1Base<<12); - } - PrintTrace(_T(" CE2=%s/%s"),szSize,szAddr); - - if (cCurrentRomType=='S') - { - wsprintf(szSize, Chipset.BSCfg2 ? _T("%05X") : _T("-----"),(Chipset.BSSize^0xFF)<<12); - wsprintf(szAddr, Chipset.BSCfig ? _T("%05X") : _T("-----"),Chipset.BSBase<<12); - } - else - { - wsprintf(szSize, Chipset.P2Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P2Size^0xFF)<<12); - wsprintf(szAddr, Chipset.P2Cfig ? _T("%05X") : _T("-----"),Chipset.P2Base<<12); - } - PrintTrace(_T(" NCE3=%s/%s\r\n"),szSize,szAddr); - } - - // disassemble line - eMapMode = GetMemMapType(); // get current map mode - SetMemMapType(MEM_MMU); // disassemble in mapped mode - - // entry has a name - if (disassembler_symb && (lpszName = RplGetName(Chipset.pc)) != NULL) - { - PrintTrace(_T("=%s\r\n"),lpszName); // print address as label - } - dwNxtAddr = disassemble(Chipset.pc,szBuffer); - - // in disassembly replace space characters - // between Opcode and Modifier with one TAB - if ((s = _tcschr(szBuffer,_T(' '))) != NULL) - { - // skip blanks - for (d = s; *d == _T(' '); ++d) { } - - if (d == &szBuffer[8]) // on TAB position - { - *s++ = _T('\t'); // replace with TAB - - // move the opcode modifier - while ((*s++ = *d++) != 0) { } - } - } - - if (bTraceOpc) // show opcode nibbles - { - dwOpcAddr = Chipset.pc; // init address - - // show opcode nibbles in a block of 5 - for (i = 0; i < 5 && dwOpcAddr < dwNxtAddr; ++i) - { - szOpc[i] = cHex[GetMemNib(&dwOpcAddr)]; - } - - if (i == 1) // only 1 nibble written - { - szOpc[i++] = _T('\t'); // one additional TAB necessary - } - szOpc[i] = 0; // EOS - - PrintTrace(_T("%05lX %s\t%s\r\n"),Chipset.pc,szOpc,szBuffer); - - while (dwOpcAddr < dwNxtAddr) // decode rest of opcode - { - // show opcode nibbles in a block of 5 - for (i = 0; i < 5 && dwOpcAddr < dwNxtAddr; ++i) - { - szOpc[i] = cHex[GetMemNib(&dwOpcAddr)]; - } - szOpc[i] = 0; // EOS - - PrintTrace(_T(" %s\r\n"),szOpc); - } - } - else // without opcode nibbles - { - PrintTrace(_T("%05lX\t%s\r\n"),Chipset.pc,szBuffer); - } - - SetMemMapType(eMapMode); // switch back to old map mode - } - return; -} - -// -// trace settings dialog -// -static BOOL OnBrowseTraceSettings(HWND hDlg) -{ - TCHAR szBuffer[MAX_PATH]; - OPENFILENAME ofn; - - // get current content of file edit box - GetDlgItemText(hDlg,IDC_TRACE_FILE,szBuffer,ARRAYSIZEOF(szBuffer)); - - ZeroMemory(&ofn, sizeof(OPENFILENAME)); - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = hDlg; - ofn.lpstrFilter = - _T("Trace Log Files (*.log)\0*.log\0") - _T("All Files (*.*)\0*.*\0"); - ofn.lpstrDefExt = _T("log"); - ofn.nFilterIndex = 1; - ofn.lpstrFile = szBuffer; - ofn.nMaxFile = ARRAYSIZEOF(szBuffer); - ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT; - if (GetSaveFileName(&ofn)) - { - SetDlgItemText(hDlg,IDC_TRACE_FILE,szBuffer); - } - return 0; -} - -// -// trace settings -// -static INT_PTR CALLBACK TraceSettings(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_INITDIALOG: - SetDlgItemText(hDlg,IDC_TRACE_FILE,szTraceFilename); - CheckDlgButton(hDlg,(uTraceMode == TRACE_FILE_NEW) ? IDC_TRACE_NEW : IDC_TRACE_APPEND,BST_CHECKED); - CheckDlgButton(hDlg,IDC_TRACE_REGISTER,bTraceReg); - CheckDlgButton(hDlg,IDC_TRACE_MMU,bTraceMmu); - CheckDlgButton(hDlg,IDC_TRACE_OPCODE,bTraceOpc); - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDC_TRACE_BROWSE: - return OnBrowseTraceSettings(hDlg); - - case IDOK: - // get filename - GetDlgItemText(hDlg,IDC_TRACE_FILE,szTraceFilename,ARRAYSIZEOF(szTraceFilename)); - - // trace mode - uTraceMode = IsDlgButtonChecked(hDlg,IDC_TRACE_NEW) ? TRACE_FILE_NEW : TRACE_FILE_APPEND; - - // trace content - bTraceReg = IsDlgButtonChecked(hDlg,IDC_TRACE_REGISTER); - bTraceMmu = IsDlgButtonChecked(hDlg,IDC_TRACE_MMU); - bTraceOpc = IsDlgButtonChecked(hDlg,IDC_TRACE_OPCODE); - - // no break - case IDCANCEL: - EndDialog(hDlg,LOWORD(wParam)); - return TRUE; - } - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -static BOOL OnTraceSettings(HWND hDlg) -{ - if (DialogBox(hApp, MAKEINTRESOURCE(IDD_TRACE), hDlg, (DLGPROC)TraceSettings) == -1) - AbortMessage(_T("TraceSettings Dialog Box Creation Error !")); - return -1; -} - -static BOOL OnTraceEnable(HWND hDlg) -{ - OnToggleMenuItem(hDlg,ID_TRACE_ENABLE,&bDbgTrace); - bDbgTrace ? StartTrace() : StopTrace(); - EnableMenuItem(GetMenu(hDlg),ID_TRACE_SETTINGS,bDbgTrace ? MF_GRAYED : MF_ENABLED); - return 0; -} +/* + * debugger.c + * + * This file is part of Emu48 + * + * Copyright (C) 1999 Christoph Gießelink + * + */ +#include "pch.h" +#include "resource.h" +#include "Emu48.h" +#include "Opcodes.h" +#include "ops.h" +#include "color.h" +#include "disrpl.h" +#include "debugger.h" + +#define MAXCODELINES 15 // number of lines in code window +#define MAXMEMLINES 6 // number of lines in memory window +#define MAXMEMITEMS 16 // number of address items in a memory window line +#define MAXBREAKPOINTS 256 // max. number of breakpoints + +#define REG_START IDC_REG_A // first register in register update table +#define REG_STOP IDC_MISC_BS // last register in register update table +#define REG_SIZE (REG_STOP-REG_START+1) // size of register update table + +// assert for register update +#define _ASSERTREG(r) _ASSERT(r >= REG_START && r <= REG_STOP) + +#define WM_UPDATE (WM_USER+0x1000) // update debugger dialog box + +#define MEMWNDMAX (sizeof(nCol) / sizeof(nCol[0])) + +#define RT_TOOLBAR MAKEINTRESOURCE(241) // MFC toolbar resource type + +#define CODELABEL 0x80000000 // label in code window + +// trace log file modes +enum TRACE_MODE { TRACE_FILE_NEW = 0, TRACE_FILE_APPEND }; + +typedef struct CToolBarData +{ + WORD wVersion; + WORD wWidth; + WORD wHeight; + WORD wItemCount; + WORD aItems[1]; +} CToolBarData; + +typedef struct // type of breakpoint table +{ + BOOL bEnable; // breakpoint enabled + UINT nType; // breakpoint type + DWORD dwAddr; // breakpoint address +} BP_T; + +static CONST int nCol[] = +{ + IDC_DEBUG_MEM_COL0, IDC_DEBUG_MEM_COL1, IDC_DEBUG_MEM_COL2, IDC_DEBUG_MEM_COL3, + IDC_DEBUG_MEM_COL4, IDC_DEBUG_MEM_COL5, IDC_DEBUG_MEM_COL6, IDC_DEBUG_MEM_COL7 +}; + +static CONST TCHAR cHex[] = { _T('0'),_T('1'),_T('2'),_T('3'), + _T('4'),_T('5'),_T('6'),_T('7'), + _T('8'),_T('9'),_T('A'),_T('B'), + _T('C'),_T('D'),_T('E'),_T('F') }; + +static INT nDbgPosX = CW_USEDEFAULT; // position of debugger window +static INT nDbgPosY = CW_USEDEFAULT; + +static WORD wBreakpointCount = 0; // number of breakpoints +static BP_T sBreakpoint[MAXBREAKPOINTS]; // breakpoint table + +static WORD wBackupBreakpointCount = 0; // number of breakpoints +static BP_T sBackupBreakpoint[MAXBREAKPOINTS]; // breakpoint table + +static INT nRplBreak; // RPL breakpoint + +static DWORD dwAdrLine[MAXCODELINES]; // addresses of disassember lines in code window +static DWORD dwAdrMem = 0; // start address of memory window + +static UINT uIDFol = ID_DEBUG_MEM_FNONE; // follow mode +static DWORD dwAdrMemFol = 0; // follow address memory window + +static UINT uIDMap = ID_DEBUG_MEM_MAP; // current memory view mode + +static BOOL bDbgTrace = FALSE; // enable trace output +static HANDLE hLogFile = NULL; // log file handle +static TCHAR szTraceFilename[MAX_PATH] = _T("trace.log"); // filename for trace file +static UINT uTraceMode = TRACE_FILE_NEW; // trace log file mode +static BOOL bTraceReg = TRUE; // enable register logging +static BOOL bTraceMmu = FALSE; // disable MMU logging +static BOOL bTraceOpc = TRUE; // enable opcode logging + +static LONG lCharWidth; // width of a character (is a fix font) + +static HMENU hMenuCode,hMenuMem,hMenuStack;// handle of context menues +static HWND hWndToolbar; // toolbar handle + +static DWORD dwDbgRefCycles; // cpu cycles counter from last opcode + +static CHIPSET OldChipset; // old chipset content +static BOOL bRegUpdate[REG_SIZE]; // register update table + +static HBITMAP hBmpCheckBox; // checked and unchecked bitmap +static HFONT hFontBold; // bold font for symbol labels in code window + +// function prototypes +static BOOL OnMemFind(HWND hDlg); +static BOOL OnProfile(HWND hDlg); +static VOID UpdateRplObjViewWnd(HWND hDlg, DWORD dwAddr); +static BOOL OnRplObjView(HWND hDlg); +static BOOL OnSettings(HWND hDlg); +static INT_PTR OnNewValue(LPTSTR lpszValue); +static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue); +static BOOL OnEditBreakpoint(HWND hDlg); +static BOOL OnInfoIntr(HWND hDlg); +static BOOL OnInfoWoRegister(HWND hDlg); +static VOID UpdateProfileWnd(HWND hDlg); +static BOOL OnMemLoadData(HWND hDlg); +static BOOL OnMemSaveData(HWND hDlg); +static VOID StartTrace(VOID); +static VOID StopTrace(VOID); +static VOID FlushTrace(VOID); +static VOID OutTrace(VOID); +static BOOL OnTraceSettings(HWND hDlg); +static BOOL OnTraceEnable(HWND hDlg); + +//################ +//# +//# Low level subroutines +//# +//################ + +// +// load external rpl symbol table +// +static BOOL LoadSymbTable(VOID) +{ + TCHAR szSymbFilename[MAX_PATH]; + TCHAR szItemname[16]; + + wsprintf(szItemname,_T("Symb%c"),(TCHAR) cCurrentRomType); + ReadSettingsString(_T("Disassembler"),szItemname,_T(""),szSymbFilename,ARRAYSIZEOF(szSymbFilename)); + + if (*szSymbFilename == 0) // no reference table defined + return FALSE; // no success + + return RplLoadTable(szSymbFilename); // load external reference table +} + +// +// disable menu keys +// +static VOID DisableMenuKeys(HWND hDlg) +{ + HMENU hMenu = GetMenu(hDlg); + + EnableMenuItem(hMenu,ID_DEBUG_RUN,MF_GRAYED); + EnableMenuItem(hMenu,ID_DEBUG_RUNCURSOR,MF_GRAYED); + EnableMenuItem(hMenu,ID_DEBUG_STEP,MF_GRAYED); + EnableMenuItem(hMenu,ID_DEBUG_STEPOVER,MF_GRAYED); + EnableMenuItem(hMenu,ID_DEBUG_STEPOUT,MF_GRAYED); + EnableMenuItem(hMenu,ID_INFO_LASTINSTRUCTIONS,MF_GRAYED); + EnableMenuItem(hMenu,ID_INFO_WRITEONLYREG,MF_GRAYED); + + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUN,MAKELONG((FALSE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_BREAK,MAKELONG((TRUE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUNCURSOR,MAKELONG((FALSE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEP,MAKELONG((FALSE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOVER,MAKELONG((FALSE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOUT,MAKELONG((FALSE),0)); + return; +} + +// +// read edit control and decode content as hex number or if enabled as symbol name +// +static BOOL GetAddr(HWND hDlg,INT nID,DWORD *pdwAddr,DWORD dwMaxAddr,BOOL bSymbEnable) +{ + TCHAR szBuffer[48]; + INT i; + BOOL bSucc = TRUE; + + HWND hWnd = GetDlgItem(hDlg,nID); + + GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer)); + + if (*szBuffer != 0) + { + // if address is not a symbol name decode number + if ( !bSymbEnable || szBuffer[0] != _T('=') + || RplGetAddr(&szBuffer[1],pdwAddr)) + { + // test if valid hex address + for (i = 0; bSucc && i < (LONG) lstrlen(szBuffer); ++i) + { + bSucc = (_istxdigit(szBuffer[i]) != 0); + } + + if (bSucc) // valid characters + { + // convert string to number + *pdwAddr = _tcstoul(szBuffer,NULL,16); + } + } + + // inside address range? + bSucc = bSucc && (*pdwAddr <= dwMaxAddr); + + if (!bSucc) // invalid address + { + SendMessage(hWnd,EM_SETSEL,0,-1); + SetFocus(hWnd); // focus to edit control + } + } + return bSucc; +} + +// +// set mapping menu +// +static VOID SetMappingMenu(HWND hDlg,UINT uID) +{ + enum MEM_MAPPING eMode; + LPTSTR szCaption; + + UINT uEnable = MF_GRAYED; // disable Memory Data menu items + + CheckMenuItem(hMenuMem,uIDMap,MF_UNCHECKED); + + switch (uID) + { + case ID_DEBUG_MEM_MAP: + szCaption = _T("Memory"); + eMode = MEM_MMU; + uEnable = MF_ENABLED; // enable Memory Data menu items + break; + case ID_DEBUG_MEM_NCE1: + szCaption = _T("Memory (NCE1)"); + eMode = MEM_NCE1; + break; + case ID_DEBUG_MEM_NCE2: + szCaption = _T("Memory (NCE2)"); + eMode = MEM_NCE2; + break; + case ID_DEBUG_MEM_CE1: + szCaption = _T("Memory (CE1)"); + eMode = MEM_CE1; + break; + case ID_DEBUG_MEM_CE2: + szCaption = _T("Memory (CE2)"); + eMode = MEM_CE2; + break; + case ID_DEBUG_MEM_NCE3: + szCaption = _T("Memory (NCE3)"); + eMode = MEM_NCE3; + break; + default: _ASSERT(0); + } + + VERIFY(SetMemMapType(eMode)); + + if (uIDMap != uID) dwAdrMem = 0; // view from address 0 + + uIDMap = uID; + CheckMenuItem(hMenuMem,uIDMap,MF_CHECKED); + + EnableMenuItem(hMenuMem,ID_DEBUG_MEM_LOAD,uEnable); + EnableMenuItem(hMenuMem,ID_DEBUG_MEM_SAVE,uEnable); + + SetDlgItemText(hDlg,IDC_STATIC_MEMORY,szCaption); + return; +}; + +// +// get address of cursor in memory window +// +static DWORD GetMemCurAddr(HWND hDlg) +{ + INT i,nPos; + DWORD dwAddr = dwAdrMem; + DWORD dwMapDataMask = GetMemDataMask(); + + for (i = 0; i < MEMWNDMAX; ++i) // scan all memory cols + { + // column has cursor + if ((nPos = (INT) SendDlgItemMessage(hDlg,nCol[i],LB_GETCURSEL,0,0)) != LB_ERR) + { + dwAddr += (DWORD) (nPos * MEMWNDMAX + i) * 2; + dwAddr &= dwMapDataMask; + break; + } + } + return dwAddr; +} + +// +// set/reset breakpoint +// +static __inline VOID ToggleBreakpoint(DWORD dwAddr) +{ + INT i; + + for (i = 0; i < wBreakpointCount; ++i) // scan all breakpoints + { + // code breakpoint found + if (sBreakpoint[i].nType == BP_EXEC && sBreakpoint[i].dwAddr == dwAddr) + { + if (!sBreakpoint[i].bEnable) // breakpoint disabled + { + sBreakpoint[i].bEnable = TRUE; + return; + } + + while (++i < wBreakpointCount) // purge breakpoint + sBreakpoint[i-1] = sBreakpoint[i]; + --wBreakpointCount; + return; + } + } + + // breakpoint not found + if (wBreakpointCount >= MAXBREAKPOINTS) // breakpoint buffer full + { + AbortMessage(_T("Reached maximum number of breakpoints !")); + return; + } + + sBreakpoint[wBreakpointCount].bEnable = TRUE; + sBreakpoint[wBreakpointCount].nType = BP_EXEC; + sBreakpoint[wBreakpointCount].dwAddr = dwAddr; + ++wBreakpointCount; + return; +} + +// +// init memory mapping table and mapping menu entry +// +static __inline VOID InitMemMap(HWND hDlg) +{ + BOOL bActive; + + SetMemRomType(cCurrentRomType); // set current model + + _ASSERT(hMenuMem); + + // enable menu mappings + EnableMenuItem(hMenuMem,ID_DEBUG_MEM_NCE1,GetMemAvail(MEM_NCE1) ? MF_ENABLED : MF_GRAYED); + EnableMenuItem(hMenuMem,ID_DEBUG_MEM_NCE2,GetMemAvail(MEM_NCE2) ? MF_ENABLED : MF_GRAYED); + EnableMenuItem(hMenuMem,ID_DEBUG_MEM_CE1, GetMemAvail(MEM_CE1) ? MF_ENABLED : MF_GRAYED); + EnableMenuItem(hMenuMem,ID_DEBUG_MEM_CE2, GetMemAvail(MEM_CE2) ? MF_ENABLED : MF_GRAYED); + EnableMenuItem(hMenuMem,ID_DEBUG_MEM_NCE3,GetMemAvail(MEM_NCE3) ? MF_ENABLED : MF_GRAYED); + + bActive = (ID_DEBUG_MEM_NCE1 == uIDMap && GetMemAvail(MEM_NCE1)) + || (ID_DEBUG_MEM_NCE2 == uIDMap && GetMemAvail(MEM_NCE2)) + || (ID_DEBUG_MEM_CE1 == uIDMap && GetMemAvail(MEM_CE1)) + || (ID_DEBUG_MEM_CE2 == uIDMap && GetMemAvail(MEM_CE2)) + || (ID_DEBUG_MEM_NCE3 == uIDMap && GetMemAvail(MEM_NCE3)); + + SetMappingMenu(hDlg,bActive ? uIDMap : ID_DEBUG_MEM_MAP); + return; +} + +// +// init bank switcher area +// +static __inline VOID InitBsArea(HWND hDlg) +{ + // HP39/40G, HP48GX, HP49G + if (cCurrentRomType=='E' || cCurrentRomType=='G' || cCurrentRomType=='X') + { + EnableWindow(GetDlgItem(hDlg,IDC_MISC_BS_TXT),TRUE); + EnableWindow(GetDlgItem(hDlg,IDC_MISC_BS),TRUE); + } + return; +} + +// +// convert nibble register to string +// +static LPTSTR RegToStr(BYTE *pReg, WORD wNib) +{ + static TCHAR szBuffer[32]; + + WORD i; + + for (i = 0;i < wNib;++i) + szBuffer[i] = cHex[pReg[wNib-i-1]]; + szBuffer[i] = 0; + + return szBuffer; +} + +// +// convert string to nibble register +// +static VOID StrToReg(BYTE *pReg, WORD wNib, LPTSTR lpszValue) +{ + int i,nValuelen; + + nValuelen = lstrlen(lpszValue); + for (i = wNib - 1;i >= 0;--i) + { + if (i >= nValuelen) // no character in string + { + pReg[i] = 0; // fill with zero + } + else + { + // convert to number + pReg[i] = _totupper(*lpszValue) - _T('0'); + if (pReg[i] > 9) pReg[i] -= _T('A') - _T('9') - 1; + ++lpszValue; + } + } + return; +} + +// +// write code window +// +static INT ViewCodeWnd(HWND hWnd, DWORD dwAddress) +{ + enum MEM_MAPPING eMapMode; + LPCTSTR lpszName; + TCHAR szAddress[64]; + DWORD dwNxtAddr; + INT i,j,nLinePC; + + nLinePC = -1; // PC not shown (no selection) + + eMapMode = GetMemMapType(); // get current map mode + SetMemMapType(MEM_MMU); // disassemble in mapped mode + + dwAddress &= 0xFFFFF; // adjust to Saturn address range + SendMessage(hWnd,WM_SETREDRAW,FALSE,0); + SendMessage(hWnd,LB_RESETCONTENT,0,0); + for (i = 0; i < MAXCODELINES; ++i) + { + // entry has a name + if (disassembler_symb && (lpszName = RplGetName(dwAddress)) != NULL) + { + // save address as label + dwAdrLine[i] = dwAddress | CODELABEL; + + szAddress[0] = _T('='); + lstrcpyn(&szAddress[1],lpszName,ARRAYSIZEOF(szAddress)-1); + SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szAddress); + if (++i == MAXCODELINES) break; + } + + // remember line of PC + if (dwAddress == Chipset.pc) nLinePC = i; + + dwAdrLine[i] = dwAddress; + j = wsprintf(szAddress, + (dwAddress == Chipset.pc) ? _T("%05lX-%c ") : _T("%05lX "), + dwAddress,nRplBreak ? _T('R') : _T('>')); + + dwNxtAddr = (dwAddress + 5) & 0xFFFFF; + + // check if address content is a PCO (Primitive Code Object) + // make sure when the PC points to such an address that it's + // interpreted as opcode + if ((dwAddress != Chipset.pc) && (Read5(dwAddress) == dwNxtAddr)) + { + if (disassembler_mode == HP_MNEMONICS) + { + _tcscat(&szAddress[j],_T("CON(5) (*)+5")); + } + else + { + wsprintf(&szAddress[j],_T("dcr.5 $%05x"),dwNxtAddr); + } + dwAddress = dwNxtAddr; + } + else + { + dwAddress = disassemble(dwAddress,&szAddress[j]); + } + SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szAddress); + } + SendMessage(hWnd,WM_SETREDRAW,TRUE,0); + SetMemMapType(eMapMode); // switch back to old map mode + return nLinePC; +} + +// +// write memory window +// +static VOID ViewMemWnd(HWND hDlg, DWORD dwAddress) +{ + #define TEXTOFF 32 + + INT i,j; + TCHAR szBuffer[16],szItem[4]; + DWORD dwMapDataMask; + BYTE cChar; + + szItem[2] = 0; // end of string + dwAdrMem = dwAddress; // save start address of memory window + dwMapDataMask = GetMemDataMask(); // size mask of data mapping + + // purge all list boxes + SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_ADDR,LB_RESETCONTENT,0,0); + SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_TEXT,LB_RESETCONTENT,0,0); + for (j = 0; j < MEMWNDMAX; ++j) + SendDlgItemMessage(hDlg,nCol[j],LB_RESETCONTENT,0,0); + + for (i = 0; i < MAXMEMLINES; ++i) + { + BYTE byLineData[MAXMEMITEMS]; + + if (ID_DEBUG_MEM_MAP == uIDMap) // mapped memory content + { + wsprintf(szBuffer,_T("%05lX"),dwAddress); + } + else // module memory content + { + wsprintf(szBuffer,_T("%06lX"),dwAddress); + } + SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_ADDR,LB_ADDSTRING,0,(LPARAM) szBuffer); + + // fetch data line + GetMemPeek(byLineData, dwAddress, MAXMEMITEMS); + + for (j = 0; j < MAXMEMITEMS; ++j) + { + // read from fetched data line + szItem[j&0x1] = cHex[byLineData[j]]; + // characters are saved in LBS, MSB order + cChar = (cChar >> 4) | (byLineData[j] << 4); + + if ((j&0x1) != 0) + { + // byte field + _ASSERT(j/2 < MEMWNDMAX); + SendDlgItemMessage(hDlg,nCol[j/2],LB_ADDSTRING,0,(LPARAM) szItem); + + // text field + szBuffer[j/2] = (isprint(cChar) != 0) ? cChar : _T('.'); + } + } + szBuffer[j/2] = 0; // end of text string + SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_TEXT,LB_ADDSTRING,0,(LPARAM) szBuffer); + + dwAddress = (dwAddress + MAXMEMITEMS) & dwMapDataMask; + } + return; + #undef TEXTOFF +} + + +//################ +//# +//# High level Window draw routines +//# +//################ + +// +// update code window with scrolling +// +static VOID UpdateCodeWnd(HWND hDlg) +{ + DWORD dwAddress,dwPriorAddr; + INT i,j; + + HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE); + + j = (INT) SendMessage(hWnd,LB_GETCOUNT,0,0); // no. of items in table + + // seach for actual address in code area + for (i = 0; i < j; ++i) + { + if (dwAdrLine[i] == Chipset.pc) // found new pc address line + break; + } + + // redraw code window + dwAddress = dwAdrLine[0]; // redraw list box with modified pc + if (i == j) // address not found + { + dwAddress = Chipset.pc; // begin with actual pc + + // check if current pc is the begin of a PCO, show PCO address + dwPriorAddr = (dwAddress - 5) & 0xFFFFF; + if (Read5(dwPriorAddr) == dwAddress) + dwAddress = dwPriorAddr; + } + else + { + if (i > 10) // cursor near bottom line + { + j = 10; // pc to line 11 + + // new address line is label + if ((dwAdrLine[i-11] & CODELABEL) != 0) + --j; // pc to line 10 + + dwAddress = dwAdrLine[i-j]; // move that pc is in line 11 + } + } + + i = ViewCodeWnd(hWnd,dwAddress); // init code area + SendMessage(hWnd,LB_SETCURSEL,i,0); // set cursor on actual pc + return; +} + +// +// update register window +// +static VOID UpdateRegisterWnd(HWND hDlg) +{ + TCHAR szBuffer[64]; + + _ASSERTREG(IDC_REG_A); + bRegUpdate[IDC_REG_A-REG_START] = memcmp(Chipset.A, OldChipset.A, sizeof(Chipset.A)) != 0; + wsprintf(szBuffer,_T("A= %s"),RegToStr(Chipset.A,16)); + SetDlgItemText(hDlg,IDC_REG_A,szBuffer); + _ASSERTREG(IDC_REG_B); + bRegUpdate[IDC_REG_B-REG_START] = memcmp(Chipset.B, OldChipset.B, sizeof(Chipset.B)) != 0; + wsprintf(szBuffer,_T("B= %s"),RegToStr(Chipset.B,16)); + SetDlgItemText(hDlg,IDC_REG_B,szBuffer); + _ASSERTREG(IDC_REG_C); + bRegUpdate[IDC_REG_C-REG_START] = memcmp(Chipset.C, OldChipset.C, sizeof(Chipset.C)) != 0; + wsprintf(szBuffer,_T("C= %s"),RegToStr(Chipset.C,16)); + SetDlgItemText(hDlg,IDC_REG_C,szBuffer); + _ASSERTREG(IDC_REG_D); + bRegUpdate[IDC_REG_D-REG_START] = memcmp(Chipset.D, OldChipset.D, sizeof(Chipset.D)) != 0; + wsprintf(szBuffer,_T("D= %s"),RegToStr(Chipset.D,16)); + SetDlgItemText(hDlg,IDC_REG_D,szBuffer); + _ASSERTREG(IDC_REG_R0); + bRegUpdate[IDC_REG_R0-REG_START] = memcmp(Chipset.R0, OldChipset.R0, sizeof(Chipset.R0)) != 0; + wsprintf(szBuffer,_T("R0=%s"),RegToStr(Chipset.R0,16)); + SetDlgItemText(hDlg,IDC_REG_R0,szBuffer); + _ASSERTREG(IDC_REG_R1); + bRegUpdate[IDC_REG_R1-REG_START] = memcmp(Chipset.R1, OldChipset.R1, sizeof(Chipset.R1)) != 0; + wsprintf(szBuffer,_T("R1=%s"),RegToStr(Chipset.R1,16)); + SetDlgItemText(hDlg,IDC_REG_R1,szBuffer); + _ASSERTREG(IDC_REG_R2); + bRegUpdate[IDC_REG_R2-REG_START] = memcmp(Chipset.R2, OldChipset.R2, sizeof(Chipset.R2)) != 0; + wsprintf(szBuffer,_T("R2=%s"),RegToStr(Chipset.R2,16)); + SetDlgItemText(hDlg,IDC_REG_R2,szBuffer); + _ASSERTREG(IDC_REG_R3); + bRegUpdate[IDC_REG_R3-REG_START] = memcmp(Chipset.R3, OldChipset.R3, sizeof(Chipset.R3)) != 0; + wsprintf(szBuffer,_T("R3=%s"),RegToStr(Chipset.R3,16)); + SetDlgItemText(hDlg,IDC_REG_R3,szBuffer); + _ASSERTREG(IDC_REG_R4); + bRegUpdate[IDC_REG_R4-REG_START] = memcmp(Chipset.R4, OldChipset.R4, sizeof(Chipset.R4)) != 0; + wsprintf(szBuffer,_T("R4=%s"),RegToStr(Chipset.R4,16)); + SetDlgItemText(hDlg,IDC_REG_R4,szBuffer); + _ASSERTREG(IDC_REG_D0); + bRegUpdate[IDC_REG_D0-REG_START] = Chipset.d0 != OldChipset.d0; + wsprintf(szBuffer,_T("D0=%05X"),Chipset.d0); + SetDlgItemText(hDlg,IDC_REG_D0,szBuffer); + _ASSERTREG(IDC_REG_D1); + bRegUpdate[IDC_REG_D1-REG_START] = Chipset.d1 != OldChipset.d1; + wsprintf(szBuffer,_T("D1=%05X"),Chipset.d1); + SetDlgItemText(hDlg,IDC_REG_D1,szBuffer); + _ASSERTREG(IDC_REG_P); + bRegUpdate[IDC_REG_P-REG_START] = Chipset.P != OldChipset.P; + wsprintf(szBuffer,_T("P=%X"),Chipset.P); + SetDlgItemText(hDlg,IDC_REG_P,szBuffer); + _ASSERTREG(IDC_REG_PC); + bRegUpdate[IDC_REG_PC-REG_START] = Chipset.pc != OldChipset.pc; + wsprintf(szBuffer,_T("PC=%05X"),Chipset.pc); + SetDlgItemText(hDlg,IDC_REG_PC,szBuffer); + _ASSERTREG(IDC_REG_OUT); + bRegUpdate[IDC_REG_OUT-REG_START] = Chipset.out != OldChipset.out; + wsprintf(szBuffer,_T("OUT=%03X"),Chipset.out); + SetDlgItemText(hDlg,IDC_REG_OUT,szBuffer); + _ASSERTREG(IDC_REG_IN); + bRegUpdate[IDC_REG_IN-REG_START] = Chipset.in != OldChipset.in; + wsprintf(szBuffer,_T("IN=%04X"),Chipset.in); + SetDlgItemText(hDlg,IDC_REG_IN,szBuffer); + _ASSERTREG(IDC_REG_ST); + bRegUpdate[IDC_REG_ST-REG_START] = memcmp(Chipset.ST, OldChipset.ST, sizeof(Chipset.ST)) != 0; + wsprintf(szBuffer,_T("ST=%s"),RegToStr(Chipset.ST,4)); + SetDlgItemText(hDlg,IDC_REG_ST,szBuffer); + _ASSERTREG(IDC_REG_CY); + bRegUpdate[IDC_REG_CY-REG_START] = Chipset.carry != OldChipset.carry; + wsprintf(szBuffer,_T("CY=%d"),Chipset.carry); + SetDlgItemText(hDlg,IDC_REG_CY,szBuffer); + _ASSERTREG(IDC_REG_MODE); + bRegUpdate[IDC_REG_MODE-REG_START] = Chipset.mode_dec != OldChipset.mode_dec; + wsprintf(szBuffer,_T("Mode=%c"),Chipset.mode_dec ? _T('D') : _T('H')); + SetDlgItemText(hDlg,IDC_REG_MODE,szBuffer); + _ASSERTREG(IDC_REG_MP); + bRegUpdate[IDC_REG_MP-REG_START] = ((Chipset.HST ^ OldChipset.HST) & MP) != 0; + wsprintf(szBuffer,_T("MP=%d"),(Chipset.HST & MP) != 0); + SetDlgItemText(hDlg,IDC_REG_MP,szBuffer); + _ASSERTREG(IDC_REG_SR); + bRegUpdate[IDC_REG_SR-REG_START] = ((Chipset.HST ^ OldChipset.HST) & SR) != 0; + wsprintf(szBuffer,_T("SR=%d"),(Chipset.HST & SR) != 0); + SetDlgItemText(hDlg,IDC_REG_SR,szBuffer); + _ASSERTREG(IDC_REG_SB); + bRegUpdate[IDC_REG_SB-REG_START] = ((Chipset.HST ^ OldChipset.HST) & SB) != 0; + wsprintf(szBuffer,_T("SB=%d"),(Chipset.HST & SB) != 0); + SetDlgItemText(hDlg,IDC_REG_SB,szBuffer); + _ASSERTREG(IDC_REG_XM); + bRegUpdate[IDC_REG_XM-REG_START] = ((Chipset.HST ^ OldChipset.HST) & XM) != 0; + wsprintf(szBuffer,_T("XM=%d"),(Chipset.HST & XM) != 0); + SetDlgItemText(hDlg,IDC_REG_XM,szBuffer); + return; +} + +// +// update memory window +// +static VOID UpdateMemoryWnd(HWND hDlg) +{ + // check follow mode setting for memory window + switch(uIDFol) + { + case ID_DEBUG_MEM_FNONE: break; + case ID_DEBUG_MEM_FADDR: dwAdrMem = Read5(dwAdrMemFol); break; + case ID_DEBUG_MEM_FPC: dwAdrMem = Chipset.pc; break; + case ID_DEBUG_MEM_FD0: dwAdrMem = Chipset.d0; break; + case ID_DEBUG_MEM_FD1: dwAdrMem = Chipset.d1; break; + default: _ASSERT(FALSE); + } + + ViewMemWnd(hDlg,dwAdrMem); + return; +} + +// +// update stack window +// +static VOID UpdateStackWnd(HWND hDlg) +{ + UINT i; + LONG nPos; + TCHAR szBuffer[64]; + + HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK); + + SendMessage(hWnd,WM_SETREDRAW,FALSE,0); + nPos = (LONG) SendMessage(hWnd,LB_GETTOPINDEX,0,0); + SendMessage(hWnd,LB_RESETCONTENT,0,0); + for (i = 1; i <= ARRAYSIZEOF(Chipset.rstk); ++i) + { + INT j; + + wsprintf(szBuffer,_T("%d: %05X"), i, Chipset.rstk[(Chipset.rstkp-i)&7]); + j = (INT) SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); + SendMessage(hWnd,LB_SETITEMDATA,j,Chipset.rstk[(Chipset.rstkp-i)&7]); + } + SendMessage(hWnd,LB_SETTOPINDEX,nPos,0); + SendMessage(hWnd,WM_SETREDRAW,TRUE,0); + return; +} + +// +// update MMU window +// +static VOID UpdateMmuWnd(HWND hDlg) +{ + TCHAR szBuffer[64]; + + if (Chipset.IOCfig) + wsprintf(szBuffer,_T("%05X"),Chipset.IOBase); + else + lstrcpy(szBuffer,_T("-----")); + SetDlgItemText(hDlg,IDC_MMU_IO_A,szBuffer); + if (Chipset.P0Cfig) + wsprintf(szBuffer,_T("%05X"),Chipset.P0Base<<12); + else + lstrcpy(szBuffer,_T("-----")); + SetDlgItemText(hDlg,IDC_MMU_NCE2_A,szBuffer); + if (Chipset.P0Cfg2) + wsprintf(szBuffer,_T("%05X"),(Chipset.P0Size^0xFF)<<12); + else + lstrcpy(szBuffer,_T("-----")); + SetDlgItemText(hDlg,IDC_MMU_NCE2_S,szBuffer); + if (Chipset.P1Cfig) + wsprintf(szBuffer,_T("%05X"),Chipset.P1Base<<12); + else + lstrcpy(szBuffer,_T("-----")); + SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE1_A : IDC_MMU_CE2_A,szBuffer); + if (Chipset.P1Cfg2) + wsprintf(szBuffer,_T("%05X"),(Chipset.P1Size^0xFF)<<12); + else + lstrcpy(szBuffer,_T("-----")); + SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE1_S : IDC_MMU_CE2_S,szBuffer); + if (Chipset.P2Cfig) + wsprintf(szBuffer,_T("%05X"),Chipset.P2Base<<12); + else + lstrcpy(szBuffer,_T("-----")); + SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE2_A : IDC_MMU_NCE3_A,szBuffer); + if (Chipset.P2Cfg2) + wsprintf(szBuffer,_T("%05X"),(Chipset.P2Size^0xFF)<<12); + else + lstrcpy(szBuffer,_T("-----")); + SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE2_S : IDC_MMU_NCE3_S,szBuffer); + if (Chipset.BSCfig) + wsprintf(szBuffer,_T("%05X"),Chipset.BSBase<<12); + else + lstrcpy(szBuffer,_T("-----")); + SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_NCE3_A : IDC_MMU_CE1_A,szBuffer); + if (Chipset.BSCfg2) + wsprintf(szBuffer,_T("%05X"),(Chipset.BSSize^0xFF)<<12); + else + lstrcpy(szBuffer,_T("-----")); + SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_NCE3_S : IDC_MMU_CE1_S,szBuffer); + return; +} + +// +// update miscellaneous window +// +static VOID UpdateMiscWnd(HWND hDlg) +{ + _ASSERTREG(IDC_MISC_INT); + bRegUpdate[IDC_MISC_INT-REG_START] = Chipset.inte != OldChipset.inte; + SetDlgItemText(hDlg,IDC_MISC_INT,Chipset.inte ? _T("On ") : _T("Off")); + + _ASSERTREG(IDC_MISC_KEY); + bRegUpdate[IDC_MISC_KEY-REG_START] = Chipset.intk != OldChipset.intk; + SetDlgItemText(hDlg,IDC_MISC_KEY,Chipset.intk ? _T("On ") : _T("Off")); + + _ASSERTREG(IDC_MISC_BS); + bRegUpdate[IDC_MISC_BS-REG_START] = FALSE; + + // HP39/40G, HP48GX, HP49G + if (cCurrentRomType=='E' || cCurrentRomType=='G' || cCurrentRomType=='X') + { + TCHAR szBuffer[64]; + + bRegUpdate[IDC_MISC_BS-REG_START] = (Chipset.Bank_FF & 0x7F) != (OldChipset.Bank_FF & 0x7F); + wsprintf(szBuffer,_T("%02X"),Chipset.Bank_FF & 0x7F); + SetDlgItemText(hDlg,IDC_MISC_BS,szBuffer); + } + return; +} + +// +// update complete debugger dialog +// +VOID OnUpdate(HWND hDlg) +{ + nDbgState = DBG_STEPINTO; // state "step into" + dwDbgStopPC = -1; // disable "cursor stop address" + + // enable debug buttons + EnableMenuItem(GetMenu(hDlg),ID_DEBUG_RUN,MF_ENABLED); + EnableMenuItem(GetMenu(hDlg),ID_DEBUG_RUNCURSOR,MF_ENABLED); + EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEP,MF_ENABLED); + EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEPOVER,MF_ENABLED); + EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEPOUT,MF_ENABLED); + EnableMenuItem(GetMenu(hDlg),ID_INFO_LASTINSTRUCTIONS,MF_ENABLED); + EnableMenuItem(GetMenu(hDlg),ID_INFO_WRITEONLYREG,MF_ENABLED); + + // enable toolbar buttons + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUN,MAKELONG((TRUE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_BREAK,MAKELONG((FALSE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUNCURSOR,MAKELONG((TRUE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEP,MAKELONG((TRUE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOVER,MAKELONG((TRUE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOUT,MAKELONG((TRUE),0)); + + // update windows + UpdateCodeWnd(hDlg); // update code window + UpdateRegisterWnd(hDlg); // update registers window + UpdateMemoryWnd(hDlg); // update memory window + UpdateStackWnd(hDlg); // update stack window + UpdateMmuWnd(hDlg); // update MMU window + UpdateMiscWnd(hDlg); // update bank switcher window + UpdateProfileWnd(hDlgProfile); // update profiler dialog + ShowWindow(hDlg,SW_RESTORE); // pop up if minimized + SetFocus(hDlg); // set focus to debugger + return; +} + + +//################ +//# +//# Virtual key handler +//# +//################ + +// +// toggle breakpoint key handler (F2) +// +static BOOL OnKeyF2(HWND hDlg) +{ + HWND hWnd; + RECT rc; + LONG i; + + hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE); + i = (LONG) SendMessage(hWnd,LB_GETCURSEL,0,0); // get selected item + ToggleBreakpoint(dwAdrLine[i]); // toggle breakpoint at address + // update region of toggled item + SendMessage(hWnd,LB_GETITEMRECT,i,(LPARAM)&rc); + InvalidateRect(hWnd,&rc,TRUE); + return -1; // call windows default handler +} + +// +// run key handler (F5) +// +static BOOL OnKeyF5(HWND hDlg) +{ + HWND hWnd; + INT i,nPos; + TCHAR szBuf[64]; + + if (nDbgState != DBG_RUN) // emulation stopped + { + DisableMenuKeys(hDlg); // disable menu keys + + hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE); + nPos = (INT) SendMessage(hWnd,LB_GETCURSEL,0,0); + + // clear "->" in code window + for (i = 0; i < MAXCODELINES; ++i) + { + if (dwAdrLine[i] == Chipset.pc) // PC in window + { + SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuf); + szBuf[5] = szBuf[6] = _T(' '); + SendMessage(hWnd,LB_DELETESTRING,i,0); + SendMessage(hWnd,LB_INSERTSTRING,i,(LPARAM) szBuf); + break; + } + } + SendMessage(hWnd,LB_SETCURSEL,nPos,0); + + nDbgState = DBG_RUN; // state "run" + OldChipset = Chipset; // save chipset values + SetEvent(hEventDebug); // run emulation + } + return -1; // call windows default handler + UNREFERENCED_PARAMETER(hDlg); +} + +// +// step cursor key handler (F6) +// +static BOOL OnKeyF6(HWND hDlg) +{ + if (nDbgState != DBG_RUN) // emulation stopped + { + // get address of selected item + INT nPos = (INT) SendDlgItemMessage(hDlg,IDC_DEBUG_CODE,LB_GETCURSEL,0,0); + dwDbgStopPC = dwAdrLine[nPos]; + + OnKeyF5(hDlg); // run emulation + } + return -1; // call windows default handler +} + +// +// step into key handler (F7) +// +static BOOL OnKeyF7(HWND hDlg) +{ + if (nDbgState != DBG_RUN) // emulation stopped + { + if (bDbgSkipInt) // skip code in interrupt handler + DisableMenuKeys(hDlg); // disable menu keys + + nDbgState = DBG_STEPINTO; // state "step into" + OldChipset = Chipset; // save chipset values + SetEvent(hEventDebug); // run emulation + } + return -1; // call windows default handler + UNREFERENCED_PARAMETER(hDlg); +} + +// +// step over key handler (F8) +// +static BOOL OnKeyF8(HWND hDlg) +{ + if (nDbgState != DBG_RUN) // emulation stopped + { + LPBYTE I = FASTPTR(Chipset.pc); + + if (bDbgSkipInt) // skip code in interrupt handler + DisableMenuKeys(hDlg); // disable menu keys + + dwDbgRstkp = Chipset.rstkp; // save stack level + + // GOSUB 7aaa, GOSUBL 8Eaaaa, GOSBVL 8Faaaaa + if (I[0] == 0x7 || (I[0] == 0x8 && (I[1] == 0xE || I[1] == 0xF))) + { + nDbgState = DBG_STEPOVER; // state "step over" + } + else + { + nDbgState = DBG_STEPINTO; // state "step into" + } + OldChipset = Chipset; // save chipset values + SetEvent(hEventDebug); // run emulation + } + return -1; // call windows default handler + UNREFERENCED_PARAMETER(hDlg); +} + +// +// step out key handler (F9) +// +static BOOL OnKeyF9(HWND hDlg) +{ + if (nDbgState != DBG_RUN) // emulation stopped + { + DisableMenuKeys(hDlg); // disable menu keys + dwDbgRstkp = (Chipset.rstkp-1)&7; // save stack data + dwDbgRstk = Chipset.rstk[dwDbgRstkp]; + nDbgState = DBG_STEPOUT; // state "step out" + OldChipset = Chipset; // save chipset values + SetEvent(hEventDebug); // run emulation + } + return -1; // call windows default handler + UNREFERENCED_PARAMETER(hDlg); +} + +// +// break key handler (F11) +// +static BOOL OnKeyF11(HWND hDlg) +{ + nDbgState = DBG_STEPINTO; // state "step into" + if (Chipset.Shutdn) // cpu thread stopped + SetEvent(hEventShutdn); // goto debug session + return -1; // call windows default handler + UNREFERENCED_PARAMETER(hDlg); +} + +// +// view of given address in disassembler window +// +static BOOL OnCodeGoAdr(HWND hDlg) +{ + DWORD dwAddress = -1; // no address given + + OnEnterAddress(hDlg, &dwAddress); + if (dwAddress != -1) + { + HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE); + ViewCodeWnd(hWnd,dwAddress); + SendMessage(hWnd,LB_SETCURSEL,0,0); + } + return -1; // call windows default handler +} + +// +// view pc in disassembler window +// +static BOOL OnCodeGoPC(HWND hDlg) +{ + UpdateCodeWnd(hDlg); + return 0; +} + +// +// set pc to selection +// +static BOOL OnCodeSetPcToSelection(HWND hDlg) +{ + Chipset.pc = dwAdrLine[SendDlgItemMessage(hDlg,IDC_DEBUG_CODE,LB_GETCURSEL,0,0)]; + return OnCodeGoPC(hDlg); +} + +// +// find PCO object in code window +// +static BOOL OnCodeFindPCO(HWND hDlg,DWORD dwAddr,INT nSearchDir) +{ + DWORD dwCnt; + BOOL bMatch; + + // searching upwards / downwards + _ASSERT(nSearchDir == 1 || nSearchDir == -1); + + dwAddr += nSearchDir; // start address for search + + // scan mapped address area until PCO found + for (dwCnt = 0; dwCnt <= 0xFFFFF; ++dwCnt) + { + // is this a PCO? + bMatch = (Read5(dwAddr & 0xFFFFF) == ((dwAddr + 5) & 0xFFFFF)); + + if (bMatch) + { + // update code window + ViewCodeWnd(GetDlgItem(hDlg,IDC_DEBUG_CODE),dwAddr); + break; + } + + dwAddr += nSearchDir; + } + return 0; +} + +// +// view from address in memory window +// +static BOOL OnMemGoDx(HWND hDlg, DWORD dwAddress) +{ + HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_MEM_COL0); + + ViewMemWnd(hDlg, dwAddress); + SendMessage(hWnd,LB_SETCURSEL,0,0); + SetFocus(hWnd); + return -1; // call windows default handler +} + +// +// view of given address in memory window +// +static BOOL OnMemGoAdr(HWND hDlg) +{ + DWORD dwAddress = -1; // no address given + + OnEnterAddress(hDlg, &dwAddress); + if (dwAddress != -1) // not Cancel key + OnMemGoDx(hDlg,dwAddress & GetMemDataMask()); + return -1; // call windows default handler +} + +// +// view from address in memory window +// +static BOOL OnMemFollow(HWND hDlg,UINT uID) +{ + if (ID_DEBUG_MEM_FADDR == uID) // ask for follow address + { + DWORD dwAddress = -1; // no address given + + OnEnterAddress(hDlg, &dwAddress); + if (dwAddress == -1) return -1; // return at cancel button + + dwAdrMemFol = dwAddress; + } + + CheckMenuItem(hMenuMem,uIDFol,MF_UNCHECKED); + uIDFol = uID; + CheckMenuItem(hMenuMem,uIDFol,MF_CHECKED); + UpdateMemoryWnd(hDlg); // update memory window + return -1; // call windows default handler +} + +// +// clear all breakpoints +// +static BOOL OnClearAll(HWND hDlg) +{ + wBreakpointCount = 0; + // redraw code window + InvalidateRect(GetDlgItem(hDlg,IDC_DEBUG_CODE),NULL,TRUE); + return 0; +} + +// +// toggle menu selection +// +static BOOL OnToggleMenuItem(HWND hDlg,UINT uIDCheckItem,BOOL *bCheck) +{ + *bCheck = !*bCheck; // toggle flag + CheckMenuItem(GetMenu(hDlg),uIDCheckItem,*bCheck ? MF_CHECKED : MF_UNCHECKED); + return 0; +} + +// +// change memory window mapping style +// +static BOOL OnMemMapping(HWND hDlg,UINT uID) +{ + if (uID == uIDMap) return -1; // same view, call windows default handler + + SetMappingMenu(hDlg,uID); // update menu settings + UpdateMemoryWnd(hDlg); // update memory window + return 0; +} + +// +// push value on hardware stack +// +static BOOL OnStackPush(HWND hDlg) +{ + TCHAR szBuffer[] = _T("00000"); + DWORD dwAddr; + HWND hWnd; + UINT i,j; + + if (nDbgState != DBG_STEPINTO) // not in single step mode + return TRUE; + + hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK); + + i = (UINT) SendMessage(hWnd,LB_GETCURSEL,0,0); + if (LB_ERR == (INT) i) return TRUE; // no selection + + if (IDOK != OnNewValue(szBuffer)) // canceled function + return TRUE; + _stscanf(szBuffer,_T("%5X"),&dwAddr); + + // push stack element + for (j = ARRAYSIZEOF(Chipset.rstk); j > i + 1; --j) + { + Chipset.rstk[(Chipset.rstkp-j)&7] = Chipset.rstk[(Chipset.rstkp-j+1)&7]; + } + Chipset.rstk[(Chipset.rstkp-j)&7] = dwAddr; + + UpdateStackWnd(hDlg); // update stack window + SendMessage(hWnd,LB_SETCURSEL,i,0); // restore cursor postion + return 0; +} + +// +// pop value from hardware stack +// +static BOOL OnStackPop(HWND hDlg) +{ + HWND hWnd; + UINT i,j; + + if (nDbgState != DBG_STEPINTO) // not in single step mode + return TRUE; + + hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK); + + i = (UINT) SendMessage(hWnd,LB_GETCURSEL,0,0); + if (LB_ERR == (INT) i) return TRUE; // no selection + + // pop stack element + for (j = i + 1; j < ARRAYSIZEOF(Chipset.rstk); ++j) + { + Chipset.rstk[(Chipset.rstkp-j)&7] = Chipset.rstk[(Chipset.rstkp-j-1)&7]; + } + Chipset.rstk[Chipset.rstkp] = 0; + + UpdateStackWnd(hDlg); // update stack window + SendMessage(hWnd,LB_SETCURSEL,i,0); // restore cursor postion + return 0; +} + +// modify value on hardware stack +static BOOL OnStackModify(HWND hDlg) +{ + TCHAR szBuffer[16]; + HWND hWnd; + INT i; + + if (nDbgState != DBG_STEPINTO) // not in single step mode + return TRUE; + + hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK); + + i = (INT) SendMessage(hWnd,LB_GETCURSEL,0,0); + if (LB_ERR == i) return TRUE; // no selection + + SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuffer); + OnNewValue(&szBuffer[3]); + _stscanf(&szBuffer[3],_T("%5X"),&Chipset.rstk[(Chipset.rstkp-i-1)&7]); + + UpdateStackWnd(hDlg); // update stack window + SendMessage(hWnd,LB_SETCURSEL,i,0); // restore cursor postion + return 0; +} + +// +// new register setting +// +static BOOL OnLButtonUp(HWND hDlg, LPARAM lParam) +{ + TCHAR szBuffer[64]; + POINT pt; + HWND hWnd; + INT nId; + + if (nDbgState != DBG_STEPINTO) // not in single step mode + return TRUE; + + POINTSTOPOINT(pt,MAKEPOINTS(lParam)); + + // handle of selected window + hWnd = ChildWindowFromPointEx(hDlg,pt,CWP_SKIPDISABLED); + nId = GetDlgCtrlID(hWnd); // control ID of window + + GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer)); + switch (nId) + { + case IDC_REG_A: // A + OnNewValue(&szBuffer[3]); + StrToReg(Chipset.A,16,&szBuffer[3]); + break; + case IDC_REG_B: // B + OnNewValue(&szBuffer[3]); + StrToReg(Chipset.B,16,&szBuffer[3]); + break; + case IDC_REG_C: // C + OnNewValue(&szBuffer[3]); + StrToReg(Chipset.C,16,&szBuffer[3]); + break; + case IDC_REG_D: // D + OnNewValue(&szBuffer[3]); + StrToReg(Chipset.D,16,&szBuffer[3]); + break; + case IDC_REG_R0: // R0 + OnNewValue(&szBuffer[3]); + StrToReg(Chipset.R0,16,&szBuffer[3]); + break; + case IDC_REG_R1: // R1 + OnNewValue(&szBuffer[3]); + StrToReg(Chipset.R1,16,&szBuffer[3]); + break; + case IDC_REG_R2: // R2 + OnNewValue(&szBuffer[3]); + StrToReg(Chipset.R2,16,&szBuffer[3]); + break; + case IDC_REG_R3: // R3 + OnNewValue(&szBuffer[3]); + StrToReg(Chipset.R3,16,&szBuffer[3]); + break; + case IDC_REG_R4: // R4 + OnNewValue(&szBuffer[3]); + StrToReg(Chipset.R4,16,&szBuffer[3]); + break; + case IDC_REG_D0: // D0 + OnNewValue(&szBuffer[3]); + _stscanf(&szBuffer[3],_T("%5X"),&Chipset.d0); + break; + case IDC_REG_D1: // D1 + OnNewValue(&szBuffer[3]); + _stscanf(&szBuffer[3],_T("%5X"),&Chipset.d1); + break; + case IDC_REG_P: // P + OnNewValue(&szBuffer[2]); + Chipset.P = _totupper(szBuffer[2]) - _T('0'); + if (Chipset.P > 9) Chipset.P -= 7; + PCHANGED; + break; + case IDC_REG_PC: // PC + OnNewValue(&szBuffer[3]); + _stscanf(&szBuffer[3],_T("%5X"),&Chipset.pc); + break; + case IDC_REG_OUT: // OUT + OnNewValue(&szBuffer[4]); + Chipset.out = (WORD) _tcstoul(&szBuffer[4],NULL,16); + break; + case IDC_REG_IN: // IN + OnNewValue(&szBuffer[3]); + Chipset.in = (WORD) _tcstoul(&szBuffer[3],NULL,16); + break; + case IDC_REG_ST: // ST + OnNewValue(&szBuffer[3]); + StrToReg(Chipset.ST,4,&szBuffer[3]); + break; + case IDC_REG_CY: // CY + Chipset.carry = !Chipset.carry; + break; + case IDC_REG_MODE: // MODE + Chipset.mode_dec = !Chipset.mode_dec; + break; + case IDC_REG_MP: // MP + Chipset.HST ^= MP; + break; + case IDC_REG_SR: // SR + Chipset.HST ^= SR; + break; + case IDC_REG_SB: // SB + Chipset.HST ^= SB; + break; + case IDC_REG_XM: // XM + Chipset.HST ^= XM; + break; + case IDC_MISC_INT: // interrupt status + Chipset.inte = !Chipset.inte; + UpdateMiscWnd(hDlg); // update miscellaneous window + break; + case IDC_MISC_KEY: // 1ms keyboard scan + Chipset.intk = !Chipset.intk; + UpdateMiscWnd(hDlg); // update miscellaneous window + break; + case IDC_MISC_BS: // Bank switcher setting + OnNewValue(szBuffer); + Chipset.Bank_FF = _tcstoul(szBuffer,NULL,16); + Chipset.Bank_FF &= 0x7F; + RomSwitch(Chipset.Bank_FF); // update memory mapping + + UpdateCodeWnd(hDlg); // update code window + UpdateMemoryWnd(hDlg); // update memory window + UpdateMiscWnd(hDlg); // update miscellaneous window + break; + } + UpdateRegisterWnd(hDlg); // update register + return TRUE; +} + +// +// double click in list box area +// +static BOOL OnDblClick(HWND hWnd, WORD wId) +{ + HWND hDlg,hWndCode; + TCHAR szBuffer[4]; + BYTE byData; + INT i; + DWORD dwAddress; + + hDlg = GetParent(hWnd); // dialog window handle + hWndCode = GetDlgItem(hDlg,IDC_DEBUG_CODE); + + if (wId == IDC_DEBUG_STACK) // stack list box + { + // get cpu address of selected item + i = (INT) SendMessage(hWnd,LB_GETCURSEL,0,0); + dwAddress = (DWORD) SendMessage(hWnd,LB_GETITEMDATA,i,0); + + ViewCodeWnd(hWndCode,dwAddress); // show code of this address + return TRUE; + } + + for (i = 0; i < MEMWNDMAX; ++i) // scan all Id's + if (nCol[i] == wId) // found ID + break; + + // not IDC_DEBUG_MEM window or module mode -> default handler + if (i == MEMWNDMAX || ID_DEBUG_MEM_MAP != uIDMap) + return FALSE; + + // calculate address of byte + dwAddress = i * 2; + i = (INT) SendMessage(hWnd,LB_GETCARETINDEX,0,0); + dwAddress += MAXMEMITEMS * i + dwAdrMem; + + // enter new value + SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuffer); + OnNewValue(szBuffer); + byData = (BYTE) _tcstoul(szBuffer,NULL,16); + byData = (byData >> 4) | (byData << 4); // change nibbles for writing + + Write2(dwAddress,byData); // write data + ViewCodeWnd(hWndCode,dwAdrLine[0]); // update code window + ViewMemWnd(hDlg,dwAdrMem); // update memory window + SendMessage(hWnd,LB_SETCURSEL,i,0); + return FALSE; +} + +// +// request for context menu +// +static VOID OnContextMenu(HWND hDlg, LPARAM lParam, WPARAM wParam) +{ + POINT pt; + INT nId; + + POINTSTOPOINT(pt,MAKEPOINTS(lParam)); // mouse position + + if (pt.x == -1 && pt.y == -1) // VK_APPS + { + RECT rc; + + GetWindowRect((HWND) wParam,&rc); // get position of active window + pt.x = rc.left + 5; + pt.y = rc.top + 5; + } + + nId = GetDlgCtrlID((HWND) wParam); // control ID of window + + switch(nId) + { + case IDC_DEBUG_CODE: // handle code window + TrackPopupMenu(hMenuCode,0,pt.x,pt.y,0,hDlg,NULL); + break; + + case IDC_DEBUG_MEM_COL0: + case IDC_DEBUG_MEM_COL1: + case IDC_DEBUG_MEM_COL2: + case IDC_DEBUG_MEM_COL3: + case IDC_DEBUG_MEM_COL4: + case IDC_DEBUG_MEM_COL5: + case IDC_DEBUG_MEM_COL6: + case IDC_DEBUG_MEM_COL7: // handle memory window + TrackPopupMenu(hMenuMem,0,pt.x,pt.y,0,hDlg,NULL); + break; + + case IDC_DEBUG_STACK: // handle stack window + TrackPopupMenu(hMenuStack,0,pt.x,pt.y,0,hDlg,NULL); + break; + } + return; +} + +// +// mouse setting for capturing window +// +static BOOL OnSetCursor(HWND hDlg) +{ + // debugger not active but cursor is over debugger window + if (bActFollowsMouse && GetActiveWindow() != hDlg) + { + // force debugger window to foreground + ForceForegroundWindow(GetLastActivePopup(hDlg)); + } + return FALSE; +} + +//################ +//# +//# Dialog handler +//# +//################ + +// +// handle right/left keys in memory window +// +static __inline BOOL OnKeyRightLeft(HWND hWnd, WPARAM wParam) +{ + HWND hWndNew; + WORD wX; + INT nId; + + nId = GetDlgCtrlID(hWnd); // control ID of window + + for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's + if (nCol[wX] == nId) // found ID + break; + + if (wX == MEMWNDMAX) return -1; // not IDC_DEBUG_MEM window, default handler + + // new position + wX = ((LOWORD(wParam) == VK_RIGHT) ? (wX + 1) : (wX + MEMWNDMAX - 1)) % MEMWNDMAX; + + // set new focus + hWndNew = GetDlgItem(GetParent(hWnd),nCol[wX]); + SendMessage(hWndNew,LB_SETCURSEL,HIWORD(wParam),0); + SetFocus(hWndNew); + return -2; +} + +// +// handle (page) up/down keys in memory window +// +static __inline BOOL OnKeyUpDown(HWND hWnd, WPARAM wParam) +{ + INT wX, wY; + INT nId; + + nId = GetDlgCtrlID(hWnd); // control ID of window + + for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's + if (nCol[wX] == nId) // found ID + break; + + if (wX == MEMWNDMAX) return -1; // not IDC_DEBUG_MEM window, default handler + + wY = HIWORD(wParam); // get old focus + + switch(LOWORD(wParam)) + { + case VK_NEXT: + dwAdrMem = (dwAdrMem + MAXMEMITEMS * MAXMEMLINES) & GetMemDataMask(); + ViewMemWnd(GetParent(hWnd),dwAdrMem); + SendMessage(hWnd,LB_SETCURSEL,wY,0); + return -2; + + case VK_PRIOR: + dwAdrMem = (dwAdrMem - MAXMEMITEMS * MAXMEMLINES) & GetMemDataMask(); + ViewMemWnd(GetParent(hWnd),dwAdrMem); + SendMessage(hWnd,LB_SETCURSEL,wY,0); + return -2; + + case VK_DOWN: + if (wY+1 >= MAXMEMLINES) + { + dwAdrMem = (dwAdrMem + MAXMEMITEMS) & GetMemDataMask(); + ViewMemWnd(GetParent(hWnd),dwAdrMem); + SendMessage(hWnd,LB_SETCURSEL,wY,0); + return -2; + } + break; + + case VK_UP: + if (wY == 0) + { + dwAdrMem = (dwAdrMem - MAXMEMITEMS) & GetMemDataMask(); + ViewMemWnd(GetParent(hWnd),dwAdrMem); + SendMessage(hWnd,LB_SETCURSEL,wY,0); + return -2; + } + break; + } + return -1; +} + +// +// handle (page) +/- keys in memory window +// +static __inline BOOL OnKeyPlusMinus(HWND hWnd, WPARAM wParam) +{ + INT wX, wY; + INT nId; + + nId = GetDlgCtrlID(hWnd); // control ID of window + + for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's + if (nCol[wX] == nId) // found ID + break; + + if (wX == MEMWNDMAX) return -1; // not IDC_DEBUG_MEM window, default handler + + wY = HIWORD(wParam); // get focus + + if (LOWORD(wParam) == VK_ADD) // move start address of memory view + dwAdrMem++; + else + dwAdrMem--; + dwAdrMem &= GetMemDataMask(); + + ViewMemWnd(GetParent(hWnd),dwAdrMem); // redraw memory view + SendMessage(hWnd,LB_SETCURSEL,wY,0); // set focus at old position + return -1; +} + +// +// handle keys in code window +// +static __inline BOOL OnKeyCodeWnd(HWND hDlg, WPARAM wParam) +{ + HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE); + WORD wKey = LOWORD(wParam); + WORD wItem = HIWORD(wParam); + + // down key on last line + if ((wKey == VK_DOWN || wKey == VK_NEXT) && wItem == MAXCODELINES - 1) + { + WORD i = ((dwAdrLine[0] & CODELABEL) != 0) ? 2 : 1; + + ViewCodeWnd(hWnd,dwAdrLine[i]); + SendMessage(hWnd,LB_SETCURSEL,wItem-i,0); + } + // up key on first line + if ((wKey == VK_UP || wKey == VK_PRIOR) && wItem == 0) + { + ViewCodeWnd(hWnd,dwAdrLine[0]-1); + } + + if (wKey == _T('G')) return OnCodeGoAdr(GetParent(hWnd)); // goto new address + + return -1; // process key +} + +// +// handle drawing in code window +// +static __inline BOOL OnDrawCodeWnd(LPDRAWITEMSTRUCT lpdis) +{ + TCHAR szBuf[64]; + COLORREF crBkColor; + COLORREF crTextColor; + HFONT hFont; + BOOL bBrk,bPC,bLabel; + + if (lpdis->itemID == -1) // no item in list box + return TRUE; + + // get item text + SendMessage(lpdis->hwndItem,LB_GETTEXT,lpdis->itemID,(LPARAM) szBuf); + + // line is a label + bLabel = ((dwAdrLine[lpdis->itemID] & CODELABEL) != 0); + + if (!bLabel) + { + // check for codebreakpoint + bBrk = CheckBreakpoint(dwAdrLine[lpdis->itemID],1,BP_EXEC); + bPC = szBuf[5] != _T(' '); // check if line of program counter + + crTextColor = COLOR_WHITE; // standard text color + + if (lpdis->itemState & ODS_SELECTED) // cursor line + { + if (bPC) // PC line + { + crBkColor = bBrk ? COLOR_DKGRAY : COLOR_TEAL; + } + else // normal line + { + crBkColor = bBrk ? COLOR_PURPLE : COLOR_NAVY; + } + } + else // not cursor line + { + if (bPC) // PC line + { + crBkColor = bBrk ? COLOR_OLIVE : COLOR_GREEN; + } + else // normal line + { + if (bBrk) + { + crBkColor = COLOR_MAROON; + } + else + { + crBkColor = COLOR_WHITE; + crTextColor = COLOR_BLACK; + } + } + } + } + else // label + { + crBkColor = COLOR_WHITE; + crTextColor = COLOR_NAVY; + hFont = (HFONT) SelectObject(lpdis->hDC,hFontBold); + } + + // write Text + crBkColor = SetBkColor(lpdis->hDC,crBkColor); + crTextColor = SetTextColor(lpdis->hDC,crTextColor); + + ExtTextOut(lpdis->hDC,(int)(lpdis->rcItem.left)+2,(int)(lpdis->rcItem.top), + ETO_OPAQUE,(LPRECT)&lpdis->rcItem,szBuf,lstrlen(szBuf),NULL); + + SetBkColor(lpdis->hDC,crBkColor); + SetTextColor(lpdis->hDC,crTextColor); + + if (bLabel) SelectObject(lpdis->hDC,hFont); + + if (lpdis->itemState & ODS_FOCUS) // redraw focus + DrawFocusRect(lpdis->hDC,&lpdis->rcItem); + + return TRUE; // focus handled here +} + +// +// detect changed register +// +static __inline BOOL OnCtlColorStatic(HWND hWnd) +{ + BOOL bError = FALSE; // not changed + + int nId = GetDlgCtrlID(hWnd); + if (nId >= REG_START && nId <= REG_STOP) // in register area + bError = bRegUpdate[nId-REG_START]; // register changed? + return bError; +} + + +//################ +//# +//# Public functions +//# +//################ + +// +// handle upper 32 bit of cpu cycle counter +// +VOID UpdateDbgCycleCounter(VOID) +{ + // update 64 bit cpu cycle counter + if (Chipset.cycles < dwDbgRefCycles) ++Chipset.cycles_reserved; + dwDbgRefCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF); + return; +} + +// +// check for breakpoints +// +BOOL CheckBreakpoint(DWORD dwAddr, DWORD dwRange, UINT nType) +{ + INT i; + + for (i = 0; i < wBreakpointCount; ++i) // scan all breakpoints + { + // check address range and type + if ( sBreakpoint[i].bEnable + && sBreakpoint[i].dwAddr >= dwAddr && sBreakpoint[i].dwAddr < dwAddr + dwRange + && (sBreakpoint[i].nType & nType) != 0) + return TRUE; + } + return FALSE; +} + +// +// notify debugger that emulation stopped +// +VOID NotifyDebugger(INT nType) // update registers +{ + nRplBreak = nType; // save breakpoint type + FlushTrace(); // flush trace buffer + _ASSERT(hDlgDebug); // debug dialog box open + PostMessage(hDlgDebug,WM_UPDATE,0,0); + return; +} + +// +// disable debugger +// +VOID DisableDebugger(VOID) +{ + if (hDlgDebug) // debugger running + DestroyWindow(hDlgDebug); // then close debugger to renter emulation + return; +} + + +//################ +//# +//# Debugger Message loop +//# +//################ + +// +// ID_TOOL_DEBUG +// +static __inline HWND CreateToolbar(HWND hWnd) +{ + HRSRC hRes; + HGLOBAL hGlobal; + CToolBarData *pData; + TBBUTTON *ptbb; + INT i,j; + + HWND hWndToolbar = NULL; // toolbar window + + InitCommonControls(); // ensure that common control DLL is loaded + + if ((hRes = FindResource(hApp,MAKEINTRESOURCE(IDR_DEBUG_TOOLBAR),RT_TOOLBAR)) == NULL) + goto quit; + + if ((hGlobal = LoadResource(hApp,hRes)) == NULL) + goto quit; + + if ((pData = (CToolBarData*) LockResource(hGlobal)) == NULL) + goto unlock; + + _ASSERT(pData->wVersion == 1); // toolbar resource version + + // alloc memory for TBBUTTON stucture + if (!(ptbb = (TBBUTTON *) malloc(pData->wItemCount*sizeof(TBBUTTON)))) + goto unlock; + + // fill TBBUTTON stucture with resource data + for (i = j = 0; i < pData->wItemCount; ++i) + { + if (pData->aItems[i]) + { + ptbb[i].iBitmap = j++; + ptbb[i].fsStyle = TBSTYLE_BUTTON; + } + else + { + ptbb[i].iBitmap = 5; // separator width + ptbb[i].fsStyle = TBSTYLE_SEP; + } + ptbb[i].idCommand = pData->aItems[i]; + ptbb[i].fsState = TBSTATE_ENABLED; + ptbb[i].dwData = 0; + ptbb[i].iString = j; + } + + hWndToolbar = CreateToolbarEx(hWnd,WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS, + IDR_DEBUG_TOOLBAR,j,hApp,IDR_DEBUG_TOOLBAR,ptbb,pData->wItemCount, + pData->wWidth,pData->wHeight,pData->wWidth,pData->wHeight, + sizeof(TBBUTTON)); + + free(ptbb); + +unlock: + FreeResource(hGlobal); +quit: + return hWndToolbar; +} + +static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + static HMENU hMenuMainCode,hMenuMainMem,hMenuMainStack; + + WINDOWPLACEMENT wndpl; + TEXTMETRIC tm; + HDC hDC; + HFONT hFont; + HMENU hSysMenu; + HMENU hDbgMenu; + INT i; + + switch (message) + { + case WM_INITDIALOG: + if (nDbgPosX != CW_USEDEFAULT) // not default window position + { + SetWindowLocation(hDlg,nDbgPosX,nDbgPosY); + } + if (bAlwaysOnTop) SetWindowPos(hDlg,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); + SendMessage(hDlg,WM_SETICON,ICON_BIG,(LPARAM) LoadIcon(hApp,MAKEINTRESOURCE(IDI_EMU48))); + + bDbgTrace = FALSE; // disable file trace + + // load file trace settings + ReadSettingsString(_T("Debugger"),_T("TraceFile"),szTraceFilename,szTraceFilename,ARRAYSIZEOF(szTraceFilename)); + uTraceMode = ReadSettingsInt(_T("Debugger"),_T("TraceFileMode"),uTraceMode); + bTraceReg = ReadSettingsInt(_T("Debugger"),_T("TraceRegister"),bTraceReg); + bTraceMmu = ReadSettingsInt(_T("Debugger"),_T("TraceMMU"),bTraceMmu); + bTraceOpc = ReadSettingsInt(_T("Debugger"),_T("TraceOpcode"),bTraceOpc); + + // add Settings item to sysmenu + _ASSERT((IDM_DEBUG_SETTINGS & 0xFFF0) == IDM_DEBUG_SETTINGS); + _ASSERT(IDM_DEBUG_SETTINGS < 0xF000); + if ((hSysMenu = GetSystemMenu(hDlg,FALSE)) != NULL) + { + VERIFY(AppendMenu(hSysMenu,MF_SEPARATOR,0,NULL)); + VERIFY(AppendMenu(hSysMenu,MF_STRING,IDM_DEBUG_SETTINGS,_T("Debugger Settings..."))); + } + + hDbgMenu = GetMenu(hDlg); // menu of debugger dialog + hWndToolbar = CreateToolbar(hDlg); // add toolbar + + CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_NOP3, bDbgNOP3 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_DOCODE,bDbgCode ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_RPL, bDbgRPL ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hDbgMenu,ID_INTR_STEPOVERINT, bDbgSkipInt ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hDbgMenu,ID_TRACE_ENABLE, bDbgTrace ? MF_CHECKED : MF_UNCHECKED); + + EnableMenuItem(hDbgMenu,ID_TRACE_SETTINGS,bDbgTrace ? MF_GRAYED : MF_ENABLED); + + hDlgDebug = hDlg; // handle for debugger dialog + hEventDebug = CreateEvent(NULL,FALSE,FALSE,NULL); + if (hEventDebug == NULL) + { + AbortMessage(_T("Event creation failed !")); + return TRUE; + } + hMenuMainCode = LoadMenu(hApp,MAKEINTRESOURCE(IDR_DEBUG_CODE)); + _ASSERT(hMenuMainCode); + hMenuCode = GetSubMenu(hMenuMainCode, 0); + _ASSERT(hMenuCode); + hMenuMainMem = LoadMenu(hApp,MAKEINTRESOURCE(IDR_DEBUG_MEM)); + _ASSERT(hMenuMainMem); + hMenuMem = GetSubMenu(hMenuMainMem, 0); + _ASSERT(hMenuMem); + hMenuMainStack = LoadMenu(hApp,MAKEINTRESOURCE(IDR_DEBUG_STACK)); + _ASSERT(hMenuMainStack); + hMenuStack = GetSubMenu(hMenuMainStack, 0); + _ASSERT(hMenuStack); + + // bold font for symbol labels in code window + hDC = GetDC(hDlg); + VERIFY(hFontBold = CreateFont(-MulDiv(8,GetDeviceCaps(hDC,LOGPIXELSY),72),0,0,0,FW_BOLD,0,0,0,ANSI_CHARSET, + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Arial"))); + ReleaseDC(hDlg,hDC); + + // font settings + SendDlgItemMessage(hDlg,IDC_STATIC_CODE, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_STATIC_REGISTERS,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_STATIC_MEMORY, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_STATIC_STACK, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_STATIC_MMU, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_STATIC_MISC, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + + // init last instruction circular buffer + pdwInstrArray = (DWORD *) malloc(wInstrSize*sizeof(*pdwInstrArray)); + wInstrWp = wInstrRp = 0; // write/read pointer + + // init "Follow" menu entry in debugger "Memory" context menu + CheckMenuItem(hMenuMem,uIDFol,MF_CHECKED); + + LoadSymbTable(); // load external rpl symbol table + + InitMemMap(hDlg); // init memory mapping table + InitBsArea(hDlg); // init bank switcher list box + DisableMenuKeys(hDlg); // set debug menu keys into run state + + fnOutTrace = OutTrace; // function for file trace + RplReadNibble = GetMemNib; // get nibble function for RPL object viewer + + dwDbgStopPC = -1; // no stop address for goto cursor + dwDbgRplPC = -1; // no stop address for RPL breakpoint + + // init reference cpu cycle counter for 64 bit debug cycle counter + dwDbgRefCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF); + + nDbgState = DBG_STEPINTO; // state "step into" + if (Chipset.Shutdn) // cpu thread stopped + SetEvent(hEventShutdn); // goto debug session + + OldChipset = Chipset; // save chipset values + return TRUE; + + case WM_DESTROY: + // SetHP48Time(); // update time & date + nDbgState = DBG_OFF; // debugger inactive + StopTrace(); // finish trace + bInterrupt = TRUE; // exit opcode loop + SetEvent(hEventDebug); + if (pdwInstrArray) // free last instruction circular buffer + { + EnterCriticalSection(&csDbgLock); + { + free(pdwInstrArray); + pdwInstrArray = NULL; + } + LeaveCriticalSection(&csDbgLock); + } + CloseHandle(hEventDebug); + wndpl.length = sizeof(wndpl); // save debugger window position + GetWindowPlacement(hDlg, &wndpl); + nDbgPosX = wndpl.rcNormalPosition.left; + nDbgPosY = wndpl.rcNormalPosition.top; + + // save file trace settings + WriteSettingsString(_T("Debugger"),_T("TraceFile"),szTraceFilename); + WriteSettingsInt(_T("Debugger"),_T("TraceFileMode"),uTraceMode); + WriteSettingsInt(_T("Debugger"),_T("TraceRegister"),bTraceReg); + WriteSettingsInt(_T("Debugger"),_T("TraceMMU"),bTraceMmu); + WriteSettingsInt(_T("Debugger"),_T("TraceOpcode"),bTraceOpc); + + RplDeleteTable(); // delete rpl symbol table + DeleteObject(hFontBold); // delete bold font + DestroyMenu(hMenuMainCode); + DestroyMenu(hMenuMainMem); + DestroyMenu(hMenuMainStack); + hDlgDebug = NULL; // debugger windows closed + break; + + case WM_CLOSE: + DestroyWindow(hDlg); + break; + + case WM_UPDATE: + OnUpdate(hDlg); + return TRUE; + + case WM_SYSCOMMAND: + if ((wParam & 0xFFF0) == IDM_DEBUG_SETTINGS) + { + return OnSettings(hDlg); + } + break; + + case WM_COMMAND: + switch (HIWORD(wParam)) + { + case LBN_DBLCLK: + return OnDblClick((HWND) lParam, LOWORD(wParam)); + + case LBN_SETFOCUS: + i = (INT) SendMessage((HWND) lParam,LB_GETCARETINDEX,0,0); + SendMessage((HWND) lParam,LB_SETCURSEL,i,0); + return TRUE; + + case LBN_KILLFOCUS: + SendMessage((HWND) lParam,LB_SETCURSEL,-1,0); + return TRUE; + } + + switch (LOWORD(wParam)) + { + case ID_BREAKPOINTS_SETBREAK: return OnKeyF2(hDlg); + case ID_DEBUG_RUN: return OnKeyF5(hDlg); + case ID_DEBUG_RUNCURSOR: return OnKeyF6(hDlg); + case ID_DEBUG_STEP: return OnKeyF7(hDlg); + case ID_DEBUG_STEPOVER: return OnKeyF8(hDlg); + case ID_DEBUG_STEPOUT: return OnKeyF9(hDlg); + case ID_DEBUG_BREAK: return OnKeyF11(hDlg); + case ID_DEBUG_CODE_GOADR: return OnCodeGoAdr(hDlg); + case ID_DEBUG_CODE_GOPC: return OnCodeGoPC(hDlg); + case ID_DEBUG_CODE_SETPCTOSELECT: return OnCodeSetPcToSelection(hDlg); + case ID_DEBUG_CODE_PREVPCO: return OnCodeFindPCO(hDlg,dwAdrLine[0],-1); + case ID_DEBUG_CODE_NEXTPCO: return OnCodeFindPCO(hDlg,dwAdrLine[0],1); + case ID_BREAKPOINTS_CODEEDIT: return OnEditBreakpoint(hDlg); + case ID_BREAKPOINTS_CLEARALL: return OnClearAll(hDlg); + case ID_BREAKPOINTS_NOP3: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgNOP3); + case ID_BREAKPOINTS_DOCODE: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgCode); + case ID_BREAKPOINTS_RPL: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgRPL); + case ID_TRACE_SETTINGS: return OnTraceSettings(hDlg); + case ID_TRACE_ENABLE: return OnTraceEnable(hDlg); + case ID_INFO_LASTINSTRUCTIONS: return OnInfoIntr(hDlg); + case ID_INFO_PROFILE: return OnProfile(hDlg); + case ID_INFO_WRITEONLYREG: return OnInfoWoRegister(hDlg); + case ID_INTR_STEPOVERINT: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgSkipInt); + case ID_DEBUG_MEM_GOADR: return OnMemGoAdr(hDlg); + case ID_DEBUG_MEM_GOPC: return OnMemGoDx(hDlg,Chipset.pc); + case ID_DEBUG_MEM_GOD0: return OnMemGoDx(hDlg,Chipset.d0); + case ID_DEBUG_MEM_GOD1: return OnMemGoDx(hDlg,Chipset.d1); + case ID_DEBUG_MEM_GOSTACK: return OnMemGoDx(hDlg,Chipset.rstk[(Chipset.rstkp-1)&7]); + case ID_DEBUG_MEM_FNONE: + case ID_DEBUG_MEM_FADDR: + case ID_DEBUG_MEM_FPC: + case ID_DEBUG_MEM_FD0: + case ID_DEBUG_MEM_FD1: return OnMemFollow(hDlg,LOWORD(wParam)); + case ID_DEBUG_MEM_FIND: return OnMemFind(hDlg); + case ID_DEBUG_MEM_MAP: + case ID_DEBUG_MEM_NCE1: + case ID_DEBUG_MEM_NCE2: + case ID_DEBUG_MEM_CE1: + case ID_DEBUG_MEM_CE2: + case ID_DEBUG_MEM_NCE3: return OnMemMapping(hDlg,LOWORD(wParam)); + case ID_DEBUG_MEM_LOAD: return OnMemLoadData(hDlg); + case ID_DEBUG_MEM_SAVE: return OnMemSaveData(hDlg); + case ID_DEBUG_MEM_RPLVIEW: return OnRplObjView(hDlg); + case ID_DEBUG_STACK_PUSH: return OnStackPush(hDlg); + case ID_DEBUG_STACK_POP: return OnStackPop(hDlg); + case ID_DEBUG_STACK_MODIFY: return OnStackModify(hDlg); + case ID_DEBUG_CANCEL: DestroyWindow(hDlg); return TRUE; + } + break; + + case WM_VKEYTOITEM: + switch (LOWORD(wParam)) // always valid + { + case VK_F2: return OnKeyF2(hDlg); // toggle breakpoint + case VK_F5: return OnKeyF5(hDlg); // key run + case VK_F6: return OnKeyF6(hDlg); // key step cursor + case VK_F7: return OnKeyF7(hDlg); // key step into + case VK_F8: return OnKeyF8(hDlg); // key step over + case VK_F9: return OnKeyF9(hDlg); // key step out + case VK_F11: return OnKeyF11(hDlg); // key break + } + + switch(GetDlgCtrlID((HWND) lParam)) // calling window + { + // handle code window + case IDC_DEBUG_CODE: + return OnKeyCodeWnd(hDlg, wParam); + + // handle memory window + case IDC_DEBUG_MEM_COL0: + case IDC_DEBUG_MEM_COL1: + case IDC_DEBUG_MEM_COL2: + case IDC_DEBUG_MEM_COL3: + case IDC_DEBUG_MEM_COL4: + case IDC_DEBUG_MEM_COL5: + case IDC_DEBUG_MEM_COL6: + case IDC_DEBUG_MEM_COL7: + switch (LOWORD(wParam)) + { + case _T('G'): return OnMemGoAdr(GetParent((HWND) lParam)); + case _T('F'): return OnMemFind(GetParent((HWND) lParam)); + case VK_RIGHT: + case VK_LEFT: return OnKeyRightLeft((HWND) lParam, wParam); + case VK_NEXT: + case VK_PRIOR: + case VK_DOWN: + case VK_UP: return OnKeyUpDown((HWND) lParam, wParam); + case VK_ADD: + case VK_SUBTRACT: return OnKeyPlusMinus((HWND) lParam, wParam); + } + break; + } + return -1; // default action + + case WM_LBUTTONUP: + return OnLButtonUp(hDlg, lParam); + + case WM_CONTEXTMENU: + OnContextMenu(hDlg, lParam, wParam); + break; + + case WM_SETCURSOR: + return OnSetCursor(hDlg); + + case WM_CTLCOLORSTATIC: // register color highlighting + // highlight text? + if (OnCtlColorStatic((HWND) lParam)) + { + SetTextColor((HDC) wParam, COLOR_RED); + SetBkColor((HDC) wParam, GetSysColor(COLOR_BTNFACE)); + return (INT_PTR) GetStockObject(NULL_BRUSH); // transparent brush + } + break; + + case WM_NOTIFY: + // tooltip for toolbar + if (((LPNMHDR) lParam)->code == TTN_GETDISPINFO) + { + ((LPTOOLTIPTEXT) lParam)->hinst = hApp; + ((LPTOOLTIPTEXT) lParam)->lpszText = MAKEINTRESOURCE(((LPTOOLTIPTEXT) lParam)->hdr.idFrom); + break; + } + break; + + case WM_DRAWITEM: + if (wParam == IDC_DEBUG_CODE) return OnDrawCodeWnd((LPDRAWITEMSTRUCT) lParam); + break; + + case WM_MEASUREITEM: + hDC = GetDC(hDlg); + + // GetTextMetrics from "Courier New 8" font + hFont = CreateFont(-MulDiv(8,GetDeviceCaps(hDC, LOGPIXELSY),72),0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Courier New")); + + hFont = (HFONT) SelectObject(hDC,hFont); + GetTextMetrics(hDC,&tm); + hFont = (HFONT) SelectObject(hDC,hFont); + DeleteObject(hFont); + + ((LPMEASUREITEMSTRUCT) lParam)->itemHeight = tm.tmHeight; + lCharWidth = tm.tmAveCharWidth; + + ReleaseDC(hDlg,hDC); + return TRUE; + } + return FALSE; +} + +LRESULT OnToolDebug(VOID) // debugger dialogbox call +{ + if ((hDlgDebug = CreateDialog(hApp,MAKEINTRESOURCE(IDD_DEBUG),hWnd, + (DLGPROC)Debugger)) == NULL) + AbortMessage(_T("Debugger Dialog Box Creation Error !")); + return 0; +} + + +//################ +//# +//# Find dialog box +//# +//################ + +static __inline BOOL OnFindOK(HWND hDlg,BOOL bASCII,DWORD *pdwAddrLast,INT nSearchDir) +{ + HWND hWnd; + BYTE *lpbySearch; + INT i,j; + DWORD dwCnt,dwAddr,dwMapDataMask; + BOOL bMatch; + + // searching upwards / downwards + _ASSERT(nSearchDir == 1 || nSearchDir == -1); + + hWnd = GetDlgItem(hDlg,IDC_FIND_DATA); + + dwMapDataMask = GetMemDataMask(); // size mask of data mapping + + i = GetWindowTextLength(hWnd) + 1; // text length incl. EOS + j = bASCII ? 2 : sizeof(*(LPTSTR)0); // buffer width + + // allocate search buffer + if ((lpbySearch = (LPBYTE) malloc(i * j)) != NULL) + { + // get search text and real length + i = GetWindowText(hWnd,(LPTSTR) lpbySearch,i); + + // add string to combo box + if (SendMessage(hWnd,CB_FINDSTRINGEXACT,0,(LPARAM) lpbySearch) == CB_ERR) + SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) lpbySearch); + + #if defined _UNICODE + { + // Unicode to byte translation + LPTSTR szTmp = DuplicateString((LPCTSTR) lpbySearch); + if (szTmp != NULL) + { + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, + szTmp, -1, + (LPSTR) lpbySearch, i+1, NULL, NULL); + free(szTmp); + } + } + #endif + + // convert input format to nibble based format + if (bASCII) // ASCII input + { + // convert ASCII to number + for (j = i - 1; j >= 0; --j) + { + // order LSB, MSB + lpbySearch[j * 2 + 1] = lpbySearch[j] >> 4; + lpbySearch[j * 2] = lpbySearch[j] & 0xF; + } + i *= 2; // no. of nibbles + } + else // hex number input + { + // convert HEX to number + for (i = 0, j = 0; lpbySearch[j] != 0; ++j) + { + if (lpbySearch[j] == ' ') // skip space + continue; + + if (isxdigit(lpbySearch[j])) + { + lpbySearch[i] = toupper(lpbySearch[j]) - '0'; + if (lpbySearch[i] > 9) lpbySearch[i] -= 'A' - '9' - 1; + } + else + { + i = 0; // wrong format, no match + break; + } + ++i; // inc, no. of nibbles + } + } + + bMatch = FALSE; // no match + dwAddr = dwAdrMem; // calculate search start address + if (*pdwAddrLast == dwAddr) + dwAddr += nSearchDir; + + // scan mapping/module until match + for (dwCnt = 0; i && !bMatch && dwCnt <= dwMapDataMask; ++dwCnt) + { + BYTE byC; + + // i = no. of nibbles that have to match + for (bMatch = TRUE, j = 0;bMatch && j < i; ++j) + { + GetMemPeek(&byC,(dwAddr + j) & dwMapDataMask,1); + bMatch = (byC == lpbySearch[j]); + } + dwAddr += nSearchDir; + } + free(lpbySearch); + + // check match result + if (bMatch) + { + // matching address + dwAddr = (dwAddr - nSearchDir) & dwMapDataMask; + + // update memory window + OnMemGoDx(GetParent(hDlg),dwAddr); + + // update rpl obj view dialog + UpdateRplObjViewWnd(hDlgRplObjView,dwAddr); + + *pdwAddrLast = dwAddr; // last matching address + } + else + { + MessageBox(hDlg,_T("Search string not found!"),_T("Find"), + MB_APPLMODAL|MB_OK|MB_ICONEXCLAMATION|MB_SETFOREGROUND); + } + } + return TRUE; +} + +// +// enter find dialog +// +static INT_PTR CALLBACK Find(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + static DWORD dwAddrEntry; + static BOOL bASCII = FALSE; + + switch (message) + { + case WM_INITDIALOG: + CheckDlgButton(hDlg,IDC_FIND_ASCII,bASCII); + dwAddrEntry = -1; + return TRUE; + + case WM_DESTROY: + hDlgFind = NULL; + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_FIND_ASCII: bASCII = !bASCII; return TRUE; + case IDC_FIND_PREV: return OnFindOK(hDlg,bASCII,&dwAddrEntry,-1); + case IDC_FIND_NEXT: return OnFindOK(hDlg,bASCII,&dwAddrEntry,1); + case IDCANCEL: DestroyWindow(hDlg); return TRUE; + } + break; + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +static BOOL OnMemFind(HWND hDlg) +{ + if (hDlgFind == NULL) // no find dialog, create it + { + if ((hDlgFind = CreateDialog(hApp,MAKEINTRESOURCE(IDD_FIND),hDlg, + (DLGPROC)Find)) == NULL) + AbortMessage(_T("Find Dialog Box Creation Error !")); + } + else + { + SetFocus(hDlgFind); // set focus on find dialog + } + return -1; // call windows default handler +} + + +//################ +//# +//# Profile dialog box +//# +//################ + +// +// update profiler dialog content +// +static VOID UpdateProfileWnd(HWND hDlg) +{ + #define CPU_FREQ 524288 // base CPU frequency + #define SX_RATE 0x0E + #define GX_RATE 0x1B + + LPCTSTR pcUnit[] = { _T("s"),_T("ms"),_T("us"),_T("ns") }; + + QWORD lVar; + TCHAR szBuffer[64]; + UINT i; + DWORD dwFreq, dwEndFreq; + + if (hDlg == NULL) return; // dialog not open + + // 64 bit cpu cycle counter + lVar = *(QWORD *)&Chipset.cycles - *(QWORD *)&OldChipset.cycles; + + // cycle counts + _sntprintf(szBuffer,ARRAYSIZEOF(szBuffer),_T("%I64u"),lVar); + SetDlgItemText(hDlg,IDC_PROFILE_LASTCYCLES,szBuffer); + + // CPU frequency + dwFreq = (cCurrentRomType=='S') + ? ((SX_RATE + 1) * CPU_FREQ / 4) + : ((GX_RATE + 1) * CPU_FREQ / 4); + dwEndFreq = ((999 * 2 - 1) * dwFreq) / (2 * 1000); + + // search for ENG unit + for (i = 0; i < ARRAYSIZEOF(pcUnit) - 1 && lVar <= dwEndFreq; ++i) + { + lVar *= 1000; // next ENG unit + } + + // calculate rounded time + lVar = (2 * lVar + dwFreq) / (2 * dwFreq); + + _ASSERT(i < ARRAYSIZEOF(pcUnit)); + _sntprintf(szBuffer,ARRAYSIZEOF(szBuffer),_T("%I64u %s"),lVar,pcUnit[i]); + SetDlgItemText(hDlg,IDC_PROFILE_LASTTIME,szBuffer); + return; + #undef SX_CLK + #undef GX_CLK + #undef CPU_FREQ +} + +// +// enter profile dialog +// +static INT_PTR CALLBACK Profile(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + UpdateProfileWnd(hDlg); + return TRUE; + + case WM_DESTROY: + hDlgProfile = NULL; + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDCANCEL: DestroyWindow(hDlg); return TRUE; + } + break; + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +static BOOL OnProfile(HWND hDlg) +{ + if (hDlgProfile == NULL) // no profile dialog, create it + { + if ((hDlgProfile = CreateDialog(hApp,MAKEINTRESOURCE(IDD_PROFILE),hDlg, + (DLGPROC)Profile)) == NULL) + AbortMessage(_T("Profile Dialog Box Creation Error !")); + } + else + { + SetFocus(hDlgProfile); // set focus on profile dialog + } + return -1; // call windows default handler +} + + +//################ +//# +//# RPL object viewer dialog box +//# +//################ + +// +// update rpl obj view dialog content +// +static VOID UpdateRplObjViewWnd(HWND hDlg, DWORD dwAddr) +{ + LPTSTR szObjList; + + if (hDlg == NULL) return; // dialog not open + + // show entry point name only in mapped mode + bRplViewName = (GetMemMapType() == MEM_MMU); + + // create view string + szObjList = RplCreateObjView(dwAddr,GetMemDataSize(),TRUE); + SetDlgItemText(hDlg,IDC_RPLVIEW_DATA,szObjList); + free(szObjList); + return; +} + +// +// enter RPL object viewer dialog +// +static INT_PTR CALLBACK RplObjView(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + switch (cCurrentRomType) + { + case 'S': // HP48SX + dwRplPlatform = RPL_P3; // Charlemagne platform + break; + case '6': // HP38G (64K RAM version) + case 'A': // HP38G + case 'G': // HP48GX + dwRplPlatform = RPL_P4; // Alcuin platform + break; + case 'E': // HP39G/40G + case 'X': // HP49G + dwRplPlatform = RPL_P5; // V'ger platform + break; + default: + _ASSERT(FALSE); + } + + bRplViewAddr = TRUE; // show address + bRplViewBin = TRUE; // show binary data + return TRUE; + + case WM_DESTROY: + hDlgRplObjView = NULL; + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDCANCEL: DestroyWindow(hDlg); return TRUE; + } + break; + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +static BOOL OnRplObjView(HWND hDlg) +{ + // get cursor address of memory view + DWORD dwAddr = GetMemCurAddr(hDlg); + + if (hDlgRplObjView == NULL) // no rpl obj view dialog, create it + { + if ((hDlgRplObjView = CreateDialog(hApp,MAKEINTRESOURCE(IDD_RPLVIEW),hDlg, + (DLGPROC)RplObjView)) == NULL) + AbortMessage(_T("RPL Object View Dialog Box Creation Error !")); + } + + UpdateRplObjViewWnd(hDlgRplObjView,dwAddr); + return -1; // call windows default handler +} + + +//################ +//# +//# Settings dialog box +//# +//################ + +// +// copy edit box content to current combox box selection +// +static VOID CopyEditToCombo(HWND hDlg,HWND hWndComboBox) +{ + TCHAR szSymbFilename[MAX_PATH]; + INT i; + + // get current selection + if ((i = (INT) SendMessage(hWndComboBox,CB_GETCURSEL,0,0)) != CB_ERR) + { + // delete associated name + free((LPVOID) SendMessage(hWndComboBox,CB_GETITEMDATA,i,0)); + + // append actual name + GetDlgItemText(hDlg,IDC_DEBUG_SET_FILE,szSymbFilename,ARRAYSIZEOF(szSymbFilename)); + SendMessage(hWndComboBox,CB_SETITEMDATA,i,(LPARAM) DuplicateString(szSymbFilename)); + } + return; +} + +// +// copy edit box content to current combox box selection +// +static VOID CopyComboToEdit(HWND hDlg,HWND hWndComboBox) +{ + HWND hWnd; + INT i; + + // get current selection + if ((i = (INT) SendMessage(hWndComboBox,CB_GETCURSEL,0,0)) != CB_ERR) + { + // update file edit box + hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_FILE); + SetWindowText(hWnd,(LPTSTR) SendMessage(hWndComboBox,CB_GETITEMDATA,i,0)); + SendMessage(hWnd,EM_SETSEL,0,-1); + } + return; +} + +// +// settings browse dialog +// +static BOOL OnBrowseSettings(HWND hDlg, HWND hWndFilename) +{ + TCHAR szBuffer[MAX_PATH]; + OPENFILENAME ofn; + + ZeroMemory(&ofn, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hDlg; + ofn.lpstrFilter = + _T("HP-Tools Linker File (*.O)\0*.O\0") + _T("All Files (*.*)\0*.*\0"); + ofn.lpstrDefExt = _T("O"); + ofn.nFilterIndex = 1; + ofn.lpstrFile = szBuffer; + ofn.lpstrFile[0] = 0; + ofn.nMaxFile = ARRAYSIZEOF(szBuffer); + ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST; + if (GetOpenFileName(&ofn)) + { + SetWindowText(hWndFilename,szBuffer); + SendMessage(hWndFilename,EM_SETSEL,0,-1); + } + return 0; +} + +// +// enter settings dialog +// +static INT_PTR CALLBACK Settings(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND hWnd; + TCHAR szSymbFilename[MAX_PATH]; + TCHAR szItemname[16]; + INT i,nMax; + + switch (message) + { + case WM_INITDIALOG: + // set disassembler mode + CheckDlgButton(hDlg,(disassembler_mode == HP_MNEMONICS) ? IDC_DISASM_HP : IDC_DISASM_CLASS,BST_CHECKED); + // set symbolic enable check button + CheckDlgButton(hDlg,IDC_DEBUG_SET_SYMB,disassembler_symb); + // fill model combo box and corresponding file edit box + { + LPCTSTR lpszModels; + TCHAR cModel[] = _T(" "); + + // fill model combo box + hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_MODEL); + for (lpszModels = _T(MODELS); *lpszModels != 0; ++lpszModels) + { + cModel[0] = *lpszModels; // string with model character + i = (INT) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) cModel); + + // get filename + wsprintf(szItemname,_T("Symb%c"),cModel[0]); + ReadSettingsString(_T("Disassembler"),szItemname,_T(""),szSymbFilename,ARRAYSIZEOF(szSymbFilename)); + + // append filename to model + SendMessage(hWnd,CB_SETITEMDATA,i,(LPARAM) DuplicateString(szSymbFilename)); + } + + // select for actual model + cModel[0] = (TCHAR) cCurrentRomType; + if ((i = (INT) SendMessage(hWnd,CB_SELECTSTRING,0,(LPARAM) cModel)) != CB_ERR) + { + LPTSTR lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0); + + // fill file edit box + hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_FILE); + SetWindowText(hWnd,lpszFilename); + SendMessage(hWnd,EM_SETSEL,0,-1); + } + } + return TRUE; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDC_DEBUG_SET_MODEL: + // combo box changing item + if (HIWORD(wParam) == CBN_SETFOCUS) + { + // update associated name with file edit box + CopyEditToCombo(hDlg,(HWND) lParam); + } + // new combo box item selected + if (HIWORD(wParam) == CBN_SELENDOK) + { + // update file edit box with associated name + CopyComboToEdit(hDlg,(HWND) lParam); + } + break; + case IDC_DEBUG_SET_BROWSE: + return OnBrowseSettings(hDlg,GetDlgItem(hDlg,IDC_DEBUG_SET_FILE)); + case IDOK: + // set disassembler mode + disassembler_mode = IsDlgButtonChecked(hDlg,IDC_DISASM_HP) ? HP_MNEMONICS : CLASS_MNEMONICS; + // set symbolic enable check button + disassembler_symb = IsDlgButtonChecked(hDlg,IDC_DEBUG_SET_SYMB); + // update associated name with file edit box + hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_MODEL); + CopyEditToCombo(hDlg,hWnd); + // write all symbol filenames to registry + nMax = (INT) SendMessage(hWnd,CB_GETCOUNT,0,0); + for (i = 0; i < nMax; ++i) + { + LPTSTR lpszFilename; + + SendMessage(hWnd,CB_GETLBTEXT,i,(LPARAM) szSymbFilename); + wsprintf(szItemname,_T("Symb%c"),szSymbFilename[0]); + lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0); + if (*lpszFilename == 0) // empty + { + DelSettingsKey(_T("Disassembler"),szItemname); + } + else + { + WriteSettingsString(_T("Disassembler"),szItemname,lpszFilename); + } + } + RplDeleteTable(); // delete rpl symbol table + LoadSymbTable(); // reload external rpl symbol table + // redraw debugger code view + ViewCodeWnd(GetDlgItem(GetParent(hDlg),IDC_DEBUG_CODE),dwAdrLine[0]); + // no break + case IDCANCEL: + // free combo box items + hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_MODEL); + nMax = (INT) SendMessage(hWnd,CB_GETCOUNT,0,0); + for (i = 0; i < nMax; ++i) + { + LPTSTR lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0); + if (lpszFilename != NULL) + { + free(lpszFilename); + } + } + EndDialog(hDlg,LOWORD(wParam)); + return TRUE; + } + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +static BOOL OnSettings(HWND hDlg) +{ + if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_SETTINGS), hDlg, (DLGPROC)Settings) == -1) + AbortMessage(_T("Settings Dialog Box Creation Error !")); + return 0; +} + + +//################ +//# +//# New Value dialog box +//# +//################ + +// +// enter new value dialog +// +static INT_PTR CALLBACK NewValue(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + static LPTSTR lpszBuffer; // handle of buffer + static int nBufferlen; // length of buffer + + HWND hWnd; + TCHAR szBuffer[64]; + LONG i; + + switch (message) + { + case WM_INITDIALOG: + lpszBuffer = (LPTSTR) lParam; + // length with zero string terminator + nBufferlen = lstrlen(lpszBuffer)+1; + _ASSERT(ARRAYSIZEOF(szBuffer) >= nBufferlen); + SetDlgItemText(hDlg,IDC_NEWVALUE,lpszBuffer); + return TRUE; + case WM_COMMAND: + wParam = LOWORD(wParam); + switch(wParam) + { + case IDOK: + hWnd = GetDlgItem(hDlg,IDC_NEWVALUE); + GetWindowText(hWnd,szBuffer,nBufferlen); + // test if valid hex address + for (i = 0; i < (LONG) lstrlen(szBuffer); ++i) + { + if (_istxdigit(szBuffer[i]) == 0) + { + SendMessage(hWnd,EM_SETSEL,0,-1); + SetFocus(hWnd); // focus to edit control + return FALSE; + } + } + lstrcpy(lpszBuffer,szBuffer); // copy valid value + // no break + case IDCANCEL: + EndDialog(hDlg,wParam); + return TRUE; + } + } + return FALSE; +} + +static INT_PTR OnNewValue(LPTSTR lpszValue) +{ + INT_PTR nResult; + + if ((nResult = DialogBoxParam(hApp, + MAKEINTRESOURCE(IDD_NEWVALUE), + hDlgDebug, + (DLGPROC)NewValue, + (LPARAM)lpszValue) + ) == -1) + AbortMessage(_T("Input Dialog Box Creation Error !")); + return nResult; +} + + +//################ +//# +//# Goto Address dialog box +//# +//################ + +// +// enter goto address dialog +// +static INT_PTR CALLBACK EnterAddr(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + SetWindowLongPtr(hDlg,GWLP_USERDATA,(LONG_PTR) lParam); + return TRUE; + case WM_COMMAND: + wParam = LOWORD(wParam); + switch(wParam) + { + case IDOK: + if (!GetAddr(hDlg, + IDC_ENTERADR, + (DWORD *) GetWindowLongPtr(hDlg,GWLP_USERDATA), + 0xFFFFFFFF, + disassembler_symb)) + return FALSE; + // no break + case IDCANCEL: + EndDialog(hDlg,wParam); + return TRUE; + } + } + return FALSE; +} + +static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue) +{ + if (DialogBoxParam(hApp, MAKEINTRESOURCE(IDD_ENTERADR), hDlg, (DLGPROC)EnterAddr, (LPARAM)dwValue) == -1) + AbortMessage(_T("Address Dialog Box Creation Error !")); +} + + +//################ +//# +//# Breakpoint dialog box +//# +//################ + +// +// enter breakpoint dialog +// +static INT_PTR CALLBACK EnterBreakpoint(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + static BP_T *sBp; + + switch (message) + { + case WM_INITDIALOG: + sBp = (BP_T *) lParam; + sBp->bEnable = TRUE; + sBp->nType = BP_EXEC; + SendDlgItemMessage(hDlg,IDC_BPCODE,BM_SETCHECK,1,0); + return TRUE; + case WM_COMMAND: + wParam = LOWORD(wParam); + switch(wParam) + { + case IDC_BPCODE: sBp->nType = BP_EXEC; return TRUE; + case IDC_BPRPL: sBp->nType = BP_RPL; return TRUE; + case IDC_BPACCESS: sBp->nType = BP_ACCESS; return TRUE; + case IDC_BPREAD: sBp->nType = BP_READ; return TRUE; + case IDC_BPWRITE: sBp->nType = BP_WRITE; return TRUE; + case IDOK: + if (!GetAddr(hDlg,IDC_ENTERADR,&sBp->dwAddr,0xFFFFF,disassembler_symb)) + return FALSE; + // no break + case IDCANCEL: + EndDialog(hDlg,wParam); + return TRUE; + } + } + return FALSE; +} + +static VOID OnEnterBreakpoint(HWND hDlg, BP_T *sValue) +{ + if (DialogBoxParam(hApp, MAKEINTRESOURCE(IDD_ENTERBREAK), hDlg, (DLGPROC)EnterBreakpoint, (LPARAM)sValue) == -1) + AbortMessage(_T("Breakpoint Dialog Box Creation Error !")); +} + + +//################ +//# +//# Edit breakpoint dialog box +//# +//################ + +// +// handle drawing in breakpoint window +// +static __inline BOOL OnDrawBreakWnd(LPDRAWITEMSTRUCT lpdis) +{ + TCHAR szBuf[64]; + COLORREF crBkColor,crTextColor; + HDC hdcMem; + HBITMAP hBmpOld; + + if (lpdis->itemID == -1) // no item in list box + return TRUE; + + crBkColor = GetBkColor(lpdis->hDC); // save actual color settings + crTextColor = GetTextColor(lpdis->hDC); + + if (lpdis->itemState & ODS_SELECTED) // cursor line + { + SetBkColor(lpdis->hDC,GetSysColor(COLOR_HIGHLIGHT)); + SetTextColor(lpdis->hDC,GetSysColor(COLOR_HIGHLIGHTTEXT)); + } + + // write Text + SendMessage(lpdis->hwndItem,LB_GETTEXT,lpdis->itemID,(LPARAM) szBuf); + ExtTextOut(lpdis->hDC,(int)(lpdis->rcItem.left)+17,(int)(lpdis->rcItem.top), + ETO_OPAQUE,(LPRECT)&lpdis->rcItem,szBuf,lstrlen(szBuf),NULL); + + SetBkColor(lpdis->hDC,crBkColor); // restore color settings + SetTextColor(lpdis->hDC,crTextColor); + + // draw checkbox + hdcMem = CreateCompatibleDC(lpdis->hDC); + _ASSERT(hBmpCheckBox); + hBmpOld = (HBITMAP) SelectObject(hdcMem,hBmpCheckBox); + + BitBlt(lpdis->hDC,lpdis->rcItem.left+2,lpdis->rcItem.top+2, + 11,lpdis->rcItem.bottom - lpdis->rcItem.top, + hdcMem,sBreakpoint[lpdis->itemData].bEnable ? 0 : 10,0,SRCCOPY); + + SelectObject(hdcMem,hBmpOld); + DeleteDC(hdcMem); + + if (lpdis->itemState & ODS_FOCUS) // redraw focus + DrawFocusRect(lpdis->hDC,&lpdis->rcItem); + + return TRUE; // focus handled here +} + +// +// toggle breakpoint drawing +// +static BOOL ToggleBreakpointItem(HWND hWnd, INT nItem) +{ + RECT rc; + + // get breakpoint number + INT i = (INT) SendMessage(hWnd,LB_GETITEMDATA,nItem,0); + + sBreakpoint[i].bEnable = !sBreakpoint[i].bEnable; + // update region of toggled item + SendMessage(hWnd,LB_GETITEMRECT,nItem,(LPARAM)&rc); + InvalidateRect(hWnd,&rc,TRUE); + return TRUE; +} + +// +// draw breakpoint type +// +static VOID DrawBreakpoint(HWND hWnd, INT i) +{ + TCHAR *szText,szBuffer[32]; + INT nItem; + + switch(sBreakpoint[i].nType) + { + case BP_EXEC: // code breakpoint + szText = _T("Code"); + break; + case BP_RPL: // RPL breakpoint + szText = _T("RPL"); + break; + case BP_READ: // read memory breakpoint + szText = _T("Memory Read"); + break; + case BP_WRITE: // write memory breakpoint + szText = _T("Memory Write"); + break; + case BP_ACCESS: // memory breakpoint + szText = _T("Memory Access"); + break; + default: // unknown breakpoint type + szText = _T("unknown"); + _ASSERT(0); + } + wsprintf(szBuffer,_T("%05X (%s)"),sBreakpoint[i].dwAddr,szText); + nItem = (INT) SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); + SendMessage(hWnd,LB_SETITEMDATA,nItem,i); + return; +} + +// +// enter edit breakpoint dialog +// +static INT_PTR CALLBACK EditBreakpoint(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + TEXTMETRIC tm; + + HWND hWnd; + HDC hDC; + HFONT hFont; + BP_T sBp; + INT i,nItem; + + switch (message) + { + case WM_INITDIALOG: + // font settings + SendDlgItemMessage(hDlg,IDC_STATIC_BREAKPOINT,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_BREAKEDIT_ADD, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_BREAKEDIT_DELETE, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDCANCEL, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + + hBmpCheckBox = LoadBitmap(hApp,MAKEINTRESOURCE(IDB_CHECKBOX)); + _ASSERT(hBmpCheckBox); + + hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND); + SendMessage(hWnd,WM_SETREDRAW,FALSE,0); + SendMessage(hWnd,LB_RESETCONTENT,0,0); + for (i = 0; i < wBreakpointCount; ++i) + DrawBreakpoint(hWnd,i); + SendMessage(hWnd,WM_SETREDRAW,TRUE,0); + return TRUE; + + case WM_DESTROY: + DeleteObject(hBmpCheckBox); + return TRUE; + + case WM_COMMAND: + hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND); + switch (HIWORD(wParam)) + { + case LBN_DBLCLK: + if (LOWORD(wParam) == IDC_BREAKEDIT_WND) + { + if ((nItem = (INT) SendMessage(hWnd,LB_GETCURSEL,0,0)) == LB_ERR) + return FALSE; + + return ToggleBreakpointItem(hWnd,nItem); + } + } + + switch(LOWORD(wParam)) + { + case IDC_BREAKEDIT_ADD: + sBp.dwAddr = -1; // no breakpoint given + OnEnterBreakpoint(hDlg, &sBp); + if (sBp.dwAddr != -1) + { + for (i = 0; i < wBreakpointCount; ++i) + { + if (sBreakpoint[i].dwAddr == sBp.dwAddr) + { + // tried to add used code breakpoint + if (sBreakpoint[i].bEnable && (sBreakpoint[i].nType & sBp.nType & (BP_EXEC | BP_RPL)) != 0) + return FALSE; + + // only modify memory breakpoints + if ( ( sBreakpoint[i].bEnable == FALSE + && (sBreakpoint[i].nType & sBp.nType & (BP_EXEC | BP_RPL)) != 0) + || ((sBreakpoint[i].nType & BP_ACCESS) && (sBp.nType & BP_ACCESS))) + { + // replace breakpoint type + sBreakpoint[i].bEnable = TRUE; + sBreakpoint[i].nType = sBp.nType; + + // redaw breakpoint list + SendMessage(hWnd,WM_SETREDRAW,FALSE,0); + SendMessage(hWnd,LB_RESETCONTENT,0,0); + for (i = 0; i < wBreakpointCount; ++i) + DrawBreakpoint(hWnd,i); + SendMessage(hWnd,WM_SETREDRAW,TRUE,0); + return FALSE; + } + } + } + + // check for breakpoint buffer full + if (wBreakpointCount >= MAXBREAKPOINTS) + { + AbortMessage(_T("Reached maximum number of breakpoints !")); + return FALSE; + } + + sBreakpoint[wBreakpointCount].bEnable = sBp.bEnable; + sBreakpoint[wBreakpointCount].nType = sBp.nType; + sBreakpoint[wBreakpointCount].dwAddr = sBp.dwAddr; + + DrawBreakpoint(hWnd,wBreakpointCount); + + ++wBreakpointCount; + } + return TRUE; + + case IDC_BREAKEDIT_DELETE: + // scan all breakpoints from top + for (nItem = wBreakpointCount-1; nItem >= 0; --nItem) + { + // item selected + if (SendMessage(hWnd,LB_GETSEL,nItem,0) > 0) + { + INT j; + + // get breakpoint index + i = (INT) SendMessage(hWnd,LB_GETITEMDATA,nItem,0); + SendMessage(hWnd,LB_DELETESTRING,nItem,0); + --wBreakpointCount; + + // update remaining list box references + for (j = 0; j < wBreakpointCount; ++j) + { + INT k = (INT) SendMessage(hWnd,LB_GETITEMDATA,j,0); + if (k > i) SendMessage(hWnd,LB_SETITEMDATA,j,k-1); + } + + // remove breakpoint from breakpoint table + while (++i <= wBreakpointCount) + sBreakpoint[i-1] = sBreakpoint[i]; + } + } + return TRUE; + + case IDCANCEL: + EndDialog(hDlg,IDCANCEL); + return TRUE; + } + + case WM_VKEYTOITEM: + if (LOWORD(wParam) == VK_SPACE) + { + hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND); + for (nItem = 0; nItem < wBreakpointCount; ++nItem) + { + // item selected + if (SendMessage(hWnd,LB_GETSEL,nItem,0) > 0) + ToggleBreakpointItem(hWnd,nItem); + } + return -2; + } + return -1; // default action + + case WM_DRAWITEM: + if (wParam == IDC_BREAKEDIT_WND) return OnDrawBreakWnd((LPDRAWITEMSTRUCT) lParam); + break; + + case WM_MEASUREITEM: + hDC = GetDC(hDlg); + + // GetTextMetrics from "Courier New 8" font + hFont = CreateFont(-MulDiv(8,GetDeviceCaps(hDC, LOGPIXELSY),72),0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Courier New")); + + hFont = (HFONT) SelectObject(hDC,hFont); + GetTextMetrics(hDC,&tm); + hFont = (HFONT) SelectObject(hDC,hFont); + DeleteObject(hFont); + + ((LPMEASUREITEMSTRUCT) lParam)->itemHeight = tm.tmHeight; + + ReleaseDC(hDlg,hDC); + return TRUE; + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +static BOOL OnEditBreakpoint(HWND hDlg) +{ + if (DialogBox(hApp, MAKEINTRESOURCE(IDD_BREAKEDIT), hDlg, (DLGPROC)EditBreakpoint) == -1) + AbortMessage(_T("Edit Breakpoint Dialog Box Creation Error !")); + + // update code window + InvalidateRect(GetDlgItem(hDlg,IDC_DEBUG_CODE),NULL,TRUE); + return -1; +} + + +//################ +//# +//# Last Instruction dialog box +//# +//################ + +// +// view last instructions +// +static INT_PTR CALLBACK InfoIntr(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND hWnd; + TCHAR szBuffer[64]; + LONG lIndex; + WORD i,j; + + switch (message) + { + case WM_INITDIALOG: + // font settings + SendDlgItemMessage(hDlg,IDC_INSTR_TEXT, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_INSTR_CLEAR, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_INSTR_COPY, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDCANCEL, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + + lIndex = 0; // init lIndex + hWnd = GetDlgItem(hDlg,IDC_INSTR_CODE); + SendMessage(hWnd,WM_SETREDRAW,FALSE,0); + SendMessage(hWnd,LB_RESETCONTENT,0,0); + for (i = wInstrRp; i != wInstrWp; i = (i + 1) % wInstrSize) + { + LPCTSTR lpszName; + + // entry has a name + if (disassembler_symb && (lpszName = RplGetName(pdwInstrArray[i])) != NULL) + { + szBuffer[0] = _T('='); + lstrcpyn(&szBuffer[1],lpszName,ARRAYSIZEOF(szBuffer)-1); + SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); + } + + j = wsprintf(szBuffer,_T("%05lX "),pdwInstrArray[i]); + disassemble(pdwInstrArray[i],&szBuffer[j]); + lIndex = (LONG) SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); + } + SendMessage(hWnd,WM_SETREDRAW,TRUE,0); + SendMessage(hWnd,LB_SETCARETINDEX,lIndex,TRUE); + return TRUE; + case WM_COMMAND: + hWnd = GetDlgItem(hDlg,IDC_INSTR_CODE); + switch(LOWORD(wParam)) + { + case IDC_INSTR_COPY: + CopyItemsToClipboard(hWnd); // copy selected items to clipboard + return TRUE; + case IDC_INSTR_CLEAR: // clear instruction buffer + wInstrRp = wInstrWp; + SendMessage(hWnd,LB_RESETCONTENT,0,0); + return TRUE; + case IDCANCEL: + EndDialog(hDlg,IDCANCEL); + return TRUE; + } + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +static BOOL OnInfoIntr(HWND hDlg) +{ + if (DialogBox(hApp, MAKEINTRESOURCE(IDD_INSTRUCTIONS), hDlg, (DLGPROC)InfoIntr) == -1) + AbortMessage(_T("Last Instructions Dialog Box Creation Error !")); + return 0; +} + +// +// view write only I/O registers +// +static INT_PTR CALLBACK InfoWoRegister(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + TCHAR szBuffer[8]; + + switch (message) + { + case WM_INITDIALOG: + wsprintf(szBuffer,_T("%05X"),Chipset.start1); + SetDlgItemText(hDlg,IDC_ADDR20_24,szBuffer); + wsprintf(szBuffer,_T("%03X"),Chipset.loffset); + SetDlgItemText(hDlg,IDC_ADDR25_27,szBuffer); + wsprintf(szBuffer,_T("%02X"),Chipset.lcounter); + SetDlgItemText(hDlg,IDC_ADDR28_29,szBuffer); + wsprintf(szBuffer,_T("%05X"),Chipset.start2); + SetDlgItemText(hDlg,IDC_ADDR30_34,szBuffer); + return TRUE; + case WM_COMMAND: + if ((LOWORD(wParam) == IDCANCEL)) + { + EndDialog(hDlg,IDCANCEL); + return TRUE; + } + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +static BOOL OnInfoWoRegister(HWND hDlg) +{ + if (DialogBox(hApp, MAKEINTRESOURCE(IDD_WRITEONLYREG), hDlg, (DLGPROC)InfoWoRegister) == -1) + AbortMessage(_T("Write-Only Register Dialog Box Creation Error !")); + return 0; +} + + +//################ +//# +//# Breakpoint list operations +//# +//################ + +// +// load breakpoint list +// +VOID LoadBreakpointList(HANDLE hFile) // NULL = clear breakpoint list +{ + DWORD lBytesRead = 0; + + // read number of breakpoints + if (hFile) ReadFile(hFile, &wBreakpointCount, sizeof(wBreakpointCount), &lBytesRead, NULL); + + // breakpoints found + if (lBytesRead == sizeof(wBreakpointCount) && wBreakpointCount < ARRAYSIZEOF(sBreakpoint)) + { + WORD wBreakpointSize; + + // read size of one breakpoint + ReadFile(hFile, &wBreakpointSize, sizeof(wBreakpointSize), &lBytesRead, NULL); + if (lBytesRead == sizeof(wBreakpointSize) && wBreakpointSize == sizeof(sBreakpoint[0])) + { + // read breakpoints + ReadFile(hFile, sBreakpoint, wBreakpointCount * sizeof(sBreakpoint[0]), &lBytesRead, NULL); + _ASSERT(lBytesRead == wBreakpointCount * sizeof(sBreakpoint[0])); + } + else // changed breakpoint structure + { + wBreakpointCount = 0; // clear breakpoint list + } + } + else // no breakpoints or breakpoint buffer too small + { + wBreakpointCount = 0; // clear breakpoint list + } + return; +} + +// +// save breakpoint list +// +VOID SaveBreakpointList(HANDLE hFile) +{ + if (wBreakpointCount) // defined breakpoints + { + DWORD lBytesWritten; + + WORD wBreakpointSize = sizeof(sBreakpoint[0]); + + _ASSERT(hFile); // valid file pointer? + + // write number of breakpoints + WriteFile(hFile, &wBreakpointCount, sizeof(wBreakpointCount), &lBytesWritten, NULL); + _ASSERT(lBytesWritten == sizeof(wBreakpointCount)); + + // write size of one breakpoint + WriteFile(hFile, &wBreakpointSize, sizeof(wBreakpointSize), &lBytesWritten, NULL); + _ASSERT(lBytesWritten == sizeof(wBreakpointSize)); + + // write breakpoints + WriteFile(hFile, sBreakpoint, wBreakpointCount * sizeof(sBreakpoint[0]), &lBytesWritten, NULL); + _ASSERT(lBytesWritten == wBreakpointCount * sizeof(sBreakpoint[0])); + } + return; +} + +// +// create a copy of the breakpoint list +// +VOID CreateBackupBreakpointList(VOID) +{ + _ASSERT(sizeof(sBackupBreakpoint) == sizeof(sBreakpoint)); + + wBackupBreakpointCount = wBreakpointCount; + + if (wBreakpointCount > 0) // list not empty + { + CopyMemory(sBackupBreakpoint,sBreakpoint,sizeof(sBackupBreakpoint)); + } + return; +} + +// +// restore the breakpoint list from the copy +// +VOID RestoreBackupBreakpointList(VOID) +{ + _ASSERT(sizeof(sBackupBreakpoint) == sizeof(sBreakpoint)); + + wBreakpointCount = wBackupBreakpointCount; + + if (wBreakpointCount > 0) // list not empty + { + CopyMemory(sBreakpoint,sBackupBreakpoint,sizeof(sBreakpoint)); + } + return; +} + + +//################ +//# +//# Load/Save Memory Data +//# +//################ + +static BOOL OnBrowseLoadMem(HWND hDlg) +{ + TCHAR szBuffer[MAX_PATH]; + OPENFILENAME ofn; + + ZeroMemory(&ofn, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hDlg; + ofn.lpstrFilter = + _T("Memory Dump Files (*.MEM)\0*.MEM\0") + _T("All Files (*.*)\0*.*\0"); + ofn.lpstrDefExt = _T("MEM"); + ofn.nFilterIndex = 1; + ofn.lpstrFile = szBuffer; + ofn.lpstrFile[0] = 0; + ofn.nMaxFile = ARRAYSIZEOF(szBuffer); + ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST; + if (GetOpenFileName(&ofn)) + { + SetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szBuffer); + } + return 0; +} + +static BOOL OnBrowseSaveMem(HWND hDlg) +{ + TCHAR szBuffer[MAX_PATH]; + OPENFILENAME ofn; + + ZeroMemory(&ofn, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hDlg; + ofn.lpstrFilter = + _T("Memory Dump Files (*.MEM)\0*.MEM\0") + _T("All Files (*.*)\0*.*\0"); + ofn.lpstrDefExt = _T("MEM"); + ofn.nFilterIndex = 1; + ofn.lpstrFile = szBuffer; + ofn.lpstrFile[0] = 0; + ofn.nMaxFile = ARRAYSIZEOF(szBuffer); + ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT; + if (GetSaveFileName(&ofn)) + { + SetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szBuffer); + } + return 0; +} + +// +// write file to memory +// +static BOOL LoadMemData(LPCTSTR lpszFilename,DWORD dwStartAddr,UINT uBitMode) +{ + HANDLE hFile; + DWORD dwFileSize,dwRead; + LPBYTE pbyData; + + hFile = CreateFile(lpszFilename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL); + if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file + return FALSE; + + dwFileSize = GetFileSize(hFile, NULL); + + if ((pbyData = (LPBYTE) malloc(dwFileSize)) != NULL) + { + ReadFile(hFile,pbyData,dwFileSize,&dwRead,NULL); + + if (uBitMode == 2) // auto mode (0=8-bit, 1=4-bit, 2=auto) + { + BOOL bPacked = FALSE; // data not packed + DWORD dwIndex; + + for (dwIndex = 0; !bPacked && dwIndex < dwFileSize; ++dwIndex) + { + bPacked = ((pbyData[dwIndex] & 0xF0) != 0); + } + uBitMode = bPacked ? 0 : 1; // 0=8-bit, 1=4-bit + } + + if (uBitMode == 0) // 0=8-bit + { + LPBYTE pbyDataNew = (LPBYTE) realloc(pbyData,2*dwFileSize); + if (pbyDataNew) + { + LPBYTE pbySrc,pbyDest; + pbyData = pbyDataNew; + + // source start address + pbySrc = pbyData + dwFileSize; + + dwFileSize *= 2; // new filesize + + // destination start address + pbyDest = pbyData + dwFileSize; + + while (pbySrc != pbyDest) // unpack source + { + CONST BYTE byValue = *(--pbySrc); + *(--pbyDest) = byValue >> 4; + *(--pbyDest) = byValue & 0xF; + } + _ASSERT(pbySrc == pbyData); + _ASSERT(pbyDest == pbyData); + } + else + { + free(pbyData); + pbyData = NULL; + } + } + + if (pbyData) // have data to save + { + LPBYTE p = pbyData; + + // read data size or end of Saturn address space + while (dwFileSize > 0 && dwStartAddr <= 0xFFFFF) + { + // write nibble in map mode + Nwrite(p++,dwStartAddr++,1); + --dwFileSize; + } + } + free(pbyData); + } + CloseHandle(hFile); + return pbyData != NULL; +} + +// +// write memory data to file +// +static BOOL SaveMemData(LPCTSTR lpszFilename,DWORD dwStartAddr,DWORD dwEndAddr,UINT uBitMode) +{ + HANDLE hFile; + DWORD dwAddr,dwSend,dwWritten; + BYTE byData[2]; + + hFile = CreateFile(lpszFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file + return FALSE; + + for (dwAddr = dwStartAddr; dwAddr <= dwEndAddr; dwAddr += 2) + { + _ASSERT(dwAddr <= 0xFFFFF); + Npeek(byData,dwAddr,2); // read two nibble in map mode + + dwSend = 2; // send 2 nibble + if (uBitMode == 0) // (0=8-bit, 1=4-bit) + { + byData[0] = byData[0]|(byData[1]<<4); + dwSend = 1; // send 1 byte + } + + WriteFile(hFile,&byData,dwSend,&dwWritten,NULL); + } + + CloseHandle(hFile); + return TRUE; +} + +// +// memory load data +// +static INT_PTR CALLBACK DebugMemLoad(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + TCHAR szFilename[MAX_PATH]; + DWORD dwStartAddr; + int nButton; + UINT uBitMode; + + switch (message) + { + case WM_INITDIALOG: + CheckDlgButton(hDlg,IDC_DEBUG_DATA_LOAD_ABIT,BST_CHECKED); + return TRUE; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDC_DEBUG_DATA_BUT: + return OnBrowseLoadMem(hDlg); + + case IDOK: + dwStartAddr = -1; // no address given + + // get filename + GetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szFilename,ARRAYSIZEOF(szFilename)); + + // decode address field + if ( !GetAddr(hDlg,IDC_DEBUG_DATA_STARTADDR,&dwStartAddr,0xFFFFF,FALSE) + || dwStartAddr == -1) + return FALSE; + + _ASSERT(dwStartAddr <= 0xFFFFF); + + // load as 8-bit or 4-bit data (0=8-bit, 1=4-bit, 2=auto) + for (nButton = IDC_DEBUG_DATA_LOAD_8BIT; nButton <= IDC_DEBUG_DATA_LOAD_ABIT; ++nButton) + { + if (IsDlgButtonChecked(hDlg,nButton) == BST_CHECKED) + break; + } + uBitMode = (UINT) (nButton - IDC_DEBUG_DATA_LOAD_8BIT); + + // load memory dump file + if (!LoadMemData(szFilename,dwStartAddr,uBitMode)) + return FALSE; + + // update memory window + UpdateMemoryWnd(GetParent(hDlg)); + + // no break + case IDCANCEL: + EndDialog(hDlg,LOWORD(wParam)); + return TRUE; + } + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +static BOOL OnMemLoadData(HWND hDlg) +{ + if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_MEMLOAD), hDlg, (DLGPROC)DebugMemLoad) == -1) + AbortMessage(_T("DebugLoad Dialog Box Creation Error !")); + return -1; +} + +// +// memory save data +// +static INT_PTR CALLBACK DebugMemSave(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + TCHAR szFilename[MAX_PATH]; + DWORD dwStartAddr,dwEndAddr; + UINT uBitMode; + + switch (message) + { + case WM_INITDIALOG: + CheckDlgButton(hDlg,IDC_DEBUG_DATA_SAVE_8BIT,BST_CHECKED); + return TRUE; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDC_DEBUG_DATA_BUT: + return OnBrowseSaveMem(hDlg); + + case IDOK: + dwStartAddr = dwEndAddr = -1; // no address given + + // get filename + GetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szFilename,ARRAYSIZEOF(szFilename)); + + // decode address fields + if ( !GetAddr(hDlg,IDC_DEBUG_DATA_STARTADDR,&dwStartAddr,0xFFFFF,FALSE) + || dwStartAddr == -1) + return FALSE; + if ( !GetAddr(hDlg,IDC_DEBUG_DATA_ENDADDR,&dwEndAddr,0xFFFFF,FALSE) + || dwEndAddr == -1) + return FALSE; + + _ASSERT(dwStartAddr <= 0xFFFFF); + _ASSERT(dwEndAddr <= 0xFFFFF); + + // save as 8-bit or 4-bit data (0=8-bit, 1=4-bit) + uBitMode = IsDlgButtonChecked(hDlg,IDC_DEBUG_DATA_SAVE_4BIT); + + // save memory dump file + if (!SaveMemData(szFilename,dwStartAddr,dwEndAddr,uBitMode)) + return FALSE; + + // no break + case IDCANCEL: + EndDialog(hDlg,LOWORD(wParam)); + return TRUE; + } + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +static BOOL OnMemSaveData(HWND hDlg) +{ + if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_MEMSAVE), hDlg, (DLGPROC)DebugMemSave) == -1) + AbortMessage(_T("DebugSave Dialog Box Creation Error !")); + return -1; +} + + +//################ +//# +//# Trace Log +//# +//################ + +static VOID StartTrace(VOID) +{ + if (hLogFile == NULL) + { + SetCurrentDirectory(szEmuDirectory); + hLogFile = CreateFile( + szTraceFilename, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + (uTraceMode == TRACE_FILE_NEW) ? CREATE_ALWAYS : OPEN_ALWAYS, + 0, + NULL); + SetCurrentDirectory(szCurrentDirectory); + if (hLogFile == INVALID_HANDLE_VALUE) + { + InfoMessage(_T("Unable to create trace log file.")); + hLogFile = NULL; + return; + } + + // goto end of file + SetFilePointer(hLogFile,0L,NULL,FILE_END); + } + return; +} + +static VOID StopTrace(VOID) +{ + if (hLogFile != NULL) + { + CloseHandle(hLogFile); + } + hLogFile = NULL; + return; +} + +static VOID FlushTrace(VOID) +{ + if (hLogFile != NULL) + { + VERIFY(FlushFileBuffers(hLogFile)); + } + return; +} + +static __inline void __cdecl PrintTrace(LPCTSTR lpFormat, ...) +{ + TCHAR cOutput[1024]; + DWORD dwWritten, dwRead; + va_list arglist; + + va_start(arglist,lpFormat); + dwWritten = (DWORD) wvsprintf(cOutput,lpFormat,arglist); + va_end(arglist); + #if defined _UNICODE + { + // Unicode to byte translation + LPTSTR szTmp = DuplicateString(cOutput); + if (szTmp != NULL) + { + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, + szTmp, -1, + (LPSTR) cOutput, sizeof(cOutput), NULL, NULL); + free(szTmp); + } + } + #endif + WriteFile(hLogFile,cOutput,dwWritten,&dwRead,NULL); + return; +} + +static VOID OutTrace(VOID) +{ + enum MEM_MAPPING eMapMode; + LPCTSTR lpszName; + LPTSTR s,d; + TCHAR szBuffer[128]; + TCHAR szOpc[8]; + DWORD dwNxtAddr,dwOpcAddr; + UINT i; + + if (hLogFile != NULL) // log file opened + { + if (bTraceReg) // show regs + { + INT nPos; + + nPos = wsprintf(szBuffer,_T("\r\n A=%s"),RegToStr(Chipset.A,16)); + nPos += wsprintf(&szBuffer[nPos],_T(" B=%s"),RegToStr(Chipset.B,16)); + nPos += wsprintf(&szBuffer[nPos],_T(" C=%s"),RegToStr(Chipset.C,16)); + wsprintf(&szBuffer[nPos],_T(" D=%s\r\n"),RegToStr(Chipset.D,16)); + PrintTrace(szBuffer); + + nPos = wsprintf(szBuffer,_T(" R0=%s"),RegToStr(Chipset.R0,16)); + nPos += wsprintf(&szBuffer[nPos],_T(" R1=%s"),RegToStr(Chipset.R1,16)); + nPos += wsprintf(&szBuffer[nPos],_T(" R2=%s"),RegToStr(Chipset.R2,16)); + wsprintf(&szBuffer[nPos],_T(" R3=%s\r\n"),RegToStr(Chipset.R3,16)); + PrintTrace(szBuffer); + + PrintTrace(_T(" R4=%s D0=%05X D1=%05X P=%X CY=%d Mode=%c OUT=%03X IN=%04X\r\n"), + RegToStr(Chipset.R4,16),Chipset.d0,Chipset.d1,Chipset.P,Chipset.carry, + Chipset.mode_dec ? _T('D') : _T('H'),Chipset.out,Chipset.in); + + PrintTrace(_T(" ST=%s MP=%d SR=%d SB=%d XM=%d IntrEn=%d KeyScan=%d BS=%02X\r\n"), + RegToStr(Chipset.ST,4), + (Chipset.HST & MP) != 0,(Chipset.HST & SR) != 0,(Chipset.HST & SB) != 0,(Chipset.HST & XM) != 0, + Chipset.inte,Chipset.intk,Chipset.Bank_FF & 0x7F); + + // hardware stack content + PrintTrace(_T(" Stack=")); + for (i = 1; i <= ARRAYSIZEOF(Chipset.rstk); ++i) + { + PrintTrace(_T(" %05X"), Chipset.rstk[(Chipset.rstkp-i)&7]); + } + PrintTrace(_T("\r\n")); + } + + if (bTraceMmu) // show MMU + { + TCHAR szSize[8],szAddr[8]; + + if (!bTraceReg) // no regs + { + PrintTrace(_T("\r\n")); // add separator line + } + + wsprintf(szAddr, Chipset.IOCfig ? _T("%05X") : _T("-----"),Chipset.IOBase); + PrintTrace(_T(" I/O=%s"),szAddr); + + wsprintf(szSize, Chipset.P0Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P0Size^0xFF)<<12); + wsprintf(szAddr, Chipset.P0Cfig ? _T("%05X") : _T("-----"),Chipset.P0Base<<12); + PrintTrace(_T(" NCE2=%s/%s"),szSize,szAddr); + + if (cCurrentRomType=='S') + { + wsprintf(szSize, Chipset.P1Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P1Size^0xFF)<<12); + wsprintf(szAddr, Chipset.P1Cfig ? _T("%05X") : _T("-----"),Chipset.P1Base<<12); + } + else + { + wsprintf(szSize, Chipset.BSCfg2 ? _T("%05X") : _T("-----"),(Chipset.BSSize^0xFF)<<12); + wsprintf(szAddr, Chipset.BSCfig ? _T("%05X") : _T("-----"),Chipset.BSBase<<12); + } + PrintTrace(_T(" CE1=%s/%s"),szSize,szAddr); + + if (cCurrentRomType=='S') + { + wsprintf(szSize, Chipset.P2Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P2Size^0xFF)<<12); + wsprintf(szAddr, Chipset.P2Cfig ? _T("%05X") : _T("-----"),Chipset.P2Base<<12); + } + else + { + wsprintf(szSize, Chipset.P1Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P1Size^0xFF)<<12); + wsprintf(szAddr, Chipset.P1Cfig ? _T("%05X") : _T("-----"),Chipset.P1Base<<12); + } + PrintTrace(_T(" CE2=%s/%s"),szSize,szAddr); + + if (cCurrentRomType=='S') + { + wsprintf(szSize, Chipset.BSCfg2 ? _T("%05X") : _T("-----"),(Chipset.BSSize^0xFF)<<12); + wsprintf(szAddr, Chipset.BSCfig ? _T("%05X") : _T("-----"),Chipset.BSBase<<12); + } + else + { + wsprintf(szSize, Chipset.P2Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P2Size^0xFF)<<12); + wsprintf(szAddr, Chipset.P2Cfig ? _T("%05X") : _T("-----"),Chipset.P2Base<<12); + } + PrintTrace(_T(" NCE3=%s/%s\r\n"),szSize,szAddr); + } + + // disassemble line + eMapMode = GetMemMapType(); // get current map mode + SetMemMapType(MEM_MMU); // disassemble in mapped mode + + // entry has a name + if (disassembler_symb && (lpszName = RplGetName(Chipset.pc)) != NULL) + { + PrintTrace(_T("=%s\r\n"),lpszName); // print address as label + } + dwNxtAddr = disassemble(Chipset.pc,szBuffer); + + // in disassembly replace space characters + // between Opcode and Modifier with one TAB + if ((s = _tcschr(szBuffer,_T(' '))) != NULL) + { + // skip blanks + for (d = s; *d == _T(' '); ++d) { } + + if (d == &szBuffer[8]) // on TAB position + { + *s++ = _T('\t'); // replace with TAB + + // move the opcode modifier + while ((*s++ = *d++) != 0) { } + } + } + + if (bTraceOpc) // show opcode nibbles + { + dwOpcAddr = Chipset.pc; // init address + + // show opcode nibbles in a block of 5 + for (i = 0; i < 5 && dwOpcAddr < dwNxtAddr; ++i) + { + szOpc[i] = cHex[GetMemNib(&dwOpcAddr)]; + } + + if (i == 1) // only 1 nibble written + { + szOpc[i++] = _T('\t'); // one additional TAB necessary + } + szOpc[i] = 0; // EOS + + PrintTrace(_T("%05lX %s\t%s\r\n"),Chipset.pc,szOpc,szBuffer); + + while (dwOpcAddr < dwNxtAddr) // decode rest of opcode + { + // show opcode nibbles in a block of 5 + for (i = 0; i < 5 && dwOpcAddr < dwNxtAddr; ++i) + { + szOpc[i] = cHex[GetMemNib(&dwOpcAddr)]; + } + szOpc[i] = 0; // EOS + + PrintTrace(_T(" %s\r\n"),szOpc); + } + } + else // without opcode nibbles + { + PrintTrace(_T("%05lX\t%s\r\n"),Chipset.pc,szBuffer); + } + + SetMemMapType(eMapMode); // switch back to old map mode + } + return; +} + +// +// trace settings dialog +// +static BOOL OnBrowseTraceSettings(HWND hDlg) +{ + TCHAR szBuffer[MAX_PATH]; + OPENFILENAME ofn; + + // get current content of file edit box + GetDlgItemText(hDlg,IDC_TRACE_FILE,szBuffer,ARRAYSIZEOF(szBuffer)); + + ZeroMemory(&ofn, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hDlg; + ofn.lpstrFilter = + _T("Trace Log Files (*.log)\0*.log\0") + _T("All Files (*.*)\0*.*\0"); + ofn.lpstrDefExt = _T("log"); + ofn.nFilterIndex = 1; + ofn.lpstrFile = szBuffer; + ofn.nMaxFile = ARRAYSIZEOF(szBuffer); + ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT; + if (GetSaveFileName(&ofn)) + { + SetDlgItemText(hDlg,IDC_TRACE_FILE,szBuffer); + } + return 0; +} + +// +// trace settings +// +static INT_PTR CALLBACK TraceSettings(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + SetDlgItemText(hDlg,IDC_TRACE_FILE,szTraceFilename); + CheckDlgButton(hDlg,(uTraceMode == TRACE_FILE_NEW) ? IDC_TRACE_NEW : IDC_TRACE_APPEND,BST_CHECKED); + CheckDlgButton(hDlg,IDC_TRACE_REGISTER,bTraceReg); + CheckDlgButton(hDlg,IDC_TRACE_MMU,bTraceMmu); + CheckDlgButton(hDlg,IDC_TRACE_OPCODE,bTraceOpc); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDC_TRACE_BROWSE: + return OnBrowseTraceSettings(hDlg); + + case IDOK: + // get filename + GetDlgItemText(hDlg,IDC_TRACE_FILE,szTraceFilename,ARRAYSIZEOF(szTraceFilename)); + + // trace mode + uTraceMode = IsDlgButtonChecked(hDlg,IDC_TRACE_NEW) ? TRACE_FILE_NEW : TRACE_FILE_APPEND; + + // trace content + bTraceReg = IsDlgButtonChecked(hDlg,IDC_TRACE_REGISTER); + bTraceMmu = IsDlgButtonChecked(hDlg,IDC_TRACE_MMU); + bTraceOpc = IsDlgButtonChecked(hDlg,IDC_TRACE_OPCODE); + + // no break + case IDCANCEL: + EndDialog(hDlg,LOWORD(wParam)); + return TRUE; + } + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +static BOOL OnTraceSettings(HWND hDlg) +{ + if (DialogBox(hApp, MAKEINTRESOURCE(IDD_TRACE), hDlg, (DLGPROC)TraceSettings) == -1) + AbortMessage(_T("TraceSettings Dialog Box Creation Error !")); + return -1; +} + +static BOOL OnTraceEnable(HWND hDlg) +{ + OnToggleMenuItem(hDlg,ID_TRACE_ENABLE,&bDbgTrace); + bDbgTrace ? StartTrace() : StopTrace(); + EnableMenuItem(GetMenu(hDlg),ID_TRACE_SETTINGS,bDbgTrace ? MF_GRAYED : MF_ENABLED); + return 0; +} diff --git a/Sources/Emu48/debugger.h b/Sources/Emu48/DEBUGGER.H similarity index 96% rename from Sources/Emu48/debugger.h rename to Sources/Emu48/DEBUGGER.H index 79d6aab..1a9b694 100644 --- a/Sources/Emu48/debugger.h +++ b/Sources/Emu48/DEBUGGER.H @@ -1,39 +1,39 @@ -/* - * debugger.h - * - * This file is part of Emu48 - * - * Copyright (C) 1999 Christoph Gießelink - * - */ - -// breakpoint type definitions -#define BP_EXEC 0x01 // code breakpoint -#define BP_READ 0x02 // read memory breakpoint -#define BP_WRITE 0x04 // write memory breakpoint -#define BP_RPL 0x08 // RPL breakpoint -#define BP_ACCESS (BP_READ|BP_WRITE) // read/write memory breakpoint - -// breakpoint notify definitions -#define BN_ASM 0 // ASM breakpoint -#define BN_RPL 1 // RPL breakpoint -#define BN_ASM_BT 2 // ASM and RPL breakpoint - -// debugger state definitions -#define DBG_SUSPEND -1 -#define DBG_OFF 0 -#define DBG_RUN 1 -#define DBG_STEPINTO 2 -#define DBG_STEPOVER 3 -#define DBG_STEPOUT 4 - -// debugger.c -extern VOID UpdateDbgCycleCounter(VOID); -extern BOOL CheckBreakpoint(DWORD dwAddr, DWORD wRange, UINT nType); -extern VOID NotifyDebugger(INT nType); -extern VOID DisableDebugger(VOID); -extern LRESULT OnToolDebug(VOID); -extern VOID LoadBreakpointList(HANDLE hFile); -extern VOID SaveBreakpointList(HANDLE hFile); -extern VOID CreateBackupBreakpointList(VOID); -extern VOID RestoreBackupBreakpointList(VOID); +/* + * debugger.h + * + * This file is part of Emu48 + * + * Copyright (C) 1999 Christoph Gießelink + * + */ + +// breakpoint type definitions +#define BP_EXEC 0x01 // code breakpoint +#define BP_READ 0x02 // read memory breakpoint +#define BP_WRITE 0x04 // write memory breakpoint +#define BP_RPL 0x08 // RPL breakpoint +#define BP_ACCESS (BP_READ|BP_WRITE) // read/write memory breakpoint + +// breakpoint notify definitions +#define BN_ASM 0 // ASM breakpoint +#define BN_RPL 1 // RPL breakpoint +#define BN_ASM_BT 2 // ASM and RPL breakpoint + +// debugger state definitions +#define DBG_SUSPEND -1 +#define DBG_OFF 0 +#define DBG_RUN 1 +#define DBG_STEPINTO 2 +#define DBG_STEPOVER 3 +#define DBG_STEPOUT 4 + +// debugger.c +extern VOID UpdateDbgCycleCounter(VOID); +extern BOOL CheckBreakpoint(DWORD dwAddr, DWORD wRange, UINT nType); +extern VOID NotifyDebugger(INT nType); +extern VOID DisableDebugger(VOID); +extern LRESULT OnToolDebug(VOID); +extern VOID LoadBreakpointList(HANDLE hFile); +extern VOID SaveBreakpointList(HANDLE hFile); +extern VOID CreateBackupBreakpointList(VOID); +extern VOID RestoreBackupBreakpointList(VOID); diff --git a/Sources/Emu48/disasm.c b/Sources/Emu48/DISASM.C similarity index 95% rename from Sources/Emu48/disasm.c rename to Sources/Emu48/DISASM.C index b9af26f..f5cbe55 100644 --- a/Sources/Emu48/disasm.c +++ b/Sources/Emu48/DISASM.C @@ -1,1847 +1,1847 @@ -/* - * Disasm.c - * - * This file is part of Emu48, a ported version of x48 - * - * Copyright (C) 1994 Eddie C. Dost - * Copyright (C) 1998 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" - -#pragma inline_depth(0) - -#define TAB_SKIP 8 - -BOOL disassembler_mode = HP_MNEMONICS; -BOOL disassembler_symb = FALSE; - -static LPCTSTR hex[] = -{ - _T("0123456789ABCDEF"), - _T("0123456789abcdef") -}; - -static LPCTSTR opcode_0_tbl[32] = -{ - /* - * HP Mnemonics - */ - _T("RTNSXM"), _T("RTN"), _T("RTNSC"), _T("RTNCC"), - _T("SETHEX"), _T("SETDEC"), _T("RSTK=C"), _T("C=RSTK"), - _T("CLRST"), _T("C=ST"), _T("ST=C"), _T("CSTEX"), - _T("P=P+1"), _T("P=P-1"), _T("(NULL)"), _T("RTI"), - /* - * Class Mnemonics - */ - _T("rtnsxm"), _T("rtn"), _T("rtnsc"), _T("rtncc"), - _T("sethex"), _T("setdec"), _T("push"), _T("pop"), - _T("clr.3 st"), _T("move.3 st, c"), _T("move.3 c, st"), _T("exg.3 c, st"), - _T("inc.1 p"), _T("dec.1 p"), _T("(null)"), _T("rti") -}; - -static LPCTSTR op_str_0[16] = -{ - /* - * HP Mnemonics - */ - _T("A=A%cB"), _T("B=B%cC"), _T("C=C%cA"), _T("D=D%cC"), - _T("B=B%cA"), _T("C=C%cB"), _T("A=A%cC"), _T("C=C%cD"), - /* - * Class Mnemonics - */ - _T("b, a"), _T("c, b"), _T("a, c"), _T("c, d"), - _T("a, b"), _T("b, c"), _T("c, a"), _T("d, c") -}; - -static LPCTSTR op_str_1[16] = -{ - /* - * HP Mnemonics - */ - _T("DAT0=A"), _T("DAT1=A"), _T("A=DAT0"), _T("A=DAT1"), - _T("DAT0=C"), _T("DAT1=C"), _T("C=DAT0"), _T("C=DAT1"), - /* - * Class Mnemonics - */ - _T("a, (d0)"), _T("a, (d1)"), _T("(d0), a"), _T("(d1), a"), - _T("c, (d0)"), _T("c, (d1)"), _T("(d0), c"), _T("(d1), c") -}; - -static LPCTSTR in_str_80[32] = -{ - /* - * HP Mnemonics - */ - _T("OUT=CS"), _T("OUT=C"), _T("A=IN"), _T("C=IN"), - _T("UNCNFG"), _T("CONFIG"), _T("C=ID"), _T("SHUTDN"), - NULL, _T("C+P+1"), _T("RESET"), _T("BUSCC"), - NULL, NULL, _T("SREQ?"), NULL, - /* - * Class Mnemonics - */ - _T("move.s c, out"), _T("move.3 c, out"), _T("move.4 in, a"), _T("move.4 in, c"), - _T("uncnfg"), _T("config"), _T("c=id"), _T("shutdn"), - NULL, _T("add.a p+1, c"), _T("reset"), _T("buscc"), - NULL, NULL, _T("sreq?"), NULL -}; - -static LPCTSTR in_str_808[32] = -{ - /* - * HP Mnemonics - */ - _T("INTON"), NULL, NULL, _T("BUSCB"), - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - _T("PC=(A)"), _T("BUSCD"), _T("PC=(C)"), _T("INTOFF"), - /* - * Class Mnemonics - */ - _T("inton"), NULL, NULL, _T("buscb"), - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - _T("jmp (a)"), _T("buscd"), _T("jmp (c)"), _T("intoff") -}; - -static LPCTSTR op_str_81[8] = -{ - /* - * HP Mnemonics - */ - _T("A"), _T("B"), _T("C"), _T("D"), - /* - * Class Mnemonics - */ - _T("a"), _T("b"), _T("c"), _T("d") -}; - -static LPCTSTR in_str_81b[32] = -{ - /* - * HP Mnemonics - */ - NULL, NULL, _T("PC=A"), _T("PC=C"), - _T("A=PC"), _T("C=PC"), _T("APCEX"), _T("CPCEX"), - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - /* - * Class Mnemonics - */ - NULL, NULL, _T("jmp a"), _T("jmp c"), - _T("move.a pc, a"), _T("move.a pc, c"), _T("exg.a a, pc"), _T("exg.a c, pc"), - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL -}; - -static LPCTSTR in_str_9[16] = -{ - /* - * HP Mnemonics - */ - _T("="), _T("#"), _T("="), _T("#"), - _T(">"), _T("<"), _T(">="), _T("<="), - /* - * Class Mnemonics - */ - _T("eq"), _T("ne"), _T("eq"), _T("ne"), - _T("gt"), _T("lt"), _T("ge"), _T("le") -}; - -static LPCTSTR op_str_9[16] = -{ - /* - * HP Mnemonics - */ - _T("?A%sB"), _T("?B%sC"), _T("?C%sA"), _T("?D%sC"), - _T("?A%s0"), _T("?B%s0"), _T("?C%s0"), _T("?D%s0"), - /* - * Class Mnemonics - */ - _T("a, b"), _T("b, c"), _T("c, a"), _T("d, c"), - _T("a, 0"), _T("b, 0"), _T("c, 0"), _T("d, 0") -}; - -static LPCTSTR op_str_af[32] = -{ - /* - * HP Mnemonics - */ - _T("A=A%sB"), _T("B=B%sC"), _T("C=C%sA"), _T("D=D%sC"), - _T("A=A%sA"), _T("B=B%sB"), _T("C=C%sC"), _T("D=D%sD"), - _T("B=B%sA"), _T("C=C%sB"), _T("A=A%sC"), _T("C=C%sD"), - _T("A=B%sA"), _T("B=C%sB"), _T("C=A%sC"), _T("D=C%sD"), - /* - * Class Mnemonics - */ - _T("b, a"), _T("c, b"), _T("a, c"), _T("c, d"), - _T("a, a"), _T("b, b"), _T("c, c"), _T("d, d"), - _T("a, b"), _T("b, c"), _T("c, a"), _T("d, c"), - _T("b, a"), _T("c, b"), _T("a, c"), _T("c, d") -}; - -static LPCTSTR hp_reg_1_af = _T("ABCDABCDBCACABAC"); -static LPCTSTR hp_reg_2_af = _T("0000BCACABCDBCCD"); - -static LPCTSTR field_tbl[32] = -{ - /* - * HP Mnemonics - */ - _T("P"), _T("WP"), _T("XS"), _T("X"), - _T("S"), _T("M"), _T("B"), _T("W"), - _T("P"), _T("WP"), _T("XS"), _T("X"), - _T("S"), _T("M"), _T("B"), _T("A"), - /* - * Class Mnemonics - */ - _T(".p"), _T(".wp"), _T(".xs"), _T(".x"), - _T(".s"), _T(".m"), _T(".b"), _T(".w"), - _T(".p"), _T(".wp"), _T(".xs"), _T(".x"), - _T(".s"), _T(".m"), _T(".b"), _T(".a") -}; - -static LPCTSTR hst_bits[8] = -{ - /* - * HP Mnemonics - */ - _T("XM"), _T("SB"), _T("SR"), _T("MP"), - /* - * Class Mnemonics - */ - _T("xm"), _T("sb"), _T("sr"), _T("mp") -}; - -// general functions - -static BYTE read_nibble (DWORD *p) -{ - return GetMemNib(p); -} - -static int read_int (DWORD *addr, int n) -{ - int i, t; - - for (i = 0, t = 0; i < n; i++) - t |= read_nibble (addr) << (i * 4); - - return t; -} - -static LPTSTR append_str (LPTSTR buf, LPCTSTR str) -{ - while ((*buf = *str++)) - buf++; - return buf; -} - -static LPTSTR append_tab (LPTSTR buf) -{ - int n; - LPTSTR p; - - n = lstrlen (buf); - p = &buf[n]; - n = TAB_SKIP - (n % TAB_SKIP); - while (n--) - *p++ = _T(' '); - *p = 0; - return p; -} - -static __inline LPTSTR append_field (LPTSTR buf, BYTE fn) -{ - return append_str (buf, field_tbl[fn + 16 * disassembler_mode]); -} - -static LPTSTR append_imm_nibble (LPTSTR buf, DWORD *addr, int n) -{ - int i; - BYTE t[16]; - - LPTSTR p = buf; // save start of buffer - - if (disassembler_mode == CLASS_MNEMONICS) - { - *buf++ = _T('#'); - if (n > 1) - *buf++ = _T('$'); - } - else // HP Mnemonics - { - if (n > 1) // hex mode - *buf++ = _T('#'); // insert hex header - } - if (n > 1) - { - DWORD dwAddr = 0; // decoded address - - for (i = 0; i < n; i++) - t[i] = read_nibble (addr); - - for (i = n - 1; i >= 0; i--) - { - dwAddr = (dwAddr << 4) | t[i]; - *buf++ = hex[disassembler_mode][t[i]]; - } - *buf = 0; - - if (n == 5) // 5 nibble address - { - LPCTSTR lpszName; - - if (disassembler_symb && (lpszName = RplGetName(dwAddr)) != NULL) - { - // overwrite number with symbolic name - buf = append_str(p, _T("=")); - buf = append_str(buf, lpszName); - } - } - } - else // single nibble - { - buf += wsprintf (buf, _T("%d"), read_nibble (addr)); - } - return buf; -} - -static LPTSTR append_numaddr (LPTSTR buf, DWORD addr) -{ - int shift; - - if (disassembler_mode == CLASS_MNEMONICS) - { - *buf++ = _T('$'); - } - for (shift = 16; shift >= 0; shift -= 4) - *buf++ = hex[disassembler_mode][(addr >> shift) & 0xF]; - *buf = 0; - return buf; -} - -static LPTSTR append_addr (LPTSTR buf, DWORD addr) -{ - LPCTSTR lpszName; - - if (disassembler_symb && (lpszName = RplGetName(addr)) != NULL) - { - buf = append_str(buf, _T("=")); - buf = append_str(buf, lpszName); - } - else // no symbol - { - buf = append_numaddr (buf, addr); - } - return buf; -} - -static LPTSTR append_r_addr (LPTSTR buf, DWORD *pc, long disp, int n, int offset) -{ - LPCTSTR lpszName; - long sign; - - sign = 1 << (n * 4 - 1); - if (disp & sign) // negative value? - disp |= ~(sign - 1); // expand it to long - *pc = (*pc + disp) & 0xFFFFF; - - if (disassembler_symb && (lpszName = RplGetName(*pc)) != NULL) - { - buf = append_str(buf, _T("=")); // show symbol - buf = append_str(buf, lpszName); - } - else // no symbol - { - if (disp < 0) - { - buf = append_str(buf, _T("-")); - disp = -disp - offset; - } - else - { - buf = append_str(buf, _T("+")); - disp += offset; - } - buf = append_numaddr(buf, disp); // show offset - - buf = append_str(buf, _T(" [")); - buf = append_numaddr(buf, *pc); // show absolute address - buf = append_str(buf, _T("]")); - } - return buf; -} - -static LPTSTR append_hst_bits (LPTSTR buf, int n) -{ - int i; - LPTSTR p = buf; - - switch (disassembler_mode) - { - case HP_MNEMONICS: - for (i = 0; i < 4; i++) - if (n & (1 << i)) - { - p = append_str (p, hst_bits[i + 4 * disassembler_mode]); - } - break; - case CLASS_MNEMONICS: - while (lstrlen (buf) < 4 * TAB_SKIP) - p = append_tab (buf); - p = &buf[lstrlen (buf)]; - p = append_str (p, _T("; hst bits: ")); - - for (buf = p, i = 0; i < 4; i++) - if (n & (1 << i)) - { - if (p != buf) - p = append_str (p, _T(", ")); - p = append_str (p, hst_bits[i + 4 * disassembler_mode]); - } - break; - default: - p = append_str (p, _T("Unknown disassembler mode")); - break; - } - return p; -} - -static LPTSTR disasm_1 (DWORD *addr, LPTSTR out) -{ - BYTE n; - BYTE fn; - LPTSTR p; - TCHAR buf[20]; - TCHAR c; - - p = out; - switch (n = read_nibble (addr)) - { - case 0: - case 1: - fn = read_nibble (addr); - c = (fn < 8); // flag for operand register - fn = (fn & 7); // get register number - if (fn > 4) // unsupported opcode - fn -= 4; // map to valid scratch register - switch (disassembler_mode) - { - case HP_MNEMONICS: - c = (TCHAR) (c ? _T('A') : _T('C')); - if (n == 0) - wsprintf (buf, _T("R%d=%c"), fn, c); - else - wsprintf (buf, _T("%c=R%d"), c, fn); - p = append_str (out, buf); - break; - case CLASS_MNEMONICS: - p = append_str (out, _T("move.w")); - p = append_tab (out); - c = (TCHAR) (c ? _T('a') : _T('c')); - if (n == 0) - wsprintf (buf, _T("%c, r%d"), c, fn); - else - wsprintf (buf, _T("r%d, %c"), fn, c); - p = append_str (p, buf); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 2: - fn = read_nibble (addr); - c = (fn < 8); // flag for operand register - fn = (fn & 7); // get register number - if (fn > 4) // unsupported opcode - fn -= 4; // map to valid scratch register - switch (disassembler_mode) - { - case HP_MNEMONICS: - c = (TCHAR) (c ? _T('A') : _T('C')); - wsprintf (buf, _T("%cR%dEX"), c, fn); - p = append_str (out, buf); - break; - case CLASS_MNEMONICS: - p = append_str (out, _T("exg.w")); - p = append_tab (out); - c = (TCHAR) (c ? _T('a') : _T('c')); - wsprintf (buf, _T("%c, r%d"), c, fn); - p = append_str (p, buf); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 3: - n = read_nibble (addr); - switch (disassembler_mode) - { - case HP_MNEMONICS: - c = (n & 4) ? _T('C') : _T('A'); - if (n & 2) - { - if (n < 8) - { - wsprintf (buf, _T("%cD%dEX"), c, (n & 1)); - } - else - { - wsprintf (buf, _T("%cD%dXS"), c, (n & 1)); - } - } - else - { - if (n < 8) - { - wsprintf (buf, _T("D%d=%c"), (n & 1), c); - } - else - { - wsprintf (buf, _T("D%d=%cS"), (n & 1), c); - } - } - p = append_str (out, buf); - break; - case CLASS_MNEMONICS: - p = append_str (out, (n & 2) ? _T("exg.") : _T("move.")); - p = append_str (p, (n < 8) ? _T("a") : _T("4")); - p = append_tab (out); - c = (n & 4) ? _T('c') : _T('a'); - wsprintf (buf, _T("%c, d%d"), c, (n & 1)); - p = append_str (p, buf); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 4: - case 5: - fn = read_nibble (addr); - switch (disassembler_mode) - { - case HP_MNEMONICS: - p = append_str (out, op_str_1[(fn & 7) + 8 * disassembler_mode]); - p = append_tab (out); - if (n == 4) - { - p = append_str (p, (fn < 8) ? _T("A") : _T("B")); - } - else - { - n = read_nibble (addr); - if (fn < 8) - { - p = append_field (p, n); - } - else - { - wsprintf (buf, _T("%d"), n + 1); - p = append_str (p, buf); - } - } - break; - case CLASS_MNEMONICS: - p = append_str (out, _T("move")); - if (n == 4) - { - p = append_str (p, _T(".")); - p = append_str (p, (fn < 8) ? _T("a") : _T("b")); - } - else - { - n = read_nibble (addr); - if (fn < 8) - { - p = append_field (p, n); - } - else - { - wsprintf (buf, _T(".%d"), n + 1); - p = append_str (p, buf); - } - } - p = append_tab (out); - p = append_str (p, op_str_1[(fn & 7) + 8 * disassembler_mode]); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 6: - case 7: - case 8: - case 0xc: - fn = read_nibble (addr); - switch (disassembler_mode) - { - case HP_MNEMONICS: - if (n == 6 || n == 8) - p = append_str (out, _T("D0=D0")); - else - p = append_str (out, _T("D1=D1")); - if (n < 8) - p = append_str (p, _T("+")); - else - p = append_str (p, _T("-")); - p = append_tab (out); - wsprintf (buf, _T("%d"), fn + 1); - p = append_str (p, buf); - break; - case CLASS_MNEMONICS: - if (n < 8) - p = append_str (out, _T("add.a")); - else - p = append_str (out, _T("sub.a")); - p = append_tab (out); - wsprintf (buf, _T("#%d, "), fn + 1); - p = append_str (p, buf); - if (n == 6 || n == 8) - p = append_str (p, _T("d0")); - else - p = append_str (p, _T("d1")); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 9: - case 0xa: - case 0xb: - case 0xd: - case 0xe: - case 0xf: - c = (TCHAR) ((n < 0xd) ? _T('0') : _T('1')); - switch (n & 3) - { - case 1: - n = 2; - break; - case 2: - n = 4; - break; - case 3: - n = 5; - break; - } - switch (disassembler_mode) - { - case HP_MNEMONICS: - wsprintf (buf, _T("D%c=(%d)"), c, n); - p = append_str (out, buf); - p = append_tab (out); - p = append_imm_nibble (p, addr, n); - break; - case CLASS_MNEMONICS: - if (n == 5) - { - wsprintf (buf, _T("move.a")); - } - else - if (n == 4) - { - wsprintf (buf, _T("move.as")); - } - else - { - wsprintf (buf, _T("move.b")); - } - p = append_str (out, buf); - p = append_tab (out); - p = append_imm_nibble (p, addr, n); - wsprintf (buf, _T(", d%c"), c); - p = append_str (p, buf); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - default: - break; - } - return p; -} - -static LPTSTR disasm_8 (DWORD *addr, LPTSTR out) -{ - BYTE n; - BYTE fn; - BYTE rn; - LPTSTR p = out; - TCHAR c; - TCHAR buf[20]; - DWORD disp, pc; - - fn = read_nibble (addr); - switch (fn) - { - case 0: - n = read_nibble (addr); - if (NULL != (p = (LPTSTR) in_str_80[n + 16 * disassembler_mode])) - { - p = append_str (out, p); - return p; - } - switch (n) - { - case 8: - fn = read_nibble (addr); - if (NULL != (p = (LPTSTR) in_str_808[fn + 16 * disassembler_mode])) - { - p = append_str (out, p); - return p; - } - switch (fn) - { - case 1: - n = read_nibble (addr); - if (n == 0) - { - switch (disassembler_mode) - { - case HP_MNEMONICS: - p = append_str (out, _T("RSI")); - break; - case CLASS_MNEMONICS: - p = append_str (out, _T("rsi")); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - } - else - p = out; // illegal opcode, no output - break; - case 2: - n = read_nibble (addr); - switch (disassembler_mode) - { - case HP_MNEMONICS: - if (n < 5) - { - wsprintf (buf, _T("LA(%d)"), n + 1); - } - else - { - wsprintf (buf, _T("LAHEX")); - } - p = append_str (out, buf); - p = append_tab (out); - p = append_imm_nibble (p, addr, n + 1); - break; - case CLASS_MNEMONICS: - wsprintf (buf, _T("move.%d"), n + 1); - p = append_str (out, buf); - p = append_tab (out); - p = append_imm_nibble (p, addr, n + 1); - wsprintf (buf, _T(", a.p")); - p = append_str (p, buf); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 4: - case 5: - case 8: - case 9: - switch (disassembler_mode) - { - case HP_MNEMONICS: - wsprintf (buf, _T("%cBIT=%d"), (fn & 8) ? _T('C') : _T('A'), - (fn & 1) ? 1 : 0); - p = append_str (out, buf); - p = append_tab (out); - p = append_imm_nibble (p, addr, 1); - break; - case CLASS_MNEMONICS: - p = append_str (out, (fn & 1) ? _T("bset") : _T("bclr")); - p = append_tab (out); - p = append_imm_nibble (p, addr, 1); - p = append_str (p, (fn & 8) ? _T(", c") : _T(", a")); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 6: - case 7: - case 0xa: - case 0xb: - n = read_nibble (addr); - pc = *addr; - disp = read_int (addr, 2); - - switch (disassembler_mode) - { - case HP_MNEMONICS: - c = (TCHAR) ((fn < 0xa) ? _T('A') : _T('C')); - wsprintf (buf, _T("?%cBIT=%d"), c, (fn & 1) ? 1 : 0); - p = append_str (out, buf); - p = append_tab (out); - wsprintf (buf, _T("%d"), n); - p = append_str (p, buf); - if (disp != 0) - { - p = append_str (p, _T(", GOYES ")); - p = append_r_addr (p, &pc, disp, 2, 5); - } - else - p = append_str (p, _T(", RTNYES")); - break; - case CLASS_MNEMONICS: - c = (TCHAR) ((fn < 0xa) ? _T('a') : _T('c')); - p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); - p = append_str (p, (fn & 1) ? _T("bs") : _T("bc")); - p = append_tab (out); - wsprintf (buf, _T("#%d, %c"), n, c); - p = append_str (p, buf); - if (disp != 0) - { - p = append_str (p, _T(", ")); - p = append_r_addr (p, &pc, disp, 2, 5); - } - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - default: - break; - } - break; - - case 0xc: - case 0xd: - case 0xf: - fn = read_nibble (addr); - switch (disassembler_mode) - { - case HP_MNEMONICS: - wsprintf (buf, (n == 0xf) ? _T("%c%cEX") : _T("%c=%c"), - (n == 0xd) ? _T('P') : _T('C'), (n == 0xd) ? _T('C') : _T('P')); - p = append_str (out, buf); - p = append_tab (out); - wsprintf (buf, _T("%d"), fn); - p = append_str (p, buf); - break; - case CLASS_MNEMONICS: - p = append_str (out, (n == 0xf) ? _T("exg.1") : _T("move.1")); - p = append_tab (out); - wsprintf (buf, (n == 0xd) ? _T("p, c.%d") : _T("c.%d, p"), fn); - p = append_str (p, buf); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - default: - break; - } - break; - - case 1: - switch (n = read_nibble (addr)) - { - case 0: - case 1: - case 2: - case 3: - switch (disassembler_mode) - { - case HP_MNEMONICS: - wsprintf (buf, _T("%sSLC"), op_str_81[(n & 3) + 4 * disassembler_mode]); - p = append_str (out, buf); - break; - case CLASS_MNEMONICS: - p = append_str (out, _T("rol.w")); - p = append_tab (out); - p = append_str (p, _T("#4, ")); - p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 4: - case 5: - case 6: - case 7: - switch (disassembler_mode) - { - case HP_MNEMONICS: - wsprintf (buf, _T("%sSRC"), op_str_81[(n & 3) + 4 * disassembler_mode]); - p = append_str (out, buf); - break; - case CLASS_MNEMONICS: - p = append_str (out, _T("ror.w")); - p = append_tab (out); - p = append_str (p, _T("#4, ")); - p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 8: - fn = read_nibble (addr); // get number - n = read_nibble (addr); // get register selector - if ((n & 7) > 3) // illegal opcode - break; // no output - switch (disassembler_mode) - { - case HP_MNEMONICS: - wsprintf (buf, _T("%s=%s%cCON"), - op_str_81[(n & 3) + 4 * disassembler_mode], - op_str_81[(n & 3) + 4 * disassembler_mode], - (n < 8) ? _T('+') : _T('-')); - p = append_str (out, buf); - p = append_tab (out); - p = append_field (p, fn); - fn = read_nibble (addr); - wsprintf (buf, _T(", %d"), fn + 1); - p = append_str (p, buf); - break; - case CLASS_MNEMONICS: - p = append_str (out, (n < 8) ? _T("add") : _T("sub")); - p = append_field (p, fn); - p = append_tab (out); - fn = read_nibble (addr); - wsprintf (buf, _T("#%d, "), fn + 1); - p = append_str (p, buf); - p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 9: - fn = read_nibble (addr); // get field selector - n = read_nibble (addr); // get register selector - if (n > 3) // illegal opcode - break; // no output - switch (disassembler_mode) - { - case HP_MNEMONICS: - wsprintf (buf, _T("%sSRB.F"), op_str_81[n + 4 * disassembler_mode]); - p = append_str (out, buf); - p = append_tab (out); - p = append_field (p, fn); - break; - case CLASS_MNEMONICS: - p = append_str (out, _T("lsr")); - p = append_field (p, fn); - p = append_tab (out); - p = append_str (p, _T("#1, ")); - p = append_str (p, op_str_81[n + 4 * disassembler_mode]); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 0xa: - fn = read_nibble (addr); - n = read_nibble (addr); - if (n > 2) // illegal opcode - break; // no output - c = (TCHAR) read_nibble (addr); - rn = (c & 7); // get register number - c = (c < 8); // flag for operand register - if (rn > 4) // unsupported opcode - rn -= 4; // map to valid scratch register - switch (disassembler_mode) - { - case HP_MNEMONICS: - c = (TCHAR) (c ? _T('A') : _T('C')); - if (n == 2) - { - wsprintf (buf, _T("%cR%dEX.F"), c, rn); - } - else - if (n == 1) - { - wsprintf (buf, _T("%c=R%d.F"), c, rn); - } - else - { - wsprintf (buf, _T("R%d=%c.F"), rn, c); - } - p = append_str (out, buf); - p = append_tab (out); - p = append_field (p, fn); - break; - case CLASS_MNEMONICS: - c = (TCHAR) (c ? _T('a') : _T('c')); - p = append_str (out, (n == 2) ? _T("exg") : _T("move")); - p = append_field (p, fn); - p = append_tab (out); - if (n == 1) - { - wsprintf (buf, _T("r%d"), rn); - p = append_str (p, buf); - } - else - *p++ = c; - p = append_str (p, _T(", ")); - if (n == 1) - *p++ = c; - else - { - wsprintf (buf, _T("r%d"), rn); - p = append_str (p, buf); - } - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 0xb: - n = read_nibble (addr); - if ((n < 2) || (n > 7)) // illegal opcode - break; // no output - - p = append_str (out, in_str_81b[n + 16 * disassembler_mode]); - break; - - case 0xc: - case 0xd: - case 0xe: - case 0xf: - switch (disassembler_mode) - { - case HP_MNEMONICS: - wsprintf (buf, _T("%sSRB"), op_str_81[(n & 3) + 4 * disassembler_mode]); - p = append_str (out, buf); - break; - case CLASS_MNEMONICS: - p = append_str (out, _T("lsr.w")); - p = append_tab (out); - p = append_str (p, _T("#1, ")); - p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - default: - break; - } - break; - - case 2: - n = read_nibble (addr); - switch (disassembler_mode) - { - case HP_MNEMONICS: - if (n == 0xf) - { - p = append_str (out, _T("CLRHST")); - } - else - { - // when not only one bit is set the HS=0 opcode is used - if (n != 1 && n != 2 && n != 4 && n != 8) - { - p = append_str (out, _T("HS=0")); - p = append_tab (out); - wsprintf (buf, _T("%d"), n); - p = append_str (p, buf); - } - else - { - p = append_hst_bits (out, n); - p = append_str (p, _T("=0")); - } - } - break; - case CLASS_MNEMONICS: - p = append_str (out, _T("clr.1")); - p = append_tab (out); - wsprintf (buf, _T("#%d, hst"), n); - p = append_str (p, buf); - p = append_hst_bits (out, n); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 3: - n = read_nibble (addr); - pc = *addr; - disp = read_int (addr, 2); - switch (disassembler_mode) - { - case HP_MNEMONICS: - if (n != 1 && n != 2 && n != 4 && n != 8) - { - p = append_str (out, _T("?HS=0")); - p = append_tab (out); - wsprintf (buf, _T("%d, "), n); - p = append_str (p, buf); - } - else - { - p = append_str (out, _T("?")); - p = append_hst_bits (p, n); - p = append_str (p, _T("=0")); - p = append_tab (out); - } - if (disp != 0) - { - p = append_str (p, _T("GOYES ")); - p = append_r_addr (p, &pc, disp, 2, 3); - } - else - p = append_str (p, _T("RTNYES")); - break; - case CLASS_MNEMONICS: - p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); - p = append_str (p, _T("eq.1")); - p = append_tab (out); - wsprintf (buf, _T("#%d, hst"), n); - p = append_str (p, buf); - if (disp != 0) - { - p = append_str (p, _T(", ")); - p = append_r_addr (p, &pc, disp, 2, 3); - } - p = append_hst_bits (out, n); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 4: - case 5: - switch (disassembler_mode) - { - case HP_MNEMONICS: - wsprintf (buf, _T("ST=%d"), (fn == 4) ? 0 : 1); - p = append_str (out, buf); - p = append_tab (out); - p = append_imm_nibble (p, addr, 1); - break; - case CLASS_MNEMONICS: - p = append_str (out, (fn == 4) ? _T("bclr") : _T("bset")); - p = append_tab (out); - p = append_imm_nibble (p, addr, 1); - p = append_str (p, _T(", st")); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 6: - case 7: - n = read_nibble (addr); - pc = *addr; - disp = read_int (addr, 2); - switch (disassembler_mode) - { - case HP_MNEMONICS: - wsprintf (buf, _T("?ST=%d"), (fn == 6) ? 0 : 1); - p = append_str (out, buf); - p = append_tab (out); - wsprintf (buf, _T("%d"), n); - p = append_str (p, buf); - if (disp != 0) - { - p = append_str (p, _T(", GOYES ")); - p = append_r_addr (p, &pc, disp, 2, 3); - } - else - p = append_str (p, _T(", RTNYES")); - break; - case CLASS_MNEMONICS: - p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); - p = append_str (p, (fn == 6) ? _T("bc") : _T("bs")); - p = append_tab (out); - wsprintf (buf, _T("#%d, st"), n); - p = append_str (p, buf); - if (disp != 0) - { - p = append_str (p, _T(", ")); - p = append_r_addr (p, &pc, disp, 2, 3); - } - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 8: - case 9: - n = read_nibble (addr); - pc = *addr; - disp = read_int (addr, 2); - switch (disassembler_mode) - { - case HP_MNEMONICS: - wsprintf (buf, _T("?P%c"), (fn == 8) ? _T('#') : _T('=')); - p = append_str (out, buf); - p = append_tab (out); - wsprintf (buf, _T("%d"), n); - p = append_str (p, buf); - if (disp != 0) - { - p = append_str (p, _T(", GOYES ")); - p = append_r_addr (p, &pc, disp, 2, 3); - } - else - p = append_str (p, _T(", RTNYES")); - break; - case CLASS_MNEMONICS: - p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); - p = append_str (p, (fn == 8) ? _T("ne.1") : _T("eq.1")); - p = append_tab (out); - wsprintf (buf, _T("#%d, p"), n); - p = append_str (p, buf); - if (disp != 0) - { - p = append_str (p, _T(", ")); - p = append_r_addr (p, &pc, disp, 2, 3); - } - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 0xc: - case 0xe: - pc = *addr; - if (fn == 0xe) - pc += 4; - disp = read_int (addr, 4); - switch (disassembler_mode) - { - case HP_MNEMONICS: - p = append_str (out, (fn == 0xc) ? _T("GOLONG") : _T("GOSUBL")); - p = append_tab (out); - p = append_r_addr (p, &pc, disp, 4, (fn == 0xc) ? 2 : 6); - break; - case CLASS_MNEMONICS: - p = append_str (out, (fn == 0xc) ? _T("bra.4") : _T("bsr.4")); - p = append_tab (out); - p = append_r_addr (p, &pc, disp, 4, (fn == 0xc) ? 2 : 6); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 0xd: - case 0xf: - pc = read_int (addr, 5); - switch (disassembler_mode) - { - case HP_MNEMONICS: - p = append_str (out, (fn == 0xd) ? _T("GOVLNG") : _T("GOSBVL")); - p = append_tab (out); - p = append_addr (p, pc); - break; - case CLASS_MNEMONICS: - p = append_str (out, (fn == 0xd) ? _T("jmp") : _T("jsr")); - p = append_tab (out); - p = append_addr (p, pc); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - default: - break; - } - return p; -} - - -// public functions - -DWORD disassemble (DWORD addr, LPTSTR out) -{ - BYTE n; - BYTE fn; - LPTSTR p = out; - TCHAR c; - TCHAR buf[20]; - DWORD disp, pc; - - switch (n = read_nibble (&addr)) - { - case 0: - if ((n = read_nibble (&addr)) != 0xe) - { - p = append_str (out, opcode_0_tbl[n + 16 * disassembler_mode]); - break; - } - fn = read_nibble (&addr); - n = read_nibble (&addr); - switch (disassembler_mode) - { - case HP_MNEMONICS: - wsprintf (buf, op_str_0[(n & 7) + 8 * HP_MNEMONICS], - (n < 8) ? _T('&') : _T('!')); - p = append_str (out, buf); - p = append_tab (out); - p = append_field (p, fn); - break; - case CLASS_MNEMONICS: - p = append_str (out, (n < 8) ? _T("and") : _T("or")); - p = append_field (p, fn); - p = append_tab (out); - p = append_str (p, op_str_0[(n & 7) + 8 * CLASS_MNEMONICS]); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 1: - p = disasm_1 (&addr, out); - break; - - case 2: - n = read_nibble (&addr); - switch (disassembler_mode) - { - case HP_MNEMONICS: - p = append_str (out, _T("P=")); - p = append_tab (out); - wsprintf (buf, _T("%d"), n); - p = append_str (p, buf); - break; - case CLASS_MNEMONICS: - wsprintf (buf, _T("move.1 #%d, p"), n); - p = append_str (out, buf); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 3: - fn = read_nibble (&addr); - switch (disassembler_mode) - { - case HP_MNEMONICS: - if (fn < 5) - { - wsprintf (buf, _T("LC(%d)"), fn + 1); - } - else - { - wsprintf (buf, _T("LCHEX")); - } - p = append_str (out, buf); - p = append_tab (out); - p = append_imm_nibble (p, &addr, fn + 1); - break; - case CLASS_MNEMONICS: - wsprintf (buf, _T("move.%d"), fn + 1); - p = append_str (out, buf); - p = append_tab (out); - p = append_imm_nibble (p, &addr, fn + 1); - wsprintf (buf, _T(", c.p")); - p = append_str (p, buf); - break; - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 4: - case 5: - pc = addr; - disp = read_int (&addr, 2); - switch (disassembler_mode) - { - case HP_MNEMONICS: - if (disp == 2) - { - p = append_str (out, _T("NOP3")); - break; - } - wsprintf (buf, (disp == 0) ? _T("RTN%sC") : _T("GO%sC"), (n == 4) ? _T("") : _T("N")); - p = append_str (out, buf); - if (disp != 0) - { - p = append_tab (out); - p = append_r_addr (p, &pc, disp, 2, 1); - } - break; - - case CLASS_MNEMONICS: - if (disp == 2) - { - p = append_str (out, _T("nop3")); - break; - } - p = append_str (out, (disp == 0) ? _T("rtc") : _T("bc")); - p = append_str (p, (n == 4) ? _T("s") : _T("c")); - if (disp != 0) - { - p = append_tab (out); - p = append_r_addr (p, &pc, disp, 2, 1); - } - break; - - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 6: - pc = addr; - disp = read_int (&addr, 3); // read GOTO distance - switch (disassembler_mode) - { - case HP_MNEMONICS: - if (disp == 3) // special case "GOTO next instruction" - { - p = append_str (out, _T("NOP4")); - break; - } - if (disp == 4) // special case "GOTO to +4 nibbles" - { - addr++; // skipping the fifth nibble in the opcode - p = append_str (out, _T("NOP5")); - break; - } - p = append_str (out, _T("GOTO")); - p = append_tab (out); - p = append_r_addr (p, &pc, disp, 3, 1); - break; - - case CLASS_MNEMONICS: - if (disp == 3) - { - p = append_str (out, _T("nop4")); - break; - } - if (disp == 4) - { - addr++; // skipping the fifth nibble in the opcode - p = append_str (out, _T("nop5")); - break; - } - p = append_str (out, _T("bra.3")); - p = append_tab (out); - p = append_r_addr (p, &pc, disp, 3, 1); - break; - - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 7: - pc = addr + 3; - disp = read_int (&addr, 3); - switch (disassembler_mode) - { - case HP_MNEMONICS: - p = append_str (out, _T("GOSUB")); - p = append_tab (out); - p = append_r_addr (p, &pc, disp, 3, 4); - break; - - case CLASS_MNEMONICS: - p = append_str (out, _T("bsr.3")); - p = append_tab (out); - p = append_r_addr (p, &pc, disp, 3, 4); - break; - - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - case 8: - fn = read_nibble (&addr); /* PEEK */ - --addr; - if (fn != 0xa && fn != 0xb) - { - p = disasm_8 (&addr, out); - break; - } - /* Fall through */ - - case 9: - fn = read_nibble (&addr); - if (n == 8) - { - c = (TCHAR) ((fn == 0xa) ? 0 : 1); - fn = 0xf; - } - else - { - c = (TCHAR) ((fn < 8) ? 0 : 1); - fn &= 7; - } - - n = read_nibble (&addr); - pc = addr; - disp = read_int (&addr, 2); - - switch (disassembler_mode) - { - case HP_MNEMONICS: - if ((c == 0) && (n >= 8)) - wsprintf (buf, op_str_9[(n & 3) + 8 * HP_MNEMONICS + 4], - in_str_9[((n >> 2) & 3) + 4 * c + 8 * HP_MNEMONICS]); - else - wsprintf (buf, op_str_9[(n & 3) + 8 * HP_MNEMONICS], - in_str_9[((n >> 2) & 3) + 4 * c + 8 * HP_MNEMONICS]); - p = append_str (out, buf); - p = append_tab (out); - p = append_field (p, fn); - p = append_str (p, _T(", ")); - p = append_str (p, (disp == 0) ? _T("RTNYES") : _T("GOYES ")); - if (disp != 0) - { - p = append_r_addr (p, &pc, disp, 2, 3); - } - break; - - case CLASS_MNEMONICS: - p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); - p = append_str (p, in_str_9[((n >> 2) & 3) + 4 * c + 8 * CLASS_MNEMONICS]); - p = append_field (p, fn); - p = append_tab (out); - if ((c == 0) && (n >= 8)) - p = append_str (p, op_str_9[(n & 3) + 8 * CLASS_MNEMONICS + 4]); - else - p = append_str (p, op_str_9[(n & 3) + 8 * CLASS_MNEMONICS]); - if (disp != 0) - { - p = append_str (p, _T(", ")); - p = append_r_addr (p, &pc, disp, 2, 3); - } - break; - - default: - p = append_str (out, _T("Unknown disassembler mode")); - break; - } - break; - - default: - switch (n) - { - case 0xa: - fn = read_nibble (&addr); - c = (TCHAR) ((fn < 8) ? 0 : 1); - fn &= 7; - disp = 0xa; - break; - case 0xb: - fn = read_nibble (&addr); - c = (TCHAR) ((fn < 8) ? 0 : 1); - fn &= 7; - disp = 0xb; - break; - case 0xc: - case 0xd: - fn = 0xf; - c = (TCHAR) (n & 1); - disp = 0xa; - break; - case 0xe: - case 0xf: - fn = 0xf; - c = (TCHAR) (n & 1); - disp = 0xb; - break; - default: - fn = 0; - disp = 0; - c = 0; - break; - } - - n = read_nibble (&addr); - pc = 0; - - switch (disp) - { - case 0xa: - switch (disassembler_mode) - { - case HP_MNEMONICS: - if (c == 0) - { - if (n < 0xc) - { - p = _T("+"); - } - else - { - p = _T("%c=%c-1"); - pc = 2; - } - } - else - { - if (n < 4) - { - p = _T("%c=0"); - pc = 1; - } - else - if (n >= 0xc) - { - p = _T("%c%cEX"); - pc = 3; - } - else - { - p = _T("%c=%c"); - pc = 3; - } - } - break; - - case CLASS_MNEMONICS: - if (c == 0) - { - if (n < 0xc) - { - p = _T("add"); - } - else - { - p = _T("dec"); - pc = 1; - } - } - else - { - if (n < 4) - { - p = _T("clr"); - pc = 1; - } - else - if (n >= 0xc) - { - p = _T("exg"); - } - else - { - p = _T("move"); - if (n < 8) - n -= 4; - } - } - break; - - default: - p = append_str (out, _T("Unknown disassembler mode")); - return addr; - } - break; - - case 0xb: - switch (disassembler_mode) - { - case HP_MNEMONICS: - if (c == 0) - { - if (n >= 0xc) - { - p = _T("-"); - } - else - if ((n >= 4) && (n <= 7)) - { - p = _T("%c=%c+1"); - pc = 2; - n -= 4; - } - else - { - p = _T("-"); - } - } - else - { - if (n < 4) - { - p = _T("%cSL"); - pc = 1; - } - else - if (n < 8) - { - p = _T("%cSR"); - pc = 1; - } - else - if (n < 0xc) - { - p = _T("%c=-%c"); - pc = 2; - } - else - { - p = _T("%c=-%c-1"); - pc = 2; - } - } - break; - - case CLASS_MNEMONICS: - if (c == 0) - { - if (n >= 0xc) - { - p = _T("subr"); - } - else - if ((n >= 4) && (n <= 7)) - { - p = _T("inc"); - pc = 1; - n -= 4; - } - else - { - p = _T("sub"); - } - } - else - { - pc = 1; - if (n < 4) - { - p = _T("lsl"); - } - else - if (n < 8) - { - p = _T("lsr"); - } - else - if (n < 0xc) - { - p = _T("neg"); - } - else - { - p = _T("not"); - } - } - break; - - default: - p = append_str (out, _T("Unknown disassembler mode")); - return addr; - } - break; - - } - - switch (disassembler_mode) - { - case HP_MNEMONICS: - if (pc == 0) - { - wsprintf (buf, op_str_af[n + 16 * HP_MNEMONICS], p); - } - else - if (pc == 1) - { - wsprintf (buf, p, (n & 3) + _T('A')); - } - else - if (pc == 2) - { - wsprintf (buf, p, (n & 3) + _T('A'), (n & 3) + _T('A')); - } - else - { - wsprintf (buf, p, hp_reg_1_af[n], hp_reg_2_af[n]); - } - p = append_str (out, buf); - p = append_tab (out); - p = append_field (p, fn); - break; - - case CLASS_MNEMONICS: - p = append_str (out, p); - p = append_field (p, fn); - p = append_tab (out); - if (pc == 1) - { - wsprintf (buf, _T("%c"), (n & 3) + _T('a')); - p = append_str (p, buf); - } - else - { - p = append_str (p, op_str_af[n + 16 * CLASS_MNEMONICS]); - } - break; - - default: - p = append_str (p, _T("Unknown disassembler mode")); - break; - } - break; - } - *p = 0; - - return addr; -} +/* + * Disasm.c + * + * This file is part of Emu48, a ported version of x48 + * + * Copyright (C) 1994 Eddie C. Dost + * Copyright (C) 1998 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" + +#pragma inline_depth(0) + +#define TAB_SKIP 8 + +BOOL disassembler_mode = HP_MNEMONICS; +BOOL disassembler_symb = FALSE; + +static LPCTSTR hex[] = +{ + _T("0123456789ABCDEF"), + _T("0123456789abcdef") +}; + +static LPCTSTR opcode_0_tbl[32] = +{ + /* + * HP Mnemonics + */ + _T("RTNSXM"), _T("RTN"), _T("RTNSC"), _T("RTNCC"), + _T("SETHEX"), _T("SETDEC"), _T("RSTK=C"), _T("C=RSTK"), + _T("CLRST"), _T("C=ST"), _T("ST=C"), _T("CSTEX"), + _T("P=P+1"), _T("P=P-1"), _T("(NULL)"), _T("RTI"), + /* + * Class Mnemonics + */ + _T("rtnsxm"), _T("rtn"), _T("rtnsc"), _T("rtncc"), + _T("sethex"), _T("setdec"), _T("push"), _T("pop"), + _T("clr.3 st"), _T("move.3 st, c"), _T("move.3 c, st"), _T("exg.3 c, st"), + _T("inc.1 p"), _T("dec.1 p"), _T("(null)"), _T("rti") +}; + +static LPCTSTR op_str_0[16] = +{ + /* + * HP Mnemonics + */ + _T("A=A%cB"), _T("B=B%cC"), _T("C=C%cA"), _T("D=D%cC"), + _T("B=B%cA"), _T("C=C%cB"), _T("A=A%cC"), _T("C=C%cD"), + /* + * Class Mnemonics + */ + _T("b, a"), _T("c, b"), _T("a, c"), _T("c, d"), + _T("a, b"), _T("b, c"), _T("c, a"), _T("d, c") +}; + +static LPCTSTR op_str_1[16] = +{ + /* + * HP Mnemonics + */ + _T("DAT0=A"), _T("DAT1=A"), _T("A=DAT0"), _T("A=DAT1"), + _T("DAT0=C"), _T("DAT1=C"), _T("C=DAT0"), _T("C=DAT1"), + /* + * Class Mnemonics + */ + _T("a, (d0)"), _T("a, (d1)"), _T("(d0), a"), _T("(d1), a"), + _T("c, (d0)"), _T("c, (d1)"), _T("(d0), c"), _T("(d1), c") +}; + +static LPCTSTR in_str_80[32] = +{ + /* + * HP Mnemonics + */ + _T("OUT=CS"), _T("OUT=C"), _T("A=IN"), _T("C=IN"), + _T("UNCNFG"), _T("CONFIG"), _T("C=ID"), _T("SHUTDN"), + NULL, _T("C+P+1"), _T("RESET"), _T("BUSCC"), + NULL, NULL, _T("SREQ?"), NULL, + /* + * Class Mnemonics + */ + _T("move.s c, out"), _T("move.3 c, out"), _T("move.4 in, a"), _T("move.4 in, c"), + _T("uncnfg"), _T("config"), _T("c=id"), _T("shutdn"), + NULL, _T("add.a p+1, c"), _T("reset"), _T("buscc"), + NULL, NULL, _T("sreq?"), NULL +}; + +static LPCTSTR in_str_808[32] = +{ + /* + * HP Mnemonics + */ + _T("INTON"), NULL, NULL, _T("BUSCB"), + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + _T("PC=(A)"), _T("BUSCD"), _T("PC=(C)"), _T("INTOFF"), + /* + * Class Mnemonics + */ + _T("inton"), NULL, NULL, _T("buscb"), + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + _T("jmp (a)"), _T("buscd"), _T("jmp (c)"), _T("intoff") +}; + +static LPCTSTR op_str_81[8] = +{ + /* + * HP Mnemonics + */ + _T("A"), _T("B"), _T("C"), _T("D"), + /* + * Class Mnemonics + */ + _T("a"), _T("b"), _T("c"), _T("d") +}; + +static LPCTSTR in_str_81b[32] = +{ + /* + * HP Mnemonics + */ + NULL, NULL, _T("PC=A"), _T("PC=C"), + _T("A=PC"), _T("C=PC"), _T("APCEX"), _T("CPCEX"), + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + /* + * Class Mnemonics + */ + NULL, NULL, _T("jmp a"), _T("jmp c"), + _T("move.a pc, a"), _T("move.a pc, c"), _T("exg.a a, pc"), _T("exg.a c, pc"), + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +static LPCTSTR in_str_9[16] = +{ + /* + * HP Mnemonics + */ + _T("="), _T("#"), _T("="), _T("#"), + _T(">"), _T("<"), _T(">="), _T("<="), + /* + * Class Mnemonics + */ + _T("eq"), _T("ne"), _T("eq"), _T("ne"), + _T("gt"), _T("lt"), _T("ge"), _T("le") +}; + +static LPCTSTR op_str_9[16] = +{ + /* + * HP Mnemonics + */ + _T("?A%sB"), _T("?B%sC"), _T("?C%sA"), _T("?D%sC"), + _T("?A%s0"), _T("?B%s0"), _T("?C%s0"), _T("?D%s0"), + /* + * Class Mnemonics + */ + _T("a, b"), _T("b, c"), _T("c, a"), _T("d, c"), + _T("a, 0"), _T("b, 0"), _T("c, 0"), _T("d, 0") +}; + +static LPCTSTR op_str_af[32] = +{ + /* + * HP Mnemonics + */ + _T("A=A%sB"), _T("B=B%sC"), _T("C=C%sA"), _T("D=D%sC"), + _T("A=A%sA"), _T("B=B%sB"), _T("C=C%sC"), _T("D=D%sD"), + _T("B=B%sA"), _T("C=C%sB"), _T("A=A%sC"), _T("C=C%sD"), + _T("A=B%sA"), _T("B=C%sB"), _T("C=A%sC"), _T("D=C%sD"), + /* + * Class Mnemonics + */ + _T("b, a"), _T("c, b"), _T("a, c"), _T("c, d"), + _T("a, a"), _T("b, b"), _T("c, c"), _T("d, d"), + _T("a, b"), _T("b, c"), _T("c, a"), _T("d, c"), + _T("b, a"), _T("c, b"), _T("a, c"), _T("c, d") +}; + +static LPCTSTR hp_reg_1_af = _T("ABCDABCDBCACABAC"); +static LPCTSTR hp_reg_2_af = _T("0000BCACABCDBCCD"); + +static LPCTSTR field_tbl[32] = +{ + /* + * HP Mnemonics + */ + _T("P"), _T("WP"), _T("XS"), _T("X"), + _T("S"), _T("M"), _T("B"), _T("W"), + _T("P"), _T("WP"), _T("XS"), _T("X"), + _T("S"), _T("M"), _T("B"), _T("A"), + /* + * Class Mnemonics + */ + _T(".p"), _T(".wp"), _T(".xs"), _T(".x"), + _T(".s"), _T(".m"), _T(".b"), _T(".w"), + _T(".p"), _T(".wp"), _T(".xs"), _T(".x"), + _T(".s"), _T(".m"), _T(".b"), _T(".a") +}; + +static LPCTSTR hst_bits[8] = +{ + /* + * HP Mnemonics + */ + _T("XM"), _T("SB"), _T("SR"), _T("MP"), + /* + * Class Mnemonics + */ + _T("xm"), _T("sb"), _T("sr"), _T("mp") +}; + +// general functions + +static BYTE read_nibble (DWORD *p) +{ + return GetMemNib(p); +} + +static int read_int (DWORD *addr, int n) +{ + int i, t; + + for (i = 0, t = 0; i < n; i++) + t |= read_nibble (addr) << (i * 4); + + return t; +} + +static LPTSTR append_str (LPTSTR buf, LPCTSTR str) +{ + while ((*buf = *str++)) + buf++; + return buf; +} + +static LPTSTR append_tab (LPTSTR buf) +{ + int n; + LPTSTR p; + + n = lstrlen (buf); + p = &buf[n]; + n = TAB_SKIP - (n % TAB_SKIP); + while (n--) + *p++ = _T(' '); + *p = 0; + return p; +} + +static __inline LPTSTR append_field (LPTSTR buf, BYTE fn) +{ + return append_str (buf, field_tbl[fn + 16 * disassembler_mode]); +} + +static LPTSTR append_imm_nibble (LPTSTR buf, DWORD *addr, int n) +{ + int i; + BYTE t[16]; + + LPTSTR p = buf; // save start of buffer + + if (disassembler_mode == CLASS_MNEMONICS) + { + *buf++ = _T('#'); + if (n > 1) + *buf++ = _T('$'); + } + else // HP Mnemonics + { + if (n > 1) // hex mode + *buf++ = _T('#'); // insert hex header + } + if (n > 1) + { + DWORD dwAddr = 0; // decoded address + + for (i = 0; i < n; i++) + t[i] = read_nibble (addr); + + for (i = n - 1; i >= 0; i--) + { + dwAddr = (dwAddr << 4) | t[i]; + *buf++ = hex[disassembler_mode][t[i]]; + } + *buf = 0; + + if (n == 5) // 5 nibble address + { + LPCTSTR lpszName; + + if (disassembler_symb && (lpszName = RplGetName(dwAddr)) != NULL) + { + // overwrite number with symbolic name + buf = append_str(p, _T("=")); + buf = append_str(buf, lpszName); + } + } + } + else // single nibble + { + buf += wsprintf (buf, _T("%d"), read_nibble (addr)); + } + return buf; +} + +static LPTSTR append_numaddr (LPTSTR buf, DWORD addr) +{ + int shift; + + if (disassembler_mode == CLASS_MNEMONICS) + { + *buf++ = _T('$'); + } + for (shift = 16; shift >= 0; shift -= 4) + *buf++ = hex[disassembler_mode][(addr >> shift) & 0xF]; + *buf = 0; + return buf; +} + +static LPTSTR append_addr (LPTSTR buf, DWORD addr) +{ + LPCTSTR lpszName; + + if (disassembler_symb && (lpszName = RplGetName(addr)) != NULL) + { + buf = append_str(buf, _T("=")); + buf = append_str(buf, lpszName); + } + else // no symbol + { + buf = append_numaddr (buf, addr); + } + return buf; +} + +static LPTSTR append_r_addr (LPTSTR buf, DWORD *pc, long disp, int n, int offset) +{ + LPCTSTR lpszName; + long sign; + + sign = 1 << (n * 4 - 1); + if (disp & sign) // negative value? + disp |= ~(sign - 1); // expand it to long + *pc = (*pc + disp) & 0xFFFFF; + + if (disassembler_symb && (lpszName = RplGetName(*pc)) != NULL) + { + buf = append_str(buf, _T("=")); // show symbol + buf = append_str(buf, lpszName); + } + else // no symbol + { + if (disp < 0) + { + buf = append_str(buf, _T("-")); + disp = -disp - offset; + } + else + { + buf = append_str(buf, _T("+")); + disp += offset; + } + buf = append_numaddr(buf, disp); // show offset + + buf = append_str(buf, _T(" [")); + buf = append_numaddr(buf, *pc); // show absolute address + buf = append_str(buf, _T("]")); + } + return buf; +} + +static LPTSTR append_hst_bits (LPTSTR buf, int n) +{ + int i; + LPTSTR p = buf; + + switch (disassembler_mode) + { + case HP_MNEMONICS: + for (i = 0; i < 4; i++) + if (n & (1 << i)) + { + p = append_str (p, hst_bits[i + 4 * disassembler_mode]); + } + break; + case CLASS_MNEMONICS: + while (lstrlen (buf) < 4 * TAB_SKIP) + p = append_tab (buf); + p = &buf[lstrlen (buf)]; + p = append_str (p, _T("; hst bits: ")); + + for (buf = p, i = 0; i < 4; i++) + if (n & (1 << i)) + { + if (p != buf) + p = append_str (p, _T(", ")); + p = append_str (p, hst_bits[i + 4 * disassembler_mode]); + } + break; + default: + p = append_str (p, _T("Unknown disassembler mode")); + break; + } + return p; +} + +static LPTSTR disasm_1 (DWORD *addr, LPTSTR out) +{ + BYTE n; + BYTE fn; + LPTSTR p; + TCHAR buf[20]; + TCHAR c; + + p = out; + switch (n = read_nibble (addr)) + { + case 0: + case 1: + fn = read_nibble (addr); + c = (fn < 8); // flag for operand register + fn = (fn & 7); // get register number + if (fn > 4) // unsupported opcode + fn -= 4; // map to valid scratch register + switch (disassembler_mode) + { + case HP_MNEMONICS: + c = (TCHAR) (c ? _T('A') : _T('C')); + if (n == 0) + wsprintf (buf, _T("R%d=%c"), fn, c); + else + wsprintf (buf, _T("%c=R%d"), c, fn); + p = append_str (out, buf); + break; + case CLASS_MNEMONICS: + p = append_str (out, _T("move.w")); + p = append_tab (out); + c = (TCHAR) (c ? _T('a') : _T('c')); + if (n == 0) + wsprintf (buf, _T("%c, r%d"), c, fn); + else + wsprintf (buf, _T("r%d, %c"), fn, c); + p = append_str (p, buf); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 2: + fn = read_nibble (addr); + c = (fn < 8); // flag for operand register + fn = (fn & 7); // get register number + if (fn > 4) // unsupported opcode + fn -= 4; // map to valid scratch register + switch (disassembler_mode) + { + case HP_MNEMONICS: + c = (TCHAR) (c ? _T('A') : _T('C')); + wsprintf (buf, _T("%cR%dEX"), c, fn); + p = append_str (out, buf); + break; + case CLASS_MNEMONICS: + p = append_str (out, _T("exg.w")); + p = append_tab (out); + c = (TCHAR) (c ? _T('a') : _T('c')); + wsprintf (buf, _T("%c, r%d"), c, fn); + p = append_str (p, buf); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 3: + n = read_nibble (addr); + switch (disassembler_mode) + { + case HP_MNEMONICS: + c = (n & 4) ? _T('C') : _T('A'); + if (n & 2) + { + if (n < 8) + { + wsprintf (buf, _T("%cD%dEX"), c, (n & 1)); + } + else + { + wsprintf (buf, _T("%cD%dXS"), c, (n & 1)); + } + } + else + { + if (n < 8) + { + wsprintf (buf, _T("D%d=%c"), (n & 1), c); + } + else + { + wsprintf (buf, _T("D%d=%cS"), (n & 1), c); + } + } + p = append_str (out, buf); + break; + case CLASS_MNEMONICS: + p = append_str (out, (n & 2) ? _T("exg.") : _T("move.")); + p = append_str (p, (n < 8) ? _T("a") : _T("4")); + p = append_tab (out); + c = (n & 4) ? _T('c') : _T('a'); + wsprintf (buf, _T("%c, d%d"), c, (n & 1)); + p = append_str (p, buf); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 4: + case 5: + fn = read_nibble (addr); + switch (disassembler_mode) + { + case HP_MNEMONICS: + p = append_str (out, op_str_1[(fn & 7) + 8 * disassembler_mode]); + p = append_tab (out); + if (n == 4) + { + p = append_str (p, (fn < 8) ? _T("A") : _T("B")); + } + else + { + n = read_nibble (addr); + if (fn < 8) + { + p = append_field (p, n); + } + else + { + wsprintf (buf, _T("%d"), n + 1); + p = append_str (p, buf); + } + } + break; + case CLASS_MNEMONICS: + p = append_str (out, _T("move")); + if (n == 4) + { + p = append_str (p, _T(".")); + p = append_str (p, (fn < 8) ? _T("a") : _T("b")); + } + else + { + n = read_nibble (addr); + if (fn < 8) + { + p = append_field (p, n); + } + else + { + wsprintf (buf, _T(".%d"), n + 1); + p = append_str (p, buf); + } + } + p = append_tab (out); + p = append_str (p, op_str_1[(fn & 7) + 8 * disassembler_mode]); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 6: + case 7: + case 8: + case 0xc: + fn = read_nibble (addr); + switch (disassembler_mode) + { + case HP_MNEMONICS: + if (n == 6 || n == 8) + p = append_str (out, _T("D0=D0")); + else + p = append_str (out, _T("D1=D1")); + if (n < 8) + p = append_str (p, _T("+")); + else + p = append_str (p, _T("-")); + p = append_tab (out); + wsprintf (buf, _T("%d"), fn + 1); + p = append_str (p, buf); + break; + case CLASS_MNEMONICS: + if (n < 8) + p = append_str (out, _T("add.a")); + else + p = append_str (out, _T("sub.a")); + p = append_tab (out); + wsprintf (buf, _T("#%d, "), fn + 1); + p = append_str (p, buf); + if (n == 6 || n == 8) + p = append_str (p, _T("d0")); + else + p = append_str (p, _T("d1")); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 9: + case 0xa: + case 0xb: + case 0xd: + case 0xe: + case 0xf: + c = (TCHAR) ((n < 0xd) ? _T('0') : _T('1')); + switch (n & 3) + { + case 1: + n = 2; + break; + case 2: + n = 4; + break; + case 3: + n = 5; + break; + } + switch (disassembler_mode) + { + case HP_MNEMONICS: + wsprintf (buf, _T("D%c=(%d)"), c, n); + p = append_str (out, buf); + p = append_tab (out); + p = append_imm_nibble (p, addr, n); + break; + case CLASS_MNEMONICS: + if (n == 5) + { + wsprintf (buf, _T("move.a")); + } + else + if (n == 4) + { + wsprintf (buf, _T("move.as")); + } + else + { + wsprintf (buf, _T("move.b")); + } + p = append_str (out, buf); + p = append_tab (out); + p = append_imm_nibble (p, addr, n); + wsprintf (buf, _T(", d%c"), c); + p = append_str (p, buf); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + default: + break; + } + return p; +} + +static LPTSTR disasm_8 (DWORD *addr, LPTSTR out) +{ + BYTE n; + BYTE fn; + BYTE rn; + LPTSTR p = out; + TCHAR c; + TCHAR buf[20]; + DWORD disp, pc; + + fn = read_nibble (addr); + switch (fn) + { + case 0: + n = read_nibble (addr); + if (NULL != (p = (LPTSTR) in_str_80[n + 16 * disassembler_mode])) + { + p = append_str (out, p); + return p; + } + switch (n) + { + case 8: + fn = read_nibble (addr); + if (NULL != (p = (LPTSTR) in_str_808[fn + 16 * disassembler_mode])) + { + p = append_str (out, p); + return p; + } + switch (fn) + { + case 1: + n = read_nibble (addr); + if (n == 0) + { + switch (disassembler_mode) + { + case HP_MNEMONICS: + p = append_str (out, _T("RSI")); + break; + case CLASS_MNEMONICS: + p = append_str (out, _T("rsi")); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + } + else + p = out; // illegal opcode, no output + break; + case 2: + n = read_nibble (addr); + switch (disassembler_mode) + { + case HP_MNEMONICS: + if (n < 5) + { + wsprintf (buf, _T("LA(%d)"), n + 1); + } + else + { + wsprintf (buf, _T("LAHEX")); + } + p = append_str (out, buf); + p = append_tab (out); + p = append_imm_nibble (p, addr, n + 1); + break; + case CLASS_MNEMONICS: + wsprintf (buf, _T("move.%d"), n + 1); + p = append_str (out, buf); + p = append_tab (out); + p = append_imm_nibble (p, addr, n + 1); + wsprintf (buf, _T(", a.p")); + p = append_str (p, buf); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 4: + case 5: + case 8: + case 9: + switch (disassembler_mode) + { + case HP_MNEMONICS: + wsprintf (buf, _T("%cBIT=%d"), (fn & 8) ? _T('C') : _T('A'), + (fn & 1) ? 1 : 0); + p = append_str (out, buf); + p = append_tab (out); + p = append_imm_nibble (p, addr, 1); + break; + case CLASS_MNEMONICS: + p = append_str (out, (fn & 1) ? _T("bset") : _T("bclr")); + p = append_tab (out); + p = append_imm_nibble (p, addr, 1); + p = append_str (p, (fn & 8) ? _T(", c") : _T(", a")); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 6: + case 7: + case 0xa: + case 0xb: + n = read_nibble (addr); + pc = *addr; + disp = read_int (addr, 2); + + switch (disassembler_mode) + { + case HP_MNEMONICS: + c = (TCHAR) ((fn < 0xa) ? _T('A') : _T('C')); + wsprintf (buf, _T("?%cBIT=%d"), c, (fn & 1) ? 1 : 0); + p = append_str (out, buf); + p = append_tab (out); + wsprintf (buf, _T("%d"), n); + p = append_str (p, buf); + if (disp != 0) + { + p = append_str (p, _T(", GOYES ")); + p = append_r_addr (p, &pc, disp, 2, 5); + } + else + p = append_str (p, _T(", RTNYES")); + break; + case CLASS_MNEMONICS: + c = (TCHAR) ((fn < 0xa) ? _T('a') : _T('c')); + p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); + p = append_str (p, (fn & 1) ? _T("bs") : _T("bc")); + p = append_tab (out); + wsprintf (buf, _T("#%d, %c"), n, c); + p = append_str (p, buf); + if (disp != 0) + { + p = append_str (p, _T(", ")); + p = append_r_addr (p, &pc, disp, 2, 5); + } + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + default: + break; + } + break; + + case 0xc: + case 0xd: + case 0xf: + fn = read_nibble (addr); + switch (disassembler_mode) + { + case HP_MNEMONICS: + wsprintf (buf, (n == 0xf) ? _T("%c%cEX") : _T("%c=%c"), + (n == 0xd) ? _T('P') : _T('C'), (n == 0xd) ? _T('C') : _T('P')); + p = append_str (out, buf); + p = append_tab (out); + wsprintf (buf, _T("%d"), fn); + p = append_str (p, buf); + break; + case CLASS_MNEMONICS: + p = append_str (out, (n == 0xf) ? _T("exg.1") : _T("move.1")); + p = append_tab (out); + wsprintf (buf, (n == 0xd) ? _T("p, c.%d") : _T("c.%d, p"), fn); + p = append_str (p, buf); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + default: + break; + } + break; + + case 1: + switch (n = read_nibble (addr)) + { + case 0: + case 1: + case 2: + case 3: + switch (disassembler_mode) + { + case HP_MNEMONICS: + wsprintf (buf, _T("%sSLC"), op_str_81[(n & 3) + 4 * disassembler_mode]); + p = append_str (out, buf); + break; + case CLASS_MNEMONICS: + p = append_str (out, _T("rol.w")); + p = append_tab (out); + p = append_str (p, _T("#4, ")); + p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 4: + case 5: + case 6: + case 7: + switch (disassembler_mode) + { + case HP_MNEMONICS: + wsprintf (buf, _T("%sSRC"), op_str_81[(n & 3) + 4 * disassembler_mode]); + p = append_str (out, buf); + break; + case CLASS_MNEMONICS: + p = append_str (out, _T("ror.w")); + p = append_tab (out); + p = append_str (p, _T("#4, ")); + p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 8: + fn = read_nibble (addr); // get number + n = read_nibble (addr); // get register selector + if ((n & 7) > 3) // illegal opcode + break; // no output + switch (disassembler_mode) + { + case HP_MNEMONICS: + wsprintf (buf, _T("%s=%s%cCON"), + op_str_81[(n & 3) + 4 * disassembler_mode], + op_str_81[(n & 3) + 4 * disassembler_mode], + (n < 8) ? _T('+') : _T('-')); + p = append_str (out, buf); + p = append_tab (out); + p = append_field (p, fn); + fn = read_nibble (addr); + wsprintf (buf, _T(", %d"), fn + 1); + p = append_str (p, buf); + break; + case CLASS_MNEMONICS: + p = append_str (out, (n < 8) ? _T("add") : _T("sub")); + p = append_field (p, fn); + p = append_tab (out); + fn = read_nibble (addr); + wsprintf (buf, _T("#%d, "), fn + 1); + p = append_str (p, buf); + p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 9: + fn = read_nibble (addr); // get field selector + n = read_nibble (addr); // get register selector + if (n > 3) // illegal opcode + break; // no output + switch (disassembler_mode) + { + case HP_MNEMONICS: + wsprintf (buf, _T("%sSRB.F"), op_str_81[n + 4 * disassembler_mode]); + p = append_str (out, buf); + p = append_tab (out); + p = append_field (p, fn); + break; + case CLASS_MNEMONICS: + p = append_str (out, _T("lsr")); + p = append_field (p, fn); + p = append_tab (out); + p = append_str (p, _T("#1, ")); + p = append_str (p, op_str_81[n + 4 * disassembler_mode]); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 0xa: + fn = read_nibble (addr); + n = read_nibble (addr); + if (n > 2) // illegal opcode + break; // no output + c = (TCHAR) read_nibble (addr); + rn = (c & 7); // get register number + c = (c < 8); // flag for operand register + if (rn > 4) // unsupported opcode + rn -= 4; // map to valid scratch register + switch (disassembler_mode) + { + case HP_MNEMONICS: + c = (TCHAR) (c ? _T('A') : _T('C')); + if (n == 2) + { + wsprintf (buf, _T("%cR%dEX.F"), c, rn); + } + else + if (n == 1) + { + wsprintf (buf, _T("%c=R%d.F"), c, rn); + } + else + { + wsprintf (buf, _T("R%d=%c.F"), rn, c); + } + p = append_str (out, buf); + p = append_tab (out); + p = append_field (p, fn); + break; + case CLASS_MNEMONICS: + c = (TCHAR) (c ? _T('a') : _T('c')); + p = append_str (out, (n == 2) ? _T("exg") : _T("move")); + p = append_field (p, fn); + p = append_tab (out); + if (n == 1) + { + wsprintf (buf, _T("r%d"), rn); + p = append_str (p, buf); + } + else + *p++ = c; + p = append_str (p, _T(", ")); + if (n == 1) + *p++ = c; + else + { + wsprintf (buf, _T("r%d"), rn); + p = append_str (p, buf); + } + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 0xb: + n = read_nibble (addr); + if ((n < 2) || (n > 7)) // illegal opcode + break; // no output + + p = append_str (out, in_str_81b[n + 16 * disassembler_mode]); + break; + + case 0xc: + case 0xd: + case 0xe: + case 0xf: + switch (disassembler_mode) + { + case HP_MNEMONICS: + wsprintf (buf, _T("%sSRB"), op_str_81[(n & 3) + 4 * disassembler_mode]); + p = append_str (out, buf); + break; + case CLASS_MNEMONICS: + p = append_str (out, _T("lsr.w")); + p = append_tab (out); + p = append_str (p, _T("#1, ")); + p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + default: + break; + } + break; + + case 2: + n = read_nibble (addr); + switch (disassembler_mode) + { + case HP_MNEMONICS: + if (n == 0xf) + { + p = append_str (out, _T("CLRHST")); + } + else + { + // when not only one bit is set the HS=0 opcode is used + if (n != 1 && n != 2 && n != 4 && n != 8) + { + p = append_str (out, _T("HS=0")); + p = append_tab (out); + wsprintf (buf, _T("%d"), n); + p = append_str (p, buf); + } + else + { + p = append_hst_bits (out, n); + p = append_str (p, _T("=0")); + } + } + break; + case CLASS_MNEMONICS: + p = append_str (out, _T("clr.1")); + p = append_tab (out); + wsprintf (buf, _T("#%d, hst"), n); + p = append_str (p, buf); + p = append_hst_bits (out, n); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 3: + n = read_nibble (addr); + pc = *addr; + disp = read_int (addr, 2); + switch (disassembler_mode) + { + case HP_MNEMONICS: + if (n != 1 && n != 2 && n != 4 && n != 8) + { + p = append_str (out, _T("?HS=0")); + p = append_tab (out); + wsprintf (buf, _T("%d, "), n); + p = append_str (p, buf); + } + else + { + p = append_str (out, _T("?")); + p = append_hst_bits (p, n); + p = append_str (p, _T("=0")); + p = append_tab (out); + } + if (disp != 0) + { + p = append_str (p, _T("GOYES ")); + p = append_r_addr (p, &pc, disp, 2, 3); + } + else + p = append_str (p, _T("RTNYES")); + break; + case CLASS_MNEMONICS: + p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); + p = append_str (p, _T("eq.1")); + p = append_tab (out); + wsprintf (buf, _T("#%d, hst"), n); + p = append_str (p, buf); + if (disp != 0) + { + p = append_str (p, _T(", ")); + p = append_r_addr (p, &pc, disp, 2, 3); + } + p = append_hst_bits (out, n); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 4: + case 5: + switch (disassembler_mode) + { + case HP_MNEMONICS: + wsprintf (buf, _T("ST=%d"), (fn == 4) ? 0 : 1); + p = append_str (out, buf); + p = append_tab (out); + p = append_imm_nibble (p, addr, 1); + break; + case CLASS_MNEMONICS: + p = append_str (out, (fn == 4) ? _T("bclr") : _T("bset")); + p = append_tab (out); + p = append_imm_nibble (p, addr, 1); + p = append_str (p, _T(", st")); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 6: + case 7: + n = read_nibble (addr); + pc = *addr; + disp = read_int (addr, 2); + switch (disassembler_mode) + { + case HP_MNEMONICS: + wsprintf (buf, _T("?ST=%d"), (fn == 6) ? 0 : 1); + p = append_str (out, buf); + p = append_tab (out); + wsprintf (buf, _T("%d"), n); + p = append_str (p, buf); + if (disp != 0) + { + p = append_str (p, _T(", GOYES ")); + p = append_r_addr (p, &pc, disp, 2, 3); + } + else + p = append_str (p, _T(", RTNYES")); + break; + case CLASS_MNEMONICS: + p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); + p = append_str (p, (fn == 6) ? _T("bc") : _T("bs")); + p = append_tab (out); + wsprintf (buf, _T("#%d, st"), n); + p = append_str (p, buf); + if (disp != 0) + { + p = append_str (p, _T(", ")); + p = append_r_addr (p, &pc, disp, 2, 3); + } + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 8: + case 9: + n = read_nibble (addr); + pc = *addr; + disp = read_int (addr, 2); + switch (disassembler_mode) + { + case HP_MNEMONICS: + wsprintf (buf, _T("?P%c"), (fn == 8) ? _T('#') : _T('=')); + p = append_str (out, buf); + p = append_tab (out); + wsprintf (buf, _T("%d"), n); + p = append_str (p, buf); + if (disp != 0) + { + p = append_str (p, _T(", GOYES ")); + p = append_r_addr (p, &pc, disp, 2, 3); + } + else + p = append_str (p, _T(", RTNYES")); + break; + case CLASS_MNEMONICS: + p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); + p = append_str (p, (fn == 8) ? _T("ne.1") : _T("eq.1")); + p = append_tab (out); + wsprintf (buf, _T("#%d, p"), n); + p = append_str (p, buf); + if (disp != 0) + { + p = append_str (p, _T(", ")); + p = append_r_addr (p, &pc, disp, 2, 3); + } + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 0xc: + case 0xe: + pc = *addr; + if (fn == 0xe) + pc += 4; + disp = read_int (addr, 4); + switch (disassembler_mode) + { + case HP_MNEMONICS: + p = append_str (out, (fn == 0xc) ? _T("GOLONG") : _T("GOSUBL")); + p = append_tab (out); + p = append_r_addr (p, &pc, disp, 4, (fn == 0xc) ? 2 : 6); + break; + case CLASS_MNEMONICS: + p = append_str (out, (fn == 0xc) ? _T("bra.4") : _T("bsr.4")); + p = append_tab (out); + p = append_r_addr (p, &pc, disp, 4, (fn == 0xc) ? 2 : 6); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 0xd: + case 0xf: + pc = read_int (addr, 5); + switch (disassembler_mode) + { + case HP_MNEMONICS: + p = append_str (out, (fn == 0xd) ? _T("GOVLNG") : _T("GOSBVL")); + p = append_tab (out); + p = append_addr (p, pc); + break; + case CLASS_MNEMONICS: + p = append_str (out, (fn == 0xd) ? _T("jmp") : _T("jsr")); + p = append_tab (out); + p = append_addr (p, pc); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + default: + break; + } + return p; +} + + +// public functions + +DWORD disassemble (DWORD addr, LPTSTR out) +{ + BYTE n; + BYTE fn; + LPTSTR p = out; + TCHAR c; + TCHAR buf[20]; + DWORD disp, pc; + + switch (n = read_nibble (&addr)) + { + case 0: + if ((n = read_nibble (&addr)) != 0xe) + { + p = append_str (out, opcode_0_tbl[n + 16 * disassembler_mode]); + break; + } + fn = read_nibble (&addr); + n = read_nibble (&addr); + switch (disassembler_mode) + { + case HP_MNEMONICS: + wsprintf (buf, op_str_0[(n & 7) + 8 * HP_MNEMONICS], + (n < 8) ? _T('&') : _T('!')); + p = append_str (out, buf); + p = append_tab (out); + p = append_field (p, fn); + break; + case CLASS_MNEMONICS: + p = append_str (out, (n < 8) ? _T("and") : _T("or")); + p = append_field (p, fn); + p = append_tab (out); + p = append_str (p, op_str_0[(n & 7) + 8 * CLASS_MNEMONICS]); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 1: + p = disasm_1 (&addr, out); + break; + + case 2: + n = read_nibble (&addr); + switch (disassembler_mode) + { + case HP_MNEMONICS: + p = append_str (out, _T("P=")); + p = append_tab (out); + wsprintf (buf, _T("%d"), n); + p = append_str (p, buf); + break; + case CLASS_MNEMONICS: + wsprintf (buf, _T("move.1 #%d, p"), n); + p = append_str (out, buf); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 3: + fn = read_nibble (&addr); + switch (disassembler_mode) + { + case HP_MNEMONICS: + if (fn < 5) + { + wsprintf (buf, _T("LC(%d)"), fn + 1); + } + else + { + wsprintf (buf, _T("LCHEX")); + } + p = append_str (out, buf); + p = append_tab (out); + p = append_imm_nibble (p, &addr, fn + 1); + break; + case CLASS_MNEMONICS: + wsprintf (buf, _T("move.%d"), fn + 1); + p = append_str (out, buf); + p = append_tab (out); + p = append_imm_nibble (p, &addr, fn + 1); + wsprintf (buf, _T(", c.p")); + p = append_str (p, buf); + break; + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 4: + case 5: + pc = addr; + disp = read_int (&addr, 2); + switch (disassembler_mode) + { + case HP_MNEMONICS: + if (disp == 2) + { + p = append_str (out, _T("NOP3")); + break; + } + wsprintf (buf, (disp == 0) ? _T("RTN%sC") : _T("GO%sC"), (n == 4) ? _T("") : _T("N")); + p = append_str (out, buf); + if (disp != 0) + { + p = append_tab (out); + p = append_r_addr (p, &pc, disp, 2, 1); + } + break; + + case CLASS_MNEMONICS: + if (disp == 2) + { + p = append_str (out, _T("nop3")); + break; + } + p = append_str (out, (disp == 0) ? _T("rtc") : _T("bc")); + p = append_str (p, (n == 4) ? _T("s") : _T("c")); + if (disp != 0) + { + p = append_tab (out); + p = append_r_addr (p, &pc, disp, 2, 1); + } + break; + + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 6: + pc = addr; + disp = read_int (&addr, 3); // read GOTO distance + switch (disassembler_mode) + { + case HP_MNEMONICS: + if (disp == 3) // special case "GOTO next instruction" + { + p = append_str (out, _T("NOP4")); + break; + } + if (disp == 4) // special case "GOTO to +4 nibbles" + { + addr++; // skipping the fifth nibble in the opcode + p = append_str (out, _T("NOP5")); + break; + } + p = append_str (out, _T("GOTO")); + p = append_tab (out); + p = append_r_addr (p, &pc, disp, 3, 1); + break; + + case CLASS_MNEMONICS: + if (disp == 3) + { + p = append_str (out, _T("nop4")); + break; + } + if (disp == 4) + { + addr++; // skipping the fifth nibble in the opcode + p = append_str (out, _T("nop5")); + break; + } + p = append_str (out, _T("bra.3")); + p = append_tab (out); + p = append_r_addr (p, &pc, disp, 3, 1); + break; + + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 7: + pc = addr + 3; + disp = read_int (&addr, 3); + switch (disassembler_mode) + { + case HP_MNEMONICS: + p = append_str (out, _T("GOSUB")); + p = append_tab (out); + p = append_r_addr (p, &pc, disp, 3, 4); + break; + + case CLASS_MNEMONICS: + p = append_str (out, _T("bsr.3")); + p = append_tab (out); + p = append_r_addr (p, &pc, disp, 3, 4); + break; + + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + case 8: + fn = read_nibble (&addr); /* PEEK */ + --addr; + if (fn != 0xa && fn != 0xb) + { + p = disasm_8 (&addr, out); + break; + } + /* Fall through */ + + case 9: + fn = read_nibble (&addr); + if (n == 8) + { + c = (TCHAR) ((fn == 0xa) ? 0 : 1); + fn = 0xf; + } + else + { + c = (TCHAR) ((fn < 8) ? 0 : 1); + fn &= 7; + } + + n = read_nibble (&addr); + pc = addr; + disp = read_int (&addr, 2); + + switch (disassembler_mode) + { + case HP_MNEMONICS: + if ((c == 0) && (n >= 8)) + wsprintf (buf, op_str_9[(n & 3) + 8 * HP_MNEMONICS + 4], + in_str_9[((n >> 2) & 3) + 4 * c + 8 * HP_MNEMONICS]); + else + wsprintf (buf, op_str_9[(n & 3) + 8 * HP_MNEMONICS], + in_str_9[((n >> 2) & 3) + 4 * c + 8 * HP_MNEMONICS]); + p = append_str (out, buf); + p = append_tab (out); + p = append_field (p, fn); + p = append_str (p, _T(", ")); + p = append_str (p, (disp == 0) ? _T("RTNYES") : _T("GOYES ")); + if (disp != 0) + { + p = append_r_addr (p, &pc, disp, 2, 3); + } + break; + + case CLASS_MNEMONICS: + p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); + p = append_str (p, in_str_9[((n >> 2) & 3) + 4 * c + 8 * CLASS_MNEMONICS]); + p = append_field (p, fn); + p = append_tab (out); + if ((c == 0) && (n >= 8)) + p = append_str (p, op_str_9[(n & 3) + 8 * CLASS_MNEMONICS + 4]); + else + p = append_str (p, op_str_9[(n & 3) + 8 * CLASS_MNEMONICS]); + if (disp != 0) + { + p = append_str (p, _T(", ")); + p = append_r_addr (p, &pc, disp, 2, 3); + } + break; + + default: + p = append_str (out, _T("Unknown disassembler mode")); + break; + } + break; + + default: + switch (n) + { + case 0xa: + fn = read_nibble (&addr); + c = (TCHAR) ((fn < 8) ? 0 : 1); + fn &= 7; + disp = 0xa; + break; + case 0xb: + fn = read_nibble (&addr); + c = (TCHAR) ((fn < 8) ? 0 : 1); + fn &= 7; + disp = 0xb; + break; + case 0xc: + case 0xd: + fn = 0xf; + c = (TCHAR) (n & 1); + disp = 0xa; + break; + case 0xe: + case 0xf: + fn = 0xf; + c = (TCHAR) (n & 1); + disp = 0xb; + break; + default: + fn = 0; + disp = 0; + c = 0; + break; + } + + n = read_nibble (&addr); + pc = 0; + + switch (disp) + { + case 0xa: + switch (disassembler_mode) + { + case HP_MNEMONICS: + if (c == 0) + { + if (n < 0xc) + { + p = _T("+"); + } + else + { + p = _T("%c=%c-1"); + pc = 2; + } + } + else + { + if (n < 4) + { + p = _T("%c=0"); + pc = 1; + } + else + if (n >= 0xc) + { + p = _T("%c%cEX"); + pc = 3; + } + else + { + p = _T("%c=%c"); + pc = 3; + } + } + break; + + case CLASS_MNEMONICS: + if (c == 0) + { + if (n < 0xc) + { + p = _T("add"); + } + else + { + p = _T("dec"); + pc = 1; + } + } + else + { + if (n < 4) + { + p = _T("clr"); + pc = 1; + } + else + if (n >= 0xc) + { + p = _T("exg"); + } + else + { + p = _T("move"); + if (n < 8) + n -= 4; + } + } + break; + + default: + p = append_str (out, _T("Unknown disassembler mode")); + return addr; + } + break; + + case 0xb: + switch (disassembler_mode) + { + case HP_MNEMONICS: + if (c == 0) + { + if (n >= 0xc) + { + p = _T("-"); + } + else + if ((n >= 4) && (n <= 7)) + { + p = _T("%c=%c+1"); + pc = 2; + n -= 4; + } + else + { + p = _T("-"); + } + } + else + { + if (n < 4) + { + p = _T("%cSL"); + pc = 1; + } + else + if (n < 8) + { + p = _T("%cSR"); + pc = 1; + } + else + if (n < 0xc) + { + p = _T("%c=-%c"); + pc = 2; + } + else + { + p = _T("%c=-%c-1"); + pc = 2; + } + } + break; + + case CLASS_MNEMONICS: + if (c == 0) + { + if (n >= 0xc) + { + p = _T("subr"); + } + else + if ((n >= 4) && (n <= 7)) + { + p = _T("inc"); + pc = 1; + n -= 4; + } + else + { + p = _T("sub"); + } + } + else + { + pc = 1; + if (n < 4) + { + p = _T("lsl"); + } + else + if (n < 8) + { + p = _T("lsr"); + } + else + if (n < 0xc) + { + p = _T("neg"); + } + else + { + p = _T("not"); + } + } + break; + + default: + p = append_str (out, _T("Unknown disassembler mode")); + return addr; + } + break; + + } + + switch (disassembler_mode) + { + case HP_MNEMONICS: + if (pc == 0) + { + wsprintf (buf, op_str_af[n + 16 * HP_MNEMONICS], p); + } + else + if (pc == 1) + { + wsprintf (buf, p, (n & 3) + _T('A')); + } + else + if (pc == 2) + { + wsprintf (buf, p, (n & 3) + _T('A'), (n & 3) + _T('A')); + } + else + { + wsprintf (buf, p, hp_reg_1_af[n], hp_reg_2_af[n]); + } + p = append_str (out, buf); + p = append_tab (out); + p = append_field (p, fn); + break; + + case CLASS_MNEMONICS: + p = append_str (out, p); + p = append_field (p, fn); + p = append_tab (out); + if (pc == 1) + { + wsprintf (buf, _T("%c"), (n & 3) + _T('a')); + p = append_str (p, buf); + } + else + { + p = append_str (p, op_str_af[n + 16 * CLASS_MNEMONICS]); + } + break; + + default: + p = append_str (p, _T("Unknown disassembler mode")); + break; + } + break; + } + *p = 0; + + return addr; +} diff --git a/Sources/Emu48/dismem.c b/Sources/Emu48/DISMEM.C similarity index 95% rename from Sources/Emu48/dismem.c rename to Sources/Emu48/DISMEM.C index 64aee72..1d3f47d 100644 --- a/Sources/Emu48/dismem.c +++ b/Sources/Emu48/DISMEM.C @@ -1,221 +1,221 @@ -/* - * dismem.c - * - * This file is part of Emu48 - * - * Copyright (C) 2012 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" - -typedef struct // type of model memory mapping -{ - BYTE byType; // calculator type - CONST LPBYTE *ppbyNCE1; // NCE1 data - CONST DWORD *pdwNCE1Size; // NCE1 size - CONST LPBYTE *ppbyNCE2; // NCE2 data - CONST DWORD *pdwNCE2Size; // NCE2 size - CONST LPBYTE *ppbyCE1; // CE1 data - CONST DWORD *pdwCE1Size; // CE1 size - CONST LPBYTE *ppbyCE2; // CE2 data - CONST DWORD *pdwCE2Size; // CE2 size - CONST LPBYTE *ppbyNCE3; // NCE3 data - CONST DWORD *pdwNCE3Size; // NCE3 size -} MODEL_MAP_T; - -static CONST LPBYTE pbyNoMEM = NULL; // no memory module - -static CONST MODEL_MAP_T MemMap[] = -{ - { - 0, // default - &pbyNoMEM, NULL, // nc. - &pbyNoMEM, NULL, // nc. - &pbyNoMEM, NULL, // nc. - &pbyNoMEM, NULL, // nc. - &pbyNoMEM, NULL // nc. - }, - { - '6', // HP38G (64K) - &pbyRom, &dwRomSize, // ROM - &Port0, &Chipset.Port0Size, // RAM - &pbyNoMEM, NULL, // nc. - &pbyNoMEM, NULL, // nc. - &pbyNoMEM, NULL // nc. - }, - { - 'A', // HP38G - &pbyRom, &dwRomSize, // ROM - &Port0, &Chipset.Port0Size, // RAM - &pbyNoMEM, NULL, // nc. - &pbyNoMEM, NULL, // nc. - &pbyNoMEM, NULL // nc. - }, - { - 'E', // HP39/40G - &pbyRom, &dwRomSize, // ROM - &Port0, &Chipset.Port0Size, // RAM part 1 - &pbyNoMEM, NULL, // BS - &pbyNoMEM, NULL, // nc. - &Port2, &Chipset.Port2Size // RAM part 2 - }, - { - 'G', // HP48GX - &pbyRom, &dwRomSize, // ROM - &Port0, &Chipset.Port0Size, // RAM - &pbyNoMEM, NULL, // BS - &Port1, &Chipset.Port1Size, // Card slot 1 - &pbyPort2, &dwPort2Size // Card slot 2 - }, - { - 'S', // HP48SX - &pbyRom, &dwRomSize, // ROM - &Port0, &Chipset.Port0Size, // RAM - &Port1, &Chipset.Port1Size, // Card slot 1 - &pbyPort2, &dwPort2Size, // Card slot 2 - &pbyNoMEM, NULL // nc. - }, - { - 'X', // HP49G - &pbyRom, &dwRomSize, // Flash - &Port0, &Chipset.Port0Size, // RAM - &pbyNoMEM, NULL, // BS - &Port1, &Chipset.Port1Size, // Port 1 part 1 - &Port2, &Chipset.Port2Size // Port 1 part 2 - } -}; - -static MODEL_MAP_T CONST *pMapping = MemMap; // model specific memory mapping -static enum MEM_MAPPING eMapType = MEM_MMU; // MMU memory mapping - -static LPBYTE pbyMapData = NULL; -static DWORD dwMapDataSize = 0; -static DWORD dwMapDataMask = 0; - -BOOL SetMemRomType(BYTE cCurrentRomType) -{ - UINT i; - - pMapping = MemMap; // init default mapping - - // scan for all table entries - for (i = 0; i < ARRAYSIZEOF(MemMap); ++i) - { - if (MemMap[i].byType == cCurrentRomType) - { - pMapping = &MemMap[i]; // found entry - return TRUE; - } - } - return FALSE; -} - -BOOL SetMemMapType(enum MEM_MAPPING eType) -{ - BOOL bSucc = TRUE; - - eMapType = eType; - - switch (eMapType) - { - case MEM_MMU: - pbyMapData = NULL; // data - dwMapDataSize = 512 * 1024 * 2; // data size - dwMapDataMask = dwMapDataSize - 1; // size mask - break; - case MEM_NCE1: - pbyMapData = *pMapping->ppbyNCE1; - dwMapDataSize = *pMapping->pdwNCE1Size; // ROM size is always in nibbles - dwMapDataMask = dwMapDataSize - 1; // size mask - break; - case MEM_NCE2: - pbyMapData = *pMapping->ppbyNCE2; - dwMapDataSize = *pMapping->pdwNCE2Size * 1024 * 2; - dwMapDataMask = dwMapDataSize - 1; // size mask - break; - case MEM_CE1: - pbyMapData = *pMapping->ppbyCE1; - dwMapDataSize = *pMapping->pdwCE1Size * 1024 * 2; - dwMapDataMask = dwMapDataSize - 1; // size mask - break; - case MEM_CE2: - pbyMapData = *pMapping->ppbyCE2; - dwMapDataSize = *pMapping->pdwCE2Size * 1024 * 2; - dwMapDataMask = dwMapDataSize - 1; // size mask - break; - case MEM_NCE3: - pbyMapData = *pMapping->ppbyNCE3; - dwMapDataSize = *pMapping->pdwNCE3Size * 1024 * 2; - dwMapDataMask = dwMapDataSize - 1; // size mask - break; - default: _ASSERT(FALSE); - pbyMapData = NULL; - dwMapDataSize = 0; - dwMapDataMask = 0; - bSucc = FALSE; - } - return bSucc; -} - -enum MEM_MAPPING GetMemMapType(VOID) -{ - return eMapType; -} - -BOOL GetMemAvail(enum MEM_MAPPING eType) -{ - switch (eType) - { - case MEM_MMU: return TRUE; - case MEM_NCE1: return *pMapping->ppbyNCE1 != NULL; - case MEM_NCE2: return *pMapping->ppbyNCE2 != NULL; - case MEM_CE1: return *pMapping->ppbyCE1 != NULL; - case MEM_CE2: return *pMapping->ppbyCE2 != NULL; - case MEM_NCE3: return *pMapping->ppbyNCE3 != NULL; - default: _ASSERT(FALSE); - } - return FALSE; -} - -DWORD GetMemDataSize(VOID) -{ - return dwMapDataSize; -} - -DWORD GetMemDataMask(VOID) -{ - return dwMapDataMask; -} - -BYTE GetMemNib(DWORD *p) -{ - BYTE byVal; - - if (pbyMapData == NULL) - { - Npeek(&byVal, *p, 1); - } - else - { - byVal = pbyMapData[*p]; - } - *p = (*p + 1) & dwMapDataMask; - return byVal; -} - -VOID GetMemPeek(BYTE *a, DWORD d, UINT s) -{ - if (pbyMapData == NULL) - { - Npeek(a, d, s); - } - else - { - for (; s > 0; --s, ++d) - { - *a++ = pbyMapData[d & dwMapDataMask]; - } - } - return; -} +/* + * dismem.c + * + * This file is part of Emu48 + * + * Copyright (C) 2012 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" + +typedef struct // type of model memory mapping +{ + BYTE byType; // calculator type + CONST LPBYTE *ppbyNCE1; // NCE1 data + CONST DWORD *pdwNCE1Size; // NCE1 size + CONST LPBYTE *ppbyNCE2; // NCE2 data + CONST DWORD *pdwNCE2Size; // NCE2 size + CONST LPBYTE *ppbyCE1; // CE1 data + CONST DWORD *pdwCE1Size; // CE1 size + CONST LPBYTE *ppbyCE2; // CE2 data + CONST DWORD *pdwCE2Size; // CE2 size + CONST LPBYTE *ppbyNCE3; // NCE3 data + CONST DWORD *pdwNCE3Size; // NCE3 size +} MODEL_MAP_T; + +static CONST LPBYTE pbyNoMEM = NULL; // no memory module + +static CONST MODEL_MAP_T MemMap[] = +{ + { + 0, // default + &pbyNoMEM, NULL, // nc. + &pbyNoMEM, NULL, // nc. + &pbyNoMEM, NULL, // nc. + &pbyNoMEM, NULL, // nc. + &pbyNoMEM, NULL // nc. + }, + { + '6', // HP38G (64K) + &pbyRom, &dwRomSize, // ROM + &Port0, &Chipset.Port0Size, // RAM + &pbyNoMEM, NULL, // nc. + &pbyNoMEM, NULL, // nc. + &pbyNoMEM, NULL // nc. + }, + { + 'A', // HP38G + &pbyRom, &dwRomSize, // ROM + &Port0, &Chipset.Port0Size, // RAM + &pbyNoMEM, NULL, // nc. + &pbyNoMEM, NULL, // nc. + &pbyNoMEM, NULL // nc. + }, + { + 'E', // HP39/40G + &pbyRom, &dwRomSize, // ROM + &Port0, &Chipset.Port0Size, // RAM part 1 + &pbyNoMEM, NULL, // BS + &pbyNoMEM, NULL, // nc. + &Port2, &Chipset.Port2Size // RAM part 2 + }, + { + 'G', // HP48GX + &pbyRom, &dwRomSize, // ROM + &Port0, &Chipset.Port0Size, // RAM + &pbyNoMEM, NULL, // BS + &Port1, &Chipset.Port1Size, // Card slot 1 + &pbyPort2, &dwPort2Size // Card slot 2 + }, + { + 'S', // HP48SX + &pbyRom, &dwRomSize, // ROM + &Port0, &Chipset.Port0Size, // RAM + &Port1, &Chipset.Port1Size, // Card slot 1 + &pbyPort2, &dwPort2Size, // Card slot 2 + &pbyNoMEM, NULL // nc. + }, + { + 'X', // HP49G + &pbyRom, &dwRomSize, // Flash + &Port0, &Chipset.Port0Size, // RAM + &pbyNoMEM, NULL, // BS + &Port1, &Chipset.Port1Size, // Port 1 part 1 + &Port2, &Chipset.Port2Size // Port 1 part 2 + } +}; + +static MODEL_MAP_T CONST *pMapping = MemMap; // model specific memory mapping +static enum MEM_MAPPING eMapType = MEM_MMU; // MMU memory mapping + +static LPBYTE pbyMapData = NULL; +static DWORD dwMapDataSize = 0; +static DWORD dwMapDataMask = 0; + +BOOL SetMemRomType(BYTE cCurrentRomType) +{ + UINT i; + + pMapping = MemMap; // init default mapping + + // scan for all table entries + for (i = 0; i < ARRAYSIZEOF(MemMap); ++i) + { + if (MemMap[i].byType == cCurrentRomType) + { + pMapping = &MemMap[i]; // found entry + return TRUE; + } + } + return FALSE; +} + +BOOL SetMemMapType(enum MEM_MAPPING eType) +{ + BOOL bSucc = TRUE; + + eMapType = eType; + + switch (eMapType) + { + case MEM_MMU: + pbyMapData = NULL; // data + dwMapDataSize = 512 * 1024 * 2; // data size + dwMapDataMask = dwMapDataSize - 1; // size mask + break; + case MEM_NCE1: + pbyMapData = *pMapping->ppbyNCE1; + dwMapDataSize = *pMapping->pdwNCE1Size; // ROM size is always in nibbles + dwMapDataMask = dwMapDataSize - 1; // size mask + break; + case MEM_NCE2: + pbyMapData = *pMapping->ppbyNCE2; + dwMapDataSize = *pMapping->pdwNCE2Size * 1024 * 2; + dwMapDataMask = dwMapDataSize - 1; // size mask + break; + case MEM_CE1: + pbyMapData = *pMapping->ppbyCE1; + dwMapDataSize = *pMapping->pdwCE1Size * 1024 * 2; + dwMapDataMask = dwMapDataSize - 1; // size mask + break; + case MEM_CE2: + pbyMapData = *pMapping->ppbyCE2; + dwMapDataSize = *pMapping->pdwCE2Size * 1024 * 2; + dwMapDataMask = dwMapDataSize - 1; // size mask + break; + case MEM_NCE3: + pbyMapData = *pMapping->ppbyNCE3; + dwMapDataSize = *pMapping->pdwNCE3Size * 1024 * 2; + dwMapDataMask = dwMapDataSize - 1; // size mask + break; + default: _ASSERT(FALSE); + pbyMapData = NULL; + dwMapDataSize = 0; + dwMapDataMask = 0; + bSucc = FALSE; + } + return bSucc; +} + +enum MEM_MAPPING GetMemMapType(VOID) +{ + return eMapType; +} + +BOOL GetMemAvail(enum MEM_MAPPING eType) +{ + switch (eType) + { + case MEM_MMU: return TRUE; + case MEM_NCE1: return *pMapping->ppbyNCE1 != NULL; + case MEM_NCE2: return *pMapping->ppbyNCE2 != NULL; + case MEM_CE1: return *pMapping->ppbyCE1 != NULL; + case MEM_CE2: return *pMapping->ppbyCE2 != NULL; + case MEM_NCE3: return *pMapping->ppbyNCE3 != NULL; + default: _ASSERT(FALSE); + } + return FALSE; +} + +DWORD GetMemDataSize(VOID) +{ + return dwMapDataSize; +} + +DWORD GetMemDataMask(VOID) +{ + return dwMapDataMask; +} + +BYTE GetMemNib(DWORD *p) +{ + BYTE byVal; + + if (pbyMapData == NULL) + { + Npeek(&byVal, *p, 1); + } + else + { + byVal = pbyMapData[*p]; + } + *p = (*p + 1) & dwMapDataMask; + return byVal; +} + +VOID GetMemPeek(BYTE *a, DWORD d, UINT s) +{ + if (pbyMapData == NULL) + { + Npeek(a, d, s); + } + else + { + for (; s > 0; --s, ++d) + { + *a++ = pbyMapData[d & dwMapDataMask]; + } + } + return; +} diff --git a/Sources/Emu48/display.c b/Sources/Emu48/DISPLAY.C similarity index 96% rename from Sources/Emu48/display.c rename to Sources/Emu48/DISPLAY.C index d011b06..111ea9c 100644 --- a/Sources/Emu48/display.c +++ b/Sources/Emu48/DISPLAY.C @@ -1,1037 +1,1037 @@ -/* - * display.c - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * Copyright (C) 2002 Christoph Gießelink - * - */ -#include "pch.h" -#include "resource.h" -#include "emu48.h" -#include "io.h" -#include "kml.h" - -// #define DEBUG_DISPLAY // switch for DISPLAY debug purpose - -#define NOCOLORSGRAY 8 // no. of colors in gray scale mode -#define NOCOLORSBW 2 // no. of colors in black and white mode - -#define DISPLAY_FREQ 19 // display update 1/frequency (1/64) in ms (gray scale mode) - -#define B 0x00000000 // black -#define W 0x00FFFFFF // white -#define I 0xFFFFFFFF // ignore - -#define LCD_ROW (36*4) // max. pixel per line - -// main display lines, handle zero lines exception -#define LINES(n) (((n) == 0) ? 64 : ((n)+1)) - -#define GRAYMASK(c) (((((c)-1)>>1)<<24) \ - |((((c)-1)>>1)<<16) \ - |((((c)-1)>>1)<<8) \ - |((((c)-1)>>1))) - -#define DIBPIXEL4(d,p) *((DWORD*)(d)) = ((*((DWORD*)(d)) & dwGrayMask) << 1) | (p); \ - *((LPBYTE*) &(d)) += 4 -#define DIBPIXEL3(d,p) *((LPBYTE)(d)+2) = \ - *((LPBYTE)(d)+1) = \ - *((LPBYTE)(d)+0) = ((*(LPBYTE)(d) & (BYTE) dwGrayMask) << 1) | (p); \ - *((LPBYTE*) &(d)) += 3 - -BOOL bGrayscale = FALSE; -UINT nBackgroundX = 0; -UINT nBackgroundY = 0; -UINT nBackgroundW = 0; -UINT nBackgroundH = 0; -UINT nLcdX = 0; -UINT nLcdY = 0; -UINT nLcdZoom = 1; // memory DC zoom -UINT nGdiXZoom = 1; // GDI x zoom -UINT nGdiYZoom = 1; // GDI y zoom -HDC hLcdDC = NULL; -HDC hMainDC = NULL; -HDC hAnnunDC = NULL; // annunciator DC - -BYTE (*GetLineCounter)(VOID) = NULL; -VOID (*StartDisplay)(BYTE byInitial) = NULL; -VOID (*StopDisplay)(VOID) = NULL; - -static BYTE GetLineCounterGray(VOID); -static BYTE GetLineCounterBW(VOID); -static VOID StartDisplayGray(BYTE byInitial); -static VOID StartDisplayBW(BYTE byInitial); -static VOID StopDisplayGray(VOID); -static VOID StopDisplayBW(VOID); - -static LPBYTE pbyLcd; - -static HBITMAP hLcdBitmap; -static HBITMAP hMainBitmap; -static HBITMAP hAnnunBitmap; - -static DWORD Pattern[16]; -static BYTE Buf[36]; - -static DWORD dwGrayMask; - -static LARGE_INTEGER lLcdRef; // reference time for VBL counter -static UINT uLcdTimerId = 0; - -static BYTE byVblRef = 0; // VBL stop reference - -static DWORD dwKMLColor[64] = // color table loaded by KML script -{ - W,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B, - B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B, - I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, - I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I -}; - -static struct -{ - BITMAPINFOHEADER Lcd_bmih; - RGBQUAD bmiColors[NOCOLORSGRAY]; -} bmiLcd = -{ - {0x28,0/*x*/,0/*y*/,1,8,BI_RGB,0,0,0,NOCOLORSGRAY,0} -}; - -static __inline VOID BuildPattern(VOID) -{ - _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); - - if (nLcdZoom == 1) - { - WORD i,j; - for (i=0; i<16; ++i) - { - Pattern[i] = 0; - for (j=8; j>0; j>>=1) - { - Pattern[i] = (Pattern[i] << 8) | ((i&j) != 0); - } - } - return; - } - if (nLcdZoom == 2) - { - Pattern[0] = 0x00000000; - Pattern[1] = 0x00000101; - Pattern[2] = 0x01010000; - Pattern[3] = 0x01010101; - return; - } - if (nLcdZoom == 4) - { - Pattern[0] = 0x00000000; - Pattern[1] = 0x01010101; - } - return; -} - -VOID UpdateContrast(BYTE byContrast) -{ - RGBQUAD c,b; - INT i,nColors; - - // table for max. 8 colors - const INT nCAdj[] = { 0, 1, 1, 2, 1, 2, 2, 3 }; - - // when display is off use contrast 0 - if ((Chipset.IORam[BITOFFSET] & DON) == 0) byContrast = 0; - - c = *(RGBQUAD*)&dwKMLColor[byContrast]; // pixel on color - b = *(RGBQUAD*)&dwKMLColor[byContrast+32]; // pixel off color - - // if background color is undefined, use color 0 for compatibility - if (I == *(DWORD*)&b) b = *(RGBQUAD*)&dwKMLColor[0]; - - nColors = bGrayscale ? (NOCOLORSGRAY-1) : (NOCOLORSBW-1); - - _ASSERT(nColors <= ARRAYSIZEOF(nCAdj)); // no. of colors must be smaller than entries in the gray color table - - // fill color palette of bitmap - for (i = 0; i <= nColors; ++i) - { - bmiLcd.bmiColors[i] = b; - bmiLcd.bmiColors[i].rgbRed += ((INT) c.rgbRed - (INT) b.rgbRed) * nCAdj[i] / nCAdj[nColors]; - bmiLcd.bmiColors[i].rgbGreen += ((INT) c.rgbGreen - (INT) b.rgbGreen) * nCAdj[i] / nCAdj[nColors]; - bmiLcd.bmiColors[i].rgbBlue += ((INT) c.rgbBlue - (INT) b.rgbBlue) * nCAdj[i] / nCAdj[nColors]; - } - - // update palette information - _ASSERT(hLcdDC); - SetDIBColorTable(hLcdDC,0,ARRAYSIZEOF(bmiLcd.bmiColors),bmiLcd.bmiColors); - return; -} - -VOID SetLcdColor(UINT nId, UINT nRed, UINT nGreen, UINT nBlue) -{ - dwKMLColor[nId&0x3F] = ((nRed&0xFF)<<16)|((nGreen&0xFF)<<8)|(nBlue&0xFF); - return; -} - -VOID SetLcdMode(BOOL bMode) -{ - if ((bGrayscale = bMode)) - { - // set pixel update mask - dwGrayMask = GRAYMASK(NOCOLORSGRAY); - GetLineCounter = GetLineCounterGray; - StartDisplay = StartDisplayGray; - StopDisplay = StopDisplayGray; - } - else - { - // set pixel update mask - dwGrayMask = GRAYMASK(NOCOLORSBW); - GetLineCounter = GetLineCounterBW; - StartDisplay = StartDisplayBW; - StopDisplay = StopDisplayBW; - } - UpdateContrast(Chipset.contrast); - return; -} - -VOID CreateLcdBitmap(VOID) -{ - // create LCD bitmap - _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); - bmiLcd.Lcd_bmih.biWidth = LCD_ROW * nLcdZoom; - bmiLcd.Lcd_bmih.biHeight = -64 * nLcdZoom; - _ASSERT(hLcdDC == NULL); - VERIFY(hLcdDC = CreateCompatibleDC(hWindowDC)); - VERIFY(hLcdBitmap = CreateDIBSection(hWindowDC,(BITMAPINFO*)&bmiLcd,DIB_RGB_COLORS,(VOID **)&pbyLcd,NULL,0)); - hLcdBitmap = (HBITMAP) SelectObject(hLcdDC,hLcdBitmap); - _ASSERT(hPalette != NULL); - SelectPalette(hLcdDC,hPalette,FALSE); // set palette for LCD DC - RealizePalette(hLcdDC); // realize palette - BuildPattern(); // build Nibble -> DIB mask pattern - SetLcdMode(bGrayscale); // init display update function pointer - return; -} - -VOID DestroyLcdBitmap(VOID) -{ - // set contrast palette to startup colors - WORD i = 0; dwKMLColor[i++] = W; - while (i < 32) dwKMLColor[i++] = B; - while (i < 64) dwKMLColor[i++] = I; - - GetLineCounter = NULL; - StartDisplay = NULL; - StopDisplay = NULL; - - if (hLcdDC != NULL) - { - // destroy LCD bitmap - DeleteObject(SelectObject(hLcdDC,hLcdBitmap)); - DeleteDC(hLcdDC); - hLcdDC = NULL; - hLcdBitmap = NULL; - } - return; -} - -BOOL CreateMainBitmap(LPCTSTR szFilename) -{ - _ASSERT(hWindowDC != NULL); - VERIFY(hMainDC = CreateCompatibleDC(hWindowDC)); - if (hMainDC == NULL) return FALSE; // quit if failed - hMainBitmap = LoadBitmapFile(szFilename,TRUE); - if (hMainBitmap == NULL) - { - DeleteDC(hMainDC); - hMainDC = NULL; - return FALSE; - } - hMainBitmap = (HBITMAP) SelectObject(hMainDC,hMainBitmap); - _ASSERT(hPalette != NULL); - VERIFY(SelectPalette(hMainDC,hPalette,FALSE)); - RealizePalette(hMainDC); - return TRUE; -} - -VOID DestroyMainBitmap(VOID) -{ - if (hMainDC != NULL) - { - // destroy Main bitmap - DeleteObject(SelectObject(hMainDC,hMainBitmap)); - DeleteDC(hMainDC); - hMainDC = NULL; - hMainBitmap = NULL; - } - return; -} - -// -// load annunciator bitmap -// -BOOL CreateAnnunBitmap(LPCTSTR szFilename) -{ - _ASSERT(hWindowDC != NULL); - VERIFY(hAnnunDC = CreateCompatibleDC(hWindowDC)); - if (hAnnunDC == NULL) return FALSE; // quit if failed - hAnnunBitmap = LoadBitmapFile(szFilename,FALSE); - if (hAnnunBitmap == NULL) - { - DeleteDC(hAnnunDC); - hAnnunDC = NULL; - return FALSE; - } - hAnnunBitmap = (HBITMAP) SelectObject(hAnnunDC,hAnnunBitmap); - return TRUE; -} - -// -// destroy annunciator bitmap -// -VOID DestroyAnnunBitmap(VOID) -{ - if (hAnnunDC != NULL) - { - VERIFY(DeleteObject(SelectObject(hAnnunDC,hAnnunBitmap))); - DeleteDC(hAnnunDC); - hAnnunDC = NULL; - hAnnunBitmap = NULL; - } - return; -} - -//**************** -//* -//* LCD functions -//* -//**************** - -VOID UpdateDisplayPointers(VOID) -{ - EnterCriticalSection(&csLcdLock); - { - UINT nLines = LINES(Chipset.lcounter); - - #if defined DEBUG_DISPLAY - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: Update Display Pointer\n"),Chipset.pc); - OutputDebugString(buffer); - } - #endif - - // calculate display width - Chipset.width = (34 + Chipset.loffset + (Chipset.boffset / 4) * 2) & 0xFFFFFFFE; - Chipset.end1 = Chipset.start1 + nLines * Chipset.width; - if (Chipset.end1 < Chipset.start1) - { - // calculate first address of main display - Chipset.start12 = Chipset.end1 - Chipset.width; - // calculate last address of main display - Chipset.end1 = Chipset.start1 - Chipset.width; - } - else - { - Chipset.start12 = Chipset.start1; - } - Chipset.end2 = Chipset.start2 + (64 - nLines) * 34; - } - LeaveCriticalSection(&csLcdLock); - return; -} - -VOID UpdateMainDisplay(VOID) -{ - UINT x, y, nLines; - BYTE *p; - DWORD d; - - #if defined DEBUG_DISPLAY - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: Update Main Display\n"),Chipset.pc); - OutputDebugString(buffer); - } - #endif - - _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); - if (!(Chipset.IORam[BITOFFSET]&DON)) - { - nLines = 64; - ZeroMemory(pbyLcd, LCD_ROW * nLcdZoom * nLines * nLcdZoom); - } - else - { - nLines = LINES(Chipset.lcounter); // main display lines - p = pbyLcd; // bitmap offset - d = 0; // pixel offset counter - if (nLcdZoom == 4) - { - for (y = 0; y < nLines; ++y) - { - // read line with actual start1 address!! - Npeek(Buf,d+Chipset.start1,36); - for (x = 0; x < 36; ++x) // every 4 pixel - { - DIBPIXEL4(p,Pattern[Buf[x]&1]); - DIBPIXEL4(p,Pattern[(Buf[x]>>1) & 1]); - DIBPIXEL4(p,Pattern[(Buf[x]>>2) & 1]); - DIBPIXEL4(p,Pattern[(Buf[x]>>3) & 1]); - } - CopyMemory(p, p-LCD_ROW*4, LCD_ROW*4); - p+=LCD_ROW*4; - CopyMemory(p, p-LCD_ROW*8, LCD_ROW*8); - p+=LCD_ROW*8; - d+=Chipset.width; - } - } - if (nLcdZoom == 3) - { - for (y = 0; y < nLines; ++y) - { - // read line with actual start1 address!! - Npeek(Buf,d+Chipset.start1,36); - for (x = 0; x < 36; ++x) // every 4 pixel - { - DIBPIXEL3(p,(Buf[x]>>0) & 1); - DIBPIXEL3(p,(Buf[x]>>1) & 1); - DIBPIXEL3(p,(Buf[x]>>2) & 1); - DIBPIXEL3(p,(Buf[x]>>3) & 1); - } - CopyMemory(p, p-LCD_ROW*3, LCD_ROW*3); - p+=LCD_ROW*3; - CopyMemory(p, p-LCD_ROW*3, LCD_ROW*3); - p+=LCD_ROW*3; - d+=Chipset.width; - } - } - if (nLcdZoom == 2) - { - for (y = 0; y < nLines; ++y) - { - // read line with actual start1 address!! - Npeek(Buf,d+Chipset.start1,36); - for (x = 0; x < 36; ++x) // every 4 pixel - { - DIBPIXEL4(p,Pattern[Buf[x]&3]); - DIBPIXEL4(p,Pattern[Buf[x]>>2]); - } - CopyMemory(p, p-LCD_ROW*2, LCD_ROW*2); - p+=LCD_ROW*2; - d+=Chipset.width; - } - } - if (nLcdZoom == 1) - { - for (y = 0; y < nLines; ++y) - { - // read line with actual start1 address!! - Npeek(Buf,d+Chipset.start1,36); - for (x = 0; x < 36; ++x) // every 4 pixel - { - DIBPIXEL4(p,Pattern[Buf[x]]); - } - d+=Chipset.width; - } - } - } - EnterCriticalSection(&csGDILock); // solving NT GDI problems - { - StretchBlt(hWindowDC, nLcdX, nLcdY, 131*nLcdZoom*nGdiXZoom, nLines*nLcdZoom*nGdiYZoom, - hLcdDC, Chipset.boffset*nLcdZoom, 0, 131*nLcdZoom, nLines*nLcdZoom,SRCCOPY); - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - return; -} - -VOID UpdateMenuDisplay(VOID) -{ - UINT x, y, nLines; - BYTE *p; - DWORD d; - - #if defined DEBUG_DISPLAY - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: Update Menu Display\n"),Chipset.pc); - OutputDebugString(buffer); - } - #endif - - if (!(Chipset.IORam[BITOFFSET]&DON)) return; - - nLines = LINES(Chipset.lcounter); - if (nLines == 64) return; // menu disabled - - _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); - // calculate bitmap offset - p = pbyLcd + (nLines*nLcdZoom*LCD_ROW*nLcdZoom); - d = 0; // pixel offset counter - if (nLcdZoom == 4) - { - for (y = nLines; y < 64; ++y) - { - Npeek(Buf,d+Chipset.start2,34); // 34 nibbles are viewed - for (x = 0; x < 34; ++x) // every 4 pixel - { - DIBPIXEL4(p,Pattern[Buf[x]&1]); - DIBPIXEL4(p,Pattern[(Buf[x]>>1) & 1]); - DIBPIXEL4(p,Pattern[(Buf[x]>>2) & 1]); - DIBPIXEL4(p,Pattern[(Buf[x]>>3) & 1]); - } - // adjust pointer to 36 DIBPIXEL drawing calls - p += (36-34) * 4 * sizeof(DWORD); - CopyMemory(p, p-LCD_ROW*4, LCD_ROW*4); - p+=LCD_ROW*4; - CopyMemory(p, p-LCD_ROW*8, LCD_ROW*8); - p+=LCD_ROW*8; - d+=34; - } - } - if (nLcdZoom == 3) - { - for (y = nLines; y < 64; ++y) - { - Npeek(Buf,d+Chipset.start2,34); // 34 nibbles are viewed - for (x = 0; x < 34; ++x) // every 4 pixel - { - DIBPIXEL3(p,(Buf[x]>>0) & 1); - DIBPIXEL3(p,(Buf[x]>>1) & 1); - DIBPIXEL3(p,(Buf[x]>>2) & 1); - DIBPIXEL3(p,(Buf[x]>>3) & 1); - } - // adjust pointer to 36 DIBPIXEL drawing calls - p += (36-34) * 3 * sizeof(DWORD); - CopyMemory(p, p-LCD_ROW*3, LCD_ROW*3); - p+=LCD_ROW*3; - CopyMemory(p, p-LCD_ROW*3, LCD_ROW*3); - p+=LCD_ROW*3; - d+=34; - } - } - if (nLcdZoom == 2) - { - for (y = nLines; y < 64; ++y) - { - Npeek(Buf,d+Chipset.start2,34); // 34 nibbles are viewed - for (x = 0; x < 34; ++x) // every 4 pixel - { - DIBPIXEL4(p,Pattern[Buf[x]&3]); - DIBPIXEL4(p,Pattern[Buf[x]>>2]); - } - // adjust pointer to 36 DIBPIXEL drawing calls - p += (36-34) * 2 * sizeof(DWORD); - CopyMemory(p, p-LCD_ROW*2, LCD_ROW*2); - p+=LCD_ROW*2; - d+=34; - } - } - if (nLcdZoom == 1) - { - for (y = nLines; y < 64; ++y) - { - Npeek(Buf,d+Chipset.start2,34); // 34 nibbles are viewed - for (x = 0; x < 34; ++x) // every 4 pixel - { - DIBPIXEL4(p,Pattern[Buf[x]]); - } - // adjust pointer to 36 DIBPIXEL drawing calls - p += (36-34) * 1 * sizeof(DWORD); - d+=34; - } - } - EnterCriticalSection(&csGDILock); // solving NT GDI problems - { - StretchBlt(hWindowDC, nLcdX, nLcdY+nLines*nLcdZoom*nGdiYZoom, - 131*nLcdZoom*nGdiXZoom, (64-nLines)*nLcdZoom*nGdiYZoom, - hLcdDC, 0, nLines*nLcdZoom, 131*nLcdZoom, (64-nLines)*nLcdZoom, SRCCOPY); - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - return; -} - -VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s) -{ - INT x0, x; - INT y0, y; - DWORD *p; - INT lWidth; - UINT nLines; - - if (bGrayscale) return; // no direct writing in grayscale mode - - lWidth = abs(Chipset.width); // display width - nLines = LINES(Chipset.lcounter); // main display lines - - #if defined DEBUG_DISPLAY - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: Write Main Display %x,%u\n"),Chipset.pc,d,s); - OutputDebugString(buffer); - } - #endif - - if (!(Chipset.IORam[BITOFFSET]&DON)) // display off - return; // no drawing - - d -= Chipset.start1; // nibble offset to DISPADDR (start of display) - d += 64 * lWidth; // make positive offset - y0 = abs((INT) d / lWidth - 64); // bitmap row - x0 = (INT) d % lWidth; // bitmap coloumn - y = y0; x = x0; // load loop variables - - // outside main display area - _ASSERT(y0 >= 0 && y0 < (INT) nLines); - - // illegal zoom factor - _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); - - // calculate memory position in LCD bitmap - p = (DWORD*) (pbyLcd + y0*LCD_ROW*nLcdZoom*nLcdZoom - + x0*sizeof(*p)*nLcdZoom); - - while (s--) // loop for nibbles to write - { - if (x<36) // only fill visible area - { - if (nLcdZoom == 4) - { - p[432] = p[288] = p[144] = p[0] = Pattern[(*a)&1]; - p[433] = p[289] = p[145] = p[1] = Pattern[((*a)>>1)&1]; - p[434] = p[290] = p[146] = p[2] = Pattern[((*a)>>2)&1]; - p[435] = p[291] = p[147] = p[3] = Pattern[((*a)>>3)&1]; - } - if (nLcdZoom == 3) - { - LPBYTE b = (LPBYTE) p; - b[216*4+2] = b[216*4+1] = b[216*4+0] = - b[108*4+2] = b[108*4+1] = b[108*4+0] = - b[ 0*4+2] = b[ 0*4+1] = b[ 0*4+0] = (*a)&1; - b[216*4+5] = b[216*4+4] = b[216*4+3] = - b[108*4+5] = b[108*4+4] = b[108*4+3] = - b[ 0*4+5] = b[ 0*4+4] = b[ 0*4+3] = ((*a)>>1)&1; - b[216*4+8] = b[216*4+7] = b[216*4+6] = - b[108*4+8] = b[108*4+7] = b[108*4+6] = - b[ 0*4+8] = b[ 0*4+7] = b[ 0*4+6] = ((*a)>>2)&1; - b[216*4+11] = b[216*4+10] = b[216*4+9] = - b[108*4+11] = b[108*4+10] = b[108*4+9] = - b[ 0*4+11] = b[ 0*4+10] = b[ 0*4+9] = ((*a)>>3)&1; - } - if (nLcdZoom == 2) - { - p[72] = p[0] = Pattern[(*a)&3]; - p[73] = p[1] = Pattern[(*a)>>2]; - } - if (nLcdZoom == 1) - { - *p = Pattern[*a]; - } - } - ++a; // next value to write - ++x; // next x position - if ((x==lWidth)&&s) // end of display line - { - // end of main display area - if (y == (INT) nLines - 1) break; - - x = 0; // first coloumn - ++y; // next row - // recalculate bitmap memory position of new line - p = (DWORD*) (pbyLcd+y*LCD_ROW*nLcdZoom*nLcdZoom); - } - else - p += nLcdZoom; // next x position in bitmap - } - - // update window region - if (y0 != y) // changed more than one line - { - x0 = 0; // no x-position offset - x = 131; // redraw complete lines - - ++y; // redraw this line as well - } - else - { - x0 <<= 2; x <<= 2; // x-position in pixel - _ASSERT(x >= x0); // can't draw negative number of pixel - x -= x0; // number of pixels to update - - x0 -= Chipset.boffset; // adjust x-position with left margin - if (x0 < 0) x0 = 0; - - if (x0 > 131) x0 = 131; // cut right borders - if (x+x0 > 131) x = 131 - x0; - - y = y0 + 1; // draw one line - } - - x0 *= nLcdZoom; // adjust dimensions to pixel size - x *= nLcdZoom; - y0 *= nLcdZoom; - y *= nLcdZoom; - - EnterCriticalSection(&csGDILock); - { - StretchBlt(hWindowDC, nLcdX+x0*nGdiXZoom, nLcdY+y0*nGdiYZoom, - x*nGdiXZoom, (y-y0)*nGdiYZoom, - hLcdDC, x0+Chipset.boffset*nLcdZoom, y0, x, y-y0, SRCCOPY); - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - return; -} - -VOID WriteToMenuDisplay(LPBYTE a, DWORD d, UINT s) -{ - UINT x0, x; - UINT y0, y; - DWORD *p; - UINT nLines; - - if (bGrayscale) return; // no direct writing in grayscale mode - - nLines = LINES(Chipset.lcounter); // main display lines - - #if defined DEBUG_DISPLAY - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: Write Menu Display %x,%u\n"),Chipset.pc,d,s); - OutputDebugString(buffer); - } - #endif - - if (!(Chipset.IORam[BITOFFSET]&DON)) return; - if (nLines == 64) return; // menu disabled - - d -= Chipset.start2; - y0 = y = (d / 34) + nLines; - x0 = x = d % 34; - if (x0 > 32) return; // position out of viewed area - _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); - - // calculate memory position in LCD bitmap - p = (DWORD*) (pbyLcd + y0*LCD_ROW*nLcdZoom*nLcdZoom - + x0*sizeof(*p)*nLcdZoom); - - if (nLcdZoom == 4) - { - while (s--) - { - if (x<34) - { - p[432] = p[288] = p[144] = p[0] = Pattern[(*a)&1]; - p[433] = p[289] = p[145] = p[1] = Pattern[((*a)>>1) &1]; - p[434] = p[290] = p[146] = p[2] = Pattern[((*a)>>2) &1]; - p[435] = p[291] = p[147] = p[3] = Pattern[((*a)>>3) &1]; - } - a++; - x++; - if ((x==34)&&s) - { - x=0; - y++; - if (y==64) break; - p=(DWORD*)(pbyLcd+y*LCD_ROW*16); - } else p+=4; - } - if (y0!=y) // modified more than 1 line - { - x = 34; // full line - x0 = 0; // no offset - } - x0<<=4; x<<=4; // calculate pixel address - y0<<=2; y<<=2; - if (x>524) x=524; - } - if (nLcdZoom == 3) - { - while (s--) - { - if (x<34) - { - LPBYTE b = (LPBYTE) p; - b[216*4+2] = b[216*4+1] = b[216*4+0] = - b[108*4+2] = b[108*4+1] = b[108*4+0] = - b[ 0*4+2] = b[ 0*4+1] = b[ 0*4+0] = (*a)&1; - b[216*4+5] = b[216*4+4] = b[216*4+3] = - b[108*4+5] = b[108*4+4] = b[108*4+3] = - b[ 0*4+5] = b[ 0*4+4] = b[ 0*4+3] = ((*a)>>1)&1; - b[216*4+8] = b[216*4+7] = b[216*4+6] = - b[108*4+8] = b[108*4+7] = b[108*4+6] = - b[ 0*4+8] = b[ 0*4+7] = b[ 0*4+6] = ((*a)>>2)&1; - b[216*4+11] = b[216*4+10] = b[216*4+9] = - b[108*4+11] = b[108*4+10] = b[108*4+9] = - b[ 0*4+11] = b[ 0*4+10] = b[ 0*4+9] = ((*a)>>3)&1; - } - a++; - x++; - if ((x==34)&&s) - { - x=0; - y++; - if (y==64) break; - p=(DWORD*)(pbyLcd+y*LCD_ROW*9); - } else p+=3; - } - if (y0!=y) // modified more than 1 line - { - x = 34; // full line - x0 = 0; // no offset - } - x0*=12; x*=12; // calculate pixel address - y0*=3; y*=3; - if (x>393) x=393; - } - if (nLcdZoom == 2) - { - while (s--) - { - if (x<34) - { - p[72] = p[0] = Pattern[(*a)&3]; - p[73] = p[1] = Pattern[(*a)>>2]; - } - a++; - x++; - if ((x==34)&&s) - { - x=0; - y++; - if (y==64) break; - p=(DWORD*)(pbyLcd+y*LCD_ROW*4); - } else p+=2; - } - if (y0!=y) // modified more than 1 line - { - x = 34; // full line - x0 = 0; // no offset - } - x0<<=3; x<<=3; // calculate pixel address - y0<<=1; y<<=1; - if (x>262) x=262; - } - if (nLcdZoom == 1) - { - while (s--) - { - if (x<34) *p = Pattern[*a]; - a++; - x++; - if ((x==34)&&s) - { - x=0; - y++; - if (y==64) break; - p=(DWORD*)(pbyLcd+y*LCD_ROW); - } else p++; - } - if (y0!=y) // modified more than 1 line - { - x = 34; // full line - x0 = 0; // no offset - } - x0<<=2; x<<=2; // calculate pixel address - if (x>131) x=131; - } - - EnterCriticalSection(&csGDILock); // solving NT GDI problems - { - StretchBlt(hWindowDC, nLcdX+x0*nGdiXZoom, nLcdY+y0*nGdiYZoom, - (x-x0)*nGdiXZoom, (y-y0+nLcdZoom)*nGdiYZoom, - hLcdDC, x0, y0, x-x0, y-y0+nLcdZoom, SRCCOPY); - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - return; -} - -VOID UpdateAnnunciators(DWORD dwUpdateMask) -{ - BYTE c; - UINT i; - - c = (BYTE)(Chipset.IORam[ANNCTRL] | (Chipset.IORam[ANNCTRL+1]<<4)); - // switch annunciators off if timer stopped - if ((c & AON) == 0 || (Chipset.IORam[TIMER2_CTRL] & RUN) == 0) - c = 0; - - for (i = 1; i <= 6; ++i) - { - if ((dwUpdateMask & 0x1) != 0) // annunciator changed? - { - DrawAnnunciator(i,c & 0x1); - } - dwUpdateMask >>= 1; - c >>= 1; - } - _ASSERT(dwUpdateMask == 0); - return; -} - -VOID ResizeWindow(VOID) -{ - if (hWnd != NULL) // if window created - { - RECT rectWindow; - RECT rectClient; - - rectWindow.left = 0; - rectWindow.top = 0; - rectWindow.right = nBackgroundW; - rectWindow.bottom = nBackgroundH; - - AdjustWindowRect(&rectWindow, - (DWORD) GetWindowLongPtr(hWnd,GWL_STYLE), - GetMenu(hWnd) != NULL || IsRectEmpty(&rectWindow)); - SetWindowPos(hWnd, bAlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, - rectWindow.right - rectWindow.left, - rectWindow.bottom - rectWindow.top, - SWP_NOMOVE); - - // check if menu bar wrapped to two or more rows - GetClientRect(hWnd, &rectClient); - if (rectClient.bottom < (LONG) nBackgroundH) - { - rectWindow.bottom += (nBackgroundH - rectClient.bottom); - SetWindowPos (hWnd, NULL, 0, 0, - rectWindow.right - rectWindow.left, - rectWindow.bottom - rectWindow.top, - SWP_NOMOVE | SWP_NOZORDER); - } - - EnterCriticalSection(&csGDILock); // solving NT GDI problems - { - _ASSERT(hWindowDC); // move origin of destination window - VERIFY(SetWindowOrgEx(hWindowDC, nBackgroundX, nBackgroundY, NULL)); - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - InvalidateRect(hWnd,NULL,TRUE); - } - return; -} - -//################ -//# -//# functions for gray scale implementation -//# -//################ - -// main display update routine -static VOID CALLBACK LcdProc(UINT uEventId, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) -{ - EnterCriticalSection(&csLcdLock); - { - UpdateMainDisplay(); // update display - UpdateMenuDisplay(); - } - LeaveCriticalSection(&csLcdLock); - - QueryPerformanceCounter(&lLcdRef); // actual time - - return; - UNREFERENCED_PARAMETER(uEventId); - UNREFERENCED_PARAMETER(uMsg); - UNREFERENCED_PARAMETER(dwUser); - UNREFERENCED_PARAMETER(dw1); - UNREFERENCED_PARAMETER(dw2); -} - -// LCD line counter calculation -static BYTE GetLineCounterGray(VOID) -{ - LARGE_INTEGER lLC; - BYTE byTime; - - if (uLcdTimerId == 0) // display off - return ((Chipset.IORam[LINECOUNT+1] & (LC5|LC4)) << 4) | Chipset.IORam[LINECOUNT]; - - QueryPerformanceCounter(&lLC); // get elapsed time since display update - - // elapsed ticks so far - byTime = (BYTE) (((lLC.QuadPart - lLcdRef.QuadPart) << 12) / lFreq.QuadPart); - - if (byTime > 0x3F) byTime = 0x3F; // all counts made - - return 0x3F - byTime; // update display between VBL counter 0x3F-0x3E -} - -static VOID StartDisplayGray(BYTE byInitial) -{ - if (uLcdTimerId) // LCD update timer running - return; // -> quit - - if (Chipset.IORam[BITOFFSET]&DON) // display on? - { - QueryPerformanceCounter(&lLcdRef); // actual time of top line - - // adjust startup counter to get the right VBL value - _ASSERT(byInitial <= 0x3F); // line counter value 0 - 63 - lLcdRef.QuadPart -= ((LONGLONG) (0x3F - byInitial) * lFreq.QuadPart) >> 12; - - VERIFY(uLcdTimerId = timeSetEvent(DISPLAY_FREQ,0,(LPTIMECALLBACK)&LcdProc,0,TIME_PERIODIC)); - } - return; -} - -static VOID StopDisplayGray(VOID) -{ - BYTE a[2]; - ReadIO(a,LINECOUNT,2,TRUE); // update VBL at display off time - - if (uLcdTimerId == 0) // timer stopped - return; // -> quit - - timeKillEvent(uLcdTimerId); // stop display update - uLcdTimerId = 0; // set flag display update stopped - - EnterCriticalSection(&csLcdLock); // update to last condition - { - UpdateMainDisplay(); // update display - UpdateMenuDisplay(); - } - LeaveCriticalSection(&csLcdLock); - return; -} - -//################ -//# -//# functions for black and white implementation -//# -//################ - -// LCD line counter calculation in BW mode -static BYTE F4096Hz(VOID) // get a 6 bit 4096Hz down counter value -{ - LARGE_INTEGER lLC; - - QueryPerformanceCounter(&lLC); // get counter value - - // calculate 4096 Hz frequency down counter value - return -(BYTE)(((lLC.QuadPart - lAppStart.QuadPart) << 12) / lFreq.QuadPart) & 0x3F; -} - -static BYTE GetLineCounterBW(VOID) // get line counter value -{ - _ASSERT(byVblRef < 0x40); - return (0x40 + F4096Hz() - byVblRef) & 0x3F; -} - -static VOID StartDisplayBW(BYTE byInitial) -{ - // get positive VBL difference between now and stop time - byVblRef = (0x40 + F4096Hz() - byInitial) & 0x3F; - return; -} - -static VOID StopDisplayBW(VOID) -{ - BYTE a[2]; - ReadIO(a,LINECOUNT,2,TRUE); // update VBL at display off time - return; -} +/* + * display.c + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * Copyright (C) 2002 Christoph Gießelink + * + */ +#include "pch.h" +#include "resource.h" +#include "Emu48.h" +#include "io.h" +#include "kml.h" + +// #define DEBUG_DISPLAY // switch for DISPLAY debug purpose + +#define NOCOLORSGRAY 8 // no. of colors in gray scale mode +#define NOCOLORSBW 2 // no. of colors in black and white mode + +#define DISPLAY_FREQ 19 // display update 1/frequency (1/64) in ms (gray scale mode) + +#define B 0x00000000 // black +#define W 0x00FFFFFF // white +#define I 0xFFFFFFFF // ignore + +#define LCD_ROW (36*4) // max. pixel per line + +// main display lines, handle zero lines exception +#define LINES(n) (((n) == 0) ? 64 : ((n)+1)) + +#define GRAYMASK(c) (((((c)-1)>>1)<<24) \ + |((((c)-1)>>1)<<16) \ + |((((c)-1)>>1)<<8) \ + |((((c)-1)>>1))) + +#define DIBPIXEL4(d,p) *((DWORD*)(d)) = ((*((DWORD*)(d)) & dwGrayMask) << 1) | (p); \ + *((LPBYTE*) &(d)) += 4 +#define DIBPIXEL3(d,p) *((LPBYTE)(d)+2) = \ + *((LPBYTE)(d)+1) = \ + *((LPBYTE)(d)+0) = ((*(LPBYTE)(d) & (BYTE) dwGrayMask) << 1) | (p); \ + *((LPBYTE*) &(d)) += 3 + +BOOL bGrayscale = FALSE; +UINT nBackgroundX = 0; +UINT nBackgroundY = 0; +UINT nBackgroundW = 0; +UINT nBackgroundH = 0; +UINT nLcdX = 0; +UINT nLcdY = 0; +UINT nLcdZoom = 1; // memory DC zoom +UINT nGdiXZoom = 1; // GDI x zoom +UINT nGdiYZoom = 1; // GDI y zoom +HDC hLcdDC = NULL; +HDC hMainDC = NULL; +HDC hAnnunDC = NULL; // annunciator DC + +BYTE (*GetLineCounter)(VOID) = NULL; +VOID (*StartDisplay)(BYTE byInitial) = NULL; +VOID (*StopDisplay)(VOID) = NULL; + +static BYTE GetLineCounterGray(VOID); +static BYTE GetLineCounterBW(VOID); +static VOID StartDisplayGray(BYTE byInitial); +static VOID StartDisplayBW(BYTE byInitial); +static VOID StopDisplayGray(VOID); +static VOID StopDisplayBW(VOID); + +static LPBYTE pbyLcd; + +static HBITMAP hLcdBitmap; +static HBITMAP hMainBitmap; +static HBITMAP hAnnunBitmap; + +static DWORD Pattern[16]; +static BYTE Buf[36]; + +static DWORD dwGrayMask; + +static LARGE_INTEGER lLcdRef; // reference time for VBL counter +static UINT uLcdTimerId = 0; + +static BYTE byVblRef = 0; // VBL stop reference + +static DWORD dwKMLColor[64] = // color table loaded by KML script +{ + W,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B, + B,B,B,B,B,B,B,B,B,B,B,B,B,B,B,B, + I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, + I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I +}; + +static struct +{ + BITMAPINFOHEADER Lcd_bmih; + RGBQUAD bmiColors[NOCOLORSGRAY]; +} bmiLcd = +{ + {0x28,0/*x*/,0/*y*/,1,8,BI_RGB,0,0,0,NOCOLORSGRAY,0} +}; + +static __inline VOID BuildPattern(VOID) +{ + _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); + + if (nLcdZoom == 1) + { + WORD i,j; + for (i=0; i<16; ++i) + { + Pattern[i] = 0; + for (j=8; j>0; j>>=1) + { + Pattern[i] = (Pattern[i] << 8) | ((i&j) != 0); + } + } + return; + } + if (nLcdZoom == 2) + { + Pattern[0] = 0x00000000; + Pattern[1] = 0x00000101; + Pattern[2] = 0x01010000; + Pattern[3] = 0x01010101; + return; + } + if (nLcdZoom == 4) + { + Pattern[0] = 0x00000000; + Pattern[1] = 0x01010101; + } + return; +} + +VOID UpdateContrast(BYTE byContrast) +{ + RGBQUAD c,b; + INT i,nColors; + + // table for max. 8 colors + const INT nCAdj[] = { 0, 1, 1, 2, 1, 2, 2, 3 }; + + // when display is off use contrast 0 + if ((Chipset.IORam[BITOFFSET] & DON) == 0) byContrast = 0; + + c = *(RGBQUAD*)&dwKMLColor[byContrast]; // pixel on color + b = *(RGBQUAD*)&dwKMLColor[byContrast+32]; // pixel off color + + // if background color is undefined, use color 0 for compatibility + if (I == *(DWORD*)&b) b = *(RGBQUAD*)&dwKMLColor[0]; + + nColors = bGrayscale ? (NOCOLORSGRAY-1) : (NOCOLORSBW-1); + + _ASSERT(nColors <= ARRAYSIZEOF(nCAdj)); // no. of colors must be smaller than entries in the gray color table + + // fill color palette of bitmap + for (i = 0; i <= nColors; ++i) + { + bmiLcd.bmiColors[i] = b; + bmiLcd.bmiColors[i].rgbRed += ((INT) c.rgbRed - (INT) b.rgbRed) * nCAdj[i] / nCAdj[nColors]; + bmiLcd.bmiColors[i].rgbGreen += ((INT) c.rgbGreen - (INT) b.rgbGreen) * nCAdj[i] / nCAdj[nColors]; + bmiLcd.bmiColors[i].rgbBlue += ((INT) c.rgbBlue - (INT) b.rgbBlue) * nCAdj[i] / nCAdj[nColors]; + } + + // update palette information + _ASSERT(hLcdDC); + SetDIBColorTable(hLcdDC,0,ARRAYSIZEOF(bmiLcd.bmiColors),bmiLcd.bmiColors); + return; +} + +VOID SetLcdColor(UINT nId, UINT nRed, UINT nGreen, UINT nBlue) +{ + dwKMLColor[nId&0x3F] = ((nRed&0xFF)<<16)|((nGreen&0xFF)<<8)|(nBlue&0xFF); + return; +} + +VOID SetLcdMode(BOOL bMode) +{ + if ((bGrayscale = bMode)) + { + // set pixel update mask + dwGrayMask = GRAYMASK(NOCOLORSGRAY); + GetLineCounter = GetLineCounterGray; + StartDisplay = StartDisplayGray; + StopDisplay = StopDisplayGray; + } + else + { + // set pixel update mask + dwGrayMask = GRAYMASK(NOCOLORSBW); + GetLineCounter = GetLineCounterBW; + StartDisplay = StartDisplayBW; + StopDisplay = StopDisplayBW; + } + UpdateContrast(Chipset.contrast); + return; +} + +VOID CreateLcdBitmap(VOID) +{ + // create LCD bitmap + _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); + bmiLcd.Lcd_bmih.biWidth = LCD_ROW * nLcdZoom; + bmiLcd.Lcd_bmih.biHeight = -64 * nLcdZoom; + _ASSERT(hLcdDC == NULL); + VERIFY(hLcdDC = CreateCompatibleDC(hWindowDC)); + VERIFY(hLcdBitmap = CreateDIBSection(hWindowDC,(BITMAPINFO*)&bmiLcd,DIB_RGB_COLORS,(VOID **)&pbyLcd,NULL,0)); + hLcdBitmap = (HBITMAP) SelectObject(hLcdDC,hLcdBitmap); + _ASSERT(hPalette != NULL); + SelectPalette(hLcdDC,hPalette,FALSE); // set palette for LCD DC + RealizePalette(hLcdDC); // realize palette + BuildPattern(); // build Nibble -> DIB mask pattern + SetLcdMode(bGrayscale); // init display update function pointer + return; +} + +VOID DestroyLcdBitmap(VOID) +{ + // set contrast palette to startup colors + WORD i = 0; dwKMLColor[i++] = W; + while (i < 32) dwKMLColor[i++] = B; + while (i < 64) dwKMLColor[i++] = I; + + GetLineCounter = NULL; + StartDisplay = NULL; + StopDisplay = NULL; + + if (hLcdDC != NULL) + { + // destroy LCD bitmap + DeleteObject(SelectObject(hLcdDC,hLcdBitmap)); + DeleteDC(hLcdDC); + hLcdDC = NULL; + hLcdBitmap = NULL; + } + return; +} + +BOOL CreateMainBitmap(LPCTSTR szFilename) +{ + _ASSERT(hWindowDC != NULL); + VERIFY(hMainDC = CreateCompatibleDC(hWindowDC)); + if (hMainDC == NULL) return FALSE; // quit if failed + hMainBitmap = LoadBitmapFile(szFilename,TRUE); + if (hMainBitmap == NULL) + { + DeleteDC(hMainDC); + hMainDC = NULL; + return FALSE; + } + hMainBitmap = (HBITMAP) SelectObject(hMainDC,hMainBitmap); + _ASSERT(hPalette != NULL); + VERIFY(SelectPalette(hMainDC,hPalette,FALSE)); + RealizePalette(hMainDC); + return TRUE; +} + +VOID DestroyMainBitmap(VOID) +{ + if (hMainDC != NULL) + { + // destroy Main bitmap + DeleteObject(SelectObject(hMainDC,hMainBitmap)); + DeleteDC(hMainDC); + hMainDC = NULL; + hMainBitmap = NULL; + } + return; +} + +// +// load annunciator bitmap +// +BOOL CreateAnnunBitmap(LPCTSTR szFilename) +{ + _ASSERT(hWindowDC != NULL); + VERIFY(hAnnunDC = CreateCompatibleDC(hWindowDC)); + if (hAnnunDC == NULL) return FALSE; // quit if failed + hAnnunBitmap = LoadBitmapFile(szFilename,FALSE); + if (hAnnunBitmap == NULL) + { + DeleteDC(hAnnunDC); + hAnnunDC = NULL; + return FALSE; + } + hAnnunBitmap = (HBITMAP) SelectObject(hAnnunDC,hAnnunBitmap); + return TRUE; +} + +// +// destroy annunciator bitmap +// +VOID DestroyAnnunBitmap(VOID) +{ + if (hAnnunDC != NULL) + { + VERIFY(DeleteObject(SelectObject(hAnnunDC,hAnnunBitmap))); + DeleteDC(hAnnunDC); + hAnnunDC = NULL; + hAnnunBitmap = NULL; + } + return; +} + +//**************** +//* +//* LCD functions +//* +//**************** + +VOID UpdateDisplayPointers(VOID) +{ + EnterCriticalSection(&csLcdLock); + { + UINT nLines = LINES(Chipset.lcounter); + + #if defined DEBUG_DISPLAY + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: Update Display Pointer\n"),Chipset.pc); + OutputDebugString(buffer); + } + #endif + + // calculate display width + Chipset.width = (34 + Chipset.loffset + (Chipset.boffset / 4) * 2) & 0xFFFFFFFE; + Chipset.end1 = Chipset.start1 + nLines * Chipset.width; + if (Chipset.end1 < Chipset.start1) + { + // calculate first address of main display + Chipset.start12 = Chipset.end1 - Chipset.width; + // calculate last address of main display + Chipset.end1 = Chipset.start1 - Chipset.width; + } + else + { + Chipset.start12 = Chipset.start1; + } + Chipset.end2 = Chipset.start2 + (64 - nLines) * 34; + } + LeaveCriticalSection(&csLcdLock); + return; +} + +VOID UpdateMainDisplay(VOID) +{ + UINT x, y, nLines; + BYTE *p; + DWORD d; + + #if defined DEBUG_DISPLAY + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: Update Main Display\n"),Chipset.pc); + OutputDebugString(buffer); + } + #endif + + _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); + if (!(Chipset.IORam[BITOFFSET]&DON)) + { + nLines = 64; + ZeroMemory(pbyLcd, LCD_ROW * nLcdZoom * nLines * nLcdZoom); + } + else + { + nLines = LINES(Chipset.lcounter); // main display lines + p = pbyLcd; // bitmap offset + d = 0; // pixel offset counter + if (nLcdZoom == 4) + { + for (y = 0; y < nLines; ++y) + { + // read line with actual start1 address!! + Npeek(Buf,d+Chipset.start1,36); + for (x = 0; x < 36; ++x) // every 4 pixel + { + DIBPIXEL4(p,Pattern[Buf[x]&1]); + DIBPIXEL4(p,Pattern[(Buf[x]>>1) & 1]); + DIBPIXEL4(p,Pattern[(Buf[x]>>2) & 1]); + DIBPIXEL4(p,Pattern[(Buf[x]>>3) & 1]); + } + CopyMemory(p, p-LCD_ROW*4, LCD_ROW*4); + p+=LCD_ROW*4; + CopyMemory(p, p-LCD_ROW*8, LCD_ROW*8); + p+=LCD_ROW*8; + d+=Chipset.width; + } + } + if (nLcdZoom == 3) + { + for (y = 0; y < nLines; ++y) + { + // read line with actual start1 address!! + Npeek(Buf,d+Chipset.start1,36); + for (x = 0; x < 36; ++x) // every 4 pixel + { + DIBPIXEL3(p,(Buf[x]>>0) & 1); + DIBPIXEL3(p,(Buf[x]>>1) & 1); + DIBPIXEL3(p,(Buf[x]>>2) & 1); + DIBPIXEL3(p,(Buf[x]>>3) & 1); + } + CopyMemory(p, p-LCD_ROW*3, LCD_ROW*3); + p+=LCD_ROW*3; + CopyMemory(p, p-LCD_ROW*3, LCD_ROW*3); + p+=LCD_ROW*3; + d+=Chipset.width; + } + } + if (nLcdZoom == 2) + { + for (y = 0; y < nLines; ++y) + { + // read line with actual start1 address!! + Npeek(Buf,d+Chipset.start1,36); + for (x = 0; x < 36; ++x) // every 4 pixel + { + DIBPIXEL4(p,Pattern[Buf[x]&3]); + DIBPIXEL4(p,Pattern[Buf[x]>>2]); + } + CopyMemory(p, p-LCD_ROW*2, LCD_ROW*2); + p+=LCD_ROW*2; + d+=Chipset.width; + } + } + if (nLcdZoom == 1) + { + for (y = 0; y < nLines; ++y) + { + // read line with actual start1 address!! + Npeek(Buf,d+Chipset.start1,36); + for (x = 0; x < 36; ++x) // every 4 pixel + { + DIBPIXEL4(p,Pattern[Buf[x]]); + } + d+=Chipset.width; + } + } + } + EnterCriticalSection(&csGDILock); // solving NT GDI problems + { + StretchBlt(hWindowDC, nLcdX, nLcdY, 131*nLcdZoom*nGdiXZoom, nLines*nLcdZoom*nGdiYZoom, + hLcdDC, Chipset.boffset*nLcdZoom, 0, 131*nLcdZoom, nLines*nLcdZoom,SRCCOPY); + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + return; +} + +VOID UpdateMenuDisplay(VOID) +{ + UINT x, y, nLines; + BYTE *p; + DWORD d; + + #if defined DEBUG_DISPLAY + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: Update Menu Display\n"),Chipset.pc); + OutputDebugString(buffer); + } + #endif + + if (!(Chipset.IORam[BITOFFSET]&DON)) return; + + nLines = LINES(Chipset.lcounter); + if (nLines == 64) return; // menu disabled + + _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); + // calculate bitmap offset + p = pbyLcd + (nLines*nLcdZoom*LCD_ROW*nLcdZoom); + d = 0; // pixel offset counter + if (nLcdZoom == 4) + { + for (y = nLines; y < 64; ++y) + { + Npeek(Buf,d+Chipset.start2,34); // 34 nibbles are viewed + for (x = 0; x < 34; ++x) // every 4 pixel + { + DIBPIXEL4(p,Pattern[Buf[x]&1]); + DIBPIXEL4(p,Pattern[(Buf[x]>>1) & 1]); + DIBPIXEL4(p,Pattern[(Buf[x]>>2) & 1]); + DIBPIXEL4(p,Pattern[(Buf[x]>>3) & 1]); + } + // adjust pointer to 36 DIBPIXEL drawing calls + p += (36-34) * 4 * sizeof(DWORD); + CopyMemory(p, p-LCD_ROW*4, LCD_ROW*4); + p+=LCD_ROW*4; + CopyMemory(p, p-LCD_ROW*8, LCD_ROW*8); + p+=LCD_ROW*8; + d+=34; + } + } + if (nLcdZoom == 3) + { + for (y = nLines; y < 64; ++y) + { + Npeek(Buf,d+Chipset.start2,34); // 34 nibbles are viewed + for (x = 0; x < 34; ++x) // every 4 pixel + { + DIBPIXEL3(p,(Buf[x]>>0) & 1); + DIBPIXEL3(p,(Buf[x]>>1) & 1); + DIBPIXEL3(p,(Buf[x]>>2) & 1); + DIBPIXEL3(p,(Buf[x]>>3) & 1); + } + // adjust pointer to 36 DIBPIXEL drawing calls + p += (36-34) * 3 * sizeof(DWORD); + CopyMemory(p, p-LCD_ROW*3, LCD_ROW*3); + p+=LCD_ROW*3; + CopyMemory(p, p-LCD_ROW*3, LCD_ROW*3); + p+=LCD_ROW*3; + d+=34; + } + } + if (nLcdZoom == 2) + { + for (y = nLines; y < 64; ++y) + { + Npeek(Buf,d+Chipset.start2,34); // 34 nibbles are viewed + for (x = 0; x < 34; ++x) // every 4 pixel + { + DIBPIXEL4(p,Pattern[Buf[x]&3]); + DIBPIXEL4(p,Pattern[Buf[x]>>2]); + } + // adjust pointer to 36 DIBPIXEL drawing calls + p += (36-34) * 2 * sizeof(DWORD); + CopyMemory(p, p-LCD_ROW*2, LCD_ROW*2); + p+=LCD_ROW*2; + d+=34; + } + } + if (nLcdZoom == 1) + { + for (y = nLines; y < 64; ++y) + { + Npeek(Buf,d+Chipset.start2,34); // 34 nibbles are viewed + for (x = 0; x < 34; ++x) // every 4 pixel + { + DIBPIXEL4(p,Pattern[Buf[x]]); + } + // adjust pointer to 36 DIBPIXEL drawing calls + p += (36-34) * 1 * sizeof(DWORD); + d+=34; + } + } + EnterCriticalSection(&csGDILock); // solving NT GDI problems + { + StretchBlt(hWindowDC, nLcdX, nLcdY+nLines*nLcdZoom*nGdiYZoom, + 131*nLcdZoom*nGdiXZoom, (64-nLines)*nLcdZoom*nGdiYZoom, + hLcdDC, 0, nLines*nLcdZoom, 131*nLcdZoom, (64-nLines)*nLcdZoom, SRCCOPY); + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + return; +} + +VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s) +{ + INT x0, x; + INT y0, y; + DWORD *p; + INT lWidth; + UINT nLines; + + if (bGrayscale) return; // no direct writing in grayscale mode + + lWidth = abs(Chipset.width); // display width + nLines = LINES(Chipset.lcounter); // main display lines + + #if defined DEBUG_DISPLAY + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: Write Main Display %x,%u\n"),Chipset.pc,d,s); + OutputDebugString(buffer); + } + #endif + + if (!(Chipset.IORam[BITOFFSET]&DON)) // display off + return; // no drawing + + d -= Chipset.start1; // nibble offset to DISPADDR (start of display) + d += 64 * lWidth; // make positive offset + y0 = abs((INT) d / lWidth - 64); // bitmap row + x0 = (INT) d % lWidth; // bitmap coloumn + y = y0; x = x0; // load loop variables + + // outside main display area + _ASSERT(y0 >= 0 && y0 < (INT) nLines); + + // illegal zoom factor + _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); + + // calculate memory position in LCD bitmap + p = (DWORD*) (pbyLcd + y0*LCD_ROW*nLcdZoom*nLcdZoom + + x0*sizeof(*p)*nLcdZoom); + + while (s--) // loop for nibbles to write + { + if (x<36) // only fill visible area + { + if (nLcdZoom == 4) + { + p[432] = p[288] = p[144] = p[0] = Pattern[(*a)&1]; + p[433] = p[289] = p[145] = p[1] = Pattern[((*a)>>1)&1]; + p[434] = p[290] = p[146] = p[2] = Pattern[((*a)>>2)&1]; + p[435] = p[291] = p[147] = p[3] = Pattern[((*a)>>3)&1]; + } + if (nLcdZoom == 3) + { + LPBYTE b = (LPBYTE) p; + b[216*4+2] = b[216*4+1] = b[216*4+0] = + b[108*4+2] = b[108*4+1] = b[108*4+0] = + b[ 0*4+2] = b[ 0*4+1] = b[ 0*4+0] = (*a)&1; + b[216*4+5] = b[216*4+4] = b[216*4+3] = + b[108*4+5] = b[108*4+4] = b[108*4+3] = + b[ 0*4+5] = b[ 0*4+4] = b[ 0*4+3] = ((*a)>>1)&1; + b[216*4+8] = b[216*4+7] = b[216*4+6] = + b[108*4+8] = b[108*4+7] = b[108*4+6] = + b[ 0*4+8] = b[ 0*4+7] = b[ 0*4+6] = ((*a)>>2)&1; + b[216*4+11] = b[216*4+10] = b[216*4+9] = + b[108*4+11] = b[108*4+10] = b[108*4+9] = + b[ 0*4+11] = b[ 0*4+10] = b[ 0*4+9] = ((*a)>>3)&1; + } + if (nLcdZoom == 2) + { + p[72] = p[0] = Pattern[(*a)&3]; + p[73] = p[1] = Pattern[(*a)>>2]; + } + if (nLcdZoom == 1) + { + *p = Pattern[*a]; + } + } + ++a; // next value to write + ++x; // next x position + if ((x==lWidth)&&s) // end of display line + { + // end of main display area + if (y == (INT) nLines - 1) break; + + x = 0; // first coloumn + ++y; // next row + // recalculate bitmap memory position of new line + p = (DWORD*) (pbyLcd+y*LCD_ROW*nLcdZoom*nLcdZoom); + } + else + p += nLcdZoom; // next x position in bitmap + } + + // update window region + if (y0 != y) // changed more than one line + { + x0 = 0; // no x-position offset + x = 131; // redraw complete lines + + ++y; // redraw this line as well + } + else + { + x0 <<= 2; x <<= 2; // x-position in pixel + _ASSERT(x >= x0); // can't draw negative number of pixel + x -= x0; // number of pixels to update + + x0 -= Chipset.boffset; // adjust x-position with left margin + if (x0 < 0) x0 = 0; + + if (x0 > 131) x0 = 131; // cut right borders + if (x+x0 > 131) x = 131 - x0; + + y = y0 + 1; // draw one line + } + + x0 *= nLcdZoom; // adjust dimensions to pixel size + x *= nLcdZoom; + y0 *= nLcdZoom; + y *= nLcdZoom; + + EnterCriticalSection(&csGDILock); + { + StretchBlt(hWindowDC, nLcdX+x0*nGdiXZoom, nLcdY+y0*nGdiYZoom, + x*nGdiXZoom, (y-y0)*nGdiYZoom, + hLcdDC, x0+Chipset.boffset*nLcdZoom, y0, x, y-y0, SRCCOPY); + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + return; +} + +VOID WriteToMenuDisplay(LPBYTE a, DWORD d, UINT s) +{ + UINT x0, x; + UINT y0, y; + DWORD *p; + UINT nLines; + + if (bGrayscale) return; // no direct writing in grayscale mode + + nLines = LINES(Chipset.lcounter); // main display lines + + #if defined DEBUG_DISPLAY + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: Write Menu Display %x,%u\n"),Chipset.pc,d,s); + OutputDebugString(buffer); + } + #endif + + if (!(Chipset.IORam[BITOFFSET]&DON)) return; + if (nLines == 64) return; // menu disabled + + d -= Chipset.start2; + y0 = y = (d / 34) + nLines; + x0 = x = d % 34; + if (x0 > 32) return; // position out of viewed area + _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); + + // calculate memory position in LCD bitmap + p = (DWORD*) (pbyLcd + y0*LCD_ROW*nLcdZoom*nLcdZoom + + x0*sizeof(*p)*nLcdZoom); + + if (nLcdZoom == 4) + { + while (s--) + { + if (x<34) + { + p[432] = p[288] = p[144] = p[0] = Pattern[(*a)&1]; + p[433] = p[289] = p[145] = p[1] = Pattern[((*a)>>1) &1]; + p[434] = p[290] = p[146] = p[2] = Pattern[((*a)>>2) &1]; + p[435] = p[291] = p[147] = p[3] = Pattern[((*a)>>3) &1]; + } + a++; + x++; + if ((x==34)&&s) + { + x=0; + y++; + if (y==64) break; + p=(DWORD*)(pbyLcd+y*LCD_ROW*16); + } else p+=4; + } + if (y0!=y) // modified more than 1 line + { + x = 34; // full line + x0 = 0; // no offset + } + x0<<=4; x<<=4; // calculate pixel address + y0<<=2; y<<=2; + if (x>524) x=524; + } + if (nLcdZoom == 3) + { + while (s--) + { + if (x<34) + { + LPBYTE b = (LPBYTE) p; + b[216*4+2] = b[216*4+1] = b[216*4+0] = + b[108*4+2] = b[108*4+1] = b[108*4+0] = + b[ 0*4+2] = b[ 0*4+1] = b[ 0*4+0] = (*a)&1; + b[216*4+5] = b[216*4+4] = b[216*4+3] = + b[108*4+5] = b[108*4+4] = b[108*4+3] = + b[ 0*4+5] = b[ 0*4+4] = b[ 0*4+3] = ((*a)>>1)&1; + b[216*4+8] = b[216*4+7] = b[216*4+6] = + b[108*4+8] = b[108*4+7] = b[108*4+6] = + b[ 0*4+8] = b[ 0*4+7] = b[ 0*4+6] = ((*a)>>2)&1; + b[216*4+11] = b[216*4+10] = b[216*4+9] = + b[108*4+11] = b[108*4+10] = b[108*4+9] = + b[ 0*4+11] = b[ 0*4+10] = b[ 0*4+9] = ((*a)>>3)&1; + } + a++; + x++; + if ((x==34)&&s) + { + x=0; + y++; + if (y==64) break; + p=(DWORD*)(pbyLcd+y*LCD_ROW*9); + } else p+=3; + } + if (y0!=y) // modified more than 1 line + { + x = 34; // full line + x0 = 0; // no offset + } + x0*=12; x*=12; // calculate pixel address + y0*=3; y*=3; + if (x>393) x=393; + } + if (nLcdZoom == 2) + { + while (s--) + { + if (x<34) + { + p[72] = p[0] = Pattern[(*a)&3]; + p[73] = p[1] = Pattern[(*a)>>2]; + } + a++; + x++; + if ((x==34)&&s) + { + x=0; + y++; + if (y==64) break; + p=(DWORD*)(pbyLcd+y*LCD_ROW*4); + } else p+=2; + } + if (y0!=y) // modified more than 1 line + { + x = 34; // full line + x0 = 0; // no offset + } + x0<<=3; x<<=3; // calculate pixel address + y0<<=1; y<<=1; + if (x>262) x=262; + } + if (nLcdZoom == 1) + { + while (s--) + { + if (x<34) *p = Pattern[*a]; + a++; + x++; + if ((x==34)&&s) + { + x=0; + y++; + if (y==64) break; + p=(DWORD*)(pbyLcd+y*LCD_ROW); + } else p++; + } + if (y0!=y) // modified more than 1 line + { + x = 34; // full line + x0 = 0; // no offset + } + x0<<=2; x<<=2; // calculate pixel address + if (x>131) x=131; + } + + EnterCriticalSection(&csGDILock); // solving NT GDI problems + { + StretchBlt(hWindowDC, nLcdX+x0*nGdiXZoom, nLcdY+y0*nGdiYZoom, + (x-x0)*nGdiXZoom, (y-y0+nLcdZoom)*nGdiYZoom, + hLcdDC, x0, y0, x-x0, y-y0+nLcdZoom, SRCCOPY); + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + return; +} + +VOID UpdateAnnunciators(DWORD dwUpdateMask) +{ + BYTE c; + UINT i; + + c = (BYTE)(Chipset.IORam[ANNCTRL] | (Chipset.IORam[ANNCTRL+1]<<4)); + // switch annunciators off if timer stopped + if ((c & AON) == 0 || (Chipset.IORam[TIMER2_CTRL] & RUN) == 0) + c = 0; + + for (i = 1; i <= 6; ++i) + { + if ((dwUpdateMask & 0x1) != 0) // annunciator changed? + { + DrawAnnunciator(i,c & 0x1); + } + dwUpdateMask >>= 1; + c >>= 1; + } + _ASSERT(dwUpdateMask == 0); + return; +} + +VOID ResizeWindow(VOID) +{ + if (hWnd != NULL) // if window created + { + RECT rectWindow; + RECT rectClient; + + rectWindow.left = 0; + rectWindow.top = 0; + rectWindow.right = nBackgroundW; + rectWindow.bottom = nBackgroundH; + + AdjustWindowRect(&rectWindow, + (DWORD) GetWindowLongPtr(hWnd,GWL_STYLE), + GetMenu(hWnd) != NULL || IsRectEmpty(&rectWindow)); + SetWindowPos(hWnd, bAlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, + rectWindow.right - rectWindow.left, + rectWindow.bottom - rectWindow.top, + SWP_NOMOVE); + + // check if menu bar wrapped to two or more rows + GetClientRect(hWnd, &rectClient); + if (rectClient.bottom < (LONG) nBackgroundH) + { + rectWindow.bottom += (nBackgroundH - rectClient.bottom); + SetWindowPos (hWnd, NULL, 0, 0, + rectWindow.right - rectWindow.left, + rectWindow.bottom - rectWindow.top, + SWP_NOMOVE | SWP_NOZORDER); + } + + EnterCriticalSection(&csGDILock); // solving NT GDI problems + { + _ASSERT(hWindowDC); // move origin of destination window + VERIFY(SetWindowOrgEx(hWindowDC, nBackgroundX, nBackgroundY, NULL)); + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + InvalidateRect(hWnd,NULL,TRUE); + } + return; +} + +//################ +//# +//# functions for gray scale implementation +//# +//################ + +// main display update routine +static VOID CALLBACK LcdProc(UINT uEventId, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) +{ + EnterCriticalSection(&csLcdLock); + { + UpdateMainDisplay(); // update display + UpdateMenuDisplay(); + } + LeaveCriticalSection(&csLcdLock); + + QueryPerformanceCounter(&lLcdRef); // actual time + + return; + UNREFERENCED_PARAMETER(uEventId); + UNREFERENCED_PARAMETER(uMsg); + UNREFERENCED_PARAMETER(dwUser); + UNREFERENCED_PARAMETER(dw1); + UNREFERENCED_PARAMETER(dw2); +} + +// LCD line counter calculation +static BYTE GetLineCounterGray(VOID) +{ + LARGE_INTEGER lLC; + BYTE byTime; + + if (uLcdTimerId == 0) // display off + return ((Chipset.IORam[LINECOUNT+1] & (LC5|LC4)) << 4) | Chipset.IORam[LINECOUNT]; + + QueryPerformanceCounter(&lLC); // get elapsed time since display update + + // elapsed ticks so far + byTime = (BYTE) (((lLC.QuadPart - lLcdRef.QuadPart) << 12) / lFreq.QuadPart); + + if (byTime > 0x3F) byTime = 0x3F; // all counts made + + return 0x3F - byTime; // update display between VBL counter 0x3F-0x3E +} + +static VOID StartDisplayGray(BYTE byInitial) +{ + if (uLcdTimerId) // LCD update timer running + return; // -> quit + + if (Chipset.IORam[BITOFFSET]&DON) // display on? + { + QueryPerformanceCounter(&lLcdRef); // actual time of top line + + // adjust startup counter to get the right VBL value + _ASSERT(byInitial <= 0x3F); // line counter value 0 - 63 + lLcdRef.QuadPart -= ((LONGLONG) (0x3F - byInitial) * lFreq.QuadPart) >> 12; + + VERIFY(uLcdTimerId = timeSetEvent(DISPLAY_FREQ,0,(LPTIMECALLBACK)&LcdProc,0,TIME_PERIODIC)); + } + return; +} + +static VOID StopDisplayGray(VOID) +{ + BYTE a[2]; + ReadIO(a,LINECOUNT,2,TRUE); // update VBL at display off time + + if (uLcdTimerId == 0) // timer stopped + return; // -> quit + + timeKillEvent(uLcdTimerId); // stop display update + uLcdTimerId = 0; // set flag display update stopped + + EnterCriticalSection(&csLcdLock); // update to last condition + { + UpdateMainDisplay(); // update display + UpdateMenuDisplay(); + } + LeaveCriticalSection(&csLcdLock); + return; +} + +//################ +//# +//# functions for black and white implementation +//# +//################ + +// LCD line counter calculation in BW mode +static BYTE F4096Hz(VOID) // get a 6 bit 4096Hz down counter value +{ + LARGE_INTEGER lLC; + + QueryPerformanceCounter(&lLC); // get counter value + + // calculate 4096 Hz frequency down counter value + return -(BYTE)(((lLC.QuadPart - lAppStart.QuadPart) << 12) / lFreq.QuadPart) & 0x3F; +} + +static BYTE GetLineCounterBW(VOID) // get line counter value +{ + _ASSERT(byVblRef < 0x40); + return (0x40 + F4096Hz() - byVblRef) & 0x3F; +} + +static VOID StartDisplayBW(BYTE byInitial) +{ + // get positive VBL difference between now and stop time + byVblRef = (0x40 + F4096Hz() - byInitial) & 0x3F; + return; +} + +static VOID StopDisplayBW(VOID) +{ + BYTE a[2]; + ReadIO(a,LINECOUNT,2,TRUE); // update VBL at display off time + return; +} diff --git a/Sources/Emu48/disrpl.c b/Sources/Emu48/DISRPL.C similarity index 95% rename from Sources/Emu48/disrpl.c rename to Sources/Emu48/DISRPL.C index c26505c..494eae8 100644 --- a/Sources/Emu48/disrpl.c +++ b/Sources/Emu48/DISRPL.C @@ -1,1604 +1,1604 @@ -/* - * disrpl.c - * - * This file is part of Emu48 - * - * Copyright (C) 2008 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" -#include "disrpl.h" - -DWORD dwRplPlatform = RPL_P3; // current RPL platform - -//################ -//# -//# String Writing Helper Functions -//# -//################ - -#define ALLOCSIZE 256 // string allocation size - -typedef struct -{ - DWORD dwSize; // size of buffer - LPTSTR szBuffer; // buffer - DWORD dwPos; // position inside buffer -} String; - -static VOID PutSn(String *str, LPCTSTR szVal, DWORD dwLen) -{ - if (str != NULL && dwLen > 0) // with output and actual string length - { - // string buffer to small - if (str->dwPos + dwLen > str->dwSize) - { - LPTSTR szNewBuffer; - - DWORD dwMinSize; - dwMinSize = dwLen + str->dwSize - str->dwPos; - dwMinSize = (dwMinSize + ALLOCSIZE - 1) / ALLOCSIZE; - dwMinSize *= ALLOCSIZE; - - str->dwSize += dwMinSize; // new buffer size - VERIFY(szNewBuffer = (LPTSTR) realloc(str->szBuffer,str->dwSize * sizeof(TCHAR))); - - if (szNewBuffer) // new buffer allocated - { - str->szBuffer = szNewBuffer; - } - else // allocation failed - { - str->dwSize = 0; // size of buffer - free(str->szBuffer); // buffer memory - str->szBuffer = NULL; - str->dwPos = 0; // position inside buffer - } - } - - if (str->szBuffer) - { - CopyMemory(&str->szBuffer[str->dwPos],szVal,dwLen * sizeof(TCHAR)); - str->dwPos += dwLen; - } - } - return; -} - -static VOID PutC(String *str, TCHAR cVal) -{ - PutSn(str,&cVal,1); - return; -} - -static VOID PutS(String *str, LPCTSTR szVal) -{ - PutSn(str,szVal,lstrlen(szVal)); - return; -} - -static VOID __cdecl PutFS(String *str, LPCTSTR lpFormat, ...) -{ - if (str != NULL) // with output - { - TCHAR cOutput[1024]; - va_list arglist; - - va_start(arglist,lpFormat); - wvsprintf(cOutput,lpFormat,arglist); - PutS(str,cOutput); - va_end(arglist); - } - return; -} - -static VOID PutCondSpc(String *str) -{ - if (str != NULL) // with output - { - // write space when not at beginning and prior character isn't a whitespace - if ( str->dwPos > 0 - && _tcschr(_T(" \t\n\r"),str->szBuffer[str->dwPos-1]) == NULL) - PutC(str,_T(' ')); - } - return; -} - -//################ -//# -//# RPL Object Decoding -//# -//################ - -static LPCTSTR cHex = _T("0123456789ABCDEF"); - -// function prototypes -static BOOL (*Getfp(LPCTSTR lpszObject))(DWORD *pdwAddr,String *str,UINT *pnLevel); -static BOOL FetchObj(DWORD *pdwAddr,String *str,UINT *pnLevel); - -static DWORD Readx(DWORD *pdwAddr,DWORD n) -{ - DWORD i, t; - - for (i = 0, t = 0; i < n; ++i) - t |= RplReadNibble(pdwAddr) << (i * 4); - - return t; -} - -static BOOL BCDx(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,String *str) -{ - BYTE byNib; - LONG v,lExp; - BOOL bPflag,bExpflag; - DWORD dwStart; - INT i; - - if (str == NULL) return FALSE; // no output - - dwStart = str->dwPos; // starting pos inside string - - lExp = 0; - for (v = 1; nExpLen--; v *= 10) // fetch exponent - { - lExp += (LONG) *pbyNum++ * v; // calc. exponent - } - - if (lExp > v / 2) lExp -= v; // negative exponent - - lExp -= nMantLen - 1; // set decimal point to end of mantissa - - bPflag = FALSE; // show no decimal point - bExpflag = FALSE; // show no exponent - - // scan mantissa - for (v = (LONG) nMantLen - 1; v >= 0 || bPflag; v--) - { - if (v >= 0L) // still mantissa digits left - byNib = *pbyNum++; - else - byNib = 0; // zero for negative exponent - - if (dwStart == str->dwPos) // still delete zeros at end - { - if (byNib == 0 && lExp && v > 0) // delete zeros - { - lExp++; // adjust exponent - continue; - } - - // TRUE at x.E - bExpflag = v + lExp >= nMantLen || lExp < -nMantLen; - bPflag = !bExpflag && v < -lExp; // decimal point flag at neg. exponent - } - - // set decimal point - if ((bExpflag && v == 0) || (!lExp && (dwStart != str->dwPos))) - { - PutC(str,_T('.')); // write decimal point - if (v < 0) // no mantissa digits any more - { -// PutC(str,_T('0')); // write heading zero - } - bPflag = FALSE; // finished with negative exponents - } - - if (v >= 0 || bPflag) - { - TCHAR cVal = (TCHAR) byNib + _T('0'); - PutC(str,cVal); // write character - } - - lExp++; // next position - } - - if (*pbyNum == 9) // negative number - { - PutC(str,_T('-')); // write sign - } - - i = (str->dwPos - dwStart) / 2; - for (v = 0; v < i; v++) // reverse string - { - // swap chars - TCHAR cNib = str->szBuffer[dwStart+v]; - str->szBuffer[dwStart+v] = str->szBuffer[str->dwPos-v-1]; - str->szBuffer[str->dwPos-v-1] = cNib; - } - - // write number with exponent - if (bExpflag) - { - PutFS(str,_T("E%d"),lExp-1); // write exponent - } - return FALSE; -} - -static BOOL BINx(DWORD *pdwAddr,INT nBinLen,String *str) -{ - LPBYTE pbyNumber = (LPBYTE) malloc(nBinLen); - if (pbyNumber != NULL) - { - INT i; - - for (i = 0; i < nBinLen; ++i) // read data - pbyNumber[i] = RplReadNibble(pdwAddr); - - // strip leading zeros - for (i = nBinLen - 1; pbyNumber[i] == 0 && i > 0; --i) { } - - for (; i >= 0; --i) // write rest of bin - { - PutC(str,cHex[pbyNumber[i]]); - } - - free(pbyNumber); - } - return FALSE; -} - -static BOOL ASCIC(DWORD *pdwAddr,String *str) -{ - DWORD dwLength; - - dwLength = Readx(pdwAddr,2); // fetch string length in bytes - - for (; dwLength > 0; --dwLength) - { - PutC(str,(TCHAR) Readx(pdwAddr,2)); // write data byte - } - return FALSE; -} - -static BOOL ASCIX(DWORD *pdwAddr,String *str) -{ - BOOL bErr = ASCIC(pdwAddr,str); // decode a ASCIC - Readx(pdwAddr,2); // skip length information at end - return bErr; -} - -// simple HEX output of object -static BOOL DoHexStream(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwLength; - - dwObjStart = *pdwAddr; // remember start position - dwLength = Readx(pdwAddr,5); // fetch code length in nibbles - if (dwLength < 5) // illegal object length - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - return TRUE; - } - - dwLength -= 5; // no. of DOCODE nibbles - PutFS(str,_T("%X"),dwLength); // write length information - if (dwLength > 0) // have data - { - PutC(str,_T(' ')); - } - - for (;dwLength > 0; --dwLength) - { - PutC(str,cHex[RplReadNibble(pdwAddr)]); // write digit - } - return FALSE; - UNREFERENCED_PARAMETER(pnLevel); -} - -// SEMI stream helper function -static BOOL DoSemiStream(DWORD *pdwAddr,String *str,UINT *pnLevel,LPCTSTR lpszSemi) -{ - DWORD dwObjStart; - BOOL bErr; - - UINT nActLevel = *pnLevel; // save actual nesting level - - (*pnLevel)++; // next level - - dwObjStart = *pdwAddr; // remember start position - - do - { - // eval object - bErr = FetchObj(pdwAddr,str,pnLevel); - } - while (!bErr && *pnLevel != nActLevel); - - if (bErr) // decoding error - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - } - else - { - // no blank because of prior SEMI - PutS(str,lpszSemi); // write semi replacement character - } - return bErr; -} - -// DOINT stream helper function -static BOOL DoIntStream(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - LPBYTE pbyData; - DWORD dwObjStart,dwLength,i; - - dwObjStart = *pdwAddr; // remember start position - dwLength = Readx(pdwAddr,5); // fetch zint length in nibbles - if (dwLength < 5) // illegal object length - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - return TRUE; - } - - dwLength -= 5; // object length - - pbyData = (LPBYTE) malloc(dwLength); - if (pbyData != NULL) - { - for (i = 0; i < dwLength; ++i) // read data - pbyData[i] = RplReadNibble(pdwAddr); - - if (dwLength <= 1) // special implementation for zero - { - _ASSERT(dwLength == 0 || (dwLength == 1 && pbyData[0] == 0)); - PutC(str,_T('0')); - } - else - { - if (pbyData[--dwLength] == 9) // negative number - PutC(str,_T('-')); - - while (dwLength > 0) // write rest of zint - { - // use only decimal part for translation - PutC(str,cHex[pbyData[--dwLength]]); - } - } - - free(pbyData); - } - return FALSE; - UNREFERENCED_PARAMETER(pnLevel); -} - - -//################ -//# -//# RPL Object Primitives -//# -//################ - -static BOOL DoBint(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - PutS(str,_T("# ")); - return BINx(pdwAddr,5,str); // BIN5 - UNREFERENCED_PARAMETER(pnLevel); -} - -static BOOL DoReal(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - BYTE byNumber[16]; - DWORD i; - - PutS(str,_T("% ")); - - // get real object content - for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) - byNumber[i] = RplReadNibble(pdwAddr); - - return BCDx(byNumber,12,3,str); - UNREFERENCED_PARAMETER(pnLevel); -} - -static BOOL DoERel(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - BYTE byNumber[21]; - DWORD i; - - PutS(str,_T("%% ")); - - // get extended real object content - for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) - byNumber[i] = RplReadNibble(pdwAddr); - - return BCDx(byNumber,15,5,str); - UNREFERENCED_PARAMETER(pnLevel); -} - -static BOOL DoCmp(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - BYTE byNumber[16]; - DWORD i; - - PutS(str,_T("C% ")); - - // get real part of complex object content - for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) - byNumber[i] = RplReadNibble(pdwAddr); - - BCDx(byNumber,12,3,str); - - PutC(str,_T(' ')); - - // get imaginary part of complex object content - for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) - byNumber[i] = RplReadNibble(pdwAddr); - - return BCDx(byNumber,12,3,str); - UNREFERENCED_PARAMETER(pnLevel); -} - -static BOOL DoECmp(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - BYTE byNumber[21]; - DWORD i; - - PutS(str,_T("C%% ")); - - // get real part of extended complex object content - for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) - byNumber[i] = RplReadNibble(pdwAddr); - - BCDx(byNumber,15,5,str); - - PutC(str,_T(' ')); - - // get imaginary part of extended complex object content - for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) - byNumber[i] = RplReadNibble(pdwAddr); - - return BCDx(byNumber,15,5,str); - UNREFERENCED_PARAMETER(pnLevel); -} - -static BOOL DoChar(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwChar = Readx(pdwAddr,2); // character code - - PutS(str,_T("CHR ")); - - if (dwChar == ' ') // special handling for space - { - PutS(str,_T("\" \"")); // write space - } - else - { - if (dwChar >= 0x80) // non ASCII character - { - // print as escape sequence - PutC(str,_T('\\')); // escape sequence prefix - PutC(str,cHex[dwChar >> 4]); // print higher nibble - dwChar = cHex[dwChar & 0xF]; // lower nibble - } - else - { - if (dwChar < ' ') // control character - { - PutC(str,_T('^')); // prefix - dwChar += '@'; // convert to control char - } - } - - PutC(str,(TCHAR) dwChar); // print character - } - return FALSE; - UNREFERENCED_PARAMETER(pnLevel); -} - -static BOOL DoArry(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - BOOL (*pObjHandler)(DWORD *,String *,UINT *pnLevel); - LPCTSTR lpszName; - DWORD i,dwObjStart,dwLength,dwObject,dwDims,dwDimI; - - dwObjStart = *pdwAddr; // remember start position - dwLength = Readx(pdwAddr,5); // fetch object length in nibbles - - // look for object handler - dwObject = Readx(pdwAddr,5); // fetch object - lpszName = RplGetName(dwObject); // name of object - if (lpszName == NULL) // unknown type - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - return TRUE; - } - pObjHandler = Getfp(lpszName); // search for object handler - if (pObjHandler == NULL) // unknown object handler - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - return TRUE; - } - - dwDims = Readx(pdwAddr,5); // number of array dimensions - dwDimI = Readx(pdwAddr,5); // 1st dimension - - PutS(str,_T("ARRY ")); - - if (dwDims > 1) // more than 1 dimension - { - DWORD dwDimJ; - - PutFS(str,_T("%u "),dwDimI); // 1st dimension - - // check other dimensions - for (--dwDims; dwDims > 0; --dwDims) - { - dwDimJ = Readx(pdwAddr,5); // other dimensions - PutFS(str,_T("%u "),dwDimJ); // write other dimension - dwDimI *= dwDimJ; // no. of elements - } - } - - PutC(str,_T('[')); - - for (i = 0; i < dwDimI; ++i) - { - PutC(str,_T(' ')); - pObjHandler(pdwAddr,str,pnLevel); // decode object - } - - PutS(str,_T(" ]")); - - // this assert also fail on illegal objects - _ASSERT(dwObjStart + dwLength == *pdwAddr); - return FALSE; -} - -static BOOL DoLnkArry(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - BOOL (*pObjHandler)(DWORD *,String *,UINT *pnLevel); - LPCTSTR lpszName; - DWORD i,dwAddr,dwLength,dwObject,dwDims,dwDimI,dwObjAddr; - - dwAddr = *pdwAddr; // address of array start - dwLength = Readx(&dwAddr,5); // fetch object length in nibbles - - // look for object handler - dwObject = Readx(&dwAddr,5); // fetch object - lpszName = RplGetName(dwObject); // name of object - if (lpszName == NULL) // unknown type - { - return TRUE; // continue decoding behind prolog - } - pObjHandler = Getfp(lpszName); // search for object handler - if (pObjHandler == NULL) // unknown object handler - { - return TRUE; // continue decoding behind prolog - } - - dwDims = Readx(&dwAddr,5); // number of array dimensions - dwDimI = Readx(&dwAddr,5); // 1st dimension - - PutS(str,_T("LNKARRY ")); - - if (dwDims > 1) // more than 1 dimension - { - DWORD dwDimJ; - - PutFS(str,_T("%u "),dwDimI); // 1st dimension - - // check other dimensions - for (--dwDims; dwDims > 0; --dwDims) - { - dwDimJ = Readx(&dwAddr,5); // other dimensions - PutFS(str,_T("%u "),dwDimJ); // write other dimension - dwDimI *= dwDimJ; // no. of elements - } - } - - PutC(str,_T('[')); - - for (i = 0; i < dwDimI; ++i) - { - PutC(str,_T(' ')); - - dwObjAddr = dwAddr; // actual address - dwObject = Readx(&dwAddr,5); // relative link to object - if (dwObject == 0) // empty link - { - PutC(str,_T('_')); - } - else - { - Readx(&dwObjAddr,dwObject); // absolute address - pObjHandler(&dwObjAddr,str,pnLevel); // decode object - } - } - - PutS(str,_T(" ]")); - - Readx(pdwAddr,dwLength); // goto end of link array - return FALSE; -} - -static BOOL DoCStr(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD i,dwObjStart,dwLength,dwC; - - dwObjStart = *pdwAddr; // remember start position - dwLength = Readx(pdwAddr,5); // fetch object length in nibbles - if (dwLength < 5) // illegal object length - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - return TRUE; - } - dwLength = (dwLength - 5) / 2; // string length - - PutS(str,_T("$ \"")); - - for (i = 0; i < dwLength; ++i) - { - dwC = Readx(pdwAddr,2); // character code - - do - { - if (dwC == '\t') // tab - { - PutS(str,_T("\\t")); - break; - } - if (dwC == '\n') // newline - { - PutS(str,_T("\\n")); - break; - } - if (dwC == '\r') // return - { - PutS(str,_T("\\r")); - break; - } - if (dwC < ' ' || dwC >= 0x80) // non ASCII character - { - PutC(str,_T('\\')); // escape sequence prefix - PutC(str,cHex[dwC >> 4]); // print higher nibble - PutC(str,cHex[dwC & 0xF]); // print lower nibble - break; - } - - if (dwC == '"' || dwC == '\\') // double " or \ symbol - PutC(str,(TCHAR) dwC); - - PutC(str,(TCHAR) dwC); // print character - } - while (FALSE); - } - - PutC(str,_T('"')); - return FALSE; - UNREFERENCED_PARAMETER(pnLevel); -} - -static BOOL DoHxs(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD i,dwObjStart,dwLength; - BOOL bRemove; - BYTE byVal; - - dwObjStart = *pdwAddr; // remember start position - dwLength = Readx(pdwAddr,5); // fetch object length in nibbles - if (dwLength < 5) // illegal object length - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - return TRUE; - } - - PutS(str,_T("HXS ")); - - dwLength -= 5; // no. of HXS - PutFS(str,_T("%X"),dwLength); // write length information - if (dwLength > 0) // have data - { - PutC(str,_T(' ')); - } - - bRemove = TRUE; // remove leading zeros - - for (i = 0; i < dwLength; ++i) - { - byVal = RplReadNibble(pdwAddr); - - // remove leading zeros - if (byVal == 0 && bRemove && i + 1 < dwLength) - continue; - - PutC(str,cHex[byVal]); // write digit - bRemove = FALSE; // got non zero digit - } - return FALSE; - UNREFERENCED_PARAMETER(pnLevel); -} - -static BOOL DoList(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - PutC(str,_T('{')); - return DoSemiStream(pdwAddr,str,pnLevel,_T("}")); -} - -static BOOL DoTag(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - PutS(str,_T("TAG ")); - ASCIC(pdwAddr,str); // name - PutC(str,_T(' ')); - return FetchObj(pdwAddr,str,pnLevel); // object -} - -static BOOL DoCol(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - BOOL bErr = FALSE; - - PutS(str,_T("::")); - - if (*pnLevel > 0) // nested objects - { - bErr = DoSemiStream(pdwAddr,str,pnLevel,_T(";")); - } - return bErr; -} - -static BOOL DoCode(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - PutS(str,_T("CODE ")); - return DoHexStream(pdwAddr,str,pnLevel); -} - -static BOOL DoIdnt(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - PutS(str,_T("ID ")); - return ASCIC(pdwAddr,str); - UNREFERENCED_PARAMETER(pnLevel); -} - -static BOOL DoLam(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - PutS(str,_T("LAM ")); - return ASCIC(pdwAddr,str); - UNREFERENCED_PARAMETER(pnLevel); -} - -static BOOL DoRomp(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - PutS(str,_T("ROMPTR ")); - BINx(pdwAddr,3,str); // BIN3 - PutC(str,_T(' ')); - BINx(pdwAddr,3,str); // BIN3 - return FALSE; - UNREFERENCED_PARAMETER(pnLevel); -} - -static BOOL Semi(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - if (*pnLevel > 0) // nested objects - { - (*pnLevel)--; // signaling end, caller handles the semi - } - else - { - PutC(str,_T(';')); // write standard semi - } - return FALSE; - UNREFERENCED_PARAMETER(pdwAddr); -} - -static BOOL DoRrp(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwOffset,dwObjStart,dwBufferPos,dwAddr; - BOOL bErr = FALSE; - - dwObjStart = *pdwAddr; // remember start position of RRP - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("DIR")); - Readx(pdwAddr,3); // skip attachments field - - dwAddr = *pdwAddr; // actual address - dwOffset = Readx(pdwAddr,5); // offset-1 - - if (dwOffset != 0) // directory not empty - { - DWORD dwOffsetAddr; - - Readx(&dwAddr,dwOffset); // name-1 - if (dwAddr < *pdwAddr) // address wrap around - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all DIR output - return TRUE; - } - - *pdwAddr = 0; // unknown end - - do - { - PutC(str,_T('\n')); - PutS(str,_T("VARNAME ")); - - // operation is safe because checked for address wrapping before - dwAddr -= 5; // address of next offset - dwOffsetAddr = dwAddr; - - dwOffset = Readx(&dwAddr,5); // read next offset - bErr = ASCIX(&dwAddr,str); // read name - - PutC(str,_T('\n')); - (*pnLevel)++; // treat object as whole - // eval object - bErr = bErr || FetchObj(&dwAddr,str,pnLevel); - (*pnLevel)--; - - if (*pdwAddr == 0) // first name - { - *pdwAddr = dwAddr; // end of dir - } - - dwAddr = dwOffsetAddr; // address of next offset - - // illegal offset - if (dwOffset >= dwAddr - dwObjStart) - { - *pdwAddr = dwObjStart; // continue decoding behind illegal RRP prolog - str->dwPos = dwBufferPos; // throw out all DIR output - return TRUE; - } - - // operation is safe because checked for address wrapping before - dwAddr -= dwOffset; // address of next name - } - while (!bErr && dwOffset != 0); - } - - PutS(str,_T("\nENDDIR")); - return bErr; -} - -// type specific handler -static BOOL DoExt(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - if (dwRplPlatform <= RPL_P2) // DOEXT - { - PutS(str,_T("EXT0 ")); - bErr = DoHexStream(pdwAddr,str,pnLevel); - } - else // Unit - { - PutS(str,_T("UNIT ")); - bErr = DoSemiStream(pdwAddr,str,pnLevel,_T(";")); - } - - if (bErr) // decoding error - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoSymb(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("SYMBOL ")); - if ((bErr = DoSemiStream(pdwAddr,str,pnLevel,_T(";")))) - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoGrob(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("GROB ")); - if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoLib(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("LIB ")); - if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoBak(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("BAK ")); - if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoExt0(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("LIBDAT ")); - if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoExt1(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - if (dwRplPlatform <= RPL_P3) // DOEXT1 - { - PutS(str,_T("EXT1 ")); - bErr = DoHexStream(pdwAddr,str,pnLevel); - } - else // DOACPTR - { - PutS(str,_T("ACPTR ")); - bErr = BINx(pdwAddr,5,str); // BIN5 - PutC(str,_T(' ')); - bErr = bErr || BINx(pdwAddr,5,str); // BIN5 - } - - if (bErr) // decoding error - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoExt2(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("EXT2 ")); - if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoExt3(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("EXT3 ")); - if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoExt4(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("EXT4 ")); - if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoZint(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("ZINT ")); - if ((bErr = DoIntStream(pdwAddr,str,pnLevel))) - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoLngReal(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos,dwExpLen,dwAddr; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - bErr = DoIntStream(pdwAddr,str,pnLevel); - PutC(str,_T('.')); - - dwAddr = *pdwAddr; // copy of address for Readx() - dwExpLen = Readx(&dwAddr,5); // length of exponent - if (dwExpLen > 6) // non zero exponent - { - PutC(str,_T('E')); - bErr = bErr || DoIntStream(pdwAddr,str,pnLevel); - } - else // no exponent - { - Readx(pdwAddr,dwExpLen); // skip exponent - } - - if (bErr) // decoding error - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr ; -} - -static BOOL DoLngCmp(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutC(str,_T('(')); - bErr = DoLngReal(pdwAddr,str,pnLevel); - PutC(str,_T(',')); - bErr = bErr || DoLngReal(pdwAddr,str,pnLevel); - PutC(str,_T(')')); - - if (bErr) // decoding error - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoFlashPtr(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("FLASHPTR ")); - bErr = BINx(pdwAddr,3,str); // BIN3 - PutC(str,_T(' ')); - bErr = bErr || BINx(pdwAddr,4,str); // BIN4 - - if (bErr) // decoding error - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; - UNREFERENCED_PARAMETER(pnLevel); -} - -static BOOL DoAplet(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("APLET ")); - if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoMinifont(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("MINIFONT ")); - if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static BOOL DoMatrix(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - DWORD dwObjStart,dwBufferPos; - BOOL bErr; - - dwObjStart = *pdwAddr; // remember start position - dwBufferPos = str->dwPos; // insert address of text - - PutS(str,_T("MATRIX")); - if ((bErr = DoSemiStream(pdwAddr,str,pnLevel,_T(";")))) - { - *pdwAddr = dwObjStart; // continue decoding behind prolog - str->dwPos = dwBufferPos; // throw out all output - } - return bErr; -} - -static struct ObjHandler -{ - LPCTSTR lpszName; // object name - // decode function - BOOL (*fp)(DWORD *pdwAddr,String *str,UINT *pnLevel); - DWORD dwType; // calculator type (RPL_P1 = all) -} ObjDecode[] = -{ - _T("DOBINT"), DoBint, RPL_P1, // System Binary - _T("DOREAL"), DoReal, RPL_P1, // Real - _T("DOEREL"), DoERel, RPL_P1, // Long Real - _T("DOCMP"), DoCmp, RPL_P1, // Complex - _T("DOECMP"), DoECmp, RPL_P1, // Long Complex - _T("DOCHAR"), DoChar, RPL_P1, // Character - _T("DOARRY"), DoArry, RPL_P1, // Array - _T("DOLNKARRY"), DoLnkArry, RPL_P1, // Linked Array - _T("DOCSTR"), DoCStr, RPL_P1, // String - _T("DOHSTR"), DoHxs, RPL_P1, // Binary Integer - _T("DOHXS"), DoHxs, RPL_P1, // Binary Integer - _T("DOLIST"), DoList, RPL_P1, // List - _T("DOSYMB"), DoSymb, RPL_P1, // Algebraic - _T("DOCOL"), DoCol, RPL_P1, // Program - _T("DOCODE"), DoCode, RPL_P1, // Code - _T("DOIDNT"), DoIdnt, RPL_P1, // Global Name - _T("DOLAM"), DoLam, RPL_P1, // Local Name - _T("DOROMP"), DoRomp, RPL_P1, // XLIB Name - _T("SEMI"), Semi, RPL_P1, // SEMI - _T("DORRP"), DoRrp, RPL_P2, // Directory - _T("DOEXT"), DoExt, RPL_P2, // Reserved or Unit (HP48 and later) - _T("DOTAG"), DoTag, RPL_P3, // Tagged - _T("DOGROB"), DoGrob, RPL_P3, // Graphic - _T("DOLIB"), DoLib, RPL_P3, // Library - _T("DOBAK"), DoBak, RPL_P3, // Backup - _T("DOEXT0"), DoExt0, RPL_P3, // Library Data - _T("DOEXT1"), DoExt1, RPL_P3, // Ext1 or ACcess PoinTeR - _T("DOACPTR"), DoExt1, RPL_P3, // Ext1 or ACcess PoinTeR - _T("DOEXT2"), DoExt2, RPL_P3, // Reserved 1, Font (HP49G) - _T("DOEXT3"), DoExt3, RPL_P3, // Reserved 2 - _T("DOEXT4"), DoExt4, RPL_P3, // Reserved 3 - _T("DOINT"), DoZint, RPL_P5, // Infinite Precision Integers - _T("DOLNGREAL"), DoLngReal, RPL_P5, // Precision Real - _T("DOLNGCMP"), DoLngCmp, RPL_P5, // Precision Complex - _T("DOFLASHP"), DoFlashPtr, RPL_P5, // Flash Pointer - _T("DOAPLET"), DoAplet, RPL_P5, // Aplet - _T("DOMINIFONT"), DoMinifont, RPL_P5, // Mini Font - _T("DOMATRIX"), DoMatrix, RPL_P5, // Symbolic matrix -}; - -static BOOL (*Getfp(LPCTSTR lpszObject))(DWORD *,String *,UINT *) -{ - UINT i; - - for (i = 0; i < ARRAYSIZEOF(ObjDecode); ++i) - { - if (lstrcmp(lpszObject,ObjDecode[i].lpszName) == 0) - { - // RPL platform type enabled - if ((ObjDecode[i].dwType & dwRplPlatform) == ObjDecode[i].dwType) - return ObjDecode[i].fp; // return object handler - } - } - return NULL; // not found -} - -static BOOL FetchObj(DWORD *pdwAddr,String *str,UINT *pnLevel) -{ - LPCTSTR lpszName; - DWORD dwObject; - BOOL bErr; - - bErr = FALSE; - - PutCondSpc(str); // write blank if necessary - - dwObject = Readx(pdwAddr,5); // fetch object - - lpszName = RplGetName(dwObject); // get name of object - if (lpszName != NULL) - { - // look for object type - BOOL (*fp)(DWORD *,String *,UINT *) = Getfp(lpszName); - - if (fp != NULL) // found an object handler - { - bErr = fp(pdwAddr,str,pnLevel); // call the handler - } - else - { - PutS(str,lpszName); // named entry - } - } - - if (lpszName == NULL || bErr) // no name or illegal object behind prolog - { - PutFS(str,_T("PTR %X"),dwObject); // unnamed entry - } - return bErr; -} - -BYTE (*RplReadNibble)(DWORD *p) = NULL; // get nibble function pointer - -DWORD RplSkipObject(DWORD dwAddr) -{ - UINT nLevel = 1; // nest DOCOL objects - - _ASSERT(RplReadNibble != NULL); // get nibble function defined - FetchObj(&dwAddr,NULL,&nLevel); // decode object without output - return dwAddr; -} - -LPTSTR RplDecodeObject(DWORD dwAddr, DWORD *pdwNxtAddr) -{ - String str = { 0, NULL, 0 }; - DWORD dwNxtAddr; - UINT nLevel = 0; // don't nest DOCOL objects - - dwNxtAddr = dwAddr; // init next address - - _ASSERT(RplReadNibble != NULL); // get nibble function defined - FetchObj(&dwNxtAddr,&str,&nLevel); // decode object - - PutC(&str,0); // set EOS - - // release unnecessary allocated buffer memory (shrinking) - VERIFY(str.szBuffer = (LPTSTR) realloc(str.szBuffer,str.dwPos * sizeof(str.szBuffer[0]))); - - // return address of next object - if (pdwNxtAddr != NULL) *pdwNxtAddr = dwNxtAddr; - return str.szBuffer; -} - - -//################ -//# -//# RPL Object Viewer -//# -//################ - -BOOL bRplViewName = TRUE; // show entry point name -BOOL bRplViewAddr = TRUE; // show address -BOOL bRplViewBin = TRUE; // show binary data -BOOL bRplViewAsm = TRUE; // show ASM code instead of hex data - -static VOID PrintHead(DWORD dwStartAddr, DWORD dwEndAddr, String *str) -{ - if (bRplViewAddr) // show address for object - { - PutFS(str,_T("%05X "),dwStartAddr); - } - - if (bRplViewBin) // show object binary data - { - DWORD dwIndex; - - for (dwIndex = 0; dwIndex < 5; ++dwIndex) - { - TCHAR c = _T(' '); - - if (dwStartAddr < dwEndAddr) // still show hex nibble - { - c = cHex[RplReadNibble(&dwStartAddr)]; - } - - PutC(str,c); // write data content - } - - PutS(str,_T(" ")); - } - else // no binary data - { - if (bRplViewAddr) // missing whitespace - { - PutC(str,_T(' ')); - } - } - return; -} - -static VOID PrintTail(DWORD dwStartAddr, DWORD dwEndAddr, String *str) -{ - if (bRplViewBin) // show binary data - { - DWORD dwActAddr,dwRemain; - - if (dwStartAddr < dwEndAddr) // remaining data to show - { - for (dwActAddr = dwStartAddr; dwActAddr < dwEndAddr;) - { - if (bRplViewAddr) // address is visible - { - // spaces instead of show address - PutS(str,_T(" ")); - - // address has 6 digit - if (dwActAddr >= 0x100000) - PutC(str,_T(' ')); - } - - dwRemain = dwEndAddr - dwActAddr; - if (dwRemain > 5) dwRemain = 5; - - for (; dwRemain > 0; --dwRemain) - { - // write data content - PutC(str,cHex[RplReadNibble(&dwActAddr)]); - } - - PutS(str,_T("\r\n")); - } - } - } - return; -} - -static VOID PrintBlank(String *str) -{ - if (bRplViewAddr) // address is visible - { - PutS(str,_T(" ")); // spaces instead of address - } - if (bRplViewBin) // show binary data - { - if (bRplViewAddr) // address is visible - { - PutC(str,_T(' ')); // need separator - } - - PutS(str,_T(" ")); // spaces instead of binary - } - if (bRplViewAddr || bRplViewBin) // any prefix - { - PutS(str,_T(" ")); // need separator - } - return; -} - -static VOID PrintLevel(DWORD dwLevel, String *str) -{ - for (; dwLevel > 0; --dwLevel) // level depending blanks - { - PutS(str,_T(" ")); - } - return; -} - -#if defined HARDWARE // compiled inside emulator sources -static DWORD AssemblyOutput(DWORD dwAddr, DWORD dwEndAddr, DWORD dwLevel, String *str) -{ - LPCTSTR lpszName; - TCHAR cBuffer[64]; - DWORD dwNxtAddr; - - PrintLevel(dwLevel,str); // level depending blanks - PutS(str,_T("CODE\r\n")); // code preamble - - PrintTail(dwAddr+5,dwAddr+10,str); // write code length information - - ++dwLevel; - - dwAddr += 10; // start of assembler code - - for (; dwAddr < dwEndAddr; dwAddr = dwNxtAddr) - { - // entry name enabled and known entry? - if (bRplViewName && (lpszName = RplGetName(dwAddr)) != NULL) - { - PrintHead(dwAddr,dwAddr,str); // write head for assembly label - PutFS(str,_T("=%s\r\n"),lpszName); - } - - // disassemble line - dwNxtAddr = disassemble(dwAddr,cBuffer); - - PrintHead(dwAddr,dwNxtAddr,str); // write head of assembly line - PrintLevel(dwLevel,str); // level depending blanks - PutS(str,cBuffer); // write disassembler text - PutS(str,_T("\r\n")); - - // write additional binary data of opcode - PrintTail(dwAddr+5,dwNxtAddr,str); - } - - --dwLevel; - - PrintBlank(str); // skip address and binary part - PrintLevel(dwLevel,str); // level depending blanks - PutS(str,_T("ENDCODE")); // code postamble - return dwAddr; -} -#endif - -LPTSTR RplCreateObjView(DWORD dwStartAddr, DWORD dwEndAddr, BOOL bSingleObj) -{ - String str = { 0, NULL, 0 }; - LPCTSTR lpszName; - LPTSTR lpszObject; - DWORD dwLevel,dwAddr,dwNxtAddr; - - _ASSERT(RplReadNibble != NULL); // get nibble function defined - - lpszObject = NULL; // no memory allocated - dwLevel = 0; // nesting level - - // decode object - for (dwAddr = dwStartAddr;dwAddr < dwEndAddr; dwAddr = dwNxtAddr) - { - lpszObject = RplDecodeObject(dwAddr,&dwNxtAddr); - if (lpszObject == NULL) // no memory - { - break; // break decoding - } - - if (dwLevel > 0 && lstrcmp(lpszObject,_T(";")) == 0) - --dwLevel; - - // entry name enabled and known entry? - if (bRplViewName && (lpszName = RplGetName(dwAddr)) != NULL) - { - if (bRplViewAddr) // show address for entry - { - PutFS(&str,_T("%05X "),dwAddr); - } - PutFS(&str,_T("=%s\r\n"),lpszName); - } - - PrintHead(dwAddr,dwAddr+5,&str); // write initial head - - do - { - // check for special RRP handling - if (_tcsncmp(lpszObject,_T("DIR\n"),4) == 0) - { - LPCTSTR lpszStart,lpszEnd; - - lpszStart = lpszEnd = lpszObject; - - // decode lines - while (*lpszEnd != 0) - { - // separate lines - if ((lpszEnd = _tcschr(lpszStart,_T('\n'))) == NULL) - { - VERIFY(lpszEnd = _tcschr(lpszStart,0)); - } - - if (dwLevel > 0 && _tcsncmp(lpszStart,_T("ENDDIR"),lpszEnd-lpszStart) == 0) - --dwLevel; - - // level depending blanks - PrintLevel(dwLevel,&str); - - // write line without LF - PutSn(&str,lpszStart,(DWORD) (lpszEnd-lpszStart)); - - if (_tcsncmp(lpszStart,_T("DIR"),lpszEnd-lpszStart) == 0) - ++dwLevel; - - if (*lpszEnd != 0) // more data? - { - PutS(&str,_T("\r\n")); // send CR LF - PrintBlank(&str); - lpszStart = lpszEnd + 1; // next part - } - } - break; - } - - #if defined HARDWARE // compiled inside emulator sources - // check for special CODE handling - if (bRplViewAsm && _tcsncmp(lpszObject,_T("CODE "),5) == 0) - { - // replace object by a disassembler output - dwAddr = AssemblyOutput(dwAddr,dwNxtAddr,dwLevel,&str); - break; - } - #endif - - // default, show the object - PrintLevel(dwLevel,&str); // level depending blanks - PutS(&str,lpszObject); // the object - } - while (FALSE); - PutS(&str,_T("\r\n")); - - PrintTail(dwAddr+5,dwNxtAddr,&str); // write additional binary data - - if (lstrcmp(lpszObject,_T("::")) == 0) - ++dwLevel; - - free(lpszObject); // free object string - lpszObject = NULL; - - if ( (bSingleObj && dwLevel == 0) // single object decoding? - || (dwNxtAddr < dwAddr)) // or address wrap around - break; // stop decoding - } - - _ASSERT(lpszObject == NULL); - - // remove CR LF at end - while ( str.dwPos > 0 - && ( str.szBuffer[str.dwPos-1] == _T('\r') - || str.szBuffer[str.dwPos-1] == _T('\n') - ) - ) - { - str.dwPos--; - } - - PutC(&str,0); // set EOS - - // release unnecessary allocated buffer memory (shrinking) - VERIFY(str.szBuffer = (LPTSTR) realloc(str.szBuffer,str.dwPos * sizeof(str.szBuffer[0]))); - return str.szBuffer; -} +/* + * disrpl.c + * + * This file is part of Emu48 + * + * Copyright (C) 2008 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" +#include "disrpl.h" + +DWORD dwRplPlatform = RPL_P3; // current RPL platform + +//################ +//# +//# String Writing Helper Functions +//# +//################ + +#define ALLOCSIZE 256 // string allocation size + +typedef struct +{ + DWORD dwSize; // size of buffer + LPTSTR szBuffer; // buffer + DWORD dwPos; // position inside buffer +} String; + +static VOID PutSn(String *str, LPCTSTR szVal, DWORD dwLen) +{ + if (str != NULL && dwLen > 0) // with output and actual string length + { + // string buffer to small + if (str->dwPos + dwLen > str->dwSize) + { + LPTSTR szNewBuffer; + + DWORD dwMinSize; + dwMinSize = dwLen + str->dwSize - str->dwPos; + dwMinSize = (dwMinSize + ALLOCSIZE - 1) / ALLOCSIZE; + dwMinSize *= ALLOCSIZE; + + str->dwSize += dwMinSize; // new buffer size + VERIFY(szNewBuffer = (LPTSTR) realloc(str->szBuffer,str->dwSize * sizeof(TCHAR))); + + if (szNewBuffer) // new buffer allocated + { + str->szBuffer = szNewBuffer; + } + else // allocation failed + { + str->dwSize = 0; // size of buffer + free(str->szBuffer); // buffer memory + str->szBuffer = NULL; + str->dwPos = 0; // position inside buffer + } + } + + if (str->szBuffer) + { + CopyMemory(&str->szBuffer[str->dwPos],szVal,dwLen * sizeof(TCHAR)); + str->dwPos += dwLen; + } + } + return; +} + +static VOID PutC(String *str, TCHAR cVal) +{ + PutSn(str,&cVal,1); + return; +} + +static VOID PutS(String *str, LPCTSTR szVal) +{ + PutSn(str,szVal,lstrlen(szVal)); + return; +} + +static VOID __cdecl PutFS(String *str, LPCTSTR lpFormat, ...) +{ + if (str != NULL) // with output + { + TCHAR cOutput[1024]; + va_list arglist; + + va_start(arglist,lpFormat); + wvsprintf(cOutput,lpFormat,arglist); + PutS(str,cOutput); + va_end(arglist); + } + return; +} + +static VOID PutCondSpc(String *str) +{ + if (str != NULL) // with output + { + // write space when not at beginning and prior character isn't a whitespace + if ( str->dwPos > 0 + && _tcschr(_T(" \t\n\r"),str->szBuffer[str->dwPos-1]) == NULL) + PutC(str,_T(' ')); + } + return; +} + +//################ +//# +//# RPL Object Decoding +//# +//################ + +static LPCTSTR cHex = _T("0123456789ABCDEF"); + +// function prototypes +static BOOL (*Getfp(LPCTSTR lpszObject))(DWORD *pdwAddr,String *str,UINT *pnLevel); +static BOOL FetchObj(DWORD *pdwAddr,String *str,UINT *pnLevel); + +static DWORD Readx(DWORD *pdwAddr,DWORD n) +{ + DWORD i, t; + + for (i = 0, t = 0; i < n; ++i) + t |= RplReadNibble(pdwAddr) << (i * 4); + + return t; +} + +static BOOL BCDx(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,String *str) +{ + BYTE byNib; + LONG v,lExp; + BOOL bPflag,bExpflag; + DWORD dwStart; + INT i; + + if (str == NULL) return FALSE; // no output + + dwStart = str->dwPos; // starting pos inside string + + lExp = 0; + for (v = 1; nExpLen--; v *= 10) // fetch exponent + { + lExp += (LONG) *pbyNum++ * v; // calc. exponent + } + + if (lExp > v / 2) lExp -= v; // negative exponent + + lExp -= nMantLen - 1; // set decimal point to end of mantissa + + bPflag = FALSE; // show no decimal point + bExpflag = FALSE; // show no exponent + + // scan mantissa + for (v = (LONG) nMantLen - 1; v >= 0 || bPflag; v--) + { + if (v >= 0L) // still mantissa digits left + byNib = *pbyNum++; + else + byNib = 0; // zero for negative exponent + + if (dwStart == str->dwPos) // still delete zeros at end + { + if (byNib == 0 && lExp && v > 0) // delete zeros + { + lExp++; // adjust exponent + continue; + } + + // TRUE at x.E + bExpflag = v + lExp >= nMantLen || lExp < -nMantLen; + bPflag = !bExpflag && v < -lExp; // decimal point flag at neg. exponent + } + + // set decimal point + if ((bExpflag && v == 0) || (!lExp && (dwStart != str->dwPos))) + { + PutC(str,_T('.')); // write decimal point + if (v < 0) // no mantissa digits any more + { +// PutC(str,_T('0')); // write heading zero + } + bPflag = FALSE; // finished with negative exponents + } + + if (v >= 0 || bPflag) + { + TCHAR cVal = (TCHAR) byNib + _T('0'); + PutC(str,cVal); // write character + } + + lExp++; // next position + } + + if (*pbyNum == 9) // negative number + { + PutC(str,_T('-')); // write sign + } + + i = (str->dwPos - dwStart) / 2; + for (v = 0; v < i; v++) // reverse string + { + // swap chars + TCHAR cNib = str->szBuffer[dwStart+v]; + str->szBuffer[dwStart+v] = str->szBuffer[str->dwPos-v-1]; + str->szBuffer[str->dwPos-v-1] = cNib; + } + + // write number with exponent + if (bExpflag) + { + PutFS(str,_T("E%d"),lExp-1); // write exponent + } + return FALSE; +} + +static BOOL BINx(DWORD *pdwAddr,INT nBinLen,String *str) +{ + LPBYTE pbyNumber = (LPBYTE) malloc(nBinLen); + if (pbyNumber != NULL) + { + INT i; + + for (i = 0; i < nBinLen; ++i) // read data + pbyNumber[i] = RplReadNibble(pdwAddr); + + // strip leading zeros + for (i = nBinLen - 1; pbyNumber[i] == 0 && i > 0; --i) { } + + for (; i >= 0; --i) // write rest of bin + { + PutC(str,cHex[pbyNumber[i]]); + } + + free(pbyNumber); + } + return FALSE; +} + +static BOOL ASCIC(DWORD *pdwAddr,String *str) +{ + DWORD dwLength; + + dwLength = Readx(pdwAddr,2); // fetch string length in bytes + + for (; dwLength > 0; --dwLength) + { + PutC(str,(TCHAR) Readx(pdwAddr,2)); // write data byte + } + return FALSE; +} + +static BOOL ASCIX(DWORD *pdwAddr,String *str) +{ + BOOL bErr = ASCIC(pdwAddr,str); // decode a ASCIC + Readx(pdwAddr,2); // skip length information at end + return bErr; +} + +// simple HEX output of object +static BOOL DoHexStream(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwLength; + + dwObjStart = *pdwAddr; // remember start position + dwLength = Readx(pdwAddr,5); // fetch code length in nibbles + if (dwLength < 5) // illegal object length + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + return TRUE; + } + + dwLength -= 5; // no. of DOCODE nibbles + PutFS(str,_T("%X"),dwLength); // write length information + if (dwLength > 0) // have data + { + PutC(str,_T(' ')); + } + + for (;dwLength > 0; --dwLength) + { + PutC(str,cHex[RplReadNibble(pdwAddr)]); // write digit + } + return FALSE; + UNREFERENCED_PARAMETER(pnLevel); +} + +// SEMI stream helper function +static BOOL DoSemiStream(DWORD *pdwAddr,String *str,UINT *pnLevel,LPCTSTR lpszSemi) +{ + DWORD dwObjStart; + BOOL bErr; + + UINT nActLevel = *pnLevel; // save actual nesting level + + (*pnLevel)++; // next level + + dwObjStart = *pdwAddr; // remember start position + + do + { + // eval object + bErr = FetchObj(pdwAddr,str,pnLevel); + } + while (!bErr && *pnLevel != nActLevel); + + if (bErr) // decoding error + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + } + else + { + // no blank because of prior SEMI + PutS(str,lpszSemi); // write semi replacement character + } + return bErr; +} + +// DOINT stream helper function +static BOOL DoIntStream(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + LPBYTE pbyData; + DWORD dwObjStart,dwLength,i; + + dwObjStart = *pdwAddr; // remember start position + dwLength = Readx(pdwAddr,5); // fetch zint length in nibbles + if (dwLength < 5) // illegal object length + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + return TRUE; + } + + dwLength -= 5; // object length + + pbyData = (LPBYTE) malloc(dwLength); + if (pbyData != NULL) + { + for (i = 0; i < dwLength; ++i) // read data + pbyData[i] = RplReadNibble(pdwAddr); + + if (dwLength <= 1) // special implementation for zero + { + _ASSERT(dwLength == 0 || (dwLength == 1 && pbyData[0] == 0)); + PutC(str,_T('0')); + } + else + { + if (pbyData[--dwLength] == 9) // negative number + PutC(str,_T('-')); + + while (dwLength > 0) // write rest of zint + { + // use only decimal part for translation + PutC(str,cHex[pbyData[--dwLength]]); + } + } + + free(pbyData); + } + return FALSE; + UNREFERENCED_PARAMETER(pnLevel); +} + + +//################ +//# +//# RPL Object Primitives +//# +//################ + +static BOOL DoBint(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + PutS(str,_T("# ")); + return BINx(pdwAddr,5,str); // BIN5 + UNREFERENCED_PARAMETER(pnLevel); +} + +static BOOL DoReal(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + BYTE byNumber[16]; + DWORD i; + + PutS(str,_T("% ")); + + // get real object content + for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) + byNumber[i] = RplReadNibble(pdwAddr); + + return BCDx(byNumber,12,3,str); + UNREFERENCED_PARAMETER(pnLevel); +} + +static BOOL DoERel(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + BYTE byNumber[21]; + DWORD i; + + PutS(str,_T("%% ")); + + // get extended real object content + for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) + byNumber[i] = RplReadNibble(pdwAddr); + + return BCDx(byNumber,15,5,str); + UNREFERENCED_PARAMETER(pnLevel); +} + +static BOOL DoCmp(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + BYTE byNumber[16]; + DWORD i; + + PutS(str,_T("C% ")); + + // get real part of complex object content + for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) + byNumber[i] = RplReadNibble(pdwAddr); + + BCDx(byNumber,12,3,str); + + PutC(str,_T(' ')); + + // get imaginary part of complex object content + for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) + byNumber[i] = RplReadNibble(pdwAddr); + + return BCDx(byNumber,12,3,str); + UNREFERENCED_PARAMETER(pnLevel); +} + +static BOOL DoECmp(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + BYTE byNumber[21]; + DWORD i; + + PutS(str,_T("C%% ")); + + // get real part of extended complex object content + for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) + byNumber[i] = RplReadNibble(pdwAddr); + + BCDx(byNumber,15,5,str); + + PutC(str,_T(' ')); + + // get imaginary part of extended complex object content + for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) + byNumber[i] = RplReadNibble(pdwAddr); + + return BCDx(byNumber,15,5,str); + UNREFERENCED_PARAMETER(pnLevel); +} + +static BOOL DoChar(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwChar = Readx(pdwAddr,2); // character code + + PutS(str,_T("CHR ")); + + if (dwChar == ' ') // special handling for space + { + PutS(str,_T("\" \"")); // write space + } + else + { + if (dwChar >= 0x80) // non ASCII character + { + // print as escape sequence + PutC(str,_T('\\')); // escape sequence prefix + PutC(str,cHex[dwChar >> 4]); // print higher nibble + dwChar = cHex[dwChar & 0xF]; // lower nibble + } + else + { + if (dwChar < ' ') // control character + { + PutC(str,_T('^')); // prefix + dwChar += '@'; // convert to control char + } + } + + PutC(str,(TCHAR) dwChar); // print character + } + return FALSE; + UNREFERENCED_PARAMETER(pnLevel); +} + +static BOOL DoArry(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + BOOL (*pObjHandler)(DWORD *,String *,UINT *pnLevel); + LPCTSTR lpszName; + DWORD i,dwObjStart,dwLength,dwObject,dwDims,dwDimI; + + dwObjStart = *pdwAddr; // remember start position + dwLength = Readx(pdwAddr,5); // fetch object length in nibbles + + // look for object handler + dwObject = Readx(pdwAddr,5); // fetch object + lpszName = RplGetName(dwObject); // name of object + if (lpszName == NULL) // unknown type + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + return TRUE; + } + pObjHandler = Getfp(lpszName); // search for object handler + if (pObjHandler == NULL) // unknown object handler + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + return TRUE; + } + + dwDims = Readx(pdwAddr,5); // number of array dimensions + dwDimI = Readx(pdwAddr,5); // 1st dimension + + PutS(str,_T("ARRY ")); + + if (dwDims > 1) // more than 1 dimension + { + DWORD dwDimJ; + + PutFS(str,_T("%u "),dwDimI); // 1st dimension + + // check other dimensions + for (--dwDims; dwDims > 0; --dwDims) + { + dwDimJ = Readx(pdwAddr,5); // other dimensions + PutFS(str,_T("%u "),dwDimJ); // write other dimension + dwDimI *= dwDimJ; // no. of elements + } + } + + PutC(str,_T('[')); + + for (i = 0; i < dwDimI; ++i) + { + PutC(str,_T(' ')); + pObjHandler(pdwAddr,str,pnLevel); // decode object + } + + PutS(str,_T(" ]")); + + // this assert also fail on illegal objects + _ASSERT(dwObjStart + dwLength == *pdwAddr); + return FALSE; +} + +static BOOL DoLnkArry(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + BOOL (*pObjHandler)(DWORD *,String *,UINT *pnLevel); + LPCTSTR lpszName; + DWORD i,dwAddr,dwLength,dwObject,dwDims,dwDimI,dwObjAddr; + + dwAddr = *pdwAddr; // address of array start + dwLength = Readx(&dwAddr,5); // fetch object length in nibbles + + // look for object handler + dwObject = Readx(&dwAddr,5); // fetch object + lpszName = RplGetName(dwObject); // name of object + if (lpszName == NULL) // unknown type + { + return TRUE; // continue decoding behind prolog + } + pObjHandler = Getfp(lpszName); // search for object handler + if (pObjHandler == NULL) // unknown object handler + { + return TRUE; // continue decoding behind prolog + } + + dwDims = Readx(&dwAddr,5); // number of array dimensions + dwDimI = Readx(&dwAddr,5); // 1st dimension + + PutS(str,_T("LNKARRY ")); + + if (dwDims > 1) // more than 1 dimension + { + DWORD dwDimJ; + + PutFS(str,_T("%u "),dwDimI); // 1st dimension + + // check other dimensions + for (--dwDims; dwDims > 0; --dwDims) + { + dwDimJ = Readx(&dwAddr,5); // other dimensions + PutFS(str,_T("%u "),dwDimJ); // write other dimension + dwDimI *= dwDimJ; // no. of elements + } + } + + PutC(str,_T('[')); + + for (i = 0; i < dwDimI; ++i) + { + PutC(str,_T(' ')); + + dwObjAddr = dwAddr; // actual address + dwObject = Readx(&dwAddr,5); // relative link to object + if (dwObject == 0) // empty link + { + PutC(str,_T('_')); + } + else + { + Readx(&dwObjAddr,dwObject); // absolute address + pObjHandler(&dwObjAddr,str,pnLevel); // decode object + } + } + + PutS(str,_T(" ]")); + + Readx(pdwAddr,dwLength); // goto end of link array + return FALSE; +} + +static BOOL DoCStr(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD i,dwObjStart,dwLength,dwC; + + dwObjStart = *pdwAddr; // remember start position + dwLength = Readx(pdwAddr,5); // fetch object length in nibbles + if (dwLength < 5) // illegal object length + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + return TRUE; + } + dwLength = (dwLength - 5) / 2; // string length + + PutS(str,_T("$ \"")); + + for (i = 0; i < dwLength; ++i) + { + dwC = Readx(pdwAddr,2); // character code + + do + { + if (dwC == '\t') // tab + { + PutS(str,_T("\\t")); + break; + } + if (dwC == '\n') // newline + { + PutS(str,_T("\\n")); + break; + } + if (dwC == '\r') // return + { + PutS(str,_T("\\r")); + break; + } + if (dwC < ' ' || dwC >= 0x80) // non ASCII character + { + PutC(str,_T('\\')); // escape sequence prefix + PutC(str,cHex[dwC >> 4]); // print higher nibble + PutC(str,cHex[dwC & 0xF]); // print lower nibble + break; + } + + if (dwC == '"' || dwC == '\\') // double " or \ symbol + PutC(str,(TCHAR) dwC); + + PutC(str,(TCHAR) dwC); // print character + } + while (FALSE); + } + + PutC(str,_T('"')); + return FALSE; + UNREFERENCED_PARAMETER(pnLevel); +} + +static BOOL DoHxs(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD i,dwObjStart,dwLength; + BOOL bRemove; + BYTE byVal; + + dwObjStart = *pdwAddr; // remember start position + dwLength = Readx(pdwAddr,5); // fetch object length in nibbles + if (dwLength < 5) // illegal object length + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + return TRUE; + } + + PutS(str,_T("HXS ")); + + dwLength -= 5; // no. of HXS + PutFS(str,_T("%X"),dwLength); // write length information + if (dwLength > 0) // have data + { + PutC(str,_T(' ')); + } + + bRemove = TRUE; // remove leading zeros + + for (i = 0; i < dwLength; ++i) + { + byVal = RplReadNibble(pdwAddr); + + // remove leading zeros + if (byVal == 0 && bRemove && i + 1 < dwLength) + continue; + + PutC(str,cHex[byVal]); // write digit + bRemove = FALSE; // got non zero digit + } + return FALSE; + UNREFERENCED_PARAMETER(pnLevel); +} + +static BOOL DoList(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + PutC(str,_T('{')); + return DoSemiStream(pdwAddr,str,pnLevel,_T("}")); +} + +static BOOL DoTag(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + PutS(str,_T("TAG ")); + ASCIC(pdwAddr,str); // name + PutC(str,_T(' ')); + return FetchObj(pdwAddr,str,pnLevel); // object +} + +static BOOL DoCol(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + BOOL bErr = FALSE; + + PutS(str,_T("::")); + + if (*pnLevel > 0) // nested objects + { + bErr = DoSemiStream(pdwAddr,str,pnLevel,_T(";")); + } + return bErr; +} + +static BOOL DoCode(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + PutS(str,_T("CODE ")); + return DoHexStream(pdwAddr,str,pnLevel); +} + +static BOOL DoIdnt(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + PutS(str,_T("ID ")); + return ASCIC(pdwAddr,str); + UNREFERENCED_PARAMETER(pnLevel); +} + +static BOOL DoLam(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + PutS(str,_T("LAM ")); + return ASCIC(pdwAddr,str); + UNREFERENCED_PARAMETER(pnLevel); +} + +static BOOL DoRomp(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + PutS(str,_T("ROMPTR ")); + BINx(pdwAddr,3,str); // BIN3 + PutC(str,_T(' ')); + BINx(pdwAddr,3,str); // BIN3 + return FALSE; + UNREFERENCED_PARAMETER(pnLevel); +} + +static BOOL Semi(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + if (*pnLevel > 0) // nested objects + { + (*pnLevel)--; // signaling end, caller handles the semi + } + else + { + PutC(str,_T(';')); // write standard semi + } + return FALSE; + UNREFERENCED_PARAMETER(pdwAddr); +} + +static BOOL DoRrp(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwOffset,dwObjStart,dwBufferPos,dwAddr; + BOOL bErr = FALSE; + + dwObjStart = *pdwAddr; // remember start position of RRP + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("DIR")); + Readx(pdwAddr,3); // skip attachments field + + dwAddr = *pdwAddr; // actual address + dwOffset = Readx(pdwAddr,5); // offset-1 + + if (dwOffset != 0) // directory not empty + { + DWORD dwOffsetAddr; + + Readx(&dwAddr,dwOffset); // name-1 + if (dwAddr < *pdwAddr) // address wrap around + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all DIR output + return TRUE; + } + + *pdwAddr = 0; // unknown end + + do + { + PutC(str,_T('\n')); + PutS(str,_T("VARNAME ")); + + // operation is safe because checked for address wrapping before + dwAddr -= 5; // address of next offset + dwOffsetAddr = dwAddr; + + dwOffset = Readx(&dwAddr,5); // read next offset + bErr = ASCIX(&dwAddr,str); // read name + + PutC(str,_T('\n')); + (*pnLevel)++; // treat object as whole + // eval object + bErr = bErr || FetchObj(&dwAddr,str,pnLevel); + (*pnLevel)--; + + if (*pdwAddr == 0) // first name + { + *pdwAddr = dwAddr; // end of dir + } + + dwAddr = dwOffsetAddr; // address of next offset + + // illegal offset + if (dwOffset >= dwAddr - dwObjStart) + { + *pdwAddr = dwObjStart; // continue decoding behind illegal RRP prolog + str->dwPos = dwBufferPos; // throw out all DIR output + return TRUE; + } + + // operation is safe because checked for address wrapping before + dwAddr -= dwOffset; // address of next name + } + while (!bErr && dwOffset != 0); + } + + PutS(str,_T("\nENDDIR")); + return bErr; +} + +// type specific handler +static BOOL DoExt(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + if (dwRplPlatform <= RPL_P2) // DOEXT + { + PutS(str,_T("EXT0 ")); + bErr = DoHexStream(pdwAddr,str,pnLevel); + } + else // Unit + { + PutS(str,_T("UNIT ")); + bErr = DoSemiStream(pdwAddr,str,pnLevel,_T(";")); + } + + if (bErr) // decoding error + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoSymb(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("SYMBOL ")); + if ((bErr = DoSemiStream(pdwAddr,str,pnLevel,_T(";")))) + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoGrob(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("GROB ")); + if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoLib(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("LIB ")); + if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoBak(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("BAK ")); + if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoExt0(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("LIBDAT ")); + if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoExt1(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + if (dwRplPlatform <= RPL_P3) // DOEXT1 + { + PutS(str,_T("EXT1 ")); + bErr = DoHexStream(pdwAddr,str,pnLevel); + } + else // DOACPTR + { + PutS(str,_T("ACPTR ")); + bErr = BINx(pdwAddr,5,str); // BIN5 + PutC(str,_T(' ')); + bErr = bErr || BINx(pdwAddr,5,str); // BIN5 + } + + if (bErr) // decoding error + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoExt2(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("EXT2 ")); + if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoExt3(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("EXT3 ")); + if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoExt4(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("EXT4 ")); + if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoZint(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("ZINT ")); + if ((bErr = DoIntStream(pdwAddr,str,pnLevel))) + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoLngReal(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos,dwExpLen,dwAddr; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + bErr = DoIntStream(pdwAddr,str,pnLevel); + PutC(str,_T('.')); + + dwAddr = *pdwAddr; // copy of address for Readx() + dwExpLen = Readx(&dwAddr,5); // length of exponent + if (dwExpLen > 6) // non zero exponent + { + PutC(str,_T('E')); + bErr = bErr || DoIntStream(pdwAddr,str,pnLevel); + } + else // no exponent + { + Readx(pdwAddr,dwExpLen); // skip exponent + } + + if (bErr) // decoding error + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr ; +} + +static BOOL DoLngCmp(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutC(str,_T('(')); + bErr = DoLngReal(pdwAddr,str,pnLevel); + PutC(str,_T(',')); + bErr = bErr || DoLngReal(pdwAddr,str,pnLevel); + PutC(str,_T(')')); + + if (bErr) // decoding error + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoFlashPtr(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("FLASHPTR ")); + bErr = BINx(pdwAddr,3,str); // BIN3 + PutC(str,_T(' ')); + bErr = bErr || BINx(pdwAddr,4,str); // BIN4 + + if (bErr) // decoding error + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; + UNREFERENCED_PARAMETER(pnLevel); +} + +static BOOL DoAplet(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("APLET ")); + if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoMinifont(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("MINIFONT ")); + if ((bErr = DoHexStream(pdwAddr,str,pnLevel))) + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static BOOL DoMatrix(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + DWORD dwObjStart,dwBufferPos; + BOOL bErr; + + dwObjStart = *pdwAddr; // remember start position + dwBufferPos = str->dwPos; // insert address of text + + PutS(str,_T("MATRIX")); + if ((bErr = DoSemiStream(pdwAddr,str,pnLevel,_T(";")))) + { + *pdwAddr = dwObjStart; // continue decoding behind prolog + str->dwPos = dwBufferPos; // throw out all output + } + return bErr; +} + +static struct ObjHandler +{ + LPCTSTR lpszName; // object name + // decode function + BOOL (*fp)(DWORD *pdwAddr,String *str,UINT *pnLevel); + DWORD dwType; // calculator type (RPL_P1 = all) +} ObjDecode[] = +{ + _T("DOBINT"), DoBint, RPL_P1, // System Binary + _T("DOREAL"), DoReal, RPL_P1, // Real + _T("DOEREL"), DoERel, RPL_P1, // Long Real + _T("DOCMP"), DoCmp, RPL_P1, // Complex + _T("DOECMP"), DoECmp, RPL_P1, // Long Complex + _T("DOCHAR"), DoChar, RPL_P1, // Character + _T("DOARRY"), DoArry, RPL_P1, // Array + _T("DOLNKARRY"), DoLnkArry, RPL_P1, // Linked Array + _T("DOCSTR"), DoCStr, RPL_P1, // String + _T("DOHSTR"), DoHxs, RPL_P1, // Binary Integer + _T("DOHXS"), DoHxs, RPL_P1, // Binary Integer + _T("DOLIST"), DoList, RPL_P1, // List + _T("DOSYMB"), DoSymb, RPL_P1, // Algebraic + _T("DOCOL"), DoCol, RPL_P1, // Program + _T("DOCODE"), DoCode, RPL_P1, // Code + _T("DOIDNT"), DoIdnt, RPL_P1, // Global Name + _T("DOLAM"), DoLam, RPL_P1, // Local Name + _T("DOROMP"), DoRomp, RPL_P1, // XLIB Name + _T("SEMI"), Semi, RPL_P1, // SEMI + _T("DORRP"), DoRrp, RPL_P2, // Directory + _T("DOEXT"), DoExt, RPL_P2, // Reserved or Unit (HP48 and later) + _T("DOTAG"), DoTag, RPL_P3, // Tagged + _T("DOGROB"), DoGrob, RPL_P3, // Graphic + _T("DOLIB"), DoLib, RPL_P3, // Library + _T("DOBAK"), DoBak, RPL_P3, // Backup + _T("DOEXT0"), DoExt0, RPL_P3, // Library Data + _T("DOEXT1"), DoExt1, RPL_P3, // Ext1 or ACcess PoinTeR + _T("DOACPTR"), DoExt1, RPL_P3, // Ext1 or ACcess PoinTeR + _T("DOEXT2"), DoExt2, RPL_P3, // Reserved 1, Font (HP49G) + _T("DOEXT3"), DoExt3, RPL_P3, // Reserved 2 + _T("DOEXT4"), DoExt4, RPL_P3, // Reserved 3 + _T("DOINT"), DoZint, RPL_P5, // Infinite Precision Integers + _T("DOLNGREAL"), DoLngReal, RPL_P5, // Precision Real + _T("DOLNGCMP"), DoLngCmp, RPL_P5, // Precision Complex + _T("DOFLASHP"), DoFlashPtr, RPL_P5, // Flash Pointer + _T("DOAPLET"), DoAplet, RPL_P5, // Aplet + _T("DOMINIFONT"), DoMinifont, RPL_P5, // Mini Font + _T("DOMATRIX"), DoMatrix, RPL_P5, // Symbolic matrix +}; + +static BOOL (*Getfp(LPCTSTR lpszObject))(DWORD *,String *,UINT *) +{ + UINT i; + + for (i = 0; i < ARRAYSIZEOF(ObjDecode); ++i) + { + if (lstrcmp(lpszObject,ObjDecode[i].lpszName) == 0) + { + // RPL platform type enabled + if ((ObjDecode[i].dwType & dwRplPlatform) == ObjDecode[i].dwType) + return ObjDecode[i].fp; // return object handler + } + } + return NULL; // not found +} + +static BOOL FetchObj(DWORD *pdwAddr,String *str,UINT *pnLevel) +{ + LPCTSTR lpszName; + DWORD dwObject; + BOOL bErr; + + bErr = FALSE; + + PutCondSpc(str); // write blank if necessary + + dwObject = Readx(pdwAddr,5); // fetch object + + lpszName = RplGetName(dwObject); // get name of object + if (lpszName != NULL) + { + // look for object type + BOOL (*fp)(DWORD *,String *,UINT *) = Getfp(lpszName); + + if (fp != NULL) // found an object handler + { + bErr = fp(pdwAddr,str,pnLevel); // call the handler + } + else + { + PutS(str,lpszName); // named entry + } + } + + if (lpszName == NULL || bErr) // no name or illegal object behind prolog + { + PutFS(str,_T("PTR %X"),dwObject); // unnamed entry + } + return bErr; +} + +BYTE (*RplReadNibble)(DWORD *p) = NULL; // get nibble function pointer + +DWORD RplSkipObject(DWORD dwAddr) +{ + UINT nLevel = 1; // nest DOCOL objects + + _ASSERT(RplReadNibble != NULL); // get nibble function defined + FetchObj(&dwAddr,NULL,&nLevel); // decode object without output + return dwAddr; +} + +LPTSTR RplDecodeObject(DWORD dwAddr, DWORD *pdwNxtAddr) +{ + String str = { 0, NULL, 0 }; + DWORD dwNxtAddr; + UINT nLevel = 0; // don't nest DOCOL objects + + dwNxtAddr = dwAddr; // init next address + + _ASSERT(RplReadNibble != NULL); // get nibble function defined + FetchObj(&dwNxtAddr,&str,&nLevel); // decode object + + PutC(&str,0); // set EOS + + // release unnecessary allocated buffer memory (shrinking) + VERIFY(str.szBuffer = (LPTSTR) realloc(str.szBuffer,str.dwPos * sizeof(str.szBuffer[0]))); + + // return address of next object + if (pdwNxtAddr != NULL) *pdwNxtAddr = dwNxtAddr; + return str.szBuffer; +} + + +//################ +//# +//# RPL Object Viewer +//# +//################ + +BOOL bRplViewName = TRUE; // show entry point name +BOOL bRplViewAddr = TRUE; // show address +BOOL bRplViewBin = TRUE; // show binary data +BOOL bRplViewAsm = TRUE; // show ASM code instead of hex data + +static VOID PrintHead(DWORD dwStartAddr, DWORD dwEndAddr, String *str) +{ + if (bRplViewAddr) // show address for object + { + PutFS(str,_T("%05X "),dwStartAddr); + } + + if (bRplViewBin) // show object binary data + { + DWORD dwIndex; + + for (dwIndex = 0; dwIndex < 5; ++dwIndex) + { + TCHAR c = _T(' '); + + if (dwStartAddr < dwEndAddr) // still show hex nibble + { + c = cHex[RplReadNibble(&dwStartAddr)]; + } + + PutC(str,c); // write data content + } + + PutS(str,_T(" ")); + } + else // no binary data + { + if (bRplViewAddr) // missing whitespace + { + PutC(str,_T(' ')); + } + } + return; +} + +static VOID PrintTail(DWORD dwStartAddr, DWORD dwEndAddr, String *str) +{ + if (bRplViewBin) // show binary data + { + DWORD dwActAddr,dwRemain; + + if (dwStartAddr < dwEndAddr) // remaining data to show + { + for (dwActAddr = dwStartAddr; dwActAddr < dwEndAddr;) + { + if (bRplViewAddr) // address is visible + { + // spaces instead of show address + PutS(str,_T(" ")); + + // address has 6 digit + if (dwActAddr >= 0x100000) + PutC(str,_T(' ')); + } + + dwRemain = dwEndAddr - dwActAddr; + if (dwRemain > 5) dwRemain = 5; + + for (; dwRemain > 0; --dwRemain) + { + // write data content + PutC(str,cHex[RplReadNibble(&dwActAddr)]); + } + + PutS(str,_T("\r\n")); + } + } + } + return; +} + +static VOID PrintBlank(String *str) +{ + if (bRplViewAddr) // address is visible + { + PutS(str,_T(" ")); // spaces instead of address + } + if (bRplViewBin) // show binary data + { + if (bRplViewAddr) // address is visible + { + PutC(str,_T(' ')); // need separator + } + + PutS(str,_T(" ")); // spaces instead of binary + } + if (bRplViewAddr || bRplViewBin) // any prefix + { + PutS(str,_T(" ")); // need separator + } + return; +} + +static VOID PrintLevel(DWORD dwLevel, String *str) +{ + for (; dwLevel > 0; --dwLevel) // level depending blanks + { + PutS(str,_T(" ")); + } + return; +} + +#if defined HARDWARE // compiled inside emulator sources +static DWORD AssemblyOutput(DWORD dwAddr, DWORD dwEndAddr, DWORD dwLevel, String *str) +{ + LPCTSTR lpszName; + TCHAR cBuffer[64]; + DWORD dwNxtAddr; + + PrintLevel(dwLevel,str); // level depending blanks + PutS(str,_T("CODE\r\n")); // code preamble + + PrintTail(dwAddr+5,dwAddr+10,str); // write code length information + + ++dwLevel; + + dwAddr += 10; // start of assembler code + + for (; dwAddr < dwEndAddr; dwAddr = dwNxtAddr) + { + // entry name enabled and known entry? + if (bRplViewName && (lpszName = RplGetName(dwAddr)) != NULL) + { + PrintHead(dwAddr,dwAddr,str); // write head for assembly label + PutFS(str,_T("=%s\r\n"),lpszName); + } + + // disassemble line + dwNxtAddr = disassemble(dwAddr,cBuffer); + + PrintHead(dwAddr,dwNxtAddr,str); // write head of assembly line + PrintLevel(dwLevel,str); // level depending blanks + PutS(str,cBuffer); // write disassembler text + PutS(str,_T("\r\n")); + + // write additional binary data of opcode + PrintTail(dwAddr+5,dwNxtAddr,str); + } + + --dwLevel; + + PrintBlank(str); // skip address and binary part + PrintLevel(dwLevel,str); // level depending blanks + PutS(str,_T("ENDCODE")); // code postamble + return dwAddr; +} +#endif + +LPTSTR RplCreateObjView(DWORD dwStartAddr, DWORD dwEndAddr, BOOL bSingleObj) +{ + String str = { 0, NULL, 0 }; + LPCTSTR lpszName; + LPTSTR lpszObject; + DWORD dwLevel,dwAddr,dwNxtAddr; + + _ASSERT(RplReadNibble != NULL); // get nibble function defined + + lpszObject = NULL; // no memory allocated + dwLevel = 0; // nesting level + + // decode object + for (dwAddr = dwStartAddr;dwAddr < dwEndAddr; dwAddr = dwNxtAddr) + { + lpszObject = RplDecodeObject(dwAddr,&dwNxtAddr); + if (lpszObject == NULL) // no memory + { + break; // break decoding + } + + if (dwLevel > 0 && lstrcmp(lpszObject,_T(";")) == 0) + --dwLevel; + + // entry name enabled and known entry? + if (bRplViewName && (lpszName = RplGetName(dwAddr)) != NULL) + { + if (bRplViewAddr) // show address for entry + { + PutFS(&str,_T("%05X "),dwAddr); + } + PutFS(&str,_T("=%s\r\n"),lpszName); + } + + PrintHead(dwAddr,dwAddr+5,&str); // write initial head + + do + { + // check for special RRP handling + if (_tcsncmp(lpszObject,_T("DIR\n"),4) == 0) + { + LPCTSTR lpszStart,lpszEnd; + + lpszStart = lpszEnd = lpszObject; + + // decode lines + while (*lpszEnd != 0) + { + // separate lines + if ((lpszEnd = _tcschr(lpszStart,_T('\n'))) == NULL) + { + VERIFY(lpszEnd = _tcschr(lpszStart,0)); + } + + if (dwLevel > 0 && _tcsncmp(lpszStart,_T("ENDDIR"),lpszEnd-lpszStart) == 0) + --dwLevel; + + // level depending blanks + PrintLevel(dwLevel,&str); + + // write line without LF + PutSn(&str,lpszStart,(DWORD) (lpszEnd-lpszStart)); + + if (_tcsncmp(lpszStart,_T("DIR"),lpszEnd-lpszStart) == 0) + ++dwLevel; + + if (*lpszEnd != 0) // more data? + { + PutS(&str,_T("\r\n")); // send CR LF + PrintBlank(&str); + lpszStart = lpszEnd + 1; // next part + } + } + break; + } + + #if defined HARDWARE // compiled inside emulator sources + // check for special CODE handling + if (bRplViewAsm && _tcsncmp(lpszObject,_T("CODE "),5) == 0) + { + // replace object by a disassembler output + dwAddr = AssemblyOutput(dwAddr,dwNxtAddr,dwLevel,&str); + break; + } + #endif + + // default, show the object + PrintLevel(dwLevel,&str); // level depending blanks + PutS(&str,lpszObject); // the object + } + while (FALSE); + PutS(&str,_T("\r\n")); + + PrintTail(dwAddr+5,dwNxtAddr,&str); // write additional binary data + + if (lstrcmp(lpszObject,_T("::")) == 0) + ++dwLevel; + + free(lpszObject); // free object string + lpszObject = NULL; + + if ( (bSingleObj && dwLevel == 0) // single object decoding? + || (dwNxtAddr < dwAddr)) // or address wrap around + break; // stop decoding + } + + _ASSERT(lpszObject == NULL); + + // remove CR LF at end + while ( str.dwPos > 0 + && ( str.szBuffer[str.dwPos-1] == _T('\r') + || str.szBuffer[str.dwPos-1] == _T('\n') + ) + ) + { + str.dwPos--; + } + + PutC(&str,0); // set EOS + + // release unnecessary allocated buffer memory (shrinking) + VERIFY(str.szBuffer = (LPTSTR) realloc(str.szBuffer,str.dwPos * sizeof(str.szBuffer[0]))); + return str.szBuffer; +} diff --git a/Sources/Emu48/disrpl.h b/Sources/Emu48/DISRPL.H similarity index 97% rename from Sources/Emu48/disrpl.h rename to Sources/Emu48/DISRPL.H index b18dab9..ba2f5cd 100644 --- a/Sources/Emu48/disrpl.h +++ b/Sources/Emu48/DISRPL.H @@ -1,25 +1,25 @@ -/* - * disrpl.h - * - * This file is part of Emu48 - * - * Copyright (C) 2008 Christoph Gießelink - * - */ - -// RPL platform type -#define RPL_P1 (1<<0) // Clamshell without RRP -#define RPL_P2 (RPL_P1 | (1<<1)) // Pioneer / Clamshell -#define RPL_P3 (RPL_P2 | (1<<2)) // Charlemagne -#define RPL_P4 (RPL_P3 | (1<<3)) // Alcuin -#define RPL_P5 (RPL_P4 | (1<<4)) // V'ger - -extern DWORD dwRplPlatform; // RPL platform -extern BOOL bRplViewName; // show entry point name -extern BOOL bRplViewAddr; // show adress -extern BOOL bRplViewBin; // show binary data -extern BOOL bRplViewAsm; // show ASM code instead of hex data -extern BYTE (*RplReadNibble)(DWORD *p); // read nibble function pointer -extern DWORD RplSkipObject(DWORD dwAddr); -extern LPTSTR RplDecodeObject(DWORD dwAddr, DWORD *pdwNxtAddr); -extern LPTSTR RplCreateObjView(DWORD dwStartAddr, DWORD dwEndAddr, BOOL bSingleObj); +/* + * disrpl.h + * + * This file is part of Emu48 + * + * Copyright (C) 2008 Christoph Gießelink + * + */ + +// RPL platform type +#define RPL_P1 (1<<0) // Clamshell without RRP +#define RPL_P2 (RPL_P1 | (1<<1)) // Pioneer / Clamshell +#define RPL_P3 (RPL_P2 | (1<<2)) // Charlemagne +#define RPL_P4 (RPL_P3 | (1<<3)) // Alcuin +#define RPL_P5 (RPL_P4 | (1<<4)) // V'ger + +extern DWORD dwRplPlatform; // RPL platform +extern BOOL bRplViewName; // show entry point name +extern BOOL bRplViewAddr; // show adress +extern BOOL bRplViewBin; // show binary data +extern BOOL bRplViewAsm; // show ASM code instead of hex data +extern BYTE (*RplReadNibble)(DWORD *p); // read nibble function pointer +extern DWORD RplSkipObject(DWORD dwAddr); +extern LPTSTR RplDecodeObject(DWORD dwAddr, DWORD *pdwNxtAddr); +extern LPTSTR RplCreateObjView(DWORD dwStartAddr, DWORD dwEndAddr, BOOL bSingleObj); diff --git a/Sources/Emu48/emu48.c b/Sources/Emu48/EMU48.C similarity index 96% rename from Sources/Emu48/emu48.c rename to Sources/Emu48/EMU48.C index e0602f4..5d11ddb 100644 --- a/Sources/Emu48/emu48.c +++ b/Sources/Emu48/EMU48.C @@ -1,2336 +1,2333 @@ -/* - * Emu48.c - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ -#include "pch.h" -#include "resource.h" -#include "emu48.h" -#include "io.h" -#include "kml.h" -#include "debugger.h" - -#define VERSION "1.66" - -#ifdef _DEBUG -LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug"); -#else -LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION); -#endif -LPTSTR szAppName = _T("Emu48"); // application name for DDE server -LPTSTR szTopic = _T("Stack"); // topic for DDE server -LPTSTR szTitle = NULL; - -static const LPCTSTR szLicence = - _T("This program is free software; you can redistribute it and/or modify\r\n") - _T("it under the terms of the GNU General Public License as published by\r\n") - _T("the Free Software Foundation; either version 2 of the License, or\r\n") - _T("(at your option) any later version.\r\n") - _T("\r\n") - _T("This program is distributed in the hope that it will be useful,\r\n") - _T("but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n") - _T("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\r\n") - _T("See the GNU General Public License for more details.\r\n") - _T("\r\n") - _T("You should have received a copy of the GNU General Public License along\r\n") - _T("with this program; if not, write to the Free Software Foundation, Inc.,\r\n") - _T("51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA."); - -static BOOL bOwnCursor = FALSE; -static BOOL bTitleBar = TRUE; -static BOOL bMouseButton = FALSE; - - -CRITICAL_SECTION csGDILock; // critical section for hWindowDC -CRITICAL_SECTION csLcdLock; // critical section for display update -CRITICAL_SECTION csKeyLock; // critical section for key scan -CRITICAL_SECTION csIOLock; // critical section for I/O access -CRITICAL_SECTION csT1Lock; // critical section for timer1 access -CRITICAL_SECTION csT2Lock; // critical section for timer2 access -CRITICAL_SECTION csTxdLock; // critical section for transmit byte -CRITICAL_SECTION csRecvLock; // critical section for receive byte -CRITICAL_SECTION csSlowLock; // critical section for speed slow down -CRITICAL_SECTION csDbgLock; // critical section for debugger purpose -INT nArgc; // no. of command line arguments -LPCTSTR *ppArgv; // command line arguments -LARGE_INTEGER lFreq; // high performance counter frequency -LARGE_INTEGER lAppStart; // high performance counter value at Appl. start -DWORD idDdeInst; // DDE server id -UINT uCF_HpObj; // DDE clipboard format -HANDLE hThread; -HANDLE hEventShutdn; // event handle to stop cpu thread - -HINSTANCE hApp = NULL; -HWND hWnd = NULL; -HWND hDlgDebug = NULL; // handle for debugger dialog -HWND hDlgFind = NULL; // handle for debugger find dialog -HWND hDlgProfile = NULL; // handle for debugger profile dialog -HWND hDlgRplObjView = NULL; // handle for debugger rpl object viewer -HDC hWindowDC = NULL; -HPALETTE hPalette = NULL; -HPALETTE hOldPalette = NULL; // old palette of hWindowDC -DWORD dwTColor = (DWORD) -1; // transparency color -DWORD dwTColorTol = 0; // transparency color tolerance -HRGN hRgn = NULL; -HCURSOR hCursorArrow = NULL; -HCURSOR hCursorHand = NULL; -UINT uWaveDevId = WAVE_MAPPER; // default audio device -DWORD dwWakeupDelay = 200; // ON key hold time to switch on calculator -BOOL bAutoSave = FALSE; -BOOL bAutoSaveOnExit = TRUE; -BOOL bSaveDefConfirm = TRUE; // yes -BOOL bStartupBackup = FALSE; -BOOL bAlwaysDisplayLog = TRUE; -BOOL bLoadObjectWarning = TRUE; -BOOL bShowTitle = TRUE; // show main window title bar -BOOL bShowMenu = TRUE; // show main window menu bar -BOOL bAlwaysOnTop = FALSE; // emulator window always on top -BOOL bActFollowsMouse = FALSE; // emulator window activation follows mouse -BOOL bClientWinMove = FALSE; // emulator window can be moved over client area -BOOL bSingleInstance = FALSE; // multiple emulator instances allowed - - -//################ -//# -//# Window Status -//# -//################ - -VOID SetWindowTitle(LPCTSTR szString) -{ - if (szTitle) free(szTitle); - - _ASSERT(hWnd != NULL); - if (szString) - { - szTitle = DuplicateString(szString); - SetWindowText(hWnd, szTitle); - } - else - { - szTitle = NULL; - SetWindowText(hWnd, szNoTitle); - } - return; -} - -VOID ForceForegroundWindow(HWND hWnd) -{ - // force window to foreground - DWORD dwEmuThreadID = GetCurrentThreadId(); - DWORD dwActThreadID = GetWindowThreadProcessId(GetForegroundWindow(),NULL); - - AttachThreadInput(dwEmuThreadID,dwActThreadID,TRUE); - SetForegroundWindow(hWnd); - AttachThreadInput(dwEmuThreadID,dwActThreadID,FALSE); - return; -} - -static __inline VOID UpdateWindowBars(VOID) -{ - DWORD dwStyle; - HMENU hMenu; - - BOOL bUpdate = FALSE; // no update - - // get current title bar style - dwStyle = (DWORD) GetWindowLongPtr(hWnd,GWL_STYLE); - if ((bTitleBar = (bShowTitle || bDocumentAvail == FALSE))) - { - // title bar off - if ((dwStyle & STYLE_TITLE) != STYLE_TITLE) - { - SetWindowLongPtr(hWnd,GWL_STYLE,(dwStyle & ~STYLE_NOTITLE) | STYLE_TITLE); - bUpdate = TRUE; - } - } - else - { - // title bar on - if ((dwStyle & STYLE_NOTITLE) != STYLE_NOTITLE) - { - SetWindowLongPtr(hWnd,GWL_STYLE,(dwStyle & ~STYLE_TITLE) | STYLE_NOTITLE); - bUpdate = TRUE; - } - } - - hMenu = GetMenu(hWnd); // get system menu - if (bShowMenu || bDocumentAvail == FALSE) - { - if (hMenu == NULL) // menu off - { - // restore menu bar - SetMenu(hWnd,LoadMenu(hApp,MAKEINTRESOURCE(IDR_MENU))); - bUpdate = TRUE; - } - } - else - { - if (hMenu != NULL) // menu on - { - // close menu bar - SetMenu(hWnd,NULL); - VERIFY(DestroyMenu(hMenu)); - bUpdate = TRUE; - } - } - - if (dwTColor != (DWORD) -1) // prepare background bitmap with transparency - { - if (!bTitleBar && GetMenu(hWnd) == NULL) - { - if (hRgn == NULL) - { - EnterCriticalSection(&csGDILock); // solving NT GDI problems - { - // enable background bitmap transparency - hRgn = CreateRgnFromBitmap((HBITMAP) GetCurrentObject(hMainDC,OBJ_BITMAP), - dwTColor, - dwTColorTol); - if (hRgn != NULL) // region definition successful - { - OffsetRgn(hRgn,-(INT) nBackgroundX,-(INT) nBackgroundY); - SetWindowRgn(hWnd,hRgn,TRUE); - } - else // region definition failed - { - // disable transparency - dwTColor = (DWORD) -1; - } - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - } - } - else - { - if (hRgn != NULL) // region active - { - EnterCriticalSection(&csGDILock); // solving NT GDI problems - { - // disable background bitmap transparency - SetWindowRgn(hWnd,NULL,TRUE); - hRgn = NULL; - - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - } - } - } - - if (bUpdate) // changed state of title or menu bar - { - ResizeWindow(); // resize & redraw window - } - return; -} - - - -//################ -//# -//# Clipboard Tool -//# -//################ - -VOID CopyItemsToClipboard(HWND hWnd) // save selected Listbox Items to Clipboard -{ - LONG i; - LPINT lpnCount; - - // get number of selections - if ((i = (LONG) SendMessage(hWnd,LB_GETSELCOUNT,0,0)) == 0) - return; // no items selected - - if ((lpnCount = (LPINT) malloc(i * sizeof(INT))) != NULL) - { - LPTSTR lpszData; - HANDLE hClipObj; - LONG j,lMem = 0; - - // get indexes of selected items - i = (LONG) SendMessage(hWnd,LB_GETSELITEMS,i,(LPARAM) lpnCount); - for (j = 0;j < i;++j) // scan all selected items - { - // calculate total amount of characters - lMem += (LONG) SendMessage(hWnd,LB_GETTEXTLEN,lpnCount[j],0) + 2; - } - // allocate clipboard data - if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,(lMem + 1) * sizeof(*lpszData))) != NULL) - { - if ((lpszData = (LPTSTR) GlobalLock(hClipObj))) - { - for (j = 0;j < i;++j) // scan all selected items - { - lpszData += SendMessage(hWnd,LB_GETTEXT,lpnCount[j],(LPARAM) lpszData); - *lpszData++ = _T('\r'); - *lpszData++ = _T('\n'); - } - *lpszData = 0; // set EOS - GlobalUnlock(hClipObj); // unlock memory - } - - if (OpenClipboard(hWnd)) - { - if (EmptyClipboard()) - #if defined _UNICODE - SetClipboardData(CF_UNICODETEXT,hClipObj); - #else - SetClipboardData(CF_TEXT,hClipObj); - #endif - else - GlobalFree(hClipObj); - CloseClipboard(); - } - else // clipboard open failed - { - GlobalFree(hClipObj); - } - } - free(lpnCount); // free item table - } - return; -} - - - -//################ -//# -//# Settings -//# -//################ - -// get R/W state of file -static BOOL IsFileWriteable(LPCTSTR szFilename) -{ - DWORD dwFileAtt; - - BOOL bWriteable = FALSE; - - SetCurrentDirectory(szEmuDirectory); - dwFileAtt = GetFileAttributes(szFilename); - if (dwFileAtt != 0xFFFFFFFF) - bWriteable = ((dwFileAtt & FILE_ATTRIBUTE_READONLY) == 0); - SetCurrentDirectory(szCurrentDirectory); - return bWriteable; -} - -// set listfield for serial combo boxes -static VOID SetCommList(HWND hDlg,LPCTSTR szWireSetting,LPCTSTR szIrSetting) -{ - WPARAM wSelectWire,wSelectIr; - HKEY hKey; - - wSelectWire = wSelectIr = 0; // set selections to disabled - SendDlgItemMessage(hDlg,IDC_WIRE,CB_ADDSTRING,0,(LPARAM) _T(NO_SERIAL)); - SendDlgItemMessage(hDlg,IDC_IR ,CB_ADDSTRING,0,(LPARAM) _T(NO_SERIAL)); - - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, - _T("Hardware\\DeviceMap\\SerialComm"), - 0, - KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, - &hKey) == ERROR_SUCCESS) - { - HANDLE hComm; - TCHAR szBuffer[256],cKey[256],cData[256]; - DWORD dwKeySize,dwDataSize; - WPARAM wSelIndexWire,wSelIndexIr; - BOOL bAddWire,bAddIr; - DWORD dwType,dwEnumVal; - LONG lRet; - - wSelIndexWire = wSelIndexIr = 1; // preset selector - - dwEnumVal = 0; - do - { - dwKeySize = ARRAYSIZEOF(cKey); // init return buffer sizes - dwDataSize = sizeof(cData); - - lRet = RegEnumValue(hKey,dwEnumVal++, - cKey,&dwKeySize, - NULL,&dwType, - (LPBYTE) cData,&dwDataSize); - - if (lRet == ERROR_SUCCESS && dwType == REG_SZ) - { - wsprintf(szBuffer,_T("\\\\.\\%s"),cData); - if ((bAddWire = (lstrcmp(&szBuffer[4],szWireSetting) == 0))) - wSelectWire = wSelIndexWire; - if ((bAddIr = (lstrcmp(&szBuffer[4],szIrSetting) == 0))) - wSelectIr = wSelIndexIr; - - // test if COM port is valid - hComm = CreateFile(szBuffer,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); - if (hComm != INVALID_HANDLE_VALUE) - { - VERIFY(CloseHandle(hComm)); - bAddWire = bAddIr = TRUE; - } - - if (bAddWire) // add item to wire combobox - { - SendDlgItemMessage(hDlg,IDC_WIRE,CB_ADDSTRING,0,(LPARAM) &szBuffer[4]); - ++wSelIndexWire; - } - if (bAddIr) // add item to ir combobox - { - SendDlgItemMessage(hDlg,IDC_IR,CB_ADDSTRING,0,(LPARAM) &szBuffer[4]); - ++wSelIndexIr; - } - } - } - while (lRet == ERROR_SUCCESS); - _ASSERT(lRet == ERROR_NO_MORE_ITEMS); - RegCloseKey(hKey); - } - - // set cursors - SendDlgItemMessage(hDlg,IDC_WIRE,CB_SETCURSEL,wSelectWire,0L); - SendDlgItemMessage(hDlg,IDC_IR ,CB_SETCURSEL,wSelectIr ,0L); - return; -} - -static INT_PTR CALLBACK SettingsGeneralProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - HWND hWndInsertAfter; - - switch (uMsg) - { - case WM_INITDIALOG: - // init speed checkbox - CheckDlgButton(hDlg,IDC_REALSPEED,bRealSpeed); - CheckDlgButton(hDlg,IDC_GRAYSCALE,bGrayscale); - CheckDlgButton(hDlg,IDC_SHOWTITLE,bShowTitle); - CheckDlgButton(hDlg,IDC_SHOWMENU,bShowMenu); - CheckDlgButton(hDlg,IDC_ALWAYSONTOP,bAlwaysOnTop); - CheckDlgButton(hDlg,IDC_ACTFOLLOWSMOUSE,bActFollowsMouse); - #if defined _USRDLL // DLL version - CheckDlgButton(hDlg,IDC_SINGLEINSTANCE,FALSE); - EnableWindow(GetDlgItem(hDlg,IDC_SINGLEINSTANCE),FALSE); - #else - CheckDlgButton(hDlg,IDC_SINGLEINSTANCE,bSingleInstance); - #endif - CheckDlgButton(hDlg,IDC_AUTOSAVE,bAutoSave); - CheckDlgButton(hDlg,IDC_AUTOSAVEONEXIT,bAutoSaveOnExit); - CheckDlgButton(hDlg,IDC_OBJECTLOADWARNING,bLoadObjectWarning); - CheckDlgButton(hDlg,IDC_ALWAYSDISPLOG,bAlwaysDisplayLog); - - // set disassembler mode - CheckDlgButton(hDlg,(disassembler_mode == HP_MNEMONICS) ? IDC_DISASM_HP : IDC_DISASM_CLASS,BST_CHECKED); - return TRUE; - case WM_NOTIFY: - switch (((LPNMHDR) lParam)->code) - { - case PSN_KILLACTIVE: - // get speed checkbox value - bRealSpeed = IsDlgButtonChecked(hDlg,IDC_REALSPEED); - bShowTitle = IsDlgButtonChecked(hDlg,IDC_SHOWTITLE); - bShowMenu = IsDlgButtonChecked(hDlg,IDC_SHOWMENU); - bAlwaysOnTop = IsDlgButtonChecked(hDlg,IDC_ALWAYSONTOP); - bActFollowsMouse = IsDlgButtonChecked(hDlg,IDC_ACTFOLLOWSMOUSE); - bSingleInstance = IsDlgButtonChecked(hDlg,IDC_SINGLEINSTANCE); - bAutoSave = IsDlgButtonChecked(hDlg,IDC_AUTOSAVE); - bAutoSaveOnExit = IsDlgButtonChecked(hDlg,IDC_AUTOSAVEONEXIT); - bLoadObjectWarning = IsDlgButtonChecked(hDlg,IDC_OBJECTLOADWARNING); - bAlwaysDisplayLog = IsDlgButtonChecked(hDlg,IDC_ALWAYSDISPLOG); - SetSpeed(bRealSpeed); // set speed - - // LCD grayscale checkbox has been changed - if (bGrayscale != (BOOL) IsDlgButtonChecked(hDlg,IDC_GRAYSCALE)) - { - UINT nOldState = SwitchToState(SM_INVALID); - SetLcdMode(!bGrayscale); // set new display mode - SwitchToState(nOldState); - } - - // set disassembler mode - disassembler_mode = IsDlgButtonChecked(hDlg,IDC_DISASM_HP) ? HP_MNEMONICS : CLASS_MNEMONICS; - - // bAlwaysOnTop maybe changed, so set new window Z order - hWndInsertAfter = bAlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST; - SetWindowPos(hWnd,hWndInsertAfter,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); - if (hDlgDebug != NULL) - { - SetWindowPos(GetLastActivePopup(hDlgDebug),hWndInsertAfter,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); - } - InvalidateRect(hWnd,NULL,TRUE); - return TRUE; - } - break; - } - return FALSE; - UNREFERENCED_PARAMETER(wParam); -} - -static INT_PTR CALLBACK SettingsMemoryProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - LPCTSTR szActPort2Filename = _T(""); - - BOOL bPort2CfgChange = FALSE; - BOOL bPort2AttChange = FALSE; - - switch (uMsg) - { - case WM_INITDIALOG: - // HP48SX/GX - if (cCurrentRomType=='S' || cCurrentRomType=='G' || cCurrentRomType==0) - { - // init port1 enable checkbox - CheckDlgButton(hDlg,IDC_PORT1EN,(Chipset.cards_status & PORT1_PRESENT) != 0); - CheckDlgButton(hDlg,IDC_PORT1WR,(Chipset.cards_status & PORT1_WRITE) != 0); - - if (nArgc < 3) // port2 filename from Emu48.ini file - { - szActPort2Filename = szPort2Filename; - } - else // port2 filename given from command line - { - szActPort2Filename = ppArgv[2]; - EnableWindow(GetDlgItem(hDlg,IDC_PORT2),FALSE); - EnableWindow(GetDlgItem(hDlg,IDC_PORT2LOAD),FALSE); - } - - // init port2 shared and writeable checkbox and set port2 filename - CheckDlgButton(hDlg,IDC_PORT2ISSHARED,bPort2IsShared); - CheckDlgButton(hDlg,IDC_PORT2WR,IsFileWriteable(szActPort2Filename)); - SetDlgItemText(hDlg,IDC_PORT2,szActPort2Filename); - if (nState == SM_INVALID) // Invalid State - { - EnableWindow(GetDlgItem(hDlg,IDC_PORT1EN),FALSE); - EnableWindow(GetDlgItem(hDlg,IDC_PORT1WR),FALSE); - } - } - else // HP38G/HP39G/HP40G/HP49G - { - EnableWindow(GetDlgItem(hDlg,IDC_PORT1EN),FALSE); - EnableWindow(GetDlgItem(hDlg,IDC_PORT1WR),FALSE); - EnableWindow(GetDlgItem(hDlg,IDC_PORT2ISSHARED),FALSE); - EnableWindow(GetDlgItem(hDlg,IDC_PORT2WR),FALSE); - EnableWindow(GetDlgItem(hDlg,IDC_PORT2),FALSE); - EnableWindow(GetDlgItem(hDlg,IDC_PORT2LOAD),FALSE); - } - return TRUE; - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDC_PORT2LOAD: - if (GetLoadObjectFilename(_T(BIN_FILTER),_T("BIN"))) - { - TCHAR szFilename[MAX_PATH]; - LPTSTR lpFilePart; - - // check if file path and Emu48 directory path is identical - if (GetFullPathName(szBufferFilename,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart)) - { - *(lpFilePart-1) = 0; // devide path and name - - // name is in the Emu48 directory -> use only name - if (lstrcmpi(szEmuDirectory,szFilename) == 0) - lstrcpy(szBufferFilename,lpFilePart); - } - SetDlgItemText(hDlg,IDC_PORT2,szBufferFilename); - - // adjust R/W checkbox - CheckDlgButton(hDlg,IDC_PORT2WR,IsFileWriteable(szBufferFilename)); - } - return TRUE; - } - break; - case WM_NOTIFY: - switch (((LPNMHDR) lParam)->code) - { - case PSN_KILLACTIVE: - if (Chipset.Port1Size && cCurrentRomType!='X') - { - UINT nOldState = SwitchToState(SM_SLEEP); - // save old card status - BYTE byCardsStatus = Chipset.cards_status; - - // port1 disabled? - Chipset.cards_status &= ~(PORT1_PRESENT | PORT1_WRITE); - if (IsDlgButtonChecked(hDlg, IDC_PORT1EN)) - { - Chipset.cards_status |= PORT1_PRESENT; - if (IsDlgButtonChecked(hDlg, IDC_PORT1WR)) - Chipset.cards_status |= PORT1_WRITE; - } - - // changed card status in slot1? - if ( ((byCardsStatus ^ Chipset.cards_status) & (PORT1_PRESENT | PORT1_WRITE)) != 0 - && (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0 - ) - { - Chipset.HST |= MP; // set Module Pulled - IOBit(SRQ2,NINT,FALSE); // set NINT to low - Chipset.SoftInt = TRUE; // set interrupt - bInterrupt = TRUE; - } - SwitchToState(nOldState); - } - // HP48SX/GX port2 change settings detection - if (cCurrentRomType=='S' || cCurrentRomType=='G' || cCurrentRomType==0) - { - TCHAR szFilename[MAX_PATH]; - BOOL bOldPort2IsShared = bPort2IsShared; - - szActPort2Filename = (nArgc < 3) ? szPort2Filename : ppArgv[2]; - - // shared port - bPort2IsShared = IsDlgButtonChecked(hDlg,IDC_PORT2ISSHARED); - if (bPort2IsShared != bOldPort2IsShared) - { - bPort2CfgChange = TRUE; // slot2 configuration changed - } - - if (nArgc < 3) // port2 filename from Emu48.ini file - { - // get current filename and notify difference - GetDlgItemText(hDlg,IDC_PORT2,szFilename,ARRAYSIZEOF(szFilename)); - if (lstrcmp(szPort2Filename,szFilename) != 0) - { - lstrcpyn(szPort2Filename,szFilename,ARRAYSIZEOF(szPort2Filename)); - bPort2CfgChange = TRUE; // slot2 configuration changed - } - } - - // R/W port - if ( *szActPort2Filename != 0 - && (BOOL) IsDlgButtonChecked(hDlg,IDC_PORT2WR) != IsFileWriteable(szActPort2Filename)) - { - bPort2AttChange = TRUE; // slot2 file R/W attribute changed - bPort2CfgChange = TRUE; // slot2 configuration changed - } - } - - if (bPort2CfgChange) // slot2 configuration changed - { - UINT nOldState = SwitchToState(SM_INVALID); - - UnmapPort2(); // unmap port2 - - if (bPort2AttChange) // slot2 R/W mode changed - { - DWORD dwFileAtt; - - SetCurrentDirectory(szEmuDirectory); - dwFileAtt = GetFileAttributes(szActPort2Filename); - if (dwFileAtt != 0xFFFFFFFF) - { - if (IsDlgButtonChecked(hDlg,IDC_PORT2WR)) - dwFileAtt &= ~FILE_ATTRIBUTE_READONLY; - else - dwFileAtt |= FILE_ATTRIBUTE_READONLY; - - SetFileAttributes(szActPort2Filename,dwFileAtt); - } - SetCurrentDirectory(szCurrentDirectory); - } - - if (cCurrentRomType) // ROM defined - { - MapPort2(szActPort2Filename); - - // port2 changed and card detection enabled - if ( (bPort2AttChange || Chipset.wPort2Crc != wPort2Crc) - && (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0 - ) - { - Chipset.HST |= MP; // set Module Pulled - IOBit(SRQ2,NINT,FALSE); // set NINT to low - Chipset.SoftInt = TRUE; // set interrupt - bInterrupt = TRUE; - } - // save fingerprint of port2 - Chipset.wPort2Crc = wPort2Crc; - } - SwitchToState(nOldState); - } - return TRUE; - } - break; - } - return FALSE; -} - -static INT_PTR CALLBACK SettingsPeripheralProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - TCHAR cPort[8]; - LONG i; - UINT uDevId; - - switch (uMsg) - { - case WM_INITDIALOG: - // set sound slider - SendDlgItemMessage(hDlg,IDC_SOUND_SLIDER,TBM_SETRANGE,FALSE,MAKELONG(0,255)); - SendDlgItemMessage(hDlg,IDC_SOUND_SLIDER,TBM_SETTICFREQ,256/8,0); - SendDlgItemMessage(hDlg,IDC_SOUND_SLIDER,TBM_SETPOS,TRUE,dwWaveVol); - - // set sound device - SetSoundDeviceList(GetDlgItem(hDlg,IDC_SOUND_DEVICE),uWaveDevId); - - // UDP infrared printer settings - SetDlgItemText(hDlg,IDC_IR_ADDR,szUdpServer); - wsprintf(cPort,_T("%u"),wUdpPort); - SetDlgItemText(hDlg,IDC_IR_PORT,cPort); - - // set combobox parameter - SetCommList(hDlg,szSerialWire,szSerialIr); - if (CommIsOpen()) // disable when port open - { - EnableWindow(GetDlgItem(hDlg,IDC_WIRE),FALSE); - EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE); - } - - if (cCurrentRomType=='X') // HP49G - { - SendDlgItemMessage(hDlg,IDC_IR,CB_RESETCONTENT,0,0); - EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE); - } - return TRUE; - case WM_NOTIFY: - switch (((LPNMHDR) lParam)->code) - { - case PSN_KILLACTIVE: - // set sound data - dwWaveVol = (DWORD) SendDlgItemMessage(hDlg,IDC_SOUND_SLIDER,TBM_GETPOS,0,0); - i = (LONG) SendDlgItemMessage(hDlg,IDC_SOUND_DEVICE,CB_GETCURSEL,0,0); - uDevId = (UINT) SendDlgItemMessage(hDlg,IDC_SOUND_DEVICE,CB_GETITEMDATA,i,0); - if (uWaveDevId != uDevId) // sound device id changed - { - UINT nActState; - - uWaveDevId = uDevId; // set new sound device id - - nActState = SwitchToState(SM_SLEEP); - - // restart sound engine with new device id - SoundClose(); // close waveform-audio output device - SoundOpen(uWaveDevId); // open waveform-audio output device - - SwitchToState(nActState); - } - // UDP infrared printer settings - GetDlgItemText(hDlg,IDC_IR_ADDR,szUdpServer,ARRAYSIZEOF(szUdpServer)); - GetDlgItemText(hDlg,IDC_IR_PORT,cPort,ARRAYSIZEOF(cPort)); - wUdpPort = (WORD) _ttoi(cPort); - ResetUdp(); // invalidate saved UDP address - // set combobox parameter - GetDlgItemText(hDlg,IDC_WIRE,szSerialWire,ARRAYSIZEOF(szSerialWire)); - if (cCurrentRomType!='X') // HP49G Ir port is not connected - GetDlgItemText(hDlg,IDC_IR,szSerialIr,ARRAYSIZEOF(szSerialIr)); - return TRUE; - } - break; - } - return FALSE; - UNREFERENCED_PARAMETER(wParam); -} - - - -//################ -//# -//# Save Helper -//# -//################ - -// -// UINT SaveChanges(BOOL bAuto); -// Return code : -// IDYES File successfuly saved -// IDNO File not saved -// IDCANCEL Cancel command -// -static UINT SaveChanges(BOOL bAuto) -{ - UINT uReply; - - if (bDocumentAvail == FALSE) return IDNO; - - if (bAuto) - uReply = IDYES; - else - { - UINT uStyle = bSaveDefConfirm ? 0 : MB_DEFBUTTON2; - uReply = YesNoCancelMessage(_T("Do you want to save changes?"),uStyle); - } - - if (uReply != IDYES) return uReply; - - if (szCurrentFilename[0] == 0) - { // Save As... - if (GetSaveAsFilename()) - { - if (SaveDocumentAs(szBufferFilename)) - { - MruAdd(szBufferFilename); - return IDYES; - } - else - return IDCANCEL; - } - return IDNO; - } - - SaveDocument(); - MruAdd(szCurrentFilename); - return IDYES; -} - - - -//################ -//# -//# Message Handlers -//# -//################ - -// -// WM_CREATE -// -static LRESULT OnCreate(HWND hWindow) -{ - InitializeCriticalSection(&csGDILock); - InitializeCriticalSection(&csLcdLock); - InitializeCriticalSection(&csKeyLock); - InitializeCriticalSection(&csIOLock); - InitializeCriticalSection(&csT1Lock); - InitializeCriticalSection(&csT2Lock); - InitializeCriticalSection(&csTxdLock); - InitializeCriticalSection(&csRecvLock); - InitializeCriticalSection(&csSlowLock); - InitializeCriticalSection(&csDbgLock); - - // load cursors - hCursorArrow = LoadCursor(NULL,IDC_ARROW); - hCursorHand = LoadCursor(NULL,IDC_HAND); - if (hCursorHand == NULL) - { - // for Win95, NT4.0 - bOwnCursor = ((hCursorHand = CreateHandCursor()) != NULL); - } - - hWnd = hWindow; - hWindowDC = GetDC(hWnd); - return 0; -} - -// -// WM_DESTROY -// -static LRESULT OnDestroy(HWND hWindow) -{ - DragAcceptFiles(hWnd,FALSE); // no WM_DROPFILES message any more - if (hThread) SwitchToState(SM_RETURN); // exit emulation thread - SetWindowTitle(NULL); // free memory of title - ReleaseDC(hWnd, hWindowDC); - hWindowDC = NULL; // hWindowDC isn't valid any more - hWnd = NULL; - - if (bOwnCursor) // destroy hand cursor - { - DestroyCursor(hCursorHand); - bOwnCursor = FALSE; - } - - DeleteCriticalSection(&csGDILock); - DeleteCriticalSection(&csLcdLock); - DeleteCriticalSection(&csKeyLock); - DeleteCriticalSection(&csIOLock); - DeleteCriticalSection(&csT1Lock); - DeleteCriticalSection(&csT2Lock); - DeleteCriticalSection(&csTxdLock); - DeleteCriticalSection(&csRecvLock); - DeleteCriticalSection(&csSlowLock); - DeleteCriticalSection(&csDbgLock); - - #if defined _USRDLL // DLL version - DLLDestroyWnd(); // cleanup system - #else // EXE version - PostQuitMessage(0); // exit message loop - #endif - return 0; - UNREFERENCED_PARAMETER(hWindow); -} - -// -// WM_PAINT -// -static LRESULT OnPaint(HWND hWindow) -{ - PAINTSTRUCT Paint; - HDC hPaintDC; - - UpdateWindowBars(); // update visibility of title and menu bar - - hPaintDC = BeginPaint(hWindow, &Paint); - if (hMainDC != NULL) - { - RECT rcMainPaint = Paint.rcPaint; - rcMainPaint.left += nBackgroundX; // coordinates in source bitmap - rcMainPaint.top += nBackgroundY; - rcMainPaint.right += nBackgroundX; - rcMainPaint.bottom += nBackgroundY; - - EnterCriticalSection(&csGDILock); // solving NT GDI problems - { - UINT nLines = (Chipset.lcounter == 0) ? 64 : (Chipset.lcounter + 1); - - // redraw background bitmap - BitBlt(hPaintDC, Paint.rcPaint.left, Paint.rcPaint.top, - Paint.rcPaint.right-Paint.rcPaint.left, Paint.rcPaint.bottom-Paint.rcPaint.top, - hMainDC, rcMainPaint.left, rcMainPaint.top, SRCCOPY); - - SetWindowOrgEx(hPaintDC, nBackgroundX, nBackgroundY, NULL); - - // redraw main display area - StretchBlt(hPaintDC, nLcdX, nLcdY, - 131*nLcdZoom*nGdiXZoom, nLines*nLcdZoom*nGdiYZoom, - hLcdDC, Chipset.boffset*nLcdZoom, 0, - 131*nLcdZoom, nLines*nLcdZoom, SRCCOPY); - // redraw menu display area - StretchBlt(hPaintDC, nLcdX, nLcdY+nLines*nLcdZoom*nGdiYZoom, - 131*nLcdZoom*nGdiXZoom, (64-nLines)*nLcdZoom*nGdiYZoom, - hLcdDC, 0, nLines*nLcdZoom, - 131*nLcdZoom, (64-nLines)*nLcdZoom, SRCCOPY); - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - UpdateAnnunciators(0x3F); - RefreshButtons(&rcMainPaint); - } - EndPaint(hWindow, &Paint); - return 0; -} - -// -// WM_INITMENU -// -static LRESULT OnInitMenu(HMENU hMenu) -{ - // disable stack loading items on HP38G, HP39/40G - BOOL bStackEnable = cCurrentRomType!='6' && cCurrentRomType!='A' && cCurrentRomType!='E'; - BOOL bRun = nState == SM_RUN || nState == SM_SLEEP; - - UINT uStackEnable = (bRun && bStackEnable) ? MF_ENABLED : MF_GRAYED; - UINT uRun = bRun ? MF_ENABLED : MF_GRAYED; - UINT uBackup = bBackup ? MF_ENABLED : MF_GRAYED; - - EnableMenuItem(hMenu,ID_FILE_NEW,MF_ENABLED); - EnableMenuItem(hMenu,ID_FILE_OPEN,MF_ENABLED); - EnableMenuItem(hMenu,ID_FILE_SAVE,(bRun && szCurrentFilename[0]) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenu,ID_FILE_SAVEAS,uRun); - EnableMenuItem(hMenu,ID_FILE_CLOSE,uRun); - EnableMenuItem(hMenu,ID_OBJECT_LOAD,uStackEnable); - EnableMenuItem(hMenu,ID_OBJECT_SAVE,uStackEnable); - EnableMenuItem(hMenu,ID_VIEW_COPY,uRun); - EnableMenuItem(hMenu,ID_STACK_COPY,uStackEnable); - EnableMenuItem(hMenu,ID_STACK_PASTE,uStackEnable); - EnableMenuItem(hMenu,ID_VIEW_RESET,uRun); - EnableMenuItem(hMenu,ID_BACKUP_SAVE,uRun); - EnableMenuItem(hMenu,ID_BACKUP_RESTORE,uBackup); - EnableMenuItem(hMenu,ID_BACKUP_DELETE,uBackup); - EnableMenuItem(hMenu,ID_VIEW_SCRIPT,uRun); - EnableMenuItem(hMenu,ID_TOOL_DISASM,uRun); - EnableMenuItem(hMenu,ID_TOOL_DEBUG,(bRun && nDbgState == DBG_OFF) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenu,ID_TOOL_MACRO_RECORD,(bRun && nMacroState == MACRO_OFF) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenu,ID_TOOL_MACRO_PLAY,(bRun && nMacroState == MACRO_OFF) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenu,ID_TOOL_MACRO_STOP,(bRun && nMacroState != MACRO_OFF) ? MF_ENABLED : MF_GRAYED); - - MruUpdateMenu(hMenu); // update MRU list - return 0; -} - -// -// WM_DROPFILES -// -static LRESULT OnDropFiles(HDROP hFilesInfo) -{ - TCHAR szFileName[MAX_PATH]; - WORD wNumFiles,wIndex; - BOOL bSuccess = FALSE; - - // get number of files dropped - wNumFiles = DragQueryFile (hFilesInfo,(UINT)-1,NULL,0); - - SuspendDebugger(); // suspend debugger - bDbgAutoStateCtrl = FALSE; // disable automatic debugger state control - - // calculator off, turn on - if (!(Chipset.IORam[BITOFFSET]&DON)) - { - // turn on HP - KeyboardEvent(TRUE,0,0x8000); - Sleep(dwWakeupDelay); - KeyboardEvent(FALSE,0,0x8000); - } - - _ASSERT(nState == SM_RUN); // emulator must be in RUN state - if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state - { - DragFinish (hFilesInfo); - InfoMessage(_T("The emulator is busy.")); - goto cancel; - } - - _ASSERT(nState == SM_SLEEP); - - // get each name and load it into the emulator - for (wIndex = 0;wIndex < wNumFiles;++wIndex) - { - DragQueryFile (hFilesInfo,wIndex,szFileName,ARRAYSIZEOF(szFileName)); - - // szFileName has file name, now try loading it - if ((bSuccess = LoadObject(szFileName)) == FALSE) - break; - } - - DragFinish (hFilesInfo); - SwitchToState(SM_RUN); // run state - while (nState!=nNextState) Sleep(0); - _ASSERT(nState == SM_RUN); - - if (bSuccess == FALSE) // data not copied - goto cancel; - - KeyboardEvent(TRUE,0,0x8000); - Sleep(dwWakeupDelay); - KeyboardEvent(FALSE,0,0x8000); - // wait for sleep mode - while (Chipset.Shutdn == FALSE) Sleep(0); - -cancel: - bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control - ResumeDebugger(); - return 0; -} - -// -// ID_FILE_NEW -// -static LRESULT OnFileNew(VOID) -{ - if (bDocumentAvail) - { - SwitchToState(SM_INVALID); - if (IDCANCEL == SaveChanges(bAutoSave)) - goto cancel; - } - if (NewDocument()) SetWindowTitle(_T("Untitled")); -cancel: - if (pbyRom) SwitchToState(SM_RUN); - return 0; -} - -// -// ID_FILE_OPEN -// -static LRESULT OnFileOpen(VOID) -{ - if (bDocumentAvail) - { - SwitchToState(SM_INVALID); - if (IDCANCEL == SaveChanges(bAutoSave)) - goto cancel; - } - if (GetOpenFilename()) - { - if (OpenDocument(szBufferFilename)) - MruAdd(szBufferFilename); - } -cancel: - if (pbyRom) SwitchToState(SM_RUN); - return 0; -} - -// -// ID_FILE_MRU_FILE1 -// -static LRESULT OnFileMruOpen(UINT wID) -{ - TCHAR szFilename[MAX_PATH]; - - wID -= ID_FILE_MRU_FILE1; // zero based MRU index - - // full filename from MRU list - MruFilename(wID,szFilename,ARRAYSIZEOF(szFilename)); - if (*szFilename == 0) return 0; // MRU slot not filled - - if (bDocumentAvail) - { - SwitchToState(SM_INVALID); - // saving may change MRU index and destroy lpszFilename pointer content - if (IDCANCEL == SaveChanges(bAutoSave)) - goto cancel; - } - if (!OpenDocument(szFilename)) // document loading failed - { - wID = MruID(szFilename); // get actual MRU ID after saving - if (wID != (UINT) -1) // entry still in MRU list - { - MruRemove(wID); // entry not valid any more - } - } - else - { - MruAdd(szFilename); // add entry to top of MRU list - } -cancel: - if (pbyRom) SwitchToState(SM_RUN); - return 0; -} - -// -// ID_FILE_SAVE -// -static LRESULT OnFileSave(VOID) -{ - if (bDocumentAvail) - { - SwitchToState(SM_INVALID); - SaveChanges(TRUE); - SwitchToState(SM_RUN); - } - return 0; -} - -// -// ID_FILE_SAVEAS -// -static LRESULT OnFileSaveAs(VOID) -{ - if (bDocumentAvail) - { - SwitchToState(SM_INVALID); - if (GetSaveAsFilename()) - { - if (SaveDocumentAs(szBufferFilename)) - MruAdd(szCurrentFilename); - } - SwitchToState(SM_RUN); - } - return 0; -} - -// -// ID_FILE_CLOSE -// -static LRESULT OnFileClose(VOID) -{ - if (bDocumentAvail) - { - SwitchToState(SM_INVALID); - if (SaveChanges(bAutoSave) != IDCANCEL) - { - ResetDocument(); - SetWindowTitle(NULL); - } - else - { - SwitchToState(SM_RUN); - } - } - return 0; -} - -// -// ID_FILE_EXIT -// -// WM_SYS_CLOSE -// -static LRESULT OnFileExit(VOID) -{ - SwitchToState(SM_INVALID); // hold emulation thread - if (SaveChanges(bAutoSaveOnExit) == IDCANCEL) - { - SwitchToState(SM_RUN); // on cancel restart emulation thread - return 0; - } - DestroyWindow(hWnd); - return 0; -} - -// -// ID_VIEW_COPY -// -static LRESULT OnViewCopy(VOID) -{ - if (OpenClipboard(hWnd)) - { - if (EmptyClipboard()) - { - // DIB bitmap - #define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4) - #define PALVERSION 0x300 - - BITMAP bm; - LPBITMAPINFOHEADER lpbi; - PLOGPALETTE ppal; - HBITMAP hBmp; - HDC hBmpDC; - HANDLE hClipObj; - WORD wBits; - DWORD dwLen, dwSizeImage; - - _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); - hBmp = CreateCompatibleBitmap(hLcdDC,131*nLcdZoom*nGdiXZoom,64*nLcdZoom*nGdiYZoom); - hBmpDC = CreateCompatibleDC(hLcdDC); - hBmp = (HBITMAP) SelectObject(hBmpDC,hBmp); - EnterCriticalSection(&csGDILock); // solving NT GDI problems - { - UINT nLines = (Chipset.lcounter == 0) ? 64 : (Chipset.lcounter + 1); - - // copy main display area - StretchBlt(hBmpDC, 0, 0, - 131*nLcdZoom*nGdiXZoom, nLines*nLcdZoom*nGdiYZoom, - hLcdDC, Chipset.boffset*nLcdZoom, 0, - 131*nLcdZoom, nLines*nLcdZoom, SRCCOPY); - // copy menu display area - StretchBlt(hBmpDC, 0, nLines*nLcdZoom*nGdiYZoom, - 131*nLcdZoom*nGdiXZoom, (64-nLines)*nLcdZoom*nGdiYZoom, - hLcdDC, 0, nLines*nLcdZoom, - 131*nLcdZoom, (64-nLines)*nLcdZoom, SRCCOPY); - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - hBmp = (HBITMAP) SelectObject(hBmpDC,hBmp); - - // fill BITMAP structure for size information - GetObject(hBmp, sizeof(bm), &bm); - - wBits = bm.bmPlanes * bm.bmBitsPixel; - // make sure bits per pixel is valid - if (wBits <= 1) - wBits = 1; - else if (wBits <= 4) - wBits = 4; - else if (wBits <= 8) - wBits = 8; - else // if greater than 8-bit, force to 24-bit - wBits = 24; - - dwSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * wBits) * bm.bmHeight; - - // calculate memory size to store CF_DIB data - dwLen = sizeof(BITMAPINFOHEADER) + dwSizeImage; - if (wBits != 24) // a 24 bitcount DIB has no color table - { - // add size for color table - dwLen += (DWORD) (1 << wBits) * sizeof(RGBQUAD); - } - - // memory allocation for clipboard data - if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE, dwLen)) != NULL) - { - lpbi = (LPBITMAPINFOHEADER ) GlobalLock(hClipObj); - // initialize BITMAPINFOHEADER - lpbi->biSize = sizeof(BITMAPINFOHEADER); - lpbi->biWidth = bm.bmWidth; - lpbi->biHeight = bm.bmHeight; - lpbi->biPlanes = 1; - lpbi->biBitCount = wBits; - lpbi->biCompression = BI_RGB; - lpbi->biSizeImage = dwSizeImage; - lpbi->biXPelsPerMeter = 0; - lpbi->biYPelsPerMeter = 0; - lpbi->biClrUsed = 0; - lpbi->biClrImportant = 0; - // get bitmap color table and bitmap data - GetDIBits(hBmpDC, hBmp, 0, lpbi->biHeight, (LPBYTE)lpbi + dwLen - dwSizeImage, - (LPBITMAPINFO)lpbi, DIB_RGB_COLORS); - GlobalUnlock(hClipObj); - SetClipboardData(CF_DIB, hClipObj); - - // get number of entries in the logical palette - GetObject(hPalette,sizeof(WORD),&wBits); - - // memory allocation for temporary palette data - if ((ppal = (PLOGPALETTE) calloc(sizeof(LOGPALETTE) + wBits * sizeof(PALETTEENTRY),1)) != NULL) - { - ppal->palVersion = PALVERSION; - ppal->palNumEntries = wBits; - GetPaletteEntries(hPalette, 0, wBits, ppal->palPalEntry); - SetClipboardData(CF_PALETTE, CreatePalette(ppal)); - free(ppal); - } - } - DeleteDC(hBmpDC); - DeleteObject(hBmp); - #undef WIDTHBYTES - #undef PALVERSION - } - CloseClipboard(); - } - return 0; -} - -// -// ID_VIEW_RESET -// -static LRESULT OnViewReset(VOID) -{ - if (nState != SM_RUN) return 0; - if (YesNoMessage(_T("Are you sure you want to press the Reset Button?"))==IDYES) - { - SwitchToState(SM_SLEEP); - CpuReset(); // register setting after Cpu Reset - SwitchToState(SM_RUN); - } - return 0; -} - -// -// ID_VIEW_SETTINGS -// -static INT_PTR CALLBACK PropSheetProc(HWND hwndPropSheet, UINT uMsg, LPARAM lParam) -{ - switch(uMsg) - { - // called before the dialog is created, hwndPropSheet = NULL, lParam points to dialog resource - case PSCB_PRECREATE: - { - LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE) lParam; - if(!(lpTemplate->style & WS_SYSMENU)) - { - lpTemplate->style |= WS_SYSMENU; - } - } - break; - - // called after the dialog is created - case PSCB_INITIALIZED: - break; - } - return 0; - UNREFERENCED_PARAMETER(hwndPropSheet); -} - -static LRESULT OnViewSettings(VOID) -{ - PROPSHEETPAGE psp[3]; - PROPSHEETHEADER psh; - - // not in nState = SM_INVALID or port2 file must be closed from document - _ASSERT(nState != SM_INVALID || pbyPort2 == NULL); - - psp[0].dwSize = sizeof(PROPSHEETPAGE); - psp[0].dwFlags = PSP_DEFAULT; - psp[0].hInstance = hApp; - psp[0].pszTemplate = MAKEINTRESOURCE(IDD_SET_GENERAL); - psp[0].hIcon = NULL; - psp[0].pszTitle = NULL; - psp[0].pfnDlgProc = SettingsGeneralProc; - psp[0].lParam = 0; - psp[0].pfnCallback = NULL; - - psp[1].dwSize = sizeof(PROPSHEETPAGE); - psp[1].dwFlags = PSP_DEFAULT; - psp[1].hInstance = hApp; - psp[1].pszTemplate = MAKEINTRESOURCE(IDD_SET_MEMORY); - psp[1].hIcon = NULL; - psp[1].pszTitle = NULL; - psp[1].pfnDlgProc = SettingsMemoryProc; - psp[1].lParam = 0; - psp[1].pfnCallback = NULL; - - psp[2].dwSize = sizeof(PROPSHEETPAGE); - psp[2].dwFlags = PSP_DEFAULT; - psp[2].hInstance = hApp; - psp[2].pszTemplate = MAKEINTRESOURCE(IDD_SET_PERIPHERAL); - psp[2].hIcon = NULL; - psp[2].pszTitle = NULL; - psp[2].pfnDlgProc = SettingsPeripheralProc; - psp[2].lParam = 0; - psp[2].pfnCallback = NULL; - - psh.dwSize = sizeof(PROPSHEETHEADER); - psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK | PSH_NOAPPLYNOW; - psh.hwndParent = hWnd; - psh.hInstance = hApp; - psh.hIcon = NULL; - psh.pszCaption = _T("Settings"); - psh.nPages = ARRAYSIZEOF(psp); - psh.nStartPage = 0; - psh.ppsp = (LPCPROPSHEETPAGE) &psp; - psh.pfnCallback = (PFNPROPSHEETCALLBACK) PropSheetProc; - - if (PropertySheet(&psh) == -1) - AbortMessage(_T("Settings Property Sheet Creation Error!")); - - WriteSettings(); - return 0; -} - -// -// ID_VIEW_SCRIPT -// -static LRESULT OnViewScript(VOID) -{ - TCHAR szKmlFile[MAX_PATH]; - BOOL bKMLChanged,bSucc; - - BYTE cType = cCurrentRomType; - if (nState != SM_RUN) - { - InfoMessage(_T("You cannot change the KML script when Emu48 is not running.\n") - _T("Use the File,New menu item to create a new calculator.")); - return 0; - } - SwitchToState(SM_INVALID); - - // make a copy of the current KML script file name - _ASSERT(sizeof(szKmlFile) == sizeof(szCurrentKml)); - lstrcpyn(szKmlFile,szCurrentKml,ARRAYSIZEOF(szKmlFile)); - - bKMLChanged = FALSE; // KML script not changed - bSucc = TRUE; // KML script successful loaded - - do - { - if (!DisplayChooseKml(cType)) // quit with Cancel - { - if (!bKMLChanged) // KML script not changed - break; // exit loop with current loaded KML script - - // restore KML script file name - lstrcpyn(szCurrentKml,szKmlFile,ARRAYSIZEOF(szCurrentKml)); - - // try to restore old KML script - if ((bSucc = InitKML(szCurrentKml,FALSE))) - break; // exit loop with success - - // restoring failed, save document - if (IDCANCEL != SaveChanges(bAutoSave)) - break; // exit loop with no success - - _ASSERT(bSucc == FALSE); // for continuing loop - } - else // quit with Ok - { - bKMLChanged = TRUE; // KML script changed - bSucc = InitKML(szCurrentKml,FALSE); - } - } - while (!bSucc); // retry if KML script is invalid - - if (bSucc) - { - if (Chipset.wRomCrc != wRomCrc) // ROM changed - { - CpuReset(); - Chipset.Shutdn = FALSE; // automatic restart - - Chipset.wRomCrc = wRomCrc; // update current ROM fingerprint - } - if (pbyRom) SwitchToState(SM_RUN); // continue emulation - } - else - { - ResetDocument(); // close document - SetWindowTitle(NULL); - } - return 0; -} - -// -// ID_BACKUP_SAVE -// -static LRESULT OnBackupSave(VOID) -{ - UINT nOldState; - if (pbyRom == NULL) return 0; - nOldState = SwitchToState(SM_INVALID); - SaveBackup(); - SwitchToState(nOldState); - return 0; -} - -// -// ID_BACKUP_RESTORE -// -static LRESULT OnBackupRestore(VOID) -{ - SwitchToState(SM_INVALID); - RestoreBackup(); - if (pbyRom) SwitchToState(SM_RUN); - return 0; -} - -// -// ID_BACKUP_DELETE -// -static LRESULT OnBackupDelete(VOID) -{ - ResetBackup(); - return 0; -} - -// -// ID_OBJECT_LOAD -// -static LRESULT OnObjectLoad(VOID) -{ - SuspendDebugger(); // suspend debugger - bDbgAutoStateCtrl = FALSE; // disable automatic debugger state control - - // calculator off, turn on - if (!(Chipset.IORam[BITOFFSET]&DON)) - { - KeyboardEvent(TRUE,0,0x8000); - Sleep(dwWakeupDelay); - KeyboardEvent(FALSE,0,0x8000); - - // wait for sleep mode - while (Chipset.Shutdn == FALSE) Sleep(0); - } - - if (nState != SM_RUN) - { - InfoMessage(_T("The emulator must be running to load an object.")); - goto cancel; - } - - if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state - { - InfoMessage(_T("The emulator is busy.")); - goto cancel; - } - - _ASSERT(nState == SM_SLEEP); - - if (bLoadObjectWarning) - { - UINT uReply = YesNoCancelMessage( - _T("Warning: Trying to load an object while the emulator is busy\n") - _T("will certainly result in a memory lost. Before loading an object\n") - _T("you should be sure that the calculator is in idle state.\n") - _T("Do you want to see this warning next time you try to load an object?"),0); - switch (uReply) - { - case IDYES: - break; - case IDNO: - bLoadObjectWarning = FALSE; - break; - case IDCANCEL: - SwitchToState(SM_RUN); - goto cancel; - } - } - - if (!GetLoadObjectFilename(_T(HP_FILTER),_T("HP"))) - { - SwitchToState(SM_RUN); - goto cancel; - } - - if (!LoadObject(szBufferFilename)) - { - SwitchToState(SM_RUN); - goto cancel; - } - - SwitchToState(SM_RUN); // run state - while (nState!=nNextState) Sleep(0); - _ASSERT(nState == SM_RUN); - KeyboardEvent(TRUE,0,0x8000); - Sleep(dwWakeupDelay); - KeyboardEvent(FALSE,0,0x8000); - while (Chipset.Shutdn == FALSE) Sleep(0); - -cancel: - bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control - ResumeDebugger(); - return 0; -} - -// -// ID_OBJECT_SAVE -// -static LRESULT OnObjectSave(VOID) -{ - if (nState != SM_RUN) - { - InfoMessage(_T("The emulator must be running to save an object.")); - return 0; - } - - if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state - { - InfoMessage(_T("The emulator is busy.")); - return 0; - } - - _ASSERT(nState == SM_SLEEP); - - if (GetSaveObjectFilename(_T(HP_FILTER),_T("HP"))) - { - SaveObject(szBufferFilename); - } - - SwitchToState(SM_RUN); - return 0; -} - -// -// ID_TOOL_DISASM -// -static INT_PTR CALLBACK Disasm(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - static DWORD dwAddress,dwAddressMax; - - enum MEM_MAPPING eMode; - LONG i; - DWORD dwNxtAddr; - TCHAR szAddress[256] = _T("0"); - - switch (message) - { - case WM_INITDIALOG: - VERIFY(SetMemRomType(cCurrentRomType)); // set current model - - // set fonts & cursor - SendDlgItemMessage(hDlg,IDC_DISASM_MODULE,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_DISASM_MODE_TEXT,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_DISASM_MODE,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_ADDRESS,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_DISASM_ADR,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_DISASM_NEXT,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_DISASM_COPY,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDCANCEL,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - - // fill disassembler mode combo box - { - // disassemble mode window - HWND hWnd = GetDlgItem(hDlg,IDC_DISASM_MODE); - - if (hDlgDebug == NULL) // debugger not open - { - LPCTSTR lpszModes[] = { _T("Map"), _T("NCE1"), _T("NCE2"), _T("CE1"), _T("CE2"), _T("NCE3") }; - - for (eMode = MEM_MMU; eMode <= MEM_NCE3; eMode = (enum MEM_MAPPING) (eMode + 1)) - { - if (GetMemAvail(eMode)) - { - _ASSERT(eMode < ARRAYSIZEOF(lpszModes)); - i = (LONG) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) lpszModes[eMode]); - SendMessage(hWnd,CB_SETITEMDATA,i,(LPARAM) eMode); - } - } - VERIFY(SendMessage(hWnd,CB_SETCURSEL,0,0) != LB_ERR); - - // disassemble with mapped modules - VERIFY(SetMemMapType(MEM_MMU)); - } - else // debugger open - { - EnableWindow(hWnd,FALSE); - } - } - - SetDlgItemText(hDlg,IDC_DISASM_ADR,szAddress); - dwAddressMax = GetMemDataSize(); - dwAddress = _tcstoul(szAddress,NULL,16); - return TRUE; - case WM_COMMAND: - switch(LOWORD(wParam)) - { - // decode memory mode combo box - case IDC_DISASM_MODE: - // new combo box item selected - if (HIWORD(wParam) == CBN_SELENDOK) - { - HWND hWnd = GetDlgItem(hDlg,IDC_DISASM_MODE); - i = (LONG) SendMessage(hWnd,CB_GETCURSEL,0,0); - eMode = (enum MEM_MAPPING) SendMessage(hWnd,CB_GETITEMDATA,i,0); - VERIFY(SetMemMapType(eMode)); - dwAddressMax = GetMemDataSize(); - } - break; - case IDOK: - SendDlgItemMessage(hDlg,IDC_DISASM_ADR,EM_SETSEL,0,-1); - GetDlgItemText(hDlg,IDC_DISASM_ADR,szAddress,ARRAYSIZEOF(szAddress)); - // test if valid hex address - for (i = 0; i < (LONG) lstrlen(szAddress); ++i) - { - if (_istxdigit(szAddress[i]) == FALSE) - return FALSE; - } - dwAddress = _tcstoul(szAddress,NULL,16); - // no break - case IDC_DISASM_NEXT: - if (dwAddress >= dwAddressMax) - return FALSE; - i = wsprintf(szAddress,(dwAddress <= 0xFFFFF) ? _T("%05lX ") : _T("%06lX "),dwAddress); - // check if address content is a PCO (Primitive Code Object) - dwNxtAddr = (dwAddress + 5) & 0xFFFFF; - if (Read5(dwAddress) == dwNxtAddr) - { - if (disassembler_mode == HP_MNEMONICS) - { - _tcscat(&szAddress[i],_T("CON(5) (*)+5")); - } - else - { - wsprintf(&szAddress[i],_T("dcr.5 $%05x"),dwNxtAddr); - } - dwAddress = dwNxtAddr; - } - else - { - dwAddress = disassemble(dwAddress,&szAddress[i]); - } - i = (LONG) SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_ADDSTRING,0,(LPARAM) szAddress); - SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_SELITEMRANGE,FALSE,MAKELPARAM(0,i)); - SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_SETSEL,TRUE,i); - SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_SETTOPINDEX,i,0); - return TRUE; - case IDC_DISASM_COPY: - // copy selected items to clipboard - CopyItemsToClipboard(GetDlgItem(hDlg,IDC_DISASM_WIN)); - return TRUE; - case IDCANCEL: - EndDialog(hDlg,IDCANCEL); - return TRUE; - } - break; - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -// -// ID_ABOUT -// -static INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_INITDIALOG: - SetDlgItemText(hDlg,IDC_VERSION,szNoTitle); - SetDlgItemText(hDlg,IDC_LICENSE,szLicence); - return TRUE; - case WM_COMMAND: - wParam = LOWORD(wParam); - if ((wParam==IDOK)||(wParam==IDCANCEL)) - { - EndDialog(hDlg, wParam); - return TRUE; - } - break; - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -static LRESULT OnToolDisasm(VOID) // disasm dialogbox call -{ - if (pbyRom) SwitchToState(SM_SLEEP); - if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DISASM), hWnd, (DLGPROC)Disasm) == -1) - AbortMessage(_T("Disassembler Dialog Box Creation Error!")); - if (pbyRom) SwitchToState(SM_RUN); - return 0; -} - -static LRESULT OnTopics(VOID) -{ - ShellExecute(hWnd,_T("open"),_T("emu48.htm"),NULL,szEmuDirectory,SW_SHOWNORMAL); - return 0; -} - -static LRESULT OnAbout(VOID) -{ - if (DialogBox(hApp, MAKEINTRESOURCE(IDD_ABOUT), hWnd, (DLGPROC)About) == -1) - AbortMessage(_T("About Dialog Box Creation Error!")); - return 0; -} - -static VOID OnContextMenu(LPARAM lParam) -{ - if (GetMenu(hWnd) == NULL) // no main window menu - { - BOOL bContextMenu = TRUE; // call context menu - POINT pt; - - POINTSTOPOINT(pt,MAKEPOINTS(lParam)); // mouse position - - if (pt.x == -1 && pt.y == -1) // VK_APPS - { - RECT rc; - - GetCursorPos(&pt); // get current mouse position - GetWindowRect(hWnd,&rc); // get position of active window - if (PtInRect(&rc,pt)==FALSE) // mouse position outside active window - { - pt.x = 15; // open context help at client position 15,15 - pt.y = 15; - VERIFY(ClientToScreen(hWnd,&pt)); - } - } - else // got a mouse position - { - POINT ptc = pt; - // convert mouse into client position - VERIFY(ScreenToClient(hWnd,&ptc)); - - // in client area not over a button - bContextMenu = (ptc.y >= 0 && !MouseIsButton(ptc.x,ptc.y)); - } - - if (bContextMenu) // call the context menu - { - HMENU hMenu; - - // load the popup menu resource - if ((hMenu = LoadMenu(hApp,MAKEINTRESOURCE(IDM_MENU))) != NULL) - { - // display the popup menu - TrackPopupMenu(GetSubMenu(hMenu,0), - TPM_LEFTALIGN | TPM_LEFTBUTTON, - pt.x, pt.y, 0, hWnd, NULL); - - DestroyMenu(hMenu); // destroy the menu - } - } - } - return; -} - -static LRESULT OnLButtonDown(UINT nFlags, WORD x, WORD y) -{ - if (nMacroState == MACRO_PLAY) return 0; // playing macro - if (nState == SM_RUN) MouseButtonDownAt(nFlags, x,y); - - bMouseButton = MouseIsButton(x,y); // mouse is over button hit area - - // no title bar or window movement over client enabled and hit area not over a button - if ((!bTitleBar || bClientWinMove) && nFlags == MK_LBUTTON && !bMouseButton) - { - // move window while holding the left mouse button - PostMessage(hWnd,WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(x,y)); - } - return 0; -} - -static LRESULT OnLButtonUp(UINT nFlags, WORD x, WORD y) -{ - if (nMacroState == MACRO_PLAY) return 0; // playing macro - if (nState == SM_RUN) MouseButtonUpAt(nFlags, x,y); - bMouseButton = FALSE; - return 0; -} - -static LRESULT OnMouseMove(UINT nFlags, WORD x, WORD y) -{ - // emulator not active but cursor is over emulator window - if (bActFollowsMouse && GetActiveWindow() != hWnd) - { - ForceForegroundWindow(hWnd); // force emulator window to foreground - } - - if (nMacroState == MACRO_PLAY) return 0; // playing macro - if (nState == SM_RUN) MouseMovesTo(nFlags, x,y); - return 0; -} - -static LRESULT OnNcMouseMove(UINT nFlags, WORD x, WORD y) -{ - // emulator not active but cursor is over emulator window - if (bActFollowsMouse && GetActiveWindow() != hWnd) - { - ForceForegroundWindow(hWnd); // force emulator window to foreground - } - return 0; - UNREFERENCED_PARAMETER(nFlags); - UNREFERENCED_PARAMETER(x); - UNREFERENCED_PARAMETER(y); -} - -static LRESULT OnKeyDown(int nVirtKey, LPARAM lKeyData) -{ - if (nMacroState == MACRO_PLAY) return 0; // playing macro - // call RunKey() only once (suppress autorepeat feature) - if (nState == SM_RUN && (lKeyData & 0x40000000) == 0) - RunKey((BYTE)nVirtKey, TRUE); - bMouseButton = FALSE; - return 0; -} - -static LRESULT OnKeyUp(int nVirtKey, LPARAM lKeyData) -{ - if (nMacroState == MACRO_PLAY) return 0; // playing macro - if (nState == SM_RUN) RunKey((BYTE)nVirtKey, FALSE); - return 0; - UNREFERENCED_PARAMETER(lKeyData); -} - -static LRESULT OnCopyData(PCOPYDATASTRUCT psCDS) -{ - switch (psCDS->dwData) - { - case CDID_FILENAME: - // current instance has document loaded and got a wide-character file name - if (bDocumentAvail && psCDS->cbData > 0 && psCDS->lpData != NULL) - { - TCHAR szActFilename[MAX_PATH]; - LPTSTR lpFilePart; // address of file name in path - - #if defined _UNICODE - { - // get full path file name for requested state file - GetFullPathName((LPCTSTR) psCDS->lpData,ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart); - } - #else - { - CHAR szAscFilename[MAX_PATH]; - - WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, - (LPCWSTR) psCDS->lpData, -1, - szAscFilename, ARRAYSIZEOF(szAscFilename), NULL, NULL); - - // get full path file name for requested state file - GetFullPathName(szAscFilename,ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart); - } - #endif - - // get full path file name for actual state file - GetFullPathName(szCurrentFilename,ARRAYSIZEOF(szActFilename),szActFilename,&lpFilePart); - - // check if both file names are unequal - if (lstrcmpi(szBufferFilename,szActFilename) != 0) - { - UINT nCurState; - - if (pbyRom) - { - nCurState = SwitchToState(SM_INVALID); - if (IDCANCEL == SaveChanges(bAutoSave)) - goto cancel; - } - if (OpenDocument(szBufferFilename)) // open new file - { - MruAdd(szBufferFilename); - } -cancel: - if (pbyRom) SwitchToState(nCurState); - } - } - break; - default: - return FALSE; // message not processed - } - return TRUE; // message processed -} - -LRESULT CALLBACK MainWndProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_CREATE: return OnCreate(hWindow); - case WM_DESTROY: return OnDestroy(hWindow); - case WM_PAINT: return OnPaint(hWindow); - case WM_INITMENU: return OnInitMenu((HMENU) wParam); - case WM_DROPFILES: return OnDropFiles((HDROP) wParam); - case WM_ACTIVATE: - if (LOWORD(wParam)==WA_INACTIVE) break; - case WM_QUERYNEWPALETTE: - if (hPalette) - { - SelectPalette(hWindowDC, hPalette, FALSE); - if (RealizePalette(hWindowDC)) - { - InvalidateRect(hWindow,NULL,TRUE); - return TRUE; - } - } - return FALSE; - case WM_PALETTECHANGED: - if ((HWND)wParam == hWindow) break; - if (hPalette) - { - SelectPalette(hWindowDC, hPalette, FALSE); - if (RealizePalette(hWindowDC)) - { - // UpdateColors(hWindowDC); - InvalidateRect(hWindow,NULL,TRUE); - } - } - return FALSE; - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case ID_FILE_NEW: return OnFileNew(); - case ID_FILE_OPEN: return OnFileOpen(); - case ID_FILE_SAVE: return OnFileSave(); - case ID_FILE_SAVEAS: return OnFileSaveAs(); - case ID_FILE_CLOSE: return OnFileClose(); - case ID_FILE_EXIT: return OnFileExit(); - case ID_STACK_COPY: return OnStackCopy(); - case ID_STACK_PASTE: return OnStackPaste(); - case ID_VIEW_COPY: return OnViewCopy(); - case ID_VIEW_RESET: return OnViewReset(); - case ID_VIEW_SETTINGS: return OnViewSettings(); - case ID_VIEW_SCRIPT: return OnViewScript(); - case ID_BACKUP_SAVE: return OnBackupSave(); - case ID_BACKUP_RESTORE: return OnBackupRestore(); - case ID_BACKUP_DELETE: return OnBackupDelete(); - case ID_OBJECT_LOAD: return OnObjectLoad(); - case ID_OBJECT_SAVE: return OnObjectSave(); - case ID_TOOL_DISASM: return OnToolDisasm(); - case ID_TOOL_DEBUG: return OnToolDebug(); - case ID_TOOL_MACRO_RECORD: return OnToolMacroNew(); - case ID_TOOL_MACRO_PLAY: return OnToolMacroPlay(); - case ID_TOOL_MACRO_STOP: return OnToolMacroStop(); - case ID_TOOL_MACRO_SETTINGS: return OnToolMacroSettings(); - case ID_HELP_TOPICS: return OnTopics(); - case ID_ABOUT: return OnAbout(); - } - // check if command ID belongs to MRU file area - if ( (LOWORD(wParam) >= ID_FILE_MRU_FILE1) - && (LOWORD(wParam) < ID_FILE_MRU_FILE1 + MruEntries())) - return OnFileMruOpen(LOWORD(wParam)); - break; - case WM_SYSCOMMAND: - switch (wParam & 0xFFF0) - { - case SC_CLOSE: return OnFileExit(); - } - break; - case WM_ENDSESSION: - // session will end and any auto saving is enabled - if (wParam == TRUE && (bAutoSave || bAutoSaveOnExit)) - { - SwitchToState(SM_INVALID); // hold emulation thread - if (szCurrentFilename[0] != 0) // has current filename - SaveDocument(); - SwitchToState(SM_RUN); // on cancel restart emulation thread - } - break; - case WM_CONTEXTMENU: - if (!bMouseButton) OnContextMenu(lParam); - break; - case WM_RBUTTONDOWN: - case WM_LBUTTONDOWN: return OnLButtonDown((UINT) wParam, LOWORD(lParam), HIWORD(lParam)); - case WM_LBUTTONUP: return OnLButtonUp((UINT) wParam, LOWORD(lParam), HIWORD(lParam)); - case WM_MOUSEMOVE: return OnMouseMove((UINT) wParam, LOWORD(lParam), HIWORD(lParam)); - case WM_NCMOUSEMOVE: return OnNcMouseMove((UINT) wParam, LOWORD(lParam), HIWORD(lParam)); - case WM_KEYUP: return OnKeyUp((int) wParam, lParam); - case WM_KEYDOWN: return OnKeyDown((int) wParam, lParam); - #if !defined _USRDLL // not in DLL version - case WM_COPYDATA: return OnCopyData((PCOPYDATASTRUCT) lParam); - #endif - } - return DefWindowProc(hWindow, uMsg, wParam, lParam); -} - -int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) -{ - MSG msg; - WNDCLASS wc; - ATOM classAtom; - RECT rectWindow; - HACCEL hAccel; - DWORD dwThreadId; - DWORD dwProcessor; - HSZ hszService, hszTopic; // variables for DDE server - LPTSTR lpFilePart; - - // module handle to kernel32 - const HMODULE hmKernel32 = GetModuleHandle(_T("kernel32")); - - // enable memory leak detection - _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); - - hApp = hInst; - #if defined _UNICODE - { - ppArgv = (LPCTSTR*) CommandLineToArgvW(GetCommandLine(),&nArgc); - } - #else - { - nArgc = __argc; // no. of command line arguments - ppArgv = (LPCTSTR*) __argv; // command line arguments - } - #endif - - wc.style = CS_BYTEALIGNCLIENT; - wc.lpfnWndProc = (WNDPROC)MainWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = hInst; - wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_EMU48)); - wc.hCursor = NULL; - wc.hbrBackground = NULL; - wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU); - wc.lpszClassName = _T("CEmu48"); - - if (!(classAtom = RegisterClass(&wc))) - { - AbortMessage( - _T("CEmu48 class registration failed.\n") - _T("This application will now terminate.")); - return FALSE; - } - - // read emulator settings - GetCurrentDirectory(ARRAYSIZEOF(szCurrentDirectory),szCurrentDirectory); - ReadSettings(); - - // running an instance of me? - if (bSingleInstance && (hWnd = FindWindow(MAKEINTATOM(classAtom),NULL)) != NULL) - { - COPYDATASTRUCT sCDS; - - if (IsIconic(hWnd)) // window minimized - ShowWindow(hWnd,SW_RESTORE); // show window - - // put the window into foreground - ForceForegroundWindow(GetLastActivePopup(hWnd)); - - if (nArgc >= 2) // use decoded parameter line - { - LPTSTR lpFilePart; // address of file name in path - DWORD dwLength; // file name length - - // get full path file name - GetFullPathName(ppArgv[1],ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart); - - // size of file name incl. EOS - dwLength = lstrlen(szBufferFilename) + 1; - sCDS.cbData = dwLength * sizeof(WCHAR); - - #if defined _UNICODE - { - sCDS.lpData = szBufferFilename; - } - #else - { - sCDS.lpData = _alloca(sCDS.cbData); - if (sCDS.lpData != NULL) - { - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szBufferFilename, dwLength, - (LPWSTR) sCDS.lpData, sCDS.cbData); - } - else - { - sCDS.cbData = 0; // size of file name - } - } - #endif - } - else - { - sCDS.lpData = NULL; // file name - sCDS.cbData = 0; // size of file name - } - - // fill the COPYDATA structure and send file name to other instance - sCDS.dwData = CDID_FILENAME; // function identifier - SendMessage(hWnd,WM_COPYDATA,(WPARAM) NULL,(LPARAM) &sCDS); - return 0; // quit program - } - - // disable TIMER_RESOLUTION throttling for Windows 11 and later - { - typedef const BOOL(WINAPI* LPFN_SPI)(HANDLE hProcess,INT ProcessInformationClass,LPVOID ProcessInformation,DWORD ProcessInformationSize); - - // SetProcessInformation() is available since Windows 8, PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION since Windows 11 - LPFN_SPI fnSetProcessInformation = (LPFN_SPI) GetProcAddress(hmKernel32, "SetProcessInformation"); - - if (fnSetProcessInformation != NULL) // running on Windows 8 or later - { - PROCESS_POWER_THROTTLING_STATE Ppts; - - ZeroMemory(&Ppts,sizeof(Ppts)); - Ppts.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION; - Ppts.ControlMask = PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION; - - // don't check for success, success only on Windoes 11 and later - fnSetProcessInformation(GetCurrentProcess(),ProcessPowerThrottling,&Ppts,sizeof(Ppts)); - } - } - - // Create window - rectWindow.left = 0; - rectWindow.top = 0; - rectWindow.right = 256; - rectWindow.bottom = 0; - AdjustWindowRect(&rectWindow, STYLE_TITLE, TRUE); - - hWnd = CreateWindow(MAKEINTATOM(classAtom),_T("Emu48"), - STYLE_TITLE, - CW_USEDEFAULT, CW_USEDEFAULT, - rectWindow.right - rectWindow.left, - rectWindow.bottom - rectWindow.top, - NULL,NULL,hApp,NULL); - - if (hWnd == NULL) - { - AbortMessage(_T("Window creation failed.")); - return FALSE; - } - - VERIFY(hAccel = LoadAccelerators(hInst, MAKEINTRESOURCE(IDR_MENU))); - - // initialization - QueryPerformanceFrequency(&lFreq); // init high resolution counter - QueryPerformanceCounter(&lAppStart); - - szCurrentKml[0] = 0; // no KML file selected - SetSpeed(bRealSpeed); // set speed - MruInit(4); // init MRU entries - - // create auto event handle - hEventShutdn = CreateEvent(NULL,FALSE,FALSE,NULL); - if (hEventShutdn == NULL) - { - AbortMessage(_T("Event creation failed.")); - DestroyWindow(hWnd); - return FALSE; - } - - nState = SM_RUN; // init state must be <> nNextState - nNextState = SM_INVALID; // go into invalid state - hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&WorkerThread, NULL, CREATE_SUSPENDED, &dwThreadId); - if (hThread == NULL) - { - CloseHandle(hEventShutdn); // close event handle - AbortMessage(_T("Thread creation failed.")); - DestroyWindow(hWnd); - return FALSE; - } - - // get processor for Saturn CPU thread - { - // GetCurrentProcessorNumber() is available since Windows Vista - typedef const DWORD (WINAPI *LPFN_GCPN)(VOID); - LPFN_GCPN fnGetCurrentProcessorNumber = (LPFN_GCPN) GetProcAddress(hmKernel32,"GetCurrentProcessorNumber"); - - if (fnGetCurrentProcessorNumber != NULL) // running on Vista or later - { - dwProcessor = fnGetCurrentProcessorNumber(); // get current processor number - } - else - { - // SetThreadIdealProcessor() is available since Windows NT4.0 - typedef const DWORD (WINAPI *LPFN_STIP)(HANDLE hThread,DWORD dwIdealProcessor); - LPFN_STIP fnSetThreadIdealProcessor = (LPFN_STIP) GetProcAddress(hmKernel32,"SetThreadIdealProcessor"); - - dwProcessor = (fnSetThreadIdealProcessor != NULL) // running on NT4.0 or later - ? fnSetThreadIdealProcessor(hThread,MAXIMUM_PROCESSORS) // get ideal processor no. - : 0; // select 1st processor - } - } - - // bind Saturn CPU emulation thread to selected processor - // on multiprocessor machines for QueryPerformanceCounter() - VERIFY(SetThreadAffinityMask(hThread,(DWORD_PTR) (1 << dwProcessor))); - ResumeThread(hThread); // start thread - while (nState!=nNextState) Sleep(0); // wait for thread initialized - - idDdeInst = 0; // initialize DDE server - if (DdeInitialize(&idDdeInst,(PFNCALLBACK) &DdeCallback, - APPCLASS_STANDARD | - CBF_FAIL_EXECUTES | CBF_FAIL_ADVISES | - CBF_SKIP_REGISTRATIONS | CBF_SKIP_UNREGISTRATIONS,0)) - { - TerminateThread(hThread, 0); // kill emulation thread - CloseHandle(hEventShutdn); // close event handle - AbortMessage(_T("Could not initialize server!")); - DestroyWindow(hWnd); - return FALSE; - } - - // init clipboard format and name service - uCF_HpObj = RegisterClipboardFormat(_T(CF_HPOBJ)); - hszService = DdeCreateStringHandle(idDdeInst,szAppName,0); - hszTopic = DdeCreateStringHandle(idDdeInst,szTopic,0); - DdeNameService(idDdeInst,hszService,NULL,DNS_REGISTER); - - SoundOpen(uWaveDevId); // open waveform-audio output device - - _ASSERT(hWnd != NULL); - _ASSERT(hWindowDC != NULL); - - if (nArgc >= 2) // use decoded parameter line - lstrcpyn(szBufferFilename,ppArgv[1],ARRAYSIZEOF(szBufferFilename)); - else // use last document setting - ReadLastDocument(szBufferFilename, ARRAYSIZEOF(szBufferFilename)); - - if (szBufferFilename[0]) // given default document - { - TCHAR szTemp[MAX_PATH+8] = _T("Loading "); - RECT rectClient; - - _ASSERT(hWnd != NULL); - VERIFY(GetClientRect(hWnd,&rectClient)); - GetCutPathName(szBufferFilename,&szTemp[8],MAX_PATH,rectClient.right/11); - SetWindowTitle(szTemp); - if (OpenDocument(szBufferFilename)) - { - MruAdd(szCurrentFilename); - ShowWindow(hWnd,nCmdShow); - goto start; - } - } - - SetWindowTitle(_T("New Document")); - ShowWindow(hWnd,nCmdShow); // show emulator menu - - // no default document, ask for new one - if (NewDocument()) SetWindowTitle(_T("Untitled")); - -start: - if (bStartupBackup) SaveBackup(); // make a RAM backup at startup - if (pbyRom) SwitchToState(SM_RUN); - - while (GetMessage(&msg, NULL, 0, 0)) - { - if ( !TranslateAccelerator(hWnd, hAccel, &msg) - && (hDlgDebug == NULL || !IsDialogMessage(hDlgDebug, &msg)) - && (hDlgFind == NULL || !IsDialogMessage(hDlgFind, &msg)) - && (hDlgProfile == NULL || !IsDialogMessage(hDlgProfile, &msg)) - && (hDlgRplObjView == NULL || !IsDialogMessage(hDlgRplObjView, &msg))) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - // clean up DDE server - DdeNameService(idDdeInst, hszService, NULL, DNS_UNREGISTER); - DdeFreeStringHandle(idDdeInst, hszService); - DdeFreeStringHandle(idDdeInst, hszTopic); - DdeUninitialize(idDdeInst); - - SoundClose(); // close waveform-audio output device - - // get full path name of szCurrentFilename - if (GetFullPathName(szCurrentFilename,ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart) == 0) - szBufferFilename[0] = 0; // no last document name - - WriteLastDocument(szBufferFilename); // save last document setting - WriteSettings(); // save emulation settings - - CloseHandle(hThread); // close thread handle - CloseHandle(hEventShutdn); // close event handle - _ASSERT(nState == SM_RETURN); // emulation thread down? - ResetDocument(); - ResetBackup(); - MruCleanup(); - _ASSERT(pbyRom == NULL); // rom file unmapped - _ASSERT(pbyPort2 == NULL); // port2 file unmapped - _ASSERT(pKml == NULL); // KML script not closed - _ASSERT(szTitle == NULL); // freed allocated memory - _ASSERT(hPalette == NULL); // freed resource memory - - return (int) msg.wParam; - UNREFERENCED_PARAMETER(lpCmdLine); - UNREFERENCED_PARAMETER(hPrevInst); -} +/* + * Emu48.c + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ +#include "pch.h" +#include "resource.h" +#include "Emu48.h" +#include "io.h" +#include "kml.h" +#include "debugger.h" + +#define VERSION "1.67" + +#ifdef _DEBUG +LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug"); +#else +LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION); +#endif +LPTSTR szAppName = _T("Emu48"); // application name for DDE server +LPTSTR szTopic = _T("Stack"); // topic for DDE server +LPTSTR szTitle = NULL; + +static const LPCTSTR szLicence = + _T("This program is free software; you can redistribute it and/or modify\r\n") + _T("it under the terms of the GNU General Public License as published by\r\n") + _T("the Free Software Foundation; either version 2 of the License, or\r\n") + _T("(at your option) any later version.\r\n") + _T("\r\n") + _T("This program is distributed in the hope that it will be useful,\r\n") + _T("but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n") + _T("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\r\n") + _T("See the GNU General Public License for more details.\r\n") + _T("\r\n") + _T("You should have received a copy of the GNU General Public License along\r\n") + _T("with this program; if not, write to the Free Software Foundation, Inc.,\r\n") + _T("51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA."); + +static BOOL bOwnCursor = FALSE; +static BOOL bTitleBar = TRUE; +static BOOL bMouseButton = FALSE; + + +CRITICAL_SECTION csGDILock; // critical section for hWindowDC +CRITICAL_SECTION csLcdLock; // critical section for display update +CRITICAL_SECTION csKeyLock; // critical section for key scan +CRITICAL_SECTION csIOLock; // critical section for I/O access +CRITICAL_SECTION csT1Lock; // critical section for timer1 access +CRITICAL_SECTION csT2Lock; // critical section for timer2 access +CRITICAL_SECTION csTxdLock; // critical section for transmit byte +CRITICAL_SECTION csRecvLock; // critical section for receive byte +CRITICAL_SECTION csSlowLock; // critical section for speed slow down +CRITICAL_SECTION csDbgLock; // critical section for debugger purpose +INT nArgc; // no. of command line arguments +LPCTSTR *ppArgv; // command line arguments +LARGE_INTEGER lFreq; // high performance counter frequency +LARGE_INTEGER lAppStart; // high performance counter value at Appl. start +DWORD idDdeInst; // DDE server id +UINT uCF_HpObj; // DDE clipboard format +HANDLE hThread; +HANDLE hEventShutdn; // event handle to stop cpu thread + +HINSTANCE hApp = NULL; +HWND hWnd = NULL; +HWND hDlgDebug = NULL; // handle for debugger dialog +HWND hDlgFind = NULL; // handle for debugger find dialog +HWND hDlgProfile = NULL; // handle for debugger profile dialog +HWND hDlgRplObjView = NULL; // handle for debugger rpl object viewer +HDC hWindowDC = NULL; +HPALETTE hPalette = NULL; +HPALETTE hOldPalette = NULL; // old palette of hWindowDC +DWORD dwTColor = (DWORD) -1; // transparency color +DWORD dwTColorTol = 0; // transparency color tolerance +HRGN hRgn = NULL; +HCURSOR hCursorArrow = NULL; +HCURSOR hCursorHand = NULL; +UINT uWaveDevId = WAVE_MAPPER; // default audio device +DWORD dwWakeupDelay = 200; // ON key hold time to switch on calculator +BOOL bAutoSave = FALSE; +BOOL bAutoSaveOnExit = TRUE; +BOOL bSaveDefConfirm = TRUE; // yes +BOOL bStartupBackup = FALSE; +BOOL bAlwaysDisplayLog = TRUE; +BOOL bLoadObjectWarning = TRUE; +BOOL bShowTitle = TRUE; // show main window title bar +BOOL bShowMenu = TRUE; // show main window menu bar +BOOL bAlwaysOnTop = FALSE; // emulator window always on top +BOOL bActFollowsMouse = FALSE; // emulator window activation follows mouse +BOOL bClientWinMove = FALSE; // emulator window can be moved over client area +BOOL bSingleInstance = FALSE; // multiple emulator instances allowed + + +//################ +//# +//# Window Status +//# +//################ + +VOID SetWindowTitle(LPCTSTR szString) +{ + if (szTitle) free(szTitle); + + _ASSERT(hWnd != NULL); + if (szString) + { + szTitle = DuplicateString(szString); + SetWindowText(hWnd, szTitle); + } + else + { + szTitle = NULL; + SetWindowText(hWnd, szNoTitle); + } + return; +} + +VOID ForceForegroundWindow(HWND hWnd) +{ + // force window to foreground + DWORD dwEmuThreadID = GetCurrentThreadId(); + DWORD dwActThreadID = GetWindowThreadProcessId(GetForegroundWindow(),NULL); + + AttachThreadInput(dwEmuThreadID,dwActThreadID,TRUE); + SetForegroundWindow(hWnd); + AttachThreadInput(dwEmuThreadID,dwActThreadID,FALSE); + return; +} + +static __inline VOID UpdateWindowBars(VOID) +{ + DWORD dwStyle; + HMENU hMenu; + + BOOL bUpdate = FALSE; // no update + + // get current title bar style + dwStyle = (DWORD) GetWindowLongPtr(hWnd,GWL_STYLE); + if ((bTitleBar = (bShowTitle || bDocumentAvail == FALSE))) + { + // title bar off + if ((dwStyle & STYLE_TITLE) != STYLE_TITLE) + { + SetWindowLongPtr(hWnd,GWL_STYLE,(dwStyle & ~STYLE_NOTITLE) | STYLE_TITLE); + bUpdate = TRUE; + } + } + else + { + // title bar on + if ((dwStyle & STYLE_NOTITLE) != STYLE_NOTITLE) + { + SetWindowLongPtr(hWnd,GWL_STYLE,(dwStyle & ~STYLE_TITLE) | STYLE_NOTITLE); + bUpdate = TRUE; + } + } + + hMenu = GetMenu(hWnd); // get system menu + if (bShowMenu || bDocumentAvail == FALSE) + { + if (hMenu == NULL) // menu off + { + // restore menu bar + SetMenu(hWnd,LoadMenu(hApp,MAKEINTRESOURCE(IDR_MENU))); + bUpdate = TRUE; + } + } + else + { + if (hMenu != NULL) // menu on + { + // close menu bar + SetMenu(hWnd,NULL); + VERIFY(DestroyMenu(hMenu)); + bUpdate = TRUE; + } + } + + if (dwTColor != (DWORD) -1) // prepare background bitmap with transparency + { + if (!bTitleBar && GetMenu(hWnd) == NULL) + { + if (hRgn == NULL) + { + EnterCriticalSection(&csGDILock); // solving NT GDI problems + { + // enable background bitmap transparency + hRgn = CreateRgnFromBitmap((HBITMAP) GetCurrentObject(hMainDC,OBJ_BITMAP), + dwTColor, + dwTColorTol); + if (hRgn != NULL) // region definition successful + { + OffsetRgn(hRgn,-(INT) nBackgroundX,-(INT) nBackgroundY); + SetWindowRgn(hWnd,hRgn,TRUE); + } + else // region definition failed + { + // disable transparency + dwTColor = (DWORD) -1; + } + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + } + } + else + { + if (hRgn != NULL) // region active + { + EnterCriticalSection(&csGDILock); // solving NT GDI problems + { + // disable background bitmap transparency + SetWindowRgn(hWnd,NULL,TRUE); + hRgn = NULL; + + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + } + } + } + + if (bUpdate) // changed state of title or menu bar + { + ResizeWindow(); // resize & redraw window + } + return; +} + + + +//################ +//# +//# Clipboard Tool +//# +//################ + +VOID CopyItemsToClipboard(HWND hWnd) // save selected Listbox Items to Clipboard +{ + LONG i; + LPINT lpnCount; + + // get number of selections + if ((i = (LONG) SendMessage(hWnd,LB_GETSELCOUNT,0,0)) == 0) + return; // no items selected + + if ((lpnCount = (LPINT) malloc(i * sizeof(INT))) != NULL) + { + LPTSTR lpszData; + HANDLE hClipObj; + LONG j,lMem = 0; + + // get indexes of selected items + i = (LONG) SendMessage(hWnd,LB_GETSELITEMS,i,(LPARAM) lpnCount); + for (j = 0;j < i;++j) // scan all selected items + { + // calculate total amount of characters + lMem += (LONG) SendMessage(hWnd,LB_GETTEXTLEN,lpnCount[j],0) + 2; + } + // allocate clipboard data + if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,(lMem + 1) * sizeof(*lpszData))) != NULL) + { + if ((lpszData = (LPTSTR) GlobalLock(hClipObj))) + { + for (j = 0;j < i;++j) // scan all selected items + { + lpszData += SendMessage(hWnd,LB_GETTEXT,lpnCount[j],(LPARAM) lpszData); + *lpszData++ = _T('\r'); + *lpszData++ = _T('\n'); + } + *lpszData = 0; // set EOS + GlobalUnlock(hClipObj); // unlock memory + } + + if (OpenClipboard(hWnd)) + { + if (EmptyClipboard()) + #if defined _UNICODE + SetClipboardData(CF_UNICODETEXT,hClipObj); + #else + SetClipboardData(CF_TEXT,hClipObj); + #endif + else + GlobalFree(hClipObj); + CloseClipboard(); + } + else // clipboard open failed + { + GlobalFree(hClipObj); + } + } + free(lpnCount); // free item table + } + return; +} + + + +//################ +//# +//# Settings +//# +//################ + +// get R/W state of file +static BOOL IsFileWriteable(LPCTSTR szFilename) +{ + DWORD dwFileAtt; + + BOOL bWriteable = FALSE; + + SetCurrentDirectory(szEmuDirectory); + dwFileAtt = GetFileAttributes(szFilename); + if (dwFileAtt != 0xFFFFFFFF) + bWriteable = ((dwFileAtt & FILE_ATTRIBUTE_READONLY) == 0); + SetCurrentDirectory(szCurrentDirectory); + return bWriteable; +} + +// set listfield for serial combo boxes +static VOID SetCommList(HWND hDlg,LPCTSTR szWireSetting,LPCTSTR szIrSetting) +{ + WPARAM wSelectWire,wSelectIr; + HKEY hKey; + + wSelectWire = wSelectIr = 0; // set selections to disabled + SendDlgItemMessage(hDlg,IDC_WIRE,CB_ADDSTRING,0,(LPARAM) _T(NO_SERIAL)); + SendDlgItemMessage(hDlg,IDC_IR ,CB_ADDSTRING,0,(LPARAM) _T(NO_SERIAL)); + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, + _T("Hardware\\DeviceMap\\SerialComm"), + 0, + KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, + &hKey) == ERROR_SUCCESS) + { + HANDLE hComm; + TCHAR szBuffer[256],cKey[256],cData[256]; + DWORD dwKeySize,dwDataSize; + WPARAM wSelIndexWire,wSelIndexIr; + BOOL bAddWire,bAddIr; + DWORD dwType,dwEnumVal; + LONG lRet; + + wSelIndexWire = wSelIndexIr = 1; // preset selector + + dwEnumVal = 0; + do + { + dwKeySize = ARRAYSIZEOF(cKey); // init return buffer sizes + dwDataSize = sizeof(cData); + + lRet = RegEnumValue(hKey,dwEnumVal++, + cKey,&dwKeySize, + NULL,&dwType, + (LPBYTE) cData,&dwDataSize); + + if (lRet == ERROR_SUCCESS && dwType == REG_SZ) + { + wsprintf(szBuffer,_T("\\\\.\\%s"),cData); + if ((bAddWire = (lstrcmp(&szBuffer[4],szWireSetting) == 0))) + wSelectWire = wSelIndexWire; + if ((bAddIr = (lstrcmp(&szBuffer[4],szIrSetting) == 0))) + wSelectIr = wSelIndexIr; + + // test if COM port is valid + hComm = CreateFile(szBuffer,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); + if (hComm != INVALID_HANDLE_VALUE) + { + VERIFY(CloseHandle(hComm)); + bAddWire = bAddIr = TRUE; + } + + if (bAddWire) // add item to wire combobox + { + SendDlgItemMessage(hDlg,IDC_WIRE,CB_ADDSTRING,0,(LPARAM) &szBuffer[4]); + ++wSelIndexWire; + } + if (bAddIr) // add item to ir combobox + { + SendDlgItemMessage(hDlg,IDC_IR,CB_ADDSTRING,0,(LPARAM) &szBuffer[4]); + ++wSelIndexIr; + } + } + } + while (lRet == ERROR_SUCCESS); + _ASSERT(lRet == ERROR_NO_MORE_ITEMS); + RegCloseKey(hKey); + } + + // set cursors + SendDlgItemMessage(hDlg,IDC_WIRE,CB_SETCURSEL,wSelectWire,0L); + SendDlgItemMessage(hDlg,IDC_IR ,CB_SETCURSEL,wSelectIr ,0L); + return; +} + +static INT_PTR CALLBACK SettingsGeneralProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HWND hWndInsertAfter; + + switch (uMsg) + { + case WM_INITDIALOG: + // init speed checkbox + CheckDlgButton(hDlg,IDC_REALSPEED,bRealSpeed); + CheckDlgButton(hDlg,IDC_GRAYSCALE,bGrayscale); + CheckDlgButton(hDlg,IDC_SHOWTITLE,bShowTitle); + CheckDlgButton(hDlg,IDC_SHOWMENU,bShowMenu); + CheckDlgButton(hDlg,IDC_ALWAYSONTOP,bAlwaysOnTop); + CheckDlgButton(hDlg,IDC_ACTFOLLOWSMOUSE,bActFollowsMouse); + #if defined _USRDLL // DLL version + CheckDlgButton(hDlg,IDC_SINGLEINSTANCE,FALSE); + EnableWindow(GetDlgItem(hDlg,IDC_SINGLEINSTANCE),FALSE); + #else + CheckDlgButton(hDlg,IDC_SINGLEINSTANCE,bSingleInstance); + #endif + CheckDlgButton(hDlg,IDC_AUTOSAVE,bAutoSave); + CheckDlgButton(hDlg,IDC_AUTOSAVEONEXIT,bAutoSaveOnExit); + CheckDlgButton(hDlg,IDC_OBJECTLOADWARNING,bLoadObjectWarning); + CheckDlgButton(hDlg,IDC_ALWAYSDISPLOG,bAlwaysDisplayLog); + + // set disassembler mode + CheckDlgButton(hDlg,(disassembler_mode == HP_MNEMONICS) ? IDC_DISASM_HP : IDC_DISASM_CLASS,BST_CHECKED); + return TRUE; + case WM_NOTIFY: + switch (((LPNMHDR) lParam)->code) + { + case PSN_KILLACTIVE: + // get speed checkbox value + bRealSpeed = IsDlgButtonChecked(hDlg,IDC_REALSPEED); + bShowTitle = IsDlgButtonChecked(hDlg,IDC_SHOWTITLE); + bShowMenu = IsDlgButtonChecked(hDlg,IDC_SHOWMENU); + bAlwaysOnTop = IsDlgButtonChecked(hDlg,IDC_ALWAYSONTOP); + bActFollowsMouse = IsDlgButtonChecked(hDlg,IDC_ACTFOLLOWSMOUSE); + bSingleInstance = IsDlgButtonChecked(hDlg,IDC_SINGLEINSTANCE); + bAutoSave = IsDlgButtonChecked(hDlg,IDC_AUTOSAVE); + bAutoSaveOnExit = IsDlgButtonChecked(hDlg,IDC_AUTOSAVEONEXIT); + bLoadObjectWarning = IsDlgButtonChecked(hDlg,IDC_OBJECTLOADWARNING); + bAlwaysDisplayLog = IsDlgButtonChecked(hDlg,IDC_ALWAYSDISPLOG); + SetSpeed(bRealSpeed); // set speed + + // LCD grayscale checkbox has been changed + if (bGrayscale != (BOOL) IsDlgButtonChecked(hDlg,IDC_GRAYSCALE)) + { + UINT nOldState = SwitchToState(SM_INVALID); + SetLcdMode(!bGrayscale); // set new display mode + SwitchToState(nOldState); + } + + // set disassembler mode + disassembler_mode = IsDlgButtonChecked(hDlg,IDC_DISASM_HP) ? HP_MNEMONICS : CLASS_MNEMONICS; + + // bAlwaysOnTop maybe changed, so set new window Z order + hWndInsertAfter = bAlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST; + SetWindowPos(hWnd,hWndInsertAfter,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); + if (hDlgDebug != NULL) + { + SetWindowPos(GetLastActivePopup(hDlgDebug),hWndInsertAfter,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); + } + InvalidateRect(hWnd,NULL,TRUE); + return TRUE; + } + break; + } + return FALSE; + UNREFERENCED_PARAMETER(wParam); +} + +static INT_PTR CALLBACK SettingsMemoryProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LPCTSTR szActPort2Filename = _T(""); + + BOOL bPort2CfgChange = FALSE; + BOOL bPort2AttChange = FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + // HP48SX/GX + if (cCurrentRomType=='S' || cCurrentRomType=='G' || cCurrentRomType==0) + { + // init port1 enable checkbox + CheckDlgButton(hDlg,IDC_PORT1EN,(Chipset.cards_status & PORT1_PRESENT) != 0); + CheckDlgButton(hDlg,IDC_PORT1WR,(Chipset.cards_status & PORT1_WRITE) != 0); + + if (nArgc < 3) // port2 filename from Emu48.ini file + { + szActPort2Filename = szPort2Filename; + } + else // port2 filename given from command line + { + szActPort2Filename = ppArgv[2]; + EnableWindow(GetDlgItem(hDlg,IDC_PORT2),FALSE); + EnableWindow(GetDlgItem(hDlg,IDC_PORT2LOAD),FALSE); + } + + // init port2 shared and writeable checkbox and set port2 filename + CheckDlgButton(hDlg,IDC_PORT2ISSHARED,bPort2IsShared); + CheckDlgButton(hDlg,IDC_PORT2WR,IsFileWriteable(szActPort2Filename)); + SetDlgItemText(hDlg,IDC_PORT2,szActPort2Filename); + if (nState == SM_INVALID) // Invalid State + { + EnableWindow(GetDlgItem(hDlg,IDC_PORT1EN),FALSE); + EnableWindow(GetDlgItem(hDlg,IDC_PORT1WR),FALSE); + } + } + else // HP38G/HP39G/HP40G/HP49G + { + EnableWindow(GetDlgItem(hDlg,IDC_PORT1EN),FALSE); + EnableWindow(GetDlgItem(hDlg,IDC_PORT1WR),FALSE); + EnableWindow(GetDlgItem(hDlg,IDC_PORT2ISSHARED),FALSE); + EnableWindow(GetDlgItem(hDlg,IDC_PORT2WR),FALSE); + EnableWindow(GetDlgItem(hDlg,IDC_PORT2),FALSE); + EnableWindow(GetDlgItem(hDlg,IDC_PORT2LOAD),FALSE); + } + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_PORT2LOAD: + if (GetLoadObjectFilename(_T(BIN_FILTER),_T("BIN"))) + { + TCHAR szFilename[MAX_PATH]; + LPTSTR lpFilePart; + + // check if file path and Emu48 directory path is identical + if (GetFullPathName(szBufferFilename,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart)) + { + *(lpFilePart-1) = 0; // devide path and name + + // name is in the Emu48 directory -> use only name + if (lstrcmpi(szEmuDirectory,szFilename) == 0) + lstrcpy(szBufferFilename,lpFilePart); + } + SetDlgItemText(hDlg,IDC_PORT2,szBufferFilename); + + // adjust R/W checkbox + CheckDlgButton(hDlg,IDC_PORT2WR,IsFileWriteable(szBufferFilename)); + } + return TRUE; + } + break; + case WM_NOTIFY: + switch (((LPNMHDR) lParam)->code) + { + case PSN_KILLACTIVE: + if (Chipset.Port1Size && cCurrentRomType!='X') + { + UINT nOldState = SwitchToState(SM_SLEEP); + // save old card status + BYTE byCardsStatus = Chipset.cards_status; + + // port1 disabled? + Chipset.cards_status &= ~(PORT1_PRESENT | PORT1_WRITE); + if (IsDlgButtonChecked(hDlg, IDC_PORT1EN)) + { + Chipset.cards_status |= PORT1_PRESENT; + if (IsDlgButtonChecked(hDlg, IDC_PORT1WR)) + Chipset.cards_status |= PORT1_WRITE; + } + + // changed card status in slot1? + if ( ((byCardsStatus ^ Chipset.cards_status) & (PORT1_PRESENT | PORT1_WRITE)) != 0 + && (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0 + ) + { + Chipset.HST |= MP; // set Module Pulled + IOBit(SRQ2,NINT,FALSE); // set NINT to low + Chipset.SoftInt = TRUE; // set interrupt + bInterrupt = TRUE; + } + SwitchToState(nOldState); + } + // HP48SX/GX port2 change settings detection + if (cCurrentRomType=='S' || cCurrentRomType=='G' || cCurrentRomType==0) + { + TCHAR szFilename[MAX_PATH]; + BOOL bOldPort2IsShared = bPort2IsShared; + + szActPort2Filename = (nArgc < 3) ? szPort2Filename : ppArgv[2]; + + // shared port + bPort2IsShared = IsDlgButtonChecked(hDlg,IDC_PORT2ISSHARED); + if (bPort2IsShared != bOldPort2IsShared) + { + bPort2CfgChange = TRUE; // slot2 configuration changed + } + + if (nArgc < 3) // port2 filename from Emu48.ini file + { + // get current filename and notify difference + GetDlgItemText(hDlg,IDC_PORT2,szFilename,ARRAYSIZEOF(szFilename)); + if (lstrcmp(szPort2Filename,szFilename) != 0) + { + lstrcpyn(szPort2Filename,szFilename,ARRAYSIZEOF(szPort2Filename)); + bPort2CfgChange = TRUE; // slot2 configuration changed + } + } + + // R/W port + if ( *szActPort2Filename != 0 + && (BOOL) IsDlgButtonChecked(hDlg,IDC_PORT2WR) != IsFileWriteable(szActPort2Filename)) + { + bPort2AttChange = TRUE; // slot2 file R/W attribute changed + bPort2CfgChange = TRUE; // slot2 configuration changed + } + } + + if (bPort2CfgChange) // slot2 configuration changed + { + UINT nOldState = SwitchToState(SM_INVALID); + + UnmapPort2(); // unmap port2 + + if (bPort2AttChange) // slot2 R/W mode changed + { + DWORD dwFileAtt; + + SetCurrentDirectory(szEmuDirectory); + dwFileAtt = GetFileAttributes(szActPort2Filename); + if (dwFileAtt != 0xFFFFFFFF) + { + if (IsDlgButtonChecked(hDlg,IDC_PORT2WR)) + dwFileAtt &= ~FILE_ATTRIBUTE_READONLY; + else + dwFileAtt |= FILE_ATTRIBUTE_READONLY; + + SetFileAttributes(szActPort2Filename,dwFileAtt); + } + SetCurrentDirectory(szCurrentDirectory); + } + + if (cCurrentRomType) // ROM defined + { + MapPort2(szActPort2Filename); + + // port2 changed and card detection enabled + if ( (bPort2AttChange || Chipset.wPort2Crc != wPort2Crc) + && (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0 + ) + { + Chipset.HST |= MP; // set Module Pulled + IOBit(SRQ2,NINT,FALSE); // set NINT to low + Chipset.SoftInt = TRUE; // set interrupt + bInterrupt = TRUE; + } + // save fingerprint of port2 + Chipset.wPort2Crc = wPort2Crc; + } + SwitchToState(nOldState); + } + return TRUE; + } + break; + } + return FALSE; +} + +static INT_PTR CALLBACK SettingsPeripheralProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TCHAR cPort[8]; + LONG i; + UINT uDevId; + + switch (uMsg) + { + case WM_INITDIALOG: + // set sound slider + SendDlgItemMessage(hDlg,IDC_SOUND_SLIDER,TBM_SETRANGE,FALSE,MAKELONG(0,255)); + SendDlgItemMessage(hDlg,IDC_SOUND_SLIDER,TBM_SETTICFREQ,256/8,0); + SendDlgItemMessage(hDlg,IDC_SOUND_SLIDER,TBM_SETPOS,TRUE,dwWaveVol); + + // set sound device + SetSoundDeviceList(GetDlgItem(hDlg,IDC_SOUND_DEVICE),uWaveDevId); + + // UDP infrared printer settings + SetDlgItemText(hDlg,IDC_IR_ADDR,szUdpServer); + wsprintf(cPort,_T("%u"),wUdpPort); + SetDlgItemText(hDlg,IDC_IR_PORT,cPort); + + // set combobox parameter + SetCommList(hDlg,szSerialWire,szSerialIr); + if (CommIsOpen()) // disable when port open + { + EnableWindow(GetDlgItem(hDlg,IDC_WIRE),FALSE); + EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE); + } + + if (cCurrentRomType=='X') // HP49G + { + SendDlgItemMessage(hDlg,IDC_IR,CB_RESETCONTENT,0,0); + EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE); + } + return TRUE; + case WM_NOTIFY: + switch (((LPNMHDR) lParam)->code) + { + case PSN_KILLACTIVE: + // set sound data + dwWaveVol = (DWORD) SendDlgItemMessage(hDlg,IDC_SOUND_SLIDER,TBM_GETPOS,0,0); + i = (LONG) SendDlgItemMessage(hDlg,IDC_SOUND_DEVICE,CB_GETCURSEL,0,0); + uDevId = (UINT) SendDlgItemMessage(hDlg,IDC_SOUND_DEVICE,CB_GETITEMDATA,i,0); + if (uWaveDevId != uDevId) // sound device id changed + { + UINT nActState; + + uWaveDevId = uDevId; // set new sound device id + + nActState = SwitchToState(SM_SLEEP); + + // restart sound engine with new device id + SoundClose(); // close waveform-audio output device + SoundOpen(uWaveDevId); // open waveform-audio output device + + SwitchToState(nActState); + } + // UDP infrared printer settings + GetDlgItemText(hDlg,IDC_IR_ADDR,szUdpServer,ARRAYSIZEOF(szUdpServer)); + GetDlgItemText(hDlg,IDC_IR_PORT,cPort,ARRAYSIZEOF(cPort)); + wUdpPort = (WORD) _ttoi(cPort); + ResetUdp(); // invalidate saved UDP address + // set combobox parameter + GetDlgItemText(hDlg,IDC_WIRE,szSerialWire,ARRAYSIZEOF(szSerialWire)); + if (cCurrentRomType!='X') // HP49G Ir port is not connected + GetDlgItemText(hDlg,IDC_IR,szSerialIr,ARRAYSIZEOF(szSerialIr)); + return TRUE; + } + break; + } + return FALSE; + UNREFERENCED_PARAMETER(wParam); +} + + + +//################ +//# +//# Save Helper +//# +//################ + +// +// UINT SaveChanges(BOOL bAuto); +// Return code : +// IDYES File successfuly saved +// IDNO File not saved +// IDCANCEL Cancel command +// +static UINT SaveChanges(BOOL bAuto) +{ + UINT uReply; + + if (bDocumentAvail == FALSE) return IDNO; + + if (bAuto) + uReply = IDYES; + else + { + UINT uStyle = bSaveDefConfirm ? 0 : MB_DEFBUTTON2; + uReply = YesNoCancelMessage(_T("Do you want to save changes?"),uStyle); + } + + if (uReply != IDYES) return uReply; + + if (szCurrentFilename[0] == 0) + { // Save As... + if (GetSaveAsFilename()) + { + if (SaveDocumentAs(szBufferFilename)) + { + MruAdd(szBufferFilename); + return IDYES; + } + else + return IDCANCEL; + } + return IDNO; + } + + SaveDocument(); + MruAdd(szCurrentFilename); + return IDYES; +} + + + +//################ +//# +//# Message Handlers +//# +//################ + +// +// WM_CREATE +// +static LRESULT OnCreate(HWND hWindow) +{ + InitializeCriticalSection(&csGDILock); + InitializeCriticalSection(&csLcdLock); + InitializeCriticalSection(&csKeyLock); + InitializeCriticalSection(&csIOLock); + InitializeCriticalSection(&csT1Lock); + InitializeCriticalSection(&csT2Lock); + InitializeCriticalSection(&csTxdLock); + InitializeCriticalSection(&csRecvLock); + InitializeCriticalSection(&csSlowLock); + InitializeCriticalSection(&csDbgLock); + + // load cursors + hCursorArrow = LoadCursor(NULL,IDC_ARROW); + hCursorHand = LoadCursor(NULL,IDC_HAND); + if (hCursorHand == NULL) + { + // for Win95, NT4.0 + bOwnCursor = ((hCursorHand = CreateHandCursor()) != NULL); + } + + hWnd = hWindow; + hWindowDC = GetDC(hWnd); + return 0; +} + +// +// WM_DESTROY +// +static LRESULT OnDestroy(HWND hWindow) +{ + DragAcceptFiles(hWnd,FALSE); // no WM_DROPFILES message any more + if (hThread) SwitchToState(SM_RETURN); // exit emulation thread + SetWindowTitle(NULL); // free memory of title + ReleaseDC(hWnd, hWindowDC); + hWindowDC = NULL; // hWindowDC isn't valid any more + hWnd = NULL; + + if (bOwnCursor) // destroy hand cursor + { + DestroyCursor(hCursorHand); + bOwnCursor = FALSE; + } + + DeleteCriticalSection(&csGDILock); + DeleteCriticalSection(&csLcdLock); + DeleteCriticalSection(&csKeyLock); + DeleteCriticalSection(&csIOLock); + DeleteCriticalSection(&csT1Lock); + DeleteCriticalSection(&csT2Lock); + DeleteCriticalSection(&csTxdLock); + DeleteCriticalSection(&csRecvLock); + DeleteCriticalSection(&csSlowLock); + DeleteCriticalSection(&csDbgLock); + + #if defined _USRDLL // DLL version + DLLDestroyWnd(); // cleanup system + #else // EXE version + PostQuitMessage(0); // exit message loop + #endif + return 0; + UNREFERENCED_PARAMETER(hWindow); +} + +// +// WM_PAINT +// +static LRESULT OnPaint(HWND hWindow) +{ + PAINTSTRUCT Paint; + HDC hPaintDC; + + UpdateWindowBars(); // update visibility of title and menu bar + + hPaintDC = BeginPaint(hWindow, &Paint); + if (hMainDC != NULL) + { + RECT rcMainPaint = Paint.rcPaint; + rcMainPaint.left += nBackgroundX; // coordinates in source bitmap + rcMainPaint.top += nBackgroundY; + rcMainPaint.right += nBackgroundX; + rcMainPaint.bottom += nBackgroundY; + + EnterCriticalSection(&csGDILock); // solving NT GDI problems + { + UINT nLines = (Chipset.lcounter == 0) ? 64 : (Chipset.lcounter + 1); + + // redraw background bitmap + BitBlt(hPaintDC, Paint.rcPaint.left, Paint.rcPaint.top, + Paint.rcPaint.right-Paint.rcPaint.left, Paint.rcPaint.bottom-Paint.rcPaint.top, + hMainDC, rcMainPaint.left, rcMainPaint.top, SRCCOPY); + + SetWindowOrgEx(hPaintDC, nBackgroundX, nBackgroundY, NULL); + + // redraw main display area + StretchBlt(hPaintDC, nLcdX, nLcdY, + 131*nLcdZoom*nGdiXZoom, nLines*nLcdZoom*nGdiYZoom, + hLcdDC, Chipset.boffset*nLcdZoom, 0, + 131*nLcdZoom, nLines*nLcdZoom, SRCCOPY); + // redraw menu display area + StretchBlt(hPaintDC, nLcdX, nLcdY+nLines*nLcdZoom*nGdiYZoom, + 131*nLcdZoom*nGdiXZoom, (64-nLines)*nLcdZoom*nGdiYZoom, + hLcdDC, 0, nLines*nLcdZoom, + 131*nLcdZoom, (64-nLines)*nLcdZoom, SRCCOPY); + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + UpdateAnnunciators(0x3F); + RefreshButtons(&rcMainPaint); + } + EndPaint(hWindow, &Paint); + return 0; +} + +// +// WM_INITMENU +// +static LRESULT OnInitMenu(HMENU hMenu) +{ + // disable stack loading items on HP38G, HP39/40G + BOOL bStackEnable = cCurrentRomType!='6' && cCurrentRomType!='A' && cCurrentRomType!='E'; + BOOL bRun = nState == SM_RUN || nState == SM_SLEEP; + + UINT uStackEnable = (bRun && bStackEnable) ? MF_ENABLED : MF_GRAYED; + UINT uRun = bRun ? MF_ENABLED : MF_GRAYED; + UINT uBackup = bBackup ? MF_ENABLED : MF_GRAYED; + + EnableMenuItem(hMenu,ID_FILE_NEW,MF_ENABLED); + EnableMenuItem(hMenu,ID_FILE_OPEN,MF_ENABLED); + EnableMenuItem(hMenu,ID_FILE_SAVE,(bRun && szCurrentFilename[0]) ? MF_ENABLED : MF_GRAYED); + EnableMenuItem(hMenu,ID_FILE_SAVEAS,uRun); + EnableMenuItem(hMenu,ID_FILE_CLOSE,uRun); + EnableMenuItem(hMenu,ID_OBJECT_LOAD,uStackEnable); + EnableMenuItem(hMenu,ID_OBJECT_SAVE,uStackEnable); + EnableMenuItem(hMenu,ID_VIEW_COPY,uRun); + EnableMenuItem(hMenu,ID_STACK_COPY,uStackEnable); + EnableMenuItem(hMenu,ID_STACK_PASTE,uStackEnable); + EnableMenuItem(hMenu,ID_VIEW_RESET,uRun); + EnableMenuItem(hMenu,ID_BACKUP_SAVE,uRun); + EnableMenuItem(hMenu,ID_BACKUP_RESTORE,uBackup); + EnableMenuItem(hMenu,ID_BACKUP_DELETE,uBackup); + EnableMenuItem(hMenu,ID_VIEW_SCRIPT,uRun); + EnableMenuItem(hMenu,ID_TOOL_DISASM,uRun); + EnableMenuItem(hMenu,ID_TOOL_DEBUG,(bRun && nDbgState == DBG_OFF) ? MF_ENABLED : MF_GRAYED); + EnableMenuItem(hMenu,ID_TOOL_MACRO_RECORD,(bRun && nMacroState == MACRO_OFF) ? MF_ENABLED : MF_GRAYED); + EnableMenuItem(hMenu,ID_TOOL_MACRO_PLAY,(bRun && nMacroState == MACRO_OFF) ? MF_ENABLED : MF_GRAYED); + EnableMenuItem(hMenu,ID_TOOL_MACRO_STOP,(bRun && nMacroState != MACRO_OFF) ? MF_ENABLED : MF_GRAYED); + + MruUpdateMenu(hMenu); // update MRU list + return 0; +} + +// +// WM_DROPFILES +// +static LRESULT OnDropFiles(HDROP hFilesInfo) +{ + TCHAR szFileName[MAX_PATH]; + WORD wNumFiles,wIndex; + BOOL bSuccess = FALSE; + + // get number of files dropped + wNumFiles = DragQueryFile (hFilesInfo,(UINT)-1,NULL,0); + + SuspendDebugger(); // suspend debugger + bDbgAutoStateCtrl = FALSE; // disable automatic debugger state control + + // calculator off, turn on + if (!(Chipset.IORam[BITOFFSET]&DON)) + { + // turn on HP + KeyboardEvent(TRUE,0,0x8000); + Sleep(dwWakeupDelay); + KeyboardEvent(FALSE,0,0x8000); + } + + _ASSERT(nState == SM_RUN); // emulator must be in RUN state + if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state + { + DragFinish (hFilesInfo); + InfoMessage(_T("The emulator is busy.")); + goto cancel; + } + + _ASSERT(nState == SM_SLEEP); + + // get each name and load it into the emulator + for (wIndex = 0;wIndex < wNumFiles;++wIndex) + { + DragQueryFile (hFilesInfo,wIndex,szFileName,ARRAYSIZEOF(szFileName)); + + // szFileName has file name, now try loading it + if ((bSuccess = LoadObject(szFileName)) == FALSE) + break; + } + + DragFinish (hFilesInfo); + SwitchToState(SM_RUN); // run state + while (nState!=nNextState) Sleep(0); + _ASSERT(nState == SM_RUN); + + if (bSuccess == FALSE) // data not copied + goto cancel; + + KeyboardEvent(TRUE,0,0x8000); + Sleep(dwWakeupDelay); + KeyboardEvent(FALSE,0,0x8000); + // wait for sleep mode + while (Chipset.Shutdn == FALSE) Sleep(0); + +cancel: + bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control + ResumeDebugger(); + return 0; +} + +// +// ID_FILE_NEW +// +static LRESULT OnFileNew(VOID) +{ + if (bDocumentAvail) + { + SwitchToState(SM_INVALID); + if (IDCANCEL == SaveChanges(bAutoSave)) + goto cancel; + } + if (NewDocument()) SetWindowTitle(_T("Untitled")); +cancel: + if (pbyRom) SwitchToState(SM_RUN); + return 0; +} + +// +// ID_FILE_OPEN +// +static LRESULT OnFileOpen(VOID) +{ + if (bDocumentAvail) + { + SwitchToState(SM_INVALID); + if (IDCANCEL == SaveChanges(bAutoSave)) + goto cancel; + } + if (GetOpenFilename()) + { + if (OpenDocument(szBufferFilename)) + MruAdd(szBufferFilename); + } +cancel: + if (pbyRom) SwitchToState(SM_RUN); + return 0; +} + +// +// ID_FILE_MRU_FILE1 +// +static LRESULT OnFileMruOpen(UINT wID) +{ + TCHAR szFilename[MAX_PATH]; + + wID -= ID_FILE_MRU_FILE1; // zero based MRU index + + // full filename from MRU list + MruFilename(wID,szFilename,ARRAYSIZEOF(szFilename)); + if (*szFilename == 0) return 0; // MRU slot not filled + + if (bDocumentAvail) + { + SwitchToState(SM_INVALID); + // saving may change MRU index and destroy lpszFilename pointer content + if (IDCANCEL == SaveChanges(bAutoSave)) + goto cancel; + } + if (!OpenDocument(szFilename)) // document loading failed + { + wID = MruID(szFilename); // get actual MRU ID after saving + if (wID != (UINT) -1) // entry still in MRU list + { + MruRemove(wID); // entry not valid any more + } + } + else + { + MruAdd(szFilename); // add entry to top of MRU list + } +cancel: + if (pbyRom) SwitchToState(SM_RUN); + return 0; +} + +// +// ID_FILE_SAVE +// +static LRESULT OnFileSave(VOID) +{ + if (bDocumentAvail) + { + SwitchToState(SM_INVALID); + SaveChanges(TRUE); + SwitchToState(SM_RUN); + } + return 0; +} + +// +// ID_FILE_SAVEAS +// +static LRESULT OnFileSaveAs(VOID) +{ + if (bDocumentAvail) + { + SwitchToState(SM_INVALID); + if (GetSaveAsFilename()) + { + if (SaveDocumentAs(szBufferFilename)) + MruAdd(szCurrentFilename); + } + SwitchToState(SM_RUN); + } + return 0; +} + +// +// ID_FILE_CLOSE +// +static LRESULT OnFileClose(VOID) +{ + if (bDocumentAvail) + { + SwitchToState(SM_INVALID); + if (SaveChanges(bAutoSave) != IDCANCEL) + { + ResetDocument(); + SetWindowTitle(NULL); + } + else + { + SwitchToState(SM_RUN); + } + } + return 0; +} + +// +// ID_FILE_EXIT +// +// WM_SYS_CLOSE +// +static LRESULT OnFileExit(VOID) +{ + SwitchToState(SM_INVALID); // hold emulation thread + if (SaveChanges(bAutoSaveOnExit) == IDCANCEL) + { + SwitchToState(SM_RUN); // on cancel restart emulation thread + return 0; + } + DestroyWindow(hWnd); + return 0; +} + +// +// ID_VIEW_COPY +// +static LRESULT OnViewCopy(VOID) +{ + if (OpenClipboard(hWnd)) + { + if (EmptyClipboard()) + { + // DIB bitmap + #define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4) + #define PALVERSION 0x300 + + BITMAP bm; + LPBITMAPINFOHEADER lpbi; + PLOGPALETTE ppal; + HBITMAP hBmp; + HDC hBmpDC; + HANDLE hClipObj; + WORD wBits; + DWORD dwLen, dwSizeImage; + + _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4); + hBmp = CreateCompatibleBitmap(hLcdDC,131*nLcdZoom*nGdiXZoom,64*nLcdZoom*nGdiYZoom); + hBmpDC = CreateCompatibleDC(hLcdDC); + hBmp = (HBITMAP) SelectObject(hBmpDC,hBmp); + EnterCriticalSection(&csGDILock); // solving NT GDI problems + { + UINT nLines = (Chipset.lcounter == 0) ? 64 : (Chipset.lcounter + 1); + + // copy main display area + StretchBlt(hBmpDC, 0, 0, + 131*nLcdZoom*nGdiXZoom, nLines*nLcdZoom*nGdiYZoom, + hLcdDC, Chipset.boffset*nLcdZoom, 0, + 131*nLcdZoom, nLines*nLcdZoom, SRCCOPY); + // copy menu display area + StretchBlt(hBmpDC, 0, nLines*nLcdZoom*nGdiYZoom, + 131*nLcdZoom*nGdiXZoom, (64-nLines)*nLcdZoom*nGdiYZoom, + hLcdDC, 0, nLines*nLcdZoom, + 131*nLcdZoom, (64-nLines)*nLcdZoom, SRCCOPY); + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + hBmp = (HBITMAP) SelectObject(hBmpDC,hBmp); + + // fill BITMAP structure for size information + GetObject(hBmp, sizeof(bm), &bm); + + wBits = bm.bmPlanes * bm.bmBitsPixel; + // make sure bits per pixel is valid + if (wBits <= 1) + wBits = 1; + else if (wBits <= 4) + wBits = 4; + else if (wBits <= 8) + wBits = 8; + else // if greater than 8-bit, force to 24-bit + wBits = 24; + + dwSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * wBits) * bm.bmHeight; + + // calculate memory size to store CF_DIB data + dwLen = sizeof(BITMAPINFOHEADER) + dwSizeImage; + if (wBits != 24) // a 24 bitcount DIB has no color table + { + // add size for color table + dwLen += (DWORD) (1 << wBits) * sizeof(RGBQUAD); + } + + // memory allocation for clipboard data + if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE, dwLen)) != NULL) + { + lpbi = (LPBITMAPINFOHEADER ) GlobalLock(hClipObj); + // initialize BITMAPINFOHEADER + lpbi->biSize = sizeof(BITMAPINFOHEADER); + lpbi->biWidth = bm.bmWidth; + lpbi->biHeight = bm.bmHeight; + lpbi->biPlanes = 1; + lpbi->biBitCount = wBits; + lpbi->biCompression = BI_RGB; + lpbi->biSizeImage = dwSizeImage; + lpbi->biXPelsPerMeter = 0; + lpbi->biYPelsPerMeter = 0; + lpbi->biClrUsed = 0; + lpbi->biClrImportant = 0; + // get bitmap color table and bitmap data + GetDIBits(hBmpDC, hBmp, 0, lpbi->biHeight, (LPBYTE)lpbi + dwLen - dwSizeImage, + (LPBITMAPINFO)lpbi, DIB_RGB_COLORS); + GlobalUnlock(hClipObj); + SetClipboardData(CF_DIB, hClipObj); + + // get number of entries in the logical palette + GetObject(hPalette,sizeof(WORD),&wBits); + + // memory allocation for temporary palette data + if ((ppal = (PLOGPALETTE) calloc(sizeof(LOGPALETTE) + wBits * sizeof(PALETTEENTRY),1)) != NULL) + { + ppal->palVersion = PALVERSION; + ppal->palNumEntries = wBits; + GetPaletteEntries(hPalette, 0, wBits, ppal->palPalEntry); + SetClipboardData(CF_PALETTE, CreatePalette(ppal)); + free(ppal); + } + } + DeleteDC(hBmpDC); + DeleteObject(hBmp); + #undef WIDTHBYTES + #undef PALVERSION + } + CloseClipboard(); + } + return 0; +} + +// +// ID_VIEW_RESET +// +static LRESULT OnViewReset(VOID) +{ + if (nState != SM_RUN) return 0; + if (YesNoMessage(_T("Are you sure you want to press the Reset Button?"))==IDYES) + { + SwitchToState(SM_SLEEP); + CpuReset(); // register setting after Cpu Reset + SwitchToState(SM_RUN); + } + return 0; +} + +// +// ID_VIEW_SETTINGS +// +static INT_PTR CALLBACK PropSheetProc(HWND hwndPropSheet, UINT uMsg, LPARAM lParam) +{ + switch(uMsg) + { + // called before the dialog is created, hwndPropSheet = NULL, lParam points to dialog resource + case PSCB_PRECREATE: + { + LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE) lParam; + if(!(lpTemplate->style & WS_SYSMENU)) + { + lpTemplate->style |= WS_SYSMENU; + } + } + break; + + // called after the dialog is created + case PSCB_INITIALIZED: + break; + } + return 0; + UNREFERENCED_PARAMETER(hwndPropSheet); +} + +static LRESULT OnViewSettings(VOID) +{ + PROPSHEETPAGE psp[3]; + PROPSHEETHEADER psh; + + // not in nState = SM_INVALID or port2 file must be closed from document + _ASSERT(nState != SM_INVALID || pbyPort2 == NULL); + + psp[0].dwSize = sizeof(PROPSHEETPAGE); + psp[0].dwFlags = PSP_DEFAULT; + psp[0].hInstance = hApp; + psp[0].pszTemplate = MAKEINTRESOURCE(IDD_SET_GENERAL); + psp[0].hIcon = NULL; + psp[0].pszTitle = NULL; + psp[0].pfnDlgProc = SettingsGeneralProc; + psp[0].lParam = 0; + psp[0].pfnCallback = NULL; + + psp[1].dwSize = sizeof(PROPSHEETPAGE); + psp[1].dwFlags = PSP_DEFAULT; + psp[1].hInstance = hApp; + psp[1].pszTemplate = MAKEINTRESOURCE(IDD_SET_MEMORY); + psp[1].hIcon = NULL; + psp[1].pszTitle = NULL; + psp[1].pfnDlgProc = SettingsMemoryProc; + psp[1].lParam = 0; + psp[1].pfnCallback = NULL; + + psp[2].dwSize = sizeof(PROPSHEETPAGE); + psp[2].dwFlags = PSP_DEFAULT; + psp[2].hInstance = hApp; + psp[2].pszTemplate = MAKEINTRESOURCE(IDD_SET_PERIPHERAL); + psp[2].hIcon = NULL; + psp[2].pszTitle = NULL; + psp[2].pfnDlgProc = SettingsPeripheralProc; + psp[2].lParam = 0; + psp[2].pfnCallback = NULL; + + psh.dwSize = sizeof(PROPSHEETHEADER); + psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK | PSH_NOAPPLYNOW; + psh.hwndParent = hWnd; + psh.hInstance = hApp; + psh.hIcon = NULL; + psh.pszCaption = _T("Settings"); + psh.nPages = ARRAYSIZEOF(psp); + psh.nStartPage = 0; + psh.ppsp = (LPCPROPSHEETPAGE) &psp; + psh.pfnCallback = (PFNPROPSHEETCALLBACK) PropSheetProc; + + if (PropertySheet(&psh) == -1) + AbortMessage(_T("Settings Property Sheet Creation Error!")); + + WriteSettings(); + return 0; +} + +// +// ID_VIEW_SCRIPT +// +static LRESULT OnViewScript(VOID) +{ + TCHAR szKmlFile[MAX_PATH]; + BOOL bKMLChanged,bSucc; + + BYTE cType = cCurrentRomType; + if (nState != SM_RUN) + { + InfoMessage(_T("You cannot change the KML script when Emu48 is not running.\n") + _T("Use the File,New menu item to create a new calculator.")); + return 0; + } + SwitchToState(SM_INVALID); + + // make a copy of the current KML script file name + _ASSERT(sizeof(szKmlFile) == sizeof(szCurrentKml)); + lstrcpyn(szKmlFile,szCurrentKml,ARRAYSIZEOF(szKmlFile)); + + bKMLChanged = FALSE; // KML script not changed + bSucc = TRUE; // KML script successful loaded + + do + { + if (!DisplayChooseKml(cType)) // quit with Cancel + { + if (!bKMLChanged) // KML script not changed + break; // exit loop with current loaded KML script + + // restore KML script file name + lstrcpyn(szCurrentKml,szKmlFile,ARRAYSIZEOF(szCurrentKml)); + + // try to restore old KML script + if ((bSucc = InitKML(szCurrentKml,FALSE))) + break; // exit loop with success + + // restoring failed, save document + if (IDCANCEL != SaveChanges(bAutoSave)) + break; // exit loop with no success + + _ASSERT(bSucc == FALSE); // for continuing loop + } + else // quit with Ok + { + bKMLChanged = TRUE; // KML script changed + bSucc = InitKML(szCurrentKml,FALSE); + } + } + while (!bSucc); // retry if KML script is invalid + + if (bSucc) + { + if (Chipset.wRomCrc != wRomCrc) // ROM changed + { + CpuReset(); + Chipset.Shutdn = FALSE; // automatic restart + + Chipset.wRomCrc = wRomCrc; // update current ROM fingerprint + } + if (pbyRom) SwitchToState(SM_RUN); // continue emulation + } + else + { + ResetDocument(); // close document + SetWindowTitle(NULL); + } + return 0; +} + +// +// ID_BACKUP_SAVE +// +static LRESULT OnBackupSave(VOID) +{ + UINT nOldState; + if (pbyRom == NULL) return 0; + nOldState = SwitchToState(SM_INVALID); + SaveBackup(); + SwitchToState(nOldState); + return 0; +} + +// +// ID_BACKUP_RESTORE +// +static LRESULT OnBackupRestore(VOID) +{ + SwitchToState(SM_INVALID); + RestoreBackup(); + if (pbyRom) SwitchToState(SM_RUN); + return 0; +} + +// +// ID_BACKUP_DELETE +// +static LRESULT OnBackupDelete(VOID) +{ + ResetBackup(); + return 0; +} + +// +// ID_OBJECT_LOAD +// +static LRESULT OnObjectLoad(VOID) +{ + SuspendDebugger(); // suspend debugger + bDbgAutoStateCtrl = FALSE; // disable automatic debugger state control + + // calculator off, turn on + if (!(Chipset.IORam[BITOFFSET]&DON)) + { + KeyboardEvent(TRUE,0,0x8000); + Sleep(dwWakeupDelay); + KeyboardEvent(FALSE,0,0x8000); + + // wait for sleep mode + while (Chipset.Shutdn == FALSE) Sleep(0); + } + + if (nState != SM_RUN) + { + InfoMessage(_T("The emulator must be running to load an object.")); + goto cancel; + } + + if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state + { + InfoMessage(_T("The emulator is busy.")); + goto cancel; + } + + _ASSERT(nState == SM_SLEEP); + + if (bLoadObjectWarning) + { + UINT uReply = YesNoCancelMessage( + _T("Warning: Trying to load an object while the emulator is busy\n") + _T("will certainly result in a memory lost. Before loading an object\n") + _T("you should be sure that the calculator is in idle state.\n") + _T("Do you want to see this warning next time you try to load an object?"),0); + switch (uReply) + { + case IDYES: + break; + case IDNO: + bLoadObjectWarning = FALSE; + break; + case IDCANCEL: + SwitchToState(SM_RUN); + goto cancel; + } + } + + if (!GetLoadObjectFilename(_T(HP_FILTER),_T("HP"))) + { + SwitchToState(SM_RUN); + goto cancel; + } + + if (!LoadObject(szBufferFilename)) + { + SwitchToState(SM_RUN); + goto cancel; + } + + SwitchToState(SM_RUN); // run state + while (nState!=nNextState) Sleep(0); + _ASSERT(nState == SM_RUN); + KeyboardEvent(TRUE,0,0x8000); + Sleep(dwWakeupDelay); + KeyboardEvent(FALSE,0,0x8000); + while (Chipset.Shutdn == FALSE) Sleep(0); + +cancel: + bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control + ResumeDebugger(); + return 0; +} + +// +// ID_OBJECT_SAVE +// +static LRESULT OnObjectSave(VOID) +{ + if (nState != SM_RUN) + { + InfoMessage(_T("The emulator must be running to save an object.")); + return 0; + } + + if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state + { + InfoMessage(_T("The emulator is busy.")); + return 0; + } + + _ASSERT(nState == SM_SLEEP); + + if (GetSaveObjectFilename(_T(HP_FILTER),_T("HP"))) + { + SaveObject(szBufferFilename); + } + + SwitchToState(SM_RUN); + return 0; +} + +// +// ID_TOOL_DISASM +// +static INT_PTR CALLBACK Disasm(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + static DWORD dwAddress,dwAddressMax; + + enum MEM_MAPPING eMode; + LONG i; + DWORD dwNxtAddr; + TCHAR szAddress[256] = _T("0"); + + switch (message) + { + case WM_INITDIALOG: + VERIFY(SetMemRomType(cCurrentRomType)); // set current model + + // set fonts & cursor + SendDlgItemMessage(hDlg,IDC_DISASM_MODULE,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_DISASM_MODE_TEXT,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_DISASM_MODE,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_ADDRESS,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_DISASM_ADR,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_DISASM_NEXT,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDC_DISASM_COPY,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDCANCEL,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + + // fill disassembler mode combo box + { + // disassemble mode window + HWND hWnd = GetDlgItem(hDlg,IDC_DISASM_MODE); + + if (hDlgDebug == NULL) // debugger not open + { + LPCTSTR lpszModes[] = { _T("Map"), _T("NCE1"), _T("NCE2"), _T("CE1"), _T("CE2"), _T("NCE3") }; + + for (eMode = MEM_MMU; eMode <= MEM_NCE3; eMode = (enum MEM_MAPPING) (eMode + 1)) + { + if (GetMemAvail(eMode)) + { + _ASSERT(eMode < ARRAYSIZEOF(lpszModes)); + i = (LONG) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) lpszModes[eMode]); + SendMessage(hWnd,CB_SETITEMDATA,i,(LPARAM) eMode); + } + } + VERIFY(SendMessage(hWnd,CB_SETCURSEL,0,0) != LB_ERR); + + // disassemble with mapped modules + VERIFY(SetMemMapType(MEM_MMU)); + } + else // debugger open + { + EnableWindow(hWnd,FALSE); + } + } + + SetDlgItemText(hDlg,IDC_DISASM_ADR,szAddress); + dwAddressMax = GetMemDataSize(); + dwAddress = _tcstoul(szAddress,NULL,16); + return TRUE; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + // decode memory mode combo box + case IDC_DISASM_MODE: + // new combo box item selected + if (HIWORD(wParam) == CBN_SELENDOK) + { + HWND hWnd = GetDlgItem(hDlg,IDC_DISASM_MODE); + i = (LONG) SendMessage(hWnd,CB_GETCURSEL,0,0); + eMode = (enum MEM_MAPPING) SendMessage(hWnd,CB_GETITEMDATA,i,0); + VERIFY(SetMemMapType(eMode)); + dwAddressMax = GetMemDataSize(); + } + break; + case IDOK: + SendDlgItemMessage(hDlg,IDC_DISASM_ADR,EM_SETSEL,0,-1); + GetDlgItemText(hDlg,IDC_DISASM_ADR,szAddress,ARRAYSIZEOF(szAddress)); + // test if valid hex address + for (i = 0; i < (LONG) lstrlen(szAddress); ++i) + { + if (_istxdigit(szAddress[i]) == FALSE) + return FALSE; + } + dwAddress = _tcstoul(szAddress,NULL,16); + // no break + case IDC_DISASM_NEXT: + if (dwAddress >= dwAddressMax) + return FALSE; + i = wsprintf(szAddress,(dwAddress <= 0xFFFFF) ? _T("%05lX ") : _T("%06lX "),dwAddress); + // check if address content is a PCO (Primitive Code Object) + dwNxtAddr = (dwAddress + 5) & 0xFFFFF; + if (Read5(dwAddress) == dwNxtAddr) + { + if (disassembler_mode == HP_MNEMONICS) + { + _tcscat(&szAddress[i],_T("CON(5) (*)+5")); + } + else + { + wsprintf(&szAddress[i],_T("dcr.5 $%05x"),dwNxtAddr); + } + dwAddress = dwNxtAddr; + } + else + { + dwAddress = disassemble(dwAddress,&szAddress[i]); + } + i = (LONG) SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_ADDSTRING,0,(LPARAM) szAddress); + SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_SELITEMRANGE,FALSE,MAKELPARAM(0,i)); + SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_SETSEL,TRUE,i); + SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_SETTOPINDEX,i,0); + return TRUE; + case IDC_DISASM_COPY: + // copy selected items to clipboard + CopyItemsToClipboard(GetDlgItem(hDlg,IDC_DISASM_WIN)); + return TRUE; + case IDCANCEL: + EndDialog(hDlg,IDCANCEL); + return TRUE; + } + break; + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +// +// ID_ABOUT +// +static INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + SetDlgItemText(hDlg,IDC_VERSION,szNoTitle); + SetDlgItemText(hDlg,IDC_LICENSE,szLicence); + return TRUE; + case WM_COMMAND: + wParam = LOWORD(wParam); + if ((wParam==IDOK)||(wParam==IDCANCEL)) + { + EndDialog(hDlg, wParam); + return TRUE; + } + break; + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +static LRESULT OnToolDisasm(VOID) // disasm dialogbox call +{ + if (pbyRom) SwitchToState(SM_SLEEP); + if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DISASM), hWnd, (DLGPROC)Disasm) == -1) + AbortMessage(_T("Disassembler Dialog Box Creation Error!")); + if (pbyRom) SwitchToState(SM_RUN); + return 0; +} + +static LRESULT OnTopics(VOID) +{ + ShellExecute(hWnd,_T("open"),_T("Emu48.htm"),NULL,szEmuDirectory,SW_SHOWNORMAL); + return 0; +} + +static LRESULT OnAbout(VOID) +{ + if (DialogBox(hApp, MAKEINTRESOURCE(IDD_ABOUT), hWnd, (DLGPROC)About) == -1) + AbortMessage(_T("About Dialog Box Creation Error!")); + return 0; +} + +static VOID OnContextMenu(LPARAM lParam) +{ + if (GetMenu(hWnd) == NULL) // no main window menu + { + BOOL bContextMenu = TRUE; // call context menu + POINT pt; + + POINTSTOPOINT(pt,MAKEPOINTS(lParam)); // mouse position + + if (pt.x == -1 && pt.y == -1) // VK_APPS + { + RECT rc; + + GetCursorPos(&pt); // get current mouse position + GetWindowRect(hWnd,&rc); // get position of active window + if (PtInRect(&rc,pt)==FALSE) // mouse position outside active window + { + pt.x = 15; // open context help at client position 15,15 + pt.y = 15; + VERIFY(ClientToScreen(hWnd,&pt)); + } + } + else // got a mouse position + { + POINT ptc = pt; + // convert mouse into client position + VERIFY(ScreenToClient(hWnd,&ptc)); + + // in client area not over a button + bContextMenu = (ptc.y >= 0 && !MouseIsButton(ptc.x,ptc.y)); + } + + if (bContextMenu) // call the context menu + { + HMENU hMenu; + + // load the popup menu resource + if ((hMenu = LoadMenu(hApp,MAKEINTRESOURCE(IDM_MENU))) != NULL) + { + // display the popup menu + TrackPopupMenu(GetSubMenu(hMenu,0), + TPM_LEFTALIGN | TPM_LEFTBUTTON, + pt.x, pt.y, 0, hWnd, NULL); + + DestroyMenu(hMenu); // destroy the menu + } + } + } + return; +} + +static LRESULT OnLButtonDown(UINT nFlags, WORD x, WORD y) +{ + if (nMacroState == MACRO_PLAY) return 0; // playing macro + if (nState == SM_RUN) MouseButtonDownAt(nFlags, x,y); + + bMouseButton = MouseIsButton(x,y); // mouse is over button hit area + + // no title bar or window movement over client enabled and hit area not over a button + if ((!bTitleBar || bClientWinMove) && nFlags == MK_LBUTTON && !bMouseButton) + { + // move window while holding the left mouse button + PostMessage(hWnd,WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(x,y)); + } + return 0; +} + +static LRESULT OnLButtonUp(UINT nFlags, WORD x, WORD y) +{ + if (nMacroState == MACRO_PLAY) return 0; // playing macro + if (nState == SM_RUN) MouseButtonUpAt(nFlags, x,y); + bMouseButton = FALSE; + return 0; +} + +static LRESULT OnMouseMove(UINT nFlags, WORD x, WORD y) +{ + // emulator not active but cursor is over emulator window + if (bActFollowsMouse && GetActiveWindow() != hWnd) + { + ForceForegroundWindow(hWnd); // force emulator window to foreground + } + + if (nMacroState == MACRO_PLAY) return 0; // playing macro + if (nState == SM_RUN) MouseMovesTo(nFlags, x,y); + return 0; +} + +static LRESULT OnNcMouseMove(UINT nFlags, WORD x, WORD y) +{ + // emulator not active but cursor is over emulator window + if (bActFollowsMouse && GetActiveWindow() != hWnd) + { + ForceForegroundWindow(hWnd); // force emulator window to foreground + } + return 0; + UNREFERENCED_PARAMETER(nFlags); + UNREFERENCED_PARAMETER(x); + UNREFERENCED_PARAMETER(y); +} + +static LRESULT OnKeyDown(int nVirtKey, LPARAM lKeyData) +{ + if (nMacroState == MACRO_PLAY) return 0; // playing macro + // call RunKey() only once (suppress autorepeat feature) + if (nState == SM_RUN && (lKeyData & 0x40000000) == 0) + RunKey((BYTE)nVirtKey, TRUE); + bMouseButton = FALSE; + return 0; +} + +static LRESULT OnKeyUp(int nVirtKey, LPARAM lKeyData) +{ + if (nMacroState == MACRO_PLAY) return 0; // playing macro + if (nState == SM_RUN) RunKey((BYTE)nVirtKey, FALSE); + return 0; + UNREFERENCED_PARAMETER(lKeyData); +} + +static LRESULT OnCopyData(PCOPYDATASTRUCT psCDS) +{ + switch (psCDS->dwData) + { + case CDID_FILENAME: + // current instance has document loaded and got a wide-character file name + if (bDocumentAvail && psCDS->cbData > 0 && psCDS->lpData != NULL) + { + TCHAR szActFilename[MAX_PATH]; + LPTSTR lpFilePart; // address of file name in path + + #if defined _UNICODE + { + // get full path file name for requested state file + GetFullPathName((LPCTSTR) psCDS->lpData,ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart); + } + #else + { + CHAR szAscFilename[MAX_PATH]; + + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, + (LPCWSTR) psCDS->lpData, -1, + szAscFilename, ARRAYSIZEOF(szAscFilename), NULL, NULL); + + // get full path file name for requested state file + GetFullPathName(szAscFilename,ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart); + } + #endif + + // get full path file name for actual state file + GetFullPathName(szCurrentFilename,ARRAYSIZEOF(szActFilename),szActFilename,&lpFilePart); + + // check if both file names are unequal + if (lstrcmpi(szBufferFilename,szActFilename) != 0) + { + UINT nCurState; + + if (pbyRom) + { + nCurState = SwitchToState(SM_INVALID); + if (IDCANCEL == SaveChanges(bAutoSave)) + goto cancel; + } + if (OpenDocument(szBufferFilename)) // open new file + { + MruAdd(szBufferFilename); + } +cancel: + if (pbyRom) SwitchToState(nCurState); + } + } + break; + default: + return FALSE; // message not processed + } + return TRUE; // message processed +} + +LRESULT CALLBACK MainWndProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: return OnCreate(hWindow); + case WM_DESTROY: return OnDestroy(hWindow); + case WM_PAINT: return OnPaint(hWindow); + case WM_INITMENU: return OnInitMenu((HMENU) wParam); + case WM_DROPFILES: return OnDropFiles((HDROP) wParam); + case WM_ACTIVATE: + if (LOWORD(wParam)==WA_INACTIVE) break; + case WM_QUERYNEWPALETTE: + if (hPalette) + { + SelectPalette(hWindowDC, hPalette, FALSE); + if (RealizePalette(hWindowDC)) + { + InvalidateRect(hWindow,NULL,TRUE); + return TRUE; + } + } + return FALSE; + case WM_PALETTECHANGED: + if ((HWND)wParam == hWindow) break; + if (hPalette) + { + SelectPalette(hWindowDC, hPalette, FALSE); + if (RealizePalette(hWindowDC)) + { + // UpdateColors(hWindowDC); + InvalidateRect(hWindow,NULL,TRUE); + } + } + return FALSE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case ID_FILE_NEW: return OnFileNew(); + case ID_FILE_OPEN: return OnFileOpen(); + case ID_FILE_SAVE: return OnFileSave(); + case ID_FILE_SAVEAS: return OnFileSaveAs(); + case ID_FILE_CLOSE: return OnFileClose(); + case ID_FILE_EXIT: return OnFileExit(); + case ID_STACK_COPY: return OnStackCopy(); + case ID_STACK_PASTE: return OnStackPaste(); + case ID_VIEW_COPY: return OnViewCopy(); + case ID_VIEW_RESET: return OnViewReset(); + case ID_VIEW_SETTINGS: return OnViewSettings(); + case ID_VIEW_SCRIPT: return OnViewScript(); + case ID_BACKUP_SAVE: return OnBackupSave(); + case ID_BACKUP_RESTORE: return OnBackupRestore(); + case ID_BACKUP_DELETE: return OnBackupDelete(); + case ID_OBJECT_LOAD: return OnObjectLoad(); + case ID_OBJECT_SAVE: return OnObjectSave(); + case ID_TOOL_DISASM: return OnToolDisasm(); + case ID_TOOL_DEBUG: return OnToolDebug(); + case ID_TOOL_MACRO_RECORD: return OnToolMacroNew(); + case ID_TOOL_MACRO_PLAY: return OnToolMacroPlay(); + case ID_TOOL_MACRO_STOP: return OnToolMacroStop(); + case ID_TOOL_MACRO_SETTINGS: return OnToolMacroSettings(); + case ID_HELP_TOPICS: return OnTopics(); + case ID_ABOUT: return OnAbout(); + } + // check if command ID belongs to MRU file area + if ( (LOWORD(wParam) >= ID_FILE_MRU_FILE1) + && (LOWORD(wParam) < ID_FILE_MRU_FILE1 + MruEntries())) + return OnFileMruOpen(LOWORD(wParam)); + break; + case WM_SYSCOMMAND: + switch (wParam & 0xFFF0) + { + case SC_CLOSE: return OnFileExit(); + } + break; + case WM_ENDSESSION: + // session will end and any auto saving is enabled + if (wParam == TRUE && (bAutoSave || bAutoSaveOnExit)) + { + SwitchToState(SM_INVALID); // hold emulation thread + if (szCurrentFilename[0] != 0) // has current filename + SaveDocument(); + SwitchToState(SM_RUN); // on cancel restart emulation thread + } + break; + case WM_CONTEXTMENU: + if (!bMouseButton) OnContextMenu(lParam); + break; + case WM_RBUTTONDOWN: + case WM_LBUTTONDOWN: return OnLButtonDown((UINT) wParam, LOWORD(lParam), HIWORD(lParam)); + case WM_LBUTTONUP: return OnLButtonUp((UINT) wParam, LOWORD(lParam), HIWORD(lParam)); + case WM_MOUSEMOVE: return OnMouseMove((UINT) wParam, LOWORD(lParam), HIWORD(lParam)); + case WM_NCMOUSEMOVE: return OnNcMouseMove((UINT) wParam, LOWORD(lParam), HIWORD(lParam)); + case WM_KEYUP: return OnKeyUp((int) wParam, lParam); + case WM_KEYDOWN: return OnKeyDown((int) wParam, lParam); + #if !defined _USRDLL // not in DLL version + case WM_COPYDATA: return OnCopyData((PCOPYDATASTRUCT) lParam); + #endif + } + return DefWindowProc(hWindow, uMsg, wParam, lParam); +} + +int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) +{ + MSG msg; + WNDCLASS wc; + ATOM classAtom; + WSADATA wsd; + RECT rectWindow; + HACCEL hAccel; + DWORD dwThreadId; + DWORD dwProcessor; + HSZ hszService, hszTopic; // variables for DDE server + LPTSTR lpFilePart; + + // module handle to kernel32 + const HMODULE hmKernel32 = GetModuleHandle(_T("kernel32")); + + // enable memory leak detection + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + + hApp = hInst; + nArgc = __argc; // no. of command line arguments + ppArgv = (LPCTSTR *) __targv; // command line arguments + + wc.style = CS_BYTEALIGNCLIENT; + wc.lpfnWndProc = (WNDPROC)MainWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInst; + wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_EMU48)); + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU); + wc.lpszClassName = _T("CEmu48"); + + if (!(classAtom = RegisterClass(&wc))) + { + AbortMessage( + _T("CEmu48 class registration failed.\n") + _T("This application will now terminate.")); + return FALSE; + } + + // read emulator settings + GetCurrentDirectory(ARRAYSIZEOF(szCurrentDirectory),szCurrentDirectory); + ReadSettings(); + + // running an instance of me? + if (bSingleInstance && (hWnd = FindWindow(MAKEINTATOM(classAtom),NULL)) != NULL) + { + COPYDATASTRUCT sCDS; + + if (IsIconic(hWnd)) // window minimized + ShowWindow(hWnd,SW_RESTORE); // show window + + // put the window into foreground + ForceForegroundWindow(GetLastActivePopup(hWnd)); + + if (nArgc >= 2) // use decoded parameter line + { + LPTSTR lpFilePart; // address of file name in path + DWORD dwLength; // file name length + + // get full path file name + GetFullPathName(ppArgv[1],ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart); + + // size of file name incl. EOS + dwLength = lstrlen(szBufferFilename) + 1; + sCDS.cbData = dwLength * sizeof(WCHAR); + + #if defined _UNICODE + { + sCDS.lpData = szBufferFilename; + } + #else + { + sCDS.lpData = _alloca(sCDS.cbData); + if (sCDS.lpData != NULL) + { + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szBufferFilename, dwLength, + (LPWSTR) sCDS.lpData, sCDS.cbData); + } + else + { + sCDS.cbData = 0; // size of file name + } + } + #endif + } + else + { + sCDS.lpData = NULL; // file name + sCDS.cbData = 0; // size of file name + } + + // fill the COPYDATA structure and send file name to other instance + sCDS.dwData = CDID_FILENAME; // function identifier + SendMessage(hWnd,WM_COPYDATA,(WPARAM) NULL,(LPARAM) &sCDS); + return 0; // quit program + } + + // disable TIMER_RESOLUTION throttling for Windows 11 and later + { + typedef const BOOL(WINAPI* LPFN_SPI)(HANDLE hProcess,INT ProcessInformationClass,LPVOID ProcessInformation,DWORD ProcessInformationSize); + + // SetProcessInformation() is available since Windows 8, PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION since Windows 11 + LPFN_SPI fnSetProcessInformation = (LPFN_SPI) GetProcAddress(hmKernel32, "SetProcessInformation"); + + if (fnSetProcessInformation != NULL) // running on Windows 8 or later + { + PROCESS_POWER_THROTTLING_STATE Ppts; + + ZeroMemory(&Ppts,sizeof(Ppts)); + Ppts.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION; + Ppts.ControlMask = PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION; + + // don't check for success, success only on Windoes 11 and later + fnSetProcessInformation(GetCurrentProcess(),ProcessPowerThrottling,&Ppts,sizeof(Ppts)); + } + } + + // Create window + rectWindow.left = 0; + rectWindow.top = 0; + rectWindow.right = 256; + rectWindow.bottom = 0; + AdjustWindowRect(&rectWindow, STYLE_TITLE, TRUE); + + hWnd = CreateWindow(MAKEINTATOM(classAtom),_T("Emu48"), + STYLE_TITLE, + CW_USEDEFAULT, CW_USEDEFAULT, + rectWindow.right - rectWindow.left, + rectWindow.bottom - rectWindow.top, + NULL,NULL,hApp,NULL); + + if (hWnd == NULL) + { + AbortMessage(_T("Window creation failed.")); + return FALSE; + } + + VERIFY(hAccel = LoadAccelerators(hInst, MAKEINTRESOURCE(IDR_MENU))); + + // initialization + QueryPerformanceFrequency(&lFreq); // init high resolution counter + QueryPerformanceCounter(&lAppStart); + + szCurrentKml[0] = 0; // no KML file selected + SetSpeed(bRealSpeed); // set speed + MruInit(4); // init MRU entries + + // create auto event handle + hEventShutdn = CreateEvent(NULL,FALSE,FALSE,NULL); + if (hEventShutdn == NULL) + { + AbortMessage(_T("Event creation failed.")); + DestroyWindow(hWnd); + return FALSE; + } + + nState = SM_RUN; // init state must be <> nNextState + nNextState = SM_INVALID; // go into invalid state + hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&WorkerThread, NULL, CREATE_SUSPENDED, &dwThreadId); + if (hThread == NULL) + { + CloseHandle(hEventShutdn); // close event handle + AbortMessage(_T("Thread creation failed.")); + DestroyWindow(hWnd); + return FALSE; + } + + // get processor for Saturn CPU thread + { + // GetCurrentProcessorNumber() is available since Windows Vista + typedef const DWORD (WINAPI *LPFN_GCPN)(VOID); + LPFN_GCPN fnGetCurrentProcessorNumber = (LPFN_GCPN) GetProcAddress(hmKernel32,"GetCurrentProcessorNumber"); + + if (fnGetCurrentProcessorNumber != NULL) // running on Vista or later + { + dwProcessor = fnGetCurrentProcessorNumber(); // get current processor number + } + else + { + // SetThreadIdealProcessor() is available since Windows NT4.0 + typedef const DWORD (WINAPI *LPFN_STIP)(HANDLE hThread,DWORD dwIdealProcessor); + LPFN_STIP fnSetThreadIdealProcessor = (LPFN_STIP) GetProcAddress(hmKernel32,"SetThreadIdealProcessor"); + + dwProcessor = (fnSetThreadIdealProcessor != NULL) // running on NT4.0 or later + ? fnSetThreadIdealProcessor(hThread,MAXIMUM_PROCESSORS) // get ideal processor no. + : 0; // select 1st processor + } + } + + // bind Saturn CPU emulation thread to selected processor + // on multiprocessor machines for QueryPerformanceCounter() + VERIFY(SetThreadAffinityMask(hThread,(DWORD_PTR) (1 << dwProcessor))); + ResumeThread(hThread); // start thread + while (nState!=nNextState) Sleep(0); // wait for thread initialized + + idDdeInst = 0; // initialize DDE server + if (DdeInitialize(&idDdeInst,(PFNCALLBACK) &DdeCallback, + APPCLASS_STANDARD | + CBF_FAIL_EXECUTES | CBF_FAIL_ADVISES | + CBF_SKIP_REGISTRATIONS | CBF_SKIP_UNREGISTRATIONS,0)) + { + TerminateThread(hThread, 0); // kill emulation thread + CloseHandle(hEventShutdn); // close event handle + AbortMessage(_T("Could not initialize server!")); + DestroyWindow(hWnd); + return FALSE; + } + + // init clipboard format and name service + uCF_HpObj = RegisterClipboardFormat(_T(CF_HPOBJ)); + hszService = DdeCreateStringHandle(idDdeInst,szAppName,0); + hszTopic = DdeCreateStringHandle(idDdeInst,szTopic,0); + DdeNameService(idDdeInst,hszService,NULL,DNS_REGISTER); + + SoundOpen(uWaveDevId); // open waveform-audio output device + + _ASSERT(hWnd != NULL); + _ASSERT(hWindowDC != NULL); + + if (nArgc >= 2) // use decoded parameter line + lstrcpyn(szBufferFilename,ppArgv[1],ARRAYSIZEOF(szBufferFilename)); + else // use last document setting + ReadLastDocument(szBufferFilename, ARRAYSIZEOF(szBufferFilename)); + + if (szBufferFilename[0]) // given default document + { + TCHAR szTemp[MAX_PATH+8] = _T("Loading "); + RECT rectClient; + + _ASSERT(hWnd != NULL); + VERIFY(GetClientRect(hWnd,&rectClient)); + GetCutPathName(szBufferFilename,&szTemp[8],MAX_PATH,rectClient.right/11); + SetWindowTitle(szTemp); + if (OpenDocument(szBufferFilename)) + { + MruAdd(szCurrentFilename); + ShowWindow(hWnd,nCmdShow); + goto start; + } + } + + SetWindowTitle(_T("New Document")); + ShowWindow(hWnd,nCmdShow); // show emulator menu + + // no default document, ask for new one + if (NewDocument()) SetWindowTitle(_T("Untitled")); + +start: + VERIFY(WSAStartup(MAKEWORD(1,1),&wsd) == 0); + + if (bStartupBackup) SaveBackup(); // make a RAM backup at startup + if (pbyRom) SwitchToState(SM_RUN); + + while (GetMessage(&msg, NULL, 0, 0)) + { + if ( !TranslateAccelerator(hWnd, hAccel, &msg) + && (hDlgDebug == NULL || !IsDialogMessage(hDlgDebug, &msg)) + && (hDlgFind == NULL || !IsDialogMessage(hDlgFind, &msg)) + && (hDlgProfile == NULL || !IsDialogMessage(hDlgProfile, &msg)) + && (hDlgRplObjView == NULL || !IsDialogMessage(hDlgRplObjView, &msg))) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + WSACleanup(); // cleanup network stack + + // clean up DDE server + DdeNameService(idDdeInst, hszService, NULL, DNS_UNREGISTER); + DdeFreeStringHandle(idDdeInst, hszService); + DdeFreeStringHandle(idDdeInst, hszTopic); + DdeUninitialize(idDdeInst); + + SoundClose(); // close waveform-audio output device + + // get full path name of szCurrentFilename + if (GetFullPathName(szCurrentFilename,ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart) == 0) + szBufferFilename[0] = 0; // no last document name + + WriteLastDocument(szBufferFilename); // save last document setting + WriteSettings(); // save emulation settings + + CloseHandle(hThread); // close thread handle + CloseHandle(hEventShutdn); // close event handle + _ASSERT(nState == SM_RETURN); // emulation thread down? + ResetDocument(); + ResetBackup(); + MruCleanup(); + _ASSERT(pbyRom == NULL); // rom file unmapped + _ASSERT(pbyPort2 == NULL); // port2 file unmapped + _ASSERT(pKml == NULL); // KML script not closed + _ASSERT(szTitle == NULL); // freed allocated memory + _ASSERT(hPalette == NULL); // freed resource memory + + return (int) msg.wParam; + UNREFERENCED_PARAMETER(lpCmdLine); + UNREFERENCED_PARAMETER(hPrevInst); +} diff --git a/Sources/Emu48/emu48.h b/Sources/Emu48/EMU48.H similarity index 96% rename from Sources/Emu48/emu48.h rename to Sources/Emu48/EMU48.H index 5118176..a946e62 100644 --- a/Sources/Emu48/emu48.h +++ b/Sources/Emu48/EMU48.H @@ -1,454 +1,455 @@ -/* - * emu48.h - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ -#include "types.h" - -#define _KB(a) ((a)*2*1024) - -#define HARDWARE "Yorke" // emulator hardware -#define MODELS "6AEGSX" // valid calculator models - -#define ARRAYSIZEOF(a) (sizeof(a) / sizeof(a[0])) - -// cards status -#define PORT1_PRESENT ((cCurrentRomType=='S')?P1C:P2C) -#define PORT1_WRITE ((cCurrentRomType=='S')?P1W:P2W) -#define PORT2_PRESENT ((cCurrentRomType=='S')?P2C:P1C) -#define PORT2_WRITE ((cCurrentRomType=='S')?P2W:P1W) - -#define BINARYHEADER48 "HPHP48-W" -#define BINARYHEADER49 "HPHP49-W" - -#define BIN_FILTER "Port Data File (*.BIN)\0*.BIN\0All Files (*.*)\0*.*\0" -#define HP_FILTER "HP Binary Object (*.HP;*.LIB)\0*.HP;*.LIB\0All Files (*.*)\0*.*\0" - -#define CF_HPOBJ "CF_HPOBJ" // clipboard format for DDE - -// CPU cycles in 16384 Hz time frame -#define T2CYCLES ((cCurrentRomType=='S')?dwSXCycles:dwGXCycles) - -#define SM_RUN 0 // states of cpu emulation thread -#define SM_INVALID 1 -#define SM_RETURN 2 -#define SM_SLEEP 3 - -#define S_ERR_NO 0 // stack errorcodes -#define S_ERR_OBJECT 1 -#define S_ERR_BINARY 2 -#define S_ERR_ASCII 3 - -#define BAD_OB (0xFFFFFFFF) // bad object - -#define NO_SERIAL "disabled" // port not open - -#define HP_MNEMONICS FALSE // disassembler mnenomics mode -#define CLASS_MNEMONICS TRUE - -#define MACRO_OFF 0 // macro recorder off -#define MACRO_NEW 1 -#define MACRO_PLAY 2 - -#define DISP_POINTER 0x01 // defines for display area -#define DISP_MAIN 0x02 -#define DISP_MENUE 0x04 - -#define ROMPAGESIZE (1<<12) // ROM dirty page size in nibbles - -// window styles -#define STYLE_TITLE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED) -#define STYLE_NOTITLE (WS_POPUP|WS_SYSMENU|WS_MINIMIZEBOX|WS_CLIPSIBLINGS) - -// WM_COPYDATA identifier -#define CDID_FILENAME 1 // send file name - -// macro to check for valid calculator model -#define isModelValid(m) (m != 0 && strchr(MODELS,m) != NULL) - -// values for mapping area -enum MMUMAP { M_IO, M_ROM, M_RAM, M_P1, M_P2, M_BS }; - -// values for disassembler memory mapping modes -enum MEM_MAPPING { MEM_MMU, MEM_NCE1, MEM_NCE2, MEM_CE1, MEM_CE2, MEM_NCE3 }; - -// Kermit CRC calculation -static __inline WORD UpCRC(WORD wCRC, BYTE nib) { return (wCRC >> 4) ^ (((wCRC ^ nib) & 0xf) * 0x1081); } - -// Emu48.c -extern HPALETTE hPalette; -extern HPALETTE hOldPalette; -extern HANDLE hEventShutdn; -extern LPTSTR szAppName; -extern LPTSTR szTopic; -extern LPTSTR szTitle; -extern CRITICAL_SECTION csGDILock; -extern CRITICAL_SECTION csLcdLock; -extern CRITICAL_SECTION csKeyLock; -extern CRITICAL_SECTION csIOLock; -extern CRITICAL_SECTION csT1Lock; -extern CRITICAL_SECTION csT2Lock; -extern CRITICAL_SECTION csTxdLock; -extern CRITICAL_SECTION csRecvLock; -extern CRITICAL_SECTION csSlowLock; -extern CRITICAL_SECTION csDbgLock; -extern INT nArgc; -extern LPCTSTR *ppArgv; -extern LARGE_INTEGER lFreq; -extern LARGE_INTEGER lAppStart; -extern DWORD idDdeInst; -extern UINT uCF_HpObj; -extern HINSTANCE hApp; -extern HWND hWnd; -extern HWND hDlgDebug; -extern HWND hDlgFind; -extern HWND hDlgProfile; -extern HWND hDlgRplObjView; -extern HDC hWindowDC; -extern DWORD dwTColor; -extern DWORD dwTColorTol; -extern HRGN hRgn; -extern HCURSOR hCursorArrow; -extern HCURSOR hCursorHand; -extern UINT uWaveDevId; -extern DWORD dwWakeupDelay; -extern BOOL bAutoSave; -extern BOOL bAutoSaveOnExit; -extern BOOL bSaveDefConfirm; -extern BOOL bStartupBackup; -extern BOOL bAlwaysDisplayLog; -extern BOOL bLoadObjectWarning; -extern BOOL bShowTitle; -extern BOOL bShowMenu; -extern BOOL bAlwaysOnTop; -extern BOOL bActFollowsMouse; -extern BOOL bClientWinMove; -extern BOOL bSingleInstance; -extern HANDLE hThread; -extern VOID SetWindowTitle(LPCTSTR szString); -extern VOID ForceForegroundWindow(HWND hWnd); -extern VOID CopyItemsToClipboard(HWND hWnd); - -// mru.c -extern BOOL MruInit(UINT nNum); -extern VOID MruCleanup(VOID); -extern VOID MruAdd(LPCTSTR lpszEntry); -extern VOID MruRemove(UINT nIndex); -extern VOID MruMoveTop(UINT nIndex); -extern UINT MruEntries(VOID); -extern UINT MruID(LPCTSTR lpszEntry); -extern VOID MruFilename(UINT nIndex, LPTSTR szFilename, UINT nBuffersize); -extern VOID MruUpdateMenu(HMENU hMenu); -extern VOID MruWriteList(VOID); -extern VOID MruReadList(VOID); - -// Settings.c -extern VOID ReadSettings(VOID); -extern VOID WriteSettings(VOID); -extern VOID ReadLastDocument(LPTSTR szFileName, DWORD nSize); -extern VOID WriteLastDocument(LPCTSTR szFilename); -extern VOID ReadSettingsString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpDefault, LPTSTR lpData, DWORD dwSize); -extern VOID WriteSettingsString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPTSTR lpData); -extern INT ReadSettingsInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nDefault); -extern VOID WriteSettingsInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nValue); -extern VOID DelSettingsKey(LPCTSTR lpszSection, LPCTSTR lpszEntry); - -// Display.c -extern BOOL bGrayscale; -extern UINT nBackgroundX; -extern UINT nBackgroundY; -extern UINT nBackgroundW; -extern UINT nBackgroundH; -extern UINT nLcdX; -extern UINT nLcdY; -extern UINT nLcdZoom; -extern UINT nGdiXZoom; -extern UINT nGdiYZoom; -extern HDC hLcdDC; -extern HDC hMainDC; -extern HDC hAnnunDC; -extern BYTE (*GetLineCounter)(VOID); -extern VOID (*StartDisplay)(BYTE byInitial); -extern VOID (*StopDisplay)(VOID); -extern VOID UpdateContrast(BYTE byContrast); -extern VOID SetLcdColor(UINT nId, UINT nRed, UINT nGreen, UINT nBlue); -extern VOID SetLcdMode(BOOL bMode); -extern VOID CreateLcdBitmap(VOID); -extern VOID DestroyLcdBitmap(VOID); -extern BOOL CreateMainBitmap(LPCTSTR szFilename); -extern VOID DestroyMainBitmap(VOID); -extern BOOL CreateAnnunBitmap(LPCTSTR szFilename); -extern VOID DestroyAnnunBitmap(VOID); -extern VOID UpdateDisplayPointers(VOID); -extern VOID UpdateMainDisplay(VOID); -extern VOID UpdateMenuDisplay(VOID); -extern VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s); -extern VOID WriteToMenuDisplay(LPBYTE a, DWORD d, UINT s); -extern VOID UpdateAnnunciators(DWORD dwUpdateMask); -extern VOID ResizeWindow(VOID); - -// Engine.c -extern BOOL bInterrupt; -extern UINT nState; -extern UINT nNextState; -extern BOOL bEnableSlow; -extern BOOL bRealSpeed; -extern BOOL bKeySlow; -extern BOOL bSoundSlow; -extern UINT nOpcSlow; -extern CHIPSET Chipset; -extern TCHAR szSerialWire[16]; -extern TCHAR szSerialIr[16]; -extern DWORD dwSXCycles; -extern DWORD dwGXCycles; -extern HANDLE hEventDebug; -extern BOOL bDbgAutoStateCtrl; -extern INT nDbgState; -extern BOOL bDbgNOP3; -extern BOOL bDbgCode; -extern BOOL bDbgRPL; -extern BOOL bDbgSkipInt; -extern DWORD dwDbgStopPC; -extern DWORD dwDbgRplPC; -extern DWORD dwDbgRstkp; -extern DWORD dwDbgRstk; -extern DWORD *pdwInstrArray; -extern WORD wInstrSize; -extern WORD wInstrWp; -extern WORD wInstrRp; -extern VOID (*fnOutTrace)(VOID); -extern VOID SuspendDebugger(VOID); -extern VOID ResumeDebugger(VOID); -extern VOID CheckSerial(VOID); -extern VOID InitAdjustSpeed(VOID); -extern VOID AdjKeySpeed(VOID); -extern VOID SetSpeed(BOOL bAdjust); -extern VOID UpdateKdnBit(VOID); -extern BOOL WaitForSleepState(VOID); -extern UINT SwitchToState(UINT nNewState); -extern UINT WorkerThread(LPVOID pParam); - -// Fetch.c -extern VOID EvalOpcode(LPBYTE I); - -// Files.c -extern TCHAR szEmuDirectory[MAX_PATH]; -extern TCHAR szCurrentDirectory[MAX_PATH]; -extern TCHAR szCurrentKml[MAX_PATH]; -extern TCHAR szBackupKml[MAX_PATH]; -extern TCHAR szCurrentFilename[MAX_PATH]; -extern TCHAR szBackupFilename[MAX_PATH]; -extern TCHAR szBufferFilename[MAX_PATH]; -extern TCHAR szPort2Filename[MAX_PATH]; -extern BOOL bDocumentAvail; -extern BYTE cCurrentRomType; -extern UINT nCurrentClass; -extern LPBYTE Port0; -extern LPBYTE Port1; -extern LPBYTE Port2; -extern LPBYTE pbyRom; -extern BOOL bRomWriteable; -extern DWORD dwRomSize; -extern LPBYTE pbyRomDirtyPage; -extern DWORD dwRomDirtyPageSize; -extern WORD wRomCrc; -extern BOOL bRomCrcCorrection; -extern LPBYTE pbyPort2; -extern BOOL bPort2Writeable; -extern BOOL bPort2IsShared; -extern DWORD dwPort2Size; -extern DWORD dwPort2Mask; -extern WORD wPort2Crc; -extern BOOL bBackup; -extern VOID SetWindowLocation(HWND hWnd,INT nPosX,INT nPosY); -extern DWORD GetCutPathName(LPCTSTR szFileName,LPTSTR szBuffer,DWORD dwBufferLength,INT nCutLength); -extern VOID SetWindowPathTitle(LPCTSTR szFileName); -extern BOOL CheckForBeepPatch(VOID); -extern BOOL PatchNibble(DWORD dwAddress, BYTE byPatch); -extern VOID UpdatePatches(BOOL bPatch); -extern BOOL PatchRom(LPCTSTR szFilename); -extern BOOL CrcRom(WORD *pwChk); -extern BOOL MapRom(LPCTSTR szFilename); -extern VOID UnmapRom(VOID); -extern BOOL MapPort2(LPCTSTR szFilename); -extern VOID UnmapPort2(VOID); -extern VOID ResetDocument(VOID); -extern BOOL NewDocument(VOID); -extern BOOL OpenDocument(LPCTSTR szFilename); -extern BOOL SaveDocument(VOID); -extern BOOL SaveDocumentAs(LPCTSTR szFilename); -extern BOOL SaveBackup(VOID); -extern BOOL RestoreBackup(VOID); -extern BOOL ResetBackup(VOID); -extern BOOL GetOpenFilename(VOID); -extern BOOL GetSaveAsFilename(VOID); -extern BOOL GetLoadObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt); -extern BOOL GetSaveObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt); -extern WORD WriteStack(UINT nStkLevel,LPBYTE lpBuf,DWORD dwSize); -extern BOOL LoadObject(LPCTSTR szFilename); -extern BOOL SaveObject(LPCTSTR szFilename); -extern BOOL LoadIconFromFile(LPCTSTR szFilename); -extern VOID LoadIconDefault(VOID); -extern HBITMAP LoadBitmapFile(LPCTSTR szFilename,BOOL bPalette); -extern HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol); - -// Romcrc.c -extern VOID RebuildRomCrc(VOID); - -// Timer.c -extern VOID SetHP48Time(VOID); -extern VOID StartTimers(VOID); -extern VOID StopTimers(VOID); -extern DWORD ReadT2(VOID); -extern VOID SetT2(DWORD dwValue); -extern BYTE ReadT1(VOID); -extern VOID SetT1(BYTE byValue); - -// Mops.c -extern BOOL bFlashRomArray; -extern BYTE disp; -extern LPBYTE RMap[256]; -extern LPBYTE WMap[256]; -extern VOID Map(BYTE a, BYTE b); -extern VOID RomSwitch(DWORD adr); -extern VOID Config(VOID); -extern VOID Uncnfg(VOID); -extern VOID Reset(VOID); -extern VOID C_Eq_Id(VOID); -extern enum MMUMAP MapData(DWORD d); -extern VOID CpuReset(VOID); -extern VOID Npeek(BYTE *a, DWORD d, UINT s); -extern VOID Nread(BYTE *a, DWORD d, UINT s); -extern VOID Nwrite(BYTE *a, DWORD d, UINT s); -extern BYTE Read2(DWORD d); -extern DWORD Read5(DWORD d); -extern VOID Write5(DWORD d, DWORD n); -extern VOID Write2(DWORD d, BYTE n); -extern VOID IOBit(DWORD d, BYTE b, BOOL s); -extern VOID ReadIO(BYTE *a, DWORD b, DWORD s, BOOL bUpdate); -extern VOID WriteIO(BYTE *a, DWORD b, DWORD s); - -// Lowbat.c -extern BOOL bLowBatDisable; -extern VOID StartBatMeasure(VOID); -extern VOID StopBatMeasure(VOID); -extern VOID GetBatteryState(BOOL *pbLBI, BOOL *pbVLBI); - -// Keyboard.c -extern DWORD dwKeyMinDelay; -extern VOID ScanKeyboard(BOOL bActive, BOOL bReset); -extern VOID KeyboardEvent(BOOL bPress, UINT out, UINT in); - -// Keymacro.c -extern INT nMacroState; -extern INT nMacroTimeout; -extern BOOL bMacroRealSpeed; -extern DWORD dwMacroMinDelay; -extern VOID KeyMacroRecord(BOOL bPress, UINT out, UINT in); -extern LRESULT OnToolMacroNew(VOID); -extern LRESULT OnToolMacroPlay(VOID); -extern LRESULT OnToolMacroStop(VOID); -extern LRESULT OnToolMacroSettings(VOID); - -// Redeye.c -extern VOID IrPrinter(BYTE c); - -// Udp.c -extern TCHAR szUdpServer[1024]; -extern WORD wUdpPort; -extern VOID ResetUdp(VOID); -extern BOOL SendByteUdp(BYTE byData); - -// Stack.c -extern BOOL bDetectClpObject; -extern LRESULT OnStackCopy(VOID); -extern LRESULT OnStackPaste(VOID); - -// RPL.c -extern BOOL RPL_GetSystemFlag(INT nFlag); -extern DWORD RPL_SkipOb(DWORD d); -extern DWORD RPL_ObjectSize(BYTE *o,DWORD s); -extern DWORD RPL_CreateTemp(DWORD l); -extern UINT RPL_Depth(VOID); -extern DWORD RPL_Pick(UINT l); -extern VOID RPL_Replace(DWORD n); -extern VOID RPL_Push(UINT l,DWORD n); - -// SndEnum.c -extern VOID SetSoundDeviceList(HWND hWnd,UINT uDeviceID); - -// Sound.c -extern DWORD dwWaveVol; -extern DWORD dwWaveTime; -extern BOOL SoundAvailable(UINT uDeviceID); -extern BOOL SoundGetDeviceID(UINT *puDeviceID); -extern BOOL SoundOpen(UINT uDeviceID); -extern VOID SoundClose(VOID); -extern VOID SoundOut(CHIPSET* w, WORD wOut); -extern VOID SoundBeep(DWORD dwFrequency, DWORD dwDuration); - -// DDEserv.c -extern HDDEDATA CALLBACK DdeCallback(UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, DWORD, DWORD); - -// Dismem.c -extern BOOL SetMemRomType(BYTE cCurrentRomType); -extern BOOL SetMemMapType(enum MEM_MAPPING eType); -extern enum MEM_MAPPING GetMemMapType(VOID); -extern BOOL GetMemAvail(enum MEM_MAPPING eType); -extern DWORD GetMemDataSize(VOID); -extern DWORD GetMemDataMask(VOID); -extern BYTE GetMemNib(DWORD *p); -extern VOID GetMemPeek(BYTE *a, DWORD d, UINT s); - -// Disasm.c -extern BOOL disassembler_mode; -extern BOOL disassembler_symb; -extern DWORD disassemble(DWORD addr, LPTSTR out); - -// Symbfile.c -extern BOOL RplTableEmpty(VOID); -extern BOOL RplLoadTable(LPCTSTR lpszFilename); -extern VOID RplDeleteTable(VOID); -extern LPCTSTR RplGetName(DWORD dwAddr); -extern BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr); - -// Serial.c -extern BOOL CommIsOpen(VOID); -extern BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort); -extern VOID CommClose(VOID); -extern VOID CommSetBaud(VOID); -extern BOOL UpdateUSRQ(VOID); -extern VOID CommTxBRK(VOID); -extern VOID CommTransmit(VOID); -extern VOID CommReceive(VOID); - -// Cursor.c -extern HCURSOR CreateHandCursor(VOID); - -#if defined _USRDLL // DLL version -// Emu48dll.c -extern VOID (CALLBACK *pEmuDocumentNotify)(LPCTSTR lpszFilename); -extern BOOL DLLCreateWnd(LPCTSTR lpszFilename, LPCTSTR lpszPort2Name); -extern BOOL DLLDestroyWnd(VOID); - -// Symbfile.c -#define RplGetName(a) NULL // for linking -#endif - -// Message Boxes -static __inline int InfoMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND);} -static __inline int AbortMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);} -static __inline int YesNoMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_YESNO|MB_ICONEXCLAMATION|MB_SETFOREGROUND);} -static __inline int YesNoCancelMessage(LPCTSTR szMessage,UINT uStyle) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_YESNOCANCEL|MB_ICONEXCLAMATION|MB_SETFOREGROUND|uStyle);} - -// Missing Win32 API calls -static __inline LPTSTR DuplicateString(LPCTSTR szString) -{ - UINT uLength = lstrlen(szString) + 1; - LPTSTR szDup = (LPTSTR) malloc(uLength*sizeof(szDup[0])); - lstrcpy(szDup,szString); - return szDup; -} +/* + * Emu48.h + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ +#include "types.h" + +#define _KB(a) ((a)*2*1024) + +#define HARDWARE "Yorke" // emulator hardware +#define MODELS "6AEGSX" // valid calculator models + +#define ARRAYSIZEOF(a) (sizeof(a) / sizeof(a[0])) + +// cards status +#define PORT1_PRESENT ((cCurrentRomType=='S')?P1C:P2C) +#define PORT1_WRITE ((cCurrentRomType=='S')?P1W:P2W) +#define PORT2_PRESENT ((cCurrentRomType=='S')?P2C:P1C) +#define PORT2_WRITE ((cCurrentRomType=='S')?P2W:P1W) + +#define BINARYHEADER48 "HPHP48-W" +#define BINARYHEADER49 "HPHP49-W" + +#define BIN_FILTER "Port Data File (*.BIN)\0*.BIN\0All Files (*.*)\0*.*\0" +#define HP_FILTER "HP Binary Object (*.HP;*.LIB)\0*.HP;*.LIB\0All Files (*.*)\0*.*\0" + +#define CF_HPOBJ "CF_HPOBJ" // clipboard format for DDE + +// CPU cycles in 16384 Hz time frame +#define T2CYCLES ((cCurrentRomType=='S')?dwSXCycles:dwGXCycles) + +#define SM_RUN 0 // states of cpu emulation thread +#define SM_INVALID 1 +#define SM_RETURN 2 +#define SM_SLEEP 3 + +#define S_ERR_NO 0 // stack errorcodes +#define S_ERR_OBJECT 1 +#define S_ERR_BINARY 2 +#define S_ERR_ASCII 3 + +#define BAD_OB (0xFFFFFFFF) // bad object + +#define NO_SERIAL "disabled" // port not open + +#define HP_MNEMONICS FALSE // disassembler mnenomics mode +#define CLASS_MNEMONICS TRUE + +#define MACRO_OFF 0 // macro recorder off +#define MACRO_NEW 1 +#define MACRO_PLAY 2 + +#define DISP_POINTER 0x01 // defines for display area +#define DISP_MAIN 0x02 +#define DISP_MENUE 0x04 + +#define ROMPAGESIZE (1<<12) // ROM dirty page size in nibbles + +// window styles +#define STYLE_TITLE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED) +#define STYLE_NOTITLE (WS_POPUP|WS_SYSMENU|WS_MINIMIZEBOX|WS_CLIPSIBLINGS) + +// WM_COPYDATA identifier +#define CDID_FILENAME 1 // send file name + +// macro to check for valid calculator model +#define isModelValid(m) (m != 0 && strchr(MODELS,m) != NULL) + +// values for mapping area +enum MMUMAP { M_IO, M_ROM, M_RAM, M_P1, M_P2, M_BS }; + +// values for disassembler memory mapping modes +enum MEM_MAPPING { MEM_MMU, MEM_NCE1, MEM_NCE2, MEM_CE1, MEM_CE2, MEM_NCE3 }; + +// Kermit CRC calculation +static __inline WORD UpCRC(WORD wCRC, BYTE nib) { return (wCRC >> 4) ^ (((wCRC ^ nib) & 0xf) * 0x1081); } + +// Emu48.c +extern HPALETTE hPalette; +extern HPALETTE hOldPalette; +extern HANDLE hEventShutdn; +extern LPTSTR szAppName; +extern LPTSTR szTopic; +extern LPTSTR szTitle; +extern CRITICAL_SECTION csGDILock; +extern CRITICAL_SECTION csLcdLock; +extern CRITICAL_SECTION csKeyLock; +extern CRITICAL_SECTION csIOLock; +extern CRITICAL_SECTION csT1Lock; +extern CRITICAL_SECTION csT2Lock; +extern CRITICAL_SECTION csTxdLock; +extern CRITICAL_SECTION csRecvLock; +extern CRITICAL_SECTION csSlowLock; +extern CRITICAL_SECTION csDbgLock; +extern INT nArgc; +extern LPCTSTR *ppArgv; +extern LARGE_INTEGER lFreq; +extern LARGE_INTEGER lAppStart; +extern DWORD idDdeInst; +extern UINT uCF_HpObj; +extern HINSTANCE hApp; +extern HWND hWnd; +extern HWND hDlgDebug; +extern HWND hDlgFind; +extern HWND hDlgProfile; +extern HWND hDlgRplObjView; +extern HDC hWindowDC; +extern DWORD dwTColor; +extern DWORD dwTColorTol; +extern HRGN hRgn; +extern HCURSOR hCursorArrow; +extern HCURSOR hCursorHand; +extern UINT uWaveDevId; +extern DWORD dwWakeupDelay; +extern BOOL bAutoSave; +extern BOOL bAutoSaveOnExit; +extern BOOL bSaveDefConfirm; +extern BOOL bStartupBackup; +extern BOOL bAlwaysDisplayLog; +extern BOOL bLoadObjectWarning; +extern BOOL bShowTitle; +extern BOOL bShowMenu; +extern BOOL bAlwaysOnTop; +extern BOOL bActFollowsMouse; +extern BOOL bClientWinMove; +extern BOOL bSingleInstance; +extern HANDLE hThread; +extern VOID SetWindowTitle(LPCTSTR szString); +extern VOID ForceForegroundWindow(HWND hWnd); +extern VOID CopyItemsToClipboard(HWND hWnd); + +// mru.c +extern BOOL MruInit(UINT nNum); +extern VOID MruCleanup(VOID); +extern VOID MruAdd(LPCTSTR lpszEntry); +extern VOID MruRemove(UINT nIndex); +extern VOID MruMoveTop(UINT nIndex); +extern UINT MruEntries(VOID); +extern UINT MruID(LPCTSTR lpszEntry); +extern VOID MruFilename(UINT nIndex, LPTSTR szFilename, UINT nBuffersize); +extern VOID MruUpdateMenu(HMENU hMenu); +extern VOID MruWriteList(VOID); +extern VOID MruReadList(VOID); + +// Settings.c +extern VOID ReadSettings(VOID); +extern VOID WriteSettings(VOID); +extern VOID ReadLastDocument(LPTSTR szFileName, DWORD nSize); +extern VOID WriteLastDocument(LPCTSTR szFilename); +extern VOID ReadSettingsString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpDefault, LPTSTR lpData, DWORD dwSize); +extern VOID WriteSettingsString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPTSTR lpData); +extern INT ReadSettingsInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nDefault); +extern VOID WriteSettingsInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nValue); +extern VOID DelSettingsKey(LPCTSTR lpszSection, LPCTSTR lpszEntry); + +// Display.c +extern BOOL bGrayscale; +extern UINT nBackgroundX; +extern UINT nBackgroundY; +extern UINT nBackgroundW; +extern UINT nBackgroundH; +extern UINT nLcdX; +extern UINT nLcdY; +extern UINT nLcdZoom; +extern UINT nGdiXZoom; +extern UINT nGdiYZoom; +extern HDC hLcdDC; +extern HDC hMainDC; +extern HDC hAnnunDC; +extern BYTE (*GetLineCounter)(VOID); +extern VOID (*StartDisplay)(BYTE byInitial); +extern VOID (*StopDisplay)(VOID); +extern VOID UpdateContrast(BYTE byContrast); +extern VOID SetLcdColor(UINT nId, UINT nRed, UINT nGreen, UINT nBlue); +extern VOID SetLcdMode(BOOL bMode); +extern VOID CreateLcdBitmap(VOID); +extern VOID DestroyLcdBitmap(VOID); +extern BOOL CreateMainBitmap(LPCTSTR szFilename); +extern VOID DestroyMainBitmap(VOID); +extern BOOL CreateAnnunBitmap(LPCTSTR szFilename); +extern VOID DestroyAnnunBitmap(VOID); +extern VOID UpdateDisplayPointers(VOID); +extern VOID UpdateMainDisplay(VOID); +extern VOID UpdateMenuDisplay(VOID); +extern VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s); +extern VOID WriteToMenuDisplay(LPBYTE a, DWORD d, UINT s); +extern VOID UpdateAnnunciators(DWORD dwUpdateMask); +extern VOID ResizeWindow(VOID); + +// Engine.c +extern BOOL bInterrupt; +extern UINT nState; +extern UINT nNextState; +extern BOOL bEnableSlow; +extern BOOL bRealSpeed; +extern BOOL bKeySlow; +extern BOOL bSoundSlow; +extern UINT nOpcSlow; +extern CHIPSET Chipset; +extern TCHAR szSerialWire[16]; +extern TCHAR szSerialIr[16]; +extern DWORD dwSXCycles; +extern DWORD dwGXCycles; +extern HANDLE hEventDebug; +extern BOOL bDbgAutoStateCtrl; +extern INT nDbgState; +extern BOOL bDbgNOP3; +extern BOOL bDbgCode; +extern BOOL bDbgRPL; +extern BOOL bDbgSkipInt; +extern DWORD dwDbgStopPC; +extern DWORD dwDbgRplPC; +extern DWORD dwDbgRstkp; +extern DWORD dwDbgRstk; +extern DWORD *pdwInstrArray; +extern WORD wInstrSize; +extern WORD wInstrWp; +extern WORD wInstrRp; +extern VOID (*fnOutTrace)(VOID); +extern VOID SuspendDebugger(VOID); +extern VOID ResumeDebugger(VOID); +extern VOID CheckSerial(VOID); +extern VOID InitAdjustSpeed(VOID); +extern VOID AdjKeySpeed(VOID); +extern VOID SetSpeed(BOOL bAdjust); +extern VOID UpdateKdnBit(VOID); +extern BOOL WaitForSleepState(VOID); +extern UINT SwitchToState(UINT nNewState); +extern UINT WorkerThread(LPVOID pParam); + +// Fetch.c +extern VOID EvalOpcode(LPBYTE I); + +// Files.c +extern TCHAR szEmuDirectory[MAX_PATH]; +extern TCHAR szCurrentDirectory[MAX_PATH]; +extern TCHAR szCurrentKml[MAX_PATH]; +extern TCHAR szBackupKml[MAX_PATH]; +extern TCHAR szCurrentFilename[MAX_PATH]; +extern TCHAR szBackupFilename[MAX_PATH]; +extern TCHAR szBufferFilename[MAX_PATH]; +extern TCHAR szPort2Filename[MAX_PATH]; +extern BOOL bDocumentAvail; +extern BYTE cCurrentRomType; +extern UINT nCurrentClass; +extern LPBYTE Port0; +extern LPBYTE Port1; +extern LPBYTE Port2; +extern LPBYTE pbyRom; +extern BOOL bRomWriteable; +extern DWORD dwRomSize; +extern LPBYTE pbyRomDirtyPage; +extern DWORD dwRomDirtyPageSize; +extern WORD wRomCrc; +extern BOOL bRomCrcCorrection; +extern LPBYTE pbyPort2; +extern BOOL bPort2Writeable; +extern BOOL bPort2IsShared; +extern DWORD dwPort2Size; +extern DWORD dwPort2Mask; +extern WORD wPort2Crc; +extern BOOL bBackup; +extern VOID SetWindowLocation(HWND hWnd,INT nPosX,INT nPosY); +extern DWORD GetCutPathName(LPCTSTR szFileName,LPTSTR szBuffer,DWORD dwBufferLength,INT nCutLength); +extern VOID SetWindowPathTitle(LPCTSTR szFileName); +extern BOOL CheckForBeepPatch(VOID); +extern BOOL PatchNibble(DWORD dwAddress, BYTE byPatch); +extern VOID UpdatePatches(BOOL bPatch); +extern BOOL PatchRom(LPCTSTR szFilename); +extern BOOL CrcRom(WORD *pwChk); +extern BOOL MapRom(LPCTSTR szFilename); +extern VOID UnmapRom(VOID); +extern BOOL MapPort2(LPCTSTR szFilename); +extern VOID UnmapPort2(VOID); +extern VOID ResetDocument(VOID); +extern BOOL NewDocument(VOID); +extern BOOL OpenDocument(LPCTSTR szFilename); +extern BOOL SaveDocument(VOID); +extern BOOL SaveDocumentAs(LPCTSTR szFilename); +extern BOOL SaveBackup(VOID); +extern BOOL RestoreBackup(VOID); +extern BOOL ResetBackup(VOID); +extern BOOL GetOpenFilename(VOID); +extern BOOL GetSaveAsFilename(VOID); +extern BOOL GetLoadObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt); +extern BOOL GetSaveObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt); +extern WORD WriteStack(UINT nStkLevel,LPBYTE lpBuf,DWORD dwSize); +extern BOOL LoadObject(LPCTSTR szFilename); +extern BOOL SaveObject(LPCTSTR szFilename); +extern BOOL LoadIconFromFile(LPCTSTR szFilename); +extern VOID LoadIconDefault(VOID); +extern HBITMAP LoadBitmapFile(LPCTSTR szFilename,BOOL bPalette); +extern HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol); + +// Romcrc.c +extern VOID RebuildRomCrc(VOID); + +// Timer.c +extern VOID SetHP48Time(VOID); +extern VOID StartTimers(VOID); +extern VOID StopTimers(VOID); +extern DWORD ReadT2(VOID); +extern VOID SetT2(DWORD dwValue); +extern BYTE ReadT1(VOID); +extern VOID SetT1(BYTE byValue); + +// Mops.c +extern BOOL bFlashRomArray; +extern BYTE disp; +extern LPBYTE RMap[256]; +extern LPBYTE WMap[256]; +extern VOID Map(BYTE a, BYTE b); +extern VOID RomSwitch(DWORD adr); +extern VOID Config(VOID); +extern VOID Uncnfg(VOID); +extern VOID Reset(VOID); +extern VOID C_Eq_Id(VOID); +extern enum MMUMAP MapData(DWORD d); +extern VOID CpuReset(VOID); +extern VOID Npeek(BYTE *a, DWORD d, UINT s); +extern VOID Nread(BYTE *a, DWORD d, UINT s); +extern VOID Nwrite(BYTE *a, DWORD d, UINT s); +extern BYTE Read2(DWORD d); +extern DWORD Read5(DWORD d); +extern VOID Write5(DWORD d, DWORD n); +extern VOID Write2(DWORD d, BYTE n); +extern VOID IOBit(DWORD d, BYTE b, BOOL s); +extern VOID ReadIO(BYTE *a, DWORD b, DWORD s, BOOL bUpdate); +extern VOID WriteIO(BYTE *a, DWORD b, DWORD s); + +// Lowbat.c +extern BOOL bLowBatDisable; +extern VOID StartBatMeasure(VOID); +extern VOID StopBatMeasure(VOID); +extern VOID GetBatteryState(BOOL *pbLBI, BOOL *pbVLBI); + +// Keyboard.c +extern DWORD dwKeyMinDelay; +extern VOID ScanKeyboard(BOOL bActive, BOOL bReset); +extern VOID KeyboardEvent(BOOL bPress, UINT out, UINT in); + +// Keymacro.c +extern INT nMacroState; +extern INT nMacroTimeout; +extern BOOL bMacroRealSpeed; +extern DWORD dwMacroMinDelay; +extern VOID KeyMacroRecord(BOOL bPress, UINT out, UINT in); +extern LRESULT OnToolMacroNew(VOID); +extern LRESULT OnToolMacroPlay(VOID); +extern LRESULT OnToolMacroStop(VOID); +extern LRESULT OnToolMacroSettings(VOID); + +// Redeye.c +extern VOID IrPrinter(BYTE c); + +// Udp.c +extern TCHAR szUdpServer[1024]; +extern WORD wUdpPort; +extern VOID ResetUdp(VOID); +extern BOOL SendByteUdp(BYTE byData); + +// Stack.c +extern BOOL bDetectClpObject; +extern BOOL bLocaleDecimalPoint; +extern LRESULT OnStackCopy(VOID); +extern LRESULT OnStackPaste(VOID); + +// RPL.c +extern BOOL RPL_GetSystemFlag(INT nFlag); +extern DWORD RPL_SkipOb(DWORD d); +extern DWORD RPL_ObjectSize(BYTE *o,DWORD s); +extern DWORD RPL_CreateTemp(DWORD l); +extern UINT RPL_Depth(VOID); +extern DWORD RPL_Pick(UINT l); +extern VOID RPL_Replace(DWORD n); +extern VOID RPL_Push(UINT l,DWORD n); + +// SndEnum.c +extern VOID SetSoundDeviceList(HWND hWnd,UINT uDeviceID); + +// Sound.c +extern DWORD dwWaveVol; +extern DWORD dwWaveTime; +extern BOOL SoundAvailable(UINT uDeviceID); +extern BOOL SoundGetDeviceID(UINT *puDeviceID); +extern BOOL SoundOpen(UINT uDeviceID); +extern VOID SoundClose(VOID); +extern VOID SoundOut(CHIPSET* w, WORD wOut); +extern VOID SoundBeep(DWORD dwFrequency, DWORD dwDuration); + +// DDEserv.c +extern HDDEDATA CALLBACK DdeCallback(UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, DWORD, DWORD); + +// Dismem.c +extern BOOL SetMemRomType(BYTE cCurrentRomType); +extern BOOL SetMemMapType(enum MEM_MAPPING eType); +extern enum MEM_MAPPING GetMemMapType(VOID); +extern BOOL GetMemAvail(enum MEM_MAPPING eType); +extern DWORD GetMemDataSize(VOID); +extern DWORD GetMemDataMask(VOID); +extern BYTE GetMemNib(DWORD *p); +extern VOID GetMemPeek(BYTE *a, DWORD d, UINT s); + +// Disasm.c +extern BOOL disassembler_mode; +extern BOOL disassembler_symb; +extern DWORD disassemble(DWORD addr, LPTSTR out); + +// Symbfile.c +extern BOOL RplTableEmpty(VOID); +extern BOOL RplLoadTable(LPCTSTR lpszFilename); +extern VOID RplDeleteTable(VOID); +extern LPCTSTR RplGetName(DWORD dwAddr); +extern BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr); + +// Serial.c +extern BOOL CommIsOpen(VOID); +extern BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort); +extern VOID CommClose(VOID); +extern VOID CommSetBaud(VOID); +extern BOOL UpdateUSRQ(VOID); +extern VOID CommTxBRK(VOID); +extern VOID CommTransmit(VOID); +extern VOID CommReceive(VOID); + +// Cursor.c +extern HCURSOR CreateHandCursor(VOID); + +#if defined _USRDLL // DLL version +// Emu48dll.c +extern VOID (CALLBACK *pEmuDocumentNotify)(LPCTSTR lpszFilename); +extern BOOL DLLCreateWnd(LPCTSTR lpszFilename, LPCTSTR lpszPort2Name); +extern BOOL DLLDestroyWnd(VOID); + +// Symbfile.c +#define RplGetName(a) NULL // for linking +#endif + +// Message Boxes +static __inline int InfoMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND);} +static __inline int AbortMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);} +static __inline int YesNoMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_YESNO|MB_ICONEXCLAMATION|MB_SETFOREGROUND);} +static __inline int YesNoCancelMessage(LPCTSTR szMessage,UINT uStyle) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_YESNOCANCEL|MB_ICONEXCLAMATION|MB_SETFOREGROUND|uStyle);} + +// Missing Win32 API calls +static __inline LPTSTR DuplicateString(LPCTSTR szString) +{ + UINT uLength = lstrlen(szString) + 1; + LPTSTR szDup = (LPTSTR) malloc(uLength*sizeof(szDup[0])); + lstrcpy(szDup,szString); + return szDup; +} diff --git a/Sources/Emu48/EMU48.RC b/Sources/Emu48/EMU48.RC index 15e2e4b..26321de 100644 --- a/Sources/Emu48/EMU48.RC +++ b/Sources/Emu48/EMU48.RC @@ -303,7 +303,7 @@ FONT 8, "MS Sans Serif" BEGIN ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP - LTEXT "Copyright © 2023 Christoph Gießelink && Sébastien Carlier", + LTEXT "Copyright © 2024 Christoph Gießelink && Sébastien Carlier", IDC_STATIC,29,18,181,8 DEFPUSHBUTTON "OK",IDOK,215,12,39,14 EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL | @@ -622,7 +622,11 @@ BEGIN EDITTEXT IDC_DEBUG_DATA_STARTADDR,101,27,37,14 LTEXT "End Address (hexadecimal):",IDC_STATIC,7,46,88,8 EDITTEXT IDC_DEBUG_DATA_ENDADDR,101,44,37,14 - PUSHBUTTON "OK",IDOK,207,27,50,14 + CONTROL "8-bit",IDC_DEBUG_DATA_SAVE_8BIT,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,158,30,29,10 + CONTROL "4-bit",IDC_DEBUG_DATA_SAVE_4BIT,"Button", + BS_AUTORADIOBUTTON,214,30,29,10 + PUSHBUTTON "OK",IDOK,151,44,50,14 PUSHBUTTON "Cancel",IDCANCEL,207,44,50,14 END @@ -636,7 +640,13 @@ BEGIN PUSHBUTTON "Browse",IDC_DEBUG_DATA_BUT,207,7,50,14 LTEXT "Start Address (hexadecimal):",IDC_STATIC,7,30,90,8 EDITTEXT IDC_DEBUG_DATA_STARTADDR,101,27,37,14 - PUSHBUTTON "OK",IDOK,207,27,50,14 + CONTROL "Auto",IDC_DEBUG_DATA_LOAD_ABIT,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,155,29,29,10 + CONTROL "8-bit",IDC_DEBUG_DATA_LOAD_8BIT,"Button", + BS_AUTORADIOBUTTON,189,29,29,10 + CONTROL "4-bit",IDC_DEBUG_DATA_LOAD_4BIT,"Button", + BS_AUTORADIOBUTTON,223,29,29,10 + PUSHBUTTON "OK",IDOK,151,44,50,14 PUSHBUTTON "Cancel",IDCANCEL,207,44,50,14 END @@ -723,8 +733,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,6,6,0 - PRODUCTVERSION 1,6,6,0 + FILEVERSION 1,6,7,0 + PRODUCTVERSION 1,6,7,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -741,12 +751,12 @@ BEGIN BEGIN VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0" VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0" - VALUE "FileVersion", "1, 6, 6, 0\0" + VALUE "FileVersion", "1, 6, 7, 0\0" VALUE "InternalName", "Emu48\0" - VALUE "LegalCopyright", "Copyright © 2023\0" + VALUE "LegalCopyright", "Copyright © 2024\0" VALUE "OriginalFilename", "Emu48.exe\0" VALUE "ProductName", "Emu48\0" - VALUE "ProductVersion", "1, 6, 6, 0\0" + VALUE "ProductVersion", "1, 6, 7, 0\0" END END BLOCK "VarFileInfo" diff --git a/Sources/Emu48/EMU48.sln b/Sources/Emu48/EMU48.sln index 70dbd12..9037d0d 100644 --- a/Sources/Emu48/EMU48.sln +++ b/Sources/Emu48/EMU48.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.32510.428 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32505.173 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Emu48", "Emu48.vcxproj", "{D259D821-B668-408E-B5DF-F0C7B42E6726}" EndProject diff --git a/Sources/Emu48/engine.c b/Sources/Emu48/ENGINE.C similarity index 96% rename from Sources/Emu48/engine.c rename to Sources/Emu48/ENGINE.C index 58dcade..e69f3ec 100644 --- a/Sources/Emu48/engine.c +++ b/Sources/Emu48/ENGINE.C @@ -1,641 +1,641 @@ -/* - * engine.c - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ -#include "pch.h" -#include "emu48.h" -#include "opcodes.h" -#include "io.h" -#include "debugger.h" - -#define SAMPLE 16384 // speed adjust sample frequency - -BOOL bInterrupt = FALSE; -UINT nState = SM_INVALID; -UINT nNextState = SM_RUN; -BOOL bEnableSlow = TRUE; // slow down is enabled -BOOL bRealSpeed = FALSE; -BOOL bKeySlow = FALSE; // slow down for key emulation -BOOL bSoundSlow = FALSE; // slow down for sound emulation -UINT nOpcSlow = 0; // no. of opcodes to slow down - -CHIPSET Chipset; - -TCHAR szSerialWire[16]; // devicename for wire port -TCHAR szSerialIr[16]; // devicename for IR port - -DWORD dwSXCycles = 82; // SX cpu cycles in interval -DWORD dwGXCycles = 123; // GX cpu cycles in interval - -// variables for debugger engine -HANDLE hEventDebug; // event handle to stop cpu thread - -BOOL bDbgAutoStateCtrl = TRUE; // debugger suspend control by SwitchToState() -INT nDbgState = DBG_OFF; // state of debugger - -BOOL bDbgNOP3 = FALSE; // halt on NOP3 (#420 opcode) -BOOL bDbgRPL = FALSE; // halt on RPL entry -BOOL bDbgCode = FALSE; // halt on DOCODE entry - -BOOL bDbgSkipInt = FALSE; // execute interrupt handler - -DWORD dwDbgStopPC = -1; // stop address for goto cursor -DWORD dwDbgRplPC = -1; // stop address for RPL breakpoint - -DWORD dwDbgRstkp; // stack recursion level of step over end -DWORD dwDbgRstk; // possible return address - -DWORD *pdwInstrArray = NULL; // last instruction array -WORD wInstrSize = 256; // size of last instruction array -WORD wInstrWp; // write pointer of instruction array -WORD wInstrRp; // read pointer of instruction array - -VOID (*fnOutTrace)(VOID) = NULL; // callback function for file trace - -static INT nDbgRplBreak = BN_ASM; // flag for RPL breakpoint detection -static INT nDbgOldState = DBG_OFF; // old state of debugger for suspend/resume - -static BOOL bCpuSlow = FALSE; // enable/disable real speed - -static DWORD dwEDbgT2 = 0; // debugger timer2 emulation -static DWORD dwEDbgCycles = 0; // debugger cycle counter - -static DWORD dwOldCyc; // cpu cycles at last event -static DWORD dwSpeedRef; // timer value at last event -static DWORD dwTickRef; // sample timer ticks - -#include "ops.h" - -// save last instruction in circular instruction buffer -static __inline VOID SaveInstrAddr(DWORD dwAddr) -{ - EnterCriticalSection(&csDbgLock); - { - if (pdwInstrArray) // circular buffer allocated - { - pdwInstrArray[wInstrWp] = dwAddr; - wInstrWp = (wInstrWp + 1) % wInstrSize; - if (wInstrWp == wInstrRp) - wInstrRp = (wInstrRp + 1) % wInstrSize; - } - } - LeaveCriticalSection(&csDbgLock); - return; -} - -static __inline VOID Debugger(VOID) // debugger part -{ - LARGE_INTEGER lDummyInt; // sample timer ticks - BOOL bStopEmulation; - LPBYTE I = FASTPTR(Chipset.pc); // get opcode stream - - UpdateDbgCycleCounter(); // update 64 bit cpu cycle counter - - SaveInstrAddr(Chipset.pc); // save pc in last instruction buffer - if (fnOutTrace != NULL) // has a trace function - { - fnOutTrace(); // write file trace - } - - nDbgRplBreak = BN_ASM; // notify ASM breakpoint - - // check for code breakpoints - bStopEmulation = CheckBreakpoint(Chipset.pc, 1, BP_EXEC); - - // check for memory breakpoints, opcode #14x or #15x - if (I[0] == 0x1 && (I[1] == 0x4 || I[1] == 0x5)) - { - DWORD dwData = (I[2] & 0x1) ? Chipset.d1 : Chipset.d0; - UINT nType = (I[2] & 0x2) ? BP_READ : BP_WRITE; - - DWORD dwRange; - if (I[1] == 0x4) // B,A - { - dwRange = (I[2] & 0x8) ? 2 : 5; - } - else // number of nibbles, (P,WP,XS,X,S,M,W) - { - dwRange = (I[2] & 0x8) ? (I[3]+1) : (F_l[I[3]]); - } - #if defined DEBUG_DEBUGGER - { - TCHAR buffer[256]; - wsprintf(buffer,_T("Memory breakpoint %.5lx, %u\n",dwData,dwRange)); - OutputDebugString(buffer); - } - #endif - bStopEmulation |= CheckBreakpoint(dwData, dwRange, nType); - } - - // check for step cursor - bStopEmulation |= (dwDbgStopPC == Chipset.pc); - - // NOP3, opcode #420 (GOC) - if (bDbgNOP3 && I[0] == 0x4 && I[1] == 0x2 && I[2] == 0x0) - bStopEmulation = TRUE; - - // stop on first instruction of DOCODE object - if (bDbgCode && (Chipset.pc == 0x02DDE || Chipset.pc == 0x02E3C)) - { - // return address - DWORD dwAddr = Chipset.rstk[(Chipset.rstkp-1)&7]; - - _ASSERT(I[0] == 0 && I[1] == 1); // stopped at RTN opcode - - if (MapData(dwAddr) != M_ROM) // address not in ROM - dwDbgStopPC = dwAddr; // then stop - } - - // check for RPL breakpoint - if (dwDbgRplPC == Chipset.pc) - { - dwDbgRplPC = -1; - nDbgRplBreak = bStopEmulation ? BN_ASM_BT : BN_RPL; - bStopEmulation = TRUE; - } - - // RPL breakpoints, PC=(A), opcode #808C or PC=(C), opcode #808E - if (I[0] == 0x8 && I[1] == 0x0 && I[2] == 0x8 && (I[3] == 0xC || I[3] == 0xE )) - { - // get next RPL entry - DWORD dwAddr = Npack((I[3] == 0xC) ? Chipset.A : Chipset.C,5); - - if (bDbgRPL || CheckBreakpoint(dwAddr, 1, BP_RPL)) - { - BYTE byRplPtr[5]; - - Npeek(byRplPtr,dwAddr,5); // get PC address of next opcode - dwDbgRplPC = Npack(byRplPtr,5); // set RPL breakpoint - } - } - - // step over interrupt execution - if (bDbgSkipInt && !bStopEmulation && !Chipset.inte) - return; - - // check for step into - bStopEmulation |= (nDbgState == DBG_STEPINTO); - - // check for step over - bStopEmulation |= (nDbgState == DBG_STEPOVER) && dwDbgRstkp == Chipset.rstkp; - - // check for step out, something was popped from hardware stack - if (nDbgState == DBG_STEPOUT && dwDbgRstkp == Chipset.rstkp) - { - _ASSERT(bStopEmulation == FALSE); - if ((bStopEmulation = (Chipset.pc == dwDbgRstk)) == FALSE) - { - // it was C=RSTK, check for next object popped from hardware stack - dwDbgRstkp = (Chipset.rstkp-1)&7; - dwDbgRstk = Chipset.rstk[dwDbgRstkp]; - } - } - - if (bStopEmulation) // stop condition - { - StopTimers(); // hold timer values when emulator is stopped - if (Chipset.IORam[TIMER2_CTRL]&RUN) // check if timer running - { - if (dwEDbgT2 == Chipset.t2) - { - // cpu cycles for one timer2 tick elapsed - if ((DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwEDbgCycles - >= (SAMPLE / 8192) * (DWORD) T2CYCLES) - { - --Chipset.t2; - // adjust cycles reference - dwEDbgCycles += (SAMPLE / 8192) * T2CYCLES; - } - } - else // new timer2 value - { - // new cycle reference - dwEDbgCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF); - } - - // check rising edge of Bit 8 of timer2 - if ((dwEDbgT2 & 0x100) == 0 && (Chipset.t2 & 0x100) != 0) - Chipset.t1 = (Chipset.t1 - 1) & 0xF; - } - dwEDbgT2 = Chipset.t2; // timer2 check reference value - - // redraw debugger window and stop - NotifyDebugger(nDbgRplBreak); - WaitForSingleObject(hEventDebug,INFINITE); - - StartTimers(); // continue timers - - if (nDbgState >= DBG_OFF) // if debugger is active - { - Chipset.Shutdn = FALSE; - Chipset.bShutdnWake = FALSE; - } - - // init slow down part - dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); - QueryPerformanceCounter(&lDummyInt); - dwSpeedRef = lDummyInt.LowPart; - } - return; -} - -VOID SuspendDebugger(VOID) -{ - // auto control enabled, emulation halted by debugger - if (bDbgAutoStateCtrl && nDbgState > DBG_OFF) - { - nDbgOldState = nDbgState; // save old state - nDbgState = DBG_SUSPEND; // suspend state - SetEvent(hEventDebug); // exit debugger - } - return; -} - -VOID ResumeDebugger(VOID) -{ - // auto control enabled, debugger is suspended - if (bDbgAutoStateCtrl && nDbgState == DBG_SUSPEND) - { - // active RPL breakpoint - if (nDbgRplBreak) dwDbgRplPC = Chipset.pc; - nDbgState = nDbgOldState; // set to old debugger state - if (Chipset.Shutdn) // inside shutdown - SetEvent(hEventShutdn); // leave it to call debugger - } - return; -} - -static __inline VOID CheckDisp(BOOL bSync) -{ - if (disp == 0) return; // no display update need - - // update display when drawing top line or display is off - if (bSync && GetLineCounter() != 0x3F && (Chipset.IORam[0x00]&8)) - return; - - _ASSERT((disp & DISP_POINTER) == 0); // display pointer already updated - if (disp & DISP_MAIN) UpdateMainDisplay(); - if (disp & DISP_MENUE) UpdateMenuDisplay(); - disp = 0; // display updated - return; -} - -static __inline VOID AdjustSpeed(VOID) // adjust emulation speed -{ - // emulation slow down - if ( bEnableSlow - && (bCpuSlow || bKeySlow || bSoundSlow || nOpcSlow > 0)) - { - DWORD dwCycles,dwTicks; - - EnterCriticalSection(&csSlowLock); - { - // cycles elapsed for next check - if ((dwCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF)-dwOldCyc) >= (DWORD) T2CYCLES) - { - LARGE_INTEGER lAct; - do - { - VERIFY(QueryPerformanceCounter(&lAct)); - - // get time difference - dwTicks = lAct.LowPart - dwSpeedRef; - } - // ticks elapsed or negative number (workaround for QueryPerformanceCounter() in Win2k) - while (dwTicks <= dwTickRef || (dwTicks & 0x80000000) != 0); - - dwOldCyc += T2CYCLES; // adjust cycles reference - dwSpeedRef += dwTickRef; // adjust reference time - } - - if (nOpcSlow > 0) --nOpcSlow; // decr. slow down opcode counter - } - LeaveCriticalSection(&csSlowLock); - } - return; -} - -VOID CheckSerial(VOID) -{ - // COM port closed and serial on - if (CommIsOpen() == FALSE && (Chipset.IORam[IOC] & SON) != 0) - { - CommOpen(szSerialWire,szSerialIr); // open COM ports - } - - // COM port opened and serial off - if (CommIsOpen() == TRUE && (Chipset.IORam[IOC] & SON) == 0) - { - CommClose(); // close COM port - } - return; -} - -VOID InitAdjustSpeed(VOID) -{ - // slow down function not initalized - if (!bEnableSlow || (!bCpuSlow && !bKeySlow && !bSoundSlow && nOpcSlow == 0)) - { - LARGE_INTEGER lTime; // sample timer ticks - - EnterCriticalSection(&csSlowLock); - { - // save reference cycles - dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); - QueryPerformanceCounter(&lTime);// get timer ticks - dwSpeedRef = lTime.LowPart; // save reference time - } - LeaveCriticalSection(&csSlowLock); - } - return; -} - -VOID AdjKeySpeed(VOID) // slow down key repeat -{ - WORD i; - BOOL bKey; - - bKey = FALSE; // search for a pressed key - for (i = 0;i < ARRAYSIZEOF(Chipset.Keyboard_Row) && !bKey;++i) - bKey = (Chipset.Keyboard_Row[i] != 0); - - if (bKey) // key pressed - { - InitAdjustSpeed(); // init variables if necessary - } - bKeySlow = bKey; // save new state - return; -} - -VOID SetSpeed(BOOL bAdjust) // set emulation speed -{ - if (bAdjust) // switch to real speed - { - InitAdjustSpeed(); // init variables if necessary - } - bCpuSlow = bAdjust; // save emulation speed - return; -} - -VOID UpdateKdnBit(VOID) // update KDN bit -{ - if ( Chipset.intk - && (Chipset.IORam[TIMER2_CTRL]&RUN) != 0 - && (DWORD) (Chipset.cycles & 0xFFFFFFFF) - Chipset.dwKdnCycles > (DWORD) T2CYCLES * 16) - IOBit(SRQ2,KDN,Chipset.in != 0); - return; -} - -BOOL WaitForSleepState(VOID) // wait for cpu SHUTDN then sleep state -{ - DWORD dwRefTime; - - SuspendDebugger(); // suspend debugger - - dwRefTime = timeGetTime(); - // wait for the SHUTDN command with 1.5 sec timeout - while (timeGetTime() - dwRefTime < 1500L && !Chipset.Shutdn) - Sleep(0); - - if (Chipset.Shutdn) // not timeout, cpu is down - SwitchToState(SM_SLEEP); // go to sleep state - else - ResumeDebugger(); // timeout, resume to debugger - - return SM_SLEEP != nNextState; // state not changed, emulator was busy -} - -UINT SwitchToState(UINT nNewState) -{ - UINT nOldState = nState; - - if (nState == nNewState) return nOldState; - switch (nState) - { - case SM_RUN: // Run - switch (nNewState) - { - case SM_INVALID: // -> Invalid - nNextState = SM_INVALID; - if (Chipset.Shutdn) - SetEvent(hEventShutdn); - else - bInterrupt = TRUE; - SuspendDebugger(); // suspend debugger - while (nState!=nNextState) Sleep(0); - break; - case SM_RETURN: // -> Return - DisableDebugger(); // disable debugger - nNextState = SM_INVALID; - if (Chipset.Shutdn) - SetEvent(hEventShutdn); - else - bInterrupt = TRUE; - while (nState!=nNextState) Sleep(0); - nNextState = SM_RETURN; - SetEvent(hEventShutdn); - WaitForSingleObject(hThread,INFINITE); - break; - case SM_SLEEP: // -> Sleep - nNextState = SM_SLEEP; - bInterrupt = TRUE; // exit main loop - SuspendDebugger(); // suspend debugger - SetEvent(hEventShutdn); // exit shutdown - while (nState!=nNextState) Sleep(0); - bInterrupt = FALSE; - ResetEvent(hEventDebug); - ResetEvent(hEventShutdn); - break; - } - break; - case SM_INVALID: // Invalid - switch (nNewState) - { - case SM_RUN: // -> Run - nNextState = SM_RUN; - // don't enter opcode loop on interrupt request - bInterrupt = Chipset.Shutdn || Chipset.SoftInt; - ResumeDebugger(); - SetEvent(hEventShutdn); - while (nState!=nNextState) Sleep(0); - break; - case SM_RETURN: // -> Return - DisableDebugger(); // disable debugger - nNextState = SM_RETURN; - SetEvent(hEventShutdn); - WaitForSingleObject(hThread,INFINITE); - break; - case SM_SLEEP: // -> Sleep - nNextState = SM_SLEEP; - SetEvent(hEventShutdn); - while (nState!=nNextState) Sleep(0); - break; - } - break; - case SM_SLEEP: // Sleep - switch (nNewState) - { - case SM_RUN: // -> Run - nNextState = SM_RUN; - // don't enter opcode loop on interrupt request - bInterrupt = (nDbgState == DBG_OFF) && (Chipset.Shutdn || Chipset.SoftInt); - ResumeDebugger(); - SetEvent(hEventShutdn); // leave sleep state - break; - case SM_INVALID: // -> Invalid - nNextState = SM_INVALID; - SetEvent(hEventShutdn); - while (nState!=nNextState) Sleep(0); - break; - case SM_RETURN: // -> Return - DisableDebugger(); // disable debugger - nNextState = SM_INVALID; - SetEvent(hEventShutdn); - while (nState!=nNextState) Sleep(0); - nNextState = SM_RETURN; - SetEvent(hEventShutdn); - WaitForSingleObject(hThread,INFINITE); - break; - } - break; - } - return nOldState; -} - -UINT WorkerThread(LPVOID pParam) -{ - LARGE_INTEGER lDummyInt; // sample timer ticks - QueryPerformanceFrequency(&lDummyInt); // init timer ticks - lDummyInt.QuadPart /= SAMPLE; // calculate sample ticks - dwTickRef = lDummyInt.LowPart; // sample timer ticks - _ASSERT(dwTickRef); // tick resolution error - -loop: - while (nNextState == SM_INVALID) // go into invalid state - { - OnToolMacroStop(); // close open keyboard macro handler - CommClose(); // close COM port - nState = SM_INVALID; // in invalid state - WaitForSingleObject(hEventShutdn,INFINITE); - if (nNextState == SM_RETURN) // go into return state - { - nState = SM_RETURN; // in return state - return 0; // kill thread - } - CheckSerial(); // test if UART on - } - while (nNextState == SM_RUN) - { - if (nState != SM_RUN) - { - nState = SM_RUN; - // clear port2 status bits - Chipset.cards_status &= ~(PORT2_PRESENT | PORT2_WRITE); - if (pbyPort2 || Port2) // card plugged in port2 - { - Chipset.cards_status |= PORT2_PRESENT; - - if (bPort2Writeable) // is card writeable - Chipset.cards_status |= PORT2_WRITE; - } - // card detection off and timer running - if ((Chipset.IORam[CARDCTL] & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0) - { - BOOL bNINT2 = Chipset.IORam[SRQ1] == 0 && (Chipset.IORam[SRQ2] & LSRQ) == 0; - BOOL bNINT = (Chipset.IORam[CARDCTL] & SMP) == 0; - - // state of CDT2 - bNINT2 = bNINT2 && (Chipset.cards_status & (P2W|P2C)) != P2C; - // state of CDT1 - bNINT = bNINT && (Chipset.cards_status & (P1W|P1C)) != P1C; - - IOBit(SRQ2,NINT2,bNINT2); - IOBit(SRQ2,NINT,bNINT); - } - RomSwitch(Chipset.Bank_FF); // select HP49G ROM bank and update memory mapping - UpdateContrast(Chipset.contrast); - UpdateDisplayPointers(); - UpdateMainDisplay(); - UpdateMenuDisplay(); - UpdateAnnunciators(0x3F); - // init speed reference - dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); - QueryPerformanceCounter(&lDummyInt); - dwSpeedRef = lDummyInt.LowPart; - SetHP48Time(); // update HP48 time & date - // start display counter/update engine - StartDisplay((BYTE)(((Chipset.IORam[LINECOUNT+1]<<4)|Chipset.IORam[LINECOUNT])&0x3F)); - StartBatMeasure(); // start battery measurement - StartTimers(); - } - PCHANGED; - while (!bInterrupt) - { - if (nDbgState > DBG_OFF) // debugger active - { - Debugger(); - - // if suspended skip next opcode execution - if (nDbgState == DBG_SUSPEND) - { - if (Chipset.Shutdn) break; - continue; - } - } - - EvalOpcode(FASTPTR(Chipset.pc)); // execute opcode - - // check for display update in BW mode - if (!bGrayscale) CheckDisp(!Chipset.Shutdn); - AdjustSpeed(); // adjust emulation speed - } - bInterrupt = FALSE; // be sure to reenter opcode loop - - // enter SHUTDN handler only in RUN mode - if (Chipset.Shutdn && !(nDbgState == DBG_STEPINTO || nDbgState == DBG_STEPOVER)) - { - if (!Chipset.SoftInt) // ignore SHUTDN on interrupt request - WaitForSingleObject(hEventShutdn,INFINITE); - else - Chipset.bShutdnWake = TRUE; // waked by interrupt - - if (Chipset.bShutdnWake) // waked up by timer, keyboard or serial - { - Chipset.bShutdnWake = FALSE; - Chipset.Shutdn = FALSE; - // init speed reference - dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); - QueryPerformanceCounter(&lDummyInt); - dwSpeedRef = lDummyInt.LowPart; - nOpcSlow = 0; // no opcodes to slow down - } - } - if (Chipset.SoftInt) - { - Chipset.SoftInt = FALSE; - if (Chipset.inte) - { - Chipset.inte = FALSE; - rstkpush(Chipset.pc); - Chipset.pc = 0xf; - } - } - } - _ASSERT(nNextState != SM_RUN); - - StopDisplay(); // stop display counter/update - StopBatMeasure(); // stop battery measurement - StopTimers(); - - while (nNextState == SM_SLEEP) // go into sleep state - { - nState = SM_SLEEP; // in sleep state - WaitForSingleObject(hEventShutdn,INFINITE); - } - goto loop; - UNREFERENCED_PARAMETER(pParam); -} +/* + * engine.c + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ +#include "pch.h" +#include "Emu48.h" +#include "Opcodes.h" +#include "io.h" +#include "debugger.h" + +#define SAMPLE 16384 // speed adjust sample frequency + +BOOL bInterrupt = FALSE; +UINT nState = SM_INVALID; +UINT nNextState = SM_RUN; +BOOL bEnableSlow = TRUE; // slow down is enabled +BOOL bRealSpeed = FALSE; +BOOL bKeySlow = FALSE; // slow down for key emulation +BOOL bSoundSlow = FALSE; // slow down for sound emulation +UINT nOpcSlow = 0; // no. of opcodes to slow down + +CHIPSET Chipset; + +TCHAR szSerialWire[16]; // devicename for wire port +TCHAR szSerialIr[16]; // devicename for IR port + +DWORD dwSXCycles = 82; // SX cpu cycles in interval +DWORD dwGXCycles = 123; // GX cpu cycles in interval + +// variables for debugger engine +HANDLE hEventDebug; // event handle to stop cpu thread + +BOOL bDbgAutoStateCtrl = TRUE; // debugger suspend control by SwitchToState() +INT nDbgState = DBG_OFF; // state of debugger + +BOOL bDbgNOP3 = FALSE; // halt on NOP3 (#420 opcode) +BOOL bDbgRPL = FALSE; // halt on RPL entry +BOOL bDbgCode = FALSE; // halt on DOCODE entry + +BOOL bDbgSkipInt = FALSE; // execute interrupt handler + +DWORD dwDbgStopPC = -1; // stop address for goto cursor +DWORD dwDbgRplPC = -1; // stop address for RPL breakpoint + +DWORD dwDbgRstkp; // stack recursion level of step over end +DWORD dwDbgRstk; // possible return address + +DWORD *pdwInstrArray = NULL; // last instruction array +WORD wInstrSize = 256; // size of last instruction array +WORD wInstrWp; // write pointer of instruction array +WORD wInstrRp; // read pointer of instruction array + +VOID (*fnOutTrace)(VOID) = NULL; // callback function for file trace + +static INT nDbgRplBreak = BN_ASM; // flag for RPL breakpoint detection +static INT nDbgOldState = DBG_OFF; // old state of debugger for suspend/resume + +static BOOL bCpuSlow = FALSE; // enable/disable real speed + +static DWORD dwEDbgT2 = 0; // debugger timer2 emulation +static DWORD dwEDbgCycles = 0; // debugger cycle counter + +static DWORD dwOldCyc; // cpu cycles at last event +static DWORD dwSpeedRef; // timer value at last event +static DWORD dwTickRef; // sample timer ticks + +#include "Ops.h" + +// save last instruction in circular instruction buffer +static __inline VOID SaveInstrAddr(DWORD dwAddr) +{ + EnterCriticalSection(&csDbgLock); + { + if (pdwInstrArray) // circular buffer allocated + { + pdwInstrArray[wInstrWp] = dwAddr; + wInstrWp = (wInstrWp + 1) % wInstrSize; + if (wInstrWp == wInstrRp) + wInstrRp = (wInstrRp + 1) % wInstrSize; + } + } + LeaveCriticalSection(&csDbgLock); + return; +} + +static __inline VOID Debugger(VOID) // debugger part +{ + LARGE_INTEGER lDummyInt; // sample timer ticks + BOOL bStopEmulation; + LPBYTE I = FASTPTR(Chipset.pc); // get opcode stream + + UpdateDbgCycleCounter(); // update 64 bit cpu cycle counter + + SaveInstrAddr(Chipset.pc); // save pc in last instruction buffer + if (fnOutTrace != NULL) // has a trace function + { + fnOutTrace(); // write file trace + } + + nDbgRplBreak = BN_ASM; // notify ASM breakpoint + + // check for code breakpoints + bStopEmulation = CheckBreakpoint(Chipset.pc, 1, BP_EXEC); + + // check for memory breakpoints, opcode #14x or #15x + if (I[0] == 0x1 && (I[1] == 0x4 || I[1] == 0x5)) + { + DWORD dwData = (I[2] & 0x1) ? Chipset.d1 : Chipset.d0; + UINT nType = (I[2] & 0x2) ? BP_READ : BP_WRITE; + + DWORD dwRange; + if (I[1] == 0x4) // B,A + { + dwRange = (I[2] & 0x8) ? 2 : 5; + } + else // number of nibbles, (P,WP,XS,X,S,M,W) + { + dwRange = (I[2] & 0x8) ? (I[3]+1) : (F_l[I[3]]); + } + #if defined DEBUG_DEBUGGER + { + TCHAR buffer[256]; + wsprintf(buffer,_T("Memory breakpoint %.5lx, %u\n",dwData,dwRange)); + OutputDebugString(buffer); + } + #endif + bStopEmulation |= CheckBreakpoint(dwData, dwRange, nType); + } + + // check for step cursor + bStopEmulation |= (dwDbgStopPC == Chipset.pc); + + // NOP3, opcode #420 (GOC) + if (bDbgNOP3 && I[0] == 0x4 && I[1] == 0x2 && I[2] == 0x0) + bStopEmulation = TRUE; + + // stop on first instruction of DOCODE object + if (bDbgCode && (Chipset.pc == 0x02DDE || Chipset.pc == 0x02E3C)) + { + // return address + DWORD dwAddr = Chipset.rstk[(Chipset.rstkp-1)&7]; + + _ASSERT(I[0] == 0 && I[1] == 1); // stopped at RTN opcode + + if (MapData(dwAddr) != M_ROM) // address not in ROM + dwDbgStopPC = dwAddr; // then stop + } + + // check for RPL breakpoint + if (dwDbgRplPC == Chipset.pc) + { + dwDbgRplPC = -1; + nDbgRplBreak = bStopEmulation ? BN_ASM_BT : BN_RPL; + bStopEmulation = TRUE; + } + + // RPL breakpoints, PC=(A), opcode #808C or PC=(C), opcode #808E + if (I[0] == 0x8 && I[1] == 0x0 && I[2] == 0x8 && (I[3] == 0xC || I[3] == 0xE )) + { + // get next RPL entry + DWORD dwAddr = Npack((I[3] == 0xC) ? Chipset.A : Chipset.C,5); + + if (bDbgRPL || CheckBreakpoint(dwAddr, 1, BP_RPL)) + { + BYTE byRplPtr[5]; + + Npeek(byRplPtr,dwAddr,5); // get PC address of next opcode + dwDbgRplPC = Npack(byRplPtr,5); // set RPL breakpoint + } + } + + // step over interrupt execution + if (bDbgSkipInt && !bStopEmulation && !Chipset.inte) + return; + + // check for step into + bStopEmulation |= (nDbgState == DBG_STEPINTO); + + // check for step over + bStopEmulation |= (nDbgState == DBG_STEPOVER) && dwDbgRstkp == Chipset.rstkp; + + // check for step out, something was popped from hardware stack + if (nDbgState == DBG_STEPOUT && dwDbgRstkp == Chipset.rstkp) + { + _ASSERT(bStopEmulation == FALSE); + if ((bStopEmulation = (Chipset.pc == dwDbgRstk)) == FALSE) + { + // it was C=RSTK, check for next object popped from hardware stack + dwDbgRstkp = (Chipset.rstkp-1)&7; + dwDbgRstk = Chipset.rstk[dwDbgRstkp]; + } + } + + if (bStopEmulation) // stop condition + { + StopTimers(); // hold timer values when emulator is stopped + if (Chipset.IORam[TIMER2_CTRL]&RUN) // check if timer running + { + if (dwEDbgT2 == Chipset.t2) + { + // cpu cycles for one timer2 tick elapsed + if ((DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwEDbgCycles + >= (SAMPLE / 8192) * (DWORD) T2CYCLES) + { + --Chipset.t2; + // adjust cycles reference + dwEDbgCycles += (SAMPLE / 8192) * T2CYCLES; + } + } + else // new timer2 value + { + // new cycle reference + dwEDbgCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF); + } + + // check rising edge of Bit 8 of timer2 + if ((dwEDbgT2 & 0x100) == 0 && (Chipset.t2 & 0x100) != 0) + Chipset.t1 = (Chipset.t1 - 1) & 0xF; + } + dwEDbgT2 = Chipset.t2; // timer2 check reference value + + // redraw debugger window and stop + NotifyDebugger(nDbgRplBreak); + WaitForSingleObject(hEventDebug,INFINITE); + + StartTimers(); // continue timers + + if (nDbgState >= DBG_OFF) // if debugger is active + { + Chipset.Shutdn = FALSE; + Chipset.bShutdnWake = FALSE; + } + + // init slow down part + dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); + QueryPerformanceCounter(&lDummyInt); + dwSpeedRef = lDummyInt.LowPart; + } + return; +} + +VOID SuspendDebugger(VOID) +{ + // auto control enabled, emulation halted by debugger + if (bDbgAutoStateCtrl && nDbgState > DBG_OFF) + { + nDbgOldState = nDbgState; // save old state + nDbgState = DBG_SUSPEND; // suspend state + SetEvent(hEventDebug); // exit debugger + } + return; +} + +VOID ResumeDebugger(VOID) +{ + // auto control enabled, debugger is suspended + if (bDbgAutoStateCtrl && nDbgState == DBG_SUSPEND) + { + // active RPL breakpoint + if (nDbgRplBreak) dwDbgRplPC = Chipset.pc; + nDbgState = nDbgOldState; // set to old debugger state + if (Chipset.Shutdn) // inside shutdown + SetEvent(hEventShutdn); // leave it to call debugger + } + return; +} + +static __inline VOID CheckDisp(BOOL bSync) +{ + if (disp == 0) return; // no display update need + + // update display when drawing top line or display is off + if (bSync && GetLineCounter() != 0x3F && (Chipset.IORam[0x00]&8)) + return; + + _ASSERT((disp & DISP_POINTER) == 0); // display pointer already updated + if (disp & DISP_MAIN) UpdateMainDisplay(); + if (disp & DISP_MENUE) UpdateMenuDisplay(); + disp = 0; // display updated + return; +} + +static __inline VOID AdjustSpeed(VOID) // adjust emulation speed +{ + // emulation slow down + if ( bEnableSlow + && (bCpuSlow || bKeySlow || bSoundSlow || nOpcSlow > 0)) + { + DWORD dwCycles,dwTicks; + + EnterCriticalSection(&csSlowLock); + { + // cycles elapsed for next check + if ((dwCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF)-dwOldCyc) >= (DWORD) T2CYCLES) + { + LARGE_INTEGER lAct; + do + { + VERIFY(QueryPerformanceCounter(&lAct)); + + // get time difference + dwTicks = lAct.LowPart - dwSpeedRef; + } + // ticks elapsed or negative number (workaround for QueryPerformanceCounter() in Win2k) + while (dwTicks <= dwTickRef || (dwTicks & 0x80000000) != 0); + + dwOldCyc += T2CYCLES; // adjust cycles reference + dwSpeedRef += dwTickRef; // adjust reference time + } + + if (nOpcSlow > 0) --nOpcSlow; // decr. slow down opcode counter + } + LeaveCriticalSection(&csSlowLock); + } + return; +} + +VOID CheckSerial(VOID) +{ + // COM port closed and serial on + if (CommIsOpen() == FALSE && (Chipset.IORam[IOC] & SON) != 0) + { + CommOpen(szSerialWire,szSerialIr); // open COM ports + } + + // COM port opened and serial off + if (CommIsOpen() == TRUE && (Chipset.IORam[IOC] & SON) == 0) + { + CommClose(); // close COM port + } + return; +} + +VOID InitAdjustSpeed(VOID) +{ + // slow down function not initalized + if (!bEnableSlow || (!bCpuSlow && !bKeySlow && !bSoundSlow && nOpcSlow == 0)) + { + LARGE_INTEGER lTime; // sample timer ticks + + EnterCriticalSection(&csSlowLock); + { + // save reference cycles + dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); + QueryPerformanceCounter(&lTime);// get timer ticks + dwSpeedRef = lTime.LowPart; // save reference time + } + LeaveCriticalSection(&csSlowLock); + } + return; +} + +VOID AdjKeySpeed(VOID) // slow down key repeat +{ + WORD i; + BOOL bKey; + + bKey = FALSE; // search for a pressed key + for (i = 0;i < ARRAYSIZEOF(Chipset.Keyboard_Row) && !bKey;++i) + bKey = (Chipset.Keyboard_Row[i] != 0); + + if (bKey) // key pressed + { + InitAdjustSpeed(); // init variables if necessary + } + bKeySlow = bKey; // save new state + return; +} + +VOID SetSpeed(BOOL bAdjust) // set emulation speed +{ + if (bAdjust) // switch to real speed + { + InitAdjustSpeed(); // init variables if necessary + } + bCpuSlow = bAdjust; // save emulation speed + return; +} + +VOID UpdateKdnBit(VOID) // update KDN bit +{ + if ( Chipset.intk + && (Chipset.IORam[TIMER2_CTRL]&RUN) != 0 + && (DWORD) (Chipset.cycles & 0xFFFFFFFF) - Chipset.dwKdnCycles > (DWORD) T2CYCLES * 16) + IOBit(SRQ2,KDN,Chipset.in != 0); + return; +} + +BOOL WaitForSleepState(VOID) // wait for cpu SHUTDN then sleep state +{ + DWORD dwRefTime; + + SuspendDebugger(); // suspend debugger + + dwRefTime = timeGetTime(); + // wait for the SHUTDN command with 1.5 sec timeout + while (timeGetTime() - dwRefTime < 1500L && !Chipset.Shutdn) + Sleep(0); + + if (Chipset.Shutdn) // not timeout, cpu is down + SwitchToState(SM_SLEEP); // go to sleep state + else + ResumeDebugger(); // timeout, resume to debugger + + return SM_SLEEP != nNextState; // state not changed, emulator was busy +} + +UINT SwitchToState(UINT nNewState) +{ + UINT nOldState = nState; + + if (nState == nNewState) return nOldState; + switch (nState) + { + case SM_RUN: // Run + switch (nNewState) + { + case SM_INVALID: // -> Invalid + nNextState = SM_INVALID; + if (Chipset.Shutdn) + SetEvent(hEventShutdn); + else + bInterrupt = TRUE; + SuspendDebugger(); // suspend debugger + while (nState!=nNextState) Sleep(0); + break; + case SM_RETURN: // -> Return + DisableDebugger(); // disable debugger + nNextState = SM_INVALID; + if (Chipset.Shutdn) + SetEvent(hEventShutdn); + else + bInterrupt = TRUE; + while (nState!=nNextState) Sleep(0); + nNextState = SM_RETURN; + SetEvent(hEventShutdn); + WaitForSingleObject(hThread,INFINITE); + break; + case SM_SLEEP: // -> Sleep + nNextState = SM_SLEEP; + bInterrupt = TRUE; // exit main loop + SuspendDebugger(); // suspend debugger + SetEvent(hEventShutdn); // exit shutdown + while (nState!=nNextState) Sleep(0); + bInterrupt = FALSE; + ResetEvent(hEventDebug); + ResetEvent(hEventShutdn); + break; + } + break; + case SM_INVALID: // Invalid + switch (nNewState) + { + case SM_RUN: // -> Run + nNextState = SM_RUN; + // don't enter opcode loop on interrupt request + bInterrupt = Chipset.Shutdn || Chipset.SoftInt; + ResumeDebugger(); + SetEvent(hEventShutdn); + while (nState!=nNextState) Sleep(0); + break; + case SM_RETURN: // -> Return + DisableDebugger(); // disable debugger + nNextState = SM_RETURN; + SetEvent(hEventShutdn); + WaitForSingleObject(hThread,INFINITE); + break; + case SM_SLEEP: // -> Sleep + nNextState = SM_SLEEP; + SetEvent(hEventShutdn); + while (nState!=nNextState) Sleep(0); + break; + } + break; + case SM_SLEEP: // Sleep + switch (nNewState) + { + case SM_RUN: // -> Run + nNextState = SM_RUN; + // don't enter opcode loop on interrupt request + bInterrupt = (nDbgState == DBG_OFF) && (Chipset.Shutdn || Chipset.SoftInt); + ResumeDebugger(); + SetEvent(hEventShutdn); // leave sleep state + break; + case SM_INVALID: // -> Invalid + nNextState = SM_INVALID; + SetEvent(hEventShutdn); + while (nState!=nNextState) Sleep(0); + break; + case SM_RETURN: // -> Return + DisableDebugger(); // disable debugger + nNextState = SM_INVALID; + SetEvent(hEventShutdn); + while (nState!=nNextState) Sleep(0); + nNextState = SM_RETURN; + SetEvent(hEventShutdn); + WaitForSingleObject(hThread,INFINITE); + break; + } + break; + } + return nOldState; +} + +UINT WorkerThread(LPVOID pParam) +{ + LARGE_INTEGER lDummyInt; // sample timer ticks + QueryPerformanceFrequency(&lDummyInt); // init timer ticks + lDummyInt.QuadPart /= SAMPLE; // calculate sample ticks + dwTickRef = lDummyInt.LowPart; // sample timer ticks + _ASSERT(dwTickRef); // tick resolution error + +loop: + while (nNextState == SM_INVALID) // go into invalid state + { + OnToolMacroStop(); // close open keyboard macro handler + CommClose(); // close COM port + nState = SM_INVALID; // in invalid state + WaitForSingleObject(hEventShutdn,INFINITE); + if (nNextState == SM_RETURN) // go into return state + { + nState = SM_RETURN; // in return state + return 0; // kill thread + } + CheckSerial(); // test if UART on + } + while (nNextState == SM_RUN) + { + if (nState != SM_RUN) + { + nState = SM_RUN; + // clear port2 status bits + Chipset.cards_status &= ~(PORT2_PRESENT | PORT2_WRITE); + if (pbyPort2 || Port2) // card plugged in port2 + { + Chipset.cards_status |= PORT2_PRESENT; + + if (bPort2Writeable) // is card writeable + Chipset.cards_status |= PORT2_WRITE; + } + // card detection off and timer running + if ((Chipset.IORam[CARDCTL] & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0) + { + BOOL bNINT2 = Chipset.IORam[SRQ1] == 0 && (Chipset.IORam[SRQ2] & LSRQ) == 0; + BOOL bNINT = (Chipset.IORam[CARDCTL] & SMP) == 0; + + // state of CDT2 + bNINT2 = bNINT2 && (Chipset.cards_status & (P2W|P2C)) != P2C; + // state of CDT1 + bNINT = bNINT && (Chipset.cards_status & (P1W|P1C)) != P1C; + + IOBit(SRQ2,NINT2,bNINT2); + IOBit(SRQ2,NINT,bNINT); + } + RomSwitch(Chipset.Bank_FF); // select HP49G ROM bank and update memory mapping + UpdateContrast(Chipset.contrast); + UpdateDisplayPointers(); + UpdateMainDisplay(); + UpdateMenuDisplay(); + UpdateAnnunciators(0x3F); + // init speed reference + dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); + QueryPerformanceCounter(&lDummyInt); + dwSpeedRef = lDummyInt.LowPart; + SetHP48Time(); // update HP48 time & date + // start display counter/update engine + StartDisplay((BYTE)(((Chipset.IORam[LINECOUNT+1]<<4)|Chipset.IORam[LINECOUNT])&0x3F)); + StartBatMeasure(); // start battery measurement + StartTimers(); + } + PCHANGED; + while (!bInterrupt) + { + if (nDbgState > DBG_OFF) // debugger active + { + Debugger(); + + // if suspended skip next opcode execution + if (nDbgState == DBG_SUSPEND) + { + if (Chipset.Shutdn) break; + continue; + } + } + + EvalOpcode(FASTPTR(Chipset.pc)); // execute opcode + + // check for display update in BW mode + if (!bGrayscale) CheckDisp(!Chipset.Shutdn); + AdjustSpeed(); // adjust emulation speed + } + bInterrupt = FALSE; // be sure to reenter opcode loop + + // enter SHUTDN handler only in RUN mode + if (Chipset.Shutdn && !(nDbgState == DBG_STEPINTO || nDbgState == DBG_STEPOVER)) + { + if (!Chipset.SoftInt) // ignore SHUTDN on interrupt request + WaitForSingleObject(hEventShutdn,INFINITE); + else + Chipset.bShutdnWake = TRUE; // waked by interrupt + + if (Chipset.bShutdnWake) // waked up by timer, keyboard or serial + { + Chipset.bShutdnWake = FALSE; + Chipset.Shutdn = FALSE; + // init speed reference + dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); + QueryPerformanceCounter(&lDummyInt); + dwSpeedRef = lDummyInt.LowPart; + nOpcSlow = 0; // no opcodes to slow down + } + } + if (Chipset.SoftInt) + { + Chipset.SoftInt = FALSE; + if (Chipset.inte) + { + Chipset.inte = FALSE; + rstkpush(Chipset.pc); + Chipset.pc = 0xf; + } + } + } + _ASSERT(nNextState != SM_RUN); + + StopDisplay(); // stop display counter/update + StopBatMeasure(); // stop battery measurement + StopTimers(); + + while (nNextState == SM_SLEEP) // go into sleep state + { + nState = SM_SLEEP; // in sleep state + WaitForSingleObject(hEventShutdn,INFINITE); + } + goto loop; + UNREFERENCED_PARAMETER(pParam); +} diff --git a/Sources/Emu48/Emu48.vcxproj b/Sources/Emu48/Emu48.vcxproj index bd73f8e..1031c64 100644 --- a/Sources/Emu48/Emu48.vcxproj +++ b/Sources/Emu48/Emu48.vcxproj @@ -27,24 +27,24 @@ Application - v142 + v143 false Unicode Application - v142 + v143 false Unicode Application - v142 + v143 false Application - v142 + v143 false diff --git a/Sources/Emu48/FETCH.C b/Sources/Emu48/FETCH.C new file mode 100644 index 0000000..52def6a --- /dev/null +++ b/Sources/Emu48/FETCH.C @@ -0,0 +1,778 @@ +/* + * fetch.c + * + * This file is part of Emu48 + * + * Copyright (C) 1999 Christoph Gießelink + * + */ +#include "pch.h" +#include "Opcodes.h" + +#define F 0xFF // F = function + +typedef const struct +{ + LPCVOID pLnk; + const DWORD dwTyp; +} JMPTAB, *PJMPTAB; + +// jump tables +static JMPTAB oF_[] = +{ + { (LPCVOID) oF0, F }, + { (LPCVOID) oF1, F }, + { (LPCVOID) oF2, F }, + { (LPCVOID) oF3, F }, + { (LPCVOID) oF4, F }, + { (LPCVOID) oF5, F }, + { (LPCVOID) oF6, F }, + { (LPCVOID) oF7, F }, + { (LPCVOID) oF8, F }, + { (LPCVOID) oF9, F }, + { (LPCVOID) oFA, F }, + { (LPCVOID) oFB, F }, + { (LPCVOID) oFC, F }, + { (LPCVOID) oFD, F }, + { (LPCVOID) oFE, F }, + { (LPCVOID) oFF, F } +}; + +static JMPTAB oE_[] = +{ + { (LPCVOID) oE0, F }, + { (LPCVOID) oE1, F }, + { (LPCVOID) oE2, F }, + { (LPCVOID) oE3, F }, + { (LPCVOID) oE4, F }, + { (LPCVOID) oE5, F }, + { (LPCVOID) oE6, F }, + { (LPCVOID) oE7, F }, + { (LPCVOID) oE8, F }, + { (LPCVOID) oE9, F }, + { (LPCVOID) oEA, F }, + { (LPCVOID) oEB, F }, + { (LPCVOID) oEC, F }, + { (LPCVOID) oED, F }, + { (LPCVOID) oEE, F }, + { (LPCVOID) oEF, F } +}; + +static JMPTAB oD_[] = +{ + { (LPCVOID) oD0, F }, + { (LPCVOID) oD1, F }, + { (LPCVOID) oD2, F }, + { (LPCVOID) oD3, F }, + { (LPCVOID) oD4, F }, + { (LPCVOID) oD5, F }, + { (LPCVOID) oD6, F }, + { (LPCVOID) oD7, F }, + { (LPCVOID) oD8, F }, + { (LPCVOID) oD9, F }, + { (LPCVOID) oDA, F }, + { (LPCVOID) oDB, F }, + { (LPCVOID) oDC, F }, + { (LPCVOID) oDD, F }, + { (LPCVOID) oDE, F }, + { (LPCVOID) oDF, F } +}; + +static JMPTAB oC_[] = +{ + { (LPCVOID) oC0, F }, + { (LPCVOID) oC1, F }, + { (LPCVOID) oC2, F }, + { (LPCVOID) oC3, F }, + { (LPCVOID) oC4, F }, + { (LPCVOID) oC5, F }, + { (LPCVOID) oC6, F }, + { (LPCVOID) oC7, F }, + { (LPCVOID) oC8, F }, + { (LPCVOID) oC9, F }, + { (LPCVOID) oCA, F }, + { (LPCVOID) oCB, F }, + { (LPCVOID) oCC, F }, + { (LPCVOID) oCD, F }, + { (LPCVOID) oCE, F }, + { (LPCVOID) oCF, F } +}; + +static JMPTAB oBb_[] = +{ + { (LPCVOID) oBb0, F }, + { (LPCVOID) oBb1, F }, + { (LPCVOID) oBb2, F }, + { (LPCVOID) oBb3, F }, + { (LPCVOID) oBb4, F }, + { (LPCVOID) oBb5, F }, + { (LPCVOID) oBb6, F }, + { (LPCVOID) oBb7, F }, + { (LPCVOID) oBb8, F }, + { (LPCVOID) oBb9, F }, + { (LPCVOID) oBbA, F }, + { (LPCVOID) oBbB, F }, + { (LPCVOID) oBbC, F }, + { (LPCVOID) oBbD, F }, + { (LPCVOID) oBbE, F }, + { (LPCVOID) oBbF, F } +}; + +static JMPTAB oBa_[] = +{ + { (LPCVOID) oBa0, F }, + { (LPCVOID) oBa1, F }, + { (LPCVOID) oBa2, F }, + { (LPCVOID) oBa3, F }, + { (LPCVOID) oBa4, F }, + { (LPCVOID) oBa5, F }, + { (LPCVOID) oBa6, F }, + { (LPCVOID) oBa7, F }, + { (LPCVOID) oBa8, F }, + { (LPCVOID) oBa9, F }, + { (LPCVOID) oBaA, F }, + { (LPCVOID) oBaB, F }, + { (LPCVOID) oBaC, F }, + { (LPCVOID) oBaD, F }, + { (LPCVOID) oBaE, F }, + { (LPCVOID) oBaF, F } +}; + +static JMPTAB oB_[] = +{ + { (LPCVOID) oBa_, 2 }, + { (LPCVOID) oBa_, 2 }, + { (LPCVOID) oBa_, 2 }, + { (LPCVOID) oBa_, 2 }, + { (LPCVOID) oBa_, 2 }, + { (LPCVOID) oBa_, 2 }, + { (LPCVOID) oBa_, 2 }, + { (LPCVOID) oBa_, 2 }, + { (LPCVOID) oBb_, 2 }, + { (LPCVOID) oBb_, 2 }, + { (LPCVOID) oBb_, 2 }, + { (LPCVOID) oBb_, 2 }, + { (LPCVOID) oBb_, 2 }, + { (LPCVOID) oBb_, 2 }, + { (LPCVOID) oBb_, 2 }, + { (LPCVOID) oBb_, 2 } +}; + +static JMPTAB oAb_[] = +{ + { (LPCVOID) oAb0, F }, + { (LPCVOID) oAb1, F }, + { (LPCVOID) oAb2, F }, + { (LPCVOID) oAb3, F }, + { (LPCVOID) oAb4, F }, + { (LPCVOID) oAb5, F }, + { (LPCVOID) oAb6, F }, + { (LPCVOID) oAb7, F }, + { (LPCVOID) oAb8, F }, + { (LPCVOID) oAb9, F }, + { (LPCVOID) oAbA, F }, + { (LPCVOID) oAbB, F }, + { (LPCVOID) oAbC, F }, + { (LPCVOID) oAbD, F }, + { (LPCVOID) oAbE, F }, + { (LPCVOID) oAbF, F } +}; + +static JMPTAB oAa_[] = +{ + { (LPCVOID) oAa0, F }, + { (LPCVOID) oAa1, F }, + { (LPCVOID) oAa2, F }, + { (LPCVOID) oAa3, F }, + { (LPCVOID) oAa4, F }, + { (LPCVOID) oAa5, F }, + { (LPCVOID) oAa6, F }, + { (LPCVOID) oAa7, F }, + { (LPCVOID) oAa8, F }, + { (LPCVOID) oAa9, F }, + { (LPCVOID) oAaA, F }, + { (LPCVOID) oAaB, F }, + { (LPCVOID) oAaC, F }, + { (LPCVOID) oAaD, F }, + { (LPCVOID) oAaE, F }, + { (LPCVOID) oAaF, F } +}; + +static JMPTAB oA_[] = +{ + { (LPCVOID) oAa_, 2 }, + { (LPCVOID) oAa_, 2 }, + { (LPCVOID) oAa_, 2 }, + { (LPCVOID) oAa_, 2 }, + { (LPCVOID) oAa_, 2 }, + { (LPCVOID) oAa_, 2 }, + { (LPCVOID) oAa_, 2 }, + { (LPCVOID) oAa_, 2 }, + { (LPCVOID) oAb_, 2 }, + { (LPCVOID) oAb_, 2 }, + { (LPCVOID) oAb_, 2 }, + { (LPCVOID) oAb_, 2 }, + { (LPCVOID) oAb_, 2 }, + { (LPCVOID) oAb_, 2 }, + { (LPCVOID) oAb_, 2 }, + { (LPCVOID) oAb_, 2 } +}; + +static JMPTAB o9b_[] = +{ + { (LPCVOID) o9b0, F }, + { (LPCVOID) o9b1, F }, + { (LPCVOID) o9b2, F }, + { (LPCVOID) o9b3, F }, + { (LPCVOID) o9b4, F }, + { (LPCVOID) o9b5, F }, + { (LPCVOID) o9b6, F }, + { (LPCVOID) o9b7, F }, + { (LPCVOID) o9b8, F }, + { (LPCVOID) o9b9, F }, + { (LPCVOID) o9bA, F }, + { (LPCVOID) o9bB, F }, + { (LPCVOID) o9bC, F }, + { (LPCVOID) o9bD, F }, + { (LPCVOID) o9bE, F }, + { (LPCVOID) o9bF, F } +}; + +static JMPTAB o9a_[] = +{ + { (LPCVOID) o9a0, F }, + { (LPCVOID) o9a1, F }, + { (LPCVOID) o9a2, F }, + { (LPCVOID) o9a3, F }, + { (LPCVOID) o9a4, F }, + { (LPCVOID) o9a5, F }, + { (LPCVOID) o9a6, F }, + { (LPCVOID) o9a7, F }, + { (LPCVOID) o9a8, F }, + { (LPCVOID) o9a9, F }, + { (LPCVOID) o9aA, F }, + { (LPCVOID) o9aB, F }, + { (LPCVOID) o9aC, F }, + { (LPCVOID) o9aD, F }, + { (LPCVOID) o9aE, F }, + { (LPCVOID) o9aF, F } +}; + +static JMPTAB o9_[] = +{ + { (LPCVOID) o9a_, 2 }, + { (LPCVOID) o9a_, 2 }, + { (LPCVOID) o9a_, 2 }, + { (LPCVOID) o9a_, 2 }, + { (LPCVOID) o9a_, 2 }, + { (LPCVOID) o9a_, 2 }, + { (LPCVOID) o9a_, 2 }, + { (LPCVOID) o9a_, 2 }, + { (LPCVOID) o9b_, 2 }, + { (LPCVOID) o9b_, 2 }, + { (LPCVOID) o9b_, 2 }, + { (LPCVOID) o9b_, 2 }, + { (LPCVOID) o9b_, 2 }, + { (LPCVOID) o9b_, 2 }, + { (LPCVOID) o9b_, 2 }, + { (LPCVOID) o9b_, 2 } +}; + +static JMPTAB o8B_[] = +{ + { (LPCVOID) o8B0, F }, + { (LPCVOID) o8B1, F }, + { (LPCVOID) o8B2, F }, + { (LPCVOID) o8B3, F }, + { (LPCVOID) o8B4, F }, + { (LPCVOID) o8B5, F }, + { (LPCVOID) o8B6, F }, + { (LPCVOID) o8B7, F }, + { (LPCVOID) o8B8, F }, + { (LPCVOID) o8B9, F }, + { (LPCVOID) o8BA, F }, + { (LPCVOID) o8BB, F }, + { (LPCVOID) o8BC, F }, + { (LPCVOID) o8BD, F }, + { (LPCVOID) o8BE, F }, + { (LPCVOID) o8BF, F } +}; + +static JMPTAB o8A_[] = +{ + { (LPCVOID) o8A0, F }, + { (LPCVOID) o8A1, F }, + { (LPCVOID) o8A2, F }, + { (LPCVOID) o8A3, F }, + { (LPCVOID) o8A4, F }, + { (LPCVOID) o8A5, F }, + { (LPCVOID) o8A6, F }, + { (LPCVOID) o8A7, F }, + { (LPCVOID) o8A8, F }, + { (LPCVOID) o8A9, F }, + { (LPCVOID) o8AA, F }, + { (LPCVOID) o8AB, F }, + { (LPCVOID) o8AC, F }, + { (LPCVOID) o8AD, F }, + { (LPCVOID) o8AE, F }, + { (LPCVOID) o8AF, F } +}; + +static JMPTAB o81B_[] = +{ + { (LPCVOID) o_invalid4, F }, + { (LPCVOID) o_invalid4, F }, + { (LPCVOID) o81B2, F }, + { (LPCVOID) o81B3, F }, + { (LPCVOID) o81B4, F }, + { (LPCVOID) o81B5, F }, + { (LPCVOID) o81B6, F }, + { (LPCVOID) o81B7, F }, + { (LPCVOID) o_invalid4, F }, + { (LPCVOID) o_invalid4, F }, + { (LPCVOID) o_invalid4, F }, + { (LPCVOID) o_invalid4, F }, + { (LPCVOID) o_invalid4, F }, + { (LPCVOID) o_invalid4, F }, + { (LPCVOID) o_invalid4, F }, + { (LPCVOID) o_invalid4, F } +}; + +static JMPTAB o81Af2_[] = +{ + { (LPCVOID) o81Af20, F }, + { (LPCVOID) o81Af21, F }, + { (LPCVOID) o81Af22, F }, + { (LPCVOID) o81Af23, F }, + { (LPCVOID) o81Af24, F }, + { (LPCVOID) o81Af21, F }, + { (LPCVOID) o81Af22, F }, + { (LPCVOID) o81Af23, F }, + { (LPCVOID) o81Af28, F }, + { (LPCVOID) o81Af29, F }, + { (LPCVOID) o81Af2A, F }, + { (LPCVOID) o81Af2B, F }, + { (LPCVOID) o81Af2C, F }, + { (LPCVOID) o81Af29, F }, + { (LPCVOID) o81Af2A, F }, + { (LPCVOID) o81Af2B, F } +}; + +static JMPTAB o81Af1_[] = +{ + { (LPCVOID) o81Af10, F }, + { (LPCVOID) o81Af11, F }, + { (LPCVOID) o81Af12, F }, + { (LPCVOID) o81Af13, F }, + { (LPCVOID) o81Af14, F }, + { (LPCVOID) o81Af11, F }, + { (LPCVOID) o81Af12, F }, + { (LPCVOID) o81Af13, F }, + { (LPCVOID) o81Af18, F }, + { (LPCVOID) o81Af19, F }, + { (LPCVOID) o81Af1A, F }, + { (LPCVOID) o81Af1B, F }, + { (LPCVOID) o81Af1C, F }, + { (LPCVOID) o81Af19, F }, + { (LPCVOID) o81Af1A, F }, + { (LPCVOID) o81Af1B, F } +}; + +static JMPTAB o81Af0_[] = +{ + { (LPCVOID) o81Af00, F }, + { (LPCVOID) o81Af01, F }, + { (LPCVOID) o81Af02, F }, + { (LPCVOID) o81Af03, F }, + { (LPCVOID) o81Af04, F }, + { (LPCVOID) o81Af01, F }, + { (LPCVOID) o81Af02, F }, + { (LPCVOID) o81Af03, F }, + { (LPCVOID) o81Af08, F }, + { (LPCVOID) o81Af09, F }, + { (LPCVOID) o81Af0A, F }, + { (LPCVOID) o81Af0B, F }, + { (LPCVOID) o81Af0C, F }, + { (LPCVOID) o81Af09, F }, + { (LPCVOID) o81Af0A, F }, + { (LPCVOID) o81Af0B, F } +}; + +static JMPTAB o81A_[] = +{ + { (LPCVOID) o81Af0_, 5 }, + { (LPCVOID) o81Af1_, 5 }, + { (LPCVOID) o81Af2_, 5 }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F } +}; + +static JMPTAB o819_[] = +{ + { (LPCVOID) o819f0, F }, + { (LPCVOID) o819f1, F }, + { (LPCVOID) o819f2, F }, + { (LPCVOID) o819f3, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F } +}; + +static JMPTAB o818_[] = +{ + { (LPCVOID) o818f0x, F }, + { (LPCVOID) o818f1x, F }, + { (LPCVOID) o818f2x, F }, + { (LPCVOID) o818f3x, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o818f8x, F }, + { (LPCVOID) o818f9x, F }, + { (LPCVOID) o818fAx, F }, + { (LPCVOID) o818fBx, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F }, + { (LPCVOID) o_invalid6, F } +}; + +static JMPTAB o81_[] = +{ + { (LPCVOID) o810, F }, + { (LPCVOID) o811, F }, + { (LPCVOID) o812, F }, + { (LPCVOID) o813, F }, + { (LPCVOID) o814, F }, + { (LPCVOID) o815, F }, + { (LPCVOID) o816, F }, + { (LPCVOID) o817, F }, + { (LPCVOID) o818_, 4 }, + { (LPCVOID) o819_, 4 }, + { (LPCVOID) o81A_, 4 }, + { (LPCVOID) o81B_, 3 }, + { (LPCVOID) o81C, F }, + { (LPCVOID) o81D, F }, + { (LPCVOID) o81E, F }, + { (LPCVOID) o81F, F } +}; + +static JMPTAB o8081_[] = +{ + { (LPCVOID) o80810, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F }, + { (LPCVOID) o_invalid5, F } +}; + +static JMPTAB o808_[] = +{ + { (LPCVOID) o8080, F }, + { (LPCVOID) o8081_, 4 }, + { (LPCVOID) o8082X, F }, + { (LPCVOID) o8083, F }, + { (LPCVOID) o8084n, F }, + { (LPCVOID) o8085n, F }, + { (LPCVOID) o8086n, F }, + { (LPCVOID) o8087n, F }, + { (LPCVOID) o8088n, F }, + { (LPCVOID) o8089n, F }, + { (LPCVOID) o808An, F }, + { (LPCVOID) o808Bn, F }, + { (LPCVOID) o808C, F }, + { (LPCVOID) o808D, F }, + { (LPCVOID) o808E, F }, + { (LPCVOID) o808F, F } +}; + +static JMPTAB o80_[] = +{ + { (LPCVOID) o800, F }, + { (LPCVOID) o801, F }, + { (LPCVOID) o802, F }, + { (LPCVOID) o803, F }, + { (LPCVOID) o804, F }, + { (LPCVOID) o805, F }, + { (LPCVOID) o806, F }, + { (LPCVOID) o807, F }, + { (LPCVOID) o808_, 3 }, + { (LPCVOID) o809, F }, + { (LPCVOID) o80A, F }, + { (LPCVOID) o80B, F }, + { (LPCVOID) o80Cn, F }, + { (LPCVOID) o80Dn, F }, + { (LPCVOID) o80E, F }, + { (LPCVOID) o80Fn, F } +}; + +static JMPTAB o8_[] = +{ + { (LPCVOID) o80_, 2 }, + { (LPCVOID) o81_, 2 }, + { (LPCVOID) o82n, F }, + { (LPCVOID) o83n, F }, + { (LPCVOID) o84n, F }, + { (LPCVOID) o85n, F }, + { (LPCVOID) o86n, F }, + { (LPCVOID) o87n, F }, + { (LPCVOID) o88n, F }, + { (LPCVOID) o89n, F }, + { (LPCVOID) o8A_, 2 }, + { (LPCVOID) o8B_, 2 }, + { (LPCVOID) o8Cd4, F }, + { (LPCVOID) o8Dd5, F }, + { (LPCVOID) o8Ed4, F }, + { (LPCVOID) o8Fd5, F } +}; + +static JMPTAB o15_[] = +{ + { (LPCVOID) o150a, F }, + { (LPCVOID) o151a, F }, + { (LPCVOID) o152a, F }, + { (LPCVOID) o153a, F }, + { (LPCVOID) o154a, F }, + { (LPCVOID) o155a, F }, + { (LPCVOID) o156a, F }, + { (LPCVOID) o157a, F }, + { (LPCVOID) o158x, F }, + { (LPCVOID) o159x, F }, + { (LPCVOID) o15Ax, F }, + { (LPCVOID) o15Bx, F }, + { (LPCVOID) o15Cx, F }, + { (LPCVOID) o15Dx, F }, + { (LPCVOID) o15Ex, F }, + { (LPCVOID) o15Fx, F } +}; + +static JMPTAB o14_[] = +{ + { (LPCVOID) o140, F }, + { (LPCVOID) o141, F }, + { (LPCVOID) o142, F }, + { (LPCVOID) o143, F }, + { (LPCVOID) o144, F }, + { (LPCVOID) o145, F }, + { (LPCVOID) o146, F }, + { (LPCVOID) o147, F }, + { (LPCVOID) o148, F }, + { (LPCVOID) o149, F }, + { (LPCVOID) o14A, F }, + { (LPCVOID) o14B, F }, + { (LPCVOID) o14C, F }, + { (LPCVOID) o14D, F }, + { (LPCVOID) o14E, F }, + { (LPCVOID) o14F, F } +}; + +static JMPTAB o13_[] = +{ + { (LPCVOID) o130, F }, + { (LPCVOID) o131, F }, + { (LPCVOID) o132, F }, + { (LPCVOID) o133, F }, + { (LPCVOID) o134, F }, + { (LPCVOID) o135, F }, + { (LPCVOID) o136, F }, + { (LPCVOID) o137, F }, + { (LPCVOID) o138, F }, + { (LPCVOID) o139, F }, + { (LPCVOID) o13A, F }, + { (LPCVOID) o13B, F }, + { (LPCVOID) o13C, F }, + { (LPCVOID) o13D, F }, + { (LPCVOID) o13E, F }, + { (LPCVOID) o13F, F } +}; + +static JMPTAB o12_[] = +{ + { (LPCVOID) o120, F }, + { (LPCVOID) o121, F }, + { (LPCVOID) o122, F }, + { (LPCVOID) o123, F }, + { (LPCVOID) o124, F }, + { (LPCVOID) o121, F }, + { (LPCVOID) o122, F }, + { (LPCVOID) o123, F }, + { (LPCVOID) o128, F }, + { (LPCVOID) o129, F }, + { (LPCVOID) o12A, F }, + { (LPCVOID) o12B, F }, + { (LPCVOID) o12C, F }, + { (LPCVOID) o129, F }, + { (LPCVOID) o12A, F }, + { (LPCVOID) o12B, F } +}; + +static JMPTAB o11_[] = +{ + { (LPCVOID) o110, F }, + { (LPCVOID) o111, F }, + { (LPCVOID) o112, F }, + { (LPCVOID) o113, F }, + { (LPCVOID) o114, F }, + { (LPCVOID) o111, F }, + { (LPCVOID) o112, F }, + { (LPCVOID) o113, F }, + { (LPCVOID) o118, F }, + { (LPCVOID) o119, F }, + { (LPCVOID) o11A, F }, + { (LPCVOID) o11B, F }, + { (LPCVOID) o11C, F }, + { (LPCVOID) o119, F }, + { (LPCVOID) o11A, F }, + { (LPCVOID) o11B, F } +}; + +static JMPTAB o10_[] = +{ + { (LPCVOID) o100, F }, + { (LPCVOID) o101, F }, + { (LPCVOID) o102, F }, + { (LPCVOID) o103, F }, + { (LPCVOID) o104, F }, + { (LPCVOID) o101, F }, + { (LPCVOID) o102, F }, + { (LPCVOID) o103, F }, + { (LPCVOID) o108, F }, + { (LPCVOID) o109, F }, + { (LPCVOID) o10A, F }, + { (LPCVOID) o10B, F }, + { (LPCVOID) o10C, F }, + { (LPCVOID) o109, F }, + { (LPCVOID) o10A, F }, + { (LPCVOID) o10B, F } +}; + +static JMPTAB o1_[] = +{ + { (LPCVOID) o10_, 2 }, + { (LPCVOID) o11_, 2 }, + { (LPCVOID) o12_, 2 }, + { (LPCVOID) o13_, 2 }, + { (LPCVOID) o14_, 2 }, + { (LPCVOID) o15_, 2 }, + { (LPCVOID) o16x, F }, + { (LPCVOID) o17x, F }, + { (LPCVOID) o18x, F }, + { (LPCVOID) o19d2, F }, + { (LPCVOID) o1Ad4, F }, + { (LPCVOID) o1Bd5, F }, + { (LPCVOID) o1Cx, F }, + { (LPCVOID) o1Dd2, F }, + { (LPCVOID) o1Ed4, F }, + { (LPCVOID) o1Fd5, F } +}; + +static JMPTAB o0E_[] = +{ + { (LPCVOID) o0Ef0, F }, + { (LPCVOID) o0Ef1, F }, + { (LPCVOID) o0Ef2, F }, + { (LPCVOID) o0Ef3, F }, + { (LPCVOID) o0Ef4, F }, + { (LPCVOID) o0Ef5, F }, + { (LPCVOID) o0Ef6, F }, + { (LPCVOID) o0Ef7, F }, + { (LPCVOID) o0Ef8, F }, + { (LPCVOID) o0Ef9, F }, + { (LPCVOID) o0EfA, F }, + { (LPCVOID) o0EfB, F }, + { (LPCVOID) o0EfC, F }, + { (LPCVOID) o0EfD, F }, + { (LPCVOID) o0EfE, F }, + { (LPCVOID) o0EfF, F } +}; + +static JMPTAB o0_[] = +{ + { (LPCVOID) o00, F }, + { (LPCVOID) o01, F }, + { (LPCVOID) o02, F }, + { (LPCVOID) o03, F }, + { (LPCVOID) o04, F }, + { (LPCVOID) o05, F }, + { (LPCVOID) o06, F }, + { (LPCVOID) o07, F }, + { (LPCVOID) o08, F }, + { (LPCVOID) o09, F }, + { (LPCVOID) o0A, F }, + { (LPCVOID) o0B, F }, + { (LPCVOID) o0C, F }, + { (LPCVOID) o0D, F }, + { (LPCVOID) o0E_, 3 }, + { (LPCVOID) o0F, F } +}; + +static JMPTAB o_[] = +{ + { (LPCVOID) o0_, 1 }, + { (LPCVOID) o1_, 1 }, + { (LPCVOID) o2n, F }, + { (LPCVOID) o3X, F }, + { (LPCVOID) o4d2, F }, + { (LPCVOID) o5d2, F }, + { (LPCVOID) o6d3, F }, + { (LPCVOID) o7d3, F }, + { (LPCVOID) o8_, 1 }, + { (LPCVOID) o9_, 1 }, + { (LPCVOID) oA_, 1 }, + { (LPCVOID) oB_, 1 }, + { (LPCVOID) oC_, 1 }, + { (LPCVOID) oD_, 1 }, + { (LPCVOID) oE_, 1 }, + { (LPCVOID) oF_, 1 } +}; + +// opcode dispatcher +VOID EvalOpcode(LPBYTE I) +{ + DWORD dwIndex = 0; + PJMPTAB pJmpTab = o_; + + do + { + _ASSERT(I[dwIndex] <= 0xf); // found packed data + pJmpTab = &pJmpTab[I[dwIndex]]; // table entry by opcode + dwIndex = pJmpTab->dwTyp; // next pointer type + pJmpTab = (PJMPTAB) pJmpTab->pLnk; // next pointer to table/function + } + while (dwIndex != F); // reference to table? -> again + + ((VOID (*)(LPBYTE)) pJmpTab)(I); // call function + return; +} diff --git a/Sources/Emu48/files.c b/Sources/Emu48/FILES.C similarity index 96% rename from Sources/Emu48/files.c rename to Sources/Emu48/FILES.C index ccb8d75..1666492 100644 --- a/Sources/Emu48/files.c +++ b/Sources/Emu48/FILES.C @@ -1,2821 +1,2821 @@ -/* - * files.c - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ -#include "pch.h" -#include "emu48.h" -#include "ops.h" -#include "io.h" // I/O register definitions -#include "kml.h" -#include "i28f160.h" // flash support -#include "debugger.h" -#include "lodepng.h" - -#pragma intrinsic(abs,labs) - -TCHAR szEmuDirectory[MAX_PATH]; -TCHAR szCurrentDirectory[MAX_PATH]; -TCHAR szCurrentKml[MAX_PATH]; -TCHAR szBackupKml[MAX_PATH]; -TCHAR szCurrentFilename[MAX_PATH]; -TCHAR szBackupFilename[MAX_PATH]; -TCHAR szBufferFilename[MAX_PATH]; -TCHAR szPort2Filename[MAX_PATH]; - -BOOL bDocumentAvail = FALSE; // document not available - -BYTE cCurrentRomType = 0; // Model -> hardware -UINT nCurrentClass = 0; // Class -> derivate - -LPBYTE Port0 = NULL; -LPBYTE Port1 = NULL; -LPBYTE Port2 = NULL; - -LPBYTE pbyRom = NULL; -BOOL bRomWriteable = TRUE; // flag if ROM writeable -DWORD dwRomSize = 0; -LPBYTE pbyRomDirtyPage = NULL; -DWORD dwRomDirtyPageSize = 0; -WORD wRomCrc = 0; // fingerprint of patched ROM -BOOL bRomCrcCorrection = FALSE; // ROM CRC correction disabled - -LPBYTE pbyPort2 = NULL; -BOOL bPort2Writeable = FALSE; -BOOL bPort2IsShared = FALSE; -DWORD dwPort2Size = 0; // size of mapped port2 -DWORD dwPort2Mask = 0; -WORD wPort2Crc = 0; // fingerprint of port2 - -BOOL bBackup = FALSE; - -static HANDLE hRomFile = NULL; -static HANDLE hPort2File = NULL; -static HANDLE hPort2Map = NULL; -static HANDLE hCurrentFile = NULL; - -// valid document signatures -static CONST LPBYTE bySignature[] = -{ - (CONST LPBYTE) "Emu48 Document\xFE", - (CONST LPBYTE) "Emu38 Document\xFE", - (CONST LPBYTE) "Emu39 Document\xFE", - (CONST LPBYTE) "Emu49 Document\xFE", - (CONST LPBYTE) "Win48 Document\xFE", - (CONST LPBYTE) "Win48 Document\xFF" -}; - -static CHIPSET BackupChipset; -static LPBYTE BackupPort0; -static LPBYTE BackupPort1; -static LPBYTE BackupPort2; -static BOOL bRomPacked; - -//################ -//# -//# Window Position Tools -//# -//################ - -VOID SetWindowLocation(HWND hWnd,INT nPosX,INT nPosY) -{ - WINDOWPLACEMENT wndpl; - RECT *pRc = &wndpl.rcNormalPosition; - - wndpl.length = sizeof(wndpl); - GetWindowPlacement(hWnd,&wndpl); - pRc->right = pRc->right - pRc->left + nPosX; - pRc->bottom = pRc->bottom - pRc->top + nPosY; - pRc->left = nPosX; - pRc->top = nPosY; - SetWindowPlacement(hWnd,&wndpl); - return; -} - - - -//################ -//# -//# Filename Title Helper Tool -//# -//################ - -DWORD GetCutPathName(LPCTSTR szFileName, LPTSTR szBuffer, DWORD dwBufferLength, INT nCutLength) -{ - TCHAR cPath[_MAX_PATH]; // full filename - TCHAR cDrive[_MAX_DRIVE]; - TCHAR cDir[_MAX_DIR]; - TCHAR cFname[_MAX_FNAME]; - TCHAR cExt[_MAX_EXT]; - - _ASSERT(nCutLength >= 0); // 0 = only drive and name - - // split original filename into parts - _tsplitpath(szFileName,cDrive,cDir,cFname,cExt); - - if (*cDir != 0) // contain directory part - { - LPTSTR lpFilePart; // address of file name in path - INT nNameLen,nPathLen,nMaxPathLen; - - GetFullPathName(szFileName,ARRAYSIZEOF(cPath),cPath,&lpFilePart); - _tsplitpath(cPath,cDrive,cDir,cFname,cExt); - - // calculate size of drive/name and path - nNameLen = lstrlen(cDrive) + lstrlen(cFname) + lstrlen(cExt); - nPathLen = lstrlen(cDir); - - // maximum length for path - nMaxPathLen = nCutLength - nNameLen; - - if (nPathLen > nMaxPathLen) // have to cut path - { - TCHAR cDirTemp[_MAX_DIR] = _T(""); - LPTSTR szPtr; - - // UNC name - if (cDir[0] == _T('\\') && cDir[1] == _T('\\')) - { - // skip server - if ((szPtr = _tcschr(cDir + 2,_T('\\'))) != NULL) - { - // skip share - if ((szPtr = _tcschr(szPtr + 1,_T('\\'))) != NULL) - { - INT nLength = (INT) (szPtr - cDir); - - *szPtr = 0; // set EOS behind share - - // enough room for \\server\\share and "\...\" - if (nLength + 5 <= nMaxPathLen) - { - lstrcpyn(cDirTemp,cDir,ARRAYSIZEOF(cDirTemp)); - nMaxPathLen -= nLength; - } - - } - } - } - - lstrcat(cDirTemp,_T("\\...")); - nMaxPathLen -= 5; // need 6 chars for additional "\..." + "\" - if (nMaxPathLen < 0) nMaxPathLen = 0; - - // get earliest possible '\' character - szPtr = &cDir[nPathLen - nMaxPathLen]; - szPtr = _tcschr(szPtr,_T('\\')); - // not found - if (szPtr == NULL) szPtr = _T(""); - - lstrcat(cDirTemp,szPtr); // copy path with preample to dir buffer - lstrcpyn(cDir,cDirTemp,ARRAYSIZEOF(cDir)); - } - } - - _tmakepath(cPath,cDrive,cDir,cFname,cExt); - lstrcpyn(szBuffer,cPath,dwBufferLength); - return lstrlen(szBuffer); -} - -VOID SetWindowPathTitle(LPCTSTR szFileName) -{ - TCHAR cPath[MAX_PATH]; - RECT rectClient; - - if (*szFileName != 0) // set new title - { - _ASSERT(hWnd != NULL); - VERIFY(GetClientRect(hWnd,&rectClient)); - GetCutPathName(szFileName,cPath,ARRAYSIZEOF(cPath),rectClient.right/11); - SetWindowTitle(cPath); - } - return; -} - - - -//################ -//# -//# BEEP Patch check -//# -//################ - -BOOL CheckForBeepPatch(VOID) -{ - typedef struct beeppatch - { - const DWORD dwAddress; // patch address - const BYTE byPattern[4]; // patch pattern - } BEEPPATCH, *PBEEPPATCH; - - // known beep patches - const BEEPPATCH s38[] = { { 0x017D0, { 0x8, 0x1, 0xB, 0x1 } } }; - const BEEPPATCH s39[] = { { 0x017BC, { 0x8, 0x1, 0xB, 0x1 } } }; - const BEEPPATCH s48[] = { { 0x017A6, { 0x8, 0x1, 0xB, 0x1 } } }; - const BEEPPATCH s49[] = { { 0x4157A, { 0x8, 0x1, 0xB, 0x1 } }, // 1.18/1.19-5/1.19-6 - { 0x41609, { 0x8, 0x1, 0xB, 0x1 } } }; // 1.24/2.01/2.09 - - const BEEPPATCH *psData; - UINT nDataItems; - BOOL bMatch; - - switch (cCurrentRomType) - { - case '6': - case 'A': // HP38G - psData = s38; - nDataItems = ARRAYSIZEOF(s38); - break; - case 'E': // HP39/40G - psData = s39; - nDataItems = ARRAYSIZEOF(s39); - break; - case 'S': // HP48SX - case 'G': // HP48GX - psData = s48; - nDataItems = ARRAYSIZEOF(s48); - break; - case 'X': // HP49G - psData = s49; - nDataItems = ARRAYSIZEOF(s49); - break; - default: - psData = NULL; - nDataItems = 0; - } - - // check if one data set match - for (bMatch = FALSE; !bMatch && nDataItems > 0; --nDataItems) - { - _ASSERT(pbyRom != NULL && psData != NULL); - - // pattern matching? - bMatch = (psData->dwAddress + ARRAYSIZEOF(psData->byPattern) < dwRomSize) - && (memcmp(&pbyRom[psData->dwAddress],psData->byPattern,ARRAYSIZEOF(psData->byPattern))) == 0; - ++psData; // next data set - } - return bMatch; -} - - - -//################ -//# -//# Patch -//# -//################ - -static __inline BYTE Asc2Nib(BYTE c) -{ - if (c<'0') return 0; - if (c<='9') return c-'0'; - if (c<'A') return 0; - if (c<='F') return c-'A'+10; - if (c<'a') return 0; - if (c<='f') return c-'a'+10; - return 0; -} - -// functions to restore ROM patches -typedef struct tnode -{ - BOOL bPatch; // TRUE = ROM address patched - DWORD dwAddress; // patch address - BYTE byROM; // original ROM value - BYTE byPatch; // patched ROM value - struct tnode *prev; // previous node - struct tnode *next; // next node -} TREENODE, *PTREENODE; - -static TREENODE *nodePatch = NULL; - -BOOL PatchNibble(DWORD dwAddress, BYTE byPatch) -{ - PTREENODE p; - - _ASSERT(pbyRom); // ROM defined - if ((p = (PTREENODE) malloc(sizeof(TREENODE))) == NULL) - return TRUE; - - p->bPatch = TRUE; // address patched - p->dwAddress = dwAddress; // save current values - p->byROM = pbyRom[dwAddress]; - p->byPatch = byPatch; - p->prev = NULL; - p->next = nodePatch; // save node - - if (nodePatch) nodePatch->prev = p; // add as previous element - nodePatch = p; - - pbyRom[dwAddress] = byPatch; // patch ROM - return FALSE; -} - -static VOID RestorePatches(VOID) -{ - TREENODE *p; - - _ASSERT(pbyRom); // ROM defined - while (nodePatch != NULL) - { - // restore original data - pbyRom[nodePatch->dwAddress] = nodePatch->byROM; - - p = nodePatch->next; // save pointer to next node - free(nodePatch); // free node - nodePatch = p; // new node - } - return; -} - -VOID UpdatePatches(BOOL bPatch) -{ - TREENODE *p = nodePatch; - - _ASSERT(pbyRom); // ROM defined - if (bPatch) // patch ROM - { - if (p) // something in patch list - { - // goto last element in list - for (; p->next != NULL; p = p->next) {} - - do - { - if (!p->bPatch) // patch only if not patched - { - // use original data for patch restore - p->byROM = pbyRom[p->dwAddress]; - - // restore patch data - pbyRom[p->dwAddress] = p->byPatch; - p->bPatch = TRUE; // address patched - } - else - { - _ASSERT(FALSE); // call ROM patch on a patched ROM - } - - p = p->prev; - } - while (p != NULL); - } - } - else // restore ROM - { - for (; p != NULL; p = p->next) - { - // restore original data - pbyRom[p->dwAddress] = p->byROM; - p->bPatch = FALSE; // address not patched - } - } - return; -} - -BOOL PatchRom(LPCTSTR szFilename) -{ - HANDLE hFile = NULL; - DWORD dwFileSizeLow = 0; - DWORD dwFileSizeHigh = 0; - DWORD lBytesRead = 0; - PSZ lpStop,lpBuf = NULL; - DWORD dwAddress = 0; - UINT nPos = 0; - BOOL bSucc = TRUE; - - if (pbyRom == NULL) return FALSE; - SetCurrentDirectory(szEmuDirectory); - hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); - SetCurrentDirectory(szCurrentDirectory); - if (hFile == INVALID_HANDLE_VALUE) return FALSE; - dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); - if (dwFileSizeHigh != 0 || dwFileSizeLow == 0) - { // file is too large or empty - CloseHandle(hFile); - return FALSE; - } - lpBuf = (PSZ) malloc(dwFileSizeLow+1); - if (lpBuf == NULL) - { - CloseHandle(hFile); - return FALSE; - } - ReadFile(hFile, lpBuf, dwFileSizeLow, &lBytesRead, NULL); - CloseHandle(hFile); - lpBuf[dwFileSizeLow] = 0; - nPos = 0; - while (lpBuf[nPos]) - { - // skip whitespace characters - nPos += (UINT) strspn(&lpBuf[nPos]," \t\n\r"); - - if (lpBuf[nPos] == ';') // comment? - { - do - { - nPos++; - if (lpBuf[nPos] == '\n') - { - nPos++; - break; - } - } while (lpBuf[nPos]); - continue; - } - dwAddress = strtoul(&lpBuf[nPos], &lpStop, 16); - nPos = (UINT) (lpStop - lpBuf); // position of lpStop - - if (*lpStop != 0) // data behind address - { - if (*lpStop != ':') // invalid syntax - { - // skip to end of line - while (lpBuf[nPos] != '\n' && lpBuf[nPos] != 0) - { - ++nPos; - } - bSucc = FALSE; - continue; - } - - while (lpBuf[++nPos]) - { - if (isxdigit(lpBuf[nPos]) == FALSE) break; - if (dwAddress < dwRomSize) // patch ROM - { - // patch ROM and save original nibble - PatchNibble(dwAddress, Asc2Nib(lpBuf[nPos])); - bRomCrcCorrection = TRUE; - } - ++dwAddress; - } - } - } - _ASSERT(nPos <= dwFileSizeLow); // buffer overflow? - free(lpBuf); - return bSucc; -} - - - -//################ -//# -//# ROM -//# -//################ - -BOOL CrcRom(WORD *pwChk) // calculate fingerprint of ROM -{ - DWORD *pdwData,dwSize; - DWORD dwChk = 0; - - if (pbyRom == NULL) return TRUE; // ROM CRC isn't available - - _ASSERT(pbyRom); // view on ROM - pdwData = (DWORD *) pbyRom; - - _ASSERT((dwRomSize % sizeof(*pdwData)) == 0); - dwSize = dwRomSize / sizeof(*pdwData); // file size in DWORD's - - // use checksum, because it's faster - while (dwSize-- > 0) - { - CONST DWORD dwData = *pdwData++; - if ((dwData & 0xF0F0F0F0) != 0) // data packed? - return FALSE; - dwChk += dwData; - } - - *pwChk = (WORD) ((dwChk >> 16) + (dwChk & 0xFFFF)); - return TRUE; -} - -BOOL MapRom(LPCTSTR szFilename) -{ - DWORD dwSize,dwFileSize,dwRead; - - // open ROM for writing - BOOL bRomRW = (cCurrentRomType == 'X') ? bRomWriteable : FALSE; - - if (pbyRom != NULL) - { - return FALSE; - } - bRomCrcCorrection = FALSE; // ROM CRC correction disabled - SetCurrentDirectory(szEmuDirectory); - if (bRomRW) // ROM writeable - { - hRomFile = CreateFile(szFilename, - GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - if (hRomFile == INVALID_HANDLE_VALUE) - { - bRomRW = FALSE; // ROM not writeable - hRomFile = CreateFile(szFilename, - GENERIC_READ, - FILE_SHARE_READ|FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - } - } - else // writing ROM disabled - { - hRomFile = CreateFile(szFilename, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - } - SetCurrentDirectory(szCurrentDirectory); - if (hRomFile == INVALID_HANDLE_VALUE) - { - hRomFile = NULL; - return FALSE; - } - dwRomSize = GetFileSize(hRomFile, NULL); - - // read the first 4 bytes - ReadFile(hRomFile,&dwSize,sizeof(dwSize),&dwRead,NULL); - if (dwRead < sizeof(dwSize)) - { // file is too small. - CloseHandle(hRomFile); - hRomFile = NULL; - dwRomSize = 0; - return FALSE; - } - - dwFileSize = dwRomSize; // calculate ROM image buffer size - bRomPacked = (dwSize & 0xF0F0F0F0) != 0; // ROM image packed - if (bRomPacked) dwRomSize *= 2; // unpacked ROM image has double size - - pbyRom = (LPBYTE) malloc(dwRomSize); - if (pbyRom == NULL) - { - CloseHandle(hRomFile); - hRomFile = NULL; - dwRomSize = 0; - return FALSE; - } - - *(DWORD *) pbyRom = dwSize; // save first 4 bytes - - // load rest of file content - ReadFile(hRomFile,&pbyRom[sizeof(dwSize)],dwFileSize - sizeof(dwSize),&dwRead,NULL); - _ASSERT(dwFileSize - sizeof(dwSize) == dwRead); - - if (bRomRW) // ROM is writeable - { - // no. of dirty pages - dwRomDirtyPageSize = dwRomSize / ROMPAGESIZE; - - // alloc dirty page table - pbyRomDirtyPage = (LPBYTE) calloc(dwRomDirtyPageSize,sizeof(*pbyRomDirtyPage)); - if (pbyRomDirtyPage == NULL) - { - free(pbyRom); // free ROM image - CloseHandle(hRomFile); - dwRomDirtyPageSize = 0; - pbyRom = NULL; - hRomFile = NULL; - dwRomSize = 0; - return FALSE; - } - } - else - { - dwRomDirtyPageSize = 0; - CloseHandle(hRomFile); - hRomFile = NULL; - } - - if (bRomPacked) // packed ROM image - { - LPBYTE pbySrc = pbyRom+dwFileSize; // source start address - LPBYTE pbyDest = pbyRom+dwRomSize; // destination start address - while (pbySrc != pbyDest) // unpack source - { - CONST BYTE byValue = *(--pbySrc); - *(--pbyDest) = byValue >> 4; - *(--pbyDest) = byValue & 0xF; - } - } - return TRUE; -} - -VOID UnmapRom(VOID) -{ - if (pbyRom == NULL) return; // ROM not mapped - RestorePatches(); // restore ROM patches - if (hRomFile) // ROM file still open (only in R/W case) - { - DWORD i; - - _ASSERT(pbyRomDirtyPage != NULL); - - // scan for every dirty page - for (i = 0; i < dwRomDirtyPageSize; ++i) - { - if (pbyRomDirtyPage[i]) // page dirty - { - DWORD dwSize,dwLinPos,dwFilePos,dwWritten; - - dwLinPos = i * ROMPAGESIZE; // position inside emulator memory - - dwSize = ROMPAGESIZE; // bytes to write - while (i+1 < dwRomDirtyPageSize && pbyRomDirtyPage[i+1]) - { - dwSize += ROMPAGESIZE; // next page is also dirty - ++i; // skip next page in outer loop - } - - dwFilePos = dwLinPos; // ROM file position - - if (bRomPacked) // repack data - { - LPBYTE pbySrc,pbyDest,pbyEnd; - - dwSize /= 2; // adjust no. of bytes to write - dwFilePos /= 2; // linear pos in packed file - - // pack data in page - pbySrc = pbyDest = &pbyRom[dwLinPos]; - pbyEnd = pbyDest + dwSize; - while (pbyDest < pbyEnd) - { - *pbyDest = *pbySrc++; - *pbyDest |= *pbySrc++ << 4; - ++pbyDest; - } - } - - SetFilePointer(hRomFile,dwFilePos,NULL,FILE_BEGIN); - WriteFile(hRomFile,&pbyRom[dwLinPos],dwSize,&dwWritten,NULL); - } - } - - free(pbyRomDirtyPage); - CloseHandle(hRomFile); - pbyRomDirtyPage = NULL; - dwRomDirtyPageSize = 0; - hRomFile = NULL; - } - - free(pbyRom); // free ROM image - pbyRom = NULL; - dwRomSize = 0; - wRomCrc = 0; - bRomCrcCorrection = FALSE; // ROM CRC correction disabled - return; -} - - - -//################ -//# -//# Port2 -//# -//################ - -static BOOL CrcPort2(WORD *pwCrc) // calculate fingerprint of port2 -{ - *pwCrc = 0; - - if (pbyPort2 != NULL) // port2 CRC available - { - LPBYTE pbyMem; - - // get real filesize - DWORD dwFileSize = GetFileSize(hPort2File, NULL); - - for (pbyMem = pbyPort2; dwFileSize > 0; --dwFileSize) - { - if ((*pbyMem & 0xF0) != 0) // data packed? - return FALSE; - - *pwCrc = UpCRC(*pwCrc,*pbyMem++); - } - } - return TRUE; -} - -BOOL MapPort2(LPCTSTR szFilename) -{ - DWORD dwFileSizeLo,dwFileSizeHi; - - if (pbyPort2 != NULL) return FALSE; - bPort2Writeable = TRUE; - dwPort2Size = 0; // reset size of port2 - - SetCurrentDirectory(szEmuDirectory); - hPort2File = CreateFile(szFilename, - GENERIC_READ|GENERIC_WRITE, - bPort2IsShared ? FILE_SHARE_READ : 0, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (hPort2File == INVALID_HANDLE_VALUE) - { - bPort2Writeable = FALSE; - hPort2File = CreateFile(szFilename, - GENERIC_READ, - bPort2IsShared ? (FILE_SHARE_READ|FILE_SHARE_WRITE) : 0, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (hPort2File == INVALID_HANDLE_VALUE) - { - SetCurrentDirectory(szCurrentDirectory); - hPort2File = NULL; - return FALSE; - } - } - SetCurrentDirectory(szCurrentDirectory); - dwFileSizeLo = GetFileSize(hPort2File, &dwFileSizeHi); - - // size not 32, 128, 256, 512, 1024, 2048 or 4096 KB - if ( dwFileSizeHi != 0 - || dwFileSizeLo == 0 - || (dwFileSizeLo & (dwFileSizeLo - 1)) != 0 - || (dwFileSizeLo & 0xFF02FFFF) != 0) - { - UnmapPort2(); - return FALSE; - } - - hPort2Map = CreateFileMapping(hPort2File, NULL, bPort2Writeable ? PAGE_READWRITE : PAGE_READONLY, - 0, dwFileSizeLo, NULL); - if (hPort2Map == NULL) - { - UnmapPort2(); - return FALSE; - } - pbyPort2 = (LPBYTE) MapViewOfFile(hPort2Map, bPort2Writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, 0, dwFileSizeLo); - if (pbyPort2 == NULL) - { - UnmapPort2(); - return FALSE; - } - - dwPort2Mask = (dwFileSizeLo - 1) >> 18; // mask for valid address lines of the BS-FF - dwPort2Size = dwFileSizeLo / 2048; // mapping size of port2 - - if (CrcPort2(&wPort2Crc) == FALSE) // calculate fingerprint of port2 - { - UnmapPort2(); // free memory - AbortMessage(_T("Packed Port 2 image detected!")); - return FALSE; - } - return TRUE; -} - -VOID UnmapPort2(VOID) -{ - if (pbyPort2 != NULL) - { - UnmapViewOfFile(pbyPort2); - pbyPort2 = NULL; - } - if (hPort2Map != NULL) - { - CloseHandle(hPort2Map); - hPort2Map = NULL; - } - if (hPort2File != NULL) - { - CloseHandle(hPort2File); - hPort2File = NULL; - } - dwPort2Size = 0; // reset size of port2 - dwPort2Mask = 0; - bPort2Writeable = FALSE; - wPort2Crc = 0; - return; -} - - - -//################ -//# -//# Documents -//# -//################ - -static BOOL IsDataPacked(VOID *pMem, DWORD dwSize) -{ - DWORD *pdwMem = (DWORD *) pMem; - - _ASSERT((dwSize % sizeof(DWORD)) == 0); - if ((dwSize % sizeof(DWORD)) != 0) return TRUE; - - for (dwSize /= sizeof(DWORD); dwSize-- > 0;) - { - if ((*pdwMem++ & 0xF0F0F0F0) != 0) - return TRUE; - } - return FALSE; -} - -VOID ResetDocument(VOID) -{ - DisableDebugger(); - if (szCurrentKml[0]) - { - KillKML(); - } - if (hCurrentFile) - { - CloseHandle(hCurrentFile); - hCurrentFile = NULL; - } - szCurrentKml[0] = 0; - szCurrentFilename[0] = 0; - if (Port0) { free(Port0); Port0 = NULL; } - if (Port1) { free(Port1); Port1 = NULL; } - if (Port2) { free(Port2); Port2 = NULL; } else UnmapPort2(); - ZeroMemory(&Chipset,sizeof(Chipset)); - ZeroMemory(&RMap,sizeof(RMap)); // delete MMU mappings - ZeroMemory(&WMap,sizeof(WMap)); - bDocumentAvail = FALSE; // document not available - return; -} - -BOOL NewDocument(VOID) -{ - SaveBackup(); - ResetDocument(); - - if (!DisplayChooseKml(0)) goto restore; - if (!InitKML(szCurrentKml,FALSE)) goto restore; - Chipset.type = cCurrentRomType; - CrcRom(&Chipset.wRomCrc); // save fingerprint of loaded ROM - - if (Chipset.type == '6' || Chipset.type == 'A') // HP38G - { - Chipset.Port0Size = (Chipset.type == 'A') ? 32 : 64; - Chipset.Port1Size = 0; - Chipset.Port2Size = 0; - - Chipset.cards_status = 0x0; - } - if (Chipset.type == 'E') // HP39/40G - { - Chipset.Port0Size = 128; - Chipset.Port1Size = 0; - Chipset.Port2Size = 128; - - Chipset.cards_status = 0xF; - - bPort2Writeable = TRUE; // port2 is writeable - } - if (Chipset.type == 'S') // HP48SX - { - Chipset.Port0Size = 32; - Chipset.Port1Size = 128; - Chipset.Port2Size = 0; - - Chipset.cards_status = 0x5; - - // use 2nd command line argument if defined - MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); - } - if (Chipset.type == 'G') // HP48GX - { - Chipset.Port0Size = 128; - Chipset.Port1Size = 128; - Chipset.Port2Size = 0; - - Chipset.cards_status = 0xA; - - // use 2nd command line argument if defined - MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); - } - if (Chipset.type == 'X') // HP49G - { - Chipset.Port0Size = 256; - Chipset.Port1Size = 128; - Chipset.Port2Size = 128; - - Chipset.cards_status = 0xF; - bPort2Writeable = TRUE; // port2 is writeable - - FlashInit(); // init flash structure - } - - Chipset.IORam[LPE] = RST; // set ReSeT bit at power on reset - - // allocate port memory - if (Chipset.Port0Size) - { - Port0 = (LPBYTE) calloc(Chipset.Port0Size*2048,sizeof(*Port0)); - if (Port0 == NULL) goto restore; - } - if (Chipset.Port1Size) - { - Port1 = (LPBYTE) calloc(Chipset.Port1Size*2048,sizeof(*Port1)); - if (Port1 == NULL) goto restore; - } - if (Chipset.Port2Size) - { - Port2 = (LPBYTE) calloc(Chipset.Port2Size*2048,sizeof(*Port2)); - if (Port2 == NULL) goto restore; - } - LoadBreakpointList(NULL); // clear debugger breakpoint list - RomSwitch(0); // boot ROM view of HP49G and map memory - bDocumentAvail = TRUE; // document available - return TRUE; -restore: - RestoreBackup(); - ResetBackup(); - - // HP48SX/GX - if (Chipset.type == 'S' || Chipset.type == 'G') - { - // use 2nd command line argument if defined - MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); - } - if (pbyRom) - { - Map(0x00,0xFF); - } - return FALSE; -} - -BOOL OpenDocument(LPCTSTR szFilename) -{ - #define CHECKAREA(s,e) (offsetof(CHIPSET,e)-offsetof(CHIPSET,s)+sizeof(((CHIPSET *)NULL)->e)) - - HANDLE hFile = INVALID_HANDLE_VALUE; - DWORD lBytesRead,lSizeofChipset; - BYTE byFileSignature[16]; - BOOL bMatch; - UINT i,nLength; - - // Open file - if (lstrcmpi(szCurrentFilename,szFilename) == 0) - { - if (YesNoMessage(_T("Do you want to reload this document?")) == IDNO) - return TRUE; - } - - SaveBackup(); - ResetDocument(); - - hFile = CreateFile(szFilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - if (hFile == INVALID_HANDLE_VALUE) - { - AbortMessage(_T("This file is missing or already loaded in another instance of Emu48.")); - goto restore; - } - - // Read and Compare signature - ReadFile(hFile, byFileSignature, sizeof(byFileSignature), &lBytesRead, NULL); - // go through all valid document signatures - for (bMatch = FALSE, i = 0; !bMatch && i < ARRAYSIZEOF(bySignature); ++i) - { - bMatch = (memcmp(byFileSignature, bySignature[i], sizeof(byFileSignature)) == 0); - } - if (!bMatch) // no valid document signature found - { - AbortMessage(_T("This file is not a valid Emu48 document.")); - goto restore; - } - - switch (byFileSignature[14]) - { - case 0xFE: // Win48 2.1 / Emu4x 0.99.x format - // read length of KML script name - ReadFile(hFile,&nLength,sizeof(nLength),&lBytesRead,NULL); - - // KML script name too long for file buffer - if (nLength >= ARRAYSIZEOF(szCurrentKml)) - { - // skip heading KML script name characters until remainder fits into file buffer - UINT nSkip = nLength - (ARRAYSIZEOF(szCurrentKml) - 1); - SetFilePointer(hFile, nSkip, NULL, FILE_CURRENT); - - nLength = ARRAYSIZEOF(szCurrentKml) - 1; - } - #if defined _UNICODE - { - LPSTR szTmp = (LPSTR) malloc(nLength); - if (szTmp == NULL) - { - AbortMessage(_T("Memory Allocation Failure.")); - goto restore; - } - ReadFile(hFile, szTmp, nLength, &lBytesRead, NULL); - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTmp, lBytesRead, - szCurrentKml, ARRAYSIZEOF(szCurrentKml)); - free(szTmp); - } - #else - { - ReadFile(hFile, szCurrentKml, nLength, &lBytesRead, NULL); - } - #endif - if (nLength != lBytesRead) goto read_err; - szCurrentKml[nLength] = 0; - break; - case 0xFF: // Win48 2.05 format - break; - default: - _ASSERT(FALSE); - } - - // read chipset size inside file - ReadFile(hFile, &lSizeofChipset, sizeof(lSizeofChipset), &lBytesRead, NULL); - if (lBytesRead != sizeof(lSizeofChipset)) goto read_err; - if (lSizeofChipset <= sizeof(Chipset)) // actual or older chipset version - { - // read chipset content - ZeroMemory(&Chipset,sizeof(Chipset)); // init chipset - ReadFile(hFile, &Chipset, lSizeofChipset, &lBytesRead, NULL); - } - else // newer chipset version - { - // read my used chipset content - ReadFile(hFile, &Chipset, sizeof(Chipset), &lBytesRead, NULL); - - // skip rest of chipset - SetFilePointer(hFile, lSizeofChipset-sizeof(Chipset), NULL, FILE_CURRENT); - lSizeofChipset = sizeof(Chipset); - } - if (lBytesRead != lSizeofChipset) goto read_err; - - if (!isModelValid(Chipset.type)) // check for valid model in emulator state file - { - AbortMessage(_T("Emulator state file with invalid calculator model.")); - goto restore; - } - - SetWindowLocation(hWnd,Chipset.nPosX,Chipset.nPosY); - - while (TRUE) - { - if (szCurrentKml[0]) // KML file name - { - BOOL bOK = InitKML(szCurrentKml,FALSE); - bOK = bOK && (cCurrentRomType == Chipset.type); - if (bOK) break; - - KillKML(); - } - if (!DisplayChooseKml(Chipset.type)) - goto restore; - } - // reload old button state - ReloadButtons(Chipset.Keyboard_Row,ARRAYSIZEOF(Chipset.Keyboard_Row)); - - FlashInit(); // init flash structure - - if (Chipset.Port0Size) - { - Port0 = (LPBYTE) malloc(Chipset.Port0Size*2048); - if (Port0 == NULL) - { - AbortMessage(_T("Memory Allocation Failure.")); - goto restore; - } - - ReadFile(hFile, Port0, Chipset.Port0Size*2048, &lBytesRead, NULL); - if (lBytesRead != Chipset.Port0Size*2048) goto read_err; - - if (IsDataPacked(Port0,Chipset.Port0Size*2048)) goto read_err; - } - - if (Chipset.Port1Size) - { - Port1 = (LPBYTE) malloc(Chipset.Port1Size*2048); - if (Port1 == NULL) - { - AbortMessage(_T("Memory Allocation Failure.")); - goto restore; - } - - ReadFile(hFile, Port1, Chipset.Port1Size*2048, &lBytesRead, NULL); - if (lBytesRead != Chipset.Port1Size*2048) goto read_err; - - if (IsDataPacked(Port1,Chipset.Port1Size*2048)) goto read_err; - } - - // HP48SX/GX - if (cCurrentRomType=='S' || cCurrentRomType=='G') - { - MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); - // port2 changed and card detection enabled - if ( Chipset.wPort2Crc != wPort2Crc - && (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0 - ) - { - Chipset.HST |= MP; // set Module Pulled - IOBit(SRQ2,NINT,FALSE); // set NINT to low - Chipset.SoftInt = TRUE; // set interrupt - bInterrupt = TRUE; - } - } - else // HP38G, HP39/40G, HP49G - { - if (Chipset.Port2Size) - { - Port2 = (LPBYTE) malloc(Chipset.Port2Size*2048); - if (Port2 == NULL) - { - AbortMessage(_T("Memory Allocation Failure.")); - goto restore; - } - - ReadFile(hFile, Port2, Chipset.Port2Size*2048, &lBytesRead, NULL); - if (lBytesRead != Chipset.Port2Size*2048) goto read_err; - - if (IsDataPacked(Port2,Chipset.Port2Size*2048)) goto read_err; - - bPort2Writeable = TRUE; - Chipset.cards_status = 0xF; - } - } - - RomSwitch(Chipset.Bank_FF); // reload ROM view of HP49G and map memory - - if (Chipset.wRomCrc != wRomCrc) // ROM changed - { - CpuReset(); - Chipset.Shutdn = FALSE; // automatic restart - } - - // check CPU main registers - if (IsDataPacked(Chipset.A,CHECKAREA(A,R4))) goto read_err; - - LoadBreakpointList(hFile); // load debugger breakpoint list - - lstrcpy(szCurrentFilename, szFilename); - _ASSERT(hCurrentFile == NULL); - hCurrentFile = hFile; - #if defined _USRDLL // DLL version - // notify main proc about current document file - if (pEmuDocumentNotify) pEmuDocumentNotify(szCurrentFilename); - #endif - SetWindowPathTitle(szCurrentFilename); // update window title line - bDocumentAvail = TRUE; // document available - return TRUE; - -read_err: - AbortMessage(_T("This file must be truncated, and cannot be loaded.")); -restore: - if (INVALID_HANDLE_VALUE != hFile) // close if valid handle - CloseHandle(hFile); - RestoreBackup(); - ResetBackup(); - - // HP48SX/GX - if (cCurrentRomType=='S' || cCurrentRomType=='G') - { - // use 2nd command line argument if defined - MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); - } - return FALSE; - #undef CHECKAREA -} - -BOOL SaveDocument(VOID) -{ - DWORD lBytesWritten; - DWORD lSizeofChipset; - UINT nLength; - WINDOWPLACEMENT wndpl; - - if (hCurrentFile == NULL) return FALSE; - - _ASSERT(hWnd); // window open - wndpl.length = sizeof(wndpl); // update saved window position - GetWindowPlacement(hWnd, &wndpl); - Chipset.nPosX = (SWORD) wndpl.rcNormalPosition.left; - Chipset.nPosY = (SWORD) wndpl.rcNormalPosition.top; - - SetFilePointer(hCurrentFile,0,NULL,FILE_BEGIN); - - // write default "Emu48 Document\xFE" signature - if (!WriteFile(hCurrentFile, bySignature[0], 16, &lBytesWritten, NULL)) - { - AbortMessage(_T("Could not write into document file!")); - return FALSE; - } - - CrcRom(&Chipset.wRomCrc); // save fingerprint of ROM - CrcPort2(&Chipset.wPort2Crc); // save fingerprint of port2 - - nLength = lstrlen(szCurrentKml); - WriteFile(hCurrentFile, &nLength, sizeof(nLength), &lBytesWritten, NULL); - #if defined _UNICODE - { - LPSTR szTmp = (LPSTR) malloc(nLength); - if (szTmp != NULL) - { - WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, - szCurrentKml, nLength, - szTmp, nLength, NULL, NULL); - WriteFile(hCurrentFile, szTmp, nLength, &lBytesWritten, NULL); - free(szTmp); - } - } - #else - { - WriteFile(hCurrentFile, szCurrentKml, nLength, &lBytesWritten, NULL); - } - #endif - lSizeofChipset = sizeof(CHIPSET); - WriteFile(hCurrentFile, &lSizeofChipset, sizeof(lSizeofChipset), &lBytesWritten, NULL); - WriteFile(hCurrentFile, &Chipset, lSizeofChipset, &lBytesWritten, NULL); - if (Chipset.Port0Size) WriteFile(hCurrentFile, Port0, Chipset.Port0Size*2048, &lBytesWritten, NULL); - if (Chipset.Port1Size) WriteFile(hCurrentFile, Port1, Chipset.Port1Size*2048, &lBytesWritten, NULL); - if (Chipset.Port2Size) WriteFile(hCurrentFile, Port2, Chipset.Port2Size*2048, &lBytesWritten, NULL); - SaveBreakpointList(hCurrentFile); // save debugger breakpoint list - SetEndOfFile(hCurrentFile); // cut the rest - return TRUE; -} - -BOOL SaveDocumentAs(LPCTSTR szFilename) -{ - HANDLE hFile; - - if (hCurrentFile) // already file in use - { - CloseHandle(hCurrentFile); // close it, even it's same, so data always will be saved - hCurrentFile = NULL; - } - hFile = CreateFile(szFilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); - if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file - { - AbortMessage(_T("This file must be currently used by another instance of Emu48.")); - return FALSE; - } - lstrcpy(szCurrentFilename, szFilename); // save new file name - hCurrentFile = hFile; // and the corresponding handle - #if defined _USRDLL // DLL version - // notify main proc about current document file - if (pEmuDocumentNotify) pEmuDocumentNotify(szCurrentFilename); - #endif - SetWindowPathTitle(szCurrentFilename); // update window title line - return SaveDocument(); // save current content -} - - - -//################ -//# -//# Backup -//# -//################ - -BOOL SaveBackup(VOID) -{ - WINDOWPLACEMENT wndpl; - - BOOL bSucc = TRUE; - - if (!bDocumentAvail) return FALSE; - - _ASSERT(nState != SM_RUN); // emulation engine is running - - // save window position - _ASSERT(hWnd); // window open - wndpl.length = sizeof(wndpl); // update saved window position - GetWindowPlacement(hWnd, &wndpl); - Chipset.nPosX = (SWORD) wndpl.rcNormalPosition.left; - Chipset.nPosY = (SWORD) wndpl.rcNormalPosition.top; - - lstrcpy(szBackupFilename, szCurrentFilename); - lstrcpy(szBackupKml, szCurrentKml); - if (BackupPort0) { free(BackupPort0); BackupPort0 = NULL; } - if (BackupPort1) { free(BackupPort1); BackupPort1 = NULL; } - if (BackupPort2) { free(BackupPort2); BackupPort2 = NULL; } - CopyMemory(&BackupChipset, &Chipset, sizeof(Chipset)); - if (Port0 && Chipset.Port0Size) - { - BackupPort0 = (LPBYTE) malloc(Chipset.Port0Size*2048); - if (BackupPort0) - { - CopyMemory(BackupPort0,Port0,Chipset.Port0Size*2048); - } - bSucc = bSucc && (BackupPort0 != NULL); - } - if (Port1 && Chipset.Port1Size) - { - BackupPort1 = (LPBYTE) malloc(Chipset.Port1Size*2048); - if (BackupPort1) - { - CopyMemory(BackupPort1,Port1,Chipset.Port1Size*2048); - } - bSucc = bSucc && (BackupPort1 != NULL); - } - if (Port2 && Chipset.Port2Size) // internal port2 - { - BackupPort2 = (LPBYTE) malloc(Chipset.Port2Size*2048); - if (BackupPort2) - { - CopyMemory(BackupPort2,Port2,Chipset.Port2Size*2048); - } - bSucc = bSucc && (BackupPort2 != NULL); - } - CreateBackupBreakpointList(); - bBackup = bSucc; - return bSucc; -} - -BOOL RestoreBackup(VOID) -{ - BOOL bDbgOpen; - - BOOL bSucc = TRUE; - - if (!bBackup) return FALSE; - - bDbgOpen = (nDbgState != DBG_OFF); // debugger window open? - ResetDocument(); - // need chipset for contrast setting in InitKML() - Chipset.contrast = BackupChipset.contrast; - if (!InitKML(szBackupKml,TRUE)) - { - InitKML(szCurrentKml,TRUE); - return FALSE; - } - lstrcpy(szCurrentKml, szBackupKml); - lstrcpy(szCurrentFilename, szBackupFilename); - if (szCurrentFilename[0]) - { - hCurrentFile = CreateFile(szCurrentFilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - if (hCurrentFile == INVALID_HANDLE_VALUE) - { - hCurrentFile = NULL; - szCurrentFilename[0] = 0; - } - } - CopyMemory(&Chipset, &BackupChipset, sizeof(Chipset)); - if (BackupPort0 && Chipset.Port0Size) - { - Port0 = (LPBYTE) malloc(Chipset.Port0Size*2048); - if (Port0) - { - CopyMemory(Port0,BackupPort0,Chipset.Port0Size*2048); - } - bSucc = bSucc && (Port0 != NULL); - } - if (BackupPort1 && Chipset.Port1Size) - { - Port1 = (LPBYTE) malloc(Chipset.Port1Size*2048); - if (Port1) - { - CopyMemory(Port1,BackupPort1,Chipset.Port1Size*2048); - } - bSucc = bSucc && (Port1 != NULL); - } - if (BackupPort2 && Chipset.Port2Size) // internal port2 - { - Port2 = (LPBYTE) malloc(Chipset.Port2Size*2048); - if (Port2) - { - CopyMemory(Port2,BackupPort2,Chipset.Port2Size*2048); - } - bSucc = bSucc && (Port2 != NULL); - } - // map port2 - else - { - if (cCurrentRomType=='S' || cCurrentRomType=='G') // HP48SX/GX - { - // use 2nd command line argument if defined - MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); - } - } - Map(0x00,0xFF); // update memory mapping - SetWindowPathTitle(szCurrentFilename); // update window title line - SetWindowLocation(hWnd,Chipset.nPosX,Chipset.nPosY); - RestoreBackupBreakpointList(); // restore the debugger breakpoint list - if (bDbgOpen) OnToolDebug(); // reopen the debugger - if (!bSucc) // restore not successful (memory allocation errors) - { - ResetDocument(); // cleanup remainders - } - bDocumentAvail = bSucc; // document available - return bSucc; -} - -BOOL ResetBackup(VOID) -{ - if (!bBackup) return FALSE; - szBackupFilename[0] = 0; - szBackupKml[0] = 0; - if (BackupPort0) { free(BackupPort0); BackupPort0 = NULL; } - if (BackupPort1) { free(BackupPort1); BackupPort1 = NULL; } - if (BackupPort2) { free(BackupPort2); BackupPort2 = NULL; } - ZeroMemory(&BackupChipset,sizeof(BackupChipset)); - bBackup = FALSE; - return TRUE; -} - - - -//################ -//# -//# Open File Common Dialog Boxes -//# -//################ - -static VOID InitializeOFN(LPOPENFILENAME ofn) -{ - ZeroMemory((LPVOID)ofn, sizeof(OPENFILENAME)); - ofn->lStructSize = sizeof(OPENFILENAME); - ofn->hwndOwner = hWnd; - ofn->Flags = OFN_EXPLORER|OFN_HIDEREADONLY; - return; -} - -BOOL GetOpenFilename(VOID) -{ - TCHAR szBuffer[ARRAYSIZEOF(szBufferFilename)]; - OPENFILENAME ofn; - - InitializeOFN(&ofn); - ofn.lpstrFilter = - _T("Emu48 Files (*.e38;*.e39;*.e48;*.e49)\0") - _T("*.e38;*.e39;*.e48;*.e49\0") - _T("HP-38 Files (*.e38)\0*.e38\0") - _T("HP-39 Files (*.e39)\0*.e39\0") - _T("HP-48 Files (*.e48)\0*.e48\0") - _T("HP-49 Files (*.e49)\0*.e49\0") - _T("Win48 Files (*.w48)\0*.w48\0"); - ofn.nFilterIndex = 1; - ofn.lpstrFile = szBuffer; - ofn.lpstrFile[0] = 0; - ofn.nMaxFile = ARRAYSIZEOF(szBuffer); - ofn.Flags |= OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST; - if (GetOpenFileName(&ofn) == FALSE) return FALSE; - _ASSERT(ARRAYSIZEOF(szBufferFilename) == ofn.nMaxFile); - lstrcpy(szBufferFilename, ofn.lpstrFile); - return TRUE; -} - -BOOL GetSaveAsFilename(VOID) -{ - TCHAR szBuffer[ARRAYSIZEOF(szBufferFilename)]; - OPENFILENAME ofn; - - InitializeOFN(&ofn); - ofn.lpstrFilter = - _T("HP-38 Files (*.e38)\0*.e38\0") - _T("HP-39 Files (*.e39)\0*.e39\0") - _T("HP-48 Files (*.e48)\0*.e48\0") - _T("HP-49 Files (*.e49)\0*.e49\0"); - ofn.lpstrDefExt = _T("e48"); // HP48SX/GX - ofn.nFilterIndex = 3; - if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G - { - ofn.lpstrDefExt = _T("e38"); - ofn.nFilterIndex = 1; - } - if (cCurrentRomType=='E') // HP39/40G - { - ofn.lpstrDefExt = _T("e39"); - ofn.nFilterIndex = 2; - } - if (cCurrentRomType=='X') // HP49G - { - ofn.lpstrDefExt = _T("e49"); - ofn.nFilterIndex = 4; - } - ofn.lpstrFile = szBuffer; - ofn.lpstrFile[0] = 0; - ofn.nMaxFile = ARRAYSIZEOF(szBuffer); - ofn.Flags |= OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT; - if (GetSaveFileName(&ofn) == FALSE) return FALSE; - _ASSERT(ARRAYSIZEOF(szBufferFilename) == ofn.nMaxFile); - lstrcpy(szBufferFilename, ofn.lpstrFile); - return TRUE; -} - -BOOL GetLoadObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt) -{ - TCHAR szBuffer[ARRAYSIZEOF(szBufferFilename)]; - OPENFILENAME ofn; - - InitializeOFN(&ofn); - ofn.lpstrFilter = lpstrFilter; - ofn.lpstrDefExt = lpstrDefExt; - ofn.nFilterIndex = 1; - ofn.lpstrFile = szBuffer; - ofn.lpstrFile[0] = 0; - ofn.nMaxFile = ARRAYSIZEOF(szBuffer); - ofn.Flags |= OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST; - if (GetOpenFileName(&ofn) == FALSE) return FALSE; - _ASSERT(ARRAYSIZEOF(szBufferFilename) == ofn.nMaxFile); - lstrcpy(szBufferFilename, ofn.lpstrFile); - return TRUE; -} - -BOOL GetSaveObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt) -{ - TCHAR szBuffer[ARRAYSIZEOF(szBufferFilename)]; - OPENFILENAME ofn; - - InitializeOFN(&ofn); - ofn.lpstrFilter = lpstrFilter; - ofn.lpstrDefExt = NULL; - ofn.nFilterIndex = 1; - ofn.lpstrFile = szBuffer; - ofn.lpstrFile[0] = 0; - ofn.nMaxFile = ARRAYSIZEOF(szBuffer); - ofn.Flags |= OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT; - if (GetSaveFileName(&ofn) == FALSE) return FALSE; - _ASSERT(ARRAYSIZEOF(szBufferFilename) == ofn.nMaxFile); - lstrcpy(szBufferFilename, ofn.lpstrFile); - if (ofn.nFileExtension == 0) // given filename has no extension - { - // actual name length - UINT nLength = lstrlen(szBufferFilename); - - // destination buffer has room for the default extension - if (nLength + 1 + lstrlen(lpstrDefExt) < ARRAYSIZEOF(szBufferFilename)) - { - // add default extension - szBufferFilename[nLength++] = _T('.'); - lstrcpy(&szBufferFilename[nLength], lpstrDefExt); - } - } - return TRUE; -} - - - -//################ -//# -//# Load and Save HP48 Objects -//# -//################ - -WORD WriteStack(UINT nStkLevel,LPBYTE lpBuf,DWORD dwSize) // separated from LoadObject() -{ - BOOL bBinary; - DWORD dwAddress, i; - - bBinary = ((lpBuf[dwSize+0]=='H') - && (lpBuf[dwSize+1]=='P') - && (lpBuf[dwSize+2]=='H') - && (lpBuf[dwSize+3]=='P') - && (lpBuf[dwSize+4]=='4') - && (lpBuf[dwSize+5]==((cCurrentRomType!='X') ? '8' : '9')) - && (lpBuf[dwSize+6]=='-')); - - for (dwAddress = 0, i = 0; i < dwSize; i++) - { - BYTE byTwoNibs = lpBuf[i+dwSize]; - lpBuf[dwAddress++] = (BYTE)(byTwoNibs&0xF); - lpBuf[dwAddress++] = (BYTE)(byTwoNibs>>4); - } - - dwSize = dwAddress; // unpacked buffer size - - if (bBinary == TRUE) - { // load as binary - dwSize = RPL_ObjectSize(lpBuf+16,dwSize-16); - if (dwSize == BAD_OB) return S_ERR_OBJECT; - dwAddress = RPL_CreateTemp(dwSize); - if (dwAddress == 0) return S_ERR_BINARY; - Nwrite(lpBuf+16,dwAddress,dwSize); - } - else - { // load as string - dwAddress = RPL_CreateTemp(dwSize+10); - if (dwAddress == 0) return S_ERR_ASCII; - Write5(dwAddress,0x02A2C); // String - Write5(dwAddress+5,dwSize+5); // length of String - Nwrite(lpBuf,dwAddress+10,dwSize); // data - } - RPL_Push(nStkLevel,dwAddress); - return S_ERR_NO; -} - -BOOL LoadObject(LPCTSTR szFilename) // separated stack writing part -{ - HANDLE hFile; - DWORD dwFileSizeLow; - DWORD dwFileSizeHigh; - LPBYTE lpBuf; - WORD wError; - - hFile = CreateFile(szFilename, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - if (hFile == INVALID_HANDLE_VALUE) return FALSE; - dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); - if (dwFileSizeHigh != 0) - { // file is too large. - CloseHandle(hFile); - return FALSE; - } - lpBuf = (LPBYTE) malloc(dwFileSizeLow*2); - if (lpBuf == NULL) - { - CloseHandle(hFile); - return FALSE; - } - ReadFile(hFile, lpBuf+dwFileSizeLow, dwFileSizeLow, &dwFileSizeHigh, NULL); - CloseHandle(hFile); - - wError = WriteStack(1,lpBuf,dwFileSizeLow); - - if (wError == S_ERR_OBJECT) - AbortMessage(_T("This isn't a valid binary file.")); - - if (wError == S_ERR_BINARY) - AbortMessage(_T("The calculator does not have enough\nfree memory to load this binary file.")); - - if (wError == S_ERR_ASCII) - AbortMessage(_T("The calculator does not have enough\nfree memory to load this text file.")); - - free(lpBuf); - return (wError == S_ERR_NO); -} - -BOOL SaveObject(LPCTSTR szFilename) // separated stack reading part -{ - HANDLE hFile; - LPBYTE pbyHeader; - DWORD lBytesWritten; - DWORD dwAddress; - DWORD dwLength; - - dwAddress = RPL_Pick(1); - if (dwAddress == 0) - { - AbortMessage(_T("Too Few Arguments.")); - return FALSE; - } - dwLength = (RPL_SkipOb(dwAddress) - dwAddress + 1) / 2; - - hFile = CreateFile(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFile == INVALID_HANDLE_VALUE) - { - AbortMessage(_T("Cannot open file.")); - return FALSE; - } - - pbyHeader = (Chipset.type != 'X') ? (LPBYTE) BINARYHEADER48 : (LPBYTE) BINARYHEADER49; - WriteFile(hFile, pbyHeader, 8, &lBytesWritten, NULL); - - while (dwLength--) - { - BYTE byByte = Read2(dwAddress); - WriteFile(hFile, &byByte, 1, &lBytesWritten, NULL); - dwAddress += 2; - } - CloseHandle(hFile); - return TRUE; -} - - - -//################ -//# -//# Load Icon -//# -//################ - -BOOL LoadIconFromFile(LPCTSTR szFilename) -{ - HANDLE hIcon; - - SetCurrentDirectory(szEmuDirectory); - // not necessary to destroy because icon is shared - hIcon = LoadImage(NULL, szFilename, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_SHARED); - SetCurrentDirectory(szCurrentDirectory); - - if (hIcon) - { - SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIcon); - SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon); - } - return hIcon != NULL; -} - -VOID LoadIconDefault(VOID) -{ - // use window class icon - SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) NULL); - SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) NULL); - return; -} - - - -//################ -//# -//# Load Bitmap -//# -//################ - -#define WIDTHBYTES(bits) ((((bits) + 31) / 32) * 4) - -typedef struct _BmpFile -{ - DWORD dwPos; // actual reading pos - DWORD dwFileSize; // file size - LPBYTE pbyFile; // buffer -} BMPFILE, FAR *LPBMPFILE, *PBMPFILE; - -static __inline WORD DibNumColors(__unaligned BITMAPINFOHEADER CONST *lpbi) -{ - if (lpbi->biClrUsed != 0) return (WORD) lpbi->biClrUsed; - - /* a 24 bitcount DIB has no color table */ - return (lpbi->biBitCount <= 8) ? (1 << lpbi->biBitCount) : 0; -} - -static HPALETTE CreateBIPalette(__unaligned BITMAPINFOHEADER CONST *lpbi) -{ - LOGPALETTE* pPal; - HPALETTE hpal = NULL; - WORD wNumColors; - BYTE red; - BYTE green; - BYTE blue; - UINT i; - __unaligned RGBQUAD* pRgb; - - if (!lpbi || lpbi->biSize != sizeof(BITMAPINFOHEADER)) - return NULL; - - // Get a pointer to the color table and the number of colors in it - pRgb = (RGBQUAD FAR *)((LPBYTE)lpbi + (WORD)lpbi->biSize); - wNumColors = DibNumColors(lpbi); - - if (wNumColors) - { - // Allocate for the logical palette structure - pPal = (PLOGPALETTE) malloc(sizeof(LOGPALETTE) + wNumColors * sizeof(PALETTEENTRY)); - if (!pPal) return NULL; - - pPal->palVersion = 0x300; - pPal->palNumEntries = wNumColors; - - // Fill in the palette entries from the DIB color table and - // create a logical color palette. - for (i = 0; i < pPal->palNumEntries; i++) - { - pPal->palPalEntry[i].peRed = pRgb[i].rgbRed; - pPal->palPalEntry[i].peGreen = pRgb[i].rgbGreen; - pPal->palPalEntry[i].peBlue = pRgb[i].rgbBlue; - pPal->palPalEntry[i].peFlags = 0; - } - hpal = CreatePalette(pPal); - free(pPal); - } - else - { - // create halftone palette for 16, 24 and 32 bitcount bitmaps - - // 16, 24 and 32 bitcount DIB's have no color table entries so, set the - // number of to the maximum value (256). - wNumColors = 256; - pPal = (PLOGPALETTE) malloc(sizeof(LOGPALETTE) + wNumColors * sizeof(PALETTEENTRY)); - if (!pPal) return NULL; - - pPal->palVersion = 0x300; - pPal->palNumEntries = wNumColors; - - red = green = blue = 0; - - // Generate 256 (= 8*8*4) RGB combinations to fill the palette - // entries. - for (i = 0; i < pPal->palNumEntries; i++) - { - pPal->palPalEntry[i].peRed = red; - pPal->palPalEntry[i].peGreen = green; - pPal->palPalEntry[i].peBlue = blue; - pPal->palPalEntry[i].peFlags = 0; - - if (!(red += 32)) - if (!(green += 32)) - blue += 64; - } - hpal = CreatePalette(pPal); - free(pPal); - } - return hpal; -} - -static HBITMAP DecodeBmp(LPBMPFILE pBmp,BOOL bPalette) -{ - DWORD dwFileSize; - - HBITMAP hBitmap = NULL; - - // map memory to BITMAPFILEHEADER and BITMAPINFO - const LPBITMAPFILEHEADER pBmfh = (LPBITMAPFILEHEADER) pBmp->pbyFile; - const __unaligned LPBITMAPINFO pBmi = (__unaligned LPBITMAPINFO) & pBmfh[1]; - - // size of bitmap header information & check for bitmap - dwFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); - if ( pBmp->dwFileSize < dwFileSize // minimum size to read data from BITMAPFILEHEADER + BITMAPINFOHEADER - || pBmfh->bfType != 0x4D42) // "BM" - return NULL; - - // size with color table - if (pBmi->bmiHeader.biCompression == BI_BITFIELDS) - { - dwFileSize += 3 * sizeof(DWORD); - } - else - { - dwFileSize += DibNumColors(&pBmi->bmiHeader) * sizeof(RGBQUAD); - } - if (dwFileSize != pBmfh->bfOffBits) return NULL; - - // size with bitmap data - if (pBmi->bmiHeader.biCompression != BI_RGB) - { - dwFileSize += pBmi->bmiHeader.biSizeImage; - } - else - { - dwFileSize += WIDTHBYTES(pBmi->bmiHeader.biWidth * pBmi->bmiHeader.biBitCount) - * labs(pBmi->bmiHeader.biHeight); - } - if (pBmp->dwFileSize < dwFileSize) return NULL; - - VERIFY(hBitmap = CreateDIBitmap( - hWindowDC, - &pBmi->bmiHeader, - CBM_INIT, - pBmp->pbyFile + pBmfh->bfOffBits, - pBmi, DIB_RGB_COLORS)); - if (hBitmap == NULL) return NULL; - - if (bPalette && hPalette == NULL) - { - hPalette = CreateBIPalette(&pBmi->bmiHeader); - // save old palette - hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE); - RealizePalette(hWindowDC); - } - return hBitmap; -} - -static BOOL ReadGifByte(LPBMPFILE pGif, INT *n) -{ - // outside GIF file - if (pGif->dwPos >= pGif->dwFileSize) - return TRUE; - - *n = pGif->pbyFile[pGif->dwPos++]; - return FALSE; -} - -static BOOL ReadGifWord(LPBMPFILE pGif, INT *n) -{ - // outside GIF file - if (pGif->dwPos + 1 >= pGif->dwFileSize) - return TRUE; - - *n = pGif->pbyFile[pGif->dwPos++]; - *n |= (pGif->pbyFile[pGif->dwPos++] << 8); - return FALSE; -} - -static HBITMAP DecodeGif(LPBMPFILE pBmp,DWORD *pdwTransparentColor,BOOL bPalette) -{ - // this implementation base on the GIF image file - // decoder engine of Free42 (c) by Thomas Okken - - HBITMAP hBitmap; - - typedef struct cmap - { - WORD biBitCount; // bits used in color map - DWORD biClrUsed; // no of colors in color map - RGBQUAD bmiColors[256]; // color map - } CMAP; - - BOOL bHasGlobalCmap; - CMAP sGlb; // data of global color map - - INT nWidth,nHeight,nInfo,nBackground,nZero; - LONG lBytesPerLine; - - LPBYTE pbyPixels; - - BITMAPINFO bmi; // global bitmap info - - BOOL bDecoding = TRUE; - - hBitmap = NULL; - - pBmp->dwPos = 6; // position behind GIF header - - /* Bits 6..4 of info contain one less than the "color resolution", - * defined as the number of significant bits per RGB component in - * the source image's color palette. If the source image (from - * which the GIF was generated) was 24-bit true color, the color - * resolution is 8, so the value in bits 6..4 is 7. If the source - * image had an EGA color cube (2x2x2), the color resolution would - * be 2, etc. - * Bit 3 of info must be zero in GIF87a; in GIF89a, if it is set, - * it indicates that the global colormap is sorted, the most - * important entries being first. In PseudoColor environments this - * can be used to make sure to get the most important colors from - * the X server first, to optimize the image's appearance in the - * event that not all the colors from the colormap can actually be - * obtained at the same time. - * The 'zero' field is always 0 in GIF87a; in GIF89a, it indicates - * the pixel aspect ratio, as (PAR + 15) : 64. If PAR is zero, - * this means no aspect ratio information is given, PAR = 1 means - * 1:4 (narrow), PAR = 49 means 1:1 (square), PAR = 255 means - * slightly over 4:1 (wide), etc. - */ - - if ( ReadGifWord(pBmp,&nWidth) - || ReadGifWord(pBmp,&nHeight) - || ReadGifByte(pBmp,&nInfo) - || ReadGifByte(pBmp,&nBackground) - || ReadGifByte(pBmp,&nZero) - || nZero != 0) - goto quit; - - ZeroMemory(&bmi,sizeof(bmi)); // init bitmap info - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = nWidth; - bmi.bmiHeader.biHeight = nHeight; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 24; // create a true color DIB - bmi.bmiHeader.biCompression = BI_RGB; - - ZeroMemory(&sGlb,sizeof(sGlb)); // init global color map - bHasGlobalCmap = (nInfo & 0x80) != 0; - - sGlb.biBitCount = (nInfo & 7) + 1; // bits used in global color map - sGlb.biClrUsed = (1 << sGlb.biBitCount); // no of colors in global color map - - // color table should not exceed 256 colors - _ASSERT(sGlb.biClrUsed <= ARRAYSIZEOF(sGlb.bmiColors)); - - if (bHasGlobalCmap) // global color map - { - DWORD i; - - for (i = 0; i < sGlb.biClrUsed; ++i) - { - int r, g, b; - - if (ReadGifByte(pBmp,&r) || ReadGifByte(pBmp,&g) || ReadGifByte(pBmp,&b)) - goto quit; - - sGlb.bmiColors[i].rgbRed = r; - sGlb.bmiColors[i].rgbGreen = g; - sGlb.bmiColors[i].rgbBlue = b; - } - } - else // no color map - { - DWORD i; - - for (i = 0; i < sGlb.biClrUsed; ++i) - { - BYTE k = (BYTE) ((i * sGlb.biClrUsed) / (sGlb.biClrUsed - 1)); - - sGlb.bmiColors[i].rgbRed = k; - sGlb.bmiColors[i].rgbGreen = k; - sGlb.bmiColors[i].rgbBlue = k; - } - } - - // bitmap dimensions - lBytesPerLine = WIDTHBYTES(bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount); - bmi.bmiHeader.biSizeImage = lBytesPerLine * bmi.bmiHeader.biHeight; - - // create top-down DIB - bmi.bmiHeader.biHeight = -bmi.bmiHeader.biHeight; - - // allocate buffer for pixels - VERIFY(hBitmap = CreateDIBSection(hWindowDC, - &bmi, - DIB_RGB_COLORS, - (VOID **)&pbyPixels, - NULL, - 0)); - if (hBitmap == NULL) goto quit; - - // fill pixel buffer with background color - for (nHeight = 0; nHeight < labs(bmi.bmiHeader.biHeight); ++nHeight) - { - LPBYTE pbyLine = pbyPixels + nHeight * lBytesPerLine; - - for (nWidth = 0; nWidth < bmi.bmiHeader.biWidth; ++nWidth) - { - *pbyLine++ = sGlb.bmiColors[nBackground].rgbBlue; - *pbyLine++ = sGlb.bmiColors[nBackground].rgbGreen; - *pbyLine++ = sGlb.bmiColors[nBackground].rgbRed; - } - - _ASSERT((DWORD) (pbyLine - pbyPixels) <= bmi.bmiHeader.biSizeImage); - } - - while (bDecoding) - { - INT nBlockType; - - if (ReadGifByte(pBmp,&nBlockType)) goto quit; - - switch (nBlockType) - { - case ',': // image - { - CMAP sAct; // data of actual color map - - INT nLeft,nTop,nWidth,nHeight; - INT i,nInfo; - - BOOL bInterlaced; - INT h,v; - INT nCodesize; // LZW codesize in bits - INT nBytecount; - - SHORT prefix_table[4096]; - SHORT code_table[4096]; - - INT nMaxcode; - INT nClearCode; - INT nEndCode; - - INT nCurrCodesize; - INT nCurrCode; - INT nOldCode; - INT nBitsNeeded; - BOOL bEndCodeSeen; - - // read image dimensions - if ( ReadGifWord(pBmp,&nLeft) - || ReadGifWord(pBmp,&nTop) - || ReadGifWord(pBmp,&nWidth) - || ReadGifWord(pBmp,&nHeight) - || ReadGifByte(pBmp,&nInfo)) - goto quit; - - if ( nTop + nHeight > labs(bmi.bmiHeader.biHeight) - || nLeft + nWidth > bmi.bmiHeader.biWidth) - goto quit; - - /* Bit 3 of info must be zero in GIF87a; in GIF89a, if it - * is set, it indicates that the local colormap is sorted, - * the most important entries being first. In PseudoColor - * environments this can be used to make sure to get the - * most important colors from the X server first, to - * optimize the image's appearance in the event that not - * all the colors from the colormap can actually be - * obtained at the same time. - */ - - if ((nInfo & 0x80) == 0) // using global color map - { - sAct = sGlb; - } - else // using local color map - { - DWORD i; - - sAct.biBitCount = (nInfo & 7) + 1; // bits used in color map - sAct.biClrUsed = (1 << sAct.biBitCount); // no of colors in color map - - for (i = 0; i < sAct.biClrUsed; ++i) - { - int r, g, b; - - if (ReadGifByte(pBmp,&r) || ReadGifByte(pBmp,&g) || ReadGifByte(pBmp,&b)) - goto quit; - - sAct.bmiColors[i].rgbRed = r; - sAct.bmiColors[i].rgbGreen = g; - sAct.bmiColors[i].rgbBlue = b; - } - } - - // interlaced image - bInterlaced = (nInfo & 0x40) != 0; - - h = 0; - v = 0; - if ( ReadGifByte(pBmp,&nCodesize) - || ReadGifByte(pBmp,&nBytecount)) - goto quit; - - nMaxcode = (1 << nCodesize); - - // preset LZW table - for (i = 0; i < nMaxcode + 2; ++i) - { - prefix_table[i] = -1; - code_table[i] = i; - } - nClearCode = nMaxcode++; - nEndCode = nMaxcode++; - - nCurrCodesize = nCodesize + 1; - nCurrCode = 0; - nOldCode = -1; - nBitsNeeded = nCurrCodesize; - bEndCodeSeen = FALSE; - - while (nBytecount != 0) - { - for (i = 0; i < nBytecount; ++i) - { - INT nCurrByte; - INT nBitsAvailable; - - if (ReadGifByte(pBmp,&nCurrByte)) - goto quit; - - if (bEndCodeSeen) continue; - - nBitsAvailable = 8; - while (nBitsAvailable != 0) - { - INT nBitsCopied = (nBitsNeeded < nBitsAvailable) - ? nBitsNeeded - : nBitsAvailable; - - INT nBits = nCurrByte >> (8 - nBitsAvailable); - - nBits &= 0xFF >> (8 - nBitsCopied); - nCurrCode |= nBits << (nCurrCodesize - nBitsNeeded); - nBitsAvailable -= nBitsCopied; - nBitsNeeded -= nBitsCopied; - - if (nBitsNeeded == 0) - { - BYTE byExpanded[4096]; - INT nExplen; - - do - { - if (nCurrCode == nEndCode) - { - bEndCodeSeen = TRUE; - break; - } - - if (nCurrCode == nClearCode) - { - nMaxcode = (1 << nCodesize) + 2; - nCurrCodesize = nCodesize + 1; - nOldCode = -1; - break; - } - - if (nCurrCode < nMaxcode) - { - if (nMaxcode < 4096 && nOldCode != -1) - { - INT c = nCurrCode; - while (prefix_table[c] != -1) - c = prefix_table[c]; - c = code_table[c]; - prefix_table[nMaxcode] = nOldCode; - code_table[nMaxcode] = c; - nMaxcode++; - if (nMaxcode == (1 << nCurrCodesize) && nCurrCodesize < 12) - nCurrCodesize++; - } - } - else - { - INT c; - - if (nCurrCode > nMaxcode || nOldCode == -1) goto quit; - - _ASSERT(nCurrCode == nMaxcode); - - /* Once maxcode == 4096, we can't get here - * any more, because we refuse to raise - * nCurrCodeSize above 12 -- so we can - * never read a bigger code than 4095. - */ - - c = nOldCode; - while (prefix_table[c] != -1) - c = prefix_table[c]; - c = code_table[c]; - prefix_table[nMaxcode] = nOldCode; - code_table[nMaxcode] = c; - nMaxcode++; - - if (nMaxcode == (1 << nCurrCodesize) && nCurrCodesize < 12) - nCurrCodesize++; - } - nOldCode = nCurrCode; - - // output nCurrCode! - nExplen = 0; - while (nCurrCode != -1) - { - _ASSERT(nExplen < ARRAYSIZEOF(byExpanded)); - byExpanded[nExplen++] = (BYTE) code_table[nCurrCode]; - nCurrCode = prefix_table[nCurrCode]; - } - _ASSERT(nExplen > 0); - - while (--nExplen >= 0) - { - // get color map index - BYTE byColIndex = byExpanded[nExplen]; - - LPBYTE pbyRgbr = pbyPixels + (lBytesPerLine * (nTop + v) + 3 * (nLeft + h)); - - _ASSERT(pbyRgbr + 2 < pbyPixels + bmi.bmiHeader.biSizeImage); - _ASSERT(byColIndex < sAct.biClrUsed); - - *pbyRgbr++ = sAct.bmiColors[byColIndex].rgbBlue; - *pbyRgbr++ = sAct.bmiColors[byColIndex].rgbGreen; - *pbyRgbr = sAct.bmiColors[byColIndex].rgbRed; - - if (++h == nWidth) - { - h = 0; - if (bInterlaced) - { - switch (v & 7) - { - case 0: - v += 8; - if (v < nHeight) - break; - /* Some GIF en/decoders go - * straight from the '0' - * pass to the '4' pass - * without checking the - * height, and blow up on - * 2/3/4 pixel high - * interlaced images. - */ - if (nHeight > 4) - v = 4; - else - if (nHeight > 2) - v = 2; - else - if (nHeight > 1) - v = 1; - else - bEndCodeSeen = TRUE; - break; - case 4: - v += 8; - if (v >= nHeight) - v = 2; - break; - case 2: - case 6: - v += 4; - if (v >= nHeight) - v = 1; - break; - case 1: - case 3: - case 5: - case 7: - v += 2; - if (v >= nHeight) - bEndCodeSeen = TRUE; - break; - } - if (bEndCodeSeen) - break; // while (--nExplen >= 0) - } - else // non interlaced - { - if (++v == nHeight) - { - bEndCodeSeen = TRUE; - break; // while (--nExplen >= 0) - } - } - } - } - } - while (FALSE); - - nCurrCode = 0; - nBitsNeeded = nCurrCodesize; - } - } - } - - if (ReadGifByte(pBmp,&nBytecount)) - goto quit; - } - } - break; - - case '!': // extension block - { - INT i,nFunctionCode,nByteCount,nDummy; - - if (ReadGifByte(pBmp,&nFunctionCode)) goto quit; - if (ReadGifByte(pBmp,&nByteCount)) goto quit; - - // Graphic Control Label & correct Block Size - if (nFunctionCode == 0xF9 && nByteCount == 0x04) - { - INT nPackedFields,nColorIndex; - - // packed fields - if (ReadGifByte(pBmp,&nPackedFields)) goto quit; - - // delay time - if (ReadGifWord(pBmp,&nDummy)) goto quit; - - // transparent color index - if (ReadGifByte(pBmp,&nColorIndex)) goto quit; - - // transparent color flag set - if ((nPackedFields & 0x1) != 0) - { - if (pdwTransparentColor != NULL) - { - *pdwTransparentColor = RGB(sGlb.bmiColors[nColorIndex].rgbRed, - sGlb.bmiColors[nColorIndex].rgbGreen, - sGlb.bmiColors[nColorIndex].rgbBlue); - } - } - - // block terminator (0 byte) - if (!(!ReadGifByte(pBmp,&nDummy) && nDummy == 0)) goto quit; - } - else // other function - { - while (nByteCount != 0) - { - for (i = 0; i < nByteCount; ++i) - { - if (ReadGifByte(pBmp,&nDummy)) goto quit; - } - - if (ReadGifByte(pBmp,&nByteCount)) goto quit; - } - } - } - break; - - case ';': // terminator - bDecoding = FALSE; - break; - - default: goto quit; - } - } - - _ASSERT(bDecoding == FALSE); // decoding successful - - // normal decoding exit - if (bPalette && hPalette == NULL) - { - hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi); - // save old palette - hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE); - RealizePalette(hWindowDC); - } - -quit: - if (hBitmap != NULL && bDecoding) // creation failed - { - DeleteObject(hBitmap); // delete bitmap - hBitmap = NULL; - } - return hBitmap; -} - -static HBITMAP DecodePng(LPBMPFILE pBmp,BOOL bPalette) -{ - // this implementation use the PNG image file decoder - // engine of Copyright (c) 2005-2018 Lode Vandevenne - - HBITMAP hBitmap; - - UINT uError,uWidth,uHeight; - INT nWidth,nHeight; - LONG lBytesPerLine; - - LPBYTE pbyImage; // PNG RGB image data - LPBYTE pbySrc; // source buffer pointer - LPBYTE pbyPixels; // BMP buffer - - BITMAPINFO bmi; - - hBitmap = NULL; - pbyImage = NULL; - - // decode PNG image - uError = lodepng_decode_memory(&pbyImage,&uWidth,&uHeight,pBmp->pbyFile,pBmp->dwFileSize,LCT_RGB,8); - if (uError) goto quit; - - ZeroMemory(&bmi,sizeof(bmi)); // init bitmap info - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = (LONG) uWidth; - bmi.bmiHeader.biHeight = (LONG) uHeight; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 24; // create a true color DIB - bmi.bmiHeader.biCompression = BI_RGB; - - // bitmap dimensions - lBytesPerLine = WIDTHBYTES(bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount); - bmi.bmiHeader.biSizeImage = lBytesPerLine * bmi.bmiHeader.biHeight; - - // allocate buffer for pixels - VERIFY(hBitmap = CreateDIBSection(hWindowDC, - &bmi, - DIB_RGB_COLORS, - (VOID **)&pbyPixels, - NULL, - 0)); - if (hBitmap == NULL) goto quit; - - pbySrc = pbyImage; // init source loop pointer - pbyPixels += bmi.bmiHeader.biSizeImage; // end of destination bitmap - - // fill bottom up DIB pixel buffer with color information - for (nHeight = 0; nHeight < bmi.bmiHeader.biHeight; ++nHeight) - { - LPBYTE pbyLine; - - pbyPixels -= lBytesPerLine; // begin of previous row - pbyLine = pbyPixels; // row working copy - - for (nWidth = 0; nWidth < bmi.bmiHeader.biWidth; ++nWidth) - { - *pbyLine++ = pbySrc[2]; // blue - *pbyLine++ = pbySrc[1]; // green - *pbyLine++ = pbySrc[0]; // red - pbySrc += 3; - } - } - - if (bPalette && hPalette == NULL) - { - hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi); - // save old palette - hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE); - RealizePalette(hWindowDC); - } - -quit: - if (pbyImage != NULL) // buffer for PNG image allocated - { - free(pbyImage); // free PNG image data - } - return hBitmap; -} - -HBITMAP LoadBitmapFile(LPCTSTR szFilename,BOOL bPalette) -{ - HANDLE hFile; - HANDLE hMap; - BMPFILE Bmp; - HBITMAP hBitmap; - - SetCurrentDirectory(szEmuDirectory); - hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - SetCurrentDirectory(szCurrentDirectory); - if (hFile == INVALID_HANDLE_VALUE) return NULL; - Bmp.dwFileSize = GetFileSize(hFile, NULL); - hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); - if (hMap == NULL) - { - CloseHandle(hFile); - return NULL; - } - Bmp.pbyFile = (LPBYTE) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); - if (Bmp.pbyFile == NULL) - { - CloseHandle(hMap); - CloseHandle(hFile); - return NULL; - } - - do - { - // check for bitmap file header "BM" - if (Bmp.dwFileSize >= 2 && *(WORD *) Bmp.pbyFile == 0x4D42) - { - hBitmap = DecodeBmp(&Bmp,bPalette); - break; - } - - // check for GIF file header - if ( Bmp.dwFileSize >= 6 - && (memcmp(Bmp.pbyFile,"GIF87a",6) == 0 || memcmp(Bmp.pbyFile,"GIF89a",6) == 0)) - { - hBitmap = DecodeGif(&Bmp,&dwTColor,bPalette); - break; - } - - // check for PNG file header - if (Bmp.dwFileSize >= 8 && memcmp(Bmp.pbyFile,"\x89PNG\r\n\x1a\n",8) == 0) - { - hBitmap = DecodePng(&Bmp,bPalette); - break; - } - - // unknown file type - hBitmap = NULL; - } - while (FALSE); - - UnmapViewOfFile(Bmp.pbyFile); - CloseHandle(hMap); - CloseHandle(hFile); - return hBitmap; -} - -static BOOL AbsColorCmp(DWORD dwColor1,DWORD dwColor2,DWORD dwTol) -{ - DWORD dwDiff; - - dwDiff = (DWORD) abs((INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF)); - dwColor1 >>= 8; - dwColor2 >>= 8; - dwDiff += (DWORD) abs((INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF)); - dwColor1 >>= 8; - dwColor2 >>= 8; - dwDiff += (DWORD) abs((INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF)); - - return dwDiff > dwTol; // FALSE = colors match -} - -static BOOL LabColorCmp(DWORD dwColor1,DWORD dwColor2,DWORD dwTol) -{ - DWORD dwDiff; - INT nDiffCol; - - nDiffCol = (INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF); - dwDiff = (DWORD) (nDiffCol * nDiffCol); - dwColor1 >>= 8; - dwColor2 >>= 8; - nDiffCol = (INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF); - dwDiff += (DWORD) (nDiffCol * nDiffCol); - dwColor1 >>= 8; - dwColor2 >>= 8; - nDiffCol = (INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF); - dwDiff += (DWORD) (nDiffCol * nDiffCol); - dwTol *= dwTol; - - return dwDiff > dwTol; // FALSE = colors match -} - -static DWORD EncodeColorBits(DWORD dwColorVal,DWORD dwMask) -{ - #define MAXBIT 32 - UINT uLshift = MAXBIT; - UINT uRshift = 8; - DWORD dwBitMask = dwMask; - - dwColorVal &= 0xFF; // the color component using the lowest 8 bit - - // position of highest bit - while ((dwBitMask & (1<<(MAXBIT-1))) == 0 && uLshift > 0) - { - dwBitMask <<= 1; // next bit - --uLshift; // next position - } - - if (uLshift > 24) // avoid overflow on 32bit mask - { - uLshift -= uRshift; // normalize left shift - uRshift = 0; - } - - return ((dwColorVal << uLshift) >> uRshift) & dwMask; - #undef MAXBIT -} - -HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol) -{ - #define ADD_RECTS_COUNT 256 - - BOOL (*fnColorCmp)(DWORD dwColor1,DWORD dwColor2,DWORD dwTol); - - DWORD dwRed,dwGreen,dwBlue; - LPRGNDATA pRgnData; - LPBITMAPINFO bi; - LPBYTE pbyBits; - LPBYTE pbyColor; - DWORD dwAlignedWidthBytes; - DWORD dwBpp; - DWORD dwRectsCount; - LONG x,y,xleft; - BOOL bFoundLeft; - BOOL bIsMask; - - HRGN hRgn = NULL; // no region defined - - if (dwTol >= 1000) // use CIE L*a*b compare - { - fnColorCmp = LabColorCmp; - dwTol -= 1000; // remove L*a*b compare selector - } - else // use Abs summation compare - { - fnColorCmp = AbsColorCmp; - } - - // allocate memory for extended image information incl. RGBQUAD color table - if ((bi = (LPBITMAPINFO) calloc(1,sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD))) == NULL) - { - return hRgn; // no region - } - bi->bmiHeader.biSize = sizeof(bi->bmiHeader); - _ASSERT(bi->bmiHeader.biBitCount == 0); // for query without color table - - // get information about image - GetDIBits(hWindowDC,hBmp,0,0,NULL,bi,DIB_RGB_COLORS); - - // DWORD aligned bitmap width in BYTES - dwAlignedWidthBytes = WIDTHBYTES( bi->bmiHeader.biWidth - * bi->bmiHeader.biPlanes - * bi->bmiHeader.biBitCount); - - // biSizeImage is empty - if (bi->bmiHeader.biSizeImage == 0 && bi->bmiHeader.biCompression == BI_RGB) - { - bi->bmiHeader.biSizeImage = dwAlignedWidthBytes * bi->bmiHeader.biHeight; - } - - // allocate memory for image data (colors) - if ((pbyBits = (LPBYTE) malloc(bi->bmiHeader.biSizeImage)) == NULL) - { - free(bi); // free bitmap info - return hRgn; // no region - } - - // fill bits buffer - GetDIBits(hWindowDC,hBmp,0,bi->bmiHeader.biHeight,pbyBits,bi,DIB_RGB_COLORS); - - // convert color if current DC is 16-bit/32-bit bitfield coded - if (bi->bmiHeader.biCompression == BI_BITFIELDS) - { - dwRed = *(LPDWORD) &bi->bmiColors[0]; - dwGreen = *(LPDWORD) &bi->bmiColors[1]; - dwBlue = *(LPDWORD) &bi->bmiColors[2]; - } - else // RGB coded - { - // convert color if current DC is 16-bit RGB coded - if (bi->bmiHeader.biBitCount == 16) - { - // for 15 bit (5:5:5) - dwRed = 0x00007C00; - dwGreen = 0x000003E0; - dwBlue = 0x0000001F; - } - else - { - // convert COLORREF to RGBQUAD color - dwRed = 0x00FF0000; - dwGreen = 0x0000FF00; - dwBlue = 0x000000FF; - } - } - color = EncodeColorBits((color >> 16), dwBlue) - | EncodeColorBits((color >> 8), dwGreen) - | EncodeColorBits((color >> 0), dwRed); - - dwBpp = bi->bmiHeader.biBitCount >> 3; // bytes per pixel - - // DIB is bottom up image so we begin with the last scanline - pbyColor = pbyBits + (bi->bmiHeader.biHeight - 1) * dwAlignedWidthBytes; - - dwRectsCount = bi->bmiHeader.biHeight; // number of rects in allocated buffer - - bFoundLeft = FALSE; // set when mask has been found in current scan line - - // allocate memory for region data - pRgnData = (PRGNDATA) malloc(sizeof(RGNDATAHEADER) + dwRectsCount * sizeof(RECT)); - if (pRgnData) - { - // fill it by default - ZeroMemory(&pRgnData->rdh,sizeof(pRgnData->rdh)); - pRgnData->rdh.dwSize = sizeof(pRgnData->rdh); - pRgnData->rdh.iType = RDH_RECTANGLES; - SetRect(&pRgnData->rdh.rcBound,MAXLONG,MAXLONG,0,0); - } - - for (y = 0; pRgnData && y < bi->bmiHeader.biHeight; ++y) - { - LPBYTE pbyLineStart = pbyColor; - - for (x = 0; pRgnData && x < bi->bmiHeader.biWidth; ++x) - { - // get color - switch (bi->bmiHeader.biBitCount) - { - case 8: - bIsMask = fnColorCmp(*(LPDWORD)(&bi->bmiColors)[*pbyColor],color,dwTol); - break; - case 16: - // it makes no sense to allow a tolerance here - bIsMask = (*(LPWORD)pbyColor != (WORD) color); - break; - case 24: - bIsMask = fnColorCmp((*(LPDWORD)pbyColor & 0x00ffffff),color,dwTol); - break; - case 32: - bIsMask = fnColorCmp(*(LPDWORD)pbyColor,color,dwTol); - } - pbyColor += dwBpp; // shift pointer to next color - - if (!bFoundLeft && bIsMask) // non transparent color found - { - xleft = x; - bFoundLeft = TRUE; - } - - if (bFoundLeft) // found non transparent color in scanline - { - // transparent color or last column - if (!bIsMask || x + 1 == bi->bmiHeader.biWidth) - { - // non transparent color and last column - if (bIsMask && x + 1 == bi->bmiHeader.biWidth) - ++x; - - // save current RECT - ((LPRECT) pRgnData->Buffer)[pRgnData->rdh.nCount].left = xleft; - ((LPRECT) pRgnData->Buffer)[pRgnData->rdh.nCount].top = y; - ((LPRECT) pRgnData->Buffer)[pRgnData->rdh.nCount].right = x; - ((LPRECT) pRgnData->Buffer)[pRgnData->rdh.nCount].bottom = y + 1; - pRgnData->rdh.nCount++; - - if (xleft < pRgnData->rdh.rcBound.left) - pRgnData->rdh.rcBound.left = xleft; - - if (y < pRgnData->rdh.rcBound.top) - pRgnData->rdh.rcBound.top = y; - - if (x > pRgnData->rdh.rcBound.right) - pRgnData->rdh.rcBound.right = x; - - if (y + 1 > pRgnData->rdh.rcBound.bottom) - pRgnData->rdh.rcBound.bottom = y + 1; - - // if buffer full reallocate it with more room - if (pRgnData->rdh.nCount >= dwRectsCount) - { - LPRGNDATA pNewRgnData; - - dwRectsCount += ADD_RECTS_COUNT; - pNewRgnData = (LPRGNDATA) realloc(pRgnData,sizeof(RGNDATAHEADER) + dwRectsCount * sizeof(RECT)); - if (pNewRgnData) - { - pRgnData = pNewRgnData; - } - else - { - free(pRgnData); - pRgnData = NULL; - } - } - - bFoundLeft = FALSE; - } - } - } - - // previous scanline - pbyColor = pbyLineStart - dwAlignedWidthBytes; - } - // release image data - free(pbyBits); - free(bi); - - if (pRgnData) // has region data, create region - { - hRgn = ExtCreateRegion(NULL,sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount * sizeof(RECT),pRgnData); - free(pRgnData); - } - return hRgn; - #undef ADD_RECTS_COUNT -} +/* + * files.c + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ +#include "pch.h" +#include "Emu48.h" +#include "ops.h" +#include "io.h" // I/O register definitions +#include "kml.h" +#include "i28f160.h" // flash support +#include "debugger.h" +#include "lodepng.h" + +#pragma intrinsic(abs,labs) + +TCHAR szEmuDirectory[MAX_PATH]; +TCHAR szCurrentDirectory[MAX_PATH]; +TCHAR szCurrentKml[MAX_PATH]; +TCHAR szBackupKml[MAX_PATH]; +TCHAR szCurrentFilename[MAX_PATH]; +TCHAR szBackupFilename[MAX_PATH]; +TCHAR szBufferFilename[MAX_PATH]; +TCHAR szPort2Filename[MAX_PATH]; + +BOOL bDocumentAvail = FALSE; // document not available + +BYTE cCurrentRomType = 0; // Model -> hardware +UINT nCurrentClass = 0; // Class -> derivate + +LPBYTE Port0 = NULL; +LPBYTE Port1 = NULL; +LPBYTE Port2 = NULL; + +LPBYTE pbyRom = NULL; +BOOL bRomWriteable = TRUE; // flag if ROM writeable +DWORD dwRomSize = 0; +LPBYTE pbyRomDirtyPage = NULL; +DWORD dwRomDirtyPageSize = 0; +WORD wRomCrc = 0; // fingerprint of patched ROM +BOOL bRomCrcCorrection = FALSE; // ROM CRC correction disabled + +LPBYTE pbyPort2 = NULL; +BOOL bPort2Writeable = FALSE; +BOOL bPort2IsShared = FALSE; +DWORD dwPort2Size = 0; // size of mapped port2 +DWORD dwPort2Mask = 0; +WORD wPort2Crc = 0; // fingerprint of port2 + +BOOL bBackup = FALSE; + +static HANDLE hRomFile = NULL; +static HANDLE hPort2File = NULL; +static HANDLE hPort2Map = NULL; +static HANDLE hCurrentFile = NULL; + +// valid document signatures +static CONST LPBYTE bySignature[] = +{ + (CONST LPBYTE) "Emu48 Document\xFE", + (CONST LPBYTE) "Emu38 Document\xFE", + (CONST LPBYTE) "Emu39 Document\xFE", + (CONST LPBYTE) "Emu49 Document\xFE", + (CONST LPBYTE) "Win48 Document\xFE", + (CONST LPBYTE) "Win48 Document\xFF" +}; + +static CHIPSET BackupChipset; +static LPBYTE BackupPort0; +static LPBYTE BackupPort1; +static LPBYTE BackupPort2; +static BOOL bRomPacked; + +//################ +//# +//# Window Position Tools +//# +//################ + +VOID SetWindowLocation(HWND hWnd,INT nPosX,INT nPosY) +{ + WINDOWPLACEMENT wndpl; + RECT *pRc = &wndpl.rcNormalPosition; + + wndpl.length = sizeof(wndpl); + GetWindowPlacement(hWnd,&wndpl); + pRc->right = pRc->right - pRc->left + nPosX; + pRc->bottom = pRc->bottom - pRc->top + nPosY; + pRc->left = nPosX; + pRc->top = nPosY; + SetWindowPlacement(hWnd,&wndpl); + return; +} + + + +//################ +//# +//# Filename Title Helper Tool +//# +//################ + +DWORD GetCutPathName(LPCTSTR szFileName, LPTSTR szBuffer, DWORD dwBufferLength, INT nCutLength) +{ + TCHAR cPath[_MAX_PATH]; // full filename + TCHAR cDrive[_MAX_DRIVE]; + TCHAR cDir[_MAX_DIR]; + TCHAR cFname[_MAX_FNAME]; + TCHAR cExt[_MAX_EXT]; + + _ASSERT(nCutLength >= 0); // 0 = only drive and name + + // split original filename into parts + _tsplitpath(szFileName,cDrive,cDir,cFname,cExt); + + if (*cDir != 0) // contain directory part + { + LPTSTR lpFilePart; // address of file name in path + INT nNameLen,nPathLen,nMaxPathLen; + + GetFullPathName(szFileName,ARRAYSIZEOF(cPath),cPath,&lpFilePart); + _tsplitpath(cPath,cDrive,cDir,cFname,cExt); + + // calculate size of drive/name and path + nNameLen = lstrlen(cDrive) + lstrlen(cFname) + lstrlen(cExt); + nPathLen = lstrlen(cDir); + + // maximum length for path + nMaxPathLen = nCutLength - nNameLen; + + if (nPathLen > nMaxPathLen) // have to cut path + { + TCHAR cDirTemp[_MAX_DIR] = _T(""); + LPTSTR szPtr; + + // UNC name + if (cDir[0] == _T('\\') && cDir[1] == _T('\\')) + { + // skip server + if ((szPtr = _tcschr(cDir + 2,_T('\\'))) != NULL) + { + // skip share + if ((szPtr = _tcschr(szPtr + 1,_T('\\'))) != NULL) + { + INT nLength = (INT) (szPtr - cDir); + + *szPtr = 0; // set EOS behind share + + // enough room for \\server\\share and "\...\" + if (nLength + 5 <= nMaxPathLen) + { + lstrcpyn(cDirTemp,cDir,ARRAYSIZEOF(cDirTemp)); + nMaxPathLen -= nLength; + } + + } + } + } + + lstrcat(cDirTemp,_T("\\...")); + nMaxPathLen -= 5; // need 6 chars for additional "\..." + "\" + if (nMaxPathLen < 0) nMaxPathLen = 0; + + // get earliest possible '\' character + szPtr = &cDir[nPathLen - nMaxPathLen]; + szPtr = _tcschr(szPtr,_T('\\')); + // not found + if (szPtr == NULL) szPtr = _T(""); + + lstrcat(cDirTemp,szPtr); // copy path with preample to dir buffer + lstrcpyn(cDir,cDirTemp,ARRAYSIZEOF(cDir)); + } + } + + _tmakepath(cPath,cDrive,cDir,cFname,cExt); + lstrcpyn(szBuffer,cPath,dwBufferLength); + return lstrlen(szBuffer); +} + +VOID SetWindowPathTitle(LPCTSTR szFileName) +{ + TCHAR cPath[MAX_PATH]; + RECT rectClient; + + if (*szFileName != 0) // set new title + { + _ASSERT(hWnd != NULL); + VERIFY(GetClientRect(hWnd,&rectClient)); + GetCutPathName(szFileName,cPath,ARRAYSIZEOF(cPath),rectClient.right/11); + SetWindowTitle(cPath); + } + return; +} + + + +//################ +//# +//# BEEP Patch check +//# +//################ + +BOOL CheckForBeepPatch(VOID) +{ + typedef struct beeppatch + { + const DWORD dwAddress; // patch address + const BYTE byPattern[4]; // patch pattern + } BEEPPATCH, *PBEEPPATCH; + + // known beep patches + const BEEPPATCH s38[] = { { 0x017D0, { 0x8, 0x1, 0xB, 0x1 } } }; + const BEEPPATCH s39[] = { { 0x017BC, { 0x8, 0x1, 0xB, 0x1 } } }; + const BEEPPATCH s48[] = { { 0x017A6, { 0x8, 0x1, 0xB, 0x1 } } }; + const BEEPPATCH s49[] = { { 0x4157A, { 0x8, 0x1, 0xB, 0x1 } }, // 1.18/1.19-5/1.19-6 + { 0x41609, { 0x8, 0x1, 0xB, 0x1 } } }; // 1.24/2.01/2.09 + + const BEEPPATCH *psData; + UINT nDataItems; + BOOL bMatch; + + switch (cCurrentRomType) + { + case '6': + case 'A': // HP38G + psData = s38; + nDataItems = ARRAYSIZEOF(s38); + break; + case 'E': // HP39/40G + psData = s39; + nDataItems = ARRAYSIZEOF(s39); + break; + case 'S': // HP48SX + case 'G': // HP48GX + psData = s48; + nDataItems = ARRAYSIZEOF(s48); + break; + case 'X': // HP49G + psData = s49; + nDataItems = ARRAYSIZEOF(s49); + break; + default: + psData = NULL; + nDataItems = 0; + } + + // check if one data set match + for (bMatch = FALSE; !bMatch && nDataItems > 0; --nDataItems) + { + _ASSERT(pbyRom != NULL && psData != NULL); + + // pattern matching? + bMatch = (psData->dwAddress + ARRAYSIZEOF(psData->byPattern) < dwRomSize) + && (memcmp(&pbyRom[psData->dwAddress],psData->byPattern,ARRAYSIZEOF(psData->byPattern))) == 0; + ++psData; // next data set + } + return bMatch; +} + + + +//################ +//# +//# Patch +//# +//################ + +static __inline BYTE Asc2Nib(BYTE c) +{ + if (c<'0') return 0; + if (c<='9') return c-'0'; + if (c<'A') return 0; + if (c<='F') return c-'A'+10; + if (c<'a') return 0; + if (c<='f') return c-'a'+10; + return 0; +} + +// functions to restore ROM patches +typedef struct tnode +{ + BOOL bPatch; // TRUE = ROM address patched + DWORD dwAddress; // patch address + BYTE byROM; // original ROM value + BYTE byPatch; // patched ROM value + struct tnode *prev; // previous node + struct tnode *next; // next node +} TREENODE, *PTREENODE; + +static TREENODE *nodePatch = NULL; + +BOOL PatchNibble(DWORD dwAddress, BYTE byPatch) +{ + PTREENODE p; + + _ASSERT(pbyRom); // ROM defined + if ((p = (PTREENODE) malloc(sizeof(TREENODE))) == NULL) + return TRUE; + + p->bPatch = TRUE; // address patched + p->dwAddress = dwAddress; // save current values + p->byROM = pbyRom[dwAddress]; + p->byPatch = byPatch; + p->prev = NULL; + p->next = nodePatch; // save node + + if (nodePatch) nodePatch->prev = p; // add as previous element + nodePatch = p; + + pbyRom[dwAddress] = byPatch; // patch ROM + return FALSE; +} + +static VOID RestorePatches(VOID) +{ + TREENODE *p; + + _ASSERT(pbyRom); // ROM defined + while (nodePatch != NULL) + { + // restore original data + pbyRom[nodePatch->dwAddress] = nodePatch->byROM; + + p = nodePatch->next; // save pointer to next node + free(nodePatch); // free node + nodePatch = p; // new node + } + return; +} + +VOID UpdatePatches(BOOL bPatch) +{ + TREENODE *p = nodePatch; + + _ASSERT(pbyRom); // ROM defined + if (bPatch) // patch ROM + { + if (p) // something in patch list + { + // goto last element in list + for (; p->next != NULL; p = p->next) {} + + do + { + if (!p->bPatch) // patch only if not patched + { + // use original data for patch restore + p->byROM = pbyRom[p->dwAddress]; + + // restore patch data + pbyRom[p->dwAddress] = p->byPatch; + p->bPatch = TRUE; // address patched + } + else + { + _ASSERT(FALSE); // call ROM patch on a patched ROM + } + + p = p->prev; + } + while (p != NULL); + } + } + else // restore ROM + { + for (; p != NULL; p = p->next) + { + // restore original data + pbyRom[p->dwAddress] = p->byROM; + p->bPatch = FALSE; // address not patched + } + } + return; +} + +BOOL PatchRom(LPCTSTR szFilename) +{ + HANDLE hFile = NULL; + DWORD dwFileSizeLow = 0; + DWORD dwFileSizeHigh = 0; + DWORD lBytesRead = 0; + PSZ lpStop,lpBuf = NULL; + DWORD dwAddress = 0; + UINT nPos = 0; + BOOL bSucc = TRUE; + + if (pbyRom == NULL) return FALSE; + SetCurrentDirectory(szEmuDirectory); + hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + SetCurrentDirectory(szCurrentDirectory); + if (hFile == INVALID_HANDLE_VALUE) return FALSE; + dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); + if (dwFileSizeHigh != 0 || dwFileSizeLow == 0) + { // file is too large or empty + CloseHandle(hFile); + return FALSE; + } + lpBuf = (PSZ) malloc(dwFileSizeLow+1); + if (lpBuf == NULL) + { + CloseHandle(hFile); + return FALSE; + } + ReadFile(hFile, lpBuf, dwFileSizeLow, &lBytesRead, NULL); + CloseHandle(hFile); + lpBuf[dwFileSizeLow] = 0; + nPos = 0; + while (lpBuf[nPos]) + { + // skip whitespace characters + nPos += (UINT) strspn(&lpBuf[nPos]," \t\n\r"); + + if (lpBuf[nPos] == ';') // comment? + { + do + { + nPos++; + if (lpBuf[nPos] == '\n') + { + nPos++; + break; + } + } while (lpBuf[nPos]); + continue; + } + dwAddress = strtoul(&lpBuf[nPos], &lpStop, 16); + nPos = (UINT) (lpStop - lpBuf); // position of lpStop + + if (*lpStop != 0) // data behind address + { + if (*lpStop != ':') // invalid syntax + { + // skip to end of line + while (lpBuf[nPos] != '\n' && lpBuf[nPos] != 0) + { + ++nPos; + } + bSucc = FALSE; + continue; + } + + while (lpBuf[++nPos]) + { + if (isxdigit(lpBuf[nPos]) == FALSE) break; + if (dwAddress < dwRomSize) // patch ROM + { + // patch ROM and save original nibble + PatchNibble(dwAddress, Asc2Nib(lpBuf[nPos])); + bRomCrcCorrection = TRUE; + } + ++dwAddress; + } + } + } + _ASSERT(nPos <= dwFileSizeLow); // buffer overflow? + free(lpBuf); + return bSucc; +} + + + +//################ +//# +//# ROM +//# +//################ + +BOOL CrcRom(WORD *pwChk) // calculate fingerprint of ROM +{ + DWORD *pdwData,dwSize; + DWORD dwChk = 0; + + if (pbyRom == NULL) return TRUE; // ROM CRC isn't available + + _ASSERT(pbyRom); // view on ROM + pdwData = (DWORD *) pbyRom; + + _ASSERT((dwRomSize % sizeof(*pdwData)) == 0); + dwSize = dwRomSize / sizeof(*pdwData); // file size in DWORD's + + // use checksum, because it's faster + while (dwSize-- > 0) + { + CONST DWORD dwData = *pdwData++; + if ((dwData & 0xF0F0F0F0) != 0) // data packed? + return FALSE; + dwChk += dwData; + } + + *pwChk = (WORD) ((dwChk >> 16) + (dwChk & 0xFFFF)); + return TRUE; +} + +BOOL MapRom(LPCTSTR szFilename) +{ + DWORD dwSize,dwFileSize,dwRead; + + // open ROM for writing + BOOL bRomRW = (cCurrentRomType == 'X') ? bRomWriteable : FALSE; + + if (pbyRom != NULL) + { + return FALSE; + } + bRomCrcCorrection = FALSE; // ROM CRC correction disabled + SetCurrentDirectory(szEmuDirectory); + if (bRomRW) // ROM writeable + { + hRomFile = CreateFile(szFilename, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + if (hRomFile == INVALID_HANDLE_VALUE) + { + bRomRW = FALSE; // ROM not writeable + hRomFile = CreateFile(szFilename, + GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + } + } + else // writing ROM disabled + { + hRomFile = CreateFile(szFilename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + } + SetCurrentDirectory(szCurrentDirectory); + if (hRomFile == INVALID_HANDLE_VALUE) + { + hRomFile = NULL; + return FALSE; + } + dwRomSize = GetFileSize(hRomFile, NULL); + + // read the first 4 bytes + ReadFile(hRomFile,&dwSize,sizeof(dwSize),&dwRead,NULL); + if (dwRead < sizeof(dwSize)) + { // file is too small. + CloseHandle(hRomFile); + hRomFile = NULL; + dwRomSize = 0; + return FALSE; + } + + dwFileSize = dwRomSize; // calculate ROM image buffer size + bRomPacked = (dwSize & 0xF0F0F0F0) != 0; // ROM image packed + if (bRomPacked) dwRomSize *= 2; // unpacked ROM image has double size + + pbyRom = (LPBYTE) malloc(dwRomSize); + if (pbyRom == NULL) + { + CloseHandle(hRomFile); + hRomFile = NULL; + dwRomSize = 0; + return FALSE; + } + + *(DWORD *) pbyRom = dwSize; // save first 4 bytes + + // load rest of file content + ReadFile(hRomFile,&pbyRom[sizeof(dwSize)],dwFileSize - sizeof(dwSize),&dwRead,NULL); + _ASSERT(dwFileSize - sizeof(dwSize) == dwRead); + + if (bRomRW) // ROM is writeable + { + // no. of dirty pages + dwRomDirtyPageSize = dwRomSize / ROMPAGESIZE; + + // alloc dirty page table + pbyRomDirtyPage = (LPBYTE) calloc(dwRomDirtyPageSize,sizeof(*pbyRomDirtyPage)); + if (pbyRomDirtyPage == NULL) + { + free(pbyRom); // free ROM image + CloseHandle(hRomFile); + dwRomDirtyPageSize = 0; + pbyRom = NULL; + hRomFile = NULL; + dwRomSize = 0; + return FALSE; + } + } + else + { + dwRomDirtyPageSize = 0; + CloseHandle(hRomFile); + hRomFile = NULL; + } + + if (bRomPacked) // packed ROM image + { + LPBYTE pbySrc = pbyRom+dwFileSize; // source start address + LPBYTE pbyDest = pbyRom+dwRomSize; // destination start address + while (pbySrc != pbyDest) // unpack source + { + CONST BYTE byValue = *(--pbySrc); + *(--pbyDest) = byValue >> 4; + *(--pbyDest) = byValue & 0xF; + } + } + return TRUE; +} + +VOID UnmapRom(VOID) +{ + if (pbyRom == NULL) return; // ROM not mapped + RestorePatches(); // restore ROM patches + if (hRomFile) // ROM file still open (only in R/W case) + { + DWORD i; + + _ASSERT(pbyRomDirtyPage != NULL); + + // scan for every dirty page + for (i = 0; i < dwRomDirtyPageSize; ++i) + { + if (pbyRomDirtyPage[i]) // page dirty + { + DWORD dwSize,dwLinPos,dwFilePos,dwWritten; + + dwLinPos = i * ROMPAGESIZE; // position inside emulator memory + + dwSize = ROMPAGESIZE; // bytes to write + while (i+1 < dwRomDirtyPageSize && pbyRomDirtyPage[i+1]) + { + dwSize += ROMPAGESIZE; // next page is also dirty + ++i; // skip next page in outer loop + } + + dwFilePos = dwLinPos; // ROM file position + + if (bRomPacked) // repack data + { + LPBYTE pbySrc,pbyDest,pbyEnd; + + dwSize /= 2; // adjust no. of bytes to write + dwFilePos /= 2; // linear pos in packed file + + // pack data in page + pbySrc = pbyDest = &pbyRom[dwLinPos]; + pbyEnd = pbyDest + dwSize; + while (pbyDest < pbyEnd) + { + *pbyDest = *pbySrc++; + *pbyDest |= *pbySrc++ << 4; + ++pbyDest; + } + } + + SetFilePointer(hRomFile,dwFilePos,NULL,FILE_BEGIN); + WriteFile(hRomFile,&pbyRom[dwLinPos],dwSize,&dwWritten,NULL); + } + } + + free(pbyRomDirtyPage); + CloseHandle(hRomFile); + pbyRomDirtyPage = NULL; + dwRomDirtyPageSize = 0; + hRomFile = NULL; + } + + free(pbyRom); // free ROM image + pbyRom = NULL; + dwRomSize = 0; + wRomCrc = 0; + bRomCrcCorrection = FALSE; // ROM CRC correction disabled + return; +} + + + +//################ +//# +//# Port2 +//# +//################ + +static BOOL CrcPort2(WORD *pwCrc) // calculate fingerprint of port2 +{ + *pwCrc = 0; + + if (pbyPort2 != NULL) // port2 CRC available + { + LPBYTE pbyMem; + + // get real filesize + DWORD dwFileSize = GetFileSize(hPort2File, NULL); + + for (pbyMem = pbyPort2; dwFileSize > 0; --dwFileSize) + { + if ((*pbyMem & 0xF0) != 0) // data packed? + return FALSE; + + *pwCrc = UpCRC(*pwCrc,*pbyMem++); + } + } + return TRUE; +} + +BOOL MapPort2(LPCTSTR szFilename) +{ + DWORD dwFileSizeLo,dwFileSizeHi; + + if (pbyPort2 != NULL) return FALSE; + bPort2Writeable = TRUE; + dwPort2Size = 0; // reset size of port2 + + SetCurrentDirectory(szEmuDirectory); + hPort2File = CreateFile(szFilename, + GENERIC_READ|GENERIC_WRITE, + bPort2IsShared ? FILE_SHARE_READ : 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hPort2File == INVALID_HANDLE_VALUE) + { + bPort2Writeable = FALSE; + hPort2File = CreateFile(szFilename, + GENERIC_READ, + bPort2IsShared ? (FILE_SHARE_READ|FILE_SHARE_WRITE) : 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hPort2File == INVALID_HANDLE_VALUE) + { + SetCurrentDirectory(szCurrentDirectory); + hPort2File = NULL; + return FALSE; + } + } + SetCurrentDirectory(szCurrentDirectory); + dwFileSizeLo = GetFileSize(hPort2File, &dwFileSizeHi); + + // size not 32, 128, 256, 512, 1024, 2048 or 4096 KB + if ( dwFileSizeHi != 0 + || dwFileSizeLo == 0 + || (dwFileSizeLo & (dwFileSizeLo - 1)) != 0 + || (dwFileSizeLo & 0xFF02FFFF) != 0) + { + UnmapPort2(); + return FALSE; + } + + hPort2Map = CreateFileMapping(hPort2File, NULL, bPort2Writeable ? PAGE_READWRITE : PAGE_READONLY, + 0, dwFileSizeLo, NULL); + if (hPort2Map == NULL) + { + UnmapPort2(); + return FALSE; + } + pbyPort2 = (LPBYTE) MapViewOfFile(hPort2Map, bPort2Writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, 0, dwFileSizeLo); + if (pbyPort2 == NULL) + { + UnmapPort2(); + return FALSE; + } + + dwPort2Mask = (dwFileSizeLo - 1) >> 18; // mask for valid address lines of the BS-FF + dwPort2Size = dwFileSizeLo / 2048; // mapping size of port2 + + if (CrcPort2(&wPort2Crc) == FALSE) // calculate fingerprint of port2 + { + UnmapPort2(); // free memory + AbortMessage(_T("Packed Port 2 image detected!")); + return FALSE; + } + return TRUE; +} + +VOID UnmapPort2(VOID) +{ + if (pbyPort2 != NULL) + { + UnmapViewOfFile(pbyPort2); + pbyPort2 = NULL; + } + if (hPort2Map != NULL) + { + CloseHandle(hPort2Map); + hPort2Map = NULL; + } + if (hPort2File != NULL) + { + CloseHandle(hPort2File); + hPort2File = NULL; + } + dwPort2Size = 0; // reset size of port2 + dwPort2Mask = 0; + bPort2Writeable = FALSE; + wPort2Crc = 0; + return; +} + + + +//################ +//# +//# Documents +//# +//################ + +static BOOL IsDataPacked(VOID *pMem, DWORD dwSize) +{ + DWORD *pdwMem = (DWORD *) pMem; + + _ASSERT((dwSize % sizeof(DWORD)) == 0); + if ((dwSize % sizeof(DWORD)) != 0) return TRUE; + + for (dwSize /= sizeof(DWORD); dwSize-- > 0;) + { + if ((*pdwMem++ & 0xF0F0F0F0) != 0) + return TRUE; + } + return FALSE; +} + +VOID ResetDocument(VOID) +{ + DisableDebugger(); + if (szCurrentKml[0]) + { + KillKML(); + } + if (hCurrentFile) + { + CloseHandle(hCurrentFile); + hCurrentFile = NULL; + } + szCurrentKml[0] = 0; + szCurrentFilename[0] = 0; + if (Port0) { free(Port0); Port0 = NULL; } + if (Port1) { free(Port1); Port1 = NULL; } + if (Port2) { free(Port2); Port2 = NULL; } else UnmapPort2(); + ZeroMemory(&Chipset,sizeof(Chipset)); + ZeroMemory(&RMap,sizeof(RMap)); // delete MMU mappings + ZeroMemory(&WMap,sizeof(WMap)); + bDocumentAvail = FALSE; // document not available + return; +} + +BOOL NewDocument(VOID) +{ + SaveBackup(); + ResetDocument(); + + if (!DisplayChooseKml(0)) goto restore; + if (!InitKML(szCurrentKml,FALSE)) goto restore; + Chipset.type = cCurrentRomType; + CrcRom(&Chipset.wRomCrc); // save fingerprint of loaded ROM + + if (Chipset.type == '6' || Chipset.type == 'A') // HP38G + { + Chipset.Port0Size = (Chipset.type == 'A') ? 32 : 64; + Chipset.Port1Size = 0; + Chipset.Port2Size = 0; + + Chipset.cards_status = 0x0; + } + if (Chipset.type == 'E') // HP39/40G + { + Chipset.Port0Size = 128; + Chipset.Port1Size = 0; + Chipset.Port2Size = 128; + + Chipset.cards_status = 0xF; + + bPort2Writeable = TRUE; // port2 is writeable + } + if (Chipset.type == 'S') // HP48SX + { + Chipset.Port0Size = 32; + Chipset.Port1Size = 128; + Chipset.Port2Size = 0; + + Chipset.cards_status = 0x5; + + // use 2nd command line argument if defined + MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); + } + if (Chipset.type == 'G') // HP48GX + { + Chipset.Port0Size = 128; + Chipset.Port1Size = 128; + Chipset.Port2Size = 0; + + Chipset.cards_status = 0xA; + + // use 2nd command line argument if defined + MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); + } + if (Chipset.type == 'X') // HP49G + { + Chipset.Port0Size = 256; + Chipset.Port1Size = 128; + Chipset.Port2Size = 128; + + Chipset.cards_status = 0xF; + bPort2Writeable = TRUE; // port2 is writeable + + FlashInit(); // init flash structure + } + + Chipset.IORam[LPE] = RST; // set ReSeT bit at power on reset + + // allocate port memory + if (Chipset.Port0Size) + { + Port0 = (LPBYTE) calloc(Chipset.Port0Size*2048,sizeof(*Port0)); + if (Port0 == NULL) goto restore; + } + if (Chipset.Port1Size) + { + Port1 = (LPBYTE) calloc(Chipset.Port1Size*2048,sizeof(*Port1)); + if (Port1 == NULL) goto restore; + } + if (Chipset.Port2Size) + { + Port2 = (LPBYTE) calloc(Chipset.Port2Size*2048,sizeof(*Port2)); + if (Port2 == NULL) goto restore; + } + LoadBreakpointList(NULL); // clear debugger breakpoint list + RomSwitch(0); // boot ROM view of HP49G and map memory + bDocumentAvail = TRUE; // document available + return TRUE; +restore: + RestoreBackup(); + ResetBackup(); + + // HP48SX/GX + if (Chipset.type == 'S' || Chipset.type == 'G') + { + // use 2nd command line argument if defined + MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); + } + if (pbyRom) + { + Map(0x00,0xFF); + } + return FALSE; +} + +BOOL OpenDocument(LPCTSTR szFilename) +{ + #define CHECKAREA(s,e) (offsetof(CHIPSET,e)-offsetof(CHIPSET,s)+sizeof(((CHIPSET *)NULL)->e)) + + HANDLE hFile = INVALID_HANDLE_VALUE; + DWORD lBytesRead,lSizeofChipset; + BYTE byFileSignature[16]; + BOOL bMatch; + UINT i,nLength; + + // Open file + if (lstrcmpi(szCurrentFilename,szFilename) == 0) + { + if (YesNoMessage(_T("Do you want to reload this document?")) == IDNO) + return TRUE; + } + + SaveBackup(); + ResetDocument(); + + hFile = CreateFile(szFilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + AbortMessage(_T("This file is missing or already loaded in another instance of Emu48.")); + goto restore; + } + + // Read and Compare signature + ReadFile(hFile, byFileSignature, sizeof(byFileSignature), &lBytesRead, NULL); + // go through all valid document signatures + for (bMatch = FALSE, i = 0; !bMatch && i < ARRAYSIZEOF(bySignature); ++i) + { + bMatch = (memcmp(byFileSignature, bySignature[i], sizeof(byFileSignature)) == 0); + } + if (!bMatch) // no valid document signature found + { + AbortMessage(_T("This file is not a valid Emu48 document.")); + goto restore; + } + + switch (byFileSignature[14]) + { + case 0xFE: // Win48 2.1 / Emu4x 0.99.x format + // read length of KML script name + ReadFile(hFile,&nLength,sizeof(nLength),&lBytesRead,NULL); + + // KML script name too long for file buffer + if (nLength >= ARRAYSIZEOF(szCurrentKml)) + { + // skip heading KML script name characters until remainder fits into file buffer + UINT nSkip = nLength - (ARRAYSIZEOF(szCurrentKml) - 1); + SetFilePointer(hFile, nSkip, NULL, FILE_CURRENT); + + nLength = ARRAYSIZEOF(szCurrentKml) - 1; + } + #if defined _UNICODE + { + LPSTR szTmp = (LPSTR) malloc(nLength); + if (szTmp == NULL) + { + AbortMessage(_T("Memory Allocation Failure.")); + goto restore; + } + ReadFile(hFile, szTmp, nLength, &lBytesRead, NULL); + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTmp, lBytesRead, + szCurrentKml, ARRAYSIZEOF(szCurrentKml)); + free(szTmp); + } + #else + { + ReadFile(hFile, szCurrentKml, nLength, &lBytesRead, NULL); + } + #endif + if (nLength != lBytesRead) goto read_err; + szCurrentKml[nLength] = 0; + break; + case 0xFF: // Win48 2.05 format + break; + default: + _ASSERT(FALSE); + } + + // read chipset size inside file + ReadFile(hFile, &lSizeofChipset, sizeof(lSizeofChipset), &lBytesRead, NULL); + if (lBytesRead != sizeof(lSizeofChipset)) goto read_err; + if (lSizeofChipset <= sizeof(Chipset)) // actual or older chipset version + { + // read chipset content + ZeroMemory(&Chipset,sizeof(Chipset)); // init chipset + ReadFile(hFile, &Chipset, lSizeofChipset, &lBytesRead, NULL); + } + else // newer chipset version + { + // read my used chipset content + ReadFile(hFile, &Chipset, sizeof(Chipset), &lBytesRead, NULL); + + // skip rest of chipset + SetFilePointer(hFile, lSizeofChipset-sizeof(Chipset), NULL, FILE_CURRENT); + lSizeofChipset = sizeof(Chipset); + } + if (lBytesRead != lSizeofChipset) goto read_err; + + if (!isModelValid(Chipset.type)) // check for valid model in emulator state file + { + AbortMessage(_T("Emulator state file with invalid calculator model.")); + goto restore; + } + + SetWindowLocation(hWnd,Chipset.nPosX,Chipset.nPosY); + + while (TRUE) + { + if (szCurrentKml[0]) // KML file name + { + BOOL bOK = InitKML(szCurrentKml,FALSE); + bOK = bOK && (cCurrentRomType == Chipset.type); + if (bOK) break; + + KillKML(); + } + if (!DisplayChooseKml(Chipset.type)) + goto restore; + } + // reload old button state + ReloadButtons(Chipset.Keyboard_Row,ARRAYSIZEOF(Chipset.Keyboard_Row)); + + FlashInit(); // init flash structure + + if (Chipset.Port0Size) + { + Port0 = (LPBYTE) malloc(Chipset.Port0Size*2048); + if (Port0 == NULL) + { + AbortMessage(_T("Memory Allocation Failure.")); + goto restore; + } + + ReadFile(hFile, Port0, Chipset.Port0Size*2048, &lBytesRead, NULL); + if (lBytesRead != Chipset.Port0Size*2048) goto read_err; + + if (IsDataPacked(Port0,Chipset.Port0Size*2048)) goto read_err; + } + + if (Chipset.Port1Size) + { + Port1 = (LPBYTE) malloc(Chipset.Port1Size*2048); + if (Port1 == NULL) + { + AbortMessage(_T("Memory Allocation Failure.")); + goto restore; + } + + ReadFile(hFile, Port1, Chipset.Port1Size*2048, &lBytesRead, NULL); + if (lBytesRead != Chipset.Port1Size*2048) goto read_err; + + if (IsDataPacked(Port1,Chipset.Port1Size*2048)) goto read_err; + } + + // HP48SX/GX + if (cCurrentRomType=='S' || cCurrentRomType=='G') + { + MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); + // port2 changed and card detection enabled + if ( Chipset.wPort2Crc != wPort2Crc + && (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0 + ) + { + Chipset.HST |= MP; // set Module Pulled + IOBit(SRQ2,NINT,FALSE); // set NINT to low + Chipset.SoftInt = TRUE; // set interrupt + bInterrupt = TRUE; + } + } + else // HP38G, HP39/40G, HP49G + { + if (Chipset.Port2Size) + { + Port2 = (LPBYTE) malloc(Chipset.Port2Size*2048); + if (Port2 == NULL) + { + AbortMessage(_T("Memory Allocation Failure.")); + goto restore; + } + + ReadFile(hFile, Port2, Chipset.Port2Size*2048, &lBytesRead, NULL); + if (lBytesRead != Chipset.Port2Size*2048) goto read_err; + + if (IsDataPacked(Port2,Chipset.Port2Size*2048)) goto read_err; + + bPort2Writeable = TRUE; + Chipset.cards_status = 0xF; + } + } + + RomSwitch(Chipset.Bank_FF); // reload ROM view of HP49G and map memory + + if (Chipset.wRomCrc != wRomCrc) // ROM changed + { + CpuReset(); + Chipset.Shutdn = FALSE; // automatic restart + } + + // check CPU main registers + if (IsDataPacked(Chipset.A,CHECKAREA(A,R4))) goto read_err; + + LoadBreakpointList(hFile); // load debugger breakpoint list + + lstrcpy(szCurrentFilename, szFilename); + _ASSERT(hCurrentFile == NULL); + hCurrentFile = hFile; + #if defined _USRDLL // DLL version + // notify main proc about current document file + if (pEmuDocumentNotify) pEmuDocumentNotify(szCurrentFilename); + #endif + SetWindowPathTitle(szCurrentFilename); // update window title line + bDocumentAvail = TRUE; // document available + return TRUE; + +read_err: + AbortMessage(_T("This file must be truncated, and cannot be loaded.")); +restore: + if (INVALID_HANDLE_VALUE != hFile) // close if valid handle + CloseHandle(hFile); + RestoreBackup(); + ResetBackup(); + + // HP48SX/GX + if (cCurrentRomType=='S' || cCurrentRomType=='G') + { + // use 2nd command line argument if defined + MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); + } + return FALSE; + #undef CHECKAREA +} + +BOOL SaveDocument(VOID) +{ + DWORD lBytesWritten; + DWORD lSizeofChipset; + UINT nLength; + WINDOWPLACEMENT wndpl; + + if (hCurrentFile == NULL) return FALSE; + + _ASSERT(hWnd); // window open + wndpl.length = sizeof(wndpl); // update saved window position + GetWindowPlacement(hWnd, &wndpl); + Chipset.nPosX = (SWORD) wndpl.rcNormalPosition.left; + Chipset.nPosY = (SWORD) wndpl.rcNormalPosition.top; + + SetFilePointer(hCurrentFile,0,NULL,FILE_BEGIN); + + // write default "Emu48 Document\xFE" signature + if (!WriteFile(hCurrentFile, bySignature[0], 16, &lBytesWritten, NULL)) + { + AbortMessage(_T("Could not write into document file!")); + return FALSE; + } + + CrcRom(&Chipset.wRomCrc); // save fingerprint of ROM + CrcPort2(&Chipset.wPort2Crc); // save fingerprint of port2 + + nLength = lstrlen(szCurrentKml); + WriteFile(hCurrentFile, &nLength, sizeof(nLength), &lBytesWritten, NULL); + #if defined _UNICODE + { + LPSTR szTmp = (LPSTR) malloc(nLength); + if (szTmp != NULL) + { + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, + szCurrentKml, nLength, + szTmp, nLength, NULL, NULL); + WriteFile(hCurrentFile, szTmp, nLength, &lBytesWritten, NULL); + free(szTmp); + } + } + #else + { + WriteFile(hCurrentFile, szCurrentKml, nLength, &lBytesWritten, NULL); + } + #endif + lSizeofChipset = sizeof(CHIPSET); + WriteFile(hCurrentFile, &lSizeofChipset, sizeof(lSizeofChipset), &lBytesWritten, NULL); + WriteFile(hCurrentFile, &Chipset, lSizeofChipset, &lBytesWritten, NULL); + if (Chipset.Port0Size) WriteFile(hCurrentFile, Port0, Chipset.Port0Size*2048, &lBytesWritten, NULL); + if (Chipset.Port1Size) WriteFile(hCurrentFile, Port1, Chipset.Port1Size*2048, &lBytesWritten, NULL); + if (Chipset.Port2Size) WriteFile(hCurrentFile, Port2, Chipset.Port2Size*2048, &lBytesWritten, NULL); + SaveBreakpointList(hCurrentFile); // save debugger breakpoint list + SetEndOfFile(hCurrentFile); // cut the rest + return TRUE; +} + +BOOL SaveDocumentAs(LPCTSTR szFilename) +{ + HANDLE hFile; + + if (hCurrentFile) // already file in use + { + CloseHandle(hCurrentFile); // close it, even it's same, so data always will be saved + hCurrentFile = NULL; + } + hFile = CreateFile(szFilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file + { + AbortMessage(_T("This file must be currently used by another instance of Emu48.")); + return FALSE; + } + lstrcpy(szCurrentFilename, szFilename); // save new file name + hCurrentFile = hFile; // and the corresponding handle + #if defined _USRDLL // DLL version + // notify main proc about current document file + if (pEmuDocumentNotify) pEmuDocumentNotify(szCurrentFilename); + #endif + SetWindowPathTitle(szCurrentFilename); // update window title line + return SaveDocument(); // save current content +} + + + +//################ +//# +//# Backup +//# +//################ + +BOOL SaveBackup(VOID) +{ + WINDOWPLACEMENT wndpl; + + BOOL bSucc = TRUE; + + if (!bDocumentAvail) return FALSE; + + _ASSERT(nState != SM_RUN); // emulation engine is running + + // save window position + _ASSERT(hWnd); // window open + wndpl.length = sizeof(wndpl); // update saved window position + GetWindowPlacement(hWnd, &wndpl); + Chipset.nPosX = (SWORD) wndpl.rcNormalPosition.left; + Chipset.nPosY = (SWORD) wndpl.rcNormalPosition.top; + + lstrcpy(szBackupFilename, szCurrentFilename); + lstrcpy(szBackupKml, szCurrentKml); + if (BackupPort0) { free(BackupPort0); BackupPort0 = NULL; } + if (BackupPort1) { free(BackupPort1); BackupPort1 = NULL; } + if (BackupPort2) { free(BackupPort2); BackupPort2 = NULL; } + CopyMemory(&BackupChipset, &Chipset, sizeof(Chipset)); + if (Port0 && Chipset.Port0Size) + { + BackupPort0 = (LPBYTE) malloc(Chipset.Port0Size*2048); + if (BackupPort0) + { + CopyMemory(BackupPort0,Port0,Chipset.Port0Size*2048); + } + bSucc = bSucc && (BackupPort0 != NULL); + } + if (Port1 && Chipset.Port1Size) + { + BackupPort1 = (LPBYTE) malloc(Chipset.Port1Size*2048); + if (BackupPort1) + { + CopyMemory(BackupPort1,Port1,Chipset.Port1Size*2048); + } + bSucc = bSucc && (BackupPort1 != NULL); + } + if (Port2 && Chipset.Port2Size) // internal port2 + { + BackupPort2 = (LPBYTE) malloc(Chipset.Port2Size*2048); + if (BackupPort2) + { + CopyMemory(BackupPort2,Port2,Chipset.Port2Size*2048); + } + bSucc = bSucc && (BackupPort2 != NULL); + } + CreateBackupBreakpointList(); + bBackup = bSucc; + return bSucc; +} + +BOOL RestoreBackup(VOID) +{ + BOOL bDbgOpen; + + BOOL bSucc = TRUE; + + if (!bBackup) return FALSE; + + bDbgOpen = (nDbgState != DBG_OFF); // debugger window open? + ResetDocument(); + // need chipset for contrast setting in InitKML() + Chipset.contrast = BackupChipset.contrast; + if (!InitKML(szBackupKml,TRUE)) + { + InitKML(szCurrentKml,TRUE); + return FALSE; + } + lstrcpy(szCurrentKml, szBackupKml); + lstrcpy(szCurrentFilename, szBackupFilename); + if (szCurrentFilename[0]) + { + hCurrentFile = CreateFile(szCurrentFilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hCurrentFile == INVALID_HANDLE_VALUE) + { + hCurrentFile = NULL; + szCurrentFilename[0] = 0; + } + } + CopyMemory(&Chipset, &BackupChipset, sizeof(Chipset)); + if (BackupPort0 && Chipset.Port0Size) + { + Port0 = (LPBYTE) malloc(Chipset.Port0Size*2048); + if (Port0) + { + CopyMemory(Port0,BackupPort0,Chipset.Port0Size*2048); + } + bSucc = bSucc && (Port0 != NULL); + } + if (BackupPort1 && Chipset.Port1Size) + { + Port1 = (LPBYTE) malloc(Chipset.Port1Size*2048); + if (Port1) + { + CopyMemory(Port1,BackupPort1,Chipset.Port1Size*2048); + } + bSucc = bSucc && (Port1 != NULL); + } + if (BackupPort2 && Chipset.Port2Size) // internal port2 + { + Port2 = (LPBYTE) malloc(Chipset.Port2Size*2048); + if (Port2) + { + CopyMemory(Port2,BackupPort2,Chipset.Port2Size*2048); + } + bSucc = bSucc && (Port2 != NULL); + } + // map port2 + else + { + if (cCurrentRomType=='S' || cCurrentRomType=='G') // HP48SX/GX + { + // use 2nd command line argument if defined + MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); + } + } + Map(0x00,0xFF); // update memory mapping + SetWindowPathTitle(szCurrentFilename); // update window title line + SetWindowLocation(hWnd,Chipset.nPosX,Chipset.nPosY); + RestoreBackupBreakpointList(); // restore the debugger breakpoint list + if (bDbgOpen) OnToolDebug(); // reopen the debugger + if (!bSucc) // restore not successful (memory allocation errors) + { + ResetDocument(); // cleanup remainders + } + bDocumentAvail = bSucc; // document available + return bSucc; +} + +BOOL ResetBackup(VOID) +{ + if (!bBackup) return FALSE; + szBackupFilename[0] = 0; + szBackupKml[0] = 0; + if (BackupPort0) { free(BackupPort0); BackupPort0 = NULL; } + if (BackupPort1) { free(BackupPort1); BackupPort1 = NULL; } + if (BackupPort2) { free(BackupPort2); BackupPort2 = NULL; } + ZeroMemory(&BackupChipset,sizeof(BackupChipset)); + bBackup = FALSE; + return TRUE; +} + + + +//################ +//# +//# Open File Common Dialog Boxes +//# +//################ + +static VOID InitializeOFN(LPOPENFILENAME ofn) +{ + ZeroMemory((LPVOID)ofn, sizeof(OPENFILENAME)); + ofn->lStructSize = sizeof(OPENFILENAME); + ofn->hwndOwner = hWnd; + ofn->Flags = OFN_EXPLORER|OFN_HIDEREADONLY; + return; +} + +BOOL GetOpenFilename(VOID) +{ + TCHAR szBuffer[ARRAYSIZEOF(szBufferFilename)]; + OPENFILENAME ofn; + + InitializeOFN(&ofn); + ofn.lpstrFilter = + _T("Emu48 Files (*.e38;*.e39;*.e48;*.e49)\0") + _T("*.e38;*.e39;*.e48;*.e49\0") + _T("HP-38 Files (*.e38)\0*.e38\0") + _T("HP-39 Files (*.e39)\0*.e39\0") + _T("HP-48 Files (*.e48)\0*.e48\0") + _T("HP-49 Files (*.e49)\0*.e49\0") + _T("Win48 Files (*.w48)\0*.w48\0"); + ofn.nFilterIndex = 1; + ofn.lpstrFile = szBuffer; + ofn.lpstrFile[0] = 0; + ofn.nMaxFile = ARRAYSIZEOF(szBuffer); + ofn.Flags |= OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST; + if (GetOpenFileName(&ofn) == FALSE) return FALSE; + _ASSERT(ARRAYSIZEOF(szBufferFilename) == ofn.nMaxFile); + lstrcpy(szBufferFilename, ofn.lpstrFile); + return TRUE; +} + +BOOL GetSaveAsFilename(VOID) +{ + TCHAR szBuffer[ARRAYSIZEOF(szBufferFilename)]; + OPENFILENAME ofn; + + InitializeOFN(&ofn); + ofn.lpstrFilter = + _T("HP-38 Files (*.e38)\0*.e38\0") + _T("HP-39 Files (*.e39)\0*.e39\0") + _T("HP-48 Files (*.e48)\0*.e48\0") + _T("HP-49 Files (*.e49)\0*.e49\0"); + ofn.lpstrDefExt = _T("e48"); // HP48SX/GX + ofn.nFilterIndex = 3; + if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G + { + ofn.lpstrDefExt = _T("e38"); + ofn.nFilterIndex = 1; + } + if (cCurrentRomType=='E') // HP39/40G + { + ofn.lpstrDefExt = _T("e39"); + ofn.nFilterIndex = 2; + } + if (cCurrentRomType=='X') // HP49G + { + ofn.lpstrDefExt = _T("e49"); + ofn.nFilterIndex = 4; + } + ofn.lpstrFile = szBuffer; + ofn.lpstrFile[0] = 0; + ofn.nMaxFile = ARRAYSIZEOF(szBuffer); + ofn.Flags |= OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT; + if (GetSaveFileName(&ofn) == FALSE) return FALSE; + _ASSERT(ARRAYSIZEOF(szBufferFilename) == ofn.nMaxFile); + lstrcpy(szBufferFilename, ofn.lpstrFile); + return TRUE; +} + +BOOL GetLoadObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt) +{ + TCHAR szBuffer[ARRAYSIZEOF(szBufferFilename)]; + OPENFILENAME ofn; + + InitializeOFN(&ofn); + ofn.lpstrFilter = lpstrFilter; + ofn.lpstrDefExt = lpstrDefExt; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szBuffer; + ofn.lpstrFile[0] = 0; + ofn.nMaxFile = ARRAYSIZEOF(szBuffer); + ofn.Flags |= OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST; + if (GetOpenFileName(&ofn) == FALSE) return FALSE; + _ASSERT(ARRAYSIZEOF(szBufferFilename) == ofn.nMaxFile); + lstrcpy(szBufferFilename, ofn.lpstrFile); + return TRUE; +} + +BOOL GetSaveObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt) +{ + TCHAR szBuffer[ARRAYSIZEOF(szBufferFilename)]; + OPENFILENAME ofn; + + InitializeOFN(&ofn); + ofn.lpstrFilter = lpstrFilter; + ofn.lpstrDefExt = NULL; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szBuffer; + ofn.lpstrFile[0] = 0; + ofn.nMaxFile = ARRAYSIZEOF(szBuffer); + ofn.Flags |= OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT; + if (GetSaveFileName(&ofn) == FALSE) return FALSE; + _ASSERT(ARRAYSIZEOF(szBufferFilename) == ofn.nMaxFile); + lstrcpy(szBufferFilename, ofn.lpstrFile); + if (ofn.nFileExtension == 0) // given filename has no extension + { + // actual name length + UINT nLength = lstrlen(szBufferFilename); + + // destination buffer has room for the default extension + if (nLength + 1 + lstrlen(lpstrDefExt) < ARRAYSIZEOF(szBufferFilename)) + { + // add default extension + szBufferFilename[nLength++] = _T('.'); + lstrcpy(&szBufferFilename[nLength], lpstrDefExt); + } + } + return TRUE; +} + + + +//################ +//# +//# Load and Save HP48 Objects +//# +//################ + +WORD WriteStack(UINT nStkLevel,LPBYTE lpBuf,DWORD dwSize) // separated from LoadObject() +{ + BOOL bBinary; + DWORD dwAddress, i; + + bBinary = ((lpBuf[dwSize+0]=='H') + && (lpBuf[dwSize+1]=='P') + && (lpBuf[dwSize+2]=='H') + && (lpBuf[dwSize+3]=='P') + && (lpBuf[dwSize+4]=='4') + && (lpBuf[dwSize+5]==((cCurrentRomType!='X') ? '8' : '9')) + && (lpBuf[dwSize+6]=='-')); + + for (dwAddress = 0, i = 0; i < dwSize; i++) + { + BYTE byTwoNibs = lpBuf[i+dwSize]; + lpBuf[dwAddress++] = (BYTE)(byTwoNibs&0xF); + lpBuf[dwAddress++] = (BYTE)(byTwoNibs>>4); + } + + dwSize = dwAddress; // unpacked buffer size + + if (bBinary == TRUE) + { // load as binary + dwSize = RPL_ObjectSize(lpBuf+16,dwSize-16); + if (dwSize == BAD_OB) return S_ERR_OBJECT; + dwAddress = RPL_CreateTemp(dwSize); + if (dwAddress == 0) return S_ERR_BINARY; + Nwrite(lpBuf+16,dwAddress,dwSize); + } + else + { // load as string + dwAddress = RPL_CreateTemp(dwSize+10); + if (dwAddress == 0) return S_ERR_ASCII; + Write5(dwAddress,0x02A2C); // String + Write5(dwAddress+5,dwSize+5); // length of String + Nwrite(lpBuf,dwAddress+10,dwSize); // data + } + RPL_Push(nStkLevel,dwAddress); + return S_ERR_NO; +} + +BOOL LoadObject(LPCTSTR szFilename) // separated stack writing part +{ + HANDLE hFile; + DWORD dwFileSizeLow; + DWORD dwFileSizeHigh; + LPBYTE lpBuf; + WORD wError; + + hFile = CreateFile(szFilename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + if (hFile == INVALID_HANDLE_VALUE) return FALSE; + dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); + if (dwFileSizeHigh != 0) + { // file is too large. + CloseHandle(hFile); + return FALSE; + } + lpBuf = (LPBYTE) malloc(dwFileSizeLow*2); + if (lpBuf == NULL) + { + CloseHandle(hFile); + return FALSE; + } + ReadFile(hFile, lpBuf+dwFileSizeLow, dwFileSizeLow, &dwFileSizeHigh, NULL); + CloseHandle(hFile); + + wError = WriteStack(1,lpBuf,dwFileSizeLow); + + if (wError == S_ERR_OBJECT) + AbortMessage(_T("This isn't a valid binary file.")); + + if (wError == S_ERR_BINARY) + AbortMessage(_T("The calculator does not have enough\nfree memory to load this binary file.")); + + if (wError == S_ERR_ASCII) + AbortMessage(_T("The calculator does not have enough\nfree memory to load this text file.")); + + free(lpBuf); + return (wError == S_ERR_NO); +} + +BOOL SaveObject(LPCTSTR szFilename) // separated stack reading part +{ + HANDLE hFile; + LPBYTE pbyHeader; + DWORD lBytesWritten; + DWORD dwAddress; + DWORD dwLength; + + dwAddress = RPL_Pick(1); + if (dwAddress == 0) + { + AbortMessage(_T("Too Few Arguments.")); + return FALSE; + } + dwLength = (RPL_SkipOb(dwAddress) - dwAddress + 1) / 2; + + hFile = CreateFile(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + AbortMessage(_T("Cannot open file.")); + return FALSE; + } + + pbyHeader = (Chipset.type != 'X') ? (LPBYTE) BINARYHEADER48 : (LPBYTE) BINARYHEADER49; + WriteFile(hFile, pbyHeader, 8, &lBytesWritten, NULL); + + while (dwLength--) + { + BYTE byByte = Read2(dwAddress); + WriteFile(hFile, &byByte, 1, &lBytesWritten, NULL); + dwAddress += 2; + } + CloseHandle(hFile); + return TRUE; +} + + + +//################ +//# +//# Load Icon +//# +//################ + +BOOL LoadIconFromFile(LPCTSTR szFilename) +{ + HANDLE hIcon; + + SetCurrentDirectory(szEmuDirectory); + // not necessary to destroy because icon is shared + hIcon = LoadImage(NULL, szFilename, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_SHARED); + SetCurrentDirectory(szCurrentDirectory); + + if (hIcon) + { + SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIcon); + SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon); + } + return hIcon != NULL; +} + +VOID LoadIconDefault(VOID) +{ + // use window class icon + SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) NULL); + SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) NULL); + return; +} + + + +//################ +//# +//# Load Bitmap +//# +//################ + +#define WIDTHBYTES(bits) ((((bits) + 31) / 32) * 4) + +typedef struct _BmpFile +{ + DWORD dwPos; // actual reading pos + DWORD dwFileSize; // file size + LPBYTE pbyFile; // buffer +} BMPFILE, FAR *LPBMPFILE, *PBMPFILE; + +static __inline WORD DibNumColors(__unaligned BITMAPINFOHEADER CONST *lpbi) +{ + if (lpbi->biClrUsed != 0) return (WORD) lpbi->biClrUsed; + + /* a 24 bitcount DIB has no color table */ + return (lpbi->biBitCount <= 8) ? (1 << lpbi->biBitCount) : 0; +} + +static HPALETTE CreateBIPalette(__unaligned BITMAPINFOHEADER CONST *lpbi) +{ + LOGPALETTE* pPal; + HPALETTE hpal = NULL; + WORD wNumColors; + BYTE red; + BYTE green; + BYTE blue; + UINT i; + __unaligned RGBQUAD* pRgb; + + if (!lpbi || lpbi->biSize != sizeof(BITMAPINFOHEADER)) + return NULL; + + // Get a pointer to the color table and the number of colors in it + pRgb = (RGBQUAD FAR *)((LPBYTE)lpbi + (WORD)lpbi->biSize); + wNumColors = DibNumColors(lpbi); + + if (wNumColors) + { + // Allocate for the logical palette structure + pPal = (PLOGPALETTE) malloc(sizeof(LOGPALETTE) + wNumColors * sizeof(PALETTEENTRY)); + if (!pPal) return NULL; + + pPal->palVersion = 0x300; + pPal->palNumEntries = wNumColors; + + // Fill in the palette entries from the DIB color table and + // create a logical color palette. + for (i = 0; i < pPal->palNumEntries; i++) + { + pPal->palPalEntry[i].peRed = pRgb[i].rgbRed; + pPal->palPalEntry[i].peGreen = pRgb[i].rgbGreen; + pPal->palPalEntry[i].peBlue = pRgb[i].rgbBlue; + pPal->palPalEntry[i].peFlags = 0; + } + hpal = CreatePalette(pPal); + free(pPal); + } + else + { + // create halftone palette for 16, 24 and 32 bitcount bitmaps + + // 16, 24 and 32 bitcount DIB's have no color table entries so, set the + // number of to the maximum value (256). + wNumColors = 256; + pPal = (PLOGPALETTE) malloc(sizeof(LOGPALETTE) + wNumColors * sizeof(PALETTEENTRY)); + if (!pPal) return NULL; + + pPal->palVersion = 0x300; + pPal->palNumEntries = wNumColors; + + red = green = blue = 0; + + // Generate 256 (= 8*8*4) RGB combinations to fill the palette + // entries. + for (i = 0; i < pPal->palNumEntries; i++) + { + pPal->palPalEntry[i].peRed = red; + pPal->palPalEntry[i].peGreen = green; + pPal->palPalEntry[i].peBlue = blue; + pPal->palPalEntry[i].peFlags = 0; + + if (!(red += 32)) + if (!(green += 32)) + blue += 64; + } + hpal = CreatePalette(pPal); + free(pPal); + } + return hpal; +} + +static HBITMAP DecodeBmp(LPBMPFILE pBmp,BOOL bPalette) +{ + DWORD dwFileSize; + + HBITMAP hBitmap = NULL; + + // map memory to BITMAPFILEHEADER and BITMAPINFO + const LPBITMAPFILEHEADER pBmfh = (LPBITMAPFILEHEADER) pBmp->pbyFile; + const __unaligned LPBITMAPINFO pBmi = (__unaligned LPBITMAPINFO) & pBmfh[1]; + + // size of bitmap header information & check for bitmap + dwFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + if ( pBmp->dwFileSize < dwFileSize // minimum size to read data from BITMAPFILEHEADER + BITMAPINFOHEADER + || pBmfh->bfType != 0x4D42) // "BM" + return NULL; + + // size with color table + if (pBmi->bmiHeader.biCompression == BI_BITFIELDS) + { + dwFileSize += 3 * sizeof(DWORD); + } + else + { + dwFileSize += DibNumColors(&pBmi->bmiHeader) * sizeof(RGBQUAD); + } + if (dwFileSize != pBmfh->bfOffBits) return NULL; + + // size with bitmap data + if (pBmi->bmiHeader.biCompression != BI_RGB) + { + dwFileSize += pBmi->bmiHeader.biSizeImage; + } + else + { + dwFileSize += WIDTHBYTES(pBmi->bmiHeader.biWidth * pBmi->bmiHeader.biBitCount) + * labs(pBmi->bmiHeader.biHeight); + } + if (pBmp->dwFileSize < dwFileSize) return NULL; + + VERIFY(hBitmap = CreateDIBitmap( + hWindowDC, + &pBmi->bmiHeader, + CBM_INIT, + pBmp->pbyFile + pBmfh->bfOffBits, + pBmi, DIB_RGB_COLORS)); + if (hBitmap == NULL) return NULL; + + if (bPalette && hPalette == NULL) + { + hPalette = CreateBIPalette(&pBmi->bmiHeader); + // save old palette + hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE); + RealizePalette(hWindowDC); + } + return hBitmap; +} + +static BOOL ReadGifByte(LPBMPFILE pGif, INT *n) +{ + // outside GIF file + if (pGif->dwPos >= pGif->dwFileSize) + return TRUE; + + *n = pGif->pbyFile[pGif->dwPos++]; + return FALSE; +} + +static BOOL ReadGifWord(LPBMPFILE pGif, INT *n) +{ + // outside GIF file + if (pGif->dwPos + 1 >= pGif->dwFileSize) + return TRUE; + + *n = pGif->pbyFile[pGif->dwPos++]; + *n |= (pGif->pbyFile[pGif->dwPos++] << 8); + return FALSE; +} + +static HBITMAP DecodeGif(LPBMPFILE pBmp,DWORD *pdwTransparentColor,BOOL bPalette) +{ + // this implementation base on the GIF image file + // decoder engine of Free42 (c) by Thomas Okken + + HBITMAP hBitmap; + + typedef struct cmap + { + WORD biBitCount; // bits used in color map + DWORD biClrUsed; // no of colors in color map + RGBQUAD bmiColors[256]; // color map + } CMAP; + + BOOL bHasGlobalCmap; + CMAP sGlb; // data of global color map + + INT nWidth,nHeight,nInfo,nBackground,nZero; + LONG lBytesPerLine; + + LPBYTE pbyPixels; + + BITMAPINFO bmi; // global bitmap info + + BOOL bDecoding = TRUE; + + hBitmap = NULL; + + pBmp->dwPos = 6; // position behind GIF header + + /* Bits 6..4 of info contain one less than the "color resolution", + * defined as the number of significant bits per RGB component in + * the source image's color palette. If the source image (from + * which the GIF was generated) was 24-bit true color, the color + * resolution is 8, so the value in bits 6..4 is 7. If the source + * image had an EGA color cube (2x2x2), the color resolution would + * be 2, etc. + * Bit 3 of info must be zero in GIF87a; in GIF89a, if it is set, + * it indicates that the global colormap is sorted, the most + * important entries being first. In PseudoColor environments this + * can be used to make sure to get the most important colors from + * the X server first, to optimize the image's appearance in the + * event that not all the colors from the colormap can actually be + * obtained at the same time. + * The 'zero' field is always 0 in GIF87a; in GIF89a, it indicates + * the pixel aspect ratio, as (PAR + 15) : 64. If PAR is zero, + * this means no aspect ratio information is given, PAR = 1 means + * 1:4 (narrow), PAR = 49 means 1:1 (square), PAR = 255 means + * slightly over 4:1 (wide), etc. + */ + + if ( ReadGifWord(pBmp,&nWidth) + || ReadGifWord(pBmp,&nHeight) + || ReadGifByte(pBmp,&nInfo) + || ReadGifByte(pBmp,&nBackground) + || ReadGifByte(pBmp,&nZero) + || nZero != 0) + goto quit; + + ZeroMemory(&bmi,sizeof(bmi)); // init bitmap info + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = nWidth; + bmi.bmiHeader.biHeight = nHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 24; // create a true color DIB + bmi.bmiHeader.biCompression = BI_RGB; + + ZeroMemory(&sGlb,sizeof(sGlb)); // init global color map + bHasGlobalCmap = (nInfo & 0x80) != 0; + + sGlb.biBitCount = (nInfo & 7) + 1; // bits used in global color map + sGlb.biClrUsed = (1 << sGlb.biBitCount); // no of colors in global color map + + // color table should not exceed 256 colors + _ASSERT(sGlb.biClrUsed <= ARRAYSIZEOF(sGlb.bmiColors)); + + if (bHasGlobalCmap) // global color map + { + DWORD i; + + for (i = 0; i < sGlb.biClrUsed; ++i) + { + int r, g, b; + + if (ReadGifByte(pBmp,&r) || ReadGifByte(pBmp,&g) || ReadGifByte(pBmp,&b)) + goto quit; + + sGlb.bmiColors[i].rgbRed = r; + sGlb.bmiColors[i].rgbGreen = g; + sGlb.bmiColors[i].rgbBlue = b; + } + } + else // no color map + { + DWORD i; + + for (i = 0; i < sGlb.biClrUsed; ++i) + { + BYTE k = (BYTE) ((i * sGlb.biClrUsed) / (sGlb.biClrUsed - 1)); + + sGlb.bmiColors[i].rgbRed = k; + sGlb.bmiColors[i].rgbGreen = k; + sGlb.bmiColors[i].rgbBlue = k; + } + } + + // bitmap dimensions + lBytesPerLine = WIDTHBYTES(bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount); + bmi.bmiHeader.biSizeImage = lBytesPerLine * bmi.bmiHeader.biHeight; + + // create top-down DIB + bmi.bmiHeader.biHeight = -bmi.bmiHeader.biHeight; + + // allocate buffer for pixels + VERIFY(hBitmap = CreateDIBSection(hWindowDC, + &bmi, + DIB_RGB_COLORS, + (VOID **)&pbyPixels, + NULL, + 0)); + if (hBitmap == NULL) goto quit; + + // fill pixel buffer with background color + for (nHeight = 0; nHeight < labs(bmi.bmiHeader.biHeight); ++nHeight) + { + LPBYTE pbyLine = pbyPixels + nHeight * lBytesPerLine; + + for (nWidth = 0; nWidth < bmi.bmiHeader.biWidth; ++nWidth) + { + *pbyLine++ = sGlb.bmiColors[nBackground].rgbBlue; + *pbyLine++ = sGlb.bmiColors[nBackground].rgbGreen; + *pbyLine++ = sGlb.bmiColors[nBackground].rgbRed; + } + + _ASSERT((DWORD) (pbyLine - pbyPixels) <= bmi.bmiHeader.biSizeImage); + } + + while (bDecoding) + { + INT nBlockType; + + if (ReadGifByte(pBmp,&nBlockType)) goto quit; + + switch (nBlockType) + { + case ',': // image + { + CMAP sAct; // data of actual color map + + INT nLeft,nTop,nWidth,nHeight; + INT i,nInfo; + + BOOL bInterlaced; + INT h,v; + INT nCodesize; // LZW codesize in bits + INT nBytecount; + + SHORT prefix_table[4096]; + SHORT code_table[4096]; + + INT nMaxcode; + INT nClearCode; + INT nEndCode; + + INT nCurrCodesize; + INT nCurrCode; + INT nOldCode; + INT nBitsNeeded; + BOOL bEndCodeSeen; + + // read image dimensions + if ( ReadGifWord(pBmp,&nLeft) + || ReadGifWord(pBmp,&nTop) + || ReadGifWord(pBmp,&nWidth) + || ReadGifWord(pBmp,&nHeight) + || ReadGifByte(pBmp,&nInfo)) + goto quit; + + if ( nTop + nHeight > labs(bmi.bmiHeader.biHeight) + || nLeft + nWidth > bmi.bmiHeader.biWidth) + goto quit; + + /* Bit 3 of info must be zero in GIF87a; in GIF89a, if it + * is set, it indicates that the local colormap is sorted, + * the most important entries being first. In PseudoColor + * environments this can be used to make sure to get the + * most important colors from the X server first, to + * optimize the image's appearance in the event that not + * all the colors from the colormap can actually be + * obtained at the same time. + */ + + if ((nInfo & 0x80) == 0) // using global color map + { + sAct = sGlb; + } + else // using local color map + { + DWORD i; + + sAct.biBitCount = (nInfo & 7) + 1; // bits used in color map + sAct.biClrUsed = (1 << sAct.biBitCount); // no of colors in color map + + for (i = 0; i < sAct.biClrUsed; ++i) + { + int r, g, b; + + if (ReadGifByte(pBmp,&r) || ReadGifByte(pBmp,&g) || ReadGifByte(pBmp,&b)) + goto quit; + + sAct.bmiColors[i].rgbRed = r; + sAct.bmiColors[i].rgbGreen = g; + sAct.bmiColors[i].rgbBlue = b; + } + } + + // interlaced image + bInterlaced = (nInfo & 0x40) != 0; + + h = 0; + v = 0; + if ( ReadGifByte(pBmp,&nCodesize) + || ReadGifByte(pBmp,&nBytecount)) + goto quit; + + nMaxcode = (1 << nCodesize); + + // preset LZW table + for (i = 0; i < nMaxcode + 2; ++i) + { + prefix_table[i] = -1; + code_table[i] = i; + } + nClearCode = nMaxcode++; + nEndCode = nMaxcode++; + + nCurrCodesize = nCodesize + 1; + nCurrCode = 0; + nOldCode = -1; + nBitsNeeded = nCurrCodesize; + bEndCodeSeen = FALSE; + + while (nBytecount != 0) + { + for (i = 0; i < nBytecount; ++i) + { + INT nCurrByte; + INT nBitsAvailable; + + if (ReadGifByte(pBmp,&nCurrByte)) + goto quit; + + if (bEndCodeSeen) continue; + + nBitsAvailable = 8; + while (nBitsAvailable != 0) + { + INT nBitsCopied = (nBitsNeeded < nBitsAvailable) + ? nBitsNeeded + : nBitsAvailable; + + INT nBits = nCurrByte >> (8 - nBitsAvailable); + + nBits &= 0xFF >> (8 - nBitsCopied); + nCurrCode |= nBits << (nCurrCodesize - nBitsNeeded); + nBitsAvailable -= nBitsCopied; + nBitsNeeded -= nBitsCopied; + + if (nBitsNeeded == 0) + { + BYTE byExpanded[4096]; + INT nExplen; + + do + { + if (nCurrCode == nEndCode) + { + bEndCodeSeen = TRUE; + break; + } + + if (nCurrCode == nClearCode) + { + nMaxcode = (1 << nCodesize) + 2; + nCurrCodesize = nCodesize + 1; + nOldCode = -1; + break; + } + + if (nCurrCode < nMaxcode) + { + if (nMaxcode < 4096 && nOldCode != -1) + { + INT c = nCurrCode; + while (prefix_table[c] != -1) + c = prefix_table[c]; + c = code_table[c]; + prefix_table[nMaxcode] = nOldCode; + code_table[nMaxcode] = c; + nMaxcode++; + if (nMaxcode == (1 << nCurrCodesize) && nCurrCodesize < 12) + nCurrCodesize++; + } + } + else + { + INT c; + + if (nCurrCode > nMaxcode || nOldCode == -1) goto quit; + + _ASSERT(nCurrCode == nMaxcode); + + /* Once maxcode == 4096, we can't get here + * any more, because we refuse to raise + * nCurrCodeSize above 12 -- so we can + * never read a bigger code than 4095. + */ + + c = nOldCode; + while (prefix_table[c] != -1) + c = prefix_table[c]; + c = code_table[c]; + prefix_table[nMaxcode] = nOldCode; + code_table[nMaxcode] = c; + nMaxcode++; + + if (nMaxcode == (1 << nCurrCodesize) && nCurrCodesize < 12) + nCurrCodesize++; + } + nOldCode = nCurrCode; + + // output nCurrCode! + nExplen = 0; + while (nCurrCode != -1) + { + _ASSERT(nExplen < ARRAYSIZEOF(byExpanded)); + byExpanded[nExplen++] = (BYTE) code_table[nCurrCode]; + nCurrCode = prefix_table[nCurrCode]; + } + _ASSERT(nExplen > 0); + + while (--nExplen >= 0) + { + // get color map index + BYTE byColIndex = byExpanded[nExplen]; + + LPBYTE pbyRgbr = pbyPixels + (lBytesPerLine * (nTop + v) + 3 * (nLeft + h)); + + _ASSERT(pbyRgbr + 2 < pbyPixels + bmi.bmiHeader.biSizeImage); + _ASSERT(byColIndex < sAct.biClrUsed); + + *pbyRgbr++ = sAct.bmiColors[byColIndex].rgbBlue; + *pbyRgbr++ = sAct.bmiColors[byColIndex].rgbGreen; + *pbyRgbr = sAct.bmiColors[byColIndex].rgbRed; + + if (++h == nWidth) + { + h = 0; + if (bInterlaced) + { + switch (v & 7) + { + case 0: + v += 8; + if (v < nHeight) + break; + /* Some GIF en/decoders go + * straight from the '0' + * pass to the '4' pass + * without checking the + * height, and blow up on + * 2/3/4 pixel high + * interlaced images. + */ + if (nHeight > 4) + v = 4; + else + if (nHeight > 2) + v = 2; + else + if (nHeight > 1) + v = 1; + else + bEndCodeSeen = TRUE; + break; + case 4: + v += 8; + if (v >= nHeight) + v = 2; + break; + case 2: + case 6: + v += 4; + if (v >= nHeight) + v = 1; + break; + case 1: + case 3: + case 5: + case 7: + v += 2; + if (v >= nHeight) + bEndCodeSeen = TRUE; + break; + } + if (bEndCodeSeen) + break; // while (--nExplen >= 0) + } + else // non interlaced + { + if (++v == nHeight) + { + bEndCodeSeen = TRUE; + break; // while (--nExplen >= 0) + } + } + } + } + } + while (FALSE); + + nCurrCode = 0; + nBitsNeeded = nCurrCodesize; + } + } + } + + if (ReadGifByte(pBmp,&nBytecount)) + goto quit; + } + } + break; + + case '!': // extension block + { + INT i,nFunctionCode,nByteCount,nDummy; + + if (ReadGifByte(pBmp,&nFunctionCode)) goto quit; + if (ReadGifByte(pBmp,&nByteCount)) goto quit; + + // Graphic Control Label & correct Block Size + if (nFunctionCode == 0xF9 && nByteCount == 0x04) + { + INT nPackedFields,nColorIndex; + + // packed fields + if (ReadGifByte(pBmp,&nPackedFields)) goto quit; + + // delay time + if (ReadGifWord(pBmp,&nDummy)) goto quit; + + // transparent color index + if (ReadGifByte(pBmp,&nColorIndex)) goto quit; + + // transparent color flag set + if ((nPackedFields & 0x1) != 0) + { + if (pdwTransparentColor != NULL) + { + *pdwTransparentColor = RGB(sGlb.bmiColors[nColorIndex].rgbRed, + sGlb.bmiColors[nColorIndex].rgbGreen, + sGlb.bmiColors[nColorIndex].rgbBlue); + } + } + + // block terminator (0 byte) + if (!(!ReadGifByte(pBmp,&nDummy) && nDummy == 0)) goto quit; + } + else // other function + { + while (nByteCount != 0) + { + for (i = 0; i < nByteCount; ++i) + { + if (ReadGifByte(pBmp,&nDummy)) goto quit; + } + + if (ReadGifByte(pBmp,&nByteCount)) goto quit; + } + } + } + break; + + case ';': // terminator + bDecoding = FALSE; + break; + + default: goto quit; + } + } + + _ASSERT(bDecoding == FALSE); // decoding successful + + // normal decoding exit + if (bPalette && hPalette == NULL) + { + hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi); + // save old palette + hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE); + RealizePalette(hWindowDC); + } + +quit: + if (hBitmap != NULL && bDecoding) // creation failed + { + DeleteObject(hBitmap); // delete bitmap + hBitmap = NULL; + } + return hBitmap; +} + +static HBITMAP DecodePng(LPBMPFILE pBmp,BOOL bPalette) +{ + // this implementation use the PNG image file decoder + // engine of Copyright (c) 2005-2018 Lode Vandevenne + + HBITMAP hBitmap; + + UINT uError,uWidth,uHeight; + INT nWidth,nHeight; + LONG lBytesPerLine; + + LPBYTE pbyImage; // PNG RGB image data + LPBYTE pbySrc; // source buffer pointer + LPBYTE pbyPixels; // BMP buffer + + BITMAPINFO bmi; + + hBitmap = NULL; + pbyImage = NULL; + + // decode PNG image + uError = lodepng_decode_memory(&pbyImage,&uWidth,&uHeight,pBmp->pbyFile,pBmp->dwFileSize,LCT_RGB,8); + if (uError) goto quit; + + ZeroMemory(&bmi,sizeof(bmi)); // init bitmap info + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = (LONG) uWidth; + bmi.bmiHeader.biHeight = (LONG) uHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 24; // create a true color DIB + bmi.bmiHeader.biCompression = BI_RGB; + + // bitmap dimensions + lBytesPerLine = WIDTHBYTES(bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount); + bmi.bmiHeader.biSizeImage = lBytesPerLine * bmi.bmiHeader.biHeight; + + // allocate buffer for pixels + VERIFY(hBitmap = CreateDIBSection(hWindowDC, + &bmi, + DIB_RGB_COLORS, + (VOID **)&pbyPixels, + NULL, + 0)); + if (hBitmap == NULL) goto quit; + + pbySrc = pbyImage; // init source loop pointer + pbyPixels += bmi.bmiHeader.biSizeImage; // end of destination bitmap + + // fill bottom up DIB pixel buffer with color information + for (nHeight = 0; nHeight < bmi.bmiHeader.biHeight; ++nHeight) + { + LPBYTE pbyLine; + + pbyPixels -= lBytesPerLine; // begin of previous row + pbyLine = pbyPixels; // row working copy + + for (nWidth = 0; nWidth < bmi.bmiHeader.biWidth; ++nWidth) + { + *pbyLine++ = pbySrc[2]; // blue + *pbyLine++ = pbySrc[1]; // green + *pbyLine++ = pbySrc[0]; // red + pbySrc += 3; + } + } + + if (bPalette && hPalette == NULL) + { + hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi); + // save old palette + hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE); + RealizePalette(hWindowDC); + } + +quit: + if (pbyImage != NULL) // buffer for PNG image allocated + { + free(pbyImage); // free PNG image data + } + return hBitmap; +} + +HBITMAP LoadBitmapFile(LPCTSTR szFilename,BOOL bPalette) +{ + HANDLE hFile; + HANDLE hMap; + BMPFILE Bmp; + HBITMAP hBitmap; + + SetCurrentDirectory(szEmuDirectory); + hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + SetCurrentDirectory(szCurrentDirectory); + if (hFile == INVALID_HANDLE_VALUE) return NULL; + Bmp.dwFileSize = GetFileSize(hFile, NULL); + hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if (hMap == NULL) + { + CloseHandle(hFile); + return NULL; + } + Bmp.pbyFile = (LPBYTE) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); + if (Bmp.pbyFile == NULL) + { + CloseHandle(hMap); + CloseHandle(hFile); + return NULL; + } + + do + { + // check for bitmap file header "BM" + if (Bmp.dwFileSize >= 2 && *(WORD *) Bmp.pbyFile == 0x4D42) + { + hBitmap = DecodeBmp(&Bmp,bPalette); + break; + } + + // check for GIF file header + if ( Bmp.dwFileSize >= 6 + && (memcmp(Bmp.pbyFile,"GIF87a",6) == 0 || memcmp(Bmp.pbyFile,"GIF89a",6) == 0)) + { + hBitmap = DecodeGif(&Bmp,&dwTColor,bPalette); + break; + } + + // check for PNG file header + if (Bmp.dwFileSize >= 8 && memcmp(Bmp.pbyFile,"\x89PNG\r\n\x1a\n",8) == 0) + { + hBitmap = DecodePng(&Bmp,bPalette); + break; + } + + // unknown file type + hBitmap = NULL; + } + while (FALSE); + + UnmapViewOfFile(Bmp.pbyFile); + CloseHandle(hMap); + CloseHandle(hFile); + return hBitmap; +} + +static BOOL AbsColorCmp(DWORD dwColor1,DWORD dwColor2,DWORD dwTol) +{ + DWORD dwDiff; + + dwDiff = (DWORD) abs((INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF)); + dwColor1 >>= 8; + dwColor2 >>= 8; + dwDiff += (DWORD) abs((INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF)); + dwColor1 >>= 8; + dwColor2 >>= 8; + dwDiff += (DWORD) abs((INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF)); + + return dwDiff > dwTol; // FALSE = colors match +} + +static BOOL LabColorCmp(DWORD dwColor1,DWORD dwColor2,DWORD dwTol) +{ + DWORD dwDiff; + INT nDiffCol; + + nDiffCol = (INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF); + dwDiff = (DWORD) (nDiffCol * nDiffCol); + dwColor1 >>= 8; + dwColor2 >>= 8; + nDiffCol = (INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF); + dwDiff += (DWORD) (nDiffCol * nDiffCol); + dwColor1 >>= 8; + dwColor2 >>= 8; + nDiffCol = (INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF); + dwDiff += (DWORD) (nDiffCol * nDiffCol); + dwTol *= dwTol; + + return dwDiff > dwTol; // FALSE = colors match +} + +static DWORD EncodeColorBits(DWORD dwColorVal,DWORD dwMask) +{ + #define MAXBIT 32 + UINT uLshift = MAXBIT; + UINT uRshift = 8; + DWORD dwBitMask = dwMask; + + dwColorVal &= 0xFF; // the color component using the lowest 8 bit + + // position of highest bit + while ((dwBitMask & (1<<(MAXBIT-1))) == 0 && uLshift > 0) + { + dwBitMask <<= 1; // next bit + --uLshift; // next position + } + + if (uLshift > 24) // avoid overflow on 32bit mask + { + uLshift -= uRshift; // normalize left shift + uRshift = 0; + } + + return ((dwColorVal << uLshift) >> uRshift) & dwMask; + #undef MAXBIT +} + +HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol) +{ + #define ADD_RECTS_COUNT 256 + + BOOL (*fnColorCmp)(DWORD dwColor1,DWORD dwColor2,DWORD dwTol); + + DWORD dwRed,dwGreen,dwBlue; + LPRGNDATA pRgnData; + LPBITMAPINFO bi; + LPBYTE pbyBits; + LPBYTE pbyColor; + DWORD dwAlignedWidthBytes; + DWORD dwBpp; + DWORD dwRectsCount; + LONG x,y,xleft; + BOOL bFoundLeft; + BOOL bIsMask; + + HRGN hRgn = NULL; // no region defined + + if (dwTol >= 1000) // use CIE L*a*b compare + { + fnColorCmp = LabColorCmp; + dwTol -= 1000; // remove L*a*b compare selector + } + else // use Abs summation compare + { + fnColorCmp = AbsColorCmp; + } + + // allocate memory for extended image information incl. RGBQUAD color table + if ((bi = (LPBITMAPINFO) calloc(1,sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD))) == NULL) + { + return hRgn; // no region + } + bi->bmiHeader.biSize = sizeof(bi->bmiHeader); + _ASSERT(bi->bmiHeader.biBitCount == 0); // for query without color table + + // get information about image + GetDIBits(hWindowDC,hBmp,0,0,NULL,bi,DIB_RGB_COLORS); + + // DWORD aligned bitmap width in BYTES + dwAlignedWidthBytes = WIDTHBYTES( bi->bmiHeader.biWidth + * bi->bmiHeader.biPlanes + * bi->bmiHeader.biBitCount); + + // biSizeImage is empty + if (bi->bmiHeader.biSizeImage == 0 && bi->bmiHeader.biCompression == BI_RGB) + { + bi->bmiHeader.biSizeImage = dwAlignedWidthBytes * bi->bmiHeader.biHeight; + } + + // allocate memory for image data (colors) + if ((pbyBits = (LPBYTE) malloc(bi->bmiHeader.biSizeImage)) == NULL) + { + free(bi); // free bitmap info + return hRgn; // no region + } + + // fill bits buffer + GetDIBits(hWindowDC,hBmp,0,bi->bmiHeader.biHeight,pbyBits,bi,DIB_RGB_COLORS); + + // convert color if current DC is 16-bit/32-bit bitfield coded + if (bi->bmiHeader.biCompression == BI_BITFIELDS) + { + dwRed = *(LPDWORD) &bi->bmiColors[0]; + dwGreen = *(LPDWORD) &bi->bmiColors[1]; + dwBlue = *(LPDWORD) &bi->bmiColors[2]; + } + else // RGB coded + { + // convert color if current DC is 16-bit RGB coded + if (bi->bmiHeader.biBitCount == 16) + { + // for 15 bit (5:5:5) + dwRed = 0x00007C00; + dwGreen = 0x000003E0; + dwBlue = 0x0000001F; + } + else + { + // convert COLORREF to RGBQUAD color + dwRed = 0x00FF0000; + dwGreen = 0x0000FF00; + dwBlue = 0x000000FF; + } + } + color = EncodeColorBits((color >> 16), dwBlue) + | EncodeColorBits((color >> 8), dwGreen) + | EncodeColorBits((color >> 0), dwRed); + + dwBpp = bi->bmiHeader.biBitCount >> 3; // bytes per pixel + + // DIB is bottom up image so we begin with the last scanline + pbyColor = pbyBits + (bi->bmiHeader.biHeight - 1) * dwAlignedWidthBytes; + + dwRectsCount = bi->bmiHeader.biHeight; // number of rects in allocated buffer + + bFoundLeft = FALSE; // set when mask has been found in current scan line + + // allocate memory for region data + pRgnData = (PRGNDATA) malloc(sizeof(RGNDATAHEADER) + dwRectsCount * sizeof(RECT)); + if (pRgnData) + { + // fill it by default + ZeroMemory(&pRgnData->rdh,sizeof(pRgnData->rdh)); + pRgnData->rdh.dwSize = sizeof(pRgnData->rdh); + pRgnData->rdh.iType = RDH_RECTANGLES; + SetRect(&pRgnData->rdh.rcBound,MAXLONG,MAXLONG,0,0); + } + + for (y = 0; pRgnData && y < bi->bmiHeader.biHeight; ++y) + { + LPBYTE pbyLineStart = pbyColor; + + for (x = 0; pRgnData && x < bi->bmiHeader.biWidth; ++x) + { + // get color + switch (bi->bmiHeader.biBitCount) + { + case 8: + bIsMask = fnColorCmp(*(LPDWORD)(&bi->bmiColors)[*pbyColor],color,dwTol); + break; + case 16: + // it makes no sense to allow a tolerance here + bIsMask = (*(LPWORD)pbyColor != (WORD) color); + break; + case 24: + bIsMask = fnColorCmp((*(LPDWORD)pbyColor & 0x00ffffff),color,dwTol); + break; + case 32: + bIsMask = fnColorCmp(*(LPDWORD)pbyColor,color,dwTol); + } + pbyColor += dwBpp; // shift pointer to next color + + if (!bFoundLeft && bIsMask) // non transparent color found + { + xleft = x; + bFoundLeft = TRUE; + } + + if (bFoundLeft) // found non transparent color in scanline + { + // transparent color or last column + if (!bIsMask || x + 1 == bi->bmiHeader.biWidth) + { + // non transparent color and last column + if (bIsMask && x + 1 == bi->bmiHeader.biWidth) + ++x; + + // save current RECT + ((LPRECT) pRgnData->Buffer)[pRgnData->rdh.nCount].left = xleft; + ((LPRECT) pRgnData->Buffer)[pRgnData->rdh.nCount].top = y; + ((LPRECT) pRgnData->Buffer)[pRgnData->rdh.nCount].right = x; + ((LPRECT) pRgnData->Buffer)[pRgnData->rdh.nCount].bottom = y + 1; + pRgnData->rdh.nCount++; + + if (xleft < pRgnData->rdh.rcBound.left) + pRgnData->rdh.rcBound.left = xleft; + + if (y < pRgnData->rdh.rcBound.top) + pRgnData->rdh.rcBound.top = y; + + if (x > pRgnData->rdh.rcBound.right) + pRgnData->rdh.rcBound.right = x; + + if (y + 1 > pRgnData->rdh.rcBound.bottom) + pRgnData->rdh.rcBound.bottom = y + 1; + + // if buffer full reallocate it with more room + if (pRgnData->rdh.nCount >= dwRectsCount) + { + LPRGNDATA pNewRgnData; + + dwRectsCount += ADD_RECTS_COUNT; + pNewRgnData = (LPRGNDATA) realloc(pRgnData,sizeof(RGNDATAHEADER) + dwRectsCount * sizeof(RECT)); + if (pNewRgnData) + { + pRgnData = pNewRgnData; + } + else + { + free(pRgnData); + pRgnData = NULL; + } + } + + bFoundLeft = FALSE; + } + } + } + + // previous scanline + pbyColor = pbyLineStart - dwAlignedWidthBytes; + } + // release image data + free(pbyBits); + free(bi); + + if (pRgnData) // has region data, create region + { + hRgn = ExtCreateRegion(NULL,sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount * sizeof(RECT),pRgnData); + free(pRgnData); + } + return hRgn; + #undef ADD_RECTS_COUNT +} diff --git a/Sources/Emu48/i28f160.c b/Sources/Emu48/I28F160.C similarity index 96% rename from Sources/Emu48/i28f160.c rename to Sources/Emu48/I28F160.C index cf8ed6a..b7175c9 100644 --- a/Sources/Emu48/i28f160.c +++ b/Sources/Emu48/I28F160.C @@ -1,754 +1,754 @@ -/* - * i28f160.c - * - * This file is part of Emu48 - * - * Copyright (C) 2000 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" -#include "i28f160.h" - -#define ARRAYSIZEOF(a) (sizeof(a) / sizeof(a[0])) - -// Flash Command Set -#define READ_ARRAY 0xFF -#define READ_ID_CODES 0x90 -#define READ_QUERY 0x98 -#define READ_STATUS_REG 0x70 -#define CLEAR_STATUS_REG 0x50 -#define WRITE_BUFFER 0xE8 -#define WORD_BYTE_PROG1 0x40 -#define WORD_BYTE_PROG2 0x10 -#define BLOCK_ERASE 0x20 -#define BLOCK_ERASE_SUSPEND 0xB0 -#define BLOCK_ERASE_RESUME 0xD0 -#define STS_CONFIG 0xB8 -#define SET_CLR_BLOCK_LOCK 0x60 -#define FULL_CHIP_ERASE 0x30 - -#define CONFIRM 0xD0 - -// Status Register Definition -#define WSMS 0x80 // WRITE STATE MACHINE STATUS -#define ESS 0x40 // ERASE SUSPEND STATUS -#define ECLBS 0x20 // ERASE AND CLEAR LOCK-BIT STATUS -#define BWSLBS 0x10 // PROGRAM AND SET LOCK-BIT STATUS -#define VPPS 0x08 // Vpp STATUS -#define BWSS 0x04 // PROGRAM SUSPEND STATUS -#define DPS 0x02 // DEVICE PROTECT STATUS - -// Extended Status Register Definition -#define WBS 0x80 // WRITE BUFFER STATUS - -// write state defines -#define WRS_DATA 0 // idle state -#define WRS_WR_BUFFER_N 1 // write buffer no. of data -#define WRS_WR_BUFFER_D 2 // write buffer data -#define WRS_WR_BUFFER_C 3 // write buffer confirm -#define WRS_WR_BYTE 4 // write byte/word -#define WRS_BLOCK_ERASE 5 // block erase -#define WRS_CHIP_ERASE 6 // full chip erase -#define WRS_STS_PIN_CONFIG 7 // STS pin Configuration -#define WRS_LOCK_BITS 8 // Set/Clear Block Lock-Bits - -// read state defines -#define RDS_DATA 0 // data read -#define RDS_ID 1 // read identifier codes -#define RDS_QUERY 2 // read query -#define RDS_SR 3 // read status register -#define RDS_XSR 4 // read extended status register - -// global data -WSMSET WSMset; -BOOL bWP = FALSE; // WP# = low, locked blocks cannot be erased - -// function prototypes -// write function WSM state -static VOID WrStateIdle(BYTE a, DWORD d); -static VOID WrStateE8(DWORD d); -static VOID WrStateE8N(BYTE a, DWORD d); -static VOID WrStateE8D(BYTE a, DWORD d); -static VOID WrStateE8C(BYTE a, DWORD d); -static VOID WrState40(DWORD d); -static VOID WrState40D(BYTE a, DWORD d); -static VOID WrState20(DWORD d); -static VOID WrState20C(BYTE a, DWORD d); -static VOID WrState30(DWORD d); -static VOID WrState30C(BYTE a, DWORD d); -static VOID WrStateB8(DWORD d); -static VOID WrStateB8D(BYTE a, DWORD d); -static VOID WrState60(DWORD d); -static VOID WrState60D(BYTE a, DWORD d); - -static VOID (*CONST fnWrState[])(BYTE a, DWORD d) = -{ - WrStateIdle, - WrStateE8N, WrStateE8D, WrStateE8C, - WrState40D, - WrState20C, - WrState30C, - WrStateB8D, - WrState60D -}; - -// read function WSM state -static BYTE RdStateData(DWORD d); -static BYTE RdStateId(DWORD d); -static BYTE RdStateQuery(DWORD d); -static BYTE RdStateSR(DWORD d); -static BYTE RdStateXSR(DWORD d); - -static BYTE (*CONST fnRdState[])(DWORD d) = -{ - RdStateData, RdStateId, RdStateQuery, RdStateSR, RdStateXSR -}; - - -// read query table -// device address A16-A1, A0 unused -static CONST BYTE byQueryTab[] = -{ - // access with "Read Identifier Codes" command - // Identifier codes - 0xB0, // 00, Manufacturer Code - 0xD0, // 01, Device Code (16 Mbit) - 0x00, // 02, Block Lock Configuration - 0x02, // 03, ?? - - 0x00, // 04, Reserved for vendor-specific information - 0x00, // 05, " - 0x00, // 06, " - 0x00, // 07, " - 0x00, // 08, " - 0x00, // 09, " - 0x00, // 0A, " - 0x00, // 0B, " - 0x00, // 0C, " - 0x00, // 0D, " - 0x00, // 0E, " - 0x00, // 0F, " - - // access with "Read Query" command - // CFI query identification string - 0x51, // 10, Query-Unique ASCII string "Q" - 0x52, // 11, Query-Unique ASCII string "R" - 0x59, // 12, Query-Unique ASCII string "Y" - 0x01, // 13, Primary Vendor Command Set and Control Interface ID CODE - 0x00, // 14, " - 0x31, // 15, Address for Primary Algorithm Extended Query Table - 0x00, // 16, " - 0x00, // 17, Alternate Vendor Command Set and Control Interface ID Code - 0x00, // 18, " - 0x00, // 19, Address for Secondary Algorithm Extended Query Table - 0x00, // 1A, " - - // System interface information - 0x30, // 1B, Vcc Logic Supply Minimum Program/Erase Voltage (0x27 intel doc, 0x30 real chip) - 0x55, // 1C, Vcc Logic Supply Maximum Program/Erase Voltage - 0x30, // 1D, Vpp [Programming] Supply Minimum Program/Erase Voltage (0x27 intel doc, 0x30 real chip) - 0x55, // 1E, Vpp [Programming] Supply Maximum Program/Erase Voltage - 0x03, // 1F, Typical Time-Out per Single Byte/Word Program - 0x06, // 20, Typical Time-Out for Max. Buffer Write - 0x0A, // 21, Typical Time-Out per Individual Block Erase - 0x0F, // 22, Typical Time-Out for Full Chip Erase - 0x04, // 23, Maximum Time-Out for Byte/Word Program - 0x04, // 24, Maximum Time-Out for Buffer Write - 0x04, // 25, Maximum Time-Out per Individual Block Erase - 0x04, // 26, Maximum Time-Out for Full Chip Erase - 0x15, // 27, Device Size - 0x02, // 28, Flash Device Interface Description - 0x00, // 29, " - 0x05, // 2A, Maximum Number of Bytes in Write Buffer - 0x00, // 2B, " - 0x01, // 2C, Number of Erase Block Regions within Device - 0x1F, // 2D, Erase Block Region Information - 0x00, // 2E, " - 0x00, // 2F, " - 0x01, // 30, " - - // Intel-specific extended query table - 0x50, // 31, Primary Extended Query Table, Unique ASCII string "P" - 0x52, // 32, Primary Extended Query Table, Unique ASCII string "R" - 0x49, // 33, Primary Extended Query Table, Unique ASCII string "I" - 0x31, // 34, Major Version Number, ASCII - 0x30, // 35, Minor Version Number, ASCII - 0x0F, // 36, Optional Feature & Command Support - 0x00, // 37, " - 0x00, // 38, " - 0x00, // 39, " - 0x01, // 3A, Supported Functions after Suspend - 0x03, // 3B, Block Status Register Mask - 0x00, // 3C, " - 0x50, // 3D, Vcc Logic Supply Optimum Program/Erase voltage - 0x50, // 3E, Vpp [Programming] Supply Optimum Program/Erase voltage - 0x00 // 3F, ?? -}; - - -// -// ROM buffer access functions -// - -static __inline void WrDirtyPage(DWORD d) -{ - if (pbyRomDirtyPage) // using dirty ROM page table - { - DWORD dwPage = d / ROMPAGESIZE; // this is the page - - _ASSERT(dwPage < dwRomDirtyPageSize); - pbyRomDirtyPage[dwPage] = TRUE; // page is dirty - } - return; -} - -static __inline void EraseBlock(DWORD d,DWORD dwNibSize) -{ - LPBYTE pbyAddr = pbyRom + d; - - while (dwNibSize--) - { - WrDirtyPage(d++); // make page dirty - *pbyAddr++ = 0x0F; // clear address - } - return; -} - -static __inline void WriteByte(DWORD d,BYTE byData) -{ - WrDirtyPage(d); // make page dirty - - _ASSERT(d+1 < dwRomSize); // address valid? - *(pbyRom+d) &= (byData & 0x0F); // write LSB - *(pbyRom+d+1) &= (byData >> 4); // write MSB - return; -} - -static __inline BYTE ReadByte(DWORD d) -{ - _ASSERT(d+1 < dwRomSize); // address valid? - return *(pbyRom+d)|(*(pbyRom+d+1)<<4); // get byte -} - - -// -// write state functions -// - -static VOID WrStateIdle(BYTE a, DWORD d) -{ - WSMset.bRomArray = FALSE; // register access - - switch(a) - { - case READ_ARRAY: // read array mode, normal operation - WSMset.bRomArray = TRUE; // data array access - WSMset.uWrState = WRS_DATA; - WSMset.uRdState = RDS_DATA; - break; - case READ_ID_CODES: // read identifier codes register - WSMset.uRdState = RDS_ID; - break; - case READ_QUERY: // read query register - WSMset.uRdState = RDS_QUERY; - break; - case READ_STATUS_REG: // read status register - WSMset.uRdState = RDS_SR; - break; - case CLEAR_STATUS_REG: // clear status register - WSMset.byStatusReg = 0; - break; - case WRITE_BUFFER: // write to buffer - WrStateE8(d); - break; - case WORD_BYTE_PROG1: - case WORD_BYTE_PROG2: // byte/word program - WrState40(d); - break; - case BLOCK_ERASE: // block erase - WrState20(d); - break; - case BLOCK_ERASE_SUSPEND: // block erase, word/byte program suspend - WSMset.byStatusReg |= WSMS; // operation suspended - WSMset.byStatusReg &= ~ESS; // block erase completed (because no timing emulation) - WSMset.byStatusReg &= ~BWSS; // program completed (because no timing emulation) - WSMset.uRdState = RDS_SR; - break; - case BLOCK_ERASE_RESUME: // block erase, word/byte program resume - WSMset.byStatusReg &= ~WSMS; // operation in progress - WSMset.byStatusReg &= ~ESS; // block erase in progress - WSMset.byStatusReg &= ~BWSS; // program in progress - WSMset.byStatusReg |= WSMS; // operation completed (because no timing emulation) - WSMset.uRdState = RDS_SR; - break; - case STS_CONFIG: - WSMset.bRomArray = bFlashRomArray; // old access mode - WrStateB8(d); - break; - case SET_CLR_BLOCK_LOCK: // set/clear block lock-bits - WrState60(d); - break; - case FULL_CHIP_ERASE: // full chip erase - WrState30(d); - break; - default: // wrong command - WSMset.bRomArray = bFlashRomArray; // old access mode - break; - } - - if (bFlashRomArray != WSMset.bRomArray) // new access mode - { - bFlashRomArray = WSMset.bRomArray; // change register access - Map(0x00,0xFF); // update memory mapping - UpdatePatches(bFlashRomArray); // patch/unpatch ROM again - } - return; -} - -// write to buffer initial command -static VOID WrStateE8(DWORD d) -{ - // @todo add 2nd write buffer implementation - // @todo add program timing implementation - - WSMset.byExStatusReg = 0; // no write buffer - if (WSMset.byWrite1No == 0) // buffer1 available - { - WSMset.byWrite1No = 1; // buffer1 in use - WSMset.dwWrite1Addr = d; // byte block address of buffer1 - WSMset.byExStatusReg = WBS; // write buffer available - // fill write buffer - FillMemory(WSMset.pbyWrite1,ARRAYSIZEOF(WSMset.pbyWrite1),0xFF); - WSMset.uWrState = WRS_WR_BUFFER_N; // set state machine - WSMset.uRdState = RDS_XSR; - } - return; -} - -// write to buffer number of byte -static VOID WrStateE8N(BYTE a, DWORD d) -{ - if (a < (1 << byQueryTab[0x2A])) // byte is length information - { - WSMset.byWrite1No += a; // save no. of byte to program - WSMset.byWrite1Size = a; // save size to check write buffer boundaries - WSMset.dwWrite1Addr = d; // byte block address of buffer1 - WSMset.byStatusReg &= ~WSMS; // state machine busy - WSMset.uWrState = WRS_WR_BUFFER_D; - } - else - { - WSMset.byWrite1No = 0; // free write buffer - // improper command sequence - WSMset.byStatusReg |= (ECLBS | BWSLBS); - WSMset.byStatusReg |= WSMS; // data written - WSMset.uWrState = WRS_DATA; - } - WSMset.uRdState = RDS_SR; - return; -} - -// write to buffer data -static VOID WrStateE8D(BYTE a, DWORD d) -{ - // first data byte - if (WSMset.byWrite1No == WSMset.byWrite1Size + 1) - { - DWORD dwBlockMask = ~(((byQueryTab[0x30] << 8) | byQueryTab[0x2F]) * 256 - 1); - - // same block - if ((WSMset.dwWrite1Addr & dwBlockMask) == (d & dwBlockMask)) - { - WSMset.dwWrite1Addr = d; // byte block address of buffer1 - WSMset.pbyWrite1[0] = a; // save byte - } - else - { - WSMset.byWrite1No = 0; // free write buffer - // improper command sequence - WSMset.byStatusReg |= (ECLBS | BWSLBS); - WSMset.byStatusReg |= WSMS; // data written - WSMset.uWrState = WRS_DATA; - return; - } - } - else - { - // write address within buffer - if (d >= WSMset.dwWrite1Addr && d <= WSMset.dwWrite1Addr + WSMset.byWrite1Size) - { - // save byte in buffer - WSMset.pbyWrite1[d-WSMset.dwWrite1Addr] = a; - } - else - { - WSMset.byWrite1No = 0; // free write buffer - // improper command sequence - WSMset.byStatusReg |= (ECLBS | BWSLBS); - WSMset.byStatusReg |= WSMS; // data written - WSMset.uWrState = WRS_DATA; - return; - } - } - - if (--WSMset.byWrite1No == 0) // last byte written - WSMset.uWrState = WRS_WR_BUFFER_C; // goto confirm state - return; -} - -// write to buffer confirm -static VOID WrStateE8C(BYTE a, DWORD d) -{ - if (CONFIRM == a) // write buffer confirm? - { - BYTE byPos; - - d = WSMset.dwWrite1Addr << 1; // nibble start address - - for (byPos = 0; byPos <= WSMset.byWrite1Size; ++byPos) - { - a = WSMset.pbyWrite1[byPos]; // get char from buffer - - _ASSERT(d+1 < dwRomSize); // address valid? - // no error set in BWSLBS, because I could alway program a "0" - WriteByte(d,a); // write byte - d += 2; // next address - } - } - else - { - WSMset.byWrite1No = 0; // free write buffer - // improper command sequence - WSMset.byStatusReg |= (ECLBS | BWSLBS); - } - WSMset.byStatusReg |= WSMS; // data written - WSMset.uWrState = WRS_DATA; - return; -} - -// byte/word program initial command -static VOID WrState40(DWORD d) -{ - WSMset.byStatusReg &= ~WSMS; // state machine busy - WSMset.uWrState = WRS_WR_BYTE; - WSMset.uRdState = RDS_SR; - return; - UNREFERENCED_PARAMETER(d); -} - -// byte/word program data -static VOID WrState40D(BYTE a, DWORD d) -{ - // no error set in BWSLBS, because I could alway program a "0" - WriteByte(d << 1,a); // write byte - WSMset.byStatusReg |= WSMS; // data written - WSMset.uWrState = WRS_DATA; - return; -} - -// block erase initial command -static VOID WrState20(DWORD d) -{ - WSMset.byStatusReg &= ~WSMS; // state machine busy - WSMset.uWrState = WRS_BLOCK_ERASE; - WSMset.uRdState = RDS_SR; - return; - UNREFERENCED_PARAMETER(d); -} - -// block erase data & confirm -static VOID WrState20C(BYTE a, DWORD d) -{ - if (CONFIRM == a) // block erase confirm? - { - // lock bit of block is set - if ((WSMset.dwLockCnfg & (1<<(d>>16))) != 0) - { - WSMset.byStatusReg |= ECLBS; // error in block erasure - WSMset.byStatusReg |= DPS; // lock bit detected - } - else - { - DWORD dwBlockSize = ((byQueryTab[0x30] << 8) | byQueryTab[0x2F]) * 256; - - d &= ~(dwBlockSize-1); // start of block - dwBlockSize *= 2; // block size in nibbles - _ASSERT(d+dwBlockSize <= dwRomSize); // address valid? - EraseBlock(d << 1,dwBlockSize); // erase 128K nibble - } - } - else - { - // improper command sequence - WSMset.byStatusReg |= (ECLBS | BWSLBS); - } - WSMset.byStatusReg |= WSMS; // block erased - WSMset.uWrState = WRS_DATA; - return; -} - -// full chip erase initial command -static VOID WrState30(DWORD d) -{ - WSMset.byStatusReg &= ~WSMS; // state machine busy - WSMset.uWrState = WRS_CHIP_ERASE; - WSMset.uRdState = RDS_SR; - return; - UNREFERENCED_PARAMETER(d); -} - -// full chip erase confirm -static VOID WrState30C(BYTE a, DWORD d) -{ - if (CONFIRM == a) // chip erase confirm? - { - UINT i; - - WORD wNoOfBlocks = (byQueryTab[0x2E] << 8) | byQueryTab[0x2D]; - DWORD dwBlockSize = ((byQueryTab[0x30] << 8) | byQueryTab[0x2F]) * 256; - - DWORD dwBlockAddr = 0; - - dwBlockSize *= 2; // block size in nibbles - - for (i = 0; i <= wNoOfBlocks; ++i) // check all blocks - { - _ASSERT((i+1)*dwBlockSize <= dwRomSize); - - // lock bit of block is set & WP# = low, locked blocks cannot be erased - if ((WSMset.dwLockCnfg & (1<>16)); // set block lock bit - else - WSMset.byStatusReg |= (BWSLBS | DPS); // device protect detect, WP# = low - break; - case CONFIRM: // clear block lock bits - if (bWP) // WP# = high, can change block lock status - { - WORD wNoOfBlocks = (byQueryTab[0x2E] << 8) | byQueryTab[0x2D]; - - for (i = 0; i <= wNoOfBlocks; ++i) // clear all lock bits - { - WSMset.dwLockCnfg &= ~(1 << i); // clear block lock bit - } - } - else - { - WSMset.byStatusReg |= (ECLBS | DPS); // device protect detect, WP# = low - } - break; - default: // improper command sequence - WSMset.byStatusReg |= (ECLBS | BWSLBS); - } - WSMset.byStatusReg |= WSMS; // block lock-bit changed - WSMset.uWrState = WRS_DATA; - return; -} - - -// -// read state functions -// - -// read array -static BYTE RdStateData(DWORD d) -{ - return ReadByte(d << 1); // get byte -} - -// read identifier codes -static BYTE RdStateId(DWORD d) -{ - BYTE byData; - - d >>= 1; // A0 is not connected, ignore it - if ((d & 0x03) != 0x02) // id code request - { - d &= 0x03; // data repetition - byData = byQueryTab[d]; // get data from first 4 bytes id/query table - } - else // block lock table - { - // get data from block lock table - byData = (BYTE) ((WSMset.dwLockCnfg >> (d >> 15)) & 1); - - d &= 0x1F; // data repetition - if (d >= 4) byData |= 0x02; // set bit 1 on wrong ID adress - } - return byData; -} - -// read query -static BYTE RdStateQuery(DWORD d) -{ - BYTE byData; - - d >>= 1; // A0 is not connected, ignore it - if ((d & 0x7F) != 0x02) // query request - { - d &= 0x7F; // data repetition - - // get data from id/query table - byData = (d >= 0x40 && d < 0x50) ? 0 : byQueryTab[d&0x3F]; - } - else // block lock table - { - // get data from block lock table - byData = (BYTE) ((WSMset.dwLockCnfg >> (d >> 15)) & 1); - } - return byData; -} - -// read status register -static BYTE RdStateSR(DWORD d) -{ - return WSMset.byStatusReg; - UNREFERENCED_PARAMETER(d); -} - -// read extended status register -static BYTE RdStateXSR(DWORD d) -{ - return WSMset.byExStatusReg; - UNREFERENCED_PARAMETER(d); -} - - -// -// public functions -// - -VOID FlashInit(VOID) -{ - // check if locking bit table has more or equal than 32 bit - _ASSERT(sizeof(WSMset.dwLockCnfg) * 8 >= 32); - - ZeroMemory(&WSMset,sizeof(WSMset)); - strcpy((LPSTR) WSMset.byType,"WSM"); // Write State Machine header - WSMset.uSize = sizeof(WSMset); // size of this structure - WSMset.byVersion = WSMVER; // version of flash implementation structure - - // factory setting of locking bits - WSMset.dwLockCnfg = (1 << 0); // first 64KB block is locked - - WSMset.uWrState = WRS_DATA; - WSMset.uRdState = RDS_DATA; - - // data mode of ROM - WSMset.bRomArray = bFlashRomArray = TRUE; - return; -} - -VOID FlashRead(BYTE *a, DWORD d, UINT s) -{ - BYTE v; - - while (s) // each nibble - { - // output muliplexer - _ASSERT(WSMset.uRdState < ARRAYSIZEOF(fnRdState)); - v = fnRdState[WSMset.uRdState](d>>1); - - if ((d & 1) == 0) // even address - { - *a++ = v & 0xf; ++d; --s; - } - if (s && (d & 1)) // odd address - { - *a++ = v >> 4; ++d; --s; - } - } - return; -} - -VOID FlashWrite(BYTE *a, DWORD d, UINT s) -{ - BYTE v; - DWORD p; - - while (s) // each nibble - { - p = d >> 1; // byte address - if (s > 1 && (d & 1) == 0) // more than one byte on even address - { - v = *a++; // LSB - v |= *a++ << 4; // MSB - d += 2; s -= 2; - } - else - { - // get byte from output muliplexer - _ASSERT(WSMset.uRdState < ARRAYSIZEOF(fnRdState)); - v = fnRdState[WSMset.uRdState](p); - - if (d & 1) // odd address - v = (v & 0x0F) | (*a << 4); // replace MSB - else // even address - v = (v & 0xF0) | *a; // replace LSB - ++a; ++d; --s; - } - - _ASSERT(WSMset.uWrState < ARRAYSIZEOF(fnWrState)); - fnWrState[WSMset.uWrState](v,p); // WSM - } - return; -} +/* + * i28f160.c + * + * This file is part of Emu48 + * + * Copyright (C) 2000 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" +#include "i28f160.h" + +#define ARRAYSIZEOF(a) (sizeof(a) / sizeof(a[0])) + +// Flash Command Set +#define READ_ARRAY 0xFF +#define READ_ID_CODES 0x90 +#define READ_QUERY 0x98 +#define READ_STATUS_REG 0x70 +#define CLEAR_STATUS_REG 0x50 +#define WRITE_BUFFER 0xE8 +#define WORD_BYTE_PROG1 0x40 +#define WORD_BYTE_PROG2 0x10 +#define BLOCK_ERASE 0x20 +#define BLOCK_ERASE_SUSPEND 0xB0 +#define BLOCK_ERASE_RESUME 0xD0 +#define STS_CONFIG 0xB8 +#define SET_CLR_BLOCK_LOCK 0x60 +#define FULL_CHIP_ERASE 0x30 + +#define CONFIRM 0xD0 + +// Status Register Definition +#define WSMS 0x80 // WRITE STATE MACHINE STATUS +#define ESS 0x40 // ERASE SUSPEND STATUS +#define ECLBS 0x20 // ERASE AND CLEAR LOCK-BIT STATUS +#define BWSLBS 0x10 // PROGRAM AND SET LOCK-BIT STATUS +#define VPPS 0x08 // Vpp STATUS +#define BWSS 0x04 // PROGRAM SUSPEND STATUS +#define DPS 0x02 // DEVICE PROTECT STATUS + +// Extended Status Register Definition +#define WBS 0x80 // WRITE BUFFER STATUS + +// write state defines +#define WRS_DATA 0 // idle state +#define WRS_WR_BUFFER_N 1 // write buffer no. of data +#define WRS_WR_BUFFER_D 2 // write buffer data +#define WRS_WR_BUFFER_C 3 // write buffer confirm +#define WRS_WR_BYTE 4 // write byte/word +#define WRS_BLOCK_ERASE 5 // block erase +#define WRS_CHIP_ERASE 6 // full chip erase +#define WRS_STS_PIN_CONFIG 7 // STS pin Configuration +#define WRS_LOCK_BITS 8 // Set/Clear Block Lock-Bits + +// read state defines +#define RDS_DATA 0 // data read +#define RDS_ID 1 // read identifier codes +#define RDS_QUERY 2 // read query +#define RDS_SR 3 // read status register +#define RDS_XSR 4 // read extended status register + +// global data +WSMSET WSMset; +BOOL bWP = FALSE; // WP# = low, locked blocks cannot be erased + +// function prototypes +// write function WSM state +static VOID WrStateIdle(BYTE a, DWORD d); +static VOID WrStateE8(DWORD d); +static VOID WrStateE8N(BYTE a, DWORD d); +static VOID WrStateE8D(BYTE a, DWORD d); +static VOID WrStateE8C(BYTE a, DWORD d); +static VOID WrState40(DWORD d); +static VOID WrState40D(BYTE a, DWORD d); +static VOID WrState20(DWORD d); +static VOID WrState20C(BYTE a, DWORD d); +static VOID WrState30(DWORD d); +static VOID WrState30C(BYTE a, DWORD d); +static VOID WrStateB8(DWORD d); +static VOID WrStateB8D(BYTE a, DWORD d); +static VOID WrState60(DWORD d); +static VOID WrState60D(BYTE a, DWORD d); + +static VOID (*CONST fnWrState[])(BYTE a, DWORD d) = +{ + WrStateIdle, + WrStateE8N, WrStateE8D, WrStateE8C, + WrState40D, + WrState20C, + WrState30C, + WrStateB8D, + WrState60D +}; + +// read function WSM state +static BYTE RdStateData(DWORD d); +static BYTE RdStateId(DWORD d); +static BYTE RdStateQuery(DWORD d); +static BYTE RdStateSR(DWORD d); +static BYTE RdStateXSR(DWORD d); + +static BYTE (*CONST fnRdState[])(DWORD d) = +{ + RdStateData, RdStateId, RdStateQuery, RdStateSR, RdStateXSR +}; + + +// read query table +// device address A16-A1, A0 unused +static CONST BYTE byQueryTab[] = +{ + // access with "Read Identifier Codes" command + // Identifier codes + 0xB0, // 00, Manufacturer Code + 0xD0, // 01, Device Code (16 Mbit) + 0x00, // 02, Block Lock Configuration + 0x02, // 03, ?? + + 0x00, // 04, Reserved for vendor-specific information + 0x00, // 05, " + 0x00, // 06, " + 0x00, // 07, " + 0x00, // 08, " + 0x00, // 09, " + 0x00, // 0A, " + 0x00, // 0B, " + 0x00, // 0C, " + 0x00, // 0D, " + 0x00, // 0E, " + 0x00, // 0F, " + + // access with "Read Query" command + // CFI query identification string + 0x51, // 10, Query-Unique ASCII string "Q" + 0x52, // 11, Query-Unique ASCII string "R" + 0x59, // 12, Query-Unique ASCII string "Y" + 0x01, // 13, Primary Vendor Command Set and Control Interface ID CODE + 0x00, // 14, " + 0x31, // 15, Address for Primary Algorithm Extended Query Table + 0x00, // 16, " + 0x00, // 17, Alternate Vendor Command Set and Control Interface ID Code + 0x00, // 18, " + 0x00, // 19, Address for Secondary Algorithm Extended Query Table + 0x00, // 1A, " + + // System interface information + 0x30, // 1B, Vcc Logic Supply Minimum Program/Erase Voltage (0x27 intel doc, 0x30 real chip) + 0x55, // 1C, Vcc Logic Supply Maximum Program/Erase Voltage + 0x30, // 1D, Vpp [Programming] Supply Minimum Program/Erase Voltage (0x27 intel doc, 0x30 real chip) + 0x55, // 1E, Vpp [Programming] Supply Maximum Program/Erase Voltage + 0x03, // 1F, Typical Time-Out per Single Byte/Word Program + 0x06, // 20, Typical Time-Out for Max. Buffer Write + 0x0A, // 21, Typical Time-Out per Individual Block Erase + 0x0F, // 22, Typical Time-Out for Full Chip Erase + 0x04, // 23, Maximum Time-Out for Byte/Word Program + 0x04, // 24, Maximum Time-Out for Buffer Write + 0x04, // 25, Maximum Time-Out per Individual Block Erase + 0x04, // 26, Maximum Time-Out for Full Chip Erase + 0x15, // 27, Device Size + 0x02, // 28, Flash Device Interface Description + 0x00, // 29, " + 0x05, // 2A, Maximum Number of Bytes in Write Buffer + 0x00, // 2B, " + 0x01, // 2C, Number of Erase Block Regions within Device + 0x1F, // 2D, Erase Block Region Information + 0x00, // 2E, " + 0x00, // 2F, " + 0x01, // 30, " + + // Intel-specific extended query table + 0x50, // 31, Primary Extended Query Table, Unique ASCII string "P" + 0x52, // 32, Primary Extended Query Table, Unique ASCII string "R" + 0x49, // 33, Primary Extended Query Table, Unique ASCII string "I" + 0x31, // 34, Major Version Number, ASCII + 0x30, // 35, Minor Version Number, ASCII + 0x0F, // 36, Optional Feature & Command Support + 0x00, // 37, " + 0x00, // 38, " + 0x00, // 39, " + 0x01, // 3A, Supported Functions after Suspend + 0x03, // 3B, Block Status Register Mask + 0x00, // 3C, " + 0x50, // 3D, Vcc Logic Supply Optimum Program/Erase voltage + 0x50, // 3E, Vpp [Programming] Supply Optimum Program/Erase voltage + 0x00 // 3F, ?? +}; + + +// +// ROM buffer access functions +// + +static __inline void WrDirtyPage(DWORD d) +{ + if (pbyRomDirtyPage) // using dirty ROM page table + { + DWORD dwPage = d / ROMPAGESIZE; // this is the page + + _ASSERT(dwPage < dwRomDirtyPageSize); + pbyRomDirtyPage[dwPage] = TRUE; // page is dirty + } + return; +} + +static __inline void EraseBlock(DWORD d,DWORD dwNibSize) +{ + LPBYTE pbyAddr = pbyRom + d; + + while (dwNibSize--) + { + WrDirtyPage(d++); // make page dirty + *pbyAddr++ = 0x0F; // clear address + } + return; +} + +static __inline void WriteByte(DWORD d,BYTE byData) +{ + WrDirtyPage(d); // make page dirty + + _ASSERT(d+1 < dwRomSize); // address valid? + *(pbyRom+d) &= (byData & 0x0F); // write LSB + *(pbyRom+d+1) &= (byData >> 4); // write MSB + return; +} + +static __inline BYTE ReadByte(DWORD d) +{ + _ASSERT(d+1 < dwRomSize); // address valid? + return *(pbyRom+d)|(*(pbyRom+d+1)<<4); // get byte +} + + +// +// write state functions +// + +static VOID WrStateIdle(BYTE a, DWORD d) +{ + WSMset.bRomArray = FALSE; // register access + + switch(a) + { + case READ_ARRAY: // read array mode, normal operation + WSMset.bRomArray = TRUE; // data array access + WSMset.uWrState = WRS_DATA; + WSMset.uRdState = RDS_DATA; + break; + case READ_ID_CODES: // read identifier codes register + WSMset.uRdState = RDS_ID; + break; + case READ_QUERY: // read query register + WSMset.uRdState = RDS_QUERY; + break; + case READ_STATUS_REG: // read status register + WSMset.uRdState = RDS_SR; + break; + case CLEAR_STATUS_REG: // clear status register + WSMset.byStatusReg = 0; + break; + case WRITE_BUFFER: // write to buffer + WrStateE8(d); + break; + case WORD_BYTE_PROG1: + case WORD_BYTE_PROG2: // byte/word program + WrState40(d); + break; + case BLOCK_ERASE: // block erase + WrState20(d); + break; + case BLOCK_ERASE_SUSPEND: // block erase, word/byte program suspend + WSMset.byStatusReg |= WSMS; // operation suspended + WSMset.byStatusReg &= ~ESS; // block erase completed (because no timing emulation) + WSMset.byStatusReg &= ~BWSS; // program completed (because no timing emulation) + WSMset.uRdState = RDS_SR; + break; + case BLOCK_ERASE_RESUME: // block erase, word/byte program resume + WSMset.byStatusReg &= ~WSMS; // operation in progress + WSMset.byStatusReg &= ~ESS; // block erase in progress + WSMset.byStatusReg &= ~BWSS; // program in progress + WSMset.byStatusReg |= WSMS; // operation completed (because no timing emulation) + WSMset.uRdState = RDS_SR; + break; + case STS_CONFIG: + WSMset.bRomArray = bFlashRomArray; // old access mode + WrStateB8(d); + break; + case SET_CLR_BLOCK_LOCK: // set/clear block lock-bits + WrState60(d); + break; + case FULL_CHIP_ERASE: // full chip erase + WrState30(d); + break; + default: // wrong command + WSMset.bRomArray = bFlashRomArray; // old access mode + break; + } + + if (bFlashRomArray != WSMset.bRomArray) // new access mode + { + bFlashRomArray = WSMset.bRomArray; // change register access + Map(0x00,0xFF); // update memory mapping + UpdatePatches(bFlashRomArray); // patch/unpatch ROM again + } + return; +} + +// write to buffer initial command +static VOID WrStateE8(DWORD d) +{ + // @todo add 2nd write buffer implementation + // @todo add program timing implementation + + WSMset.byExStatusReg = 0; // no write buffer + if (WSMset.byWrite1No == 0) // buffer1 available + { + WSMset.byWrite1No = 1; // buffer1 in use + WSMset.dwWrite1Addr = d; // byte block address of buffer1 + WSMset.byExStatusReg = WBS; // write buffer available + // fill write buffer + FillMemory(WSMset.pbyWrite1,ARRAYSIZEOF(WSMset.pbyWrite1),0xFF); + WSMset.uWrState = WRS_WR_BUFFER_N; // set state machine + WSMset.uRdState = RDS_XSR; + } + return; +} + +// write to buffer number of byte +static VOID WrStateE8N(BYTE a, DWORD d) +{ + if (a < (1 << byQueryTab[0x2A])) // byte is length information + { + WSMset.byWrite1No += a; // save no. of byte to program + WSMset.byWrite1Size = a; // save size to check write buffer boundaries + WSMset.dwWrite1Addr = d; // byte block address of buffer1 + WSMset.byStatusReg &= ~WSMS; // state machine busy + WSMset.uWrState = WRS_WR_BUFFER_D; + } + else + { + WSMset.byWrite1No = 0; // free write buffer + // improper command sequence + WSMset.byStatusReg |= (ECLBS | BWSLBS); + WSMset.byStatusReg |= WSMS; // data written + WSMset.uWrState = WRS_DATA; + } + WSMset.uRdState = RDS_SR; + return; +} + +// write to buffer data +static VOID WrStateE8D(BYTE a, DWORD d) +{ + // first data byte + if (WSMset.byWrite1No == WSMset.byWrite1Size + 1) + { + DWORD dwBlockMask = ~(((byQueryTab[0x30] << 8) | byQueryTab[0x2F]) * 256 - 1); + + // same block + if ((WSMset.dwWrite1Addr & dwBlockMask) == (d & dwBlockMask)) + { + WSMset.dwWrite1Addr = d; // byte block address of buffer1 + WSMset.pbyWrite1[0] = a; // save byte + } + else + { + WSMset.byWrite1No = 0; // free write buffer + // improper command sequence + WSMset.byStatusReg |= (ECLBS | BWSLBS); + WSMset.byStatusReg |= WSMS; // data written + WSMset.uWrState = WRS_DATA; + return; + } + } + else + { + // write address within buffer + if (d >= WSMset.dwWrite1Addr && d <= WSMset.dwWrite1Addr + WSMset.byWrite1Size) + { + // save byte in buffer + WSMset.pbyWrite1[d-WSMset.dwWrite1Addr] = a; + } + else + { + WSMset.byWrite1No = 0; // free write buffer + // improper command sequence + WSMset.byStatusReg |= (ECLBS | BWSLBS); + WSMset.byStatusReg |= WSMS; // data written + WSMset.uWrState = WRS_DATA; + return; + } + } + + if (--WSMset.byWrite1No == 0) // last byte written + WSMset.uWrState = WRS_WR_BUFFER_C; // goto confirm state + return; +} + +// write to buffer confirm +static VOID WrStateE8C(BYTE a, DWORD d) +{ + if (CONFIRM == a) // write buffer confirm? + { + BYTE byPos; + + d = WSMset.dwWrite1Addr << 1; // nibble start address + + for (byPos = 0; byPos <= WSMset.byWrite1Size; ++byPos) + { + a = WSMset.pbyWrite1[byPos]; // get char from buffer + + _ASSERT(d+1 < dwRomSize); // address valid? + // no error set in BWSLBS, because I could alway program a "0" + WriteByte(d,a); // write byte + d += 2; // next address + } + } + else + { + WSMset.byWrite1No = 0; // free write buffer + // improper command sequence + WSMset.byStatusReg |= (ECLBS | BWSLBS); + } + WSMset.byStatusReg |= WSMS; // data written + WSMset.uWrState = WRS_DATA; + return; +} + +// byte/word program initial command +static VOID WrState40(DWORD d) +{ + WSMset.byStatusReg &= ~WSMS; // state machine busy + WSMset.uWrState = WRS_WR_BYTE; + WSMset.uRdState = RDS_SR; + return; + UNREFERENCED_PARAMETER(d); +} + +// byte/word program data +static VOID WrState40D(BYTE a, DWORD d) +{ + // no error set in BWSLBS, because I could alway program a "0" + WriteByte(d << 1,a); // write byte + WSMset.byStatusReg |= WSMS; // data written + WSMset.uWrState = WRS_DATA; + return; +} + +// block erase initial command +static VOID WrState20(DWORD d) +{ + WSMset.byStatusReg &= ~WSMS; // state machine busy + WSMset.uWrState = WRS_BLOCK_ERASE; + WSMset.uRdState = RDS_SR; + return; + UNREFERENCED_PARAMETER(d); +} + +// block erase data & confirm +static VOID WrState20C(BYTE a, DWORD d) +{ + if (CONFIRM == a) // block erase confirm? + { + // lock bit of block is set + if ((WSMset.dwLockCnfg & (1<<(d>>16))) != 0) + { + WSMset.byStatusReg |= ECLBS; // error in block erasure + WSMset.byStatusReg |= DPS; // lock bit detected + } + else + { + DWORD dwBlockSize = ((byQueryTab[0x30] << 8) | byQueryTab[0x2F]) * 256; + + d &= ~(dwBlockSize-1); // start of block + dwBlockSize *= 2; // block size in nibbles + _ASSERT(d+dwBlockSize <= dwRomSize); // address valid? + EraseBlock(d << 1,dwBlockSize); // erase 128K nibble + } + } + else + { + // improper command sequence + WSMset.byStatusReg |= (ECLBS | BWSLBS); + } + WSMset.byStatusReg |= WSMS; // block erased + WSMset.uWrState = WRS_DATA; + return; +} + +// full chip erase initial command +static VOID WrState30(DWORD d) +{ + WSMset.byStatusReg &= ~WSMS; // state machine busy + WSMset.uWrState = WRS_CHIP_ERASE; + WSMset.uRdState = RDS_SR; + return; + UNREFERENCED_PARAMETER(d); +} + +// full chip erase confirm +static VOID WrState30C(BYTE a, DWORD d) +{ + if (CONFIRM == a) // chip erase confirm? + { + UINT i; + + WORD wNoOfBlocks = (byQueryTab[0x2E] << 8) | byQueryTab[0x2D]; + DWORD dwBlockSize = ((byQueryTab[0x30] << 8) | byQueryTab[0x2F]) * 256; + + DWORD dwBlockAddr = 0; + + dwBlockSize *= 2; // block size in nibbles + + for (i = 0; i <= wNoOfBlocks; ++i) // check all blocks + { + _ASSERT((i+1)*dwBlockSize <= dwRomSize); + + // lock bit of block is set & WP# = low, locked blocks cannot be erased + if ((WSMset.dwLockCnfg & (1<>16)); // set block lock bit + else + WSMset.byStatusReg |= (BWSLBS | DPS); // device protect detect, WP# = low + break; + case CONFIRM: // clear block lock bits + if (bWP) // WP# = high, can change block lock status + { + WORD wNoOfBlocks = (byQueryTab[0x2E] << 8) | byQueryTab[0x2D]; + + for (i = 0; i <= wNoOfBlocks; ++i) // clear all lock bits + { + WSMset.dwLockCnfg &= ~(1 << i); // clear block lock bit + } + } + else + { + WSMset.byStatusReg |= (ECLBS | DPS); // device protect detect, WP# = low + } + break; + default: // improper command sequence + WSMset.byStatusReg |= (ECLBS | BWSLBS); + } + WSMset.byStatusReg |= WSMS; // block lock-bit changed + WSMset.uWrState = WRS_DATA; + return; +} + + +// +// read state functions +// + +// read array +static BYTE RdStateData(DWORD d) +{ + return ReadByte(d << 1); // get byte +} + +// read identifier codes +static BYTE RdStateId(DWORD d) +{ + BYTE byData; + + d >>= 1; // A0 is not connected, ignore it + if ((d & 0x03) != 0x02) // id code request + { + d &= 0x03; // data repetition + byData = byQueryTab[d]; // get data from first 4 bytes id/query table + } + else // block lock table + { + // get data from block lock table + byData = (BYTE) ((WSMset.dwLockCnfg >> (d >> 15)) & 1); + + d &= 0x1F; // data repetition + if (d >= 4) byData |= 0x02; // set bit 1 on wrong ID adress + } + return byData; +} + +// read query +static BYTE RdStateQuery(DWORD d) +{ + BYTE byData; + + d >>= 1; // A0 is not connected, ignore it + if ((d & 0x7F) != 0x02) // query request + { + d &= 0x7F; // data repetition + + // get data from id/query table + byData = (d >= 0x40 && d < 0x50) ? 0 : byQueryTab[d&0x3F]; + } + else // block lock table + { + // get data from block lock table + byData = (BYTE) ((WSMset.dwLockCnfg >> (d >> 15)) & 1); + } + return byData; +} + +// read status register +static BYTE RdStateSR(DWORD d) +{ + return WSMset.byStatusReg; + UNREFERENCED_PARAMETER(d); +} + +// read extended status register +static BYTE RdStateXSR(DWORD d) +{ + return WSMset.byExStatusReg; + UNREFERENCED_PARAMETER(d); +} + + +// +// public functions +// + +VOID FlashInit(VOID) +{ + // check if locking bit table has more or equal than 32 bit + _ASSERT(sizeof(WSMset.dwLockCnfg) * 8 >= 32); + + ZeroMemory(&WSMset,sizeof(WSMset)); + strcpy((LPSTR) WSMset.byType,"WSM"); // Write State Machine header + WSMset.uSize = sizeof(WSMset); // size of this structure + WSMset.byVersion = WSMVER; // version of flash implementation structure + + // factory setting of locking bits + WSMset.dwLockCnfg = (1 << 0); // first 64KB block is locked + + WSMset.uWrState = WRS_DATA; + WSMset.uRdState = RDS_DATA; + + // data mode of ROM + WSMset.bRomArray = bFlashRomArray = TRUE; + return; +} + +VOID FlashRead(BYTE *a, DWORD d, UINT s) +{ + BYTE v; + + while (s) // each nibble + { + // output muliplexer + _ASSERT(WSMset.uRdState < ARRAYSIZEOF(fnRdState)); + v = fnRdState[WSMset.uRdState](d>>1); + + if ((d & 1) == 0) // even address + { + *a++ = v & 0xf; ++d; --s; + } + if (s && (d & 1)) // odd address + { + *a++ = v >> 4; ++d; --s; + } + } + return; +} + +VOID FlashWrite(BYTE *a, DWORD d, UINT s) +{ + BYTE v; + DWORD p; + + while (s) // each nibble + { + p = d >> 1; // byte address + if (s > 1 && (d & 1) == 0) // more than one byte on even address + { + v = *a++; // LSB + v |= *a++ << 4; // MSB + d += 2; s -= 2; + } + else + { + // get byte from output muliplexer + _ASSERT(WSMset.uRdState < ARRAYSIZEOF(fnRdState)); + v = fnRdState[WSMset.uRdState](p); + + if (d & 1) // odd address + v = (v & 0x0F) | (*a << 4); // replace MSB + else // even address + v = (v & 0xF0) | *a; // replace LSB + ++a; ++d; --s; + } + + _ASSERT(WSMset.uWrState < ARRAYSIZEOF(fnWrState)); + fnWrState[WSMset.uWrState](v,p); // WSM + } + return; +} diff --git a/Sources/Emu48/i28f160.h b/Sources/Emu48/I28F160.H similarity index 97% rename from Sources/Emu48/i28f160.h rename to Sources/Emu48/I28F160.H index 365d255..a164678 100644 --- a/Sources/Emu48/i28f160.h +++ b/Sources/Emu48/I28F160.H @@ -1,40 +1,40 @@ -/* - * i28f160.h - * - * This file is part of Emu48 - * - * Copyright (C) 2000 Christoph Gießelink - * - */ - -#define WSMVER 0 // version of flash implementation structure - -#define WSMSET WSMset_t -typedef struct -{ - BYTE byType[4]; // "WSM" - UINT uSize; // size of this structure - BYTE byVersion; // WSM version - - BOOL bRomArray; // copy of bFlashRomArray - DWORD dwLockCnfg; // block lock table (32 entries) - UINT uWrState; // state of write function WSM - UINT uRdState; // state of read function WSM - BYTE byStatusReg; // status register - BYTE byExStatusReg; // extended status register - BYTE byWrite1No; // no. of written data in write buffer1 - BYTE byWrite1Size; // no. of valid data in write buffer1 - DWORD dwWrite1Addr; // destination address of buffer1 - BYTE pbyWrite1[32]; // write buffer1 -// BYTE byWrite2No; // no. of written data in write buffer2 -// BYTE byWrite2Size; // no. of valid data in write buffer2 -// DWORD dwWrite2Addr; // destination address of buffer2 -// BYTE pbyWrite2[32]; // write buffer2 -} WSMset_t; - -// i28f160.h -extern WSMSET WSMset; -extern BOOL bWP; -extern VOID FlashInit(VOID); -extern VOID FlashRead(BYTE *a, DWORD d, UINT s); -extern VOID FlashWrite(BYTE *a, DWORD d, UINT s); +/* + * i28f160.h + * + * This file is part of Emu48 + * + * Copyright (C) 2000 Christoph Gießelink + * + */ + +#define WSMVER 0 // version of flash implementation structure + +#define WSMSET WSMset_t +typedef struct +{ + BYTE byType[4]; // "WSM" + UINT uSize; // size of this structure + BYTE byVersion; // WSM version + + BOOL bRomArray; // copy of bFlashRomArray + DWORD dwLockCnfg; // block lock table (32 entries) + UINT uWrState; // state of write function WSM + UINT uRdState; // state of read function WSM + BYTE byStatusReg; // status register + BYTE byExStatusReg; // extended status register + BYTE byWrite1No; // no. of written data in write buffer1 + BYTE byWrite1Size; // no. of valid data in write buffer1 + DWORD dwWrite1Addr; // destination address of buffer1 + BYTE pbyWrite1[32]; // write buffer1 +// BYTE byWrite2No; // no. of written data in write buffer2 +// BYTE byWrite2Size; // no. of valid data in write buffer2 +// DWORD dwWrite2Addr; // destination address of buffer2 +// BYTE pbyWrite2[32]; // write buffer2 +} WSMset_t; + +// i28f160.h +extern WSMSET WSMset; +extern BOOL bWP; +extern VOID FlashInit(VOID); +extern VOID FlashRead(BYTE *a, DWORD d, UINT s); +extern VOID FlashWrite(BYTE *a, DWORD d, UINT s); diff --git a/Sources/Emu48/io.h b/Sources/Emu48/IO.H similarity index 97% rename from Sources/Emu48/io.h rename to Sources/Emu48/IO.H index 04f7ab7..b5a4bda 100644 --- a/Sources/Emu48/io.h +++ b/Sources/Emu48/IO.H @@ -1,154 +1,154 @@ -/* - * io.h - * - * This file is part of Emu48 - * - * Copyright (C) 1999 Christoph Gießelink - * - */ - -// I/O addresses without mapping offset -#define BITOFFSET 0x00 // Display bit offset and DON -#define CRC 0x04 // Crc (16 bit, LSB first) -#define LPD 0x08 // Low Power Detection -#define LPE 0x09 // Low Power detection Enable -#define ANNCTRL 0x0b // Annunciator Control (2 nibble) -#define BAUD 0x0d // Baudrate (Bit 2-0) -#define CARDCTL 0x0e // card control -#define CARDSTAT 0x0f // card status -#define IOC 0x10 // IO CONTROL -#define RCS 0x11 // RCS -#define TCS 0x12 // TCS -#define CRER 0x13 // CRER -#define RBR_LSB 0x14 // RBR low nibble -#define RBR_MSB 0x15 // RBR high nibble -#define TBR_LSB 0x16 // TBR low nibble -#define TBR_MSB 0x17 // TBR high nibble -#define SRQ1 0x18 // SRQ1 -#define SRQ2 0x19 // SRQ2 -#define IR_CTRL 0x1a // IR CONTROL -#define LCR 0x1c // Led Control Register -#define LBR 0x1d // Led Buffer Register -#define DISP1CTL 0x20 // Display Start Address -#define LINENIBS 0x25 // Display Line Offset -#define LINECOUNT 0x28 // Display Line Counter -#define TIMER1_CTRL 0x2e // Timer1 Control -#define TIMER2_CTRL 0x2f // Timer2 Control -#define DISP2CTL 0x30 // Display Secondary Start Address -#define TIMER1 0x37 // Timer1 (4 bit) -#define TIMER2 0x38 // Timer2 (32 bit, LSB first) - -// 0x00 Display bit offset and DON [DON OFF2 OFF1 OFF0] -#define DON 0x08 // Display On -#define OFF2 0x04 // Display OFFset Bit2 -#define OFF1 0x02 // Display OFFset Bit1 -#define OFF0 0x01 // Display OFFset Bit0 - -// 0x08 Low Power Detection [LB2 LB1 LB0 VLBI] -#define LB2 0x08 // Low Battery indicator memory port 2 -#define LB1 0x04 // Low Battery indicator memory port 1 -#define LB0 0x02 // Low Battery indicator system battery -#define VLBI 0x01 // Very Low Battery Indicator - -// 0x09 Low Power detection Enable [ELBI EVLBI GRAM RST] -#define ELBI 0x08 // Enable Low Battery Indicator -#define EVLBI 0x04 // Enable Very Low Battery Indicator -#define GRAM 0x02 // Glitch sensitive RAM -#define RST 0x01 // ReSeT - -// 0x0b Annunciator Control [AON XTRA LA6 LA5] [LA4 LA3 LA2 LA1] -#define AON 0x80 // Annunciators on -#define LXTRA 0x40 // does nothing -#define LA6 0x20 // LA6 - Transmitting -#define LA5 0x10 // LA5 - Busy -#define LA4 0x08 // LA4 - Alert -#define LA3 0x04 // LA3 - Alpha -#define LA2 0x02 // LA2 - ALT Shift -#define LA1 0x01 // LA1 - Shift - -// 0x0d SERIAL Baud Rate [UCK BD2 BD1 BD0] -#define UCK 0x08 // Uart ClocK -#define BD2 0x04 // BauDrate Bit2 -#define BD1 0x02 // BauDrate Bit1 -#define BD0 0x01 // BauDrate Bit0 - -// 0x0e Card Control [ECDT RCDT SMP SWINT] -#define ECDT 0x08 // Enable Card Detect -#define RCDT 0x04 // Run Card Detect -#define SMP 0x02 // Set module pulled -#define SWINT 0x01 // Software Interrupt - -// 0x0f Card Status [P2W P1W P2C P1C] -#define P2W 0x08 // High when Port2 writeable -#define P1W 0x04 // High when Port1 writeable -#define P2C 0x02 // High when Card in Port2 inserted -#define P1C 0x01 // High when Card in Port1 inserted - -// 0x10 Serial I/O Control [SON ETBE ERBF ERBZ] -#define SON 0x08 // Serial on -#define ETBE 0x04 // Interrupt on transmit buffer empty -#define ERBF 0x02 // Interrupt on receive buffer full -#define ERBZ 0x01 // Interrupt on receiver busy - -// 0x11 Serial Receive Control/Status [RX RER RBZ RBF] -#define RX 0x08 // Rx pin state (read-only) -#define RER 0x04 // Receiver error -#define RBZ 0x02 // Receiver busy -#define RBF 0x01 // Receive buffer full - -// 0x12 Serial Transmit Control/Status [BRK LPB TBZ TBF] -#define BRK 0x08 // Break -#define LPB 0x04 // Loopback -#define TBZ 0x02 // Transmitter busy -#define TBF 0x01 // Transmit buffer full - -// 0x18 Service Request Register 1 [ISRQ TSRQ USRQ VSRQ] -#define ISRQ 0x08 // IR receiver pulls NINT2 -#define TSRQ 0x04 // Timer pulls NINT2 -#define USRQ 0x02 // UART pulls NINT2 -#define VSRQ 0x01 // VLBI pulls NINT2 - -// 0x19 Service Request Register 2 [KDN NINT2 NINT LSRQ] -#define KDN 0x08 // Bit set when ON Key or Key Interrupt -#define NINT2 0x04 // State of NINT2 -#define NINT 0x02 // State of NINT -#define LSRQ 0x01 // LED driver pulls NINT2 - -// 0x1a IR Control Register [IRI EIRU EIRI IRE] -#define IRI 0x08 // IR input (read-only) -#define EIRU 0x04 // Enable IR UART mode -#define EIRI 0x02 // Enable IR interrupt -#define IRE 0x01 // IR event - -// 0x1c Led Control Register [LED ELBE LBZ LBF] -#define LED 0x08 // Turn on LED -#define ELBE 0x04 // Enable Interrupt on Led Buffer empty -#define LBZ 0x02 // Led Port Busy -#define LBF 0x01 // Led Buffer Full - -// 0x1d Led Buffer Register [0 0 0 LBO] (bits 1-3 read zero) -#define LBO 0x01 - -// 0x28 Display Line Counter LSB [LC3 LC2 LC1 LC0] -#define LC3 0x08 // LC3 - Line Counter Bit3 -#define LC2 0x04 // LC2 - Line Counter Bit2 -#define LC1 0x02 // LC1 - Line Counter Bit1 -#define LC0 0x01 // LC0 - Line Counter Bit0 - -// 0x29 Display Line Counter MSB [DA19 M32 LC5 LC4] -#define DA19 0x08 // Drive A[19] -#define M32 0x04 // Multiplex 32 way -#define LC5 0x02 // LC5 - Line Counter Bit5 -#define LC4 0x01 // LC4 - Line Counter Bit4 - -// 0x2e Timer1 Control [SRQ WKE INT XTRA] -#define SRQ 0x08 // Service request -#define WKE 0x04 // Wake up -#define INTR 0x02 // Interrupt -#define XTRA 0x01 // Extra function - -// 0x2f Timer2 Control [SRQ WKE INT RUN] -#define SRQ 0x08 // Service request -#define WKE 0x04 // Wake up -#define INTR 0x02 // Interrupt -#define RUN 0x01 // Timer run +/* + * io.h + * + * This file is part of Emu48 + * + * Copyright (C) 1999 Christoph Gießelink + * + */ + +// I/O addresses without mapping offset +#define BITOFFSET 0x00 // Display bit offset and DON +#define CRC 0x04 // Crc (16 bit, LSB first) +#define LPD 0x08 // Low Power Detection +#define LPE 0x09 // Low Power detection Enable +#define ANNCTRL 0x0b // Annunciator Control (2 nibble) +#define BAUD 0x0d // Baudrate (Bit 2-0) +#define CARDCTL 0x0e // card control +#define CARDSTAT 0x0f // card status +#define IOC 0x10 // IO CONTROL +#define RCS 0x11 // RCS +#define TCS 0x12 // TCS +#define CRER 0x13 // CRER +#define RBR_LSB 0x14 // RBR low nibble +#define RBR_MSB 0x15 // RBR high nibble +#define TBR_LSB 0x16 // TBR low nibble +#define TBR_MSB 0x17 // TBR high nibble +#define SRQ1 0x18 // SRQ1 +#define SRQ2 0x19 // SRQ2 +#define IR_CTRL 0x1a // IR CONTROL +#define LCR 0x1c // Led Control Register +#define LBR 0x1d // Led Buffer Register +#define DISP1CTL 0x20 // Display Start Address +#define LINENIBS 0x25 // Display Line Offset +#define LINECOUNT 0x28 // Display Line Counter +#define TIMER1_CTRL 0x2e // Timer1 Control +#define TIMER2_CTRL 0x2f // Timer2 Control +#define DISP2CTL 0x30 // Display Secondary Start Address +#define TIMER1 0x37 // Timer1 (4 bit) +#define TIMER2 0x38 // Timer2 (32 bit, LSB first) + +// 0x00 Display bit offset and DON [DON OFF2 OFF1 OFF0] +#define DON 0x08 // Display On +#define OFF2 0x04 // Display OFFset Bit2 +#define OFF1 0x02 // Display OFFset Bit1 +#define OFF0 0x01 // Display OFFset Bit0 + +// 0x08 Low Power Detection [LB2 LB1 LB0 VLBI] +#define LB2 0x08 // Low Battery indicator memory port 2 +#define LB1 0x04 // Low Battery indicator memory port 1 +#define LB0 0x02 // Low Battery indicator system battery +#define VLBI 0x01 // Very Low Battery Indicator + +// 0x09 Low Power detection Enable [ELBI EVLBI GRAM RST] +#define ELBI 0x08 // Enable Low Battery Indicator +#define EVLBI 0x04 // Enable Very Low Battery Indicator +#define GRAM 0x02 // Glitch sensitive RAM +#define RST 0x01 // ReSeT + +// 0x0b Annunciator Control [AON XTRA LA6 LA5] [LA4 LA3 LA2 LA1] +#define AON 0x80 // Annunciators on +#define LXTRA 0x40 // does nothing +#define LA6 0x20 // LA6 - Transmitting +#define LA5 0x10 // LA5 - Busy +#define LA4 0x08 // LA4 - Alert +#define LA3 0x04 // LA3 - Alpha +#define LA2 0x02 // LA2 - ALT Shift +#define LA1 0x01 // LA1 - Shift + +// 0x0d SERIAL Baud Rate [UCK BD2 BD1 BD0] +#define UCK 0x08 // Uart ClocK +#define BD2 0x04 // BauDrate Bit2 +#define BD1 0x02 // BauDrate Bit1 +#define BD0 0x01 // BauDrate Bit0 + +// 0x0e Card Control [ECDT RCDT SMP SWINT] +#define ECDT 0x08 // Enable Card Detect +#define RCDT 0x04 // Run Card Detect +#define SMP 0x02 // Set module pulled +#define SWINT 0x01 // Software Interrupt + +// 0x0f Card Status [P2W P1W P2C P1C] +#define P2W 0x08 // High when Port2 writeable +#define P1W 0x04 // High when Port1 writeable +#define P2C 0x02 // High when Card in Port2 inserted +#define P1C 0x01 // High when Card in Port1 inserted + +// 0x10 Serial I/O Control [SON ETBE ERBF ERBZ] +#define SON 0x08 // Serial on +#define ETBE 0x04 // Interrupt on transmit buffer empty +#define ERBF 0x02 // Interrupt on receive buffer full +#define ERBZ 0x01 // Interrupt on receiver busy + +// 0x11 Serial Receive Control/Status [RX RER RBZ RBF] +#define RX 0x08 // Rx pin state (read-only) +#define RER 0x04 // Receiver error +#define RBZ 0x02 // Receiver busy +#define RBF 0x01 // Receive buffer full + +// 0x12 Serial Transmit Control/Status [BRK LPB TBZ TBF] +#define BRK 0x08 // Break +#define LPB 0x04 // Loopback +#define TBZ 0x02 // Transmitter busy +#define TBF 0x01 // Transmit buffer full + +// 0x18 Service Request Register 1 [ISRQ TSRQ USRQ VSRQ] +#define ISRQ 0x08 // IR receiver pulls NINT2 +#define TSRQ 0x04 // Timer pulls NINT2 +#define USRQ 0x02 // UART pulls NINT2 +#define VSRQ 0x01 // VLBI pulls NINT2 + +// 0x19 Service Request Register 2 [KDN NINT2 NINT LSRQ] +#define KDN 0x08 // Bit set when ON Key or Key Interrupt +#define NINT2 0x04 // State of NINT2 +#define NINT 0x02 // State of NINT +#define LSRQ 0x01 // LED driver pulls NINT2 + +// 0x1a IR Control Register [IRI EIRU EIRI IRE] +#define IRI 0x08 // IR input (read-only) +#define EIRU 0x04 // Enable IR UART mode +#define EIRI 0x02 // Enable IR interrupt +#define IRE 0x01 // IR event + +// 0x1c Led Control Register [LED ELBE LBZ LBF] +#define LED 0x08 // Turn on LED +#define ELBE 0x04 // Enable Interrupt on Led Buffer empty +#define LBZ 0x02 // Led Port Busy +#define LBF 0x01 // Led Buffer Full + +// 0x1d Led Buffer Register [0 0 0 LBO] (bits 1-3 read zero) +#define LBO 0x01 + +// 0x28 Display Line Counter LSB [LC3 LC2 LC1 LC0] +#define LC3 0x08 // LC3 - Line Counter Bit3 +#define LC2 0x04 // LC2 - Line Counter Bit2 +#define LC1 0x02 // LC1 - Line Counter Bit1 +#define LC0 0x01 // LC0 - Line Counter Bit0 + +// 0x29 Display Line Counter MSB [DA19 M32 LC5 LC4] +#define DA19 0x08 // Drive A[19] +#define M32 0x04 // Multiplex 32 way +#define LC5 0x02 // LC5 - Line Counter Bit5 +#define LC4 0x01 // LC4 - Line Counter Bit4 + +// 0x2e Timer1 Control [SRQ WKE INT XTRA] +#define SRQ 0x08 // Service request +#define WKE 0x04 // Wake up +#define INTR 0x02 // Interrupt +#define XTRA 0x01 // Extra function + +// 0x2f Timer2 Control [SRQ WKE INT RUN] +#define SRQ 0x08 // Service request +#define WKE 0x04 // Wake up +#define INTR 0x02 // Interrupt +#define RUN 0x01 // Timer run diff --git a/Sources/Emu48/keyboard.c b/Sources/Emu48/KEYBOARD.C similarity index 96% rename from Sources/Emu48/keyboard.c rename to Sources/Emu48/KEYBOARD.C index f2ee824..9072982 100644 --- a/Sources/Emu48/keyboard.c +++ b/Sources/Emu48/KEYBOARD.C @@ -1,131 +1,131 @@ -/* - * keyboard.c - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ -#include "pch.h" -#include "emu48.h" -#include "io.h" // I/O definitions - -DWORD dwKeyMinDelay = 50; // minimum time for key hold - -static WORD Keyboard_GetIR(VOID) -{ - WORD r = 0; - - // OR[0:8] are wired on Clarke/Yorke chip - if (Chipset.out==0) return 0; - if (Chipset.out&0x001) r|=Chipset.Keyboard_Row[0]; - if (Chipset.out&0x002) r|=Chipset.Keyboard_Row[1]; - if (Chipset.out&0x004) r|=Chipset.Keyboard_Row[2]; - if (Chipset.out&0x008) r|=Chipset.Keyboard_Row[3]; - if (Chipset.out&0x010) r|=Chipset.Keyboard_Row[4]; - if (Chipset.out&0x020) r|=Chipset.Keyboard_Row[5]; - if (Chipset.out&0x040) r|=Chipset.Keyboard_Row[6]; - if (Chipset.out&0x080) r|=Chipset.Keyboard_Row[7]; - if (Chipset.out&0x100) r|=Chipset.Keyboard_Row[8]; - return r; -} - -VOID ScanKeyboard(BOOL bActive, BOOL bReset) -{ - // bActive = TRUE -> function called by direct read (A=IN, C=IN, RSI) - // FALSE -> function called by 1ms keyboard poll simulation - // bReset = TRUE -> Reset Chipset.in interrupt state register - // FALSE -> generate interrupt only for new pressed keys - - // keyboard read not active? - if (!( bActive || Chipset.Shutdn || Chipset.IR15X - || (Chipset.intk && (Chipset.IORam[TIMER2_CTRL]&RUN) != 0))) - { - EnterCriticalSection(&csKeyLock); - { - Chipset.in &= ~0x8000; // remove ON key - } - LeaveCriticalSection(&csKeyLock); - return; - } - - EnterCriticalSection(&csKeyLock); // synchronize - { - BOOL bKbdInt; - - WORD wOldIn = Chipset.in; // save old Chipset.in state - - UpdateKdnBit(); // update KDN bit - Chipset.dwKdnCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF); - - Chipset.in = Keyboard_GetIR(); // update Chipset.in register - Chipset.in |= Chipset.IR15X; // add ON key - - // interrupt for any new pressed keys? - bKbdInt = (Chipset.in && (wOldIn & 0x1FF) == 0) || Chipset.IR15X || bReset; - - // update keyboard interrupt pending flag when 1ms keyboard scan is disabled - Chipset.intd = Chipset.intd || (bKbdInt && !Chipset.intk); - - // keyboard interrupt enabled? - bKbdInt = bKbdInt && Chipset.intk; - - // interrupt at ON key pressed - bKbdInt = bKbdInt || Chipset.IR15X != 0; - - // no interrupt if still inside interrupt service routine - bKbdInt = bKbdInt && Chipset.inte; - - if (Chipset.in != 0) // any key pressed - { - if (bKbdInt) // interrupt enabled - { - Chipset.SoftInt = TRUE; // interrupt request - bInterrupt = TRUE; // exit emulation loop - } - - if (Chipset.Shutdn) // cpu sleeping - { - Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode - SetEvent(hEventShutdn); // wake up emulation thread - } - } - else - { - Chipset.intd = FALSE; // no keyboard interrupt pending - } - } - LeaveCriticalSection(&csKeyLock); - - return; -} - -VOID KeyboardEvent(BOOL bPress, UINT out, UINT in) -{ - if (nState != SM_RUN) // not in running state - return; // ignore key - - KeyMacroRecord(bPress,out,in); // save all keyboard events - - if (in == 0x8000) // ON key ? - { - Chipset.IR15X = bPress?0x8000:0x0000; // refresh special ON key flag - } - else - { - // "out" is outside Keyboard_Row - if (out >= ARRAYSIZEOF(Chipset.Keyboard_Row)) return; - - // in &= 0x1FF; // only IR[0:8] are wired on Clarke/Yorke chip - - _ASSERT(out < ARRAYSIZEOF(Chipset.Keyboard_Row)); - if (bPress) // key pressed - Chipset.Keyboard_Row[out] |= in; // set key marker in keyboard row - else - Chipset.Keyboard_Row[out] &= (~in); // clear key marker in keyboard row - } - AdjKeySpeed(); // adjust key repeat speed - ScanKeyboard(FALSE,FALSE); // update Chipset.in register by 1ms keyboard poll - Sleep(dwKeyMinDelay); // hold key state for a definite time - return; -} +/* + * keyboard.c + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ +#include "pch.h" +#include "Emu48.h" +#include "io.h" // I/O definitions + +DWORD dwKeyMinDelay = 50; // minimum time for key hold + +static WORD Keyboard_GetIR(VOID) +{ + WORD r = 0; + + // OR[0:8] are wired on Clarke/Yorke chip + if (Chipset.out==0) return 0; + if (Chipset.out&0x001) r|=Chipset.Keyboard_Row[0]; + if (Chipset.out&0x002) r|=Chipset.Keyboard_Row[1]; + if (Chipset.out&0x004) r|=Chipset.Keyboard_Row[2]; + if (Chipset.out&0x008) r|=Chipset.Keyboard_Row[3]; + if (Chipset.out&0x010) r|=Chipset.Keyboard_Row[4]; + if (Chipset.out&0x020) r|=Chipset.Keyboard_Row[5]; + if (Chipset.out&0x040) r|=Chipset.Keyboard_Row[6]; + if (Chipset.out&0x080) r|=Chipset.Keyboard_Row[7]; + if (Chipset.out&0x100) r|=Chipset.Keyboard_Row[8]; + return r; +} + +VOID ScanKeyboard(BOOL bActive, BOOL bReset) +{ + // bActive = TRUE -> function called by direct read (A=IN, C=IN, RSI) + // FALSE -> function called by 1ms keyboard poll simulation + // bReset = TRUE -> Reset Chipset.in interrupt state register + // FALSE -> generate interrupt only for new pressed keys + + // keyboard read not active? + if (!( bActive || Chipset.Shutdn || Chipset.IR15X + || (Chipset.intk && (Chipset.IORam[TIMER2_CTRL]&RUN) != 0))) + { + EnterCriticalSection(&csKeyLock); + { + Chipset.in &= ~0x8000; // remove ON key + } + LeaveCriticalSection(&csKeyLock); + return; + } + + EnterCriticalSection(&csKeyLock); // synchronize + { + BOOL bKbdInt; + + WORD wOldIn = Chipset.in; // save old Chipset.in state + + UpdateKdnBit(); // update KDN bit + Chipset.dwKdnCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF); + + Chipset.in = Keyboard_GetIR(); // update Chipset.in register + Chipset.in |= Chipset.IR15X; // add ON key + + // interrupt for any new pressed keys? + bKbdInt = (Chipset.in && (wOldIn & 0x1FF) == 0) || Chipset.IR15X || bReset; + + // update keyboard interrupt pending flag when 1ms keyboard scan is disabled + Chipset.intd = Chipset.intd || (bKbdInt && !Chipset.intk); + + // keyboard interrupt enabled? + bKbdInt = bKbdInt && Chipset.intk; + + // interrupt at ON key pressed + bKbdInt = bKbdInt || Chipset.IR15X != 0; + + // no interrupt if still inside interrupt service routine + bKbdInt = bKbdInt && Chipset.inte; + + if (Chipset.in != 0) // any key pressed + { + if (bKbdInt) // interrupt enabled + { + Chipset.SoftInt = TRUE; // interrupt request + bInterrupt = TRUE; // exit emulation loop + } + + if (Chipset.Shutdn) // cpu sleeping + { + Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode + SetEvent(hEventShutdn); // wake up emulation thread + } + } + else + { + Chipset.intd = FALSE; // no keyboard interrupt pending + } + } + LeaveCriticalSection(&csKeyLock); + + return; +} + +VOID KeyboardEvent(BOOL bPress, UINT out, UINT in) +{ + if (nState != SM_RUN) // not in running state + return; // ignore key + + KeyMacroRecord(bPress,out,in); // save all keyboard events + + if (in == 0x8000) // ON key ? + { + Chipset.IR15X = bPress?0x8000:0x0000; // refresh special ON key flag + } + else + { + // "out" is outside Keyboard_Row + if (out >= ARRAYSIZEOF(Chipset.Keyboard_Row)) return; + + // in &= 0x1FF; // only IR[0:8] are wired on Clarke/Yorke chip + + _ASSERT(out < ARRAYSIZEOF(Chipset.Keyboard_Row)); + if (bPress) // key pressed + Chipset.Keyboard_Row[out] |= in; // set key marker in keyboard row + else + Chipset.Keyboard_Row[out] &= (~in); // clear key marker in keyboard row + } + AdjKeySpeed(); // adjust key repeat speed + ScanKeyboard(FALSE,FALSE); // update Chipset.in register by 1ms keyboard poll + Sleep(dwKeyMinDelay); // hold key state for a definite time + return; +} diff --git a/Sources/Emu48/keymacro.c b/Sources/Emu48/KEYMACRO.C similarity index 95% rename from Sources/Emu48/keymacro.c rename to Sources/Emu48/KEYMACRO.C index bba6ec8..9d4d930 100644 --- a/Sources/Emu48/keymacro.c +++ b/Sources/Emu48/KEYMACRO.C @@ -1,337 +1,337 @@ -/* - * Keymacro.c - * - * This file is part of Emu48 - * - * Copyright (C) 2004 Christoph Gießelink - * - */ -#include "pch.h" -#include "resource.h" -#include "emu48.h" -#include "kml.h" - -#define KEYMACROHEAD "Emu-KeyMacro" // macro signature - -#define MIN_SPEED 0 -#define MAX_SPEED 500 - -typedef struct -{ - DWORD dwTime; // elapsed time - DWORD dwKeyEvent; // key code -} KeyData; - -INT nMacroState = MACRO_OFF; -INT nMacroTimeout = MIN_SPEED; -BOOL bMacroRealSpeed = TRUE; -DWORD dwMacroMinDelay = 0; // minimum macro play key hold time in ms - -static DWORD dwTimeRef; - -static HANDLE hMacroFile = INVALID_HANDLE_VALUE; -static HANDLE hEventPlay = NULL; -static HANDLE hThreadEv = NULL; - -static VOID InitializeOFN(LPOPENFILENAME ofn) -{ - ZeroMemory((LPVOID)ofn, sizeof(OPENFILENAME)); - ofn->lStructSize = sizeof(OPENFILENAME); - ofn->hwndOwner = hWnd; - ofn->Flags = OFN_EXPLORER|OFN_HIDEREADONLY; - return; -} - -// -// thread playing keys -// -static DWORD WINAPI EventThread(LPVOID pParam) -{ - DWORD dwRead = 0; - DWORD dwData = 0,dwTime = 0; - - while (WaitForSingleObject(hEventPlay,dwTime) == WAIT_TIMEOUT) - { - if (dwRead != 0) // data read - { - UINT nIn = (dwData >> 0) & 0xFFFF; - UINT nOut = (dwData >> 16) & 0xFF; - BOOL bPress = (dwData >> 24) & 0xFF; - - PlayKey(nOut,nIn,bPress); - } - - dwTime = nMacroTimeout; // set default speed - - while (TRUE) - { - // read next data element - if ( !ReadFile(hMacroFile,&dwData,sizeof(dwData),&dwRead,NULL) - || dwRead != sizeof(dwData)) - { - // play record empty -> quit - PostMessage(hWnd,WM_COMMAND,ID_TOOL_MACRO_STOP,0); - return 0; // exit on file end - } - - if ((dwData & 0x80000000) != 0) // time information - { - if (bMacroRealSpeed) // realspeed from data - { - dwTime = dwData & 0x7FFFFFFF; - } - continue; - } - - // hold the key state the minimum macro play key hold time - if (dwTime < dwMacroMinDelay) dwTime = dwMacroMinDelay; - - dwTime -= dwKeyMinDelay; // remove the actual key hold time - // set negative number to zero - if ((dwTime & 0x80000000) != 0) dwTime = 0; - break; // got key information - } - } - return 0; // exit on stop - UNREFERENCED_PARAMETER(pParam); -} - -// -// callback function for recording keys -// -VOID KeyMacroRecord(BOOL bPress, UINT out, UINT in) -{ - if (nMacroState == MACRO_NEW) // save key event - { - KeyData Data; - DWORD dwWritten; - - dwWritten = GetTickCount(); // time reference - Data.dwTime = (dwWritten - dwTimeRef); - Data.dwTime |= 0x80000000; // set time marker - dwTimeRef = dwWritten; - - Data.dwKeyEvent = (bPress & 0xFF); - Data.dwKeyEvent = (Data.dwKeyEvent << 8) | (out & 0xFF); - Data.dwKeyEvent = (Data.dwKeyEvent << 16) | (in & 0xFFFF); - - // save key event in file - WriteFile(hMacroFile,&Data,sizeof(Data),&dwWritten,NULL); - _ASSERT(dwWritten == sizeof(Data)); - } - return; -} - -// -// message handler for save new keyboard macro -// -LRESULT OnToolMacroNew(VOID) -{ - TCHAR szMacroFile[MAX_PATH]; - OPENFILENAME ofn; - DWORD dwExtensionLength,dwWritten; - - // get filename for saving - InitializeOFN(&ofn); - ofn.lpstrFilter = - _T("Keyboard Macro Files (*.MAC)\0*.MAC\0") - _T("All Files (*.*)\0*.*\0"); - ofn.lpstrDefExt = _T("MAC"); - ofn.nFilterIndex = 1; - ofn.lpstrFile = szMacroFile; - ofn.lpstrFile[0] = 0; - ofn.nMaxFile = ARRAYSIZEOF(szMacroFile); - ofn.Flags |= OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT; - if (GetSaveFileName(&ofn) == FALSE) return 0; - - // open file for writing - hMacroFile = CreateFile(szMacroFile, - GENERIC_READ|GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (hMacroFile == INVALID_HANDLE_VALUE) return 0; - - // write header - WriteFile(hMacroFile,KEYMACROHEAD,sizeof(KEYMACROHEAD) - 1,&dwWritten,NULL); - _ASSERT(dwWritten == (DWORD) strlen(KEYMACROHEAD)); - - // write extension length - dwExtensionLength = 0; // no extension - WriteFile(hMacroFile,&dwExtensionLength,sizeof(dwExtensionLength),&dwWritten,NULL); - _ASSERT(dwWritten == sizeof(dwExtensionLength)); - - nMacroState = MACRO_NEW; - - MessageBox(hWnd, - _T("Press OK to begin to record the Macro."), - _T("Macro Recorder"), - MB_OK|MB_ICONINFORMATION); - - dwTimeRef = GetTickCount(); // time reference - return 0; -} - -// -// message handler for play keyboard macro -// -LRESULT OnToolMacroPlay(VOID) -{ - BYTE byHeader[sizeof(KEYMACROHEAD)-1]; - TCHAR szMacroFile[MAX_PATH]; - OPENFILENAME ofn; - DWORD dwExtensionLength,dwRead,dwThreadId; - - InitializeOFN(&ofn); - ofn.lpstrFilter = - _T("Keyboard Macro Files (*.MAC)\0*.MAC\0") - _T("All Files (*.*)\0*.*\0"); - ofn.lpstrDefExt = _T("MAC"); - ofn.nFilterIndex = 1; - ofn.lpstrFile = szMacroFile; - ofn.lpstrFile[0] = 0; - ofn.nMaxFile = ARRAYSIZEOF(szMacroFile); - ofn.Flags |= OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST; - if (GetOpenFileName(&ofn) == FALSE) return 0; - - // open file for Reading - hMacroFile = CreateFile(szMacroFile, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (hMacroFile == INVALID_HANDLE_VALUE) return 0; - - // read header - ReadFile(hMacroFile,byHeader,sizeof(byHeader),&dwRead,NULL); - if ( dwRead != sizeof(byHeader) - || memcmp(byHeader,KEYMACROHEAD,dwRead) != 0) - { - MessageBox(hWnd, - _T("Wrong keyboard macro file format."), - _T("Macro Recorder"), - MB_OK|MB_ICONSTOP); - CloseHandle(hMacroFile); - return 0; - } - - // read extension length - ReadFile(hMacroFile,&dwExtensionLength,sizeof(dwExtensionLength),&dwRead,NULL); - if (dwRead != sizeof(dwExtensionLength)) - { - CloseHandle(hMacroFile); - return 0; - } - - // read extension - while (dwExtensionLength-- > 0) - { - BYTE byData; - - ReadFile(hMacroFile,&byData,sizeof(byData),&dwRead,NULL); - if (dwRead != sizeof(byData)) - { - CloseHandle(hMacroFile); - return 0; - } - } - - // event for quit playing - hEventPlay = CreateEvent(NULL,FALSE,FALSE,NULL); - - nMacroState = MACRO_PLAY; - - // start playing thread - VERIFY(hThreadEv = CreateThread(NULL,0,&EventThread,NULL,0,&dwThreadId)); - return 0; -} - -// -// message handler for stop recording/playing -// -LRESULT OnToolMacroStop(VOID) -{ - if (nMacroState != MACRO_OFF) - { - if (hEventPlay) // playing keys - { - // stop playing thread - SetEvent(hEventPlay); // quit play loop - - WaitForSingleObject(hThreadEv,INFINITE); - CloseHandle(hThreadEv); - hThreadEv = NULL; - - CloseHandle(hEventPlay); // close playing keys event - hEventPlay = NULL; - } - - // macro file open - if (hMacroFile != INVALID_HANDLE_VALUE) CloseHandle(hMacroFile); - - nMacroState = MACRO_OFF; - } - return 0; -} - -// -// activate/deactivate slider -// -static VOID SliderEnable(HWND hDlg,BOOL bEnable) -{ - EnableWindow(GetDlgItem(hDlg,IDC_MACRO_SLOW),bEnable); - EnableWindow(GetDlgItem(hDlg,IDC_MACRO_FAST),bEnable); - EnableWindow(GetDlgItem(hDlg,IDC_MACRO_SLIDER),bEnable); - return; -} - -// -// Macro settings dialog -// -static INT_PTR CALLBACK MacroProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_INITDIALOG: - // set slider - SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_SETRANGE,FALSE,MAKELONG(0,MAX_SPEED-MIN_SPEED)); - SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_SETTICFREQ,MAX_SPEED/10,0); - SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_SETPOS,TRUE,MAX_SPEED-nMacroTimeout); - - // set button - CheckDlgButton(hDlg,bMacroRealSpeed ? IDC_MACRO_REAL : IDC_MACRO_MANUAL,BST_CHECKED); - SliderEnable(hDlg,!bMacroRealSpeed); - return TRUE; - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDC_MACRO_REAL: - SliderEnable(hDlg,FALSE); - return TRUE; - case IDC_MACRO_MANUAL: - SliderEnable(hDlg,TRUE); - return TRUE; - case IDOK: - // get macro data - nMacroTimeout = MAX_SPEED - (INT) SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_GETPOS,0,0); - bMacroRealSpeed = IsDlgButtonChecked(hDlg,IDC_MACRO_REAL); - // no break - case IDCANCEL: - EndDialog(hDlg, LOWORD(wParam)); - } - break; - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -LRESULT OnToolMacroSettings(VOID) -{ - if (DialogBox(hApp, MAKEINTRESOURCE(IDD_MACROSET), hWnd, (DLGPROC)MacroProc) == -1) - AbortMessage(_T("Macro Dialog Box Creation Error !")); - return 0; -} +/* + * Keymacro.c + * + * This file is part of Emu48 + * + * Copyright (C) 2004 Christoph Gießelink + * + */ +#include "pch.h" +#include "resource.h" +#include "Emu48.h" +#include "kml.h" + +#define KEYMACROHEAD "Emu-KeyMacro" // macro signature + +#define MIN_SPEED 0 +#define MAX_SPEED 500 + +typedef struct +{ + DWORD dwTime; // elapsed time + DWORD dwKeyEvent; // key code +} KeyData; + +INT nMacroState = MACRO_OFF; +INT nMacroTimeout = MIN_SPEED; +BOOL bMacroRealSpeed = TRUE; +DWORD dwMacroMinDelay = 0; // minimum macro play key hold time in ms + +static DWORD dwTimeRef; + +static HANDLE hMacroFile = INVALID_HANDLE_VALUE; +static HANDLE hEventPlay = NULL; +static HANDLE hThreadEv = NULL; + +static VOID InitializeOFN(LPOPENFILENAME ofn) +{ + ZeroMemory((LPVOID)ofn, sizeof(OPENFILENAME)); + ofn->lStructSize = sizeof(OPENFILENAME); + ofn->hwndOwner = hWnd; + ofn->Flags = OFN_EXPLORER|OFN_HIDEREADONLY; + return; +} + +// +// thread playing keys +// +static DWORD WINAPI EventThread(LPVOID pParam) +{ + DWORD dwRead = 0; + DWORD dwData = 0,dwTime = 0; + + while (WaitForSingleObject(hEventPlay,dwTime) == WAIT_TIMEOUT) + { + if (dwRead != 0) // data read + { + UINT nIn = (dwData >> 0) & 0xFFFF; + UINT nOut = (dwData >> 16) & 0xFF; + BOOL bPress = (dwData >> 24) & 0xFF; + + PlayKey(nOut,nIn,bPress); + } + + dwTime = nMacroTimeout; // set default speed + + while (TRUE) + { + // read next data element + if ( !ReadFile(hMacroFile,&dwData,sizeof(dwData),&dwRead,NULL) + || dwRead != sizeof(dwData)) + { + // play record empty -> quit + PostMessage(hWnd,WM_COMMAND,ID_TOOL_MACRO_STOP,0); + return 0; // exit on file end + } + + if ((dwData & 0x80000000) != 0) // time information + { + if (bMacroRealSpeed) // realspeed from data + { + dwTime = dwData & 0x7FFFFFFF; + } + continue; + } + + // hold the key state the minimum macro play key hold time + if (dwTime < dwMacroMinDelay) dwTime = dwMacroMinDelay; + + dwTime -= dwKeyMinDelay; // remove the actual key hold time + // set negative number to zero + if ((dwTime & 0x80000000) != 0) dwTime = 0; + break; // got key information + } + } + return 0; // exit on stop + UNREFERENCED_PARAMETER(pParam); +} + +// +// callback function for recording keys +// +VOID KeyMacroRecord(BOOL bPress, UINT out, UINT in) +{ + if (nMacroState == MACRO_NEW) // save key event + { + KeyData Data; + DWORD dwWritten; + + dwWritten = GetTickCount(); // time reference + Data.dwTime = (dwWritten - dwTimeRef); + Data.dwTime |= 0x80000000; // set time marker + dwTimeRef = dwWritten; + + Data.dwKeyEvent = (bPress & 0xFF); + Data.dwKeyEvent = (Data.dwKeyEvent << 8) | (out & 0xFF); + Data.dwKeyEvent = (Data.dwKeyEvent << 16) | (in & 0xFFFF); + + // save key event in file + WriteFile(hMacroFile,&Data,sizeof(Data),&dwWritten,NULL); + _ASSERT(dwWritten == sizeof(Data)); + } + return; +} + +// +// message handler for save new keyboard macro +// +LRESULT OnToolMacroNew(VOID) +{ + TCHAR szMacroFile[MAX_PATH]; + OPENFILENAME ofn; + DWORD dwExtensionLength,dwWritten; + + // get filename for saving + InitializeOFN(&ofn); + ofn.lpstrFilter = + _T("Keyboard Macro Files (*.MAC)\0*.MAC\0") + _T("All Files (*.*)\0*.*\0"); + ofn.lpstrDefExt = _T("MAC"); + ofn.nFilterIndex = 1; + ofn.lpstrFile = szMacroFile; + ofn.lpstrFile[0] = 0; + ofn.nMaxFile = ARRAYSIZEOF(szMacroFile); + ofn.Flags |= OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT; + if (GetSaveFileName(&ofn) == FALSE) return 0; + + // open file for writing + hMacroFile = CreateFile(szMacroFile, + GENERIC_READ|GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hMacroFile == INVALID_HANDLE_VALUE) return 0; + + // write header + WriteFile(hMacroFile,KEYMACROHEAD,sizeof(KEYMACROHEAD) - 1,&dwWritten,NULL); + _ASSERT(dwWritten == (DWORD) strlen(KEYMACROHEAD)); + + // write extension length + dwExtensionLength = 0; // no extension + WriteFile(hMacroFile,&dwExtensionLength,sizeof(dwExtensionLength),&dwWritten,NULL); + _ASSERT(dwWritten == sizeof(dwExtensionLength)); + + nMacroState = MACRO_NEW; + + MessageBox(hWnd, + _T("Press OK to begin to record the Macro."), + _T("Macro Recorder"), + MB_OK|MB_ICONINFORMATION); + + dwTimeRef = GetTickCount(); // time reference + return 0; +} + +// +// message handler for play keyboard macro +// +LRESULT OnToolMacroPlay(VOID) +{ + BYTE byHeader[sizeof(KEYMACROHEAD)-1]; + TCHAR szMacroFile[MAX_PATH]; + OPENFILENAME ofn; + DWORD dwExtensionLength,dwRead,dwThreadId; + + InitializeOFN(&ofn); + ofn.lpstrFilter = + _T("Keyboard Macro Files (*.MAC)\0*.MAC\0") + _T("All Files (*.*)\0*.*\0"); + ofn.lpstrDefExt = _T("MAC"); + ofn.nFilterIndex = 1; + ofn.lpstrFile = szMacroFile; + ofn.lpstrFile[0] = 0; + ofn.nMaxFile = ARRAYSIZEOF(szMacroFile); + ofn.Flags |= OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST; + if (GetOpenFileName(&ofn) == FALSE) return 0; + + // open file for Reading + hMacroFile = CreateFile(szMacroFile, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hMacroFile == INVALID_HANDLE_VALUE) return 0; + + // read header + ReadFile(hMacroFile,byHeader,sizeof(byHeader),&dwRead,NULL); + if ( dwRead != sizeof(byHeader) + || memcmp(byHeader,KEYMACROHEAD,dwRead) != 0) + { + MessageBox(hWnd, + _T("Wrong keyboard macro file format."), + _T("Macro Recorder"), + MB_OK|MB_ICONSTOP); + CloseHandle(hMacroFile); + return 0; + } + + // read extension length + ReadFile(hMacroFile,&dwExtensionLength,sizeof(dwExtensionLength),&dwRead,NULL); + if (dwRead != sizeof(dwExtensionLength)) + { + CloseHandle(hMacroFile); + return 0; + } + + // read extension + while (dwExtensionLength-- > 0) + { + BYTE byData; + + ReadFile(hMacroFile,&byData,sizeof(byData),&dwRead,NULL); + if (dwRead != sizeof(byData)) + { + CloseHandle(hMacroFile); + return 0; + } + } + + // event for quit playing + hEventPlay = CreateEvent(NULL,FALSE,FALSE,NULL); + + nMacroState = MACRO_PLAY; + + // start playing thread + VERIFY(hThreadEv = CreateThread(NULL,0,&EventThread,NULL,0,&dwThreadId)); + return 0; +} + +// +// message handler for stop recording/playing +// +LRESULT OnToolMacroStop(VOID) +{ + if (nMacroState != MACRO_OFF) + { + if (hEventPlay) // playing keys + { + // stop playing thread + SetEvent(hEventPlay); // quit play loop + + WaitForSingleObject(hThreadEv,INFINITE); + CloseHandle(hThreadEv); + hThreadEv = NULL; + + CloseHandle(hEventPlay); // close playing keys event + hEventPlay = NULL; + } + + // macro file open + if (hMacroFile != INVALID_HANDLE_VALUE) CloseHandle(hMacroFile); + + nMacroState = MACRO_OFF; + } + return 0; +} + +// +// activate/deactivate slider +// +static VOID SliderEnable(HWND hDlg,BOOL bEnable) +{ + EnableWindow(GetDlgItem(hDlg,IDC_MACRO_SLOW),bEnable); + EnableWindow(GetDlgItem(hDlg,IDC_MACRO_FAST),bEnable); + EnableWindow(GetDlgItem(hDlg,IDC_MACRO_SLIDER),bEnable); + return; +} + +// +// Macro settings dialog +// +static INT_PTR CALLBACK MacroProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + // set slider + SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_SETRANGE,FALSE,MAKELONG(0,MAX_SPEED-MIN_SPEED)); + SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_SETTICFREQ,MAX_SPEED/10,0); + SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_SETPOS,TRUE,MAX_SPEED-nMacroTimeout); + + // set button + CheckDlgButton(hDlg,bMacroRealSpeed ? IDC_MACRO_REAL : IDC_MACRO_MANUAL,BST_CHECKED); + SliderEnable(hDlg,!bMacroRealSpeed); + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_MACRO_REAL: + SliderEnable(hDlg,FALSE); + return TRUE; + case IDC_MACRO_MANUAL: + SliderEnable(hDlg,TRUE); + return TRUE; + case IDOK: + // get macro data + nMacroTimeout = MAX_SPEED - (INT) SendDlgItemMessage(hDlg,IDC_MACRO_SLIDER,TBM_GETPOS,0,0); + bMacroRealSpeed = IsDlgButtonChecked(hDlg,IDC_MACRO_REAL); + // no break + case IDCANCEL: + EndDialog(hDlg, LOWORD(wParam)); + } + break; + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +LRESULT OnToolMacroSettings(VOID) +{ + if (DialogBox(hApp, MAKEINTRESOURCE(IDD_MACROSET), hWnd, (DLGPROC)MacroProc) == -1) + AbortMessage(_T("Macro Dialog Box Creation Error !")); + return 0; +} diff --git a/Sources/Emu48/kml.c b/Sources/Emu48/KML.C similarity index 95% rename from Sources/Emu48/kml.c rename to Sources/Emu48/KML.C index f5edce8..80b5d1a 100644 --- a/Sources/Emu48/kml.c +++ b/Sources/Emu48/KML.C @@ -1,2704 +1,2704 @@ -/* - * kml.c - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ -#include "pch.h" -#include "resource.h" -#include "emu48.h" -#include "kml.h" - -static VOID InitLex(LPCTSTR szScript); -static VOID CleanLex(VOID); -static VOID SkipWhite(UINT nMode); -static TokenId ParseToken(UINT nMode); -static DWORD ParseInteger(VOID); -static LPTSTR ParseString(VOID); -static TokenId Lex(UINT nMode); -static KmlLine* ParseLine(TokenId eCommand); -static KmlLine* IncludeLines(BOOL bInclude, LPCTSTR szFilename); -static KmlLine* ParseLines(BOOL bInclude); -static KmlBlock* ParseBlock(BOOL bInclude, TokenId eBlock); -static KmlBlock* IncludeBlocks(BOOL bInclude, LPCTSTR szFilename); -static KmlBlock* ParseBlocks(BOOL bInclude, BOOL bEndTokenEn); -static VOID FreeLines(KmlLine* pLine); -static VOID PressButton(UINT nId); -static VOID ReleaseButton(UINT nId); -static VOID PressButtonById(UINT nId); -static VOID ReleaseButtonById(UINT nId); -static LPCTSTR GetStringParam(KmlBlock* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam); -static DWORD GetIntegerParam(KmlBlock* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam); -static KmlLine* SkipLines(KmlLine* pLine, TokenId eCommand); -static KmlLine* If(KmlLine* pLine, BOOL bCondition); -static KmlLine* RunLine(KmlLine* pLine); -static KmlBlock* LoadKMLGlobal(LPCTSTR szFilename); - -KmlBlock* pKml = NULL; -static KmlBlock* pVKey[256]; -static BYTE byVKeyMap[256]; -static KmlButton pButton[256]; -static KmlAnnunciator pAnnunciator[6]; -static UINT nButtons = 0; -static UINT nScancodes = 0; -static UINT nAnnunciators = 0; -static BOOL bDebug = TRUE; -static WORD wKeybLocId = 0; -static BOOL bLocaleInc = FALSE; // no locale block content included -static UINT nLexLine; -static UINT nLexInteger; -static UINT nBlocksIncludeLevel; -static UINT nLinesIncludeLevel; -static DWORD nKMLFlags = 0; -static LPTSTR szLexString; -static LPCTSTR szText; -static LPCTSTR szLexDelim[] = -{ - _T(" \t\n\r"), // valid whitespaces for LEX_BLOCK - _T(" \t\n\r"), // valid whitespaces for LEX_COMMAND - _T(" \t\r") // valid whitespaces for LEX_PARAM -}; - -static CONST KmlToken pLexToken[] = -{ - {TOK_ANNUNCIATOR,000001,11,_T("Annunciator")}, - {TOK_BACKGROUND, 000000,10,_T("Background")}, - {TOK_IFPRESSED, 000001, 9,_T("IfPressed")}, - {TOK_RESETFLAG, 000001, 9,_T("ResetFlag")}, - {TOK_SCANCODE, 000001, 8,_T("Scancode")}, - {TOK_HARDWARE, 000002, 8,_T("Hardware")}, - {TOK_MENUITEM, 000001, 8,_T("MenuItem")}, - {TOK_SYSITEM, 000001, 7,_T("SysItem")}, - {TOK_SETFLAG, 000001, 7,_T("SetFlag")}, - {TOK_RELEASE, 000001, 7,_T("Release")}, - {TOK_VIRTUAL, 000000, 7,_T("Virtual")}, - {TOK_INCLUDE, 000002, 7,_T("Include")}, - {TOK_NOTFLAG, 000001, 7,_T("NotFlag")}, - {TOK_MENUBAR, 000001, 7,_T("Menubar")}, // for PPC compatibility reasons - {TOK_GLOBAL, 000000, 6,_T("Global")}, - {TOK_AUTHOR, 000002, 6,_T("Author")}, - {TOK_BITMAP, 000002, 6,_T("Bitmap")}, - {TOK_OFFSET, 000011, 6,_T("Offset")}, - {TOK_ZOOMXY, 000011, 6,_T("Zoomxy")}, - {TOK_BUTTON, 000001, 6,_T("Button")}, - {TOK_IFFLAG, 000001, 6,_T("IfFlag")}, - {TOK_ONDOWN, 000000, 6,_T("OnDown")}, - {TOK_NOHOLD, 000000, 6,_T("NoHold")}, - {TOK_LOCALE, 000001, 6,_T("Locale")}, - {TOK_TOPBAR, 000001, 6,_T("Topbar")}, // for PPC compatibility reasons - {TOK_TITLE, 000002, 5,_T("Title")}, - {TOK_OUTIN, 000011, 5,_T("OutIn")}, - {TOK_PATCH, 000002, 5,_T("Patch")}, - {TOK_PRINT, 000002, 5,_T("Print")}, - {TOK_DEBUG, 000001, 5,_T("Debug")}, - {TOK_COLOR, 001111, 5,_T("Color")}, - {TOK_MODEL, 000002, 5,_T("Model")}, - {TOK_CLASS, 000001, 5,_T("Class")}, - {TOK_PRESS, 000001, 5,_T("Press")}, - {TOK_IFMEM, 000111, 5,_T("IfMem")}, - {TOK_SCALE, 000011, 5,_T("Scale")}, - {TOK_TYPE, 000001, 4,_T("Type")}, - {TOK_SIZE, 000011, 4,_T("Size")}, - {TOK_ZOOM, 000001, 4,_T("Zoom")}, - {TOK_DOWN, 000011, 4,_T("Down")}, - {TOK_ELSE, 000000, 4,_T("Else")}, - {TOK_ONUP, 000000, 4,_T("OnUp")}, - {TOK_ICON, 000002, 4,_T("Icon")}, - {TOK_MAP, 000011, 3,_T("Map")}, - {TOK_ROM, 000002, 3,_T("Rom")}, - {TOK_VGA, 000001, 3,_T("Vga")}, // for PPC compatibility reasons - {TOK_LCD, 000000, 3,_T("Lcd")}, - {TOK_END, 000000, 3,_T("End")}, - {TOK_NONE, 000000, 0,_T("")} -}; - -static CONST TokenId eIsGlobalBlock[] = -{ - TOK_GLOBAL, - TOK_BACKGROUND, - TOK_LCD, - TOK_ANNUNCIATOR, - TOK_BUTTON, - TOK_SCANCODE, - TOK_LOCALE -}; - -static CONST TokenId eIsBlock[] = -{ - TOK_IFFLAG, - TOK_IFPRESSED, - TOK_IFMEM, - TOK_ONDOWN, - TOK_ONUP -}; - -static BOOL bClicking = FALSE; -static UINT uButtonClicked = 0; - -static BOOL bKeyPressed = FALSE; // no key pressed -static UINT uLastKeyPressed = 0; // var for last pressed key - -static INT nScaleMul = 0; // no scaling -static INT nScaleDiv = 0; - -//################ -//# -//# Compilation Result -//# -//################ - -static UINT nLogLength = 0; -static LPTSTR szLog = NULL; - -static VOID ClearLog() -{ - nLogLength = 0; - if (szLog != NULL) - { - free(szLog); - szLog = NULL; - } - return; -} - -static VOID AddToLog(LPCTSTR szString) -{ - LPTSTR szLogTmp; - - UINT nLength = lstrlen(szString) + 2; // CR+LF - if (szLog == NULL) // no log - { - nLogLength = 1; // room for \0 - } - - szLogTmp = (LPTSTR) realloc(szLog,(nLogLength+nLength)*sizeof(szLog[0])); - if (szLogTmp == NULL) - { - ClearLog(); - return; - } - szLog = szLogTmp; - lstrcpy(&szLog[nLogLength-1],szString); - nLogLength += nLength; - szLog[nLogLength-3] = _T('\r'); - szLog[nLogLength-2] = _T('\n'); - szLog[nLogLength-1] = 0; - return; -} - -static VOID __cdecl PrintfToLog(LPCTSTR lpFormat, ...) -{ - TCHAR cOutput[1024]; - va_list arglist; - - va_start(arglist,lpFormat); - wvsprintf(cOutput,lpFormat,arglist); - AddToLog(cOutput); - va_end(arglist); - return; -} - -static INT_PTR CALLBACK KMLLogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - LPCTSTR szString; - - switch (message) - { - case WM_INITDIALOG: - // set OK - EnableWindow(GetDlgItem(hDlg,IDOK),(BOOL) lParam); - // set IDC_TITLE - szString = GetStringParam(pKml, TOK_GLOBAL, TOK_TITLE, 0); - if (szString == NULL) szString = _T("Untitled"); - SetDlgItemText(hDlg,IDC_TITLE,szString); - // set IDC_AUTHOR - szString = GetStringParam(pKml, TOK_GLOBAL, TOK_AUTHOR, 0); - if (szString == NULL) szString = _T(""); - SetDlgItemText(hDlg,IDC_AUTHOR,szString); - // set IDC_KMLLOG - szString = szLog; - if (szString == NULL) szString = _T("Memory Allocation Failure."); - SetDlgItemText(hDlg,IDC_KMLLOG,szString); - // set IDC_ALWAYSDISPLOG - CheckDlgButton(hDlg,IDC_ALWAYSDISPLOG,bAlwaysDisplayLog); - return TRUE; - case WM_COMMAND: - wParam = LOWORD(wParam); - if ((wParam==IDOK)||(wParam==IDCANCEL)) - { - bAlwaysDisplayLog = IsDlgButtonChecked(hDlg, IDC_ALWAYSDISPLOG); - EndDialog(hDlg, wParam); - return TRUE; - } - break; - } - return FALSE; -} - -BOOL DisplayKMLLog(BOOL bOkEnabled) -{ - return IDOK == DialogBoxParam(hApp, - MAKEINTRESOURCE(IDD_KMLLOG), - hWnd, - (DLGPROC)KMLLogProc, - bOkEnabled); -} - - - -//################ -//# -//# Choose Script -//# -//################ - -typedef struct _KmlScript -{ - LPTSTR szFilename; - LPTSTR szTitle; - DWORD nId; - struct _KmlScript* pNext; -} KmlScript; - -static KmlScript* pKmlList = NULL; -static CHAR cKmlType; - -static VOID DestroyKmlList(VOID) -{ - while (pKmlList) - { - KmlScript* pList = pKmlList->pNext; - free(pKmlList->szFilename); - free(pKmlList->szTitle); - free(pKmlList); - pKmlList = pList; - } - return; -} - -static VOID CreateKmlList(VOID) -{ - HANDLE hFindFile; - WIN32_FIND_DATA pFindFileData; - UINT nKmlFiles; - - _ASSERT(pKmlList == NULL); // KML file list must be empty - SetCurrentDirectory(szEmuDirectory); - hFindFile = FindFirstFile(_T("*.KML"),&pFindFileData); - SetCurrentDirectory(szCurrentDirectory); - if (hFindFile == INVALID_HANDLE_VALUE) return; - nKmlFiles = 0; - do - { - KmlScript* pScript; - KmlBlock* pBlock; - LPCTSTR szTitle; - BOOL bInvalidPlatform; - - pBlock = LoadKMLGlobal(pFindFileData.cFileName); - if (pBlock == NULL) continue; - // check for correct KML script platform - szTitle = GetStringParam(pBlock,TOK_GLOBAL,TOK_HARDWARE,0); - bInvalidPlatform = (szTitle && lstrcmpi(_T(HARDWARE),szTitle) != 0); - // check for supported Model - szTitle = GetStringParam(pBlock,TOK_GLOBAL,TOK_MODEL,0); - // skip all scripts with invalid platform and invalid or different Model statement - if ( bInvalidPlatform - || (szTitle == NULL) - || (cKmlType && szTitle[0] != cKmlType) - || !isModelValid(szTitle[0])) - { - FreeBlocks(pBlock); - continue; - } - pScript = (KmlScript*) malloc(sizeof(KmlScript)); - if (pScript) // script node allocated - { - pScript->szFilename = DuplicateString(pFindFileData.cFileName); - szTitle = GetStringParam(pBlock,TOK_GLOBAL,TOK_TITLE,0); - if (szTitle == NULL) szTitle = pScript->szFilename; - pScript->szTitle = DuplicateString(szTitle); - if (pScript->szFilename == NULL || pScript->szTitle == NULL) - { - free(pScript->szFilename); - free(pScript->szTitle); - free(pScript); - FreeBlocks(pBlock); - continue; - } - pScript->nId = nKmlFiles; - pScript->pNext = pKmlList; - pKmlList = pScript; - nKmlFiles++; - } - FreeBlocks(pBlock); - } while (FindNextFile(hFindFile,&pFindFileData)); - FindClose(hFindFile); - return; -}; - -static INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) -{ - TCHAR szDir[MAX_PATH]; - - switch(uMsg) - { - case BFFM_INITIALIZED: - SendMessage(hwnd,BFFM_SETSELECTION,TRUE,pData); - break; - case BFFM_SELCHANGED: - // Set the status window to the currently selected path. - if (SHGetPathFromIDList((LPITEMIDLIST) lp,szDir)) - { - SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM) szDir); - } - break; - } - return 0; -} - -static VOID BrowseFolder(HWND hDlg) -{ - TCHAR szDir[MAX_PATH]; - BROWSEINFO bi; - LPITEMIDLIST pidl; - LPMALLOC pMalloc; - - // gets the shell's default allocator - if (SUCCEEDED(SHGetMalloc(&pMalloc))) - { - GetDlgItemText(hDlg,IDC_EMUDIR,szDir,ARRAYSIZEOF(szDir)); - - ZeroMemory(&bi,sizeof(bi)); - bi.hwndOwner = hDlg; - bi.pidlRoot = NULL; - bi.pszDisplayName = NULL; - bi.lpszTitle = _T("Choose a folder:"); - bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT; - bi.lpfn = BrowseCallbackProc; - bi.lParam = (LPARAM) szDir; // current setting - - pidl = SHBrowseForFolder(&bi); - if (pidl) - { - if (SHGetPathFromIDList(pidl,szDir)) - { - SetDlgItemText(hDlg,IDC_EMUDIR,szDir); - } - // free the PIDL allocated by SHBrowseForFolder - #if defined __cplusplus - pMalloc->Free(pidl); - #else - pMalloc->lpVtbl->Free(pMalloc,pidl); - #endif - } - // release the shell's allocator - #if defined __cplusplus - pMalloc->Release(); - #else - pMalloc->lpVtbl->Release(pMalloc); - #endif - } - return; -} - -static VOID UpdateScriptList(HWND hDlg) -{ - HWND hList; - KmlScript* pList; - UINT nIndex,nEntries; - DWORD dwActId = (DWORD) CB_ERR; - - // add all script titles to combo box - hList = GetDlgItem(hDlg,IDC_KMLSCRIPT); - SendMessage(hList, CB_RESETCONTENT, 0, 0); - for (nEntries = 0, pList = pKmlList; pList; pList = pList->pNext) - { - nIndex = (UINT) SendMessage(hList, CB_ADDSTRING, 0, (LPARAM)pList->szTitle); - SendMessage(hList, CB_SETITEMDATA, nIndex, (LPARAM) pList->nId); - - // this has the same filename like the actual KML script - if (lstrcmpi(szCurrentKml, pList->szFilename) == 0) - dwActId = pList->nId; - - nEntries++; - } - - while (--nEntries > 0) // scan all combo box items - { - // found ID of actual KML script - if ((DWORD) SendMessage(hList, CB_GETITEMDATA, nEntries, 0) == dwActId) - break; - } - SendMessage(hList, CB_SETCURSEL, nEntries, 0); - return; -} - -static INT_PTR CALLBACK ChooseKMLProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - HWND hList; - KmlScript* pList; - UINT nIndex; - - switch (message) - { - case WM_INITDIALOG: - SetDlgItemText(hDlg,IDC_EMUDIR,szEmuDirectory); - UpdateScriptList(hDlg); // update combo box with script titles - return TRUE; - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDC_EMUDIRSEL: - BrowseFolder(hDlg); // select new folder for IDC_EMUDIR - // fall into IDC_UPDATE to search for KML files in new folder - case IDC_UPDATE: - DestroyKmlList(); - GetDlgItemText(hDlg,IDC_EMUDIR,szEmuDirectory,ARRAYSIZEOF(szEmuDirectory)); - CreateKmlList(); - UpdateScriptList(hDlg); // update combo box with script titles - return TRUE; - case IDOK: - GetDlgItemText(hDlg,IDC_EMUDIR,szEmuDirectory,ARRAYSIZEOF(szEmuDirectory)); - hList = GetDlgItem(hDlg,IDC_KMLSCRIPT); - nIndex = (UINT) SendMessage(hList, CB_GETCURSEL, 0, 0); - nIndex = (UINT) SendMessage(hList, CB_GETITEMDATA, nIndex, 0); - for (pList = pKmlList; pList; pList = pList->pNext) - { - if (pList->nId == nIndex) - { - lstrcpy(szCurrentKml, pList->szFilename); - EndDialog(hDlg, IDOK); - break; - } - } - return TRUE; - case IDCANCEL: - EndDialog(hDlg, IDCANCEL); - return TRUE; - } - } - return FALSE; - UNREFERENCED_PARAMETER(lParam); -} - -BOOL DisplayChooseKml(CHAR cType) -{ - INT_PTR nResult; - cKmlType = cType; - CreateKmlList(); - nResult = DialogBox(hApp, MAKEINTRESOURCE(IDD_CHOOSEKML), hWnd, (DLGPROC)ChooseKMLProc); - DestroyKmlList(); - return (nResult == IDOK); -} - - - -//################ -//# -//# KML File Mapping -//# -//################ - -static LPTSTR MapKMLFile(HANDLE hFile) -{ - DWORD lBytesRead; - DWORD dwFileSizeLow; - DWORD dwFileSizeHigh; - LPTSTR lpBuf = NULL; - - dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); - if (dwFileSizeHigh != 0) - { - AddToLog(_T("File is too large.")); - goto fail; - } - - lpBuf = (LPTSTR) malloc((dwFileSizeLow+1)*sizeof(lpBuf[0])); - if (lpBuf == NULL) - { - PrintfToLog(_T("Cannot allocate %i bytes."), (dwFileSizeLow+1)*sizeof(lpBuf[0])); - goto fail; - } - #if defined _UNICODE - { - LPSTR szTmp = (LPSTR) malloc(dwFileSizeLow+1); - if (szTmp == NULL) - { - free(lpBuf); - lpBuf = NULL; - PrintfToLog(_T("Cannot allocate %i bytes."), dwFileSizeLow+1); - goto fail; - } - ReadFile(hFile, szTmp, dwFileSizeLow, &lBytesRead, NULL); - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTmp, lBytesRead, lpBuf, dwFileSizeLow+1); - free(szTmp); - } - #else - { - ReadFile(hFile, lpBuf, dwFileSizeLow, &lBytesRead, NULL); - } - #endif - lpBuf[dwFileSizeLow] = 0; - -fail: - CloseHandle(hFile); - return lpBuf; -} - - - -//################ -//# -//# Script Parsing -//# -//################ - -static VOID InitLex(LPCTSTR szScript) -{ - nLexLine = 1; - szText = szScript; - return; -} - -static VOID CleanLex(VOID) -{ - nLexLine = 0; - nLexInteger = 0; - szLexString = NULL; - szText = NULL; - return; -} - -static BOOL IsGlobalBlock(TokenId eId) -{ - UINT i; - - for (i = 0; i < ARRAYSIZEOF(eIsGlobalBlock); ++i) - { - if (eId == eIsGlobalBlock[i]) return TRUE; - } - return FALSE; -} - -static BOOL IsBlock(TokenId eId) -{ - UINT i; - - for (i = 0; i < ARRAYSIZEOF(eIsBlock); ++i) - { - if (eId == eIsBlock[i]) return TRUE; - } - return FALSE; -} - -static LPCTSTR GetStringOf(TokenId eId) -{ - UINT i; - - for (i = 0; pLexToken[i].nLen; ++i) - { - if (pLexToken[i].eId == eId) return pLexToken[i].szName; - } - return _T(""); -} - -static VOID SkipWhite(UINT nMode) -{ - LPCTSTR pcDelim; - - while (*szText) - { - // search for delimiter - if ((pcDelim = _tcschr(szLexDelim[nMode],*szText)) != NULL) - { - _ASSERT(*pcDelim != 0); // no EOS - if (*pcDelim == _T('\n')) nLexLine++; - szText++; - continue; - } - if (*szText == _T('#')) // start of remark - { - // skip until LF or EOS - do szText++; while (*szText != _T('\n') && *szText != 0); - if (nMode != LEX_PARAM) continue; - } - break; - } - return; -} - -static TokenId ParseToken(UINT nMode) -{ - UINT i,j; - - for (i = 0; szText[i]; i++) // search for delimeter - { - if (_tcschr(szLexDelim[nMode],szText[i]) != NULL) - break; - } - if (i == 0) return TOK_NONE; - - // token length longer or equal than current command - for (j = 0; pLexToken[j].nLen >= i; ++j) - { - if (pLexToken[j].nLen == i) // token length has command length - { - if (_tcsncmp(pLexToken[j].szName,szText,i) == 0) - { - szText += i; // remove command from text - return pLexToken[j].eId; // return token Id - } - } - } - if (bDebug) // token not found - { - // allocate target string memory with token length - LPTSTR szToken = (LPTSTR) malloc((i+1) * sizeof(szToken[0])); - lstrcpyn(szToken,szText,i+1); // copy token text and append EOS - PrintfToLog(_T("%i: Undefined token %s"),nLexLine,szToken); - free(szToken); - } - return TOK_NONE; -} - -static DWORD ParseInteger(VOID) -{ - DWORD nNum = 0; - while (_istdigit(*szText)) - { - nNum = nNum * 10 + ((*szText) - _T('0')); - szText++; - } - return nNum; -} - -static LPTSTR ParseString(VOID) -{ - LPTSTR lpszString = NULL; // no mem allocated - UINT nBlock = 0; - UINT nLength = 0; - - LPTSTR lpszAllocString; - - szText++; // skip leading '"' - - while (*szText != _T('"')) - { - if (nLength >= nBlock) // ran out of buffer space - { - nBlock += 256; - lpszAllocString = (LPTSTR) realloc(lpszString,nBlock * sizeof(lpszString[0])); - if (lpszAllocString) - { - lpszString = lpszAllocString; - } - else - { - free(lpszString); // cleanup allocation failture - return NULL; - } - } - - if (*szText == _T('\\')) // escape char - { - // skip a '\' escape char before a quotation to - // decode the \" sequence as a quotation mark inside text - switch (szText[1]) - { - case _T('\"'): - case _T('\\'): - ++szText; // skip escape char '\' - break; - } - } - - if (*szText == 0) // EOS found inside string - { - lpszString[nLength] = 0; // set EOS - PrintfToLog(_T("%i: Invalid string %s."), nLexLine, lpszString); - free(lpszString); - return NULL; - } - lpszString[nLength++] = *szText++; // save char - } - szText++; // skip ending '"' - - // release unnecessary allocated bytes or allocate byte for EOS - if ((lpszAllocString = (LPTSTR) realloc(lpszString,(nLength+1) * sizeof(lpszString[0])))) - { - lpszAllocString[nLength] = 0; // set EOS - } - else - { - free(lpszString); // cleanup allocation failture - } - return lpszAllocString; -} - -static TokenId Lex(UINT nMode) -{ - _ASSERT(nMode >= LEX_BLOCK && nMode <= LEX_PARAM); - _ASSERT(nMode >= 0 && nMode < ARRAYSIZEOF(szLexDelim)); - - SkipWhite(nMode); - if (_istdigit(*szText)) - { - nLexInteger = ParseInteger(); - return TOK_INTEGER; - } - if (*szText == _T('"')) - { - szLexString = ParseString(); - return TOK_STRING; - } - if (nMode == LEX_PARAM) - { - if (*szText == _T('\n')) // end of line - { - nLexLine++; // next line - szText++; // skip LF - return TOK_EOL; - } - if (*szText == 0) // end of file - { - return TOK_EOL; - } - } - return ParseToken(nMode); -} - -static KmlLine* ParseLine(TokenId eCommand) -{ - UINT i, j; - DWORD nParams; - TokenId eToken; - KmlLine* pLine; - - for (i = 0; pLexToken[i].nLen; ++i) - { - if (pLexToken[i].eId == eCommand) break; - } - if (pLexToken[i].nLen == 0) return NULL; - - if ((pLine = (KmlLine*) calloc(1,sizeof(KmlLine))) == NULL) - return NULL; - - pLine->eCommand = eCommand; - - for (j = 0, nParams = pLexToken[i].nParams; TRUE; nParams >>= 3) - { - // check for parameter overflow - _ASSERT(j < ARRAYSIZEOF(pLine->nParam)); - - eToken = Lex(LEX_PARAM); // decode argument token - if ((nParams & 7) == TYPE_NONE) - { - if (eToken != TOK_EOL) - { - PrintfToLog(_T("%i: Too many parameters for %s (%i expected)."), nLexLine, pLexToken[i].szName, j); - break; // free memory of arguments - } - return pLine; // normal exit -> parsed line - } - if ((nParams & 7) == TYPE_INTEGER) - { - if (eToken != TOK_INTEGER) - { - PrintfToLog(_T("%i: Parameter %i of %s must be an integer."), nLexLine, j+1, pLexToken[i].szName); - break; // free memory of arguments - } - pLine->nParam[j++] = nLexInteger; - continue; - } - if ((nParams & 7) == TYPE_STRING) - { - if (eToken != TOK_STRING) - { - PrintfToLog(_T("%i: Parameter %i of %s must be a string."), nLexLine, j+1, pLexToken[i].szName); - break; // free memory of arguments - } - pLine->nParam[j++] = (DWORD_PTR) szLexString; - szLexString = NULL; - continue; - } - _ASSERT(FALSE); // unknown parameter type - break; - } - - // if last argument was string, free it - if (eToken == TOK_STRING) - { - free(szLexString); - szLexString = NULL; - } - - nParams = pLexToken[i].nParams; // get argument types of command - for (i = 0; i < j; ++i) // handle all scanned arguments - { - if ((nParams & 7) == TYPE_STRING) // string type - { - free((LPVOID)pLine->nParam[i]); - } - nParams >>= 3; // next argument type - } - free(pLine); - return NULL; -} - -static KmlLine* IncludeLines(BOOL bInclude, LPCTSTR szFilename) -{ - HANDLE hFile; - LPTSTR lpbyBuf; - UINT uOldLine; - LPCTSTR szOldText; - KmlLine* pLine; - - SetCurrentDirectory(szEmuDirectory); - hFile = CreateFile(szFilename, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - SetCurrentDirectory(szCurrentDirectory); - if (hFile == INVALID_HANDLE_VALUE) - { - PrintfToLog(_T("Error while opening include file %s."), szFilename); - return NULL; - } - if ((lpbyBuf = MapKMLFile(hFile)) == NULL) - { - return NULL; - } - - uOldLine = nLexLine; - szOldText = szText; - - nLinesIncludeLevel++; - PrintfToLog(_T("l%i:%s %s"), - nLinesIncludeLevel, - (bInclude) ? _T("Including") : _T("Parsing"), - szFilename); - InitLex(lpbyBuf); - pLine = ParseLines(bInclude); - CleanLex(); - nLinesIncludeLevel--; - - nLexLine = uOldLine; - szText = szOldText; - free(lpbyBuf); - - return pLine; -} - -static KmlLine* ParseLines(BOOL bInclude) -{ - KmlLine* pFirst = NULL; - KmlLine* pLine = NULL; - TokenId eToken; - UINT nLevel = 0; - - while ((eToken = Lex(LEX_COMMAND)) != TOK_NONE) - { - if (IsGlobalBlock(eToken)) // check for block command - { - PrintfToLog(_T("%i: Invalid Command %s."), nLexLine, GetStringOf(eToken)); - goto abort; - } - if (IsBlock(eToken)) nLevel++; - if (eToken == TOK_INCLUDE) - { - LPTSTR szFilename; - UINT nLexLineKml; - - eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString' - if (eToken != TOK_STRING) // not a string (token don't begin with ") - { - PrintfToLog(_T("%i: Include: string expected as parameter."), nLexLine); - goto abort; - } - szFilename = szLexString; // save pointer to allocated memory - szLexString = NULL; - nLexLineKml = nLexLine; // save line number - eToken = Lex(LEX_PARAM); // decode argument - if (eToken != TOK_EOL) - { - free(szFilename); // free filename string - if (eToken == TOK_STRING) - { - free(szLexString); - szLexString = NULL; - } - PrintfToLog(_T("%i: Include: Too many parameters."), nLexLine); - goto abort; - } - if (pFirst) - { - pLine = pLine->pNext = IncludeLines(bInclude,szFilename); - } - else - { - pLine = pFirst = IncludeLines(bInclude,szFilename); - } - free(szFilename); // free filename string - if (pLine == NULL) // parsing error - { - nLexLine = nLexLineKml; // restore line number - goto abort; - } - while (pLine->pNext) pLine=pLine->pNext; - continue; - } - if (eToken == TOK_END) - { - if (nLevel) - { - nLevel--; - } - else - { - if (pFirst == NULL) // regular exit with empty block - { - // create an empty line - if ((pFirst = (KmlLine*) calloc(1,sizeof(KmlLine))) == NULL) - goto abort; - - pLine = pFirst; - pLine->eCommand = TOK_NONE; - } - if (pLine) pLine->pNext = NULL; - _ASSERT(szLexString == NULL); - return pFirst; - } - } - if (pFirst) - { - pLine = pLine->pNext = ParseLine(eToken); - } - else - { - pLine = pFirst = ParseLine(eToken); - } - if (pLine == NULL) // parsing error - goto abort; - } - if (nLinesIncludeLevel) - { - if (pLine) pLine->pNext = NULL; - _ASSERT(szLexString == NULL); - return pFirst; - } -abort: - if (pFirst) FreeLines(pFirst); - _ASSERT(szLexString == NULL); - return NULL; -} - -static KmlBlock* ParseBlock(BOOL bInclude, TokenId eType) -{ - UINT i; - KmlBlock* pBlock; - TokenId eToken; - - nLinesIncludeLevel = 0; - - if ((pBlock = (KmlBlock *) calloc(1,sizeof(KmlBlock))) == NULL) - return NULL; - - pBlock->eType = eType; - - for (i = 0; pLexToken[i].nLen; ++i) // search for token - { - if (pLexToken[i].eId == eType) break; - } - - if (pLexToken[i].nParams) // has block command arguments - { - // block command parser accept only one integer argument - _ASSERT(pLexToken[i].nParams == TYPE_INTEGER); - - eToken = Lex(LEX_PARAM); // decode argument - if (eToken != TOK_INTEGER) - { - if (eToken == TOK_STRING) - { - free(szLexString); - szLexString = NULL; - } - PrintfToLog(_T("%i: Block %s parameter must be an integer."), nLexLine, pLexToken[i].szName); - free(pBlock); - _ASSERT(szLexString == NULL); - return NULL; - } - - pBlock->nId = nLexInteger; // remember block no. - } - - eToken = Lex(LEX_PARAM); // decode argument - if (eToken != TOK_EOL) - { - if (eToken == TOK_STRING) - { - free(szLexString); - szLexString = NULL; - } - PrintfToLog(_T("%i: Too many parameters for block %s."), nLexLine, pLexToken[i].szName); - free(pBlock); - _ASSERT(szLexString == NULL); - return NULL; - } - - pBlock->pFirstLine = ParseLines(bInclude); - if (pBlock->pFirstLine == NULL) // break on ParseLines error - { - free(pBlock); - pBlock = NULL; - } - _ASSERT(szLexString == NULL); - return pBlock; -} - -static KmlBlock* IncludeBlocks(BOOL bInclude, LPCTSTR szFilename) -{ - HANDLE hFile; - LPTSTR lpbyBuf; - UINT uOldLine; - LPCTSTR szOldText; - KmlBlock* pFirst; - - SetCurrentDirectory(szEmuDirectory); - hFile = CreateFile(szFilename, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - SetCurrentDirectory(szCurrentDirectory); - if (hFile == INVALID_HANDLE_VALUE) - { - PrintfToLog(_T("Error while opening include file %s."), szFilename); - return NULL; - } - if ((lpbyBuf = MapKMLFile(hFile)) == NULL) - { - return NULL; - } - - uOldLine = nLexLine; - szOldText = szText; - - nBlocksIncludeLevel++; - PrintfToLog(_T("b%i:%s %s"), - nBlocksIncludeLevel, - (bInclude) ? _T("Including") : _T("Parsing"), - szFilename); - InitLex(lpbyBuf); - pFirst = ParseBlocks(bInclude, FALSE); - CleanLex(); - nBlocksIncludeLevel--; - - nLexLine = uOldLine; - szText = szOldText; - free(lpbyBuf); - - return pFirst; -} - -static KmlBlock* ParseBlocks(BOOL bInclude, BOOL bEndTokenEn) -{ - TokenId eToken; - KmlBlock* pFirst = NULL; - KmlBlock* pBlock = NULL; - - while ((eToken = Lex(LEX_BLOCK)) != TOK_NONE) - { - // allow TOK_END token only as end of a "Locale" block - if (bEndTokenEn && eToken == TOK_END) - { - return pFirst; - } - if (eToken == TOK_INCLUDE) - { - LPTSTR szFilename; - UINT nLexLineKml; - - eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString' - if (eToken != TOK_STRING) // not a string (token don't begin with ") - { - AddToLog(_T("Include: string expected as parameter.")); - goto abort; - } - szFilename = szLexString; // save pointer to allocated memory - szLexString = NULL; - nLexLineKml = nLexLine; // save line number - eToken = Lex(LEX_PARAM); // decode argument - if (eToken != TOK_EOL) - { - free(szFilename); // free filename string - PrintfToLog(_T("%i: Include: Too many parameters."), nLexLine); - goto abort; - } - if (pFirst) - pBlock = pBlock->pNext = IncludeBlocks(bInclude,szFilename); - else - pBlock = pFirst = IncludeBlocks(bInclude,szFilename); - free(szFilename); // free filename string - if (pBlock == NULL) // parsing error - { - nLexLine = nLexLineKml; // restore line number - goto abort; - } - while (pBlock->pNext) pBlock = pBlock->pNext; - continue; - } - if (eToken == TOK_LOCALE) - { - WORD wLocId,wKeybId; - KmlBlock* pData; - BOOL bIncludeId; - - eToken = Lex(LEX_PARAM); // get include parameter in 'nLexInteger' - if (eToken != TOK_INTEGER) - { - PrintfToLog(_T("%i: Locale parameter must be an integer."), nLexLine); - goto abort; - } - wLocId = nLexInteger; // requested keyboard locale id - eToken = Lex(LEX_PARAM); // decode argument - if (eToken != TOK_EOL) - { - PrintfToLog(_T("%i: Too many parameters for Locale."), nLexLine); - goto abort; - } - - wKeybId = wKeybLocId; // get current keyboard layout input locale - if (SUBLANGID(wLocId) == SUBLANG_NEUTRAL) - { - wKeybId = (PRIMARYLANGID(wLocId) != LANG_NEUTRAL) - ? PRIMARYLANGID(wKeybId) - : LANG_NEUTRAL; - } - - // check if block should be included or skipped - bIncludeId = bInclude && !bLocaleInc && (wKeybId == wLocId); - - PrintfToLog(_T("b%i:%s \"Locale %i\""), - nBlocksIncludeLevel, - (bIncludeId) ? _T("Including") : _T("Skipping"), - wLocId); - - pData = ParseBlocks(bIncludeId,TRUE); // parse block, allow "End" - if (pData == NULL) // parsing error - { - // don't blame the block twice - if (pFirst) FreeBlocks(pFirst); - return NULL; - } - - if (bIncludeId) // insert blocks to block list - { - if (pFirst) - pBlock = pBlock->pNext = pData; - else - pBlock = pFirst = pData; - - // goto end of insertion - while (pBlock->pNext) pBlock = pBlock->pNext; - bLocaleInc = TRUE; // locale block content included - } - else // skip block - { - if (pData) FreeBlocks(pData); - } - continue; - } - if (!IsGlobalBlock(eToken)) // check for valid block commands - { - PrintfToLog(_T("%i: Invalid Block %s."), nLexLine, GetStringOf(eToken)); - goto abort; - } - if (pFirst) - pBlock = pBlock->pNext = ParseBlock(bInclude,eToken); - else - pBlock = pFirst = ParseBlock(bInclude,eToken); - - if (pBlock == NULL) goto abort; - } - if (*szText != 0) // still KML text left - { - goto abort; - } - _ASSERT(szLexString == NULL); - return pFirst; - -abort: - PrintfToLog(_T("Fatal Error at line %i."), nLexLine); - if (szLexString && eToken == TOK_STRING) - { - free(szLexString); - szLexString = NULL; - } - if (pFirst) FreeBlocks(pFirst); - _ASSERT(szLexString == NULL); - return NULL; -} - - - -//################ -//# -//# Initialization Phase -//# -//################ - -static VOID InitGlobal(KmlBlock* pBlock) -{ - KmlLine* pLine = pBlock->pFirstLine; - while (pLine) - { - switch (pLine->eCommand) - { - case TOK_TITLE: - PrintfToLog(_T("Title: %s"), (LPTSTR)pLine->nParam[0]); - break; - case TOK_AUTHOR: - PrintfToLog(_T("Author: %s"), (LPTSTR)pLine->nParam[0]); - break; - case TOK_PRINT: - AddToLog((LPTSTR)pLine->nParam[0]); - break; - case TOK_HARDWARE: - PrintfToLog(_T("Hardware Platform: %s"), (LPTSTR)pLine->nParam[0]); - break; - case TOK_MODEL: - cCurrentRomType = ((BYTE *)pLine->nParam[0])[0]; - PrintfToLog(_T("Calculator Model : %c"), cCurrentRomType); - break; - case TOK_CLASS: - nCurrentClass = (UINT) pLine->nParam[0]; - PrintfToLog(_T("Calculator Class : %u"), nCurrentClass); - break; - case TOK_ICON: - if (!LoadIconFromFile((LPTSTR) pLine->nParam[0])) - { - PrintfToLog(_T("Cannot load Icon %s."), (LPTSTR)pLine->nParam[0]); - break; - } - PrintfToLog(_T("Icon %s loaded."), (LPTSTR)pLine->nParam[0]); - break; - case TOK_DEBUG: - bDebug = (BOOL) pLine->nParam[0]&1; - PrintfToLog(_T("Debug %s"), bDebug?_T("On"):_T("Off")); - break; - case TOK_ROM: - if (pbyRom != NULL) - { - PrintfToLog(_T("Rom %s ignored."), (LPTSTR)pLine->nParam[0]); - AddToLog(_T("Please put only one Rom command in the Global block.")); - break; - } - if (!MapRom((LPTSTR)pLine->nParam[0])) - { - PrintfToLog(_T("Cannot open Rom %s."), (LPTSTR)pLine->nParam[0]); - break; - } - PrintfToLog(_T("Rom %s loaded."), (LPTSTR)pLine->nParam[0]); - break; - case TOK_PATCH: - if (pbyRom == NULL) - { - PrintfToLog(_T("Patch %s ignored."), (LPTSTR)pLine->nParam[0]); - AddToLog(_T("Please put the Rom command before any Patch.")); - break; - } - if (PatchRom((LPTSTR)pLine->nParam[0]) == TRUE) - PrintfToLog(_T("Patch %s loaded."), (LPTSTR)pLine->nParam[0]); - else - PrintfToLog(_T("Patch %s is Wrong or Missing."), (LPTSTR)pLine->nParam[0]); - break; - case TOK_BITMAP: - if (hMainDC != NULL) - { - PrintfToLog(_T("Bitmap %s ignored."), (LPTSTR)pLine->nParam[0]); - AddToLog(_T("Please put only one Bitmap command in the Global block.")); - break; - } - if (!CreateMainBitmap((LPTSTR)pLine->nParam[0])) - { - PrintfToLog(_T("Cannot load Bitmap %s."), (LPTSTR)pLine->nParam[0]); - break; - } - PrintfToLog(_T("Bitmap %s loaded."), (LPTSTR)pLine->nParam[0]); - break; - case TOK_COLOR: - dwTColorTol = (DWORD) pLine->nParam[0]; - dwTColor = RGB((BYTE) pLine->nParam[1],(BYTE) pLine->nParam[2],(BYTE) pLine->nParam[3]); - break; - case TOK_SCALE: - nScaleMul = (INT) pLine->nParam[0]; - nScaleDiv = (INT) pLine->nParam[1]; - break; - default: - PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); - } - pLine = pLine->pNext; - } - return; -} - -static KmlLine* InitBackground(KmlBlock* pBlock) -{ - KmlLine* pLine = pBlock->pFirstLine; - while (pLine) - { - switch (pLine->eCommand) - { - case TOK_OFFSET: - nBackgroundX = (UINT) pLine->nParam[0]; - nBackgroundY = (UINT) pLine->nParam[1]; - break; - case TOK_SIZE: - nBackgroundW = (UINT) pLine->nParam[0]; - nBackgroundH = (UINT) pLine->nParam[1]; - break; - case TOK_END: - return pLine; - default: - PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); - } - pLine = pLine->pNext; - } - return NULL; -} - -static KmlLine* InitLcd(KmlBlock* pBlock) -{ - KmlLine* pLine = pBlock->pFirstLine; - while (pLine) - { - switch (pLine->eCommand) - { - case TOK_OFFSET: - nLcdX = (UINT) pLine->nParam[0]; - nLcdY = (UINT) pLine->nParam[1]; - break; - case TOK_ZOOM: - if ((nGdiXZoom = (UINT) pLine->nParam[0]) == 0) - nGdiXZoom = 1; // default zoom - - // search for memory DC zoom (1-4) - for (nLcdZoom = 4; (nGdiXZoom % nLcdZoom) != 0; --nLcdZoom) { }; - _ASSERT(nLcdZoom > 0); // because (nGdiXZoom % 1) == 0 - nGdiXZoom /= nLcdZoom; // remainder is GDI zoom - nGdiYZoom = nGdiXZoom; - break; - case TOK_ZOOMXY: - if ((nGdiXZoom = (UINT) pLine->nParam[0]) == 0) - nGdiXZoom = 1; // default zoom - if ((nGdiYZoom = (UINT) pLine->nParam[1]) == 0) - nGdiYZoom = 1; // default zoom - - // search for memory DC zoom (1-4) - for (nLcdZoom = 4; ((nGdiXZoom % nLcdZoom) | (nGdiYZoom % nLcdZoom)) != 0 ; --nLcdZoom) { }; - _ASSERT(nLcdZoom > 0); // because (nGdiYZoom % 1) == 0 && (nGdiYZoom % 1) == 0 - nGdiXZoom /= nLcdZoom; // remainder is GDI zoom - nGdiYZoom /= nLcdZoom; - break; - case TOK_COLOR: - SetLcdColor((UINT) pLine->nParam[0],(UINT) pLine->nParam[1], - (UINT) pLine->nParam[2],(UINT) pLine->nParam[3]); - break; - case TOK_BITMAP: - if (hAnnunDC != NULL) - { - PrintfToLog(_T("Bitmap %s ignored."), (LPCTSTR)pLine->nParam[0]); - AddToLog(_T("Please put only one Bitmap command in the Lcd block.")); - break; - } - if (!CreateAnnunBitmap((LPCTSTR)pLine->nParam[0])) - { - PrintfToLog(_T("Cannot load Annunciator Bitmap %s."), (LPCTSTR)pLine->nParam[0]); - break; - } - PrintfToLog(_T("Annunciator Bitmap %s loaded."), (LPCTSTR)pLine->nParam[0]); - break; - case TOK_END: - return pLine; - default: - PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); - } - pLine = pLine->pNext; - } - return NULL; -} - -static KmlLine* InitAnnunciator(KmlBlock* pBlock) -{ - KmlLine* pLine = pBlock->pFirstLine; - UINT nId = pBlock->nId-1; - if (nId >= ARRAYSIZEOF(pAnnunciator)) - { - PrintfToLog(_T("Wrong Annunciator Id %i"), nId); - return NULL; - } - nAnnunciators++; - while (pLine) - { - switch (pLine->eCommand) - { - case TOK_OFFSET: - pAnnunciator[nId].nOx = (UINT) pLine->nParam[0]; - pAnnunciator[nId].nOy = (UINT) pLine->nParam[1]; - break; - case TOK_DOWN: - pAnnunciator[nId].nDx = (UINT) pLine->nParam[0]; - pAnnunciator[nId].nDy = (UINT) pLine->nParam[1]; - break; - case TOK_SIZE: - pAnnunciator[nId].nCx = (UINT) pLine->nParam[0]; - pAnnunciator[nId].nCy = (UINT) pLine->nParam[1]; - break; - case TOK_END: - return pLine; - default: - PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); - } - pLine = pLine->pNext; - } - return NULL; -} - -static VOID InitButton(KmlBlock* pBlock) -{ - KmlLine* pLine = pBlock->pFirstLine; - UINT nLevel = 0; - - _ASSERT(ARRAYSIZEOF(pButton) == 256); // adjust warning message - if (nButtons >= ARRAYSIZEOF(pButton)) - { - AddToLog(_T("Only the first 256 buttons will be defined.")); - return; - } - pButton[nButtons].nId = pBlock->nId; - pButton[nButtons].bDown = FALSE; - pButton[nButtons].nType = 0; // default: user defined button - while (pLine) - { - if (nLevel) - { - if (IsBlock(pLine->eCommand)) nLevel++; - if (pLine->eCommand == TOK_END) nLevel--; - pLine = pLine->pNext; - continue; - } - if (IsBlock(pLine->eCommand)) nLevel++; - switch (pLine->eCommand) - { - case TOK_TYPE: - pButton[nButtons].nType = (UINT) pLine->nParam[0]; - break; - case TOK_OFFSET: - pButton[nButtons].nOx = (UINT) pLine->nParam[0]; - pButton[nButtons].nOy = (UINT) pLine->nParam[1]; - break; - case TOK_DOWN: - pButton[nButtons].nDx = (UINT) pLine->nParam[0]; - pButton[nButtons].nDy = (UINT) pLine->nParam[1]; - break; - case TOK_SIZE: - pButton[nButtons].nCx = (UINT) pLine->nParam[0]; - pButton[nButtons].nCy = (UINT) pLine->nParam[1]; - break; - case TOK_OUTIN: - pButton[nButtons].nOut = (UINT) pLine->nParam[0]; - pButton[nButtons].nIn = (UINT) pLine->nParam[1]; - break; - case TOK_ONDOWN: - pButton[nButtons].pOnDown = pLine; - break; - case TOK_ONUP: - pButton[nButtons].pOnUp = pLine; - break; - case TOK_NOHOLD: - pButton[nButtons].dwFlags &= ~(BUTTON_VIRTUAL); - pButton[nButtons].dwFlags |= BUTTON_NOHOLD; - break; - case TOK_VIRTUAL: - pButton[nButtons].dwFlags &= ~(BUTTON_NOHOLD); - pButton[nButtons].dwFlags |= BUTTON_VIRTUAL; - break; - default: - PrintfToLog(_T("Command %s Ignored in Block %s %i"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType), pBlock->nId); - } - pLine = pLine->pNext; - } - if (nLevel) - PrintfToLog(_T("%i Open Block(s) in Block %s %i"), nLevel, GetStringOf(pBlock->eType), pBlock->nId); - nButtons++; - return; -} - - - -//################ -//# -//# Execution -//# -//################ - -static KmlLine* SkipLines(KmlLine* pLine, TokenId eCommand) -{ - UINT nLevel = 0; - while (pLine) - { - if (IsBlock(pLine->eCommand)) nLevel++; - if (pLine->eCommand == eCommand) - { - // found token, return command behind token - if (nLevel == 0) return pLine->pNext; - } - if (pLine->eCommand == TOK_END) - { - if (nLevel) - nLevel--; - else - break; - } - pLine = pLine->pNext; - } - return pLine; -} - -static KmlLine* If(KmlLine* pLine, BOOL bCondition) -{ - pLine = pLine->pNext; - if (bCondition) - { - while (pLine) - { - if (pLine->eCommand == TOK_END) - { - pLine = pLine->pNext; - break; - } - if (pLine->eCommand == TOK_ELSE) - { - pLine = SkipLines(pLine, TOK_END); - break; - } - pLine = RunLine(pLine); - } - } - else - { - pLine = SkipLines(pLine, TOK_ELSE); - while (pLine) - { - if (pLine->eCommand == TOK_END) - { - pLine = pLine->pNext; - break; - } - pLine = RunLine(pLine); - } - } - return pLine; -} - -static KmlLine* RunLine(KmlLine* pLine) -{ - BYTE byVal; - - switch (pLine->eCommand) - { - case TOK_MAP: - if (byVKeyMap[pLine->nParam[0]&0xFF]&1) - PressButtonById((UINT) pLine->nParam[1]); - else - ReleaseButtonById((UINT) pLine->nParam[1]); - break; - case TOK_PRESS: - PressButtonById((UINT) pLine->nParam[0]); - break; - case TOK_RELEASE: - ReleaseButtonById((UINT) pLine->nParam[0]); - break; - case TOK_MENUITEM: - PostMessage(hWnd, WM_COMMAND, 0x19C40+(pLine->nParam[0]&0xFF), 0); - break; - case TOK_SYSITEM: - PostMessage(hWnd, WM_SYSCOMMAND, pLine->nParam[0], 0); - break; - case TOK_SETFLAG: - nKMLFlags |= 1<<(pLine->nParam[0]&0x1F); - break; - case TOK_RESETFLAG: - nKMLFlags &= ~(1<<(pLine->nParam[0]&0x1F)); - break; - case TOK_NOTFLAG: - nKMLFlags ^= 1<<(pLine->nParam[0]&0x1F); - break; - case TOK_IFPRESSED: - return If(pLine,byVKeyMap[pLine->nParam[0]&0xFF]); - case TOK_IFFLAG: - return If(pLine,(nKMLFlags>>(pLine->nParam[0]&0x1F))&1); - case TOK_IFMEM: - Npeek(&byVal,(DWORD) pLine->nParam[0],1); - return If(pLine,(byVal & pLine->nParam[1]) == pLine->nParam[2]); - default: - break; - } - return pLine->pNext; -} - - - -//################ -//# -//# Clean Up -//# -//################ - -static VOID FreeLines(KmlLine* pLine) -{ - while (pLine) - { - KmlLine* pThisLine = pLine; - UINT i = 0; - DWORD nParams; - while (pLexToken[i].nLen) // search in all token definitions - { - // break when token definition found - if (pLexToken[i].eId == pLine->eCommand) break; - i++; // next token definition - } - nParams = pLexToken[i].nParams; // get argument types of command - i = 0; // first parameter - while ((nParams&7)) // argument left - { - if ((nParams&7) == TYPE_STRING) // string type - { - free((LPVOID)pLine->nParam[i]); - } - i++; // incr. parameter buffer index - nParams >>= 3; // next argument type - } - pLine = pLine->pNext; // get next line - free(pThisLine); - } - return; -} - -VOID FreeBlocks(KmlBlock* pBlock) -{ - while (pBlock) - { - KmlBlock* pThisBlock = pBlock; - pBlock = pBlock->pNext; - FreeLines(pThisBlock->pFirstLine); - free(pThisBlock); - } - return; -} - -VOID KillKML(VOID) -{ - if ((nState==SM_RUN)||(nState==SM_SLEEP)) - { - AbortMessage(_T("FATAL: KillKML while emulator is running !!!")); - SwitchToState(SM_RETURN); - DestroyWindow(hWnd); - } - UnmapRom(); - DestroyLcdBitmap(); - DestroyAnnunBitmap(); - DestroyMainBitmap(); - if (hPalette) - { - if (hWindowDC) SelectPalette(hWindowDC, hOldPalette, FALSE); - VERIFY(DeleteObject(hPalette)); - hPalette = NULL; - } - if (hRgn != NULL) // region defined - { - if (hWnd != NULL) // window available - { - EnterCriticalSection(&csGDILock); - { - // deletes the region resource - SetWindowRgn(hWnd,NULL,FALSE); - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - } - hRgn = NULL; - } - LoadIconDefault(); - bClicking = FALSE; - uButtonClicked = 0; - FreeBlocks(pKml); - pKml = NULL; - nButtons = 0; - nScancodes = 0; - nAnnunciators = 0; - bDebug = TRUE; - wKeybLocId = 0; - bLocaleInc = FALSE; - nKMLFlags = 0; - ZeroMemory(pButton, sizeof(pButton)); - ZeroMemory(pAnnunciator, sizeof(pAnnunciator)); - ZeroMemory(pVKey, sizeof(pVKey)); - ZeroMemory(byVKeyMap, sizeof(byVKeyMap)); - ClearLog(); - nBackgroundX = 0; - nBackgroundY = 0; - nBackgroundW = 256; - nBackgroundH = 0; - nLcdZoom = 1; - nGdiXZoom = 1; - nGdiYZoom = 1; - dwTColor = (DWORD) -1; - dwTColorTol = 0; - nScaleMul = 0; - nScaleDiv = 0; - cCurrentRomType = 0; - nCurrentClass = 0; - ResizeWindow(); - return; -} - - - -//################ -//# -//# Extract Keyword's Parameters -//# -//################ - -static LPCTSTR GetStringParam(KmlBlock* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam) -{ - while (pBlock) - { - if (pBlock->eType == eBlock) - { - KmlLine* pLine = pBlock->pFirstLine; - while (pLine) - { - if (pLine->eCommand == eCommand) - { - return (LPCTSTR) pLine->nParam[nParam]; - } - pLine = pLine->pNext; - } - } - pBlock = pBlock->pNext; - } - return NULL; -} - -static DWORD GetIntegerParam(KmlBlock* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam) -{ - while (pBlock) - { - if (pBlock->eType == eBlock) - { - KmlLine* pLine = pBlock->pFirstLine; - while (pLine) - { - if (pLine->eCommand == eCommand) - { - return (DWORD) pLine->nParam[nParam]; - } - pLine = pLine->pNext; - } - } - pBlock = pBlock->pNext; - } - return 0; -} - - - -//################ -//# -//# Buttons -//# -//################ - -static UINT iSqrt(UINT nNumber) // integer y=sqrt(x) function -{ - UINT b, t; - - b = t = nNumber; - - if (nNumber > 0) - { - do - { - b = t; - t = (t + nNumber / t) / 2; // Heron's method - } - while (t < b); - } - return b; -} - -static VOID AdjustPixel(LPBYTE pbyPixel, BYTE byOffset) -{ - INT i = 3; // BGR colors - - while (--i >= 0) - { - WORD wColor = (WORD) *pbyPixel + byOffset; - // jumpless saturation to 0xFF - wColor = -(wColor >> 8) | (BYTE) wColor; - *pbyPixel++ = (BYTE) wColor; - } - return; -} - -// draw transparent circle button type -static __inline VOID TransparentCircle(UINT nOx, UINT nOy, UINT nCx, UINT nCy) -{ - #define HIGHADJ 0x80 // color incr. at center - #define LOWADJ 0x10 // color incr. at border - - BITMAPINFO bmi; - HDC hMemDC; - HBITMAP hMemBitMap; - LPBYTE pbyPixels; // BMP data - - UINT x, y, cx, cy, r, rr, rrc; - - r = min(nCx,nCy) / 2; // radius - if (r < 2) return; // radius 2 pixel minimum - - // create memory copy of button rectangle - ZeroMemory(&bmi,sizeof(bmi)); - bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); - bmi.bmiHeader.biWidth = (LONG) nCx; - bmi.bmiHeader.biHeight = (LONG) nCy; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; // use 32 bit bitmap for easier buffer calculation - bmi.bmiHeader.biCompression = BI_RGB; - VERIFY(hMemBitMap = CreateDIBSection(hWindowDC, - &bmi, - DIB_RGB_COLORS, - (VOID **)&pbyPixels, - NULL, - 0)); - if (hMemBitMap == NULL) return; - - hMemDC = CreateCompatibleDC(hWindowDC); - hMemBitMap = (HBITMAP) SelectObject(hMemDC,hMemBitMap); - BitBlt(hMemDC, 0, 0, nCx, nCy, hWindowDC, nOx, nOy, SRCCOPY); - - cx = nCx / 2; // x-center coordinate - cy = nCy / 2; // y-center coordinate - - rr = r * r; // calculate r^2 - rrc = (r-1) * (r-1); // calculate (r-1)^2 for color steps - - // y-rows of circle - for (y = 0; y < r; ++y) - { - UINT yy = y * y; // calculate y^2 - - // x-columns of circle - UINT nXWidth = iSqrt(rr-yy); - - for (x = 0; x < nXWidth; ++x) - { - // color offset, sqrt(x*x+y*y) < r !!! - BYTE byOff = HIGHADJ - (BYTE) (iSqrt((x*x+yy) * (HIGHADJ-LOWADJ)*(HIGHADJ-LOWADJ) / rrc)); - - AdjustPixel(pbyPixels + (((cy+y) * bmi.bmiHeader.biWidth + (cx+x)) << 2), byOff); - - if (x != 0) - { - AdjustPixel(pbyPixels + (((cy+y) * bmi.bmiHeader.biWidth + (cx-x)) << 2), byOff); - } - - if (y != 0) - { - AdjustPixel(pbyPixels + (((cy-y) * bmi.bmiHeader.biWidth + (cx+x)) << 2), byOff); - } - - if (x != 0 && y != 0) - { - AdjustPixel(pbyPixels + (((cy-y) * bmi.bmiHeader.biWidth + (cx-x)) << 2), byOff); - } - } - } - - // update button area with modified data - BitBlt(hWindowDC, nOx, nOy, nCx, nCy, hMemDC, 0, 0, SRCCOPY); - - // delete memory bitmap - VERIFY(DeleteObject(SelectObject(hMemDC,hMemBitMap))); - DeleteDC(hMemDC); - return; - - #undef HIGHADJ - #undef LOWADJ -} - -static VOID DrawButton(UINT nId) -{ - UINT x0 = pButton[nId].nOx; - UINT y0 = pButton[nId].nOy; - - EnterCriticalSection(&csGDILock); // solving NT GDI problems - { - switch (pButton[nId].nType) - { - case 0: // bitmap key - if (pButton[nId].bDown) - { - BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, pButton[nId].nDx, pButton[nId].nDy, SRCCOPY); - } - else - { - // update background only - BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); - } - break; - case 1: // shift key to right down - if (pButton[nId].bDown) - { - UINT x1 = x0+pButton[nId].nCx-1; - UINT y1 = y0+pButton[nId].nCy-1; - BitBlt(hWindowDC, x0+3,y0+3,pButton[nId].nCx-5,pButton[nId].nCy-5,hMainDC,x0+2,y0+2,SRCCOPY); - SelectObject(hWindowDC, GetStockObject(BLACK_PEN)); - MoveToEx(hWindowDC, x0, y0, NULL); LineTo(hWindowDC, x1, y0); - MoveToEx(hWindowDC, x0, y0, NULL); LineTo(hWindowDC, x0, y1); - SelectObject(hWindowDC, GetStockObject(WHITE_PEN)); - MoveToEx(hWindowDC, x1, y0, NULL); LineTo(hWindowDC, x1, y1); - MoveToEx(hWindowDC, x0, y1, NULL); LineTo(hWindowDC, x1+1, y1); - } - else - { - BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); - } - break; - case 2: // do nothing - break; - case 3: // invert key color, even in display - if (pButton[nId].bDown) - { - PatBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, DSTINVERT); - } - else - { - RECT Rect; - Rect.left = x0 - nBackgroundX; - Rect.top = y0 - nBackgroundY; - Rect.right = Rect.left + pButton[nId].nCx; - Rect.bottom = Rect.top + pButton[nId].nCy; - InvalidateRect(hWnd, &Rect, FALSE); // call WM_PAINT for background and display redraw - } - break; - case 4: // bitmap key, even in display - if (pButton[nId].bDown) - { - // update background only - BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); - } - else - { - RECT Rect; - Rect.left = x0 - nBackgroundX; - Rect.top = y0 - nBackgroundY; - Rect.right = Rect.left + pButton[nId].nCx; - Rect.bottom = Rect.top + pButton[nId].nCy; - InvalidateRect(hWnd, &Rect, FALSE); // call WM_PAINT for background and display redraw - } - break; - case 5: // transparent circle - if (pButton[nId].bDown) - { - TransparentCircle(x0, y0, pButton[nId].nCx, pButton[nId].nCy); - } - else - { - // update background only - BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); - } - break; - default: // black key, default drawing on illegal types - if (pButton[nId].bDown) - { - PatBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, BLACKNESS); - } - else - { - // update background only - BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); - } - } - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - return; -} - -static VOID PressButton(UINT nId) -{ - if (!pButton[nId].bDown) // button not pressed - { - pButton[nId].bDown = TRUE; - DrawButton(nId); - if (pButton[nId].nIn) - { - KeyboardEvent(TRUE,pButton[nId].nOut,pButton[nId].nIn); - } - else - { - KmlLine* pLine = pButton[nId].pOnDown; - while ((pLine)&&(pLine->eCommand!=TOK_END)) - { - pLine = RunLine(pLine); - } - } - } - return; -} - -static VOID ReleaseButton(UINT nId) -{ - if (pButton[nId].bDown) // button not released - { - pButton[nId].bDown = FALSE; - DrawButton(nId); - if (pButton[nId].nIn) - { - KeyboardEvent(FALSE,pButton[nId].nOut,pButton[nId].nIn); - } - else - { - KmlLine* pLine = pButton[nId].pOnUp; - while ((pLine)&&(pLine->eCommand!=TOK_END)) - { - pLine = RunLine(pLine); - } - } - } - return; -} - -static VOID PressButtonById(UINT nId) -{ - UINT i; - for (i=0; iright > (LONG) (pButton[i].nOx) - && rc->bottom > (LONG) (pButton[i].nOy) - && rc->left <= (LONG) (pButton[i].nOx + pButton[i].nCx) - && rc->top <= (LONG) (pButton[i].nOy + pButton[i].nCy)) - { - // on button type 3 and 5 clear complete key area before drawing - if (pButton[i].nType == 3 || pButton[i].nType == 5) - { - UINT x0 = pButton[i].nOx; - UINT y0 = pButton[i].nOy; - EnterCriticalSection(&csGDILock); // solving NT GDI problems - { - BitBlt(hWindowDC, x0, y0, pButton[i].nCx, pButton[i].nCy, hMainDC, x0, y0, SRCCOPY); - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - } - DrawButton(i); // redraw pressed button - } - } - return; -} - - -//################ -//# -//# Annunciators -//# -//################ - -VOID DrawAnnunciator(UINT nId, BOOL bOn) -{ - HDC hDC; - UINT nSx,nSy; - - --nId; // zero based ID - if (nId >= ARRAYSIZEOF(pAnnunciator)) return; - if (bOn) - { - hDC = hAnnunDC != NULL ? hAnnunDC : hMainDC; - - nSx = pAnnunciator[nId].nDx; // position of annunciator - nSy = pAnnunciator[nId].nDy; - } - else - { - hDC = hMainDC; - - nSx = pAnnunciator[nId].nOx; // position of background - nSy = pAnnunciator[nId].nOy; - } - EnterCriticalSection(&csGDILock); // solving NT GDI problems - { - BitBlt(hWindowDC, - pAnnunciator[nId].nOx, pAnnunciator[nId].nOy, - pAnnunciator[nId].nCx, pAnnunciator[nId].nCy, - hDC, - nSx, nSy, - SRCCOPY); - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - return; -} - - - -//################ -//# -//# Mouse -//# -//################ - -static BOOL ClipButton(UINT x, UINT y, UINT nId) -{ - x += nBackgroundX; // source display offset - y += nBackgroundY; - - return (pButton[nId].nOx<=x) - && (pButton[nId].nOy<=y) - &&(x<(pButton[nId].nOx+pButton[nId].nCx)) - &&(y<(pButton[nId].nOy+pButton[nId].nCy)); -} - -BOOL MouseIsButton(DWORD x, DWORD y) -{ - UINT i; - for (i = 0; i < nButtons; i++) // scan all buttons - { - if (ClipButton(x,y,i)) // cursor over button? - { - return TRUE; - } - } - return FALSE; -} - -VOID MouseButtonDownAt(UINT nFlags, DWORD x, DWORD y) -{ - UINT i; - for (i=0; i hand cursor else normal arrow cursor - SetCursor(MouseIsButton(x,y) ? hCursorHand : hCursorArrow); - - if (!(nFlags&MK_LBUTTON)) return; // left mouse key not pressed -> quit - if (bKeyPressed && !ClipButton(x,y,uLastKeyPressed)) // not on last pressed key - ReleaseAllButtons(); // release all buttons - if (!bClicking) return; // normal emulation key -> quit - - if (pButton[uButtonClicked].dwFlags&BUTTON_NOHOLD) - { - if (ClipButton(x,y, uButtonClicked) != pButton[uButtonClicked].bDown) - { - pButton[uButtonClicked].bDown = !pButton[uButtonClicked].bDown; - DrawButton(uButtonClicked); - } - return; - } - if (pButton[uButtonClicked].dwFlags&BUTTON_VIRTUAL) - { - if (!ClipButton(x,y, uButtonClicked)) - { - ReleaseButton(uButtonClicked); - bClicking = FALSE; - uButtonClicked = 0; - } - return; - } - return; -} - - - -//################ -//# -//# Keyboard -//# -//################ - -VOID RunKey(BYTE nId, BOOL bPressed) -{ - if (pVKey[nId]) - { - KmlLine* pLine = pVKey[nId]->pFirstLine; - byVKeyMap[nId] = (BYTE) bPressed; - while (pLine) pLine = RunLine(pLine); - } - else - { - if (bDebug&&bPressed) - { - TCHAR szTemp[128]; - wsprintf(szTemp,_T("Scancode %i"),nId); - InfoMessage(szTemp); - } - } - return; -} - - - -//################ -//# -//# Macro player -//# -//################ - -VOID PlayKey(UINT nOut, UINT nIn, BOOL bPressed) -{ - // scan from last buttons because LCD buttons mostly defined first - INT i = nButtons; - while (--i >= 0) - { - if (pButton[i].nOut == nOut && pButton[i].nIn == nIn) - { - if (bPressed) - PressButton(i); - else - ReleaseButton(i); - return; - } - } - return; -} - - - -//################ -//# -//# Load and Initialize Script -//# -//################ - -static VOID ResizeMainBitmap(INT nMul, INT nDiv) -{ - if (nMul * nDiv > 0) // resize main picture - { - BITMAP Bitmap; - int nMode; - INT nWidth,nHeight; - UINT i; - - // update graphic - nBackgroundX = MulDiv(nBackgroundX,nMul,nDiv); - nBackgroundY = MulDiv(nBackgroundY,nMul,nDiv); - nBackgroundW = MulDiv(nBackgroundW,nMul,nDiv); - nBackgroundH = MulDiv(nBackgroundH,nMul,nDiv); - nLcdX = MulDiv(nLcdX,nMul,nDiv); - nLcdY = MulDiv(nLcdY,nMul,nDiv); - nGdiXZoom = MulDiv(nGdiXZoom * nLcdZoom,nMul,nDiv); - nGdiYZoom = MulDiv(nGdiYZoom * nLcdZoom,nMul,nDiv); - - // search for memory DC zoom (1-4) - for (nLcdZoom = 4; ((nGdiXZoom % nLcdZoom) | (nGdiYZoom % nLcdZoom)) != 0 ; --nLcdZoom) { }; - _ASSERT(nLcdZoom > 0); // because (nGdiYZoom % 1) == 0 && (nGdiYZoom % 1) == 0 - nGdiXZoom /= nLcdZoom; // remainder is GDI zoom - nGdiYZoom /= nLcdZoom; - - // update script coordinates (buttons) - for (i = 0; i < nButtons; ++i) - { - pButton[i].nOx = (UINT) (pButton[i].nOx * nMul / nDiv); - pButton[i].nOy = (UINT) (pButton[i].nOy * nMul / nDiv); - pButton[i].nDx = (UINT) (pButton[i].nDx * nMul / nDiv); - pButton[i].nDy = (UINT) (pButton[i].nDy * nMul / nDiv); - pButton[i].nCx = (UINT) (pButton[i].nCx * nMul / nDiv); - pButton[i].nCy = (UINT) (pButton[i].nCy * nMul / nDiv); - } - - // update script coordinates (annunciators) - for (i = 0; i < ARRAYSIZEOF(pAnnunciator); ++i) - { - // translate offset - pAnnunciator[i].nOx = (UINT) (pAnnunciator[i].nOx * nMul / nDiv); - pAnnunciator[i].nOy = (UINT) (pAnnunciator[i].nOy * nMul / nDiv); - - if (hAnnunDC == NULL) // no external annunciator bitmap - { - // translate down (with rounding) - pAnnunciator[i].nDx = (UINT) MulDiv(pAnnunciator[i].nDx,nMul,nDiv); - pAnnunciator[i].nDy = (UINT) MulDiv(pAnnunciator[i].nDy,nMul,nDiv); - // translate size (with rounding) - pAnnunciator[i].nCx = (UINT) MulDiv(pAnnunciator[i].nCx,nMul,nDiv); - pAnnunciator[i].nCy = (UINT) MulDiv(pAnnunciator[i].nCy,nMul,nDiv); - } - } - - EnterCriticalSection(&csGDILock); // solving NT GDI problems - { - // get bitmap size - GetObject(GetCurrentObject(hMainDC,OBJ_BITMAP),sizeof(Bitmap),&Bitmap); - - // resulting bitmap size - nWidth = MulDiv(Bitmap.bmWidth,nMul,nDiv); - nHeight = MulDiv(Bitmap.bmHeight,nMul,nDiv); - - VERIFY(nMode = SetStretchBltMode(hMainDC,HALFTONE)); - - if (nMul <= nDiv) // shrinking bitmap - { - VERIFY(StretchBlt( - hMainDC,0,0,nWidth,nHeight, - hMainDC,0,0,Bitmap.bmWidth,Bitmap.bmHeight, - SRCCOPY)); - } - else // expanding bitmap - { - // bitmap with new size - HDC hMemDC = CreateCompatibleDC(hMainDC); - HBITMAP hMainBitMap = CreateCompatibleBitmap(hMainDC,nWidth,nHeight); - HBITMAP hMemBitMap = (HBITMAP) SelectObject(hMemDC,SelectObject(hMainDC,hMainBitMap)); - - VERIFY(StretchBlt( - hMainDC,0,0,nWidth,nHeight, - hMemDC,0,0,Bitmap.bmWidth,Bitmap.bmHeight, - SRCCOPY)); - - // delete original bitmap - VERIFY(DeleteObject(SelectObject(hMemDC,hMemBitMap))); - DeleteDC(hMemDC); - } - - VERIFY(SetStretchBltMode(hMainDC,nMode)); - - GdiFlush(); - } - LeaveCriticalSection(&csGDILock); - ResizeWindow(); - } - return; -} - -static KmlBlock* LoadKMLGlobal(LPCTSTR szFilename) -{ - HANDLE hFile; - LPTSTR lpBuf; - KmlBlock* pBlock; - TokenId eToken; - - SetCurrentDirectory(szEmuDirectory); - hFile = CreateFile(szFilename, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - SetCurrentDirectory(szCurrentDirectory); - if (hFile == INVALID_HANDLE_VALUE) return NULL; - if ((lpBuf = MapKMLFile(hFile)) == NULL) - return NULL; - - InitLex(lpBuf); - pBlock = NULL; - while ((eToken = Lex(LEX_BLOCK)) != TOK_NONE) - { - if (eToken == TOK_GLOBAL) - { - pBlock = ParseBlock(TRUE,eToken); - if (pBlock) pBlock->pNext = NULL; - break; - } - if (eToken == TOK_STRING) - { - free(szLexString); - szLexString = NULL; - } - } - CleanLex(); - ClearLog(); - free(lpBuf); - return pBlock; -} - -BOOL InitKML(LPCTSTR szFilename, BOOL bNoLog) -{ - TCHAR szKLID[KL_NAMELENGTH]; - HANDLE hFile; - LPTSTR lpBuf; - KmlBlock* pBlock; - BOOL bOk = FALSE; - - KillKML(); - - // get current keyboard layout input locale - if (GetKeyboardLayoutName(szKLID)) - { - wKeybLocId = (WORD) _tcstoul(szKLID,NULL,16); - } - - nBlocksIncludeLevel = 0; - PrintfToLog(_T("Reading %s"), szFilename); - SetCurrentDirectory(szEmuDirectory); - hFile = CreateFile(szFilename, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - SetCurrentDirectory(szCurrentDirectory); - if (hFile == INVALID_HANDLE_VALUE) - { - AddToLog(_T("Error while opening the file.")); - goto quit; - } - if ((lpBuf = MapKMLFile(hFile)) == NULL) - goto quit; - - InitLex(lpBuf); - pKml = ParseBlocks(TRUE, // include blocks - FALSE); // keyword "End" is invalid - CleanLex(); - - free(lpBuf); - if (pKml == NULL) goto quit; - - pBlock = pKml; - while (pBlock) - { - switch (pBlock->eType) - { - case TOK_BUTTON: - InitButton(pBlock); - break; - case TOK_SCANCODE: - nScancodes++; - pVKey[pBlock->nId] = pBlock; - break; - case TOK_ANNUNCIATOR: - InitAnnunciator(pBlock); - break; - case TOK_GLOBAL: - InitGlobal(pBlock); - break; - case TOK_LCD: - InitLcd(pBlock); - break; - case TOK_BACKGROUND: - InitBackground(pBlock); - break; - default: - PrintfToLog(_T("Block %s Ignored."), GetStringOf(pBlock->eType)); - pBlock = pBlock->pNext; - } - pBlock = pBlock->pNext; - } - - if (!isModelValid(cCurrentRomType)) - { - AddToLog(_T("This KML Script doesn't specify a valid model.")); - goto quit; - } - if (pbyRom == NULL) - { - AddToLog(_T("This KML Script doesn't specify the ROM to use, or the ROM could not be loaded.")); - goto quit; - } - if (bRomCrcCorrection) // ROM CRC correction enabled - { - AddToLog(_T("Rebuild the ROM CRC.")); - RebuildRomCrc(); // rebuild the ROM CRC's - } - if (hMainDC == NULL) - { - AddToLog(_T("This KML Script doesn't specify the background bitmap, or bitmap could not be loaded.")); - goto quit; - } - if (!CrcRom(&wRomCrc)) // build patched ROM fingerprint and check for unpacked data - { - AddToLog(_T("Error, packed ROM image detected.")); - goto quit; - } - if (CheckForBeepPatch()) // check if ROM contain beep patches - { - AddToLog(_T("Error, ROM beep patch detected. Remove beep patches please.")); - goto quit; - } - - ResizeMainBitmap(nScaleMul,nScaleDiv); // resize main picture - CreateLcdBitmap(); - - PrintfToLog(_T("%i Buttons Defined"), nButtons); - PrintfToLog(_T("%i Scancodes Defined"), nScancodes); - PrintfToLog(_T("%i Annunciators Defined"), nAnnunciators); - PrintfToLog(_T("Keyboard Locale: %i"), wKeybLocId); - - bOk = TRUE; - -quit: - if (bOk) - { - // HP38G/HP39G/HP40G have no object loading, ignore - DragAcceptFiles(hWnd,cCurrentRomType != '6' && cCurrentRomType != 'A' && cCurrentRomType != 'E'); - - if (!bNoLog) - { - AddToLog(_T("Press Ok to Continue.")); - if (bAlwaysDisplayLog&&(!DisplayKMLLog(bOk))) - { - KillKML(); - return FALSE; - } - } - } - else - { - AddToLog(_T("Press Cancel to Abort.")); - if (!DisplayKMLLog(bOk)) - { - KillKML(); - return FALSE; - } - } - - ResizeWindow(); - ClearLog(); - return bOk; -} +/* + * kml.c + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ +#include "pch.h" +#include "resource.h" +#include "Emu48.h" +#include "kml.h" + +static VOID InitLex(LPCTSTR szScript); +static VOID CleanLex(VOID); +static VOID SkipWhite(UINT nMode); +static TokenId ParseToken(UINT nMode); +static DWORD ParseInteger(VOID); +static LPTSTR ParseString(VOID); +static TokenId Lex(UINT nMode); +static KmlLine* ParseLine(TokenId eCommand); +static KmlLine* IncludeLines(BOOL bInclude, LPCTSTR szFilename); +static KmlLine* ParseLines(BOOL bInclude); +static KmlBlock* ParseBlock(BOOL bInclude, TokenId eBlock); +static KmlBlock* IncludeBlocks(BOOL bInclude, LPCTSTR szFilename); +static KmlBlock* ParseBlocks(BOOL bInclude, BOOL bEndTokenEn); +static VOID FreeLines(KmlLine* pLine); +static VOID PressButton(UINT nId); +static VOID ReleaseButton(UINT nId); +static VOID PressButtonById(UINT nId); +static VOID ReleaseButtonById(UINT nId); +static LPCTSTR GetStringParam(KmlBlock* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam); +static DWORD GetIntegerParam(KmlBlock* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam); +static KmlLine* SkipLines(KmlLine* pLine, TokenId eCommand); +static KmlLine* If(KmlLine* pLine, BOOL bCondition); +static KmlLine* RunLine(KmlLine* pLine); +static KmlBlock* LoadKMLGlobal(LPCTSTR szFilename); + +KmlBlock* pKml = NULL; +static KmlBlock* pVKey[256]; +static BYTE byVKeyMap[256]; +static KmlButton pButton[256]; +static KmlAnnunciator pAnnunciator[6]; +static UINT nButtons = 0; +static UINT nScancodes = 0; +static UINT nAnnunciators = 0; +static BOOL bDebug = TRUE; +static WORD wKeybLocId = 0; +static BOOL bLocaleInc = FALSE; // no locale block content included +static UINT nLexLine; +static UINT nLexInteger; +static UINT nBlocksIncludeLevel; +static UINT nLinesIncludeLevel; +static DWORD nKMLFlags = 0; +static LPTSTR szLexString; +static LPCTSTR szText; +static LPCTSTR szLexDelim[] = +{ + _T(" \t\n\r"), // valid whitespaces for LEX_BLOCK + _T(" \t\n\r"), // valid whitespaces for LEX_COMMAND + _T(" \t\r") // valid whitespaces for LEX_PARAM +}; + +static CONST KmlToken pLexToken[] = +{ + {TOK_ANNUNCIATOR,000001,11,_T("Annunciator")}, + {TOK_BACKGROUND, 000000,10,_T("Background")}, + {TOK_IFPRESSED, 000001, 9,_T("IfPressed")}, + {TOK_RESETFLAG, 000001, 9,_T("ResetFlag")}, + {TOK_SCANCODE, 000001, 8,_T("Scancode")}, + {TOK_HARDWARE, 000002, 8,_T("Hardware")}, + {TOK_MENUITEM, 000001, 8,_T("MenuItem")}, + {TOK_SYSITEM, 000001, 7,_T("SysItem")}, + {TOK_SETFLAG, 000001, 7,_T("SetFlag")}, + {TOK_RELEASE, 000001, 7,_T("Release")}, + {TOK_VIRTUAL, 000000, 7,_T("Virtual")}, + {TOK_INCLUDE, 000002, 7,_T("Include")}, + {TOK_NOTFLAG, 000001, 7,_T("NotFlag")}, + {TOK_MENUBAR, 000001, 7,_T("Menubar")}, // for PPC compatibility reasons + {TOK_GLOBAL, 000000, 6,_T("Global")}, + {TOK_AUTHOR, 000002, 6,_T("Author")}, + {TOK_BITMAP, 000002, 6,_T("Bitmap")}, + {TOK_OFFSET, 000011, 6,_T("Offset")}, + {TOK_ZOOMXY, 000011, 6,_T("Zoomxy")}, + {TOK_BUTTON, 000001, 6,_T("Button")}, + {TOK_IFFLAG, 000001, 6,_T("IfFlag")}, + {TOK_ONDOWN, 000000, 6,_T("OnDown")}, + {TOK_NOHOLD, 000000, 6,_T("NoHold")}, + {TOK_LOCALE, 000001, 6,_T("Locale")}, + {TOK_TOPBAR, 000001, 6,_T("Topbar")}, // for PPC compatibility reasons + {TOK_TITLE, 000002, 5,_T("Title")}, + {TOK_OUTIN, 000011, 5,_T("OutIn")}, + {TOK_PATCH, 000002, 5,_T("Patch")}, + {TOK_PRINT, 000002, 5,_T("Print")}, + {TOK_DEBUG, 000001, 5,_T("Debug")}, + {TOK_COLOR, 001111, 5,_T("Color")}, + {TOK_MODEL, 000002, 5,_T("Model")}, + {TOK_CLASS, 000001, 5,_T("Class")}, + {TOK_PRESS, 000001, 5,_T("Press")}, + {TOK_IFMEM, 000111, 5,_T("IfMem")}, + {TOK_SCALE, 000011, 5,_T("Scale")}, + {TOK_TYPE, 000001, 4,_T("Type")}, + {TOK_SIZE, 000011, 4,_T("Size")}, + {TOK_ZOOM, 000001, 4,_T("Zoom")}, + {TOK_DOWN, 000011, 4,_T("Down")}, + {TOK_ELSE, 000000, 4,_T("Else")}, + {TOK_ONUP, 000000, 4,_T("OnUp")}, + {TOK_ICON, 000002, 4,_T("Icon")}, + {TOK_MAP, 000011, 3,_T("Map")}, + {TOK_ROM, 000002, 3,_T("Rom")}, + {TOK_VGA, 000001, 3,_T("Vga")}, // for PPC compatibility reasons + {TOK_LCD, 000000, 3,_T("Lcd")}, + {TOK_END, 000000, 3,_T("End")}, + {TOK_NONE, 000000, 0,_T("")} +}; + +static CONST TokenId eIsGlobalBlock[] = +{ + TOK_GLOBAL, + TOK_BACKGROUND, + TOK_LCD, + TOK_ANNUNCIATOR, + TOK_BUTTON, + TOK_SCANCODE, + TOK_LOCALE +}; + +static CONST TokenId eIsBlock[] = +{ + TOK_IFFLAG, + TOK_IFPRESSED, + TOK_IFMEM, + TOK_ONDOWN, + TOK_ONUP +}; + +static BOOL bClicking = FALSE; +static UINT uButtonClicked = 0; + +static BOOL bKeyPressed = FALSE; // no key pressed +static UINT uLastKeyPressed = 0; // var for last pressed key + +static INT nScaleMul = 0; // no scaling +static INT nScaleDiv = 0; + +//################ +//# +//# Compilation Result +//# +//################ + +static UINT nLogLength = 0; +static LPTSTR szLog = NULL; + +static VOID ClearLog() +{ + nLogLength = 0; + if (szLog != NULL) + { + free(szLog); + szLog = NULL; + } + return; +} + +static VOID AddToLog(LPCTSTR szString) +{ + LPTSTR szLogTmp; + + UINT nLength = lstrlen(szString) + 2; // CR+LF + if (szLog == NULL) // no log + { + nLogLength = 1; // room for \0 + } + + szLogTmp = (LPTSTR) realloc(szLog,(nLogLength+nLength)*sizeof(szLog[0])); + if (szLogTmp == NULL) + { + ClearLog(); + return; + } + szLog = szLogTmp; + lstrcpy(&szLog[nLogLength-1],szString); + nLogLength += nLength; + szLog[nLogLength-3] = _T('\r'); + szLog[nLogLength-2] = _T('\n'); + szLog[nLogLength-1] = 0; + return; +} + +static VOID __cdecl PrintfToLog(LPCTSTR lpFormat, ...) +{ + TCHAR cOutput[1024]; + va_list arglist; + + va_start(arglist,lpFormat); + wvsprintf(cOutput,lpFormat,arglist); + AddToLog(cOutput); + va_end(arglist); + return; +} + +static INT_PTR CALLBACK KMLLogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + LPCTSTR szString; + + switch (message) + { + case WM_INITDIALOG: + // set OK + EnableWindow(GetDlgItem(hDlg,IDOK),(BOOL) lParam); + // set IDC_TITLE + szString = GetStringParam(pKml, TOK_GLOBAL, TOK_TITLE, 0); + if (szString == NULL) szString = _T("Untitled"); + SetDlgItemText(hDlg,IDC_TITLE,szString); + // set IDC_AUTHOR + szString = GetStringParam(pKml, TOK_GLOBAL, TOK_AUTHOR, 0); + if (szString == NULL) szString = _T(""); + SetDlgItemText(hDlg,IDC_AUTHOR,szString); + // set IDC_KMLLOG + szString = szLog; + if (szString == NULL) szString = _T("Memory Allocation Failure."); + SetDlgItemText(hDlg,IDC_KMLLOG,szString); + // set IDC_ALWAYSDISPLOG + CheckDlgButton(hDlg,IDC_ALWAYSDISPLOG,bAlwaysDisplayLog); + return TRUE; + case WM_COMMAND: + wParam = LOWORD(wParam); + if ((wParam==IDOK)||(wParam==IDCANCEL)) + { + bAlwaysDisplayLog = IsDlgButtonChecked(hDlg, IDC_ALWAYSDISPLOG); + EndDialog(hDlg, wParam); + return TRUE; + } + break; + } + return FALSE; +} + +BOOL DisplayKMLLog(BOOL bOkEnabled) +{ + return IDOK == DialogBoxParam(hApp, + MAKEINTRESOURCE(IDD_KMLLOG), + hWnd, + (DLGPROC)KMLLogProc, + bOkEnabled); +} + + + +//################ +//# +//# Choose Script +//# +//################ + +typedef struct _KmlScript +{ + LPTSTR szFilename; + LPTSTR szTitle; + DWORD nId; + struct _KmlScript* pNext; +} KmlScript; + +static KmlScript* pKmlList = NULL; +static CHAR cKmlType; + +static VOID DestroyKmlList(VOID) +{ + while (pKmlList) + { + KmlScript* pList = pKmlList->pNext; + free(pKmlList->szFilename); + free(pKmlList->szTitle); + free(pKmlList); + pKmlList = pList; + } + return; +} + +static VOID CreateKmlList(VOID) +{ + HANDLE hFindFile; + WIN32_FIND_DATA pFindFileData; + UINT nKmlFiles; + + _ASSERT(pKmlList == NULL); // KML file list must be empty + SetCurrentDirectory(szEmuDirectory); + hFindFile = FindFirstFile(_T("*.KML"),&pFindFileData); + SetCurrentDirectory(szCurrentDirectory); + if (hFindFile == INVALID_HANDLE_VALUE) return; + nKmlFiles = 0; + do + { + KmlScript* pScript; + KmlBlock* pBlock; + LPCTSTR szTitle; + BOOL bInvalidPlatform; + + pBlock = LoadKMLGlobal(pFindFileData.cFileName); + if (pBlock == NULL) continue; + // check for correct KML script platform + szTitle = GetStringParam(pBlock,TOK_GLOBAL,TOK_HARDWARE,0); + bInvalidPlatform = (szTitle && lstrcmpi(_T(HARDWARE),szTitle) != 0); + // check for supported Model + szTitle = GetStringParam(pBlock,TOK_GLOBAL,TOK_MODEL,0); + // skip all scripts with invalid platform and invalid or different Model statement + if ( bInvalidPlatform + || (szTitle == NULL) + || (cKmlType && szTitle[0] != cKmlType) + || !isModelValid(szTitle[0])) + { + FreeBlocks(pBlock); + continue; + } + pScript = (KmlScript*) malloc(sizeof(KmlScript)); + if (pScript) // script node allocated + { + pScript->szFilename = DuplicateString(pFindFileData.cFileName); + szTitle = GetStringParam(pBlock,TOK_GLOBAL,TOK_TITLE,0); + if (szTitle == NULL) szTitle = pScript->szFilename; + pScript->szTitle = DuplicateString(szTitle); + if (pScript->szFilename == NULL || pScript->szTitle == NULL) + { + free(pScript->szFilename); + free(pScript->szTitle); + free(pScript); + FreeBlocks(pBlock); + continue; + } + pScript->nId = nKmlFiles; + pScript->pNext = pKmlList; + pKmlList = pScript; + nKmlFiles++; + } + FreeBlocks(pBlock); + } while (FindNextFile(hFindFile,&pFindFileData)); + FindClose(hFindFile); + return; +}; + +static INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) +{ + TCHAR szDir[MAX_PATH]; + + switch(uMsg) + { + case BFFM_INITIALIZED: + SendMessage(hwnd,BFFM_SETSELECTION,TRUE,pData); + break; + case BFFM_SELCHANGED: + // Set the status window to the currently selected path. + if (SHGetPathFromIDList((LPITEMIDLIST) lp,szDir)) + { + SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM) szDir); + } + break; + } + return 0; +} + +static VOID BrowseFolder(HWND hDlg) +{ + TCHAR szDir[MAX_PATH]; + BROWSEINFO bi; + LPITEMIDLIST pidl; + LPMALLOC pMalloc; + + // gets the shell's default allocator + if (SUCCEEDED(SHGetMalloc(&pMalloc))) + { + GetDlgItemText(hDlg,IDC_EMUDIR,szDir,ARRAYSIZEOF(szDir)); + + ZeroMemory(&bi,sizeof(bi)); + bi.hwndOwner = hDlg; + bi.pidlRoot = NULL; + bi.pszDisplayName = NULL; + bi.lpszTitle = _T("Choose a folder:"); + bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT; + bi.lpfn = BrowseCallbackProc; + bi.lParam = (LPARAM) szDir; // current setting + + pidl = SHBrowseForFolder(&bi); + if (pidl) + { + if (SHGetPathFromIDList(pidl,szDir)) + { + SetDlgItemText(hDlg,IDC_EMUDIR,szDir); + } + // free the PIDL allocated by SHBrowseForFolder + #if defined __cplusplus + pMalloc->Free(pidl); + #else + pMalloc->lpVtbl->Free(pMalloc,pidl); + #endif + } + // release the shell's allocator + #if defined __cplusplus + pMalloc->Release(); + #else + pMalloc->lpVtbl->Release(pMalloc); + #endif + } + return; +} + +static VOID UpdateScriptList(HWND hDlg) +{ + HWND hList; + KmlScript* pList; + UINT nIndex,nEntries; + DWORD dwActId = (DWORD) CB_ERR; + + // add all script titles to combo box + hList = GetDlgItem(hDlg,IDC_KMLSCRIPT); + SendMessage(hList, CB_RESETCONTENT, 0, 0); + for (nEntries = 0, pList = pKmlList; pList; pList = pList->pNext) + { + nIndex = (UINT) SendMessage(hList, CB_ADDSTRING, 0, (LPARAM)pList->szTitle); + SendMessage(hList, CB_SETITEMDATA, nIndex, (LPARAM) pList->nId); + + // this has the same filename like the actual KML script + if (lstrcmpi(szCurrentKml, pList->szFilename) == 0) + dwActId = pList->nId; + + nEntries++; + } + + while (--nEntries > 0) // scan all combo box items + { + // found ID of actual KML script + if ((DWORD) SendMessage(hList, CB_GETITEMDATA, nEntries, 0) == dwActId) + break; + } + SendMessage(hList, CB_SETCURSEL, nEntries, 0); + return; +} + +static INT_PTR CALLBACK ChooseKMLProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND hList; + KmlScript* pList; + UINT nIndex; + + switch (message) + { + case WM_INITDIALOG: + SetDlgItemText(hDlg,IDC_EMUDIR,szEmuDirectory); + UpdateScriptList(hDlg); // update combo box with script titles + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_EMUDIRSEL: + BrowseFolder(hDlg); // select new folder for IDC_EMUDIR + // fall into IDC_UPDATE to search for KML files in new folder + case IDC_UPDATE: + DestroyKmlList(); + GetDlgItemText(hDlg,IDC_EMUDIR,szEmuDirectory,ARRAYSIZEOF(szEmuDirectory)); + CreateKmlList(); + UpdateScriptList(hDlg); // update combo box with script titles + return TRUE; + case IDOK: + GetDlgItemText(hDlg,IDC_EMUDIR,szEmuDirectory,ARRAYSIZEOF(szEmuDirectory)); + hList = GetDlgItem(hDlg,IDC_KMLSCRIPT); + nIndex = (UINT) SendMessage(hList, CB_GETCURSEL, 0, 0); + nIndex = (UINT) SendMessage(hList, CB_GETITEMDATA, nIndex, 0); + for (pList = pKmlList; pList; pList = pList->pNext) + { + if (pList->nId == nIndex) + { + lstrcpy(szCurrentKml, pList->szFilename); + EndDialog(hDlg, IDOK); + break; + } + } + return TRUE; + case IDCANCEL: + EndDialog(hDlg, IDCANCEL); + return TRUE; + } + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +BOOL DisplayChooseKml(CHAR cType) +{ + INT_PTR nResult; + cKmlType = cType; + CreateKmlList(); + nResult = DialogBox(hApp, MAKEINTRESOURCE(IDD_CHOOSEKML), hWnd, (DLGPROC)ChooseKMLProc); + DestroyKmlList(); + return (nResult == IDOK); +} + + + +//################ +//# +//# KML File Mapping +//# +//################ + +static LPTSTR MapKMLFile(HANDLE hFile) +{ + DWORD lBytesRead; + DWORD dwFileSizeLow; + DWORD dwFileSizeHigh; + LPTSTR lpBuf = NULL; + + dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); + if (dwFileSizeHigh != 0) + { + AddToLog(_T("File is too large.")); + goto fail; + } + + lpBuf = (LPTSTR) malloc((dwFileSizeLow+1)*sizeof(lpBuf[0])); + if (lpBuf == NULL) + { + PrintfToLog(_T("Cannot allocate %i bytes."), (dwFileSizeLow+1)*sizeof(lpBuf[0])); + goto fail; + } + #if defined _UNICODE + { + LPSTR szTmp = (LPSTR) malloc(dwFileSizeLow+1); + if (szTmp == NULL) + { + free(lpBuf); + lpBuf = NULL; + PrintfToLog(_T("Cannot allocate %i bytes."), dwFileSizeLow+1); + goto fail; + } + ReadFile(hFile, szTmp, dwFileSizeLow, &lBytesRead, NULL); + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTmp, lBytesRead, lpBuf, dwFileSizeLow+1); + free(szTmp); + } + #else + { + ReadFile(hFile, lpBuf, dwFileSizeLow, &lBytesRead, NULL); + } + #endif + lpBuf[dwFileSizeLow] = 0; + +fail: + CloseHandle(hFile); + return lpBuf; +} + + + +//################ +//# +//# Script Parsing +//# +//################ + +static VOID InitLex(LPCTSTR szScript) +{ + nLexLine = 1; + szText = szScript; + return; +} + +static VOID CleanLex(VOID) +{ + nLexLine = 0; + nLexInteger = 0; + szLexString = NULL; + szText = NULL; + return; +} + +static BOOL IsGlobalBlock(TokenId eId) +{ + UINT i; + + for (i = 0; i < ARRAYSIZEOF(eIsGlobalBlock); ++i) + { + if (eId == eIsGlobalBlock[i]) return TRUE; + } + return FALSE; +} + +static BOOL IsBlock(TokenId eId) +{ + UINT i; + + for (i = 0; i < ARRAYSIZEOF(eIsBlock); ++i) + { + if (eId == eIsBlock[i]) return TRUE; + } + return FALSE; +} + +static LPCTSTR GetStringOf(TokenId eId) +{ + UINT i; + + for (i = 0; pLexToken[i].nLen; ++i) + { + if (pLexToken[i].eId == eId) return pLexToken[i].szName; + } + return _T(""); +} + +static VOID SkipWhite(UINT nMode) +{ + LPCTSTR pcDelim; + + while (*szText) + { + // search for delimiter + if ((pcDelim = _tcschr(szLexDelim[nMode],*szText)) != NULL) + { + _ASSERT(*pcDelim != 0); // no EOS + if (*pcDelim == _T('\n')) nLexLine++; + szText++; + continue; + } + if (*szText == _T('#')) // start of remark + { + // skip until LF or EOS + do szText++; while (*szText != _T('\n') && *szText != 0); + if (nMode != LEX_PARAM) continue; + } + break; + } + return; +} + +static TokenId ParseToken(UINT nMode) +{ + UINT i,j; + + for (i = 0; szText[i]; i++) // search for delimeter + { + if (_tcschr(szLexDelim[nMode],szText[i]) != NULL) + break; + } + if (i == 0) return TOK_NONE; + + // token length longer or equal than current command + for (j = 0; pLexToken[j].nLen >= i; ++j) + { + if (pLexToken[j].nLen == i) // token length has command length + { + if (_tcsncmp(pLexToken[j].szName,szText,i) == 0) + { + szText += i; // remove command from text + return pLexToken[j].eId; // return token Id + } + } + } + if (bDebug) // token not found + { + // allocate target string memory with token length + LPTSTR szToken = (LPTSTR) malloc((i+1) * sizeof(szToken[0])); + lstrcpyn(szToken,szText,i+1); // copy token text and append EOS + PrintfToLog(_T("%i: Undefined token %s"),nLexLine,szToken); + free(szToken); + } + return TOK_NONE; +} + +static DWORD ParseInteger(VOID) +{ + DWORD nNum = 0; + while (_istdigit(*szText)) + { + nNum = nNum * 10 + ((*szText) - _T('0')); + szText++; + } + return nNum; +} + +static LPTSTR ParseString(VOID) +{ + LPTSTR lpszString = NULL; // no mem allocated + UINT nBlock = 0; + UINT nLength = 0; + + LPTSTR lpszAllocString; + + szText++; // skip leading '"' + + while (*szText != _T('"')) + { + if (nLength >= nBlock) // ran out of buffer space + { + nBlock += 256; + lpszAllocString = (LPTSTR) realloc(lpszString,nBlock * sizeof(lpszString[0])); + if (lpszAllocString) + { + lpszString = lpszAllocString; + } + else + { + free(lpszString); // cleanup allocation failture + return NULL; + } + } + + if (*szText == _T('\\')) // escape char + { + // skip a '\' escape char before a quotation to + // decode the \" sequence as a quotation mark inside text + switch (szText[1]) + { + case _T('\"'): + case _T('\\'): + ++szText; // skip escape char '\' + break; + } + } + + if (*szText == 0) // EOS found inside string + { + lpszString[nLength] = 0; // set EOS + PrintfToLog(_T("%i: Invalid string %s."), nLexLine, lpszString); + free(lpszString); + return NULL; + } + lpszString[nLength++] = *szText++; // save char + } + szText++; // skip ending '"' + + // release unnecessary allocated bytes or allocate byte for EOS + if ((lpszAllocString = (LPTSTR) realloc(lpszString,(nLength+1) * sizeof(lpszString[0])))) + { + lpszAllocString[nLength] = 0; // set EOS + } + else + { + free(lpszString); // cleanup allocation failture + } + return lpszAllocString; +} + +static TokenId Lex(UINT nMode) +{ + _ASSERT(nMode >= LEX_BLOCK && nMode <= LEX_PARAM); + _ASSERT(nMode >= 0 && nMode < ARRAYSIZEOF(szLexDelim)); + + SkipWhite(nMode); + if (_istdigit(*szText)) + { + nLexInteger = ParseInteger(); + return TOK_INTEGER; + } + if (*szText == _T('"')) + { + szLexString = ParseString(); + return TOK_STRING; + } + if (nMode == LEX_PARAM) + { + if (*szText == _T('\n')) // end of line + { + nLexLine++; // next line + szText++; // skip LF + return TOK_EOL; + } + if (*szText == 0) // end of file + { + return TOK_EOL; + } + } + return ParseToken(nMode); +} + +static KmlLine* ParseLine(TokenId eCommand) +{ + UINT i, j; + DWORD nParams; + TokenId eToken; + KmlLine* pLine; + + for (i = 0; pLexToken[i].nLen; ++i) + { + if (pLexToken[i].eId == eCommand) break; + } + if (pLexToken[i].nLen == 0) return NULL; + + if ((pLine = (KmlLine*) calloc(1,sizeof(KmlLine))) == NULL) + return NULL; + + pLine->eCommand = eCommand; + + for (j = 0, nParams = pLexToken[i].nParams; TRUE; nParams >>= 3) + { + // check for parameter overflow + _ASSERT(j < ARRAYSIZEOF(pLine->nParam)); + + eToken = Lex(LEX_PARAM); // decode argument token + if ((nParams & 7) == TYPE_NONE) + { + if (eToken != TOK_EOL) + { + PrintfToLog(_T("%i: Too many parameters for %s (%i expected)."), nLexLine, pLexToken[i].szName, j); + break; // free memory of arguments + } + return pLine; // normal exit -> parsed line + } + if ((nParams & 7) == TYPE_INTEGER) + { + if (eToken != TOK_INTEGER) + { + PrintfToLog(_T("%i: Parameter %i of %s must be an integer."), nLexLine, j+1, pLexToken[i].szName); + break; // free memory of arguments + } + pLine->nParam[j++] = nLexInteger; + continue; + } + if ((nParams & 7) == TYPE_STRING) + { + if (eToken != TOK_STRING) + { + PrintfToLog(_T("%i: Parameter %i of %s must be a string."), nLexLine, j+1, pLexToken[i].szName); + break; // free memory of arguments + } + pLine->nParam[j++] = (DWORD_PTR) szLexString; + szLexString = NULL; + continue; + } + _ASSERT(FALSE); // unknown parameter type + break; + } + + // if last argument was string, free it + if (eToken == TOK_STRING) + { + free(szLexString); + szLexString = NULL; + } + + nParams = pLexToken[i].nParams; // get argument types of command + for (i = 0; i < j; ++i) // handle all scanned arguments + { + if ((nParams & 7) == TYPE_STRING) // string type + { + free((LPVOID)pLine->nParam[i]); + } + nParams >>= 3; // next argument type + } + free(pLine); + return NULL; +} + +static KmlLine* IncludeLines(BOOL bInclude, LPCTSTR szFilename) +{ + HANDLE hFile; + LPTSTR lpbyBuf; + UINT uOldLine; + LPCTSTR szOldText; + KmlLine* pLine; + + SetCurrentDirectory(szEmuDirectory); + hFile = CreateFile(szFilename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + SetCurrentDirectory(szCurrentDirectory); + if (hFile == INVALID_HANDLE_VALUE) + { + PrintfToLog(_T("Error while opening include file %s."), szFilename); + return NULL; + } + if ((lpbyBuf = MapKMLFile(hFile)) == NULL) + { + return NULL; + } + + uOldLine = nLexLine; + szOldText = szText; + + nLinesIncludeLevel++; + PrintfToLog(_T("l%i:%s %s"), + nLinesIncludeLevel, + (bInclude) ? _T("Including") : _T("Parsing"), + szFilename); + InitLex(lpbyBuf); + pLine = ParseLines(bInclude); + CleanLex(); + nLinesIncludeLevel--; + + nLexLine = uOldLine; + szText = szOldText; + free(lpbyBuf); + + return pLine; +} + +static KmlLine* ParseLines(BOOL bInclude) +{ + KmlLine* pFirst = NULL; + KmlLine* pLine = NULL; + TokenId eToken; + UINT nLevel = 0; + + while ((eToken = Lex(LEX_COMMAND)) != TOK_NONE) + { + if (IsGlobalBlock(eToken)) // check for block command + { + PrintfToLog(_T("%i: Invalid Command %s."), nLexLine, GetStringOf(eToken)); + goto abort; + } + if (IsBlock(eToken)) nLevel++; + if (eToken == TOK_INCLUDE) + { + LPTSTR szFilename; + UINT nLexLineKml; + + eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString' + if (eToken != TOK_STRING) // not a string (token don't begin with ") + { + PrintfToLog(_T("%i: Include: string expected as parameter."), nLexLine); + goto abort; + } + szFilename = szLexString; // save pointer to allocated memory + szLexString = NULL; + nLexLineKml = nLexLine; // save line number + eToken = Lex(LEX_PARAM); // decode argument + if (eToken != TOK_EOL) + { + free(szFilename); // free filename string + if (eToken == TOK_STRING) + { + free(szLexString); + szLexString = NULL; + } + PrintfToLog(_T("%i: Include: Too many parameters."), nLexLine); + goto abort; + } + if (pFirst) + { + pLine = pLine->pNext = IncludeLines(bInclude,szFilename); + } + else + { + pLine = pFirst = IncludeLines(bInclude,szFilename); + } + free(szFilename); // free filename string + if (pLine == NULL) // parsing error + { + nLexLine = nLexLineKml; // restore line number + goto abort; + } + while (pLine->pNext) pLine=pLine->pNext; + continue; + } + if (eToken == TOK_END) + { + if (nLevel) + { + nLevel--; + } + else + { + if (pFirst == NULL) // regular exit with empty block + { + // create an empty line + if ((pFirst = (KmlLine*) calloc(1,sizeof(KmlLine))) == NULL) + goto abort; + + pLine = pFirst; + pLine->eCommand = TOK_NONE; + } + if (pLine) pLine->pNext = NULL; + _ASSERT(szLexString == NULL); + return pFirst; + } + } + if (pFirst) + { + pLine = pLine->pNext = ParseLine(eToken); + } + else + { + pLine = pFirst = ParseLine(eToken); + } + if (pLine == NULL) // parsing error + goto abort; + } + if (nLinesIncludeLevel) + { + if (pLine) pLine->pNext = NULL; + _ASSERT(szLexString == NULL); + return pFirst; + } +abort: + if (pFirst) FreeLines(pFirst); + _ASSERT(szLexString == NULL); + return NULL; +} + +static KmlBlock* ParseBlock(BOOL bInclude, TokenId eType) +{ + UINT i; + KmlBlock* pBlock; + TokenId eToken; + + nLinesIncludeLevel = 0; + + if ((pBlock = (KmlBlock *) calloc(1,sizeof(KmlBlock))) == NULL) + return NULL; + + pBlock->eType = eType; + + for (i = 0; pLexToken[i].nLen; ++i) // search for token + { + if (pLexToken[i].eId == eType) break; + } + + if (pLexToken[i].nParams) // has block command arguments + { + // block command parser accept only one integer argument + _ASSERT(pLexToken[i].nParams == TYPE_INTEGER); + + eToken = Lex(LEX_PARAM); // decode argument + if (eToken != TOK_INTEGER) + { + if (eToken == TOK_STRING) + { + free(szLexString); + szLexString = NULL; + } + PrintfToLog(_T("%i: Block %s parameter must be an integer."), nLexLine, pLexToken[i].szName); + free(pBlock); + _ASSERT(szLexString == NULL); + return NULL; + } + + pBlock->nId = nLexInteger; // remember block no. + } + + eToken = Lex(LEX_PARAM); // decode argument + if (eToken != TOK_EOL) + { + if (eToken == TOK_STRING) + { + free(szLexString); + szLexString = NULL; + } + PrintfToLog(_T("%i: Too many parameters for block %s."), nLexLine, pLexToken[i].szName); + free(pBlock); + _ASSERT(szLexString == NULL); + return NULL; + } + + pBlock->pFirstLine = ParseLines(bInclude); + if (pBlock->pFirstLine == NULL) // break on ParseLines error + { + free(pBlock); + pBlock = NULL; + } + _ASSERT(szLexString == NULL); + return pBlock; +} + +static KmlBlock* IncludeBlocks(BOOL bInclude, LPCTSTR szFilename) +{ + HANDLE hFile; + LPTSTR lpbyBuf; + UINT uOldLine; + LPCTSTR szOldText; + KmlBlock* pFirst; + + SetCurrentDirectory(szEmuDirectory); + hFile = CreateFile(szFilename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + SetCurrentDirectory(szCurrentDirectory); + if (hFile == INVALID_HANDLE_VALUE) + { + PrintfToLog(_T("Error while opening include file %s."), szFilename); + return NULL; + } + if ((lpbyBuf = MapKMLFile(hFile)) == NULL) + { + return NULL; + } + + uOldLine = nLexLine; + szOldText = szText; + + nBlocksIncludeLevel++; + PrintfToLog(_T("b%i:%s %s"), + nBlocksIncludeLevel, + (bInclude) ? _T("Including") : _T("Parsing"), + szFilename); + InitLex(lpbyBuf); + pFirst = ParseBlocks(bInclude, FALSE); + CleanLex(); + nBlocksIncludeLevel--; + + nLexLine = uOldLine; + szText = szOldText; + free(lpbyBuf); + + return pFirst; +} + +static KmlBlock* ParseBlocks(BOOL bInclude, BOOL bEndTokenEn) +{ + TokenId eToken; + KmlBlock* pFirst = NULL; + KmlBlock* pBlock = NULL; + + while ((eToken = Lex(LEX_BLOCK)) != TOK_NONE) + { + // allow TOK_END token only as end of a "Locale" block + if (bEndTokenEn && eToken == TOK_END) + { + return pFirst; + } + if (eToken == TOK_INCLUDE) + { + LPTSTR szFilename; + UINT nLexLineKml; + + eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString' + if (eToken != TOK_STRING) // not a string (token don't begin with ") + { + AddToLog(_T("Include: string expected as parameter.")); + goto abort; + } + szFilename = szLexString; // save pointer to allocated memory + szLexString = NULL; + nLexLineKml = nLexLine; // save line number + eToken = Lex(LEX_PARAM); // decode argument + if (eToken != TOK_EOL) + { + free(szFilename); // free filename string + PrintfToLog(_T("%i: Include: Too many parameters."), nLexLine); + goto abort; + } + if (pFirst) + pBlock = pBlock->pNext = IncludeBlocks(bInclude,szFilename); + else + pBlock = pFirst = IncludeBlocks(bInclude,szFilename); + free(szFilename); // free filename string + if (pBlock == NULL) // parsing error + { + nLexLine = nLexLineKml; // restore line number + goto abort; + } + while (pBlock->pNext) pBlock = pBlock->pNext; + continue; + } + if (eToken == TOK_LOCALE) + { + WORD wLocId,wKeybId; + KmlBlock* pData; + BOOL bIncludeId; + + eToken = Lex(LEX_PARAM); // get include parameter in 'nLexInteger' + if (eToken != TOK_INTEGER) + { + PrintfToLog(_T("%i: Locale parameter must be an integer."), nLexLine); + goto abort; + } + wLocId = nLexInteger; // requested keyboard locale id + eToken = Lex(LEX_PARAM); // decode argument + if (eToken != TOK_EOL) + { + PrintfToLog(_T("%i: Too many parameters for Locale."), nLexLine); + goto abort; + } + + wKeybId = wKeybLocId; // get current keyboard layout input locale + if (SUBLANGID(wLocId) == SUBLANG_NEUTRAL) + { + wKeybId = (PRIMARYLANGID(wLocId) != LANG_NEUTRAL) + ? PRIMARYLANGID(wKeybId) + : LANG_NEUTRAL; + } + + // check if block should be included or skipped + bIncludeId = bInclude && !bLocaleInc && (wKeybId == wLocId); + + PrintfToLog(_T("b%i:%s \"Locale %i\""), + nBlocksIncludeLevel, + (bIncludeId) ? _T("Including") : _T("Skipping"), + wLocId); + + pData = ParseBlocks(bIncludeId,TRUE); // parse block, allow "End" + if (pData == NULL) // parsing error + { + // don't blame the block twice + if (pFirst) FreeBlocks(pFirst); + return NULL; + } + + if (bIncludeId) // insert blocks to block list + { + if (pFirst) + pBlock = pBlock->pNext = pData; + else + pBlock = pFirst = pData; + + // goto end of insertion + while (pBlock->pNext) pBlock = pBlock->pNext; + bLocaleInc = TRUE; // locale block content included + } + else // skip block + { + if (pData) FreeBlocks(pData); + } + continue; + } + if (!IsGlobalBlock(eToken)) // check for valid block commands + { + PrintfToLog(_T("%i: Invalid Block %s."), nLexLine, GetStringOf(eToken)); + goto abort; + } + if (pFirst) + pBlock = pBlock->pNext = ParseBlock(bInclude,eToken); + else + pBlock = pFirst = ParseBlock(bInclude,eToken); + + if (pBlock == NULL) goto abort; + } + if (*szText != 0) // still KML text left + { + goto abort; + } + _ASSERT(szLexString == NULL); + return pFirst; + +abort: + PrintfToLog(_T("Fatal Error at line %i."), nLexLine); + if (szLexString && eToken == TOK_STRING) + { + free(szLexString); + szLexString = NULL; + } + if (pFirst) FreeBlocks(pFirst); + _ASSERT(szLexString == NULL); + return NULL; +} + + + +//################ +//# +//# Initialization Phase +//# +//################ + +static VOID InitGlobal(KmlBlock* pBlock) +{ + KmlLine* pLine = pBlock->pFirstLine; + while (pLine) + { + switch (pLine->eCommand) + { + case TOK_TITLE: + PrintfToLog(_T("Title: %s"), (LPTSTR)pLine->nParam[0]); + break; + case TOK_AUTHOR: + PrintfToLog(_T("Author: %s"), (LPTSTR)pLine->nParam[0]); + break; + case TOK_PRINT: + AddToLog((LPTSTR)pLine->nParam[0]); + break; + case TOK_HARDWARE: + PrintfToLog(_T("Hardware Platform: %s"), (LPTSTR)pLine->nParam[0]); + break; + case TOK_MODEL: + cCurrentRomType = ((BYTE *)pLine->nParam[0])[0]; + PrintfToLog(_T("Calculator Model : %c"), cCurrentRomType); + break; + case TOK_CLASS: + nCurrentClass = (UINT) pLine->nParam[0]; + PrintfToLog(_T("Calculator Class : %u"), nCurrentClass); + break; + case TOK_ICON: + if (!LoadIconFromFile((LPTSTR) pLine->nParam[0])) + { + PrintfToLog(_T("Cannot load Icon %s."), (LPTSTR)pLine->nParam[0]); + break; + } + PrintfToLog(_T("Icon %s loaded."), (LPTSTR)pLine->nParam[0]); + break; + case TOK_DEBUG: + bDebug = (BOOL) pLine->nParam[0]&1; + PrintfToLog(_T("Debug %s"), bDebug?_T("On"):_T("Off")); + break; + case TOK_ROM: + if (pbyRom != NULL) + { + PrintfToLog(_T("Rom %s ignored."), (LPTSTR)pLine->nParam[0]); + AddToLog(_T("Please put only one Rom command in the Global block.")); + break; + } + if (!MapRom((LPTSTR)pLine->nParam[0])) + { + PrintfToLog(_T("Cannot open Rom %s."), (LPTSTR)pLine->nParam[0]); + break; + } + PrintfToLog(_T("Rom %s loaded."), (LPTSTR)pLine->nParam[0]); + break; + case TOK_PATCH: + if (pbyRom == NULL) + { + PrintfToLog(_T("Patch %s ignored."), (LPTSTR)pLine->nParam[0]); + AddToLog(_T("Please put the Rom command before any Patch.")); + break; + } + if (PatchRom((LPTSTR)pLine->nParam[0]) == TRUE) + PrintfToLog(_T("Patch %s loaded."), (LPTSTR)pLine->nParam[0]); + else + PrintfToLog(_T("Patch %s is Wrong or Missing."), (LPTSTR)pLine->nParam[0]); + break; + case TOK_BITMAP: + if (hMainDC != NULL) + { + PrintfToLog(_T("Bitmap %s ignored."), (LPTSTR)pLine->nParam[0]); + AddToLog(_T("Please put only one Bitmap command in the Global block.")); + break; + } + if (!CreateMainBitmap((LPTSTR)pLine->nParam[0])) + { + PrintfToLog(_T("Cannot load Bitmap %s."), (LPTSTR)pLine->nParam[0]); + break; + } + PrintfToLog(_T("Bitmap %s loaded."), (LPTSTR)pLine->nParam[0]); + break; + case TOK_COLOR: + dwTColorTol = (DWORD) pLine->nParam[0]; + dwTColor = RGB((BYTE) pLine->nParam[1],(BYTE) pLine->nParam[2],(BYTE) pLine->nParam[3]); + break; + case TOK_SCALE: + nScaleMul = (INT) pLine->nParam[0]; + nScaleDiv = (INT) pLine->nParam[1]; + break; + default: + PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); + } + pLine = pLine->pNext; + } + return; +} + +static KmlLine* InitBackground(KmlBlock* pBlock) +{ + KmlLine* pLine = pBlock->pFirstLine; + while (pLine) + { + switch (pLine->eCommand) + { + case TOK_OFFSET: + nBackgroundX = (UINT) pLine->nParam[0]; + nBackgroundY = (UINT) pLine->nParam[1]; + break; + case TOK_SIZE: + nBackgroundW = (UINT) pLine->nParam[0]; + nBackgroundH = (UINT) pLine->nParam[1]; + break; + case TOK_END: + return pLine; + default: + PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); + } + pLine = pLine->pNext; + } + return NULL; +} + +static KmlLine* InitLcd(KmlBlock* pBlock) +{ + KmlLine* pLine = pBlock->pFirstLine; + while (pLine) + { + switch (pLine->eCommand) + { + case TOK_OFFSET: + nLcdX = (UINT) pLine->nParam[0]; + nLcdY = (UINT) pLine->nParam[1]; + break; + case TOK_ZOOM: + if ((nGdiXZoom = (UINT) pLine->nParam[0]) == 0) + nGdiXZoom = 1; // default zoom + + // search for memory DC zoom (1-4) + for (nLcdZoom = 4; (nGdiXZoom % nLcdZoom) != 0; --nLcdZoom) { }; + _ASSERT(nLcdZoom > 0); // because (nGdiXZoom % 1) == 0 + nGdiXZoom /= nLcdZoom; // remainder is GDI zoom + nGdiYZoom = nGdiXZoom; + break; + case TOK_ZOOMXY: + if ((nGdiXZoom = (UINT) pLine->nParam[0]) == 0) + nGdiXZoom = 1; // default zoom + if ((nGdiYZoom = (UINT) pLine->nParam[1]) == 0) + nGdiYZoom = 1; // default zoom + + // search for memory DC zoom (1-4) + for (nLcdZoom = 4; ((nGdiXZoom % nLcdZoom) | (nGdiYZoom % nLcdZoom)) != 0 ; --nLcdZoom) { }; + _ASSERT(nLcdZoom > 0); // because (nGdiYZoom % 1) == 0 && (nGdiYZoom % 1) == 0 + nGdiXZoom /= nLcdZoom; // remainder is GDI zoom + nGdiYZoom /= nLcdZoom; + break; + case TOK_COLOR: + SetLcdColor((UINT) pLine->nParam[0],(UINT) pLine->nParam[1], + (UINT) pLine->nParam[2],(UINT) pLine->nParam[3]); + break; + case TOK_BITMAP: + if (hAnnunDC != NULL) + { + PrintfToLog(_T("Bitmap %s ignored."), (LPCTSTR)pLine->nParam[0]); + AddToLog(_T("Please put only one Bitmap command in the Lcd block.")); + break; + } + if (!CreateAnnunBitmap((LPCTSTR)pLine->nParam[0])) + { + PrintfToLog(_T("Cannot load Annunciator Bitmap %s."), (LPCTSTR)pLine->nParam[0]); + break; + } + PrintfToLog(_T("Annunciator Bitmap %s loaded."), (LPCTSTR)pLine->nParam[0]); + break; + case TOK_END: + return pLine; + default: + PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); + } + pLine = pLine->pNext; + } + return NULL; +} + +static KmlLine* InitAnnunciator(KmlBlock* pBlock) +{ + KmlLine* pLine = pBlock->pFirstLine; + UINT nId = pBlock->nId-1; + if (nId >= ARRAYSIZEOF(pAnnunciator)) + { + PrintfToLog(_T("Wrong Annunciator Id %i"), nId); + return NULL; + } + nAnnunciators++; + while (pLine) + { + switch (pLine->eCommand) + { + case TOK_OFFSET: + pAnnunciator[nId].nOx = (UINT) pLine->nParam[0]; + pAnnunciator[nId].nOy = (UINT) pLine->nParam[1]; + break; + case TOK_DOWN: + pAnnunciator[nId].nDx = (UINT) pLine->nParam[0]; + pAnnunciator[nId].nDy = (UINT) pLine->nParam[1]; + break; + case TOK_SIZE: + pAnnunciator[nId].nCx = (UINT) pLine->nParam[0]; + pAnnunciator[nId].nCy = (UINT) pLine->nParam[1]; + break; + case TOK_END: + return pLine; + default: + PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); + } + pLine = pLine->pNext; + } + return NULL; +} + +static VOID InitButton(KmlBlock* pBlock) +{ + KmlLine* pLine = pBlock->pFirstLine; + UINT nLevel = 0; + + _ASSERT(ARRAYSIZEOF(pButton) == 256); // adjust warning message + if (nButtons >= ARRAYSIZEOF(pButton)) + { + AddToLog(_T("Only the first 256 buttons will be defined.")); + return; + } + pButton[nButtons].nId = pBlock->nId; + pButton[nButtons].bDown = FALSE; + pButton[nButtons].nType = 0; // default: user defined button + while (pLine) + { + if (nLevel) + { + if (IsBlock(pLine->eCommand)) nLevel++; + if (pLine->eCommand == TOK_END) nLevel--; + pLine = pLine->pNext; + continue; + } + if (IsBlock(pLine->eCommand)) nLevel++; + switch (pLine->eCommand) + { + case TOK_TYPE: + pButton[nButtons].nType = (UINT) pLine->nParam[0]; + break; + case TOK_OFFSET: + pButton[nButtons].nOx = (UINT) pLine->nParam[0]; + pButton[nButtons].nOy = (UINT) pLine->nParam[1]; + break; + case TOK_DOWN: + pButton[nButtons].nDx = (UINT) pLine->nParam[0]; + pButton[nButtons].nDy = (UINT) pLine->nParam[1]; + break; + case TOK_SIZE: + pButton[nButtons].nCx = (UINT) pLine->nParam[0]; + pButton[nButtons].nCy = (UINT) pLine->nParam[1]; + break; + case TOK_OUTIN: + pButton[nButtons].nOut = (UINT) pLine->nParam[0]; + pButton[nButtons].nIn = (UINT) pLine->nParam[1]; + break; + case TOK_ONDOWN: + pButton[nButtons].pOnDown = pLine; + break; + case TOK_ONUP: + pButton[nButtons].pOnUp = pLine; + break; + case TOK_NOHOLD: + pButton[nButtons].dwFlags &= ~(BUTTON_VIRTUAL); + pButton[nButtons].dwFlags |= BUTTON_NOHOLD; + break; + case TOK_VIRTUAL: + pButton[nButtons].dwFlags &= ~(BUTTON_NOHOLD); + pButton[nButtons].dwFlags |= BUTTON_VIRTUAL; + break; + default: + PrintfToLog(_T("Command %s Ignored in Block %s %i"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType), pBlock->nId); + } + pLine = pLine->pNext; + } + if (nLevel) + PrintfToLog(_T("%i Open Block(s) in Block %s %i"), nLevel, GetStringOf(pBlock->eType), pBlock->nId); + nButtons++; + return; +} + + + +//################ +//# +//# Execution +//# +//################ + +static KmlLine* SkipLines(KmlLine* pLine, TokenId eCommand) +{ + UINT nLevel = 0; + while (pLine) + { + if (IsBlock(pLine->eCommand)) nLevel++; + if (pLine->eCommand == eCommand) + { + // found token, return command behind token + if (nLevel == 0) return pLine->pNext; + } + if (pLine->eCommand == TOK_END) + { + if (nLevel) + nLevel--; + else + break; + } + pLine = pLine->pNext; + } + return pLine; +} + +static KmlLine* If(KmlLine* pLine, BOOL bCondition) +{ + pLine = pLine->pNext; + if (bCondition) + { + while (pLine) + { + if (pLine->eCommand == TOK_END) + { + pLine = pLine->pNext; + break; + } + if (pLine->eCommand == TOK_ELSE) + { + pLine = SkipLines(pLine, TOK_END); + break; + } + pLine = RunLine(pLine); + } + } + else + { + pLine = SkipLines(pLine, TOK_ELSE); + while (pLine) + { + if (pLine->eCommand == TOK_END) + { + pLine = pLine->pNext; + break; + } + pLine = RunLine(pLine); + } + } + return pLine; +} + +static KmlLine* RunLine(KmlLine* pLine) +{ + BYTE byVal; + + switch (pLine->eCommand) + { + case TOK_MAP: + if (byVKeyMap[pLine->nParam[0]&0xFF]&1) + PressButtonById((UINT) pLine->nParam[1]); + else + ReleaseButtonById((UINT) pLine->nParam[1]); + break; + case TOK_PRESS: + PressButtonById((UINT) pLine->nParam[0]); + break; + case TOK_RELEASE: + ReleaseButtonById((UINT) pLine->nParam[0]); + break; + case TOK_MENUITEM: + PostMessage(hWnd, WM_COMMAND, 0x19C40+(pLine->nParam[0]&0xFF), 0); + break; + case TOK_SYSITEM: + PostMessage(hWnd, WM_SYSCOMMAND, pLine->nParam[0], 0); + break; + case TOK_SETFLAG: + nKMLFlags |= 1<<(pLine->nParam[0]&0x1F); + break; + case TOK_RESETFLAG: + nKMLFlags &= ~(1<<(pLine->nParam[0]&0x1F)); + break; + case TOK_NOTFLAG: + nKMLFlags ^= 1<<(pLine->nParam[0]&0x1F); + break; + case TOK_IFPRESSED: + return If(pLine,byVKeyMap[pLine->nParam[0]&0xFF]); + case TOK_IFFLAG: + return If(pLine,(nKMLFlags>>(pLine->nParam[0]&0x1F))&1); + case TOK_IFMEM: + Npeek(&byVal,(DWORD) pLine->nParam[0],1); + return If(pLine,(byVal & pLine->nParam[1]) == pLine->nParam[2]); + default: + break; + } + return pLine->pNext; +} + + + +//################ +//# +//# Clean Up +//# +//################ + +static VOID FreeLines(KmlLine* pLine) +{ + while (pLine) + { + KmlLine* pThisLine = pLine; + UINT i = 0; + DWORD nParams; + while (pLexToken[i].nLen) // search in all token definitions + { + // break when token definition found + if (pLexToken[i].eId == pLine->eCommand) break; + i++; // next token definition + } + nParams = pLexToken[i].nParams; // get argument types of command + i = 0; // first parameter + while ((nParams&7)) // argument left + { + if ((nParams&7) == TYPE_STRING) // string type + { + free((LPVOID)pLine->nParam[i]); + } + i++; // incr. parameter buffer index + nParams >>= 3; // next argument type + } + pLine = pLine->pNext; // get next line + free(pThisLine); + } + return; +} + +VOID FreeBlocks(KmlBlock* pBlock) +{ + while (pBlock) + { + KmlBlock* pThisBlock = pBlock; + pBlock = pBlock->pNext; + FreeLines(pThisBlock->pFirstLine); + free(pThisBlock); + } + return; +} + +VOID KillKML(VOID) +{ + if ((nState==SM_RUN)||(nState==SM_SLEEP)) + { + AbortMessage(_T("FATAL: KillKML while emulator is running !!!")); + SwitchToState(SM_RETURN); + DestroyWindow(hWnd); + } + UnmapRom(); + DestroyLcdBitmap(); + DestroyAnnunBitmap(); + DestroyMainBitmap(); + if (hPalette) + { + if (hWindowDC) SelectPalette(hWindowDC, hOldPalette, FALSE); + VERIFY(DeleteObject(hPalette)); + hPalette = NULL; + } + if (hRgn != NULL) // region defined + { + if (hWnd != NULL) // window available + { + EnterCriticalSection(&csGDILock); + { + // deletes the region resource + SetWindowRgn(hWnd,NULL,FALSE); + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + } + hRgn = NULL; + } + LoadIconDefault(); + bClicking = FALSE; + uButtonClicked = 0; + FreeBlocks(pKml); + pKml = NULL; + nButtons = 0; + nScancodes = 0; + nAnnunciators = 0; + bDebug = TRUE; + wKeybLocId = 0; + bLocaleInc = FALSE; + nKMLFlags = 0; + ZeroMemory(pButton, sizeof(pButton)); + ZeroMemory(pAnnunciator, sizeof(pAnnunciator)); + ZeroMemory(pVKey, sizeof(pVKey)); + ZeroMemory(byVKeyMap, sizeof(byVKeyMap)); + ClearLog(); + nBackgroundX = 0; + nBackgroundY = 0; + nBackgroundW = 256; + nBackgroundH = 0; + nLcdZoom = 1; + nGdiXZoom = 1; + nGdiYZoom = 1; + dwTColor = (DWORD) -1; + dwTColorTol = 0; + nScaleMul = 0; + nScaleDiv = 0; + cCurrentRomType = 0; + nCurrentClass = 0; + ResizeWindow(); + return; +} + + + +//################ +//# +//# Extract Keyword's Parameters +//# +//################ + +static LPCTSTR GetStringParam(KmlBlock* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam) +{ + while (pBlock) + { + if (pBlock->eType == eBlock) + { + KmlLine* pLine = pBlock->pFirstLine; + while (pLine) + { + if (pLine->eCommand == eCommand) + { + return (LPCTSTR) pLine->nParam[nParam]; + } + pLine = pLine->pNext; + } + } + pBlock = pBlock->pNext; + } + return NULL; +} + +static DWORD GetIntegerParam(KmlBlock* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam) +{ + while (pBlock) + { + if (pBlock->eType == eBlock) + { + KmlLine* pLine = pBlock->pFirstLine; + while (pLine) + { + if (pLine->eCommand == eCommand) + { + return (DWORD) pLine->nParam[nParam]; + } + pLine = pLine->pNext; + } + } + pBlock = pBlock->pNext; + } + return 0; +} + + + +//################ +//# +//# Buttons +//# +//################ + +static UINT iSqrt(UINT nNumber) // integer y=sqrt(x) function +{ + UINT b, t; + + b = t = nNumber; + + if (nNumber > 0) + { + do + { + b = t; + t = (t + nNumber / t) / 2; // Heron's method + } + while (t < b); + } + return b; +} + +static VOID AdjustPixel(LPBYTE pbyPixel, BYTE byOffset) +{ + INT i = 3; // BGR colors + + while (--i >= 0) + { + WORD wColor = (WORD) *pbyPixel + byOffset; + // jumpless saturation to 0xFF + wColor = -(wColor >> 8) | (BYTE) wColor; + *pbyPixel++ = (BYTE) wColor; + } + return; +} + +// draw transparent circle button type +static __inline VOID TransparentCircle(UINT nOx, UINT nOy, UINT nCx, UINT nCy) +{ + #define HIGHADJ 0x80 // color incr. at center + #define LOWADJ 0x10 // color incr. at border + + BITMAPINFO bmi; + HDC hMemDC; + HBITMAP hMemBitMap; + LPBYTE pbyPixels; // BMP data + + UINT x, y, cx, cy, r, rr, rrc; + + r = min(nCx,nCy) / 2; // radius + if (r < 2) return; // radius 2 pixel minimum + + // create memory copy of button rectangle + ZeroMemory(&bmi,sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); + bmi.bmiHeader.biWidth = (LONG) nCx; + bmi.bmiHeader.biHeight = (LONG) nCy; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; // use 32 bit bitmap for easier buffer calculation + bmi.bmiHeader.biCompression = BI_RGB; + VERIFY(hMemBitMap = CreateDIBSection(hWindowDC, + &bmi, + DIB_RGB_COLORS, + (VOID **)&pbyPixels, + NULL, + 0)); + if (hMemBitMap == NULL) return; + + hMemDC = CreateCompatibleDC(hWindowDC); + hMemBitMap = (HBITMAP) SelectObject(hMemDC,hMemBitMap); + BitBlt(hMemDC, 0, 0, nCx, nCy, hWindowDC, nOx, nOy, SRCCOPY); + + cx = nCx / 2; // x-center coordinate + cy = nCy / 2; // y-center coordinate + + rr = r * r; // calculate r^2 + rrc = (r-1) * (r-1); // calculate (r-1)^2 for color steps + + // y-rows of circle + for (y = 0; y < r; ++y) + { + UINT yy = y * y; // calculate y^2 + + // x-columns of circle + UINT nXWidth = iSqrt(rr-yy); + + for (x = 0; x < nXWidth; ++x) + { + // color offset, sqrt(x*x+y*y) < r !!! + BYTE byOff = HIGHADJ - (BYTE) (iSqrt((x*x+yy) * (HIGHADJ-LOWADJ)*(HIGHADJ-LOWADJ) / rrc)); + + AdjustPixel(pbyPixels + (((cy+y) * bmi.bmiHeader.biWidth + (cx+x)) << 2), byOff); + + if (x != 0) + { + AdjustPixel(pbyPixels + (((cy+y) * bmi.bmiHeader.biWidth + (cx-x)) << 2), byOff); + } + + if (y != 0) + { + AdjustPixel(pbyPixels + (((cy-y) * bmi.bmiHeader.biWidth + (cx+x)) << 2), byOff); + } + + if (x != 0 && y != 0) + { + AdjustPixel(pbyPixels + (((cy-y) * bmi.bmiHeader.biWidth + (cx-x)) << 2), byOff); + } + } + } + + // update button area with modified data + BitBlt(hWindowDC, nOx, nOy, nCx, nCy, hMemDC, 0, 0, SRCCOPY); + + // delete memory bitmap + VERIFY(DeleteObject(SelectObject(hMemDC,hMemBitMap))); + DeleteDC(hMemDC); + return; + + #undef HIGHADJ + #undef LOWADJ +} + +static VOID DrawButton(UINT nId) +{ + UINT x0 = pButton[nId].nOx; + UINT y0 = pButton[nId].nOy; + + EnterCriticalSection(&csGDILock); // solving NT GDI problems + { + switch (pButton[nId].nType) + { + case 0: // bitmap key + if (pButton[nId].bDown) + { + BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, pButton[nId].nDx, pButton[nId].nDy, SRCCOPY); + } + else + { + // update background only + BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); + } + break; + case 1: // shift key to right down + if (pButton[nId].bDown) + { + UINT x1 = x0+pButton[nId].nCx-1; + UINT y1 = y0+pButton[nId].nCy-1; + BitBlt(hWindowDC, x0+3,y0+3,pButton[nId].nCx-5,pButton[nId].nCy-5,hMainDC,x0+2,y0+2,SRCCOPY); + SelectObject(hWindowDC, GetStockObject(BLACK_PEN)); + MoveToEx(hWindowDC, x0, y0, NULL); LineTo(hWindowDC, x1, y0); + MoveToEx(hWindowDC, x0, y0, NULL); LineTo(hWindowDC, x0, y1); + SelectObject(hWindowDC, GetStockObject(WHITE_PEN)); + MoveToEx(hWindowDC, x1, y0, NULL); LineTo(hWindowDC, x1, y1); + MoveToEx(hWindowDC, x0, y1, NULL); LineTo(hWindowDC, x1+1, y1); + } + else + { + BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); + } + break; + case 2: // do nothing + break; + case 3: // invert key color, even in display + if (pButton[nId].bDown) + { + PatBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, DSTINVERT); + } + else + { + RECT Rect; + Rect.left = x0 - nBackgroundX; + Rect.top = y0 - nBackgroundY; + Rect.right = Rect.left + pButton[nId].nCx; + Rect.bottom = Rect.top + pButton[nId].nCy; + InvalidateRect(hWnd, &Rect, FALSE); // call WM_PAINT for background and display redraw + } + break; + case 4: // bitmap key, even in display + if (pButton[nId].bDown) + { + // update background only + BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); + } + else + { + RECT Rect; + Rect.left = x0 - nBackgroundX; + Rect.top = y0 - nBackgroundY; + Rect.right = Rect.left + pButton[nId].nCx; + Rect.bottom = Rect.top + pButton[nId].nCy; + InvalidateRect(hWnd, &Rect, FALSE); // call WM_PAINT for background and display redraw + } + break; + case 5: // transparent circle + if (pButton[nId].bDown) + { + TransparentCircle(x0, y0, pButton[nId].nCx, pButton[nId].nCy); + } + else + { + // update background only + BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); + } + break; + default: // black key, default drawing on illegal types + if (pButton[nId].bDown) + { + PatBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, BLACKNESS); + } + else + { + // update background only + BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); + } + } + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + return; +} + +static VOID PressButton(UINT nId) +{ + if (!pButton[nId].bDown) // button not pressed + { + pButton[nId].bDown = TRUE; + DrawButton(nId); + if (pButton[nId].nIn) + { + KeyboardEvent(TRUE,pButton[nId].nOut,pButton[nId].nIn); + } + else + { + KmlLine* pLine = pButton[nId].pOnDown; + while ((pLine)&&(pLine->eCommand!=TOK_END)) + { + pLine = RunLine(pLine); + } + } + } + return; +} + +static VOID ReleaseButton(UINT nId) +{ + if (pButton[nId].bDown) // button not released + { + pButton[nId].bDown = FALSE; + DrawButton(nId); + if (pButton[nId].nIn) + { + KeyboardEvent(FALSE,pButton[nId].nOut,pButton[nId].nIn); + } + else + { + KmlLine* pLine = pButton[nId].pOnUp; + while ((pLine)&&(pLine->eCommand!=TOK_END)) + { + pLine = RunLine(pLine); + } + } + } + return; +} + +static VOID PressButtonById(UINT nId) +{ + UINT i; + for (i=0; iright > (LONG) (pButton[i].nOx) + && rc->bottom > (LONG) (pButton[i].nOy) + && rc->left <= (LONG) (pButton[i].nOx + pButton[i].nCx) + && rc->top <= (LONG) (pButton[i].nOy + pButton[i].nCy)) + { + // on button type 3 and 5 clear complete key area before drawing + if (pButton[i].nType == 3 || pButton[i].nType == 5) + { + UINT x0 = pButton[i].nOx; + UINT y0 = pButton[i].nOy; + EnterCriticalSection(&csGDILock); // solving NT GDI problems + { + BitBlt(hWindowDC, x0, y0, pButton[i].nCx, pButton[i].nCy, hMainDC, x0, y0, SRCCOPY); + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + } + DrawButton(i); // redraw pressed button + } + } + return; +} + + +//################ +//# +//# Annunciators +//# +//################ + +VOID DrawAnnunciator(UINT nId, BOOL bOn) +{ + HDC hDC; + UINT nSx,nSy; + + --nId; // zero based ID + if (nId >= ARRAYSIZEOF(pAnnunciator)) return; + if (bOn) + { + hDC = hAnnunDC != NULL ? hAnnunDC : hMainDC; + + nSx = pAnnunciator[nId].nDx; // position of annunciator + nSy = pAnnunciator[nId].nDy; + } + else + { + hDC = hMainDC; + + nSx = pAnnunciator[nId].nOx; // position of background + nSy = pAnnunciator[nId].nOy; + } + EnterCriticalSection(&csGDILock); // solving NT GDI problems + { + BitBlt(hWindowDC, + pAnnunciator[nId].nOx, pAnnunciator[nId].nOy, + pAnnunciator[nId].nCx, pAnnunciator[nId].nCy, + hDC, + nSx, nSy, + SRCCOPY); + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + return; +} + + + +//################ +//# +//# Mouse +//# +//################ + +static BOOL ClipButton(UINT x, UINT y, UINT nId) +{ + x += nBackgroundX; // source display offset + y += nBackgroundY; + + return (pButton[nId].nOx<=x) + && (pButton[nId].nOy<=y) + &&(x<(pButton[nId].nOx+pButton[nId].nCx)) + &&(y<(pButton[nId].nOy+pButton[nId].nCy)); +} + +BOOL MouseIsButton(DWORD x, DWORD y) +{ + UINT i; + for (i = 0; i < nButtons; i++) // scan all buttons + { + if (ClipButton(x,y,i)) // cursor over button? + { + return TRUE; + } + } + return FALSE; +} + +VOID MouseButtonDownAt(UINT nFlags, DWORD x, DWORD y) +{ + UINT i; + for (i=0; i hand cursor else normal arrow cursor + SetCursor(MouseIsButton(x,y) ? hCursorHand : hCursorArrow); + + if (!(nFlags&MK_LBUTTON)) return; // left mouse key not pressed -> quit + if (bKeyPressed && !ClipButton(x,y,uLastKeyPressed)) // not on last pressed key + ReleaseAllButtons(); // release all buttons + if (!bClicking) return; // normal emulation key -> quit + + if (pButton[uButtonClicked].dwFlags&BUTTON_NOHOLD) + { + if (ClipButton(x,y, uButtonClicked) != pButton[uButtonClicked].bDown) + { + pButton[uButtonClicked].bDown = !pButton[uButtonClicked].bDown; + DrawButton(uButtonClicked); + } + return; + } + if (pButton[uButtonClicked].dwFlags&BUTTON_VIRTUAL) + { + if (!ClipButton(x,y, uButtonClicked)) + { + ReleaseButton(uButtonClicked); + bClicking = FALSE; + uButtonClicked = 0; + } + return; + } + return; +} + + + +//################ +//# +//# Keyboard +//# +//################ + +VOID RunKey(BYTE nId, BOOL bPressed) +{ + if (pVKey[nId]) + { + KmlLine* pLine = pVKey[nId]->pFirstLine; + byVKeyMap[nId] = (BYTE) bPressed; + while (pLine) pLine = RunLine(pLine); + } + else + { + if (bDebug&&bPressed) + { + TCHAR szTemp[128]; + wsprintf(szTemp,_T("Scancode %i"),nId); + InfoMessage(szTemp); + } + } + return; +} + + + +//################ +//# +//# Macro player +//# +//################ + +VOID PlayKey(UINT nOut, UINT nIn, BOOL bPressed) +{ + // scan from last buttons because LCD buttons mostly defined first + INT i = nButtons; + while (--i >= 0) + { + if (pButton[i].nOut == nOut && pButton[i].nIn == nIn) + { + if (bPressed) + PressButton(i); + else + ReleaseButton(i); + return; + } + } + return; +} + + + +//################ +//# +//# Load and Initialize Script +//# +//################ + +static VOID ResizeMainBitmap(INT nMul, INT nDiv) +{ + if (nMul * nDiv > 0) // resize main picture + { + BITMAP Bitmap; + int nMode; + INT nWidth,nHeight; + UINT i; + + // update graphic + nBackgroundX = MulDiv(nBackgroundX,nMul,nDiv); + nBackgroundY = MulDiv(nBackgroundY,nMul,nDiv); + nBackgroundW = MulDiv(nBackgroundW,nMul,nDiv); + nBackgroundH = MulDiv(nBackgroundH,nMul,nDiv); + nLcdX = MulDiv(nLcdX,nMul,nDiv); + nLcdY = MulDiv(nLcdY,nMul,nDiv); + nGdiXZoom = MulDiv(nGdiXZoom * nLcdZoom,nMul,nDiv); + nGdiYZoom = MulDiv(nGdiYZoom * nLcdZoom,nMul,nDiv); + + // search for memory DC zoom (1-4) + for (nLcdZoom = 4; ((nGdiXZoom % nLcdZoom) | (nGdiYZoom % nLcdZoom)) != 0 ; --nLcdZoom) { }; + _ASSERT(nLcdZoom > 0); // because (nGdiYZoom % 1) == 0 && (nGdiYZoom % 1) == 0 + nGdiXZoom /= nLcdZoom; // remainder is GDI zoom + nGdiYZoom /= nLcdZoom; + + // update script coordinates (buttons) + for (i = 0; i < nButtons; ++i) + { + pButton[i].nOx = (UINT) (pButton[i].nOx * nMul / nDiv); + pButton[i].nOy = (UINT) (pButton[i].nOy * nMul / nDiv); + pButton[i].nDx = (UINT) (pButton[i].nDx * nMul / nDiv); + pButton[i].nDy = (UINT) (pButton[i].nDy * nMul / nDiv); + pButton[i].nCx = (UINT) (pButton[i].nCx * nMul / nDiv); + pButton[i].nCy = (UINT) (pButton[i].nCy * nMul / nDiv); + } + + // update script coordinates (annunciators) + for (i = 0; i < ARRAYSIZEOF(pAnnunciator); ++i) + { + // translate offset + pAnnunciator[i].nOx = (UINT) (pAnnunciator[i].nOx * nMul / nDiv); + pAnnunciator[i].nOy = (UINT) (pAnnunciator[i].nOy * nMul / nDiv); + + if (hAnnunDC == NULL) // no external annunciator bitmap + { + // translate down (with rounding) + pAnnunciator[i].nDx = (UINT) MulDiv(pAnnunciator[i].nDx,nMul,nDiv); + pAnnunciator[i].nDy = (UINT) MulDiv(pAnnunciator[i].nDy,nMul,nDiv); + // translate size (with rounding) + pAnnunciator[i].nCx = (UINT) MulDiv(pAnnunciator[i].nCx,nMul,nDiv); + pAnnunciator[i].nCy = (UINT) MulDiv(pAnnunciator[i].nCy,nMul,nDiv); + } + } + + EnterCriticalSection(&csGDILock); // solving NT GDI problems + { + // get bitmap size + GetObject(GetCurrentObject(hMainDC,OBJ_BITMAP),sizeof(Bitmap),&Bitmap); + + // resulting bitmap size + nWidth = MulDiv(Bitmap.bmWidth,nMul,nDiv); + nHeight = MulDiv(Bitmap.bmHeight,nMul,nDiv); + + VERIFY(nMode = SetStretchBltMode(hMainDC,HALFTONE)); + + if (nMul <= nDiv) // shrinking bitmap + { + VERIFY(StretchBlt( + hMainDC,0,0,nWidth,nHeight, + hMainDC,0,0,Bitmap.bmWidth,Bitmap.bmHeight, + SRCCOPY)); + } + else // expanding bitmap + { + // bitmap with new size + HDC hMemDC = CreateCompatibleDC(hMainDC); + HBITMAP hMainBitMap = CreateCompatibleBitmap(hMainDC,nWidth,nHeight); + HBITMAP hMemBitMap = (HBITMAP) SelectObject(hMemDC,SelectObject(hMainDC,hMainBitMap)); + + VERIFY(StretchBlt( + hMainDC,0,0,nWidth,nHeight, + hMemDC,0,0,Bitmap.bmWidth,Bitmap.bmHeight, + SRCCOPY)); + + // delete original bitmap + VERIFY(DeleteObject(SelectObject(hMemDC,hMemBitMap))); + DeleteDC(hMemDC); + } + + VERIFY(SetStretchBltMode(hMainDC,nMode)); + + GdiFlush(); + } + LeaveCriticalSection(&csGDILock); + ResizeWindow(); + } + return; +} + +static KmlBlock* LoadKMLGlobal(LPCTSTR szFilename) +{ + HANDLE hFile; + LPTSTR lpBuf; + KmlBlock* pBlock; + TokenId eToken; + + SetCurrentDirectory(szEmuDirectory); + hFile = CreateFile(szFilename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + SetCurrentDirectory(szCurrentDirectory); + if (hFile == INVALID_HANDLE_VALUE) return NULL; + if ((lpBuf = MapKMLFile(hFile)) == NULL) + return NULL; + + InitLex(lpBuf); + pBlock = NULL; + while ((eToken = Lex(LEX_BLOCK)) != TOK_NONE) + { + if (eToken == TOK_GLOBAL) + { + pBlock = ParseBlock(TRUE,eToken); + if (pBlock) pBlock->pNext = NULL; + break; + } + if (eToken == TOK_STRING) + { + free(szLexString); + szLexString = NULL; + } + } + CleanLex(); + ClearLog(); + free(lpBuf); + return pBlock; +} + +BOOL InitKML(LPCTSTR szFilename, BOOL bNoLog) +{ + TCHAR szKLID[KL_NAMELENGTH]; + HANDLE hFile; + LPTSTR lpBuf; + KmlBlock* pBlock; + BOOL bOk = FALSE; + + KillKML(); + + // get current keyboard layout input locale + if (GetKeyboardLayoutName(szKLID)) + { + wKeybLocId = (WORD) _tcstoul(szKLID,NULL,16); + } + + nBlocksIncludeLevel = 0; + PrintfToLog(_T("Reading %s"), szFilename); + SetCurrentDirectory(szEmuDirectory); + hFile = CreateFile(szFilename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + SetCurrentDirectory(szCurrentDirectory); + if (hFile == INVALID_HANDLE_VALUE) + { + AddToLog(_T("Error while opening the file.")); + goto quit; + } + if ((lpBuf = MapKMLFile(hFile)) == NULL) + goto quit; + + InitLex(lpBuf); + pKml = ParseBlocks(TRUE, // include blocks + FALSE); // keyword "End" is invalid + CleanLex(); + + free(lpBuf); + if (pKml == NULL) goto quit; + + pBlock = pKml; + while (pBlock) + { + switch (pBlock->eType) + { + case TOK_BUTTON: + InitButton(pBlock); + break; + case TOK_SCANCODE: + nScancodes++; + pVKey[pBlock->nId] = pBlock; + break; + case TOK_ANNUNCIATOR: + InitAnnunciator(pBlock); + break; + case TOK_GLOBAL: + InitGlobal(pBlock); + break; + case TOK_LCD: + InitLcd(pBlock); + break; + case TOK_BACKGROUND: + InitBackground(pBlock); + break; + default: + PrintfToLog(_T("Block %s Ignored."), GetStringOf(pBlock->eType)); + pBlock = pBlock->pNext; + } + pBlock = pBlock->pNext; + } + + if (!isModelValid(cCurrentRomType)) + { + AddToLog(_T("This KML Script doesn't specify a valid model.")); + goto quit; + } + if (pbyRom == NULL) + { + AddToLog(_T("This KML Script doesn't specify the ROM to use, or the ROM could not be loaded.")); + goto quit; + } + if (bRomCrcCorrection) // ROM CRC correction enabled + { + AddToLog(_T("Rebuild the ROM CRC.")); + RebuildRomCrc(); // rebuild the ROM CRC's + } + if (hMainDC == NULL) + { + AddToLog(_T("This KML Script doesn't specify the background bitmap, or bitmap could not be loaded.")); + goto quit; + } + if (!CrcRom(&wRomCrc)) // build patched ROM fingerprint and check for unpacked data + { + AddToLog(_T("Error, packed ROM image detected.")); + goto quit; + } + if (CheckForBeepPatch()) // check if ROM contain beep patches + { + AddToLog(_T("Error, ROM beep patch detected. Remove beep patches please.")); + goto quit; + } + + ResizeMainBitmap(nScaleMul,nScaleDiv); // resize main picture + CreateLcdBitmap(); + + PrintfToLog(_T("%i Buttons Defined"), nButtons); + PrintfToLog(_T("%i Scancodes Defined"), nScancodes); + PrintfToLog(_T("%i Annunciators Defined"), nAnnunciators); + PrintfToLog(_T("Keyboard Locale: %i"), wKeybLocId); + + bOk = TRUE; + +quit: + if (bOk) + { + // HP38G/HP39G/HP40G have no object loading, ignore + DragAcceptFiles(hWnd,cCurrentRomType != '6' && cCurrentRomType != 'A' && cCurrentRomType != 'E'); + + if (!bNoLog) + { + AddToLog(_T("Press Ok to Continue.")); + if (bAlwaysDisplayLog&&(!DisplayKMLLog(bOk))) + { + KillKML(); + return FALSE; + } + } + } + else + { + AddToLog(_T("Press Cancel to Abort.")); + if (!DisplayKMLLog(bOk)) + { + KillKML(); + return FALSE; + } + } + + ResizeWindow(); + ClearLog(); + return bOk; +} diff --git a/Sources/Emu48/kml.h b/Sources/Emu48/KML.H similarity index 95% rename from Sources/Emu48/kml.h rename to Sources/Emu48/KML.H index 2a0eccf..ced8be5 100644 --- a/Sources/Emu48/kml.h +++ b/Sources/Emu48/KML.H @@ -1,133 +1,133 @@ -/* - * kml.h - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ - -#define LEX_BLOCK 0 -#define LEX_COMMAND 1 -#define LEX_PARAM 2 - -typedef enum eTokenId -{ - TOK_NONE, //0 - TOK_ANNUNCIATOR, //1 - TOK_BACKGROUND, //2 - TOK_IFPRESSED, //3 - TOK_RESETFLAG, //4 - TOK_SCANCODE, //5 - TOK_HARDWARE, //6 - TOK_MENUITEM, //7 - TOK_SYSITEM, //8 - TOK_INTEGER, //9 - TOK_SETFLAG, //10 - TOK_RELEASE, //11 - TOK_VIRTUAL, //12 - TOK_INCLUDE, //13 - TOK_NOTFLAG, //14 - TOK_STRING, //15 - TOK_GLOBAL, //16 - TOK_AUTHOR, //17 - TOK_BITMAP, //18 - TOK_ZOOMXY, //19 - TOK_OFFSET, //20 - TOK_BUTTON, //21 - TOK_IFFLAG, //22 - TOK_ONDOWN, //23 - TOK_NOHOLD, //24 - TOK_LOCALE, //25 - TOK_TOPBAR, //26 - TOK_MENUBAR, //27 - TOK_TITLE, //28 - TOK_OUTIN, //29 - TOK_PATCH, //30 - TOK_PRINT, //31 - TOK_DEBUG, //32 - TOK_COLOR, //33 - TOK_MODEL, //34 - TOK_CLASS, //35 - TOK_PRESS, //36 - TOK_IFMEM, //37 - TOK_SCALE, //38 - TOK_TYPE, //39 - TOK_SIZE, //40 - TOK_DOWN, //41 - TOK_ZOOM, //42 - TOK_ELSE, //43 - TOK_ONUP, //44 - TOK_ICON, //45 - TOK_EOL, //46 - TOK_MAP, //47 - TOK_ROM, //48 - TOK_VGA, //49 - TOK_LCD, //50 - TOK_END //51 -} TokenId; - -#define TYPE_NONE 00 -#define TYPE_INTEGER 01 -#define TYPE_STRING 02 - -typedef struct KmlToken -{ - TokenId eId; - DWORD nParams; - DWORD nLen; - LPCTSTR szName; -} KmlToken; - -typedef struct KmlLine -{ - struct KmlLine* pNext; - TokenId eCommand; - DWORD_PTR nParam[6]; -} KmlLine; - -typedef struct KmlBlock -{ - TokenId eType; - DWORD nId; - struct KmlLine* pFirstLine; - struct KmlBlock* pNext; -} KmlBlock; - -#define BUTTON_NOHOLD 0x0001 -#define BUTTON_VIRTUAL 0x0002 -typedef struct KmlButton -{ - UINT nId; - BOOL bDown; - UINT nType; - DWORD dwFlags; - UINT nOx, nOy; - UINT nDx, nDy; - UINT nCx, nCy; - UINT nOut, nIn; - KmlLine* pOnDown; - KmlLine* pOnUp; -} KmlButton; - -typedef struct KmlAnnunciator -{ - UINT nOx, nOy; - UINT nDx, nDy; - UINT nCx, nCy; -} KmlAnnunciator; - -extern KmlBlock* pKml; -extern BOOL DisplayChooseKml(CHAR cType); -extern VOID FreeBlocks(KmlBlock* pBlock); -extern VOID DrawAnnunciator(UINT nId, BOOL bOn); -extern VOID ReloadButtons(BYTE *Keyboard_Row, UINT nSize); -extern VOID RefreshButtons(RECT *rc); -extern BOOL MouseIsButton(DWORD x, DWORD y); -extern VOID MouseButtonDownAt(UINT nFlags, DWORD x, DWORD y); -extern VOID MouseButtonUpAt(UINT nFlags, DWORD x, DWORD y); -extern VOID MouseMovesTo(UINT nFlags, DWORD x, DWORD y); -extern VOID RunKey(BYTE nId, BOOL bPressed); -extern VOID PlayKey(UINT nOut, UINT nIn, BOOL bPressed); -extern BOOL InitKML(LPCTSTR szFilename, BOOL bNoLog); -extern VOID KillKML(VOID); +/* + * kml.h + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ + +#define LEX_BLOCK 0 +#define LEX_COMMAND 1 +#define LEX_PARAM 2 + +typedef enum eTokenId +{ + TOK_NONE, //0 + TOK_ANNUNCIATOR, //1 + TOK_BACKGROUND, //2 + TOK_IFPRESSED, //3 + TOK_RESETFLAG, //4 + TOK_SCANCODE, //5 + TOK_HARDWARE, //6 + TOK_MENUITEM, //7 + TOK_SYSITEM, //8 + TOK_INTEGER, //9 + TOK_SETFLAG, //10 + TOK_RELEASE, //11 + TOK_VIRTUAL, //12 + TOK_INCLUDE, //13 + TOK_NOTFLAG, //14 + TOK_STRING, //15 + TOK_GLOBAL, //16 + TOK_AUTHOR, //17 + TOK_BITMAP, //18 + TOK_ZOOMXY, //19 + TOK_OFFSET, //20 + TOK_BUTTON, //21 + TOK_IFFLAG, //22 + TOK_ONDOWN, //23 + TOK_NOHOLD, //24 + TOK_LOCALE, //25 + TOK_TOPBAR, //26 + TOK_MENUBAR, //27 + TOK_TITLE, //28 + TOK_OUTIN, //29 + TOK_PATCH, //30 + TOK_PRINT, //31 + TOK_DEBUG, //32 + TOK_COLOR, //33 + TOK_MODEL, //34 + TOK_CLASS, //35 + TOK_PRESS, //36 + TOK_IFMEM, //37 + TOK_SCALE, //38 + TOK_TYPE, //39 + TOK_SIZE, //40 + TOK_DOWN, //41 + TOK_ZOOM, //42 + TOK_ELSE, //43 + TOK_ONUP, //44 + TOK_ICON, //45 + TOK_EOL, //46 + TOK_MAP, //47 + TOK_ROM, //48 + TOK_VGA, //49 + TOK_LCD, //50 + TOK_END //51 +} TokenId; + +#define TYPE_NONE 00 +#define TYPE_INTEGER 01 +#define TYPE_STRING 02 + +typedef struct KmlToken +{ + TokenId eId; + DWORD nParams; + DWORD nLen; + LPCTSTR szName; +} KmlToken; + +typedef struct KmlLine +{ + struct KmlLine* pNext; + TokenId eCommand; + DWORD_PTR nParam[6]; +} KmlLine; + +typedef struct KmlBlock +{ + TokenId eType; + DWORD nId; + struct KmlLine* pFirstLine; + struct KmlBlock* pNext; +} KmlBlock; + +#define BUTTON_NOHOLD 0x0001 +#define BUTTON_VIRTUAL 0x0002 +typedef struct KmlButton +{ + UINT nId; + BOOL bDown; + UINT nType; + DWORD dwFlags; + UINT nOx, nOy; + UINT nDx, nDy; + UINT nCx, nCy; + UINT nOut, nIn; + KmlLine* pOnDown; + KmlLine* pOnUp; +} KmlButton; + +typedef struct KmlAnnunciator +{ + UINT nOx, nOy; + UINT nDx, nDy; + UINT nCx, nCy; +} KmlAnnunciator; + +extern KmlBlock* pKml; +extern BOOL DisplayChooseKml(CHAR cType); +extern VOID FreeBlocks(KmlBlock* pBlock); +extern VOID DrawAnnunciator(UINT nId, BOOL bOn); +extern VOID ReloadButtons(BYTE *Keyboard_Row, UINT nSize); +extern VOID RefreshButtons(RECT *rc); +extern BOOL MouseIsButton(DWORD x, DWORD y); +extern VOID MouseButtonDownAt(UINT nFlags, DWORD x, DWORD y); +extern VOID MouseButtonUpAt(UINT nFlags, DWORD x, DWORD y); +extern VOID MouseMovesTo(UINT nFlags, DWORD x, DWORD y); +extern VOID RunKey(BYTE nId, BOOL bPressed); +extern VOID PlayKey(UINT nOut, UINT nIn, BOOL bPressed); +extern BOOL InitKML(LPCTSTR szFilename, BOOL bNoLog); +extern VOID KillKML(VOID); diff --git a/Sources/Emu48/lodepng.c b/Sources/Emu48/LODEPNG.C similarity index 99% rename from Sources/Emu48/lodepng.c rename to Sources/Emu48/LODEPNG.C index 2c807ef..e0dcdd2 100644 --- a/Sources/Emu48/lodepng.c +++ b/Sources/Emu48/LODEPNG.C @@ -664,7 +664,7 @@ which is possible in case of only 0 or 1 present symbols. */ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) { static const unsigned headsize = 1u << FIRSTBITS; /*size of the first table*/ static const unsigned mask = (1u << FIRSTBITS) /*headsize*/ - 1u; - unsigned i, numpresent, pointer, size; /*total table size*/ + size_t i, numpresent, pointer, size; /*total table size*/ unsigned* maxlens = (unsigned*)lodepng_malloc(headsize * sizeof(unsigned)); if(!maxlens) return 83; /*alloc fail*/ @@ -683,7 +683,7 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) { size = headsize; for(i = 0; i < headsize; ++i) { unsigned l = maxlens[i]; - if(l > FIRSTBITS) size += (1u << (l - FIRSTBITS)); + if(l > FIRSTBITS) size += (((size_t)1) << (l - FIRSTBITS)); } tree->table_len = (unsigned char*)lodepng_malloc(size * sizeof(*tree->table_len)); tree->table_value = (unsigned short*)lodepng_malloc(size * sizeof(*tree->table_value)); @@ -701,8 +701,8 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) { unsigned l = maxlens[i]; if(l <= FIRSTBITS) continue; tree->table_len[i] = l; - tree->table_value[i] = pointer; - pointer += (1u << (l - FIRSTBITS)); + tree->table_value[i] = (unsigned short)pointer; + pointer += (((size_t)1) << (l - FIRSTBITS)); } lodepng_free(maxlens); @@ -726,7 +726,7 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) { unsigned index = reverse | (j << l); if(tree->table_len[index] != 16) return 55; /*invalid tree: long symbol shares prefix with short symbol*/ tree->table_len[index] = l; - tree->table_value[index] = i; + tree->table_value[index] = (unsigned short)i; } } else { /*long symbol, shares prefix with other long symbols in first lookup table, needs second lookup*/ @@ -743,7 +743,7 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) { unsigned reverse2 = reverse >> FIRSTBITS; /* l - FIRSTBITS bits */ unsigned index2 = start + (reverse2 | (j << (l - FIRSTBITS))); tree->table_len[index2] = l; - tree->table_value[index2] = i; + tree->table_value[index2] = (unsigned short)i; } } } @@ -2886,7 +2886,7 @@ static unsigned lodepng_chunk_createv(ucvector* out, } unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, - unsigned length, const char* type, const unsigned char* data) { + size_t length, const char* type, const unsigned char* data) { ucvector v = ucvector_init(*out, *outsize); unsigned error = lodepng_chunk_createv(&v, length, type, data); *out = v.data; @@ -3363,7 +3363,7 @@ unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) { static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) { unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ - unsigned p = (unsigned)index & m; + unsigned p = (unsigned) index & m; in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ in = in << (bits * (m - p)); if(p == 0) out[index * bits / 8u] = in; @@ -5889,7 +5889,7 @@ static size_t ilog2i(size_t i) { l = ilog2(i); /* approximate i*log2(i): l is integer logarithm, ((i - (1u << l)) << 1u) linearly approximates the missing fractional part multiplied by i */ - return i * l + ((i - ((size_t) 1u << l)) << 1u); + return i * l + ((i - (((size_t)1) << l)) << 1u); } static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, diff --git a/Sources/Emu48/lodepng.h b/Sources/Emu48/LODEPNG.H similarity index 99% rename from Sources/Emu48/lodepng.h rename to Sources/Emu48/LODEPNG.H index 81d4985..3f3649d 100644 --- a/Sources/Emu48/lodepng.h +++ b/Sources/Emu48/LODEPNG.H @@ -1001,7 +1001,7 @@ and data separately. The type is a 4-letter string. The out variable and outsize are updated to reflect the new reallocated buffer. Returne error code (0 if it went ok) */ -unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length, +unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, size_t length, const char* type, const unsigned char* data); diff --git a/Sources/Emu48/lowbat.c b/Sources/Emu48/LOWBAT.C similarity index 95% rename from Sources/Emu48/lowbat.c rename to Sources/Emu48/LOWBAT.C index 67ceb27..adfc75d 100644 --- a/Sources/Emu48/lowbat.c +++ b/Sources/Emu48/LOWBAT.C @@ -1,122 +1,122 @@ -/* - * lowbat.c - * - * This file is part of Emu48 - * - * Copyright (C) 2006 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" -#include "io.h" // I/O definitions - -// #define BAT_SIMULATION // switch low bat simulation - -#define BAT_FREQ (60*1000) // bat update time in ms (real machine = 60us, HP28C = 60s) - -BOOL bLowBatDisable = FALSE; - -static HANDLE hCThreadBat = NULL; -static HANDLE hEventBat; - -static DWORD WINAPI LowBatThread(LPVOID pParam) -{ - BOOL bLBI,bVLBI; - - do - { - GetBatteryState(&bLBI,&bVLBI); // get battery state - - // very low bat detection - bVLBI = bVLBI && (Chipset.IORam[LPE] & EVLBI) != 0; - - IOBit(LPD,VLBI,bVLBI); // set VLBI - IOBit(SRQ1,VSRQ,bVLBI); // and service bit - - if (bVLBI) // VLBI detected - { - Chipset.SoftInt = TRUE; - bInterrupt = TRUE; - - if (Chipset.Shutdn) // CPU shut down - { - Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode - SetEvent(hEventShutdn); // wake up emulation thread - } - } - } - while (WaitForSingleObject(hEventBat,BAT_FREQ) == WAIT_TIMEOUT); - - return 0; - UNREFERENCED_PARAMETER(pParam); -} - -VOID StartBatMeasure(VOID) -{ - DWORD dwThreadId; - - if (hCThreadBat) // Bat measuring thread running - return; // -> quit - - // event to cancel Bat refresh loop - hEventBat = CreateEvent(NULL,FALSE,FALSE,NULL); - - VERIFY(hCThreadBat = CreateThread(NULL,0,&LowBatThread,NULL,0,&dwThreadId)); - return; -} - -VOID StopBatMeasure(VOID) -{ - if (hCThreadBat == NULL) // thread stopped - return; // -> quit - - SetEvent(hEventBat); // leave Bat update thread - WaitForSingleObject(hCThreadBat,INFINITE); - CloseHandle(hCThreadBat); - hCThreadBat = NULL; // set flag Bat update stopped - CloseHandle(hEventBat); // close Bat event - return; -} - -VOID GetBatteryState(BOOL *pbLBI, BOOL *pbVLBI) -{ -#if defined BAT_SIMULATION - switch (GetPrivateProfileInt(_T("LowBat"),_T("Level"),2,_T(".\\Lowbat.ini"))) - { - case 0: // empty - *pbLBI = TRUE; - *pbVLBI = TRUE; - break; - case 1: // low - *pbLBI = TRUE; - *pbVLBI = FALSE; - break; - default: // full - *pbLBI = FALSE; - *pbVLBI = FALSE; - break; - } -#else - SYSTEM_POWER_STATUS sSps; - - *pbLBI = FALSE; // no battery warning - *pbVLBI = FALSE; - - VERIFY(GetSystemPowerStatus(&sSps)); - - // low bat emulation enabled and battery powered - if (!bLowBatDisable && sSps.ACLineStatus == AC_LINE_OFFLINE) - { - // on critical battery state make sure that lowbat flag is also set - if ((sSps.BatteryFlag & BATTERY_FLAG_CRITICAL) != 0) - sSps.BatteryFlag |= BATTERY_FLAG_LOW; - - // low bat detection - *pbLBI = ((sSps.BatteryFlag & BATTERY_FLAG_LOW) != 0); - - // very low bat detection - *pbVLBI = ((sSps.BatteryFlag & BATTERY_FLAG_CRITICAL) != 0); - } -#endif - return; -} +/* + * lowbat.c + * + * This file is part of Emu48 + * + * Copyright (C) 2006 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" +#include "io.h" // I/O definitions + +// #define BAT_SIMULATION // switch low bat simulation + +#define BAT_FREQ (60*1000) // bat update time in ms (real machine = 60us, HP28C = 60s) + +BOOL bLowBatDisable = FALSE; + +static HANDLE hCThreadBat = NULL; +static HANDLE hEventBat; + +static DWORD WINAPI LowBatThread(LPVOID pParam) +{ + BOOL bLBI,bVLBI; + + do + { + GetBatteryState(&bLBI,&bVLBI); // get battery state + + // very low bat detection + bVLBI = bVLBI && (Chipset.IORam[LPE] & EVLBI) != 0; + + IOBit(LPD,VLBI,bVLBI); // set VLBI + IOBit(SRQ1,VSRQ,bVLBI); // and service bit + + if (bVLBI) // VLBI detected + { + Chipset.SoftInt = TRUE; + bInterrupt = TRUE; + + if (Chipset.Shutdn) // CPU shut down + { + Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode + SetEvent(hEventShutdn); // wake up emulation thread + } + } + } + while (WaitForSingleObject(hEventBat,BAT_FREQ) == WAIT_TIMEOUT); + + return 0; + UNREFERENCED_PARAMETER(pParam); +} + +VOID StartBatMeasure(VOID) +{ + DWORD dwThreadId; + + if (hCThreadBat) // Bat measuring thread running + return; // -> quit + + // event to cancel Bat refresh loop + hEventBat = CreateEvent(NULL,FALSE,FALSE,NULL); + + VERIFY(hCThreadBat = CreateThread(NULL,0,&LowBatThread,NULL,0,&dwThreadId)); + return; +} + +VOID StopBatMeasure(VOID) +{ + if (hCThreadBat == NULL) // thread stopped + return; // -> quit + + SetEvent(hEventBat); // leave Bat update thread + WaitForSingleObject(hCThreadBat,INFINITE); + CloseHandle(hCThreadBat); + hCThreadBat = NULL; // set flag Bat update stopped + CloseHandle(hEventBat); // close Bat event + return; +} + +VOID GetBatteryState(BOOL *pbLBI, BOOL *pbVLBI) +{ +#if defined BAT_SIMULATION + switch (GetPrivateProfileInt(_T("LowBat"),_T("Level"),2,_T(".\\Lowbat.ini"))) + { + case 0: // empty + *pbLBI = TRUE; + *pbVLBI = TRUE; + break; + case 1: // low + *pbLBI = TRUE; + *pbVLBI = FALSE; + break; + default: // full + *pbLBI = FALSE; + *pbVLBI = FALSE; + break; + } +#else + SYSTEM_POWER_STATUS sSps; + + *pbLBI = FALSE; // no battery warning + *pbVLBI = FALSE; + + VERIFY(GetSystemPowerStatus(&sSps)); + + // low bat emulation enabled and battery powered + if (!bLowBatDisable && sSps.ACLineStatus == AC_LINE_OFFLINE) + { + // on critical battery state make sure that lowbat flag is also set + if ((sSps.BatteryFlag & BATTERY_FLAG_CRITICAL) != 0) + sSps.BatteryFlag |= BATTERY_FLAG_LOW; + + // low bat detection + *pbLBI = ((sSps.BatteryFlag & BATTERY_FLAG_LOW) != 0); + + // very low bat detection + *pbVLBI = ((sSps.BatteryFlag & BATTERY_FLAG_CRITICAL) != 0); + } +#endif + return; +} diff --git a/Sources/Emu48/mops.c b/Sources/Emu48/MOPS.C similarity index 96% rename from Sources/Emu48/mops.c rename to Sources/Emu48/MOPS.C index b5b2643..5719467 100644 --- a/Sources/Emu48/mops.c +++ b/Sources/Emu48/MOPS.C @@ -1,1830 +1,1830 @@ -/* - * mops.c - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ -#include "pch.h" -#include "emu48.h" -#include "ops.h" -#include "opcodes.h" -#include "io.h" -#include "i28f160.h" // flash support - -// #define DEBUG_SERIAL // switch for SERIAL debug purpose -// #define DEBUG_IO // switch for I/O debug purpose -// #define DEBUG_FLASH // switch for FLASH MEMORY debug purpose - -// defines for reading an open data bus -#define READEVEN 0x0D -#define READODD 0x0E - -// on mapping boundary adjusted base addresses -#define P0MAPBASE ((BYTE)(Chipset.P0Base & ~Chipset.P0Size)) -#define P1MAPBASE ((BYTE)(Chipset.P1Base & ~Chipset.P1Size)) -#define P2MAPBASE ((BYTE)(Chipset.P2Base & ~Chipset.P2Size)) -#define BSMAPBASE ((BYTE)(Chipset.BSBase & ~Chipset.BSSize)) - -BOOL bFlashRomArray = TRUE; // flag ROM mode - -BYTE disp = 0; // flag for update display area - -static LPBYTE pbyRomView[2] = {NULL, NULL}; // HP49G ROM views - -static __inline UINT MIN(UINT a, UINT b) -{ - return (ab)?a:b; -} - -// generate UCK signal -static __inline BYTE UckBit(BYTE byBaudIndex) -{ - // table content = baudrate * 16 - const DWORD dwBaudrates[] = { 19200, 30720, 38400, 61440, 76800, 122880, 153600, 245760 }; - - LARGE_INTEGER lLC; - - _ASSERT(byBaudIndex < ARRAYSIZEOF(dwBaudrates)); - - if ((Chipset.IORam[IOC] & SON) == 0) // UART off - return UCK; // UCK bit always set - - QueryPerformanceCounter(&lLC); // get counter value - - // calculate UCK frequency - return (((BYTE)(((lLC.QuadPart - lAppStart.QuadPart) * dwBaudrates[byBaudIndex]) - / lFreq.QuadPart) & 0x1) << 3); -} - -// calculate nibble based linear flash address -static __inline DWORD FlashROMAddr(DWORD d) -{ - DWORD dwLinAddr; - - // 6 bit of latch (was A6-A1 of address bus) - dwLinAddr = (Chipset.Bank_FF >> 1) & 0x3f; - // decode A21-A18 - dwLinAddr = ((d & 0x40000) ? (dwLinAddr & 0xf) : (dwLinAddr >> 4)) << 18; - // decode A21-A18, A17-A0 - dwLinAddr |= d & 0x3FFFF; - return dwLinAddr; -} - -// update display -static __inline VOID UpdateDisplay(DWORD d, UINT s) -{ - BYTE p[16]; - DWORD u; - UINT c; - - // address in display main area? - if ((dChipset.start12)) - { - // write to display main area - u = d; // copy destination ptr - c = MIN(s,Chipset.end1-d); // number of nibbles to copy - - if (d < Chipset.start12) // first address is out of display area - { - u = Chipset.start12; // set destination ptr to start of display area - c -= Chipset.start12 - d; // - number of bytes that aren't in display area - } - - _ASSERT(c <= ARRAYSIZEOF(p)); - Npeek(p,u,c); // get source data - WriteToMainDisplay(p,u,c); - } - // address in display menu area? - if ((dChipset.start2)) - { - // write to display menu area - u = d; // copy destination ptr - c = MIN(s,Chipset.end2-d); // number of nibbles to copy - - if (d < Chipset.start2) // first address is out of display area - { - u = Chipset.start2; // set destination ptr to start of display area - c -= Chipset.start2 - d; // - number of bytes that are not in display area - } - - _ASSERT(c <= ARRAYSIZEOF(p)); - Npeek(p,u,c); // get source data - WriteToMenuDisplay(p,u,c); - } - return; -} - -// port mapping - -LPBYTE RMap[256] = {NULL,}; -LPBYTE WMap[256] = {NULL,}; - -static VOID MapP0(BYTE a, BYTE b) -{ - UINT i; - DWORD p, m; - - a = (BYTE)MAX(a,P0MAPBASE); // adjust base to mapping boundary - b = (BYTE)MIN(b,Chipset.P0End); - m = (Chipset.Port0Size*2048)-1; - p = (a<<12)&m; // offset to begin of P0 in nibbles - for (i=a; i<=b; i++) - { - // mapping area may have holes - if (((i ^ Chipset.P0Base) & ~Chipset.P0Size) == 0) - { - RMap[i]=Port0 + p; - WMap[i]=Port0 + p; - } - p = (p+0x1000)&m; - } - return; -} - -static VOID MapBS(BYTE a, BYTE b) -{ - UINT i; - - a = (BYTE)MAX(a,BSMAPBASE); // adjust base to mapping boundary - b = (BYTE)MIN(b,Chipset.BSEnd); - for (i=a;i<=b;i++) - { - // mapping area may have holes - if (((i ^ Chipset.BSBase) & ~Chipset.BSSize) == 0) - { - RMap[i]=NULL; // no read cycle, open data bus - WMap[i]=NULL; - } - } - return; -} - -static VOID MapP1(BYTE a, BYTE b) -{ - UINT i; - DWORD p, m; - - // clear mapping area if port1 is configured but not plugged - a = (BYTE)MAX(a,P1MAPBASE); // lowest address for use is P1Base - b = (BYTE)MIN(b,Chipset.P1End); // highest address for use is P1End - - // port1 not plugged - if (Port1 == NULL || !(Chipset.cards_status & PORT1_PRESENT)) - { - for (i=a; i<=b; i++) // scan each 2KB page - { - if (((i ^ Chipset.P1Base) & ~Chipset.P1Size) == 0) - { - RMap[i]=NULL; - WMap[i]=NULL; - } - } - return; - } - - m = (Chipset.Port1Size*2048)-1; // real size of module, address mask for mirroring - p = (a<<12)&m; // offset to begin of P1 in nibbles - - if (Chipset.cards_status & PORT1_WRITE) // port1 write enabled - { - for (i=a; i<=b; i++) // scan each 2KB page - { - // mapping area may have holes - if (((i ^ Chipset.P1Base) & ~Chipset.P1Size) == 0) - { - RMap[i]=Port1 + p; // save page address for read - WMap[i]=Port1 + p; // save page address for write - } - p = (p+0x1000)&m; // next page, mirror page if real size smaller allocated size - } - } - else // port1 read only - { - for (i=a; i<=b; i++) // scan each 2KB page - { - // mapping area may have holes - if (((i ^ Chipset.P1Base) & ~Chipset.P1Size) == 0) - { - RMap[i]=Port1 + p; // save page address for read - WMap[i]=NULL; // no writing - } - p = (p+0x1000)&m; // next page, mirror page if real size smaller allocated size - } - } - return; -} - -static VOID MapP2(BYTE a, BYTE b) -{ - UINT i; - DWORD p, m; - LPBYTE pbyTemp; - - // clear mapping area if port2 is configured but not plugged - a = (BYTE)MAX(a,P2MAPBASE); // adjust base to mapping boundary - b = (BYTE)MIN(b,Chipset.P2End); - - if (Chipset.Port2Size) // internal port2 - { - m = (Chipset.Port2Size*2048)-1; - p = (a<<12)&m; // offset to begin of P0 in nibbles - for (i=a; i<=b; i++) - { - // mapping area may have holes - if (((i ^ Chipset.P2Base) & ~Chipset.P2Size) == 0) - { - RMap[i]=Port2 + p; - WMap[i]=Port2 + p; - } - p = (p+0x1000)&m; - } - return; - } - - // HP48SX / HP48GX - // only fill mapping table when CE2.2 is set - for (i=a; i<=b; i++) // fill mapping area with not configured - { - // mapping area may have holes - if (((i ^ Chipset.P2Base) & ~Chipset.P2Size) == 0) - { - RMap[i]=NULL; - WMap[i]=NULL; - } - } - - // port2 not plugged - if (pbyPort2 == NULL || !(Chipset.cards_status & PORT2_PRESENT)) - return; - - pbyTemp = pbyPort2; - if (cCurrentRomType != 'S') // bank switching only with GX - { - // Chipset.Port2_Bank is the saved port2 FF content - pbyTemp += (((Chipset.Bank_FF>>1)-1)&dwPort2Mask) << 18; - } - - // max. size per bank is 128KB - m = (dwPort2Size > 128) ? 128 : dwPort2Size; - - m = (m * 2048) - 1; // real size of module, address mask for mirroring - p = (a << 12) & m; // offset to begin of P2 in nibbles - - // SX: CE2.2 = CE2 - // GX: CE2.2 = BEN & /DA19 & /NCE3 - if (cCurrentRomType == 'S' || ((Chipset.IORam[0x29]&DA19) == 0 && (Chipset.Bank_FF&0x40))) - { - if (bPort2Writeable) - { - for (i=a; i<=b; i++) - { - // mapping area may have holes - if (((i ^ Chipset.P2Base) & ~Chipset.P2Size) == 0) - { - RMap[i]=pbyTemp + p; - WMap[i]=pbyTemp + p; - } - p = (p+0x1000)&m; - } - } - else - { - for (i=a; i<=b; i++) - { - // mapping area may have holes - if (((i ^ Chipset.P2Base) & ~Chipset.P2Size) == 0) - { - RMap[i]=pbyTemp + p; - } - p = (p+0x1000)&m; - } - } - } - return; -} - -static VOID MapROM(BYTE a, BYTE b) -{ - UINT i; - DWORD p, m; - - // HP39/49G, HP49G - if (cCurrentRomType == 'E' || cCurrentRomType == 'X') - { - if (bFlashRomArray) // view flash ROM data - { - _ASSERT(pbyRomView[0]); // check ROM bank set - _ASSERT(pbyRomView[1]); - - m = (128*1024*2)-1; // mapped in 128KB pages - p = (a<<12)&m; // offset to the begin of ROM in nibbles - for (i=a; i<=b; i++) // scan each 2KB page - { - RMap[i]=pbyRomView[(i & 0x40)!=0] + p; - WMap[i]=NULL; // no writing - p = (p+0x1000)&m; - } - } - else // view flash ROM register - { - for (i=a; i<=b; i++) // scan each 2KB page - { - RMap[i]=NULL; // view flash register - WMap[i]=NULL; // no writing - } - } - return; - } - - // HP38G / HP48SX / HP48GX - m = dwRomSize - 1; // ROM address mask for mirroring - // when 512KB ROM and DA19=0 (ROM disabled) - if ((m & 0x80000) != 0 && (Chipset.IORam[0x29]&DA19) == 0) - m >>= 1; // mirror ROM at #80000 (AR18=0) - p = (a*0x1000)&m; // data offset in nibbles - for (i=a;i<=b;i++) // scan each 2KB page - { - RMap[i]=pbyRom + p; // save page address for read - WMap[i]=NULL; // no writing - p = (p+0x1000)&m; // next page, mirror page if real size smaller allocated size - } - return; -} - -VOID Map(BYTE a, BYTE b) // maps 2KB pages with priority -{ - // On HP39/40G and HP49G Chipset.cards_status must be 0xF - _ASSERT((cCurrentRomType!='E' && cCurrentRomType!='X') || !Chipset.P1Cfig || Chipset.cards_status == 0xF); - - // priority order is HDW, RAM, CE2, CE1, NCE3, ROM - MapROM(a,b); // ROM, lowest priority, always mapped - if (cCurrentRomType == 'S') // HP48SX - { - if (Chipset.BSCfig) MapBS(a,b); // NCE3, not used in S(X) - if (Chipset.P1Cfig) MapP1(a,b); // CE1, port1 (lower priority than CE2) - if (Chipset.P2Cfig) MapP2(a,b); // CE2, port2 (higher priority than CE1) - } - else // HP48GX / HP49G - { - if (Chipset.P2Cfig) // NCE3, port2 - { - // LED bit set on a HP49 - if (cCurrentRomType=='X' && (Chipset.IORam[LCR]&LED)) - MapROM(a,b); // NCE3, ROM - else - MapP2(a,b); // NCE3, port2 - } - if (Chipset.BSCfig) MapBS(a,b); // CE1, bank select (lower priority than CE2) - if (Chipset.P1Cfig) MapP1(a,b); // CE2, port1 (higher priority than CE1) - } - if (Chipset.P0Cfig) MapP0(a,b); // RAM, highest priority (execpt HDW) - return; -} - -VOID RomSwitch(DWORD adr) -{ - // only HP39/40G, HP49G - if (cCurrentRomType=='E' || cCurrentRomType=='X') - { - Chipset.Bank_FF = adr; // save address line - adr = (adr >> 1) & 0x3f; // 6 bit of latch (was A6-A1 of address bus) - // lower 4 bit (16 banks) for 2nd ROM view - pbyRomView[1] = pbyRom + (((adr & 0xf) * 128 * 1024 * 2) & (dwRomSize - 1)); - // higher 2 bit (4 banks) for 1st ROM view - pbyRomView[0] = pbyRom + (((adr >> 4) * 128 * 1024 * 2) & (dwRomSize - 1)); - } - Map(0x00,0xFF); // update memory mapping - return; -} - -//////////////////////////////////////////////////////////////////////////////// -// -// Bus Commands -// -//////////////////////////////////////////////////////////////////////////////// - -VOID Config() // configure modules in fixed order -{ - DWORD d = Npack(Chipset.C,5); // decode size or address - BYTE b = (BYTE)(d>>12); // number of 2KB pages or page address - BYTE s = (BYTE)(b^0xFF); // size in pages-1, offset to last page - - // config order is HDW, RAM, CE1, CE2, NCE3 - if (!Chipset.IOCfig) // address of HDW, first module, ROM always configured - { - Chipset.IOCfig = TRUE; - Chipset.IOBase = d&0xFFFC0; // save HDW base on a 64 nib boundary - Map(b,b); - return; - } - if (!Chipset.P0Cfg2) // RAM size, port0 - { - Chipset.P0Cfg2 = TRUE; - Chipset.P0Size = s; // offset to last used page - return; - } - if (!Chipset.P0Cfig) // RAM address, port0 - { - Chipset.P0Cfig = TRUE; - Chipset.P0Base = b; // save first page address - b &= ~Chipset.P0Size; // adjust base to mapping boundary - Chipset.P0End = b+Chipset.P0Size; // save last page address - Map(b,Chipset.P0End); // refresh mapping - return; - } - if (cCurrentRomType=='S') // HP48SX - { - if (!Chipset.P1Cfg2) // CE1 size, port1 - { - Chipset.P1Cfg2 = TRUE; - Chipset.P1Size = s; - return; - } - if (!Chipset.P1Cfig) // CE1 address, port1 - { - Chipset.P1Cfig = TRUE; - Chipset.P1Base = b; - b &= ~Chipset.P1Size; // adjust base to mapping boundary - Chipset.P1End = b+Chipset.P1Size; - Map(b,Chipset.P1End); // refresh mapping - return; - } - if (!Chipset.P2Cfg2) // CE2 size, port2 - { - Chipset.P2Cfg2 = TRUE; - Chipset.P2Size = s; - return; - } - if (!Chipset.P2Cfig) // CE2 address, port2 - { - Chipset.P2Cfig = TRUE; - Chipset.P2Base = b; - b &= ~Chipset.P2Size; // adjust base to mapping boundary - Chipset.P2End = b+Chipset.P2Size; - Map(b,Chipset.P2End); // refresh mapping - return; - } - if (!Chipset.BSCfg2) // NCE3 size, not used in S(X) - { - Chipset.BSCfg2 = TRUE; - Chipset.BSSize = s; - return; - } - if (!Chipset.BSCfig) // NCE3 address, not used in S(X) - { - Chipset.BSCfig = TRUE; - Chipset.BSBase = b; - b &= ~Chipset.BSSize; // adjust base to mapping boundary - Chipset.BSEnd = b+Chipset.BSSize; - Map(b,Chipset.BSEnd); // refresh mapping - return; - } - } - else // HP48GX / HP49G - { - if (!Chipset.BSCfg2) // CE1 size, bank select - { - Chipset.BSCfg2 = TRUE; - Chipset.BSSize = s; - return; - } - if (!Chipset.BSCfig) // CE1 address, bank select - { - Chipset.BSCfig = TRUE; - Chipset.BSBase = b; - b &= ~Chipset.BSSize; // adjust base to mapping boundary - Chipset.BSEnd = b+Chipset.BSSize; - Map(b,Chipset.BSEnd); // refresh mapping - return; - } - if (!Chipset.P1Cfg2) // CE2 size, port1 - { - Chipset.P1Cfg2 = TRUE; - Chipset.P1Size = s; - return; - } - if (!Chipset.P1Cfig) // CE2 address, port1 - { - Chipset.P1Cfig = TRUE; - Chipset.P1Base = b; - b &= ~Chipset.P1Size; // adjust base to mapping boundary - Chipset.P1End = b+Chipset.P1Size; - Map(b,Chipset.P1End); // refresh mapping - return; - } - if (!Chipset.P2Cfg2) // NCE3 size, port2 - { - Chipset.P2Cfg2 = TRUE; - Chipset.P2Size = s; - return; - } - if (!Chipset.P2Cfig) // NCE3 address, port2 - { - Chipset.P2Cfig = TRUE; - Chipset.P2Base = b; - b &= ~Chipset.P2Size; // adjust base to mapping boundary - Chipset.P2End = b+Chipset.P2Size; - Map(b,Chipset.P2End); // refresh mapping - return; - } - } - return; -} - -VOID Uncnfg() -{ - DWORD d=Npack(Chipset.C,5); // decode address - BYTE b=(BYTE)(d>>12); // page address - - // unconfig order is HDW, RAM, CE2, CE1, NCE3 - if ((Chipset.IOCfig)&&((d&0xFFFC0)==Chipset.IOBase)) - {Chipset.IOCfig=FALSE;Map(b,b);return;} - if ((Chipset.P0Cfig)&&((b&~Chipset.P0Size)==P0MAPBASE)) - {Chipset.P0Cfig=FALSE;Chipset.P0Cfg2=FALSE;Map(P0MAPBASE,Chipset.P0End);return;} - if (cCurrentRomType=='S') // HP48SX - { - if ((Chipset.P2Cfig)&&((b&~Chipset.P2Size)==P2MAPBASE)) - {Chipset.P2Cfig=FALSE;Chipset.P2Cfg2=FALSE;Map(P2MAPBASE,Chipset.P2End);return;} - if ((Chipset.P1Cfig)&&((b&~Chipset.P1Size)==P1MAPBASE)) - {Chipset.P1Cfig=FALSE;Chipset.P1Cfg2=FALSE;Map(P1MAPBASE,Chipset.P1End);return;} - if ((Chipset.BSCfig)&&((b&~Chipset.BSSize)==BSMAPBASE)) - {Chipset.BSCfig=FALSE;Chipset.BSCfg2=FALSE;Map(BSMAPBASE,Chipset.BSEnd);return;} - } - else // HP48GX / HP49G - { - if ((Chipset.P1Cfig)&&((b&~Chipset.P1Size)==P1MAPBASE)) - {Chipset.P1Cfig=FALSE;Chipset.P1Cfg2=FALSE;Map(P1MAPBASE,Chipset.P1End);return;} - if ((Chipset.BSCfig)&&((b&~Chipset.BSSize)==BSMAPBASE)) - {Chipset.BSCfig=FALSE;Chipset.BSCfg2=FALSE;Map(BSMAPBASE,Chipset.BSEnd);return;} - if ((Chipset.P2Cfig)&&((b&~Chipset.P2Size)==P2MAPBASE)) - {Chipset.P2Cfig=FALSE;Chipset.P2Cfg2=FALSE;Map(P2MAPBASE,Chipset.P2End);return;} - } - return; -} - -VOID Reset() -{ - Chipset.IOCfig=FALSE;Chipset.IOBase=0x100000; - Chipset.P0Cfig=FALSE;Chipset.P0Cfg2=FALSE;Chipset.P0Base=0;Chipset.P0Size=0;Chipset.P0End=0; - Chipset.BSCfig=FALSE;Chipset.BSCfg2=FALSE;Chipset.BSBase=0;Chipset.BSSize=0;Chipset.BSEnd=0; - Chipset.P1Cfig=FALSE;Chipset.P1Cfg2=FALSE;Chipset.P1Base=0;Chipset.P1Size=0;Chipset.P1End=0; - Chipset.P2Cfig=FALSE;Chipset.P2Cfg2=FALSE;Chipset.P2Base=0;Chipset.P2Size=0;Chipset.P2End=0; - Map(0x00,0xFF); // refresh mapping - return; -} - -VOID C_Eq_Id() -{ - // config order is HDW, RAM, CE1, CE2, NCE3 - if (!Chipset.IOCfig) {Nunpack(Chipset.C,(Chipset.IOBase) ^0x00019,5);return;} - if (!Chipset.P0Cfg2) {Nunpack(Chipset.C,(Chipset.P0Size*0x1000)^0xFF003,5);return;} - if (!Chipset.P0Cfig) {Nunpack(Chipset.C,(Chipset.P0Base*0x1000)^0x000F4,5);return;} - if (cCurrentRomType=='S') // HP48SX - { - if (!Chipset.P1Cfg2) {Nunpack(Chipset.C,(Chipset.P1Size*0x1000)^0xFF005,5);return;} - if (!Chipset.P1Cfig) {Nunpack(Chipset.C,(Chipset.P1Base*0x1000)^0x000F6,5);return;} - if (!Chipset.P2Cfg2) {Nunpack(Chipset.C,(Chipset.P2Size*0x1000)^0xFF007,5);return;} - if (!Chipset.P2Cfig) {Nunpack(Chipset.C,(Chipset.P2Base*0x1000)^0x000F8,5);return;} - if (!Chipset.BSCfg2) {Nunpack(Chipset.C,(Chipset.BSSize*0x1000)^0xFF001,5);return;} - if (!Chipset.BSCfig) {Nunpack(Chipset.C,(Chipset.BSBase*0x1000)^0x000F2,5);return;} - } - else // HP48GX / HP49G - { - if (!Chipset.BSCfg2) {Nunpack(Chipset.C,(Chipset.BSSize*0x1000)^0xFF005,5);return;} - if (!Chipset.BSCfig) {Nunpack(Chipset.C,(Chipset.BSBase*0x1000)^0x000F6,5);return;} - if (!Chipset.P1Cfg2) {Nunpack(Chipset.C,(Chipset.P1Size*0x1000)^0xFF007,5);return;} - if (!Chipset.P1Cfig) {Nunpack(Chipset.C,(Chipset.P1Base*0x1000)^0x000F8,5);return;} - if (!Chipset.P2Cfg2) {Nunpack(Chipset.C,(Chipset.P2Size*0x1000)^0xFF001,5);return;} - if (!Chipset.P2Cfig) {Nunpack(Chipset.C,(Chipset.P2Base*0x1000)^0x000F2,5);return;} - } - memset(Chipset.C,0,5); - return; -} - -enum MMUMAP MapData(DWORD d) // check MMU area -{ - BYTE u = (BYTE) (d>>12); - - if (Chipset.IOCfig && ((d&0xFFFC0)==Chipset.IOBase)) return M_IO; - if (Chipset.P0Cfig && (((u^Chipset.P0Base) & ~Chipset.P0Size) == 0)) return M_RAM; - if (cCurrentRomType == 'S') - { - if (Chipset.P2Cfig && (((u^Chipset.P2Base) & ~Chipset.P2Size) == 0)) return M_P2; - if (Chipset.P1Cfig && (((u^Chipset.P1Base) & ~Chipset.P1Size) == 0)) return M_P1; - if (Chipset.BSCfig && (((u^Chipset.BSBase) & ~Chipset.BSSize) == 0)) return M_BS; - } - else - { - if (Chipset.P1Cfig && (((u^Chipset.P1Base) & ~Chipset.P1Size) == 0)) return M_P1; - if (Chipset.BSCfig && (((u^Chipset.BSBase) & ~Chipset.BSSize) == 0)) return M_BS; - if (Chipset.P2Cfig && (((u^Chipset.P2Base) & ~Chipset.P2Size) == 0)) return M_P2; - } - return M_ROM; -} - -VOID CpuReset(VOID) // register setting after Cpu Reset -{ - StopTimers(); // stop timer, do here because function change Chipset.t2 - - Chipset.pc = 0; - Chipset.rstkp = 0; - ZeroMemory(Chipset.rstk,sizeof(Chipset.rstk)); - Chipset.HST = 0; - Chipset.SoftInt = FALSE; - Chipset.Shutdn = TRUE; - Chipset.inte = TRUE; // enable interrupts - Chipset.intk = TRUE; // INTON - Chipset.intd = FALSE; // no keyboard interrupts pending - Chipset.crc = 0; - Chipset.Bank_FF = 0; // state of bank switcher FF - Chipset.FlashRomState = 0; // WSM state of flash memory - ZeroMemory(Chipset.IORam,sizeof(Chipset.IORam)); - Chipset.IORam[LPE] = RST; // set ReSeT bit at hardware reset - Reset(); // reset MMU - Chipset.t1 = 0; // reset timer values - Chipset.t2 = 0; - Chipset.loffset = 0; // right margin - Chipset.boffset = 0; // left margin - Chipset.lcounter = 0; // number of main display lines - Chipset.contrast = 0; // contrast dark - - UpdateContrast(Chipset.contrast); // update contrast - // display update when changing to run state - CommSetBaud(); // new baudrate - CheckSerial(); // close serial port - - RomSwitch(Chipset.Bank_FF); // force new memory mapping - return; -} - -VOID Npeek(BYTE *a, DWORD d, UINT s) -{ - enum MMUMAP eMap; - DWORD u, v; - UINT c; - BYTE *p; - - do - { - eMap = MapData(d); // get active memory controller - if (M_IO == eMap) // I/O access - { - v = d&0x3F; - - do - { - if (v == LPE) - { - // don't read LPE content with the function ReadIO() - c = 1; - memcpy(a, Chipset.IORam+v, c); - break; - } - if (v >= RBR_LSB && v <= RBR_MSB) - { - // don't read RBR content with the function ReadIO() - c = MIN(s,RBR_MSB-v+1); - memcpy(a, Chipset.IORam+v, c); - break; - } - // all others registers - do - { - if (v < LPE) - { - c = MIN(s,LPE-v); - break; - } - if (v < RBR_LSB && (v+s) > RBR_LSB) - { - c = MIN(s,RBR_LSB-v); - break; - } - c = MIN(s,0x40-v); - } - while (0); - ReadIO(a,v,c,FALSE); - } - while (0); - } - else - { - u = d>>12; - v = d&0xFFF; - c = MIN(s,0x1000-v); - // Flash memory Read access - if (cCurrentRomType=='X' && (Chipset.IORam[LCR] & LED) && M_P2 == eMap) - { - FlashRead(a, FlashROMAddr(d), c); - } - else - { - if ((p=RMap[u]) != NULL) // module mapped - { - memcpy(a, p+v, c); - } - else // open data bus - { - for (u=0; u>12; - v = d&0xFFF; - c = MIN(s,0x1000-v); - // bank switcher access - if (cCurrentRomType!='S' && M_BS == eMap) - { - if (cCurrentRomType=='G') // HP48GX - { - Chipset.Bank_FF = v+c; // save FF value - Map(Chipset.P2Base,Chipset.P2End); - } - if (cCurrentRomType=='E' || cCurrentRomType=='X') // HP39/40G, HP49G - { - RomSwitch(v+c); - } - } - // Flash memory Read access - if (cCurrentRomType=='X' && (Chipset.IORam[LCR] & LED) && M_P2 == eMap) - { - DWORD dwLinAddr = FlashROMAddr(d); - - FlashRead(a, dwLinAddr, c); - - #if defined DEBUG_FLASH - { - TCHAR buffer[256]; - DWORD j; - int i; - - i = wsprintf(buffer,_T("%.5lx: Flash Read : %.5x (%.6x),%u = "),Chipset.pc,d,dwLinAddr,c); - for (j = 0;j < c;++j,++i) - { - buffer[i] = a[j]; - if (buffer[i] > 9) buffer[i] += _T('a') - _T('9') - 1; - buffer[i] += _T('0'); - } - buffer[i++] = _T('\n'); - buffer[i] = 0; - OutputDebugString(buffer); - } - #endif - } - else - { - if ((p=RMap[u]) != NULL) // module mapped - { - memcpy(a, p+v, c); - } - // simulate open data bus - else // open data bus - { - for (u=0; u>12; - v = d&0xFFF; - c = MIN(s,0x1000-v); - // bank switcher access - if (cCurrentRomType!='S' && M_BS == eMap) - { - BOOL bWrite = FALSE; - - // write enabled - if (Chipset.cards_status & PORT2_WRITE) - { - Chipset.Bank_FF = v+c-1;// save FF value - bWrite = TRUE; // bank switched - } - else // write disabled, so latch last read cycle - { - if ((v & 1) != 0) // low address odd - { - Chipset.Bank_FF = v;// save FF value - bWrite = TRUE; // bank switched - } - - if (((v+c) & 1) != 0) // high address odd - { - Chipset.Bank_FF = v+c-1;// save FF value - bWrite = TRUE; // bank switched - } - } - - if (bWrite) // write cycle? - { - // HP48GX - if (cCurrentRomType=='G') Map(Chipset.P2Base,Chipset.P2End); - // HP39/40G, HP49G - if (cCurrentRomType=='E' || cCurrentRomType=='X') RomSwitch(Chipset.Bank_FF); - } - } - // Flash memory Write access - if (cCurrentRomType=='X' && (Chipset.IORam[LCR] & LED) && M_P2 == eMap) - { - DWORD dwLinAddr = FlashROMAddr(d); - - FlashWrite(a, dwLinAddr, c); - - #if defined DEBUG_FLASH - { - TCHAR buffer[256]; - DWORD j; - int i; - - i = wsprintf(buffer,_T("%.5lx: Flash Write: %.5x (%.6x),%u = "),Chipset.pc,d,dwLinAddr,c); - for (j = 0;j < c;++j,++i) - { - buffer[i] = a[j]; - if (buffer[i] > 9) buffer[i] += _T('a') - _T('9') - 1; - buffer[i] += _T('0'); - } - buffer[i++] = _T('\n'); - buffer[i] = 0; - OutputDebugString(buffer); - } - #endif - } - else - { - if ((p=WMap[u]) != NULL) memcpy(p+v, a, c); - } - } - if (!bGrayscale) UpdateDisplay(d, c); // update display - a+=c; - d=(d+c)&0xFFFFF; - } while (s-=c); - return; -} - -DWORD Read5(DWORD d) -{ - BYTE p[5]; - - Npeek(p,d,5); - return Npack(p,5); -} - -BYTE Read2(DWORD d) -{ - BYTE p[2]; - - Npeek(p,d,2); - return (BYTE)(p[0]|(p[1]<<4)); -} - -VOID Write5(DWORD d, DWORD n) -{ - BYTE p[5]; - - Nunpack(p,n,5); - Nwrite(p,d,5); - return; -} - -VOID Write2(DWORD d, BYTE n) -{ - BYTE p[2]; - - Nunpack(p,n,2); - Nwrite(p,d,2); - return; -} - -VOID IOBit(DWORD d, BYTE b, BOOL s) // set/clear bit in I/O section -{ - EnterCriticalSection(&csIOLock); - { - if (s) - Chipset.IORam[d] |= b; // set bit - else - Chipset.IORam[d] &= ~b; // clear bit - } - LeaveCriticalSection(&csIOLock); -} - -static DWORD ReadT2Acc(VOID) -{ - static DWORD dwCyc = 0; // CPU cycle counter at last timer2 read access - - DWORD dwCycDif; - - // CPU cycles since last call - dwCycDif = (DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwCyc; - dwCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); - - // maybe CPU speed measurement, slow down the next 10 CPU opcodes - if (dwCycDif < 150) - { - InitAdjustSpeed(); // init variables if necessary - EnterCriticalSection(&csSlowLock); - { - nOpcSlow = 10; // slow down next 10 opcodes - } - LeaveCriticalSection(&csSlowLock); - } - return ReadT2(); -} - -VOID ReadIO(BYTE *a, DWORD d, DWORD s, BOOL bUpdate) -{ - BOOL bNINT,bNINT2; - BOOL bLBI,bVLBI; - - BYTE c = 0xFF; // LINECOUNT not initialized - BOOL rbr_acc = FALSE; // flag to receive data - - #if defined DEBUG_IO - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: IO read : %02x,%u\n"),Chipset.pc,d,s); - OutputDebugString(buffer); - } - #endif - - do - { - switch (d) - { - case 0x00: *a = (Chipset.IORam[d]&DON)|Chipset.boffset; break; - case 0x01: *a = Chipset.contrast&0xF; break; - case 0x02: *a = Chipset.contrast>>4; break; - case 0x03: *a = 0; - case 0x04: *a = (Chipset.crc )&0xF; break; - case 0x05: *a = (Chipset.crc>> 4)&0xF; break; - case 0x06: *a = (Chipset.crc>> 8)&0xF; break; - case 0x07: *a = (Chipset.crc>>12)&0xF; break; - case 0x08: // LPD - // LB2 and LB1 not emulated, must be 0 - _ASSERT((Chipset.IORam[LPD] & (LB2 | LB1)) == 0); - - GetBatteryState(&bLBI,&bVLBI); // get battery state - - // check if battery states enabled - bLBI = bLBI && ((Chipset.IORam[LPE] & ELBI) != 0); - bVLBI = bVLBI && ((Chipset.IORam[LPE] & EVLBI) != 0); - - // set IO bits - IOBit(LPD,LB0,bLBI); - IOBit(LPD,VLBI,bVLBI); - IOBit(SRQ1,VSRQ,bVLBI); - *a = Chipset.IORam[d]; - break; - case 0x09: // LPE - *a = Chipset.IORam[d]; - if (bUpdate) - { - Chipset.IORam[d] &= ~RST; // clear RST bit after reading - } - break; - case 0x0A: *a = 0; break; -// case 0x0B: *a = Chipset.IORam[d]; break; -// case 0x0C: *a = Chipset.IORam[d]; break; - case 0x0D: // BAUD - *a = Chipset.IORam[d] & 0x7; - #if defined DEBUG_SERIAL // return BAUD value - if (bUpdate) - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: BAUD Read: %x\n"),Chipset.pc,*a); - OutputDebugString(buffer); - } - #endif - *a |= UckBit(*a); // add UCK bit to BAUD rate register - break; - case 0x0E: - // SMP is !NINT and SWINT is always 0 - // clear SMP and SWINT bit - Chipset.IORam[d] &= (ECDT | RCDT); - // SMP is !NINT - if ((Chipset.IORam[SRQ2] & NINT) == 0) - Chipset.IORam[d] |= SMP; - *a = Chipset.IORam[d]; - break; - case 0x0F: - // card detection disabled - if ((Chipset.IORam[CARDCTL] & ECDT) == 0) - { - *a = 0; // no cards - } - else - { - // on a HP30/40G and HP49G Chipset.cards_status bust always be 0xF - _ASSERT((cCurrentRomType!='E' && cCurrentRomType!='X') || Chipset.cards_status == 0xF); - *a = Chipset.cards_status; - } - break; - case 0x10: // IO CONTROL - *a = Chipset.IORam[d]; // return IO CONTROL value - #if defined DEBUG_SERIAL - if (bUpdate) - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: IOC Read: %x\n"),Chipset.pc,*a); - OutputDebugString(buffer); - } - #endif - break; - case 0x11: // RCS - *a = Chipset.IORam[d] | RX; // return RCS value - #if defined DEBUG_SERIAL - if (bUpdate) - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: RCS Read: %x\n"),Chipset.pc,*a); - OutputDebugString(buffer); - } - #endif - break; - case 0x12: // TCS - *a = Chipset.IORam[d]; // return TCS value - - if ((*a & TBF)) // Transmit buffer full - { - // the G-series XModem implementation has a timeout loop counter - // waiting for transmit buffer empty, so on fast hosts with - // CPU running with max. speed we may get a timeout overflow - // -> to avoid this slow down CPU speed on transmit buffer full - - InitAdjustSpeed(); // init variables if necessary - EnterCriticalSection(&csSlowLock); - { - nOpcSlow = 10; // slow down next 10 opcodes - } - LeaveCriticalSection(&csSlowLock); - } - - #if defined DEBUG_SERIAL - if (bUpdate) - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: TCS Read: %x\n"),Chipset.pc,*a); - OutputDebugString(buffer); - } - #endif - break; - case 0x13: // CRER - *a = 0; - break; - case 0x14: // RBR LSB - case 0x15: // RBR MSB - if (bUpdate) - { - *a = Chipset.IORam[d]; // return RBR value - if (d==0x15) // reading RBR MSB - { - Chipset.IORam[RCS] &= ~RBF; // clear Receive Buffer Full flag - } - UpdateUSRQ(); // update USRQ - rbr_acc = TRUE; // search for new RBR value - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: RBR %s Read: %x\n"),Chipset.pc,(d==0x14) ? "LSB" : "MSB",*a); - OutputDebugString(buffer); - } - #endif - } - else - { - *a = Chipset.IORam[d]; // return RBR value - UpdateUSRQ(); // update USRQ - } - break; -// case 0x16: *a = Chipset.IORam[d]; break; // TBR LSB -// case 0x17: *a = Chipset.IORam[d]; break; // TBR MSB - case 0x19: // SREQ? MSB - UpdateKdnBit(); // update KDN bit - bNINT2 = Chipset.IORam[SRQ1] == 0 && (Chipset.IORam[SRQ2] & LSRQ) == 0; - bNINT = (Chipset.IORam[SRQ2] & NINT) != 0; - // card detection off and timer running - if ((Chipset.IORam[CARDCTL] & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0) - { - // state of CDT2 - bNINT2 = bNINT2 && (Chipset.cards_status & (P2W|P2C)) != P2C; - // state of CDT1 - bNINT = bNINT && (Chipset.cards_status & (P1W|P1C)) != P1C; - } - IOBit(SRQ2,NINT2,bNINT2); - IOBit(SRQ2,NINT,bNINT); - // no break! - case 0x18: // SREQ? LSB - *a = Chipset.IORam[d]; // return SREQ value - #if defined DEBUG_SERIAL - if (bUpdate) - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: SEQ %s Read: %x\n"),Chipset.pc,(d==0x18) ? "LSB" : "MSB",*a); - OutputDebugString(buffer); - } - #endif - break; - case 0x1A: // IR CONTROL - if (cCurrentRomType=='E') // HP39/40G - { - Chipset.IORam[d] = (nCurrentClass != 40) - ? (Chipset.IORam[d] & ~IRI) // HP39G - : (Chipset.IORam[d] | IRI); // HP40G - } - *a = Chipset.IORam[d]; // return IR CONTROL value - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: IRC Read: %x\n"),Chipset.pc,*a); - OutputDebugString(buffer); - } - #endif - break; - case 0x1B: *a = 0; break; - case 0x1C: // LED CONTROL - // put LBF and LBZ always to zero to indicate a free REDEYE buffer and formatter - *a = (Chipset.IORam[d] & (LED|ELBE)); - break; - case 0x1D: // LED BUFFER - *a = (Chipset.IORam[d] & LBO); - break; -// case 0x1E: *a = Chipset.IORam[d]; break; -// case 0x1F: *a = Chipset.IORam[d]; break; - case 0x20: *a = 3; break; - case 0x21: *a = 3; break; - case 0x22: *a = 3; break; - case 0x23: *a = 3; break; - case 0x24: *a = 3; break; - case 0x25: *a = 3; break; - case 0x26: *a = 3; break; - case 0x27: *a = 3; break; - case 0x28: // LINECOUNT LSB - case 0x29: // LINECOUNT MSB + DA19 M32 - if (Chipset.IORam[0x00]&DON) // display on - { - if (c == 0xFF) // no actual line information - { - c = GetLineCounter(); // get LCD update line - // save line information in IO registers - Chipset.IORam[0x28] = c & 0xF; - Chipset.IORam[0x29] = (Chipset.IORam[0x29] & (DA19|M32)) | (c >> 4); - } - } - *a = Chipset.IORam[d]; - - if (d==0x29) // address 0x29 is mirrored to 0x2A-0x2D - { - Chipset.IORam[0x2A] = *a; - Chipset.IORam[0x2B] = *a; - Chipset.IORam[0x2C] = *a; - Chipset.IORam[0x2D] = *a; - } - break; -// case 0x2A: *a = 0; break; -// case 0x2B: *a = 0; break; -// case 0x2C: *a = 0; break; -// case 0x2D: *a = 0; break; - case 0x2E: - ReadT1(); // dummy read for update timer1 control register - *a = Chipset.IORam[d]; - break; - case 0x2F: - ReadT2(); // dummy read for update timer2 control register - *a = Chipset.IORam[d]; - break; - case 0x30: *a = 3; break; - case 0x31: *a = 3; break; - case 0x32: *a = 3; break; - case 0x33: *a = 3; break; - case 0x34: *a = 3; break; - case 0x35: *a = 0; break; - case 0x36: *a = 0; break; - case 0x37: *a = ReadT1(); break; - case 0x38: Nunpack(a, ReadT2Acc() , s); return; - case 0x39: Nunpack(a, ReadT2Acc()>> 4, s); return; - case 0x3A: Nunpack(a, ReadT2Acc()>> 8, s); return; - case 0x3B: Nunpack(a, ReadT2Acc()>>12, s); return; - case 0x3C: Nunpack(a, ReadT2Acc()>>16, s); return; - case 0x3D: Nunpack(a, ReadT2Acc()>>20, s); return; - case 0x3E: Nunpack(a, ReadT2Acc()>>24, s); return; - case 0x3F: Nunpack(a, ReadT2Acc()>>28, s); return; - default: *a = Chipset.IORam[d]; - } - d++; a++; - } while (--s); - if (rbr_acc) CommReceive(); // look for new character - return; -} - -VOID WriteIO(BYTE *a, DWORD d, DWORD s) -{ - DWORD b; - BYTE c; - BOOL tbr_acc = FALSE; // flag to transmit data - BOOL bDISPADDR = FALSE; // flag addr 0x120-0x124 changed - BOOL bLINEOFFS = FALSE; // flag addr 0x125-0x127 changed - BOOL bMENUADDR = FALSE; // flag addr 0x130-0x134 changed - DWORD dwAnnunciator = 0; // no annunciator write - - #if defined DEBUG_IO - { - TCHAR buffer[256]; - DWORD j; - int i; - - i = wsprintf(buffer,_T("%.5lx: IO write: %02x,%u = "),Chipset.pc,d,s); - for (j = 0;j < s;++j,++i) - { - buffer[i] = a[j]; - if (buffer[i] > 9) buffer[i] += _T('a') - _T('9') - 1; - buffer[i] += _T('0'); - } - buffer[i++] = _T('\n'); - buffer[i] = 0; - OutputDebugString(buffer); - } - #endif - - do - { - c = *a; - switch (d) - { -// 00100 = NS:DISPIO -// 00100 @ Display bit offset and DON [DON OFF2 OFF1 OFF0] -// 00100 @ 3 nibs for display offset (scrolling), DON=Display ON - case 0x00: - if ((c^Chipset.IORam[d])&DON) // DON bit changed - { - disp |= (DISP_POINTER | DISP_MAIN | DISP_MENUE); - - // adjust VBL counter start/stop values - if ((c & DON) != 0) // set display on - { - Chipset.IORam[d] |= DON; // for StartDisplay(); - UpdateContrast(Chipset.contrast); - StartDisplay((BYTE) Chipset.lcounter); // start display update - } - else // display is off - { - Chipset.IORam[d] &= ~DON; - UpdateContrast(Chipset.contrast); - StopDisplay(); // stop display update - } - } - // OFF bits changed - if ((c^Chipset.IORam[d]) & (OFF2 | OFF1 | OFF0)) - { - Chipset.boffset = c & (OFF2 | OFF1 | OFF0); - disp |= (DISP_POINTER | DISP_MAIN); - } - Chipset.IORam[d] = c; - break; - -// 00101 = NS:CONTRLSB -// 00101 @ Contrast Control [CON3 CON2 CON1 CON0] -// 00101 @ Higher value = darker screen - case 0x01: - if (c!=Chipset.IORam[d]) - { - Chipset.IORam[d]=c; - Chipset.contrast = (Chipset.contrast&0x10)|c; - UpdateContrast(Chipset.contrast); - disp |= (DISP_MAIN | DISP_MENUE); - } - break; - -// 00102 = NS:DISPTEST -// 00102 @ Display test [VDIG LID TRIM CON4] [LRT LRTD LRTC BIN] -// 00102 @ Normally zeros - case 0x02: - if (c!=Chipset.IORam[d]) - { - Chipset.IORam[d]=c; - Chipset.contrast = (Chipset.contrast&0x0f)|((c&1)<<4); - UpdateContrast(Chipset.contrast); - disp |= (DISP_MAIN | DISP_MENUE); - } - break; - - case 0x03: Chipset.IORam[d]=c; break; - -// 00104 = HP:CRC -// 00104 @ 16 bit hardware CRC (104-107) (X^16+X^12+X^5+1) -// 00104 @ crc = ( crc >> 4 ) ^ ( ( ( crc ^ nib ) & 0x000F ) * 0x1081 ); - case 0x04: Chipset.crc = (Chipset.crc&0xfff0)|(c*0x0001); break; - case 0x05: Chipset.crc = (Chipset.crc&0xff0f)|(c*0x0010); break; - case 0x06: Chipset.crc = (Chipset.crc&0xf0ff)|(c*0x0100); break; - case 0x07: Chipset.crc = (Chipset.crc&0x0fff)|(c*0x1000); break; - -// 00108 = NS:POWERSTATUS -// 00108 @ Low power registers (108-109) -// 00108 @ [LB2 LB1 LB0 VLBI] (read only) -// 00108 @ LowBat(2) LowBat(1) LowBat(S) VeryLowBat - case 0x08: break; // read-only - -// 00109 = NS:POWERCTRL -// 00109 @ [ELBI EVLBI GRST RST] (read/write) - case 0x09: - Chipset.IORam[d]=c; - if (c & RST) - { - CpuReset(); // emulate NRES signal - disp |= (DISP_POINTER | DISP_MAIN | DISP_MENUE); - dwAnnunciator = 0x3F; // update all annunciators - bInterrupt = TRUE; // SHUTDN - } - break; - -// 0010A = NS:MODE -// 0010A @ Mode Register (read-only) - case 0x0A: break; // read-only - -// 0010B = HP:ANNCTRL -// 0010B @ Annunciator control [LA4 LA3 LA2 LA1] = [ alarm alpha -> <- ] - case 0x0B: - case 0x0C: - // annunciator changed - dwAnnunciator |= ((Chipset.IORam[d] ^c) << ((d - 0x0B) * 4)) & 0x3F; - Chipset.IORam[d] = c; - break; - -// 0010D = NS:BAUD -// 0010D @ Serial baud rate [UCK BD2 BD1 BD0] (bit 3 is read-only) -// 0010D @ 3 bits = {1200 1920 2400 3840 4800 7680 9600 15360} - case 0x0D: - Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); // bit 3 is read-only - CommSetBaud(); // set baudrate - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: BAUD write: %x\n"),Chipset.pc,Chipset.IORam[d]); - OutputDebugString(buffer); - } - #endif - break; - -// 0010E = NS:CARDCTL -// 0010E @ [ECDT RCDT SMP SWINT] (read/write) -// 0010E @ Enable Card Det., Run Card Det., Set Module Pulled, Software interrupt - case 0x0E: - if (c & SWINT) // SWINT bit set - { - c &= (ECDT | RCDT | SMP); // clear SWINT bit - Chipset.SoftInt = TRUE; - bInterrupt = TRUE; - } - if ((c & SMP) == 0) // SMP bit cleared - { - BOOL bNINT = TRUE; // ack NINT interrupt -> NINT high - // card detect disabled and CDT1 low -> retrigger - if ((c & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0) - bNINT = (Chipset.cards_status & (P1W|P1C)) != P1C; - IOBit(SRQ2,NINT,bNINT); - } - // falling edge of Enable Card Detect bit and timer running - if ( ((c^Chipset.IORam[d]) & ECDT) != 0 && (c & ECDT) == 0 - && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0) - { - BOOL bNINT = (Chipset.IORam[SRQ2] & NINT) != 0; - // card in slot1 isn't Read Only - if ((Chipset.cards_status & (P1W|P1C)) != P1C) - { - // use random state of NINT line - bNINT = bNINT && (ReadT2() & 0x1) != 0; - } - IOBit(SRQ2,NINT,bNINT); - - Chipset.HST |= MP; // set Module Pulled - - // Port1 and Port2 plugged and writeable or NINT2/NINT interrupt - if ( Chipset.cards_status != (P2W|P1W|P2C|P1C) - || (Chipset.IORam[SRQ2] & NINT2) == 0 - || (Chipset.IORam[SRQ2] & NINT ) == 0 - ) - { - Chipset.SoftInt = TRUE; // set interrupt - bInterrupt = TRUE; - } - } - Chipset.IORam[d]=c; - break; - -// 0010F = NS:CARDSTATUS -// 0010F @ [P2W P1W P2C P1C] (read-only) Port 2 writable .. Port 1 inserted - case 0x0F: break; // read-only - -// 00110 = HP:IOC -// 00110 @ Serial I/O Control [SON ETBE ERBF ERBZ] -// 00110 @ Serial On, Interrupt On Recv.Buf.Empty, Full, Buzy - case 0x10: - Chipset.IORam[d]=c; - CheckSerial(); // handle UART on/off - if ((c & SON) == 0) // SON bit cleared - { - Chipset.IORam[IOC] = 0; // clear IOC - Chipset.IORam[RCS] = 0; // clear RCS - Chipset.IORam[TCS] = 0; // clear TCS - Chipset.IORam[RBR_LSB] = 0; // clear RBR - Chipset.IORam[RBR_MSB] = 0; - Chipset.IORam[TBR_LSB] = 0; // clear TBR - Chipset.IORam[TBR_MSB] = 0; - } - if (UpdateUSRQ()) INTERRUPT; // update USRQ bit - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: IOC write: %x\n"),Chipset.pc,Chipset.IORam[d]); - OutputDebugString(buffer); - } - #endif - break; - -// 00111 = HP:RCS -// 00111 Serial Receive Control/Status [RX RER RBZ RBF] (bit 3 is read-only) - case 0x11: - if (Chipset.IORam[IOC] & SON) - { - EnterCriticalSection(&csIOLock); - { - // critical section because of RER access - Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); - } - LeaveCriticalSection(&csIOLock); - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: RCS write: %x\n"),Chipset.pc,Chipset.IORam[d]); - OutputDebugString(buffer); - } - #endif - } - break; - -// 00112 = HP:TCS -// 00112 @ Serial Transmit Control/Status [BRK LPB TBZ TBF] - case 0x12: - if (Chipset.IORam[IOC] & SON) - { - Chipset.IORam[d]=c; - CommTxBRK(); // update BRK condition - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: TCS write: %x\n"),Chipset.pc,Chipset.IORam[d]); - OutputDebugString(buffer); - } - #endif - } - break; - -// 00113 = HP:CRER -// 00113 @ Serial Clear RER (writing anything clears RER bit) - case 0x13: - IOBit(RCS,RER,FALSE); - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: CRER write: %x\n"),Chipset.pc,Chipset.IORam[d]); - OutputDebugString(buffer); - } - #endif - break; - -// 00114 = HP:RBR -// 00114 @ Serial Receive Buffer Register (Reading clears RBF bit) - case 0x14: break; // read-only - case 0x15: break; // read-only - -// 00116 = HP:TBR -// 00116 @ Serial Transmit Buffer Register (Writing sets TBF bit) - case 0x16: - case 0x17: - if (Chipset.IORam[IOC] & SON) - { - Chipset.IORam[d]=c; - tbr_acc = TRUE; // new TBR value - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: TBR %s write: %x\n"),Chipset.pc,(d==0x16) ? "LSB" : "MSB",*a); - OutputDebugString(buffer); - } - #endif - } - break; - -// 00118 = NS:SRR -// 00118 @ Service Request Register (read-only) -// 00118 @ [ISRQ TSRQ USRQ VSRQ] [KDN NINT2 NINT LSRQ] - case 0x18: break; // read-only - case 0x19: break; // read-only - -// 0011A = HP:IRC -// 0011A @ IR Control Register [IRI EIRU EIRI IRE] (bit 3 is read-only) -// 0011A @ IR Input, Enable IR UART mode, Enable IR Interrupt, IR Event - case 0x1A: - // EIRU bit changed - if (((c^Chipset.IORam[d]) & EIRU) != 0) - { - // save new value for COM open - Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); - // reopen COM port with new setting - CommOpen(szSerialWire,szSerialIr); - } - Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: IRC write: %x\n"),Chipset.pc,Chipset.IORam[d]); - OutputDebugString(buffer); - } - #endif - break; - -// 0011B = NS:BASENIBOFF -// 0011B @ Used as addressto get BASENIB from 11F to the 5th nibble - case 0x1B: break; - -// 0011C = NS:LCR -// 0011C @ Led Control Register [LED ELBE LBZ LBF] (Setting LED is draining) - case 0x1C: - // HP49G new mapping on LED bit change - if (cCurrentRomType=='X' && ((c^Chipset.IORam[d])&LED)) - { - Chipset.IORam[d]=c; // save new value for mapping - Map(Chipset.P2Base,Chipset.P2End); // new ROM mapping - #if defined DEBUG_FLASH - { - TCHAR buffer[256]; - wsprintf(buffer,_T("%.5lx: NCE3: R%cM\n"),Chipset.pc,(c&LED) ? 'O' : 'A'); - OutputDebugString(buffer); - } - #endif - } - if ((c^Chipset.IORam[d])&ELBE) // ELBE bit changed - { - // Led Service ReQuest on Led Buffer Empty enabled - BOOL bLSRQ = (c & (ELBE | LBF)) == ELBE; - - IOBit(SRQ2,LSRQ,bLSRQ); // update LSRQ bit - if (bLSRQ) // interrupt on Led Buffer Empty enabled - { - Chipset.SoftInt = TRUE; - bInterrupt = TRUE; - } - } - Chipset.IORam[d]=c; - break; - -// 0011D = NS:LBR -// 0011D @ Led Buffer Register [0 0 0 LBO] (bits 1-3 read zero) - case 0x1D: - IrPrinter((BYTE)(c&LBO)); - Chipset.IORam[d]=c&LBO; - break; - -// 0011E = NS:SCRATCHPAD -// 0011E @ Scratch pad - case 0x1E: Chipset.IORam[d]=c; break; - -// 0011F = NS:BASENIB -// 0011F @ 7 or 8 for base memory - case 0x1F: Chipset.IORam[d]=c; break; - -// 00120 = NS:DISPADDR -// 00120 @ Display Start Address (write only) -// 00120 @ bit 0 is ignored (display must start on byte boundary) - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - Chipset.IORam[d]=c; - bDISPADDR = TRUE; // addr 0x120-0x124 changed - break; - -// 00125 = NS:LINEOFFS -// 00125 @ Display Line offset (write only) (no of bytes skipped after each line) -// 00125 @ MSG sign extended - case 0x25: - case 0x26: - case 0x27: - Chipset.IORam[d]=c; - bLINEOFFS = TRUE; // addr 0x125-0x127 changed - break; - -// 00128 = NS:LINECOUNT -// 00128 @ Display Line Counter and miscellaneous (28-29) -// 00128 @ [LC3 LC2 LC1 LC0] [DA19 M32 LC5 LC4] -// 00128 @ Line counter 6 bits -> max = 2^6-1 = 63 = disp height -// 00128 @ Normally has 55 -> Menu starts at display row 56 - case 0x28: - // LSB of LINECOUNT changed - if (c != (BYTE) (Chipset.lcounter & 0xf)) - { - Chipset.lcounter = (Chipset.lcounter & ~0xF) | c; - disp |= (DISP_POINTER | DISP_MAIN | DISP_MENUE); - } - break; - - case 0x29: - // MSB of LINECOUNT changed - b = (c & 0x3) << 4; // upper two bits - if (b != (Chipset.lcounter & 0x30)) - { - Chipset.lcounter = (Chipset.lcounter & ~0x30) | b; - disp |= (DISP_POINTER | DISP_MAIN | DISP_MENUE); - } - - if ((c^Chipset.IORam[d])&DA19) // DA19 changed - { - Chipset.IORam[d]^=DA19; // save new DA19 - Map(0x00,0xFF); // new ROM mapping - } - break; - - case 0x2A: break; - case 0x2B: break; - case 0x2C: break; - case 0x2D: break; - -// 0012E = NS:TIMER1CTRL -// 0012E @ TIMER1 Control [SRQ WKE INT XTRA] - case 0x2E: - Chipset.IORam[d]=c; // don't clear XTRA bit - ReadT1(); // dummy read for checking control bits - break; - -// 0012F = NS:TIMER2CTRL -// 0012F @ TIMER2 Control [SRQ WKE INT RUN] - case 0x2F: - Chipset.IORam[d]=c; - ReadT2(); // dummy read for checking control bits - if (c&1) - StartTimers(); - else - StopTimers(); - dwAnnunciator = 0x3F; // update all annunciators - break; - -// 00130 = NS:MENUADDR -// 00130 @ Display Secondary Start Address (write only) (30-34) -// 00130 @ Menu Display Address, no line offsets - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - Chipset.IORam[d]=c; - bMENUADDR = TRUE; // addr 0x130-0x134 changed - break; - - case 0x35: break; - case 0x36: break; - -// 00137 = HP:TIMER1 -// 00137 @ Decremented 16 times/s - case 0x37: - SetT1(c); // set new value - break; - -// 00138 = HP:TIMER2 -// 00138 @ hardware timer (38-3F), decremented 8192 times/s - // nothing - fall through to default - - default: - Chipset.IORam[d]=c; // write data - - if (d >= TIMER2) // timer2 update - { - Nunpack(Chipset.IORam+TIMER2,ReadT2(),8); - memcpy(Chipset.IORam+d,a,s); - SetT2(Npack(Chipset.IORam+TIMER2,8)); - goto finish; - } - } - a++; d++; - } while (--s); - -finish: - if (bDISPADDR) // 0x120-0x124 changed - { - b = Npack(Chipset.IORam+DISP1CTL,5)&0xFFFFE; - if (b != Chipset.start1) - { - Chipset.start1 = b; - disp |= (DISP_POINTER | DISP_MAIN); - } - } - if (bLINEOFFS) // addr 0x125-0x127 changed - { - signed short lo = (signed short)Npack(Chipset.IORam+LINENIBS,3); - if (lo&0x800) lo-=0x1000; - if (lo != Chipset.loffset) - { - Chipset.loffset = lo; - disp |= (DISP_POINTER | DISP_MAIN); - } - } - if (bMENUADDR) // addr 0x130-0x134 changed - { - b = Npack(Chipset.IORam+DISP2CTL,5)&0xFFFFE; - if (b != Chipset.start2) - { - Chipset.start2 = b; - disp |= (DISP_POINTER | DISP_MENUE); - } - } - - if (tbr_acc) // addr 0x116-0x117 changed - { - IOBit(TCS,TBF,TRUE); // set transmit buffer full bit - CommTransmit(); // transmit char - } - - if (disp & DISP_POINTER) - { - disp &= ~DISP_POINTER; // display pointer updated - UpdateDisplayPointers(); - } - if (dwAnnunciator) - { - UpdateAnnunciators(dwAnnunciator); - } - return; -} +/* + * mops.c + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ +#include "pch.h" +#include "Emu48.h" +#include "ops.h" +#include "opcodes.h" +#include "io.h" +#include "i28f160.h" // flash support + +// #define DEBUG_SERIAL // switch for SERIAL debug purpose +// #define DEBUG_IO // switch for I/O debug purpose +// #define DEBUG_FLASH // switch for FLASH MEMORY debug purpose + +// defines for reading an open data bus +#define READEVEN 0x0D +#define READODD 0x0E + +// on mapping boundary adjusted base addresses +#define P0MAPBASE ((BYTE)(Chipset.P0Base & ~Chipset.P0Size)) +#define P1MAPBASE ((BYTE)(Chipset.P1Base & ~Chipset.P1Size)) +#define P2MAPBASE ((BYTE)(Chipset.P2Base & ~Chipset.P2Size)) +#define BSMAPBASE ((BYTE)(Chipset.BSBase & ~Chipset.BSSize)) + +BOOL bFlashRomArray = TRUE; // flag ROM mode + +BYTE disp = 0; // flag for update display area + +static LPBYTE pbyRomView[2] = {NULL, NULL}; // HP49G ROM views + +static __inline UINT MIN(UINT a, UINT b) +{ + return (ab)?a:b; +} + +// generate UCK signal +static __inline BYTE UckBit(BYTE byBaudIndex) +{ + // table content = baudrate * 16 + const DWORD dwBaudrates[] = { 19200, 30720, 38400, 61440, 76800, 122880, 153600, 245760 }; + + LARGE_INTEGER lLC; + + _ASSERT(byBaudIndex < ARRAYSIZEOF(dwBaudrates)); + + if ((Chipset.IORam[IOC] & SON) == 0) // UART off + return UCK; // UCK bit always set + + QueryPerformanceCounter(&lLC); // get counter value + + // calculate UCK frequency + return (((BYTE)(((lLC.QuadPart - lAppStart.QuadPart) * dwBaudrates[byBaudIndex]) + / lFreq.QuadPart) & 0x1) << 3); +} + +// calculate nibble based linear flash address +static __inline DWORD FlashROMAddr(DWORD d) +{ + DWORD dwLinAddr; + + // 6 bit of latch (was A6-A1 of address bus) + dwLinAddr = (Chipset.Bank_FF >> 1) & 0x3f; + // decode A21-A18 + dwLinAddr = ((d & 0x40000) ? (dwLinAddr & 0xf) : (dwLinAddr >> 4)) << 18; + // decode A21-A18, A17-A0 + dwLinAddr |= d & 0x3FFFF; + return dwLinAddr; +} + +// update display +static __inline VOID UpdateDisplay(DWORD d, UINT s) +{ + BYTE p[16]; + DWORD u; + UINT c; + + // address in display main area? + if ((dChipset.start12)) + { + // write to display main area + u = d; // copy destination ptr + c = MIN(s,Chipset.end1-d); // number of nibbles to copy + + if (d < Chipset.start12) // first address is out of display area + { + u = Chipset.start12; // set destination ptr to start of display area + c -= Chipset.start12 - d; // - number of bytes that aren't in display area + } + + _ASSERT(c <= ARRAYSIZEOF(p)); + Npeek(p,u,c); // get source data + WriteToMainDisplay(p,u,c); + } + // address in display menu area? + if ((dChipset.start2)) + { + // write to display menu area + u = d; // copy destination ptr + c = MIN(s,Chipset.end2-d); // number of nibbles to copy + + if (d < Chipset.start2) // first address is out of display area + { + u = Chipset.start2; // set destination ptr to start of display area + c -= Chipset.start2 - d; // - number of bytes that are not in display area + } + + _ASSERT(c <= ARRAYSIZEOF(p)); + Npeek(p,u,c); // get source data + WriteToMenuDisplay(p,u,c); + } + return; +} + +// port mapping + +LPBYTE RMap[256] = {NULL,}; +LPBYTE WMap[256] = {NULL,}; + +static VOID MapP0(BYTE a, BYTE b) +{ + UINT i; + DWORD p, m; + + a = (BYTE)MAX(a,P0MAPBASE); // adjust base to mapping boundary + b = (BYTE)MIN(b,Chipset.P0End); + m = (Chipset.Port0Size*2048)-1; + p = (a<<12)&m; // offset to begin of P0 in nibbles + for (i=a; i<=b; i++) + { + // mapping area may have holes + if (((i ^ Chipset.P0Base) & ~Chipset.P0Size) == 0) + { + RMap[i]=Port0 + p; + WMap[i]=Port0 + p; + } + p = (p+0x1000)&m; + } + return; +} + +static VOID MapBS(BYTE a, BYTE b) +{ + UINT i; + + a = (BYTE)MAX(a,BSMAPBASE); // adjust base to mapping boundary + b = (BYTE)MIN(b,Chipset.BSEnd); + for (i=a;i<=b;i++) + { + // mapping area may have holes + if (((i ^ Chipset.BSBase) & ~Chipset.BSSize) == 0) + { + RMap[i]=NULL; // no read cycle, open data bus + WMap[i]=NULL; + } + } + return; +} + +static VOID MapP1(BYTE a, BYTE b) +{ + UINT i; + DWORD p, m; + + // clear mapping area if port1 is configured but not plugged + a = (BYTE)MAX(a,P1MAPBASE); // lowest address for use is P1Base + b = (BYTE)MIN(b,Chipset.P1End); // highest address for use is P1End + + // port1 not plugged + if (Port1 == NULL || !(Chipset.cards_status & PORT1_PRESENT)) + { + for (i=a; i<=b; i++) // scan each 2KB page + { + if (((i ^ Chipset.P1Base) & ~Chipset.P1Size) == 0) + { + RMap[i]=NULL; + WMap[i]=NULL; + } + } + return; + } + + m = (Chipset.Port1Size*2048)-1; // real size of module, address mask for mirroring + p = (a<<12)&m; // offset to begin of P1 in nibbles + + if (Chipset.cards_status & PORT1_WRITE) // port1 write enabled + { + for (i=a; i<=b; i++) // scan each 2KB page + { + // mapping area may have holes + if (((i ^ Chipset.P1Base) & ~Chipset.P1Size) == 0) + { + RMap[i]=Port1 + p; // save page address for read + WMap[i]=Port1 + p; // save page address for write + } + p = (p+0x1000)&m; // next page, mirror page if real size smaller allocated size + } + } + else // port1 read only + { + for (i=a; i<=b; i++) // scan each 2KB page + { + // mapping area may have holes + if (((i ^ Chipset.P1Base) & ~Chipset.P1Size) == 0) + { + RMap[i]=Port1 + p; // save page address for read + WMap[i]=NULL; // no writing + } + p = (p+0x1000)&m; // next page, mirror page if real size smaller allocated size + } + } + return; +} + +static VOID MapP2(BYTE a, BYTE b) +{ + UINT i; + DWORD p, m; + LPBYTE pbyTemp; + + // clear mapping area if port2 is configured but not plugged + a = (BYTE)MAX(a,P2MAPBASE); // adjust base to mapping boundary + b = (BYTE)MIN(b,Chipset.P2End); + + if (Chipset.Port2Size) // internal port2 + { + m = (Chipset.Port2Size*2048)-1; + p = (a<<12)&m; // offset to begin of P0 in nibbles + for (i=a; i<=b; i++) + { + // mapping area may have holes + if (((i ^ Chipset.P2Base) & ~Chipset.P2Size) == 0) + { + RMap[i]=Port2 + p; + WMap[i]=Port2 + p; + } + p = (p+0x1000)&m; + } + return; + } + + // HP48SX / HP48GX + // only fill mapping table when CE2.2 is set + for (i=a; i<=b; i++) // fill mapping area with not configured + { + // mapping area may have holes + if (((i ^ Chipset.P2Base) & ~Chipset.P2Size) == 0) + { + RMap[i]=NULL; + WMap[i]=NULL; + } + } + + // port2 not plugged + if (pbyPort2 == NULL || !(Chipset.cards_status & PORT2_PRESENT)) + return; + + pbyTemp = pbyPort2; + if (cCurrentRomType != 'S') // bank switching only with GX + { + // Chipset.Port2_Bank is the saved port2 FF content + pbyTemp += (((Chipset.Bank_FF>>1)-1)&dwPort2Mask) << 18; + } + + // max. size per bank is 128KB + m = (dwPort2Size > 128) ? 128 : dwPort2Size; + + m = (m * 2048) - 1; // real size of module, address mask for mirroring + p = (a << 12) & m; // offset to begin of P2 in nibbles + + // SX: CE2.2 = CE2 + // GX: CE2.2 = BEN & /DA19 & /NCE3 + if (cCurrentRomType == 'S' || ((Chipset.IORam[0x29]&DA19) == 0 && (Chipset.Bank_FF&0x40))) + { + if (bPort2Writeable) + { + for (i=a; i<=b; i++) + { + // mapping area may have holes + if (((i ^ Chipset.P2Base) & ~Chipset.P2Size) == 0) + { + RMap[i]=pbyTemp + p; + WMap[i]=pbyTemp + p; + } + p = (p+0x1000)&m; + } + } + else + { + for (i=a; i<=b; i++) + { + // mapping area may have holes + if (((i ^ Chipset.P2Base) & ~Chipset.P2Size) == 0) + { + RMap[i]=pbyTemp + p; + } + p = (p+0x1000)&m; + } + } + } + return; +} + +static VOID MapROM(BYTE a, BYTE b) +{ + UINT i; + DWORD p, m; + + // HP39/49G, HP49G + if (cCurrentRomType == 'E' || cCurrentRomType == 'X') + { + if (bFlashRomArray) // view flash ROM data + { + _ASSERT(pbyRomView[0]); // check ROM bank set + _ASSERT(pbyRomView[1]); + + m = (128*1024*2)-1; // mapped in 128KB pages + p = (a<<12)&m; // offset to the begin of ROM in nibbles + for (i=a; i<=b; i++) // scan each 2KB page + { + RMap[i]=pbyRomView[(i & 0x40)!=0] + p; + WMap[i]=NULL; // no writing + p = (p+0x1000)&m; + } + } + else // view flash ROM register + { + for (i=a; i<=b; i++) // scan each 2KB page + { + RMap[i]=NULL; // view flash register + WMap[i]=NULL; // no writing + } + } + return; + } + + // HP38G / HP48SX / HP48GX + m = dwRomSize - 1; // ROM address mask for mirroring + // when 512KB ROM and DA19=0 (ROM disabled) + if ((m & 0x80000) != 0 && (Chipset.IORam[0x29]&DA19) == 0) + m >>= 1; // mirror ROM at #80000 (AR18=0) + p = (a*0x1000)&m; // data offset in nibbles + for (i=a;i<=b;i++) // scan each 2KB page + { + RMap[i]=pbyRom + p; // save page address for read + WMap[i]=NULL; // no writing + p = (p+0x1000)&m; // next page, mirror page if real size smaller allocated size + } + return; +} + +VOID Map(BYTE a, BYTE b) // maps 2KB pages with priority +{ + // On HP39/40G and HP49G Chipset.cards_status must be 0xF + _ASSERT((cCurrentRomType!='E' && cCurrentRomType!='X') || !Chipset.P1Cfig || Chipset.cards_status == 0xF); + + // priority order is HDW, RAM, CE2, CE1, NCE3, ROM + MapROM(a,b); // ROM, lowest priority, always mapped + if (cCurrentRomType == 'S') // HP48SX + { + if (Chipset.BSCfig) MapBS(a,b); // NCE3, not used in S(X) + if (Chipset.P1Cfig) MapP1(a,b); // CE1, port1 (lower priority than CE2) + if (Chipset.P2Cfig) MapP2(a,b); // CE2, port2 (higher priority than CE1) + } + else // HP48GX / HP49G + { + if (Chipset.P2Cfig) // NCE3, port2 + { + // LED bit set on a HP49 + if (cCurrentRomType=='X' && (Chipset.IORam[LCR]&LED)) + MapROM(a,b); // NCE3, ROM + else + MapP2(a,b); // NCE3, port2 + } + if (Chipset.BSCfig) MapBS(a,b); // CE1, bank select (lower priority than CE2) + if (Chipset.P1Cfig) MapP1(a,b); // CE2, port1 (higher priority than CE1) + } + if (Chipset.P0Cfig) MapP0(a,b); // RAM, highest priority (execpt HDW) + return; +} + +VOID RomSwitch(DWORD adr) +{ + // only HP39/40G, HP49G + if (cCurrentRomType=='E' || cCurrentRomType=='X') + { + Chipset.Bank_FF = adr; // save address line + adr = (adr >> 1) & 0x3f; // 6 bit of latch (was A6-A1 of address bus) + // lower 4 bit (16 banks) for 2nd ROM view + pbyRomView[1] = pbyRom + (((adr & 0xf) * 128 * 1024 * 2) & (dwRomSize - 1)); + // higher 2 bit (4 banks) for 1st ROM view + pbyRomView[0] = pbyRom + (((adr >> 4) * 128 * 1024 * 2) & (dwRomSize - 1)); + } + Map(0x00,0xFF); // update memory mapping + return; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Bus Commands +// +//////////////////////////////////////////////////////////////////////////////// + +VOID Config() // configure modules in fixed order +{ + DWORD d = Npack(Chipset.C,5); // decode size or address + BYTE b = (BYTE)(d>>12); // number of 2KB pages or page address + BYTE s = (BYTE)(b^0xFF); // size in pages-1, offset to last page + + // config order is HDW, RAM, CE1, CE2, NCE3 + if (!Chipset.IOCfig) // address of HDW, first module, ROM always configured + { + Chipset.IOCfig = TRUE; + Chipset.IOBase = d&0xFFFC0; // save HDW base on a 64 nib boundary + Map(b,b); + return; + } + if (!Chipset.P0Cfg2) // RAM size, port0 + { + Chipset.P0Cfg2 = TRUE; + Chipset.P0Size = s; // offset to last used page + return; + } + if (!Chipset.P0Cfig) // RAM address, port0 + { + Chipset.P0Cfig = TRUE; + Chipset.P0Base = b; // save first page address + b &= ~Chipset.P0Size; // adjust base to mapping boundary + Chipset.P0End = b+Chipset.P0Size; // save last page address + Map(b,Chipset.P0End); // refresh mapping + return; + } + if (cCurrentRomType=='S') // HP48SX + { + if (!Chipset.P1Cfg2) // CE1 size, port1 + { + Chipset.P1Cfg2 = TRUE; + Chipset.P1Size = s; + return; + } + if (!Chipset.P1Cfig) // CE1 address, port1 + { + Chipset.P1Cfig = TRUE; + Chipset.P1Base = b; + b &= ~Chipset.P1Size; // adjust base to mapping boundary + Chipset.P1End = b+Chipset.P1Size; + Map(b,Chipset.P1End); // refresh mapping + return; + } + if (!Chipset.P2Cfg2) // CE2 size, port2 + { + Chipset.P2Cfg2 = TRUE; + Chipset.P2Size = s; + return; + } + if (!Chipset.P2Cfig) // CE2 address, port2 + { + Chipset.P2Cfig = TRUE; + Chipset.P2Base = b; + b &= ~Chipset.P2Size; // adjust base to mapping boundary + Chipset.P2End = b+Chipset.P2Size; + Map(b,Chipset.P2End); // refresh mapping + return; + } + if (!Chipset.BSCfg2) // NCE3 size, not used in S(X) + { + Chipset.BSCfg2 = TRUE; + Chipset.BSSize = s; + return; + } + if (!Chipset.BSCfig) // NCE3 address, not used in S(X) + { + Chipset.BSCfig = TRUE; + Chipset.BSBase = b; + b &= ~Chipset.BSSize; // adjust base to mapping boundary + Chipset.BSEnd = b+Chipset.BSSize; + Map(b,Chipset.BSEnd); // refresh mapping + return; + } + } + else // HP48GX / HP49G + { + if (!Chipset.BSCfg2) // CE1 size, bank select + { + Chipset.BSCfg2 = TRUE; + Chipset.BSSize = s; + return; + } + if (!Chipset.BSCfig) // CE1 address, bank select + { + Chipset.BSCfig = TRUE; + Chipset.BSBase = b; + b &= ~Chipset.BSSize; // adjust base to mapping boundary + Chipset.BSEnd = b+Chipset.BSSize; + Map(b,Chipset.BSEnd); // refresh mapping + return; + } + if (!Chipset.P1Cfg2) // CE2 size, port1 + { + Chipset.P1Cfg2 = TRUE; + Chipset.P1Size = s; + return; + } + if (!Chipset.P1Cfig) // CE2 address, port1 + { + Chipset.P1Cfig = TRUE; + Chipset.P1Base = b; + b &= ~Chipset.P1Size; // adjust base to mapping boundary + Chipset.P1End = b+Chipset.P1Size; + Map(b,Chipset.P1End); // refresh mapping + return; + } + if (!Chipset.P2Cfg2) // NCE3 size, port2 + { + Chipset.P2Cfg2 = TRUE; + Chipset.P2Size = s; + return; + } + if (!Chipset.P2Cfig) // NCE3 address, port2 + { + Chipset.P2Cfig = TRUE; + Chipset.P2Base = b; + b &= ~Chipset.P2Size; // adjust base to mapping boundary + Chipset.P2End = b+Chipset.P2Size; + Map(b,Chipset.P2End); // refresh mapping + return; + } + } + return; +} + +VOID Uncnfg() +{ + DWORD d=Npack(Chipset.C,5); // decode address + BYTE b=(BYTE)(d>>12); // page address + + // unconfig order is HDW, RAM, CE2, CE1, NCE3 + if ((Chipset.IOCfig)&&((d&0xFFFC0)==Chipset.IOBase)) + {Chipset.IOCfig=FALSE;Map(b,b);return;} + if ((Chipset.P0Cfig)&&((b&~Chipset.P0Size)==P0MAPBASE)) + {Chipset.P0Cfig=FALSE;Chipset.P0Cfg2=FALSE;Map(P0MAPBASE,Chipset.P0End);return;} + if (cCurrentRomType=='S') // HP48SX + { + if ((Chipset.P2Cfig)&&((b&~Chipset.P2Size)==P2MAPBASE)) + {Chipset.P2Cfig=FALSE;Chipset.P2Cfg2=FALSE;Map(P2MAPBASE,Chipset.P2End);return;} + if ((Chipset.P1Cfig)&&((b&~Chipset.P1Size)==P1MAPBASE)) + {Chipset.P1Cfig=FALSE;Chipset.P1Cfg2=FALSE;Map(P1MAPBASE,Chipset.P1End);return;} + if ((Chipset.BSCfig)&&((b&~Chipset.BSSize)==BSMAPBASE)) + {Chipset.BSCfig=FALSE;Chipset.BSCfg2=FALSE;Map(BSMAPBASE,Chipset.BSEnd);return;} + } + else // HP48GX / HP49G + { + if ((Chipset.P1Cfig)&&((b&~Chipset.P1Size)==P1MAPBASE)) + {Chipset.P1Cfig=FALSE;Chipset.P1Cfg2=FALSE;Map(P1MAPBASE,Chipset.P1End);return;} + if ((Chipset.BSCfig)&&((b&~Chipset.BSSize)==BSMAPBASE)) + {Chipset.BSCfig=FALSE;Chipset.BSCfg2=FALSE;Map(BSMAPBASE,Chipset.BSEnd);return;} + if ((Chipset.P2Cfig)&&((b&~Chipset.P2Size)==P2MAPBASE)) + {Chipset.P2Cfig=FALSE;Chipset.P2Cfg2=FALSE;Map(P2MAPBASE,Chipset.P2End);return;} + } + return; +} + +VOID Reset() +{ + Chipset.IOCfig=FALSE;Chipset.IOBase=0x100000; + Chipset.P0Cfig=FALSE;Chipset.P0Cfg2=FALSE;Chipset.P0Base=0;Chipset.P0Size=0;Chipset.P0End=0; + Chipset.BSCfig=FALSE;Chipset.BSCfg2=FALSE;Chipset.BSBase=0;Chipset.BSSize=0;Chipset.BSEnd=0; + Chipset.P1Cfig=FALSE;Chipset.P1Cfg2=FALSE;Chipset.P1Base=0;Chipset.P1Size=0;Chipset.P1End=0; + Chipset.P2Cfig=FALSE;Chipset.P2Cfg2=FALSE;Chipset.P2Base=0;Chipset.P2Size=0;Chipset.P2End=0; + Map(0x00,0xFF); // refresh mapping + return; +} + +VOID C_Eq_Id() +{ + // config order is HDW, RAM, CE1, CE2, NCE3 + if (!Chipset.IOCfig) {Nunpack(Chipset.C,(Chipset.IOBase) ^0x00019,5);return;} + if (!Chipset.P0Cfg2) {Nunpack(Chipset.C,(Chipset.P0Size*0x1000)^0xFF003,5);return;} + if (!Chipset.P0Cfig) {Nunpack(Chipset.C,(Chipset.P0Base*0x1000)^0x000F4,5);return;} + if (cCurrentRomType=='S') // HP48SX + { + if (!Chipset.P1Cfg2) {Nunpack(Chipset.C,(Chipset.P1Size*0x1000)^0xFF005,5);return;} + if (!Chipset.P1Cfig) {Nunpack(Chipset.C,(Chipset.P1Base*0x1000)^0x000F6,5);return;} + if (!Chipset.P2Cfg2) {Nunpack(Chipset.C,(Chipset.P2Size*0x1000)^0xFF007,5);return;} + if (!Chipset.P2Cfig) {Nunpack(Chipset.C,(Chipset.P2Base*0x1000)^0x000F8,5);return;} + if (!Chipset.BSCfg2) {Nunpack(Chipset.C,(Chipset.BSSize*0x1000)^0xFF001,5);return;} + if (!Chipset.BSCfig) {Nunpack(Chipset.C,(Chipset.BSBase*0x1000)^0x000F2,5);return;} + } + else // HP48GX / HP49G + { + if (!Chipset.BSCfg2) {Nunpack(Chipset.C,(Chipset.BSSize*0x1000)^0xFF005,5);return;} + if (!Chipset.BSCfig) {Nunpack(Chipset.C,(Chipset.BSBase*0x1000)^0x000F6,5);return;} + if (!Chipset.P1Cfg2) {Nunpack(Chipset.C,(Chipset.P1Size*0x1000)^0xFF007,5);return;} + if (!Chipset.P1Cfig) {Nunpack(Chipset.C,(Chipset.P1Base*0x1000)^0x000F8,5);return;} + if (!Chipset.P2Cfg2) {Nunpack(Chipset.C,(Chipset.P2Size*0x1000)^0xFF001,5);return;} + if (!Chipset.P2Cfig) {Nunpack(Chipset.C,(Chipset.P2Base*0x1000)^0x000F2,5);return;} + } + memset(Chipset.C,0,5); + return; +} + +enum MMUMAP MapData(DWORD d) // check MMU area +{ + BYTE u = (BYTE) (d>>12); + + if (Chipset.IOCfig && ((d&0xFFFC0)==Chipset.IOBase)) return M_IO; + if (Chipset.P0Cfig && (((u^Chipset.P0Base) & ~Chipset.P0Size) == 0)) return M_RAM; + if (cCurrentRomType == 'S') + { + if (Chipset.P2Cfig && (((u^Chipset.P2Base) & ~Chipset.P2Size) == 0)) return M_P2; + if (Chipset.P1Cfig && (((u^Chipset.P1Base) & ~Chipset.P1Size) == 0)) return M_P1; + if (Chipset.BSCfig && (((u^Chipset.BSBase) & ~Chipset.BSSize) == 0)) return M_BS; + } + else + { + if (Chipset.P1Cfig && (((u^Chipset.P1Base) & ~Chipset.P1Size) == 0)) return M_P1; + if (Chipset.BSCfig && (((u^Chipset.BSBase) & ~Chipset.BSSize) == 0)) return M_BS; + if (Chipset.P2Cfig && (((u^Chipset.P2Base) & ~Chipset.P2Size) == 0)) return M_P2; + } + return M_ROM; +} + +VOID CpuReset(VOID) // register setting after Cpu Reset +{ + StopTimers(); // stop timer, do here because function change Chipset.t2 + + Chipset.pc = 0; + Chipset.rstkp = 0; + ZeroMemory(Chipset.rstk,sizeof(Chipset.rstk)); + Chipset.HST = 0; + Chipset.SoftInt = FALSE; + Chipset.Shutdn = TRUE; + Chipset.inte = TRUE; // enable interrupts + Chipset.intk = TRUE; // INTON + Chipset.intd = FALSE; // no keyboard interrupts pending + Chipset.crc = 0; + Chipset.Bank_FF = 0; // state of bank switcher FF + Chipset.FlashRomState = 0; // WSM state of flash memory + ZeroMemory(Chipset.IORam,sizeof(Chipset.IORam)); + Chipset.IORam[LPE] = RST; // set ReSeT bit at hardware reset + Reset(); // reset MMU + Chipset.t1 = 0; // reset timer values + Chipset.t2 = 0; + Chipset.loffset = 0; // right margin + Chipset.boffset = 0; // left margin + Chipset.lcounter = 0; // number of main display lines + Chipset.contrast = 0; // contrast dark + + UpdateContrast(Chipset.contrast); // update contrast + // display update when changing to run state + CommSetBaud(); // new baudrate + CheckSerial(); // close serial port + + RomSwitch(Chipset.Bank_FF); // force new memory mapping + return; +} + +VOID Npeek(BYTE *a, DWORD d, UINT s) +{ + enum MMUMAP eMap; + DWORD u, v; + UINT c; + BYTE *p; + + do + { + eMap = MapData(d); // get active memory controller + if (M_IO == eMap) // I/O access + { + v = d&0x3F; + + do + { + if (v == LPE) + { + // don't read LPE content with the function ReadIO() + c = 1; + memcpy(a, Chipset.IORam+v, c); + break; + } + if (v >= RBR_LSB && v <= RBR_MSB) + { + // don't read RBR content with the function ReadIO() + c = MIN(s,RBR_MSB-v+1); + memcpy(a, Chipset.IORam+v, c); + break; + } + // all others registers + do + { + if (v < LPE) + { + c = MIN(s,LPE-v); + break; + } + if (v < RBR_LSB && (v+s) > RBR_LSB) + { + c = MIN(s,RBR_LSB-v); + break; + } + c = MIN(s,0x40-v); + } + while (0); + ReadIO(a,v,c,FALSE); + } + while (0); + } + else + { + u = d>>12; + v = d&0xFFF; + c = MIN(s,0x1000-v); + // Flash memory Read access + if (cCurrentRomType=='X' && (Chipset.IORam[LCR] & LED) && M_P2 == eMap) + { + FlashRead(a, FlashROMAddr(d), c); + } + else + { + if ((p=RMap[u]) != NULL) // module mapped + { + memcpy(a, p+v, c); + } + else // open data bus + { + for (u=0; u>12; + v = d&0xFFF; + c = MIN(s,0x1000-v); + // bank switcher access + if (cCurrentRomType!='S' && M_BS == eMap) + { + if (cCurrentRomType=='G') // HP48GX + { + Chipset.Bank_FF = v+c; // save FF value + Map(Chipset.P2Base,Chipset.P2End); + } + if (cCurrentRomType=='E' || cCurrentRomType=='X') // HP39/40G, HP49G + { + RomSwitch(v+c); + } + } + // Flash memory Read access + if (cCurrentRomType=='X' && (Chipset.IORam[LCR] & LED) && M_P2 == eMap) + { + DWORD dwLinAddr = FlashROMAddr(d); + + FlashRead(a, dwLinAddr, c); + + #if defined DEBUG_FLASH + { + TCHAR buffer[256]; + DWORD j; + int i; + + i = wsprintf(buffer,_T("%.5lx: Flash Read : %.5x (%.6x),%u = "),Chipset.pc,d,dwLinAddr,c); + for (j = 0;j < c;++j,++i) + { + buffer[i] = a[j]; + if (buffer[i] > 9) buffer[i] += _T('a') - _T('9') - 1; + buffer[i] += _T('0'); + } + buffer[i++] = _T('\n'); + buffer[i] = 0; + OutputDebugString(buffer); + } + #endif + } + else + { + if ((p=RMap[u]) != NULL) // module mapped + { + memcpy(a, p+v, c); + } + // simulate open data bus + else // open data bus + { + for (u=0; u>12; + v = d&0xFFF; + c = MIN(s,0x1000-v); + // bank switcher access + if (cCurrentRomType!='S' && M_BS == eMap) + { + BOOL bWrite = FALSE; + + // write enabled + if (Chipset.cards_status & PORT2_WRITE) + { + Chipset.Bank_FF = v+c-1;// save FF value + bWrite = TRUE; // bank switched + } + else // write disabled, so latch last read cycle + { + if ((v & 1) != 0) // low address odd + { + Chipset.Bank_FF = v;// save FF value + bWrite = TRUE; // bank switched + } + + if (((v+c) & 1) != 0) // high address odd + { + Chipset.Bank_FF = v+c-1;// save FF value + bWrite = TRUE; // bank switched + } + } + + if (bWrite) // write cycle? + { + // HP48GX + if (cCurrentRomType=='G') Map(Chipset.P2Base,Chipset.P2End); + // HP39/40G, HP49G + if (cCurrentRomType=='E' || cCurrentRomType=='X') RomSwitch(Chipset.Bank_FF); + } + } + // Flash memory Write access + if (cCurrentRomType=='X' && (Chipset.IORam[LCR] & LED) && M_P2 == eMap) + { + DWORD dwLinAddr = FlashROMAddr(d); + + FlashWrite(a, dwLinAddr, c); + + #if defined DEBUG_FLASH + { + TCHAR buffer[256]; + DWORD j; + int i; + + i = wsprintf(buffer,_T("%.5lx: Flash Write: %.5x (%.6x),%u = "),Chipset.pc,d,dwLinAddr,c); + for (j = 0;j < c;++j,++i) + { + buffer[i] = a[j]; + if (buffer[i] > 9) buffer[i] += _T('a') - _T('9') - 1; + buffer[i] += _T('0'); + } + buffer[i++] = _T('\n'); + buffer[i] = 0; + OutputDebugString(buffer); + } + #endif + } + else + { + if ((p=WMap[u]) != NULL) memcpy(p+v, a, c); + } + } + if (!bGrayscale) UpdateDisplay(d, c); // update display + a+=c; + d=(d+c)&0xFFFFF; + } while (s-=c); + return; +} + +DWORD Read5(DWORD d) +{ + BYTE p[5]; + + Npeek(p,d,5); + return Npack(p,5); +} + +BYTE Read2(DWORD d) +{ + BYTE p[2]; + + Npeek(p,d,2); + return (BYTE)(p[0]|(p[1]<<4)); +} + +VOID Write5(DWORD d, DWORD n) +{ + BYTE p[5]; + + Nunpack(p,n,5); + Nwrite(p,d,5); + return; +} + +VOID Write2(DWORD d, BYTE n) +{ + BYTE p[2]; + + Nunpack(p,n,2); + Nwrite(p,d,2); + return; +} + +VOID IOBit(DWORD d, BYTE b, BOOL s) // set/clear bit in I/O section +{ + EnterCriticalSection(&csIOLock); + { + if (s) + Chipset.IORam[d] |= b; // set bit + else + Chipset.IORam[d] &= ~b; // clear bit + } + LeaveCriticalSection(&csIOLock); +} + +static DWORD ReadT2Acc(VOID) +{ + static DWORD dwCyc = 0; // CPU cycle counter at last timer2 read access + + DWORD dwCycDif; + + // CPU cycles since last call + dwCycDif = (DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwCyc; + dwCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); + + // maybe CPU speed measurement, slow down the next 10 CPU opcodes + if (dwCycDif < 150) + { + EnterCriticalSection(&csSlowLock); + { + InitAdjustSpeed(); // init variables if necessary + nOpcSlow = 10; // slow down next 10 opcodes + } + LeaveCriticalSection(&csSlowLock); + } + return ReadT2(); +} + +VOID ReadIO(BYTE *a, DWORD d, DWORD s, BOOL bUpdate) +{ + BOOL bNINT,bNINT2; + BOOL bLBI,bVLBI; + + BYTE c = 0xFF; // LINECOUNT not initialized + BOOL rbr_acc = FALSE; // flag to receive data + + #if defined DEBUG_IO + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: IO read : %02x,%u\n"),Chipset.pc,d,s); + OutputDebugString(buffer); + } + #endif + + do + { + switch (d) + { + case 0x00: *a = (Chipset.IORam[d]&DON)|Chipset.boffset; break; + case 0x01: *a = Chipset.contrast&0xF; break; + case 0x02: *a = Chipset.contrast>>4; break; + case 0x03: *a = 0; + case 0x04: *a = (Chipset.crc )&0xF; break; + case 0x05: *a = (Chipset.crc>> 4)&0xF; break; + case 0x06: *a = (Chipset.crc>> 8)&0xF; break; + case 0x07: *a = (Chipset.crc>>12)&0xF; break; + case 0x08: // LPD + // LB2 and LB1 not emulated, must be 0 + _ASSERT((Chipset.IORam[LPD] & (LB2 | LB1)) == 0); + + GetBatteryState(&bLBI,&bVLBI); // get battery state + + // check if battery states enabled + bLBI = bLBI && ((Chipset.IORam[LPE] & ELBI) != 0); + bVLBI = bVLBI && ((Chipset.IORam[LPE] & EVLBI) != 0); + + // set IO bits + IOBit(LPD,LB0,bLBI); + IOBit(LPD,VLBI,bVLBI); + IOBit(SRQ1,VSRQ,bVLBI); + *a = Chipset.IORam[d]; + break; + case 0x09: // LPE + *a = Chipset.IORam[d]; + if (bUpdate) + { + Chipset.IORam[d] &= ~RST; // clear RST bit after reading + } + break; + case 0x0A: *a = 0; break; +// case 0x0B: *a = Chipset.IORam[d]; break; +// case 0x0C: *a = Chipset.IORam[d]; break; + case 0x0D: // BAUD + *a = Chipset.IORam[d] & 0x7; + #if defined DEBUG_SERIAL // return BAUD value + if (bUpdate) + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: BAUD Read: %x\n"),Chipset.pc,*a); + OutputDebugString(buffer); + } + #endif + *a |= UckBit(*a); // add UCK bit to BAUD rate register + break; + case 0x0E: + // SMP is !NINT and SWINT is always 0 + // clear SMP and SWINT bit + Chipset.IORam[d] &= (ECDT | RCDT); + // SMP is !NINT + if ((Chipset.IORam[SRQ2] & NINT) == 0) + Chipset.IORam[d] |= SMP; + *a = Chipset.IORam[d]; + break; + case 0x0F: + // card detection disabled + if ((Chipset.IORam[CARDCTL] & ECDT) == 0) + { + *a = 0; // no cards + } + else + { + // on a HP30/40G and HP49G Chipset.cards_status bust always be 0xF + _ASSERT((cCurrentRomType!='E' && cCurrentRomType!='X') || Chipset.cards_status == 0xF); + *a = Chipset.cards_status; + } + break; + case 0x10: // IO CONTROL + *a = Chipset.IORam[d]; // return IO CONTROL value + #if defined DEBUG_SERIAL + if (bUpdate) + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: IOC Read: %x\n"),Chipset.pc,*a); + OutputDebugString(buffer); + } + #endif + break; + case 0x11: // RCS + *a = Chipset.IORam[d] | RX; // return RCS value + #if defined DEBUG_SERIAL + if (bUpdate) + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: RCS Read: %x\n"),Chipset.pc,*a); + OutputDebugString(buffer); + } + #endif + break; + case 0x12: // TCS + *a = Chipset.IORam[d]; // return TCS value + + if ((*a & TBF)) // Transmit buffer full + { + // the G-series XModem implementation has a timeout loop counter + // waiting for transmit buffer empty, so on fast hosts with + // CPU running with max. speed we may get a timeout overflow + // -> to avoid this slow down CPU speed on transmit buffer full + + EnterCriticalSection(&csSlowLock); + { + InitAdjustSpeed(); // init variables if necessary + nOpcSlow = 10; // slow down next 10 opcodes + } + LeaveCriticalSection(&csSlowLock); + } + + #if defined DEBUG_SERIAL + if (bUpdate) + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: TCS Read: %x\n"),Chipset.pc,*a); + OutputDebugString(buffer); + } + #endif + break; + case 0x13: // CRER + *a = 0; + break; + case 0x14: // RBR LSB + case 0x15: // RBR MSB + if (bUpdate) + { + *a = Chipset.IORam[d]; // return RBR value + if (d==0x15) // reading RBR MSB + { + Chipset.IORam[RCS] &= ~RBF; // clear Receive Buffer Full flag + } + UpdateUSRQ(); // update USRQ + rbr_acc = TRUE; // search for new RBR value + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: RBR %s Read: %x\n"),Chipset.pc,(d==0x14) ? "LSB" : "MSB",*a); + OutputDebugString(buffer); + } + #endif + } + else + { + *a = Chipset.IORam[d]; // return RBR value + UpdateUSRQ(); // update USRQ + } + break; +// case 0x16: *a = Chipset.IORam[d]; break; // TBR LSB +// case 0x17: *a = Chipset.IORam[d]; break; // TBR MSB + case 0x19: // SREQ? MSB + UpdateKdnBit(); // update KDN bit + bNINT2 = Chipset.IORam[SRQ1] == 0 && (Chipset.IORam[SRQ2] & LSRQ) == 0; + bNINT = (Chipset.IORam[SRQ2] & NINT) != 0; + // card detection off and timer running + if ((Chipset.IORam[CARDCTL] & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0) + { + // state of CDT2 + bNINT2 = bNINT2 && (Chipset.cards_status & (P2W|P2C)) != P2C; + // state of CDT1 + bNINT = bNINT && (Chipset.cards_status & (P1W|P1C)) != P1C; + } + IOBit(SRQ2,NINT2,bNINT2); + IOBit(SRQ2,NINT,bNINT); + // no break! + case 0x18: // SREQ? LSB + *a = Chipset.IORam[d]; // return SREQ value + #if defined DEBUG_SERIAL + if (bUpdate) + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: SEQ %s Read: %x\n"),Chipset.pc,(d==0x18) ? "LSB" : "MSB",*a); + OutputDebugString(buffer); + } + #endif + break; + case 0x1A: // IR CONTROL + if (cCurrentRomType=='E') // HP39/40G + { + Chipset.IORam[d] = (nCurrentClass != 40) + ? (Chipset.IORam[d] & ~IRI) // HP39G + : (Chipset.IORam[d] | IRI); // HP40G + } + *a = Chipset.IORam[d]; // return IR CONTROL value + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: IRC Read: %x\n"),Chipset.pc,*a); + OutputDebugString(buffer); + } + #endif + break; + case 0x1B: *a = 0; break; + case 0x1C: // LED CONTROL + // put LBF and LBZ always to zero to indicate a free REDEYE buffer and formatter + *a = (Chipset.IORam[d] & (LED|ELBE)); + break; + case 0x1D: // LED BUFFER + *a = (Chipset.IORam[d] & LBO); + break; +// case 0x1E: *a = Chipset.IORam[d]; break; +// case 0x1F: *a = Chipset.IORam[d]; break; + case 0x20: *a = 3; break; + case 0x21: *a = 3; break; + case 0x22: *a = 3; break; + case 0x23: *a = 3; break; + case 0x24: *a = 3; break; + case 0x25: *a = 3; break; + case 0x26: *a = 3; break; + case 0x27: *a = 3; break; + case 0x28: // LINECOUNT LSB + case 0x29: // LINECOUNT MSB + DA19 M32 + if (Chipset.IORam[0x00]&DON) // display on + { + if (c == 0xFF) // no actual line information + { + c = GetLineCounter(); // get LCD update line + // save line information in IO registers + Chipset.IORam[0x28] = c & 0xF; + Chipset.IORam[0x29] = (Chipset.IORam[0x29] & (DA19|M32)) | (c >> 4); + } + } + *a = Chipset.IORam[d]; + + if (d==0x29) // address 0x29 is mirrored to 0x2A-0x2D + { + Chipset.IORam[0x2A] = *a; + Chipset.IORam[0x2B] = *a; + Chipset.IORam[0x2C] = *a; + Chipset.IORam[0x2D] = *a; + } + break; +// case 0x2A: *a = 0; break; +// case 0x2B: *a = 0; break; +// case 0x2C: *a = 0; break; +// case 0x2D: *a = 0; break; + case 0x2E: + ReadT1(); // dummy read for update timer1 control register + *a = Chipset.IORam[d]; + break; + case 0x2F: + ReadT2(); // dummy read for update timer2 control register + *a = Chipset.IORam[d]; + break; + case 0x30: *a = 3; break; + case 0x31: *a = 3; break; + case 0x32: *a = 3; break; + case 0x33: *a = 3; break; + case 0x34: *a = 3; break; + case 0x35: *a = 0; break; + case 0x36: *a = 0; break; + case 0x37: *a = ReadT1(); break; + case 0x38: Nunpack(a, ReadT2Acc() , s); return; + case 0x39: Nunpack(a, ReadT2Acc()>> 4, s); return; + case 0x3A: Nunpack(a, ReadT2Acc()>> 8, s); return; + case 0x3B: Nunpack(a, ReadT2Acc()>>12, s); return; + case 0x3C: Nunpack(a, ReadT2Acc()>>16, s); return; + case 0x3D: Nunpack(a, ReadT2Acc()>>20, s); return; + case 0x3E: Nunpack(a, ReadT2Acc()>>24, s); return; + case 0x3F: Nunpack(a, ReadT2Acc()>>28, s); return; + default: *a = Chipset.IORam[d]; + } + d++; a++; + } while (--s); + if (rbr_acc) CommReceive(); // look for new character + return; +} + +VOID WriteIO(BYTE *a, DWORD d, DWORD s) +{ + DWORD b; + BYTE c; + BOOL tbr_acc = FALSE; // flag to transmit data + BOOL bDISPADDR = FALSE; // flag addr 0x120-0x124 changed + BOOL bLINEOFFS = FALSE; // flag addr 0x125-0x127 changed + BOOL bMENUADDR = FALSE; // flag addr 0x130-0x134 changed + DWORD dwAnnunciator = 0; // no annunciator write + + #if defined DEBUG_IO + { + TCHAR buffer[256]; + DWORD j; + int i; + + i = wsprintf(buffer,_T("%.5lx: IO write: %02x,%u = "),Chipset.pc,d,s); + for (j = 0;j < s;++j,++i) + { + buffer[i] = a[j]; + if (buffer[i] > 9) buffer[i] += _T('a') - _T('9') - 1; + buffer[i] += _T('0'); + } + buffer[i++] = _T('\n'); + buffer[i] = 0; + OutputDebugString(buffer); + } + #endif + + do + { + c = *a; + switch (d) + { +// 00100 = NS:DISPIO +// 00100 @ Display bit offset and DON [DON OFF2 OFF1 OFF0] +// 00100 @ 3 nibs for display offset (scrolling), DON=Display ON + case 0x00: + if ((c^Chipset.IORam[d])&DON) // DON bit changed + { + disp |= (DISP_POINTER | DISP_MAIN | DISP_MENUE); + + // adjust VBL counter start/stop values + if ((c & DON) != 0) // set display on + { + Chipset.IORam[d] |= DON; // for StartDisplay(); + UpdateContrast(Chipset.contrast); + StartDisplay((BYTE) Chipset.lcounter); // start display update + } + else // display is off + { + Chipset.IORam[d] &= ~DON; + UpdateContrast(Chipset.contrast); + StopDisplay(); // stop display update + } + } + // OFF bits changed + if ((c^Chipset.IORam[d]) & (OFF2 | OFF1 | OFF0)) + { + Chipset.boffset = c & (OFF2 | OFF1 | OFF0); + disp |= (DISP_POINTER | DISP_MAIN); + } + Chipset.IORam[d] = c; + break; + +// 00101 = NS:CONTRLSB +// 00101 @ Contrast Control [CON3 CON2 CON1 CON0] +// 00101 @ Higher value = darker screen + case 0x01: + if (c!=Chipset.IORam[d]) + { + Chipset.IORam[d]=c; + Chipset.contrast = (Chipset.contrast&0x10)|c; + UpdateContrast(Chipset.contrast); + disp |= (DISP_MAIN | DISP_MENUE); + } + break; + +// 00102 = NS:DISPTEST +// 00102 @ Display test [VDIG LID TRIM CON4] [LRT LRTD LRTC BIN] +// 00102 @ Normally zeros + case 0x02: + if (c!=Chipset.IORam[d]) + { + Chipset.IORam[d]=c; + Chipset.contrast = (Chipset.contrast&0x0f)|((c&1)<<4); + UpdateContrast(Chipset.contrast); + disp |= (DISP_MAIN | DISP_MENUE); + } + break; + + case 0x03: Chipset.IORam[d]=c; break; + +// 00104 = HP:CRC +// 00104 @ 16 bit hardware CRC (104-107) (X^16+X^12+X^5+1) +// 00104 @ crc = ( crc >> 4 ) ^ ( ( ( crc ^ nib ) & 0x000F ) * 0x1081 ); + case 0x04: Chipset.crc = (Chipset.crc&0xfff0)|(c*0x0001); break; + case 0x05: Chipset.crc = (Chipset.crc&0xff0f)|(c*0x0010); break; + case 0x06: Chipset.crc = (Chipset.crc&0xf0ff)|(c*0x0100); break; + case 0x07: Chipset.crc = (Chipset.crc&0x0fff)|(c*0x1000); break; + +// 00108 = NS:POWERSTATUS +// 00108 @ Low power registers (108-109) +// 00108 @ [LB2 LB1 LB0 VLBI] (read only) +// 00108 @ LowBat(2) LowBat(1) LowBat(S) VeryLowBat + case 0x08: break; // read-only + +// 00109 = NS:POWERCTRL +// 00109 @ [ELBI EVLBI GRST RST] (read/write) + case 0x09: + Chipset.IORam[d]=c; + if (c & RST) + { + CpuReset(); // emulate NRES signal + disp |= (DISP_POINTER | DISP_MAIN | DISP_MENUE); + dwAnnunciator = 0x3F; // update all annunciators + bInterrupt = TRUE; // SHUTDN + } + break; + +// 0010A = NS:MODE +// 0010A @ Mode Register (read-only) + case 0x0A: break; // read-only + +// 0010B = HP:ANNCTRL +// 0010B @ Annunciator control [LA4 LA3 LA2 LA1] = [ alarm alpha -> <- ] + case 0x0B: + case 0x0C: + // annunciator changed + dwAnnunciator |= ((Chipset.IORam[d] ^c) << ((d - 0x0B) * 4)) & 0x3F; + Chipset.IORam[d] = c; + break; + +// 0010D = NS:BAUD +// 0010D @ Serial baud rate [UCK BD2 BD1 BD0] (bit 3 is read-only) +// 0010D @ 3 bits = {1200 1920 2400 3840 4800 7680 9600 15360} + case 0x0D: + Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); // bit 3 is read-only + CommSetBaud(); // set baudrate + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: BAUD write: %x\n"),Chipset.pc,Chipset.IORam[d]); + OutputDebugString(buffer); + } + #endif + break; + +// 0010E = NS:CARDCTL +// 0010E @ [ECDT RCDT SMP SWINT] (read/write) +// 0010E @ Enable Card Det., Run Card Det., Set Module Pulled, Software interrupt + case 0x0E: + if (c & SWINT) // SWINT bit set + { + c &= (ECDT | RCDT | SMP); // clear SWINT bit + Chipset.SoftInt = TRUE; + bInterrupt = TRUE; + } + if ((c & SMP) == 0) // SMP bit cleared + { + BOOL bNINT = TRUE; // ack NINT interrupt -> NINT high + // card detect disabled and CDT1 low -> retrigger + if ((c & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0) + bNINT = (Chipset.cards_status & (P1W|P1C)) != P1C; + IOBit(SRQ2,NINT,bNINT); + } + // falling edge of Enable Card Detect bit and timer running + if ( ((c^Chipset.IORam[d]) & ECDT) != 0 && (c & ECDT) == 0 + && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0) + { + BOOL bNINT = (Chipset.IORam[SRQ2] & NINT) != 0; + // card in slot1 isn't Read Only + if ((Chipset.cards_status & (P1W|P1C)) != P1C) + { + // use random state of NINT line + bNINT = bNINT && (ReadT2() & 0x1) != 0; + } + IOBit(SRQ2,NINT,bNINT); + + Chipset.HST |= MP; // set Module Pulled + + // Port1 and Port2 plugged and writeable or NINT2/NINT interrupt + if ( Chipset.cards_status != (P2W|P1W|P2C|P1C) + || (Chipset.IORam[SRQ2] & NINT2) == 0 + || (Chipset.IORam[SRQ2] & NINT ) == 0 + ) + { + Chipset.SoftInt = TRUE; // set interrupt + bInterrupt = TRUE; + } + } + Chipset.IORam[d]=c; + break; + +// 0010F = NS:CARDSTATUS +// 0010F @ [P2W P1W P2C P1C] (read-only) Port 2 writable .. Port 1 inserted + case 0x0F: break; // read-only + +// 00110 = HP:IOC +// 00110 @ Serial I/O Control [SON ETBE ERBF ERBZ] +// 00110 @ Serial On, Interrupt On Recv.Buf.Empty, Full, Buzy + case 0x10: + Chipset.IORam[d]=c; + CheckSerial(); // handle UART on/off + if ((c & SON) == 0) // SON bit cleared + { + Chipset.IORam[IOC] = 0; // clear IOC + Chipset.IORam[RCS] = 0; // clear RCS + Chipset.IORam[TCS] = 0; // clear TCS + Chipset.IORam[RBR_LSB] = 0; // clear RBR + Chipset.IORam[RBR_MSB] = 0; + Chipset.IORam[TBR_LSB] = 0; // clear TBR + Chipset.IORam[TBR_MSB] = 0; + } + if (UpdateUSRQ()) INTERRUPT; // update USRQ bit + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: IOC write: %x\n"),Chipset.pc,Chipset.IORam[d]); + OutputDebugString(buffer); + } + #endif + break; + +// 00111 = HP:RCS +// 00111 Serial Receive Control/Status [RX RER RBZ RBF] (bit 3 is read-only) + case 0x11: + if (Chipset.IORam[IOC] & SON) + { + EnterCriticalSection(&csIOLock); + { + // critical section because of RER access + Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); + } + LeaveCriticalSection(&csIOLock); + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: RCS write: %x\n"),Chipset.pc,Chipset.IORam[d]); + OutputDebugString(buffer); + } + #endif + } + break; + +// 00112 = HP:TCS +// 00112 @ Serial Transmit Control/Status [BRK LPB TBZ TBF] + case 0x12: + if (Chipset.IORam[IOC] & SON) + { + Chipset.IORam[d]=c; + CommTxBRK(); // update BRK condition + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: TCS write: %x\n"),Chipset.pc,Chipset.IORam[d]); + OutputDebugString(buffer); + } + #endif + } + break; + +// 00113 = HP:CRER +// 00113 @ Serial Clear RER (writing anything clears RER bit) + case 0x13: + IOBit(RCS,RER,FALSE); + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: CRER write: %x\n"),Chipset.pc,Chipset.IORam[d]); + OutputDebugString(buffer); + } + #endif + break; + +// 00114 = HP:RBR +// 00114 @ Serial Receive Buffer Register (Reading clears RBF bit) + case 0x14: break; // read-only + case 0x15: break; // read-only + +// 00116 = HP:TBR +// 00116 @ Serial Transmit Buffer Register (Writing sets TBF bit) + case 0x16: + case 0x17: + if (Chipset.IORam[IOC] & SON) + { + Chipset.IORam[d]=c; + tbr_acc = TRUE; // new TBR value + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: TBR %s write: %x\n"),Chipset.pc,(d==0x16) ? "LSB" : "MSB",*a); + OutputDebugString(buffer); + } + #endif + } + break; + +// 00118 = NS:SRR +// 00118 @ Service Request Register (read-only) +// 00118 @ [ISRQ TSRQ USRQ VSRQ] [KDN NINT2 NINT LSRQ] + case 0x18: break; // read-only + case 0x19: break; // read-only + +// 0011A = HP:IRC +// 0011A @ IR Control Register [IRI EIRU EIRI IRE] (bit 3 is read-only) +// 0011A @ IR Input, Enable IR UART mode, Enable IR Interrupt, IR Event + case 0x1A: + // EIRU bit changed + if (((c^Chipset.IORam[d]) & EIRU) != 0) + { + // save new value for COM open + Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); + // reopen COM port with new setting + CommOpen(szSerialWire,szSerialIr); + } + Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: IRC write: %x\n"),Chipset.pc,Chipset.IORam[d]); + OutputDebugString(buffer); + } + #endif + break; + +// 0011B = NS:BASENIBOFF +// 0011B @ Used as addressto get BASENIB from 11F to the 5th nibble + case 0x1B: break; + +// 0011C = NS:LCR +// 0011C @ Led Control Register [LED ELBE LBZ LBF] (Setting LED is draining) + case 0x1C: + // HP49G new mapping on LED bit change + if (cCurrentRomType=='X' && ((c^Chipset.IORam[d])&LED)) + { + Chipset.IORam[d]=c; // save new value for mapping + Map(Chipset.P2Base,Chipset.P2End); // new ROM mapping + #if defined DEBUG_FLASH + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: NCE3: R%cM\n"),Chipset.pc,(c&LED) ? 'O' : 'A'); + OutputDebugString(buffer); + } + #endif + } + if ((c^Chipset.IORam[d])&ELBE) // ELBE bit changed + { + // Led Service ReQuest on Led Buffer Empty enabled + BOOL bLSRQ = (c & (ELBE | LBF)) == ELBE; + + IOBit(SRQ2,LSRQ,bLSRQ); // update LSRQ bit + if (bLSRQ) // interrupt on Led Buffer Empty enabled + { + Chipset.SoftInt = TRUE; + bInterrupt = TRUE; + } + } + Chipset.IORam[d]=c; + break; + +// 0011D = NS:LBR +// 0011D @ Led Buffer Register [0 0 0 LBO] (bits 1-3 read zero) + case 0x1D: + IrPrinter((BYTE)(c&LBO)); + Chipset.IORam[d]=c&LBO; + break; + +// 0011E = NS:SCRATCHPAD +// 0011E @ Scratch pad + case 0x1E: Chipset.IORam[d]=c; break; + +// 0011F = NS:BASENIB +// 0011F @ 7 or 8 for base memory + case 0x1F: Chipset.IORam[d]=c; break; + +// 00120 = NS:DISPADDR +// 00120 @ Display Start Address (write only) +// 00120 @ bit 0 is ignored (display must start on byte boundary) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + Chipset.IORam[d]=c; + bDISPADDR = TRUE; // addr 0x120-0x124 changed + break; + +// 00125 = NS:LINEOFFS +// 00125 @ Display Line offset (write only) (no of bytes skipped after each line) +// 00125 @ MSG sign extended + case 0x25: + case 0x26: + case 0x27: + Chipset.IORam[d]=c; + bLINEOFFS = TRUE; // addr 0x125-0x127 changed + break; + +// 00128 = NS:LINECOUNT +// 00128 @ Display Line Counter and miscellaneous (28-29) +// 00128 @ [LC3 LC2 LC1 LC0] [DA19 M32 LC5 LC4] +// 00128 @ Line counter 6 bits -> max = 2^6-1 = 63 = disp height +// 00128 @ Normally has 55 -> Menu starts at display row 56 + case 0x28: + // LSB of LINECOUNT changed + if (c != (BYTE) (Chipset.lcounter & 0xf)) + { + Chipset.lcounter = (Chipset.lcounter & ~0xF) | c; + disp |= (DISP_POINTER | DISP_MAIN | DISP_MENUE); + } + break; + + case 0x29: + // MSB of LINECOUNT changed + b = (c & 0x3) << 4; // upper two bits + if (b != (Chipset.lcounter & 0x30)) + { + Chipset.lcounter = (Chipset.lcounter & ~0x30) | b; + disp |= (DISP_POINTER | DISP_MAIN | DISP_MENUE); + } + + if ((c^Chipset.IORam[d])&DA19) // DA19 changed + { + Chipset.IORam[d]^=DA19; // save new DA19 + Map(0x00,0xFF); // new ROM mapping + } + break; + + case 0x2A: break; + case 0x2B: break; + case 0x2C: break; + case 0x2D: break; + +// 0012E = NS:TIMER1CTRL +// 0012E @ TIMER1 Control [SRQ WKE INT XTRA] + case 0x2E: + Chipset.IORam[d]=c; // don't clear XTRA bit + ReadT1(); // dummy read for checking control bits + break; + +// 0012F = NS:TIMER2CTRL +// 0012F @ TIMER2 Control [SRQ WKE INT RUN] + case 0x2F: + Chipset.IORam[d]=c; + ReadT2(); // dummy read for checking control bits + if (c&1) + StartTimers(); + else + StopTimers(); + dwAnnunciator = 0x3F; // update all annunciators + break; + +// 00130 = NS:MENUADDR +// 00130 @ Display Secondary Start Address (write only) (30-34) +// 00130 @ Menu Display Address, no line offsets + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + Chipset.IORam[d]=c; + bMENUADDR = TRUE; // addr 0x130-0x134 changed + break; + + case 0x35: break; + case 0x36: break; + +// 00137 = HP:TIMER1 +// 00137 @ Decremented 16 times/s + case 0x37: + SetT1(c); // set new value + break; + +// 00138 = HP:TIMER2 +// 00138 @ hardware timer (38-3F), decremented 8192 times/s + // nothing - fall through to default + + default: + Chipset.IORam[d]=c; // write data + + if (d >= TIMER2) // timer2 update + { + Nunpack(Chipset.IORam+TIMER2,ReadT2(),8); + memcpy(Chipset.IORam+d,a,s); + SetT2(Npack(Chipset.IORam+TIMER2,8)); + goto finish; + } + } + a++; d++; + } while (--s); + +finish: + if (bDISPADDR) // 0x120-0x124 changed + { + b = Npack(Chipset.IORam+DISP1CTL,5)&0xFFFFE; + if (b != Chipset.start1) + { + Chipset.start1 = b; + disp |= (DISP_POINTER | DISP_MAIN); + } + } + if (bLINEOFFS) // addr 0x125-0x127 changed + { + signed short lo = (signed short)Npack(Chipset.IORam+LINENIBS,3); + if (lo&0x800) lo-=0x1000; + if (lo != Chipset.loffset) + { + Chipset.loffset = lo; + disp |= (DISP_POINTER | DISP_MAIN); + } + } + if (bMENUADDR) // addr 0x130-0x134 changed + { + b = Npack(Chipset.IORam+DISP2CTL,5)&0xFFFFE; + if (b != Chipset.start2) + { + Chipset.start2 = b; + disp |= (DISP_POINTER | DISP_MENUE); + } + } + + if (tbr_acc) // addr 0x116-0x117 changed + { + IOBit(TCS,TBF,TRUE); // set transmit buffer full bit + CommTransmit(); // transmit char + } + + if (disp & DISP_POINTER) + { + disp &= ~DISP_POINTER; // display pointer updated + UpdateDisplayPointers(); + } + if (dwAnnunciator) + { + UpdateAnnunciators(dwAnnunciator); + } + return; +} diff --git a/Sources/Emu48/mru.c b/Sources/Emu48/MRU.C similarity index 95% rename from Sources/Emu48/mru.c rename to Sources/Emu48/MRU.C index a04ec3f..a72e4a9 100644 --- a/Sources/Emu48/mru.c +++ b/Sources/Emu48/MRU.C @@ -1,380 +1,380 @@ -/* - * mru.c - * - * This file is part of Emu48 - * - * Copyright (C) 2007 Christoph Gießelink - * - */ -#include "pch.h" -#include "resource.h" -#include "emu48.h" - -static TCHAR szOriginal[MAX_PATH] = _T(""); - -static LPTSTR *ppszFiles = NULL; // pointer to MRU table -static UINT nEntry = 0; // no. of MRU entries - -static BOOL GetMenuPosForId(HMENU hMenu, UINT nItem, HMENU *phMruMenu, UINT *pnMruPos) -{ - HMENU hSubMenu; - UINT i,nID,nMaxID; - - nMaxID = GetMenuItemCount(hMenu); - for (i = 0; i < nMaxID; ++i) - { - nID = GetMenuItemID(hMenu,i); // get ID - - if (nID == 0) continue; // separator or invalid command - - if (nID == (UINT)-1) // possibly a popup menu - { - hSubMenu = GetSubMenu(hMenu,i); // try to get handle to popup menu - if (hSubMenu != NULL) // it's a popup menu - { - // recursive search - if (GetMenuPosForId(hSubMenu,nItem,phMruMenu,pnMruPos)) - return TRUE; - } - continue; - } - - if (nID == nItem) // found ID - { - *phMruMenu = hMenu; // remember menu and position - *pnMruPos = i; - return TRUE; - } - } - return FALSE; -} - -BOOL MruInit(UINT nNum) -{ - HMENU hMenu = GetMenu(hWnd); // main menu - if (hMenu == NULL) return FALSE; // failed, no menu bar - - _ASSERT(ppszFiles == NULL); // MRU already initialized - - // no. of files in MRU list - nEntry = ReadSettingsInt(_T("MRU"),_T("FileCount"),nNum); - - if (nEntry > 0) // allocate MRU table - { - // create MRU table - if ((ppszFiles = (LPTSTR *) malloc(nEntry * sizeof(*ppszFiles))) == NULL) - return FALSE; - - // fill each entry - for (nNum = 0; nNum < nEntry; ++nNum) - ppszFiles[nNum] = NULL; - - MruReadList(); // read actual MRU list - } - return TRUE; -} - -VOID MruCleanup(VOID) -{ - UINT i; - - MruWriteList(); // write actual MRU list - - if (ppszFiles != NULL) // table defined - { - for (i = 0; i < nEntry; ++i) // cleanup each entry - { - if (ppszFiles[i] != NULL) // valid entry - free(ppszFiles[i]); // cleanup entry - } - - free(ppszFiles); // free table - ppszFiles = NULL; - } - return; -} - -VOID MruAdd(LPCTSTR lpszEntry) -{ - TCHAR szFilename[MAX_PATH]; - LPTSTR lpFilePart; - UINT i; - - if (ppszFiles != NULL) // MRU initialized - { - _ASSERT(nEntry > 0); // must have entries - - // get full path name - GetFullPathName(lpszEntry,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart); - - // look if entry is already in table - for (i = 0; i < nEntry; ++i) - { - // already in table -> quit - if ( ppszFiles[i] != NULL // valid entry - && lstrcmpi(ppszFiles[i],szFilename) == 0) - { - MruMoveTop(i); // move to top and update menu - return; - } - } - - i = nEntry - 1; // last index - if (ppszFiles[i] != NULL) // valid entry - free(ppszFiles[i]); // free oldest entry - - for (; i > 0; --i) // move old entries 1 line down - { - ppszFiles[i] = ppszFiles[i-1]; - } - - // add new entry to top - ppszFiles[0] = DuplicateString(szFilename); - } - return; -} - -VOID MruRemove(UINT nIndex) -{ - // MRU initialized and index inside valid range - if (ppszFiles != NULL && nIndex < nEntry) - { - free(ppszFiles[nIndex]); // free entry - - for (; nIndex < nEntry - 1; ++nIndex) // move below entries 1 line up - { - ppszFiles[nIndex] = ppszFiles[nIndex+1]; - } - - ppszFiles[nIndex] = NULL; // clear last line - } - return; -} - -VOID MruMoveTop(UINT nIndex) -{ - // MRU initialized and index inside valid range - if (ppszFiles != NULL && nIndex < nEntry) - { - LPTSTR lpszEntry = ppszFiles[nIndex];// remember selected entry - - for (; nIndex > 0; --nIndex) // move above entries 1 line down - { - ppszFiles[nIndex] = ppszFiles[nIndex-1]; - } - - ppszFiles[0] = lpszEntry; // insert entry on top - } - return; -} - -UINT MruEntries(VOID) -{ - return nEntry; -} - -UINT MruID(LPCTSTR lpszEntry) -{ - TCHAR szFilename[MAX_PATH]; - LPTSTR lpFilePart; - UINT i; - - if (ppszFiles != NULL) // MRU initialized - { - _ASSERT(nEntry > 0); // must have entries - - // get full path name - GetFullPathName(lpszEntry,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart); - - // look if entry is already in table - for (i = 0; i < nEntry; ++i) - { - if ( ppszFiles[i] != NULL // valid entry - && lstrcmpi(ppszFiles[i],szFilename) == 0) - { - return i; // return ID - } - } - } - return (UINT) -1; // not found -} - -VOID MruFilename(UINT nIndex, LPTSTR szFilename, UINT nBuffersize) -{ - *szFilename = 0; // not found - - // MRU initialized and index inside valid range - if (ppszFiles != NULL && nIndex < nEntry) - { - _ASSERT(ppszFiles[nIndex] != NULL); // valid entry - lstrcpyn(szFilename,ppszFiles[nIndex],nBuffersize); - } - return; -} - -VOID MruUpdateMenu(HMENU hMenu) -{ - TCHAR szCurPath[MAX_PATH]; - BOOL bEmpty; - UINT i; - - if (hMenu != NULL) // have menu - { - HMENU hMruMenu; // menu handle for MRU list - UINT nMruPos; // insert position for MRU list - - _ASSERT(IsMenu(hMenu)); // validate menu handle - - // search for menu position of ID_FILE_MRU_FILE1 - if (GetMenuPosForId(hMenu,ID_FILE_MRU_FILE1,&hMruMenu,&nMruPos)) - { - if (*szOriginal == 0) // get orginal value of first MRU entry - { - VERIFY(GetMenuString(hMruMenu,nMruPos,szOriginal,ARRAYSIZEOF(szOriginal),MF_BYPOSITION)); - } - - if (nEntry == 0) // kill MRU menu entry - { - // delete MRU menu - DeleteMenu(hMruMenu,nMruPos,MF_BYPOSITION); - - // delete the following separator - _ASSERT((GetMenuState(hMruMenu,nMruPos,MF_BYPOSITION) & MF_SEPARATOR) != 0); - DeleteMenu(hMruMenu,nMruPos,MF_BYPOSITION); - } - - if (ppszFiles != NULL) // MRU initialized - { - _ASSERT(nEntry > 0); // must have entries - - // delete all menu entries - for (i = 0; DeleteMenu(hMenu,ID_FILE_MRU_FILE1+i,MF_BYCOMMAND) != FALSE; ++i) { } - - // check if MRU list is empty - for (bEmpty = TRUE, i = 0; bEmpty && i < nEntry; ++i) - { - bEmpty = (ppszFiles[i] == NULL); - } - - if (bEmpty) // MRU list is empty - { - // fill with orginal string - VERIFY(InsertMenu(hMruMenu,nMruPos,MF_STRING|MF_BYPOSITION|MF_GRAYED,ID_FILE_MRU_FILE1,szOriginal)); - return; - } - - // current directory - GetCurrentDirectory(ARRAYSIZEOF(szCurPath),szCurPath); - - for (i = 0; i < nEntry; ++i) // add menu entries - { - if (ppszFiles[i] != NULL) // valid entry - { - TCHAR szMenuname[2*MAX_PATH+3]; - TCHAR szFilename[MAX_PATH]; - LPTSTR lpFilePart,lpszPtr; - - // check if file path and current path is identical - if (GetFullPathName(ppszFiles[i],ARRAYSIZEOF(szFilename),szFilename,&lpFilePart)) - { - TCHAR szCutname[MAX_PATH]; - - *(lpFilePart-1) = 0; // devide path and name - - // name is current directory -> use only name - if (lstrcmpi(szCurPath,szFilename) == 0) - { - // short name view - } - else - { - // full name view - lpFilePart = ppszFiles[i]; - } - - // cut filename to fit into menu - GetCutPathName(lpFilePart,szCutname,ARRAYSIZEOF(szCutname),36); - lpFilePart = szCutname; - - // adding accelerator key - lpszPtr = szMenuname; - *lpszPtr++ = _T('&'); - *lpszPtr++ = _T('0') + ((i + 1) % 10); - *lpszPtr++ = _T(' '); - - // copy file to view buffer and expand & to && - while (*lpFilePart != 0) - { - if (*lpFilePart == _T('&')) - { - *lpszPtr++ = *lpFilePart; - } - *lpszPtr++ = *lpFilePart++; - } - *lpszPtr = 0; - - VERIFY(InsertMenu(hMruMenu,nMruPos+i, - MF_STRING|MF_BYPOSITION,ID_FILE_MRU_FILE1+i, - szMenuname)); - } - } - } - } - } - } - return; -} - -VOID MruWriteList(VOID) -{ - TCHAR szItemname[32]; - UINT i; - - if (nEntry > 0) - { - // no. of files in MRU list - WriteSettingsInt(_T("MRU"),_T("FileCount"),nEntry); - - for (i = 0; i < nEntry; ++i) // add menu entries - { - _ASSERT(ppszFiles != NULL); // MRU not initialized - wsprintf(szItemname,_T("File%d"),i+1); - if (ppszFiles[i] != NULL) // valid entry - { - WriteSettingsString(_T("MRU"),szItemname,ppszFiles[i]); - } - else - { - DelSettingsKey(_T("MRU"),szItemname); - } - } - } - return; -} - -VOID MruReadList(VOID) -{ - TCHAR szFilename[MAX_PATH]; - TCHAR szItemname[32]; - UINT i; - - for (i = 0; i < nEntry; ++i) // add menu entries - { - _ASSERT(ppszFiles != NULL); // MRU not initialized - - wsprintf(szItemname,_T("File%d"),i+1); - ReadSettingsString(_T("MRU"),szItemname,_T(""),szFilename,ARRAYSIZEOF(szFilename)); - - if (ppszFiles[i] != NULL) // valid entry - { - free(ppszFiles[i]); // free entry - ppszFiles[i] = NULL; // clear last line - } - - if (*szFilename) // read a valid entry - { - ppszFiles[i] = DuplicateString(szFilename); - } - } - return; -} +/* + * mru.c + * + * This file is part of Emu48 + * + * Copyright (C) 2007 Christoph Gießelink + * + */ +#include "pch.h" +#include "resource.h" +#include "Emu48.h" + +static TCHAR szOriginal[MAX_PATH] = _T(""); + +static LPTSTR *ppszFiles = NULL; // pointer to MRU table +static UINT nEntry = 0; // no. of MRU entries + +static BOOL GetMenuPosForId(HMENU hMenu, UINT nItem, HMENU *phMruMenu, UINT *pnMruPos) +{ + HMENU hSubMenu; + UINT i,nID,nMaxID; + + nMaxID = GetMenuItemCount(hMenu); + for (i = 0; i < nMaxID; ++i) + { + nID = GetMenuItemID(hMenu,i); // get ID + + if (nID == 0) continue; // separator or invalid command + + if (nID == (UINT)-1) // possibly a popup menu + { + hSubMenu = GetSubMenu(hMenu,i); // try to get handle to popup menu + if (hSubMenu != NULL) // it's a popup menu + { + // recursive search + if (GetMenuPosForId(hSubMenu,nItem,phMruMenu,pnMruPos)) + return TRUE; + } + continue; + } + + if (nID == nItem) // found ID + { + *phMruMenu = hMenu; // remember menu and position + *pnMruPos = i; + return TRUE; + } + } + return FALSE; +} + +BOOL MruInit(UINT nNum) +{ + HMENU hMenu = GetMenu(hWnd); // main menu + if (hMenu == NULL) return FALSE; // failed, no menu bar + + _ASSERT(ppszFiles == NULL); // MRU already initialized + + // no. of files in MRU list + nEntry = ReadSettingsInt(_T("MRU"),_T("FileCount"),nNum); + + if (nEntry > 0) // allocate MRU table + { + // create MRU table + if ((ppszFiles = (LPTSTR *) malloc(nEntry * sizeof(*ppszFiles))) == NULL) + return FALSE; + + // fill each entry + for (nNum = 0; nNum < nEntry; ++nNum) + ppszFiles[nNum] = NULL; + + MruReadList(); // read actual MRU list + } + return TRUE; +} + +VOID MruCleanup(VOID) +{ + UINT i; + + MruWriteList(); // write actual MRU list + + if (ppszFiles != NULL) // table defined + { + for (i = 0; i < nEntry; ++i) // cleanup each entry + { + if (ppszFiles[i] != NULL) // valid entry + free(ppszFiles[i]); // cleanup entry + } + + free(ppszFiles); // free table + ppszFiles = NULL; + } + return; +} + +VOID MruAdd(LPCTSTR lpszEntry) +{ + TCHAR szFilename[MAX_PATH]; + LPTSTR lpFilePart; + UINT i; + + if (ppszFiles != NULL) // MRU initialized + { + _ASSERT(nEntry > 0); // must have entries + + // get full path name + GetFullPathName(lpszEntry,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart); + + // look if entry is already in table + for (i = 0; i < nEntry; ++i) + { + // already in table -> quit + if ( ppszFiles[i] != NULL // valid entry + && lstrcmpi(ppszFiles[i],szFilename) == 0) + { + MruMoveTop(i); // move to top and update menu + return; + } + } + + i = nEntry - 1; // last index + if (ppszFiles[i] != NULL) // valid entry + free(ppszFiles[i]); // free oldest entry + + for (; i > 0; --i) // move old entries 1 line down + { + ppszFiles[i] = ppszFiles[i-1]; + } + + // add new entry to top + ppszFiles[0] = DuplicateString(szFilename); + } + return; +} + +VOID MruRemove(UINT nIndex) +{ + // MRU initialized and index inside valid range + if (ppszFiles != NULL && nIndex < nEntry) + { + free(ppszFiles[nIndex]); // free entry + + for (; nIndex < nEntry - 1; ++nIndex) // move below entries 1 line up + { + ppszFiles[nIndex] = ppszFiles[nIndex+1]; + } + + ppszFiles[nIndex] = NULL; // clear last line + } + return; +} + +VOID MruMoveTop(UINT nIndex) +{ + // MRU initialized and index inside valid range + if (ppszFiles != NULL && nIndex < nEntry) + { + LPTSTR lpszEntry = ppszFiles[nIndex];// remember selected entry + + for (; nIndex > 0; --nIndex) // move above entries 1 line down + { + ppszFiles[nIndex] = ppszFiles[nIndex-1]; + } + + ppszFiles[0] = lpszEntry; // insert entry on top + } + return; +} + +UINT MruEntries(VOID) +{ + return nEntry; +} + +UINT MruID(LPCTSTR lpszEntry) +{ + TCHAR szFilename[MAX_PATH]; + LPTSTR lpFilePart; + UINT i; + + if (ppszFiles != NULL) // MRU initialized + { + _ASSERT(nEntry > 0); // must have entries + + // get full path name + GetFullPathName(lpszEntry,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart); + + // look if entry is already in table + for (i = 0; i < nEntry; ++i) + { + if ( ppszFiles[i] != NULL // valid entry + && lstrcmpi(ppszFiles[i],szFilename) == 0) + { + return i; // return ID + } + } + } + return (UINT) -1; // not found +} + +VOID MruFilename(UINT nIndex, LPTSTR szFilename, UINT nBuffersize) +{ + *szFilename = 0; // not found + + // MRU initialized and index inside valid range + if (ppszFiles != NULL && nIndex < nEntry) + { + _ASSERT(ppszFiles[nIndex] != NULL); // valid entry + lstrcpyn(szFilename,ppszFiles[nIndex],nBuffersize); + } + return; +} + +VOID MruUpdateMenu(HMENU hMenu) +{ + TCHAR szCurPath[MAX_PATH]; + BOOL bEmpty; + UINT i; + + if (hMenu != NULL) // have menu + { + HMENU hMruMenu; // menu handle for MRU list + UINT nMruPos; // insert position for MRU list + + _ASSERT(IsMenu(hMenu)); // validate menu handle + + // search for menu position of ID_FILE_MRU_FILE1 + if (GetMenuPosForId(hMenu,ID_FILE_MRU_FILE1,&hMruMenu,&nMruPos)) + { + if (*szOriginal == 0) // get orginal value of first MRU entry + { + VERIFY(GetMenuString(hMruMenu,nMruPos,szOriginal,ARRAYSIZEOF(szOriginal),MF_BYPOSITION)); + } + + if (nEntry == 0) // kill MRU menu entry + { + // delete MRU menu + DeleteMenu(hMruMenu,nMruPos,MF_BYPOSITION); + + // delete the following separator + _ASSERT((GetMenuState(hMruMenu,nMruPos,MF_BYPOSITION) & MF_SEPARATOR) != 0); + DeleteMenu(hMruMenu,nMruPos,MF_BYPOSITION); + } + + if (ppszFiles != NULL) // MRU initialized + { + _ASSERT(nEntry > 0); // must have entries + + // delete all menu entries + for (i = 0; DeleteMenu(hMenu,ID_FILE_MRU_FILE1+i,MF_BYCOMMAND) != FALSE; ++i) { } + + // check if MRU list is empty + for (bEmpty = TRUE, i = 0; bEmpty && i < nEntry; ++i) + { + bEmpty = (ppszFiles[i] == NULL); + } + + if (bEmpty) // MRU list is empty + { + // fill with orginal string + VERIFY(InsertMenu(hMruMenu,nMruPos,MF_STRING|MF_BYPOSITION|MF_GRAYED,ID_FILE_MRU_FILE1,szOriginal)); + return; + } + + // current directory + GetCurrentDirectory(ARRAYSIZEOF(szCurPath),szCurPath); + + for (i = 0; i < nEntry; ++i) // add menu entries + { + if (ppszFiles[i] != NULL) // valid entry + { + TCHAR szMenuname[2*MAX_PATH+3]; + TCHAR szFilename[MAX_PATH]; + LPTSTR lpFilePart,lpszPtr; + + // check if file path and current path is identical + if (GetFullPathName(ppszFiles[i],ARRAYSIZEOF(szFilename),szFilename,&lpFilePart)) + { + TCHAR szCutname[MAX_PATH]; + + *(lpFilePart-1) = 0; // devide path and name + + // name is current directory -> use only name + if (lstrcmpi(szCurPath,szFilename) == 0) + { + // short name view + } + else + { + // full name view + lpFilePart = ppszFiles[i]; + } + + // cut filename to fit into menu + GetCutPathName(lpFilePart,szCutname,ARRAYSIZEOF(szCutname),36); + lpFilePart = szCutname; + + // adding accelerator key + lpszPtr = szMenuname; + *lpszPtr++ = _T('&'); + *lpszPtr++ = _T('0') + ((i + 1) % 10); + *lpszPtr++ = _T(' '); + + // copy file to view buffer and expand & to && + while (*lpFilePart != 0) + { + if (*lpFilePart == _T('&')) + { + *lpszPtr++ = *lpFilePart; + } + *lpszPtr++ = *lpFilePart++; + } + *lpszPtr = 0; + + VERIFY(InsertMenu(hMruMenu,nMruPos+i, + MF_STRING|MF_BYPOSITION,ID_FILE_MRU_FILE1+i, + szMenuname)); + } + } + } + } + } + } + return; +} + +VOID MruWriteList(VOID) +{ + TCHAR szItemname[32]; + UINT i; + + if (nEntry > 0) + { + // no. of files in MRU list + WriteSettingsInt(_T("MRU"),_T("FileCount"),nEntry); + + for (i = 0; i < nEntry; ++i) // add menu entries + { + _ASSERT(ppszFiles != NULL); // MRU not initialized + wsprintf(szItemname,_T("File%d"),i+1); + if (ppszFiles[i] != NULL) // valid entry + { + WriteSettingsString(_T("MRU"),szItemname,ppszFiles[i]); + } + else + { + DelSettingsKey(_T("MRU"),szItemname); + } + } + } + return; +} + +VOID MruReadList(VOID) +{ + TCHAR szFilename[MAX_PATH]; + TCHAR szItemname[32]; + UINT i; + + for (i = 0; i < nEntry; ++i) // add menu entries + { + _ASSERT(ppszFiles != NULL); // MRU not initialized + + wsprintf(szItemname,_T("File%d"),i+1); + ReadSettingsString(_T("MRU"),szItemname,_T(""),szFilename,ARRAYSIZEOF(szFilename)); + + if (ppszFiles[i] != NULL) // valid entry + { + free(ppszFiles[i]); // free entry + ppszFiles[i] = NULL; // clear last line + } + + if (*szFilename) // read a valid entry + { + ppszFiles[i] = DuplicateString(szFilename); + } + } + return; +} diff --git a/Sources/Emu48/opcodes.c b/Sources/Emu48/OPCODES.C similarity index 94% rename from Sources/Emu48/opcodes.c rename to Sources/Emu48/OPCODES.C index 53e19d9..8a10973 100644 --- a/Sources/Emu48/opcodes.c +++ b/Sources/Emu48/OPCODES.C @@ -1,2439 +1,2439 @@ -/* - * opcodes.c - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * Copyright (C) 1999 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" -#include "opcodes.h" -#include "io.h" // I/O register definitions - -#define w Chipset -#define GOYES3 {if(w.carry) o_goyes3(I);else{w.pc+=2;return;}} -#define GOYES5 {if(w.carry) o_goyes5(I);else{w.pc+=2;return;}} - -#if !defined _BIGENDIAN -#define REG(t,r) (*((t*)&(r))) // little endian machine -#else -#define REG(t,r) (*((t*)((BYTE*)&(r)+sizeof(r)-sizeof(t)))) // big endian machine -#endif - -#pragma intrinsic(memset,memcpy) - -#include "ops.h" - -// Fields start and length -UINT F_s[16] = {0/*P*/,0,2,0,15,3,0,0,0,0,0,0,0,0,0,0}; -UINT F_l[16] = {1,1/*P+1*/,1,3,1,12,2,16,0,0,0,0,0,0,0,5}; - -VOID o00(LPBYTE I) // RTNSXM -{ - w.cycles+=9; - w.pc = rstkpop(); - w.HST |= XM; - return; -} - -VOID o01(LPBYTE I) // RTN -{ - w.cycles+=9; - w.pc = rstkpop(); - return; -} - -VOID o02(LPBYTE I) // RTNSC -{ - w.cycles+=9; - w.pc = rstkpop(); - w.carry = TRUE; - return; -} - -VOID o03(LPBYTE I) // RTNCC -{ - w.cycles+=9; - w.pc = rstkpop(); - w.carry = FALSE; - return; -} - -VOID o04(LPBYTE I) // SETHEX -{ - w.cycles+=3; - w.pc+=2; - w.mode_dec = FALSE; - return; -} - -VOID o05(LPBYTE I) // SETDEC -{ - w.cycles+=3; - w.pc+=2; - w.mode_dec = TRUE; - return; -} - -VOID o06(LPBYTE I) // RSTK=C -{ - w.cycles+=8; - w.pc+=2; - rstkpush(Npack(w.C,5)); - return; -} - -VOID o07(LPBYTE I) // C=RSTK -{ - w.cycles+=8; - w.pc+=2; - Nunpack(w.C,rstkpop(),5); - return; -} - -VOID o08(LPBYTE I) // CLRST -{ - w.cycles+=5; - w.pc+=2; - memset(w.ST, 0, 3); - return; -} - -VOID o09(LPBYTE I) // C=ST -{ - w.cycles+=5; - w.pc+=2; - memcpy(w.C, w.ST, 3); - return; -} - -VOID o0A(LPBYTE I) // ST=C -{ - w.cycles+=5; - w.pc+=2; - memcpy(w.ST, w.C, 3); - return; -} - -VOID o0B(LPBYTE I) // CSTEX -{ - w.cycles+=5; - w.pc+=2; - Nxchg(w.C, w.ST, 3); - return; -} - -VOID o0C(LPBYTE I) // P=P+1 -{ - w.cycles+=3; - w.pc+=2; - if (w.P<15) - { - w.P++; - w.carry=FALSE; - } - else - { - w.P=0; - w.carry=TRUE; - } - PCHANGED; - return; -} - -VOID o0D(LPBYTE I) // P=P-1 -{ - w.cycles+=3; - w.pc+=2; - if (w.P) - { - w.P--; - w.carry=FALSE; - } - else - { - w.P=0xF; - w.carry=TRUE; - } - PCHANGED; - return; -} - -VOID o0Ef0(LPBYTE I) // A=A&B f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFand(w.A,w.B,I[2]); - return; -} -VOID o0Ef1(LPBYTE I) // B=B&C f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFand(w.B,w.C,I[2]); - return; -} -VOID o0Ef2(LPBYTE I) // C=C&A f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFand(w.C,w.A,I[2]); - return; -} -VOID o0Ef3(LPBYTE I) // D=D&C f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFand(w.D,w.C,I[2]); - return; -} -VOID o0Ef4(LPBYTE I) // B=B&A f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFand(w.B,w.A,I[2]); - return; -} -VOID o0Ef5(LPBYTE I) // C=C&B f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFand(w.C,w.B,I[2]); - return; -} -VOID o0Ef6(LPBYTE I) // A=A&C f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFand(w.A,w.C,I[2]); - return; -} -VOID o0Ef7(LPBYTE I) // C=C&D f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFand(w.C,w.D,I[2]); - return; -} - -VOID o0Ef8(LPBYTE I) // A=A!B f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFor(w.A,w.B,I[2]); - return; -} -VOID o0Ef9(LPBYTE I) // B=B!C f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFor(w.B,w.C,I[2]); - return; -} -VOID o0EfA(LPBYTE I) // C=C!A f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFor(w.C,w.A,I[2]); - return; -} -VOID o0EfB(LPBYTE I) // D=D!C f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFor(w.D,w.C,I[2]); - return; -} -VOID o0EfC(LPBYTE I) // B=B!A f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFor(w.B,w.A,I[2]); - return; -} -VOID o0EfD(LPBYTE I) // C=C!B f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFor(w.C,w.B,I[2]); - return; -} -VOID o0EfE(LPBYTE I) // A=A!C f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFor(w.A,w.C,I[2]); - return; -} -VOID o0EfF(LPBYTE I) // C=C!D f -{ - w.cycles+=4+F_l[I[2]]; - w.pc+=4; - NFor(w.C,w.D,I[2]); - return; -} - -VOID o0F(LPBYTE I) // RTI -{ - w.cycles+=9; - w.pc = rstkpop(); - w.inte = TRUE; // enable interrupt - - if ((w.intd && w.intk) || w.IR15X) // keyboard interrupt pending - { - w.intd = FALSE; // no keyboard interrupt pending any more - INTERRUPT; // restart interrupt handler - } - - // low interrupt lines - { - BOOL bNINT2 = Chipset.IORam[SRQ1] == 0 && (Chipset.IORam[SRQ2] & LSRQ) == 0; - BOOL bNINT = (Chipset.IORam[SRQ2] & NINT) != 0; - - // card detection off and timer running - if ((Chipset.IORam[CARDCTL] & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0) - { - // state of CDT2 - bNINT2 = bNINT2 && (Chipset.cards_status & (P2W|P2C)) != P2C; - // state of CDT1 - bNINT = bNINT && (Chipset.cards_status & (P1W|P1C)) != P1C; - } - - if (!bNINT2 || !bNINT) // NINT2 or NINT interrupt line low - INTERRUPT; // restart interrupt handler - } - - // restart interrupt handler when timer interrupt - if (w.IORam[TIMER1_CTRL]&INTR) // INT bit of timer1 is set - ReadT1(); // check for int - - if (w.IORam[TIMER2_CTRL]&INTR) // INT bit of timer2 is set - ReadT2(); // check for int - return; -} - -VOID o100(LPBYTE I) // R0=A W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.R0, w.A, 16); - return; -} - -VOID o101(LPBYTE I) // R1=A W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.R1, w.A, 16); - return; -} - -VOID o102(LPBYTE I) // R2=A W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.R2, w.A, 16); - return; -} - -VOID o103(LPBYTE I) // R3=A W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.R3, w.A, 16); - return; -} - -VOID o104(LPBYTE I) // R4=A W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.R4, w.A, 16); - return; -} - -VOID o108(LPBYTE I) // R0=C W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.R0, w.C, 16); - return; -} - -VOID o109(LPBYTE I) // R1=C W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.R1, w.C, 16); - return; -} - -VOID o10A(LPBYTE I) // R2=C W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.R2, w.C, 16); - return; -} - -VOID o10B(LPBYTE I) // R3=C W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.R3, w.C, 16); - return; -} - -VOID o10C(LPBYTE I) // R4=C W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.R4, w.C, 16); - return; -} - -VOID o110(LPBYTE I) // A=R0 W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.A, w.R0, 16); - return; -} - -VOID o111(LPBYTE I) // A=R1 W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.A, w.R1, 16); - return; -} - -VOID o112(LPBYTE I) // A=R2 W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.A, w.R2, 16); - return; -} - -VOID o113(LPBYTE I) // A=R3 W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.A, w.R3, 16); - return; -} - -VOID o114(LPBYTE I) // A=R4 W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.A, w.R4, 16); - return; -} - -VOID o118(LPBYTE I) // C=R0 W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.C, w.R0, 16); - return; -} - -VOID o119(LPBYTE I) // C=R1 W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.C, w.R1, 16); - return; -} - -VOID o11A(LPBYTE I) // C=R2 W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.C, w.R2, 16); - return; -} - -VOID o11B(LPBYTE I) // C=R3 W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.C, w.R3, 16); - return; -} - -VOID o11C(LPBYTE I) // C=R4 W -{ - w.cycles+=19; - w.pc+=3; - memcpy(w.C, w.R4, 16); - return; -} - -VOID o120(LPBYTE I) // AR0EX W -{ - w.cycles+=19; - w.pc+=3; - Nxchg(w.A, w.R0, 16); - return; -} - -VOID o121(LPBYTE I) // AR1EX W -{ - w.cycles+=19; - w.pc+=3; - Nxchg(w.A, w.R1, 16); - return; -} - -VOID o122(LPBYTE I) // AR2EX W -{ - w.cycles+=19; - w.pc+=3; - Nxchg(w.A, w.R2, 16); - return; -} - -VOID o123(LPBYTE I) // AR3EX W -{ - w.cycles+=19; - w.pc+=3; - Nxchg(w.A, w.R3, 16); - return; -} - -VOID o124(LPBYTE I) // AR4EX W -{ - w.cycles+=19; - w.pc+=3; - Nxchg(w.A, w.R4, 16); - return; -} - -VOID o128(LPBYTE I) // CR0EX W -{ - w.cycles+=19; - w.pc+=3; - Nxchg(w.C, w.R0, 16); - return; -} - -VOID o129(LPBYTE I) // CR1EX W -{ - w.cycles+=19; - w.pc+=3; - Nxchg(w.C, w.R1, 16); - return; -} - -VOID o12A(LPBYTE I) // CR2EX W -{ - w.cycles+=19; - w.pc+=3; - Nxchg(w.C, w.R2, 16); - return; -} - -VOID o12B(LPBYTE I) // CR3EX W -{ - w.cycles+=19; - w.pc+=3; - Nxchg(w.C, w.R3, 16); - return; -} - -VOID o12C(LPBYTE I) // CR4EX W -{ - w.cycles+=19; - w.pc+=3; - Nxchg(w.C, w.R4, 16); - return; -} - -VOID o130(LPBYTE I) // D0=A -{ - w.cycles+=8; - w.pc+=3; - w.d0=Npack(w.A,5); - return; -} - -VOID o131(LPBYTE I) // D1=A -{ - w.cycles+=8; - w.pc+=3; - w.d1=Npack(w.A,5); - return; -} - -VOID o132(LPBYTE I) // AD0EX -{ - DWORD d = w.d0; - w.d0=Npack(w.A,5); - Nunpack(w.A,d,5); - w.cycles+=8; - w.pc+=3; - return; -} - -VOID o133(LPBYTE I) // AD1EX -{ - DWORD d=w.d1; - w.d1=Npack(w.A,5); - Nunpack(w.A,d,5); - w.cycles+=8; - w.pc+=3; - return; -} - -VOID o134(LPBYTE I) // D0=C -{ - w.cycles+=8; - w.pc+=3; - w.d0=Npack(w.C,5); - return; -} - -VOID o135(LPBYTE I) // D1=C -{ - w.cycles+=8; - w.pc+=3; - w.d1=Npack(w.C,5); - return; -} - -VOID o136(LPBYTE I) // CD0EX -{ - DWORD d=w.d0; - w.d0=Npack(w.C,5); - Nunpack(w.C,d,5); - w.cycles+=8; - w.pc+=3; - return; -} - -VOID o137(LPBYTE I) // CD1EX -{ - DWORD d=w.d1; - w.d1=Npack(w.C,5); - Nunpack(w.C,d,5); - w.cycles+=8; - w.pc+=3; - return; -} - -VOID o138(LPBYTE I) // D0=AS -{ - w.cycles+=7; - w.pc+=3; - REG(WORD,w.d0)=(WORD)Npack(w.A,4); - return; -} - -VOID o139(LPBYTE I) // D1=AS -{ - w.cycles+=7; - w.pc+=3; - REG(WORD,w.d1)=(WORD)Npack(w.A,4); - return; -} - -VOID o13A(LPBYTE I) // AD0XS -{ - DWORD d=w.d0; - REG(WORD,w.d0)=(WORD)Npack(w.A,4); - Nunpack(w.A,d,4); - w.cycles+=7; - w.pc+=3; - return; -} - -VOID o13B(LPBYTE I) // AD1XS -{ - DWORD d=w.d1; - REG(WORD,w.d1)=(WORD)Npack(w.A,4); - Nunpack(w.A,d,4); - w.cycles+=7; - w.pc+=3; - return; -} - -VOID o13C(LPBYTE I) // D0=CS -{ - w.cycles+=7; - w.pc+=3; - REG(WORD,w.d0)=(WORD)Npack(w.C,4); - return; -} - -VOID o13D(LPBYTE I) // D1=CS -{ - w.cycles+=7; - w.pc+=3; - REG(WORD,w.d1)=(WORD)Npack(w.C,4); - return; -} - -VOID o13E(LPBYTE I) // CD0XS -{ - DWORD d=w.d0; - REG(WORD,w.d0)=(WORD)Npack(w.C,4); - Nunpack(w.C,d,4); - w.cycles+=7; - w.pc+=3; - return; -} - -VOID o13F(LPBYTE I) // CD1XS -{ - DWORD d=w.d1; - REG(WORD,w.d1)=(WORD)Npack(w.C,4); - Nunpack(w.C,d,4); - w.cycles+=7; - w.pc+=3; - return; -} - -VOID o140(LPBYTE I) { w.cycles+=17; w.pc+=3; Nwrite(w.A, w.d0, 5); return; } // DAT0=A A -VOID o141(LPBYTE I) { w.cycles+=17; w.pc+=3; Nwrite(w.A, w.d1, 5); return; } // DAT1=A A -VOID o144(LPBYTE I) { w.cycles+=17; w.pc+=3; Nwrite(w.C, w.d0, 5); return; } // DAT0=C A -VOID o145(LPBYTE I) { w.cycles+=17; w.pc+=3; Nwrite(w.C, w.d1, 5); return; } // DAT1=C A -VOID o148(LPBYTE I) { w.cycles+=14; w.pc+=3; Nwrite(w.A, w.d0, 2); return; } // DAT0=A B -VOID o149(LPBYTE I) { w.cycles+=14; w.pc+=3; Nwrite(w.A, w.d1, 2); return; } // DAT1=A B -VOID o14C(LPBYTE I) { w.cycles+=14; w.pc+=3; Nwrite(w.C, w.d0, 2); return; } // DAT0=C B -VOID o14D(LPBYTE I) { w.cycles+=14; w.pc+=3; Nwrite(w.C, w.d1, 2); return; } // DAT1=C B - -VOID o142(LPBYTE I) { w.cycles+=18; w.pc+=3; Nread(w.A, w.d0, 5); return; } // A=DAT0 A -VOID o143(LPBYTE I) { w.cycles+=18; w.pc+=3; Nread(w.A, w.d1, 5); return; } // A=DAT1 A -VOID o146(LPBYTE I) { w.cycles+=18; w.pc+=3; Nread(w.C, w.d0, 5); return; } // C=DAT0 A -VOID o147(LPBYTE I) { w.cycles+=18; w.pc+=3; Nread(w.C, w.d1, 5); return; } // C=DAT1 A -VOID o14A(LPBYTE I) { w.cycles+=15; w.pc+=3; Nread(w.A, w.d0, 2); return; } // A=DAT0 B -VOID o14B(LPBYTE I) { w.cycles+=15; w.pc+=3; Nread(w.A, w.d1, 2); return; } // A=DAT1 B -VOID o14E(LPBYTE I) { w.cycles+=15; w.pc+=3; Nread(w.C, w.d0, 2); return; } // C=DAT0 B -VOID o14F(LPBYTE I) { w.cycles+=15; w.pc+=3; Nread(w.C, w.d1, 2); return; } // C=DAT0 B - -VOID o150a(LPBYTE I) { w.cycles+=16+F_l[I[3]]; w.pc+=4; NFwrite(w.A, w.d0, I[3]); return; } // DAT0=A a -VOID o151a(LPBYTE I) { w.cycles+=16+F_l[I[3]]; w.pc+=4; NFwrite(w.A, w.d1, I[3]); return; } // DAT1=A a -VOID o154a(LPBYTE I) { w.cycles+=16+F_l[I[3]]; w.pc+=4; NFwrite(w.C, w.d0, I[3]); return; } // DAT0=C a -VOID o155a(LPBYTE I) { w.cycles+=16+F_l[I[3]]; w.pc+=4; NFwrite(w.C, w.d1, I[3]); return; } // DAT1=C a -VOID o152a(LPBYTE I) { w.cycles+=17+F_l[I[3]]; w.pc+=4; NFread(w.A, w.d0, I[3]); return; } // A=DAT0 a -VOID o153a(LPBYTE I) { w.cycles+=17+F_l[I[3]]; w.pc+=4; NFread(w.A, w.d1, I[3]); return; } // A=DAT1 a -VOID o156a(LPBYTE I) { w.cycles+=17+F_l[I[3]]; w.pc+=4; NFread(w.C, w.d0, I[3]); return; } // C=DAT0 a -VOID o157a(LPBYTE I) { w.cycles+=17+F_l[I[3]]; w.pc+=4; NFread(w.C, w.d1, I[3]); return; } // C=DAT1 a - -VOID o158x(LPBYTE I) { w.cycles+=16+I[3]+1; w.pc+=4; Nwrite(w.A, w.d0, I[3]+1); return; } // DAT0=A x -VOID o159x(LPBYTE I) { w.cycles+=16+I[3]+1; w.pc+=4; Nwrite(w.A, w.d1, I[3]+1); return; } // DAT1=A x -VOID o15Cx(LPBYTE I) { w.cycles+=16+I[3]+1; w.pc+=4; Nwrite(w.C, w.d0, I[3]+1); return; } // DAT0=C x -VOID o15Dx(LPBYTE I) { w.cycles+=16+I[3]+1; w.pc+=4; Nwrite(w.C, w.d1, I[3]+1); return; } // DAT1=C x -VOID o15Ax(LPBYTE I) { w.cycles+=17+I[3]+1; w.pc+=4; Nread(w.A, w.d0, I[3]+1); return; } // A=DAT0 x -VOID o15Bx(LPBYTE I) { w.cycles+=17+I[3]+1; w.pc+=4; Nread(w.A, w.d1, I[3]+1); return; } // A=DAT1 x -VOID o15Ex(LPBYTE I) { w.cycles+=17+I[3]+1; w.pc+=4; Nread(w.C, w.d0, I[3]+1); return; } // C=DAT0 x -VOID o15Fx(LPBYTE I) { w.cycles+=17+I[3]+1; w.pc+=4; Nread(w.C, w.d1, I[3]+1); return; } // C=DAT1 x - -VOID o16x(LPBYTE I) // D0=D0+ (n+1) -{ - w.cycles+=7; - w.pc+=3; - w.d0+=I[2]+1; - if (w.d0>0xfffff) - { - w.d0&=0xfffff; - w.carry=TRUE; - } - else - { - w.carry=FALSE; - } - return; -} - -VOID o17x(LPBYTE I) // D1=D1+ (n+1) -{ - w.cycles+=7; - w.pc+=3; - w.d1+=I[2]+1; - if (w.d1>0xfffff) - { - w.d1&=0xfffff; - w.carry=TRUE; - } - else - { - w.carry=FALSE; - } - return; -} - -VOID o18x(LPBYTE I) // D0=D0- (n+1) -{ - w.cycles+=7; - w.pc+=3; - w.d0-=I[2]+1; - if (w.d0>0xfffff) - { - w.d0&=0xfffff; - w.carry=TRUE; - } - else - { - w.carry=FALSE; - } - return; -} - -VOID o19d2(LPBYTE I) // D0=(2) #dd -{ - w.cycles+=4; - w.pc+=4; - REG(BYTE,w.d0)=(BYTE)Npack(I+2,2); - return; -} - -VOID o1Ad4(LPBYTE I) // D0=(4) #dddd -{ - w.cycles+=6; - w.pc+=6; - REG(WORD,w.d0)=(WORD)Npack(I+2,4); - return; -} - -VOID o1Bd5(LPBYTE I) // D0=(5) #ddddd -{ - w.cycles+=7; - w.pc+=7; - w.d0=Npack(I+2,5); - return; -} - -VOID o1Cx(LPBYTE I) // D1=D1- (n+1) -{ - w.cycles+=7; - w.pc+=3; - w.d1-=I[2]+1; - if (w.d1>0xfffff) - { - w.d1&=0xfffff; - w.carry=TRUE; - } - else - { - w.carry=FALSE; - } - return; -} - -VOID o1Dd2(LPBYTE I) // D1=(2) #dd -{ - w.cycles+=4; - w.pc+=4; - REG(BYTE,w.d1)=(BYTE)Npack(I+2,2); - return; -} - -VOID o1Ed4(LPBYTE I) // D1=(4) #dddd -{ - w.cycles+=6; - w.pc+=6; - REG(WORD,w.d1)=(WORD)Npack(I+2,4); - return; -} - -VOID o1Fd5(LPBYTE I) // D1=(5) #ddddd -{ - w.cycles+=7; - w.pc+=7; - w.d1=Npack(I+2,5); - return; -} - -VOID o2n(LPBYTE I) // P= n -{ - w.cycles+=2; - w.pc+=2; - w.P=I[1]; - PCHANGED; - return; -} - -VOID o3X(LPBYTE I) // LCHEX -{ - UINT n=I[1]+1; - UINT d=16-w.P; - w.cycles+=3+I[1]; - w.pc+=2; - I+=2; // UNSAFE - if (n<=d) - { - memcpy(w.C+w.P,I,n); - } - else - { - memcpy(w.C+w.P,I,d); - memcpy(w.C,I+d,n-d); - } - w.pc+=n; - return; -} - -VOID o4d2(LPBYTE I) // GOC #dd -{ - if (!w.carry) - { - w.cycles+=3; - w.pc+=3; - } - else - { - signed char jmp=I[1]+(I[2]<<4); - if (jmp) - w.pc+=jmp+1; - else - w.pc=rstkpop(); - w.cycles+=10; - w.pc&=0xFFFFF; - } - return; -} - -VOID o5d2(LPBYTE I) // GONC -{ - if (w.carry) - { - w.cycles+=3; - w.pc+=3; - } - else - { - signed char jmp=I[1]+(I[2]<<4); - if (jmp) - w.pc+=jmp+1; - else - w.pc=rstkpop(); - w.cycles+=10; - w.pc&=0xFFFFF; - } - return; -} - -VOID o6d3(LPBYTE I) // GOTO -{ - DWORD d=Npack(I+1,3); - if (d&0x800) - w.pc-=0xFFF-d; - else - w.pc+=d+1; - w.cycles+=11; - w.pc&=0xFFFFF; - return; -} - -VOID o7d3(LPBYTE I) // GOSUB -{ - DWORD d=Npack(I+1,3); - rstkpush(w.pc+4); - if (d&0x800) w.pc-=0xFFC-d; else w.pc+=d+4; - w.cycles+=12; - w.pc&=0xFFFFF; - return; -} - -VOID o800(LPBYTE I) // OUT=CS -{ - w.cycles+=4; - w.pc+=3; - w.out = (w.out&0xff0) | w.C[0]; - ScanKeyboard(FALSE,FALSE); // 1ms keyboard poll - return; -} - -VOID o801(LPBYTE I) // OUT=C -{ - WORD wOut; - w.cycles+=6; - w.pc+=3; - wOut = (WORD) Npack(w.C, 3); - if (((wOut ^ w.out) & 0x800) != 0) // beeper bit OR[11] changed - SoundOut(&w,wOut); - w.out = wOut; - ScanKeyboard(FALSE,FALSE); // 1ms keyboard poll - return; -} - -VOID o802(LPBYTE I) // A=IN -{ - w.cycles+=7; - // emulate Clarke/Yorke bug - if ((w.pc & 1) == 0 || MapData(w.pc) == M_IO) - w.pc+=3; - ScanKeyboard(TRUE,FALSE); // update Chipset.in register (direct) - IOBit(0x19,8,w.in != 0); // update KDN bit in the SRQ register - Nunpack(w.A, w.in, 4); - return; -} - -VOID o803(LPBYTE I) // C=IN -{ - w.cycles+=7; - // emulate Clarke/Yorke bug - if ((w.pc & 1) == 0 || MapData(w.pc) == M_IO) - w.pc+=3; - ScanKeyboard(TRUE,FALSE); // update Chipset.in register (direct) - IOBit(0x19,8,w.in != 0); // update KDN bit in the SRQ register - Nunpack(w.C, w.in, 4); - return; -} - -VOID o804(LPBYTE I) // UNCNFG -{ - w.cycles+=12; - w.pc+=3; - Uncnfg(); - return; -} - -VOID o805(LPBYTE I) // CONFIG -{ - w.cycles+=11; - w.pc+=3; - Config(); - return; -} - -VOID o806(LPBYTE I) // C=ID -{ - w.cycles+=11; - w.pc+=3; - C_Eq_Id(); - return; -} - -VOID o807(LPBYTE I) // SHUTDN -{ - BOOL bShutdn = TRUE; // shut down - - // only shut down when no timer wake up - if (w.IORam[TIMER1_CTRL]&WKE) // WKE bit of timer1 is set - { - if (ReadT1()&0x08) // and MSB of timer1 is set - { - w.IORam[TIMER1_CTRL] &= ~WKE; // clear WKE - bShutdn = FALSE; // don't shut down - } - } - if (w.IORam[TIMER2_CTRL]&WKE) // WKE bit of timer2 is set - { - if (ReadT2()&0x80000000) // and MSB of timer2 is set - { - w.IORam[TIMER2_CTRL] &= ~WKE; // clear WKE - bShutdn = FALSE; // don't shut down - } - } - ScanKeyboard(TRUE,FALSE); // update Chipset.in register (direct) - // out register going low during shutdown, so normal keys produce a rising - // edge trigger when out register going high again. Because the ON key is not - // connected to the out register, the rising edge trigger must be done manually. - if ((w.in & 0x7FFF) == 0 && bShutdn) // shut down only when enabled - { - w.Shutdn = TRUE; // set mode before exit emulation loop - bInterrupt = TRUE; - - // emulation of BS reset circuit in deep sleep - // HP39/40G, HP48GX, HP49G, display off, card control off or in slow mode - if ( (cCurrentRomType=='E' || cCurrentRomType=='G' || cCurrentRomType=='X') - && (w.IORam[BITOFFSET]&DON) == 0 - && ((w.IORam[CARDCTL]&(ECDT|RCDT)) != (ECDT|RCDT))) - { - // on HP48GX ROM must be selected (DA19=1) and - // the NOT MA18 address line must be low (test for high) - // else we get power on VCO from the ROM chip - // (MA18 input pin security diode to VCC pin) - if ( cCurrentRomType!='G' - || ((w.IORam[LINECOUNT+1]&DA19) && (w.pc & 0x80000))) - { - w.Bank_FF = 0; // reset bank switcher FF - RomSwitch(w.Bank_FF); // force new mapping - } - } - } - w.cycles+=6; - w.pc+=3; - return; -} - -VOID o8080(LPBYTE I) // INTON -{ - w.cycles+=5; - w.pc+=4; - w.intk = TRUE; - ScanKeyboard(FALSE,FALSE); // 1ms keyboard poll - if (w.intd || w.IR15X) // keyboard interrupt pending - { - w.intd = FALSE; // no keyboard interrupt pending any more - INTERRUPT; // restart interrupt handler - } - return; -} - -VOID o80810(LPBYTE I) // RSI -{ - w.cycles+=6; - w.pc+=5; - ScanKeyboard(TRUE,TRUE); // one input bit high (direct)? - - // enable KDN update - w.dwKdnCycles = (DWORD) (w.cycles & 0xFFFFFFFF) - (DWORD) T2CYCLES * 16; - - if (w.in && w.inte == FALSE) // key interrupt pending - w.intd = TRUE; // keyboard interrupt pending - return; -} - -VOID o8082X(LPBYTE I) // LA -{ - UINT n=I[4]+1; - UINT d=16-w.P; - w.cycles+=6+I[4]; - w.pc+=5+n; - I+=5; // UNSAFE - if (n<=d) - { - memcpy(w.A+w.P,I,n); - } - else - { - memcpy(w.A+w.P,I,d); - memcpy(w.A,I+d,n-d); - } - return; -} - -VOID o8083(LPBYTE I) // BUSCB -{ - w.cycles+=7; - w.pc+=4; - // emulated as NOP - // InfoMessage(_T("BUSCB instruction executed.")); - return; -} - -VOID o8084n(LPBYTE I) // ABIT=0 n -{ - w.cycles+=6; - w.pc+=5; - Nbit0(w.A, I[4]); - return; -} - -VOID o8085n(LPBYTE I) // ABIT=1 n -{ - w.cycles+=6; - w.pc+=5; - Nbit1(w.A, I[4]); - return; -} - -VOID o8086n(LPBYTE I) // ?ABIT=0 n -{ - w.cycles+=9; - w.pc+=5; - Tbit0(w.A, I[4]); - GOYES5; -} - -VOID o8087n(LPBYTE I) // ?ABIT=1 n -{ - w.cycles+=9; - w.pc+=5; - Tbit1(w.A, I[4]); - GOYES5; -} - -VOID o8088n(LPBYTE I) // CBIT=0 n -{ - w.cycles+=6; - w.pc+=5; - Nbit0(w.C, I[4]); - return; -} - -VOID o8089n(LPBYTE I) // CBIT=1 n -{ - w.cycles+=6; - w.pc+=5; - Nbit1(w.C, I[4]); - return; -} - -VOID o808An(LPBYTE I) // ?CBIT=0 n -{ - w.cycles+=9; - w.pc+=5; - Tbit0(w.C, I[4]); - GOYES5; -} - -VOID o808Bn(LPBYTE I) // ?CBIT=1 n -{ - w.cycles+=9; - w.pc+=5; - Tbit1(w.C, I[4]); - GOYES5; -} - -VOID o808C(LPBYTE I) // PC=(A) -{ - BYTE p[5]; - w.cycles+=23; - Nread(p,Npack(w.A,5),5); // read (A) and update CRC - w.pc=Npack(p,5); - return; -} - -VOID o808D(LPBYTE I) // BUSCD -{ - w.cycles+=7; - w.pc+=4; - // emulated as NOP - // InfoMessage(_T("BUSCD instruction executed.")); - return; -} - -VOID o808E(LPBYTE I) // PC=(C) -{ - BYTE p[5]; - w.cycles+=23; - Nread(p,Npack(w.C,5),5); // read (C) and update CRC - w.pc=Npack(p,5); - return; -} - -VOID o808F(LPBYTE I) // INTOFF -{ - w.cycles+=5; - w.pc+=4; - UpdateKdnBit(); // update KDN bit - w.intk = FALSE; - return; -} - -VOID o809(LPBYTE I) // C+P+1 - HEX MODE -{ - w.cycles+=8; - w.pc+=3; - w.C[0]+=w.P; Nincx(w.C,5); - return; -} - -VOID o80A(LPBYTE I) // RESET -{ - w.cycles+=6; - w.pc+=3; - Reset(); - return; -} - -VOID o80B(LPBYTE I) // BUSCC -{ - w.cycles+=6; - w.pc+=3; - // emulated as NOP - // InfoMessage(_T("BUSCC instruction executed.")); - return; -} - -VOID o80Cn(LPBYTE I) // C=P n -{ - w.cycles+=6; - w.pc+=4; - w.C[I[3]] = w.P; - return; -} - -VOID o80Dn(LPBYTE I) // P=C n -{ - w.cycles+=6; - w.pc+=4; - w.P = w.C[I[3]]; - PCHANGED; - return; -} - -VOID o80E(LPBYTE I) // SREQ? -{ - w.cycles+=7; - w.pc+=3; - w.C[0]=0; // no device - return; -} - -VOID o80Fn(LPBYTE I) // CPEX n -{ - BYTE n = w.P; - w.P = w.C[I[3]]; - w.C[I[3]] = n; - PCHANGED; - w.cycles+=6; - w.pc+=4; - return; -} - -VOID o810(LPBYTE I) // ASLC -{ - w.cycles+=21; - w.pc+=3; - Nslc(w.A, 16); - return; -} - -VOID o811(LPBYTE I) // BSLC -{ - w.cycles+=21; - w.pc+=3; - Nslc(w.B, 16); - return; -} - -VOID o812(LPBYTE I) // CSLC -{ - w.cycles+=21; - w.pc+=3; - Nslc(w.C, 16); - return; -} - -VOID o813(LPBYTE I) // DSLC -{ - w.cycles+=21; - w.pc+=3; - Nslc(w.D, 16); - return; -} - -VOID o814(LPBYTE I) // ASRC -{ - w.cycles+=21; - w.pc+=3; - Nsrc(w.A, 16); - return; -} - -VOID o815(LPBYTE I) // BSRC -{ - w.cycles+=21; - w.pc+=3; - Nsrc(w.B, 16); - return; -} - -VOID o816(LPBYTE I) // CSRC -{ - w.cycles+=21; - w.pc+=3; - Nsrc(w.C, 16); - return; -} - -VOID o817(LPBYTE I) // DSRC -{ - w.cycles+=21; - w.pc+=3; - Nsrc(w.D, 16); - return; -} - -VOID o818f0x(LPBYTE I) // A=A+x+1 f -{ - // register length with saturn bug emulation - UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; - - w.cycles+=5+F_l[I[3]]; - w.pc+=6; - w.A[F_s[I[3]]]+=I[5]; // add constant value-1 - Ninc16(w.A,nF_l,F_s[I[3]]); // add one and adjust in HEX mode - return; -} - -VOID o818f1x(LPBYTE I) // B=B+x+1 f -{ - // register length with saturn bug emulation - UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; - - w.cycles+=5+F_l[I[3]]; - w.pc+=6; - w.B[F_s[I[3]]]+=I[5]; // add constant value-1 - Ninc16(w.B,nF_l,F_s[I[3]]); // add one and adjust in HEX mode - return; -} - -VOID o818f2x(LPBYTE I) // C=C+x+1 f -{ - // register length with saturn bug emulation - UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; - - w.cycles+=5+F_l[I[3]]; - w.pc+=6; - w.C[F_s[I[3]]]+=I[5]; // add constant value-1 - Ninc16(w.C,nF_l,F_s[I[3]]); // add one and adjust in HEX mode - return; -} - -VOID o818f3x(LPBYTE I) // D=D+x+1 f -{ - // register length with saturn bug emulation - UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; - - w.cycles+=5+F_l[I[3]]; - w.pc+=6; - w.D[F_s[I[3]]]+=I[5]; // add constant value-1 - Ninc16(w.D,nF_l,F_s[I[3]]); // add one and adjust in HEX mode - return; -} - -VOID o818f8x(LPBYTE I) // A=A-x-1 f -{ - // register length with saturn bug emulation - UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; - - w.cycles+=5+F_l[I[3]]; - w.pc+=6; - w.A[F_s[I[3]]]-=I[5]; // sub constant value+1 - Ndec16(w.A,nF_l,F_s[I[3]]); // dec one and adjust in HEX mode - return; -} - -VOID o818f9x(LPBYTE I) // B=B-x-1 f -{ - // register length with saturn bug emulation - UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; - - w.cycles+=5+F_l[I[3]]; - w.pc+=6; - w.B[F_s[I[3]]]-=I[5]; // sub constant value+1 - Ndec16(w.B,nF_l,F_s[I[3]]); // dec one and adjust in HEX mode - return; -} - -VOID o818fAx(LPBYTE I) // C=C-x-1 f -{ - // register length with saturn bug emulation - UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; - - w.cycles+=5+F_l[I[3]]; - w.pc+=6; - w.C[F_s[I[3]]]-=I[5]; // sub constant value+1 - Ndec16(w.C,nF_l,F_s[I[3]]); // dec one and adjust in HEX mode - return; -} - -VOID o818fBx(LPBYTE I) // D=D-x-1 f -{ - // register length with saturn bug emulation - UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; - - w.cycles+=5+F_l[I[3]]; - w.pc+=6; - w.D[F_s[I[3]]]-=I[5]; // sub constant value+1 - Ndec16(w.D,nF_l,F_s[I[3]]); // dec one and adjust in HEX mode - return; -} - -VOID o819f0(LPBYTE I) // ASRB.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=5; - NFsrb(w.A, I[3]); - return; -} - -VOID o819f1(LPBYTE I) // BSRB.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=5; - NFsrb(w.B, I[3]); - return; -} - -VOID o819f2(LPBYTE I) // CSRB.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=5; - NFsrb(w.C, I[3]); - return; -} - -VOID o819f3(LPBYTE I) // DSRB.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=5; - NFsrb(w.D, I[3]); - return; -} - -VOID o81Af00(LPBYTE I) // R0=A.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.R0, w.A, I[3]); - return; -} - -VOID o81Af01(LPBYTE I) // R1=A.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.R1, w.A, I[3]); - return; -} - -VOID o81Af02(LPBYTE I) // R2=A.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.R2, w.A, I[3]); - return; -} - -VOID o81Af03(LPBYTE I) // R3=A.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.R3, w.A, I[3]); - return; -} - -VOID o81Af04(LPBYTE I) // R4=A.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.R4, w.A, I[3]); - return; -} - -VOID o81Af08(LPBYTE I) // R0=C.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.R0, w.C, I[3]); - return; -} - -VOID o81Af09(LPBYTE I) // R1=C.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.R1, w.C, I[3]); - return; -} - -VOID o81Af0A(LPBYTE I) // R2=C.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.R2, w.C, I[3]); - return; -} - -VOID o81Af0B(LPBYTE I) // R3=C.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.R3, w.C, I[3]); - return; -} - -VOID o81Af0C(LPBYTE I) // R4=C.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.R4, w.C, I[3]); - return; -} - -VOID o81Af10(LPBYTE I) // A=R0.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.A, w.R0, I[3]); - return; -} - -VOID o81Af11(LPBYTE I) // A=R1.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.A, w.R1, I[3]); - return; -} - -VOID o81Af12(LPBYTE I) // A=R2.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.A, w.R2, I[3]); - return; -} - -VOID o81Af13(LPBYTE I) // A=R3.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.A, w.R3, I[3]); - return; -} - -VOID o81Af14(LPBYTE I) // A=R4.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.A, w.R4, I[3]); - return; -} - -VOID o81Af18(LPBYTE I) // C=R0.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.C, w.R0, I[3]); - return; -} - -VOID o81Af19(LPBYTE I) // C=R1.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.C, w.R1, I[3]); - return; -} - -VOID o81Af1A(LPBYTE I) // C=R2.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.C, w.R2, I[3]); - return; -} - -VOID o81Af1B(LPBYTE I) // C=R3.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.C, w.R3, I[3]); - return; -} - -VOID o81Af1C(LPBYTE I) // C=R4.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFcopy(w.C, w.R4, I[3]); - return; -} - -VOID o81Af20(LPBYTE I) // AR0EX.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFxchg(w.A, w.R0, I[3]); - return; -} - -VOID o81Af21(LPBYTE I) // AR1EX.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFxchg(w.A, w.R1, I[3]); - return; -} - -VOID o81Af22(LPBYTE I) // AR2EX.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFxchg(w.A, w.R2, I[3]); - return; -} - -VOID o81Af23(LPBYTE I) // AR3EX.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFxchg(w.A, w.R3, I[3]); - return; -} - -VOID o81Af24(LPBYTE I) // AR4EX.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFxchg(w.A, w.R4, I[3]); - return; -} - -VOID o81Af28(LPBYTE I) // CR0EX.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFxchg(w.C, w.R0, I[3]); - return; -} - -VOID o81Af29(LPBYTE I) // CR1EX.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFxchg(w.C, w.R1, I[3]); - return; -} - -VOID o81Af2A(LPBYTE I) // CR2EX.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFxchg(w.C, w.R2, I[3]); - return; -} - -VOID o81Af2B(LPBYTE I) // CR3EX.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFxchg(w.C, w.R3, I[3]); - return; -} - -VOID o81Af2C(LPBYTE I) // CR4EX.F f -{ - w.cycles+=6+F_l[I[3]]; - w.pc+=6; - NFxchg(w.C, w.R4, I[3]); - return; -} - -VOID o81B2(LPBYTE I) // PC=A -{ - w.cycles+=16; - w.pc = Npack(w.A,5); - return; -} - -VOID o81B3(LPBYTE I) // PC=C -{ - w.cycles+=16; - w.pc = Npack(w.C,5); - return; -} - -VOID o81B4(LPBYTE I) // A=PC -{ - w.cycles+=9; - w.pc+=4; - Nunpack(w.A,w.pc,5); - return; -} - -VOID o81B5(LPBYTE I) // C=PC -{ - w.cycles+=9; - w.pc+=4; - Nunpack(w.C,w.pc,5); - return; -} - -VOID o81B6(LPBYTE I) // APCEX -{ - DWORD d=w.pc+4; - w.cycles+=16; - w.pc=Npack(w.A,5); - Nunpack(w.A,d,5); - return; -} - -VOID o81B7(LPBYTE I) // CPCEX -{ - DWORD d=w.pc+4; - w.cycles+=16; - w.pc=Npack(w.C,5); - Nunpack(w.C,d,5); - return; -} - -VOID o81C(LPBYTE I) // ASRB -{ - w.cycles+=20; - w.pc+=3; - Nsrb(w.A, 16); - return; -} - -VOID o81D(LPBYTE I) // BSRB -{ - w.cycles+=20; - w.pc+=3; - Nsrb(w.B, 16); - return; -} - -VOID o81E(LPBYTE I) // CSRB -{ - w.cycles+=20; - w.pc+=3; - Nsrb(w.C, 16); - return; -} - -VOID o81F(LPBYTE I) // DSRB -{ - w.cycles+=20; - w.pc+=3; - Nsrb(w.D, 16); - return; -} - -VOID o82n(LPBYTE I) // HST=0 m -{ - w.cycles+=3; - w.pc+=3; - w.HST&=~I[2]; - return; -} - -VOID o83n(LPBYTE I) // ?HST=0 m -{ - w.cycles+=6; - w.pc+=3; - w.carry=((w.HST&I[2])==0); - GOYES3; -} - -VOID o84n(LPBYTE I) // ST=0 n -{ - w.cycles+=4; - w.pc+=3; - Nbit0(w.ST, I[2]); - return; -} - -VOID o85n(LPBYTE I) // ST=1 n -{ - w.cycles+=4; - w.pc+=3; - Nbit1(w.ST, I[2]); - return; -} - -VOID o86n(LPBYTE I) // ?ST=0 n -{ - w.cycles+=7; - w.pc+=3; - Tbit0(w.ST, I[2]); - GOYES3; -} - -VOID o87n(LPBYTE I) // ?ST=1 n -{ - w.cycles+=7; - w.pc+=3; - Tbit1(w.ST, I[2]); - GOYES3; -} - -VOID o88n(LPBYTE I) // ?P# n -{ - w.cycles+=6; - w.pc+=3; - w.carry=(w.P!=I[2]); - GOYES3; -} - -VOID o89n(LPBYTE I) // ?P= n -{ - w.cycles+=6; - w.pc+=3; - w.carry=(w.P==I[2]); - GOYES3; -} - -VOID o8A0(LPBYTE I) // ?A=B A -{ - w.cycles+=11; - w.pc+=3; - Te(w.A, w.B, 5); - GOYES3; -} - -VOID o8A1(LPBYTE I) // ?B=C A -{ - w.cycles+=11; - w.pc+=3; - Te(w.B, w.C, 5); - GOYES3; -} - -VOID o8A2(LPBYTE I) // ?C=A A -{ - w.cycles+=11; - w.pc+=3; - Te(w.C, w.A, 5); - GOYES3; -} - -VOID o8A3(LPBYTE I) // ?D=C A -{ - w.cycles+=11; - w.pc+=3; - Te(w.D, w.C, 5); - GOYES3; -} - -VOID o8A4(LPBYTE I) // ?A#B A -{ - w.cycles+=11; - w.pc+=3; - Tne(w.A, w.B, 5); - GOYES3; -} - -VOID o8A5(LPBYTE I) // ?B#C A -{ - w.cycles+=11; - w.pc+=3; - Tne(w.B, w.C, 5); - GOYES3; -} - -VOID o8A6(LPBYTE I) // ?C#A A -{ - w.cycles+=11; - w.pc+=3; - Tne(w.C, w.A, 5); - GOYES3; -} - -VOID o8A7(LPBYTE I) // ?D#C A -{ - w.cycles+=11; - w.pc+=3; - Tne(w.D, w.C, 5); - GOYES3; -} - -VOID o8A8(LPBYTE I) // ?A=0 A -{ - w.cycles+=11; - w.pc+=3; - Tz(w.A, 5); - GOYES3; -} - -VOID o8A9(LPBYTE I) // ?B=0 A -{ - w.cycles+=11; - w.pc+=3; - Tz(w.B, 5); - GOYES3; -} - -VOID o8AA(LPBYTE I) // ?C=0 A -{ - w.cycles+=11; - w.pc+=3; - Tz(w.C, 5); - GOYES3; -} - -VOID o8AB(LPBYTE I) // ?D=0 A -{ - w.cycles+=11; - w.pc+=3; - Tz(w.D, 5); - GOYES3; -} - -VOID o8AC(LPBYTE I) // ?A#0 A -{ - w.cycles+=11; - w.pc+=3; - Tnz(w.A, 5); - GOYES3; -} - -VOID o8AD(LPBYTE I) // ?B#0 A -{ - w.cycles+=11; - w.pc+=3; - Tnz(w.B, 5); - GOYES3; -} - -VOID o8AE(LPBYTE I) // ?C#0 A -{ - w.cycles+=11; - w.pc+=3; - Tnz(w.C, 5); - GOYES3; -} - -VOID o8AF(LPBYTE I) // ?D#0 A -{ - w.cycles+=11; - w.pc+=3; - Tnz(w.D, 5); - GOYES3; -} - -VOID o8B0(LPBYTE I) // ?A>B A -{ - w.cycles+=11; - w.pc+=3; - Ta(w.A, w.B, 5); - GOYES3; -} - -VOID o8B1(LPBYTE I) // ?B>C A -{ - w.cycles+=11; - w.pc+=3; - Ta(w.B, w.C, 5); - GOYES3; -} - -VOID o8B2(LPBYTE I) // ?C>A A -{ - w.cycles+=11; - w.pc+=3; - Ta(w.C, w.A, 5); - GOYES3; -} - -VOID o8B3(LPBYTE I) // ?D>C A -{ - w.cycles+=11; - w.pc+=3; - Ta(w.D, w.C, 5); - GOYES3; -} - -VOID o8B4(LPBYTE I) // ?A=B A -{ - w.cycles+=11; - w.pc+=3; - Tae(w.A, w.B, 5); - GOYES3; -} - -VOID o8B9(LPBYTE I) // ?B>=C A -{ - w.cycles+=11; - w.pc+=3; - Tae(w.B, w.C, 5); - GOYES3; -} - -VOID o8BA(LPBYTE I) // ?C>=A A -{ - w.cycles+=11; - w.pc+=3; - Tae(w.C, w.A, 5); - GOYES3; -} - -VOID o8BB(LPBYTE I) // ?D>=C A -{ - w.cycles+=11; - w.pc+=3; - Tae(w.D, w.C, 5); - GOYES3; -} - -VOID o8BC(LPBYTE I) // ?A<=B A -{ - w.cycles+=11; - w.pc+=3; - Tbe(w.A, w.B, 5); - GOYES3; -} - -VOID o8BD(LPBYTE I) // ?B<=C A -{ - w.cycles+=11; - w.pc+=3; - Tbe(w.B, w.C, 5); - GOYES3; -} - -VOID o8BE(LPBYTE I) // ?C<=A A -{ - w.cycles+=11; - w.pc+=3; - Tbe(w.C, w.A, 5); - GOYES3; -} - -VOID o8BF(LPBYTE I) // ?D<=C A -{ - w.cycles+=11; - w.pc+=3; - Tbe(w.D, w.C, 5); - GOYES3; -} - -VOID o8Cd4(LPBYTE I) // GOLONG #dddd -{ - DWORD d=Npack(I+2, 4); - if (d&0x8000) w.pc -= 0xfffe - d; else w.pc+= d + 2; - w.cycles+=14; - w.pc&=0xFFFFF; - return; -} - -VOID o8Dd5(LPBYTE I) // GOVLNG #ddddd -{ - w.cycles+=14; - w.pc = Npack(I+2, 5); - return; -} - -VOID o8Ed4(LPBYTE I) // GOSUBL #dddd -{ - DWORD d=Npack(I+2,4); - rstkpush(w.pc+6); - if (d&0x8000) w.pc -= 0xfffa - d; else w.pc += d + 6; - w.cycles+=14; - w.pc&=0xFFFFF; - return; -} - -VOID o8Fd5(LPBYTE I) // GOSBVL #ddddd -{ - w.cycles+=15; - rstkpush(w.pc+7); - w.pc=Npack(I+2, 5); - return; -} - - // ?r=s f -VOID o9a0(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFe(w.A, w.B, I[1]); GOYES3; } -VOID o9a1(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFe(w.B, w.C, I[1]); GOYES3; } -VOID o9a2(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFe(w.C, w.A, I[1]); GOYES3; } -VOID o9a3(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFe(w.D, w.C, I[1]); GOYES3; } - - // ?r#s f -VOID o9a4(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFne(w.A, w.B, I[1]); GOYES3; } -VOID o9a5(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFne(w.B, w.C, I[1]); GOYES3; } -VOID o9a6(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFne(w.C, w.A, I[1]); GOYES3; } -VOID o9a7(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFne(w.D, w.C, I[1]); GOYES3; } - - // ?r=0 f -VOID o9a8(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFz(w.A, I[1]); GOYES3; } -VOID o9a9(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFz(w.B, I[1]); GOYES3; } -VOID o9aA(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFz(w.C, I[1]); GOYES3; } -VOID o9aB(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFz(w.D, I[1]); GOYES3; } - - // ?r#0 f -VOID o9aC(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFnz(w.A, I[1]); GOYES3; } -VOID o9aD(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFnz(w.B, I[1]); GOYES3; } -VOID o9aE(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFnz(w.C, I[1]); GOYES3; } -VOID o9aF(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFnz(w.D, I[1]); GOYES3; } - - // ?s>r f -VOID o9b0(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFa(w.A, w.B, I[1]&7); GOYES3; } -VOID o9b1(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFa(w.B, w.C, I[1]&7); GOYES3; } -VOID o9b2(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFa(w.C, w.A, I[1]&7); GOYES3; } -VOID o9b3(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFa(w.D, w.C, I[1]&7); GOYES3; } - - // ?r=s f -VOID o9b8(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFae(w.A, w.B, I[1]&7); GOYES3; } -VOID o9b9(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFae(w.B, w.C, I[1]&7); GOYES3; } -VOID o9bA(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFae(w.C, w.A, I[1]&7); GOYES3; } -VOID o9bB(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFae(w.D, w.C, I[1]&7); GOYES3; } - - // ?r<=s f -VOID o9bC(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFbe(w.A, w.B, I[1]&7); GOYES3; } -VOID o9bD(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFbe(w.B, w.C, I[1]&7); GOYES3; } -VOID o9bE(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFbe(w.C, w.A, I[1]&7); GOYES3; } -VOID o9bF(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFbe(w.D, w.C, I[1]&7); GOYES3; } - - // r=r+s f -VOID oAa0(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.A, w.B, I[1]); return; } -VOID oAa1(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.B, w.C, I[1]); return; } -VOID oAa2(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.C, w.A, I[1]); return; } -VOID oAa3(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.D, w.C, I[1]); return; } - - // r=r+r f -VOID oAa4(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.A, w.A, I[1]); return; } -VOID oAa5(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.B, w.B, I[1]); return; } -VOID oAa6(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.C, w.C, I[1]); return; } -VOID oAa7(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.D, w.D, I[1]); return; } - - // s=s+r f -VOID oAa8(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.B, w.A, I[1]); return; } -VOID oAa9(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.C, w.B, I[1]); return; } -VOID oAaA(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.A, w.C, I[1]); return; } -VOID oAaB(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.C, w.D, I[1]); return; } - - // r=r-1 f -VOID oAaC(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFdec(w.A, I[1]); return; } -VOID oAaD(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFdec(w.B, I[1]); return; } -VOID oAaE(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFdec(w.C, I[1]); return; } -VOID oAaF(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFdec(w.D, I[1]); return; } - - // r=0 f -VOID oAb0(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFzero(w.A, I[1]&7); return; } -VOID oAb1(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFzero(w.B, I[1]&7); return; } -VOID oAb2(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFzero(w.C, I[1]&7); return; } -VOID oAb3(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFzero(w.D, I[1]&7); return; } - - // r=s f -VOID oAb4(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.A, w.B, I[1]&7); return; } -VOID oAb5(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.B, w.C, I[1]&7); return; } -VOID oAb6(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.C, w.A, I[1]&7); return; } -VOID oAb7(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.D, w.C, I[1]&7); return; } - - // s=r f -VOID oAb8(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.B, w.A, I[1]&7); return; } -VOID oAb9(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.C, w.B, I[1]&7); return; } -VOID oAbA(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.A, w.C, I[1]&7); return; } -VOID oAbB(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.C, w.D, I[1]&7); return; } - - // rsEX f -VOID oAbC(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFxchg(w.A, w.B, I[1]&7); return; } -VOID oAbD(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFxchg(w.B, w.C, I[1]&7); return; } -VOID oAbE(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFxchg(w.C, w.A, I[1]&7); return; } -VOID oAbF(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFxchg(w.D, w.C, I[1]&7); return; } - - // r=r-s f -VOID oBa0(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.A, w.B, I[1]); return; } -VOID oBa1(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.B, w.C, I[1]); return; } -VOID oBa2(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.C, w.A, I[1]); return; } -VOID oBa3(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.D, w.C, I[1]); return; } - - // r=r+1 f -VOID oBa4(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFinc(w.A, I[1]); return; } -VOID oBa5(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFinc(w.B, I[1]); return; } -VOID oBa6(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFinc(w.C, I[1]); return; } -VOID oBa7(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFinc(w.D, I[1]); return; } - - // s=s-r f -VOID oBa8(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.B, w.A, I[1]); return; } -VOID oBa9(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.C, w.B, I[1]); return; } -VOID oBaA(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.A, w.C, I[1]); return; } -VOID oBaB(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.C, w.D, I[1]); return; } - - // r=s-r f -VOID oBaC(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFrsub(w.A, w.B, I[1]); return; } -VOID oBaD(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFrsub(w.B, w.C, I[1]); return; } -VOID oBaE(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFrsub(w.C, w.A, I[1]); return; } -VOID oBaF(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFrsub(w.D, w.C, I[1]); return; } - - // rSL f -VOID oBb0(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsl(w.A, I[1]&7); return; } -VOID oBb1(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsl(w.B, I[1]&7); return; } -VOID oBb2(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsl(w.C, I[1]&7); return; } -VOID oBb3(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsl(w.D, I[1]&7); return; } - - // rSR f -VOID oBb4(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsr(w.A, I[1]&7); return; } -VOID oBb5(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsr(w.B, I[1]&7); return; } -VOID oBb6(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsr(w.C, I[1]&7); return; } -VOID oBb7(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsr(w.D, I[1]&7); return; } - - // r=-r f -VOID oBb8(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFneg(w.A, I[1]&7); return; } -VOID oBb9(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFneg(w.B, I[1]&7); return; } -VOID oBbA(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFneg(w.C, I[1]&7); return; } -VOID oBbB(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFneg(w.D, I[1]&7); return; } - - // r=-r-1 f -VOID oBbC(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFnot(w.A, I[1]&7); return; } -VOID oBbD(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFnot(w.B, I[1]&7); return; } -VOID oBbE(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFnot(w.C, I[1]&7); return; } -VOID oBbF(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFnot(w.D, I[1]&7); return; } - - // r=r+s A -VOID oC0(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.A, w.B, 5); return; } -VOID oC1(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.B, w.C, 5); return; } -VOID oC2(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.C, w.A, 5); return; } -VOID oC3(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.D, w.C, 5); return; } - - // r=r+r A -VOID oC4(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.A, w.A, 5); return; } -VOID oC5(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.B, w.B, 5); return; } -VOID oC6(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.C, w.C, 5); return; } -VOID oC7(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.D, w.D, 5); return; } - - // s=s+r A -VOID oC8(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.B, w.A, 5); return; } -VOID oC9(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.C, w.B, 5); return; } -VOID oCA(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.A, w.C, 5); return; } -VOID oCB(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.C, w.D, 5); return; } - - // r=r-1 A -VOID oCC(LPBYTE I) { w.cycles+=7; w.pc+=2; Ndec(w.A, 5, 0); return; } -VOID oCD(LPBYTE I) { w.cycles+=7; w.pc+=2; Ndec(w.B, 5, 0); return; } -VOID oCE(LPBYTE I) { w.cycles+=7; w.pc+=2; Ndec(w.C, 5, 0); return; } -VOID oCF(LPBYTE I) { w.cycles+=7; w.pc+=2; Ndec(w.D, 5, 0); return; } - - // r=0 A -VOID oD0(LPBYTE I) { w.cycles+=7; w.pc+=2; memset(w.A, 0, 5); return; } -VOID oD1(LPBYTE I) { w.cycles+=7; w.pc+=2; memset(w.B, 0, 5); return; } -VOID oD2(LPBYTE I) { w.cycles+=7; w.pc+=2; memset(w.C, 0, 5); return; } -VOID oD3(LPBYTE I) { w.cycles+=7; w.pc+=2; memset(w.D, 0, 5); return; } - - // r=s A -VOID oD4(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.A, w.B, 5); return; } -VOID oD5(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.B, w.C, 5); return; } -VOID oD6(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.C, w.A, 5); return; } -VOID oD7(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.D, w.C, 5); return; } - - // s=r A -VOID oD8(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.B, w.A, 5); return; } -VOID oD9(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.C, w.B, 5); return; } -VOID oDA(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.A, w.C, 5); return; } -VOID oDB(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.C, w.D, 5); return; } - - // rsEX -VOID oDC(LPBYTE I) { w.cycles+=7; w.pc+=2; Nxchg(w.A, w.B, 5); return; } -VOID oDD(LPBYTE I) { w.cycles+=7; w.pc+=2; Nxchg(w.B, w.C, 5); return; } -VOID oDE(LPBYTE I) { w.cycles+=7; w.pc+=2; Nxchg(w.C, w.A, 5); return; } -VOID oDF(LPBYTE I) { w.cycles+=7; w.pc+=2; Nxchg(w.D, w.C, 5); return; } - - // r=r-s A -VOID oE0(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.A, w.B, 5); return; } -VOID oE1(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.B, w.C, 5); return; } -VOID oE2(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.C, w.A, 5); return; } -VOID oE3(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.D, w.C, 5); return; } - - // r=r+1 A -VOID oE4(LPBYTE I) { w.cycles+=7; w.pc+=2; Ninc(w.A, 5, 0); return; } -VOID oE5(LPBYTE I) { w.cycles+=7; w.pc+=2; Ninc(w.B, 5, 0); return; } -VOID oE6(LPBYTE I) { w.cycles+=7; w.pc+=2; Ninc(w.C, 5, 0); return; } -VOID oE7(LPBYTE I) { w.cycles+=7; w.pc+=2; Ninc(w.D, 5, 0); return; } - - // s=s-r A -VOID oE8(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.B, w.A, 5); return; } -VOID oE9(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.C, w.B, 5); return; } -VOID oEA(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.A, w.C, 5); return; } -VOID oEB(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.C, w.D, 5); return; } - - // r=s-r A -VOID oEC(LPBYTE I) { w.cycles+=7; w.pc+=2; Nrsub(w.A, w.B, 5); return; } -VOID oED(LPBYTE I) { w.cycles+=7; w.pc+=2; Nrsub(w.B, w.C, 5); return; } -VOID oEE(LPBYTE I) { w.cycles+=7; w.pc+=2; Nrsub(w.C, w.A, 5); return; } -VOID oEF(LPBYTE I) { w.cycles+=7; w.pc+=2; Nrsub(w.D, w.C, 5); return; } - - // rSL A -VOID oF0(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsl(w.A, 5); return; } -VOID oF1(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsl(w.B, 5); return; } -VOID oF2(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsl(w.C, 5); return; } -VOID oF3(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsl(w.D, 5); return; } - - // rSR A -VOID oF4(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsr(w.A, 5); return; } -VOID oF5(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsr(w.B, 5); return; } -VOID oF6(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsr(w.C, 5); return; } -VOID oF7(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsr(w.D, 5); return; } - - // r=-r A -VOID oF8(LPBYTE I) { w.cycles+=7; w.pc+=2; Nneg(w.A, 5); return; } -VOID oF9(LPBYTE I) { w.cycles+=7; w.pc+=2; Nneg(w.B, 5); return; } -VOID oFA(LPBYTE I) { w.cycles+=7; w.pc+=2; Nneg(w.C, 5); return; } -VOID oFB(LPBYTE I) { w.cycles+=7; w.pc+=2; Nneg(w.D, 5); return; } - - // r=-r-1 A -VOID oFC(LPBYTE I) { w.cycles+=7; w.pc+=2; Nnot(w.A, 5); return; } -VOID oFD(LPBYTE I) { w.cycles+=7; w.pc+=2; Nnot(w.B, 5); return; } -VOID oFE(LPBYTE I) { w.cycles+=7; w.pc+=2; Nnot(w.C, 5); return; } -VOID oFF(LPBYTE I) { w.cycles+=7; w.pc+=2; Nnot(w.D, 5); return; } - -// length is guessed, just skip -VOID o_invalid3(LPBYTE I) -{ - _ASSERT(FALSE); // invalid, length guessed, skip 3 nibbles - w.pc+=3; - return; -} - -VOID o_invalid4(LPBYTE I) -{ - _ASSERT(FALSE); // invalid, length guessed, skip 4 nibbles - w.pc+=4; - return; -} - -VOID o_invalid5(LPBYTE I) -{ - _ASSERT(FALSE); // invalid, length guessed, skip 5 nibbles - w.pc+=5; - return; -} - -VOID o_invalid6(LPBYTE I) -{ - _ASSERT(FALSE); // invalid, length guessed, skip 6 nibbles - w.pc+=6; - return; -} - -VOID o_goyes3(LPBYTE I) -{ - signed char jmp = I[3]+(I[4]<<4); - w.cycles+=7; - if (jmp) - w.pc=(w.pc+jmp)&0xFFFFF; - else - w.pc=rstkpop(); - return; -} - -VOID o_goyes5(LPBYTE I) -{ - signed char jmp = I[5]+(I[6]<<4); - w.cycles+=7; - if (jmp) - w.pc=(w.pc+jmp)&0xFFFFF; - else - w.pc=rstkpop(); - return; -} +/* + * opcodes.c + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * Copyright (C) 1999 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" +#include "Opcodes.h" +#include "io.h" // I/O register definitions + +#define w Chipset +#define GOYES3 {if(w.carry) o_goyes3(I);else{w.pc+=2;return;}} +#define GOYES5 {if(w.carry) o_goyes5(I);else{w.pc+=2;return;}} + +#if !defined _BIGENDIAN +#define REG(t,r) (*((t*)&(r))) // little endian machine +#else +#define REG(t,r) (*((t*)((BYTE*)&(r)+sizeof(r)-sizeof(t)))) // big endian machine +#endif + +#pragma intrinsic(memset,memcpy) + +#include "Ops.h" + +// Fields start and length +UINT F_s[16] = {0/*P*/,0,2,0,15,3,0,0,0,0,0,0,0,0,0,0}; +UINT F_l[16] = {1,1/*P+1*/,1,3,1,12,2,16,0,0,0,0,0,0,0,5}; + +VOID o00(LPBYTE I) // RTNSXM +{ + w.cycles+=9; + w.pc = rstkpop(); + w.HST |= XM; + return; +} + +VOID o01(LPBYTE I) // RTN +{ + w.cycles+=9; + w.pc = rstkpop(); + return; +} + +VOID o02(LPBYTE I) // RTNSC +{ + w.cycles+=9; + w.pc = rstkpop(); + w.carry = TRUE; + return; +} + +VOID o03(LPBYTE I) // RTNCC +{ + w.cycles+=9; + w.pc = rstkpop(); + w.carry = FALSE; + return; +} + +VOID o04(LPBYTE I) // SETHEX +{ + w.cycles+=3; + w.pc+=2; + w.mode_dec = FALSE; + return; +} + +VOID o05(LPBYTE I) // SETDEC +{ + w.cycles+=3; + w.pc+=2; + w.mode_dec = TRUE; + return; +} + +VOID o06(LPBYTE I) // RSTK=C +{ + w.cycles+=8; + w.pc+=2; + rstkpush(Npack(w.C,5)); + return; +} + +VOID o07(LPBYTE I) // C=RSTK +{ + w.cycles+=8; + w.pc+=2; + Nunpack(w.C,rstkpop(),5); + return; +} + +VOID o08(LPBYTE I) // CLRST +{ + w.cycles+=5; + w.pc+=2; + memset(w.ST, 0, 3); + return; +} + +VOID o09(LPBYTE I) // C=ST +{ + w.cycles+=5; + w.pc+=2; + memcpy(w.C, w.ST, 3); + return; +} + +VOID o0A(LPBYTE I) // ST=C +{ + w.cycles+=5; + w.pc+=2; + memcpy(w.ST, w.C, 3); + return; +} + +VOID o0B(LPBYTE I) // CSTEX +{ + w.cycles+=5; + w.pc+=2; + Nxchg(w.C, w.ST, 3); + return; +} + +VOID o0C(LPBYTE I) // P=P+1 +{ + w.cycles+=3; + w.pc+=2; + if (w.P<15) + { + w.P++; + w.carry=FALSE; + } + else + { + w.P=0; + w.carry=TRUE; + } + PCHANGED; + return; +} + +VOID o0D(LPBYTE I) // P=P-1 +{ + w.cycles+=3; + w.pc+=2; + if (w.P) + { + w.P--; + w.carry=FALSE; + } + else + { + w.P=0xF; + w.carry=TRUE; + } + PCHANGED; + return; +} + +VOID o0Ef0(LPBYTE I) // A=A&B f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFand(w.A,w.B,I[2]); + return; +} +VOID o0Ef1(LPBYTE I) // B=B&C f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFand(w.B,w.C,I[2]); + return; +} +VOID o0Ef2(LPBYTE I) // C=C&A f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFand(w.C,w.A,I[2]); + return; +} +VOID o0Ef3(LPBYTE I) // D=D&C f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFand(w.D,w.C,I[2]); + return; +} +VOID o0Ef4(LPBYTE I) // B=B&A f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFand(w.B,w.A,I[2]); + return; +} +VOID o0Ef5(LPBYTE I) // C=C&B f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFand(w.C,w.B,I[2]); + return; +} +VOID o0Ef6(LPBYTE I) // A=A&C f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFand(w.A,w.C,I[2]); + return; +} +VOID o0Ef7(LPBYTE I) // C=C&D f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFand(w.C,w.D,I[2]); + return; +} + +VOID o0Ef8(LPBYTE I) // A=A!B f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFor(w.A,w.B,I[2]); + return; +} +VOID o0Ef9(LPBYTE I) // B=B!C f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFor(w.B,w.C,I[2]); + return; +} +VOID o0EfA(LPBYTE I) // C=C!A f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFor(w.C,w.A,I[2]); + return; +} +VOID o0EfB(LPBYTE I) // D=D!C f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFor(w.D,w.C,I[2]); + return; +} +VOID o0EfC(LPBYTE I) // B=B!A f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFor(w.B,w.A,I[2]); + return; +} +VOID o0EfD(LPBYTE I) // C=C!B f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFor(w.C,w.B,I[2]); + return; +} +VOID o0EfE(LPBYTE I) // A=A!C f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFor(w.A,w.C,I[2]); + return; +} +VOID o0EfF(LPBYTE I) // C=C!D f +{ + w.cycles+=4+F_l[I[2]]; + w.pc+=4; + NFor(w.C,w.D,I[2]); + return; +} + +VOID o0F(LPBYTE I) // RTI +{ + w.cycles+=9; + w.pc = rstkpop(); + w.inte = TRUE; // enable interrupt + + if ((w.intd && w.intk) || w.IR15X) // keyboard interrupt pending + { + w.intd = FALSE; // no keyboard interrupt pending any more + INTERRUPT; // restart interrupt handler + } + + // low interrupt lines + { + BOOL bNINT2 = Chipset.IORam[SRQ1] == 0 && (Chipset.IORam[SRQ2] & LSRQ) == 0; + BOOL bNINT = (Chipset.IORam[SRQ2] & NINT) != 0; + + // card detection off and timer running + if ((Chipset.IORam[CARDCTL] & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0) + { + // state of CDT2 + bNINT2 = bNINT2 && (Chipset.cards_status & (P2W|P2C)) != P2C; + // state of CDT1 + bNINT = bNINT && (Chipset.cards_status & (P1W|P1C)) != P1C; + } + + if (!bNINT2 || !bNINT) // NINT2 or NINT interrupt line low + INTERRUPT; // restart interrupt handler + } + + // restart interrupt handler when timer interrupt + if (w.IORam[TIMER1_CTRL]&INTR) // INT bit of timer1 is set + ReadT1(); // check for int + + if (w.IORam[TIMER2_CTRL]&INTR) // INT bit of timer2 is set + ReadT2(); // check for int + return; +} + +VOID o100(LPBYTE I) // R0=A W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.R0, w.A, 16); + return; +} + +VOID o101(LPBYTE I) // R1=A W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.R1, w.A, 16); + return; +} + +VOID o102(LPBYTE I) // R2=A W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.R2, w.A, 16); + return; +} + +VOID o103(LPBYTE I) // R3=A W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.R3, w.A, 16); + return; +} + +VOID o104(LPBYTE I) // R4=A W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.R4, w.A, 16); + return; +} + +VOID o108(LPBYTE I) // R0=C W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.R0, w.C, 16); + return; +} + +VOID o109(LPBYTE I) // R1=C W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.R1, w.C, 16); + return; +} + +VOID o10A(LPBYTE I) // R2=C W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.R2, w.C, 16); + return; +} + +VOID o10B(LPBYTE I) // R3=C W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.R3, w.C, 16); + return; +} + +VOID o10C(LPBYTE I) // R4=C W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.R4, w.C, 16); + return; +} + +VOID o110(LPBYTE I) // A=R0 W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.A, w.R0, 16); + return; +} + +VOID o111(LPBYTE I) // A=R1 W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.A, w.R1, 16); + return; +} + +VOID o112(LPBYTE I) // A=R2 W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.A, w.R2, 16); + return; +} + +VOID o113(LPBYTE I) // A=R3 W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.A, w.R3, 16); + return; +} + +VOID o114(LPBYTE I) // A=R4 W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.A, w.R4, 16); + return; +} + +VOID o118(LPBYTE I) // C=R0 W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.C, w.R0, 16); + return; +} + +VOID o119(LPBYTE I) // C=R1 W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.C, w.R1, 16); + return; +} + +VOID o11A(LPBYTE I) // C=R2 W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.C, w.R2, 16); + return; +} + +VOID o11B(LPBYTE I) // C=R3 W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.C, w.R3, 16); + return; +} + +VOID o11C(LPBYTE I) // C=R4 W +{ + w.cycles+=19; + w.pc+=3; + memcpy(w.C, w.R4, 16); + return; +} + +VOID o120(LPBYTE I) // AR0EX W +{ + w.cycles+=19; + w.pc+=3; + Nxchg(w.A, w.R0, 16); + return; +} + +VOID o121(LPBYTE I) // AR1EX W +{ + w.cycles+=19; + w.pc+=3; + Nxchg(w.A, w.R1, 16); + return; +} + +VOID o122(LPBYTE I) // AR2EX W +{ + w.cycles+=19; + w.pc+=3; + Nxchg(w.A, w.R2, 16); + return; +} + +VOID o123(LPBYTE I) // AR3EX W +{ + w.cycles+=19; + w.pc+=3; + Nxchg(w.A, w.R3, 16); + return; +} + +VOID o124(LPBYTE I) // AR4EX W +{ + w.cycles+=19; + w.pc+=3; + Nxchg(w.A, w.R4, 16); + return; +} + +VOID o128(LPBYTE I) // CR0EX W +{ + w.cycles+=19; + w.pc+=3; + Nxchg(w.C, w.R0, 16); + return; +} + +VOID o129(LPBYTE I) // CR1EX W +{ + w.cycles+=19; + w.pc+=3; + Nxchg(w.C, w.R1, 16); + return; +} + +VOID o12A(LPBYTE I) // CR2EX W +{ + w.cycles+=19; + w.pc+=3; + Nxchg(w.C, w.R2, 16); + return; +} + +VOID o12B(LPBYTE I) // CR3EX W +{ + w.cycles+=19; + w.pc+=3; + Nxchg(w.C, w.R3, 16); + return; +} + +VOID o12C(LPBYTE I) // CR4EX W +{ + w.cycles+=19; + w.pc+=3; + Nxchg(w.C, w.R4, 16); + return; +} + +VOID o130(LPBYTE I) // D0=A +{ + w.cycles+=8; + w.pc+=3; + w.d0=Npack(w.A,5); + return; +} + +VOID o131(LPBYTE I) // D1=A +{ + w.cycles+=8; + w.pc+=3; + w.d1=Npack(w.A,5); + return; +} + +VOID o132(LPBYTE I) // AD0EX +{ + DWORD d = w.d0; + w.d0=Npack(w.A,5); + Nunpack(w.A,d,5); + w.cycles+=8; + w.pc+=3; + return; +} + +VOID o133(LPBYTE I) // AD1EX +{ + DWORD d=w.d1; + w.d1=Npack(w.A,5); + Nunpack(w.A,d,5); + w.cycles+=8; + w.pc+=3; + return; +} + +VOID o134(LPBYTE I) // D0=C +{ + w.cycles+=8; + w.pc+=3; + w.d0=Npack(w.C,5); + return; +} + +VOID o135(LPBYTE I) // D1=C +{ + w.cycles+=8; + w.pc+=3; + w.d1=Npack(w.C,5); + return; +} + +VOID o136(LPBYTE I) // CD0EX +{ + DWORD d=w.d0; + w.d0=Npack(w.C,5); + Nunpack(w.C,d,5); + w.cycles+=8; + w.pc+=3; + return; +} + +VOID o137(LPBYTE I) // CD1EX +{ + DWORD d=w.d1; + w.d1=Npack(w.C,5); + Nunpack(w.C,d,5); + w.cycles+=8; + w.pc+=3; + return; +} + +VOID o138(LPBYTE I) // D0=AS +{ + w.cycles+=7; + w.pc+=3; + REG(WORD,w.d0)=(WORD)Npack(w.A,4); + return; +} + +VOID o139(LPBYTE I) // D1=AS +{ + w.cycles+=7; + w.pc+=3; + REG(WORD,w.d1)=(WORD)Npack(w.A,4); + return; +} + +VOID o13A(LPBYTE I) // AD0XS +{ + DWORD d=w.d0; + REG(WORD,w.d0)=(WORD)Npack(w.A,4); + Nunpack(w.A,d,4); + w.cycles+=7; + w.pc+=3; + return; +} + +VOID o13B(LPBYTE I) // AD1XS +{ + DWORD d=w.d1; + REG(WORD,w.d1)=(WORD)Npack(w.A,4); + Nunpack(w.A,d,4); + w.cycles+=7; + w.pc+=3; + return; +} + +VOID o13C(LPBYTE I) // D0=CS +{ + w.cycles+=7; + w.pc+=3; + REG(WORD,w.d0)=(WORD)Npack(w.C,4); + return; +} + +VOID o13D(LPBYTE I) // D1=CS +{ + w.cycles+=7; + w.pc+=3; + REG(WORD,w.d1)=(WORD)Npack(w.C,4); + return; +} + +VOID o13E(LPBYTE I) // CD0XS +{ + DWORD d=w.d0; + REG(WORD,w.d0)=(WORD)Npack(w.C,4); + Nunpack(w.C,d,4); + w.cycles+=7; + w.pc+=3; + return; +} + +VOID o13F(LPBYTE I) // CD1XS +{ + DWORD d=w.d1; + REG(WORD,w.d1)=(WORD)Npack(w.C,4); + Nunpack(w.C,d,4); + w.cycles+=7; + w.pc+=3; + return; +} + +VOID o140(LPBYTE I) { w.cycles+=17; w.pc+=3; Nwrite(w.A, w.d0, 5); return; } // DAT0=A A +VOID o141(LPBYTE I) { w.cycles+=17; w.pc+=3; Nwrite(w.A, w.d1, 5); return; } // DAT1=A A +VOID o144(LPBYTE I) { w.cycles+=17; w.pc+=3; Nwrite(w.C, w.d0, 5); return; } // DAT0=C A +VOID o145(LPBYTE I) { w.cycles+=17; w.pc+=3; Nwrite(w.C, w.d1, 5); return; } // DAT1=C A +VOID o148(LPBYTE I) { w.cycles+=14; w.pc+=3; Nwrite(w.A, w.d0, 2); return; } // DAT0=A B +VOID o149(LPBYTE I) { w.cycles+=14; w.pc+=3; Nwrite(w.A, w.d1, 2); return; } // DAT1=A B +VOID o14C(LPBYTE I) { w.cycles+=14; w.pc+=3; Nwrite(w.C, w.d0, 2); return; } // DAT0=C B +VOID o14D(LPBYTE I) { w.cycles+=14; w.pc+=3; Nwrite(w.C, w.d1, 2); return; } // DAT1=C B + +VOID o142(LPBYTE I) { w.cycles+=18; w.pc+=3; Nread(w.A, w.d0, 5); return; } // A=DAT0 A +VOID o143(LPBYTE I) { w.cycles+=18; w.pc+=3; Nread(w.A, w.d1, 5); return; } // A=DAT1 A +VOID o146(LPBYTE I) { w.cycles+=18; w.pc+=3; Nread(w.C, w.d0, 5); return; } // C=DAT0 A +VOID o147(LPBYTE I) { w.cycles+=18; w.pc+=3; Nread(w.C, w.d1, 5); return; } // C=DAT1 A +VOID o14A(LPBYTE I) { w.cycles+=15; w.pc+=3; Nread(w.A, w.d0, 2); return; } // A=DAT0 B +VOID o14B(LPBYTE I) { w.cycles+=15; w.pc+=3; Nread(w.A, w.d1, 2); return; } // A=DAT1 B +VOID o14E(LPBYTE I) { w.cycles+=15; w.pc+=3; Nread(w.C, w.d0, 2); return; } // C=DAT0 B +VOID o14F(LPBYTE I) { w.cycles+=15; w.pc+=3; Nread(w.C, w.d1, 2); return; } // C=DAT0 B + +VOID o150a(LPBYTE I) { w.cycles+=16+F_l[I[3]]; w.pc+=4; NFwrite(w.A, w.d0, I[3]); return; } // DAT0=A a +VOID o151a(LPBYTE I) { w.cycles+=16+F_l[I[3]]; w.pc+=4; NFwrite(w.A, w.d1, I[3]); return; } // DAT1=A a +VOID o154a(LPBYTE I) { w.cycles+=16+F_l[I[3]]; w.pc+=4; NFwrite(w.C, w.d0, I[3]); return; } // DAT0=C a +VOID o155a(LPBYTE I) { w.cycles+=16+F_l[I[3]]; w.pc+=4; NFwrite(w.C, w.d1, I[3]); return; } // DAT1=C a +VOID o152a(LPBYTE I) { w.cycles+=17+F_l[I[3]]; w.pc+=4; NFread(w.A, w.d0, I[3]); return; } // A=DAT0 a +VOID o153a(LPBYTE I) { w.cycles+=17+F_l[I[3]]; w.pc+=4; NFread(w.A, w.d1, I[3]); return; } // A=DAT1 a +VOID o156a(LPBYTE I) { w.cycles+=17+F_l[I[3]]; w.pc+=4; NFread(w.C, w.d0, I[3]); return; } // C=DAT0 a +VOID o157a(LPBYTE I) { w.cycles+=17+F_l[I[3]]; w.pc+=4; NFread(w.C, w.d1, I[3]); return; } // C=DAT1 a + +VOID o158x(LPBYTE I) { w.cycles+=16+I[3]+1; w.pc+=4; Nwrite(w.A, w.d0, I[3]+1); return; } // DAT0=A x +VOID o159x(LPBYTE I) { w.cycles+=16+I[3]+1; w.pc+=4; Nwrite(w.A, w.d1, I[3]+1); return; } // DAT1=A x +VOID o15Cx(LPBYTE I) { w.cycles+=16+I[3]+1; w.pc+=4; Nwrite(w.C, w.d0, I[3]+1); return; } // DAT0=C x +VOID o15Dx(LPBYTE I) { w.cycles+=16+I[3]+1; w.pc+=4; Nwrite(w.C, w.d1, I[3]+1); return; } // DAT1=C x +VOID o15Ax(LPBYTE I) { w.cycles+=17+I[3]+1; w.pc+=4; Nread(w.A, w.d0, I[3]+1); return; } // A=DAT0 x +VOID o15Bx(LPBYTE I) { w.cycles+=17+I[3]+1; w.pc+=4; Nread(w.A, w.d1, I[3]+1); return; } // A=DAT1 x +VOID o15Ex(LPBYTE I) { w.cycles+=17+I[3]+1; w.pc+=4; Nread(w.C, w.d0, I[3]+1); return; } // C=DAT0 x +VOID o15Fx(LPBYTE I) { w.cycles+=17+I[3]+1; w.pc+=4; Nread(w.C, w.d1, I[3]+1); return; } // C=DAT1 x + +VOID o16x(LPBYTE I) // D0=D0+ (n+1) +{ + w.cycles+=7; + w.pc+=3; + w.d0+=I[2]+1; + if (w.d0>0xfffff) + { + w.d0&=0xfffff; + w.carry=TRUE; + } + else + { + w.carry=FALSE; + } + return; +} + +VOID o17x(LPBYTE I) // D1=D1+ (n+1) +{ + w.cycles+=7; + w.pc+=3; + w.d1+=I[2]+1; + if (w.d1>0xfffff) + { + w.d1&=0xfffff; + w.carry=TRUE; + } + else + { + w.carry=FALSE; + } + return; +} + +VOID o18x(LPBYTE I) // D0=D0- (n+1) +{ + w.cycles+=7; + w.pc+=3; + w.d0-=I[2]+1; + if (w.d0>0xfffff) + { + w.d0&=0xfffff; + w.carry=TRUE; + } + else + { + w.carry=FALSE; + } + return; +} + +VOID o19d2(LPBYTE I) // D0=(2) #dd +{ + w.cycles+=4; + w.pc+=4; + REG(BYTE,w.d0)=(BYTE)Npack(I+2,2); + return; +} + +VOID o1Ad4(LPBYTE I) // D0=(4) #dddd +{ + w.cycles+=6; + w.pc+=6; + REG(WORD,w.d0)=(WORD)Npack(I+2,4); + return; +} + +VOID o1Bd5(LPBYTE I) // D0=(5) #ddddd +{ + w.cycles+=7; + w.pc+=7; + w.d0=Npack(I+2,5); + return; +} + +VOID o1Cx(LPBYTE I) // D1=D1- (n+1) +{ + w.cycles+=7; + w.pc+=3; + w.d1-=I[2]+1; + if (w.d1>0xfffff) + { + w.d1&=0xfffff; + w.carry=TRUE; + } + else + { + w.carry=FALSE; + } + return; +} + +VOID o1Dd2(LPBYTE I) // D1=(2) #dd +{ + w.cycles+=4; + w.pc+=4; + REG(BYTE,w.d1)=(BYTE)Npack(I+2,2); + return; +} + +VOID o1Ed4(LPBYTE I) // D1=(4) #dddd +{ + w.cycles+=6; + w.pc+=6; + REG(WORD,w.d1)=(WORD)Npack(I+2,4); + return; +} + +VOID o1Fd5(LPBYTE I) // D1=(5) #ddddd +{ + w.cycles+=7; + w.pc+=7; + w.d1=Npack(I+2,5); + return; +} + +VOID o2n(LPBYTE I) // P= n +{ + w.cycles+=2; + w.pc+=2; + w.P=I[1]; + PCHANGED; + return; +} + +VOID o3X(LPBYTE I) // LCHEX +{ + UINT n=I[1]+1; + UINT d=16-w.P; + w.cycles+=3+I[1]; + w.pc+=2; + I+=2; // UNSAFE + if (n<=d) + { + memcpy(w.C+w.P,I,n); + } + else + { + memcpy(w.C+w.P,I,d); + memcpy(w.C,I+d,n-d); + } + w.pc+=n; + return; +} + +VOID o4d2(LPBYTE I) // GOC #dd +{ + if (!w.carry) + { + w.cycles+=3; + w.pc+=3; + } + else + { + signed char jmp=I[1]+(I[2]<<4); + if (jmp) + w.pc+=jmp+1; + else + w.pc=rstkpop(); + w.cycles+=10; + w.pc&=0xFFFFF; + } + return; +} + +VOID o5d2(LPBYTE I) // GONC +{ + if (w.carry) + { + w.cycles+=3; + w.pc+=3; + } + else + { + signed char jmp=I[1]+(I[2]<<4); + if (jmp) + w.pc+=jmp+1; + else + w.pc=rstkpop(); + w.cycles+=10; + w.pc&=0xFFFFF; + } + return; +} + +VOID o6d3(LPBYTE I) // GOTO +{ + DWORD d=Npack(I+1,3); + if (d&0x800) + w.pc-=0xFFF-d; + else + w.pc+=d+1; + w.cycles+=11; + w.pc&=0xFFFFF; + return; +} + +VOID o7d3(LPBYTE I) // GOSUB +{ + DWORD d=Npack(I+1,3); + rstkpush(w.pc+4); + if (d&0x800) w.pc-=0xFFC-d; else w.pc+=d+4; + w.cycles+=12; + w.pc&=0xFFFFF; + return; +} + +VOID o800(LPBYTE I) // OUT=CS +{ + w.cycles+=4; + w.pc+=3; + w.out = (w.out&0xff0) | w.C[0]; + ScanKeyboard(FALSE,FALSE); // 1ms keyboard poll + return; +} + +VOID o801(LPBYTE I) // OUT=C +{ + WORD wOut; + w.cycles+=6; + w.pc+=3; + wOut = (WORD) Npack(w.C, 3); + if (((wOut ^ w.out) & 0x800) != 0) // beeper bit OR[11] changed + SoundOut(&w,wOut); + w.out = wOut; + ScanKeyboard(FALSE,FALSE); // 1ms keyboard poll + return; +} + +VOID o802(LPBYTE I) // A=IN +{ + w.cycles+=7; + // emulate Clarke/Yorke bug + if ((w.pc & 1) == 0 || MapData(w.pc) == M_IO) + w.pc+=3; + ScanKeyboard(TRUE,FALSE); // update Chipset.in register (direct) + IOBit(0x19,8,w.in != 0); // update KDN bit in the SRQ register + Nunpack(w.A, w.in, 4); + return; +} + +VOID o803(LPBYTE I) // C=IN +{ + w.cycles+=7; + // emulate Clarke/Yorke bug + if ((w.pc & 1) == 0 || MapData(w.pc) == M_IO) + w.pc+=3; + ScanKeyboard(TRUE,FALSE); // update Chipset.in register (direct) + IOBit(0x19,8,w.in != 0); // update KDN bit in the SRQ register + Nunpack(w.C, w.in, 4); + return; +} + +VOID o804(LPBYTE I) // UNCNFG +{ + w.cycles+=12; + w.pc+=3; + Uncnfg(); + return; +} + +VOID o805(LPBYTE I) // CONFIG +{ + w.cycles+=11; + w.pc+=3; + Config(); + return; +} + +VOID o806(LPBYTE I) // C=ID +{ + w.cycles+=11; + w.pc+=3; + C_Eq_Id(); + return; +} + +VOID o807(LPBYTE I) // SHUTDN +{ + BOOL bShutdn = TRUE; // shut down + + // only shut down when no timer wake up + if (w.IORam[TIMER1_CTRL]&WKE) // WKE bit of timer1 is set + { + if (ReadT1()&0x08) // and MSB of timer1 is set + { + w.IORam[TIMER1_CTRL] &= ~WKE; // clear WKE + bShutdn = FALSE; // don't shut down + } + } + if (w.IORam[TIMER2_CTRL]&WKE) // WKE bit of timer2 is set + { + if (ReadT2()&0x80000000) // and MSB of timer2 is set + { + w.IORam[TIMER2_CTRL] &= ~WKE; // clear WKE + bShutdn = FALSE; // don't shut down + } + } + ScanKeyboard(TRUE,FALSE); // update Chipset.in register (direct) + // out register going low during shutdown, so normal keys produce a rising + // edge trigger when out register going high again. Because the ON key is not + // connected to the out register, the rising edge trigger must be done manually. + if ((w.in & 0x7FFF) == 0 && bShutdn) // shut down only when enabled + { + w.Shutdn = TRUE; // set mode before exit emulation loop + bInterrupt = TRUE; + + // emulation of BS reset circuit in deep sleep + // HP39/40G, HP48GX, HP49G, display off, card control off or in slow mode + if ( (cCurrentRomType=='E' || cCurrentRomType=='G' || cCurrentRomType=='X') + && (w.IORam[BITOFFSET]&DON) == 0 + && ((w.IORam[CARDCTL]&(ECDT|RCDT)) != (ECDT|RCDT))) + { + // on HP48GX ROM must be selected (DA19=1) and + // the NOT MA18 address line must be low (test for high) + // else we get power on VCO from the ROM chip + // (MA18 input pin security diode to VCC pin) + if ( cCurrentRomType!='G' + || ((w.IORam[LINECOUNT+1]&DA19) && (w.pc & 0x80000))) + { + w.Bank_FF = 0; // reset bank switcher FF + RomSwitch(w.Bank_FF); // force new mapping + } + } + } + w.cycles+=6; + w.pc+=3; + return; +} + +VOID o8080(LPBYTE I) // INTON +{ + w.cycles+=5; + w.pc+=4; + w.intk = TRUE; + ScanKeyboard(FALSE,FALSE); // 1ms keyboard poll + if (w.intd || w.IR15X) // keyboard interrupt pending + { + w.intd = FALSE; // no keyboard interrupt pending any more + INTERRUPT; // restart interrupt handler + } + return; +} + +VOID o80810(LPBYTE I) // RSI +{ + w.cycles+=6; + w.pc+=5; + ScanKeyboard(TRUE,TRUE); // one input bit high (direct)? + + // enable KDN update + w.dwKdnCycles = (DWORD) (w.cycles & 0xFFFFFFFF) - (DWORD) T2CYCLES * 16; + + if (w.in && w.inte == FALSE) // key interrupt pending + w.intd = TRUE; // keyboard interrupt pending + return; +} + +VOID o8082X(LPBYTE I) // LA +{ + UINT n=I[4]+1; + UINT d=16-w.P; + w.cycles+=6+I[4]; + w.pc+=5+n; + I+=5; // UNSAFE + if (n<=d) + { + memcpy(w.A+w.P,I,n); + } + else + { + memcpy(w.A+w.P,I,d); + memcpy(w.A,I+d,n-d); + } + return; +} + +VOID o8083(LPBYTE I) // BUSCB +{ + w.cycles+=7; + w.pc+=4; + // emulated as NOP + // InfoMessage(_T("BUSCB instruction executed.")); + return; +} + +VOID o8084n(LPBYTE I) // ABIT=0 n +{ + w.cycles+=6; + w.pc+=5; + Nbit0(w.A, I[4]); + return; +} + +VOID o8085n(LPBYTE I) // ABIT=1 n +{ + w.cycles+=6; + w.pc+=5; + Nbit1(w.A, I[4]); + return; +} + +VOID o8086n(LPBYTE I) // ?ABIT=0 n +{ + w.cycles+=9; + w.pc+=5; + Tbit0(w.A, I[4]); + GOYES5; +} + +VOID o8087n(LPBYTE I) // ?ABIT=1 n +{ + w.cycles+=9; + w.pc+=5; + Tbit1(w.A, I[4]); + GOYES5; +} + +VOID o8088n(LPBYTE I) // CBIT=0 n +{ + w.cycles+=6; + w.pc+=5; + Nbit0(w.C, I[4]); + return; +} + +VOID o8089n(LPBYTE I) // CBIT=1 n +{ + w.cycles+=6; + w.pc+=5; + Nbit1(w.C, I[4]); + return; +} + +VOID o808An(LPBYTE I) // ?CBIT=0 n +{ + w.cycles+=9; + w.pc+=5; + Tbit0(w.C, I[4]); + GOYES5; +} + +VOID o808Bn(LPBYTE I) // ?CBIT=1 n +{ + w.cycles+=9; + w.pc+=5; + Tbit1(w.C, I[4]); + GOYES5; +} + +VOID o808C(LPBYTE I) // PC=(A) +{ + BYTE p[5]; + w.cycles+=23; + Nread(p,Npack(w.A,5),5); // read (A) and update CRC + w.pc=Npack(p,5); + return; +} + +VOID o808D(LPBYTE I) // BUSCD +{ + w.cycles+=7; + w.pc+=4; + // emulated as NOP + // InfoMessage(_T("BUSCD instruction executed.")); + return; +} + +VOID o808E(LPBYTE I) // PC=(C) +{ + BYTE p[5]; + w.cycles+=23; + Nread(p,Npack(w.C,5),5); // read (C) and update CRC + w.pc=Npack(p,5); + return; +} + +VOID o808F(LPBYTE I) // INTOFF +{ + w.cycles+=5; + w.pc+=4; + UpdateKdnBit(); // update KDN bit + w.intk = FALSE; + return; +} + +VOID o809(LPBYTE I) // C+P+1 - HEX MODE +{ + w.cycles+=8; + w.pc+=3; + w.C[0]+=w.P; Nincx(w.C,5); + return; +} + +VOID o80A(LPBYTE I) // RESET +{ + w.cycles+=6; + w.pc+=3; + Reset(); + return; +} + +VOID o80B(LPBYTE I) // BUSCC +{ + w.cycles+=6; + w.pc+=3; + // emulated as NOP + // InfoMessage(_T("BUSCC instruction executed.")); + return; +} + +VOID o80Cn(LPBYTE I) // C=P n +{ + w.cycles+=6; + w.pc+=4; + w.C[I[3]] = w.P; + return; +} + +VOID o80Dn(LPBYTE I) // P=C n +{ + w.cycles+=6; + w.pc+=4; + w.P = w.C[I[3]]; + PCHANGED; + return; +} + +VOID o80E(LPBYTE I) // SREQ? +{ + w.cycles+=7; + w.pc+=3; + w.C[0]=0; // no device + return; +} + +VOID o80Fn(LPBYTE I) // CPEX n +{ + BYTE n = w.P; + w.P = w.C[I[3]]; + w.C[I[3]] = n; + PCHANGED; + w.cycles+=6; + w.pc+=4; + return; +} + +VOID o810(LPBYTE I) // ASLC +{ + w.cycles+=21; + w.pc+=3; + Nslc(w.A, 16); + return; +} + +VOID o811(LPBYTE I) // BSLC +{ + w.cycles+=21; + w.pc+=3; + Nslc(w.B, 16); + return; +} + +VOID o812(LPBYTE I) // CSLC +{ + w.cycles+=21; + w.pc+=3; + Nslc(w.C, 16); + return; +} + +VOID o813(LPBYTE I) // DSLC +{ + w.cycles+=21; + w.pc+=3; + Nslc(w.D, 16); + return; +} + +VOID o814(LPBYTE I) // ASRC +{ + w.cycles+=21; + w.pc+=3; + Nsrc(w.A, 16); + return; +} + +VOID o815(LPBYTE I) // BSRC +{ + w.cycles+=21; + w.pc+=3; + Nsrc(w.B, 16); + return; +} + +VOID o816(LPBYTE I) // CSRC +{ + w.cycles+=21; + w.pc+=3; + Nsrc(w.C, 16); + return; +} + +VOID o817(LPBYTE I) // DSRC +{ + w.cycles+=21; + w.pc+=3; + Nsrc(w.D, 16); + return; +} + +VOID o818f0x(LPBYTE I) // A=A+x+1 f +{ + // register length with saturn bug emulation + UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; + + w.cycles+=5+F_l[I[3]]; + w.pc+=6; + w.A[F_s[I[3]]]+=I[5]; // add constant value-1 + Ninc16(w.A,nF_l,F_s[I[3]]); // add one and adjust in HEX mode + return; +} + +VOID o818f1x(LPBYTE I) // B=B+x+1 f +{ + // register length with saturn bug emulation + UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; + + w.cycles+=5+F_l[I[3]]; + w.pc+=6; + w.B[F_s[I[3]]]+=I[5]; // add constant value-1 + Ninc16(w.B,nF_l,F_s[I[3]]); // add one and adjust in HEX mode + return; +} + +VOID o818f2x(LPBYTE I) // C=C+x+1 f +{ + // register length with saturn bug emulation + UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; + + w.cycles+=5+F_l[I[3]]; + w.pc+=6; + w.C[F_s[I[3]]]+=I[5]; // add constant value-1 + Ninc16(w.C,nF_l,F_s[I[3]]); // add one and adjust in HEX mode + return; +} + +VOID o818f3x(LPBYTE I) // D=D+x+1 f +{ + // register length with saturn bug emulation + UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; + + w.cycles+=5+F_l[I[3]]; + w.pc+=6; + w.D[F_s[I[3]]]+=I[5]; // add constant value-1 + Ninc16(w.D,nF_l,F_s[I[3]]); // add one and adjust in HEX mode + return; +} + +VOID o818f8x(LPBYTE I) // A=A-x-1 f +{ + // register length with saturn bug emulation + UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; + + w.cycles+=5+F_l[I[3]]; + w.pc+=6; + w.A[F_s[I[3]]]-=I[5]; // sub constant value+1 + Ndec16(w.A,nF_l,F_s[I[3]]); // dec one and adjust in HEX mode + return; +} + +VOID o818f9x(LPBYTE I) // B=B-x-1 f +{ + // register length with saturn bug emulation + UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; + + w.cycles+=5+F_l[I[3]]; + w.pc+=6; + w.B[F_s[I[3]]]-=I[5]; // sub constant value+1 + Ndec16(w.B,nF_l,F_s[I[3]]); // dec one and adjust in HEX mode + return; +} + +VOID o818fAx(LPBYTE I) // C=C-x-1 f +{ + // register length with saturn bug emulation + UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; + + w.cycles+=5+F_l[I[3]]; + w.pc+=6; + w.C[F_s[I[3]]]-=I[5]; // sub constant value+1 + Ndec16(w.C,nF_l,F_s[I[3]]); // dec one and adjust in HEX mode + return; +} + +VOID o818fBx(LPBYTE I) // D=D-x-1 f +{ + // register length with saturn bug emulation + UINT nF_l = (F_l[I[3]] == 1) ? 0x11 : F_l[I[3]]; + + w.cycles+=5+F_l[I[3]]; + w.pc+=6; + w.D[F_s[I[3]]]-=I[5]; // sub constant value+1 + Ndec16(w.D,nF_l,F_s[I[3]]); // dec one and adjust in HEX mode + return; +} + +VOID o819f0(LPBYTE I) // ASRB.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=5; + NFsrb(w.A, I[3]); + return; +} + +VOID o819f1(LPBYTE I) // BSRB.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=5; + NFsrb(w.B, I[3]); + return; +} + +VOID o819f2(LPBYTE I) // CSRB.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=5; + NFsrb(w.C, I[3]); + return; +} + +VOID o819f3(LPBYTE I) // DSRB.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=5; + NFsrb(w.D, I[3]); + return; +} + +VOID o81Af00(LPBYTE I) // R0=A.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.R0, w.A, I[3]); + return; +} + +VOID o81Af01(LPBYTE I) // R1=A.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.R1, w.A, I[3]); + return; +} + +VOID o81Af02(LPBYTE I) // R2=A.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.R2, w.A, I[3]); + return; +} + +VOID o81Af03(LPBYTE I) // R3=A.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.R3, w.A, I[3]); + return; +} + +VOID o81Af04(LPBYTE I) // R4=A.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.R4, w.A, I[3]); + return; +} + +VOID o81Af08(LPBYTE I) // R0=C.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.R0, w.C, I[3]); + return; +} + +VOID o81Af09(LPBYTE I) // R1=C.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.R1, w.C, I[3]); + return; +} + +VOID o81Af0A(LPBYTE I) // R2=C.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.R2, w.C, I[3]); + return; +} + +VOID o81Af0B(LPBYTE I) // R3=C.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.R3, w.C, I[3]); + return; +} + +VOID o81Af0C(LPBYTE I) // R4=C.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.R4, w.C, I[3]); + return; +} + +VOID o81Af10(LPBYTE I) // A=R0.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.A, w.R0, I[3]); + return; +} + +VOID o81Af11(LPBYTE I) // A=R1.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.A, w.R1, I[3]); + return; +} + +VOID o81Af12(LPBYTE I) // A=R2.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.A, w.R2, I[3]); + return; +} + +VOID o81Af13(LPBYTE I) // A=R3.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.A, w.R3, I[3]); + return; +} + +VOID o81Af14(LPBYTE I) // A=R4.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.A, w.R4, I[3]); + return; +} + +VOID o81Af18(LPBYTE I) // C=R0.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.C, w.R0, I[3]); + return; +} + +VOID o81Af19(LPBYTE I) // C=R1.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.C, w.R1, I[3]); + return; +} + +VOID o81Af1A(LPBYTE I) // C=R2.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.C, w.R2, I[3]); + return; +} + +VOID o81Af1B(LPBYTE I) // C=R3.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.C, w.R3, I[3]); + return; +} + +VOID o81Af1C(LPBYTE I) // C=R4.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFcopy(w.C, w.R4, I[3]); + return; +} + +VOID o81Af20(LPBYTE I) // AR0EX.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFxchg(w.A, w.R0, I[3]); + return; +} + +VOID o81Af21(LPBYTE I) // AR1EX.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFxchg(w.A, w.R1, I[3]); + return; +} + +VOID o81Af22(LPBYTE I) // AR2EX.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFxchg(w.A, w.R2, I[3]); + return; +} + +VOID o81Af23(LPBYTE I) // AR3EX.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFxchg(w.A, w.R3, I[3]); + return; +} + +VOID o81Af24(LPBYTE I) // AR4EX.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFxchg(w.A, w.R4, I[3]); + return; +} + +VOID o81Af28(LPBYTE I) // CR0EX.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFxchg(w.C, w.R0, I[3]); + return; +} + +VOID o81Af29(LPBYTE I) // CR1EX.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFxchg(w.C, w.R1, I[3]); + return; +} + +VOID o81Af2A(LPBYTE I) // CR2EX.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFxchg(w.C, w.R2, I[3]); + return; +} + +VOID o81Af2B(LPBYTE I) // CR3EX.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFxchg(w.C, w.R3, I[3]); + return; +} + +VOID o81Af2C(LPBYTE I) // CR4EX.F f +{ + w.cycles+=6+F_l[I[3]]; + w.pc+=6; + NFxchg(w.C, w.R4, I[3]); + return; +} + +VOID o81B2(LPBYTE I) // PC=A +{ + w.cycles+=16; + w.pc = Npack(w.A,5); + return; +} + +VOID o81B3(LPBYTE I) // PC=C +{ + w.cycles+=16; + w.pc = Npack(w.C,5); + return; +} + +VOID o81B4(LPBYTE I) // A=PC +{ + w.cycles+=9; + w.pc+=4; + Nunpack(w.A,w.pc,5); + return; +} + +VOID o81B5(LPBYTE I) // C=PC +{ + w.cycles+=9; + w.pc+=4; + Nunpack(w.C,w.pc,5); + return; +} + +VOID o81B6(LPBYTE I) // APCEX +{ + DWORD d=w.pc+4; + w.cycles+=16; + w.pc=Npack(w.A,5); + Nunpack(w.A,d,5); + return; +} + +VOID o81B7(LPBYTE I) // CPCEX +{ + DWORD d=w.pc+4; + w.cycles+=16; + w.pc=Npack(w.C,5); + Nunpack(w.C,d,5); + return; +} + +VOID o81C(LPBYTE I) // ASRB +{ + w.cycles+=20; + w.pc+=3; + Nsrb(w.A, 16); + return; +} + +VOID o81D(LPBYTE I) // BSRB +{ + w.cycles+=20; + w.pc+=3; + Nsrb(w.B, 16); + return; +} + +VOID o81E(LPBYTE I) // CSRB +{ + w.cycles+=20; + w.pc+=3; + Nsrb(w.C, 16); + return; +} + +VOID o81F(LPBYTE I) // DSRB +{ + w.cycles+=20; + w.pc+=3; + Nsrb(w.D, 16); + return; +} + +VOID o82n(LPBYTE I) // HST=0 m +{ + w.cycles+=3; + w.pc+=3; + w.HST&=~I[2]; + return; +} + +VOID o83n(LPBYTE I) // ?HST=0 m +{ + w.cycles+=6; + w.pc+=3; + w.carry=((w.HST&I[2])==0); + GOYES3; +} + +VOID o84n(LPBYTE I) // ST=0 n +{ + w.cycles+=4; + w.pc+=3; + Nbit0(w.ST, I[2]); + return; +} + +VOID o85n(LPBYTE I) // ST=1 n +{ + w.cycles+=4; + w.pc+=3; + Nbit1(w.ST, I[2]); + return; +} + +VOID o86n(LPBYTE I) // ?ST=0 n +{ + w.cycles+=7; + w.pc+=3; + Tbit0(w.ST, I[2]); + GOYES3; +} + +VOID o87n(LPBYTE I) // ?ST=1 n +{ + w.cycles+=7; + w.pc+=3; + Tbit1(w.ST, I[2]); + GOYES3; +} + +VOID o88n(LPBYTE I) // ?P# n +{ + w.cycles+=6; + w.pc+=3; + w.carry=(w.P!=I[2]); + GOYES3; +} + +VOID o89n(LPBYTE I) // ?P= n +{ + w.cycles+=6; + w.pc+=3; + w.carry=(w.P==I[2]); + GOYES3; +} + +VOID o8A0(LPBYTE I) // ?A=B A +{ + w.cycles+=11; + w.pc+=3; + Te(w.A, w.B, 5); + GOYES3; +} + +VOID o8A1(LPBYTE I) // ?B=C A +{ + w.cycles+=11; + w.pc+=3; + Te(w.B, w.C, 5); + GOYES3; +} + +VOID o8A2(LPBYTE I) // ?C=A A +{ + w.cycles+=11; + w.pc+=3; + Te(w.C, w.A, 5); + GOYES3; +} + +VOID o8A3(LPBYTE I) // ?D=C A +{ + w.cycles+=11; + w.pc+=3; + Te(w.D, w.C, 5); + GOYES3; +} + +VOID o8A4(LPBYTE I) // ?A#B A +{ + w.cycles+=11; + w.pc+=3; + Tne(w.A, w.B, 5); + GOYES3; +} + +VOID o8A5(LPBYTE I) // ?B#C A +{ + w.cycles+=11; + w.pc+=3; + Tne(w.B, w.C, 5); + GOYES3; +} + +VOID o8A6(LPBYTE I) // ?C#A A +{ + w.cycles+=11; + w.pc+=3; + Tne(w.C, w.A, 5); + GOYES3; +} + +VOID o8A7(LPBYTE I) // ?D#C A +{ + w.cycles+=11; + w.pc+=3; + Tne(w.D, w.C, 5); + GOYES3; +} + +VOID o8A8(LPBYTE I) // ?A=0 A +{ + w.cycles+=11; + w.pc+=3; + Tz(w.A, 5); + GOYES3; +} + +VOID o8A9(LPBYTE I) // ?B=0 A +{ + w.cycles+=11; + w.pc+=3; + Tz(w.B, 5); + GOYES3; +} + +VOID o8AA(LPBYTE I) // ?C=0 A +{ + w.cycles+=11; + w.pc+=3; + Tz(w.C, 5); + GOYES3; +} + +VOID o8AB(LPBYTE I) // ?D=0 A +{ + w.cycles+=11; + w.pc+=3; + Tz(w.D, 5); + GOYES3; +} + +VOID o8AC(LPBYTE I) // ?A#0 A +{ + w.cycles+=11; + w.pc+=3; + Tnz(w.A, 5); + GOYES3; +} + +VOID o8AD(LPBYTE I) // ?B#0 A +{ + w.cycles+=11; + w.pc+=3; + Tnz(w.B, 5); + GOYES3; +} + +VOID o8AE(LPBYTE I) // ?C#0 A +{ + w.cycles+=11; + w.pc+=3; + Tnz(w.C, 5); + GOYES3; +} + +VOID o8AF(LPBYTE I) // ?D#0 A +{ + w.cycles+=11; + w.pc+=3; + Tnz(w.D, 5); + GOYES3; +} + +VOID o8B0(LPBYTE I) // ?A>B A +{ + w.cycles+=11; + w.pc+=3; + Ta(w.A, w.B, 5); + GOYES3; +} + +VOID o8B1(LPBYTE I) // ?B>C A +{ + w.cycles+=11; + w.pc+=3; + Ta(w.B, w.C, 5); + GOYES3; +} + +VOID o8B2(LPBYTE I) // ?C>A A +{ + w.cycles+=11; + w.pc+=3; + Ta(w.C, w.A, 5); + GOYES3; +} + +VOID o8B3(LPBYTE I) // ?D>C A +{ + w.cycles+=11; + w.pc+=3; + Ta(w.D, w.C, 5); + GOYES3; +} + +VOID o8B4(LPBYTE I) // ?A=B A +{ + w.cycles+=11; + w.pc+=3; + Tae(w.A, w.B, 5); + GOYES3; +} + +VOID o8B9(LPBYTE I) // ?B>=C A +{ + w.cycles+=11; + w.pc+=3; + Tae(w.B, w.C, 5); + GOYES3; +} + +VOID o8BA(LPBYTE I) // ?C>=A A +{ + w.cycles+=11; + w.pc+=3; + Tae(w.C, w.A, 5); + GOYES3; +} + +VOID o8BB(LPBYTE I) // ?D>=C A +{ + w.cycles+=11; + w.pc+=3; + Tae(w.D, w.C, 5); + GOYES3; +} + +VOID o8BC(LPBYTE I) // ?A<=B A +{ + w.cycles+=11; + w.pc+=3; + Tbe(w.A, w.B, 5); + GOYES3; +} + +VOID o8BD(LPBYTE I) // ?B<=C A +{ + w.cycles+=11; + w.pc+=3; + Tbe(w.B, w.C, 5); + GOYES3; +} + +VOID o8BE(LPBYTE I) // ?C<=A A +{ + w.cycles+=11; + w.pc+=3; + Tbe(w.C, w.A, 5); + GOYES3; +} + +VOID o8BF(LPBYTE I) // ?D<=C A +{ + w.cycles+=11; + w.pc+=3; + Tbe(w.D, w.C, 5); + GOYES3; +} + +VOID o8Cd4(LPBYTE I) // GOLONG #dddd +{ + DWORD d=Npack(I+2, 4); + if (d&0x8000) w.pc -= 0xfffe - d; else w.pc+= d + 2; + w.cycles+=14; + w.pc&=0xFFFFF; + return; +} + +VOID o8Dd5(LPBYTE I) // GOVLNG #ddddd +{ + w.cycles+=14; + w.pc = Npack(I+2, 5); + return; +} + +VOID o8Ed4(LPBYTE I) // GOSUBL #dddd +{ + DWORD d=Npack(I+2,4); + rstkpush(w.pc+6); + if (d&0x8000) w.pc -= 0xfffa - d; else w.pc += d + 6; + w.cycles+=14; + w.pc&=0xFFFFF; + return; +} + +VOID o8Fd5(LPBYTE I) // GOSBVL #ddddd +{ + w.cycles+=15; + rstkpush(w.pc+7); + w.pc=Npack(I+2, 5); + return; +} + + // ?r=s f +VOID o9a0(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFe(w.A, w.B, I[1]); GOYES3; } +VOID o9a1(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFe(w.B, w.C, I[1]); GOYES3; } +VOID o9a2(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFe(w.C, w.A, I[1]); GOYES3; } +VOID o9a3(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFe(w.D, w.C, I[1]); GOYES3; } + + // ?r#s f +VOID o9a4(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFne(w.A, w.B, I[1]); GOYES3; } +VOID o9a5(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFne(w.B, w.C, I[1]); GOYES3; } +VOID o9a6(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFne(w.C, w.A, I[1]); GOYES3; } +VOID o9a7(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFne(w.D, w.C, I[1]); GOYES3; } + + // ?r=0 f +VOID o9a8(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFz(w.A, I[1]); GOYES3; } +VOID o9a9(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFz(w.B, I[1]); GOYES3; } +VOID o9aA(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFz(w.C, I[1]); GOYES3; } +VOID o9aB(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFz(w.D, I[1]); GOYES3; } + + // ?r#0 f +VOID o9aC(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFnz(w.A, I[1]); GOYES3; } +VOID o9aD(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFnz(w.B, I[1]); GOYES3; } +VOID o9aE(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFnz(w.C, I[1]); GOYES3; } +VOID o9aF(LPBYTE I) { w.cycles+=6+F_l[I[1]]; w.pc+=3; TFnz(w.D, I[1]); GOYES3; } + + // ?s>r f +VOID o9b0(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFa(w.A, w.B, I[1]&7); GOYES3; } +VOID o9b1(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFa(w.B, w.C, I[1]&7); GOYES3; } +VOID o9b2(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFa(w.C, w.A, I[1]&7); GOYES3; } +VOID o9b3(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFa(w.D, w.C, I[1]&7); GOYES3; } + + // ?r=s f +VOID o9b8(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFae(w.A, w.B, I[1]&7); GOYES3; } +VOID o9b9(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFae(w.B, w.C, I[1]&7); GOYES3; } +VOID o9bA(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFae(w.C, w.A, I[1]&7); GOYES3; } +VOID o9bB(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFae(w.D, w.C, I[1]&7); GOYES3; } + + // ?r<=s f +VOID o9bC(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFbe(w.A, w.B, I[1]&7); GOYES3; } +VOID o9bD(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFbe(w.B, w.C, I[1]&7); GOYES3; } +VOID o9bE(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFbe(w.C, w.A, I[1]&7); GOYES3; } +VOID o9bF(LPBYTE I) { w.cycles+=6+F_l[I[1]&7]; w.pc+=3; TFbe(w.D, w.C, I[1]&7); GOYES3; } + + // r=r+s f +VOID oAa0(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.A, w.B, I[1]); return; } +VOID oAa1(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.B, w.C, I[1]); return; } +VOID oAa2(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.C, w.A, I[1]); return; } +VOID oAa3(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.D, w.C, I[1]); return; } + + // r=r+r f +VOID oAa4(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.A, w.A, I[1]); return; } +VOID oAa5(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.B, w.B, I[1]); return; } +VOID oAa6(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.C, w.C, I[1]); return; } +VOID oAa7(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.D, w.D, I[1]); return; } + + // s=s+r f +VOID oAa8(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.B, w.A, I[1]); return; } +VOID oAa9(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.C, w.B, I[1]); return; } +VOID oAaA(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.A, w.C, I[1]); return; } +VOID oAaB(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFadd(w.C, w.D, I[1]); return; } + + // r=r-1 f +VOID oAaC(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFdec(w.A, I[1]); return; } +VOID oAaD(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFdec(w.B, I[1]); return; } +VOID oAaE(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFdec(w.C, I[1]); return; } +VOID oAaF(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFdec(w.D, I[1]); return; } + + // r=0 f +VOID oAb0(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFzero(w.A, I[1]&7); return; } +VOID oAb1(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFzero(w.B, I[1]&7); return; } +VOID oAb2(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFzero(w.C, I[1]&7); return; } +VOID oAb3(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFzero(w.D, I[1]&7); return; } + + // r=s f +VOID oAb4(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.A, w.B, I[1]&7); return; } +VOID oAb5(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.B, w.C, I[1]&7); return; } +VOID oAb6(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.C, w.A, I[1]&7); return; } +VOID oAb7(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.D, w.C, I[1]&7); return; } + + // s=r f +VOID oAb8(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.B, w.A, I[1]&7); return; } +VOID oAb9(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.C, w.B, I[1]&7); return; } +VOID oAbA(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.A, w.C, I[1]&7); return; } +VOID oAbB(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFcopy(w.C, w.D, I[1]&7); return; } + + // rsEX f +VOID oAbC(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFxchg(w.A, w.B, I[1]&7); return; } +VOID oAbD(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFxchg(w.B, w.C, I[1]&7); return; } +VOID oAbE(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFxchg(w.C, w.A, I[1]&7); return; } +VOID oAbF(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFxchg(w.D, w.C, I[1]&7); return; } + + // r=r-s f +VOID oBa0(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.A, w.B, I[1]); return; } +VOID oBa1(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.B, w.C, I[1]); return; } +VOID oBa2(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.C, w.A, I[1]); return; } +VOID oBa3(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.D, w.C, I[1]); return; } + + // r=r+1 f +VOID oBa4(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFinc(w.A, I[1]); return; } +VOID oBa5(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFinc(w.B, I[1]); return; } +VOID oBa6(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFinc(w.C, I[1]); return; } +VOID oBa7(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFinc(w.D, I[1]); return; } + + // s=s-r f +VOID oBa8(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.B, w.A, I[1]); return; } +VOID oBa9(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.C, w.B, I[1]); return; } +VOID oBaA(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.A, w.C, I[1]); return; } +VOID oBaB(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFsub(w.C, w.D, I[1]); return; } + + // r=s-r f +VOID oBaC(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFrsub(w.A, w.B, I[1]); return; } +VOID oBaD(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFrsub(w.B, w.C, I[1]); return; } +VOID oBaE(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFrsub(w.C, w.A, I[1]); return; } +VOID oBaF(LPBYTE I) { w.cycles+=3+F_l[I[1]]; w.pc+=3; NFrsub(w.D, w.C, I[1]); return; } + + // rSL f +VOID oBb0(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsl(w.A, I[1]&7); return; } +VOID oBb1(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsl(w.B, I[1]&7); return; } +VOID oBb2(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsl(w.C, I[1]&7); return; } +VOID oBb3(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsl(w.D, I[1]&7); return; } + + // rSR f +VOID oBb4(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsr(w.A, I[1]&7); return; } +VOID oBb5(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsr(w.B, I[1]&7); return; } +VOID oBb6(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsr(w.C, I[1]&7); return; } +VOID oBb7(LPBYTE I) { w.cycles+=4+F_l[I[1]&7]; w.pc+=3; NFsr(w.D, I[1]&7); return; } + + // r=-r f +VOID oBb8(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFneg(w.A, I[1]&7); return; } +VOID oBb9(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFneg(w.B, I[1]&7); return; } +VOID oBbA(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFneg(w.C, I[1]&7); return; } +VOID oBbB(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFneg(w.D, I[1]&7); return; } + + // r=-r-1 f +VOID oBbC(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFnot(w.A, I[1]&7); return; } +VOID oBbD(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFnot(w.B, I[1]&7); return; } +VOID oBbE(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFnot(w.C, I[1]&7); return; } +VOID oBbF(LPBYTE I) { w.cycles+=3+F_l[I[1]&7]; w.pc+=3; NFnot(w.D, I[1]&7); return; } + + // r=r+s A +VOID oC0(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.A, w.B, 5); return; } +VOID oC1(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.B, w.C, 5); return; } +VOID oC2(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.C, w.A, 5); return; } +VOID oC3(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.D, w.C, 5); return; } + + // r=r+r A +VOID oC4(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.A, w.A, 5); return; } +VOID oC5(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.B, w.B, 5); return; } +VOID oC6(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.C, w.C, 5); return; } +VOID oC7(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.D, w.D, 5); return; } + + // s=s+r A +VOID oC8(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.B, w.A, 5); return; } +VOID oC9(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.C, w.B, 5); return; } +VOID oCA(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.A, w.C, 5); return; } +VOID oCB(LPBYTE I) { w.cycles+=7; w.pc+=2; Nadd(w.C, w.D, 5); return; } + + // r=r-1 A +VOID oCC(LPBYTE I) { w.cycles+=7; w.pc+=2; Ndec(w.A, 5, 0); return; } +VOID oCD(LPBYTE I) { w.cycles+=7; w.pc+=2; Ndec(w.B, 5, 0); return; } +VOID oCE(LPBYTE I) { w.cycles+=7; w.pc+=2; Ndec(w.C, 5, 0); return; } +VOID oCF(LPBYTE I) { w.cycles+=7; w.pc+=2; Ndec(w.D, 5, 0); return; } + + // r=0 A +VOID oD0(LPBYTE I) { w.cycles+=7; w.pc+=2; memset(w.A, 0, 5); return; } +VOID oD1(LPBYTE I) { w.cycles+=7; w.pc+=2; memset(w.B, 0, 5); return; } +VOID oD2(LPBYTE I) { w.cycles+=7; w.pc+=2; memset(w.C, 0, 5); return; } +VOID oD3(LPBYTE I) { w.cycles+=7; w.pc+=2; memset(w.D, 0, 5); return; } + + // r=s A +VOID oD4(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.A, w.B, 5); return; } +VOID oD5(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.B, w.C, 5); return; } +VOID oD6(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.C, w.A, 5); return; } +VOID oD7(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.D, w.C, 5); return; } + + // s=r A +VOID oD8(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.B, w.A, 5); return; } +VOID oD9(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.C, w.B, 5); return; } +VOID oDA(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.A, w.C, 5); return; } +VOID oDB(LPBYTE I) { w.cycles+=7; w.pc+=2; memcpy(w.C, w.D, 5); return; } + + // rsEX +VOID oDC(LPBYTE I) { w.cycles+=7; w.pc+=2; Nxchg(w.A, w.B, 5); return; } +VOID oDD(LPBYTE I) { w.cycles+=7; w.pc+=2; Nxchg(w.B, w.C, 5); return; } +VOID oDE(LPBYTE I) { w.cycles+=7; w.pc+=2; Nxchg(w.C, w.A, 5); return; } +VOID oDF(LPBYTE I) { w.cycles+=7; w.pc+=2; Nxchg(w.D, w.C, 5); return; } + + // r=r-s A +VOID oE0(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.A, w.B, 5); return; } +VOID oE1(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.B, w.C, 5); return; } +VOID oE2(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.C, w.A, 5); return; } +VOID oE3(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.D, w.C, 5); return; } + + // r=r+1 A +VOID oE4(LPBYTE I) { w.cycles+=7; w.pc+=2; Ninc(w.A, 5, 0); return; } +VOID oE5(LPBYTE I) { w.cycles+=7; w.pc+=2; Ninc(w.B, 5, 0); return; } +VOID oE6(LPBYTE I) { w.cycles+=7; w.pc+=2; Ninc(w.C, 5, 0); return; } +VOID oE7(LPBYTE I) { w.cycles+=7; w.pc+=2; Ninc(w.D, 5, 0); return; } + + // s=s-r A +VOID oE8(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.B, w.A, 5); return; } +VOID oE9(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.C, w.B, 5); return; } +VOID oEA(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.A, w.C, 5); return; } +VOID oEB(LPBYTE I) { w.cycles+=7; w.pc+=2; Nsub(w.C, w.D, 5); return; } + + // r=s-r A +VOID oEC(LPBYTE I) { w.cycles+=7; w.pc+=2; Nrsub(w.A, w.B, 5); return; } +VOID oED(LPBYTE I) { w.cycles+=7; w.pc+=2; Nrsub(w.B, w.C, 5); return; } +VOID oEE(LPBYTE I) { w.cycles+=7; w.pc+=2; Nrsub(w.C, w.A, 5); return; } +VOID oEF(LPBYTE I) { w.cycles+=7; w.pc+=2; Nrsub(w.D, w.C, 5); return; } + + // rSL A +VOID oF0(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsl(w.A, 5); return; } +VOID oF1(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsl(w.B, 5); return; } +VOID oF2(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsl(w.C, 5); return; } +VOID oF3(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsl(w.D, 5); return; } + + // rSR A +VOID oF4(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsr(w.A, 5); return; } +VOID oF5(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsr(w.B, 5); return; } +VOID oF6(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsr(w.C, 5); return; } +VOID oF7(LPBYTE I) { w.cycles+=8; w.pc+=2; Nsr(w.D, 5); return; } + + // r=-r A +VOID oF8(LPBYTE I) { w.cycles+=7; w.pc+=2; Nneg(w.A, 5); return; } +VOID oF9(LPBYTE I) { w.cycles+=7; w.pc+=2; Nneg(w.B, 5); return; } +VOID oFA(LPBYTE I) { w.cycles+=7; w.pc+=2; Nneg(w.C, 5); return; } +VOID oFB(LPBYTE I) { w.cycles+=7; w.pc+=2; Nneg(w.D, 5); return; } + + // r=-r-1 A +VOID oFC(LPBYTE I) { w.cycles+=7; w.pc+=2; Nnot(w.A, 5); return; } +VOID oFD(LPBYTE I) { w.cycles+=7; w.pc+=2; Nnot(w.B, 5); return; } +VOID oFE(LPBYTE I) { w.cycles+=7; w.pc+=2; Nnot(w.C, 5); return; } +VOID oFF(LPBYTE I) { w.cycles+=7; w.pc+=2; Nnot(w.D, 5); return; } + +// length is guessed, just skip +VOID o_invalid3(LPBYTE I) +{ + _ASSERT(FALSE); // invalid, length guessed, skip 3 nibbles + w.pc+=3; + return; +} + +VOID o_invalid4(LPBYTE I) +{ + _ASSERT(FALSE); // invalid, length guessed, skip 4 nibbles + w.pc+=4; + return; +} + +VOID o_invalid5(LPBYTE I) +{ + _ASSERT(FALSE); // invalid, length guessed, skip 5 nibbles + w.pc+=5; + return; +} + +VOID o_invalid6(LPBYTE I) +{ + _ASSERT(FALSE); // invalid, length guessed, skip 6 nibbles + w.pc+=6; + return; +} + +VOID o_goyes3(LPBYTE I) +{ + signed char jmp = I[3]+(I[4]<<4); + w.cycles+=7; + if (jmp) + w.pc=(w.pc+jmp)&0xFFFFF; + else + w.pc=rstkpop(); + return; +} + +VOID o_goyes5(LPBYTE I) +{ + signed char jmp = I[5]+(I[6]<<4); + w.cycles+=7; + if (jmp) + w.pc=(w.pc+jmp)&0xFFFFF; + else + w.pc=rstkpop(); + return; +} diff --git a/Sources/Emu48/opcodes.h b/Sources/Emu48/OPCODES.H similarity index 97% rename from Sources/Emu48/opcodes.h rename to Sources/Emu48/OPCODES.H index d2c9724..fa3c958 100644 --- a/Sources/Emu48/opcodes.h +++ b/Sources/Emu48/OPCODES.H @@ -1,443 +1,443 @@ -/* - * opcodes.h - * - * This file is part of Emu48 - * - * Copyright (C) 1999 Christoph Gießelink - * - */ - -#define PCHANGED ((void)(F_s[0]=Chipset.P,F_l[1]=Chipset.P+1)) -#define INTERRUPT ((void)(Chipset.SoftInt=TRUE,bInterrupt=TRUE)) - -extern UINT F_s[16]; -extern UINT F_l[16]; - -extern VOID o00(LPBYTE I); // RTNSXM -extern VOID o01(LPBYTE I); // RTN -extern VOID o02(LPBYTE I); // RTNSC -extern VOID o03(LPBYTE I); // RTNCC -extern VOID o04(LPBYTE I); // SETHEX -extern VOID o05(LPBYTE I); // SETDEC -extern VOID o06(LPBYTE I); // RSTK=C -extern VOID o07(LPBYTE I); // C=RSTK -extern VOID o08(LPBYTE I); // CLRST -extern VOID o09(LPBYTE I); // C=ST -extern VOID o0A(LPBYTE I); // ST=C -extern VOID o0B(LPBYTE I); // CSTEX -extern VOID o0C(LPBYTE I); // P=P+1 -extern VOID o0D(LPBYTE I); // P=P-1 -extern VOID o0Ef0(LPBYTE I); // A=A&B f -extern VOID o0Ef1(LPBYTE I); // B=B&C f -extern VOID o0Ef2(LPBYTE I); // C=C&A f -extern VOID o0Ef3(LPBYTE I); // D=D&C f -extern VOID o0Ef4(LPBYTE I); // B=B&A f -extern VOID o0Ef5(LPBYTE I); // C=C&B f -extern VOID o0Ef6(LPBYTE I); // A=A&C f -extern VOID o0Ef7(LPBYTE I); // C=C&D f -extern VOID o0Ef8(LPBYTE I); // A=A!B f -extern VOID o0Ef9(LPBYTE I); // B=B!C f -extern VOID o0EfA(LPBYTE I); // C=C!A f -extern VOID o0EfB(LPBYTE I); // D=D!C f -extern VOID o0EfC(LPBYTE I); // B=B!A f -extern VOID o0EfD(LPBYTE I); // C=C!B f -extern VOID o0EfE(LPBYTE I); // A=A!C f -extern VOID o0EfF(LPBYTE I); // C=C!D f -extern VOID o0F(LPBYTE I); // RTI -extern VOID o100(LPBYTE I); // R0=A W -extern VOID o101(LPBYTE I); // R1=A W -extern VOID o102(LPBYTE I); // R2=A W -extern VOID o103(LPBYTE I); // R3=A W -extern VOID o104(LPBYTE I); // R4=A W -extern VOID o108(LPBYTE I); // R0=C W -extern VOID o109(LPBYTE I); // R1=C W -extern VOID o10A(LPBYTE I); // R2=C W -extern VOID o10B(LPBYTE I); // R3=C W -extern VOID o10C(LPBYTE I); // R4=C W -extern VOID o110(LPBYTE I); // A=R0 W -extern VOID o111(LPBYTE I); // A=R1 W -extern VOID o112(LPBYTE I); // A=R2 W -extern VOID o113(LPBYTE I); // A=R3 W -extern VOID o114(LPBYTE I); // A=R4 W -extern VOID o118(LPBYTE I); // C=R0 W -extern VOID o119(LPBYTE I); // C=R1 W -extern VOID o11A(LPBYTE I); // C=R2 W -extern VOID o11B(LPBYTE I); // C=R3 W -extern VOID o11C(LPBYTE I); // C=R4 W -extern VOID o120(LPBYTE I); // AR0EX W -extern VOID o121(LPBYTE I); // AR1EX W -extern VOID o122(LPBYTE I); // AR2EX W -extern VOID o123(LPBYTE I); // AR3EX W -extern VOID o124(LPBYTE I); // AR4EX W -extern VOID o128(LPBYTE I); // CR0EX W -extern VOID o129(LPBYTE I); // CR1EX W -extern VOID o12A(LPBYTE I); // CR2EX W -extern VOID o12B(LPBYTE I); // CR3EX W -extern VOID o12C(LPBYTE I); // CR4EX W -extern VOID o130(LPBYTE I); // D0=A -extern VOID o131(LPBYTE I); // D1=A -extern VOID o132(LPBYTE I); // AD0EX -extern VOID o133(LPBYTE I); // AD1EX -extern VOID o134(LPBYTE I); // D0=C -extern VOID o135(LPBYTE I); // D1=C -extern VOID o136(LPBYTE I); // CD0EX -extern VOID o137(LPBYTE I); // CD1EX -extern VOID o138(LPBYTE I); // D0=AS -extern VOID o139(LPBYTE I); // D1=AS -extern VOID o13A(LPBYTE I); // AD0XS -extern VOID o13B(LPBYTE I); // AD1XS -extern VOID o13C(LPBYTE I); // D0=CS -extern VOID o13D(LPBYTE I); // D1=CS -extern VOID o13E(LPBYTE I); // CD0XS -extern VOID o13F(LPBYTE I); // CD1XS -extern VOID o140(LPBYTE I); // DAT0=A A -extern VOID o141(LPBYTE I); // DAT0=A A -extern VOID o144(LPBYTE I); // DAT0=C A -extern VOID o145(LPBYTE I); // DAT1=C A -extern VOID o148(LPBYTE I); // DAT0=A B -extern VOID o149(LPBYTE I); // DAT1=A B -extern VOID o14C(LPBYTE I); // DAT0=C B -extern VOID o14D(LPBYTE I); // DAT1=C B -extern VOID o142(LPBYTE I); // A=DAT0 A -extern VOID o143(LPBYTE I); // A=DAT1 A -extern VOID o146(LPBYTE I); // C=DAT0 A -extern VOID o147(LPBYTE I); // C=DAT1 A -extern VOID o14A(LPBYTE I); // A=DAT0 B -extern VOID o14B(LPBYTE I); // A=DAT1 B -extern VOID o14E(LPBYTE I); // C=DAT0 B -extern VOID o14F(LPBYTE I); // C=DAT0 B -extern VOID o150a(LPBYTE I); // DAT0=A a -extern VOID o151a(LPBYTE I); // DAT1=A a -extern VOID o154a(LPBYTE I); // DAT0=C a -extern VOID o155a(LPBYTE I); // DAT1=C a -extern VOID o152a(LPBYTE I); // A=DAT0 a -extern VOID o153a(LPBYTE I); // A=DAT1 a -extern VOID o156a(LPBYTE I); // C=DAT0 a -extern VOID o157a(LPBYTE I); // C=DAT1 a -extern VOID o158x(LPBYTE I); // DAT0=A x -extern VOID o159x(LPBYTE I); // DAT1=A x -extern VOID o15Cx(LPBYTE I); // DAT0=C x -extern VOID o15Dx(LPBYTE I); // DAT1=C x -extern VOID o15Ax(LPBYTE I); // A=DAT0 x -extern VOID o15Bx(LPBYTE I); // A=DAT1 x -extern VOID o15Ex(LPBYTE I); // C=DAT0 x -extern VOID o15Fx(LPBYTE I); // C=DAT1 x -extern VOID o16x(LPBYTE I); // D0=D0+ (n+1) -extern VOID o17x(LPBYTE I); // D1=D1+ (n+1) -extern VOID o18x(LPBYTE I); // D0=D0- (n+1) -extern VOID o19d2(LPBYTE I); // D0=(2) #dd -extern VOID o1Ad4(LPBYTE I); // D0=(4) #dddd -extern VOID o1Bd5(LPBYTE I); // D0=(5) #ddddd -extern VOID o1Cx(LPBYTE I); // D1=D1- (n+1) -extern VOID o1Dd2(LPBYTE I); // D1=(2) #dd -extern VOID o1Ed4(LPBYTE I); // D1=(4) #dddd -extern VOID o1Fd5(LPBYTE I); // D1=(5) #ddddd -extern VOID o2n(LPBYTE I); // P= n -extern VOID o3X(LPBYTE I); // LCHEX -extern VOID o4d2(LPBYTE I); // GOC #dd -extern VOID o5d2(LPBYTE I); // GONC -extern VOID o6d3(LPBYTE I); // GOTO -extern VOID o7d3(LPBYTE I); // GOSUB -extern VOID o800(LPBYTE I); // OUT=CS -extern VOID o801(LPBYTE I); // OUT=C -extern VOID o802(LPBYTE I); // A=IN -extern VOID o803(LPBYTE I); // C=IN -extern VOID o804(LPBYTE I); // UNCNFG -extern VOID o805(LPBYTE I); // CONFIG -extern VOID o806(LPBYTE I); // C=ID -extern VOID o807(LPBYTE I); // SHUTDN -extern VOID o8080(LPBYTE I); // INTON -extern VOID o80810(LPBYTE I); // RSI -extern VOID o8082X(LPBYTE I); // LA -extern VOID o8083(LPBYTE I); // BUSCB -extern VOID o8084n(LPBYTE I); // ABIT=0 n -extern VOID o8085n(LPBYTE I); // ABIT=1 n -extern VOID o8086n(LPBYTE I); // ?ABIT=0 n -extern VOID o8087n(LPBYTE I); // ?ABIT=1 n -extern VOID o8088n(LPBYTE I); // CBIT=0 n -extern VOID o8089n(LPBYTE I); // CBIT=1 n -extern VOID o808An(LPBYTE I); // ?CBIT=0 n -extern VOID o808Bn(LPBYTE I); // ?CBIT=1 n -extern VOID o808C(LPBYTE I); // PC=(A) -extern VOID o808D(LPBYTE I); // BUSCD -extern VOID o808E(LPBYTE I); // PC=(C) -extern VOID o808F(LPBYTE I); // INTOFF -extern VOID o809(LPBYTE I); // C+P+1 - HEX MODE -extern VOID o80A(LPBYTE I); // RESET -extern VOID o80B(LPBYTE I); // BUSCC -extern VOID o80Cn(LPBYTE I); // C=P n -extern VOID o80Dn(LPBYTE I); // P=C n -extern VOID o80E(LPBYTE I); // SREQ? -extern VOID o80Fn(LPBYTE I); // CPEX n -extern VOID o810(LPBYTE I); // ASLC -extern VOID o811(LPBYTE I); // BSLC -extern VOID o812(LPBYTE I); // CSLC -extern VOID o813(LPBYTE I); // DSLC -extern VOID o814(LPBYTE I); // ASRC -extern VOID o815(LPBYTE I); // BSRC -extern VOID o816(LPBYTE I); // CSRC -extern VOID o817(LPBYTE I); // DSRC -extern VOID o818f0x(LPBYTE I); // A=A+x+1 f -extern VOID o818f1x(LPBYTE I); // B=B+x+1 f -extern VOID o818f2x(LPBYTE I); // C=C+x+1 f -extern VOID o818f3x(LPBYTE I); // D=D+x+1 f -extern VOID o818f8x(LPBYTE I); // A=A-x-1 f -extern VOID o818f9x(LPBYTE I); // B=B-x-1 f -extern VOID o818fAx(LPBYTE I); // C=C-x-1 f -extern VOID o818fBx(LPBYTE I); // D=D-x-1 f -extern VOID o819f0(LPBYTE I); // ASRB.F -extern VOID o819f1(LPBYTE I); // BSRB.F -extern VOID o819f2(LPBYTE I); // CSRB.F -extern VOID o819f3(LPBYTE I); // DSRB.F -extern VOID o81Af00(LPBYTE I); // R0=A.F f -extern VOID o81Af01(LPBYTE I); // R1=A.F f -extern VOID o81Af02(LPBYTE I); // R2=A.F f -extern VOID o81Af03(LPBYTE I); // R3=A.F f -extern VOID o81Af04(LPBYTE I); // R4=A.F f -extern VOID o81Af08(LPBYTE I); // R0=C.F f -extern VOID o81Af09(LPBYTE I); // R1=C.F f -extern VOID o81Af0A(LPBYTE I); // R2=C.F f -extern VOID o81Af0B(LPBYTE I); // R3=C.F f -extern VOID o81Af0C(LPBYTE I); // R4=C.F f -extern VOID o81Af10(LPBYTE I); // A=R0.F f -extern VOID o81Af11(LPBYTE I); // A=R1.F f -extern VOID o81Af12(LPBYTE I); // A=R2.F f -extern VOID o81Af13(LPBYTE I); // A=R3.F f -extern VOID o81Af14(LPBYTE I); // A=R4.F f -extern VOID o81Af18(LPBYTE I); // C=R0.F f -extern VOID o81Af19(LPBYTE I); // C=R1.F f -extern VOID o81Af1A(LPBYTE I); // C=R2.F f -extern VOID o81Af1B(LPBYTE I); // C=R3.F f -extern VOID o81Af1C(LPBYTE I); // C=R4.F f -extern VOID o81Af20(LPBYTE I); // AR0EX.F f -extern VOID o81Af21(LPBYTE I); // AR1EX.F f -extern VOID o81Af22(LPBYTE I); // AR2EX.F f -extern VOID o81Af23(LPBYTE I); // AR3EX.F f -extern VOID o81Af24(LPBYTE I); // AR4EX.F f -extern VOID o81Af28(LPBYTE I); // CR0EX.F f -extern VOID o81Af29(LPBYTE I); // CR1EX.F f -extern VOID o81Af2A(LPBYTE I); // CR2EX.F f -extern VOID o81Af2B(LPBYTE I); // CR3EX.F f -extern VOID o81Af2C(LPBYTE I); // CR4EX.F f -extern VOID o81B2(LPBYTE I); // PC=A -extern VOID o81B3(LPBYTE I); // PC=C -extern VOID o81B4(LPBYTE I); // A=PC -extern VOID o81B5(LPBYTE I); // C=PC -extern VOID o81B6(LPBYTE I); // APCEX -extern VOID o81B7(LPBYTE I); // CPCEX -extern VOID o81C(LPBYTE I); // ASRB -extern VOID o81D(LPBYTE I); // BSRB -extern VOID o81E(LPBYTE I); // CSRB -extern VOID o81F(LPBYTE I); // DSRB -extern VOID o82n(LPBYTE I); // HST=0 m -extern VOID o83n(LPBYTE I); // ?HST=0 m -extern VOID o84n(LPBYTE I); // ST=0 n -extern VOID o85n(LPBYTE I); // ST=1 n -extern VOID o86n(LPBYTE I); // ?ST=0 n -extern VOID o87n(LPBYTE I); // ?ST=1 n -extern VOID o88n(LPBYTE I); // ?P# n -extern VOID o89n(LPBYTE I); // ?P= n -extern VOID o8A0(LPBYTE I); // ?A=B A -extern VOID o8A1(LPBYTE I); // ?B=C A -extern VOID o8A2(LPBYTE I); // ?C=A A -extern VOID o8A3(LPBYTE I); // ?D=C A -extern VOID o8A4(LPBYTE I); // ?A#B A -extern VOID o8A5(LPBYTE I); // ?B#C A -extern VOID o8A6(LPBYTE I); // ?C#A A -extern VOID o8A7(LPBYTE I); // ?D#C A -extern VOID o8A8(LPBYTE I); // ?A=0 A -extern VOID o8A9(LPBYTE I); // ?B=0 A -extern VOID o8AA(LPBYTE I); // ?C=0 A -extern VOID o8AB(LPBYTE I); // ?D=0 A -extern VOID o8AC(LPBYTE I); // ?A#0 A -extern VOID o8AD(LPBYTE I); // ?B#0 A -extern VOID o8AE(LPBYTE I); // ?C#0 A -extern VOID o8AF(LPBYTE I); // ?D#0 A -extern VOID o8B0(LPBYTE I); // ?A>B A -extern VOID o8B1(LPBYTE I); // ?B>C A -extern VOID o8B2(LPBYTE I); // ?C>A A -extern VOID o8B3(LPBYTE I); // ?D>C A -extern VOID o8B4(LPBYTE I); // ?A=B A -extern VOID o8B9(LPBYTE I); // ?B>=C A -extern VOID o8BA(LPBYTE I); // ?C>=A A -extern VOID o8BB(LPBYTE I); // ?D>=C A -extern VOID o8BC(LPBYTE I); // ?A<=B A -extern VOID o8BD(LPBYTE I); // ?B<=C A -extern VOID o8BE(LPBYTE I); // ?C<=A A -extern VOID o8BF(LPBYTE I); // ?D<=C A -extern VOID o8Cd4(LPBYTE I); // GOLONG #dddd -extern VOID o8Dd5(LPBYTE I); // GOVLNG #ddddd -extern VOID o8Ed4(LPBYTE I); // GOSUBL #dddd -extern VOID o8Fd5(LPBYTE I); // GOSBVL #ddddd -extern VOID o9a0(LPBYTE I); // ?A=B f -extern VOID o9a1(LPBYTE I); // ?B=C f -extern VOID o9a2(LPBYTE I); // ?C=A f -extern VOID o9a3(LPBYTE I); // ?D=C f -extern VOID o9a4(LPBYTE I); // ?A#B f -extern VOID o9a5(LPBYTE I); // ?B#C f -extern VOID o9a6(LPBYTE I); // ?C#A f -extern VOID o9a7(LPBYTE I); // ?D#C f -extern VOID o9a8(LPBYTE I); // ?A=0 f -extern VOID o9a9(LPBYTE I); // ?B=0 f -extern VOID o9aA(LPBYTE I); // ?C=0 f -extern VOID o9aB(LPBYTE I); // ?D=0 f -extern VOID o9aC(LPBYTE I); // ?A#0 f -extern VOID o9aD(LPBYTE I); // ?B#0 f -extern VOID o9aE(LPBYTE I); // ?C#0 f -extern VOID o9aF(LPBYTE I); // ?D#0 f -extern VOID o9b0(LPBYTE I); // ?A>B f -extern VOID o9b1(LPBYTE I); // ?B>C f -extern VOID o9b2(LPBYTE I); // ?C>A f -extern VOID o9b3(LPBYTE I); // ?D>C f -extern VOID o9b4(LPBYTE I); // ?A=B f -extern VOID o9b9(LPBYTE I); // ?B>=C f -extern VOID o9bA(LPBYTE I); // ?C>=A f -extern VOID o9bB(LPBYTE I); // ?D>=C f -extern VOID o9bC(LPBYTE I); // ?A<=B f -extern VOID o9bD(LPBYTE I); // ?B<=C f -extern VOID o9bE(LPBYTE I); // ?C<=A f -extern VOID o9bF(LPBYTE I); // ?D<=C f -extern VOID oAa0(LPBYTE I); // A=A+B f -extern VOID oAa1(LPBYTE I); // B=B+C f -extern VOID oAa2(LPBYTE I); // C=C+A f -extern VOID oAa3(LPBYTE I); // D=D+C f -extern VOID oAa4(LPBYTE I); // A=A+A f -extern VOID oAa5(LPBYTE I); // B=B+B f -extern VOID oAa6(LPBYTE I); // C=C+C f -extern VOID oAa7(LPBYTE I); // D=D+D f -extern VOID oAa8(LPBYTE I); // B=B+A f -extern VOID oAa9(LPBYTE I); // C=C+B f -extern VOID oAaA(LPBYTE I); // A=A+C f -extern VOID oAaB(LPBYTE I); // C=C+D f -extern VOID oAaC(LPBYTE I); // A=A-1 f -extern VOID oAaD(LPBYTE I); // B=B-1 f -extern VOID oAaE(LPBYTE I); // C=C-1 f -extern VOID oAaF(LPBYTE I); // D=D-1 f -extern VOID oAb0(LPBYTE I); // A=0 f -extern VOID oAb1(LPBYTE I); // B=0 f -extern VOID oAb2(LPBYTE I); // C=0 f -extern VOID oAb3(LPBYTE I); // D=0 f -extern VOID oAb4(LPBYTE I); // A=B f -extern VOID oAb5(LPBYTE I); // B=C f -extern VOID oAb6(LPBYTE I); // C=A f -extern VOID oAb7(LPBYTE I); // D=C f -extern VOID oAb8(LPBYTE I); // B=A f -extern VOID oAb9(LPBYTE I); // C=B f -extern VOID oAbA(LPBYTE I); // A=C f -extern VOID oAbB(LPBYTE I); // C=D f -extern VOID oAbC(LPBYTE I); // ABEX f -extern VOID oAbD(LPBYTE I); // BCEX f -extern VOID oAbE(LPBYTE I); // CAEX f -extern VOID oAbF(LPBYTE I); // DCEX f -extern VOID oBa0(LPBYTE I); // A=A-B f -extern VOID oBa1(LPBYTE I); // B=B-C f -extern VOID oBa2(LPBYTE I); // C=C-A f -extern VOID oBa3(LPBYTE I); // D=D-C f -extern VOID oBa4(LPBYTE I); // A=A+1 f -extern VOID oBa5(LPBYTE I); // B=B+1 f -extern VOID oBa6(LPBYTE I); // C=C+1 f -extern VOID oBa7(LPBYTE I); // D=D+1 f -extern VOID oBa8(LPBYTE I); // B=B-A f -extern VOID oBa9(LPBYTE I); // C=C-B f -extern VOID oBaA(LPBYTE I); // A=A-C f -extern VOID oBaB(LPBYTE I); // C=C-D f -extern VOID oBaC(LPBYTE I); // A=B-A f -extern VOID oBaD(LPBYTE I); // B=C-B f -extern VOID oBaE(LPBYTE I); // C=A-C f -extern VOID oBaF(LPBYTE I); // D=C-D f -extern VOID oBb0(LPBYTE I); // ASL f -extern VOID oBb1(LPBYTE I); // BSL f -extern VOID oBb2(LPBYTE I); // CSL f -extern VOID oBb3(LPBYTE I); // DSL f -extern VOID oBb4(LPBYTE I); // ASR f -extern VOID oBb5(LPBYTE I); // BSR f -extern VOID oBb6(LPBYTE I); // CSR f -extern VOID oBb7(LPBYTE I); // DSR f -extern VOID oBb8(LPBYTE I); // A=-A f -extern VOID oBb9(LPBYTE I); // B=-B f -extern VOID oBbA(LPBYTE I); // C=-C f -extern VOID oBbB(LPBYTE I); // D=-D f -extern VOID oBbC(LPBYTE I); // A=-A-1 f -extern VOID oBbD(LPBYTE I); // B=-B-1 f -extern VOID oBbE(LPBYTE I); // C=-C-1 f -extern VOID oBbF(LPBYTE I); // D=-D-1 f -extern VOID oC0(LPBYTE I); // A=A+B A -extern VOID oC1(LPBYTE I); // B=B+C A -extern VOID oC2(LPBYTE I); // C=C+A A -extern VOID oC3(LPBYTE I); // D=D+C A -extern VOID oC4(LPBYTE I); // A=A+A A -extern VOID oC5(LPBYTE I); // B=B+B A -extern VOID oC6(LPBYTE I); // C=C+C A -extern VOID oC7(LPBYTE I); // D=D+D A -extern VOID oC8(LPBYTE I); // B=B+A A -extern VOID oC9(LPBYTE I); // C=C+B A -extern VOID oCA(LPBYTE I); // A=A+C A -extern VOID oCB(LPBYTE I); // C=C+D A -extern VOID oCC(LPBYTE I); // A=A-1 A -extern VOID oCD(LPBYTE I); // B=B-1 A -extern VOID oCE(LPBYTE I); // C=C-1 A -extern VOID oCF(LPBYTE I); // D=D-1 A -extern VOID oD0(LPBYTE I); // A=0 A -extern VOID oD1(LPBYTE I); // B=0 A -extern VOID oD2(LPBYTE I); // C=0 A -extern VOID oD3(LPBYTE I); // D=0 A -extern VOID oD4(LPBYTE I); // A=B A -extern VOID oD5(LPBYTE I); // B=C A -extern VOID oD6(LPBYTE I); // C=A A -extern VOID oD7(LPBYTE I); // D=C A -extern VOID oD8(LPBYTE I); // B=A A -extern VOID oD9(LPBYTE I); // C=B A -extern VOID oDA(LPBYTE I); // A=C A -extern VOID oDB(LPBYTE I); // C=D A -extern VOID oDC(LPBYTE I); // ABEX -extern VOID oDD(LPBYTE I); // BCEX -extern VOID oDE(LPBYTE I); // CAEX -extern VOID oDF(LPBYTE I); // DCEX -extern VOID oE0(LPBYTE I); // A=A-B A -extern VOID oE1(LPBYTE I); // B=B-C A -extern VOID oE2(LPBYTE I); // C=C-A A -extern VOID oE3(LPBYTE I); // D=D-C A -extern VOID oE4(LPBYTE I); // A=A+1 A -extern VOID oE5(LPBYTE I); // B=B+1 A -extern VOID oE6(LPBYTE I); // C=C+1 A -extern VOID oE7(LPBYTE I); // D=D+1 A -extern VOID oE8(LPBYTE I); // B=B-A A -extern VOID oE9(LPBYTE I); // C=C-B A -extern VOID oEA(LPBYTE I); // A=A-C A -extern VOID oEB(LPBYTE I); // C=C-D A -extern VOID oEC(LPBYTE I); // A=B-A A -extern VOID oED(LPBYTE I); // B=C-B A -extern VOID oEE(LPBYTE I); // C=A-C A -extern VOID oEF(LPBYTE I); // D=C-D A -extern VOID oF0(LPBYTE I); // ASL A -extern VOID oF1(LPBYTE I); // BSL A -extern VOID oF2(LPBYTE I); // CSL A -extern VOID oF3(LPBYTE I); // DSL A -extern VOID oF4(LPBYTE I); // ASR A -extern VOID oF5(LPBYTE I); // BSR A -extern VOID oF6(LPBYTE I); // CSR A -extern VOID oF7(LPBYTE I); // DSR A -extern VOID oF8(LPBYTE I); // A=-A A -extern VOID oF9(LPBYTE I); // B=-B A -extern VOID oFA(LPBYTE I); // C=-C A -extern VOID oFB(LPBYTE I); // D=-D A -extern VOID oFC(LPBYTE I); // A=-A-1 A -extern VOID oFD(LPBYTE I); // B=-B-1 A -extern VOID oFE(LPBYTE I); // C=-C-1 A -extern VOID oFF(LPBYTE I); // D=-D-1 A - -extern VOID o_invalid3(LPBYTE I); -extern VOID o_invalid4(LPBYTE I); -extern VOID o_invalid5(LPBYTE I); -extern VOID o_invalid6(LPBYTE I); - -extern VOID o_goyes3(LPBYTE I); -extern VOID o_goyes5(LPBYTE I); +/* + * opcodes.h + * + * This file is part of Emu48 + * + * Copyright (C) 1999 Christoph Gießelink + * + */ + +#define PCHANGED ((void)(F_s[0]=Chipset.P,F_l[1]=Chipset.P+1)) +#define INTERRUPT ((void)(Chipset.SoftInt=TRUE,bInterrupt=TRUE)) + +extern UINT F_s[16]; +extern UINT F_l[16]; + +extern VOID o00(LPBYTE I); // RTNSXM +extern VOID o01(LPBYTE I); // RTN +extern VOID o02(LPBYTE I); // RTNSC +extern VOID o03(LPBYTE I); // RTNCC +extern VOID o04(LPBYTE I); // SETHEX +extern VOID o05(LPBYTE I); // SETDEC +extern VOID o06(LPBYTE I); // RSTK=C +extern VOID o07(LPBYTE I); // C=RSTK +extern VOID o08(LPBYTE I); // CLRST +extern VOID o09(LPBYTE I); // C=ST +extern VOID o0A(LPBYTE I); // ST=C +extern VOID o0B(LPBYTE I); // CSTEX +extern VOID o0C(LPBYTE I); // P=P+1 +extern VOID o0D(LPBYTE I); // P=P-1 +extern VOID o0Ef0(LPBYTE I); // A=A&B f +extern VOID o0Ef1(LPBYTE I); // B=B&C f +extern VOID o0Ef2(LPBYTE I); // C=C&A f +extern VOID o0Ef3(LPBYTE I); // D=D&C f +extern VOID o0Ef4(LPBYTE I); // B=B&A f +extern VOID o0Ef5(LPBYTE I); // C=C&B f +extern VOID o0Ef6(LPBYTE I); // A=A&C f +extern VOID o0Ef7(LPBYTE I); // C=C&D f +extern VOID o0Ef8(LPBYTE I); // A=A!B f +extern VOID o0Ef9(LPBYTE I); // B=B!C f +extern VOID o0EfA(LPBYTE I); // C=C!A f +extern VOID o0EfB(LPBYTE I); // D=D!C f +extern VOID o0EfC(LPBYTE I); // B=B!A f +extern VOID o0EfD(LPBYTE I); // C=C!B f +extern VOID o0EfE(LPBYTE I); // A=A!C f +extern VOID o0EfF(LPBYTE I); // C=C!D f +extern VOID o0F(LPBYTE I); // RTI +extern VOID o100(LPBYTE I); // R0=A W +extern VOID o101(LPBYTE I); // R1=A W +extern VOID o102(LPBYTE I); // R2=A W +extern VOID o103(LPBYTE I); // R3=A W +extern VOID o104(LPBYTE I); // R4=A W +extern VOID o108(LPBYTE I); // R0=C W +extern VOID o109(LPBYTE I); // R1=C W +extern VOID o10A(LPBYTE I); // R2=C W +extern VOID o10B(LPBYTE I); // R3=C W +extern VOID o10C(LPBYTE I); // R4=C W +extern VOID o110(LPBYTE I); // A=R0 W +extern VOID o111(LPBYTE I); // A=R1 W +extern VOID o112(LPBYTE I); // A=R2 W +extern VOID o113(LPBYTE I); // A=R3 W +extern VOID o114(LPBYTE I); // A=R4 W +extern VOID o118(LPBYTE I); // C=R0 W +extern VOID o119(LPBYTE I); // C=R1 W +extern VOID o11A(LPBYTE I); // C=R2 W +extern VOID o11B(LPBYTE I); // C=R3 W +extern VOID o11C(LPBYTE I); // C=R4 W +extern VOID o120(LPBYTE I); // AR0EX W +extern VOID o121(LPBYTE I); // AR1EX W +extern VOID o122(LPBYTE I); // AR2EX W +extern VOID o123(LPBYTE I); // AR3EX W +extern VOID o124(LPBYTE I); // AR4EX W +extern VOID o128(LPBYTE I); // CR0EX W +extern VOID o129(LPBYTE I); // CR1EX W +extern VOID o12A(LPBYTE I); // CR2EX W +extern VOID o12B(LPBYTE I); // CR3EX W +extern VOID o12C(LPBYTE I); // CR4EX W +extern VOID o130(LPBYTE I); // D0=A +extern VOID o131(LPBYTE I); // D1=A +extern VOID o132(LPBYTE I); // AD0EX +extern VOID o133(LPBYTE I); // AD1EX +extern VOID o134(LPBYTE I); // D0=C +extern VOID o135(LPBYTE I); // D1=C +extern VOID o136(LPBYTE I); // CD0EX +extern VOID o137(LPBYTE I); // CD1EX +extern VOID o138(LPBYTE I); // D0=AS +extern VOID o139(LPBYTE I); // D1=AS +extern VOID o13A(LPBYTE I); // AD0XS +extern VOID o13B(LPBYTE I); // AD1XS +extern VOID o13C(LPBYTE I); // D0=CS +extern VOID o13D(LPBYTE I); // D1=CS +extern VOID o13E(LPBYTE I); // CD0XS +extern VOID o13F(LPBYTE I); // CD1XS +extern VOID o140(LPBYTE I); // DAT0=A A +extern VOID o141(LPBYTE I); // DAT0=A A +extern VOID o144(LPBYTE I); // DAT0=C A +extern VOID o145(LPBYTE I); // DAT1=C A +extern VOID o148(LPBYTE I); // DAT0=A B +extern VOID o149(LPBYTE I); // DAT1=A B +extern VOID o14C(LPBYTE I); // DAT0=C B +extern VOID o14D(LPBYTE I); // DAT1=C B +extern VOID o142(LPBYTE I); // A=DAT0 A +extern VOID o143(LPBYTE I); // A=DAT1 A +extern VOID o146(LPBYTE I); // C=DAT0 A +extern VOID o147(LPBYTE I); // C=DAT1 A +extern VOID o14A(LPBYTE I); // A=DAT0 B +extern VOID o14B(LPBYTE I); // A=DAT1 B +extern VOID o14E(LPBYTE I); // C=DAT0 B +extern VOID o14F(LPBYTE I); // C=DAT0 B +extern VOID o150a(LPBYTE I); // DAT0=A a +extern VOID o151a(LPBYTE I); // DAT1=A a +extern VOID o154a(LPBYTE I); // DAT0=C a +extern VOID o155a(LPBYTE I); // DAT1=C a +extern VOID o152a(LPBYTE I); // A=DAT0 a +extern VOID o153a(LPBYTE I); // A=DAT1 a +extern VOID o156a(LPBYTE I); // C=DAT0 a +extern VOID o157a(LPBYTE I); // C=DAT1 a +extern VOID o158x(LPBYTE I); // DAT0=A x +extern VOID o159x(LPBYTE I); // DAT1=A x +extern VOID o15Cx(LPBYTE I); // DAT0=C x +extern VOID o15Dx(LPBYTE I); // DAT1=C x +extern VOID o15Ax(LPBYTE I); // A=DAT0 x +extern VOID o15Bx(LPBYTE I); // A=DAT1 x +extern VOID o15Ex(LPBYTE I); // C=DAT0 x +extern VOID o15Fx(LPBYTE I); // C=DAT1 x +extern VOID o16x(LPBYTE I); // D0=D0+ (n+1) +extern VOID o17x(LPBYTE I); // D1=D1+ (n+1) +extern VOID o18x(LPBYTE I); // D0=D0- (n+1) +extern VOID o19d2(LPBYTE I); // D0=(2) #dd +extern VOID o1Ad4(LPBYTE I); // D0=(4) #dddd +extern VOID o1Bd5(LPBYTE I); // D0=(5) #ddddd +extern VOID o1Cx(LPBYTE I); // D1=D1- (n+1) +extern VOID o1Dd2(LPBYTE I); // D1=(2) #dd +extern VOID o1Ed4(LPBYTE I); // D1=(4) #dddd +extern VOID o1Fd5(LPBYTE I); // D1=(5) #ddddd +extern VOID o2n(LPBYTE I); // P= n +extern VOID o3X(LPBYTE I); // LCHEX +extern VOID o4d2(LPBYTE I); // GOC #dd +extern VOID o5d2(LPBYTE I); // GONC +extern VOID o6d3(LPBYTE I); // GOTO +extern VOID o7d3(LPBYTE I); // GOSUB +extern VOID o800(LPBYTE I); // OUT=CS +extern VOID o801(LPBYTE I); // OUT=C +extern VOID o802(LPBYTE I); // A=IN +extern VOID o803(LPBYTE I); // C=IN +extern VOID o804(LPBYTE I); // UNCNFG +extern VOID o805(LPBYTE I); // CONFIG +extern VOID o806(LPBYTE I); // C=ID +extern VOID o807(LPBYTE I); // SHUTDN +extern VOID o8080(LPBYTE I); // INTON +extern VOID o80810(LPBYTE I); // RSI +extern VOID o8082X(LPBYTE I); // LA +extern VOID o8083(LPBYTE I); // BUSCB +extern VOID o8084n(LPBYTE I); // ABIT=0 n +extern VOID o8085n(LPBYTE I); // ABIT=1 n +extern VOID o8086n(LPBYTE I); // ?ABIT=0 n +extern VOID o8087n(LPBYTE I); // ?ABIT=1 n +extern VOID o8088n(LPBYTE I); // CBIT=0 n +extern VOID o8089n(LPBYTE I); // CBIT=1 n +extern VOID o808An(LPBYTE I); // ?CBIT=0 n +extern VOID o808Bn(LPBYTE I); // ?CBIT=1 n +extern VOID o808C(LPBYTE I); // PC=(A) +extern VOID o808D(LPBYTE I); // BUSCD +extern VOID o808E(LPBYTE I); // PC=(C) +extern VOID o808F(LPBYTE I); // INTOFF +extern VOID o809(LPBYTE I); // C+P+1 - HEX MODE +extern VOID o80A(LPBYTE I); // RESET +extern VOID o80B(LPBYTE I); // BUSCC +extern VOID o80Cn(LPBYTE I); // C=P n +extern VOID o80Dn(LPBYTE I); // P=C n +extern VOID o80E(LPBYTE I); // SREQ? +extern VOID o80Fn(LPBYTE I); // CPEX n +extern VOID o810(LPBYTE I); // ASLC +extern VOID o811(LPBYTE I); // BSLC +extern VOID o812(LPBYTE I); // CSLC +extern VOID o813(LPBYTE I); // DSLC +extern VOID o814(LPBYTE I); // ASRC +extern VOID o815(LPBYTE I); // BSRC +extern VOID o816(LPBYTE I); // CSRC +extern VOID o817(LPBYTE I); // DSRC +extern VOID o818f0x(LPBYTE I); // A=A+x+1 f +extern VOID o818f1x(LPBYTE I); // B=B+x+1 f +extern VOID o818f2x(LPBYTE I); // C=C+x+1 f +extern VOID o818f3x(LPBYTE I); // D=D+x+1 f +extern VOID o818f8x(LPBYTE I); // A=A-x-1 f +extern VOID o818f9x(LPBYTE I); // B=B-x-1 f +extern VOID o818fAx(LPBYTE I); // C=C-x-1 f +extern VOID o818fBx(LPBYTE I); // D=D-x-1 f +extern VOID o819f0(LPBYTE I); // ASRB.F +extern VOID o819f1(LPBYTE I); // BSRB.F +extern VOID o819f2(LPBYTE I); // CSRB.F +extern VOID o819f3(LPBYTE I); // DSRB.F +extern VOID o81Af00(LPBYTE I); // R0=A.F f +extern VOID o81Af01(LPBYTE I); // R1=A.F f +extern VOID o81Af02(LPBYTE I); // R2=A.F f +extern VOID o81Af03(LPBYTE I); // R3=A.F f +extern VOID o81Af04(LPBYTE I); // R4=A.F f +extern VOID o81Af08(LPBYTE I); // R0=C.F f +extern VOID o81Af09(LPBYTE I); // R1=C.F f +extern VOID o81Af0A(LPBYTE I); // R2=C.F f +extern VOID o81Af0B(LPBYTE I); // R3=C.F f +extern VOID o81Af0C(LPBYTE I); // R4=C.F f +extern VOID o81Af10(LPBYTE I); // A=R0.F f +extern VOID o81Af11(LPBYTE I); // A=R1.F f +extern VOID o81Af12(LPBYTE I); // A=R2.F f +extern VOID o81Af13(LPBYTE I); // A=R3.F f +extern VOID o81Af14(LPBYTE I); // A=R4.F f +extern VOID o81Af18(LPBYTE I); // C=R0.F f +extern VOID o81Af19(LPBYTE I); // C=R1.F f +extern VOID o81Af1A(LPBYTE I); // C=R2.F f +extern VOID o81Af1B(LPBYTE I); // C=R3.F f +extern VOID o81Af1C(LPBYTE I); // C=R4.F f +extern VOID o81Af20(LPBYTE I); // AR0EX.F f +extern VOID o81Af21(LPBYTE I); // AR1EX.F f +extern VOID o81Af22(LPBYTE I); // AR2EX.F f +extern VOID o81Af23(LPBYTE I); // AR3EX.F f +extern VOID o81Af24(LPBYTE I); // AR4EX.F f +extern VOID o81Af28(LPBYTE I); // CR0EX.F f +extern VOID o81Af29(LPBYTE I); // CR1EX.F f +extern VOID o81Af2A(LPBYTE I); // CR2EX.F f +extern VOID o81Af2B(LPBYTE I); // CR3EX.F f +extern VOID o81Af2C(LPBYTE I); // CR4EX.F f +extern VOID o81B2(LPBYTE I); // PC=A +extern VOID o81B3(LPBYTE I); // PC=C +extern VOID o81B4(LPBYTE I); // A=PC +extern VOID o81B5(LPBYTE I); // C=PC +extern VOID o81B6(LPBYTE I); // APCEX +extern VOID o81B7(LPBYTE I); // CPCEX +extern VOID o81C(LPBYTE I); // ASRB +extern VOID o81D(LPBYTE I); // BSRB +extern VOID o81E(LPBYTE I); // CSRB +extern VOID o81F(LPBYTE I); // DSRB +extern VOID o82n(LPBYTE I); // HST=0 m +extern VOID o83n(LPBYTE I); // ?HST=0 m +extern VOID o84n(LPBYTE I); // ST=0 n +extern VOID o85n(LPBYTE I); // ST=1 n +extern VOID o86n(LPBYTE I); // ?ST=0 n +extern VOID o87n(LPBYTE I); // ?ST=1 n +extern VOID o88n(LPBYTE I); // ?P# n +extern VOID o89n(LPBYTE I); // ?P= n +extern VOID o8A0(LPBYTE I); // ?A=B A +extern VOID o8A1(LPBYTE I); // ?B=C A +extern VOID o8A2(LPBYTE I); // ?C=A A +extern VOID o8A3(LPBYTE I); // ?D=C A +extern VOID o8A4(LPBYTE I); // ?A#B A +extern VOID o8A5(LPBYTE I); // ?B#C A +extern VOID o8A6(LPBYTE I); // ?C#A A +extern VOID o8A7(LPBYTE I); // ?D#C A +extern VOID o8A8(LPBYTE I); // ?A=0 A +extern VOID o8A9(LPBYTE I); // ?B=0 A +extern VOID o8AA(LPBYTE I); // ?C=0 A +extern VOID o8AB(LPBYTE I); // ?D=0 A +extern VOID o8AC(LPBYTE I); // ?A#0 A +extern VOID o8AD(LPBYTE I); // ?B#0 A +extern VOID o8AE(LPBYTE I); // ?C#0 A +extern VOID o8AF(LPBYTE I); // ?D#0 A +extern VOID o8B0(LPBYTE I); // ?A>B A +extern VOID o8B1(LPBYTE I); // ?B>C A +extern VOID o8B2(LPBYTE I); // ?C>A A +extern VOID o8B3(LPBYTE I); // ?D>C A +extern VOID o8B4(LPBYTE I); // ?A=B A +extern VOID o8B9(LPBYTE I); // ?B>=C A +extern VOID o8BA(LPBYTE I); // ?C>=A A +extern VOID o8BB(LPBYTE I); // ?D>=C A +extern VOID o8BC(LPBYTE I); // ?A<=B A +extern VOID o8BD(LPBYTE I); // ?B<=C A +extern VOID o8BE(LPBYTE I); // ?C<=A A +extern VOID o8BF(LPBYTE I); // ?D<=C A +extern VOID o8Cd4(LPBYTE I); // GOLONG #dddd +extern VOID o8Dd5(LPBYTE I); // GOVLNG #ddddd +extern VOID o8Ed4(LPBYTE I); // GOSUBL #dddd +extern VOID o8Fd5(LPBYTE I); // GOSBVL #ddddd +extern VOID o9a0(LPBYTE I); // ?A=B f +extern VOID o9a1(LPBYTE I); // ?B=C f +extern VOID o9a2(LPBYTE I); // ?C=A f +extern VOID o9a3(LPBYTE I); // ?D=C f +extern VOID o9a4(LPBYTE I); // ?A#B f +extern VOID o9a5(LPBYTE I); // ?B#C f +extern VOID o9a6(LPBYTE I); // ?C#A f +extern VOID o9a7(LPBYTE I); // ?D#C f +extern VOID o9a8(LPBYTE I); // ?A=0 f +extern VOID o9a9(LPBYTE I); // ?B=0 f +extern VOID o9aA(LPBYTE I); // ?C=0 f +extern VOID o9aB(LPBYTE I); // ?D=0 f +extern VOID o9aC(LPBYTE I); // ?A#0 f +extern VOID o9aD(LPBYTE I); // ?B#0 f +extern VOID o9aE(LPBYTE I); // ?C#0 f +extern VOID o9aF(LPBYTE I); // ?D#0 f +extern VOID o9b0(LPBYTE I); // ?A>B f +extern VOID o9b1(LPBYTE I); // ?B>C f +extern VOID o9b2(LPBYTE I); // ?C>A f +extern VOID o9b3(LPBYTE I); // ?D>C f +extern VOID o9b4(LPBYTE I); // ?A=B f +extern VOID o9b9(LPBYTE I); // ?B>=C f +extern VOID o9bA(LPBYTE I); // ?C>=A f +extern VOID o9bB(LPBYTE I); // ?D>=C f +extern VOID o9bC(LPBYTE I); // ?A<=B f +extern VOID o9bD(LPBYTE I); // ?B<=C f +extern VOID o9bE(LPBYTE I); // ?C<=A f +extern VOID o9bF(LPBYTE I); // ?D<=C f +extern VOID oAa0(LPBYTE I); // A=A+B f +extern VOID oAa1(LPBYTE I); // B=B+C f +extern VOID oAa2(LPBYTE I); // C=C+A f +extern VOID oAa3(LPBYTE I); // D=D+C f +extern VOID oAa4(LPBYTE I); // A=A+A f +extern VOID oAa5(LPBYTE I); // B=B+B f +extern VOID oAa6(LPBYTE I); // C=C+C f +extern VOID oAa7(LPBYTE I); // D=D+D f +extern VOID oAa8(LPBYTE I); // B=B+A f +extern VOID oAa9(LPBYTE I); // C=C+B f +extern VOID oAaA(LPBYTE I); // A=A+C f +extern VOID oAaB(LPBYTE I); // C=C+D f +extern VOID oAaC(LPBYTE I); // A=A-1 f +extern VOID oAaD(LPBYTE I); // B=B-1 f +extern VOID oAaE(LPBYTE I); // C=C-1 f +extern VOID oAaF(LPBYTE I); // D=D-1 f +extern VOID oAb0(LPBYTE I); // A=0 f +extern VOID oAb1(LPBYTE I); // B=0 f +extern VOID oAb2(LPBYTE I); // C=0 f +extern VOID oAb3(LPBYTE I); // D=0 f +extern VOID oAb4(LPBYTE I); // A=B f +extern VOID oAb5(LPBYTE I); // B=C f +extern VOID oAb6(LPBYTE I); // C=A f +extern VOID oAb7(LPBYTE I); // D=C f +extern VOID oAb8(LPBYTE I); // B=A f +extern VOID oAb9(LPBYTE I); // C=B f +extern VOID oAbA(LPBYTE I); // A=C f +extern VOID oAbB(LPBYTE I); // C=D f +extern VOID oAbC(LPBYTE I); // ABEX f +extern VOID oAbD(LPBYTE I); // BCEX f +extern VOID oAbE(LPBYTE I); // CAEX f +extern VOID oAbF(LPBYTE I); // DCEX f +extern VOID oBa0(LPBYTE I); // A=A-B f +extern VOID oBa1(LPBYTE I); // B=B-C f +extern VOID oBa2(LPBYTE I); // C=C-A f +extern VOID oBa3(LPBYTE I); // D=D-C f +extern VOID oBa4(LPBYTE I); // A=A+1 f +extern VOID oBa5(LPBYTE I); // B=B+1 f +extern VOID oBa6(LPBYTE I); // C=C+1 f +extern VOID oBa7(LPBYTE I); // D=D+1 f +extern VOID oBa8(LPBYTE I); // B=B-A f +extern VOID oBa9(LPBYTE I); // C=C-B f +extern VOID oBaA(LPBYTE I); // A=A-C f +extern VOID oBaB(LPBYTE I); // C=C-D f +extern VOID oBaC(LPBYTE I); // A=B-A f +extern VOID oBaD(LPBYTE I); // B=C-B f +extern VOID oBaE(LPBYTE I); // C=A-C f +extern VOID oBaF(LPBYTE I); // D=C-D f +extern VOID oBb0(LPBYTE I); // ASL f +extern VOID oBb1(LPBYTE I); // BSL f +extern VOID oBb2(LPBYTE I); // CSL f +extern VOID oBb3(LPBYTE I); // DSL f +extern VOID oBb4(LPBYTE I); // ASR f +extern VOID oBb5(LPBYTE I); // BSR f +extern VOID oBb6(LPBYTE I); // CSR f +extern VOID oBb7(LPBYTE I); // DSR f +extern VOID oBb8(LPBYTE I); // A=-A f +extern VOID oBb9(LPBYTE I); // B=-B f +extern VOID oBbA(LPBYTE I); // C=-C f +extern VOID oBbB(LPBYTE I); // D=-D f +extern VOID oBbC(LPBYTE I); // A=-A-1 f +extern VOID oBbD(LPBYTE I); // B=-B-1 f +extern VOID oBbE(LPBYTE I); // C=-C-1 f +extern VOID oBbF(LPBYTE I); // D=-D-1 f +extern VOID oC0(LPBYTE I); // A=A+B A +extern VOID oC1(LPBYTE I); // B=B+C A +extern VOID oC2(LPBYTE I); // C=C+A A +extern VOID oC3(LPBYTE I); // D=D+C A +extern VOID oC4(LPBYTE I); // A=A+A A +extern VOID oC5(LPBYTE I); // B=B+B A +extern VOID oC6(LPBYTE I); // C=C+C A +extern VOID oC7(LPBYTE I); // D=D+D A +extern VOID oC8(LPBYTE I); // B=B+A A +extern VOID oC9(LPBYTE I); // C=C+B A +extern VOID oCA(LPBYTE I); // A=A+C A +extern VOID oCB(LPBYTE I); // C=C+D A +extern VOID oCC(LPBYTE I); // A=A-1 A +extern VOID oCD(LPBYTE I); // B=B-1 A +extern VOID oCE(LPBYTE I); // C=C-1 A +extern VOID oCF(LPBYTE I); // D=D-1 A +extern VOID oD0(LPBYTE I); // A=0 A +extern VOID oD1(LPBYTE I); // B=0 A +extern VOID oD2(LPBYTE I); // C=0 A +extern VOID oD3(LPBYTE I); // D=0 A +extern VOID oD4(LPBYTE I); // A=B A +extern VOID oD5(LPBYTE I); // B=C A +extern VOID oD6(LPBYTE I); // C=A A +extern VOID oD7(LPBYTE I); // D=C A +extern VOID oD8(LPBYTE I); // B=A A +extern VOID oD9(LPBYTE I); // C=B A +extern VOID oDA(LPBYTE I); // A=C A +extern VOID oDB(LPBYTE I); // C=D A +extern VOID oDC(LPBYTE I); // ABEX +extern VOID oDD(LPBYTE I); // BCEX +extern VOID oDE(LPBYTE I); // CAEX +extern VOID oDF(LPBYTE I); // DCEX +extern VOID oE0(LPBYTE I); // A=A-B A +extern VOID oE1(LPBYTE I); // B=B-C A +extern VOID oE2(LPBYTE I); // C=C-A A +extern VOID oE3(LPBYTE I); // D=D-C A +extern VOID oE4(LPBYTE I); // A=A+1 A +extern VOID oE5(LPBYTE I); // B=B+1 A +extern VOID oE6(LPBYTE I); // C=C+1 A +extern VOID oE7(LPBYTE I); // D=D+1 A +extern VOID oE8(LPBYTE I); // B=B-A A +extern VOID oE9(LPBYTE I); // C=C-B A +extern VOID oEA(LPBYTE I); // A=A-C A +extern VOID oEB(LPBYTE I); // C=C-D A +extern VOID oEC(LPBYTE I); // A=B-A A +extern VOID oED(LPBYTE I); // B=C-B A +extern VOID oEE(LPBYTE I); // C=A-C A +extern VOID oEF(LPBYTE I); // D=C-D A +extern VOID oF0(LPBYTE I); // ASL A +extern VOID oF1(LPBYTE I); // BSL A +extern VOID oF2(LPBYTE I); // CSL A +extern VOID oF3(LPBYTE I); // DSL A +extern VOID oF4(LPBYTE I); // ASR A +extern VOID oF5(LPBYTE I); // BSR A +extern VOID oF6(LPBYTE I); // CSR A +extern VOID oF7(LPBYTE I); // DSR A +extern VOID oF8(LPBYTE I); // A=-A A +extern VOID oF9(LPBYTE I); // B=-B A +extern VOID oFA(LPBYTE I); // C=-C A +extern VOID oFB(LPBYTE I); // D=-D A +extern VOID oFC(LPBYTE I); // A=-A-1 A +extern VOID oFD(LPBYTE I); // B=-B-1 A +extern VOID oFE(LPBYTE I); // C=-C-1 A +extern VOID oFF(LPBYTE I); // D=-D-1 A + +extern VOID o_invalid3(LPBYTE I); +extern VOID o_invalid4(LPBYTE I); +extern VOID o_invalid5(LPBYTE I); +extern VOID o_invalid6(LPBYTE I); + +extern VOID o_goyes3(LPBYTE I); +extern VOID o_goyes5(LPBYTE I); diff --git a/Sources/Emu48/ops.h b/Sources/Emu48/OPS.H similarity index 94% rename from Sources/Emu48/ops.h rename to Sources/Emu48/OPS.H index ac3d02c..20aebb5 100644 --- a/Sources/Emu48/ops.h +++ b/Sources/Emu48/OPS.H @@ -1,462 +1,462 @@ -/* - * ops.h - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ - -#define NFunpack(a, b, f) Nunpack((a)+F_s[f], b, F_l[f]) -#define NFread(a, b, f) Nread((a)+F_s[f], b, F_l[f]) -#define NFwrite(a, b, f) Nwrite((a)+F_s[f], b, F_l[f]) -#define NFcopy(a, b, f) memcpy((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define NFxchg(a, b, f) Nxchg((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define NFadd(a, b, f) Nadd((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define NFsub(a, b, f) Nsub((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define NFrsub(a, b, f) Nrsub((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define NFand(a, b, f) Nand((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define NFor(a, b, f) Nor((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define NFzero(a,f) memset((a)+F_s[f], 0, F_l[f]) -#define NFpack(a, f) Npack((a)+F_s[f], F_l[f]) -#define NFinc(a, f) Ninc(a, F_l[f], F_s[f]) -#define NFdec(a, f) Ndec(a, F_l[f], F_s[f]) -#define NFnot(a, f) Nnot((a)+F_s[f], F_l[f]) -#define NFneg(a, f) Nneg((a)+F_s[f], F_l[f]) -#define NFsl(a, f) Nsl((a)+F_s[f], F_l[f]) -#define NFsr(a, f) Nsr((a)+F_s[f], F_l[f]) -#define NFsrb(a, f) Nsrb((a)+F_s[f], F_l[f]) -#define TFe(a, b, f) Te((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define TFa(a, b, f) Ta((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define TFb(a, b, f) Tb((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define TFz(a, f) Tz((a)+F_s[f], F_l[f]) -#define TFne(a, b, f) Tne((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define TFae(a, b, f) Tae((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define TFbe(a, b, f) Tbe((a)+F_s[f], (b)+F_s[f], F_l[f]) -#define TFnz(a, f) Tnz((a)+F_s[f], F_l[f]) - -static __inline LPBYTE FASTPTR(DWORD d) -{ - static BYTE pbyNULL[21]; - LPBYTE lpbyPage; - DWORD u, v; - - d &= 0xFFFFF; // handle address overflows - - u = d >> 12; // page - v = d & 0xFFF; // offset - - if ( !(Chipset.IOCfig && ((d & 0xFFFC0) == Chipset.IOBase)) - && RMap[u] != NULL // page valid - && ( v < 0x1000 - ARRAYSIZEOF(pbyNULL) // complete opcode inside page - // or next page continue linear addressing - || (RMap[u] + 0x1000 == RMap[(u+1) & (ARRAYSIZEOF(RMap)-1)]) - ) - ) - { - lpbyPage = RMap[u] + v; // full address - } - else - { - lpbyPage = pbyNULL; // memory allocation - Npeek(lpbyPage, d, ARRAYSIZEOF(pbyNULL)); // fill with data (LAHEX + 16 digits = longest opcode) - } - return lpbyPage; -} - -static __inline void rstkpush(DWORD d) -{ - Chipset.rstk[Chipset.rstkp] = d; - Chipset.rstkp=(Chipset.rstkp+1)&7; -} - -static __inline DWORD rstkpop(VOID) -{ - DWORD r; - - Chipset.rstkp=(Chipset.rstkp-1)&7; - r = Chipset.rstk[Chipset.rstkp]; - Chipset.rstk[Chipset.rstkp] = 0; - return r; -} - -static __inline DWORD Npack(BYTE *a, UINT s) -{ - DWORD r = 0; - - while (s--) r = (r<<4)|a[s]; - return r; -} - -static __inline VOID Nunpack(BYTE *a, DWORD b, UINT s) -{ - for (; s>0; --s) { *a++ = (BYTE)(b&0xf); b>>=4; } -} - -static __inline void Nxchg(BYTE *a, BYTE *b, UINT s) -{ - BYTE X[16]; - - memcpy(X, b, s); - memcpy(b, a, s); - memcpy(a, X, s); -} - -static __inline void Ninc(BYTE *a, UINT s, UINT d) -{ - UINT i; - - if (Chipset.mode_dec) - { - BYTE c = 1; - for (i=d; iA)); - - // illegal number in dec mode - if (a[i] >= 10) a[i] &= 0x7; - - a[i] += c; - c = (a[i] >= 10); - if (c) a[i] -= 10; - } - Chipset.carry = (c==1); - } - else - { - for (i=d; iA)); - - a[i]++; - if (a[i] < 16) - { - Chipset.carry = FALSE; - return; - } - a[i] -= 16; - } - Chipset.carry = TRUE; - } -} - -static __inline void Ninc16(BYTE *a, UINT s, UINT d) -{ - UINT i; - - for (i=d; iA)); - - a[i]--; - if ((a[i] & 0xF0) == 0) // check overflow - { - Chipset.carry = FALSE; - return; - } - a[i] += cBase; - } - Chipset.carry = TRUE; -} - -static __inline void Ndec16(BYTE *a, UINT s, UINT d) -{ - UINT i; - - for (i=d; i= cBase) a[i] &= 0x7; - - a[i] += b[i] + c; - if (a[i] >= cBase) - { - a[i] -= cBase; - c = 1; - } - else - c = 0; - } - Chipset.carry = (c==1); -} - -static __inline void Nsub(BYTE *a, BYTE *b, UINT s) -{ - UINT i; - BYTE c = 0; - BYTE cBase = Chipset.mode_dec ? 10 : 16; - - for (i=0; i 0); // check for non-zero digit - for (--a[i]; i>= 1; - *a |= ((a[1] & 1) << 3); - a++; - } - *a >>= 1; -} - -static __inline void Nbit0(BYTE *a, UINT b) -{ - a[b>>2] &= ~(1<<(b&3)); -} - -static __inline void Nbit1(BYTE *a, UINT b) -{ - a[b>>2] |= 1<<(b&3); -} - -static __inline void Tbit0(BYTE *a, UINT b) -{ - Chipset.carry = ((a[b>>2] & (1<<(b&3))) == 0); -} - -static __inline void Tbit1(BYTE *a, UINT b) -{ - Chipset.carry = ((a[b>>2] & (1<<(b&3))) != 0); -} - -static __inline void Te(BYTE *a, BYTE *b, UINT s) -{ - while (s--) - { - if (a[s]!=b[s]) - { - Chipset.carry = FALSE; - return; - } - } - Chipset.carry = TRUE; -} - -static __inline void Tne(BYTE *a, BYTE *b, UINT s) -{ - while (s--) - { - if (a[s]!=b[s]) - { - Chipset.carry = TRUE; - return; - } - } - Chipset.carry = FALSE; -} - -static __inline void Tz(BYTE *a, UINT s) -{ - while (s--) - { - if (a[s]!=0) - { - Chipset.carry = FALSE; - return; - } - } - Chipset.carry = TRUE; -} - -static __inline void Tnz(BYTE *a, UINT s) -{ - while (s--) - { - if (a[s]!=0) - { - Chipset.carry = TRUE; - return; - } - } - Chipset.carry = FALSE; -} - -static __inline void Ta(BYTE *a, BYTE *b, UINT s) -{ - while (--s) if (a[s]!=b[s]) break; - Chipset.carry = (a[s]>b[s]); -} - -static __inline void Tb(BYTE *a, BYTE *b, UINT s) -{ - while (--s) if (a[s]!=b[s]) break; - Chipset.carry = (a[s]=b[s]); -} - -static __inline void Tbe(BYTE *a, BYTE *b, UINT s) -{ - while (--s) if (a[s]!=b[s]) break; - Chipset.carry = (a[s]<=b[s]); -} +/* + * ops.h + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ + +#define NFunpack(a, b, f) Nunpack((a)+F_s[f], b, F_l[f]) +#define NFread(a, b, f) Nread((a)+F_s[f], b, F_l[f]) +#define NFwrite(a, b, f) Nwrite((a)+F_s[f], b, F_l[f]) +#define NFcopy(a, b, f) memcpy((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define NFxchg(a, b, f) Nxchg((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define NFadd(a, b, f) Nadd((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define NFsub(a, b, f) Nsub((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define NFrsub(a, b, f) Nrsub((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define NFand(a, b, f) Nand((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define NFor(a, b, f) Nor((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define NFzero(a,f) memset((a)+F_s[f], 0, F_l[f]) +#define NFpack(a, f) Npack((a)+F_s[f], F_l[f]) +#define NFinc(a, f) Ninc(a, F_l[f], F_s[f]) +#define NFdec(a, f) Ndec(a, F_l[f], F_s[f]) +#define NFnot(a, f) Nnot((a)+F_s[f], F_l[f]) +#define NFneg(a, f) Nneg((a)+F_s[f], F_l[f]) +#define NFsl(a, f) Nsl((a)+F_s[f], F_l[f]) +#define NFsr(a, f) Nsr((a)+F_s[f], F_l[f]) +#define NFsrb(a, f) Nsrb((a)+F_s[f], F_l[f]) +#define TFe(a, b, f) Te((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define TFa(a, b, f) Ta((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define TFb(a, b, f) Tb((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define TFz(a, f) Tz((a)+F_s[f], F_l[f]) +#define TFne(a, b, f) Tne((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define TFae(a, b, f) Tae((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define TFbe(a, b, f) Tbe((a)+F_s[f], (b)+F_s[f], F_l[f]) +#define TFnz(a, f) Tnz((a)+F_s[f], F_l[f]) + +static __inline LPBYTE FASTPTR(DWORD d) +{ + static BYTE pbyNULL[21]; + LPBYTE lpbyPage; + DWORD u, v; + + d &= 0xFFFFF; // handle address overflows + + u = d >> 12; // page + v = d & 0xFFF; // offset + + if ( !(Chipset.IOCfig && ((d & 0xFFFC0) == Chipset.IOBase)) + && RMap[u] != NULL // page valid + && ( v < 0x1000 - ARRAYSIZEOF(pbyNULL) // complete opcode inside page + // or next page continue linear addressing + || (RMap[u] + 0x1000 == RMap[(u+1) & (ARRAYSIZEOF(RMap)-1)]) + ) + ) + { + lpbyPage = RMap[u] + v; // full address + } + else + { + lpbyPage = pbyNULL; // memory allocation + Npeek(lpbyPage, d, ARRAYSIZEOF(pbyNULL)); // fill with data (LAHEX + 16 digits = longest opcode) + } + return lpbyPage; +} + +static __inline void rstkpush(DWORD d) +{ + Chipset.rstk[Chipset.rstkp] = d; + Chipset.rstkp=(Chipset.rstkp+1)&7; +} + +static __inline DWORD rstkpop(VOID) +{ + DWORD r; + + Chipset.rstkp=(Chipset.rstkp-1)&7; + r = Chipset.rstk[Chipset.rstkp]; + Chipset.rstk[Chipset.rstkp] = 0; + return r; +} + +static __inline DWORD Npack(BYTE *a, UINT s) +{ + DWORD r = 0; + + while (s--) r = (r<<4)|a[s]; + return r; +} + +static __inline VOID Nunpack(BYTE *a, DWORD b, UINT s) +{ + for (; s>0; --s) { *a++ = (BYTE)(b&0xf); b>>=4; } +} + +static __inline void Nxchg(BYTE *a, BYTE *b, UINT s) +{ + BYTE X[16]; + + memcpy(X, b, s); + memcpy(b, a, s); + memcpy(a, X, s); +} + +static __inline void Ninc(BYTE *a, UINT s, UINT d) +{ + UINT i; + + if (Chipset.mode_dec) + { + BYTE c = 1; + for (i=d; iA)); + + // illegal number in dec mode + if (a[i] >= 10) a[i] &= 0x7; + + a[i] += c; + c = (a[i] >= 10); + if (c) a[i] -= 10; + } + Chipset.carry = (c==1); + } + else + { + for (i=d; iA)); + + a[i]++; + if (a[i] < 16) + { + Chipset.carry = FALSE; + return; + } + a[i] -= 16; + } + Chipset.carry = TRUE; + } +} + +static __inline void Ninc16(BYTE *a, UINT s, UINT d) +{ + UINT i; + + for (i=d; iA)); + + a[i]--; + if ((a[i] & 0xF0) == 0) // check overflow + { + Chipset.carry = FALSE; + return; + } + a[i] += cBase; + } + Chipset.carry = TRUE; +} + +static __inline void Ndec16(BYTE *a, UINT s, UINT d) +{ + UINT i; + + for (i=d; i= cBase) a[i] &= 0x7; + + a[i] += b[i] + c; + if (a[i] >= cBase) + { + a[i] -= cBase; + c = 1; + } + else + c = 0; + } + Chipset.carry = (c==1); +} + +static __inline void Nsub(BYTE *a, BYTE *b, UINT s) +{ + UINT i; + BYTE c = 0; + BYTE cBase = Chipset.mode_dec ? 10 : 16; + + for (i=0; i 0); // check for non-zero digit + for (--a[i]; i>= 1; + *a |= ((a[1] & 1) << 3); + a++; + } + *a >>= 1; +} + +static __inline void Nbit0(BYTE *a, UINT b) +{ + a[b>>2] &= ~(1<<(b&3)); +} + +static __inline void Nbit1(BYTE *a, UINT b) +{ + a[b>>2] |= 1<<(b&3); +} + +static __inline void Tbit0(BYTE *a, UINT b) +{ + Chipset.carry = ((a[b>>2] & (1<<(b&3))) == 0); +} + +static __inline void Tbit1(BYTE *a, UINT b) +{ + Chipset.carry = ((a[b>>2] & (1<<(b&3))) != 0); +} + +static __inline void Te(BYTE *a, BYTE *b, UINT s) +{ + while (s--) + { + if (a[s]!=b[s]) + { + Chipset.carry = FALSE; + return; + } + } + Chipset.carry = TRUE; +} + +static __inline void Tne(BYTE *a, BYTE *b, UINT s) +{ + while (s--) + { + if (a[s]!=b[s]) + { + Chipset.carry = TRUE; + return; + } + } + Chipset.carry = FALSE; +} + +static __inline void Tz(BYTE *a, UINT s) +{ + while (s--) + { + if (a[s]!=0) + { + Chipset.carry = FALSE; + return; + } + } + Chipset.carry = TRUE; +} + +static __inline void Tnz(BYTE *a, UINT s) +{ + while (s--) + { + if (a[s]!=0) + { + Chipset.carry = TRUE; + return; + } + } + Chipset.carry = FALSE; +} + +static __inline void Ta(BYTE *a, BYTE *b, UINT s) +{ + while (--s) if (a[s]!=b[s]) break; + Chipset.carry = (a[s]>b[s]); +} + +static __inline void Tb(BYTE *a, BYTE *b, UINT s) +{ + while (--s) if (a[s]!=b[s]) break; + Chipset.carry = (a[s]=b[s]); +} + +static __inline void Tbe(BYTE *a, BYTE *b, UINT s) +{ + while (--s) if (a[s]!=b[s]) break; + Chipset.carry = (a[s]<=b[s]); +} diff --git a/Sources/Emu48/pch.c b/Sources/Emu48/PCH.C similarity index 86% rename from Sources/Emu48/pch.c rename to Sources/Emu48/PCH.C index 348fa58..c20bfab 100644 --- a/Sources/Emu48/pch.c +++ b/Sources/Emu48/PCH.C @@ -1,5 +1,5 @@ -// -// PCH.C -// - -#include "pch.h" +// +// PCH.C +// + +#include "pch.h" diff --git a/Sources/Emu48/pch.h b/Sources/Emu48/PCH.H similarity index 96% rename from Sources/Emu48/pch.h rename to Sources/Emu48/PCH.H index 80639fa..555374a 100644 --- a/Sources/Emu48/pch.h +++ b/Sources/Emu48/PCH.H @@ -1,112 +1,112 @@ -// -// PCH.H -// - -#define _WIN32_IE 0x0200 -#define _CRT_SECURE_NO_DEPRECATE -#define _CRTDBG_MAP_ALLOC -#define _WINSOCK_DEPRECATED_NO_WARNINGS - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined VERIFY -#if defined _DEBUG -#define VERIFY(f) _ASSERT(f) -#else // _DEBUG -#define VERIFY(f) ((VOID)(f)) -#endif // _DEBUG -#endif // _VERIFY - -#if !defined INVALID_SET_FILE_POINTER -#define INVALID_SET_FILE_POINTER ((DWORD)-1) -#endif - -#if !defined INVALID_FILE_ATTRIBUTES -#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif - -#if !defined GWLP_USERDATA -#define GWLP_USERDATA GWL_USERDATA -#endif - -#if !defined GCLP_HCURSOR -#define GCLP_HCURSOR GCL_HCURSOR -#endif - -#if !defined IDC_HAND // Win2k specific definition -#define IDC_HAND MAKEINTRESOURCE(32649) -#endif - -#if _MSC_VER <= 1200 // missing type definition in the MSVC6.0 SDK and earlier -#define __unaligned -#define SetWindowLongPtr SetWindowLong -#define GetWindowLongPtr GetWindowLong -#define SetClassLongPtr SetClassLong -#define GetClassLongPtr GetClassLong -typedef SIZE_T DWORD_PTR, *PDWORD_PTR; -typedef ULONG ULONG_PTR, *PULONG_PTR; -typedef LONG LONG_PTR, *PLONG_PTR; -#endif - -#if !defined PROCESS_POWER_THROTTLING_CURRENT_VERSION -#define PROCESS_POWER_THROTTLING_CURRENT_VERSION 1 -#endif - -#if !defined PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION -#define PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION 0x04 -#endif - -#if _MSC_VER <= 1900 // add until VS2015 from processthreadsapi.h -enum { ProcessPowerThrottling = 4 }; - -typedef struct _PROCESS_POWER_THROTTLING_STATE { - ULONG Version; - ULONG ControlMask; - ULONG StateMask; -} PROCESS_POWER_THROTTLING_STATE, * PPROCESS_POWER_THROTTLING_STATE; -#endif - -#if _MSC_VER >= 1400 // valid for VS2005 and later -#if defined _M_IX86 -#pragma comment(linker,"/manifestdependency:\" \ - type='win32' \ - name='Microsoft.Windows.Common-Controls' \ - version='6.0.0.0' processorArchitecture='x86' \ - publicKeyToken='6595b64144ccf1df' \ - language='*'\"") -#elif defined _M_IA64 -#pragma comment(linker,"/manifestdependency:\" \ - type='win32' \ - name='Microsoft.Windows.Common-Controls' \ - version='6.0.0.0' processorArchitecture='ia64' \ - publicKeyToken='6595b64144ccf1df' \ - language='*'\"") -#elif defined _M_X64 -#pragma comment(linker,"/manifestdependency:\" \ - type='win32' \ - name='Microsoft.Windows.Common-Controls' \ - version='6.0.0.0' processorArchitecture='amd64' \ - publicKeyToken='6595b64144ccf1df' \ - language='*'\"") -#else -#pragma comment(linker,"/manifestdependency:\" \ - type='win32' \ - name='Microsoft.Windows.Common-Controls' \ - version='6.0.0.0' processorArchitecture='*' \ - publicKeyToken='6595b64144ccf1df' \ - language='*'\"") -#endif -#endif +// +// PCH.H +// + +#define _WIN32_IE 0x0200 +#define _CRT_SECURE_NO_DEPRECATE +#define _CRTDBG_MAP_ALLOC +#define _WINSOCK_DEPRECATED_NO_WARNINGS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined VERIFY +#if defined _DEBUG +#define VERIFY(f) _ASSERT(f) +#else // _DEBUG +#define VERIFY(f) ((VOID)(f)) +#endif // _DEBUG +#endif // _VERIFY + +#if !defined INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + +#if !defined INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif + +#if !defined GWLP_USERDATA +#define GWLP_USERDATA GWL_USERDATA +#endif + +#if !defined GCLP_HCURSOR +#define GCLP_HCURSOR GCL_HCURSOR +#endif + +#if !defined IDC_HAND // Win2k specific definition +#define IDC_HAND MAKEINTRESOURCE(32649) +#endif + +#if _MSC_VER <= 1200 // missing type definition in the MSVC6.0 SDK and earlier +#define __unaligned +#define SetWindowLongPtr SetWindowLong +#define GetWindowLongPtr GetWindowLong +#define SetClassLongPtr SetClassLong +#define GetClassLongPtr GetClassLong +typedef SIZE_T DWORD_PTR, *PDWORD_PTR; +typedef ULONG ULONG_PTR, *PULONG_PTR; +typedef LONG LONG_PTR, *PLONG_PTR; +#endif + +#if !defined PROCESS_POWER_THROTTLING_CURRENT_VERSION +#define PROCESS_POWER_THROTTLING_CURRENT_VERSION 1 +#endif + +#if !defined PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION +#define PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION 0x04 +#endif + +#if _MSC_VER <= 1900 // add until VS2015 from processthreadsapi.h +enum { ProcessPowerThrottling = 4 }; + +typedef struct _PROCESS_POWER_THROTTLING_STATE { + ULONG Version; + ULONG ControlMask; + ULONG StateMask; +} PROCESS_POWER_THROTTLING_STATE, * PPROCESS_POWER_THROTTLING_STATE; +#endif + +#if _MSC_VER >= 1400 // valid for VS2005 and later +#if defined _M_IX86 +#pragma comment(linker,"/manifestdependency:\" \ + type='win32' \ + name='Microsoft.Windows.Common-Controls' \ + version='6.0.0.0' processorArchitecture='x86' \ + publicKeyToken='6595b64144ccf1df' \ + language='*'\"") +#elif defined _M_IA64 +#pragma comment(linker,"/manifestdependency:\" \ + type='win32' \ + name='Microsoft.Windows.Common-Controls' \ + version='6.0.0.0' processorArchitecture='ia64' \ + publicKeyToken='6595b64144ccf1df' \ + language='*'\"") +#elif defined _M_X64 +#pragma comment(linker,"/manifestdependency:\" \ + type='win32' \ + name='Microsoft.Windows.Common-Controls' \ + version='6.0.0.0' processorArchitecture='amd64' \ + publicKeyToken='6595b64144ccf1df' \ + language='*'\"") +#else +#pragma comment(linker,"/manifestdependency:\" \ + type='win32' \ + name='Microsoft.Windows.Common-Controls' \ + version='6.0.0.0' processorArchitecture='*' \ + publicKeyToken='6595b64144ccf1df' \ + language='*'\"") +#endif +#endif diff --git a/Sources/Emu48/pngcrc.c b/Sources/Emu48/PNGCRC.C similarity index 98% rename from Sources/Emu48/pngcrc.c rename to Sources/Emu48/PNGCRC.C index 9922bc4..d8493c5 100644 --- a/Sources/Emu48/pngcrc.c +++ b/Sources/Emu48/PNGCRC.C @@ -1,57 +1,57 @@ -/* - * pngcrc.c - * - * This file is part of Emu48 - * - * Copyright (C) 2023 Christoph Gießelink - * - */ -#include "pch.h" - -/* CRC polynomial: 0xedb88320 */ -static const unsigned lodepng_crc32_table[256] = -{ - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -}; - -/*Return the CRC of the bytes buf[0..len-1].*/ -unsigned lodepng_crc32(const unsigned char* data, size_t length) -{ - unsigned r = 0xffffffffu; - while (length--) - { - r = lodepng_crc32_table[(r ^ *data++) & 0xffu] ^ (r >> 8u); - } - return ~r; -} +/* + * pngcrc.c + * + * This file is part of Emu48 + * + * Copyright (C) 2023 Christoph Gießelink + * + */ +#include "pch.h" + +/* CRC polynomial: 0xedb88320 */ +static const unsigned lodepng_crc32_table[256] = +{ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +/*Return the CRC of the bytes buf[0..len-1].*/ +unsigned lodepng_crc32(const unsigned char* data, size_t length) +{ + unsigned r = 0xffffffffu; + while (length--) + { + r = lodepng_crc32_table[(r ^ *data++) & 0xffu] ^ (r >> 8u); + } + return ~r; +} diff --git a/Sources/Emu48/redeye.c b/Sources/Emu48/REDEYE.C similarity index 95% rename from Sources/Emu48/redeye.c rename to Sources/Emu48/REDEYE.C index 262d2ba..2c47163 100644 --- a/Sources/Emu48/redeye.c +++ b/Sources/Emu48/REDEYE.C @@ -1,177 +1,177 @@ -/* - * redeye.c - * - * This file is part of Emu48 - * - * Copyright (C) 2011 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" -#include "io.h" - -#define ERR_CHAR 127 // character for transfer error - -#define H1 0x78 -#define H2 0xE6 -#define H3 0xD5 -#define H4 0x8B - -// HP redeye correction masks -static CONST BYTE byEmask[] = { H1, H2, H3, H4 }; - -static __inline UINT MAX(UINT a, UINT b) -{ - return (a>b)?a:b; -} - -static __inline BYTE Parity(BYTE b) -{ - b ^= (b >> 4); - b ^= (b >> 2); - b ^= (b >> 1); - return b & 1; -} - -static __inline BYTE CreateCorrectionBits(BYTE b) -{ - UINT i; - BYTE byVal = 0; - - for (i = 0; i < ARRAYSIZEOF(byEmask);++i) - { - byVal <<= 1; - byVal |= Parity((BYTE) (b & byEmask[i])); - } - return byVal; -} - -static __inline WORD CorrectData(WORD wData,WORD wMissed) -{ - while ((wMissed & 0xFF) != 0) // clear every missed bit in data area - { - BYTE byBitMask; - - // detect valid H(i) mask - WORD wMi = 0x800; // first M(i) bit - INT i = 0; // index to first H(i) mask - - while (TRUE) - { - if ((wMissed & wMi) == 0) // possible valid mask - { - _ASSERT(i < ARRAYSIZEOF(byEmask)); - - // select bit to correct - byBitMask = wMissed & byEmask[i]; - - if (Parity(byBitMask)) // only one bit set (parity odd) - break; // -> valid H(i) mask - } - - wMi >>= 1; // next M(i) bit - i++; // next H(i) mask - } - - // correct bit with H(i) mask - wMissed ^= byBitMask; // clear this missed bit - - // parity odd -> wrong data value - if (Parity((BYTE) ((wData & byEmask[i]) ^ ((wData & wMi) >> 8)))) - wData ^= byBitMask; // correct value - } - return wData & 0xFF; // only data byte is correct -} - -VOID IrPrinter(BYTE c) -{ - static INT nFrame = 0; // frame counter - static DWORD dwData = 0; // half bit data container - static INT nStart = 0; // frame counter disabled - - BOOL bLSRQ; - - dwData = (dwData << 1) | (c & LBO); // grab the last 32 bit send through IR - - // Led Service ReQuest on Led Buffer Empty enabled - bLSRQ = (Chipset.IORam[LCR] & ELBE) != 0; - - IOBit(SRQ2,LSRQ,bLSRQ); // update LSRQ bit - if (bLSRQ) // interrupt on Led Buffer Empty enabled - { - Chipset.SoftInt = TRUE; // execute interrupt - bInterrupt = TRUE; - } - - // HP40G and HP49G have no IR transmitter Led - if ((cCurrentRomType == 'E' && nCurrentClass == 40) || cCurrentRomType == 'X') - return; - - if (nFrame == 0) // waiting for start bit condition - { - if ((dwData & 0x3F) == 0x07) // start bit condition (000111 pattern) - { - nStart = 1; // enable frame counter - } - } - - if (nFrame == 24) // 24 half bit received - { - INT i; - - WORD wData = 0; // data container - WORD wMissed = 0; // missed bit container - INT nCount = 0; // no. of missed bits - - nFrame = 0; // reset for next character - nStart = 0; // disable frame counter - - // separate to data and missed bits - for (i = 0; i < 12; ++i) // 12 bit frames - { - BYTE b = (BYTE) (dwData & 3); // last 2 half bits - - if (b == 0x0 || b == 0x3) // illegal half bit combination - { - wMissed |= (1 << i); // this is a missed bit - ++nCount; // incr. number of missed bits - } - else // valid data bit - { - wData |= ((b >> 1) << i); // add data bit - } - dwData >>= 2; // next 2 half bits - } - - if (nCount <= 2) // error can be fixed - { - BYTE byOrgParity,byNewParity; - - byOrgParity = wData >> 8; // the original parity information with missed bits - byNewParity = ~(wMissed >> 8); // missed bit mask for recalculated parity - - if (nCount > 0) // error correction - { - wData = CorrectData(wData,wMissed); - } - - wData &= 0xFF; // remove parity information - - // recalculate parity data - byNewParity &= CreateCorrectionBits((BYTE) wData); - - // wrong parity - if (byOrgParity != byNewParity) - wData = ERR_CHAR; // character for transfer error - } - else - { - wData = ERR_CHAR; // character for transfer error - } - - SendByteUdp((BYTE) wData); // send data byte - return; - } - nFrame += nStart; // next frame - return; -} +/* + * redeye.c + * + * This file is part of Emu48 + * + * Copyright (C) 2011 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" +#include "io.h" + +#define ERR_CHAR 127 // character for transfer error + +#define H1 0x78 +#define H2 0xE6 +#define H3 0xD5 +#define H4 0x8B + +// HP redeye correction masks +static CONST BYTE byEmask[] = { H1, H2, H3, H4 }; + +static __inline UINT MAX(UINT a, UINT b) +{ + return (a>b)?a:b; +} + +static __inline BYTE Parity(BYTE b) +{ + b ^= (b >> 4); + b ^= (b >> 2); + b ^= (b >> 1); + return b & 1; +} + +static __inline BYTE CreateCorrectionBits(BYTE b) +{ + UINT i; + BYTE byVal = 0; + + for (i = 0; i < ARRAYSIZEOF(byEmask);++i) + { + byVal <<= 1; + byVal |= Parity((BYTE) (b & byEmask[i])); + } + return byVal; +} + +static __inline WORD CorrectData(WORD wData,WORD wMissed) +{ + while ((wMissed & 0xFF) != 0) // clear every missed bit in data area + { + BYTE byBitMask; + + // detect valid H(i) mask + WORD wMi = 0x800; // first M(i) bit + INT i = 0; // index to first H(i) mask + + while (TRUE) + { + if ((wMissed & wMi) == 0) // possible valid mask + { + _ASSERT(i < ARRAYSIZEOF(byEmask)); + + // select bit to correct + byBitMask = wMissed & byEmask[i]; + + if (Parity(byBitMask)) // only one bit set (parity odd) + break; // -> valid H(i) mask + } + + wMi >>= 1; // next M(i) bit + i++; // next H(i) mask + } + + // correct bit with H(i) mask + wMissed ^= byBitMask; // clear this missed bit + + // parity odd -> wrong data value + if (Parity((BYTE) ((wData & byEmask[i]) ^ ((wData & wMi) >> 8)))) + wData ^= byBitMask; // correct value + } + return wData & 0xFF; // only data byte is correct +} + +VOID IrPrinter(BYTE c) +{ + static INT nFrame = 0; // frame counter + static DWORD dwData = 0; // half bit data container + static INT nStart = 0; // frame counter disabled + + BOOL bLSRQ; + + dwData = (dwData << 1) | (c & LBO); // grab the last 32 bit send through IR + + // Led Service ReQuest on Led Buffer Empty enabled + bLSRQ = (Chipset.IORam[LCR] & ELBE) != 0; + + IOBit(SRQ2,LSRQ,bLSRQ); // update LSRQ bit + if (bLSRQ) // interrupt on Led Buffer Empty enabled + { + Chipset.SoftInt = TRUE; // execute interrupt + bInterrupt = TRUE; + } + + // HP40G and HP49G have no IR transmitter Led + if ((cCurrentRomType == 'E' && nCurrentClass == 40) || cCurrentRomType == 'X') + return; + + if (nFrame == 0) // waiting for start bit condition + { + if ((dwData & 0x3F) == 0x07) // start bit condition (000111 pattern) + { + nStart = 1; // enable frame counter + } + } + + if (nFrame == 24) // 24 half bit received + { + INT i; + + WORD wData = 0; // data container + WORD wMissed = 0; // missed bit container + INT nCount = 0; // no. of missed bits + + nFrame = 0; // reset for next character + nStart = 0; // disable frame counter + + // separate to data and missed bits + for (i = 0; i < 12; ++i) // 12 bit frames + { + BYTE b = (BYTE) (dwData & 3); // last 2 half bits + + if (b == 0x0 || b == 0x3) // illegal half bit combination + { + wMissed |= (1 << i); // this is a missed bit + ++nCount; // incr. number of missed bits + } + else // valid data bit + { + wData |= ((b >> 1) << i); // add data bit + } + dwData >>= 2; // next 2 half bits + } + + if (nCount <= 2) // error can be fixed + { + BYTE byOrgParity,byNewParity; + + byOrgParity = wData >> 8; // the original parity information with missed bits + byNewParity = ~(wMissed >> 8); // missed bit mask for recalculated parity + + if (nCount > 0) // error correction + { + wData = CorrectData(wData,wMissed); + } + + wData &= 0xFF; // remove parity information + + // recalculate parity data + byNewParity &= CreateCorrectionBits((BYTE) wData); + + // wrong parity + if (byOrgParity != byNewParity) + wData = ERR_CHAR; // character for transfer error + } + else + { + wData = ERR_CHAR; // character for transfer error + } + + SendByteUdp((BYTE) wData); // send data byte + return; + } + nFrame += nStart; // next frame + return; +} diff --git a/Sources/Emu48/resource.h b/Sources/Emu48/RESOURCE.H similarity index 74% rename from Sources/Emu48/resource.h rename to Sources/Emu48/RESOURCE.H index edfc547..601e56a 100644 --- a/Sources/Emu48/resource.h +++ b/Sources/Emu48/RESOURCE.H @@ -1,263 +1,268 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by Emu48.rc -// -#define IDM_DEBUG_SETTINGS 0x0010 -#define IDI_EMU48 100 -#define IDR_MENU 101 -#define IDM_MENU 102 -#define IDR_DEBUG 103 -#define IDR_DEBUG_TOOLBAR 104 -#define IDR_DEBUG_CODE 105 -#define IDR_DEBUG_MEM 106 -#define IDR_DEBUG_STACK 107 -#define IDB_CHECKBOX 108 -#define IDD_ABOUT 109 -#define IDD_SET_GENERAL 110 -#define IDD_SET_MEMORY 111 -#define IDD_SET_PERIPHERAL 112 -#define IDD_CHOOSEKML 113 -#define IDD_KMLLOG 114 -#define IDD_DISASM 115 -#define IDD_DEBUG 116 -#define IDD_NEWVALUE 117 -#define IDD_ENTERADR 118 -#define IDD_BREAKEDIT 119 -#define IDD_ENTERBREAK 120 -#define IDD_INSTRUCTIONS 121 -#define IDD_WRITEONLYREG 122 -#define IDD_FIND 123 -#define IDD_PROFILE 124 -#define IDD_RPLVIEW 125 -#define IDD_MACROSET 126 -#define IDD_DEBUG_MEMSAVE 127 -#define IDD_DEBUG_MEMLOAD 128 -#define IDD_DEBUG_SETTINGS 129 -#define IDD_TRACE 130 -#define IDC_REALSPEED 1000 -#define IDC_GRAYSCALE 1001 -#define IDC_ALWAYSONTOP 1002 -#define IDC_ACTFOLLOWSMOUSE 1003 -#define IDC_SINGLEINSTANCE 1004 -#define IDC_AUTOSAVE 1005 -#define IDC_AUTOSAVEONEXIT 1006 -#define IDC_OBJECTLOADWARNING 1007 -#define IDC_SHOWTITLE 1008 -#define IDC_SHOWMENU 1009 -#define IDC_ALWAYSDISPLOG 1010 -#define IDC_PORT1EN 1011 -#define IDC_PORT1WR 1012 -#define IDC_PORT2ISSHARED 1013 -#define IDC_PORT2WR 1014 -#define IDC_PORT2 1015 -#define IDC_PORT2LOAD 1016 -#define IDC_IR_ADDR 1017 -#define IDC_IR_PORT 1018 -#define IDC_WIRE 1019 -#define IDC_IR 1020 -#define IDC_EMUDIR 1021 -#define IDC_EMUDIRSEL 1022 -#define IDC_UPDATE 1023 -#define IDC_KMLSCRIPT 1024 -#define IDC_AUTHOR 1025 -#define IDC_TITLE 1026 -#define IDC_KMLLOG 1027 -#define IDC_VERSION 1028 -#define IDC_LICENSE 1029 -#define IDC_DISASM_WIN 1030 -#define IDC_DISASM_MODE_TEXT 1031 -#define IDC_DISASM_MODE 1032 -#define IDC_DISASM_MODULE 1033 -#define IDC_DISASM_HP 1034 -#define IDC_DISASM_CLASS 1035 -#define IDC_ADDRESS 1036 -#define IDC_DISASM_ADR 1037 -#define IDC_DISASM_NEXT 1038 -#define IDC_DISASM_COPY 1039 -#define IDC_DEBUG_CODE 1040 -#define IDC_STATIC_CODE 1041 -#define IDC_STATIC_REGISTERS 1042 -#define IDC_STATIC_MEMORY 1043 -#define IDC_STATIC_STACK 1044 -#define IDC_REG_A 1045 -#define IDC_REG_B 1046 -#define IDC_REG_C 1047 -#define IDC_REG_D 1048 -#define IDC_REG_R0 1049 -#define IDC_REG_R1 1050 -#define IDC_REG_R2 1051 -#define IDC_REG_R3 1052 -#define IDC_REG_R4 1053 -#define IDC_REG_D0 1054 -#define IDC_REG_D1 1055 -#define IDC_REG_P 1056 -#define IDC_REG_PC 1057 -#define IDC_REG_OUT 1058 -#define IDC_REG_IN 1059 -#define IDC_REG_ST 1060 -#define IDC_REG_CY 1061 -#define IDC_REG_MODE 1062 -#define IDC_REG_MP 1063 -#define IDC_REG_SR 1064 -#define IDC_REG_SB 1065 -#define IDC_REG_XM 1066 -#define IDC_MISC_INT 1067 -#define IDC_MISC_KEY 1068 -#define IDC_MISC_BS 1069 -#define IDC_NEWVALUE 1070 -#define IDC_ENTERADR 1071 -#define IDC_DEBUG_MEM 1072 -#define IDC_DEBUG_MEM_ADDR 1073 -#define IDC_DEBUG_MEM_COL0 1074 -#define IDC_DEBUG_MEM_COL1 1075 -#define IDC_DEBUG_MEM_COL2 1076 -#define IDC_DEBUG_MEM_COL3 1077 -#define IDC_DEBUG_MEM_COL4 1078 -#define IDC_DEBUG_MEM_COL5 1079 -#define IDC_DEBUG_MEM_COL6 1080 -#define IDC_DEBUG_MEM_COL7 1081 -#define IDC_DEBUG_MEM_TEXT 1082 -#define IDC_DEBUG_DATA_FILE 1083 -#define IDC_DEBUG_DATA_BUT 1084 -#define IDC_DEBUG_DATA_STARTADDR 1085 -#define IDC_DEBUG_DATA_ENDADDR 1086 -#define IDC_DEBUG_SET_SYMB 1087 -#define IDC_DEBUG_SET_MODEL 1088 -#define IDC_DEBUG_SET_FILE 1089 -#define IDC_DEBUG_SET_BROWSE 1090 -#define IDC_DEBUG_STACK 1091 -#define IDC_STATIC_BREAKPOINT 1092 -#define IDC_BREAKEDIT_ADD 1093 -#define IDC_BREAKEDIT_DELETE 1094 -#define IDC_BREAKEDIT_WND 1095 -#define IDC_STATIC_MMU 1096 -#define IDC_MMU_IO_A 1097 -#define IDC_MMU_NCE2_A 1098 -#define IDC_MMU_CE1_A 1099 -#define IDC_MMU_CE2_A 1100 -#define IDC_MMU_NCE3_A 1101 -#define IDC_MMU_IO_S 1102 -#define IDC_MMU_CE1_S 1103 -#define IDC_MMU_CE2_S 1104 -#define IDC_MMU_NCE2_S 1105 -#define IDC_MMU_NCE3_S 1106 -#define IDC_STATIC_MISC 1107 -#define IDC_MISC_BS_TXT 1108 -#define IDC_INSTR_TEXT 1109 -#define IDC_INSTR_CODE 1110 -#define IDC_INSTR_COPY 1111 -#define IDC_INSTR_CLEAR 1112 -#define IDC_PROFILE_LASTCYCLES 1113 -#define IDC_PROFILE_LASTTIME 1114 -#define IDC_BPCODE 1115 -#define IDC_BPRPL 1116 -#define IDC_BPACCESS 1117 -#define IDC_BPREAD 1118 -#define IDC_BPWRITE 1119 -#define IDC_FIND_DATA 1120 -#define IDC_FIND_PREV 1121 -#define IDC_FIND_NEXT 1122 -#define IDC_FIND_ASCII 1123 -#define IDC_ADDR20_24 1124 -#define IDC_ADDR25_27 1125 -#define IDC_ADDR28_29 1126 -#define IDC_ADDR30_34 1127 -#define IDC_RPLVIEW_DATA 1128 -#define IDC_MACRO_SLOW 1129 -#define IDC_MACRO_FAST 1130 -#define IDC_MACRO_SLIDER 1131 -#define IDC_MACRO_REAL 1132 -#define IDC_MACRO_MANUAL 1133 -#define IDC_SOUND_SLIDER 1134 -#define IDC_SOUND_DEVICE 1135 -#define IDC_TRACE_FILE 1136 -#define IDC_TRACE_BROWSE 1137 -#define IDC_TRACE_NEW 1138 -#define IDC_TRACE_APPEND 1139 -#define IDC_TRACE_REGISTER 1140 -#define IDC_TRACE_MMU 1141 -#define IDC_TRACE_OPCODE 1142 -#define ID_FILE_NEW 40001 -#define ID_FILE_OPEN 40002 -#define ID_FILE_SAVE 40003 -#define ID_FILE_SAVEAS 40004 -#define ID_FILE_EXIT 40005 -#define ID_VIEW_COPY 40006 -#define ID_VIEW_SETTINGS 40007 -#define ID_VIEW_RESET 40008 -#define ID_OBJECT_LOAD 40009 -#define ID_OBJECT_SAVE 40010 -#define ID_ABOUT 40011 -#define ID_HELP_TOPICS 40012 -#define ID_FILE_CLOSE 40013 -#define ID_BACKUP_SAVE 40014 -#define ID_BACKUP_RESTORE 40015 -#define ID_BACKUP_DELETE 40016 -#define ID_VIEW_SCRIPT 40017 -#define ID_STACK_COPY 40019 -#define ID_STACK_PASTE 40020 -#define ID_TOOL_DISASM 40021 -#define ID_TOOL_DEBUG 40022 -#define ID_TOOL_MACRO_RECORD 40023 -#define ID_TOOL_MACRO_PLAY 40024 -#define ID_TOOL_MACRO_STOP 40025 -#define ID_TOOL_MACRO_SETTINGS 40026 -#define ID_DEBUG_RUN 40027 -#define ID_DEBUG_RUNCURSOR 40028 -#define ID_DEBUG_STEP 40029 -#define ID_DEBUG_STEPOVER 40030 -#define ID_DEBUG_BREAK 40031 -#define ID_DEBUG_STEPOUT 40032 -#define ID_DEBUG_CANCEL 40033 -#define ID_BREAKPOINTS_SETBREAK 40034 -#define ID_BREAKPOINTS_CODEEDIT 40035 -#define ID_BREAKPOINTS_CLEARALL 40036 -#define ID_BREAKPOINTS_NOP3 40037 -#define ID_BREAKPOINTS_DOCODE 40038 -#define ID_BREAKPOINTS_RPL 40039 -#define ID_DEBUG_CODE_GOADR 40040 -#define ID_DEBUG_CODE_GOPC 40041 -#define ID_DEBUG_CODE_SETPCTOSELECT 40042 -#define ID_DEBUG_CODE_PREVPCO 40043 -#define ID_DEBUG_CODE_NEXTPCO 40044 -#define ID_DEBUG_MEM_GOADR 40045 -#define ID_DEBUG_MEM_GOPC 40046 -#define ID_DEBUG_MEM_GOD0 40047 -#define ID_DEBUG_MEM_GOD1 40048 -#define ID_DEBUG_MEM_GOSTACK 40049 -#define ID_DEBUG_MEM_FNONE 40050 -#define ID_DEBUG_MEM_FADDR 40051 -#define ID_DEBUG_MEM_FPC 40052 -#define ID_DEBUG_MEM_FD0 40053 -#define ID_DEBUG_MEM_FD1 40054 -#define ID_DEBUG_MEM_FIND 40055 -#define ID_DEBUG_MEM_MAP 40056 -#define ID_DEBUG_MEM_NCE1 40057 -#define ID_DEBUG_MEM_NCE2 40058 -#define ID_DEBUG_MEM_CE1 40059 -#define ID_DEBUG_MEM_CE2 40060 -#define ID_DEBUG_MEM_NCE3 40061 -#define ID_DEBUG_MEM_SAVE 40062 -#define ID_DEBUG_MEM_LOAD 40063 -#define ID_DEBUG_MEM_RPLVIEW 40064 -#define ID_DEBUG_STACK_PUSH 40065 -#define ID_DEBUG_STACK_POP 40066 -#define ID_DEBUG_STACK_MODIFY 40067 -#define ID_INTR_STEPOVERINT 40068 -#define ID_INFO_LASTINSTRUCTIONS 40069 -#define ID_INFO_PROFILE 40070 -#define ID_INFO_WRITEONLYREG 40071 -#define ID_TRACE_SETTINGS 40072 -#define ID_TRACE_ENABLE 40073 -#define ID_FILE_MRU_FILE1 40100 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 131 -#define _APS_NEXT_COMMAND_VALUE 40074 -#define _APS_NEXT_CONTROL_VALUE 1143 -#define _APS_NEXT_SYMED_VALUE 109 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Emu48.rc +// +#define IDM_DEBUG_SETTINGS 0x0010 +#define IDI_EMU48 100 +#define IDR_MENU 101 +#define IDM_MENU 102 +#define IDR_DEBUG 103 +#define IDR_DEBUG_TOOLBAR 104 +#define IDR_DEBUG_CODE 105 +#define IDR_DEBUG_MEM 106 +#define IDR_DEBUG_STACK 107 +#define IDB_CHECKBOX 108 +#define IDD_ABOUT 109 +#define IDD_SET_GENERAL 110 +#define IDD_SET_MEMORY 111 +#define IDD_SET_PERIPHERAL 112 +#define IDD_CHOOSEKML 113 +#define IDD_KMLLOG 114 +#define IDD_DISASM 115 +#define IDD_DEBUG 116 +#define IDD_NEWVALUE 117 +#define IDD_ENTERADR 118 +#define IDD_BREAKEDIT 119 +#define IDD_ENTERBREAK 120 +#define IDD_INSTRUCTIONS 121 +#define IDD_WRITEONLYREG 122 +#define IDD_FIND 123 +#define IDD_PROFILE 124 +#define IDD_RPLVIEW 125 +#define IDD_MACROSET 126 +#define IDD_DEBUG_MEMSAVE 127 +#define IDD_DEBUG_MEMLOAD 128 +#define IDD_DEBUG_SETTINGS 129 +#define IDD_TRACE 130 +#define IDC_REALSPEED 1000 +#define IDC_GRAYSCALE 1001 +#define IDC_ALWAYSONTOP 1002 +#define IDC_ACTFOLLOWSMOUSE 1003 +#define IDC_SINGLEINSTANCE 1004 +#define IDC_AUTOSAVE 1005 +#define IDC_AUTOSAVEONEXIT 1006 +#define IDC_OBJECTLOADWARNING 1007 +#define IDC_SHOWTITLE 1008 +#define IDC_SHOWMENU 1009 +#define IDC_ALWAYSDISPLOG 1010 +#define IDC_PORT1EN 1011 +#define IDC_PORT1WR 1012 +#define IDC_PORT2ISSHARED 1013 +#define IDC_PORT2WR 1014 +#define IDC_PORT2 1015 +#define IDC_PORT2LOAD 1016 +#define IDC_IR_ADDR 1017 +#define IDC_IR_PORT 1018 +#define IDC_WIRE 1019 +#define IDC_IR 1020 +#define IDC_EMUDIR 1021 +#define IDC_EMUDIRSEL 1022 +#define IDC_UPDATE 1023 +#define IDC_KMLSCRIPT 1024 +#define IDC_AUTHOR 1025 +#define IDC_TITLE 1026 +#define IDC_KMLLOG 1027 +#define IDC_VERSION 1028 +#define IDC_LICENSE 1029 +#define IDC_DISASM_WIN 1030 +#define IDC_DISASM_MODE_TEXT 1031 +#define IDC_DISASM_MODE 1032 +#define IDC_DISASM_MODULE 1033 +#define IDC_DISASM_HP 1034 +#define IDC_DISASM_CLASS 1035 +#define IDC_ADDRESS 1036 +#define IDC_DISASM_ADR 1037 +#define IDC_DISASM_NEXT 1038 +#define IDC_DISASM_COPY 1039 +#define IDC_DEBUG_CODE 1040 +#define IDC_STATIC_CODE 1041 +#define IDC_STATIC_REGISTERS 1042 +#define IDC_STATIC_MEMORY 1043 +#define IDC_STATIC_STACK 1044 +#define IDC_REG_A 1045 +#define IDC_REG_B 1046 +#define IDC_REG_C 1047 +#define IDC_REG_D 1048 +#define IDC_REG_R0 1049 +#define IDC_REG_R1 1050 +#define IDC_REG_R2 1051 +#define IDC_REG_R3 1052 +#define IDC_REG_R4 1053 +#define IDC_REG_D0 1054 +#define IDC_REG_D1 1055 +#define IDC_REG_P 1056 +#define IDC_REG_PC 1057 +#define IDC_REG_OUT 1058 +#define IDC_REG_IN 1059 +#define IDC_REG_ST 1060 +#define IDC_REG_CY 1061 +#define IDC_REG_MODE 1062 +#define IDC_REG_MP 1063 +#define IDC_REG_SR 1064 +#define IDC_REG_SB 1065 +#define IDC_REG_XM 1066 +#define IDC_MISC_INT 1067 +#define IDC_MISC_KEY 1068 +#define IDC_MISC_BS 1069 +#define IDC_NEWVALUE 1070 +#define IDC_ENTERADR 1071 +#define IDC_DEBUG_MEM 1072 +#define IDC_DEBUG_MEM_ADDR 1073 +#define IDC_DEBUG_MEM_COL0 1074 +#define IDC_DEBUG_MEM_COL1 1075 +#define IDC_DEBUG_MEM_COL2 1076 +#define IDC_DEBUG_MEM_COL3 1077 +#define IDC_DEBUG_MEM_COL4 1078 +#define IDC_DEBUG_MEM_COL5 1079 +#define IDC_DEBUG_MEM_COL6 1080 +#define IDC_DEBUG_MEM_COL7 1081 +#define IDC_DEBUG_MEM_TEXT 1082 +#define IDC_DEBUG_DATA_FILE 1083 +#define IDC_DEBUG_DATA_BUT 1084 +#define IDC_DEBUG_DATA_STARTADDR 1085 +#define IDC_DEBUG_DATA_ENDADDR 1086 +#define IDC_DEBUG_DATA_SAVE_8BIT 1087 +#define IDC_DEBUG_DATA_SAVE_4BIT 1088 +#define IDC_DEBUG_DATA_LOAD_8BIT 1089 +#define IDC_DEBUG_DATA_LOAD_4BIT 1090 +#define IDC_DEBUG_DATA_LOAD_ABIT 1091 +#define IDC_DEBUG_SET_SYMB 1092 +#define IDC_DEBUG_SET_MODEL 1093 +#define IDC_DEBUG_SET_FILE 1094 +#define IDC_DEBUG_SET_BROWSE 1095 +#define IDC_DEBUG_STACK 1096 +#define IDC_STATIC_BREAKPOINT 1097 +#define IDC_BREAKEDIT_ADD 1098 +#define IDC_BREAKEDIT_DELETE 1099 +#define IDC_BREAKEDIT_WND 1100 +#define IDC_STATIC_MMU 1101 +#define IDC_MMU_IO_A 1102 +#define IDC_MMU_NCE2_A 1103 +#define IDC_MMU_CE1_A 1104 +#define IDC_MMU_CE2_A 1105 +#define IDC_MMU_NCE3_A 1106 +#define IDC_MMU_IO_S 1107 +#define IDC_MMU_CE1_S 1108 +#define IDC_MMU_CE2_S 1109 +#define IDC_MMU_NCE2_S 1110 +#define IDC_MMU_NCE3_S 1111 +#define IDC_STATIC_MISC 1112 +#define IDC_MISC_BS_TXT 1113 +#define IDC_INSTR_TEXT 1114 +#define IDC_INSTR_CODE 1115 +#define IDC_INSTR_COPY 1116 +#define IDC_INSTR_CLEAR 1117 +#define IDC_PROFILE_LASTCYCLES 1118 +#define IDC_PROFILE_LASTTIME 1119 +#define IDC_BPCODE 1120 +#define IDC_BPRPL 1121 +#define IDC_BPACCESS 1122 +#define IDC_BPREAD 1123 +#define IDC_BPWRITE 1124 +#define IDC_FIND_DATA 1125 +#define IDC_FIND_PREV 1126 +#define IDC_FIND_NEXT 1127 +#define IDC_FIND_ASCII 1128 +#define IDC_ADDR20_24 1129 +#define IDC_ADDR25_27 1130 +#define IDC_ADDR28_29 1131 +#define IDC_ADDR30_34 1132 +#define IDC_RPLVIEW_DATA 1133 +#define IDC_MACRO_SLOW 1134 +#define IDC_MACRO_FAST 1135 +#define IDC_MACRO_SLIDER 1136 +#define IDC_MACRO_REAL 1137 +#define IDC_MACRO_MANUAL 1138 +#define IDC_SOUND_SLIDER 1139 +#define IDC_SOUND_DEVICE 1140 +#define IDC_TRACE_FILE 1141 +#define IDC_TRACE_BROWSE 1142 +#define IDC_TRACE_NEW 1143 +#define IDC_TRACE_APPEND 1144 +#define IDC_TRACE_REGISTER 1145 +#define IDC_TRACE_MMU 1146 +#define IDC_TRACE_OPCODE 1147 +#define ID_FILE_NEW 40001 +#define ID_FILE_OPEN 40002 +#define ID_FILE_SAVE 40003 +#define ID_FILE_SAVEAS 40004 +#define ID_FILE_EXIT 40005 +#define ID_VIEW_COPY 40006 +#define ID_VIEW_SETTINGS 40007 +#define ID_VIEW_RESET 40008 +#define ID_OBJECT_LOAD 40009 +#define ID_OBJECT_SAVE 40010 +#define ID_ABOUT 40011 +#define ID_HELP_TOPICS 40012 +#define ID_FILE_CLOSE 40013 +#define ID_BACKUP_SAVE 40014 +#define ID_BACKUP_RESTORE 40015 +#define ID_BACKUP_DELETE 40016 +#define ID_VIEW_SCRIPT 40017 +#define ID_STACK_COPY 40019 +#define ID_STACK_PASTE 40020 +#define ID_TOOL_DISASM 40021 +#define ID_TOOL_DEBUG 40022 +#define ID_TOOL_MACRO_RECORD 40023 +#define ID_TOOL_MACRO_PLAY 40024 +#define ID_TOOL_MACRO_STOP 40025 +#define ID_TOOL_MACRO_SETTINGS 40026 +#define ID_DEBUG_RUN 40027 +#define ID_DEBUG_RUNCURSOR 40028 +#define ID_DEBUG_STEP 40029 +#define ID_DEBUG_STEPOVER 40030 +#define ID_DEBUG_BREAK 40031 +#define ID_DEBUG_STEPOUT 40032 +#define ID_DEBUG_CANCEL 40033 +#define ID_BREAKPOINTS_SETBREAK 40034 +#define ID_BREAKPOINTS_CODEEDIT 40035 +#define ID_BREAKPOINTS_CLEARALL 40036 +#define ID_BREAKPOINTS_NOP3 40037 +#define ID_BREAKPOINTS_DOCODE 40038 +#define ID_BREAKPOINTS_RPL 40039 +#define ID_DEBUG_CODE_GOADR 40040 +#define ID_DEBUG_CODE_GOPC 40041 +#define ID_DEBUG_CODE_SETPCTOSELECT 40042 +#define ID_DEBUG_CODE_PREVPCO 40043 +#define ID_DEBUG_CODE_NEXTPCO 40044 +#define ID_DEBUG_MEM_GOADR 40045 +#define ID_DEBUG_MEM_GOPC 40046 +#define ID_DEBUG_MEM_GOD0 40047 +#define ID_DEBUG_MEM_GOD1 40048 +#define ID_DEBUG_MEM_GOSTACK 40049 +#define ID_DEBUG_MEM_FNONE 40050 +#define ID_DEBUG_MEM_FADDR 40051 +#define ID_DEBUG_MEM_FPC 40052 +#define ID_DEBUG_MEM_FD0 40053 +#define ID_DEBUG_MEM_FD1 40054 +#define ID_DEBUG_MEM_FIND 40055 +#define ID_DEBUG_MEM_MAP 40056 +#define ID_DEBUG_MEM_NCE1 40057 +#define ID_DEBUG_MEM_NCE2 40058 +#define ID_DEBUG_MEM_CE1 40059 +#define ID_DEBUG_MEM_CE2 40060 +#define ID_DEBUG_MEM_NCE3 40061 +#define ID_DEBUG_MEM_SAVE 40062 +#define ID_DEBUG_MEM_LOAD 40063 +#define ID_DEBUG_MEM_RPLVIEW 40064 +#define ID_DEBUG_STACK_PUSH 40065 +#define ID_DEBUG_STACK_POP 40066 +#define ID_DEBUG_STACK_MODIFY 40067 +#define ID_INTR_STEPOVERINT 40068 +#define ID_INFO_LASTINSTRUCTIONS 40069 +#define ID_INFO_PROFILE 40070 +#define ID_INFO_WRITEONLYREG 40071 +#define ID_TRACE_SETTINGS 40072 +#define ID_TRACE_ENABLE 40073 +#define ID_FILE_MRU_FILE1 40100 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 131 +#define _APS_NEXT_COMMAND_VALUE 40074 +#define _APS_NEXT_CONTROL_VALUE 1148 +#define _APS_NEXT_SYMED_VALUE 109 +#endif +#endif diff --git a/Sources/Emu48/romcrc.c b/Sources/Emu48/ROMCRC.C similarity index 95% rename from Sources/Emu48/romcrc.c rename to Sources/Emu48/ROMCRC.C index 84eeebd..392c0dd 100644 --- a/Sources/Emu48/romcrc.c +++ b/Sources/Emu48/ROMCRC.C @@ -1,250 +1,250 @@ -/* - * romcrc.c - * - * This file is part of Emu48 - * - * Copyright (C) 2022 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" -#include "ops.h" - -// flash page types -#define BOOT 0x86 -#define FS 0x18 -#define SYSTEM 0x32 -#define ROM 0x0F -#define RAM 0xF0 - -//################ -//# -//# Restore HP38G/HP48GX/SX ROM CRC -//# -//################ - -// Clarke/Yorke CRC for HP38G and HP48GX/SX -#define a0 0x0 // Start Address -#define d0 (n0*16) // Address offset -#define n0 0x4000 // Reads/Half-Sector -#define s0 1 // #Sectors (Sector Size=2*d) - -// rebuild of the calculator =CHECKSUM function for the Clarke and the Yorke chip ROM -static WORD Checksum(LPBYTE pbyROM, DWORD dwStart, DWORD dwOffset, INT nReads, INT nSector) -{ - int i,j; - - WORD wCrc = 0; - - for (;nSector > 0; --nSector) // evaluate each sector - { - LPBYTE pbyAddr1 = pbyROM + dwStart; - LPBYTE pbyAddr2 = pbyAddr1 + dwOffset; - - for (i = 0; i < nReads; ++i) // no. of reads in sector - { - for (j = 0; j < 16; ++j) wCrc = UpCRC(wCrc,*pbyAddr1++); - for (j = 0; j < 16; ++j) wCrc = UpCRC(wCrc,*pbyAddr2++); - } - - dwStart += 2 * dwOffset; // next start page - } - return wCrc; -} - -// calculate proper checksum to produce final CRC of FFFF -static __inline WORD CalcChksum(WORD wCrc, WORD wChksum) -{ - WORD q, r = wCrc, s = wChksum; - - // first take the last 4-nib back out of the CRC - r = (((r >> 12) * 0x811) ^ (r << 4) ^ (s & 0xf)); - s >>= 4; - r = (((r >> 12) * 0x811) ^ (r << 4) ^ (s & 0xf)); - s >>= 4; - r = (((r >> 12) * 0x811) ^ (r << 4) ^ (s & 0xf)); - s >>= 4; - r = (((r >> 12) * 0x811) ^ (r << 4) ^ (s & 0xf)); - - // calculate new checksum to correct the CRC - s = 0xf831; // required MSNs to make goal - q = (q<<4) | ((r ^ s) & 0xf); // get 1st (least sig) nib - r = (r>>4) ^ ((s & 0xf) * 0x1081); - s >>= 4; - q = (q<<4) | ((r ^ s) & 0xf); - r = (r>>4) ^ ((s & 0xf) * 0x1081); - s >>= 4; - q = (q<<4) | ((r ^ s) & 0xf); - r = (r>>4) ^ ((s & 0xf) * 0x1081); - s >>= 4; - q = (q<<4) | ((r ^ s) & 0xf); - return q; -} - -static VOID CorrectCrc(DWORD dwAddrCrc, WORD wCrc) -{ - if (wCrc != 0xFFFF) // wrong crc result - { - INT s; - - // get actual crc correction value - const WORD wChkAct = (pbyRom[dwAddrCrc+0] << 12) - | (pbyRom[dwAddrCrc+1] << 8) - | (pbyRom[dwAddrCrc+2] << 4) - | (pbyRom[dwAddrCrc+3]); - - wCrc = CalcChksum(wCrc,wChkAct); // calculate new checksum - - for (s = 3; s >= 0; --s) // write new checksum - { - PatchNibble(dwAddrCrc + s,(BYTE) (wCrc & 0xf)); - wCrc >>= 4; - } - } - return; -} - - -//################ -//# -//# Restore HP49G ROM CRC -//# -//################ - -static VOID CorrectFlashCrc(LPBYTE pbyMem, DWORD dwSize, DWORD dwOffset, DWORD dwLength) -{ - // address overflow (data length + 4 nibble CRC) - if (dwOffset + dwLength + 4 <= dwSize) - { - WORD wRefCrc,wCrc = 0; - - pbyMem += dwOffset; // start address - - for (; dwLength > 0; --dwLength) // update CRC - { - wCrc = UpCRC(wCrc,*pbyMem++); - } - - wRefCrc = (WORD) Npack(pbyMem,4); // read reference CRC - - if(wRefCrc != wCrc) // wrong page CRC - { - INT s; - - // linear CRC address in ROM - DWORD dwAddrCrc = (DWORD) (pbyMem - pbyRom); - - wRefCrc = wCrc; // working copy of CRC - for (s = 0; s < 4; ++s) // write new checksum - { - PatchNibble(dwAddrCrc++,(BYTE) (wRefCrc & 0xf)); - wRefCrc >>= 4; - } - - _ASSERT(wCrc == (WORD) Npack(pbyMem,4)); - } - } - return; -} - -static __inline VOID CorrectFlashRom(LPBYTE pbyMem, DWORD dwSize) -{ - CorrectFlashCrc(pbyMem,dwSize,0x20A,Npack(pbyMem+0x20A,5)); - return; -} - -static __inline VOID CorrectFlashSystem(LPBYTE pbyMem, DWORD dwSize) -{ - CorrectFlashCrc(pbyMem,dwSize,0x20A,Npack(pbyMem+0x100,5)); - return; -} - -static __inline VOID CorrectFlashPage(LPBYTE pbyMem, DWORD dwSize, DWORD dwPage) -{ - _ASSERT(dwPage >= 0 && dwPage < 16); - - dwPage *= _KB(128); // convert page no. to data offset - if (dwPage + _KB(128) <= dwSize) // page inside flash chip - { - BYTE byType; - - pbyMem += dwPage; // page address - dwPage = _KB(128); // page size - - // get bank type - byType = (BYTE) Npack(pbyMem+0x200,2); - if (byType == BOOT) // 1st half of page is the boot bank - { - pbyMem += _KB(64); // 2nd half of page - dwPage = _KB(64); // page size - - // get bank type - byType = (BYTE) Npack(pbyMem+0x200,2); - } - - _ASSERT(dwPage == _KB(64) || dwPage == _KB(128)); - - switch (byType) - { - case FS: // FRBankFileSystem - case ROM: // FRBankRom - CorrectFlashRom(pbyMem,dwPage); - break; - case SYSTEM: // FRBankSystem - CorrectFlashSystem(pbyMem,dwPage); - break; - case RAM: // FRBankRam - default: // illegal bank identifier - break; - } - } - return; -} - -static __inline VOID CorrectAllFlashPages(VOID) -{ - DWORD dwPage; - - // check CRC of all pages - CONST DWORD dwLastPage = dwRomSize / _KB(128); - for (dwPage = 0; dwPage < dwLastPage; ++dwPage) - { - // correct CRC of page - CorrectFlashPage(pbyRom,dwRomSize,dwPage); - } - return; -} - - -//################ -//# -//# Restore ROM CRC -//# -//################ - -VOID RebuildRomCrc(VOID) -{ - // HP38G, HP48GX, HP48SX - if ((strchr("6AGS",cCurrentRomType)) && dwRomSize >= _KB(256)) - { - // first 256KB - CorrectCrc(0x7FFFC,Checksum(pbyRom,a0,d0,n0,s0)); - } - // HP38G, HP48GX - if ((strchr("6AG",cCurrentRomType)) && dwRomSize == _KB(512)) - { - // second 256KB - CorrectCrc(0xFFFFC,Checksum(pbyRom,a0+_KB(256),d0,n0,s0)); - } - // HP39G/40G - if (cCurrentRomType == 'E') - { - // has no Crc - } - // HP49G - if (cCurrentRomType == 'X' && dwRomSize == _KB(2048)) - { - CorrectAllFlashPages(); // go through all pages - } - return; -} +/* + * romcrc.c + * + * This file is part of Emu48 + * + * Copyright (C) 2022 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" +#include "ops.h" + +// flash page types +#define BOOT 0x86 +#define FS 0x18 +#define SYSTEM 0x32 +#define ROM 0x0F +#define RAM 0xF0 + +//################ +//# +//# Restore HP38G/HP48GX/SX ROM CRC +//# +//################ + +// Clarke/Yorke CRC for HP38G and HP48GX/SX +#define a0 0x0 // Start Address +#define d0 (n0*16) // Address offset +#define n0 0x4000 // Reads/Half-Sector +#define s0 1 // #Sectors (Sector Size=2*d) + +// rebuild of the calculator =CHECKSUM function for the Clarke and the Yorke chip ROM +static WORD Checksum(LPBYTE pbyROM, DWORD dwStart, DWORD dwOffset, INT nReads, INT nSector) +{ + int i,j; + + WORD wCrc = 0; + + for (;nSector > 0; --nSector) // evaluate each sector + { + LPBYTE pbyAddr1 = pbyROM + dwStart; + LPBYTE pbyAddr2 = pbyAddr1 + dwOffset; + + for (i = 0; i < nReads; ++i) // no. of reads in sector + { + for (j = 0; j < 16; ++j) wCrc = UpCRC(wCrc,*pbyAddr1++); + for (j = 0; j < 16; ++j) wCrc = UpCRC(wCrc,*pbyAddr2++); + } + + dwStart += 2 * dwOffset; // next start page + } + return wCrc; +} + +// calculate proper checksum to produce final CRC of FFFF +static __inline WORD CalcChksum(WORD wCrc, WORD wChksum) +{ + WORD q, r = wCrc, s = wChksum; + + // first take the last 4-nib back out of the CRC + r = (((r >> 12) * 0x811) ^ (r << 4) ^ (s & 0xf)); + s >>= 4; + r = (((r >> 12) * 0x811) ^ (r << 4) ^ (s & 0xf)); + s >>= 4; + r = (((r >> 12) * 0x811) ^ (r << 4) ^ (s & 0xf)); + s >>= 4; + r = (((r >> 12) * 0x811) ^ (r << 4) ^ (s & 0xf)); + + // calculate new checksum to correct the CRC + s = 0xf831; // required MSNs to make goal + q = (q<<4) | ((r ^ s) & 0xf); // get 1st (least sig) nib + r = (r>>4) ^ ((s & 0xf) * 0x1081); + s >>= 4; + q = (q<<4) | ((r ^ s) & 0xf); + r = (r>>4) ^ ((s & 0xf) * 0x1081); + s >>= 4; + q = (q<<4) | ((r ^ s) & 0xf); + r = (r>>4) ^ ((s & 0xf) * 0x1081); + s >>= 4; + q = (q<<4) | ((r ^ s) & 0xf); + return q; +} + +static VOID CorrectCrc(DWORD dwAddrCrc, WORD wCrc) +{ + if (wCrc != 0xFFFF) // wrong crc result + { + INT s; + + // get actual crc correction value + const WORD wChkAct = (pbyRom[dwAddrCrc+0] << 12) + | (pbyRom[dwAddrCrc+1] << 8) + | (pbyRom[dwAddrCrc+2] << 4) + | (pbyRom[dwAddrCrc+3]); + + wCrc = CalcChksum(wCrc,wChkAct); // calculate new checksum + + for (s = 3; s >= 0; --s) // write new checksum + { + PatchNibble(dwAddrCrc + s,(BYTE) (wCrc & 0xf)); + wCrc >>= 4; + } + } + return; +} + + +//################ +//# +//# Restore HP49G ROM CRC +//# +//################ + +static VOID CorrectFlashCrc(LPBYTE pbyMem, DWORD dwSize, DWORD dwOffset, DWORD dwLength) +{ + // address overflow (data length + 4 nibble CRC) + if (dwOffset + dwLength + 4 <= dwSize) + { + WORD wRefCrc,wCrc = 0; + + pbyMem += dwOffset; // start address + + for (; dwLength > 0; --dwLength) // update CRC + { + wCrc = UpCRC(wCrc,*pbyMem++); + } + + wRefCrc = (WORD) Npack(pbyMem,4); // read reference CRC + + if(wRefCrc != wCrc) // wrong page CRC + { + INT s; + + // linear CRC address in ROM + DWORD dwAddrCrc = (DWORD) (pbyMem - pbyRom); + + wRefCrc = wCrc; // working copy of CRC + for (s = 0; s < 4; ++s) // write new checksum + { + PatchNibble(dwAddrCrc++,(BYTE) (wRefCrc & 0xf)); + wRefCrc >>= 4; + } + + _ASSERT(wCrc == (WORD) Npack(pbyMem,4)); + } + } + return; +} + +static __inline VOID CorrectFlashRom(LPBYTE pbyMem, DWORD dwSize) +{ + CorrectFlashCrc(pbyMem,dwSize,0x20A,Npack(pbyMem+0x20A,5)); + return; +} + +static __inline VOID CorrectFlashSystem(LPBYTE pbyMem, DWORD dwSize) +{ + CorrectFlashCrc(pbyMem,dwSize,0x20A,Npack(pbyMem+0x100,5)); + return; +} + +static __inline VOID CorrectFlashPage(LPBYTE pbyMem, DWORD dwSize, DWORD dwPage) +{ + _ASSERT(dwPage >= 0 && dwPage < 16); + + dwPage *= _KB(128); // convert page no. to data offset + if (dwPage + _KB(128) <= dwSize) // page inside flash chip + { + BYTE byType; + + pbyMem += dwPage; // page address + dwPage = _KB(128); // page size + + // get bank type + byType = (BYTE) Npack(pbyMem+0x200,2); + if (byType == BOOT) // 1st half of page is the boot bank + { + pbyMem += _KB(64); // 2nd half of page + dwPage = _KB(64); // page size + + // get bank type + byType = (BYTE) Npack(pbyMem+0x200,2); + } + + _ASSERT(dwPage == _KB(64) || dwPage == _KB(128)); + + switch (byType) + { + case FS: // FRBankFileSystem + case ROM: // FRBankRom + CorrectFlashRom(pbyMem,dwPage); + break; + case SYSTEM: // FRBankSystem + CorrectFlashSystem(pbyMem,dwPage); + break; + case RAM: // FRBankRam + default: // illegal bank identifier + break; + } + } + return; +} + +static __inline VOID CorrectAllFlashPages(VOID) +{ + DWORD dwPage; + + // check CRC of all pages + CONST DWORD dwLastPage = dwRomSize / _KB(128); + for (dwPage = 0; dwPage < dwLastPage; ++dwPage) + { + // correct CRC of page + CorrectFlashPage(pbyRom,dwRomSize,dwPage); + } + return; +} + + +//################ +//# +//# Restore ROM CRC +//# +//################ + +VOID RebuildRomCrc(VOID) +{ + // HP38G, HP48GX, HP48SX + if ((strchr("6AGS",cCurrentRomType)) && dwRomSize >= _KB(256)) + { + // first 256KB + CorrectCrc(0x7FFFC,Checksum(pbyRom,a0,d0,n0,s0)); + } + // HP38G, HP48GX + if ((strchr("6AG",cCurrentRomType)) && dwRomSize == _KB(512)) + { + // second 256KB + CorrectCrc(0xFFFFC,Checksum(pbyRom,a0+_KB(256),d0,n0,s0)); + } + // HP39G/40G + if (cCurrentRomType == 'E') + { + // has no Crc + } + // HP49G + if (cCurrentRomType == 'X' && dwRomSize == _KB(2048)) + { + CorrectAllFlashPages(); // go through all pages + } + return; +} diff --git a/Sources/Emu48/rpl.c b/Sources/Emu48/RPL.C similarity index 96% rename from Sources/Emu48/rpl.c rename to Sources/Emu48/RPL.C index ffc763c..1bd9ec7 100644 --- a/Sources/Emu48/rpl.c +++ b/Sources/Emu48/RPL.C @@ -1,453 +1,453 @@ -/* - * rpl.c - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ -#include "pch.h" -#include "emu48.h" -#include "ops.h" -#include "io.h" - -//| 38G | 39G | 40G | 48SX | 48GX | 49G | Name -//#F0688 #806E9 #806E9 #7056A #806E9 #806E9 =TEMPOB -//#F068D #806EE #806EE #7056F #806EE #806EE =TEMPTOP -//#F0692 #806F3 #806F3 #70574 #806F3 #806F3 =RSKTOP (B) -//#F0697 #806F8 #806F8 #70579 #806F8 #806F8 =DSKTOP (D1) -//#F069C #806FD #806FD #7057E #806FD #806FD =EDITLINE -//#F0DEA #80E9B #80E9B #7066E #807ED #80E9B =AVMEM (D) -//#F0705 #8076B #8076B #705B0 #8072F #8076B =INTRPPTR (D0) -//#F0E42 #80F02 #80F02 #706C5 #80843 #80F02 =SystemFlags - -#define TEMPOB ((cCurrentRomType=='S')?0x7056A:0x806E9) -#define TEMPTOP ((cCurrentRomType=='S')?0x7056F:0x806EE) -#define RSKTOP ((cCurrentRomType=='S')?0x70574:0x806F3) -#define DSKTOP ((cCurrentRomType=='S')?0x70579:0x806F8) -#define EDITLINE ((cCurrentRomType=='S')?0x7057E:0x806FD) -#define AVMEM ((cCurrentRomType!='X')?((cCurrentRomType=='S')?0x7066E:0x807ED):0x80E9B) -#define INTRPPTR ((cCurrentRomType!='X')?((cCurrentRomType=='S')?0x705B0:0x8072F):0x8076B) -#define SYSTEMFLAGS ((cCurrentRomType!='X')?((cCurrentRomType=='S')?0x706C5:0x80843):0x80F02) - -#define DOINT 0x02614 // Precision Integer (HP49G) -#define DOLNGREAL 0x0263A // Precision Real (HP49G) -#define DOLNGCMP 0x02660 // Precision Complex (HP49G) -#define DOMATRIX 0x02686 // Symbolic matrix (HP49G) -#define DOFLASHP 0x026AC // Flash PTR (HP49G) -#define DOAPLET 0x026D5 // Aplet (HP49G) -#define DOMINIFONT 0x026FE // Mini Font (HP49G) -#define DOBINT 0x02911 // System Binary -#define DOREAL 0x02933 // Real -#define DOEREL 0x02955 // Long Real -#define DOCMP 0x02977 // Complex -#define DOECMP 0x0299D // Long Complex -#define DOCHAR 0x029BF // Character -#define DOARRY 0x029E8 // Array -#define DOLNKARRY 0x02A0A // Linked Array -#define DOCSTR 0x02A2C // String -#define DOHSTR 0x02A4E // Binary Integer -#define DOLIST 0x02A74 // List -#define DORRP 0x02A96 // Directory -#define DOSYMB 0x02AB8 // Algebraic -#define DOEXT 0x02ADA // Unit -#define DOTAG 0x02AFC // Tagged -#define DOGROB 0x02B1E // Graphic -#define DOLIB 0x02B40 // Library -#define DOBAK 0x02B62 // Backup -#define DOEXT0 0x02B88 // Library Data -#define DOEXT1 0x02BAA // Reserved 1, ACcess PoinTeR (HP48GX and later) -#define DOEXT2 0x02BCC // Reserved 2, Font (HP49G) -#define DOEXT3 0x02BEE // Reserved 3 -#define DOEXT4 0x02C10 // Reserved 4 -#define DOCOL 0x02D9D // Program -#define DOCODE 0x02DCC // Code -#define DOIDNT 0x02E48 // Global Name -#define DOLAM 0x02E6D // Local Name -#define DOROMP 0x02E92 // XLIB Name -#define SEMI 0x0312B // ; - -#define GARBAGECOL 0x0613E // =GARBAGECOL entry for HP48S/G and HP49G - -// check for Metakernel version -#define METAKERNEL Metakernel() - -// search for "MDGKER:MK2.30" or "MDGKER:PREVIE" in port1 of a HP48GX -static BOOL Metakernel(VOID) -{ - BOOL bMkDetect = FALSE; - - // card in slot1 of a HP48GX enabled - if (cCurrentRomType=='G' && Port1 && Chipset.cards_status & PORT1_PRESENT) - { - // check for Metakernel string "MDGKER:" - if (!strncmp((LPCSTR) &Port1[12],"\xD\x4\x4\x4\x7\x4\xB\x4\x5\x4\x2\x5\xA\x3",14)) - { - bMkDetect = TRUE; // Metakernel detected - // check for "MK" - if (!strncmp((LPCSTR) &Port1[26],"\xD\x4\xB\x4",4)) - { - // get version number - WORD wVersion = ((Port1[30] * 10) + Port1[34]) * 10 - + Port1[36]; - - // version newer then V2.30, then compatible with HP OS - bMkDetect = (wVersion <= 230); - } - } - } - return bMkDetect; -} - -static DWORD RPL_GarbageCol(VOID) // RPL variables must be in system RAM -{ - CHIPSET OrgChipset; - DWORD dwAVMEM; - - // only for HP48SX, HP48GX and HP49G - _ASSERT(cCurrentRomType == 'S' || cCurrentRomType == 'G' || cCurrentRomType == 'X'); - - OrgChipset = Chipset; // save original chipset - - // entry for =GARBAGECOL - Chipset.P = 0; // P=0 - Chipset.mode_dec = FALSE; // hex mode - Chipset.pc = GARBAGECOL; // =GARBAGECOL entry - rstkpush(0xFFFFF); // return address for stopping - - while (Chipset.pc != 0xFFFFF) // wait for stop address - { - EvalOpcode(FASTPTR(Chipset.pc)); // execute opcode - } - - dwAVMEM = Npack(Chipset.C,5); // available AVMEM - Chipset = OrgChipset; // restore original chipset - return dwAVMEM; -} - -BOOL RPL_GetSystemFlag(INT nFlag) -{ - DWORD dwAddr; - BYTE byMask,byFlag; - - _ASSERT(nFlag > 0); // first flag is 1 - - // calculate memory address and bit mask - dwAddr = SYSTEMFLAGS + (nFlag - 1) / 4; - byMask = 1 << ((nFlag - 1) & 0x3); - - Npeek(&byFlag,dwAddr,sizeof(byFlag)); - return (byFlag & byMask) != 0; -} - -DWORD RPL_SkipOb(DWORD d) -{ - BYTE X[8]; - DWORD n, l; - - Npeek(X,d,5); - n = Npack(X, 5); // read prolog - switch (n) - { - case DOFLASHP: l = (cCurrentRomType!='X') ? 5 : 12; break; // Flash PTR (HP49G) - case DOBINT: l = 10; break; // System Binary - case DOREAL: l = 21; break; // Real - case DOEREL: l = 26; break; // Long Real - case DOCMP: l = 37; break; // Complex - case DOECMP: l = 47; break; // Long Complex - case DOCHAR: l = 7; break; // Character - case DOROMP: l = 11; break; // XLIB Name - case DOMATRIX: // Symbolic matrix (HP49G) - if (cCurrentRomType!='X') - { - l = 5; - break; - } - case DOLIST: // List - case DOSYMB: // Algebraic - case DOEXT: // Unit - case DOCOL: // Program - n=d+5; - do - { - d=n; n=RPL_SkipOb(d); - } while (d!=n); - return n+5; - case SEMI: return d; // SEMI - case DOIDNT: // Global Name - case DOLAM: // Local Name - case DOTAG: // Tagged - Npeek(X,d+5,2); n = 7 + Npack(X,2)*2; - return RPL_SkipOb(d+n); - case DORRP: // Directory - d+=8; - n = Read5(d); - if (n==0) - { - return d+5; - } - else - { - d+=n; - Npeek(X,d,2); - n = Npack(X,2)*2 + 4; - return RPL_SkipOb(d+n); - } - case DOINT: // Precision Integer (HP49G) - case DOAPLET: // Aplet (HP49G) - case DOMINIFONT: // Mini Font (HP49G) - if (cCurrentRomType!='X') - { - l = 5; - break; - } - case DOARRY: // Array - case DOLNKARRY: // Linked Array - case DOCSTR: // String - case DOHSTR: // Binary Integer - case DOGROB: // Graphic - case DOLIB: // Library - case DOBAK: // Backup - case DOEXT0: // Library Data - case DOEXT1: // Reserved 1 - if (n == DOEXT1 && cCurrentRomType != 'S') - { - // on HP48G series and later interpreted as DOACPTR - l = 15; break; // ACcess PoinTeR - break; - } - case DOEXT2: // Reserved 2, Font (HP49G) - case DOEXT3: // Reserved 3 - case DOEXT4: // Reserved 4 - case DOCODE: // Code - l = 5+Read5(d+5); - break; - case DOLNGREAL: // Precision Real (HP49G) - l = 5; - if (cCurrentRomType=='X') - { - l += Read5(d+l); - l += Read5(d+l); - } - break; - case DOLNGCMP: // Precision Complex (HP49G) - l = 5; - if (cCurrentRomType=='X') - { - l += Read5(d+l); - l += Read5(d+l); - l += Read5(d+l); - l += Read5(d+l); - } - break; - default: return d+5; - } - return d+l; -} - -DWORD RPL_ObjectSize(BYTE *o,DWORD s) -{ - DWORD n, l = 0; - - if (s < 5) return BAD_OB; // size too small for prolog - n = Npack(o,5); // read prolog - switch (n) - { - case DOFLASHP: l = (cCurrentRomType!='X') ? 5 : 12; break; // Flash PTR (HP49G) - case DOBINT: l = 10; break; // System Binary - case DOREAL: l = 21; break; // Real - case DOEREL: l = 26; break; // Long Real - case DOCMP: l = 37; break; // Complex - case DOECMP: l = 47; break; // Long Complex - case DOCHAR: l = 7; break; // Character - case DOROMP: l = 11; break; // XLIB Name - case DOMATRIX: // Symbolic matrix (HP49G) - if (cCurrentRomType!='X') - { - l = 5; - break; - } - case DOLIST: // List - case DOSYMB: // Algebraic - case DOEXT: // Unit - case DOCOL: // Program - n = 5; // prolog length - do - { - l += n; - if (l > s) return BAD_OB; // prevent negative size argument - n = RPL_ObjectSize(o+l,s-l); // get new object - if (n == BAD_OB) return BAD_OB; // buffer overflow - } - while (n); - l += 5; - break; - case SEMI: l = 0; break; // SEMI - case DOIDNT: // Global Name - case DOLAM: // Local Name - case DOTAG: // Tagged - if (s < 5 + 2) return BAD_OB; - l = 7 + Npack(o+5,2) * 2; // prolog + name length - if (l > s) return BAD_OB; // prevent negative size argument - n = RPL_ObjectSize(o+l,s-l); // get new object - if (n == BAD_OB) return BAD_OB; // buffer overflow - l += n; - break; - case DORRP: // Directory - if (s < 8 + 5) return BAD_OB; - n = Npack(o+8,5); - if (n == 0) // empty dir - { - l = 13; - } - else - { - l = 8 + n; - if (s < l + 2) return BAD_OB; - n = Npack(o+l,2) * 2 + 4; - l += n; - if (l > s) return BAD_OB; // prevent negative size argument - n = RPL_ObjectSize(o+l,s-l); // next rrp - if (n == BAD_OB) return BAD_OB; // buffer overflow - l += n; - } - break; - case DOINT: // Precision Integer (HP49G) - case DOAPLET: // Aplet (HP49G) - case DOMINIFONT: // Mini Font (HP49G) - if (cCurrentRomType!='X') - { - l = 5; - break; - } - case DOARRY: // Array - case DOLNKARRY: // Linked Array - case DOCSTR: // String - case DOHSTR: // Binary Integer - case DOGROB: // Graphic - case DOLIB: // Library - case DOBAK: // Backup - case DOEXT0: // Library Data - case DOEXT1: // Reserved 1 - if (n == DOEXT1 && cCurrentRomType != 'S') - { - // on HP48G series and later interpreted as DOACPTR - l = 15; break; // ACcess PoinTeR - break; - } - case DOEXT2: // Reserved 2, Font (HP49G) - case DOEXT3: // Reserved 3 - case DOEXT4: // Reserved 4 - case DOCODE: // Code - if (s < 5 + 5) return BAD_OB; - l = 5 + Npack(o+5,5); - break; - case DOLNGREAL: // Precision Real (HP49G) - l = 5; - if (cCurrentRomType=='X') - { - if (s < l + 5) return BAD_OB; - l += Npack(o+l,5); - if (s < l + 5) return BAD_OB; - l += Npack(o+l,5); - } - break; - case DOLNGCMP: // Precision Complex (HP49G) - l = 5; - if (cCurrentRomType=='X') - { - if (s < l + 5) return BAD_OB; - l += Npack(o+l,5); - if (s < l + 5) return BAD_OB; - l += Npack(o+l,5); - if (s < l + 5) return BAD_OB; - l += Npack(o+l,5); - if (s < l + 5) return BAD_OB; - l += Npack(o+l,5); - } - break; - default: l = 5; - } - return (s >= l) ? l : BAD_OB; -} - -DWORD RPL_CreateTemp(DWORD l) -{ - DWORD a, b, c; - BYTE *p; - - l += 6; // memory for link field (5) + marker (1) and end - b = Read5(RSKTOP); // tail address of rtn stack - c = Read5(DSKTOP); // top of data stack - if ((b+l)>c) // there's not enough memory to move DSKTOP - { - RPL_GarbageCol(); // do a garbage collection - b = Read5(RSKTOP); // reload tail address of rtn stack - c = Read5(DSKTOP); // reload top of data stack - } - if ((b+l)>c) return 0; // check if now there's enough memory to move DSKTOP - a = Read5(TEMPTOP); // tail address of top object - Write5(TEMPTOP, a+l); // adjust new end of top object - Write5(RSKTOP, b+l); // adjust new end of rtn stack - Write5(AVMEM, (c-b-l)/5); // calculate free memory (*5 nibbles) - p = (LPBYTE) malloc(b-a); // move down rtn stack - Npeek(p,a,b-a); - Nwrite(p,a+l,b-a); - free(p); - Write5(a+l-5,l); // set object length field - return (a+1); // return base address of new object -} - -UINT RPL_Depth(VOID) -{ - return (Read5(EDITLINE) - Read5(DSKTOP)) / 5 - 1; -} - -DWORD RPL_Pick(UINT l) -{ - DWORD stkp; - - _ASSERT(l > 0); // first stack element is one - if (l == 0) return 0; - if (METAKERNEL) ++l; // Metakernel support - if (RPL_Depth() < l) return 0; // not enough elements on stack - stkp = Read5(DSKTOP) + (l-1)*5; - return Read5(stkp); // return object address -} - -VOID RPL_Replace(DWORD n) -{ - DWORD stkp; - - stkp = Read5(DSKTOP); - if (METAKERNEL) stkp+=5; // Metakernel support - Write5(stkp,n); - return; -} - -VOID RPL_Push(UINT l,DWORD n) -{ - UINT i; - DWORD stkp, avmem; - - if (l > RPL_Depth() + 1) return; // invalid stack level - - avmem = Read5(AVMEM); // amount of free memory - if (avmem == 0) return; // no memory free - avmem--; // fetch memory - Write5(AVMEM,avmem); // save new amount of free memory - - if (METAKERNEL) ++l; // Metakernel, save MK object on stack level 1 - - stkp = Read5(DSKTOP) - 5; // get pointer of new stack level 1 - Write5(DSKTOP,stkp); // save it - - for (i = 1; i < l; ++i) // move down stack level entries before insert pos - { - Write5(stkp,Read5(stkp+5)); // move down stack level entry - stkp += 5; // next stack entry - } - - Write5(stkp,n); // save pointer of new object on given stack level - return; -} +/* + * rpl.c + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ +#include "pch.h" +#include "Emu48.h" +#include "ops.h" +#include "io.h" + +//| 38G | 39G | 40G | 48SX | 48GX | 49G | Name +//#F0688 #806E9 #806E9 #7056A #806E9 #806E9 =TEMPOB +//#F068D #806EE #806EE #7056F #806EE #806EE =TEMPTOP +//#F0692 #806F3 #806F3 #70574 #806F3 #806F3 =RSKTOP (B) +//#F0697 #806F8 #806F8 #70579 #806F8 #806F8 =DSKTOP (D1) +//#F069C #806FD #806FD #7057E #806FD #806FD =EDITLINE +//#F0DEA #80E9B #80E9B #7066E #807ED #80E9B =AVMEM (D) +//#F0705 #8076B #8076B #705B0 #8072F #8076B =INTRPPTR (D0) +//#F0E42 #80F02 #80F02 #706C5 #80843 #80F02 =SystemFlags + +#define TEMPOB ((cCurrentRomType=='S')?0x7056A:0x806E9) +#define TEMPTOP ((cCurrentRomType=='S')?0x7056F:0x806EE) +#define RSKTOP ((cCurrentRomType=='S')?0x70574:0x806F3) +#define DSKTOP ((cCurrentRomType=='S')?0x70579:0x806F8) +#define EDITLINE ((cCurrentRomType=='S')?0x7057E:0x806FD) +#define AVMEM ((cCurrentRomType!='X')?((cCurrentRomType=='S')?0x7066E:0x807ED):0x80E9B) +#define INTRPPTR ((cCurrentRomType!='X')?((cCurrentRomType=='S')?0x705B0:0x8072F):0x8076B) +#define SYSTEMFLAGS ((cCurrentRomType!='X')?((cCurrentRomType=='S')?0x706C5:0x80843):0x80F02) + +#define DOINT 0x02614 // Precision Integer (HP49G) +#define DOLNGREAL 0x0263A // Precision Real (HP49G) +#define DOLNGCMP 0x02660 // Precision Complex (HP49G) +#define DOMATRIX 0x02686 // Symbolic matrix (HP49G) +#define DOFLASHP 0x026AC // Flash PTR (HP49G) +#define DOAPLET 0x026D5 // Aplet (HP49G) +#define DOMINIFONT 0x026FE // Mini Font (HP49G) +#define DOBINT 0x02911 // System Binary +#define DOREAL 0x02933 // Real +#define DOEREL 0x02955 // Long Real +#define DOCMP 0x02977 // Complex +#define DOECMP 0x0299D // Long Complex +#define DOCHAR 0x029BF // Character +#define DOARRY 0x029E8 // Array +#define DOLNKARRY 0x02A0A // Linked Array +#define DOCSTR 0x02A2C // String +#define DOHSTR 0x02A4E // Binary Integer +#define DOLIST 0x02A74 // List +#define DORRP 0x02A96 // Directory +#define DOSYMB 0x02AB8 // Algebraic +#define DOEXT 0x02ADA // Unit +#define DOTAG 0x02AFC // Tagged +#define DOGROB 0x02B1E // Graphic +#define DOLIB 0x02B40 // Library +#define DOBAK 0x02B62 // Backup +#define DOEXT0 0x02B88 // Library Data +#define DOEXT1 0x02BAA // Reserved 1, ACcess PoinTeR (HP48GX and later) +#define DOEXT2 0x02BCC // Reserved 2, Font (HP49G) +#define DOEXT3 0x02BEE // Reserved 3 +#define DOEXT4 0x02C10 // Reserved 4 +#define DOCOL 0x02D9D // Program +#define DOCODE 0x02DCC // Code +#define DOIDNT 0x02E48 // Global Name +#define DOLAM 0x02E6D // Local Name +#define DOROMP 0x02E92 // XLIB Name +#define SEMI 0x0312B // ; + +#define GARBAGECOL 0x0613E // =GARBAGECOL entry for HP48S/G and HP49G + +// check for Metakernel version +#define METAKERNEL Metakernel() + +// search for "MDGKER:MK2.30" or "MDGKER:PREVIE" in port1 of a HP48GX +static BOOL Metakernel(VOID) +{ + BOOL bMkDetect = FALSE; + + // card in slot1 of a HP48GX enabled + if (cCurrentRomType=='G' && Port1 && Chipset.cards_status & PORT1_PRESENT) + { + // check for Metakernel string "MDGKER:" + if (!strncmp((LPCSTR) &Port1[12],"\xD\x4\x4\x4\x7\x4\xB\x4\x5\x4\x2\x5\xA\x3",14)) + { + bMkDetect = TRUE; // Metakernel detected + // check for "MK" + if (!strncmp((LPCSTR) &Port1[26],"\xD\x4\xB\x4",4)) + { + // get version number + WORD wVersion = ((Port1[30] * 10) + Port1[34]) * 10 + + Port1[36]; + + // version newer then V2.30, then compatible with HP OS + bMkDetect = (wVersion <= 230); + } + } + } + return bMkDetect; +} + +static DWORD RPL_GarbageCol(VOID) // RPL variables must be in system RAM +{ + CHIPSET OrgChipset; + DWORD dwAVMEM; + + // only for HP48SX, HP48GX and HP49G + _ASSERT(cCurrentRomType == 'S' || cCurrentRomType == 'G' || cCurrentRomType == 'X'); + + OrgChipset = Chipset; // save original chipset + + // entry for =GARBAGECOL + Chipset.P = 0; // P=0 + Chipset.mode_dec = FALSE; // hex mode + Chipset.pc = GARBAGECOL; // =GARBAGECOL entry + rstkpush(0xFFFFF); // return address for stopping + + while (Chipset.pc != 0xFFFFF) // wait for stop address + { + EvalOpcode(FASTPTR(Chipset.pc)); // execute opcode + } + + dwAVMEM = Npack(Chipset.C,5); // available AVMEM + Chipset = OrgChipset; // restore original chipset + return dwAVMEM; +} + +BOOL RPL_GetSystemFlag(INT nFlag) +{ + DWORD dwAddr; + BYTE byMask,byFlag; + + _ASSERT(nFlag > 0); // first flag is 1 + + // calculate memory address and bit mask + dwAddr = SYSTEMFLAGS + (nFlag - 1) / 4; + byMask = 1 << ((nFlag - 1) & 0x3); + + Npeek(&byFlag,dwAddr,sizeof(byFlag)); + return (byFlag & byMask) != 0; +} + +DWORD RPL_SkipOb(DWORD d) +{ + BYTE X[8]; + DWORD n, l; + + Npeek(X,d,5); + n = Npack(X, 5); // read prolog + switch (n) + { + case DOFLASHP: l = (cCurrentRomType!='X') ? 5 : 12; break; // Flash PTR (HP49G) + case DOBINT: l = 10; break; // System Binary + case DOREAL: l = 21; break; // Real + case DOEREL: l = 26; break; // Long Real + case DOCMP: l = 37; break; // Complex + case DOECMP: l = 47; break; // Long Complex + case DOCHAR: l = 7; break; // Character + case DOROMP: l = 11; break; // XLIB Name + case DOMATRIX: // Symbolic matrix (HP49G) + if (cCurrentRomType!='X') + { + l = 5; + break; + } + case DOLIST: // List + case DOSYMB: // Algebraic + case DOEXT: // Unit + case DOCOL: // Program + n=d+5; + do + { + d=n; n=RPL_SkipOb(d); + } while (d!=n); + return n+5; + case SEMI: return d; // SEMI + case DOIDNT: // Global Name + case DOLAM: // Local Name + case DOTAG: // Tagged + Npeek(X,d+5,2); n = 7 + Npack(X,2)*2; + return RPL_SkipOb(d+n); + case DORRP: // Directory + d+=8; + n = Read5(d); + if (n==0) + { + return d+5; + } + else + { + d+=n; + Npeek(X,d,2); + n = Npack(X,2)*2 + 4; + return RPL_SkipOb(d+n); + } + case DOINT: // Precision Integer (HP49G) + case DOAPLET: // Aplet (HP49G) + case DOMINIFONT: // Mini Font (HP49G) + if (cCurrentRomType!='X') + { + l = 5; + break; + } + case DOARRY: // Array + case DOLNKARRY: // Linked Array + case DOCSTR: // String + case DOHSTR: // Binary Integer + case DOGROB: // Graphic + case DOLIB: // Library + case DOBAK: // Backup + case DOEXT0: // Library Data + case DOEXT1: // Reserved 1 + if (n == DOEXT1 && cCurrentRomType != 'S') + { + // on HP48G series and later interpreted as DOACPTR + l = 15; break; // ACcess PoinTeR + break; + } + case DOEXT2: // Reserved 2, Font (HP49G) + case DOEXT3: // Reserved 3 + case DOEXT4: // Reserved 4 + case DOCODE: // Code + l = 5+Read5(d+5); + break; + case DOLNGREAL: // Precision Real (HP49G) + l = 5; + if (cCurrentRomType=='X') + { + l += Read5(d+l); + l += Read5(d+l); + } + break; + case DOLNGCMP: // Precision Complex (HP49G) + l = 5; + if (cCurrentRomType=='X') + { + l += Read5(d+l); + l += Read5(d+l); + l += Read5(d+l); + l += Read5(d+l); + } + break; + default: return d+5; + } + return d+l; +} + +DWORD RPL_ObjectSize(BYTE *o,DWORD s) +{ + DWORD n, l = 0; + + if (s < 5) return BAD_OB; // size too small for prolog + n = Npack(o,5); // read prolog + switch (n) + { + case DOFLASHP: l = (cCurrentRomType!='X') ? 5 : 12; break; // Flash PTR (HP49G) + case DOBINT: l = 10; break; // System Binary + case DOREAL: l = 21; break; // Real + case DOEREL: l = 26; break; // Long Real + case DOCMP: l = 37; break; // Complex + case DOECMP: l = 47; break; // Long Complex + case DOCHAR: l = 7; break; // Character + case DOROMP: l = 11; break; // XLIB Name + case DOMATRIX: // Symbolic matrix (HP49G) + if (cCurrentRomType!='X') + { + l = 5; + break; + } + case DOLIST: // List + case DOSYMB: // Algebraic + case DOEXT: // Unit + case DOCOL: // Program + n = 5; // prolog length + do + { + l += n; + if (l > s) return BAD_OB; // prevent negative size argument + n = RPL_ObjectSize(o+l,s-l); // get new object + if (n == BAD_OB) return BAD_OB; // buffer overflow + } + while (n); + l += 5; + break; + case SEMI: l = 0; break; // SEMI + case DOIDNT: // Global Name + case DOLAM: // Local Name + case DOTAG: // Tagged + if (s < 5 + 2) return BAD_OB; + l = 7 + Npack(o+5,2) * 2; // prolog + name length + if (l > s) return BAD_OB; // prevent negative size argument + n = RPL_ObjectSize(o+l,s-l); // get new object + if (n == BAD_OB) return BAD_OB; // buffer overflow + l += n; + break; + case DORRP: // Directory + if (s < 8 + 5) return BAD_OB; + n = Npack(o+8,5); + if (n == 0) // empty dir + { + l = 13; + } + else + { + l = 8 + n; + if (s < l + 2) return BAD_OB; + n = Npack(o+l,2) * 2 + 4; + l += n; + if (l > s) return BAD_OB; // prevent negative size argument + n = RPL_ObjectSize(o+l,s-l); // next rrp + if (n == BAD_OB) return BAD_OB; // buffer overflow + l += n; + } + break; + case DOINT: // Precision Integer (HP49G) + case DOAPLET: // Aplet (HP49G) + case DOMINIFONT: // Mini Font (HP49G) + if (cCurrentRomType!='X') + { + l = 5; + break; + } + case DOARRY: // Array + case DOLNKARRY: // Linked Array + case DOCSTR: // String + case DOHSTR: // Binary Integer + case DOGROB: // Graphic + case DOLIB: // Library + case DOBAK: // Backup + case DOEXT0: // Library Data + case DOEXT1: // Reserved 1 + if (n == DOEXT1 && cCurrentRomType != 'S') + { + // on HP48G series and later interpreted as DOACPTR + l = 15; break; // ACcess PoinTeR + break; + } + case DOEXT2: // Reserved 2, Font (HP49G) + case DOEXT3: // Reserved 3 + case DOEXT4: // Reserved 4 + case DOCODE: // Code + if (s < 5 + 5) return BAD_OB; + l = 5 + Npack(o+5,5); + break; + case DOLNGREAL: // Precision Real (HP49G) + l = 5; + if (cCurrentRomType=='X') + { + if (s < l + 5) return BAD_OB; + l += Npack(o+l,5); + if (s < l + 5) return BAD_OB; + l += Npack(o+l,5); + } + break; + case DOLNGCMP: // Precision Complex (HP49G) + l = 5; + if (cCurrentRomType=='X') + { + if (s < l + 5) return BAD_OB; + l += Npack(o+l,5); + if (s < l + 5) return BAD_OB; + l += Npack(o+l,5); + if (s < l + 5) return BAD_OB; + l += Npack(o+l,5); + if (s < l + 5) return BAD_OB; + l += Npack(o+l,5); + } + break; + default: l = 5; + } + return (s >= l) ? l : BAD_OB; +} + +DWORD RPL_CreateTemp(DWORD l) +{ + DWORD a, b, c; + BYTE *p; + + l += 6; // memory for link field (5) + marker (1) and end + b = Read5(RSKTOP); // tail address of rtn stack + c = Read5(DSKTOP); // top of data stack + if ((b+l)>c) // there's not enough memory to move DSKTOP + { + RPL_GarbageCol(); // do a garbage collection + b = Read5(RSKTOP); // reload tail address of rtn stack + c = Read5(DSKTOP); // reload top of data stack + } + if ((b+l)>c) return 0; // check if now there's enough memory to move DSKTOP + a = Read5(TEMPTOP); // tail address of top object + Write5(TEMPTOP, a+l); // adjust new end of top object + Write5(RSKTOP, b+l); // adjust new end of rtn stack + Write5(AVMEM, (c-b-l)/5); // calculate free memory (*5 nibbles) + p = (LPBYTE) malloc(b-a); // move down rtn stack + Npeek(p,a,b-a); + Nwrite(p,a+l,b-a); + free(p); + Write5(a+l-5,l); // set object length field + return (a+1); // return base address of new object +} + +UINT RPL_Depth(VOID) +{ + return (Read5(EDITLINE) - Read5(DSKTOP)) / 5 - 1; +} + +DWORD RPL_Pick(UINT l) +{ + DWORD stkp; + + _ASSERT(l > 0); // first stack element is one + if (l == 0) return 0; + if (METAKERNEL) ++l; // Metakernel support + if (RPL_Depth() < l) return 0; // not enough elements on stack + stkp = Read5(DSKTOP) + (l-1)*5; + return Read5(stkp); // return object address +} + +VOID RPL_Replace(DWORD n) +{ + DWORD stkp; + + stkp = Read5(DSKTOP); + if (METAKERNEL) stkp+=5; // Metakernel support + Write5(stkp,n); + return; +} + +VOID RPL_Push(UINT l,DWORD n) +{ + UINT i; + DWORD stkp, avmem; + + if (l > RPL_Depth() + 1) return; // invalid stack level + + avmem = Read5(AVMEM); // amount of free memory + if (avmem == 0) return; // no memory free + avmem--; // fetch memory + Write5(AVMEM,avmem); // save new amount of free memory + + if (METAKERNEL) ++l; // Metakernel, save MK object on stack level 1 + + stkp = Read5(DSKTOP) - 5; // get pointer of new stack level 1 + Write5(DSKTOP,stkp); // save it + + for (i = 1; i < l; ++i) // move down stack level entries before insert pos + { + Write5(stkp,Read5(stkp+5)); // move down stack level entry + stkp += 5; // next stack entry + } + + Write5(stkp,n); // save pointer of new object on given stack level + return; +} diff --git a/Sources/Emu48/serial.c b/Sources/Emu48/SERIAL.C similarity index 95% rename from Sources/Emu48/serial.c rename to Sources/Emu48/SERIAL.C index ccbcabc..d95823d 100644 --- a/Sources/Emu48/serial.c +++ b/Sources/Emu48/SERIAL.C @@ -1,401 +1,400 @@ -/* - * Serial.c - * - * This file is part of Emu48 - * - * Copyright (C) 1998 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" -#include "io.h" - -#define INTERRUPT ((void)(Chipset.SoftInt=TRUE,bInterrupt=TRUE)) - -// state of USRQ -#define NINT2ERBZ ((Chipset.IORam[IOC] & (SON | ERBZ)) == (SON | ERBZ) && (Chipset.IORam[RCS] & RBZ) != 0) -#define NINT2ERBF ((Chipset.IORam[IOC] & (SON | ERBF)) == (SON | ERBF) && (Chipset.IORam[RCS] & RBF) != 0) -#define NINT2ETBE ((Chipset.IORam[IOC] & (SON | ETBE)) == (SON | ETBE) && (Chipset.IORam[TCS] & TBF) == 0) - -#define NINT2USRQ (NINT2ERBZ || NINT2ERBF || NINT2ETBE) - -static HANDLE hComm = NULL; - -static HANDLE hCThreadTxd; -static HANDLE hCThreadEv; - -static HANDLE hEventTxd; -static BOOL bWriting; -static BYTE tbr; - -static BOOL bReading; -static BYTE cBuffer[32]; -static WORD nRp; -static DWORD dwBytesRead; - -static DWORD WINAPI TransmitThread(LPVOID pParam) -{ - OVERLAPPED osWr = { 0 }; - - osWr.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); - - while (bWriting) - { - WaitForSingleObject(hEventTxd,INFINITE); - if (bWriting) - { - DWORD dwWritten; - if (!WriteFile(hComm,(LPCVOID) &tbr,1,&dwWritten,&osWr)) - if (GetLastError() == ERROR_IO_PENDING) - GetOverlappedResult(hComm,&osWr,&dwWritten,TRUE); - } - } - - CloseHandle(osWr.hEvent); // close write event handle - return 0; - UNREFERENCED_PARAMETER(pParam); -} - -static DWORD WINAPI EventThread(LPVOID pParam) -{ - DWORD dwEvent; - - bReading = TRUE; // flag for SerialThread started - while (bReading) - { - _ASSERT(hComm != NULL); - WaitCommEvent(hComm,&dwEvent,NULL); // wait for serial event - if (dwEvent & EV_RXCHAR) // signal char received - { - CommReceive(); // get data - // interrupt request and emulation thread down - if (Chipset.SoftInt && Chipset.Shutdn) - { - Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode - SetEvent(hEventShutdn); // wake up emulation thread - } - } - if (dwEvent & EV_TXEMPTY) // signal transmit buffer empty - { - IOBit(TCS,TBZ,FALSE); // clear transmitter busy bit - CommTransmit(); // check for new char to transmit - } - if (dwEvent & EV_ERR) // signal error received - { - DWORD dwError; - - ClearCommError(hComm,&dwError,NULL); - if (dwError & (CE_FRAME | CE_OVERRUN | CE_BREAK)) - IOBit(RCS,RER,TRUE); // receiver error - } - } - return 0; - UNREFERENCED_PARAMETER(pParam); -} - -BOOL CommIsOpen(VOID) -{ - return hComm != NULL; // have COM port handle -} - -BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort) -{ - COMMTIMEOUTS CommTimeouts = { MAXDWORD, 0L, 0L, 0L, 0L }; - - LPCTSTR strPort = (Chipset.IORam[IR_CTRL] & EIRU) ? strIrPort : strWirePort; - - _ASSERT(Chipset.IORam[IOC] & SON); // UART on - CommClose(); // close port if already open - - dwBytesRead = 0L; // no bytes received - - if (lstrcmp(strPort, _T(NO_SERIAL))) // port defined - { - TCHAR szDevice[256] = _T("\\\\.\\"); - - // check if device buffer is big enough - _ASSERT(lstrlen(szDevice) + lstrlen(strPort) < (INT) ARRAYSIZEOF(szDevice)); - if (lstrlen(szDevice) + lstrlen(strPort) >= (INT) ARRAYSIZEOF(szDevice)) - return hComm != NULL; - - _tcscat(szDevice,strPort); // device name - hComm = CreateFile(szDevice, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, - NULL); - - if (hComm != INVALID_HANDLE_VALUE) - { - DWORD dwThreadId; - - nRp = 0; // reset receiver state - - SetCommTimeouts(hComm,&CommTimeouts); - CommSetBaud(); - - CommTxBRK(); // update BRK condition - - // event to transmit character - hEventTxd = CreateEvent(NULL,FALSE,FALSE,NULL); - - // create char transmit handler - bWriting = TRUE; - hCThreadTxd = CreateThread(NULL,0,&TransmitThread,NULL,CREATE_SUSPENDED,&dwThreadId); - _ASSERT(hCThreadTxd); - SetThreadPriority(hCThreadTxd,THREAD_PRIORITY_ABOVE_NORMAL); - ResumeThread(hCThreadTxd); // start thread - - // create Comm event handler - bReading = FALSE; - SetCommMask(hComm,EV_RXCHAR | EV_TXEMPTY | EV_ERR); // event on RX, TX, error - hCThreadEv = CreateThread(NULL,0,&EventThread,NULL,CREATE_SUSPENDED,&dwThreadId); - _ASSERT(hCThreadEv); - SetThreadPriority(hCThreadEv,THREAD_PRIORITY_ABOVE_NORMAL); - ResumeThread(hCThreadEv); // start thread - while (!bReading) Sleep(0); // wait for SerialThread started - } - else - { - hComm = NULL; - } - } - - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - wsprintf(buffer,_T("COM port %s.\n"),hComm ? _T("opened"): _T("open error")); - OutputDebugString(buffer); - } - #endif - return hComm != NULL; -} - -VOID CommClose(VOID) -{ - if (hComm != NULL) // port open - { - // workaround to fix problems with some Kermit server programs - // reason: on one hand we have the character transmitting time base on the - // selected baudrate, on the other hand the time between sending the last - // character and closing the port. The last time is much longer on the real - // calculator than on the emulator running at full speed, therefore the - // slow down time on the emulator - Sleep(25); // slow down time - - bReading = FALSE; // kill event thread - SetCommMask(hComm,0L); // clear all events and force WaitCommEvent to return - WaitForSingleObject(hCThreadEv,INFINITE); - CloseHandle(hCThreadEv); - - bWriting = FALSE; // kill write thread - SetEvent(hEventTxd); // continue write thread - WaitForSingleObject(hCThreadTxd,INFINITE); - CloseHandle(hCThreadTxd); - - CloseHandle(hEventTxd); // close Txd event - CloseHandle(hComm); // close port - hComm = NULL; - #if defined DEBUG_SERIAL - OutputDebugString(_T("COM port closed.\n")); - #endif - } - return; -} - -VOID CommSetBaud(VOID) -{ - if (hComm != NULL) - { - const DWORD dwBaudrates[] = { 1200, 1920, 2400, 3840, 4800, 7680, 9600, 15360 }; - - DCB dcb; - - ZeroMemory(&dcb,sizeof(dcb)); - dcb.DCBlength = sizeof(dcb); - dcb.BaudRate = dwBaudrates[Chipset.IORam[BAUD] & 0x7]; - dcb.fBinary = TRUE; - dcb.fParity = TRUE; - dcb.fOutxCtsFlow = FALSE; - dcb.fOutxDsrFlow = FALSE; - dcb.fDtrControl = DTR_CONTROL_DISABLE; - dcb.fDsrSensitivity = FALSE; - dcb.fOutX = FALSE; - dcb.fErrorChar = FALSE; - dcb.fNull = FALSE; - dcb.fRtsControl = RTS_CONTROL_DISABLE; - dcb.fAbortOnError = FALSE; // may changed in further implementations - dcb.ByteSize = 8; - dcb.Parity = NOPARITY; // no parity check, emulated by software - dcb.StopBits = TWOSTOPBITS; - - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - wsprintf(buffer,_T("CommsetBaud: %ld\n"),dcb.BaudRate); - OutputDebugString(buffer); - } - #endif - - SetCommState(hComm,&dcb); - } - return; -} - -BOOL UpdateUSRQ(VOID) // USRQ handling -{ - BOOL bUSRQ = NINT2USRQ; - IOBit(SRQ1,USRQ,bUSRQ); // update USRQ bit - return bUSRQ; -} - -VOID CommTxBRK(VOID) -{ - if (Chipset.IORam[TCS] & BRK) // BRK condition - { - if (hComm != NULL) // com port open - { - // abort data transfer - PurgeComm(hComm,PURGE_TXABORT | PURGE_TXCLEAR); - SetCommBreak(hComm); // set into BRK state - } - - // TBF and TBZ bits of TCS are undefined - - if (Chipset.IORam[TCS] & LPB) // is loopback bit set - { - dwBytesRead = nRp = 0; // clear receive buffer - cBuffer[dwBytesRead++] = 0; // save character in receive buffer - - CommReceive(); // receive available byte - IOBit(RCS,RER,TRUE); // receiver error (no stop bit) - } - } - else - { - if (hComm != NULL) // com port open - { - ClearCommBreak(hComm); // clear BRK state - } - } - return; -} - -VOID CommTransmit(VOID) -{ - BOOL bTxChar = FALSE; - - EnterCriticalSection(&csTxdLock); - if ( (Chipset.IORam[TCS] & TBZ) == 0 // transmitter not busy - && (Chipset.IORam[TCS] & TBF) != 0) // transmit buffer full - { - tbr = (Chipset.IORam[TBR_MSB] << 4) | Chipset.IORam[TBR_LSB]; - - IOBit(TCS,TBF,FALSE); // clear transmit buffer full bit - IOBit(TCS,TBZ,TRUE); // set transmitter busy bit - - bTxChar = TRUE; - } - LeaveCriticalSection(&csTxdLock); - - if (bTxChar) // character to transmit - { - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - if (isprint(tbr)) - wsprintf(buffer,_T("-> '%c'\n"),tbr); - else - wsprintf(buffer,_T("-> %02X\n"),tbr); - OutputDebugString(buffer); - } - #endif - - if (Chipset.IORam[TCS] & LPB) // is loopback bit set - { - if (dwBytesRead == 0) nRp = 0; // no character received, reset read pointer - cBuffer[nRp+dwBytesRead] = tbr; // save character in receive buffer - ++dwBytesRead; - - CommReceive(); // receive available byte - } - - if (hComm != NULL) // com port open - { - SetEvent(hEventTxd); // write TBR byte - } - else - { - IOBit(TCS,TBZ,FALSE); // clear transmitter busy bit - } - } - if (UpdateUSRQ()) // update USRQ bit - INTERRUPT; - return; -} - -VOID CommReceive(VOID) -{ - OVERLAPPED os = { 0 }; - - if (!(Chipset.IORam[IOC] & SON)) // UART off - { - dwBytesRead = 0L; // no bytes received - return; - } - - EnterCriticalSection(&csRecvLock); - do - { - if (Chipset.IORam[RCS] & RBF) // receive buffer full - break; - - // reject reading if com port is closed and not whole operation - if (hComm) // com port open - { - UINT uCnt = 0; // retry counter - - while (dwBytesRead == 0L) // buffer empty - { - if (ReadFile(hComm,cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE) - dwBytesRead = 0L; - else // bytes received - nRp = 0; // reset read pointer - - // something received or passed 1st retry - if (dwBytesRead != 0L || ++uCnt > 1) - break; // quit - - Sleep(1); // workaround, retry 1ms later - } - } - - if (dwBytesRead == 0L) // receive buffer empty - break; - - #if defined DEBUG_SERIAL - { - TCHAR buffer[256]; - if (isprint(cBuffer[nRp])) - wsprintf(buffer,_T("<- '%c'\n"),cBuffer[nRp]); - else - wsprintf(buffer,_T("<- %02X\n"),cBuffer[nRp]); - OutputDebugString(buffer); - } - #endif - - Chipset.IORam[RBR_MSB] = (cBuffer[nRp] >> 4); - Chipset.IORam[RBR_LSB] = (cBuffer[nRp] & 0x0f); - ++nRp; - --dwBytesRead; - - Chipset.IORam[RCS] |= RBF; // receive buffer full - if (UpdateUSRQ()) // update USRQ bit - INTERRUPT; - } - while (FALSE); - LeaveCriticalSection(&csRecvLock); - return; -} +/* + * Serial.c + * + * This file is part of Emu48 + * + * Copyright (C) 1998 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" +#include "io.h" + +#define INTERRUPT ((void)(Chipset.SoftInt=TRUE,bInterrupt=TRUE)) + +// state of USRQ +#define NINT2ERBZ ((Chipset.IORam[IOC] & (SON | ERBZ)) == (SON | ERBZ) && (Chipset.IORam[RCS] & RBZ) != 0) +#define NINT2ERBF ((Chipset.IORam[IOC] & (SON | ERBF)) == (SON | ERBF) && (Chipset.IORam[RCS] & RBF) != 0) +#define NINT2ETBE ((Chipset.IORam[IOC] & (SON | ETBE)) == (SON | ETBE) && (Chipset.IORam[TCS] & TBF) == 0) + +#define NINT2USRQ (NINT2ERBZ || NINT2ERBF || NINT2ETBE) + +static HANDLE hComm = NULL; + +static HANDLE hCThreadTxd; +static HANDLE hCThreadEv; + +static HANDLE hEventTxd; +static BOOL bWriting; +static BYTE tbr; + +static BOOL bReading; +static BYTE cBuffer[32]; +static WORD nRp; +static DWORD dwBytesRead; + +static DWORD WINAPI TransmitThread(LPVOID pParam) +{ + OVERLAPPED osWr = { 0 }; + + osWr.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + + while (bWriting) + { + WaitForSingleObject(hEventTxd,INFINITE); + if (bWriting) + { + DWORD dwWritten; + if (!WriteFile(hComm,(LPCVOID) &tbr,1,&dwWritten,&osWr)) + if (GetLastError() == ERROR_IO_PENDING) + GetOverlappedResult(hComm,&osWr,&dwWritten,TRUE); + } + } + + CloseHandle(osWr.hEvent); // close write event handle + return 0; + UNREFERENCED_PARAMETER(pParam); +} + +static DWORD WINAPI EventThread(LPVOID pParam) +{ + DWORD dwEvent; + + bReading = TRUE; // flag for SerialThread started + while (bReading) + { + _ASSERT(hComm != NULL); + WaitCommEvent(hComm,&dwEvent,NULL); // wait for serial event + if (dwEvent & EV_RXCHAR) // signal char received + { + CommReceive(); // get data + // interrupt request and emulation thread down + if (Chipset.SoftInt && Chipset.Shutdn) + { + Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode + SetEvent(hEventShutdn); // wake up emulation thread + } + } + if (dwEvent & EV_TXEMPTY) // signal transmit buffer empty + { + IOBit(TCS,TBZ,FALSE); // clear transmitter busy bit + CommTransmit(); // check for new char to transmit + } + if (dwEvent & EV_ERR) // signal error received + { + DWORD dwError; + + ClearCommError(hComm,&dwError,NULL); + if (dwError & (CE_FRAME | CE_OVERRUN | CE_BREAK)) + IOBit(RCS,RER,TRUE); // receiver error + } + } + return 0; + UNREFERENCED_PARAMETER(pParam); +} + +BOOL CommIsOpen(VOID) +{ + return hComm != NULL; // have COM port handle +} + +BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort) +{ + COMMTIMEOUTS CommTimeouts = { MAXDWORD, 0L, 0L, 0L, 0L }; + + LPCTSTR strPort = (Chipset.IORam[IR_CTRL] & EIRU) ? strIrPort : strWirePort; + + CommClose(); // close port if already open + + dwBytesRead = 0L; // no bytes received + + if (lstrcmp(strPort, _T(NO_SERIAL))) // port defined + { + TCHAR szDevice[256] = _T("\\\\.\\"); + + // check if device buffer is big enough + _ASSERT(lstrlen(szDevice) + lstrlen(strPort) < (INT) ARRAYSIZEOF(szDevice)); + if (lstrlen(szDevice) + lstrlen(strPort) >= (INT) ARRAYSIZEOF(szDevice)) + return hComm != NULL; + + _tcscat(szDevice,strPort); // device name + hComm = CreateFile(szDevice, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + + if (hComm != INVALID_HANDLE_VALUE) + { + DWORD dwThreadId; + + nRp = 0; // reset receiver state + + SetCommTimeouts(hComm,&CommTimeouts); + CommSetBaud(); + + CommTxBRK(); // update BRK condition + + // event to transmit character + hEventTxd = CreateEvent(NULL,FALSE,FALSE,NULL); + + // create char transmit handler + bWriting = TRUE; + hCThreadTxd = CreateThread(NULL,0,&TransmitThread,NULL,CREATE_SUSPENDED,&dwThreadId); + _ASSERT(hCThreadTxd); + SetThreadPriority(hCThreadTxd,THREAD_PRIORITY_ABOVE_NORMAL); + ResumeThread(hCThreadTxd); // start thread + + // create Comm event handler + bReading = FALSE; + SetCommMask(hComm,EV_RXCHAR | EV_TXEMPTY | EV_ERR); // event on RX, TX, error + hCThreadEv = CreateThread(NULL,0,&EventThread,NULL,CREATE_SUSPENDED,&dwThreadId); + _ASSERT(hCThreadEv); + SetThreadPriority(hCThreadEv,THREAD_PRIORITY_ABOVE_NORMAL); + ResumeThread(hCThreadEv); // start thread + while (!bReading) Sleep(0); // wait for SerialThread started + } + else + { + hComm = NULL; + } + } + + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("COM port %s.\n"),hComm ? _T("opened"): _T("open error")); + OutputDebugString(buffer); + } + #endif + return hComm != NULL; +} + +VOID CommClose(VOID) +{ + if (hComm != NULL) // port open + { + // workaround to fix problems with some Kermit server programs + // reason: on one hand we have the character transmitting time base on the + // selected baudrate, on the other hand the time between sending the last + // character and closing the port. The last time is much longer on the real + // calculator than on the emulator running at full speed, therefore the + // slow down time on the emulator + Sleep(25); // slow down time + + bReading = FALSE; // kill event thread + SetCommMask(hComm,0L); // clear all events and force WaitCommEvent to return + WaitForSingleObject(hCThreadEv,INFINITE); + CloseHandle(hCThreadEv); + + bWriting = FALSE; // kill write thread + SetEvent(hEventTxd); // continue write thread + WaitForSingleObject(hCThreadTxd,INFINITE); + CloseHandle(hCThreadTxd); + + CloseHandle(hEventTxd); // close Txd event + CloseHandle(hComm); // close port + hComm = NULL; + #if defined DEBUG_SERIAL + OutputDebugString(_T("COM port closed.\n")); + #endif + } + return; +} + +VOID CommSetBaud(VOID) +{ + if (hComm != NULL) + { + const DWORD dwBaudrates[] = { 1200, 1920, 2400, 3840, 4800, 7680, 9600, 15360 }; + + DCB dcb; + + ZeroMemory(&dcb,sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + dcb.BaudRate = dwBaudrates[Chipset.IORam[BAUD] & 0x7]; + dcb.fBinary = TRUE; + dcb.fParity = TRUE; + dcb.fOutxCtsFlow = FALSE; + dcb.fOutxDsrFlow = FALSE; + dcb.fDtrControl = DTR_CONTROL_DISABLE; + dcb.fDsrSensitivity = FALSE; + dcb.fOutX = FALSE; + dcb.fErrorChar = FALSE; + dcb.fNull = FALSE; + dcb.fRtsControl = RTS_CONTROL_DISABLE; + dcb.fAbortOnError = FALSE; // may changed in further implementations + dcb.ByteSize = 8; + dcb.Parity = NOPARITY; // no parity check, emulated by software + dcb.StopBits = TWOSTOPBITS; + + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("CommsetBaud: %ld\n"),dcb.BaudRate); + OutputDebugString(buffer); + } + #endif + + SetCommState(hComm,&dcb); + } + return; +} + +BOOL UpdateUSRQ(VOID) // USRQ handling +{ + BOOL bUSRQ = NINT2USRQ; + IOBit(SRQ1,USRQ,bUSRQ); // update USRQ bit + return bUSRQ; +} + +VOID CommTxBRK(VOID) +{ + if (Chipset.IORam[TCS] & BRK) // BRK condition + { + if (hComm != NULL) // com port open + { + // abort data transfer + PurgeComm(hComm,PURGE_TXABORT | PURGE_TXCLEAR); + SetCommBreak(hComm); // set into BRK state + } + + // TBF and TBZ bits of TCS are undefined + + if (Chipset.IORam[TCS] & LPB) // is loopback bit set + { + dwBytesRead = nRp = 0; // clear receive buffer + cBuffer[dwBytesRead++] = 0; // save character in receive buffer + + CommReceive(); // receive available byte + IOBit(RCS,RER,TRUE); // receiver error (no stop bit) + } + } + else + { + if (hComm != NULL) // com port open + { + ClearCommBreak(hComm); // clear BRK state + } + } + return; +} + +VOID CommTransmit(VOID) +{ + BOOL bTxChar = FALSE; + + EnterCriticalSection(&csTxdLock); + if ( (Chipset.IORam[TCS] & TBZ) == 0 // transmitter not busy + && (Chipset.IORam[TCS] & TBF) != 0) // transmit buffer full + { + tbr = (Chipset.IORam[TBR_MSB] << 4) | Chipset.IORam[TBR_LSB]; + + IOBit(TCS,TBF,FALSE); // clear transmit buffer full bit + IOBit(TCS,TBZ,TRUE); // set transmitter busy bit + + bTxChar = TRUE; + } + LeaveCriticalSection(&csTxdLock); + + if (bTxChar) // character to transmit + { + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + if (isprint(tbr)) + wsprintf(buffer,_T("-> '%c'\n"),tbr); + else + wsprintf(buffer,_T("-> %02X\n"),tbr); + OutputDebugString(buffer); + } + #endif + + if (Chipset.IORam[TCS] & LPB) // is loopback bit set + { + if (dwBytesRead == 0) nRp = 0; // no character received, reset read pointer + cBuffer[nRp+dwBytesRead] = tbr; // save character in receive buffer + ++dwBytesRead; + + CommReceive(); // receive available byte + } + + if (hComm != NULL) // com port open + { + SetEvent(hEventTxd); // write TBR byte + } + else + { + IOBit(TCS,TBZ,FALSE); // clear transmitter busy bit + } + } + if (UpdateUSRQ()) // update USRQ bit + INTERRUPT; + return; +} + +VOID CommReceive(VOID) +{ + OVERLAPPED os = { 0 }; + + if (!(Chipset.IORam[IOC] & SON)) // UART off + { + dwBytesRead = 0L; // no bytes received + return; + } + + EnterCriticalSection(&csRecvLock); + do + { + if (Chipset.IORam[RCS] & RBF) // receive buffer full + break; + + // reject reading if com port is closed and not whole operation + if (hComm) // com port open + { + UINT uCnt = 0; // retry counter + + while (dwBytesRead == 0L) // buffer empty + { + if (ReadFile(hComm,cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE) + dwBytesRead = 0L; + else // bytes received + nRp = 0; // reset read pointer + + // something received or passed 1st retry + if (dwBytesRead != 0L || ++uCnt > 1) + break; // quit + + Sleep(1); // workaround, retry 1ms later + } + } + + if (dwBytesRead == 0L) // receive buffer empty + break; + + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + if (isprint(cBuffer[nRp])) + wsprintf(buffer,_T("<- '%c'\n"),cBuffer[nRp]); + else + wsprintf(buffer,_T("<- %02X\n"),cBuffer[nRp]); + OutputDebugString(buffer); + } + #endif + + Chipset.IORam[RBR_MSB] = (cBuffer[nRp] >> 4); + Chipset.IORam[RBR_LSB] = (cBuffer[nRp] & 0x0f); + ++nRp; + --dwBytesRead; + + Chipset.IORam[RCS] |= RBF; // receive buffer full + if (UpdateUSRQ()) // update USRQ bit + INTERRUPT; + } + while (FALSE); + LeaveCriticalSection(&csRecvLock); + return; +} diff --git a/Sources/Emu48/settings.c b/Sources/Emu48/SETTINGS.C similarity index 84% rename from Sources/Emu48/settings.c rename to Sources/Emu48/SETTINGS.C index 11585bc..910d683 100644 --- a/Sources/Emu48/settings.c +++ b/Sources/Emu48/SETTINGS.C @@ -1,308 +1,310 @@ -/* - * settings.c - * - * This file is part of Emu48 - * - * Copyright (C) 2000 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" -#include "i28f160.h" - -// #define REGISTRY // use registry instead of *.ini file - -//################ -//# -//# Low level subroutines -//# -//################ - -#if !defined REGISTRY - -// INI-file handling - -#if !defined EMU48_INI - #define EMU48_INI "Emu48.ini" -#endif - -#define ReadString(sec,key,dv,v,sv) GetPrivateProfileString(sec,key,dv,v,sv,_T(EMU48_INI)) -#define ReadInt(sec,key,dv) GetPrivateProfileInt(sec,key,dv,_T(EMU48_INI)); -#define WriteString(sec,key,v) WritePrivateProfileString(sec,key,v,_T(EMU48_INI)) -#define WriteInt(sec,key,v) WritePrivateProfileInt(sec,key,v,_T(EMU48_INI)) -#define DelKey(sec,key) WritePrivateProfileString(sec,key,NULL,_T(EMU48_INI)) - -static BOOL WritePrivateProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue, LPCTSTR lpszFilename) -{ - TCHAR s[16]; - wsprintf(s,_T("%i"),nValue); - return WritePrivateProfileString(lpszSection, lpszEntry, s, lpszFilename); -} - -#else - -// registry handling - -#if !defined REGISTRYKEY - #define REGISTRYKEY "Software\\Emu48" -#endif - -#define ReadString(sec,key,dv,v,sv) GetRegistryString(sec,key,dv,v,sv) -#define ReadInt(sec,key,dv) GetRegistryInt(sec,key,dv) -#define WriteString(sec,key,v) WriteReg(sec,key,REG_SZ,(BYTE *) v,(lstrlen(v)+1) * sizeof(*v)) -#define WriteInt(sec,key,v) WriteReg(sec,key,REG_DWORD,(BYTE *) &v,sizeof(int)) -#define DelKey(sec,key) DelReg(sec,key) - -static VOID ReadReg(LPCTSTR lpSubKey, LPCTSTR lpValueName, LPBYTE lpData, DWORD *pdwSize) -{ - TCHAR lpKey[256] = _T(REGISTRYKEY) _T("\\"); - - DWORD retCode,dwType; - HKEY hKey; - - lstrcat(lpKey, lpSubKey); // full registry key - - retCode = RegOpenKeyEx(HKEY_CURRENT_USER, - lpKey, - 0, - KEY_QUERY_VALUE, - &hKey); - if (retCode == ERROR_SUCCESS) - { - retCode = RegQueryValueEx(hKey,lpValueName,NULL,&dwType,lpData,pdwSize); - RegCloseKey(hKey); - } - - if (retCode != ERROR_SUCCESS) // registry entry not found - *pdwSize = 0; // return zero size - return; -} - -static BOOL WriteReg(LPCTSTR lpSubKey, LPCTSTR lpValueName, DWORD dwType, CONST BYTE *lpData, DWORD cbData) -{ - TCHAR lpKey[256] = _T(REGISTRYKEY) _T("\\"); - - DWORD retCode; - HKEY hKey; - DWORD dwDisposition; - - lstrcat(lpKey, lpSubKey); // full registry key - - retCode = RegCreateKeyEx(HKEY_CURRENT_USER, - lpKey, - 0,_T(""), - REG_OPTION_NON_VOLATILE, - KEY_WRITE, - NULL, - &hKey, - &dwDisposition); - _ASSERT(retCode == ERROR_SUCCESS); - - RegSetValueEx(hKey,lpValueName,0,dwType,lpData,cbData); - RegCloseKey(hKey); - return retCode == ERROR_SUCCESS; -} - -static BOOL DelReg(LPCTSTR lpSubKey, LPCTSTR lpValueName) -{ - TCHAR lpKey[256] = _T(REGISTRYKEY) _T("\\"); - - DWORD retCode; - HKEY hKey; - - lstrcat(lpKey, lpSubKey); // full registry key - - retCode = RegOpenKeyEx(HKEY_CURRENT_USER, - lpKey, - 0, - KEY_SET_VALUE, - &hKey); - if (retCode == ERROR_SUCCESS) - { - retCode = RegDeleteValue(hKey,lpValueName); - RegCloseKey(hKey); - } - return retCode == ERROR_SUCCESS; -} - -static DWORD GetRegistryString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpDefault, LPTSTR lpData, DWORD dwSize) -{ - // buffer size in bytes - DWORD dwBufSize = dwSize * sizeof(*lpData); - - ReadReg(lpszSection,lpszEntry,(LPBYTE) lpData,&dwBufSize); - if (dwBufSize == 0) - { - lstrcpyn(lpData,lpDefault,dwSize); - dwSize = lstrlen(lpData); - } - else - { - dwSize = (dwBufSize / sizeof(*lpData)) - 1; - } - return dwSize; -} - -static UINT GetRegistryInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nDefault) -{ - UINT nValue; - DWORD dwSize = sizeof(nValue); - - ReadReg(lpszSection,lpszEntry,(LPBYTE) &nValue,&dwSize); - return dwSize ? nValue : nDefault; -} - -#endif - - -//################ -//# -//# Public functions -//# -//################ - -VOID ReadSettings(VOID) -{ - // Files - ReadString(_T("Files"),_T("Emu48Directory"),szCurrentDirectory,szEmuDirectory,ARRAYSIZEOF(szEmuDirectory)); - bAutoSave = ReadInt(_T("Files"),_T("AutoSave"),bAutoSave); - bAutoSaveOnExit = ReadInt(_T("Files"),_T("AutoSaveOnExit"),bAutoSaveOnExit); - bSaveDefConfirm = ReadInt(_T("Files"),_T("SaveDefaultConfirm"),bSaveDefConfirm); - bStartupBackup = ReadInt(_T("Files"),_T("StartupBackup"),bStartupBackup); - bLoadObjectWarning = ReadInt(_T("Files"),_T("LoadObjectWarning"),bLoadObjectWarning); - // Port2 - bPort2IsShared = ReadInt(_T("Port2"),_T("IsShared"),bPort2IsShared); - ReadString(_T("Port2"),_T("Filename"),_T("SHARED.BIN"),szPort2Filename,ARRAYSIZEOF(szPort2Filename)); - // KML - bAlwaysDisplayLog = ReadInt(_T("KML"),_T("AlwaysDisplayLog"),bAlwaysDisplayLog); - // Debugger - wInstrSize = ReadInt(_T("Debugger"),_T("LastInstrBufSize"),wInstrSize); - // Disassembler - disassembler_mode = ReadInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode); - disassembler_symb = ReadInt(_T("Disassembler"),_T("Symbolic"),disassembler_symb); - // Emulator - bShowTitle = ReadInt(_T("Emulator"),_T("ShowTitle"),bShowTitle); - bShowMenu = ReadInt(_T("Emulator"),_T("ShowMenu"),bShowMenu); - bAlwaysOnTop = ReadInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop); - bActFollowsMouse = ReadInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse); - bClientWinMove = ReadInt(_T("Emulator"),_T("ClientWinMove"),bClientWinMove); - bSingleInstance = ReadInt(_T("Emulator"),_T("SingleInstance"),bSingleInstance); - bRealSpeed = ReadInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed); - dwSXCycles = ReadInt(_T("Emulator"),_T("SXCycles"),dwSXCycles); - dwGXCycles = ReadInt(_T("Emulator"),_T("GXCycles"),dwGXCycles); - dwKeyMinDelay = ReadInt(_T("Emulator"),_T("KeyMinDelay"),dwKeyMinDelay); - dwWakeupDelay = ReadInt(_T("Emulator"),_T("WakeupDelay"),dwWakeupDelay); - bGrayscale = ReadInt(_T("Emulator"),_T("Grayscale"),bGrayscale); - uWaveDevId = ReadInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId); - dwWaveVol = ReadInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol); - dwWaveTime = ReadInt(_T("Emulator"),_T("WaveTime"),dwWaveTime); - // LowBat - bLowBatDisable = ReadInt(_T("LowBat"),_T("Disable"),bLowBatDisable); - // Macro - bMacroRealSpeed = ReadInt(_T("Macro"),_T("RealSpeed"),bMacroRealSpeed); - nMacroTimeout = ReadInt(_T("Macro"),_T("ReplayTimeout"),nMacroTimeout); - dwMacroMinDelay = ReadInt(_T("Macro"),_T("KeyMinDelay"),dwMacroMinDelay); - // IrPrinter - ReadString(_T("IrPrinter"),_T("Address"),szUdpServer,szUdpServer,ARRAYSIZEOF(szUdpServer)); - wUdpPort = ReadInt(_T("IrPrinter"),_T("Port"),wUdpPort); - // Serial - ReadString(_T("Serial"),_T("Wire"),_T(NO_SERIAL),szSerialWire,ARRAYSIZEOF(szSerialWire)); - ReadString(_T("Serial"),_T("Ir"),_T(NO_SERIAL),szSerialIr,ARRAYSIZEOF(szSerialIr)); - // ROM - bRomWriteable = ReadInt(_T("ROM"),_T("Writeable"),bRomWriteable); - bWP = ReadInt(_T("ROM"),_T("WP#"),bWP); - return; -} - -VOID WriteSettings(VOID) -{ - // Files - WriteString(_T("Files"),_T("Emu48Directory"),szEmuDirectory); - WriteInt(_T("Files"),_T("AutoSave"),bAutoSave); - WriteInt(_T("Files"),_T("AutoSaveOnExit"),bAutoSaveOnExit); - WriteInt(_T("Files"),_T("SaveDefaultConfirm"),bSaveDefConfirm); - WriteInt(_T("Files"),_T("StartupBackup"),bStartupBackup); - WriteInt(_T("Files"),_T("LoadObjectWarning"),bLoadObjectWarning); - // Port2 - WriteInt(_T("Port2"),_T("IsShared"),bPort2IsShared); - WriteString(_T("Port2"),_T("Filename"),szPort2Filename); - // KML - WriteInt(_T("KML"),_T("AlwaysDisplayLog"),bAlwaysDisplayLog); - // Debugger - WriteInt(_T("Debugger"),_T("LastInstrBufSize"),wInstrSize); - // Disassembler - WriteInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode); - WriteInt(_T("Disassembler"),_T("Symbolic"),disassembler_symb); - // Emulator - WriteInt(_T("Emulator"),_T("ShowTitle"),bShowTitle); - WriteInt(_T("Emulator"),_T("ShowMenu"),bShowMenu); - WriteInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop); - WriteInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse); - WriteInt(_T("Emulator"),_T("ClientWinMove"),bClientWinMove); - WriteInt(_T("Emulator"),_T("SingleInstance"),bSingleInstance); - WriteInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed); - WriteInt(_T("Emulator"),_T("SXCycles"),dwSXCycles); - WriteInt(_T("Emulator"),_T("GXCycles"),dwGXCycles); - WriteInt(_T("Emulator"),_T("KeyMinDelay"),dwKeyMinDelay); - WriteInt(_T("Emulator"),_T("WakeupDelay"),dwWakeupDelay); - WriteInt(_T("Emulator"),_T("Grayscale"),bGrayscale); - WriteInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId); - WriteInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol); - WriteInt(_T("Emulator"),_T("WaveTime"),dwWaveTime); - // LowBat - WriteInt(_T("LowBat"),_T("Disable"),bLowBatDisable); - // Macro - WriteInt(_T("Macro"),_T("RealSpeed"),bMacroRealSpeed); - WriteInt(_T("Macro"),_T("ReplayTimeout"),nMacroTimeout); - WriteInt(_T("Macro"),_T("KeyMinDelay"),dwMacroMinDelay); - // IrPrinter - WriteString(_T("IrPrinter"),_T("Address"),szUdpServer); - WriteInt(_T("IrPrinter"),_T("Port"),wUdpPort); - // Serial - WriteString(_T("Serial"),_T("Wire"),szSerialWire); - WriteString(_T("Serial"),_T("Ir"),szSerialIr); - // ROM - WriteInt(_T("ROM"),_T("Writeable"),bRomWriteable); - return; -} - -VOID ReadLastDocument(LPTSTR szFilename, DWORD nSize) -{ - ReadString(_T("Files"),_T("LastDocument"),_T(""),szFilename,nSize); - return; -} - -VOID WriteLastDocument(LPCTSTR szFilename) -{ - WriteString(_T("Files"),_T("LastDocument"),szFilename); - return; -} - -VOID ReadSettingsString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpDefault, LPTSTR lpData, DWORD dwSize) -{ - ReadString(lpszSection,lpszEntry,lpDefault,lpData,dwSize); - return; -} - -VOID WriteSettingsString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPTSTR lpData) -{ - WriteString(lpszSection,lpszEntry,lpData); - return; -} - -INT ReadSettingsInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nDefault) -{ - return ReadInt(lpszSection,lpszEntry,nDefault); -} - -VOID WriteSettingsInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nValue) -{ - WriteInt(lpszSection,lpszEntry,nValue); - return; -} - -VOID DelSettingsKey(LPCTSTR lpszSection, LPCTSTR lpszEntry) -{ - DelKey(lpszSection,lpszEntry); - return; -} +/* + * settings.c + * + * This file is part of Emu48 + * + * Copyright (C) 2000 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" +#include "i28f160.h" + +// #define REGISTRY // use registry instead of *.ini file + +//################ +//# +//# Low level subroutines +//# +//################ + +#if !defined REGISTRY + +// INI-file handling + +#if !defined EMU48_INI + #define EMU48_INI "Emu48.ini" +#endif + +#define ReadString(sec,key,dv,v,sv) GetPrivateProfileString(sec,key,dv,v,sv,_T(EMU48_INI)) +#define ReadInt(sec,key,dv) GetPrivateProfileInt(sec,key,dv,_T(EMU48_INI)); +#define WriteString(sec,key,v) WritePrivateProfileString(sec,key,v,_T(EMU48_INI)) +#define WriteInt(sec,key,v) WritePrivateProfileInt(sec,key,v,_T(EMU48_INI)) +#define DelKey(sec,key) WritePrivateProfileString(sec,key,NULL,_T(EMU48_INI)) + +static BOOL WritePrivateProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue, LPCTSTR lpszFilename) +{ + TCHAR s[16]; + wsprintf(s,_T("%i"),nValue); + return WritePrivateProfileString(lpszSection, lpszEntry, s, lpszFilename); +} + +#else + +// registry handling + +#if !defined REGISTRYKEY + #define REGISTRYKEY "Software\\Emu48" +#endif + +#define ReadString(sec,key,dv,v,sv) GetRegistryString(sec,key,dv,v,sv) +#define ReadInt(sec,key,dv) GetRegistryInt(sec,key,dv) +#define WriteString(sec,key,v) WriteReg(sec,key,REG_SZ,(BYTE *) v,(lstrlen(v)+1) * sizeof(*v)) +#define WriteInt(sec,key,v) WriteReg(sec,key,REG_DWORD,(BYTE *) &v,sizeof(int)) +#define DelKey(sec,key) DelReg(sec,key) + +static VOID ReadReg(LPCTSTR lpSubKey, LPCTSTR lpValueName, LPBYTE lpData, DWORD *pdwSize) +{ + TCHAR lpKey[256] = _T(REGISTRYKEY) _T("\\"); + + DWORD retCode,dwType; + HKEY hKey; + + lstrcat(lpKey, lpSubKey); // full registry key + + retCode = RegOpenKeyEx(HKEY_CURRENT_USER, + lpKey, + 0, + KEY_QUERY_VALUE, + &hKey); + if (retCode == ERROR_SUCCESS) + { + retCode = RegQueryValueEx(hKey,lpValueName,NULL,&dwType,lpData,pdwSize); + RegCloseKey(hKey); + } + + if (retCode != ERROR_SUCCESS) // registry entry not found + *pdwSize = 0; // return zero size + return; +} + +static BOOL WriteReg(LPCTSTR lpSubKey, LPCTSTR lpValueName, DWORD dwType, CONST BYTE *lpData, DWORD cbData) +{ + TCHAR lpKey[256] = _T(REGISTRYKEY) _T("\\"); + + DWORD retCode; + HKEY hKey; + DWORD dwDisposition; + + lstrcat(lpKey, lpSubKey); // full registry key + + retCode = RegCreateKeyEx(HKEY_CURRENT_USER, + lpKey, + 0,_T(""), + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + NULL, + &hKey, + &dwDisposition); + _ASSERT(retCode == ERROR_SUCCESS); + + RegSetValueEx(hKey,lpValueName,0,dwType,lpData,cbData); + RegCloseKey(hKey); + return retCode == ERROR_SUCCESS; +} + +static BOOL DelReg(LPCTSTR lpSubKey, LPCTSTR lpValueName) +{ + TCHAR lpKey[256] = _T(REGISTRYKEY) _T("\\"); + + DWORD retCode; + HKEY hKey; + + lstrcat(lpKey, lpSubKey); // full registry key + + retCode = RegOpenKeyEx(HKEY_CURRENT_USER, + lpKey, + 0, + KEY_SET_VALUE, + &hKey); + if (retCode == ERROR_SUCCESS) + { + retCode = RegDeleteValue(hKey,lpValueName); + RegCloseKey(hKey); + } + return retCode == ERROR_SUCCESS; +} + +static DWORD GetRegistryString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpDefault, LPTSTR lpData, DWORD dwSize) +{ + // buffer size in bytes + DWORD dwBufSize = dwSize * sizeof(*lpData); + + ReadReg(lpszSection,lpszEntry,(LPBYTE) lpData,&dwBufSize); + if (dwBufSize == 0) + { + lstrcpyn(lpData,lpDefault,dwSize); + dwSize = lstrlen(lpData); + } + else + { + dwSize = (dwBufSize / sizeof(*lpData)) - 1; + } + return dwSize; +} + +static UINT GetRegistryInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nDefault) +{ + UINT nValue; + DWORD dwSize = sizeof(nValue); + + ReadReg(lpszSection,lpszEntry,(LPBYTE) &nValue,&dwSize); + return dwSize ? nValue : nDefault; +} + +#endif + + +//################ +//# +//# Public functions +//# +//################ + +VOID ReadSettings(VOID) +{ + // Files + ReadString(_T("Files"),_T("Emu48Directory"),szCurrentDirectory,szEmuDirectory,ARRAYSIZEOF(szEmuDirectory)); + bAutoSave = ReadInt(_T("Files"),_T("AutoSave"),bAutoSave); + bAutoSaveOnExit = ReadInt(_T("Files"),_T("AutoSaveOnExit"),bAutoSaveOnExit); + bSaveDefConfirm = ReadInt(_T("Files"),_T("SaveDefaultConfirm"),bSaveDefConfirm); + bStartupBackup = ReadInt(_T("Files"),_T("StartupBackup"),bStartupBackup); + bLoadObjectWarning = ReadInt(_T("Files"),_T("LoadObjectWarning"),bLoadObjectWarning); + // Port2 + bPort2IsShared = ReadInt(_T("Port2"),_T("IsShared"),bPort2IsShared); + ReadString(_T("Port2"),_T("Filename"),_T("SHARED.BIN"),szPort2Filename,ARRAYSIZEOF(szPort2Filename)); + // KML + bAlwaysDisplayLog = ReadInt(_T("KML"),_T("AlwaysDisplayLog"),bAlwaysDisplayLog); + // Debugger + wInstrSize = ReadInt(_T("Debugger"),_T("LastInstrBufSize"),wInstrSize); + // Disassembler + disassembler_mode = ReadInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode); + disassembler_symb = ReadInt(_T("Disassembler"),_T("Symbolic"),disassembler_symb); + // Emulator + bShowTitle = ReadInt(_T("Emulator"),_T("ShowTitle"),bShowTitle); + bShowMenu = ReadInt(_T("Emulator"),_T("ShowMenu"),bShowMenu); + bAlwaysOnTop = ReadInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop); + bActFollowsMouse = ReadInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse); + bClientWinMove = ReadInt(_T("Emulator"),_T("ClientWinMove"),bClientWinMove); + bSingleInstance = ReadInt(_T("Emulator"),_T("SingleInstance"),bSingleInstance); + bRealSpeed = ReadInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed); + dwSXCycles = ReadInt(_T("Emulator"),_T("SXCycles"),dwSXCycles); + dwGXCycles = ReadInt(_T("Emulator"),_T("GXCycles"),dwGXCycles); + dwKeyMinDelay = ReadInt(_T("Emulator"),_T("KeyMinDelay"),dwKeyMinDelay); + dwWakeupDelay = ReadInt(_T("Emulator"),_T("WakeupDelay"),dwWakeupDelay); + bGrayscale = ReadInt(_T("Emulator"),_T("Grayscale"),bGrayscale); + uWaveDevId = ReadInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId); + dwWaveVol = ReadInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol); + dwWaveTime = ReadInt(_T("Emulator"),_T("WaveTime"),dwWaveTime); + bLocaleDecimalPoint = ReadInt(_T("Emulator"),_T("LocaleDecimalPoint"),bLocaleDecimalPoint); + // LowBat + bLowBatDisable = ReadInt(_T("LowBat"),_T("Disable"),bLowBatDisable); + // Macro + bMacroRealSpeed = ReadInt(_T("Macro"),_T("RealSpeed"),bMacroRealSpeed); + nMacroTimeout = ReadInt(_T("Macro"),_T("ReplayTimeout"),nMacroTimeout); + dwMacroMinDelay = ReadInt(_T("Macro"),_T("KeyMinDelay"),dwMacroMinDelay); + // IrPrinter + ReadString(_T("IrPrinter"),_T("Address"),szUdpServer,szUdpServer,ARRAYSIZEOF(szUdpServer)); + wUdpPort = ReadInt(_T("IrPrinter"),_T("Port"),wUdpPort); + // Serial + ReadString(_T("Serial"),_T("Wire"),_T(NO_SERIAL),szSerialWire,ARRAYSIZEOF(szSerialWire)); + ReadString(_T("Serial"),_T("Ir"),_T(NO_SERIAL),szSerialIr,ARRAYSIZEOF(szSerialIr)); + // ROM + bRomWriteable = ReadInt(_T("ROM"),_T("Writeable"),bRomWriteable); + bWP = ReadInt(_T("ROM"),_T("WP#"),bWP); + return; +} + +VOID WriteSettings(VOID) +{ + // Files + WriteString(_T("Files"),_T("Emu48Directory"),szEmuDirectory); + WriteInt(_T("Files"),_T("AutoSave"),bAutoSave); + WriteInt(_T("Files"),_T("AutoSaveOnExit"),bAutoSaveOnExit); + WriteInt(_T("Files"),_T("SaveDefaultConfirm"),bSaveDefConfirm); + WriteInt(_T("Files"),_T("StartupBackup"),bStartupBackup); + WriteInt(_T("Files"),_T("LoadObjectWarning"),bLoadObjectWarning); + // Port2 + WriteInt(_T("Port2"),_T("IsShared"),bPort2IsShared); + WriteString(_T("Port2"),_T("Filename"),szPort2Filename); + // KML + WriteInt(_T("KML"),_T("AlwaysDisplayLog"),bAlwaysDisplayLog); + // Debugger + WriteInt(_T("Debugger"),_T("LastInstrBufSize"),wInstrSize); + // Disassembler + WriteInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode); + WriteInt(_T("Disassembler"),_T("Symbolic"),disassembler_symb); + // Emulator + WriteInt(_T("Emulator"),_T("ShowTitle"),bShowTitle); + WriteInt(_T("Emulator"),_T("ShowMenu"),bShowMenu); + WriteInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop); + WriteInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse); + WriteInt(_T("Emulator"),_T("ClientWinMove"),bClientWinMove); + WriteInt(_T("Emulator"),_T("SingleInstance"),bSingleInstance); + WriteInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed); + WriteInt(_T("Emulator"),_T("SXCycles"),dwSXCycles); + WriteInt(_T("Emulator"),_T("GXCycles"),dwGXCycles); + WriteInt(_T("Emulator"),_T("KeyMinDelay"),dwKeyMinDelay); + WriteInt(_T("Emulator"),_T("WakeupDelay"),dwWakeupDelay); + WriteInt(_T("Emulator"),_T("Grayscale"),bGrayscale); + WriteInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId); + WriteInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol); + WriteInt(_T("Emulator"),_T("WaveTime"),dwWaveTime); + WriteInt(_T("Emulator"),_T("LocaleDecimalPoint"),bLocaleDecimalPoint); + // LowBat + WriteInt(_T("LowBat"),_T("Disable"),bLowBatDisable); + // Macro + WriteInt(_T("Macro"),_T("RealSpeed"),bMacroRealSpeed); + WriteInt(_T("Macro"),_T("ReplayTimeout"),nMacroTimeout); + WriteInt(_T("Macro"),_T("KeyMinDelay"),dwMacroMinDelay); + // IrPrinter + WriteString(_T("IrPrinter"),_T("Address"),szUdpServer); + WriteInt(_T("IrPrinter"),_T("Port"),wUdpPort); + // Serial + WriteString(_T("Serial"),_T("Wire"),szSerialWire); + WriteString(_T("Serial"),_T("Ir"),szSerialIr); + // ROM + WriteInt(_T("ROM"),_T("Writeable"),bRomWriteable); + return; +} + +VOID ReadLastDocument(LPTSTR szFilename, DWORD nSize) +{ + ReadString(_T("Files"),_T("LastDocument"),_T(""),szFilename,nSize); + return; +} + +VOID WriteLastDocument(LPCTSTR szFilename) +{ + WriteString(_T("Files"),_T("LastDocument"),szFilename); + return; +} + +VOID ReadSettingsString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpDefault, LPTSTR lpData, DWORD dwSize) +{ + ReadString(lpszSection,lpszEntry,lpDefault,lpData,dwSize); + return; +} + +VOID WriteSettingsString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPTSTR lpData) +{ + WriteString(lpszSection,lpszEntry,lpData); + return; +} + +INT ReadSettingsInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nDefault) +{ + return ReadInt(lpszSection,lpszEntry,nDefault); +} + +VOID WriteSettingsInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nValue) +{ + WriteInt(lpszSection,lpszEntry,nValue); + return; +} + +VOID DelSettingsKey(LPCTSTR lpszSection, LPCTSTR lpszEntry) +{ + DelKey(lpszSection,lpszEntry); + return; +} diff --git a/Sources/Emu48/snddef.h b/Sources/Emu48/SNDDEF.H similarity index 97% rename from Sources/Emu48/snddef.h rename to Sources/Emu48/SNDDEF.H index 95a8438..500232d 100644 --- a/Sources/Emu48/snddef.h +++ b/Sources/Emu48/SNDDEF.H @@ -1,102 +1,102 @@ -/* - * snddef.h - * - * This file is part of Emu48 - * - * Copyright (C) 2015 Christoph Gießelink - * - */ - -#include - -#if _MSC_VER >= 1600 // valid for VS2010 and later - -#include -#include - -#else // create the necessary definitions manually - -// -// IKsPropertySet -// - -#ifndef _IKsPropertySet_ -#define _IKsPropertySet_ - -#ifdef __cplusplus -struct IKsPropertySet; -#endif // __cplusplus - -typedef struct IKsPropertySet *LPKSPROPERTYSET; - -DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93); - -#undef INTERFACE -#define INTERFACE IKsPropertySet - -DECLARE_INTERFACE_(IKsPropertySet, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID*) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IKsPropertySet methods - STDMETHOD(Get) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength, - LPVOID pPropertyData, ULONG ulDataLength, PULONG pulBytesReturned) PURE; - STDMETHOD(Set) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength, - LPVOID pPropertyData, ULONG ulDataLength) PURE; - STDMETHOD(QuerySupport) (THIS_ REFGUID rguidPropSet, ULONG ulId, PULONG pulTypeSupport) PURE; -}; - -#endif // _IKsPropertySet_ - -// DirectSound Configuration Component GUID {11AB3EC0-25EC-11d1-A4D8-00C04FC28ACA} -DEFINE_GUID(CLSID_DirectSoundPrivate, 0x11ab3ec0, 0x25ec, 0x11d1, 0xa4, 0xd8, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); - -// DirectSound Device Properties {84624F82-25EC-11d1-A4D8-00C04FC28ACA} -DEFINE_GUID(DSPROPSETID_DirectSoundDevice, 0x84624f82, 0x25ec, 0x11d1, 0xa4, 0xd8, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); - -typedef enum -{ - DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A = 1, - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1 = 2, - DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1 = 3, - DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W = 4, - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A = 5, - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W = 6, - DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A = 7, - DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W = 8, -} DSPROPERTY_DIRECTSOUNDDEVICE; - -#ifdef UNICODE -#define DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W -#else // UNICODE -#define DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A -#endif // UNICODE - -typedef enum -{ - DIRECTSOUNDDEVICE_TYPE_EMULATED, - DIRECTSOUNDDEVICE_TYPE_VXD, - DIRECTSOUNDDEVICE_TYPE_WDM -} DIRECTSOUNDDEVICE_TYPE; - -typedef enum -{ - DIRECTSOUNDDEVICE_DATAFLOW_RENDER, - DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE -} DIRECTSOUNDDEVICE_DATAFLOW; - -typedef struct _DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA -{ - DIRECTSOUNDDEVICE_TYPE Type; // Device type - DIRECTSOUNDDEVICE_DATAFLOW DataFlow; // Device dataflow - GUID DeviceId; // DirectSound device id - LPTSTR Description; // Device description - LPTSTR Module; // Device driver module - LPTSTR Interface; // Device interface - ULONG WaveDeviceId; // Wave device id -} DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA, *PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA; - -#endif +/* + * snddef.h + * + * This file is part of Emu48 + * + * Copyright (C) 2015 Christoph Gießelink + * + */ + +#include + +#if _MSC_VER >= 1600 // valid for VS2010 and later + +#include +#include + +#else // create the necessary definitions manually + +// +// IKsPropertySet +// + +#ifndef _IKsPropertySet_ +#define _IKsPropertySet_ + +#ifdef __cplusplus +struct IKsPropertySet; +#endif // __cplusplus + +typedef struct IKsPropertySet *LPKSPROPERTYSET; + +DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93); + +#undef INTERFACE +#define INTERFACE IKsPropertySet + +DECLARE_INTERFACE_(IKsPropertySet, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID*) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IKsPropertySet methods + STDMETHOD(Get) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength, + LPVOID pPropertyData, ULONG ulDataLength, PULONG pulBytesReturned) PURE; + STDMETHOD(Set) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength, + LPVOID pPropertyData, ULONG ulDataLength) PURE; + STDMETHOD(QuerySupport) (THIS_ REFGUID rguidPropSet, ULONG ulId, PULONG pulTypeSupport) PURE; +}; + +#endif // _IKsPropertySet_ + +// DirectSound Configuration Component GUID {11AB3EC0-25EC-11d1-A4D8-00C04FC28ACA} +DEFINE_GUID(CLSID_DirectSoundPrivate, 0x11ab3ec0, 0x25ec, 0x11d1, 0xa4, 0xd8, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); + +// DirectSound Device Properties {84624F82-25EC-11d1-A4D8-00C04FC28ACA} +DEFINE_GUID(DSPROPSETID_DirectSoundDevice, 0x84624f82, 0x25ec, 0x11d1, 0xa4, 0xd8, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); + +typedef enum +{ + DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A = 1, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1 = 2, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1 = 3, + DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W = 4, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A = 5, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W = 6, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A = 7, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W = 8, +} DSPROPERTY_DIRECTSOUNDDEVICE; + +#ifdef UNICODE +#define DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W +#else // UNICODE +#define DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A +#endif // UNICODE + +typedef enum +{ + DIRECTSOUNDDEVICE_TYPE_EMULATED, + DIRECTSOUNDDEVICE_TYPE_VXD, + DIRECTSOUNDDEVICE_TYPE_WDM +} DIRECTSOUNDDEVICE_TYPE; + +typedef enum +{ + DIRECTSOUNDDEVICE_DATAFLOW_RENDER, + DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE +} DIRECTSOUNDDEVICE_DATAFLOW; + +typedef struct _DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA +{ + DIRECTSOUNDDEVICE_TYPE Type; // Device type + DIRECTSOUNDDEVICE_DATAFLOW DataFlow; // Device dataflow + GUID DeviceId; // DirectSound device id + LPTSTR Description; // Device description + LPTSTR Module; // Device driver module + LPTSTR Interface; // Device interface + ULONG WaveDeviceId; // Wave device id +} DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA, *PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA; + +#endif diff --git a/Sources/Emu48/sndenum.c b/Sources/Emu48/SNDENUM.C similarity index 96% rename from Sources/Emu48/sndenum.c rename to Sources/Emu48/SNDENUM.C index 52986a8..eb9adda 100644 --- a/Sources/Emu48/sndenum.c +++ b/Sources/Emu48/SNDENUM.C @@ -1,256 +1,256 @@ -/* - * SndEnum.c - * - * This file is part of Emu48 - * - * Copyright (C) 2015 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" -#include "snddef.h" - -typedef HRESULT (WINAPI *LPFNDLLGETCLASSOBJECT)(REFCLSID,REFIID,LPVOID *); -static LPFNDLLGETCLASSOBJECT pfnDllGetClassObject = NULL; - -// -// create a IKsPropertySet interface -// -static __inline HRESULT DirectSoundPrivateCreate(LPKSPROPERTYSET *ppKsPropertySet) -{ - LPCLASSFACTORY pClassFactory = NULL; - HRESULT hr; - - // create a class factory object - #if defined __cplusplus - hr = pfnDllGetClassObject(CLSID_DirectSoundPrivate,IID_IClassFactory,(LPVOID *) &pClassFactory); - #else - hr = pfnDllGetClassObject(&CLSID_DirectSoundPrivate,&IID_IClassFactory,(LPVOID *) &pClassFactory); - #endif - - // create the DirectSoundPrivate object and query for an IKsPropertySet interface - if (SUCCEEDED(hr)) - { - #if defined __cplusplus - hr = pClassFactory->CreateInstance(NULL,IID_IKsPropertySet,(LPVOID *) ppKsPropertySet); - #else - hr = pClassFactory->lpVtbl->CreateInstance(pClassFactory,NULL,&IID_IKsPropertySet,(LPVOID *) ppKsPropertySet); - #endif - } - - if (pClassFactory) // release the class factory object - { - #if defined __cplusplus - pClassFactory->Release(); - #else - pClassFactory->lpVtbl->Release(pClassFactory); - #endif - } - - if (FAILED(hr) && *ppKsPropertySet) // handle failure - { - #if defined __cplusplus - (*ppKsPropertySet)->Release(); - #else - (*ppKsPropertySet)->lpVtbl->Release(*ppKsPropertySet); - #endif - } - return hr; -} - -// -// get the device information about a DirectSound GUID. -// -static BOOL GetInfoFromDSoundGUID(CONST GUID *lpGUID, UINT *puWaveDeviceID) -{ - LPKSPROPERTYSET pKsPropertySet = NULL; - HRESULT hr; - BOOL bSuccess = FALSE; - - hr = DirectSoundPrivateCreate(&pKsPropertySet); - if (SUCCEEDED(hr)) - { - ULONG ulBytesReturned = 0; - - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA sDirectSoundDeviceDescription; - - ZeroMemory(&sDirectSoundDeviceDescription,sizeof(sDirectSoundDeviceDescription)); - sDirectSoundDeviceDescription.DeviceId = *lpGUID; - - // get the size of the direct sound device description - #if defined __cplusplus - hr = pKsPropertySet->Get( - DSPROPSETID_DirectSoundDevice, - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, - NULL, - 0, - &sDirectSoundDeviceDescription, - sizeof(sDirectSoundDeviceDescription), - &ulBytesReturned - ); - #else - hr = pKsPropertySet->lpVtbl->Get(pKsPropertySet, - &DSPROPSETID_DirectSoundDevice, - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, - NULL, - 0, - &sDirectSoundDeviceDescription, - sizeof(sDirectSoundDeviceDescription), - &ulBytesReturned - ); - #endif - - if (SUCCEEDED(hr) && ulBytesReturned) - { - PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA psDirectSoundDeviceDescription = NULL; - - // fetch the direct sound device description - psDirectSoundDeviceDescription = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA) malloc(ulBytesReturned); - if (psDirectSoundDeviceDescription != NULL) - { - // init structure with data from length request - *psDirectSoundDeviceDescription = sDirectSoundDeviceDescription; - - #if defined __cplusplus - hr = pKsPropertySet->Get( - DSPROPSETID_DirectSoundDevice, - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, - NULL, - 0, - psDirectSoundDeviceDescription, - ulBytesReturned, - &ulBytesReturned - ); - #else - hr = pKsPropertySet->lpVtbl->Get(pKsPropertySet, - &DSPROPSETID_DirectSoundDevice, - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, - NULL, - 0, - psDirectSoundDeviceDescription, - ulBytesReturned, - &ulBytesReturned - ); - #endif - - if ((bSuccess = SUCCEEDED(hr))) - { - // the requested device ID - *puWaveDeviceID = psDirectSoundDeviceDescription->WaveDeviceId; - } - free(psDirectSoundDeviceDescription); - } - } - - #if defined __cplusplus - pKsPropertySet->Release(); - #else - pKsPropertySet->lpVtbl->Release(pKsPropertySet); - #endif - } - return bSuccess; -} - -// -// callback function for DirectSoundEnumerate() -// -static BOOL CALLBACK DSEnumProc(LPGUID lpGUID,LPCTSTR lpszDesc,LPCTSTR lpszDrvName,LPVOID lpContext) -{ - HWND hWnd = (HWND) lpContext; // window handle of the combo box - - if (lpGUID != NULL) // NULL only for "Primary Sound Driver" - { - UINT uDevID; - - if (GetInfoFromDSoundGUID(lpGUID,&uDevID)) - { - WAVEOUTCAPS woc; - - // has device the necessary capabilities? - if ( waveOutGetDevCaps(uDevID,&woc,sizeof(woc)) == MMSYSERR_NOERROR - && (woc.dwFormats & WAVE_FORMAT_4M08) != 0) - { - // copy product name and wave device ID to combo box - LONG i = (LONG) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) lpszDesc); - SendMessage(hWnd,CB_SETITEMDATA,i,uDevID); - } - } - } - return TRUE; - UNREFERENCED_PARAMETER(lpszDrvName); -} - -// set listfield for sound device combo box -VOID SetSoundDeviceList(HWND hWnd,UINT uDeviceID) -{ - typedef BOOL (CALLBACK *LPDSENUMCALLBACK)(LPGUID, LPCTSTR, LPCTSTR, LPVOID); - typedef HRESULT (WINAPI *LPFN_SDE)(LPDSENUMCALLBACK lpDSEnumCallback,LPVOID lpContext); - LPFN_SDE pfnDirectSoundEnumerate = NULL; - - UINT uSelectDevice,uDevID,uDevNo; - - HMODULE hDSound = LoadLibrary(_T("dsound.dll")); - - if (hDSound != NULL) // direct sound dll found - { - #if defined _UNICODE - pfnDirectSoundEnumerate = (LPFN_SDE) GetProcAddress(hDSound,"DirectSoundEnumerateW"); - #else - pfnDirectSoundEnumerate = (LPFN_SDE) GetProcAddress(hDSound,"DirectSoundEnumerateA"); - #endif - pfnDllGetClassObject = (LPFNDLLGETCLASSOBJECT) GetProcAddress(hDSound,"DllGetClassObject"); - } - - SendMessage(hWnd,CB_RESETCONTENT,0,0); - - // preset selector - uSelectDevice = (UINT) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) _T("Standard Audio")); - SendMessage(hWnd,CB_SETITEMDATA,uSelectDevice,WAVE_MAPPER); - - // check for direct sound interface functions - if (pfnDirectSoundEnumerate != NULL && pfnDllGetClassObject != NULL) - { - // copy product name and wave device ID to combo box - if (SUCCEEDED(pfnDirectSoundEnumerate((LPDSENUMCALLBACK) DSEnumProc,hWnd))) - { - UINT i; - - uDevNo = (UINT) SendMessage(hWnd,CB_GETCOUNT,0,0); - for (i = 0; i < uDevNo; ++i) - { - // translate device ID to combo box position - uDevID = (UINT) SendMessage(hWnd,CB_GETITEMDATA,i,0); - - if (uDevID == uDeviceID) uSelectDevice = i; - } - } - } - else // direct sound not available, detect over wave capabilities - { - WAVEOUTCAPS woc; - - uDevNo = waveOutGetNumDevs(); - for (uDevID = 0; uDevID < uDevNo; ++uDevID) - { - if ( waveOutGetDevCaps(uDevID,&woc,sizeof(woc)) == MMSYSERR_NOERROR - && (woc.dwFormats & WAVE_FORMAT_4M08) != 0) - { - // copy product name and wave device ID to combo box - LONG i = (LONG) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) woc.szPname); - SendMessage(hWnd,CB_SETITEMDATA,i,uDevID); - - if (uDevID == uDeviceID) uSelectDevice = i; - } - } - } - - // activate last selected combo box item - SendMessage(hWnd,CB_SETCURSEL,uSelectDevice,0L); - - if (hDSound != NULL) // direct sound dll loaded - { - pfnDllGetClassObject = NULL; - VERIFY(FreeLibrary(hDSound)); - } - return; -} +/* + * SndEnum.c + * + * This file is part of Emu48 + * + * Copyright (C) 2015 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" +#include "snddef.h" + +typedef HRESULT (WINAPI *LPFNDLLGETCLASSOBJECT)(REFCLSID,REFIID,LPVOID *); +static LPFNDLLGETCLASSOBJECT pfnDllGetClassObject = NULL; + +// +// create a IKsPropertySet interface +// +static __inline HRESULT DirectSoundPrivateCreate(LPKSPROPERTYSET *ppKsPropertySet) +{ + LPCLASSFACTORY pClassFactory = NULL; + HRESULT hr; + + // create a class factory object + #if defined __cplusplus + hr = pfnDllGetClassObject(CLSID_DirectSoundPrivate,IID_IClassFactory,(LPVOID *) &pClassFactory); + #else + hr = pfnDllGetClassObject(&CLSID_DirectSoundPrivate,&IID_IClassFactory,(LPVOID *) &pClassFactory); + #endif + + // create the DirectSoundPrivate object and query for an IKsPropertySet interface + if (SUCCEEDED(hr)) + { + #if defined __cplusplus + hr = pClassFactory->CreateInstance(NULL,IID_IKsPropertySet,(LPVOID *) ppKsPropertySet); + #else + hr = pClassFactory->lpVtbl->CreateInstance(pClassFactory,NULL,&IID_IKsPropertySet,(LPVOID *) ppKsPropertySet); + #endif + } + + if (pClassFactory) // release the class factory object + { + #if defined __cplusplus + pClassFactory->Release(); + #else + pClassFactory->lpVtbl->Release(pClassFactory); + #endif + } + + if (FAILED(hr) && *ppKsPropertySet) // handle failure + { + #if defined __cplusplus + (*ppKsPropertySet)->Release(); + #else + (*ppKsPropertySet)->lpVtbl->Release(*ppKsPropertySet); + #endif + } + return hr; +} + +// +// get the device information about a DirectSound GUID. +// +static BOOL GetInfoFromDSoundGUID(CONST GUID *lpGUID, UINT *puWaveDeviceID) +{ + LPKSPROPERTYSET pKsPropertySet = NULL; + HRESULT hr; + BOOL bSuccess = FALSE; + + hr = DirectSoundPrivateCreate(&pKsPropertySet); + if (SUCCEEDED(hr)) + { + ULONG ulBytesReturned = 0; + + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA sDirectSoundDeviceDescription; + + ZeroMemory(&sDirectSoundDeviceDescription,sizeof(sDirectSoundDeviceDescription)); + sDirectSoundDeviceDescription.DeviceId = *lpGUID; + + // get the size of the direct sound device description + #if defined __cplusplus + hr = pKsPropertySet->Get( + DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, + NULL, + 0, + &sDirectSoundDeviceDescription, + sizeof(sDirectSoundDeviceDescription), + &ulBytesReturned + ); + #else + hr = pKsPropertySet->lpVtbl->Get(pKsPropertySet, + &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, + NULL, + 0, + &sDirectSoundDeviceDescription, + sizeof(sDirectSoundDeviceDescription), + &ulBytesReturned + ); + #endif + + if (SUCCEEDED(hr) && ulBytesReturned) + { + PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA psDirectSoundDeviceDescription = NULL; + + // fetch the direct sound device description + psDirectSoundDeviceDescription = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA) malloc(ulBytesReturned); + if (psDirectSoundDeviceDescription != NULL) + { + // init structure with data from length request + *psDirectSoundDeviceDescription = sDirectSoundDeviceDescription; + + #if defined __cplusplus + hr = pKsPropertySet->Get( + DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, + NULL, + 0, + psDirectSoundDeviceDescription, + ulBytesReturned, + &ulBytesReturned + ); + #else + hr = pKsPropertySet->lpVtbl->Get(pKsPropertySet, + &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, + NULL, + 0, + psDirectSoundDeviceDescription, + ulBytesReturned, + &ulBytesReturned + ); + #endif + + if ((bSuccess = SUCCEEDED(hr))) + { + // the requested device ID + *puWaveDeviceID = psDirectSoundDeviceDescription->WaveDeviceId; + } + free(psDirectSoundDeviceDescription); + } + } + + #if defined __cplusplus + pKsPropertySet->Release(); + #else + pKsPropertySet->lpVtbl->Release(pKsPropertySet); + #endif + } + return bSuccess; +} + +// +// callback function for DirectSoundEnumerate() +// +static BOOL CALLBACK DSEnumProc(LPGUID lpGUID,LPCTSTR lpszDesc,LPCTSTR lpszDrvName,LPVOID lpContext) +{ + HWND hWnd = (HWND) lpContext; // window handle of the combo box + + if (lpGUID != NULL) // NULL only for "Primary Sound Driver" + { + UINT uDevID; + + if (GetInfoFromDSoundGUID(lpGUID,&uDevID)) + { + WAVEOUTCAPS woc; + + // has device the necessary capabilities? + if ( waveOutGetDevCaps(uDevID,&woc,sizeof(woc)) == MMSYSERR_NOERROR + && (woc.dwFormats & WAVE_FORMAT_4M08) != 0) + { + // copy product name and wave device ID to combo box + LONG i = (LONG) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) lpszDesc); + SendMessage(hWnd,CB_SETITEMDATA,i,uDevID); + } + } + } + return TRUE; + UNREFERENCED_PARAMETER(lpszDrvName); +} + +// set listfield for sound device combo box +VOID SetSoundDeviceList(HWND hWnd,UINT uDeviceID) +{ + typedef BOOL (CALLBACK *LPDSENUMCALLBACK)(LPGUID, LPCTSTR, LPCTSTR, LPVOID); + typedef HRESULT (WINAPI *LPFN_SDE)(LPDSENUMCALLBACK lpDSEnumCallback,LPVOID lpContext); + LPFN_SDE pfnDirectSoundEnumerate = NULL; + + UINT uSelectDevice,uDevID,uDevNo; + + HMODULE hDSound = LoadLibrary(_T("dsound.dll")); + + if (hDSound != NULL) // direct sound dll found + { + #if defined _UNICODE + pfnDirectSoundEnumerate = (LPFN_SDE) GetProcAddress(hDSound,"DirectSoundEnumerateW"); + #else + pfnDirectSoundEnumerate = (LPFN_SDE) GetProcAddress(hDSound,"DirectSoundEnumerateA"); + #endif + pfnDllGetClassObject = (LPFNDLLGETCLASSOBJECT) GetProcAddress(hDSound,"DllGetClassObject"); + } + + SendMessage(hWnd,CB_RESETCONTENT,0,0); + + // preset selector + uSelectDevice = (UINT) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) _T("Standard Audio")); + SendMessage(hWnd,CB_SETITEMDATA,uSelectDevice,WAVE_MAPPER); + + // check for direct sound interface functions + if (pfnDirectSoundEnumerate != NULL && pfnDllGetClassObject != NULL) + { + // copy product name and wave device ID to combo box + if (SUCCEEDED(pfnDirectSoundEnumerate((LPDSENUMCALLBACK) DSEnumProc,hWnd))) + { + UINT i; + + uDevNo = (UINT) SendMessage(hWnd,CB_GETCOUNT,0,0); + for (i = 0; i < uDevNo; ++i) + { + // translate device ID to combo box position + uDevID = (UINT) SendMessage(hWnd,CB_GETITEMDATA,i,0); + + if (uDevID == uDeviceID) uSelectDevice = i; + } + } + } + else // direct sound not available, detect over wave capabilities + { + WAVEOUTCAPS woc; + + uDevNo = waveOutGetNumDevs(); + for (uDevID = 0; uDevID < uDevNo; ++uDevID) + { + if ( waveOutGetDevCaps(uDevID,&woc,sizeof(woc)) == MMSYSERR_NOERROR + && (woc.dwFormats & WAVE_FORMAT_4M08) != 0) + { + // copy product name and wave device ID to combo box + LONG i = (LONG) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) woc.szPname); + SendMessage(hWnd,CB_SETITEMDATA,i,uDevID); + + if (uDevID == uDeviceID) uSelectDevice = i; + } + } + } + + // activate last selected combo box item + SendMessage(hWnd,CB_SETCURSEL,uSelectDevice,0L); + + if (hDSound != NULL) // direct sound dll loaded + { + pfnDllGetClassObject = NULL; + VERIFY(FreeLibrary(hDSound)); + } + return; +} diff --git a/Sources/Emu48/sound.c b/Sources/Emu48/SOUND.C similarity index 96% rename from Sources/Emu48/sound.c rename to Sources/Emu48/SOUND.C index 2c3d5a8..048d928 100644 --- a/Sources/Emu48/sound.c +++ b/Sources/Emu48/SOUND.C @@ -1,549 +1,549 @@ -/* - * sound.c - * - * This file is part of Emu48 - * - * Copyright (C) 2013 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" - -// #define DEBUG_SOUND // switch for sound debug purpose -// #define SINE_APPROX // sine signal approximation - -#define SAMPLES_PER_SEC 44100 // sound sampling rate -#define MILLISEC_PER_BUFFER 20 // time period of each sound buffer - -#define NO_OF_BUFFERS 3 // number of reserve buffers before playing - -typedef struct _MSAMPLE -{ - LPBYTE pbyData; - DWORD dwBufferLength; - DWORD dwPosition; - // buffer admin part - DWORD dwIndex; // index to count no. of sample buffers - struct _MSAMPLE* pNext; // pointer to next sample buffer -} MSAMPLE, *PMSAMPLE; - -DWORD dwWaveVol = 64; // wave sound volume -DWORD dwWaveTime = MILLISEC_PER_BUFFER; // time period (in ms) of each sound buffer - -static HWAVEOUT hWaveDevice = NULL; // handle to the waveform-audio output device -static HANDLE hThreadWave = NULL; // thread handle of sound message handler -static DWORD dwThreadWaveId = 0; // thread id of sound message handler -static UINT uHeaders = 0; // no. of sending wave headers -static PMSAMPLE psHead = NULL; // head of sound samples -static PMSAMPLE psTail = NULL; // tail of sound samples - -static CRITICAL_SECTION csSoundLock; // critical section for sound emulation -static DWORD dwSoundBufferLength; // sound buffer length for the given time period - -static VOID FlushSample(VOID); - -// -// sound message handler thread -// -static DWORD WINAPI SoundWndProc(LPVOID pParam) -{ - MSG msg; - - while (GetMessage(&msg, NULL, 0, 0)) - { - if (msg.message == MM_WOM_DONE) - { - HWAVEOUT hwo = (HWAVEOUT) msg.wParam; - PWAVEHDR pwh = (PWAVEHDR) msg.lParam; - - VERIFY(waveOutUnprepareHeader(hwo,pwh,sizeof(*pwh)) == MMSYSERR_NOERROR); - free(pwh->lpData); // free waveform data - free(pwh); // free wavefom header - - _ASSERT(uHeaders > 0); - --uHeaders; // finished header - - FlushSample(); // check for new sample - - if (uHeaders == 0) // no wave headers in transmission - { - bSoundSlow = FALSE; // no sound slow down - bEnableSlow = TRUE; // reenable CPU slow down possibility - } - } - } - return 0; - UNREFERENCED_PARAMETER(pParam); -} - -// -// create sound message handler thread -// -static BOOL CreateWaveThread(VOID) -{ - _ASSERT(hThreadWave == NULL); - - // create sound message handler thread - hThreadWave = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&SoundWndProc,NULL,0,&dwThreadWaveId); - return hThreadWave != NULL; -} - -// -// destroy sound message handler thread -// -static VOID DestroyWaveThread(VOID) -{ - if (hThreadWave != NULL) // sound message handler thread running - { - // shut down thread - while (!PostThreadMessage(dwThreadWaveId,WM_QUIT,0,0)) - Sleep(0); - WaitForSingleObject(hThreadWave,INFINITE); - CloseHandle(hThreadWave); - hThreadWave = NULL; - } - return; -} - -// -// add sample buffer to tail of sample job list -// -static __inline VOID AddSoundBuf(PMSAMPLE psData) -{ - _ASSERT(psData != NULL); // there must be a sample - psData->pNext = NULL; // last sample in job list - - // add sample to list - EnterCriticalSection(&csSoundLock); - { - if (psTail == NULL) // root - { - psData->dwIndex = 0; // this is the root index - - _ASSERT(psHead == NULL); - psHead = psTail = psData; // add sample at head - } - else // add at tail - { - // use next index - psData->dwIndex = psTail->dwIndex + 1; - - psTail->pNext = psData; // add sample at tail - psTail = psData; - } - } - LeaveCriticalSection(&csSoundLock); - return; -} - -// -// remove sample buffer from head of sample job list -// -static __inline BOOL GetSoundBuf(PMSAMPLE *ppsData) -{ - BOOL bSucc; - - EnterCriticalSection(&csSoundLock); - { - if ((bSucc = (psHead != NULL))) // data in head - { - *ppsData = psHead; // get sample - psHead = psHead->pNext; // and remove it from head - if (psHead == NULL) // was last one in head - { - psTail = NULL; // so tail is also the last one - } - } - } - LeaveCriticalSection(&csSoundLock); - return bSucc; -} - -// -// number of sample buffers in sample job list -// -static DWORD GetSoundBufSize(VOID) -{ - DWORD dwNoSamples; - - EnterCriticalSection(&csSoundLock); - { - // no. of samples in buffer - dwNoSamples = (psTail == NULL) - ? 0 - : (psTail->dwIndex - psHead->dwIndex) + 1; - } - LeaveCriticalSection(&csSoundLock); - return dwNoSamples; -} - -// -// allocate new sample buffer and add the -// buffer to the tail of the sample job list -// -static __inline BOOL AllocSample(PMSAMPLE *ppsData) -{ - // alloc new sample buffer - *ppsData = (PMSAMPLE) malloc(sizeof(**ppsData)); - - if (*ppsData != NULL) - { - (*ppsData)->dwPosition = 0; // begin of buffer - (*ppsData)->dwBufferLength = dwSoundBufferLength; - (*ppsData)->pbyData = (LPBYTE) malloc((*ppsData)->dwBufferLength); - if ((*ppsData)->pbyData != NULL) - { - // buffers allocated - _ASSERT(*ppsData != NULL && (*ppsData)->pbyData != NULL); - - AddSoundBuf(*ppsData); // add sample buffer to list - } - else - { - free(*ppsData); // data alloc failed, delete sample buffer - *ppsData = NULL; - } - } - return *ppsData != NULL; -} - -// -// write samples to sample buffer -// -static BOOL AddSamples(DWORD dwSamples, BYTE byLevel) -{ - PMSAMPLE psData; - DWORD dwBufSamples; - #if defined SINE_APPROX - INT w,s,ss,x,y; - #endif - - BOOL bSucc = TRUE; - - if (dwSamples == 0) return TRUE; // nothing to add - - #if defined SINE_APPROX - // calculate constants - w = (INT) (byLevel - 0x80); // max. wave level - s = (INT) dwSamples; // interval length (pi) - ss = s * s; // interval length ^ 2 - x = 1; // sample no. - #endif - - EnterCriticalSection(&csSoundLock); - { - psData = psTail; // get last sample buffer - - do - { - // number of free sound samples in current buffer - dwBufSamples = (psData != NULL) - ? (psData->dwBufferLength - psData->dwPosition) - : 0; - - if (dwBufSamples == 0) // sample buffer is full - { - // alloc new sample buffer - VERIFY(bSucc = AllocSample(&psData)); - if (!bSucc) break; - - _ASSERT( psData != NULL - && psData->pbyData != NULL - && psData->dwPosition == 0); - dwBufSamples = psData->dwBufferLength; - } - - if (dwSamples < dwBufSamples) // free sample buffer is larger then needed - dwBufSamples = dwSamples; // fill only the necessary no. of samples - - dwSamples -= dwBufSamples; // remaining samples after buffer fill - - // fill buffer with level for beep - #if defined SINE_APPROX - for (; dwBufSamples > 0; --dwBufSamples) - { - // sine approximation function - y = w - w * (4 * x * (x - s) + ss ) / ss; - ++x; // next sample - - psData->pbyData[psData->dwPosition++] = (BYTE) (y + 0x80); - } - #else - FillMemory(&psData->pbyData[psData->dwPosition],dwBufSamples,byLevel); - psData->dwPosition += dwBufSamples; - #endif - } - while (dwSamples > 0); - } - LeaveCriticalSection(&csSoundLock); - return bSucc; -} - -// -// write sample buffer from head of sample job list -// to waveform-audio output device and delete the -// sample buffer control from head of sample job list -// -static VOID FlushSample(VOID) -{ - PMSAMPLE psData; - - _ASSERT(hWaveDevice != NULL); - - if (GetSoundBuf(&psData) == TRUE) // fetch sample buffer - { - PWAVEHDR pwh; - - // allocate new wave header - if ((pwh = (PWAVEHDR) malloc(sizeof(*pwh))) != NULL) - { - pwh->lpData = (LPSTR) psData->pbyData; - pwh->dwBufferLength = psData->dwPosition; - pwh->dwBytesRecorded = 0; - pwh->dwUser = 0; - pwh->dwFlags = 0; - pwh->dwLoops = 0; - - ++uHeaders; // add header - - // prepare sample - VERIFY(waveOutPrepareHeader(hWaveDevice,pwh,sizeof(*pwh)) == MMSYSERR_NOERROR); - - // send sample - VERIFY(waveOutWrite(hWaveDevice,pwh,sizeof(*pwh)) == MMSYSERR_NOERROR); - } - free(psData); // delete sample buffer - } - return; -} - -// -// 44.1 kHz, mono, 8-bit waveform-audio output device available -// -BOOL SoundAvailable(UINT uDeviceID) -{ - WAVEOUTCAPS woc; - return waveOutGetDevCaps(uDeviceID,&woc,sizeof(woc)) == MMSYSERR_NOERROR - && (woc.dwFormats & WAVE_FORMAT_4M08) != 0; -} - -// -// get the device ID of the current waveform-audio output device -// -BOOL SoundGetDeviceID(UINT *puDeviceID) -{ - BOOL bSucc = FALSE; - - if (hWaveDevice) // have sound device - { - bSucc = (waveOutGetID(hWaveDevice,puDeviceID) == MMSYSERR_NOERROR); - } - return bSucc; -} - -// -// open waveform-audio output device -// -BOOL SoundOpen(UINT uDeviceID) -{ - // check if sound device is already open - if (hWaveDevice == NULL && SoundAvailable(uDeviceID)) - { - WAVEFORMATEX wf; - BOOL bSucc; - - wf.wFormatTag = WAVE_FORMAT_PCM; - wf.nChannels = 1; - wf.nSamplesPerSec = SAMPLES_PER_SEC; - wf.wBitsPerSample = 8; - wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8; - wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; - wf.cbSize = 0; - - InitializeCriticalSection(&csSoundLock); - - // sound buffer length for the given time period - dwSoundBufferLength = SAMPLES_PER_SEC * dwWaveTime / 1000; - - if ((bSucc = CreateWaveThread())) // create sound message handler - { - // create a sound device, use the CALLBACK_THREAD flag because with the - // CALLBACK_FUNCTION flag unfortunately the called callback function - // can only call a specific set of Windows functions. Attempting to - // call other functions at the wrong time will result in a deadlock. - bSucc = (waveOutOpen(&hWaveDevice,uDeviceID,&wf,dwThreadWaveId,0,CALLBACK_THREAD) == MMSYSERR_NOERROR); - } - if (!bSucc) - { - DestroyWaveThread(); // shut down message thread - DeleteCriticalSection(&csSoundLock); - hWaveDevice = NULL; - } - } - return hWaveDevice != NULL; -} - -// -// close waveform-audio output device -// -VOID SoundClose(VOID) -{ - if (hWaveDevice != NULL) - { - EnterCriticalSection(&csSoundLock); - { - while (psHead != NULL) // cleanup remaining sample buffers - { - PMSAMPLE psNext = psHead->pNext; - - free(psHead->pbyData); - free(psHead); - psHead = psNext; - } - psTail = NULL; - } - LeaveCriticalSection(&csSoundLock); - - // abandon all pending wave headers - VERIFY(waveOutReset(hWaveDevice) == MMSYSERR_NOERROR); - - DestroyWaveThread(); // shut down message thread - - VERIFY(waveOutClose(hWaveDevice) == MMSYSERR_NOERROR); - DeleteCriticalSection(&csSoundLock); - hWaveDevice = NULL; - } - uHeaders = 0; // no wave headers in transmission - bSoundSlow = FALSE; // no sound slow down - bEnableSlow = TRUE; // reenable CPU slow down possibility - return; -} - -// -// calculate the wave level from the beeper bit state -// -static BYTE WaveLevel(WORD wOut) -{ - wOut >>= 11; // mask out beeper bit OR[11] - return (BYTE) (wOut & 0x01) + 1; // return 1 or 2 -} - -// -// decode change of beeper OUT bits -// -VOID SoundOut(CHIPSET* w, WORD wOut) -{ - static DWORD dwLastCyc; // last timer value at beeper bit change - - DWORD dwCycles,dwDiffSatCycles,dwDiffCycles,dwCpuFreq,dwSamples; - BYTE byWaveLevel; - - // sound device not opened or waveform-audio output device not available - if (hWaveDevice == NULL) - return; - - // actual timestamp - dwCycles = (DWORD) (w->cycles & 0xFFFFFFFF); - - dwDiffSatCycles = dwCycles - dwLastCyc; // time difference from syncpoint in original Saturn cycles - - // theoretical CPU frequency from given T2CYCLES - dwCpuFreq = T2CYCLES * 16384; - - if (dwDiffSatCycles > dwCpuFreq / 2) // frequency < 1 Hz - { - dwLastCyc = dwCycles; // initial call for start beeping - return; - } - - // estimated CPU cycles for Clarke/Yorke chip - dwDiffCycles = (cCurrentRomType == 'S') - ? (dwDiffSatCycles * 26) / 25 // Clarke * 1.04 - : (dwDiffSatCycles * 11) / 10; // Yorke * 1.10 - - // adjust original CPU cycles - w->cycles += (dwDiffCycles - dwDiffSatCycles); - dwLastCyc = (DWORD) (w->cycles & 0xFFFFFFFF); // new syncpoint - - // calculate no. of sound samples from CPU cycles, !! intermediate result maybe > 32bit !! - dwSamples = (DWORD) ((2 * (QWORD) dwDiffCycles + 1) * SAMPLES_PER_SEC / 2 / dwCpuFreq); - - if (dwSamples == 0) // frequency too high -> play nothing - return; - - #if defined DEBUG_SOUND - { - TCHAR buffer[256]; - - // calculate rounded time in us - QWORD lDuration = 1000000 * (2 * (QWORD) dwDiffCycles + 1) / (2 * dwCpuFreq); - - wsprintf(buffer,_T("State %u: Time = %I64u us f = %u Hz, Time = %I64u us f = %u Hz\n"), - wOut >> 11,lDuration,(DWORD) (1000000 / 2 / lDuration), - (QWORD) dwSamples * 1000000 / SAMPLES_PER_SEC,SAMPLES_PER_SEC / 2 / dwSamples); - OutputDebugString(buffer); - } - #endif - - // begin of beep - if (uHeaders == 0 && GetSoundBufSize() == 0) - { - // use silence buffers to start output engine - AddSamples(dwSoundBufferLength * NO_OF_BUFFERS,0x80); - } - - // offset for wave level - byWaveLevel = 0x80 + (BYTE) (dwWaveVol * (WaveLevel(wOut) - WaveLevel(w->out)) / 2); - - AddSamples(dwSamples,byWaveLevel); // add samples to latest wave sample buffer - - if (GetSoundBufSize() > NO_OF_BUFFERS) // have more than 3 wave sample buffers - { - FlushSample(); // send 2 of them - FlushSample(); - } - - // ran out of buffers -> disable CPU slow down - InitAdjustSpeed(); // init variables if necessary - bEnableSlow = (GetSoundBufSize() > 1); - - if (bSoundSlow == FALSE) - { - InitAdjustSpeed(); // init variables if necessary - bSoundSlow = TRUE; // CPU slow down - } - return; -} - -// -// beep with frequency (Hz) and duration (ms) -// -VOID SoundBeep(DWORD dwFrequency, DWORD dwDuration) -{ - QWORD lPeriods; - DWORD dwSamples; - BYTE byLevel; - - // waveform-audio output device opened and have frequency - if (hWaveDevice && dwFrequency > 0) - { - // samples for 1/2 of time period - dwSamples = SAMPLES_PER_SEC / 2 / dwFrequency; - - // overall half periods - lPeriods = (QWORD) dwFrequency * dwDuration / 500; - - while (lPeriods-- > 0) // create sample buffers - { - // signal level - byLevel = 0x80 + (BYTE) ((((DWORD) lPeriods & 1) * 2 - 1) * (dwWaveVol / 2)); - - AddSamples(dwSamples,byLevel); // add half period sample - } - - while (GetSoundBufSize() > 0) // samples in job list - FlushSample(); // send sample buffer - } - Sleep(dwDuration); - return; -} +/* + * sound.c + * + * This file is part of Emu48 + * + * Copyright (C) 2013 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" + +// #define DEBUG_SOUND // switch for sound debug purpose +// #define SINE_APPROX // sine signal approximation + +#define SAMPLES_PER_SEC 44100 // sound sampling rate +#define MILLISEC_PER_BUFFER 20 // time period of each sound buffer + +#define NO_OF_BUFFERS 3 // number of reserve buffers before playing + +typedef struct _MSAMPLE +{ + LPBYTE pbyData; + DWORD dwBufferLength; + DWORD dwPosition; + // buffer admin part + DWORD dwIndex; // index to count no. of sample buffers + struct _MSAMPLE* pNext; // pointer to next sample buffer +} MSAMPLE, *PMSAMPLE; + +DWORD dwWaveVol = 64; // wave sound volume +DWORD dwWaveTime = MILLISEC_PER_BUFFER; // time period (in ms) of each sound buffer + +static HWAVEOUT hWaveDevice = NULL; // handle to the waveform-audio output device +static HANDLE hThreadWave = NULL; // thread handle of sound message handler +static DWORD dwThreadWaveId = 0; // thread id of sound message handler +static UINT uHeaders = 0; // no. of sending wave headers +static PMSAMPLE psHead = NULL; // head of sound samples +static PMSAMPLE psTail = NULL; // tail of sound samples + +static CRITICAL_SECTION csSoundLock; // critical section for sound emulation +static DWORD dwSoundBufferLength; // sound buffer length for the given time period + +static VOID FlushSample(VOID); + +// +// sound message handler thread +// +static DWORD WINAPI SoundWndProc(LPVOID pParam) +{ + MSG msg; + + while (GetMessage(&msg, NULL, 0, 0)) + { + if (msg.message == MM_WOM_DONE) + { + HWAVEOUT hwo = (HWAVEOUT) msg.wParam; + PWAVEHDR pwh = (PWAVEHDR) msg.lParam; + + VERIFY(waveOutUnprepareHeader(hwo,pwh,sizeof(*pwh)) == MMSYSERR_NOERROR); + free(pwh->lpData); // free waveform data + free(pwh); // free wavefom header + + _ASSERT(uHeaders > 0); + --uHeaders; // finished header + + FlushSample(); // check for new sample + + if (uHeaders == 0) // no wave headers in transmission + { + bSoundSlow = FALSE; // no sound slow down + bEnableSlow = TRUE; // reenable CPU slow down possibility + } + } + } + return 0; + UNREFERENCED_PARAMETER(pParam); +} + +// +// create sound message handler thread +// +static BOOL CreateWaveThread(VOID) +{ + _ASSERT(hThreadWave == NULL); + + // create sound message handler thread + hThreadWave = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&SoundWndProc,NULL,0,&dwThreadWaveId); + return hThreadWave != NULL; +} + +// +// destroy sound message handler thread +// +static VOID DestroyWaveThread(VOID) +{ + if (hThreadWave != NULL) // sound message handler thread running + { + // shut down thread + while (!PostThreadMessage(dwThreadWaveId,WM_QUIT,0,0)) + Sleep(0); + WaitForSingleObject(hThreadWave,INFINITE); + CloseHandle(hThreadWave); + hThreadWave = NULL; + } + return; +} + +// +// add sample buffer to tail of sample job list +// +static __inline VOID AddSoundBuf(PMSAMPLE psData) +{ + _ASSERT(psData != NULL); // there must be a sample + psData->pNext = NULL; // last sample in job list + + // add sample to list + EnterCriticalSection(&csSoundLock); + { + if (psTail == NULL) // root + { + psData->dwIndex = 0; // this is the root index + + _ASSERT(psHead == NULL); + psHead = psTail = psData; // add sample at head + } + else // add at tail + { + // use next index + psData->dwIndex = psTail->dwIndex + 1; + + psTail->pNext = psData; // add sample at tail + psTail = psData; + } + } + LeaveCriticalSection(&csSoundLock); + return; +} + +// +// remove sample buffer from head of sample job list +// +static __inline BOOL GetSoundBuf(PMSAMPLE *ppsData) +{ + BOOL bSucc; + + EnterCriticalSection(&csSoundLock); + { + if ((bSucc = (psHead != NULL))) // data in head + { + *ppsData = psHead; // get sample + psHead = psHead->pNext; // and remove it from head + if (psHead == NULL) // was last one in head + { + psTail = NULL; // so tail is also the last one + } + } + } + LeaveCriticalSection(&csSoundLock); + return bSucc; +} + +// +// number of sample buffers in sample job list +// +static DWORD GetSoundBufSize(VOID) +{ + DWORD dwNoSamples; + + EnterCriticalSection(&csSoundLock); + { + // no. of samples in buffer + dwNoSamples = (psTail == NULL) + ? 0 + : (psTail->dwIndex - psHead->dwIndex) + 1; + } + LeaveCriticalSection(&csSoundLock); + return dwNoSamples; +} + +// +// allocate new sample buffer and add the +// buffer to the tail of the sample job list +// +static __inline BOOL AllocSample(PMSAMPLE *ppsData) +{ + // alloc new sample buffer + *ppsData = (PMSAMPLE) malloc(sizeof(**ppsData)); + + if (*ppsData != NULL) + { + (*ppsData)->dwPosition = 0; // begin of buffer + (*ppsData)->dwBufferLength = dwSoundBufferLength; + (*ppsData)->pbyData = (LPBYTE) malloc((*ppsData)->dwBufferLength); + if ((*ppsData)->pbyData != NULL) + { + // buffers allocated + _ASSERT(*ppsData != NULL && (*ppsData)->pbyData != NULL); + + AddSoundBuf(*ppsData); // add sample buffer to list + } + else + { + free(*ppsData); // data alloc failed, delete sample buffer + *ppsData = NULL; + } + } + return *ppsData != NULL; +} + +// +// write samples to sample buffer +// +static BOOL AddSamples(DWORD dwSamples, BYTE byLevel) +{ + PMSAMPLE psData; + DWORD dwBufSamples; + #if defined SINE_APPROX + INT w,s,ss,x,y; + #endif + + BOOL bSucc = TRUE; + + if (dwSamples == 0) return TRUE; // nothing to add + + #if defined SINE_APPROX + // calculate constants + w = (INT) (byLevel - 0x80); // max. wave level + s = (INT) dwSamples; // interval length (pi) + ss = s * s; // interval length ^ 2 + x = 1; // sample no. + #endif + + EnterCriticalSection(&csSoundLock); + { + psData = psTail; // get last sample buffer + + do + { + // number of free sound samples in current buffer + dwBufSamples = (psData != NULL) + ? (psData->dwBufferLength - psData->dwPosition) + : 0; + + if (dwBufSamples == 0) // sample buffer is full + { + // alloc new sample buffer + VERIFY(bSucc = AllocSample(&psData)); + if (!bSucc) break; + + _ASSERT( psData != NULL + && psData->pbyData != NULL + && psData->dwPosition == 0); + dwBufSamples = psData->dwBufferLength; + } + + if (dwSamples < dwBufSamples) // free sample buffer is larger then needed + dwBufSamples = dwSamples; // fill only the necessary no. of samples + + dwSamples -= dwBufSamples; // remaining samples after buffer fill + + // fill buffer with level for beep + #if defined SINE_APPROX + for (; dwBufSamples > 0; --dwBufSamples) + { + // sine approximation function + y = w - w * (4 * x * (x - s) + ss ) / ss; + ++x; // next sample + + psData->pbyData[psData->dwPosition++] = (BYTE) (y + 0x80); + } + #else + FillMemory(&psData->pbyData[psData->dwPosition],dwBufSamples,byLevel); + psData->dwPosition += dwBufSamples; + #endif + } + while (dwSamples > 0); + } + LeaveCriticalSection(&csSoundLock); + return bSucc; +} + +// +// write sample buffer from head of sample job list +// to waveform-audio output device and delete the +// sample buffer control from head of sample job list +// +static VOID FlushSample(VOID) +{ + PMSAMPLE psData; + + _ASSERT(hWaveDevice != NULL); + + if (GetSoundBuf(&psData) == TRUE) // fetch sample buffer + { + PWAVEHDR pwh; + + // allocate new wave header + if ((pwh = (PWAVEHDR) malloc(sizeof(*pwh))) != NULL) + { + pwh->lpData = (LPSTR) psData->pbyData; + pwh->dwBufferLength = psData->dwPosition; + pwh->dwBytesRecorded = 0; + pwh->dwUser = 0; + pwh->dwFlags = 0; + pwh->dwLoops = 0; + + ++uHeaders; // add header + + // prepare sample + VERIFY(waveOutPrepareHeader(hWaveDevice,pwh,sizeof(*pwh)) == MMSYSERR_NOERROR); + + // send sample + VERIFY(waveOutWrite(hWaveDevice,pwh,sizeof(*pwh)) == MMSYSERR_NOERROR); + } + free(psData); // delete sample buffer + } + return; +} + +// +// 44.1 kHz, mono, 8-bit waveform-audio output device available +// +BOOL SoundAvailable(UINT uDeviceID) +{ + WAVEOUTCAPS woc; + return waveOutGetDevCaps(uDeviceID,&woc,sizeof(woc)) == MMSYSERR_NOERROR + && (woc.dwFormats & WAVE_FORMAT_4M08) != 0; +} + +// +// get the device ID of the current waveform-audio output device +// +BOOL SoundGetDeviceID(UINT *puDeviceID) +{ + BOOL bSucc = FALSE; + + if (hWaveDevice) // have sound device + { + bSucc = (waveOutGetID(hWaveDevice,puDeviceID) == MMSYSERR_NOERROR); + } + return bSucc; +} + +// +// open waveform-audio output device +// +BOOL SoundOpen(UINT uDeviceID) +{ + // check if sound device is already open + if (hWaveDevice == NULL && SoundAvailable(uDeviceID)) + { + WAVEFORMATEX wf; + BOOL bSucc; + + wf.wFormatTag = WAVE_FORMAT_PCM; + wf.nChannels = 1; + wf.nSamplesPerSec = SAMPLES_PER_SEC; + wf.wBitsPerSample = 8; + wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8; + wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; + wf.cbSize = 0; + + InitializeCriticalSection(&csSoundLock); + + // sound buffer length for the given time period + dwSoundBufferLength = SAMPLES_PER_SEC * dwWaveTime / 1000; + + if ((bSucc = CreateWaveThread())) // create sound message handler + { + // create a sound device, use the CALLBACK_THREAD flag because with the + // CALLBACK_FUNCTION flag unfortunately the called callback function + // can only call a specific set of Windows functions. Attempting to + // call other functions at the wrong time will result in a deadlock. + bSucc = (waveOutOpen(&hWaveDevice,uDeviceID,&wf,dwThreadWaveId,0,CALLBACK_THREAD) == MMSYSERR_NOERROR); + } + if (!bSucc) + { + DestroyWaveThread(); // shut down message thread + DeleteCriticalSection(&csSoundLock); + hWaveDevice = NULL; + } + } + return hWaveDevice != NULL; +} + +// +// close waveform-audio output device +// +VOID SoundClose(VOID) +{ + if (hWaveDevice != NULL) + { + EnterCriticalSection(&csSoundLock); + { + while (psHead != NULL) // cleanup remaining sample buffers + { + PMSAMPLE psNext = psHead->pNext; + + free(psHead->pbyData); + free(psHead); + psHead = psNext; + } + psTail = NULL; + } + LeaveCriticalSection(&csSoundLock); + + // abandon all pending wave headers + VERIFY(waveOutReset(hWaveDevice) == MMSYSERR_NOERROR); + + DestroyWaveThread(); // shut down message thread + + VERIFY(waveOutClose(hWaveDevice) == MMSYSERR_NOERROR); + DeleteCriticalSection(&csSoundLock); + hWaveDevice = NULL; + } + uHeaders = 0; // no wave headers in transmission + bSoundSlow = FALSE; // no sound slow down + bEnableSlow = TRUE; // reenable CPU slow down possibility + return; +} + +// +// calculate the wave level from the beeper bit state +// +static BYTE WaveLevel(WORD wOut) +{ + wOut >>= 11; // mask out beeper bit OR[11] + return (BYTE) (wOut & 0x01) + 1; // return 1 or 2 +} + +// +// decode change of beeper OUT bits +// +VOID SoundOut(CHIPSET* w, WORD wOut) +{ + static DWORD dwLastCyc; // last timer value at beeper bit change + + DWORD dwCycles,dwDiffSatCycles,dwDiffCycles,dwCpuFreq,dwSamples; + BYTE byWaveLevel; + + // sound device not opened or waveform-audio output device not available + if (hWaveDevice == NULL) + return; + + // actual timestamp + dwCycles = (DWORD) (w->cycles & 0xFFFFFFFF); + + dwDiffSatCycles = dwCycles - dwLastCyc; // time difference from syncpoint in original Saturn cycles + + // theoretical CPU frequency from given T2CYCLES + dwCpuFreq = T2CYCLES * 16384; + + if (dwDiffSatCycles > dwCpuFreq / 2) // frequency < 1 Hz + { + dwLastCyc = dwCycles; // initial call for start beeping + return; + } + + // estimated CPU cycles for Clarke/Yorke chip + dwDiffCycles = (cCurrentRomType == 'S') + ? (dwDiffSatCycles * 26) / 25 // Clarke * 1.04 + : (dwDiffSatCycles * 11) / 10; // Yorke * 1.10 + + // adjust original CPU cycles + w->cycles += (dwDiffCycles - dwDiffSatCycles); + dwLastCyc = (DWORD) (w->cycles & 0xFFFFFFFF); // new syncpoint + + // calculate no. of sound samples from CPU cycles, !! intermediate result maybe > 32bit !! + dwSamples = (DWORD) ((2 * (QWORD) dwDiffCycles + 1) * SAMPLES_PER_SEC / 2 / dwCpuFreq); + + if (dwSamples == 0) // frequency too high -> play nothing + return; + + #if defined DEBUG_SOUND + { + TCHAR buffer[256]; + + // calculate rounded time in us + QWORD lDuration = 1000000 * (2 * (QWORD) dwDiffCycles + 1) / (2 * dwCpuFreq); + + wsprintf(buffer,_T("State %u: Time = %I64u us f = %u Hz, Time = %I64u us f = %u Hz\n"), + wOut >> 11,lDuration,(DWORD) (1000000 / 2 / lDuration), + (QWORD) dwSamples * 1000000 / SAMPLES_PER_SEC,SAMPLES_PER_SEC / 2 / dwSamples); + OutputDebugString(buffer); + } + #endif + + // begin of beep + if (uHeaders == 0 && GetSoundBufSize() == 0) + { + // use silence buffers to start output engine + AddSamples(dwSoundBufferLength * NO_OF_BUFFERS,0x80); + } + + // offset for wave level + byWaveLevel = 0x80 + (BYTE) (dwWaveVol * (WaveLevel(wOut) - WaveLevel(w->out)) / 2); + + AddSamples(dwSamples,byWaveLevel); // add samples to latest wave sample buffer + + if (GetSoundBufSize() > NO_OF_BUFFERS) // have more than 3 wave sample buffers + { + FlushSample(); // send 2 of them + FlushSample(); + } + + // ran out of buffers -> disable CPU slow down + InitAdjustSpeed(); // init variables if necessary + bEnableSlow = (GetSoundBufSize() > 1); + + if (bSoundSlow == FALSE) + { + InitAdjustSpeed(); // init variables if necessary + bSoundSlow = TRUE; // CPU slow down + } + return; +} + +// +// beep with frequency (Hz) and duration (ms) +// +VOID SoundBeep(DWORD dwFrequency, DWORD dwDuration) +{ + QWORD lPeriods; + DWORD dwSamples; + BYTE byLevel; + + // waveform-audio output device opened and have frequency + if (hWaveDevice && dwFrequency > 0) + { + // samples for 1/2 of time period + dwSamples = SAMPLES_PER_SEC / 2 / dwFrequency; + + // overall half periods + lPeriods = (QWORD) dwFrequency * dwDuration / 500; + + while (lPeriods-- > 0) // create sample buffers + { + // signal level + byLevel = 0x80 + (BYTE) ((((DWORD) lPeriods & 1) * 2 - 1) * (dwWaveVol / 2)); + + AddSamples(dwSamples,byLevel); // add half period sample + } + + while (GetSoundBufSize() > 0) // samples in job list + FlushSample(); // send sample buffer + } + Sleep(dwDuration); + return; +} diff --git a/Sources/Emu48/stack.c b/Sources/Emu48/STACK.C similarity index 81% rename from Sources/Emu48/stack.c rename to Sources/Emu48/STACK.C index 1c8cb4e..455a243 100644 --- a/Sources/Emu48/stack.c +++ b/Sources/Emu48/STACK.C @@ -1,833 +1,952 @@ -/* - * stack.c - * - * This file is part of Emu48 - * - * Copyright (C) 2005 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" -#include "io.h" - -#define fnRadix 51 // fraction mark -#define fnApprox 105 // exact / approx. mode (HP49G) - -#define DOINT 0x02614 // Precision Integer (HP49G) -#define DOREAL 0x02933 // Real -#define DOCMP 0x02977 // Complex -#define DOCSTR 0x02A2C // String - -BOOL bDetectClpObject = TRUE; // try to detect clipboard object - -//################ -//# -//# Low level subroutines -//# -//################ - -static LPTSTR Trim(LPCTSTR cp) -{ - LPCTSTR pcWs = _T(" \t\n\r"); // valid whitespace characters - - LPTSTR pc; - DWORD dwFirst,dwLast; - - dwLast = lstrlen(cp); // last position in string (EOS) - - // trim leading and tailing whitespace characters - dwFirst = (DWORD) _tcsspn(cp,pcWs); // position of 1st non whitespace character - - // search for position behind last non whitespace character - while (dwLast > dwFirst && _tcschr(pcWs,cp[dwLast-1]) != NULL) - --dwLast; - - dwLast = 1 + dwLast - dwFirst; // calculate buffer length - - if ((pc = (LPTSTR) malloc(dwLast * sizeof(*pc))) != NULL) - { - lstrcpyn(pc,&cp[dwFirst],dwLast); // copy relevant data + EOS - } - return pc; -} - -static INT RPL_GetZInt(BYTE CONST *pbyNum,INT nIntLen,LPTSTR cp,INT nSize) -{ - INT i = 0; // character counter - - _ASSERT(nSize > 0); // target buffer size - - if (nIntLen > 1) // has sign nibble - { - --nIntLen; // remove sign from digit length - - // check for valid sign - _ASSERT(pbyNum[nIntLen] == 0 || pbyNum[nIntLen] == 9); - if (pbyNum[nIntLen] == 9) // negative number - { - *cp++ = _T('-'); // add sign - --nSize; // dec dest buffer size - ++i; // wrote one character - } - } - - if (nIntLen >= nSize) return 0; // dest buffer overflow - i += nIntLen; // adjust character counter - - while (nIntLen-- > 0) // write all digits - { - // check for valid digit - _ASSERT(pbyNum[nIntLen] >= 0 && pbyNum[nIntLen] <= 9); - *cp++ = _T('0') + pbyNum[nIntLen]; // and write - } - *cp = 0; // set EOS - return i; -} - -static __inline INT SetZInt(LPCTSTR cp,LPBYTE pbyNum,INT nSize) -{ - BYTE bySign; - INT nStrLen,nNumSize; - - _ASSERT(nSize > 0); // target buffer size - - nStrLen = lstrlen(cp); // source string length - - if ( nStrLen == 0 // empty string - // precisition integer contain only these numbers - || _tcsspn(cp,_T("0123456789+-")) != (SIZE_T) nStrLen) - return 0; - - bySign = (*cp != _T('-')) ? 0 : 9; // set sign nibble - if (*cp == _T('-') || *cp == _T('+')) // skip sign character - { - ++cp; - --nStrLen; - } - - if (nStrLen == 1 && *cp == _T('0')) // special code for zero - { - *pbyNum = 0; // zero data - return 1; // finish - } - - // nStrLen = no. of digits without sign - if (nStrLen >= nSize) // destination buffer too small - return 0; - - nNumSize = nStrLen + 1; // no. of written data - - while (--nStrLen >= 0) // eval all digits - { - TCHAR c = cp[nStrLen]; - - // only '0' .. '9' are valid here - if (!((c >= _T('0')) || (c <= _T('9')))) - return 0; - - c -= _T('0'); - *pbyNum++ = (BYTE) c; - } - *pbyNum = bySign; // add sign - - return nNumSize; -} - -static INT RPL_SetZInt(LPCTSTR cp,LPBYTE pbyNum,INT nSize) -{ - LPTSTR pszData; - - INT s = 0; - - if ((pszData = Trim(cp)) != NULL) // create a trimmed working copy of the string - { - s = SetZInt(pszData,pbyNum,nSize); - free(pszData); - } - return s; -} - -static INT RPL_GetBcd(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPTSTR cp,INT nSize) -{ - BYTE byNib; - LONG v,lExp; - BOOL bPflag,bExpflag; - INT i; - - lExp = 0; - for (v = 1; nExpLen--; v *= 10) // fetch exponent - { - lExp += (LONG) *pbyNum++ * v; // calc. exponent - } - - if (lExp > v / 2) lExp -= v; // negative exponent - - lExp -= nMantLen - 1; // set decimal point to end of mantissa - - i = 0; // first character - bPflag = FALSE; // show no decimal point - bExpflag = FALSE; // show no exponent - - // scan mantissa - for (v = (LONG) nMantLen - 1; v >= 0 || bPflag; v--) - { - if (v >= 0L) // still mantissa digits left - byNib = *pbyNum++; - else - byNib = 0; // zero for negativ exponent - - if (!i) // still delete zeros at end - { - if (byNib == 0 && lExp && v > 0) // delete zeros - { - lExp++; // adjust exponent - continue; - } - - // TRUE at x.E - bExpflag = v + lExp >= nMantLen || lExp < -nMantLen; - bPflag = !bExpflag && v < -lExp; // decimal point flag at neg. exponent - } - - // set decimal point - if ((bExpflag && v == 0) || (!lExp && i)) - { - if (i >= nSize) return 0; // dest buffer overflow - cp[i++] = cDec; // write decimal point - if (v < 0) // no mantissa digits any more - { - if (i >= nSize) return 0; // dest buffer overflow - cp[i++] = _T('0'); // write heading zero - } - bPflag = FALSE; // finished with negativ exponents - } - - if (v >= 0 || bPflag) - { - if (i >= nSize) return 0; // dest buffer overflow - cp[i++] = (TCHAR) byNib + _T('0'); // write character - } - - lExp++; // next position - } - - if (*pbyNum == 9) // negative number - { - if (i >= nSize) return 0; // dest buffer overflow - cp[i++] = _T('-'); // write sign - } - - if (i >= nSize) return 0; // dest buffer overflow - cp[i] = 0; // set EOS - - for (v = 0; v < (i / 2); v++) // reverse string - { - TCHAR cNib = cp[v]; // swap chars - cp[v] = cp[i-v-1]; - cp[i-v-1] = cNib; - } - - // write number with exponent - if (bExpflag) - { - if (i + 5 >= nSize) return 0; // dest buffer overflow - i += wsprintf(&cp[i],_T("E%d"),lExp-1); - } - return i; -} - -static __inline INT SetBcd(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYTE pbyNum,INT nSize) -{ - TCHAR cVc[] = _T(".0123456789eE+-"); - - BYTE byNum[80]; - INT i,nIp,nDp,nMaxExp; - LONG lExp; - - cVc[0] = cDec; // replace decimal char - - if ( nMantLen + nExpLen >= nSize // destination buffer too small - || !*cp // empty string - || _tcsspn(cp,cVc) != (SIZE_T) lstrlen(cp) // real contain only these numbers - || (SIZE_T) lstrlen(cp) >= ARRAYSIZEOF(byNum)) // ignore too long reals - return 0; - - byNum[0] = (*cp != _T('-')) ? 0 : 9; // set sign nibble - if (*cp == _T('-') || *cp == _T('+')) // skip sign character - cp++; - - // only '.', '0' .. '9' are valid here - if (!((*cp == cDec) || (*cp >= _T('0')) || (*cp <= _T('9')))) - return 0; - - nIp = 0; // length of integer part - if (*cp != cDec) // no decimal point - { - // count integer part - while (*cp >= _T('0') && *cp <= _T('9')) - byNum[++nIp] = *cp++ - _T('0'); - if (!nIp) return 0; - } - - // only '.', 'E', 'e' or end are valid here - if (!(!*cp || (*cp == cDec) || (*cp == _T('E')) || (*cp == _T('e')))) - return 0; - - nDp = 0; // length of decimal part - if (*cp == cDec) // decimal point - { - cp++; // skip '.' - - // count decimal part - while (*cp >= _T('0') && *cp <= _T('9')) - byNum[nIp + ++nDp] = *cp++ - _T('0'); - } - - // count number of heading zeros in mantissa - for (i = 0; byNum[i+1] == 0 && i + 1 < nIp + nDp; ++i) { } - - if (i > 0) // have to normalize - { - INT j; - - nIp -= i; // for later ajust of exponent - for (j = 1; j <= nIp + nDp; ++j) // normalize mantissa - byNum[j] = byNum[j + i]; - } - - if (byNum[1] == 0) // number is 0 - { - ZeroMemory(pbyNum,nMantLen + nExpLen + 1); - return nMantLen + nExpLen + 1; - } - - for (i = nIp + nDp; i < nMantLen;) // fill rest of mantissa with 0 - byNum[++i] = 0; - - // must be 'E', 'e' or end - if (!(!*cp || (*cp == _T('E')) || (*cp == _T('e')))) - return 0; - - lExp = 0; - if (*cp == _T('E') || *cp == _T('e')) - { - cp++; // skip 'E' - - i = FALSE; // positive exponent - if (*cp == _T('-') || *cp == _T('+')) - { - i = (*cp++ == _T('-')); // adjust exponent sign - } - - // exponent symbol must be followed by number - if (*cp < _T('0') || *cp > _T('9')) return 0; - - while (*cp >= _T('0') && *cp <= _T('9')) - lExp = lExp * 10 + *cp++ - _T('0'); - - if (i) lExp = -lExp; - } - - if (*cp != 0) return 0; - - // adjust exponent value with exponent from normalized mantissa - lExp += nIp - 1; - - // calculate max. posive exponent - for (nMaxExp = 5, i = 1; i < nExpLen; ++i) - nMaxExp *= 10; - - // check range of exponent - if ((lExp < 0 && -lExp >= nMaxExp) || (lExp >= nMaxExp)) - return 0; - - if (lExp < 0) lExp += 2 * nMaxExp; // adjust negative offset - - for (i = nExpLen; i > 0; --i) // convert number into digits - { - byNum[nMantLen + i] = (BYTE) (lExp % 10); - lExp /= 10; - } - - // copy to target in reversed order - for (i = nMantLen + nExpLen; i >= 0; --i) - *pbyNum++ = byNum[i]; - - return nMantLen + nExpLen + 1; -} - -static INT RPL_SetBcd(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYTE pbyNum,INT nSize) -{ - LPTSTR pszData; - - INT s = 0; - - if ((pszData = Trim(cp)) != NULL) // create a trimmed working copy of the string - { - s = SetBcd(pszData,nMantLen,nExpLen,cDec,pbyNum,nSize); - free(pszData); - } - return s; -} - -static INT RPL_GetComplex(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPTSTR cp,INT nSize) -{ - INT nLen,nPos; - TCHAR cSep; - - cSep = (cDec == _T('.')) // current separator - ? _T(',') // radix mark '.' -> ',' separator - : _T(';'); // radix mark ',' -> ';' separator - - nPos = 0; // write buffer position - - if (nSize < 5) return 0; // target buffer to small - nSize -= 4; // reserved room for (,)\0 - - cp[nPos++] = _T('('); // start of complex number - - // real part - nLen = RPL_GetBcd(pbyNum,nMantLen,nExpLen,cDec,&cp[1],nSize); - if (nLen == 0) return 0; // target buffer to small - - _ASSERT(nLen <= nSize); - - nPos += nLen; // actual buffer postion - nSize -= nLen; // remainder target buffer size - - cp[nPos++] = cSep; // write of complex number seperator - - // imaginary part - nLen = RPL_GetBcd(&pbyNum[16],nMantLen,nExpLen,cDec,&cp[nPos],nSize); - if (nLen == 0) return 0; // target buffer to small - - nPos += nLen; // actual buffer postion - - cp[nPos++] = _T(')'); // end of complex number - cp[nPos] = 0; // EOS - - _ASSERT(lstrlen(cp) == nPos); - - return nPos; -} - -static INT RPL_SetComplex(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYTE pbyNum,INT nSize) -{ - LPTSTR pcSep,pszData; - INT nLen; - TCHAR cSep; - - nLen = 0; // read data length - - cSep = (cDec == _T('.')) // current separator - ? _T(',') // radix mark '.' -> ',' separator - : _T(';'); // radix mark ',' -> ';' separator - - if ((pszData = Trim(cp)) != NULL) // create a trimmed working copy of the string - { - INT nStrLength = lstrlen(pszData); // string length - - // complex number with brackets around - if ( nStrLength > 0 - && pszData[0] == _T('(') - && pszData[nStrLength - 1] == _T(')')) - { - pszData[--nStrLength] = 0; // replace ')' with EOS - - // search for number separator - if ((pcSep = _tcschr(pszData+1,cSep)) != NULL) - { - INT nLen1st; - - *pcSep = 0; // set EOS for 1st substring - - // decode 1st substring - nLen1st = RPL_SetBcd(pszData+1,nMantLen,nExpLen,cDec,&pbyNum[0],nSize); - if (nLen1st > 0) - { - // decode 2nd substring - nLen = RPL_SetBcd(pcSep+1,nMantLen,nExpLen,cDec,&pbyNum[nMantLen+nExpLen+1],nSize-nLen1st); - if (nLen > 0) - { - nLen += nLen1st; // complete Bcd length - } - } - } - } - free(pszData); - } - return nLen; -} - - -//################ -//# -//# Object subroutines -//# -//################ - -static TCHAR GetRadix(VOID) -{ - // get locale decimal point - // GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SDECIMAL,&cDecimal,1); - - return RPL_GetSystemFlag(fnRadix) ? _T(',') : _T('.'); -} - -static INT DoInt(DWORD dwAddress,LPTSTR cp,INT nSize) -{ - LPBYTE lpbyData; - INT nLength,nIntLen; - - nIntLen = Read5(dwAddress) - 5; // no. of digits - if (nIntLen <= 0) return 0; // error in calculator object - - nLength = 0; - if ((lpbyData = (LPBYTE) malloc(nIntLen))) - { - // get precisition integer object content and decode it - Npeek(lpbyData,dwAddress+5,nIntLen); - nLength = RPL_GetZInt(lpbyData,nIntLen,cp,nSize); - free(lpbyData); - } - return nLength; -} - -static INT DoReal(DWORD dwAddress,LPTSTR cp,INT nSize) -{ - BYTE byNumber[16]; - - // get real object content and decode it - Npeek(byNumber,dwAddress,ARRAYSIZEOF(byNumber)); - return RPL_GetBcd(byNumber,12,3,GetRadix(),cp,nSize); -} - -static INT DoComplex(DWORD dwAddress,LPTSTR cp,INT nSize) -{ - BYTE byNumber[32]; - - // get complex object content and decode it - Npeek(byNumber,dwAddress,ARRAYSIZEOF(byNumber)); - return RPL_GetComplex(byNumber,12,3,GetRadix(),cp,nSize); -} - - -//################ -//# -//# Stack routines -//# -//################ - -// -// ID_STACK_COPY -// -LRESULT OnStackCopy(VOID) // copy data from stack -{ - TCHAR cBuffer[128]; - HANDLE hClipObj; - LPBYTE lpbyData; - DWORD dwAddress,dwObject,dwSize; - UINT uClipboardFormat; - - _ASSERT(nState == SM_RUN); // emulator must be in RUN state - if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state - { - InfoMessage(_T("The emulator is busy.")); - return 0; - } - - _ASSERT(nState == SM_SLEEP); - - if ((dwAddress = RPL_Pick(1)) == 0) // pick address of level1 object - { - MessageBeep(MB_OK); // error beep - goto error; - } - - switch (dwObject = Read5(dwAddress)) // select object - { - case DOINT: // Precision Integer (HP49G) - case DOREAL: // real object - case DOCMP: // complex object - dwAddress += 5; // object content - - switch (dwObject) - { - case DOINT: // Precision Integer (HP49G) - // get precision integer object content and decode it - dwSize = DoInt(dwAddress,cBuffer,ARRAYSIZEOF(cBuffer)); - break; - case DOREAL: // real object - // get real object content and decode it - dwSize = DoReal(dwAddress,cBuffer,ARRAYSIZEOF(cBuffer)); - break; - case DOCMP: // complex object - // get complex object content and decode it - dwSize = DoComplex(dwAddress,cBuffer,ARRAYSIZEOF(cBuffer)); - break; - } - - // calculate buffer size - dwSize = (dwSize + 1) * sizeof(*cBuffer); - - // memory allocation for clipboard data - if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,dwSize)) == NULL) - goto error; - - if ((lpbyData = (LPBYTE) GlobalLock(hClipObj))) - { - // copy data to memory - CopyMemory(lpbyData,cBuffer,dwSize); - GlobalUnlock(hClipObj); // unlock memory - } - - #if defined _UNICODE - uClipboardFormat = CF_UNICODETEXT; - #else - uClipboardFormat = CF_TEXT; - #endif - break; - case DOCSTR: // string - dwAddress += 5; // address of string length - dwSize = (Read5(dwAddress) - 5) / 2; // length of string - - // memory allocation for clipboard data - if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,dwSize + 1)) == NULL) - goto error; - - if ((lpbyData = (LPBYTE) GlobalLock(hClipObj))) // lock memory - { - // copy data into clipboard buffer - for (dwAddress += 5;dwSize-- > 0;dwAddress += 2,++lpbyData) - *lpbyData = Read2(dwAddress); - *lpbyData = 0; // set EOS - - GlobalUnlock(hClipObj); // unlock memory - } - uClipboardFormat = CF_TEXT; // always text - break; - default: - MessageBeep(MB_OK); // error beep - goto error; - } - - if (OpenClipboard(hWnd)) - { - if (EmptyClipboard()) - SetClipboardData(uClipboardFormat,hClipObj); - else - GlobalFree(hClipObj); - CloseClipboard(); - } - else // clipboard open failed - { - GlobalFree(hClipObj); - } - -error: - SwitchToState(SM_RUN); - return 0; -} - -// -// ID_STACK_PASTE -// -LRESULT OnStackPaste(VOID) // paste data to stack -{ - #if defined _UNICODE - #define CF_TEXTFORMAT CF_UNICODETEXT - #else - #define CF_TEXTFORMAT CF_TEXT - #endif - - HANDLE hClipObj; - - BOOL bSuccess = FALSE; - - // check if clipboard format is available - if (!IsClipboardFormatAvailable(CF_TEXTFORMAT)) - { - MessageBeep(MB_OK); // error beep - return 0; - } - - SuspendDebugger(); // suspend debugger - bDbgAutoStateCtrl = FALSE; // disable automatic debugger state control - - // calculator off, turn on - if (!(Chipset.IORam[BITOFFSET]&DON)) - { - KeyboardEvent(TRUE,0,0x8000); - Sleep(dwWakeupDelay); - KeyboardEvent(FALSE,0,0x8000); - - // wait for sleep mode - while (Chipset.Shutdn == FALSE) Sleep(0); - } - - _ASSERT(nState == SM_RUN); // emulator must be in RUN state - if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state - { - InfoMessage(_T("The emulator is busy.")); - goto cancel; - } - - _ASSERT(nState == SM_SLEEP); - - if (OpenClipboard(hWnd)) - { - if ((hClipObj = GetClipboardData(CF_TEXTFORMAT))) - { - LPCTSTR lpstrClipdata; - LPBYTE lpbyData; - - if ((lpstrClipdata = (LPCTSTR) GlobalLock(hClipObj))) - { - BYTE byNumber[128]; - DWORD dwAddress; - INT s; - - do - { - if (bDetectClpObject) // autodetect clipboard object enabled - { - // HP49G in exact mode - if (cCurrentRomType == 'X' && !RPL_GetSystemFlag(fnApprox)) - { - // try to convert string to HP49 precision integer - s = RPL_SetZInt(lpstrClipdata,byNumber,sizeof(byNumber)); - - if (s > 0) // is a real number for exact mode - { - // get TEMPOB memory for HP49 precision integer object - dwAddress = RPL_CreateTemp(s+5+5); - if ((bSuccess = (dwAddress > 0))) - { - Write5(dwAddress,DOINT); // prolog - Write5(dwAddress+5,s+5); // size - Nwrite(byNumber,dwAddress+10,s); // data - - // push object to stack - RPL_Push(1,dwAddress); - } - break; - } - } - - // try to convert string to real format - _ASSERT(16 <= ARRAYSIZEOF(byNumber)); - s = RPL_SetBcd(lpstrClipdata,12,3,GetRadix(),byNumber,sizeof(byNumber)); - - if (s > 0) // is a real number - { - _ASSERT(s == 16); // length of real number BCD coded - - // get TEMPOB memory for real object - dwAddress = RPL_CreateTemp(16+5); - if ((bSuccess = (dwAddress > 0))) - { - Write5(dwAddress,DOREAL); // prolog - Nwrite(byNumber,dwAddress+5,s); // data - - // push object to stack - RPL_Push(1,dwAddress); - } - break; - } - - // try to convert string to complex format - _ASSERT(32 <= ARRAYSIZEOF(byNumber)); - s = RPL_SetComplex(lpstrClipdata,12,3,GetRadix(),byNumber,sizeof(byNumber)); - - if (s > 0) // is a real complex - { - _ASSERT(s == 32); // length of complex number BCD coded - - // get TEMPOB memory for complex object - dwAddress = RPL_CreateTemp(16+16+5); - if ((bSuccess = (dwAddress > 0))) - { - Write5(dwAddress,DOCMP); // prolog - Nwrite(byNumber,dwAddress+5,s); // data - - // push object to stack - RPL_Push(1,dwAddress); - } - break; - } - } - - // any other format - { - DWORD dwSize = lstrlen(lpstrClipdata); - if ((lpbyData = (LPBYTE) malloc(dwSize * 2))) - { - LPBYTE lpbySrc,lpbyDest; - DWORD dwLoop; - - #if defined _UNICODE - // copy data UNICODE -> ASCII - WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, - lpstrClipdata, dwSize, - (LPSTR) lpbyData+dwSize, dwSize, NULL, NULL); - #else - // copy data - memcpy(lpbyData+dwSize,lpstrClipdata,dwSize); - #endif - - // unpack data - lpbySrc = lpbyData+dwSize; - lpbyDest = lpbyData; - dwLoop = dwSize; - while (dwLoop-- > 0) - { - BYTE byTwoNibs = *lpbySrc++; - *lpbyDest++ = (BYTE) (byTwoNibs & 0xF); - *lpbyDest++ = (BYTE) (byTwoNibs >> 4); - } - - dwSize *= 2; // size in nibbles - - // get TEMPOB memory for string object - dwAddress = RPL_CreateTemp(dwSize+10); - if ((bSuccess = (dwAddress > 0))) - { - Write5(dwAddress,DOCSTR); // String - Write5(dwAddress+5,dwSize+5); // length of String - Nwrite(lpbyData,dwAddress+10,dwSize); // data - - // push object to stack - RPL_Push(1,dwAddress); - } - free(lpbyData); - } - } - } - while (FALSE); - - GlobalUnlock(hClipObj); - } - } - CloseClipboard(); - } - - SwitchToState(SM_RUN); // run state - while (nState!=nNextState) Sleep(0); - _ASSERT(nState == SM_RUN); - - if (bSuccess == FALSE) // data not copied - goto cancel; - - KeyboardEvent(TRUE,0,0x8000); - Sleep(dwWakeupDelay); - KeyboardEvent(FALSE,0,0x8000); - - // wait for sleep mode - while (Chipset.Shutdn == FALSE) Sleep(0); - -cancel: - bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control - ResumeDebugger(); - return 0; - #undef CF_TEXTFORMAT -} +/* + * stack.c + * + * This file is part of Emu48 + * + * Copyright (C) 2005 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" +#include "io.h" + +#define fnRadix 51 // fraction mark +#define fnApprox 105 // exact / approx. mode (HP49G) + +#define DOINT 0x02614 // Precision Integer (HP49G) +#define DOREAL 0x02933 // Real +#define DOCMP 0x02977 // Complex +#define DOCSTR 0x02A2C // String + +BOOL bDetectClpObject = TRUE; // try to detect clipboard object +BOOL bLocaleDecimalPoint = FALSE; // use decimal point character from calculator + +//################ +//# +//# Low level subroutines +//# +//################ + +// +// check if cGroup character is thousands separator +// +static BOOL CheckThousandGroup(LPCTSTR cp,TCHAR cGroup) +{ + UINT uLastPos; + UINT i; + + // get decimal point + CONST TCHAR cDecimalPoint = cGroup ^ (_T('.') ^ _T(',')); + + BOOL bFound = FALSE; // 1st separator not found + BOOL bPosOK = TRUE; + + for (i = 0; bPosOK && cp[i] != cDecimalPoint && cp[i] != 0; ++i) + { + if (cp[i] == cGroup) // found separator + { + if (bFound) + { + // verify separator position + bPosOK = (uLastPos + 4 == i); + } + + uLastPos = i; // last position of separator + bFound = TRUE; // separator found + } + } + + // check last grouping + return bPosOK && bFound && (uLastPos + 4 == i); +} + +// +// get decimal point from clipboard +// +static TCHAR GetClpbrdDecimalPoint(LPCTSTR cp) +{ + TCHAR cDec = 0; // default for invalid decimal point detection + + TCHAR cLast = 0; // last decimal point + UINT uPoint = 0; // no. of points + UINT uComma = 0; // no. of commas + + LPCTSTR p; + for (p = cp; *p; ++p) // count '.' and ',' characters + { + if (*p == _T('.')) + { + cLast = *p; // last occurance + ++uPoint; + } + if (*p == _T(',')) + { + cLast = *p; // last occurance + ++uComma; + } + } + + if (uComma == 0 && uPoint == 0) // none of both + { + cDec = _T('.'); + } + else if (uComma == 1 && uPoint == 0) // one single ',' + { + cDec = _T(','); + } + else if (uComma == 0 && uPoint == 1) // one single '.' + { + cDec = _T('.'); + } + else if (uComma == 1 && uPoint == 1) // one single ',' and '.' + { + // change from ',' to '.' or vice versa + const TCHAR cFirst = cLast ^ (_T('.') ^ _T(',')); + + if (CheckThousandGroup(cp,cFirst)) // check if 1st character is grouped + { + cDec = cLast; + } + } + // multiple grouped ',' and single '.' + else if (uComma > 1 && uPoint == 1 && CheckThousandGroup(cp,_T(','))) + { + cDec = _T('.'); + } + // multiple grouped '.' and single ',' + else if (uComma == 1 && uPoint > 1 && CheckThousandGroup(cp,_T('.'))) + { + cDec = _T(','); + } + return cDec; +} + +static LPTSTR Trim(LPCTSTR cp) +{ + LPCTSTR pcWs = _T(" \t\n\r"); // valid whitespace characters + + LPTSTR pc; + DWORD dwFirst,dwLast; + + dwLast = lstrlen(cp); // last position in string (EOS) + + // trim leading and tailing whitespace characters + dwFirst = (DWORD) _tcsspn(cp,pcWs); // position of 1st non whitespace character + + // search for position behind last non whitespace character + while (dwLast > dwFirst && _tcschr(pcWs,cp[dwLast-1]) != NULL) + --dwLast; + + dwLast = 1 + dwLast - dwFirst; // calculate buffer length + + if ((pc = (LPTSTR) malloc(dwLast * sizeof(*pc))) != NULL) + { + lstrcpyn(pc,&cp[dwFirst],dwLast); // copy relevant data + EOS + } + return pc; +} + +static INT RPL_GetZInt(BYTE CONST *pbyNum,INT nIntLen,LPTSTR cp,INT nSize) +{ + INT i = 0; // character counter + + _ASSERT(nSize > 0); // target buffer size + + if (nIntLen > 1) // has sign nibble + { + --nIntLen; // remove sign from digit length + + // check for valid sign + _ASSERT(pbyNum[nIntLen] == 0 || pbyNum[nIntLen] == 9); + if (pbyNum[nIntLen] == 9) // negative number + { + *cp++ = _T('-'); // add sign + --nSize; // dec dest buffer size + ++i; // wrote one character + } + } + + if (nIntLen >= nSize) return 0; // dest buffer overflow + i += nIntLen; // adjust character counter + + while (nIntLen-- > 0) // write all digits + { + // check for valid digit + _ASSERT(pbyNum[nIntLen] >= 0 && pbyNum[nIntLen] <= 9); + *cp++ = _T('0') + pbyNum[nIntLen]; // and write + } + *cp = 0; // set EOS + return i; +} + +static __inline INT SetZInt(LPCTSTR cp,LPBYTE pbyNum,INT nSize) +{ + BYTE bySign; + INT nStrLen,nNumSize; + + _ASSERT(nSize > 0); // target buffer size + + nStrLen = lstrlen(cp); // source string length + + if ( nStrLen == 0 // empty string + // precisition integer contain only these numbers + || _tcsspn(cp,_T("0123456789+-")) != (SIZE_T) nStrLen) + return 0; + + bySign = (*cp != _T('-')) ? 0 : 9; // set sign nibble + if (*cp == _T('-') || *cp == _T('+')) // skip sign character + { + ++cp; + --nStrLen; + } + + if (nStrLen == 1 && *cp == _T('0')) // special code for zero + { + *pbyNum = 0; // zero data + return 1; // finish + } + + // nStrLen = no. of digits without sign + if (nStrLen >= nSize) // destination buffer too small + return 0; + + nNumSize = nStrLen + 1; // no. of written data + + while (--nStrLen >= 0) // eval all digits + { + TCHAR c = cp[nStrLen]; + + // only '0' .. '9' are valid here + if (!((c >= _T('0')) || (c <= _T('9')))) + return 0; + + c -= _T('0'); + *pbyNum++ = (BYTE) c; + } + *pbyNum = bySign; // add sign + + return nNumSize; +} + +static INT RPL_SetZInt(LPCTSTR cp,LPBYTE pbyNum,INT nSize) +{ + LPTSTR pszData; + + INT s = 0; + + if ((pszData = Trim(cp)) != NULL) // create a trimmed working copy of the string + { + s = SetZInt(pszData,pbyNum,nSize); + free(pszData); + } + return s; +} + +static INT RPL_GetBcd(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPTSTR cp,INT nSize) +{ + BYTE byNib; + LONG v,lExp; + BOOL bPflag,bExpflag; + INT i; + + lExp = 0; + for (v = 1; nExpLen--; v *= 10) // fetch exponent + { + lExp += (LONG) *pbyNum++ * v; // calc. exponent + } + + if (lExp > v / 2) lExp -= v; // negative exponent + + lExp -= nMantLen - 1; // set decimal point to end of mantissa + + i = 0; // first character + bPflag = FALSE; // show no decimal point + bExpflag = FALSE; // show no exponent + + // scan mantissa + for (v = (LONG) nMantLen - 1; v >= 0 || bPflag; v--) + { + if (v >= 0L) // still mantissa digits left + byNib = *pbyNum++; + else + byNib = 0; // zero for negativ exponent + + if (!i) // still delete zeros at end + { + if (byNib == 0 && lExp && v > 0) // delete zeros + { + lExp++; // adjust exponent + continue; + } + + // TRUE at x.E + bExpflag = v + lExp >= nMantLen || lExp < -nMantLen; + bPflag = !bExpflag && v < -lExp; // decimal point flag at neg. exponent + } + + // set decimal point + if ((bExpflag && v == 0) || (!lExp && i)) + { + if (i >= nSize) return 0; // dest buffer overflow + cp[i++] = cDec; // write decimal point + if (v < 0) // no mantissa digits any more + { + if (i >= nSize) return 0; // dest buffer overflow + cp[i++] = _T('0'); // write heading zero + } + bPflag = FALSE; // finished with negativ exponents + } + + if (v >= 0 || bPflag) + { + if (i >= nSize) return 0; // dest buffer overflow + cp[i++] = (TCHAR) byNib + _T('0'); // write character + } + + lExp++; // next position + } + + if (*pbyNum == 9) // negative number + { + if (i >= nSize) return 0; // dest buffer overflow + cp[i++] = _T('-'); // write sign + } + + if (i >= nSize) return 0; // dest buffer overflow + cp[i] = 0; // set EOS + + for (v = 0; v < (i / 2); v++) // reverse string + { + TCHAR cNib = cp[v]; // swap chars + cp[v] = cp[i-v-1]; + cp[i-v-1] = cNib; + } + + // write number with exponent + if (bExpflag) + { + if (i + 5 >= nSize) return 0; // dest buffer overflow + i += wsprintf(&cp[i],_T("E%d"),lExp-1); + } + return i; +} + +static __inline INT SetBcd(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYTE pbyNum,INT nSize) +{ + TCHAR cVc[] = _T(",.0123456789eE+-"); + + BYTE byNum[80]; + INT i,nIp,nDp,nMaxExp; + LONG lExp; + + // get thousand separator + const TCHAR cThousand = cDec ^ (_T('.') ^ _T(',')); + + if ( nMantLen + nExpLen >= nSize // destination buffer too small + || !*cp // empty string + || _tcsspn(cp,cVc) != (SIZE_T) lstrlen(cp) // real doesn't contain only these numbers + || (SIZE_T) lstrlen(cp) >= ARRAYSIZEOF(byNum)) // ignore too long reals + return 0; + + byNum[0] = (*cp != _T('-')) ? 0 : 9; // set sign nibble + if (*cp == _T('-') || *cp == _T('+')) // skip sign nibble + cp++; + + // only '.', '0' .. '9' are valid here + if (!((*cp == cDec) || (*cp >= _T('0')) || (*cp <= _T('9')))) + return 0; + + nIp = 0; // length of integer part + if (*cp != cDec) // no decimal point + { + // count integer part + for (; (*cp >= _T('0') && *cp <= _T('9')) || *cp == cThousand; ++cp) + { + if (*cp != cThousand) // not thousand separator + { + byNum[++nIp] = *cp - _T('0'); + } + } + if (!nIp) return 0; + } + + // only '.', 'E', 'e' or end are valid here + if (!(!*cp || (*cp == cDec) || (*cp == _T('E')) || (*cp == _T('e')))) + return 0; + + nDp = 0; // length of decimal part + if (*cp == cDec) // decimal point + { + cp++; // skip '.' + + // count decimal part + while (*cp >= _T('0') && *cp <= _T('9')) + byNum[nIp + ++nDp] = *cp++ - _T('0'); + } + + // count number of heading zeros in mantissa + for (i = 0; byNum[i+1] == 0 && i + 1 < nIp + nDp; ++i) { } + + if (i > 0) // have to normalize + { + INT j; + + nIp -= i; // for later ajust of exponent + for (j = 1; j <= nIp + nDp; ++j) // normalize mantissa + byNum[j] = byNum[j + i]; + } + + if (byNum[1] == 0) // number is 0 + { + ZeroMemory(pbyNum,nMantLen + nExpLen + 1); + return nMantLen + nExpLen + 1; + } + + for (i = nIp + nDp; i < nMantLen;) // fill rest of mantissa with 0 + byNum[++i] = 0; + + // must be 'E', 'e' or end + if (!(!*cp || (*cp == _T('E')) || (*cp == _T('e')))) + return 0; + + lExp = 0; + if (*cp == _T('E') || *cp == _T('e')) + { + cp++; // skip 'E' + + i = FALSE; // positive exponent + if (*cp == _T('-') || *cp == _T('+')) + { + i = (*cp++ == _T('-')); // adjust exponent sign + } + + // exponent symbol must be followed by number + if (*cp < _T('0') || *cp > _T('9')) return 0; + + while (*cp >= _T('0') && *cp <= _T('9')) + lExp = lExp * 10 + *cp++ - _T('0'); + + if (i) lExp = -lExp; + } + + if (*cp != 0) return 0; + + // adjust exponent value with exponent from normalized mantissa + lExp += nIp - 1; + + // calculate max. posive exponent + for (nMaxExp = 5, i = 1; i < nExpLen; ++i) + nMaxExp *= 10; + + // check range of exponent + if ((lExp < 0 && -lExp >= nMaxExp) || (lExp >= nMaxExp)) + return 0; + + if (lExp < 0) lExp += 2 * nMaxExp; // adjust negative offset + + for (i = nExpLen; i > 0; --i) // convert number into digits + { + byNum[nMantLen + i] = (BYTE) (lExp % 10); + lExp /= 10; + } + + // copy to target in reversed order + for (i = nMantLen + nExpLen; i >= 0; --i) + *pbyNum++ = byNum[i]; + + return nMantLen + nExpLen + 1; +} + +static INT RPL_SetBcd(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYTE pbyNum,INT nSize) +{ + LPTSTR pszData; + + INT s = 0; + + if ((pszData = Trim(cp)) != NULL) // create a trimmed working copy of the string + { + s = SetBcd(pszData,nMantLen,nExpLen,cDec,pbyNum,nSize); + free(pszData); + } + return s; +} + +static INT RPL_GetComplex(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPTSTR cp,INT nSize) +{ + INT nLen,nPos; + TCHAR cSep; + + cSep = (cDec == _T('.')) // current separator + ? _T(',') // decimal point '.' -> ',' separator + : _T(';'); // decimal comma ',' -> ';' separator + + nPos = 0; // write buffer position + + if (nSize < 5) return 0; // target buffer to small + nSize -= 4; // reserved room for (,)\0 + + cp[nPos++] = _T('('); // start of complex number + + // real part + nLen = RPL_GetBcd(pbyNum,nMantLen,nExpLen,cDec,&cp[1],nSize); + if (nLen == 0) return 0; // target buffer to small + + _ASSERT(nLen <= nSize); + + nPos += nLen; // actual buffer postion + nSize -= nLen; // remainder target buffer size + + cp[nPos++] = cSep; // write of complex number seperator + + // imaginary part + nLen = RPL_GetBcd(&pbyNum[16],nMantLen,nExpLen,cDec,&cp[nPos],nSize); + if (nLen == 0) return 0; // target buffer to small + + nPos += nLen; // actual buffer postion + + cp[nPos++] = _T(')'); // end of complex number + cp[nPos] = 0; // EOS + + _ASSERT(lstrlen(cp) == nPos); + + return nPos; +} + +static INT RPL_SetComplex(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYTE pbyNum,INT nSize) +{ + LPTSTR pcSep,pszData; + INT nLen; + TCHAR cSep; + + nLen = 0; // read data length + + cSep = (cDec == _T('.')) // current separator + ? _T(',') // decimal point '.' -> ',' separator + : _T(';'); // decimal comma ',' -> ';' separator + + if ((pszData = Trim(cp)) != NULL) // create a trimmed working copy of the string + { + INT nStrLength = lstrlen(pszData); // string length + + // complex number with brackets around + if ( nStrLength > 0 + && pszData[0] == _T('(') + && pszData[nStrLength - 1] == _T(')')) + { + pszData[--nStrLength] = 0; // replace ')' with EOS + + // search for number separator + if ((pcSep = _tcschr(pszData+1,cSep)) != NULL) + { + INT nLen1st; + + *pcSep = 0; // set EOS for 1st substring + + // decode 1st substring + nLen1st = RPL_SetBcd(pszData+1,nMantLen,nExpLen,cDec,&pbyNum[0],nSize); + if (nLen1st > 0) + { + // decode 2nd substring + nLen = RPL_SetBcd(pcSep+1,nMantLen,nExpLen,cDec,&pbyNum[nMantLen+nExpLen+1],nSize-nLen1st); + if (nLen > 0) + { + nLen += nLen1st; // complete Bcd length + } + } + } + } + free(pszData); + } + return nLen; +} + + +//################ +//# +//# Object subroutines +//# +//################ + +static TCHAR GetRadix(VOID) +{ + if (bLocaleDecimalPoint) // use Windows Locale decimal point character + { + TCHAR cDecimal[2]; + + // get locale decimal point with zero terminator + GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SDECIMAL,cDecimal,2); + return cDecimal[0]; + } + + return RPL_GetSystemFlag(fnRadix) ? _T(',') : _T('.'); +} + +static INT DoInt(DWORD dwAddress,LPTSTR cp,INT nSize) +{ + LPBYTE lpbyData; + INT nLength,nIntLen; + + nIntLen = Read5(dwAddress) - 5; // no. of digits + if (nIntLen <= 0) return 0; // error in calculator object + + nLength = 0; + if ((lpbyData = (LPBYTE) malloc(nIntLen))) + { + // get precisition integer object content and decode it + Npeek(lpbyData,dwAddress+5,nIntLen); + nLength = RPL_GetZInt(lpbyData,nIntLen,cp,nSize); + free(lpbyData); + } + return nLength; +} + +static INT DoReal(DWORD dwAddress,LPTSTR cp,INT nSize) +{ + BYTE byNumber[16]; + + // get real object content and decode it + Npeek(byNumber,dwAddress,ARRAYSIZEOF(byNumber)); + return RPL_GetBcd(byNumber,12,3,GetRadix(),cp,nSize); +} + +static INT DoComplex(DWORD dwAddress,LPTSTR cp,INT nSize) +{ + BYTE byNumber[32]; + + // get complex object content and decode it + Npeek(byNumber,dwAddress,ARRAYSIZEOF(byNumber)); + return RPL_GetComplex(byNumber,12,3,GetRadix(),cp,nSize); +} + + +//################ +//# +//# Stack routines +//# +//################ + +// +// ID_STACK_COPY +// +LRESULT OnStackCopy(VOID) // copy data from stack +{ + TCHAR cBuffer[128]; + HANDLE hClipObj; + LPBYTE lpbyData; + DWORD dwAddress,dwObject,dwSize; + UINT uClipboardFormat; + + _ASSERT(nState == SM_RUN); // emulator must be in RUN state + if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state + { + InfoMessage(_T("The emulator is busy.")); + return 0; + } + + _ASSERT(nState == SM_SLEEP); + + if ((dwAddress = RPL_Pick(1)) == 0) // pick address of level1 object + { + MessageBeep(MB_OK); // error beep + goto error; + } + + switch (dwObject = Read5(dwAddress)) // select object + { + case DOINT: // Precision Integer (HP49G) + case DOREAL: // real object + case DOCMP: // complex object + dwAddress += 5; // object content + + switch (dwObject) + { + case DOINT: // Precision Integer (HP49G) + // get precision integer object content and decode it + dwSize = DoInt(dwAddress,cBuffer,ARRAYSIZEOF(cBuffer)); + break; + case DOREAL: // real object + // get real object content and decode it + dwSize = DoReal(dwAddress,cBuffer,ARRAYSIZEOF(cBuffer)); + break; + case DOCMP: // complex object + // get complex object content and decode it + dwSize = DoComplex(dwAddress,cBuffer,ARRAYSIZEOF(cBuffer)); + break; + } + + // calculate buffer size + dwSize = (dwSize + 1) * sizeof(*cBuffer); + + // memory allocation for clipboard data + if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,dwSize)) == NULL) + goto error; + + if ((lpbyData = (LPBYTE) GlobalLock(hClipObj))) + { + // copy data to memory + CopyMemory(lpbyData,cBuffer,dwSize); + GlobalUnlock(hClipObj); // unlock memory + } + + #if defined _UNICODE + uClipboardFormat = CF_UNICODETEXT; + #else + uClipboardFormat = CF_TEXT; + #endif + break; + case DOCSTR: // string + dwAddress += 5; // address of string length + dwSize = (Read5(dwAddress) - 5) / 2; // length of string + + // memory allocation for clipboard data + if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,dwSize + 1)) == NULL) + goto error; + + if ((lpbyData = (LPBYTE) GlobalLock(hClipObj))) // lock memory + { + // copy data into clipboard buffer + for (dwAddress += 5;dwSize-- > 0;dwAddress += 2,++lpbyData) + *lpbyData = Read2(dwAddress); + *lpbyData = 0; // set EOS + + GlobalUnlock(hClipObj); // unlock memory + } + uClipboardFormat = CF_TEXT; // always text + break; + default: + MessageBeep(MB_OK); // error beep + goto error; + } + + if (OpenClipboard(hWnd)) + { + if (EmptyClipboard()) + SetClipboardData(uClipboardFormat,hClipObj); + else + GlobalFree(hClipObj); + CloseClipboard(); + } + else // clipboard open failed + { + GlobalFree(hClipObj); + } + +error: + SwitchToState(SM_RUN); + return 0; +} + +// +// ID_STACK_PASTE +// +LRESULT OnStackPaste(VOID) // paste data to stack +{ + #if defined _UNICODE + #define CF_TEXTFORMAT CF_UNICODETEXT + #else + #define CF_TEXTFORMAT CF_TEXT + #endif + + HANDLE hClipObj; + + BOOL bSuccess = FALSE; + + // check if clipboard format is available + if (!IsClipboardFormatAvailable(CF_TEXTFORMAT)) + { + MessageBeep(MB_OK); // error beep + return 0; + } + + SuspendDebugger(); // suspend debugger + bDbgAutoStateCtrl = FALSE; // disable automatic debugger state control + + // calculator off, turn on + if (!(Chipset.IORam[BITOFFSET]&DON)) + { + KeyboardEvent(TRUE,0,0x8000); + Sleep(dwWakeupDelay); + KeyboardEvent(FALSE,0,0x8000); + + // wait for sleep mode + while (Chipset.Shutdn == FALSE) Sleep(0); + } + + _ASSERT(nState == SM_RUN); // emulator must be in RUN state + if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state + { + InfoMessage(_T("The emulator is busy.")); + goto cancel; + } + + _ASSERT(nState == SM_SLEEP); + + if (OpenClipboard(hWnd)) + { + if ((hClipObj = GetClipboardData(CF_TEXTFORMAT))) + { + LPCTSTR lpstrClipdata; + LPBYTE lpbyData; + + if ((lpstrClipdata = (LPCTSTR) GlobalLock(hClipObj))) + { + TCHAR cDec; + BYTE byNumber[128]; + DWORD dwAddress; + + INT s = 0; // no valid object + + do + { + if (bDetectClpObject) // autodetect clipboard object enabled + { + // HP49G in exact mode + if (cCurrentRomType == 'X' && !RPL_GetSystemFlag(fnApprox)) + { + // try to convert string to HP49 precision integer + s = RPL_SetZInt(lpstrClipdata,byNumber,sizeof(byNumber)); + + if (s > 0) // is a real number for exact mode + { + // get TEMPOB memory for HP49 precision integer object + dwAddress = RPL_CreateTemp(s+5+5); + if ((bSuccess = (dwAddress > 0))) + { + Write5(dwAddress,DOINT); // prolog + Write5(dwAddress+5,s+5); // size + Nwrite(byNumber,dwAddress+10,s); // data + + // push object to stack + RPL_Push(1,dwAddress); + } + break; + } + } + + cDec = GetClpbrdDecimalPoint(lpstrClipdata); + + if (cDec) // valid decimal point + { + // try to convert string to real format + _ASSERT(16 <= ARRAYSIZEOF(byNumber)); + s = RPL_SetBcd(lpstrClipdata,12,3,cDec,byNumber,sizeof(byNumber)); + } + + if (s > 0) // is a real number + { + _ASSERT(s == 16); // length of real number BCD coded + + // get TEMPOB memory for real object + dwAddress = RPL_CreateTemp(16+5); + if ((bSuccess = (dwAddress > 0))) + { + Write5(dwAddress,DOREAL); // prolog + Nwrite(byNumber,dwAddress+5,s); // data + + // push object to stack + RPL_Push(1,dwAddress); + } + break; + } + + // search for ';' as separator + cDec = (_tcschr(lpstrClipdata,_T(';')) != NULL) + ? _T(',') // decimal comma + : _T('.'); // decimal point + + // try to convert string to complex format + _ASSERT(32 <= ARRAYSIZEOF(byNumber)); + s = RPL_SetComplex(lpstrClipdata,12,3,cDec,byNumber,sizeof(byNumber)); + + if (s > 0) // is a real complex + { + _ASSERT(s == 32); // length of complex number BCD coded + + // get TEMPOB memory for complex object + dwAddress = RPL_CreateTemp(16+16+5); + if ((bSuccess = (dwAddress > 0))) + { + Write5(dwAddress,DOCMP); // prolog + Nwrite(byNumber,dwAddress+5,s); // data + + // push object to stack + RPL_Push(1,dwAddress); + } + break; + } + } + + // any other format + { + DWORD dwSize = lstrlen(lpstrClipdata); + if ((lpbyData = (LPBYTE) malloc(dwSize * 2))) + { + LPBYTE lpbySrc,lpbyDest; + DWORD dwLoop; + + #if defined _UNICODE + // copy data UNICODE -> ASCII + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, + lpstrClipdata, dwSize, + (LPSTR) lpbyData+dwSize, dwSize, NULL, NULL); + #else + // copy data + memcpy(lpbyData+dwSize,lpstrClipdata,dwSize); + #endif + + // unpack data + lpbySrc = lpbyData+dwSize; + lpbyDest = lpbyData; + dwLoop = dwSize; + while (dwLoop-- > 0) + { + BYTE byTwoNibs = *lpbySrc++; + *lpbyDest++ = (BYTE) (byTwoNibs & 0xF); + *lpbyDest++ = (BYTE) (byTwoNibs >> 4); + } + + dwSize *= 2; // size in nibbles + + // get TEMPOB memory for string object + dwAddress = RPL_CreateTemp(dwSize+10); + if ((bSuccess = (dwAddress > 0))) + { + Write5(dwAddress,DOCSTR); // String + Write5(dwAddress+5,dwSize+5); // length of String + Nwrite(lpbyData,dwAddress+10,dwSize); // data + + // push object to stack + RPL_Push(1,dwAddress); + } + free(lpbyData); + } + } + } + while (FALSE); + + GlobalUnlock(hClipObj); + } + } + CloseClipboard(); + } + + SwitchToState(SM_RUN); // run state + while (nState!=nNextState) Sleep(0); + _ASSERT(nState == SM_RUN); + + if (bSuccess == FALSE) // data not copied + goto cancel; + + KeyboardEvent(TRUE,0,0x8000); + Sleep(dwWakeupDelay); + KeyboardEvent(FALSE,0,0x8000); + + // wait for sleep mode + while (Chipset.Shutdn == FALSE) Sleep(0); + +cancel: + bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control + ResumeDebugger(); + return 0; + #undef CF_TEXTFORMAT +} diff --git a/Sources/Emu48/symbfile.c b/Sources/Emu48/SYMBFILE.C similarity index 95% rename from Sources/Emu48/symbfile.c rename to Sources/Emu48/SYMBFILE.C index 3a1df05..16e7658 100644 --- a/Sources/Emu48/symbfile.c +++ b/Sources/Emu48/SYMBFILE.C @@ -1,257 +1,257 @@ -/* - * symbfile.c - * - * This file is part of Emu48 - * - * Copyright (C) 2008 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" - -//################ -//# -//# Saturn Object File Reading -//# -//################ - -#define RECORD_BLOCK 256 // block size -#define OS_RESOLVED 0x8000 // resolved symbol -#define OS_RELOCATABLE 0x4000 // relocatable symbol - -#define SAT_ID "Saturn3" // saturn block header -#define SYMB_ID "Symb" // symbol block header - -#define HASHENTRIES 199 // size of hash table - -typedef struct _REFDATA -{ - LPTSTR lpszName; // symbol name - DWORD dwAddr; // resolved address - struct _REFDATA* pNext; -} REFDATA, *PREFDATA; - -static PREFDATA ppsBase[HASHENTRIES]; // base of symbol references (initialized with NULL) - -static __inline DWORD GetHash(DWORD dwVal) -{ - return dwVal % HASHENTRIES; // hash function -} - -static DWORD GetBigEndian(LPBYTE pbyData, INT nSize) -{ - DWORD dwVal = 0; - - while (nSize-- > 0) - { - dwVal <<= 8; - dwVal += *pbyData++; - } - return dwVal; -} - -// -// check if entry table is empty -// -BOOL RplTableEmpty(VOID) -{ - DWORD i; - - BOOL bEmpty = TRUE; - - // check if hash table is empty - for (i = 0; bEmpty && i < ARRAYSIZEOF(ppsBase); ++i) - { - bEmpty = (ppsBase[i] == NULL); // check if empty - } - return bEmpty; -} - -// -// load entry table -// -BOOL RplLoadTable(LPCTSTR lpszFilename) -{ - BYTE byPage[RECORD_BLOCK]; // record page size - HANDLE hFile; - DWORD dwFileLength,dwCodeLength,dwNoSymbols,dwNoReferences; - DWORD dwFilePos,dwBytesRead,dwSymb,dwPageIndex,dwResolvedSymb; - BOOL bSymbol,bSucc; - - bSucc = FALSE; - - hFile = CreateFile(lpszFilename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL); - if (hFile != INVALID_HANDLE_VALUE) - { - dwResolvedSymb = 0; // no resolved symbols added - bSymbol = TRUE; // next set is a symbol - - // read first page - ReadFile(hFile,byPage,sizeof(byPage),&dwBytesRead,NULL); - if (dwBytesRead == sizeof(byPage) && memcmp(byPage,SAT_ID,7) == 0) - { - // file length in bytes - dwFileLength = GetBigEndian(byPage+7,sizeof(WORD)) * sizeof(byPage); - - // code area in nibbles - dwCodeLength = GetBigEndian(byPage+9,sizeof(DWORD)); - - // no. of symbols & references - dwNoSymbols = GetBigEndian(byPage+13,sizeof(WORD)); - - // no. of references - dwNoReferences = GetBigEndian(byPage+15,sizeof(WORD)); - - // convert code area length into no. of pages - dwPageIndex = (dwCodeLength + (2 * sizeof(byPage) - 1)) / (2 * sizeof(byPage)); - - // calculate no. of code pages - dwFilePos = dwPageIndex * sizeof(byPage); - - // jump to begin of symbols by skipping no. of code pages - bSucc = SetFilePointer(hFile,dwFilePos,NULL,FILE_CURRENT) != INVALID_SET_FILE_POINTER; - - dwFilePos += sizeof(byPage); // actual file position - } - - // read all symbol pages - for (dwPageIndex = 256, dwSymb = 0; bSucc && dwSymb < dwNoSymbols; dwPageIndex += 42) - { - if (dwPageIndex >= 256) // read complete page - { - // read new symbol page - ReadFile(hFile,byPage,sizeof(byPage),&dwBytesRead,NULL); - dwFilePos += dwBytesRead; // update file position - if ( dwFilePos > dwFileLength - || dwBytesRead != sizeof(byPage) - || memcmp(byPage,SYMB_ID,4) != 0) - { - bSucc = FALSE; - break; - } - - dwPageIndex = 4; // begin of new symbol - } - - if (bSymbol) // this is the 42 byte symbol set - { - WORD wSymbolType = (WORD) GetBigEndian(byPage+dwPageIndex+36,sizeof(WORD)); - - // check if it's a resolved or relocatable symbol - bSymbol = (wSymbolType & OS_RESOLVED) != 0; - - if (bSymbol) ++dwResolvedSymb; // added resolved symbol - - if (wSymbolType == OS_RESOLVED) // resolved symbol type - { - TCHAR szSymbolName[36+1],*pcPtr; - PREFDATA pData; - DWORD dwHash; - - #if defined _UNICODE - { - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,(LPCSTR)byPage+dwPageIndex,36, - szSymbolName,ARRAYSIZEOF(szSymbolName)); - szSymbolName[36] = 0; // set EOS - } - #else - { - lstrcpyn(szSymbolName,(LPCSTR)byPage+dwPageIndex,ARRAYSIZEOF(szSymbolName)); - } - #endif - - // cut symbol name at first space character - if ((pcPtr = _tcschr(szSymbolName,_T(' '))) != NULL) - *pcPtr = 0; // set EOS - - // allocate symbol memory - VERIFY(pData = (PREFDATA) malloc(sizeof(*pData))); - pData->lpszName = DuplicateString(szSymbolName); - pData->dwAddr = GetBigEndian(byPage+dwPageIndex+38,sizeof(DWORD)); - - // add to hash table - dwHash = GetHash(pData->dwAddr); - pData->pNext = ppsBase[dwHash]; - ppsBase[dwHash] = pData; - } - - ++dwSymb; // got symbol - } - else // 42 byte fill reference - { - bSymbol = TRUE; // nothing to do, next is a symbol set - } - } - - bSucc = bSucc && (dwFilePos <= dwFileLength) - && (dwNoSymbols == (dwResolvedSymb + dwNoReferences)); - - CloseHandle(hFile); - } - - if (!bSucc) RplDeleteTable(); // delete current table - return bSucc; -} - -// -// delete entry table -// -VOID RplDeleteTable(VOID) -{ - PREFDATA pData; - DWORD i; - - // clear hash entries - for (i = 0; i < ARRAYSIZEOF(ppsBase); ++i) - { - while (ppsBase[i] != NULL) // walk through all datasets - { - pData = ppsBase[i]->pNext; - free(ppsBase[i]->lpszName); - free(ppsBase[i]); - ppsBase[i] = pData; - } - } - return; -} - -// -// return name for given entry address -// -LPCTSTR RplGetName(DWORD dwAddr) -{ - PREFDATA pData = ppsBase[GetHash(dwAddr)]; - - // walk through all datasets of hash entry - for (; pData != NULL; pData = pData->pNext) - { - if (pData->dwAddr == dwAddr) // found address - return pData->lpszName; // return symbol name - } - return NULL; -} - -// -// return entry address for given name -// -BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr) -{ - PREFDATA pData; - DWORD i; - - // check for every dataset in hash table - for (i = 0; i < ARRAYSIZEOF(ppsBase); ++i) - { - // walk through all datasets of hash entry - for (pData = ppsBase[i]; pData != NULL; pData = pData->pNext) - { - // found symbol name - if (lstrcmp(lpszName,pData->lpszName) == 0) - { - *pdwAddr = pData->dwAddr; // return address - return FALSE; // found - } - } - } - return TRUE; // not found -} +/* + * symbfile.c + * + * This file is part of Emu48 + * + * Copyright (C) 2008 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" + +//################ +//# +//# Saturn Object File Reading +//# +//################ + +#define RECORD_BLOCK 256 // block size +#define OS_RESOLVED 0x8000 // resolved symbol +#define OS_RELOCATABLE 0x4000 // relocatable symbol + +#define SAT_ID "Saturn3" // saturn block header +#define SYMB_ID "Symb" // symbol block header + +#define HASHENTRIES 199 // size of hash table + +typedef struct _REFDATA +{ + LPTSTR lpszName; // symbol name + DWORD dwAddr; // resolved address + struct _REFDATA* pNext; +} REFDATA, *PREFDATA; + +static PREFDATA ppsBase[HASHENTRIES]; // base of symbol references (initialized with NULL) + +static __inline DWORD GetHash(DWORD dwVal) +{ + return dwVal % HASHENTRIES; // hash function +} + +static DWORD GetBigEndian(LPBYTE pbyData, INT nSize) +{ + DWORD dwVal = 0; + + while (nSize-- > 0) + { + dwVal <<= 8; + dwVal += *pbyData++; + } + return dwVal; +} + +// +// check if entry table is empty +// +BOOL RplTableEmpty(VOID) +{ + DWORD i; + + BOOL bEmpty = TRUE; + + // check if hash table is empty + for (i = 0; bEmpty && i < ARRAYSIZEOF(ppsBase); ++i) + { + bEmpty = (ppsBase[i] == NULL); // check if empty + } + return bEmpty; +} + +// +// load entry table +// +BOOL RplLoadTable(LPCTSTR lpszFilename) +{ + BYTE byPage[RECORD_BLOCK]; // record page size + HANDLE hFile; + DWORD dwFileLength,dwCodeLength,dwNoSymbols,dwNoReferences; + DWORD dwFilePos,dwBytesRead,dwSymb,dwPageIndex,dwResolvedSymb; + BOOL bSymbol,bSucc; + + bSucc = FALSE; + + hFile = CreateFile(lpszFilename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + dwResolvedSymb = 0; // no resolved symbols added + bSymbol = TRUE; // next set is a symbol + + // read first page + ReadFile(hFile,byPage,sizeof(byPage),&dwBytesRead,NULL); + if (dwBytesRead == sizeof(byPage) && memcmp(byPage,SAT_ID,7) == 0) + { + // file length in bytes + dwFileLength = GetBigEndian(byPage+7,sizeof(WORD)) * sizeof(byPage); + + // code area in nibbles + dwCodeLength = GetBigEndian(byPage+9,sizeof(DWORD)); + + // no. of symbols & references + dwNoSymbols = GetBigEndian(byPage+13,sizeof(WORD)); + + // no. of references + dwNoReferences = GetBigEndian(byPage+15,sizeof(WORD)); + + // convert code area length into no. of pages + dwPageIndex = (dwCodeLength + (2 * sizeof(byPage) - 1)) / (2 * sizeof(byPage)); + + // calculate no. of code pages + dwFilePos = dwPageIndex * sizeof(byPage); + + // jump to begin of symbols by skipping no. of code pages + bSucc = SetFilePointer(hFile,dwFilePos,NULL,FILE_CURRENT) != INVALID_SET_FILE_POINTER; + + dwFilePos += sizeof(byPage); // actual file position + } + + // read all symbol pages + for (dwPageIndex = 256, dwSymb = 0; bSucc && dwSymb < dwNoSymbols; dwPageIndex += 42) + { + if (dwPageIndex >= 256) // read complete page + { + // read new symbol page + ReadFile(hFile,byPage,sizeof(byPage),&dwBytesRead,NULL); + dwFilePos += dwBytesRead; // update file position + if ( dwFilePos > dwFileLength + || dwBytesRead != sizeof(byPage) + || memcmp(byPage,SYMB_ID,4) != 0) + { + bSucc = FALSE; + break; + } + + dwPageIndex = 4; // begin of new symbol + } + + if (bSymbol) // this is the 42 byte symbol set + { + WORD wSymbolType = (WORD) GetBigEndian(byPage+dwPageIndex+36,sizeof(WORD)); + + // check if it's a resolved or relocatable symbol + bSymbol = (wSymbolType & OS_RESOLVED) != 0; + + if (bSymbol) ++dwResolvedSymb; // added resolved symbol + + if (wSymbolType == OS_RESOLVED) // resolved symbol type + { + TCHAR szSymbolName[36+1],*pcPtr; + PREFDATA pData; + DWORD dwHash; + + #if defined _UNICODE + { + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,(LPCSTR)byPage+dwPageIndex,36, + szSymbolName,ARRAYSIZEOF(szSymbolName)); + szSymbolName[36] = 0; // set EOS + } + #else + { + lstrcpyn(szSymbolName,(LPCSTR)byPage+dwPageIndex,ARRAYSIZEOF(szSymbolName)); + } + #endif + + // cut symbol name at first space character + if ((pcPtr = _tcschr(szSymbolName,_T(' '))) != NULL) + *pcPtr = 0; // set EOS + + // allocate symbol memory + VERIFY(pData = (PREFDATA) malloc(sizeof(*pData))); + pData->lpszName = DuplicateString(szSymbolName); + pData->dwAddr = GetBigEndian(byPage+dwPageIndex+38,sizeof(DWORD)); + + // add to hash table + dwHash = GetHash(pData->dwAddr); + pData->pNext = ppsBase[dwHash]; + ppsBase[dwHash] = pData; + } + + ++dwSymb; // got symbol + } + else // 42 byte fill reference + { + bSymbol = TRUE; // nothing to do, next is a symbol set + } + } + + bSucc = bSucc && (dwFilePos <= dwFileLength) + && (dwNoSymbols == (dwResolvedSymb + dwNoReferences)); + + CloseHandle(hFile); + } + + if (!bSucc) RplDeleteTable(); // delete current table + return bSucc; +} + +// +// delete entry table +// +VOID RplDeleteTable(VOID) +{ + PREFDATA pData; + DWORD i; + + // clear hash entries + for (i = 0; i < ARRAYSIZEOF(ppsBase); ++i) + { + while (ppsBase[i] != NULL) // walk through all datasets + { + pData = ppsBase[i]->pNext; + free(ppsBase[i]->lpszName); + free(ppsBase[i]); + ppsBase[i] = pData; + } + } + return; +} + +// +// return name for given entry address +// +LPCTSTR RplGetName(DWORD dwAddr) +{ + PREFDATA pData = ppsBase[GetHash(dwAddr)]; + + // walk through all datasets of hash entry + for (; pData != NULL; pData = pData->pNext) + { + if (pData->dwAddr == dwAddr) // found address + return pData->lpszName; // return symbol name + } + return NULL; +} + +// +// return entry address for given name +// +BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr) +{ + PREFDATA pData; + DWORD i; + + // check for every dataset in hash table + for (i = 0; i < ARRAYSIZEOF(ppsBase); ++i) + { + // walk through all datasets of hash entry + for (pData = ppsBase[i]; pData != NULL; pData = pData->pNext) + { + // found symbol name + if (lstrcmp(lpszName,pData->lpszName) == 0) + { + *pdwAddr = pData->dwAddr; // return address + return FALSE; // found + } + } + } + return TRUE; // not found +} diff --git a/Sources/Emu48/timer.c b/Sources/Emu48/TIMER.C similarity index 94% rename from Sources/Emu48/timer.c rename to Sources/Emu48/TIMER.C index 632b93a..6aa529d 100644 --- a/Sources/Emu48/timer.c +++ b/Sources/Emu48/TIMER.C @@ -1,435 +1,429 @@ -/* - * timer.c - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ -#include "pch.h" -#include "emu48.h" -#include "ops.h" -#include "io.h" // I/O definitions - -#define AUTO_OFF 10 // Time in minutes for 'auto off' - -// Ticks for 'auto off' -#define OFF_TIME ((ULONGLONG) (AUTO_OFF * 60) << 13) - -// memory address for clock and auto off -// S(X) = 0x70052-0x70070, G(X) = 0x80058-0x80076, 49G = 0x80058-0x80076 -#define RPLTIME ((cCurrentRomType=='S')?0x52:0x58) - -#define T1_FREQ 62 // Timer1 1/frequency in ms -#define T2_FREQ 8192 // Timer2 frequency - -static BOOL bStarted = FALSE; -static BOOL bOutRange = FALSE; // flag if timer value out of range -static UINT uT1TimerId = 0; -static UINT uT2TimerId = 0; - -static BOOL bNINT2T1 = FALSE; // state of NINT2 affected from timer1 -static BOOL bNINT2T2 = FALSE; // state of NINT2 affected from timer2 - -static BOOL bAccurateTimer; // flag if accurate timer is used -static LARGE_INTEGER lT2Ref; // counter value at timer2 start -static TIMECAPS tc; // timer information -static UINT uT2MaxTicks; // max. timer2 ticks handled by one timer event - -static DWORD dwT2Ref; // timer2 value at last timer2 access -static DWORD dwT2Cyc; // cpu cycle counter at last timer2 access - -static void CALLBACK TimeProc(UINT uEventId, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2); - -static DWORD CalcT2(VOID) // calculate timer2 value -{ - DWORD dwT2 = Chipset.t2; // get value from chipset - if (bStarted) // timer2 running - { - LARGE_INTEGER lT2Act; - DWORD dwT2Dif; - - // timer should run a little bit faster (10%) than maschine in authentic speed mode - DWORD dwCycPerTick = (9 * T2CYCLES) / 5; - - QueryPerformanceCounter(&lT2Act); // actual time - // calculate realtime timer2 ticks since reference point - dwT2 -= (DWORD) - (((lT2Act.QuadPart - lT2Ref.QuadPart) * T2_FREQ) - / lFreq.QuadPart); - - dwT2Dif = dwT2Ref - dwT2; // timer2 ticks since last request - - // checking if the MSB of dwT2Dif can be used as sign flag - _ASSERT((DWORD) tc.wPeriodMax < ((1<<(sizeof(dwT2Dif)*8-1))/8192)*1000); - - // 2nd timer call in a 32ms time frame or elapsed time is negative (Win2k bug) - if (!Chipset.Shutdn && ((dwT2Dif > 0x01 && dwT2Dif <= 0x100) || (dwT2Dif & 0x80000000) != 0)) - { - DWORD dwT2Ticks = ((DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwT2Cyc) / dwCycPerTick; - - // estimated < real elapsed timer2 ticks or negative time - if (dwT2Ticks < dwT2Dif || (dwT2Dif & 0x80000000) != 0) - { - // real time too long or got negative time elapsed - dwT2 = dwT2Ref - dwT2Ticks; // estimated timer2 value from CPU cycles - dwT2Cyc += dwT2Ticks * dwCycPerTick; // estimated CPU cycles for the timer2 ticks - } - else - { - // reached actual time -> new synchronizing - dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwCycPerTick; - } - } - else - { - // valid actual time -> new synchronizing - dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwCycPerTick; - } - - // check if timer2 interrupt is active -> no timer2 value below 0xFFFFFFFF - if ( Chipset.inte - && (dwT2 & 0x80000000) != 0 - && (!Chipset.Shutdn || (Chipset.IORam[TIMER2_CTRL]&WKE)) - && (Chipset.IORam[TIMER2_CTRL]&INTR) - ) - { - dwT2 = 0xFFFFFFFF; - dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwCycPerTick; - } - - dwT2Ref = dwT2; // new reference time - } - return dwT2; -} - -static VOID CheckT1(BYTE nT1) -{ - // implementation of TSRQ - bNINT2T1 = (Chipset.IORam[TIMER1_CTRL]&INTR) != 0 && (nT1&8) != 0; - IOBit(SRQ1,TSRQ,bNINT2T1 || bNINT2T2); - - if ((nT1&8) == 0) // timer1 MSB not set - { - Chipset.IORam[TIMER1_CTRL] &= ~SRQ; // clear SRQ bit - return; - } - - _ASSERT((nT1&8) != 0); // timer1 MSB set - - // timer MSB and INT or WAKE bit is set - if ((Chipset.IORam[TIMER1_CTRL]&(WKE|INTR)) != 0) - Chipset.IORam[TIMER1_CTRL] |= SRQ; // set SRQ - // cpu not sleeping and T1 -> Interrupt - if ( (!Chipset.Shutdn || (Chipset.IORam[TIMER1_CTRL]&WKE)) - && (Chipset.IORam[TIMER1_CTRL]&INTR)) - { - Chipset.SoftInt = TRUE; - bInterrupt = TRUE; - } - // cpu sleeping and T1 -> Wake Up - if (Chipset.Shutdn && (Chipset.IORam[TIMER1_CTRL]&WKE)) - { - Chipset.IORam[TIMER1_CTRL] &= ~WKE; // clear WKE bit - Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode - SetEvent(hEventShutdn); // wake up emulation thread - } - return; -} - -static VOID CheckT2(DWORD dwT2) -{ - // implementation of TSRQ - bNINT2T2 = (Chipset.IORam[TIMER2_CTRL]&INTR) != 0 && (dwT2&0x80000000) != 0; - IOBit(SRQ1,TSRQ,bNINT2T1 || bNINT2T2); - - if ((dwT2&0x80000000) == 0) // timer2 MSB not set - { - Chipset.IORam[TIMER2_CTRL] &= ~SRQ; // clear SRQ bit - return; - } - - _ASSERT((dwT2&0x80000000) != 0); // timer2 MSB set - - // timer MSB and INT or WAKE bit is set - if ((Chipset.IORam[TIMER2_CTRL]&(WKE|INTR)) != 0) - Chipset.IORam[TIMER2_CTRL] |= SRQ; // set SRQ - // cpu not sleeping and T2 -> Interrupt - if ( (!Chipset.Shutdn || (Chipset.IORam[TIMER2_CTRL]&WKE)) - && (Chipset.IORam[TIMER2_CTRL]&INTR)) - { - Chipset.SoftInt = TRUE; - bInterrupt = TRUE; - } - // cpu sleeping and T2 -> Wake Up - if (Chipset.Shutdn && (Chipset.IORam[TIMER2_CTRL]&WKE)) - { - Chipset.IORam[TIMER2_CTRL] &= ~WKE; // clear WKE bit - Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode - SetEvent(hEventShutdn); // wake up emulation thread - } - return; -} - -static VOID RescheduleT2(BOOL bRefPoint) -{ - UINT uDelay; - _ASSERT(uT2TimerId == 0); // timer2 must stopped - if (bRefPoint) // save reference time - { - dwT2Ref = Chipset.t2; // timer2 value at last timer2 access - dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); // cpu cycle counter at last timer2 access - QueryPerformanceCounter(&lT2Ref); // time of corresponding Chipset.t2 value - uDelay = Chipset.t2; // timer value for delay - } - else // called without new refpoint, restart t2 with actual value - { - uDelay = CalcT2(); // actual timer value for delay - } - if ((bOutRange = uDelay > uT2MaxTicks)) // delay greater maximum delay - uDelay = uT2MaxTicks; // wait maximum delay time - uDelay = (uDelay * 125 + 1023) / 1024; // timer delay in ms (1000/8192 = 125/1024) - uDelay = __max(tc.wPeriodMin,uDelay); // wait minimum delay of timer - _ASSERT(uDelay <= tc.wPeriodMax); // inside maximum event delay - // start timer2; schedule event, when Chipset.t2 will be zero - VERIFY(uT2TimerId = timeSetEvent(uDelay,0,&TimeProc,2,TIME_ONESHOT)); - return; -} - -static VOID AbortT2(VOID) -{ - _ASSERT(uT2TimerId); - timeKillEvent(uT2TimerId); // kill event - uT2TimerId = 0; // then reset var - return; -} - -static void CALLBACK TimeProc(UINT uEventId, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) -{ - if (uEventId == 0) return; // illegal EventId - - if (uEventId == uT1TimerId) // called from timer1 event (default period 16 Hz) - { - EnterCriticalSection(&csT1Lock); - { - Chipset.t1 = (Chipset.t1-1)&0xF;// decrement timer value - CheckT1(Chipset.t1); // test timer1 control bits - } - LeaveCriticalSection(&csT1Lock); - return; - } - if (uEventId == uT2TimerId) // called from timer2 event, Chipset.t2 should be zero - { - EnterCriticalSection(&csT2Lock); - { - uT2TimerId = 0; // single shot timer timer2 stopped - if (!bOutRange) // timer event elapsed - { - // timer2 overrun, test timer2 control bits else restart timer2 - Chipset.t2 = CalcT2(); // calculate new timer2 value - CheckT2(Chipset.t2); // test timer2 control bits - } - RescheduleT2(!bOutRange); // restart timer2 - } - LeaveCriticalSection(&csT2Lock); - return; - } - return; - UNREFERENCED_PARAMETER(uMsg); - UNREFERENCED_PARAMETER(dwUser); - UNREFERENCED_PARAMETER(dw1); - UNREFERENCED_PARAMETER(dw2); -} - -VOID SetHP48Time(VOID) // set date and time -{ - SYSTEMTIME ts; - ULONGLONG ticks, time; - DWORD dw; - WORD crc, i; - BYTE p[4]; - - _ASSERT(sizeof(ULONGLONG) == 8); // check size of datatype - - GetLocalTime(&ts); // local time, _ftime() cause memory/resource leaks - - // calculate days until 01.01.0000 (Erlang BIF localtime/0) - dw = (DWORD) ts.wMonth; - if (dw > 2) - dw -= 3L; - else - { - dw += 9L; - --ts.wYear; - } - dw = (DWORD) ts.wDay + (153L * dw + 2L) / 5L; - dw += (146097L * (((DWORD) ts.wYear) / 100L)) / 4L; - dw += (1461L * (((DWORD) ts.wYear) % 100L)) / 4L; - dw += (-719469L + 719528L); // days from year 0 - - ticks = (ULONGLONG) dw; // convert to 64 bit - - // convert into seconds and add time - ticks = ticks * 24L + (ULONGLONG) ts.wHour; - ticks = ticks * 60L + (ULONGLONG) ts.wMinute; - ticks = ticks * 60L + (ULONGLONG) ts.wSecond; - - // create timerticks = (s + ms) * 8192 - ticks = (ticks << 13) | (((ULONGLONG) ts.wMilliseconds << 10) / 125); - - ticks += Chipset.t2; // add actual timer2 value - - time = ticks; // save for calc. timeout - time += OFF_TIME; // add 10 min for auto off - - dw = RPLTIME; // HP addresses for clock in port0 - - crc = 0x0; // reset crc value - for (i = 0; i < 13; ++i, ++dw) // write date and time - { - *p = (BYTE) ticks & 0xf; - crc = (crc >> 4) ^ (((crc ^ ((WORD) *p)) & 0xf) * 0x1081); - Port0[dw] = *p; // always store in port0 - ticks >>= 4; - } - - Nunpack(p,crc,4); // write crc - memcpy(Port0+dw,p,4); // always store in port0 - - dw += 4; // HP addresses for timeout - - for (i = 0; i < 13; ++i, ++dw) // write time for auto off - { - Port0[dw] = (BYTE) time & 0xf; // always store in port0 - time >>= 4; - } - - Port0[dw] = 0xf; // always store in port0 - return; -} - -VOID StartTimers(VOID) -{ - if (bStarted) // timer running - return; // -> quit - if (Chipset.IORam[TIMER2_CTRL]&RUN) // start timer1 and timer2 ? - { - bStarted = TRUE; // flag timer running - // initialisation of NINT2 lines - bNINT2T1 = (Chipset.IORam[TIMER1_CTRL]&INTR) != 0 && (Chipset.t1 & 8) != 0; - bNINT2T2 = (Chipset.IORam[TIMER2_CTRL]&INTR) != 0 && (Chipset.t2 & 0x80000000) != 0; - timeGetDevCaps(&tc,sizeof(tc)); // get timer resolution - - // max. timer2 ticks that can be handled by one timer event - uT2MaxTicks = __min((0xFFFFFFFF / 1024),tc.wPeriodMax); - uT2MaxTicks = __min((0xFFFFFFFF - 1023) / 125,uT2MaxTicks * 1024 / 125); - - CheckT1(Chipset.t1); // check for timer1 interrupts - CheckT2(Chipset.t2); // check for timer2 interrupts - // set timer resolution to greatest possible one - bAccurateTimer = (timeBeginPeriod(tc.wPeriodMin) == TIMERR_NOERROR); - // set timer1 with given period - VERIFY(uT1TimerId = timeSetEvent(T1_FREQ,0,&TimeProc,1,TIME_PERIODIC)); - RescheduleT2(TRUE); // start timer2 - } - return; -} - -VOID StopTimers(VOID) -{ - if (!bStarted) // timer stopped - return; // -> quit - if (uT1TimerId != 0) // timer1 running - { - // Critical Section handler may cause a dead lock - timeKillEvent(uT1TimerId); // stop timer1 - uT1TimerId = 0; // set flag timer1 stopped - } - if (uT2TimerId != 0) // timer2 running - { - EnterCriticalSection(&csT2Lock); - { - Chipset.t2 = CalcT2(); // update chipset timer2 value - } - LeaveCriticalSection(&csT2Lock); - AbortT2(); // stop timer2 outside critical section - } - bStarted = FALSE; - if (bAccurateTimer) // "Accurate timer" running - { - timeEndPeriod(tc.wPeriodMin); // finish service - } - return; -} - -DWORD ReadT2(VOID) -{ - DWORD dwT2; - EnterCriticalSection(&csT2Lock); - { - dwT2 = CalcT2(); // calculate timer2 value or if stopped last timer value - CheckT2(dwT2); // update timer2 control bits - } - LeaveCriticalSection(&csT2Lock); - return dwT2; -} - -VOID SetT2(DWORD dwValue) -{ - // calling AbortT2() inside Critical Section handler may cause a dead lock - if (uT2TimerId != 0) // timer2 running - AbortT2(); // stop timer2 - EnterCriticalSection(&csT2Lock); - { - Chipset.t2 = dwValue; // set new value - CheckT2(Chipset.t2); // test timer2 control bits - if (bStarted) // timer running - RescheduleT2(TRUE); // restart timer2 - } - LeaveCriticalSection(&csT2Lock); - return; -} - -BYTE ReadT1(VOID) -{ - BYTE nT1; - EnterCriticalSection(&csT1Lock); - { - nT1 = Chipset.t1; // read timer1 value - CheckT1(nT1); // update timer1 control bits - } - LeaveCriticalSection(&csT1Lock); - return nT1; -} - -VOID SetT1(BYTE byValue) -{ - BOOL bEqual; - - _ASSERT(byValue < 0x10); // timer1 is only a 4bit counter - - EnterCriticalSection(&csT1Lock); - { - bEqual = (Chipset.t1 == byValue); // check for same value - } - LeaveCriticalSection(&csT1Lock); - if (bEqual) return; // same value doesn't restart timer period - - if (uT1TimerId != 0) // timer1 running - { - timeKillEvent(uT1TimerId); // stop timer1 - uT1TimerId = 0; // set flag timer1 stopped - } - EnterCriticalSection(&csT1Lock); - { - Chipset.t1 = byValue; // set new timer1 value - CheckT1(Chipset.t1); // test timer1 control bits - } - LeaveCriticalSection(&csT1Lock); - if (bStarted) // timer running - { - // restart timer1 to get full period of frequency - VERIFY(uT1TimerId = timeSetEvent(T1_FREQ,0,&TimeProc,1,TIME_PERIODIC)); - } - return; -} +/* + * timer.c + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ +#include "pch.h" +#include "Emu48.h" +#include "ops.h" +#include "io.h" // I/O definitions + +#define AUTO_OFF 10 // Time in minutes for 'auto off' + +// Ticks for 'auto off' +#define OFF_TIME ((ULONGLONG) (AUTO_OFF * 60) << 13) + +// memory address for clock and auto off +// S(X) = 0x70052-0x70070, G(X) = 0x80058-0x80076, 49G = 0x80058-0x80076 +#define RPLTIME ((cCurrentRomType=='S')?0x52:0x58) + +#define T1_FREQ 62 // Timer1 1/frequency in ms +#define T2_FREQ 8192 // Timer2 frequency + +static BOOL bStarted = FALSE; +static BOOL bOutRange = FALSE; // flag if timer value out of range +static UINT uT1TimerId = 0; +static UINT uT2TimerId = 0; + +static BOOL bNINT2T1 = FALSE; // state of NINT2 affected from timer1 +static BOOL bNINT2T2 = FALSE; // state of NINT2 affected from timer2 + +static BOOL bAccurateTimer; // flag if accurate timer is used +static LARGE_INTEGER lT2Ref; // counter value at timer2 start +static TIMECAPS tc; // timer information +static UINT uT2MaxTicks; // max. timer2 ticks handled by one timer event + +static DWORD dwT2Ref; // timer2 value at last timer2 access +static DWORD dwT2Cyc; // cpu cycle counter at last timer2 access + +static void CALLBACK TimeProc(UINT uEventId, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2); + +static DWORD CalcT2(VOID) // calculate timer2 value +{ + DWORD dwT2 = Chipset.t2; // get value from chipset + if (bStarted) // timer2 running + { + LARGE_INTEGER lT2Act; + DWORD dwT2Dif; + + // timer should run a little bit faster (10%) than maschine in authentic speed mode + DWORD dwCycPerTick = (9 * T2CYCLES) / 5; + + QueryPerformanceCounter(&lT2Act); // actual time + // calculate realtime timer2 ticks since reference point + dwT2 -= (DWORD) + (((lT2Act.QuadPart - lT2Ref.QuadPart) * T2_FREQ) + / lFreq.QuadPart); + + dwT2Dif = dwT2Ref - dwT2; // timer2 ticks since last request + + // checking if the MSB of dwT2Dif can be used as sign flag + _ASSERT((DWORD) tc.wPeriodMax < ((1<<(sizeof(dwT2Dif)*8-1))/8192)*1000); + + // 2nd timer call in a 32ms time frame or elapsed time is negative (Win2k bug) + if (!Chipset.Shutdn && ((dwT2Dif > 0x01 && dwT2Dif <= 0x100) || (dwT2Dif & 0x80000000) != 0)) + { + DWORD dwT2Ticks = ((DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwT2Cyc) / dwCycPerTick; + + // estimated < real elapsed timer2 ticks or negative time + if (dwT2Ticks < dwT2Dif || (dwT2Dif & 0x80000000) != 0) + { + // real time too long or got negative time elapsed + dwT2 = dwT2Ref - dwT2Ticks; // estimated timer2 value from CPU cycles + dwT2Cyc += dwT2Ticks * dwCycPerTick; // estimated CPU cycles for the timer2 ticks + } + else + { + // reached actual time -> new synchronizing + dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwCycPerTick; + } + } + else + { + // valid actual time -> new synchronizing + dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwCycPerTick; + } + + // check if timer2 interrupt is active -> no timer2 value below 0xFFFFFFFF + if ( Chipset.inte + && (dwT2 & 0x80000000) != 0 + && (!Chipset.Shutdn || (Chipset.IORam[TIMER2_CTRL]&WKE)) + && (Chipset.IORam[TIMER2_CTRL]&INTR) + ) + { + dwT2 = 0xFFFFFFFF; + dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwCycPerTick; + } + + dwT2Ref = dwT2; // new reference time + } + return dwT2; +} + +static VOID CheckT1(BYTE nT1) +{ + // implementation of TSRQ + bNINT2T1 = (Chipset.IORam[TIMER1_CTRL]&INTR) != 0 && (nT1&8) != 0; + IOBit(SRQ1,TSRQ,bNINT2T1 || bNINT2T2); + + if ((nT1&8) == 0) // timer1 MSB not set + { + Chipset.IORam[TIMER1_CTRL] &= ~SRQ; // clear SRQ bit + return; + } + + _ASSERT((nT1&8) != 0); // timer1 MSB set + + // timer MSB and INT or WAKE bit is set + if ((Chipset.IORam[TIMER1_CTRL]&(WKE|INTR)) != 0) + Chipset.IORam[TIMER1_CTRL] |= SRQ; // set SRQ + // cpu not sleeping and T1 -> Interrupt + if ( (!Chipset.Shutdn || (Chipset.IORam[TIMER1_CTRL]&WKE)) + && (Chipset.IORam[TIMER1_CTRL]&INTR)) + { + Chipset.SoftInt = TRUE; + bInterrupt = TRUE; + } + // cpu sleeping and T1 -> Wake Up + if (Chipset.Shutdn && (Chipset.IORam[TIMER1_CTRL]&WKE)) + { + Chipset.IORam[TIMER1_CTRL] &= ~WKE; // clear WKE bit + Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode + SetEvent(hEventShutdn); // wake up emulation thread + } + return; +} + +static VOID CheckT2(DWORD dwT2) +{ + // implementation of TSRQ + bNINT2T2 = (Chipset.IORam[TIMER2_CTRL]&INTR) != 0 && (dwT2&0x80000000) != 0; + IOBit(SRQ1,TSRQ,bNINT2T1 || bNINT2T2); + + if ((dwT2&0x80000000) == 0) // timer2 MSB not set + { + Chipset.IORam[TIMER2_CTRL] &= ~SRQ; // clear SRQ bit + return; + } + + _ASSERT((dwT2&0x80000000) != 0); // timer2 MSB set + + // timer MSB and INT or WAKE bit is set + if ((Chipset.IORam[TIMER2_CTRL]&(WKE|INTR)) != 0) + Chipset.IORam[TIMER2_CTRL] |= SRQ; // set SRQ + // cpu not sleeping and T2 -> Interrupt + if ( (!Chipset.Shutdn || (Chipset.IORam[TIMER2_CTRL]&WKE)) + && (Chipset.IORam[TIMER2_CTRL]&INTR)) + { + Chipset.SoftInt = TRUE; + bInterrupt = TRUE; + } + // cpu sleeping and T2 -> Wake Up + if (Chipset.Shutdn && (Chipset.IORam[TIMER2_CTRL]&WKE)) + { + Chipset.IORam[TIMER2_CTRL] &= ~WKE; // clear WKE bit + Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode + SetEvent(hEventShutdn); // wake up emulation thread + } + return; +} + +static VOID RescheduleT2(BOOL bRefPoint) +{ + UINT uDelay; + _ASSERT(uT2TimerId == 0); // timer2 must stopped + if (bRefPoint) // save reference time + { + dwT2Ref = Chipset.t2; // timer2 value at last timer2 access + dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); // cpu cycle counter at last timer2 access + QueryPerformanceCounter(&lT2Ref); // time of corresponding Chipset.t2 value + uDelay = Chipset.t2; // timer value for delay + } + else // called without new refpoint, restart t2 with actual value + { + uDelay = CalcT2(); // actual timer value for delay + } + if ((bOutRange = uDelay > uT2MaxTicks)) // delay greater maximum delay + uDelay = uT2MaxTicks; // wait maximum delay time + uDelay = (uDelay * 125 + 1023) / 1024; // timer delay in ms (1000/8192 = 125/1024) + uDelay = __max(tc.wPeriodMin,uDelay); // wait minimum delay of timer + _ASSERT(uDelay <= tc.wPeriodMax); // inside maximum event delay + // start timer2; schedule event, when Chipset.t2 will be zero + VERIFY(uT2TimerId = timeSetEvent(uDelay,0,&TimeProc,2,TIME_ONESHOT)); + return; +} + +static VOID AbortT2(VOID) +{ + _ASSERT(uT2TimerId); + timeKillEvent(uT2TimerId); // kill event + uT2TimerId = 0; // then reset var + return; +} + +static void CALLBACK TimeProc(UINT uEventId, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) +{ + if (uEventId == 0) return; // illegal EventId + + if (uEventId == uT1TimerId) // called from timer1 event (default period 16 Hz) + { + EnterCriticalSection(&csT1Lock); + { + Chipset.t1 = (Chipset.t1-1)&0xF;// decrement timer value + CheckT1(Chipset.t1); // test timer1 control bits + } + LeaveCriticalSection(&csT1Lock); + return; + } + if (uEventId == uT2TimerId) // called from timer2 event, Chipset.t2 should be zero + { + EnterCriticalSection(&csT2Lock); + { + uT2TimerId = 0; // single shot timer timer2 stopped + if (!bOutRange) // timer event elapsed + { + // timer2 overrun, test timer2 control bits else restart timer2 + Chipset.t2 = CalcT2(); // calculate new timer2 value + CheckT2(Chipset.t2); // test timer2 control bits + } + RescheduleT2(!bOutRange); // restart timer2 + } + LeaveCriticalSection(&csT2Lock); + return; + } + return; + UNREFERENCED_PARAMETER(uMsg); + UNREFERENCED_PARAMETER(dwUser); + UNREFERENCED_PARAMETER(dw1); + UNREFERENCED_PARAMETER(dw2); +} + +VOID SetHP48Time(VOID) // set date and time +{ + SYSTEMTIME ts; + ULONGLONG ticks, time; + DWORD dw; + WORD crc, i; + LPBYTE pbyTime; + + _ASSERT(sizeof(ULONGLONG) == 8); // check size of datatype + + GetLocalTime(&ts); // local time, _ftime() cause memory/resource leaks + + // calculate days until 01.01.0000 (Erlang BIF localtime/0) + dw = (DWORD) ts.wMonth; + if (dw > 2) + dw -= 3L; + else + { + dw += 9L; + --ts.wYear; + } + dw = (DWORD) ts.wDay + (153L * dw + 2L) / 5L; + dw += (146097L * (((DWORD) ts.wYear) / 100L)) / 4L; + dw += (1461L * (((DWORD) ts.wYear) % 100L)) / 4L; + dw += (-719469L + 719528L); // days from year 0 + + ticks = (ULONGLONG) dw; // convert to 64 bit + + // convert into seconds and add time + ticks = ticks * 24L + (ULONGLONG) ts.wHour; + ticks = ticks * 60L + (ULONGLONG) ts.wMinute; + ticks = ticks * 60L + (ULONGLONG) ts.wSecond; + + // create timerticks = (s + ms) * 8192 + ticks = (ticks << 13) | (((ULONGLONG) ts.wMilliseconds << 10) / 125); + + ticks += Chipset.t2; // add actual timer2 value + + time = ticks; // save for calc. timeout + time += OFF_TIME; // add 10 min for auto off + + pbyTime = Port0 + RPLTIME; // HP addresses for clock in port0 + + crc = 0x0; // reset crc value + for (i = 0; i < 13; ++i) // write date and time + { + *pbyTime = (BYTE) ticks & 0xf; // time + crc = UpCRC(crc,*pbyTime); + ticks >>= 4; + + pbyTime[13+4] = (BYTE) time & 0xf; // auto off + time >>= 4; + ++pbyTime; + } + + Nunpack(pbyTime,crc,4); // write crc + + pbyTime[13+4] = 0xf; + return; +} + +VOID StartTimers(VOID) +{ + if (bStarted) // timer running + return; // -> quit + if (Chipset.IORam[TIMER2_CTRL]&RUN) // start timer1 and timer2 ? + { + bStarted = TRUE; // flag timer running + // initialisation of NINT2 lines + bNINT2T1 = (Chipset.IORam[TIMER1_CTRL]&INTR) != 0 && (Chipset.t1 & 8) != 0; + bNINT2T2 = (Chipset.IORam[TIMER2_CTRL]&INTR) != 0 && (Chipset.t2 & 0x80000000) != 0; + timeGetDevCaps(&tc,sizeof(tc)); // get timer resolution + + // max. timer2 ticks that can be handled by one timer event + uT2MaxTicks = __min((0xFFFFFFFF / 1024),tc.wPeriodMax); + uT2MaxTicks = __min((0xFFFFFFFF - 1023) / 125,uT2MaxTicks * 1024 / 125); + + CheckT1(Chipset.t1); // check for timer1 interrupts + CheckT2(Chipset.t2); // check for timer2 interrupts + // set timer resolution to greatest possible one + bAccurateTimer = (timeBeginPeriod(tc.wPeriodMin) == TIMERR_NOERROR); + // set timer1 with given period + VERIFY(uT1TimerId = timeSetEvent(T1_FREQ,0,&TimeProc,1,TIME_PERIODIC)); + RescheduleT2(TRUE); // start timer2 + } + return; +} + +VOID StopTimers(VOID) +{ + if (!bStarted) // timer stopped + return; // -> quit + if (uT1TimerId != 0) // timer1 running + { + // Critical Section handler may cause a dead lock + timeKillEvent(uT1TimerId); // stop timer1 + uT1TimerId = 0; // set flag timer1 stopped + } + if (uT2TimerId != 0) // timer2 running + { + EnterCriticalSection(&csT2Lock); + { + Chipset.t2 = CalcT2(); // update chipset timer2 value + } + LeaveCriticalSection(&csT2Lock); + AbortT2(); // stop timer2 outside critical section + } + bStarted = FALSE; + if (bAccurateTimer) // "Accurate timer" running + { + timeEndPeriod(tc.wPeriodMin); // finish service + } + return; +} + +DWORD ReadT2(VOID) +{ + DWORD dwT2; + EnterCriticalSection(&csT2Lock); + { + dwT2 = CalcT2(); // calculate timer2 value or if stopped last timer value + CheckT2(dwT2); // update timer2 control bits + } + LeaveCriticalSection(&csT2Lock); + return dwT2; +} + +VOID SetT2(DWORD dwValue) +{ + // calling AbortT2() inside Critical Section handler may cause a dead lock + if (uT2TimerId != 0) // timer2 running + AbortT2(); // stop timer2 + EnterCriticalSection(&csT2Lock); + { + Chipset.t2 = dwValue; // set new value + CheckT2(Chipset.t2); // test timer2 control bits + if (bStarted) // timer running + RescheduleT2(TRUE); // restart timer2 + } + LeaveCriticalSection(&csT2Lock); + return; +} + +BYTE ReadT1(VOID) +{ + BYTE nT1; + EnterCriticalSection(&csT1Lock); + { + nT1 = Chipset.t1; // read timer1 value + CheckT1(nT1); // update timer1 control bits + } + LeaveCriticalSection(&csT1Lock); + return nT1; +} + +VOID SetT1(BYTE byValue) +{ + BOOL bEqual; + + _ASSERT(byValue < 0x10); // timer1 is only a 4bit counter + + EnterCriticalSection(&csT1Lock); + { + bEqual = (Chipset.t1 == byValue); // check for same value + } + LeaveCriticalSection(&csT1Lock); + if (bEqual) return; // same value doesn't restart timer period + + if (uT1TimerId != 0) // timer1 running + { + timeKillEvent(uT1TimerId); // stop timer1 + uT1TimerId = 0; // set flag timer1 stopped + } + EnterCriticalSection(&csT1Lock); + { + Chipset.t1 = byValue; // set new timer1 value + CheckT1(Chipset.t1); // test timer1 control bits + } + LeaveCriticalSection(&csT1Lock); + if (bStarted) // timer running + { + // restart timer1 to get full period of frequency + VERIFY(uT1TimerId = timeSetEvent(T1_FREQ,0,&TimeProc,1,TIME_PERIODIC)); + } + return; +} diff --git a/Sources/Emu48/types.h b/Sources/Emu48/TYPES.H similarity index 96% rename from Sources/Emu48/types.h rename to Sources/Emu48/TYPES.H index b336127..003d3ff 100644 --- a/Sources/Emu48/types.h +++ b/Sources/Emu48/TYPES.H @@ -1,103 +1,103 @@ -/* - * types.h - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ - -// HST bits -#define XM 1 -#define SB 2 -#define SR 4 -#define MP 8 - -#define SWORD SHORT // signed 16 Bit variable -#define QWORD ULONGLONG // unsigned 64 Bit variable - -#define CHIPSET Chipset_t -typedef struct -{ - SWORD nPosX; // position of window - SWORD nPosY; - BYTE type; // calculator type - - DWORD Port0Size; // real size of module in KB - DWORD Port1Size; // real size of module in KB - DWORD Port2Size; // real size of module in KB (HP49G only) - DWORD dwUnused0; // not used, was memory pointer Port0 - DWORD dwUnused1; // not used, was memory pointer Port1 - DWORD dwUnused2; // not used, was memory pointer Port2 - - DWORD pc; - DWORD d0; - DWORD d1; - DWORD rstkp; - DWORD rstk[8]; - BYTE A[16]; - BYTE B[16]; - BYTE C[16]; - BYTE D[16]; - BYTE R0[16]; - BYTE R1[16]; - BYTE R2[16]; - BYTE R3[16]; - BYTE R4[16]; - BYTE ST[4]; - BYTE HST; - BYTE P; - WORD out; - WORD in; - BOOL SoftInt; - BOOL Shutdn; - BOOL mode_dec; - BOOL inte; // interrupt status flag (FALSE = int in service) - BOOL intk; // 1 ms keyboard scan flag (TRUE = enable) - BOOL intd; // keyboard interrupt pending (TRUE = int pending) - BOOL carry; - - WORD crc; - WORD wPort2Crc; // fingerprint of port2 - WORD wRomCrc; // fingerprint of ROM -#if defined _USRDLL // DLL version - QWORD cycles; // oscillator cycles -#else // EXE version - DWORD cycles; // oscillator cycles - DWORD cycles_reserved; // reserved for MSB of oscillator cycles -#endif - DWORD dwKdnCycles; // cpu cycles at start of 1ms key handler - - UINT Bank_FF; // save state of HP48GX port2 or state of HP49G ROM FF - UINT FlashRomState; // WSM state of flash memory (unused) - BYTE cards_status; - BYTE IORam[64]; // I/O hardware register - UINT IOBase; // address of I/O modules page - BOOL IOCfig; // I/O module configuration flag - BYTE P0Base, BSBase, P1Base, P2Base; // address of modules first 2KB page - BYTE P0Size, BSSize, P1Size, P2Size; // mapped size of module in 2KB - BYTE P0End, BSEnd, P1End, P2End; // address of modules last 2KB page - BOOL P0Cfig, BSCfig, P1Cfig, P2Cfig; // module address configuration flag - BOOL P0Cfg2, BSCfg2, P1Cfg2, P2Cfg2; // module size configuration flag - - BYTE t1; - DWORD t2; - - BOOL bShutdnWake; // flag for wake up from SHUTDN mode - - BYTE Keyboard_Row[9]; - WORD IR15X; - UINT Keyboard_State; // not used - - signed short loffset; - signed int width; - UINT boffset; - UINT lcounter; - UINT sync; // not used - BYTE contrast; - BOOL dispon; // not used - DWORD start1; - DWORD start12; - DWORD end1; - DWORD start2, end2; -} Chipset_t; +/* + * types.h + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ + +// HST bits +#define XM 1 +#define SB 2 +#define SR 4 +#define MP 8 + +#define SWORD SHORT // signed 16 Bit variable +#define QWORD ULONGLONG // unsigned 64 Bit variable + +#define CHIPSET Chipset_t +typedef struct +{ + SWORD nPosX; // position of window + SWORD nPosY; + BYTE type; // calculator type + + DWORD Port0Size; // real size of module in KB + DWORD Port1Size; // real size of module in KB + DWORD Port2Size; // real size of module in KB (HP49G only) + DWORD dwUnused0; // not used, was memory pointer Port0 + DWORD dwUnused1; // not used, was memory pointer Port1 + DWORD dwUnused2; // not used, was memory pointer Port2 + + DWORD pc; + DWORD d0; + DWORD d1; + DWORD rstkp; + DWORD rstk[8]; + BYTE A[16]; + BYTE B[16]; + BYTE C[16]; + BYTE D[16]; + BYTE R0[16]; + BYTE R1[16]; + BYTE R2[16]; + BYTE R3[16]; + BYTE R4[16]; + BYTE ST[4]; + BYTE HST; + BYTE P; + WORD out; + WORD in; + BOOL SoftInt; + BOOL Shutdn; + BOOL mode_dec; + BOOL inte; // interrupt status flag (FALSE = int in service) + BOOL intk; // 1 ms keyboard scan flag (TRUE = enable) + BOOL intd; // keyboard interrupt pending (TRUE = int pending) + BOOL carry; + + WORD crc; + WORD wPort2Crc; // fingerprint of port2 + WORD wRomCrc; // fingerprint of ROM +#if defined _USRDLL // DLL version + QWORD cycles; // oscillator cycles +#else // EXE version + DWORD cycles; // oscillator cycles + DWORD cycles_reserved; // reserved for MSB of oscillator cycles +#endif + DWORD dwKdnCycles; // cpu cycles at start of 1ms key handler + + UINT Bank_FF; // save state of HP48GX port2 or state of HP49G ROM FF + UINT FlashRomState; // WSM state of flash memory (unused) + BYTE cards_status; + BYTE IORam[64]; // I/O hardware register + UINT IOBase; // address of I/O modules page + BOOL IOCfig; // I/O module configuration flag + BYTE P0Base, BSBase, P1Base, P2Base; // address of modules first 2KB page + BYTE P0Size, BSSize, P1Size, P2Size; // mapped size of module in 2KB + BYTE P0End, BSEnd, P1End, P2End; // address of modules last 2KB page + BOOL P0Cfig, BSCfig, P1Cfig, P2Cfig; // module address configuration flag + BOOL P0Cfg2, BSCfg2, P1Cfg2, P2Cfg2; // module size configuration flag + + BYTE t1; + DWORD t2; + + BOOL bShutdnWake; // flag for wake up from SHUTDN mode + + BYTE Keyboard_Row[9]; + WORD IR15X; + UINT Keyboard_State; // not used + + signed short loffset; + signed int width; + UINT boffset; + UINT lcounter; + UINT sync; // not used + BYTE contrast; + BOOL dispon; // not used + DWORD start1; + DWORD start12; + DWORD end1; + DWORD start2, end2; +} Chipset_t; diff --git a/Sources/Emu48/udp.c b/Sources/Emu48/UDP.C similarity index 92% rename from Sources/Emu48/udp.c rename to Sources/Emu48/UDP.C index 63e9a79..09972f6 100644 --- a/Sources/Emu48/udp.c +++ b/Sources/Emu48/UDP.C @@ -1,78 +1,73 @@ -/* - * udp.c - * - * This file is part of Emu48 - * - * Copyright (C) 2011 Christoph Gießelink - * - */ -#include "pch.h" -#include "emu48.h" - -TCHAR szUdpServer[1024] = _T("localhost"); -WORD wUdpPort = 5025; // scpi-raw - -static SOCKADDR_IN sServer = { AF_INET, 0, { 255, 255, 255, 255 } }; - -VOID ResetUdp(VOID) -{ - sServer.sin_addr.s_addr = INADDR_NONE; // invalidate saved UDP address - return; -} - -BOOL SendByteUdp(BYTE byData) -{ - WSADATA wsd; - SOCKET sClient; - - BOOL bErr = TRUE; - - VERIFY(WSAStartup(MAKEWORD(1,1),&wsd) == 0); - - // IP address not specified - if (sServer.sin_addr.s_addr == INADDR_NONE) - { - LPSTR lpszIpAddr; - - #if defined _UNICODE - DWORD dwLength = lstrlen(szUdpServer) + 1; - - if ((lpszIpAddr = (LPSTR) _alloca(dwLength)) == NULL) - return TRUE; // server ip address not found - - WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, - szUdpServer, dwLength, - lpszIpAddr, dwLength, NULL, NULL); - #else - lpszIpAddr = szUdpServer; - #endif - - // try to interpret string as IPv4 address - sServer.sin_addr.s_addr = inet_addr(lpszIpAddr); - - // not a valid ip address -> try to get ip address from name server - if (sServer.sin_addr.s_addr == INADDR_NONE) - { - PHOSTENT host = gethostbyname(lpszIpAddr); - if (host == NULL) - { - return TRUE; // server ip address not found - } - - sServer.sin_addr.s_addr = ((PIN_ADDR) host->h_addr_list[0])->s_addr; - } - } - - // create UDP socket - if ((sClient = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) - { - sServer.sin_port = htons(wUdpPort); - - // transmit data byte - bErr = sendto(sClient, (LPCCH) &byData, sizeof(byData), 0, (LPSOCKADDR) &sServer, sizeof(sServer)) == SOCKET_ERROR; - closesocket(sClient); - } - - WSACleanup(); // cleanup network stack - return bErr; -} +/* + * udp.c + * + * This file is part of Emu48 + * + * Copyright (C) 2011 Christoph Gießelink + * + */ +#include "pch.h" +#include "Emu48.h" + +TCHAR szUdpServer[1024] = _T("localhost"); +WORD wUdpPort = 5025; // scpi-raw + +static SOCKADDR_IN sServer = { AF_INET, 0, { 255, 255, 255, 255 } }; + +VOID ResetUdp(VOID) +{ + sServer.sin_addr.s_addr = INADDR_NONE; // invalidate saved UDP address + return; +} + +BOOL SendByteUdp(BYTE byData) +{ + SOCKET sClient; + + BOOL bErr = TRUE; + + // IP address not specified + if (sServer.sin_addr.s_addr == INADDR_NONE) + { + LPSTR lpszIpAddr; + + #if defined _UNICODE + DWORD dwLength = lstrlen(szUdpServer) + 1; + + if ((lpszIpAddr = (LPSTR) _alloca(dwLength)) == NULL) + return TRUE; // server ip address not found + + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, + szUdpServer, dwLength, + lpszIpAddr, dwLength, NULL, NULL); + #else + lpszIpAddr = szUdpServer; + #endif + + // try to interpret string as IPv4 address + sServer.sin_addr.s_addr = inet_addr(lpszIpAddr); + + // not a valid ip address -> try to get ip address from name server + if (sServer.sin_addr.s_addr == INADDR_NONE) + { + PHOSTENT host = gethostbyname(lpszIpAddr); + if (host == NULL) + { + return TRUE; // server ip address not found + } + + sServer.sin_addr.s_addr = ((PIN_ADDR) host->h_addr_list[0])->s_addr; + } + } + + // create UDP socket + if ((sClient = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) + { + sServer.sin_port = htons(wUdpPort); + + // transmit data byte + bErr = sendto(sClient, (LPCCH) &byData, sizeof(byData), 0, (LPSOCKADDR) &sServer, sizeof(sServer)) == SOCKET_ERROR; + closesocket(sClient); + } + return bErr; +} diff --git a/Sources/Emu48/fetch.c b/Sources/Emu48/fetch.c deleted file mode 100644 index 074e3c7..0000000 --- a/Sources/Emu48/fetch.c +++ /dev/null @@ -1,778 +0,0 @@ -/* - * fetch.c - * - * This file is part of Emu48 - * - * Copyright (C) 1999 Christoph Gießelink - * - */ -#include "pch.h" -#include "opcodes.h" - -#define F 0xFF // F = function - -typedef const struct -{ - LPCVOID pLnk; - const DWORD dwTyp; -} JMPTAB, *PJMPTAB; - -// jump tables -static JMPTAB oF_[] = -{ - (LPCVOID) oF0, F, - (LPCVOID) oF1, F, - (LPCVOID) oF2, F, - (LPCVOID) oF3, F, - (LPCVOID) oF4, F, - (LPCVOID) oF5, F, - (LPCVOID) oF6, F, - (LPCVOID) oF7, F, - (LPCVOID) oF8, F, - (LPCVOID) oF9, F, - (LPCVOID) oFA, F, - (LPCVOID) oFB, F, - (LPCVOID) oFC, F, - (LPCVOID) oFD, F, - (LPCVOID) oFE, F, - (LPCVOID) oFF, F -}; - -static JMPTAB oE_[] = -{ - (LPCVOID) oE0, F, - (LPCVOID) oE1, F, - (LPCVOID) oE2, F, - (LPCVOID) oE3, F, - (LPCVOID) oE4, F, - (LPCVOID) oE5, F, - (LPCVOID) oE6, F, - (LPCVOID) oE7, F, - (LPCVOID) oE8, F, - (LPCVOID) oE9, F, - (LPCVOID) oEA, F, - (LPCVOID) oEB, F, - (LPCVOID) oEC, F, - (LPCVOID) oED, F, - (LPCVOID) oEE, F, - (LPCVOID) oEF, F -}; - -static JMPTAB oD_[] = -{ - (LPCVOID) oD0, F, - (LPCVOID) oD1, F, - (LPCVOID) oD2, F, - (LPCVOID) oD3, F, - (LPCVOID) oD4, F, - (LPCVOID) oD5, F, - (LPCVOID) oD6, F, - (LPCVOID) oD7, F, - (LPCVOID) oD8, F, - (LPCVOID) oD9, F, - (LPCVOID) oDA, F, - (LPCVOID) oDB, F, - (LPCVOID) oDC, F, - (LPCVOID) oDD, F, - (LPCVOID) oDE, F, - (LPCVOID) oDF, F -}; - -static JMPTAB oC_[] = -{ - (LPCVOID) oC0, F, - (LPCVOID) oC1, F, - (LPCVOID) oC2, F, - (LPCVOID) oC3, F, - (LPCVOID) oC4, F, - (LPCVOID) oC5, F, - (LPCVOID) oC6, F, - (LPCVOID) oC7, F, - (LPCVOID) oC8, F, - (LPCVOID) oC9, F, - (LPCVOID) oCA, F, - (LPCVOID) oCB, F, - (LPCVOID) oCC, F, - (LPCVOID) oCD, F, - (LPCVOID) oCE, F, - (LPCVOID) oCF, F -}; - -static JMPTAB oBb_[] = -{ - (LPCVOID) oBb0, F, - (LPCVOID) oBb1, F, - (LPCVOID) oBb2, F, - (LPCVOID) oBb3, F, - (LPCVOID) oBb4, F, - (LPCVOID) oBb5, F, - (LPCVOID) oBb6, F, - (LPCVOID) oBb7, F, - (LPCVOID) oBb8, F, - (LPCVOID) oBb9, F, - (LPCVOID) oBbA, F, - (LPCVOID) oBbB, F, - (LPCVOID) oBbC, F, - (LPCVOID) oBbD, F, - (LPCVOID) oBbE, F, - (LPCVOID) oBbF, F -}; - -static JMPTAB oBa_[] = -{ - (LPCVOID) oBa0, F, - (LPCVOID) oBa1, F, - (LPCVOID) oBa2, F, - (LPCVOID) oBa3, F, - (LPCVOID) oBa4, F, - (LPCVOID) oBa5, F, - (LPCVOID) oBa6, F, - (LPCVOID) oBa7, F, - (LPCVOID) oBa8, F, - (LPCVOID) oBa9, F, - (LPCVOID) oBaA, F, - (LPCVOID) oBaB, F, - (LPCVOID) oBaC, F, - (LPCVOID) oBaD, F, - (LPCVOID) oBaE, F, - (LPCVOID) oBaF, F -}; - -static JMPTAB oB_[] = -{ - (LPCVOID) oBa_, 2, - (LPCVOID) oBa_, 2, - (LPCVOID) oBa_, 2, - (LPCVOID) oBa_, 2, - (LPCVOID) oBa_, 2, - (LPCVOID) oBa_, 2, - (LPCVOID) oBa_, 2, - (LPCVOID) oBa_, 2, - (LPCVOID) oBb_, 2, - (LPCVOID) oBb_, 2, - (LPCVOID) oBb_, 2, - (LPCVOID) oBb_, 2, - (LPCVOID) oBb_, 2, - (LPCVOID) oBb_, 2, - (LPCVOID) oBb_, 2, - (LPCVOID) oBb_, 2 -}; - -static JMPTAB oAb_[] = -{ - (LPCVOID) oAb0, F, - (LPCVOID) oAb1, F, - (LPCVOID) oAb2, F, - (LPCVOID) oAb3, F, - (LPCVOID) oAb4, F, - (LPCVOID) oAb5, F, - (LPCVOID) oAb6, F, - (LPCVOID) oAb7, F, - (LPCVOID) oAb8, F, - (LPCVOID) oAb9, F, - (LPCVOID) oAbA, F, - (LPCVOID) oAbB, F, - (LPCVOID) oAbC, F, - (LPCVOID) oAbD, F, - (LPCVOID) oAbE, F, - (LPCVOID) oAbF, F -}; - -static JMPTAB oAa_[] = -{ - (LPCVOID) oAa0, F, - (LPCVOID) oAa1, F, - (LPCVOID) oAa2, F, - (LPCVOID) oAa3, F, - (LPCVOID) oAa4, F, - (LPCVOID) oAa5, F, - (LPCVOID) oAa6, F, - (LPCVOID) oAa7, F, - (LPCVOID) oAa8, F, - (LPCVOID) oAa9, F, - (LPCVOID) oAaA, F, - (LPCVOID) oAaB, F, - (LPCVOID) oAaC, F, - (LPCVOID) oAaD, F, - (LPCVOID) oAaE, F, - (LPCVOID) oAaF, F -}; - -static JMPTAB oA_[] = -{ - (LPCVOID) oAa_, 2, - (LPCVOID) oAa_, 2, - (LPCVOID) oAa_, 2, - (LPCVOID) oAa_, 2, - (LPCVOID) oAa_, 2, - (LPCVOID) oAa_, 2, - (LPCVOID) oAa_, 2, - (LPCVOID) oAa_, 2, - (LPCVOID) oAb_, 2, - (LPCVOID) oAb_, 2, - (LPCVOID) oAb_, 2, - (LPCVOID) oAb_, 2, - (LPCVOID) oAb_, 2, - (LPCVOID) oAb_, 2, - (LPCVOID) oAb_, 2, - (LPCVOID) oAb_, 2 -}; - -static JMPTAB o9b_[] = -{ - (LPCVOID) o9b0, F, - (LPCVOID) o9b1, F, - (LPCVOID) o9b2, F, - (LPCVOID) o9b3, F, - (LPCVOID) o9b4, F, - (LPCVOID) o9b5, F, - (LPCVOID) o9b6, F, - (LPCVOID) o9b7, F, - (LPCVOID) o9b8, F, - (LPCVOID) o9b9, F, - (LPCVOID) o9bA, F, - (LPCVOID) o9bB, F, - (LPCVOID) o9bC, F, - (LPCVOID) o9bD, F, - (LPCVOID) o9bE, F, - (LPCVOID) o9bF, F -}; - -static JMPTAB o9a_[] = -{ - (LPCVOID) o9a0, F, - (LPCVOID) o9a1, F, - (LPCVOID) o9a2, F, - (LPCVOID) o9a3, F, - (LPCVOID) o9a4, F, - (LPCVOID) o9a5, F, - (LPCVOID) o9a6, F, - (LPCVOID) o9a7, F, - (LPCVOID) o9a8, F, - (LPCVOID) o9a9, F, - (LPCVOID) o9aA, F, - (LPCVOID) o9aB, F, - (LPCVOID) o9aC, F, - (LPCVOID) o9aD, F, - (LPCVOID) o9aE, F, - (LPCVOID) o9aF, F -}; - -static JMPTAB o9_[] = -{ - (LPCVOID) o9a_, 2, - (LPCVOID) o9a_, 2, - (LPCVOID) o9a_, 2, - (LPCVOID) o9a_, 2, - (LPCVOID) o9a_, 2, - (LPCVOID) o9a_, 2, - (LPCVOID) o9a_, 2, - (LPCVOID) o9a_, 2, - (LPCVOID) o9b_, 2, - (LPCVOID) o9b_, 2, - (LPCVOID) o9b_, 2, - (LPCVOID) o9b_, 2, - (LPCVOID) o9b_, 2, - (LPCVOID) o9b_, 2, - (LPCVOID) o9b_, 2, - (LPCVOID) o9b_, 2 -}; - -static JMPTAB o8B_[] = -{ - (LPCVOID) o8B0, F, - (LPCVOID) o8B1, F, - (LPCVOID) o8B2, F, - (LPCVOID) o8B3, F, - (LPCVOID) o8B4, F, - (LPCVOID) o8B5, F, - (LPCVOID) o8B6, F, - (LPCVOID) o8B7, F, - (LPCVOID) o8B8, F, - (LPCVOID) o8B9, F, - (LPCVOID) o8BA, F, - (LPCVOID) o8BB, F, - (LPCVOID) o8BC, F, - (LPCVOID) o8BD, F, - (LPCVOID) o8BE, F, - (LPCVOID) o8BF, F -}; - -static JMPTAB o8A_[] = -{ - (LPCVOID) o8A0, F, - (LPCVOID) o8A1, F, - (LPCVOID) o8A2, F, - (LPCVOID) o8A3, F, - (LPCVOID) o8A4, F, - (LPCVOID) o8A5, F, - (LPCVOID) o8A6, F, - (LPCVOID) o8A7, F, - (LPCVOID) o8A8, F, - (LPCVOID) o8A9, F, - (LPCVOID) o8AA, F, - (LPCVOID) o8AB, F, - (LPCVOID) o8AC, F, - (LPCVOID) o8AD, F, - (LPCVOID) o8AE, F, - (LPCVOID) o8AF, F -}; - -static JMPTAB o81B_[] = -{ - (LPCVOID) o_invalid4, F, - (LPCVOID) o_invalid4, F, - (LPCVOID) o81B2, F, - (LPCVOID) o81B3, F, - (LPCVOID) o81B4, F, - (LPCVOID) o81B5, F, - (LPCVOID) o81B6, F, - (LPCVOID) o81B7, F, - (LPCVOID) o_invalid4, F, - (LPCVOID) o_invalid4, F, - (LPCVOID) o_invalid4, F, - (LPCVOID) o_invalid4, F, - (LPCVOID) o_invalid4, F, - (LPCVOID) o_invalid4, F, - (LPCVOID) o_invalid4, F, - (LPCVOID) o_invalid4, F -}; - -static JMPTAB o81Af2_[] = -{ - (LPCVOID) o81Af20, F, - (LPCVOID) o81Af21, F, - (LPCVOID) o81Af22, F, - (LPCVOID) o81Af23, F, - (LPCVOID) o81Af24, F, - (LPCVOID) o81Af21, F, - (LPCVOID) o81Af22, F, - (LPCVOID) o81Af23, F, - (LPCVOID) o81Af28, F, - (LPCVOID) o81Af29, F, - (LPCVOID) o81Af2A, F, - (LPCVOID) o81Af2B, F, - (LPCVOID) o81Af2C, F, - (LPCVOID) o81Af29, F, - (LPCVOID) o81Af2A, F, - (LPCVOID) o81Af2B, F -}; - -static JMPTAB o81Af1_[] = -{ - (LPCVOID) o81Af10, F, - (LPCVOID) o81Af11, F, - (LPCVOID) o81Af12, F, - (LPCVOID) o81Af13, F, - (LPCVOID) o81Af14, F, - (LPCVOID) o81Af11, F, - (LPCVOID) o81Af12, F, - (LPCVOID) o81Af13, F, - (LPCVOID) o81Af18, F, - (LPCVOID) o81Af19, F, - (LPCVOID) o81Af1A, F, - (LPCVOID) o81Af1B, F, - (LPCVOID) o81Af1C, F, - (LPCVOID) o81Af19, F, - (LPCVOID) o81Af1A, F, - (LPCVOID) o81Af1B, F -}; - -static JMPTAB o81Af0_[] = -{ - (LPCVOID) o81Af00, F, - (LPCVOID) o81Af01, F, - (LPCVOID) o81Af02, F, - (LPCVOID) o81Af03, F, - (LPCVOID) o81Af04, F, - (LPCVOID) o81Af01, F, - (LPCVOID) o81Af02, F, - (LPCVOID) o81Af03, F, - (LPCVOID) o81Af08, F, - (LPCVOID) o81Af09, F, - (LPCVOID) o81Af0A, F, - (LPCVOID) o81Af0B, F, - (LPCVOID) o81Af0C, F, - (LPCVOID) o81Af09, F, - (LPCVOID) o81Af0A, F, - (LPCVOID) o81Af0B, F -}; - -static JMPTAB o81A_[] = -{ - (LPCVOID) o81Af0_, 5, - (LPCVOID) o81Af1_, 5, - (LPCVOID) o81Af2_, 5, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F -}; - -static JMPTAB o819_[] = -{ - (LPCVOID) o819f0, F, - (LPCVOID) o819f1, F, - (LPCVOID) o819f2, F, - (LPCVOID) o819f3, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F -}; - -static JMPTAB o818_[] = -{ - (LPCVOID) o818f0x, F, - (LPCVOID) o818f1x, F, - (LPCVOID) o818f2x, F, - (LPCVOID) o818f3x, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o818f8x, F, - (LPCVOID) o818f9x, F, - (LPCVOID) o818fAx, F, - (LPCVOID) o818fBx, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F, - (LPCVOID) o_invalid6, F -}; - -static JMPTAB o81_[] = -{ - (LPCVOID) o810, F, - (LPCVOID) o811, F, - (LPCVOID) o812, F, - (LPCVOID) o813, F, - (LPCVOID) o814, F, - (LPCVOID) o815, F, - (LPCVOID) o816, F, - (LPCVOID) o817, F, - (LPCVOID) o818_, 4, - (LPCVOID) o819_, 4, - (LPCVOID) o81A_, 4, - (LPCVOID) o81B_, 3, - (LPCVOID) o81C, F, - (LPCVOID) o81D, F, - (LPCVOID) o81E, F, - (LPCVOID) o81F, F -}; - -static JMPTAB o8081_[] = -{ - (LPCVOID) o80810, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F, - (LPCVOID) o_invalid5, F -}; - -static JMPTAB o808_[] = -{ - (LPCVOID) o8080, F, - (LPCVOID) o8081_, 4, - (LPCVOID) o8082X, F, - (LPCVOID) o8083, F, - (LPCVOID) o8084n, F, - (LPCVOID) o8085n, F, - (LPCVOID) o8086n, F, - (LPCVOID) o8087n, F, - (LPCVOID) o8088n, F, - (LPCVOID) o8089n, F, - (LPCVOID) o808An, F, - (LPCVOID) o808Bn, F, - (LPCVOID) o808C, F, - (LPCVOID) o808D, F, - (LPCVOID) o808E, F, - (LPCVOID) o808F, F -}; - -static JMPTAB o80_[] = -{ - (LPCVOID) o800, F, - (LPCVOID) o801, F, - (LPCVOID) o802, F, - (LPCVOID) o803, F, - (LPCVOID) o804, F, - (LPCVOID) o805, F, - (LPCVOID) o806, F, - (LPCVOID) o807, F, - (LPCVOID) o808_, 3, - (LPCVOID) o809, F, - (LPCVOID) o80A, F, - (LPCVOID) o80B, F, - (LPCVOID) o80Cn, F, - (LPCVOID) o80Dn, F, - (LPCVOID) o80E, F, - (LPCVOID) o80Fn, F -}; - -static JMPTAB o8_[] = -{ - (LPCVOID) o80_, 2, - (LPCVOID) o81_, 2, - (LPCVOID) o82n, F, - (LPCVOID) o83n, F, - (LPCVOID) o84n, F, - (LPCVOID) o85n, F, - (LPCVOID) o86n, F, - (LPCVOID) o87n, F, - (LPCVOID) o88n, F, - (LPCVOID) o89n, F, - (LPCVOID) o8A_, 2, - (LPCVOID) o8B_, 2, - (LPCVOID) o8Cd4, F, - (LPCVOID) o8Dd5, F, - (LPCVOID) o8Ed4, F, - (LPCVOID) o8Fd5, F -}; - -static JMPTAB o15_[] = -{ - (LPCVOID) o150a, F, - (LPCVOID) o151a, F, - (LPCVOID) o152a, F, - (LPCVOID) o153a, F, - (LPCVOID) o154a, F, - (LPCVOID) o155a, F, - (LPCVOID) o156a, F, - (LPCVOID) o157a, F, - (LPCVOID) o158x, F, - (LPCVOID) o159x, F, - (LPCVOID) o15Ax, F, - (LPCVOID) o15Bx, F, - (LPCVOID) o15Cx, F, - (LPCVOID) o15Dx, F, - (LPCVOID) o15Ex, F, - (LPCVOID) o15Fx, F -}; - -static JMPTAB o14_[] = -{ - (LPCVOID) o140, F, - (LPCVOID) o141, F, - (LPCVOID) o142, F, - (LPCVOID) o143, F, - (LPCVOID) o144, F, - (LPCVOID) o145, F, - (LPCVOID) o146, F, - (LPCVOID) o147, F, - (LPCVOID) o148, F, - (LPCVOID) o149, F, - (LPCVOID) o14A, F, - (LPCVOID) o14B, F, - (LPCVOID) o14C, F, - (LPCVOID) o14D, F, - (LPCVOID) o14E, F, - (LPCVOID) o14F, F -}; - -static JMPTAB o13_[] = -{ - (LPCVOID) o130, F, - (LPCVOID) o131, F, - (LPCVOID) o132, F, - (LPCVOID) o133, F, - (LPCVOID) o134, F, - (LPCVOID) o135, F, - (LPCVOID) o136, F, - (LPCVOID) o137, F, - (LPCVOID) o138, F, - (LPCVOID) o139, F, - (LPCVOID) o13A, F, - (LPCVOID) o13B, F, - (LPCVOID) o13C, F, - (LPCVOID) o13D, F, - (LPCVOID) o13E, F, - (LPCVOID) o13F, F -}; - -static JMPTAB o12_[] = -{ - (LPCVOID) o120, F, - (LPCVOID) o121, F, - (LPCVOID) o122, F, - (LPCVOID) o123, F, - (LPCVOID) o124, F, - (LPCVOID) o121, F, - (LPCVOID) o122, F, - (LPCVOID) o123, F, - (LPCVOID) o128, F, - (LPCVOID) o129, F, - (LPCVOID) o12A, F, - (LPCVOID) o12B, F, - (LPCVOID) o12C, F, - (LPCVOID) o129, F, - (LPCVOID) o12A, F, - (LPCVOID) o12B, F -}; - -static JMPTAB o11_[] = -{ - (LPCVOID) o110, F, - (LPCVOID) o111, F, - (LPCVOID) o112, F, - (LPCVOID) o113, F, - (LPCVOID) o114, F, - (LPCVOID) o111, F, - (LPCVOID) o112, F, - (LPCVOID) o113, F, - (LPCVOID) o118, F, - (LPCVOID) o119, F, - (LPCVOID) o11A, F, - (LPCVOID) o11B, F, - (LPCVOID) o11C, F, - (LPCVOID) o119, F, - (LPCVOID) o11A, F, - (LPCVOID) o11B, F -}; - -static JMPTAB o10_[] = -{ - (LPCVOID) o100, F, - (LPCVOID) o101, F, - (LPCVOID) o102, F, - (LPCVOID) o103, F, - (LPCVOID) o104, F, - (LPCVOID) o101, F, - (LPCVOID) o102, F, - (LPCVOID) o103, F, - (LPCVOID) o108, F, - (LPCVOID) o109, F, - (LPCVOID) o10A, F, - (LPCVOID) o10B, F, - (LPCVOID) o10C, F, - (LPCVOID) o109, F, - (LPCVOID) o10A, F, - (LPCVOID) o10B, F -}; - -static JMPTAB o1_[] = -{ - (LPCVOID) o10_, 2, - (LPCVOID) o11_, 2, - (LPCVOID) o12_, 2, - (LPCVOID) o13_, 2, - (LPCVOID) o14_, 2, - (LPCVOID) o15_, 2, - (LPCVOID) o16x, F, - (LPCVOID) o17x, F, - (LPCVOID) o18x, F, - (LPCVOID) o19d2, F, - (LPCVOID) o1Ad4, F, - (LPCVOID) o1Bd5, F, - (LPCVOID) o1Cx, F, - (LPCVOID) o1Dd2, F, - (LPCVOID) o1Ed4, F, - (LPCVOID) o1Fd5, F -}; - -static JMPTAB o0E_[] = -{ - (LPCVOID) o0Ef0, F, - (LPCVOID) o0Ef1, F, - (LPCVOID) o0Ef2, F, - (LPCVOID) o0Ef3, F, - (LPCVOID) o0Ef4, F, - (LPCVOID) o0Ef5, F, - (LPCVOID) o0Ef6, F, - (LPCVOID) o0Ef7, F, - (LPCVOID) o0Ef8, F, - (LPCVOID) o0Ef9, F, - (LPCVOID) o0EfA, F, - (LPCVOID) o0EfB, F, - (LPCVOID) o0EfC, F, - (LPCVOID) o0EfD, F, - (LPCVOID) o0EfE, F, - (LPCVOID) o0EfF, F -}; - -static JMPTAB o0_[] = -{ - (LPCVOID) o00, F, - (LPCVOID) o01, F, - (LPCVOID) o02, F, - (LPCVOID) o03, F, - (LPCVOID) o04, F, - (LPCVOID) o05, F, - (LPCVOID) o06, F, - (LPCVOID) o07, F, - (LPCVOID) o08, F, - (LPCVOID) o09, F, - (LPCVOID) o0A, F, - (LPCVOID) o0B, F, - (LPCVOID) o0C, F, - (LPCVOID) o0D, F, - (LPCVOID) o0E_, 3, - (LPCVOID) o0F, F -}; - -static JMPTAB o_[] = -{ - (LPCVOID) o0_, 1, - (LPCVOID) o1_, 1, - (LPCVOID) o2n, F, - (LPCVOID) o3X, F, - (LPCVOID) o4d2, F, - (LPCVOID) o5d2, F, - (LPCVOID) o6d3, F, - (LPCVOID) o7d3, F, - (LPCVOID) o8_, 1, - (LPCVOID) o9_, 1, - (LPCVOID) oA_, 1, - (LPCVOID) oB_, 1, - (LPCVOID) oC_, 1, - (LPCVOID) oD_, 1, - (LPCVOID) oE_, 1, - (LPCVOID) oF_, 1 -}; - -// opcode dispatcher -VOID EvalOpcode(LPBYTE I) -{ - DWORD dwIndex = 0; - PJMPTAB pJmpTab = o_; - - do - { - _ASSERT(I[dwIndex] <= 0xf); // found packed data - pJmpTab = &pJmpTab[I[dwIndex]]; // table entry by opcode - dwIndex = pJmpTab->dwTyp; // next pointer type - pJmpTab = (PJMPTAB) pJmpTab->pLnk; // next pointer to table/function - } - while (dwIndex != F); // reference to table? -> again - - ((VOID (*)(LPBYTE)) pJmpTab)(I); // call function - return; -} diff --git a/Sources/GCCPatch/EMU48GCC.RC b/Sources/GCCPatch/EMU48GCC.RC index 8f5933f..da021d5 100644 --- a/Sources/GCCPatch/EMU48GCC.RC +++ b/Sources/GCCPatch/EMU48GCC.RC @@ -303,7 +303,7 @@ FONT 8, "MS Sans Serif" BEGIN ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP - LTEXT "Copyright © 2023 Christoph Gießelink && Sébastien Carlier", + LTEXT "Copyright © 2024 Christoph Gießelink && Sébastien Carlier", IDC_STATIC,29,18,181,8 DEFPUSHBUTTON "OK",IDOK,215,12,39,14 EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL | @@ -752,8 +752,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,6,6,0 - PRODUCTVERSION 1,6,6,0 + FILEVERSION 1,6,7,0 + PRODUCTVERSION 1,6,7,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -770,12 +770,12 @@ BEGIN BEGIN VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0" VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0" - VALUE "FileVersion", "1, 6, 6, 0\0" + VALUE "FileVersion", "1, 6, 7, 0\0" VALUE "InternalName", "Emu48\0" - VALUE "LegalCopyright", "Copyright © 2023\0" + VALUE "LegalCopyright", "Copyright © 2024\0" VALUE "OriginalFilename", "Emu48.exe\0" VALUE "ProductName", "Emu48\0" - VALUE "ProductVersion", "1, 6, 6, 0\0" + VALUE "ProductVersion", "1, 6, 7, 0\0" END END BLOCK "VarFileInfo" diff --git a/Sources/GCCPatch/pch.h b/Sources/GCCPatch/PCH.H similarity index 95% rename from Sources/GCCPatch/pch.h rename to Sources/GCCPatch/PCH.H index 9607328..10a2d1f 100644 --- a/Sources/GCCPatch/pch.h +++ b/Sources/GCCPatch/PCH.H @@ -1,63 +1,63 @@ -// -// PCH.H (MinGW version) -// - -#define _WIN32_IE 0x0200 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// #include // missing file - -#if !defined IDC_HAND // Win2k specific definition -#define IDC_HAND MAKEINTRESOURCE(32649) -#endif - -#define __unaligned - -// normally defined in STDLIB.H -#if !defined __max - #define __max(a,b) (((a) > (b)) ? (a) : (b)) -#endif -#if !defined __min - #define __min(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -// normally defined in missing CRTDBG.H -#if !defined _ASSERT - #define _ASSERT(a) -#endif -#define _CrtSetDbgFlag(f) - -#if !defined VERIFY -#if defined _DEBUG -#define VERIFY(f) _ASSERT(f) -#else // _DEBUG -#define VERIFY(f) ((VOID)(f)) -#endif // _DEBUG -#endif // VERIFY - -#if !defined PROCESS_POWER_THROTTLING_CURRENT_VERSION -#define PROCESS_POWER_THROTTLING_CURRENT_VERSION 1 -#endif - -#if !defined PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION -#define PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION 0x04 -#endif - -enum { ProcessPowerThrottling = 4 }; - -typedef struct _PROCESS_POWER_THROTTLING_STATE { - ULONG Version; - ULONG ControlMask; - ULONG StateMask; -} PROCESS_POWER_THROTTLING_STATE, * PPROCESS_POWER_THROTTLING_STATE; +// +// PCH.H (MinGW version) +// + +#define _WIN32_IE 0x0200 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include // missing file + +#if !defined IDC_HAND // Win2k specific definition +#define IDC_HAND MAKEINTRESOURCE(32649) +#endif + +#define __unaligned + +// normally defined in STDLIB.H +#if !defined __max + #define __max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#if !defined __min + #define __min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +// normally defined in missing CRTDBG.H +#if !defined _ASSERT + #define _ASSERT(a) +#endif +#define _CrtSetDbgFlag(f) + +#if !defined VERIFY +#if defined _DEBUG +#define VERIFY(f) _ASSERT(f) +#else // _DEBUG +#define VERIFY(f) ((VOID)(f)) +#endif // _DEBUG +#endif // VERIFY + +#if !defined PROCESS_POWER_THROTTLING_CURRENT_VERSION +#define PROCESS_POWER_THROTTLING_CURRENT_VERSION 1 +#endif + +#if !defined PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION +#define PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION 0x04 +#endif + +enum { ProcessPowerThrottling = 4 }; + +typedef struct _PROCESS_POWER_THROTTLING_STATE { + ULONG Version; + ULONG ControlMask; + ULONG StateMask; +} PROCESS_POWER_THROTTLING_STATE, * PPROCESS_POWER_THROTTLING_STATE; diff --git a/Sources/GCCPatch/README.TXT b/Sources/GCCPatch/README.TXT index c9a1c94..bb69847 100644 --- a/Sources/GCCPatch/README.TXT +++ b/Sources/GCCPatch/README.TXT @@ -67,4 +67,4 @@ Many thanks to Pedro A. Arranda Guti compatible. -04/18/23 (c) by Christoph Gießelink +09/23/24 (c) by Christoph Gießelink diff --git a/Sources/MkShared/mkshared.c b/Sources/MkShared/MKSHARED.C similarity index 96% rename from Sources/MkShared/mkshared.c rename to Sources/MkShared/MKSHARED.C index fb3dd43..5383c4c 100644 --- a/Sources/MkShared/mkshared.c +++ b/Sources/MkShared/MKSHARED.C @@ -1,266 +1,266 @@ -/* - * MkShared, (c) 2006 Christoph Giesselink (c.giesselink@gmx.de) - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. - */ - -#define WIN32_LEAN_AND_MEAN -#define WIN32_EXTRA_LEAN -#include -#include -#include -#include -#include -#include "resource.h" - -#if _MSC_VER >= 1400 // valid for VS2005 and later -#if defined _M_IX86 -#pragma comment(linker,"/manifestdependency:\" \ - type='win32' \ - name='Microsoft.Windows.Common-Controls' \ - version='6.0.0.0' processorArchitecture='x86' \ - publicKeyToken='6595b64144ccf1df' \ - language='*'\"") -#elif defined _M_IA64 -#pragma comment(linker,"/manifestdependency:\" \ - type='win32' \ - name='Microsoft.Windows.Common-Controls' \ - version='6.0.0.0' processorArchitecture='ia64' \ - publicKeyToken='6595b64144ccf1df' \ - language='*'\"") -#elif defined _M_X64 -#pragma comment(linker,"/manifestdependency:\" \ - type='win32' \ - name='Microsoft.Windows.Common-Controls' \ - version='6.0.0.0' processorArchitecture='amd64' \ - publicKeyToken='6595b64144ccf1df' \ - language='*'\"") -#else -#pragma comment(linker,"/manifestdependency:\" \ - type='win32' \ - name='Microsoft.Windows.Common-Controls' \ - version='6.0.0.0' processorArchitecture='*' \ - publicKeyToken='6595b64144ccf1df' \ - language='*'\"") -#endif -#endif - -#define _KB(n) (2*(n)*1024) - -#define ARRAYSIZEOF(a) (sizeof(a) / sizeof(a[0])) - -#define DEFAULTFILE "SHARED.BIN" - -typedef enum -{ - STATE_UNKOWN, - STATE_GOOD, - STATE_FAIL -} CheckState; - -static HBRUSH hBrushGreen; -static HBRUSH hBrushRed; - -static CheckState eState = STATE_UNKOWN; - -static VOID SetInformation(HWND hWnd,LPCTSTR strSize,LPCTSTR strNoOfPorts,LPCTSTR strPorts) -{ - SetDlgItemText(hWnd,IDC_FILE_SIZE,strSize); - SetDlgItemText(hWnd,IDC_NO_OF_PORTS,strNoOfPorts); - SetDlgItemText(hWnd,IDC_PORT_NO,strPorts); - eState = STATE_UNKOWN; - SetDlgItemText(hWnd,IDC_RESULT,_T("")); - InvalidateRect(GetDlgItem(hWnd,IDC_RESULT),NULL,TRUE); - return; -} - -static BOOL WriteCardFile(LPCTSTR strFilename,INT nBlocks) -{ - HANDLE hFile = CreateFile(strFilename,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL); - if (hFile != INVALID_HANDLE_VALUE) - { - DWORD dwWritten; - - LPBYTE pbyBuffer = (LPBYTE) calloc(1,_KB(1)); - - while (nBlocks--) WriteFile(hFile, pbyBuffer, _KB(1), &dwWritten, NULL); - - free(pbyBuffer); - - CloseHandle(hFile); - return FALSE; - } - return TRUE; -} - -static LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) -{ - static WORD wSize; - - TCHAR szFilename[MAX_PATH]; - HCURSOR hCursor; - - switch (iMsg) - { - case WM_INITDIALOG: - // filename - SetDlgItemText(hWnd,IDC_FILENAME,_T(DEFAULTFILE)); - - // set to 32kb - SendDlgItemMessage(hWnd,IDC_CARD32,BM_SETCHECK,1,0); - PostMessage(hWnd,WM_COMMAND,IDC_CARD32,0); - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDC_CARD32: - wSize = 32; - SetInformation(hWnd,_T("64kb"),_T("1"),_T("2")); - return 0; - case IDC_CARD128: - wSize = 128; - SetInformation(hWnd,_T("256kb"),_T("1"),_T("2")); - return 0; - case IDC_CARD256: - wSize = 256; - SetInformation(hWnd,_T("512kb"),_T("2"),_T("2,3")); - return 0; - case IDC_CARD512: - wSize = 512; - SetInformation(hWnd,_T("1mb"),_T("4"),_T("2 through 5")); - return 0; - case IDC_CARD1024: - wSize = 1024; - SetInformation(hWnd,_T("2mb"),_T("8"),_T("2 through 9")); - return 0; - case IDC_CARD2048: - wSize = 2048; - SetInformation(hWnd,_T("4mb"),_T("16"),_T("2 through 17")); - return 0; - case IDC_CARD4096: - wSize = 4096; - SetInformation(hWnd,_T("8mb"),_T("32"),_T("2 through 33")); - return 0; - case IDOK: - GetDlgItemText(hWnd,IDC_FILENAME,szFilename,ARRAYSIZEOF(szFilename)); - hCursor = SetCursor(LoadCursor(NULL,IDC_WAIT)); - - // create file - if (WriteCardFile(szFilename,wSize)) - { - eState = STATE_FAIL; - SetDlgItemText(hWnd,IDC_RESULT,_T("Fail!")); - } - else - { - eState = STATE_GOOD; - SetDlgItemText(hWnd,IDC_RESULT,_T("Done!")); - } - InvalidateRect(GetDlgItem(hWnd,IDC_RESULT),NULL,TRUE); - SetCursor(hCursor); // restore cursor - return 0; - } - return 0; - case WM_CTLCOLORSTATIC: - if (GetDlgCtrlID((HWND) lParam) == IDC_RESULT) - { - switch (eState) - { - case STATE_GOOD: - SetTextColor((HDC) wParam,(COLORREF) 0xFFFFFF); // white - SetBkMode((HDC) wParam,TRANSPARENT); - return (LRESULT) hBrushGreen; - case STATE_FAIL: - SetTextColor((HDC) wParam,(COLORREF) 0xFFFFFF); // white - SetBkMode((HDC) wParam,TRANSPARENT); - return (LRESULT) hBrushRed; - } - } - break; // default handler for all other windows - case WM_DESTROY: - PostQuitMessage(0); - return 0; - } - - return DefWindowProc(hWnd,iMsg,wParam,lParam); -} - -INT WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPSTR lpszCmdLine,INT nCmdShow) -{ - HWND hWnd; - MSG msg; - WNDCLASS wc; -// RECT rc; - HFONT hFont; - - InitCommonControls(); - - // create background brushes - hBrushGreen = CreateSolidBrush(0x008000); - hBrushRed = CreateSolidBrush(0x0000FF); - - wc.style = CS_HREDRAW | CS_VREDRAW; - wc.lpfnWndProc = WndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = DLGWINDOWEXTRA; - wc.hInstance = hInst; - wc.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_MKSHARED)); - wc.hCursor = LoadCursor(NULL,IDC_ARROW); - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - wc.lpszMenuName = NULL; - wc.lpszClassName = _T("CMkShared"); - RegisterClass(&wc); - - hWnd = CreateDialog(hInst,MAKEINTRESOURCE(IDD_MAIN),0,(DLGPROC) WndProc); - _ASSERT(hWnd); - -#if 0 - // center window - GetWindowRect(hWnd, &rc); - SetWindowPos(hWnd, HWND_TOP, - ((GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2), - ((GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 2), - 0, 0, SWP_NOSIZE | SWP_NOACTIVATE); -#endif - - // initialization - hFont = CreateFont(20,0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, - OUT_DEVICE_PRECIS,CLIP_DEFAULT_PRECIS, - PROOF_QUALITY,DEFAULT_PITCH|TMPF_TRUETYPE|FF_ROMAN, - _T("Times New Roman")); - _ASSERT(hFont); - SendDlgItemMessage(hWnd,IDC_STATIC_TITLE,WM_SETFONT,(WPARAM)hFont,MAKELPARAM(TRUE,0)); - SendDlgItemMessage(hWnd,IDC_RESULT,WM_SETFONT,(WPARAM)hFont,MAKELPARAM(TRUE,0)); - - while(GetMessage(&msg,NULL,0,0)) - { - if(!IsDialogMessage(hWnd,&msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - DeleteObject(hFont); - DeleteObject(hBrushGreen); - DeleteObject(hBrushRed); - - return msg.wParam; - UNREFERENCED_PARAMETER(hPrev); - UNREFERENCED_PARAMETER(lpszCmdLine); - UNREFERENCED_PARAMETER(nCmdShow); -} +/* + * MkShared, (c) 2006 Christoph Giesselink (c.giesselink@gmx.de) + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#define WIN32_LEAN_AND_MEAN +#define WIN32_EXTRA_LEAN +#include +#include +#include +#include +#include +#include "resource.h" + +#if _MSC_VER >= 1400 // valid for VS2005 and later +#if defined _M_IX86 +#pragma comment(linker,"/manifestdependency:\" \ + type='win32' \ + name='Microsoft.Windows.Common-Controls' \ + version='6.0.0.0' processorArchitecture='x86' \ + publicKeyToken='6595b64144ccf1df' \ + language='*'\"") +#elif defined _M_IA64 +#pragma comment(linker,"/manifestdependency:\" \ + type='win32' \ + name='Microsoft.Windows.Common-Controls' \ + version='6.0.0.0' processorArchitecture='ia64' \ + publicKeyToken='6595b64144ccf1df' \ + language='*'\"") +#elif defined _M_X64 +#pragma comment(linker,"/manifestdependency:\" \ + type='win32' \ + name='Microsoft.Windows.Common-Controls' \ + version='6.0.0.0' processorArchitecture='amd64' \ + publicKeyToken='6595b64144ccf1df' \ + language='*'\"") +#else +#pragma comment(linker,"/manifestdependency:\" \ + type='win32' \ + name='Microsoft.Windows.Common-Controls' \ + version='6.0.0.0' processorArchitecture='*' \ + publicKeyToken='6595b64144ccf1df' \ + language='*'\"") +#endif +#endif + +#define _KB(n) (2*(n)*1024) + +#define ARRAYSIZEOF(a) (sizeof(a) / sizeof(a[0])) + +#define DEFAULTFILE "SHARED.BIN" + +typedef enum +{ + STATE_UNKOWN, + STATE_GOOD, + STATE_FAIL +} CheckState; + +static HBRUSH hBrushGreen; +static HBRUSH hBrushRed; + +static CheckState eState = STATE_UNKOWN; + +static VOID SetInformation(HWND hWnd,LPCTSTR strSize,LPCTSTR strNoOfPorts,LPCTSTR strPorts) +{ + SetDlgItemText(hWnd,IDC_FILE_SIZE,strSize); + SetDlgItemText(hWnd,IDC_NO_OF_PORTS,strNoOfPorts); + SetDlgItemText(hWnd,IDC_PORT_NO,strPorts); + eState = STATE_UNKOWN; + SetDlgItemText(hWnd,IDC_RESULT,_T("")); + InvalidateRect(GetDlgItem(hWnd,IDC_RESULT),NULL,TRUE); + return; +} + +static BOOL WriteCardFile(LPCTSTR strFilename,INT nBlocks) +{ + HANDLE hFile = CreateFile(strFilename,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD dwWritten; + + LPBYTE pbyBuffer = (LPBYTE) calloc(1,_KB(1)); + + while (nBlocks--) WriteFile(hFile, pbyBuffer, _KB(1), &dwWritten, NULL); + + free(pbyBuffer); + + CloseHandle(hFile); + return FALSE; + } + return TRUE; +} + +static LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + static WORD wSize; + + TCHAR szFilename[MAX_PATH]; + HCURSOR hCursor; + + switch (iMsg) + { + case WM_INITDIALOG: + // filename + SetDlgItemText(hWnd,IDC_FILENAME,_T(DEFAULTFILE)); + + // set to 32kb + SendDlgItemMessage(hWnd,IDC_CARD32,BM_SETCHECK,1,0); + PostMessage(hWnd,WM_COMMAND,IDC_CARD32,0); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CARD32: + wSize = 32; + SetInformation(hWnd,_T("64kb"),_T("1"),_T("2")); + return 0; + case IDC_CARD128: + wSize = 128; + SetInformation(hWnd,_T("256kb"),_T("1"),_T("2")); + return 0; + case IDC_CARD256: + wSize = 256; + SetInformation(hWnd,_T("512kb"),_T("2"),_T("2,3")); + return 0; + case IDC_CARD512: + wSize = 512; + SetInformation(hWnd,_T("1mb"),_T("4"),_T("2 through 5")); + return 0; + case IDC_CARD1024: + wSize = 1024; + SetInformation(hWnd,_T("2mb"),_T("8"),_T("2 through 9")); + return 0; + case IDC_CARD2048: + wSize = 2048; + SetInformation(hWnd,_T("4mb"),_T("16"),_T("2 through 17")); + return 0; + case IDC_CARD4096: + wSize = 4096; + SetInformation(hWnd,_T("8mb"),_T("32"),_T("2 through 33")); + return 0; + case IDOK: + GetDlgItemText(hWnd,IDC_FILENAME,szFilename,ARRAYSIZEOF(szFilename)); + hCursor = SetCursor(LoadCursor(NULL,IDC_WAIT)); + + // create file + if (WriteCardFile(szFilename,wSize)) + { + eState = STATE_FAIL; + SetDlgItemText(hWnd,IDC_RESULT,_T("Fail!")); + } + else + { + eState = STATE_GOOD; + SetDlgItemText(hWnd,IDC_RESULT,_T("Done!")); + } + InvalidateRect(GetDlgItem(hWnd,IDC_RESULT),NULL,TRUE); + SetCursor(hCursor); // restore cursor + return 0; + } + return 0; + case WM_CTLCOLORSTATIC: + if (GetDlgCtrlID((HWND) lParam) == IDC_RESULT) + { + switch (eState) + { + case STATE_GOOD: + SetTextColor((HDC) wParam,(COLORREF) 0xFFFFFF); // white + SetBkMode((HDC) wParam,TRANSPARENT); + return (LRESULT) hBrushGreen; + case STATE_FAIL: + SetTextColor((HDC) wParam,(COLORREF) 0xFFFFFF); // white + SetBkMode((HDC) wParam,TRANSPARENT); + return (LRESULT) hBrushRed; + } + } + break; // default handler for all other windows + case WM_DESTROY: + PostQuitMessage(0); + return 0; + } + + return DefWindowProc(hWnd,iMsg,wParam,lParam); +} + +INT WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPSTR lpszCmdLine,INT nCmdShow) +{ + HWND hWnd; + MSG msg; + WNDCLASS wc; +// RECT rc; + HFONT hFont; + + InitCommonControls(); + + // create background brushes + hBrushGreen = CreateSolidBrush(0x008000); + hBrushRed = CreateSolidBrush(0x0000FF); + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = DLGWINDOWEXTRA; + wc.hInstance = hInst; + wc.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_MKSHARED)); + wc.hCursor = LoadCursor(NULL,IDC_ARROW); + wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); + wc.lpszMenuName = NULL; + wc.lpszClassName = _T("CMkShared"); + RegisterClass(&wc); + + hWnd = CreateDialog(hInst,MAKEINTRESOURCE(IDD_MAIN),0,(DLGPROC) WndProc); + _ASSERT(hWnd); + +#if 0 + // center window + GetWindowRect(hWnd, &rc); + SetWindowPos(hWnd, HWND_TOP, + ((GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2), + ((GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 2), + 0, 0, SWP_NOSIZE | SWP_NOACTIVATE); +#endif + + // initialization + hFont = CreateFont(20,0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, + OUT_DEVICE_PRECIS,CLIP_DEFAULT_PRECIS, + PROOF_QUALITY,DEFAULT_PITCH|TMPF_TRUETYPE|FF_ROMAN, + _T("Times New Roman")); + _ASSERT(hFont); + SendDlgItemMessage(hWnd,IDC_STATIC_TITLE,WM_SETFONT,(WPARAM)hFont,MAKELPARAM(TRUE,0)); + SendDlgItemMessage(hWnd,IDC_RESULT,WM_SETFONT,(WPARAM)hFont,MAKELPARAM(TRUE,0)); + + while(GetMessage(&msg,NULL,0,0)) + { + if(!IsDialogMessage(hWnd,&msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + DeleteObject(hFont); + DeleteObject(hBrushGreen); + DeleteObject(hBrushRed); + + return msg.wParam; + UNREFERENCED_PARAMETER(hPrev); + UNREFERENCED_PARAMETER(lpszCmdLine); + UNREFERENCED_PARAMETER(nCmdShow); +} diff --git a/Sources/MkShared/resource.h b/Sources/MkShared/RESOURCE.H similarity index 97% rename from Sources/MkShared/resource.h rename to Sources/MkShared/RESOURCE.H index fa5ac5f..67e1767 100644 --- a/Sources/MkShared/resource.h +++ b/Sources/MkShared/RESOURCE.H @@ -1,32 +1,32 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by MKSHARED.RC -// -#define IDD_MAIN 100 -#define IDI_MKSHARED 101 -#define IDC_CARD32 1000 -#define IDC_CARD128 1001 -#define IDC_CARD256 1002 -#define IDC_CARD512 1003 -#define IDC_CARD1024 1004 -#define IDC_CARD2048 1005 -#define IDC_CARD4096 1006 -#define IDC_STATIC_TITLE 1007 -#define IDC_FILENAME 1008 -#define IDC_FILE_SIZE 1009 -#define IDC_NO_OF_PORTS 1010 -#define IDC_PORT_NO 1011 -#define IDC_RESULT 1012 -#define IDC_STATIC -1 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1013 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by MKSHARED.RC +// +#define IDD_MAIN 100 +#define IDI_MKSHARED 101 +#define IDC_CARD32 1000 +#define IDC_CARD128 1001 +#define IDC_CARD256 1002 +#define IDC_CARD512 1003 +#define IDC_CARD1024 1004 +#define IDC_CARD2048 1005 +#define IDC_CARD4096 1006 +#define IDC_STATIC_TITLE 1007 +#define IDC_FILENAME 1008 +#define IDC_FILE_SIZE 1009 +#define IDC_NO_OF_PORTS 1010 +#define IDC_PORT_NO 1011 +#define IDC_RESULT 1012 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1013 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Sources/Mke48/mke48.c b/Sources/Mke48/MKE48.C similarity index 96% rename from Sources/Mke48/mke48.c rename to Sources/Mke48/MKE48.C index 2941a9c..dcb6f89 100644 --- a/Sources/Mke48/mke48.c +++ b/Sources/Mke48/MKE48.C @@ -1,120 +1,120 @@ -/* - * T48G, (c) 2000 Christoph Giesselink (cgiess@swol.de) - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. - */ - -#define WIN32_LEAN_AND_MEAN -#define WIN32_EXTRA_LEAN -#include -#include -#include -#include -#include -#include "types.h" - -#define VERSION "1.0" - -#define _KB(n) (n*1024*2) // KB emulator block - -#define HP48SIG "Emu48 Document\xFE" // HP49 state file signature - -VOID MakeTemplate(FILE *hFile,BYTE type,DWORD Port0Size,DWORD Port1Size) -{ - CHIPSET Chipset; - DWORD dwBytesWritten; - UINT nVar; - BYTE byZ; - - // file signature - WriteFile(hFile,HP48SIG,sizeof(HP48SIG),&dwBytesWritten,NULL); - assert(dwBytesWritten == sizeof(HP48SIG)); - - // KML filename length - nVar = 0; // no name - WriteFile(hFile,&nVar,sizeof(nVar),&dwBytesWritten,NULL); - assert(dwBytesWritten == sizeof(nVar)); - - // KML filename - - // Chipset Size - nVar = sizeof(Chipset); // length, no name - WriteFile(hFile,&nVar,sizeof(nVar),&dwBytesWritten,NULL); - assert(dwBytesWritten == sizeof(nVar)); - - // Chipset - ZeroMemory(&Chipset,sizeof(Chipset)); - Chipset.type = type; - Chipset.Port0Size = Port0Size; - Chipset.Port1Size = Port1Size; - Chipset.Port2Size = 0; - Chipset.cards_status = 0x0; - - WriteFile(hFile,&Chipset,sizeof(Chipset),&dwBytesWritten,NULL); - assert(dwBytesWritten == sizeof(Chipset)); - - byZ = 0; // fill with zero nibble - - // write port0 memory content - for (nVar = 0; nVar < _KB(Chipset.Port0Size); ++nVar) - { - WriteFile(hFile,&byZ,1,&dwBytesWritten,NULL); - assert(dwBytesWritten == 1); - } - - // write port1 memory content - for (nVar = 0; nVar < _KB(Chipset.Port1Size); ++nVar) - { - WriteFile(hFile,&byZ,1,&dwBytesWritten,NULL); - assert(dwBytesWritten == 1); - } - return; -} - -UINT main(int argc, char *argv[]) -{ - HANDLE hFile; - - BYTE type; - DWORD Port0Size; - DWORD Port1Size; - - printf("HP48 State File Template for Emu48 V" VERSION "\n"); - if (argc != 5 || (*argv[2] != 'S' && *argv[2] != 'G')) - { - printf("\nUsage:\n\t%s \n\n", argv[0]); - return 1; - } - - type = *argv[2]; - Port0Size = atoi(argv[3]); - Port1Size = atoi(argv[4]); - - hFile = CreateFile(argv[1],GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL); - if (hFile != INVALID_HANDLE_VALUE) - { - // write template - MakeTemplate(hFile,type,Port0Size,Port1Size); - puts("Generation successful."); - CloseHandle(hFile); - } - else - { - printf("Cannot open file %s.\n", argv[1]); - return TRUE; - } - return FALSE; -} +/* + * T48G, (c) 2000 Christoph Giesselink (cgiess@swol.de) + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#define WIN32_LEAN_AND_MEAN +#define WIN32_EXTRA_LEAN +#include +#include +#include +#include +#include +#include "types.h" + +#define VERSION "1.0" + +#define _KB(n) (n*1024*2) // KB emulator block + +#define HP48SIG "Emu48 Document\xFE" // HP49 state file signature + +VOID MakeTemplate(FILE *hFile,BYTE type,DWORD Port0Size,DWORD Port1Size) +{ + CHIPSET Chipset; + DWORD dwBytesWritten; + UINT nVar; + BYTE byZ; + + // file signature + WriteFile(hFile,HP48SIG,sizeof(HP48SIG),&dwBytesWritten,NULL); + assert(dwBytesWritten == sizeof(HP48SIG)); + + // KML filename length + nVar = 0; // no name + WriteFile(hFile,&nVar,sizeof(nVar),&dwBytesWritten,NULL); + assert(dwBytesWritten == sizeof(nVar)); + + // KML filename + + // Chipset Size + nVar = sizeof(Chipset); // length, no name + WriteFile(hFile,&nVar,sizeof(nVar),&dwBytesWritten,NULL); + assert(dwBytesWritten == sizeof(nVar)); + + // Chipset + ZeroMemory(&Chipset,sizeof(Chipset)); + Chipset.type = type; + Chipset.Port0Size = Port0Size; + Chipset.Port1Size = Port1Size; + Chipset.Port2Size = 0; + Chipset.cards_status = 0x0; + + WriteFile(hFile,&Chipset,sizeof(Chipset),&dwBytesWritten,NULL); + assert(dwBytesWritten == sizeof(Chipset)); + + byZ = 0; // fill with zero nibble + + // write port0 memory content + for (nVar = 0; nVar < _KB(Chipset.Port0Size); ++nVar) + { + WriteFile(hFile,&byZ,1,&dwBytesWritten,NULL); + assert(dwBytesWritten == 1); + } + + // write port1 memory content + for (nVar = 0; nVar < _KB(Chipset.Port1Size); ++nVar) + { + WriteFile(hFile,&byZ,1,&dwBytesWritten,NULL); + assert(dwBytesWritten == 1); + } + return; +} + +UINT main(int argc, char *argv[]) +{ + HANDLE hFile; + + BYTE type; + DWORD Port0Size; + DWORD Port1Size; + + printf("HP48 State File Template for Emu48 V" VERSION "\n"); + if (argc != 5 || (*argv[2] != 'S' && *argv[2] != 'G')) + { + printf("\nUsage:\n\t%s \n\n", argv[0]); + return 1; + } + + type = *argv[2]; + Port0Size = atoi(argv[3]); + Port1Size = atoi(argv[4]); + + hFile = CreateFile(argv[1],GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + // write template + MakeTemplate(hFile,type,Port0Size,Port1Size); + puts("Generation successful."); + CloseHandle(hFile); + } + else + { + printf("Cannot open file %s.\n", argv[1]); + return TRUE; + } + return FALSE; +} diff --git a/Sources/Mke48/types.h b/Sources/Mke48/TYPES.H similarity index 96% rename from Sources/Mke48/types.h rename to Sources/Mke48/TYPES.H index c14d725..456c1aa 100644 --- a/Sources/Mke48/types.h +++ b/Sources/Mke48/TYPES.H @@ -1,103 +1,103 @@ -/* - * types.h - * - * This file is part of Emu48 - * - * Copyright (C) 1995 Sebastien Carlier - * - */ - -// HST bits -#define XM 1 -#define SB 2 -#define SR 4 -#define MP 8 - -#define SWORD SHORT // signed 16 Bit variable -#define QWORD ULONGLONG // unsigned 64 Bit variable - -#define CHIPSET Chipset_t -typedef struct -{ - SWORD nPosX; // position of window - SWORD nPosY; - BYTE type; // calculator type - - DWORD Port0Size; // real size of module in KB - DWORD Port1Size; // real size of module in KB - DWORD Port2Size; // real size of module in KB (HP49G only) - LPBYTE Port0; - LPBYTE Port1; - LPBYTE Port2; - - DWORD pc; - DWORD d0; - DWORD d1; - DWORD rstkp; - DWORD rstk[8]; - BYTE A[16]; - BYTE B[16]; - BYTE C[16]; - BYTE D[16]; - BYTE R0[16]; - BYTE R1[16]; - BYTE R2[16]; - BYTE R3[16]; - BYTE R4[16]; - BYTE ST[4]; - BYTE HST; - BYTE P; - WORD out; - WORD in; - BOOL SoftInt; - BOOL Shutdn; - BOOL mode_dec; - BOOL inte; // interrupt status flag (FALSE = int in service) - BOOL intk; // 1 ms keyboard scan flag (TRUE = enable) - BOOL intd; // keyboard interrupt pending (TRUE = int pending) - BOOL carry; - - WORD crc; - WORD wPort2Crc; // fingerprint of port2 - WORD wRomCrc; // fingerprint of ROM -#if defined _USRDLL // DLL version - QWORD cycles; // oscillator cycles -#else // EXE version - DWORD cycles; // oscillator cycles - DWORD cycles_reserved; // reserved for MSB of oscillator cycles -#endif - DWORD dwKdnCycles; // cpu cycles at start of 1ms key handler - - UINT Bank_FF; // save state of HP48GX port2 or state of HP49G ROM FF - UINT FlashRomState; // WSM state of flash memory (unused) - BYTE cards_status; - BYTE IORam[64]; // I/O hardware register - UINT IOBase; // address of I/O modules page - BOOL IOCfig; // I/O module configuration flag - BYTE P0Base, BSBase, P1Base, P2Base; // address of modules first 2KB page - BYTE P0Size, BSSize, P1Size, P2Size; // mapped size of module in 2KB - BYTE P0End, BSEnd, P1End, P2End; // address of modules last 2KB page - BOOL P0Cfig, BSCfig, P1Cfig, P2Cfig; // module address configuration flag - BOOL P0Cfg2, BSCfg2, P1Cfg2, P2Cfg2; // module size configuration flag - - BYTE t1; - DWORD t2; - - BOOL bShutdnWake; // flag for wake up from SHUTDN mode - - BYTE Keyboard_Row[9]; - WORD IR15X; - UINT Keyboard_State; // not used - - signed short loffset; - signed int width; - UINT boffset; - UINT lcounter; - UINT sync; // not used - BYTE contrast; - BOOL dispon; - DWORD start1; - DWORD start12; - DWORD end1; - DWORD start2, end2; -} Chipset_t; +/* + * types.h + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ + +// HST bits +#define XM 1 +#define SB 2 +#define SR 4 +#define MP 8 + +#define SWORD SHORT // signed 16 Bit variable +#define QWORD ULONGLONG // unsigned 64 Bit variable + +#define CHIPSET Chipset_t +typedef struct +{ + SWORD nPosX; // position of window + SWORD nPosY; + BYTE type; // calculator type + + DWORD Port0Size; // real size of module in KB + DWORD Port1Size; // real size of module in KB + DWORD Port2Size; // real size of module in KB (HP49G only) + LPBYTE Port0; + LPBYTE Port1; + LPBYTE Port2; + + DWORD pc; + DWORD d0; + DWORD d1; + DWORD rstkp; + DWORD rstk[8]; + BYTE A[16]; + BYTE B[16]; + BYTE C[16]; + BYTE D[16]; + BYTE R0[16]; + BYTE R1[16]; + BYTE R2[16]; + BYTE R3[16]; + BYTE R4[16]; + BYTE ST[4]; + BYTE HST; + BYTE P; + WORD out; + WORD in; + BOOL SoftInt; + BOOL Shutdn; + BOOL mode_dec; + BOOL inte; // interrupt status flag (FALSE = int in service) + BOOL intk; // 1 ms keyboard scan flag (TRUE = enable) + BOOL intd; // keyboard interrupt pending (TRUE = int pending) + BOOL carry; + + WORD crc; + WORD wPort2Crc; // fingerprint of port2 + WORD wRomCrc; // fingerprint of ROM +#if defined _USRDLL // DLL version + QWORD cycles; // oscillator cycles +#else // EXE version + DWORD cycles; // oscillator cycles + DWORD cycles_reserved; // reserved for MSB of oscillator cycles +#endif + DWORD dwKdnCycles; // cpu cycles at start of 1ms key handler + + UINT Bank_FF; // save state of HP48GX port2 or state of HP49G ROM FF + UINT FlashRomState; // WSM state of flash memory (unused) + BYTE cards_status; + BYTE IORam[64]; // I/O hardware register + UINT IOBase; // address of I/O modules page + BOOL IOCfig; // I/O module configuration flag + BYTE P0Base, BSBase, P1Base, P2Base; // address of modules first 2KB page + BYTE P0Size, BSSize, P1Size, P2Size; // mapped size of module in 2KB + BYTE P0End, BSEnd, P1End, P2End; // address of modules last 2KB page + BOOL P0Cfig, BSCfig, P1Cfig, P2Cfig; // module address configuration flag + BOOL P0Cfg2, BSCfg2, P1Cfg2, P2Cfg2; // module size configuration flag + + BYTE t1; + DWORD t2; + + BOOL bShutdnWake; // flag for wake up from SHUTDN mode + + BYTE Keyboard_Row[9]; + WORD IR15X; + UINT Keyboard_State; // not used + + signed short loffset; + signed int width; + UINT boffset; + UINT lcounter; + UINT sync; // not used + BYTE contrast; + BOOL dispon; + DWORD start1; + DWORD start12; + DWORD end1; + DWORD start2, end2; +} Chipset_t; diff --git a/uninst.exe b/uninst.exe index 6bebbff5e92c9a32c47bd3bd819e3df467bfd8af..68a95c042bf6999886333a8005b2748cf6a7a24b 100755 GIT binary patch delta 66 zcmZqaVrl7O*)Z=ACp!Zh10w?i1N-LXhg=yM%_qM-Yz-tej|4KBOs+m+3uNy+;tnJk TkJ>YuZ+1Mo-<~DtP_-%m%^McJ delta 66 zcmZqaVrl7O*)Z=ACmRDB10w?i1KZ~1hg=yM%_hG+Yz-tej|4IrPp&><3uNy+;tnJk TkJ>YuZFW4m-=2m4<`xG4%iR{<