2008-05-11: Updated to version 1.47

Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
This commit is contained in:
Gwenhael Le Moine 2024-03-19 23:35:29 +01:00
parent 87da7ee0dd
commit 8fe52143cf
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
31 changed files with 389 additions and 241 deletions

BIN
EMU48.EXE

Binary file not shown.

View file

@ -474,4 +474,4 @@ E-Mail:
c dot giesselink at gmx dot de c dot giesselink at gmx dot de
Homepage: Homepage:
http://privat.swol.de/ChristophGiesselink/index.htm http://hp.giesselink.com/index.htm

View file

@ -1,4 +1,4 @@
Known bugs and restrictions of Emu48 V1.45 Known bugs and restrictions of Emu48 V1.47
------------------------------------------ ------------------------------------------
- the following I/O bits aren't emulated (incomplete) - the following I/O bits aren't emulated (incomplete)
@ -53,4 +53,4 @@ Known bugs and restrictions of Emu48 V1.45
- quitting the emulator while programming the flash isn't allowed, - quitting the emulator while programming the flash isn't allowed,
because the content of flash state machine isn't saved so far because the content of flash state machine isn't saved so far
08/07/07 (c) by Christoph Gießelink, c dot giesselink at gmx dot de 04/21/07 (c) by Christoph Gießelink, c dot giesselink at gmx dot de

View file

@ -1,3 +1,108 @@
Service Pack 47 for Emu48 Version 1.0
DDESERV.C
- bugfix in function DdeCallback(), readded delay after ON key state
change, bug introduced in SP37
DEBUGGER.C
- changed function OnLButtonUp(), NewValue(), EnterAddr() and
EnterBreakpoint(), replaced WM_GETTEXT message call with function
GetWindowText()
DISASM.C
- bugfix in function disassemble(), the NOP5 opcode returned wrong
address for next instruction (GOTO opcode skipping one nibble)
EMU48.C
- changed function SettingsProc(), adjusted to new prototype of
function GetLoadObjectFilename(), use (*.BIN) as default file
filter now
- changed function OnPaint(), removed mixture of BitBlt() calls with
argument hPaintDC and hWindowDC inside critical section
- changed function OnFileClose(), removed call of DisableDebugger()
because it's now done in function ResetDocument()
- bugfix in function OnDropFiles() and OnObjectLoad(), readded delay
after ON key state change, bug introduced in SP37
- changed function OnObjectLoad() and OnObjectSave(), adjusted to
new prototype of function GetLoadObjectFilename() and
GetSaveObjectFilename(), use (*.HP;*.LIB) as default file filter
now
EMU48.H
- added file filter definitions
- extern declaration of global variable and function
- changed function prototypes
EMU48.RC
- changed name order in copyright messages
- changed version and copyright
EXTERNAL.C
- removed inline function Return(), replaced by a rstkpop() call
- added function Beeper() for beeping without taking care about
the different beeping methods
- added function RCKBp() simulating the ROM Check Beep
FILES.C
- changed function ResetDocument(), added call of DisableDebugger()
- changed function GetOpenFilename() and GetSaveAsFilename(),
removed some NULL characters at end of file filter definition
string
- changed function GetLoadObjectFilename() and
GetSaveObjectFilename(), changed function prototype, added
arguments for the file filter and the default extention
I28F160.C
- adjusted implementation to the new bit array of the block lock
table
I28F160.H
- changed structure WSMset_t, replaced byte array byLockCnfg[32]
with the bit array dwLockCnfg variable
KEYMACRO.C
- changed function OnToolMacroNew() and OnToolMacroPlay(), removed
some NULL characters at end of file filter definition string
KML.C
- changed function GetStringOf(), changed for better reading
- changed function SkipWhite(), optimized and better readable
implementation
- bugfix in function ParseToken(), optimized string delimeter
searching among other optimizations and removed increment of line
counter on LF character to correct the line numbering on UNIX
files with LF instead of CR LF at line end -> line counter
increment is done in function SkipWhite() on decoding next keyword
in function Lex()
- changed function ParseLine(), replaced main loop "goto" construct
LOWBAT.C
- bugfix in function StartBatMeasure(), creating the battery
watching thread wasn't Win9x compatible
- changed function GetBatteryState(), added possibility to disable
low battery detection
SETTINGS.C
- changed function ReadSettings() and WriteSettings(), added item
"Disable" in section [LowBat] in the INI-File
STACK.C
- bugfix in function OnStackPaste(), readded delay after ON key
state change, bug introduced in SP37
Service Pack 46 for Emu48 Version 1.0
EMU48.C
- bugfix in function SaveChanges(), returned wrong ID when function
GetSaveAsFilename() returned FALSE, bug introduced in SP45
- bugfix in function WinMain(), in some cases only file short names
had been written as last document
EMU48.RC
- changed version
Service Pack 45 for Emu48 Version 1.0 Service Pack 45 for Emu48 Version 1.0
EMU48.C EMU48.C
@ -87,9 +192,9 @@ EMU48.C
handler handler
- bugfix in function WinMain(), moved additional DDE stuff just - bugfix in function WinMain(), moved additional DDE stuff just
behind DDE server initialization, added StartupBackup handling, behind DDE server initialization, added StartupBackup handling,
adjusted length for cutted filenames preventing negative values adjusted length for cut filenames preventing negative values and
and call ShowWindow() before asking for a new document preventing call ShowWindow() before asking for a new document preventing a
a KML script dialog without a parent window KML script dialog without a parent window
EMU48.H EMU48.H
- removed declaration of bClassicCursor - removed declaration of bClassicCursor
@ -106,7 +211,7 @@ FILES.C
- added global variables holding the patched ROM checksum and the - added global variables holding the patched ROM checksum and the
port2 CRC port2 CRC
- changed function GetCutPathName(), better support for UNC names - changed function GetCutPathName(), better support for UNC names
- changed function SetWindowPathTitle(), adjusted length for cutted - changed function SetWindowPathTitle(), adjusted length for cut
filename filename
- changed function CrcRom(), change function prototype, added - changed function CrcRom(), change function prototype, added
unpacked data check and made function public unpacked data check and made function public
@ -489,7 +594,7 @@ EMU48.RC
ENGINE.C ENGINE.C
- bugfix in function WorkerThread(), when changing into SM_RUN state - bugfix in function WorkerThread(), when changing into SM_RUN state
display constrast must also be restored display contrast must also be restored
FILES.C FILES.C
- changed function CrcPort2(), made it global accessible - changed function CrcPort2(), made it global accessible
@ -520,7 +625,7 @@ RPL.C
SETTINGS.C SETTINGS.C
- changed function ReadSettings() and WriteSettings(), added item - changed function ReadSettings() and WriteSettings(), added item
"SaveDefaultConfirm" in section [File] in the INI-File "SaveDefaultConfirm" in section [Files] in the INI-File
STACK.C STACK.C
- added helper functions RPL_GetZInt() and RPL_SetZInt() to handle - added helper functions RPL_GetZInt() and RPL_SetZInt() to handle

View file

@ -92,9 +92,10 @@ HDDEDATA CALLBACK DdeCallback(UINT iType,UINT iFmt,HCONV hConv,
} }
KeyboardEvent(TRUE,0,0x8000); KeyboardEvent(TRUE,0,0x8000);
Sleep(200);
KeyboardEvent(FALSE,0,0x8000); KeyboardEvent(FALSE,0,0x8000);
// wait for sleep mode // wait for sleep mode
while(Chipset.Shutdn == FALSE) Sleep(0); while (Chipset.Shutdn == FALSE) Sleep(0);
hReturn = (HDDEDATA) DDE_FACK; hReturn = (HDDEDATA) DDE_FACK;
cancel: cancel:

View file

