2000-07-16: Updated to version 1.20

This commit is contained in:
Gwenhael Le Moine 2024-03-19 22:36:03 +01:00
parent 2e85d27e43
commit 0f41d8fed0
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
43 changed files with 4176 additions and 1408 deletions

BIN
CARDCOPY.EXE Normal file

Binary file not shown.

57
CARDCOPY.TXT Normal file
View file

@ -0,0 +1,57 @@
CARDCOPY - A HP48 Port1 Import/Export Tool for Emu48
05/23/00 (c) by Christoph Gießelink, cgiess@swol.de
************
* CARDCOPY *
************
Emu48, when emulating a HP48, save the user, the port1 memory and other
information in one file (*.E48). But sometimes it's useful to import or to
export port1 data. CARDCOPY now allows you to import/export a 128KB card file
into/from the port1 memory of an Emu48 state file. The program can handle
HP48SX/GX state and 128KB card files (file size 256KB) as source or destination.
On all other file types you'll get an error. It's recommended to switch off the
emulated HP48 before importing port1 data into a state file. So you're sure that
the HP48 wasn't busy and, when you switch on the emulated calculator, the
changed card will be detected.
Remember: Don't import data when port1 is merged! This will corrupt memory.
Second, when you import data, all files that are saved in port1 are purged.
The syntax is: CARDCOPY <Sourcefile> <Destinationfile>
Some examples:
- SX.E48 , an Emu48 state file for a HP48SX
- GX.E48 , an Emu48 state file for a HP48GX
- RPLTOOLS.BIN , a 128KB port2 file
If you want to
- export the port1 content of SX.E48 to RPLTOOLS.BIN then type
CARDCOPY SX.E48 RPLTOOLS.BIN
- import the RPLTOOLS.BIN as port1 into GX.E48 then type
CARDCOPY RPLTOOLS.BIN GX.E48
- export the port1 content of SX.E48 to GX.48 then type
CARDCOPY SX.E48 GX.E48
***************
* LEGAL STUFF *
***************
CARDCOPY - A HP48 Port1 Import/Export Tool for Emu48
Copyright (C) 2000 Christoph Gießelink
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the license with this program in the file
"COPYING". If not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

View file

@ -34,7 +34,7 @@ End
Lcd
Zoom 2
Offset 20 52
Color 0 255 255 255
Color 0 255 255 255 # character color table
Color 1 255 255 255
Color 2 255 255 255
Color 3 255 255 255
@ -42,22 +42,22 @@ Lcd
Color 5 255 255 255
Color 6 255 255 255
Color 7 255 255 255
Color 8 240 240 240
Color 9 225 225 225
Color 10 210 210 210
Color 11 195 195 195
Color 12 180 180 180
Color 13 165 165 165
Color 14 150 150 150
Color 15 135 135 135
Color 16 120 120 120
Color 17 105 105 105
Color 18 90 90 90
Color 19 75 75 75
Color 20 60 60 60
Color 21 45 45 45
Color 22 30 30 30
Color 23 15 15 15
Color 8 255 255 255
Color 9 223 223 223
Color 10 179 171 171
Color 11 135 135 135
Color 12 91 91 91
Color 13 47 47 47
Color 14 0 0 0
Color 15 0 0 0
Color 16 0 0 0
Color 17 0 0 0
Color 18 0 0 0
Color 19 0 0 0
Color 20 0 0 0
Color 21 0 0 0
Color 22 0 0 0
Color 23 0 0 0
Color 24 0 0 0
Color 25 0 0 0
Color 26 0 0 0
@ -66,6 +66,38 @@ Lcd
Color 29 0 0 0
Color 30 0 0 0
Color 31 0 0 0
Color 32 255 255 255 # background color table
Color 33 255 255 255
Color 34 255 255 255
Color 35 255 255 255
Color 36 255 255 255
Color 37 255 255 255
Color 38 255 255 255
Color 39 255 255 255
Color 40 255 255 255
Color 41 255 255 255
Color 42 255 255 255
Color 43 255 255 255
Color 44 255 255 255
Color 45 255 255 255
Color 46 255 255 255
Color 47 232 232 232
Color 48 209 209 209
Color 49 186 186 186
Color 50 163 163 163
Color 51 140 140 140
Color 52 117 117 117
Color 53 94 94 94
Color 54 71 71 71
Color 55 48 48 48
Color 56 25 25 25
Color 57 2 2 2
Color 58 0 0 0
Color 59 0 0 0
Color 60 0 0 0
Color 61 0 0 0
Color 62 0 0 0
Color 63 0 0 0
End
Annunciator 1

View file

@ -26,25 +26,25 @@ End
Lcd
Zoom 2
Offset 20 52
Color 0 255 255 255
Color 0 255 255 255 # character color table
Color 1 255 255 255
Color 2 255 255 255
Color 3 240 240 240
Color 4 225 225 225
Color 5 210 210 210
Color 6 195 195 195
Color 7 180 180 180
Color 8 165 165 165
Color 9 150 150 150
Color 10 135 135 135
Color 11 120 120 120
Color 12 105 105 105
Color 13 90 90 90
Color 14 75 75 75
Color 15 60 60 60
Color 16 45 45 45
Color 17 30 30 30
Color 18 15 15 15
Color 4 216 216 216
Color 5 192 192 192
Color 6 168 168 168
Color 7 144 144 144
Color 8 120 120 120
Color 9 96 96 96
Color 10 72 72 72
Color 11 48 48 48
Color 12 24 24 24
Color 13 0 0 0
Color 14 0 0 0
Color 15 0 0 0
Color 16 0 0 0
Color 17 0 0 0
Color 18 0 0 0
Color 19 0 0 0
Color 20 0 0 0
Color 21 0 0 0
@ -58,6 +58,38 @@ Lcd
Color 29 0 0 0
Color 30 0 0 0
Color 31 0 0 0
Color 32 255 255 255 # background color table
Color 33 255 255 255
Color 34 255 255 255
Color 35 255 255 255
Color 36 255 255 255
Color 37 255 255 255
Color 38 255 255 255
Color 39 255 255 255
Color 40 255 255 255
Color 41 255 255 255
Color 42 255 255 255
Color 43 255 255 255
Color 44 255 255 255
Color 45 255 255 255
Color 46 230 230 230
Color 47 205 205 205
Color 48 180 180 180
Color 49 155 155 155
Color 50 130 130 130
Color 51 105 105 105
Color 52 80 80 80
Color 53 55 55 55
Color 54 30 30 30
Color 55 5 5 5
Color 56 0 0 0
Color 57 0 0 0
Color 58 0 0 0
Color 59 0 0 0
Color 60 0 0 0
Color 61 0 0 0
Color 62 0 0 0
Color 63 0 0 0
End
Annunciator 1

Binary file not shown.

View file

@ -1,7 +1,7 @@
Debugger in Emu48/Tools/Debugger...
-----------------------------------
This is a short description of the internal debugger of Emu48. The debugger is not perfect and/or complete. I provide it as it is. Please don't send me any suggestions or changes at the moment. If you have a better idea make it for yourself. Of course you're free to publish them or send me your changes.
This is a short description of the internal assembly debugger of Emu48. The debugger is not perfect and/or complete. I provide it as it is. Please don't send me any suggestions or changes at the moment. If you have a better idea make it for yourself. Of course you're free to publish them or send me your changes.
The debugger was designed to help costumers inspecting assembler code objects, a part that cannot be handled satisfactorily by the JAZZ package. Thanks to Mika Heiskanen and all the others supporting this great program.
@ -73,15 +73,20 @@ Toggle a code breakpoint at the cursor position in the code window.
- Edit breakpoints...
You get a sorted list of the current code breakpoints. With "Add" you can add a new, with "Delete" you can delete an existing breakpoint. Addresses greater than #FFFFF are cutted after the fifths nibble.
You get a sorted list of the current code and memory breakpoints. With "Add" you can add a new, with "Delete" you can delete an existing breakpoint. Addresses greater than #FFFFF are cutted after the fifths nibble. When adding a new breakpoint, you must select if this is a "Code", "Memory Access", "Memory Read" or "Memory Write" breakpoint.
- "Code" stop before opcode execution on this address
- "Memory Access" stop before reading or writing to the selected address
- "Memory Read" stop before reading the selected address
- "Memory Write" stop before writing to the selected address
- Clear all breakpoints
Clear all code breakpoints except the NOP3 ones.
Clear all breakpoints except the NOP3 ones.
- NOP3 code breakpoints
What are NOP3 code breakpoints? As you now user programs are loaded somewhere in memory and can be moved after a garbage collection. So it's very difficult to break a user program at a hard set breakpoint with F2. To solve this problem the debugger will stop emulation at a NOP3 opcode. So you can easily add a NOP3 command into your sources to force a break condition. To enable this you have to check this item.
What are NOP3 code breakpoints? As you know user programs are loaded somewhere in memory and can be moved after a garbage collection. So it's very difficult to break a user program at a hard set breakpoint with F2. To solve this problem the debugger will stop emulation at a NOP3 opcode. So you can easily add a NOP3 command into your sources to force a break condition. To enable this you have to check this item.
NOP3 and NOP3, what's the difference? The Saturn CPU has no NOP command, so NOP3 is an opcode that is three nibbles long and doesn't change a register. In the HP SASM.DOC document two different opcodes are defined for NOP3:
@ -115,8 +120,28 @@ CODE
GOVLNG =GETPTRLOOP
ENDCODE
- RPL breakpoints
3.) Code window
If this item is checked, the debugger stops program execution on every A=DAT0 A, D0=D0+ 5, PC=(A) sequence. This is the typical RPL exit sequence, so you're able to jump easily to the end of any RPL command.
3.) Menu Interrupts
- Step Over Interrupts
If this item is checked, interrupt handler code will be skipped. This option is useful when you don't want to debug the interrupt handler. But be careful, when you disable the interrupts all code until interrupt enable belong to the interrupt handler code and could't executed in single step any more. Code and memory breakpoints are still active.
You can also use this option if you want to quit the interrupt handler. Just check this option, press F7 for "Step Into", and uncheck the option again. The debugger stopped behind the RTI instruction.
4.) Menu Info
- Last Instructions...
This is a short viewer for the last 255 executed CPU addresses. The disassembled opcode maybe wrong, because only the CPU address of each command was saved and memory mapping may have changed meanwhile.
5.) Code window
This windows shows you the disassembled code. The line with the current PC is marked with a "->" between the address and the disassembly.
@ -141,16 +166,16 @@ Toggle a code breakpoint at the cursor position in the code window.
Set the PC to the cursor position. Be careful with this command, you change the execution order of the commands!
4.) Register window
6.) Register window
Here you can see the actual contents of the CPU registers. The values are only updated after a single step execution.
With the left mouse button you change the content of the register. On bit registers like CY and Mode the state changes immediately without any request.
5.) Memory window
7.) Memory window
This windows shows you the memory content.
This windows shows the memory content.
You can use the arrow, PAGE UP and PAGE DOWN keys to move the cursor to a memory position. With a double click on the left mouse button you change the content of the two addresses. When the memory position is read only (ROM) the content wouldn't change.
@ -177,13 +202,30 @@ Sets the cursor to the actual position of the D0 register.
Sets the cursor to the return address placed in the top level of the stack.
6.) Stack window
8.) Stack window
The content of the hardware stack is viewed here.
7.) Problems
9.) MMU window
The timers aren't updated in the single step mode at the moment. Please skip these parts with setting a code breakpoint behind the critical section and continue emulation with F5.
The configuration of the memory controllers is viewed here. The viewed addresses are the first configured addresses of the modules and may differ from the given address in the CONFIG command.
12/14/99 (c) by Christoph Gießelink, cgiess@swol.de
This example
LC(5) #C0000 128KB size
CONFIG
LC(5) #98765 start address of modul
CONFIG
will config a 128KB modul at address #80000 and not at the given address. So the MMU viewer will show you address #80000.
10.) Miscellaneous window
The Miscellaneous window show you the internal state of the interrupt flag, the 1ms keyboard handler and the contents of the Bank Switcher latch. The Bank Switcher item is only enabled on a HP48GX and a HP49G calculator. Only these versions have a latch inside. You see the loaded value of the address lines A6-A0. You have to ignore the last bit (A0), because it isn't wired to the six bit latch.
You can change the values by pressing the left mouse button over the old content.
06/13/00 (c) by Christoph Gießelink, cgiess@swol.de

BIN
EMU48.EXE

Binary file not shown.

150
EMU48.TXT
View file

