2019-10-16: Updated to version 61

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 9ed4c0cec5
commit b29959b1f3
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
17 changed files with 4397 additions and 4454 deletions

View file

@ -87,28 +87,32 @@ h3 { color:red; font-size:1.1em; }
</div> </div>
<div id="main"> <div id="main">
<h1><a name=s1>1. General</a></h1> <h1><a name=s1>1. General</a></h1>
<p>Emu48 is an emulator for the Hewlett Packard HP38G, HP39G, <p><a href="http://hp.giesselink.com/emu42.htm">Emu48</a> is an
HP40G, HP48SX, HP48GX and HP49G calculator hardware. These calculators emulator for the Hewlett Packard HP38G, HP39G, HP40G, HP48SX, HP48GX
are based on the 1LT8 Clarke (HP48SX) and on the Yorke chip.</p> and HP49G calculator hardware. These calculators are based on the
1LT8 Clarke (HP48SX) and on the Yorke chip.</p>
<h1><a name=s2>2. Acknowledgements</a></h1> <h1><a name=s2>2. Acknowledgements</a></h1>
<p>First of all a big thank to S&eacute;bastien Carlier for publishing <p>First of all a big thank to S&eacute;bastien Carlier for publishing
Emu48 v1.0 under the GPL. Without this decision newer versions of the Emu48 v1.0 under the GPL. Without this decision newer versions of the
emulator wouldn't have been possible or ports to other similar emulator wouldn't have been possible or ports to other similar
calculators wouldn't have been made. Also a big thank to Jean-Yves calculators wouldn't have been made. Also a big thank to Jean-Yves
Avenard for his technical assistance in the beginning. Lode Vandevenne Avenard for his technical assistance in the beginning. Lode Vandevenne
spend the PNG image decoder and finally I want to thank all the spent the PNG image decoder and finally I want to thank all the
unnamed authors for publishing material about these calculators.</p> unnamed authors for publishing material about these calculators.</p>
<h1><a name=s3>3. ROM Images</a></h1> <h1><a name=s3>3. ROM Images</a></h1>
<p>Emu48 needs an image of a calculator ROM to be able to run. ROM <p>Emu48 needs a <a href="https://en.wikipedia.org/wiki/ROM_image">ROM
images are valid in a packed (even address lower nibble, odd address image</a> for each calculator model you want to emulate. ROM images
higher nibble) or unpacked (one nibble per byte with even address first) are valid in a packed (even address lower nibble, odd address higher
nibble) or unpacked (one nibble per byte with even address first)
form.</p> form.</p>
<p>Since fall 2000 the emulator ROM's for the HP38, 39, 40, 48 and 49 <p>Since fall 2000 the emulator ROM's for the HP38, 39, 40, 48 and 49
are freely available on different Internet sites. Because there's no are freely available on different Internet sites. Because there's no
license for the distribution of the ROM images, they aren't included license for the distribution of the ROM images, they aren't included
in the Emu48 package. You can still use the classic way extracting in the Emu48 package. Since accepting packed ROM images, in most cases
them from your own calculator. But in mostly all cases you have to converting the given ROM format (which is regulary a packed ROM image)
convert the ROM files into the Emu48 ROM format.</p> into the native Emu48 ROM format is not necessary any more. You can
still use the classic way extracting them from your own calculator.
</p>
<ul> <ul>
<li>HP38 <li>HP38
<p>To upload the ROM of your HP38G, you will need a special aplet <p>To upload the ROM of your HP38G, you will need a special aplet
@ -178,24 +182,24 @@ h3 { color:red; font-size:1.1em; }
<p>To install Emu48 you may use the installer package which contain, <p>To install Emu48 you may use the installer package which contain,
among the binaries, some HP48 KML scripts or just unzip the emulator among the binaries, some HP48 KML scripts or just unzip the emulator
and the required emulator skins from archives into an empty directory. and the required emulator skins from archives into an empty directory.
Finally you have to copy your ROM images into this directory and Finally copy your ROM images into this directory and adjust the ROM
adjust the ROM image name to the name used in the corresponding KML image name to the name used in the corresponding KML script. When you
script. When you first run Emu48, it will detect the directory in first run Emu48, it will detect the directory in which you installed
which you installed it, and will write the configuration to the it, and will write the configuration to the registry at
registry at <i>HKCU\Software\Emu48</i>.</p> <i>HKCU\Software\Emu48</i>.</p>
<h1><a name=s5>5. How to Start</a></h1> <h1><a name=s5>5. How to Start</a></h1>
<p>When Emu48 is installed and you have put valid KML scripts and the <p>When Emu48 is installed and you have put valid KML scripts and the
corresponding ROM image(s) into your Emu48 installation directory, you corresponding ROM image(s) into your Emu48 installation directory, you
can start Emu48. You'll see a &quot;Choose Your KML Script&quot; can start Emu48. You'll see a &quot;Choose Your KML Script&quot;
box.</p> box.</p>
<p>KML scripts in fact define the visual aspect of Emu48, the behavior of <p>KML (Keyboard Mapping Language) scripts define the visual aspect
the buttons, of the keyboard, ... It's a GREAT way to customize your copy of Emu48, the behaviour of the buttons, of the keyboard, ... It's a
of Emu48.</p> <b>great</b> way to customize your copy of Emu48.</p>
<p>Check that the path in the &quot;Emu48 Directory&quot; text area is <p>Check in this dialog that the path in the &quot;Emu48 Directory&quot;
correct. Modify it if the directory in which you installed Emu48 is not text area points to the directory in which you installed the Emu48 KML
the directory displayed. Click the refresh button (&quot;V&quot;) after files. Click the refresh button (&quot;V&quot;) after modifying the
modifying it to update the list box or use the (&quot;...&quot;) button to directory path manually to update the list box or use the
start the directory browser.</p> (&quot;...&quot;) button to start a directory browser.</p>
<p>Choose a KML script in the list box for your calculator ROM you put <p>Choose a KML script in the list box for your calculator ROM you put
into Emu48's directory.</p> into Emu48's directory.</p>
<p>Several HP48 scripts are included in the Emu48 archive:</p> <p>Several HP48 scripts are included in the Emu48 archive:</p>
@ -218,19 +222,21 @@ h3 { color:red; font-size:1.1em; }
</ul> </ul>
<p>If you want other great scripts, visit Rechlin's great HP archive <p>If you want other great scripts, visit Rechlin's great HP archive
<a href="http://www.hpcalc.org/"></a></p> <a href="http://www.hpcalc.org/"></a></p>
<p>And if you are interested in writing new scripts, get the KML 2.0 <p>If you are interested in writing new scripts, get the KML 2.0
documentation from <a href="http://hp.giesselink.com/emu48.htm">the documentation from <a href="http://hp.giesselink.com/emu48.htm">the
authors Emu48 page</a>.</p> authors Emu48 page</a>.</p>
<p>Once you have selected a script, press OK to start the emulator. In <p>Having selected a script, press OK to start the emulator. In most
most cases, when Emu48 crash after pressing the OK button, you are using cases, when Emu48 crash after pressing the OK button, you are using
an invalid ROM image. While it's running, you can use the View/Change KML an invalid ROM image. While it's running, you can use the
Script... command to change the visual aspect of Emu48.</p> &quot;<a href="#ss10.1">View/Change KML Script...</a>&quot; command to
change the visual aspect of Emu48.</p>
<h1><a name=s6>6. Command Line</a></h1> <h1><a name=s6>6. Command Line</a></h1>
<p>The command line syntax is &quot;<i>Emu48 [E48file [Port2file]]</i>&quot;. <p>The command line syntax is &quot;<i>Emu48 [E48file [Port2file]]</i>&quot;.
The first parameter sets the filename for the emulation data The first parameter sets the filename of the emulation data
independent from the &quot;LastDocument&quot; setting, the second independent from the &quot;LastDocument&quot; setting, normally
parameter the Port2 file. You're not able to set a Port 2 file without reponsible for opening the last used state file. The second parameter
setting the emulation data file. The arguments are optional.</p> the Port2 file. You're not able to set a Port 2 file without setting
the emulation data file. The arguments are optional.</p>
<h1><a name=s7>7. Virtual Keyboard</a></h1> <h1><a name=s7>7. Virtual Keyboard</a></h1>
<p>There are two ways to use the virtual keyboard on the emulated <p>There are two ways to use the virtual keyboard on the emulated
calculator:</p> calculator:</p>
@ -239,38 +245,41 @@ h3 { color:red; font-size:1.1em; }
<li><a href="#keyboard">by PC keyboard</a></li> <li><a href="#keyboard">by PC keyboard</a></li>
</ol> </ol>
<p><a name=mouse></a> <p><a name=mouse></a>
The easiest way to use the emulated calculator is using the mouse. The KML The easiest way to use the emulated calculator is by using the mouse. The
script define buttons with an area where mouse input is active. The mouse KML script defines buttons with an area where mouse clicks take effect.
cursor change from an arrow to a hand cursor in these areas. The state of The active area is indicated by changing the cursor from an arrow to a
the virtual key follow the state of your left mouse button. When the mouse hand cursor. Pressing the left mouse button over an active area will
cursor leaves the virtual key area the virtual button automatically press the virtual button. When the mouse cursor leaves the virtual key
release. In some cases you need to press more than one key on the area with still the left mouse button pressed, the virtual button is
emulator. For these cases press the virtual key with the right mouse automatically released. The visual aspect of a pressed or released
button. When you release the mouse button or leave the area of the virtual virtual button is defined in the KML script. In some cases you need to
key, the key is still hold. To release all hold virtual buttons, just use press more than one key on the emulator. For these cases press the
the left mouse button again. A single release of a hold virtual key isn't virtual key with the right mouse button. When you release the mouse
possible.</p> button or leave the area of the virtual key, the key is still held.
To release all held virtual buttons, just use the left mouse button
again. A single release of a hold virtual key isn't possible.</p>
<p><a name=keyboard></a> <p><a name=keyboard></a>
Another convenient way is using the PC keyboard. The KML script language Another convenient way is using the PC keyboard. The KML script language
support a large variety of commands to implement this feature. So keyboard supports a large variety of commands to implement this feature. So
usage depends on your used KML script and not on the emulator. Because of keyboard usage mostly depends on your used KML script and not on the
this it's impossible to say what's happen when you press a key on the PC emulator. Because of this it's impossible to say what's happen when you
keyboard. For further details read the KML 2.0 documentation mentioned press a key on the PC keyboard. Some Windows specific accelerator keys
before please.</p> like F10 cannot be overloaded by the KML script. For further details
read the KML 2.0 documentation mentioned before please.</p>
<h1><a name=s8>8. File Menu</a></h1> <h1><a name=s8>8. File Menu</a></h1>
<h2><a name=ss8.1>8.1 New...</a></h2> <h2><a name=ss8.1>8.1 New...</a></h2>
<p>Creates a new emulation session. You're asked for a new KML script <p>Creates a new emulation session. You're asked for a KML script where
where you can select the calculator type and skin to emulate.</p> you can select the calculator type and skin to emulate.</p>
<h2><a name=ss8.2>8.2 Open...</a></h2> <h2><a name=ss8.2>8.2 Open...</a></h2>
<p>Opens an existing emulation session. The emulation continues at the <p>Opens a previously saved emulation session. The emulation continues
same position where the loaded session was aborted. Loading emulation at the same position where the session was aborted. Loading emulation
sessions made with a different ROM revision may <u>destroy</u> the memory sessions made with a different ROM revision may <u>destroy</u> the memory
content or may cause other unpredictable results.</p> content or may cause other unpredictable results.</p>
<h2><a name=ss8.3>8.3 Save</a></h2> <h2><a name=ss8.3>8.3 Save</a></h2>
<p>Saves the current running session with the actual name.</p> <p>Saves the current session with the actual name.</p>
<h2><a name=ss8.4>8.4 Save As...</a></h2> <h2><a name=ss8.4>8.4 Save As...</a></h2>
<p>Saves the current running session with a new name. You're also get in <p>Saves the current session with a new name. You're also get this
this dialog when you Exit a new session without a state file name.</p> dialog when you Exit a new session without a state file name.</p>
<h2><a name=ss8.5>8.5 Close</a></h2> <h2><a name=ss8.5>8.5 Close</a></h2>
<p>Closes the current session without closing the emulator.</p> <p>Closes the current session without closing the emulator.</p>
<h2><a name=ss8.6>8.6 Settings</a></h2> <h2><a name=ss8.6>8.6 Settings</a></h2>
@ -294,10 +303,10 @@ h3 { color:red; font-size:1.1em; }
mouse is moved over the emulator window, the emulator is getting the mouse is moved over the emulator window, the emulator is getting the
focus and popping up into foreground.</p></li> focus and popping up into foreground.</p></li>
<li><i>Single Instance</i> <li><i>Single Instance</i>
<p>When this option is checked, the program is only allowed to run in <p>When this option is checked, only one instance of the emulator can
a single instance. If another running instance is detected, the detected be started. If another running instance is detected, the detected
instance is set into foreground as active window and get a request to instance is set into foreground as active window and get a request to
change his state file to the given one by the current instance. Finally change his state file to the given one by the current instance. Then
the current instance is terminated.</p></li> the current instance is terminated.</p></li>
<li><i>Automatically Save Files</i> <li><i>Automatically Save Files</i>
<p>When this option is checked, the current state file will automatically <p>When this option is checked, the current state file will automatically
@ -305,14 +314,15 @@ h3 { color:red; font-size:1.1em; }
emulator program.</p></li> emulator program.</p></li>
<li><i>Automatically Save Files On Exit</i> <li><i>Automatically Save Files On Exit</i>
<p>When this option is checked, the current state file will be saved <p>When this option is checked, the current state file will be saved
automatically at the end when the emulator program is closed.</p></li> automatically when the emulator program is closed.</p></li>
<li><i>Show Load Object Warning</i> <li><i>Show Load Object Warning</i>
<p>When this option is checked, you'll get a warning message box when you <p>When this option is checked, you'll get a warning message box when you
try to load an object with the <i>Load Object...</i> menu command. If try to load an object with the <i>Load Object...</i> menu command. If
this option is unchecked, the warning will be skipped.</p></li> this option is unchecked, the warning will be skipped.</p></li>
<li><i>Always Show KML Compilation Result</i> <li><i>Always Show KML Compilation Result</i>
<p>When this option is checked, you see the results of the KML <p>When this option is checked, you see the results of the KML
(Keyboard Macro Language) interpreter at every KML script load.</p></li> (Keyboard Mapping Language) interpreter at every KML script load.
</p></li>
</ul> </ul>
<h4>8.6.1.2 Section Style</h4> <h4>8.6.1.2 Section Style</h4>
<ul> <ul>
@ -385,21 +395,24 @@ h3 { color:red; font-size:1.1em; }
</ul> </ul>
<h3><a name=ss8.6.3>8.6.3 Settings Peripheral</a></h3> <h3><a name=ss8.6.3>8.6.3 Settings Peripheral</a></h3>
<h4>8.6.3.1 Section Sound</h4> <h4>8.6.3.1 Section Sound</h4>
<p>A new implementation of the sound engine made ROM patches for sound <p>A new implementation of the sound engine made ROM patches for sound
output obsolete. The new sound engine emulates the behavior of the beeper output obsolete. The new sound engine emulates the behaviour of the
output ports and only work in connection with a sound card. Using the beeper output ports and only work in connection with a sound card.
internal PC speaker isn't possible any more. The old beeper method with a Using the legacy PC speaker mode isn't possible any more. The old
ROM patch is still working but deprecated, it's strongly recommended to beeper method with a ROM patch is still working but deprecated, it's
remove all beep patches from your current KML scripts to enable the new strongly recommended to remove all beep patches from your current KML
sound engine. The support of the old sound implementation by a ROM patch scripts to enable the new sound engine. The support of the old sound
maybe removed in later versions of the emulator and remaining beep implementation by a ROM patch maybe removed in later versions of the
patches will corrupt the ROM with an illegal opcode then. emulator and remaining beep patches will corrupt the ROM with an
illegal opcode then. Actually the program informs you when
detecting ROM beep patches by opening the &quot;KML Script Compilation
Result&quot; dialog. To prevent this, remove the ROM beep patches
from the KML script.
</p> </p>
<p> <p>For the sound generation the calculator must know his own CPU strobe
For the sound generation the calculator must know his own CPU strobe
frequency. On the real calculator the speed depends on various settings frequency. On the real calculator the speed depends on various settings
like component tolerances, actual temperature, humidity and other like component tolerances, actual temperature, humidity and other
variables. The resulting speed is measured by the calculator firmware variables. The actual speed is measured by the calculator firmware
at a cold- or at a warmstart and stored in the =CSPEED variable. The at a cold- or at a warmstart and stored in the =CSPEED variable. The
content of this calculator variable has direct influence on the content of this calculator variable has direct influence on the
resulting frequency and duration. On the emulator the HP48SX CPU resulting frequency and duration. On the emulator the HP48SX CPU
@ -414,27 +427,24 @@ h3 { color:red; font-size:1.1em; }
frequency registry content has been changed since the last frequency registry content has been changed since the last
measurement, the =CSPEED variable of this session file may contain measurement, the =CSPEED variable of this session file may contain
a wrong frequency value. You easily may discover this by measuring a wrong frequency value. You easily may discover this by measuring
the real duration of a 10s beep. Is the difference to 10s less the real duration of a 10s beep. A deviance less than 1s is ok,
than 1s everything is ok, if not, you should perform a otherwise you should perform a <u style="color:red">warmstart</u>
<u style="color:red">warmstart</u> of the calculator in this of the calculator in this session file. Alternatively you may
session file. Alternatively you may execute a execute a <a href=#ss9.6>Reset Calculator</a>. This recalls the
<a href=#ss9.6>Reset Calculator</a>. This recalls the measuring measuring routine and save the result in the speed variable. Both
routine and save the result in the speed variable. Both restart restart variants purge the stack content!
variants purge the stack content!
</p> </p>
<ul> <ul>
<li><i>Volume</i> <li><i>Volume</i>
<p>The output volume can be selected with the Volume slider relative to <p>The output volume can be set with the Volume slider relative to
the Master Volume control. the Windows Master Volume control.
</p></li> </p></li>
<li><i>Device</i> <li><i>Device</i>
<p>By default the sound device is set to &quot;Standard Audio&quot;, but <p>By default the sound device is set to &quot;Standard Audio&quot;,
you can also manually choose the output device. The device name is but you can also manually choose the output device. When you change
somehow cut since Window Vista, but the method of reading the device the Standard Audio device in the Operating System settings dialog,
name is used for backwards compatibility to older versions of the the internal device numbering may change, and so the manually selected
Operating System. When you change the Standard Audio device in the audio device.</p></li>
Operating System settings dialog, the internal device numbering may
change, and so the manually selected audio device.</p></li>
</ul> </ul>
<h4>8.6.3.2 Section Infrared Printer</h4> <h4>8.6.3.2 Section Infrared Printer</h4>
<p>The emulator has the ability to print data to a HP82240A/B printer <p>The emulator has the ability to print data to a HP82240A/B printer
@ -475,34 +485,34 @@ h3 { color:red; font-size:1.1em; }
<h2><a name=ss9.3>9.3 Copy Screen</a></h2> <h2><a name=ss9.3>9.3 Copy Screen</a></h2>
<p>Copy the screen content as bitmap to the clipboard.</p> <p>Copy the screen content as bitmap to the clipboard.</p>
<h2><a name=ss9.4>9.4 Copy Stack</a></h2> <h2><a name=ss9.4>9.4 Copy Stack</a></h2>
<p>This is only valid for the HP48SX, HP48GX and the HP49G emulation.</p> <p>This menu item is enabled for the HP48SX, HP48GX and the HP49G
emulation.</p>
<p>Copy a &quot;Real Number&quot;, &quot;Complex Number&quot; or <p>Copy a &quot;Real Number&quot;, &quot;Complex Number&quot; or
&quot;String&quot; object in stack level 1 to the clipboard. On all &quot;String&quot; object in stack level 1 to the clipboard. On all
other objects, the command will be ignored. This prevents sending other objects, the command will be ignored. This prevents sending
binary objects to the clipboard.</p> binary objects to the clipboard.</p>
<p>The decimal point (radix mark) of &quot;Real Numbers&quot; in the <p>The decimal point (radix mark) of &quot;Real Numbers&quot; in the
clipboard is equal to the calculator setting. This point maybe clipboard is equal to the calculator setting. This is important when
important when you try to paste the numbers into a program using the you try to paste the numbers into a program using the locale settings
locale settings of the host operating system.</p> of the host operating system.</p>
<h2><a name=ss9.5>9.5 Paste Stack</a></h2> <h2><a name=ss9.5>9.5 Paste Stack</a></h2>
<p>This is only valid for the HP48SX, HP48GX and the HP49G emulation.</p> <p>This menu item is enabled for the HP48SX, HP48GX and the HP49G
emulation.</p>
<p>Paste the text field content of the clipboard to stack level 1 of <p>Paste the text field content of the clipboard to stack level 1 of
the emulated calculator. If the clipboard content is representing a the emulated calculator. If the clipboard content is representing a
real number, the number will be saved as &quot;Real Number&quot; real number, the number will be saved as &quot;Real Number&quot;
object. Is the content a complex number object, the number will be object. Is the content a complex number object, the number will be
saved as &quot;Complex Number&quot; object, in all other cases as saved as &quot;Complex Number&quot; object, otherwise cases as
&quot;String&quot; object.</p> &quot;String&quot; object.</p>
<p>To import &quot;Real or Complex Numbers&quot; from the clipboard, <p>To import &quot;Real or Complex Numbers&quot; from the clipboard, the
the decimal point (radix mark) of the clipboard and calculator decimal point (radix mark) of the clipboard and calculator <u>must</u>
<u>must</u> be equal. A real or complex number is only detected in the match. A real or complex number is only detected in the case of valid
case of valid real number characters in the clipboard. Especially real number characters in the clipboard. Especially heading and tailing
heading and tailing white spaces aren't valid number characters white spaces aren't valid number characters also.</p>
also.</p> <p>Complex numbers must be in the form <i>(a,b)</i> when using the point
<p>Complex numbers must be in the form <i>(a,b)</i> when using the radix mark or in the form <i>(a;b)</i> when using the comma radix mark.
point radix mark or in the form <i>(a;b)</i> when using the comma The Cartesian or algebraic form <i>a+bi</i> is not supported.</p>
radix mark. The Cartesian or algebraic form <i>a+bi</i> is not <h2><a name=ss9.6>9.6 Reset Calculator</a></h2>
supported.</p>
<h2><a name=ss9.6>9.6 Reset Calculator</a></h2>
<p>This emulates the Reset pin of the internal CPU.</p> <p>This emulates the Reset pin of the internal CPU.</p>
<h2><a name=ss9.7>9.7 Backup</a></h2> <h2><a name=ss9.7>9.7 Backup</a></h2>
<h3><a name=ss9.7.1>9.7.1 Backup Save</a></h3> <h3><a name=ss9.7.1>9.7.1 Backup Save</a></h3>
@ -511,7 +521,7 @@ h3 { color:red; font-size:1.1em; }
<h3><a name=ss9.7.2>9.7.2 Backup Restore</a></h3> <h3><a name=ss9.7.2>9.7.2 Backup Restore</a></h3>
<p>This restores a previous saved emulator status without request. If you <p>This restores a previous saved emulator status without request. If you
changed the calculator model meanwhile, the emulator will switch back to changed the calculator model meanwhile, the emulator will switch back to
the old model.</p> the model used in the backup.</p>
<h3><a name=ss9.7.3>9.7.3 Backup Delete</a></h3> <h3><a name=ss9.7.3>9.7.3 Backup Delete</a></h3>
<p>This deletes the data in the backup slot.</p> <p>This deletes the data in the backup slot.</p>
<h1><a name=s10>10. View Menu</a></h1> <h1><a name=s10>10. View Menu</a></h1>
@ -525,22 +535,22 @@ h3 { color:red; font-size:1.1em; }
<p>Enter the address to disassemble in hexadecimal into the &quot;Address <p>Enter the address to disassemble in hexadecimal into the &quot;Address
(HEX)&quot; field and press &lt;Return&gt;. With the &quot;Next Address&quot; (HEX)&quot; field and press &lt;Return&gt;. With the &quot;Next Address&quot;
button the next opcode is disassembled. With the &quot;Copy Data&quot; button button the next opcode is disassembled. With the &quot;Copy Data&quot; button
you can copy all selected lines inside the list box to the clipboard.</p> you can copy all selected lines from the list box to the clipboard.</p>
<h2><a name=ss11.2>11.2 Debugger...</a></h2> <h2><a name=ss11.2>11.2 Debugger...</a></h2>
<p>The assembler code debugger of the emulator. For more details refer to the <p>The assembler code debugger of the emulator. For more details refer to the
extra documentation of the debugger please.</p> extra documentation of the debugger please.</p>
<h2><a name=ss11.3>11.3 Macro</a></h2> <h2><a name=ss11.3>11.3 Macro</a></h2>
<p>The keyboard macro recorder unit.</p> <p>The keyboard macro recorder unit.</p>
<h3><a name=ss11.3.1>11.3.1 Macro Record...</a></h3> <h3><a name=ss11.3.1>11.3.1 Macro Record...</a></h3>
<p>Prompts a dialog to enter the macro file for the data to record. After <p>Prompts a dialog to enter the macro file for the data to record. After
accepting the confirm message, every key event is recorded into the macro accepting the confirm message, every key event is recorded into the macro
file with it's time information.</p> file with it's time information.</p>
<h3><a name=ss11.3.2>11.3.2 Macro Play...</a></h3> <h3><a name=ss11.3.2>11.3.2 Macro Play...</a></h3>
<p>Prompts a dialog box to ask for the keyboard macro file to play. The <p>Prompts a dialog box to ask for the keyboard macro file to play. The
replay starts immediately after selecting the file.</p> replay starts immediately after opening the selected file.</p>
<h3><a name=ss11.3.3>11.3.3 Macro Stop</a></h3> <h3><a name=ss11.3.3>11.3.3 Macro Stop</a></h3>
<p>Stops recording or replaying a keyboard macro file.</p> <p>Stops recording or replaying a keyboard macro file.</p>
<h3><a name=ss11.3.4>11.3.4 Macro Settings...</a></h3> <h3><a name=ss11.3.4>11.3.4 Macro Settings...</a></h3>
<p>Settings for the Macro Replay mode</p> <p>Settings for the Macro Replay mode</p>
<ul> <ul>
<li><i>Real</i> <li><i>Real</i>
@ -550,9 +560,9 @@ h3 { color:red; font-size:1.1em; }
</ul> </ul>
<h1><a name=s12>12. Help Menu</a></h1> <h1><a name=s12>12. Help Menu</a></h1>
<h2><a name=ss12.1>12.1 Help Topics</a></h2> <h2><a name=ss12.1>12.1 Help Topics</a></h2>
<p>Call this document.</p> <p>Show this document.</p>
<h2><a name=ss12.2>12.2 About Emu48...</a></h2> <h2><a name=ss12.2>12.2 About Emu48...</a></h2>
<p>The version, copyright and license message...</p> <p>Show the version, copyright and license message...</p>
<h1><a name=s13>13. DDE Server</a></h1> <h1><a name=s13>13. DDE Server</a></h1>
<p>Emu48 has an integrated DDE server to transmit data from and to the HP <p>Emu48 has an integrated DDE server to transmit data from and to the HP
stack. Because only the HP48 and HP49 have a stack, all DDE transfers stack. Because only the HP48 and HP49 have a stack, all DDE transfers
@ -591,7 +601,7 @@ h3 { color:red; font-size:1.1em; }
</table> </table>
<h1><a name=s14>14. License</a></h1> <h1><a name=s14>14. License</a></h1>
<p>Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator<br> <p>Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator<br>
Copyright (C) 2018 Christoph Gie&szlig;elink</p> Copyright (C) 2019 Christoph Gie&szlig;elink</p>
<p>This program is free software; you can redistribute it and/or modify it <p>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 under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option) Software Foundation; either version 2 of the License, or (at your option)

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.61 Known bugs and restrictions of Emu48 V1.62
------------------------------------------ ------------------------------------------
- the following I/O bits aren't emulated (incomplete) - the following I/O bits aren't emulated (incomplete)
@ -47,4 +47,4 @@ Known bugs and restrictions of Emu48 V1.61
- 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/14/18 (c) by Christoph Gießelink, c dot giesselink at gmx dot de 10/15/19 (c) by Christoph Gießelink, c dot giesselink at gmx dot de

