2009-08-29: Updated to version 46

Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
This commit is contained in:
Gwenhael Le Moine 2024-03-20 07:46:28 +01:00
parent 34b7d141b8
commit af664bab5f
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
29 changed files with 2077 additions and 387 deletions

View file

@ -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

View file

@ -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/

View file

@ -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

Binary file not shown.

BIN
Emu48.exe

Binary file not shown.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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;
}
//################
//#

View file

@ -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;
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;
}
else
{
if (i > 10) // cursor near bottom line
{
dwAddress = dwAdrLine[i-10]; // move that pc is in line 11
i = 10; // set cursor to actual pc
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,6 +1672,11 @@ static __inline BOOL OnDrawCodeWnd(LPDRAWITEMSTRUCT lpdis)
// get item text
SendMessage(lpdis->hwndItem,LB_GETTEXT,lpdis->itemID,(LPARAM) szBuf);
// line is a label
bLabel = ((dwAdrLine[lpdis->itemID] & CODELABEL) != 0);
if (!bLabel)
{
// check for codebreakpoint
bBrk = CheckBreakpoint(dwAdrLine[lpdis->itemID],1,BP_EXEC);
bPC = szBuf[5] != _T(' '); // check if line of program counter
@ -1577,6 +1713,13 @@ static __inline BOOL OnDrawCodeWnd(LPDRAWITEMSTRUCT lpdis)
}
}
}
}
else // label
{
crBkColor = COLOR_WHITE;
crTextColor = COLOR_NAVY;
hFont = SelectObject(lpdis->hDC,hFontBold);
}
// write Text
crBkColor = SetBkColor(lpdis->hDC,crBkColor);
@ -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))
{
@ -1940,6 +2114,8 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
case VK_PRIOR:
case VK_DOWN:
case VK_UP: return OnKeyUpDown((HWND) lParam, wParam);
case VK_ADD:
case VK_SUBTRACT: return OnKeyPlusMinus((HWND) lParam, wParam);
}
break;
}
@ -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,6 +2759,11 @@ static INT_PTR CALLBACK EnterAddr(HWND hDlg, UINT message, WPARAM wParam, LPARAM
case IDOK:
hWnd = GetDlgItem(hDlg,IDC_ENTERADR);
GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer));
// if address is not a symbol name decode number
if ( !disassembler_symb || szBuffer[0] != _T('=')
|| RplGetAddr(&szBuffer[1],pdwAddress))
{
// test if valid hex address
for (i = 0; i < (LONG) lstrlen(szBuffer); ++i)
{
@ -2389,7 +2774,8 @@ static INT_PTR CALLBACK EnterAddr(HWND hDlg, UINT message, WPARAM wParam, LPARAM
return FALSE;
}
}
if (*szBuffer) _stscanf(szBuffer,_T("%6X"),dwAddress);
if (*szBuffer) _stscanf(szBuffer,_T("%6X"),pdwAddress);
}
// 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;
}

View file

@ -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);

View file

@ -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,7 +330,9 @@ 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)
{
@ -342,45 +347,84 @@ 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;
}
else
if (n == 5) // 5 nibble address
{
wsprintf (t, _T("%d"), read_nibble (addr));
buf = append_str (buf, t);
LPCTSTR lpszName;
if (disassembler_symb && (lpszName = RplGetName(dwAddr)) != NULL)
{
// overwrite number with symbolic name
buf = append_str(p, _T("="));
buf = append_str(buf, lpszName);
}
}
}
else // single nibble
{
buf += wsprintf (buf, _T("%d"), read_nibble (addr));
}
return buf;
}
static LPTSTR append_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;
*pc = (*pc + disp) & 0xFFFFF;
if (disassembler_symb && (lpszName = RplGetName(*pc)) != NULL)
{
buf = append_str(buf, _T("=")); // show symbol
buf = append_str(buf, lpszName);
}
else // no symbol
{
if (disp < 0)
{
buf = append_str(buf, _T("-"));
@ -391,44 +435,15 @@ static LPTSTR append_r_addr (LPTSTR buf, DWORD *pc, long disp, int n, int offset
buf = append_str(buf, _T("+"));
disp += offset;
}
buf = append_addr(buf, disp);
buf = append_numaddr(buf, disp); // show offset
buf = append_str(buf, _T(" ["));
buf = append_numaddr(buf, *pc); // show absolute address
buf = append_str(buf, _T("]"));
}
return buf;
}
static LPTSTR append_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)
{
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;
}
}
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;
}
static LPTSTR append_hst_bits (LPTSTR buf, int n)
{
int i;
@ -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;
}