@ -10,16 +10,16 @@
****************
Emu48 is distributed in 1 archive:
- Emu48-1_15.zip All files and sources
- Emu48-1_20.zip All files and sources
To install Emu48, just unzip Emu48-1_15.zip into an empty directory. When you
To install Emu48, just unzip Emu48-1_20.zip into an empty directory. When you
first run Emu48, it will detect the directory in which you installed it, and
will write its configuration to a file named Emu48.ini in your Windows
directory.
You can also update your current version with the Unofficial Service Packs:
- E48BP1x.ZIP New EXE-File
- E48SP1x.ZIP Sources of the Service Pack
- E48BP2x.ZIP New EXE-File
- E48SP2x.ZIP Sources of the Service Pack
Replace the original EXE file please.
@ -136,9 +136,9 @@ In some cases you have to fix Color 0 in your KML script file, because the
colors red and blue has been swapped in the "Lcd" section (bugfix in a previous
version). Don't use TRUELCD.KMI for emulating display contrast in your scripts.
It's not fully correct. The hardware contrast values are in the area from 0 to
31. But the HP48 ROMs bounds them to useful values. The S(X) ROM use only
display contrast values between 3 and 19 and the G(X) ROM values between 9 and
24.
31. But the ROMs bounds them to useful values. The HP48 S(X) ROM use only
display contrast values between 3 and 19 and the HP48 G(X) ROM values between 9
and 24.
****************
@ -147,8 +147,8 @@ display contrast values between 3 and 19 and the G(X) ROM values between 9 and
The command line syntax is "Emu48 [E48file [Port2file]]". The first parameter
sets the filename for the emulation data, the second parameter the Port2 file.
You're not able to set a Port2 file without setting the emulation data file. The
arguments are optional.
You're not able to set a Port 2 file without setting the emulation data file.
The arguments are optional.
*******************
@ -156,23 +156,23 @@ arguments are optional.
*******************
There are two ways to transfer files from or to the emulator. The one way is to
use the serial port to transfer the data directly from your HP48 to the
emulator. The second way is to load data, saved on your PC, into the stack of
the emulator. You can do this by using the Edit/Load Object... command or with
the file Drag and Drop feature. But there's one important restriction, the data
must a HP binary file (begin with HPHP48- or HPHP49-, this depends on your
emulated calculator)! If not, the data is load as string. The Edit/Save
Object... command will save the data in stack level 1 on the PC (always binary
mode). Be sure, when you use the second way for data transfer, that no program
is running on the emulator. The second way doesn't work on a HP38, because he
has no stack. So you can load aplets only from the serial port.
use the serial port to transfer the data directly from your HP to the emulator.
The second way is to load data, saved on your PC, into the stack of the
emulator. You can do this by using the Edit/Load Object... command or with the
file Drag and Drop feature. But there's one important restriction, the data must
a HP binary file (begin with HPHP48- or HPHP49-, this depends on your emulated
calculator)! If not, the data is load as string. The Edit/Save Object... command
will save the data in stack level 1 on the PC (always binary mode). Be sure,
when you use the second way for data transfer, that no program is running on the
emulator. The second way doesn't work on a HP38, because he has no stack. So you
can load aplets only from the serial port.
*****************
* DRAG AND DROP *
*****************
Dropping HP48 objects over the emulator window will load program files (like the
Dropping HP objects over the emulator window will load program files (like the
command "Load object...") on the stack. Be sure that the emulator isn't busy
before doing this.
@ -209,12 +209,28 @@ Port 2 will be write-protected. Thus you can transfer files very easily between
two calculators. This RAM card is used by both S/SX and G/GX types.
***********************
* FLASH ROM EMULATION *
***********************
The HP49G save the operation system a reprogramable memory, a so called flash
memory. The flash memory is divided into two parts, into the Operating System
and into a User Data area. The User Data area is viewed as Port 2 in the HP49G.
Emu48 saves the Port 2 data in the ROM file (normally ROM.E49). As default
setting the ROM file is writeable in the first instance of Emu48. When you open
another instance of a HP49G emulation the Port 2 area is READ ONLY, that mean
all changes in Port 2 are lost when you exit this instance. If you don't want to
save data in Port 2 and want to protect the operating systems from overwriting,
you're able protect the ROM file. To do this, close all Emu48 instances and set
the variable 'Writeable' defined in the Emu48.ini file, section [ROM] to zero.
***********************
* COPY / PASTE STRING *
***********************
With the menu items "Copy String" and "Paste String" in the "Edit" menu you're
able to copy HP48 string objects from the stack to the PC clipboard and vice
able to copy HP string objects from the stack to the PC clipboard and vice
versa.
@ -249,9 +265,9 @@ button.
The emulator time is synchronized with the PC time at startup of the emulator.
This may cause problems with other non original operating systems running on the
HP48. On S(X) calculators the address area #00052-#00070, on G(X) calculators
the address area #00058-#00076 in Port0 are rewritten with the actual time
information.
HP. On HP48 S(X) calculators the address area #00052-#00070, on all other
emulated calculators the address area #00058-#00076 in Port 0 are rewritten with
the actual time information.
*************
@ -268,28 +284,28 @@ again.
* REAL SPEED EMULATION *
************************
As you recognized the speed of the emulated HP48 is much faster than an original
HP48. The reason is, the assembler commands are emulated faster than the
original CPU can execute them. On one side this is a big advantage (faster
execution of programs) on the other side this cause many trouble. In Emu48 only
the timers work with the original speed. In result all commands like User-RPL
WAIT wait more or less the correct time. But many programs like shells or
editors use an own key handler to realize an autorepeat implementation. Normally
these programs use the execution time of each assembler command for waiting. On
Emu48 this time is much shorter, so the time between each key read is shorter as
well and you get a very fast key repetition. The editor ED from the JAZZ package
hasn't this problem, because the key input is synchronized with one of the
timers. To solve this problem Emu48 generally slow down emulation if a key is
pressed. To solve some other speed depending problems you are able to slow down
the whole emulation speed. There are two variables 'SXCycles=82' and
'GXCycles=123' defined in the Emu48.ini file, section [Emulator] which control
the "real" speed and key repetition slow down for each calculator type. Each
numeric value is representing the allowed CPU cycles in a 16384Hz time frame.
Because the used cycle statements (from SASM.DOC) in Emu48 doesn't correspond to
the real values of the CPU, the saved values are estimated by comparing the
execution time of a program to the real calculator. Increasing the value fitting
to your ROM will make the "real speed" HP faster and vice versa. No warranty to
the functionality of Emu48 when you go below the default values.
As you recognized the speed of the emulated HP is much faster than an original
one. The reason is, the assembler commands are emulated faster than the original
CPU can execute them. On one side this is a big advantage (faster execution of
programs) on the other side this cause many trouble. In Emu48 only the timers
work with the original speed. In result all commands like User-RPL WAIT wait
more or less the correct time. But many programs like shells or editors use an
own key handler to realize an autorepeat implementation. Normally these programs
use the execution time of each assembler command for waiting. On Emu48 this time
is much shorter, so the time between each key read is shorter as well and you
get a very fast key repetition. The editor ED from the JAZZ package hasn't this
problem, because the key input is synchronized with one of the timers. To solve
this problem Emu48 generally slow down emulation if a key is pressed. To solve
some other speed depending problems you are able to slow down the whole
emulation speed. There are two variables 'SXCycles=82' and 'GXCycles=123'
defined in the Emu48.ini file, section [Emulator] which control the "real" speed
and key repetition slow down for each calculator type. Each numeric value is
representing the allowed CPU cycles in a 16384Hz time frame. Because the used
cycle statements (from SASM.DOC) in Emu48 doesn't correspond to the real values
of the CPU, the saved values are estimated by comparing the execution time of a
program to the real calculator. Increasing the value fitting to your ROM will
make the "real speed" HP faster and vice versa. No warranty to the functionality
of Emu48 when you go below the default values.
*************************
@ -299,33 +315,33 @@ the functionality of Emu48 when you go below the default values.
The serial ports are emulated as well now. You may choose the same serial port
for wire and IR. Remember that the IR port only work with 2400 Baud. If you want
to change the serial port settings, but they are disabled, close the serial port
with the command CLOSEIO or power cycle the HP48 first.
with the command CLOSEIO or power cycle the HP first.
Now it's possible to make transfers between the HP48 and Emu48. If you have
problems with the connection please try the following. There's a simple way to
check if your serial port is used by another program. First disable the serial
settings in both combo boxes and very important close the settings dialog.
Reopen the settings dialog and choose the COM port in the wire combo box to the
port the HP48 is connected with. When you open this combo box you only see valid
(unused) serial ports. Don't use the IR combo box, it only works with 2400 Baud.
The next important thing are the serial settings of the HP48 and Emu48, they
must be equal. If this doesn't work then mostly there's a hardware or a resource
problem of the serial port. Check this with connecting the HP48 with a transfer
program you like on the same serial port.
Now it's possible to make transfers between the real calculator and Emu48. If
you have problems with the connection please try the following. There's a simple
way to check if your serial port is used by another program. First disable the
serial settings in both combo boxes and very important close the settings
dialog. Reopen the settings dialog and choose the COM port in the wire combo box
to the port the HP is connected with. When you open this combo box you only see
valid (unused) serial ports. Don't use the IR combo box, it only works with 2400
Baud. The next important thing are the serial settings of the real calculator
and Emu48, they must be equal. If this doesn't work then mostly there's a
hardware or a resource problem of the serial port. Check this with connecting
the HP with a transfer program you like on the same serial port.
****************
* DISASSEMBLER *
****************
With the internal disassembler you're able to disassemble the HP48 address area.
With the default Map setting the disassembler always see the mapped memory
address. If for example you configured the RAM at #00000 you will see the RAM
and not the ROM at this address. With the other Module settings you specify a
special module for disassembly. Each module will begin at address #00000 and
will not overlapped by other modules. For Port2 I use a linear address mode,
that means that the second port of a RAM card greater than 128KB is at address
#40000 (128 * 1024 * 2) and so on. The "Copy Data" button copies the selected
With the internal disassembler you're able to disassemble the Saturn chip
address area. With the default Map setting the disassembler always see the
mapped memory address. If for example you configured the RAM at #00000 you will
see the RAM and not the ROM at this address. With the other module settings you
specify a special module for disassembly. Each module use a linear address mode,
beginning at address #00000 and will not overlapped by other modules. So, for
example, you can access the second port of a HP48 RAM card greater than 128KB at
address #40000 (128 * 1024 * 2). The "Copy Data" button copies the selected
disassembler lines to the PC clipboard.
@ -389,7 +405,7 @@ Other graphics and scripts are available at Casey's Emu48 Graphics Page:
***************
Emu48 - An HP38/48/49 Emulator
Copyright (C) 1999 Sebastien Carlier & Christoph Gießelink
Copyright (C) 2000 Sebastien Carlier & Christoph Gießelink
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software

View file

@ -1,4 +1,4 @@
Known bugs and restrictions of Emu48 V1.15
Known bugs and restrictions of Emu48 V1.20
------------------------------------------
- the following I/O bits aren't emulated (incomplete)
@ -30,15 +30,26 @@ Known bugs and restrictions of Emu48 V1.15
-> all programs that run on a real calculator will run as well,
programs with incorrect DA19 / BEN handling may run on the
emulator but will crash on a real calculator
- no MP interrupt on card control circuit or timer restart
- no beeper support with OUT command -> all programs that aren't
use the "=makebeep" subroutine, like alarm wake up, have no sound
- beeper emulation, ATTN key doesn't work,
Windows 9x: plays only default sound event or standard system beep
- no infrared printer support
- problem with timer2 (8192Hz) emulation in Windows 2000, timer2
values may skip, so an emulated delay loop may take very very long
- memory window of debugger view some addresses in I/O register area
with invalid data
- Shell OS: clock isn't synchronized with real time
- HP49G: flash ROM is treated as ROM (no writing to flash memory)
-> writing to port 2:FLASH will crash the emulation!
- HP49G: the flash memory is emulated now with some restrictions
- first implementation, at the moment the flash memory is more a
simulation than an emulation
- no flash programming times, the flash state machine returns
immediately the ready signal
- only one write buffer, second not needed because of prior reason
- not fully tested, especially the status byte may sometimes
return incorrect values (error bits)
- quitting the emulator while programming the flash isn't allowed,
because the content of flash state machine isn't saved so far
12/14/99 (c) by Christoph Gießelink, cgiess@swol.de
07/10/00 (c) by Christoph Gießelink, cgiess@swol.de

139
sources/Cardcopy/CARDCOPY.C Normal file
View file

@ -0,0 +1,139 @@
/*
* cardcopy, (c) 2000 Christoph Giesselink (cgiess@swol.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#define VERSION "1.0"
#define FT_ERR 0 // illegal format
#define FT_NEW 1 // empty file
#define FT_SXGX 2 // Emu48 HP48SX/GX state file
#define FT_PORT 3 // 128KB port file
#define PORT1SIZE (128*1024*2) // file size of 128KB file
#define HP48SIG "Emu48 Document\xFE" // HP48 state file signature
UINT CheckType(char *lpszFileName)
{
BYTE pbyFileSignature[16];
HANDLE hFile;
DWORD FileSizeHigh,FileSizeLow;
UINT nType = FT_ERR;
hFile = CreateFile(lpszFileName,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FT_NEW;
// check filesize
FileSizeLow = GetFileSize(hFile,&FileSizeHigh);
if (FileSizeHigh == 0 && FileSizeLow == PORT1SIZE)
nType = FT_PORT;
// Read and Compare signature
ReadFile(hFile,pbyFileSignature,sizeof(pbyFileSignature),&FileSizeLow,NULL);
if (FileSizeLow == sizeof(pbyFileSignature) && strcmp(pbyFileSignature,HP48SIG) == 0)
nType = FT_SXGX;
CloseHandle(hFile);
return nType;
}
BOOL CopyData(HANDLE hFileSource,HANDLE hFileDest)
{
BYTE byBuffer[16];
INT i;
DWORD lBytes;
assert(PORT1SIZE % sizeof(byBuffer) == 0);
for (i = PORT1SIZE / sizeof(byBuffer); i > 0; --i)
{
ReadFile(hFileSource,byBuffer,sizeof(byBuffer),&lBytes,NULL);
if (lBytes != sizeof(byBuffer)) return TRUE;
WriteFile(hFileDest,byBuffer,sizeof(byBuffer),&lBytes,NULL);
if (lBytes != sizeof(byBuffer)) return TRUE;
}
return FALSE;
}
UINT main(int argc, char *argv[])
{
HANDLE hFileSource,hFileDest;
UINT nSourceType,nDestType;
printf("HP48 Port1 Import/Export Tool for Emu48 V" VERSION "\n");
if (argc != 3)
{
printf("\nUsage:\n\t%s <SourceFile> <DestinationFile>\n\n", argv[0]);
return 1;
}
// check source file type
nSourceType = CheckType(argv[1]);
if (nSourceType == FT_ERR)
{
printf("Error: Illegal source file type\n");
return 2;
}
// check destination file type
nDestType = CheckType(argv[2]);
if (nDestType == FT_ERR)
{
printf("Error: Illegal destination file type\n");
return 3;
}
// open source file
hFileSource = CreateFile(argv[1],GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
if (hFileSource != INVALID_HANDLE_VALUE)
{
hFileDest = CreateFile(argv[2],GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_ALWAYS,0,NULL);
if (hFileDest != INVALID_HANDLE_VALUE)
{
if (nSourceType == FT_SXGX) SetFilePointer(hFileSource,-PORT1SIZE,NULL,FILE_END);
if (nDestType == FT_SXGX) SetFilePointer(hFileDest ,-PORT1SIZE,NULL,FILE_END);
CopyData(hFileSource,hFileDest);
puts("Copy successful.");
CloseHandle(hFileDest);
}
else
{
printf("Error: Can't open destination file %s\n",argv[2]);
return 4;
}
CloseHandle(hFileSource);
}
else
{
printf("Error: Can't open source file %s\n",argv[1]);
return 5;
}
return 0;
}

View file

@ -0,0 +1,100 @@
# Microsoft Developer Studio Project File - Name="CARDCOPY" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=CARDCOPY - Win32 Release
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "CARDCOPY.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "CARDCOPY.mak" CFG="CARDCOPY - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "CARDCOPY - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "CARDCOPY - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "CARDCOPY - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir ".\Release"
# PROP Intermediate_Dir ".\Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x407 /d "NDEBUG"
# ADD RSC /l 0x407 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "CARDCOPY - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ".\Debug"
# PROP Intermediate_Dir ".\Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x407 /d "_DEBUG"
# ADD RSC /l 0x407 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "CARDCOPY - Win32 Release"
# Name "CARDCOPY - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CARDCOPY.C
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

View file

@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "CARDCOPY"=.\CARDCOPY.DSP - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View file

@ -4,20 +4,15 @@
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#define HP38G 0
#define HP48S 1
#define HP48G 2
HANDLE hFile;
HANDLE hMap;
HANDLE hOut;
LPBYTE pIn;
LPBYTE pRom;
DWORD dwSizeLo, dwSizeHi;
BYTE szVersion[16];
BOOL bUnpack = FALSE;
BOOL bSwap = FALSE;
BOOL bText = FALSE;
DWORD dwWritten;
WORD wCRC;
BOOL bIsGx;
WORD wType;
static WORD crc_table[16] =
{
@ -36,7 +31,7 @@ BOOL CheckCRC()
UINT i;
DWORD dwBase = 0x00000;
UINT nPass = 0;
UINT nPasses = bIsGx?2:1;
UINT nPasses = (wType != HP48S)?2:1;
again:
@ -94,32 +89,58 @@ static DWORD Asc2Nib5(LPSTR lpBuf)
|((DWORD)Asc2Nib(lpBuf[4])));
}
static BOOL IsHP(DWORD dwAddress)
{
char cH = (pRom[dwAddress + 1] << 4) | pRom[dwAddress];
char cP = (pRom[dwAddress + 3] << 4) | pRom[dwAddress + 2];
return cH == 'H' && cP == 'P';
}
UINT main(int argc, char *argv[])
{
HANDLE hFile;
HANDLE hMap;
HANDLE hOut;
LPBYTE pIn;
DWORD dwSizeLo;
BYTE szVersion[16];
DWORD dwWritten;
UINT i,uLen;
DWORD dwAddress;
DWORD dwAddrOffset = 0x00000;
BOOL bFormatDetected = FALSE;
BOOL bUnpack = FALSE;
BOOL bSwap = FALSE;
BOOL bText = FALSE;
BOOL bDA19 = FALSE;
if ((argc!=2)&&(argc!=3))
{
printf("Usage:\n\t%s <old-rom-dump> [<new-rom-dump>]\n", argv[0]);
return 1;
}
pRom = LocalAlloc(0,1048576);
pRom = LocalAlloc(LMEM_FIXED,512*1024*2);
if (pRom == NULL)
{
printf("Memory Allocation Failed !");
return 1;
}
hFile = CreateFile(argv[1],GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
hFile = CreateFile(argv[1],GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
LocalFree(pRom);
printf("Cannot open file %s.\n", argv[1]);
return 1;
}
dwSizeLo = GetFileSize(hFile, &dwSizeHi);
dwSizeLo = GetFileSize(hFile, NULL);
hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMap == NULL)
{
LocalFree(pRom);
CloseHandle(hFile);
puts("CreateFileMapping failed.");
return 1;
@ -127,42 +148,65 @@ UINT main(int argc, char *argv[])
pIn = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if (pIn == NULL)
{
LocalFree(pRom);
CloseHandle(hMap);
CloseHandle(hFile);
puts("MapViewOfFile failed.\n");
return 1;
}
switch (pIn[0])
for (i = 0; i < 2 && !bFormatDetected; ++i)
{
switch (pIn[0+dwAddrOffset])
{
case '0':
if (pIn[1]!='0') break;
if (pIn[2]!='0') break;
if (pIn[3]!='0') break;
if (pIn[4]!='0') break;
if (pIn[5]!=':') break;
if (pIn[1+dwAddrOffset]!='0') break;
if (pIn[2+dwAddrOffset]!='0') break;
if (pIn[3+dwAddrOffset]!='0') break;
if (pIn[4+dwAddrOffset]!='0') break;
if (pIn[5+dwAddrOffset]!=':') break;
bText = TRUE;
bFormatDetected = TRUE;
break;
case 0x23:
bUnpack = TRUE;
bSwap = TRUE;
bFormatDetected = TRUE;
break;
case 0x32:
bUnpack = TRUE;
break;
case 0x02:
bFormatDetected = TRUE;
break;
case 0x03:
if (pIn[1] == 0x02)
{
bSwap = TRUE;
}
case 0x02:
if (pIn[1+dwAddrOffset] == (bSwap ? 0x02 : 0x03))
{
bFormatDetected = TRUE;
break;
}
bSwap = FALSE;
default:
dwAddrOffset = dwSizeLo / 2;
bDA19 = TRUE;
break;
}
}
if (!bFormatDetected)
{
LocalFree(pRom);
UnmapViewOfFile(pIn);
CloseHandle(hMap);
CloseHandle(hFile);
printf("Stopped, unknown format.\n");
return 1;
}
if (bUnpack) printf("Unpacking nibbles.\n");
if (bSwap) printf("Swapping nibbles.\n");
if (bText) printf("Reading text file.\n");
if (bDA19) printf("Swapping banks.\n");
if (bText)
{
@ -200,8 +244,9 @@ UINT main(int argc, char *argv[])
DWORD i;
for (i=0; i<dwSizeLo; i++)
{
pRom[(i<<1) ] = pIn[i]>>4;
pRom[(i<<1)+1] = pIn[i]&0xF;
BYTE byC = pIn[(i+dwAddrOffset)&(dwSizeLo-1)];
pRom[(i<<1) ] = byC>>4;
pRom[(i<<1)+1] = byC&0xF;
}
}
else
@ -209,8 +254,9 @@ UINT main(int argc, char *argv[])
DWORD i;
for (i=0; i<dwSizeLo; i++)
{
pRom[(i<<1) ] = pIn[i]&0xF;
pRom[(i<<1)+1] = pIn[i]>>4;
BYTE byC = pIn[(i+dwAddrOffset)&(dwSizeLo-1)];
pRom[(i<<1) ] = byC&0xF;
pRom[(i<<1)+1] = byC>>4;
}
}
}
@ -222,55 +268,74 @@ UINT main(int argc, char *argv[])
for (i=0; i<dwSizeLo; i+=2)
{
BYTE a, b;
a = pIn[i];
b = pIn[i+1];
pRom[i] = a;
pRom[i+1] = b;
a = pIn[(i+dwAddrOffset)&(dwSizeLo-1)];
b = pIn[(i+1+dwAddrOffset)&(dwSizeLo-1)];
pRom[i] = b;
pRom[i+1] = a;
}
}
else
{
if(bDA19)
{
assert(dwAddrOffset == dwSizeLo/2);
CopyMemory(&pRom[0] , &pIn[dwAddrOffset], dwAddrOffset);
CopyMemory(&pRom[dwAddrOffset], &pIn[0] , dwAddrOffset);
}
else
{
CopyMemory(pRom, pIn, dwSizeLo);
}
}
}
}
UnmapViewOfFile(pIn);
CloseHandle(hMap);
CloseHandle(hFile);
if (bText||bUnpack||bSwap)
if (bText||bUnpack||bSwap||bDA19)
{
printf("File converted.");
printf("File converted.\n\n");
}
bIsGx = (pRom[0x29] == 0x00);
do
{
// HP38G
wType = HP38G;
dwAddress = 0x7FFAF;
uLen = 10;
if (IsHP(dwAddress)) break;
printf("ROM Model Detected : HP48%c\n", bIsGx?'G':'S');
// HP48SX
wType = HP48S;
dwAddress = 0x7FFF0;
uLen = 6;
if (IsHP(dwAddress)) break;
if (bIsGx)
{
UINT i;
for (i=0; i<6; i++)
{
szVersion[i] = pRom[0x7FFBF + (i<<1) + 1] << 4;
szVersion[i] |= pRom[0x7FFBF + (i<<1) ];
// HP48GX
wType = HP48G;
dwAddress = 0x7FFBF;
uLen = 6;
if (IsHP(dwAddress)) break;
// unknown
uLen = 0;
}
}
else
while (0);
printf("ROM Model Detected : HP%c8%c\n",(wType == HP38G)?'3':'4',(wType != HP48S)?'G':'S');
for (i=0; i<uLen; ++i)
{
UINT i;
for (i=0; i<6; i++)
{
szVersion[i] = pRom[0x7FFF0 + (i<<1) + 1] << 4;
szVersion[i] |= pRom[0x7FFF0 + (i<<1) ];
szVersion[i] = pRom[dwAddress + (i<<1) + 1] << 4;
szVersion[i] |= pRom[dwAddress + (i<<1)];
}
}
szVersion[6] = 0;
szVersion[i] = 0;
printf("ROM Version : %s\n", szVersion);
FillMemory(pRom+0x100, 0x40, 0);
ZeroMemory(pRom+0x100, 0x40); // clear IO register area
if (CheckCRC())
{
@ -283,14 +348,14 @@ UINT main(int argc, char *argv[])
if (argc == 3)
{
hOut = CreateFile(argv[2],GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
hOut = CreateFile(argv[2],GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
LocalFree(pRom);
printf("Cannot open file %s.\n", argv[2]);
return 1;
}
WriteFile(hOut,pRom,bIsGx?1048576:524288,&dwWritten,NULL);
WriteFile(hOut,pRom,(wType != HP48S)?(512*1024*2):(256*1024*2),&dwWritten,NULL);
CloseHandle(hOut);
}

View file

@ -10,16 +10,16 @@
****************
Emu48 is distributed in 1 archive:
- Emu48-1_15.zip All files and sources
- Emu48-1_20.zip All files and sources
To install Emu48, just unzip Emu48-1_15.zip into an empty directory. When you
To install Emu48, just unzip Emu48-1_20.zip into an empty directory. When you
first run Emu48, it will detect the directory in which you installed it, and
will write its configuration to a file named Emu48.ini in your Windows
directory.
You can also update your current version with the Unofficial Service Packs:
- E48BP1x.ZIP New EXE-File
- E48SP1x.ZIP Sources of the Service Pack
- E48BP2x.ZIP New EXE-File
- E48SP2x.ZIP Sources of the Service Pack
Replace the original EXE file please.
@ -136,9 +136,9 @@ In some cases you have to fix Color 0 in your KML script file, because the
colors red and blue has been swapped in the "Lcd" section (bugfix in a previous
version). Don't use TRUELCD.KMI for emulating display contrast in your scripts.
It's not fully correct. The hardware contrast values are in the area from 0 to
31. But the HP48 ROMs bounds them to useful values. The S(X) ROM use only
display contrast values between 3 and 19 and the G(X) ROM values between 9 and
24.
31. But the ROMs bounds them to useful values. The HP48 S(X) ROM use only
display contrast values between 3 and 19 and the HP48 G(X) ROM values between 9
and 24.
****************
@ -147,8 +147,8 @@ display contrast values between 3 and 19 and the G(X) ROM values between 9 and
The command line syntax is "Emu48 [E48file [Port2file]]". The first parameter
sets the filename for the emulation data, the second parameter the Port2 file.
You're not able to set a Port2 file without setting the emulation data file. The
arguments are optional.
You're not able to set a Port 2 file without setting the emulation data file.
The arguments are optional.
*******************
@ -156,23 +156,23 @@ arguments are optional.
*******************
There are two ways to transfer files from or to the emulator. The one way is to
use the serial port to transfer the data directly from your HP48 to the
emulator. The second way is to load data, saved on your PC, into the stack of
the emulator. You can do this by using the Edit/Load Object... command or with
the file Drag and Drop feature. But there's one important restriction, the data
must a HP binary file (begin with HPHP48- or HPHP49-, this depends on your
emulated calculator)! If not, the data is load as string. The Edit/Save
Object... command will save the data in stack level 1 on the PC (always binary
mode). Be sure, when you use the second way for data transfer, that no program
is running on the emulator. The second way doesn't work on a HP38, because he
has no stack. So you can load aplets only from the serial port.
use the serial port to transfer the data directly from your HP to the emulator.
The second way is to load data, saved on your PC, into the stack of the
emulator. You can do this by using the Edit/Load Object... command or with the
file Drag and Drop feature. But there's one important restriction, the data must
a HP binary file (begin with HPHP48- or HPHP49-, this depends on your emulated
calculator)! If not, the data is load as string. The Edit/Save Object... command
will save the data in stack level 1 on the PC (always binary mode). Be sure,
when you use the second way for data transfer, that no program is running on the
emulator. The second way doesn't work on a HP38, because he has no stack. So you
can load aplets only from the serial port.
*****************
* DRAG AND DROP *
*****************
Dropping HP48 objects over the emulator window will load program files (like the
Dropping HP objects over the emulator window will load program files (like the
command "Load object...") on the stack. Be sure that the emulator isn't busy
before doing this.
@ -209,12 +209,28 @@ Port 2 will be write-protected. Thus you can transfer files very easily between
two calculators. This RAM card is used by both S/SX and G/GX types.
***********************
* FLASH ROM EMULATION *
***********************
The HP49G save the operation system a reprogramable memory, a so called flash
memory. The flash memory is divided into two parts, into the Operating System
and into a User Data area. The User Data area is viewed as Port 2 in the HP49G.
Emu48 saves the Port 2 data in the ROM file (normally ROM.E49). As default
setting the ROM file is writeable in the first instance of Emu48. When you open
another instance of a HP49G emulation the Port 2 area is READ ONLY, that mean
all changes in Port 2 are lost when you exit this instance. If you don't want to
save data in Port 2 and want to protect the operating systems from overwriting,
you're able protect the ROM file. To do this, close all Emu48 instances and set
the variable 'Writeable' defined in the Emu48.ini file, section [ROM] to zero.
***********************
* COPY / PASTE STRING *
***********************
With the menu items "Copy String" and "Paste String" in the "Edit" menu you're
able to copy HP48 string objects from the stack to the PC clipboard and vice
able to copy HP string objects from the stack to the PC clipboard and vice
versa.
@ -249,9 +265,9 @@ button.
The emulator time is synchronized with the PC time at startup of the emulator.
This may cause problems with other non original operating systems running on the
HP48. On S(X) calculators the address area #00052-#00070, on G(X) calculators
the address area #00058-#00076 in Port0 are rewritten with the actual time
information.
HP. On HP48 S(X) calculators the address area #00052-#00070, on all other
emulated calculators the address area #00058-#00076 in Port 0 are rewritten with
the actual time information.
*************
@ -268,28 +284,28 @@ again.
* REAL SPEED EMULATION *
************************
As you recognized the speed of the emulated HP48 is much faster than an original
HP48. The reason is, the assembler commands are emulated faster than the
original CPU can execute them. On one side this is a big advantage (faster
execution of programs) on the other side this cause many trouble. In Emu48 only
the timers work with the original speed. In result all commands like User-RPL
WAIT wait more or less the correct time. But many programs like shells or
editors use an own key handler to realize an autorepeat implementation. Normally
these programs use the execution time of each assembler command for waiting. On
Emu48 this time is much shorter, so the time between each key read is shorter as
well and you get a very fast key repetition. The editor ED from the JAZZ package
hasn't this problem, because the key input is synchronized with one of the
timers. To solve this problem Emu48 generally slow down emulation if a key is
pressed. To solve some other speed depending problems you are able to slow down
the whole emulation speed. There are two variables 'SXCycles=82' and
'GXCycles=123' defined in the Emu48.ini file, section [Emulator] which control
the "real" speed and key repetition slow down for each calculator type. Each
numeric value is representing the allowed CPU cycles in a 16384Hz time frame.
Because the used cycle statements (from SASM.DOC) in Emu48 doesn't correspond to
the real values of the CPU, the saved values are estimated by comparing the
execution time of a program to the real calculator. Increasing the value fitting
to your ROM will make the "real speed" HP faster and vice versa. No warranty to
the functionality of Emu48 when you go below the default values.
As you recognized the speed of the emulated HP is much faster than an original
one. The reason is, the assembler commands are emulated faster than the original
CPU can execute them. On one side this is a big advantage (faster execution of
programs) on the other side this cause many trouble. In Emu48 only the timers
work with the original speed. In result all commands like User-RPL WAIT wait
more or less the correct time. But many programs like shells or editors use an
own key handler to realize an autorepeat implementation. Normally these programs
use the execution time of each assembler command for waiting. On Emu48 this time
is much shorter, so the time between each key read is shorter as well and you
get a very fast key repetition. The editor ED from the JAZZ package hasn't this
problem, because the key input is synchronized with one of the timers. To solve
this problem Emu48 generally slow down emulation if a key is pressed. To solve
some other speed depending problems you are able to slow down the whole
emulation speed. There are two variables 'SXCycles=82' and 'GXCycles=123'
defined in the Emu48.ini file, section [Emulator] which control the "real" speed
and key repetition slow down for each calculator type. Each numeric value is
representing the allowed CPU cycles in a 16384Hz time frame. Because the used
cycle statements (from SASM.DOC) in Emu48 doesn't correspond to the real values
of the CPU, the saved values are estimated by comparing the execution time of a
program to the real calculator. Increasing the value fitting to your ROM will
make the "real speed" HP faster and vice versa. No warranty to the functionality
of Emu48 when you go below the default values.
*************************
@ -299,33 +315,33 @@ the functionality of Emu48 when you go below the default values.
The serial ports are emulated as well now. You may choose the same serial port
for wire and IR. Remember that the IR port only work with 2400 Baud. If you want
to change the serial port settings, but they are disabled, close the serial port
with the command CLOSEIO or power cycle the HP48 first.
with the command CLOSEIO or power cycle the HP first.
Now it's possible to make transfers between the HP48 and Emu48. If you have
problems with the connection please try the following. There's a simple way to
check if your serial port is used by another program. First disable the serial
settings in both combo boxes and very important close the settings dialog.
Reopen the settings dialog and choose the COM port in the wire combo box to the
port the HP48 is connected with. When you open this combo box you only see valid
(unused) serial ports. Don't use the IR combo box, it only works with 2400 Baud.
The next important thing are the serial settings of the HP48 and Emu48, they
must be equal. If this doesn't work then mostly there's a hardware or a resource
problem of the serial port. Check this with connecting the HP48 with a transfer
program you like on the same serial port.
Now it's possible to make transfers between the real calculator and Emu48. If
you have problems with the connection please try the following. There's a simple
way to check if your serial port is used by another program. First disable the
serial settings in both combo boxes and very important close the settings
dialog. Reopen the settings dialog and choose the COM port in the wire combo box
to the port the HP is connected with. When you open this combo box you only see
valid (unused) serial ports. Don't use the IR combo box, it only works with 2400
Baud. The next important thing are the serial settings of the real calculator
and Emu48, they must be equal. If this doesn't work then mostly there's a
hardware or a resource problem of the serial port. Check this with connecting
the HP with a transfer program you like on the same serial port.
****************
* DISASSEMBLER *
****************
With the internal disassembler you're able to disassemble the HP48 address area.
With the default Map setting the disassembler always see the mapped memory
address. If for example you configured the RAM at #00000 you will see the RAM
and not the ROM at this address. With the other Module settings you specify a
special module for disassembly. Each module will begin at address #00000 and
will not overlapped by other modules. For Port2 I use a linear address mode,
that means that the second port of a RAM card greater than 128KB is at address
#40000 (128 * 1024 * 2) and so on. The "Copy Data" button copies the selected
With the internal disassembler you're able to disassemble the Saturn chip
address area. With the default Map setting the disassembler always see the
mapped memory address. If for example you configured the RAM at #00000 you will
see the RAM and not the ROM at this address. With the other module settings you
specify a special module for disassembly. Each module use a linear address mode,
beginning at address #00000 and will not overlapped by other modules. So, for
example, you can access the second port of a HP48 RAM card greater than 128KB at
address #40000 (128 * 1024 * 2). The "Copy Data" button copies the selected
disassembler lines to the PC clipboard.
@ -389,7 +405,7 @@ Other graphics and scripts are available at Casey's Emu48 Graphics Page:
***************
Emu48 - An HP38/48/49 Emulator
Copyright (C) 1999 Sebastien Carlier & Christoph Gießelink
Copyright (C) 2000 Sebastien Carlier & Christoph Gießelink
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software

View file

@ -1,3 +1,353 @@
Service Pack 20 for Emu48 Version 1.0
DEBUGGER.C
- changed function UpdateStackWnd(), index of topmost item is now
saved at content update
- changed function CheckBreakpoint(), allow breakpoints in an area
now (used by memory breakpoints to get all touched addresses on a
r=DATx fs access)
DEBUGGER.H
- changed prototype of function CheckBreakpoint()
EMU48.C
- use semaphores to avoid GDI trouble with NT in OnPaint()
- specify processor affinity for the cpu emulation thread to avoid
problems with the QueryPerformanceCounter() function
EMU48.H
- extern declaration of global variable
EMU48.RC
- fixed multiple use of accelerator key in debugger menu
- changed version and copyright
ENGINE.C
- bugfix in function Debugger(), check complete address range of
memory access area
- workaround for Win2k in function AdjustSpeed(), when command
sequence took over 50ms new synchronizing of the emulation slow
down part
- bugfix in function WorkerThread(), update NINT and NINT2 lines
after port status changing
KML.C
- use semaphores to avoid GDI trouble with NT in RefreshButtons()
MOPS.C
- bugfix in function UckBit() and F4096Hz(), depending on clock
value functions returned wrong results
OPCODES.C
- moved address field start and length array from OPS.H and made
them public
OPCODES.H
- extern declaration of global address field start and length
variables
OPS.H
- moved address field start and length array to OPCODES.C
- bugfix in function FASTPTR(), address area is only 5 nibbles long
RESOURCE.H
- deleted several unused definitions
RPL.C
- added function Metakernel() to detect MK2.30 and prior
- changed function RPL_Pick() and RPL_Push() to support
"Save/Load Object" with a stack incompatible Metakernel versions
SERIAL.C
- use own OVERLAPPED stucture for reading and writing
- bugfix in function CommClose(), added additional delay to fix
problems with some Kermit server
- bugfix in function CommTransmit(), wait until write completed
SETTINGS.C
- changed function ReadSettings(), use variable content as default
Service Pack 19 for Emu48 Version 1.0
DISPLAY.C
- added io.h in header definition
- bugfix in function CreateMainBitmap(), check error condition and
realize palette also in memory DC
- bugfix in CreateLcdBitmap(), must set color palette for LCD DC
- bugfix in function UpdateAnnunciators(), annunciators are off if
timer2 is stopped
DEBUGGER.C
- several modifications for memory breakpoint handling
- added step over interrupt code part setting
- bugfix in function NewValue(), at wrong input numbers ignore input
string at <CANCEL> and set focus to edit control
- bugfix in function EnterAddr(), at wrong input numbers set focus
to edit control
DEBUGGER.H
- added breakpoint type defines
- extern declaration of global variable
- changed prototype of function CheckBreakpoint()
EMU48.C
- added io.h in header definition
- changed function SettingsProc(), added HP/Class mnemonic setting
- bugfix in function SettingsProc(), new implementation of card
detection port 1
- moved initialize/remove of the Critical Section part from main
program to message handler
- changed function OnDropFiles(), OnStackCopy(), OnStackPaste(),
OnObjectLoad() and OnObjectSave(), don't wait for changed state
after function WaitForSleepState()
- bugfix in function OnObjectSave(), set info message when emulator
is busy
- changed function Disasm(), removed HP/Class mnemonic setting
- bugfix in function Disasm(), addresses > 0x1869F showed in wrong
format
- bugfix in function WinMain(), synchronized thread start
EMU48.H
- changed definition of PORT1_PRESENT, PORT1_WRITE, PORT2_PRESENT
and PORT2_WRITE
EMU48.RC
- added HP/Class mnemonics in "Settings" dialog
- added "Interrupts" part in debugger menu
- added "Enter breakpoint" dialog
- changed version and copyright
ENGINE.C
- moved debugger part from function WorkerThread() to own function
- added C=DAT0 A, D0=D0+ 5, PC=(C) code sequence detection for RPL
breakpoint in debugger
- added step over interrupt code part handler in debugger section
- bugfix in function SwitchToState(), when switch from Invalid into
Run state then don't enter opcode loop on interrupt request or in
SHUTDN mode
- changed function WorkerThread(), added memory breakpoint handler
- bugfix in function WorkerThread(), timer emulation in debugger
part must check the timer RUN bit
- bugfix in function WorkerThread(), must set wakeup flag on SHUTDN
on interrupt request condition
- changed function WorkerThread(), minor optimization
FILES.C
- added io.h in header definition
- bugfix in function OpenDocument(), check card detection only if
enabled and set NINT line to low on a MP interrupt
- changed function DibNumColors(), optimized by removing case switch
IO.H
- added ANNCTRL and CARDSTAT definitions
MOPS.C
- removed conditional compiling with WSMSET
- bugfix in function RomSwitch(), mirror smaller ROMs than 2MB
- bugfix in function Npeek(), wrong content of SRQ2 register (0x119)
- bugfix in function ReadIO(), wrong implementation of the SMP and
SWINT bit in the CARDCTL register (0x10E)
- bugfix in function ReadIO(), wrong implementation of the NINT2 and
NINT bit in the SRQ2 register (0x119)
- bugfix in function WriteIO(), wrong implementation of the SMP and
ECDT bit and removed some wrong stuff in the CARDCTL register
(0x10E)
- bugfix in function WriteIO(), the DA19 bit in the LINECOUNT
register (0x129) is also available in the Clarke hardware
- bugfix in function WriteIO(), the RUN bit in the TIMER2CTRL
register (0x12F) has an affection to the display annunciators
OPCODES.C
- added io.h in header definition
- bugfix in RTI command, low NINT2 or NINT line reenter interrupt
- bugfix in function o808C() and o808E(), opcodes PC=(A) and PC=(C)
modify the CRC register
OPCODES.H
- moved HST bit definition to TYPES.H
RESOURCE.H
- added several definitions
SETTINGS.C
- changed function ReadSettings() and WriteSettings(), added section
[Disassembler] in INI-File
TYPES.H
- added definition of HST bits
Service Pack 18 for Emu48 Version 1.0
EMU48.RC
- changed version and copyright
ENGINE.C
- bugfix in function WorkerThread(), ignore SHUTDN on interrupt
request
SERIAL.C
- bugfix in function CommOpen(), must wait for EV_RXCHAR event
thread directly after opening the serial port
Service Pack 17 for Emu48 Version 1.0
DEBUGGER.C
- bugfix in function StrToReg() and OnLButtonUp(), wrong string to
HEX conversation with lowercase letters
- bugfix in function Debugger(), used wrong background color in
WM_CTLCOLORSTATIC message handler
EMU48.C
- bugfix in function SettingsProc(), don't overwite Serial-Ir
setting in HP49 mode
EMU48.DSP
- added i28f160.c sources
EMU48.H
- extern declaration of global variable and functions
EMU48.RC
- changed version and copyright
FILES.C
- added new functions in the ROM patch part
- changed function PatchRom(), original content of patched address
is saved now
- changed function MapRom(), added ROM writing feature
- changed function UnmapRom(), restore original content before
closing
- bugfix in function MapPort2(), shared mode now works, when first
program instance opened the file with Read/Write access
- changed function NewDocument() and OpenDocument(), initialize
flash memory structure
I28F160.C
- new modul with I28F160 flash memory implementation
I28F160.H
- header file for flash memory implementation
MOPS.C
- changed function MapROM(), added flash register mode
- changed function Npeek(), added flash access part
- changed function Nread(), completed flash access part
- changed function Nwrite(), completed flash access part
OPS.H
- bugfix in function FASTPTR(), handle NULL pointer pages now
- bugfix in function Ninc(), Ndec(), Nadd(), Nsub(), Nrsub(), Nnot()
and Nneg(), wrong results in dec mode with illegal decimal number
entry
SETTINGS.C
- changed function ReadSettings() and WriteSettings(), added section
[ROM] in INI-File
TIMER.C
- bugfix in function CalcT2(), workaround to minimize skipping
timer2 values
Service Pack 16 for Emu48 Version 1.0
DEBUGGER.C
- added "MMU" and "Miscellaneous" view in debugger dialog
- added RPL exit breakpoint on A=DAT0 A, D0=D0+ 5, PC=(A) sequence
- added last instruction viewer in debugger
- renamed funtion name ViewStackWnd() to UpdateStackWnd()
- bugfix in function UpdateRegisterWnd() and OnCtlColorStatic(),
fixed problems of register update in RUN mode
- bugfix in function OnKeyF11(), in sleep mode break hasn't worked
- bugfix in function OnLButtonUp(), register setting wasn't disabled
in running state
- changed function NotifyDebugger(), added argument to detect RPL
breakpoint
- bugfix in function Debugger(), code disassembler wasn't reset to
mapped mode at startup and fixed a resource leak
- bugfix in function EditBreakpoint(), added breakpoint buffer
overflow check at add breakpoint command
DEBUGGER.H
- extern declaration of global variables
DISASM.C
- bugfix in function disasm_1(), the C=ss, ss=C and CssEX opcodes
showed always as A=ss, ss=A and AssEX opcodes
- bugfix in function disasm_8(), the r register in the rSRB.F fs
opcodes and the opcode lenght was wrong
EMU48.C
- new function CopyItemsToClipboard(), copy selected items from
listbox to clipboard, extracted from function Disasm()
- added HP38G64K stuff to function UpdateWindowStatus() and
SettingsProc()
- changed function Disasm(), call function CopyItemsToClipboard()
now
EMU48.H
- extern declaration of global functions
EMU48.RC
- added "MMU" and "Miscellaneous" part in debugger dialog
- changed copyright date in IDD_ABOUT
- changed version and copyright
ENGINE.C
- added RPL breakpoint handling
- added last instruction buffer update handling
- changed function WorkerThread(), added timer emulation in debugger
mode
- bugfix infunction WorkerThread(), in debugger mode Chipset.pc may
have been changed, so the FASTPTR access must be updated as well
EXTERNAL.C
- some minor changes for the HP38G64K beeper emulation
FILES.C
- added new document type for HP38G64K
IO.H
- added CARDCTL and LCR definitions
KEYBOARD.C
- bugfix in function ScanKeyboard(), update keyboard status only on
timer running and keyboard interrupt only occur on the rising edge
of "logic or" of IR[8:0] and not on the rising edge of each line;
the IRX15 interrupt (ON key) is level sensitive
MOPS.C
- added function MapData() to detect the memory controller handle
the given address, needed for function Npeek(), Nread() and
Nwrite()
- bugfix in function MapROM(), no difference between Clarke and
Yorke chip in DA19 bit behavior, depends on ROM size
- bugfix in function Map(), on a HP49 NCE3 may mapped to ROM
- changed function CpuReset(), reset WSM state of flash memory
- bugfix in function Npeek(), update card status register in I/O
register area before reading and simulate an open data bus
- bugfix in function Nread(), loaded wrong bank switcher FF value
for a HP49
- bugfix in function Nwrite(), loaded wrong bank switcher FF value
when writing on slot2 enabled (GX only)
- changed function Nread() and Nwrite(), added Flash memory access
detection part
- bugfix in function ReadIO(), the CARDSTATUS register (0x10F)
return zero when card detection is disabled
- bugfix in function WriteIO(), on a HP49 force new memory mapping
on changing the LED bit in the LCR register (0x11C)
RESOURCE.H
- added several definitions
TYPES.H
- conditional compiling of cycle counter (32bit EXE/64bit DLL)
- use position of Port2_NBanks for flash memory WSM state variable
Service Pack 15 for Emu48 Version 1.0
DEBUGGER.C
@ -200,7 +550,7 @@ EXTERNAL.C
- some minor changes for the HP49 beeper emulation
FILES.C
- added new document type for HP49G
- added new document type for HP49
- change in function WriteStack(), accept HP49 binary files now
- the port2 open/close handling is now controlled by the document
- several changes in port2 handling, the HP49 use an internal 128KB

File diff suppressed because it is too large Load diff

View file

@ -7,12 +7,13 @@
*
*/
// #define BP_EXEC 1 // code breakpoint
// #define BP_READ 2 // read memory breakpoint
// #define BP_WRITE 4 // write memory breakpoint
// #define BP_RANGE 8 // check address range
// breakpoint type definitions
#define BP_EXEC 1 // code breakpoint
#define BP_READ 2 // read memory breakpoint
#define BP_WRITE 4 // write memory breakpoint
#define BP_ACCESS (BP_READ|BP_WRITE) // read/write memory breakpoint
// 13.11.99 cg, new, debugger state definitions
// debugger state definitions
#define DBG_RUN 0
#define DBG_STEPINTO 1
#define DBG_STEPOVER 2
@ -22,10 +23,16 @@
extern HWND hDlgDebug;
extern HANDLE hEventDebug;
extern BOOL bDbgEnable;
extern INT nDbgState; // 13.11.99 cg, state of debugger
extern INT nDbgState;
extern BOOL bDbgNOP3;
extern BOOL bDbgRPL;
extern BOOL bDbgSkipInt;
extern DWORD dwDbgRstkp;
extern DWORD dwDbgRstk; // 13.11.99 cg, possible return address
extern BOOL CheckBreakpoint(DWORD dwAddr);
extern VOID NotifyDebugger(VOID); // 10.11.99 cg, notify debugger emulation stopped
extern DWORD dwDbgRstk;
extern DWORD *pdwInstrArray;
extern WORD wInstrSize;
extern WORD wInstrWp;
extern WORD wInstrRp;
extern BOOL CheckBreakpoint(DWORD dwAddr, DWORD wRange, UINT nType);
extern VOID NotifyDebugger(BOOL bType);
extern LRESULT OnToolDebug(VOID);

View file

@ -503,13 +503,14 @@ static char *disasm_1 (DWORD *addr, char *out)
case 0:
case 1:
fn = read_nibble (addr);
fn = (fn & 7);
if (fn > 4)
fn -= 4;
c = (fn < 8); // flag for operand register
fn = (fn & 7); // get register number
if (fn > 4) // illegal opcode
break; // no output
switch (disassembler_mode)
{
case HP_MNEMONICS:
c = (char) ((fn < 8) ? 'A' : 'C');
c = (char) (c ? 'A' : 'C');
if (n == 0)
wsprintf (buf, "R%d=%c", fn, c);
else
@ -519,7 +520,7 @@ static char *disasm_1 (DWORD *addr, char *out)
case CLASS_MNEMONICS:
p = append_str (out, "move.w");
p = append_tab (out);
c = (char) ((fn < 8) ? 'a' : 'c');
c = (char) (c ? 'a' : 'c');
if (n == 0)
wsprintf (buf, "%c, r%d", c, fn);
else
@ -534,20 +535,21 @@ static char *disasm_1 (DWORD *addr, char *out)
case 2:
fn = read_nibble (addr);
fn = (fn & 7);
if (fn > 4)
fn -= 4;
c = (fn < 8); // flag for operand register
fn = (fn & 7); // get register number
if (fn > 4) // illegal opcode
break; // no output
switch (disassembler_mode)
{
case HP_MNEMONICS:
c = (char) ((fn < 8) ? 'A' : 'C');
c = (char) (c ? 'A' : 'C');
wsprintf (buf, "%cR%dEX", c, fn);
p = append_str (out, buf);
break;
case CLASS_MNEMONICS:
p = append_str (out, "exg.w");
p = append_tab (out);
c = (char) ((fn < 8) ? 'a' : 'c');
c = (char) (c ? 'a' : 'c');
wsprintf (buf, "%c, r%d", c, fn);
p = append_str (p, buf);
break;
@ -1020,6 +1022,8 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view)
break;
case 9:
fn = read_nibble (addr); // get field selector
n = read_nibble (addr); // get register selector
switch (disassembler_mode)
{
case HP_MNEMONICS:
@ -1027,11 +1031,11 @@ static char *disasm_8 (DWORD *addr, char *out, BOOL view)
op_str_81[(n & 3) + 4 * disassembler_mode]);
p = append_str (out, buf);
p = append_tab (out);
p = append_field (p, read_nibble (addr));
p = append_field (p, fn);
break;
case CLASS_MNEMONICS:
p = append_str (out, "lsr");
p = append_field (p, read_nibble (addr));
p = append_field (p, fn);
p = append_tab (out);
p = append_str (p, "#1, ");
p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]);

View file