@ -1183,7 +1183,7 @@ static BOOL OnLButtonUp(HWND hDlg, LPARAM lParam)
hWnd = ChildWindowFromPointEx(hDlg,pt,CWP_SKIPDISABLED); hWnd = ChildWindowFromPointEx(hDlg,pt,CWP_SKIPDISABLED);
nId = GetDlgCtrlID(hWnd); // control ID of window nId = GetDlgCtrlID(hWnd); // control ID of window
SendMessage(hWnd,WM_GETTEXT,ARRAYSIZEOF(szBuffer),(LPARAM)szBuffer); GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer));
switch (nId) switch (nId)
{ {
case IDC_REG_A: // A case IDC_REG_A: // A
@ -1943,7 +1943,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
case WM_NOTIFY: case WM_NOTIFY:
// tooltip for toolbar // tooltip for toolbar
if(((LPNMHDR) lParam)->code == TTN_GETDISPINFO) if (((LPNMHDR) lParam)->code == TTN_GETDISPINFO)
{ {
((LPTOOLTIPTEXT) lParam)->hinst = hApp; ((LPTOOLTIPTEXT) lParam)->hinst = hApp;
((LPTOOLTIPTEXT) lParam)->lpszText = MAKEINTRESOURCE(((LPTOOLTIPTEXT) lParam)->hdr.idFrom); ((LPTOOLTIPTEXT) lParam)->lpszText = MAKEINTRESOURCE(((LPTOOLTIPTEXT) lParam)->hdr.idFrom);
@ -2281,7 +2281,7 @@ static INT_PTR CALLBACK NewValue(HWND hDlg, UINT message, WPARAM wParam, LPARAM
{ {
case IDOK: case IDOK:
hWnd = GetDlgItem(hDlg,IDC_NEWVALUE); hWnd = GetDlgItem(hDlg,IDC_NEWVALUE);
SendMessage(hWnd,WM_GETTEXT,(WPARAM)nBufferlen,(LPARAM)szBuffer); GetWindowText(hWnd,szBuffer,nBufferlen);
// test if valid hex address // test if valid hex address
for (i = 0; i < (LONG) lstrlen(szBuffer); ++i) for (i = 0; i < (LONG) lstrlen(szBuffer); ++i)
{ {
@ -2346,7 +2346,7 @@ static INT_PTR CALLBACK EnterAddr(HWND hDlg, UINT message, WPARAM wParam, LPARAM
{ {
case IDOK: case IDOK:
hWnd = GetDlgItem(hDlg,IDC_ENTERADR); hWnd = GetDlgItem(hDlg,IDC_ENTERADR);
SendMessage(hWnd,WM_GETTEXT,8,(LPARAM)szBuffer); GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer));
// test if valid hex address // test if valid hex address
for (i = 0; i < (LONG) lstrlen(szBuffer); ++i) for (i = 0; i < (LONG) lstrlen(szBuffer); ++i)
{ {
@ -2411,7 +2411,7 @@ static INT_PTR CALLBACK EnterBreakpoint(HWND hDlg, UINT message, WPARAM wParam,
case IDC_BPWRITE: sBp->nType = BP_WRITE; return TRUE; case IDC_BPWRITE: sBp->nType = BP_WRITE; return TRUE;
case IDOK: case IDOK:
hWnd = GetDlgItem(hDlg,IDC_ENTERADR); hWnd = GetDlgItem(hDlg,IDC_ENTERADR);
SendMessage(hWnd,WM_GETTEXT,8,(LPARAM)szBuffer); GetWindowText(hWnd,szBuffer,ARRAYSIZEOF(szBuffer));
// test if valid hex address // test if valid hex address
for (i = 0; i < (LONG) lstrlen(szBuffer); ++i) for (i = 0; i < (LONG) lstrlen(szBuffer); ++i)
{ {
@ -2690,7 +2690,7 @@ static INT_PTR CALLBACK EditBreakpoint(HWND hDlg, UINT message, WPARAM wParam, L
} }
case WM_VKEYTOITEM: case WM_VKEYTOITEM:
if(LOWORD(wParam) == VK_SPACE) if (LOWORD(wParam) == VK_SPACE)
{ {
hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND); hWnd = GetDlgItem(hDlg,IDC_BREAKEDIT_WND);
for (nItem = 0; nItem < wBreakpointCount; ++nItem) for (nItem = 0; nItem < wBreakpointCount; ++nItem)
@ -2858,7 +2858,7 @@ VOID LoadBreakpointList(HANDLE hFile) // NULL = clear breakpoint list
// read number of breakpoints // read number of breakpoints
if (hFile) ReadFile(hFile, &wBreakpointCount, sizeof(wBreakpointCount), &lBytesRead, NULL); if (hFile) ReadFile(hFile, &wBreakpointCount, sizeof(wBreakpointCount), &lBytesRead, NULL);
if(lBytesRead) // breakpoints found if (lBytesRead) // breakpoints found
{ {
WORD wBreakpointSize; WORD wBreakpointSize;

View file

@ -1508,17 +1508,18 @@ DWORD disassemble (DWORD addr, LPTSTR out, BOOL view)
case 6: case 6:
pc = addr; pc = addr;
disp = read_int (&addr, 3); disp = read_int (&addr, 3); // read GOTO distance
switch (disassembler_mode) switch (disassembler_mode)
{ {
case HP_MNEMONICS: case HP_MNEMONICS:
if (disp == 3) if (disp == 3) // special case "GOTO next instruction"
{ {
p = append_str (out, _T("NOP4")); p = append_str (out, _T("NOP4"));
break; break;
} }
if (disp == 4) if (disp == 4) // special case "GOTO to +4 nibbles"
{ {
addr++; // skipping the fifth nibble in the opcode
p = append_str (out, _T("NOP5")); p = append_str (out, _T("NOP5"));
break; break;
} }
@ -1536,6 +1537,7 @@ DWORD disassemble (DWORD addr, LPTSTR out, BOOL view)
} }
if (disp == 4) if (disp == 4)
{ {
addr++; // skipping the fifth nibble in the opcode
p = append_str (out, _T("nop5")); p = append_str (out, _T("nop5"));
break; break;
} }

View file

@ -209,8 +209,8 @@ VOID DestroyLcdBitmap(VOID)
{ {
// set contrast palette to startup colors // set contrast palette to startup colors
WORD i = 0; dwKMLColor[i++] = W; WORD i = 0; dwKMLColor[i++] = W;
while(i < 32) dwKMLColor[i++] = B; while (i < 32) dwKMLColor[i++] = B;
while(i < 64) dwKMLColor[i++] = I; while (i < 64) dwKMLColor[i++] = I;
GetLineCounter = NULL; GetLineCounter = NULL;
StartDisplay = NULL; StartDisplay = NULL;

View file

@ -13,7 +13,7 @@
#include "kml.h" #include "kml.h"
#include "debugger.h" #include "debugger.h"
#define VERSION "1.45" #define VERSION "1.47"
// #define MONOCHROME // CF_BITMAP clipboard format // #define MONOCHROME // CF_BITMAP clipboard format
@ -296,7 +296,7 @@ static VOID SetCommList(HWND hDlg,LPCTSTR szWireSetting,LPCTSTR szIrSetting)
// test if COM port is valid // test if COM port is valid
hComm = CreateFile(szBuffer,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); hComm = CreateFile(szBuffer,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
if(hComm != INVALID_HANDLE_VALUE) if (hComm != INVALID_HANDLE_VALUE)
{ {
VERIFY(CloseHandle(hComm)); VERIFY(CloseHandle(hComm));
bAddWire = bAddIr = TRUE; bAddWire = bAddIr = TRUE;
@ -420,7 +420,7 @@ static INT_PTR CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPA
EnableWindow(GetDlgItem(hDlg,IDC_SOUND_SLIDER),TRUE); EnableWindow(GetDlgItem(hDlg,IDC_SOUND_SLIDER),TRUE);
return TRUE; return TRUE;
case IDC_PORT2LOAD: case IDC_PORT2LOAD:
if (GetLoadObjectFilename()) if (GetLoadObjectFilename(_T(BIN_FILTER),_T("BIN")))
{ {
TCHAR szFilename[MAX_PATH]; TCHAR szFilename[MAX_PATH];
LPTSTR lpFilePart; LPTSTR lpFilePart;
@ -469,7 +469,7 @@ static INT_PTR CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPA
SwitchToState(nOldState); SwitchToState(nOldState);
} }
// HP48SX/GX port2 change settings detection // HP48SX/GX port2 change settings detection
if(cCurrentRomType=='S' || cCurrentRomType=='G' || cCurrentRomType==0) if (cCurrentRomType=='S' || cCurrentRomType=='G' || cCurrentRomType==0)
{ {
TCHAR szFilename[MAX_PATH]; TCHAR szFilename[MAX_PATH];
BOOL bOldPort2IsShared = bPort2IsShared; BOOL bOldPort2IsShared = bPort2IsShared;
@ -623,9 +623,10 @@ static UINT SaveChanges(BOOL bAuto)
{ {
if (SaveDocumentAs(szBufferFilename)) if (SaveDocumentAs(szBufferFilename))
return IDYES; return IDYES;
// error on saving file else
return IDCANCEL;
} }
return IDCANCEL; return IDNO;
} }
SaveDocument(); SaveDocument();
@ -731,12 +732,15 @@ static LRESULT OnPaint(HWND hWindow)
BitBlt(hPaintDC, Paint.rcPaint.left, Paint.rcPaint.top, BitBlt(hPaintDC, Paint.rcPaint.left, Paint.rcPaint.top,
Paint.rcPaint.right-Paint.rcPaint.left, Paint.rcPaint.bottom-Paint.rcPaint.top, Paint.rcPaint.right-Paint.rcPaint.left, Paint.rcPaint.bottom-Paint.rcPaint.top,
hMainDC, rcMainPaint.left, rcMainPaint.top, SRCCOPY); hMainDC, rcMainPaint.left, rcMainPaint.top, SRCCOPY);
SetWindowOrgEx(hPaintDC, nBackgroundX, nBackgroundY, NULL);
// redraw main display area // redraw main display area
BitBlt(hWindowDC, nLcdX, nLcdY, BitBlt(hPaintDC, nLcdX, nLcdY,
131*nLcdZoom, nLines*nLcdZoom, 131*nLcdZoom, nLines*nLcdZoom,
hLcdDC, Chipset.boffset*nLcdZoom, 0, SRCCOPY); hLcdDC, Chipset.boffset*nLcdZoom, 0, SRCCOPY);
// redraw menu display area // redraw menu display area
BitBlt(hWindowDC, nLcdX, nLcdY+nLines*nLcdZoom, BitBlt(hPaintDC, nLcdX, nLcdY+nLines*nLcdZoom,
131*nLcdZoom, (64-nLines)*nLcdZoom, 131*nLcdZoom, (64-nLines)*nLcdZoom,
hLcdDC, 0, nLines*nLcdZoom, SRCCOPY); hLcdDC, 0, nLines*nLcdZoom, SRCCOPY);
GdiFlush(); GdiFlush();
@ -801,6 +805,7 @@ static LRESULT OnDropFiles(HANDLE hFilesInfo)
goto cancel; goto cancel;
KeyboardEvent(TRUE,0,0x8000); KeyboardEvent(TRUE,0,0x8000);
Sleep(200);
KeyboardEvent(FALSE,0,0x8000); KeyboardEvent(FALSE,0,0x8000);
// wait for sleep mode // wait for sleep mode
while (Chipset.Shutdn == FALSE) Sleep(0); while (Chipset.Shutdn == FALSE) Sleep(0);
@ -915,9 +920,8 @@ static LRESULT OnFileClose(VOID)
{ {
if (pbyRom == NULL) return 0; if (pbyRom == NULL) return 0;
SwitchToState(SM_INVALID); SwitchToState(SM_INVALID);
if (SaveChanges(bAutoSave)!=IDCANCEL) if (SaveChanges(bAutoSave) != IDCANCEL)
{ {
DisableDebugger();
ResetDocument(); ResetDocument();
SetWindowTitle(NULL); SetWindowTitle(NULL);
} }
@ -1106,7 +1110,7 @@ static LRESULT OnViewScript(VOID)
{ {
if (!DisplayChooseKml(cType)) break; if (!DisplayChooseKml(cType)) break;
} }
while(!InitKML(szCurrentKml,FALSE)); while (!InitKML(szCurrentKml,FALSE));
SetWindowPathTitle(szCurrentFilename); // update window title line SetWindowPathTitle(szCurrentFilename); // update window title line
if (pbyRom) SwitchToState(SM_RUN); if (pbyRom) SwitchToState(SM_RUN);
@ -1198,7 +1202,7 @@ static LRESULT OnObjectLoad(VOID)
} }
} }
if (!GetLoadObjectFilename()) if (!GetLoadObjectFilename(_T(HP_FILTER),_T("HP")))
{ {
SwitchToState(SM_RUN); SwitchToState(SM_RUN);
goto cancel; goto cancel;
@ -1214,6 +1218,7 @@ static LRESULT OnObjectLoad(VOID)
while (nState!=nNextState) Sleep(0); while (nState!=nNextState) Sleep(0);
_ASSERT(nState == SM_RUN); _ASSERT(nState == SM_RUN);
KeyboardEvent(TRUE,0,0x8000); KeyboardEvent(TRUE,0,0x8000);
Sleep(200);
KeyboardEvent(FALSE,0,0x8000); KeyboardEvent(FALSE,0,0x8000);
while (Chipset.Shutdn == FALSE) Sleep(0); while (Chipset.Shutdn == FALSE) Sleep(0);
@ -1242,7 +1247,7 @@ static LRESULT OnObjectSave(VOID)
_ASSERT(nState == SM_SLEEP); _ASSERT(nState == SM_SLEEP);
if (GetSaveObjectFilename()) if (GetSaveObjectFilename(_T(HP_FILTER),_T("HP")))
{ {
SaveObject(szBufferFilename); SaveObject(szBufferFilename);
} }
@ -1532,6 +1537,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
HACCEL hAccel; HACCEL hAccel;
HSZ hszService, hszTopic; // variables for DDE server HSZ hszService, hszTopic; // variables for DDE server
DWORD_PTR dwAffMask; DWORD_PTR dwAffMask;
LPTSTR lpFilePart;
hApp = hInst; hApp = hInst;
#if defined _UNICODE #if defined _UNICODE
@ -1668,7 +1674,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
SetWindowTitle(szTemp); SetWindowTitle(szTemp);
if (OpenDocument(szBufferFilename)) if (OpenDocument(szBufferFilename))
{ {
MruAdd(szBufferFilename); MruAdd(szCurrentFilename);
ShowWindow(hWnd,nCmdShow); ShowWindow(hWnd,nCmdShow);
goto start; goto start;
} }
@ -1686,10 +1692,10 @@ start:
while (GetMessage(&msg, NULL, 0, 0)) while (GetMessage(&msg, NULL, 0, 0))
{ {
if( !TranslateAccelerator(hWnd, hAccel, &msg) if ( !TranslateAccelerator(hWnd, hAccel, &msg)
&& (hDlgDebug == NULL || !IsDialogMessage(hDlgDebug, &msg)) && (hDlgDebug == NULL || !IsDialogMessage(hDlgDebug, &msg))
&& (hDlgFind == NULL || !IsDialogMessage(hDlgFind, &msg)) && (hDlgFind == NULL || !IsDialogMessage(hDlgFind, &msg))
&& (hDlgProfile == NULL || !IsDialogMessage(hDlgProfile, &msg))) && (hDlgProfile == NULL || !IsDialogMessage(hDlgProfile, &msg)))
{ {
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
@ -1702,7 +1708,10 @@ start:
DdeFreeStringHandle(idDdeInst, hszTopic); DdeFreeStringHandle(idDdeInst, hszTopic);
DdeUninitialize(idDdeInst); DdeUninitialize(idDdeInst);
WriteLastDocument(szCurrentFilename); // save last document setting // get full path name of szCurrentFilename
GetFullPathName(szCurrentFilename,ARRAYSIZEOF(szBufferFilename),szBufferFilename,&lpFilePart);
WriteLastDocument(szBufferFilename); // save last document setting
WriteSettings(); // save emulation settings WriteSettings(); // save emulation settings
CloseHandle(hThread); // close thread handle CloseHandle(hThread); // close thread handle

View file

@ -19,8 +19,11 @@
#define PORT2_PRESENT ((cCurrentRomType=='S')?P2C:P1C) #define PORT2_PRESENT ((cCurrentRomType=='S')?P2C:P1C)
#define PORT2_WRITE ((cCurrentRomType=='S')?P2W:P1W) #define PORT2_WRITE ((cCurrentRomType=='S')?P2W:P1W)
#define BINARYHEADER48 "HPHP48-W" #define BINARYHEADER48 "HPHP48-W"
#define BINARYHEADER49 "HPHP49-W" #define BINARYHEADER49 "HPHP49-W"
#define BIN_FILTER "Port Data File (*.BIN)\0*.BIN\0All Files (*.*)\0*.*\0"
#define HP_FILTER "HP Binary Object (*.HP;*.LIB)\0*.HP;*.LIB\0All Files (*.*)\0*.*\0"
#define CF_HPOBJ "CF_HPOBJ" // clipboard format for DDE #define CF_HPOBJ "CF_HPOBJ" // clipboard format for DDE
@ -249,8 +252,8 @@ extern BOOL RestoreBackup(VOID);
extern BOOL ResetBackup(VOID); extern BOOL ResetBackup(VOID);
extern BOOL GetOpenFilename(VOID); extern BOOL GetOpenFilename(VOID);
extern BOOL GetSaveAsFilename(VOID); extern BOOL GetSaveAsFilename(VOID);
extern BOOL GetLoadObjectFilename(VOID); extern BOOL GetLoadObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt);
extern BOOL GetSaveObjectFilename(VOID); extern BOOL GetSaveObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt);
extern WORD WriteStack(UINT nStkLevel,LPBYTE lpBuf,DWORD dwSize); extern WORD WriteStack(UINT nStkLevel,LPBYTE lpBuf,DWORD dwSize);
extern BOOL LoadObject(LPCTSTR szFilename); extern BOOL LoadObject(LPCTSTR szFilename);
extern BOOL SaveObject(LPCTSTR szFilename); extern BOOL SaveObject(LPCTSTR szFilename);
@ -290,6 +293,7 @@ extern VOID ReadIO(BYTE *a, DWORD b, DWORD s, BOOL bUpdate);
extern VOID WriteIO(BYTE *a, DWORD b, DWORD s); extern VOID WriteIO(BYTE *a, DWORD b, DWORD s);
// Lowbat.c // Lowbat.c
extern BOOL bLowBatDisable;
extern VOID StartBatMeasure(VOID); extern VOID StartBatMeasure(VOID);
extern VOID StopBatMeasure(VOID); extern VOID StopBatMeasure(VOID);
extern VOID GetBatteryState(BOOL *pbLBI, BOOL *pbVLBI); extern VOID GetBatteryState(BOOL *pbLBI, BOOL *pbVLBI);
@ -326,6 +330,7 @@ extern VOID RPL_Push(UINT l,DWORD n);
extern BOOL bWaveBeep; extern BOOL bWaveBeep;
extern DWORD dwWaveVol; extern DWORD dwWaveVol;
extern VOID External(CHIPSET* w); extern VOID External(CHIPSET* w);
extern VOID RCKBp(CHIPSET* w);
// DDEserv.c // DDEserv.c
extern HDDEDATA CALLBACK DdeCallback(UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, DWORD, DWORD); extern HDDEDATA CALLBACK DdeCallback(UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, DWORD, DWORD);

View file

@ -225,7 +225,7 @@ FONT 8, "MS Sans Serif"
BEGIN BEGIN
ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE
LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP
LTEXT "Copyright © 2007 Sébastien Carlier && Christoph Gießelink", LTEXT "Copyright © 2008 Christoph Gießelink && Sébastien Carlier",
IDC_STATIC,29,18,181,8 IDC_STATIC,29,18,181,8
DEFPUSHBUTTON "OK",IDOK,215,12,39,14 DEFPUSHBUTTON "OK",IDOK,215,12,39,14
EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL | EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL |
@ -553,8 +553,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,4,5,0 FILEVERSION 1,4,7,0
PRODUCTVERSION 1,4,5,0 PRODUCTVERSION 1,4,7,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -569,14 +569,14 @@ BEGIN
BEGIN BEGIN
BLOCK "04090000" BLOCK "04090000"
BEGIN BEGIN
VALUE "CompanyName", "Sebastien Carlier & Christoph Gießelink\0" VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0"
VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0" VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0"
VALUE "FileVersion", "1, 4, 5, 0\0" VALUE "FileVersion", "1, 4, 7, 0\0"
VALUE "InternalName", "Emu48\0" VALUE "InternalName", "Emu48\0"
VALUE "LegalCopyright", "Copyright © 2007\0" VALUE "LegalCopyright", "Copyright © 2008\0"
VALUE "OriginalFilename", "Emu48.exe\0" VALUE "OriginalFilename", "Emu48.exe\0"
VALUE "ProductName", "Emu48\0" VALUE "ProductName", "Emu48\0"
VALUE "ProductVersion", "1, 4, 5, 0\0" VALUE "ProductVersion", "1, 4, 7, 0\0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -293,7 +293,7 @@ static __inline VOID AdjustSpeed(VOID) // adjust emulation speed
dwTicks = lAct.LowPart - dwSpeedRef; dwTicks = lAct.LowPart - dwSpeedRef;
} }
// ticks elapsed or negative number (workaround for QueryPerformanceCounter() in Win2k) // ticks elapsed or negative number (workaround for QueryPerformanceCounter() in Win2k)
while(dwTicks <= dwTickRef || (dwTicks & 0x80000000) != 0); while (dwTicks <= dwTickRef || (dwTicks & 0x80000000) != 0);
dwOldCyc += T2CYCLES; // adjust cycles reference dwOldCyc += T2CYCLES; // adjust cycles reference
dwSpeedRef += dwTickRef; // adjust reference time dwSpeedRef += dwTickRef; // adjust reference time

View file

@ -129,11 +129,30 @@ static __inline VOID BeepWin9x(DWORD dwFrequency,DWORD dwDuration)
#endif #endif
} }
static __inline VOID Return(CHIPSET* w) static VOID Beeper(DWORD freq,DWORD dur)
{ {
w->rstkp=(w->rstkp-1)&7; if (bWaveBeep)
w->pc = w->rstk[w->rstkp]; {
w->rstk[w->rstkp] = 0; BeepWave(freq,dur); // wave output over sound card
}
else
{
OSVERSIONINFO version;
version.dwOSVersionInfoSize = sizeof(version);
GetVersionEx(&version);
if (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
BeepWin9x(freq,dur); // do it the hard way on '9x / Me
}
else // VER_PLATFORM_WIN32_NT
{
if (freq < 37) freq = 37; // low limit of freqency (NT)
_ASSERT(freq >= 0x25 && freq <= 0x7FFF);
Beep(freq,dur); // NT: ok, Windows 95: default sound or standard system beep
}
}
return; return;
} }
@ -151,28 +170,7 @@ VOID External(CHIPSET* w) // Beep patch
{ {
if (freq > 4400) freq = 4400; // high limit of HP (SX) if (freq > 4400) freq = 4400; // high limit of HP (SX)
if (bWaveBeep) Beeper(freq,dur); // beeping
{
BeepWave(freq,dur); // wave output over sound card
}
else
{
OSVERSIONINFO version;
version.dwOSVersionInfoSize = sizeof(version);
GetVersionEx(&version);
if (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
BeepWin9x(freq,dur); // do it the hard way on '9x / Me
}
else // VER_PLATFORM_WIN32_NT
{
if (freq < 37) freq = 37; // low limit of freqency (NT)
_ASSERT(freq >= 0x25 && freq <= 0x7FFF);
Beep(freq,dur); // NT: ok, Windows 95: default sound or standard system beep
}
}
// estimate cpu cycles for beeping time (2MHz / 4MHz) // estimate cpu cycles for beeping time (2MHz / 4MHz)
w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000); w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000);
@ -182,6 +180,47 @@ VOID External(CHIPSET* w) // Beep patch
w->intk = TRUE; // INTON w->intk = TRUE; // INTON
w->carry = FALSE; // RTNCC w->carry = FALSE; // RTNCC
} }
Return(w); w->pc = rstkpop();
return;
}
VOID RCKBp(CHIPSET* w) // ROM Check Beep patch
{
DWORD dw2F,dwCpuFreq;
DWORD freq,dur;
BYTE f,d;
f = w->C[1]; // f = freq ctl
d = w->C[0]; // d = duration ctl
if (cCurrentRomType == 'S') // Clarke chip with 48S ROM
{
// CPU strobe frequency @ RATE 14 = 1.97MHz
dwCpuFreq = ((14 + 1) * 524288) >> 2;
dw2F = f * 126 + 262; // F=f*63+131
}
else // York chip with 48G and later ROM
{
// CPU strobe frequency @ RATE 27 = 3.67MHz
// CPU strobe frequency @ RATE 29 = 3.93MHz
dwCpuFreq = ((27 + 1) * 524288) >> 2;
dw2F = f * 180 + 367; // F=f*90+183.5
}
freq = dwCpuFreq / dw2F;
dur = (dw2F * (256 - 16 * d)) * 1000 / 2 / dwCpuFreq;
if (freq > 4400) freq = 4400; // high limit of HP
Beeper(freq,dur); // beeping
// estimate cpu cycles for beeping time (2MHz / 4MHz)
w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000);
w->P = 0; // P=0
w->carry = FALSE; // RTNCC
w->pc = rstkpop();
return; return;
} }

View file

@ -212,7 +212,7 @@ static BOOL PatchNibble(DWORD dwAddress, BYTE byPatch)
TREENODE *p; TREENODE *p;
_ASSERT(pbyRom); // ROM defined _ASSERT(pbyRom); // ROM defined
if((p = HeapAlloc(hHeap,0,sizeof(TREENODE))) == NULL) if ((p = HeapAlloc(hHeap,0,sizeof(TREENODE))) == NULL)
return TRUE; return TRUE;
p->bPatch = TRUE; // address patched p->bPatch = TRUE; // address patched
@ -646,6 +646,7 @@ static BOOL IsDataPacked(VOID *pMem, DWORD dwSize)
VOID ResetDocument(VOID) VOID ResetDocument(VOID)
{ {
DisableDebugger();
if (szCurrentKml[0]) if (szCurrentKml[0])
{ {
KillKML(); KillKML();
@ -754,7 +755,7 @@ restore:
ResetBackup(); ResetBackup();
// HP48SX/GX // HP48SX/GX
if(Chipset.type == 'S' || Chipset.type == 'G') if (Chipset.type == 'S' || Chipset.type == 'G')
{ {
// use 2nd command line argument if defined // use 2nd command line argument if defined
MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]);
@ -940,7 +941,7 @@ BOOL OpenDocument(LPCTSTR szFilename)
} }
// HP48SX/GX // HP48SX/GX
if(cCurrentRomType=='S' || cCurrentRomType=='G') if (cCurrentRomType=='S' || cCurrentRomType=='G')
{ {
MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]);
// port2 changed and card detection enabled // port2 changed and card detection enabled
@ -1008,7 +1009,7 @@ restore:
ResetBackup(); ResetBackup();
// HP48SX/GX // HP48SX/GX
if(cCurrentRomType=='S' || cCurrentRomType=='G') if (cCurrentRomType=='S' || cCurrentRomType=='G')
{ {
// use 2nd command line argument if defined // use 2nd command line argument if defined
MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]);
@ -1178,7 +1179,7 @@ BOOL RestoreBackup(VOID)
// map port2 // map port2
else else
{ {
if(cCurrentRomType=='S' || cCurrentRomType=='G') // HP48SX/GX if (cCurrentRomType=='S' || cCurrentRomType=='G') // HP48SX/GX
{ {
// use 2nd command line argument if defined // use 2nd command line argument if defined
MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]); MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]);
@ -1233,8 +1234,7 @@ BOOL GetOpenFilename(VOID)
_T("Emu39 Document (*.E39)\0*.E39\0") _T("Emu39 Document (*.E39)\0*.E39\0")
_T("Emu48 Document (*.E48)\0*.E48\0") _T("Emu48 Document (*.E48)\0*.E48\0")
_T("Emu49 Document (*.E49)\0*.E49\0") _T("Emu49 Document (*.E49)\0*.E49\0")
_T("Win48 Document (*.W48)\0*.W48\0") _T("Win48 Document (*.W48)\0*.W48\0");
_T("\0\0");
ofn.lpstrDefExt = _T("E48"); // HP48SX/GX ofn.lpstrDefExt = _T("E48"); // HP48SX/GX
ofn.nFilterIndex = 3; ofn.nFilterIndex = 3;
if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G
@ -1272,8 +1272,7 @@ BOOL GetSaveAsFilename(VOID)
_T("Emu38 Document (*.E38)\0*.E38\0") _T("Emu38 Document (*.E38)\0*.E38\0")
_T("Emu39 Document (*.E39)\0*.E39\0") _T("Emu39 Document (*.E39)\0*.E39\0")
_T("Emu48 Document (*.E48)\0*.E48\0") _T("Emu48 Document (*.E48)\0*.E48\0")
_T("Emu49 Document (*.E49)\0*.E49\0") _T("Emu49 Document (*.E49)\0*.E49\0");
_T("\0\0");
ofn.lpstrDefExt = _T("E48"); // HP48SX/GX ofn.lpstrDefExt = _T("E48"); // HP48SX/GX
ofn.nFilterIndex = 3; ofn.nFilterIndex = 3;
if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G
@ -1301,13 +1300,14 @@ BOOL GetSaveAsFilename(VOID)
return TRUE; return TRUE;
} }
BOOL GetLoadObjectFilename(VOID) BOOL GetLoadObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt)
{ {
TCHAR szBuffer[ARRAYSIZEOF(szBufferFilename)]; TCHAR szBuffer[ARRAYSIZEOF(szBufferFilename)];
OPENFILENAME ofn; OPENFILENAME ofn;
InitializeOFN(&ofn); InitializeOFN(&ofn);
ofn.lpstrFilter = _T("All Files (*.*)\0*.*\0") _T("\0\0"); ofn.lpstrFilter = lpstrFilter;
ofn.lpstrDefExt = lpstrDefExt;
ofn.nFilterIndex = 1; ofn.nFilterIndex = 1;
ofn.lpstrFile = szBuffer; ofn.lpstrFile = szBuffer;
ofn.lpstrFile[0] = 0; ofn.lpstrFile[0] = 0;
@ -1319,13 +1319,14 @@ BOOL GetLoadObjectFilename(VOID)
return TRUE; return TRUE;
} }
BOOL GetSaveObjectFilename(VOID) BOOL GetSaveObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt)
{ {
TCHAR szBuffer[ARRAYSIZEOF(szBufferFilename)]; TCHAR szBuffer[ARRAYSIZEOF(szBufferFilename)];
OPENFILENAME ofn; OPENFILENAME ofn;
InitializeOFN(&ofn); InitializeOFN(&ofn);
ofn.lpstrFilter = _T("All Files (*.*)\0*.*\0") _T("\0\0"); ofn.lpstrFilter = lpstrFilter;
ofn.lpstrDefExt = lpstrDefExt;
ofn.nFilterIndex = 1; ofn.nFilterIndex = 1;
ofn.lpstrFile = szBuffer; ofn.lpstrFile = szBuffer;
ofn.lpstrFile[0] = 0; ofn.lpstrFile[0] = 0;

View file

@ -252,7 +252,7 @@ static VOID WrStateIdle(BYTE a, DWORD d)
break; break;
} }
if(bFlashRomArray != WSMset.bRomArray) // new access mode if (bFlashRomArray != WSMset.bRomArray) // new access mode
{ {
bFlashRomArray = WSMset.bRomArray; // change register access bFlashRomArray = WSMset.bRomArray; // change register access
Map(0x00,0xFF); // update memory mapping Map(0x00,0xFF); // update memory mapping
@ -420,8 +420,8 @@ static VOID WrState20C(BYTE a, DWORD d)
{ {
if (CONFIRM == a) // block erase confirm? if (CONFIRM == a) // block erase confirm?
{ {
_ASSERT((d>>16) < ARRAYSIZEOF(WSMset.byLockCnfg)); // lock bit of block is set
if (WSMset.byLockCnfg[d>>16] & 1) // lock bit of block is set if ((WSMset.dwLockCnfg & (1<<(d>>16))) != 0)
{ {
WSMset.byStatusReg |= ECLBS; // error in block erasure WSMset.byStatusReg |= ECLBS; // error in block erasure
WSMset.byStatusReg |= DPS; // lock bit detected WSMset.byStatusReg |= DPS; // lock bit detected
@ -474,12 +474,12 @@ static VOID WrState30C(BYTE a, DWORD d)
for (i = 0; i <= wNoOfBlocks; ++i) // check all blocks for (i = 0; i <= wNoOfBlocks; ++i) // check all blocks
{ {
_ASSERT((i+1)*dwBlockSize <= dwRomSize); _ASSERT((i+1)*dwBlockSize <= dwRomSize);
_ASSERT(i < ARRAYSIZEOF(WSMset.byLockCnfg));
// lock bit of block is set & WP# = low, locked blocks cannot be erased // lock bit of block is set & WP# = low, locked blocks cannot be erased
if ((WSMset.byLockCnfg[i] & 1) == 0 || bWP != FALSE) if ((WSMset.dwLockCnfg & (1<<i)) == 0 || bWP != FALSE)
{ {
WSMset.byLockCnfg[i] = 0; // clear block lock bit // clear block lock bit
WSMset.dwLockCnfg &= ~(1<<i);
// write 128K nibble // write 128K nibble
FillMemory(pbyBlock,dwBlockSize,0x0F); FillMemory(pbyBlock,dwBlockSize,0x0F);
@ -535,9 +535,8 @@ static VOID WrState60D(BYTE a, DWORD d)
switch(a) switch(a)
{ {
case 0x01: // set block lock bit case 0x01: // set block lock bit
_ASSERT((d>>16) < ARRAYSIZEOF(WSMset.byLockCnfg));
if (bWP) // WP# = high, can change block lock status if (bWP) // WP# = high, can change block lock status
WSMset.byLockCnfg[d>>16] = 1; // set block lock bit WSMset.dwLockCnfg |= (1<<(d>>16)); // set block lock bit
else else
WSMset.byStatusReg |= (BWSLBS | DPS); // device protect detect, WP# = low WSMset.byStatusReg |= (BWSLBS | DPS); // device protect detect, WP# = low
break; break;
@ -548,8 +547,7 @@ static VOID WrState60D(BYTE a, DWORD d)
for (i = 0; i <= wNoOfBlocks; ++i) // clear all lock bits for (i = 0; i <= wNoOfBlocks; ++i) // clear all lock bits
{ {
_ASSERT(i < ARRAYSIZEOF(WSMset.byLockCnfg)); WSMset.dwLockCnfg &= ~(1 << i); // clear block lock bit
WSMset.byLockCnfg[i] = 0; // clear block lock bit
} }
} }
else else
@ -591,12 +589,11 @@ static BYTE RdStateId(DWORD d)
} }
else // block lock table else // block lock table
{ {
UINT uIndex = d >> 15; // index into lock table // get data from block lock table
_ASSERT(uIndex < ARRAYSIZEOF(WSMset.byLockCnfg)); byData = (BYTE) ((WSMset.dwLockCnfg >> (d >> 15)) & 1);
byData = WSMset.byLockCnfg[uIndex]; // get data from block lock table
d &= 0x1F; // data repetition d &= 0x1F; // data repetition
if (d >= 4) byData |= 0x02; // set bit 1 on wrong ID adresses if (d >= 4) byData |= 0x02; // set bit 1 on wrong ID adress
} }
return byData; return byData;
} }
@ -616,9 +613,8 @@ static BYTE RdStateQuery(DWORD d)
} }
else // block lock table else // block lock table
{ {
UINT uIndex = d >> 15; // index into lock table // get data from block lock table
_ASSERT(uIndex < ARRAYSIZEOF(WSMset.byLockCnfg)); byData = (BYTE) ((WSMset.dwLockCnfg >> (d >> 15)) & 1);
byData = WSMset.byLockCnfg[uIndex]; // get data from block lock table
} }
return byData; return byData;
} }
@ -644,13 +640,16 @@ static BYTE RdStateXSR(DWORD d)
VOID FlashInit(VOID) VOID FlashInit(VOID)
{ {
// check if locking bit table has more or equal than 32 bit
_ASSERT(sizeof(WSMset.dwLockCnfg) * 8 >= 32);
ZeroMemory(&WSMset,sizeof(WSMset)); ZeroMemory(&WSMset,sizeof(WSMset));
strcpy(WSMset.byType,"WSM"); // Write State Machine header strcpy(WSMset.byType,"WSM"); // Write State Machine header
WSMset.uSize = sizeof(WSMset); // size of this structure WSMset.uSize = sizeof(WSMset); // size of this structure
WSMset.byVersion = WSMVER; // version of flash implementation structure WSMset.byVersion = WSMVER; // version of flash implementation structure
// factory setting of locking bits // factory setting of locking bits
WSMset.byLockCnfg[0] = 0x01; // first 64KB block is locked WSMset.dwLockCnfg = (1 << 0); // first 64KB block is locked
WSMset.uWrState = WRS_DATA; WSMset.uWrState = WRS_DATA;
WSMset.uRdState = RDS_DATA; WSMset.uRdState = RDS_DATA;

View file

@ -17,7 +17,7 @@ typedef struct
BYTE byVersion; // WSM version BYTE byVersion; // WSM version
BOOL bRomArray; // copy of bFlashRomArray BOOL bRomArray; // copy of bFlashRomArray
BYTE byLockCnfg[32]; // block lock table DWORD dwLockCnfg; // block lock table (32 entries)
UINT uWrState; // state of write function WSM UINT uWrState; // state of write function WSM
UINT uRdState; // state of read function WSM UINT uRdState; // state of read function WSM
BYTE byStatusReg; // status register BYTE byStatusReg; // status register

View file

@ -132,8 +132,7 @@ LRESULT OnToolMacroNew(VOID)
InitializeOFN(&ofn); InitializeOFN(&ofn);
ofn.lpstrFilter = ofn.lpstrFilter =
_T("Keyboard Macro Files (*.MAC)\0*.MAC\0") _T("Keyboard Macro Files (*.MAC)\0*.MAC\0")
_T("All Files (*.*)\0*.*\0") _T("All Files (*.*)\0*.*\0");
_T("\0\0");
ofn.lpstrDefExt = _T("MAC"); ofn.lpstrDefExt = _T("MAC");
ofn.nFilterIndex = 1; ofn.nFilterIndex = 1;
ofn.lpstrFile = szMacroFile; ofn.lpstrFile = szMacroFile;
@ -186,8 +185,7 @@ LRESULT OnToolMacroPlay(VOID)
InitializeOFN(&ofn); InitializeOFN(&ofn);
ofn.lpstrFilter = ofn.lpstrFilter =
_T("Keyboard Macro Files (*.MAC)\0*.MAC\0") _T("Keyboard Macro Files (*.MAC)\0*.MAC\0")
_T("All Files (*.*)\0*.*\0") _T("All Files (*.*)\0*.*\0");
_T("\0\0");
ofn.lpstrDefExt = _T("MAC"); ofn.lpstrDefExt = _T("MAC");
ofn.nFilterIndex = 1; ofn.nFilterIndex = 1;
ofn.lpstrFile = szMacroFile; ofn.lpstrFile = szMacroFile;

View file

@ -571,81 +571,67 @@ static BOOL IsBlock(TokenId eId)
static LPCTSTR GetStringOf(TokenId eId) static LPCTSTR GetStringOf(TokenId eId)
{ {
UINT i = 0; UINT i;
while (pLexToken[i].nLen)
for (i = 0; pLexToken[i].nLen; ++i)
{ {
if (pLexToken[i].eId == eId) return pLexToken[i].szName; if (pLexToken[i].eId == eId) return pLexToken[i].szName;
i++;
} }
return _T("<Undefined>"); return _T("<Undefined>");
} }
static VOID SkipWhite(UINT nMode) static VOID SkipWhite(UINT nMode)
{ {
UINT i; LPTSTR pcDelim;
loop:
i = 0; while (*szText)
while (szLexDelim[nMode][i])
{ {
if (*szText == szLexDelim[nMode][i]) break; // search for delimiter
i++; if ((pcDelim = _tcschr(szLexDelim[nMode],*szText)) != NULL)
} {
if (szLexDelim[nMode][i] != 0) _ASSERT(*pcDelim != 0); // no EOS
{ if (*pcDelim == _T('\n')) nLexLine++;
if (szLexDelim[nMode][i]==_T('\n')) nLexLine++; szText++;
szText++; continue;
goto loop; }
} if (*szText == _T('#')) // start of remark
if (*szText==_T('#')) {
{ // skip until LF or EOS
do szText++; while (*szText != _T('\n') && *szText != 0); do szText++; while (*szText != _T('\n') && *szText != 0);
if (nMode != LEX_PARAM) goto loop; if (nMode != LEX_PARAM) continue;
}
break;
} }
return; return;
} }
static TokenId ParseToken(UINT nMode) static TokenId ParseToken(UINT nMode)
{ {
UINT i, j, k; UINT i,j;
i = 0;
while (szText[i]) for (i = 0; szText[i]; i++) // search for delimeter
{ {
j = 0; if (_tcschr(szLexDelim[nMode],szText[i]) != NULL)
while (szLexDelim[nMode][j]) break;
{
if (szLexDelim[nMode][j] == szText[i]) break;
j++;
}
if (szLexDelim[nMode][j] == _T('\n')) nLexLine++;
if (szLexDelim[nMode][j] != 0) break;
i++;
} }
if (i==0) if (i == 0) return TOK_NONE;
// token length longer or equal than current command
for (j = 0; pLexToken[j].nLen >= i; ++j)
{ {
return TOK_NONE; if (pLexToken[j].nLen == i) // token length has command length
}
j = 0;
while (pLexToken[j].nLen)
{
if (pLexToken[j].nLen>i)
{ {
j++; if (_tcsncmp(pLexToken[j].szName,szText,i) == 0)
continue; {
szText += i; // remove command from text
return pLexToken[j].eId; // return token Id
}
} }
if (pLexToken[j].nLen<i) break;
k = 0;
if (_tcsncmp(pLexToken[j].szName, szText, i)==0)
{
szText += i;
return pLexToken[j].eId;
}
j++;
} }
szText[i] = 0; szText[i] = 0; // token not found, set EOS
if (bDebug) if (bDebug)
{ {
PrintfToLog(_T("%i: Undefined token %s"), nLexLine, szText); PrintfToLog(_T("%i: Undefined token %s"),nLexLine,szText);
return TOK_NONE;
} }
return TOK_NONE; return TOK_NONE;
} }
@ -734,60 +720,61 @@ static KmlLine* ParseLine(TokenId eCommand)
TokenId eToken; TokenId eToken;
KmlLine* pLine; KmlLine* pLine;
i = 0; for (i = 0; pLexToken[i].nLen; ++i)
while (pLexToken[i].nLen)
{ {
if (pLexToken[i].eId == eCommand) break; if (pLexToken[i].eId == eCommand) break;
i++;
} }
if (pLexToken[i].nLen == 0) return NULL; if (pLexToken[i].nLen == 0) return NULL;
j = 0;
pLine = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(KmlLine)); pLine = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(KmlLine));
pLine->eCommand = eCommand; pLine->eCommand = eCommand;
nParams = pLexToken[i].nParams;
loop: for (j = 0, nParams = pLexToken[i].nParams; TRUE; nParams >>= 3)
eToken = Lex(LEX_PARAM);
if ((nParams&7)==TYPE_NONE)
{ {
if (eToken != TOK_EOL) // check for parameter overflow
_ASSERT(j < ARRAYSIZEOF(pLine->nParam));
eToken = Lex(LEX_PARAM); // decode argument token
if ((nParams & 7) == TYPE_NONE)
{ {
PrintfToLog(_T("%i: Too many parameters (%i expected)."), nLexLine, j); if (eToken != TOK_EOL)
goto errline; // free memory of arguments {
PrintfToLog(_T("%i: Too many parameters for %s (%i expected)."), nLexLine, pLexToken[i].szName, j);
break; // free memory of arguments
}
return pLine; // normal exit -> parsed line
} }
return pLine; if ((nParams & 7) == TYPE_INTEGER)
}
if ((nParams&7)==TYPE_INTEGER)
{
if (eToken != TOK_INTEGER)
{ {
PrintfToLog(_T("%i: Parameter %i of %s must be an integer."), nLexLine, j+1, pLexToken[i].szName); if (eToken != TOK_INTEGER)
goto errline; // free memory of arguments {
PrintfToLog(_T("%i: Parameter %i of %s must be an integer."), nLexLine, j+1, pLexToken[i].szName);
break; // free memory of arguments
}
pLine->nParam[j++] = nLexInteger;
continue;
} }
pLine->nParam[j++] = nLexInteger; if ((nParams & 7) == TYPE_STRING)
nParams >>= 3;
goto loop;
}
if ((nParams&7)==TYPE_STRING)
{
if (eToken != TOK_STRING)
{ {
PrintfToLog(_T("%i: Parameter %i of %s must be a string."), nLexLine, j+1, pLexToken[i].szName); if (eToken != TOK_STRING)
goto errline; // free memory of arguments {
PrintfToLog(_T("%i: Parameter %i of %s must be a string."), nLexLine, j+1, pLexToken[i].szName);
break; // free memory of arguments
}
pLine->nParam[j++] = (DWORD_PTR) szLexString;
continue;
} }
pLine->nParam[j++] = (DWORD_PTR) szLexString; _ASSERT(FALSE); // unknown parameter type
nParams >>= 3; break;
goto loop;
} }
AddToLog(_T("Oops..."));
errline:
// if last argument was string, free it // if last argument was string, free it
if (eToken == TOK_STRING) HeapFree(hHeap,0,szLexString); if (eToken == TOK_STRING) HeapFree(hHeap,0,szLexString);
nParams = pLexToken[i].nParams; // get argument types of command nParams = pLexToken[i].nParams; // get argument types of command
for (i=0; i<j; i++) // handle all scanned arguments for (i = 0; i < j; ++i) // handle all scanned arguments
{ {
if ((nParams&7) == TYPE_STRING) // string type if ((nParams & 7) == TYPE_STRING) // string type
{ {
HeapFree(hHeap,0,(LPVOID)pLine->nParam[i]); HeapFree(hHeap,0,(LPVOID)pLine->nParam[i]);
} }
@ -1596,7 +1583,7 @@ static INT iSqrt(INT nNumber) // integer y=sqrt(x) function
else else
b = m; // adjust lower border b = m; // adjust lower border
} }
while(t - b > 1); while (t - b > 1);
return b; return b;
} }

View file

@ -14,6 +14,8 @@
#define BAT_FREQ (60*1000) // bat update time in ms (real machine = 60us, HP28C = 60s) #define BAT_FREQ (60*1000) // bat update time in ms (real machine = 60us, HP28C = 60s)
BOOL bLowBatDisable = FALSE;
static HANDLE hCThreadBat = NULL; static HANDLE hCThreadBat = NULL;
static HANDLE hEventBat; static HANDLE hEventBat;
@ -51,13 +53,15 @@ static DWORD WINAPI LowBatThread(LPVOID pParam)
VOID StartBatMeasure(VOID) VOID StartBatMeasure(VOID)
{ {
DWORD dwThreadId;
if (hCThreadBat) // Bat measuring thread running if (hCThreadBat) // Bat measuring thread running
return; // -> quit return; // -> quit
// event to cancel Bat refresh loop // event to cancel Bat refresh loop
hEventBat = CreateEvent(NULL,FALSE,FALSE,NULL); hEventBat = CreateEvent(NULL,FALSE,FALSE,NULL);
VERIFY(hCThreadBat = CreateThread(NULL,0,&LowBatThread,NULL,0,NULL)); VERIFY(hCThreadBat = CreateThread(NULL,0,&LowBatThread,NULL,0,&dwThreadId));
return; return;
} }
@ -100,8 +104,8 @@ VOID GetBatteryState(BOOL *pbLBI, BOOL *pbVLBI)
VERIFY(GetSystemPowerStatus(&sSps)); VERIFY(GetSystemPowerStatus(&sSps));
// battery powered // low bat emulation enabled and battery powered
if (sSps.ACLineStatus == AC_LINE_OFFLINE) if (!bLowBatDisable && sSps.ACLineStatus == AC_LINE_OFFLINE)
{ {
// on critical battery state make sure that lowbat flag is also set // on critical battery state make sure that lowbat flag is also set
if ((sSps.BatteryFlag & BATTERY_FLAG_CRITICAL) != 0) if ((sSps.BatteryFlag & BATTERY_FLAG_CRITICAL) != 0)

View file

@ -73,7 +73,7 @@ BOOL MruInit(INT nNum)
if (nEntry > 0) // allocate MRU table if (nEntry > 0) // allocate MRU table
{ {
// create MRU table // create MRU table
if((ppszFiles = HeapAlloc(hHeap,0,nEntry * sizeof(*ppszFiles))) == NULL) if ((ppszFiles = HeapAlloc(hHeap,0,nEntry * sizeof(*ppszFiles))) == NULL)
return TRUE; return TRUE;
// fill each entry // fill each entry

View file

@ -45,7 +45,7 @@ static __inline LPBYTE FASTPTR(DWORD d)
if ((Chipset.IOCfig)&&((d&0xFFFC0)==Chipset.IOBase)) if ((Chipset.IOCfig)&&((d&0xFFFC0)==Chipset.IOBase))
return Chipset.IORam+d-Chipset.IOBase; return Chipset.IORam+d-Chipset.IOBase;
if((lpbyPage = RMap[d>>12]) != NULL) // page valid if ((lpbyPage = RMap[d>>12]) != NULL) // page valid
{ {
lpbyPage += d & 0xFFF; // full address lpbyPage += d & 0xFFF; // full address
} }

View file

@ -120,7 +120,7 @@ BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort)
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL); NULL);
if(hComm != INVALID_HANDLE_VALUE) if (hComm != INVALID_HANDLE_VALUE)
{ {
DWORD dwThreadId; DWORD dwThreadId;
@ -347,13 +347,13 @@ VOID CommReceive(VOID)
// reject reading if com port is closed and not whole operation // reject reading if com port is closed and not whole operation
if (hComm && dwBytesRead == 0L) // com port open and buffer empty if (hComm && dwBytesRead == 0L) // com port open and buffer empty
{ {
if(ReadFile(hComm,&cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE) if (ReadFile(hComm,&cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE)
dwBytesRead = 0L; dwBytesRead = 0L;
else // bytes received else // bytes received
nRp = 0; // reset read pointer nRp = 0; // reset read pointer
} }
if(dwBytesRead == 0L) // receive buffer empty if (dwBytesRead == 0L) // receive buffer empty
break; break;
#if defined DEBUG_SERIAL #if defined DEBUG_SERIAL
@ -373,10 +373,10 @@ VOID CommReceive(VOID)
--dwBytesRead; --dwBytesRead;
Chipset.IORam[RCS] |= RBF; // receive buffer full Chipset.IORam[RCS] |= RBF; // receive buffer full
if(UpdateUSRQ()) // update USRQ bit if (UpdateUSRQ()) // update USRQ bit
INTERRUPT; INTERRUPT;
} }
while(0); while (FALSE);
LeaveCriticalSection(&csRecvLock); LeaveCriticalSection(&csRecvLock);
return; return;
} }

View file

@ -185,6 +185,8 @@ VOID ReadSettings(VOID)
bWaveBeep = ReadInt(_T("Emulator"),_T("WaveBeep"),bWaveBeep); bWaveBeep = ReadInt(_T("Emulator"),_T("WaveBeep"),bWaveBeep);
dwWaveVol = ReadInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol); dwWaveVol = ReadInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol);
SetSpeed(bRealSpeed); // set speed SetSpeed(bRealSpeed); // set speed
// LowBat
bLowBatDisable = ReadInt(_T("LowBat"),_T("Disable"),bLowBatDisable);
// Macro // Macro
bMacroRealSpeed = ReadInt(_T("Macro"),_T("RealSpeed"),bMacroRealSpeed); bMacroRealSpeed = ReadInt(_T("Macro"),_T("RealSpeed"),bMacroRealSpeed);
nMacroTimeout = ReadInt(_T("Macro"),_T("ReplayTimeout"),nMacroTimeout); nMacroTimeout = ReadInt(_T("Macro"),_T("ReplayTimeout"),nMacroTimeout);
@ -222,6 +224,8 @@ VOID WriteSettings(VOID)
WriteInt(_T("Emulator"),_T("Grayscale"),bGrayscale); WriteInt(_T("Emulator"),_T("Grayscale"),bGrayscale);
WriteInt(_T("Emulator"),_T("WaveBeep"),bWaveBeep); WriteInt(_T("Emulator"),_T("WaveBeep"),bWaveBeep);
WriteInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol); WriteInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol);
// LowBat
WriteInt(_T("LowBat"),_T("Disable"),bLowBatDisable);
// Macro // Macro
WriteInt(_T("Macro"),_T("RealSpeed"),bMacroRealSpeed); WriteInt(_T("Macro"),_T("RealSpeed"),bMacroRealSpeed);
WriteInt(_T("Macro"),_T("ReplayTimeout"),nMacroTimeout); WriteInt(_T("Macro"),_T("ReplayTimeout"),nMacroTimeout);

View file

@ -253,7 +253,7 @@ static INT RPL_SetBcd(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYT
byNum[j] = byNum[j + i]; byNum[j] = byNum[j + i];
} }
if(byNum[1] == 0) // number is 0 if (byNum[1] == 0) // number is 0
{ {
ZeroMemory(pbyNum,nMantLen + nExpLen + 1); ZeroMemory(pbyNum,nMantLen + nExpLen + 1);
return nMantLen + nExpLen + 1; return nMantLen + nExpLen + 1;
@ -283,7 +283,7 @@ static INT RPL_SetBcd(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYT
while (*cp >= _T('0') && *cp <= _T('9')) while (*cp >= _T('0') && *cp <= _T('9'))
lExp = lExp * 10 + *cp++ - _T('0'); lExp = lExp * 10 + *cp++ - _T('0');
if(i) lExp = -lExp; if (i) lExp = -lExp;
} }
if (*cp != 0) return 0; if (*cp != 0) return 0;
@ -530,7 +530,7 @@ LRESULT OnStackPaste(VOID) // paste data to stack
KeyboardEvent(FALSE,0,0x8000); KeyboardEvent(FALSE,0,0x8000);
// wait for sleep mode // wait for sleep mode
while(Chipset.Shutdn == FALSE) Sleep(0); while (Chipset.Shutdn == FALSE) Sleep(0);
} }
_ASSERT(nState == SM_RUN); // emulator must be in RUN state _ASSERT(nState == SM_RUN); // emulator must be in RUN state
@ -644,7 +644,7 @@ LRESULT OnStackPaste(VOID) // paste data to stack
} }
} }
} }
while(FALSE); while (FALSE);
GlobalUnlock(hClipObj); GlobalUnlock(hClipObj);
} }
@ -660,10 +660,11 @@ LRESULT OnStackPaste(VOID) // paste data to stack
goto cancel; goto cancel;
KeyboardEvent(TRUE,0,0x8000); KeyboardEvent(TRUE,0,0x8000);
Sleep(200);
KeyboardEvent(FALSE,0,0x8000); KeyboardEvent(FALSE,0,0x8000);
// wait for sleep mode // wait for sleep mode
while(Chipset.Shutdn == FALSE) Sleep(0); while (Chipset.Shutdn == FALSE) Sleep(0);
cancel: cancel:
bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control bDbgAutoStateCtrl = TRUE; // enable automatic debugger state control