View file

@ -1,8 +1,13 @@
Service Pack 59+ based on Emu48 Service Pack 61 Service Pack 61+ based on Emu48 Service Pack 62
See CHANGES.TXT in Emu48 for full history. See CHANGES.TXT in Emu48 for full history.
Only changes specifically made to Emu48+ are shown below. Only changes specifically made to Emu48+ are shown below.
Service Pack 60+ for Emu48 Version 1.0
DISPLAY.C
- bugfix in function WriteToMainDisplay() to fix display corruption
Service Pack 55+ for Emu48 Version 1.0 Service Pack 55+ for Emu48 Version 1.0
DEBUGDLL.C DEBUGDLL.C
@ -42,7 +47,7 @@ MOPS.C
bit in the LCR (0x11C) register for apples; the Saturnator has no bit in the LCR (0x11C) register for apples; the Saturnator has no
ELBE bit simulation so the LSRQ bit in SRQ2 register is untouched ELBE bit simulation so the LSRQ bit in SRQ2 register is untouched
Service Pack 51 for Emu48 Version 1.0 Service Pack 51+ for Emu48 Version 1.0
EMU48DLL.C EMU48DLL.C
- bugfix in function DLLCreateWnd(), when starting an emulator - bugfix in function DLLCreateWnd(), when starting an emulator