@ -9,6 +9,7 @@
#include "pch.h"
#include "resource.h"
#include "Emu48.h"
#include "io.h"
#include "kml.h"
#define LCD1_ROW 144
@ -109,8 +110,13 @@ VOID CreateLcdBitmap()
bmiLcd.Lcd_bmih.biWidth = LCD1_ROW * nLcdDoubled;
bmiLcd.Lcd_bmih.biHeight = -64 * nLcdDoubled;
hLcdDC = CreateCompatibleDC(hWindowDC);
_ASSERT(hLcdDC != NULL);
hLcdBitmap = CreateDIBSection(hLcdDC, (BITMAPINFO*)&bmiLcd,DIB_RGB_COLORS, (LPVOID*)&pbyLcd, NULL, 0);
_ASSERT(hLcdBitmap != NULL);
hOldLcdBitmap = SelectObject(hLcdDC, hLcdBitmap);
_ASSERT(hPalette != NULL);
SelectPalette(hLcdDC, hPalette, FALSE); // set palette for LCD DC
RealizePalette(hLcdDC); // realize palette
UpdateContrast(Chipset.contrast);
}
@ -135,7 +141,12 @@ VOID DestroyLcdBitmap()
BOOL CreateMainBitmap(LPSTR szFilename)
{
HPALETTE hAssertPalette;
_ASSERT(hWindowDC != NULL);
hMainDC = CreateCompatibleDC(hWindowDC);
_ASSERT(hMainDC != NULL);
if (hMainDC == NULL) return FALSE; // quit if failed
hMainBitmap = LoadBitmapFile(szFilename);
if (hMainBitmap == NULL)
{
@ -143,7 +154,10 @@ BOOL CreateMainBitmap(LPSTR szFilename)
return FALSE;
}
hOldMainBitmap = SelectObject(hMainDC, hMainBitmap);
SelectPalette(hMainDC, hPalette, FALSE);
_ASSERT(hPalette != NULL);
hAssertPalette = SelectPalette(hMainDC, hPalette, FALSE);
_ASSERT(hAssertPalette != NULL);
RealizePalette(hMainDC);
return TRUE;
}
@ -556,14 +570,17 @@ VOID UpdateAnnunciators()
{
BYTE c;
c = (BYTE)(Chipset.IORam[0xB] | (Chipset.IORam[0xC]<<4));
if (!(c&0x80)) c=0;
DrawAnnunciator(1,c&0x01);
DrawAnnunciator(2,c&0x02);
DrawAnnunciator(3,c&0x04);
DrawAnnunciator(4,c&0x08);
DrawAnnunciator(5,c&0x10);
DrawAnnunciator(6,c&0x20);
c = (BYTE)(Chipset.IORam[ANNCTRL] | (Chipset.IORam[ANNCTRL+1]<<4));
// switch annunciators off if timer stopped
if ((c & AON) == 0 || (Chipset.IORam[TIMER2_CTRL] & RUN) == 0)
c=0;
DrawAnnunciator(1,c&LA1);
DrawAnnunciator(2,c&LA2);
DrawAnnunciator(3,c&LA3);
DrawAnnunciator(4,c&LA4);
DrawAnnunciator(5,c&LA5);
DrawAnnunciator(6,c&LA6);
return;
}

View file

@ -9,10 +9,11 @@
#include "pch.h"
#include "resource.h"
#include "Emu48.h"
#include "io.h"
#include "kml.h"
#include "debugger.h"
#define VERSION "1.15" // 23.10.99 cg, changed version
#define VERSION "1.20"
#define CF_HPOBJ "CF_HPOBJ" // clipboard format for DDE
#define MAXPORTS 16 // number of COM ports
@ -28,7 +29,7 @@ LPSTR szAppName = "Emu48"; // application name for DDE server
LPSTR szTopic = "Stack"; // topic for DDE server
LPSTR szTitle = NULL;
static const char szLicence[] = // 30.11.99 cg, changed, update of address
static const char szLicence[] =
"This program is free software; you can redistribute it and/or modify\r\n"
"it under the terms of the GNU General Public License as published by\r\n"
"the Free Software Foundation; either version 2 of the License, or\r\n"
@ -49,10 +50,11 @@ CRITICAL_SECTION csKeyLock; // critical section for key scan
CRITICAL_SECTION csIOLock; // critical section for I/O access
CRITICAL_SECTION csT1Lock; // critical section for timer1 access
CRITICAL_SECTION csT2Lock; // critical section for timer2 access
CRITICAL_SECTION csRecvLock; // 24.10.99 cg, moved, critical section for receive byte
INT nArgc; // 08.11.99 cg, new, no. of command line arguments
LPCTSTR *ppArgv; // 08.11.99 cg, new, command line arguments
LARGE_INTEGER lFreq; // counter frequency
CRITICAL_SECTION csRecvLock; // critical section for receive byte
INT nArgc; // no. of command line arguments
LPCTSTR *ppArgv; // command line arguments
LARGE_INTEGER lFreq; // high performance counter frequency
LARGE_INTEGER lAppStart; // high performance counter value at Appl. start
DWORD idDdeInst; // DDE server id
UINT uCF_HpObj; // DDE clipboard format
HANDLE hThread;
@ -110,10 +112,9 @@ VOID UpdateWindowStatus()
if ((nState == 0)||(nState == 3))
{
// 02.12.99 cg, new, disable stack loading items on HP38G
UINT uStackEnable = (cCurrentRomType!='A') ? MF_ENABLED : MF_GRAYED;
// disable stack loading items on HP38G
UINT uStackEnable = (cCurrentRomType!='6' && cCurrentRomType!='A') ? MF_ENABLED : MF_GRAYED;
// 02.12.99 cg, changed implementation
EnableMenuItem(hMenu,ID_FILE_SAVE,(szCurrentFilename[0]) ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(hMenu,ID_FILE_SAVEAS,MF_ENABLED);
EnableMenuItem(hMenu,ID_FILE_CLOSE,MF_ENABLED);
@ -121,12 +122,10 @@ VOID UpdateWindowStatus()
EnableMenuItem(hMenu,ID_BACKUP_SAVE,MF_ENABLED);
EnableMenuItem(hMenu,ID_VIEW_COPY,MF_ENABLED);
EnableMenuItem(hMenu,ID_VIEW_RESET,MF_ENABLED);
// 02.12.99 cg, new, added HP38G part
EnableMenuItem(hMenu,ID_OBJECT_LOAD,uStackEnable);
EnableMenuItem(hMenu,ID_OBJECT_SAVE,uStackEnable);
EnableMenuItem(hMenu,ID_STACK_COPY,uStackEnable);
EnableMenuItem(hMenu,ID_STACK_PASTE,uStackEnable);
// 02.12.99 cg, end of added part
EnableMenuItem(hMenu,ID_TOOL_DISASM,MF_ENABLED);
}
else
@ -158,6 +157,70 @@ VOID UpdateWindowStatus()
//################
//#
//# Clipboard Tool
//#
//################
VOID CopyItemsToClipboard(HWND hWnd) // save selected Listbox Items to Clipboard
{
LONG i;
LPINT lpnCount;
// get number of selections
if ((i = SendMessage(hWnd,LB_GETSELCOUNT,0,0)) == 0)
return; // no items selected
if ((lpnCount = (LPINT) LocalAlloc(LMEM_FIXED,i * sizeof(INT))) != NULL)
{
HANDLE hClipObj;
LONG j,lMem = 0;
// get indexes of selected items
i = SendMessage(hWnd,LB_GETSELITEMS,i,(LPARAM) lpnCount);
for (j = 0;j < i;++j) // scan all selected items
{
// calculate total amount of needed memory
lMem += SendMessage(hWnd,LB_GETTEXTLEN,lpnCount[j],0) + 2;
}
// allocate clipboard data
if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,lMem + 1)) != NULL)
{
LPBYTE lpData;
if (lpData = GlobalLock(hClipObj))
{
for (j = 0;j < i;++j) // scan all selected items
{
lpData += SendMessage(hWnd,LB_GETTEXT,lpnCount[j],(LPARAM) lpData);
*lpData++ = '\r';
*lpData++ = '\n';
}
*lpData = 0; // set end of string
GlobalUnlock(hClipObj); // unlock memory
}
if (OpenClipboard(hWnd))
{
if (EmptyClipboard())
SetClipboardData(CF_TEXT,hClipObj);
else
GlobalFree(hClipObj);
CloseClipboard();
}
else // clipboard open failed
{
GlobalFree(hClipObj);
}
}
LocalFree(lpnCount); // free item table
}
return;
}
//################
//#
//# Settings
@ -210,6 +273,9 @@ static BOOL CALLBACK SettingsProc(HWND hDlg, UINT message, DWORD wParam, LONG lP
CheckDlgButton(hDlg,IDC_AUTOSAVEONEXIT,bAutoSaveOnExit);
CheckDlgButton(hDlg,IDC_ALWAYSDISPLOG,bAlwaysDisplayLog);
// set disassebler mode
CheckDlgButton(hDlg,(disassembler_mode == HP_MNEMONICS) ? IDC_DISASM_HP : IDC_DISASM_CLASS,BST_CHECKED);
// set combobox parameter
SetCommList(hDlg,IDC_WIRE,szSerialWire);
SetCommList(hDlg,IDC_IR,szSerialIr);
@ -219,12 +285,11 @@ static BOOL CALLBACK SettingsProc(HWND hDlg, UINT message, DWORD wParam, LONG lP
EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE);
}
// 01.12.99 cg, HP48SX/GX
if (cCurrentRomType!='A' && cCurrentRomType!='X')
// HP48SX/GX
if (cCurrentRomType!='6' && cCurrentRomType!='A' && cCurrentRomType!='X')
{
// init port1 enable checkbox
CheckDlgButton(hDlg,IDC_PORT1EN,(Chipset.cards_status & PORT1_PRESENT) != 0);
// 19.11.99 cg, changed, use cards_status variable now
CheckDlgButton(hDlg,IDC_PORT1WR,(Chipset.cards_status & PORT1_WRITE) != 0);
// init port2 shared checkbox and set port2 filename
CheckDlgButton(hDlg,IDC_PORT2ISSHARED,bPort2IsShared);
@ -245,7 +310,7 @@ static BOOL CALLBACK SettingsProc(HWND hDlg, UINT message, DWORD wParam, LONG lP
CheckDlgButton(hDlg,IDC_PORT2ISSHARED,bPort2IsShared);
SetDlgItemText(hDlg,IDC_PORT2,szPort2Filename);
}
if (cCurrentRomType=='X') // 01.12.99 cg, HP48SX/GX
if (cCurrentRomType=='X') // HP49G
{
SendDlgItemMessage(hDlg,IDC_IR,CB_RESETCONTENT,0,0);
EnableWindow(GetDlgItem(hDlg,IDC_IR),FALSE);
@ -264,19 +329,27 @@ static BOOL CALLBACK SettingsProc(HWND hDlg, UINT message, DWORD wParam, LONG lP
if (Chipset.Port1Size && cCurrentRomType!='X')
{
UINT nOldState = SwitchToState(3);
// port1 disabled ?;
// save old card status
BYTE bCardsStatus = Chipset.cards_status;
// port1 disabled?
Chipset.cards_status &= ~(PORT1_PRESENT | PORT1_WRITE);
if (IsDlgButtonChecked(hDlg, IDC_PORT1EN))
{
Chipset.cards_status |= PORT1_PRESENT;
// 19.11.99 cg, changed, use dialog variable now
if (IsDlgButtonChecked(hDlg, IDC_PORT1WR))
Chipset.cards_status |= PORT1_WRITE;
}
if (Chipset.inte)
// changed card status in slot1?
if ( ((bCardsStatus ^ Chipset.cards_status) & (PORT1_PRESENT | PORT1_WRITE)) != 0
&& (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0
)
{
Chipset.Shutdn = FALSE;
Chipset.SoftInt = TRUE;
Chipset.HST |= MP; // set Module Pulled
IOBit(SRQ2,NINT,FALSE); // set NINT to low
Chipset.SoftInt = TRUE; // set interrupt
bInterrupt = TRUE;
}
Map(0x00,0xFF);
@ -293,9 +366,12 @@ static BOOL CALLBACK SettingsProc(HWND hDlg, UINT message, DWORD wParam, LONG lP
bPort2IsShared = IsDlgButtonChecked(hDlg,IDC_PORT2ISSHARED);
GetDlgItemText(hDlg,IDC_PORT2,szPort2Filename,sizeof(szPort2Filename));
}
// set disassebler mode
disassembler_mode = IsDlgButtonChecked(hDlg,IDC_DISASM_HP) ? HP_MNEMONICS : CLASS_MNEMONICS;
// set combobox parameter
GetDlgItemText(hDlg,IDC_WIRE,szSerialWire,sizeof(szSerialWire));
GetDlgItemText(hDlg,IDC_IR ,szSerialIr ,sizeof(szSerialIr));
if (cCurrentRomType!='X') // HP49G Ir port is not connected
GetDlgItemText(hDlg,IDC_IR,szSerialIr,sizeof(szSerialIr));
EndDialog(hDlg, wParam);
}
if (wParam == IDCANCEL)
@ -340,7 +416,7 @@ static UINT SaveChanges(BOOL bAuto)
uReply = GetSaveAsFilename();
if (uReply != IDOK) return uReply;
if (!SaveDocumentAs(szBufferFilename)) return IDCANCEL;
WriteLastDocument(szCurrentFilename); // 11.12.99 cg, changed, call function
WriteLastDocument(szCurrentFilename);
return IDYES;
}
@ -361,6 +437,13 @@ static UINT SaveChanges(BOOL bAuto)
//
static LRESULT OnCreate(HWND hWindow)
{
InitializeCriticalSection(&csGDILock);
InitializeCriticalSection(&csKeyLock);
InitializeCriticalSection(&csIOLock);
InitializeCriticalSection(&csT1Lock);
InitializeCriticalSection(&csT2Lock);
InitializeCriticalSection(&csRecvLock);
hWnd = hWindow;
hWindowDC = GetDC(hWnd);
DragAcceptFiles(hWnd,TRUE); // support dropped files
@ -373,12 +456,18 @@ static LRESULT OnCreate(HWND hWindow)
static LRESULT OnDestroy(HWND hWindow)
{
DragAcceptFiles(hWnd,FALSE); // no WM_DROPFILES message any more
// SwitchToState(2); // 01.12.99 cg, removed, doing in main program now
// WriteSettings(); // 01.12.99 cg, removed, doing in main program now
ReleaseDC(hWnd, hWindowDC);
SetWindowTitle(NULL); // free memory of title
hWindowDC = NULL; // hWindowDC isn't valid any more
hWnd = NULL;
DeleteCriticalSection(&csGDILock);
DeleteCriticalSection(&csKeyLock);
DeleteCriticalSection(&csIOLock);
DeleteCriticalSection(&csT1Lock);
DeleteCriticalSection(&csT2Lock);
DeleteCriticalSection(&csRecvLock);
PostQuitMessage(0);
return 0;
UNREFERENCED_PARAMETER(hWindow);
@ -394,8 +483,13 @@ static LRESULT OnPaint(HWND hWindow)
hPaintDC = BeginPaint(hWindow, &Paint);
if (hMainDC != NULL)
{
EnterCriticalSection(&csGDILock); // solving NT GDI problems
{
BitBlt(hPaintDC, 0, 0, nBackgroundW, nBackgroundH, hMainDC, nBackgroundX, nBackgroundY, SRCCOPY);
GdiFlush();
}
LeaveCriticalSection(&csGDILock);
if ((nState==0)||(nState==3))
{
UpdateMainDisplay();
@ -417,7 +511,8 @@ static LRESULT OnDropFiles(HANDLE hFilesInfo)
WORD wNumFiles,wIndex;
BOOL bSuccess;
if (cCurrentRomType=='A') return 0; // 06.12.99 cg, new, HP38 has no stack, ignore
// HP38 has no stack, ignore
if (cCurrentRomType=='6' || cCurrentRomType=='A') return 0;
// get number of files dropped
wNumFiles = DragQueryFile (hFilesInfo,(UINT)-1,NULL,0);
@ -438,7 +533,6 @@ static LRESULT OnDropFiles(HANDLE hFilesInfo)
return 0;
}
while (nState!=nNextState) Sleep(0);
_ASSERT(nState==3);
// get each name and load it into the emulator
@ -547,7 +641,7 @@ static LRESULT OnFileSaveAs()
SwitchToState(0);
return 0;
}
WriteLastDocument(szCurrentFilename); // 11.12.99 cg, changed, call function
WriteLastDocument(szCurrentFilename);
SwitchToState(0);
return 0;
@ -606,7 +700,6 @@ static LRESULT OnStackCopy() // copy data from stack
return 0;
}
while (nState!=nNextState) Sleep(0);
_ASSERT(nState==3);
if ((dwAddress = RPL_Pick(1)) == 0) // pick address of level1 object
@ -682,7 +775,6 @@ static LRESULT OnStackPaste() // paste data to stack
return 0;
}
while (nState!=nNextState) Sleep(0);
_ASSERT(nState==3);
if (OpenClipboard(hWnd))
@ -848,7 +940,7 @@ static LRESULT OnViewReset()
if (YesNoMessage("Are you sure you want to press the Reset Button ?")==IDYES)
{
SwitchToState(3);
CpuReset(); // 19.03.99 cg, changed, register setting after Cpu Reset
CpuReset(); // register setting after Cpu Reset
SwitchToState(0);
}
return 0;
@ -963,7 +1055,6 @@ static LRESULT OnObjectLoad()
return 0;
}
while (nState!=nNextState) Sleep(0);
_ASSERT(nState==3);
if (bWarning)
@ -971,7 +1062,7 @@ static LRESULT OnObjectLoad()
UINT uReply = YesNoCancelMessage(
"Warning: Trying to load an object while the emulator is busy \n"
"will certainly result in a memory lost. Before loading an object \n"
"you should be sure that the HP48 is not doing anything. \n"
"you should be sure that the calculator is not doing anything. \n"
"Do you want to see this warning next time you try to load an object ?");
switch (uReply)
{
@ -1020,9 +1111,11 @@ static LRESULT OnObjectSave()
}
if (WaitForSleepState()) // wait for cpu SHUTDN then sleep state
{
InfoMessage("The emulator is busy.");
return 0;
}
while (nState!=nNextState) Sleep(0);
_ASSERT(nState==3);
if (!GetSaveObjectFilename())
@ -1046,7 +1139,6 @@ static BOOL CALLBACK Disasm(HWND hDlg, UINT message, DWORD wParam, LONG lParam)
static DWORD dwAddress, dwAddressMax;
LONG i;
LPINT lpnCount;
char *cpStop,szAddress[256] = "0";
switch (message)
@ -1059,11 +1151,7 @@ static BOOL CALLBACK Disasm(HWND hDlg, UINT message, DWORD wParam, LONG lParam)
SendDlgItemMessage(hDlg,IDC_DISASM_RAM,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
SendDlgItemMessage(hDlg,IDC_DISASM_PORT1,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
SendDlgItemMessage(hDlg,IDC_DISASM_PORT2,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
SendDlgItemMessage(hDlg,IDC_DISASM_MNEMONICS,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
SendDlgItemMessage(hDlg,IDC_DISASM_HP,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
SendDlgItemMessage(hDlg,IDC_DISASM_CLASS,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
SendDlgItemMessage(hDlg,IDC_DISASM_MAP,BM_SETCHECK,1,0);
SendDlgItemMessage(hDlg,IDC_DISASM_HP,BM_SETCHECK,1,0);
SendDlgItemMessage(hDlg,IDC_ADDRESS,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
SendDlgItemMessage(hDlg,IDC_DISASM_ADR,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
SendDlgItemMessage(hDlg,IDC_DISASM_NEXT,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
@ -1071,7 +1159,6 @@ static BOOL CALLBACK Disasm(HWND hDlg, UINT message, DWORD wParam, LONG lParam)
SendDlgItemMessage(hDlg,IDCANCEL,WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT),MAKELPARAM(FALSE,0));
SetDlgItemText(hDlg,IDC_DISASM_ADR,szAddress);
disassembler_map = MEM_MAP; // disassemble with mapped modules
disassembler_mode = HP_MNEMONICS; // use HP mnemonics for disassembling
dwAddress = strtoul(szAddress,&cpStop,16);
dwAddressMax = 0x100000; // greatest address (mapped mode)
return TRUE;
@ -1101,12 +1188,6 @@ static BOOL CALLBACK Disasm(HWND hDlg, UINT message, DWORD wParam, LONG lParam)
? (Chipset.Port2Size * 2048)
: ((dwPort2Mask != 0) ? ((dwPort2Mask + 1) << 18) : (dwPort2Size * 2048));
return TRUE;
case IDC_DISASM_HP:
disassembler_mode = HP_MNEMONICS;
return TRUE;
case IDC_DISASM_CLASS:
disassembler_mode = CLASS_MNEMONICS;
return TRUE;
case IDOK:
SendDlgItemMessage(hDlg,IDC_DISASM_ADR,EM_SETSEL,0,-1);
GetDlgItemText(hDlg,IDC_DISASM_ADR,szAddress,sizeof(szAddress));
@ -1121,7 +1202,7 @@ static BOOL CALLBACK Disasm(HWND hDlg, UINT message, DWORD wParam, LONG lParam)
case IDC_DISASM_NEXT:
if (dwAddress >= dwAddressMax)
return FALSE;
i = wsprintf(szAddress,(dwAddress <= 99999) ? "%05lX " : "%06lX ",dwAddress);
i = wsprintf(szAddress,(dwAddress <= 0xFFFFF) ? "%05lX " : "%06lX ",dwAddress);
dwAddress = disassemble(dwAddress,&szAddress[i],VIEW_LONG);
i = SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_ADDSTRING,0,(LPARAM) szAddress);
SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_SELITEMRANGE,FALSE,MAKELPARAM(0,i));
@ -1129,54 +1210,8 @@ static BOOL CALLBACK Disasm(HWND hDlg, UINT message, DWORD wParam, LONG lParam)
SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_SETTOPINDEX,i,0);
return TRUE;
case IDC_DISASM_COPY:
// get number of selections
if ((i = SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_GETSELCOUNT,0,0)) == 0)
break; // no items selected
if ((lpnCount = (LPINT) LocalAlloc(LMEM_FIXED,i * sizeof(INT))) != NULL)
{
HANDLE hClipObj;
LONG j,lMem = 0;
// get indexes of selected items
i = SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_GETSELITEMS,i,(LPARAM) lpnCount);
for (j = 0;j < i;++j) // scan all selected items
{
// calculate total amount of needed memory
lMem += SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_GETTEXTLEN,lpnCount[j],0) + 2;
}
// allocate clipboard data
if ((hClipObj = GlobalAlloc(GMEM_MOVEABLE,lMem + 1)) != NULL)
{
LPBYTE lpData;
if (lpData = GlobalLock(hClipObj))
{
for (j = 0;j < i;++j) // scan all selected items
{
lpData += SendDlgItemMessage(hDlg,IDC_DISASM_WIN,LB_GETTEXT,lpnCount[j],(LPARAM) lpData);
*lpData++ = '\r';
*lpData++ = '\n';
}
*lpData = 0; // set end of string
GlobalUnlock(hClipObj); // unlock memory
}
if (OpenClipboard(hWnd))
{
if (EmptyClipboard())
SetClipboardData(CF_TEXT,hClipObj);
else
GlobalFree(hClipObj);
CloseClipboard();
}
else // clipboard open failed
{
GlobalFree(hClipObj);
}
}
LocalFree(lpnCount); // free item table
}
// copy selected items to clipboard
CopyItemsToClipboard(GetDlgItem(hDlg,IDC_DISASM_WIN));
return TRUE;
case IDCANCEL:
EndDialog(hDlg, wParam);
@ -1335,29 +1370,17 @@ LRESULT CALLBACK MainWndProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lPar
return DefWindowProc(hWindow, uMsg, wParam, lParam);
}
#if 0 // 01.12.99 cg, removed
static BOOL FlushMessages(LPMSG msg)
{
while (PeekMessage(msg, NULL, 0, 0, PM_REMOVE))
{
if (msg->message == WM_QUIT) return TRUE;
TranslateMessage(msg);
DispatchMessage(msg);
}
return FALSE;
}
#endif // 01.12.99 cg
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS wc;
RECT rectWindow;
HSZ hszService, hszTopic; // variables for DDE server
DWORD dwAffMask;
hApp = hInst;
nArgc = __argc; // 08.11.99 cg, new, no. of command line arguments
ppArgv = (LPCTSTR*) __argv; // 08.11.99 cg, new, command line arguments
nArgc = __argc; // no. of command line arguments
ppArgv = (LPCTSTR*) __argv; // command line arguments
wc.style = CS_BYTEALIGNCLIENT;
wc.lpfnWndProc = (WNDPROC)MainWndProc;
@ -1379,7 +1402,6 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
}
// Create window
rectWindow.left = 0;
rectWindow.top = 0;
rectWindow.right = 256;
@ -1402,11 +1424,9 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
ShowWindow(hWnd, nCmdShow);
// 01.12.99 cg, removed, useless and quit with resources open
// if (FlushMessages(&msg)) return msg.wParam;
// initialization
QueryPerformanceFrequency(&lFreq); // init high resolution counter
QueryPerformanceCounter(&lAppStart);
GetCurrentDirectory(sizeof(szCurrentDirectory), szCurrentDirectory);
@ -1419,20 +1439,25 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
if (hEventShutdn == NULL)
{
AbortMessage("Event creation failed.");
DestroyWindow(hWnd); // 02.12.99 cg, bugfix, close DC
DestroyWindow(hWnd);
return FALSE;
}
nState = 1; // thread starts in an invalid state
nNextState = 1;
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&WorkerThread, NULL, 0, &lThreadId);
nState = 0; // init state must be <> nNextState
nNextState = 1; // go into invalid state
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&WorkerThread, NULL, CREATE_SUSPENDED, &lThreadId);
if (hThread == NULL)
{
CloseHandle(hEventShutdn); // close event handle
AbortMessage("Thread creation failed.");
DestroyWindow(hWnd); // 01.12.99 cg, bugfix, close DC
DestroyWindow(hWnd);
return FALSE;
}
// on multiprocessor machines for QueryPerformanceCounter()
dwAffMask = SetThreadAffinityMask(hThread,1);
_ASSERT(dwAffMask != 0);
ResumeThread(hThread); // start thread
while (nState!=nNextState) Sleep(0); // wait for thread initialized
// initialize DDE server
if (DdeInitialize(&idDdeInst,(PFNCALLBACK) &DdeCallback,
@ -1440,42 +1465,36 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
CBF_FAIL_EXECUTES | CBF_FAIL_ADVISES |
CBF_SKIP_REGISTRATIONS | CBF_SKIP_UNREGISTRATIONS,0))
{
TerminateThread(hThread, 0); // 01.12.99 cg, bugfix, kill emulation thread
CloseHandle(hEventShutdn); // 01.12.99 cg, bugfix, close event handle
TerminateThread(hThread, 0); // kill emulation thread
CloseHandle(hEventShutdn); // close event handle
AbortMessage("Could not initialize server!");
DestroyWindow(hWnd); // 01.12.99 cg, bugfix, close DC
DestroyWindow(hWnd);
return FALSE;
}
// 08.11.99 cg, changed, replaced __argc and __argv variable
_ASSERT(hWnd != NULL);
_ASSERT(hWindowDC != NULL);
if (nArgc >= 2) // use decoded parameter line
{
CHAR szTemp[256] = "Loading ";
strcat(szTemp, ppArgv[1]);
SetWindowTitle(szTemp);
// 01.12.99 cg, removed, useless and quit with resources open
// if (FlushMessages(&msg)) return msg.wParam;
if (OpenDocument(ppArgv[1]))
goto start;
}
// 08.11.99 cg, end of replacement
// 11.12.99 cg, changed, call function
ReadLastDocument(szBufferFilename, sizeof(szBufferFilename));
if (szBufferFilename[0])
{
CHAR szTemp[256] = "Loading ";
strcat(szTemp, szBufferFilename);
SetWindowTitle(szTemp);
// 01.12.99 cg, removed, useless and quit with resources open
// if (FlushMessages(&msg)) return msg.wParam;
if (OpenDocument(szBufferFilename))
goto start;
}
SetWindowTitle("New Document");
// 01.12.99 cg, removed, useless and quit with resources open
// if (FlushMessages(&msg)) return msg.wParam;
if (NewDocument())
{
SetWindowTitle("Untitled");
@ -1485,13 +1504,6 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
ResetDocument();
start:
InitializeCriticalSection(&csGDILock);
InitializeCriticalSection(&csKeyLock);
InitializeCriticalSection(&csIOLock);
InitializeCriticalSection(&csT1Lock);
InitializeCriticalSection(&csT2Lock);
InitializeCriticalSection(&csRecvLock); // 24.10.99 cg, moved, init critical section for receive byte
// init clipboard format and name service
uCF_HpObj = RegisterClipboardFormat(CF_HPOBJ);
hszService = DdeCreateStringHandle(idDdeInst,szAppName,0);
@ -1509,7 +1521,7 @@ start:
}
}
SwitchToState(2); // 01.12.99 cg, moved from OnDestroy(), exit emulation thread
SwitchToState(2); // exit emulation thread
// clean up DDE server
DdeNameService(idDdeInst, hszService, NULL, DNS_UNREGISTER);
@ -1517,14 +1529,7 @@ start:
DdeFreeStringHandle(idDdeInst, hszTopic);
DdeUninitialize(idDdeInst);
DeleteCriticalSection(&csGDILock);
DeleteCriticalSection(&csKeyLock);
DeleteCriticalSection(&csIOLock);
DeleteCriticalSection(&csT1Lock);
DeleteCriticalSection(&csT2Lock);
DeleteCriticalSection(&csRecvLock); // 24.10.99 cg, moved, end of critical section for receive byte
WriteSettings(); // 01.12.99 cg, moved from OnDestroy()
WriteSettings(); // save emulation settings
CloseHandle(hEventShutdn); // close event handle
_ASSERT(nState == 2); // emulation thread down?

View file

@ -112,13 +112,6 @@ SOURCE=.\Emu48.c
# Begin Source File
SOURCE=.\Emu48.rc
!IF "$(CFG)" == "Emu48 - Win32 Release"
!ELSEIF "$(CFG)" == "Emu48 - Win32 Debug"
!ENDIF
# End Source File
# Begin Source File
@ -138,6 +131,10 @@ SOURCE=.\files.c
# End Source File
# Begin Source File
SOURCE=.\i28f160.c
# End Source File
# Begin Source File
SOURCE=.\keyboard.c
# End Source File
# Begin Source File
@ -191,6 +188,10 @@ SOURCE=.\Emu48.h
# End Source File
# Begin Source File
SOURCE=.\i28f160.h
# End Source File
# Begin Source File
SOURCE=.\io.h
# End Source File
# Begin Source File

View file

