From 5f619b11abc21d079cea509418798114214c4402 Mon Sep 17 00:00:00 2001 From: Gwenhael Le Moine Date: Tue, 19 Mar 2024 22:37:03 +0100 Subject: [PATCH] 2001-05-18: Updated to version 1.25 --- CARDCOPY.EXE | Bin 28672 -> 32768 bytes CARDCOPY.TXT | 16 +- CP_48G3.BMP | Bin 217526 -> 217526 bytes CP_48G3.KML | 37 +- CP_48S3.BMP | Bin 217436 -> 217526 bytes CP_48S3.KML | 35 +- DEBUGGER.TXT | 55 +- EMU48.EXE | Bin 233472 -> 233472 bytes EMU48.TXT | 92 +-- Emu48asc/EMU48ASC.BIN | Bin 0 -> 147 bytes Emu48asc/EMU48ASC.SRC | 48 ++ Emu48asc/EMU48ASC.TXT | 42 ++ Emu48asc/EMU49ASC.BIN | Bin 0 -> 147 bytes Emu48asc/EMU49ASC.SRC | 60 ++ MKE48.EXE | Bin 0 -> 31232 bytes MKE48.TXT | 57 ++ MkShared.exe | Bin 21504 -> 28672 bytes PROBLEMS.TXT | 13 +- TRUELCD.KMI | 60 +- sources/Cardcopy/CARDCOPY.C | 82 ++- sources/Cardcopy/TYPES.H | 103 ++++ sources/Emu48/CHANGES.TXT | 542 ++++++++++++++++- sources/Emu48/CHECKBOX.BMP | Bin 0 -> 250 bytes sources/Emu48/DBGTOOL.BMP | Bin 0 -> 1198 bytes sources/Emu48/DDESERV.C | 33 +- sources/Emu48/DEBUGGER.C | 1090 ++++++++++++++++++++++++---------- sources/Emu48/DEBUGGER.H | 25 +- sources/Emu48/DISASM.C | 744 +++++++++++------------ sources/Emu48/DISPLAY.C | 149 +++-- sources/Emu48/EMU48.C | 463 +++++++-------- sources/Emu48/EMU48.DSP | 15 +- sources/Emu48/EMU48.H | 238 ++++---- sources/Emu48/EMU48.ICO | Bin 7078 -> 1078 bytes sources/Emu48/EMU48.RC | 290 +++++---- sources/Emu48/ENGINE.C | 222 ++++--- sources/Emu48/EXTERNAL.C | 29 +- sources/Emu48/FETCH.C | 2 +- sources/Emu48/FILES.C | 418 +++++++------ sources/Emu48/I28F160.C | 4 +- sources/Emu48/IO.H | 20 + sources/Emu48/KEYBOARD.C | 2 +- sources/Emu48/KML.C | 693 +++++++++++---------- sources/Emu48/KML.H | 35 +- sources/Emu48/MOPS.C | 467 +++++++++------ sources/Emu48/OPCODES.C | 62 +- sources/Emu48/OPCODES.H | 3 +- sources/Emu48/OPS.H | 7 +- sources/Emu48/PCH.H | 2 + sources/Emu48/RESOURCE.H | 222 +++---- sources/Emu48/RPL.C | 39 +- sources/Emu48/SERIAL.C | 71 +-- sources/Emu48/SETTINGS.C | 174 ++++-- sources/Emu48/TIMER.C | 7 +- sources/GCCPatch/EMU48GCC.RC | 705 ++++++++++++++++++++++ sources/GCCPatch/Makefile | 117 ++++ sources/GCCPatch/PCH.H | 37 ++ sources/GCCPatch/ReadMe.txt | 25 + sources/MkShared/Main.c | 7 +- sources/Mke48/MKE48.C | 120 ++++ sources/Mke48/MKE48.DSP | 103 ++++ sources/Mke48/TYPES.H | 103 ++++ 61 files changed, 5547 insertions(+), 2438 deletions(-) create mode 100644 Emu48asc/EMU48ASC.BIN create mode 100644 Emu48asc/EMU48ASC.SRC create mode 100644 Emu48asc/EMU48ASC.TXT create mode 100644 Emu48asc/EMU49ASC.BIN create mode 100644 Emu48asc/EMU49ASC.SRC create mode 100644 MKE48.EXE create mode 100644 MKE48.TXT create mode 100644 sources/Cardcopy/TYPES.H create mode 100644 sources/Emu48/CHECKBOX.BMP create mode 100644 sources/Emu48/DBGTOOL.BMP create mode 100644 sources/GCCPatch/EMU48GCC.RC create mode 100644 sources/GCCPatch/Makefile create mode 100644 sources/GCCPatch/PCH.H create mode 100644 sources/GCCPatch/ReadMe.txt create mode 100644 sources/Mke48/MKE48.C create mode 100644 sources/Mke48/MKE48.DSP create mode 100644 sources/Mke48/TYPES.H diff --git a/CARDCOPY.EXE b/CARDCOPY.EXE index d8f6abadf7dcf7a39d090f213769502fc8ba8423..b6517bcf7c210521187faa9269d363986708419d 100644 GIT binary patch delta 7077 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 W|1{R(i^JMoz4hWhCa?xg_WuH(4hOCP diff --git a/CARDCOPY.TXT b/CARDCOPY.TXT index 590a724..9d17272 100644 --- a/CARDCOPY.TXT +++ b/CARDCOPY.TXT @@ -1,5 +1,5 @@ CARDCOPY - A HP48 Port1 Import/Export Tool for Emu48 -05/23/00 (c) by Christoph Gießelink, cgiess@swol.de +12/27/00 (c) by Christoph Gießelink, cgiess@swol.de ************ @@ -8,13 +8,13 @@ CARDCOPY - A HP48 Port1 Import/Export Tool for Emu48 Emu48, when emulating a HP48, save the user, the port1 memory and other information in one file (*.E48). But sometimes it's useful to import or to -export port1 data. CARDCOPY now allows you to import/export a 128KB card file -into/from the port1 memory of an Emu48 state file. The program can handle -HP48SX/GX state and 128KB card files (file size 256KB) as source or destination. -On all other file types you'll get an error. It's recommended to switch off the -emulated HP48 before importing port1 data into a state file. So you're sure that -the HP48 wasn't busy and, when you switch on the emulated calculator, the -changed card will be detected. +export port1 data. CARDCOPY now allows you to import/export 32KB or 128KB card +files into/from the port1 memory of an Emu48 state file. The program can handle +HP48SX/GX state and 32/128KB card files (file size 64/256KB) as source or +destination. On all other file types you'll get an error. It's recommended to +switch off the emulated HP48 before importing port1 data into a state file. So +you're sure that the HP48 wasn't busy and, when you switch on the emulated +calculator, the changed card will be detected. Remember: Don't import data when port1 is merged! This will corrupt memory. Second, when you import data, all files that are saved in port1 are purged. diff --git a/CP_48G3.BMP b/CP_48G3.BMP index b8278aac54db1aa2c93b969bf405a69b9f534993..56e6045a72e9d1ef6f9288d70bf359cb32312213 100644 GIT binary patch delta 663 zcmaKqF-yZx5P)BLIE6-|qeT$GJW zgiA$mbt+iuPY8jNB8+j@B}yqpZAr8ziBd{YZw+EI{0)pHoaCrzcOBx{kXqpgl|qFp zB{F4&!dUy*BCz5GR)ID!;gA~8Er9K_A<<|$8c{ufk~_MOWZB^4Ez4HNiDezhBu82 zc-&+-X{JZAh}Sz1=>M}@@QfD{Og&B;Ut7>luK%5KH=rGO3up%@rFLN0CTewvQYzft Ici?m83n5ptWB>pF delta 542 zcmdnCn0MP^-U(`a3@D({q}7D6)r4uQ33Hv{bX`4W?&+HhnU7C*P+}CH9&5y`IQ^^< zGdoB^aJq{=v*h$gMnG8sV`hu#e~nQjgiJu%On?%)rYI6lrp%kC?>A!>!75v129$L) zXAVZPW05&ftk42Q?2-jgY@sEJ7?TyIn2|M5jL`-~U6Kt@%+MA^Y?3WdEYS`{?2sK$ zY@$7i*e83S*g*#rF(pT!*hfbcu^=a)n4&X^Sd%kQEYJl-Y?BL6tkD%k?2#)_3>ZRO z(|5Zudm;sdkUR69>95?Gy^zIlg>#W7Faj2M0wbW;3ncFc_xUk Qn7-E=s$}~SZ{|;|0EC2^Jpcdz diff --git a/CP_48G3.KML b/CP_48G3.KML index 0363bd5..a4bbc31 100644 --- a/CP_48G3.KML +++ b/CP_48G3.KML @@ -12,7 +12,7 @@ Global Print "" Print "A few improvements by Sebastien Carlier, the author of Emu48." Print "Please visit the Emu48 Official Homepage :" - Print "http://www.geocities.com/CapeCanaveral/5948/index.html" + Print "http://www.epita.fr/~sebc/Emu48/index.html" Print "" Print "Thanks for using Emu48 !" Print "" @@ -23,7 +23,7 @@ Global Rom "ROM.48G" Patch "BEEP.EXT" Bitmap "cp_48g3.bmp" - Debug 1 + Debug 0 End Background @@ -536,7 +536,7 @@ End Button 110 Type 1 Size 23 22 - Offset 23 5 + Offset 12 5 NoHold OnUp MenuItem 1 @@ -545,7 +545,7 @@ End Button 111 Type 1 Size 23 22 - Offset 46 5 + Offset 35 5 NoHold OnUp MenuItem 2 @@ -554,7 +554,7 @@ End Button 112 Type 1 Size 23 22 - Offset 69 5 + Offset 59 5 NoHold OnUp MenuItem 3 @@ -563,7 +563,7 @@ End Button 113 Type 1 Size 23 22 - Offset 97 5 + Offset 86 5 NoHold OnUp MenuItem 6 @@ -572,7 +572,7 @@ End Button 114 Type 1 Size 23 22 - Offset 125 5 + Offset 114 5 NoHold OnUp MenuItem 8 @@ -581,7 +581,7 @@ End Button 115 Type 1 Size 23 22 - Offset 148 5 + Offset 137 5 NoHold OnUp MenuItem 7 @@ -590,7 +590,7 @@ End Button 116 Type 1 Size 23 22 - Offset 171 5 + Offset 160 5 NoHold OnUp MenuItem 17 @@ -599,25 +599,34 @@ End Button 117 Type 1 Size 23 22 - Offset 199 5 + Offset 188 5 NoHold OnUp - MenuItem 9 + MenuItem 22 End End Button 118 Type 1 Size 23 22 - Offset 222 5 + Offset 216 5 NoHold OnUp - MenuItem 10 + MenuItem 9 End End Button 119 Type 1 Size 23 22 - Offset 250 5 + Offset 239 5 + NoHold + OnUp + MenuItem 10 + End +End +Button 120 + Type 1 + Size 23 22 + Offset 267 5 NoHold OnUp MenuItem 11 diff --git a/CP_48S3.BMP b/CP_48S3.BMP index 2ffea41e539feaa60772b0c7ac46c5a793f445ab..2a2827dd55b4ba30a4dbad936f78bae211898e7c 100644 GIT binary patch delta 842 zcmZ{iO)LXJ6vt=#tgg@~2R)GBAS#hI+Ep#3RUgf6qfPH3dUQe}agq=bHz5))J&BKS zaM3i;BR4K2PA)D^TPK{vL3p!k616(X%)Xi5|37bb<~<&|E{2HP9inH*TlS2|;%z zh*rK_E2bwww^hL;Y~i^IZmd_K0auccvPr5HN{vosl+mmqk6#+q5>3O{p^IAjNJ9(W X>a?jpMf6Um6Nt#eqn^@S3f|;zFliZi delta 587 zcmdnCnD@>iUK1zZm_TL*5V!@TG=Q`|BLl+;CI$vZ1`e<|h!En2;Fm!5ONNam%b1(Z zSlZ247=f5+yBP~}jqY?^J!bCdn+%zcPihsP9&5y`IQ^^w`gt#4rtkHJD%pP2oB1Ov HFr@$hNQI#p diff --git a/CP_48S3.KML b/CP_48S3.KML index 43bbb9a..e914819 100644 --- a/CP_48S3.KML +++ b/CP_48S3.KML @@ -14,8 +14,8 @@ Global Model "S" Rom "ROM.48S" Patch "BEEP.EXT" - Debug 0 Bitmap "cp_48s3.bmp" + Debug 0 End Background @@ -528,7 +528,7 @@ End Button 110 Type 1 Size 23 22 - Offset 23 5 + Offset 12 5 NoHold OnUp MenuItem 1 @@ -537,7 +537,7 @@ End Button 111 Type 1 Size 23 22 - Offset 46 5 + Offset 35 5 NoHold OnUp MenuItem 2 @@ -546,7 +546,7 @@ End Button 112 Type 1 Size 23 22 - Offset 69 5 + Offset 59 5 NoHold OnUp MenuItem 3 @@ -555,7 +555,7 @@ End Button 113 Type 1 Size 23 22 - Offset 97 5 + Offset 86 5 NoHold OnUp MenuItem 6 @@ -564,7 +564,7 @@ End Button 114 Type 1 Size 23 22 - Offset 125 5 + Offset 114 5 NoHold OnUp MenuItem 8 @@ -573,7 +573,7 @@ End Button 115 Type 1 Size 23 22 - Offset 148 5 + Offset 137 5 NoHold OnUp MenuItem 7 @@ -582,7 +582,7 @@ End Button 116 Type 1 Size 23 22 - Offset 171 5 + Offset 160 5 NoHold OnUp MenuItem 17 @@ -591,25 +591,34 @@ End Button 117 Type 1 Size 23 22 - Offset 199 5 + Offset 188 5 NoHold OnUp - MenuItem 9 + MenuItem 22 End End Button 118 Type 1 Size 23 22 - Offset 222 5 + Offset 216 5 NoHold OnUp - MenuItem 10 + MenuItem 9 End End Button 119 Type 1 Size 23 22 - Offset 250 5 + Offset 239 5 + NoHold + OnUp + MenuItem 10 + End +End +Button 120 + Type 1 + Size 23 22 + Offset 267 5 NoHold OnUp MenuItem 11 diff --git a/DEBUGGER.TXT b/DEBUGGER.TXT index 5bf0e56..b7dee8a 100644 --- a/DEBUGGER.TXT +++ b/DEBUGGER.TXT @@ -3,7 +3,7 @@ Debugger in Emu48/Tools/Debugger... This is a short description of the internal assembly debugger of Emu48. The debugger is not perfect and/or complete. I provide it as it is. Please don't send me any suggestions or changes at the moment. If you have a better idea make it for yourself. Of course you're free to publish them or send me your changes. -The debugger was designed to help costumers inspecting assembler code objects, a part that cannot be handled satisfactorily by the JAZZ package. Thanks to Mika Heiskanen and all the others supporting this great program. +The debugger was designed to help customers inspecting assembler code objects, a part that cannot be handled satisfactorily by the JAZZ package. Thanks to Mika Heiskanen and all the others supporting this great program. After starting the debugger the emulation will stop at the current PC position. The emulation will continue after closing the debugger window. Please remember that the clock now shows the wrong time. @@ -14,6 +14,10 @@ After starting the debugger the emulation will stop at the current PC position. Continue calculator emulation under debugger control. The emulation will stop at a breakpoint. Please remember that the emulation speed is slower than without debugger control. +- Run to Cursor F6 + +Execute program until address at cursor position is reached. Code and memory breakpoints are still active and may stop execution before. + - Step Into F7 Execute one code instruction. @@ -62,29 +66,32 @@ So be careful using the F9 key. - Break F11 -Stop the emulation started with F5. +Stop the emulation at the current program counter position. 2.) Menu Breakpoints -- Set breakpoint F2 +- Set Breakpoint F2 Toggle a code breakpoint at the cursor position in the code window. -- Edit breakpoints... +- Edit Breakpoints... -You get a sorted list of the current code and memory breakpoints. With "Add" you can add a new, with "Delete" you can delete an existing breakpoint. Addresses greater than #FFFFF are cutted after the fifths nibble. When adding a new breakpoint, you must select if this is a "Code", "Memory Access", "Memory Read" or "Memory Write" breakpoint. +You get a sorted list of the current code and memory breakpoints. When the breakpoint is checked it's enabled otherwise it's disabled. With "Add" you can add a new or enable an existing breakpoint, with "Delete" you can delete the selected ones. Addresses greater than #FFFFF are cut after the fifths nibble. When adding a new breakpoint, you must select if this is a "Code", "RPL", "Memory Access", "Memory Read" or "Memory Write" breakpoint. - "Code" stop before opcode execution on this address + - "RPL" stop on the first opcode of the selected RPL address - "Memory Access" stop before reading or writing to the selected address - "Memory Read" stop before reading the selected address - "Memory Write" stop before writing to the selected address -- Clear all breakpoints +With a left mouse button double click on a breakpoint you can toggle the check box inside. + +- Clear All Breakpoints Clear all breakpoints except the NOP3 ones. -- NOP3 code breakpoints +- NOP3 Code Breakpoints What are NOP3 code breakpoints? As you know user programs are loaded somewhere in memory and can be moved after a garbage collection. So it's very difficult to break a user program at a hard set breakpoint with F2. To solve this problem the debugger will stop emulation at a NOP3 opcode. So you can easily add a NOP3 command into your sources to force a break condition. To enable this you have to check this item. @@ -120,25 +127,29 @@ CODE GOVLNG =GETPTRLOOP ENDCODE -- RPL breakpoints +- CODE Object Breakpoints -If this item is checked, the debugger stops program execution on every A=DAT0 A, D0=D0+ 5, PC=(A) sequence. This is the typical RPL exit sequence, so you're able to jump easily to the end of any RPL command. +If this item is checked, the debugger stops program execution at the first instruction of every DOCODE object which isn't located in ROM. For inspecting DOCODE objects in ROM use the static CODE breakpoints instead please. + +- RPL Breakpoints + +If this item is checked, the debugger stops program execution on every instruction called after a PC=(A) or PC=(C) opcode. This is normally the begin of a new RPL command. RPL breakpoints use a "-R" marker instead of the assembler "->" PC position marker. 3.) Menu Interrupts - Step Over Interrupts -If this item is checked, interrupt handler code will be skipped. This option is useful when you don't want to debug the interrupt handler. But be careful, when you disable the interrupts all code until interrupt enable belong to the interrupt handler code and could't executed in single step any more. Code and memory breakpoints are still active. +If this item is checked, interrupt handler code will be skipped. This option is useful when you don't want to debug the interrupt handler. But be careful, when you disable the interrupts all code until interrupt enable belong to the interrupt handler code and couldn't executed in single step any more. Code and memory breakpoints are still active. -You can also use this option if you want to quit the interrupt handler. Just check this option, press F7 for "Step Into", and uncheck the option again. The debugger stopped behind the RTI instruction. +You can also use this option if you want to quit the interrupt handler. Just check this option, press F7 for "Step Into" for stopping the debugger behind the RTI instruction, and uncheck this option again. 4.) Menu Info - Last Instructions... -This is a short viewer for the last 255 executed CPU addresses. The disassembled opcode maybe wrong, because only the CPU address of each command was saved and memory mapping may have changed meanwhile. +This is a short viewer for the last 255 executed CPU addresses. The disassembled opcode maybe wrong, because only the CPU address of each command was saved and memory mapping may have changed meanwhile. In the "Last Instructions" dialog you can copy selected lines to the clipboard or clear this list. 5.) Code window @@ -168,9 +179,9 @@ Set the PC to the cursor position. Be careful with this command, you change the 6.) Register window -Here you can see the actual contents of the CPU registers. The values are only updated after a single step execution. +Here you can see the actual contents of the CPU registers. The values are only updated at a program execution stop. All changed CPU registers are highlighted. -With the left mouse button you change the content of the register. On bit registers like CY and Mode the state changes immediately without any request. +With the left mouse button you change the content of the register. On bit registers, like CY and Mode, the state change immediately without any request. 7.) Memory window @@ -195,16 +206,20 @@ Sets the cursor to the actual position of the D0 register. - Go to D1 -Sets the cursor to the actual position of the D0 register. +Sets the cursor to the actual position of the D1 register. - Go to Stack Sets the cursor to the return address placed in the top level of the stack. +- Find... F + +Calls the "Find" dialog box, allowing you to search for a data sequence in hexadecimal or ASCII mode. The search area is restricted to the mapped CPU address area, so it isn't possible to access hidden memory. When you close the "Find" dialog box, you will loose all saved strings in the data combo box. + 8.) Stack window -The content of the hardware stack is viewed here. +The content of the hardware stack is viewed here. In "1:" is the current return address. A double click on an item shows the address content in the code window. 9.) MMU window @@ -215,17 +230,17 @@ This example LC(5) #C0000 128KB size CONFIG - LC(5) #98765 start address of modul + LC(5) #98765 start address of module CONFIG -will config a 128KB modul at address #80000 and not at the given address. So the MMU viewer will show you address #80000. +will config a 128KB module at address #80000 and not at the given address. So the MMU viewer will show you address #80000. 10.) Miscellaneous window -The Miscellaneous window show you the internal state of the interrupt flag, the 1ms keyboard handler and the contents of the Bank Switcher latch. The Bank Switcher item is only enabled on a HP48GX and a HP49G calculator. Only these versions have a latch inside. You see the loaded value of the address lines A6-A0. You have to ignore the last bit (A0), because it isn't wired to the six bit latch. +The Miscellaneous window show you the internal state of the interrupt flag, the 1ms keyboard handler and the contents of the Bank Switcher latch. The Bank Switcher item is only enabled on calculators with a latch inside. You see the loaded value of the address lines A6-A0. You have to ignore the last bit (A0), because it isn't wired to the six bit latch. You can change the values by pressing the left mouse button over the old content. -06/13/00 (c) by Christoph Gießelink, cgiess@swol.de +05/15/01 (c) by Christoph Gießelink, cgiess@swol.de diff --git a/EMU48.EXE b/EMU48.EXE index 7442e9515662f7feae4918f2e14fdb7dce7b1589..a15d4cf3447bd82ddb63b2623d0f8aa5f484215a 100644 GIT binary patch literal 233472 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 literal 233472 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 is the path to your ROM image. This will create a file named ROM.38G. This tool will also check its validity. +- HP39/40: +To upload the ROM of your HP39G/HP40G, you will need a special aplet called "ROM +UPLOAD", available at http://privat.swol.de/ChristophGiesselink/emu48.htm. Once +you've uploaded the ROM, you have to convert it using the Rom2emu utility. + +To do that, start a Command Prompt while running Windows, and type: + Rom2emu ROM.39G + +There's also a HP39G/HP40G beta ROM for emulators at +http://www.epita.fr/~avenar_j/hp/39.htm for download. + - HP48: If you have already used another HP48 emulator, you can convert the ROM using the Convert utility. @@ -68,17 +84,13 @@ still check the validity of the ROM. If you have never used an HP48 emulator, and don't have a ROM dump, you can either use Jean-Yves Avenard's ROMUPL.BIN or the ROMDump Wizard V1.x, which will -almost automatically get the ROM from your HP48. Don't use the ROMDump Wizard -versions V0.x any more please! After the download you may have to convert your -dump with the CONVERT utility into the Emu48 format. +almost automatically get the ROM from your HP48. After the download you may have +to convert your dump with the CONVERT utility into the Emu48 format. You can find the latest version of the ROM dump programs on: ROMUPL.BIN http://www.epita.fr/~avenar_j/hp/calcen.html ROMDump Wizard http://privat.swol.de/ChristophGiesselink/index.htm -Once you have your ROM dump(s), SAVE THEM TO A FLOPPY DISK! It will save you a -lot of trouble if you were lose them. - - HP49: There's no ROM download program available so far. But you can find a HP49G ROM for emulators in the YorkeM emulator package or in the HP49G SDK on @@ -89,8 +101,9 @@ http://www.hpcalc.org in the HP49 section. * HOW TO START * **************** -When Emu48 is installed and you have put the ROM image(s) in the Emu48 -directory, you can start Emu48. You'll see a "Choose Your KML Script" box. +When Emu48 is installed and you have put the ROM image(s), which must be in the +Emu48 ROM format, into the Emu48 directory, you can start Emu48. You'll see a +"Choose Your KML Script" box. KML Scripts in fact define the visual aspect of Emu48, the behavior of the buttons, of the keyboard, ... It's a GREAT way to customize your copy of Emu48. @@ -99,11 +112,10 @@ Check that the path in the "Emu48 Directory" text area is correct. Modify it if the directory in which you installed Emu48 is not the directory displayed. Click the refresh button ("V") after modifying it to update the list box. -Choose a KML script in the list box. If you have put a G/GX ROM dump in Emu48's -directory, choose a script for G/GX. If you have put a S/SX ROM dump in Emu48's -directory, choose a script for S/SX. +Choose a KML script in the list box for your calculator ROM you put into Emu48's +directory. -Several scripts are included in the common archive: +Several HP48 scripts are included in the Emu48 archive: * Emu48's Default Faceplate for HP48G/GX * Emu48's Default Faceplate for HP48S/SX These two are simple scripts, good for 800x600 display resolution. @@ -117,28 +129,33 @@ Several scripts are included in the common archive: This one has been designed for small resolutions such as 640x480. Note: some things in this script have to be fixed. - If you want other great scripts, visit Casey's Emu48 homepage: +If you want other great scripts, visit Casey's Emu48 homepage http://www.gulftel.com/~pattersc/emu48/ +or visit Eric Rechlin's great HP archive + http://www.hpcalc.org/ And if you are interested in writing new scripts, get the KML 2.0 documentation from Christoph's page at http://privat.swol.de/ChristophGiesselink/emu48.htm -Once you have selected a script, press OK to start the emulator. While it's -running, you can use the View/Change KML Script... command to change the visual -aspect of Emu48. +Once you have selected a script, press OK to start the emulator. In most cases, +when Emu48 crash after pressing the OK button, you forgot to convert the ROM +image into the emulator format. While it's running, you can use the View/Change +KML Script... command to change the visual aspect of Emu48. *************** * KML SCRIPTS * *************** -In some cases you have to fix Color 0 in your KML script file, because the -colors red and blue has been swapped in the "Lcd" section (bugfix in a previous -version). Don't use TRUELCD.KMI for emulating display contrast in your scripts. -It's not fully correct. The hardware contrast values are in the area from 0 to -31. But the ROMs bounds them to useful values. The HP48 S(X) ROM use only -display contrast values between 3 and 19 and the HP48 G(X) ROM values between 9 -and 24. +Don't use TRUELCD.KMI for emulating display contrast in your scripts. It's not +fully correct. The hardware contrast values are in the area from 0 to 31. But +the ROMs bounds them to useful values. The HP48 S(X) ROM use only display +contrast values between 3 and 19 and the HP48 G(X) ROM values between 9 and 24. + +Maybe you have to adjust the "Rom" filename in the "Global" section. This mostly +happen with the HP49G ROM name. Some KML files use the name ROM.E49, that's the +name of the emulator ROM file published by HP. But Emu48 state files for the +HP49G have the same file extension, so the use of ROM.49G is preferred now. **************** @@ -188,13 +205,16 @@ utility will allow you to create it. The syntax is: MkShared -For example, you can create a 4MB RAM card name SHARED.BIN (in Emu48's +For example, you can create a 2MB RAM card name SHARED.BIN (in Emu48's directory) with the following command: - MkShared SHARED.BIN 4096 + MkShared SHARED.BIN 2048 Valid sizes are 32, 128, 256, 512, 1024, 2048 and 4096 KB. If you use RAM cards greater than 128 KB in a HP48SX, you can only see the first 128 KB of the card. +Please remember, the firmware of all HP48GX versions has a bug when using a 4MB +RAM card. You always get the message "Warning: Invalid Card Data" at startup and +Port 33 is unaccessible. This is not a bug of the emulator! When you have created this file, run Emu48, and use the Close menu item to close the calculator state. Now select File/Settings. In the "Port 2" text area, type @@ -216,7 +236,7 @@ two calculators. This RAM card is used by both S/SX and G/GX types. The HP49G save the operation system a reprogramable memory, a so called flash memory. The flash memory is divided into two parts, into the Operating System and into a User Data area. The User Data area is viewed as Port 2 in the HP49G. -Emu48 saves the Port 2 data in the ROM file (normally ROM.E49). As default +Emu48 saves the Port 2 data in the ROM file (normally ROM.49G). As default setting the ROM file is writeable in the first instance of Emu48. When you open another instance of a HP49G emulation the Port 2 area is READ ONLY, that mean all changes in Port 2 are lost when you exit this instance. If you don't want to @@ -404,8 +424,8 @@ Other graphics and scripts are available at Casey's Emu48 Graphics Page: * LEGAL STUFF * *************** -Emu48 - An HP38/48/49 Emulator -Copyright (C) 2000 Sebastien Carlier & Christoph Gießelink +Emu48 - An HP38/39/40/48/49 Emulator +Copyright (C) 2001 Sebastien Carlier & Christoph Gießelink This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff --git a/Emu48asc/EMU48ASC.BIN b/Emu48asc/EMU48ASC.BIN new file mode 100644 index 0000000000000000000000000000000000000000..8f0837ac58c501a49ad0311a24db134536254c39 GIT binary patch literal 147 zcmeYW@CY!m&<&rfdts93rv8fzEOT`mB$#6zCa5OsXnkN{P*wE^u=;5)5S`LtxWG7h zuI_?}q+Fvm31%Iw0tN 1 3 2 ) + 1_#1-SUB$ ( take out the Kermit header at given position ) + PTR 30477 ( set settings based on header [unsupported] ) + ; + DROP ( garbage...we don't need this ) + KINVISLF ( translate, remove all CR's; we just need LF's ) + DROP ( drop empty string ) + palparse ( get object from string, returns true or false ) + ?SEMI ( if true skip to end of secondary... ) + 2DROP ( else drop two ) + ; + ZERO ( ...check if it's not a string [actually, anything] ) + :: + EDITDECOMP$ ( make into string ) + KVISLF ( translations, add a CR to each LF for Windows/DOS ) + $ "%%HP:" ( Kermit pre-header ) + PTR 303AC ( retrieve current settings [unsupported] ) + !append$ ( combine strings, use little memory ) + $ ";\\r\\n" ( semicolon, CR, LF ) + !append$SWAP ( combine strings, use little memory, swap ) + !append$ ( combine strings, use little memory ) + ; +; \ No newline at end of file diff --git a/Emu48asc/EMU48ASC.TXT b/Emu48asc/EMU48ASC.TXT new file mode 100644 index 0000000..94c12e5 --- /dev/null +++ b/Emu48asc/EMU48ASC.TXT @@ -0,0 +1,42 @@ +ASCII to Binary and Binary to ASCII Translator + +Emu48 can't import programs transferred via ASCII mode. This System +RPL program will take the string that Emu48 puts on the stack when the +program was originally transferred in ASCII mode and will convert it +to a binary. If the header exists the settings will set accordingly, +and if any comments exist it will remove them. If you are loading a +text file rather than a program, this will simply remove the carriage +returns so there is nothing but line feeds. If you give it a binary +program rather than a text file, it will convert it to a text file, +making it suitable for exporting from Emu48. Remember that Emu48 adds +a 13-byte HPHP48-W header to the beginning that must be removed when +exporting ASCII files. + +Simple directions: +1. Load emu48asc.bin into Emu48 with the Edit-Load Object... command +2. STO it in a variable +3. Load the file you want to translate +4. Run this program with the VAR menu softkey +5. STO the translated program in a variable (if wanted) or export it + with the Edit-Save Object... command + +This can also be used on a real HP48 if you prefer to transfer ASCII +files via Xmodem, which doesn't do translation. However, it will be +very slow. + +Unfortunately, this program sometimes fails on directories. I'm not +entirely sure why it doesn't work (since it properly imports some +directories) and don't have a solution at present. For these pesky +directories, you'll have to use your real HP48. + +The commented System RPL source code is in emu48asc.src. This uses +two unsupported entry points, PTR 30477 and PTR 303AC, but they appear +stable and have been tested to work in revisions D, E, M, P, and R. + +Program created by Eric Rechlin based on posts to +comp.sys.hp48 by John H Meyers . I would also like +to thank Christoph Giesselink for optimizing my program, saving about +20 bytes, as well as for correcting a major bug. The attached HP49G +version of this program is unsupported, use it on your own risk. + +Revision 1.4, see http://www.hpcalc.org for updates. \ No newline at end of file diff --git a/Emu48asc/EMU49ASC.BIN b/Emu48asc/EMU49ASC.BIN new file mode 100644 index 0000000000000000000000000000000000000000..ca7cdaeb7062bdc1b329f94e5228110f46277b9c GIT binary patch literal 147 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%0AnKU(>TA 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 JeEz3?{u>H5`h@@h literal 0 HcmV?d00001 diff --git a/MKE48.TXT b/MKE48.TXT new file mode 100644 index 0000000..ccb6313 --- /dev/null +++ b/MKE48.TXT @@ -0,0 +1,57 @@ +MKE48 - HP48 State File Template for Emu48 +12/08/00 (c) by Christoph Gießelink, cgiess@swol.de + + + ********* + * MKE48 * + ********* + +Emu48 can only generate a HP48SX with 32KB system or a HP48GX with 128KB system +RAM both with 128KB port1 RAM. It isn't for example possible to generate a HP48G +with 32KB system and no port1 RAM. Emulating a HP48G is only interesting for +test purpose, so this type isn't selectable in Emu48. MKE48 now create a Emu48 +state file with the given memory capabilities with one restriction. The state +file has no control on the port2 file, this is part of Emu48. So if you want to +emulate a HP48 with no port2 memory you have to disable port2 in Emu48. Refer to +Emu48.txt, especially to the COMMAND LINE section please. + +The syntax is: MKE48 + +where +- is the state file name to create +- is the calculator model (S for S(X), G for G(X)) +- is the size of system memory in KB +- is the size of port1 memory in KB + +There's no parameter check, so you have to know what you do. + +If you want to +- create a HP48G state file with the name HP48G.E48 then type + MKE48 HP48G.E48 G 32 0 +- start the emulator with the state file HP48G.E48 and no port2 RAM then type + EMU48 HP48G.E48 "" + +Of course I never start Emu48 from the command line, I usually add the command +line arguments to a Windows link. After starting the emulator you're asked for a +KML script that should be used with the state file. + + + *************** + * LEGAL STUFF * + *************** + +MKE48 - HP48 State File Template for Emu48 +Copyright (C) 2000 Christoph Gießelink + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the license with this program in the file +"COPYING". If not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. diff --git a/MkShared.exe b/MkShared.exe index f022dcf92000ce2904ecea93dd56da76bab355ec..57a9cf5cb9b878033e903d5af72433f9cd0b89a4 100644 GIT binary patch literal 28672 zcmeHv4_H*!weK0`00$VDQ6Z8RXN>9x%vhZs^Vj5>1OZ|yUq zm_NP!-n;Mn-o2m0w`cFY_S$Q&z4qU=)*i|}yNk1O9LFOV2FLA1OdmJ<{`+4CP@Hl7 z&oj6eQhqaMuVwXb=B#UI>~OZVx8C1g^MG@6O-oCw==@xrvt4R&Hnup6@2PM;&{|u! zFg-mrCr0|N$=Cjn^yJTb>q-I8WWGCPxJLSLGW*n!}syxUA8PyMG)Jmvz(5FS1x zAC_Txe8u3gh?VxNOc9*%W=>B9g+*hx@{uLAG{M^#E?4{BZ_~V9Jgs*P30#rD z6$xCCz!eExk-!xR{1=dbTAaiCV+N~*rjOmm>G zmllxLE#6kZK{pk13P?2-r!{zqkN1Eq@8|RTtHZGxz|pUYrBO{!jitenTEaJR_)DPg z2Gn$WjVy=P&B+mC_b6DBveh+wdBakoybDcV>R|&l+T=E}Y(U?A61aWT2la4i@aS$z ziHp=F0?PWROid?hXk!c!tLiN`e*d8w(rXMCEbypjRw*~K)*;i7M;v4@4p`rIUHnv3 z`d%7Fsoy96+R%#8D?`l5RyA#2B03oH`I{^N+^D6X@ACd^*N~KBq@P5EZH_*wH^`+L ziImV&eNCy_Z$O}`D*uG9QVUX24OeZf-f(Xi&G^;MoJ_f3b)B2D?6BMSBsU3O?E|z@ zRi#r_O?Pj0bG>|_JS+tJMe7RvsD00EE9A+W)l*`kJee!;l+QmAr(tX2ecE#-fwVre za+^HNqjGwP|8D5MlEYL%e^tJ4vl^BXCXO>!&>dcDHVmUGToLcPwhFRQBcbA)Y%lfS zrwK6QfaT-bOH69nYItMyz2QoAw8?0AjzoIjr`=p_9|oQC)++NUmPZ{GKEG0@8CluD z$UoZqnv%7t5o2*+=i4xKaZ37q$PK(LSYJ`n*Hcn+>|TesiPO@qf*^wZlF&3u`wnoc zO|5o3^RT`9G=%Yt+aA;@ zwuo2B^*r~C!`^)Yd3BADGpS@KKrXRSfm~R5G;PNRxJ_KJ8~nTQj3zIuE|~*G?X>`4u{`cq5Tx>vvIZQ`SN)~yh;tL zzaEGr%5Pt<^1)3HxVaF2Ku_E|hQ&7S=AB|XZBiB5pV1cTfpTw|&?D%XO_q>H*hnO6 zFOpo=W!oqw$!ly*-L86s`84{vU~__h`G8Ss2CUl;26Ym>lPq7n=D=Z!%_qc1Q{SLJ&sxJV$KKo0YSDQ15Jpc$*;z9$gmt?O3m%;vr zh);0G1y9(6UhEU9$APtfFia9rJyEnWl*<~m>F*p;SLg5(17xukGkYzC-Tk85%u2Mi zp|h5s8BY&Sfz(31bEIUO_EsO$pQTItP=UFT+PMm=VdvAjNn^2)aRC5Qy zp~A_FsS6iV(O9Z4fGxq-1eU9%PfD_u4Hv^Hxqg^(AFbbI1JI~UIywzsz z{q~>oh5B0cfKOdQEe@O&?0b%k7yB%MYB3{FH_7#sMSDCKniBMsK-~qd#}maW50#}h zS?B;R_l7)CZ<9sajW*={v%pTm!La?Op453B+rjW5^MfTWKz@$21NgQ{DRdv1czd6N ztC)COJx-+)wKYnv2hKY?X9Uh~dnm*HQn)wpIJQT5*sdq!_uF6U9()nmfe0^0 zk`>Qk``{Y|Kz94=I($mC9kI@}yE3RVv>c*#-;{qC1dF)~w>qvL=Yv zmzIjtk+TP@P%M{4g%Pir;73-N3CqYGNCe8FfsrL9Bw^$xf}H=fG%w_Fc(uPFhjpcR zhV7y0CJH}s9N7^bIThfSejVZiq2j{B`iN3FHu4@OI90!nRo@e@K4uRcLkaOe@(L0m zUZI+(rg+9i_OePV#f5?M4Wct}zFC|eIKR~%e2U;@7le^-vbs^n$XCpSb0kPbcit*x z1|G63mNHhX0A2ucA8AH`QhC^%JP?k3Pk6kz&=L@@4tYks*h?TNul5kIdauV;vI2Fc z7SvM%`)woh5tB$G_uC(xg;ACxb@tFdVKvH;_4Y?;o40pwBe+&%?|u?lNV^T8S=Ma! z;0V@!{e&l)CrCVXK$XViNkd9}2|LF_OfrvyK4Cb7D)oR;7O{6vV$uf>V)CWeVuJ=~ z$nz#ZoI0TXeogSGz56xf>gAxC$X7sIvIWlHFJU7dqo%L{8`2@UUr;D9 zrj|yOvc0N1s(4&TRYZMy zaC{2*X$EFuy;(}fKw3h-{22rV3H!B~=dd@9M8S)!HQKvL$g-Ab?|uRah^d<*v78oQ z_XX4`1?*oL4p!tr)Ee@<_9^7`<+%e#A|o#VVvauRb6F%d?4l4@%86FD{z2}*$fK;< zn1E`ios4MQ6AeK2I6ygZL$BwxLC?E+eEE>)B&3JEP}fUi7*t1ep$iH65;iW^Vgym< ztP)e|)w0ogMbHxwD?)74N9NIZU|NBEDr@ONK*UnPrtlt0s`NstEzZHWn@uH~c7Wja zm;1l1&(~gL>7VxNf4ztxX#c`04r@TbE0F~#Bup3r;bg$L6TO_ z>AX6op2K_z;0Sq#qao``iH*L_<0?F%4yFxBNS(w~`zhv$>KQZ2#&B9EQHkhMJ!ihX z*6a5vo_?irzxFE}|Aw?*JuZjy45{Dm(~9UqaDExJv%_lL@S5t07-f;3Z2c!7n2U@j zg7y?7=gTk-8x|9(Id2j1O7FBn-vPdggf8 zOy=q-WfV1 zco@rPJj_q2k*EC``n zAk5&}akI8MbPxJ=SkH>FVn}BUDWd({EX82);#4lb5UbT?GfzI8dBGWH>1H&_ZblW? zxVZ&aySZY7T?j)6uOje(e-i-*s9I(-R`T02)M>pQp(nwx*!MsaAjY(BpTX*)ix}3q zlqd_vhOohH2s4Gz!8qM92Y2^uA8BR?nc9!Aw_@*-?=Zw$bisQ1Ba5MJf; z2m5#20Bv&?YB}sLCHYHGYnE4&V%6@XYT;FwJbxmkj;;VQ$EzH+lvqZ9mQ)x~%j0CPp$gWaif^oPZa}%^c0bkm0A)W@FvK(b!Hl-D&O9>jbX}AH=R!aagqt+@l27rjC4|!PUUh?$n93%mK8+@;sv2%2Kn?+L-3K6e;$F!?O)HEIBa76x zji&zQ0;?VA7wHc2`g^86M1!^jQxto>z1xX|x?aF#xjT!d?fFE>CT|kZ)%7Fk3}CT$ zkE1a){W0*bl;MhGQ&<|ugp500@Bk|v#sQ#aoy52Gh|l#(S5|28%G@KN#Xo5Sh;+0; z+uhOxMrp|?00lTE`X$>?B4uO{(Ax@jO#$sB(1wDqP65$2t>0bn^(mkrfo>}ZO#wYj zpqzq7r+~ghplJnPBM{6#)FQnDF&HCFf^n=$Vacj$U7)U)1A_bQZt5>ICOyTFY)00N zkSug3bzKgxrfZmVn{<0voW8t3w5;%HHK(zzLSm9d*FyX+Y0i1If)pT+ zRk=R_`#|?Y zO`8VeM3p?qS6MGCy z1>6Q6IKB!a>n6ylkE|U~RRC8fmu8F54MVsa&;`Gu!mpKq8uo9sEE?i_yjlZJJavq$ zQ>Vcp<|c6%$A`ui;=kne;S^`J=xR`^FeAyv>fK}|fojJ#sBG1fS>coCV7GRVZac)d z#y|!QQBZD^hj?5d154*h#l2pOJ8*8UxS;!}IN!eK==j5h&DiZkn_&r#i%GqXo~ugS zEd4u{)_=<~eBcJIgb0+l^&$pIWW~J>w|&nW=I0yBy0XRez&6X=kk=yd>OS47bO{g!X*AjP$Mz|e*++Es*s9=BF{6kW z8BDsb#IUTAPWL*%=iPEwHYcSLD|dnw@pidO;KYSMyn0F(lT7)TvVraIq5!RsnqhH| ztjA8xdI^CUmXVp1HAJiYDGYli_G~&I%FFv6Z*p@LmFmrIOc|d)|3v`Nr?m zG1qAky8~fRZ}l6EtmVK`Bd+uI?sow(%My?p!CJ>%-(nB$L;`cjX4bcN??b+R*>&om znBjKUFUywBn$cf#2i1b5Aa^8EQQ@wr@cJq$l;WJl#_Ou)(#1uU+V61HrX^FH;}GXn zR8*2xF$Y-2>o|8aka1|=#7(YBxi80oE#BcXvKAA2VZB0*BuJ}W=V{A`b1W`jdc8U% zrn;AAOXulpJa@>gYL!|GnqkWshP81$trGW~?_#myu<;vNc|>rKG)=O5lI3o+nC!3( zBoQs&tcpvp&~&YqFp4FkEFsI$P~s*mSSPw3`VwKf#yYMEkSQy}7%WLl?IRp{P)MXQ z{ZBBNI&ffl(N;Z9th+E9e}$?zQ;UQB_U@liIxp0~?S4_fbYurMp?Sd=bSI{&cIW{+2Uz1Lu_R4OoxjkNR7Nu& z^JYhhY9))rt-WR3_<%)RI6fdqY2b1-xWp-WojRnx`eAFCnx?=g#`To)D?Df!7iR0Jy%l&@?;ZhQHL^cd@CIlaA#>OmX z${jSINr5%ITerjUfyJ?g7jz!qfg<_5we!0MW8BCp1`!%5d4DnNmQCC;7$cam-~L!X z+E~w+-(3ociCJ1Lc3Dg%yRn1-Miz%s91S>i!-ue&!BSDlyb_%YP>S<9GN0o%VCATP z#t}p|t3uN1Ip%N??PT}B!Q@a9_CiNrUeMZim1iU3z{3Xjdjlpdbsvc%sVzi>FSl= zU#q55e&=?c8j>7pxlLVbTUIVeiHx^!MfoqHIR5n1SVAomlvRRK#4De-Ro%Of=MEk6 z6)nnJUzC@Je#@f*bv>$Xuwmn#aI;R@gLJ4frNN=#IPgT2qNv(oQ@&GetzXRFwj5X$+Ox0~!Y_nUUxoHZmJv{`$)XlNDrhy>pH%)) zrO1Z50xF`m;W;6gDhjKx`7&HI*E(zitSbqQ4h$&*AJXcRBa*Ji+hU)czM`u z(gvXvpY~PatUBz|=9&D!eFnpQ7|sv3XeYPK_26mZcvbba{merG4+rl0`6vA3>~Xdf^yP~@qq*}!>i4R6-fzckrEdp*7-cEsD^P<9E$676{gI5{*DgyfI0?=!Dby= z&V+_ZuiD3pZ{aPX&#RTv3`1k2Pn0&gIUJ#!eh)@3n`v;fF#K&830M=(V=pzbnvtP% z6`ZGdwFQ_(Rk~A64%FuH7ed8(JdW{9dH!lp!f6^Oh#?@(*qY4bu_nue3RgOvgFe4q z-cGA@0IQK%)VeQV2s8H;Sn0uU=OJ3241&w}87vet=l7~sV{x9jLLiYMm?JEnh-;`b4R`Nc zkIm(AwD;yiy9dl3RKdcsEGGN03%ulF)9F*hl~frikHC(uYE2XZ$b|!0=}? zE;RzuXV4?;>H5E1LVlc1y6=$XLoZOR;}D!%#5sUV`!)9N-(cf0+oDyf6i{RORk@zA zPaG?(cIKXBhp?7F4iY*#gZ)aOAg0SJZNgAtHhHx4X~^)Q!b}tZMDtxO6yzGL0!!TS z5c5A^`2EbESmsc1u^v#5SO;B`TLf3c{_r-8=EM+fD^ljbNP_$)E7arm1*gAnV(4#B(DAc~ zF>53)34=Pk385JwfPmA!dgH(ga zr@tRXyTkct#hCa5q`V7B(29@8S#vycX*@LW0t`al6+t>12{%G-iFMwQo)y+LAbbx= zZqF35#8<5R(iojekl$z0e`E^gt|@rn9=(f=)hVm|K8>jT;m=|lm{J3@A4B_(BRq}p zBZLT9f)m+ZHNWL0%9I9fBCqW@)-lY2!gN} za{wVOU+|6IPZdN+D)#GGp&#>V38dA2AC88}j30+}vv$7!?T8>pA_gizK+MlLlm#x!O zcuC*%SNOEK$m4j@(@00bqZ3ls;dC&ds4u_+6rV{S7ScFXki@Q^=|u_7Tyh>h7x1!nf+CK zIbvV|u_Dec2{jmoUcJqOREB-*@@4teJd3g6#0*5S zw-MV7Jw3F2QWrwoFX-0Lc6tn9i_yQjcUmEAP_;cXSHzk)r6(#gVI^R1FjPzI6^1(P z;yaADfxozWT>R9;KGxE7idj=b%1jdI#&Erv7+jG6!+0#SG29a?#VVFZX|2-LqX!2# znPZkXK95BK|8sW}AXvSp?cF{~9o>5XO3AW3v0d)ZyQ_eng zYiMhxS{d#AT0ankT|~z18rt%=!ot8ZPI?VjMma3VT~WS$0NeUd;!Wr?IOn{(srT9- zF}CLr>b~qm{`=pr+D*KFU#|p#?FO{XQXEv+3rr3LcL6D`?H~BGM-ZFHmx$^~%4}*N zzn@Y2;SYbPr!SlR3>K}Jp?w7vw12}Fwri_-%|2*4a^@2Tq&g`%h7u`F3>x!$n5ZvY z4(w*YsAOkb-X(NK>E@?#^AhLE8ZXY2wRF)|Dv~O;m*-(E**l$m^8%%(QQF_+t^%tx zei*eF(@ZYAsTWKV=)=aCHh^^nN1P9D_egY8rovS;Y5HFxwtKo0M{$F7y9V3O^m_g} z7^IvNZ-{QgYq`qP_C2ZasJRBV&dxm$dXb?P?sej${sA|H(?3*y4Yls{5AM3F_b#Iw zuD^}H%!uJj=5qh~bt!NJFH;L$cqeHV*;W+m-b?7|EOcjFJ^G;nNV zCE{8J@Z|mXVfPMEllAJf@qKtYXAZri_p!uLG}5!njo$0C#`h(N4ztKfMWC(!d*CT5 zkVlVvxD zcqlP~iRM7%_2E7$2-yOCR3T*RffI*L20qto+j)+D6Wg9F_h;%FrV`sou;6T@7y8sf zhx*stFWA)2M&*4`|G+7``djtEXyZX1LS2RDcA-Zs#o$cYa7Mw4BO7#M3tm%54-K5< zo9QGssv>K54UZR+Y7yleFgK`O*SKJBIP%bNf*PNJ)gWod-oh?VQ0YEXgA&ST{tJ?E;ul&kq>*pv@r+NSC8osTFTWIbD`qric_-n1q{g%x@VY`m{?Uj^6}B>W_+hCRUuT* zm~xGB-;AgMXDOx)*GJQi%|MVCAez zOgJfCfn{Sg-46Nb9vWhkuIhG7mKK=^rH;V%BFIGE#7{DaybUiDnsHG!+HA(_3}m!9 zF0Bu`5U@$FX0a*H2L^@{)B_9=8`J7(qvfH}%yO@`j&A540T)6eofe5Jk@~d7Dr=c) zI#tC558pbe47;gFSwh{6U-;zF%qh)O_(FUDZ-yTRGOdl$ney9XSQnUTD>3D}GUVSH z$4<#*5d)9*bO$CmPKo^SV;a5T^F;cnCH1)LEoFnyakaXNS6%bUBJ(EGUX{}1aHeZR z6b0??AeOePZ@7*VTGnM~i9pl;;yNx>0jXn}{6zt-RltC$zen|Mh}TPJWeoom@H4cf zSkUV6;0d6Lnb2I2tx{Jx6pLEqke3?F%wq>ona#K?a;OgZ99{-S#Z2{)T{LWJ=dR*7 zzqhF-sI7QjWn`XohF+0}N{iEeuS#d6nd(=&fsd0Lg}4H#lk=9Py)KU6lviKLH_Xi? zzOj^@QCEZRZ>98DGfhr3vN3qDGx5mVEA$B!22`fn?R^@DL-*c*)TfqzMf(QVbU&Ps^e|I=$thDmZ|H4;f5Yz zGj!tEoU148s3xVwkXP}TBB+N2{2(uPML61(u(BT%up!yINsl2;J3rtSZr&4aiwnNXCl~iT*v?y4{#wLwfkA&7(2(&1Q@li8^2SeK}${o@* zuGuu@rRkvMV#`-bj-54tC_?Bio-G7(38d3`1LLaU8j$ir#fle84p#|UMEk793oU#7b;X zA-6a#HbRRZSFoA#8o|I*{2jcJNK0ESalm<}4w^b|IXmC{>K7a^k>#HV_G3N`!wId1 zo9=Avr{nFjq3%3(w!vuW78ExRf5qJp&-o^P;2pblyN%i78fcS?@dDjXz=|HB3vcL~ zTpP!^&TU;DTH%mOBZk~FYR9Ax^+XX3xuau6s(fY-CJ#{Sxiq`DgM}0 z)so_>+EsX9Vm_JwBUF={psHOLQ`KyyswNF8GxhA9f1-aTgH#4mXbLGl|0tuG-@j5! z&F@!|p$D#%B4Ahw#(C^}(G;4UJT=B)@;~!ro**v^UWJ(sgpLB}*oVn|@TcozK9}+0 zBk&x|_p;wq!BLd;I7W|V;bp#o>CB*g$-a##%6zY2ES;>+d;6jPxdhRP34T|>jevB1 zAfKJlK3hJUvo+hShl?{8R{7uU2kLHeC4_gLeG#zs={wK9g4o0oklKQ$NrZ3}s{ys! zXL=X>9hFlY3(GG$7Lu8pz#`s;QwC3dV_wDU^ZRoTh>n$_uu_`gZ91b1-lo6lR&Ucd z-qzA|O_ptW2IkQxI5?)tZPtf8RpanfSwj4PXjM7foj>XyfhB<%GRVk&R9unY-wO@g zub!39@$ENH`~ez_DC8cY2_>CV4-5-QiNM#Vt0nj?ftcpi z{(K4!mik#ZpNHgn8x|D!EoVO;48eEXp1E^`c95ItD`;Wxj?vr$>i(cbeH#x7-Mly4 zl%Rd{6=)bS>t7p|^~YNOW|`JM_F_pbHsR=V z{r(Em1crJs9X2&H9UP$_C}J(Z)=q1|7rNWPvn)IhhhOf4l`wvvMy6Uy%%!=l?z?1ygBtmNTo~8A%tO~{r}v*PMyAmm-^ zk=};z6hhoD^b!9OVM6xt^1tI>Vl=1V{m1^L80|A?KZ?MkDH}p2!YqUwgxe4>F8>Ms zC2CAHy!c*^(16fMkodU#U-_3}zfN`)kUQQke+lazZ^R}(>Wn9!vPEq4Ygw?4F_+JB z*|6X^F%qP!u(?l0$fk*(PyY>xD%Y>7#94lAgwnVqtYdq!lxkiQR1NNo_xxHpN>ytW zJs#kK?};gu+VKhC>sggK2GNy=~$=jK@k6{YJKg z$023RuSLuMe|*M$9M@8b{~w3&C4|QiovVF3HZF94p)D*}D64I4XVxVf((;C_%qRzU}6P2!Rg9K6TlNuufxyD1hE4czTwB{Vd<0-{$($e{67WY^{4c*2PU4#Jw}7f}H?~O4%}C;38H$Y$ z)H&Y4z+b#8aGeDjmfBPTU*^`v96X$ z=8_aK4{y!8g~>-ki!q!Bq-L>EY-q2msfC0#fBwVxpDdSHCHnt|U^hLr=5sBr?GHcz z@&9Kj*0n#-*mAj?^H_gAc6{nuAi>s_2kKfx&;ze|tUn)%Tho5OM2H=6`Q|MmIn_6} zqPdp)oo%g+Eh3u+fYjF2n({1b+}z&U(ONG$eT^M7R7JVD&b6@#y1Mam?KSP&Y3`AW3Nm|M7TA-6o<%a$6} zUDF{JVp?pe^R~80Z5+YOyuY!fwsk94R@c!{bAR1kt=kGYsiUqvf6>C)=4NyKX5WqT z2!UuGLVOtExpncDIPQDcKgoJtyo4S?R9nB zTM7R5MzOA>5%2>hys#Nlmg5$4MVP;4Q6aa=vv!SVbzFY0kfe)RA9w%+S2woQ6>@mw zP$&B8+B>jDIj)QIVAWxCH)8;}Clc1hCT(3D#7!^?QhPh*TO9a56DnI87>l)@ZJX=b zXuX3m%y^E=A^K&lwNf+Vbq(f6A;J7#J}A@}?zl=!)$3I4{~x}t`f z_I0ggv`+8ZF4l2LME|3NIN{^rI2RsBsHhW7i59hDx?^?|ZiQGI6El}Zd6Mk9?QM0O z*DS5Ue%7|KrM|V0`yZB4?6Spm9b$XycJ8|@XUd%8UQY0tJ0BaRCs`Rwa-T_9D>hfQ zY{d-czRlp~fL%lMX+^Nb1q&7NN3DBl*^&%TS}yi?U29wjT!qOO$&L7gRDG92(ASsQ zXnBck?q`%PEW*)t3*p`4DWmi+;{3*D&-WN-YwOJH9fV24Tv%J%PE&&0hq+dRxx=;x zwD|+Bq*>}{Ab#(X>gzF)a5_^DrpWVU%j%-Cnl^KcQKx@u9$a4eT#>*P30#rD6$xCC zz!eGnSCzo3nQrc}&Ic{&&8ExQ#IDoJa&JvC*1 zhjTg6C3WNu=W?R7v9V?2=RbExDi?K{kAaA{01QO&n10@N@#DCdx|kq~`&5*R1+fH` zQ@HZEB7uKY0(WnAa};1)`pDmnup*g%A1(VRq!f0nzxUV8ee~~g{GHsTKMVJd{Y|Ct zFn8%M0W0Aj`HRZ;WR_-)L{7IR3e@9KSh1fDf}jEe4#8G#^X<)0A`wX(0yx z%9Qk@Q_{Ppq`x{P{k19SuTM$S;{jMcIog{aK_Ht8WoUbJCVm}1w7dL6``=>~cwmgU z0dWfA<%p?%He#wby4KB2L;ND*>4?9Dcn0ET#My`!BPPN&#MdBx4gJ3s@#Bc;w_YOR zZHQ|TlYwd-;s+5IBaR|=Bc?|Kc@&p^d_Xb#SQ6-&FULKNj&6E*`@?fgF!#@InTfvd zoAJ&khlw=j-VtE&Gr%9%{l;#mS^SZ2{69$camV7H{Db&~G5kHifAxDOzjqDy=kICX zyZ4jn@91MS$}vI8->81W$!&b2>5WAn#XolZkHcr7`R_0}i-10TXs%s_5I?&JOlg{5 zG!`Js(VGR>%Gp@bT(BXK&?u(yrI^N-%4m+p%ZM)3rPz)@bR7r;qw%M)r$BI$JHeO4 z@`bT{Q7rF8Om)`A;1#i$j0Z%&3W3^gMj$#5AUF})5NOV{BM`6D55f;15YIbf@xzFz zTt=YsZUmz9RfGiyPsH+lh>72)5vaX?K_I-JA`pMSMWFK65vV*HLLvEF`CO5}6$xCC Oz!eExk-&c^3H)zrPpwV> literal 21504 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 diff --git a/PROBLEMS.TXT b/PROBLEMS.TXT index c871be1..74faa52 100644 --- a/PROBLEMS.TXT +++ b/PROBLEMS.TXT @@ -1,10 +1,12 @@ -Known bugs and restrictions of Emu48 V1.20 +Known bugs and restrictions of Emu48 V1.25 ------------------------------------------ - the following I/O bits aren't emulated (incomplete) DTEST (0x102) [VDIG LID TRIM] DSPCTL (0x103) [LRT LRTD LRTC BIN] + LPD (0x108) [LB2 LB1 LB0 VLBI] LPE (0x109) [ELBI EVLBI GRST RST] + CMODE (0x10A) Mode register IOC (0x110) [ERBZ] RCS (0x111) [RX RER RBZ] TCS (0x112) [BRK TBZ TBF] @@ -30,16 +32,19 @@ Known bugs and restrictions of Emu48 V1.20 -> all programs that run on a real calculator will run as well, programs with incorrect DA19 / BEN handling may run on the emulator but will crash on a real calculator +- incomplete reset logic of the bank switcher FF, on real + calculators a reset happen after about 4s in deep sleep, in the + emulator this happens immediately - no MP interrupt on card control circuit or timer restart - 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, Windows 9x: plays only default sound event or standard system beep - no infrared printer support -- problem with timer2 (8192Hz) emulation in Windows 2000, timer2 - values may skip, so an emulated delay loop may take very very long - memory window of debugger view some addresses in I/O register area with invalid data +- the 'Offset' command in the 'Background' section of KML scripts + don't work, the offset is always zero - Shell OS: clock isn't synchronized with real time - HP49G: the flash memory is emulated now with some restrictions - first implementation, at the moment the flash memory is more a @@ -52,4 +57,4 @@ Known bugs and restrictions of Emu48 V1.20 - quitting the emulator while programming the flash isn't allowed, because the content of flash state machine isn't saved so far -07/10/00 (c) by Christoph Gießelink, cgiess@swol.de +05/15/01 (c) by Christoph Gießelink, cgiess@swol.de diff --git a/TRUELCD.KMI b/TRUELCD.KMI index 4470e97..cda708d 100644 --- a/TRUELCD.KMI +++ b/TRUELCD.KMI @@ -1,31 +1,31 @@ -Color 0 130 173 161 -Color 1 128 166 159 -Color 2 124 160 154 -Color 3 119 155 148 -Color 4 115 149 143 -Color 5 110 143 137 -Color 6 106 137 132 -Color 8 102 132 126 -Color 9 98 126 121 -Color 10 93 120 115 -Color 11 89 114 110 -Color 12 83 109 104 -Color 13 79 103 99 -Color 14 74 97 93 -Color 15 70 91 88 -Color 16 65 86 82 -Color 17 61 80 77 -Color 18 57 74 71 -Color 19 53 68 66 -Color 20 48 63 60 -Color 21 44 57 55 -Color 22 39 51 49 -Color 23 35 46 44 -Color 24 31 41 38 -Color 25 27 35 33 -Color 26 22 29 27 -Color 27 18 23 22 -Color 28 13 18 16 -Color 29 9 12 11 -Color 30 4 6 5 +Color 0 161 173 130 +Color 1 159 166 128 +Color 2 154 160 124 +Color 3 148 155 119 +Color 4 143 149 115 +Color 5 137 143 110 +Color 6 132 137 106 +Color 8 126 132 102 +Color 9 121 126 98 +Color 10 115 120 93 +Color 11 110 114 89 +Color 12 104 109 83 +Color 13 99 103 79 +Color 14 93 97 74 +Color 15 88 91 70 +Color 16 82 86 65 +Color 17 77 80 61 +Color 18 71 74 57 +Color 19 66 68 53 +Color 20 60 63 48 +Color 21 55 57 44 +Color 22 49 51 39 +Color 23 44 46 35 +Color 24 38 41 31 +Color 25 33 35 27 +Color 26 27 29 22 +Color 27 22 23 18 +Color 28 13 16 18 +Color 29 9 11 12 +Color 30 4 5 6 Color 31 0 0 0 diff --git a/sources/Cardcopy/CARDCOPY.C b/sources/Cardcopy/CARDCOPY.C index 2c1e16e..4d01877 100644 --- a/sources/Cardcopy/CARDCOPY.C +++ b/sources/Cardcopy/CARDCOPY.C @@ -22,17 +22,18 @@ #include #include #include +#include "types.h" -#define VERSION "1.0" +#define VERSION "2.0" #define FT_ERR 0 // illegal format #define FT_NEW 1 // empty file #define FT_SXGX 2 // Emu48 HP48SX/GX state file -#define FT_PORT 3 // 128KB port file -#define PORT1SIZE (128*1024*2) // file size of 128KB file +#define _KB(n) (n*1024*2) // KB in state file #define HP48SIG "Emu48 Document\xFE" // HP48 state file signature + UINT CheckType(char *lpszFileName) { BYTE pbyFileSignature[16]; @@ -47,8 +48,8 @@ UINT CheckType(char *lpszFileName) // check filesize FileSizeLow = GetFileSize(hFile,&FileSizeHigh); - if (FileSizeHigh == 0 && FileSizeLow == PORT1SIZE) - nType = FT_PORT; + if (FileSizeHigh == 0 && (FileSizeLow == _KB(32) || FileSizeLow == _KB(128))) + nType = FileSizeLow; // return card size // Read and Compare signature ReadFile(hFile,pbyFileSignature,sizeof(pbyFileSignature),&FileSizeLow,NULL); @@ -59,14 +60,50 @@ UINT CheckType(char *lpszFileName) return nType; } -BOOL CopyData(HANDLE hFileSource,HANDLE hFileDest) +BOOL SeekData(HANDLE hFile,UINT *nPortSize) +{ + BYTE byBuffer[16]; + CHIPSET Chipset; + UINT i; + DWORD lBytes; + + SetFilePointer(hFile,0,NULL,FILE_BEGIN); + + // read and check signature + ReadFile(hFile,byBuffer,sizeof(byBuffer),&lBytes,NULL); + if (lBytes != sizeof(HP48SIG) || strcmp(byBuffer,HP48SIG) != 0) return TRUE; + + // read KML file length + ReadFile(hFile,&i,sizeof(i),&lBytes,NULL); + if (lBytes != sizeof(i)) return TRUE; + + // skip KML file name + SetFilePointer(hFile,i,NULL,FILE_CURRENT); + + // read CHIPSET structure length + ReadFile(hFile,&i,sizeof(i),&lBytes,NULL); + if (lBytes != sizeof(i)) return TRUE; + + // read CHIPSET structure + ReadFile(hFile,&Chipset,sizeof(Chipset),&lBytes,NULL); + if (lBytes != sizeof(Chipset)) return TRUE; + + // skip port0 + SetFilePointer(hFile,_KB(Chipset.Port0Size),NULL,FILE_CURRENT); + + *nPortSize = _KB(Chipset.Port1Size); // expected filesize + + return FALSE; +} + +BOOL CopyData(HANDLE hFileSource,HANDLE hFileDest,UINT nSize) { BYTE byBuffer[16]; INT i; DWORD lBytes; - assert(PORT1SIZE % sizeof(byBuffer) == 0); - for (i = PORT1SIZE / sizeof(byBuffer); i > 0; --i) + assert(nSize % sizeof(byBuffer) == 0); + for (i = nSize / sizeof(byBuffer); i > 0; --i) { ReadFile(hFileSource,byBuffer,sizeof(byBuffer),&lBytes,NULL); if (lBytes != sizeof(byBuffer)) return TRUE; @@ -74,7 +111,6 @@ BOOL CopyData(HANDLE hFileSource,HANDLE hFileDest) WriteFile(hFileDest,byBuffer,sizeof(byBuffer),&lBytes,NULL); if (lBytes != sizeof(byBuffer)) return TRUE; } - return FALSE; } @@ -82,6 +118,7 @@ UINT main(int argc, char *argv[]) { HANDLE hFileSource,hFileDest; UINT nSourceType,nDestType; + UINT nError = 0; printf("HP48 Port1 Import/Export Tool for Emu48 V" VERSION "\n"); if (argc != 3) @@ -92,7 +129,7 @@ UINT main(int argc, char *argv[]) // check source file type nSourceType = CheckType(argv[1]); - if (nSourceType == FT_ERR) + if (nSourceType == FT_ERR || nSourceType == FT_NEW) { printf("Error: Illegal source file type\n"); return 2; @@ -113,18 +150,29 @@ UINT main(int argc, char *argv[]) hFileDest = CreateFile(argv[2],GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_ALWAYS,0,NULL); if (hFileDest != INVALID_HANDLE_VALUE) { - if (nSourceType == FT_SXGX) SetFilePointer(hFileSource,-PORT1SIZE,NULL,FILE_END); - if (nDestType == FT_SXGX) SetFilePointer(hFileDest ,-PORT1SIZE,NULL,FILE_END); + BOOL bFormatErr = FALSE; - CopyData(hFileSource,hFileDest); - puts("Copy successful."); + if (nSourceType == FT_SXGX) bFormatErr |= SeekData(hFileSource,&nSourceType); + if (nDestType == FT_SXGX) bFormatErr |= SeekData(hFileDest,&nDestType); + + if (!bFormatErr && (nSourceType == nDestType || nDestType == FT_NEW)) + { + assert(nSourceType > FT_SXGX); + CopyData(hFileSource,hFileDest,nSourceType); + puts("Copy successful."); + } + else + { + printf("Error: Non matching file size or format\n"); + nError = 4; + } CloseHandle(hFileDest); } else { printf("Error: Can't open destination file %s\n",argv[2]); - return 4; + nError = 5; } CloseHandle(hFileSource); @@ -132,8 +180,8 @@ UINT main(int argc, char *argv[]) else { printf("Error: Can't open source file %s\n",argv[1]); - return 5; + nError = 6; } - return 0; + return nError; } diff --git a/sources/Cardcopy/TYPES.H b/sources/Cardcopy/TYPES.H new file mode 100644 index 0000000..456c1aa --- /dev/null +++ b/sources/Cardcopy/TYPES.H @@ -0,0 +1,103 @@ +/* + * types.h + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ + +// HST bits +#define XM 1 +#define SB 2 +#define SR 4 +#define MP 8 + +#define SWORD SHORT // signed 16 Bit variable +#define QWORD ULONGLONG // unsigned 64 Bit variable + +#define CHIPSET Chipset_t +typedef struct +{ + SWORD nPosX; // position of window + SWORD nPosY; + BYTE type; // calculator type + + DWORD Port0Size; // real size of module in KB + DWORD Port1Size; // real size of module in KB + DWORD Port2Size; // real size of module in KB (HP49G only) + LPBYTE Port0; + LPBYTE Port1; + LPBYTE Port2; + + DWORD pc; + DWORD d0; + DWORD d1; + DWORD rstkp; + DWORD rstk[8]; + BYTE A[16]; + BYTE B[16]; + BYTE C[16]; + BYTE D[16]; + BYTE R0[16]; + BYTE R1[16]; + BYTE R2[16]; + BYTE R3[16]; + BYTE R4[16]; + BYTE ST[4]; + BYTE HST; + BYTE P; + WORD out; + WORD in; + BOOL SoftInt; + BOOL Shutdn; + BOOL mode_dec; + BOOL inte; // interrupt status flag (FALSE = int in service) + BOOL intk; // 1 ms keyboard scan flag (TRUE = enable) + BOOL intd; // keyboard interrupt pending (TRUE = int pending) + BOOL carry; + + WORD crc; + WORD wPort2Crc; // fingerprint of port2 + WORD wRomCrc; // fingerprint of ROM +#if defined _USRDLL // DLL version + QWORD cycles; // oscillator cycles +#else // EXE version + DWORD cycles; // oscillator cycles + DWORD cycles_reserved; // reserved for MSB of oscillator cycles +#endif + DWORD dwKdnCycles; // cpu cycles at start of 1ms key handler + + UINT Bank_FF; // save state of HP48GX port2 or state of HP49G ROM FF + UINT FlashRomState; // WSM state of flash memory (unused) + BYTE cards_status; + BYTE IORam[64]; // I/O hardware register + UINT IOBase; // address of I/O modules page + BOOL IOCfig; // I/O module configuration flag + BYTE P0Base, BSBase, P1Base, P2Base; // address of modules first 2KB page + BYTE P0Size, BSSize, P1Size, P2Size; // mapped size of module in 2KB + BYTE P0End, BSEnd, P1End, P2End; // address of modules last 2KB page + BOOL P0Cfig, BSCfig, P1Cfig, P2Cfig; // module address configuration flag + BOOL P0Cfg2, BSCfg2, P1Cfg2, P2Cfg2; // module size configuration flag + + BYTE t1; + DWORD t2; + + BOOL bShutdnWake; // flag for wake up from SHUTDN mode + + BYTE Keyboard_Row[9]; + WORD IR15X; + UINT Keyboard_State; // not used + + signed short loffset; + signed int width; + UINT boffset; + UINT lcounter; + UINT sync; // not used + BYTE contrast; + BOOL dispon; + DWORD start1; + DWORD start12; + DWORD end1; + DWORD start2, end2; +} Chipset_t; diff --git a/sources/Emu48/CHANGES.TXT b/sources/Emu48/CHANGES.TXT index 0a74f43..47c3702 100644 --- a/sources/Emu48/CHANGES.TXT +++ b/sources/Emu48/CHANGES.TXT @@ -1,3 +1,483 @@ +Service Pack 25 for Emu48 Version 1.0 + +DDESERV.C +- replaced variable type _TCHAR with TCHAR +- added some UNREFERENCED_PARAMETER statements + +DEBUGGER.C +- replaced variable type _TCHAR with TCHAR +- added UNREFERENCED_PARAMETER statement +- bugfix in function UpdateCodeWnd(), used uninitialized variables + at first call and optimized actual address searching +- changed function UpdateStackWnd(), save stack content also as + value for easier access +- changed function OnKeyF6(), optimized getting address of selected + item +- changed function OnKeyF8(), optimized GOSUB, GOSUBL, GOSBVL + decoding +- replaced functions OnNOP3Break(), OnRplBreak() and + OnInterruptsStepOverInt() with OnToggleMenuItem() +- changed function OnDblClick(), double click on stack window item + now shows the address content in the code window +- bugfix in function InfoIntr(), variable lIndex may be used without + having been initialized + +DISASM.C +- replaced variable type _TCHAR with TCHAR +- bugfix in function disassemble(), the r=-r fs opcodes showed + always as r=r-1 fs opcodes + +DISPLAY.C +- added UNICODE support in debug output parts +- used wrong black and white RGB definition, so default display + color was white on black background and not vice versa +- changed function UpdateContrast(), optimization + +EMU48.C +- replaced variable type _TCHAR with TCHAR +- changed function CopyItemsToClipboard(), SetCommList(), + OnStackCopy() and OnStackPaste(), added some brackets + +EMU48.H +- replaced variable type _TCHAR with TCHAR +- added MapData defines +- extern declaration of global variable and function +- removed declaration of Npack() and Nunpack() + +EMU48.RC +- changed properties of IDC_DEBUG_STACK +- added Menuitem Debug "CODE Objects Breakpoints" in debugger menu +- changed version and copyright + +ENGINE.C +- replaced variable type _TCHAR with TCHAR +- changed function Debugger(), added DOCODE breakpoint handling + +EXTERNAL.C +- added ops.h in header definition + +FILES.C +- replaced variable type _TCHAR with TCHAR +- added ops.h in header definition +- changed function PatchRom(), added typecast for GCC compiler +- bugfix in function PatchRom(), lines beginning with a remark were + sometimes decoded as a valid line +- bugfix in function MapPort2(), 32KB cards were rejected + +I28F160.C +- changed table definitions fnWrState[] and fnRdState[], removed a + CONST statement + +KML.C +- replaced variable type _TCHAR with TCHAR +- changed function ParseLines(), added some brackets +- changed prototypes of function GetStringParam(), GetIntegerParam() + and SkipLines(), fixed argument mismatch +- changed function RunLine(), added default case for GCC compiler +- changed function SkipWhite(), If() and InitKML(), removed unused + variables +- changed function KillKML(), optimizations +- changed function DrawAnnunciator(), optimizations + +KML.H +- replaced variable type _TCHAR with TCHAR + +MOPS.C +- added UNICODE support in debug output parts +- added ops.h in header definition +- moved MapData defines to EMU48.H +- made function MapData() public +- changed function Npeek(), Nread() and Nwrite(), added brackets for + better code understanding + +OPCODES.C +- changed function o8Cd4() and o8Ed4(), added some spaces for better + code understanding + +OPS.H +- changed function Npack() and Nunpack(), made them static +- changed function Nneg(), added some brackets + +RESOURCE.H +- added definition + +RPL.C +- added ops.h in header definition +- added missing HP39/40G entries in RAM entry table + +SERIAL.C +- replaced variable type _TCHAR with TCHAR +- changed function UpdateUSRQ(), added return type +- changed function CommTransmit() and CommReceive(), derivate + interrupt generation from the state of the USRQ bit now + +SETTINGS.C +- replaced variable type _TCHAR with TCHAR +- bugfix in registry macro WriteString(), used wrong data size in + UNICODE mode +- bugfix in function GetRegistryString(), returned wrong string + length and used wrong read buffer size in UNICODE mode + +TIMER.C +- added ops.h in header definition +- changed function MAX(), had no definition of return value +- changed function RescheduleT2(), added some brackets + + +Service Pack 24 for Emu48 Version 1.0 + +DBGTOOL.BMP +- bitmap with debugger toolbar buttons + +DEBUGGER.C +- added toolbar to debugger window +- changed function EnterBreakpoint(), DrawBreakpoint() and + EditBreakpoint(), added RPL breakpoint handling +- changed function OnToggleCheck(), changed method of item redraw +- changed function EditBreakpoint(), added multiple selection for + deleting breakpoints + +DEBUGGER.H +- added new breakpoint define + +DISASM.C +- bugfix in function rn_map(), handle NULL pointer pages now +- bugfix in function disasm_8(), fixed broken opcode 80810 + mnemonic + +EMU48.C +- changed function SetWindowTitle(), optimization + +EMU48.DSP +- added library comctl32.lib + +EMU48.RC +- added debugger toolbar +- added RPL breakpoint in "Enter breakpoint" dialog +- changed version and copyright + +ENGINE.C +- changed function Debugger(), added RPL breakpoint handling + +PCH.H +- added include commctrl.h + +RESOURCE.H +- added definitions + + +Service Pack 23 for Emu48 Version 1.0 + +DDESERV.C +- replaced numbers with state machines defines + +DEBUGGER.C +- new function DisableMenuKeys(), replace menu item disable in + function OnKeyF5() and OnKeyF9() +- bugfix in function StrToReg() and OnLButtonUp(), used ASCII + instead of a member function of TCHAR.H +- changed function OnLButtonUp(), skip automatically disabled + windows +- bugfix in function OnKeyF9(), "Run to Cursor" menu item wasn't + disabled + +DISASM.C +- bugfix in function disasm_8(), illegal opcodes beginning with 8081 + crashed emulator, illegal opcodes beginning with 818f were shown + as r=r+CON fs,n and r=r-CON fs,n opcodes, illegal opcodes + beginning with 819f were shown as rSRB.F opcodes + +EMU48.C +- replaced numbers with state machines defines +- moved the ShowWindow() call in main program behind the state file + load to avoid viewing the window at the standard startup position + +EMU48.RC +- changed version and copyright + +ENGINE.C +- replaced numbers with state machines defines +- bugfix in function Debugger(), checked wrong data breakpoint + addresses in connection with the P,WP,XS,S,M fields + +FILES.C +- bugfix in function SaveDocument(), when the emulator window is + minimized the wrong window position was saved in the Chipset + structure + +IO.H +- changed LINECOUNT MSB definitions + +KEYBOARD.C +- replaced numbers with state machines defines + +KML.C +- replaced numbers with state machines defines + +MOPS.C +- bugfix in function CpuReset(), BS-FF must be cleared as well + +OPCODES.C +- bugfix in function o807(), added BS-FF reset handling +- removed function o_invalid() + +OPCODES.H +- removed prototype of function o_invalid() + + +Service Pack 22 for Emu48 Version 1.0 + +DEBUGGER.C +- moved global variables to EMU48.C and ENGINE.C +- changed function ViewCodeWnd() and NotifyDebugger(), changed "->" + PC position marker to "-R" on RPL breakpoints +- bugfix in function DisableDebugger(), don't destroy handle before + windows closed +- changed function Debugger(), set signal for window and last + instruction buffer closed at end of WM_DESTROY message handler, + init additional variables +- added implementation of "Find" dialog box +- bugfix in function NewValue(), EnterAddr() and EnterBreakpoint(), + used ASCII instead of a member function of TCHAR.H +- changed function OnToggleCheck(), OnDrawBreakWnd(), + DrawBreakpoint() and EditBreakpoint(), now the list box element + use a link to the corresponding breakpoint element +- bugfix in function OnDrawBreakWnd(), sometimes the old focus + rectangle wasn't purged +- changed function EditBreakpoint(), checkbox can also be toggled + with the space key now +- bugfix in function OnEditBreakpoint(), redrawed code window always + at PC position and not at actual address + +DEBUGGER.H +- moved extern declaration of global variables to EMU48.H + +DISPLAY.C +- bugfix in function UpdateDisplayPointers(), UpdateMainDisplay(), + UpdateMenuDisplay(), WriteToMainDisplay(), WriteToMenuDisplay(), + calculated wrong display areas when LINECOUNT (0x128,0x129) + register was zero + +EMU48.C +- replaced numbers with state machines defines +- added global variable from DEBUGGER.C +- changed function UpdateWindowStatus(), use groups for + enable/disable menu items now +- changed function SettingsProc(), use global variable if COM port + is open instead of calling CommConnect() +- bugfix in function OnPaint(), calculated wrong rectangle for + display area when LINECOUNT (0x128,0x129) register was zero +- bugfix in function OnDropFiles(), OnStackPaste(), OnObjectLoad(), + can't switch on if in debugger mode +- changed function WinMain(), added non modal "Find" dialog box in + main message handler +- bugfix in function WinMain(), fixed a resource leak + +EMU48.DSP +- added library advapi32.lib + +EMU48.H +- removed extern declaration of global variable and function +- removed COM port state defines +- added state machine defines +- extern declaration of global variables +- changed function prototype + +EMU48.RC +- changed properties of IDC_BREAKEDIT_WND +- added "Find" dialog +- changed version + +ENGINE.C +- replaced numbers with state machines defines +- made COM port open flag public +- added global variables from DEBUGGER.C +- changed function Debugger(), a RPL breakpoint is now set on the + destination address of a PC=(A) or a PC=(C) instruction and the + RPL breakpoint detection with a prior A=DAT0 A D0=D0+ 5 sequence + has been removed +- changed function CheckSerial(), use return value of CommOpen() + instead of calling CommConnect() +- changed function WaitForSleepState(), close debugger before going + into sleep state +- changed function SwitchToState(), changed detection of emulation + thread termination and debugger now can be active when changing + from Run to Sleep state + +FILES.C +- changed function OpenDocument(), because of changed function + CpuReset() additional work for automatic restart on changed ROM + needed + +IO.H +- added BITOFFSET definition + +MOPS.C +- removed variable ir_ctrl_acc, was never used +- bugfix in function CpuReset(), changed some initial settings +- bugfix in function WriteIO(), force new COM port initialization + when the EIRU bit in the IRC (0x11A) register has changed +- bugfix in function WriteIO(), reading from the LINECOUNT + (0x128,0x129) register destroyed the settings for the + Chipset.lcounter variable + +RESOURCE.H +- added some definitions + +RPL.C +- changed function RPL_CreateTemp(), changed remarks + +SERIAL.C +- removed function CommConnect(), not used any more +- changed function CommOpen(), changed function return type +- bugfix in function CommOpen(), receiver state variables weren't + resetted +- bugfix in function CommClose(), changed detection of thread + termination and fixed a resource leak +- bugfix in function CommTransmit(), receive buffer may be + overflowed when LPB (Loop Back) bit was set + +SETTINGS.C +- prepared for registry support + + +Service Pack 21 for Emu48 Version 1.0 + +CHECKBOX.BMP +- bitmap with checked and unchecked box + +DDESERV.C +- prepared for UNICODE support + +DEBUGGER.C +- prepared for UNICODE support +- added implementation of "Run to Cursor" +- added HP39/40G stuff to function InitBsArea() and UpdateMiscWnd() +- added Enable/Disable of breakpoints in the Edit breakpoints dialog +- added breakpoint load/save file functions +- bugfix in function NewValue(), EnterAddr(), EnterBreakpoint(), + EditBreakpoint() and InfoIntr(), try to get a window handle at + begin of a dialog message handler cause illegal handles in some + cases + +DEBUGGER.H +- extern declaration of global variable and functions + +DISASM.C +- prepared for UNICODE support +- changed function rn_port2(), select internal or external port2 + memory by the Chipset.Port2Size variable now + +DISPLAY.C +- prepared for UNICODE support + +EMU48.C +- prepared for UNICODE support +- added HP39/40G stuff to function UpdateWindowStatus(), + SettingsProc(), OnDropFiles() and Disasm() +- bugfix in function OnPaint(), redraw display and button area even + if emulation is suspended, redraw only requested bitmap area and + redraw display without updating bitmap with display data +- bugfix in function OnFileNew(), overwrite title only on new + document + +EMU48.H +- prepared for UNICODE support + +EMU48.ICO +- deleted unused device images + +EMU48.RC +- changed properties of IDC_BREAKEDIT_WND +- added Menuitem Debug "Run to Cursor" in debugger menu +- changed version and copyright + +ENGINE.C +- prepared for UNICODE support +- added part for debugger function "Run to Cursor" + +EXTERNAL.C +- added HP39/40G stuff to the SFLAG53_56 definition + +FILES.C +- prepared for UNICODE support +- added new document type for HP39/40G in several functions +- bugfix in function MapPort2(), in the first program instance in + not shared mode a read only port2 file couldn't be loaded +- bugfix in function ResetDocument(), delete MMU mappings as well +- bugfix in function OpenDocument(), ask for new KML script when + emulator state file and KML script file use different 'Model' + settings +- changed function OpenDocument() and SaveDocument(), added debugger + breakpoint data handling + +IO.H +- added LINECOUNT definition + +KML.C +- prepared for UNICODE support +- added "Class" keyword in Global section +- deleted function IsDigit(), replaced by function _istdigit() +- bugfix in function AddToLog(), fixed a memory leak +- new function MapKMLFile(), map KML file into memory +- new functions iSqrt(), AdjustPixel() and TransparentCircle(), + subroutines for new button type +- changed function DrawButton(), changed button type 5 (was same + implementation as type 0) to draw transparent circles +- changed function RefreshButtons(), redraw only buttons in + requested area + +KML.H +- prepared for UNICODE support +- added TOK_CLASS definition + +MOPS.C +- new function UpdateDisplay(), handle display update +- changed function MapP2(), select internal or external port2 memory + by the Chipset.Port2Size variable now +- added HP39/40G stuff to function MapROM(), RomSwitch(), Nread(), + Nwrite() and ReadIO() +- bugfix in function Nwrite(), update display with address content +- changed function ReadIO(), set RX bit in the RCS (0x111) register + for no character receive +- bugfix in function ReadIO(), wrong implementation of TBR register + (0x116,0x117), read return last written byte +- bugfix in function WriteIO(), clearing the SON bit in the IOC + (0x110) register clears also the IOC (0x110), RCS (0x111), TCS + (0x112), RBR (0x114,0x115) and TBR (0x116,0x117) register +- bugfix in function WriteIO(), writing to the RCS (0x111), TCS + (0x111) and TBR (0x116,0x117) register only works when the SON bit + in the IOC (0x110) register is set + +OPCODES.C +- prepared for UNICODE support +- removed InfoMessage in SREQ? opcode + +PCH.H +- added include tchar.h + +RESOURCE.H +- added some definitions +- removed IDC_DISASM_MNEMONICS + +RPL.C +- bugfix in function Metakernel(), check for port1 memory before + reading + +SERIAL.C +- prepared for UNICODE support +- bugfix in function UpdateUSRQ(), USRQ bit in SRQ1 (0x118) register + only set on serial interrupt condition when UART enabled + +SETTINGS.C +- prepared for UNICODE support +- changed function ReadSettings(), use variable content as default + +TIMER.C +- bugfix in function StartTimers(), check for timer interrupts at + timer start + + Service Pack 20 for Emu48 Version 1.0 DEBUGGER.C @@ -145,18 +625,18 @@ IO.H MOPS.C - removed conditional compiling with WSMSET - bugfix in function RomSwitch(), mirror smaller ROMs than 2MB -- bugfix in function Npeek(), wrong content of SRQ2 register (0x119) +- bugfix in function Npeek(), wrong content of SRQ2 (0x119) register - bugfix in function ReadIO(), wrong implementation of the SMP and - SWINT bit in the CARDCTL register (0x10E) + SWINT bit in the CARDCTL (0x10E) register - bugfix in function ReadIO(), wrong implementation of the NINT2 and - NINT bit in the SRQ2 register (0x119) + NINT bit in the SRQ2 (0x119) register - bugfix in function WriteIO(), wrong implementation of the SMP and - ECDT bit and removed some wrong stuff in the CARDCTL register - (0x10E) + ECDT bit and removed some wrong stuff in the CARDCTL (0x10E) + register - bugfix in function WriteIO(), the DA19 bit in the LINECOUNT - register (0x129) is also available in the Clarke hardware + (0x129) register is also available in the Clarke hardware - bugfix in function WriteIO(), the RUN bit in the TIMER2CTRL - register (0x12F) has an affection to the display annunciators + (0x12F) register has an affection to the display annunciators OPCODES.C - added io.h in header definition @@ -335,10 +815,10 @@ MOPS.C when writing on slot2 enabled (GX only) - changed function Nread() and Nwrite(), added Flash memory access detection part -- bugfix in function ReadIO(), the CARDSTATUS register (0x10F) +- bugfix in function ReadIO(), the CARDSTATUS (0x10F) register return zero when card detection is disabled - bugfix in function WriteIO(), on a HP49 force new memory mapping - on changing the LED bit in the LCR register (0x11C) + on changing the LED bit in the LCR (0x11C) register RESOURCE.H - added several definitions @@ -446,15 +926,15 @@ MOPS.C - added function CpuReset() to set cpu registers after reset - changed function Npeek(), return data from I/O register area as well now (for debugger support) -- bugfix in function Nread(), reading from the timer2 MSB register - (0x13F) updates the CRC register (0x104-0x107) +- bugfix in function Nread(), reading from the timer2 MSB (0x13F) + register updates the CRC (0x104-0x107) register - bugfix in function ReadIO(), update the USRQ bit in the SRQ1 - register (0x118) after reading the RBR register (0x114,0x115) + (0x118) register after reading the RBR (0x114,0x115) register - bugfix in function ReadIO(), update the NINT2 and NINT bits in the - SRQ2 register (0x119) + SRQ2 (0x119) register - bugfix in function WriteIO(), update the USRQ bit in the SRQ1 - register (0x118) after writing the IOC register (0x110) or the - TBR register (0x116,0x117) + (0x118) register after writing the IOC (0x110) register or the + TBR (0x116,0x117) register OPCODES.C - added DWORD casting from w.cycles variable @@ -473,11 +953,11 @@ SERIAL.C function CommOpen() and CommClose() to main program - added function UpdateUSRQ(), implements USRQ bit handling - bugfix in function CommTransmit(), added LPB bit emulation in the - TCS register (0x112) and USRQ bit emulation in the SRQ1 register - (0x118) + TCS (0x112) register and USRQ bit emulation in the SRQ1 (0x118) + register - bugfix in function CommReceive(), only reject reading if com port is closed and not whole operation and added USRQ bit emulation in - the SRQ1 register (0x118) + the SRQ1 (0x118) register SERIAL.H - renamed to IO.H @@ -490,7 +970,7 @@ TIMER.C - replaced INT define with INTR (conflict with C variable type INT) - renamed wShutdnWake variable to bShutdnWake - bugfix in function CheckT1() and CheckT2(), added TSRQ bit - emulation in the SRQ1 register (0x118) + emulation in the SRQ1 (0x118) register TYPES.H - changed variable type of wPosX and wPosY, position data is signed @@ -575,8 +1055,8 @@ KML.C MOPS.C - added HP49 MMU parts -- bugfix in function ReadIO(), update the UCK bit in the BAU - register (0x10D) +- bugfix in function ReadIO(), update the UCK bit in the BAU (0x10D) + register OPS.H - moved inline function FASTPTR() from ENGINE.C to header file @@ -797,7 +1277,7 @@ KML.C MOPS.C - added new function IOBit() - bugfix in function ReadIO(), update the KDN bit in the SRQ2 - register (0x119) before reading + (0x119) register before reading OPCODES.H - bugfix in A=IN and C=IN command, update KDN bit in the SRQ @@ -879,13 +1359,13 @@ MOPS.C display area and IO area couldn't be unconfigured - removed functions Nread2(), Nwrite2(), Nread5() and Nwrite5() - bugfix in function ReadIO(), several minor fixes in the LINECOUNT - register (0x128,0x129) emulation + (0x128,0x129) register emulation - bugfix in function ReadIO(), the TIMER1CTRL and TIMER2CTRL - register (0x12E,0x12F) must be updated before reading + (0x12E,0x12F) register must be updated before reading - bugfix in function WriteIO(), don't clear the XTRA bit in the - TIMER1CTRL register (0x12E) while setting + TIMER1CTRL (0x12E) register while setting - bugfix in function WriteIO(), after setting new TIMER1CTRL and - TIMER2CTRL register (0x12E,0x12F) values the control bit + TIMER2CTRL (0x12E,0x12F) register values the control bit condition must be checked - bugfix in function WriteIO(), handle start/stop of the LINECOUNT register when the DON bit in the DISPIO (0x100) register has @@ -1078,18 +1558,18 @@ KML.C MOPS.C - bugfix in function WriteIO(), the Chipset.start1 variable only - was updated when five nibbles at the DISPADDR register (0x120) + was updated when five nibbles at the DISPADDR (0x120) register has been written - bugfix in function WriteIO(), the Chipset.loffset variable only - was updated when three nibbles at the LINEOFFS register (0x125) + was updated when three nibbles at the LINEOFFS (0x125) register has been written - bugfix in function WriteIO(), the Chipset.lcounter variable only - was updated when the MSB of the LINECOUNT register (0x129) has + was updated when the MSB of the LINECOUNT (0x129) register has been written - bugfix in function WriteIO(), the Chipset.start2 variable only - was updated when five nibbles at the MENUADDR register (0x130) + was updated when five nibbles at the MENUADDR (0x130) register has been written -- bugfix in function ReadIO(), the LINECOUNT register (0x128-0x129) +- bugfix in function ReadIO(), the LINECOUNT (0x128-0x129) register is a down counter OPCODES.H diff --git a/sources/Emu48/CHECKBOX.BMP b/sources/Emu48/CHECKBOX.BMP new file mode 100644 index 0000000000000000000000000000000000000000..b3945ec9d4e2cfbd54116e652bda185e31417e3c GIT binary patch literal 250 zcmZvVu?>JQ3rlI(pkt+sl$yr86PcvI@xM=ROWF1ZwGNJzTBw;C zFw%ju_@61jhH4#jB2r46zOd3TbE5b>qFrApZU$D&SsG`aMh-}0E+Q9$1e@iKt>?I( Gx_@6>^=za7 literal 0 HcmV?d00001 diff --git a/sources/Emu48/DBGTOOL.BMP b/sources/Emu48/DBGTOOL.BMP new file mode 100644 index 0000000000000000000000000000000000000000..47f2e1d7a654c73d30c4e71195d30e34da890ed9 GIT binary patch literal 1198 zcma)5!Ait15S;~~f`=OM&`p0EjIWypHynUt{5aDFzRf+^6Y1^^}&5n)zpe(as6 z`tA3VYK!!l>ki04uA0x#3F%TZ&FI}W#smM}f0-Qe%q$<^6c2ZKUEQ?QM?Ead^suaR zc+hXlmoN^wo7jKqX_?QuDmY)yrZXO-Lr*F)!%$ZR=t7U;yf3}=CNvanUnRr zT#tlsOI^|qb}f$epsvbe6;epn7^Cy-^^{H6*88;Z_&o$+!$SV!`O_n~X4E6?7|3Js z!lR5$7aL>6*nRF1W-z1AnQvI`GxnDf3Qi0jyyQ`V3e#r*6UeSc#IxdXTk_10IIleq q-s3#;rR~iFoN*a?1AKH6JP*I~mu`ud4Hl2eep(Vfp^6lc%x=F*kTZz@ literal 0 HcmV?d00001 diff --git a/sources/Emu48/DDESERV.C b/sources/Emu48/DDESERV.C index 9684598..c376972 100644 --- a/sources/Emu48/DDESERV.C +++ b/sources/Emu48/DDESERV.C @@ -13,7 +13,7 @@ HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv, HSZ hsz1,HSZ hsz2,HDDEDATA hData, DWORD dwData1,DWORD dwData2) { - BYTE szBuffer[32]; + TCHAR szBuffer[32]; HDDEDATA hReturn; LPBYTE lpData,lpHeader; DWORD dwAddress,dwSize,dwLoop,dwIndex; @@ -22,15 +22,15 @@ HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv, switch (iType) { case XTYP_CONNECT: - DdeQueryString(idDdeInst,hsz2,szBuffer,sizeof(szBuffer),0); - if (0 != strcmp(szBuffer,szAppName)) + DdeQueryString(idDdeInst,hsz2,szBuffer,ARRAYSIZEOF(szBuffer),0); + if (0 != lstrcmp(szBuffer,szAppName)) return (HDDEDATA) FALSE; - DdeQueryString(idDdeInst,hsz1,szBuffer,sizeof(szBuffer),0); - return (HDDEDATA) (0==strcmp(szBuffer,szTopic)); + DdeQueryString(idDdeInst,hsz1,szBuffer,ARRAYSIZEOF(szBuffer),0); + return (HDDEDATA) (0==lstrcmp(szBuffer,szTopic)); case XTYP_POKE: // illegal data format or not in running state - if (iFmt != uCF_HpObj || nState != 0) + if (iFmt != uCF_HpObj || nState != SM_RUN) return (HDDEDATA) DDE_FNOTPROCESSED; DdeAccessData(hData,&dwSize); // fetch data size @@ -55,7 +55,7 @@ HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv, } while (nState!=nNextState) Sleep(0); - _ASSERT(nState==3); + _ASSERT(nState==SM_SLEEP); // fetch data and write to stack DdeGetData(hData,(LPBYTE) &dwIndex,sizeof(DWORD),0L); @@ -65,9 +65,9 @@ HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv, bSuccess = (WriteStack(lpData,dwSize) == S_ERR_NO); LocalFree(lpData); // free memory - SwitchToState(0); // run state + SwitchToState(SM_RUN); // run state while (nState!=nNextState) Sleep(0); - _ASSERT(nState==0); + _ASSERT(nState==SM_RUN); if (bSuccess == FALSE) return (HDDEDATA) DDE_FNOTPROCESSED; @@ -82,19 +82,19 @@ HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv, case XTYP_REQUEST: // illegal data format or not in running state - if (iFmt != uCF_HpObj || nState != 0) + if (iFmt != uCF_HpObj || nState != SM_RUN) return NULL; if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state return NULL; while (nState!=nNextState) Sleep(0); - _ASSERT(nState==3); + _ASSERT(nState==SM_SLEEP); dwAddress = RPL_Pick(1); // pick address of level1 object if (dwAddress == 0) { - SwitchToState(0); // run state + SwitchToState(SM_RUN); // run state return NULL; } dwLoop = dwSize = (RPL_SkipOb(dwAddress) - dwAddress + 1) / 2; @@ -110,7 +110,7 @@ HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv, // reserve memory if ((lpData = (LPBYTE) LocalAlloc(LMEM_FIXED,dwSize)) == NULL) { - SwitchToState(0); // run state + SwitchToState(SM_RUN); // run state return NULL; } @@ -128,11 +128,14 @@ HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv, hReturn = DdeCreateDataHandle(idDdeInst,lpData,dwSize,0,hsz2,iFmt,0); LocalFree(lpData); - SwitchToState(0); // run state + SwitchToState(SM_RUN); // run state while (nState!=nNextState) Sleep(0); - _ASSERT(nState==0); + _ASSERT(nState==SM_RUN); return hReturn; } return NULL; + UNREFERENCED_PARAMETER(hConv); + UNREFERENCED_PARAMETER(dwData1); + UNREFERENCED_PARAMETER(dwData2); } diff --git a/sources/Emu48/DEBUGGER.C b/sources/Emu48/DEBUGGER.C index 346a964..9fd54e9 100644 --- a/sources/Emu48/DEBUGGER.C +++ b/sources/Emu48/DEBUGGER.C @@ -32,16 +32,31 @@ #define MEMWNDMAX (sizeof(nCol) / sizeof(nCol[0])) +#define RT_TOOLBAR MAKEINTRESOURCE(241) // MFC toolbar resource type + +typedef struct CToolBarData +{ + WORD wVersion; + WORD wWidth; + WORD wHeight; + WORD wItemCount; + WORD aItems[1]; +} CToolBarData; + static CONST int nCol[] = { IDC_DEBUG_MEM_COL0, IDC_DEBUG_MEM_COL1, IDC_DEBUG_MEM_COL2, IDC_DEBUG_MEM_COL3, IDC_DEBUG_MEM_COL4, IDC_DEBUG_MEM_COL5, IDC_DEBUG_MEM_COL6, IDC_DEBUG_MEM_COL7 }; -static CONST char cHex[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; +static CONST TCHAR cHex[] = { _T('0'),_T('1'),_T('2'),_T('3'), + _T('4'),_T('5'),_T('6'),_T('7'), + _T('8'),_T('9'),_T('A'),_T('B'), + _T('C'),_T('D'),_T('E'),_T('F') }; typedef struct // type of breakpoint table { + BOOL bEnable; // breakpoint enabled UINT nType; // breakpoint type DWORD dwAddr; // breakpoint address } BP_T; @@ -49,38 +64,24 @@ typedef struct // type of breakpoint table static WORD wBreakpointCount = 0; // number of breakpoints static BP_T sBreakpoint[MAXBREAKPOINTS]; // breakpoint table +static BOOL bRplBreak; // RPL breakpoint + static DWORD dwAdrLine[MAXCODELINES]; // addresses of disassember lines in code window static DWORD dwAdrMem = 0; // start address of memory window static LONG lCharWidth; // width of a character (is a fix font) static HMENU hMenuCode,hMenuMem; // handle of context menues +static HWND hWndToolbar; // toolbar handle static CHIPSET OldChipset; // old chipset content static BOOL bRegUpdate[REG_SIZE]; // register update table -HWND hDlgDebug = NULL; // handle for debugger dialog - -HANDLE hEventDebug; // event handle to stop cpu thread - -BOOL bDbgEnable = FALSE; // debugger mode enable flag -INT nDbgState = DBG_RUN; // state of debugger - -BOOL bDbgNOP3 = FALSE; // halt on NOP3 (#420 opcode) -BOOL bDbgRPL = FALSE; // halt on RPL exit - -BOOL bDbgSkipInt = FALSE; // execute interrupt handler - -DWORD dwDbgRstkp; // stack recursion level of step over end -DWORD dwDbgRstk; // possible return address - -DWORD *pdwInstrArray = NULL; // last instruction array -WORD wInstrSize = INSTRSIZE; // size of last instruction array -WORD wInstrWp; // write pointer of instruction array -WORD wInstrRp; // read pointer of instruction array +static HBITMAP hBmpCheckBox; // checked and unchecked bitmap // function prototypes -static VOID OnNewValue(LPSTR lpszValue); +static BOOL OnMemFind(HWND hDlg); +static VOID OnNewValue(LPTSTR lpszValue); static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue); static BOOL OnEditBreakpoint(HWND hDlg); static BOOL OnInfoIntr(HWND hDlg); @@ -91,6 +92,29 @@ static BOOL OnInfoIntr(HWND hDlg); //# //################ +// +// disable menu keys +// +static VOID DisableMenuKeys(HWND hDlg) +{ + HMENU hMenu = GetMenu(hDlg); + + EnableMenuItem(hMenu,ID_DEBUG_RUN,MF_GRAYED); + EnableMenuItem(hMenu,ID_DEBUG_RUNCURSOR,MF_GRAYED); + EnableMenuItem(hMenu,ID_DEBUG_STEP,MF_GRAYED); + EnableMenuItem(hMenu,ID_DEBUG_STEPOVER,MF_GRAYED); + EnableMenuItem(hMenu,ID_DEBUG_STEPOUT,MF_GRAYED); + EnableMenuItem(hMenu,ID_INFO_LASTINSTRUCTIONS,MF_GRAYED); + + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUN,MAKELONG((FALSE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_BREAK,MAKELONG((TRUE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUNCURSOR,MAKELONG((FALSE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEP,MAKELONG((FALSE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOVER,MAKELONG((FALSE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOUT,MAKELONG((FALSE),0)); + return; +} + // // set/reset breakpoint // @@ -103,6 +127,12 @@ static __inline VOID ToggleBreakpoint(DWORD dwAddr) // code breakpoint found if (sBreakpoint[i].nType == BP_EXEC && sBreakpoint[i].dwAddr == dwAddr) { + if (!sBreakpoint[i].bEnable) // breakpoint disabled + { + sBreakpoint[i].bEnable = TRUE; + return; + } + // purge breakpoint for (++i; i < wBreakpointCount; ++i) sBreakpoint[i-1] = sBreakpoint[i]; @@ -114,12 +144,13 @@ static __inline VOID ToggleBreakpoint(DWORD dwAddr) // breakpoint not found if (wBreakpointCount >= MAXBREAKPOINTS) // breakpoint buffer full { - AbortMessage("Reached maximum number of breakpoints !"); + AbortMessage(_T("Reached maximum number of breakpoints !")); return; } - sBreakpoint[wBreakpointCount].nType = BP_EXEC; - sBreakpoint[wBreakpointCount].dwAddr = dwAddr; + sBreakpoint[wBreakpointCount].bEnable = TRUE; + sBreakpoint[wBreakpointCount].nType = BP_EXEC; + sBreakpoint[wBreakpointCount].dwAddr = dwAddr; ++wBreakpointCount; return; } @@ -129,8 +160,8 @@ static __inline VOID ToggleBreakpoint(DWORD dwAddr) // static __inline VOID InitBsArea(HWND hDlg) { - // HP48GX, HP49G - if (cCurrentRomType=='G' || cCurrentRomType=='X') + // HP39/40G, HP48GX, HP49G + if (cCurrentRomType=='E' || cCurrentRomType=='G' || cCurrentRomType=='X') { EnableWindow(GetDlgItem(hDlg,IDC_MISC_BS_TXT),TRUE); EnableWindow(GetDlgItem(hDlg,IDC_MISC_BS),TRUE); @@ -141,9 +172,9 @@ static __inline VOID InitBsArea(HWND hDlg) // // convert nibble register to string // -static LPSTR RegToStr(BYTE *pReg, WORD wNib) +static LPTSTR RegToStr(BYTE *pReg, WORD wNib) { - static char szBuffer[32]; + static TCHAR szBuffer[32]; WORD i; @@ -157,11 +188,11 @@ static LPSTR RegToStr(BYTE *pReg, WORD wNib) // // convert string to nibble register // -static VOID StrToReg(BYTE *pReg, WORD wNib, LPSTR lpszValue) +static VOID StrToReg(BYTE *pReg, WORD wNib, LPTSTR lpszValue) { int i,nValuelen; - nValuelen = strlen(lpszValue); + nValuelen = lstrlen(lpszValue); for (i = wNib - 1;i >= 0;--i) { if (i >= nValuelen) // no character in string @@ -171,8 +202,8 @@ static VOID StrToReg(BYTE *pReg, WORD wNib, LPSTR lpszValue) else { // convert to number - pReg[i] = toupper(*lpszValue) - '0'; - if (pReg[i] > 9) pReg[i] -= 7; + pReg[i] = _totupper(*lpszValue) - _T('0'); + if (pReg[i] > 9) pReg[i] -= _T('A') - _T('9') - 1; ++lpszValue; } } @@ -184,8 +215,8 @@ static VOID StrToReg(BYTE *pReg, WORD wNib, LPSTR lpszValue) // static VOID ViewCodeWnd(HWND hWnd, DWORD dwAddress) { - INT i,j; - char szAddress[64]; + INT i,j; + TCHAR szAddress[64]; _ASSERT(disassembler_map == MEM_MAP); // disassemble in mapped mode SendMessage(hWnd,WM_SETREDRAW,FALSE,0); @@ -193,7 +224,9 @@ static VOID ViewCodeWnd(HWND hWnd, DWORD dwAddress) for (i = 0; i < MAXCODELINES; ++i) { dwAdrLine[i] = dwAddress; - j = wsprintf(szAddress,(dwAddress == Chipset.pc) ?"%05lX-> " : "%05lX ",dwAddress); + j = wsprintf(szAddress, + (dwAddress == Chipset.pc) ? _T("%05lX-%c ") : _T("%05lX "), + dwAddress,bRplBreak ? _T('R') : _T('>')); dwAddress = disassemble(dwAddress,&szAddress[j],VIEW_SHORT); SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szAddress); } @@ -208,9 +241,9 @@ static VOID ViewMemWnd(HWND hDlg, DWORD dwAddress) { #define TEXTOFF 32 - INT i,j,k; - char szBuffer[16],szItem[4]; - BYTE cChar = 0; + INT i,j,k; + TCHAR szBuffer[16],szItem[4]; + BYTE cChar = 0; szItem[2] = 0; // end of string dwAdrMem = dwAddress; // save start address of memory window @@ -228,7 +261,7 @@ static VOID ViewMemWnd(HWND hDlg, DWORD dwAddress) // fetch data line Npeek(byLineData, dwAddress, MAXMEMITEMS); - wsprintf(szBuffer,"%05lX",dwAddress); + wsprintf(szBuffer,_T("%05lX"),dwAddress); SendDlgItemMessage(hDlg,IDC_DEBUG_MEM_ADDR,LB_ADDSTRING,0,(LPARAM) szBuffer); for (k = 0, j = 0; j < MAXMEMITEMS; ++j) @@ -244,7 +277,7 @@ static VOID ViewMemWnd(HWND hDlg, DWORD dwAddress) SendDlgItemMessage(hDlg,nCol[j/2],LB_ADDSTRING,0,(LPARAM) szItem); // text field - szBuffer[j/2] = (isprint(cChar) != 0) ? cChar : '.'; + szBuffer[j/2] = (isprint(cChar) != 0) ? cChar : _T('.'); } } szBuffer[j/2] = 0; // end of text string @@ -267,26 +300,23 @@ static VOID ViewMemWnd(HWND hDlg, DWORD dwAddress) // static VOID UpdateCodeWnd(HWND hDlg) { - INT i; DWORD dwAddress; - char szAddress[256]; + INT i,j; HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE); - // seach for actual address in code area - for (i = 0; i < MAXCODELINES; ++i) - { - // get address - SendMessage(hWnd,LB_GETTEXT,i,(LONG) szAddress); - sscanf(szAddress,"%X",&dwAddress); + j = SendMessage(hWnd,LB_GETCOUNT,0,0); // no. of items in table - if (dwAddress == Chipset.pc) // found new pc address line + // seach for actual address in code area + for (i = 0; i < j; ++i) + { + if (dwAdrLine[i] == Chipset.pc) // found new pc address line break; } // redraw code window dwAddress = dwAdrLine[0]; // redraw list box with modified pc - if (i == MAXCODELINES) // address not found + if (i == j) // address not found { dwAddress = Chipset.pc; // begin with actual pc i = 0; // set cursor on top @@ -306,95 +336,95 @@ static VOID UpdateCodeWnd(HWND hDlg) // static VOID UpdateRegisterWnd(HWND hDlg) { - char szBuffer[64]; + TCHAR szBuffer[64]; _ASSERTREG(IDC_REG_A); bRegUpdate[IDC_REG_A-REG_START] = memcmp(Chipset.A, OldChipset.A, sizeof(Chipset.A)) != 0; - wsprintf(szBuffer,"A= %s",RegToStr(Chipset.A,16)); + wsprintf(szBuffer,_T("A= %s"),RegToStr(Chipset.A,16)); SetDlgItemText(hDlg,IDC_REG_A,szBuffer); _ASSERTREG(IDC_REG_B); bRegUpdate[IDC_REG_B-REG_START] = memcmp(Chipset.B, OldChipset.B, sizeof(Chipset.B)) != 0; - wsprintf(szBuffer,"B= %s",RegToStr(Chipset.B,16)); + wsprintf(szBuffer,_T("B= %s"),RegToStr(Chipset.B,16)); SetDlgItemText(hDlg,IDC_REG_B,szBuffer); _ASSERTREG(IDC_REG_C); bRegUpdate[IDC_REG_C-REG_START] = memcmp(Chipset.C, OldChipset.C, sizeof(Chipset.C)) != 0; - wsprintf(szBuffer,"C= %s",RegToStr(Chipset.C,16)); + wsprintf(szBuffer,_T("C= %s"),RegToStr(Chipset.C,16)); SetDlgItemText(hDlg,IDC_REG_C,szBuffer); _ASSERTREG(IDC_REG_D); bRegUpdate[IDC_REG_D-REG_START] = memcmp(Chipset.D, OldChipset.D, sizeof(Chipset.D)) != 0; - wsprintf(szBuffer,"D= %s",RegToStr(Chipset.D,16)); + wsprintf(szBuffer,_T("D= %s"),RegToStr(Chipset.D,16)); SetDlgItemText(hDlg,IDC_REG_D,szBuffer); _ASSERTREG(IDC_REG_R0); bRegUpdate[IDC_REG_R0-REG_START] = memcmp(Chipset.R0, OldChipset.R0, sizeof(Chipset.R0)) != 0; - wsprintf(szBuffer,"R0=%s",RegToStr(Chipset.R0,16)); + wsprintf(szBuffer,_T("R0=%s"),RegToStr(Chipset.R0,16)); SetDlgItemText(hDlg,IDC_REG_R0,szBuffer); _ASSERTREG(IDC_REG_R1); bRegUpdate[IDC_REG_R1-REG_START] = memcmp(Chipset.R1, OldChipset.R1, sizeof(Chipset.R1)) != 0; - wsprintf(szBuffer,"R1=%s",RegToStr(Chipset.R1,16)); + wsprintf(szBuffer,_T("R1=%s"),RegToStr(Chipset.R1,16)); SetDlgItemText(hDlg,IDC_REG_R1,szBuffer); _ASSERTREG(IDC_REG_R2); bRegUpdate[IDC_REG_R2-REG_START] = memcmp(Chipset.R2, OldChipset.R2, sizeof(Chipset.R2)) != 0; - wsprintf(szBuffer,"R2=%s",RegToStr(Chipset.R2,16)); + wsprintf(szBuffer,_T("R2=%s"),RegToStr(Chipset.R2,16)); SetDlgItemText(hDlg,IDC_REG_R2,szBuffer); _ASSERTREG(IDC_REG_R3); bRegUpdate[IDC_REG_R3-REG_START] = memcmp(Chipset.R3, OldChipset.R3, sizeof(Chipset.R3)) != 0; - wsprintf(szBuffer,"R3=%s",RegToStr(Chipset.R3,16)); + wsprintf(szBuffer,_T("R3=%s"),RegToStr(Chipset.R3,16)); SetDlgItemText(hDlg,IDC_REG_R3,szBuffer); _ASSERTREG(IDC_REG_R4); bRegUpdate[IDC_REG_R4-REG_START] = memcmp(Chipset.R4, OldChipset.R4, sizeof(Chipset.R4)) != 0; - wsprintf(szBuffer,"R4=%s",RegToStr(Chipset.R4,16)); + wsprintf(szBuffer,_T("R4=%s"),RegToStr(Chipset.R4,16)); SetDlgItemText(hDlg,IDC_REG_R4,szBuffer); _ASSERTREG(IDC_REG_D0); bRegUpdate[IDC_REG_D0-REG_START] = Chipset.d0 != OldChipset.d0; - wsprintf(szBuffer,"D0=%05X",Chipset.d0); + wsprintf(szBuffer,_T("D0=%05X"),Chipset.d0); SetDlgItemText(hDlg,IDC_REG_D0,szBuffer); _ASSERTREG(IDC_REG_D1); bRegUpdate[IDC_REG_D1-REG_START] = Chipset.d1 != OldChipset.d1; - wsprintf(szBuffer,"D1=%05X",Chipset.d1); + wsprintf(szBuffer,_T("D1=%05X"),Chipset.d1); SetDlgItemText(hDlg,IDC_REG_D1,szBuffer); _ASSERTREG(IDC_REG_P); bRegUpdate[IDC_REG_P-REG_START] = Chipset.P != OldChipset.P; - wsprintf(szBuffer,"P=%X",Chipset.P); + wsprintf(szBuffer,_T("P=%X"),Chipset.P); SetDlgItemText(hDlg,IDC_REG_P,szBuffer); _ASSERTREG(IDC_REG_PC); bRegUpdate[IDC_REG_PC-REG_START] = Chipset.pc != OldChipset.pc; - wsprintf(szBuffer,"PC=%05X",Chipset.pc); + wsprintf(szBuffer,_T("PC=%05X"),Chipset.pc); SetDlgItemText(hDlg,IDC_REG_PC,szBuffer); _ASSERTREG(IDC_REG_OUT); bRegUpdate[IDC_REG_OUT-REG_START] = Chipset.out != OldChipset.out; - wsprintf(szBuffer,"OUT=%03X",Chipset.out); + wsprintf(szBuffer,_T("OUT=%03X"),Chipset.out); SetDlgItemText(hDlg,IDC_REG_OUT,szBuffer); _ASSERTREG(IDC_REG_IN); bRegUpdate[IDC_REG_IN-REG_START] = Chipset.in != OldChipset.in; - wsprintf(szBuffer,"IN=%04X",Chipset.in); + wsprintf(szBuffer,_T("IN=%04X"),Chipset.in); SetDlgItemText(hDlg,IDC_REG_IN,szBuffer); _ASSERTREG(IDC_REG_ST); bRegUpdate[IDC_REG_ST-REG_START] = memcmp(Chipset.ST, OldChipset.ST, sizeof(Chipset.ST)) != 0; - wsprintf(szBuffer,"ST=%s",RegToStr(Chipset.ST,4)); + wsprintf(szBuffer,_T("ST=%s"),RegToStr(Chipset.ST,4)); SetDlgItemText(hDlg,IDC_REG_ST,szBuffer); _ASSERTREG(IDC_REG_CY); bRegUpdate[IDC_REG_CY-REG_START] = Chipset.carry != OldChipset.carry; - wsprintf(szBuffer,"CY=%d",Chipset.carry); + wsprintf(szBuffer,_T("CY=%d"),Chipset.carry); SetDlgItemText(hDlg,IDC_REG_CY,szBuffer); _ASSERTREG(IDC_REG_MODE); bRegUpdate[IDC_REG_MODE-REG_START] = Chipset.mode_dec != OldChipset.mode_dec; - wsprintf(szBuffer,"Mode=%c",Chipset.mode_dec ? 'D' : 'H'); + wsprintf(szBuffer,_T("Mode=%c"),Chipset.mode_dec ? _T('D') : _T('H')); SetDlgItemText(hDlg,IDC_REG_MODE,szBuffer); _ASSERTREG(IDC_REG_MP); bRegUpdate[IDC_REG_MP-REG_START] = ((Chipset.HST ^ OldChipset.HST) & MP) != 0; - wsprintf(szBuffer,"MP=%d",(Chipset.HST & MP) != 0); + wsprintf(szBuffer,_T("MP=%d"),(Chipset.HST & MP) != 0); SetDlgItemText(hDlg,IDC_REG_MP,szBuffer); _ASSERTREG(IDC_REG_SR); bRegUpdate[IDC_REG_SR-REG_START] = ((Chipset.HST ^ OldChipset.HST) & SR) != 0; - wsprintf(szBuffer,"SR=%d",(Chipset.HST & SR) != 0); + wsprintf(szBuffer,_T("SR=%d"),(Chipset.HST & SR) != 0); SetDlgItemText(hDlg,IDC_REG_SR,szBuffer); _ASSERTREG(IDC_REG_SB); bRegUpdate[IDC_REG_SB-REG_START] = ((Chipset.HST ^ OldChipset.HST) & SB) != 0; - wsprintf(szBuffer,"SB=%d",(Chipset.HST & SB) != 0); + wsprintf(szBuffer,_T("SB=%d"),(Chipset.HST & SB) != 0); SetDlgItemText(hDlg,IDC_REG_SB,szBuffer); _ASSERTREG(IDC_REG_XM); bRegUpdate[IDC_REG_XM-REG_START] = ((Chipset.HST ^ OldChipset.HST) & XM) != 0; - wsprintf(szBuffer,"XM=%d",(Chipset.HST & XM) != 0); + wsprintf(szBuffer,_T("XM=%d"),(Chipset.HST & XM) != 0); SetDlgItemText(hDlg,IDC_REG_XM,szBuffer); return; } @@ -413,19 +443,22 @@ static VOID UpdateMemoryWnd(HWND hDlg) // static VOID UpdateStackWnd(HWND hDlg) { - INT i; - LONG nPos; - char szBuffer[64]; + INT i; + LONG nPos; + TCHAR szBuffer[64]; HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_STACK); SendMessage(hWnd,WM_SETREDRAW,FALSE,0); nPos = SendMessage(hWnd,LB_GETTOPINDEX,0,0); SendMessage(hWnd,LB_RESETCONTENT,0,0); - for (i = 1; i <= sizeof(Chipset.rstk) / sizeof(Chipset.rstk[0]); ++i) + for (i = 1; i <= ARRAYSIZEOF(Chipset.rstk); ++i) { - wsprintf(szBuffer,"%d: %05X", i, Chipset.rstk[(Chipset.rstkp-i)&7]); - SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); + INT j; + + wsprintf(szBuffer,_T("%d: %05X"), i, Chipset.rstk[(Chipset.rstkp-i)&7]); + j = SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); + SendMessage(hWnd,LB_SETITEMDATA,j,Chipset.rstk[(Chipset.rstkp-i)&7]); } SendMessage(hWnd,LB_SETTOPINDEX,nPos,0); SendMessage(hWnd,WM_SETREDRAW,TRUE,0); @@ -437,52 +470,52 @@ static VOID UpdateStackWnd(HWND hDlg) // static VOID UpdateMmuWnd(HWND hDlg) { - char szBuffer[64]; + TCHAR szBuffer[64]; if (Chipset.IOCfig) - wsprintf(szBuffer,"%05X",Chipset.IOBase); + wsprintf(szBuffer,_T("%05X"),Chipset.IOBase); else - strcpy(szBuffer,"-----"); + lstrcpy(szBuffer,_T("-----")); SetDlgItemText(hDlg,IDC_MMU_IO_A,szBuffer); if (Chipset.P0Cfig) - wsprintf(szBuffer,"%05X",Chipset.P0Base<<12); + wsprintf(szBuffer,_T("%05X"),Chipset.P0Base<<12); else - strcpy(szBuffer,"-----"); + lstrcpy(szBuffer,_T("-----")); SetDlgItemText(hDlg,IDC_MMU_NCE2_A,szBuffer); if (Chipset.P0Cfg2) - wsprintf(szBuffer,"%05X",(Chipset.P0Size^0xFF)<<12); + wsprintf(szBuffer,_T("%05X"),(Chipset.P0Size^0xFF)<<12); else - strcpy(szBuffer,"-----"); + lstrcpy(szBuffer,_T("-----")); SetDlgItemText(hDlg,IDC_MMU_NCE2_S,szBuffer); if (Chipset.P1Cfig) - wsprintf(szBuffer,"%05X",Chipset.P1Base<<12); + wsprintf(szBuffer,_T("%05X"),Chipset.P1Base<<12); else - strcpy(szBuffer,"-----"); + lstrcpy(szBuffer,_T("-----")); SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE1_A : IDC_MMU_CE2_A,szBuffer); if (Chipset.P1Cfg2) - wsprintf(szBuffer,"%05X",(Chipset.P1Size^0xFF)<<12); + wsprintf(szBuffer,_T("%05X"),(Chipset.P1Size^0xFF)<<12); else - strcpy(szBuffer,"-----"); + lstrcpy(szBuffer,_T("-----")); SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE1_S : IDC_MMU_CE2_S,szBuffer); if (Chipset.P2Cfig) - wsprintf(szBuffer,"%05X",Chipset.P2Base<<12); + wsprintf(szBuffer,_T("%05X"),Chipset.P2Base<<12); else - strcpy(szBuffer,"-----"); + lstrcpy(szBuffer,_T("-----")); SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE2_A : IDC_MMU_NCE3_A,szBuffer); if (Chipset.P2Cfg2) - wsprintf(szBuffer,"%05X",(Chipset.P2Size^0xFF)<<12); + wsprintf(szBuffer,_T("%05X"),(Chipset.P2Size^0xFF)<<12); else - strcpy(szBuffer,"-----"); + lstrcpy(szBuffer,_T("-----")); SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_CE2_S : IDC_MMU_NCE3_S,szBuffer); if (Chipset.BSCfig) - wsprintf(szBuffer,"%05X",Chipset.BSBase<<12); + wsprintf(szBuffer,_T("%05X"),Chipset.BSBase<<12); else - strcpy(szBuffer,"-----"); + lstrcpy(szBuffer,_T("-----")); SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_NCE3_A : IDC_MMU_CE1_A,szBuffer); if (Chipset.BSCfg2) - wsprintf(szBuffer,"%05X",(Chipset.BSSize^0xFF)<<12); + wsprintf(szBuffer,_T("%05X"),(Chipset.BSSize^0xFF)<<12); else - strcpy(szBuffer,"-----"); + lstrcpy(szBuffer,_T("-----")); SetDlgItemText(hDlg,(cCurrentRomType=='S') ? IDC_MMU_NCE3_S : IDC_MMU_CE1_S,szBuffer); return; } @@ -494,22 +527,22 @@ static VOID UpdateMiscWnd(HWND hDlg) { _ASSERTREG(IDC_MISC_INT); bRegUpdate[IDC_MISC_INT-REG_START] = Chipset.inte != OldChipset.inte; - SetDlgItemText(hDlg,IDC_MISC_INT,Chipset.inte ? "On " : "Off"); + SetDlgItemText(hDlg,IDC_MISC_INT,Chipset.inte ? _T("On ") : _T("Off")); _ASSERTREG(IDC_MISC_KEY); bRegUpdate[IDC_MISC_KEY-REG_START] = Chipset.intk != OldChipset.intk; - SetDlgItemText(hDlg,IDC_MISC_KEY,Chipset.intk ? "On " : "Off"); + SetDlgItemText(hDlg,IDC_MISC_KEY,Chipset.intk ? _T("On ") : _T("Off")); _ASSERTREG(IDC_MISC_BS); bRegUpdate[IDC_MISC_BS-REG_START] = FALSE; - // HP48GX, HP49G - if (cCurrentRomType=='G' || cCurrentRomType=='X') + // HP39/40G, HP48GX, HP49G + if (cCurrentRomType=='E' || cCurrentRomType=='G' || cCurrentRomType=='X') { - char szBuffer[64]; + TCHAR szBuffer[64]; bRegUpdate[IDC_MISC_BS-REG_START] = (Chipset.Bank_FF & 0x7F) != (OldChipset.Bank_FF & 0x7F); - wsprintf(szBuffer,"%02X",Chipset.Bank_FF & 0x7F); + wsprintf(szBuffer,_T("%02X"),Chipset.Bank_FF & 0x7F); SetDlgItemText(hDlg,IDC_MISC_BS,szBuffer); } return; @@ -521,14 +554,24 @@ static VOID UpdateMiscWnd(HWND hDlg) VOID OnUpdate(HWND hDlg) { nDbgState = DBG_STEPINTO; // state "step into" + dwDbgStopPC = -1; // disable "cursor stop address" // enable debug buttons EnableMenuItem(GetMenu(hDlg),ID_DEBUG_RUN,MF_ENABLED); + EnableMenuItem(GetMenu(hDlg),ID_DEBUG_RUNCURSOR,MF_ENABLED); EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEP,MF_ENABLED); EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEPOVER,MF_ENABLED); EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEPOUT,MF_ENABLED); EnableMenuItem(GetMenu(hDlg),ID_INFO_LASTINSTRUCTIONS,MF_ENABLED); + // enable toolbar buttons + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUN,MAKELONG((TRUE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_BREAK,MAKELONG((FALSE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_RUNCURSOR,MAKELONG((TRUE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEP,MAKELONG((TRUE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOVER,MAKELONG((TRUE),0)); + SendMessage(hWndToolbar,TB_ENABLEBUTTON,ID_DEBUG_STEPOUT,MAKELONG((TRUE),0)); + // update windows UpdateCodeWnd(hDlg); // update code window UpdateRegisterWnd(hDlg); // update registers window @@ -571,12 +614,14 @@ static BOOL OnKeyF2(HWND hDlg) // static BOOL OnKeyF5(HWND hDlg) { - HWND hWnd; - INT i,nPos; - char szBuf[64]; + HWND hWnd; + INT i,nPos; + TCHAR szBuf[64]; if (nDbgState != DBG_RUN) // emulation stopped { + DisableMenuKeys(hDlg); // disable menu keys + hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE); nPos = SendMessage(hWnd,LB_GETCURSEL,0,0); @@ -584,23 +629,16 @@ static BOOL OnKeyF5(HWND hDlg) for (i = 0; i < MAXCODELINES; ++i) { SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuf); - if (szBuf[5] == '-') // PC in window + if (szBuf[5] != _T(' ')) // PC in window { - szBuf[5] = szBuf[6] = ' '; + szBuf[5] = szBuf[6] = _T(' '); SendMessage(hWnd,LB_DELETESTRING,i,0); - SendMessage(hWnd,LB_INSERTSTRING,i,(LPARAM)(LPSTR)szBuf); + SendMessage(hWnd,LB_INSERTSTRING,i,(LPARAM)(LPTSTR)szBuf); break; } } SendMessage(hWnd,LB_SETCURSEL,nPos,0); - // disable menu keys - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_RUN,MF_GRAYED); - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEP,MF_GRAYED); - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEPOVER,MF_GRAYED); - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEPOUT,MF_GRAYED); - EnableMenuItem(GetMenu(hDlg),ID_INFO_LASTINSTRUCTIONS,MF_GRAYED); - nDbgState = DBG_RUN; // state "run" OldChipset = Chipset; // save chipset values SetEvent(hEventDebug); // run emulation @@ -609,6 +647,22 @@ static BOOL OnKeyF5(HWND hDlg) UNREFERENCED_PARAMETER(hDlg); } +// +// step cursor key handler (F6) +// +static BOOL OnKeyF6(HWND hDlg) +{ + if (nDbgState != DBG_RUN) // emulation stopped + { + // get address of selected item + INT nPos = SendDlgItemMessage(hDlg,IDC_DEBUG_CODE,LB_GETCURSEL,0,0); + dwDbgStopPC = dwAdrLine[nPos]; + + OnKeyF5(hDlg); // run emulation + } + return -1; // call windows default handler +} + // // step into key handler (F7) // @@ -635,21 +689,14 @@ static BOOL OnKeyF8(HWND hDlg) dwDbgRstkp = Chipset.rstkp; // save stack level - nDbgState = DBG_STEPINTO; // state "step into" - if (I[0] == 0x7) // GOSUB 7aaa + // GOSUB 7aaa, GOSUBL 8Eaaaa, GOSBVL 8Faaaaa + if (I[0] == 0x7 || (I[0] == 0x8 && (I[1] == 0xE || I[1] == 0xF))) { nDbgState = DBG_STEPOVER; // state "step over" } - if (I[0] == 0x8) // GOSUBL or GOSBVL + else { - if (I[1] == 0xE) // GOSUBL 8Eaaaa - { - nDbgState = DBG_STEPOVER; // state "step over" - } - if (I[1] == 0xF) // GOSBVL 8Eaaaaa - { - nDbgState = DBG_STEPOVER; // state "step over" - } + nDbgState = DBG_STEPINTO; // state "step into" } OldChipset = Chipset; // save chipset values SetEvent(hEventDebug); // run emulation @@ -665,13 +712,7 @@ static BOOL OnKeyF9(HWND hDlg) { if (nDbgState != DBG_RUN) // emulation stopped { - // disable menu keys - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_RUN,MF_GRAYED); - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEP,MF_GRAYED); - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEPOVER,MF_GRAYED); - EnableMenuItem(GetMenu(hDlg),ID_DEBUG_STEPOUT,MF_GRAYED); - EnableMenuItem(GetMenu(hDlg),ID_INFO_LASTINSTRUCTIONS,MF_GRAYED); - + DisableMenuKeys(hDlg); // disable menu keys dwDbgRstkp = (Chipset.rstkp-1)&7; // save stack data dwDbgRstk = Chipset.rstk[dwDbgRstkp]; nDbgState = DBG_STEPOUT; // state "step out" @@ -767,32 +808,12 @@ static BOOL OnClearAll(HWND hDlg) } // -// toggle NOP3 breakpoint +// toggle menu selection // -static BOOL OnNOP3Break(HWND hDlg) +static BOOL OnToggleMenuItem(HWND hDlg,UINT uIDCheckItem,BOOL *bCheck) { - bDbgNOP3 = !bDbgNOP3; // toggle NOP3 debug flag - CheckMenuItem(GetMenu(hDlg),ID_BREAKPOINTS_NOP3,bDbgNOP3 ? MF_CHECKED : MF_UNCHECKED); - return TRUE; -} - -// -// toggle RPL breakpoint -// -static BOOL OnRplBreak(HWND hDlg) -{ - bDbgRPL = !bDbgRPL; // toggle RPL debug flag - CheckMenuItem(GetMenu(hDlg),ID_BREAKPOINTS_RPL,bDbgRPL ? MF_CHECKED : MF_UNCHECKED); - return TRUE; -} - -// -// toggle Step Over Interrupts -// -static OnInterruptsStepOverInt(HWND hDlg) -{ - bDbgSkipInt = !bDbgSkipInt; // toggle interrupt handler skip flag - CheckMenuItem(GetMenu(hDlg),ID_INTR_STEPOVERINT,bDbgSkipInt ? MF_CHECKED : MF_UNCHECKED); + *bCheck = !*bCheck; // toggle flag + CheckMenuItem(GetMenu(hDlg),uIDCheckItem,*bCheck ? MF_CHECKED : MF_UNCHECKED); return TRUE; } @@ -801,21 +822,21 @@ static OnInterruptsStepOverInt(HWND hDlg) // static BOOL OnLButtonUp(HWND hDlg, LPARAM lParam) { - char szBuffer[64]; + TCHAR szBuffer[64]; POINT pt; HWND hWnd; INT nId; - #define BUFLEN (sizeof(szBuffer) / sizeof(szBuffer[0])) - if (nDbgState != DBG_STEPINTO) // not in single step mode return TRUE; POINTSTOPOINT(pt,MAKEPOINTS(lParam)); - hWnd = ChildWindowFromPoint(hDlg,pt); // handle of selected window + + // handle of selected window + hWnd = ChildWindowFromPointEx(hDlg,pt,CWP_SKIPDISABLED); nId = GetDlgCtrlID(hWnd); // control ID of window - SendMessage(hWnd,WM_GETTEXT,BUFLEN,(LPARAM)szBuffer); + SendMessage(hWnd,WM_GETTEXT,ARRAYSIZEOF(szBuffer),(LPARAM)szBuffer); switch (nId) { case IDC_REG_A: // A @@ -856,35 +877,34 @@ static BOOL OnLButtonUp(HWND hDlg, LPARAM lParam) break; case IDC_REG_D0: // D0 OnNewValue(&szBuffer[3]); - sscanf(&szBuffer[3],"%5X",&Chipset.d0); + _stscanf(&szBuffer[3],_T("%5X"),&Chipset.d0); break; case IDC_REG_D1: // D1 OnNewValue(&szBuffer[3]); - sscanf(&szBuffer[3],"%5X",&Chipset.d1); + _stscanf(&szBuffer[3],_T("%5X"),&Chipset.d1); break; case IDC_REG_P: // P OnNewValue(&szBuffer[2]); - Chipset.P = toupper(szBuffer[2]) - '0'; + Chipset.P = _totupper(szBuffer[2]) - _T('0'); if (Chipset.P > 9) Chipset.P -= 7; break; case IDC_REG_PC: // PC OnNewValue(&szBuffer[3]); - sscanf(&szBuffer[3],"%5X",&Chipset.pc); + _stscanf(&szBuffer[3],_T("%5X"),&Chipset.pc); break; case IDC_REG_OUT: // OUT OnNewValue(&szBuffer[4]); - sscanf(&szBuffer[4],"%3X",&Chipset.out); + _stscanf(&szBuffer[4],_T("%3X"),&Chipset.out); break; case IDC_REG_IN: // IN OnNewValue(&szBuffer[3]); - sscanf(&szBuffer[3],"%4X",&Chipset.in); + _stscanf(&szBuffer[3],_T("%4X"),&Chipset.in); break; case IDC_REG_ST: // ST OnNewValue(&szBuffer[3]); StrToReg(Chipset.ST,4,&szBuffer[3]); break; case IDC_REG_CY: // CY -// if (YesNoMessage("Change Carry flag ?") == IDYES) Chipset.carry = !Chipset.carry; break; case IDC_REG_MODE: // MODE @@ -911,22 +931,18 @@ static BOOL OnLButtonUp(HWND hDlg, LPARAM lParam) UpdateMiscWnd(hDlg); // update miscellaneous window break; case IDC_MISC_BS: // Bank switcher setting - if (IsWindowEnabled(hWnd)) // BS text enabled - { - OnNewValue(szBuffer); - sscanf(szBuffer,"%2X",&Chipset.Bank_FF); - Chipset.Bank_FF &= 0x7F; - RomSwitch(Chipset.Bank_FF); // update memory mapping + OnNewValue(szBuffer); + _stscanf(szBuffer,_T("%2X"),&Chipset.Bank_FF); + Chipset.Bank_FF &= 0x7F; + RomSwitch(Chipset.Bank_FF); // update memory mapping - UpdateCodeWnd(hDlg); // update code window - UpdateMemoryWnd(hDlg); // update memory window - UpdateMiscWnd(hDlg); // update miscellaneous window - } + UpdateCodeWnd(hDlg); // update code window + UpdateMemoryWnd(hDlg); // update memory window + UpdateMiscWnd(hDlg); // update miscellaneous window break; } UpdateRegisterWnd(hDlg); // update register return TRUE; - #undef BUFLEN } // @@ -934,11 +950,22 @@ static BOOL OnLButtonUp(HWND hDlg, LPARAM lParam) // static BOOL OnDblClick(HWND hWnd, WORD wId) { - char szBuffer[4]; + TCHAR szBuffer[4]; BYTE byData; INT i; DWORD dwAddress; + if (wId == IDC_DEBUG_STACK) // stack list box + { + // get cpu address of selected item + i = SendMessage(hWnd,LB_GETCURSEL,0,0); + dwAddress = SendMessage(hWnd,LB_GETITEMDATA,i,0); + + // show code of this address + ViewCodeWnd(GetDlgItem(GetParent(hWnd),IDC_DEBUG_CODE),dwAddress); + return TRUE; + } + for (i = 0; i < MEMWNDMAX; ++i) // scan all Id's if (nCol[i] == wId) // found ID break; @@ -953,7 +980,7 @@ static BOOL OnDblClick(HWND hWnd, WORD wId) // enter new value SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuffer); OnNewValue(szBuffer); - sscanf(szBuffer,"%2X", &byData); + _stscanf(szBuffer,_T("%2X"), &byData); byData = (byData >> 4) | (byData << 4); // change nibbles for writing Write2(dwAddress, byData); // write data @@ -1028,7 +1055,6 @@ static __inline BOOL OnKeyRightLeft(HWND hWnd, WPARAM wParam) hWndNew = GetDlgItem(GetParent(hWnd),nCol[wX]); SendMessage(hWndNew,LB_SETCURSEL,wY,0); SetFocus(hWndNew); - return -2; } @@ -1108,7 +1134,7 @@ static __inline BOOL OnKeyCodeWnd(HWND hDlg, WPARAM wParam) if (dwAdrLine[0] > 0) ViewCodeWnd(hWnd,dwAdrLine[0]-1); } - if (wKey == 'G') return OnCodeGoAdr(GetParent(hWnd)); // goto new address + if (wKey == _T('G')) return OnCodeGoAdr(GetParent(hWnd)); // goto new address return -1; } @@ -1118,7 +1144,7 @@ static __inline BOOL OnKeyCodeWnd(HWND hDlg, WPARAM wParam) // static __inline BOOL OnDrawCodeWnd(LPDRAWITEMSTRUCT lpdis) { - char szBuf[64]; + TCHAR szBuf[64]; COLORREF crBkColor; COLORREF crTextColor; BOOL bBrk,bPC; @@ -1127,11 +1153,11 @@ static __inline BOOL OnDrawCodeWnd(LPDRAWITEMSTRUCT lpdis) return TRUE; // get item text - SendMessage(lpdis->hwndItem,LB_GETTEXT,lpdis->itemID,(LONG)(LPSTR)szBuf); + SendMessage(lpdis->hwndItem,LB_GETTEXT,lpdis->itemID,(LONG)(LPTSTR)szBuf); // check for codebreakpoint bBrk = CheckBreakpoint(dwAdrLine[lpdis->itemID],1,BP_EXEC); - bPC = szBuf[5] == '-'; // check if line of program counter + bPC = szBuf[5] != _T(' '); // check if line of program counter crTextColor = COLOR_WHITE; // standard text color @@ -1171,7 +1197,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,strlen(szBuf),NULL); + ETO_OPAQUE,(LPRECT)&lpdis->rcItem,szBuf,lstrlen(szBuf),NULL); SetBkColor(lpdis->hDC,crBkColor); SetTextColor(lpdis->hDC,crTextColor); @@ -1212,12 +1238,12 @@ BOOL CheckBreakpoint(DWORD dwAddr, DWORD dwRange, UINT nType) for (i = 0; i < wBreakpointCount; ++i) // scan all breakpoints { // check address range and type - if ( sBreakpoint[i].dwAddr >= dwAddr && sBreakpoint[i].dwAddr < dwAddr + dwRange + if ( sBreakpoint[i].bEnable + && sBreakpoint[i].dwAddr >= dwAddr && sBreakpoint[i].dwAddr < dwAddr + dwRange && (sBreakpoint[i].nType & nType) != 0) return TRUE; } return FALSE; - UNREFERENCED_PARAMETER(dwRange); } // @@ -1225,12 +1251,23 @@ BOOL CheckBreakpoint(DWORD dwAddr, DWORD dwRange, UINT nType) // VOID NotifyDebugger(BOOL bType) // update registers { + bRplBreak = bType; // save breakpoint type _ASSERT(hDlgDebug); // debug dialog box open PostMessage(hDlgDebug,WM_UPDATE,0,0); return; - UNREFERENCED_PARAMETER(bType); } +// +// disable debugger +// +VOID DisableDebugger(VOID) +{ + if (hDlgDebug) // debugger running + DestroyWindow(hDlgDebug); // then close debugger to renter emulation + return; +} + + //################ //# //# Debugger Message loop @@ -1240,13 +1277,75 @@ VOID NotifyDebugger(BOOL bType) // update registers // // ID_TOOL_DEBUG // +static __inline HWND CreateToolbar(HWND hWnd) +{ + INITCOMMONCONTROLSEX icex; + + HRSRC hRes; + HGLOBAL hGlobal; + CToolBarData *pData; + TBBUTTON *ptbb; + INT i,j; + + HWND hWndToolbar = NULL; // toolbar window + + // init common control DLL + icex.dwSize = sizeof(INITCOMMONCONTROLSEX); + icex.dwICC = ICC_BAR_CLASSES; + InitCommonControlsEx(&icex); + + if ((hRes = FindResource(hApp,MAKEINTRESOURCE(IDR_DEBUG_TOOLBAR),RT_TOOLBAR)) == NULL) + goto quit; + + if ((hGlobal = LoadResource(hApp,hRes)) == NULL) + goto quit; + + if ((pData = (CToolBarData*) LockResource(hGlobal)) == NULL) + goto unlock; + + _ASSERT(pData->wVersion == 1); // toolbar resource version + + // alloc memory for TBBUTTON stucture + if (!(ptbb = (PTBBUTTON) LocalAlloc(LMEM_FIXED,pData->wItemCount*sizeof(TBBUTTON)))) + goto unlock; + + // fill TBBUTTON stucture with resource data + for (i = j = 0; i < pData->wItemCount; ++i) + { + if (pData->aItems[i]) + { + ptbb[i].iBitmap = j++; + ptbb[i].fsStyle = TBSTYLE_BUTTON; + } + else + { + ptbb[i].iBitmap = 5; // separator width + ptbb[i].fsStyle = TBSTYLE_SEP; + } + ptbb[i].idCommand = pData->aItems[i]; + ptbb[i].fsState = TBSTATE_ENABLED; + ptbb[i].dwData = 0; + ptbb[i].iString = j; + } + + hWndToolbar = CreateToolbarEx(hWnd,WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS, + IDR_DEBUG_TOOLBAR,j,hApp,IDR_DEBUG_TOOLBAR,ptbb,pData->wItemCount, + pData->wWidth,pData->wHeight,pData->wWidth,pData->wHeight, + sizeof(TBBUTTON)); + + LocalFree(ptbb); + +unlock: + FreeResource(hGlobal); +quit: + return hWndToolbar; +} + static BOOL CALLBACK Debugger(HWND hDlg, UINT message, DWORD wParam, LONG lParam) { static HMENU hMenuMainCode,hMenuMainMem; - LPDRAWITEMSTRUCT lpdis; - LPMEASUREITEMSTRUCT lpmis; - TEXTMETRIC tm; + TEXTMETRIC tm; HDC hDC; HFONT hFont; INT i; @@ -1255,7 +1354,8 @@ static BOOL CALLBACK Debugger(HWND hDlg, UINT message, DWORD wParam, LONG lParam { case WM_INITDIALOG: _ASSERT(hWnd); - EnableMenuItem(GetMenu(hWnd),ID_TOOL_DEBUG,MF_GRAYED); + SetClassLong(hDlg,GCL_HICON,(LONG) LoadIcon(hApp,MAKEINTRESOURCE(IDI_EMU48))); + hWndToolbar = CreateToolbar(hDlg); // add toolbar CheckMenuItem(GetMenu(hDlg),ID_BREAKPOINTS_NOP3,bDbgNOP3 ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(GetMenu(hDlg),ID_BREAKPOINTS_RPL, bDbgRPL ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(GetMenu(hDlg),ID_INTR_STEPOVERINT,bDbgSkipInt ? MF_CHECKED : MF_UNCHECKED); @@ -1263,7 +1363,7 @@ static BOOL CALLBACK Debugger(HWND hDlg, UINT message, DWORD wParam, LONG lParam hEventDebug = CreateEvent(NULL,FALSE,FALSE,NULL); if (hEventDebug == NULL) { - AbortMessage("Event creation failed !"); + AbortMessage(_T("Event creation failed !")); return TRUE; } hMenuMainCode = LoadMenu(hApp,MAKEINTRESOURCE(IDR_DEBUG_CODE)); @@ -1284,35 +1384,43 @@ static BOOL CALLBACK Debugger(HWND hDlg, UINT message, DWORD wParam, LONG lParam SendDlgItemMessage(hDlg,IDC_STATIC_MISC, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); // init last instruction circular buffer - pdwInstrArray = LocalAlloc(LMEM_FIXED,wInstrSize*sizeof(*pdwInstrArray)); + pdwInstrArray = LocalAlloc(LMEM_FIXED,INSTRSIZE*sizeof(*pdwInstrArray)); + wInstrSize = INSTRSIZE; // size of last instruction array wInstrWp = wInstrRp = 0; // write/read pointer InitBsArea(hDlg); // init bank switcher list box disassembler_map = MEM_MAP; // disassemble with mapped modules + dwDbgStopPC = -1; // no stop address for goto cursor + dwDbgRplPC = -1; // no stop address for RPL breakpoint + bDbgEnable = TRUE; // debugger active nDbgState = DBG_STEPINTO; // state "step into" if (Chipset.Shutdn) // cpu thread stopped SetEvent(hEventShutdn); // goto debug session + UpdateWindowStatus(); // disable application menu items OldChipset = Chipset; // save chipset values return TRUE; case WM_DESTROY: - // SetHP48Time(); // update HP48 time & date - hDlgDebug = NULL; // debugger windows closed + // SetHP48Time(); // update time & date bDbgEnable = FALSE; // debugger inactive nDbgState = DBG_RUN; // state of debugger bInterrupt = TRUE; // exit opcode loop SetEvent(hEventDebug); - // free last instruction circular buffer - if (pdwInstrArray) LocalFree(pdwInstrArray); + if (pdwInstrArray) // free last instruction circular buffer + { + LocalFree(pdwInstrArray); + pdwInstrArray = NULL; + } CloseHandle(hEventDebug); DestroyMenu(hMenuMainCode); DestroyMenu(hMenuMainMem); _ASSERT(hWnd); - EnableMenuItem(GetMenu(hWnd),ID_TOOL_DEBUG,MF_ENABLED); + UpdateWindowStatus(); // enable application menu items + hDlgDebug = NULL; // debugger windows closed break; case WM_CLOSE: @@ -1343,6 +1451,7 @@ static BOOL CALLBACK Debugger(HWND hDlg, UINT message, DWORD wParam, LONG lParam { case ID_BREAKPOINTS_SETBREAK: return OnKeyF2(hDlg); case ID_DEBUG_RUN: return OnKeyF5(hDlg); + case ID_DEBUG_RUNCURSOR: return OnKeyF6(hDlg); case ID_DEBUG_STEP: return OnKeyF7(hDlg); case ID_DEBUG_STEPOVER: return OnKeyF8(hDlg); case ID_DEBUG_STEPOUT: return OnKeyF9(hDlg); @@ -1352,15 +1461,19 @@ static BOOL CALLBACK Debugger(HWND hDlg, UINT message, DWORD wParam, LONG lParam case ID_DEBUG_CODE_SETPCTOSELECT: return OnCodeSetPcToSelection(hDlg); case ID_BREAKPOINTS_CODEEDIT: return OnEditBreakpoint(hDlg); case ID_BREAKPOINTS_CLEARALL: return OnClearAll(hDlg); - case ID_BREAKPOINTS_NOP3: return OnNOP3Break(hDlg); - case ID_BREAKPOINTS_RPL: return OnRplBreak(hDlg); + case ID_BREAKPOINTS_NOP3: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgNOP3); + case ID_BREAKPOINTS_DOCODE: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgCode); + case ID_BREAKPOINTS_RPL: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgRPL); case ID_INFO_LASTINSTRUCTIONS: return OnInfoIntr(hDlg); - case ID_INTR_STEPOVERINT: return OnInterruptsStepOverInt(hDlg); + case ID_INTR_STEPOVERINT: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgSkipInt); case ID_DEBUG_MEM_GOADR: return OnMemGoAdr(hDlg); - case ID_DEBUG_MEM_GOPC: return OnMemGoDx(hDlg, Chipset.pc); - case ID_DEBUG_MEM_GOD0: return OnMemGoDx(hDlg, Chipset.d0); - case ID_DEBUG_MEM_GOD1: return OnMemGoDx(hDlg, Chipset.d1); - case ID_DEBUG_MEM_GOSTACK: return OnMemGoDx(hDlg, Chipset.rstk[(Chipset.rstkp-1)&7]); + case ID_DEBUG_MEM_GOPC: return OnMemGoDx(hDlg,Chipset.pc); + case ID_DEBUG_MEM_GOD0: return OnMemGoDx(hDlg,Chipset.d0); + case ID_DEBUG_MEM_GOD1: return OnMemGoDx(hDlg,Chipset.d1); + case ID_DEBUG_MEM_GOSTACK: return OnMemGoDx(hDlg,Chipset.rstk[(Chipset.rstkp-1)&7]); + case ID_DEBUG_MEM_FIND: return OnMemFind(hDlg); + + case ID_DEBUG_CANCEL: DestroyWindow(hDlg); return TRUE; } break; @@ -1369,6 +1482,7 @@ static BOOL CALLBACK Debugger(HWND hDlg, UINT message, DWORD wParam, LONG lParam { case VK_F2: return OnKeyF2(hDlg); // toggle breakpoint case VK_F5: return OnKeyF5(hDlg); // key run + case VK_F6: return OnKeyF6(hDlg); // key step cursor case VK_F7: return OnKeyF7(hDlg); // key step into case VK_F8: return OnKeyF8(hDlg); // key step over case VK_F9: return OnKeyF9(hDlg); // key step out @@ -1392,7 +1506,8 @@ static BOOL CALLBACK Debugger(HWND hDlg, UINT message, DWORD wParam, LONG lParam case IDC_DEBUG_MEM_COL7: switch (LOWORD(wParam)) { - case 'G': return OnMemGoAdr(GetParent((HWND) lParam)); + case _T('G'): return OnMemGoAdr(GetParent((HWND) lParam)); + case _T('F'): return OnMemFind(GetParent((HWND) lParam)); case VK_RIGHT: case VK_LEFT: return OnKeyRightLeft((HWND) lParam, wParam); case VK_NEXT: @@ -1421,26 +1536,33 @@ static BOOL CALLBACK Debugger(HWND hDlg, UINT message, DWORD wParam, LONG lParam } break; + case WM_NOTIFY: + // tooltip for toolbar + if(((LPNMHDR) lParam)->code == TTN_GETDISPINFO) + { + ((LPTOOLTIPTEXT) lParam)->hinst = hApp; + ((LPTOOLTIPTEXT) lParam)->lpszText = MAKEINTRESOURCE(((LPTOOLTIPTEXT) lParam)->hdr.idFrom); + break; + } + break; + case WM_DRAWITEM: - lpdis = (LPDRAWITEMSTRUCT)lParam; // get pointer to the DRAWITEMSTRUCT - if (wParam == IDC_DEBUG_CODE) return OnDrawCodeWnd(lpdis); + if (wParam == IDC_DEBUG_CODE) return OnDrawCodeWnd((LPDRAWITEMSTRUCT) lParam); break; case WM_MEASUREITEM: - lpmis = (LPMEASUREITEMSTRUCT)lParam; // get pointer to the MEASUREITEMSTRUCT - hDC = GetDC(hDlg); // GetTextMetrics from "Courier New 8" font hFont = CreateFont(-MulDiv(8,GetDeviceCaps(hDC, LOGPIXELSY),72),0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, - OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,"Courier New"); + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Courier New")); hFont = SelectObject(hDC,hFont); GetTextMetrics(hDC,&tm); hFont = SelectObject(hDC,hFont); DeleteObject(hFont); - lpmis->itemHeight = tm.tmHeight; + ((LPMEASUREITEMSTRUCT) lParam)->itemHeight = tm.tmHeight; lCharWidth = tm.tmAveCharWidth; ReleaseDC(hDlg,hDC); @@ -1453,13 +1575,172 @@ LRESULT OnToolDebug() // debugger dialogbox call { if ((hDlgDebug = CreateDialog(hApp,MAKEINTRESOURCE(IDD_DEBUG),GetParent(hWnd), (DLGPROC)Debugger)) == NULL) - AbortMessage("Debugger Dialog Box Creation Error !"); - - SetClassLong(hDlgDebug,GCL_HICON,(LONG) LoadIcon(hApp,MAKEINTRESOURCE(IDI_EMU48))); + AbortMessage(_T("Debugger Dialog Box Creation Error !")); return 0; } +//################ +//# +//# Find dialog box +//# +//################ + +static __inline BOOL OnFindOK(HWND hDlg,BOOL bASCII,DWORD *pdwAddrLast) +{ + BYTE *lpbySearch; + INT i,j; + DWORD dwAddr; + BOOL bMatch; + + HWND hWnd = GetDlgItem(hDlg,IDC_FIND_DATA); + + i = GetWindowTextLength(hWnd); // text length + + j = bASCII ? 2 : 1; // buffer width + if (j < sizeof(*(LPTSTR)0)) j = sizeof(*(LPTSTR)0); + + // allocate search buffer + if ((lpbySearch = LocalAlloc(GMEM_FIXED,(i+1) * j)) != NULL) + { + // get search text and real length + i = GetWindowText(hWnd,(LPTSTR) lpbySearch,(i+1)); + + // add string to combo box + if (SendMessage(hWnd,CB_FINDSTRINGEXACT,0,(LPARAM) lpbySearch) == CB_ERR) + SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) lpbySearch); + + #if defined _UNICODE + { + // Unicode to byte translation + LPTSTR szTmp = DuplicateString((LPTSTR) lpbySearch); + if (szTmp != NULL) + { + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, + szTmp, -1, + lpbySearch, i+1, NULL, NULL); + LocalFree(szTmp); + } + } + #endif + + // convert input format to nibble based format + if (bASCII) // ASCII input + { + // convert ASCII to number + for (j = i - 1; j >= 0; --j) + { + // order MSB, LSB + lpbySearch[j * 2 + 1] = lpbySearch[j] & 0xF; + lpbySearch[j * 2] = lpbySearch[j] >> 4; + } + i *= 2; // no. of nibbles + } + else // hex number input + { + // convert HEX to number + for (i = 0, j = 0; lpbySearch[j] != 0; ++j) + { + if (lpbySearch[j] == ' ') // skip space + continue; + + if (isxdigit(lpbySearch[j])) + { + lpbySearch[i] = toupper(lpbySearch[j]) - '0'; + if (lpbySearch[i] > 9) lpbySearch[i] -= 'A' - '9' - 1; + } + else + { + i = 0; // wrong format, no match + break; + } + ++i; // inc, no. of nibbles + } + } + + bMatch = FALSE; // no match + dwAddr = dwAdrMem; // calculate search start address + if (*pdwAddrLast == dwAddr) + ++dwAddr; + + // scan 1M Nibble until match + for (; i && !bMatch && dwAddr <= dwAdrMem + 0x100000; ++dwAddr) + { + BYTE byC; + + // i = no. of nibbles that have to match + for (bMatch = TRUE, j = 0;bMatch && j < i; ++j) + { + Npeek(&byC,(dwAddr + j) & 0xFFFFF,1); + bMatch = (byC == lpbySearch[j]); + } + } + dwAddr = (dwAddr - 1) & 0xFFFFF; // possible matching address + LocalFree(lpbySearch); + + // check match result + if (bMatch) + { + OnMemGoDx(GetParent(hDlg),dwAddr); + *pdwAddrLast = dwAddr; // latest written address + } + else + { + MessageBox(hDlg,_T("Search string not found!"),_T("Find"), + MB_APPLMODAL|MB_OK|MB_ICONEXCLAMATION|MB_SETFOREGROUND); + } + } + return TRUE; +} + +// +// enter find dialog +// +static BOOL CALLBACK Find(HWND hDlg, UINT message, DWORD wParam, LONG lParam) +{ + static DWORD dwAddrEntry; + static BOOL bASCII = FALSE; + + switch (message) + { + case WM_INITDIALOG: + CheckDlgButton(hDlg,IDC_FIND_ASCII,bASCII); + dwAddrEntry = -1; + return TRUE; + + case WM_DESTROY: + hDlgFind = NULL; + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_FIND_ASCII: bASCII = !bASCII; return TRUE; + case IDOK: return OnFindOK(hDlg,bASCII,&dwAddrEntry); + case IDCANCEL: DestroyWindow(hDlg); return TRUE; + } + break; + } + return FALSE; + UNREFERENCED_PARAMETER(lParam); +} + +static BOOL OnMemFind(HWND hDlg) +{ + if (hDlgFind == NULL) // no find dialog, create it + { + if ((hDlgFind = CreateDialog(hApp,MAKEINTRESOURCE(IDD_FIND),hDlg, + (DLGPROC)Find)) == NULL) + AbortMessage(_T("Find Dialog Box Creation Error !")); + } + else + { + SetFocus(hDlgFind); // set focus on find dialog + } + return -1; // call windows default handler +} + + //################ //# //# New Value dialog box @@ -1471,38 +1752,39 @@ LRESULT OnToolDebug() // debugger dialogbox call // static BOOL CALLBACK NewValue(HWND hDlg, UINT message, DWORD wParam, LONG lParam) { - static LPSTR lpszBuffer; // handle of buffer - static int nBufferlen; // length of buffer + static LPTSTR lpszBuffer; // handle of buffer + static int nBufferlen; // length of buffer - char szBuffer[64]; - LONG i; + HWND hWnd; + TCHAR szBuffer[64]; + LONG i; - HWND hWnd = GetDlgItem(hDlg,IDC_NEWVALUE); - switch (message) { case WM_INITDIALOG: - lpszBuffer = (LPSTR) lParam; - nBufferlen = strlen(lpszBuffer)+1; // length with zero string terminator - _ASSERT(sizeof(szBuffer) / sizeof(szBuffer[0]) >= nBufferlen); - SendMessage(hWnd,WM_SETTEXT,0,(LPARAM)lpszBuffer); + lpszBuffer = (LPTSTR) lParam; + // length with zero string terminator + nBufferlen = lstrlen(lpszBuffer)+1; + _ASSERT(ARRAYSIZEOF(szBuffer) >= nBufferlen); + SetDlgItemText(hDlg,IDC_NEWVALUE,lpszBuffer); return TRUE; case WM_COMMAND: + hWnd = GetDlgItem(hDlg,IDC_NEWVALUE); switch(wParam) { case IDOK: SendMessage(hWnd,WM_GETTEXT,(WPARAM)nBufferlen,(LPARAM)szBuffer); // test if valid hex address - for (i = 0; i < (LONG) strlen(szBuffer); ++i) + for (i = 0; i < (LONG) lstrlen(szBuffer); ++i) { - if (isxdigit(szBuffer[i]) == 0) + if (_istxdigit(szBuffer[i]) == 0) { SendMessage(hWnd,EM_SETSEL,0,-1); SetFocus(hWnd); // focus to edit control return FALSE; } } - strcpy(lpszBuffer,szBuffer); // copy valid value + lstrcpy(lpszBuffer,szBuffer); // copy valid value // no break case IDCANCEL: EndDialog(hDlg,wParam); @@ -1513,10 +1795,10 @@ static BOOL CALLBACK NewValue(HWND hDlg, UINT message, DWORD wParam, LONG lParam UNREFERENCED_PARAMETER(wParam); } -static VOID OnNewValue(LPSTR lpszValue) +static VOID OnNewValue(LPTSTR lpszValue) { if (DialogBoxParam(hApp, MAKEINTRESOURCE(IDD_NEWVALUE), hDlgDebug, (DLGPROC)NewValue, (LPARAM)lpszValue) == -1) - AbortMessage("Input Dialog Box Creation Error !"); + AbortMessage(_T("Input Dialog Box Creation Error !")); } @@ -1533,33 +1815,32 @@ static BOOL CALLBACK EnterAddr(HWND hDlg, UINT message, DWORD wParam, LONG lPara { static DWORD *dwAddress; - char szBuffer[8]; + HWND hWnd; + TCHAR szBuffer[8]; LONG i; - - HWND hWnd = GetDlgItem(hDlg,IDC_ENTERADR); switch (message) { case WM_INITDIALOG: dwAddress = (DWORD *) lParam; - SendMessage(hWnd,WM_SETTEXT,0,(LPARAM)""); return TRUE; case WM_COMMAND: + hWnd = GetDlgItem(hDlg,IDC_ENTERADR); switch(wParam) { case IDOK: SendMessage(hWnd,WM_GETTEXT,8,(LPARAM)szBuffer); // test if valid hex address - for (i = 0; i < (LONG) strlen(szBuffer); ++i) + for (i = 0; i < (LONG) lstrlen(szBuffer); ++i) { - if (isxdigit(szBuffer[i]) == 0) + if (_istxdigit(szBuffer[i]) == 0) { SendMessage(hWnd,EM_SETSEL,0,-1); SetFocus(hWnd); // focus to edit control return FALSE; } } - if (*szBuffer) sscanf(szBuffer,"%5X",dwAddress); + if (*szBuffer) _stscanf(szBuffer,_T("%5X"),dwAddress); // no break case IDCANCEL: EndDialog(hDlg,wParam); @@ -1573,7 +1854,7 @@ static BOOL CALLBACK EnterAddr(HWND hDlg, UINT message, DWORD wParam, LONG lPara static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue) { if (DialogBoxParam(hApp, MAKEINTRESOURCE(IDD_ENTERADR), hDlg, (DLGPROC)EnterAddr, (LPARAM)dwValue) == -1) - AbortMessage("Address Dialog Box Creation Error !"); + AbortMessage(_T("Address Dialog Box Creation Error !")); } @@ -1590,39 +1871,40 @@ static BOOL CALLBACK EnterBreakpoint(HWND hDlg, UINT message, DWORD wParam, LONG { static BP_T *sBp; - char szBuffer[8]; + HWND hWnd; + TCHAR szBuffer[8]; LONG i; - HWND hWnd = GetDlgItem(hDlg,IDC_ENTERADR); - switch (message) { case WM_INITDIALOG: sBp = (BP_T *) lParam; - sBp->nType = BP_EXEC; - SendMessage(hWnd,WM_SETTEXT,0,(LPARAM)""); + sBp->bEnable = TRUE; + sBp->nType = BP_EXEC; SendDlgItemMessage(hDlg,IDC_BPCODE,BM_SETCHECK,1,0); return TRUE; case WM_COMMAND: + hWnd = GetDlgItem(hDlg,IDC_ENTERADR); switch(wParam) { case IDC_BPCODE: sBp->nType = BP_EXEC; return TRUE; + case IDC_BPRPL: sBp->nType = BP_RPL; return TRUE; case IDC_BPACCESS: sBp->nType = BP_ACCESS; return TRUE; case IDC_BPREAD: sBp->nType = BP_READ; return TRUE; case IDC_BPWRITE: sBp->nType = BP_WRITE; return TRUE; case IDOK: SendMessage(hWnd,WM_GETTEXT,8,(LPARAM)szBuffer); // test if valid hex address - for (i = 0; i < (LONG) strlen(szBuffer); ++i) + for (i = 0; i < (LONG) lstrlen(szBuffer); ++i) { - if (isxdigit(szBuffer[i]) == 0) + if (_istxdigit(szBuffer[i]) == 0) { SendMessage(hWnd,EM_SETSEL,0,-1); SetFocus(hWnd); return FALSE; } } - if (*szBuffer) sscanf(szBuffer,"%5X",&sBp->dwAddr); + if (*szBuffer) _stscanf(szBuffer,_T("%5X"),&sBp->dwAddr); // no break case IDCANCEL: EndDialog(hDlg,wParam); @@ -1636,7 +1918,7 @@ static BOOL CALLBACK EnterBreakpoint(HWND hDlg, UINT message, DWORD wParam, LONG static VOID OnEnterBreakpoint(HWND hDlg, BP_T *sValue) { if (DialogBoxParam(hApp, MAKEINTRESOURCE(IDD_ENTERBREAK), hDlg, (DLGPROC)EnterBreakpoint, (LPARAM)sValue) == -1) - AbortMessage("Breakpoint Dialog Box Creation Error !"); + AbortMessage(_T("Breakpoint Dialog Box Creation Error !")); } @@ -1646,32 +1928,114 @@ static VOID OnEnterBreakpoint(HWND hDlg, BP_T *sValue) //# //################ +// +// toggle enable/disable breakpoint +// +static BOOL OnToggleCheck(HWND hWnd) +{ + RECT rc; + INT i,nItem; + + if ((nItem = SendMessage(hWnd,LB_GETCURSEL,0,0)) == LB_ERR) + return FALSE; + + // get breakpoint number + i = SendMessage(hWnd,LB_GETITEMDATA,nItem,0); + + sBreakpoint[i].bEnable = !sBreakpoint[i].bEnable; + // update region of toggled item + SendMessage(hWnd,LB_GETITEMRECT,nItem,(LPARAM)&rc); + InvalidateRect(hWnd,&rc,TRUE); + return TRUE; +} + +// +// handle drawing in breakpoint window +// +static __inline BOOL OnDrawBreakWnd(LPDRAWITEMSTRUCT lpdis) +{ + TCHAR szBuf[64]; + COLORREF crBkColor,crTextColor; + HDC hdcMem; + HBITMAP hBmpOld; + INT i; + + if (lpdis->itemID == -1) // no item in list box + return TRUE; + + if (lpdis->itemState & ODS_SELECTED) // cursor line + { + crBkColor = COLOR_NAVY; + crTextColor = COLOR_WHITE; + } + else + { + crBkColor = COLOR_WHITE; + crTextColor = COLOR_BLACK; + } + + // write Text + crBkColor = SetBkColor(lpdis->hDC,crBkColor); + crTextColor = SetTextColor(lpdis->hDC,crTextColor); + + SendMessage(lpdis->hwndItem,LB_GETTEXT,lpdis->itemID,(LONG)(LPTSTR)szBuf); + ExtTextOut(lpdis->hDC,(int)(lpdis->rcItem.left)+17,(int)(lpdis->rcItem.top), + ETO_OPAQUE,(LPRECT)&lpdis->rcItem,szBuf,lstrlen(szBuf),NULL); + + SetBkColor(lpdis->hDC,crBkColor); + SetTextColor(lpdis->hDC,crTextColor); + + // draw checkbox + i = SendMessage(lpdis->hwndItem,LB_GETITEMDATA,lpdis->itemID,0); + hdcMem = CreateCompatibleDC(lpdis->hDC); + _ASSERT(hBmpCheckBox); + hBmpOld = SelectObject(hdcMem,hBmpCheckBox); + + BitBlt(lpdis->hDC,lpdis->rcItem.left+2,lpdis->rcItem.top+2, + 11,lpdis->rcItem.bottom - lpdis->rcItem.top, + hdcMem,sBreakpoint[i].bEnable ? 0 : 10,0,SRCCOPY); + + SelectObject(hdcMem,hBmpOld); + DeleteDC(hdcMem); + + if (lpdis->itemState & ODS_FOCUS) // redraw focus + DrawFocusRect(lpdis->hDC,&lpdis->rcItem); + + return TRUE; // focus handled here +} + // // draw breakpoint type // -static VOID DrawBreakpoint(HWND hWnd, BP_T sBp) +static VOID DrawBreakpoint(HWND hWnd, INT i) { - char *szFmt,szBuffer[32]; + TCHAR *szText,szBuffer[32]; + INT nItem; - switch(sBp.nType) + switch(sBreakpoint[i].nType) { case BP_EXEC: // code breakpoint - szFmt = "%05X (Code)"; + szText = _T("Code"); + break; + case BP_RPL: // RPL breakpoint + szText = _T("RPL"); break; case BP_READ: // read memory breakpoint - szFmt = "%05X (Memory Read)"; + szText = _T("Memory Read"); break; case BP_WRITE: // write memory breakpoint - szFmt = "%05X (Memory Write)"; + szText = _T("Memory Write"); break; case BP_ACCESS: // memory breakpoint - szFmt = "%05X (Memory Access)"; + szText = _T("Memory Access"); break; default: // unknown breakpoint type + szText = _T("unknown"); _ASSERT(0); } - wsprintf(szBuffer,szFmt,sBp.dwAddr); - SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); + wsprintf(szBuffer,_T("%05X (%s)"),sBreakpoint[i].dwAddr,szText); + nItem = SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); + SendMessage(hWnd,LB_SETITEMDATA,nItem,i); return; } @@ -1680,11 +2044,13 @@ static VOID DrawBreakpoint(HWND hWnd, BP_T sBp) // static BOOL CALLBACK EditBreakpoint(HWND hDlg, UINT message, DWORD wParam, LONG lParam) { - char szBuffer[32]; - BP_T sBp; - INT i; + TEXTMETRIC tm; - HWND hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND); + HWND hWnd; + HDC hDC; + HFONT hFont; + BP_T sBp; + INT i,nItem; switch (message) { @@ -1693,15 +2059,31 @@ static BOOL CALLBACK EditBreakpoint(HWND hDlg, UINT message, DWORD wParam, LONG SendDlgItemMessage(hDlg,IDC_STATIC_BREAKPOINT,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); SendDlgItemMessage(hDlg,IDC_BREAKEDIT_ADD, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); SendDlgItemMessage(hDlg,IDC_BREAKEDIT_DELETE, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); - SendDlgItemMessage(hDlg,IDOK, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + SendDlgItemMessage(hDlg,IDCANCEL, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + hBmpCheckBox = LoadBitmap(hApp,MAKEINTRESOURCE(IDB_CHECKBOX)); + _ASSERT(hBmpCheckBox); + + hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND); SendMessage(hWnd,WM_SETREDRAW,FALSE,0); SendMessage(hWnd,LB_RESETCONTENT,0,0); for (i = 0; i < wBreakpointCount; ++i) - DrawBreakpoint(hWnd,sBreakpoint[i]); + DrawBreakpoint(hWnd,i); SendMessage(hWnd,WM_SETREDRAW,TRUE,0); return TRUE; + + case WM_DESTROY: + DeleteObject(hBmpCheckBox); + return TRUE; + case WM_COMMAND: + hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND); + switch (HIWORD(wParam)) + { + case LBN_DBLCLK: + if (LOWORD(wParam) == IDC_BREAKEDIT_WND) return OnToggleCheck(hWnd); + } + switch(wParam) { case IDC_BREAKEDIT_ADD: @@ -1714,20 +2096,23 @@ static BOOL CALLBACK EditBreakpoint(HWND hDlg, UINT message, DWORD wParam, LONG if (sBreakpoint[i].dwAddr == sBp.dwAddr) { // tried to add used code breakpoint - if ((sBreakpoint[i].nType & sBp.nType & BP_EXEC) != 0) + if (sBreakpoint[i].bEnable && (sBreakpoint[i].nType & sBp.nType & (BP_EXEC | BP_RPL)) != 0) return FALSE; // only modify memory breakpoints - if (sBreakpoint[i].nType != BP_EXEC && sBp.nType != BP_EXEC) + if ( ( sBreakpoint[i].bEnable == FALSE + && (sBreakpoint[i].nType & sBp.nType & (BP_EXEC | BP_RPL)) != 0) + || ((sBreakpoint[i].nType & BP_ACCESS) && (sBp.nType & BP_ACCESS))) { // replace breakpoint type - sBreakpoint[i].nType = sBp.nType; + sBreakpoint[i].bEnable = TRUE; + sBreakpoint[i].nType = sBp.nType; // redaw breakpoint list SendMessage(hWnd,WM_SETREDRAW,FALSE,0); SendMessage(hWnd,LB_RESETCONTENT,0,0); for (i = 0; i < wBreakpointCount; ++i) - DrawBreakpoint(hWnd,sBreakpoint[i]); + DrawBreakpoint(hWnd,i); SendMessage(hWnd,WM_SETREDRAW,TRUE,0); return FALSE; } @@ -1737,45 +2122,81 @@ static BOOL CALLBACK EditBreakpoint(HWND hDlg, UINT message, DWORD wParam, LONG // check for breakpoint buffer full if (wBreakpointCount >= MAXBREAKPOINTS) { - AbortMessage("Reached maximum number of breakpoints !"); + AbortMessage(_T("Reached maximum number of breakpoints !")); return FALSE; } - DrawBreakpoint(hWnd,sBp); + sBreakpoint[wBreakpointCount].bEnable = sBp.bEnable; + sBreakpoint[wBreakpointCount].nType = sBp.nType; + sBreakpoint[wBreakpointCount].dwAddr = sBp.dwAddr; + + DrawBreakpoint(hWnd,wBreakpointCount); - sBreakpoint[wBreakpointCount].nType = sBp.nType; - sBreakpoint[wBreakpointCount].dwAddr = sBp.dwAddr; ++wBreakpointCount; } return TRUE; + case IDC_BREAKEDIT_DELETE: - if ((i = SendMessage(hWnd,LB_GETCURSEL,0,0)) == LB_ERR) - return FALSE; - - SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuffer); - SendMessage(hWnd,LB_DELETESTRING,i,0); - - sBp.nType = (szBuffer[7] == 'C') ? BP_EXEC : BP_ACCESS; - sscanf(szBuffer,"%X",&sBp.dwAddr); - for (i = 0; i < wBreakpointCount; ++i) + // scan all breakpoints from top + for (nItem = wBreakpointCount-1; nItem >= 0; --nItem) { - if ( (sBreakpoint[i].nType & sBp.nType) != 0 - && sBreakpoint[i].dwAddr == sBp.dwAddr) + // item selected + if (SendMessage(hWnd,LB_GETSEL,nItem,0) > 0) { - // move rest to top - for (++i; i < wBreakpointCount; ++i) - sBreakpoint[i-1] = sBreakpoint[i]; + INT j; + // get breakpoint index + i = SendMessage(hWnd,LB_GETITEMDATA,nItem,0); + SendMessage(hWnd,LB_DELETESTRING,nItem,0); --wBreakpointCount; - break; + + // update remaining list box references + for (j = 0; j < wBreakpointCount; ++j) + { + INT k = SendMessage(hWnd,LB_GETITEMDATA,j,0); + if (k > i) SendMessage(hWnd,LB_SETITEMDATA,j,k-1); + } + + // remove breakpoint from breakpoint table + for (++i; i <= wBreakpointCount; ++i) + sBreakpoint[i-1] = sBreakpoint[i]; } } return TRUE; - case IDOK: + case IDCANCEL: EndDialog(hDlg,wParam); return TRUE; } + + case WM_VKEYTOITEM: + if(LOWORD(wParam) == VK_SPACE) + { + OnToggleCheck(GetDlgItem(hDlg,IDC_BREAKEDIT_WND)); + return -2; + } + return -1; // default action + + case WM_DRAWITEM: + if (wParam == IDC_BREAKEDIT_WND) return OnDrawBreakWnd((LPDRAWITEMSTRUCT) lParam); + break; + + case WM_MEASUREITEM: + hDC = GetDC(hDlg); + + // GetTextMetrics from "Courier New 8" font + hFont = CreateFont(-MulDiv(8,GetDeviceCaps(hDC, LOGPIXELSY),72),0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET, + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Courier New")); + + hFont = SelectObject(hDC,hFont); + GetTextMetrics(hDC,&tm); + hFont = SelectObject(hDC,hFont); + DeleteObject(hFont); + + ((LPMEASUREITEMSTRUCT) lParam)->itemHeight = tm.tmHeight; + + ReleaseDC(hDlg,hDC); + return TRUE; } return FALSE; UNREFERENCED_PARAMETER(wParam); @@ -1785,9 +2206,10 @@ static BOOL CALLBACK EditBreakpoint(HWND hDlg, UINT message, DWORD wParam, LONG static BOOL OnEditBreakpoint(HWND hDlg) { if (DialogBox(hApp, MAKEINTRESOURCE(IDD_BREAKEDIT), hDlg, (DLGPROC)EditBreakpoint) == -1) - AbortMessage("Edit Breakpoint Dialog Box Creation Error !"); + AbortMessage(_T("Edit Breakpoint Dialog Box Creation Error !")); - UpdateCodeWnd(hDlg); // update code window + // update code window + InvalidateRect(GetDlgItem(hDlg,IDC_DEBUG_CODE),NULL,TRUE); return -1; } @@ -1803,12 +2225,11 @@ static BOOL OnEditBreakpoint(HWND hDlg) // static BOOL CALLBACK InfoIntr(HWND hDlg, UINT message, DWORD wParam, LONG lParam) { - char szBuffer[64]; + HWND hWnd; + TCHAR szBuffer[64]; LONG lIndex; WORD i,j; - HWND hWnd = GetDlgItem(hDlg,IDC_INSTR_CODE); - switch (message) { case WM_INITDIALOG: @@ -1818,11 +2239,13 @@ static BOOL CALLBACK InfoIntr(HWND hDlg, UINT message, DWORD wParam, LONG lParam SendDlgItemMessage(hDlg,IDC_INSTR_COPY, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); SendDlgItemMessage(hDlg,IDCANCEL, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); + lIndex = 0; // init lIndex + hWnd = GetDlgItem(hDlg,IDC_INSTR_CODE); SendMessage(hWnd,WM_SETREDRAW,FALSE,0); SendMessage(hWnd,LB_RESETCONTENT,0,0); for (i = wInstrRp; i != wInstrWp; i = (i + 1) % wInstrSize) { - j = wsprintf(szBuffer,"%05lX ",pdwInstrArray[i]); + j = wsprintf(szBuffer,_T("%05lX "),pdwInstrArray[i]); disassemble(pdwInstrArray[i],&szBuffer[j],VIEW_SHORT); lIndex = SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer); } @@ -1830,6 +2253,7 @@ static BOOL CALLBACK InfoIntr(HWND hDlg, UINT message, DWORD wParam, LONG lParam SendMessage(hWnd,LB_SETCARETINDEX,lIndex,TRUE); return TRUE; case WM_COMMAND: + hWnd = GetDlgItem(hDlg,IDC_INSTR_CODE); switch(wParam) { case IDC_INSTR_COPY: @@ -1852,6 +2276,74 @@ static BOOL CALLBACK InfoIntr(HWND hDlg, UINT message, DWORD wParam, LONG lParam static BOOL OnInfoIntr(HWND hDlg) { if (DialogBox(hApp, MAKEINTRESOURCE(IDD_INSTRUCTIONS), hDlg, (DLGPROC)InfoIntr) == -1) - AbortMessage("Last Instructions Dialog Box Creation Error !"); + AbortMessage(_T("Last Instructions Dialog Box Creation Error !")); return TRUE; } + + +//################ +//# +//# File operations +//# +//################ + +// +// load breakpoint list +// +VOID LoadBreakpointList(HANDLE hFile) // NULL = clear breakpoint list +{ + DWORD lBytesRead = 0; + + // read number of breakpoints + if (hFile) ReadFile(hFile, &wBreakpointCount, sizeof(wBreakpointCount), &lBytesRead, NULL); + if(lBytesRead) // breakpoints found + { + WORD wBreakpointSize; + + // read size of one breakpoint + ReadFile(hFile, &wBreakpointSize, sizeof(wBreakpointSize), &lBytesRead, NULL); + if (lBytesRead == sizeof(wBreakpointSize) && wBreakpointSize == sizeof(sBreakpoint[0])) + { + // read breakpoints + ReadFile(hFile, sBreakpoint, wBreakpointCount * sizeof(sBreakpoint[0]), &lBytesRead, NULL); + _ASSERT(lBytesRead == wBreakpointCount * sizeof(sBreakpoint[0])); + } + else // changed breakpoint structure + { + wBreakpointCount = 0; // clear breakpoint list + } + } + else + { + wBreakpointCount = 0; // clear breakpoint list + } + return; +} + +// +// save breakpoint list +// +VOID SaveBreakpointList(HANDLE hFile) +{ + if (wBreakpointCount) // defined breakpoints + { + DWORD lBytesWritten; + + WORD wBreakpointSize = sizeof(sBreakpoint[0]); + + _ASSERT(hFile); // valid file pointer? + + // write number of breakpoints + WriteFile(hFile, &wBreakpointCount, sizeof(wBreakpointCount), &lBytesWritten, NULL); + _ASSERT(lBytesWritten == sizeof(wBreakpointCount)); + + // write size of one breakpoint + WriteFile(hFile, &wBreakpointSize, sizeof(wBreakpointSize), &lBytesWritten, NULL); + _ASSERT(lBytesWritten == sizeof(wBreakpointSize)); + + // write breakpoints + WriteFile(hFile, sBreakpoint, wBreakpointCount * sizeof(sBreakpoint[0]), &lBytesWritten, NULL); + _ASSERT(lBytesWritten == wBreakpointCount * sizeof(sBreakpoint[0])); + } + return; +} diff --git a/sources/Emu48/DEBUGGER.H b/sources/Emu48/DEBUGGER.H index 5d0e0e9..a38b6c9 100644 --- a/sources/Emu48/DEBUGGER.H +++ b/sources/Emu48/DEBUGGER.H @@ -8,10 +8,11 @@ */ // breakpoint type definitions -#define BP_EXEC 1 // code breakpoint -#define BP_READ 2 // read memory breakpoint -#define BP_WRITE 4 // write memory breakpoint -#define BP_ACCESS (BP_READ|BP_WRITE) // read/write memory breakpoint +#define BP_EXEC 0x01 // code breakpoint +#define BP_READ 0x02 // read memory breakpoint +#define BP_WRITE 0x04 // write memory breakpoint +#define BP_RPL 0x08 // RPL breakpoint +#define BP_ACCESS (BP_READ|BP_WRITE) // read/write memory breakpoint // debugger state definitions #define DBG_RUN 0 @@ -20,19 +21,9 @@ #define DBG_STEPOUT 3 // debugger.c -extern HWND hDlgDebug; -extern HANDLE hEventDebug; -extern BOOL bDbgEnable; -extern INT nDbgState; -extern BOOL bDbgNOP3; -extern BOOL bDbgRPL; -extern BOOL bDbgSkipInt; -extern DWORD dwDbgRstkp; -extern DWORD dwDbgRstk; -extern DWORD *pdwInstrArray; -extern WORD wInstrSize; -extern WORD wInstrWp; -extern WORD wInstrRp; extern BOOL CheckBreakpoint(DWORD dwAddr, DWORD wRange, UINT nType); extern VOID NotifyDebugger(BOOL bType); +extern VOID DisableDebugger(VOID); extern LRESULT OnToolDebug(VOID); +extern VOID LoadBreakpointList(HANDLE hFile); +extern VOID SaveBreakpointList(HANDLE hFile); diff --git a/sources/Emu48/DISASM.C b/sources/Emu48/DISASM.C index a35edea..bb74486 100644 --- a/sources/Emu48/DISASM.C +++ b/sources/Emu48/DISASM.C @@ -15,201 +15,201 @@ BOOL disassembler_mode = HP_MNEMONICS; WORD disassembler_map = MEM_MAP; -static char *hex[] = +static TCHAR *hex[] = { - "0123456789ABCDEF", - "0123456789abcdef", + _T("0123456789ABCDEF"), + _T("0123456789abcdef") }; -static char *opcode_0_tbl[32] = +static TCHAR *opcode_0_tbl[32] = { /* * HP Mnemonics */ - "RTNSXM", "RTN", "RTNSC", "RTNCC", - "SETHEX", "SETDEC", "RSTK=C", "C=RSTK", - "CLRST", "C=ST", "ST=C", "CSTEX", - "P=P+1", "P=P-1", "(NULL)", "RTI", + _T("RTNSXM"), _T("RTN"), _T("RTNSC"), _T("RTNCC"), + _T("SETHEX"), _T("SETDEC"), _T("RSTK=C"), _T("C=RSTK"), + _T("CLRST"), _T("C=ST"), _T("ST=C"), _T("CSTEX"), + _T("P=P+1"), _T("P=P-1"), _T("(NULL)"), _T("RTI"), /* * Class Mnemonics */ - "rtnsxm", "rtn", "rtnsc", "rtncc", - "sethex", "setdec", "push", "pop", - "clr.3 st", "move.3 st, c", "move.3 c, st", "exg.3 c, st", - "inc.1 p", "dec.1 p", "(null)", "rti" + _T("rtnsxm"), _T("rtn"), _T("rtnsc"), _T("rtncc"), + _T("sethex"), _T("setdec"), _T("push"), _T("pop"), + _T("clr.3 st"), _T("move.3 st, c"), _T("move.3 c, st"), _T("exg.3 c, st"), + _T("inc.1 p"), _T("dec.1 p"), _T("(null)"), _T("rti") }; -static char *op_str_0[16] = +static TCHAR *op_str_0[16] = { /* * HP Mnemonics */ - "A=A%cB", "B=B%cC", "C=C%cA", "D=D%cC", - "B=B%cA", "C=C%cB", "A=A%cC", "C=C%cD", + _T("A=A%cB"), _T("B=B%cC"), _T("C=C%cA"), _T("D=D%cC"), + _T("B=B%cA"), _T("C=C%cB"), _T("A=A%cC"), _T("C=C%cD"), /* * Class Mnemonics */ - "b, a", "c, b", "a, c", "c, d", - "a, b", "b, c", "c, a", "d, c" + _T("b, a"), _T("c, b"), _T("a, c"), _T("c, d"), + _T("a, b"), _T("b, c"), _T("c, a"), _T("d, c") }; -static char *op_str_1[16] = +static TCHAR *op_str_1[16] = { /* * HP Mnemonics */ - "DAT0=A", "DAT1=A", "A=DAT0", "A=DAT1", - "DAT0=C", "DAT1=C", "C=DAT0", "C=DAT1", + _T("DAT0=A"), _T("DAT1=A"), _T("A=DAT0"), _T("A=DAT1"), + _T("DAT0=C"), _T("DAT1=C"), _T("C=DAT0"), _T("C=DAT1"), /* * Class Mnemonics */ - "a, (d0)", "a, (d1)", "(d0), a", "(d1), a", - "c, (d0)", "c, (d1)", "(d0), c", "(d1), c" + _T("a, (d0)"), _T("a, (d1)"), _T("(d0), a"), _T("(d1), a"), + _T("c, (d0)"), _T("c, (d1)"), _T("(d0), c"), _T("(d1), c") }; -static char *in_str_80[32] = +static TCHAR *in_str_80[32] = { /* * HP Mnemonics */ - "OUT=CS", "OUT=C", "A=IN", "C=IN", - "UNCNFG", "CONFIG", "C=ID", "SHUTDN", - NULL, "C+P+1", "RESET", "BUSCC", - NULL, NULL, "SREQ?", NULL, + _T("OUT=CS"), _T("OUT=C"), _T("A=IN"), _T("C=IN"), + _T("UNCNFG"), _T("CONFIG"), _T("C=ID"), _T("SHUTDN"), + NULL, _T("C+P+1"), _T("RESET"), _T("BUSCC"), + NULL, NULL, _T("SREQ?"), NULL, /* * Class Mnemonics */ - "move.s c, out", "move.3 c, out", "move.4 in, a", "move.4 in, c", - "uncnfg", "config", "c=id", "shutdn", - NULL, "add.a p+1, c", "reset", "buscc", - NULL, NULL, "sreq?", NULL + _T("move.s c, out"), _T("move.3 c, out"), _T("move.4 in, a"), _T("move.4 in, c"), + _T("uncnfg"), _T("config"), _T("c=id"), _T("shutdn"), + NULL, _T("add.a p+1, c"), _T("reset"), _T("buscc"), + NULL, NULL, _T("sreq?"), NULL }; -static char *in_str_808[32] = +static TCHAR *in_str_808[32] = { /* * HP Mnemonics */ - "INTON", NULL, NULL, "BUSCB", + _T("INTON"), NULL, NULL, _T("BUSCB"), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "PC=(A)", "BUSCD", "PC=(C)", "INTOFF", + _T("PC=(A)"), _T("BUSCD"), _T("PC=(C)"), _T("INTOFF"), /* * Class Mnemonics */ - "inton", NULL, NULL, "buscb", + _T("inton"), NULL, NULL, _T("buscb"), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "jmp (a)", "buscd", "jmp (c)", "intoff" + _T("jmp (a)"), _T("buscd"), _T("jmp (c)"), _T("intoff") }; -static char *op_str_81[8] = +static TCHAR *op_str_81[8] = { /* * HP Mnemonics */ - "A", "B", "C", "D", + _T("A"), _T("B"), _T("C"), _T("D"), /* * Class Mnemonics */ - "a", "b", "c", "d", + _T("a"), _T("b"), _T("c"), _T("d") }; -static char *in_str_81b[32] = +static TCHAR *in_str_81b[32] = { /* * HP Mnemonics */ - NULL, NULL, "PC=A", "PC=C", - "A=PC", "C=PC", "APCEX", "CPCEX", + NULL, NULL, _T("PC=A"), _T("PC=C"), + _T("A=PC"), _T("C=PC"), _T("APCEX"), _T("CPCEX"), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* * Class Mnemonics */ - NULL, NULL, "jmp a", "jmp c", - "move.a pc, a", "move.a pc, c", "exg.a a, pc", "exg.a c, pc", - NULL, NULL, NULL, NULL, + NULL, NULL, _T("jmp a"), _T("jmp c"), + _T("move.a pc, a"), _T("move.a pc, c"), _T("exg.a a, pc"), _T("exg.a c, pc"), NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; -static char *in_str_9[16] = +static TCHAR *in_str_9[16] = { /* * HP Mnemonics */ - "=", "#", "=", "#", - ">", "<", ">=", "<=", + _T("="), _T("#"), _T("="), _T("#"), + _T(">"), _T("<"), _T(">="), _T("<="), /* * Class Mnemonics */ - "eq", "ne", "eq", "ne", - "gt", "lt", "ge", "le" + _T("eq"), _T("ne"), _T("eq"), _T("ne"), + _T("gt"), _T("lt"), _T("ge"), _T("le") }; -static char *op_str_9[16] = +static TCHAR *op_str_9[16] = { /* * HP Mnemonics */ - "?A%sB", "?B%sC", "?C%sA", "?D%sC", - "?A%s0", "?B%s0", "?C%s0", "?D%s0", + _T("?A%sB"), _T("?B%sC"), _T("?C%sA"), _T("?D%sC"), + _T("?A%s0"), _T("?B%s0"), _T("?C%s0"), _T("?D%s0"), /* * Class Mnemonics */ - "a, b", "b, c", "c, a", "d, c", - "a, 0", "b, 0", "c, 0", "d, 0" + _T("a, b"), _T("b, c"), _T("c, a"), _T("d, c"), + _T("a, 0"), _T("b, 0"), _T("c, 0"), _T("d, 0") }; -static char *op_str_af[32] = +static TCHAR *op_str_af[32] = { /* * HP Mnemonics */ - "A=A%sB", "B=B%sC", "C=C%sA", "D=D%sC", - "A=A%sA", "B=B%sB", "C=C%sC", "D=D%sD", - "B=B%sA", "C=C%sB", "A=A%sC", "C=C%sD", - "A=B%sA", "B=C%sB", "C=A%sC", "D=C%sD", + _T("A=A%sB"), _T("B=B%sC"), _T("C=C%sA"), _T("D=D%sC"), + _T("A=A%sA"), _T("B=B%sB"), _T("C=C%sC"), _T("D=D%sD"), + _T("B=B%sA"), _T("C=C%sB"), _T("A=A%sC"), _T("C=C%sD"), + _T("A=B%sA"), _T("B=C%sB"), _T("C=A%sC"), _T("D=C%sD"), /* * Class Mnemonics */ - "b, a", "c, b", "a, c", "c, d", - "a, a", "b, b", "c, c", "d, d", - "a, b", "b, c", "c, a", "d, c", - "b, a", "c, b", "a, c", "c, d" + _T("b, a"), _T("c, b"), _T("a, c"), _T("c, d"), + _T("a, a"), _T("b, b"), _T("c, c"), _T("d, d"), + _T("a, b"), _T("b, c"), _T("c, a"), _T("d, c"), + _T("b, a"), _T("c, b"), _T("a, c"), _T("c, d") }; -static char hp_reg_1_af[] = "ABCDABCDBCACABAC"; -static char hp_reg_2_af[] = "0000BCACABCDBCCD"; +static TCHAR hp_reg_1_af[] = _T("ABCDABCDBCACABAC"); +static TCHAR hp_reg_2_af[] = _T("0000BCACABCDBCCD"); -static char *field_tbl[32] = +static TCHAR *field_tbl[32] = { /* * HP Mnemonics */ - "P", "WP", "XS", "X", - "S", "M", "B", "W", - "P", "WP", "XS", "X", - "S", "M", "B", "A", + _T("P"), _T("WP"), _T("XS"), _T("X"), + _T("S"), _T("M"), _T("B"), _T("W"), + _T("P"), _T("WP"), _T("XS"), _T("X"), + _T("S"), _T("M"), _T("B"), _T("A"), /* * Class Mnemonics */ - ".p", ".wp", ".xs", ".x", - ".s", ".m", ".b", ".w", - ".p", ".wp", ".xs", ".x", - ".s", ".m", ".b", ".a", + _T(".p"), _T(".wp"), _T(".xs"), _T(".x"), + _T(".s"), _T(".m"), _T(".b"), _T(".w"), + _T(".p"), _T(".wp"), _T(".xs"), _T(".x"), + _T(".s"), _T(".m"), _T(".b"), _T(".a") }; -static char *hst_bits[8] = +static TCHAR *hst_bits[8] = { /* * HP Mnemonics */ - "XM", "SB", "SR", "MP", + _T("XM"), _T("SB"), _T("SR"), _T("MP"), /* * Class Mnemonics */ - "xm", "sb", "sr", "mp", + _T("xm"), _T("sb"), _T("sr"), _T("mp"), }; @@ -217,12 +217,11 @@ static char *hst_bits[8] = static BYTE rn_map (DWORD *p) { - DWORD d = *p; + BYTE byVal; + Npeek(&byVal, *p, 1); *p = ++(*p) & 0xFFFFF; - - _ASSERT(d < 0x100000); - return *(RMap[d>>12]+(d&0xFFF)); + return byVal; } static BYTE rn_rom (DWORD *p) @@ -260,7 +259,7 @@ static BYTE rn_port2 (DWORD *p) BYTE *pbyVal; DWORD d = *p; - if (cCurrentRomType=='X') // HP49G + if (Chipset.Port2Size) // HP39/40G, HP49G { *p = ++(*p) & (Chipset.Port2Size * 2048 - 1); @@ -281,7 +280,7 @@ static BYTE read_nibble (DWORD *p) { BYTE (*pnread[])(DWORD *) = { rn_map, rn_rom, rn_ram, rn_port1, rn_port2 }; - _ASSERT(disassembler_map < sizeof(pnread) / sizeof(pnread[0])); + _ASSERT(disassembler_map < ARRAYSIZEOF(pnread)); return pnread[disassembler_map](p); } @@ -297,47 +296,47 @@ static int read_int (DWORD *addr, int n) return t; } -static char *append_str (char *buf, char *str) +static TCHAR *append_str (TCHAR *buf, TCHAR *str) { while ((*buf = *str++)) buf++; return buf; } -static char *append_tab (char *buf) +static TCHAR *append_tab (TCHAR *buf) { int n; - char *p; + TCHAR *p; - n = TAB_SKIP - (strlen (buf) % TAB_SKIP); - p = &buf[strlen (buf)]; + n = TAB_SKIP - (lstrlen (buf) % TAB_SKIP); + p = &buf[lstrlen (buf)]; while (n--) - *p++ = ' '; + *p++ = _T(' '); *p = 0; return p; } -static char *append_field (char *buf, BYTE fn) +static TCHAR *append_field (TCHAR *buf, BYTE fn) { buf = append_str (buf, field_tbl[fn + 16 * disassembler_mode]); return buf; } -static char *append_imm_nibble (char *buf, DWORD *addr, int n) +static TCHAR *append_imm_nibble (TCHAR *buf, DWORD *addr, int n) { int i; - char t[16]; + TCHAR t[16]; if (disassembler_mode == CLASS_MNEMONICS) { - *buf++ = '#'; + *buf++ = _T('#'); if (n > 1) - *buf++ = '$'; + *buf++ = _T('$'); } else // HP Mnemonics { if (n > 1) // hex mode - *buf++ = '#'; // insert hex header + *buf++ = _T('#'); // insert hex header } if (n > 1) { @@ -351,20 +350,20 @@ static char *append_imm_nibble (char *buf, DWORD *addr, int n) } else { - wsprintf (t, "%d", read_nibble (addr)); + wsprintf (t, _T("%d"), read_nibble (addr)); buf = append_str (buf, t); } return buf; } -static char *append_addr (char *buf, DWORD addr) +static TCHAR *append_addr (TCHAR *buf, DWORD addr) { int shift; long mask; if (disassembler_mode == CLASS_MNEMONICS) { - *buf++ = '$'; + *buf++ = _T('$'); } for (mask = 0xf0000, shift = 16; mask != 0; mask >>= 4, shift -= 4) *buf++ = hex[disassembler_mode][(addr & mask) >> shift]; @@ -372,7 +371,7 @@ static char *append_addr (char *buf, DWORD addr) return buf; } -static char *append_r_addr (char *buf, DWORD * pc, long disp, int n, int offset) +static TCHAR *append_r_addr (TCHAR *buf, DWORD * pc, long disp, int n, int offset) { long sign; @@ -386,12 +385,12 @@ static char *append_r_addr (char *buf, DWORD * pc, long disp, int n, int offset) case HP_MNEMONICS: if (disp < 0) { - buf = append_str(buf, "-"); + buf = append_str(buf, _T("-")); disp = -disp - offset; } else { - buf = append_str(buf, "+"); + buf = append_str(buf, _T("+")); disp += offset; } buf = append_addr(buf, disp); @@ -399,61 +398,61 @@ static char *append_r_addr (char *buf, DWORD * pc, long disp, int n, int offset) case CLASS_MNEMONICS: if (disp < 0) { - buf = append_str(buf, "-"); + buf = append_str(buf, _T("-")); disp = -disp - offset; } else { - buf = append_str(buf, "+"); + buf = append_str(buf, _T("+")); disp += offset; } - buf = append_addr (buf, disp); + buf = append_addr(buf, disp); break; default: - buf = append_str (buf, "Unknown disassembler mode"); + buf = append_str (buf, _T("Unknown disassembler mode")); break; } return buf; } -static char *append_pc_comment (char *buf, DWORD pc, BOOL view) +static TCHAR *append_pc_comment (TCHAR *buf, DWORD pc, BOOL view) { - char *p = buf; + TCHAR *p = buf; if (view == VIEW_LONG) // output of address in remarks { - while (strlen (buf) < 4 * TAB_SKIP) + while (lstrlen (buf) < 4 * TAB_SKIP) p = append_tab (buf); switch (disassembler_mode) { case HP_MNEMONICS: - p = append_str (p, "# Address: "); + p = append_str (p, _T("# Address: ")); p = append_addr (p, pc); break; case CLASS_MNEMONICS: - p = append_str (p, "; address: "); + p = append_str (p, _T("; address: ")); p = append_addr (p, pc); break; default: - p = append_str (p, "Unknown disassembler mode"); + p = append_str (p, _T("Unknown disassembler mode")); break; } } else // output of address in brackets { while (*p) ++p; - p = append_str (p, " ["); + p = append_str (p, _T(" [")); p = append_addr (p, pc); - p = append_str (p, "]"); + p = append_str (p, _T("]")); } return p; } -static char *append_hst_bits (char *buf, int n) +static TCHAR *append_hst_bits (TCHAR *buf, int n) { int i; - char *p = buf; + TCHAR *p = buf; switch (disassembler_mode) { @@ -464,38 +463,34 @@ static char *append_hst_bits (char *buf, int n) p = append_str (p, hst_bits[i + 4 * disassembler_mode]); } break; - case CLASS_MNEMONICS: - while (strlen (buf) < 4 * TAB_SKIP) + while (lstrlen (buf) < 4 * TAB_SKIP) p = append_tab (buf); - p = &buf[strlen (buf)]; - p = append_str (p, "; hst bits: "); + p = &buf[lstrlen (buf)]; + p = append_str (p, _T("; hst bits: ")); for (buf = p, i = 0; i < 4; i++) if (n & (1 << i)) { if (p != buf) - p = append_str (p, ", "); + p = append_str (p, _T(", ")); p = append_str (p, hst_bits[i + 4 * disassembler_mode]); } break; - default: - p = append_str (p, "Unknown disassembler mode"); + p = append_str (p, _T("Unknown disassembler mode")); break; } - return p; } - -static char *disasm_1 (DWORD *addr, char *out) +static TCHAR *disasm_1 (DWORD *addr, TCHAR *out) { BYTE n; BYTE fn; - char *p; - char buf[20]; - char c; + TCHAR *p; + TCHAR buf[20]; + TCHAR c; p = out; switch (n = read_nibble (addr)) @@ -510,25 +505,25 @@ static char *disasm_1 (DWORD *addr, char *out) switch (disassembler_mode) { case HP_MNEMONICS: - c = (char) (c ? 'A' : 'C'); + c = (TCHAR) (c ? _T('A') : _T('C')); if (n == 0) - wsprintf (buf, "R%d=%c", fn, c); + wsprintf (buf, _T("R%d=%c"), fn, c); else - wsprintf (buf, "%c=R%d", c, fn); + wsprintf (buf, _T("%c=R%d"), c, fn); p = append_str (out, buf); break; case CLASS_MNEMONICS: - p = append_str (out, "move.w"); + p = append_str (out, _T("move.w")); p = append_tab (out); - c = (char) (c ? 'a' : 'c'); + c = (TCHAR) (c ? _T('a') : _T('c')); if (n == 0) - wsprintf (buf, "%c, r%d", c, fn); + wsprintf (buf, _T("%c, r%d"), c, fn); else - wsprintf (buf, "r%d, %c", fn, c); + wsprintf (buf, _T("r%d, %c"), fn, c); p = append_str (p, buf); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -542,19 +537,19 @@ static char *disasm_1 (DWORD *addr, char *out) switch (disassembler_mode) { case HP_MNEMONICS: - c = (char) (c ? 'A' : 'C'); - wsprintf (buf, "%cR%dEX", c, fn); + c = (TCHAR) (c ? _T('A') : _T('C')); + wsprintf (buf, _T("%cR%dEX"), c, fn); p = append_str (out, buf); break; case CLASS_MNEMONICS: - p = append_str (out, "exg.w"); + p = append_str (out, _T("exg.w")); p = append_tab (out); - c = (char) (c ? 'a' : 'c'); - wsprintf (buf, "%c, r%d", c, fn); + c = (TCHAR) (c ? _T('a') : _T('c')); + wsprintf (buf, _T("%c, r%d"), c, fn); p = append_str (p, buf); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -564,41 +559,41 @@ static char *disasm_1 (DWORD *addr, char *out) switch (disassembler_mode) { case HP_MNEMONICS: - c = (n & 4) ? 'C' : 'A'; + c = (n & 4) ? _T('C') : _T('A'); if (n & 2) { if (n < 8) { - wsprintf (buf, "%cD%dEX", c, (n & 1)); + wsprintf (buf, _T("%cD%dEX"), c, (n & 1)); } else { - wsprintf (buf, "%cD%dXS", c, (n & 1)); + wsprintf (buf, _T("%cD%dXS"), c, (n & 1)); } } else { if (n < 8) { - wsprintf (buf, "D%d=%c", (n & 1), c); + wsprintf (buf, _T("D%d=%c"), (n & 1), c); } else { - wsprintf (buf, "D%d=%cS", (n & 1), c); + wsprintf (buf, _T("D%d=%cS"), (n & 1), c); } } p = append_str (out, buf); break; case CLASS_MNEMONICS: - p = append_str (out, (n & 2) ? "exg." : "move."); - p = append_str (p, (n < 8) ? "a" : "4"); + p = append_str (out, (n & 2) ? _T("exg.") : _T("move.")); + p = append_str (p, (n < 8) ? _T("a") : _T("4")); p = append_tab (out); - c = (n & 4) ? 'c' : 'a'; - wsprintf (buf, "%c, d%d", c, (n & 1)); + c = (n & 4) ? _T('c') : _T('a'); + wsprintf (buf, _T("%c, d%d"), c, (n & 1)); p = append_str (p, buf); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -613,7 +608,7 @@ static char *disasm_1 (DWORD *addr, char *out) p = append_tab (out); if (n == 4) { - p = append_str (p, (fn < 8) ? "A" : "B"); + p = append_str (p, (fn < 8) ? _T("A") : _T("B")); } else { @@ -624,17 +619,17 @@ static char *disasm_1 (DWORD *addr, char *out) } else { - wsprintf (buf, "%d", n + 1); + wsprintf (buf, _T("%d"), n + 1); p = append_str (p, buf); } } break; case CLASS_MNEMONICS: - p = append_str (out, "move"); + p = append_str (out, _T("move")); if (n == 4) { - p = append_str (p, "."); - p = append_str (p, (fn < 8) ? "a" : "b"); + p = append_str (p, _T(".")); + p = append_str (p, (fn < 8) ? _T("a") : _T("b")); } else { @@ -645,7 +640,7 @@ static char *disasm_1 (DWORD *addr, char *out) } else { - wsprintf (buf, ".%d", n + 1); + wsprintf (buf, _T(".%d"), n + 1); p = append_str (p, buf); } } @@ -653,7 +648,7 @@ static char *disasm_1 (DWORD *addr, char *out) p = append_str (p, op_str_1[(fn & 7) + 8 * disassembler_mode]); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -667,32 +662,32 @@ static char *disasm_1 (DWORD *addr, char *out) { case HP_MNEMONICS: if (n == 6 || n == 8) - p = append_str (out, "D0=D0"); + p = append_str (out, _T("D0=D0")); else - p = append_str (out, "D1=D1"); + p = append_str (out, _T("D1=D1")); if (n < 8) - p = append_str (p, "+"); + p = append_str (p, _T("+")); else - p = append_str (p, "-"); + p = append_str (p, _T("-")); p = append_tab (out); - wsprintf (buf, "%d", fn + 1); + wsprintf (buf, _T("%d"), fn + 1); p = append_str (p, buf); break; case CLASS_MNEMONICS: if (n < 8) - p = append_str (out, "add.a"); + p = append_str (out, _T("add.a")); else - p = append_str (out, "sub.a"); + p = append_str (out, _T("sub.a")); p = append_tab (out); - wsprintf (buf, "#%d, ", fn + 1); + wsprintf (buf, _T("#%d, "), fn + 1); p = append_str (p, buf); if (n == 6 || n == 8) - p = append_str (p, "d0"); + p = append_str (p, _T("d0")); else - p = append_str (p, "d1"); + p = append_str (p, _T("d1")); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -703,7 +698,7 @@ static char *disasm_1 (DWORD *addr, char *out) case 0xd: case 0xe: case 0xf: - c = (char) ((n < 0xd) ? '0' : '1'); + c = (TCHAR) ((n < 0xd) ? _T('0') : _T('1')); switch (n & 3) { case 1: @@ -719,7 +714,7 @@ static char *disasm_1 (DWORD *addr, char *out) switch (disassembler_mode) { case HP_MNEMONICS: - wsprintf (buf, "D%c=(%d)", c, n); + wsprintf (buf, _T("D%c=(%d)"), c, n); p = append_str (out, buf); p = append_tab (out); p = append_imm_nibble (p, addr, n); @@ -727,25 +722,25 @@ static char *disasm_1 (DWORD *addr, char *out) case CLASS_MNEMONICS: if (n == 5) { - wsprintf (buf, "move.a"); + wsprintf (buf, _T("move.a")); } else if (n == 4) { - wsprintf (buf, "move.as"); + wsprintf (buf, _T("move.as")); } else { - wsprintf (buf, "move.b"); + wsprintf (buf, _T("move.b")); } p = append_str (out, buf); p = append_tab (out); p = append_imm_nibble (p, addr, n); - wsprintf (buf, ", d%c", c); + wsprintf (buf, _T(", d%c"), c); p = append_str (p, buf); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -756,13 +751,13 @@ static char *disasm_1 (DWORD *addr, char *out) return p; } -static char *disasm_8 (DWORD *addr, char *out, BOOL view) +static TCHAR *disasm_8 (DWORD *addr, TCHAR *out, BOOL view) { BYTE n; BYTE fn; - char *p = out; - char c; - char buf[20]; + TCHAR *p = out; + TCHAR c; + TCHAR buf[20]; DWORD disp, pc; fn = read_nibble (addr); @@ -793,16 +788,18 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - p = append_str (out, "RSI"); + p = append_str (out, _T("RSI")); break; case CLASS_MNEMONICS: - p = append_str (out, "rsi"); + p = append_str (out, _T("rsi")); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } } + else + p = out; // illegal opcode, no output break; case 2: n = read_nibble (addr); @@ -811,26 +808,26 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) case HP_MNEMONICS: if (n < 5) { - wsprintf (buf, "LA(%d)", n + 1); + wsprintf (buf, _T("LA(%d)"), n + 1); } else { - wsprintf (buf, "LAHEX"); + wsprintf (buf, _T("LAHEX")); } p = append_str (out, buf); p = append_tab (out); p = append_imm_nibble (p, addr, n + 1); break; case CLASS_MNEMONICS: - wsprintf (buf, "move.%d", n + 1); + wsprintf (buf, _T("move.%d"), n + 1); p = append_str (out, buf); p = append_tab (out); p = append_imm_nibble (p, addr, n + 1); - wsprintf (buf, ", a.p"); + wsprintf (buf, _T(", a.p")); p = append_str (p, buf); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -842,20 +839,20 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - wsprintf (buf, "%cBIT=%d", (fn & 8) ? 'C' : 'A', + wsprintf (buf, _T("%cBIT=%d"), (fn & 8) ? _T('C') : _T('A'), (fn & 1) ? 1 : 0); p = append_str (out, buf); p = append_tab (out); p = append_imm_nibble (p, addr, 1); break; case CLASS_MNEMONICS: - p = append_str (out, (fn & 1) ? "bset" : "bclr"); + p = append_str (out, (fn & 1) ? _T("bset") : _T("bclr")); p = append_tab (out); p = append_imm_nibble (p, addr, 1); - p = append_str (p, (fn & 8) ? ", c" : ", a"); + p = append_str (p, (fn & 8) ? _T(", c") : _T(", a")); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -871,37 +868,37 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - c = (char) ((fn < 0xa) ? 'A' : 'C'); - wsprintf (buf, "?%cBIT=%d", c, (fn & 1) ? 1 : 0); + c = (TCHAR) ((fn < 0xa) ? _T('A') : _T('C')); + wsprintf (buf, _T("?%cBIT=%d"), c, (fn & 1) ? 1 : 0); p = append_str (out, buf); p = append_tab (out); - wsprintf (buf, "%d", n); + wsprintf (buf, _T("%d"), n); p = append_str (p, buf); if (disp != 0) { - p = append_str (p, ", GOYES "); + p = append_str (p, _T(", GOYES ")); p = append_r_addr (p, &pc, disp, 2, 5); p = append_pc_comment (out, pc, view); } else - p = append_str (p, ", RTNYES"); + p = append_str (p, _T(", RTNYES")); break; case CLASS_MNEMONICS: - c = (char) ((fn < 0xa) ? 'a' : 'c'); - p = append_str (out, (disp == 0) ? "rt" : "b"); - p = append_str (p, (fn & 1) ? "bs" : "bc"); + c = (TCHAR) ((fn < 0xa) ? _T('a') : _T('c')); + p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); + p = append_str (p, (fn & 1) ? _T("bs") : _T("bc")); p = append_tab (out); - wsprintf (buf, "#%d, %c", n, c); + wsprintf (buf, _T("#%d, %c"), n, c); p = append_str (p, buf); if (disp != 0) { - p = append_str (p, ", "); + p = append_str (p, _T(", ")); p = append_r_addr (p, &pc, disp, 2, 5); p = append_pc_comment (out, pc, view); } break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -918,21 +915,21 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - wsprintf (buf, (n == 0xf) ? "%c%cEX" : "%c=%c", - (n == 0xd) ? 'P' : 'C', (n == 0xd) ? 'C' : 'P'); + wsprintf (buf, (n == 0xf) ? _T("%c%cEX") : _T("%c=%c"), + (n == 0xd) ? _T('P') : _T('C'), (n == 0xd) ? _T('C') : _T('P')); p = append_str (out, buf); p = append_tab (out); - wsprintf (buf, "%d", fn); + wsprintf (buf, _T("%d"), fn); p = append_str (p, buf); break; case CLASS_MNEMONICS: - p = append_str (out, (n == 0xf) ? "exg.1" : "move.1"); + p = append_str (out, (n == 0xf) ? _T("exg.1") : _T("move.1")); p = append_tab (out); - wsprintf (buf, (n == 0xd) ? "p, c.%d" : "c.%d, p", fn); + wsprintf (buf, (n == 0xd) ? _T("p, c.%d") : _T("c.%d, p"), fn); p = append_str (p, buf); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -952,17 +949,17 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - wsprintf (buf, "%sSLC", op_str_81[(n & 3) + 4 * disassembler_mode]); + wsprintf (buf, _T("%sSLC"), op_str_81[(n & 3) + 4 * disassembler_mode]); p = append_str (out, buf); break; case CLASS_MNEMONICS: - p = append_str (out, "rol.w"); + p = append_str (out, _T("rol.w")); p = append_tab (out); - p = append_str (p, "#4, "); + p = append_str (p, _T("#4, ")); p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -974,49 +971,51 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - wsprintf (buf, "%sSRC", op_str_81[(n & 3) + 4 * disassembler_mode]); + wsprintf (buf, _T("%sSRC"), op_str_81[(n & 3) + 4 * disassembler_mode]); p = append_str (out, buf); break; case CLASS_MNEMONICS: - p = append_str (out, "ror.w"); + p = append_str (out, _T("ror.w")); p = append_tab (out); - p = append_str (p, "#4, "); + p = append_str (p, _T("#4, ")); p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; case 8: - fn = read_nibble (addr); - n = read_nibble (addr); + fn = read_nibble (addr); // get number + n = read_nibble (addr); // get register selector + if ((n & 7) > 3) // illegal opcode + break; // no output switch (disassembler_mode) { case HP_MNEMONICS: - wsprintf (buf, "%s=%s%cCON", + wsprintf (buf, _T("%s=%s%cCON"), op_str_81[(n & 3) + 4 * disassembler_mode], op_str_81[(n & 3) + 4 * disassembler_mode], - (n < 8) ? '+' : '-'); + (n < 8) ? _T('+') : _T('-')); p = append_str (out, buf); p = append_tab (out); p = append_field (p, fn); fn = read_nibble (addr); - wsprintf (buf, ", %d", fn + 1); + wsprintf (buf, _T(", %d"), fn + 1); p = append_str (p, buf); break; case CLASS_MNEMONICS: - p = append_str (out, (n < 8) ? "add" : "sub"); + p = append_str (out, (n < 8) ? _T("add") : _T("sub")); p = append_field (p, fn); p = append_tab (out); fn = read_nibble (addr); - wsprintf (buf, "#%d, ", fn + 1); + wsprintf (buf, _T("#%d, "), fn + 1); p = append_str (p, buf); p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1024,24 +1023,25 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) case 9: fn = read_nibble (addr); // get field selector n = read_nibble (addr); // get register selector + if (n > 3) // illegal opcode + break; // no output switch (disassembler_mode) { case HP_MNEMONICS: - wsprintf (buf, "%sSRB.F", - op_str_81[(n & 3) + 4 * disassembler_mode]); + wsprintf (buf, _T("%sSRB.F"), op_str_81[n + 4 * disassembler_mode]); p = append_str (out, buf); p = append_tab (out); p = append_field (p, fn); break; case CLASS_MNEMONICS: - p = append_str (out, "lsr"); + p = append_str (out, _T("lsr")); p = append_field (p, fn); p = append_tab (out); - p = append_str (p, "#1, "); - p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); + p = append_str (p, _T("#1, ")); + p = append_str (p, op_str_81[n + 4 * disassembler_mode]); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1049,64 +1049,64 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) case 0xa: fn = read_nibble (addr); n = read_nibble (addr); - if (n > 2) - break; - c = (char) read_nibble (addr); - if (((int) c & 7) > 4) - break; + if (n > 2) // illegal opcode + break; // no output + c = (TCHAR) read_nibble (addr); + if (((int) c & 7) > 4) // illegal opcode + break; // no output switch (disassembler_mode) { case HP_MNEMONICS: if (n == 2) { - wsprintf (buf, "%cR%dEX.F", ((int) c < 8) ? 'A' : 'C', + wsprintf (buf, _T("%cR%dEX.F"), ((int) c < 8) ? _T('A') : _T('C'), (int) c & 7); } else if (n == 1) { - wsprintf (buf, "%c=R%d.F", ((int) c < 8) ? 'A' : 'C', + wsprintf (buf, _T("%c=R%d.F"), ((int) c < 8) ? _T('A') : _T('C'), (int) c & 7); } else { - wsprintf (buf, "R%d=%c.F", (int) c & 7, - ((int) c < 8) ? 'A' : 'C'); + wsprintf (buf, _T("R%d=%c.F"), (int) c & 7, + ((int) c < 8) ? _T('A') : _T('C')); } p = append_str (out, buf); p = append_tab (out); p = append_field (p, fn); break; case CLASS_MNEMONICS: - p = append_str (out, (n == 2) ? "exg" : "move"); + p = append_str (out, (n == 2) ? _T("exg") : _T("move")); p = append_field (p, fn); p = append_tab (out); if (n == 1) { - wsprintf (buf, "r%d", (int) c & 7); + wsprintf (buf, _T("r%d"), (int) c & 7); p = append_str (p, buf); } else - p = append_str (p, ((int) c < 8) ? "a" : "c"); - p = append_str (p, ", "); + p = append_str (p, ((int) c < 8) ? _T("a") : _T("c")); + p = append_str (p, _T(", ")); if (n == 1) - p = append_str (p, ((int) c < 8) ? "a" : "c"); + p = append_str (p, ((int) c < 8) ? _T("a") : _T("c")); else { - wsprintf (buf, "r%d", (int) c & 7); + wsprintf (buf, _T("r%d"), (int) c & 7); p = append_str (p, buf); } break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; case 0xb: n = read_nibble (addr); - if ((n < 2) || (n > 7)) - break; + if ((n < 2) || (n > 7)) // illegal opcode + break; // no output p = append_str (out, in_str_81b[n + 16 * disassembler_mode]); break; @@ -1118,17 +1118,17 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - wsprintf (buf, "%sSRB", op_str_81[(n & 3) + 4 * disassembler_mode]); + wsprintf (buf, _T("%sSRB"), op_str_81[(n & 3) + 4 * disassembler_mode]); p = append_str (out, buf); break; case CLASS_MNEMONICS: - p = append_str (out, "lsr.w"); + p = append_str (out, _T("lsr.w")); p = append_tab (out); - p = append_str (p, "#1, "); + p = append_str (p, _T("#1, ")); p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1145,34 +1145,34 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) case HP_MNEMONICS: if (n == 0xf) { - p = append_str (out, "CLRHST"); + p = append_str (out, _T("CLRHST")); } else { // when not only one bit is set the HS=0 opcode is used if (n != 1 && n != 2 && n != 4 && n != 8) { - p = append_str (out, "HS=0"); + p = append_str (out, _T("HS=0")); p = append_tab (out); - wsprintf (buf, "%d", n); + wsprintf (buf, _T("%d"), n); p = append_str (p, buf); } else { p = append_hst_bits (out, n); - p = append_str (p, "=0"); + p = append_str (p, _T("=0")); } } break; case CLASS_MNEMONICS: - p = append_str (out, "clr.1"); + p = append_str (out, _T("clr.1")); p = append_tab (out); - wsprintf (buf, "#%d, hst", n); + wsprintf (buf, _T("#%d, hst"), n); p = append_str (p, buf); p = append_hst_bits (out, n); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1184,35 +1184,35 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - p = append_str (out, "?"); + p = append_str (out, _T("?")); p = append_hst_bits (p, n); - p = append_str (p, "=0"); + p = append_str (p, _T("=0")); p = append_tab (out); if (disp != 0) { - p = append_str (p, "GOYES "); + p = append_str (p, _T("GOYES ")); p = append_r_addr (p, &pc, disp, 2, 3); p = append_pc_comment (out, pc, view); } else - p = append_str (p, "RTNYES"); + p = append_str (p, _T("RTNYES")); break; case CLASS_MNEMONICS: - p = append_str (out, (disp == 0) ? "rt" : "b"); - p = append_str (p, "eq.1"); + p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); + p = append_str (p, _T("eq.1")); p = append_tab (out); - wsprintf (buf, "#%d, hst", n); + wsprintf (buf, _T("#%d, hst"), n); p = append_str (p, buf); if (disp != 0) { - p = append_str (p, ", "); + p = append_str (p, _T(", ")); p = append_r_addr (p, &pc, disp, 2, 3); p = append_pc_comment (out, pc, view); } p = append_hst_bits (out, n); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1222,19 +1222,19 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - wsprintf (buf, "ST=%d", (fn == 4) ? 0 : 1); + wsprintf (buf, _T("ST=%d"), (fn == 4) ? 0 : 1); p = append_str (out, buf); p = append_tab (out); p = append_imm_nibble (p, addr, 1); break; case CLASS_MNEMONICS: - p = append_str (out, (fn == 4) ? "bclr" : "bset"); + p = append_str (out, (fn == 4) ? _T("bclr") : _T("bset")); p = append_tab (out); p = append_imm_nibble (p, addr, 1); - p = append_str (p, ", st"); + p = append_str (p, _T(", st")); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1247,35 +1247,35 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - wsprintf (buf, "?ST=%d", (fn == 6) ? 0 : 1); + wsprintf (buf, _T("?ST=%d"), (fn == 6) ? 0 : 1); p = append_str (out, buf); p = append_tab (out); - wsprintf (buf, "%d", n); + wsprintf (buf, _T("%d"), n); p = append_str (p, buf); if (disp != 0) { - p = append_str (p, ", GOYES "); + p = append_str (p, _T(", GOYES ")); p = append_r_addr (p, &pc, disp, 2, 3); p = append_pc_comment (out, pc, view); } else - p = append_str (p, ", RTNYES"); + p = append_str (p, _T(", RTNYES")); break; case CLASS_MNEMONICS: - p = append_str (out, (disp == 0) ? "rt" : "b"); - p = append_str (p, (fn == 6) ? "bc" : "bs"); + p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); + p = append_str (p, (fn == 6) ? _T("bc") : _T("bs")); p = append_tab (out); - wsprintf (buf, "#%d, st", n); + wsprintf (buf, _T("#%d, st"), n); p = append_str (p, buf); if (disp != 0) { - p = append_str (p, ", "); + p = append_str (p, _T(", ")); p = append_r_addr (p, &pc, disp, 2, 3); p = append_pc_comment (out, pc, view); } break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1288,35 +1288,35 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - wsprintf (buf, "?P%c", (fn == 8) ? '#' : '='); + wsprintf (buf, _T("?P%c"), (fn == 8) ? _T('#') : _T('=')); p = append_str (out, buf); p = append_tab (out); - wsprintf (buf, "%d", n); + wsprintf (buf, _T("%d"), n); p = append_str (p, buf); if (disp != 0) { - p = append_str (p, ", GOYES "); + p = append_str (p, _T(", GOYES ")); p = append_r_addr (p, &pc, disp, 2, 3); p = append_pc_comment (out, pc, view); } else - p = append_str (p, ", RTNYES"); + p = append_str (p, _T(", RTNYES")); break; case CLASS_MNEMONICS: - p = append_str (out, (disp == 0) ? "rt" : "b"); - p = append_str (p, (fn == 8) ? "ne.1" : "eq.1"); + p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); + p = append_str (p, (fn == 8) ? _T("ne.1") : _T("eq.1")); p = append_tab (out); - wsprintf (buf, "#%d, p", n); + wsprintf (buf, _T("#%d, p"), n); p = append_str (p, buf); if (disp != 0) { - p = append_str (p, ", "); + p = append_str (p, _T(", ")); p = append_r_addr (p, &pc, disp, 2, 3); p = append_pc_comment (out, pc, view); } break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1330,19 +1330,19 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - p = append_str (out, (fn == 0xc) ? "GOLONG" : "GOSUBL"); + p = append_str (out, (fn == 0xc) ? _T("GOLONG") : _T("GOSUBL")); p = append_tab (out); p = append_r_addr (p, &pc, disp, 4, (fn == 0xc) ? 2 : 6); p = append_pc_comment (out, pc, view); break; case CLASS_MNEMONICS: - p = append_str (out, (fn == 0xc) ? "bra.4" : "bsr.4"); + p = append_str (out, (fn == 0xc) ? _T("bra.4") : _T("bsr.4")); p = append_tab (out); p = append_r_addr (p, &pc, disp, 4, (fn == 0xc) ? 2 : 6); p = append_pc_comment (out, pc, view); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1353,17 +1353,17 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - p = append_str (out, (fn == 0xd) ? "GOVLNG" : "GOSBVL"); + p = append_str (out, (fn == 0xd) ? _T("GOVLNG") : _T("GOSBVL")); p = append_tab (out); p = append_addr (p, pc); break; case CLASS_MNEMONICS: - p = append_str (out, (fn == 0xd) ? "jmp" : "jsr"); + p = append_str (out, (fn == 0xd) ? _T("jmp") : _T("jsr")); p = append_tab (out); p = append_addr (p, pc); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1377,13 +1377,13 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view) // public functions -DWORD disassemble (DWORD addr, LPSTR out, BOOL view) +DWORD disassemble (DWORD addr, LPTSTR out, BOOL view) { BYTE n; BYTE fn; - char *p = out; - char c; - char buf[20]; + TCHAR *p = out; + TCHAR c; + TCHAR buf[20]; DWORD disp, pc; switch (n = read_nibble (&addr)) @@ -1400,19 +1400,19 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) { case HP_MNEMONICS: wsprintf (buf, op_str_0[(n & 7) + 8 * HP_MNEMONICS], - (n < 8) ? '&' : '!'); + (n < 8) ? _T('&') : _T('!')); p = append_str (out, buf); p = append_tab (out); p = append_field (p, fn); break; case CLASS_MNEMONICS: - p = append_str (out, (n < 8) ? "and" : "or"); + p = append_str (out, (n < 8) ? _T("and") : _T("or")); p = append_field (p, fn); p = append_tab (out); p = append_str (p, op_str_0[(n & 7) + 8 * CLASS_MNEMONICS]); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1426,17 +1426,17 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - p = append_str (out, "P="); + p = append_str (out, _T("P=")); p = append_tab (out); - wsprintf (buf, "%d", n); + wsprintf (buf, _T("%d"), n); p = append_str (p, buf); break; case CLASS_MNEMONICS: - wsprintf (buf, "move.1 #%d, p", n); + wsprintf (buf, _T("move.1 #%d, p"), n); p = append_str (out, buf); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1448,26 +1448,26 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) case HP_MNEMONICS: if (fn < 5) { - wsprintf (buf, "LC(%d)", fn + 1); + wsprintf (buf, _T("LC(%d)"), fn + 1); } else { - wsprintf (buf, "LCHEX"); + wsprintf (buf, _T("LCHEX")); } p = append_str (out, buf); p = append_tab (out); p = append_imm_nibble (p, &addr, fn + 1); break; case CLASS_MNEMONICS: - wsprintf (buf, "move.%d", fn + 1); + wsprintf (buf, _T("move.%d"), fn + 1); p = append_str (out, buf); p = append_tab (out); p = append_imm_nibble (p, &addr, fn + 1); - wsprintf (buf, ", c.p"); + wsprintf (buf, _T(", c.p")); p = append_str (p, buf); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1481,10 +1481,10 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) case HP_MNEMONICS: if (disp == 2) { - p = append_str (out, "NOP3"); + p = append_str (out, _T("NOP3")); break; } - wsprintf (buf, (disp == 0) ? "RTN%sC" : "GO%sC", (n == 4) ? "" : "N"); + wsprintf (buf, (disp == 0) ? _T("RTN%sC") : _T("GO%sC"), (n == 4) ? _T("") : _T("N")); p = append_str (out, buf); if (disp != 0) { @@ -1497,11 +1497,11 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) case CLASS_MNEMONICS: if (disp == 2) { - p = append_str (out, "nop3"); + p = append_str (out, _T("nop3")); break; } - p = append_str (out, (disp == 0) ? "rtc" : "bc"); - p = append_str (p, (n == 4) ? "s" : "c"); + p = append_str (out, (disp == 0) ? _T("rtc") : _T("bc")); + p = append_str (p, (n == 4) ? _T("s") : _T("c")); if (disp != 0) { p = append_tab (out); @@ -1511,7 +1511,7 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1524,15 +1524,15 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) case HP_MNEMONICS: if (disp == 3) { - p = append_str (out, "NOP4"); + p = append_str (out, _T("NOP4")); break; } if (disp == 4) { - p = append_str (out, "NOP5"); + p = append_str (out, _T("NOP5")); break; } - p = append_str (out, "GOTO"); + p = append_str (out, _T("GOTO")); p = append_tab (out); p = append_r_addr (p, &pc, disp, 3, 1); p = append_pc_comment (out, pc, view); @@ -1541,22 +1541,22 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) case CLASS_MNEMONICS: if (disp == 3) { - p = append_str (out, "nop4"); + p = append_str (out, _T("nop4")); break; } if (disp == 4) { - p = append_str (out, "nop5"); + p = append_str (out, _T("nop5")); break; } - p = append_str (out, "bra.3"); + p = append_str (out, _T("bra.3")); p = append_tab (out); p = append_r_addr (p, &pc, disp, 3, 1); p = append_pc_comment (out, pc, view); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1567,21 +1567,21 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) switch (disassembler_mode) { case HP_MNEMONICS: - p = append_str (out, "GOSUB"); + p = append_str (out, _T("GOSUB")); p = append_tab (out); p = append_r_addr (p, &pc, disp, 3, 4); p = append_pc_comment (out, pc, view); break; case CLASS_MNEMONICS: - p = append_str (out, "bsr.3"); + p = append_str (out, _T("bsr.3")); p = append_tab (out); p = append_r_addr (p, &pc, disp, 3, 4); p = append_pc_comment (out, pc, view); break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1600,12 +1600,12 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) fn = read_nibble (&addr); if (n == 8) { - c = (char) ((fn == 0xa) ? 0 : 1); + c = (TCHAR) ((fn == 0xa) ? 0 : 1); fn = 0xf; } else { - c = (char) ((fn < 8) ? 0 : 1); + c = (TCHAR) ((fn < 8) ? 0 : 1); fn &= 7; } @@ -1625,8 +1625,8 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) p = append_str (out, buf); p = append_tab (out); p = append_field (p, fn); - p = append_str (p, ", "); - p = append_str (p, (disp == 0) ? "RTNYES" : "GOYES "); + p = append_str (p, _T(", ")); + p = append_str (p, (disp == 0) ? _T("RTNYES") : _T("GOYES ")); if (disp != 0) { p = append_r_addr (p, &pc, disp, 2, 3); @@ -1635,7 +1635,7 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) break; case CLASS_MNEMONICS: - p = append_str (out, (disp == 0) ? "rt" : "b"); + p = append_str (out, (disp == 0) ? _T("rt") : _T("b")); p = append_str (p, in_str_9[((n >> 2) & 3) + 4 * c + 8 * CLASS_MNEMONICS]); p = append_field (p, fn); p = append_tab (out); @@ -1645,14 +1645,14 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) p = append_str (p, op_str_9[(n & 3) + 8 * CLASS_MNEMONICS]); if (disp != 0) { - p = append_str (p, ", "); + p = append_str (p, _T(", ")); p = append_r_addr (p, &pc, disp, 2, 3); p = append_pc_comment (out, pc, view); } break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); break; } break; @@ -1662,26 +1662,26 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) { case 0xa: fn = read_nibble (&addr); - c = (char) ((fn < 8) ? 0 : 1); + c = (TCHAR) ((fn < 8) ? 0 : 1); fn &= 7; disp = 0xa; break; case 0xb: fn = read_nibble (&addr); - c = (char) ((fn < 8) ? 0 : 1); + c = (TCHAR) ((fn < 8) ? 0 : 1); fn &= 7; disp = 0xb; break; case 0xc: case 0xd: fn = 0xf; - c = (char) (n & 1); + c = (TCHAR) (n & 1); disp = 0xa; break; case 0xe: case 0xf: fn = 0xf; - c = (char) (n & 1); + c = (TCHAR) (n & 1); disp = 0xb; break; default: @@ -1704,11 +1704,11 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) { if (n < 0xc) { - p = "+"; + p = _T("+"); } else { - p = "%c=%c-1"; + p = _T("%c=%c-1"); pc = 2; } } @@ -1716,18 +1716,18 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) { if (n < 4) { - p = "%c=0"; + p = _T("%c=0"); pc = 1; } else if (n >= 0xc) { - p = "%c%cEX"; + p = _T("%c%cEX"); pc = 3; } else { - p = "%c=%c"; + p = _T("%c=%c"); pc = 3; } } @@ -1738,11 +1738,11 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) { if (n < 0xc) { - p = "add"; + p = _T("add"); } else { - p = "dec"; + p = _T("dec"); pc = 1; } } @@ -1750,17 +1750,17 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) { if (n < 4) { - p = "clr"; + p = _T("clr"); pc = 1; } else if (n >= 0xc) { - p = "exg"; + p = _T("exg"); } else { - p = "move"; + p = _T("move"); if (n < 8) n -= 4; } @@ -1768,7 +1768,7 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); return addr; } break; @@ -1781,42 +1781,42 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) { if (n >= 0xc) { - p = "-"; + p = _T("-"); } else if ((n >= 4) && (n <= 7)) { - p = "%c=%c+1"; + p = _T("%c=%c+1"); pc = 2; n -= 4; } else { - p = "-"; + p = _T("-"); } } else { if (n < 4) { - p = "%cSL"; + p = _T("%cSL"); pc = 1; } else if (n < 8) { - p = "%cSR"; + p = _T("%cSR"); pc = 1; } else if (n < 0xc) { - p = "%c=%c-1"; + p = _T("%c=-%c"); pc = 2; } else { - p = "%c=-%c-1"; + p = _T("%c=-%c-1"); pc = 2; } } @@ -1827,18 +1827,18 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) { if (n >= 0xc) { - p = "subr"; + p = _T("subr"); } else if ((n >= 4) && (n <= 7)) { - p = "inc"; + p = _T("inc"); pc = 1; n -= 4; } else { - p = "sub"; + p = _T("sub"); } } else @@ -1846,27 +1846,27 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) pc = 1; if (n < 4) { - p = "lsl"; + p = _T("lsl"); } else if (n < 8) { - p = "lsr"; + p = _T("lsr"); } else if (n < 0xc) { - p = "neg"; + p = _T("neg"); } else { - p = "not"; + p = _T("not"); } } break; default: - p = append_str (out, "Unknown disassembler mode"); + p = append_str (out, _T("Unknown disassembler mode")); return addr; } break; @@ -1883,12 +1883,12 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) else if (pc == 1) { - wsprintf (buf, p, (n & 3) + 'A'); + wsprintf (buf, p, (n & 3) + _T('A')); } else if (pc == 2) { - wsprintf (buf, p, (n & 3) + 'A', (n & 3) + 'A'); + wsprintf (buf, p, (n & 3) + _T('A'), (n & 3) + _T('A')); } else { @@ -1905,7 +1905,7 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) p = append_tab (out); if (pc == 1) { - wsprintf (buf, "%c", (n & 3) + 'a'); + wsprintf (buf, _T("%c"), (n & 3) + _T('a')); p = append_str (p, buf); } else @@ -1915,7 +1915,7 @@ DWORD disassemble (DWORD addr, LPSTR out, BOOL view) break; default: - p = append_str (p, "Unknown disassembler mode"); + p = append_str (p, _T("Unknown disassembler mode")); break; } break; diff --git a/sources/Emu48/DISPLAY.C b/sources/Emu48/DISPLAY.C index 3f11721..d5f39f8 100644 --- a/sources/Emu48/DISPLAY.C +++ b/sources/Emu48/DISPLAY.C @@ -12,10 +12,15 @@ #include "io.h" #include "kml.h" +// #define DEBUG_DISPLAY // switch for DISPLAY debug purpose + #define LCD1_ROW 144 #define LCD2_ROW 288 #define LCD3_ROW 576 +// main display lines, handle zero lines exception +#define LINES(n) ((n == 0) ? 64 : (n+1)) + UINT nBackgroundX = 0; UINT nBackgroundY = 0; UINT nBackgroundW = 0; @@ -31,8 +36,8 @@ static HBITMAP hMainBitmap; static HBITMAP hOldLcdBitmap; static HBITMAP hOldMainBitmap; -#define B 0x00FFFFFF -#define W 0x00000000 +#define B 0x00000000 +#define W 0x00FFFFFF #define I 0xFFFFFFFF static struct { @@ -73,6 +78,7 @@ VOID UpdateContrast(BYTE byContrast) Pattern[i] = (Pattern[i] << 8) | ((i&j) ? c : b); } } + return; } c = (c<<8) | c; @@ -84,6 +90,7 @@ VOID UpdateContrast(BYTE byContrast) Pattern[1] = (b<<16)|c; Pattern[2] = (c<<16)|b; Pattern[3] = (c<<16)|c; + return; } c = (c<<16) | c; @@ -103,7 +110,7 @@ VOID SetLcdColor(UINT nId, UINT nRed, UINT nGreen, UINT nBlue) return; } -VOID CreateLcdBitmap() +VOID CreateLcdBitmap(VOID) { // create LCD bitmap _ASSERT(nLcdDoubled == 1 || nLcdDoubled == 2 || nLcdDoubled == 4); @@ -120,7 +127,7 @@ VOID CreateLcdBitmap() UpdateContrast(Chipset.contrast); } -VOID DestroyLcdBitmap() +VOID DestroyLcdBitmap(VOID) { WORD i; // clear background colors @@ -139,7 +146,7 @@ VOID DestroyLcdBitmap() return; } -BOOL CreateMainBitmap(LPSTR szFilename) +BOOL CreateMainBitmap(LPCTSTR szFilename) { HPALETTE hAssertPalette; @@ -161,7 +168,7 @@ BOOL CreateMainBitmap(LPSTR szFilename) return TRUE; } -VOID DestroyMainBitmap() +VOID DestroyMainBitmap(VOID) { if (hMainDC != NULL) { @@ -182,11 +189,21 @@ VOID DestroyMainBitmap() //* //**************** -VOID UpdateDisplayPointers() +VOID UpdateDisplayPointers(VOID) { + UINT nLines = LINES(Chipset.lcounter); + + #if defined DEBUG_DISPLAY + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: Update Display Pointer\n"),Chipset.pc); + OutputDebugString(buffer); + } + #endif + // calculate display width Chipset.width = (34 + Chipset.loffset + (Chipset.boffset / 4) * 2) & 0xFFFFFFFE; - Chipset.end1 = Chipset.start1 + (Chipset.lcounter + 1) * Chipset.width; + Chipset.end1 = Chipset.start1 + nLines * Chipset.width; if (Chipset.end1 < Chipset.start1) { // calculate first address of main display @@ -198,36 +215,37 @@ VOID UpdateDisplayPointers() { Chipset.start12 = Chipset.start1; } - Chipset.end2 = Chipset.start2 + (63 - Chipset.lcounter) * 34; + Chipset.end2 = Chipset.start2 + (64 - nLines) * 34; } static BYTE Buf[36]; -static BOOL bScreenIsClean = FALSE; -VOID UpdateMainDisplay() +VOID UpdateMainDisplay(VOID) { - UINT x, y; - INT nLines; + UINT x, y, nLines; DWORD d = Chipset.start1; BYTE *p = pbyLcd; + #if defined DEBUG_DISPLAY + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: Update Main Display\n"),Chipset.pc); + OutputDebugString(buffer); + } + #endif + + _ASSERT(nLcdDoubled == 1 || nLcdDoubled == 2 || nLcdDoubled == 4); if (!Chipset.dispon) { nLines = 64; - if (!bScreenIsClean) - { - bScreenIsClean = TRUE; - ZeroMemory(pbyLcd, LCD1_ROW * nLcdDoubled * nLines * nLcdDoubled); - } + ZeroMemory(pbyLcd, LCD1_ROW * nLcdDoubled * nLines * nLcdDoubled); } else { - nLines = Chipset.lcounter + 1; - bScreenIsClean = FALSE; - _ASSERT(nLcdDoubled == 1 || nLcdDoubled == 2 || nLcdDoubled == 4); + nLines = LINES(Chipset.lcounter); // main display lines if (nLcdDoubled == 4) { - for (y=0; y<=Chipset.lcounter; y++) + for (y = 0; y < nLines; ++y) { Npeek(Buf,d,36); for (x=0; x<36; x++) @@ -246,7 +264,7 @@ VOID UpdateMainDisplay() } if (nLcdDoubled == 2) { - for (y=0; y<=Chipset.lcounter; y++) + for (y = 0; y < nLines; ++y) { Npeek(Buf,d,36); for (x=0; x<36; x++) @@ -261,7 +279,7 @@ VOID UpdateMainDisplay() } if (nLcdDoubled == 1) { - for (y=0; y<=Chipset.lcounter; y++) + for (y = 0; y < nLines; ++y) { Npeek(Buf,d,36); for (x=0; x<36; x++) *(((DWORD*)p)++)=Pattern[Buf[x]]; @@ -271,30 +289,42 @@ VOID UpdateMainDisplay() } EnterCriticalSection(&csGDILock); // solving NT GDI problems { - BitBlt(hWindowDC, nLcdX, nLcdY, 131*nLcdDoubled, nLines*nLcdDoubled, hLcdDC, Chipset.boffset*nLcdDoubled, 0, SRCCOPY); + BitBlt(hWindowDC, nLcdX, nLcdY, 131*nLcdDoubled, nLines*nLcdDoubled, + hLcdDC, Chipset.boffset*nLcdDoubled, 0, SRCCOPY); GdiFlush(); } LeaveCriticalSection(&csGDILock); return; } -VOID UpdateMenuDisplay() +VOID UpdateMenuDisplay(VOID) { - UINT x, y; + UINT x, y, nLines; BYTE *p; DWORD d = Chipset.start2; + #if defined DEBUG_DISPLAY + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: Update Menu Display\n"),Chipset.pc); + OutputDebugString(buffer); + } + #endif + + nLines = LINES(Chipset.lcounter); + if (!Chipset.dispon) return; - if (Chipset.lcounter==0x3F) return; // menu disabled + if (nLines == 64) return; // menu disabled + _ASSERT(nLcdDoubled == 1 || nLcdDoubled == 2 || nLcdDoubled == 4); - // calculate offset once - p = pbyLcd + ((Chipset.lcounter+1)*nLcdDoubled*LCD1_ROW*nLcdDoubled); + // calculate bitmap offset + p = pbyLcd + (nLines*nLcdDoubled*LCD1_ROW*nLcdDoubled); if (nLcdDoubled == 4) { - for (y=Chipset.lcounter+1; y<64; y++) + for (y = nLines; y < 64; ++y) { Npeek(Buf,d,34); // 34 nibbles are viewed - for (x=0; x<36; x++) + for (x = 0; x < 36; ++x) { *(((DWORD*)p)++)=Pattern[Buf[x]&1]; *(((DWORD*)p)++)=Pattern[(Buf[x]>>1) & 1]; @@ -310,10 +340,10 @@ VOID UpdateMenuDisplay() } if (nLcdDoubled == 2) { - for (y=Chipset.lcounter+1; y<64; y++) + for (y = nLines; y < 64; ++y) { Npeek(Buf,d,34); // 34 nibbles are viewed - for (x=0; x<36; x++) + for (x = 0; x < 36; ++x) { *(((DWORD*)p)++)=Pattern[Buf[x]&3]; *(((DWORD*)p)++)=Pattern[Buf[x]>>2]; @@ -325,18 +355,18 @@ VOID UpdateMenuDisplay() } if (nLcdDoubled == 1) { - for (y=Chipset.lcounter+1; y<64; y++) + for (y = nLines; y < 64; ++y) { Npeek(Buf,d,34); // 34 nibbles are viewed - for (x=0; x<36; x++) *(((DWORD*)p)++)=Pattern[Buf[x]]; + for (x = 0; x < 36; ++x) *(((DWORD*)p)++)=Pattern[Buf[x]]; d+=34; } } EnterCriticalSection(&csGDILock); // solving NT GDI problems { - BitBlt(hWindowDC, nLcdX, nLcdY+(Chipset.lcounter+1)*nLcdDoubled, - 131*nLcdDoubled, (63-Chipset.lcounter)*nLcdDoubled, - hLcdDC, 0, (Chipset.lcounter+1)*nLcdDoubled, SRCCOPY); + BitBlt(hWindowDC, nLcdX, nLcdY+nLines*nLcdDoubled, + 131*nLcdDoubled, (64-nLines)*nLcdDoubled, + hLcdDC, 0, nLines*nLcdDoubled, SRCCOPY); GdiFlush(); } LeaveCriticalSection(&csGDILock); @@ -345,11 +375,20 @@ VOID UpdateMenuDisplay() VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s) { - INT x0, x; - INT y0, y; - DWORD *p; + INT x0, x; + INT y0, y; + DWORD *p; - INT lWidth = abs(Chipset.width); // display width + INT lWidth = abs(Chipset.width); // display width + UINT nLines = LINES(Chipset.lcounter); // main display lines + + #if defined DEBUG_DISPLAY + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: Write Main Display %x,%u\n"),Chipset.pc,d,s); + OutputDebugString(buffer); + } + #endif d -= Chipset.start1; // nibble offset to DISPADDR (start of display) d += 64 * lWidth; // make positive offset @@ -358,7 +397,7 @@ VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s) y = y0; x = x0; // load loop variables // outside main display area - _ASSERT(y0 >= 0 && y0 <= (INT) Chipset.lcounter); + _ASSERT(y0 >= 0 && y0 < (INT) nLines); // illegal zoom factor _ASSERT(nLcdDoubled == 1 || nLcdDoubled == 2 || nLcdDoubled == 4); @@ -393,7 +432,7 @@ VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s) if ((x==lWidth)&&s) // end of display line { // end of main display area - if (y == (INT) Chipset.lcounter) break; + if (y == (INT) nLines - 1) break; x = 0; // first coloumn ++y; // next row @@ -447,9 +486,19 @@ VOID WriteToMenuDisplay(LPBYTE a, DWORD d, UINT s) UINT y0, y; DWORD *p; - if (Chipset.lcounter==0x3F) return; // menu disabled + UINT nLines = LINES(Chipset.lcounter); // main display lines + + #if defined DEBUG_DISPLAY + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: Write Menu Display %x,%u\n"),Chipset.pc,d,s); + OutputDebugString(buffer); + } + #endif + + if (nLines == 64) return; // menu disabled d -= Chipset.start2; - y0 = y = (d / 34) + (Chipset.lcounter+1); + y0 = y = (d / 34) + nLines; x0 = x = d % 34; if (x0 > 32) return; // position out of viewed area _ASSERT(nLcdDoubled == 1 || nLcdDoubled == 2 || nLcdDoubled == 4); @@ -566,14 +615,14 @@ VOID WriteToMenuDisplay(LPBYTE a, DWORD d, UINT s) return; } -VOID UpdateAnnunciators() +VOID UpdateAnnunciators(VOID) { BYTE c; c = (BYTE)(Chipset.IORam[ANNCTRL] | (Chipset.IORam[ANNCTRL+1]<<4)); // switch annunciators off if timer stopped if ((c & AON) == 0 || (Chipset.IORam[TIMER2_CTRL] & RUN) == 0) - c=0; + c = 0; DrawAnnunciator(1,c&LA1); DrawAnnunciator(2,c&LA2); @@ -584,7 +633,7 @@ VOID UpdateAnnunciators() return; } -VOID ResizeWindow() +VOID ResizeWindow(VOID) { RECT rectWindow; RECT rectClient; diff --git a/sources/Emu48/EMU48.C b/sources/Emu48/EMU48.C index c3d7724..da600be 100644 --- a/sources/Emu48/EMU48.C +++ b/sources/Emu48/EMU48.C @@ -13,7 +13,7 @@ #include "kml.h" #include "debugger.h" -#define VERSION "1.20" +#define VERSION "1.25" #define CF_HPOBJ "CF_HPOBJ" // clipboard format for DDE #define MAXPORTS 16 // number of COM ports @@ -21,28 +21,28 @@ // #define MONOCHROME // CF_BITMAP clipboard format #ifdef _DEBUG -LPSTR szNoTitle = "Emu48 "VERSION" Debug"; +LPTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug"); #else -LPSTR szNoTitle = "Emu48 "VERSION; +LPTSTR szNoTitle = _T("Emu48 ")_T(VERSION); #endif -LPSTR szAppName = "Emu48"; // application name for DDE server -LPSTR szTopic = "Stack"; // topic for DDE server -LPSTR szTitle = NULL; +LPTSTR szAppName = _T("Emu48"); // application name for DDE server +LPTSTR szTopic = _T("Stack"); // topic for DDE server +LPTSTR szTitle = NULL; -static const char szLicence[] = - "This program is free software; you can redistribute it and/or modify\r\n" - "it under the terms of the GNU General Public License as published by\r\n" - "the Free Software Foundation; either version 2 of the License, or\r\n" - "(at your option) any later version.\r\n" - "\r\n" - "This program is distributed in the hope that it will be useful,\r\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\r\n" - "See the GNU General Public License for more details.\r\n" - "\r\n" - "You should have received a copy of the GNU General Public License\r\n" - "along with this program; if not, write to the Free Software Foundation,\r\n" - "Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"; +static const TCHAR szLicence[] = + _T("This program is free software; you can redistribute it and/or modify\r\n") + _T("it under the terms of the GNU General Public License as published by\r\n") + _T("the Free Software Foundation; either version 2 of the License, or\r\n") + _T("(at your option) any later version.\r\n") + _T("\r\n") + _T("This program is distributed in the hope that it will be useful,\r\n") + _T("but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n") + _T("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\r\n") + _T("See the GNU General Public License for more details.\r\n") + _T("\r\n") + _T("You should have received a copy of the GNU General Public License\r\n") + _T("along with this program; if not, write to the Free Software Foundation,\r\n") + _T("Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"); CRITICAL_SECTION csGDILock; // critical section for hWindowDC @@ -63,6 +63,8 @@ HANDLE hEventShutdn; // event handle to stop cpu thread HINSTANCE hApp = NULL; HWND hWnd = NULL; +HWND hDlgDebug = NULL; // handle for debugger dialog +HWND hDlgFind = NULL; // handle for debugger find dialog HDC hWindowDC = NULL; HPALETTE hPalette = NULL; HPALETTE hOldPalette = NULL; // old palette of hWindowDC @@ -70,33 +72,26 @@ BOOL bAutoSave = FALSE; BOOL bAutoSaveOnExit = TRUE; BOOL bAlwaysDisplayLog = TRUE; + //################ //# //# Window Status //# //################ -VOID SetWindowTitle(LPSTR szString) +VOID SetWindowTitle(LPTSTR szString) { - if (szTitle) - { - LocalFree(szTitle); - } + if (szTitle) LocalFree(szTitle); + + _ASSERT(hWnd != NULL); if (szString) { szTitle = DuplicateString(szString); - } - else - { - szTitle = NULL; - } - _ASSERT(hWnd != NULL); - if (szTitle) - { SetWindowText(hWnd, szTitle); } else { + szTitle = NULL; SetWindowText(hWnd, szNoTitle); } return; @@ -104,53 +99,35 @@ VOID SetWindowTitle(LPSTR szString) VOID UpdateWindowStatus() { - HMENU hMenu; - - if (hWnd == NULL) return; // return if window closed - - hMenu = GetMenu(hWnd); - - if ((nState == 0)||(nState == 3)) + if (hWnd) // window open { - // disable stack loading items on HP38G - UINT uStackEnable = (cCurrentRomType!='6' && cCurrentRomType!='A') ? MF_ENABLED : MF_GRAYED; + // disable stack loading items on HP38G, HP39/40G + BOOL bStackEnable = cCurrentRomType!='6' && cCurrentRomType!='A' && cCurrentRomType!='E'; + BOOL bRun = nState == SM_RUN || nState == SM_SLEEP; - EnableMenuItem(hMenu,ID_FILE_SAVE,(szCurrentFilename[0]) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hMenu,ID_FILE_SAVEAS,MF_ENABLED); - EnableMenuItem(hMenu,ID_FILE_CLOSE,MF_ENABLED); - EnableMenuItem(hMenu,ID_BACKUP_SAVE,MF_GRAYED); - EnableMenuItem(hMenu,ID_BACKUP_SAVE,MF_ENABLED); - EnableMenuItem(hMenu,ID_VIEW_COPY,MF_ENABLED); - EnableMenuItem(hMenu,ID_VIEW_RESET,MF_ENABLED); + 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_TOOL_DISASM,MF_ENABLED); - } - else - { - EnableMenuItem(hMenu,ID_FILE_SAVE,MF_GRAYED); - EnableMenuItem(hMenu,ID_FILE_SAVEAS,MF_GRAYED); - EnableMenuItem(hMenu,ID_FILE_CLOSE,MF_ENABLED); - EnableMenuItem(hMenu,ID_BACKUP_SAVE,MF_GRAYED); - EnableMenuItem(hMenu,ID_VIEW_COPY,MF_GRAYED); - EnableMenuItem(hMenu,ID_VIEW_RESET,MF_GRAYED); - EnableMenuItem(hMenu,ID_OBJECT_LOAD,MF_GRAYED); - EnableMenuItem(hMenu,ID_OBJECT_SAVE,MF_GRAYED); - EnableMenuItem(hMenu,ID_STACK_COPY,MF_GRAYED); - EnableMenuItem(hMenu,ID_STACK_PASTE,MF_GRAYED); - EnableMenuItem(hMenu,ID_TOOL_DISASM,MF_GRAYED); - } - if (bBackup) - { - EnableMenuItem(hMenu,ID_BACKUP_RESTORE,MF_ENABLED); - EnableMenuItem(hMenu,ID_BACKUP_DELETE,MF_ENABLED); - } - else - { - EnableMenuItem(hMenu,ID_BACKUP_RESTORE,MF_GRAYED); - EnableMenuItem(hMenu,ID_BACKUP_DELETE,MF_GRAYED); + 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 && !bDbgEnable) ? MF_ENABLED : MF_GRAYED); } return; } @@ -189,7 +166,7 @@ VOID CopyItemsToClipboard(HWND hWnd) // save selected Listbox Items to Clipboar { LPBYTE lpData; - if (lpData = GlobalLock(hClipObj)) + if ((lpData = GlobalLock(hClipObj))) { for (j = 0;j < i;++j) // scan all selected items { @@ -228,20 +205,20 @@ VOID CopyItemsToClipboard(HWND hWnd) // save selected Listbox Items to Clipboar //################ // set listfield for serial combobox -static VOID SetCommList(HWND hDlg,int nIDDlgItem,char *szSetting) +static VOID SetCommList(HWND hDlg,int nIDDlgItem,LPCTSTR szSetting) { HANDLE hComm; BOOL bAdd; WORD wCount, wIndex = 1; - char szBuffer[16]; + TCHAR szBuffer[16]; WPARAM wSelect = 0; // set select to disabled SendDlgItemMessage(hDlg,nIDDlgItem,CB_ADDSTRING,0,(LPARAM) NO_SERIAL); for (wCount = 1;wCount <= MAXPORTS;++wCount) { - wsprintf(szBuffer,"COM%u",wCount); - if (bAdd = (strcmp(szBuffer,szSetting) == 0)) + wsprintf(szBuffer,_T("COM%u"),wCount); + if ((bAdd = (lstrcmp(szBuffer,szSetting) == 0))) wSelect = wIndex; // test if COM port is valid @@ -279,14 +256,14 @@ static BOOL CALLBACK SettingsProc(HWND hDlg, UINT message, DWORD wParam, LONG lP // set combobox parameter SetCommList(hDlg,IDC_WIRE,szSerialWire); SetCommList(hDlg,IDC_IR,szSerialIr); - if (CommConnect() != PORT_CLOSE) // disable when port open + if (bCommInit) // disable when port open { EnableWindow(GetDlgItem(hDlg,IDC_WIRE),FALSE); EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE); } // HP48SX/GX - if (cCurrentRomType!='6' && cCurrentRomType!='A' && cCurrentRomType!='X') + if (cCurrentRomType=='S' || cCurrentRomType=='G') { // init port1 enable checkbox CheckDlgButton(hDlg,IDC_PORT1EN,(Chipset.cards_status & PORT1_PRESENT) != 0); @@ -294,17 +271,17 @@ static BOOL CALLBACK SettingsProc(HWND hDlg, UINT message, DWORD wParam, LONG lP // init port2 shared checkbox and set port2 filename CheckDlgButton(hDlg,IDC_PORT2ISSHARED,bPort2IsShared); SetDlgItemText(hDlg,IDC_PORT2,szPort2Filename); - if (nState == 1) // Invalid State + if (nState == SM_INVALID) // Invalid State { EnableWindow(GetDlgItem(hDlg,IDC_PORT1EN),FALSE); EnableWindow(GetDlgItem(hDlg,IDC_PORT1WR),FALSE); } } - else // HP38G/HP49G + else // HP38G/HP39G/HP40G/HP49G { EnableWindow(GetDlgItem(hDlg,IDC_PORT1EN),FALSE); EnableWindow(GetDlgItem(hDlg,IDC_PORT1WR),FALSE); - if (nState == 1) // Invalid State + if (nState == SM_INVALID) // Invalid State { // init port2 shared checkbox and set port2 filename CheckDlgButton(hDlg,IDC_PORT2ISSHARED,bPort2IsShared); @@ -316,7 +293,7 @@ static BOOL CALLBACK SettingsProc(HWND hDlg, UINT message, DWORD wParam, LONG lP EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE); } } - if (nState != 1) // not in Invalid State + if (nState != SM_INVALID) // not in Invalid State { // hide port2 settings EnableWindow(GetDlgItem(hDlg,IDC_PORT2ISSHARED),FALSE); @@ -328,7 +305,7 @@ static BOOL CALLBACK SettingsProc(HWND hDlg, UINT message, DWORD wParam, LONG lP { if (Chipset.Port1Size && cCurrentRomType!='X') { - UINT nOldState = SwitchToState(3); + UINT nOldState = SwitchToState(SM_SLEEP); // save old card status BYTE bCardsStatus = Chipset.cards_status; @@ -361,17 +338,17 @@ static BOOL CALLBACK SettingsProc(HWND hDlg, UINT message, DWORD wParam, LONG lP bAutoSaveOnExit = IsDlgButtonChecked(hDlg, IDC_AUTOSAVEONEXIT); bAlwaysDisplayLog = IsDlgButtonChecked(hDlg, IDC_ALWAYSDISPLOG); SetSpeed(bRealSpeed); // set speed - if (nState == 1) + if (nState == SM_INVALID) { bPort2IsShared = IsDlgButtonChecked(hDlg,IDC_PORT2ISSHARED); - GetDlgItemText(hDlg,IDC_PORT2,szPort2Filename,sizeof(szPort2Filename)); + GetDlgItemText(hDlg,IDC_PORT2,szPort2Filename,ARRAYSIZEOF(szPort2Filename)); } // set disassebler mode disassembler_mode = IsDlgButtonChecked(hDlg,IDC_DISASM_HP) ? HP_MNEMONICS : CLASS_MNEMONICS; // set combobox parameter - GetDlgItemText(hDlg,IDC_WIRE,szSerialWire,sizeof(szSerialWire)); + GetDlgItemText(hDlg,IDC_WIRE,szSerialWire,ARRAYSIZEOF(szSerialWire)); if (cCurrentRomType!='X') // HP49G Ir port is not connected - GetDlgItemText(hDlg,IDC_IR,szSerialIr,sizeof(szSerialIr)); + GetDlgItemText(hDlg,IDC_IR,szSerialIr,ARRAYSIZEOF(szSerialIr)); EndDialog(hDlg, wParam); } if (wParam == IDCANCEL) @@ -407,7 +384,7 @@ static UINT SaveChanges(BOOL bAuto) if (bAuto) uReply = IDYES; else - uReply = YesNoCancelMessage("Do you want to save changes ?"); + uReply = YesNoCancelMessage(_T("Do you want to save changes ?")); if (uReply != IDYES) return uReply; @@ -468,7 +445,11 @@ static LRESULT OnDestroy(HWND hWindow) DeleteCriticalSection(&csT2Lock); DeleteCriticalSection(&csRecvLock); - PostQuitMessage(0); + #if defined _USRDLL // DLL version + DLLDestroyWnd(); // cleanup system + #else // EXE version + PostQuitMessage(0); // exit message loop + #endif return 0; UNREFERENCED_PARAMETER(hWindow); } @@ -486,17 +467,25 @@ static LRESULT OnPaint(HWND hWindow) { EnterCriticalSection(&csGDILock); // solving NT GDI problems { - BitBlt(hPaintDC, 0, 0, nBackgroundW, nBackgroundH, hMainDC, nBackgroundX, nBackgroundY, SRCCOPY); + UINT nLines = (Chipset.lcounter == 0) ? 64 : (Chipset.lcounter + 1); + + // redraw background bitmap + BitBlt(hPaintDC, Paint.rcPaint.left, Paint.rcPaint.top, + Paint.rcPaint.right-Paint.rcPaint.left, Paint.rcPaint.bottom-Paint.rcPaint.top, + hMainDC, Paint.rcPaint.left, Paint.rcPaint.top, SRCCOPY); + // redraw main display area + BitBlt(hWindowDC, nLcdX, nLcdY, + 131*nLcdDoubled, nLines*nLcdDoubled, + hLcdDC, Chipset.boffset*nLcdDoubled, 0, SRCCOPY); + // redraw menu display area + BitBlt(hWindowDC, nLcdX, nLcdY+nLines*nLcdDoubled, + 131*nLcdDoubled, (64-nLines)*nLcdDoubled, + hLcdDC, 0, nLines*nLcdDoubled, SRCCOPY); GdiFlush(); } LeaveCriticalSection(&csGDILock); - if ((nState==0)||(nState==3)) - { - UpdateMainDisplay(); - UpdateMenuDisplay(); - UpdateAnnunciators(); - RefreshButtons(); - } + UpdateAnnunciators(); + RefreshButtons(&Paint.rcPaint); } EndPaint(hWindow, &Paint); return 0; @@ -507,17 +496,17 @@ static LRESULT OnPaint(HWND hWindow) // static LRESULT OnDropFiles(HANDLE hFilesInfo) { - char szFileName[MAX_PATH]; - WORD wNumFiles,wIndex; - BOOL bSuccess; + TCHAR szFileName[MAX_PATH]; + WORD wNumFiles,wIndex; + BOOL bSuccess; - // HP38 has no stack, ignore - if (cCurrentRomType=='6' || cCurrentRomType=='A') return 0; + // HP38G/HP39G/HP40G has no stack, ignore + if (cCurrentRomType=='6' || cCurrentRomType=='A' || cCurrentRomType=='E') return 0; // get number of files dropped wNumFiles = DragQueryFile (hFilesInfo,(UINT)-1,NULL,0); - if (!Chipset.dispon) // calculator off, turn on + if (!Chipset.dispon && !bDbgEnable) // calculator off, turn on { // turn on HP KeyboardEvent(TRUE,0,0x8000); @@ -525,20 +514,20 @@ static LRESULT OnDropFiles(HANDLE hFilesInfo) KeyboardEvent(FALSE,0,0x8000); } - _ASSERT(nState == 0); // Emulator must be in RUN state + _ASSERT(nState == SM_RUN); // emulator must be in RUN state if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state { DragFinish (hFilesInfo); - InfoMessage("The emulator is busy."); + InfoMessage(_T("The emulator is busy.")); return 0; } - _ASSERT(nState==3); + _ASSERT(nState == SM_SLEEP); // get each name and load it into the emulator for (wIndex = 0;wIndex < wNumFiles;++wIndex) { - DragQueryFile (hFilesInfo,wIndex,(LPSTR) szFileName,sizeof(szFileName)); + DragQueryFile (hFilesInfo,wIndex,szFileName,ARRAYSIZEOF(szFileName)); // szFileName has file name, now try loading it if ((bSuccess = LoadObject(szFileName)) == FALSE) @@ -546,9 +535,9 @@ static LRESULT OnDropFiles(HANDLE hFilesInfo) } DragFinish (hFilesInfo); - SwitchToState(0); // run state + SwitchToState(SM_RUN); // run state while (nState!=nNextState) Sleep(0); - _ASSERT(nState==0); + _ASSERT(nState == SM_RUN); if (bSuccess == FALSE) // data not copied return 0; @@ -566,20 +555,17 @@ static LRESULT OnDropFiles(HANDLE hFilesInfo) // static LRESULT OnFileNew() { - UINT uReply; - SaveBackup(); if (pbyRom) { - SwitchToState(1); - uReply = SaveChanges(bAutoSave); - if (uReply==IDCANCEL) goto cancel; + SwitchToState(SM_INVALID); + if (IDCANCEL == SaveChanges(bAutoSave)) + goto cancel; } - NewDocument(); - SetWindowTitle("Untitled"); + if (NewDocument()) SetWindowTitle(_T("Untitled")); UpdateWindowStatus(); cancel: - if (pbyRom) SwitchToState(0); + if (pbyRom) SwitchToState(SM_RUN); return 0; } @@ -588,23 +574,18 @@ cancel: // static LRESULT OnFileOpen() { - UINT uReply; - if (pbyRom) { - SwitchToState(1); - uReply = SaveChanges(bAutoSave); - if (uReply==IDCANCEL) goto cancel; + SwitchToState(SM_INVALID); + if (IDCANCEL == SaveChanges(bAutoSave)) + goto cancel; } if (GetOpenFilename()) { OpenDocument(szBufferFilename); } cancel: - if (pbyRom) - { - SwitchToState(0); - } + if (pbyRom) SwitchToState(SM_RUN); return 0; } @@ -614,9 +595,9 @@ cancel: static LRESULT OnFileSave() { if (pbyRom == NULL) return 0; - SwitchToState(1); + SwitchToState(SM_INVALID); SaveChanges(TRUE); - SwitchToState(0); + SwitchToState(SM_RUN); return 0; } @@ -628,22 +609,22 @@ static LRESULT OnFileSaveAs() UINT uReply; if (pbyRom == NULL) return 0; - SwitchToState(1); + SwitchToState(SM_INVALID); uReply = GetSaveAsFilename(); if (uReply != IDOK) { - SwitchToState(0); + SwitchToState(SM_RUN); return 0; } if (!SaveDocumentAs(szBufferFilename)) { - SwitchToState(0); + SwitchToState(SM_RUN); return 0; } WriteLastDocument(szCurrentFilename); - SwitchToState(0); + SwitchToState(SM_RUN); return 0; } @@ -653,7 +634,7 @@ static LRESULT OnFileSaveAs() static LRESULT OnFileClose() { if (pbyRom == NULL) return 0; - SwitchToState(1); + SwitchToState(SM_INVALID); if (SaveChanges(bAutoSave)!=IDCANCEL) { KillKML(); @@ -662,7 +643,7 @@ static LRESULT OnFileClose() } else { - SwitchToState(0); + SwitchToState(SM_RUN); } return 0; } @@ -674,10 +655,10 @@ static LRESULT OnFileClose() // static LRESULT OnFileExit() { - SwitchToState(1); // hold emulation thread + SwitchToState(SM_INVALID); // hold emulation thread if (SaveChanges(bAutoSaveOnExit) == IDCANCEL) { - SwitchToState(0); // on cancel restart emulation thread + SwitchToState(SM_RUN); // on cancel restart emulation thread return 0; } DestroyWindow(hWnd); @@ -693,14 +674,14 @@ static LRESULT OnStackCopy() // copy data from stack LPBYTE lpData; DWORD dwAddress,dwSize; - _ASSERT(nState == 0); // Emulator must be in RUN state + _ASSERT(nState == SM_RUN); // emulator must be in RUN state if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state { - InfoMessage("The emulator is busy."); + InfoMessage(_T("The emulator is busy.")); return 0; } - _ASSERT(nState==3); + _ASSERT(nState == SM_SLEEP); if ((dwAddress = RPL_Pick(1)) == 0) // pick address of level1 object { @@ -721,7 +702,7 @@ static LRESULT OnStackCopy() // copy data from stack if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,dwSize + 1)) == NULL) goto error; - if (lpData = GlobalLock(hClipObj)) // lock memory + if ((lpData = GlobalLock(hClipObj))) // lock memory { // copy data into clipboard buffer for (dwAddress += 5;dwSize-- > 0;dwAddress += 2,++lpData) @@ -745,7 +726,7 @@ static LRESULT OnStackCopy() // copy data from stack } error: - SwitchToState(0); + SwitchToState(SM_RUN); return 0; } @@ -759,7 +740,7 @@ static LRESULT OnStackPaste() // paste data to stack BOOL bSuccess = FALSE; - if (!Chipset.dispon) // calculator off, turn on + if (!Chipset.dispon && !bDbgEnable) // calculator off, turn on { KeyboardEvent(TRUE,0,0x8000); Sleep(200); @@ -768,26 +749,26 @@ static LRESULT OnStackPaste() // paste data to stack while(Chipset.Shutdn == FALSE) Sleep(0); } - _ASSERT(nState == 0); // Emulator must be in RUN state + _ASSERT(nState == SM_RUN); // emulator must be in RUN state if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state { - InfoMessage("The emulator is busy."); + InfoMessage(_T("The emulator is busy.")); return 0; } - _ASSERT(nState==3); + _ASSERT(nState == SM_SLEEP); if (OpenClipboard(hWnd)) { if ( IsClipboardFormatAvailable(CF_TEXT) || IsClipboardFormatAvailable(CF_OEMTEXT)) { - if (hClipObj = GetClipboardData(CF_TEXT)) + if ((hClipObj = GetClipboardData(CF_TEXT))) { - if (lpClipdata = GlobalLock(hClipObj)) + if ((lpClipdata = GlobalLock(hClipObj))) { DWORD dwSize = strlen(lpClipdata); - if (lpData = (LPBYTE) LocalAlloc(LMEM_FIXED,dwSize * 2)) + if ((lpData = (LPBYTE) LocalAlloc(LMEM_FIXED,dwSize * 2))) { memcpy(lpData+dwSize,lpClipdata,dwSize); // copy data bSuccess = (WriteStack(lpData,dwSize) == S_ERR_NO); @@ -804,9 +785,9 @@ static LRESULT OnStackPaste() // paste data to stack CloseClipboard(); } - SwitchToState(0); // run state + SwitchToState(SM_RUN); // run state while (nState!=nNextState) Sleep(0); - _ASSERT(nState == 0); + _ASSERT(nState == SM_RUN); if (bSuccess == FALSE) // data not copied return 0; @@ -936,12 +917,12 @@ static LRESULT OnViewCopy() // static LRESULT OnViewReset() { - if (nState!=0) return 0; - if (YesNoMessage("Are you sure you want to press the Reset Button ?")==IDYES) + if (nState != SM_RUN) return 0; + if (YesNoMessage(_T("Are you sure you want to press the Reset Button ?"))==IDYES) { - SwitchToState(3); + SwitchToState(SM_SLEEP); CpuReset(); // register setting after Cpu Reset - SwitchToState(0); + SwitchToState(SM_RUN); } return 0; } @@ -953,11 +934,11 @@ static LRESULT OnViewSettings() { ReadSettings(); - // in nState = 1 port2 file must be closed from document - _ASSERT(nState != 1 || pbyPort2 == NULL); + // 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("Settings Dialog Creation Error !"); + AbortMessage(_T("Settings Dialog Creation Error !")); WriteSettings(); return 0; @@ -968,19 +949,19 @@ static LRESULT OnViewSettings() // static LRESULT OnViewScript() { - CHAR cType = cCurrentRomType; - if (nState!=0) + BYTE cType = cCurrentRomType; + if (nState != SM_RUN) { - InfoMessage("You cannot change the KML script when Emu48 is not running.\n" - "Use the File,New menu item to create a new calculator."); + InfoMessage(_T("You cannot change the KML script when Emu48 is not running.\n") + _T("Use the File,New menu item to create a new calculator.")); return 0; } - SwitchToState(1); + SwitchToState(SM_INVALID); retry: if (!DisplayChooseKml(cType)) goto ok; if (!InitKML(szCurrentKml,FALSE)) { - if (AbortMessage("This KML Script has errors.\nPress Ok to try to find a correct script.")==IDCANCEL) + if (AbortMessage(_T("This KML Script has errors.\nPress Ok to try to find a correct script."))==IDCANCEL) { if (szCurrentFilename[0]) OnFileSave(); @@ -991,7 +972,7 @@ retry: goto retry; } ok: - if (pbyRom) SwitchToState(0); + if (pbyRom) SwitchToState(SM_RUN); return 0; } @@ -1002,7 +983,7 @@ static LRESULT OnBackupSave() { UINT nOldState; if (pbyRom == NULL) return 0; - nOldState = SwitchToState(1); + nOldState = SwitchToState(SM_INVALID); SaveBackup(); SwitchToState(nOldState); return 0; @@ -1013,9 +994,9 @@ static LRESULT OnBackupSave() // static LRESULT OnBackupRestore() { - SwitchToState(1); + SwitchToState(SM_INVALID); RestoreBackup(); - if (pbyRom) SwitchToState(0); + if (pbyRom) SwitchToState(SM_RUN); return 0; } @@ -1035,7 +1016,7 @@ static LRESULT OnObjectLoad() { static BOOL bWarning = TRUE; - if (!Chipset.dispon) // calculator off, turn on + if (!Chipset.dispon && !bDbgEnable) // calculator off, turn on { // turn on HP KeyboardEvent(TRUE,0,0x8000); @@ -1043,27 +1024,27 @@ static LRESULT OnObjectLoad() KeyboardEvent(FALSE,0,0x8000); } - if (nState!=0) + if (nState != SM_RUN) { - InfoMessage("The emulator must be running to load an object."); + InfoMessage(_T("The emulator must be running to load an object.")); return 0; } if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state { - InfoMessage("The emulator is busy."); + InfoMessage(_T("The emulator is busy.")); return 0; } - _ASSERT(nState==3); + _ASSERT(nState == SM_SLEEP); if (bWarning) { UINT uReply = YesNoCancelMessage( - "Warning: Trying to load an object while the emulator is busy \n" - "will certainly result in a memory lost. Before loading an object \n" - "you should be sure that the calculator is not doing anything. \n" - "Do you want to see this warning next time you try to load an object ?"); + _T("Warning: Trying to load an object while the emulator is busy\n") + _T("will certainly result in a memory lost. Before loading an object\n") + _T("you should be sure that the calculator is not doing anything.\n") + _T("Do you want to see this warning next time you try to load an object ?")); switch (uReply) { case IDYES: @@ -1072,26 +1053,26 @@ static LRESULT OnObjectLoad() bWarning = FALSE; break; case IDCANCEL: - SwitchToState(0); + SwitchToState(SM_RUN); return 0; } } if (!GetLoadObjectFilename()) { - SwitchToState(0); + SwitchToState(SM_RUN); return 0; } if (!LoadObject(szBufferFilename)) { - SwitchToState(0); + SwitchToState(SM_RUN); return 0; } - SwitchToState(0); // run state + SwitchToState(SM_RUN); // run state while (nState!=nNextState) Sleep(0); - _ASSERT(nState==0); + _ASSERT(nState == SM_RUN); KeyboardEvent(TRUE,0,0x8000); Sleep(200); KeyboardEvent(FALSE,0,0x8000); @@ -1104,29 +1085,29 @@ static LRESULT OnObjectLoad() // static LRESULT OnObjectSave() { - if (nState!=0) + if (nState != SM_RUN) { - InfoMessage("The emulator must be running to save an object."); + InfoMessage(_T("The emulator must be running to save an object.")); return 0; } if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state { - InfoMessage("The emulator is busy."); + InfoMessage(_T("The emulator is busy.")); return 0; } - _ASSERT(nState==3); + _ASSERT(nState == SM_SLEEP); if (!GetSaveObjectFilename()) { - SwitchToState(0); + SwitchToState(SM_RUN); return 0; } SaveObject(szBufferFilename); - SwitchToState(0); + SwitchToState(SM_RUN); return 0; } @@ -1139,7 +1120,7 @@ static BOOL CALLBACK Disasm(HWND hDlg, UINT message, DWORD wParam, LONG lParam) static DWORD dwAddress, dwAddressMax; LONG i; - char *cpStop,szAddress[256] = "0"; + TCHAR *cpStop,szAddress[256] = _T("0"); switch (message) { @@ -1159,7 +1140,7 @@ static BOOL CALLBACK Disasm(HWND hDlg, UINT message, DWORD wParam, LONG lParam) SendDlgItemMessage(hDlg,IDCANCEL,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0)); SetDlgItemText(hDlg,IDC_DISASM_ADR,szAddress); disassembler_map = MEM_MAP; // disassemble with mapped modules - dwAddress = strtoul(szAddress,&cpStop,16); + dwAddress = _tcstoul(szAddress,&cpStop,16); dwAddressMax = 0x100000; // greatest address (mapped mode) return TRUE; case WM_COMMAND: @@ -1184,25 +1165,25 @@ static BOOL CALLBACK Disasm(HWND hDlg, UINT message, DWORD wParam, LONG lParam) return TRUE; case IDC_DISASM_PORT2: disassembler_map = MEM_PORT2; - dwAddressMax = (cCurrentRomType=='X') + dwAddressMax = (cCurrentRomType=='E' || cCurrentRomType=='X') ? (Chipset.Port2Size * 2048) : ((dwPort2Mask != 0) ? ((dwPort2Mask + 1) << 18) : (dwPort2Size * 2048)); return TRUE; case IDOK: SendDlgItemMessage(hDlg,IDC_DISASM_ADR,EM_SETSEL,0,-1); - GetDlgItemText(hDlg,IDC_DISASM_ADR,szAddress,sizeof(szAddress)); + GetDlgItemText(hDlg,IDC_DISASM_ADR,szAddress,ARRAYSIZEOF(szAddress)); // test if valid hex address - for (i = 0; i < (LONG) strlen(szAddress); ++i) + for (i = 0; i < (LONG) lstrlen(szAddress); ++i) { - if (isxdigit(szAddress[i]) == FALSE) + if (_istxdigit(szAddress[i]) == FALSE) return FALSE; } - dwAddress = strtoul(szAddress,&cpStop,16); + dwAddress = _tcstoul(szAddress,&cpStop,16); // no break case IDC_DISASM_NEXT: if (dwAddress >= dwAddressMax) return FALSE; - i = wsprintf(szAddress,(dwAddress <= 0xFFFFF) ? "%05lX " : "%06lX ",dwAddress); + i = wsprintf(szAddress,(dwAddress <= 0xFFFFF) ? _T("%05lX ") : _T("%06lX "),dwAddress); dwAddress = disassemble(dwAddress,&szAddress[i],VIEW_LONG); i = SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_ADDSTRING,0,(LPARAM) szAddress); SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_SELITEMRANGE,FALSE,MAKELPARAM(0,i)); @@ -1249,49 +1230,49 @@ static BOOL CALLBACK About(HWND hDlg, UINT message, DWORD wParam, LONG lParam) static LRESULT OnToolDisasm() // disasm dialogbox call { - if (pbyRom) SwitchToState(3); + if (pbyRom) SwitchToState(SM_SLEEP); if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DISASM), hWnd, (DLGPROC)Disasm) == -1) - AbortMessage("Disassembler Dialog Box Creation Error !"); - if (pbyRom) SwitchToState(0); + AbortMessage(_T("Disassembler Dialog Box Creation Error !")); + if (pbyRom) SwitchToState(SM_RUN); return 0; } static LRESULT OnAbout() { if (DialogBox(hApp, MAKEINTRESOURCE(IDD_ABOUT), hWnd, (DLGPROC)About) == -1) - AbortMessage("About Dialog Box Creation Error !"); + AbortMessage(_T("About Dialog Box Creation Error !")); return 0; } static LRESULT OnLButtonDown(UINT nFlags, WORD x, WORD y) { - if (nState==0) MouseButtonDownAt(nFlags, x,y); + if (nState == SM_RUN) MouseButtonDownAt(nFlags, x,y); return 0; } static LRESULT OnLButtonUp(UINT nFlags, WORD x, WORD y) { - if (nState==0) MouseButtonUpAt(nFlags, x,y); + if (nState == SM_RUN) MouseButtonUpAt(nFlags, x,y); return 0; } static LRESULT OnMouseMove(UINT nFlags, WORD x, WORD y) { - if (nState==0) MouseMovesTo(nFlags, x,y); + if (nState == SM_RUN) MouseMovesTo(nFlags, x,y); return 0; } static LRESULT OnKeyDown(int nVirtKey, DWORD lKeyData) { // call RunKey() only once (suppress autorepeat feature) - if (nState==0 && (lKeyData & 0x40000000)==0) + if (nState == SM_RUN && (lKeyData & 0x40000000) == 0) RunKey((BYTE)nVirtKey, TRUE); return 0; } static LRESULT OnKeyUp(int nVirtKey, DWORD lKeyData) { - if (nState==0) RunKey((BYTE)nVirtKey, FALSE); + if (nState == SM_RUN) RunKey((BYTE)nVirtKey, FALSE); return 0; UNREFERENCED_PARAMETER(lKeyData); } @@ -1379,9 +1360,17 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC DWORD dwAffMask; hApp = hInst; - nArgc = __argc; // no. of command line arguments - ppArgv = (LPCTSTR*) __argv; // command line arguments - + #if defined _UNICODE + { + ppArgv = CommandLineToArgvW(GetCommandLine(),&nArgc); + } + #else + { + nArgc = __argc; // no. of command line arguments + ppArgv = (LPCTSTR*) __argv; // command line arguments + } + #endif + wc.style = CS_BYTEALIGNCLIENT; wc.lpfnWndProc = (WNDPROC)MainWndProc; wc.cbClsExtra = 0; @@ -1391,13 +1380,13 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU); - wc.lpszClassName = "CEmu48"; + wc.lpszClassName = _T("CEmu48"); if (!RegisterClass(&wc)) { AbortMessage( - "CEmu48 class registration failed.\n" - "This application will now terminate."); + _T("CEmu48 class registration failed.\n") + _T("This application will now terminate.")); return FALSE; } @@ -1408,7 +1397,7 @@ 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("CEmu48", "Emu48", + hWnd = CreateWindow(_T("CEmu48"), _T("Emu48"), WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, rectWindow.right - rectWindow.left, @@ -1418,17 +1407,15 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC if (hWnd == NULL) { - AbortMessage("Window creation failed.\n"); + AbortMessage(_T("Window creation failed.")); return FALSE; } - ShowWindow(hWnd, nCmdShow); - // initialization QueryPerformanceFrequency(&lFreq); // init high resolution counter QueryPerformanceCounter(&lAppStart); - GetCurrentDirectory(sizeof(szCurrentDirectory), szCurrentDirectory); + GetCurrentDirectory(ARRAYSIZEOF(szCurrentDirectory), szCurrentDirectory); ReadSettings(); @@ -1438,18 +1425,18 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC hEventShutdn = CreateEvent(NULL,FALSE,FALSE,NULL); if (hEventShutdn == NULL) { - AbortMessage("Event creation failed."); + AbortMessage(_T("Event creation failed.")); DestroyWindow(hWnd); return FALSE; } - nState = 0; // init state must be <> nNextState - nNextState = 1; // go into invalid state + nState = SM_RUN; // init state must be <> nNextState + nNextState = SM_INVALID; // go into invalid state hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&WorkerThread, NULL, CREATE_SUSPENDED, &lThreadId); if (hThread == NULL) { CloseHandle(hEventShutdn); // close event handle - AbortMessage("Thread creation failed."); + AbortMessage(_T("Thread creation failed.")); DestroyWindow(hWnd); return FALSE; } @@ -1459,7 +1446,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC ResumeThread(hThread); // start thread while (nState!=nNextState) Sleep(0); // wait for thread initialized - // initialize DDE server + idDdeInst = 0; // initialize DDE server if (DdeInitialize(&idDdeInst,(PFNCALLBACK) &DdeCallback, APPCLASS_STANDARD | CBF_FAIL_EXECUTES | CBF_FAIL_ADVISES | @@ -1467,7 +1454,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC { TerminateThread(hThread, 0); // kill emulation thread CloseHandle(hEventShutdn); // close event handle - AbortMessage("Could not initialize server!"); + AbortMessage(_T("Could not initialize server!")); DestroyWindow(hWnd); return FALSE; } @@ -1477,27 +1464,27 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC if (nArgc >= 2) // use decoded parameter line { - CHAR szTemp[256] = "Loading "; - strcat(szTemp, ppArgv[1]); + TCHAR szTemp[256] = _T("Loading "); + lstrcat(szTemp, ppArgv[1]); SetWindowTitle(szTemp); if (OpenDocument(ppArgv[1])) goto start; } - ReadLastDocument(szBufferFilename, sizeof(szBufferFilename)); + ReadLastDocument(szBufferFilename, ARRAYSIZEOF(szBufferFilename)); if (szBufferFilename[0]) { - CHAR szTemp[256] = "Loading "; - strcat(szTemp, szBufferFilename); + TCHAR szTemp[256] = _T("Loading "); + lstrcat(szTemp, szBufferFilename); SetWindowTitle(szTemp); if (OpenDocument(szBufferFilename)) goto start; } - SetWindowTitle("New Document"); + SetWindowTitle(_T("New Document")); if (NewDocument()) { - SetWindowTitle("Untitled"); + SetWindowTitle(_T("Untitled")); goto start; } @@ -1505,23 +1492,26 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC start: // init clipboard format and name service - uCF_HpObj = RegisterClipboardFormat(CF_HPOBJ); + uCF_HpObj = RegisterClipboardFormat(_T(CF_HPOBJ)); hszService = DdeCreateStringHandle(idDdeInst,szAppName,0); hszTopic = DdeCreateStringHandle(idDdeInst,szTopic,0); DdeNameService(idDdeInst,hszService,NULL,DNS_REGISTER); - if (pbyRom) SwitchToState(0); + ShowWindow(hWnd, nCmdShow); + + if (pbyRom) SwitchToState(SM_RUN); while (GetMessage(&msg, NULL, 0, 0)) { - if(hDlgDebug == NULL || !IsDialogMessage(hDlgDebug, &msg)) + if( (hDlgDebug == NULL || !IsDialogMessage(hDlgDebug, &msg)) + && (hDlgFind == NULL || !IsDialogMessage(hDlgFind, &msg))) { TranslateMessage(&msg); DispatchMessage(&msg); } } - SwitchToState(2); // exit emulation thread + SwitchToState(SM_RETURN); // exit emulation thread // clean up DDE server DdeNameService(idDdeInst, hszService, NULL, DNS_UNREGISTER); @@ -1531,8 +1521,9 @@ start: WriteSettings(); // save emulation settings + CloseHandle(hThread); // close thread handle CloseHandle(hEventShutdn); // close event handle - _ASSERT(nState == 2); // emulation thread down? + _ASSERT(nState == SM_RETURN); // emulation thread down? ResetDocument(); ResetBackup(); _ASSERT(pbyPort2 == NULL); // port2 file unmapped diff --git a/sources/Emu48/EMU48.DSP b/sources/Emu48/EMU48.DSP index 26a8027..76e6fd1 100644 --- a/sources/Emu48/EMU48.DSP +++ b/sources/Emu48/EMU48.DSP @@ -52,7 +52,7 @@ BSC32=bscmake.exe # 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 /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 !ELSEIF "$(CFG)" == "Emu48 - Win32 Debug" @@ -78,7 +78,7 @@ BSC32=bscmake.exe # 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 /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 !ENDIF @@ -112,6 +112,13 @@ SOURCE=.\Emu48.c # Begin Source File SOURCE=.\Emu48.rc + +!IF "$(CFG)" == "Emu48 - Win32 Release" + +!ELSEIF "$(CFG)" == "Emu48 - Win32 Debug" + +!ENDIF + # End Source File # Begin Source File @@ -220,6 +227,10 @@ SOURCE=.\types.h # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" # Begin Source File +SOURCE=.\DBGTOOL.BMP +# End Source File +# Begin Source File + SOURCE=.\Emu48.ico # End Source File # End Group diff --git a/sources/Emu48/EMU48.H b/sources/Emu48/EMU48.H index 0a84511..c5eedc9 100644 --- a/sources/Emu48/EMU48.H +++ b/sources/Emu48/EMU48.H @@ -8,6 +8,8 @@ */ #include "types.h" +#define ARRAYSIZEOF(a) (sizeof(a) / sizeof(a[0])) + // cards status #define PORT1_PRESENT ((cCurrentRomType=='S')?P1C:P2C) #define PORT1_WRITE ((cCurrentRomType=='S')?P1W:P2W) @@ -17,16 +19,17 @@ #define BINARYHEADER48 "HPHP48-W" #define BINARYHEADER49 "HPHP49-W" +#define SM_RUN 0 // states of cpu emulation thread +#define SM_INVALID 1 +#define SM_RETURN 2 +#define SM_SLEEP 3 + #define S_ERR_NO 0 // stack errorcodes #define S_ERR_BINARY 1 #define S_ERR_ASCII 2 #define NO_SERIAL "disabled" // port not open -#define PORT_CLOSE 0 // COM port status -#define PORT_WIRE 1 -#define PORT_IR 2 - #define HP_MNEMONICS FALSE // disassembler mnenomics mode #define CLASS_MNEMONICS TRUE @@ -44,27 +47,32 @@ #define DISP_MENUE 0x04 #define DISP_ANNUN 0x08 +// values for mapping area +enum MMUMAP { M_IO, M_ROM, M_RAM, M_P1, M_P2, M_BS }; + // Emu48.c extern HPALETTE hPalette; -extern HPALETTE hOldPalette; -extern HANDLE hEventShutdn; -extern LPSTR szAppName; -extern LPSTR szTopic; -extern LPSTR szTitle; -extern CRITICAL_SECTION csGDILock; -extern CRITICAL_SECTION csKeyLock; -extern CRITICAL_SECTION csIOLock; -extern CRITICAL_SECTION csT1Lock; -extern CRITICAL_SECTION csT2Lock; -extern CRITICAL_SECTION csRecvLock; -extern INT nArgc; -extern LPCTSTR *ppArgv; -extern LARGE_INTEGER lFreq; -extern LARGE_INTEGER lAppStart; -extern DWORD idDdeInst; -extern UINT uCF_HpObj; +extern HPALETTE hOldPalette; +extern HANDLE hEventShutdn; +extern LPTSTR szAppName; +extern LPTSTR szTopic; +extern LPTSTR szTitle; +extern CRITICAL_SECTION csGDILock; +extern CRITICAL_SECTION csKeyLock; +extern CRITICAL_SECTION csIOLock; +extern CRITICAL_SECTION csT1Lock; +extern CRITICAL_SECTION csT2Lock; +extern CRITICAL_SECTION csRecvLock; +extern INT nArgc; +extern LPCTSTR *ppArgv; +extern LARGE_INTEGER lFreq; +extern LARGE_INTEGER lAppStart; +extern DWORD idDdeInst; +extern UINT uCF_HpObj; extern HINSTANCE hApp; extern HWND hWnd; +extern HWND hDlgDebug; +extern HWND hDlgFind; extern HDC hWindowDC; extern BOOL bPort2IsShared; extern BOOL bAutoSave; @@ -72,7 +80,7 @@ extern BOOL bAutoSaveOnExit; extern BOOL bAlwaysDisplayLog; extern HANDLE hThread; extern DWORD lThreadId; -extern VOID SetWindowTitle(LPSTR szString); +extern VOID SetWindowTitle(LPTSTR szString); extern VOID CopyItemsToClipboard(HWND hWnd); extern VOID UpdateWindowStatus(VOID); @@ -93,55 +101,70 @@ extern UINT nLcdDoubled; extern LPBYTE pbyLcd; extern HDC hLcdDC; extern HDC hMainDC; -extern VOID UpdateContrast(BYTE byContrast); -extern VOID SetLcdColor(UINT nId, UINT nRed, UINT nGreen, UINT nBlue); -extern VOID CreateLcdBitmap(VOID); -extern VOID DestroyLcdBitmap(VOID); -extern BOOL CreateMainBitmap(LPSTR szFilename); -extern VOID DestroyMainBitmap(VOID); -extern VOID UpdateDisplayPointers(VOID); -extern VOID UpdateMainDisplay(VOID); -extern VOID UpdateMenuDisplay(VOID); -extern VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s); -extern VOID WriteToMenuDisplay(LPBYTE a, DWORD d, UINT s); -extern VOID UpdateAnnunciators(VOID); -extern VOID ResizeWindow(VOID); +extern VOID UpdateContrast(BYTE byContrast); +extern VOID SetLcdColor(UINT nId, UINT nRed, UINT nGreen, UINT nBlue); +extern VOID CreateLcdBitmap(VOID); +extern VOID DestroyLcdBitmap(VOID); +extern BOOL CreateMainBitmap(LPCTSTR szFilename); +extern VOID DestroyMainBitmap(VOID); +extern VOID UpdateDisplayPointers(VOID); +extern VOID UpdateMainDisplay(VOID); +extern VOID UpdateMenuDisplay(VOID); +extern VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s); +extern VOID WriteToMenuDisplay(LPBYTE a, DWORD d, UINT s); +extern VOID UpdateAnnunciators(VOID); +extern VOID ResizeWindow(VOID); // Engine.c -extern BOOL bInterrupt; -extern UINT nState; -extern UINT nNextState; -extern BOOL bRealSpeed; -extern BOOL bKeySlow; -extern CHIPSET Chipset; -extern char szSerialWire[16]; -extern char szSerialIr[16]; -extern DWORD dwSXCycles; -extern DWORD dwGXCycles; -extern VOID AdjKeySpeed(VOID); -extern VOID SetSpeed(BOOL bAdjust); -extern VOID UpdateKdnBit(VOID); -extern BOOL WaitForSleepState(VOID); -extern UINT SwitchToState(UINT nNewState); -extern UINT WorkerThread(LPVOID pParam); -extern DWORD Npack(BYTE *a, UINT s); -extern VOID Nunpack(BYTE *a, DWORD b, UINT s); +extern BOOL bInterrupt; +extern UINT nState; +extern UINT nNextState; +extern BOOL bRealSpeed; +extern BOOL bKeySlow; +extern BOOL bCommInit; +extern CHIPSET Chipset; +extern TCHAR szSerialWire[16]; +extern TCHAR szSerialIr[16]; +extern DWORD dwSXCycles; +extern DWORD dwGXCycles; +extern HANDLE hEventDebug; +extern BOOL bDbgEnable; +extern INT nDbgState; +extern BOOL bDbgNOP3; +extern BOOL bDbgCode; +extern BOOL bDbgRPL; +extern BOOL bDbgSkipInt; +extern DWORD dwDbgStopPC; +extern DWORD dwDbgRplPC; +extern DWORD dwDbgRstkp; +extern DWORD dwDbgRstk; +extern DWORD *pdwInstrArray; +extern WORD wInstrSize; +extern WORD wInstrWp; +extern WORD wInstrRp; +extern VOID AdjKeySpeed(VOID); +extern VOID SetSpeed(BOOL bAdjust); +extern VOID UpdateKdnBit(VOID); +extern BOOL WaitForSleepState(VOID); +extern UINT SwitchToState(UINT nNewState); +extern UINT WorkerThread(LPVOID pParam); // Fetch.c extern VOID EvalOpcode(LPBYTE I); // Files.c -extern char szEmu48Directory[260]; -extern char szCurrentDirectory[260]; -extern char szCurrentKml[260]; -extern char szBackupKml[260]; -extern char szCurrentFilename[260]; -extern char szBackupFilename[260]; -extern char szBufferFilename[260]; -extern char szPort2Filename[260]; +extern TCHAR szEmu48Directory[260]; +extern TCHAR szCurrentDirectory[260]; +extern TCHAR szCurrentKml[260]; +extern TCHAR szBackupKml[260]; +extern TCHAR szCurrentFilename[260]; +extern TCHAR szBackupFilename[260]; +extern TCHAR szBufferFilename[260]; +extern TCHAR szPort2Filename[260]; extern LPBYTE pbyRom; extern DWORD dwRomSize; -extern char cCurrentRomType; +extern BYTE cCurrentRomType; +extern UINT nCurrentClass; extern BOOL bRomWriteable; extern LPBYTE pbyPort2; extern BOOL bPort2Writeable; @@ -150,15 +173,15 @@ extern DWORD dwPort2Size; extern DWORD dwPort2Mask; extern BOOL bBackup; extern WORD WriteStack(LPBYTE,DWORD); -extern BOOL MapRom(LPCSTR szFilename); +extern BOOL MapRom(LPCTSTR szFilename); extern VOID UnmapRom(VOID); -extern BOOL MapPort2(LPCSTR szFilename); +extern BOOL MapPort2(LPCTSTR szFilename); extern VOID UnmapPort2(VOID); extern VOID UpdatePatches(BOOL bPatch); -extern BOOL PatchRom(LPCSTR szFilename); +extern BOOL PatchRom(LPCTSTR szFilename); extern VOID ResetDocument(VOID); extern BOOL NewDocument(VOID); -extern BOOL OpenDocument(LPCSTR szFilename); +extern BOOL OpenDocument(LPCTSTR szFilename); extern BOOL SaveDocument(VOID); extern BOOL SaveDocumentAs(LPCTSTR szFilename); extern BOOL SaveBackup(VOID); @@ -168,9 +191,9 @@ extern BOOL GetOpenFilename(VOID); extern BOOL GetSaveAsFilename(VOID); extern BOOL GetLoadObjectFilename(VOID); extern BOOL GetSaveObjectFilename(VOID); -extern BOOL LoadObject(LPCSTR szFilename); -extern BOOL SaveObject(LPCSTR szFilename); -extern HBITMAP LoadBitmapFile(LPCSTR szFilename); +extern BOOL LoadObject(LPCTSTR szFilename); +extern BOOL SaveObject(LPCTSTR szFilename); +extern HBITMAP LoadBitmapFile(LPCTSTR szFilename); // Timer.c extern VOID SetHP48Time(VOID); @@ -182,30 +205,30 @@ extern BYTE ReadT1(VOID); extern VOID SetT1(BYTE byValue); // MOps.c -extern BOOL ioc_acc; -extern BOOL ir_ctrl_acc; -extern BOOL bFlashRomArray; -extern BYTE disp; -extern LPBYTE RMap[256]; -extern LPBYTE WMap[256]; -extern VOID Map(BYTE a, BYTE b); -extern VOID RomSwitch(DWORD adr); -extern VOID Config(VOID); -extern VOID Uncnfg(VOID); -extern VOID Reset(VOID); -extern VOID C_Eq_Id(VOID); -extern VOID CpuReset(VOID); -extern BYTE GetLineCounter(VOID); -extern VOID Npeek(BYTE *a, DWORD d, UINT s); -extern VOID Nread(BYTE *a, DWORD d, UINT s); -extern VOID Nwrite(BYTE *a, DWORD d, UINT s); -extern BYTE Read2(DWORD d); -extern DWORD Read5(DWORD d); -extern VOID Write5(DWORD d, DWORD n); -extern VOID Write2(DWORD d, BYTE n); -extern VOID IOBit(DWORD d, BYTE b, BOOL s); -extern VOID ReadIO(BYTE *a, DWORD b, DWORD s); -extern VOID WriteIO(BYTE *a, DWORD b, DWORD s); +extern BOOL ioc_acc; +extern BOOL bFlashRomArray; +extern BYTE disp; +extern LPBYTE RMap[256]; +extern LPBYTE WMap[256]; +extern VOID Map(BYTE a, BYTE b); +extern VOID RomSwitch(DWORD adr); +extern VOID Config(VOID); +extern VOID Uncnfg(VOID); +extern VOID Reset(VOID); +extern VOID C_Eq_Id(VOID); +extern enum MMUMAP MapData(DWORD d); +extern VOID CpuReset(VOID); +extern BYTE GetLineCounter(VOID); +extern VOID Npeek(BYTE *a, DWORD d, UINT s); +extern VOID Nread(BYTE *a, DWORD d, UINT s); +extern VOID Nwrite(BYTE *a, DWORD d, UINT s); +extern BYTE Read2(DWORD d); +extern DWORD Read5(DWORD d); +extern VOID Write5(DWORD d, DWORD n); +extern VOID Write2(DWORD d, BYTE n); +extern VOID IOBit(DWORD d, BYTE b, BOOL s); +extern VOID ReadIO(BYTE *a, DWORD b, DWORD s); +extern VOID WriteIO(BYTE *a, DWORD b, DWORD s); // Keyboard.c extern VOID ScanKeyboard(BOOL bReset); @@ -228,28 +251,33 @@ extern HDDEDATA CALLBACK DdeCallback(UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, DWOR // Disasm.c extern BOOL disassembler_mode; extern WORD disassembler_map; -extern DWORD disassemble (DWORD addr, LPSTR out, BOOL view); +extern DWORD disassemble (DWORD addr, LPTSTR out, BOOL view); // Serial.c -extern WORD CommConnect(VOID); -extern VOID CommOpen(LPSTR strWirePort,LPSTR strIrPort); +extern BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort); extern VOID CommClose(VOID); extern VOID CommSetBaud(VOID); -extern VOID UpdateUSRQ(VOID); +extern BOOL UpdateUSRQ(VOID); extern VOID CommTransmit(VOID); extern VOID CommReceive(VOID); +#if defined _USRDLL // DLL version +// Emu48dll.c +extern BOOL DLLCreateWnd(LPCTSTR lpszFilename); +extern BOOL DLLDestroyWnd(VOID); +#endif + // Message Boxes -static __inline int InfoMessage(LPCSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND);} -static __inline int AbortMessage(LPCSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);} -static __inline int YesNoMessage(LPCSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_YESNO|MB_ICONEXCLAMATION|MB_SETFOREGROUND);} -static __inline int YesNoCancelMessage(LPCSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_YESNOCANCEL|MB_ICONEXCLAMATION|MB_SETFOREGROUND);} +static __inline int InfoMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND);} +static __inline int AbortMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);} +static __inline int YesNoMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_YESNO|MB_ICONEXCLAMATION|MB_SETFOREGROUND);} +static __inline int YesNoCancelMessage(LPCTSTR szMessage) {return MessageBox(hWnd, szMessage, szTitle, MB_APPLMODAL|MB_YESNOCANCEL|MB_ICONEXCLAMATION|MB_SETFOREGROUND);} // Missing Win32 API calls -static __inline LPSTR DuplicateString(LPCSTR szString) +static __inline LPTSTR DuplicateString(LPCTSTR szString) { - UINT uLength = strlen(szString) + 1; - LPSTR szDup = LocalAlloc(LMEM_FIXED,uLength); - CopyMemory(szDup,szString,uLength); + UINT uLength = lstrlen(szString) + 1; + LPTSTR szDup = LocalAlloc(LMEM_FIXED,uLength*sizeof(*(LPTSTR)0)); + lstrcpy(szDup,szString); return szDup; } diff --git a/sources/Emu48/EMU48.ICO b/sources/Emu48/EMU48.ICO index 1acb3b2018158cf75fff9ef536d3598dc6355186..82fc1a73569ab0c7218b5a583c7a2f8860c833bd 100644 GIT binary patch delta 154 zcmZ2xzKz3%fq{{Mi9ta@fB^(vFflNw0cimN2w#Jdfq{>ifk6W(rU1kaK+MR%0wft2 q8ki$VRoLZFUY;|Py-X=0icK^P-KrC1H%J;^6&?F1_l7*-W&4( literal 7078 zcmeI0zfT-T6o4P`i6asU&`=>ks7wu?drTLE1nMM9d+MG_@N z8vX*R6lQ8@f@Fz;2wCz``J~89zW4U__V!q~!(bdK%Ae1UOyrA4Lc6w#{5B!-O+#dPxm*8C4quA>CS!1 z9#I-g7c7VSjA~PD>pIsbV}V$#^NezR$XMgFu%;~|rFgS-uB*9)j;R(w^P>K2px%;d z`(Xc~{xl`i^K|ohp6~4R>(!^MEz+J3@@gs)6H$nc=!wJS?Rht_AFyd?Xyn=DG{Z+o zagJrA6wOcjf9*^A<*(9cG-P68LMA6CWoBkZW@l$*Zf;H%7Z+t|X-U@C*JW*OO;%S| zWo2bWvhR{Sd6MKOIh6D|%AbdCBb4h9E6y#p1t1O3d^*bXoSj0Ow@m;$x~jRD&M+X34)9cCLj_5=0<_H~K^_5;2NFa#I^ ze$Z*dD|Yut$Vqh?@j=91ge}4mv1e1O9QYu@5tV}*v*~6~geAfffruEiB>+ogV5Cz- z5MkjWqK7$&utfETvFK{hSwIFuf+4|>U`Q||7;HJg5Mf9#Bp4zLs3FoHh6F=`A;ExZ zB61iK3<-t=K*D}RSz=(KlShZA?%_zLTl;wVTz-*_jSXSvk*%#Q+1=fhgM$Ov+uM_) zqa!&!K9-Y{6FECOlk@X)>2x~M{wK-LFJAB*XLwhi0nN~7HPx$Ct&J8EO3QF*Ov+!O zMcNtcpzXYcrTeRGF9ws>wqM+G{JUF@za>8|xz+ubqov+IL;Ux#$9I~2zq<7?guk!3 z_WnD1M#)2cdrv|7Fzw~zQLDdaonuZ8~D(^xI2{?tsVQ;B!WW3Q-wmdmfK9@KsCyc=Zs$UK#K zD%g4+sTS_TKQ{Yt^j}qqvSvIS6Iefe*WIq4DoIXN5>!jZ(?^n1J@6D>x)=X&b|1J3 z^Oy4b;3;<5GQWO3R8GHCYL4K&`%wN)saQ*+^dE1I)04EG!L>wgoTfp4qs(3(%Ias>@8 oH|o8{_bcQY`OgMFJV%-SNBpJcuSDh_^1Jgx;n%{?=6I2R0aKF5IsgCw diff --git a/sources/Emu48/EMU48.RC b/sources/Emu48/EMU48.RC index 99456d5..406375b 100644 --- a/sources/Emu48/EMU48.RC +++ b/sources/Emu48/EMU48.RC @@ -29,10 +29,18 @@ LANGUAGE LANG_FRENCH, SUBLANG_FRENCH #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO DISCARDABLE BEGIN + IDD_FIND, DIALOG + BEGIN + LEFTMARGIN, 6 + RIGHTMARGIN, 190 + TOPMARGIN, 7 + BOTTOMMARGIN, 40 + END + IDD_BREAKEDIT, DIALOG BEGIN LEFTMARGIN, 5 - RIGHTMARGIN, 106 + RIGHTMARGIN, 113 TOPMARGIN, 5 BOTTOMMARGIN, 95 END @@ -81,8 +89,8 @@ BEGIN BEGIN LEFTMARGIN, 5 RIGHTMARGIN, 274 - TOPMARGIN, 2 - BOTTOMMARGIN, 252 + TOPMARGIN, 17 + BOTTOMMARGIN, 264 END IDD_NEWVALUE, DIALOG @@ -106,7 +114,7 @@ BEGIN LEFTMARGIN, 8 RIGHTMARGIN, 149 TOPMARGIN, 7 - BOTTOMMARGIN, 69 + BOTTOMMARGIN, 79 END IDD_INSTRUCTIONS, DIALOG @@ -125,28 +133,45 @@ END // Dialog // -IDD_BREAKEDIT DIALOG DISCARDABLE 0, 0, 111, 100 +IDD_FIND DIALOGEX 0, 0, 197, 47 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Find" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Find &what:",IDC_STATIC,7,9,34,8 + COMBOBOX IDC_FIND_DATA,46,7,88,41,CBS_DROPDOWN | CBS_AUTOHSCROLL | + WS_VSCROLL | WS_TABSTOP + CONTROL "Find &ASCII",IDC_FIND_ASCII,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,46,30,49,10 + DEFPUSHBUTTON "Find Next",IDOK,140,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,140,26,50,14 +END + +IDD_BREAKEDIT DIALOG DISCARDABLE 0, 0, 118, 100 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Edit breakpoints" +CAPTION "Edit Breakpoints" FONT 8, "Courier New" BEGIN - DEFPUSHBUTTON "OK",IDOK,78,81,28,14 + DEFPUSHBUTTON "OK",IDCANCEL,83,81,30,14 LTEXT "Current breakpoints:",IDC_STATIC_BREAKPOINT,5,5,82,8 - LISTBOX IDC_BREAKEDIT_WND,5,17,101,58,NOT LBS_NOTIFY | LBS_SORT | - LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Add",IDC_BREAKEDIT_ADD,5,81,28,14 - PUSHBUTTON "&Delete",IDC_BREAKEDIT_DELETE,41,81,28,14 + LISTBOX IDC_BREAKEDIT_WND,5,17,108,58,LBS_SORT | + LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | + LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | + LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Add...",IDC_BREAKEDIT_ADD,5,81,30,14 + PUSHBUTTON "&Delete",IDC_BREAKEDIT_DELETE,44,81,30,14 END IDD_ABOUT DIALOGEX 0, 0, 261, 160 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About Emu48" -FONT 8, "MS Sans Serif", 0, 0, 0x1 +FONT 8, "MS Sans Serif" BEGIN ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE, WS_EX_TRANSPARENT LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP - LTEXT "Copyright © 2000 Sébastien Carlier && Christoph Gießelink", + LTEXT "Copyright © 2001 Sébastien Carlier && Christoph Gießelink", IDC_STATIC,29,18,181,8 DEFPUSHBUTTON "OK",IDOK,215,12,39,14 EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL | @@ -156,7 +181,7 @@ END IDD_SETTINGS DIALOGEX 0, 0, 167, 209 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Settings" -FONT 8, "MS Sans Serif", 0, 0, 0x1 +FONT 8, "MS Sans Serif" BEGIN CONTROL "Authentic Calculator Speed",IDC_REALSPEED,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,13,13,104,10 @@ -172,7 +197,7 @@ BEGIN WS_GROUP | WS_TABSTOP,13,81,65,11 CONTROL "Class Mnemonics",IDC_DISASM_CLASS,"Button", BS_AUTORADIOBUTTON,84,81,70,11 - GROUPBOX "Disassembler",IDC_DISASM_MNEMONICS,7,70,153,28 + GROUPBOX "Disassembler",IDC_STATIC,7,70,153,28 CONTROL "Port 1 is Plugged",IDC_PORT1EN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,110,67,10 CONTROL "Port 1 is Writeable",IDC_PORT1WR,"Button", @@ -211,7 +236,7 @@ END IDD_KMLLOG DIALOGEX 0, 0, 301, 167 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "KML Script Compilation Result" -FONT 8, "MS Sans Serif", 0, 0, 0x1 +FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,86,146,50,14 PUSHBUTTON "Cancel",IDCANCEL,164,146,50,14 @@ -229,7 +254,7 @@ END IDD_DISASM DIALOGEX 0, 0, 255, 165 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Disassembler" -FONT 8, "Courier New", 0, 0, 0x1 +FONT 8, "Courier New" BEGIN LTEXT "Address (HEX):",IDC_ADDRESS,7,147,46,8 EDITTEXT IDC_DISASM_ADR,56,145,36,12,ES_AUTOHSCROLL @@ -252,95 +277,94 @@ BEGIN WS_TABSTOP,WS_EX_NOPARENTNOTIFY END -IDD_DEBUG DIALOGEX 0, 0, 279, 254 +IDD_DEBUG DIALOGEX 0, 0, 279, 269 STYLE WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Debugger" MENU IDR_DEBUG -FONT 8, "Courier New", 0, 0, 0x1 +FONT 8, "Courier New" BEGIN - LISTBOX IDC_DEBUG_CODE,11,12,165,122,NOT LBS_NOTIFY | + LISTBOX IDC_DEBUG_CODE,11,27,165,122,NOT LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | WS_TABSTOP - GROUPBOX "Code",IDC_STATIC_CODE,5,2,177,138 - LTEXT "A= 0000000000000000",IDC_REG_A,192,12,77,8 - LTEXT "B= 0000000000000000",IDC_REG_B,192,19,77,8 - LTEXT "C= 0000000000000000",IDC_REG_C,192,26,77,8 - LTEXT "D= 0000000000000000",IDC_REG_D,192,33,77,8 - LTEXT "R0=0000000000000000",IDC_REG_R0,192,43,77,8 - LTEXT "R1=0000000000000000",IDC_REG_R1,192,50,77,8 - LTEXT "R2=0000000000000000",IDC_REG_R2,192,57,77,8 - LTEXT "R3=0000000000000000",IDC_REG_R3,192,64,77,8 - LTEXT "R4=0000000000000000",IDC_REG_R4,192,71,77,8 - LTEXT "D0=00000",IDC_REG_D0,192,82,33,8 - LTEXT "D1=00000",IDC_REG_D1,236,82,33,8 - LTEXT "P=0",IDC_REG_P,192,93,13,8 - LTEXT "PC=00000",IDC_REG_PC,236,93,33,8 - LTEXT "OUT=000",IDC_REG_OUT,192,104,29,8 - LTEXT "IN=0000",IDC_REG_IN,240,104,29,8 - LTEXT "ST=0000",IDC_REG_ST,192,115,29,8 - LTEXT "CY=0",IDC_REG_CY,224,115,17,8 - LTEXT "Mode=H",IDC_REG_MODE,244,115,25,8 - LTEXT "MP=0",IDC_REG_MP,192,125,17,8 - LTEXT "SR=0",IDC_REG_SR,212,125,17,8 - LTEXT "SB=0",IDC_REG_SB,232,125,17,8 - LTEXT "XM=0",IDC_REG_XM,252,125,17,8 - GROUPBOX "Registers",IDC_STATIC_REGISTERS,187,2,87,138 - CONTROL "",IDC_DEBUG_MEM,"Static",SS_WHITERECT | WS_GROUP,11,151, + GROUPBOX "Code",IDC_STATIC_CODE,5,17,177,138 + LTEXT "A= 0000000000000000",IDC_REG_A,192,27,77,8 + LTEXT "B= 0000000000000000",IDC_REG_B,192,34,77,8 + LTEXT "C= 0000000000000000",IDC_REG_C,192,41,77,8 + LTEXT "D= 0000000000000000",IDC_REG_D,192,48,77,8 + LTEXT "R0=0000000000000000",IDC_REG_R0,192,58,77,8 + LTEXT "R1=0000000000000000",IDC_REG_R1,192,65,77,8 + LTEXT "R2=0000000000000000",IDC_REG_R2,192,72,77,8 + LTEXT "R3=0000000000000000",IDC_REG_R3,192,79,77,8 + LTEXT "R4=0000000000000000",IDC_REG_R4,192,86,77,8 + LTEXT "D0=00000",IDC_REG_D0,192,97,33,8 + LTEXT "D1=00000",IDC_REG_D1,236,97,33,8 + LTEXT "P=0",IDC_REG_P,192,108,13,8 + 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 "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 + LTEXT "SR=0",IDC_REG_SR,212,140,17,8 + LTEXT "SB=0",IDC_REG_SB,232,140,17,8 + LTEXT "XM=0",IDC_REG_XM,252,140,17,8 + GROUPBOX "Registers",IDC_STATIC_REGISTERS,187,17,87,138 + CONTROL "",IDC_DEBUG_MEM,"Static",SS_WHITERECT | WS_GROUP,11,166, 165,52,WS_EX_CLIENTEDGE - LISTBOX IDC_DEBUG_MEM_ADDR,12,153,25,48,NOT LBS_NOTIFY | + LISTBOX IDC_DEBUG_MEM_ADDR,12,168,25,48,NOT LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_DISABLED | NOT WS_BORDER - LISTBOX IDC_DEBUG_MEM_COL0,40,153,11,48,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_DEBUG_MEM_COL0,40,168,11,48,LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | NOT WS_BORDER | WS_TABSTOP - LISTBOX IDC_DEBUG_MEM_COL1,52,153,11,48,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_DEBUG_MEM_COL1,52,168,11,48,LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | NOT WS_BORDER - LISTBOX IDC_DEBUG_MEM_COL2,64,153,11,48,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_DEBUG_MEM_COL2,64,168,11,48,LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | NOT WS_BORDER - LISTBOX IDC_DEBUG_MEM_COL3,76,153,11,48,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_DEBUG_MEM_COL3,76,168,11,48,LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | NOT WS_BORDER - LISTBOX IDC_DEBUG_MEM_COL4,88,153,11,48,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_DEBUG_MEM_COL4,88,168,11,48,LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | NOT WS_BORDER - LISTBOX IDC_DEBUG_MEM_COL5,100,153,11,48,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_DEBUG_MEM_COL5,100,168,11,48,LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | NOT WS_BORDER - LISTBOX IDC_DEBUG_MEM_COL6,112,153,11,48,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_DEBUG_MEM_COL6,112,168,11,48,LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | NOT WS_BORDER - LISTBOX IDC_DEBUG_MEM_COL7,124,153,11,48,LBS_NOINTEGRALHEIGHT | + LISTBOX IDC_DEBUG_MEM_COL7,124,168,11,48,LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | NOT WS_BORDER - LISTBOX IDC_DEBUG_MEM_TEXT,139,153,35,48,NOT LBS_NOTIFY | + LISTBOX IDC_DEBUG_MEM_TEXT,139,168,35,48,NOT LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_DISABLED | NOT WS_BORDER - GROUPBOX "Memory",IDC_STATIC_MEMORY,5,141,177,68 - LISTBOX IDC_DEBUG_STACK,192,151,76,52,NOT LBS_NOTIFY | - LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | - WS_VSCROLL | WS_TABSTOP - GROUPBOX "Stack",IDC_STATIC_STACK,187,141,87,68 - LTEXT "Size Mask",IDC_STATIC,11,228,37,8 - LTEXT "Address",IDC_STATIC,11,236,29,8 - CTEXT "I/O",IDC_STATIC,55,220,21,8 - CTEXT "NCE2",IDC_STATIC,80,220,21,8 - CTEXT "CE1",IDC_STATIC,105,220,21,8 - CTEXT "CE2",IDC_STATIC,130,220,21,8 - CTEXT "NCE3",IDC_STATIC,155,220,21,8 - CTEXT "-----",IDC_MMU_IO_S,55,228,21,8 - CTEXT "-----",IDC_MMU_NCE2_S,80,228,21,8 - CTEXT "-----",IDC_MMU_CE1_S,105,228,21,8 - CTEXT "-----",IDC_MMU_CE2_S,130,228,21,8 - CTEXT "-----",IDC_MMU_NCE3_S,155,228,21,8 - CTEXT "-----",IDC_MMU_IO_A,55,236,21,8 - CTEXT "-----",IDC_MMU_CE1_A,105,236,21,8 - CTEXT "-----",IDC_MMU_CE2_A,130,236,21,8 - CTEXT "-----",IDC_MMU_NCE2_A,80,236,21,8 - CTEXT "-----",IDC_MMU_NCE3_A,155,236,21,8 - GROUPBOX "MMU",IDC_STATIC_MMU,5,210,177,39 - LTEXT "Interrupts =",IDC_STATIC,193,220,61,8 - LTEXT "Keyboard Scan =",IDC_STATIC,193,228,61,8 - LTEXT "Bank Switcher =",IDC_MISC_BS_TXT,193,236,61,8, + GROUPBOX "Memory",IDC_STATIC_MEMORY,5,156,177,68 + LISTBOX IDC_DEBUG_STACK,192,166,76,52,LBS_NOINTEGRALHEIGHT | + LBS_WANTKEYBOARDINPUT | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Stack",IDC_STATIC_STACK,187,156,87,68 + LTEXT "Size Mask",IDC_STATIC,11,243,37,8 + LTEXT "Address",IDC_STATIC,11,251,29,8 + CTEXT "I/O",IDC_STATIC,55,235,21,8 + CTEXT "NCE2",IDC_STATIC,80,235,21,8 + CTEXT "CE1",IDC_STATIC,105,235,21,8 + CTEXT "CE2",IDC_STATIC,130,235,21,8 + CTEXT "NCE3",IDC_STATIC,155,235,21,8 + CTEXT "-----",IDC_MMU_IO_S,55,243,21,8 + CTEXT "-----",IDC_MMU_NCE2_S,80,243,21,8 + CTEXT "-----",IDC_MMU_CE1_S,105,243,21,8 + CTEXT "-----",IDC_MMU_CE2_S,130,243,21,8 + CTEXT "-----",IDC_MMU_NCE3_S,155,243,21,8 + CTEXT "-----",IDC_MMU_IO_A,55,251,21,8 + CTEXT "-----",IDC_MMU_CE1_A,105,251,21,8 + CTEXT "-----",IDC_MMU_CE2_A,130,251,21,8 + CTEXT "-----",IDC_MMU_NCE2_A,80,251,21,8 + CTEXT "-----",IDC_MMU_NCE3_A,155,251,21,8 + GROUPBOX "MMU",IDC_STATIC_MMU,5,225,177,39 + LTEXT "Interrupts =",IDC_STATIC,193,235,61,8 + LTEXT "Keyboard Scan =",IDC_STATIC,193,243,61,8 + LTEXT "Bank Switcher =",IDC_MISC_BS_TXT,193,251,61,8, WS_DISABLED - LTEXT "",IDC_MISC_INT,256,220,13,8 - LTEXT "",IDC_MISC_KEY,256,228,13,8 - LTEXT "00",IDC_MISC_BS,256,236,13,8,WS_DISABLED - GROUPBOX "Miscellaneous",IDC_STATIC_MISC,187,210,87,39 + LTEXT "",IDC_MISC_INT,256,235,13,8 + LTEXT "",IDC_MISC_KEY,256,243,13,8 + LTEXT "00",IDC_MISC_BS,256,251,13,8,WS_DISABLED + GROUPBOX "Miscellaneous",IDC_STATIC_MISC,187,225,87,39 END IDD_NEWVALUE DIALOG DISCARDABLE 0, 0, 175, 50 @@ -356,7 +380,7 @@ END IDD_ENTERADR DIALOG DISCARDABLE 0, 0, 156, 50 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Enter address" +CAPTION "Enter Address" FONT 8, "MS Sans Serif" BEGIN LTEXT "Enter address (hexdezimal):",IDC_STATIC,8,9,90,8 @@ -365,29 +389,30 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,92,29,50,14 END -IDD_ENTERBREAK DIALOG DISCARDABLE 0, 0, 156, 76 +IDD_ENTERBREAK DIALOG DISCARDABLE 0, 0, 156, 86 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Enter breakpoint" +CAPTION "Enter Breakpoint" FONT 8, "MS Sans Serif" BEGIN LTEXT "Enter breakpoint (hexdezimal):",IDC_STATIC,8,9,96,8 EDITTEXT IDC_ENTERADR,110,7,39,12,ES_AUTOHSCROLL CONTROL "&Code",IDC_BPCODE,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,17,24,33,10 + CONTROL "R&PL",IDC_BPRPL,"Button",BS_AUTORADIOBUTTON,17,50,30,10 CONTROL "Memory &Access",IDC_BPACCESS,"Button", BS_AUTORADIOBUTTON,79,24,63,10 - CONTROL "Memory &Read",IDC_BPREAD,"Button",BS_AUTORADIOBUTTON,17, - 38,60,10 + CONTROL "Memory &Read",IDC_BPREAD,"Button",BS_AUTORADIOBUTTON,79, + 37,60,10 CONTROL "Memory &Write",IDC_BPWRITE,"Button",BS_AUTORADIOBUTTON, - 79,38,59,10 - DEFPUSHBUTTON "OK",IDOK,14,55,50,14 - PUSHBUTTON "Cancel",IDCANCEL,92,55,50,14 + 79,50,59,10 + DEFPUSHBUTTON "OK",IDOK,14,65,50,14 + PUSHBUTTON "Cancel",IDCANCEL,92,65,50,14 END IDD_INSTRUCTIONS DIALOGEX 0, 0, 186, 169 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Last Instructions" -FONT 8, "Courier New", 0, 0, 0x1 +FONT 8, "Courier New" BEGIN LTEXT "Instructions (disassembly maybe incorrect):", IDC_INSTR_TEXT,7,7,173,8 @@ -400,6 +425,35 @@ BEGIN END +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_CHECKBOX BITMAP DISCARDABLE "checkbox.bmp" +IDR_DEBUG_TOOLBAR BITMAP MOVEABLE PURE "dbgtool.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Toolbar +// + +IDR_DEBUG_TOOLBAR TOOLBAR DISCARDABLE 16, 15 +BEGIN + BUTTON ID_DEBUG_RUN + BUTTON ID_DEBUG_CANCEL + BUTTON ID_DEBUG_BREAK + SEPARATOR + BUTTON ID_BREAKPOINTS_SETBREAK + BUTTON ID_BREAKPOINTS_CODEEDIT + SEPARATOR + BUTTON ID_DEBUG_STEP + BUTTON ID_DEBUG_STEPOVER + BUTTON ID_DEBUG_STEPOUT + BUTTON ID_DEBUG_RUNCURSOR +END + + #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // @@ -407,13 +461,13 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,2,0,0 - PRODUCTVERSION 1,2,0,0 + FILEVERSION 1,2,5,0 + PRODUCTVERSION 1,2,5,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG - FILEFLAGS 0x21L + FILEFLAGS 0x1L #else - FILEFLAGS 0x20L + FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x1L @@ -425,13 +479,12 @@ BEGIN BEGIN VALUE "CompanyName", "Sebastien Carlier & Christoph Gießelink\0" VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0" - VALUE "FileVersion", "1, 2, 0, 0\0" + VALUE "FileVersion", "1, 2, 5, 0\0" VALUE "InternalName", "Emu48\0" - VALUE "LegalCopyright", "Copyright © 2000\0" + VALUE "LegalCopyright", "Copyright © 2001\0" VALUE "OriginalFilename", "Emu48.exe\0" VALUE "ProductName", "Emu48\0" - VALUE "ProductVersion", "1, 2, 0, 0\0" - VALUE "SpecialBuild", "Service Pack 20, Christoph Gießelink\0" + VALUE "ProductVersion", "1, 2, 5, 0\0" END END BLOCK "VarFileInfo" @@ -509,6 +562,7 @@ BEGIN POPUP "&Debug" BEGIN MENUITEM "&Run\tF5", ID_DEBUG_RUN + MENUITEM "Run to &Cursor\tF6", ID_DEBUG_RUNCURSOR MENUITEM "&Step Into\tF7", ID_DEBUG_STEP MENUITEM "Step &Over\tF8", ID_DEBUG_STEPOVER MENUITEM "Step O&ut\tF9", ID_DEBUG_STEPOUT @@ -516,13 +570,14 @@ BEGIN END POPUP "&Breakpoints" BEGIN - MENUITEM "Set &breakpoint\tF2", ID_BREAKPOINTS_SETBREAK - MENUITEM "&Edit breakpoints...", ID_BREAKPOINTS_CODEEDIT - MENUITEM "&Clear all breakpoints", ID_BREAKPOINTS_CLEARALL + MENUITEM "Set &Breakpoint\tF2", ID_BREAKPOINTS_SETBREAK + MENUITEM "&Edit Breakpoints...", ID_BREAKPOINTS_CODEEDIT + MENUITEM "&Clear All Breakpoints", ID_BREAKPOINTS_CLEARALL MENUITEM SEPARATOR - MENUITEM "&NOP3 code breakpoints", ID_BREAKPOINTS_NOP3 + MENUITEM "&NOP3 Code Breakpoints", ID_BREAKPOINTS_NOP3 + MENUITEM "CODE &Object Breakpoints", ID_BREAKPOINTS_DOCODE MENUITEM SEPARATOR - MENUITEM "&RPL breakpoints", ID_BREAKPOINTS_RPL + MENUITEM "&RPL Breakpoints", ID_BREAKPOINTS_RPL END POPUP "I&nterrupts" BEGIN @@ -554,6 +609,8 @@ BEGIN MENUITEM "Go to D&0", ID_DEBUG_MEM_GOD0 MENUITEM "Go to D&1", ID_DEBUG_MEM_GOD1 MENUITEM "Go to &Stack", ID_DEBUG_MEM_GOSTACK + MENUITEM SEPARATOR + MENUITEM "Find...\tF", ID_DEBUG_MEM_FIND END END @@ -583,6 +640,25 @@ END #endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + ID_DEBUG_RUN "Run" + ID_DEBUG_RUNCURSOR "Run to Cursor" + ID_DEBUG_STEP "Step Into" + ID_DEBUG_STEPOVER "Step Over" + ID_DEBUG_BREAK "Break Execution" + ID_DEBUG_STEPOUT "Step Out" + ID_DEBUG_CANCEL "Stop Debugging" + ID_BREAKPOINTS_SETBREAK "Insert/Remove Breakpoint" + ID_BREAKPOINTS_CODEEDIT "Breakpoint List" +END + #endif // French (France) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/sources/Emu48/ENGINE.C b/sources/Emu48/ENGINE.C index 160b2e9..a0bda4e 100644 --- a/sources/Emu48/ENGINE.C +++ b/sources/Emu48/ENGINE.C @@ -14,20 +14,44 @@ #define SAMPLE 16384 // speed adjust sample frequency -BOOL bInterrupt = FALSE; -UINT nState = 1; -UINT nNextState = 0; -BOOL bRealSpeed = FALSE; -BOOL bKeySlow = FALSE; // slow down for key emulation -CHIPSET Chipset; +BOOL bInterrupt = FALSE; +UINT nState = SM_INVALID; +UINT nNextState = SM_RUN; +BOOL bRealSpeed = FALSE; +BOOL bKeySlow = FALSE; // slow down for key emulation +BOOL bCommInit = FALSE; // COM port not open -char szSerialWire[16]; // evicename for wire port -char szSerialIr[16]; // devicename for IR port +CHIPSET Chipset; -DWORD dwSXCycles = 82; // SX cpu cycles in interval -DWORD dwGXCycles = 123; // GX cpu cycles in interval +TCHAR szSerialWire[16]; // devicename for wire port +TCHAR szSerialIr[16]; // devicename for IR port + +DWORD dwSXCycles = 82; // SX cpu cycles in interval +DWORD dwGXCycles = 123; // GX cpu cycles in interval + +// variables for debugger engine +HANDLE hEventDebug; // event handle to stop cpu thread + +BOOL bDbgEnable = FALSE; // debugger mode enable flag +INT nDbgState = DBG_RUN; // state of debugger + +BOOL bDbgNOP3 = FALSE; // halt on NOP3 (#420 opcode) +BOOL bDbgRPL = FALSE; // halt on RPL entry +BOOL bDbgCode = FALSE; // halt on DOCODE entry + +BOOL bDbgSkipInt = FALSE; // execute interrupt handler + +DWORD dwDbgStopPC = -1; // stop address for goto cursor +DWORD dwDbgRplPC = -1; // stop address for RPL breakpoint + +DWORD dwDbgRstkp; // stack recursion level of step over end +DWORD dwDbgRstk; // possible return address + +DWORD *pdwInstrArray = NULL; // last instruction array +WORD wInstrSize; // size of last instruction array +WORD wInstrWp; // write pointer of instruction array +WORD wInstrRp; // read pointer of instruction array -static BOOL bCommInit = FALSE; // COM port not open static BOOL bCpuSlow = FALSE; // enable/disable real speed static DWORD dwEDbgT2 = 0; // debugger timer2 emulation @@ -55,8 +79,8 @@ static __inline VOID SaveInstrAddr(DWORD dwAddr) static __inline VOID Debugger(VOID) // debugger part { LARGE_INTEGER lDummyInt; // sample timer ticks - BOOL bStopEmulation; - BOOL bRplBreak = FALSE; // flag for RPL breakpoint + BOOL bStopEmulation; + BOOL bRplBreak = FALSE; // flag for RPL breakpoint LPBYTE I = FASTPTR(Chipset.pc); // get opcode stream @@ -76,44 +100,59 @@ static __inline VOID Debugger(VOID) // debugger part { dwRange = (I[2] & 0x8) ? 2 : 5; } - else // P,WP,XS,X,S,M,W or number of nibbles + else // number of nibbles, (P,WP,XS,X,S,M,W) { - if (I[2] & 0x8) // number of nibbles - { - dwRange = I[3]+1; - } - else // P,WP,XS,X,S,M,W - { - dwData += F_s[I[3]]; - dwRange = F_l[I[3]]; - } + dwRange = (I[2] & 0x8) ? (I[3]+1) : (F_l[I[3]]); } #if defined DEBUG_DEBUGGER { - char buffer[256]; - wsprintf(buffer,"Memory breakpoint %.5lx, %u\n",dwData,dwRange); + TCHAR buffer[256]; + wsprintf(buffer,_T("Memory breakpoint %.5lx, %u\n",dwData,dwRange)); OutputDebugString(buffer); } #endif bStopEmulation |= CheckBreakpoint(dwData, dwRange, nType); } + // check for step cursor + bStopEmulation |= (dwDbgStopPC == Chipset.pc); + + // check for RPL breakpoint + if (dwDbgRplPC == Chipset.pc) + { + dwDbgRplPC = -1; + bRplBreak = TRUE; + bStopEmulation = TRUE; + } + // NOP3, opcode #420 (GOC) if (bDbgNOP3 && I[0] == 0x4 && I[1] == 0x2 && I[2] == 0x0) bStopEmulation = TRUE; - // RPL breakpoints, PC=(A), opcode #808C or PC=(C), opcode #808E - if (bDbgRPL && I[0] == 0x8 && I[1] == 0x0 && I[2] == 0x8 && (I[3] == 0xC || I[3] == 0xE )) + // stop on first instruction of DOCODE object + if (bDbgCode && (Chipset.pc == 0x02DDE || Chipset.pc == 0x02E3C)) { - BYTE byRplPtr[5]; + // return address + DWORD dwAddr = Chipset.rstk[(Chipset.rstkp-1)&7]; - // A=DAT0 A, D0=D0+ 5, PC=(A) - // C=DAT0 A, D0=D0+ 5, PC=(C) - Npeek(byRplPtr,Chipset.d0-5,5); - if (memcmp(byRplPtr,(I[3] == 0xC) ? Chipset.A : Chipset.C,5) == 0) + _ASSERT(I[0] == 0 && I[1] == 1); // stopped at RTN opcode + + if (MapData(dwAddr) != M_ROM) // address not in ROM + dwDbgStopPC = dwAddr; // then stop + } + + // RPL breakpoints, PC=(A), opcode #808C or PC=(C), opcode #808E + if (I[0] == 0x8 && I[1] == 0x0 && I[2] == 0x8 && (I[3] == 0xC || I[3] == 0xE )) + { + // get next RPL entry + DWORD dwAddr = Npack((I[3] == 0xC) ? Chipset.A : Chipset.C,5); + + if (bDbgRPL || CheckBreakpoint(dwAddr, 1, BP_RPL)) { - bRplBreak = TRUE; - bStopEmulation = TRUE; + BYTE byRplPtr[5]; + + Npeek(byRplPtr,dwAddr,5); // get PC address of next opcode + dwDbgRplPC = Npack(byRplPtr,5); // set RPL breakpoint } } @@ -167,10 +206,10 @@ static __inline VOID Debugger(VOID) // debugger part } dwEDbgT2 = Chipset.t2; // timer2 check reference value - // OutputDebugString("Emulator stopped...\n"); + // OutputDebugString(_T("Emulator stopped...\n")); NotifyDebugger(bRplBreak); WaitForSingleObject(hEventDebug,INFINITE); - // OutputDebugString("Emulator running...\n"); + // OutputDebugString(_T("Emulator running...\n")); StartTimers(); // continue timers @@ -209,11 +248,10 @@ static __inline VOID CheckSerial(VOID) // COM port closed and serial on if (bCommInit == FALSE && (Chipset.IORam[IOC] & SON) != 0) { - CommOpen(szSerialWire,szSerialIr); // open COM ports - bCommInit = CommConnect() != PORT_CLOSE; + bCommInit = CommOpen(szSerialWire,szSerialIr); // open COM ports } - // COM port opend and serial off + // COM port opened and serial off if (bCommInit == TRUE && (Chipset.IORam[IOC] & SON) == 0) { CommClose(); // close COM port @@ -227,6 +265,7 @@ static __inline VOID CheckSerial(VOID) INTERRUPT; } } + return; } static __inline VOID AdjustSpeed(VOID) // adjust emulation speed @@ -273,7 +312,7 @@ VOID AdjKeySpeed(VOID) // slow down key repeat if (bCpuSlow) return; // no need to slow down bKey = FALSE; // search for a pressed key - for (i = 0;i < sizeof(Chipset.Keyboard_Row) / sizeof(Chipset.Keyboard_Row[0]) && !bKey;++i) + for (i = 0;i < ARRAYSIZEOF(Chipset.Keyboard_Row) && !bKey;++i) bKey = (Chipset.Keyboard_Row[i] != 0); if (!bKeySlow && bKey) // key pressed, init variables @@ -309,16 +348,19 @@ VOID UpdateKdnBit(VOID) // update KDN bit BOOL WaitForSleepState(VOID) // wait for cpu SHUTDN then sleep state { - DWORD dwRefTime = timeGetTime(); + DWORD dwRefTime; + DisableDebugger(); // disable debugger + + dwRefTime = timeGetTime(); // wait for the SHUTDN command with 1.5 sec timeout while (timeGetTime() - dwRefTime < 1500L && !Chipset.Shutdn) Sleep(0); if (Chipset.Shutdn) // not timeout, cpu is down - SwitchToState(3); // go to sleep state + SwitchToState(SM_SLEEP); // go to sleep state - return 3 != nNextState; // state not changed, emulator was busy + return SM_SLEEP != nNextState; // state not changed, emulator was busy } UINT SwitchToState(UINT nNewState) @@ -328,16 +370,12 @@ UINT SwitchToState(UINT nNewState) if (nState == nNewState) return nOldState; switch (nState) { - case 0: // Run - if (hDlgDebug) // debugger running - { - DestroyWindow(hDlgDebug); // then close debugger to renter emulation - hDlgDebug = NULL; - } + case SM_RUN: // Run switch (nNewState) { - case 1: // -> Invalid - nNextState = 1; + case SM_INVALID: // -> Invalid + DisableDebugger(); // disable debugger + nNextState = SM_INVALID; if (Chipset.Shutdn) SetEvent(hEventShutdn); else @@ -345,73 +383,77 @@ UINT SwitchToState(UINT nNewState) while (nState!=nNextState) Sleep(0); UpdateWindowStatus(); break; - case 2: // -> Return - nNextState = 1; + case SM_RETURN: // -> Return + DisableDebugger(); // disable debugger + nNextState = SM_INVALID; if (Chipset.Shutdn) SetEvent(hEventShutdn); else bInterrupt = TRUE; while (nState!=nNextState) Sleep(0); - nNextState = 2; + nNextState = SM_RETURN; SetEvent(hEventShutdn); - while (nState!=nNextState) Sleep(0); + WaitForSingleObject(hThread,INFINITE); UpdateWindowStatus(); break; - case 3: // -> Sleep - nNextState = 3; - if (Chipset.Shutdn) - SetEvent(hEventShutdn); - else - bInterrupt = TRUE; + case SM_SLEEP: // -> Sleep + nNextState = SM_SLEEP; + bInterrupt = TRUE; // exit main loop + SetEvent(hEventDebug); // exit debugger + SetEvent(hEventShutdn); // exit shutdown while (nState!=nNextState) Sleep(0); + bInterrupt = FALSE; + ResetEvent(hEventDebug); + ResetEvent(hEventShutdn); break; } break; - case 1: // Invalid + case SM_INVALID: // Invalid switch (nNewState) { - case 0: // -> Run - nNextState = 0; + case SM_RUN: // -> Run + nNextState = SM_RUN; // don't enter opcode loop on interrupt request bInterrupt = Chipset.Shutdn || Chipset.SoftInt; SetEvent(hEventShutdn); while (nState!=nNextState) Sleep(0); UpdateWindowStatus(); break; - case 2: // -> Return - nNextState = 2; + case SM_RETURN: // -> Return + nNextState = SM_RETURN; SetEvent(hEventShutdn); - while (nState!=nNextState) Sleep(0); + WaitForSingleObject(hThread,INFINITE); break; - case 3: // -> Sleep - nNextState = 3; + case SM_SLEEP: // -> Sleep + nNextState = SM_SLEEP; SetEvent(hEventShutdn); while (nState!=nNextState) Sleep(0); UpdateWindowStatus(); break; } break; - case 3: // Sleep + case SM_SLEEP: // Sleep switch (nNewState) { - case 0: // -> Run - nNextState = 0; - if (Chipset.Shutdn) bInterrupt=TRUE; - SetEvent(hEventShutdn); + case SM_RUN: // -> Run + nNextState = SM_RUN; + // don't enter opcode loop on interrupt request + bInterrupt = !bDbgEnable && (Chipset.Shutdn || Chipset.SoftInt); + SetEvent(hEventShutdn); // leave sleep state break; - case 1: // -> Invalid - nNextState = 1; + case SM_INVALID: // -> Invalid + nNextState = SM_INVALID; SetEvent(hEventShutdn); while (nState!=nNextState) Sleep(0); UpdateWindowStatus(); break; - case 2: // -> Return - nNextState = 1; + case SM_RETURN: // -> Return + nNextState = SM_INVALID; SetEvent(hEventShutdn); while (nState!=nNextState) Sleep(0); - nNextState = 2; + nNextState = SM_RETURN; SetEvent(hEventShutdn); - while (nState!=nNextState) Sleep(0); + WaitForSingleObject(hThread,INFINITE); UpdateWindowStatus(); break; } @@ -429,24 +471,24 @@ UINT WorkerThread(LPVOID pParam) _ASSERT(dwTickRef); // tick resolution error loop: - while (nNextState == 1) // go into invalid state + while (nNextState == SM_INVALID) // go into invalid state { CommClose(); // close COM port bCommInit = FALSE; // COM port not open - nState = 1; // in invalid state + nState = SM_INVALID; // in invalid state WaitForSingleObject(hEventShutdn,INFINITE); - if (nNextState == 2) // go into return state + if (nNextState == SM_RETURN) // go into return state { - nState = 2; // in return state + nState = SM_RETURN; // in return state return 0; // kill thread } ioc_acc = TRUE; // test if UART on } - while (nNextState == 0) + while (nNextState == SM_RUN) { - if (nState!=0) + if (nState != SM_RUN) { - nState = 0; + nState = SM_RUN; // clear port2 status bits Chipset.cards_status &= ~(PORT2_PRESENT | PORT2_WRITE); if (pbyPort2 || Chipset.Port2) // card plugged in port2 @@ -524,13 +566,13 @@ loop: } } } - _ASSERT(nNextState != 0); + _ASSERT(nNextState != SM_RUN); StopTimers(); - while (nNextState == 3) // go into sleep state + while (nNextState == SM_SLEEP) // go into sleep state { - nState = 3; // in sleep state + nState = SM_SLEEP; // in sleep state WaitForSingleObject(hEventShutdn,INFINITE); } goto loop; diff --git a/sources/Emu48/EXTERNAL.C b/sources/Emu48/EXTERNAL.C index 2a7a68b..dbffcd1 100644 --- a/sources/Emu48/EXTERNAL.C +++ b/sources/Emu48/EXTERNAL.C @@ -8,23 +8,24 @@ */ #include "pch.h" #include "Emu48.h" +#include "ops.h" -//| 38G | 48SX | 48GX | 49G | Name -//#F0E4F #706D2 #80850 #80F0F =SFLAG53_56 +//| 38G | 39G | 40G | 48SX | 48GX | 49G | Name +//#F0E4F #80F0F #80F0F #706D2 #80850 #80F0F =SFLAG53_56 // memory address for flags -53 to -56 -#define SFLAG53_56 ( (cCurrentRomType=='6') \ - ? 0xE0E4F \ - : ( (cCurrentRomType=='A') \ - ? 0xF0E4F \ - : ( (cCurrentRomType!='X') \ - ? ( (cCurrentRomType=='S') \ - ? 0x706D2 \ - : 0x80850 \ - ) \ - : 0x80F0F \ - ) \ - ) \ +#define SFLAG53_56 ( (cCurrentRomType=='6') \ + ? 0xE0E4F \ + : ( (cCurrentRomType=='A') \ + ? 0xF0E4F \ + : ( (cCurrentRomType!='E' && cCurrentRomType!='X') \ + ? ( (cCurrentRomType=='S') \ + ? 0x706D2 \ + : 0x80850 \ + ) \ + : 0x80F0F \ + ) \ + ) \ ) static __inline VOID Return(CHIPSET* w) diff --git a/sources/Emu48/FETCH.C b/sources/Emu48/FETCH.C index 550d10f..84214ab 100644 --- a/sources/Emu48/FETCH.C +++ b/sources/Emu48/FETCH.C @@ -321,7 +321,7 @@ static const JMPTAB o8A_[] = static const JMPTAB o81B_[] = { o_invalid4, F, - o81B1, F, + o81B1, F, // normally o_invalid4, beep patch o81B2, F, o81B3, F, o81B4, F, diff --git a/sources/Emu48/FILES.C b/sources/Emu48/FILES.C index 8789ba7..788ed81 100644 --- a/sources/Emu48/FILES.C +++ b/sources/Emu48/FILES.C @@ -8,36 +8,40 @@ */ #include "pch.h" #include "Emu48.h" +#include "ops.h" #include "io.h" // I/O register definitions #include "kml.h" #include "i28f160.h" // flash support +#include "debugger.h" -char szEmu48Directory[260]; -char szCurrentDirectory[260]; -char szCurrentKml[260]; -char szBackupKml[260]; -char szCurrentFilename[260]; -char szBackupFilename[260]; -char szBufferFilename[260]; -char szPort2Filename[260]; +TCHAR szEmu48Directory[260]; +TCHAR szCurrentDirectory[260]; +TCHAR szCurrentKml[260]; +TCHAR szBackupKml[260]; +TCHAR szCurrentFilename[260]; +TCHAR szBackupFilename[260]; +TCHAR szBufferFilename[260]; +TCHAR szPort2Filename[260]; -LPBYTE pbyRom = NULL; +LPBYTE pbyRom = NULL; static HANDLE hRomFile = NULL; static HANDLE hRomMap = NULL; -DWORD dwRomSize = 0; -char cCurrentRomType = 0; -BOOL bRomWriteable = FALSE; // flag if ROM writeable +DWORD dwRomSize = 0; +BYTE cCurrentRomType = 0; // Model -> hardware +UINT nCurrentClass = 0; // Class -> derivate +BOOL bRomWriteable = TRUE; // flag if ROM writeable static HANDLE hPort2File = NULL; static HANDLE hPort2Map = NULL; -LPBYTE pbyPort2 = NULL; -BOOL bPort2Writeable = FALSE; -BOOL bPort2IsShared = FALSE; -DWORD dwPort2Size = 0; // size of mapped port2 -DWORD dwPort2Mask = 0; +LPBYTE pbyPort2 = NULL; +BOOL bPort2Writeable = FALSE; +BOOL bPort2IsShared = FALSE; +DWORD dwPort2Size = 0; // size of mapped port2 +DWORD dwPort2Mask = 0; // document signatures static BYTE pbySignatureA[16] = "Emu38 Document\xFE"; +static BYTE pbySignatureB[16] = "Emu39 Document\xFE"; static BYTE pbySignatureE[16] = "Emu48 Document\xFE"; static BYTE pbySignatureW[16] = "Win48 Document\xFE"; static BYTE pbySignatureV[16] = "Emu49 Document\xFE"; @@ -105,7 +109,7 @@ WORD WriteStack(LPBYTE lpBuf,DWORD dwSize) // separated from LoadObject() //# //################ -static __inline BYTE Asc2Nib(char c) +static __inline BYTE Asc2Nib(BYTE c) { if (c<'0') return 0; if (c<='9') return c-'0'; @@ -186,7 +190,7 @@ VOID UpdatePatches(BOOL bPatch) return; } -BOOL PatchRom(LPCSTR szFilename) +BOOL PatchRom(LPCTSTR szFilename) { HANDLE hFile = NULL; DWORD dwFileSizeLow = 0; @@ -243,9 +247,9 @@ BOOL PatchRom(LPCSTR szFilename) break; } } while (lpBuf[nPos]); + continue; } - if (lpBuf[nPos] == 0) break; - dwAddress = strtoul(&lpBuf[nPos],&lpStop,16); + dwAddress = strtoul(&lpBuf[nPos],(CHAR **)&lpStop,16); nPos += lpStop-&lpBuf[nPos]+1; if (*lpStop != ':' || *lpStop == 0) continue; @@ -287,7 +291,7 @@ static WORD CrcRom(VOID) // calculate fingerprint of ROM return (WORD) dwCrc; } -BOOL MapRom(LPCSTR szFilename) +BOOL MapRom(LPCTSTR szFilename) { DWORD dwFileSizeHigh; @@ -354,7 +358,7 @@ BOOL MapRom(LPCSTR szFilename) } if (GetLastError() == ERROR_ALREADY_EXISTS) { - AbortMessage("Sharing file mapping handle."); + AbortMessage(_T("Sharing file mapping handle.")); } pbyRom = MapViewOfFile(hRomMap, bWrite ? FILE_MAP_WRITE : FILE_MAP_COPY, 0, 0, dwRomSize); if (pbyRom == NULL) @@ -398,7 +402,7 @@ static WORD CrcPort2(VOID) // calculate fingerprint of port2 WORD wCrc = 0; // port2 CRC isn't available - if (cCurrentRomType=='X' || pbyPort2==NULL) return wCrc; + if (pbyPort2 == NULL) return wCrc; dwFileSize = GetFileSize(hPort2File, &dwCount); // get real filesize _ASSERT(dwCount == 0); // isn't created by MapPort2() @@ -408,7 +412,7 @@ static WORD CrcPort2(VOID) // calculate fingerprint of port2 return wCrc; } -BOOL MapPort2(LPCSTR szFilename) +BOOL MapPort2(LPCTSTR szFilename) { DWORD dwFileSizeLo; DWORD dwFileSizeHi; @@ -418,51 +422,31 @@ BOOL MapPort2(LPCSTR szFilename) dwPort2Size = 0; // reset size of port2 SetCurrentDirectory(szEmu48Directory); - if (bPort2IsShared) + hPort2File = CreateFile(szFilename, + GENERIC_READ|GENERIC_WRITE, + bPort2IsShared ? FILE_SHARE_READ : 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hPort2File == INVALID_HANDLE_VALUE) { + bPort2Writeable = FALSE; hPort2File = CreateFile(szFilename, - GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ, + GENERIC_READ, + bPort2IsShared ? (FILE_SHARE_READ|FILE_SHARE_WRITE) : 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - SetCurrentDirectory(szCurrentDirectory); if (hPort2File == INVALID_HANDLE_VALUE) { - bPort2Writeable = FALSE; - SetCurrentDirectory(szEmu48Directory); - hPort2File = CreateFile(szFilename, - GENERIC_READ, - FILE_SHARE_READ|FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); SetCurrentDirectory(szCurrentDirectory); - if (hPort2File == INVALID_HANDLE_VALUE) - { - hPort2File = NULL; - return FALSE; - } - } - } - else - { - hPort2File = CreateFile(szFilename, - GENERIC_READ|GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - SetCurrentDirectory(szCurrentDirectory); - if (hPort2File == INVALID_HANDLE_VALUE) - { hPort2File = NULL; return FALSE; } } + SetCurrentDirectory(szCurrentDirectory); dwFileSizeLo = GetFileSize(hPort2File, &dwFileSizeHi); if (dwFileSizeHi != 0) { // file is too large. @@ -472,7 +456,7 @@ BOOL MapPort2(LPCSTR szFilename) bPort2Writeable = FALSE; return FALSE; } - if (dwFileSizeLo & 0x3FFFF) + if (dwFileSizeLo & 0x2FFFF) { // file size is wrong CloseHandle(hPort2File); hPort2File = NULL; @@ -480,7 +464,7 @@ BOOL MapPort2(LPCSTR szFilename) bPort2Writeable = FALSE; return FALSE; } - dwPort2Mask = (dwFileSizeLo >> 18) - 1; // mask for valid address lines of the BS-FF + dwPort2Mask = (dwFileSizeLo - 1) >> 18; // mask for valid address lines of the BS-FF hPort2Map = CreateFileMapping(hPort2File, NULL, bPort2Writeable ? PAGE_READWRITE : PAGE_READONLY, 0, dwFileSizeLo, NULL); if (hPort2Map == NULL) @@ -545,15 +529,10 @@ VOID ResetDocument(VOID) szCurrentFilename[0]=0; if (Chipset.Port0) LocalFree(Chipset.Port0); if (Chipset.Port1) LocalFree(Chipset.Port1); - if (cCurrentRomType == 'X') - { - if (Chipset.Port2) LocalFree(Chipset.Port2); - } - else - { - UnmapPort2(); - } + if (Chipset.Port2) LocalFree(Chipset.Port2); else UnmapPort2(); FillMemory(&Chipset,sizeof(Chipset),0); + FillMemory(&RMap,sizeof(RMap),0); // delete MMU mappings + FillMemory(&WMap,sizeof(WMap),0); UpdateWindowStatus(); return; } @@ -571,23 +550,25 @@ BOOL NewDocument(VOID) Chipset.Port0Size = (Chipset.type == 'A') ? 32 : 64; Chipset.Port1Size = 0; Chipset.Port2Size = 0; - Chipset.Port0 = (LPBYTE)LocalAlloc(0,Chipset.Port0Size*2048); - _ASSERT(Chipset.Port0 != NULL); - FillMemory(Chipset.Port0, Chipset.Port0Size*2048, 0); - Chipset.Port1 = NULL; - Chipset.Port2 = NULL; + Chipset.cards_status = 0x0; } + if (Chipset.type == 'E') // HP39/40G + { + Chipset.Port0Size = 128; + Chipset.Port1Size = 0; + Chipset.Port2Size = 128; + + Chipset.cards_status = 0xF; + + bPort2Writeable = TRUE; // port2 is writeable + } if (Chipset.type == 'S') // HP48SX { Chipset.Port0Size = 32; Chipset.Port1Size = 128; - Chipset.Port0 = (LPBYTE)LocalAlloc(0,Chipset.Port0Size*2048); - _ASSERT(Chipset.Port0 != NULL); - FillMemory(Chipset.Port0, Chipset.Port0Size*2048, 0); - Chipset.Port1 = (LPBYTE)LocalAlloc(0,Chipset.Port1Size*2048); - _ASSERT(Chipset.Port1 != NULL); - FillMemory(Chipset.Port1, Chipset.Port1Size*2048, 0); + Chipset.Port2Size = 0; + Chipset.cards_status = 0x5; // use 2nd command line argument if defined @@ -597,12 +578,8 @@ BOOL NewDocument(VOID) { Chipset.Port0Size = 128; Chipset.Port1Size = 128; - Chipset.Port0 = (LPBYTE)LocalAlloc(0,Chipset.Port0Size*2048); - _ASSERT(Chipset.Port0 != NULL); - FillMemory(Chipset.Port0, Chipset.Port0Size*2048, 0); - Chipset.Port1 = (LPBYTE)LocalAlloc(0,Chipset.Port1Size*2048); - _ASSERT(Chipset.Port1 != NULL); - FillMemory(Chipset.Port1, Chipset.Port1Size*2048, 0); + Chipset.Port2Size = 0; + Chipset.cards_status = 0xA; // use 2nd command line argument if defined @@ -613,21 +590,30 @@ BOOL NewDocument(VOID) Chipset.Port0Size = 256; Chipset.Port1Size = 128; Chipset.Port2Size = 128; - Chipset.Port0 = (LPBYTE)LocalAlloc(0,Chipset.Port0Size*2048); - _ASSERT(Chipset.Port0 != NULL); - FillMemory(Chipset.Port0, Chipset.Port0Size*2048, 0); - Chipset.Port1 = (LPBYTE)LocalAlloc(0,Chipset.Port1Size*2048); - _ASSERT(Chipset.Port1 != NULL); - FillMemory(Chipset.Port1, Chipset.Port1Size*2048, 0); - Chipset.Port2 = (LPBYTE)LocalAlloc(0,Chipset.Port2Size*2048); - _ASSERT(Chipset.Port2 != NULL); - FillMemory(Chipset.Port2, Chipset.Port2Size*2048, 0); - bPort2Writeable = TRUE; Chipset.cards_status = 0xF; + bPort2Writeable = TRUE; // port2 is writeable FlashInit(); // init flash structure } + + // allocate port memory + if (Chipset.Port0Size) + { + Chipset.Port0 = (LPBYTE)LocalAlloc(LPTR,Chipset.Port0Size*2048); + _ASSERT(Chipset.Port0 != NULL); + } + if (Chipset.Port1Size) + { + Chipset.Port1 = (LPBYTE)LocalAlloc(LPTR,Chipset.Port1Size*2048); + _ASSERT(Chipset.Port1 != NULL); + } + if (Chipset.Port2Size) + { + Chipset.Port2 = (LPBYTE)LocalAlloc(LPTR,Chipset.Port2Size*2048); + _ASSERT(Chipset.Port2 != NULL); + } + LoadBreakpointList(NULL); // clear debugger breakpoint list RomSwitch(0); // boot ROM view of HP49G and map memory SaveBackup(); return TRUE; @@ -636,7 +622,7 @@ restore: ResetBackup(); // HP48SX/GX - if(Chipset.type != '6' && Chipset.type != 'A' && Chipset.type != 'X') + if(Chipset.type == 'S' || Chipset.type == 'G') { // use 2nd command line argument if defined MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); @@ -649,7 +635,7 @@ restore: return FALSE; } -BOOL OpenDocument(LPCSTR szFilename) +BOOL OpenDocument(LPCTSTR szFilename) { HANDLE hFile = INVALID_HANDLE_VALUE; DWORD lBytesRead; @@ -665,13 +651,13 @@ BOOL OpenDocument(LPCSTR szFilename) // Open file if (lstrcmpi(szBackupFilename, szFilename)==0) { - if (YesNoMessage("Do you want to reload this document ?") == IDNO) + if (YesNoMessage(_T("Do you want to reload this document ?")) == IDNO) goto restore; } hFile = CreateFile(szFilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { - AbortMessage("This file is missing or already loaded in another instance of Emu48.\n"); + AbortMessage(_T("This file is missing or already loaded in another instance of Emu48.")); goto restore; } @@ -681,13 +667,13 @@ BOOL OpenDocument(LPCSTR szFilename) { case 'E': pbySig = (pbyFileSignature[3] == '3') - ? pbySignatureA + ? ((pbyFileSignature[4] == '8') ? pbySignatureA : pbySignatureB) : ((pbyFileSignature[4] == '8') ? pbySignatureE : pbySignatureV); for (ctBytesCompared=0; ctBytesCompared<14; ctBytesCompared++) { if (pbyFileSignature[ctBytesCompared]!=pbySig[ctBytesCompared]) { - AbortMessage("This file is not a valid Emu48 document."); + AbortMessage(_T("This file is not a valid Emu48 document.")); goto restore; } } @@ -697,29 +683,45 @@ BOOL OpenDocument(LPCSTR szFilename) { if (pbyFileSignature[ctBytesCompared]!=pbySignatureW[ctBytesCompared]) { - AbortMessage("This file is not a valid Win48 document."); + AbortMessage(_T("This file is not a valid Win48 document.")); goto restore; } } break; default: - AbortMessage("This file is not a valid document."); + AbortMessage(_T("This file is not a valid document.")); goto restore; } switch (pbyFileSignature[14]) { case 0xFE: // Win48 2.1 / Emu4x 0.99.x format - ReadFile(hFile, &nLength, sizeof(nLength), &lBytesRead, NULL); - ReadFile(hFile, szCurrentKml, nLength, &lBytesRead, NULL); + ReadFile(hFile,&nLength,sizeof(nLength),&lBytesRead,NULL); + #if defined _UNICODE + { + LPSTR szTmp = LocalAlloc(LMEM_FIXED,nLength); + if (szTmp == NULL) + { + AbortMessage(_T("Memory Allocation Failure.")); + goto restore; + } + ReadFile(hFile, szTmp, nLength, &lBytesRead, NULL); + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTmp, lBytesRead, + szCurrentKml, ARRAYSIZEOF(szCurrentKml)); + LocalFree(szTmp); + } + #else + { + ReadFile(hFile, szCurrentKml, nLength, &lBytesRead, NULL); + } + #endif if (nLength != lBytesRead) goto read_err; szCurrentKml[nLength] = 0; break; case 0xFF: // Win48 2.05 format break; default: - AbortMessage("This file is for an unknown version of Emu48.\n" - "Please contact the author (see Emu48.txt)."); + AbortMessage(_T("This file is for an unknown version of Emu48.")); goto restore; } @@ -727,7 +729,7 @@ BOOL OpenDocument(LPCSTR szFilename) if (lBytesRead != sizeof(lSizeofChipset)) goto read_err; if (lSizeofChipset!=sizeof(CHIPSET)) { - AbortMessage("This file is probably corrupted, and cannot be loaded."); + AbortMessage(_T("This file is probably corrupted, and cannot be loaded.")); goto restore; } @@ -744,8 +746,15 @@ BOOL OpenDocument(LPCSTR szFilename) if (!DisplayChooseKml(Chipset.type)) goto restore; } - while (!InitKML(szCurrentKml,FALSE)) + while (TRUE) { + BOOL bOK; + + bOK = InitKML(szCurrentKml,FALSE); + bOK = bOK && (cCurrentRomType == Chipset.type); + if (bOK) break; + + KillKML(); if (!DisplayChooseKml(Chipset.type)) goto restore; } @@ -757,7 +766,7 @@ BOOL OpenDocument(LPCSTR szFilename) Chipset.Port0 = (LPBYTE)LocalAlloc(0,Chipset.Port0Size*2048); if (Chipset.Port0 == NULL) { - AbortMessage("Memory Allocation Failure."); + AbortMessage(_T("Memory Allocation Failure.")); goto restore; } @@ -770,7 +779,7 @@ BOOL OpenDocument(LPCSTR szFilename) Chipset.Port1 = (LPBYTE)LocalAlloc(0,Chipset.Port1Size*2048); if (Chipset.Port1 == NULL) { - AbortMessage("Memory Allocation Failure."); + AbortMessage(_T("Memory Allocation Failure.")); goto restore; } @@ -778,32 +787,29 @@ BOOL OpenDocument(LPCSTR szFilename) if (lBytesRead != Chipset.Port1Size*2048) goto read_err; } - if (cCurrentRomType!='X') // HP38G, HP48SX/GX + // HP48SX/GX + if(cCurrentRomType=='S' || cCurrentRomType=='G') { - // HP48SX/GX - if(cCurrentRomType!='6' && cCurrentRomType!='A') + MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); + // port2 changed and card detection enabled + if ( Chipset.wPort2Crc != CrcPort2() + && (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0 + ) { - MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); - // port2 changed and card detection enabled - if ( Chipset.wPort2Crc != CrcPort2() - && (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0 - ) - { - Chipset.HST |= MP; // set Module Pulled - IOBit(SRQ2,NINT,FALSE); // set NINT to low - Chipset.SoftInt = TRUE; // set interrupt - bInterrupt = TRUE; - } + Chipset.HST |= MP; // set Module Pulled + IOBit(SRQ2,NINT,FALSE); // set NINT to low + Chipset.SoftInt = TRUE; // set interrupt + bInterrupt = TRUE; } } - else // HP49G + else // HP38G, HP39/40G, HP49G { if (Chipset.Port2Size) { Chipset.Port2 = (LPBYTE)LocalAlloc(0,Chipset.Port2Size*2048); if (Chipset.Port2 == NULL) { - AbortMessage("Memory Allocation Failure."); + AbortMessage(_T("Memory Allocation Failure.")); goto restore; } @@ -815,10 +821,14 @@ BOOL OpenDocument(LPCSTR szFilename) } } + LoadBreakpointList(hFile); // load debugger breakpoint list RomSwitch(Chipset.Bank_FF); // reload ROM view of HP49G and map memory if (Chipset.wRomCrc != CrcRom()) // ROM changed + { CpuReset(); + Chipset.Shutdn = FALSE; // automatic restart + } lstrcpy(szCurrentFilename, szFilename); _ASSERT(hCurrentFile == NULL); @@ -828,7 +838,7 @@ BOOL OpenDocument(LPCSTR szFilename) return TRUE; read_err: - AbortMessage("This file must be truncated, and cannot be loaded."); + AbortMessage(_T("This file must be truncated, and cannot be loaded.")); restore: if (INVALID_HANDLE_VALUE != hFile) // close if valid handle CloseHandle(hFile); @@ -836,7 +846,7 @@ restore: ResetBackup(); // HP48SX/GX - if(cCurrentRomType!='6' && cCurrentRomType!='A' && cCurrentRomType!='X') + if(cCurrentRomType=='S' || cCurrentRomType=='G') { // use 2nd command line argument if defined MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); @@ -846,42 +856,62 @@ restore: BOOL SaveDocument(VOID) { - DWORD lBytesWritten; - DWORD lSizeofChipset; - LPBYTE pbySig; - UINT nLength; - RECT Rect; + DWORD lBytesWritten; + DWORD lSizeofChipset; + LPBYTE pbySig; + UINT nLength; + WINDOWPLACEMENT wndpl; if (hCurrentFile == NULL) return FALSE; - GetWindowRect(hWnd, &Rect); // update saved window position - Chipset.nPosX = (SWORD)Rect.left; - Chipset.nPosY = (SWORD)Rect.top; + _ASSERT(hWnd); // window open + wndpl.length = sizeof(wndpl); // update saved window position + GetWindowPlacement(hWnd, &wndpl); + Chipset.nPosX = (SWORD) wndpl.rcNormalPosition.left; + Chipset.nPosY = (SWORD) wndpl.rcNormalPosition.top; - SetFilePointer(hCurrentFile,0,0,FILE_BEGIN); + SetFilePointer(hCurrentFile,0,NULL,FILE_BEGIN); // get document signature pbySig = (Chipset.type=='6' || Chipset.type=='A') - ? pbySignatureA : ((Chipset.type!='X') ? pbySignatureE : pbySignatureV); + ? pbySignatureA : (Chipset.type=='E' ? pbySignatureB : ((Chipset.type!='X') ? pbySignatureE : pbySignatureV)); if (!WriteFile(hCurrentFile, pbySig, 16, &lBytesWritten, NULL)) { - AbortMessage("Could not write into file !"); + AbortMessage(_T("Could not write into file !")); return FALSE; } Chipset.wRomCrc = CrcRom(); // save fingerprint of ROM Chipset.wPort2Crc = CrcPort2(); // save fingerprint of port2 - nLength = strlen(szCurrentKml); + nLength = lstrlen(szCurrentKml); WriteFile(hCurrentFile, &nLength, sizeof(nLength), &lBytesWritten, NULL); - WriteFile(hCurrentFile, szCurrentKml, nLength, &lBytesWritten, NULL); + #if defined _UNICODE + { + LPSTR szTmp = LocalAlloc(LMEM_FIXED,nLength); + if (szTmp != NULL) + { + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, + szCurrentKml, nLength, + szTmp, nLength, NULL, NULL); + WriteFile(hCurrentFile, szTmp, nLength, &lBytesWritten, NULL); + LocalFree(szTmp); + } + } + #else + { + WriteFile(hCurrentFile, szCurrentKml, nLength, &lBytesWritten, NULL); + } + #endif lSizeofChipset = sizeof(CHIPSET); WriteFile(hCurrentFile, &lSizeofChipset, sizeof(lSizeofChipset), &lBytesWritten, NULL); WriteFile(hCurrentFile, &Chipset, lSizeofChipset, &lBytesWritten, NULL); if (Chipset.Port0Size) WriteFile(hCurrentFile, Chipset.Port0, Chipset.Port0Size*2048, &lBytesWritten, NULL); if (Chipset.Port1Size) WriteFile(hCurrentFile, Chipset.Port1, Chipset.Port1Size*2048, &lBytesWritten, NULL); - if (cCurrentRomType=='X' && Chipset.Port2Size) WriteFile(hCurrentFile, Chipset.Port2, Chipset.Port2Size*2048, &lBytesWritten, NULL); + if (Chipset.Port2Size) WriteFile(hCurrentFile, Chipset.Port2, Chipset.Port2Size*2048, &lBytesWritten, NULL); + SaveBreakpointList(hCurrentFile); // save debugger breakpoint list + SetEndOfFile(hCurrentFile); // cut the rest return TRUE; } @@ -897,7 +927,7 @@ BOOL SaveDocumentAs(LPCTSTR szFilename) hFile = CreateFile(szFilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file { - AbortMessage("This file must be currently used by another instance of Emu48."); + AbortMessage(_T("This file must be currently used by another instance of Emu48.")); return FALSE; } lstrcpy(szCurrentFilename, szFilename); // save new file name @@ -937,7 +967,7 @@ BOOL SaveBackup(VOID) BackupChipset.Port1 = (LPBYTE)LocalAlloc(0,Chipset.Port1Size*2048); CopyMemory(BackupChipset.Port1, Chipset.Port1, Chipset.Port1Size*2048); BackupChipset.Port2 = NULL; - if (cCurrentRomType=='X') // HP49G + if (Chipset.Port2Size) // internal port2 { BackupChipset.Port2 = (LPBYTE)LocalAlloc(0,Chipset.Port2Size*2048); CopyMemory(BackupChipset.Port2, Chipset.Port2, Chipset.Port2Size*2048); @@ -973,7 +1003,7 @@ BOOL RestoreBackup(VOID) CopyMemory(Chipset.Port0, BackupChipset.Port0, Chipset.Port0Size*2048); Chipset.Port1 = (LPBYTE)LocalAlloc(0,Chipset.Port1Size*2048); CopyMemory(Chipset.Port1, BackupChipset.Port1, Chipset.Port1Size*2048); - if (cCurrentRomType=='X') // HP49G + if (Chipset.Port2Size) // internal port2 { Chipset.Port2 = (LPBYTE)LocalAlloc(0,Chipset.Port2Size*2048); CopyMemory(Chipset.Port2, BackupChipset.Port2, Chipset.Port2Size*2048); @@ -981,7 +1011,7 @@ BOOL RestoreBackup(VOID) // map port2 else { - if(cCurrentRomType!='6' && cCurrentRomType!='A') // HP48SX/GX + if(cCurrentRomType=='S' || cCurrentRomType=='G') // HP48SX/GX { // use 2nd command line argument if defined MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); @@ -1030,28 +1060,28 @@ BOOL GetOpenFilename(VOID) InitializeOFN(&ofn); ofn.lpstrFilter = - "Emu38 Document (*.E38)\0*.E38\0" - "Emu48 Document (*.E48)\0*.E48\0" - "Emu49 Document (*.E49)\0*.E49\0" - "Win48 Document (*.W48)\0*.W48\0" - "\0\0"; - if (cCurrentRomType!='X') // HP38G / HP48SX/GX + _T("Emu38 Document (*.E38)\0*.E38\0") + _T("Emu39 Document (*.E39)\0*.E39\0") + _T("Emu48 Document (*.E48)\0*.E48\0") + _T("Emu49 Document (*.E49)\0*.E49\0") + _T("Win48 Document (*.W48)\0*.W48\0") + _T("\0\0"); + ofn.lpstrDefExt = _T("E48"); // HP48SX/GX + ofn.nFilterIndex = 3; + if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G { - if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G - { - ofn.lpstrDefExt = "E38"; - ofn.nFilterIndex = 1; - } - else - { - ofn.lpstrDefExt = "E48"; - ofn.nFilterIndex = 2; - } + ofn.lpstrDefExt = _T("E38"); + ofn.nFilterIndex = 1; } - else // HP49G + if (cCurrentRomType=='E') // HP39/40G { - ofn.lpstrDefExt = "E49"; - ofn.nFilterIndex = 3; + ofn.lpstrDefExt = _T("E39"); + ofn.nFilterIndex = 2; + } + if (cCurrentRomType=='X') // HP49G + { + ofn.lpstrDefExt = _T("E49"); + ofn.nFilterIndex = 4; } ofn.lpstrFile = LocalAlloc(0,512); ofn.lpstrFile[0] = 0; @@ -1073,28 +1103,28 @@ BOOL GetSaveAsFilename(VOID) InitializeOFN(&ofn); ofn.lpstrFilter = - "Emu38 Document (*.E38)\0*.E38\0" - "Emu48 Document (*.E48)\0*.E48\0" - "Emu49 Document (*.E49)\0*.E49\0" - "Win48 Document (*.W48)\0*.W48\0" - "\0\0"; - if (cCurrentRomType!='X') // HP38G / HP48SX/GX + _T("Emu38 Document (*.E38)\0*.E38\0") + _T("Emu39 Document (*.E39)\0*.E39\0") + _T("Emu48 Document (*.E48)\0*.E48\0") + _T("Emu49 Document (*.E49)\0*.E49\0") + _T("Win48 Document (*.W48)\0*.W48\0") + _T("\0\0"); + ofn.lpstrDefExt = _T("E48"); // HP48SX/GX + ofn.nFilterIndex = 3; + if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G { - if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G - { - ofn.lpstrDefExt = "E38"; - ofn.nFilterIndex = 1; - } - else - { - ofn.lpstrDefExt = "E48"; - ofn.nFilterIndex = 2; - } + ofn.lpstrDefExt = _T("E38"); + ofn.nFilterIndex = 1; } - else // HP49G + if (cCurrentRomType=='E') // HP39/40G { - ofn.lpstrDefExt = "E49"; - ofn.nFilterIndex = 3; + ofn.lpstrDefExt = _T("E39"); + ofn.nFilterIndex = 2; + } + if (cCurrentRomType=='X') // HP49G + { + ofn.lpstrDefExt = _T("E49"); + ofn.nFilterIndex = 4; } ofn.lpstrFile = LocalAlloc(0,512); ofn.lpstrFile[0] = 0; @@ -1115,7 +1145,7 @@ BOOL GetLoadObjectFilename(VOID) OPENFILENAME ofn; InitializeOFN(&ofn); - ofn.lpstrFilter = "All Files (*.*)\0*.*\0" "\0\0"; + ofn.lpstrFilter = _T("All Files (*.*)\0*.*\0") _T("\0\0"); ofn.nFilterIndex = 1; ofn.lpstrFile = LocalAlloc(0,512); ofn.lpstrFile[0] = 0; @@ -1136,7 +1166,7 @@ BOOL GetSaveObjectFilename(VOID) OPENFILENAME ofn; InitializeOFN(&ofn); - ofn.lpstrFilter = "All Files (*.*)\0*.*\0" "\0\0"; + ofn.lpstrFilter = _T("All Files (*.*)\0*.*\0") _T("\0\0"); ofn.nFilterIndex = 1; ofn.lpstrFile = LocalAlloc(0,512); ofn.lpstrFile[0] = 0; @@ -1160,7 +1190,7 @@ BOOL GetSaveObjectFilename(VOID) //# //################ -BOOL LoadObject(LPCSTR szFilename) // separated stack writing part +BOOL LoadObject(LPCTSTR szFilename) // separated stack writing part { HANDLE hFile; DWORD dwFileSizeLow; @@ -1188,16 +1218,16 @@ BOOL LoadObject(LPCSTR szFilename) // separated stack writing part wError = WriteStack(lpBuf,dwFileSizeLow); if (wError == S_ERR_BINARY) - AbortMessage("The HP48 has not enough free memory left to load this binary file."); + AbortMessage(_T("The HP48 has not enough free memory left to load this binary file.")); if (wError == S_ERR_ASCII) - AbortMessage("The HP48 has not enough free memory left to load this text file."); + AbortMessage(_T("The HP48 has not enough free memory left to load this text file.")); LocalFree(lpBuf); return (wError == S_ERR_NO); } -BOOL SaveObject(LPCSTR szFilename) // separated stack reading part +BOOL SaveObject(LPCTSTR szFilename) // separated stack reading part { HANDLE hFile; LPBYTE pbyHeader; @@ -1208,7 +1238,7 @@ BOOL SaveObject(LPCSTR szFilename) // separated stack reading part dwAddress = RPL_Pick(1); if (dwAddress == 0) { - AbortMessage("Too Few Arguments."); + AbortMessage(_T("Too Few Arguments.")); return FALSE; } dwLength = (RPL_SkipOb(dwAddress) - dwAddress + 1) / 2; @@ -1216,7 +1246,7 @@ BOOL SaveObject(LPCSTR szFilename) // separated stack reading part hFile = CreateFile(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hFile == INVALID_HANDLE_VALUE) { - AbortMessage("Cannot open file."); + AbortMessage(_T("Cannot open file.")); return FALSE; } @@ -1267,7 +1297,7 @@ static HPALETTE CreateBIPalette(LPBITMAPINFOHEADER lpbi) return NULL; // Get a pointer to the color table and the number of colors in it - pRgb = (RGBQUAD FAR *)((LPSTR)lpbi + (WORD)lpbi->biSize); + pRgb = (RGBQUAD FAR *)((LPBYTE)lpbi + (WORD)lpbi->biSize); nNumColors = DibNumColors(lpbi); if (nNumColors) @@ -1328,7 +1358,7 @@ static HPALETTE CreateBIPalette(LPBITMAPINFOHEADER lpbi) return hpal; } -HBITMAP LoadBitmapFile(LPCSTR szFilename) +HBITMAP LoadBitmapFile(LPCTSTR szFilename) { HANDLE hFile; HANDLE hMap; diff --git a/sources/Emu48/I28F160.C b/sources/Emu48/I28F160.C index 14948f4..c7d7408 100644 --- a/sources/Emu48/I28F160.C +++ b/sources/Emu48/I28F160.C @@ -84,7 +84,7 @@ static VOID WrStateB8D(BYTE a, DWORD d); static VOID WrState60(DWORD d); static VOID WrState60D(BYTE a, DWORD d); -static CONST VOID (*CONST fnWrState[])(BYTE a, DWORD d) = +static VOID (*CONST fnWrState[])(BYTE a, DWORD d) = { WrStateIdle, WrStateE8N, WrStateE8D, WrStateE8C, @@ -102,7 +102,7 @@ static BYTE RdStateQuery(DWORD d); static BYTE RdStateSR(DWORD d); static BYTE RdStateXSR(DWORD d); -static CONST BYTE (*CONST fnRdState[])(DWORD d) = +static BYTE (*CONST fnRdState[])(DWORD d) = { RdStateData, RdStateId, RdStateQuery, RdStateSR, RdStateXSR }; diff --git a/sources/Emu48/IO.H b/sources/Emu48/IO.H index d4729df..37cdf88 100644 --- a/sources/Emu48/IO.H +++ b/sources/Emu48/IO.H @@ -8,6 +8,7 @@ */ // I/O addresses without mapping offset +#define BITOFFSET 0x00 // Display bit offset and DON #define CRC 0x04 // Crc (16 bit, LSB first) #define ANNCTRL 0x0b // Annunciator Control (2 nibble) #define BAUD 0x0d // Baudrate (Bit 2-0) @@ -25,11 +26,18 @@ #define SRQ2 0x19 // SRQ2 #define IR_CTRL 0x1a // IR CONTROL #define LCR 0x1c // Led Control Register +#define LINECOUNT 0x28 // Display Line Counter #define TIMER1_CTRL 0x2e // Timer1 Control #define TIMER2_CTRL 0x2f // Timer2 Control #define TIMER1 0x37 // Timer1 (4 bit) #define TIMER2 0x38 // Timer2 (32 bit, LSB first) +// 0x00 Display bit offset and DON [DON OFF2 OFF1 OFF0] +#define DON 0x08 // Display On +#define OFF2 0x04 // Display OFFset Bit2 +#define OFF1 0x02 // Display OFFset Bit1 +#define OFF0 0x01 // Display OFFset Bit0 + // 0x0b Annunciator Control [AON XTRA LA6 LA5] [LA4 LA3 LA2 LA1] #define AON 0x80 // Annunciators on #define LXTRA 0x40 // does nothing @@ -94,6 +102,18 @@ #define LBZ 0x02 // Led Port Busy #define LBF 0x01 // Led Buffer Full +// 0x28 Display Line Counter LSB [LC3 LC2 LC1 LC0] +#define LC3 0x08 // LC3 - Line Counter Bit3 +#define LC2 0x04 // LC2 - Line Counter Bit2 +#define LC1 0x02 // LC1 - Line Counter Bit1 +#define LC0 0x01 // LC0 - Line Counter Bit0 + +// 0x29 Display Line Counter MSB [DA19 M32 LC5 LC4] +#define DA19 0x08 // Drive A[19] +#define M32 0x04 // Multiplex 32 way +#define LC5 0x02 // LC5 - Line Counter Bit5 +#define LC4 0x01 // LC4 - Line Counter Bit4 + // 0x2e Timer1 Control [SRQ WKE INT XTRA] #define SRQ 0x08 // Service request #define WKE 0x04 // Wake up diff --git a/sources/Emu48/KEYBOARD.C b/sources/Emu48/KEYBOARD.C index 42152fa..2c2fc1f 100644 --- a/sources/Emu48/KEYBOARD.C +++ b/sources/Emu48/KEYBOARD.C @@ -83,7 +83,7 @@ VOID ScanKeyboard(BOOL bReset) VOID KeyboardEvent(BOOL bPress, UINT out, UINT in) { - if (nState != 0) // not in running state + if (nState != SM_RUN) // not in running state return; // ignore key if (in == 0x8000) // ON key ? { diff --git a/sources/Emu48/KML.C b/sources/Emu48/KML.C index a301cb4..6894ec1 100644 --- a/sources/Emu48/KML.C +++ b/sources/Emu48/KML.C @@ -12,96 +12,96 @@ #include "kml.h" static VOID FatalError(); -static VOID InitLex(LPSTR szScript); +static VOID InitLex(LPTSTR szScript); static VOID CleanLex(); -static BOOL IsDigit(CHAR cChar); static VOID SkipWhite(UINT nMode); static TokenId ParseToken(UINT nMode); static DWORD ParseInteger(); -static LPSTR ParseString(); +static LPTSTR ParseString(); static TokenId Lex(UINT nMode); static Line* ParseLine(TokenId eCommand); -static Line* IncludeLines(LPCSTR szFilename); +static Line* IncludeLines(LPCTSTR szFilename); static Line* ParseLines(); static Block* ParseBlock(TokenId eBlock); -static Block* IncludeBlocks(LPCSTR szFilename); +static Block* IncludeBlocks(LPCTSTR szFilename); static Block* ParseBlocks(); static VOID FreeLines(Line* pLine); static VOID PressButton(UINT nId); static VOID ReleaseButton(UINT nId); static VOID PressButtonById(UINT nId); static VOID ReleaseButtonById(UINT nId); -static LPSTR GetStringParam(Block* pBlock, TokenId eBlock, enum eCommand, UINT nParam); -static DWORD GetIntegerParam(Block* pBlock, TokenId eBlock, enum eCommand, UINT nParam); -static Line* SkipLines(Line* pLine, enum eCommand); +static LPTSTR GetStringParam(Block* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam); +static DWORD GetIntegerParam(Block* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam); +static Line* SkipLines(Line* pLine, TokenId eCommand); static Line* If(Line* pLine, BOOL bCondition); static Line* RunLine(Line* pLine); -static Block* LoadKMLGlobal(LPCSTR szFilename); +static Block* LoadKMLGlobal(LPCTSTR szFilename); Block* pKml; -static Block* pVKey[256]; -static BYTE byVKeyMap[256]; -static Button pButton[256]; +static Block* pVKey[256]; +static BYTE byVKeyMap[256]; +static Button pButton[256]; static Annunciator pAnnunciator[6]; -static UINT nButtons = 0; -static UINT nScancodes = 0; -static UINT nAnnunciators = 0; -static BOOL bDebug = TRUE; -static UINT nLexLine; -static UINT nLexInteger; -static UINT nBlocksIncludeLevel; -static UINT nLinesIncludeLevel; -static DWORD nKMLFlags = 0; -static LPSTR szLexString; -static LPSTR szText; -static LPSTR szLexDelim[] = +static UINT nButtons = 0; +static UINT nScancodes = 0; +static UINT nAnnunciators = 0; +static BOOL bDebug = TRUE; +static UINT nLexLine; +static UINT nLexInteger; +static UINT nBlocksIncludeLevel; +static UINT nLinesIncludeLevel; +static DWORD nKMLFlags = 0; +static LPTSTR szLexString; +static LPTSTR szText; +static LPTSTR szLexDelim[] = { - "", - " \t\n\r", - " \t\n\r", - " \t\r" + _T(""), + _T(" \t\n\r"), + _T(" \t\n\r"), + _T(" \t\r") }; static Token pLexToken[] = { - {TOK_ANNUNCIATOR,000001,11,"Annunciator"}, - {TOK_BACKGROUND, 000000,10,"Background"}, - {TOK_IFPRESSED, 000001, 9,"IfPressed"}, - {TOK_RESETFLAG, 000001, 9,"ResetFlag"}, - {TOK_SCANCODE, 000001, 8,"Scancode"}, - {TOK_MENUITEM, 000001, 8,"MenuItem"}, - {TOK_SETFLAG, 000001, 7,"SetFlag"}, - {TOK_RELEASE, 000001, 7,"Release"}, - {TOK_VIRTUAL, 000000, 7,"Virtual"}, - {TOK_INCLUDE, 000002, 7,"Include"}, - {TOK_NOTFLAG, 000001, 7,"NotFlag"}, - {TOK_GLOBAL, 000000, 6,"Global"}, - {TOK_AUTHOR, 000002, 6,"Author"}, - {TOK_BITMAP, 000002, 6,"Bitmap"}, - {TOK_OFFSET, 000011, 6,"Offset"}, - {TOK_BUTTON, 000001, 6,"Button"}, - {TOK_IFFLAG, 000001, 6,"IfFlag"}, - {TOK_ONDOWN, 000000, 6,"OnDown"}, - {TOK_NOHOLD, 000000, 6,"NoHold"}, - {TOK_TITLE, 000002, 5,"Title"}, - {TOK_OUTIN, 000011, 5,"OutIn"}, - {TOK_PATCH, 000002, 5,"Patch"}, - {TOK_PRINT, 000002, 5,"Print"}, - {TOK_DEBUG, 000001, 5,"Debug"}, - {TOK_COLOR, 001111, 5,"Color"}, - {TOK_MODEL, 000002, 5,"Model"}, - {TOK_PRESS, 000001, 5,"Press"}, - {TOK_TYPE, 000001, 4,"Type"}, - {TOK_SIZE, 000011, 4,"Size"}, - {TOK_ZOOM, 000001, 4,"Zoom"}, - {TOK_DOWN, 000011, 4,"Down"}, - {TOK_ELSE, 000000, 4,"Else"}, - {TOK_ONUP, 000000, 4,"OnUp"}, - {TOK_MAP, 000011, 3,"Map"}, - {TOK_ROM, 000002, 3,"Rom"}, - {TOK_LCD, 000000, 3,"Lcd"}, - {TOK_END, 000000, 3,"End"}, - {0, 000000, 0,""}, + {TOK_ANNUNCIATOR,000001,11,_T("Annunciator")}, + {TOK_BACKGROUND, 000000,10,_T("Background")}, + {TOK_IFPRESSED, 000001, 9,_T("IfPressed")}, + {TOK_RESETFLAG, 000001, 9,_T("ResetFlag")}, + {TOK_SCANCODE, 000001, 8,_T("Scancode")}, + {TOK_MENUITEM, 000001, 8,_T("MenuItem")}, + {TOK_SETFLAG, 000001, 7,_T("SetFlag")}, + {TOK_RELEASE, 000001, 7,_T("Release")}, + {TOK_VIRTUAL, 000000, 7,_T("Virtual")}, + {TOK_INCLUDE, 000002, 7,_T("Include")}, + {TOK_NOTFLAG, 000001, 7,_T("NotFlag")}, + {TOK_GLOBAL, 000000, 6,_T("Global")}, + {TOK_AUTHOR, 000002, 6,_T("Author")}, + {TOK_BITMAP, 000002, 6,_T("Bitmap")}, + {TOK_OFFSET, 000011, 6,_T("Offset")}, + {TOK_BUTTON, 000001, 6,_T("Button")}, + {TOK_IFFLAG, 000001, 6,_T("IfFlag")}, + {TOK_ONDOWN, 000000, 6,_T("OnDown")}, + {TOK_NOHOLD, 000000, 6,_T("NoHold")}, + {TOK_TITLE, 000002, 5,_T("Title")}, + {TOK_OUTIN, 000011, 5,_T("OutIn")}, + {TOK_PATCH, 000002, 5,_T("Patch")}, + {TOK_PRINT, 000002, 5,_T("Print")}, + {TOK_DEBUG, 000001, 5,_T("Debug")}, + {TOK_COLOR, 001111, 5,_T("Color")}, + {TOK_MODEL, 000002, 5,_T("Model")}, + {TOK_CLASS, 000001, 5,_T("Class")}, + {TOK_PRESS, 000001, 5,_T("Press")}, + {TOK_TYPE, 000001, 4,_T("Type")}, + {TOK_SIZE, 000011, 4,_T("Size")}, + {TOK_ZOOM, 000001, 4,_T("Zoom")}, + {TOK_DOWN, 000011, 4,_T("Down")}, + {TOK_ELSE, 000000, 4,_T("Else")}, + {TOK_ONUP, 000000, 4,_T("OnUp")}, + {TOK_MAP, 000011, 3,_T("Map")}, + {TOK_ROM, 000002, 3,_T("Rom")}, + {TOK_LCD, 000000, 3,_T("Lcd")}, + {TOK_END, 000000, 3,_T("End")}, + {0, 000000, 0,_T("")}, }; static TokenId eIsBlock[] = @@ -126,7 +126,7 @@ static UINT uLastPressedKey = 0; // var for last pressed key //################ static UINT nLogLength = 0; -static LPSTR szLog = NULL; +static LPTSTR szLog = NULL; static BOOL bKmlLogOkEnabled = FALSE; static VOID ClearLog() @@ -140,13 +140,13 @@ static VOID ClearLog() return; } -static VOID AddToLog(LPSTR szString) +static VOID AddToLog(LPTSTR szString) { - UINT nLength = strlen(szString); + UINT nLength = lstrlen(szString); if (szLog == NULL) { - nLogLength = nLength+3; - szLog = LocalAlloc(0,nLogLength); + nLogLength = nLength + 3; // CR+LF+\0 + szLog = LocalAlloc(LMEM_FIXED,nLogLength*sizeof(szLog[0])); if (szLog==NULL) { nLogLength = 0; @@ -156,24 +156,25 @@ static VOID AddToLog(LPSTR szString) } else { - szLog = LocalReAlloc(szLog,nLogLength+nLength+2,LMEM_MOVEABLE); - if (szLog == NULL) + LPTSTR szLogTmp = LocalReAlloc(szLog,(nLogLength+nLength+2)*sizeof(szLog[0]),LMEM_MOVEABLE); + if (szLogTmp == NULL) { - nLogLength = 0; + ClearLog(); return; } - lstrcpy(szLog+nLogLength-1,szString); - nLogLength += nLength+2; + szLog = szLogTmp; + lstrcpy(&szLog[nLogLength-1],szString); + nLogLength += nLength + 2; // CR+LF } - szLog[nLogLength-3] = 0x0D; - szLog[nLogLength-2] = 0x0A; + szLog[nLogLength-3] = _T('\r'); + szLog[nLogLength-2] = _T('\n'); szLog[nLogLength-1] = 0; return; } static VOID __cdecl PrintfToLog(LPCTSTR lpFormat, ...) { - LPSTR lpOutput; + LPTSTR lpOutput; va_list arglist; va_start(arglist,lpFormat); @@ -187,7 +188,7 @@ static VOID __cdecl PrintfToLog(LPCTSTR lpFormat, ...) static BOOL CALLBACK KMLLogProc(HWND hDlg, UINT message, DWORD wParam, LONG lParam) { - LPSTR szString; + LPTSTR szString; switch (message) { @@ -196,15 +197,15 @@ static BOOL CALLBACK KMLLogProc(HWND hDlg, UINT message, DWORD wParam, LONG lPar EnableWindow(GetDlgItem(hDlg,IDOK),bKmlLogOkEnabled); // set IDC_TITLE szString = GetStringParam(pKml, TOK_GLOBAL, TOK_TITLE, 0); - if (szString == NULL) szString = "Untitled"; + if (szString == NULL) szString = _T("Untitled"); SetDlgItemText(hDlg,IDC_TITLE,szString); // set IDC_AUTHOR szString = GetStringParam(pKml, TOK_GLOBAL, TOK_AUTHOR, 0); - if (szString == NULL) szString = ""; + if (szString == NULL) szString = _T(""); SetDlgItemText(hDlg,IDC_AUTHOR,szString); // set IDC_KMLLOG if (szLog == NULL) - SetDlgItemText(hDlg,IDC_KMLLOG,"Memory Allocation Failure."); + SetDlgItemText(hDlg,IDC_KMLLOG,_T("Memory Allocation Failure.")); else SetDlgItemText(hDlg,IDC_KMLLOG,szLog); // set IDC_ALWAYSDISPLOG @@ -240,8 +241,8 @@ BOOL DisplayKMLLog(BOOL bOkEnabled) typedef struct _KmlScript { - LPSTR szFilename; - LPSTR szTitle; + LPTSTR szFilename; + LPTSTR szTitle; DWORD nId; struct _KmlScript* pNext; } KmlScript; @@ -271,7 +272,7 @@ static VOID CreateKmlList() WIN32_FIND_DATA pFindFileData; SetCurrentDirectory(szEmu48Directory); - hFindFile = FindFirstFile("*.KML",&pFindFileData); + hFindFile = FindFirstFile(_T("*.KML"),&pFindFileData); SetCurrentDirectory(szCurrentDirectory); nKmlFiles = 0; if (hFindFile == INVALID_HANDLE_VALUE) return; @@ -279,7 +280,7 @@ static VOID CreateKmlList() { KmlScript* pScript; Block* pBlock; - LPSTR szTitle; + LPTSTR szTitle; pBlock = LoadKMLGlobal(pFindFileData.cFileName); if (pBlock == NULL) continue; @@ -330,8 +331,8 @@ static BOOL CALLBACK ChooseKMLProc(HWND hDlg, UINT message, DWORD wParam, LONG l return TRUE; case WM_SETTEXT: { - CHAR szBuffer[80]; - wsprintf(szBuffer,"%i %i %i", hDlg, wParam, lParam); + TCHAR szBuffer[80]; + wsprintf(szBuffer,_T("%i %i %i"), hDlg, wParam, lParam); InfoMessage(szBuffer); } break; @@ -396,6 +397,60 @@ BOOL DisplayChooseKml(CHAR cType) +//################ +//# +//# KML File Mapping +//# +//################ + +static LPTSTR MapKMLFile(HANDLE hFile) +{ + DWORD lBytesRead; + DWORD dwFileSizeLow; + DWORD dwFileSizeHigh; + LPTSTR lpBuf = NULL; + + dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); + if (dwFileSizeHigh != 0) + { + AddToLog(_T("File is too large.")); + goto fail; + } + + lpBuf = LocalAlloc(LMEM_FIXED,(dwFileSizeLow+1)*sizeof(lpBuf[0])); + if (lpBuf == NULL) + { + PrintfToLog(_T("Cannot allocate %i bytes."), (dwFileSizeLow+1)*sizeof(lpBuf[0])); + goto fail; + } + #if defined _UNICODE + { + LPSTR szTmp = LocalAlloc(LMEM_FIXED,dwFileSizeLow+1); + if (szTmp == NULL) + { + LocalFree(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); + LocalFree(szTmp); + } + #else + { + ReadFile(hFile, lpBuf, dwFileSizeLow, &lBytesRead, NULL); + } + #endif + lpBuf[dwFileSizeLow] = 0; + +fail: + CloseHandle(hFile); + return lpBuf; +} + + + //################ //# //# Script Parsing @@ -404,12 +459,12 @@ BOOL DisplayChooseKml(CHAR cType) static VOID FatalError() { - PrintfToLog("Fatal Error at line %i", nLexLine); + PrintfToLog(_T("Fatal Error at line %i"), nLexLine); szText[0] = 0; return; } -static VOID InitLex(LPSTR szScript) +static VOID InitLex(LPTSTR szScript) { nLexLine = 1; szText = szScript; @@ -446,20 +501,12 @@ static LPCTSTR GetStringOf(TokenId eId) if (pLexToken[i].eId == eId) return pLexToken[i].szName; i++; } - return ""; -} - -static BOOL IsDigit(CHAR cChar) -{ - if (cChar<'0') return FALSE; - if (cChar>'9') return FALSE; - return TRUE; + return _T(""); } static VOID SkipWhite(UINT nMode) { UINT i; - BOOL bStop = FALSE; loop: i = 0; while (szLexDelim[nMode][i]) @@ -469,13 +516,13 @@ loop: } if (szLexDelim[nMode][i] != 0) { - if (szLexDelim[nMode][i]=='\n') nLexLine++; + if (szLexDelim[nMode][i]==_T('\n')) nLexLine++; szText++; goto loop; } - if (*szText=='#') + if (*szText==_T('#')) { - do szText++; while (*szText != '\n'); + do szText++; while (*szText != _T('\n')); if (nMode != LEX_PARAM) goto loop; } return; @@ -493,7 +540,7 @@ static TokenId ParseToken(UINT nMode) if (szLexDelim[nMode][j] == szText[i]) break; j++; } - if (szLexDelim[nMode][j] == '\n') nLexLine++; + if (szLexDelim[nMode][j] == _T('\n')) nLexLine++; if (szLexDelim[nMode][j] != 0) break; i++; } @@ -511,7 +558,7 @@ static TokenId ParseToken(UINT nMode) } if (pLexToken[j].nLennParam[j++] = nLexInteger; @@ -640,14 +687,14 @@ loop: { if (eToken != TOK_STRING) { - PrintfToLog("%i: Parameter %i of %s must be a string.", nLexLine, j+1, pLexToken[i].szName); + PrintfToLog(_T("%i: Parameter %i of %s must be a string."), nLexLine, j+1, pLexToken[i].szName); goto errline; // free memory of arguments } pLine->nParam[j++] = (DWORD)szLexString; nParams >>= 3; goto loop; } - AddToLog("Oops..."); + AddToLog(_T("Oops...")); errline: // if last argument was string, free it if (eToken == TOK_STRING) LocalFree(szLexString); @@ -665,15 +712,12 @@ errline: return NULL; } -static Line* IncludeLines(LPCSTR szFilename) +static Line* IncludeLines(LPCTSTR szFilename) { HANDLE hFile; - DWORD dwFileSizeLow; - DWORD dwFileSizeHigh; - DWORD dwBytesRead; - LPBYTE lpbyBuf; + LPTSTR lpbyBuf; UINT uOldLine; - LPSTR szOldText; + LPTSTR szOldText; Line* pLine; SetCurrentDirectory(szEmu48Directory); @@ -681,35 +725,21 @@ static Line* IncludeLines(LPCSTR szFilename) SetCurrentDirectory(szCurrentDirectory); if (hFile == INVALID_HANDLE_VALUE) { - PrintfToLog("Error while opening include file %s.", szFilename); + PrintfToLog(_T("Error while opening include file %s."), szFilename); FatalError(); return NULL; } - dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); - if (dwFileSizeHigh != 0) - { // file is too large. - AddToLog("File is too large."); - CloseHandle(hFile); - FatalError(); - return NULL; - } - lpbyBuf = (LPBYTE)LocalAlloc(0,dwFileSizeLow+1); - if (lpbyBuf == NULL) + if ((lpbyBuf = MapKMLFile(hFile)) == NULL) { - PrintfToLog("Cannot allocate %i bytes.", dwFileSizeLow+1); - CloseHandle(hFile); FatalError(); return NULL; } - ReadFile(hFile, lpbyBuf, dwFileSizeLow, &dwBytesRead, NULL); - CloseHandle(hFile); - lpbyBuf[dwFileSizeLow] = 0; uOldLine = nLexLine; szOldText = szText; nLinesIncludeLevel++; - PrintfToLog("l%i:Including %s", nLinesIncludeLevel, szFilename); + PrintfToLog(_T("l%i:Including %s"), nLinesIncludeLevel, szFilename); InitLex(lpbyBuf); pLine = ParseLines(); CleanLex(); @@ -729,16 +759,16 @@ static Line* ParseLines() TokenId eToken; UINT nLevel = 0; - while (eToken = Lex(LEX_COMMAND)) + while ((eToken = Lex(LEX_COMMAND))) { if (IsBlock(eToken)) nLevel++; if (eToken == TOK_INCLUDE) { - LPSTR szFilename; + LPTSTR szFilename; eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString' if (eToken != TOK_STRING) // not a string (token don't begin with ") { - AddToLog("Include: string expected as parameter."); + AddToLog(_T("Include: string expected as parameter.")); FatalError(); goto abort; } @@ -785,7 +815,7 @@ static Line* ParseLines() if (pLine) pLine->pNext = NULL; return pFirst; } - AddToLog("Open block."); + AddToLog(_T("Open block.")); abort: if (pFirst) { @@ -817,14 +847,14 @@ static Block* ParseBlock(TokenId eType) switch (eToken) { case TOK_NONE: - AddToLog("Open Block at End Of File."); + AddToLog(_T("Open Block at End Of File.")); LocalFree(pBlock); FatalError(); return NULL; case TOK_INTEGER: if ((pLexToken[u1].nParams&7)!=TYPE_INTEGER) { - AddToLog("Wrong block argument."); + AddToLog(_T("Wrong block argument.")); LocalFree(pBlock); FatalError(); return NULL; @@ -832,7 +862,7 @@ static Block* ParseBlock(TokenId eType) pBlock->nId = nLexInteger; break; default: - AddToLog("Wrong block argument."); + AddToLog(_T("Wrong block argument.")); LocalFree(pBlock); FatalError(); return NULL; @@ -850,15 +880,12 @@ static Block* ParseBlock(TokenId eType) return pBlock; } -static Block* IncludeBlocks(LPCSTR szFilename) +static Block* IncludeBlocks(LPCTSTR szFilename) { HANDLE hFile; - DWORD dwFileSizeLow; - DWORD dwFileSizeHigh; - DWORD dwBytesRead; - LPBYTE lpbyBuf; + LPTSTR lpbyBuf; UINT uOldLine; - LPSTR szOldText; + LPTSTR szOldText; Block* pFirst; SetCurrentDirectory(szEmu48Directory); @@ -866,35 +893,21 @@ static Block* IncludeBlocks(LPCSTR szFilename) SetCurrentDirectory(szCurrentDirectory); if (hFile == INVALID_HANDLE_VALUE) { - PrintfToLog("Error while opening include file %s.", szFilename); + PrintfToLog(_T("Error while opening include file %s."), szFilename); FatalError(); return NULL; } - dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); - if (dwFileSizeHigh != 0) - { // file is too large. - AddToLog("File is too large."); - CloseHandle(hFile); - FatalError(); - return NULL; - } - lpbyBuf = (LPBYTE)LocalAlloc(0,dwFileSizeLow+1); - if (lpbyBuf == NULL) + if ((lpbyBuf = MapKMLFile(hFile)) == NULL) { - PrintfToLog("Cannot allocate %i bytes.", dwFileSizeLow+1); - CloseHandle(hFile); FatalError(); return NULL; } - ReadFile(hFile, lpbyBuf, dwFileSizeLow, &dwBytesRead, NULL); - CloseHandle(hFile); - lpbyBuf[dwFileSizeLow] = 0; uOldLine = nLexLine; szOldText = szText; nBlocksIncludeLevel++; - PrintfToLog("b%i:Including %s", nBlocksIncludeLevel, szFilename); + PrintfToLog(_T("b%i:Including %s"), nBlocksIncludeLevel, szFilename); InitLex(lpbyBuf); pFirst = ParseBlocks(); CleanLex(); @@ -917,11 +930,11 @@ static Block* ParseBlocks() { if (eToken == TOK_INCLUDE) { - LPSTR szFilename; + LPTSTR szFilename; eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString' if (eToken != TOK_STRING) // not a string (token don't begin with ") { - AddToLog("Include: string expected as parameter."); + AddToLog(_T("Include: string expected as parameter.")); FatalError(); goto abort; } @@ -942,7 +955,7 @@ static Block* ParseBlocks() pBlock = pFirst = ParseBlock(eToken); if (pBlock == NULL) { - AddToLog("Invalid block."); + AddToLog(_T("Invalid block.")); FatalError(); goto abort; } @@ -970,64 +983,68 @@ static VOID InitGlobal(Block* pBlock) switch (pLine->eCommand) { case TOK_TITLE: - PrintfToLog("Title: %s", (LPSTR)pLine->nParam[0]); + PrintfToLog(_T("Title: %s"), (LPTSTR)pLine->nParam[0]); break; case TOK_AUTHOR: - PrintfToLog("Author: %s", (LPSTR)pLine->nParam[0]); + PrintfToLog(_T("Author: %s"), (LPTSTR)pLine->nParam[0]); break; case TOK_PRINT: - AddToLog((LPSTR)pLine->nParam[0]); + AddToLog((LPTSTR)pLine->nParam[0]); break; case TOK_MODEL: - cCurrentRomType = ((LPSTR)pLine->nParam[0])[0]; - PrintfToLog("Calculator Model : %c", cCurrentRomType); + cCurrentRomType = ((BYTE *)pLine->nParam[0])[0]; + PrintfToLog(_T("Calculator Model : %c"), cCurrentRomType); + break; + case TOK_CLASS: + nCurrentClass = pLine->nParam[0]; + PrintfToLog(_T("Calculator Class : %u"), nCurrentClass); break; case TOK_DEBUG: bDebug = pLine->nParam[0]&1; - PrintfToLog("Debug %s", bDebug?"On":"Off"); + PrintfToLog(_T("Debug %s"), bDebug?_T("On"):_T("Off")); break; case TOK_ROM: if (pbyRom != NULL) { - PrintfToLog("Rom %s Ignored.", (LPSTR)pLine->nParam[0]); - AddToLog("Please put only one Rom command in the Global block."); + PrintfToLog(_T("Rom %s Ignored."), (LPTSTR)pLine->nParam[0]); + AddToLog(_T("Please put only one Rom command in the Global block.")); break; } - if (!MapRom((LPSTR)pLine->nParam[0])) + if (!MapRom((LPTSTR)pLine->nParam[0])) { - PrintfToLog("Cannot open Rom %s", (LPSTR)pLine->nParam[0]); + PrintfToLog(_T("Cannot open Rom %s"), (LPTSTR)pLine->nParam[0]); break; } - PrintfToLog("Rom %s Loaded.", (LPSTR)pLine->nParam[0]); + PrintfToLog(_T("Rom %s Loaded."), (LPTSTR)pLine->nParam[0]); break; case TOK_PATCH: if (pbyRom == NULL) { - PrintfToLog("Patch %s ignored.", (LPSTR)pLine->nParam[0]); - AddToLog("Please put the Rom command before any Patch."); + PrintfToLog(_T("Patch %s ignored."), (LPTSTR)pLine->nParam[0]); + AddToLog(_T("Please put the Rom command before any Patch.")); break; } - if (PatchRom((LPSTR)pLine->nParam[0]) == TRUE) - PrintfToLog("Patch %s Loaded", (LPSTR)pLine->nParam[0]); + if (PatchRom((LPTSTR)pLine->nParam[0]) == TRUE) + PrintfToLog(_T("Patch %s Loaded"), (LPTSTR)pLine->nParam[0]); else - PrintfToLog("Patch %s is Wrong or Missing", (LPSTR)pLine->nParam[0]); + PrintfToLog(_T("Patch %s is Wrong or Missing"), (LPTSTR)pLine->nParam[0]); break; case TOK_BITMAP: if (hMainDC != NULL) { - PrintfToLog("Bitmap %s Ignored.", (LPSTR)pLine->nParam[0]); - AddToLog("Please put only one Bitmap command in the Global block."); + PrintfToLog(_T("Bitmap %s Ignored."), (LPTSTR)pLine->nParam[0]); + AddToLog(_T("Please put only one Bitmap command in the Global block.")); break; } - if (!CreateMainBitmap((LPSTR)pLine->nParam[0])) + if (!CreateMainBitmap((LPTSTR)pLine->nParam[0])) { - PrintfToLog("Cannot Load Bitmap %s.", (LPSTR)pLine->nParam[0]); + PrintfToLog(_T("Cannot Load Bitmap %s."), (LPTSTR)pLine->nParam[0]); break; } - PrintfToLog("Bitmap %s Loaded.", (LPSTR)pLine->nParam[0]); + PrintfToLog(_T("Bitmap %s Loaded."), (LPTSTR)pLine->nParam[0]); break; default: - PrintfToLog("Command %s Ignored in Block %s", GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); + PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); } pLine = pLine->pNext; } @@ -1052,7 +1069,7 @@ static Line* InitBackground(Block* pBlock) case TOK_END: return pLine; default: - PrintfToLog("Command %s Ignored in Block %s", GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); + PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); } pLine = pLine->pNext; } @@ -1081,7 +1098,7 @@ static Line* InitLcd(Block* pBlock) case TOK_END: return pLine; default: - PrintfToLog("Command %s Ignored in Block %s", GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); + PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); } pLine = pLine->pNext; } @@ -1094,7 +1111,7 @@ static Line* InitAnnunciator(Block* pBlock) UINT nId = pBlock->nId-1; if (nId >= 6) { - PrintfToLog("Wrong Annunciator Id %i", nId); + PrintfToLog(_T("Wrong Annunciator Id %i"), nId); return NULL; } nAnnunciators++; @@ -1117,7 +1134,7 @@ static Line* InitAnnunciator(Block* pBlock) case TOK_END: return pLine; default: - PrintfToLog("Command %s Ignored in Block %s", GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); + PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType)); } pLine = pLine->pNext; } @@ -1130,7 +1147,7 @@ static VOID InitButton(Block* pBlock) UINT nLevel = 0; if (nButtons>=256) { - AddToLog("Only the first 256 buttons will be defined."); + AddToLog(_T("Only the first 256 buttons will be defined.")); return; } pButton[nButtons].nId = pBlock->nId; @@ -1181,12 +1198,12 @@ static VOID InitButton(Block* pBlock) pButton[nButtons].dwFlags |= BUTTON_VIRTUAL; break; default: - PrintfToLog("Command %s Ignored in Block %s %i", GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType), pBlock->nId); + PrintfToLog(_T("Command %s Ignored in Block %s %i"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType), pBlock->nId); } pLine = pLine->pNext; } if (nLevel) - PrintfToLog("%i Open Block(s) in Block %s %i", nLevel, GetStringOf(pBlock->eType), pBlock->nId); + PrintfToLog(_T("%i Open Block(s) in Block %s %i"), nLevel, GetStringOf(pBlock->eType), pBlock->nId); nButtons++; return; } @@ -1223,7 +1240,6 @@ static Line* SkipLines(Line* pLine, TokenId eCommand) static Line* If(Line* pLine, BOOL bCondition) { - UINT nLevel = 0; pLine = pLine->pNext; if (bCondition) { @@ -1291,6 +1307,8 @@ static Line* RunLine(Line* pLine) break; case TOK_IFFLAG: return If(pLine,(nKMLFlags>>(pLine->nParam[0]&0x1F))&1); + default: + break; } return pLine->pNext; } @@ -1345,12 +1363,12 @@ VOID FreeBlocks(Block* pBlock) return; } -VOID KillKML() +VOID KillKML(VOID) { - if ((nState==0)||(nState==3)) + if ((nState==SM_RUN)||(nState==SM_SLEEP)) { - AbortMessage("FATAL: KillKML while emulator is running !!!"); - SwitchToState(2); + AbortMessage(_T("FATAL: KillKML while emulator is running !!!")); + SwitchToState(SM_RETURN); DestroyWindow(hWnd); } UnmapRom(); @@ -1359,7 +1377,7 @@ VOID KillKML() if (hPalette) { BOOL err; - // 11.09.98, bugfix, unlock hPalette + if (hWindowDC) SelectPalette(hWindowDC, hOldPalette, FALSE); err = DeleteObject(hPalette); _ASSERT(err != FALSE); // freed resource memory @@ -1372,15 +1390,16 @@ VOID KillKML() nButtons = 0; nScancodes = 0; nAnnunciators = 0; - FillMemory(pButton, 256*sizeof(Button), 0); - FillMemory(pAnnunciator, 6*sizeof(Annunciator), 0); - FillMemory(pVKey, 256*sizeof(Block*), 0); + ZeroMemory(pButton, sizeof(pButton)); + ZeroMemory(pAnnunciator, sizeof(pAnnunciator)); + ZeroMemory(pVKey, sizeof(pVKey)); ClearLog(); + nBackgroundX = 0; + nBackgroundY = 0; nBackgroundW = 256; nBackgroundH = 0; UpdateWindowStatus(); ResizeWindow(); - return; } @@ -1392,7 +1411,7 @@ VOID KillKML() //# //################ -static LPSTR GetStringParam(Block* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam) +static LPTSTR GetStringParam(Block* pBlock, TokenId eBlock, TokenId eCommand, UINT nParam) { while (pBlock) { @@ -1403,7 +1422,7 @@ static LPSTR GetStringParam(Block* pBlock, TokenId eBlock, TokenId eCommand, UIN { if (pLine->eCommand == eCommand) { - return (LPSTR)pLine->nParam[nParam]; + return (LPTSTR)pLine->nParam[nParam]; } pLine = pLine->pNext; } @@ -1442,6 +1461,80 @@ static DWORD GetIntegerParam(Block* pBlock, TokenId eBlock, TokenId eCommand, UI //# //################ +static INT iSqrt(INT nNumber) // integer y=sqrt(x) function +{ + INT m, b = 0, t = nNumber; + + do + { + m = (b + t + 1) / 2; // median number + if (m * m - nNumber > 0) // calculate x^2-y + t = m; // adjust upper border + else + b = m; // adjust lower border + } + while(t - b > 1); + + return b; +} + +static VOID AdjustPixel(UINT x, UINT y, BYTE byOffset) +{ + COLORREF rgb; + WORD wB, wG, wR; + + rgb = GetPixel(hWindowDC, x, y); + + // adjust color red + wR = (((WORD) rgb) & 0x00FF) + byOffset; + if (wR > 0xFF) wR = 0xFF; + rgb >>= 8; + // adjust color green + wG = (((WORD) rgb) & 0x00FF) + byOffset; + if (wG > 0xFF) wG = 0xFF; + rgb >>= 8; + // adjust color blue + wB = (((WORD) rgb) & 0x00FF) + byOffset; + if (wB > 0xFF) wB = 0xFF; + + SetPixel(hWindowDC, x, y, RGB(wR,wG,wB)); + return; +} + +// draw transparent circle with center coordinates and radius in pixel +static __inline VOID TransparentCircle(UINT cx, UINT cy, UINT r) +{ + #define HIGHADJ 0x80 // color incr. at center + #define LOWADJ 0x08 // color incr. at border + + INT x, y; + INT rr = r * r; // calculate r^2 + + // y-rows of circle + for (y = 0; y < (INT) r; ++y) + { + INT yy = y * y; // calculate y^2 + + // x-columns of circle + INT nXWidth = iSqrt(rr-yy); + + for (x = 0; x < nXWidth; ++x) + { + // color offset, sqrt(x*x+y*y) <= r !!! + BYTE byOff = HIGHADJ - (BYTE) (iSqrt((x*x+yy) * (HIGHADJ-LOWADJ)*(HIGHADJ-LOWADJ) / rr)); + + AdjustPixel(cx+x, cy+y, byOff); + if (x != 0) AdjustPixel(cx-x, cy+y, byOff); + if (y != 0) AdjustPixel(cx+x, cy-y, byOff); + if (x != 0 && y != 0) AdjustPixel(cx-x, cy-y, byOff); + } + } + return; + + #undef HIGHADJ + #undef LOWADJ +} + static VOID DrawButton(UINT nId) { UINT x0 = pButton[nId].nOx; @@ -1451,37 +1544,38 @@ static VOID DrawButton(UINT nId) { switch (pButton[nId].nType) { - case 0: + case 0: // bitmap key if (pButton[nId].bDown) { BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, pButton[nId].nDx, pButton[nId].nDy, SRCCOPY); } else { + // update background only BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); } break; - case 1: + case 1: // shift key to right down if (pButton[nId].bDown) { UINT x1 = x0+pButton[nId].nCx-1; UINT y1 = y0+pButton[nId].nCy-1; BitBlt(hWindowDC, x0+3,y0+3,pButton[nId].nCx-5,pButton[nId].nCy-5,hMainDC,x0+2,y0+2,SRCCOPY); SelectObject(hWindowDC, GetStockObject(BLACK_PEN)); - MoveToEx(hWindowDC, x0,y0, NULL); LineTo(hWindowDC, x1,y0); - MoveToEx(hWindowDC, x0,y0, NULL); LineTo(hWindowDC, x0,y1); + MoveToEx(hWindowDC, x0, y0, NULL); LineTo(hWindowDC, x1, y0); + MoveToEx(hWindowDC, x0, y0, NULL); LineTo(hWindowDC, x0, y1); SelectObject(hWindowDC, GetStockObject(WHITE_PEN)); - MoveToEx(hWindowDC, x1,y0, NULL); LineTo(hWindowDC, x1,y1); - MoveToEx(hWindowDC, x0,y1, NULL); LineTo(hWindowDC, x1+1,y1); + MoveToEx(hWindowDC, x1, y0, NULL); LineTo(hWindowDC, x1, y1); + MoveToEx(hWindowDC, x0, y1, NULL); LineTo(hWindowDC, x1+1, y1); } else { BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); } break; - case 2: + case 2: // do nothing break; - case 3: + case 3: // invert key color, even in display if (pButton[nId].bDown) { PatBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, DSTINVERT); @@ -1493,12 +1587,13 @@ static VOID DrawButton(UINT nId) Rect.right = x0 + pButton[nId].nCx; Rect.top = y0; Rect.bottom = y0 + pButton[nId].nCy; - InvalidateRect(hWnd, &Rect, 0); + InvalidateRect(hWnd, &Rect, FALSE); // call WM_PAINT for background and display redraw } break; - case 4: + case 4: // bitmap key, even in display if (pButton[nId].bDown) { + // update background only BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); } else @@ -1508,24 +1603,32 @@ static VOID DrawButton(UINT nId) Rect.right = x0 + pButton[nId].nCx; Rect.top = y0; Rect.bottom = y0 + pButton[nId].nCy; - InvalidateRect(hWnd, &Rect, 0); + InvalidateRect(hWnd, &Rect, FALSE); // call WM_PAINT for background and display redraw } break; - case 5: + case 5: // transparent circle if (pButton[nId].bDown) { - BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, pButton[nId].nDx, pButton[nId].nDy, SRCCOPY); + TransparentCircle(x0 + pButton[nId].nCx / 2, // x-center coordinate + y0 + pButton[nId].nCy / 2, // y-center coordinate + min(pButton[nId].nCx,pButton[nId].nCy) / 2); // radius } else { + // update background only BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); } break; - default: + default: // black key, default drawing on illegal types if (pButton[nId].bDown) - PatBlt(hWindowDC, x0,y0, pButton[nId].nCx, pButton[nId].nCy, BLACKNESS); + { + PatBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, BLACKNESS); + } else + { + // update background only BitBlt(hWindowDC, x0, y0, pButton[nId].nCx, pButton[nId].nCy, hMainDC, x0, y0, SRCCOPY); + } } GdiFlush(); } @@ -1615,14 +1718,19 @@ static VOID ReleaseAllButtons(VOID) // release all buttons uButtonClicked = 0; // set var to default } -VOID RefreshButtons() +VOID RefreshButtons(RECT *rc) { UINT i; for (i=0; iright > (LONG) (pButton[i].nOx) + && rc->bottom > (LONG) (pButton[i].nOy) + && rc->left <= (LONG) (pButton[i].nOx + pButton[i].nCx) + && rc->top <= (LONG) (pButton[i].nOy + pButton[i].nCy)) { - if (pButton[i].nType == 3) // on button type 3 clear complete key area before drawing + // on button type 3 and 5 clear complete key area before drawing + if (pButton[i].nType == 3 || pButton[i].nType == 5) { UINT x0 = pButton[i].nOx; UINT y0 = pButton[i].nOy; @@ -1648,28 +1756,28 @@ VOID RefreshButtons() VOID DrawAnnunciator(UINT nId, BOOL bOn) { - nId--; + UINT nSx,nSy; + + --nId; // zero based ID if (nId>=6) return; + if (bOn) + { + nSx = pAnnunciator[nId].nDx; // position of annunciator + nSy = pAnnunciator[nId].nDy; + } + else + { + nSx = pAnnunciator[nId].nOx; // position of background + nSy = pAnnunciator[nId].nOy; + } EnterCriticalSection(&csGDILock); // solving NT GDI problems { - if (bOn) - { - BitBlt(hWindowDC, - pAnnunciator[nId].nOx, pAnnunciator[nId].nOy, - pAnnunciator[nId].nCx, pAnnunciator[nId].nCy, - hMainDC, - pAnnunciator[nId].nDx, pAnnunciator[nId].nDy, - SRCCOPY); - } - else - { - BitBlt(hWindowDC, - pAnnunciator[nId].nOx, pAnnunciator[nId].nOy, - pAnnunciator[nId].nCx, pAnnunciator[nId].nCy, - hMainDC, - pAnnunciator[nId].nOx, pAnnunciator[nId].nOy, - SRCCOPY); - } + BitBlt(hWindowDC, + pAnnunciator[nId].nOx, pAnnunciator[nId].nOy, + pAnnunciator[nId].nCx, pAnnunciator[nId].nCy, + hMainDC, + nSx, nSy, + SRCCOPY); GdiFlush(); } LeaveCriticalSection(&csGDILock); @@ -1797,8 +1905,8 @@ VOID RunKey(BYTE nId, BOOL bPressed) { if (bDebug&&bPressed) { - CHAR szTemp[128]; - wsprintf(szTemp,"Scancode %i",nId); + TCHAR szTemp[128]; + wsprintf(szTemp,_T("Scancode %i"),nId); InfoMessage(szTemp); } } @@ -1813,13 +1921,10 @@ VOID RunKey(BYTE nId, BOOL bPressed) //# //################ -static Block* LoadKMLGlobal(LPCSTR szFilename) +static Block* LoadKMLGlobal(LPCTSTR szFilename) { HANDLE hFile; - DWORD dwFileSizeLow; - DWORD dwFileSizeHigh; - DWORD lBytesRead; - LPBYTE lpBuf; + LPTSTR lpBuf; Block* pBlock; DWORD eToken; @@ -1827,21 +1932,8 @@ static Block* LoadKMLGlobal(LPCSTR szFilename) hFile = CreateFile(szFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); SetCurrentDirectory(szCurrentDirectory); if (hFile == INVALID_HANDLE_VALUE) return NULL; - dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); - if (dwFileSizeHigh != 0) - { // file is too large. - CloseHandle(hFile); + if ((lpBuf = MapKMLFile(hFile)) == NULL) return NULL; - } - lpBuf = (LPBYTE)LocalAlloc(0,dwFileSizeLow+1); - if (lpBuf == NULL) - { - CloseHandle(hFile); - return NULL; - } - ReadFile(hFile, lpBuf, dwFileSizeLow, &lBytesRead, NULL); - CloseHandle(hFile); - lpBuf[dwFileSizeLow] = 0; InitLex(lpBuf); pBlock = NULL; @@ -1858,46 +1950,27 @@ static Block* LoadKMLGlobal(LPCSTR szFilename) } -BOOL InitKML(LPCSTR szFilename, BOOL bNoLog) +BOOL InitKML(LPCTSTR szFilename, BOOL bNoLog) { HANDLE hFile; - DWORD dwFileSizeLow; - DWORD dwFileSizeHigh; - DWORD lBytesRead; - LPBYTE lpBuf; + LPTSTR lpBuf; Block* pBlock; - BOOL bOk = FALSE; - BYTE bySum = 0; + BOOL bOk = FALSE; KillKML(); nBlocksIncludeLevel = 0; - PrintfToLog("Reading %s", szFilename); + PrintfToLog(_T("Reading %s"), szFilename); SetCurrentDirectory(szEmu48Directory); hFile = CreateFile(szFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); SetCurrentDirectory(szCurrentDirectory); if (hFile == INVALID_HANDLE_VALUE) { - AddToLog("Error while opening the file."); + AddToLog(_T("Error while opening the file.")); goto quit; } - dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); - if (dwFileSizeHigh != 0) - { // file is too large. - AddToLog("File is too large."); - CloseHandle(hFile); + if ((lpBuf = MapKMLFile(hFile)) == NULL) goto quit; - } - lpBuf = (LPBYTE)LocalAlloc(0,dwFileSizeLow+1); - if (lpBuf == NULL) - { - PrintfToLog("Cannot allocate %i bytes.", dwFileSizeLow+1); - CloseHandle(hFile); - goto quit; - } - ReadFile(hFile, lpBuf, dwFileSizeLow, &lBytesRead, NULL); - CloseHandle(hFile); - lpBuf[dwFileSizeLow] = 0; InitLex(lpBuf); pKml = ParseBlocks(); @@ -1931,7 +2004,7 @@ BOOL InitKML(LPCSTR szFilename, BOOL bNoLog) InitBackground(pBlock); break; default: - PrintfToLog("Block %s Ignored.", GetStringOf(pBlock->eType)); + PrintfToLog(_T("Block %s Ignored."), GetStringOf(pBlock->eType)); pBlock = pBlock->pNext; } pBlock = pBlock->pNext; @@ -1939,19 +2012,19 @@ BOOL InitKML(LPCSTR szFilename, BOOL bNoLog) if (cCurrentRomType == 0) { - AddToLog("This KML Script doesn't specify the ROM Type."); + AddToLog(_T("This KML Script doesn't specify the ROM Type.")); goto quit; } if (pbyRom == NULL) { - AddToLog("This KML Script doesn't specify the ROM to use, or the ROM could not be loaded."); + AddToLog(_T("This KML Script doesn't specify the ROM to use, or the ROM could not be loaded.")); goto quit; } CreateLcdBitmap(); - PrintfToLog("%i Buttons Defined", nButtons); - PrintfToLog("%i Scancodes Defined", nScancodes); - PrintfToLog("%i Annunciators Defined", nAnnunciators); + PrintfToLog(_T("%i Buttons Defined"), nButtons); + PrintfToLog(_T("%i Scancodes Defined"), nScancodes); + PrintfToLog(_T("%i Annunciators Defined"), nAnnunciators); bOk = TRUE; @@ -1960,7 +2033,7 @@ quit: { if (!bNoLog) { - AddToLog("Press Ok to Continue."); + AddToLog(_T("Press Ok to Continue.")); if (bAlwaysDisplayLog&&(!DisplayKMLLog(bOk))) { KillKML(); @@ -1970,7 +2043,7 @@ quit: } else { - AddToLog("Press Cancel to Abort."); + AddToLog(_T("Press Cancel to Abort.")); if (!DisplayKMLLog(bOk)) { KillKML(); diff --git a/sources/Emu48/KML.H b/sources/Emu48/KML.H index d1ecad3..e4ac63f 100644 --- a/sources/Emu48/KML.H +++ b/sources/Emu48/KML.H @@ -41,19 +41,20 @@ typedef enum eTokenId TOK_DEBUG, //25 TOK_COLOR, //26 TOK_MODEL, //27 - TOK_PRESS, //28 - TOK_TYPE, //29 - TOK_SIZE, //30 - TOK_DOWN, //31 - TOK_ZOOM, //32 - TOK_ELSE, //33 - TOK_ONUP, //34 - TOK_EOL, //35 - TOK_MAP, //36 - TOK_ROM, //37 - TOK_LCD, //38 - TOK_NOTFLAG, //39 - TOK_END //40 + TOK_CLASS, //28 + TOK_PRESS, //29 + TOK_TYPE, //30 + TOK_SIZE, //31 + TOK_DOWN, //32 + TOK_ZOOM, //33 + TOK_ELSE, //34 + TOK_ONUP, //35 + TOK_EOL, //36 + TOK_MAP, //37 + TOK_ROM, //38 + TOK_LCD, //39 + TOK_NOTFLAG, //40 + TOK_END //41 } TokenId; #define TYPE_NONE 00 @@ -65,7 +66,7 @@ typedef struct Token TokenId eId; DWORD nParams; DWORD nLen; - CHAR szName[20]; + TCHAR szName[20]; } Token; typedef struct Line @@ -110,10 +111,10 @@ extern Block* pKml; extern BOOL DisplayChooseKml(CHAR cType); extern VOID FreeBlocks(Block* pBlock); extern VOID DrawAnnunciator(UINT nId, BOOL bOn); -extern VOID RefreshButtons(); +extern VOID RefreshButtons(RECT *rc); extern VOID MouseButtonDownAt(UINT nFlags, DWORD x, DWORD y); extern VOID MouseButtonUpAt(UINT nFlags, DWORD x, DWORD y); extern VOID MouseMovesTo(UINT nFlags, DWORD x, DWORD y); extern VOID RunKey(BYTE nId, BOOL bPressed); -extern BOOL InitKML(LPCSTR szFilename, BOOL bNoLog); -extern VOID KillKML(); +extern BOOL InitKML(LPCTSTR szFilename, BOOL bNoLog); +extern VOID KillKML(VOID); diff --git a/sources/Emu48/MOPS.C b/sources/Emu48/MOPS.C index 1c19144..00f0f61 100644 --- a/sources/Emu48/MOPS.C +++ b/sources/Emu48/MOPS.C @@ -8,6 +8,7 @@ */ #include "pch.h" #include "Emu48.h" +#include "ops.h" #include "opcodes.h" #include "io.h" #include "i28f160.h" // flash support @@ -26,11 +27,7 @@ #define P2MAPBASE ((BYTE)(Chipset.P2Base & ~Chipset.P2Size)) #define BSMAPBASE ((BYTE)(Chipset.BSBase & ~Chipset.BSSize)) -// values for mapping area -enum MMUMAP { M_IO, M_ROM, M_RAM, M_P1, M_P2, M_BS }; - BOOL ioc_acc = FALSE; // flag ioc changed -BOOL ir_ctrl_acc = FALSE; // flag ir_ctl changed BOOL bFlashRomArray = TRUE; // flag ROM mode @@ -51,6 +48,16 @@ static __inline VOID UpCRC(BYTE nib) Chipset.crc = (WORD)((Chipset.crc>>4)^crc_table[(Chipset.crc^nib)&0xf]); } +static __inline UINT MIN(UINT a, UINT b) +{ + return (ab)?a:b; +} + // generate UCK signal static __inline BYTE UckBit(BYTE byBaudIndex) { @@ -59,7 +66,7 @@ static __inline BYTE UckBit(BYTE byBaudIndex) LARGE_INTEGER lLC; - _ASSERT(byBaudIndex < sizeof(dwBaudrates) / sizeof(dwBaudrates[0])); + _ASSERT(byBaudIndex < ARRAYSIZEOF(dwBaudrates)); QueryPerformanceCounter(&lLC); // get counter value @@ -82,6 +89,50 @@ static __inline DWORD FlashROMAddr(DWORD d) return dwLinAddr; } +// update display +static __inline VOID UpdateDisplay(DWORD d, UINT s) +{ + BYTE p[16]; + DWORD u; + UINT c; + + // address in display main area? + if ((dChipset.start12)) + { + // write to display main area + u = d; // copy destination ptr + c = MIN(s,Chipset.end1-d); // number of nibbles to copy + + if (d < Chipset.start12) // first address is out of display area + { + u = Chipset.start12; // set destination ptr to start of display area + c -= Chipset.start12 - d; // - number of bytes that aren't in display area + } + + _ASSERT(c <= ARRAYSIZEOF(p)); + Npeek(p,u,c); // get source data + WriteToMainDisplay(p,u,c); + } + // address in display menu area? + if ((dChipset.start2)) + { + // write to display menu area + u = d; // copy destination ptr + c = MIN(s,Chipset.end2-d); // number of nibbles to copy + + if (d < Chipset.start2) // first address is out of display area + { + u = Chipset.start2; // set destination ptr to start of display area + c -= Chipset.start2 - d; // - number of bytes that are not in display area + } + + _ASSERT(c <= ARRAYSIZEOF(p)); + Npeek(p,u,c); // get source data + WriteToMenuDisplay(p,u,c); + } + return; +} + // LCD line counter calculation static BYTE F4096Hz(VOID) // get a 6 bit 4096Hz down counter value { @@ -93,43 +144,11 @@ static BYTE F4096Hz(VOID) // get a 6 bit 4096Hz down counter value return -(BYTE)(((lLC.QuadPart - lAppStart.QuadPart) << 12) / lFreq.QuadPart) & 0x3F; } -// port configuration -static enum MMUMAP MapData(DWORD d) // check MMU area -{ - BYTE u = (BYTE) (d>>12); - - if (Chipset.IOCfig && ((d&0xFFFC0)==Chipset.IOBase)) return M_IO; - if (Chipset.P0Cfig && (((u^Chipset.P0Base) & ~Chipset.P0Size) == 0)) return M_RAM; - if (cCurrentRomType=='S') - { - if (Chipset.P2Cfig && (((u^Chipset.P2Base) & ~Chipset.P2Size) == 0)) return M_P2; - if (Chipset.P1Cfig && (((u^Chipset.P1Base) & ~Chipset.P1Size) == 0)) return M_P1; - if (Chipset.BSCfig && (((u^Chipset.BSBase) & ~Chipset.BSSize) == 0)) return M_BS; - } - else - { - if (Chipset.P1Cfig && (((u^Chipset.P1Base) & ~Chipset.P1Size) == 0)) return M_P1; - if (Chipset.BSCfig && (((u^Chipset.BSBase) & ~Chipset.BSSize) == 0)) return M_BS; - if (Chipset.P2Cfig && (((u^Chipset.P2Base) & ~Chipset.P2Size) == 0)) return M_P2; - } - return M_ROM; -} - // port mapping LPBYTE RMap[256] = {NULL,}; LPBYTE WMap[256] = {NULL,}; -static __inline UINT MIN(UINT a, UINT b) -{ - return (ab)?a:b; -} - static VOID MapP0(BYTE a, BYTE b) { UINT i; @@ -163,7 +182,7 @@ static VOID MapBS(BYTE a, BYTE b) // mapping area may have holes if (((i ^ Chipset.BSBase) & ~Chipset.BSSize) == 0) { - RMap[i]=NULL; // bugfix, no read cycle, open data bus + RMap[i]=NULL; // no read cycle, open data bus WMap[i]=NULL; } } @@ -235,7 +254,7 @@ static VOID MapP2(BYTE a, BYTE b) a = (BYTE)MAX(a,P2MAPBASE); // adjust base to mapping boundary b = (BYTE)MIN(b,Chipset.P2End); - if (cCurrentRomType == 'X') // HP49G + if (Chipset.Port2Size) // internal port2 { m = (Chipset.Port2Size*2048)-1; p = (a<<12)&m; // offset to begin of P0 in nibbles @@ -280,7 +299,7 @@ static VOID MapP2(BYTE a, BYTE b) // SX: CE2.2 = CE2 // GX: CE2.2 = BEN & /DA19 & /NCE3 - if (cCurrentRomType == 'S' || ((Chipset.IORam[0x29]&0x8) == 0 && (Chipset.Bank_FF&0x40))) + if (cCurrentRomType == 'S' || ((Chipset.IORam[0x29]&DA19) == 0 && (Chipset.Bank_FF&0x40))) { if (bPort2Writeable) { @@ -316,7 +335,8 @@ static VOID MapROM(BYTE a, BYTE b) UINT i; DWORD p, m; - if (cCurrentRomType == 'X') // HP49G + // HP39/49G, HP49G + if (cCurrentRomType == 'E' || cCurrentRomType == 'X') { if (bFlashRomArray) // view flash ROM data { @@ -346,7 +366,7 @@ static VOID MapROM(BYTE a, BYTE b) // HP38G / HP48SX / HP48GX m = dwRomSize - 1; // ROM address mask for mirroring // when 512KB ROM and DA19=0 (ROM disabled) - if ((m & 0x80000) != 0 && (Chipset.IORam[0x29]&0x8) == 0) + if ((m & 0x80000) != 0 && (Chipset.IORam[0x29]&DA19) == 0) m >>= 1; // mirror ROM at #80000 (AR18=0) p = (a*0x1000)&m; // data offset in nibbles for (i=a;i<=b;i++) // scan each 2KB page @@ -360,12 +380,12 @@ static VOID MapROM(BYTE a, BYTE b) VOID Map(BYTE a, BYTE b) // maps 2KB pages with priority { - // On HP49G Chipset.cards_status must be 0xF - _ASSERT(cCurrentRomType!='X' || !Chipset.P1Cfig || Chipset.cards_status == 0xF); + // On HP39/40G and HP49G Chipset.cards_status must be 0xF + _ASSERT((cCurrentRomType!='E' && cCurrentRomType!='X') || !Chipset.P1Cfig || Chipset.cards_status == 0xF); // priority order is HDW, RAM, CE2, CE1, NCE3, ROM MapROM(a,b); // ROM, lowest priority, always mapped - if (cCurrentRomType=='S') // HP48SX + if (cCurrentRomType == 'S') // HP48SX { if (Chipset.BSCfig) MapBS(a,b); // NCE3, not used in S(X) if (Chipset.P1Cfig) MapP1(a,b); // CE1, port1 (lower priority than CE2) @@ -390,7 +410,8 @@ VOID Map(BYTE a, BYTE b) // maps 2KB pages with priority VOID RomSwitch(DWORD adr) { - if (cCurrentRomType=='X') // only HP49G + // only HP39/40G, HP49G + if (cCurrentRomType=='E' || cCurrentRomType=='X') { Chipset.Bank_FF = adr; // save address line adr = (adr >> 1) & 0x3f; // 6 bit of latch (was A6-A1 of address bus) @@ -607,18 +628,59 @@ VOID C_Eq_Id() return; } +enum MMUMAP MapData(DWORD d) // check MMU area +{ + BYTE u = (BYTE) (d>>12); + + if (Chipset.IOCfig && ((d&0xFFFC0)==Chipset.IOBase)) return M_IO; + if (Chipset.P0Cfig && (((u^Chipset.P0Base) & ~Chipset.P0Size) == 0)) return M_RAM; + if (cCurrentRomType == 'S') + { + if (Chipset.P2Cfig && (((u^Chipset.P2Base) & ~Chipset.P2Size) == 0)) return M_P2; + if (Chipset.P1Cfig && (((u^Chipset.P1Base) & ~Chipset.P1Size) == 0)) return M_P1; + if (Chipset.BSCfig && (((u^Chipset.BSBase) & ~Chipset.BSSize) == 0)) return M_BS; + } + else + { + if (Chipset.P1Cfig && (((u^Chipset.P1Base) & ~Chipset.P1Size) == 0)) return M_P1; + if (Chipset.BSCfig && (((u^Chipset.BSBase) & ~Chipset.BSSize) == 0)) return M_BS; + if (Chipset.P2Cfig && (((u^Chipset.P2Base) & ~Chipset.P2Size) == 0)) return M_P2; + } + return M_ROM; +} + VOID CpuReset(VOID) // register setting after Cpu Reset { + StopTimers(); // stop timer, do here because function change Chipset.t2 + Chipset.pc = 0; Chipset.rstkp = 0; - FillMemory(Chipset.rstk,sizeof(Chipset.rstk),0); + ZeroMemory(Chipset.rstk,sizeof(Chipset.rstk)); Chipset.HST = 0; - Chipset.inte = TRUE; - Chipset.Shutdn = FALSE; - Chipset.SoftInt = TRUE; + Chipset.SoftInt = FALSE; + Chipset.Shutdn = TRUE; + Chipset.inte = TRUE; // enable interrupts + Chipset.intk = TRUE; // INTON + Chipset.intd = FALSE; // no keyboard interrupts pending + Chipset.crc = 0; + Chipset.Bank_FF = 0; // state of bank switcher FF Chipset.FlashRomState = 0; // WSM state of flash memory + ZeroMemory(Chipset.IORam,sizeof(Chipset.IORam)); Reset(); // reset MMU - bInterrupt = TRUE; + Chipset.t1 = 0; // reset timer values + Chipset.t2 = 0; + Chipset.loffset = 0; // right margin + Chipset.boffset = 0; // left margin + Chipset.lcounter = 0; // number of main display lines + Chipset.contrast = 0; // contrast dark + Chipset.dispon = 0; // display off + + UpdateContrast(Chipset.contrast); // update contrast + // display update when changing to run state + CommSetBaud(); // new baudrate + ioc_acc = TRUE; // new IOC value, close serial port + + RomSwitch(Chipset.Bank_FF); // force new memory mapping return; } @@ -661,7 +723,7 @@ VOID Npeek(BYTE *a, DWORD d, UINT s) v = d&0xFFF; c = MIN(s,0x1000-v); // Flash memory Read access - if (cCurrentRomType == 'X' && (Chipset.IORam[LCR] & LED) && M_P2 == eMap) + if (cCurrentRomType=='X' && (Chipset.IORam[LCR] & LED) && M_P2 == eMap) { FlashRead(a, FlashROMAddr(d), s); } @@ -671,18 +733,16 @@ VOID Npeek(BYTE *a, DWORD d, UINT s) { memcpy(a, p+v, c); } - // simulate open data bus else // open data bus { for (u=0; u> 4); + Chipset.IORam[0x29] = (Chipset.IORam[0x29] & (DA19|M32)) | (c >> 4); } } *a = Chipset.IORam[d]; @@ -1162,28 +1210,26 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) { DWORD b; BYTE c; - BOOL tbr_acc = FALSE; // flag to transmit data - BOOL bDISPADDR = FALSE; // flag addr 0x120-0x124 changed - BOOL bLINEOFFS = FALSE; // flag addr 0x125-0x127 changed - BOOL bLINECOUNT = FALSE; // flag addr 0x128-0x129 changed - BOOL bMENUADDR = FALSE; // flag addr 0x130-0x134 changed + BOOL tbr_acc = FALSE; // flag to transmit data + BOOL bDISPADDR = FALSE; // flag addr 0x120-0x124 changed + BOOL bLINEOFFS = FALSE; // flag addr 0x125-0x127 changed + BOOL bMENUADDR = FALSE; // flag addr 0x130-0x134 changed #if defined DEBUG_IO { - char buffer[256]; + TCHAR buffer[256]; DWORD j; int i; - i = wsprintf(buffer,"%.5lx: IO write: %02x,%u = ",Chipset.pc,d,s); + i = wsprintf(buffer,_T("%.5lx: IO write: %02x,%u = "),Chipset.pc,d,s); for (j = 0;j < s;++j,++i) { buffer[i] = a[j]; - if (buffer[i] > 9) buffer[i] += 0x27; - buffer[i] += '0'; + if (buffer[i] > 9) buffer[i] += _T('a') - _T('9') - 1; + buffer[i] += _T('0'); } - buffer[i++] = '\n'; + buffer[i++] = _T('\n'); buffer[i] = 0; - OutputDebugString(buffer); } #endif @@ -1204,7 +1250,7 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) // 00100 @ Display bit offset and DON [DON OFF2 OFF1 OFF0] // 00100 @ 3 nibs for display offset (scrolling), DON=Display ON case 0x00: - if ((c^Chipset.IORam[d])&8) // DON bit changed + if ((c^Chipset.IORam[d])&DON) // DON bit changed { Chipset.dispon = c>>3; disp |= (DISP_POINTER | DISP_MAIN | DISP_MENUE); @@ -1224,9 +1270,10 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) ReadIO(a,0x28,2); // update VBL at display off time } } - if ((c^Chipset.IORam[d])&7) // OFF bits changed + // OFF bits changed + if ((c^Chipset.IORam[d]) & (OFF2 | OFF1 | OFF0)) { - Chipset.boffset = c&7; + Chipset.boffset = c & (OFF2 | OFF1 | OFF0); disp |= (DISP_POINTER | DISP_MAIN); } Chipset.IORam[d] = c; @@ -1301,8 +1348,8 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) CommSetBaud(); // set baudrate #if defined DEBUG_SERIAL { - char buffer[256]; - wsprintf(buffer,"%.5lx: BAUD write: %x\n",Chipset.pc,Chipset.IORam[d]); + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: BAUD write: %x\n"),Chipset.pc,Chipset.IORam[d]); OutputDebugString(buffer); } #endif @@ -1362,13 +1409,23 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) // 00110 @ Serial I/O Control [SON ETBE ERBF ERBZ] // 00110 @ Serial On, Interrupt On Recv.Buf.Empty, Full, Buzy case 0x10: + if ((c & SON) == 0) // SON bit cleared + { + c = 0; // clear IOC + Chipset.IORam[RCS] = 0; // clear RCS + Chipset.IORam[TCS] = 0; // clear TCS + Chipset.IORam[RBR_LSB] = 0; // clear RBR + Chipset.IORam[RBR_MSB] = 0; + Chipset.IORam[TBR_LSB] = 0; // clear TBR + Chipset.IORam[TBR_MSB] = 0; + } Chipset.IORam[d]=c; UpdateUSRQ(); // update USRQ ioc_acc = TRUE; // new IOC value #if defined DEBUG_SERIAL { - char buffer[256]; - wsprintf(buffer,"%.5lx: IOC write: %x\n",Chipset.pc,Chipset.IORam[d]); + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: IOC write: %x\n"),Chipset.pc,Chipset.IORam[d]); OutputDebugString(buffer); } #endif @@ -1377,27 +1434,33 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) // 00111 = HP:RCS // 00111 Serial Receive Control/Status [RX RER RBZ RBF] (bit 3 is read-only) case 0x11: - Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); - #if defined DEBUG_SERIAL + if (Chipset.IORam[IOC] & SON) { - char buffer[256]; - wsprintf(buffer,"%.5lx: RCS write: %x\n",Chipset.pc,Chipset.IORam[d]); - OutputDebugString(buffer); + Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: RCS write: %x\n"),Chipset.pc,Chipset.IORam[d]); + OutputDebugString(buffer); + } + #endif } - #endif break; // 00112 = HP:TCS // 00112 @ Serial Transmit Control/Status [BRK LPB TBZ TBF] case 0x12: - Chipset.IORam[d]=c; - #if defined DEBUG_SERIAL + if (Chipset.IORam[IOC] & SON) { - char buffer[256]; - wsprintf(buffer,"%.5lx: TCS write: %x\n",Chipset.pc,Chipset.IORam[d]); - OutputDebugString(buffer); + Chipset.IORam[d]=c; + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: TCS write: %x\n"),Chipset.pc,Chipset.IORam[d]); + OutputDebugString(buffer); + } + #endif } - #endif break; // 00113 = HP:CRER @@ -1406,8 +1469,8 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) Chipset.IORam[RCS]&=~RER; #if defined DEBUG_SERIAL { - char buffer[256]; - wsprintf(buffer,"%.5lx: CRER write: %x\n",Chipset.pc,Chipset.IORam[d]); + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: CRER write: %x\n"),Chipset.pc,Chipset.IORam[d]); OutputDebugString(buffer); } #endif @@ -1423,17 +1486,20 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) // 00116 @ Serial Transmit Buffer Register (Writing sets TBF bit) case 0x16: case 0x17: - Chipset.IORam[d]=c; - Chipset.IORam[TCS]|=TBF; - UpdateUSRQ(); // update USRQ - tbr_acc = TRUE; // new TBR value - #if defined DEBUG_SERIAL + if (Chipset.IORam[IOC] & SON) { - char buffer[256]; - wsprintf(buffer,"%.5lx: TBR %s write: %x\n",Chipset.pc,(d==0x16) ? "LSB" : "MSB",*a); - OutputDebugString(buffer); + Chipset.IORam[d]=c; + Chipset.IORam[TCS]|=TBF; + UpdateUSRQ(); // update USRQ + tbr_acc = TRUE; // new TBR value + #if defined DEBUG_SERIAL + { + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: TBR %s write: %x\n"),Chipset.pc,(d==0x16) ? "LSB" : "MSB",*a); + OutputDebugString(buffer); + } + #endif } - #endif break; // 00118 = NS:SRR @@ -1446,12 +1512,19 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) // 0011A @ IR Control Register [IRI EIRU EIRI IRE] (bit 3 is read-only) // 0011A @ IR Input, Enable IR UART mode, Enable IR Interrupt, IR Event case 0x1A: + // COM port open and EIRU bit changed + if (bCommInit && ((c^Chipset.IORam[d]) & EIRU) != 0) + { + // save new value for COM open + Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); + // reopen COM port with new setting + bCommInit = CommOpen(szSerialWire,szSerialIr); + } Chipset.IORam[d]=(Chipset.IORam[d]&8)|(c&7); - ir_ctrl_acc = TRUE; // new IR_CTRL value #if defined DEBUG_SERIAL { - char buffer[256]; - wsprintf(buffer,"%.5lx: IRC write: %x\n",Chipset.pc,Chipset.IORam[d]); + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: IRC write: %x\n"),Chipset.pc,Chipset.IORam[d]); OutputDebugString(buffer); } #endif @@ -1471,8 +1544,8 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) Map(Chipset.P2Base,Chipset.P2End); // new ROM mapping #if defined DEBUG_FLASH { - char buffer[256]; - wsprintf(buffer,"%.5lx: NCE3: R%cM\n",Chipset.pc,(c&LED) ? 'O' : 'A'); + TCHAR buffer[256]; + wsprintf(buffer,_T("%.5lx: NCE3: R%cM\n"),Chipset.pc,(c&LED) ? 'O' : 'A'); OutputDebugString(buffer); } #endif @@ -1501,7 +1574,7 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) case 0x23: case 0x24: Chipset.IORam[d]=c; - bDISPADDR = TRUE; // addr 0x120-0x124 changed + bDISPADDR = TRUE; // addr 0x120-0x124 changed break; // 00125 = NS:LINEOFFS @@ -1511,7 +1584,7 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) case 0x26: case 0x27: Chipset.IORam[d]=c; - bLINEOFFS = TRUE; // addr 0x125-0x127 changed + bLINEOFFS = TRUE; // addr 0x125-0x127 changed break; // 00128 = NS:LINECOUNT @@ -1520,17 +1593,28 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) // 00128 @ Line counter 6 bits -> max = 2^6-1 = 63 = disp height // 00128 @ Normally has 55 -> Menu starts at display row 56 case 0x28: - case 0x29: - if (d == 0x29) + // LSB of LINECOUNT changed + if (c != (BYTE) (Chipset.lcounter & 0xf)) { - if ((c^Chipset.IORam[d])&8) // DA19 changed - { - Chipset.IORam[d]=c; // save new DA19 - Map(0x00,0xFF); // new ROM mapping - } + Chipset.lcounter = (Chipset.lcounter & ~0xF) | c; + disp |= (DISP_POINTER | DISP_MAIN | DISP_MENUE); + } + break; + + case 0x29: + // MSB of LINECOUNT changed + b = (c & 0x3) << 4; // upper two bits + if (b != (Chipset.lcounter & 0x30)) + { + Chipset.lcounter = (Chipset.lcounter & ~0x30) | b; + disp |= (DISP_POINTER | DISP_MAIN | DISP_MENUE); + } + + if ((c^Chipset.IORam[d])&DA19) // DA19 changed + { + Chipset.IORam[d]^=DA19; // save new DA19 + Map(0x00,0xFF); // new ROM mapping } - Chipset.IORam[d]=c; - bLINECOUNT = TRUE; // addr 0x128-0x129 changed break; case 0x2A: break; @@ -1606,15 +1690,6 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s) disp |= (DISP_POINTER | DISP_MAIN); } } - if (bLINECOUNT) // addr 0x128-0x129 changed - { - b = Npack(Chipset.IORam+0x28,2)&0x3F; - if (Chipset.lcounter != b) - { - Chipset.lcounter = b; - disp |= (DISP_POINTER | DISP_MAIN | DISP_MENUE); - } - } if (bMENUADDR) // addr 0x130-0x134 changed { b = Npack(Chipset.IORam+0x30,5)&0xFFFFE; diff --git a/sources/Emu48/OPCODES.C b/sources/Emu48/OPCODES.C index fa24b03..67394a1 100644 --- a/sources/Emu48/OPCODES.C +++ b/sources/Emu48/OPCODES.C @@ -1001,30 +1001,48 @@ VOID o807(LPBYTE I) // SHUTDN { BOOL bShutdn = TRUE; // shut down - w.cycles+=5; - w.pc+=3; // only shut down when no timer wake up - if (w.IORam[0x2E]&0x04) // WKE bit of timer1 is set + if (w.IORam[TIMER1_CTRL]&WKE) // WKE bit of timer1 is set { if (ReadT1()&0x08) // and MSB of timer1 is set { - w.IORam[0x2E] &= ~0x04; // clear WKE + w.IORam[TIMER1_CTRL] &= ~WKE; // clear WKE bShutdn = FALSE; // don't shut down } } - if (w.IORam[0x2F]&0x04) // WKE bit of timer2 is set + if (w.IORam[TIMER2_CTRL]&WKE) // WKE bit of timer2 is set { if (ReadT2()&0x80000000) // and MSB of timer2 is set { - w.IORam[0x2F] &= ~0x04; // clear WKE + w.IORam[TIMER2_CTRL] &= ~WKE; // clear WKE bShutdn = FALSE; // don't shut down } } - if (w.in==0 && bShutdn) // changed, shut down only when enabled + if (w.in==0 && bShutdn) // shut down only when enabled { w.Shutdn = TRUE; // set mode before exit emulation loop bInterrupt = TRUE; + + // emulation of BS reset circuit in deep sleep + // HP39/40G, HP48GX, HP49G, display off, card control off or in slow mode + if ( (cCurrentRomType=='E' || cCurrentRomType=='G' || cCurrentRomType=='X') + && (w.IORam[BITOFFSET]&DON) == 0 + && ((w.IORam[CARDCTL]&(ECDT|RCDT)) != (ECDT|RCDT))) + { + // on HP48GX ROM must be selected (DA19=1) and + // the NOT MA18 address line must be low (test for high) + // else we get power on VCO from the ROM chip + // (MA18 input pin security diode to VCC pin) + if ( cCurrentRomType!='G' + || ((w.IORam[LINECOUNT+1]&DA19) && (w.pc & 0x80000))) + { + w.Bank_FF = 0; // reset bank switcher FF + RomSwitch(w.Bank_FF); // force new mapping + } + } } + w.cycles+=5; + w.pc+=3; return; } @@ -1082,7 +1100,7 @@ VOID o8083(LPBYTE I) // BUSCB w.cycles+=7; w.pc+=4; // emulated as NOP - // InfoMessage("BUSCB instruction executed."); + // InfoMessage(_T("BUSCB instruction executed.")); return; } @@ -1164,7 +1182,7 @@ VOID o808D(LPBYTE I) // BUSCD w.cycles+=7; w.pc+=4; // emulated as NOP - // InfoMessage("BUSCD instruction executed."); + // InfoMessage(_T("BUSCD instruction executed.")); return; } @@ -1207,7 +1225,7 @@ VOID o80B(LPBYTE I) // BUSCC w.cycles+=6; w.pc+=3; // emulated as NOP - // InfoMessage("BUSCC instruction executed."); + // InfoMessage(_T("BUSCC instruction executed.")); return; } @@ -1233,7 +1251,7 @@ VOID o80E(LPBYTE I) // SREQ? w.cycles+=7; w.pc+=3; w.C[0]=0; - InfoMessage("SREQ? instruction executed."); + // InfoMessage(_T("SREQ? instruction executed.")); return; } @@ -2092,7 +2110,7 @@ VOID o8BF(LPBYTE I) // ?D<=C A VOID o8Cd4(LPBYTE I) // GOLONG #dddd { DWORD d=Npack(I+2, 4); - if (d&0x8000) w.pc-=0xfffe-d; else w.pc+=d+2; + if (d&0x8000) w.pc -= 0xfffe - d; else w.pc+= d + 2; w.cycles+=14; w.pc&=0xFFFFF; return; @@ -2109,7 +2127,7 @@ VOID o8Ed4(LPBYTE I) // GOSUBL #dddd { DWORD d=Npack(I+2,4); rstkpush(w.pc+6); - if (d&0x8000) w.pc-=0xfffa-d; else w.pc+=d+6; + if (d&0x8000) w.pc -= 0xfffa - d; else w.pc += d + 6; w.cycles+=14; w.pc&=0xFFFFF; return; @@ -2363,14 +2381,6 @@ VOID oFD(LPBYTE I) { w.cycles+=7; w.pc+=2; Nnot(w.B, 5); return; } VOID oFE(LPBYTE I) { w.cycles+=7; w.pc+=2; Nnot(w.C, 5); return; } VOID oFF(LPBYTE I) { w.cycles+=7; w.pc+=2; Nnot(w.D, 5); return; } -// invalid, unknown length (LPBYTE I) reset -VOID o_invalid(LPBYTE I) -{ - _ASSERT(FALSE); // invalid, unknow length - w.pc=0; - return; -} - // length is guessed, just skip VOID o_invalid3(LPBYTE I) { @@ -2423,15 +2433,7 @@ VOID o_goyes5(LPBYTE I) } //////// EXTENSIONS //////// -#if 0 // unused extension -VOID o81B0(LPBYTE I) - // ?Win48 - w.HST |= SB; - w.pc+=4; - return; -#endif - -VOID o81B1(LPBYTE I) +VOID o81B1(LPBYTE I) // beep patch { External(&w); PCHANGED; // update field select table diff --git a/sources/Emu48/OPCODES.H b/sources/Emu48/OPCODES.H index 590b37c..2fd9d35 100644 --- a/sources/Emu48/OPCODES.H +++ b/sources/Emu48/OPCODES.H @@ -436,7 +436,6 @@ extern VOID oFD(LPBYTE I); // B=-B-1 A extern VOID oFE(LPBYTE I); // C=-C-1 A extern VOID oFF(LPBYTE I); // D=-D-1 A -extern VOID o_invalid(LPBYTE I); extern VOID o_invalid3(LPBYTE I); extern VOID o_invalid4(LPBYTE I); extern VOID o_invalid5(LPBYTE I); @@ -445,4 +444,4 @@ extern VOID o_invalid6(LPBYTE I); extern VOID o_goyes3(LPBYTE I); extern VOID o_goyes5(LPBYTE I); -extern VOID o81B1(LPBYTE I); +extern VOID o81B1(LPBYTE I); // beep patch diff --git a/sources/Emu48/OPS.H b/sources/Emu48/OPS.H index b761b63..232bea4 100644 --- a/sources/Emu48/OPS.H +++ b/sources/Emu48/OPS.H @@ -6,7 +6,6 @@ * Copyright (C) 1995 Sebastien Carlier * */ -// #pragma warning(disable:4244) #define NFunpack(a, b, f) Nunpack((a)+F_s[f], b, F_l[f]) #define NFread(a, b, f) Nread((a)+F_s[f], b, F_l[f]) @@ -74,7 +73,7 @@ static __inline DWORD rstkpop() return r; } -__inline DWORD Npack(BYTE *a, UINT s) +static __inline DWORD Npack(BYTE *a, UINT s) { DWORD r = 0; @@ -82,7 +81,7 @@ __inline DWORD Npack(BYTE *a, UINT s) return r; } -__inline VOID Nunpack(BYTE *a, DWORD b, UINT s) +static __inline VOID Nunpack(BYTE *a, DWORD b, UINT s) { UINT i; for (i=0; i>=4; } @@ -288,7 +287,7 @@ static __inline void Nneg(BYTE *a, UINT s) BYTE cBase = Chipset.mode_dec ? 10 : 16; for (i=0; i +#include #include +#include #include #include #include diff --git a/sources/Emu48/RESOURCE.H b/sources/Emu48/RESOURCE.H index 60f0a18..c56b8b2 100644 --- a/sources/Emu48/RESOURCE.H +++ b/sources/Emu48/RESOURCE.H @@ -5,19 +5,22 @@ #define IDI_EMU48 100 #define IDR_MENU 101 #define IDR_DEBUG 102 -#define IDR_DEBUG_CODE 103 -#define IDR_DEBUG_MEM 104 -#define IDD_ABOUT 105 -#define IDD_SETTINGS 106 -#define IDD_CHOOSEKML 107 -#define IDD_KMLLOG 108 -#define IDD_DISASM 109 -#define IDD_DEBUG 110 -#define IDD_NEWVALUE 111 -#define IDD_ENTERADR 112 -#define IDD_BREAKEDIT 113 -#define IDD_ENTERBREAK 114 -#define IDD_INSTRUCTIONS 115 +#define IDR_DEBUG_TOOLBAR 103 +#define IDR_DEBUG_CODE 104 +#define IDR_DEBUG_MEM 105 +#define IDD_ABOUT 106 +#define IDD_SETTINGS 107 +#define IDD_CHOOSEKML 108 +#define IDD_KMLLOG 109 +#define IDD_DISASM 110 +#define IDD_DEBUG 111 +#define IDD_NEWVALUE 112 +#define IDD_ENTERADR 113 +#define IDD_BREAKEDIT 114 +#define IDD_ENTERBREAK 115 +#define IDD_INSTRUCTIONS 116 +#define IDD_FIND 117 +#define IDB_CHECKBOX 120 #define IDC_PORT1WR 1000 #define IDC_AUTOSAVE 1001 #define IDC_AUTOSAVEONEXIT 1002 @@ -45,80 +48,83 @@ #define IDC_DISASM_MODULE 1024 #define IDC_DISASM_HP 1025 #define IDC_DISASM_CLASS 1026 -#define IDC_DISASM_MNEMONICS 1027 -#define IDC_ADDRESS 1028 -#define IDC_DISASM_ADR 1029 -#define IDC_DISASM_NEXT 1030 -#define IDC_DISASM_COPY 1031 -#define IDC_DEBUG_CODE 1032 -#define IDC_STATIC_CODE 1033 -#define IDC_STATIC_REGISTERS 1034 -#define IDC_STATIC_MEMORY 1035 -#define IDC_STATIC_STACK 1036 -#define IDC_REG_A 1037 -#define IDC_REG_B 1038 -#define IDC_REG_C 1039 -#define IDC_REG_D 1040 -#define IDC_REG_R0 1041 -#define IDC_REG_R1 1042 -#define IDC_REG_R2 1043 -#define IDC_REG_R3 1044 -#define IDC_REG_R4 1045 -#define IDC_REG_D0 1046 -#define IDC_REG_D1 1047 -#define IDC_REG_P 1048 -#define IDC_REG_PC 1049 -#define IDC_REG_OUT 1050 -#define IDC_REG_IN 1051 -#define IDC_REG_ST 1052 -#define IDC_REG_CY 1053 -#define IDC_REG_MODE 1054 -#define IDC_REG_MP 1055 -#define IDC_REG_SR 1056 -#define IDC_REG_SB 1057 -#define IDC_REG_XM 1058 -#define IDC_MISC_INT 1059 -#define IDC_MISC_KEY 1060 -#define IDC_MISC_BS 1061 -#define IDC_NEWVALUE 1062 -#define IDC_ENTERADR 1063 -#define IDC_DEBUG_MEM 1064 -#define IDC_DEBUG_MEM_ADDR 1065 -#define IDC_DEBUG_MEM_COL0 1066 -#define IDC_DEBUG_MEM_COL1 1067 -#define IDC_DEBUG_MEM_COL2 1068 -#define IDC_DEBUG_MEM_COL3 1069 -#define IDC_DEBUG_MEM_COL4 1070 -#define IDC_DEBUG_MEM_COL5 1071 -#define IDC_DEBUG_MEM_COL6 1072 -#define IDC_DEBUG_MEM_COL7 1073 -#define IDC_DEBUG_MEM_TEXT 1074 -#define IDC_DEBUG_STACK 1075 -#define IDC_STATIC_BREAKPOINT 1076 -#define IDC_BREAKEDIT_ADD 1077 -#define IDC_BREAKEDIT_DELETE 1078 -#define IDC_BREAKEDIT_WND 1079 -#define IDC_STATIC_MMU 1080 -#define IDC_MMU_IO_A 1081 -#define IDC_MMU_NCE2_A 1082 -#define IDC_MMU_CE1_A 1083 -#define IDC_MMU_CE2_A 1084 -#define IDC_MMU_NCE3_A 1085 -#define IDC_MMU_IO_S 1086 -#define IDC_MMU_CE1_S 1087 -#define IDC_MMU_CE2_S 1088 -#define IDC_MMU_NCE2_S 1089 -#define IDC_MMU_NCE3_S 1090 -#define IDC_STATIC_MISC 1091 -#define IDC_MISC_BS_TXT 1092 -#define IDC_INSTR_TEXT 1093 -#define IDC_INSTR_CODE 1094 -#define IDC_INSTR_COPY 1095 -#define IDC_INSTR_CLEAR 1096 -#define IDC_BPCODE 1097 +#define IDC_ADDRESS 1027 +#define IDC_DISASM_ADR 1028 +#define IDC_DISASM_NEXT 1029 +#define IDC_DISASM_COPY 1030 +#define IDC_DEBUG_CODE 1031 +#define IDC_STATIC_CODE 1032 +#define IDC_STATIC_REGISTERS 1033 +#define IDC_STATIC_MEMORY 1034 +#define IDC_STATIC_STACK 1035 +#define IDC_REG_A 1036 +#define IDC_REG_B 1037 +#define IDC_REG_C 1038 +#define IDC_REG_D 1039 +#define IDC_REG_R0 1040 +#define IDC_REG_R1 1041 +#define IDC_REG_R2 1042 +#define IDC_REG_R3 1043 +#define IDC_REG_R4 1044 +#define IDC_REG_D0 1045 +#define IDC_REG_D1 1046 +#define IDC_REG_P 1047 +#define IDC_REG_PC 1048 +#define IDC_REG_OUT 1049 +#define IDC_REG_IN 1050 +#define IDC_REG_ST 1051 +#define IDC_REG_CY 1052 +#define IDC_REG_MODE 1053 +#define IDC_REG_MP 1054 +#define IDC_REG_SR 1055 +#define IDC_REG_SB 1056 +#define IDC_REG_XM 1057 +#define IDC_MISC_INT 1058 +#define IDC_MISC_KEY 1059 +#define IDC_MISC_BS 1060 +#define IDC_NEWVALUE 1061 +#define IDC_ENTERADR 1062 +#define IDC_DEBUG_MEM 1063 +#define IDC_DEBUG_MEM_ADDR 1064 +#define IDC_DEBUG_MEM_COL0 1065 +#define IDC_DEBUG_MEM_COL1 1066 +#define IDC_DEBUG_MEM_COL2 1067 +#define IDC_DEBUG_MEM_COL3 1068 +#define IDC_DEBUG_MEM_COL4 1069 +#define IDC_DEBUG_MEM_COL5 1070 +#define IDC_DEBUG_MEM_COL6 1071 +#define IDC_DEBUG_MEM_COL7 1072 +#define IDC_DEBUG_MEM_TEXT 1073 +#define IDC_DEBUG_STACK 1074 +#define IDC_STATIC_BREAKPOINT 1075 +#define IDC_BREAKEDIT_ADD 1076 +#define IDC_BREAKEDIT_DELETE 1077 +#define IDC_BREAKEDIT_WND 1078 +#define IDC_STATIC_MMU 1079 +#define IDC_MMU_IO_A 1080 +#define IDC_MMU_NCE2_A 1081 +#define IDC_MMU_CE1_A 1082 +#define IDC_MMU_CE2_A 1083 +#define IDC_MMU_NCE3_A 1084 +#define IDC_MMU_IO_S 1085 +#define IDC_MMU_CE1_S 1086 +#define IDC_MMU_CE2_S 1087 +#define IDC_MMU_NCE2_S 1088 +#define IDC_MMU_NCE3_S 1089 +#define IDC_STATIC_MISC 1090 +#define IDC_MISC_BS_TXT 1091 +#define IDC_INSTR_TEXT 1092 +#define IDC_INSTR_CODE 1093 +#define IDC_INSTR_COPY 1094 +#define IDC_INSTR_CLEAR 1095 +#define IDC_BPCODE 1096 +#define IDC_BPRPL 1097 #define IDC_BPACCESS 1098 #define IDC_BPREAD 1099 #define IDC_BPWRITE 1100 +#define IDC_FIND_DATA 1101 +#define IDC_FIND_ASCII 1102 +#define IDC_FIND_CASE 1103 #define ID_FILE_NEW 40001 #define ID_FILE_OPEN 40002 #define ID_FILE_SAVE 40003 @@ -140,33 +146,37 @@ #define ID_TOOL_DISASM 40021 #define ID_TOOL_DEBUG 40022 #define ID_DEBUG_RUN 40023 -#define ID_DEBUG_STEP 40024 -#define ID_DEBUG_STEPOVER 40025 -#define ID_DEBUG_BREAK 40026 -#define ID_DEBUG_STEPOUT 40027 -#define ID_BREAKPOINTS_SETBREAK 40028 -#define ID_BREAKPOINTS_CODEEDIT 40029 -#define ID_BREAKPOINTS_CLEARALL 40030 -#define ID_BREAKPOINTS_NOP3 40031 -#define ID_BREAKPOINTS_RPL 40032 -#define ID_DEBUG_CODE_GOADR 40033 -#define ID_DEBUG_CODE_GOPC 40034 -#define ID_DEBUG_CODE_SETPCTOSELECT 40035 -#define ID_DEBUG_MEM_GOADR 40036 -#define ID_DEBUG_MEM_GOPC 40037 -#define ID_DEBUG_MEM_GOD0 40038 -#define ID_DEBUG_MEM_GOD1 40039 -#define ID_DEBUG_MEM_GOSTACK 40040 -#define ID_INFO_LASTINSTRUCTIONS 40041 -#define ID_INTR_STEPOVERINT 40042 +#define ID_DEBUG_RUNCURSOR 40024 +#define ID_DEBUG_STEP 40025 +#define ID_DEBUG_STEPOVER 40026 +#define ID_DEBUG_BREAK 40027 +#define ID_DEBUG_STEPOUT 40028 +#define ID_DEBUG_CANCEL 40029 +#define ID_BREAKPOINTS_SETBREAK 40030 +#define ID_BREAKPOINTS_CODEEDIT 40031 +#define ID_BREAKPOINTS_CLEARALL 40032 +#define ID_BREAKPOINTS_NOP3 40033 +#define ID_BREAKPOINTS_DOCODE 40034 +#define ID_BREAKPOINTS_RPL 40035 +#define ID_DEBUG_CODE_GOADR 40036 +#define ID_DEBUG_CODE_GOPC 40037 +#define ID_DEBUG_CODE_SETPCTOSELECT 40038 +#define ID_DEBUG_MEM_GOADR 40039 +#define ID_DEBUG_MEM_GOPC 40040 +#define ID_DEBUG_MEM_GOD0 40041 +#define ID_DEBUG_MEM_GOD1 40042 +#define ID_DEBUG_MEM_GOSTACK 40043 +#define ID_DEBUG_MEM_FIND 40044 +#define ID_INFO_LASTINSTRUCTIONS 40045 +#define ID_INTR_STEPOVERINT 40046 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 116 -#define _APS_NEXT_COMMAND_VALUE 40043 -#define _APS_NEXT_CONTROL_VALUE 1101 +#define _APS_NEXT_RESOURCE_VALUE 121 +#define _APS_NEXT_COMMAND_VALUE 40047 +#define _APS_NEXT_CONTROL_VALUE 1104 #define _APS_NEXT_SYMED_VALUE 108 #endif #endif diff --git a/sources/Emu48/RPL.C b/sources/Emu48/RPL.C index 1e10b25..8bd227b 100644 --- a/sources/Emu48/RPL.C +++ b/sources/Emu48/RPL.C @@ -8,15 +8,16 @@ */ #include "pch.h" #include "Emu48.h" +#include "ops.h" #include "io.h" -//| 38G | 48SX | 48GX | 49G | Name -// #7056A #806E9 #806E9 =TEMPOB -// #7056F #806EE #806EE =TEMPTOP -//#F0692 #70574 #806F3 #806F3 =RSKTOP (B) -//#F0697 #70579 #806F8 #806F8 =DSKTOP (D1) -//#F0DEA #7066E #807ED #80E9B =AVMEM (D) -//#F0705 #705B0 #8072F #8076B =INTRPPTR (D0) +//| 38G | 39G | 40G | 48SX | 48GX | 49G | Name +//#F0688 #806E9 #806E9 #7056A #806E9 #806E9 =TEMPOB +//#F068D #806EE #806EE #7056F #806EE #806EE =TEMPTOP +//#F0692 #806F3 #806F3 #70574 #806F3 #806F3 =RSKTOP (B) +//#F0697 #806F8 #806F8 #70579 #806F8 #806F8 =DSKTOP (D1) +//#F0DEA #80E9B #80E9B #7066E #807ED #80E9B =AVMEM (D) +//#F0705 #8076B #8076B #705B0 #8072F #8076B =INTRPPTR (D0) #define TEMPOB ((cCurrentRomType=='S')?0x7056A:0x806E9) #define TEMPTOP ((cCurrentRomType=='S')?0x7056F:0x806EE) @@ -34,7 +35,7 @@ static BOOL Metakernel(VOID) BOOL bMkDetect = FALSE; // card in slot1 of a HP48GX enabled - if (cCurrentRomType=='G' && Chipset.cards_status & PORT1_PRESENT) + if (cCurrentRomType=='G' && Chipset.Port1 && Chipset.cards_status & PORT1_PRESENT) { // check for Metakernel string "MDGKER:" if (!strncmp(&Chipset.Port1[12],"\xD\x4\x4\x4\x7\x4\xB\x4\x5\x4\x2\x5\xA\x3",14)) @@ -255,20 +256,20 @@ DWORD RPL_CreateTemp(DWORD l) DWORD a, b, c; BYTE *p; - l += 6; - a = Read5(TEMPTOP); - b = Read5(RSKTOP); // start of available mem - c = Read5(DSKTOP); // end of available mem - if ((b+l)>c) return 0; // check if there is enough memory - Write5(TEMPTOP, a+l); // adjust end of temporary objects - Write5(RSKTOP, b+l); // adjust start of available mem - Write5(AVMEM, (c-(b+l))/5); // free memory (*5 nibbles) - p = (BYTE*)LocalAlloc(0,b-a); + l += 6; // memory for link field (5) + marker (1) and end + a = Read5(TEMPTOP); // tail address of top object + b = Read5(RSKTOP); // tail address of rtn stack + c = Read5(DSKTOP); // top of data stack + if ((b+l)>c) return 0; // check if there's enough memory to move DSKTOP + 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 = (BYTE*)LocalAlloc(LMEM_FIXED,b-a); // move down rtn stack Npeek(p,a,b-a); Nwrite(p,a+l,b-a); LocalFree(p); - Write5(a+l-5,l); // set temporary object length field - return (a+1); // return temporary object address + Write5(a+l-5,l); // set object length field + return (a+1); // return base address of new object } DWORD RPL_Pick(UINT l) diff --git a/sources/Emu48/SERIAL.C b/sources/Emu48/SERIAL.C index ed8283f..13b3552 100644 --- a/sources/Emu48/SERIAL.C +++ b/sources/Emu48/SERIAL.C @@ -13,25 +13,24 @@ #define INTERRUPT ((void)(Chipset.SoftInt=TRUE,bInterrupt=TRUE)) // state of USRQ -#define NINT2ERBZ ((Chipset.IORam[IOC] & ERBZ) != 0 && (Chipset.IORam[RCS] & RBZ) != 0) -#define NINT2ERBF ((Chipset.IORam[IOC] & ERBF) != 0 && (Chipset.IORam[RCS] & RBF) != 0) -#define NINT2ETBE ((Chipset.IORam[IOC] & ETBE) != 0 && (Chipset.IORam[TCS] & TBF) == 0) +#define NINT2ERBZ ((Chipset.IORam[IOC] & (SON | ERBZ)) == (SON | ERBZ) && (Chipset.IORam[RCS] & RBZ) != 0) +#define NINT2ERBF ((Chipset.IORam[IOC] & (SON | ERBF)) == (SON | ERBF) && (Chipset.IORam[RCS] & RBF) != 0) +#define NINT2ETBE ((Chipset.IORam[IOC] & (SON | ETBE)) == (SON | ETBE) && (Chipset.IORam[TCS] & TBF) == 0) #define NINT2USRQ (NINT2ERBZ || NINT2ERBF || NINT2ETBE) static HANDLE hComm = NULL; static HANDLE hCThread = NULL; -static DWORD lSerialThreadId = 0; -static WORD wPort = PORT_CLOSE; +static DWORD lSerialThreadId; static BOOL bReading; static BYTE cBuffer[128]; static WORD nRp; -static DWORD dwBytesRead = 0L; +static DWORD dwBytesRead; static DWORD WINAPI SerialThread(LPVOID pParam) { - DWORD dwEvent; + DWORD dwEvent; bReading = TRUE; // flag for SerialThread started while (bReading) @@ -49,27 +48,21 @@ static DWORD WINAPI SerialThread(LPVOID pParam) } } } - lSerialThreadId = 0; // signal serial thread is down return 0; UNREFERENCED_PARAMETER(pParam); } -WORD CommConnect(VOID) -{ - return wPort; -} - -VOID CommOpen(LPSTR strWirePort,LPSTR strIrPort) +BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort) { COMMTIMEOUTS CommTimeouts = { MAXDWORD, 0L, 0L, 0L, 0L }; - LPSTR strPort = (Chipset.IORam[IR_CTRL] & EIRU) ? strIrPort : strWirePort; + LPTSTR strPort = (Chipset.IORam[IR_CTRL] & EIRU) ? strIrPort : strWirePort; _ASSERT(Chipset.IORam[IOC] & SON); // UART on if (hComm != NULL) // port already open CloseHandle(hComm); - if (strcmp(strPort, NO_SERIAL)) // port defined + if (lstrcmp(strPort, _T(NO_SERIAL))) // port defined { hComm = CreateFile(strPort, GENERIC_READ | GENERIC_WRITE, @@ -81,7 +74,9 @@ VOID CommOpen(LPSTR strWirePort,LPSTR strIrPort) if(hComm != INVALID_HANDLE_VALUE) { - wPort = (Chipset.IORam[IR_CTRL] & EIRU) ? PORT_IR : PORT_WIRE; + nRp = 0; // reset receiver state + dwBytesRead = 0L; + SetCommTimeouts(hComm,&CommTimeouts); CommSetBaud(); @@ -98,12 +93,12 @@ VOID CommOpen(LPSTR strWirePort,LPSTR strIrPort) #if defined DEBUG_SERIAL { - char buffer[256]; - wsprintf(buffer,"COM port %s.\n",hComm ? "opened": "open error"); + TCHAR buffer[256]; + wsprintf(buffer,_T("COM port %s.\n"),hComm ? _T("opened"): _T("open error")); OutputDebugString(buffer); } #endif - return; + return hComm != NULL; } VOID CommClose(VOID) @@ -113,13 +108,13 @@ VOID CommClose(VOID) Sleep(25); // workaround to fix problems with some Kermit server bReading = FALSE; // kill read thread SetCommMask(hComm,0L); // clear all events and force WaitCommEvent to return - while (lSerialThreadId != 0) Sleep(0); // wait for termination + WaitForSingleObject(hCThread,INFINITE); // wait for thread termination + CloseHandle(hCThread); // close thread handle CloseHandle(hComm); // close port hComm = NULL; #if defined DEBUG_SERIAL - OutputDebugString("COM port closed.\n"); + OutputDebugString(_T("COM port closed.\n")); #endif - wPort = PORT_CLOSE; } return; } @@ -152,8 +147,8 @@ VOID CommSetBaud(VOID) #if defined DEBUG_SERIAL { - char buffer[256]; - wsprintf(buffer,"CommsetBaud: %ld\n",dcb.BaudRate); + TCHAR buffer[256]; + wsprintf(buffer,_T("CommsetBaud: %ld\n"),dcb.BaudRate); OutputDebugString(buffer); } #endif @@ -163,10 +158,11 @@ VOID CommSetBaud(VOID) return; } -VOID UpdateUSRQ(VOID) // USRQ handling +BOOL UpdateUSRQ(VOID) // USRQ handling { - IOBit(SRQ1,USRQ,NINT2USRQ); // update USRQ bit - return; + BOOL bUSRQ = NINT2USRQ; + IOBit(SRQ1,USRQ,bUSRQ); // update USRQ bit + return bUSRQ; } VOID CommTransmit(VOID) @@ -178,17 +174,18 @@ VOID CommTransmit(VOID) #if defined DEBUG_SERIAL { - char buffer[256]; + TCHAR buffer[256]; if (isprint(tbr)) - wsprintf(buffer,"-> '%c'\n",tbr); + wsprintf(buffer,_T("-> '%c'\n"),tbr); else - wsprintf(buffer,"-> %02X\n",tbr); + wsprintf(buffer,_T("-> %02X\n"),tbr); OutputDebugString(buffer); } #endif if (Chipset.IORam[TCS] & LPB) // is loopback bit set { + if (dwBytesRead == 0) nRp = 0; // no character received, reset read pointer cBuffer[nRp+dwBytesRead] = tbr; // save character in receive buffer ++dwBytesRead; @@ -204,8 +201,7 @@ VOID CommTransmit(VOID) } Chipset.IORam[TCS] &= (~TBF); // clear transmit buffer - UpdateUSRQ(); // update USRQ bit - if (Chipset.IORam[IOC] & ETBE) // interrupt on transmit buffer empty + if (UpdateUSRQ()) // update USRQ bit INTERRUPT; return; } @@ -240,11 +236,11 @@ VOID CommReceive(VOID) #if defined DEBUG_SERIAL { - char buffer[256]; + TCHAR buffer[256]; if (isprint(cBuffer[nRp])) - wsprintf(buffer,"<- '%c'\n",cBuffer[nRp]); + wsprintf(buffer,_T("<- '%c'\n"),cBuffer[nRp]); else - wsprintf(buffer,"<- %02X\n",cBuffer[nRp]); + wsprintf(buffer,_T("<- %02X\n"),cBuffer[nRp]); OutputDebugString(buffer); } #endif @@ -255,8 +251,7 @@ VOID CommReceive(VOID) --dwBytesRead; Chipset.IORam[RCS] |= RBF; // receive buffer full - UpdateUSRQ(); // update USRQ bit - if (Chipset.IORam[IOC] & ERBF) // interrupt on recv buffer full + if (UpdateUSRQ()) // update USRQ bit INTERRUPT; } while(0); diff --git a/sources/Emu48/SETTINGS.C b/sources/Emu48/SETTINGS.C index 7c4e3e9..31955fc 100644 --- a/sources/Emu48/SETTINGS.C +++ b/sources/Emu48/SETTINGS.C @@ -3,84 +3,190 @@ * * This file is part of Emu48 * - * Copyright (C) 1995 Sebastien Carlier - * Copyright (C) 1999 Christoph Gießelink + * Copyright (C) 2000 Christoph Gießelink * */ #include "pch.h" #include "Emu48.h" #include "i28f160.h" +// #define REGISTRY // use registry instead of *.ini file + +//################ +//# +//# Low level subroutines +//# +//################ + +#ifndef REGISTRY + #define EMU48_INI "Emu48.ini" +#define ReadString(sec,key,dv,v,sv) GetPrivateProfileString(sec,key,dv,v,sv,_T(EMU48_INI)) +#define ReadInt(sec,key,dv) GetPrivateProfileInt(sec,key,dv,_T(EMU48_INI)); +#define WriteString(sec,key,v) WritePrivateProfileString(sec,key,v,_T(EMU48_INI)) +#define WriteInt(sec,key,v) WritePrivateProfileInt(sec,key,v,_T(EMU48_INI)) + static BOOL WritePrivateProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue, LPCTSTR lpszFilename) { - char s[16]; - wsprintf(s,"%i",nValue); + TCHAR s[16]; + wsprintf(s,_T("%i"),nValue); return WritePrivateProfileString(lpszSection, lpszEntry, s, lpszFilename); } +#else + +#define SUBKEY "Software\\Emu48\\" + +#define ReadString(sec,key,dv,v,sv) GetRegistryString(sec,key,dv,v,sv) +#define ReadInt(sec,key,dv) GetRegistryInt(sec,key,dv) +#define WriteString(sec,key,v) WriteReg(sec,key,REG_SZ,(BYTE *) v,(lstrlen(v)+1) * sizeof(*v)) +#define WriteInt(sec,key,v) WriteReg(sec,key,REG_DWORD,(BYTE *) &v,sizeof(int)) + +static VOID ReadReg(LPCTSTR lpSubKey, LPCTSTR lpValueName, LPBYTE lpData, DWORD *pdwSize) +{ + TCHAR lpKey[256] = _T(SUBKEY); + + DWORD retCode,dwType; + HKEY hKey; + + lstrcat(lpKey, lpSubKey); // full registry key + + retCode = RegOpenKeyEx(HKEY_CURRENT_USER, + lpKey, + 0, + KEY_QUERY_VALUE, + &hKey); + if (retCode == ERROR_SUCCESS) + { + retCode = RegQueryValueEx(hKey,lpValueName,NULL,&dwType,lpData,pdwSize); + RegCloseKey(hKey); + } + + if (retCode != ERROR_SUCCESS) // registry entry not found + *pdwSize = 0; // return zero size + return; +} + +static VOID WriteReg(LPCTSTR lpSubKey, LPCTSTR lpValueName, DWORD dwType, CONST BYTE *lpData, DWORD cbData) +{ + TCHAR lpKey[256] = _T(SUBKEY); + + DWORD retCode; + HKEY hKey; + DWORD dwDisposition; + + lstrcat(lpKey, lpSubKey); // full registry key + + retCode = RegCreateKeyEx(HKEY_CURRENT_USER, + lpKey, + 0,_T(""), + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + NULL, + &hKey, + &dwDisposition); + _ASSERT(retCode == ERROR_SUCCESS); + + RegSetValueEx(hKey,lpValueName,0,dwType,lpData,cbData); + RegCloseKey(hKey); + return; +} + +static DWORD GetRegistryString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpDefault, LPTSTR lpData, DWORD dwSize) +{ + dwSize *= sizeof(*lpData); // buffer size in bytes + ReadReg(lpszSection,lpszEntry,(LPBYTE) lpData,&dwSize); + if (dwSize == 0) + { + lstrcpy(lpData,lpDefault); + dwSize = lstrlen(lpData); + } + else + { + dwSize = (dwSize / sizeof(*lpData)) - 1; + } + return dwSize; +} + +static INT GetRegistryInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, INT nDefault) +{ + UINT nValue; + DWORD dwSize = sizeof(nValue); + + ReadReg(lpszSection,lpszEntry,(LPBYTE) &nValue,&dwSize); + return dwSize ? nValue : nDefault; +} + +#endif + + +//################ +//# +//# Public functions +//# +//################ + VOID ReadSettings(VOID) { // Files - GetPrivateProfileString("Files","Emu48Directory",szCurrentDirectory,szEmu48Directory, - sizeof(szEmu48Directory),EMU48_INI); - bAutoSave = GetPrivateProfileInt("Files","AutoSave",bAutoSave,EMU48_INI); - bAutoSaveOnExit = GetPrivateProfileInt("Files","AutoSaveOnExit",bAutoSaveOnExit,EMU48_INI); + ReadString(_T("Files"),_T("Emu48Directory"),szCurrentDirectory,szEmu48Directory,ARRAYSIZEOF(szEmu48Directory)); + bAutoSave = ReadInt(_T("Files"),_T("AutoSave"),bAutoSave); + bAutoSaveOnExit = ReadInt(_T("Files"),_T("AutoSaveOnExit"),bAutoSaveOnExit); // Port2 - bPort2IsShared = GetPrivateProfileInt("Port2","IsShared",0,EMU48_INI); - GetPrivateProfileString("Port2","Filename","SHARED.BIN",szPort2Filename,sizeof(szPort2Filename),EMU48_INI); + bPort2IsShared = ReadInt(_T("Port2"),_T("IsShared"),bPort2IsShared); + ReadString(_T("Port2"),_T("Filename"),_T("SHARED.BIN"),szPort2Filename,ARRAYSIZEOF(szPort2Filename)); // KML - bAlwaysDisplayLog = GetPrivateProfileInt("KML","AlwaysDisplayLog",bAlwaysDisplayLog,EMU48_INI); + bAlwaysDisplayLog = ReadInt(_T("KML"),_T("AlwaysDisplayLog"),bAlwaysDisplayLog); // Disassebler - disassembler_mode = GetPrivateProfileInt("Disassembler","Mnemonics",disassembler_mode,EMU48_INI); + disassembler_mode = ReadInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode); // Emulator - bRealSpeed = GetPrivateProfileInt("Emulator","RealSpeed",0,EMU48_INI); - dwSXCycles = GetPrivateProfileInt("Emulator","SXCycles",dwSXCycles,EMU48_INI); - dwGXCycles = GetPrivateProfileInt("Emulator","GXCycles",dwGXCycles,EMU48_INI); + bRealSpeed = ReadInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed); + dwSXCycles = ReadInt(_T("Emulator"),_T("SXCycles"),dwSXCycles); + dwGXCycles = ReadInt(_T("Emulator"),_T("GXCycles"),dwGXCycles); SetSpeed(bRealSpeed); // set speed // Serial - GetPrivateProfileString("Serial","Wire",NO_SERIAL,szSerialWire,sizeof(szSerialWire),EMU48_INI); - GetPrivateProfileString("Serial","Ir",NO_SERIAL,szSerialIr,sizeof(szSerialIr),EMU48_INI); + ReadString(_T("Serial"),_T("Wire"),_T(NO_SERIAL),szSerialWire,ARRAYSIZEOF(szSerialWire)); + ReadString(_T("Serial"),_T("Ir"),_T(NO_SERIAL),szSerialIr,ARRAYSIZEOF(szSerialIr)); // ROM - bRomWriteable = GetPrivateProfileInt("ROM","Writeable",TRUE,EMU48_INI); - bWP = GetPrivateProfileInt("ROM","WP#",FALSE,EMU48_INI); + bRomWriteable = ReadInt(_T("ROM"),_T("Writeable"),bRomWriteable); + bWP = ReadInt(_T("ROM"),_T("WP#"),bWP); return; } VOID WriteSettings(VOID) { // Files - WritePrivateProfileString("Files","Emu48Directory",szEmu48Directory,EMU48_INI); - WritePrivateProfileInt("Files","AutoSave",bAutoSave,EMU48_INI); - WritePrivateProfileInt("Files","AutoSaveOnExit",bAutoSaveOnExit,EMU48_INI); + WriteString(_T("Files"),_T("Emu48Directory"),szEmu48Directory); + WriteInt(_T("Files"),_T("AutoSave"),bAutoSave); + WriteInt(_T("Files"),_T("AutoSaveOnExit"),bAutoSaveOnExit); // Port2 - WritePrivateProfileInt("Port2","IsShared",bPort2IsShared,EMU48_INI); - WritePrivateProfileString("Port2","Filename",szPort2Filename,EMU48_INI); + WriteInt(_T("Port2"),_T("IsShared"),bPort2IsShared); + WriteString(_T("Port2"),_T("Filename"),szPort2Filename); // KML - WritePrivateProfileInt("KML","AlwaysDisplayLog",bAlwaysDisplayLog,EMU48_INI); + WriteInt(_T("KML"),_T("AlwaysDisplayLog"),bAlwaysDisplayLog); // Disassebler - WritePrivateProfileInt("Disassembler","Mnemonics",disassembler_mode,EMU48_INI); + WriteInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode); // Emulator - WritePrivateProfileInt("Emulator","RealSpeed",bRealSpeed,EMU48_INI); - WritePrivateProfileInt("Emulator","SXCycles",dwSXCycles,EMU48_INI); - WritePrivateProfileInt("Emulator","GXCycles",dwGXCycles,EMU48_INI); + WriteInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed); + WriteInt(_T("Emulator"),_T("SXCycles"),dwSXCycles); + WriteInt(_T("Emulator"),_T("GXCycles"),dwGXCycles); // Serial - WritePrivateProfileString("Serial","Wire",szSerialWire,EMU48_INI); - WritePrivateProfileString("Serial","Ir",szSerialIr,EMU48_INI); + WriteString(_T("Serial"),_T("Wire"),szSerialWire); + WriteString(_T("Serial"),_T("Ir"),szSerialIr); // ROM - WritePrivateProfileInt("ROM","Writeable",bRomWriteable,EMU48_INI); + WriteInt(_T("ROM"),_T("Writeable"),bRomWriteable); return; } VOID ReadLastDocument(LPTSTR szFilename, DWORD nSize) { - GetPrivateProfileString("Files","LastDocument","",szFilename,nSize,EMU48_INI); + ReadString(_T("Files"),_T("LastDocument"),_T(""),szFilename,nSize); return; } VOID WriteLastDocument(LPCTSTR szFilename) { - WritePrivateProfileString("Files","LastDocument",szFilename,EMU48_INI); + WriteString(_T("Files"),_T("LastDocument"),szFilename); return; } diff --git a/sources/Emu48/TIMER.C b/sources/Emu48/TIMER.C index 2f754db..e05e5a8 100644 --- a/sources/Emu48/TIMER.C +++ b/sources/Emu48/TIMER.C @@ -8,6 +8,7 @@ */ #include "pch.h" #include "Emu48.h" +#include "ops.h" #include "io.h" // I/O definitions #define AUTO_OFF 10 // Time in minutes for 'auto off' @@ -39,7 +40,7 @@ static TIMECAPS tc; // timer information static BOOL bT2Val; // last access values valid -static __inline MAX(int a, int b) {return (a>b)?a:b;} +static __inline int MAX(int a, int b) {return (a>b)?a:b;} static void CALLBACK TimeProc(UINT uEventId, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); @@ -175,7 +176,7 @@ static VOID RescheduleT2(BOOL bRefPoint) uDelay &= 0x7FFFFFFF; // execute timer2 event when MSB change uDelay >>= 3; // timer delay in ms uDelay = MAX(tc.wPeriodMin,uDelay); // wait minimum delay of timer - if (bOutRange = uDelay > tc.wPeriodMax) // delay greater maximum delay + if ((bOutRange = uDelay > tc.wPeriodMax)) // delay greater maximum delay uDelay = tc.wPeriodMax; // wait maximum delay time // start timer2; schedule event, when Chipset.t2 will be zero (Chipset.t2 / 8 = time in ms) uT2TimerId = timeSetEvent(uDelay,0,(LPTIMECALLBACK)&TimeProc,2,TIME_ONESHOT); @@ -310,6 +311,8 @@ VOID StartTimers(VOID) // set timer resolution to 1 ms, if failed don't use "Accurate timer" bAccurateTimer = (timeBeginPeriod(1) == TIMERR_NOERROR); timeGetDevCaps(&tc,sizeof(tc)); // get timer resolution + CheckT1(Chipset.t1); // check for timer1 interrupts + CheckT2(Chipset.t2); // check for timer2 interrupts // set timer1 with given period uT1TimerId = timeSetEvent(T1_FREQ,0,(LPTIMECALLBACK)&TimeProc,1,TIME_PERIODIC); _ASSERT(uT1TimerId); // test if timer1 started diff --git a/sources/GCCPatch/EMU48GCC.RC b/sources/GCCPatch/EMU48GCC.RC new file mode 100644 index 0000000..b575e37 --- /dev/null +++ b/sources/GCCPatch/EMU48GCC.RC @@ -0,0 +1,705 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winresrc.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// French (France) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) +#ifdef _WIN32 +LANGUAGE LANG_FRENCH, SUBLANG_FRENCH +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_FIND, DIALOG + BEGIN + LEFTMARGIN, 6 + RIGHTMARGIN, 190 + TOPMARGIN, 7 + BOTTOMMARGIN, 40 + END + + IDD_BREAKEDIT, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 113 + TOPMARGIN, 5 + BOTTOMMARGIN, 95 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 254 + TOPMARGIN, 6 + BOTTOMMARGIN, 145 + END + + IDD_SETTINGS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 160 + TOPMARGIN, 4 + BOTTOMMARGIN, 202 + END + + IDD_CHOOSEKML, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 59 + END + + IDD_KMLLOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 294 + TOPMARGIN, 7 + BOTTOMMARGIN, 160 + END + + IDD_DISASM, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + TOPMARGIN, 5 + BOTTOMMARGIN, 158 + END + + IDD_DEBUG, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 274 + TOPMARGIN, 17 + BOTTOMMARGIN, 264 + END + + IDD_NEWVALUE, DIALOG + BEGIN + LEFTMARGIN, 8 + RIGHTMARGIN, 168 + TOPMARGIN, 7 + BOTTOMMARGIN, 43 + END + + IDD_ENTERADR, DIALOG + BEGIN + LEFTMARGIN, 8 + RIGHTMARGIN, 149 + TOPMARGIN, 7 + BOTTOMMARGIN, 43 + END + + IDD_ENTERBREAK, DIALOG + BEGIN + LEFTMARGIN, 8 + RIGHTMARGIN, 149 + TOPMARGIN, 7 + BOTTOMMARGIN, 79 + END + + IDD_INSTRUCTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 162 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_FIND DIALOGEX 0, 0, 197, 47 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Find" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Find &what:",IDC_STATIC,7,9,34,8 + COMBOBOX IDC_FIND_DATA,46,7,88,41,CBS_DROPDOWN | CBS_AUTOHSCROLL | + WS_VSCROLL | WS_TABSTOP + CONTROL "Find &ASCII",IDC_FIND_ASCII,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,46,30,49,10 + DEFPUSHBUTTON "Find Next",IDOK,140,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,140,26,50,14 +END + +IDD_BREAKEDIT DIALOG DISCARDABLE 0, 0, 118, 100 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Edit Breakpoints" +FONT 8, "Courier New" +BEGIN + DEFPUSHBUTTON "OK",IDCANCEL,83,81,30,14 + LTEXT "Current breakpoints:",IDC_STATIC_BREAKPOINT,5,5,82,8 + LISTBOX IDC_BREAKEDIT_WND,5,17,108,58,LBS_SORT | + LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | + LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | + LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Add...",IDC_BREAKEDIT_ADD,5,81,30,14 + PUSHBUTTON "&Delete",IDC_BREAKEDIT_DELETE,44,81,30,14 +END + +IDD_ABOUT DIALOGEX 0, 0, 261, 160 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About Emu48" +FONT 8, "MS Sans Serif" +BEGIN + ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE, + WS_EX_TRANSPARENT + LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP + LTEXT "Copyright © 2001 Sébastien Carlier && Christoph Gießelink", + 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 DIALOGEX 0, 0, 167, 209 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Settings" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Authentic Calculator Speed",IDC_REALSPEED,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,13,13,104,10 + CONTROL "Automatically Save Files",IDC_AUTOSAVE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,13,26,89,10 + CONTROL "Automatically Save Files On Exit",IDC_AUTOSAVEONEXIT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,39,114,10 + CONTROL "Always display KML Compilation Result", + IDC_ALWAYSDISPLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 13,52,136,10 + GROUPBOX "General",IDC_STATIC,7,4,153,63 + CONTROL "HP Mnemonics",IDC_DISASM_HP,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,13,81,65,11 + CONTROL "Class Mnemonics",IDC_DISASM_CLASS,"Button", + BS_AUTORADIOBUTTON,84,81,70,11 + GROUPBOX "Disassembler",IDC_STATIC,7,70,153,28 + CONTROL "Port 1 is Plugged",IDC_PORT1EN,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,13,110,67,10 + CONTROL "Port 1 is Writeable",IDC_PORT1WR,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,84,110,69,10 + CONTROL "Port 2 is Shared",IDC_PORT2ISSHARED,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,13,123,65,10 + LTEXT "Port 2 File :",IDC_STATIC,13,136,37,8 + EDITTEXT IDC_PORT2,51,134,104,12,ES_AUTOHSCROLL + GROUPBOX "Memory Cards",IDC_STATIC,7,101,153,50 + LTEXT "Wire:",IDC_STATIC,13,166,17,8 + COMBOBOX IDC_WIRE,31,164,48,42,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP,WS_EX_LEFTSCROLLBAR + LTEXT "IR:",IDC_STATIC,89,166,9,8 + COMBOBOX IDC_IR,107,164,48,43,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + GROUPBOX "Serial Ports",IDC_STATIC,7,154,153,27 + DEFPUSHBUTTON "&Ok",IDOK,9,188,50,14 + PUSHBUTTON "&Cancel",IDCANCEL,107,188,50,14 +END + +IDD_CHOOSEKML DIALOG DISCARDABLE 0, 0, 186, 66 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Choose Your KML Script" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,27,50,14 + COMBOBOX IDC_KMLSCRIPT,7,47,172,120,CBS_DROPDOWNLIST | + CBS_OEMCONVERT | CBS_SORT | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_EMU48DIR,7,17,107,14,ES_AUTOHSCROLL + LTEXT "Emu48 Directory :",IDC_STATIC,7,7,115,8 + LTEXT "Current KML Script :",IDC_STATIC,7,37,115,8 + PUSHBUTTON "V",IDC_UPDATE,115,17,10,14 +END + +IDD_KMLLOG DIALOGEX 0, 0, 301, 167 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "KML Script Compilation Result" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,86,146,50,14 + PUSHBUTTON "Cancel",IDCANCEL,164,146,50,14 + CONTROL "Always",IDC_ALWAYSDISPLOG,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | WS_TABSTOP,263,147,31,13,WS_EX_STATICEDGE + GROUPBOX "",IDC_STATIC,7,7,287,36 + CTEXT "Title of the Script",IDC_TITLE,71,14,158,8 + CTEXT "by",IDC_STATIC,71,22,158,8 + CTEXT "The Author",IDC_AUTHOR,71,30,158,8,NOT WS_GROUP + EDITTEXT IDC_KMLLOG,7,48,287,92,ES_MULTILINE | ES_AUTOHSCROLL | + ES_OEMCONVERT | ES_READONLY | ES_WANTRETURN | NOT + WS_BORDER | WS_VSCROLL | NOT WS_TABSTOP,WS_EX_CLIENTEDGE +END + +IDD_DISASM DIALOGEX 0, 0, 255, 165 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Disassembler" +FONT 8, "Courier New" +BEGIN + LTEXT "Address (HEX):",IDC_ADDRESS,7,147,46,8 + EDITTEXT IDC_DISASM_ADR,56,145,36,12,ES_AUTOHSCROLL + 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 + 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,WS_EX_NOPARENTNOTIFY +END + +IDD_DEBUG DIALOGEX 0, 0, 279, 269 +STYLE WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Debugger" +MENU IDR_DEBUG +FONT 8, "Courier New" +BEGIN + LISTBOX IDC_DEBUG_CODE,11,27,165,122,NOT LBS_NOTIFY | + LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | + LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | + WS_TABSTOP + GROUPBOX "Code",IDC_STATIC_CODE,5,17,177,138 + LTEXT "A= 0000000000000000",IDC_REG_A,192,27,77,8 + LTEXT "B= 0000000000000000",IDC_REG_B,192,34,77,8 + LTEXT "C= 0000000000000000",IDC_REG_C,192,41,77,8 + LTEXT "D= 0000000000000000",IDC_REG_D,192,48,77,8 + LTEXT "R0=0000000000000000",IDC_REG_R0,192,58,77,8 + LTEXT "R1=0000000000000000",IDC_REG_R1,192,65,77,8 + LTEXT "R2=0000000000000000",IDC_REG_R2,192,72,77,8 + LTEXT "R3=0000000000000000",IDC_REG_R3,192,79,77,8 + LTEXT "R4=0000000000000000",IDC_REG_R4,192,86,77,8 + LTEXT "D0=00000",IDC_REG_D0,192,97,33,8 + LTEXT "D1=00000",IDC_REG_D1,236,97,33,8 + LTEXT "P=0",IDC_REG_P,192,108,13,8 + 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 "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 + LTEXT "SR=0",IDC_REG_SR,212,140,17,8 + LTEXT "SB=0",IDC_REG_SB,232,140,17,8 + LTEXT "XM=0",IDC_REG_XM,252,140,17,8 + GROUPBOX "Registers",IDC_STATIC_REGISTERS,187,17,87,138 + CONTROL "",IDC_DEBUG_MEM,"Static",SS_WHITERECT | WS_GROUP,11,166, + 165,52,WS_EX_CLIENTEDGE + LISTBOX IDC_DEBUG_MEM_ADDR,12,168,25,48,NOT LBS_NOTIFY | + LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_DISABLED | NOT + WS_BORDER + LISTBOX IDC_DEBUG_MEM_COL0,40,168,11,48,LBS_NOINTEGRALHEIGHT | + LBS_WANTKEYBOARDINPUT | NOT WS_BORDER | WS_TABSTOP + LISTBOX IDC_DEBUG_MEM_COL1,52,168,11,48,LBS_NOINTEGRALHEIGHT | + LBS_WANTKEYBOARDINPUT | NOT WS_BORDER + LISTBOX IDC_DEBUG_MEM_COL2,64,168,11,48,LBS_NOINTEGRALHEIGHT | + LBS_WANTKEYBOARDINPUT | NOT WS_BORDER + LISTBOX IDC_DEBUG_MEM_COL3,76,168,11,48,LBS_NOINTEGRALHEIGHT | + LBS_WANTKEYBOARDINPUT | NOT WS_BORDER + LISTBOX IDC_DEBUG_MEM_COL4,88,168,11,48,LBS_NOINTEGRALHEIGHT | + LBS_WANTKEYBOARDINPUT | NOT WS_BORDER + LISTBOX IDC_DEBUG_MEM_COL5,100,168,11,48,LBS_NOINTEGRALHEIGHT | + LBS_WANTKEYBOARDINPUT | NOT WS_BORDER + LISTBOX IDC_DEBUG_MEM_COL6,112,168,11,48,LBS_NOINTEGRALHEIGHT | + LBS_WANTKEYBOARDINPUT | NOT WS_BORDER + LISTBOX IDC_DEBUG_MEM_COL7,124,168,11,48,LBS_NOINTEGRALHEIGHT | + LBS_WANTKEYBOARDINPUT | NOT WS_BORDER + LISTBOX IDC_DEBUG_MEM_TEXT,139,168,35,48,NOT LBS_NOTIFY | + LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_DISABLED | NOT + WS_BORDER + GROUPBOX "Memory",IDC_STATIC_MEMORY,5,156,177,68 + LISTBOX IDC_DEBUG_STACK,192,166,76,52,LBS_NOINTEGRALHEIGHT | + LBS_WANTKEYBOARDINPUT | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Stack",IDC_STATIC_STACK,187,156,87,68 + LTEXT "Size Mask",IDC_STATIC,11,243,37,8 + LTEXT "Address",IDC_STATIC,11,251,29,8 + CTEXT "I/O",IDC_STATIC,55,235,21,8 + CTEXT "NCE2",IDC_STATIC,80,235,21,8 + CTEXT "CE1",IDC_STATIC,105,235,21,8 + CTEXT "CE2",IDC_STATIC,130,235,21,8 + CTEXT "NCE3",IDC_STATIC,155,235,21,8 + CTEXT "-----",IDC_MMU_IO_S,55,243,21,8 + CTEXT "-----",IDC_MMU_NCE2_S,80,243,21,8 + CTEXT "-----",IDC_MMU_CE1_S,105,243,21,8 + CTEXT "-----",IDC_MMU_CE2_S,130,243,21,8 + CTEXT "-----",IDC_MMU_NCE3_S,155,243,21,8 + CTEXT "-----",IDC_MMU_IO_A,55,251,21,8 + CTEXT "-----",IDC_MMU_CE1_A,105,251,21,8 + CTEXT "-----",IDC_MMU_CE2_A,130,251,21,8 + CTEXT "-----",IDC_MMU_NCE2_A,80,251,21,8 + CTEXT "-----",IDC_MMU_NCE3_A,155,251,21,8 + GROUPBOX "MMU",IDC_STATIC_MMU,5,225,177,39 + LTEXT "Interrupts =",IDC_STATIC,193,235,61,8 + LTEXT "Keyboard Scan =",IDC_STATIC,193,243,61,8 + LTEXT "Bank Switcher =",IDC_MISC_BS_TXT,193,251,61,8, + WS_DISABLED + LTEXT "",IDC_MISC_INT,256,235,13,8 + LTEXT "",IDC_MISC_KEY,256,243,13,8 + LTEXT "00",IDC_MISC_BS,256,251,13,8,WS_DISABLED + GROUPBOX "Miscellaneous",IDC_STATIC_MISC,187,225,87,39 +END + +IDD_NEWVALUE DIALOG DISCARDABLE 0, 0, 175, 50 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "New Value" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "New value (hexdezimal):",IDC_STATIC,8,9,81,8 + EDITTEXT IDC_NEWVALUE,91,7,77,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,21,29,50,14 + PUSHBUTTON "Cancel",IDCANCEL,103,29,50,14 +END + +IDD_ENTERADR DIALOG DISCARDABLE 0, 0, 156, 50 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Enter Address" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Enter address (hexdezimal):",IDC_STATIC,8,9,90,8 + EDITTEXT IDC_ENTERADR,106,7,43,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,14,29,50,14 + PUSHBUTTON "Cancel",IDCANCEL,92,29,50,14 +END + +IDD_ENTERBREAK DIALOG DISCARDABLE 0, 0, 156, 86 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Enter Breakpoint" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Enter breakpoint (hexdezimal):",IDC_STATIC,8,9,96,8 + EDITTEXT IDC_ENTERADR,110,7,39,12,ES_AUTOHSCROLL + CONTROL "&Code",IDC_BPCODE,"Button",BS_AUTORADIOBUTTON | + WS_GROUP | WS_TABSTOP,17,24,33,10 + CONTROL "R&PL",IDC_BPRPL,"Button",BS_AUTORADIOBUTTON,17,50,30,10 + CONTROL "Memory &Access",IDC_BPACCESS,"Button", + BS_AUTORADIOBUTTON,79,24,63,10 + CONTROL "Memory &Read",IDC_BPREAD,"Button",BS_AUTORADIOBUTTON,79, + 37,60,10 + CONTROL "Memory &Write",IDC_BPWRITE,"Button",BS_AUTORADIOBUTTON, + 79,50,59,10 + DEFPUSHBUTTON "OK",IDOK,14,65,50,14 + PUSHBUTTON "Cancel",IDCANCEL,92,65,50,14 +END + +IDD_INSTRUCTIONS DIALOGEX 0, 0, 186, 169 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Last Instructions" +FONT 8, "Courier New" +BEGIN + LTEXT "Instructions (disassembly maybe incorrect):", + IDC_INSTR_TEXT,7,7,173,8 + LISTBOX IDC_INSTR_CODE,7,18,172,122,NOT LBS_NOTIFY | + LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | + WS_TABSTOP,WS_EX_NOPARENTNOTIFY + PUSHBUTTON "&Copy Data",IDC_INSTR_COPY,7,148,50,14 + PUSHBUTTON "C&lear Data",IDC_INSTR_CLEAR,68,148,50,14 + DEFPUSHBUTTON "Cancel",IDCANCEL,129,148,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_CHECKBOX BITMAP DISCARDABLE "checkbox.bmp" +IDR_DEBUG_TOOLBAR BITMAP MOVEABLE PURE "dbgtool.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Toolbar +// + + +#if 0 + +// with VC++, this definition would be possible: + +IDR_DEBUG_TOOLBAR TOOLBAR DISCARDABLE 16, 15 +BEGIN + BUTTON ID_DEBUG_RUN + BUTTON ID_DEBUG_CANCEL + BUTTON ID_DEBUG_BREAK + SEPARATOR + BUTTON ID_BREAKPOINTS_SETBREAK + BUTTON ID_BREAKPOINTS_CODEEDIT + SEPARATOR + BUTTON ID_DEBUG_STEP + BUTTON ID_DEBUG_STEPOVER + BUTTON ID_DEBUG_STEPOUT + BUTTON ID_DEBUG_RUNCURSOR +END + +#else + +// winres does not recognize TOOLBAR, so this workaround is used: + +IDR_DEBUG_TOOLBAR 241 DISCARDABLE +BEGIN + 1, // wVersion + 16, // wWidth + 15, // wHeight + 11, // wItemCount + ID_DEBUG_RUN, + ID_DEBUG_CANCEL, + ID_DEBUG_BREAK, + 0, + ID_BREAKPOINTS_SETBREAK, + ID_BREAKPOINTS_CODEEDIT, + 0, + ID_DEBUG_STEP, + ID_DEBUG_STEPOVER, + ID_DEBUG_STEPOUT, + ID_DEBUG_RUNCURSOR +END + +#endif + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,2,5,0 + PRODUCTVERSION 1,2,5,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "00000000" + BEGIN + VALUE "CompanyName", "Sebastien Carlier & Christoph Gießelink\0" + VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0" + VALUE "FileVersion", "1, 2, 5, 0\0" + VALUE "InternalName", "Emu48\0" + VALUE "LegalCopyright", "Copyright © 2001\0" + VALUE "OriginalFilename", "Emu48.exe\0" + VALUE "ProductName", "Emu48\0" + VALUE "ProductVersion", "1, 2, 5, 0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 0 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_EMU48 ICON DISCARDABLE "Emu48.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New...", ID_FILE_NEW + MENUITEM "&Open...", ID_FILE_OPEN + MENUITEM "&Save", ID_FILE_SAVE, GRAYED + MENUITEM "Save &As...", ID_FILE_SAVEAS, GRAYED + MENUITEM "&Close", ID_FILE_CLOSE, GRAYED + MENUITEM SEPARATOR + MENUITEM "S&ettings...", ID_VIEW_SETTINGS + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_FILE_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Load Object...", ID_OBJECT_LOAD + MENUITEM "&Save Object...", ID_OBJECT_SAVE + MENUITEM SEPARATOR + MENUITEM "&Copy String", ID_STACK_COPY + MENUITEM "C&opy Screen", ID_VIEW_COPY + MENUITEM "&Paste String", ID_STACK_PASTE + MENUITEM SEPARATOR + MENUITEM "&Reset Calculator", ID_VIEW_RESET, GRAYED + POPUP "&Backup" + BEGIN + MENUITEM "&Save", ID_BACKUP_SAVE, GRAYED + MENUITEM "&Restore", ID_BACKUP_RESTORE + , GRAYED + MENUITEM "&Delete", ID_BACKUP_DELETE, GRAYED + END + END + POPUP "&View" + BEGIN + MENUITEM "Change &KML Script...", ID_VIEW_SCRIPT + END + POPUP "&Tools" + BEGIN + MENUITEM "D&isassembler...", ID_TOOL_DISASM + MENUITEM "&Debugger...", ID_TOOL_DEBUG + END + POPUP "&Help" + BEGIN + MENUITEM "&About Emu48...", ID_ABOUT + END +END + +IDR_DEBUG MENU DISCARDABLE +BEGIN + POPUP "&Debug" + BEGIN + MENUITEM "&Run\tF5", ID_DEBUG_RUN + MENUITEM "Run to &Cursor\tF6", ID_DEBUG_RUNCURSOR + MENUITEM "&Step Into\tF7", ID_DEBUG_STEP + MENUITEM "Step &Over\tF8", ID_DEBUG_STEPOVER + MENUITEM "Step O&ut\tF9", ID_DEBUG_STEPOUT + MENUITEM "&Break\tF11", ID_DEBUG_BREAK + END + POPUP "&Breakpoints" + BEGIN + MENUITEM "Set &Breakpoint\tF2", ID_BREAKPOINTS_SETBREAK + MENUITEM "&Edit Breakpoints...", ID_BREAKPOINTS_CODEEDIT + MENUITEM "&Clear All Breakpoints", ID_BREAKPOINTS_CLEARALL + MENUITEM SEPARATOR + MENUITEM "&NOP3 Code Breakpoints", ID_BREAKPOINTS_NOP3 + MENUITEM "CODE &Object Breakpoints", ID_BREAKPOINTS_DOCODE + MENUITEM SEPARATOR + MENUITEM "&RPL Breakpoints", ID_BREAKPOINTS_RPL + END + POPUP "I&nterrupts" + BEGIN + MENUITEM "&Step Over Interrupts", ID_INTR_STEPOVERINT + END + POPUP "&Info" + BEGIN + MENUITEM "&Last Instructions...", ID_INFO_LASTINSTRUCTIONS + END +END + +IDR_DEBUG_CODE MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Go to address...\tG", ID_DEBUG_CODE_GOADR + MENUITEM "Go to &PC", ID_DEBUG_CODE_GOPC + MENUITEM "Set &breakpoint\tF2", ID_BREAKPOINTS_SETBREAK + MENUITEM "&Set PC to selection", ID_DEBUG_CODE_SETPCTOSELECT + END +END + +IDR_DEBUG_MEM MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Go to address...\tG", ID_DEBUG_MEM_GOADR + MENUITEM "Go to &PC", ID_DEBUG_MEM_GOPC + MENUITEM "Go to D&0", ID_DEBUG_MEM_GOD0 + MENUITEM "Go to D&1", ID_DEBUG_MEM_GOD1 + MENUITEM "Go to &Stack", ID_DEBUG_MEM_GOSTACK + MENUITEM SEPARATOR + MENUITEM "Find...\tF", ID_DEBUG_MEM_FIND + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + ID_DEBUG_RUN "Run" + ID_DEBUG_RUNCURSOR "Run to Cursor" + ID_DEBUG_STEP "Step Into" + ID_DEBUG_STEPOVER "Step Over" + ID_DEBUG_BREAK "Break Execution" + ID_DEBUG_STEPOUT "Step Out" + ID_DEBUG_CANCEL "Stop Debugging" + ID_BREAKPOINTS_SETBREAK "Insert/Remove Breakpoint" + ID_BREAKPOINTS_CODEEDIT "Breakpoint List" +END + +#endif // French (France) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/sources/GCCPatch/Makefile b/sources/GCCPatch/Makefile new file mode 100644 index 0000000..2b65b92 --- /dev/null +++ b/sources/GCCPatch/Makefile @@ -0,0 +1,117 @@ +PRJ=Emu48gcc + +CC=gcc +LD=gcc + +# This is to make GCC not bitch at things M$ allows + +CFLAGS= -Wall -Wno-missing-braces -Wno-format -Wno-uninitialized -O3 + +# Things we need around to compile successfully +# I wonder why we need this _WIN32_IE definition, should take the +# default from the headers, but take a look and win32api 0.5's commctrl.h + +DEFINES= -D_TCHAR=TCHAR -DIDC_STATIC=-1 -D_WIN32_IE=0x0300 + +LDFLAGS= -s -mwindows + +TARGET=$(PRJ).exe + +# +# Warning.. my own resources because WINDRES doesn't understand +# the FONT definition for dialogs produced by the M$ tools +# +RSRC=$(PRJ).rc +RSRCOBJ=$(PRJ).o + +OBJS=disasm.o display.o debugger.o ddeserv.o \ + emu48.o engine.o external.o fetch.o files.o i28f160.o keyboard.o \ + kml.o mops.o opcodes.o rpl.o serial.o settings.o timer.o \ + $(RSRCOBJ) + +LIBS=-lwinmm -lcomctl32 + +all: $(TARGET) + +rebuild: tidy $(TARGET) + +tidy: cleanemacs cleanobj cleanexe + +cleanemacs: + -rm -f *~ + +cleanobj: + -rm -f $(OBJS) + +cleanexe: + -rm -f $(TARGET) + +ddeserv.o: ddeserv.c pch.h emu48.h types.h + $(CC) $(CFLAGS) $(DEFINES) -c -o ddeserv.o ddeserv.c + +debugger.o: debugger.c pch.h resource.h emu48.h \ + types.h opcodes.h ops.h color.h debugger.h + $(CC) $(CFLAGS) $(DEFINES) -c -o debugger.o debugger.c + +disasm.o: disasm.c pch.h emu48.h types.h + $(CC) $(CFLAGS) $(DEFINES) -c -o disasm.o disasm.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 + +emu48.o: emu48.c pch.h resource.h emu48.h types.h \ + io.h kml.h debugger.h + $(CC) $(CFLAGS) $(DEFINES) -c -o emu48.o emu48.c + +engine.o: engine.c pch.h emu48.h types.h opcodes.h \ + io.h debugger.h ops.h + $(CC) $(CFLAGS) $(DEFINES) -c -o engine.o engine.c + +external.o: external.c pch.h emu48.h types.h + $(CC) $(CFLAGS) $(DEFINES) -c -o external.o external.c + +fetch.o: fetch.c pch.h opcodes.h + $(CC) $(CFLAGS) $(DEFINES) -c -o fetch.o fetch.c + +files.o: files.c pch.h emu48.h types.h io.h \ + kml.h i28f160.h debugger.h + $(CC) $(CFLAGS) $(DEFINES) -c -o files.o files.c + +i28f160.o: i28f160.c pch.h emu48.h types.h i28f160.h + $(CC) $(CFLAGS) $(DEFINES) -c -o i28f160.o i28f160.c + +keyboard.o: keyboard.c pch.h emu48.h types.h io.h + $(CC) $(CFLAGS) $(DEFINES) -c -o keyboard.o keyboard.c + +kml.o: kml.c pch.h resource.h emu48.h types.h kml.h + $(CC) $(CFLAGS) $(DEFINES) -c -o kml.o kml.c + +mops.o: mops.c pch.h emu48.h types.h opcodes.h io.h \ + i28f160.h + $(CC) $(CFLAGS) $(DEFINES) -c -o mops.o mops.c + +opcodes.o: opcodes.c pch.h emu48.h types.h opcodes.h \ + io.h ops.h + $(CC) $(CFLAGS) $(DEFINES) -c -o opcodes.o opcodes.c + +# pch.o: pch.c pch.h +# $(CC) $(CFLAGS) $(DEFINES) -c -o pch.o pch.c + +rpl.o: rpl.c pch.h emu48.h types.h io.h + $(CC) $(CFLAGS) $(DEFINES) -c -o rpl.o rpl.c + +serial.o: serial.c pch.h emu48.h types.h io.h + $(CC) $(CFLAGS) $(DEFINES) -c -o serial.o serial.c + +settings.o: settings.c pch.h emu48.h types.h i28f160.h + $(CC) $(CFLAGS) $(DEFINES) -c -o settings.o settings.c + +timer.o: timer.c pch.h emu48.h types.h io.h + $(CC) $(CFLAGS) $(DEFINES) -c -o timer.o timer.c + +$(RSRCOBJ): $(RSRC) resource.h dbgtool.bmp emu48.ico checkbox.bmp + windres $(DEFINES) -i $(RSRC) -o $(RSRCOBJ) + +$(TARGET): $(OBJS) + $(LD) $(LDFLAGS) -o $(TARGET) $(OBJS) $(LIBS) diff --git a/sources/GCCPatch/PCH.H b/sources/GCCPatch/PCH.H new file mode 100644 index 0000000..77ad481 --- /dev/null +++ b/sources/GCCPatch/PCH.H @@ -0,0 +1,37 @@ +// +// PCH.H (MinGW version) +// + +#include +#include +#include +#include +#include +#include // for functions missing in stdlib.h +#include +#include +// #include // missing file + +#define _ASSERT(a) // normally defined in missing crtdbg.h + +#if defined POINTSTOPOINT // wrong implemented, so new correct definition + #undef POINTSTOPOINT + #define POINTSTOPOINT(pt, pts) \ + { (pt).x = (LONG)(SHORT)LOWORD(*(LONG*)&pts); \ + (pt).y = (LONG)(SHORT)HIWORD(*(LONG*)&pts); } +#endif + +#if !defined TTN_GETDISPINFOA // missing + #define TTN_GETDISPINFOA (TTN_FIRST - 0) +#endif +#if !defined TTN_GETDISPINFOW // missing + #define TTN_GETDISPINFOW (TTN_FIRST - 10) +#endif + +#if !defined TTN_GETDISPINFO // missing + #ifdef UNICODE + #define TTN_GETDISPINFO TTN_GETDISPINFOW + #else + #define TTN_GETDISPINFO TTN_GETDISPINFOA + #endif +#endif diff --git a/sources/GCCPatch/ReadMe.txt b/sources/GCCPatch/ReadMe.txt new file mode 100644 index 0000000..40f190a --- /dev/null +++ b/sources/GCCPatch/ReadMe.txt @@ -0,0 +1,25 @@ +********************* +* Emu48 GCC Version * +********************* + +Emu48 is normally compiled with the Microsoft Visual C++ V6.0 compiler. An +alternative is the GCC compiler from the GNU project. A great distribution +of the compiler and the necessary file is MinGW at www.mingw.org. + +Emu48 was tested with the following MinGW file versions: + +libbfd-2.10.91-20010121.zip +binutils-2.10.91-20010114.zip +ld-2.10.91-20010126.zip +gcc-2.95.2-3.zip +w32api-0.5.1.tar.gz +mingw-runtime-0.5-20010221.tar.gz + +Because of some inconsistences in the current MinGW distribution you have to +add the files of this archive to the actual Emu48 source files. + +Many thanks to Pedro A. Arranda Gutiérrez for his work on making Emu48 GCC +compatible. + + +04/21/01 (c) by Christoph Gießelink, cgiess@swol.de diff --git a/sources/MkShared/Main.c b/sources/MkShared/Main.c index 64d9801..d99e696 100644 --- a/sources/MkShared/Main.c +++ b/sources/MkShared/Main.c @@ -3,7 +3,6 @@ #include #include #include -#include HANDLE hFile; DWORD dwWritten; @@ -21,6 +20,9 @@ UINT main(int argc, char *argv[]) nSize = atoi(argv[2]); switch (nSize) { + case 32: + nBlocks = 16; + break; case 128: nBlocks = 64; break; @@ -40,7 +42,7 @@ UINT main(int argc, char *argv[]) nBlocks = 2048; break; default: - puts("Error: Valid sizes are 128, 256, 512, 1024, 2048 and 4096.\n"); + puts("Error: Valid sizes are 32, 128, 256, 512, 1024, 2048 and 4096.\n"); return 0; } @@ -55,6 +57,7 @@ UINT main(int argc, char *argv[]) while (nBlocks--) WriteFile(hFile, pbyBuffer, 4096, &dwWritten, NULL); + LocalFree(pbyBuffer); CloseHandle(hFile); printf("Done."); diff --git a/sources/Mke48/MKE48.C b/sources/Mke48/MKE48.C new file mode 100644 index 0000000..dcb6f89 --- /dev/null +++ b/sources/Mke48/MKE48.C @@ -0,0 +1,120 @@ +/* + * T48G, (c) 2000 Christoph Giesselink (cgiess@swol.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#define WIN32_LEAN_AND_MEAN +#define WIN32_EXTRA_LEAN +#include +#include +#include +#include +#include +#include "types.h" + +#define VERSION "1.0" + +#define _KB(n) (n*1024*2) // KB emulator block + +#define HP48SIG "Emu48 Document\xFE" // HP49 state file signature + +VOID MakeTemplate(FILE *hFile,BYTE type,DWORD Port0Size,DWORD Port1Size) +{ + CHIPSET Chipset; + DWORD dwBytesWritten; + UINT nVar; + BYTE byZ; + + // file signature + WriteFile(hFile,HP48SIG,sizeof(HP48SIG),&dwBytesWritten,NULL); + assert(dwBytesWritten == sizeof(HP48SIG)); + + // KML filename length + nVar = 0; // no name + WriteFile(hFile,&nVar,sizeof(nVar),&dwBytesWritten,NULL); + assert(dwBytesWritten == sizeof(nVar)); + + // KML filename + + // Chipset Size + nVar = sizeof(Chipset); // length, no name + WriteFile(hFile,&nVar,sizeof(nVar),&dwBytesWritten,NULL); + assert(dwBytesWritten == sizeof(nVar)); + + // Chipset + ZeroMemory(&Chipset,sizeof(Chipset)); + Chipset.type = type; + Chipset.Port0Size = Port0Size; + Chipset.Port1Size = Port1Size; + Chipset.Port2Size = 0; + Chipset.cards_status = 0x0; + + WriteFile(hFile,&Chipset,sizeof(Chipset),&dwBytesWritten,NULL); + assert(dwBytesWritten == sizeof(Chipset)); + + byZ = 0; // fill with zero nibble + + // write port0 memory content + for (nVar = 0; nVar < _KB(Chipset.Port0Size); ++nVar) + { + WriteFile(hFile,&byZ,1,&dwBytesWritten,NULL); + assert(dwBytesWritten == 1); + } + + // write port1 memory content + for (nVar = 0; nVar < _KB(Chipset.Port1Size); ++nVar) + { + WriteFile(hFile,&byZ,1,&dwBytesWritten,NULL); + assert(dwBytesWritten == 1); + } + return; +} + +UINT main(int argc, char *argv[]) +{ + HANDLE hFile; + + BYTE type; + DWORD Port0Size; + DWORD Port1Size; + + printf("HP48 State File Template for Emu48 V" VERSION "\n"); + if (argc != 5 || (*argv[2] != 'S' && *argv[2] != 'G')) + { + printf("\nUsage:\n\t%s \n\n", argv[0]); + return 1; + } + + type = *argv[2]; + Port0Size = atoi(argv[3]); + Port1Size = atoi(argv[4]); + + hFile = CreateFile(argv[1],GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + // write template + MakeTemplate(hFile,type,Port0Size,Port1Size); + puts("Generation successful."); + CloseHandle(hFile); + } + else + { + printf("Cannot open file %s.\n", argv[1]); + return TRUE; + } + return FALSE; +} diff --git a/sources/Mke48/MKE48.DSP b/sources/Mke48/MKE48.DSP new file mode 100644 index 0000000..05afec3 --- /dev/null +++ b/sources/Mke48/MKE48.DSP @@ -0,0 +1,103 @@ +# Microsoft Developer Studio Project File - Name="MKE48" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=MKE48 - 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 NMAKE /f "MKE48.MAK". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "MKE48.MAK" CFG="MKE48 - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "MKE48 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "MKE48 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "MKE48 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /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:console /machine:I386 +# ADD 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:console /machine:I386 + +!ELSEIF "$(CFG)" == "MKE48 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /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:console /debug /machine:I386 /pdbtype:sept +# ADD 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:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "MKE48 - Win32 Release" +# Name "MKE48 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\MKE48.C +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\TYPES.H +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/sources/Mke48/TYPES.H b/sources/Mke48/TYPES.H new file mode 100644 index 0000000..456c1aa --- /dev/null +++ b/sources/Mke48/TYPES.H @@ -0,0 +1,103 @@ +/* + * types.h + * + * This file is part of Emu48 + * + * Copyright (C) 1995 Sebastien Carlier + * + */ + +// HST bits +#define XM 1 +#define SB 2 +#define SR 4 +#define MP 8 + +#define SWORD SHORT // signed 16 Bit variable +#define QWORD ULONGLONG // unsigned 64 Bit variable + +#define CHIPSET Chipset_t +typedef struct +{ + SWORD nPosX; // position of window + SWORD nPosY; + BYTE type; // calculator type + + DWORD Port0Size; // real size of module in KB + DWORD Port1Size; // real size of module in KB + DWORD Port2Size; // real size of module in KB (HP49G only) + LPBYTE Port0; + LPBYTE Port1; + LPBYTE Port2; + + DWORD pc; + DWORD d0; + DWORD d1; + DWORD rstkp; + DWORD rstk[8]; + BYTE A[16]; + BYTE B[16]; + BYTE C[16]; + BYTE D[16]; + BYTE R0[16]; + BYTE R1[16]; + BYTE R2[16]; + BYTE R3[16]; + BYTE R4[16]; + BYTE ST[4]; + BYTE HST; + BYTE P; + WORD out; + WORD in; + BOOL SoftInt; + BOOL Shutdn; + BOOL mode_dec; + BOOL inte; // interrupt status flag (FALSE = int in service) + BOOL intk; // 1 ms keyboard scan flag (TRUE = enable) + BOOL intd; // keyboard interrupt pending (TRUE = int pending) + BOOL carry; + + WORD crc; + WORD wPort2Crc; // fingerprint of port2 + WORD wRomCrc; // fingerprint of ROM +#if defined _USRDLL // DLL version + QWORD cycles; // oscillator cycles +#else // EXE version + DWORD cycles; // oscillator cycles + DWORD cycles_reserved; // reserved for MSB of oscillator cycles +#endif + DWORD dwKdnCycles; // cpu cycles at start of 1ms key handler + + UINT Bank_FF; // save state of HP48GX port2 or state of HP49G ROM FF + UINT FlashRomState; // WSM state of flash memory (unused) + BYTE cards_status; + BYTE IORam[64]; // I/O hardware register + UINT IOBase; // address of I/O modules page + BOOL IOCfig; // I/O module configuration flag + BYTE P0Base, BSBase, P1Base, P2Base; // address of modules first 2KB page + BYTE P0Size, BSSize, P1Size, P2Size; // mapped size of module in 2KB + BYTE P0End, BSEnd, P1End, P2End; // address of modules last 2KB page + BOOL P0Cfig, BSCfig, P1Cfig, P2Cfig; // module address configuration flag + BOOL P0Cfg2, BSCfg2, P1Cfg2, P2Cfg2; // module size configuration flag + + BYTE t1; + DWORD t2; + + BOOL bShutdnWake; // flag for wake up from SHUTDN mode + + BYTE Keyboard_Row[9]; + WORD IR15X; + UINT Keyboard_State; // not used + + signed short loffset; + signed int width; + UINT boffset; + UINT lcounter; + UINT sync; // not used + BYTE contrast; + BOOL dispon; + DWORD start1; + DWORD start12; + DWORD end1; + DWORD start2, end2; +} Chipset_t;