View file

@ -35,6 +35,9 @@
#define CODELABEL 0x80000000 // label in code window #define CODELABEL 0x80000000 // label in code window
// trace log file modes
enum TRACE_MODE { TRACE_FILE_NEW = 0, TRACE_FILE_APPEND };
typedef struct CToolBarData typedef struct CToolBarData
{ {
WORD wVersion; WORD wVersion;
@ -81,6 +84,14 @@ static DWORD dwAdrMemFol = 0; // follow address memory window
static UINT uIDMap = ID_DEBUG_MEM_MAP; // current memory view mode static UINT uIDMap = ID_DEBUG_MEM_MAP; // current memory view mode
static BOOL bDbgTrace = FALSE; // enable trace output
static HANDLE hLogFile = NULL; // log file handle
static TCHAR szTraceFilename[MAX_PATH] = _T("trace.log"); // filename for trace file
static UINT uTraceMode = TRACE_FILE_NEW; // trace log file mode
static BOOL bTraceReg = TRUE; // enable register logging
static BOOL bTraceMmu = FALSE; // disable MMU logging
static BOOL bTraceOpc = TRUE; // enable opcode logging
static LONG lCharWidth; // width of a character (is a fix font) static LONG lCharWidth; // width of a character (is a fix font)
static HMENU hMenuCode,hMenuMem,hMenuStack;// handle of context menues static HMENU hMenuCode,hMenuMem,hMenuStack;// handle of context menues
@ -108,6 +119,12 @@ static BOOL OnInfoWoRegister(HWND hDlg);
static VOID UpdateProfileWnd(HWND hDlg); static VOID UpdateProfileWnd(HWND hDlg);
static BOOL OnMemLoadData(HWND hDlg); static BOOL OnMemLoadData(HWND hDlg);
static BOOL OnMemSaveData(HWND hDlg); static BOOL OnMemSaveData(HWND hDlg);
static VOID StartTrace(VOID);
static VOID StopTrace(VOID);
static VOID FlushTrace(VOID);
static VOID OutTrace(VOID);
static BOOL OnTraceSettings(HWND hDlg);
static BOOL OnTraceEnable(HWND hDlg);
//################ //################
//# //#
@ -1768,6 +1785,7 @@ BOOL CheckBreakpoint(DWORD dwAddr, DWORD dwRange, UINT nType)
VOID NotifyDebugger(INT nType) // update registers VOID NotifyDebugger(INT nType) // update registers
{ {
nRplBreak = nType; // save breakpoint type nRplBreak = nType; // save breakpoint type
FlushTrace(); // flush trace buffer
_ASSERT(hDlgDebug); // debug dialog box open _ASSERT(hDlgDebug); // debug dialog box open
PostMessage(hDlgDebug,WM_UPDATE,0,0); PostMessage(hDlgDebug,WM_UPDATE,0,0);
return; return;
@ -1861,6 +1879,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
HDC hDC; HDC hDC;
HFONT hFont; HFONT hFont;
HMENU hSysMenu; HMENU hSysMenu;
HMENU hDbgMenu;
INT i; INT i;
switch (message) switch (message)
@ -1870,6 +1889,15 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
if (bAlwaysOnTop) SetWindowPos(hDlg,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); 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))); SendMessage(hDlg,WM_SETICON,ICON_BIG,(LPARAM) LoadIcon(hApp,MAKEINTRESOURCE(IDI_EMU48)));
bDbgTrace = FALSE; // disable file trace
// load file trace settings
ReadSettingsString(_T("Debugger"),_T("TraceFile"),szTraceFilename,szTraceFilename,ARRAYSIZEOF(szTraceFilename));
uTraceMode = ReadSettingsInt(_T("Debugger"),_T("TraceFileMode"),uTraceMode);
bTraceReg = ReadSettingsInt(_T("Debugger"),_T("TraceRegister"),bTraceReg);
bTraceMmu = ReadSettingsInt(_T("Debugger"),_T("TraceMMU"),bTraceMmu);
bTraceOpc = ReadSettingsInt(_T("Debugger"),_T("TraceOpcode"),bTraceOpc);
// add Settings item to sysmenu // add Settings item to sysmenu
_ASSERT((IDM_DEBUG_SETTINGS & 0xFFF0) == IDM_DEBUG_SETTINGS); _ASSERT((IDM_DEBUG_SETTINGS & 0xFFF0) == IDM_DEBUG_SETTINGS);
_ASSERT(IDM_DEBUG_SETTINGS < 0xF000); _ASSERT(IDM_DEBUG_SETTINGS < 0xF000);
@ -1879,11 +1907,17 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
VERIFY(AppendMenu(hSysMenu,MF_STRING,IDM_DEBUG_SETTINGS,_T("Debugger Settings..."))); VERIFY(AppendMenu(hSysMenu,MF_STRING,IDM_DEBUG_SETTINGS,_T("Debugger Settings...")));
} }
hDbgMenu = GetMenu(hDlg); // menu of debugger dialog
hWndToolbar = CreateToolbar(hDlg); // add toolbar 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); CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_NOP3, bDbgNOP3 ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(GetMenu(hDlg),ID_BREAKPOINTS_RPL, bDbgRPL ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_DOCODE,bDbgCode ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(GetMenu(hDlg),ID_INTR_STEPOVERINT, bDbgSkipInt ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_RPL, bDbgRPL ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hDbgMenu,ID_INTR_STEPOVERINT, bDbgSkipInt ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hDbgMenu,ID_TRACE_ENABLE, bDbgTrace ? MF_CHECKED : MF_UNCHECKED);
EnableMenuItem(hDbgMenu,ID_TRACE_SETTINGS,bDbgTrace ? MF_GRAYED : MF_ENABLED);
hDlgDebug = hDlg; // handle for debugger dialog hDlgDebug = hDlg; // handle for debugger dialog
hEventDebug = CreateEvent(NULL,FALSE,FALSE,NULL); hEventDebug = CreateEvent(NULL,FALSE,FALSE,NULL);
if (hEventDebug == NULL) if (hEventDebug == NULL)
@ -1931,6 +1965,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
InitBsArea(hDlg); // init bank switcher list box InitBsArea(hDlg); // init bank switcher list box
DisableMenuKeys(hDlg); // set debug menu keys into run state DisableMenuKeys(hDlg); // set debug menu keys into run state
fnOutTrace = OutTrace; // function for file trace
RplReadNibble = GetMemNib; // get nibble function for RPL object viewer RplReadNibble = GetMemNib; // get nibble function for RPL object viewer
dwDbgStopPC = -1; // no stop address for goto cursor dwDbgStopPC = -1; // no stop address for goto cursor
@ -1949,6 +1984,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
case WM_DESTROY: case WM_DESTROY:
// SetHP48Time(); // update time & date // SetHP48Time(); // update time & date
nDbgState = DBG_OFF; // debugger inactive nDbgState = DBG_OFF; // debugger inactive
StopTrace(); // finish trace
bInterrupt = TRUE; // exit opcode loop bInterrupt = TRUE; // exit opcode loop
SetEvent(hEventDebug); SetEvent(hEventDebug);
if (pdwInstrArray) // free last instruction circular buffer if (pdwInstrArray) // free last instruction circular buffer
@ -1965,6 +2001,14 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
GetWindowPlacement(hDlg, &wndpl); GetWindowPlacement(hDlg, &wndpl);
nDbgPosX = wndpl.rcNormalPosition.left; nDbgPosX = wndpl.rcNormalPosition.left;
nDbgPosY = wndpl.rcNormalPosition.top; nDbgPosY = wndpl.rcNormalPosition.top;
// save file trace settings
WriteSettingsString(_T("Debugger"),_T("TraceFile"),szTraceFilename);
WriteSettingsInt(_T("Debugger"),_T("TraceFileMode"),uTraceMode);
WriteSettingsInt(_T("Debugger"),_T("TraceRegister"),bTraceReg);
WriteSettingsInt(_T("Debugger"),_T("TraceMMU"),bTraceMmu);
WriteSettingsInt(_T("Debugger"),_T("TraceOpcode"),bTraceOpc);
RplDeleteTable(); // delete rpl symbol table RplDeleteTable(); // delete rpl symbol table
DeleteObject(hFontBold); // delete bold font DeleteObject(hFontBold); // delete bold font
DestroyMenu(hMenuMainCode); DestroyMenu(hMenuMainCode);
@ -2023,6 +2067,8 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
case ID_BREAKPOINTS_NOP3: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgNOP3); case ID_BREAKPOINTS_NOP3: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgNOP3);
case ID_BREAKPOINTS_DOCODE: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgCode); case ID_BREAKPOINTS_DOCODE: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgCode);
case ID_BREAKPOINTS_RPL: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgRPL); case ID_BREAKPOINTS_RPL: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgRPL);
case ID_TRACE_SETTINGS: return OnTraceSettings(hDlg);
case ID_TRACE_ENABLE: return OnTraceEnable(hDlg);
case ID_INFO_LASTINSTRUCTIONS: return OnInfoIntr(hDlg); case ID_INFO_LASTINSTRUCTIONS: return OnInfoIntr(hDlg);
case ID_INFO_PROFILE: return OnProfile(hDlg); case ID_INFO_PROFILE: return OnProfile(hDlg);
case ID_INFO_WRITEONLYREG: return OnInfoWoRegister(hDlg); case ID_INFO_WRITEONLYREG: return OnInfoWoRegister(hDlg);
@ -2199,7 +2245,7 @@ static __inline BOOL OnFindOK(HWND hDlg,BOOL bASCII,DWORD *pdwAddrLast,INT nSear
#if defined _UNICODE #if defined _UNICODE
{ {
// Unicode to byte translation // Unicode to byte translation
LPTSTR szTmp = DuplicateString((LPTSTR) lpbySearch); LPTSTR szTmp = DuplicateString((LPCTSTR) lpbySearch);
if (szTmp != NULL) if (szTmp != NULL)
{ {
WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK,
@ -2719,7 +2765,6 @@ static INT_PTR CALLBACK Settings(HWND hDlg, UINT message, WPARAM wParam, LPARAM
} }
} }
return FALSE; return FALSE;
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam); UNREFERENCED_PARAMETER(lParam);
} }
@ -2783,7 +2828,6 @@ static INT_PTR CALLBACK NewValue(HWND hDlg, UINT message, WPARAM wParam, LPARAM
} }
} }
return FALSE; return FALSE;
UNREFERENCED_PARAMETER(wParam);
} }
static INT_PTR OnNewValue(LPTSTR lpszValue) static INT_PTR OnNewValue(LPTSTR lpszValue)
@ -2835,7 +2879,6 @@ static INT_PTR CALLBACK EnterAddr(HWND hDlg, UINT message, WPARAM wParam, LPARAM
} }
} }
return FALSE; return FALSE;
UNREFERENCED_PARAMETER(wParam);
} }
static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue) static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue)
@ -2888,7 +2931,6 @@ static INT_PTR CALLBACK EnterBreakpoint(HWND hDlg, UINT message, WPARAM wParam,
} }
} }
return FALSE; return FALSE;
UNREFERENCED_PARAMETER(wParam);
} }
static VOID OnEnterBreakpoint(HWND hDlg, BP_T *sValue) static VOID OnEnterBreakpoint(HWND hDlg, BP_T *sValue)
@ -3183,7 +3225,6 @@ static INT_PTR CALLBACK EditBreakpoint(HWND hDlg, UINT message, WPARAM wParam, L
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam); UNREFERENCED_PARAMETER(lParam);
} }
@ -3569,7 +3610,6 @@ static INT_PTR CALLBACK DebugMemLoad(HWND hDlg, UINT message, WPARAM wParam, LPA
} }
} }
return FALSE; return FALSE;
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam); UNREFERENCED_PARAMETER(lParam);
} }
@ -3577,7 +3617,6 @@ static BOOL OnMemLoadData(HWND hDlg)
{ {
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_MEMLOAD), hDlg, (DLGPROC)DebugMemLoad) == -1) if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_MEMLOAD), hDlg, (DLGPROC)DebugMemLoad) == -1)
AbortMessage(_T("DebugLoad Dialog Box Creation Error !")); AbortMessage(_T("DebugLoad Dialog Box Creation Error !"));
return -1; return -1;
} }
@ -3625,7 +3664,6 @@ static INT_PTR CALLBACK DebugMemSave(HWND hDlg, UINT message, WPARAM wParam, LPA
} }
} }
return FALSE; return FALSE;
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam); UNREFERENCED_PARAMETER(lParam);
} }
@ -3633,6 +3671,337 @@ static BOOL OnMemSaveData(HWND hDlg)
{ {
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_MEMSAVE), hDlg, (DLGPROC)DebugMemSave) == -1) if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_MEMSAVE), hDlg, (DLGPROC)DebugMemSave) == -1)
AbortMessage(_T("DebugSave Dialog Box Creation Error !")); AbortMessage(_T("DebugSave Dialog Box Creation Error !"));
return -1; return -1;
} }
//################
//#
//# Trace Log
//#
//################
static VOID StartTrace(VOID)
{
if (hLogFile == NULL)
{
SetCurrentDirectory(szEmuDirectory);
hLogFile = CreateFile(
szTraceFilename,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
(uTraceMode == TRACE_FILE_NEW) ? CREATE_ALWAYS : OPEN_ALWAYS,
0,
NULL);
SetCurrentDirectory(szCurrentDirectory);
if (hLogFile == INVALID_HANDLE_VALUE)
{
InfoMessage(_T("Unable to create trace log file."));
hLogFile = NULL;
return;
}
// goto end of file
SetFilePointer(hLogFile,0L,NULL,FILE_END);
}
return;
}
static VOID StopTrace(VOID)
{
if (hLogFile != NULL)
{
CloseHandle(hLogFile);
}
hLogFile = NULL;
return;
}
static VOID FlushTrace(VOID)
{
if (hLogFile != NULL)
{
VERIFY(FlushFileBuffers(hLogFile));
}
return;
}
static __inline void __cdecl PrintTrace(LPCTSTR lpFormat, ...)
{
TCHAR cOutput[1024];
DWORD dwWritten, dwRead;
va_list arglist;
va_start(arglist,lpFormat);
dwWritten = (DWORD) wvsprintf(cOutput,lpFormat,arglist);
va_end(arglist);
#if defined _UNICODE
{
// Unicode to byte translation
LPTSTR szTmp = DuplicateString(cOutput);
if (szTmp != NULL)
{
WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK,
szTmp, -1,
(LPSTR) cOutput, sizeof(cOutput), NULL, NULL);
free(szTmp);
}
}
#endif
WriteFile(hLogFile,cOutput,dwWritten,&dwRead,NULL);
return;
}
static VOID OutTrace(VOID)
{
enum MEM_MAPPING eMapMode;
LPCTSTR lpszName;
LPTSTR s,d;
TCHAR szBuffer[128];
TCHAR szOpc[8];
DWORD dwNxtAddr,dwOpcAddr;
UINT i;
if (hLogFile != NULL) // log file opened
{
if (bTraceReg) // show regs
{
INT nPos;
nPos = wsprintf(szBuffer,_T("\r\n A=%s"),RegToStr(Chipset.A,16));
nPos += wsprintf(&szBuffer[nPos],_T(" B=%s"),RegToStr(Chipset.B,16));
nPos += wsprintf(&szBuffer[nPos],_T(" C=%s"),RegToStr(Chipset.C,16));
wsprintf(&szBuffer[nPos],_T(" D=%s\r\n"),RegToStr(Chipset.D,16));
PrintTrace(szBuffer);
nPos = wsprintf(szBuffer,_T(" R0=%s"),RegToStr(Chipset.R0,16));
nPos += wsprintf(&szBuffer[nPos],_T(" R1=%s"),RegToStr(Chipset.R1,16));
nPos += wsprintf(&szBuffer[nPos],_T(" R2=%s"),RegToStr(Chipset.R2,16));
wsprintf(&szBuffer[nPos],_T(" R3=%s\r\n"),RegToStr(Chipset.R3,16));
PrintTrace(szBuffer);
PrintTrace(_T(" R4=%s D0=%05X D1=%05X P=%X CY=%d Mode=%c OUT=%03X IN=%04X\r\n"),
RegToStr(Chipset.R4,16),Chipset.d0,Chipset.d1,Chipset.P,Chipset.carry,
Chipset.mode_dec ? _T('D') : _T('H'),Chipset.out,Chipset.in);
PrintTrace(_T(" ST=%s MP=%d SR=%d SB=%d XM=%d IntrEn=%d KeyScan=%d BS=%02X\r\n"),
RegToStr(Chipset.ST,4),
(Chipset.HST & MP) != 0,(Chipset.HST & SR) != 0,(Chipset.HST & SB) != 0,(Chipset.HST & XM) != 0,
Chipset.inte,Chipset.intk,Chipset.Bank_FF & 0x7F);
// hardware stack content
PrintTrace(_T(" Stack="));
for (i = 1; i <= ARRAYSIZEOF(Chipset.rstk); ++i)
{
PrintTrace(_T(" %05X"), Chipset.rstk[(Chipset.rstkp-i)&7]);
}
PrintTrace(_T("\r\n"));
}
if (bTraceMmu) // show MMU
{
TCHAR szSize[8],szAddr[8];
if (!bTraceReg) // no regs
{
PrintTrace(_T("\r\n")); // add separator line
}
wsprintf(szAddr, Chipset.IOCfig ? _T("%05X") : _T("-----"),Chipset.IOBase);
PrintTrace(_T(" I/O=%s"),szAddr);
wsprintf(szSize, Chipset.P0Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P0Size^0xFF)<<12);
wsprintf(szAddr, Chipset.P0Cfig ? _T("%05X") : _T("-----"),Chipset.P0Base<<12);
PrintTrace(_T(" NCE2=%s/%s"),szSize,szAddr);
if (cCurrentRomType=='S')
{
wsprintf(szSize, Chipset.P1Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P1Size^0xFF)<<12);
wsprintf(szAddr, Chipset.P1Cfig ? _T("%05X") : _T("-----"),Chipset.P1Base<<12);
}
else
{
wsprintf(szSize, Chipset.BSCfg2 ? _T("%05X") : _T("-----"),(Chipset.BSSize^0xFF)<<12);
wsprintf(szAddr, Chipset.BSCfig ? _T("%05X") : _T("-----"),Chipset.BSBase<<12);
}
PrintTrace(_T(" CE1=%s/%s"),szSize,szAddr);
if (cCurrentRomType=='S')
{
wsprintf(szSize, Chipset.P2Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P2Size^0xFF)<<12);
wsprintf(szAddr, Chipset.P2Cfig ? _T("%05X") : _T("-----"),Chipset.P2Base<<12);
}
else
{
wsprintf(szSize, Chipset.P1Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P1Size^0xFF)<<12);
wsprintf(szAddr, Chipset.P1Cfig ? _T("%05X") : _T("-----"),Chipset.P1Base<<12);
}
PrintTrace(_T(" CE2=%s/%s"),szSize,szAddr);
if (cCurrentRomType=='S')
{
wsprintf(szSize, Chipset.BSCfg2 ? _T("%05X") : _T("-----"),(Chipset.BSSize^0xFF)<<12);
wsprintf(szAddr, Chipset.BSCfig ? _T("%05X") : _T("-----"),Chipset.BSBase<<12);
}
else
{
wsprintf(szSize, Chipset.P2Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P2Size^0xFF)<<12);
wsprintf(szAddr, Chipset.P2Cfig ? _T("%05X") : _T("-----"),Chipset.P2Base<<12);
}
PrintTrace(_T(" NCE3=%s/%s\r\n"),szSize,szAddr);
}
// disassemble line
eMapMode = GetMemMapType(); // get current map mode
SetMemMapType(MEM_MMU); // disassemble in mapped mode
// entry has a name
if (disassembler_symb && (lpszName = RplGetName(Chipset.pc)) != NULL)
{
PrintTrace(_T("=%s\r\n"),lpszName); // print address as label
}
dwNxtAddr = disassemble(Chipset.pc,szBuffer);
// in disassembly replace space characters
// between Opcode and Modifier with one TAB
if ((s = _tcschr(szBuffer,_T(' '))) != NULL)
{
// skip blanks
for (d = s; *d == _T(' '); ++d) { }
if (d == &szBuffer[8]) // on TAB position
{
*s++ = _T('\t'); // replace with TAB
// move the opcode modifier
while ((*s++ = *d++) != 0) { }
}
}
if (bTraceOpc) // show opcode nibbles
{
dwOpcAddr = Chipset.pc; // init address
// show opcode nibbles in a block of 5
for (i = 0; i < 5 && dwOpcAddr < dwNxtAddr; ++i)
{
szOpc[i] = cHex[GetMemNib(&dwOpcAddr)];
}
if (i == 1) // only 1 nibble written
{
szOpc[i++] = _T('\t'); // one additional TAB necessary
}
szOpc[i] = 0; // EOS
PrintTrace(_T("%05lX %s\t%s\r\n"),Chipset.pc,szOpc,szBuffer);
while (dwOpcAddr < dwNxtAddr) // decode rest of opcode
{
// show opcode nibbles in a block of 5
for (i = 0; i < 5 && dwOpcAddr < dwNxtAddr; ++i)
{
szOpc[i] = cHex[GetMemNib(&dwOpcAddr)];
}
szOpc[i] = 0; // EOS
PrintTrace(_T(" %s\r\n"),szOpc);
}
}
else // without opcode nibbles
{
PrintTrace(_T("%05lX\t%s\r\n"),Chipset.pc,szBuffer);
}
SetMemMapType(eMapMode); // switch back to old map mode
}
return;
}
//
// trace settings dialog
//
static BOOL OnBrowseTraceSettings(HWND hDlg)
{
TCHAR szBuffer[MAX_PATH];
OPENFILENAME ofn;
// get current content of file edit box
GetDlgItemText(hDlg,IDC_TRACE_FILE,szBuffer,ARRAYSIZEOF(szBuffer));
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hDlg;
ofn.lpstrFilter =
_T("Trace Log Files (*.log)\0*.log\0")
_T("All Files (*.*)\0*.*\0");
ofn.lpstrDefExt = _T("log");
ofn.nFilterIndex = 1;
ofn.lpstrFile = szBuffer;
ofn.nMaxFile = ARRAYSIZEOF(szBuffer);
ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT;
if (GetSaveFileName(&ofn))
{
SetDlgItemText(hDlg,IDC_TRACE_FILE,szBuffer);
}
return 0;
}
//
// trace settings
//
static INT_PTR CALLBACK TraceSettings(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
SetDlgItemText(hDlg,IDC_TRACE_FILE,szTraceFilename);
CheckDlgButton(hDlg,(uTraceMode == TRACE_FILE_NEW) ? IDC_TRACE_NEW : IDC_TRACE_APPEND,BST_CHECKED);
CheckDlgButton(hDlg,IDC_TRACE_REGISTER,bTraceReg);
CheckDlgButton(hDlg,IDC_TRACE_MMU,bTraceMmu);
CheckDlgButton(hDlg,IDC_TRACE_OPCODE,bTraceOpc);
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_TRACE_BROWSE:
return OnBrowseTraceSettings(hDlg);
case IDOK:
// get filename
GetDlgItemText(hDlg,IDC_TRACE_FILE,szTraceFilename,ARRAYSIZEOF(szTraceFilename));
// trace mode
uTraceMode = IsDlgButtonChecked(hDlg,IDC_TRACE_NEW) ? TRACE_FILE_NEW : TRACE_FILE_APPEND;
// trace content
bTraceReg = IsDlgButtonChecked(hDlg,IDC_TRACE_REGISTER);
bTraceMmu = IsDlgButtonChecked(hDlg,IDC_TRACE_MMU);
bTraceOpc = IsDlgButtonChecked(hDlg,IDC_TRACE_OPCODE);
// no break
case IDCANCEL:
EndDialog(hDlg,LOWORD(wParam));
return TRUE;
}
}
return FALSE;
UNREFERENCED_PARAMETER(lParam);
}
static BOOL OnTraceSettings(HWND hDlg)
{
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_TRACE), hDlg, (DLGPROC)TraceSettings) == -1)
AbortMessage(_T("TraceSettings Dialog Box Creation Error !"));
return -1;
}
static BOOL OnTraceEnable(HWND hDlg)
{
OnToggleMenuItem(hDlg,ID_TRACE_ENABLE,&bDbgTrace);
bDbgTrace ? StartTrace() : StopTrace();
EnableMenuItem(GetMenu(hDlg),ID_TRACE_SETTINGS,bDbgTrace ? MF_GRAYED : MF_ENABLED);
return 0;
}