@ -9,10 +9,10 @@
#include "types.h"
// cards status
#define PORT1_PRESENT ((cCurrentRomType=='S')?0x1:0x2)
#define PORT1_WRITE ((cCurrentRomType=='S')?0x4:0x8)
#define PORT2_PRESENT ((cCurrentRomType=='S')?0x2:0x1)
#define PORT2_WRITE ((cCurrentRomType=='S')?0x8:0x4)
#define PORT1_PRESENT ((cCurrentRomType=='S')?P1C:P2C)
#define PORT1_WRITE ((cCurrentRomType=='S')?P1W:P2W)
#define PORT2_PRESENT ((cCurrentRomType=='S')?P2C:P1C)
#define PORT2_WRITE ((cCurrentRomType=='S')?P2W:P1W)
#define BINARYHEADER48 "HPHP48-W"
#define BINARYHEADER49 "HPHP49-W"
@ -56,28 +56,29 @@ extern CRITICAL_SECTION csKeyLock;
extern CRITICAL_SECTION csIOLock;
extern CRITICAL_SECTION csT1Lock;
extern CRITICAL_SECTION csT2Lock;
extern CRITICAL_SECTION csRecvLock; // 24.10.99 cg, critical section for receive byte
extern INT nArgc; // 08.11.99 cg, no. of command line arguments
extern LPCTSTR *ppArgv; // 08.11.99 cg, command line arguments
extern CRITICAL_SECTION csRecvLock;
extern INT nArgc;
extern LPCTSTR *ppArgv;
extern LARGE_INTEGER lFreq;
extern LARGE_INTEGER lAppStart;
extern DWORD idDdeInst;
extern UINT uCF_HpObj;
extern HINSTANCE hApp;
extern HWND hWnd;
extern HDC hWindowDC;
extern BOOL bPort2IsShared;
extern BOOL bAutoSave; // 11.12.99 cg, add declaration
extern BOOL bAutoSaveOnExit; // 11.12.99 cg, add declaration
extern BOOL bAutoSave;
extern BOOL bAutoSaveOnExit;
extern BOOL bAlwaysDisplayLog;
// extern UINT uTimer1Period; // 11.12.99 cg, removed old definition
extern HANDLE hThread; // 11.12.99 cg, add declaration
extern DWORD lThreadId; // 11.12.99 cg, add declaration
extern HANDLE hThread;
extern DWORD lThreadId;
extern VOID SetWindowTitle(LPSTR szString);
extern VOID CopyItemsToClipboard(HWND hWnd);
extern VOID UpdateWindowStatus(VOID);
// Settings.c
extern VOID ReadSettings(VOID); // 11.12.99 cg, moved from Emu48.c
extern VOID WriteSettings(VOID); // 11.12.99 cg, moved from Emu48.c
extern VOID ReadSettings(VOID);
extern VOID WriteSettings(VOID);
extern VOID ReadLastDocument(LPTSTR szFileName, DWORD nSize);
extern VOID WriteLastDocument(LPCTSTR szFilename);
@ -110,7 +111,7 @@ extern VOID ResizeWindow(VOID);
extern BOOL bInterrupt;
extern UINT nState;
extern UINT nNextState;
extern BOOL bRealSpeed; // 11.12.99 cg, new, real speed flag
extern BOOL bRealSpeed;
extern BOOL bKeySlow;
extern CHIPSET Chipset;
extern char szSerialWire[16];
@ -141,6 +142,7 @@ extern char szPort2Filename[260];
extern LPBYTE pbyRom;
extern DWORD dwRomSize;
extern char cCurrentRomType;
extern BOOL bRomWriteable;
extern LPBYTE pbyPort2;
extern BOOL bPort2Writeable;
extern BOOL bPort2IsShared;
@ -152,6 +154,7 @@ extern BOOL MapRom(LPCSTR szFilename);
extern VOID UnmapRom(VOID);
extern BOOL MapPort2(LPCSTR szFilename);
extern VOID UnmapPort2(VOID);
extern VOID UpdatePatches(BOOL bPatch);
extern BOOL PatchRom(LPCSTR szFilename);
extern VOID ResetDocument(VOID);
extern BOOL NewDocument(VOID);
@ -181,6 +184,7 @@ extern VOID SetT1(BYTE byValue);
// MOps.c
extern BOOL ioc_acc;
extern BOOL ir_ctrl_acc;
extern BOOL bFlashRomArray;
extern BYTE disp;
extern LPBYTE RMap[256];
extern LPBYTE WMap[256];
@ -190,7 +194,7 @@ extern VOID Config(VOID);
extern VOID Uncnfg(VOID);
extern VOID Reset(VOID);
extern VOID C_Eq_Id(VOID);
extern VOID CpuReset(VOID); // 19.03.99 cg, register setting after Cpu Reset
extern VOID CpuReset(VOID);
extern BYTE GetLineCounter(VOID);
extern VOID Npeek(BYTE *a, DWORD d, UINT s);
extern VOID Nread(BYTE *a, DWORD d, UINT s);
@ -231,7 +235,7 @@ extern WORD CommConnect(VOID);
extern VOID CommOpen(LPSTR strWirePort,LPSTR strIrPort);
extern VOID CommClose(VOID);
extern VOID CommSetBaud(VOID);
extern VOID UpdateUSRQ(VOID); // 25.10.99 cg, USRQ handling
extern VOID UpdateUSRQ(VOID);
extern VOID CommTransmit(VOID);
extern VOID CommReceive(VOID);

View file

@ -32,9 +32,9 @@ BEGIN
IDD_BREAKEDIT, DIALOG
BEGIN
LEFTMARGIN, 5
RIGHTMARGIN, 105
RIGHTMARGIN, 106
TOPMARGIN, 5
BOTTOMMARGIN, 97
BOTTOMMARGIN, 95
END
IDD_ABOUT, DIALOG
@ -50,7 +50,7 @@ BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 160
TOPMARGIN, 4
BOTTOMMARGIN, 171
BOTTOMMARGIN, 202
END
IDD_CHOOSEKML, DIALOG
@ -80,9 +80,9 @@ BEGIN
IDD_DEBUG, DIALOG
BEGIN
LEFTMARGIN, 5
RIGHTMARGIN, 273
TOPMARGIN, 5
BOTTOMMARGIN, 212
RIGHTMARGIN, 274
TOPMARGIN, 2
BOTTOMMARGIN, 252
END
IDD_NEWVALUE, DIALOG
@ -100,6 +100,22 @@ BEGIN
TOPMARGIN, 7
BOTTOMMARGIN, 43
END
IDD_ENTERBREAK, DIALOG
BEGIN
LEFTMARGIN, 8
RIGHTMARGIN, 149
TOPMARGIN, 7
BOTTOMMARGIN, 69
END
IDD_INSTRUCTIONS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 162
END
END
#endif // APSTUDIO_INVOKED
@ -109,17 +125,17 @@ END
// Dialog
//
IDD_BREAKEDIT DIALOG DISCARDABLE 0, 0, 110, 102
IDD_BREAKEDIT DIALOG DISCARDABLE 0, 0, 111, 100
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Edit breakpoints"
FONT 8, "Courier New"
BEGIN
DEFPUSHBUTTON "OK",IDOK,77,83,28,14
DEFPUSHBUTTON "OK",IDOK,78,81,28,14
LTEXT "Current breakpoints:",IDC_STATIC_BREAKPOINT,5,5,82,8
LISTBOX IDC_BREAKEDIT_WND,5,17,100,60,NOT LBS_NOTIFY | LBS_SORT |
LISTBOX IDC_BREAKEDIT_WND,5,17,101,58,NOT LBS_NOTIFY | LBS_SORT |
LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "&Add",IDC_BREAKEDIT_ADD,5,83,28,14
PUSHBUTTON "&Delete",IDC_BREAKEDIT_DELETE,41,83,28,14
PUSHBUTTON "&Add",IDC_BREAKEDIT_ADD,5,81,28,14
PUSHBUTTON "&Delete",IDC_BREAKEDIT_DELETE,41,81,28,14
END
IDD_ABOUT DIALOGEX 0, 0, 261, 160
@ -130,21 +146,18 @@ BEGIN
ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE,
WS_EX_TRANSPARENT
LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP
LTEXT "Copyright © 1999 Sébastien Carlier && Christoph Gießelink",
LTEXT "Copyright © 2000 Sébastien Carlier && Christoph Gießelink",
IDC_STATIC,29,18,181,8
DEFPUSHBUTTON "OK",IDOK,215,12,39,14
EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL |
ES_READONLY
END
IDD_SETTINGS DIALOGEX 0, 0, 167, 178
IDD_SETTINGS DIALOGEX 0, 0, 167, 209
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Settings"
FONT 8, "MS Sans Serif", 0, 0, 0x1
BEGIN
GROUPBOX "General",IDC_STATIC,7,4,153,63
GROUPBOX "Memory Cards",IDC_STATIC,7,70,153,50
GROUPBOX "Serial Ports",IDC_STATIC,7,124,153,27
CONTROL "Authentic Calculator Speed",IDC_REALSPEED,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,13,13,104,10
CONTROL "Automatically Save Files",IDC_AUTOSAVE,"Button",
@ -154,22 +167,30 @@ BEGIN
CONTROL "Always display KML Compilation Result",
IDC_ALWAYSDISPLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
13,52,136,10
GROUPBOX "General",IDC_STATIC,7,4,153,63
CONTROL "HP Mnemonics",IDC_DISASM_HP,"Button",BS_AUTORADIOBUTTON |
WS_GROUP | WS_TABSTOP,13,81,65,11
CONTROL "Class Mnemonics",IDC_DISASM_CLASS,"Button",
BS_AUTORADIOBUTTON,84,81,70,11
GROUPBOX "Disassembler",IDC_DISASM_MNEMONICS,7,70,153,28
CONTROL "Port 1 is Plugged",IDC_PORT1EN,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,13,79,67,10
WS_TABSTOP,13,110,67,10
CONTROL "Port 1 is Writeable",IDC_PORT1WR,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,84,79,69,10
BS_AUTOCHECKBOX | WS_TABSTOP,84,110,69,10
CONTROL "Port 2 is Shared",IDC_PORT2ISSHARED,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,13,92,65,10
LTEXT "Port 2 File :",IDC_STATIC,13,105,37,8
EDITTEXT IDC_PORT2,51,103,104,12,ES_AUTOHSCROLL
LTEXT "Wire:",IDC_STATIC,13,136,17,8
COMBOBOX IDC_WIRE,31,134,48,42,CBS_DROPDOWNLIST | WS_VSCROLL |
BS_AUTOCHECKBOX | WS_TABSTOP,13,123,65,10
LTEXT "Port 2 File :",IDC_STATIC,13,136,37,8
EDITTEXT IDC_PORT2,51,134,104,12,ES_AUTOHSCROLL
GROUPBOX "Memory Cards",IDC_STATIC,7,101,153,50
LTEXT "Wire:",IDC_STATIC,13,166,17,8
COMBOBOX IDC_WIRE,31,164,48,42,CBS_DROPDOWNLIST | WS_VSCROLL |
WS_TABSTOP,WS_EX_LEFTSCROLLBAR
LTEXT "IR:",IDC_STATIC,89,136,9,8
COMBOBOX IDC_IR,107,134,48,43,CBS_DROPDOWNLIST | WS_VSCROLL |
LTEXT "IR:",IDC_STATIC,89,166,9,8
COMBOBOX IDC_IR,107,164,48,43,CBS_DROPDOWNLIST | WS_VSCROLL |
WS_TABSTOP
DEFPUSHBUTTON "&Ok",IDOK,9,157,50,14
PUSHBUTTON "&Cancel",IDCANCEL,107,157,50,14
GROUPBOX "Serial Ports",IDC_STATIC,7,154,153,27
DEFPUSHBUTTON "&Ok",IDOK,9,188,50,14
PUSHBUTTON "&Cancel",IDCANCEL,107,188,50,14
END
IDD_CHOOSEKML DIALOG DISCARDABLE 0, 0, 186, 66
@ -215,90 +236,111 @@ BEGIN
PUSHBUTTON "&Next Address",IDC_DISASM_NEXT,99,144,47,14
PUSHBUTTON "&Copy Data",IDC_DISASM_COPY,150,144,47,14
PUSHBUTTON "Cancel",IDCANCEL,201,144,47,14
GROUPBOX "Module",IDC_DISASM_MODULE,7,5,166,26
GROUPBOX "Module",IDC_DISASM_MODULE,7,5,241,26
CONTROL "Map",IDC_DISASM_MAP,"Button",BS_AUTORADIOBUTTON |
WS_GROUP | WS_TABSTOP,14,16,28,10
CONTROL "ROM",IDC_DISASM_ROM,"Button",BS_AUTORADIOBUTTON,45,16,
28,10
CONTROL "RAM",IDC_DISASM_RAM,"Button",BS_AUTORADIOBUTTON,76,16,
28,10
WS_GROUP | WS_TABSTOP,14,16,37,10
CONTROL "ROM",IDC_DISASM_ROM,"Button",BS_AUTORADIOBUTTON,61,16,
37,10
CONTROL "RAM",IDC_DISASM_RAM,"Button",BS_AUTORADIOBUTTON,108,16,
37,10
CONTROL "Port 1",IDC_DISASM_PORT1,"Button",BS_AUTORADIOBUTTON,
107,16,28,10
155,16,37,10
CONTROL "Port 2",IDC_DISASM_PORT2,"Button",BS_AUTORADIOBUTTON,
138,16,28,10
GROUPBOX "Mnemonics",IDC_DISASM_MNEMONICS,180,5,68,26
CONTROL "HP",IDC_DISASM_HP,"Button",BS_AUTORADIOBUTTON |
WS_GROUP | WS_TABSTOP,187,16,24,10
CONTROL "Class",IDC_DISASM_CLASS,"Button",BS_AUTORADIOBUTTON,215,
16,31,10
202,16,37,10
LISTBOX IDC_DISASM_WIN,7,37,241,100,NOT LBS_NOTIFY |
LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL |
WS_TABSTOP,WS_EX_NOPARENTNOTIFY
END
IDD_DEBUG DIALOGEX 0, 0, 278, 217
IDD_DEBUG DIALOGEX 0, 0, 279, 254
STYLE WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Debugger"
MENU IDR_DEBUG
FONT 8, "Courier New", 0, 0, 0x1
BEGIN
LISTBOX IDC_DEBUG_CODE,11,15,165,122,NOT LBS_NOTIFY |
LISTBOX IDC_DEBUG_CODE,11,12,165,122,NOT LBS_NOTIFY |
LBS_OWNERDRAWFIXED | LBS_HASSTRINGS |
LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT |
WS_TABSTOP
GROUPBOX "Code",IDC_STATIC_CODE,5,5,177,138
LTEXT "A= 0000000000000000",IDC_REG_A,192,15,77,8
LTEXT "B= 0000000000000000",IDC_REG_B,192,22,77,8
LTEXT "C= 0000000000000000",IDC_REG_C,192,29,77,8
LTEXT "D= 0000000000000000",IDC_REG_D,192,36,77,8
LTEXT "R0=0000000000000000",IDC_REG_R0,192,46,77,8
LTEXT "R1=0000000000000000",IDC_REG_R1,192,53,77,8
LTEXT "R2=0000000000000000",IDC_REG_R2,192,60,77,8
LTEXT "R3=0000000000000000",IDC_REG_R3,192,67,77,8
LTEXT "R4=0000000000000000",IDC_REG_R4,192,74,77,8
LTEXT "D0=00000",IDC_REG_D0,192,85,33,8
LTEXT "D1=00000",IDC_REG_D1,236,85,33,8
LTEXT "P=0",IDC_REG_P,192,96,13,8
LTEXT "PC=00000",IDC_REG_PC,236,96,33,8
LTEXT "OUT=000",IDC_REG_OUT,192,107,29,8
LTEXT "IN=0000",IDC_REG_IN,240,107,29,8
LTEXT "ST=0000",IDC_REG_ST,192,118,29,8
LTEXT "CY=0",IDC_REG_CY,224,118,17,8
LTEXT "Mode=H",IDC_REG_MODE,244,118,25,8
LTEXT "MP=0",IDC_REG_MP,192,128,17,8
LTEXT "SR=0",IDC_REG_SR,212,128,17,8
LTEXT "SB=0",IDC_REG_SB,232,128,17,8
LTEXT "XM=0",IDC_REG_XM,252,128,17,8
GROUPBOX "Registers",IDC_STATIC_REGISTERS,186,5,87,138
CONTROL "",IDC_DEBUG_MEM,"Static",SS_WHITERECT | WS_GROUP,11,154,
GROUPBOX "Code",IDC_STATIC_CODE,5,2,177,138
LTEXT "A= 0000000000000000",IDC_REG_A,192,12,77,8
LTEXT "B= 0000000000000000",IDC_REG_B,192,19,77,8
LTEXT "C= 0000000000000000",IDC_REG_C,192,26,77,8
LTEXT "D= 0000000000000000",IDC_REG_D,192,33,77,8
LTEXT "R0=0000000000000000",IDC_REG_R0,192,43,77,8
LTEXT "R1=0000000000000000",IDC_REG_R1,192,50,77,8
LTEXT "R2=0000000000000000",IDC_REG_R2,192,57,77,8
LTEXT "R3=0000000000000000",IDC_REG_R3,192,64,77,8
LTEXT "R4=0000000000000000",IDC_REG_R4,192,71,77,8
LTEXT "D0=00000",IDC_REG_D0,192,82,33,8
LTEXT "D1=00000",IDC_REG_D1,236,82,33,8
LTEXT "P=0",IDC_REG_P,192,93,13,8
LTEXT "PC=00000",IDC_REG_PC,236,93,33,8
LTEXT "OUT=000",IDC_REG_OUT,192,104,29,8
LTEXT "IN=0000",IDC_REG_IN,240,104,29,8
LTEXT "ST=0000",IDC_REG_ST,192,115,29,8
LTEXT "CY=0",IDC_REG_CY,224,115,17,8
LTEXT "Mode=H",IDC_REG_MODE,244,115,25,8
LTEXT "MP=0",IDC_REG_MP,192,125,17,8
LTEXT "SR=0",IDC_REG_SR,212,125,17,8
LTEXT "SB=0",IDC_REG_SB,232,125,17,8
LTEXT "XM=0",IDC_REG_XM,252,125,17,8
GROUPBOX "Registers",IDC_STATIC_REGISTERS,187,2,87,138
CONTROL "",IDC_DEBUG_MEM,"Static",SS_WHITERECT | WS_GROUP,11,151,
165,52,WS_EX_CLIENTEDGE
LISTBOX IDC_DEBUG_MEM_ADDR,12,156,25,48,NOT LBS_NOTIFY |
LISTBOX IDC_DEBUG_MEM_ADDR,12,153,25,48,NOT LBS_NOTIFY |
LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_DISABLED | NOT
WS_BORDER
LISTBOX IDC_DEBUG_MEM_COL0,40,156,11,48,LBS_NOINTEGRALHEIGHT |
LISTBOX IDC_DEBUG_MEM_COL0,40,153,11,48,LBS_NOINTEGRALHEIGHT |
LBS_WANTKEYBOARDINPUT | NOT WS_BORDER | WS_TABSTOP
LISTBOX IDC_DEBUG_MEM_COL1,52,156,11,48,LBS_NOINTEGRALHEIGHT |
LISTBOX IDC_DEBUG_MEM_COL1,52,153,11,48,LBS_NOINTEGRALHEIGHT |
LBS_WANTKEYBOARDINPUT | NOT WS_BORDER
LISTBOX IDC_DEBUG_MEM_COL2,64,156,11,48,LBS_NOINTEGRALHEIGHT |
LISTBOX IDC_DEBUG_MEM_COL2,64,153,11,48,LBS_NOINTEGRALHEIGHT |
LBS_WANTKEYBOARDINPUT | NOT WS_BORDER
LISTBOX IDC_DEBUG_MEM_COL3,76,156,11,48,LBS_NOINTEGRALHEIGHT |
LISTBOX IDC_DEBUG_MEM_COL3,76,153,11,48,LBS_NOINTEGRALHEIGHT |
LBS_WANTKEYBOARDINPUT | NOT WS_BORDER
LISTBOX IDC_DEBUG_MEM_COL4,88,156,11,48,LBS_NOINTEGRALHEIGHT |
LISTBOX IDC_DEBUG_MEM_COL4,88,153,11,48,LBS_NOINTEGRALHEIGHT |
LBS_WANTKEYBOARDINPUT | NOT WS_BORDER
LISTBOX IDC_DEBUG_MEM_COL5,100,156,11,48,LBS_NOINTEGRALHEIGHT |
LISTBOX IDC_DEBUG_MEM_COL5,100,153,11,48,LBS_NOINTEGRALHEIGHT |
LBS_WANTKEYBOARDINPUT | NOT WS_BORDER
LISTBOX IDC_DEBUG_MEM_COL6,112,156,11,48,LBS_NOINTEGRALHEIGHT |
LISTBOX IDC_DEBUG_MEM_COL6,112,153,11,48,LBS_NOINTEGRALHEIGHT |
LBS_WANTKEYBOARDINPUT | NOT WS_BORDER
LISTBOX IDC_DEBUG_MEM_COL7,124,156,11,48,LBS_NOINTEGRALHEIGHT |
LISTBOX IDC_DEBUG_MEM_COL7,124,153,11,48,LBS_NOINTEGRALHEIGHT |
LBS_WANTKEYBOARDINPUT | NOT WS_BORDER
LISTBOX IDC_DEBUG_MEM_TEXT,139,156,35,48,NOT LBS_NOTIFY |
LISTBOX IDC_DEBUG_MEM_TEXT,139,153,35,48,NOT LBS_NOTIFY |
LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_DISABLED | NOT
WS_BORDER
GROUPBOX "Memory",IDC_STATIC_MEMORY,5,144,177,68
LISTBOX IDC_DEBUG_STACK,192,154,75,52,NOT LBS_NOTIFY |
GROUPBOX "Memory",IDC_STATIC_MEMORY,5,141,177,68
LISTBOX IDC_DEBUG_STACK,192,151,76,52,NOT LBS_NOTIFY |
LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT |
WS_VSCROLL | WS_TABSTOP
GROUPBOX "Stack",IDC_STATIC_STACK,186,144,87,68
GROUPBOX "Stack",IDC_STATIC_STACK,187,141,87,68
LTEXT "Size Mask",IDC_STATIC,11,228,37,8
LTEXT "Address",IDC_STATIC,11,236,29,8
CTEXT "I/O",IDC_STATIC,55,220,21,8
CTEXT "NCE2",IDC_STATIC,80,220,21,8
CTEXT "CE1",IDC_STATIC,105,220,21,8
CTEXT "CE2",IDC_STATIC,130,220,21,8
CTEXT "NCE3",IDC_STATIC,155,220,21,8
CTEXT "-----",IDC_MMU_IO_S,55,228,21,8
CTEXT "-----",IDC_MMU_NCE2_S,80,228,21,8
CTEXT "-----",IDC_MMU_CE1_S,105,228,21,8
CTEXT "-----",IDC_MMU_CE2_S,130,228,21,8
CTEXT "-----",IDC_MMU_NCE3_S,155,228,21,8
CTEXT "-----",IDC_MMU_IO_A,55,236,21,8
CTEXT "-----",IDC_MMU_CE1_A,105,236,21,8
CTEXT "-----",IDC_MMU_CE2_A,130,236,21,8
CTEXT "-----",IDC_MMU_NCE2_A,80,236,21,8
CTEXT "-----",IDC_MMU_NCE3_A,155,236,21,8
GROUPBOX "MMU",IDC_STATIC_MMU,5,210,177,39
LTEXT "Interrupts =",IDC_STATIC,193,220,61,8
LTEXT "Keyboard Scan =",IDC_STATIC,193,228,61,8
LTEXT "Bank Switcher =",IDC_MISC_BS_TXT,193,236,61,8,
WS_DISABLED
LTEXT "",IDC_MISC_INT,256,220,13,8
LTEXT "",IDC_MISC_KEY,256,228,13,8
LTEXT "00",IDC_MISC_BS,256,236,13,8,WS_DISABLED
GROUPBOX "Miscellaneous",IDC_STATIC_MISC,187,210,87,39
END
IDD_NEWVALUE DIALOG DISCARDABLE 0, 0, 175, 50
@ -323,6 +365,40 @@ BEGIN
PUSHBUTTON "Cancel",IDCANCEL,92,29,50,14
END
IDD_ENTERBREAK DIALOG DISCARDABLE 0, 0, 156, 76
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Enter breakpoint"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Enter breakpoint (hexdezimal):",IDC_STATIC,8,9,96,8
EDITTEXT IDC_ENTERADR,110,7,39,12,ES_AUTOHSCROLL
CONTROL "&Code",IDC_BPCODE,"Button",BS_AUTORADIOBUTTON |
WS_GROUP | WS_TABSTOP,17,24,33,10
CONTROL "Memory &Access",IDC_BPACCESS,"Button",
BS_AUTORADIOBUTTON,79,24,63,10
CONTROL "Memory &Read",IDC_BPREAD,"Button",BS_AUTORADIOBUTTON,17,
38,60,10
CONTROL "Memory &Write",IDC_BPWRITE,"Button",BS_AUTORADIOBUTTON,
79,38,59,10
DEFPUSHBUTTON "OK",IDOK,14,55,50,14
PUSHBUTTON "Cancel",IDCANCEL,92,55,50,14
END
IDD_INSTRUCTIONS DIALOGEX 0, 0, 186, 169
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Last Instructions"
FONT 8, "Courier New", 0, 0, 0x1
BEGIN
LTEXT "Instructions (disassembly maybe incorrect):",
IDC_INSTR_TEXT,7,7,173,8
LISTBOX IDC_INSTR_CODE,7,18,172,122,NOT LBS_NOTIFY |
LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL |
WS_TABSTOP,WS_EX_NOPARENTNOTIFY
PUSHBUTTON "&Copy Data",IDC_INSTR_COPY,7,148,50,14
PUSHBUTTON "C&lear Data",IDC_INSTR_CLEAR,68,148,50,14
DEFPUSHBUTTON "Cancel",IDCANCEL,129,148,50,14
END
#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
@ -331,8 +407,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,1,5,0
PRODUCTVERSION 1,1,5,0
FILEVERSION 1,2,0,0
PRODUCTVERSION 1,2,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x21L
@ -347,15 +423,15 @@ BEGIN
BEGIN
BLOCK "00000000"
BEGIN
VALUE "CompanyName", "Sebastien Carlier\0"
VALUE "FileDescription", "HP38/48/49 Emulator\0"
VALUE "FileVersion", "1, 1, 5, 0\0"
VALUE "CompanyName", "Sebastien Carlier & Christoph Gießelink\0"
VALUE "FileDescription", "HP38/39/40/48/49 Emulator\0"
VALUE "FileVersion", "1, 2, 0, 0\0"
VALUE "InternalName", "Emu48\0"
VALUE "LegalCopyright", "Copyright © 1999\0"
VALUE "LegalCopyright", "Copyright © 2000\0"
VALUE "OriginalFilename", "Emu48.exe\0"
VALUE "ProductName", "Emu48\0"
VALUE "ProductVersion", "1, 1, 5, 0\0"
VALUE "SpecialBuild", "Service Pack 15, Christoph Gießelink\0"
VALUE "ProductVersion", "1, 2, 0, 0\0"
VALUE "SpecialBuild", "Service Pack 20, Christoph Gießelink\0"
END
END
BLOCK "VarFileInfo"
@ -445,6 +521,16 @@ BEGIN
MENUITEM "&Clear all breakpoints", ID_BREAKPOINTS_CLEARALL
MENUITEM SEPARATOR
MENUITEM "&NOP3 code breakpoints", ID_BREAKPOINTS_NOP3
MENUITEM SEPARATOR
MENUITEM "&RPL breakpoints", ID_BREAKPOINTS_RPL
END
POPUP "I&nterrupts"
BEGIN
MENUITEM "&Step Over Interrupts", ID_INTR_STEPOVERINT
END
POPUP "&Info"
BEGIN
MENUITEM "&Last Instructions...", ID_INFO_LASTINSTRUCTIONS
END
END

View file

