2009-08-29: Updated to version 46
Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
This commit is contained in:
parent
34b7d141b8
commit
af664bab5f
29 changed files with 2077 additions and 387 deletions
66
DEBUGGER.TXT
66
DEBUGGER.TXT
|
@ -7,8 +7,40 @@ The debugger was designed to help customers inspecting assembler code objects, a
|
|||
|
||||
After starting the debugger the emulation will stop at the current program counter position. The emulation will continue after closing the debugger window. Please remember that the clock now shows the wrong time.
|
||||
|
||||
1.) System Menu / Debugger Settings
|
||||
|
||||
1.) Menu Debug
|
||||
This is the configuration dialog for the debugger.
|
||||
|
||||
In the "Disassembler" section you can switch between HP and Class Mnemonics for the disassembler. This switch is exactly the same like in the main Settings dialog.
|
||||
|
||||
In the "Symbolic" section you can setup the debugger for symbolic debugging. Therefore the debugger needs a reference file. The reference file must contain a table for converting an absolute address into a symbolic name. I decided to use the HP-TOOLS object files (file extension *.o) with the supported entries. These object files are usually provided by HP for the HP48 and HP49 series and are necessary for linking object files. In the case of older calculators you have to make them by your own. Using the object file for the linker as reference has two disadvantages. First such an object file has an assembler specific output format, in our case the debugger only understands the output format of HP SASM v3.x. Second, in some cases an entries has two or more different names and I cannot control which name is returned.
|
||||
|
||||
Example from ENTRIES.A (HP48 Supported ROM Entry Points)
|
||||
|
||||
=UNROT EQU #60FAC *
|
||||
=3UNROLL EQU #60FAC *
|
||||
=XYZ>ZXY EQU #60FAC *
|
||||
|
||||
My implementation returns the last name inside the linker object file to the chosen address.
|
||||
|
||||
If you don't have the linker object file, the HP28S entry point list for example is only distributed as assembler source file SUPROM28.A, you can simply generate it with
|
||||
|
||||
sasm -N SUPROM28.A
|
||||
|
||||
- Enable
|
||||
|
||||
With an unchecked Enable check box you can disable the symbolic debugging without removing the reference file.
|
||||
|
||||
- Model
|
||||
|
||||
Each calculator model needs his own symbol reference file. The given models exactly corresponds to the one used in the KML script. When you opening the settings dialog automatically the actual model is chosen in the combo box. You can switch to all other possible calculator models to enter the corresponding reference files. When you exit the dialog with the Ok button all filenames are saved.
|
||||
|
||||
- Edit field
|
||||
|
||||
The edit field must contain the filename to the model specific symbol reference file which is chosen by the combo box.
|
||||
|
||||
|
||||
2.) Menu Debug
|
||||
|
||||
- Run F5
|
||||
|
||||
|
@ -69,7 +101,7 @@ So be careful using the F9 key.
|
|||
Stops the emulation at the current program counter position.
|
||||
|
||||
|
||||
2.) Menu Breakpoints
|
||||
3.) Menu Breakpoints
|
||||
|
||||
- Set Breakpoint F2
|
||||
|
||||
|
@ -136,7 +168,7 @@ If this item is checked, the debugger stops program execution at the first instr
|
|||
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
|
||||
4.) Menu Interrupts
|
||||
|
||||
- Step Over Interrupts
|
||||
|
||||
|
@ -145,7 +177,7 @@ If this item is checked, interrupt handler code will be skipped. This option is
|
|||
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
|
||||
5.) Menu Info
|
||||
|
||||
- Last Instructions...
|
||||
|
||||
|
@ -160,7 +192,7 @@ This opens a small toolbox window which shows the number of CPU cycles and the c
|
|||
Some of the display registers have a different meaning on reading and writing. This dialog shows the data written to the write only I/O registers.
|
||||
|
||||
|
||||
5.) Code window
|
||||
6.) Code window
|
||||
|
||||
This windows shows you the disassembled code. The line with the current PC is marked with a "->" or "-R" between the address and the disassembly.
|
||||
|
||||
|
@ -170,7 +202,7 @@ Context menu pressing the right mouse button:
|
|||
|
||||
- Go to address... G
|
||||
|
||||
Moves the cursor to the specified code address.
|
||||
Moves the cursor to the specified code address. Therefore you can enter a hexadecimal number or the symbolic reference name.
|
||||
|
||||
- Go to PC
|
||||
|
||||
|
@ -185,24 +217,24 @@ Toggle a code breakpoint at the cursor position in the Code window.
|
|||
Set the PC to the cursor position. Be careful with this command, you change the execution order of the commands!
|
||||
|
||||
|
||||
6.) Register window
|
||||
7.) Register window
|
||||
|
||||
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 change immediately without any request.
|
||||
|
||||
|
||||
7.) Memory window
|
||||
8.) Memory window
|
||||
|
||||
This windows shows the memory content in the selected context.
|
||||
|
||||
You can use the arrow, PAGE UP and PAGE DOWN keys to move the cursor to a memory position. With a double click on the left mouse button (only in Map mode) you can change the content of the two addresses. When the memory position is read only (ROM or write protected RAM) the content wouldn't change.
|
||||
You can use the arrow, PAGE UP and PAGE DOWN keys to move the cursor to a memory position, the + and - keys change the memory position by one nibble under the cursor. With a double click on the left mouse button (only in Map mode) you can change the content of the two addresses. When the memory position is read only (ROM or write protected RAM) the content wouldn't change.
|
||||
|
||||
Context menu pressing the right mouse button:
|
||||
|
||||
- Go to address... G
|
||||
|
||||
Moves the cursor to the specified memory address.
|
||||
Moves the cursor to the specified memory address. Therefore you can enter a hexadecimal number or the symbolic reference name.
|
||||
|
||||
- Go to PC
|
||||
|
||||
|
@ -234,7 +266,7 @@ This is a special mode of indirect addressing. You can specify an address which
|
|||
|
||||
- Follow Register PC/D0/D1
|
||||
|
||||
The memory window follow the content of the selected register.
|
||||
The Memory window follow the content of the selected register.
|
||||
|
||||
- Find... F
|
||||
|
||||
|
@ -269,8 +301,12 @@ CE1 | nc. | BS | Slt1 32/128KB | BS | BS
|
|||
CE2 | nc. | nc. | Slt2 32/128KB | Slt1 32/128KB | RAM 128KB
|
||||
NCE3 | nc. | RAM 128KB | nc. | Slt2 32KB-4MB | RAM 128KB
|
||||
|
||||
- RPL Object Viewer...
|
||||
|
||||
8.) Stack window
|
||||
This opens a small toolbox window showing the decompiled RPL object at the memory address marked by the cursor. If the toolbox window is already open the content will be updated. There's a problem if you want to select an address inside the marked two addresses. The easiest way to switch the address is the use of the + and - keys changing the memory position by one nibble under the cursor.
|
||||
|
||||
|
||||
9.) Stack window
|
||||
|
||||
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.
|
||||
|
||||
|
@ -289,7 +325,7 @@ Pop the selected element from the stack.
|
|||
Modifies the stack content of the current selection.
|
||||
|
||||
|
||||
9.) MMU window
|
||||
10.) MMU window
|
||||
|
||||
The configuration of the memory controllers is viewed here. The viewed addresses are the first address of each module area and may differ from the given address in the CONFIG command.
|
||||
|
||||
|
@ -303,11 +339,11 @@ This example
|
|||
will config a 128KB module at address #80000 and not at the given address. So the MMU viewer will show you the address #80000.
|
||||
|
||||
|
||||
10.) Miscellaneous window
|
||||
11.) 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 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.
|
||||
|
||||
|
||||
02/24/06 (c) by Christoph Gießelink
|
||||
04/04/09 (c) by Christoph Gießelink
|
||||
|
|
18
EMU48.TXT
18
EMU48.TXT
|
@ -59,8 +59,8 @@ 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.
|
||||
UPLOAD", available at http://hp.giesselink.com/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-file> ROM.39G
|
||||
|
@ -89,7 +89,7 @@ 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
|
||||
ROMDump Wizard http://hp.giesselink.com/index.htm
|
||||
|
||||
- HP49:
|
||||
There's no ROM download program available so far. But you can find a HP49G ROM
|
||||
|
@ -134,7 +134,7 @@ If you want other great scripts, visit 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
|
||||
from Christoph's page at http://hp.giesselink.com/emu48.htm
|
||||
|
||||
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
|
||||
|
@ -414,8 +414,8 @@ The structure of the clipboard format "CF_HPOBJ":
|
|||
* TROUBLE SHOOTING *
|
||||
********************
|
||||
|
||||
Visit the Emu48 FAQ site at http://privat.swol.de/ChristophGiesselink/index.htm
|
||||
to get more information please.
|
||||
Visit the Emu48 FAQ site at http://hp.giesselink.com/index.htm to get more
|
||||
information please.
|
||||
|
||||
|
||||
***********
|
||||
|
@ -425,7 +425,7 @@ to get more information please.
|
|||
We cannot provide any individual support for Emu48. Information about Emu48 will
|
||||
be on the Emu48 Homepage or on the Emu48 FAQ at
|
||||
|
||||
http://privat.swol.de/ChristophGiesselink/index.htm
|
||||
http://hp.giesselink.com/index.htm
|
||||
|
||||
It's also a good idea to look at the Usenet forum comp.sys.hp48. Emu48 topics
|
||||
have discussed there in different threads for years now.
|
||||
|
@ -436,7 +436,7 @@ have discussed there in different threads for years now.
|
|||
***************
|
||||
|
||||
Emu48 - An HP38/39/40/48/49 Emulator
|
||||
Copyright (C) 2007 Sebastien Carlier & Christoph Gießelink
|
||||
Copyright (C) 2009 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
|
||||
|
@ -474,4 +474,4 @@ E-Mail:
|
|||
c dot giesselink at gmx dot de
|
||||
|
||||
Homepage:
|
||||
http://hp.giesselink.com/index.htm
|
||||
http://hp.giesselink.com/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Emu48 1.45+
|
||||
Emu48 1.46+
|
||||
|
||||
Emu48+ is a modified version of Emu48 to add support for the ARM-based
|
||||
calculators. It does not emulate the ARM CPU, but it enhances the
|
||||
|
|
BIN
Emu48.dll
BIN
Emu48.dll
Binary file not shown.
BIN
Emu48.exe
BIN
Emu48.exe
Binary file not shown.
|
@ -1,4 +1,4 @@
|
|||
Known bugs and restrictions of Emu48 V1.47
|
||||
Known bugs and restrictions of Emu48 V1.49
|
||||
------------------------------------------
|
||||
|
||||
- the following I/O bits aren't emulated (incomplete)
|
||||
|
@ -53,4 +53,4 @@ Known bugs and restrictions of Emu48 V1.47
|
|||
- quitting the emulator while programming the flash isn't allowed,
|
||||
because the content of flash state machine isn't saved so far
|
||||
|
||||
04/21/07 (c) by Christoph Gießelink, c dot giesselink at gmx dot de
|
||||
08/18/09 (c) by Christoph Gießelink, c dot giesselink at gmx dot de
|
||||
|
|
|
@ -348,6 +348,7 @@ VOID o80BExt(LPBYTE I) // Saturnator extentions
|
|||
case 0x88: { QWORD a = o80BReg164(I); QWORD b = o80BReg264(I); o80BRegWrite(a<<b, I); w.pc+=2; break; } // r=r<s
|
||||
case 0x89: { QWORD a = o80BReg164(I); QWORD b = o80BReg264(I); o80BRegWrite(a>>b, I); w.pc+=2; break; } // r=r>s
|
||||
case 0x8A: { QWORD a = o80BReg164(I); QWORD b = o80BReg264(I); o80BRegWrite(a^b, I); w.pc+=2; break; } // r=r^s
|
||||
case 0x90: break; // data streamer not implemented
|
||||
case 0xEE: break; // ARMFLUSH not implemented
|
||||
case 0xEF: break; // ARMSYS not implemented
|
||||
case 0xFF: break; // ARMSAT not implemented
|
||||
|
|
|
@ -1,10 +1,210 @@
|
|||
--------------------------------------------------------------------
|
||||
Service Pack 45 for Emu48 Version 1.0
|
||||
Service Pack 46 for Emu48 Version 1.0
|
||||
|
||||
APPLE.C
|
||||
- added BUSCC 09 (opcode 80B90) data streamer implementation as NOP
|
||||
|
||||
DDESERV.C
|
||||
- bugfix in function DdeCallback(), readded delay at XTYP_POKE after
|
||||
ON key state change switching calculator on, bug introduced in
|
||||
SP37
|
||||
|
||||
DEBUGDLL.C
|
||||
- added dummy functions CreateBackupBreakpointList() and
|
||||
RestoreBackupBreakpointList() for linking
|
||||
|
||||
DEBUGGER.C
|
||||
- added backup breakpoint list
|
||||
- bugfix in function InfoWoRegister(), changed WM_COMMAND message
|
||||
handler from IDOK to IDCANCEL to make the close button working
|
||||
properly
|
||||
- added functions SaveBreakpointList() and
|
||||
CreateBackupBreakpointList() to handle the backup breakpoint list
|
||||
|
||||
DEBUGGER.H
|
||||
- extern declaration of global functions
|
||||
|
||||
DISPLAY.C
|
||||
- made gobal variable pbyLcd static
|
||||
|
||||
EMU48.C
|
||||
- bugfix in function OnDropFiles() and OnObjectLoad(), readded
|
||||
delay after ON key state change switching calculator on, bug
|
||||
introduced in SP37
|
||||
- changed function OnFileOpen(), added MruAdd() call
|
||||
- added new function OnFileMruOpen(), command handler for MRU menu
|
||||
selections
|
||||
- changed function OnFileSaveAs(), added MruAdd() call
|
||||
- changed function OnObjectLoad(), changed load object warning
|
||||
message
|
||||
- changed function MainWndProc(), added MRU message handler
|
||||
- changed function WinMain(), added MRU handling
|
||||
- bugfix in function WinMain(), getting the full path name of the
|
||||
current state file failed in the case of an empty name buffer
|
||||
|
||||
EMU48.DSP
|
||||
- added mru.c sources
|
||||
|
||||
EMU48.H
|
||||
- removed extern declaration of pbyLcd
|
||||
- extern declaration of global functions
|
||||
|
||||
EMU48.RC
|
||||
- changed IDD_WRITEONLYREG, changed ID of OK control from IDOK to
|
||||
IDCANCEL
|
||||
- changed IDD_SETTINGS, replaced "Ok" with "OK" and removed
|
||||
accelerator keys from "OK" and "Cancel"
|
||||
- added Menuitem Files "Recent Files..."
|
||||
- changed version and copyright
|
||||
|
||||
EMU48DLL.C
|
||||
- bugfix in function DLLDestroyWnd(), getting the full path name of
|
||||
the current state file failed in the case of an empty name buffer
|
||||
|
||||
FILES.C
|
||||
- bugfix in function OpenDocument(), if document reload was refused
|
||||
the function returned no success -> this caused trouble in
|
||||
function OnFileMruOpen() removing the MRU entry of this document
|
||||
- bugfix in function SaveBackup(), a backup of the debugger
|
||||
breakpoint list wasn't created
|
||||
- bugfix in function RestoreBackup(), the debugger breakpoint list
|
||||
wasn't restored so the breakpoints got lost when saving the state
|
||||
file and added preserving debugger open state, this feature was
|
||||
lost as a result of a bugfix in an earlier version
|
||||
- changed function GetOpenFilename(), added file filter for all
|
||||
Emu48 specific filenames which is default, changed filter names
|
||||
and removed model specific file extention selection
|
||||
- changed function GetSaveAsFilename(), changed filter names and use
|
||||
small size characters for file extentions
|
||||
- changed function DecodeGif(), fixed a GCC type mismatch warning
|
||||
|
||||
KML.C
|
||||
- added token TOK_IFMEM to eIsBlock[] table
|
||||
- added function UpdateScriptList(), filling the KML script combo
|
||||
box with all found script titles and select the current used one
|
||||
- changed function ChooseKMLProc(), call function UpdateScriptList()
|
||||
to update the KML script combo box now
|
||||
- removed function FatalError()
|
||||
- bugfix in function ParseString(), replaced error text
|
||||
- bugfix in function IncludeLines(), removed fatal error message
|
||||
text
|
||||
- bugfix in function ParseLines(), in some cases parsing hadn't
|
||||
stopped with an error inside a block with an unreferenced include
|
||||
file and removed a fatal error message text
|
||||
- bugfix in function ParseBlock(), block argument checking generated
|
||||
wrong error messages in the case of syntax errors
|
||||
- bugfix in function IncludeBlocks(), removed fatal error message
|
||||
text
|
||||
- changed function ParseBlocks(), removed "Invalid block." message
|
||||
text and made some code optimizations calling the function
|
||||
FatalError()
|
||||
- changed function InitGlobal(), changed some punctuation and
|
||||
capital letters
|
||||
- changed function InitButton(), source code improvement checking
|
||||
the size of button array
|
||||
- changed function RunLine(), added implementation of "IfMem"
|
||||
command
|
||||
- bugfix in function ReloadButtons(), global variable bKeyPressed
|
||||
wasn't updated
|
||||
|
||||
KML.H
|
||||
- added TOK_IFMEM definition
|
||||
|
||||
MRU.C
|
||||
- new module for MRU routines
|
||||
|
||||
STACK.C
|
||||
- bugfix in function OnStackPaste(), readded delay after ON key
|
||||
state change switching calculator on
|
||||
|
||||
|
||||
Service Pack 45 for Emu48 Version 1.0
|
||||
|
||||
DEBUGGER.C
|
||||
- added function LoadSymbTable(), loading symbol table defined in
|
||||
INI-File
|
||||
- added function GetMemCurAddr(), get address of cursor in memory
|
||||
window
|
||||
- changed function ViewCodeWnd(), function now returns the line
|
||||
number with the pc, adjusted address to Saturn address area, added
|
||||
label line if address is a known entry and added a check if the 5
|
||||
nibble sequence on an address should be interpreted as PCO
|
||||
- changed function ViewCodeWnd() and InfoIntr(), adjusted to new
|
||||
prototype of function disassemble()
|
||||
- changed function UpdateCodeWnd(), if pc should shown at first line
|
||||
but the pc is the begin of a PCO, show PCO address as first line
|
||||
instead, added handling for label line
|
||||
- changed function OnKeyF5(), for label line support changed
|
||||
detection of PC line
|
||||
- changed function OnCodeGoAdr(), removed limitation to Saturn
|
||||
address area, limitation now done in function ViewCodeWnd()
|
||||
- added function OnKeyPlusMinus(), +/- key handler for memory window
|
||||
- changed function OnKeyCodeWnd(), added handling for label line and
|
||||
removed limitation going back before address 0
|
||||
- changed function OnDrawCodeWnd(), added draw style for label line
|
||||
- changed function Debugger(), added initialization and
|
||||
uninitialization of smybol table and bold font and added +/- key
|
||||
handling for memory window
|
||||
- added functions for Debugger Settings handling
|
||||
- changed function EnterAddr(), added decoding a symbolic entry into
|
||||
an address
|
||||
- changed function InfoIntr(), added label line if instruction
|
||||
address is a known entry
|
||||
|
||||
DISASM.C
|
||||
- added variable disassembler_symb to enable symbolic address
|
||||
disassembly
|
||||
- changed function read_nibble(), made function public
|
||||
- changed function append_imm_nibble(), if the immediate data is 5
|
||||
nibbles long and the decoded data is a known symbolic entry, show
|
||||
the symbolic name instead of the data
|
||||
- added new function append_numaddr(), numeric output of an address
|
||||
- changed function append_addr(), if the address is a known symbolic
|
||||
entry, show the symbolic name instead of the address
|
||||
- bugfix in function append_r_addr(), in some rare conditions the
|
||||
program counter value got larger than 0xFFFFF, if the calculated
|
||||
absolute address is a known symbolic entry show the symbolic name
|
||||
instead of the relative address, in the case of showing the
|
||||
relative address the corresponding absolute address is now printed
|
||||
by this function and not by the function append_pc_comment(), so
|
||||
there's no difference between VIEW_SHORT and VIEW_LONG any more
|
||||
- removed function append_pc_comment(), implementation is obsolete
|
||||
now because absolute address printing is now done in function
|
||||
append_r_addr()
|
||||
- changed function disasm_8() and disassemble(), changed function
|
||||
prototypes by removing the view argument
|
||||
|
||||
DISPLAY.C
|
||||
- changed DIBPIXEL() define, generates the same code on MSVC6.0 but
|
||||
made it GCC compiler compatible
|
||||
|
||||
EMU48.C
|
||||
- changed function Disasm(), adjusted to new prototype of function
|
||||
disassemble()
|
||||
|
||||
EMU48.H
|
||||
- removed VIEW_SHORT and VIEW_LONG definition
|
||||
- changed function prototypes
|
||||
- extern declaration of global variable and functions
|
||||
|
||||
EMU48.RC
|
||||
- added dialog IDD_DEBUG_SETTINGS
|
||||
- changed name order in copyright messages
|
||||
- changed version
|
||||
|
||||
FILES.C
|
||||
- changed function IsDataPacked(), made a DWORD pointer copy of the
|
||||
VOID pointer argument to avoid type casting, this generates the
|
||||
same code on MSVC6.0 but made it GCC compiler compatible
|
||||
- added function DecodeBmp(), contain the BMP image file decoder
|
||||
prior located in function LoadBitmapFile() and added check of
|
||||
bitmap file size
|
||||
- added functions ReadGifByte(), ReadGifWord() and DecodeGif() for
|
||||
decoding GIF image files
|
||||
- bugfix in function LoadBitmapFile(), check for a valid file handle
|
||||
was missing, moved BMP image file decoder to function DecodeBmp()
|
||||
and added GIF image file support
|
||||
|
||||
KML.C
|
||||
- changed szText variable qualifier from LPTSTR to LPCTSTR
|
||||
- changed function CreateKmlList(), adjusted to new prototype of
|
||||
|
@ -16,13 +216,25 @@ KML.C
|
|||
- changed function GetStringParam(), changed return variable
|
||||
qualifier from LPTSTR to LPCTSTR
|
||||
|
||||
PCH.H
|
||||
- added INVALID_SET_FILE_POINTER definition
|
||||
|
||||
RESOURCE.H
|
||||
- added definitions for Debugger Settings handling
|
||||
|
||||
RPL.C
|
||||
- renamed definition DOEREAL to DOEREL and adjusted usage in
|
||||
function RPL_SkipOb() and RPL_ObjectSize()
|
||||
- bugfix in function RPL_SkipOb() and RPL_ObjectSize(), the object
|
||||
at address 0x02BAA was always interpreted as =DOACPTR, a
|
||||
constant-length object consisting of two 5-nibble addresses, on
|
||||
the HP48S series the object is interpreted as =DOEXT1, an object
|
||||
with 5-nibble length information followed by data
|
||||
|
||||
SETTINGS.C
|
||||
- changed function ReadSettings() and WriteSettings(), added item
|
||||
"Symbolic" in section [Disassembler] in the INI-File
|
||||
|
||||
|
||||
Service Pack 44 for Emu48 Version 1.0
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv,
|
|||
{
|
||||
// turn on HP
|
||||
KeyboardEvent(TRUE,0,0x8000);
|
||||
Sleep(200);
|
||||
KeyboardEvent(FALSE,0,0x8000);
|
||||
}
|
||||
|
||||
|
|
|
@ -195,6 +195,22 @@ VOID SaveBreakpointList(HANDLE hFile)
|
|||
UNREFERENCED_PARAMETER(hFile);
|
||||
}
|
||||
|
||||
//
|
||||
// create a copy of the breakpoint list
|
||||
//
|
||||
VOID CreateBackupBreakpointList(VOID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// restore the breakpoint list from the copy
|
||||
//
|
||||
VOID RestoreBackupBreakpointList(VOID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//################
|
||||
//#
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
#define RT_TOOLBAR MAKEINTRESOURCE(241) // MFC toolbar resource type
|
||||
|
||||
#define CODELABEL 0x80000000 // label in code window
|
||||
|
||||
typedef struct CToolBarData
|
||||
{
|
||||
WORD wVersion;
|
||||
|
@ -168,6 +170,9 @@ static INT nDbgPosY = 0;
|
|||
static WORD wBreakpointCount = 0; // number of breakpoints
|
||||
static BP_T sBreakpoint[MAXBREAKPOINTS]; // breakpoint table
|
||||
|
||||
static WORD wBackupBreakpointCount = 0; // number of breakpoints
|
||||
static BP_T sBackupBreakpoint[MAXBREAKPOINTS]; // breakpoint table
|
||||
|
||||
static INT nRplBreak; // RPL breakpoint
|
||||
|
||||
static DWORD dwAdrLine[MAXCODELINES]; // addresses of disassember lines in code window
|
||||
|
@ -193,10 +198,12 @@ static CHIPSET OldChipset; // old chipset content
|
|||
static BOOL bRegUpdate[REG_SIZE]; // register update table
|
||||
|
||||
static HBITMAP hBmpCheckBox; // checked and unchecked bitmap
|
||||
static HFONT hFontBold; // bold font for symbol labels in code window
|
||||
|
||||
// function prototypes
|
||||
static BOOL OnMemFind(HWND hDlg);
|
||||
static BOOL OnProfile(HWND hDlg);
|
||||
static BOOL OnSettings(HWND hDlg);
|
||||
static INT_PTR OnNewValue(LPTSTR lpszValue);
|
||||
static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue);
|
||||
static BOOL OnEditBreakpoint(HWND hDlg);
|
||||
|
@ -210,6 +217,23 @@ static VOID UpdateProfileWnd(HWND hDlg);
|
|||
//#
|
||||
//################
|
||||
|
||||
//
|
||||
// load external rpl symbol table
|
||||
//
|
||||
static BOOL LoadSymbTable(VOID)
|
||||
{
|
||||
TCHAR szSymbFilename[MAX_PATH];
|
||||
TCHAR szItemname[16];
|
||||
|
||||
wsprintf(szItemname,_T("Symb%c"),(TCHAR) cCurrentRomType);
|
||||
ReadSettingsString(_T("Disassembler"),szItemname,_T(""),szSymbFilename,ARRAYSIZEOF(szSymbFilename));
|
||||
|
||||
if (*szSymbFilename == 0) // no reference table defined
|
||||
return FALSE; // no success
|
||||
|
||||
return RplLoadTable(szSymbFilename); // load external reference table
|
||||
}
|
||||
|
||||
//
|
||||
// disable menu keys
|
||||
//
|
||||
|
@ -289,6 +313,27 @@ static VOID SetMappingMenu(HWND hDlg,UINT uID)
|
|||
return;
|
||||
};
|
||||
|
||||
//
|
||||
// get address of cursor in memory window
|
||||
//
|
||||
static DWORD GetMemCurAddr(HWND hDlg)
|
||||
{
|
||||
INT i,nPos;
|
||||
DWORD dwAddr = dwAdrMem;
|
||||
|
||||
for (i = 0; i < MEMWNDMAX; ++i) // scan all memory cols
|
||||
{
|
||||
// column has cursor
|
||||
if ((nPos = (INT) SendDlgItemMessage(hDlg,nCol[i],LB_GETCURSEL,0,0)) != LB_ERR)
|
||||
{
|
||||
dwAddr += (DWORD) (nPos * MEMWNDMAX + i) * 2;
|
||||
dwAddr &= (dwMapDataSize - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dwAddr;
|
||||
}
|
||||
|
||||
//
|
||||
// set/reset breakpoint
|
||||
//
|
||||
|
@ -426,25 +471,66 @@ static VOID StrToReg(BYTE *pReg, WORD wNib, LPTSTR lpszValue)
|
|||
//
|
||||
// write code window
|
||||
//
|
||||
static VOID ViewCodeWnd(HWND hWnd, DWORD dwAddress)
|
||||
static INT ViewCodeWnd(HWND hWnd, DWORD dwAddress)
|
||||
{
|
||||
INT i,j;
|
||||
TCHAR szAddress[64];
|
||||
LPCTSTR lpszName;
|
||||
TCHAR szAddress[64];
|
||||
DWORD dwNxtAddr;
|
||||
INT i,j,nLinePC;
|
||||
|
||||
nLinePC = -1; // PC not shown (no selection)
|
||||
|
||||
_ASSERT(disassembler_map == MEM_MAP); // disassemble in mapped mode
|
||||
dwAddress &= 0xFFFFF; // adjust to Saturn address range
|
||||
SendMessage(hWnd,WM_SETREDRAW,FALSE,0);
|
||||
SendMessage(hWnd,LB_RESETCONTENT,0,0);
|
||||
for (i = 0; i < MAXCODELINES; ++i)
|
||||
{
|
||||
// entry has a name
|
||||
if (disassembler_symb && (lpszName = RplGetName(dwAddress)) != NULL)
|
||||
{
|
||||
// save address as label
|
||||
dwAdrLine[i] = dwAddress | CODELABEL;
|
||||
|
||||
szAddress[0] = _T('=');
|
||||
lstrcpyn(&szAddress[1],lpszName,ARRAYSIZEOF(szAddress)-1);
|
||||
SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szAddress);
|
||||
if (++i == MAXCODELINES) break;
|
||||
}
|
||||
|
||||
// remember line of PC
|
||||
if (dwAddress == Chipset.pc) nLinePC = i;
|
||||
|
||||
dwAdrLine[i] = dwAddress;
|
||||
j = wsprintf(szAddress,
|
||||
(dwAddress == Chipset.pc) ? _T("%05lX-%c ") : _T("%05lX "),
|
||||
dwAddress,nRplBreak ? _T('R') : _T('>'));
|
||||
dwAddress = disassemble(dwAddress,&szAddress[j],VIEW_SHORT);
|
||||
|
||||
dwNxtAddr = (dwAddress + 5) & 0xFFFFF;
|
||||
|
||||
// check if address content is a PCO (Primitive Code Object)
|
||||
// make sure when the PC points to such an address that it's
|
||||
// interpreted as opcode
|
||||
if ((dwAddress != Chipset.pc) && (Read5(dwAddress) == dwNxtAddr))
|
||||
{
|
||||
if (disassembler_mode == HP_MNEMONICS)
|
||||
{
|
||||
_tcscat(&szAddress[j],_T("CON(5) (*)+5"));
|
||||
}
|
||||
else
|
||||
{
|
||||
wsprintf(&szAddress[j],_T("dcr.5 $%05x"),dwNxtAddr);
|
||||
}
|
||||
dwAddress = dwNxtAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwAddress = disassemble(dwAddress,&szAddress[j]);
|
||||
}
|
||||
SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szAddress);
|
||||
}
|
||||
SendMessage(hWnd,WM_SETREDRAW,TRUE,0);
|
||||
return;
|
||||
return nLinePC;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -532,7 +618,7 @@ static VOID ViewMemWnd(HWND hDlg, DWORD dwAddress)
|
|||
//
|
||||
static VOID UpdateCodeWnd(HWND hDlg)
|
||||
{
|
||||
DWORD dwAddress;
|
||||
DWORD dwAddress,dwPriorAddr;
|
||||
INT i,j;
|
||||
|
||||
HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE);
|
||||
|
@ -551,15 +637,28 @@ static VOID UpdateCodeWnd(HWND hDlg)
|
|||
if (i == j) // address not found
|
||||
{
|
||||
dwAddress = Chipset.pc; // begin with actual pc
|
||||
i = 0; // set cursor on top
|
||||
|
||||
// check if current pc is the begin of a PCO, show PCO address
|
||||
dwPriorAddr = (dwAddress - 5) & 0xFFFFF;
|
||||
if (Read5(dwPriorAddr) == dwAddress)
|
||||
dwAddress = dwPriorAddr;
|
||||
}
|
||||
if (i > 10) // cursor near bottom line
|
||||
else
|
||||
{
|
||||
dwAddress = dwAdrLine[i-10]; // move that pc is in line 11
|
||||
i = 10; // set cursor to actual pc
|
||||
if (i > 10) // cursor near bottom line
|
||||
{
|
||||
j = 10; // pc to line 11
|
||||
|
||||
// new address line is label
|
||||
if ((dwAdrLine[i-11] & CODELABEL) != 0)
|
||||
--j; // pc to line 10
|
||||
|
||||
dwAddress = dwAdrLine[i-j]; // move that pc is in line 11
|
||||
}
|
||||
}
|
||||
ViewCodeWnd(hWnd,dwAddress); // init code area
|
||||
SendMessage(hWnd,LB_SETCURSEL,i,0); // set
|
||||
|
||||
i = ViewCodeWnd(hWnd,dwAddress); // init code area
|
||||
SendMessage(hWnd,LB_SETCURSEL,i,0); // set cursor on actual pc
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -873,9 +972,9 @@ static BOOL OnKeyF5(HWND hDlg)
|
|||
// clear "->" in code window
|
||||
for (i = 0; i < MAXCODELINES; ++i)
|
||||
{
|
||||
SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuf);
|
||||
if (szBuf[5] != _T(' ')) // PC in window
|
||||
if (dwAdrLine[i] == Chipset.pc) // PC in window
|
||||
{
|
||||
SendMessage(hWnd,LB_GETTEXT,i,(LPARAM) szBuf);
|
||||
szBuf[5] = szBuf[6] = _T(' ');
|
||||
SendMessage(hWnd,LB_DELETESTRING,i,0);
|
||||
SendMessage(hWnd,LB_INSERTSTRING,i,(LPARAM) szBuf);
|
||||
|
@ -997,7 +1096,7 @@ static BOOL OnCodeGoAdr(HWND hDlg)
|
|||
if (dwAddress != -1)
|
||||
{
|
||||
HWND hWnd = GetDlgItem(hDlg,IDC_DEBUG_CODE);
|
||||
ViewCodeWnd(hWnd,dwAddress & 0xFFFFF);
|
||||
ViewCodeWnd(hWnd,dwAddress);
|
||||
SendMessage(hWnd,LB_SETCURSEL,0,0);
|
||||
}
|
||||
return -1; // call windows default handler
|
||||
|
@ -1499,6 +1598,35 @@ static __inline BOOL OnKeyUpDown(HWND hWnd, WPARAM wParam)
|
|||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// handle (page) +/- keys in memory window
|
||||
//
|
||||
static __inline BOOL OnKeyPlusMinus(HWND hWnd, WPARAM wParam)
|
||||
{
|
||||
INT wX, wY;
|
||||
INT nId;
|
||||
|
||||
nId = GetDlgCtrlID(hWnd); // control ID of window
|
||||
|
||||
for (wX = 0; wX < MEMWNDMAX; ++wX) // scan all Id's
|
||||
if (nCol[wX] == nId) // found ID
|
||||
break;
|
||||
|
||||
if (wX == MEMWNDMAX) return -1; // not IDC_DEBUG_MEM window, default handler
|
||||
|
||||
wY = HIWORD(wParam); // get focus
|
||||
|
||||
if (LOWORD(wParam) == VK_ADD) // move start address of memory view
|
||||
dwAdrMem++;
|
||||
else
|
||||
dwAdrMem--;
|
||||
dwAdrMem &= (dwMapDataSize - 1);
|
||||
|
||||
ViewMemWnd(GetParent(hWnd),dwAdrMem); // redraw memory view
|
||||
SendMessage(hWnd,LB_SETCURSEL,wY,0); // set focus at old position
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// handle keys in code window
|
||||
//
|
||||
|
@ -1511,18 +1639,20 @@ static __inline BOOL OnKeyCodeWnd(HWND hDlg, WPARAM wParam)
|
|||
// down key on last line
|
||||
if ((wKey == VK_DOWN || wKey == VK_NEXT) && wItem == MAXCODELINES - 1)
|
||||
{
|
||||
ViewCodeWnd(hWnd,dwAdrLine[1]);
|
||||
SendMessage(hWnd,LB_SETCURSEL,wItem,0);
|
||||
WORD i = ((dwAdrLine[0] & CODELABEL) != 0) ? 2 : 1;
|
||||
|
||||
ViewCodeWnd(hWnd,dwAdrLine[i]);
|
||||
SendMessage(hWnd,LB_SETCURSEL,wItem-i,0);
|
||||
}
|
||||
// up key on first line
|
||||
if ((wKey == VK_UP || wKey == VK_PRIOR) && wItem == 0)
|
||||
{
|
||||
if (dwAdrLine[0] > 0) ViewCodeWnd(hWnd,dwAdrLine[0]-1);
|
||||
ViewCodeWnd(hWnd,dwAdrLine[0]-1);
|
||||
}
|
||||
|
||||
if (wKey == _T('G')) return OnCodeGoAdr(GetParent(hWnd)); // goto new address
|
||||
|
||||
return -1;
|
||||
return -1; // process key
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1533,7 +1663,8 @@ static __inline BOOL OnDrawCodeWnd(LPDRAWITEMSTRUCT lpdis)
|
|||
TCHAR szBuf[64];
|
||||
COLORREF crBkColor;
|
||||
COLORREF crTextColor;
|
||||
BOOL bBrk,bPC;
|
||||
HFONT hFont;
|
||||
BOOL bBrk,bPC,bLabel;
|
||||
|
||||
if (lpdis->itemID == -1) // no item in list box
|
||||
return TRUE;
|
||||
|
@ -1541,41 +1672,53 @@ static __inline BOOL OnDrawCodeWnd(LPDRAWITEMSTRUCT lpdis)
|
|||
// get item text
|
||||
SendMessage(lpdis->hwndItem,LB_GETTEXT,lpdis->itemID,(LPARAM) szBuf);
|
||||
|
||||
// check for codebreakpoint
|
||||
bBrk = CheckBreakpoint(dwAdrLine[lpdis->itemID],1,BP_EXEC);
|
||||
bPC = szBuf[5] != _T(' '); // check if line of program counter
|
||||
// line is a label
|
||||
bLabel = ((dwAdrLine[lpdis->itemID] & CODELABEL) != 0);
|
||||
|
||||
crTextColor = COLOR_WHITE; // standard text color
|
||||
|
||||
if (lpdis->itemState & ODS_SELECTED) // cursor line
|
||||
if (!bLabel)
|
||||
{
|
||||
if (bPC) // PC line
|
||||
// check for codebreakpoint
|
||||
bBrk = CheckBreakpoint(dwAdrLine[lpdis->itemID],1,BP_EXEC);
|
||||
bPC = szBuf[5] != _T(' '); // check if line of program counter
|
||||
|
||||
crTextColor = COLOR_WHITE; // standard text color
|
||||
|
||||
if (lpdis->itemState & ODS_SELECTED) // cursor line
|
||||
{
|
||||
crBkColor = bBrk ? COLOR_DKGRAY : COLOR_TEAL;
|
||||
if (bPC) // PC line
|
||||
{
|
||||
crBkColor = bBrk ? COLOR_DKGRAY : COLOR_TEAL;
|
||||
}
|
||||
else // normal line
|
||||
{
|
||||
crBkColor = bBrk ? COLOR_PURPLE : COLOR_NAVY;
|
||||
}
|
||||
}
|
||||
else // normal line
|
||||
else // not cursor line
|
||||
{
|
||||
crBkColor = bBrk ? COLOR_PURPLE : COLOR_NAVY;
|
||||
if (bPC) // PC line
|
||||
{
|
||||
crBkColor = bBrk ? COLOR_OLIVE : COLOR_GREEN;
|
||||
}
|
||||
else // normal line
|
||||
{
|
||||
if (bBrk)
|
||||
{
|
||||
crBkColor = COLOR_MAROON;
|
||||
}
|
||||
else
|
||||
{
|
||||
crBkColor = COLOR_WHITE;
|
||||
crTextColor = COLOR_BLACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // not cursor line
|
||||
else // label
|
||||
{
|
||||
if (bPC) // PC line
|
||||
{
|
||||
crBkColor = bBrk ? COLOR_OLIVE : COLOR_GREEN;
|
||||
}
|
||||
else // normal line
|
||||
{
|
||||
if (bBrk)
|
||||
{
|
||||
crBkColor = COLOR_MAROON;
|
||||
}
|
||||
else
|
||||
{
|
||||
crBkColor = COLOR_WHITE;
|
||||
crTextColor = COLOR_BLACK;
|
||||
}
|
||||
}
|
||||
crBkColor = COLOR_WHITE;
|
||||
crTextColor = COLOR_NAVY;
|
||||
hFont = SelectObject(lpdis->hDC,hFontBold);
|
||||
}
|
||||
|
||||
// write Text
|
||||
|
@ -1588,6 +1731,8 @@ static __inline BOOL OnDrawCodeWnd(LPDRAWITEMSTRUCT lpdis)
|
|||
SetBkColor(lpdis->hDC,crBkColor);
|
||||
SetTextColor(lpdis->hDC,crTextColor);
|
||||
|
||||
if (bLabel) SelectObject(lpdis->hDC,hFont);
|
||||
|
||||
if (lpdis->itemState & ODS_FOCUS) // redraw focus
|
||||
DrawFocusRect(lpdis->hDC,&lpdis->rcItem);
|
||||
|
||||
|
@ -1741,6 +1886,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
TEXTMETRIC tm;
|
||||
HDC hDC;
|
||||
HFONT hFont;
|
||||
HMENU hSysMenu;
|
||||
INT i;
|
||||
|
||||
switch (message)
|
||||
|
@ -1749,6 +1895,17 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
SetWindowLocation(hDlg,nDbgPosX,nDbgPosY);
|
||||
if (bAlwaysOnTop) SetWindowPos(hDlg,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
|
||||
SendMessage(hDlg,WM_SETICON,ICON_BIG,(LPARAM) LoadIcon(hApp,MAKEINTRESOURCE(IDI_EMU48)));
|
||||
|
||||
// add Settings item to sysmenu
|
||||
_ASSERT((IDM_DEBUG_SETTINGS & 0xFFF0) == IDM_DEBUG_SETTINGS);
|
||||
_ASSERT(IDM_DEBUG_SETTINGS < 0xF000);
|
||||
|
||||
if ((hSysMenu = GetSystemMenu(hDlg,FALSE)) != NULL)
|
||||
{
|
||||
// VERIFY(AppendMenu(hSysMenu,MF_SEPARATOR,0,NULL));
|
||||
// VERIFY(AppendMenu(hSysMenu,MF_STRING,IDM_DEBUG_SETTINGS,_T("Debugger Settings...")));
|
||||
}
|
||||
|
||||
hWndToolbar = CreateToolbar(hDlg); // add toolbar
|
||||
CheckMenuItem(GetMenu(hDlg),ID_BREAKPOINTS_NOP3, bDbgNOP3 ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(GetMenu(hDlg),ID_BREAKPOINTS_DOCODE,bDbgCode ? MF_CHECKED : MF_UNCHECKED);
|
||||
|
@ -1774,6 +1931,12 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
hMenuStack = GetSubMenu(hMenuMainStack, 0);
|
||||
_ASSERT(hMenuStack);
|
||||
|
||||
// bold font for symbol labels in code window
|
||||
hDC = GetDC(hDlg);
|
||||
VERIFY(hFontBold = CreateFont(-MulDiv(8,GetDeviceCaps(hDC,LOGPIXELSY),72),0,0,0,FW_BOLD,0,0,0,ANSI_CHARSET,
|
||||
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,_T("Arial")));
|
||||
ReleaseDC(hDlg,hDC);
|
||||
|
||||
// font settings
|
||||
SendDlgItemMessage(hDlg,IDC_STATIC_CODE, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
||||
SendDlgItemMessage(hDlg,IDC_STATIC_REGISTERS,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
|
||||
|
@ -1790,6 +1953,8 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
// init "Follow" menu entry in debugger "Memory" context menu
|
||||
CheckMenuItem(hMenuMem,uIDFol,MF_CHECKED);
|
||||
|
||||
LoadSymbTable(); // load external rpl symbol table
|
||||
|
||||
InitMemMap(hDlg); // init memory mapping table
|
||||
InitBsArea(hDlg); // init bank switcher list box
|
||||
DisableMenuKeys(hDlg); // set debug menu keys into run state
|
||||
|
@ -1825,6 +1990,8 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
GetWindowPlacement(hDlg, &wndpl);
|
||||
nDbgPosX = wndpl.rcNormalPosition.left;
|
||||
nDbgPosY = wndpl.rcNormalPosition.top;
|
||||
RplDeleteTable(); // delete rpl symbol table
|
||||
DeleteObject(hFontBold); // delete bold font
|
||||
DestroyMenu(hMenuMainCode);
|
||||
DestroyMenu(hMenuMainMem);
|
||||
DestroyMenu(hMenuMainStack);
|
||||
|
@ -1841,6 +2008,13 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
OnUpdate(hDlg);
|
||||
return TRUE;
|
||||
|
||||
case WM_SYSCOMMAND:
|
||||
if ((wParam & 0xFFF0) == IDM_DEBUG_SETTINGS)
|
||||
{
|
||||
return OnSettings(hDlg);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
switch (HIWORD(wParam))
|
||||
{
|
||||
|
@ -1932,14 +2106,16 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
case IDC_DEBUG_MEM_COL7:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case _T('G'): return OnMemGoAdr(GetParent((HWND) lParam));
|
||||
case _T('F'): return OnMemFind(GetParent((HWND) lParam));
|
||||
case _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_LEFT: return OnKeyRightLeft((HWND) lParam, wParam);
|
||||
case VK_NEXT:
|
||||
case VK_PRIOR:
|
||||
case VK_DOWN:
|
||||
case VK_UP: return OnKeyUpDown((HWND) lParam, wParam);
|
||||
case VK_UP: return OnKeyUpDown((HWND) lParam, wParam);
|
||||
case VK_ADD:
|
||||
case VK_SUBTRACT: return OnKeyPlusMinus((HWND) lParam, wParam);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2280,6 +2456,210 @@ static BOOL OnProfile(HWND hDlg)
|
|||
return -1; // call windows default handler
|
||||
}
|
||||
|
||||
|
||||
//################
|
||||
//#
|
||||
//# Settings dialog box
|
||||
//#
|
||||
//################
|
||||
|
||||
//
|
||||
// copy edit box content to current combox box selection
|
||||
//
|
||||
static VOID CopyEditToCombo(HWND hDlg,HWND hWndComboBox)
|
||||
{
|
||||
TCHAR szSymbFilename[MAX_PATH];
|
||||
INT i;
|
||||
|
||||
// get current selection
|
||||
if ((i = (INT) SendMessage(hWndComboBox,CB_GETCURSEL,0,0)) != CB_ERR)
|
||||
{
|
||||
// delete associated name
|
||||
HeapFree(hHeap,0,(LPVOID) SendMessage(hWndComboBox,CB_GETITEMDATA,i,0));
|
||||
|
||||
// append actual name
|
||||
GetDlgItemText(hDlg,IDC_DEBUG_SET_FILE,szSymbFilename,ARRAYSIZEOF(szSymbFilename));
|
||||
SendMessage(hWndComboBox,CB_SETITEMDATA,i,(LPARAM) DuplicateString(szSymbFilename));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// copy edit box content to current combox box selection
|
||||
//
|
||||
static VOID CopyComboToEdit(HWND hDlg,HWND hWndComboBox)
|
||||
{
|
||||
HWND hWnd;
|
||||
INT i;
|
||||
|
||||
// get current selection
|
||||
if ((i = (INT) SendMessage(hWndComboBox,CB_GETCURSEL,0,0)) != CB_ERR)
|
||||
{
|
||||
// update file edit box
|
||||
hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_FILE);
|
||||
SetWindowText(hWnd,(LPTSTR) SendMessage(hWndComboBox,CB_GETITEMDATA,i,0));
|
||||
SendMessage(hWnd,EM_SETSEL,0,-1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// settings browse dialog
|
||||
//
|
||||
static BOOL OnBrowseSettings(HWND hDlg, HWND hWndFilename)
|
||||
{
|
||||
TCHAR szBuffer[MAX_PATH];
|
||||
OPENFILENAME ofn;
|
||||
|
||||
ZeroMemory(&ofn, sizeof(OPENFILENAME));
|
||||
ofn.lStructSize = sizeof(OPENFILENAME);
|
||||
ofn.hwndOwner = hDlg;
|
||||
ofn.lpstrFilter =
|
||||
_T("HP-Tools Linker File (*.O)\0*.O\0")
|
||||
_T("All Files (*.*)\0*.*\0");
|
||||
ofn.lpstrDefExt = _T("O");
|
||||
ofn.nFilterIndex = 1;
|
||||
ofn.lpstrFile = szBuffer;
|
||||
ofn.lpstrFile[0] = 0;
|
||||
ofn.nMaxFile = ARRAYSIZEOF(szBuffer);
|
||||
ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST;
|
||||
if (GetOpenFileName(&ofn))
|
||||
{
|
||||
SetWindowText(hWndFilename,szBuffer);
|
||||
SendMessage(hWndFilename,EM_SETSEL,0,-1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// enter settings dialog
|
||||
//
|
||||
static INT_PTR CALLBACK Settings(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
HWND hWnd;
|
||||
TCHAR szSymbFilename[MAX_PATH];
|
||||
TCHAR szItemname[16];
|
||||
INT i,nMax;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
// set disassembler mode
|
||||
CheckDlgButton(hDlg,(disassembler_mode == HP_MNEMONICS) ? IDC_DISASM_HP : IDC_DISASM_CLASS,BST_CHECKED);
|
||||
// set symbolic enable check button
|
||||
CheckDlgButton(hDlg,IDC_DEBUG_SET_SYMB,disassembler_symb);
|
||||
// fill model combo box and corresponding file edit box
|
||||
{
|
||||
LPCTSTR lpszModels;
|
||||
TCHAR cModel[] = _T(" ");
|
||||
|
||||
// fill model combo box
|
||||
hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_MODEL);
|
||||
for (lpszModels = _T(MODELS); *lpszModels != 0; ++lpszModels)
|
||||
{
|
||||
cModel[0] = *lpszModels; // string with model character
|
||||
i = (INT) SendMessage(hWnd,CB_ADDSTRING,0,(LPARAM) cModel);
|
||||
|
||||
// get filename
|
||||
wsprintf(szItemname,_T("Symb%c"),cModel[0]);
|
||||
ReadSettingsString(_T("Disassembler"),szItemname,_T(""),szSymbFilename,ARRAYSIZEOF(szSymbFilename));
|
||||
|
||||
// append filename to model
|
||||
SendMessage(hWnd,CB_SETITEMDATA,i,(LPARAM) DuplicateString(szSymbFilename));
|
||||
}
|
||||
|
||||
// select for actual model
|
||||
cModel[0] = (TCHAR) cCurrentRomType;
|
||||
if ((i = (INT) SendMessage(hWnd,CB_SELECTSTRING,0,(LPARAM) cModel)) != CB_ERR)
|
||||
{
|
||||
LPTSTR lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0);
|
||||
|
||||
// fill file edit box
|
||||
hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_FILE);
|
||||
SetWindowText(hWnd,lpszFilename);
|
||||
SendMessage(hWnd,EM_SETSEL,0,-1);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
case WM_COMMAND:
|
||||
switch(LOWORD(wParam))
|
||||
{
|
||||
case IDC_DEBUG_SET_MODEL:
|
||||
// combo box changing item
|
||||
if (HIWORD(wParam) == CBN_SETFOCUS)
|
||||
{
|
||||
// update associated name with file edit box
|
||||
CopyEditToCombo(hDlg,(HWND) lParam);
|
||||
}
|
||||
// new combo box item selected
|
||||
if (HIWORD(wParam) == CBN_SELENDOK)
|
||||
{
|
||||
// update file edit box with associated name
|
||||
CopyComboToEdit(hDlg,(HWND) lParam);
|
||||
}
|
||||
break;
|
||||
case IDC_DEBUG_SET_BROWSE:
|
||||
return OnBrowseSettings(hDlg,GetDlgItem(hDlg,IDC_DEBUG_SET_FILE));
|
||||
case IDOK:
|
||||
// set disassembler mode
|
||||
disassembler_mode = IsDlgButtonChecked(hDlg,IDC_DISASM_HP) ? HP_MNEMONICS : CLASS_MNEMONICS;
|
||||
// set symbolic enable check button
|
||||
disassembler_symb = IsDlgButtonChecked(hDlg,IDC_DEBUG_SET_SYMB);
|
||||
// update associated name with file edit box
|
||||
hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_MODEL);
|
||||
CopyEditToCombo(hDlg,hWnd);
|
||||
// write all symbol filenames to registry
|
||||
nMax = (INT) SendMessage(hWnd,CB_GETCOUNT,0,0);
|
||||
for (i = 0; i < nMax; ++i)
|
||||
{
|
||||
LPTSTR lpszFilename;
|
||||
|
||||
SendMessage(hWnd,CB_GETLBTEXT,i,(LPARAM) szSymbFilename);
|
||||
wsprintf(szItemname,_T("Symb%c"),szSymbFilename[0]);
|
||||
lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0);
|
||||
if (*lpszFilename == 0) // empty
|
||||
{
|
||||
DelSettingsKey(_T("Disassembler"),szItemname);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteSettingsString(_T("Disassembler"),szItemname,lpszFilename);
|
||||
}
|
||||
}
|
||||
RplDeleteTable(); // delete rpl symbol table
|
||||
LoadSymbTable(); // reload external rpl symbol table
|
||||
// redraw debugger code view
|
||||
ViewCodeWnd(GetDlgItem(GetParent(hDlg),IDC_DEBUG_CODE),dwAdrLine[0]);
|
||||
// no break
|
||||
case IDCANCEL:
|
||||
// free combo box items
|
||||
hWnd = GetDlgItem(hDlg,IDC_DEBUG_SET_MODEL);
|
||||
nMax = (INT) SendMessage(hWnd,CB_GETCOUNT,0,0);
|
||||
for (i = 0; i < nMax; ++i)
|
||||
{
|
||||
LPTSTR lpszFilename = (LPTSTR) SendMessage(hWnd,CB_GETITEMDATA,i,0);
|
||||
if (lpszFilename != NULL)
|
||||
{
|
||||
HeapFree(hHeap,0,lpszFilename);
|
||||
}
|
||||
}
|
||||
EndDialog(hDlg,LOWORD(wParam));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
UNREFERENCED_PARAMETER(wParam);
|
||||
UNREFERENCED_PARAMETER(lParam);
|
||||
}
|
||||
|
||||
static BOOL OnSettings(HWND hDlg)
|
||||
{
|
||||
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_SETTINGS), hDlg, (DLGPROC)Settings) == -1)
|
||||
AbortMessage(_T("Settings Dialog Box Creation Error !"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//################
|
||||
//#
|
||||
//# New Value dialog box
|
||||
|
@ -2361,16 +2741,16 @@ static INT_PTR OnNewValue(LPTSTR lpszValue)
|
|||
//
|
||||
static INT_PTR CALLBACK EnterAddr(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static DWORD *dwAddress;
|
||||
static DWORD *pdwAddress;
|
||||
|
||||
HWND hWnd;
|
||||
TCHAR szBuffer[8];
|
||||
TCHAR szBuffer[64];
|
||||
LONG i;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
dwAddress = (DWORD *) lParam;
|
||||
pdwAddress = (DWORD *) lParam;
|
||||
return TRUE;
|
||||
case WM_COMMAND:
|
||||
wParam = LOWORD(wParam);
|
||||
|
@ -2379,17 +2759,23 @@ static INT_PTR CALLBACK EnterAddr(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
case IDOK:
|
||||
hWnd = GetDlgItem(hDlg,IDC_ENTERADR);
|
||||
GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer));
|
||||
// test if valid hex address
|
||||
for (i = 0; i < (LONG) lstrlen(szBuffer); ++i)
|
||||
|
||||
// if address is not a symbol name decode number
|
||||
if ( !disassembler_symb || szBuffer[0] != _T('=')
|
||||
|| RplGetAddr(&szBuffer[1],pdwAddress))
|
||||
{
|
||||
if (_istxdigit(szBuffer[i]) == 0)
|
||||
// test if valid hex address
|
||||
for (i = 0; i < (LONG) lstrlen(szBuffer); ++i)
|
||||
{
|
||||
SendMessage(hWnd,EM_SETSEL,0,-1);
|
||||
SetFocus(hWnd); // focus to edit control
|
||||
return FALSE;
|
||||
if (_istxdigit(szBuffer[i]) == 0)
|
||||
{
|
||||
SendMessage(hWnd,EM_SETSEL,0,-1);
|
||||
SetFocus(hWnd); // focus to edit control
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (*szBuffer) _stscanf(szBuffer,_T("%6X"),pdwAddress);
|
||||
}
|
||||
if (*szBuffer) _stscanf(szBuffer,_T("%6X"),dwAddress);
|
||||
// no break
|
||||
case IDCANCEL:
|
||||
EndDialog(hDlg,wParam);
|
||||
|
@ -2803,8 +3189,18 @@ static INT_PTR CALLBACK InfoIntr(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
SendMessage(hWnd,LB_RESETCONTENT,0,0);
|
||||
for (i = wInstrRp; i != wInstrWp; i = (i + 1) % wInstrSize)
|
||||
{
|
||||
LPCTSTR lpszName;
|
||||
|
||||
// entry has a name
|
||||
if (disassembler_symb && (lpszName = RplGetName(pdwInstrArray[i])) != NULL)
|
||||
{
|
||||
szBuffer[0] = _T('=');
|
||||
lstrcpyn(&szBuffer[1],lpszName,ARRAYSIZEOF(szBuffer)-1);
|
||||
SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer);
|
||||
}
|
||||
|
||||
j = wsprintf(szBuffer,_T("%05lX "),pdwInstrArray[i]);
|
||||
disassemble(pdwInstrArray[i],&szBuffer[j],VIEW_SHORT);
|
||||
disassemble(pdwInstrArray[i],&szBuffer[j]);
|
||||
lIndex = (LONG) SendMessage(hWnd,LB_ADDSTRING,0,(LPARAM) szBuffer);
|
||||
}
|
||||
SendMessage(hWnd,WM_SETREDRAW,TRUE,0);
|
||||
|
@ -2857,9 +3253,9 @@ static BOOL CALLBACK InfoWoRegister(HWND hDlg, UINT message, DWORD wParam, LONG
|
|||
SetDlgItemText(hDlg,IDC_ADDR30_34,szBuffer);
|
||||
return TRUE;
|
||||
case WM_COMMAND:
|
||||
if ((LOWORD(wParam) == IDOK))
|
||||
if ((LOWORD(wParam) == IDCANCEL))
|
||||
{
|
||||
EndDialog(hDlg,IDOK);
|
||||
EndDialog(hDlg,IDCANCEL);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -2877,7 +3273,7 @@ static BOOL OnInfoWoRegister(HWND hDlg)
|
|||
|
||||
//################
|
||||
//#
|
||||
//# File operations
|
||||
//# Breakpoint list operations
|
||||
//#
|
||||
//################
|
||||
|
||||
|
@ -2941,3 +3337,35 @@ VOID SaveBreakpointList(HANDLE hFile)
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// create a copy of the breakpoint list
|
||||
//
|
||||
VOID CreateBackupBreakpointList(VOID)
|
||||
{
|
||||
_ASSERT(sizeof(sBackupBreakpoint) == sizeof(sBreakpoint));
|
||||
|
||||
wBackupBreakpointCount = wBreakpointCount;
|
||||
|
||||
if (wBreakpointCount > 0) // list not empty
|
||||
{
|
||||
CopyMemory(sBackupBreakpoint,sBreakpoint,sizeof(sBackupBreakpoint));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// restore the breakpoint list from the copy
|
||||
//
|
||||
VOID RestoreBackupBreakpointList(VOID)
|
||||
{
|
||||
_ASSERT(sizeof(sBackupBreakpoint) == sizeof(sBreakpoint));
|
||||
|
||||
wBreakpointCount = wBackupBreakpointCount;
|
||||
|
||||
if (wBreakpointCount > 0) // list not empty
|
||||
{
|
||||
CopyMemory(sBreakpoint,sBackupBreakpoint,sizeof(sBreakpoint));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -35,3 +35,5 @@ extern VOID DisableDebugger(VOID);
|
|||
extern LRESULT OnToolDebug(VOID);
|
||||
extern VOID LoadBreakpointList(HANDLE hFile);
|
||||
extern VOID SaveBreakpointList(HANDLE hFile);
|
||||
extern VOID CreateBackupBreakpointList(VOID);
|
||||
extern VOID RestoreBackupBreakpointList(VOID);
|
||||
|
|
144
source/DISASM.C
144
source/DISASM.C
|
@ -15,6 +15,7 @@
|
|||
#define TAB_SKIP 8
|
||||
|
||||
BOOL disassembler_mode = HP_MNEMONICS;
|
||||
BOOL disassembler_symb = FALSE;
|
||||
WORD disassembler_map = MEM_MAP;
|
||||
|
||||
static LPCTSTR hex[] =
|
||||
|
@ -278,7 +279,9 @@ static BYTE rn_port2 (DWORD *p)
|
|||
return *(pbyVal + d);
|
||||
}
|
||||
|
||||
static BYTE read_nibble (DWORD *p)
|
||||
// global functions
|
||||
|
||||
BYTE read_nibble (DWORD *p)
|
||||
{
|
||||
BYTE (*pnread[])(DWORD *) = { rn_map, rn_rom, rn_ram, rn_port1, rn_port2 };
|
||||
|
||||
|
@ -327,8 +330,10 @@ static __inline LPTSTR append_field (LPTSTR buf, BYTE fn)
|
|||
static LPTSTR append_imm_nibble (LPTSTR buf, DWORD *addr, int n)
|
||||
{
|
||||
int i;
|
||||
TCHAR t[16];
|
||||
BYTE t[16];
|
||||
|
||||
LPTSTR p = buf; // save start of buffer
|
||||
|
||||
if (disassembler_mode == CLASS_MNEMONICS)
|
||||
{
|
||||
*buf++ = _T('#');
|
||||
|
@ -342,91 +347,101 @@ static LPTSTR append_imm_nibble (LPTSTR buf, DWORD *addr, int n)
|
|||
}
|
||||
if (n > 1)
|
||||
{
|
||||
DWORD dwAddr = 0; // decoded address
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
t[i] = hex[disassembler_mode][read_nibble (addr)];
|
||||
t[i] = read_nibble (addr);
|
||||
|
||||
for (i = n - 1; i >= 0; i--)
|
||||
{
|
||||
*buf++ = t[i];
|
||||
dwAddr = (dwAddr << 4) | t[i];
|
||||
*buf++ = hex[disassembler_mode][t[i]];
|
||||
}
|
||||
*buf = 0;
|
||||
|
||||
if (n == 5) // 5 nibble address
|
||||
{
|
||||
LPCTSTR lpszName;
|
||||
|
||||
if (disassembler_symb && (lpszName = RplGetName(dwAddr)) != NULL)
|
||||
{
|
||||
// overwrite number with symbolic name
|
||||
buf = append_str(p, _T("="));
|
||||
buf = append_str(buf, lpszName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else // single nibble
|
||||
{
|
||||
wsprintf (t, _T("%d"), read_nibble (addr));
|
||||
buf = append_str (buf, t);
|
||||
buf += wsprintf (buf, _T("%d"), read_nibble (addr));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static LPTSTR append_addr (LPTSTR buf, DWORD addr)
|
||||
static LPTSTR append_numaddr (LPTSTR buf, DWORD addr)
|
||||
{
|
||||
int shift;
|
||||
long mask;
|
||||
|
||||
if (disassembler_mode == CLASS_MNEMONICS)
|
||||
{
|
||||
*buf++ = _T('$');
|
||||
}
|
||||
for (mask = 0xf0000, shift = 16; mask != 0; mask >>= 4, shift -= 4)
|
||||
*buf++ = hex[disassembler_mode][(addr & mask) >> shift];
|
||||
for (shift = 16; shift >= 0; shift -= 4)
|
||||
*buf++ = hex[disassembler_mode][(addr >> shift) & 0xF];
|
||||
*buf = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static LPTSTR append_addr (LPTSTR buf, DWORD addr)
|
||||
{
|
||||
LPCTSTR lpszName;
|
||||
|
||||
if (disassembler_symb && (lpszName = RplGetName(addr)) != NULL)
|
||||
{
|
||||
buf = append_str(buf, _T("="));
|
||||
buf = append_str(buf, lpszName);
|
||||
}
|
||||
else // no symbol
|
||||
{
|
||||
buf = append_numaddr (buf, addr);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static LPTSTR append_r_addr (LPTSTR buf, DWORD *pc, long disp, int n, int offset)
|
||||
{
|
||||
LPCTSTR lpszName;
|
||||
long sign;
|
||||
|
||||
sign = 1 << (n * 4 - 1);
|
||||
if (disp & sign) // negative value?
|
||||
disp |= ~(sign - 1); // expand it to long
|
||||
*pc += disp;
|
||||
if (disp < 0)
|
||||
*pc = (*pc + disp) & 0xFFFFF;
|
||||
|
||||
if (disassembler_symb && (lpszName = RplGetName(*pc)) != NULL)
|
||||
{
|
||||
buf = append_str(buf, _T("-"));
|
||||
disp = -disp - offset;
|
||||
buf = append_str(buf, _T("=")); // show symbol
|
||||
buf = append_str(buf, lpszName);
|
||||
}
|
||||
else
|
||||
else // no symbol
|
||||
{
|
||||
buf = append_str(buf, _T("+"));
|
||||
disp += offset;
|
||||
}
|
||||
buf = append_addr(buf, disp);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static LPTSTR append_pc_comment (LPTSTR buf, DWORD pc, BOOL view)
|
||||
{
|
||||
LPTSTR p = buf;
|
||||
|
||||
if (view == VIEW_LONG) // output of address in remarks
|
||||
{
|
||||
while (lstrlen (buf) < 4 * TAB_SKIP)
|
||||
p = append_tab (buf);
|
||||
|
||||
switch (disassembler_mode)
|
||||
if (disp < 0)
|
||||
{
|
||||
case HP_MNEMONICS:
|
||||
p = append_str (p, _T("# Address: "));
|
||||
p = append_addr (p, pc);
|
||||
break;
|
||||
case CLASS_MNEMONICS:
|
||||
p = append_str (p, _T("; address: "));
|
||||
p = append_addr (p, pc);
|
||||
break;
|
||||
default:
|
||||
p = append_str (p, _T("Unknown disassembler mode"));
|
||||
break;
|
||||
buf = append_str(buf, _T("-"));
|
||||
disp = -disp - offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf = append_str(buf, _T("+"));
|
||||
disp += offset;
|
||||
}
|
||||
buf = append_numaddr(buf, disp); // show offset
|
||||
|
||||
buf = append_str(buf, _T(" ["));
|
||||
buf = append_numaddr(buf, *pc); // show absolute address
|
||||
buf = append_str(buf, _T("]"));
|
||||
}
|
||||
else // output of address in brackets
|
||||
{
|
||||
while (*p) ++p;
|
||||
p = append_str (p, _T(" ["));
|
||||
p = append_addr (p, pc);
|
||||
p = append_str (p, _T("]"));
|
||||
}
|
||||
return p;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static LPTSTR append_hst_bits (LPTSTR buf, int n)
|
||||
|
@ -731,7 +746,7 @@ static LPTSTR disasm_1 (DWORD *addr, LPTSTR out)
|
|||
return p;
|
||||
}
|
||||
|
||||
static LPTSTR disasm_8 (DWORD *addr, LPTSTR out, BOOL view)
|
||||
static LPTSTR disasm_8 (DWORD *addr, LPTSTR out)
|
||||
{
|
||||
BYTE n;
|
||||
BYTE fn;
|
||||
|
@ -858,7 +873,6 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out, BOOL view)
|
|||
{
|
||||
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, _T(", RTNYES"));
|
||||
|
@ -874,7 +888,6 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out, BOOL view)
|
|||
{
|
||||
p = append_str (p, _T(", "));
|
||||
p = append_r_addr (p, &pc, disp, 2, 5);
|
||||
p = append_pc_comment (out, pc, view);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1182,7 +1195,6 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out, BOOL view)
|
|||
{
|
||||
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, _T("RTNYES"));
|
||||
|
@ -1197,7 +1209,6 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out, BOOL view)
|
|||
{
|
||||
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;
|
||||
|
@ -1246,7 +1257,6 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out, BOOL view)
|
|||
{
|
||||
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, _T(", RTNYES"));
|
||||
|
@ -1261,7 +1271,6 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out, BOOL view)
|
|||
{
|
||||
p = append_str (p, _T(", "));
|
||||
p = append_r_addr (p, &pc, disp, 2, 3);
|
||||
p = append_pc_comment (out, pc, view);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1287,7 +1296,6 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out, BOOL view)
|
|||
{
|
||||
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, _T(", RTNYES"));
|
||||
|
@ -1302,7 +1310,6 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out, BOOL view)
|
|||
{
|
||||
p = append_str (p, _T(", "));
|
||||
p = append_r_addr (p, &pc, disp, 2, 3);
|
||||
p = append_pc_comment (out, pc, view);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1323,13 +1330,11 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out, BOOL view)
|
|||
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) ? _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, _T("Unknown disassembler mode"));
|
||||
|
@ -1367,7 +1372,7 @@ static LPTSTR disasm_8 (DWORD *addr, LPTSTR out, BOOL view)
|
|||
|
||||
// public functions
|
||||
|
||||
DWORD disassemble (DWORD addr, LPTSTR out, BOOL view)
|
||||
DWORD disassemble (DWORD addr, LPTSTR out)
|
||||
{
|
||||
BYTE n;
|
||||
BYTE fn;
|
||||
|
@ -1480,7 +1485,6 @@ DWORD disassemble (DWORD addr, LPTSTR out, BOOL view)
|
|||
{
|
||||
p = append_tab (out);
|
||||
p = append_r_addr (p, &pc, disp, 2, 1);
|
||||
p = append_pc_comment (out, pc, view);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1496,7 +1500,6 @@ DWORD disassemble (DWORD addr, LPTSTR out, BOOL view)
|
|||
{
|
||||
p = append_tab (out);
|
||||
p = append_r_addr (p, &pc, disp, 2, 1);
|
||||
p = append_pc_comment (out, pc, view);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1526,7 +1529,6 @@ DWORD disassemble (DWORD addr, LPTSTR out, BOOL view)
|
|||
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);
|
||||
break;
|
||||
|
||||
case CLASS_MNEMONICS:
|
||||
|
@ -1544,7 +1546,6 @@ DWORD disassemble (DWORD addr, LPTSTR out, BOOL view)
|
|||
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:
|
||||
|
@ -1562,14 +1563,12 @@ DWORD disassemble (DWORD addr, LPTSTR out, BOOL view)
|
|||
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, _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:
|
||||
|
@ -1583,7 +1582,7 @@ DWORD disassemble (DWORD addr, LPTSTR out, BOOL view)
|
|||
--addr;
|
||||
if (fn != 0xa && fn != 0xb)
|
||||
{
|
||||
p = disasm_8 (&addr, out, view);
|
||||
p = disasm_8 (&addr, out);
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
|
@ -1622,7 +1621,6 @@ DWORD disassemble (DWORD addr, LPTSTR out, BOOL view)
|
|||
if (disp != 0)
|
||||
{
|
||||
p = append_r_addr (p, &pc, disp, 2, 3);
|
||||
p = append_pc_comment (out, pc, view);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1639,7 +1637,6 @@ DWORD disassemble (DWORD addr, LPTSTR out, BOOL view)
|
|||
{
|
||||
p = append_str (p, _T(", "));
|
||||
p = append_r_addr (p, &pc, disp, 2, 3);
|
||||
p = append_pc_comment (out, pc, view);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1916,4 +1913,3 @@ DWORD disassemble (DWORD addr, LPTSTR out, BOOL view)
|
|||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|((((c)-1)>>1)<<8) \
|
||||
|((((c)-1)>>1)))
|
||||
|
||||
#define DIBPIXEL(d,p) *(((DWORD*)(d))++) = ((*((DWORD*)(d)) & dwGrayMask) << 1) | (p)
|
||||
#define DIBPIXEL(d,p) *((DWORD*)(d)) = ((*((DWORD*)(d)) & dwGrayMask) << 1) | (p); (BYTE *) d += 4
|
||||
|
||||
BOOL bGrayscale = FALSE; // Default is to not emulate grayscale
|
||||
UINT nBackgroundX = 0;
|
||||
|
@ -39,10 +39,11 @@ UINT nBackgroundH = 0;
|
|||
UINT nLcdX = 0;
|
||||
UINT nLcdY = 0;
|
||||
UINT nLcdZoom = 1;
|
||||
LPBYTE pbyLcd;
|
||||
HDC hLcdDC = NULL;
|
||||
HDC hMainDC = NULL;
|
||||
|
||||
static LPBYTE pbyLcd;
|
||||
|
||||
static HBITMAP hLcdBitmap;
|
||||
static HBITMAP hMainBitmap;
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "kml.h"
|
||||
#include "debugger.h"
|
||||
|
||||
#define VERSION "1.45+"
|
||||
#define VERSION "1.46+"
|
||||
|
||||
// #define MONOCHROME // CF_BITMAP clipboard format
|
||||
|
||||
|
@ -613,7 +613,7 @@ static UINT SaveChanges(BOOL bAuto)
|
|||
else
|
||||
{
|
||||
UINT uStyle = bSaveDefConfirm ? 0 : MB_DEFBUTTON2;
|
||||
uReply = YesNoCancelMessage(_T("Do you want to save changes ?"),uStyle);
|
||||
uReply = YesNoCancelMessage(_T("Do you want to save changes?"),uStyle);
|
||||
}
|
||||
|
||||
if (uReply != IDYES) return uReply;
|
||||
|
@ -777,6 +777,7 @@ static LRESULT OnDropFiles(HANDLE hFilesInfo)
|
|||
{
|
||||
// turn on HP
|
||||
KeyboardEvent(TRUE,0,0x8000);
|
||||
Sleep(200);
|
||||
KeyboardEvent(FALSE,0,0x8000);
|
||||
}
|
||||
|
||||
|
@ -853,7 +854,34 @@ static LRESULT OnFileOpen(VOID)
|
|||
}
|
||||
if (GetOpenFilename())
|
||||
{
|
||||
OpenDocument(szBufferFilename);
|
||||
if (OpenDocument(szBufferFilename))
|
||||
MruAdd(szCurrentFilename);
|
||||
}
|
||||
cancel:
|
||||
if (pbyRom) SwitchToState(SM_RUN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// ID_FILE_MRU_FILE1
|
||||
//
|
||||
static LRESULT OnFileMruOpen(UINT wID)
|
||||
{
|
||||
LPCTSTR lpszFilename;
|
||||
|
||||
wID -= ID_FILE_MRU_FILE1; // zero based MRU index
|
||||
lpszFilename = MruFilename(wID); // full filename from MRU list
|
||||
if (lpszFilename == NULL) return 0; // MRU slot not filled
|
||||
|
||||
if (pbyRom)
|
||||
{
|
||||
SwitchToState(SM_INVALID);
|
||||
if (IDCANCEL == SaveChanges(bAutoSave))
|
||||
goto cancel;
|
||||
}
|
||||
if (!OpenDocument(lpszFilename)) // document loading failed
|
||||
{
|
||||
MruRemove(wID); // entry not valid any more
|
||||
}
|
||||
cancel:
|
||||
if (pbyRom) SwitchToState(SM_RUN);
|
||||
|
@ -882,7 +910,8 @@ static LRESULT OnFileSaveAs(VOID)
|
|||
|
||||
if (GetSaveAsFilename())
|
||||
{
|
||||
SaveDocumentAs(szBufferFilename);
|
||||
if (SaveDocumentAs(szBufferFilename))
|
||||
MruAdd(szCurrentFilename);
|
||||
}
|
||||
|
||||
SwitchToState(SM_RUN);
|
||||
|
@ -1044,7 +1073,7 @@ static LRESULT OnViewCopy(VOID)
|
|||
static LRESULT OnViewReset(VOID)
|
||||
{
|
||||
if (nState != SM_RUN) return 0;
|
||||
if (YesNoMessage(_T("Are you sure you want to press the Reset Button ?"))==IDYES)
|
||||
if (YesNoMessage(_T("Are you sure you want to press the Reset Button?"))==IDYES)
|
||||
{
|
||||
SwitchToState(SM_SLEEP);
|
||||
CpuReset(); // register setting after Cpu Reset
|
||||
|
@ -1138,6 +1167,7 @@ static LRESULT OnObjectLoad(VOID)
|
|||
if (!(Chipset.IORam[BITOFFSET]&DON))
|
||||
{
|
||||
KeyboardEvent(TRUE,0,0x8000);
|
||||
Sleep(200);
|
||||
KeyboardEvent(FALSE,0,0x8000);
|
||||
|
||||
// wait for sleep mode
|
||||
|
@ -1163,8 +1193,8 @@ static LRESULT OnObjectLoad(VOID)
|
|||
UINT uReply = YesNoCancelMessage(
|
||||
_T("Warning: Trying to load an object while the emulator is busy\n")
|
||||
_T("will certainly result in a memory lost. Before loading an object\n")
|
||||
_T("you should be sure that the calculator is not doing anything.\n")
|
||||
_T("Do you want to see this warning next time you try to load an object ?"),0);
|
||||
_T("you should be sure that the calculator is in idle state.\n")
|
||||
_T("Do you want to see this warning next time you try to load an object?"),0);
|
||||
switch (uReply)
|
||||
{
|
||||
case IDYES:
|
||||
|
@ -1305,7 +1335,7 @@ static INT_PTR CALLBACK Disasm(HWND hDlg, UINT message, WPARAM wParam, LPARAM lP
|
|||
if (dwAddress >= dwAddressMax)
|
||||
return FALSE;
|
||||
i = wsprintf(szAddress,(dwAddress <= 0xFFFFF) ? _T("%05lX ") : _T("%06lX "),dwAddress);
|
||||
dwAddress = disassemble(dwAddress,&szAddress[i],VIEW_LONG);
|
||||
dwAddress = disassemble(dwAddress,&szAddress[i]);
|
||||
i = (LONG) SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_ADDSTRING,0,(LPARAM) szAddress);
|
||||
SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_SELITEMRANGE,FALSE,MAKELPARAM(0,i));
|
||||
SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_SETSEL,TRUE,i);
|
||||
|
@ -1483,6 +1513,10 @@ LRESULT CALLBACK MainWndProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
case ID_TOOL_MACRO_SETTINGS: return OnToolMacroSettings();
|
||||
case ID_ABOUT: return OnAbout();
|
||||
}
|
||||
// check if command ID belongs to MRU file area
|
||||
if ( (LOWORD(wParam) >= ID_FILE_MRU_FILE1)
|
||||
&& (LOWORD(wParam) < ID_FILE_MRU_FILE1 + MruEntries()))
|
||||
return OnFileMruOpen(LOWORD(wParam));
|
||||
break;
|
||||
case WM_SYSCOMMAND:
|
||||
switch (wParam & 0xFFF0)
|
||||
|
@ -1579,6 +1613,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
|
|||
GetCurrentDirectory(ARRAYSIZEOF(szCurrentDirectory), szCurrentDirectory);
|
||||
szCurrentKml[0] = 0; // no KML file selected
|
||||
ReadSettings();
|
||||
MruInit(0); // init MRU entries
|
||||
|
||||
UpdateWindowStatus();
|
||||
|
||||
|
@ -1645,6 +1680,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
|
|||
SetWindowTitle(szTemp);
|
||||
if (OpenDocument(szBufferFilename))
|
||||
{
|
||||
MruAdd(szCurrentFilename);
|
||||
ShowWindow(hWnd,nCmdShow);
|
||||
goto start;
|
||||
}
|
||||
|
@ -1679,7 +1715,8 @@ start:
|
|||
DdeUninitialize(idDdeInst);
|
||||
|
||||
// get full path name of szCurrentFilename
|
||||
GetFullPathName(szCurrentFilename,ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart);
|
||||
if (GetFullPathName(szCurrentFilename,ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart) == 0)
|
||||
szBufferFilename[0] = 0; // no last document name
|
||||
|
||||
WriteLastDocument(szBufferFilename); // save last document setting
|
||||
WriteSettings(); // save emulation settings
|
||||
|
@ -1689,6 +1726,7 @@ start:
|
|||
_ASSERT(nState == SM_RETURN); // emulation thread down?
|
||||
ResetDocument();
|
||||
ResetBackup();
|
||||
MruCleanup();
|
||||
_ASSERT(pbyRom == NULL); // rom file unmapped
|
||||
_ASSERT(pbyPort2 == NULL); // port2 file unmapped
|
||||
_ASSERT(pKml == NULL); // KML script not closed
|
||||
|
|
|
@ -53,9 +53,6 @@
|
|||
#define MEM_PORT1 3
|
||||
#define MEM_PORT2 4
|
||||
|
||||
#define VIEW_SHORT FALSE // view of disassembler output
|
||||
#define VIEW_LONG TRUE
|
||||
|
||||
#define MACRO_OFF 0 // macro recorder off
|
||||
#define MACRO_NEW 1
|
||||
#define MACRO_PLAY 2
|
||||
|
@ -117,6 +114,17 @@ extern VOID CopyItemsToClipboard(HWND hWnd);
|
|||
extern VOID UpdateWindowStatus(VOID);
|
||||
extern VOID ForceForegroundWindow(HWND hWnd);
|
||||
|
||||
// mru.c
|
||||
extern BOOL MruInit(INT nNum);
|
||||
extern VOID MruCleanup(VOID);
|
||||
extern VOID MruAdd(LPCTSTR lpszEntry);
|
||||
extern VOID MruRemove(INT nIndex);
|
||||
extern INT MruEntries(VOID);
|
||||
extern LPCTSTR MruFilename(INT nIndex);
|
||||
extern VOID MruUpdateMenu(VOID);
|
||||
extern VOID MruWriteList(VOID);
|
||||
extern VOID MruReadList(VOID);
|
||||
|
||||
// Settings.c
|
||||
extern VOID ReadSettings(VOID);
|
||||
extern VOID WriteSettings(VOID);
|
||||
|
@ -136,7 +144,6 @@ extern UINT nBackgroundH;
|
|||
extern UINT nLcdX;
|
||||
extern UINT nLcdY;
|
||||
extern UINT nLcdZoom;
|
||||
extern LPBYTE pbyLcd;
|
||||
extern HDC hLcdDC;
|
||||
extern HDC hMainDC;
|
||||
extern VOID UpdateContrast(BYTE byContrast);
|
||||
|
@ -324,8 +331,17 @@ extern HDDEDATA CALLBACK DdeCallback(UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, DWOR
|
|||
|
||||
// Disasm.c
|
||||
extern BOOL disassembler_mode;
|
||||
extern BOOL disassembler_symb;
|
||||
extern WORD disassembler_map;
|
||||
extern DWORD disassemble (DWORD addr, LPTSTR out, BOOL view);
|
||||
extern BYTE read_nibble(DWORD *p);
|
||||
extern DWORD disassemble(DWORD addr, LPTSTR out);
|
||||
|
||||
// Symbfile.c
|
||||
#define RplTableEmpty() TRUE // function not implemented so far
|
||||
#define RplLoadTable(n) FALSE // function not implemented so far
|
||||
#define RplDeleteTable() // function not implemented so far
|
||||
#define RplGetName(a) NULL // function not implemented so far
|
||||
#define RplGetAddr(n,a) FALSE // function not implemented so far
|
||||
|
||||
// Serial.c
|
||||
extern BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort);
|
||||
|
|
|
@ -148,6 +148,14 @@ BEGIN
|
|||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 74
|
||||
END
|
||||
|
||||
IDD_DEBUG_SETTINGS, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 177
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 109
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
@ -171,7 +179,7 @@ BEGIN
|
|||
LTEXT "30-34 (Display Secondary Start Address)",IDC_STATIC,11,
|
||||
41,131,8
|
||||
RTEXT "00000",IDC_ADDR30_34,144,41,25,8
|
||||
DEFPUSHBUTTON "OK",IDOK,65,61,50,14
|
||||
DEFPUSHBUTTON "OK",IDCANCEL,65,61,50,14
|
||||
END
|
||||
|
||||
IDD_FIND DIALOGEX 0, 0, 197, 47
|
||||
|
@ -225,7 +233,7 @@ FONT 8, "MS Sans Serif"
|
|||
BEGIN
|
||||
ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE
|
||||
LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP
|
||||
LTEXT "Copyright © 2008 Christoph Gießelink && Sébastien Carlier",
|
||||
LTEXT "Copyright © 2009 Christoph Gießelink && Sébastien Carlier",
|
||||
IDC_STATIC,29,18,181,8
|
||||
DEFPUSHBUTTON "OK",IDOK,215,12,39,14
|
||||
EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL |
|
||||
|
@ -286,8 +294,8 @@ BEGIN
|
|||
COMBOBOX IDC_IR,107,243,48,43,CBS_DROPDOWNLIST | WS_VSCROLL |
|
||||
WS_TABSTOP
|
||||
GROUPBOX "Serial Ports",IDC_STATIC,7,233,153,27
|
||||
DEFPUSHBUTTON "&Ok",IDOK,9,266,50,14
|
||||
PUSHBUTTON "&Cancel",IDCANCEL,107,266,50,14
|
||||
DEFPUSHBUTTON "OK",IDOK,9,266,50,14
|
||||
PUSHBUTTON "Cancel",IDCANCEL,107,266,50,14
|
||||
END
|
||||
|
||||
IDD_CHOOSEKML DIALOG DISCARDABLE 0, 0, 195, 66
|
||||
|
@ -516,6 +524,28 @@ BEGIN
|
|||
PUSHBUTTON "Cancel",IDCANCEL,93,60,50,14
|
||||
END
|
||||
|
||||
IDD_DEBUG_SETTINGS DIALOG DISCARDABLE 0, 0, 184, 116
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Debugger Settings"
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
CONTROL "HP Mnemonics",IDC_DISASM_HP,"Button",BS_AUTORADIOBUTTON |
|
||||
WS_GROUP | WS_TABSTOP,15,16,65,11
|
||||
CONTROL "Class Mnemonics",IDC_DISASM_CLASS,"Button",
|
||||
BS_AUTORADIOBUTTON,98,16,70,11
|
||||
GROUPBOX "Disassembler",IDC_STATIC,7,3,170,32
|
||||
CONTROL "Enable",IDC_DEBUG_SET_SYMB,"Button",BS_AUTOCHECKBOX |
|
||||
WS_TABSTOP,15,49,38,10
|
||||
LTEXT "Model:",IDC_STATIC,104,50,22,8
|
||||
COMBOBOX IDC_DEBUG_SET_MODEL,131,47,38,72,CBS_DROPDOWNLIST |
|
||||
CBS_SORT | WS_VSCROLL | WS_TABSTOP
|
||||
EDITTEXT IDC_DEBUG_SET_FILE,15,65,143,14,ES_AUTOHSCROLL
|
||||
PUSHBUTTON "...",IDC_DEBUG_SET_BROWSE,159,65,10,14
|
||||
GROUPBOX "Symbolic",IDC_STATIC,7,36,170,53
|
||||
DEFPUSHBUTTON "&Ok",IDOK,12,95,50,14
|
||||
PUSHBUTTON "&Cancel",IDCANCEL,122,95,50,14
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -553,8 +583,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,4,5,0
|
||||
PRODUCTVERSION 1,4,5,0
|
||||
FILEVERSION 1,4,6,0
|
||||
PRODUCTVERSION 1,4,6,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -571,12 +601,12 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0"
|
||||
VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0"
|
||||
VALUE "FileVersion", "1, 4, 5, 0\0"
|
||||
VALUE "FileVersion", "1, 4, 6, 0\0"
|
||||
VALUE "InternalName", "Emu48\0"
|
||||
VALUE "LegalCopyright", "Copyright © 2008\0"
|
||||
VALUE "LegalCopyright", "Copyright © 2009\0"
|
||||
VALUE "OriginalFilename", "Emu48.exe\0"
|
||||
VALUE "ProductName", "Emu48\0"
|
||||
VALUE "ProductVersion", "1, 4, 5, 0\0"
|
||||
VALUE "ProductVersion", "1, 4, 6, 0\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -614,6 +644,8 @@ BEGIN
|
|||
MENUITEM SEPARATOR
|
||||
MENUITEM "S&ettings...", ID_VIEW_SETTINGS
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Recent File List", ID_FILE_MRU_FILE1, GRAYED
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "E&xit", ID_FILE_EXIT
|
||||
END
|
||||
POPUP "&Edit"
|
||||
|
|
|
@ -116,6 +116,7 @@ BOOL DLLCreateWnd(LPCTSTR lpszFilename, LPCTSTR lpszPort2Name)
|
|||
szCurrentKml[0] = 0; // no KML file selected
|
||||
|
||||
ReadSettings();
|
||||
MruInit(0); // init MRU entries
|
||||
|
||||
UpdateWindowStatus();
|
||||
|
||||
|
@ -194,6 +195,7 @@ BOOL DLLCreateWnd(LPCTSTR lpszFilename, LPCTSTR lpszPort2Name)
|
|||
SetWindowTitle(szTemp);
|
||||
if (OpenDocument(szBufferFilename))
|
||||
{
|
||||
MruAdd(szCurrentFilename);
|
||||
ShowWindow(hWnd,SW_SHOWNORMAL);
|
||||
goto start;
|
||||
}
|
||||
|
@ -234,7 +236,8 @@ BOOL DLLDestroyWnd(VOID)
|
|||
DdeUninitialize(idDdeInst);
|
||||
|
||||
// get full path name of szCurrentFilename
|
||||
GetFullPathName(szCurrentFilename,ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart);
|
||||
if (GetFullPathName(szCurrentFilename,ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart) == 0)
|
||||
szBufferFilename[0] = 0; // no last document name
|
||||
|
||||
WriteLastDocument(szBufferFilename); // save last document setting
|
||||
WriteSettings(); // save variable settings
|
||||
|
@ -245,6 +248,7 @@ BOOL DLLDestroyWnd(VOID)
|
|||
_ASSERT(nState == SM_RETURN); // emulation thread down?
|
||||
ResetDocument();
|
||||
ResetBackup();
|
||||
MruCleanup();
|
||||
_ASSERT(pbyRom == NULL); // rom file unmapped
|
||||
_ASSERT(pbyPort2 == NULL); // port2 file unmapped
|
||||
_ASSERT(pKml == NULL); // KML script not closed
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
CFG=Emu48 - Win32 Release
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "EMU48DLL.MAK".
|
||||
!MESSAGE
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "EMU48DLL.MAK" CFG="Emu48 - Win32 Release"
|
||||
!MESSAGE
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE
|
||||
!MESSAGE "Emu48 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "Emu48 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
|
@ -81,7 +81,7 @@ 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 /dll /debug /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib advapi32.lib /nologo /dll /debug /machine:I386 /out:".\Debug/Emu48.dll"
|
||||
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
|
@ -164,6 +164,10 @@ SOURCE=.\mops.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mru.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\opcodes.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -7,23 +7,23 @@
|
|||
CFG=Emu48 - Win32 DebugRegDebug4x
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "Emu48.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "Emu48.mak" CFG="Emu48 - Win32 DebugRegDebug4x"
|
||||
!MESSAGE
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE
|
||||
!MESSAGE "Emu48 - Win32 Release" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "Emu48 - Win32 Debug" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "Emu48 - Win32 Release Unicode" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "Emu48 - Win32 Debug Unicode" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "Emu48 - Win32 DebugRegDebug4x" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "Emu48 - Win32 ReleaseRegDebug4x" (based on "Win32 (x86) Application")
|
||||
!MESSAGE
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
|
@ -193,7 +193,7 @@ LINK32=link.exe
|
|||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib comctl32.lib advapi32.lib /nologo /subsystem:windows /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib winmm.lib comctl32.lib advapi32.lib /nologo /subsystem:windows /machine:I386
|
||||
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
|
@ -276,6 +276,10 @@ SOURCE=.\mops.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mru.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\opcodes.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
698
source/FILES.C
698
source/FILES.C
|
@ -634,12 +634,14 @@ VOID UnmapPort2(VOID)
|
|||
|
||||
static BOOL IsDataPacked(VOID *pMem, DWORD dwSize)
|
||||
{
|
||||
DWORD *pdwMem = pMem;
|
||||
|
||||
_ASSERT((dwSize % sizeof(DWORD)) == 0);
|
||||
if ((dwSize % sizeof(DWORD)) != 0) return TRUE;
|
||||
|
||||
for (dwSize /= sizeof(DWORD); dwSize-- > 0;)
|
||||
{
|
||||
if ((*((DWORD *) pMem)++ & 0xF0F0F0F0) != 0)
|
||||
if ((*pdwMem++ & 0xF0F0F0F0) != 0)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
@ -784,15 +786,16 @@ BOOL OpenDocument(LPCTSTR szFilename)
|
|||
UINT ctBytesCompared;
|
||||
UINT nLength;
|
||||
|
||||
// Open file
|
||||
if (lstrcmpi(szCurrentFilename,szFilename) == 0)
|
||||
{
|
||||
if (YesNoMessage(_T("Do you want to reload this document?")) == IDNO)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
SaveBackup();
|
||||
ResetDocument();
|
||||
|
||||
// Open file
|
||||
if (lstrcmpi(szBackupFilename, szFilename)==0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -1144,6 +1147,7 @@ BOOL SaveBackup(VOID)
|
|||
BackupChipset.Port2 = HeapAlloc(hHeap,0,Chipset.Port2Size*2048);
|
||||
CopyMemory(BackupChipset.Port2, Chipset.Port2, Chipset.Port2Size*2048);
|
||||
}
|
||||
CreateBackupBreakpointList();
|
||||
bBackup = TRUE;
|
||||
UpdateWindowStatus();
|
||||
return TRUE;
|
||||
|
@ -1151,7 +1155,11 @@ BOOL SaveBackup(VOID)
|
|||
|
||||
BOOL RestoreBackup(VOID)
|
||||
{
|
||||
BOOL bDbgOpen;
|
||||
|
||||
if (!bBackup) return FALSE;
|
||||
|
||||
bDbgOpen = (nDbgState != DBG_OFF); // debugger window open?
|
||||
ResetDocument();
|
||||
// need chipset for contrast setting in InitKML()
|
||||
Chipset.contrast = BackupChipset.contrast;
|
||||
|
@ -1190,10 +1198,12 @@ BOOL RestoreBackup(VOID)
|
|||
MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]);
|
||||
}
|
||||
}
|
||||
Map(0x00,0xFF);
|
||||
SetWindowPathTitle(szCurrentFilename); // update window title line
|
||||
SetWindowLocation(hWnd,Chipset.nPosX,Chipset.nPosY);
|
||||
RestoreBackupBreakpointList(); // restore the debugger breakpoint list
|
||||
if (bDbgOpen) OnToolDebug(); // reopen the debugger
|
||||
UpdateWindowStatus();
|
||||
Map(0x00,0xFF);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1235,28 +1245,14 @@ BOOL GetOpenFilename(VOID)
|
|||
|
||||
InitializeOFN(&ofn);
|
||||
ofn.lpstrFilter =
|
||||
_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");
|
||||
ofn.lpstrDefExt = _T("E48"); // HP48SX/GX
|
||||
ofn.nFilterIndex = 3;
|
||||
if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G
|
||||
{
|
||||
ofn.lpstrDefExt = _T("E38");
|
||||
ofn.nFilterIndex = 1;
|
||||
}
|
||||
if (cCurrentRomType=='E' || cCurrentRomType=='P') // HP39/40G/HP49G+ // CdB for HP: add apples
|
||||
{
|
||||
ofn.lpstrDefExt = _T("E39");
|
||||
ofn.nFilterIndex = 2;
|
||||
}
|
||||
if (cCurrentRomType=='X' || cCurrentRomType=='2' || cCurrentRomType=='Q') // HP49G/HP48Gii/HP49G+ // CdB for HP: add apples
|
||||
{
|
||||
ofn.lpstrDefExt = _T("E49");
|
||||
ofn.nFilterIndex = 4;
|
||||
}
|
||||
_T("Emu48 Files (*.e38;*.e39;*.e48;*.e49)\0")
|
||||
_T("*.e38;*.e39;*.e48;*.e49\0")
|
||||
_T("HP-38 Files (*.e38)\0*.e38\0")
|
||||
_T("HP-39 Files (*.e39)\0*.e39\0")
|
||||
_T("HP-48 Files (*.e48)\0*.e48\0")
|
||||
_T("HP-49 Files (*.e49)\0*.e49\0")
|
||||
_T("Win48 Files (*.w48)\0*.w48\0");
|
||||
ofn.nFilterIndex = 1;
|
||||
ofn.lpstrFile = szBuffer;
|
||||
ofn.lpstrFile[0] = 0;
|
||||
ofn.nMaxFile = ARRAYSIZEOF(szBuffer);
|
||||
|
@ -1274,25 +1270,25 @@ BOOL GetSaveAsFilename(VOID)
|
|||
|
||||
InitializeOFN(&ofn);
|
||||
ofn.lpstrFilter =
|
||||
_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");
|
||||
ofn.lpstrDefExt = _T("E48"); // HP48SX/GX
|
||||
_T("HP-38 Files (*.e38)\0*.e38\0")
|
||||
_T("HP-39 Files (*.e39)\0*.e39\0")
|
||||
_T("HP-48 Files (*.e48)\0*.e48\0")
|
||||
_T("HP-49 Files (*.e49)\0*.e49\0");
|
||||
ofn.lpstrDefExt = _T("e48"); // HP48SX/GX
|
||||
ofn.nFilterIndex = 3;
|
||||
if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G
|
||||
{
|
||||
ofn.lpstrDefExt = _T("E38");
|
||||
ofn.lpstrDefExt = _T("e38");
|
||||
ofn.nFilterIndex = 1;
|
||||
}
|
||||
if (cCurrentRomType=='E' || cCurrentRomType=='P') // HP39/40G/hp439G+ // CdB for HP: add apples
|
||||
{
|
||||
ofn.lpstrDefExt = _T("E39");
|
||||
ofn.lpstrDefExt = _T("e39");
|
||||
ofn.nFilterIndex = 2;
|
||||
}
|
||||
if (cCurrentRomType=='X' || cCurrentRomType=='2' || cCurrentRomType=='Q') // HP49G/HP48Gii/HP49G+ // CdB for HP: add apples
|
||||
{
|
||||
ofn.lpstrDefExt = _T("E49");
|
||||
ofn.lpstrDefExt = _T("e49");
|
||||
ofn.nFilterIndex = 4;
|
||||
}
|
||||
ofn.lpstrFile = szBuffer;
|
||||
|
@ -1486,6 +1482,15 @@ BOOL SaveObject(LPCTSTR szFilename) // separated stack reading part
|
|||
//#
|
||||
//################
|
||||
|
||||
#define WIDTHBYTES(bits) ((((bits) + 31) / 32) * 4)
|
||||
|
||||
typedef struct _BmpFile
|
||||
{
|
||||
DWORD dwPos; // actual reading pos
|
||||
DWORD dwFileSize; // file size
|
||||
LPBYTE pbyFile; // buffer
|
||||
} BMPFILE, FAR *LPBMPFILE, *PBMPFILE;
|
||||
|
||||
static __inline UINT DibNumColors(BITMAPINFOHEADER CONST *lpbi)
|
||||
{
|
||||
if (lpbi->biClrUsed != 0) return (UINT)lpbi->biClrUsed;
|
||||
|
@ -1512,14 +1517,15 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
|
|||
return NULL;
|
||||
|
||||
// Get a pointer to the color table and the number of colors in it
|
||||
pRgb = (RGBQUAD *)((LPBYTE)lpbi + (WORD)lpbi->biSize);
|
||||
pRgb = (RGBQUAD FAR *)((LPBYTE)lpbi + (WORD)lpbi->biSize);
|
||||
nNumColors = DibNumColors(lpbi);
|
||||
|
||||
if (nNumColors)
|
||||
{
|
||||
// Allocate for the logical palette structure
|
||||
pPal = HeapAlloc(hHeap,0,sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY));
|
||||
if (!pPal) return NULL;
|
||||
pPal = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY));
|
||||
if (!pPal)
|
||||
return NULL;
|
||||
|
||||
pPal->palNumEntries = nNumColors;
|
||||
pPal->palVersion = 0x300;
|
||||
|
@ -1531,7 +1537,7 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
|
|||
pPal->palPalEntry[i].peRed = pRgb[i].rgbRed;
|
||||
pPal->palPalEntry[i].peGreen = pRgb[i].rgbGreen;
|
||||
pPal->palPalEntry[i].peBlue = pRgb[i].rgbBlue;
|
||||
pPal->palPalEntry[i].peFlags = 0;
|
||||
pPal->palPalEntry[i].peFlags = (BYTE)0;
|
||||
}
|
||||
hpal = CreatePalette(pPal);
|
||||
HeapFree(hHeap,0,pPal);
|
||||
|
@ -1570,55 +1576,613 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
|
|||
return hpal;
|
||||
}
|
||||
|
||||
static HBITMAP DecodeBmp(LPBMPFILE pBmp)
|
||||
{
|
||||
LPBITMAPFILEHEADER pBmfh;
|
||||
LPBITMAPINFO pBmi;
|
||||
HBITMAP hBitmap;
|
||||
DWORD dwFileSize;
|
||||
|
||||
hBitmap = NULL;
|
||||
|
||||
// size of bitmap header information
|
||||
dwFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
||||
if (pBmp->dwFileSize < dwFileSize) return NULL;
|
||||
|
||||
// check for bitmap
|
||||
pBmfh = (LPBITMAPFILEHEADER) pBmp->pbyFile;
|
||||
if (pBmfh->bfType != 0x4D42) return NULL; // "BM"
|
||||
|
||||
pBmi = (LPBITMAPINFO) (pBmp->pbyFile + sizeof(BITMAPFILEHEADER));
|
||||
|
||||
// size with color table
|
||||
if (pBmi->bmiHeader.biCompression == BI_BITFIELDS)
|
||||
{
|
||||
dwFileSize += 3 * sizeof(DWORD);
|
||||
}
|
||||
else
|
||||
{
|
||||
dwFileSize += DibNumColors(&pBmi->bmiHeader) * sizeof(RGBQUAD);
|
||||
}
|
||||
if (dwFileSize != pBmfh->bfOffBits) return NULL;
|
||||
|
||||
// size with bitmap data
|
||||
if (pBmi->bmiHeader.biCompression != BI_RGB)
|
||||
{
|
||||
dwFileSize += pBmi->bmiHeader.biSizeImage;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwFileSize += WIDTHBYTES(pBmi->bmiHeader.biWidth * pBmi->bmiHeader.biBitCount)
|
||||
* labs(pBmi->bmiHeader.biHeight);
|
||||
}
|
||||
if (pBmp->dwFileSize < dwFileSize) return NULL;
|
||||
|
||||
VERIFY(hBitmap = CreateDIBitmap(
|
||||
hWindowDC,
|
||||
&pBmi->bmiHeader,
|
||||
CBM_INIT,
|
||||
pBmp->pbyFile + pBmfh->bfOffBits,
|
||||
pBmi, DIB_RGB_COLORS));
|
||||
if (hBitmap == NULL) return NULL;
|
||||
|
||||
_ASSERT(hPalette == NULL); // resource free
|
||||
hPalette = CreateBIPalette(&pBmi->bmiHeader);
|
||||
// save old palette
|
||||
hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE);
|
||||
RealizePalette(hWindowDC);
|
||||
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
static BOOL ReadGifByte(LPBMPFILE pGif, INT *n)
|
||||
{
|
||||
// outside GIF file
|
||||
if (pGif->dwPos >= pGif->dwFileSize)
|
||||
return TRUE;
|
||||
|
||||
*n = pGif->pbyFile[pGif->dwPos++];
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL ReadGifWord(LPBMPFILE pGif, INT *n)
|
||||
{
|
||||
// outside GIF file
|
||||
if (pGif->dwPos + 1 >= pGif->dwFileSize)
|
||||
return TRUE;
|
||||
|
||||
*n = pGif->pbyFile[pGif->dwPos++];
|
||||
*n |= (pGif->pbyFile[pGif->dwPos++] << 8);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static HBITMAP DecodeGif(LPBMPFILE pBmp)
|
||||
{
|
||||
// this implementation base on the GIF image file
|
||||
// decoder engine of Free42 (c) by Thomas Okken
|
||||
|
||||
HBITMAP hBitmap;
|
||||
|
||||
typedef struct cmap
|
||||
{
|
||||
WORD biBitCount; // bits used in color map
|
||||
DWORD biClrUsed; // no of colors in color map
|
||||
RGBQUAD bmiColors[256]; // color map
|
||||
} CMAP;
|
||||
|
||||
BOOL bHasGlobalCmap;
|
||||
CMAP sGlb; // data of global color map
|
||||
|
||||
INT nWidth,nHeight,nInfo,nBackground,nZero;
|
||||
LONG lBytesPerLine;
|
||||
|
||||
LPBYTE pbyPixels;
|
||||
|
||||
BITMAPINFO bmi; // global bitmap info
|
||||
|
||||
BOOL bDecoding = TRUE;
|
||||
|
||||
hBitmap = NULL;
|
||||
|
||||
pBmp->dwPos = 6; // position behind GIF header
|
||||
|
||||
/* Bits 6..4 of info contain one less than the "color resolution",
|
||||
* defined as the number of significant bits per RGB component in
|
||||
* the source image's color palette. If the source image (from
|
||||
* which the GIF was generated) was 24-bit true color, the color
|
||||
* resolution is 8, so the value in bits 6..4 is 7. If the source
|
||||
* image had an EGA color cube (2x2x2), the color resolution would
|
||||
* be 2, etc.
|
||||
* Bit 3 of info must be zero in GIF87a; in GIF89a, if it is set,
|
||||
* it indicates that the global colormap is sorted, the most
|
||||
* important entries being first. In PseudoColor environments this
|
||||
* can be used to make sure to get the most important colors from
|
||||
* the X server first, to optimize the image's appearance in the
|
||||
* event that not all the colors from the colormap can actually be
|
||||
* obtained at the same time.
|
||||
* The 'zero' field is always 0 in GIF87a; in GIF89a, it indicates
|
||||
* the pixel aspect ratio, as (PAR + 15) : 64. If PAR is zero,
|
||||
* this means no aspect ratio information is given, PAR = 1 means
|
||||
* 1:4 (narrow), PAR = 49 means 1:1 (square), PAR = 255 means
|
||||
* slightly over 4:1 (wide), etc.
|
||||
*/
|
||||
|
||||
if ( ReadGifWord(pBmp,&nWidth)
|
||||
|| ReadGifWord(pBmp,&nHeight)
|
||||
|| ReadGifByte(pBmp,&nInfo)
|
||||
|| ReadGifByte(pBmp,&nBackground)
|
||||
|| ReadGifByte(pBmp,&nZero)
|
||||
|| nZero != 0)
|
||||
goto quit;
|
||||
|
||||
ZeroMemory(&bmi,sizeof(bmi)); // init bitmap info
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = nWidth;
|
||||
bmi.bmiHeader.biHeight = nHeight;
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 24; // create a true color DIB
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
ZeroMemory(&sGlb,sizeof(sGlb)); // init global color map
|
||||
bHasGlobalCmap = (nInfo & 0x80) != 0;
|
||||
|
||||
sGlb.biBitCount = (nInfo & 7) + 1; // bits used in global color map
|
||||
sGlb.biClrUsed = (1 << sGlb.biBitCount); // no of colors in global color map
|
||||
|
||||
// color table should not exceed 256 colors
|
||||
_ASSERT(sGlb.biClrUsed <= ARRAYSIZEOF(sGlb.bmiColors));
|
||||
|
||||
if (bHasGlobalCmap) // global color map
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
for (i = 0; i < sGlb.biClrUsed; ++i)
|
||||
{
|
||||
int r, g, b;
|
||||
|
||||
if (ReadGifByte(pBmp,&r) || ReadGifByte(pBmp,&g) || ReadGifByte(pBmp,&b))
|
||||
goto quit;
|
||||
|
||||
sGlb.bmiColors[i].rgbRed = r;
|
||||
sGlb.bmiColors[i].rgbGreen = g;
|
||||
sGlb.bmiColors[i].rgbBlue = b;
|
||||
}
|
||||
}
|
||||
else // no color map
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
for (i = 0; i < sGlb.biClrUsed; ++i)
|
||||
{
|
||||
BYTE k = (BYTE) ((i * sGlb.biClrUsed) / (sGlb.biClrUsed - 1));
|
||||
|
||||
sGlb.bmiColors[i].rgbRed = k;
|
||||
sGlb.bmiColors[i].rgbGreen = k;
|
||||
sGlb.bmiColors[i].rgbBlue = k;
|
||||
}
|
||||
}
|
||||
|
||||
// bitmap dimensions
|
||||
lBytesPerLine = WIDTHBYTES(bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount);
|
||||
bmi.bmiHeader.biSizeImage = lBytesPerLine * bmi.bmiHeader.biHeight;
|
||||
|
||||
// create top-down DIB
|
||||
bmi.bmiHeader.biHeight = -bmi.bmiHeader.biHeight;
|
||||
|
||||
// allocate buffer for pixels
|
||||
VERIFY(hBitmap = CreateDIBSection(hWindowDC,
|
||||
(LPBITMAPINFO)&bmi,
|
||||
DIB_RGB_COLORS,
|
||||
(VOID **)&pbyPixels,
|
||||
NULL,
|
||||
0));
|
||||
if (hBitmap == NULL) goto quit;
|
||||
|
||||
// fill pixel buffer with background color
|
||||
for (nHeight = 0; nHeight < labs(bmi.bmiHeader.biHeight); ++nHeight)
|
||||
{
|
||||
LPBYTE pbyLine = pbyPixels + nHeight * lBytesPerLine;
|
||||
|
||||
for (nWidth = 0; nWidth < bmi.bmiHeader.biWidth; ++nWidth)
|
||||
{
|
||||
*pbyLine++ = sGlb.bmiColors[nBackground].rgbBlue;
|
||||
*pbyLine++ = sGlb.bmiColors[nBackground].rgbGreen;
|
||||
*pbyLine++ = sGlb.bmiColors[nBackground].rgbRed;
|
||||
}
|
||||
|
||||
_ASSERT((DWORD) (pbyLine - pbyPixels) <= bmi.bmiHeader.biSizeImage);
|
||||
}
|
||||
|
||||
while (bDecoding)
|
||||
{
|
||||
INT nBlockType;
|
||||
|
||||
if (ReadGifByte(pBmp,&nBlockType)) goto quit;
|
||||
|
||||
switch (nBlockType)
|
||||
{
|
||||
case ',': // image
|
||||
{
|
||||
CMAP sAct; // data of actual color map
|
||||
|
||||
INT nLeft,nTop,nWidth,nHeight;
|
||||
INT i,nInfo;
|
||||
|
||||
BOOL bInterlaced;
|
||||
INT h,v;
|
||||
INT nCodesize; // LZW codesize in bits
|
||||
INT nBytecount;
|
||||
|
||||
SHORT prefix_table[4096];
|
||||
SHORT code_table[4096];
|
||||
|
||||
INT nMaxcode;
|
||||
INT nClearCode;
|
||||
INT nEndCode;
|
||||
|
||||
INT nCurrCodesize;
|
||||
INT nCurrCode;
|
||||
INT nOldCode;
|
||||
INT nBitsNeeded;
|
||||
BOOL bEndCodeSeen;
|
||||
|
||||
// read image dimensions
|
||||
if ( ReadGifWord(pBmp,&nLeft)
|
||||
|| ReadGifWord(pBmp,&nTop)
|
||||
|| ReadGifWord(pBmp,&nWidth)
|
||||
|| ReadGifWord(pBmp,&nHeight)
|
||||
|| ReadGifByte(pBmp,&nInfo))
|
||||
goto quit;
|
||||
|
||||
if ( nTop + nHeight > labs(bmi.bmiHeader.biHeight)
|
||||
|| nLeft + nWidth > bmi.bmiHeader.biWidth)
|
||||
goto quit;
|
||||
|
||||
/* Bit 3 of info must be zero in GIF87a; in GIF89a, if it
|
||||
* is set, it indicates that the local colormap is sorted,
|
||||
* the most important entries being first. In PseudoColor
|
||||
* environments this can be used to make sure to get the
|
||||
* most important colors from the X server first, to
|
||||
* optimize the image's appearance in the event that not
|
||||
* all the colors from the colormap can actually be
|
||||
* obtained at the same time.
|
||||
*/
|
||||
|
||||
if ((nInfo & 0x80) == 0) // using global color map
|
||||
{
|
||||
sAct = sGlb;
|
||||
}
|
||||
else // using local color map
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
sAct.biBitCount = (nInfo & 7) + 1; // bits used in color map
|
||||
sAct.biClrUsed = (1 << sAct.biBitCount); // no of colors in color map
|
||||
|
||||
for (i = 0; i < sAct.biClrUsed; ++i)
|
||||
{
|
||||
int r, g, b;
|
||||
|
||||
if (ReadGifByte(pBmp,&r) || ReadGifByte(pBmp,&g) || ReadGifByte(pBmp,&b))
|
||||
goto quit;
|
||||
|
||||
sAct.bmiColors[i].rgbRed = r;
|
||||
sAct.bmiColors[i].rgbGreen = g;
|
||||
sAct.bmiColors[i].rgbBlue = b;
|
||||
}
|
||||
}
|
||||
|
||||
// interlaced image
|
||||
bInterlaced = (nInfo & 0x40) != 0;
|
||||
|
||||
h = 0;
|
||||
v = 0;
|
||||
if ( ReadGifByte(pBmp,&nCodesize)
|
||||
|| ReadGifByte(pBmp,&nBytecount))
|
||||
goto quit;
|
||||
|
||||
nMaxcode = (1 << nCodesize);
|
||||
|
||||
// preset LZW table
|
||||
for (i = 0; i < nMaxcode + 2; ++i)
|
||||
{
|
||||
prefix_table[i] = -1;
|
||||
code_table[i] = i;
|
||||
}
|
||||
nClearCode = nMaxcode++;
|
||||
nEndCode = nMaxcode++;
|
||||
|
||||
nCurrCodesize = nCodesize + 1;
|
||||
nCurrCode = 0;
|
||||
nOldCode = -1;
|
||||
nBitsNeeded = nCurrCodesize;
|
||||
bEndCodeSeen = FALSE;
|
||||
|
||||
while (nBytecount != 0)
|
||||
{
|
||||
for (i = 0; i < nBytecount; ++i)
|
||||
{
|
||||
INT nCurrByte;
|
||||
INT nBitsAvailable;
|
||||
|
||||
if (ReadGifByte(pBmp,&nCurrByte))
|
||||
goto quit;
|
||||
|
||||
if (bEndCodeSeen) continue;
|
||||
|
||||
nBitsAvailable = 8;
|
||||
while (nBitsAvailable != 0)
|
||||
{
|
||||
INT nBitsCopied = (nBitsNeeded < nBitsAvailable)
|
||||
? nBitsNeeded
|
||||
: nBitsAvailable;
|
||||
|
||||
INT nBits = nCurrByte >> (8 - nBitsAvailable);
|
||||
|
||||
nBits &= 0xFF >> (8 - nBitsCopied);
|
||||
nCurrCode |= nBits << (nCurrCodesize - nBitsNeeded);
|
||||
nBitsAvailable -= nBitsCopied;
|
||||
nBitsNeeded -= nBitsCopied;
|
||||
|
||||
if (nBitsNeeded == 0)
|
||||
{
|
||||
BYTE byExpanded[4096];
|
||||
INT nExplen;
|
||||
|
||||
do
|
||||
{
|
||||
if (nCurrCode == nEndCode)
|
||||
{
|
||||
bEndCodeSeen = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nCurrCode == nClearCode)
|
||||
{
|
||||
nMaxcode = (1 << nCodesize) + 2;
|
||||
nCurrCodesize = nCodesize + 1;
|
||||
nOldCode = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nCurrCode < nMaxcode)
|
||||
{
|
||||
if (nMaxcode < 4096 && nOldCode != -1)
|
||||
{
|
||||
INT c = nCurrCode;
|
||||
while (prefix_table[c] != -1)
|
||||
c = prefix_table[c];
|
||||
c = code_table[c];
|
||||
prefix_table[nMaxcode] = nOldCode;
|
||||
code_table[nMaxcode] = c;
|
||||
nMaxcode++;
|
||||
if (nMaxcode == (1 << nCurrCodesize) && nCurrCodesize < 12)
|
||||
nCurrCodesize++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
INT c;
|
||||
|
||||
if (nCurrCode > nMaxcode || nOldCode == -1) goto quit;
|
||||
|
||||
_ASSERT(nCurrCode == nMaxcode);
|
||||
|
||||
/* Once maxcode == 4096, we can't get here
|
||||
* any more, because we refuse to raise
|
||||
* nCurrCodeSize above 12 -- so we can
|
||||
* never read a bigger code than 4095.
|
||||
*/
|
||||
|
||||
c = nOldCode;
|
||||
while (prefix_table[c] != -1)
|
||||
c = prefix_table[c];
|
||||
c = code_table[c];
|
||||
prefix_table[nMaxcode] = nOldCode;
|
||||
code_table[nMaxcode] = c;
|
||||
nMaxcode++;
|
||||
|
||||
if (nMaxcode == (1 << nCurrCodesize) && nCurrCodesize < 12)
|
||||
nCurrCodesize++;
|
||||
}
|
||||
nOldCode = nCurrCode;
|
||||
|
||||
// output nCurrCode!
|
||||
nExplen = 0;
|
||||
while (nCurrCode != -1)
|
||||
{
|
||||
_ASSERT(nExplen < ARRAYSIZEOF(byExpanded));
|
||||
byExpanded[nExplen++] = (BYTE) code_table[nCurrCode];
|
||||
nCurrCode = prefix_table[nCurrCode];
|
||||
}
|
||||
_ASSERT(nExplen > 0);
|
||||
|
||||
while (--nExplen >= 0)
|
||||
{
|
||||
// get color map index
|
||||
BYTE byColIndex = byExpanded[nExplen];
|
||||
|
||||
LPBYTE pbyRgbr = pbyPixels + (lBytesPerLine * (nTop + v) + 3 * (nLeft + h));
|
||||
|
||||
_ASSERT(pbyRgbr + 2 < pbyPixels + bmi.bmiHeader.biSizeImage);
|
||||
_ASSERT(byColIndex < sAct.biClrUsed);
|
||||
|
||||
*pbyRgbr++ = sAct.bmiColors[byColIndex].rgbBlue;
|
||||
*pbyRgbr++ = sAct.bmiColors[byColIndex].rgbGreen;
|
||||
*pbyRgbr = sAct.bmiColors[byColIndex].rgbRed;
|
||||
|
||||
if (++h == nWidth)
|
||||
{
|
||||
h = 0;
|
||||
if (bInterlaced)
|
||||
{
|
||||
switch (v & 7)
|
||||
{
|
||||
case 0:
|
||||
v += 8;
|
||||
if (v < nHeight)
|
||||
break;
|
||||
/* Some GIF en/decoders go
|
||||
* straight from the '0'
|
||||
* pass to the '4' pass
|
||||
* without checking the
|
||||
* height, and blow up on
|
||||
* 2/3/4 pixel high
|
||||
* interlaced images.
|
||||
*/
|
||||
if (nHeight > 4)
|
||||
v = 4;
|
||||
else
|
||||
if (nHeight > 2)
|
||||
v = 2;
|
||||
else
|
||||
if (nHeight > 1)
|
||||
v = 1;
|
||||
else
|
||||
bEndCodeSeen = TRUE;
|
||||
break;
|
||||
case 4:
|
||||
v += 8;
|
||||
if (v >= nHeight)
|
||||
v = 2;
|
||||
break;
|
||||
case 2:
|
||||
case 6:
|
||||
v += 4;
|
||||
if (v >= nHeight)
|
||||
v = 1;
|
||||
break;
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
v += 2;
|
||||
if (v >= nHeight)
|
||||
bEndCodeSeen = TRUE;
|
||||
break;
|
||||
}
|
||||
if (bEndCodeSeen)
|
||||
break; // while (--nExplen >= 0)
|
||||
}
|
||||
else // non interlaced
|
||||
{
|
||||
if (++v == nHeight)
|
||||
{
|
||||
bEndCodeSeen = TRUE;
|
||||
break; // while (--nExplen >= 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (FALSE);
|
||||
|
||||
nCurrCode = 0;
|
||||
nBitsNeeded = nCurrCodesize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ReadGifByte(pBmp,&nBytecount))
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case '!': // extension block
|
||||
{
|
||||
INT i,nFunctionCode,nByteCount,nDummy;
|
||||
|
||||
if (ReadGifByte(pBmp,&nFunctionCode)) goto quit;
|
||||
if (ReadGifByte(pBmp,&nByteCount)) goto quit;
|
||||
|
||||
while (nByteCount != 0)
|
||||
{
|
||||
for (i = 0; i < nByteCount; ++i)
|
||||
{
|
||||
if (ReadGifByte(pBmp,&nDummy)) goto quit;
|
||||
}
|
||||
|
||||
if (ReadGifByte(pBmp,&nByteCount)) goto quit;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ';': // terminator
|
||||
bDecoding = FALSE;
|
||||
break;
|
||||
|
||||
default: goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
_ASSERT(bDecoding == FALSE); // decoding successful
|
||||
|
||||
// normal decoding exit
|
||||
_ASSERT(hPalette == NULL); // resource free
|
||||
hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi);
|
||||
// save old palette
|
||||
hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE);
|
||||
RealizePalette(hWindowDC);
|
||||
|
||||
quit:
|
||||
if (hBitmap != NULL && bDecoding) // creation failed
|
||||
{
|
||||
DeleteObject(hBitmap); // delete bitmap
|
||||
hBitmap = NULL;
|
||||
}
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
HBITMAP LoadBitmapFile(LPCTSTR szFilename)
|
||||
{
|
||||
HANDLE hFile;
|
||||
HANDLE hMap;
|
||||
LPBYTE pbyFile;
|
||||
BMPFILE Bmp;
|
||||
HBITMAP hBitmap;
|
||||
LPBITMAPFILEHEADER pBmfh;
|
||||
LPBITMAPINFO pBmi;
|
||||
|
||||
SetCurrentDirectory(szEmuDirectory);
|
||||
hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
SetCurrentDirectory(szCurrentDirectory);
|
||||
// opened with GENERIC_READ -> PAGE_READONLY
|
||||
if (hFile == INVALID_HANDLE_VALUE) return NULL;
|
||||
Bmp.dwFileSize = GetFileSize(hFile, NULL);
|
||||
hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMap == NULL)
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
return NULL;
|
||||
}
|
||||
// opened with GENERIC_READ -> PAGE_READONLY -> FILE_MAP_READ
|
||||
pbyFile = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
|
||||
if (pbyFile == NULL)
|
||||
Bmp.pbyFile = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
|
||||
if (Bmp.pbyFile == NULL)
|
||||
{
|
||||
CloseHandle(hMap);
|
||||
CloseHandle(hFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hBitmap = NULL;
|
||||
pBmfh = (LPBITMAPFILEHEADER)pbyFile;
|
||||
if (pBmfh->bfType != 0x4D42) goto quit; // "BM"
|
||||
pBmi = (LPBITMAPINFO)(pbyFile+sizeof(BITMAPFILEHEADER));
|
||||
do
|
||||
{
|
||||
// check for bitmap file header "BM"
|
||||
if (Bmp.dwFileSize >= 2 && *(WORD *) Bmp.pbyFile == 0x4D42)
|
||||
{
|
||||
hBitmap = DecodeBmp(&Bmp);
|
||||
break;
|
||||
}
|
||||
|
||||
_ASSERT(hPalette == NULL); // resource free
|
||||
hPalette = CreateBIPalette(&pBmi->bmiHeader);
|
||||
// save old palette
|
||||
hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE);
|
||||
RealizePalette(hWindowDC);
|
||||
// check for GIF file header
|
||||
if ( Bmp.dwFileSize >= 6
|
||||
&& (memcmp(Bmp.pbyFile,"GIF87a",6) == 0 || memcmp(Bmp.pbyFile,"GIF89a",6) == 0))
|
||||
{
|
||||
hBitmap = DecodeGif(&Bmp);
|
||||
break;
|
||||
}
|
||||
|
||||
hBitmap = CreateDIBitmap(
|
||||
hWindowDC,
|
||||
&pBmi->bmiHeader,
|
||||
CBM_INIT,
|
||||
pbyFile + pBmfh->bfOffBits,
|
||||
pBmi, DIB_RGB_COLORS);
|
||||
_ASSERT(hBitmap != NULL);
|
||||
// unknown file type
|
||||
hBitmap = NULL;
|
||||
}
|
||||
while (FALSE);
|
||||
|
||||
quit:
|
||||
UnmapViewOfFile(pbyFile);
|
||||
UnmapViewOfFile(Bmp.pbyFile);
|
||||
CloseHandle(hMap);
|
||||
CloseHandle(hFile);
|
||||
return hBitmap;
|
||||
|
|
189
source/KML.C
189
source/KML.C
|
@ -11,7 +11,6 @@
|
|||
#include "Emu48.h"
|
||||
#include "kml.h"
|
||||
|
||||
static VOID FatalError(VOID);
|
||||
static VOID InitLex(LPCTSTR szScript);
|
||||
static VOID CleanLex(VOID);
|
||||
static VOID SkipWhite(UINT nMode);
|
||||
|
@ -91,6 +90,7 @@ static KmlToken pLexToken[] =
|
|||
{TOK_MODEL, 000002, 5,_T("Model")},
|
||||
{TOK_CLASS, 000001, 5,_T("Class")},
|
||||
{TOK_PRESS, 000001, 5,_T("Press")},
|
||||
// {TOK_IFMEM, 000111, 5,_T("IfMem")},
|
||||
{TOK_TYPE, 000001, 4,_T("Type")},
|
||||
{TOK_SIZE, 000011, 4,_T("Size")},
|
||||
{TOK_ZOOM, 000001, 4,_T("Zoom")},
|
||||
|
@ -118,6 +118,7 @@ static CONST TokenId eIsBlock[] =
|
|||
{
|
||||
TOK_IFFLAG,
|
||||
TOK_IFPRESSED,
|
||||
TOK_IFMEM,
|
||||
TOK_ONDOWN,
|
||||
TOK_ONUP
|
||||
};
|
||||
|
@ -125,8 +126,8 @@ static CONST TokenId eIsBlock[] =
|
|||
static BOOL bClicking = FALSE;
|
||||
static UINT uButtonClicked = 0;
|
||||
|
||||
static BOOL bPressed = FALSE; // no key pressed
|
||||
static UINT uLastPressedKey = 0; // var for last pressed key
|
||||
static BOOL bKeyPressed = FALSE; // no key pressed
|
||||
static UINT uLastKeyPressed = 0; // var for last pressed key
|
||||
|
||||
//################
|
||||
//#
|
||||
|
@ -381,6 +382,38 @@ static VOID BrowseFolder(HWND hDlg)
|
|||
return;
|
||||
}
|
||||
|
||||
static VOID UpdateScriptList(HWND hDlg)
|
||||
{
|
||||
HWND hList;
|
||||
KmlScript* pList;
|
||||
UINT nIndex,nEntries;
|
||||
DWORD dwActId = CB_ERR;
|
||||
|
||||
// add all script titles to combo box
|
||||
hList = GetDlgItem(hDlg,IDC_KMLSCRIPT);
|
||||
SendMessage(hList, CB_RESETCONTENT, 0, 0);
|
||||
for (nEntries = 0, pList = pKmlList; pList; pList = pList->pNext)
|
||||
{
|
||||
nIndex = (UINT) SendMessage(hList, CB_ADDSTRING, 0, (LPARAM)pList->szTitle);
|
||||
SendMessage(hList, CB_SETITEMDATA, nIndex, (LPARAM) pList->nId);
|
||||
|
||||
// this has the same filename like the actual KML script
|
||||
if (lstrcmpi(szCurrentKml, pList->szFilename) == 0)
|
||||
dwActId = pList->nId;
|
||||
|
||||
nEntries++;
|
||||
}
|
||||
|
||||
while (--nEntries > 0) // scan all combo box items
|
||||
{
|
||||
// found ID of actual KML script
|
||||
if ((DWORD) SendMessage(hList, CB_GETITEMDATA, nEntries, 0) == dwActId)
|
||||
break;
|
||||
}
|
||||
SendMessage(hList, CB_SETCURSEL, nEntries, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
static INT_PTR CALLBACK ChooseKMLProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
HWND hList;
|
||||
|
@ -391,16 +424,7 @@ static INT_PTR CALLBACK ChooseKMLProc(HWND hDlg, UINT message, WPARAM wParam, LP
|
|||
{
|
||||
case WM_INITDIALOG:
|
||||
SetDlgItemText(hDlg,IDC_EMUDIR,szEmuDirectory);
|
||||
hList = GetDlgItem(hDlg,IDC_KMLSCRIPT);
|
||||
SendMessage(hList, CB_RESETCONTENT, 0, 0);
|
||||
pList = pKmlList;
|
||||
while (pList)
|
||||
{
|
||||
nIndex = (UINT) SendMessage(hList, CB_ADDSTRING, 0, (LPARAM)pList->szTitle);
|
||||
SendMessage(hList, CB_SETITEMDATA, nIndex, (LPARAM)pList->nId);
|
||||
pList = pList->pNext;
|
||||
}
|
||||
SendMessage(hList, CB_SETCURSEL, 0, 0);
|
||||
UpdateScriptList(hDlg); // update combo box with script titles
|
||||
return TRUE;
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
|
@ -412,24 +436,14 @@ static INT_PTR CALLBACK ChooseKMLProc(HWND hDlg, UINT message, WPARAM wParam, LP
|
|||
DestroyKmlList();
|
||||
GetDlgItemText(hDlg,IDC_EMUDIR,szEmuDirectory,ARRAYSIZEOF(szEmuDirectory));
|
||||
CreateKmlList();
|
||||
hList = GetDlgItem(hDlg,IDC_KMLSCRIPT);
|
||||
SendMessage(hList, CB_RESETCONTENT, 0, 0);
|
||||
pList = pKmlList;
|
||||
while (pList)
|
||||
{
|
||||
nIndex = (UINT) SendMessage(hList, CB_ADDSTRING, 0, (LPARAM)pList->szTitle);
|
||||
SendMessage(hList, CB_SETITEMDATA, nIndex, (LPARAM)pList->nId);
|
||||
pList = pList->pNext;
|
||||
}
|
||||
SendMessage(hList, CB_SETCURSEL, 0, 0);
|
||||
UpdateScriptList(hDlg); // update combo box with script titles
|
||||
return TRUE;
|
||||
case IDOK:
|
||||
GetDlgItemText(hDlg,IDC_EMUDIR,szEmuDirectory,ARRAYSIZEOF(szEmuDirectory));
|
||||
hList = GetDlgItem(hDlg,IDC_KMLSCRIPT);
|
||||
nIndex = (UINT) SendMessage(hList, CB_GETCURSEL, 0, 0);
|
||||
nIndex = (UINT) SendMessage(hList, CB_GETITEMDATA, nIndex, 0);
|
||||
pList = pKmlList;
|
||||
while (pList)
|
||||
for (pList = pKmlList; pList; pList = pList->pNext)
|
||||
{
|
||||
if (pList->nId == nIndex)
|
||||
{
|
||||
|
@ -437,7 +451,6 @@ static INT_PTR CALLBACK ChooseKMLProc(HWND hDlg, UINT message, WPARAM wParam, LP
|
|||
EndDialog(hDlg, IDOK);
|
||||
break;
|
||||
}
|
||||
pList = pList->pNext;
|
||||
}
|
||||
return TRUE;
|
||||
case IDCANCEL:
|
||||
|
@ -521,12 +534,6 @@ fail:
|
|||
//#
|
||||
//################
|
||||
|
||||
static VOID FatalError(VOID)
|
||||
{
|
||||
PrintfToLog(_T("Fatal Error at line %i"), nLexLine);
|
||||
return;
|
||||
}
|
||||
|
||||
static VOID InitLex(LPCTSTR szScript)
|
||||
{
|
||||
nLexLine = 1;
|
||||
|
@ -664,11 +671,12 @@ static LPTSTR ParseString(VOID)
|
|||
lpszString = HeapReAlloc(hHeap,0,lpszString,nBlock * sizeof(lpszString[0]));
|
||||
}
|
||||
|
||||
if (*szText == _T('\\')) szText++; // skip '\' escape char
|
||||
if (*szText == _T('\\')) szText++; // skip '\' escape char to decode \"
|
||||
if (*szText == 0) // EOS found inside string
|
||||
{
|
||||
lpszString[nLength] = 0; // set EOS
|
||||
PrintfToLog(_T("%i: Invalid string %s."), nLexLine, lpszString);
|
||||
HeapFree(hHeap,0,lpszString);
|
||||
FatalError();
|
||||
return NULL;
|
||||
}
|
||||
lpszString[nLength++] = *szText++; // save char
|
||||
|
@ -803,12 +811,10 @@ static KmlLine* IncludeLines(LPCTSTR szFilename)
|
|||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
PrintfToLog(_T("Error while opening include file %s."), szFilename);
|
||||
FatalError();
|
||||
return NULL;
|
||||
}
|
||||
if ((lpbyBuf = MapKMLFile(hFile)) == NULL)
|
||||
{
|
||||
FatalError();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -851,13 +857,12 @@ static KmlLine* ParseLines(VOID)
|
|||
if (eToken != TOK_STRING) // not a string (token don't begin with ")
|
||||
{
|
||||
AddToLog(_T("Include: string expected as parameter."));
|
||||
FatalError();
|
||||
goto abort;
|
||||
}
|
||||
szFilename = szLexString; // save pointer to allocated memory
|
||||
if (pFirst)
|
||||
{
|
||||
pLine->pNext = IncludeLines(szLexString);
|
||||
pLine = pLine->pNext = IncludeLines(szLexString);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -907,51 +912,45 @@ abort:
|
|||
|
||||
static KmlBlock* ParseBlock(TokenId eType)
|
||||
{
|
||||
UINT u1;
|
||||
UINT i;
|
||||
KmlBlock* pBlock;
|
||||
TokenId eToken;
|
||||
|
||||
nLinesIncludeLevel = 0;
|
||||
|
||||
pBlock = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(KmlBlock));
|
||||
VERIFY(pBlock = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(KmlBlock)));
|
||||
pBlock->eType = eType;
|
||||
|
||||
u1 = 0;
|
||||
while (pLexToken[u1].nLen)
|
||||
for (i = 0; pLexToken[i].nLen; ++i) // search for token
|
||||
{
|
||||
if (pLexToken[u1].eId == eType) break;
|
||||
u1++;
|
||||
if (pLexToken[i].eId == eType) break;
|
||||
}
|
||||
if (pLexToken[u1].nParams)
|
||||
|
||||
if (pLexToken[i].nParams) // has block command arguments
|
||||
{
|
||||
eToken = Lex(LEX_COMMAND);
|
||||
switch (eToken)
|
||||
// block command parser accept only one integer argument
|
||||
_ASSERT(pLexToken[i].nParams == TYPE_INTEGER);
|
||||
|
||||
eToken = Lex(LEX_PARAM); // decode argument
|
||||
if (eToken != TOK_INTEGER)
|
||||
{
|
||||
case TOK_NONE:
|
||||
AddToLog(_T("Open Block at End Of File."));
|
||||
PrintfToLog(_T("%i: Block %s parameter must be an integer."), nLexLine, pLexToken[i].szName);
|
||||
HeapFree(hHeap,0,pBlock);
|
||||
FatalError();
|
||||
return NULL;
|
||||
case TOK_INTEGER:
|
||||
if ((pLexToken[u1].nParams&7)!=TYPE_INTEGER)
|
||||
{
|
||||
AddToLog(_T("Wrong block argument."));
|
||||
HeapFree(hHeap,0,pBlock);
|
||||
FatalError();
|
||||
return NULL;
|
||||
}
|
||||
pBlock->nId = nLexInteger;
|
||||
break;
|
||||
default:
|
||||
AddToLog(_T("Wrong block argument."));
|
||||
HeapFree(hHeap,0,pBlock);
|
||||
FatalError();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pBlock->nId = nLexInteger; // remember block no.
|
||||
}
|
||||
|
||||
eToken = Lex(LEX_PARAM); // decode argument
|
||||
if (eToken != TOK_EOL)
|
||||
{
|
||||
PrintfToLog(_T("%i: Too many parameters for block %s."), nLexLine, pLexToken[i].szName);
|
||||
HeapFree(hHeap,0,pBlock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pBlock->pFirstLine = ParseLines();
|
||||
|
||||
if (pBlock->pFirstLine == NULL) // break on ParseLines error
|
||||
{
|
||||
HeapFree(hHeap,0,pBlock);
|
||||
|
@ -981,12 +980,10 @@ static KmlBlock* IncludeBlocks(LPCTSTR szFilename)
|
|||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
PrintfToLog(_T("Error while opening include file %s."), szFilename);
|
||||
FatalError();
|
||||
return NULL;
|
||||
}
|
||||
if ((lpbyBuf = MapKMLFile(hFile)) == NULL)
|
||||
{
|
||||
FatalError();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1022,7 +1019,6 @@ static KmlBlock* ParseBlocks(VOID)
|
|||
if (eToken != TOK_STRING) // not a string (token don't begin with ")
|
||||
{
|
||||
AddToLog(_T("Include: string expected as parameter."));
|
||||
FatalError();
|
||||
goto abort;
|
||||
}
|
||||
szFilename = szLexString; // save pointer to allocated memory
|
||||
|
@ -1039,28 +1035,24 @@ static KmlBlock* ParseBlocks(VOID)
|
|||
if (!IsGlobalBlock(eToken)) // check for valid block commands
|
||||
{
|
||||
PrintfToLog(_T("%i: Invalid Block %s."), nLexLine, GetStringOf(eToken));
|
||||
FatalError();
|
||||
goto abort;
|
||||
}
|
||||
if (pFirst)
|
||||
pBlock = pBlock->pNext = ParseBlock(eToken);
|
||||
else
|
||||
pBlock = pFirst = ParseBlock(eToken);
|
||||
if (pBlock == NULL)
|
||||
{
|
||||
AddToLog(_T("Invalid block."));
|
||||
FatalError();
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (pBlock == NULL) goto abort;
|
||||
}
|
||||
if (pFirst) pBlock->pNext = NULL;
|
||||
if (pBlock) pBlock->pNext = NULL;
|
||||
if (*szText != 0) // still KML text left
|
||||
{
|
||||
FatalError(); // error unknown block token
|
||||
goto abort;
|
||||
}
|
||||
return pFirst;
|
||||
|
||||
abort:
|
||||
PrintfToLog(_T("Fatal Error at line %i."), nLexLine);
|
||||
if (pFirst) FreeBlocks(pFirst);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1107,16 +1099,16 @@ static VOID InitGlobal(KmlBlock* pBlock)
|
|||
case TOK_ROM:
|
||||
if (pbyRom != NULL)
|
||||
{
|
||||
PrintfToLog(_T("Rom %s Ignored."), (LPTSTR)pLine->nParam[0]);
|
||||
PrintfToLog(_T("Rom %s ignored."), (LPTSTR)pLine->nParam[0]);
|
||||
AddToLog(_T("Please put only one Rom command in the Global block."));
|
||||
break;
|
||||
}
|
||||
if (!MapRom((LPTSTR)pLine->nParam[0]))
|
||||
{
|
||||
PrintfToLog(_T("Cannot open Rom %s"), (LPTSTR)pLine->nParam[0]);
|
||||
PrintfToLog(_T("Cannot open Rom %s."), (LPTSTR)pLine->nParam[0]);
|
||||
break;
|
||||
}
|
||||
PrintfToLog(_T("Rom %s Loaded."), (LPTSTR)pLine->nParam[0]);
|
||||
PrintfToLog(_T("Rom %s loaded."), (LPTSTR)pLine->nParam[0]);
|
||||
break;
|
||||
case TOK_PATCH:
|
||||
if (pbyRom == NULL)
|
||||
|
@ -1126,23 +1118,23 @@ static VOID InitGlobal(KmlBlock* pBlock)
|
|||
break;
|
||||
}
|
||||
if (PatchRom((LPTSTR)pLine->nParam[0]) == TRUE)
|
||||
PrintfToLog(_T("Patch %s Loaded"), (LPTSTR)pLine->nParam[0]);
|
||||
PrintfToLog(_T("Patch %s loaded."), (LPTSTR)pLine->nParam[0]);
|
||||
else
|
||||
PrintfToLog(_T("Patch %s is Wrong or Missing"), (LPTSTR)pLine->nParam[0]);
|
||||
PrintfToLog(_T("Patch %s is Wrong or Missing."), (LPTSTR)pLine->nParam[0]);
|
||||
break;
|
||||
case TOK_BITMAP:
|
||||
if (hMainDC != NULL)
|
||||
{
|
||||
PrintfToLog(_T("Bitmap %s Ignored."), (LPTSTR)pLine->nParam[0]);
|
||||
PrintfToLog(_T("Bitmap %s ignored."), (LPTSTR)pLine->nParam[0]);
|
||||
AddToLog(_T("Please put only one Bitmap command in the Global block."));
|
||||
break;
|
||||
}
|
||||
if (!CreateMainBitmap((LPTSTR)pLine->nParam[0]))
|
||||
{
|
||||
PrintfToLog(_T("Cannot Load Bitmap %s."), (LPTSTR)pLine->nParam[0]);
|
||||
PrintfToLog(_T("Cannot load Bitmap %s."), (LPTSTR)pLine->nParam[0]);
|
||||
break;
|
||||
}
|
||||
PrintfToLog(_T("Bitmap %s Loaded."), (LPTSTR)pLine->nParam[0]);
|
||||
PrintfToLog(_T("Bitmap %s loaded."), (LPTSTR)pLine->nParam[0]);
|
||||
break;
|
||||
default:
|
||||
PrintfToLog(_T("Command %s Ignored in Block %s"), GetStringOf(pLine->eCommand), GetStringOf(pBlock->eType));
|
||||
|
@ -1247,14 +1239,16 @@ static VOID InitButton(KmlBlock* pBlock)
|
|||
{
|
||||
KmlLine* pLine = pBlock->pFirstLine;
|
||||
UINT nLevel = 0;
|
||||
if (nButtons>=256)
|
||||
|
||||
_ASSERT(ARRAYSIZEOF(pButton) == 256); // adjust warning message
|
||||
if (nButtons >= ARRAYSIZEOF(pButton))
|
||||
{
|
||||
AddToLog(_T("Only the first 256 buttons will be defined."));
|
||||
return;
|
||||
}
|
||||
pButton[nButtons].nId = pBlock->nId;
|
||||
pButton[nButtons].bDown = FALSE;
|
||||
pButton[nButtons].nType = 0; // default : user defined button
|
||||
pButton[nButtons].nType = 0; // default: user defined button
|
||||
while (pLine)
|
||||
{
|
||||
if (nLevel)
|
||||
|
@ -1379,6 +1373,8 @@ static KmlLine* If(KmlLine* pLine, BOOL bCondition)
|
|||
|
||||
static KmlLine* RunLine(KmlLine* pLine)
|
||||
{
|
||||
BYTE byVal;
|
||||
|
||||
switch (pLine->eCommand)
|
||||
{
|
||||
case TOK_MAP:
|
||||
|
@ -1407,9 +1403,11 @@ static KmlLine* RunLine(KmlLine* pLine)
|
|||
break;
|
||||
case TOK_IFPRESSED:
|
||||
return If(pLine,byVKeyMap[pLine->nParam[0]&0xFF]);
|
||||
break;
|
||||
case TOK_IFFLAG:
|
||||
return If(pLine,(nKMLFlags>>(pLine->nParam[0]&0x1F))&1);
|
||||
case TOK_IFMEM:
|
||||
Npeek(&byVal,pLine->nParam[0],1);
|
||||
return If(pLine,(byVal & pLine->nParam[1]) == pLine->nParam[2]);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1825,7 +1823,7 @@ static VOID ReleaseAllButtons(VOID) // release all buttons
|
|||
ReleaseButton(i); // release button
|
||||
}
|
||||
|
||||
bPressed = FALSE; // key not pressed
|
||||
bKeyPressed = FALSE; // key not pressed
|
||||
bClicking = FALSE; // var uButtonClicked not valid (no virtual or nohold key)
|
||||
uButtonClicked = 0; // set var to default
|
||||
}
|
||||
|
@ -1839,6 +1837,9 @@ VOID ReloadButtons(BYTE *Keyboard_Row, UINT nSize)
|
|||
{
|
||||
// get state of button from keyboard matrix
|
||||
pButton[i].bDown = ((Keyboard_Row[pButton[i].nOut] & pButton[i].nIn) != 0);
|
||||
|
||||
// any key pressed?
|
||||
bKeyPressed = bKeyPressed || pButton[i].bDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1953,8 +1954,8 @@ VOID MouseButtonDownAt(UINT nFlags, DWORD x, DWORD y)
|
|||
bClicking = TRUE;
|
||||
uButtonClicked = i;
|
||||
}
|
||||
bPressed = TRUE; // key pressed
|
||||
uLastPressedKey = i; // save pressed key
|
||||
bKeyPressed = TRUE; // key pressed
|
||||
uLastKeyPressed = i; // save pressed key
|
||||
PressButton(i);
|
||||
return;
|
||||
}
|
||||
|
@ -1964,7 +1965,7 @@ VOID MouseButtonDownAt(UINT nFlags, DWORD x, DWORD y)
|
|||
VOID MouseButtonUpAt(UINT nFlags, DWORD x, DWORD y)
|
||||
{
|
||||
UINT i;
|
||||
if (bPressed) // emulator key pressed
|
||||
if (bKeyPressed) // emulator key pressed
|
||||
{
|
||||
ReleaseAllButtons(); // release all buttons
|
||||
return;
|
||||
|
@ -2010,7 +2011,7 @@ VOID MouseMovesTo(UINT nFlags, DWORD x, DWORD y)
|
|||
SetCursor(hCursor);
|
||||
|
||||
if (!(nFlags&MK_LBUTTON)) return; // left mouse key not pressed -> quit
|
||||
if ((bPressed) && !(ClipButton(x,y,uLastPressedKey))) // not on last pressed key
|
||||
if (bKeyPressed && !ClipButton(x,y,uLastKeyPressed)) // not on last pressed key
|
||||
ReleaseAllButtons(); // release all buttons
|
||||
if (!bClicking) return; // normal emulation key -> quit
|
||||
|
||||
|
|
27
source/KML.H
27
source/KML.H
|
@ -45,19 +45,20 @@ typedef enum eTokenId
|
|||
TOK_MODEL, //29
|
||||
TOK_CLASS, //30
|
||||
TOK_PRESS, //31
|
||||
TOK_TYPE, //32
|
||||
TOK_SIZE, //33
|
||||
TOK_DOWN, //34
|
||||
TOK_ZOOM, //35
|
||||
TOK_ELSE, //36
|
||||
TOK_ONUP, //37
|
||||
TOK_EOL, //38
|
||||
TOK_MAP, //39
|
||||
TOK_ROM, //40
|
||||
TOK_VGA, //41
|
||||
TOK_LCD, //42
|
||||
TOK_NOTFLAG, //43
|
||||
TOK_END //44
|
||||
TOK_IFMEM, //32
|
||||
TOK_TYPE, //33
|
||||
TOK_SIZE, //34
|
||||
TOK_DOWN, //35
|
||||
TOK_ZOOM, //36
|
||||
TOK_ELSE, //37
|
||||
TOK_ONUP, //38
|
||||
TOK_EOL, //39
|
||||
TOK_MAP, //34
|
||||
TOK_ROM, //41
|
||||
TOK_VGA, //42
|
||||
TOK_LCD, //43
|
||||
TOK_NOTFLAG, //44
|
||||
TOK_END //45
|
||||
} TokenId;
|
||||
|
||||
#define TYPE_NONE 00
|
||||
|
|
320
source/MRU.C
Normal file
320
source/MRU.C
Normal file
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* mru.c
|
||||
*
|
||||
* This file is part of Emu48
|
||||
*
|
||||
* Copyright (C) 2007 Christoph Gießelink
|
||||
*
|
||||
*/
|
||||
#include "pch.h"
|
||||
#include "resource.h"
|
||||
#include "Emu48.h"
|
||||
|
||||
static TCHAR szOriginal[MAX_PATH] = _T("");
|
||||
|
||||
static LPTSTR *ppszFiles = NULL; // pointer to MRU table
|
||||
static INT nEntry = 0; // no. of MRU entries
|
||||
|
||||
static HMENU hMruMenu = NULL; // menu handle for MRU list
|
||||
static INT nMruPos; // insert position for MRU list
|
||||
|
||||
static BOOL GetMenuPosForId(HMENU hMenu, UINT nItem)
|
||||
{
|
||||
HMENU hSubMenu;
|
||||
UINT nID;
|
||||
INT i,nMaxID;
|
||||
|
||||
nMaxID = GetMenuItemCount(hMenu);
|
||||
for (i = 0; i < nMaxID; ++i)
|
||||
{
|
||||
nID = GetMenuItemID(hMenu,i); // get ID
|
||||
|
||||
if (nID == 0) continue; // separator or invalid command
|
||||
|
||||
if (nID == (UINT)-1) // possibly a popup menu
|
||||
{
|
||||
hSubMenu = GetSubMenu(hMenu,i); // try to get handle to popup menu
|
||||
if (hSubMenu != NULL) // it's a popup menu
|
||||
{
|
||||
// recursive search
|
||||
if (GetMenuPosForId(hSubMenu,nItem))
|
||||
return TRUE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nID == nItem) // found ID
|
||||
{
|
||||
hMruMenu = hMenu; // remember menu and position
|
||||
nMruPos = i;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL MruInit(INT nNum)
|
||||
{
|
||||
HMENU hMenu = GetMenu(hWnd); // main menu
|
||||
|
||||
_ASSERT(ppszFiles == NULL); // MRU already initialized
|
||||
|
||||
if (*szOriginal == 0) // get orginal value of first MRU entry
|
||||
{
|
||||
VERIFY(GetMenuString(hMenu,ID_FILE_MRU_FILE1,szOriginal,ARRAYSIZEOF(szOriginal),MF_BYCOMMAND));
|
||||
}
|
||||
|
||||
// no. of files in MRU list
|
||||
nEntry = ReadSettingsInt(_T("MRU"),_T("FileCount"),nNum);
|
||||
|
||||
// look for menu position of ID_FILE_MRU_FILE1
|
||||
VERIFY(GetMenuPosForId(hMenu,ID_FILE_MRU_FILE1));
|
||||
|
||||
if (nEntry > 0) // allocate MRU table
|
||||
{
|
||||
// create MRU table
|
||||
if ((ppszFiles = HeapAlloc(hHeap,0,nEntry * sizeof(*ppszFiles))) == NULL)
|
||||
return TRUE;
|
||||
|
||||
// fill each entry
|
||||
for (nNum = 0; nNum < nEntry; ++nNum)
|
||||
ppszFiles[nNum] = NULL;
|
||||
|
||||
MruReadList(); // read actual MRU list
|
||||
MruUpdateMenu(); // update menu
|
||||
}
|
||||
else // kill MRU menu entries
|
||||
{
|
||||
// delete MRU menu
|
||||
DeleteMenu(hMruMenu,nMruPos,MF_BYPOSITION);
|
||||
|
||||
// delete following separator
|
||||
_ASSERT((GetMenuState(hMruMenu,nMruPos,MF_BYPOSITION) & MF_SEPARATOR) != 0);
|
||||
DeleteMenu(hMruMenu,nMruPos,MF_BYPOSITION);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID MruCleanup(VOID)
|
||||
{
|
||||
INT i;
|
||||
|
||||
MruWriteList(); // write actual MRU list
|
||||
|
||||
for (i = 0; i < nEntry; ++i) // cleanup each entry
|
||||
{
|
||||
if (ppszFiles[i] != NULL)
|
||||
HeapFree(hHeap,0,ppszFiles[i]); // cleanup entry
|
||||
}
|
||||
|
||||
if (ppszFiles != NULL) // table defined
|
||||
{
|
||||
HeapFree(hHeap,0,ppszFiles); // free table
|
||||
ppszFiles = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
VOID MruAdd(LPCTSTR lpszEntry)
|
||||
{
|
||||
TCHAR szFilename[MAX_PATH];
|
||||
LPTSTR lpFilePart;
|
||||
INT i;
|
||||
|
||||
if (nEntry == 0) return; // no entries
|
||||
|
||||
// get full path name
|
||||
GetFullPathName(lpszEntry,ARRAYSIZEOF(szFilename),szFilename,&lpFilePart);
|
||||
|
||||
// look if entry is already in table
|
||||
for (i = 0; i < nEntry; ++i)
|
||||
{
|
||||
// already in table -> quit
|
||||
if ( ppszFiles[i] != NULL
|
||||
&& lstrcmpi(ppszFiles[i],szFilename) == 0)
|
||||
{
|
||||
MruUpdateMenu(); // update menu
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
i = nEntry - 1; // last index
|
||||
if (ppszFiles[i] != NULL)
|
||||
HeapFree(hHeap,0,ppszFiles[i]); // free oldest entry
|
||||
|
||||
for (; i > 0; --i) // move old entries 1 line down
|
||||
{
|
||||
ppszFiles[i] = ppszFiles[i-1];
|
||||
}
|
||||
|
||||
// add new entry to top
|
||||
ppszFiles[0] = DuplicateString(szFilename);
|
||||
|
||||
MruUpdateMenu(); // update menu
|
||||
return;
|
||||
}
|
||||
|
||||
VOID MruRemove(INT nIndex)
|
||||
{
|
||||
HeapFree(hHeap,0,ppszFiles[nIndex]); // free entry
|
||||
|
||||
for (; nIndex < nEntry - 1; ++nIndex) // move old entries 1 line up
|
||||
{
|
||||
ppszFiles[nIndex] = ppszFiles[nIndex+1];
|
||||
}
|
||||
|
||||
ppszFiles[nIndex] = NULL; // clear last line
|
||||
|
||||
MruUpdateMenu(); // update menu
|
||||
return;
|
||||
}
|
||||
|
||||
INT MruEntries(VOID)
|
||||
{
|
||||
return nEntry;
|
||||
}
|
||||
|
||||
LPCTSTR MruFilename(INT nIndex)
|
||||
{
|
||||
_ASSERT(ppszFiles != NULL); // MRU not initialized
|
||||
_ASSERT(nIndex >= 0 && nIndex < nEntry); // inside range
|
||||
return ppszFiles[nIndex];
|
||||
}
|
||||
|
||||
VOID MruUpdateMenu(VOID)
|
||||
{
|
||||
TCHAR szCurPath[MAX_PATH];
|
||||
HANDLE hMenu;
|
||||
BOOL bEmpty;
|
||||
INT i;
|
||||
|
||||
if (nEntry == 0) return; // no entries
|
||||
|
||||
_ASSERT(ppszFiles != NULL); // MRU not initialized
|
||||
_ASSERT(hWnd != NULL);
|
||||
VERIFY(hMenu = GetMenu(hWnd)); // main menu
|
||||
|
||||
bEmpty = TRUE; // MRU list empty
|
||||
for (i = 0; i < nEntry; ++i) // delete all menu entries
|
||||
{
|
||||
DeleteMenu(hMenu,ID_FILE_MRU_FILE1+i,MF_BYCOMMAND);
|
||||
|
||||
if (ppszFiles[i] != NULL) // valid entry
|
||||
bEmpty = FALSE; // MRU list not empty
|
||||
}
|
||||
|
||||
if (bEmpty) // empty MRU list
|
||||
{
|
||||
// fill with orginal string
|
||||
VERIFY(InsertMenu(hMruMenu,nMruPos,MF_STRING|MF_BYPOSITION|MF_GRAYED,ID_FILE_MRU_FILE1,szOriginal));
|
||||
return;
|
||||
}
|
||||
|
||||
// current directory
|
||||
GetCurrentDirectory(ARRAYSIZEOF(szCurPath),szCurPath);
|
||||
|
||||
for (i = 0; i < nEntry; ++i) // add menu entries
|
||||
{
|
||||
if (ppszFiles[i] != NULL) // valid entry
|
||||
{
|
||||
TCHAR szMenuname[2*MAX_PATH+3];
|
||||
TCHAR szFilename[MAX_PATH];
|
||||
LPTSTR lpFilePart,lpszPtr;
|
||||
|
||||
// check if file path and current path is identical
|
||||
if (GetFullPathName(ppszFiles[i],ARRAYSIZEOF(szFilename),szFilename,&lpFilePart))
|
||||
{
|
||||
TCHAR szCutname[MAX_PATH];
|
||||
|
||||
*(lpFilePart-1) = 0; // devide path and name
|
||||
|
||||
// name is current directory -> use only name
|
||||
if (lstrcmpi(szCurPath,szFilename) == 0)
|
||||
{
|
||||
// short name view
|
||||
}
|
||||
else
|
||||
{
|
||||
// full name view
|
||||
lpFilePart = ppszFiles[i];
|
||||
}
|
||||
|
||||
// cut filename to fit into menu
|
||||
GetCutPathName(lpFilePart,szCutname,ARRAYSIZEOF(szCutname),36);
|
||||
lpFilePart = szCutname;
|
||||
|
||||
lpszPtr = szMenuname; // adding accelerator key
|
||||
*lpszPtr++ = _T('&');
|
||||
*lpszPtr++ = _T('0') + ((i + 1) % 10);
|
||||
*lpszPtr++ = _T(' ');
|
||||
|
||||
// copy file to view buffer and expand & to &&
|
||||
while (*lpFilePart != 0)
|
||||
{
|
||||
if (*lpFilePart == _T('&'))
|
||||
{
|
||||
*lpszPtr++ = *lpFilePart;
|
||||
}
|
||||
*lpszPtr++ = *lpFilePart++;
|
||||
}
|
||||
*lpszPtr = 0;
|
||||
|
||||
VERIFY(InsertMenu(hMruMenu,nMruPos+i,MF_STRING|MF_BYPOSITION,ID_FILE_MRU_FILE1+i,szMenuname));
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
VOID MruWriteList(VOID)
|
||||
{
|
||||
TCHAR szItemname[32];
|
||||
INT i;
|
||||
|
||||
// no. of files in MRU list
|
||||
WriteSettingsInt(_T("MRU"),_T("FileCount"),nEntry);
|
||||
|
||||
for (i = 0; i < nEntry; ++i) // add menu entries
|
||||
{
|
||||
_ASSERT(ppszFiles != NULL); // MRU not initialized
|
||||
wsprintf(szItemname,_T("File%d"),i+1);
|
||||
if (ppszFiles[i] != NULL)
|
||||
{
|
||||
WriteSettingsString(_T("MRU"),szItemname,ppszFiles[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
DelSettingsKey(_T("MRU"),szItemname);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
VOID MruReadList(VOID)
|
||||
{
|
||||
TCHAR szFilename[MAX_PATH];
|
||||
TCHAR szItemname[32];
|
||||
LPTSTR lpszValue;
|
||||
INT i;
|
||||
|
||||
_ASSERT(ppszFiles != NULL); // MRU not initialized
|
||||
|
||||
for (i = 0; i < nEntry; ++i) // add menu entries
|
||||
{
|
||||
wsprintf(szItemname,_T("File%d"),i+1);
|
||||
ReadSettingsString(_T("MRU"),szItemname,_T(""),szFilename,ARRAYSIZEOF(szFilename));
|
||||
|
||||
if (ppszFiles[i] != NULL) // already filled
|
||||
{
|
||||
HeapFree(hHeap,0,ppszFiles[i]); // free entry
|
||||
ppszFiles[i] = NULL; // clear last line
|
||||
lpszValue = _T("");
|
||||
}
|
||||
|
||||
if (*szFilename) // read a valid entry
|
||||
{
|
||||
ppszFiles[i] = DuplicateString(szFilename);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
|
@ -26,6 +26,10 @@
|
|||
#endif // _DEBUG
|
||||
#endif // _VERIFY
|
||||
|
||||
#if !defined INVALID_SET_FILE_POINTER
|
||||
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
|
||||
#endif
|
||||
|
||||
#if !defined IDC_HAND // Win2k specific definition
|
||||
#define IDC_HAND MAKEINTRESOURCE(32649)
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Microsoft Developer Studio generated include file.
|
||||
// Used by Emu48.rc
|
||||
//
|
||||
#define IDM_DEBUG_SETTINGS 0x0010
|
||||
#define IDI_EMU48 100
|
||||
#define IDR_MENU 101
|
||||
#define IDR_DEBUG 102
|
||||
|
@ -25,6 +26,7 @@
|
|||
#define IDD_FIND 120
|
||||
#define IDD_PROFILE 121
|
||||
#define IDD_MACROSET 122
|
||||
#define IDD_DEBUG_SETTINGS 123
|
||||
#define IDC_REALSPEED 1000
|
||||
#define IDC_GRAYSCALE 1001
|
||||
#define IDC_ALWAYSONTOP 1002
|
||||
|
@ -150,6 +152,10 @@
|
|||
#define IDC_SOUND_SLIDER 1122
|
||||
#define IDC_SOUND_SPEAKER 1123
|
||||
#define IDC_SOUND_WAVE 1124
|
||||
#define IDC_DEBUG_SET_SYMB 1125
|
||||
#define IDC_DEBUG_SET_MODEL 1126
|
||||
#define IDC_DEBUG_SET_FILE 1227
|
||||
#define IDC_DEBUG_SET_BROWSE 1228
|
||||
#define ID_FILE_NEW 40001
|
||||
#define ID_FILE_OPEN 40002
|
||||
#define ID_FILE_SAVE 40003
|
||||
|
@ -220,9 +226,9 @@
|
|||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 123
|
||||
#define _APS_NEXT_RESOURCE_VALUE 124
|
||||
#define _APS_NEXT_COMMAND_VALUE 40067
|
||||
#define _APS_NEXT_CONTROL_VALUE 1125
|
||||
#define _APS_NEXT_CONTROL_VALUE 1129
|
||||
#define _APS_NEXT_SYMED_VALUE 108
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
#define DOMINIFONT 0x026FE // Mini Font (HP49G)
|
||||
#define DOBINT 0x02911 // System Binary
|
||||
#define DOREAL 0x02933 // Real
|
||||
#define DOEREAL 0x02955 // Long Real
|
||||
#define DOEREL 0x02955 // Long Real
|
||||
#define DOCMP 0x02977 // Complex
|
||||
#define DOECMP 0x0299D // Long Complex
|
||||
#define DOCHAR 0x029BF // Character
|
||||
|
@ -154,7 +154,7 @@ DWORD RPL_SkipOb(DWORD d)
|
|||
case DOFLASHP: l = (cCurrentRomType!='X' && cCurrentRomType!='2' && cCurrentRomType!='Q') ? 5 : 12; break; // Flash PTR (HP49G) // CdB for HP: add apples
|
||||
case DOBINT: l = 10; break; // System Binary
|
||||
case DOREAL: l = 21; break; // Real
|
||||
case DOEREAL: l = 26; break; // Long Real
|
||||
case DOEREL: l = 26; break; // Long Real
|
||||
case DOCMP: l = 37; break; // Complex
|
||||
case DOECMP: l = 47; break; // Long Complex
|
||||
case DOCHAR: l = 7; break; // Character
|
||||
|
@ -260,7 +260,7 @@ DWORD RPL_ObjectSize(BYTE *o,DWORD s)
|
|||
case DOFLASHP: l = (SERIES49) ? 12 : 5; break; // Flash PTR (HP49G)
|
||||
case DOBINT: l = 10; break; // System Binary
|
||||
case DOREAL: l = 21; break; // Real
|
||||
case DOEREAL: l = 26; break; // Long Real
|
||||
case DOEREL: l = 26; break; // Long Real
|
||||
case DOCMP: l = 37; break; // Complex
|
||||
case DOECMP: l = 47; break; // Long Complex
|
||||
case DOCHAR: l = 7; break; // Character
|
||||
|
|
|
@ -176,6 +176,7 @@ VOID ReadSettings(VOID)
|
|||
bAlwaysDisplayLog = ReadInt(_T("KML"),_T("AlwaysDisplayLog"),bAlwaysDisplayLog);
|
||||
// Disassembler
|
||||
disassembler_mode = ReadInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode);
|
||||
disassembler_symb = ReadInt(_T("Disassembler"),_T("Symbolic"),disassembler_symb);
|
||||
// Emulator
|
||||
bAlwaysOnTop = ReadInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop);
|
||||
bActFollowsMouse = ReadInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse);
|
||||
|
@ -216,6 +217,7 @@ VOID WriteSettings(VOID)
|
|||
WriteInt(_T("KML"),_T("AlwaysDisplayLog"),bAlwaysDisplayLog);
|
||||
// Disassembler
|
||||
WriteInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode);
|
||||
WriteInt(_T("Disassembler"),_T("Symbolic"),disassembler_symb);
|
||||
// Emulator
|
||||
WriteInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop);
|
||||
WriteInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse);
|
||||
|
|
|
@ -527,10 +527,11 @@ LRESULT OnStackPaste(VOID) // paste data to stack
|
|||
if (!(Chipset.IORam[BITOFFSET]&DON))
|
||||
{
|
||||
KeyboardEvent(TRUE,0,0x8000);
|
||||
Sleep(200);
|
||||
KeyboardEvent(FALSE,0,0x8000);
|
||||
|
||||
// wait for sleep mode
|
||||
while(Chipset.Shutdn == FALSE) Sleep(0);
|
||||
while (Chipset.Shutdn == FALSE) Sleep(0);
|
||||
}
|
||||
|
||||
_ASSERT(nState == SM_RUN); // emulator must be in RUN state
|
||||
|
|
Loading…
Reference in a new issue