View file

@ -214,7 +214,7 @@ BOOL CreateMainBitmap(LPCTSTR szFilename)
_ASSERT(hWindowDC != NULL); _ASSERT(hWindowDC != NULL);
VERIFY(hMainDC = CreateCompatibleDC(hWindowDC)); VERIFY(hMainDC = CreateCompatibleDC(hWindowDC));
if (hMainDC == NULL) return FALSE; // quit if failed if (hMainDC == NULL) return FALSE; // quit if failed
hMainBitmap = LoadBitmapFile(szFilename); hMainBitmap = LoadBitmapFile(szFilename,TRUE);
if (hMainBitmap == NULL) if (hMainBitmap == NULL)
{ {
DeleteDC(hMainDC); DeleteDC(hMainDC);
@ -249,7 +249,7 @@ BOOL CreateAnnunBitmap(LPCTSTR szFilename)
_ASSERT(hWindowDC != NULL); _ASSERT(hWindowDC != NULL);
VERIFY(hAnnunDC = CreateCompatibleDC(hWindowDC)); VERIFY(hAnnunDC = CreateCompatibleDC(hWindowDC));
if (hAnnunDC == NULL) return FALSE; // quit if failed if (hAnnunDC == NULL) return FALSE; // quit if failed
hAnnunBitmap = LoadBitmapFile(szFilename); hAnnunBitmap = LoadBitmapFile(szFilename,FALSE);
if (hAnnunBitmap == NULL) if (hAnnunBitmap == NULL)
{ {
DeleteDC(hAnnunDC); DeleteDC(hAnnunDC);

View file

@ -13,7 +13,7 @@
#include "kml.h" #include "kml.h"
#include "debugger.h" #include "debugger.h"
#define VERSION "1.60+" #define VERSION "1.61+"
#ifdef _DEBUG #ifdef _DEBUG
LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug"); LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug");
@ -41,6 +41,7 @@ static const LPCTSTR szLicence =
static BOOL bOwnCursor = FALSE; static BOOL bOwnCursor = FALSE;
static BOOL bTitleBar = TRUE; static BOOL bTitleBar = TRUE;
static BOOL bMouseButton = FALSE;
CRITICAL_SECTION csGDILock; // critical section for hWindowDC CRITICAL_SECTION csGDILock; // critical section for hWindowDC
@ -1787,28 +1788,19 @@ static VOID OnContextMenu(LPARAM lParam)
return; return;
} }
static BOOL OnNcHitTest(LPARAM lParam)
{
if (!bTitleBar || bClientWinMove) // no title bar or window movement over client enabled
{
POINT pt;
POINTSTOPOINT(pt,MAKEPOINTS(lParam)); // mouse position
VERIFY(ScreenToClient(hWnd,&pt)); // convert mouse into client position
if (pt.y >= 0) // client area
{
// hit area not over a button
return !MouseIsButton(pt.x,pt.y);
}
}
return FALSE;
}
static LRESULT OnLButtonDown(UINT nFlags, WORD x, WORD y) static LRESULT OnLButtonDown(UINT nFlags, WORD x, WORD y)
{ {
if (nMacroState == MACRO_PLAY) return 0; // playing macro if (nMacroState == MACRO_PLAY) return 0; // playing macro
if (nState == SM_RUN) MouseButtonDownAt(nFlags, x,y); if (nState == SM_RUN) MouseButtonDownAt(nFlags, x,y);
bMouseButton = MouseIsButton(x,y); // mouse is over button hit area
// no title bar or window movement over client enabled and hit area not over a button
if ((!bTitleBar || bClientWinMove) && nFlags == MK_LBUTTON && !bMouseButton)
{
// move window while holding the left mouse button
PostMessage(hWnd,WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(x,y));
}
return 0; return 0;
} }
@ -1816,6 +1808,7 @@ static LRESULT OnLButtonUp(UINT nFlags, WORD x, WORD y)
{ {
if (nMacroState == MACRO_PLAY) return 0; // playing macro if (nMacroState == MACRO_PLAY) return 0; // playing macro
if (nState == SM_RUN) MouseButtonUpAt(nFlags, x,y); if (nState == SM_RUN) MouseButtonUpAt(nFlags, x,y);
bMouseButton = FALSE;
return 0; return 0;
} }
@ -1851,6 +1844,7 @@ static LRESULT OnKeyDown(int nVirtKey, LPARAM lKeyData)
// call RunKey() only once (suppress autorepeat feature) // call RunKey() only once (suppress autorepeat feature)
if (nState == SM_RUN && (lKeyData & 0x40000000) == 0) if (nState == SM_RUN && (lKeyData & 0x40000000) == 0)
RunKey((BYTE)nVirtKey, TRUE); RunKey((BYTE)nVirtKey, TRUE);
bMouseButton = FALSE;
return 0; return 0;
} }
@ -1994,12 +1988,18 @@ LRESULT CALLBACK MainWndProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lPar
case SC_CLOSE: return OnFileExit(); case SC_CLOSE: return OnFileExit();
} }
break; break;
case WM_CONTEXTMENU: case WM_ENDSESSION:
case WM_NCRBUTTONUP: // session will end and any auto saving is enabled
OnContextMenu(lParam); if (wParam == TRUE && (bAutoSave || bAutoSaveOnExit))
{
SwitchToState(SM_INVALID); // hold emulation thread
if (szCurrentFilename[0] != 0) // has current filename
SaveDocument();
SwitchToState(SM_RUN); // on cancel restart emulation thread
}
break; break;
case WM_NCHITTEST: case WM_CONTEXTMENU:
if (OnNcHitTest(lParam)) return HTCAPTION; if (!bMouseButton) OnContextMenu(lParam);
break; break;
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
case WM_LBUTTONDOWN: return OnLButtonDown((UINT) wParam, LOWORD(lParam), HIWORD(lParam)); case WM_LBUTTONDOWN: return OnLButtonDown((UINT) wParam, LOWORD(lParam), HIWORD(lParam));