@ -9,7 +9,7 @@
#include "pch.h"
#include "Emu48.h"
#include "Opcodes.h"
#include "io.h" // 24.10.99 cg, renamed from Serial.h
#include "io.h"
#include "debugger.h"
#define SAMPLE 16384 // speed adjust sample frequency
@ -17,7 +17,7 @@
BOOL bInterrupt = FALSE;
UINT nState = 1;
UINT nNextState = 0;
BOOL bRealSpeed = FALSE; // 11.12.99 cg, moved from Emu48.c
BOOL bRealSpeed = FALSE;
BOOL bKeySlow = FALSE; // slow down for key emulation
CHIPSET Chipset;
@ -28,7 +28,10 @@ DWORD dwSXCycles = 82; // SX cpu cycles in interval
DWORD dwGXCycles = 123; // GX cpu cycles in interval
static BOOL bCommInit = FALSE; // COM port not open
static BOOL bCpuSlow = FALSE; // 11.12.99 cg, renamed, enable/disable real speed
static BOOL bCpuSlow = FALSE; // enable/disable real speed
static DWORD dwEDbgT2 = 0; // debugger timer2 emulation
static DWORD dwEDbgCycles = 0; // debugger cycle counter
static DWORD dwOldCyc; // cpu cycles at last event
static DWORD dwSpeedRef; // timer value at last event
@ -36,6 +39,151 @@ static DWORD dwTickRef; // sample timer ticks
#include "Ops.h"
// save last instruction in circular instruction buffer
static __inline VOID SaveInstrAddr(DWORD dwAddr)
{
if (pdwInstrArray) // circular buffer allocated
{
pdwInstrArray[wInstrWp] = dwAddr;
wInstrWp = (wInstrWp + 1) % wInstrSize;
if (wInstrWp == wInstrRp)
wInstrRp = (wInstrRp + 1) % wInstrSize;
}
return;
}
static __inline VOID Debugger(VOID) // debugger part
{
LARGE_INTEGER lDummyInt; // sample timer ticks
BOOL bStopEmulation;
BOOL bRplBreak = FALSE; // flag for RPL breakpoint
LPBYTE I = FASTPTR(Chipset.pc); // get opcode stream
SaveInstrAddr(Chipset.pc); // save pc in last instruction buffer
// check for code breakpoints
bStopEmulation = CheckBreakpoint(Chipset.pc, 1, BP_EXEC);
// check for memory breakpoints, opcode #14x or #15x
if (I[0] == 0x1 && (I[1] == 0x4 || I[1] == 0x5))
{
DWORD dwData = (I[2] & 0x1) ? Chipset.d1 : Chipset.d0;
UINT nType = (I[2] & 0x2) ? BP_READ : BP_WRITE;
DWORD dwRange;
if (I[1] == 0x4) // B,A
{
dwRange = (I[2] & 0x8) ? 2 : 5;
}
else // P,WP,XS,X,S,M,W or number of nibbles
{
if (I[2] & 0x8) // number of nibbles
{
dwRange = I[3]+1;
}
else // P,WP,XS,X,S,M,W
{
dwData += F_s[I[3]];
dwRange = F_l[I[3]];
}
}
#if defined DEBUG_DEBUGGER
{
char buffer[256];
wsprintf(buffer,"Memory breakpoint %.5lx, %u\n",dwData,dwRange);
OutputDebugString(buffer);
}
#endif
bStopEmulation |= CheckBreakpoint(dwData, dwRange, nType);
}
// NOP3, opcode #420 (GOC)
if (bDbgNOP3 && I[0] == 0x4 && I[1] == 0x2 && I[2] == 0x0)
bStopEmulation = TRUE;
// RPL breakpoints, PC=(A), opcode #808C or PC=(C), opcode #808E
if (bDbgRPL && I[0] == 0x8 && I[1] == 0x0 && I[2] == 0x8 && (I[3] == 0xC || I[3] == 0xE ))
{
BYTE byRplPtr[5];
// A=DAT0 A, D0=D0+ 5, PC=(A)
// C=DAT0 A, D0=D0+ 5, PC=(C)
Npeek(byRplPtr,Chipset.d0-5,5);
if (memcmp(byRplPtr,(I[3] == 0xC) ? Chipset.A : Chipset.C,5) == 0)
{
bRplBreak = TRUE;
bStopEmulation = TRUE;
}
}
// step over interrupt execution
if (bDbgSkipInt && !bStopEmulation && !Chipset.inte)
return;
// check for step into
bStopEmulation |= (nDbgState == DBG_STEPINTO);
// check for step over
bStopEmulation |= (nDbgState == DBG_STEPOVER) && dwDbgRstkp == Chipset.rstkp;
// check for step out, something was popped from hardware stack
if (nDbgState == DBG_STEPOUT && dwDbgRstkp == Chipset.rstkp)
{
_ASSERT(bStopEmulation == FALSE);
if ((bStopEmulation = (Chipset.pc == dwDbgRstk)) == FALSE)
{
// it was C=RSTK, check for next object popped from hardware stack
dwDbgRstkp = (Chipset.rstkp-1)&7;
dwDbgRstk = Chipset.rstk[dwDbgRstkp];
}
}
if (bStopEmulation) // stop condition
{
StopTimers(); // hold timer values when emulator is stopped
if (Chipset.IORam[TIMER2_CTRL]&RUN) // check if timer running
{
if (dwEDbgT2 == Chipset.t2)
{
// cpu cycles for one timer2 tick elapsed
if ((DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwEDbgCycles
>= (SAMPLE / 8192) * (DWORD) T2CYCLES)
{
--Chipset.t2;
// adjust cycles reference
dwEDbgCycles += (SAMPLE / 8192) * T2CYCLES;
}
}
else // new timer2 value
{
// new cycle reference
dwEDbgCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
}
// check rising edge of Bit 8 of timer2
if ((dwEDbgT2 & 0x100) == 0 && (Chipset.t2 & 0x100) != 0)
Chipset.t1 = (Chipset.t1 - 1) & 0xF;
}
dwEDbgT2 = Chipset.t2; // timer2 check reference value
// OutputDebugString("Emulator stopped...\n");
NotifyDebugger(bRplBreak);
WaitForSingleObject(hEventDebug,INFINITE);
// OutputDebugString("Emulator running...\n");
StartTimers(); // continue timers
Chipset.Shutdn = FALSE;
Chipset.bShutdnWake = FALSE;
// init slow down part
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
QueryPerformanceCounter(&lDummyInt);
dwSpeedRef = lDummyInt.LowPart;
}
}
static __inline VOID CheckDisp(BOOL bSync)
{
if (disp == 0) return; // no display update need
@ -83,11 +231,12 @@ static __inline VOID CheckSerial(VOID)
static __inline VOID AdjustSpeed(VOID) // adjust emulation speed
{
if (bCpuSlow || bKeySlow) // 11.12.99 cg, changed, emulation slow down
if (bCpuSlow || bKeySlow) // emulation slow down
{
DWORD dwCycles,dwTicks;
// cycles elapsed for next check
// 22.11.99 cg, changed, DWORD casting of Chipset.cycles
if ((DWORD) (Chipset.cycles & 0xFFFFFFFF)-dwOldCyc >= (DWORD) T2CYCLES)
if ((dwCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF)-dwOldCyc) >= (DWORD) T2CYCLES)
{
LARGE_INTEGER lAct;
do
@ -95,12 +244,24 @@ static __inline VOID AdjustSpeed(VOID) // adjust emulation speed
BOOL bErr = QueryPerformanceCounter(&lAct);
_ASSERT(bErr); // no high-resolution performance counter
}
while(lAct.LowPart-dwSpeedRef <= dwTickRef);
while((dwTicks = lAct.LowPart-dwSpeedRef) <= dwTickRef);
// workaround for QueryPerformanceCounter() in Win2k,
// if last command sequence took over 50ms -> synchronize
if(dwTicks > 819 * dwTickRef) // time for last commands > 50ms (819 / 16384Hz)
{
// new synchronizing
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
QueryPerformanceCounter(&lAct); // get timer ticks
dwSpeedRef = lAct.LowPart; // save reference time
}
else
{
dwOldCyc += T2CYCLES; // adjust cycles reference
dwSpeedRef += dwTickRef; // adjust reference time
}
}
}
return;
}
@ -109,7 +270,7 @@ VOID AdjKeySpeed(VOID) // slow down key repeat
WORD i;
BOOL bKey;
if (bCpuSlow) return; // 11.12.99 cg, changed, no need to slow down
if (bCpuSlow) return; // no need to slow down
bKey = FALSE; // search for a pressed key
for (i = 0;i < sizeof(Chipset.Keyboard_Row) / sizeof(Chipset.Keyboard_Row[0]) && !bKey;++i)
@ -119,7 +280,6 @@ VOID AdjKeySpeed(VOID) // slow down key repeat
{
LARGE_INTEGER lTime; // sample timer ticks
// save reference cycles
// 22.11.99 cg, changed, DWORD casting
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
QueryPerformanceCounter(&lTime); // get timer ticks
dwSpeedRef = lTime.LowPart; // save reference time
@ -134,17 +294,15 @@ VOID SetSpeed(BOOL bAdjust) // set emulation speed
{
LARGE_INTEGER lTime; // sample timer ticks
// save reference cycles
// 22.11.99 cg, changed, DWORD casting
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
QueryPerformanceCounter(&lTime); // get timer ticks
dwSpeedRef = lTime.LowPart; // save reference time
}
bCpuSlow = bAdjust; // 11.12.99 cg, changed, save emulation speed
bCpuSlow = bAdjust; // save emulation speed
}
VOID UpdateKdnBit(VOID) // update KDN bit
{
// 22.11.99 cg, changed, DWORD casting of Chipset.cycles
if (Chipset.intk && (DWORD) (Chipset.cycles & 0xFFFFFFFFF) - Chipset.dwKdnCycles > (DWORD) T2CYCLES * 16)
IOBit(0x19,8,Chipset.in != 0);
}
@ -214,7 +372,8 @@ UINT SwitchToState(UINT nNewState)
{
case 0: // -> Run
nNextState = 0;
bInterrupt = FALSE;
// don't enter opcode loop on interrupt request
bInterrupt = Chipset.Shutdn || Chipset.SoftInt;
SetEvent(hEventShutdn);
while (nState!=nNextState) Sleep(0);
UpdateWindowStatus();
@ -297,13 +456,26 @@ loop:
if (bPort2Writeable) // is card writeable
Chipset.cards_status |= PORT2_WRITE;
}
// card detection off and timer running
if ((Chipset.IORam[CARDCTL] & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0)
{
BOOL bNINT2 = Chipset.IORam[SRQ1] == 0 && (Chipset.IORam[SRQ2] & LSRQ) == 0;
BOOL bNINT = (Chipset.IORam[CARDCTL] & SMP) == 0;
// state of CDT2
bNINT2 = bNINT2 && (Chipset.cards_status & (P2W|P2C)) != P2C;
// state of CDT1
bNINT = bNINT && (Chipset.cards_status & (P1W|P1C)) != P1C;
IOBit(SRQ2,NINT2,bNINT2);
IOBit(SRQ2,NINT,bNINT);
}
RomSwitch(Chipset.Bank_FF); // select HP49G ROM bank and update memory mapping
UpdateDisplayPointers();
UpdateMainDisplay();
UpdateMenuDisplay();
UpdateAnnunciators();
// init speed reference
// 22.11.99 cg, changed, DWORD casting
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
QueryPerformanceCounter(&lDummyInt);
dwSpeedRef = lDummyInt.LowPart;
@ -313,65 +485,9 @@ loop:
PCHANGED;
while (!bInterrupt)
{
LPBYTE I = FASTPTR(Chipset.pc);
if (bDbgEnable) Debugger(); // debugger active
if (bDbgEnable) // debugger active
{
BOOL bStopEmulation;
// 13.11.99 cg, changed, check for step into
bStopEmulation = (nDbgState == DBG_STEPINTO);
// check for step over
bStopEmulation |= (nDbgState == DBG_STEPOVER) && dwDbgRstkp == Chipset.rstkp;
// 13.11.99 cg, new, check for step out, something was popped from hardware stack
if (nDbgState == DBG_STEPOUT && dwDbgRstkp == Chipset.rstkp)
{
_ASSERT(bStopEmulation == FALSE);
if ((bStopEmulation = (Chipset.pc == dwDbgRstk)) == FALSE)
{
// it was C=RSTK, check for next object popped from hardware stack
dwDbgRstkp = (Chipset.rstkp-1)&7;
dwDbgRstk = Chipset.rstk[dwDbgRstkp];
}
}
// 13.11.99 cg, end of step out implementation
// check for breakpoints
bStopEmulation |= CheckBreakpoint(Chipset.pc);
// NOP3, opcode #420 (GOC)
if (bDbgNOP3 && I[0] == 0x4 && I[1] == 0x2 && I[2] == 0x0)
bStopEmulation = TRUE;
if (bStopEmulation) // stop condition
{
StopTimers(); // hold timer values when emulator is stopped
OutputDebugString("Emulator stopped...\n");
NotifyDebugger(); // 10.11.99 cg, changed, update registers
WaitForSingleObject(hEventDebug,INFINITE);
OutputDebugString("Emulator running...\n");
// @todo add timer emulation
StartTimers(); // continue timers
Chipset.Shutdn = FALSE;
Chipset.bShutdnWake = FALSE;
// init slow down part
// 22.11.99 cg, changed, DWORD casting
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
QueryPerformanceCounter(&lDummyInt);
dwSpeedRef = lDummyInt.LowPart;
}
}
EvalOpcode(I);
EvalOpcode(FASTPTR(Chipset.pc)); // execute opcode
CheckDisp(!Chipset.Shutdn); // check for display update
CheckSerial(); // serial support
@ -382,14 +498,16 @@ loop:
// enter SHUTDN handler only in RUN mode
if (Chipset.Shutdn && !(nDbgState == DBG_STEPINTO || nDbgState == DBG_STEPOVER))
{
if (!Chipset.SoftInt) // ignore SHUTDN on interrupt request
WaitForSingleObject(hEventShutdn,INFINITE);
else
Chipset.bShutdnWake = TRUE; // waked by interrupt
if (Chipset.bShutdnWake) // waked up by timer, keyboard or serial
{
Chipset.bShutdnWake = FALSE;
Chipset.Shutdn = FALSE;
// init speed reference
// 22.11.99 cg, changed, DWORD casting
dwOldCyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
QueryPerformanceCounter(&lDummyInt);
dwSpeedRef = lDummyInt.LowPart;
@ -405,12 +523,11 @@ loop:
Chipset.pc = 0xf;
}
}
if (nNextState != 0)
{
}
_ASSERT(nNextState != 0);
StopTimers();
Chipset.cards_status &= (Chipset.type=='S')?0x5:0xA;
}
}
while (nNextState == 3) // go into sleep state
{
nState = 3; // in sleep state

View file

@ -13,7 +13,9 @@
//#F0E4F #706D2 #80850 #80F0F =SFLAG53_56
// memory address for flags -53 to -56
#define SFLAG53_56 ( (cCurrentRomType=='A') \
#define SFLAG53_56 ( (cCurrentRomType=='6') \
? 0xE0E4F \
: ( (cCurrentRomType=='A') \
? 0xF0E4F \
: ( (cCurrentRomType!='X') \
? ( (cCurrentRomType=='S') \
@ -22,6 +24,7 @@
) \
: 0x80F0F \
) \
) \
)
static __inline VOID Return(CHIPSET* w)

View file