View file

@ -225,7 +225,7 @@ FONT 8, "MS Sans Serif"
BEGIN BEGIN
ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE
LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP
LTEXT "Copyright © 2007 Sébastien Carlier && Christoph Gießelink", LTEXT "Copyright © 2008 Sébastien Carlier && Christoph Gießelink",
IDC_STATIC,29,18,181,8 IDC_STATIC,29,18,181,8
DEFPUSHBUTTON "OK",IDOK,215,12,39,14 DEFPUSHBUTTON "OK",IDOK,215,12,39,14
EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL | EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL |
@ -581,8 +581,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,4,5,0 FILEVERSION 1,4,7,0
PRODUCTVERSION 1,4,5,0 PRODUCTVERSION 1,4,7,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -599,12 +599,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Sebastien Carlier & Christoph Gießelink\0" VALUE "CompanyName", "Sebastien Carlier & Christoph Gießelink\0"
VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0" VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0"
VALUE "FileVersion", "1, 4, 5, 0\0" VALUE "FileVersion", "1, 4, 7, 0\0"
VALUE "InternalName", "Emu48\0" VALUE "InternalName", "Emu48\0"
VALUE "LegalCopyright", "Copyright © 2007\0" VALUE "LegalCopyright", "Copyright © 2008\0"
VALUE "OriginalFilename", "Emu48.exe\0" VALUE "OriginalFilename", "Emu48.exe\0"
VALUE "ProductName", "Emu48\0" VALUE "ProductName", "Emu48\0"
VALUE "ProductVersion", "1, 4, 5, 0\0" VALUE "ProductVersion", "1, 4, 7, 0\0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -9,25 +9,18 @@ of the compiler and the necessary files is MinGW at www.mingw.org.
Emu48 was tested with the following MinGW file versions: Emu48 was tested with the following MinGW file versions:
MinGW-3.1.0-1.exe MinGW-3.1.0-1.exe
w32api-3.3.tar.gz w32api-3.10.tar.gz
mingw-runtime-3.8.tar.gz mingw-runtime-3.13.tar.gz
binutils-2.16.91-20050827-1.tar.gz mingw32-make-3.81-2.tar.gz
gcc-core-3.4.4-20050522-1.tar.gz
or
MinGW-3.1.0-1.exe
w32api-3.7.tar.gz
mingw-runtime-3.9.tar.gz
binutils-2.16.91-20060119-1.tar.gz binutils-2.16.91-20060119-1.tar.gz
gcc-core-3.4.5-20060117-1.tar.gz gcc-core-3.4.5-20060117-1.tar.gz
or or
MinGW-3.1.0-1.exe w32api-3.11.tar.gz
w32api-3.8.tar.gz mingw-runtime-3.14.tar.gz
mingw-runtime-3.11.tar.gz mingw32-make-3.81-20080326.tar.gz
binutils-2.16.91-20060119-1.tar.gz binutils-2.18.50-20080109-2.tar.gz
gcc-core-3.4.5-20060117-1.tar.gz gcc-core-3.4.5-20060117-1.tar.gz
Older versions of the MinGW package might not work, because there are several Older versions of the MinGW package might not work, because there are several
@ -41,4 +34,4 @@ Many thanks to Pedro A. Arranda Guti
compatible. compatible.
08/07/07 (c) by Christoph Gießelink 04/01/08 (c) by Christoph Gießelink

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View file

@ -1,7 +1,7 @@
Global Global
Print "=======================================================" Print "======================================================="
Print "KML script by Christoph Giesselink, c.giesselink@gmx.de" Print "KML script by Christoph Giesselink, c.giesselink@gmx.de"
Print "http://privat.swol.de/ChristophGiesselink/" Print "http://hp.giesselink.com/"
Print "Wombat3 base on the design of Wombat2 by" Print "Wombat3 base on the design of Wombat2 by"
Print "Victor Chow & Pete Wilson" Print "Victor Chow & Pete Wilson"
Print "=======================================================" Print "======================================================="

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View file

@ -1,7 +1,7 @@
Global Global
Print "=======================================================" Print "======================================================="
Print "KML script by Christoph Giesselink, c.giesselink@gmx.de" Print "KML script by Christoph Giesselink, c.giesselink@gmx.de"
Print "http://privat.swol.de/ChristophGiesselink/" Print "http://hp.giesselink.com/"
Print "Wombat3 base on the design of Wombat2 by" Print "Wombat3 base on the design of Wombat2 by"
Print "Victor Chow & Pete Wilson" Print "Victor Chow & Pete Wilson"
Print "=======================================================" Print "======================================================="

Binary file not shown.