From 27520054a1210a2aa6dd30a1061d7382d97f27de Mon Sep 17 00:00:00 2001 From: Gwenhael Le Moine Date: Tue, 19 Mar 2024 23:35:30 +0100 Subject: [PATCH] 2012-09-15: Updated to version 1.53 Signed-off-by: Gwenhael Le Moine --- DEBUGGER.TXT | 12 +- EMU48.EXE | Bin 294912 -> 0 bytes Emu48.exe | Bin 0 -> 278528 bytes KML_20.DOC | 169 ++++++---- PROBLEMS.TXT | 8 +- Sources/Emu48/CHANGES.TXT | 359 +++++++++++++++++++++ Sources/Emu48/DDESERV.C | 14 +- Sources/Emu48/DEBUGGER.C | 562 ++++++++++++++++++++------------- Sources/Emu48/DEBUGGER.H | 6 +- Sources/Emu48/DISASM.C | 104 +------ Sources/Emu48/DISMEM.C | 221 +++++++++++++ Sources/Emu48/DISPLAY.C | 10 +- Sources/Emu48/DISRPL.C | 66 ++-- Sources/Emu48/DISRPL.H | 1 + Sources/Emu48/EMU48.C | 586 +++++++++++++++++++++++------------ Sources/Emu48/EMU48.DSP | 51 +-- Sources/Emu48/EMU48.H | 51 ++- Sources/Emu48/EMU48.RC | 213 +++++++++---- Sources/Emu48/ENGINE.C | 42 +-- Sources/Emu48/EXTERNAL.C | 4 +- Sources/Emu48/FETCH.C | 2 +- Sources/Emu48/FILES.C | 338 +++++++++++++------- Sources/Emu48/I28F160.C | 69 ++++- Sources/Emu48/IO.H | 4 + Sources/Emu48/KEYMACRO.C | 30 +- Sources/Emu48/KML.C | 111 ++++--- Sources/Emu48/MOPS.C | 65 +++- Sources/Emu48/MRU.C | 22 +- Sources/Emu48/OPCODES.C | 4 +- Sources/Emu48/OPS.H | 4 +- Sources/Emu48/PCH.H | 2 + Sources/Emu48/REDEYE.C | 177 +++++++++++ Sources/Emu48/RESOURCE.H | 216 +++++++------ Sources/Emu48/RPL.C | 4 +- Sources/Emu48/SERIAL.C | 8 +- Sources/Emu48/SETTINGS.C | 19 +- Sources/Emu48/STACK.C | 21 +- Sources/Emu48/SYMBFILE.C | 6 +- Sources/Emu48/TIMER.C | 16 +- Sources/Emu48/UDP.C | 85 +++++ Sources/GCCPatch/EMU48GCC.RC | 230 +++++++++----- Sources/GCCPatch/Makefile | 17 +- Sources/GCCPatch/PCH.H | 1 + Sources/GCCPatch/README.TXT | 18 +- uninst.exe | Bin 62313 -> 63324 bytes 45 files changed, 2792 insertions(+), 1156 deletions(-) delete mode 100755 EMU48.EXE create mode 100755 Emu48.exe create mode 100644 Sources/Emu48/DISMEM.C create mode 100644 Sources/Emu48/REDEYE.C create mode 100644 Sources/Emu48/UDP.C diff --git a/DEBUGGER.TXT b/DEBUGGER.TXT index d09e7b2..f48cdf9 100644 --- a/DEBUGGER.TXT +++ b/DEBUGGER.TXT @@ -301,9 +301,17 @@ CE1 | nc. | BS | Slt1 32/128KB | BS | BS CE2 | nc. | nc. | Slt2 32/128KB | Slt1 32/128KB | RAM 128KB 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. + +- 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. + - RPL Object Viewer... -This opens a small toolbox window showing the decompiled RPL object at the memory address marked by the cursor. If the toolbox window is already open the content will be updated. There's a problem if you want to select an address inside the marked two addresses. The easiest way to switch the address is the use of the + and - keys changing the memory position by one nibble under the cursor. +This opens a small toolbox window showing the decompiled RPL object in the selected memory map mode at the memory address marked by the cursor. If the toolbox window is already open the content will be updated. There's a problem if you want to select an address inside the marked two addresses. The easiest way to switch the address is the use of the + and - keys changing the memory position by one nibble under the cursor. 9.) Stack window @@ -346,4 +354,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. -04/04/09 (c) by Christoph Gießelink +05/02/12 (c) by Christoph Gießelink diff --git a/EMU48.EXE b/EMU48.EXE deleted file mode 100755 index fc3fab83f0a48b644e81b3f453c592727e7e394b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 294912 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%0DwHids&RQH)Bdg&LY4Mj3fC@@WE* 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