@ -8,7 +8,9 @@
*/
#include "pch.h"
#include "Emu48.h"
#include "io.h" // I/O register definitions
#include "kml.h"
#include "i28f160.h" // flash support
char szEmu48Directory[260];
char szCurrentDirectory[260];
@ -24,6 +26,7 @@ static HANDLE hRomFile = NULL;
static HANDLE hRomMap = NULL;
DWORD dwRomSize = 0;
char cCurrentRomType = 0;
BOOL bRomWriteable = FALSE; // flag if ROM writeable
static HANDLE hPort2File = NULL;
static HANDLE hPort2Map = NULL;
@ -33,7 +36,7 @@ BOOL bPort2IsShared = FALSE;
DWORD dwPort2Size = 0; // size of mapped port2
DWORD dwPort2Mask = 0;
// 01.12.99 cg, new, HP38G signature
// document signatures
static BYTE pbySignatureA[16] = "Emu38 Document\xFE";
static BYTE pbySignatureE[16] = "Emu48 Document\xFE";
static BYTE pbySignatureW[16] = "Win48 Document\xFE";
@ -96,227 +99,13 @@ WORD WriteStack(LPBYTE lpBuf,DWORD dwSize) // separated from LoadObject()
//################
//#
//# ROM
//#
//################
static WORD CrcRom(VOID) // 19.11.99 cg, new, calculate fingerprint of ROM
{
DWORD dwCount;
DWORD dwFileSize;
DWORD dwCrc = 0;
dwFileSize = GetFileSize(hRomFile, &dwCount); // get real filesize
_ASSERT(dwCount == 0); // isn't created by MapRom()
_ASSERT(pbyRom); // view on ROM
// use checksum, because it's faster
for (dwCount = 0;dwCount < dwFileSize; dwCount+=sizeof(dwCrc))
dwCrc += *((DWORD *) &pbyRom[dwCount]);
return (WORD) dwCrc;
}
BOOL MapRom(LPCSTR szFilename)
{
DWORD dwFileSizeHigh;
if (pbyRom != NULL)
{
return FALSE;
}
SetCurrentDirectory(szEmu48Directory);
hRomFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
SetCurrentDirectory(szCurrentDirectory);
if (hRomFile == INVALID_HANDLE_VALUE)
{
hRomFile = NULL;
return FALSE;
}
dwRomSize = GetFileSize(hRomFile, &dwFileSizeHigh);
if (dwFileSizeHigh != 0)
{ // file is too large.
CloseHandle(hRomFile);
hRomFile = NULL;
dwRomSize = 0;
return FALSE;
}
hRomMap = CreateFileMapping(hRomFile, NULL, PAGE_WRITECOPY, 0, dwRomSize, NULL);
if (hRomMap == NULL)
{
CloseHandle(hRomFile);
hRomFile = NULL;
dwRomSize = 0;
return FALSE;
}
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
AbortMessage("Sharing file mapping handle.");
}
pbyRom = MapViewOfFile(hRomMap, FILE_MAP_COPY, 0, 0, dwRomSize);
if (pbyRom == NULL)
{
CloseHandle(hRomMap);
CloseHandle(hRomFile);
hRomMap = NULL;
hRomFile = NULL;
dwRomSize = 0;
return FALSE;
}
return TRUE;
}
VOID UnmapRom(VOID)
{
if (pbyRom==NULL) return;
UnmapViewOfFile(pbyRom);
CloseHandle(hRomMap);
CloseHandle(hRomFile);
pbyRom = NULL;
hRomMap = NULL;
hRomFile = NULL;
dwRomSize = 0;
return;
}
//################
//#
//# Port2
//#
//################
static WORD CrcPort2(VOID) // calculate fingerprint of port2
{
DWORD dwCount;
DWORD dwFileSize;
WORD wCrc = 0;
// port2 CRC isn't available
if (cCurrentRomType=='X' || pbyPort2==NULL) return wCrc;
dwFileSize = GetFileSize(hPort2File, &dwCount); // get real filesize
_ASSERT(dwCount == 0); // isn't created by MapPort2()
for (dwCount = 0;dwCount < dwFileSize; ++dwCount)
wCrc = (wCrc >> 4) ^ (((wCrc ^ ((WORD) pbyPort2[dwCount])) & 0xf) * 0x1081);
return wCrc;
}
BOOL MapPort2(LPCSTR szFilename)
{
DWORD dwFileSizeLo;
DWORD dwFileSizeHi;
if (pbyPort2 != NULL) return FALSE;
bPort2Writeable = TRUE;
dwPort2Size = 0; // reset size of port2
SetCurrentDirectory(szEmu48Directory);
if (bPort2IsShared)
{
hPort2File = CreateFile(szFilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
SetCurrentDirectory(szCurrentDirectory);
if (hPort2File == INVALID_HANDLE_VALUE)
{
bPort2Writeable = FALSE;
SetCurrentDirectory(szEmu48Directory);
hPort2File = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
SetCurrentDirectory(szCurrentDirectory);
if (hPort2File == INVALID_HANDLE_VALUE)
{
hPort2File = NULL;
return FALSE;
}
}
}
else
{
hPort2File = CreateFile(szFilename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
SetCurrentDirectory(szCurrentDirectory);
if (hPort2File == INVALID_HANDLE_VALUE)
{
hPort2File = NULL;
return FALSE;
}
}
dwFileSizeLo = GetFileSize(hPort2File, &dwFileSizeHi);
if (dwFileSizeHi != 0)
{ // file is too large.
CloseHandle(hPort2File);
hPort2File = NULL;
dwPort2Mask = 0;
bPort2Writeable = FALSE;
return FALSE;
}
if (dwFileSizeLo & 0x3FFFF)
{ // file size is wrong
CloseHandle(hPort2File);
hPort2File = NULL;
dwPort2Mask = 0;
bPort2Writeable = FALSE;
return FALSE;
}
dwPort2Mask = (dwFileSizeLo >> 18) - 1; // mask for valid address lines of the BS-FF
if (bPort2Writeable)
hPort2Map = CreateFileMapping(hPort2File, NULL, PAGE_READWRITE, 0, dwFileSizeLo, NULL);
else
hPort2Map = CreateFileMapping(hPort2File, NULL, PAGE_READONLY, 0, dwFileSizeLo, NULL);
if (hPort2Map == NULL)
{
CloseHandle(hPort2File);
hPort2File = NULL;
dwPort2Mask = 0;
bPort2Writeable = FALSE;
return FALSE;
}
if (bPort2Writeable)
pbyPort2 = MapViewOfFile(hPort2Map, FILE_MAP_WRITE, 0, 0, dwFileSizeLo);
else
pbyPort2 = MapViewOfFile(hPort2Map, FILE_MAP_READ, 0, 0, dwFileSizeLo);
if (pbyPort2 == NULL)
{
CloseHandle(hPort2Map);
CloseHandle(hPort2File);
hPort2Map = NULL;
hPort2File = NULL;
dwPort2Mask = 0;
bPort2Writeable = FALSE;
return FALSE;
}
dwPort2Size = dwFileSizeLo / 2048; // mapping size of port2
if (dwPort2Size > 128) dwPort2Size = 128;
return TRUE;
}
VOID UnmapPort2(VOID)
{
if (pbyPort2==NULL) return;
UnmapViewOfFile(pbyPort2);
CloseHandle(hPort2Map);
CloseHandle(hPort2File);
pbyPort2 = NULL;
hPort2Map = NULL;
hPort2File = NULL;
dwPort2Size = 0; // reset size of port2
dwPort2Mask = 0;
bPort2Writeable = FALSE;
return;
}
//################
//#
//# Patch
//#
//################
static BYTE Asc2Nib(char c)
static __inline BYTE Asc2Nib(char c)
{
if (c<'0') return 0;
if (c<='9') return c-'0';
@ -327,6 +116,76 @@ static BYTE Asc2Nib(char c)
return 0;
}
// functions to restore ROM patches
typedef struct tnode
{
DWORD dwAddress; // patch address
BYTE byROM; // original ROM value
BYTE byPatch; // patched ROM value
struct tnode *next; // next node
} TREENODE;
static TREENODE *nodePatch = NULL;
static BOOL PatchNibble(DWORD dwAddress, BYTE byPatch)
{
TREENODE *p;
_ASSERT(pbyRom); // ROM defined
if((p = (TREENODE *) LocalAlloc(LMEM_FIXED,sizeof(TREENODE))) == NULL)
return TRUE;
p->dwAddress = dwAddress; // save current values
p->byROM = pbyRom[dwAddress];
p->byPatch = byPatch;
p->next = nodePatch; // save node
nodePatch = p;
pbyRom[dwAddress] = byPatch; // patch ROM
return FALSE;
}
static VOID RestorePatches(VOID)
{
TREENODE *p;
_ASSERT(pbyRom); // ROM defined
while (nodePatch != NULL)
{
// restore original data
pbyRom[nodePatch->dwAddress] = nodePatch->byROM;
p = nodePatch->next; // save pointer to next node
LocalFree(nodePatch); // free node
nodePatch = p; // new node
}
return;
}
VOID UpdatePatches(BOOL bPatch)
{
TREENODE *p = nodePatch;
_ASSERT(pbyRom); // ROM defined
while (p != NULL)
{
if (bPatch)
{
// save original data and patch address
p->byROM = pbyRom[p->dwAddress];
pbyRom[p->dwAddress] = p->byPatch;
}
else
{
// restore original data
pbyRom[p->dwAddress] = p->byROM;
}
p = p->next; // next node
}
return;
}
BOOL PatchRom(LPCSTR szFilename)
{
HANDLE hFile = NULL;
@ -393,7 +252,8 @@ BOOL PatchRom(LPCSTR szFilename)
while (lpBuf[nPos])
{
if (isxdigit(lpBuf[nPos]) == FALSE) break;
pbyRom[dwAddress] = Asc2Nib(lpBuf[nPos]);
// patch ROM and save original nibble
PatchNibble(dwAddress, Asc2Nib(lpBuf[nPos]));
dwAddress = (dwAddress+1)&(dwRomSize-1);
nPos++;
}
@ -404,6 +264,266 @@ BOOL PatchRom(LPCSTR szFilename)
//################
//#
//# ROM
//#
//################
static WORD CrcRom(VOID) // calculate fingerprint of ROM
{
DWORD dwCount;
DWORD dwFileSize;
DWORD dwCrc = 0;
dwFileSize = GetFileSize(hRomFile, &dwCount); // get real filesize
_ASSERT(dwCount == 0); // isn't created by MapRom()
_ASSERT(pbyRom); // view on ROM
// use checksum, because it's faster
for (dwCount = 0;dwCount < dwFileSize; dwCount+=sizeof(dwCrc))
dwCrc += *((DWORD *) &pbyRom[dwCount]);
return (WORD) dwCrc;
}
BOOL MapRom(LPCSTR szFilename)
{
DWORD dwFileSizeHigh;
// open ROM for writing
BOOL bWrite = (cCurrentRomType == 'X') ? bRomWriteable : FALSE;
if (pbyRom != NULL)
{
return FALSE;
}
SetCurrentDirectory(szEmu48Directory);
if (bWrite) // ROM writeable
{
hRomFile = CreateFile(szFilename,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hRomFile == INVALID_HANDLE_VALUE)
{
bWrite = FALSE; // ROM not writeable
hRomFile = CreateFile(szFilename,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
}
}
else // writing ROM disabled
{
hRomFile = CreateFile(szFilename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
}
SetCurrentDirectory(szCurrentDirectory);
if (hRomFile == INVALID_HANDLE_VALUE)
{
hRomFile = NULL;
return FALSE;
}
dwRomSize = GetFileSize(hRomFile, &dwFileSizeHigh);
if (dwFileSizeHigh != 0)
{ // file is too large.
CloseHandle(hRomFile);
hRomFile = NULL;
dwRomSize = 0;
return FALSE;
}
hRomMap = CreateFileMapping(hRomFile, NULL, bWrite ? PAGE_READWRITE : PAGE_WRITECOPY, 0, dwRomSize, NULL);
if (hRomMap == NULL)
{
CloseHandle(hRomFile);
hRomFile = NULL;
dwRomSize = 0;
return FALSE;
}
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
AbortMessage("Sharing file mapping handle.");
}
pbyRom = MapViewOfFile(hRomMap, bWrite ? FILE_MAP_WRITE : FILE_MAP_COPY, 0, 0, dwRomSize);
if (pbyRom == NULL)
{
CloseHandle(hRomMap);
CloseHandle(hRomFile);
hRomMap = NULL;
hRomFile = NULL;
dwRomSize = 0;
return FALSE;
}
return TRUE;
}
VOID UnmapRom(VOID)
{
if (pbyRom==NULL) return;
RestorePatches(); // restore ROM Patches
UnmapViewOfFile(pbyRom);
CloseHandle(hRomMap);
CloseHandle(hRomFile);
pbyRom = NULL;
hRomMap = NULL;
hRomFile = NULL;
dwRomSize = 0;
return;
}
//################
//#
//# Port2
//#
//################
static WORD CrcPort2(VOID) // calculate fingerprint of port2
{
DWORD dwCount;
DWORD dwFileSize;
WORD wCrc = 0;
// port2 CRC isn't available
if (cCurrentRomType=='X' || pbyPort2==NULL) return wCrc;
dwFileSize = GetFileSize(hPort2File, &dwCount); // get real filesize
_ASSERT(dwCount == 0); // isn't created by MapPort2()
for (dwCount = 0;dwCount < dwFileSize; ++dwCount)
wCrc = (wCrc >> 4) ^ (((wCrc ^ ((WORD) pbyPort2[dwCount])) & 0xf) * 0x1081);
return wCrc;
}
BOOL MapPort2(LPCSTR szFilename)
{
DWORD dwFileSizeLo;
DWORD dwFileSizeHi;
if (pbyPort2 != NULL) return FALSE;
bPort2Writeable = TRUE;
dwPort2Size = 0; // reset size of port2
SetCurrentDirectory(szEmu48Directory);
if (bPort2IsShared)
{
hPort2File = CreateFile(szFilename,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
SetCurrentDirectory(szCurrentDirectory);
if (hPort2File == INVALID_HANDLE_VALUE)
{
bPort2Writeable = FALSE;
SetCurrentDirectory(szEmu48Directory);
hPort2File = CreateFile(szFilename,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
SetCurrentDirectory(szCurrentDirectory);
if (hPort2File == INVALID_HANDLE_VALUE)
{
hPort2File = NULL;
return FALSE;
}
}
}
else
{
hPort2File = CreateFile(szFilename,
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
SetCurrentDirectory(szCurrentDirectory);
if (hPort2File == INVALID_HANDLE_VALUE)
{
hPort2File = NULL;
return FALSE;
}
}
dwFileSizeLo = GetFileSize(hPort2File, &dwFileSizeHi);
if (dwFileSizeHi != 0)
{ // file is too large.
CloseHandle(hPort2File);
hPort2File = NULL;
dwPort2Mask = 0;
bPort2Writeable = FALSE;
return FALSE;
}
if (dwFileSizeLo & 0x3FFFF)
{ // file size is wrong
CloseHandle(hPort2File);
hPort2File = NULL;
dwPort2Mask = 0;
bPort2Writeable = FALSE;
return FALSE;
}
dwPort2Mask = (dwFileSizeLo >> 18) - 1; // mask for valid address lines of the BS-FF
hPort2Map = CreateFileMapping(hPort2File, NULL, bPort2Writeable ? PAGE_READWRITE : PAGE_READONLY,
0, dwFileSizeLo, NULL);
if (hPort2Map == NULL)
{
CloseHandle(hPort2File);
hPort2File = NULL;
dwPort2Mask = 0;
bPort2Writeable = FALSE;
return FALSE;
}
pbyPort2 = MapViewOfFile(hPort2Map, bPort2Writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, 0, dwFileSizeLo);
if (pbyPort2 == NULL)
{
CloseHandle(hPort2Map);
CloseHandle(hPort2File);
hPort2Map = NULL;
hPort2File = NULL;
dwPort2Mask = 0;
bPort2Writeable = FALSE;
return FALSE;
}
dwPort2Size = dwFileSizeLo / 2048; // mapping size of port2
if (dwPort2Size > 128) dwPort2Size = 128;
return TRUE;
}
VOID UnmapPort2(VOID)
{
if (pbyPort2==NULL) return;
UnmapViewOfFile(pbyPort2);
CloseHandle(hPort2Map);
CloseHandle(hPort2File);
pbyPort2 = NULL;
hPort2Map = NULL;
hPort2File = NULL;
dwPort2Size = 0; // reset size of port2
dwPort2Mask = 0;
bPort2Writeable = FALSE;
return;
}
//################
//#
//# Documents
@ -446,9 +566,9 @@ BOOL NewDocument(VOID)
if (!InitKML(szCurrentKml,FALSE)) goto restore;
Chipset.type = cCurrentRomType;
if (Chipset.type == 'A') // 01.12.99 cg, new, HP38G
if (Chipset.type == '6' || Chipset.type == 'A') // HP38G
{
Chipset.Port0Size = 32;
Chipset.Port0Size = (Chipset.type == 'A') ? 32 : 64;
Chipset.Port1Size = 0;
Chipset.Port2Size = 0;
Chipset.Port0 = (LPBYTE)LocalAlloc(0,Chipset.Port0Size*2048);
@ -471,7 +591,6 @@ BOOL NewDocument(VOID)
Chipset.cards_status = 0x5;
// use 2nd command line argument if defined
// 08.11.99 cg, changed, replaced __argc and __argv variable
MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]);
}
if (Chipset.type == 'G') // HP48GX
@ -487,7 +606,6 @@ BOOL NewDocument(VOID)
Chipset.cards_status = 0xA;
// use 2nd command line argument if defined
// 08.11.99 cg, changed, replaced __argc and __argv variable
MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]);
}
if (Chipset.type == 'X') // HP49G
@ -507,6 +625,8 @@ BOOL NewDocument(VOID)
bPort2Writeable = TRUE;
Chipset.cards_status = 0xF;
FlashInit(); // init flash structure
}
RomSwitch(0); // boot ROM view of HP49G and map memory
SaveBackup();
@ -515,16 +635,14 @@ restore:
RestoreBackup();
ResetBackup();
// 01.12.99 cg, changed, added HP38G
if(Chipset.type != 'A' && Chipset.type != 'X')
// HP48SX/GX
if(Chipset.type != '6' && Chipset.type != 'A' && Chipset.type != 'X')
{
// use 2nd command line argument if defined
// 08.11.99 cg, changed, replaced __argc and __argv variable
MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]);
}
if (pbyRom)
{
// 09.12.99 cg, changed, removed typecast of the position data
SetWindowPos(hWnd,NULL,Chipset.nPosX,Chipset.nPosY,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
Map(0x00,0xFF);
}
@ -562,7 +680,6 @@ BOOL OpenDocument(LPCSTR szFilename)
switch (pbyFileSignature[0])
{
case 'E':
// 01.12.99 cg, changed, added HP38 signature
pbySig = (pbyFileSignature[3] == '3')
? pbySignatureA
: ((pbyFileSignature[4] == '8') ? pbySignatureE : pbySignatureV);
@ -620,7 +737,6 @@ BOOL OpenDocument(LPCSTR szFilename)
Chipset.Port1 = NULL;
Chipset.Port2 = NULL;
// 09.12.99 cg, changed, removed typecast of the position data
SetWindowPos(hWnd,NULL,Chipset.nPosX,Chipset.nPosY,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
if (szCurrentKml == NULL)
@ -634,6 +750,8 @@ BOOL OpenDocument(LPCSTR szFilename)
goto restore;
}
FlashInit(); // init flash structure
if (Chipset.Port0Size)
{
Chipset.Port0 = (LPBYTE)LocalAlloc(0,Chipset.Port0Size*2048);
@ -662,13 +780,17 @@ BOOL OpenDocument(LPCSTR szFilename)
if (cCurrentRomType!='X') // HP38G, HP48SX/GX
{
if(cCurrentRomType!='A') // 01.12.99 cg, new, HP48SX/GX
// HP48SX/GX
if(cCurrentRomType!='6' && cCurrentRomType!='A')
{
// 08.11.99 cg, changed, replaced __argc and __argv variable
MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]);
if (Chipset.wPort2Crc != CrcPort2())// port2 changed
// port2 changed and card detection enabled
if ( Chipset.wPort2Crc != CrcPort2()
&& (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0
)
{
Chipset.HST |= 8; // set Module Pulled
Chipset.HST |= MP; // set Module Pulled
IOBit(SRQ2,NINT,FALSE); // set NINT to low
Chipset.SoftInt = TRUE; // set interrupt
bInterrupt = TRUE;
}
@ -695,10 +817,8 @@ BOOL OpenDocument(LPCSTR szFilename)
RomSwitch(Chipset.Bank_FF); // reload ROM view of HP49G and map memory
// 20.11.99 cg, new, check fingerprint of ROM
if (Chipset.wRomCrc != CrcRom()) // ROM changed
CpuReset();
// 20.11.99 cg, end of fingerprint check
lstrcpy(szCurrentFilename, szFilename);
_ASSERT(hCurrentFile == NULL);
@ -715,11 +835,10 @@ restore:
RestoreBackup();
ResetBackup();
// 01.12.99 cg, bugfix, add port2 only on HP48 calculators
if(cCurrentRomType!='A' && cCurrentRomType!='X')
// HP48SX/GX
if(cCurrentRomType!='6' && cCurrentRomType!='A' && cCurrentRomType!='X')
{
// use 2nd command line argument if defined
// 08.11.99 cg, changed, replaced __argc and __argv variable
MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]);
}
return FALSE;
@ -741,8 +860,9 @@ BOOL SaveDocument(VOID)
SetFilePointer(hCurrentFile,0,0,FILE_BEGIN);
// 01.12.99 cg, changed, added HP38G signature
pbySig = (Chipset.type=='A') ? pbySignatureA : ((Chipset.type!='X') ? pbySignatureE : pbySignatureV);
// get document signature
pbySig = (Chipset.type=='6' || Chipset.type=='A')
? pbySignatureA : ((Chipset.type!='X') ? pbySignatureE : pbySignatureV);
if (!WriteFile(hCurrentFile, pbySig, 16, &lBytesWritten, NULL))
{
@ -750,7 +870,7 @@ BOOL SaveDocument(VOID)
return FALSE;
}
Chipset.wRomCrc = CrcRom(); // 20.11.99 cg, new, save fingerprint of ROM
Chipset.wRomCrc = CrcRom(); // save fingerprint of ROM
Chipset.wPort2Crc = CrcPort2(); // save fingerprint of port2
nLength = strlen(szCurrentKml);
@ -801,11 +921,10 @@ BOOL SaveBackup(VOID)
if (pbyRom == NULL) return FALSE;
// 09.12.99 cg, changed, save window position
// save window position
GetWindowRect(hWnd, &Rect); // update saved window position
Chipset.nPosX = (SWORD)Rect.left;
Chipset.nPosY = (SWORD)Rect.top;
// 09.12.99 cg, end of part
lstrcpy(szBackupFilename, szCurrentFilename);
lstrcpy(szBackupKml, szCurrentKml);
@ -859,17 +978,15 @@ BOOL RestoreBackup(VOID)
Chipset.Port2 = (LPBYTE)LocalAlloc(0,Chipset.Port2Size*2048);
CopyMemory(Chipset.Port2, BackupChipset.Port2, Chipset.Port2Size*2048);
}
// 09.12.99 cg, bugfix, map port2
// map port2
else
{
if(cCurrentRomType!='A') // HP48SX/GX
if(cCurrentRomType!='6' && cCurrentRomType!='A') // HP48SX/GX
{
// use 2nd command line argument if defined
MapPort2((nArgc < 3) ? szPort2Filename : ppArgv[2]);
}
}
// 09.12.99 cg, end of bugfix
// 09.12.99 cg, changed, removed typecast of the position data
SetWindowPos(hWnd,NULL,Chipset.nPosX,Chipset.nPosY,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
UpdateWindowStatus();
Map(0x00,0xFF);
@ -920,14 +1037,12 @@ BOOL GetOpenFilename(VOID)
"\0\0";
if (cCurrentRomType!='X') // HP38G / HP48SX/GX
{
// 01.12.99 cg, new, HP38G support
if (cCurrentRomType=='A') // HP38G
if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G
{
ofn.lpstrDefExt = "E38";
ofn.nFilterIndex = 1;
}
else
// 01.12.99 cg, end
{
ofn.lpstrDefExt = "E48";
ofn.nFilterIndex = 2;
@ -965,14 +1080,12 @@ BOOL GetSaveAsFilename(VOID)
"\0\0";
if (cCurrentRomType!='X') // HP38G / HP48SX/GX
{
// 01.12.99 cg, new, HP38G support
if (cCurrentRomType=='A') // HP38G
if (cCurrentRomType=='6' || cCurrentRomType=='A') // HP38G
{
ofn.lpstrDefExt = "E38";
ofn.nFilterIndex = 1;
}
else
// 01.12.99 cg, end
{
ofn.lpstrDefExt = "E48";
ofn.nFilterIndex = 2;
@ -1128,25 +1241,12 @@ BOOL SaveObject(LPCSTR szFilename) // separated stack reading part
//#
//################
static UINT DibNumColors (LPBITMAPINFOHEADER lpbi)
static __inline UINT DibNumColors (LPBITMAPINFOHEADER lpbi)
{
UINT bits;
if (lpbi->biClrUsed != 0) return (UINT)lpbi->biClrUsed;
bits = lpbi->biBitCount;
switch (bits)
{
case 1:
return 2;
case 4:
return 16;
case 8:
return 256;
default:
/* A 24 bitcount DIB has no color table */
return 0;
}
/* a 24 bitcount DIB has no color table */
return (lpbi->biBitCount <= 8) ? (1 << lpbi->biBitCount) : 0;
}
static HPALETTE CreateBIPalette(LPBITMAPINFOHEADER lpbi)
@ -1292,6 +1392,7 @@ HBITMAP LoadBitmapFile(LPCSTR szFilename)
pbyFile+pBmfh->bfOffBits,
pBmi, DIB_RGB_COLORS);
}
_ASSERT(hBitmap != NULL);
quit:
UnmapViewOfFile(pbyFile);

696
sources/Emu48/I28F160.C Normal file
View file

@ -0,0 +1,696 @@
/*
* i28f160.c
*
* This file is part of Emu48
*
* Copyright (C) 2000 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
#include "i28f160.h"
#define _64KB (64*1024) // define 64KB
#define ARRAYSIZEOF(a) (sizeof(a) / sizeof(a[0]))
// Flash Command Set
#define READ_ARRAY 0xFF
#define READ_ID_CODES 0x90
#define READ_QUERY 0x98
#define READ_STATUS_REG 0x70
#define CLEAR_STATUS_REG 0x50
#define WRITE_BUFFER 0xE8
#define WORD_BYTE_PROG1 0x40
#define WORD_BYTE_PROG2 0x10
#define BLOCK_ERASE 0x20
#define BLOCK_ERASE_SUSPEND 0xB0
#define BLOCK_ERASE_RESUME 0xD0
#define STS_CONFIG 0xB8
#define SET_CLR_BLOCK_LOCK 0x60
#define FULL_CHIP_ERASE 0x30
#define CONFIRM 0xD0
// Status Register Definition
#define WSMS 0x80 // WRITE STATE MACHINE STATUS
#define ESS 0x40 // ERASE SUSPEND STATUS
#define ECLBS 0x20 // ERASE AND CLEAR LOCK-BIT STATUS
#define BWSLBS 0x10 // PROGRAM AND SET LOCK-BIT STATUS
#define VPPS 0x08 // Vpp STATUS
#define BWSS 0x04 // PROGRAM SUSPEND STATUS
#define DPS 0x02 // DEVICE PROTECT STATUS
// Extended Status Register Definition
#define WBS 0x80 // WRITE BUFFER STATUS
// write state defines
#define WRS_DATA 0 // idle state
#define WRS_WR_BUFFER_N 1 // write buffer no. of data
#define WRS_WR_BUFFER_D 2 // write buffer data
#define WRS_WR_BUFFER_C 3 // write buffer confirm
#define WRS_WR_BYTE 4 // write byte/word
#define WRS_BLOCK_ERASE 5 // block erase
#define WRS_CHIP_ERASE 6 // full chip erase
#define WRS_STS_PIN_CONFIG 7 // STS pin Configuration
#define WRS_LOCK_BITS 8 // Set/Clear Block Lock-Bits
// read state defines
#define RDS_DATA 0
#define RDS_ID 1
#define RDS_QUERY 2
#define RDS_SR 3
#define RDS_XSR 4
// global data
WSMSET WSMset;
BOOL bWP = FALSE; // WP# = low, locked blocks cannot be erased
// function prototypes
// write function WSM state
static VOID WrStateIdle(BYTE a, DWORD d);
static VOID WrStateE8(DWORD d);
static VOID WrStateE8N(BYTE a, DWORD d);
static VOID WrStateE8D(BYTE a, DWORD d);
static VOID WrStateE8C(BYTE a, DWORD d);
static VOID WrState40(DWORD d);
static VOID WrState40D(BYTE a, DWORD d);
static VOID WrState20(DWORD d);
static VOID WrState20C(BYTE a, DWORD d);
static VOID WrState30(DWORD d);
static VOID WrState30C(BYTE a, DWORD d);
static VOID WrStateB8(DWORD d);
static VOID WrStateB8D(BYTE a, DWORD d);
static VOID WrState60(DWORD d);
static VOID WrState60D(BYTE a, DWORD d);
static CONST VOID (*CONST fnWrState[])(BYTE a, DWORD d) =
{
WrStateIdle,
WrStateE8N, WrStateE8D, WrStateE8C,
WrState40D,
WrState20C,
WrState30C,
WrStateB8D,
WrState60D
};
// read function WSM state
static BYTE RdStateData(DWORD d);
static BYTE RdStateId(DWORD d);
static BYTE RdStateQuery(DWORD d);
static BYTE RdStateSR(DWORD d);
static BYTE RdStateXSR(DWORD d);
static CONST BYTE (*CONST fnRdState[])(DWORD d) =
{
RdStateData, RdStateId, RdStateQuery, RdStateSR, RdStateXSR
};
// read query table
// device address A16-A1, A0 unused
static CONST BYTE byQueryTab[] =
{
// access with "Read Identifier Codes" command
// Identifier codes
0xB0, // 00, Manufacturer Code
0xD0, // 01, Device Code (16 Mbit)
0x00, // 02, Block Lock Configuration
0x00, // 03, Reserved for vendor-specific information
0x00, // 04, "
0x00, // 05, "
0x00, // 06, "
0x00, // 07, "
0x00, // 08, "
0x00, // 09, "
0x00, // 0A, "
0x00, // 0B, "
0x00, // 0C, "
0x00, // 0D, "
0x00, // 0E, "
0x00, // 0F, "
// access with "Read Query" command
// CFI query identification string
0x51, // 10, Query-Unique ASCII string "Q"
0x52, // 11, Query-Unique ASCII string "R"
0x59, // 12, Query-Unique ASCII string "Y"
0x01, // 13, Primary Vendor Command Set and Control Interface ID CODE
0x00, // 14, "
0x31, // 15, Address for Primary Algorithm Extended Query Table
0x00, // 16, "
0x00, // 17, Alternate Vendor Command Set and Control Interface ID Code
0x00, // 18, "
0x00, // 19, Address for Secondary Algorithm Extended Query Table
0x00, // 1A, "
// System interface information
0x27, // 1B, Vcc Logic Supply Minimum Program/Erase Voltage
0x55, // 1C, Vcc Logic Supply Maximum Program/Erase Voltage
0x27, // 1D, Vpp [Programming] Supply Minimum Program/Erase Voltage
0x55, // 1E, Vpp [Programming] Supply Maximum Program/Erase Voltage
0x03, // 1F, Typical Time-Out per Single Byte/Word Program
0x06, // 20, Typical Time-Out for Max. Buffer Write
0x0A, // 21, Typical Time-Out per Individual Block Erase
0x0F, // 22, Typical Time-Out for Full Chip Erase
0x04, // 23, Maximum Time-Out for Byte/Word Program
0x04, // 24, Maximum Time-Out for Buffer Write
0x04, // 25, Maximum Time-Out per Individual Block Erase
0x04, // 26, Maximum Time-Out for Full Chip Erase
0x15, // 27, Device Size
0x02, // 28, Flash Device Interface Description
0x00, // 29, "
0x05, // 2A, Maximum Number of Bytes in Write Buffer
0x00, // 2B, "
0x01, // 2C, Number of Erase Block Regions within Device
0x1F, // 2D, Erase Block Region Information
0x00, // 2E, "
0x00, // 2F, "
0x01, // 30, "
// Intel-specific extended query table
0x50, // 31, Primary Extended Query Table, Unique ASCII string "P"
0x52, // 32, Primary Extended Query Table, Unique ASCII string "R"
0x49, // 33, Primary Extended Query Table, Unique ASCII string "I"
0x31, // 34, Major Version Number, ASCII
0x30, // 35, Minor Version Number, ASCII
0x0F, // 36, Optional Feature & Command Support
0x00, // 37, "
0x00, // 38, "
0x00, // 39, "
0x01, // 3A, Supported Functions after Suspend
0x03, // 3B, Block Status Register Mask
0x00, // 3C, "
0x50, // 3D, Vcc Logic Supply Optimum Program/Erase voltage
0x50 // 3E, Vpp [Programming] Supply Optimum Program/Erase voltage
};
//
// write state functions
//
static VOID WrStateIdle(BYTE a, DWORD d)
{
WSMset.bRomArray = FALSE; // register access
switch(a)
{
case READ_ARRAY: // read array mode, normal operation
WSMset.bRomArray = TRUE; // data array access
WSMset.uWrState = WRS_DATA;
WSMset.uRdState = RDS_DATA;
break;
case READ_ID_CODES: // read identifier codes register
WSMset.uRdState = RDS_ID;
break;
case READ_QUERY: // read query register
WSMset.uRdState = RDS_QUERY;
break;
case READ_STATUS_REG: // read status register
WSMset.uRdState = RDS_SR;
break;
case CLEAR_STATUS_REG: // clear status register
WSMset.byStatusReg = 0;
break;
case WRITE_BUFFER: // write to buffer
WrStateE8(d);
break;
case WORD_BYTE_PROG1:
case WORD_BYTE_PROG2: // byte/word program
WrState40(d);
break;
case BLOCK_ERASE: // block erase
WrState20(d);
break;
case BLOCK_ERASE_SUSPEND: // block erase, word/byte program suspend
WSMset.byStatusReg |= WSMS; // operation suspended
WSMset.byStatusReg &= ~ESS; // block erase completed (because no timing emulation)
WSMset.byStatusReg &= ~BWSS; // program completed (because no timing emulation)
WSMset.uRdState = RDS_SR;
break;
case BLOCK_ERASE_RESUME: // block erase, word/byte program resume
WSMset.byStatusReg &= ~WSMS; // operation in progress
WSMset.byStatusReg &= ~ESS; // block erase in progress
WSMset.byStatusReg &= ~BWSS; // program in progress
WSMset.byStatusReg |= WSMS; // operation completed (because no timing emulation)
WSMset.uRdState = RDS_SR;
break;
case STS_CONFIG:
WSMset.bRomArray = bFlashRomArray; // old access mode
WrStateB8(d);
break;
case SET_CLR_BLOCK_LOCK: // set/clear block lock-bits
WrState60(d);
break;
case FULL_CHIP_ERASE: // full chip erase
WrState30(d);
break;
default: // wrong command
WSMset.bRomArray = bFlashRomArray; // old access mode
break;
}
if(bFlashRomArray != WSMset.bRomArray) // new access mode
{
bFlashRomArray = WSMset.bRomArray; // change register access
Map(0x00,0xFF); // update memory mapping
UpdatePatches(bFlashRomArray); // patch/unpatch ROM again
}
return;
}
// write to buffer initial command
static VOID WrStateE8(DWORD d)
{
// @todo add 2nd write buffer implementation
// @todo add program timing implementation
WSMset.byExStatusReg = 0; // no write buffer
if (WSMset.byWrite1No == 0) // buffer1 available
{
WSMset.byWrite1No = 1; // buffer1 in use
WSMset.dwWrite1Addr = d; // byte block address of buffer1
WSMset.byExStatusReg = WBS; // write buffer available
// fill write buffer
FillMemory(WSMset.pbyWrite1,ARRAYSIZEOF(WSMset.pbyWrite1),0xFF);
WSMset.uWrState = WRS_WR_BUFFER_N; // set state machine
WSMset.uRdState = RDS_XSR;
}
return;
}
// write to buffer number of byte
static VOID WrStateE8N(BYTE a, DWORD d)
{
_ASSERT(a <= 0x1F); // check buffer size
a &= 0x1F; // maximum write buffer size
WSMset.byWrite1No += a; // save no. of byte to program
WSMset.byWrite1Size = a; // save size to check write buffer boundaries
WSMset.dwWrite1Addr = d; // byte block address of buffer1
WSMset.byStatusReg &= ~WSMS; // state machine busy
WSMset.uWrState = WRS_WR_BUFFER_D;
WSMset.uRdState = RDS_SR;
return;
}
// write to buffer data
static VOID WrStateE8D(BYTE a, DWORD d)
{
// first data byte
if (WSMset.byWrite1No == WSMset.byWrite1Size + 1)
{
// same block
if ((WSMset.dwWrite1Addr & ~(_64KB-1)) == (d & ~(_64KB-1)))
{
WSMset.dwWrite1Addr = d; // byte block address of buffer1
WSMset.pbyWrite1[0] = a; // save byte
}
else
{
WSMset.byWrite1No = 0; // free write buffer
// improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
WSMset.byStatusReg |= WSMS; // data written
WSMset.uWrState = WRS_DATA;
return;
}
}
else
{
// write address within buffer
if (d >= WSMset.dwWrite1Addr && d <= WSMset.dwWrite1Addr + WSMset.byWrite1Size)
{
// save byte in buffer
WSMset.pbyWrite1[d-WSMset.dwWrite1Addr] = a;
}
else
{
WSMset.byWrite1No = 0; // free write buffer
// improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
WSMset.byStatusReg |= WSMS; // data written
WSMset.uWrState = WRS_DATA;
return;
}
}
if (--WSMset.byWrite1No == 0) // last byte written
WSMset.uWrState = WRS_WR_BUFFER_C; // goto confirm state
return;
}
// write to buffer confirm
static VOID WrStateE8C(BYTE a, DWORD d)
{
if (CONFIRM == a) // write buffer confirm?
{
BYTE byPos;
d = WSMset.dwWrite1Addr << 1; // nibble start address
for (byPos = 0; byPos <= WSMset.byWrite1Size; ++byPos)
{
a = WSMset.pbyWrite1[byPos]; // get char from buffer
_ASSERT(d+1 < dwRomSize); // address valid?
*(pbyRom+d) &= (a & 0x0f); // write LSB
if (*(pbyRom+d) != (a & 0x0f)) // check writing
WSMset.byStatusReg |= BWSLBS;
++d; // next nibble
*(pbyRom+d) &= (a >> 4); // write MSB
if (*(pbyRom+d) != (a >> 4)) // check writing
WSMset.byStatusReg |= BWSLBS;
++d; // next nibble
}
}
else
{
WSMset.byWrite1No = 0; // free write buffer
// improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
}
WSMset.byStatusReg |= WSMS; // data written
WSMset.uWrState = WRS_DATA;
return;
}
// byte/word program initial command
static VOID WrState40(DWORD d)
{
WSMset.byStatusReg &= ~WSMS; // state machine busy
WSMset.uWrState = WRS_WR_BYTE;
WSMset.uRdState = RDS_SR;
return;
UNREFERENCED_PARAMETER(d);
}
// byte/word program data
static VOID WrState40D(BYTE a, DWORD d)
{
d <<= 1; // nibble start address
_ASSERT(d+1 < dwRomSize); // address valid?
// no error set in BWSLBS, because i could alway program a "0"
*(pbyRom+d++) &= (a & 0x0f); // write LSB
*(pbyRom+d++) &= (a >> 4); // write MSB
WSMset.byStatusReg |= WSMS; // data written
WSMset.uWrState = WRS_DATA;
return;
}
// block erase initial command
static VOID WrState20(DWORD d)
{
WSMset.byStatusReg &= ~WSMS; // state machine busy
WSMset.uWrState = WRS_BLOCK_ERASE;
WSMset.uRdState = RDS_SR;
return;
UNREFERENCED_PARAMETER(d);
}
// block erase data & confirm
static VOID WrState20C(BYTE a, DWORD d)
{
if (CONFIRM == a) // block erase confirm?
{
_ASSERT((d>>16) < ARRAYSIZEOF(WSMset.byLockCnfg));
if (WSMset.byLockCnfg[d>>16] & 1) // lock bit of block is set
{
WSMset.byStatusReg |= ECLBS; // error in block erasure
WSMset.byStatusReg |= DPS; // lock bit detected
}
else
{
LPBYTE pbyBlock;
UINT i;
d &= ~(_64KB-1); // start of 64KB block
_ASSERT(2*(d+_64KB) <= dwRomSize); // address valid?
pbyBlock = pbyRom + (d << 1); // nibble start address
for (i = 0; i < 2*_64KB; ++i) // write 128K nibble
*pbyBlock++ = 0xf; // write nibble
}
}
else
{
// improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
}
WSMset.byStatusReg |= WSMS; // block erased
WSMset.uWrState = WRS_DATA;
return;
}
// full chip erase initial command
static VOID WrState30(DWORD d)
{
WSMset.byStatusReg &= ~WSMS; // state machine busy
WSMset.uWrState = WRS_CHIP_ERASE;
WSMset.uRdState = RDS_SR;
return;
UNREFERENCED_PARAMETER(d);
}
// full chip erase confirm
static VOID WrState30C(BYTE a, DWORD d)
{
LPBYTE pbyBlock;
UINT i,j;
if (CONFIRM == a) // chip erase confirm?
{
pbyBlock = pbyRom;
for (i = 0; i < 32; ++i) // check all blocks
{
_ASSERT(2*((i+1)*_64KB) <= dwRomSize);
_ASSERT(i < ARRAYSIZEOF(WSMset.byLockCnfg));
// lock bit of block is set & WP# = low, locked blocks cannot be erased
if ((WSMset.byLockCnfg[i] & 1) != 0 && bWP == FALSE)
{
pbyBlock += 2*_64KB; // next block
WSMset.byStatusReg |= ECLBS; // error in block erasure
// WSMset.byStatusReg |= DPS; // lock bit detected
}
else
{
WSMset.byLockCnfg[i] = 0; // clear block lock bit
// write 128K nibble
for (j = 0; j < 2*_64KB; ++j)
*pbyBlock++ = 0xf; // write nibble
}
}
}
else
{
// improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
}
WSMset.byStatusReg |= WSMS; // chip erased
WSMset.uWrState = WRS_DATA;
return;
UNREFERENCED_PARAMETER(d);
}
// STS pin Configuration initial command
static VOID WrStateB8(DWORD d)
{
WSMset.uWrState = WRS_STS_PIN_CONFIG;
return;
UNREFERENCED_PARAMETER(d);
}
// STS pin Configuration data
static VOID WrStateB8D(BYTE a, DWORD d)
{
// no emulation of STS pin Configuration
WSMset.uWrState = WRS_DATA;
return;
UNREFERENCED_PARAMETER(a);
UNREFERENCED_PARAMETER(d);
}
// Set/Clear block Lock-Bits initial command
static VOID WrState60(DWORD d)
{
WSMset.byStatusReg &= ~WSMS; // state machine busy
WSMset.uWrState = WRS_LOCK_BITS;
WSMset.uRdState = RDS_SR;
return;
UNREFERENCED_PARAMETER(d);
}
// Set/Clear block Lock-Bits confirm
static VOID WrState60D(BYTE a, DWORD d)
{
UINT i;
switch(a)
{
case 0x01: // set block lock bit
_ASSERT((d>>16) < ARRAYSIZEOF(WSMset.byLockCnfg));
if (bWP) // WP# = high, can change block lock status
WSMset.byLockCnfg[d>>16] = 1; // set block lock bit
else
WSMset.byStatusReg |= DPS; // device protect detect, WP# = low
break;
case CONFIRM: // clear block lock bits
if (bWP) // WP# = high, can change block lock status
{
for (i = 0; i < 32; ++i) // clear all lock bits
{
_ASSERT(i < ARRAYSIZEOF(WSMset.byLockCnfg));
WSMset.byLockCnfg[i] = 0; // clear block lock bit
}
}
else
{
WSMset.byStatusReg |= DPS; // device protect detect, WP# = low
}
break;
default: // improper command sequence
WSMset.byStatusReg |= (ECLBS | BWSLBS);
}
WSMset.byStatusReg |= WSMS; // block lock-bit changed
WSMset.uWrState = WRS_DATA;
return;
}
//
// read state functions
//
// read array
static BYTE RdStateData(DWORD d)
{
d <<= 1; // nibble address
_ASSERT(d+1 < dwRomSize); // address valid?
return *(pbyRom+d)|(*(pbyRom+d+1)<<4); // get byte
}
// read identifier codes
static BYTE RdStateId(DWORD d)
{
BYTE byData;
d >>= 1; // A0 is not connected, ignore it
_ASSERT((d & 0xFF) < 0x10); // id with valid address?
if ((d & 0xFF) != 0x02) // id code request
{
// get data from id/query table
byData = (d < ARRAYSIZEOF(byQueryTab)) ? byQueryTab[d] : 0;
}
else // block lock table
{
UINT uIndex = d >> 15; // index into lock table
_ASSERT(uIndex < ARRAYSIZEOF(WSMset.byLockCnfg));
byData = WSMset.byLockCnfg[uIndex]; // get data from block lock table
}
return byData;
}
// read query
static BYTE RdStateQuery(DWORD d)
{
d >>= 1; // A0 is not connected, ignore it
// query with valid address?
_ASSERT(d >= 0x10 && d < ARRAYSIZEOF(byQueryTab));
// get data from query table
return (d < ARRAYSIZEOF(byQueryTab)) ? byQueryTab[d] : 0;
}
// read status register
static BYTE RdStateSR(DWORD d)
{
return WSMset.byStatusReg;
UNREFERENCED_PARAMETER(d);
}
// read extended status register
static BYTE RdStateXSR(DWORD d)
{
return WSMset.byExStatusReg;
UNREFERENCED_PARAMETER(d);
}
//
// public functions
//
VOID FlashInit(VOID)
{
ZeroMemory(&WSMset,sizeof(WSMset));
strcpy(WSMset.byType,"WSM"); // Write State Machine header
WSMset.uSize = sizeof(WSMset); // size of this structure
WSMset.byVersion = WSMVER; // version of flash implementation structure
// factory setting of locking bits
WSMset.byLockCnfg[0] = 0x01; // first 64KB block is locked
WSMset.uWrState = WRS_DATA;
WSMset.uRdState = RDS_DATA;
// data mode of ROM
WSMset.bRomArray = bFlashRomArray = TRUE;
return;
}
VOID FlashRead(BYTE *a, DWORD d, UINT s)
{
BYTE v;
while (s) // each nibble
{
// output muliplexer
_ASSERT(WSMset.uRdState < ARRAYSIZEOF(fnRdState));
v = fnRdState[WSMset.uRdState](d>>1);
if ((d & 1) == 0) // even address
{
*a++ = v & 0xf; ++d; --s;
}
if (s && (d & 1)) // odd address
{
*a++ = v >> 4; ++d; --s;
}
}
return;
}
VOID FlashWrite(BYTE *a, DWORD d, UINT s)
{
BYTE v;
DWORD p;
while (s) // each nibble
{
p = d >> 1; // byte address
if (s > 1 && (d & 1) == 0) // more than one byte on even address
{
v = *a++; // LSB
v |= *a++ << 4; // MSB
d += 2; s -= 2;
}
else
{
// get byte from output muliplexer
_ASSERT(WSMset.uRdState < ARRAYSIZEOF(fnRdState));
v = fnRdState[WSMset.uRdState](p);
if (d & 1) // odd address
v = (v & 0x0f) | (*a << 4); // replace MSB
else // even address
v = (v & 0xf0) | *a; // replace LSB
++a; ++d; --s;
}
_ASSERT(WSMset.uWrState < ARRAYSIZEOF(fnWrState));
fnWrState[WSMset.uWrState](v,p); // WSM
}
return;
}

40
sources/Emu48/I28F160.H Normal file
View file

@ -0,0 +1,40 @@
/*
* i28f160.h
*
* This file is part of Emu48
*
* Copyright (C) 2000 Christoph Gießelink
*
*/
#define WSMVER 0 // version of flash implementation structure
#define WSMSET WSMset_t
typedef struct
{
BYTE byType[4]; // "WSM"
UINT uSize; // size of this structure
BYTE byVersion; // WSM version
BOOL bRomArray; // copy of bFlashRomArray
BYTE byLockCnfg[32]; // block lock table
UINT uWrState; // state of write function WSM
UINT uRdState; // state of read function WSM
BYTE byStatusReg; // status register
BYTE byExStatusReg; // extended status register
BYTE byWrite1No; // no. of written data in write buffer1
BYTE byWrite1Size; // no. of valid data in write buffer1
DWORD dwWrite1Addr; // destination address of buffer1
BYTE pbyWrite1[32]; // write buffer1
// BYTE byWrite2No; // no. of written data in write buffer2
// BYTE byWrite2Size; // no. of valid data in write buffer2
// DWORD dwWrite2Addr; // destination address of buffer2
// BYTE pbyWrite2[32]; // write buffer2
} WSMset_t;
// i28f160.h
extern WSMSET WSMset;
extern BOOL bWP;
extern VOID FlashInit(VOID);
extern VOID FlashRead(BYTE *a, DWORD d, UINT s);
extern VOID FlashWrite(BYTE *a, DWORD d, UINT s);

View file

@ -9,7 +9,10 @@
// I/O addresses without mapping offset
#define CRC 0x04 // Crc (16 bit, LSB first)
#define ANNCTRL 0x0b // Annunciator Control (2 nibble)
#define BAUD 0x0d // Baudrate (Bit 2-0)
#define CARDCTL 0x0e // card control
#define CARDSTAT 0x0f // card status
#define IOC 0x10 // IO CONTROL
#define RCS 0x11 // RCS
#define TCS 0x12 // TCS
@ -21,11 +24,34 @@
#define SRQ1 0x18 // SRQ1
#define SRQ2 0x19 // SRQ2
#define IR_CTRL 0x1a // IR CONTROL
#define LCR 0x1c // Led Control Register
#define TIMER1_CTRL 0x2e // Timer1 Control
#define TIMER2_CTRL 0x2f // Timer2 Control
#define TIMER1 0x37 // Timer1 (4 bit)
#define TIMER2 0x38 // Timer2 (32 bit, LSB first)
// 0x0b Annunciator Control [AON XTRA LA6 LA5] [LA4 LA3 LA2 LA1]
#define AON 0x80 // Annunciators on
#define LXTRA 0x40 // does nothing
#define LA6 0x20 // LA6 - Transmitting
#define LA5 0x10 // LA5 - Busy
#define LA4 0x08 // LA4 - Alert
#define LA3 0x04 // LA3 - Alpha
#define LA2 0x02 // LA2 - ALT Shift
#define LA1 0x01 // LA1 - Shift
// 0x0e Card Control [ECDT RCDT SMP SWINT]
#define ECDT 0x08 // Enable Card Detect
#define RCDT 0x04 // Run Card Detect
#define SMP 0x02 // Set module pulled
#define SWINT 0x01 // Software Interrupt
// 0x0f Card Status [P2W P1W P2C P1C]
#define P2W 0x08 // High when Port2 writeable
#define P1W 0x04 // High when Port1 writeable
#define P2C 0x02 // High when Card in Port2 inserted
#define P1C 0x01 // High when Card in Port1 inserted
// 0x10 Serial I/O Control [SON ETBE ERBF ERBZ]
#define SON 0x08 // Serial on
#define ETBE 0x04 // Interrupt on transmit buffer empty
@ -62,6 +88,12 @@
#define EIRI 0x02 // Enable IR interrupt
#define IRE 0x01 // IR event
// 0x1c Led Control Register [LED ELBE LBZ LBF]
#define LED 0x08 // Turn on LED
#define ELBE 0x04 // Enable Interrupt on Led Buffer empty
#define LBZ 0x02 // Led Port Busy
#define LBF 0x01 // Led Buffer Full
// 0x2e Timer1 Control [SRQ WKE INT XTRA]
#define SRQ 0x08 // Service request
#define WKE 0x04 // Wake up

View file

@ -8,6 +8,7 @@
*/
#include "pch.h"
#include "Emu48.h"
#include "io.h" // I/O definitions
static WORD Keyboard_GetIR(VOID)
{
@ -38,16 +39,19 @@ VOID ScanKeyboard(BOOL bReset)
WORD wOldIn = Chipset.in; // save old Chipset.in state
UpdateKdnBit(); // update KDN bit
// 22.11.99 cg, changed, DWORD casting
Chipset.dwKdnCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
// update Chipset.in register
Chipset.in = Keyboard_GetIR() | Chipset.IR15X;
// update keyboard only if timer is running
if (Chipset.IORam[TIMER2_CTRL]&RUN) // timer running
Chipset.in = Keyboard_GetIR(); // update Chipset.in register
else // timer stopped, no keyboard update
Chipset.in &= 0x1FF; // IR[0:8], old keystate without ON key
Chipset.in |= Chipset.IR15X; // add ON key
// interrrupt for any new pressed keys ?
bKbdInt = ((Chipset.in & (Chipset.in ^ wOldIn)) != 0) || bReset;
bKbdInt = (Chipset.in && (wOldIn & 0x1FF) == 0) || Chipset.IR15X || bReset;
// update keyboard interrupt pending flag
// update keyboard interrupt pending flag when 1ms keyboard scan is disabled
Chipset.intd = Chipset.intd || (bKbdInt && !Chipset.intk);
// keyboard interrupt enabled
@ -87,7 +91,7 @@ VOID KeyboardEvent(BOOL bPress, UINT out, UINT in)
}
else
{
_ASSERT(out<9);
_ASSERT(out < sizeof(Chipset.Keyboard_Row) / sizeof(Chipset.Keyboard_Row[0]));
if (bPress) // key pressed
Chipset.Keyboard_Row[out] |= in; // set key marker in keyboard row
else

View file

@ -1626,7 +1626,12 @@ VOID RefreshButtons()
{
UINT x0 = pButton[i].nOx;
UINT y0 = pButton[i].nOy;
EnterCriticalSection(&csGDILock); // solving NT GDI problems
{
BitBlt(hWindowDC, x0, y0, pButton[i].nCx, pButton[i].nCy, hMainDC, x0, y0, SRCCOPY);
GdiFlush();
}
LeaveCriticalSection(&csGDILock);
}
DrawButton(i); // redraw pressed button
}
@ -1861,7 +1866,7 @@ BOOL InitKML(LPCSTR szFilename, BOOL bNoLog)
DWORD lBytesRead;
LPBYTE lpBuf;
Block* pBlock;
BOOL bOk = FALSE; // 08.12.99 cg, bugfix, variable not initialized at error condition
BOOL bOk = FALSE;
BYTE bySum = 0;
KillKML();

View file

@ -8,11 +8,13 @@
*/
#include "pch.h"
#include "Emu48.h"
#include "opcodes.h" // 25.10.99 cg, new, added for HST bits
#include "io.h" // 24.10.99 cg, renamed from Serial.h
#include "opcodes.h"
#include "io.h"
#include "i28f160.h" // flash support
// #define DEBUG_SERIAL // switch for SERIAL debug purpose
// #define DEBUG_IO // switch for I/O debug purpose
// #define DEBUG_FLASH // switch for FLASH MEMORY debug purpose
// defines for reading an open data bus
#define READEVEN 0x0D
@ -24,9 +26,14 @@
#define P2MAPBASE ((BYTE)(Chipset.P2Base & ~Chipset.P2Size))
#define BSMAPBASE ((BYTE)(Chipset.BSBase & ~Chipset.BSSize))
// values for mapping area
enum MMUMAP { M_IO, M_ROM, M_RAM, M_P1, M_P2, M_BS };
BOOL ioc_acc = FALSE; // flag ioc changed
BOOL ir_ctrl_acc = FALSE; // flag ir_ctl changed
BOOL bFlashRomArray = TRUE; // flag ROM mode
BYTE disp = 0; // flag for update display area
static LPBYTE pbyRomView[2] = {NULL,NULL}; // HP49G ROM views
@ -57,8 +64,22 @@ static __inline BYTE UckBit(BYTE byBaudIndex)
QueryPerformanceCounter(&lLC); // get counter value
// calculate UCK frequency
return (((BYTE)((lLC.LowPart * dwBaudrates[byBaudIndex]) / lFreq.LowPart) & 0x1) << 3)
& Chipset.IORam[IOC];
return (((BYTE)(((lLC.QuadPart - lAppStart.QuadPart) * dwBaudrates[byBaudIndex])
/ lFreq.QuadPart) & 0x1) << 3) & Chipset.IORam[IOC];
}
// calculate nibble based linear flash address
static __inline DWORD FlashROMAddr(DWORD d)
{
DWORD dwLinAddr;
// 6 bit of latch (was A6-A1 of address bus)
dwLinAddr = (Chipset.Bank_FF >> 1) & 0x3f;
// decode A21-A18
dwLinAddr = ((d & 0x40000) ? (dwLinAddr & 0xf) : (dwLinAddr >> 4)) << 18;
// decode A21-A18, A17-A0
dwLinAddr |= d & 0x3FFFF;
return dwLinAddr;
}
// LCD line counter calculation
@ -67,8 +88,31 @@ static BYTE F4096Hz(VOID) // get a 6 bit 4096Hz down counter value
LARGE_INTEGER lLC;
QueryPerformanceCounter(&lLC); // get counter value
// calculate 4096 Hz frequency down counter value
return -(BYTE)((lLC.LowPart * 4096) / lFreq.LowPart) & 0x3F;
return -(BYTE)(((lLC.QuadPart - lAppStart.QuadPart) << 12) / lFreq.QuadPart) & 0x3F;
}
// port configuration
static enum MMUMAP MapData(DWORD d) // check MMU area
{
BYTE u = (BYTE) (d>>12);
if (Chipset.IOCfig && ((d&0xFFFC0)==Chipset.IOBase)) return M_IO;
if (Chipset.P0Cfig && (((u^Chipset.P0Base) & ~Chipset.P0Size) == 0)) return M_RAM;
if (cCurrentRomType=='S')
{
if (Chipset.P2Cfig && (((u^Chipset.P2Base) & ~Chipset.P2Size) == 0)) return M_P2;
if (Chipset.P1Cfig && (((u^Chipset.P1Base) & ~Chipset.P1Size) == 0)) return M_P1;
if (Chipset.BSCfig && (((u^Chipset.BSBase) & ~Chipset.BSSize) == 0)) return M_BS;
}
else
{
if (Chipset.P1Cfig && (((u^Chipset.P1Base) & ~Chipset.P1Size) == 0)) return M_P1;
if (Chipset.BSCfig && (((u^Chipset.BSBase) & ~Chipset.BSSize) == 0)) return M_BS;
if (Chipset.P2Cfig && (((u^Chipset.P2Base) & ~Chipset.P2Size) == 0)) return M_P2;
}
return M_ROM;
}
// port mapping
@ -152,7 +196,7 @@ static VOID MapP1(BYTE a, BYTE b)
m = (Chipset.Port1Size*2048)-1; // real size of module, address mask for mirroring
p = (a<<12)&m; // offset to begin of P1 in nibbles
if (Chipset.cards_status & PORT1_WRITE) // 19.11.99 cg, changed, port1 write enabled
if (Chipset.cards_status & PORT1_WRITE) // port1 write enabled
{
for (i=a; i<=b; i++) // scan each 2KB page
{
@ -273,6 +317,8 @@ static VOID MapROM(BYTE a, BYTE b)
DWORD p, m;
if (cCurrentRomType == 'X') // HP49G
{
if (bFlashRomArray) // view flash ROM data
{
_ASSERT(pbyRomView[0]); // check ROM bank set
_ASSERT(pbyRomView[1]);
@ -285,13 +331,22 @@ static VOID MapROM(BYTE a, BYTE b)
WMap[i]=NULL; // no writing
p = (p+0x1000)&m;
}
}
else // view flash ROM register
{
for (i=a; i<=b; i++) // scan each 2KB page
{
RMap[i]=NULL; // view flash register
WMap[i]=NULL; // no writing
}
}
return;
}
// HP48SX / HP48GX
m = (dwRomSize-1)&0xFF000; // ROM address mask for mirroring
// when G(X) ROM and DA19=0 (ROM disabled)
if (cCurrentRomType != 'S' && (Chipset.IORam[0x29]&0x8) == 0)
// HP38G / HP48SX / HP48GX
m = dwRomSize - 1; // ROM address mask for mirroring
// when 512KB ROM and DA19=0 (ROM disabled)
if ((m & 0x80000) != 0 && (Chipset.IORam[0x29]&0x8) == 0)
m >>= 1; // mirror ROM at #80000 (AR18=0)
p = (a*0x1000)&m; // data offset in nibbles
for (i=a;i<=b;i++) // scan each 2KB page
@ -318,7 +373,14 @@ VOID Map(BYTE a, BYTE b) // maps 2KB pages with priority
}
else // HP48GX / HP49G
{
if (Chipset.P2Cfig) MapP2(a,b); // NCE3, port2
if (Chipset.P2Cfig) // NCE3, port2
{
// LED bit set on a HP49
if (cCurrentRomType=='X' && (Chipset.IORam[LCR]&LED))
MapROM(a,b); // NCE3, ROM
else
MapP2(a,b); // NCE3, port2
}
if (Chipset.BSCfig) MapBS(a,b); // CE1, bank select (lower priority than CE2)
if (Chipset.P1Cfig) MapP1(a,b); // CE2, port1 (higher priority than CE1)
}
@ -331,12 +393,11 @@ VOID RomSwitch(DWORD adr)
if (cCurrentRomType=='X') // only HP49G
{
Chipset.Bank_FF = adr; // save address line
// 13.12.99 cg, bugfix, A6 was always zero
adr = (adr >> 1) & 0x3f; // 6 bit of latch (was A6-A1 of address bus)
// lower 4 bit (16 banks) for 2nd ROM view
pbyRomView[1] = pbyRom + ((adr & 0xf) * 128 * 1024 * 2);
pbyRomView[1] = pbyRom + (((adr & 0xf) * 128 * 1024 * 2) & (dwRomSize - 1));
// higher 2 bit (4 banks) for 1st ROM view
pbyRomView[0] = pbyRom + ((adr >> 4) * 128 * 1024 * 2);
pbyRomView[0] = pbyRom + (((adr >> 4) * 128 * 1024 * 2) & (dwRomSize - 1));
}
Map(0x00,0xFF); // update memory mapping
return;
@ -546,18 +607,16 @@ VOID C_Eq_Id()
return;
}
VOID CpuReset(VOID) // 19.03.99 cg, new, register setting after Cpu Reset
VOID CpuReset(VOID) // register setting after Cpu Reset
{
Chipset.pc = 0;
// 23.10.99 cg, bugfix, additional settings
Chipset.rstkp = 0;
FillMemory(Chipset.rstk,sizeof(Chipset.rstk),0);
Chipset.HST = 0;
// 23.10.99 cg, end of additional settings
Chipset.inte = TRUE;
Chipset.Shutdn = FALSE;
Chipset.SoftInt = TRUE;
Chipset.FlashRomState = 0; // WSM state of flash memory
Reset(); // reset MMU
bInterrupt = TRUE;
return;
@ -565,27 +624,28 @@ VOID CpuReset(VOID) // 19.03.99 cg, new, register setting after Cpu Reset
BYTE GetLineCounter(VOID) // get line counter value
{
_ASSERT(byVblRef < 0x40);
return (0x40 + F4096Hz() - byVblRef) & 0x3F;
}
VOID Npeek(BYTE *a, DWORD d, UINT s)
{
enum MMUMAP eMap;
DWORD u, v;
UINT c;
BYTE *p;
do
{
// 12.11.99 cg, new, added reading of I/O area
// test Chipset.IOCfig for mapping
if ((Chipset.IOCfig)&&((d&0xFFFC0)==Chipset.IOBase))
eMap = MapData(d); // get active memory controller
if (M_IO == eMap) // I/O access
{
// update crc
// update CRC
Nunpack(Chipset.IORam+CRC, Chipset.crc, 4);
// update CARDSTAT
Chipset.IORam[CARDSTAT] = (Chipset.IORam[CARDCTL] & ECDT) ? Chipset.cards_status : 0;
// update SRQ2
UpdateKdnBit();
IOBit(SRQ2,NINT2,Chipset.IORam[SRQ1] == 0 && (Chipset.IORam[SRQ2] & LSRQ) == 0);
IOBit(SRQ2,NINT,(Chipset.HST & MP) == 0);
ReadIO(a,SRQ2,1);
// update timer1
Chipset.IORam[TIMER1] = Chipset.t1;
// update timer2
@ -596,62 +656,20 @@ VOID Npeek(BYTE *a, DWORD d, UINT s)
memcpy(a, Chipset.IORam+v, c);
}
else
// 12.11.99 cg, end of new part
{
u = d>>12;
v = d&0xFFF;
c = MIN(s,0x1000-v);
if ((p=RMap[u]) != NULL) memcpy(a, p+v, c);
}
if (s-=c) {a+=c; d+=c;}
} while (s);
return;
}
VOID Nread(BYTE *a, DWORD d, UINT s)
{
DWORD u, v;
UINT c;
BYTE *p;
do
// Flash memory Read access
if (cCurrentRomType == 'X' && (Chipset.IORam[LCR] & LED) && M_P2 == eMap)
{
// test Chipset.IOCfig for mapping
if ((Chipset.IOCfig)&&((d&0xFFFC0)==Chipset.IOBase))
{
v = d&0x3F;
c = MIN(s,0x40-v);
ReadIO(a,v,c);
// 11.11.99 cg, bugfix, reading MSB of timer2 update the CRC register
if (v+c == 0x40) UpCRC(a[c-1]); // timer2 MSB touched, update the CRC register
FlashRead(a, FlashROMAddr(d), s);
}
else
{
u = d>>12;
v = d&0xFFF;
c = MIN(s,0x1000-v);
if ( (cCurrentRomType != 'S')
&& (Chipset.BSCfig && (((u^Chipset.BSBase) & ~Chipset.BSSize) == 0))
&& !(Chipset.P0Cfig && (((u^Chipset.P0Base) & ~Chipset.P0Size) == 0))
&& !(Chipset.P1Cfig && (((u^Chipset.P1Base) & ~Chipset.P1Size) == 0))
)
{
if (cCurrentRomType == 'G') // HP48GX
{
Chipset.Bank_FF = v+c; // save FF value
Map(Chipset.P2Base,Chipset.P2End);
}
else // HP49G
{
if (0!=c) RomSwitch(d+c-1);
}
}
if ((p=RMap[u]) != NULL) // module mapped
{
memcpy(a, p+v, c);
for (u=0; u<c; u++)
UpCRC(a[u]);
}
// simulate open data bus
else // open data bus
@ -662,10 +680,89 @@ VOID Nread(BYTE *a, DWORD d, UINT s)
a[u] = READODD;
else // even address
a[u] = READEVEN;
}
}
// end of bugfix
}
}
if (s-=c) {a+=c; d+=c;}
} while (s);
return;
}
UpCRC(a[u]); // update CRC
VOID Nread(BYTE *a, DWORD d, UINT s)
{
enum MMUMAP eMap;
DWORD u, v;
UINT c;
BYTE *p;
do
{
eMap = MapData(d); // get active memory controller
if (M_IO == eMap) // I/O access
{
v = d&0x3F;
c = MIN(s,0x40-v);
ReadIO(a,v,c);
// reading MSB of timer2 update the CRC register
if (v+c == 0x40) UpCRC(a[c-1]); // timer2 MSB touched, update the CRC register
}
else
{
u = d>>12;
v = d&0xFFF;
c = MIN(s,0x1000-v);
// bank switcher access
if (cCurrentRomType != 'S' && M_BS == eMap)
{
if (cCurrentRomType == 'G') // HP48GX
{
Chipset.Bank_FF = v+c; // save FF value
Map(Chipset.P2Base,Chipset.P2End);
}
if (cCurrentRomType == 'X') // HP49G
{
RomSwitch(v+c);
}
}
// Flash memory Read access
if (cCurrentRomType == 'X' && (Chipset.IORam[LCR] & LED) && M_P2 == eMap)
{
DWORD dwLinAddr = FlashROMAddr(d);
FlashRead(a, dwLinAddr, s);
#if defined DEBUG_FLASH
{
char buffer[256];
wsprintf(buffer,"%.5lx: Flash Read : %.5x (%.6x),%u\n",Chipset.pc,d,dwLinAddr,s);
OutputDebugString(buffer);
}
#endif
}
else
{
if ((p=RMap[u]) != NULL) // module mapped
{
memcpy(a, p+v, c);
}
// simulate open data bus
else // open data bus
{
for (u=0; u<c; ++u) // fill all nibbles
{
if (v+u & 1) // odd address
a[u] = READODD;
else // even address
a[u] = READEVEN;
}
}
}
for (u=0; u<c; u++) // update CRC
UpCRC(a[u]);
}
if (s-=c) {a+=c; d+=c;}
} while (s);
@ -674,6 +771,7 @@ VOID Nread(BYTE *a, DWORD d, UINT s)
VOID Nwrite(BYTE *a, DWORD d, UINT s)
{
enum MMUMAP eMap;
DWORD u, v;
UINT c;
BYTE *p;
@ -708,8 +806,8 @@ VOID Nwrite(BYTE *a, DWORD d, UINT s)
}
do
{
// test Chipset.IOCfig for mapping
if ((Chipset.IOCfig)&&((d&0xFFFC0)==Chipset.IOBase))
eMap = MapData(d); // get active memory controller
if (M_IO == eMap) // I/O access
{
v = d&0x3F;
c = MIN(s,0x40-v);
@ -720,37 +818,71 @@ VOID Nwrite(BYTE *a, DWORD d, UINT s)
u = d>>12;
v = d&0xFFF;
c = MIN(s,0x1000-v);
if ( (cCurrentRomType != 'S')
&& (Chipset.BSCfig && (((u^Chipset.BSBase) & ~Chipset.BSSize) == 0))
&& !(Chipset.P0Cfig && (((u^Chipset.P0Base) & ~Chipset.P0Size) == 0))
&& !(Chipset.P1Cfig && (((u^Chipset.P1Base) & ~Chipset.P1Size) == 0))
)
// bank switcher access
if (cCurrentRomType != 'S' && M_BS == eMap)
{
if (cCurrentRomType == 'G') // HP48GX
{
BOOL bMap = FALSE;
BOOL bWrite = FALSE;
// write enabled
if (Chipset.cards_status & PORT2_WRITE)
{
Chipset.Bank_FF = v+c-1;// save FF value
bWrite = TRUE; // bank switched
}
else // write disabled, so latch last read cycle
{
if ((v & 1) != 0) // low address odd
{
Chipset.Bank_FF = v;// save FF value
bMap = TRUE; // bank switched
bWrite = TRUE; // bank switched
}
if ((v+c & 1) != 0) // high address odd
{
Chipset.Bank_FF = v+c-1;// save FF value
bMap = TRUE; // bank switched
bWrite = TRUE; // bank switched
}
}
if (bMap) Map(Chipset.P2Base,Chipset.P2End);
}
else // HP49G
if (bWrite) // write cycle?
{
if (0!=c) RomSwitch(d+c-1);
// HP48GX
if (cCurrentRomType == 'G') Map(Chipset.P2Base,Chipset.P2End);
// HP49G
if (cCurrentRomType == 'X') RomSwitch(Chipset.Bank_FF);
}
}
// Flash memory Write access
if (cCurrentRomType == 'X' && (Chipset.IORam[LCR] & LED) && M_P2 == eMap)
{
DWORD dwLinAddr = FlashROMAddr(d);
FlashWrite(a, dwLinAddr, s);
#if defined DEBUG_FLASH
{
char buffer[256];
DWORD j;
int i;
i = wsprintf(buffer,"%.5lx: Flash Write: %.5x (%.6x),%u = ",Chipset.pc,d,dwLinAddr,s);
for (j = 0;j < s;++j,++i)
{
buffer[i] = a[j];
if (buffer[i] > 9) buffer[i] += 0x27;
buffer[i] += '0';
}
buffer[i++] = '\n';
buffer[i] = 0;
OutputDebugString(buffer);
}
#endif
}
else
{
if ((p=WMap[u]) != NULL) memcpy(p+v, a, c);
}
}
a+=c;
d+=c;
} while (s-=c);
@ -805,6 +937,9 @@ VOID IOBit(DWORD d, BYTE b, BOOL s) // set/clear bit in I/O section
VOID ReadIO(BYTE *a, DWORD d, DWORD s)
{
BOOL bNINT;
BOOL bNINT2;
BYTE c = 0xFF; // LINECOUNT not initialized
BOOL rbr_acc = FALSE; // flag to receive data
@ -844,11 +979,27 @@ VOID ReadIO(BYTE *a, DWORD d, DWORD s)
#endif
*a |= UckBit(*a); // add UCK bit to BAUD rate register
break;
// case 0x0E: *a = Chipset.IORam[d]; break;
case 0x0E:
// SMP is !NINT and SWINT is always 0
// clear SMP and SWINT bit
Chipset.IORam[d] &= (ECDT | RCDT);
// SMP is !NINT
if ((Chipset.IORam[SRQ2] & NINT) == 0)
Chipset.IORam[d] |= SMP;
*a = Chipset.IORam[d];
break;
case 0x0F:
// On a HP49G Chipset.cards_status bust always be 0xF
// card detection disabled
if ((Chipset.IORam[CARDCTL] & ECDT) == 0)
{
*a = 0; // no cards
}
else
{
// on a HP49G Chipset.cards_status bust always be 0xF
_ASSERT(cCurrentRomType!='X' || Chipset.cards_status == 0xF);
*a = Chipset.cards_status;
}
break;
case 0x10: // IO CONTROL
*a = Chipset.IORam[d]; // return IO CONTROL value
@ -887,7 +1038,7 @@ VOID ReadIO(BYTE *a, DWORD d, DWORD s)
case 0x15: // RBR MSB
Chipset.IORam[RCS]&=~RBF;
*a = Chipset.IORam[d]; // return RBR value
UpdateUSRQ(); // 25.10.99 cg, bugfix, update USRQ
UpdateUSRQ(); // update USRQ
rbr_acc = TRUE; // search for new RBR value
#if defined DEBUG_SERIAL
{
@ -903,10 +1054,18 @@ VOID ReadIO(BYTE *a, DWORD d, DWORD s)
break;
case 0x19: // SREQ? MSB
UpdateKdnBit(); // update KDN bit
// 25.10.99 cg, bugfix, update NINT2 bit
IOBit(SRQ2,NINT2,Chipset.IORam[SRQ1] == 0 && (Chipset.IORam[SRQ2] & LSRQ) == 0);
// 25.10.99 cg, bugfix, update NINT bit
IOBit(SRQ2,NINT,(Chipset.HST & MP) == 0);
bNINT2 = Chipset.IORam[SRQ1] == 0 && (Chipset.IORam[SRQ2] & LSRQ) == 0;
bNINT = (Chipset.IORam[SRQ2] & NINT) != 0;
// card detection off and timer running
if ((Chipset.IORam[CARDCTL] & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0)
{
// state of CDT2
bNINT2 = bNINT2 && (Chipset.cards_status & (P2W|P2C)) != P2C;
// state of CDT1
bNINT = bNINT && (Chipset.cards_status & (P1W|P1C)) != P1C;
}
IOBit(SRQ2,NINT2,bNINT2);
IOBit(SRQ2,NINT,bNINT);
// no break!
case 0x18: // SREQ? LSB
*a = Chipset.IORam[d]; // return SREQ value
@ -1149,28 +1308,50 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s)
#endif
break;
// 0010E = NS:CARDCTRL
// 0010E = NS:CARDCTL
// 0010E @ [ECDT RCDT SMP SWINT] (read/write)
// 0010E @ Enable Card Det., Run Card Det., Set Module Pulled, Software interrupt
case 0x0E:
Chipset.IORam[d]=c;
#if 1
if ( (RMap[4]!=(pbyRom+0x4000)) && (12 != c) )
{
c |= 0x10;
}
#endif
if (c&1)
if (c & SWINT) // SWINT bit set
{
c &= (ECDT | RCDT | SMP); // clear SWINT bit
Chipset.SoftInt = TRUE;
bInterrupt = TRUE;
}
if (c&2)
if ((c & SMP) == 0) // SMP bit cleared
{
Chipset.HST |= 8; // MP
// Chipset.SoftInt = TRUE;
// bInterrupt = TRUE;
BOOL bNINT = TRUE; // ack NINT interrupt -> NINT high
// card detect disabled and CDT1 low -> retrigger
if ((c & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0)
bNINT = (Chipset.cards_status & (P1W|P1C)) != P1C;
IOBit(SRQ2,NINT,bNINT);
}
// falling edge of Enable Card Detect bit and timer running
if ( ((c^Chipset.IORam[d]) & ECDT) != 0 && (c & ECDT) == 0
&& (Chipset.IORam[TIMER2_CTRL] & RUN) != 0)
{
BOOL bNINT = (Chipset.IORam[SRQ2] & NINT) != 0;
// card in slot1 isn't Read Only
if ((Chipset.cards_status & (P1W|P1C)) != P1C)
{
// use random state of NINT line
bNINT = bNINT && (ReadT2() & 0x1) != 0;
}
IOBit(SRQ2,NINT,bNINT);
Chipset.HST |= MP; // set Module Pulled
// Port1 and Port2 plugged and writeable or NINT2/NINT interrupt
if ( Chipset.cards_status != (P2W|P1W|P2C|P1C)
|| (Chipset.IORam[SRQ2] & NINT2) == 0
|| (Chipset.IORam[SRQ2] & NINT ) == 0
)
{
Chipset.SoftInt = TRUE; // set interrupt
bInterrupt = TRUE;
}
}
Chipset.IORam[d]=c;
break;
// 0010F = NS:CARDSTATUS
@ -1182,7 +1363,7 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s)
// 00110 @ Serial On, Interrupt On Recv.Buf.Empty, Full, Buzy
case 0x10:
Chipset.IORam[d]=c;
UpdateUSRQ(); // 25.10.99 cg, bugfix, update USRQ
UpdateUSRQ(); // update USRQ
ioc_acc = TRUE; // new IOC value
#if defined DEBUG_SERIAL
{
@ -1244,7 +1425,7 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s)
case 0x17:
Chipset.IORam[d]=c;
Chipset.IORam[TCS]|=TBF;
UpdateUSRQ(); // 25.10.99 cg, bugfix, update USRQ
UpdateUSRQ(); // update USRQ
tbr_acc = TRUE; // new TBR value
#if defined DEBUG_SERIAL
{
@ -1282,7 +1463,22 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s)
// 0011C = NS:LCR
// 0011C @ Led Control Register [LED ELBE LBZ LBF] (Setting LED is draining)
case 0x1C: Chipset.IORam[d]=c; break;
case 0x1C:
// HP49G new mapping on LED bit change
if (cCurrentRomType=='X' && ((c^Chipset.IORam[d])&LED))
{
Chipset.IORam[d]=c; // save new value for mapping
Map(Chipset.P2Base,Chipset.P2End); // new ROM mapping
#if defined DEBUG_FLASH
{
char buffer[256];
wsprintf(buffer,"%.5lx: NCE3: R%cM\n",Chipset.pc,(c&LED) ? 'O' : 'A');
OutputDebugString(buffer);
}
#endif
}
Chipset.IORam[d]=c;
break;
// 0011D = NS:LBR
// 0011D @ Led Buffer Register [0 0 0 LBO] (bits 1-3 read zero)
@ -1325,8 +1521,7 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s)
// 00128 @ Normally has 55 -> Menu starts at display row 56
case 0x28:
case 0x29:
// when G(X) and writing to register 0x29
if (cCurrentRomType != 'S' && d == 0x29)
if (d == 0x29)
{
if ((c^Chipset.IORam[d])&8) // DA19 changed
{
@ -1359,6 +1554,7 @@ VOID WriteIO(BYTE *a, DWORD d, DWORD s)
StartTimers();
else
StopTimers();
disp |= DISP_ANNUN; // update annunciators
break;
// 00130 = NS:MENUADDR

View file

@ -10,6 +10,7 @@
#include "pch.h"
#include "Emu48.h"
#include "Opcodes.h"
#include "io.h" // I/O register definitions
#define w Chipset
#define GOYES3 {if(w.carry) o_goyes3(I);else{w.pc+=2;return;}}
@ -19,6 +20,10 @@
#include "Ops.h"
// Fields start and length
UINT F_s[16] = {0/*P*/,0,2,0,15,3,0,0,0,0,0,0,0,0,0,0};
UINT F_l[16] = {1,1/*P+1*/,1,3,1,12,2,16,0,0,0,0,0,0,0,5};
VOID o00(LPBYTE I) // RTNSXM
{
w.cycles+=9;
@ -84,7 +89,7 @@ VOID o07(LPBYTE I) // C=RSTK
VOID o08(LPBYTE I) // CLRST
{
w.cycles+=5; // 22.10.99 cg, bugfix, fixed no. of cycles
w.cycles+=5;
w.pc+=2;
memset(w.ST, 0, 3);
return;
@ -92,7 +97,7 @@ VOID o08(LPBYTE I) // CLRST
VOID o09(LPBYTE I) // C=ST
{
w.cycles+=5; // 22.10.99 cg, bugfix, fixed no. of cycles
w.cycles+=5;
w.pc+=2;
memcpy(w.C, w.ST, 3);
return;
@ -100,7 +105,7 @@ VOID o09(LPBYTE I) // C=ST
VOID o0A(LPBYTE I) // ST=C
{
w.cycles+=5; // 22.10.99 cg, bugfix, fixed no. of cycles
w.cycles+=5;
w.pc+=2;
memcpy(w.ST, w.C, 3);
return;
@ -108,7 +113,7 @@ VOID o0A(LPBYTE I) // ST=C
VOID o0B(LPBYTE I) // CSTEX
{
w.cycles+=5; // 22.10.99 cg, bugfix, fixed no. of cycles
w.cycles+=5;
w.pc+=2;
Nxchg(w.C, w.ST, 3);
return;
@ -276,11 +281,29 @@ VOID o0F(LPBYTE I) // RTI
INTERRUPT; // restart interrupt handler
}
// low interrupt lines
{
BOOL bNINT2 = Chipset.IORam[SRQ1] == 0 && (Chipset.IORam[SRQ2] & LSRQ) == 0;
BOOL bNINT = (Chipset.IORam[SRQ2] & NINT) != 0;
// card detection off and timer running
if ((Chipset.IORam[CARDCTL] & ECDT) == 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0)
{
// state of CDT2
bNINT2 = bNINT2 && (Chipset.cards_status & (P2W|P2C)) != P2C;
// state of CDT1
bNINT = bNINT && (Chipset.cards_status & (P1W|P1C)) != P1C;
}
if (!bNINT2 || !bNINT) // NINT2 or NINT interrupt line low
INTERRUPT; // restart interrupt handler
}
// restart interrupt handler when timer interrupt
if (w.IORam[0x2E]&0x02) // INT bit of timer1 is set
if (w.IORam[TIMER1_CTRL]&INTR) // INT bit of timer1 is set
ReadT1(); // check for int
if (w.IORam[0x2F]&0x02) // INT bit of timer2 is set
if (w.IORam[TIMER2_CTRL]&INTR) // INT bit of timer2 is set
ReadT2(); // check for int
return;
}
@ -834,7 +857,7 @@ VOID o3X(LPBYTE I) // LCHEX
{
UINT n=I[1]+1;
UINT d=16-w.P;
w.cycles+=3+n; // 22.10.99 cg, bugfix, fixed no. of cycles
w.cycles+=3+n;
w.pc+=2;
I+=2; // UNSAFE
if (n<=d)
@ -1010,7 +1033,6 @@ VOID o8080(LPBYTE I) // INTON
w.cycles+=5;
w.pc+=4;
// cpu cycles at start of 1ms key handler
// 22.11.99 cg, changed, DWORD casting
w.dwKdnCycles = (DWORD) (w.cycles & 0xFFFFFFFF);
w.intk = TRUE;
@ -1029,7 +1051,6 @@ VOID o80810(LPBYTE I) // RSI
ScanKeyboard(TRUE); // one input bit high ?
// enable KDN update
// 22.11.99 cg, changed, DWORD casting
w.dwKdnCycles = (DWORD) (w.cycles & 0xFFFFFFFF) - (DWORD) T2CYCLES * 16;
if (w.in && w.inte == FALSE) // key interrupt pending
@ -1083,7 +1104,7 @@ VOID o8085n(LPBYTE I) // ABIT=1 n
VOID o8086n(LPBYTE I) // ?ABIT=0 n
{
w.cycles+=9; // 22.10.99 cg, bugfix, fixed no. of cycles
w.cycles+=9;
w.pc+=5;
Tbit0(w.A, I[4]);
GOYES5;
@ -1091,7 +1112,7 @@ VOID o8086n(LPBYTE I) // ?ABIT=0 n
VOID o8087n(LPBYTE I) // ?ABIT=1 n
{
w.cycles+=9; // 22.10.99 cg, bugfix, fixed no. of cycles
w.cycles+=9;
w.pc+=5;
Tbit1(w.A, I[4]);
GOYES5;
@ -1115,7 +1136,7 @@ VOID o8089n(LPBYTE I) // CBIT=1 n
VOID o808An(LPBYTE I) // ?CBIT=0 n
{
w.cycles+=9; // 22.10.99 cg, bugfix, fixed no. of cycles
w.cycles+=9;
w.pc+=5;
Tbit0(w.C, I[4]);
GOYES5;
@ -1123,7 +1144,7 @@ VOID o808An(LPBYTE I) // ?CBIT=0 n
VOID o808Bn(LPBYTE I) // ?CBIT=1 n
{
w.cycles+=9; // 22.10.99 cg, bugfix, fixed no. of cycles
w.cycles+=9;
w.pc+=5;
Tbit1(w.C, I[4]);
GOYES5;
@ -1131,8 +1152,10 @@ VOID o808Bn(LPBYTE I) // ?CBIT=1 n
VOID o808C(LPBYTE I) // PC=(A)
{
BYTE p[5];
w.cycles+=23;
w.pc=Read5(Npack(w.A,5));
Nread(p,Npack(w.A,5),5); // read (A) and update CRC
w.pc=Npack(p,5);
return;
}
@ -1147,8 +1170,10 @@ VOID o808D(LPBYTE I) // BUSCD
VOID o808E(LPBYTE I) // PC=(C)
{
BYTE p[5];
w.cycles+=23;
w.pc=Read5(Npack(w.C,5));
Nread(p,Npack(w.C,5),5); // read (C) and update CRC
w.pc=Npack(p,5);
return;
}
@ -2085,7 +2110,7 @@ VOID o8Ed4(LPBYTE I) // GOSUBL #dddd
DWORD d=Npack(I+2,4);
rstkpush(w.pc+6);
if (d&0x8000) w.pc-=0xfffa-d; else w.pc+=d+6;
w.cycles+=14; // 22.10.99 cg, bugfix, fixed no. of cycles
w.cycles+=14;
w.pc&=0xFFFFF;
return;
}

View file

@ -7,17 +7,14 @@
*
*/
// HST bits
#define XM 1
#define SB 2
#define SR 4
#define MP 8
#define PCHANGED ((void)(F_s[0]=Chipset.P,F_l[1]=Chipset.P+1))
#define INTERRUPT ((void)(Chipset.SoftInt=TRUE,bInterrupt=TRUE))
#define T2CYCLES ((cCurrentRomType=='S')?dwSXCycles:dwGXCycles)
extern UINT F_s[16];
extern UINT F_l[16];
extern VOID o00(LPBYTE I); // RTNSXM
extern VOID o01(LPBYTE I); // RTN
extern VOID o02(LPBYTE I); // RTNSC

View file

@ -8,10 +8,6 @@
*/
// #pragma warning(disable:4244)
// Fields start and length
static UINT F_s[16] = {0/*P*/,0,2,0,15,3,0,0,0,0,0,0,0,0,0,0};
static UINT F_l[16] = {1,1/*P+1*/,1,3,1,12,2,16,0,0,0,0,0,0,0,5};
#define NFunpack(a, b, f) Nunpack((a)+F_s[f], b, F_l[f])
#define NFread(a, b, f) Nread((a)+F_s[f], b, F_l[f])
#define NFwrite(a, b, f) Nwrite((a)+F_s[f], b, F_l[f])
@ -42,10 +38,24 @@ static UINT F_l[16] = {1,1/*P+1*/,1,3,1,12,2,16,0,0,0,0,0,0,0,5};
static __inline LPBYTE FASTPTR(DWORD d)
{
static BYTE pbyNULL[16];
LPBYTE lpbyPage;
d &= 0xFFFFF; // handle address overflows
if ((Chipset.IOCfig)&&((d&0xFFFC0)==Chipset.IOBase))
return Chipset.IORam+d-Chipset.IOBase;
return RMap[d>>12]+(d&0xFFF);
if((lpbyPage = RMap[d>>12]) != NULL) // page valid
{
lpbyPage += d & 0xFFF; // full address
}
else
{
lpbyPage = pbyNULL; // memory allocation
Npeek(lpbyPage, d, 13); // fill with data (LA(8) = longest opcode)
}
return lpbyPage;
}
static __inline void rstkpush(DWORD d)
@ -90,19 +100,34 @@ static __inline void Nxchg(BYTE *a, BYTE *b, UINT s)
static __inline void Ninc(BYTE *a, UINT s, UINT d)
{
UINT i;
BYTE cBase = Chipset.mode_dec ? 10 : 16;
if (Chipset.mode_dec)
{
BYTE c = 1;
for (i=d; i<s+d; ++i)
{
if (a[i&0xf] >= 10) a[i&0xf] &= 0x7;
a[i&0xf] += c;
c = (a[i&0xf] >= 10);
if (c) a[i&0xf] -= 10;
}
Chipset.carry = (c==1);
}
else
{
for (i=d; i<s+d; ++i)
{
a[i&0xf]++;
if (a[i&0xf] < cBase)
if (a[i&0xf] < 16)
{
Chipset.carry = FALSE;
return;
}
a[i&0xf] -= cBase;
a[i&0xf] -= 16;
}
Chipset.carry = TRUE;
}
}
static __inline void Ninc16(BYTE *a, UINT s, UINT d)
@ -143,7 +168,7 @@ static __inline void Ndec(BYTE *a, UINT s, UINT d)
for (i=d; i<s+d; ++i)
{
a[i&0xf]--;
if (a[i&0xf] < cBase)
if ((a[i&0xf] & 0xF0) == 0) // check overflow
{
Chipset.carry = FALSE;
return;
@ -178,6 +203,10 @@ static __inline void Nadd(BYTE *a, BYTE *b, UINT s)
for (i=0; i<s; ++i)
{
// illegal number in dec mode
if (Chipset.mode_dec && a[i] >= 10)
a[i] &= 0x7;
a[i] += b[i] + c;
if (a[i] >= cBase)
{
@ -199,7 +228,7 @@ static __inline void Nsub(BYTE *a, BYTE *b, UINT s)
for (i=0; i<s; ++i)
{
a[i] -= b[i] + c;
if (a[i] >= cBase)
if ((a[i&0xf] & 0xF0) != 0) // check overflow
{
a[i] += cBase;
c = 1;
@ -219,7 +248,7 @@ static __inline void Nrsub(BYTE *a, BYTE *b, UINT s)
for (i=0; i<s; ++i)
{
a[i] = b[i] - (a[i] + c);
if (a[i] >= cBase)
if ((a[i&0xf] & 0xF0) != 0) // check overflow
{
a[i] += cBase;
c = 1;
@ -244,7 +273,12 @@ static __inline void Nnot(BYTE *a, UINT s)
{
BYTE cBase = Chipset.mode_dec ? 9 : 15;
while (s--) a[s] = cBase - a[s];
while (s--)
{
a[s] = cBase - a[s];
if ((a[s] & 0xF0) != 0) // check overflow (dec mode only)
a[s] &= 0x7;
}
Chipset.carry = FALSE;
}
@ -257,8 +291,14 @@ static __inline void Nneg(BYTE *a, UINT s)
if (Chipset.carry = (i!=s)) // value was non-zero
{
a[i] = cBase - a[i]; // first non-zero digit
if ((a[i] & 0xF0) != 0) // check overflow (dec mode only)
a[i] &= 0x7;
for (--cBase, ++i; i<s; i++)
{
a[i] = cBase - a[i];
if ((a[i] & 0xF0) != 0) // check overflow (dec mode only)
a[i] &= 0x7;
}
}
}

View file

@ -7,18 +7,17 @@
#define IDR_DEBUG 102
#define IDR_DEBUG_CODE 103
#define IDR_DEBUG_MEM 104
#define IDB_EMPTY 105
#define IDD_ABOUT 106
#define IDD_ABOUTS 107
#define IDD_SETTINGS 108
#define IDD_CHOOSEKML 109
#define IDD_KMLLOG 110
#define IDD_REGISTER 111
#define IDD_DISASM 112
#define IDD_DEBUG 113
#define IDD_NEWVALUE 114
#define IDD_ENTERADR 115
#define IDD_BREAKEDIT 116
#define IDD_ABOUT 105
#define IDD_SETTINGS 106
#define IDD_CHOOSEKML 107
#define IDD_KMLLOG 108
#define IDD_DISASM 109
#define IDD_DEBUG 110
#define IDD_NEWVALUE 111
#define IDD_ENTERADR 112
#define IDD_BREAKEDIT 113
#define IDD_ENTERBREAK 114
#define IDD_INSTRUCTIONS 115
#define IDC_PORT1WR 1000
#define IDC_AUTOSAVE 1001
#define IDC_AUTOSAVEONEXIT 1002
@ -31,75 +30,95 @@
#define IDC_PORT2ISSHARED 1009
#define IDC_PORT2 1010
#define IDC_ALWAYSDISPLOG 1011
#define IDC_NAME 1012
#define IDC_REGTEXT 1013
#define IDC_CODE 1014
#define IDC_REGISTER 1015
#define IDC_UPDATE 1016
#define IDC_LICENSE 1017
#define IDC_REALSPEED 1018
#define IDC_PORT1EN 1019
#define IDC_WIRE 1020
#define IDC_IR 1021
#define IDC_DISASM_WIN 1022
#define IDC_DISASM_MAP 1023
#define IDC_DISASM_ROM 1024
#define IDC_DISASM_RAM 1025
#define IDC_DISASM_PORT1 1026
#define IDC_DISASM_PORT2 1027
#define IDC_DISASM_MODULE 1028
#define IDC_DISASM_HP 1029
#define IDC_DISASM_CLASS 1030
#define IDC_DISASM_MNEMONICS 1031
#define IDC_ADDRESS 1032
#define IDC_DISASM_ADR 1033
#define IDC_DISASM_NEXT 1034
#define IDC_DISASM_COPY 1035
#define IDC_DEBUG_CODE 1036
#define IDC_STATIC_CODE 1037
#define IDC_STATIC_REGISTERS 1038
#define IDC_STATIC_MEMORY 1039
#define IDC_STATIC_STACK 1040
#define IDC_REG_A 1041
#define IDC_REG_B 1042
#define IDC_REG_C 1043
#define IDC_REG_D 1044
#define IDC_REG_R0 1045
#define IDC_REG_R1 1046
#define IDC_REG_R2 1047
#define IDC_REG_R3 1048
#define IDC_REG_R4 1049
#define IDC_REG_D0 1050
#define IDC_REG_D1 1051
#define IDC_REG_P 1052
#define IDC_REG_PC 1053
#define IDC_REG_OUT 1054
#define IDC_REG_IN 1055
#define IDC_REG_ST 1056
#define IDC_REG_CY 1057
#define IDC_REG_MODE 1058
#define IDC_REG_MP 1059
#define IDC_REG_SR 1060
#define IDC_REG_SB 1061
#define IDC_REG_XM 1062
#define IDC_NEWVALUE 1063
#define IDC_ENTERADR 1064
#define IDC_DEBUG_MEM 1065
#define IDC_DEBUG_MEM_ADDR 1066
#define IDC_DEBUG_MEM_COL0 1067
#define IDC_DEBUG_MEM_COL1 1068
#define IDC_DEBUG_MEM_COL2 1069
#define IDC_DEBUG_MEM_COL3 1070
#define IDC_DEBUG_MEM_COL4 1071
#define IDC_DEBUG_MEM_COL5 1072
#define IDC_DEBUG_MEM_COL6 1073
#define IDC_DEBUG_MEM_COL7 1074
#define IDC_DEBUG_MEM_TEXT 1075
#define IDC_DEBUG_STACK 1076
#define IDC_STATIC_BREAKPOINT 1077
#define IDC_BREAKEDIT_ADD 1078
#define IDC_BREAKEDIT_DELETE 1079
#define IDC_BREAKEDIT_WND 1080
#define IDC_UPDATE 1012
#define IDC_LICENSE 1013
#define IDC_REALSPEED 1014
#define IDC_PORT1EN 1015
#define IDC_WIRE 1016
#define IDC_IR 1017
#define IDC_DISASM_WIN 1018
#define IDC_DISASM_MAP 1019
#define IDC_DISASM_ROM 1020
#define IDC_DISASM_RAM 1021
#define IDC_DISASM_PORT1 1022
#define IDC_DISASM_PORT2 1023
#define IDC_DISASM_MODULE 1024
#define IDC_DISASM_HP 1025
#define IDC_DISASM_CLASS 1026
#define IDC_DISASM_MNEMONICS 1027
#define IDC_ADDRESS 1028
#define IDC_DISASM_ADR 1029
#define IDC_DISASM_NEXT 1030
#define IDC_DISASM_COPY 1031
#define IDC_DEBUG_CODE 1032
#define IDC_STATIC_CODE 1033
#define IDC_STATIC_REGISTERS 1034
#define IDC_STATIC_MEMORY 1035
#define IDC_STATIC_STACK 1036
#define IDC_REG_A 1037
#define IDC_REG_B 1038
#define IDC_REG_C 1039
#define IDC_REG_D 1040
#define IDC_REG_R0 1041
#define IDC_REG_R1 1042
#define IDC_REG_R2 1043
#define IDC_REG_R3 1044
#define IDC_REG_R4 1045
#define IDC_REG_D0 1046
#define IDC_REG_D1 1047
#define IDC_REG_P 1048
#define IDC_REG_PC 1049
#define IDC_REG_OUT 1050
#define IDC_REG_IN 1051
#define IDC_REG_ST 1052
#define IDC_REG_CY 1053
#define IDC_REG_MODE 1054
#define IDC_REG_MP 1055
#define IDC_REG_SR 1056
#define IDC_REG_SB 1057
#define IDC_REG_XM 1058
#define IDC_MISC_INT 1059
#define IDC_MISC_KEY 1060
#define IDC_MISC_BS 1061
#define IDC_NEWVALUE 1062
#define IDC_ENTERADR 1063
#define IDC_DEBUG_MEM 1064
#define IDC_DEBUG_MEM_ADDR 1065
#define IDC_DEBUG_MEM_COL0 1066
#define IDC_DEBUG_MEM_COL1 1067
#define IDC_DEBUG_MEM_COL2 1068
#define IDC_DEBUG_MEM_COL3 1069
#define IDC_DEBUG_MEM_COL4 1070
#define IDC_DEBUG_MEM_COL5 1071
#define IDC_DEBUG_MEM_COL6 1072
#define IDC_DEBUG_MEM_COL7 1073
#define IDC_DEBUG_MEM_TEXT 1074
#define IDC_DEBUG_STACK 1075
#define IDC_STATIC_BREAKPOINT 1076
#define IDC_BREAKEDIT_ADD 1077
#define IDC_BREAKEDIT_DELETE 1078
#define IDC_BREAKEDIT_WND 1079
#define IDC_STATIC_MMU 1080
#define IDC_MMU_IO_A 1081
#define IDC_MMU_NCE2_A 1082
#define IDC_MMU_CE1_A 1083
#define IDC_MMU_CE2_A 1084
#define IDC_MMU_NCE3_A 1085
#define IDC_MMU_IO_S 1086
#define IDC_MMU_CE1_S 1087
#define IDC_MMU_CE2_S 1088
#define IDC_MMU_NCE2_S 1089
#define IDC_MMU_NCE3_S 1090
#define IDC_STATIC_MISC 1091
#define IDC_MISC_BS_TXT 1092
#define IDC_INSTR_TEXT 1093
#define IDC_INSTR_CODE 1094
#define IDC_INSTR_COPY 1095
#define IDC_INSTR_CLEAR 1096
#define IDC_BPCODE 1097
#define IDC_BPACCESS 1098
#define IDC_BPREAD 1099
#define IDC_BPWRITE 1100
#define ID_FILE_NEW 40001
#define ID_FILE_OPEN 40002
#define ID_FILE_SAVE 40003
@ -120,31 +139,34 @@
#define ID_STACK_PASTE 40020
#define ID_TOOL_DISASM 40021
#define ID_TOOL_DEBUG 40022
#define ID_DEBUG_RUN 40024
#define ID_DEBUG_STEP 40025
#define ID_DEBUG_STEPOVER 40026
#define ID_DEBUG_BREAK 40027
#define ID_DEBUG_RUN 40023
#define ID_DEBUG_STEP 40024
#define ID_DEBUG_STEPOVER 40025
#define ID_DEBUG_BREAK 40026
#define ID_DEBUG_STEPOUT 40027
#define ID_BREAKPOINTS_SETBREAK 40028
#define ID_BREAKPOINTS_CODEEDIT 40029
#define ID_BREAKPOINTS_CLEARALL 40030
#define ID_DEBUG_CODE_GOADR 40031
#define ID_DEBUG_CODE_GOPC 40032
#define ID_DEBUG_CODE_SETPCTOSELECT 40033
#define ID_DEBUG_MEM_GOADR 40034
#define ID_DEBUG_MEM_GOPC 40035
#define ID_DEBUG_MEM_GOD0 40036
#define ID_DEBUG_MEM_GOD1 40037
#define ID_DEBUG_MEM_GOSTACK 40038
#define ID_BREAKPOINTS_NOP3 40039
#define ID_DEBUG_STEPOUT 40040
#define ID_BREAKPOINTS_NOP3 40031
#define ID_BREAKPOINTS_RPL 40032
#define ID_DEBUG_CODE_GOADR 40033
#define ID_DEBUG_CODE_GOPC 40034
#define ID_DEBUG_CODE_SETPCTOSELECT 40035
#define ID_DEBUG_MEM_GOADR 40036
#define ID_DEBUG_MEM_GOPC 40037
#define ID_DEBUG_MEM_GOD0 40038
#define ID_DEBUG_MEM_GOD1 40039
#define ID_DEBUG_MEM_GOSTACK 40040
#define ID_INFO_LASTINSTRUCTIONS 40041
#define ID_INTR_STEPOVERINT 40042
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 117
#define _APS_NEXT_COMMAND_VALUE 40041
#define _APS_NEXT_CONTROL_VALUE 1081
#define _APS_NEXT_RESOURCE_VALUE 116
#define _APS_NEXT_COMMAND_VALUE 40043
#define _APS_NEXT_CONTROL_VALUE 1101
#define _APS_NEXT_SYMED_VALUE 108
#endif
#endif

View file

@ -8,6 +8,7 @@
*/
#include "pch.h"
#include "Emu48.h"
#include "io.h"
//| 38G | 48SX | 48GX | 49G | Name
// #7056A #806E9 #806E9 =TEMPOB
@ -24,6 +25,36 @@
#define AVMEM ((cCurrentRomType!='X')?((cCurrentRomType=='S')?0x7066E:0x807ED):0x80E9B)
#define INTRPPTR ((cCurrentRomType!='X')?((cCurrentRomType=='S')?0x705B0:0x8072F):0x8076B)
// check for Metakernel version
#define METAKERNEL Metakernel()
// search for "MDGKER:MK2.30" or "MDGKER:PREVIE" in port1 of a HP48GX
static BOOL Metakernel(VOID)
{
BOOL bMkDetect = FALSE;
// card in slot1 of a HP48GX enabled
if (cCurrentRomType=='G' && Chipset.cards_status & PORT1_PRESENT)
{
// check for Metakernel string "MDGKER:"
if (!strncmp(&Chipset.Port1[12],"\xD\x4\x4\x4\x7\x4\xB\x4\x5\x4\x2\x5\xA\x3",14))
{
bMkDetect = TRUE; // Metakernel detected
// check for "MK"
if (!strncmp(&Chipset.Port1[26],"\xD\x4\xB\x4",4))
{
// get version number
WORD wVersion = ((Chipset.Port1[30] * 10) + Chipset.Port1[34]) * 10
+ Chipset.Port1[36];
// version newer then V2.30, then compatible with HP OS
bMkDetect = (wVersion <= 230);
}
}
}
return bMkDetect;
}
DWORD RPL_SkipOb(DWORD d)
{
BYTE X[8];
@ -246,6 +277,7 @@ DWORD RPL_Pick(UINT l)
_ASSERT(l > 0); // first stack elememt is one
if (l==0) return 0;
if (METAKERNEL) ++l; // Metakernel support
stkp = Read5(DSKTOP) + (l-1)*5;
return Read5(stkp);
}
@ -256,6 +288,7 @@ VOID RPL_Replace(DWORD n)
DWORD stkp;
stkp = Read5(DSKTOP);
if (METAKERNEL) stkp+=5; // Metakernel support
Write5(stkp,n);
return;
}
@ -270,8 +303,17 @@ VOID RPL_Push(DWORD n)
avmem--; // fetch memory
Write5(AVMEM,avmem); // save new amount of free memory
stkp = Read5(DSKTOP); // get pointer to stack level 1
if (METAKERNEL) // Metakernel running ?
{
Write5(stkp-5,Read5(stkp)); // copy object pointer of stack level 1 to new stack level 1 entry
Write5(stkp,n); // save pointer to new object on stack level 2
stkp-=5; // fetch new stack entry
}
else
{
stkp-=5; // fetch new stack entry
Write5(stkp,n); // save pointer to new object on stack level 1
}
Write5(DSKTOP,stkp); // save new pointer to stack level 1
return;
}

View file

@ -8,34 +8,32 @@
*/
#include "pch.h"
#include "Emu48.h"
#include "io.h" // 24.10.99 cg, renamed from Serial.h
#include "io.h"
#define INTERRUPT ((void)(Chipset.SoftInt=TRUE,bInterrupt=TRUE))
// 25.10.99 cg, new, state of USRQ
// state of USRQ
#define NINT2ERBZ ((Chipset.IORam[IOC] & ERBZ) != 0 && (Chipset.IORam[RCS] & RBZ) != 0)
#define NINT2ERBF ((Chipset.IORam[IOC] & ERBF) != 0 && (Chipset.IORam[RCS] & RBF) != 0)
#define NINT2ETBE ((Chipset.IORam[IOC] & ETBE) != 0 && (Chipset.IORam[TCS] & TBF) == 0)
#define NINT2USRQ (NINT2ERBZ || NINT2ERBF || NINT2ETBE)
static OVERLAPPED os = { 0 };
static HANDLE hComm = NULL;
static HANDLE hCThread = NULL;
static DWORD lSerialThreadId = 0;
static BOOL bReading = TRUE;
static WORD wPort = PORT_CLOSE;
static BOOL bReading;
static BYTE cBuffer[128];
static WORD nRp;
static DWORD dwBytesRead = 0L;
// static CRITICAL_SECTION csRecv; // 24.10.99 cg, moved to main function
static DWORD WINAPI SerialThread(LPVOID pParam)
{
DWORD dwEvent;
SetCommMask(hComm,EV_RXCHAR); // event on RX
bReading = TRUE; // flag for SerialThread started
while (bReading)
{
_ASSERT(hComm != NULL);
@ -83,16 +81,16 @@ VOID CommOpen(LPSTR strWirePort,LPSTR strIrPort)
if(hComm != INVALID_HANDLE_VALUE)
{
// InitializeCriticalSection(&csRecv);
wPort = (Chipset.IORam[IR_CTRL] & EIRU) ? PORT_IR : PORT_WIRE;
SetCommTimeouts(hComm,&CommTimeouts);
CommSetBaud();
// set event RXD handler
bReading = TRUE;
bReading = FALSE;
SetCommMask(hComm,EV_RXCHAR); // event on RX
hCThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&SerialThread,NULL,0,&lSerialThreadId);
_ASSERT(lSerialThreadId);
while (!bReading) Sleep(0); // wait for SerialThread started
}
else
hComm = NULL;
@ -112,6 +110,7 @@ VOID CommClose(VOID)
{
if (hComm != NULL) // port open
{
Sleep(25); // workaround to fix problems with some Kermit server
bReading = FALSE; // kill read thread
SetCommMask(hComm,0L); // clear all events and force WaitCommEvent to return
while (lSerialThreadId != 0) Sleep(0); // wait for termination
@ -120,7 +119,6 @@ VOID CommClose(VOID)
#if defined DEBUG_SERIAL
OutputDebugString("COM port closed.\n");
#endif
// DeleteCriticalSection(&csRecv);
wPort = PORT_CLOSE;
}
return;
@ -165,7 +163,7 @@ VOID CommSetBaud(VOID)
return;
}
VOID UpdateUSRQ(VOID) // 25.10.99 cg, new, USRQ handling
VOID UpdateUSRQ(VOID) // USRQ handling
{
IOBit(SRQ1,USRQ,NINT2USRQ); // update USRQ bit
return;
@ -173,6 +171,7 @@ VOID UpdateUSRQ(VOID) // 25.10.99 cg, new, USRQ handling
VOID CommTransmit(VOID)
{
OVERLAPPED os = { 0 };
DWORD dwWritten;
BYTE tbr = (Chipset.IORam[TBR_MSB] << 4) | Chipset.IORam[TBR_LSB];
@ -188,7 +187,6 @@ VOID CommTransmit(VOID)
}
#endif
// 23.10.99 cg, bugfix, add serial loopback support
if (Chipset.IORam[TCS] & LPB) // is loopback bit set
{
cBuffer[nRp+dwBytesRead] = tbr; // save character in receive buffer
@ -196,13 +194,17 @@ VOID CommTransmit(VOID)
CommReceive(); // receive byte available
}
// 23.10.99 cg, end of implementation
if (hComm != NULL) // com port open
{
os.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
WriteFile(hComm,(LPCVOID) &tbr,1,&dwWritten,&os);
GetOverlappedResult(hComm,&os,&dwWritten,TRUE);
CloseHandle(os.hEvent);
}
Chipset.IORam[TCS] &= (~TBF); // clear transmit buffer
UpdateUSRQ(); // 25.10.99 cg, bugfix, update USRQ bit
UpdateUSRQ(); // update USRQ bit
if (Chipset.IORam[IOC] & ETBE) // interrupt on transmit buffer empty
INTERRUPT;
return;
@ -210,6 +212,8 @@ VOID CommTransmit(VOID)
VOID CommReceive(VOID)
{
OVERLAPPED os = { 0 };
if (!(Chipset.IORam[IOC] & SON)) // UART off
{
dwBytesRead = 0L; // no bytes received
@ -222,7 +226,7 @@ VOID CommReceive(VOID)
if (Chipset.IORam[RCS] & RBF) // receive buffer full
break;
// 23.10.99 cg, bugfix, 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(ReadFile(hComm,&cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE)
@ -251,7 +255,7 @@ VOID CommReceive(VOID)
--dwBytesRead;
Chipset.IORam[RCS] |= RBF; // receive buffer full
UpdateUSRQ(); // 25.10.99 cg, bugfix, update USRQ bit
UpdateUSRQ(); // update USRQ bit
if (Chipset.IORam[IOC] & ERBF) // interrupt on recv buffer full
INTERRUPT;
}

View file

@ -9,6 +9,7 @@
*/
#include "pch.h"
#include "Emu48.h"
#include "i28f160.h"
#define EMU48_INI "Emu48.ini"
@ -31,14 +32,19 @@ VOID ReadSettings(VOID)
GetPrivateProfileString("Port2","Filename","SHARED.BIN",szPort2Filename,sizeof(szPort2Filename),EMU48_INI);
// KML
bAlwaysDisplayLog = GetPrivateProfileInt("KML","AlwaysDisplayLog",bAlwaysDisplayLog,EMU48_INI);
// Disassebler
disassembler_mode = GetPrivateProfileInt("Disassembler","Mnemonics",disassembler_mode,EMU48_INI);
// Emulator
bRealSpeed = GetPrivateProfileInt("Emulator","RealSpeed",0,EMU48_INI);
dwSXCycles = GetPrivateProfileInt("Emulator","SXCycles",82,EMU48_INI);
dwGXCycles = GetPrivateProfileInt("Emulator","GXCycles",123,EMU48_INI);
dwSXCycles = GetPrivateProfileInt("Emulator","SXCycles",dwSXCycles,EMU48_INI);
dwGXCycles = GetPrivateProfileInt("Emulator","GXCycles",dwGXCycles,EMU48_INI);
SetSpeed(bRealSpeed); // set speed
// Serial
GetPrivateProfileString("Serial","Wire",NO_SERIAL,szSerialWire,sizeof(szSerialWire),EMU48_INI);
GetPrivateProfileString("Serial","Ir",NO_SERIAL,szSerialIr,sizeof(szSerialIr),EMU48_INI);
// ROM
bRomWriteable = GetPrivateProfileInt("ROM","Writeable",TRUE,EMU48_INI);
bWP = GetPrivateProfileInt("ROM","WP#",FALSE,EMU48_INI);
return;
}
@ -53,6 +59,8 @@ VOID WriteSettings(VOID)
WritePrivateProfileString("Port2","Filename",szPort2Filename,EMU48_INI);
// KML
WritePrivateProfileInt("KML","AlwaysDisplayLog",bAlwaysDisplayLog,EMU48_INI);
// Disassebler
WritePrivateProfileInt("Disassembler","Mnemonics",disassembler_mode,EMU48_INI);
// Emulator
WritePrivateProfileInt("Emulator","RealSpeed",bRealSpeed,EMU48_INI);
WritePrivateProfileInt("Emulator","SXCycles",dwSXCycles,EMU48_INI);
@ -60,6 +68,8 @@ VOID WriteSettings(VOID)
// Serial
WritePrivateProfileString("Serial","Wire",szSerialWire,EMU48_INI);
WritePrivateProfileString("Serial","Ir",szSerialIr,EMU48_INI);
// ROM
WritePrivateProfileInt("ROM","Writeable",bRomWriteable,EMU48_INI);
return;
}

View file

@ -8,7 +8,7 @@
*/
#include "pch.h"
#include "Emu48.h"
#include "io.h" // 24.10.99 cg, new, I/O definitions
#include "io.h" // I/O definitions
#define AUTO_OFF 10 // Time in minutes for 'auto off'
@ -30,13 +30,15 @@ static BOOL bOutRange = FALSE; // flag if timer value out of range
static UINT uT1TimerId = 0;
static UINT uT2TimerId = 0;
static BOOL bNINT2T1 = FALSE; // 24.10.99 cg, new, state of NINT2 affected form Timer1
static BOOL bNINT2T2 = FALSE; // 24.10.99 cg, new, state of NINT2 affected form Timer2
static BOOL bNINT2T1 = FALSE; // state of NINT2 affected from timer1
static BOOL bNINT2T2 = FALSE; // state of NINT2 affected from timer2
static BOOL bAccurateTimer; // flag if accurate timer is used
static LARGE_INTEGER lT2Ref; // counter value at timer2 start
static TIMECAPS tc; // timer information
static BOOL bT2Val; // last access values valid
static __inline MAX(int a, int b) {return (a>b)?a:b;}
static void CALLBACK TimeProc(UINT uEventId, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
@ -46,22 +48,51 @@ static DWORD CalcT2(VOID) // calculate timer2 value
DWORD dwT2 = Chipset.t2; // get value from chipset
if (bStarted) // timer2 running
{
static DWORD dwT2Ref; // timer2 value at last timer2 access
static DWORD dwT2Cyc; // cpu cycle counter at last timer2 access
LARGE_INTEGER lT2Act;
DWORD dwT2Dif;
QueryPerformanceCounter(&lT2Act); // actual time
// calculate ticks since reference point
dwT2 -= (DWORD)
(((lT2Act.QuadPart - lT2Ref.QuadPart) * T2_FREQ)
/ lFreq.QuadPart);
// 2nd timer call in a time 32ms time frame
dwT2Dif = dwT2Ref - dwT2;
if (bT2Val && dwT2Dif > 0x01 && dwT2Dif <= 0x100)
{
#define CYC_PER_TICK (2 * 72)
DWORD dwT2Ticks = ((DWORD) (Chipset.cycles & 0xFFFFFFFF) - dwT2Cyc) / CYC_PER_TICK;
if (dwT2Ticks >= dwT2Dif)
{
dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
}
else
{
dwT2 = dwT2Ref - dwT2Ticks;
dwT2Cyc += dwT2Ticks * CYC_PER_TICK;
}
#undef CYC_PER_TICK
}
else
{
dwT2Cyc = (DWORD) (Chipset.cycles & 0xFFFFFFFF);
}
dwT2Ref = dwT2;
bT2Val = TRUE; // access values valid
}
return dwT2;
}
static VOID CheckT1(BYTE nT1)
{
// 24.10.99 cg, bugfix, implementation of TSRQ
// implementation of TSRQ
bNINT2T1 = (Chipset.IORam[TIMER1_CTRL]&INTR) != 0 && (nT1&8) != 0;
IOBit(SRQ1,TSRQ,bNINT2T1 || bNINT2T2);
// 24.10.99 cg, end of implementation
if ((nT1&8) == 0) // timer1 MSB not set
{
@ -94,10 +125,9 @@ static VOID CheckT1(BYTE nT1)
static VOID CheckT2(DWORD dwT2)
{
// 24.10.99 cg, bugfix, implementation of TSRQ
// implementation of TSRQ
bNINT2T2 = (Chipset.IORam[TIMER2_CTRL]&INTR) != 0 && (dwT2&0x80000000) != 0;
IOBit(SRQ1,TSRQ,bNINT2T1 || bNINT2T2);
// 24.10.99 cg, end of implementation
if ((dwT2&0x80000000) == 0) // timer2 MSB not set
{
@ -134,6 +164,7 @@ static VOID RescheduleT2(BOOL bRefPoint)
_ASSERT(uT2TimerId == 0); // timer2 must stopped
if (bRefPoint) // save reference time
{
bT2Val = FALSE; // init thread interrupt workaround
QueryPerformanceCounter(&lT2Ref); // time of corresponding Chipset.t2 value
uDelay = Chipset.t2; // timer value for delay
}
@ -273,10 +304,9 @@ VOID StartTimers(VOID)
if (Chipset.IORam[TIMER2_CTRL]&RUN) // start timer1 and timer2 ?
{
bStarted = TRUE; // flag timer running
// 24.10.99 cg, new, initialisation of NINT2 lines
// initialisation of NINT2 lines
bNINT2T1 = (Chipset.IORam[TIMER1_CTRL]&INTR) != 0 && (Chipset.t1 & 8) != 0;
bNINT2T2 = (Chipset.IORam[TIMER2_CTRL]&INTR) != 0 && (Chipset.t2 & 0x80000000) != 0;
// 24.10.99 cg, end of initialisation
// set timer resolution to 1 ms, if failed don't use "Accurate timer"
bAccurateTimer = (timeBeginPeriod(1) == TIMERR_NOERROR);
timeGetDevCaps(&tc,sizeof(tc)); // get timer resolution

View file

@ -7,15 +7,21 @@
*
*/
#define SWORD SHORT // 09.12.99 cg, new, signed 16 Bit variable
#define QWORD ULONGLONG // 22.11.99 cg, new, unsigned 64 Bit variable
// HST bits
#define XM 1
#define SB 2
#define SR 4
#define MP 8
#define SWORD SHORT // signed 16 Bit variable
#define QWORD ULONGLONG // unsigned 64 Bit variable
#define CHIPSET Chipset_t
typedef struct
{
SWORD nPosX; // 09.12.99 cg, bugfix, is a signed number
SWORD nPosY; // 09.12.99 cg, bugfix, is a signed number
BYTE type;
SWORD nPosX; // position of window
SWORD nPosY;
BYTE type; // calculator type
DWORD Port0Size; // real size of module in KB
DWORD Port1Size; // real size of module in KB
@ -53,14 +59,17 @@ typedef struct
WORD crc;
WORD wPort2Crc; // fingerprint of port2
WORD wRomCrc; // 20.11.99 cg, new, fingerprint of ROM
// QWORD cycles; // 22.11.99 cg, changed, oscillator cycles
DWORD cycles; // 22.11.99 cg, moved, oscillator cycles
DWORD cycles_reserved; // 22.11.99 cg, reserved for MSB of oscillator cycles
DWORD dwKdnCycles; // 22.11.99 cg, moved, cpu cycles at start of 1ms key handler
WORD wRomCrc; // fingerprint of ROM
#if defined _USRDLL // DLL version
QWORD cycles; // oscillator cycles
#else // EXE version
DWORD cycles; // oscillator cycles
DWORD cycles_reserved; // reserved for MSB of oscillator cycles
#endif
DWORD dwKdnCycles; // cpu cycles at start of 1ms key handler
UINT Bank_FF; // save state of HP48GX port2 or state of HP49G ROM FF
UINT Port2_NBanks; // not used
UINT FlashRomState; // WSM state of flash memory (unused)
BYTE cards_status;
BYTE IORam[64]; // I/O hardware register
UINT IOBase; // address of I/O modules page
@ -74,7 +83,7 @@ typedef struct
BYTE t1;
DWORD t2;
BOOL bShutdnWake; // 20.11.99 cg, moved, flag for wake up from SHUTDN mode
BOOL bShutdnWake; // flag for wake up from SHUTDN mode
BYTE Keyboard_Row[9];
WORD IR15X;