View file

@ -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;

View file

@ -13,7 +13,7 @@
#include "kml.h"
#include "debugger.h"
#define VERSION "1.45+"
#define VERSION "1.46+"
// #define MONOCHROME // CF_BITMAP clipboard format
@ -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);
@ -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,7 +1193,7 @@ 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("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)
{
@ -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

View file

@ -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);

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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");
_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;
}
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;
}
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,38 +1576,55 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
return hpal;
}
HBITMAP LoadBitmapFile(LPCTSTR szFilename)
static HBITMAP DecodeBmp(LPBMPFILE pBmp)
{
HANDLE hFile;
HANDLE hMap;
LPBYTE pbyFile;
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
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)
{
CloseHandle(hMap);
CloseHandle(hFile);
return NULL;
}
HBITMAP hBitmap;
DWORD dwFileSize;
hBitmap = NULL;
pBmfh = (LPBITMAPFILEHEADER)pbyFile;
if (pBmfh->bfType != 0x4D42) goto quit; // "BM"
pBmi = (LPBITMAPINFO)(pbyFile+sizeof(BITMAPFILEHEADER));
// 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);
@ -1609,16 +1632,557 @@ HBITMAP LoadBitmapFile(LPCTSTR szFilename)
hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE);
RealizePalette(hWindowDC);
hBitmap = CreateDIBitmap(
hWindowDC,
&pBmi->bmiHeader,
CBM_INIT,
pbyFile + pBmfh->bfOffBits,
pBmi, DIB_RGB_COLORS);
_ASSERT(hBitmap != NULL);
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:
UnmapViewOfFile(pbyFile);
if (hBitmap != NULL && bDecoding) // creation failed
{
DeleteObject(hBitmap); // delete bitmap
hBitmap = NULL;
}
return hBitmap;
}
HBITMAP LoadBitmapFile(LPCTSTR szFilename)
{
HANDLE hFile;
HANDLE hMap;
BMPFILE Bmp;
HBITMAP hBitmap;
SetCurrentDirectory(szEmuDirectory);
hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
SetCurrentDirectory(szCurrentDirectory);
if (hFile == INVALID_HANDLE_VALUE) return NULL;
Bmp.dwFileSize = GetFileSize(hFile, NULL);
hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMap == NULL)
{
CloseHandle(hFile);
return NULL;
}
Bmp.pbyFile = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if (Bmp.pbyFile == NULL)
{
CloseHandle(hMap);
CloseHandle(hFile);
return NULL;
}
do
{
// check for bitmap file header "BM"
if (Bmp.dwFileSize >= 2 && *(WORD *) Bmp.pbyFile == 0x4D42)
{
hBitmap = DecodeBmp(&Bmp);
break;
}
// check for GIF file header
if ( Bmp.dwFileSize >= 6
&& (memcmp(Bmp.pbyFile,"GIF87a",6) == 0 || memcmp(Bmp.pbyFile,"GIF89a",6) == 0))
{
hBitmap = DecodeGif(&Bmp);
break;
}
// unknown file type
hBitmap = NULL;
}
while (FALSE);
UnmapViewOfFile(Bmp.pbyFile);
CloseHandle(hMap);
CloseHandle(hFile);
return hBitmap;

View file

@ -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,7 +1239,9 @@ 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;
@ -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

View file

@ -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
View 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;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -527,6 +527,7 @@ 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