View file

@ -282,7 +282,7 @@ SOURCE=.\kml.c
# Begin Source File # Begin Source File
SOURCE=.\lodepng.c SOURCE=.\lodepng.c
# ADD CPP /D "LODEPNG_NO_COMPILE_ENCODER" /D "LODEPNG_NO_COMPILE_DISK" /D "LODEPNG_NO_COMPILE_ERROR_TEXT" /D "LODEPNG_NO_COMPILE_CPP" # ADD CPP /D "LODEPNG_NO_COMPILE_ENCODER" /D "LODEPNG_NO_COMPILE_DISK" /D "LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS" /D "LODEPNG_NO_COMPILE_ERROR_TEXT" /D "LODEPNG_NO_COMPILE_CPP"
# SUBTRACT CPP /YX /Yc /Yu # SUBTRACT CPP /YX /Yc /Yu
# End Source File # End Source File
# Begin Source File # Begin Source File

View file

@ -218,6 +218,7 @@ extern DWORD *pdwInstrArray;
extern WORD wInstrSize; extern WORD wInstrSize;
extern WORD wInstrWp; extern WORD wInstrWp;
extern WORD wInstrRp; extern WORD wInstrRp;
extern VOID (*fnOutTrace)(VOID);
extern VOID SuspendDebugger(VOID); extern VOID SuspendDebugger(VOID);
extern VOID ResumeDebugger(VOID); extern VOID ResumeDebugger(VOID);
extern VOID CheckSerial(VOID); extern VOID CheckSerial(VOID);
@ -290,7 +291,7 @@ extern BOOL LoadObject(LPCTSTR szFilename);
extern BOOL SaveObject(LPCTSTR szFilename); extern BOOL SaveObject(LPCTSTR szFilename);
extern BOOL LoadIconFromFile(LPCTSTR szFilename); extern BOOL LoadIconFromFile(LPCTSTR szFilename);
extern VOID LoadIconDefault(VOID); extern VOID LoadIconDefault(VOID);
extern HBITMAP LoadBitmapFile(LPCTSTR szFilename); extern HBITMAP LoadBitmapFile(LPCTSTR szFilename,BOOL bPalette);
extern HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol); extern HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol);
// Timer.c // Timer.c