`z}Vs05crJN6ova-R6gnMFNf|C4AY( zKEIc)Y?RlskBjx7RIOYdo){e;&K4_$>T;>FdU^P*`Riw=hO)aW=E)9hNkS||oVwLV=hJSv67LbzTBU++v! zdVos4jP$kg`uQoJ6K>X!6O}6GUPsOtt6VMyg?gzLLh3gK^wL-|OCV~+3K%ME0-pQ; zM{~kyFS;*~LQ_Yl3@l>kq~2;!mZ-weD(bz+JExG#S2T5=O@meFBDcLmRGu}UCUQi*Ym4T z=JyjNR455jg?lv==ZYpTjhUu^MLWb*tScRS?HAlUp1s3yycb+!oc2!}Ejw2l@m$1t zMpqYcp3P60#4OC+AnuLulp|N`@pyZ(V`gLNtL^m`EvT_~GDnhCSlU@9M{k~&8UvqP o8&>`4z+SU!l8<;@viA$1w?>X~k2G+kfg=qZY2Zi${|_4Y4`K!>{r~^~ diff --git a/Emu48.exe b/Emu48.exe new file mode 100755 index 0000000000000000000000000000000000000000..2547bddebedd118d2e432fc516ed1932e1750625 GIT binary patch literal 278528 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

|={ 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 z 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 K\cell 1\cell 2\cell 3\cell +\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 \clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx1179\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx2389\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx3598\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx4808\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx6018\pard\intbl\nowidctlpar\cf1\b0\fs20 7 2\cell 3 2\cell 2 2\cell 1 2\cell 0 2\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 -\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx1179\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx2389\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx3598\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx4808\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx6018\pard\intbl\nowidctlpar\cf2\b\fs24 ON\cell 0\cell .\cell SPC\cell ENTER\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 -\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx1179\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx2389\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx3598\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx4808\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx6018\pard\intbl\nowidctlpar\cf1\b0\fs20 0 32768\cell 3 1\cell 2 1\cell 1 1\cell 0 1\cell\row\pard\nowidctlpar\cf0\b\f0\fs28\page Scancode\b0\fs24\par +\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx1179\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx2389\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx3598\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx4808\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx6018\pard\intbl\nowidctlpar\cf2\b\fs24 ON\cell\lang1036 0\cell .\cell SPC\cell ENTER\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx1179\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx2389\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx3598\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx4808\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx6018\pard\intbl\nowidctlpar\cf1\b0\fs20 0 32768\cell 3 1\cell 2 1\cell 1 1\cell 0 1\cell\row\pard\nowidctlpar\cf0\f0\fs24\par +\pard\nowidctlpar\qj\b\fs28 OutIn Codes HP71B\par +\pard\nowidctlpar\b0\fs24\par +\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx849\cellx1698\cellx2549\cellx3399\cellx4250\cellx5100\cellx5951\cellx6801\cellx7653\cellx8505\pard\intbl\nowidctlpar\cf2\lang1033\b\f2 Key\cell\b0\cell\cell\cell\cell\cell\cell\cell\cell\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx849\cellx1698\cellx2549\cellx3399\cellx4250\cellx5100\cellx5951\cellx6801\cellx7653\cellx8505\pard\intbl\nowidctlpar\cf1\b\fs20 OutIn\cell\b0\cell\cell\cell\cell\cell\cell\cell\cell\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\cellx849\cellx1698\cellx2549\cellx3399\cellx4250\cellx5100\cellx5951\cellx6801\cellx7653\cellx8505\pard\intbl\nowidctlpar\b\fs16\cell\b0\cell\cell\cell\cell\cell\cell\cell\cell\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx849\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx1698\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx2549\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx3399\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx4250\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx5100\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx5951\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx6801\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx7653\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx8505\pard\intbl\nowidctlpar\cf2\b\fs24 Q\cell\lang1040 W\cell E\cell R\cell\lang1036 T\cell Y\cell U\cell\lang1040 I\cell O\cell P\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx849\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx1698\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx2549\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx3399\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx4250\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx5100\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx5951\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx6801\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx7653\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx8505\pard\intbl\nowidctlpar\cf1\lang1033\b0\fs20 3 1\cell 3 2\cell 3 4\cell 3 8\cell 3 16\cell 3 32\cell 3 64\cell 3 128\cell 3 256\cell 3 512\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx849\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx1698\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx2549\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx3399\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx4250\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx5100\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx5951\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx6801\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx7653\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx8505\pard\intbl\nowidctlpar\cf2\b\fs24 A\cell S\cell D\cell F\cell G\cell H\cell\lang1031 J\cell K\cell L\cell =\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx849\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx1698\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx2549\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx3399\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx4250\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx5100\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx5951\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx6801\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx7653\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx8505\pard\intbl\nowidctlpar\cf1\b0\fs20 2 1\cell 2 2\cell 2 4\cell 2 8\cell 2 16\cell 2 32\cell 2 64\cell 2 128\cell 2 256\cell 2 512\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx849\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx1698\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx2549\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx3399\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx4250\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx5100\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx5951\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx6801\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx7653\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx8505\pard\intbl\nowidctlpar\cf2\b\fs24 Z\cell X\cell C\cell\lang1033 V\cell B\cell N\cell M\cell (\cell )\cell END\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx849\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx1698\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx2549\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx3399\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx4250\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx5100\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx5951\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx6801\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx7653\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx8505\pard\intbl\nowidctlpar\cf1\b0\fs20 1 1\cell 1 2\cell 1 4\cell 1 8\cell 1 16\cell 1 32\cell 1 64\cell 1 128\cell 1 256\cell\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx849\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx1698\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx2549\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx3399\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx4250\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx5100\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx5951\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx6801\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx7653\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx8505\pard\intbl\nowidctlpar\cf2\b\fs24 ON\cell F\cell G\cell RUN\cell <\cell >\cell SPC\cell\f3\'d9\f2\cell\f3\'da\f2\cell LINE\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx849\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx1698\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx2549\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx3399\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx4250\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx5100\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx5951\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx6801\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx7653\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx8505\pard\intbl\nowidctlpar\cf1\b0\fs20 0 32769\cell 0 2\cell 0 4\cell 0 8\cell 0 16\cell 0 32\cell 0 64\cell 0 128\cell 0 256\cell 1 512\cell\row\pard\nowidctlpar\cf0\b\f0\fs28\par +\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx851\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx1701\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx2552\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx3402\pard\intbl\nowidctlpar\cf2\f2\fs24 7\cell 8\cell 9\cell /\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx851\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx1701\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx2552\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx3402\pard\intbl\nowidctlpar\cf1\b0\fs20 3 1024\cell 3 2048\cell 3 4096\cell 3 8192\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx851\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx1701\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx2552\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx3402\pard\intbl\nowidctlpar\cf2\b\fs24 4\cell 5\cell 6\cell *\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx851\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx1701\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx2552\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx3402\pard\intbl\nowidctlpar\cf1\b0\fs20 2 1024\cell 2 2048\cell 2 4096\cell 2 8192\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx851\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx1701\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx2552\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx3402\pard\intbl\nowidctlpar\cf2\b\fs24 1\cell 2\cell 3\cell -\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx851\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx1701\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx2552\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx3402\pard\intbl\nowidctlpar\cf1\b0\fs20 1 1024\cell 1 2048\cell 1 4096\cell 1 8192\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx851\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx1701\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx2552\clbrdrl\brdrw30\brdrs\clbrdrt\brdrw30\brdrs\clbrdrr\brdrw30\brdrs \cellx3402\pard\intbl\nowidctlpar\cf2\b\fs24 0\cell .\cell ,\cell +\cell\row\trowd\trgaph30\trleft-30\trpaddl30\trpaddr30\trpaddfl3\trpaddfr3 +\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx851\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx1701\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx2552\clbrdrl\brdrw30\brdrs\clbrdrr\brdrw30\brdrs\clbrdrb\brdrw30\brdrs \cellx3402\pard\intbl\nowidctlpar\cf1\b0\fs20 0 1024\cell 0 2048\cell 0 4096\cell 0 8192\cell\row\pard\nowidctlpar\cf0\b\f0\fs28\par +\page Scancode\b0\fs24\par \par \pard\nowidctlpar\qj\tab The Scancode defines what the emulator will do when a certain key on the keyboard is pressed. Pressing a key that has no scancode defined will (only if debug mode is on) display a message box with the key's scancode number, so that you can write a Scancode block. The commands in the Scancode block are executed twice, first when the key is pressed and a second time when the key is released. Flags can help to transfer information (for example can be set to show that a shift key is pressed) from one Scancode block to another. Valid flags are 0-31.\par \pard\nowidctlpar\par @@ -703,16 +735,16 @@ or\par \tab\tab \par \tab End\par Or\par -\tab\lang1031 IfMem INTEGER INTEGER INTEGER\par -\tab\tab\lang1033 \par +\tab IfMem INTEGER INTEGER INTEGER\par +\tab\tab \par \tab Else\par \tab\tab \par \tab End\par or\par -\tab\lang1031 SetFlag INTEGER\par +\tab SetFlag INTEGER\par or\par \tab ResetFlag INTEGER\par -\lang1033 or\par +or\par \tab NotFlag INTEGER\par or\par \tab IfFlag INTEGER\par @@ -772,31 +804,32 @@ Example:\par \par \page MenuItem will open a menu (only if it\rquote s supported). The following values are accepted:\par \par -\pard\nowidctlpar\fi720\cf1\f1\fs16 FILE_NEW 1\par -FILE_OPEN 2\par -FILE_SAVE 3\par -FILE_SAVEAS 4\par -FILE_EXIT 5\par -EDIT_COPY_SCREEN 6\par -FILE_SETTINGS 7\par -EDIT_RESET 8\par -EDIT_LOAD_OBJECT 9\par -EDIT_SAVE_OBJECT 10\par -HELP_ABOUT 11\par -HELP_TOPICS 12\par -FILE_CLOSE 13\par -EDIT_BACKUP_SAVE 14\par -EDIT_BACKUP_RESTORE 15\par -EDIT_BACKUP_DELETE 16\par -VIEW_SCRIPT 17\par -EDIT_COPY_STRING 19\par -EDIT_PASTE_STRING 20\par -TOOL_DISASM 21\par -TOOL_DEBUG 22\par -TOOL_MACRO_RECORD 23\par -TOOL_MACRO_PLAY 24\par -TOOL_MACRO_STOP 25\par -TOOL_MACRO_SETTINGS 26\par +\pard\nowidctlpar\fi720\cf1\f1\fs16 FILE_NEW 1\par +FILE_OPEN 2\par +FILE_SAVE 3\par +FILE_SAVEAS 4\par +FILE_EXIT 5\par +EDIT_COPY_SCREEN 6\par +FILE_SETTINGS 7\par +EDIT_RESET 8\par +EDIT_LOAD_OBJECT 9\par +EDIT_SAVE_OBJECT 10\par +HELP_ABOUT 11\par +HELP_TOPICS 12\par +FILE_CLOSE 13\par +EDIT_BACKUP_SAVE 14\par +EDIT_BACKUP_RESTORE 15\par +EDIT_BACKUP_DELETE 16\par +VIEW_SCRIPT 17\par +EDIT_PORT_CONFIGURATION 18\par +EDIT_COPY_STRING 19\par +EDIT_PASTE_STRING 20\par +TOOL_DISASM 21\par +TOOL_DEBUG 22\par +TOOL_MACRO_RECORD 23\par +TOOL_MACRO_PLAY 24\par +TOOL_MACRO_STOP 25\par +TOOL_MACRO_SETTINGS 26\par \pard\nowidctlpar\f0\fs24\par \cf0\b\fs28\page Conclusion\par \b0\fs24\par @@ -814,6 +847,6 @@ The latest updates are available at:\par http://hp.giesselink.com/\par \pard\nowidctlpar\par \par -Release 14: September 9th, 2009\par +Release 16: May 18th, 2012\par } \ No newline at end of file diff --git a/PROBLEMS.TXT b/PROBLEMS.TXT index b8a2f51..22c63b7 100644 --- a/PROBLEMS.TXT +++ b/PROBLEMS.TXT @@ -1,4 +1,4 @@ -Known bugs and restrictions of Emu48 V1.50 +Known bugs and restrictions of Emu48 V1.53 ------------------------------------------ - the following I/O bits aren't emulated (incomplete) @@ -12,8 +12,7 @@ Known bugs and restrictions of Emu48 V1.50 SRQ1 (0x118) [ISQR] SRQ2 (0x119) [LSRQ] IRC (0x11A) [IRI EIRU EIRI IRE] - LCR (0x11C) [LED ELBE LBZ LBF] - LBR (0x11D) [LBO] + LCR (0x11C) [LBZ LBF] - the baudrates 1920, 3840, 7680 and 15360 aren't emulated on most operating systems Windows 95a 1920, 3840, 7680 work, 15360 fail @@ -41,7 +40,6 @@ Known bugs and restrictions of Emu48 V1.50 - no beeper support with OUT command -> all programs that aren't use the "=makebeep" subroutine, like alarm wake up, have no sound - beeper emulation, ATTN key doesn't work -- no infrared printer support - Shell OS: clock isn't synchronized with real time - HP49G: the flash memory is emulated now with some restrictions - no flash programming times, the flash state machine returns @@ -52,4 +50,4 @@ Known bugs and restrictions of Emu48 V1.50 - quitting the emulator while programming the flash isn't allowed, because the content of flash state machine isn't saved so far -07/27/10 (c) by Christoph Gießelink, c dot giesselink at gmx dot de +08/07/12 (c) by Christoph Gießelink, c dot giesselink at gmx dot de diff --git a/Sources/Emu48/CHANGES.TXT b/Sources/Emu48/CHANGES.TXT index 7a5bfe0..483d458 100644 --- a/Sources/Emu48/CHANGES.TXT +++ b/Sources/Emu48/CHANGES.TXT @@ -1,3 +1,362 @@ +Service Pack 53 for Emu48 Version 1.0 + +DEBUGGER.C +- removed structure MODEL_MAP_T, variables pbyNoMEM, MemMap[], + pbyMapData, dwMapDataSize and pMapping, the implementation behind + moved to module DISMEM.C +- changed function SetMappingMenu(), changed to DISMEM.C + implementation and added control of memory data menu items +- changed function GetMemCurAddr(), OnMemGoAdr(), OnKeyUpDown() and + OnKeyPlusMinus(), variable dwMapDataSize isn't global any more, + use function GetMemDataMask() instead +- changed function InitMemMap(), ViewMemWnd() and OnFindOK(), + changed to DISMEM.C implementation +- changed function ViewCodeWnd(), set disassembler to memory mapped + mode +- bugfix in function OnDblClick(), fixed buffer overflow when + converting a 2 byte hexadecimal string to a byte and added an + update of code window +- changed function Debugger(), changed disassembler mode setting and + added initialization of RPL object viewer get nibble function in + WM_INITDIALOG message and added calls of "Load Memory Data..." and + "Save Memory Data..." handling functions +- bugfix in function UpdateRplObjViewWnd(), show entry point names + only in mapped mode and end address for RPL object viewer depend + on the actual memory mapping mode and with the design change to + the DISMEM.C implementation in all debugger and disassembler + related parts, the RPL object viewer also works in all memory + mapping modes properly now +- added functions OnBrowseLoadMem(), OnBrowseSaveMem(), + LoadMemData(), SaveMemData(), GetAddr(), DebugMemLoad(), + OnMemLoadData(), DebugMemSave() and OnMemSaveData() to handle the + Load/Save Memory Data feature + +DISASM.C +- removed global variable disassembler_map +- removed functions rn_map(), rn_rom(), rn_ram(), rn_port1() and + rn_port2() +- changed function read_nibble(), call function GetMemNib() from the + new module DISMEM.C for mapping mode memory access and made + function static again + +DISMEM.C +- new module for accessing memory data for debug view purpose + +DISPLAY.C +- changed function GetLineCounterGray() to static + +DISRPL.C +- the get nibble function is not hard referenced as read_nibble() + call any more, it's now called over RplReadNibble() function + pointer +- changed function PrintTail(), expanded to handle 6 digit addresses + +DISRPL.H +- added extern declaration of RplReadNibble() function pointer + +EMU48.C +- changed function Disasm(), replaced the radio button + implementation for the memory mapping mode by a combo box + solution; the combo box solution don't work with the HP48 module + names any more, it now use the memory controller names used in the + debugger memory viewer for a more general approach for the non + HP48 calculator models +- changed function WinMain(), added more flexible CPU binding for + the Saturn core emulation thread on Windows NT4.0 and later + +EMU48.DSP +- added dismem.c sources + +EMU48.H +- replaced old "memory module definitions" by the enum MEM_MAPPING +- extern declaration of global functions +- removed extern declaration of global variables + +EMU48.RC +- changed IDD_DISASM dialog, replaced the radio buttons for the + memory mapping mode by a more general combo box +- added dialogs IDD_DEBUG_MEMSAVE and IDD_DEBUG_MEMLOAD +- added "Load Memory Data..." and "Save Memory Data..." menu entries + in debugger "Memory" context menu +- changed version + +KML.C +- bugfix in function ReloadButtons(), ON key button wasn't handled + +RESOURCE.H +- added several definitions +- deleted some radio button definitions from the IDD_DISASM dialog + +TIMER.C +- changed function SetHP48Time(), time calculation now work properly + for host system dates before 1970/01/01 and after 2106/02/07 + + +Service Pack 52 for Emu48 Version 1.0 + +DEBUGGER.C +- changed function ViewMemWnd(), removed initialized but unused + variable + +DISPLAY.C +- changed DIBPIXEL4() and DIBPIXEL3() define, generates the same + code on MSVC6.0 but made it GCC4 compiler compatible + +DISRPL.C +- changed function RplCreateObjView(), defined end pointer also as + constant + +EMU48.C +- added property sheet page handlers SettingsGeneralProc(), + SettingsMemoryProc() and SettingsPeripheralProc() +- removed function SettingsProc(), replaced by the property sheet + page handler functions +- bugfix in function OnDropFiles(), changed function prototype to + the correct structure type of dropped file names and initialized + the bSuccess variable for the case the wNumFiles variable is 0 +- added function PropSheetProc(), callback function for setup the + property sheet +- changed function OnViewSettings(), now creating a propery sheet + instead of a settings dialog +- changed function MainWndProc(), made correct type cast to argument + of function OnDropFiles() +- changed function WinMain(), replaced multiple class name usage + with atom variable, moved read settings before window creation, + and added check for setting "SingleInstance" to switch to an + already running program instance instead of creating a new one + +EMU48.H +- extern declaration of global variable and function + +EMU48.RC +- split IDD_SETTINGS dialog into the property pages IDD_SET_GENERAL, + IDD_SET_MEMORY and IDD_SET_PERIPHERAL and added item + "Single Instance" in the "General" property page +- removed IDD_SETTINGS dialog +- changed version and copyright + +FILES.C +- bugfix in function DecodeBmp() and DecodeGif(), a 2nd bitmap load + allocated and bound a 2nd palette to the main window, now only the + 1st bitmap (mostly the KML background bitmap) bound his palette to + the main window + +KML.C +- changed table pLexToken[], defined table as constant and changed + last token id table preset from constant number to member of token + id enumerator +- bugfix in function ParseString(), decoding the \" sequence as + quotation mark inside a string was incomplete, so every single '\' + character was also removed + +MRU.C +- changed function MruUpdateMenu(), changed variable type of + variable hMenu +- changed function MruReadList(), removed initialized but unused + variable + +RESOURCE.H +- removed IDD_SETTINGS definition +- added some definitions + +SETTINGS.C +- changed function ReadSettings(), moved CPU speed setting to + MainWndProc() +- changed function ReadSettings() and WriteSettings(), added item + "SingleInstance" in section [Emulator] in the INI-File + +UDP.C +- added function ResetUdp(), reset UDP address +- bugfix in function SendByteUdp(), fixed memory leak at error + condition and optimized IP address decoding + + +Service Pack 51 for Emu48 Version 1.0 + +DDESERV.C +- replaced all HeapAlloc() with malloc() memory requests + +DEBUGGER.C +- replaced all HeapAlloc() with malloc() memory requests +- changed function ToggleBreakpoint() and EditBreakpoint(), minor + code optimization purging breakpoint +- changed function Debugger(), removed all UpdateWindowStatus() + function calls +- bugfix in function LoadBreakpointList(), added check of breakpoint + entries against breakpoint table size + +DISRPL.C +- replaced all HeapAlloc() with malloc() memory requests +- bugfix in function BCDx(), fixed possible uninitialized bExpflag + variable +- bugfix in function DoRrp(), fixed possible uninitialized bErr + variable + +EMU48.C +- removed global variable hHeap +- replaced all HeapAlloc() with malloc() memory requests +- changed function SettingsProc(), added infrared printer settings +- changed function SaveChanges(), detect if document is available + now over the variable bDocumentAvail and not over the variable + pbyRom any more; in the case of an illegal KML script there maybe + a document loaded, but no ROM image, so pbyRom will be NULL in + this case +- renamed function UpdateWindowStatus() to OnInitMenu() and modified + it to a WM_INITMENU message handler +- changed function OnFileNew() and WinMain(), removed all + UpdateWindowStatus() function calls +- bugfix function OnViewScript(), when quitted the dialog "Choose + Your KML Script" with the Cancel button when chosen an invalid + script the function returned without the possibility of saving the + current document; now the function try to reload the primarily KML + script and if this also fails then the current document is saved +- changed function MainWndProc(), added WM_INITMENU message handler + and call of _CrtDumpMemoryLeaks() at end of program to detect + malloc() memory leaks + +EMU48.DSP +- changed the resource natural language to English +- added redeye.c and udp.c sources +- added library Ws2_32.lib + +EMU48.H +- removed extern declaration of hHeap +- extern declaration of global variables and functions +- removed declaration of global function UpdateWindowStatus() +- replaced all HeapAlloc() with malloc() memory requests + +EMU48.RC +- changed version and copyright + +ENGINE.C +- added global variable nOpcSlow to hold the number of CPU opcodes + slowing down the CPU core +- changed function AdjustSpeed(), added CPU opcode slow down + implementation +- added function InitAdjustSpeed(), initialize CPU slow down part + if necessary +- changed function AdjKeySpeed() and SetSpeed(), use function + InitAdjustSpeed() to initialize the CPU slow down variables +- changed function SwitchToState(), removed all UpdateWindowStatus() + function calls + +EXTERNAL.C +- replaced all HeapAlloc() with malloc() memory requests + +FILES.C +- replaced all HeapAlloc() with malloc() memory requests +- changed TREENODE structure, added prev element for a double linked + list +- changed function PatchNibble(), added prev element handling +- bugfix in function UpdatePatches(), in the case an address was + patched more than one time, the ROM was patched in wrong order and + moreover the original content of the double patched ROM address + was destroyed +- changed function CrcRom(), if no ROM available return without + modifying the checksum +- changed function MapRom(), removed using of memory mapped files + which has the major advantage that packed ROM files are also valid + now +- changed function UnmapRom(), adjusted to changed MapRom() function +- changed function ResetDocument(), OpenDocument(), + SaveDocumentAs(), SaveBackup(), RestoreBackup() and ResetBackup(), + removed all UpdateWindowStatus() function calls +- changed function ResetDocument(), NewDocument(), OpenDocument() + and RestoreBackup(), added state variable if document is available +- bugfix in function OpenDocument(), added check of KML script name + length against target buffer size +- changed function DibNumColors(), changed function prototype from + UINT to WORD return +- changed function CreateBIPalette(), changed variable + UINT nNumColors to WORD wNumColors to avoid variable overflow + loading palNumEntries of LOGPALETTE structure + +I28F160.C +- added functions WrDirtyPage(), EraseBlock(), WriteByte() and + ReadByte() for access to the ROM buffer +- changed function WrStateE8C(), WrState40D(), WrState20C(), + WrState30C() and RdStateData(), changed implementation using the + new ROM buffer access functions + +IO.H +- added LBR and LBO bit definitions + +KEYMACRO.C +- changed function OnToolMacroNew(), OnToolMacroPlay() and + OnToolMacroStop(), removed all UpdateWindowStatus() function calls +- changed function EventThread(), added minimum key hold time for + keyboard macro playing and subtract minimum key hold time from + saved waiting time, this is more accurate when the user has + selected a different minimum key hold time than the default one +- changed function KeyMacroRecord(), now saving the complete waiting + time including the key state holding time, the key state holding + time is now subtract in the player function thread EventThread() +- changed function OnToolMacroNew(), removed adding the key state + holding time to the reference time, this is not necessary any more + +KML.C +- replaced all HeapAlloc() with malloc() memory requests +- changed function ParseLines(), BOOL expression was missing in main + while() loop, worked because TOK_NONE is 0 +- bugfix in function ParseBlock(), string argument wasn't freed in + error case +- changed function KillKML(), removed UpdateWindowStatus() function + call +- changed function LoadKMLGlobal(), used wrong variable type for + variable eToken + +MOPS.C +- added function ReadT2Acc(), reading timer2 value with checking for + CPU speed measurement behaviour +- bugfix in function ReadIO(), added implementation of the LED and + ELBE bit in the LCR (0x11C) register and of the LBO bit in the LBR + (0x11D) register +- changed function ReadIO(), the timer2 register content is now read + by function ReadT2Acc() to analyze the read access scheme +- bugfix in function WriteIO(), added implementation of the ELBE bit + in the LCR (0x11C) register and of the LBO bit in the LBR (0x11D) + register + +MRU.C +- replaced all HeapAlloc() with malloc() memory requests + +OPS.H +- bugfix in function FASTPTR(), longest opcode calculation from + buffer size was wrong, so MMU boundary fixup wasn't working + properly + +PCH.H +- added include winsock2.h + +REDEYE.C +- new module for decoding the redeye data stream for a HP82240B + printer + +RESOURCE.H +- added some definitions + +RPL.C +- replaced all HeapAlloc() with malloc() memory requests + +SETTINGS.C +- changed function ReadSettings() and WriteSettings(), added item + "KeyMinDelay" in section [Macro] and the items "Address" and + "Port" in section [IrPrinter] in the INI-File + +STACK.C +- replaced all HeapAlloc() with malloc() memory requests +- bugfix in function RPL_GetBcd(), fixed possible uninitialized + bExpflag variable +- bugfix in function OnStackCopy(), fixed possible uninitialized + uClipboardFormat variable in DOCSTR case + +SYMBFILE.C +- replaced all HeapAlloc() with malloc() memory requests + +UDP.C +- new module for sending a byte over UDP + + Service Pack 50 for Emu48 Version 1.0 DEBUGGER.C diff --git a/Sources/Emu48/DDESERV.C b/Sources/Emu48/DDESERV.C index 884542b..162f87d 100644 --- a/Sources/Emu48/DDESERV.C +++ b/Sources/Emu48/DDESERV.C @@ -11,8 +11,8 @@ #include "io.h" HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv, - HSZ hsz1,HSZ hsz2,HDDEDATA hData, - DWORD dwData1,DWORD dwData2) + HSZ hsz1,HSZ hsz2,HDDEDATA hData, + DWORD dwData1,DWORD dwData2) { TCHAR *psz,szBuffer[32]; HDDEDATA hReturn; @@ -50,7 +50,7 @@ HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv, DdeUnaccessData(hData); // reserve memory - if ((lpData = HeapAlloc(hHeap,0,dwSize * 2)) == NULL) + if ((lpData = malloc(dwSize * 2)) == NULL) return (HDDEDATA) DDE_FNOTPROCESSED; SuspendDebugger(); // suspend debugger @@ -66,7 +66,7 @@ HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv, if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state { - HeapFree(hHeap,0,lpData); // free memory + free(lpData); // free memory hReturn = DDE_FNOTPROCESSED; goto cancel; } @@ -80,7 +80,7 @@ HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv, dwSize = dwIndex; dwSize = DdeGetData(hData,lpData+dwSize,dwSize,sizeof(DWORD)); bSuccess = (WriteStack(nStkLvl,lpData,dwSize) == S_ERR_NO); - HeapFree(hHeap,0,lpData); // free memory + free(lpData); // free memory SwitchToState(SM_RUN); // run state while (nState!=nNextState) Sleep(0); @@ -138,7 +138,7 @@ cancel: dwSize += dwIndex + sizeof(DWORD); // reserve memory - if ((lpData = HeapAlloc(hHeap,0,dwSize)) == NULL) + if ((lpData = malloc(dwSize)) == NULL) { SwitchToState(SM_RUN); // run state return NULL; @@ -156,7 +156,7 @@ cancel: // write data hReturn = DdeCreateDataHandle(idDdeInst,lpData,dwSize,0,hsz2,iFmt,0); - HeapFree(hHeap,0,lpData); + free(lpData); SwitchToState(SM_RUN); // run state while (nState!=nNextState) Sleep(0); diff --git a/Sources/Emu48/DEBUGGER.C b/Sources/Emu48/DEBUGGER.C index aff99b3..7bf028c 100644 --- a/Sources/Emu48/DEBUGGER.C +++ b/Sources/Emu48/DEBUGGER.C @@ -53,21 +53,6 @@ typedef struct // type of breakpoint table DWORD dwAddr; // breakpoint address } BP_T; -typedef struct // type of model memory mapping -{ - CONST 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 int nCol[] = { IDC_DEBUG_MEM_COL0, IDC_DEBUG_MEM_COL1, IDC_DEBUG_MEM_COL2, IDC_DEBUG_MEM_COL3, @@ -79,68 +64,6 @@ static CONST TCHAR cHex[] = { _T('0'),_T('1'),_T('2'),_T('3'), _T('8'),_T('9'),_T('A'),_T('B'), _T('C'),_T('D'),_T('E'),_T('F') }; -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 INT nDbgPosX = 0; // position of debugger window static INT nDbgPosY = 0; @@ -159,16 +82,12 @@ 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 LPBYTE lbyMapData; // data -static DWORD dwMapDataSize; // data size 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 MODEL_MAP_T CONST *pMapping; // model specific memory mapping - static DWORD dwDbgRefCycles; // cpu cycles counter from last opcode static CHIPSET OldChipset; // old chipset content @@ -189,6 +108,8 @@ 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); //################ //# @@ -242,52 +163,53 @@ static VOID DisableMenuKeys(HWND hDlg) // 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"); - lbyMapData = NULL; // data - dwMapDataSize = 512; // data size + eMode = MEM_MMU; + uEnable = MF_ENABLED; // enable Memory Data menu items break; case ID_DEBUG_MEM_NCE1: szCaption = _T("Memory (NCE1)"); - lbyMapData = *pMapping->ppbyNCE1; - dwMapDataSize = *pMapping->pdwNCE1Size / 2048; // ROM size is always in nibbles + eMode = MEM_NCE1; break; case ID_DEBUG_MEM_NCE2: szCaption = _T("Memory (NCE2)"); - lbyMapData = *pMapping->ppbyNCE2; - dwMapDataSize = *pMapping->pdwNCE2Size; + eMode = MEM_NCE2; break; case ID_DEBUG_MEM_CE1: szCaption = _T("Memory (CE1)"); - lbyMapData = *pMapping->ppbyCE1; - dwMapDataSize = *pMapping->pdwCE1Size; + eMode = MEM_CE1; break; case ID_DEBUG_MEM_CE2: szCaption = _T("Memory (CE2)"); - lbyMapData = *pMapping->ppbyCE2; - dwMapDataSize = *pMapping->pdwCE2Size; + eMode = MEM_CE2; break; case ID_DEBUG_MEM_NCE3: szCaption = _T("Memory (NCE3)"); - lbyMapData = *pMapping->ppbyNCE3; - dwMapDataSize = *pMapping->pdwNCE3Size; + eMode = MEM_NCE3; break; default: _ASSERT(0); } - dwMapDataSize *= 2048; // size in nibble + 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; }; @@ -299,6 +221,7 @@ static DWORD GetMemCurAddr(HWND hDlg) { INT i,nPos; DWORD dwAddr = dwAdrMem; + DWORD dwMapDataMask = GetMemDataMask(); for (i = 0; i < MEMWNDMAX; ++i) // scan all memory cols { @@ -306,7 +229,7 @@ static DWORD GetMemCurAddr(HWND hDlg) if ((nPos = (INT) SendDlgItemMessage(hDlg,nCol[i],LB_GETCURSEL,0,0)) != LB_ERR) { dwAddr += (DWORD) (nPos * MEMWNDMAX + i) * 2; - dwAddr &= (dwMapDataSize - 1); + dwAddr &= dwMapDataMask; break; } } @@ -331,8 +254,7 @@ static __inline VOID ToggleBreakpoint(DWORD dwAddr) return; } - // purge breakpoint - for (++i; i < wBreakpointCount; ++i) + while (++i < wBreakpointCount) // purge breakpoint sBreakpoint[i-1] = sBreakpoint[i]; --wBreakpointCount; return; @@ -359,34 +281,23 @@ static __inline VOID ToggleBreakpoint(DWORD dwAddr) static __inline VOID InitMemMap(HWND hDlg) { BOOL bActive; - INT 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 - break; - } - } + SetMemRomType(cCurrentRomType); // set current model _ASSERT(hMenuMem); // enable menu mappings - EnableMenuItem(hMenuMem,ID_DEBUG_MEM_NCE1,(*pMapping->ppbyNCE1) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenuMem,ID_DEBUG_MEM_NCE2,(*pMapping->ppbyNCE2) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenuMem,ID_DEBUG_MEM_CE1, (*pMapping->ppbyCE1) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenuMem,ID_DEBUG_MEM_CE2, (*pMapping->ppbyCE2) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenuMem,ID_DEBUG_MEM_NCE3,(*pMapping->ppbyNCE3) ? MF_ENABLED : MF_GRAYED); + 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 && *pMapping->ppbyNCE1 != NULL) - || (ID_DEBUG_MEM_NCE2 == uIDMap && *pMapping->ppbyNCE2 != NULL) - || (ID_DEBUG_MEM_CE1 == uIDMap && *pMapping->ppbyCE1 != NULL) - || (ID_DEBUG_MEM_CE2 == uIDMap && *pMapping->ppbyCE2 != NULL) - || (ID_DEBUG_MEM_NCE3 == uIDMap && *pMapping->ppbyNCE3 != NULL); + 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; @@ -452,6 +363,7 @@ static VOID StrToReg(BYTE *pReg, WORD wNib, LPTSTR lpszValue) // static INT ViewCodeWnd(HWND hWnd, DWORD dwAddress) { + enum MEM_MAPPING eMapMode; LPCTSTR lpszName; TCHAR szAddress[64]; DWORD dwNxtAddr; @@ -459,7 +371,9 @@ static INT ViewCodeWnd(HWND hWnd, DWORD dwAddress) nLinePC = -1; // PC not shown (no selection) - _ASSERT(disassembler_map == MEM_MAP); // disassemble in mapped mode + 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); @@ -509,6 +423,7 @@ static INT ViewCodeWnd(HWND hWnd, DWORD dwAddress) SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szAddress); } SendMessage(hWnd,WM_SETREDRAW,TRUE,0); + SetMemMapType(eMapMode); // switch back to old map mode return nLinePC; } @@ -519,12 +434,14 @@ static VOID ViewMemWnd(HWND hDlg, DWORD dwAddress) { #define TEXTOFF 32 - INT i,j,k; + 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); @@ -538,28 +455,18 @@ static VOID ViewMemWnd(HWND hDlg, DWORD dwAddress) if (ID_DEBUG_MEM_MAP == uIDMap) // mapped memory content { - // fetch mapping data line - Npeek(byLineData, dwAddress, MAXMEMITEMS); - wsprintf(szBuffer,_T("%05lX"),dwAddress); } else // module memory content { - INT i; - - _ASSERT(lbyMapData); // valid module - - // fetch modul data line - for (i = 0; i < MAXMEMITEMS; ++i) - { - byLineData[i] = lbyMapData[(dwAddress + i) & (dwMapDataSize - 1)]; - } - wsprintf(szBuffer,_T("%06lX"),dwAddress); } SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_ADDR,LB_ADDSTRING,0,(LPARAM) szBuffer); - for (k = 0, j = 0; j < MAXMEMITEMS; ++j) + // fetch data line + GetMemPeek(byLineData, dwAddress, MAXMEMITEMS); + + for (j = 0; j < MAXMEMITEMS; ++j) { // read from fetched data line szItem[j&0x1] = cHex[byLineData[j]]; @@ -579,7 +486,7 @@ static VOID ViewMemWnd(HWND hDlg, DWORD dwAddress) szBuffer[j/2] = 0; // end of text string SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_TEXT,LB_ADDSTRING,0,(LPARAM) szBuffer); - dwAddress = (dwAddress + MAXMEMITEMS) & (dwMapDataSize - 1); + dwAddress = (dwAddress + MAXMEMITEMS) & dwMapDataMask; } return; #undef TEXTOFF @@ -967,7 +874,7 @@ static BOOL OnKeyF5(HWND hDlg) SetEvent(hEventDebug); // run emulation } return -1; // call windows default handler - UNREFERENCED_PARAMETER(hDlg); + UNREFERENCED_PARAMETER(hDlg); } // @@ -1001,7 +908,7 @@ static BOOL OnKeyF7(HWND hDlg) SetEvent(hEventDebug); // run emulation } return -1; // call windows default handler - UNREFERENCED_PARAMETER(hDlg); + UNREFERENCED_PARAMETER(hDlg); } // @@ -1031,7 +938,7 @@ static BOOL OnKeyF8(HWND hDlg) SetEvent(hEventDebug); // run emulation } return -1; // call windows default handler - UNREFERENCED_PARAMETER(hDlg); + UNREFERENCED_PARAMETER(hDlg); } // @@ -1049,7 +956,7 @@ static BOOL OnKeyF9(HWND hDlg) SetEvent(hEventDebug); // run emulation } return -1; // call windows default handler - UNREFERENCED_PARAMETER(hDlg); + UNREFERENCED_PARAMETER(hDlg); } // @@ -1061,7 +968,7 @@ static BOOL OnKeyF11(HWND hDlg) if (Chipset.Shutdn) // cpu thread stopped SetEvent(hEventShutdn); // goto debug session return -1; // call windows default handler - UNREFERENCED_PARAMETER(hDlg); + UNREFERENCED_PARAMETER(hDlg); } // @@ -1121,7 +1028,7 @@ static BOOL OnMemGoAdr(HWND hDlg) OnEnterAddress(hDlg, &dwAddress); if (dwAddress != -1) // not Cancel key - OnMemGoDx(hDlg,dwAddress & (dwMapDataSize - 1)); + OnMemGoDx(hDlg,dwAddress & GetMemDataMask()); return -1; // call windows default handler } @@ -1219,8 +1126,8 @@ static BOOL OnStackPush(HWND hDlg) // static BOOL OnStackPop(HWND hDlg) { - HWND hWnd; - INT i,j; + HWND hWnd; + INT i,j; if (nDbgState != DBG_STEPINTO) // not in single step mode return TRUE; @@ -1283,7 +1190,7 @@ static BOOL OnLButtonUp(HWND hDlg, LPARAM lParam) // handle of selected window hWnd = ChildWindowFromPointEx(hDlg,pt,CWP_SKIPDISABLED); - nId = GetDlgCtrlID(hWnd); // control ID of window + nId = GetDlgCtrlID(hWnd); // control ID of window GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer)); switch (nId) @@ -1400,19 +1307,22 @@ static BOOL OnLButtonUp(HWND hDlg, LPARAM lParam) // 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); - // show code of this address - ViewCodeWnd(GetDlgItem(GetParent(hWnd),IDC_DEBUG_CODE),dwAddress); + ViewCodeWnd(hWndCode,dwAddress); // show code of this address return TRUE; } @@ -1432,11 +1342,12 @@ static BOOL OnDblClick(HWND hWnd, WORD wId) // enter new value SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuffer); OnNewValue(szBuffer); - _stscanf(szBuffer,_T("%2X"), &byData); + byData = (BYTE) _tcstoul(szBuffer,NULL,16); byData = (byData >> 4) | (byData << 4); // change nibbles for writing - Write2(dwAddress, byData); // write data - ViewMemWnd(GetParent(hWnd),dwAdrMem); // update memory window + 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; } @@ -1450,7 +1361,7 @@ static VOID OnContextMenu(HWND hDlg, LPARAM lParam, WPARAM wParam) INT nId; POINTSTOPOINT(pt,MAKEPOINTS(lParam)); // mouse position - nId = GetDlgCtrlID((HWND) wParam); // control ID of window + nId = GetDlgCtrlID((HWND) wParam); // control ID of window switch(nId) { @@ -1504,7 +1415,7 @@ static __inline BOOL OnKeyRightLeft(HWND hWnd, WPARAM wParam) WORD wX; INT nId; - nId = GetDlgCtrlID(hWnd); // control ID of window + nId = GetDlgCtrlID(hWnd); // control ID of window for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's if (nCol[wX] == nId) // found ID @@ -1527,10 +1438,10 @@ static __inline BOOL OnKeyRightLeft(HWND hWnd, WPARAM wParam) // static __inline BOOL OnKeyUpDown(HWND hWnd, WPARAM wParam) { - INT wX, wY; - INT nId; + INT wX, wY; + INT nId; - nId = GetDlgCtrlID(hWnd); // control ID of window + nId = GetDlgCtrlID(hWnd); // control ID of window for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's if (nCol[wX] == nId) // found ID @@ -1543,13 +1454,13 @@ static __inline BOOL OnKeyUpDown(HWND hWnd, WPARAM wParam) switch(LOWORD(wParam)) { case VK_NEXT: - dwAdrMem = (dwAdrMem + MAXMEMITEMS * MAXMEMLINES) & (dwMapDataSize - 1); + dwAdrMem = (dwAdrMem + MAXMEMITEMS * MAXMEMLINES) & GetMemDataMask(); ViewMemWnd(GetParent(hWnd),dwAdrMem); SendMessage(hWnd,LB_SETCURSEL,wY,0); return -2; case VK_PRIOR: - dwAdrMem = (dwAdrMem - MAXMEMITEMS * MAXMEMLINES) & (dwMapDataSize - 1); + dwAdrMem = (dwAdrMem - MAXMEMITEMS * MAXMEMLINES) & GetMemDataMask(); ViewMemWnd(GetParent(hWnd),dwAdrMem); SendMessage(hWnd,LB_SETCURSEL,wY,0); return -2; @@ -1557,7 +1468,7 @@ static __inline BOOL OnKeyUpDown(HWND hWnd, WPARAM wParam) case VK_DOWN: if (wY+1 >= MAXMEMLINES) { - dwAdrMem = (dwAdrMem + MAXMEMITEMS) & (dwMapDataSize - 1); + dwAdrMem = (dwAdrMem + MAXMEMITEMS) & GetMemDataMask(); ViewMemWnd(GetParent(hWnd),dwAdrMem); SendMessage(hWnd,LB_SETCURSEL,wY,0); return -2; @@ -1567,7 +1478,7 @@ static __inline BOOL OnKeyUpDown(HWND hWnd, WPARAM wParam) case VK_UP: if (wY == 0) { - dwAdrMem = (dwAdrMem - MAXMEMITEMS) & (dwMapDataSize - 1); + dwAdrMem = (dwAdrMem - MAXMEMITEMS) & GetMemDataMask(); ViewMemWnd(GetParent(hWnd),dwAdrMem); SendMessage(hWnd,LB_SETCURSEL,wY,0); return -2; @@ -1582,10 +1493,10 @@ static __inline BOOL OnKeyUpDown(HWND hWnd, WPARAM wParam) // static __inline BOOL OnKeyPlusMinus(HWND hWnd, WPARAM wParam) { - INT wX, wY; - INT nId; + INT wX, wY; + INT nId; - nId = GetDlgCtrlID(hWnd); // control ID of window + nId = GetDlgCtrlID(hWnd); // control ID of window for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's if (nCol[wX] == nId) // found ID @@ -1599,7 +1510,7 @@ static __inline BOOL OnKeyPlusMinus(HWND hWnd, WPARAM wParam) dwAdrMem++; else dwAdrMem--; - dwAdrMem &= (dwMapDataSize - 1); + dwAdrMem &= GetMemDataMask(); ViewMemWnd(GetParent(hWnd),dwAdrMem); // redraw memory view SendMessage(hWnd,LB_SETCURSEL,wY,0); // set focus at old position @@ -1705,7 +1616,7 @@ static __inline BOOL OnDrawCodeWnd(LPDRAWITEMSTRUCT lpdis) 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); + ETO_OPAQUE,(LPRECT)&lpdis->rcItem,szBuf,lstrlen(szBuf),NULL); SetBkColor(lpdis->hDC,crBkColor); SetTextColor(lpdis->hDC,crTextColor); @@ -1803,7 +1714,7 @@ static __inline HWND CreateToolbar(HWND hWnd) HRSRC hRes; HGLOBAL hGlobal; CToolBarData *pData; - TBBUTTON *ptbb; + TBBUTTON *ptbb; INT i,j; HWND hWndToolbar = NULL; // toolbar window @@ -1822,12 +1733,12 @@ static __inline HWND CreateToolbar(HWND hWnd) _ASSERT(pData->wVersion == 1); // toolbar resource version // alloc memory for TBBUTTON stucture - if (!(ptbb = HeapAlloc(hHeap,0,pData->wItemCount*sizeof(TBBUTTON)))) + if (!(ptbb = 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++; @@ -1842,14 +1753,14 @@ static __inline HWND CreateToolbar(HWND hWnd) 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)); - HeapFree(hHeap,0,ptbb); + free(ptbb); unlock: FreeResource(hGlobal); @@ -1862,7 +1773,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM static HMENU hMenuMainCode,hMenuMainMem,hMenuMainStack; WINDOWPLACEMENT wndpl; - TEXTMETRIC tm; + TEXTMETRIC tm; HDC hDC; HFONT hFont; HMENU hSysMenu; @@ -1924,7 +1835,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM SendDlgItemMessage(hDlg,IDC_STATIC_MISC, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); // init last instruction circular buffer - pdwInstrArray = HeapAlloc(hHeap,0,INSTRSIZE*sizeof(*pdwInstrArray)); + pdwInstrArray = malloc(INSTRSIZE*sizeof(*pdwInstrArray)); wInstrSize = INSTRSIZE; // size of last instruction array wInstrWp = wInstrRp = 0; // write/read pointer @@ -1937,7 +1848,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM InitBsArea(hDlg); // init bank switcher list box DisableMenuKeys(hDlg); // set debug menu keys into run state - disassembler_map = MEM_MAP; // disassemble with mapped modules + 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 @@ -1949,7 +1860,6 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM if (Chipset.Shutdn) // cpu thread stopped SetEvent(hEventShutdn); // goto debug session - UpdateWindowStatus(); // disable application menu items OldChipset = Chipset; // save chipset values return TRUE; @@ -1960,7 +1870,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM SetEvent(hEventDebug); if (pdwInstrArray) // free last instruction circular buffer { - HeapFree(hHeap,0,pdwInstrArray); + free(pdwInstrArray); pdwInstrArray = NULL; } CloseHandle(hEventDebug); @@ -1973,8 +1883,6 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM DestroyMenu(hMenuMainCode); DestroyMenu(hMenuMainMem); DestroyMenu(hMenuMainStack); - _ASSERT(hWnd); - UpdateWindowStatus(); // enable application menu items hDlgDebug = NULL; // debugger windows closed break; @@ -2047,6 +1955,8 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM 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); @@ -2138,7 +2048,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM // 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")); + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Courier New")); hFont = SelectObject(hDC,hFont); GetTextMetrics(hDC,&tm); @@ -2157,7 +2067,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM LRESULT OnToolDebug(VOID) // debugger dialogbox call { if ((hDlgDebug = CreateDialog(hApp,MAKEINTRESOURCE(IDD_DEBUG),NULL, - (DLGPROC)Debugger)) == NULL) + (DLGPROC)Debugger)) == NULL) AbortMessage(_T("Debugger Dialog Box Creation Error !")); return 0; } @@ -2173,16 +2083,18 @@ static __inline BOOL OnFindOK(HWND hDlg,BOOL bASCII,DWORD *pdwAddrLast) { BYTE *lpbySearch; INT i,j; - DWORD dwAddr; + DWORD dwAddr,dwMapDataMask; BOOL bMatch; HWND 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 = HeapAlloc(hHeap,0,i * j)) != NULL) + if ((lpbySearch = malloc(i * j)) != NULL) { // get search text and real length i = GetWindowText(hWnd,(LPTSTR) lpbySearch,i); @@ -2200,7 +2112,7 @@ static __inline BOOL OnFindOK(HWND hDlg,BOOL bASCII,DWORD *pdwAddrLast) WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, szTmp, -1, lpbySearch, i+1, NULL, NULL); - HeapFree(hHeap,0,szTmp); + free(szTmp); } } #endif @@ -2245,26 +2157,19 @@ static __inline BOOL OnFindOK(HWND hDlg,BOOL bASCII,DWORD *pdwAddrLast) ++dwAddr; // scan mapping/module until match - for (; i && !bMatch && dwAddr <= dwAdrMem + dwMapDataSize; ++dwAddr) + for (; i && !bMatch && dwAddr <= dwAdrMem + dwMapDataMask + 1; ++dwAddr) { BYTE byC; // i = no. of nibbles that have to match for (bMatch = TRUE, j = 0;bMatch && j < i; ++j) { - if (ID_DEBUG_MEM_MAP == uIDMap) // mapped memory content - { - Npeek(&byC,(dwAddr + j) & 0xFFFFF,1); - } - else // module memory content - { - byC = lbyMapData[(dwAddr + j) & (dwMapDataSize - 1)]; - } + GetMemPeek(&byC,(dwAddr + j) & dwMapDataMask,1); bMatch = (byC == lpbySearch[j]); } } - dwAddr = (dwAddr - 1) & (dwMapDataSize - 1); // possible matching address - HeapFree(hHeap,0,lpbySearch); + dwAddr = (dwAddr - 1) & dwMapDataMask; // possible matching address + free(lpbySearch); // check match result if (bMatch) @@ -2447,10 +2352,13 @@ static VOID UpdateRplObjViewWnd(HWND hDlg, DWORD dwAddr) 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,0x100000,TRUE); + szObjList = RplCreateObjView(dwAddr,GetMemDataSize(),TRUE); SetDlgItemText(hDlg,IDC_RPLVIEW_DATA,szObjList); - HeapFree(hHeap,0,szObjList); + free(szObjList); return; } @@ -2480,7 +2388,6 @@ static INT_PTR CALLBACK RplObjView(HWND hDlg, UINT message, WPARAM wParam, LPARA _ASSERT(FALSE); } - bRplViewName = TRUE; // show entry point name bRplViewAddr = TRUE; // show address bRplViewBin = TRUE; // show binary data return TRUE; @@ -2535,7 +2442,7 @@ static VOID CopyEditToCombo(HWND hDlg,HWND hWndComboBox) if ((i = (INT) SendMessage(hWndComboBox,CB_GETCURSEL,0,0)) != CB_ERR) { // delete associated name - HeapFree(hHeap,0,(LPVOID) SendMessage(hWndComboBox,CB_GETITEMDATA,i,0)); + free((LPVOID) SendMessage(hWndComboBox,CB_GETITEMDATA,i,0)); // append actual name GetDlgItemText(hDlg,IDC_DEBUG_SET_FILE,szSymbFilename,ARRAYSIZEOF(szSymbFilename)); @@ -2700,7 +2607,7 @@ static INT_PTR CALLBACK Settings(HWND hDlg, UINT message, WPARAM wParam, LPARAM LPTSTR lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0); if (lpszFilename != NULL) { - HeapFree(hHeap,0,lpszFilename); + free(lpszFilename); } } EndDialog(hDlg,LOWORD(wParam)); @@ -2708,8 +2615,8 @@ static INT_PTR CALLBACK Settings(HWND hDlg, UINT message, WPARAM wParam, LPARAM } } return FALSE; - UNREFERENCED_PARAMETER(wParam); - UNREFERENCED_PARAMETER(lParam); + UNREFERENCED_PARAMETER(wParam); + UNREFERENCED_PARAMETER(lParam); } static BOOL OnSettings(HWND hDlg) @@ -2772,7 +2679,7 @@ static INT_PTR CALLBACK NewValue(HWND hDlg, UINT message, WPARAM wParam, LPARAM } } return FALSE; - UNREFERENCED_PARAMETER(wParam); + UNREFERENCED_PARAMETER(wParam); } static INT_PTR OnNewValue(LPTSTR lpszValue) @@ -2843,7 +2750,7 @@ static INT_PTR CALLBACK EnterAddr(HWND hDlg, UINT message, WPARAM wParam, LPARAM } } return FALSE; - UNREFERENCED_PARAMETER(wParam); + UNREFERENCED_PARAMETER(wParam); } static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue) @@ -2908,7 +2815,7 @@ static INT_PTR CALLBACK EnterBreakpoint(HWND hDlg, UINT message, WPARAM wParam, } } return FALSE; - UNREFERENCED_PARAMETER(wParam); + UNREFERENCED_PARAMETER(wParam); } static VOID OnEnterBreakpoint(HWND hDlg, BP_T *sValue) @@ -2955,7 +2862,7 @@ static __inline BOOL OnDrawBreakWnd(LPDRAWITEMSTRUCT lpdis) 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); + ETO_OPAQUE,(LPRECT)&lpdis->rcItem,szBuf,lstrlen(szBuf),NULL); SetBkColor(lpdis->hDC,crBkColor); SetTextColor(lpdis->hDC,crTextColor); @@ -3099,7 +3006,7 @@ static INT_PTR CALLBACK EditBreakpoint(HWND hDlg, UINT message, WPARAM wParam, L // only modify memory breakpoints if ( ( sBreakpoint[i].bEnable == FALSE - && (sBreakpoint[i].nType & sBp.nType & (BP_EXEC | BP_RPL)) != 0) + && (sBreakpoint[i].nType & sBp.nType & (BP_EXEC | BP_RPL)) != 0) || ((sBreakpoint[i].nType & BP_ACCESS) && (sBp.nType & BP_ACCESS))) { // replace breakpoint type @@ -3156,7 +3063,7 @@ static INT_PTR CALLBACK EditBreakpoint(HWND hDlg, UINT message, WPARAM wParam, L } // remove breakpoint from breakpoint table - for (++i; i <= wBreakpointCount; ++i) + while (++i <= wBreakpointCount) sBreakpoint[i-1] = sBreakpoint[i]; } } @@ -3190,7 +3097,7 @@ static INT_PTR CALLBACK EditBreakpoint(HWND hDlg, UINT message, WPARAM wParam, L // 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")); + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Courier New")); hFont = SelectObject(hDC,hFont); GetTextMetrics(hDC,&tm); @@ -3203,8 +3110,8 @@ static INT_PTR CALLBACK EditBreakpoint(HWND hDlg, UINT message, WPARAM wParam, L return TRUE; } return FALSE; - UNREFERENCED_PARAMETER(wParam); - UNREFERENCED_PARAMETER(lParam); + UNREFERENCED_PARAMETER(wParam); + UNREFERENCED_PARAMETER(lParam); } static BOOL OnEditBreakpoint(HWND hDlg) @@ -3283,7 +3190,7 @@ static INT_PTR CALLBACK InfoIntr(HWND hDlg, UINT message, WPARAM wParam, LPARAM } } return FALSE; - UNREFERENCED_PARAMETER(lParam); + UNREFERENCED_PARAMETER(lParam); } static BOOL OnInfoIntr(HWND hDlg) @@ -3320,7 +3227,7 @@ static BOOL CALLBACK InfoWoRegister(HWND hDlg, UINT message, DWORD wParam, LONG } } return FALSE; - UNREFERENCED_PARAMETER(lParam); + UNREFERENCED_PARAMETER(lParam); } static BOOL OnInfoWoRegister(HWND hDlg) @@ -3346,7 +3253,9 @@ VOID LoadBreakpointList(HANDLE hFile) // NULL = clear breakpoint list // read number of breakpoints if (hFile) ReadFile(hFile, &wBreakpointCount, sizeof(wBreakpointCount), &lBytesRead, NULL); - if (lBytesRead) // breakpoints found + + // breakpoints found + if (lBytesRead == sizeof(wBreakpointCount) && wBreakpointCount < ARRAYSIZEOF(sBreakpoint)) { WORD wBreakpointSize; @@ -3363,7 +3272,7 @@ VOID LoadBreakpointList(HANDLE hFile) // NULL = clear breakpoint list wBreakpointCount = 0; // clear breakpoint list } } - else + else // no breakpoints or breakpoint buffer too small { wBreakpointCount = 0; // clear breakpoint list } @@ -3429,3 +3338,232 @@ VOID RestoreBackupBreakpointList(VOID) } 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 (TRUE) // read until EOF + { + ReadFile(hFile,&byData,sizeof(byData),&dwRead,NULL); + if (dwRead == 0) break; // EOF + + Write2(dwStartAddr,byData); // write byte in map mode + dwStartAddr += 2; + } + + 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) + { + byData = Read2(dwAddr); // read byte in map mode + WriteFile(hFile,&byData,sizeof(byData),&dwWritten,NULL); + } + + CloseHandle(hFile); + return TRUE; +} + +// +// read edit control and decode content as hex number +// +static BOOL GetAddr(HWND hDlg, INT nID, DWORD *pdwAddr) +{ + TCHAR szBuffer[8]; + INT i; + + HWND hWnd = GetDlgItem(hDlg,nID); + + GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer)); + + // 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; + } + } + _stscanf(szBuffer,_T("%6X"),pdwAddr); + 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: + // get filename + GetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szFilename,ARRAYSIZEOF(szFilename)); + + // decode address field + if (!GetAddr(hDlg,IDC_DEBUG_DATA_STARTADDR,&dwStartAddr)) + return FALSE; + + // 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(wParam); + 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: + // get filename + GetDlgItemText(hDlg,IDC_DEBUG_DATA_FILE,szFilename,ARRAYSIZEOF(szFilename)); + + // decode address fields + if (!GetAddr(hDlg,IDC_DEBUG_DATA_STARTADDR,&dwStartAddr)) + return FALSE; + if (!GetAddr(hDlg,IDC_DEBUG_DATA_ENDADDR,&dwEndAddr)) + return FALSE; + + // 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(wParam); + 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; +} diff --git a/Sources/Emu48/DEBUGGER.H b/Sources/Emu48/DEBUGGER.H index 78224f5..1a9b694 100644 --- a/Sources/Emu48/DEBUGGER.H +++ b/Sources/Emu48/DEBUGGER.H @@ -11,7 +11,7 @@ #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_RPL 0x08 // RPL breakpoint #define BP_ACCESS (BP_READ|BP_WRITE) // read/write memory breakpoint // breakpoint notify definitions @@ -24,8 +24,8 @@ #define DBG_OFF 0 #define DBG_RUN 1 #define DBG_STEPINTO 2 -#define DBG_STEPOVER 3 -#define DBG_STEPOUT 4 +#define DBG_STEPOVER 3 +#define DBG_STEPOUT 4 // debugger.c extern VOID UpdateDbgCycleCounter(VOID); diff --git a/Sources/Emu48/DISASM.C b/Sources/Emu48/DISASM.C index 944302a..71078e0 100644 --- a/Sources/Emu48/DISASM.C +++ b/Sources/Emu48/DISASM.C @@ -16,7 +16,6 @@ BOOL disassembler_mode = HP_MNEMONICS; BOOL disassembler_symb = FALSE; -WORD disassembler_map = MEM_MAP; static LPCTSTR hex[] = { @@ -215,82 +214,13 @@ static LPCTSTR hst_bits[8] = _T("xm"), _T("sb"), _T("sr"), _T("mp") }; - -// static functions - -static BYTE rn_map (DWORD *p) -{ - BYTE byVal; - - Npeek(&byVal, *p, 1); - *p = ++(*p) & 0xFFFFF; - return byVal; -} - -static BYTE rn_rom (DWORD *p) -{ - DWORD d = *p; - - *p = ++(*p) & (dwRomSize - 1); - - _ASSERT(d < dwRomSize); - return *(pbyRom + d); -} - -static BYTE rn_ram (DWORD *p) -{ - DWORD d = *p; - - *p = ++(*p) & (Chipset.Port0Size * 2048 - 1); - - _ASSERT(d < Chipset.Port0Size * 2048); - return *(Port0 + d); -} - -static BYTE rn_port1 (DWORD *p) -{ - DWORD d = *p; - - *p = ++(*p) & (Chipset.Port1Size * 2048 - 1); - - _ASSERT(d < Chipset.Port1Size * 2048); - return *(Port1 + d); -} - -static BYTE rn_port2 (DWORD *p) -{ - BYTE *pbyVal; - DWORD d = *p; - - if (Chipset.Port2Size) // HP39/40G, HP49G - { - *p = ++(*p) & (Chipset.Port2Size * 2048 - 1); - - _ASSERT(d < Chipset.Port2Size * 2048); - pbyVal = Port2; - } - else // HP48SX/GX - { - *p = ++(*p) & (((dwPort2Mask + 1) << 18) - 1); - - _ASSERT(d < ((dwPort2Mask + 1) << 18)); - pbyVal = pbyPort2; - } - return *(pbyVal + d); -} - -// global functions - -BYTE read_nibble (DWORD *p) -{ - BYTE (*pnread[])(DWORD *) = { rn_map, rn_rom, rn_ram, rn_port1, rn_port2 }; - - _ASSERT(disassembler_map < ARRAYSIZEOF(pnread)); - return pnread[disassembler_map](p); -} - // general functions +static BYTE read_nibble (DWORD *p) +{ + return GetMemNib(p); +} + static int read_int (DWORD *addr, int n) { int i, t; @@ -835,7 +765,7 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out) { case HP_MNEMONICS: wsprintf (buf, _T("%cBIT=%d"), (fn & 8) ? _T('C') : _T('A'), - (fn & 1) ? 1 : 0); + (fn & 1) ? 1 : 0); p = append_str (out, buf); p = append_tab (out); p = append_imm_nibble (p, addr, 1); @@ -909,7 +839,7 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out) { 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')); + (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); @@ -919,7 +849,7 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out) 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); + p = append_str (p, buf); break; default: p = append_str (out, _T("Unknown disassembler mode")); @@ -988,9 +918,9 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out) { 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('-')); + 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); @@ -1053,18 +983,18 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out) if (n == 2) { wsprintf (buf, _T("%cR%dEX.F"), ((int) c < 8) ? _T('A') : _T('C'), - (int) c & 7); + (int) c & 7); } else if (n == 1) { wsprintf (buf, _T("%c=R%d.F"), ((int) c < 8) ? _T('A') : _T('C'), - (int) c & 7); + (int) c & 7); } else { wsprintf (buf, _T("R%d=%c.F"), (int) c & 7, - ((int) c < 8) ? _T('A') : _T('C')); + ((int) c < 8) ? _T('A') : _T('C')); } p = append_str (out, buf); p = append_tab (out); @@ -1395,7 +1325,7 @@ DWORD disassemble (DWORD addr, LPTSTR out) { case HP_MNEMONICS: wsprintf (buf, op_str_0[(n & 7) + 8 * HP_MNEMONICS], - (n < 8) ? _T('&') : _T('!')); + (n < 8) ? _T('&') : _T('!')); p = append_str (out, buf); p = append_tab (out); p = append_field (p, fn); @@ -1609,10 +1539,10 @@ DWORD disassemble (DWORD addr, LPTSTR out) 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]); + 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]); + 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); diff --git a/Sources/Emu48/DISMEM.C b/Sources/Emu48/DISMEM.C new file mode 100644 index 0000000..15313a3 --- /dev/null +++ b/Sources/Emu48/DISMEM.C @@ -0,0 +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 +{ + CONST 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) +{ + INT 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 index d97d930..6ab3d2d 100644 --- a/Sources/Emu48/DISPLAY.C +++ b/Sources/Emu48/DISPLAY.C @@ -34,8 +34,12 @@ |((((c)-1)>>1)<<8) \ |((((c)-1)>>1))) -#define DIBPIXEL4(d,p) *((DWORD*)(d)) = ((*((DWORD*)(d)) & dwGrayMask) << 1) | (p); (BYTE *) d += 4 -#define DIBPIXEL3(d,p) *(d+2) = *(d+1) = *d = ((*d & (BYTE) dwGrayMask) << 1) | (p); (BYTE *) d += 3 +#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; @@ -882,7 +886,7 @@ static VOID CALLBACK LcdProc(UINT uEventId, UINT uMsg, DWORD dwUser, DWORD dw1, } // LCD line counter calculation -BYTE GetLineCounterGray(VOID) +static BYTE GetLineCounterGray(VOID) { LARGE_INTEGER lLC; BYTE byTime; diff --git a/Sources/Emu48/DISRPL.C b/Sources/Emu48/DISRPL.C index b704550..93bd880 100644 --- a/Sources/Emu48/DISRPL.C +++ b/Sources/Emu48/DISRPL.C @@ -34,7 +34,7 @@ static VOID PutSn(String *str, LPCTSTR szVal, DWORD dwLen) if (str->dwSize == 0) // no buffer allocated { str->dwSize = ALLOCSIZE; // buffer size - VERIFY(str->szBuffer = HeapAlloc(hHeap,0,str->dwSize * sizeof(TCHAR))); + VERIFY(str->szBuffer = (LPTSTR) malloc(str->dwSize * sizeof(TCHAR))); str->dwPos = 0; } @@ -51,7 +51,7 @@ static VOID PutSn(String *str, LPCTSTR szVal, DWORD dwLen) dwMinSize *= ALLOCSIZE; str->dwSize += dwMinSize; // new buffer size - VERIFY(str->szBuffer = HeapReAlloc(hHeap,0,str->szBuffer,str->dwSize * sizeof(TCHAR))); + VERIFY(str->szBuffer = (LPTSTR) realloc(str->szBuffer,str->dwSize * sizeof(TCHAR))); } CopyMemory(&str->szBuffer[str->dwPos],szVal,dwLen * sizeof(TCHAR)); @@ -117,7 +117,7 @@ static DWORD Readx(DWORD *pdwAddr,DWORD n) DWORD i, t; for (i = 0, t = 0; i < n; ++i) - t |= read_nibble(pdwAddr) << (i * 4); + t |= RplReadNibble(pdwAddr) << (i * 4); return t; } @@ -145,6 +145,7 @@ static BOOL BCDx(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,String *str) 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--) @@ -214,10 +215,10 @@ static BOOL BINx(DWORD *pdwAddr,INT nBinLen,String *str) LPBYTE pbyNumber; INT i; - VERIFY(pbyNumber = HeapAlloc(hHeap,0,nBinLen)); + VERIFY(pbyNumber = (LPBYTE) malloc(nBinLen)); for (i = 0; i < nBinLen; ++i) // read data - pbyNumber[i] = read_nibble(pdwAddr); + pbyNumber[i] = RplReadNibble(pdwAddr); // strip leading zeros for (i = nBinLen - 1; pbyNumber[i] == 0 && i > 0; --i) { } @@ -227,7 +228,7 @@ static BOOL BINx(DWORD *pdwAddr,INT nBinLen,String *str) PutC(str,cHex[pbyNumber[i]]); } - HeapFree(hHeap,0,pbyNumber); + free(pbyNumber); return FALSE; } @@ -269,7 +270,7 @@ static BOOL DoHexStream(DWORD *pdwAddr,String *str,UINT *pnLevel) for (;dwLength > 0; --dwLength) { - PutC(str,cHex[read_nibble(pdwAddr)]); // write digit + PutC(str,cHex[RplReadNibble(pdwAddr)]); // write digit } return FALSE; } @@ -321,10 +322,10 @@ static BOOL DoIntStream(DWORD *pdwAddr,String *str,UINT *pnLevel) dwLength -= 5; // object length - VERIFY(pbyData = HeapAlloc(hHeap,0,dwLength)); + VERIFY(pbyData = (LPBYTE) malloc(dwLength)); for (i = 0; i < dwLength; ++i) // read data - pbyData[i] = read_nibble(pdwAddr); + pbyData[i] = RplReadNibble(pdwAddr); if (dwLength == 1) // special implementation for zero { @@ -343,7 +344,7 @@ static BOOL DoIntStream(DWORD *pdwAddr,String *str,UINT *pnLevel) } } - HeapFree(hHeap,0,pbyData); + free(pbyData); return FALSE; } @@ -369,7 +370,7 @@ static BOOL DoReal(DWORD *pdwAddr,String *str,UINT *pnLevel) // get real object content for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) - byNumber[i] = read_nibble(pdwAddr); + byNumber[i] = RplReadNibble(pdwAddr); return BCDx(byNumber,12,3,str); } @@ -383,7 +384,7 @@ BOOL DoERel(DWORD *pdwAddr,String *str,UINT *pnLevel) // get extended real object content for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) - byNumber[i] = read_nibble(pdwAddr); + byNumber[i] = RplReadNibble(pdwAddr); return BCDx(byNumber,15,5,str); } @@ -397,7 +398,7 @@ static BOOL DoCmp(DWORD *pdwAddr,String *str,UINT *pnLevel) // get real part of complex object content for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) - byNumber[i] = read_nibble(pdwAddr); + byNumber[i] = RplReadNibble(pdwAddr); BCDx(byNumber,12,3,str); @@ -405,7 +406,7 @@ static BOOL DoCmp(DWORD *pdwAddr,String *str,UINT *pnLevel) // get imaginary part of complex object content for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) - byNumber[i] = read_nibble(pdwAddr); + byNumber[i] = RplReadNibble(pdwAddr); return BCDx(byNumber,12,3,str); } @@ -419,7 +420,7 @@ static BOOL DoECmp(DWORD *pdwAddr,String *str,UINT *pnLevel) // get real part of extended complex object content for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) - byNumber[i] = read_nibble(pdwAddr); + byNumber[i] = RplReadNibble(pdwAddr); BCDx(byNumber,15,5,str); @@ -427,7 +428,7 @@ static BOOL DoECmp(DWORD *pdwAddr,String *str,UINT *pnLevel) // get imaginary part of extended complex object content for (i = 0; i < ARRAYSIZEOF(byNumber); ++i) - byNumber[i] = read_nibble(pdwAddr); + byNumber[i] = RplReadNibble(pdwAddr); return BCDx(byNumber,15,5,str); } @@ -670,7 +671,7 @@ static BOOL DoHxs(DWORD *pdwAddr,String *str,UINT *pnLevel) for (i = 0; i < dwLength; ++i) { - byVal = read_nibble(pdwAddr); + byVal = RplReadNibble(pdwAddr); // remove leading zeros if (byVal == 0 && bRemove && i + 1 < dwLength) @@ -752,7 +753,7 @@ static BOOL Semi(DWORD *pdwAddr,String *str,UINT *pnLevel) static BOOL DoRrp(DWORD *pdwAddr,String *str,UINT *pnLevel) { DWORD dwOffset,dwObjStart,dwBufferPos,dwAddr; - BOOL bErr; + BOOL bErr = FALSE; dwObjStart = *pdwAddr; // remember start position of RRP dwBufferPos = str->dwPos; // insert address of text @@ -1254,10 +1255,13 @@ static BOOL FetchObj(DWORD *pdwAddr,String *str,UINT *pnLevel) 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; } @@ -1269,12 +1273,14 @@ LPTSTR RplDecodeObject(DWORD dwAddr, DWORD *pdwNxtAddr) 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 - VERIFY(str.szBuffer = HeapReAlloc(hHeap,0,str.szBuffer,str.dwPos * sizeof(str.szBuffer[0]))); + VERIFY(str.szBuffer = (LPTSTR) realloc(str.szBuffer,str.dwPos * sizeof(str.szBuffer[0]))); // return address of next object if (pdwNxtAddr != NULL) *pdwNxtAddr = dwNxtAddr; @@ -1310,7 +1316,7 @@ static VOID PrintHead(DWORD dwStartAddr, DWORD dwEndAddr, String *str) if (dwStartAddr < dwEndAddr) // still show hex nibble { - c = cHex[read_nibble(&dwStartAddr)]; + c = cHex[RplReadNibble(&dwStartAddr)]; } PutC(str,c); // write data content @@ -1342,6 +1348,10 @@ static VOID PrintTail(DWORD dwStartAddr, DWORD dwEndAddr, String *str) { // spaces instead of show address PutS(str,_T(" ")); + + // address has 6 digit + if (dwActAddr >= 0x100000) + PutC(str,_T(' ')); } dwRemain = dwEndAddr - dwActAddr; @@ -1350,7 +1360,7 @@ static VOID PrintTail(DWORD dwStartAddr, DWORD dwEndAddr, String *str) for (; dwRemain > 0; --dwRemain) { // write data content - PutC(str,cHex[read_nibble(&dwActAddr)]); + PutC(str,cHex[RplReadNibble(&dwActAddr)]); } PutS(str,_T("\r\n")); @@ -1444,6 +1454,8 @@ LPTSTR RplCreateObjView(DWORD dwStartAddr, DWORD dwEndAddr, BOOL bSingleObj) LPTSTR lpszObject; DWORD dwLevel,dwAddr,dwNxtAddr; + _ASSERT(RplReadNibble != NULL); // get nibble function defined + lpszObject = NULL; // no memory allocated dwLevel = 0; // nesting level @@ -1465,15 +1477,14 @@ LPTSTR RplCreateObjView(DWORD dwStartAddr, DWORD dwEndAddr, BOOL bSingleObj) PutFS(&str,_T("=%s\r\n"),lpszName); } - PrintHead(dwAddr,dwAddr+5,&str); // write initial head + PrintHead(dwAddr,dwAddr+5,&str); // write initial head do { // check for special RRP handling if (_tcsncmp(lpszObject,_T("DIR\n"),4) == 0) { - LPCTSTR lpszStart; - LPTSTR lpszEnd; + LPCTSTR lpszStart,lpszEnd; lpszStart = lpszEnd = lpszObject; @@ -1525,13 +1536,12 @@ LPTSTR RplCreateObjView(DWORD dwStartAddr, DWORD dwEndAddr, BOOL bSingleObj) while (FALSE); PutS(&str,_T("\r\n")); - // write additional binary data - PrintTail(dwAddr+5,dwNxtAddr,&str); + PrintTail(dwAddr+5,dwNxtAddr,&str); // write additional binary data if (lstrcmp(lpszObject,_T("::")) == 0) ++dwLevel; - HeapFree(hHeap,0,lpszObject); // free object string + free(lpszObject); // free object string lpszObject = NULL; if ( (bSingleObj && dwLevel == 0) // single object decoding? @@ -1554,6 +1564,6 @@ LPTSTR RplCreateObjView(DWORD dwStartAddr, DWORD dwEndAddr, BOOL bSingleObj) PutC(&str,0); // set EOS // release unnecessary allocated buffer memory - VERIFY(str.szBuffer = HeapReAlloc(hHeap,0,str.szBuffer,str.dwPos * sizeof(str.szBuffer[0]))); + 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 index f32fab5..ba2f5cd 100644 --- a/Sources/Emu48/DISRPL.H +++ b/Sources/Emu48/DISRPL.H @@ -19,6 +19,7 @@ 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 index 8b0196f..cd910b5 100644 --- a/Sources/Emu48/EMU48.C +++ b/Sources/Emu48/EMU48.C @@ -13,7 +13,7 @@ #include "kml.h" #include "debugger.h" -#define VERSION "1.50" +#define VERSION "1.53" // #define MONOCHROME // CF_BITMAP clipboard format @@ -59,7 +59,6 @@ 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 hHeap; HANDLE hThread; DWORD lThreadId; HANDLE hEventShutdn; // event handle to stop cpu thread @@ -84,7 +83,7 @@ BOOL bAlwaysDisplayLog = TRUE; BOOL bLoadObjectWarning = TRUE; BOOL bAlwaysOnTop = FALSE; // emulator window always on top BOOL bActFollowsMouse = FALSE; // emulator window activation follows mouse - +BOOL bSingleInstance = FALSE; // multiple emulator instances allowed //################ @@ -95,7 +94,7 @@ BOOL bActFollowsMouse = FALSE; // emulator window activation follows VOID SetWindowTitle(LPCTSTR szString) { - if (szTitle) HeapFree(hHeap,0,szTitle); + if (szTitle) free(szTitle); _ASSERT(hWnd != NULL); if (szString) @@ -111,44 +110,6 @@ VOID SetWindowTitle(LPCTSTR szString) return; } -VOID UpdateWindowStatus(VOID) -{ - if (hWnd) // window open - { - // 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; - - HMENU hMenu = GetMenu(hWnd); // get menu handle - - 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); - } - return; -} - VOID ForceForegroundWindow(HWND hWnd) { // force window to foreground @@ -178,7 +139,7 @@ VOID CopyItemsToClipboard(HWND hWnd) // save selected Listbox Items to Clipboar if ((i = (LONG) SendMessage(hWnd,LB_GETSELCOUNT,0,0)) == 0) return; // no items selected - if ((lpnCount = HeapAlloc(hHeap,0,i * sizeof(INT))) != NULL) + if ((lpnCount = malloc(i * sizeof(INT))) != NULL) { LPTSTR lpszData; HANDLE hClipObj; @@ -223,7 +184,7 @@ VOID CopyItemsToClipboard(HWND hWnd) // save selected Listbox Items to Clipboar GlobalFree(hClipObj); } } - HeapFree(hHeap,0,lpnCount); // free item table + free(lpnCount); // free item table } return; } @@ -327,16 +288,11 @@ static VOID SetCommList(HWND hDlg,LPCTSTR szWireSetting,LPCTSTR szIrSetting) return; } -static INT_PTR CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +static BOOL CALLBACK SettingsGeneralProc(HWND hDlg, UINT uMsg, DWORD wParam, LONG lParam) { HWND hWndInsertAfter; - LPCTSTR szActPort2Filename = _T(""); - - BOOL bPort2CfgChange = FALSE; - BOOL bPort2AttChange = FALSE; - - switch (message) + switch (uMsg) { case WM_INITDIALOG: // init speed checkbox @@ -344,6 +300,12 @@ static INT_PTR CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPA CheckDlgButton(hDlg,IDC_GRAYSCALE,bGrayscale); 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); @@ -351,24 +313,58 @@ static INT_PTR CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPA // set disassebler mode CheckDlgButton(hDlg,(disassembler_mode == HP_MNEMONICS) ? IDC_DISASM_HP : IDC_DISASM_CLASS,BST_CHECKED); - - // 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 radio button - CheckDlgButton(hDlg,bWaveBeep ? IDC_SOUND_WAVE : IDC_SOUND_SPEAKER,BST_CHECKED); - EnableWindow(GetDlgItem(hDlg,IDC_SOUND_SLIDER),bWaveBeep); - - // set combobox parameter - SetCommList(hDlg,szSerialWire,szSerialIr); - if (bCommInit) // disable when port open + return TRUE; + case WM_NOTIFY: + switch (((LPNMHDR) lParam)->code) { - EnableWindow(GetDlgItem(hDlg,IDC_WIRE),FALSE); - EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE); - } + case PSN_KILLACTIVE: + // get speed checkbox value + bRealSpeed = IsDlgButtonChecked(hDlg,IDC_REALSPEED); + 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(hDlgDebug,hWndInsertAfter,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); + } + return TRUE; + } + break; + } + return FALSE; + UNREFERENCED_PARAMETER(wParam); +} + +static BOOL CALLBACK SettingsMemoryProc(HWND hDlg, UINT uMsg, DWORD wParam, LONG lParam) +{ + LPCTSTR szActPort2Filename = _T(""); + + BOOL bPort2CfgChange = FALSE; + BOOL bPort2AttChange = FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: // HP48SX/GX if (cCurrentRomType=='S' || cCurrentRomType=='G' || cCurrentRomType==0) { @@ -405,22 +401,11 @@ static INT_PTR CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPA EnableWindow(GetDlgItem(hDlg,IDC_PORT2WR),FALSE); EnableWindow(GetDlgItem(hDlg,IDC_PORT2),FALSE); EnableWindow(GetDlgItem(hDlg,IDC_PORT2LOAD),FALSE); - if (cCurrentRomType=='X') // HP49G - { - SendDlgItemMessage(hDlg,IDC_IR,CB_RESETCONTENT,0,0); - EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE); - } } return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { - case IDC_SOUND_SPEAKER: - EnableWindow(GetDlgItem(hDlg,IDC_SOUND_SLIDER),FALSE); - return TRUE; - case IDC_SOUND_WAVE: - EnableWindow(GetDlgItem(hDlg,IDC_SOUND_SLIDER),TRUE); - return TRUE; case IDC_PORT2LOAD: if (GetLoadObjectFilename(_T(BIN_FILTER),_T("BIN"))) { @@ -442,12 +427,17 @@ static INT_PTR CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPA CheckDlgButton(hDlg,IDC_PORT2WR,IsFileWriteable(szBufferFilename)); } return TRUE; - case IDOK: + } + 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 bCardsStatus = Chipset.cards_status; + BYTE byCardsStatus = Chipset.cards_status; // port1 disabled? Chipset.cards_status &= ~(PORT1_PRESENT | PORT1_WRITE); @@ -459,7 +449,7 @@ static INT_PTR CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPA } // changed card status in slot1? - if ( ((bCardsStatus ^ Chipset.cards_status) & (PORT1_PRESENT | PORT1_WRITE)) != 0 + if ( ((byCardsStatus ^ Chipset.cards_status) & (PORT1_PRESENT | PORT1_WRITE)) != 0 && (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0 ) { @@ -504,22 +494,7 @@ static INT_PTR CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPA bPort2CfgChange = TRUE; // slot2 configuration changed } } - // get speed checkbox value - bRealSpeed = IsDlgButtonChecked(hDlg,IDC_REALSPEED); - bAlwaysOnTop = IsDlgButtonChecked(hDlg,IDC_ALWAYSONTOP); - bActFollowsMouse = IsDlgButtonChecked(hDlg,IDC_ACTFOLLOWSMOUSE); - 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); - } + if (bPort2CfgChange) // slot2 configuration changed { UINT nOldState = SwitchToState(SM_INVALID); @@ -563,32 +538,83 @@ static INT_PTR CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPA } SwitchToState(nOldState); } - // set disassembler mode - disassembler_mode = IsDlgButtonChecked(hDlg,IDC_DISASM_HP) ? HP_MNEMONICS : CLASS_MNEMONICS; - // set sound data - dwWaveVol = (DWORD) SendDlgItemMessage(hDlg,IDC_SOUND_SLIDER,TBM_GETPOS,0,0); - bWaveBeep = IsDlgButtonChecked(hDlg,IDC_SOUND_WAVE); - // 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)); - // set window Z order - hWndInsertAfter = bAlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST; - SetWindowPos(hWnd,hWndInsertAfter,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); - if (hDlgDebug != NULL) - { - SetWindowPos(hDlgDebug,hWndInsertAfter,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); - } - // no break - case IDCANCEL: - EndDialog(hDlg, LOWORD(wParam)); + return TRUE; } break; } return FALSE; - UNREFERENCED_PARAMETER(lParam); } +static BOOL CALLBACK SettingsPeripheralProc(HWND hDlg, UINT uMsg, DWORD wParam, LONG lParam) +{ + TCHAR cPort[8]; + + 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 radio button + CheckDlgButton(hDlg,bWaveBeep ? IDC_SOUND_WAVE : IDC_SOUND_SPEAKER,BST_CHECKED); + EnableWindow(GetDlgItem(hDlg,IDC_SOUND_SLIDER),bWaveBeep); + + // 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 (bCommInit) // 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_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_SOUND_SPEAKER: + EnableWindow(GetDlgItem(hDlg,IDC_SOUND_SLIDER),FALSE); + return TRUE; + case IDC_SOUND_WAVE: + EnableWindow(GetDlgItem(hDlg,IDC_SOUND_SLIDER),TRUE); + return TRUE; + } + break; + case WM_NOTIFY: + switch (((LPNMHDR) lParam)->code) + { + case PSN_KILLACTIVE: + // set sound data + dwWaveVol = (DWORD) SendDlgItemMessage(hDlg,IDC_SOUND_SLIDER,TBM_GETPOS,0,0); + bWaveBeep = IsDlgButtonChecked(hDlg,IDC_SOUND_WAVE); + // 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; +} + + //################ //# @@ -607,7 +633,7 @@ static UINT SaveChanges(BOOL bAuto) { UINT uReply; - if (pbyRom == NULL) return IDNO; + if (bDocumentAvail == FALSE) return IDNO; if (bAuto) uReply = IDYES; @@ -755,14 +781,50 @@ static LRESULT OnPaint(HWND hWindow) 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); + return 0; +} + // // WM_DROPFILES // -static LRESULT OnDropFiles(HANDLE hFilesInfo) +static LRESULT OnDropFiles(HDROP hFilesInfo) { TCHAR szFileName[MAX_PATH]; WORD wNumFiles,wIndex; - BOOL bSuccess; + BOOL bSuccess = FALSE; // get number of files dropped wNumFiles = DragQueryFile (hFilesInfo,(UINT)-1,NULL,0); @@ -833,7 +895,6 @@ static LRESULT OnFileNew(VOID) SaveBackup(); } if (NewDocument()) SetWindowTitle(_T("Untitled")); - UpdateWindowStatus(); cancel: if (pbyRom) SwitchToState(SM_RUN); return 0; @@ -1028,7 +1089,7 @@ static LRESULT OnViewCopy(VOID) 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); + (LPBITMAPINFO)lpbi, DIB_RGB_COLORS); GlobalUnlock(hClipObj); SetClipboardData(CF_DIB, hClipObj); @@ -1036,13 +1097,13 @@ static LRESULT OnViewCopy(VOID) GetObject(hPalette,sizeof(WORD),&wBits); // memory allocation for temporary palette data - if ((ppal = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(LOGPALETTE) + wBits * sizeof(PALETTEENTRY))) != NULL) + if ((ppal = 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)); - HeapFree(hHeap,0,ppal); + free(ppal); } } DeleteDC(hBmpDC); @@ -1087,13 +1148,80 @@ static LRESULT OnViewReset(VOID) // // 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); - if (DialogBox(hApp, MAKEINTRESOURCE(IDD_SETTINGS), hWnd, (DLGPROC)SettingsProc) == -1) - AbortMessage(_T("Settings Dialog Creation Error !")); + 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 = (DLGPROC) 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 = (DLGPROC) 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 = (DLGPROC) 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; @@ -1104,6 +1232,9 @@ static LRESULT OnViewSettings(VOID) // static LRESULT OnViewScript(VOID) { + TCHAR szKmlFile[MAX_PATH]; + BOOL bKMLChanged,bSucc; + BYTE cType = cCurrentRomType; if (nState != SM_RUN) { @@ -1113,14 +1244,50 @@ static LRESULT OnViewScript(VOID) } 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)) break; - } - while (!InitKML(szCurrentKml,FALSE)); + if (!DisplayChooseKml(cType)) // quit with Cancel + { + if (!bKMLChanged) // KML script not changed + break; // exit loop with current loaded KML script - SetWindowPathTitle(szCurrentFilename); // update window title line - if (pbyRom) SwitchToState(SM_RUN); + // 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 (pbyRom) SwitchToState(SM_RUN); // continue emulation + } + else + { + ResetDocument(); // close document + SetWindowTitle(NULL); + } return 0; } @@ -1271,58 +1438,74 @@ static INT_PTR CALLBACK Disasm(HWND hDlg, UINT message, WPARAM wParam, LPARAM lP { static DWORD dwAddress,dwAddressMax; + enum MEM_MAPPING eMode; LONG i; DWORD dwNxtAddr; - TCHAR *cpStop,szAddress[256] = _T("0"); + 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_MAP,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_DISASM_ROM,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_DISASM_RAM,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_DISASM_PORT1,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_DISASM_PORT2,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDC_DISASM_MAP,BM_SETCHECK,1,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); - disassembler_map = MEM_MAP; // disassemble with mapped modules - dwAddress = _tcstoul(szAddress,&cpStop,16); - dwAddressMax = 0x100000; // greatest address (mapped mode) + dwAddressMax = GetMemDataSize(); + dwAddress = _tcstoul(szAddress,NULL,16); return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { - // decode radio buttons - case IDC_DISASM_MAP: - disassembler_map = MEM_MAP; - dwAddressMax = 0x100000; - return TRUE; - case IDC_DISASM_ROM: - disassembler_map = MEM_ROM; - dwAddressMax = dwRomSize; - return TRUE; - case IDC_DISASM_RAM: - disassembler_map = MEM_RAM; - dwAddressMax = Chipset.Port0Size * 2048; - return TRUE; - case IDC_DISASM_PORT1: - disassembler_map = MEM_PORT1; - dwAddressMax = ((Chipset.cards_status & PORT1_PRESENT) != 0) ? (Chipset.Port1Size * 2048) : 0; - return TRUE; - case IDC_DISASM_PORT2: - disassembler_map = MEM_PORT2; - dwAddressMax = ((cCurrentRomType=='E' || cCurrentRomType=='X') - ? Chipset.Port2Size - : dwPort2Size) - * 2048; - return TRUE; + // 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)); @@ -1332,7 +1515,7 @@ static INT_PTR CALLBACK Disasm(HWND hDlg, UINT message, WPARAM wParam, LPARAM lP if (_istxdigit(szAddress[i]) == FALSE) return FALSE; } - dwAddress = _tcstoul(szAddress,&cpStop,16); + dwAddress = _tcstoul(szAddress,NULL,16); // no break case IDC_DISASM_NEXT: if (dwAddress >= dwAddressMax) @@ -1403,7 +1586,7 @@ 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 !")); + AbortMessage(_T("Disassembler Dialog Box Creation Error!")); if (pbyRom) SwitchToState(SM_RUN); return 0; } @@ -1411,7 +1594,7 @@ static LRESULT OnToolDisasm(VOID) // disasm dialogbox call static LRESULT OnAbout(VOID) { if (DialogBox(hApp, MAKEINTRESOURCE(IDD_ABOUT), hWnd, (DLGPROC)About) == -1) - AbortMessage(_T("About Dialog Box Creation Error !")); + AbortMessage(_T("About Dialog Box Creation Error!")); return 0; } @@ -1479,7 +1662,8 @@ LRESULT CALLBACK MainWndProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lPar case WM_CREATE: return OnCreate(hWindow); case WM_DESTROY: return OnDestroy(hWindow); case WM_PAINT: return OnPaint(hWindow); - case WM_DROPFILES: return OnDropFiles((HANDLE)wParam); + 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: @@ -1557,12 +1741,16 @@ LRESULT CALLBACK MainWndProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lPar int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) { + typedef DWORD (WINAPI *LPFN_STIP)(HANDLE hThread,DWORD dwIdealProcessor); + MSG msg; WNDCLASS wc; + ATOM classAtom; RECT rectWindow; HACCEL hAccel; + LPFN_STIP fnSetThreadIdealProcessor; + DWORD dwProcessor; HSZ hszService, hszTopic; // variables for DDE server - DWORD_PTR dwAffMask; LPTSTR lpFilePart; hApp = hInst; @@ -1577,13 +1765,6 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC } #endif - hHeap = GetProcessHeap(); - if (hHeap == NULL) - { - AbortMessage(_T("Heap creation failed.")); - return FALSE; - } - wc.style = CS_BYTEALIGNCLIENT; wc.lpfnWndProc = (WNDPROC)MainWndProc; wc.cbClsExtra = 0; @@ -1595,7 +1776,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU); wc.lpszClassName = _T("CEmu48"); - if (!RegisterClass(&wc)) + if (!(classAtom = RegisterClass(&wc))) { AbortMessage( _T("CEmu48 class registration failed.\n") @@ -1603,6 +1784,21 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC return FALSE; } + // read emulator settings + GetCurrentDirectory(ARRAYSIZEOF(szCurrentDirectory),szCurrentDirectory); + ReadSettings(); + + // running an instance of me? + if (bSingleInstance && (hWnd = FindWindow(MAKEINTATOM(classAtom),NULL)) != NULL) + { + if (IsIconic(hWnd)) // window minimized + ShowWindow(hWnd,SW_RESTORE); // show window + + // put the window into foreground + ForceForegroundWindow(GetLastActivePopup(hWnd)); + return 0; // quit + } + // Create window rectWindow.left = 0; rectWindow.top = 0; @@ -1610,13 +1806,12 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC rectWindow.bottom = 0; AdjustWindowRect(&rectWindow, WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED, TRUE); - hWnd = CreateWindow(_T("CEmu48"), _T("Emu48"), + hWnd = CreateWindow(MAKEINTATOM(classAtom),_T("Emu48"), WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, rectWindow.right - rectWindow.left, rectWindow.bottom - rectWindow.top, - NULL,NULL,hApp,NULL - ); + NULL,NULL,hApp,NULL); if (hWnd == NULL) { @@ -1630,13 +1825,10 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC QueryPerformanceFrequency(&lFreq); // init high resolution counter QueryPerformanceCounter(&lAppStart); - GetCurrentDirectory(ARRAYSIZEOF(szCurrentDirectory), szCurrentDirectory); szCurrentKml[0] = 0; // no KML file selected - ReadSettings(); + SetSpeed(bRealSpeed); // set speed MruInit(4); // init MRU entries - UpdateWindowStatus(); - // create auto event handle hEventShutdn = CreateEvent(NULL,FALSE,FALSE,NULL); if (hEventShutdn == NULL) @@ -1656,17 +1848,26 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC DestroyWindow(hWnd); return FALSE; } + + // SetThreadIdealProcessor() is available since Windows NT4.0 + fnSetThreadIdealProcessor = (LPFN_STIP) GetProcAddress(GetModuleHandle(_T("kernel32")), + "SetThreadIdealProcessor"); + + // bind Saturn CPU emulation thread to current ideal processor + dwProcessor = (fnSetThreadIdealProcessor != NULL) // running on NT4.0 or later + ? fnSetThreadIdealProcessor(hThread,MAXIMUM_PROCESSORS) // get ideal processor no. + : 0; // select 1st processor + // on multiprocessor machines for QueryPerformanceCounter() - dwAffMask = SetThreadAffinityMask(hThread,1); - _ASSERT(dwAffMask != 0); + 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)) + 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 @@ -1720,9 +1921,9 @@ start: { if ( !TranslateAccelerator(hWnd, hAccel, &msg) && (hDlgDebug == NULL || !IsDialogMessage(hDlgDebug, &msg)) - && (hDlgFind == NULL || !IsDialogMessage(hDlgFind, &msg)) + && (hDlgFind == NULL || !IsDialogMessage(hDlgFind, &msg)) && (hDlgProfile == NULL || !IsDialogMessage(hDlgProfile, &msg)) - && (hDlgRplObjView == NULL || !IsDialogMessage(hDlgRplObjView, &msg))) + && (hDlgRplObjView == NULL || !IsDialogMessage(hDlgRplObjView, &msg))) { TranslateMessage(&msg); DispatchMessage(&msg); @@ -1753,6 +1954,7 @@ start: _ASSERT(pKml == NULL); // KML script not closed _ASSERT(szTitle == NULL); // freed allocated memory _ASSERT(hPalette == NULL); // freed resource memory + _CrtDumpMemoryLeaks(); // show memory leaks return (int) msg.wParam; UNREFERENCED_PARAMETER(lpCmdLine); diff --git a/Sources/Emu48/EMU48.DSP b/Sources/Emu48/EMU48.DSP index fe38c25..11ac5a7 100644 --- a/Sources/Emu48/EMU48.DSP +++ b/Sources/Emu48/EMU48.DSP @@ -7,21 +7,21 @@ CFG=Emu48 - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run -!MESSAGE +!MESSAGE !MESSAGE NMAKE /f "Emu48.mak". -!MESSAGE +!MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE +!MESSAGE !MESSAGE NMAKE /f "Emu48.mak" CFG="Emu48 - Win32 Release" -!MESSAGE +!MESSAGE !MESSAGE Possible choices for configuration are: -!MESSAGE +!MESSAGE !MESSAGE "Emu48 - Win32 Release" (based on "Win32 (x86) Application") !MESSAGE "Emu48 - Win32 Debug" (based on "Win32 (x86) Application") !MESSAGE "Emu48 - Win32 Release Unicode" (based on "Win32 (x86) Application") !MESSAGE "Emu48 - Win32 Debug Unicode" (based on "Win32 (x86) Application") -!MESSAGE +!MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 @@ -48,14 +48,14 @@ RSC=rc.exe # ADD CPP /nologo /Gr /MT /W3 /GX /O2 /Ob2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "STRICT" /D "REGISTRY" /Yu"pch.h" /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x40c /d "NDEBUG" -# ADD RSC /l 0x40c /d "NDEBUG" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib comctl32.lib advapi32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib comctl32.lib advapi32.lib ws2_32.lib /nologo /subsystem:windows /machine:I386 !ELSEIF "$(CFG)" == "Emu48 - Win32 Debug" @@ -74,14 +74,14 @@ LINK32=link.exe # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "STRICT" /D "REGISTRY" /FR /Yu"pch.h" /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x40c /d "_DEBUG" -# ADD RSC /l 0x40c /d "_DEBUG" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib comctl32.lib advapi32.lib /nologo /subsystem:windows /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib comctl32.lib advapi32.lib ws2_32.lib /nologo /subsystem:windows /debug /machine:I386 !ELSEIF "$(CFG)" == "Emu48 - Win32 Release Unicode" @@ -101,14 +101,14 @@ LINK32=link.exe # ADD CPP /nologo /Gr /MT /W3 /GX /O2 /Ob2 /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "STRICT" /D "REGISTRY" /Yu"pch.h" /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x40c /d "NDEBUG" -# ADD RSC /l 0x40c /d "NDEBUG" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib comctl32.lib advapi32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib comctl32.lib advapi32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib comctl32.lib advapi32.lib ws2_32.lib /nologo /subsystem:windows /machine:I386 !ELSEIF "$(CFG)" == "Emu48 - Win32 Debug Unicode" @@ -128,16 +128,17 @@ LINK32=link.exe # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "STRICT" /D "REGISTRY" /FR /Yu"pch.h" /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x40c /d "_DEBUG" -# ADD RSC /l 0x40c /d "_DEBUG" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +# SUBTRACT RSC /x BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib comctl32.lib advapi32.lib /nologo /subsystem:windows /debug /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib comctl32.lib advapi32.lib /nologo /subsystem:windows /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib comctl32.lib advapi32.lib ws2_32.lib /nologo /subsystem:windows /debug /machine:I386 -!ENDIF +!ENDIF # Begin Target @@ -166,6 +167,10 @@ SOURCE=.\disasm.c # End Source File # Begin Source File +SOURCE=.\dismem.c +# End Source File +# Begin Source File + SOURCE=.\display.c # End Source File # Begin Source File @@ -235,6 +240,10 @@ SOURCE=.\pch.c # End Source File # Begin Source File +SOURCE=.\redeye.c +# End Source File +# Begin Source File + SOURCE=.\rpl.c # End Source File # Begin Source File @@ -257,6 +266,10 @@ SOURCE=.\symbfile.c SOURCE=.\timer.c # End Source File +# Begin Source File + +SOURCE=.\udp.c +# End Source File # End Group # Begin Group "Header Files" diff --git a/Sources/Emu48/EMU48.H b/Sources/Emu48/EMU48.H index 4a0a6a0..b53fbba 100644 --- a/Sources/Emu48/EMU48.H +++ b/Sources/Emu48/EMU48.H @@ -35,24 +35,18 @@ #define SM_RETURN 2 #define SM_SLEEP 3 -#define S_ERR_NO 0 // stack errorcodes +#define S_ERR_NO 0 // stack errorcodes #define S_ERR_OBJECT 1 -#define S_ERR_BINARY 2 -#define S_ERR_ASCII 3 +#define S_ERR_BINARY 2 +#define S_ERR_ASCII 3 #define BAD_OB (0xFFFFFFFF) // bad object -#define NO_SERIAL "disabled" // port not open +#define NO_SERIAL "disabled" // port not open #define HP_MNEMONICS FALSE // disassembler mnenomics mode #define CLASS_MNEMONICS TRUE -#define MEM_MAP 0 // memory module definition -#define MEM_ROM 1 -#define MEM_RAM 2 -#define MEM_PORT1 3 -#define MEM_PORT2 4 - #define MACRO_OFF 0 // macro recorder off #define MACRO_NEW 1 #define MACRO_PLAY 2 @@ -62,12 +56,17 @@ #define DISP_MENUE 0x04 #define DISP_ANNUN 0x08 +#define ROMPAGESIZE (1<<12) // ROM dirty page size in nibbles + // 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 }; + // Emu48.c extern HPALETTE hPalette; extern HPALETTE hOldPalette; @@ -90,7 +89,6 @@ extern LARGE_INTEGER lFreq; extern LARGE_INTEGER lAppStart; extern DWORD idDdeInst; extern UINT uCF_HpObj; -extern HANDLE hHeap; extern HINSTANCE hApp; extern HWND hWnd; extern HWND hDlgDebug; @@ -109,11 +107,11 @@ extern BOOL bAlwaysDisplayLog; extern BOOL bLoadObjectWarning; extern BOOL bAlwaysOnTop; extern BOOL bActFollowsMouse; +extern BOOL bSingleInstance; extern HANDLE hThread; extern DWORD lThreadId; extern VOID SetWindowTitle(LPCTSTR szString); extern VOID CopyItemsToClipboard(HWND hWnd); -extern VOID UpdateWindowStatus(VOID); extern VOID ForceForegroundWindow(HWND hWnd); // mru.c @@ -174,6 +172,7 @@ extern UINT nState; extern UINT nNextState; extern BOOL bRealSpeed; extern BOOL bKeySlow; +extern UINT nOpcSlow; extern BOOL bCommInit; extern CHIPSET Chipset; extern TCHAR szSerialWire[16]; @@ -198,6 +197,7 @@ extern WORD wInstrRp; 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); @@ -217,6 +217,7 @@ 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; @@ -225,6 +226,8 @@ extern LPBYTE Port2; extern LPBYTE pbyRom; extern BOOL bRomWriteable; extern DWORD dwRomSize; +extern LPBYTE pbyRomDirtyPage; +extern DWORD dwRomDirtyPageSize; extern WORD wRomCrc; extern LPBYTE pbyPort2; extern BOOL bPort2Writeable; @@ -309,12 +312,22 @@ extern VOID KeyboardEvent(BOOL bPress, UINT out, UINT in); 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); @@ -339,11 +352,19 @@ extern VOID RCKBp(CHIPSET* w); // 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 WORD disassembler_map; -extern BYTE read_nibble(DWORD *p); extern DWORD disassemble(DWORD addr, LPTSTR out); // Symbfile.c @@ -385,7 +406,7 @@ static __inline int YesNoCancelMessage(LPCTSTR szMessage,UINT uStyle) {return Me static __inline LPTSTR DuplicateString(LPCTSTR szString) { UINT uLength = lstrlen(szString) + 1; - LPTSTR szDup = HeapAlloc(hHeap,0,uLength*sizeof(szDup[0])); + LPTSTR szDup = malloc(uLength*sizeof(szDup[0])); lstrcpy(szDup,szString); return szDup; } diff --git a/Sources/Emu48/EMU48.RC b/Sources/Emu48/EMU48.RC index e36e8f8..e67e8c1 100644 --- a/Sources/Emu48/EMU48.RC +++ b/Sources/Emu48/EMU48.RC @@ -77,12 +77,40 @@ BEGIN BOTTOMMARGIN, 145 END - IDD_SETTINGS, DIALOG + IDD_SET_GENERAL, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 160 - TOPMARGIN, 4 - BOTTOMMARGIN, 280 + RIGHTMARGIN, 244 + VERTGUIDE, 14 + VERTGUIDE, 161 + VERTGUIDE, 168 + VERTGUIDE, 237 + TOPMARGIN, 7 + BOTTOMMARGIN, 127 + END + + IDD_SET_MEMORY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 244 + VERTGUIDE, 14 + VERTGUIDE, 237 + TOPMARGIN, 7 + BOTTOMMARGIN, 127 + END + + IDD_SET_PERIPHERAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 244 + VERTGUIDE, 14 + VERTGUIDE, 147 + VERTGUIDE, 154 + VERTGUIDE, 161 + VERTGUIDE, 237 + TOPMARGIN, 7 + BOTTOMMARGIN, 127 + HORZGUIDE, 82 END IDD_CHOOSEKML, DIALOG @@ -157,6 +185,22 @@ BEGIN BOTTOMMARGIN, 74 END + IDD_DEBUG_MEMSAVE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 257 + TOPMARGIN, 7 + BOTTOMMARGIN, 58 + END + + IDD_DEBUG_MEMLOAD, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 257 + TOPMARGIN, 7 + BOTTOMMARGIN, 58 + END + IDD_DEBUG_SETTINGS, DIALOG BEGIN LEFTMARGIN, 7 @@ -252,69 +296,88 @@ 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 © 2010 Christoph Gießelink && Sébastien Carlier", + LTEXT "Copyright © 2012 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 | ES_READONLY END -IDD_SETTINGS DIALOG DISCARDABLE 0, 0, 167, 287 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Settings" +IDD_SET_GENERAL DIALOG DISCARDABLE 0, 0, 251, 134 +STYLE WS_CHILD | WS_VISIBLE | WS_CAPTION +CAPTION "General" FONT 8, "MS Sans Serif" BEGIN CONTROL "Authentic Calculator Speed",IDC_REALSPEED,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,13,13,100,10 + BS_AUTOCHECKBOX | WS_TABSTOP,14,17,133,10 CONTROL "Enable Virtual LCD Delay",IDC_GRAYSCALE,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,13,25,100,10 - CONTROL "Always On Top",IDC_ALWAYSONTOP,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,13,37,65,10 - CONTROL "Activation Follows Mouse",IDC_ACTFOLLOWSMOUSE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,49,100,10 + BS_AUTOCHECKBOX | WS_TABSTOP,14,28,133,10 + CONTROL "Always On Top",IDC_ALWAYSONTOP,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,14,40,133,10 + CONTROL "Activation Follows Mouse",IDC_ACTFOLLOWSMOUSE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,14,52,133,10 + CONTROL "Single Instance",IDC_SINGLEINSTANCE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,14,64,133,10 CONTROL "Automatically Save Files",IDC_AUTOSAVE,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,13,61,89,10 + BS_AUTOCHECKBOX | WS_TABSTOP,14,76,133,10 CONTROL "Automatically Save Files On Exit",IDC_AUTOSAVEONEXIT, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,73,114,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,88,133,10 CONTROL "Show Load Object Warning",IDC_OBJECTLOADWARNING,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,13,85,102,10 + BS_AUTOCHECKBOX | WS_TABSTOP,14,100,133,10 CONTROL "Always Show KML Compilation Result",IDC_ALWAYSDISPLOG, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,97,133,10 - GROUPBOX "General",IDC_STATIC,7,4,153,107 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,112,133,10 + GROUPBOX "General",IDC_STATIC,7,7,148,120 CONTROL "HP Mnemonics",IDC_DISASM_HP,"Button",BS_AUTORADIOBUTTON | - WS_GROUP | WS_TABSTOP,13,125,65,11 + WS_GROUP | WS_TABSTOP,168,21,69,11 CONTROL "Class Mnemonics",IDC_DISASM_CLASS,"Button", - BS_AUTORADIOBUTTON,84,125,70,11 - GROUPBOX "Disassembler",IDC_STATIC,7,114,153,28 - LTEXT "Volume",IDC_STATIC,13,158,24,8 - CONTROL "Slider1",IDC_SOUND_SLIDER,"msctls_trackbar32", - TBS_AUTOTICKS | WS_TABSTOP,39,153,68,18 - CONTROL "Speaker",IDC_SOUND_SPEAKER,"Button",BS_AUTORADIOBUTTON | - WS_GROUP | WS_TABSTOP,111,152,43,10 - CONTROL "Wave",IDC_SOUND_WAVE,"Button",BS_AUTORADIOBUTTON,111, - 163,43,10 - GROUPBOX "Sound",IDC_STATIC,7,144,153,34 + BS_AUTORADIOBUTTON,168,35,69,11 + GROUPBOX "Disassembler",IDC_STATIC,161,7,83,120 +END + +IDD_SET_MEMORY DIALOG DISCARDABLE 0, 0, 251, 134 +STYLE WS_CHILD | WS_VISIBLE | WS_CAPTION +CAPTION "Memory" +FONT 8, "MS Sans Serif" +BEGIN CONTROL "Port 1 is Plugged",IDC_PORT1EN,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,13,189,67,10 + WS_TABSTOP,14,20,67,10 CONTROL "Port 1 is Writeable",IDC_PORT1WR,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,84,189,69,10 + BS_AUTOCHECKBOX | WS_TABSTOP,124,20,69,10 CONTROL "Port 2 is Shared",IDC_PORT2ISSHARED,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,13,201,65,10 + BS_AUTOCHECKBOX | WS_TABSTOP,14,32,65,10 CONTROL "Port 2 is Writeable",IDC_PORT2WR,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,84,201,69,10 - LTEXT "Port 2 File :",IDC_STATIC,13,216,37,8 - EDITTEXT IDC_PORT2,51,214,94,12,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_PORT2LOAD,145,214,10,12 - GROUPBOX "Memory Cards",IDC_STATIC,7,180,153,51 - LTEXT "Wire:",IDC_STATIC,13,245,17,8 - COMBOBOX IDC_WIRE,31,243,48,42,CBS_DROPDOWNLIST | WS_VSCROLL | + BS_AUTOCHECKBOX | WS_TABSTOP,124,32,69,10 + LTEXT "Port 2 File :",IDC_STATIC,14,47,37,8 + EDITTEXT IDC_PORT2,52,45,175,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_PORT2LOAD,227,45,10,12 + GROUPBOX "Memory Cards",IDC_STATIC,7,7,237,58 +END + +IDD_SET_PERIPHERAL DIALOG DISCARDABLE 0, 0, 251, 134 +STYLE WS_CHILD | WS_VISIBLE | WS_CAPTION +CAPTION "Peripheral" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Volume",IDC_STATIC,14,21,24,8 + CONTROL "Slider1",IDC_SOUND_SLIDER,"msctls_trackbar32", + TBS_AUTOTICKS | WS_TABSTOP,40,16,84,18 + CONTROL "Speaker",IDC_SOUND_SPEAKER,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,135,20,43,10 + CONTROL "Wave",IDC_SOUND_WAVE,"Button",BS_AUTORADIOBUTTON,194,20, + 43,10 + GROUPBOX "Sound",IDC_STATIC,7,7,237,34 + LTEXT "IP Address:",IDC_STATIC,14,60,37,8 + LTEXT "Port:",IDC_STATIC,119,60,16,8 + EDITTEXT IDC_IR_ADDR,14,70,101,12,ES_AUTOHSCROLL + EDITTEXT IDC_IR_PORT,119,70,28,12,ES_NUMBER + GROUPBOX "Infrared Printer",IDC_STATIC,7,43,147,50 + LTEXT "Wire:",IDC_STATIC,168,58,17,8 + COMBOBOX IDC_WIRE,189,56,48,42,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "IR:",IDC_STATIC,89,245,9,8 - COMBOBOX IDC_IR,107,243,48,43,CBS_DROPDOWNLIST | WS_VSCROLL | + LTEXT "IR:",IDC_STATIC,168,74,9,8 + COMBOBOX IDC_IR,189,72,48,43,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Serial Ports",IDC_STATIC,7,233,153,27 - DEFPUSHBUTTON "OK",IDOK,9,266,50,14 - PUSHBUTTON "Cancel",IDCANCEL,107,266,50,14 + GROUPBOX "Serial Ports",IDC_STATIC,161,43,83,50 END IDD_CHOOSEKML DIALOG DISCARDABLE 0, 0, 195, 66 @@ -362,19 +425,12 @@ BEGIN PUSHBUTTON "&Next Address",IDC_DISASM_NEXT,99,144,47,14 PUSHBUTTON "&Copy Data",IDC_DISASM_COPY,150,144,47,14 PUSHBUTTON "Cancel",IDCANCEL,201,144,47,14 + LTEXT "Mapping Mode:",IDC_DISASM_MODE_TEXT,12,17,45,8 + COMBOBOX IDC_DISASM_MODE,60,14,35,90,CBS_DROPDOWNLIST | + WS_TABSTOP GROUPBOX "Module",IDC_DISASM_MODULE,7,5,241,26 - CONTROL "Map",IDC_DISASM_MAP,"Button",BS_AUTORADIOBUTTON | - WS_GROUP | WS_TABSTOP,14,16,37,10 - CONTROL "ROM",IDC_DISASM_ROM,"Button",BS_AUTORADIOBUTTON,61,16, - 37,10 - CONTROL "RAM",IDC_DISASM_RAM,"Button",BS_AUTORADIOBUTTON,108,16, - 37,10 - CONTROL "Port 1",IDC_DISASM_PORT1,"Button",BS_AUTORADIOBUTTON, - 155,16,37,10 - CONTROL "Port 2",IDC_DISASM_PORT2,"Button",BS_AUTORADIOBUTTON, - 202,16,37,10 - LISTBOX IDC_DISASM_WIN,7,37,241,100,NOT LBS_NOTIFY | - LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | + LISTBOX IDC_DISASM_WIN,7,37,241,100,NOT LBS_NOTIFY | + LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP END @@ -543,6 +599,36 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,93,60,50,14 END +IDD_DEBUG_MEMSAVE DIALOG DISCARDABLE 0, 0, 264, 65 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Save Memory Data" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "File:",IDC_STATIC,7,10,14,8 + EDITTEXT IDC_DEBUG_DATA_FILE,25,7,181,14,ES_AUTOHSCROLL + 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 + 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 + PUSHBUTTON "Cancel",IDCANCEL,207,44,50,14 +END + +IDD_DEBUG_MEMLOAD DIALOG DISCARDABLE 0, 0, 264, 65 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Load Memory Data" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "File:",IDC_STATIC,7,10,14,8 + EDITTEXT IDC_DEBUG_DATA_FILE,25,7,181,14,ES_AUTOHSCROLL + 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 + PUSHBUTTON "Cancel",IDCANCEL,207,44,50,14 +END + IDD_DEBUG_SETTINGS DIALOG DISCARDABLE 0, 0, 184, 116 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Debugger Settings" @@ -602,8 +688,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,5,0,0 - PRODUCTVERSION 1,5,0,0 + FILEVERSION 1,5,3,0 + PRODUCTVERSION 1,5,3,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -620,12 +706,12 @@ BEGIN BEGIN VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0" VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0" - VALUE "FileVersion", "1, 5, 0, 0\0" + VALUE "FileVersion", "1, 5, 3, 0\0" VALUE "InternalName", "Emu48\0" - VALUE "LegalCopyright", "Copyright © 2010\0" + VALUE "LegalCopyright", "Copyright © 2012\0" VALUE "OriginalFilename", "Emu48.exe\0" VALUE "ProductName", "Emu48\0" - VALUE "ProductVersion", "1, 5, 0, 0\0" + VALUE "ProductVersion", "1, 5, 3, 0\0" END END BLOCK "VarFileInfo" @@ -791,6 +877,9 @@ BEGIN , GRAYED END MENUITEM SEPARATOR + MENUITEM "&Load Memory Data...", ID_DEBUG_MEM_LOAD + MENUITEM "S&ave Memory Data...", ID_DEBUG_MEM_SAVE + MENUITEM SEPARATOR MENUITEM "&RPL Object Viewer...", ID_DEBUG_MEM_RPLVIEW END END diff --git a/Sources/Emu48/ENGINE.C b/Sources/Emu48/ENGINE.C index b88b2d0..44a0367 100644 --- a/Sources/Emu48/ENGINE.C +++ b/Sources/Emu48/ENGINE.C @@ -19,6 +19,7 @@ UINT nState = SM_INVALID; UINT nNextState = SM_RUN; BOOL bRealSpeed = FALSE; BOOL bKeySlow = FALSE; // slow down for key emulation +UINT nOpcSlow = 0; // no. of opcodes to slow down BOOL bCommInit = FALSE; // COM port not open CHIPSET Chipset; @@ -275,7 +276,7 @@ static __inline VOID CheckDisp(BOOL bSync) static __inline VOID AdjustSpeed(VOID) // adjust emulation speed { - if (bCpuSlow || bKeySlow) // emulation slow down + if (bCpuSlow || bKeySlow || nOpcSlow > 0) // emulation slow down { DWORD dwCycles,dwTicks; @@ -298,6 +299,8 @@ static __inline VOID AdjustSpeed(VOID) // adjust emulation speed dwOldCyc += T2CYCLES; // adjust cycles reference dwSpeedRef += dwTickRef; // adjust reference time } + + if (nOpcSlow > 0) --nOpcSlow; // decr. slow down opcode counter } LeaveCriticalSection(&csSlowLock); } @@ -321,26 +324,34 @@ VOID CheckSerial(VOID) return; } +VOID InitAdjustSpeed(VOID) +{ + // slow down function not initalized + if (!bCpuSlow && !bKeySlow && nOpcSlow == 0) + { + LARGE_INTEGER lTime; // sample timer ticks + // save reference cycles + dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); + QueryPerformanceCounter(&lTime); // get timer ticks + dwSpeedRef = lTime.LowPart; // save reference time + } + return; +} + VOID AdjKeySpeed(VOID) // slow down key repeat { WORD i; BOOL bKey; - if (bCpuSlow) return; // no need to slow down - bKey = FALSE; // search for a pressed key for (i = 0;i < ARRAYSIZEOF(Chipset.Keyboard_Row) && !bKey;++i) bKey = (Chipset.Keyboard_Row[i] != 0); EnterCriticalSection(&csSlowLock); { - if (!bKeySlow && bKey) // key pressed, init variables + if (bKey) // key pressed { - LARGE_INTEGER lTime; // sample timer ticks - // save reference cycles - dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); - QueryPerformanceCounter(&lTime); // get timer ticks - dwSpeedRef = lTime.LowPart; // save reference time + InitAdjustSpeed(); // init variables if necessary } bKeySlow = bKey; // save new state } @@ -354,11 +365,7 @@ VOID SetSpeed(BOOL bAdjust) // set emulation speed { if (bAdjust) // switch to real speed { - LARGE_INTEGER lTime; // sample timer ticks - // save reference cycles - dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); - QueryPerformanceCounter(&lTime); // get timer ticks - dwSpeedRef = lTime.LowPart; // save reference time + InitAdjustSpeed(); // init variables if necessary } bCpuSlow = bAdjust; // save emulation speed } @@ -412,7 +419,6 @@ UINT SwitchToState(UINT nNewState) bInterrupt = TRUE; SuspendDebugger(); // suspend debugger while (nState!=nNextState) Sleep(0); - UpdateWindowStatus(); break; case SM_RETURN: // -> Return DisableDebugger(); // disable debugger @@ -425,7 +431,6 @@ UINT SwitchToState(UINT nNewState) nNextState = SM_RETURN; SetEvent(hEventShutdn); WaitForSingleObject(hThread,INFINITE); - UpdateWindowStatus(); break; case SM_SLEEP: // -> Sleep nNextState = SM_SLEEP; @@ -449,7 +454,6 @@ UINT SwitchToState(UINT nNewState) ResumeDebugger(); SetEvent(hEventShutdn); while (nState!=nNextState) Sleep(0); - UpdateWindowStatus(); break; case SM_RETURN: // -> Return DisableDebugger(); // disable debugger @@ -461,7 +465,6 @@ UINT SwitchToState(UINT nNewState) nNextState = SM_SLEEP; SetEvent(hEventShutdn); while (nState!=nNextState) Sleep(0); - UpdateWindowStatus(); break; } break; @@ -479,7 +482,6 @@ UINT SwitchToState(UINT nNewState) nNextState = SM_INVALID; SetEvent(hEventShutdn); while (nState!=nNextState) Sleep(0); - UpdateWindowStatus(); break; case SM_RETURN: // -> Return DisableDebugger(); // disable debugger @@ -489,7 +491,6 @@ UINT SwitchToState(UINT nNewState) nNextState = SM_RETURN; SetEvent(hEventShutdn); WaitForSingleObject(hThread,INFINITE); - UpdateWindowStatus(); break; } break; @@ -603,6 +604,7 @@ loop: dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF); QueryPerformanceCounter(&lDummyInt); dwSpeedRef = lDummyInt.LowPart; + nOpcSlow = 0; // no opcodes to slow down } } if (Chipset.SoftInt) diff --git a/Sources/Emu48/EXTERNAL.C b/Sources/Emu48/EXTERNAL.C index 3021716..af00234 100644 --- a/Sources/Emu48/EXTERNAL.C +++ b/Sources/Emu48/EXTERNAL.C @@ -66,7 +66,7 @@ static __inline VOID BeepWave(DWORD dwFrequency,DWORD dwDuration) // (samp/sec) * msecs * (secs/msec) = samps wh.dwBufferLength = (DWORD) ((QWORD) MUSIC_FREQ * dwDuration / 1000); - VERIFY(wh.lpData = HeapAlloc(hHeap,0,wh.dwBufferLength)); + VERIFY(wh.lpData = malloc(wh.dwBufferLength)); wh.dwBytesRecorded = 0; wh.dwUser = 0; wh.dwFlags = 0; @@ -86,7 +86,7 @@ static __inline VOID BeepWave(DWORD dwFrequency,DWORD dwDuration) VERIFY(waveOutUnprepareHeader(hSoundDevice,&wh,sizeof(wh)) == MMSYSERR_NOERROR); VERIFY(waveOutClose(hSoundDevice) == MMSYSERR_NOERROR); - HeapFree(hHeap,0,wh.lpData); + free(wh.lpData); CloseHandle(hEventSound); return; } diff --git a/Sources/Emu48/FETCH.C b/Sources/Emu48/FETCH.C index b9a98d8..2260eb7 100644 --- a/Sources/Emu48/FETCH.C +++ b/Sources/Emu48/FETCH.C @@ -501,7 +501,7 @@ static const JMPTAB o8081_[] = static const JMPTAB o808_[] = { o8080, F, - o8081_, 4, + o8081_, 4, o8082X, F, o8083, F, o8084n, F, diff --git a/Sources/Emu48/FILES.C b/Sources/Emu48/FILES.C index 6083656..f1239ad 100644 --- a/Sources/Emu48/FILES.C +++ b/Sources/Emu48/FILES.C @@ -23,6 +23,8 @@ 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 @@ -33,6 +35,8 @@ 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 LPBYTE pbyPort2 = NULL; @@ -45,7 +49,6 @@ WORD wPort2Crc = 0; // fingerprint of port2 BOOL bBackup = FALSE; static HANDLE hRomFile = NULL; -static HANDLE hRomMap = NULL; static HANDLE hPort2File = NULL; static HANDLE hPort2Map = NULL; @@ -61,6 +64,7 @@ static CHIPSET BackupChipset; static LPBYTE BackupPort0; static LPBYTE BackupPort1; static LPBYTE BackupPort2; +static BOOL bRomPacked; //################ //# @@ -209,6 +213,7 @@ typedef struct tnode 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; @@ -219,14 +224,17 @@ static BOOL PatchNibble(DWORD dwAddress, BYTE byPatch) TREENODE *p; _ASSERT(pbyRom); // ROM defined - if ((p = HeapAlloc(hHeap,0,sizeof(TREENODE))) == NULL) + if ((p = 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 @@ -244,7 +252,7 @@ static VOID RestorePatches(VOID) pbyRom[nodePatch->dwAddress] = nodePatch->byROM; p = nodePatch->next; // save pointer to next node - HeapFree(hHeap,0,nodePatch); // free node + free(nodePatch); // free node nodePatch = p; // new node } return; @@ -255,32 +263,42 @@ VOID UpdatePatches(BOOL bPatch) TREENODE *p = nodePatch; _ASSERT(pbyRom); // ROM defined - while (p != NULL) + if (bPatch) // patch ROM { - if (bPatch) // patch ROM + if (p) // something in patch list { - if (!p->bPatch) // patch only if not patched - { - // use original data for patch restore - p->byROM = pbyRom[p->dwAddress]; + // goto last element in list + for (; p->next != NULL; p = p->next) {} - // restore patch data - pbyRom[p->dwAddress] = p->byPatch; - p->bPatch = TRUE; // address patched - } - else + do { - _ASSERT(FALSE); // call ROM patch on a patched ROM + 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 + } + else // restore ROM + { + for (; p != NULL; p = p->next) { // restore original data pbyRom[p->dwAddress] = p->byROM; p->bPatch = FALSE; // address not patched } - - p = p->next; // next node } return; } @@ -311,7 +329,7 @@ BOOL PatchRom(LPCTSTR szFilename) CloseHandle(hFile); return FALSE; } - lpBuf = HeapAlloc(hHeap,0,dwFileSizeLow+1); + lpBuf = malloc(dwFileSizeLow+1); if (lpBuf == NULL) { CloseHandle(hFile); @@ -360,7 +378,7 @@ BOOL PatchRom(LPCTSTR szFilename) ++nPos; } } - HeapFree(hHeap,0,lpBuf); + free(lpBuf); return TRUE; } @@ -377,6 +395,8 @@ 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; @@ -398,34 +418,34 @@ BOOL CrcRom(WORD *pwChk) // calculate fingerprint of ROM BOOL MapRom(LPCTSTR szFilename) { - DWORD dwFileSizeHigh; + DWORD dwSize,dwFileSize,dwRead; // open ROM for writing - BOOL bWrite = (cCurrentRomType == 'X') ? bRomWriteable : FALSE; + BOOL bRomRW = (cCurrentRomType == 'X') ? bRomWriteable : FALSE; if (pbyRom != NULL) { return FALSE; } SetCurrentDirectory(szEmuDirectory); - if (bWrite) // ROM writeable + if (bRomRW) // ROM writeable { hRomFile = CreateFile(szFilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, + FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hRomFile == INVALID_HANDLE_VALUE) { - bWrite = FALSE; // ROM not writeable + bRomRW = FALSE; // ROM not writeable hRomFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, + FILE_FLAG_SEQUENTIAL_SCAN, NULL); } } @@ -436,7 +456,7 @@ BOOL MapRom(LPCTSTR szFilename) FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, + FILE_FLAG_SEQUENTIAL_SCAN, NULL); } SetCurrentDirectory(szCurrentDirectory); @@ -445,49 +465,136 @@ BOOL MapRom(LPCTSTR szFilename) hRomFile = NULL; return FALSE; } - dwRomSize = GetFileSize(hRomFile, &dwFileSizeHigh); - if (dwFileSizeHigh != 0) - { // file is too large. + dwRomSize = GetFileSize(hRomFile, NULL); + + if (dwRomSize <= 4) + { // file is too small. CloseHandle(hRomFile); hRomFile = NULL; dwRomSize = 0; return FALSE; } - hRomMap = CreateFileMapping(hRomFile, NULL, bWrite ? PAGE_READWRITE : PAGE_WRITECOPY, 0, dwRomSize, NULL); - if (hRomMap == NULL) - { - CloseHandle(hRomFile); - hRomFile = NULL; - dwRomSize = 0; - return FALSE; - } - if (GetLastError() == ERROR_ALREADY_EXISTS) - { - AbortMessage(_T("Sharing file mapping handle.")); - } - pbyRom = MapViewOfFile(hRomMap, bWrite ? FILE_MAP_WRITE : FILE_MAP_COPY, 0, 0, dwRomSize); + + // read the first 4 bytes + ReadFile(hRomFile,&dwSize,sizeof(dwSize),&dwRead,NULL); + + 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 = VirtualAlloc(NULL,dwRomSize,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE); if (pbyRom == NULL) { - CloseHandle(hRomMap); CloseHandle(hRomFile); - hRomMap = NULL; 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 = calloc(dwRomDirtyPageSize,sizeof(*pbyRomDirtyPage)); + if (pbyRomDirtyPage == NULL) + { + VirtualFree(pbyRom,0,MEM_RELEASE); // 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 + { + dwSize = dwRomSize; // destination start address + while (dwFileSize > 0) // unpack source + { + BYTE byValue = pbyRom[--dwFileSize]; + pbyRom[--dwSize] = byValue >> 4; + pbyRom[--dwSize] = byValue & 0xF; + } + } return TRUE; } VOID UnmapRom(VOID) { - if (pbyRom == NULL) return; - RestorePatches(); // restore ROM Patches - UnmapViewOfFile(pbyRom); - CloseHandle(hRomMap); - CloseHandle(hRomFile); + 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; + DWORD j; + + dwSize /= 2; // adjust no. of bytes to write + dwFilePos /= 2; // linear pos in packed file + + // pack data in page + pbySrc = pbyDest = &pbyRom[dwLinPos]; + for (j = 0; j < dwSize; j++) + { + *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; + } + + VirtualFree(pbyRom,0,MEM_RELEASE); // free ROM image pbyRom = NULL; - hRomMap = NULL; - hRomFile = NULL; dwRomSize = 0; wRomCrc = 0; return; @@ -670,13 +777,13 @@ VOID ResetDocument(VOID) } szCurrentKml[0] = 0; szCurrentFilename[0]=0; - if (Port0) { HeapFree(hHeap,0,Port0); Port0 = NULL; } - if (Port1) { HeapFree(hHeap,0,Port1); Port1 = NULL; } - if (Port2) { HeapFree(hHeap,0,Port2); Port2 = NULL; } else UnmapPort2(); + 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)); - UpdateWindowStatus(); + bDocumentAvail = FALSE; // document not available return; } @@ -746,21 +853,22 @@ BOOL NewDocument(VOID) // allocate port memory if (Chipset.Port0Size) { - Port0 = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,Chipset.Port0Size*2048); + Port0 = calloc(Chipset.Port0Size*2048,sizeof(*Port0)); _ASSERT(Port0 != NULL); } if (Chipset.Port1Size) { - Port1 = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,Chipset.Port1Size*2048); + Port1 = calloc(Chipset.Port1Size*2048,sizeof(*Port1)); _ASSERT(Port1 != NULL); } if (Chipset.Port2Size) { - Port2 = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,Chipset.Port2Size*2048); + Port2 = calloc(Chipset.Port2Size*2048,sizeof(*Port1)); _ASSERT(Port2 != NULL); } LoadBreakpointList(NULL); // clear debugger breakpoint list RomSwitch(0); // boot ROM view of HP49G and map memory + bDocumentAvail = TRUE; // document available return TRUE; restore: RestoreBackup(); @@ -843,10 +951,13 @@ BOOL OpenDocument(LPCTSTR szFilename) switch (pbyFileSignature[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)) goto read_err; #if defined _UNICODE { - LPSTR szTmp = HeapAlloc(hHeap,0,nLength); + LPSTR szTmp = malloc(nLength); if (szTmp == NULL) { AbortMessage(_T("Memory Allocation Failure.")); @@ -855,7 +966,7 @@ BOOL OpenDocument(LPCTSTR szFilename) ReadFile(hFile, szTmp, nLength, &lBytesRead, NULL); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTmp, lBytesRead, szCurrentKml, ARRAYSIZEOF(szCurrentKml)); - HeapFree(hHeap,0,szTmp); + free(szTmp); } #else { @@ -916,13 +1027,13 @@ BOOL OpenDocument(LPCTSTR szFilename) goto restore; } // reload old button state - ReloadButtons(Chipset.Keyboard_Row,sizeof(Chipset.Keyboard_Row)); + ReloadButtons(Chipset.Keyboard_Row,ARRAYSIZEOF(Chipset.Keyboard_Row)); FlashInit(); // init flash structure if (Chipset.Port0Size) { - Port0 = HeapAlloc(hHeap,0,Chipset.Port0Size*2048); + Port0 = malloc(Chipset.Port0Size*2048); if (Port0 == NULL) { AbortMessage(_T("Memory Allocation Failure.")); @@ -937,7 +1048,7 @@ BOOL OpenDocument(LPCTSTR szFilename) if (Chipset.Port1Size) { - Port1 = HeapAlloc(hHeap,0,Chipset.Port1Size*2048); + Port1 = malloc(Chipset.Port1Size*2048); if (Port1 == NULL) { AbortMessage(_T("Memory Allocation Failure.")); @@ -969,7 +1080,7 @@ BOOL OpenDocument(LPCTSTR szFilename) { if (Chipset.Port2Size) { - Port2 = HeapAlloc(hHeap,0,Chipset.Port2Size*2048); + Port2 = malloc(Chipset.Port2Size*2048); if (Port2 == NULL) { AbortMessage(_T("Memory Allocation Failure.")); @@ -1007,7 +1118,7 @@ BOOL OpenDocument(LPCTSTR szFilename) if (pEmuDocumentNotify) pEmuDocumentNotify(szCurrentFilename); #endif SetWindowPathTitle(szCurrentFilename); // update window title line - UpdateWindowStatus(); + bDocumentAvail = TRUE; // document available return TRUE; read_err: @@ -1058,14 +1169,14 @@ BOOL SaveDocument(VOID) WriteFile(hCurrentFile, &nLength, sizeof(nLength), &lBytesWritten, NULL); #if defined _UNICODE { - LPSTR szTmp = HeapAlloc(hHeap,0,nLength); + LPSTR szTmp = malloc(nLength); if (szTmp != NULL) { WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, szCurrentKml, nLength, szTmp, nLength, NULL, NULL); WriteFile(hCurrentFile, szTmp, nLength, &lBytesWritten, NULL); - HeapFree(hHeap,0,szTmp); + free(szTmp); } } #else @@ -1106,7 +1217,6 @@ BOOL SaveDocumentAs(LPCTSTR szFilename) if (pEmuDocumentNotify) pEmuDocumentNotify(szCurrentFilename); #endif SetWindowPathTitle(szCurrentFilename); // update window title line - UpdateWindowStatus(); // and draw it return SaveDocument(); // save current content } @@ -1135,23 +1245,22 @@ BOOL SaveBackup(VOID) lstrcpy(szBackupFilename, szCurrentFilename); lstrcpy(szBackupKml, szCurrentKml); - if (BackupPort0) HeapFree(hHeap,0,BackupPort0); - if (BackupPort1) HeapFree(hHeap,0,BackupPort1); - if (BackupPort2) HeapFree(hHeap,0,BackupPort2); + if (BackupPort0) free(BackupPort0); + if (BackupPort1) free(BackupPort1); + if (BackupPort2) free(BackupPort2); CopyMemory(&BackupChipset, &Chipset, sizeof(Chipset)); - BackupPort0 = HeapAlloc(hHeap,0,Chipset.Port0Size*2048); + BackupPort0 = malloc(Chipset.Port0Size*2048); CopyMemory(BackupPort0,Port0,Chipset.Port0Size*2048); - BackupPort1 = HeapAlloc(hHeap,0,Chipset.Port1Size*2048); + BackupPort1 = malloc(Chipset.Port1Size*2048); CopyMemory(BackupPort1,Port1,Chipset.Port1Size*2048); BackupPort2 = NULL; if (Chipset.Port2Size) // internal port2 { - BackupPort2 = HeapAlloc(hHeap,0,Chipset.Port2Size*2048); + BackupPort2 = malloc(Chipset.Port2Size*2048); CopyMemory(BackupPort2,Port2,Chipset.Port2Size*2048); } CreateBackupBreakpointList(); bBackup = TRUE; - UpdateWindowStatus(); return TRUE; } @@ -1182,13 +1291,13 @@ BOOL RestoreBackup(VOID) } } CopyMemory(&Chipset, &BackupChipset, sizeof(Chipset)); - Port0 = HeapAlloc(hHeap,0,Chipset.Port0Size*2048); + Port0 = malloc(Chipset.Port0Size*2048); CopyMemory(Port0,BackupPort0,Chipset.Port0Size*2048); - Port1 = HeapAlloc(hHeap,0,Chipset.Port1Size*2048); + Port1 = malloc(Chipset.Port1Size*2048); CopyMemory(Port1,BackupPort1,Chipset.Port1Size*2048); if (Chipset.Port2Size) // internal port2 { - Port2 = HeapAlloc(hHeap,0,Chipset.Port2Size*2048); + Port2 = malloc(Chipset.Port2Size*2048); CopyMemory(Port2,BackupPort2,Chipset.Port2Size*2048); } // map port2 @@ -1205,7 +1314,7 @@ BOOL RestoreBackup(VOID) SetWindowLocation(hWnd,Chipset.nPosX,Chipset.nPosY); RestoreBackupBreakpointList(); // restore the debugger breakpoint list if (bDbgOpen) OnToolDebug(); // reopen the debugger - UpdateWindowStatus(); + bDocumentAvail = TRUE; // document available return TRUE; } @@ -1214,12 +1323,11 @@ BOOL ResetBackup(VOID) if (!bBackup) return FALSE; szBackupFilename[0] = 0; szBackupKml[0] = 0; - if (BackupPort0) { HeapFree(hHeap,0,BackupPort0); BackupPort0 = NULL; } - if (BackupPort1) { HeapFree(hHeap,0,BackupPort1); BackupPort1 = NULL; } - if (BackupPort2) { HeapFree(hHeap,0,BackupPort2); BackupPort2 = NULL; } + if (BackupPort0) { free(BackupPort0); BackupPort0 = NULL; } + if (BackupPort1) { free(BackupPort1); BackupPort1 = NULL; } + if (BackupPort2) { free(BackupPort2); BackupPort2 = NULL; } ZeroMemory(&BackupChipset,sizeof(BackupChipset)); bBackup = FALSE; - UpdateWindowStatus(); return TRUE; } @@ -1413,7 +1521,7 @@ BOOL LoadObject(LPCTSTR szFilename) // separated stack writing part CloseHandle(hFile); return FALSE; } - lpBuf = HeapAlloc(hHeap,0,dwFileSizeLow*2); + lpBuf = malloc(dwFileSizeLow*2); if (lpBuf == NULL) { CloseHandle(hFile); @@ -1433,7 +1541,7 @@ BOOL LoadObject(LPCTSTR szFilename) // separated stack writing part if (wError == S_ERR_ASCII) AbortMessage(_T("The calculator does not have enough\nfree memory to load this text file.")); - HeapFree(hHeap,0,lpBuf); + free(lpBuf); return (wError == S_ERR_NO); } @@ -1490,7 +1598,7 @@ typedef struct _BmpFile LPBYTE pbyFile; // buffer } BMPFILE, FAR *LPBMPFILE, *PBMPFILE; -static __inline UINT DibNumColors(BITMAPINFOHEADER CONST *lpbi) +static __inline WORD DibNumColors(BITMAPINFOHEADER CONST *lpbi) { if (lpbi->biClrUsed != 0) return (UINT)lpbi->biClrUsed; @@ -1502,7 +1610,7 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi) { LOGPALETTE* pPal; HPALETTE hpal = NULL; - UINT nNumColors; + WORD wNumColors; BYTE red; BYTE green; BYTE blue; @@ -1517,29 +1625,28 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi) // Get a pointer to the color table and the number of colors in it pRgb = (RGBQUAD FAR *)((LPBYTE)lpbi + (WORD)lpbi->biSize); - nNumColors = DibNumColors(lpbi); + wNumColors = DibNumColors(lpbi); - if (nNumColors) + if (wNumColors) { // Allocate for the logical palette structure - pPal = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY)); - if (!pPal) - return NULL; + pPal = malloc(sizeof(LOGPALETTE) + wNumColors * sizeof(PALETTEENTRY)); + if (!pPal) return NULL; - pPal->palNumEntries = nNumColors; 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 < nNumColors; i++) + 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 = (BYTE)0; + pPal->palPalEntry[i].peFlags = 0; } hpal = CreatePalette(pPal); - HeapFree(hHeap,0,pPal); + free(pPal); } else { @@ -1547,12 +1654,12 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi) // 16, 24 and 32 bitcount DIB's have no color table entries so, set the // number of to the maximum value (256). - nNumColors = 256; - pPal = HeapAlloc(hHeap,0,sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY)); + wNumColors = 256; + pPal = malloc(sizeof(LOGPALETTE) + wNumColors * sizeof(PALETTEENTRY)); if (!pPal) return NULL; - pPal->palNumEntries = nNumColors; pPal->palVersion = 0x300; + pPal->palNumEntries = wNumColors; red = green = blue = 0; @@ -1570,7 +1677,7 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi) blue += 64; } hpal = CreatePalette(pPal); - HeapFree(hHeap,0,pPal); + free(pPal); } return hpal; } @@ -1625,12 +1732,13 @@ static HBITMAP DecodeBmp(LPBMPFILE pBmp) pBmi, DIB_RGB_COLORS)); if (hBitmap == NULL) return NULL; - _ASSERT(hPalette == NULL); // resource free - hPalette = CreateBIPalette(&pBmi->bmiHeader); - // save old palette - hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE); - RealizePalette(hWindowDC); - + if (hPalette == NULL) + { + hPalette = CreateBIPalette(&pBmi->bmiHeader); + // save old palette + hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE); + RealizePalette(hWindowDC); + } return hBitmap; } @@ -1719,7 +1827,7 @@ static HBITMAP DecodeGif(LPBMPFILE pBmp) bmi.bmiHeader.biWidth = nWidth; bmi.bmiHeader.biHeight = nHeight; bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 24; // create a true color DIB + bmi.bmiHeader.biBitCount = 24; // create a true color DIB bmi.bmiHeader.biCompression = BI_RGB; ZeroMemory(&sGlb,sizeof(sGlb)); // init global color map @@ -2115,14 +2223,16 @@ static HBITMAP DecodeGif(LPBMPFILE pBmp) } } - _ASSERT(bDecoding == FALSE); // decoding successful + _ASSERT(bDecoding == FALSE); // decoding successful // normal decoding exit - _ASSERT(hPalette == NULL); // resource free - hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi); - // save old palette - hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE); - RealizePalette(hWindowDC); + if (hPalette == NULL) + { + hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi); + // save old palette + hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE); + RealizePalette(hWindowDC); + } quit: if (hBitmap != NULL && bDecoding) // creation failed diff --git a/Sources/Emu48/I28F160.C b/Sources/Emu48/I28F160.C index a239b13..a7145b9 100644 --- a/Sources/Emu48/I28F160.C +++ b/Sources/Emu48/I28F160.C @@ -187,6 +187,51 @@ static CONST BYTE byQueryTab[] = }; +// +// 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 // @@ -367,8 +412,8 @@ static VOID WrStateE8C(BYTE a, DWORD d) _ASSERT(d+1 < dwRomSize); // address valid? // no error set in BWSLBS, because I could alway program a "0" - *(pbyRom+d++) &= (a & 0x0F); // write LSB - *(pbyRom+d++) &= (a >> 4); // write MSB + WriteByte(d,a); // write byte + d += 2; // next address } } else @@ -395,11 +440,8 @@ static VOID WrState40(DWORD d) // byte/word program data static VOID WrState40D(BYTE a, DWORD d) { - d <<= 1; // nibble start address - _ASSERT(d+1 < dwRomSize); // address valid? // no error set in BWSLBS, because I could alway program a "0" - *(pbyRom+d++) &= (a & 0x0F); // write LSB - *(pbyRom+d) &= (a >> 4); // write MSB + WriteByte(d << 1,a); // write byte WSMset.byStatusReg |= WSMS; // data written WSMset.uWrState = WRS_DATA; return; @@ -433,8 +475,7 @@ static VOID WrState20C(BYTE a, DWORD d) d &= ~(dwBlockSize-1); // start of block dwBlockSize *= 2; // block size in nibbles _ASSERT(d+dwBlockSize <= dwRomSize); // address valid? - // write 128K nibble - FillMemory(pbyRom + (d << 1),dwBlockSize,0x0F); + EraseBlock(d << 1,dwBlockSize); // erase 128K nibble } } else @@ -467,7 +508,7 @@ static VOID WrState30C(BYTE a, DWORD d) WORD wNoOfBlocks = (byQueryTab[0x2E] << 8) | byQueryTab[0x2D]; DWORD dwBlockSize = ((byQueryTab[0x30] << 8) | byQueryTab[0x2F]) * 256; - LPBYTE pbyBlock = pbyRom; + DWORD dwBlockAddr = 0; dwBlockSize *= 2; // block size in nibbles @@ -481,11 +522,11 @@ static VOID WrState30C(BYTE a, DWORD d) // clear block lock bit WSMset.dwLockCnfg &= ~(1<> 16) & 0xFF; BOOL bPress = (dwData >> 24) & 0xFF; - PlayKey(nOut,nIn,bPress); -// KeyboardEvent(bPress,nOut,nIn); + PlayKey(nOut,nIn,bPress); } dwTime = nMacroTimeout; // set default speed @@ -84,6 +82,13 @@ static DWORD WINAPI EventThread(LPVOID pParam) } 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 } } @@ -102,9 +107,7 @@ VOID KeyMacroRecord(BOOL bPress, UINT out, UINT in) DWORD dwWritten; dwWritten = GetTickCount(); // time reference - Data.dwTime = (dwWritten - dwTimeRef - KEYHOLDTIME); - // set negative number to zero - if ((Data.dwTime & 0x80000000) != 0) Data.dwTime = 0; + Data.dwTime = (dwWritten - dwTimeRef); Data.dwTime |= 0x80000000; // set time marker dwTimeRef = dwWritten; @@ -161,14 +164,13 @@ LRESULT OnToolMacroNew(VOID) _ASSERT(dwWritten == sizeof(dwExtensionLength)); nMacroState = MACRO_NEW; - UpdateWindowStatus(); MessageBox(hWnd, _T("Press OK to begin to record the Macro."), _T("Macro Recorder"), MB_OK|MB_ICONINFORMATION); - dwTimeRef = GetTickCount() + KEYHOLDTIME; // time reference + dwTimeRef = GetTickCount(); // time reference return 0; } @@ -242,7 +244,6 @@ LRESULT OnToolMacroPlay(VOID) hEventPlay = CreateEvent(NULL,FALSE,FALSE,NULL); nMacroState = MACRO_PLAY; - UpdateWindowStatus(); // start playing thread VERIFY(hThreadEv = CreateThread(NULL,0,&EventThread,NULL,0,&dwThreadId)); @@ -273,7 +274,6 @@ LRESULT OnToolMacroStop(VOID) if (hMacroFile != INVALID_HANDLE_VALUE) CloseHandle(hMacroFile); nMacroState = MACRO_OFF; - UpdateWindowStatus(); } return 0; } diff --git a/Sources/Emu48/KML.C b/Sources/Emu48/KML.C index 444bec8..2bbcdba 100644 --- a/Sources/Emu48/KML.C +++ b/Sources/Emu48/KML.C @@ -59,7 +59,7 @@ static LPCTSTR szLexDelim[] = _T(" \t\r") // valid whitespaces for LEX_PARAM }; -static KmlToken pLexToken[] = +static CONST KmlToken pLexToken[] = { {TOK_ANNUNCIATOR,000001,11,_T("Annunciator")}, {TOK_BACKGROUND, 000000,10,_T("Background")}, @@ -104,7 +104,7 @@ static KmlToken pLexToken[] = {TOK_VGA, 000001, 3,_T("Vga")}, // for PPC compatibility reasons {TOK_LCD, 000000, 3,_T("Lcd")}, {TOK_END, 000000, 3,_T("End")}, - {0, 000000, 0,_T("")}, + {TOK_NONE, 000000, 0,_T("")} }; static CONST TokenId eIsGlobalBlock[] = @@ -146,7 +146,7 @@ static VOID ClearLog() nLogLength = 0; if (szLog != NULL) { - HeapFree(hHeap,0,szLog); + free(szLog); szLog = NULL; } return; @@ -158,7 +158,7 @@ static VOID AddToLog(LPCTSTR szString) if (szLog == NULL) { nLogLength = nLength + 1; // \0 - szLog = HeapAlloc(hHeap,0,nLogLength*sizeof(szLog[0])); + szLog = malloc(nLogLength*sizeof(szLog[0])); if (szLog==NULL) { nLogLength = 0; @@ -168,7 +168,7 @@ static VOID AddToLog(LPCTSTR szString) } else { - LPTSTR szLogTmp = HeapReAlloc(hHeap,0,szLog,(nLogLength+nLength)*sizeof(szLog[0])); + LPTSTR szLogTmp = realloc(szLog,(nLogLength+nLength)*sizeof(szLog[0])); if (szLogTmp == NULL) { ClearLog(); @@ -268,9 +268,9 @@ static VOID DestroyKmlList(VOID) while (pKmlList) { pList = pKmlList->pNext; - HeapFree(hHeap,0,pKmlList->szFilename); - HeapFree(hHeap,0,pKmlList->szTitle); - HeapFree(hHeap,0,pKmlList); + free(pKmlList->szFilename); + free(pKmlList->szTitle); + free(pKmlList); pKmlList = pList; } return; @@ -313,7 +313,7 @@ static VOID CreateKmlList(VOID) FreeBlocks(pBlock); continue; } - VERIFY(pScript = HeapAlloc(hHeap,0,sizeof(KmlScript))); + VERIFY(pScript = malloc(sizeof(KmlScript))); pScript->szFilename = DuplicateString(pFindFileData.cFileName); szTitle = GetStringParam(pBlock,TOK_GLOBAL,TOK_TITLE,0); if (szTitle == NULL) szTitle = pScript->szFilename; @@ -497,7 +497,7 @@ static LPTSTR MapKMLFile(HANDLE hFile) goto fail; } - lpBuf = HeapAlloc(hHeap,0,(dwFileSizeLow+1)*sizeof(lpBuf[0])); + lpBuf = malloc((dwFileSizeLow+1)*sizeof(lpBuf[0])); if (lpBuf == NULL) { PrintfToLog(_T("Cannot allocate %i bytes."), (dwFileSizeLow+1)*sizeof(lpBuf[0])); @@ -505,17 +505,17 @@ static LPTSTR MapKMLFile(HANDLE hFile) } #if defined _UNICODE { - LPSTR szTmp = HeapAlloc(hHeap,0,dwFileSizeLow+1); + LPSTR szTmp = malloc(dwFileSizeLow+1); if (szTmp == NULL) { - HeapFree(hHeap,0,lpBuf); + 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); - HeapFree(hHeap,0,szTmp); + free(szTmp); } #else { @@ -637,10 +637,10 @@ static TokenId ParseToken(UINT nMode) if (bDebug) // token not found { // allocate target string memory with token length - LPTSTR szToken = HeapAlloc(hHeap,0,(i+1) * sizeof(szToken[0])); + LPTSTR szToken = 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); - HeapFree(hHeap,0,szToken); + free(szToken); } return TOK_NONE; } @@ -665,21 +665,33 @@ static LPTSTR ParseString(VOID) szText++; // skip leading '"' nLength = 0; nBlock = 256; - lpszString = HeapAlloc(hHeap,0,nBlock * sizeof(lpszString[0])); + lpszString = malloc(nBlock * sizeof(lpszString[0])); while (*szText != _T('"')) { if (nLength == nBlock - 1) // ran out of buffer space { nBlock += 256; - lpszString = HeapReAlloc(hHeap,0,lpszString,nBlock * sizeof(lpszString[0])); + lpszString = realloc(lpszString,nBlock * sizeof(lpszString[0])); + } + + 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 == _T('\\')) szText++; // skip '\' escape char to decode \" if (*szText == 0) // EOS found inside string { lpszString[nLength] = 0; // set EOS PrintfToLog(_T("%i: Invalid string %s."), nLexLine, lpszString); - HeapFree(hHeap,0,lpszString); + free(lpszString); return NULL; } lpszString[nLength++] = *szText++; // save char @@ -688,7 +700,7 @@ static LPTSTR ParseString(VOID) lpszString[nLength] = 0; // set EOS // release unnecessary allocated bytes - return HeapReAlloc(hHeap,0,lpszString,(nLength+1) * sizeof(lpszString[0])); + return realloc(lpszString,(nLength+1) * sizeof(lpszString[0])); } static TokenId Lex(UINT nMode) @@ -736,7 +748,7 @@ static KmlLine* ParseLine(TokenId eCommand) } if (pLexToken[i].nLen == 0) return NULL; - pLine = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(KmlLine)); + pLine = calloc(1,sizeof(KmlLine)); pLine->eCommand = eCommand; for (j = 0, nParams = pLexToken[i].nParams; TRUE; nParams >>= 3) @@ -779,18 +791,18 @@ static KmlLine* ParseLine(TokenId eCommand) } // if last argument was string, free it - if (eToken == TOK_STRING) HeapFree(hHeap,0,szLexString); + if (eToken == TOK_STRING) free(szLexString); 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 { - HeapFree(hHeap,0,(LPVOID)pLine->nParam[i]); + free((LPVOID)pLine->nParam[i]); } nParams >>= 3; // next argument type } - HeapFree(hHeap,0,pLine); + free(pLine); return NULL; } @@ -833,7 +845,7 @@ static KmlLine* IncludeLines(LPCTSTR szFilename) nLexLine = uOldLine; szText = szOldText; - HeapFree(hHeap,0,lpbyBuf); + free(lpbyBuf); return pLine; } @@ -845,7 +857,7 @@ static KmlLine* ParseLines(VOID) TokenId eToken; UINT nLevel = 0; - while ((eToken = Lex(LEX_COMMAND))) + while ((eToken = Lex(LEX_COMMAND)) != TOK_NONE) { if (IsGlobalBlock(eToken)) // check for block command { @@ -871,7 +883,7 @@ static KmlLine* ParseLines(VOID) { pLine = pFirst = IncludeLines(szLexString); } - HeapFree(hHeap,0,szFilename); // free memory + free(szFilename); // free memory if (pLine == NULL) // parsing error goto abort; while (pLine->pNext) pLine=pLine->pNext; @@ -921,7 +933,7 @@ static KmlBlock* ParseBlock(TokenId eType) nLinesIncludeLevel = 0; - VERIFY(pBlock = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(KmlBlock))); + VERIFY(pBlock = calloc(1,sizeof(KmlBlock))); pBlock->eType = eType; for (i = 0; pLexToken[i].nLen; ++i) // search for token @@ -937,8 +949,9 @@ static KmlBlock* ParseBlock(TokenId eType) eToken = Lex(LEX_PARAM); // decode argument if (eToken != TOK_INTEGER) { + if (eToken == TOK_STRING) free(szLexString); PrintfToLog(_T("%i: Block %s parameter must be an integer."), nLexLine, pLexToken[i].szName); - HeapFree(hHeap,0,pBlock); + free(pBlock); return NULL; } @@ -949,14 +962,14 @@ static KmlBlock* ParseBlock(TokenId eType) if (eToken != TOK_EOL) { PrintfToLog(_T("%i: Too many parameters for block %s."), nLexLine, pLexToken[i].szName); - HeapFree(hHeap,0,pBlock); + free(pBlock); return NULL; } pBlock->pFirstLine = ParseLines(); if (pBlock->pFirstLine == NULL) // break on ParseLines error { - HeapFree(hHeap,0,pBlock); + free(pBlock); pBlock = NULL; } @@ -1002,7 +1015,7 @@ static KmlBlock* IncludeBlocks(LPCTSTR szFilename) nLexLine = uOldLine; szText = szOldText; - HeapFree(hHeap,0,lpbyBuf); + free(lpbyBuf); return pFirst; } @@ -1029,7 +1042,7 @@ static KmlBlock* ParseBlocks(VOID) pBlock = pBlock->pNext = IncludeBlocks(szLexString); else pBlock = pFirst = IncludeBlocks(szLexString); - HeapFree(hHeap,0,szFilename); // free memory + free(szFilename); // free memory if (pBlock == NULL) // parsing error goto abort; while (pBlock->pNext) pBlock=pBlock->pNext; @@ -1445,13 +1458,13 @@ static VOID FreeLines(KmlLine* pLine) { if ((nParams&7) == TYPE_STRING) // string type { - HeapFree(hHeap,0,(LPVOID)pLine->nParam[i]); + free((LPVOID)pLine->nParam[i]); } i++; // incr. parameter buffer index nParams >>= 3; // next argument type } pLine = pLine->pNext; // get next line - HeapFree(hHeap,0,pThisLine); + free(pThisLine); } return; } @@ -1463,7 +1476,7 @@ VOID FreeBlocks(KmlBlock* pBlock) KmlBlock* pThisBlock = pBlock; pBlock = pBlock->pNext; FreeLines(pThisBlock->pFirstLine); - HeapFree(hHeap,0,pThisBlock); + free(pThisBlock); } return; } @@ -1481,11 +1494,8 @@ VOID KillKML(VOID) DestroyMainBitmap(); if (hPalette) { - BOOL err; - if (hWindowDC) SelectPalette(hWindowDC, hOldPalette, FALSE); - err = DeleteObject(hPalette); - _ASSERT(err != FALSE); // freed resource memory + VERIFY(DeleteObject(hPalette)); hPalette = NULL; } bClicking = FALSE; @@ -1508,7 +1518,6 @@ VOID KillKML(VOID) nLcdZoom = 1; cCurrentRomType = 0; nCurrentClass = 0; - UpdateWindowStatus(); ResizeWindow(); return; } @@ -1840,8 +1849,16 @@ VOID ReloadButtons(BYTE *Keyboard_Row, UINT nSize) { if (pButton[i].nOut < nSize) // valid out code { - // get state of button from keyboard matrix - pButton[i].bDown = ((Keyboard_Row[pButton[i].nOut] & pButton[i].nIn) != 0); + if (pButton[i].nIn == 0x8000) // ON key + { + // get state of ON button from interrupt line + pButton[i].bDown = (Chipset.IR15X != 0); + } + else + { + // get state of button from keyboard matrix + pButton[i].bDown = ((Keyboard_Row[pButton[i].nOut] & pButton[i].nIn) != 0); + } // any key pressed? bKeyPressed = bKeyPressed || pButton[i].bDown; @@ -1987,7 +2004,7 @@ VOID MouseButtonUpAt(UINT nFlags, DWORD x, DWORD y) bClicking = FALSE; uButtonClicked = 0; return; - UNREFERENCED_PARAMETER(nFlags); + UNREFERENCED_PARAMETER(nFlags); } VOID MouseMovesTo(UINT nFlags, DWORD x, DWORD y) @@ -2109,7 +2126,7 @@ static KmlBlock* LoadKMLGlobal(LPCTSTR szFilename) HANDLE hFile; LPTSTR lpBuf; KmlBlock* pBlock; - DWORD eToken; + TokenId eToken; SetCurrentDirectory(szEmuDirectory); hFile = CreateFile(szFilename, @@ -2137,7 +2154,7 @@ static KmlBlock* LoadKMLGlobal(LPCTSTR szFilename) } CleanLex(); ClearLog(); - HeapFree(hHeap,0,lpBuf); + free(lpBuf); return pBlock; } @@ -2173,7 +2190,7 @@ BOOL InitKML(LPCTSTR szFilename, BOOL bNoLog) pKml = ParseBlocks(); CleanLex(); - HeapFree(hHeap,0,lpBuf); + free(lpBuf); if (pKml == NULL) goto quit; pBlock = pKml; diff --git a/Sources/Emu48/MOPS.C b/Sources/Emu48/MOPS.C index 664c844..b1c6c62 100644 --- a/Sources/Emu48/MOPS.C +++ b/Sources/Emu48/MOPS.C @@ -987,6 +987,29 @@ VOID IOBit(DWORD d, BYTE b, BOOL s) // set/clear bit in I/O section 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; @@ -1173,8 +1196,13 @@ VOID ReadIO(BYTE *a, DWORD d, DWORD s, BOOL bUpdate) #endif break; case 0x1B: *a = 0; break; - case 0x1C: *a = 0; break; // LED CONTROL - case 0x1D: *a = 0; break; // LED BUFFER + 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; @@ -1227,14 +1255,14 @@ VOID ReadIO(BYTE *a, DWORD d, DWORD s, BOOL bUpdate) case 0x35: *a = 0; break; case 0x36: *a = 0; break; case 0x37: *a = ReadT1(); break; - case 0x38: Nunpack(a, ReadT2() , s); return; - case 0x39: Nunpack(a, ReadT2()>> 4, s); return; - case 0x3A: Nunpack(a, ReadT2()>> 8, s); return; - case 0x3B: Nunpack(a, ReadT2()>>12, s); return; - case 0x3C: Nunpack(a, ReadT2()>>16, s); return; - case 0x3D: Nunpack(a, ReadT2()>>20, s); return; - case 0x3E: Nunpack(a, ReadT2()>>24, s); return; - case 0x3F: Nunpack(a, ReadT2()>>28, s); return; + 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++; @@ -1589,12 +1617,27 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) } #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: Chipset.IORam[d]=c&1; break; + case 0x1D: + IrPrinter((BYTE)(c&LBO)); + Chipset.IORam[d]=c&LBO; + break; // 0011E = NS:SCRATCHPAD // 0011E @ Scratch pad diff --git a/Sources/Emu48/MRU.C b/Sources/Emu48/MRU.C index 82c62a9..a7a2f72 100644 --- a/Sources/Emu48/MRU.C +++ b/Sources/Emu48/MRU.C @@ -73,7 +73,7 @@ BOOL MruInit(INT nNum) if (nEntry > 0) // allocate MRU table { // create MRU table - if ((ppszFiles = HeapAlloc(hHeap,0,nEntry * sizeof(*ppszFiles))) == NULL) + if ((ppszFiles = malloc(nEntry * sizeof(*ppszFiles))) == NULL) return TRUE; // fill each entry @@ -104,12 +104,12 @@ VOID MruCleanup(VOID) for (i = 0; i < nEntry; ++i) // cleanup each entry { if (ppszFiles[i] != NULL) - HeapFree(hHeap,0,ppszFiles[i]); // cleanup entry + free(ppszFiles[i]); // cleanup entry } if (ppszFiles != NULL) // table defined { - HeapFree(hHeap,0,ppszFiles); // free table + free(ppszFiles); // free table ppszFiles = NULL; } return; @@ -140,7 +140,7 @@ VOID MruAdd(LPCTSTR lpszEntry) i = nEntry - 1; // last index if (ppszFiles[i] != NULL) - HeapFree(hHeap,0,ppszFiles[i]); // free oldest entry + free(ppszFiles[i]); // free oldest entry for (; i > 0; --i) // move old entries 1 line down { @@ -156,7 +156,7 @@ VOID MruAdd(LPCTSTR lpszEntry) VOID MruRemove(INT nIndex) { - HeapFree(hHeap,0,ppszFiles[nIndex]); // free entry + free(ppszFiles[nIndex]); // free entry for (; nIndex < nEntry - 1; ++nIndex) // move below entries 1 line up { @@ -198,10 +198,10 @@ LPCTSTR MruFilename(INT nIndex) VOID MruUpdateMenu(VOID) { - TCHAR szCurPath[MAX_PATH]; - HANDLE hMenu; - BOOL bEmpty; - INT i; + TCHAR szCurPath[MAX_PATH]; + HMENU hMenu; + BOOL bEmpty; + INT i; if (nEntry == 0) return; // no entries @@ -309,7 +309,6 @@ VOID MruReadList(VOID) { TCHAR szFilename[MAX_PATH]; TCHAR szItemname[32]; - LPTSTR lpszValue; INT i; _ASSERT(ppszFiles != NULL); // MRU not initialized @@ -321,9 +320,8 @@ VOID MruReadList(VOID) if (ppszFiles[i] != NULL) // already filled { - HeapFree(hHeap,0,ppszFiles[i]); // free entry + free(ppszFiles[i]); // free entry ppszFiles[i] = NULL; // clear last line - lpszValue = _T(""); } if (*szFilename) // read a valid entry diff --git a/Sources/Emu48/OPCODES.C b/Sources/Emu48/OPCODES.C index d616986..0b0f086 100644 --- a/Sources/Emu48/OPCODES.C +++ b/Sources/Emu48/OPCODES.C @@ -1040,7 +1040,7 @@ VOID o807(LPBYTE I) // SHUTDN // 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[BITOFFSET]&DON) == 0 && ((w.IORam[CARDCTL]&(ECDT|RCDT)) != (ECDT|RCDT))) { // on HP48GX ROM must be selected (DA19=1) and @@ -2143,7 +2143,7 @@ VOID o8Fd5(LPBYTE I) // GOSBVL #ddddd return; } - // ?r=s f + // ?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; } diff --git a/Sources/Emu48/OPS.H b/Sources/Emu48/OPS.H index 9ad24d2..20aebb5 100644 --- a/Sources/Emu48/OPS.H +++ b/Sources/Emu48/OPS.H @@ -48,7 +48,7 @@ static __inline LPBYTE FASTPTR(DWORD d) if ( !(Chipset.IOCfig && ((d & 0xFFFC0) == Chipset.IOBase)) && RMap[u] != NULL // page valid - && ( v < 0x1000 - ARRAYSIZEOF(lpbyPage) // complete opcode inside page + && ( v < 0x1000 - ARRAYSIZEOF(pbyNULL) // complete opcode inside page // or next page continue linear addressing || (RMap[u] + 0x1000 == RMap[(u+1) & (ARRAYSIZEOF(RMap)-1)]) ) @@ -59,7 +59,7 @@ static __inline LPBYTE FASTPTR(DWORD d) else { lpbyPage = pbyNULL; // memory allocation - Npeek(lpbyPage, d, ARRAYSIZEOF(lpbyPage)); // fill with data (LAHEX + 16 digits = longest opcode) + Npeek(lpbyPage, d, ARRAYSIZEOF(pbyNULL)); // fill with data (LAHEX + 16 digits = longest opcode) } return lpbyPage; } diff --git a/Sources/Emu48/PCH.H b/Sources/Emu48/PCH.H index 81dddc3..9ac2d85 100644 --- a/Sources/Emu48/PCH.H +++ b/Sources/Emu48/PCH.H @@ -4,7 +4,9 @@ #define _WIN32_IE 0x0200 #define _CRT_SECURE_NO_DEPRECATE +#define _CRTDBG_MAP_ALLOC +#include #include #include #include diff --git a/Sources/Emu48/REDEYE.C b/Sources/Emu48/REDEYE.C new file mode 100644 index 0000000..bd646fe --- /dev/null +++ b/Sources/Emu48/REDEYE.C @@ -0,0 +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) +{ + INT 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 index f0ba17e..5339580 100644 --- a/Sources/Emu48/RESOURCE.H +++ b/Sources/Emu48/RESOURCE.H @@ -12,53 +12,57 @@ #define IDR_DEBUG_STACK 106 #define IDB_CHECKBOX 107 #define IDD_ABOUT 108 -#define IDD_SETTINGS 109 -#define IDD_CHOOSEKML 110 -#define IDD_KMLLOG 111 -#define IDD_DISASM 112 -#define IDD_DEBUG 113 -#define IDD_NEWVALUE 114 -#define IDD_ENTERADR 115 -#define IDD_BREAKEDIT 116 -#define IDD_ENTERBREAK 117 -#define IDD_INSTRUCTIONS 118 -#define IDD_WRITEONLYREG 119 -#define IDD_FIND 120 -#define IDD_PROFILE 121 -#define IDD_RPLVIEW 122 -#define IDD_MACROSET 123 -#define IDD_DEBUG_SETTINGS 124 +#define IDD_SET_GENERAL 109 +#define IDD_SET_MEMORY 110 +#define IDD_SET_PERIPHERAL 111 +#define IDD_CHOOSEKML 112 +#define IDD_KMLLOG 113 +#define IDD_DISASM 114 +#define IDD_DEBUG 115 +#define IDD_NEWVALUE 116 +#define IDD_ENTERADR 117 +#define IDD_BREAKEDIT 118 +#define IDD_ENTERBREAK 119 +#define IDD_INSTRUCTIONS 120 +#define IDD_WRITEONLYREG 121 +#define IDD_FIND 122 +#define IDD_PROFILE 123 +#define IDD_RPLVIEW 124 +#define IDD_MACROSET 125 +#define IDD_DEBUG_MEMSAVE 126 +#define IDD_DEBUG_MEMLOAD 127 +#define IDD_DEBUG_SETTINGS 128 #define IDC_REALSPEED 1000 #define IDC_GRAYSCALE 1001 #define IDC_ALWAYSONTOP 1002 #define IDC_ACTFOLLOWSMOUSE 1003 -#define IDC_AUTOSAVE 1004 -#define IDC_AUTOSAVEONEXIT 1005 -#define IDC_OBJECTLOADWARNING 1006 -#define IDC_ALWAYSDISPLOG 1007 -#define IDC_PORT1EN 1008 -#define IDC_PORT1WR 1009 -#define IDC_PORT2ISSHARED 1010 -#define IDC_PORT2WR 1011 -#define IDC_PORT2 1012 -#define IDC_PORT2LOAD 1013 -#define IDC_WIRE 1014 -#define IDC_IR 1015 -#define IDC_EMUDIR 1016 -#define IDC_EMUDIRSEL 1017 -#define IDC_UPDATE 1018 -#define IDC_KMLSCRIPT 1019 -#define IDC_AUTHOR 1020 -#define IDC_TITLE 1021 -#define IDC_KMLLOG 1022 -#define IDC_VERSION 1023 -#define IDC_LICENSE 1024 -#define IDC_DISASM_WIN 1025 -#define IDC_DISASM_MAP 1026 -#define IDC_DISASM_ROM 1027 -#define IDC_DISASM_RAM 1028 -#define IDC_DISASM_PORT1 1029 -#define IDC_DISASM_PORT2 1030 +#define IDC_SINGLEINSTANCE 1004 +#define IDC_AUTOSAVE 1005 +#define IDC_AUTOSAVEONEXIT 1006 +#define IDC_OBJECTLOADWARNING 1007 +#define IDC_ALWAYSDISPLOG 1008 +#define IDC_PORT1EN 1009 +#define IDC_PORT1WR 1010 +#define IDC_PORT2ISSHARED 1011 +#define IDC_PORT2WR 1012 +#define IDC_PORT2 1013 +#define IDC_PORT2LOAD 1014 +#define IDC_IR_ADDR 1015 +#define IDC_IR_PORT 1016 +#define IDC_WIRE 1017 +#define IDC_IR 1018 +#define IDC_EMUDIR 1019 +#define IDC_EMUDIRSEL 1020 +#define IDC_UPDATE 1021 +#define IDC_KMLSCRIPT 1022 +#define IDC_AUTHOR 1023 +#define IDC_TITLE 1024 +#define IDC_KMLLOG 1025 +#define IDC_VERSION 1026 +#define IDC_LICENSE 1027 +#define IDC_DISASM_WIN 1028 +#define IDC_DISASM_MODE_TEXT 1029 +#define IDC_DISASM_MODE 1030 #define IDC_DISASM_MODULE 1031 #define IDC_DISASM_HP 1032 #define IDC_DISASM_CLASS 1033 @@ -109,55 +113,59 @@ #define IDC_DEBUG_MEM_COL6 1078 #define IDC_DEBUG_MEM_COL7 1079 #define IDC_DEBUG_MEM_TEXT 1080 -#define IDC_DEBUG_STACK 1081 -#define IDC_STATIC_BREAKPOINT 1082 -#define IDC_BREAKEDIT_ADD 1083 -#define IDC_BREAKEDIT_DELETE 1084 -#define IDC_BREAKEDIT_WND 1085 -#define IDC_STATIC_MMU 1086 -#define IDC_MMU_IO_A 1087 -#define IDC_MMU_NCE2_A 1088 -#define IDC_MMU_CE1_A 1089 -#define IDC_MMU_CE2_A 1090 -#define IDC_MMU_NCE3_A 1091 -#define IDC_MMU_IO_S 1092 -#define IDC_MMU_CE1_S 1093 -#define IDC_MMU_CE2_S 1094 -#define IDC_MMU_NCE2_S 1095 -#define IDC_MMU_NCE3_S 1096 -#define IDC_STATIC_MISC 1097 -#define IDC_MISC_BS_TXT 1098 -#define IDC_INSTR_TEXT 1099 -#define IDC_INSTR_CODE 1100 -#define IDC_INSTR_COPY 1101 -#define IDC_INSTR_CLEAR 1102 -#define IDC_PROFILE_LASTCYCLES 1103 -#define IDC_PROFILE_LASTTIME 1104 -#define IDC_BPCODE 1105 -#define IDC_BPRPL 1106 -#define IDC_BPACCESS 1107 -#define IDC_BPREAD 1108 -#define IDC_BPWRITE 1109 -#define IDC_FIND_DATA 1110 -#define IDC_FIND_ASCII 1111 -#define IDC_FIND_CASE 1112 -#define IDC_ADDR20_24 1113 -#define IDC_ADDR25_27 1114 -#define IDC_ADDR28_29 1115 -#define IDC_ADDR30_34 1116 -#define IDC_RPLVIEW_DATA 1117 -#define IDC_MACRO_SLOW 1118 -#define IDC_MACRO_FAST 1119 -#define IDC_MACRO_SLIDER 1120 -#define IDC_MACRO_REAL 1121 -#define IDC_MACRO_MANUAL 1122 -#define IDC_SOUND_SLIDER 1123 -#define IDC_SOUND_SPEAKER 1124 -#define IDC_SOUND_WAVE 1125 -#define IDC_DEBUG_SET_SYMB 1126 -#define IDC_DEBUG_SET_MODEL 1127 -#define IDC_DEBUG_SET_FILE 1128 -#define IDC_DEBUG_SET_BROWSE 1129 +#define IDC_DEBUG_DATA_FILE 1081 +#define IDC_DEBUG_DATA_BUT 1082 +#define IDC_DEBUG_DATA_STARTADDR 1083 +#define IDC_DEBUG_DATA_ENDADDR 1084 +#define IDC_DEBUG_SET_SYMB 1085 +#define IDC_DEBUG_SET_MODEL 1086 +#define IDC_DEBUG_SET_FILE 1087 +#define IDC_DEBUG_SET_BROWSE 1088 +#define IDC_DEBUG_STACK 1089 +#define IDC_STATIC_BREAKPOINT 1090 +#define IDC_BREAKEDIT_ADD 1091 +#define IDC_BREAKEDIT_DELETE 1092 +#define IDC_BREAKEDIT_WND 1093 +#define IDC_STATIC_MMU 1094 +#define IDC_MMU_IO_A 1095 +#define IDC_MMU_NCE2_A 1096 +#define IDC_MMU_CE1_A 1097 +#define IDC_MMU_CE2_A 1098 +#define IDC_MMU_NCE3_A 1099 +#define IDC_MMU_IO_S 1100 +#define IDC_MMU_CE1_S 1101 +#define IDC_MMU_CE2_S 1102 +#define IDC_MMU_NCE2_S 1103 +#define IDC_MMU_NCE3_S 1104 +#define IDC_STATIC_MISC 1105 +#define IDC_MISC_BS_TXT 1106 +#define IDC_INSTR_TEXT 1107 +#define IDC_INSTR_CODE 1108 +#define IDC_INSTR_COPY 1109 +#define IDC_INSTR_CLEAR 1110 +#define IDC_PROFILE_LASTCYCLES 1111 +#define IDC_PROFILE_LASTTIME 1112 +#define IDC_BPCODE 1113 +#define IDC_BPRPL 1114 +#define IDC_BPACCESS 1115 +#define IDC_BPREAD 1116 +#define IDC_BPWRITE 1117 +#define IDC_FIND_DATA 1118 +#define IDC_FIND_ASCII 1119 +#define IDC_FIND_CASE 1120 +#define IDC_ADDR20_24 1121 +#define IDC_ADDR25_27 1122 +#define IDC_ADDR28_29 1123 +#define IDC_ADDR30_34 1124 +#define IDC_RPLVIEW_DATA 1125 +#define IDC_MACRO_SLOW 1126 +#define IDC_MACRO_FAST 1127 +#define IDC_MACRO_SLIDER 1128 +#define IDC_MACRO_REAL 1129 +#define IDC_MACRO_MANUAL 1130 +#define IDC_SOUND_SLIDER 1131 +#define IDC_SOUND_SPEAKER 1132 +#define IDC_SOUND_WAVE 1133 #define ID_FILE_NEW 40001 #define ID_FILE_OPEN 40002 #define ID_FILE_SAVE 40003 @@ -215,23 +223,25 @@ #define ID_DEBUG_MEM_CE1 40057 #define ID_DEBUG_MEM_CE2 40058 #define ID_DEBUG_MEM_NCE3 40059 -#define ID_DEBUG_MEM_RPLVIEW 40060 -#define ID_DEBUG_STACK_PUSH 40061 -#define ID_DEBUG_STACK_POP 40062 -#define ID_DEBUG_STACK_MODIFY 40063 -#define ID_INTR_STEPOVERINT 40064 -#define ID_INFO_LASTINSTRUCTIONS 40065 -#define ID_INFO_PROFILE 40066 -#define ID_INFO_WRITEONLYREG 40067 +#define ID_DEBUG_MEM_SAVE 40060 +#define ID_DEBUG_MEM_LOAD 40061 +#define ID_DEBUG_MEM_RPLVIEW 40062 +#define ID_DEBUG_STACK_PUSH 40063 +#define ID_DEBUG_STACK_POP 40064 +#define ID_DEBUG_STACK_MODIFY 40065 +#define ID_INTR_STEPOVERINT 40066 +#define ID_INFO_LASTINSTRUCTIONS 40067 +#define ID_INFO_PROFILE 40068 +#define ID_INFO_WRITEONLYREG 40069 #define ID_FILE_MRU_FILE1 40100 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 125 -#define _APS_NEXT_COMMAND_VALUE 40068 -#define _APS_NEXT_CONTROL_VALUE 1130 +#define _APS_NEXT_RESOURCE_VALUE 132 +#define _APS_NEXT_COMMAND_VALUE 40070 +#define _APS_NEXT_CONTROL_VALUE 1134 #define _APS_NEXT_SYMED_VALUE 108 #endif #endif diff --git a/Sources/Emu48/RPL.C b/Sources/Emu48/RPL.C index 21aecc9..76fcbec 100644 --- a/Sources/Emu48/RPL.C +++ b/Sources/Emu48/RPL.C @@ -390,10 +390,10 @@ DWORD RPL_CreateTemp(DWORD l) 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 = HeapAlloc(hHeap,0,b-a); // move down rtn stack + p = malloc(b-a); // move down rtn stack Npeek(p,a,b-a); Nwrite(p,a+l,b-a); - HeapFree(hHeap,0,p); + free(p); Write5(a+l-5,l); // set object length field return (a+1); // return base address of new object } diff --git a/Sources/Emu48/SERIAL.C b/Sources/Emu48/SERIAL.C index 467748c..ea8b60e 100644 --- a/Sources/Emu48/SERIAL.C +++ b/Sources/Emu48/SERIAL.C @@ -113,11 +113,11 @@ BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort) _tcscat(szDevice,strPort); // device name hComm = CreateFile(szDevice, - GENERIC_READ | GENERIC_WRITE, + GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (hComm != INVALID_HANDLE_VALUE) @@ -140,7 +140,7 @@ BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort) hCThreadTxd = CreateThread(NULL,0,&TransmitThread,NULL,CREATE_SUSPENDED,&dwThreadId); _ASSERT(hCThreadTxd); SetThreadPriority(hCThreadTxd,THREAD_PRIORITY_ABOVE_NORMAL); - ResumeThread(hCThreadTxd); // start thread + ResumeThread(hCThreadTxd); // start thread // create Comm event handler bReading = FALSE; @@ -148,7 +148,7 @@ BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort) hCThreadEv = CreateThread(NULL,0,&EventThread,NULL,CREATE_SUSPENDED,&dwThreadId); _ASSERT(hCThreadEv); SetThreadPriority(hCThreadEv,THREAD_PRIORITY_ABOVE_NORMAL); - ResumeThread(hCThreadEv); // start thread + ResumeThread(hCThreadEv); // start thread while (!bReading) Sleep(0); // wait for SerialThread started } else diff --git a/Sources/Emu48/SETTINGS.C b/Sources/Emu48/SETTINGS.C index 8d60e8e..2458471 100644 --- a/Sources/Emu48/SETTINGS.C +++ b/Sources/Emu48/SETTINGS.C @@ -63,7 +63,7 @@ static VOID ReadReg(LPCTSTR lpSubKey, LPCTSTR lpValueName, LPBYTE lpData, DWORD lstrcat(lpKey, lpSubKey); // full registry key retCode = RegOpenKeyEx(HKEY_CURRENT_USER, - lpKey, + lpKey, 0, KEY_QUERY_VALUE, &hKey); @@ -91,9 +91,9 @@ static BOOL WriteReg(LPCTSTR lpSubKey, LPCTSTR lpValueName, DWORD dwType, CONST retCode = RegCreateKeyEx(HKEY_CURRENT_USER, lpKey, 0,_T(""), - REG_OPTION_NON_VOLATILE, + REG_OPTION_NON_VOLATILE, KEY_WRITE, - NULL, + NULL, &hKey, &dwDisposition); _ASSERT(retCode == ERROR_SUCCESS); @@ -113,7 +113,7 @@ static BOOL DelReg(LPCTSTR lpSubKey, LPCTSTR lpValueName) lstrcat(lpKey, lpSubKey); // full registry key retCode = RegOpenKeyEx(HKEY_CURRENT_USER, - lpKey, + lpKey, 0, KEY_SET_VALUE, &hKey); @@ -179,6 +179,7 @@ VOID ReadSettings(VOID) // Emulator bAlwaysOnTop = ReadInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop); bActFollowsMouse = ReadInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse); + 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); @@ -187,12 +188,15 @@ VOID ReadSettings(VOID) bGrayscale = ReadInt(_T("Emulator"),_T("Grayscale"),bGrayscale); bWaveBeep = ReadInt(_T("Emulator"),_T("WaveBeep"),bWaveBeep); dwWaveVol = ReadInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol); - SetSpeed(bRealSpeed); // set speed // 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)); @@ -222,6 +226,7 @@ VOID WriteSettings(VOID) // Emulator WriteInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop); WriteInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse); + WriteInt(_T("Emulator"),_T("SingleInstance"),bSingleInstance); WriteInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed); WriteInt(_T("Emulator"),_T("SXCycles"),dwSXCycles); WriteInt(_T("Emulator"),_T("GXCycles"),dwGXCycles); @@ -235,6 +240,10 @@ VOID WriteSettings(VOID) // 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); diff --git a/Sources/Emu48/STACK.C b/Sources/Emu48/STACK.C index 75b7eea..d10fd32 100644 --- a/Sources/Emu48/STACK.C +++ b/Sources/Emu48/STACK.C @@ -88,7 +88,7 @@ static INT RPL_SetZInt(LPCTSTR cp,LPBYTE pbyNum,INT nSize) } // nStrLen = no. of digits without sign - if (nStrLen >= nSize) // destination buffer too small + if (nStrLen >= nSize) // destination buffer too small return 0; nNumSize = nStrLen + 1; // no. of written data @@ -128,6 +128,7 @@ static INT RPL_GetBcd(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,CONST TCHAR cD 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--) @@ -225,7 +226,7 @@ static INT RPL_SetBcd(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYT if (*cp != cDec) // no decimal point { // count integer part - while (*cp >= _T('0') && *cp <= _T('9')) + while (*cp >= _T('0') && *cp <= _T('9')) byNum[++nIp] = *cp++ - _T('0'); if (!nIp) return 0; } @@ -402,7 +403,7 @@ static INT RPL_SetComplex(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,L } } } - HeapFree(hHeap,0,pszData); + free(pszData); } return nLen; } @@ -460,12 +461,12 @@ static INT DoInt(DWORD dwAddress,LPTSTR cp,INT nSize) if (nIntLen <= 0) return 0; // error in calculator object nLength = 0; - if ((lpbyData = HeapAlloc(hHeap,0,nIntLen))) + if ((lpbyData = malloc(nIntLen))) { // get precisition integer object content and decode it Npeek(lpbyData,dwAddress+5,nIntLen); nLength = RPL_GetZInt(lpbyData,nIntLen,cp,nSize); - HeapFree(hHeap,0,lpbyData); + free(lpbyData); } return nLength; } @@ -551,7 +552,7 @@ LRESULT OnStackCopy(VOID) // copy data from stack if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,dwSize)) == NULL) goto error; - if ((lpbyData = GlobalLock(hClipObj))) + if ((lpbyData = (LPBYTE) GlobalLock(hClipObj))) { // copy data to memory CopyMemory(lpbyData,cBuffer,dwSize); @@ -572,7 +573,7 @@ LRESULT OnStackCopy(VOID) // copy data from stack if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,dwSize + 1)) == NULL) goto error; - if ((lpbyData = GlobalLock(hClipObj))) // lock memory + if ((lpbyData = (LPBYTE) GlobalLock(hClipObj))) // lock memory { // copy data into clipboard buffer for (dwAddress += 5;dwSize-- > 0;dwAddress += 2,++lpbyData) @@ -580,8 +581,8 @@ LRESULT OnStackCopy(VOID) // copy data from stack *lpbyData = 0; // set EOS GlobalUnlock(hClipObj); // unlock memory - uClipboardFormat = CF_TEXT; // always text } + uClipboardFormat = CF_TEXT; // always text break; default: MessageBeep(MB_OK); // error beep @@ -737,7 +738,7 @@ LRESULT OnStackPaste(VOID) // paste data to stack // any other format { DWORD dwSize = lstrlen(lpstrClipdata); - if ((lpbyData = HeapAlloc(hHeap,0,dwSize * 2))) + if ((lpbyData = malloc(dwSize * 2))) { LPBYTE lpbySrc,lpbyDest; DWORD dwLoop; @@ -776,7 +777,7 @@ LRESULT OnStackPaste(VOID) // paste data to stack // push object to stack RPL_Push(1,dwAddress); } - HeapFree(hHeap,0,lpbyData); + free(lpbyData); } } } diff --git a/Sources/Emu48/SYMBFILE.C b/Sources/Emu48/SYMBFILE.C index 3784887..f0d609d 100644 --- a/Sources/Emu48/SYMBFILE.C +++ b/Sources/Emu48/SYMBFILE.C @@ -171,7 +171,7 @@ BOOL RplLoadTable(LPCTSTR lpszFilename) *pcPtr = 0; // set EOS // allocate symbol memory - VERIFY(pData = HeapAlloc(hHeap,0,sizeof(RefData))); + VERIFY(pData = malloc(sizeof(RefData))); pData->lpszName = DuplicateString(szSymbolName); pData->dwAddr = GetBigEndian(byPage+dwPageIndex+38,sizeof(DWORD)); @@ -209,8 +209,8 @@ VOID RplDeleteTable(VOID) while (ppsBase[i] != NULL) // walk through all datasets { pData = ppsBase[i]->pNext; - HeapFree(hHeap,0,ppsBase[i]->lpszName); - HeapFree(hHeap,0,ppsBase[i]); + free(ppsBase[i]->lpszName); + free(ppsBase[i]); ppsBase[i] = pData; } } diff --git a/Sources/Emu48/TIMER.C b/Sources/Emu48/TIMER.C index fc830bf..678ad02 100644 --- a/Sources/Emu48/TIMER.C +++ b/Sources/Emu48/TIMER.C @@ -244,7 +244,6 @@ static void CALLBACK TimeProc(UINT uEventId, UINT uMsg, DWORD_PTR dwUser, DWORD_ UNREFERENCED_PARAMETER(dw2); } - VOID SetHP48Time(VOID) // set date and time { SYSTEMTIME ts; @@ -257,7 +256,7 @@ VOID SetHP48Time(VOID) // set date and time GetLocalTime(&ts); // local time, _ftime() cause memory/resource leaks - // calculate days until 01.01.1970 + // calculate days until 01.01.0000 (Erlang BIF localtime/0) dw = (DWORD) ts.wMonth; if (dw > 2) dw -= 3L; @@ -269,17 +268,18 @@ VOID SetHP48Time(VOID) // set date and time dw = (DWORD) ts.wDay + (153L * dw + 2L) / 5L; dw += (146097L * (((DWORD) ts.wYear) / 100L)) / 4L; dw += (1461L * (((DWORD) ts.wYear) % 100L)) / 4L; - dw -= 719469L; + dw += (-719469L + 719528L); // days from year 0 + + ticks = (ULONGLONG) dw; // convert to 64 bit // convert into seconds and add time - dw = dw * 24L + (DWORD) ts.wHour; - dw = dw * 60L + (DWORD) ts.wMinute; - dw = dw * 60L + (DWORD) ts.wSecond; + ticks = ticks * 24L + (ULONGLONG) ts.wHour; + ticks = ticks * 60L + (ULONGLONG) ts.wMinute; + ticks = ticks * 60L + (ULONGLONG) ts.wSecond; // create timerticks = (s + ms) * 8192 - ticks = ((ULONGLONG) dw << 13) | (((ULONGLONG) ts.wMilliseconds << 10) / 125); + ticks = (ticks << 13) | (((ULONGLONG) ts.wMilliseconds << 10) / 125); - ticks += UNIX_0_TIME; // add offset ticks from year 0 ticks += Chipset.t2; // add actual timer2 value time = ticks; // save for calc. timeout diff --git a/Sources/Emu48/UDP.C b/Sources/Emu48/UDP.C new file mode 100644 index 0000000..753066a --- /dev/null +++ b/Sources/Emu48/UDP.C @@ -0,0 +1,85 @@ +/* + * 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 IN_ADDR ip_addr = { 255, 255, 255, 255 }; + +VOID ResetUdp(VOID) +{ + ip_addr.s_addr = INADDR_NONE; // invalidate saved UDP address + return; +} + +BOOL SendByteUdp(BYTE byData) +{ + WSADATA wsd; + SOCKET sClient; + SOCKADDR_IN sServer; + + BOOL bErr = TRUE; + + VERIFY(WSAStartup(MAKEWORD(1,1),&wsd) == 0); + + if (ip_addr.s_addr == INADDR_NONE) // IP address not specified + { + LPSTR lpszIpAddr; + + #if defined _UNICODE + DWORD dwLength = lstrlen(szUdpServer) + 1; + + if ((lpszIpAddr = (LPSTR) malloc(dwLength)) == NULL) + return TRUE; // server not found + + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, + szUdpServer, dwLength, + lpszIpAddr, dwLength, NULL, NULL); + #else + lpszIpAddr = szUdpServer; + #endif + + ip_addr.s_addr = inet_addr(lpszIpAddr); + + // not a valid ip address -> try to get ip address from name server + if (ip_addr.s_addr == INADDR_NONE) + { + PHOSTENT host = gethostbyname(lpszIpAddr); + if (host == NULL) + { + #if defined _UNICODE + free(lpszIpAddr); + #endif + return TRUE; // server not found + } + + ip_addr.s_addr = ((PIN_ADDR) host->h_addr_list[0])->s_addr; + } + #if defined _UNICODE + free(lpszIpAddr); + #endif + } + + // create UDP socket + if ((sClient = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) + { + sServer.sin_family = AF_INET; + sServer.sin_port = htons(wUdpPort); + sServer.sin_addr.s_addr = ip_addr.s_addr; + + // 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; +} diff --git a/Sources/GCCPatch/EMU48GCC.RC b/Sources/GCCPatch/EMU48GCC.RC index 533cae2..55dcc67 100644 --- a/Sources/GCCPatch/EMU48GCC.RC +++ b/Sources/GCCPatch/EMU48GCC.RC @@ -77,12 +77,40 @@ BEGIN BOTTOMMARGIN, 145 END - IDD_SETTINGS, DIALOG + IDD_SET_GENERAL, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 160 - TOPMARGIN, 4 - BOTTOMMARGIN, 280 + RIGHTMARGIN, 244 + VERTGUIDE, 14 + VERTGUIDE, 161 + VERTGUIDE, 168 + VERTGUIDE, 237 + TOPMARGIN, 7 + BOTTOMMARGIN, 127 + END + + IDD_SET_MEMORY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 244 + VERTGUIDE, 14 + VERTGUIDE, 237 + TOPMARGIN, 7 + BOTTOMMARGIN, 127 + END + + IDD_SET_PERIPHERAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 244 + VERTGUIDE, 14 + VERTGUIDE, 147 + VERTGUIDE, 154 + VERTGUIDE, 161 + VERTGUIDE, 237 + TOPMARGIN, 7 + BOTTOMMARGIN, 127 + HORZGUIDE, 82 END IDD_CHOOSEKML, DIALOG @@ -157,6 +185,22 @@ BEGIN BOTTOMMARGIN, 74 END + IDD_DEBUG_MEMSAVE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 257 + TOPMARGIN, 7 + BOTTOMMARGIN, 58 + END + + IDD_DEBUG_MEMLOAD, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 257 + TOPMARGIN, 7 + BOTTOMMARGIN, 58 + END + IDD_DEBUG_SETTINGS, DIALOG BEGIN LEFTMARGIN, 7 @@ -252,69 +296,88 @@ 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 © 2010 Christoph Gießelink && Sébastien Carlier", + LTEXT "Copyright © 2012 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 | ES_READONLY END -IDD_SETTINGS DIALOG DISCARDABLE 0, 0, 167, 287 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Settings" +IDD_SET_GENERAL DIALOG DISCARDABLE 0, 0, 251, 134 +STYLE WS_CHILD | WS_VISIBLE | WS_CAPTION +CAPTION "General" FONT 8, "MS Sans Serif" BEGIN CONTROL "Authentic Calculator Speed",IDC_REALSPEED,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,13,13,100,10 + BS_AUTOCHECKBOX | WS_TABSTOP,14,17,133,10 CONTROL "Enable Virtual LCD Delay",IDC_GRAYSCALE,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,13,25,100,10 - CONTROL "Always On Top",IDC_ALWAYSONTOP,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,13,37,65,10 - CONTROL "Activation Follows Mouse",IDC_ACTFOLLOWSMOUSE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,49,100,10 + BS_AUTOCHECKBOX | WS_TABSTOP,14,28,133,10 + CONTROL "Always On Top",IDC_ALWAYSONTOP,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,14,40,133,10 + CONTROL "Activation Follows Mouse",IDC_ACTFOLLOWSMOUSE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,14,52,133,10 + CONTROL "Single Instance",IDC_SINGLEINSTANCE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,14,64,133,10 CONTROL "Automatically Save Files",IDC_AUTOSAVE,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,13,61,89,10 + BS_AUTOCHECKBOX | WS_TABSTOP,14,76,133,10 CONTROL "Automatically Save Files On Exit",IDC_AUTOSAVEONEXIT, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,73,114,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,88,133,10 CONTROL "Show Load Object Warning",IDC_OBJECTLOADWARNING,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,13,85,102,10 + BS_AUTOCHECKBOX | WS_TABSTOP,14,100,133,10 CONTROL "Always Show KML Compilation Result",IDC_ALWAYSDISPLOG, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,97,133,10 - GROUPBOX "General",IDC_STATIC,7,4,153,107 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,112,133,10 + GROUPBOX "General",IDC_STATIC,7,7,148,120 CONTROL "HP Mnemonics",IDC_DISASM_HP,"Button",BS_AUTORADIOBUTTON | - WS_GROUP | WS_TABSTOP,13,125,65,11 + WS_GROUP | WS_TABSTOP,168,21,69,11 CONTROL "Class Mnemonics",IDC_DISASM_CLASS,"Button", - BS_AUTORADIOBUTTON,84,125,70,11 - GROUPBOX "Disassembler",IDC_STATIC,7,114,153,28 - LTEXT "Volume",IDC_STATIC,13,158,24,8 - CONTROL "Slider1",IDC_SOUND_SLIDER,"msctls_trackbar32", - TBS_AUTOTICKS | WS_TABSTOP,39,153,68,18 - CONTROL "Speaker",IDC_SOUND_SPEAKER,"Button",BS_AUTORADIOBUTTON | - WS_GROUP | WS_TABSTOP,111,152,43,10 - CONTROL "Wave",IDC_SOUND_WAVE,"Button",BS_AUTORADIOBUTTON,111, - 163,43,10 - GROUPBOX "Sound",IDC_STATIC,7,144,153,34 + BS_AUTORADIOBUTTON,168,35,69,11 + GROUPBOX "Disassembler",IDC_STATIC,161,7,83,120 +END + +IDD_SET_MEMORY DIALOG DISCARDABLE 0, 0, 251, 134 +STYLE WS_CHILD | WS_VISIBLE | WS_CAPTION +CAPTION "Memory" +FONT 8, "MS Sans Serif" +BEGIN CONTROL "Port 1 is Plugged",IDC_PORT1EN,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,13,189,67,10 + WS_TABSTOP,14,20,67,10 CONTROL "Port 1 is Writeable",IDC_PORT1WR,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,84,189,69,10 + BS_AUTOCHECKBOX | WS_TABSTOP,124,20,69,10 CONTROL "Port 2 is Shared",IDC_PORT2ISSHARED,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,13,201,65,10 + BS_AUTOCHECKBOX | WS_TABSTOP,14,32,65,10 CONTROL "Port 2 is Writeable",IDC_PORT2WR,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,84,201,69,10 - LTEXT "Port 2 File :",IDC_STATIC,13,216,37,8 - EDITTEXT IDC_PORT2,51,214,94,12,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_PORT2LOAD,145,214,10,12 - GROUPBOX "Memory Cards",IDC_STATIC,7,180,153,51 - LTEXT "Wire:",IDC_STATIC,13,245,17,8 - COMBOBOX IDC_WIRE,31,243,48,42,CBS_DROPDOWNLIST | WS_VSCROLL | + BS_AUTOCHECKBOX | WS_TABSTOP,124,32,69,10 + LTEXT "Port 2 File :",IDC_STATIC,14,47,37,8 + EDITTEXT IDC_PORT2,52,45,175,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_PORT2LOAD,227,45,10,12 + GROUPBOX "Memory Cards",IDC_STATIC,7,7,237,58 +END + +IDD_SET_PERIPHERAL DIALOG DISCARDABLE 0, 0, 251, 134 +STYLE WS_CHILD | WS_VISIBLE | WS_CAPTION +CAPTION "Peripheral" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Volume",IDC_STATIC,14,21,24,8 + CONTROL "Slider1",IDC_SOUND_SLIDER,"msctls_trackbar32", + TBS_AUTOTICKS | WS_TABSTOP,40,16,84,18 + CONTROL "Speaker",IDC_SOUND_SPEAKER,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,135,20,43,10 + CONTROL "Wave",IDC_SOUND_WAVE,"Button",BS_AUTORADIOBUTTON,194,20, + 43,10 + GROUPBOX "Sound",IDC_STATIC,7,7,237,34 + LTEXT "IP Address:",IDC_STATIC,14,60,37,8 + LTEXT "Port:",IDC_STATIC,119,60,16,8 + EDITTEXT IDC_IR_ADDR,14,70,101,12,ES_AUTOHSCROLL + EDITTEXT IDC_IR_PORT,119,70,28,12,ES_NUMBER + GROUPBOX "Infrared Printer",IDC_STATIC,7,43,147,50 + LTEXT "Wire:",IDC_STATIC,168,58,17,8 + COMBOBOX IDC_WIRE,189,56,48,42,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "IR:",IDC_STATIC,89,245,9,8 - COMBOBOX IDC_IR,107,243,48,43,CBS_DROPDOWNLIST | WS_VSCROLL | + LTEXT "IR:",IDC_STATIC,168,74,9,8 + COMBOBOX IDC_IR,189,72,48,43,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Serial Ports",IDC_STATIC,7,233,153,27 - DEFPUSHBUTTON "OK",IDOK,9,266,50,14 - PUSHBUTTON "Cancel",IDCANCEL,107,266,50,14 + GROUPBOX "Serial Ports",IDC_STATIC,161,43,83,50 END IDD_CHOOSEKML DIALOG DISCARDABLE 0, 0, 195, 66 @@ -362,17 +425,10 @@ BEGIN PUSHBUTTON "&Next Address",IDC_DISASM_NEXT,99,144,47,14 PUSHBUTTON "&Copy Data",IDC_DISASM_COPY,150,144,47,14 PUSHBUTTON "Cancel",IDCANCEL,201,144,47,14 + LTEXT "Mapping Mode:",IDC_DISASM_MODE_TEXT,12,17,45,8 + COMBOBOX IDC_DISASM_MODE,60,14,35,90,CBS_DROPDOWNLIST | + WS_TABSTOP GROUPBOX "Module",IDC_DISASM_MODULE,7,5,241,26 - CONTROL "Map",IDC_DISASM_MAP,"Button",BS_AUTORADIOBUTTON | - WS_GROUP | WS_TABSTOP,14,16,37,10 - CONTROL "ROM",IDC_DISASM_ROM,"Button",BS_AUTORADIOBUTTON,61,16, - 37,10 - CONTROL "RAM",IDC_DISASM_RAM,"Button",BS_AUTORADIOBUTTON,108,16, - 37,10 - CONTROL "Port 1",IDC_DISASM_PORT1,"Button",BS_AUTORADIOBUTTON, - 155,16,37,10 - CONTROL "Port 2",IDC_DISASM_PORT2,"Button",BS_AUTORADIOBUTTON, - 202,16,37,10 LISTBOX IDC_DISASM_WIN,7,37,241,100,NOT LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP @@ -404,7 +460,7 @@ BEGIN LTEXT "PC=00000",IDC_REG_PC,236,108,33,8 LTEXT "OUT=000",IDC_REG_OUT,192,119,29,8 LTEXT "IN=0000",IDC_REG_IN,240,119,29,8 - LTEXT "ST=0000",IDC_REG_ST,192,130,29,8 + LTEXT "ST=0000",IDC_REG_ST,192,130,29,8 LTEXT "CY=0",IDC_REG_CY,224,130,17,8 LTEXT "Mode=H",IDC_REG_MODE,244,130,25,8 LTEXT "MP=0",IDC_REG_MP,192,140,17,8 @@ -543,6 +599,36 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,93,60,50,14 END +IDD_DEBUG_MEMSAVE DIALOG DISCARDABLE 0, 0, 264, 65 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Save Memory Data" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "File:",IDC_STATIC,7,10,14,8 + EDITTEXT IDC_DEBUG_DATA_FILE,25,7,181,14,ES_AUTOHSCROLL + 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 + 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 + PUSHBUTTON "Cancel",IDCANCEL,207,44,50,14 +END + +IDD_DEBUG_MEMLOAD DIALOG DISCARDABLE 0, 0, 264, 65 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Load Memory Data" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "File:",IDC_STATIC,7,10,14,8 + EDITTEXT IDC_DEBUG_DATA_FILE,25,7,181,14,ES_AUTOHSCROLL + 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 + PUSHBUTTON "Cancel",IDCANCEL,207,44,50,14 +END + IDD_DEBUG_SETTINGS DIALOG DISCARDABLE 0, 0, 184, 116 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Debugger Settings" @@ -630,8 +716,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,5,0,0 - PRODUCTVERSION 1,5,0,0 + FILEVERSION 1,5,3,0 + PRODUCTVERSION 1,5,3,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -646,14 +732,14 @@ BEGIN BEGIN BLOCK "04090000" BEGIN - VALUE "CompanyName", "Sebastien Carlier & Christoph Gießelink\0" + VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0" VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0" - VALUE "FileVersion", "1, 5, 0, 0\0" + VALUE "FileVersion", "1, 5, 3, 0\0" VALUE "InternalName", "Emu48\0" - VALUE "LegalCopyright", "Copyright © 2010\0" + VALUE "LegalCopyright", "Copyright © 2012\0" VALUE "OriginalFilename", "Emu48.exe\0" VALUE "ProductName", "Emu48\0" - VALUE "ProductVersion", "1, 5, 0, 0\0" + VALUE "ProductVersion", "1, 5, 3, 0\0" END END BLOCK "VarFileInfo" @@ -819,7 +905,10 @@ BEGIN , GRAYED END MENUITEM SEPARATOR - MENUITEM "RPL Object Viewer...", ID_DEBUG_MEM_RPLVIEW + MENUITEM "&Load Memory Data...", ID_DEBUG_MEM_LOAD + MENUITEM "S&ave Memory Data...", ID_DEBUG_MEM_SAVE + MENUITEM SEPARATOR + MENUITEM "&RPL Object Viewer...", ID_DEBUG_MEM_RPLVIEW END END @@ -860,6 +949,13 @@ END #endif // APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// 24 +// + +1 24 MOVEABLE PURE "Emu48.xml" + ///////////////////////////////////////////////////////////////////////////// // // Accelerator @@ -890,14 +986,6 @@ BEGIN ID_BREAKPOINTS_CODEEDIT "Breakpoint List" END - -///////////////////////////////////////////////////////////////////////////// -// -// Manifest -// - -1 24 MOVEABLE PURE "Emu48.xml" - #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/Sources/GCCPatch/Makefile b/Sources/GCCPatch/Makefile index 3eddb8d..1b17bc0 100644 --- a/Sources/GCCPatch/Makefile +++ b/Sources/GCCPatch/Makefile @@ -22,13 +22,13 @@ TARGET=$(PRJ).exe RSRC=$(PRJ).rc RSRCOBJ=$(PRJ).o -OBJS=cursor.o ddeserv.o debugger.o disasm.o display.o disrpl.o \ +OBJS=cursor.o ddeserv.o debugger.o disasm.o dismem.o display.o disrpl.o \ emu48.o engine.o external.o fetch.o files.o i28f160.o keyboard.o \ - keymacro.o kml.o lowbat.o mru.o mops.o opcodes.o rpl.o serial.o \ - settings.o stack.o symbfile.o timer.o \ + keymacro.o kml.o lowbat.o mru.o mops.o opcodes.o redeye.o \ + rpl.o serial.o settings.o stack.o symbfile.o timer.o udp.o \ $(RSRCOBJ) -LIBS=-lwinmm -lcomctl32 +LIBS=-lwinmm -lcomctl32 -lws2_32 all: $(TARGET) @@ -58,6 +58,9 @@ debugger.o: debugger.c pch.h resource.h emu48.h \ disasm.o: disasm.c pch.h emu48.h types.h $(CC) $(CFLAGS) $(DEFINES) -c -o disasm.o disasm.c +dismem.o: dismem.c pch.h emu48.h + $(CC) $(CFLAGS) $(DEFINES) -c -o dismem.o dismem.c + display.o: display.c pch.h resource.h emu48.h \ types.h io.h kml.h $(CC) $(CFLAGS) $(DEFINES) -c -o display.o display.c @@ -112,6 +115,9 @@ opcodes.o: opcodes.c pch.h emu48.h types.h opcodes.h \ # pch.o: pch.c pch.h # $(CC) $(CFLAGS) $(DEFINES) -c -o pch.o pch.c +redeye.o: redeye.c pch.h emu48.h io.h + $(CC) $(CFLAGS) $(DEFINES) -c -o redeye.o redeye.c + rpl.o: rpl.c pch.h emu48.h types.h io.h $(CC) $(CFLAGS) $(DEFINES) -c -o rpl.o rpl.c @@ -130,6 +136,9 @@ symbfile.o: symbfile.c pch.h emu48.h timer.o: timer.c pch.h emu48.h types.h io.h $(CC) $(CFLAGS) $(DEFINES) -c -o timer.o timer.c +udp.o: udp.c pch.h io.h + $(CC) $(CFLAGS) $(DEFINES) -c -o udp.o udp.c + $(RSRCOBJ): $(RSRC) resource.h emu48.ico dbgtool.bmp checkbox.bmp Emu48.xml windres $(DEFINES) -i $(RSRC) -o $(RSRCOBJ) diff --git a/Sources/GCCPatch/PCH.H b/Sources/GCCPatch/PCH.H index c0ab333..d88913e 100644 --- a/Sources/GCCPatch/PCH.H +++ b/Sources/GCCPatch/PCH.H @@ -45,3 +45,4 @@ int __cdecl _outp(unsigned short, int); #if !defined _ASSERT #define _ASSERT(a) #endif +#define _CrtDumpMemoryLeaks() ((int)0) diff --git a/Sources/GCCPatch/README.TXT b/Sources/GCCPatch/README.TXT index 880055a..d95f105 100644 --- a/Sources/GCCPatch/README.TXT +++ b/Sources/GCCPatch/README.TXT @@ -2,7 +2,7 @@ * Emu48 GCC Version * ********************* -Emu48 is normally compiled with the Microsoft Visual C++ V6.0 compiler. An +Emu48 is normally compiled with the Microsoft Visual C++ 2005 compiler. An alternative is the GCC compiler from the GNU project. A great distribution of the compiler and the necessary files is MinGW at www.mingw.org. @@ -23,6 +23,20 @@ mingw32-make-3.81-20080326.tar.gz binutils-2.18.50-20080109-2.tar.gz gcc-core-3.4.5-20060117-1.tar.gz +or + +gcc-core-4.6.2-1-mingw32-bin.tar.lzma +binutils-2.22-1-mingw32-bin.tar.lzma +libgmp-5.0.1-1-mingw32-dll-10.tar.lzma +libmpc-0.8.1-1-mingw32-dll-2.tar.lzma +libmpfr-2.4.1-1-mingw32-dll-1.tar.lzma +libpthreadgc-2.9.0-mingw32-pre-20110507-2-dll-2.tar.lzma +mingwrt-3.20-mingw32-dev.tar.gz +mingwrt-3.20-mingw32-dll.tar.gz +pthreads-w32-2.9.0-mingw32-pre-20110507-2-dev.tar.lzma +w32api-3.17-2-mingw32-dev.tar.lzma +mingw32-make-3.81-20080326.tar.gz + Older versions of the MinGW package might not work, because there are several bug fixes, especially in the header files, made in the last time. @@ -34,4 +48,4 @@ Many thanks to Pedro A. Arranda Guti compatible. -07/27/10 (c) by Christoph Gießelink +05/03/12 (c) by Christoph Gießelink diff --git a/uninst.exe b/uninst.exe index 742cfe92427ef2f405bca5260b09c84c3125d683..84f95664969c64a7a7051bc0d080ff23d0922e35 100755 GIT binary patch delta 12777 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