View file

@ -206,6 +206,14 @@ BEGIN
TOPMARGIN, 7 TOPMARGIN, 7
BOTTOMMARGIN, 109 BOTTOMMARGIN, 109
END END
IDD_TRACE, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 240
TOPMARGIN, 7
BOTTOMMARGIN, 106
END
END END
#endif // APSTUDIO_INVOKED #endif // APSTUDIO_INVOKED
@ -654,6 +662,30 @@ BEGIN
PUSHBUTTON "Cancel",IDCANCEL,122,95,50,14 PUSHBUTTON "Cancel",IDCANCEL,122,95,50,14
END END
IDD_TRACE DIALOG DISCARDABLE 0, 0, 247, 113
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Trace Settings"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Log File:",IDC_STATIC,7,13,28,8
EDITTEXT IDC_TRACE_FILE,39,11,180,12,ES_AUTOHSCROLL
PUSHBUTTON "...",IDC_TRACE_BROWSE,220,11,20,12
CONTROL "&New",IDC_TRACE_NEW,"Button",BS_AUTORADIOBUTTON |
WS_GROUP | WS_TABSTOP,16,49,41,10
CONTROL "&Append",IDC_TRACE_APPEND,"Button",BS_AUTORADIOBUTTON,
16,64,41,10
GROUPBOX "File Mode",IDC_STATIC,7,32,113,53
CONTROL "&Register",IDC_TRACE_REGISTER,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,140,45,43,10
CONTROL "&MMU",IDC_TRACE_MMU,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,140,57,43,10
CONTROL "&Opcode",IDC_TRACE_OPCODE,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,140,69,43,10
GROUPBOX "Logging",IDC_STATIC,127,32,113,53
DEFPUSHBUTTON "OK",IDOK,62,92,50,14
PUSHBUTTON "Cancel",IDCANCEL,135,92,50,14
END
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
@ -691,8 +723,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,6,0,0 FILEVERSION 1,6,1,0
PRODUCTVERSION 1,6,0,0 PRODUCTVERSION 1,6,1,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -709,12 +741,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0" VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0"
VALUE "FileDescription", "HP38/39/40/48/49/50 Emulator\0" VALUE "FileDescription", "HP38/39/40/48/49/50 Emulator\0"
VALUE "FileVersion", "1, 6, 0, 0\0" VALUE "FileVersion", "1, 6, 1, 0\0"
VALUE "InternalName", "Emu48\0" VALUE "InternalName", "Emu48\0"
VALUE "LegalCopyright", "Copyright © 2019\0" VALUE "LegalCopyright", "Copyright © 2019\0"
VALUE "OriginalFilename", "Emu48.exe\0" VALUE "OriginalFilename", "Emu48.exe\0"
VALUE "ProductName", "Emu48\0" VALUE "ProductName", "Emu48\0"
VALUE "ProductVersion", "1, 6, 0, 0\0" VALUE "ProductVersion", "1, 6, 1, 0\0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
@ -896,6 +928,11 @@ BEGIN
BEGIN BEGIN
MENUITEM "&Step Over Interrupts", ID_INTR_STEPOVERINT MENUITEM "&Step Over Interrupts", ID_INTR_STEPOVERINT
END END
POPUP "&Trace"
BEGIN
MENUITEM "&Settings...", ID_TRACE_SETTINGS
MENUITEM "&Enable", ID_TRACE_ENABLE
END
POPUP "&Info" POPUP "&Info"
BEGIN BEGIN
MENUITEM "&Last Instructions...", ID_INFO_LASTINSTRUCTIONS MENUITEM "&Last Instructions...", ID_INFO_LASTINSTRUCTIONS

View file

@ -59,6 +59,8 @@ WORD wInstrSize = 256; // size of last instruction array
WORD wInstrWp; // write pointer of instruction array WORD wInstrWp; // write pointer of instruction array
WORD wInstrRp; // read pointer of instruction array WORD wInstrRp; // read pointer of instruction array
VOID (*fnOutTrace)(VOID) = NULL; // callback function for file trace
static INT nDbgRplBreak = BN_ASM; // flag for RPL breakpoint detection static INT nDbgRplBreak = BN_ASM; // flag for RPL breakpoint detection
static INT nDbgOldState = DBG_OFF; // old state of debugger for suspend/resume static INT nDbgOldState = DBG_OFF; // old state of debugger for suspend/resume
@ -99,6 +101,10 @@ static __inline VOID Debugger(VOID) // debugger part
UpdateDbgCycleCounter(); // update 64 bit cpu cycle counter UpdateDbgCycleCounter(); // update 64 bit cpu cycle counter
SaveInstrAddr(Chipset.pc); // save pc in last instruction buffer SaveInstrAddr(Chipset.pc); // save pc in last instruction buffer
if (fnOutTrace != NULL) // has a trace function
{
fnOutTrace(); // write file trace
}
nDbgRplBreak = BN_ASM; // notify ASM breakpoint nDbgRplBreak = BN_ASM; // notify ASM breakpoint

View file

@ -855,6 +855,7 @@ BOOL NewDocument(VOID)
if (!DisplayChooseKml(0)) goto restore; if (!DisplayChooseKml(0)) goto restore;
if (!InitKML(szCurrentKml,FALSE)) goto restore; if (!InitKML(szCurrentKml,FALSE)) goto restore;
Chipset.type = cCurrentRomType; Chipset.type = cCurrentRomType;
CrcRom(&Chipset.wRomCrc); // save fingerprint of loaded ROM
if (Chipset.type == '6' || Chipset.type == 'A') // HP38G if (Chipset.type == '6' || Chipset.type == 'A') // HP38G
{ {
@ -1805,7 +1806,7 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
return hpal; return hpal;
} }
static HBITMAP DecodeBmp(LPBMPFILE pBmp) static HBITMAP DecodeBmp(LPBMPFILE pBmp,BOOL bPalette)
{ {
LPBITMAPFILEHEADER pBmfh; LPBITMAPFILEHEADER pBmfh;
LPBITMAPINFO pBmi; LPBITMAPINFO pBmi;
@ -1855,7 +1856,7 @@ static HBITMAP DecodeBmp(LPBMPFILE pBmp)
pBmi, DIB_RGB_COLORS)); pBmi, DIB_RGB_COLORS));
if (hBitmap == NULL) return NULL; if (hBitmap == NULL) return NULL;
if (hPalette == NULL) if (bPalette && hPalette == NULL)
{ {
hPalette = CreateBIPalette(&pBmi->bmiHeader); hPalette = CreateBIPalette(&pBmi->bmiHeader);
// save old palette // save old palette
@ -1886,7 +1887,7 @@ static BOOL ReadGifWord(LPBMPFILE pGif, INT *n)
return FALSE; return FALSE;
} }
static HBITMAP DecodeGif(LPBMPFILE pBmp,DWORD *pdwTransparentColor) static HBITMAP DecodeGif(LPBMPFILE pBmp,DWORD *pdwTransparentColor,BOOL bPalette)
{ {
// this implementation base on the GIF image file // this implementation base on the GIF image file
// decoder engine of Free42 (c) by Thomas Okken // decoder engine of Free42 (c) by Thomas Okken
@ -2380,7 +2381,7 @@ static HBITMAP DecodeGif(LPBMPFILE pBmp,DWORD *pdwTransparentColor)
_ASSERT(bDecoding == FALSE); // decoding successful _ASSERT(bDecoding == FALSE); // decoding successful
// normal decoding exit // normal decoding exit
if (hPalette == NULL) if (bPalette && hPalette == NULL)
{ {
hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi); hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi);
// save old palette // save old palette
@ -2397,7 +2398,7 @@ quit:
return hBitmap; return hBitmap;
} }
static HBITMAP DecodePng(LPBMPFILE pBmp) static HBITMAP DecodePng(LPBMPFILE pBmp,BOOL bPalette)
{ {
// this implementation use the PNG image file decoder // this implementation use the PNG image file decoder
// engine of Copyright (c) 2005-2018 Lode Vandevenne // engine of Copyright (c) 2005-2018 Lode Vandevenne
@ -2422,7 +2423,7 @@ static HBITMAP DecodePng(LPBMPFILE pBmp)
if (uError) goto quit; if (uError) goto quit;
ZeroMemory(&bmi,sizeof(bmi)); // init bitmap info ZeroMemory(&bmi,sizeof(bmi)); // init bitmap info
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = (LONG) uWidth; bmi.bmiHeader.biWidth = (LONG) uWidth;
bmi.bmiHeader.biHeight = (LONG) uHeight; bmi.bmiHeader.biHeight = (LONG) uHeight;
bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biPlanes = 1;
@ -2460,7 +2461,7 @@ static HBITMAP DecodePng(LPBMPFILE pBmp)
_ASSERT((DWORD) (pbyLine - pbyPixels) <= bmi.bmiHeader.biSizeImage); _ASSERT((DWORD) (pbyLine - pbyPixels) <= bmi.bmiHeader.biSizeImage);
} }
if (hPalette == NULL) if (bPalette && hPalette == NULL)
{ {
hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi); hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi);
// save old palette // save old palette
@ -2482,7 +2483,7 @@ quit:
return hBitmap; return hBitmap;
} }
HBITMAP LoadBitmapFile(LPCTSTR szFilename) HBITMAP LoadBitmapFile(LPCTSTR szFilename,BOOL bPalette)
{ {
HANDLE hFile; HANDLE hFile;
HANDLE hMap; HANDLE hMap;
@ -2513,7 +2514,7 @@ HBITMAP LoadBitmapFile(LPCTSTR szFilename)
// check for bitmap file header "BM" // check for bitmap file header "BM"
if (Bmp.dwFileSize >= 2 && *(WORD *) Bmp.pbyFile == 0x4D42) if (Bmp.dwFileSize >= 2 && *(WORD *) Bmp.pbyFile == 0x4D42)
{ {
hBitmap = DecodeBmp(&Bmp); hBitmap = DecodeBmp(&Bmp,bPalette);
break; break;
} }
@ -2521,14 +2522,14 @@ HBITMAP LoadBitmapFile(LPCTSTR szFilename)
if ( Bmp.dwFileSize >= 6 if ( Bmp.dwFileSize >= 6
&& (memcmp(Bmp.pbyFile,"GIF87a",6) == 0 || memcmp(Bmp.pbyFile,"GIF89a",6) == 0)) && (memcmp(Bmp.pbyFile,"GIF87a",6) == 0 || memcmp(Bmp.pbyFile,"GIF89a",6) == 0))
{ {
hBitmap = DecodeGif(&Bmp,&dwTColor); hBitmap = DecodeGif(&Bmp,&dwTColor,bPalette);
break; break;
} }
// check for PNG file header // check for PNG file header
if (Bmp.dwFileSize >= 8 && memcmp(Bmp.pbyFile,"\x89PNG\r\n\x1a\n",8) == 0) if (Bmp.dwFileSize >= 8 && memcmp(Bmp.pbyFile,"\x89PNG\r\n\x1a\n",8) == 0)
{ {
hBitmap = DecodePng(&Bmp); hBitmap = DecodePng(&Bmp,bPalette);
break; break;
} }

View file

@ -895,6 +895,8 @@ static KmlLine* ParseLines(BOOL bInclude)
if (eToken == TOK_INCLUDE) if (eToken == TOK_INCLUDE)
{ {
LPTSTR szFilename; LPTSTR szFilename;
UINT nLexLineKml;
eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString' eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString'
if (eToken != TOK_STRING) // not a string (token don't begin with ") if (eToken != TOK_STRING) // not a string (token don't begin with ")
{ {
@ -903,6 +905,7 @@ static KmlLine* ParseLines(BOOL bInclude)
} }
szFilename = szLexString; // save pointer to allocated memory szFilename = szLexString; // save pointer to allocated memory
szLexString = NULL; szLexString = NULL;
nLexLineKml = nLexLine; // save line number
eToken = Lex(LEX_PARAM); // decode argument eToken = Lex(LEX_PARAM); // decode argument
if (eToken != TOK_EOL) if (eToken != TOK_EOL)
{ {
@ -925,7 +928,10 @@ static KmlLine* ParseLines(BOOL bInclude)
} }
free(szFilename); // free filename string free(szFilename); // free filename string
if (pLine == NULL) // parsing error if (pLine == NULL) // parsing error
{
nLexLine = nLexLineKml; // restore line number
goto abort; goto abort;
}
while (pLine->pNext) pLine=pLine->pNext; while (pLine->pNext) pLine=pLine->pNext;
continue; continue;
} }
@ -1096,6 +1102,8 @@ static KmlBlock* ParseBlocks(BOOL bInclude, BOOL bEndTokenEn)
if (eToken == TOK_INCLUDE) if (eToken == TOK_INCLUDE)
{ {
LPTSTR szFilename; LPTSTR szFilename;
UINT nLexLineKml;
eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString' eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString'
if (eToken != TOK_STRING) // not a string (token don't begin with ") if (eToken != TOK_STRING) // not a string (token don't begin with ")
{ {
@ -1104,6 +1112,7 @@ static KmlBlock* ParseBlocks(BOOL bInclude, BOOL bEndTokenEn)
} }
szFilename = szLexString; // save pointer to allocated memory szFilename = szLexString; // save pointer to allocated memory
szLexString = NULL; szLexString = NULL;
nLexLineKml = nLexLine; // save line number
eToken = Lex(LEX_PARAM); // decode argument eToken = Lex(LEX_PARAM); // decode argument
if (eToken != TOK_EOL) if (eToken != TOK_EOL)
{ {
@ -1117,7 +1126,10 @@ static KmlBlock* ParseBlocks(BOOL bInclude, BOOL bEndTokenEn)
pBlock = pFirst = IncludeBlocks(bInclude,szFilename); pBlock = pFirst = IncludeBlocks(bInclude,szFilename);
free(szFilename); // free filename string free(szFilename); // free filename string
if (pBlock == NULL) // parsing error if (pBlock == NULL) // parsing error
{
nLexLine = nLexLineKml; // restore line number
goto abort; goto abort;
}
while (pBlock->pNext) pBlock = pBlock->pNext; while (pBlock->pNext) pBlock = pBlock->pNext;
continue; continue;
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -33,6 +33,7 @@
#define IDD_DEBUG_MEMSAVE 127 #define IDD_DEBUG_MEMSAVE 127
#define IDD_DEBUG_MEMLOAD 128 #define IDD_DEBUG_MEMLOAD 128
#define IDD_DEBUG_SETTINGS 129 #define IDD_DEBUG_SETTINGS 129
#define IDD_TRACE 130
#define IDC_REALSPEED 1000 #define IDC_REALSPEED 1000
#define IDC_GRAYSCALE 1001 #define IDC_GRAYSCALE 1001
#define IDC_ALWAYSONTOP 1002 #define IDC_ALWAYSONTOP 1002
@ -169,6 +170,13 @@
#define IDC_MACRO_MANUAL 1133 #define IDC_MACRO_MANUAL 1133
#define IDC_SOUND_SLIDER 1134 #define IDC_SOUND_SLIDER 1134
#define IDC_SOUND_DEVICE 1135 #define IDC_SOUND_DEVICE 1135
#define IDC_TRACE_FILE 1136
#define IDC_TRACE_BROWSE 1137
#define IDC_TRACE_NEW 1138
#define IDC_TRACE_APPEND 1139
#define IDC_TRACE_REGISTER 1140
#define IDC_TRACE_MMU 1141
#define IDC_TRACE_OPCODE 1142
#define ID_FILE_NEW 40001 #define ID_FILE_NEW 40001
#define ID_FILE_OPEN 40002 #define ID_FILE_OPEN 40002
#define ID_FILE_SAVE 40003 #define ID_FILE_SAVE 40003
@ -239,15 +247,17 @@
#define ID_INFO_LASTINSTRUCTIONS 40069 #define ID_INFO_LASTINSTRUCTIONS 40069
#define ID_INFO_PROFILE 40070 #define ID_INFO_PROFILE 40070
#define ID_INFO_WRITEONLYREG 40071 #define ID_INFO_WRITEONLYREG 40071
#define ID_TRACE_SETTINGS 40072
#define ID_TRACE_ENABLE 40073
#define ID_FILE_MRU_FILE1 40100 #define ID_FILE_MRU_FILE1 40100
// Next default values for new objects // Next default values for new objects
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 130 #define _APS_NEXT_RESOURCE_VALUE 131
#define _APS_NEXT_COMMAND_VALUE 40072 #define _APS_NEXT_COMMAND_VALUE 40074
#define _APS_NEXT_CONTROL_VALUE 1136 #define _APS_NEXT_CONTROL_VALUE 1143
#define _APS_NEXT_SYMED_VALUE 109 #define _APS_NEXT_SYMED_VALUE 109
#endif #endif
#endif #endif