Merge branch 'master' into sdl4

# Conflicts:
#	source/CMakeLists.txt
#	source/frontends/ncurses/main.cpp
#	source/frontends/ncurses/resources.cpp
This commit is contained in:
Andrea Odetti 2020-10-09 09:17:55 +01:00
commit ae0194d5b1
185 changed files with 6641 additions and 3485 deletions

View file

@ -70,7 +70,7 @@
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="3"
DisableSpecificWarnings="4819;4995;4996"
DisableSpecificWarnings="4482;4819;4995;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@ -169,7 +169,7 @@
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"
DisableSpecificWarnings="4819;4995;4996"
DisableSpecificWarnings="4482;4819;4995;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@ -826,11 +826,11 @@
>
</File>
<File
RelativePath=".\source\CPU\cpu65d02.h"
RelativePath=".\source\CPU\cpu_general.inl"
>
</File>
<File
RelativePath=".\source\CPU\cpu_general.inl"
RelativePath=".\source\CPU\cpu_heatmap.inl"
>
</File>
<File
@ -1087,6 +1087,14 @@
RelativePath=".\resource\Apple2.rom"
>
</File>
<File
RelativePath=".\resource\Apple2_JPlus.rom"
>
</File>
<File
RelativePath=".\resource\Apple2_JPlus_Video.rom"
>
</File>
<File
RelativePath=".\resource\Apple2_Plus.rom"
>
@ -1177,6 +1185,10 @@
RelativePath="RESOURCE\DISK.ICO"
>
</File>
<File
RelativePath=".\resource\Disk2-13sector.rom"
>
</File>
<File
RelativePath=".\resource\Disk2.rom"
>

View file

@ -48,7 +48,6 @@
<ClInclude Include="source\CPU.h" />
<ClInclude Include="source\CPU\cpu6502.h" />
<ClInclude Include="source\CPU\cpu65C02.h" />
<ClInclude Include="source\CPU\cpu65d02.h" />
<ClInclude Include="source\Debugger\Debug.h" />
<ClInclude Include="source\Debugger\DebugDefs.h" />
<ClInclude Include="source\Debugger\Debugger_Assembler.h" />

View file

@ -237,9 +237,6 @@
<ClInclude Include="source\CPU\cpu6502.h">
<Filter>Source Files\CPU</Filter>
</ClInclude>
<ClInclude Include="source\CPU\cpu65d02.h">
<Filter>Source Files\CPU</Filter>
</ClInclude>
<ClInclude Include="source\CPU\cpu65C02.h">
<Filter>Source Files\CPU</Filter>
</ClInclude>

View file

@ -48,7 +48,6 @@
<ClInclude Include="source\CPU.h" />
<ClInclude Include="source\CPU\cpu6502.h" />
<ClInclude Include="source\CPU\cpu65C02.h" />
<ClInclude Include="source\CPU\cpu65d02.h" />
<ClInclude Include="source\Debugger\Debug.h" />
<ClInclude Include="source\Debugger\DebugDefs.h" />
<ClInclude Include="source\Debugger\Debugger_Assembler.h" />

View file

@ -237,9 +237,6 @@
<ClInclude Include="source\CPU\cpu6502.h">
<Filter>Source Files\CPU</Filter>
</ClInclude>
<ClInclude Include="source\CPU\cpu65d02.h">
<Filter>Source Files\CPU</Filter>
</ClInclude>
<ClInclude Include="source\CPU\cpu65C02.h">
<Filter>Source Files\CPU</Filter>
</ClInclude>

View file

@ -48,7 +48,6 @@
<ClInclude Include="source\CPU.h" />
<ClInclude Include="source\CPU\cpu6502.h" />
<ClInclude Include="source\CPU\cpu65C02.h" />
<ClInclude Include="source\CPU\cpu65d02.h" />
<ClInclude Include="source\Debugger\Debug.h" />
<ClInclude Include="source\Debugger\DebugDefs.h" />
<ClInclude Include="source\Debugger\Debugger_Assembler.h" />

View file

@ -237,9 +237,6 @@
<ClInclude Include="source\CPU\cpu6502.h">
<Filter>Source Files\CPU</Filter>
</ClInclude>
<ClInclude Include="source\CPU\cpu65d02.h">
<Filter>Source Files\CPU</Filter>
</ClInclude>
<ClInclude Include="source\CPU\cpu65C02.h">
<Filter>Source Files\CPU</Filter>
</ClInclude>

View file

@ -48,7 +48,6 @@
<ClInclude Include="source\CPU.h" />
<ClInclude Include="source\CPU\cpu6502.h" />
<ClInclude Include="source\CPU\cpu65C02.h" />
<ClInclude Include="source\CPU\cpu65d02.h" />
<ClInclude Include="source\Debugger\Debug.h" />
<ClInclude Include="source\Debugger\DebugDefs.h" />
<ClInclude Include="source\Debugger\Debugger_Assembler.h" />
@ -237,6 +236,8 @@
<None Include="resource\Apple2e.rom" />
<None Include="resource\Apple2e_Enhanced.rom" />
<None Include="resource\Apple2_Plus.rom" />
<None Include="resource\Base64A.rom" />
<None Include="resource\Base64A_German_Video.rom" />
<None Include="resource\DISK2.rom" />
<None Include="resource\Freezes_Non-autostart_F8_Rom.rom" />
<None Include="resource\Hddrvr.bin" />
@ -298,6 +299,7 @@
<Image Include="resource\LED_CAPS_ON_P8.BMP" />
<Image Include="resource\RUN.BMP" />
<Image Include="resource\RUN3000E.bmp" />
<Image Include="resource\RUNBASE64A.BMP" />
<Image Include="resource\RUNP.BMP" />
<Image Include="resource\SETUP.BMP" />
</ItemGroup>
@ -372,7 +374,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;YAML_DECLARE_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>source;source\cpu;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
@ -399,7 +401,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;YAML_DECLARE_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>source;source\cpu;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
@ -427,7 +429,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;YAML_DECLARE_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>source;source\cpu;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
@ -459,7 +461,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;YAML_DECLARE_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>source\cpu;source\emulator;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>source;source\cpu;source\debugger;zlib;zip_lib;libyaml\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>

View file

@ -237,9 +237,6 @@
<ClInclude Include="source\CPU\cpu6502.h">
<Filter>Source Files\CPU</Filter>
</ClInclude>
<ClInclude Include="source\CPU\cpu65d02.h">
<Filter>Source Files\CPU</Filter>
</ClInclude>
<ClInclude Include="source\CPU\cpu65C02.h">
<Filter>Source Files\CPU</Filter>
</ClInclude>
@ -593,6 +590,9 @@
<Image Include="resource\RUN3000E.bmp">
<Filter>Resource Files</Filter>
</Image>
<Image Include="resource\RUNBASE64A.BMP">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<None Include="resource\Apple2.rom">
@ -652,6 +652,12 @@
<None Include="resource\TKClock.rom">
<Filter>Resource Files</Filter>
</None>
<None Include="resource\Base64A.rom">
<Filter>Resource Files</Filter>
</None>
<None Include="resource\Base64A_German_Video.rom">
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Text Include="docs\CodingConventions.txt">

View file

@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.9)
include(CPack)
project(applewin)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-multichar -Werror=return-type")

View file

@ -4,9 +4,9 @@ AppleWin
Apple II emulator for Windows
Download latest (stable) release: [AppleWin v1.29.0.0](https://github.com/AppleWin/AppleWin/releases/download/v1.29.0.0/AppleWin1.29.0.0.zip)
Download latest (stable) release: [AppleWin v1.29.13.0](https://github.com/AppleWin/AppleWin/releases/download/v1.29.13.0/AppleWin1.29.13.0.zip)
Release Notes: [v1.29.0.0](https://github.com/AppleWin/AppleWin/releases/tag/v1.29.0.0)
Release Notes: [v1.29.13.0](https://github.com/AppleWin/AppleWin/releases/tag/v1.29.13.0)
Building
@ -26,8 +26,8 @@ Please report [new issues](https://github.com/AppleWin/AppleWin/issues/new)
Previous Versions
=================
* [AppleWin v1.28.0.0](https://github.com/AppleWin/AppleWin/releases/download/v1.28.0.0/AppleWin1.28.0.0.zip)
* [AppleWin v1.28.8.0](https://github.com/AppleWin/AppleWin/releases/tag/v1.28.8.0)
Last pre-NTSC change:
* [AppleWin v1.25.0.4](https://github.com/AppleWin/AppleWin/releases/download/v1.25.0.4/AppleWin1.25.0.4.zip)
* [AppleWin v1.25.0.4](https://github.com/AppleWin/AppleWin/releases/tag/v1.25.0.4)

View file

@ -121,11 +121,14 @@ C017 RDC3ROM
C018 RD80STORE
C019 RDVBLBAR
C01A RDTEXT
C01B RDMIXED
C01C RDPAGE2
C01D RDHIRES
C01E ALTCHARSET
C01F RD80COL
C020 TAPEOUT
C030 SPKR
C040 STROBE
C050 TXTCLR
C051 TXTSET
C052 MIXCLR
@ -145,18 +148,48 @@ C05F CLRAN3
C060 TAPEIN
C061 BUTNO
C062 BUTN1
C063 BUTN2
C064 PADDL0
C065 PADDL1
C066 PADDL2
C067 PADDL3
C070 PTRIG
C080 STEPPER
C081 ROMIN
; Slot-0: Language Card
C080 LCRAMIN2
C081 ROMIN2
C082 LCROMIN2
C083 LCBANK2
C08A ENABLE1
C08B LCBANK1/ENABLE2
C08C DATASTROBE
C08D LOADLATCH
C08E SETREADMODE
C08E WRITEPROT
C08F SETWRITEMODE
C084 LCRAMIN2_
C085 ROMIN2_
C086 LCROMIN2_
C087 LCBANK2_
C088 LCRAMIN1
C089 ROMIN1
C08A LCROMIN1
C08B LCBANK1
C08C LCRAMIN1_
C08D ROMIN1_
C08E LCROMIN1_
C08F LCBANK1_
; Slot-6: DiskII interface
C0E0 DRV_P0_OFF
C0E1 DRV_P0_ON
C0E2 DRV_P1_OFF
C0E3 DRV_P1_ON
C0E4 DRV_P2_OFF
C0E5 DRV_P2_ON
C0E6 DRV_P3_OFF
C0E7 DRV_P3_ON
C0E8 DRV_OFF
C0E9 DRV_ON
C0EA DRV_SEL1
C0EB DRV_SEL2
C0EC DRV_SHIFT
C0ED DRV_LOAD
C0EE DRV_READ
C0EF DRV_WRITE
; Firmware
; Renamed due to ROM name collision

View file

@ -8,6 +8,82 @@ https://github.com/AppleWin/AppleWin/issues/new
Tom Charlesworth
1.29.14.0 - 17 Aug 2020
-----------------------
. [Change #822] Updated Uthernet card support to use Npcap for Win10.
. [Change #806] Added support for 'Base 64A' - a Taiwanese Apple II clone.
. [Change #763] Support for PAL(50Hz) killing color-burst during TEXT video mode.
- When 50Hz, then AppleWin's window title changes to "Color (PAL Monitor)" instead of "Color (NTSC Monitor)"
. [Change #781] Loading a large save-state takes some time - added a busy indicator.
. [Change #139] NIB disk image: added warning if any track's first D5-nibble triple isn't an address prologue.
. [Bug #824] Fixed a regression in multi-zip support (introduced at 1.29.10.0).
. [Bug #820] Fixed a GDI Object leak (occurring when accessing the Disk II with AppleWin minimised).
. [Bug #813] Mockingboard playback looping after entering debugger then configuration.
. [Bug #809] Fixed a memory leak.
. [Bug #801] Wrong timing with LSR abs,X / ROR abs,X / ROL abs,X for the 6502 CPU.
. [Bug #796] Fix for 'IRQ occurring on last cycle of opcode' not always true.
. [Bug #751] No-Slot Clock running and power-cycle can causes lock-up on power-cycle.
- NSC state persisted to save-state.
- added a new switch '-no-nsc' to configure Apple II without an NSC.
. [Bug #663, #691] Fixes for image loading switches (-d1,-d2,-h1,-h2,-s5d1,-s5d2):
- support relative paths (#663).
- updated the current directory with the path for each loaded image (#663) & when saving state (#691).
- added a new switch '-current-dir <path>' to guarantee the current dir after using image loading switches.
. [Bug #52] Fixed the 6502/65C02 false-read of 6522 issue for Willy Byte!
. [PR #800] Improved debugger's rendering speed for PrintGlyph().
1.29.13.0 - 31 May 2020
-----------------------
. [Bug #790] Fixed regression for -d1,-d2 & -s7-empty-on-exit (introduced at 1.29.7.0).
. [Change #787] Debugger: Extended 'cycles part' command to do timings relative to a user-specified base.
. [Change #783] Debugger: Extended 'tf' command to include cycle count.
. [Change #720] Debugger: Added more symbols to APPLE2E.SYM.
- NB. LC ($C08n) symbols are now correct for the LC, so 'LDA $C08C,X' will disassemble as 'LDA LCRAMIN1_,X'
instead of 'LDA DATASTROBE,X'. So now perhaps less helpful when stepping Disk II code.
. [PR #785] Debugger: Improvements to Bookmarks.
- AppleWin.chm: Added debugger help about Bookmarks.
. Fixed occasional speaker clicks in full-speed mode.
1.29.12.0 - 26 Apr 2020
-----------------------
. [PR #757] Allow use of an INI-file for configuration instead of the Registry (fixes #709).
- new command line switch: -conf <INI-file>
. [Change #773] Added Apple II J-Plus support.
. [Bug #778] Fixed for when Joystick(s) are disabled.
. [Bug #777] Fixed Phasor speech (SSI263) to match Mockingboard (when in Mockingboard mode).
- fixes: #698 (Rescue Raiders), #753 (Bejeweled).
- also improvements to Phasor card's native Phasor mode.
. [PR #775] Debugger: Fixed so that hitting "=" in the debugger sets PC to the current cursor address.
1.29.11.0 - 27 Mar 2020
-----------------------
. [Change #771] Added new command line switch to load custom ROM: -rom <file>.
- Supports 12KiB (at $D000) and 16KiB (at $C000) rom files.
. [Bug #765] Lancaster (Total Replay) hangs when starting second game.
. [Change #734] DiskII controller card: support 13-sector firmware.
- The card auto-selects the firmware based on the .woz (v2 or higher) image properties.
- Only change the firmware at reset/reboot to avoid changing whilst running in $C6xx space!
- Fixes 'The Best of MUSE' & 'MicroChess 2.0' (#732)
1.29.10.0 - 13 Feb 2020
-----------------------
. [PR #756] Write support for WOZ1/WOZ2 images.
- Fixes titles that need write support (see: #686, #704, #705).
- Allow creation of a blank (WOZ2) image (see AppleWin.chm: 'Creating Disk Images').
- multi-file zip support extended to scan for the first valid image.
- useful for most woz-a-day multi-file zips which have at least 2 entries and previously needed unzipping.
. NB. files in multi-file zips are still write-protected (same for all image types, not just woz).
1.29.9.0 - 26 Jan 2020
----------------------
. [Bug #750] Fixed double-clicking a registered file-type issue (regression introduced at 1.29.8.0).
. [Bug #752] Fixed Ctrl+Alt+Break wasn't emulating CTRL+OA+RESET (regression introduced at 1.29.8.0).
1.29.8.0 - 19 Jan 2020
----------------------
@ -15,7 +91,7 @@ Tom Charlesworth
. [Bug #748] DiskII: data latch returns a rand() value when no disk is in drive.
. [Bug #746] Debugger: correctly repaint Apple II screen when showing it from debugger.
. [Bug #745] WOZ: Support for large tracks.
. [Bug #743] Added new command line switches:
. [Change #743] Added new command line switches:
-left-alt-control-buttons : left-ctrl=button0, left-alt=button1
-right-alt-control-buttons : right-alt=button0, right-ctrl=button1
-swap-buttons : for swapping buttons 0 & 1

View file

@ -1,4 +1,11 @@
/*
2.9.1.0 Added: Bookmarks now have their own indicator (a number with a box around it) and replace the ":" seperator. Updated Debug_Font.bmp
.18 Fixed: Resetting bookmarks wasn't setting the total bookmarks back to zero.
.17 Fixed: If all bookmarks were used then setting a new one wouldn't update an existing one to the new address.
.16 Fixed: Replacing an existing bookmark incorrectly increased the total bookmark count.
.15 Cleanup: HELP CALC examples and See also.
.14 Fixed: HELP JSR wasn't color-coding syntax.
.13 Added: PROFILE LIST now shows how many clock cycles were executed.

View file

@ -98,3 +98,26 @@ N/A
5. Clean & build:
devenv AppleWinExpress2008.sln /clean
cov-build --dir cov-int devenv AppleWinExpress2008.sln /build release
How to disable F12 so it doesn't trigger a breakpoint
=====================================================
When running AppleWin from Visual Studio (eg. F5), then F12 will trigger a breakpoint.
This is undesirable, since F12 is used to load a save-state.
AppleWin does also support CTRL+F12 to load a save-state too (for this very reason), but it's possible to disable F12 triggering the breakpoint.
Background:
F12 is the OS's default UserDebuggerHotKey:
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc786263(v=ws.10)
Fix:
. Change this Registry key: "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug" -> UserDebuggerHotKey to 0x07 (*)
. And restart the PC for it to take effect.
(*) Where 0x07 = Undefined
(See: https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes)

View file

@ -1,165 +0,0 @@
Setting up CVS for AppleWin
Revision 3
+ Added pass-phrase, pageant, putty info
Revision 2
+ Added diff/merge
This is the step-by-step tutorial in getting CVS setup for AppleWin.
There are a few steps, but each one is quick and easy to do.
1. Create an account BerliOS
http://developer.berlios.de/
2. Download and install TortoiseCVS.
a) http://www.tortoisecvs.org/
b) Reboot Windows (Grr...)
You can find a tutorial on how to use TortoiseCVS here:
http://cedric.babault.free.fr/TortoiseCVSDoc/UserGuide_en.html
If you don't want to use TortoiseCVs, you have a few options:
i) WinCVS (which also has a Mac OS X port, called MacCVS)
http://www.wincvs.org/
ii) cvsnt:
http://www.march-hare.com/cvspro/
3. Generate a SSH2 key, using "puttygen"
Recommend: using a pass-phrase
Recommend: using comment:
<username>@shell.berlios.de
If you installed TortoiseCVS, you will notice it includes an older version of puttygen.exe:
i.e.
\Program Files\TortoiseCVS\puttygen.exe
\Programs\VersionControl\TortoiseCVS\puttygen.exe
You can find the latest PuTTY here:
http://www.chiark.greenend.org.uk/~sgtatham/putty/
And depending on where you installed it to:
C:\Program Files\Putty\puttgygen.exe
P:\Programs\Util\Shell\PuTTY\puttygen.exe
4. In your home directory, make a sub-directory called: .ssh
i.e.
C:\Document and Settings\<username>\.ssh
\users\<username>\.ssh
5. Save your public key into your home directory
i.e.
<username>\.ssh\identity.pub
6. Save your private key into your home directory
i.e.
<username>\.ssh\identity
7. Upload your Public SSH key to BerliOS
a) http://developer.berlios.de/
b) Account Options
c) Edit Keys (at bottom of webpage)
d) copy from puttygen, and paste into web form
e) Verify: CVS/SVN/SSH Shared Keys: 1 <-- was zero
You will have to use your pass-phrase (may be up to a few hours),
until BerliOS recognizes the uploaded ssh2 key.
8. Using Windows Explorer, navigate to the parent directory where you will download AppleWin
i.e.
<username>\Projects\
P:\<username>\Projects\
9. (Optional) Specify a home folder.
If you have TortoiseCVS installed:
a) right Click on any directory
b) select CVS
c) Preferences.
TortoiseCVS should appear.
d) Select "Advanced" Tab
e) Home Folder: uncheck, always recalculate home folder
f) Enter your home directory, for "Custom Home folder"
10. (Optional) Set CVS environment variable: CVS_RSH
If you are using TortoiseCVS you can skip this step.
(TortoiseCVS uses 'plink' -- command line wrapper for ssh.)
For other cvs clients, you may need to set CVS_RSH:
To set the environment variable "CVS_RSH" to "ssh" (without the quotes):
Right-click the My Computer icon on your desktop, Properties, Advanced, Environment variables button.
11. Setting CVSROOT.
If you use TortoiseCVS
a) right click on the AppleWin Parent directory (the folder where AppleWin will be downloaded to)
b) CVS Checkout,
and set CVSROOT to:
:ext:<username>@cvs.applewin.berlios.de:/cvsroot/applewin
c) set Module (case sensitive!) to:
AppleWin
d) select OK, and wait to fetch the complete AppleWin directory.
Troubleshooting:
* You can delete "Previous CVSROOTs":
Right click on folder, CVS, Checkout, select appropiate, delete key
You will have to press OK for the old entries to be deleted.
When you do, a fetch attempt will also be made.
* If you enter the wrong init param, you may have to rename / delete your local AppleWin folder!
* If you still have problems, you may have to remove the SSH (host) entry from the registry:
i.e.
HKEY_CURRENT_USER\Software\SimonTatham\Putty\SshHostKeys
* You shouldn't have to edit, but if you need to, this CVS config file is plain text:
AppleWin\CVS\Root
If you use another cvs client, such as WinCVS, or CVSNT, this may work:
:ssh:<username>@cvs.applewin.berlios.de:/cvsroot/applewin
12. You can download a free source-code 'diff' & 'merge' app for win32
(which integrates into TortoiseCVS) from here:
http://winmerge.sourceforge.net/
Alternatively you can download a free source-code 'diff' for Win32 here:
http://www.prestosoft.com/ps.asp?page=edp_examdiff
13. Start hacking the code!
14. Automatically use your SSH2 key, instead of manually typing your pass-phrase.
If you generated a SSH2 private/public key, and have uploaded it to BerliOS,
you can tell TortoiseCVS to use your SSH2 key-pair instead of asking for your pass-phrase on every CVS action.
If you have PuTTY (pageant) installed:
a) Run pageant
C:\Program Files\PuTTY\pageant.exe
If you get a configuration error when starting pageant.exe on Win XP, this provides a workaround:
http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/xp-wont-run
b) Right Click on pageant in the system tool bar
c) Add key
d) Select your private key
<username>\.ssh\identity.ppk
If you have TortoiseCVS installed:
a) right Click on any directory
b) select CVS
c) Preferences.
TortoiseCVS should appear.
d) Select "Tools" Tab
e) To the SSH paramaters, add: -2

View file

@ -1,28 +0,0 @@
Setting up SVN for AppleWin
===========================
(This doc assumes you started with cvs_setup.txt)
1. Download and install TortoiseSVN.
a) http://tortoisesvn.sourceforge.net/
b) Reboot Windows (Grr...)
==========
Start by reading the TortoiseSVN help... or just dive right in :)
To browse the svn repository using:
a) Web browser (WebSVN) : http://svn.berlios.de/wsvn/applewin
b) Windows Explorer: TortoiseSVN -> Repro-browser
Use 'SVN Checkout...' off the right-context menu in a Windows folder.
URL of repository:
http://svn.berlios.de/svnroot/repos/applewin/trunk
(to get trunk)
http://svn.berlios.de/svnroot/repos/applewin
(to get everything! Or use [...] to browse for your specific branch)

View file

@ -11,6 +11,11 @@
<p style="FONT-WEIGHT: bold">AppleWin can be driven from the command line as
follows:
</p>
-conf &lt;pathname&gt;<br>
Use an INI file for configuration instead of the Registry.<br><br>
-current-dir &lt;path&gt;<br>
This is guaranteed to be processed after all the image loading switches (eg. -d1, -h1, etc).<br>
Use this switch if you have a mix of (eg) -d1 and -h1 loading images from different folders, and you want to guarantee the current dir.<br><br>
-d1 &lt;pathname&gt;<br>
Start with a floppy disk in slot 6 drive-1 (and auto power-on the Apple II).<br>
NB. -s6d1 has the meaning same as -d1.<br><br>
@ -25,8 +30,8 @@
Start with hard disk 1 plugged-in (and auto power-on the Apple II). NB. Hard disk controller card gets enabled.<br><br>
-h2 &lt;pathname&gt;<br>
Start with hard disk 2 plugged-in. NB. Hard disk controller card gets enabled.<br><br>
-model &lt;apple2|apple2p|apple2e|apple2ee&gt;<br>
Select the machine model: Apple II, Apple II+, Apple //e, Enhanced Apple //e.<br><br>
-model &lt;apple2|apple2p|apple2jp|apple2e|apple2ee&gt;<br>
Select the machine model: Apple II, Apple II+, Apple II J-Plus, Apple //e, Enhanced Apple //e.<br><br>
-clock-multiplier &lt;value&gt;<br>
Where value is between 0.5 and 3.9, and is a base-clock multiplier, roughly mapping to 0.5MHz - 3.9MHz<br><br>
-s0 &lt;saturn|saturn64|saturn128&gt;<br>
@ -50,10 +55,12 @@
Useful to allow a floppy disk to boot from slot 6, drive 1. Use in combination with -d1.<br><br>
-s7-empty-on-exit<br>
Remove the hard disk controller card from slot 7 on AppleWin exit.<br><br>
-no-nsc<br>
Remove the No-Slot clock (NSC).<br><br>
-r &lt;number of pages&gt;<br>
Emulate a RamWorks III card with 1 to 127 pages (each page is 64K, giving a max of 8MB) in the auxiliary slot in an Apple //e machine.<br><br>
-load-state &lt;savestate&gt;<br>
Load a save-state file<br>
Load a save-state file (and auto power-on the Apple II).<br>
NB. This takes precedent over the -d1, -d2, -d#s#, -h1, -h2, s0-7, -model and -r switches.<br><br>
-f<br>
Start in full-screen mode<br><br>
@ -64,8 +71,10 @@
<li>nnnn: select a specific resolution with height=nnnn pixels</li>
</ul>
NB. This changes the display resolution (and restores on exit).<br><br>
-rom &lt;file&gt;<br>
Use custom 12K ROM (at $D000) for Apple II machine, or 16K ROM (at $C000) for Apple //e machine.<br><br>
-f8rom &lt;file&gt;<br>
Use custom 2K ROM for any Apple II machine at [$F800..$FFFF]. &lt;file&gt; must be 2048 bytes long<br><br>
Use custom 2K ROM for any Apple II machine at [$F800..$FFFF]. &lt;file&gt; must be 2048 bytes long.<br><br>
-videorom &lt;file&gt;<br>
Use an alternate custom 2K video ROM for Apple II or II+ machines (but not clones).<br>
Use an alternate European or custom 4K, 8K or 16K (top 8K only) video ROM for the original or Enhanced //e (but not clones).<br><br>
@ -89,16 +98,18 @@
NB. Using this switch may prevent international keyboards from being able to type certain keys.<br><br>
-left-alt-control-buttons<br>
Use LEFT CONTROL & LEFT ALT for Open Apple & Solid Apple keys respectively.<br><br>
Use Left Control & Left Alt for Open Apple & Solid Apple keys respectively.<br>
Caveat: Left Control + F2 will do the //e Ctrl+Open Apple+RESET (as Left Control is now both Ctrl and Open Apple!). A workaround is just to use the Right Control key.<br><br>
-right-alt-control-buttons<br>
Use RIGHT CONTROL & RIGHT ALT for Open Apple & Solid Apple keys respectively.<br><br>
Use Right Alt (AltGr) & Right Control for Open Apple & Solid Apple keys respectively.<br>
Caveat: Right Control + F2 will do the //e self test (as Right Control is now both Ctrl and Solid Apple!). A workaround is just to use the Left Control key.<br><br>
-swap-buttons<br>
Swap the Windows keys used for Open Apple & Solid Apple keys.<br><br>
-use-real-printer<br>
Enables Advanced configuration control to allow dumping to a real printer<br><br>
-noreg<br>
Disable registration of file extensions (.do/.dsk/.nib/.po)<br><br>
Disable registration of file extensions (.do/.dsk/.nib/.po/.woz)<br><br>
-memclear &lt;n&gt;<br>
Where n is [0..7]:
<ul>
@ -132,7 +143,10 @@
-50hz<br>
Support 50Hz(PAL) video refresh rate and PAL 1.016MHz base CPU clock.<br><br>
-60hz<br>
Support 60Hz(NTSC) video refresh rate and NTSC 1.020MHz base CPU clock (default).<br>
Support 60Hz(NTSC) video refresh rate and NTSC 1.020MHz base CPU clock (default).<br><br>
-power-on<br>
Force a power-on.<br>
Use to auto power-on when not using -d1, -h1 or -load-state.<br>
<br>
<P style="FONT-WEIGHT: bold">Debug arguments:

View file

@ -78,6 +78,10 @@
<param name="Name" value="Save-state Files">
<param name="Local" value="savestate.html">
</OBJECT>
<LI> <OBJECT type="text/sitemap">
<param name="Name" value="Command line">
<param name="Local" value="CommandLine.html">
</OBJECT>
<LI> <OBJECT type="text/sitemap">
<param name="Name" value="Sound">
<param name="Local" value="sound.html">
@ -101,10 +105,6 @@
<param name="Local" value="uthernet-wifi-workaround.html">
</OBJECT>
</UL>
<LI> <OBJECT type="text/sitemap">
<param name="Name" value="Command line">
<param name="Local" value="CommandLine.html">
</OBJECT>
<LI> <OBJECT type="text/sitemap">
<param name="Name" value="AppleWin Configuration">
<param name="Local" value="configuration.html">
@ -195,6 +195,10 @@
<param name="Name" value="Breakpoints">
<param name="Local" value="dbg-breakpoints.html">
</OBJECT>
<LI> <OBJECT type="text/sitemap">
<param name="Name" value="Bookmarks">
<param name="Local" value="dbg-bookmarks.html">
</OBJECT>
<LI> <OBJECT type="text/sitemap">
<param name="Name" value="Configuration">
<param name="Local" value="dbg-configuration.html">
@ -211,7 +215,7 @@
<param name="Local" value="newsgroups.html">
</OBJECT>
<LI> <OBJECT type="text/sitemap">
<param name="Name" value="Internet FTP Sites">
<param name="Name" value="Internet Sites">
<param name="Local" value="ftp.html">
</OBJECT>
<LI> <OBJECT type="text/sitemap">

View file

@ -8,10 +8,10 @@
link="#008000" vlink="#008000">
<h2 style="COLOR: rgb(0,128,0)">Acknowledgements</h2>
<hr size="4">
<p>The team&nbsp;would like to thank the following people for their contributions:</p>
<p>The team would like to thank the following people for their contributions:</p>
<p style="MARGIN-LEFT: 40px">Brian Broker: This HTML / CHM help file</p>
<p style="MARGIN-LEFT: 40px">Thomas Stahl: TV emulation mode (up to v1.25.0.4)</p>
<p style="MARGIN-LEFT: 40px">Chris Foxwell: SSI263 phoneme samples</p>
<p style="MARGIN-LEFT: 40px">Greg Hedger: SSI263 phoneme samples</p>
<p style="MARGIN-LEFT: 40px">Robert Hoem: Hard disk card (source module &amp; f/w)</p>
<p style="MARGIN-LEFT: 40px">VICE team: TFE, Z80, MC6821 PIA emulation modules (<a href="http://vice-emu.sourceforge.net/index.html#developers">http://vice-emu.sourceforge.net/index.html#developers</a>)<br>
- In particular, Spiro Trikaliotis for TFE, whose code Glenn Jones adapted for Uthernet support</p>
@ -21,5 +21,9 @@
<p style="MARGIN-LEFT: 40px">Bob Sander-Cederlof: Applesoft Symbols (<a href="http://www.txbobsc.com/scsc/scdocumentor/index.html">http://www.txbobsc.com/scsc/scdocumentor/</a> S-C DocuMentor: Applesoft)</p>
<p style="MARGIN-LEFT: 40px">David Schmidt: Updates to this help file</p>
<p style="MARGIN-LEFT: 40px">Mike Harvey, Founder &amp; Editor of Nibble Magazine: For providing us Apple fans the pleasure of eagerly awaiting each next month's issue to learn about the Apple! (<a href="http://www.nibblemagazine.com/">http://www.nibblemagazine.com/</a>)</p>
<p style="MARGIN-LEFT: 40px">Andrea Odetti: numerous pull-requests</p>
<p style="MARGIN-LEFT: 40px">Iván Izaguirre: Taiwanese Copam Base64A Apple II clone</p>
<p style="MARGIN-LEFT: 40px">Arnaud C: debugger suggestions and help with 6502/6522/video timing issues</p>
<p style="MARGIN-LEFT: 40px">Cyril Lambin: debugger improvements</p>
</body>
</html>

View file

@ -22,7 +22,9 @@ emulation by pressing the F12 key.</p>
<p><strong>Clone:</strong><br>
If you have specified Computer as 'Clone' on the main Configuration
page, then this drop-down menu can be used to specify the clone type.<br>
NB. Pravets 82, 8M and 8A are Bulgarian Apple II clones.<br>
NB. Pravets 82, 8M and 8A are Bulgarian Apple II clones;
TK3000 is a Brazilian //e clone;
Base 64A is a Taiwanese Apple II clone.<br>
</p>
<p><strong>Printer settings </strong>(Printer is emulated in slot 1)
</p>

View file

@ -18,6 +18,7 @@
<ul>
<li>Apple ][ : 48K non-autostarting, Integer BASIC, no lower-case, no 80-column, 6502 CPU
<li>Apple ][+ : 64K autostarting, Applesoft BASIC version of the Apple ][
<li>Apple ][ J-Plus : 64K autostarting, Applesoft BASIC, Japanese version of the Apple ][+
<li>Apple //e : 128K machine, lower-case, 80-column, 6502 CPU</li>
<li>Enhanced Apple //e : 128K machine, lower-case, 80-column, 65C02 CPU</li>
<li>Clone (specific model selectable from Advanced page)</li>

View file

@ -12,7 +12,7 @@
<h3>Clock:</h3>
<p>AppleWin emulates a No-Slot clock (aka NSC).</p>
<p>This is a chip (a Dallas SmartWatch DS1216) that sits under one of the 28-pin ROM chips in the Apple II.<br>
No hardware configuration is required: this chip is always present, but won't interfere with emulation when not in use.
No hardware configuration is required: this chip is always present (unless -no-nsc is used), but won't interfere with emulation when not in use.
</p>
<p>It requires a software driver to be installed (for DOS and ProDOS). This driver then emulates the Thunderclock card.</p>
<p>Here's a summary of NSC/ROM chip locations and which drivers work:</p>

127
help/dbg-bookmarks.html Normal file
View file

@ -0,0 +1,127 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>AppleWin Debugger Tutorial</title>
<meta http-equiv="CONTENT-TYPE" content="text/html; charset=windows-1252">
</head>
<body style="DIRECTION: ltr" lang="en-US">
<h1>Bookmarks</h1>
<p>Bookmarks allow you to "tag" an address and consequently jump back to them.<br>
They appear as a number with a circle around them between where address and opcodes are listed (where the : separator is).
</p>
<img src="img/debugger-bookmarks-annotated.png" hspace="5" vspace="5">
<br>
<p><font size="4"><b>Notes</b>:</font></p>
<ul>
<li>Set a bookmark at the current disassembly cursor, use Ctrl-Shift-#, ie:
<ul>
<li>NB. Ctrl-Shift-0 can't be used, as it's not recognised by Windows
<li>Ctrl-Shift-1 set bookmark 1
<li>Ctrl-Shift-2 set bookmark 2
<li>...
<li>Ctrl-Shift-9 set bookmark 9
</ul>
</li>
<br>
<li>To jump to an existing bookmark, if it exists, press Ctrl-#, ie:
<ul>
<li>Ctrl-0 to jump to bookmark 0
<li>Ctrl-1 to jump to bookmark 1
<li>Ctrl-2 to jump to bookmark 2
<li>...
<li>Ctrl-9 to jump to bookmark 9
</ul>
</li>
<br>
<li>NB.
<ul>
<li>Bookmarks can appear in any order that you set - not just contiguous.
<li>An address can only have ONE bookmark assigned to it. If you try setting a new bookmark over an existing one, the old one will become free for use.
</ul>
</li>
</ul>
<p>
</p>
<p><font size="4"><b>Commands to manipulate bookmarks:</b></font></p>
<table border="1" cellpadding="2" cellspacing="0" width="75%">
<COLGROUP>
<col width="64">
<col width="192">
<tbody>
<tr bgcolor="#000000">
<td width="25%">
<p><font color="#ffffff"><b>Command</b></font></p>
</td>
<td>
<p><font color="#ffffff"><b>Description</b></font></p>
</td>
</tr>
<tr>
<td width="25%">
<p>help bookmarks</p>
</td>
<td>
<p>Lists all bookmark related commands</p>
</td>
</tr>
<tr>
<td width="25%">
<p>help bma</p>
</td>
<td>
<p>Lists specific help about the bma command</p>
</td>
</tr>
<tr>
<td width="25%">
<p>bma &lt;address|label&gt;</p>
</td>
<td>
<p>Add a bookmark at an address or label</p>
</td>
</tr>
<tr>
<td width="25%">
<p>bmc #</p>
</td>
<td>
<p>Clear a specific bookmarks, for example 'bmc 1' clears bookmark 1</p>
</td>
</tr>
<tr>
<td width="25%">
<p>bmc *</p>
</td>
<td>
<p>Clears all bookmarks</p>
</td>
</tr>
<tr>
<td width="25%">
<p>bml</p>
</td>
<td>
<p>Lists all boommarks</p>
</td>
</tr>
<tr>
<td width="25%">
<p>bmsave</p>
</td>
<td>
<p>Not implemented yet</p>
</td>
</tr>
</tbody>
</table>
</body>
</html>

View file

@ -27,6 +27,7 @@
<LI><A href="dbg-calculator.html">Calculator</A>
<LI><A href="dbg-windows.html">Windows</A>
<LI><A href="dbg-breakpoints.html">Breakpoints</A>
<LI><A href="dbg-bookmarks.html">Bookmarks</A>
<LI><A href="dbg-configuration.html">Configuration</A>
<UL>
<LI><A href="dbg-configuration.html#Colors">Colors</A>

View file

@ -47,9 +47,9 @@ do is make a nibble image of the disk. </p>
<p>After nibble copiers became
prevalent on
the Apple, some software publishers developed tricky new ways of
creating disks that even nibble copiers could not copy. It is
unlikely that such a disk could be successfully transferred into
a disk image. </p>
creating disks that even nibble copiers could not copy. Such a
disk can only be transferred onto a WOZ disk image using the
AppleSauce hardware & software. </p>
</body>
</html>

View file

@ -63,9 +63,9 @@ Disk Images</a> topic for more information. </p>
<p>Please note that not all disk image types supported by
AppleWin can be created in this manner.&nbsp; Since there is no way
to detect the image type from the image itself, it is determined by the
given file extension only. Three extensions are allowed: (.DSK, .DO,
.NIB). The first two create a "DOS Order Image" and then latter creates
a "Nibble Image".&nbsp; If the extension is completely omitted,
given file extension only. Four extensions are allowed: (.DSK, .DO,
.NIB, .WOZ). The first two create a "DOS Order Image", .NIB creates
a "Nibble Image" and .WOZ creates an empty .WOZ image.&nbsp; If the extension is completely omitted,
".DSK" will be chosen by default.&nbsp; For more information, see <a href="ddi-formats.html">Disk Image Formats</a>.</p>
</body>

View file

@ -44,11 +44,22 @@ To do this, click the checkbox for "Open as Read Only" in the Select
Disk Image dialog.&nbsp; This works like the physical
write-protection mechanism on a real Apple //e floppy disk.</p>
<p>If a Disk Image name is to
<p>If a Disk Image name is too
long to read in the Toolbar,
simply pause the mouse cursor over a drive button to get a
tool-tip with the full name.</p>
<p>Under the vertical Toolbar, are 2 LEDs, one for each floppy disk drive. The colors indicate drive status:
<li>Black: drive is off
<li>Green: drive is reading
<li>Red: drive is writing
<li>Orange: drive is reading (and floppy is write-protected)
</p>
<p>By default the Disk II Controller card has the 16-sector firmware (as used by DOS 3.3 and ProDOS). But if a WOZ image that internally identifies as 13-sector format (eg. DOS 3.2) is put into drive 1, then from the start-up/logo screen (or the next reset), the Disk II Controller card's firmware will automatically be switched to the old 13-sector firmware, allowing the disk to boot. And it will automatically switch back if a non-13-sector WOZ (or any non-WOZ) image is put into drive 1 and the machine is reset.<br>
NB. There is no support for this feature for non-WOZ images.
</p>
<p><sub style="FONT-WEIGHT: bold">1</sub>&nbsp;To register the file types in Windows Vista, Windows 7 and Windows 10,
you will need to run AppleWin with elevated privileges. This only needs to be done once.
Right click the AppleWin.exe icon and select 'Run as Administrator'.</p>

View file

@ -48,7 +48,7 @@ Common programs for doing this work are ADTPro and Arme Leute Apple Disk Transfe
<p style="font-weight: bold;">Ethernet Transfers:</p>
Apples with an <a href="http://a2retrosystems.com/">A2RetroSystems</a> Uthernet
Apples with an <a href="http://a2retrosystems.com/">A2RetroSystems</a>' Uthernet
card can transfer disk images via ADTPro:
<ul>
<li>Apple Disk Transfer ProDOS (ADTPro) - <a target="_blank" href="http://adtpro.sourceforge.net/configethernet.html">http://adtpro.sourceforge.net/configethernet.html</a>

View file

@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Internet FTP Sites</title>
<title>Internet Sites</title>
</head>
@ -11,8 +11,7 @@
<body style="background-color: rgb(255, 255, 255); font-family: verdana;" alink="#008000" link="#008000" vlink="#008000">
<h2 style="color: rgb(0, 128, 0);">Internet
FTP Sites</h2>
<h2 style="color: rgb(0, 128, 0);">Internet Sites</h2>
<hr size="4">
<p>Before transferring a program
@ -23,11 +22,21 @@ typing the word "binary".</p>
<p>
<a style="font-weight: bold;" target="_blank" href="ftp://public.asimov.net/pub/apple_II/">ftp://public.asimov.net/pub/apple_II/</a><br>
This site is the largest Apple
II emulation site, and the official release point for new
versions of AppleWin. Under the /pub/apple_II directory, you will
This site is the largest Apple II emulation site. Under the /pub/apple_II directory, you will
find disk images, utilities for making your own disk images, and
Apple emulators for other computers and operating systems.</p>
<p>
<a style="font-weight: bold;" target="_blank" href="https://archive.org/details/softwarelibrary_apple">https://archive.org/details/softwarelibrary_apple/</a><br>
This site contains a number of collections of Apple II software. Including:
<ul>
<li><a style="font-weight: bold;" target="_blank" href="https://archive.org/details/wozaday">https://archive.org/details/wozaday/</a><br>
This is an ever expanding collection of Apple II images in WOZ format.<br>
<li><a style="font-weight: bold;" target="_blank" href="https://archive.org/details/softwarelibrary_apple_woz">https://archive.org/details/softwarelibrary_apple_woz/</a><br>
Another collection of Apple II images in WOZ format.<br>
</ul>
</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -31,20 +31,22 @@
<li>CP/M SoftCard</li>
<li>Parallel Printer card</li>
<li>Super Serial card</li>
<li>No-Slot clock</li>
</ul>
The following are not yet persisted to the file:
<ul>
<li>Uthernet card</li>
<li>SAM card</li>
<li>No-Slot clock (there's nothing to persist)</li>
<li>Using The Freeze's F8 ROM</li>
<li>Alternate F8 ROM</li>
<li>Alternate ROM</li>
<li>Alternate video ROM</li>
</ul>
<p>Note: Only the file names of the disk images are stored in the .yaml file (not the
full path). This allows you to move your disk image around or distribute them.
If AppleWin can't locate the disk image(s), then it will prompt for the new
location.</p>
<p>NB. Loading of the old v1 file format (.aws file) is still supported.</p>
<p>NB. Loading of the old v1 file format (.aws file) is no longer supported. Use AppleWin 1.27.13 to load it at the AppleWin start-up/logo screen,
then immediately save it (and it'll be saved in the v2 format).</p>
</body>
</html>

View file

@ -28,11 +28,11 @@
<li><a href="toolbar.html">Using the Toolbar</a>
<li><a href="keyboard.html">Using the Keyboard</a>
<li><a href="savestate.html">Save-state Files</a>
<li><a href="CommandLine.html">Command line</a>
<li><a href="sound.html">Sound</a>
<li><a href="clock.html">Clock</a>
<li><a href="card-ssc.html">Super Serial card</a>
<li><a href="uthernet.html">Uthernet network card</a>
<li><a href="CommandLine.html">Command line</a>
<li><a href="configuration.html">AppleWin Configuration</a>
<li><a href="dbg-toc-intro.html">Using the Debugger</a>
<li><a href="resources.html">Resources</a></li>

View file

@ -20,16 +20,17 @@
<P style="FONT-WEIGHT: bold">Details:
</P>
<P>To enable ethernet support in AppleWin you must first download and install
WinPcap.
Npcap (or WinPcap).
</P>
<P>An alternative to downloading WinPcap is to get the Wireshark package which
includes WinPcap along with Wireshark network analyzer code. To use Wireshark to
<P>An alternative to downloading Npcap is to get the Wireshark package which
includes Npcap along with Wireshark network analyzer code. To use Wireshark to
capture traffic (other than your own) you must be plugged into a shared hub vs
a switch. If you plan on doing any network programming Wireshark is a definite
must have.
</P>
<P>WinPcap: <A href="http://www.WinPcap.org/install/default.htm">http://www.WinPcap.org/install/default.htm</A>
or Wireshark: <A href="https://www.wireshark.org">https://www.wireshark.org</A>
<P>Npcap: <A href="https://nmap.org/npcap/#download">https://nmap.org/npcap/#download</A>
or Wireshark: <A href="https://www.wireshark.org">https://www.wireshark.org</A>
(or WinPcap: <A href="https://www.winpcap.org/install/default.htm">https://www.winpcap.org/install/default.htm</A>)
</P>
<P>After AppleWin starts, select the settings icon and then select the ethernet
settings button.
@ -41,7 +42,7 @@
ethernet interface.
</P>
<P>If you have more than one interface you may need to select them in turn in order
to get the text description for each interface vs what WinPcap likes to use for
to get the text description for each interface vs what Npcap likes to use for
a reference. Select Ok. and then close AppleWin.
</P>
<P><span style="font-weight: bold;">Note:</span> Wireless does not work

View file

@ -38,13 +38,14 @@ Some key files have been completely reimplemented or discarded:
* AppleWin.cpp
* Frame.cpp
* Video.cpp (partially)
* Audio (including Mockingboard but excluding speech in QApple)
Some features totally ignored:
* ethernet
* serial port
* debugger
* speech
* speech (currently it hangs the emulator)
The rest is in a very usable state.
@ -79,6 +80,8 @@ This is based on Qt, currently tested with 5.10
* the app runs at 60FPS with correction for uneven timer deltas.
* full speed when disk spins execute up to 5 ms real wall clock of emulator code (then returns to Qt)
* (standard) audio is supported and there are a few configuration options to tune the latency (default very conservative 200ms)
* plain mockingboard is supported as well (not speech, which hang the emulator)
* Open Apple and Closed Apple can be emulated using AltGr and Menu (unfortunately, Alt does not work well)
## Build

BIN
resource/Apple2_JPlus.rom Normal file

Binary file not shown.

Binary file not shown.

View file

@ -55,6 +55,7 @@ FULLSCR_BUTTON BITMAP "FULLSCR.BMP"
RUN_BUTTON BITMAP "RUN.BMP"
RUNP_BUTTON BITMAP "RUNP.BMP"
RUN3000E_BUTTON BITMAP "RUN3000E.BMP"
RUNBASE64A_BUTTON BITMAP "RUNBASE64A.BMP"
DEBUG_BUTTON BITMAP "DEBUG.BMP"
DRIVE1_BUTTON BITMAP "DRIVE1.BMP"
DRIVE2_BUTTON BITMAP "DRIVE2.BMP"
@ -89,11 +90,11 @@ CAPTION "Configuration"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
LTEXT "&Model:",IDC_STATIC,5,7,40,8
COMBOBOX IDC_COMPUTER,45,5,90,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMPUTER,45,5,91,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "Confirm reboot",IDC_CHECK_CONFIRM_REBOOT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,8,62,10
GROUPBOX "Video",IDC_STATIC,5,22,200,56
LTEXT "Mo&de:",IDC_STATIC,12,33,33,8
COMBOBOX IDC_VIDEOTYPE,45,30,90,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_VIDEOTYPE,33,30,103,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Monochrome &Color...",IDC_MONOCOLOR,12,46,80,14
CONTROL "50% Scan lines",IDC_CHECK_HALF_SCAN_LINES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,33,62,10
CONTROL "Vertical blend",IDC_CHECK_VERTICAL_BLEND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,48,62,10
@ -175,21 +176,20 @@ BEGIN
GROUPBOX "Floppy Disk Drives",IDC_STATIC,5,7,200,72
LTEXT "&Disk access speed:",IDC_STATIC,12,21,64,8
COMBOBOX IDC_DISKTYPE,80,18,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
GROUPBOX "Hard Disk Drives",IDC_STATIC,5,83,200,64
CONTROL "&Enable hard disk controller in slot 7",IDC_HDD_ENABLE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,96,122,10
PUSHBUTTON "Swap",IDC_HDD_SWAP,156,92,40,14
LTEXT "&Path to CiderPress:",IDC_STATIC,7,155,74,8
EDITTEXT IDC_CIDERPRESS_FILENAME,7,165,143,12,ES_AUTOHSCROLL | ES_READONLY
PUSHBUTTON "&Browse...",IDC_CIDERPRESS_BROWSE,156,164,50,14
LTEXT "HDD 1:",IDC_STATIC,11,113,23,8
LTEXT "HDD 2:",IDC_STATIC,11,130,23,8
COMBOBOX IDC_COMBO_HDD1,46,112,150,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBO_HDD2,46,128,150,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Disk 1:",IDC_STATIC,10,41,23,8
LTEXT "Disk 2:",IDC_STATIC,10,58,23,8
COMBOBOX IDC_COMBO_DISK1,40,40,150,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBO_DISK2,40,57,150,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
GROUPBOX "Hard Disk Drives",IDC_STATIC,5,83,200,64
CONTROL "&Enable hard disk controller in slot 7",IDC_HDD_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,96,122,10
PUSHBUTTON "Swap",IDC_HDD_SWAP,156,92,40,14
LTEXT "HDD 1:",IDC_STATIC,11,113,23,8
LTEXT "HDD 2:",IDC_STATIC,11,130,23,8
COMBOBOX IDC_COMBO_HDD1,46,112,150,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMBO_HDD2,46,128,150,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "&Path to CiderPress:",IDC_STATIC,7,155,74,8
EDITTEXT IDC_CIDERPRESS_FILENAME,7,165,143,12,ES_AUTOHSCROLL | ES_READONLY
PUSHBUTTON "&Browse...",IDC_CIDERPRESS_BROWSE,156,164,50,14
END
IDD_TFE_SETTINGS_DIALOG DIALOGEX 0, 0, 270, 100
@ -200,7 +200,7 @@ BEGIN
LTEXT "Ethernet",IDC_TFE_SETTINGS_ENABLE_T,9,7,30,8
COMBOBOX IDC_TFE_SETTINGS_ENABLE,45,5,50,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Interface",IDC_TFE_SETTINGS_INTERFACE_T,9,24,30,8
COMBOBOX IDC_TFE_SETTINGS_INTERFACE,45,22,200,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_TFE_SETTINGS_INTERFACE,45,22,210,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "",IDC_TFE_SETTINGS_INTERFACE_NAME,9,44,250,8
LTEXT "",IDC_TFE_SETTINGS_INTERFACE_DESC,9,60,250,8
DEFPUSHBUTTON "Ok",IDOK,20,75,50,14
@ -308,7 +308,8 @@ END
// FIRMWARE
//
IDR_DISK2_FW FIRMWARE "Disk2.rom"
IDR_DISK2_13SECTOR_FW FIRMWARE "Disk2-13sector.rom"
IDR_DISK2_16SECTOR_FW FIRMWARE "Disk2.rom"
IDR_SSC_FW FIRMWARE "SSC.rom"
IDR_HDDRVR_FW FIRMWARE "Hddrvr.bin"
IDR_PRINTDRVR_FW FIRMWARE "Parallel.rom"
@ -324,14 +325,24 @@ IDR_TKCLOCK_FW FIRMWARE "TKClock.rom"
IDR_APPLE2_ROM ROM "Apple2.rom"
IDR_APPLE2_PLUS_ROM ROM "Apple2_Plus.rom"
IDR_APPLE2_JPLUS_ROM ROM "Apple2_JPlus.rom"
IDR_APPLE2E_ROM ROM "Apple2e.rom"
IDR_APPLE2E_ENHANCED_ROM ROM "Apple2e_Enhanced.rom"
IDR_PRAVETS_82_ROM ROM "Pravets82.rom"
IDR_PRAVETS_8M_ROM ROM "Pravets8M.rom"
IDR_PRAVETS_8C_ROM ROM "Pravets8C.rom"
IDR_TK3000_2E_ROM ROM "TK3000e.rom"
IDR_BASE_64A_ROM ROM "Base64A.rom"
IDR_FREEZES_F8_ROM ROM "FREEZES_NON-AUTOSTART_F8_ROM.rom"
/////////////////////////////////////////////////////////////////////////////
//
// VIDEO ROM
//
IDR_APPLE2_JPLUS_VIDEO_ROM ROM "Apple2_JPlus_Video.rom"
IDR_BASE64A_VIDEO_ROM ROM "Base64A_German_Video.rom"
/////////////////////////////////////////////////////////////////////////////
//
// Menu

BIN
resource/Base64A.rom Normal file

Binary file not shown.

Binary file not shown.

BIN
resource/DISK2-13sector.rom Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 42 KiB

BIN
resource/RUNBASE64A.BMP Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -34,7 +34,6 @@
#define IDD_TFE_SETTINGS_DIALOG 131
#define IDR_PRINTDRVR_FW 132
#define IDD_PROPPAGE_ADVANCED 132
#define IDR_DISK2_FW 133
#define IDR_SSC_FW 134
#define IDR_MOCKINGBOARD_D_FW 135
#define IDR_MOUSEINTERFACE_FW 136
@ -48,6 +47,12 @@
#define IDC_CHECK_CONFIRM_REBOOT 146
#define IDR_TK3000_2E_ROM 147
#define IDR_TKCLOCK_FW 148
#define IDR_DISK2_13SECTOR_FW 149
#define IDR_DISK2_16SECTOR_FW 150
#define IDR_APPLE2_JPLUS_ROM 151
#define IDR_APPLE2_JPLUS_VIDEO_ROM 152
#define IDR_BASE_64A_ROM 153
#define IDR_BASE64A_VIDEO_ROM 154
#define IDC_KEYB_BUFFER_ENABLE 1005
#define IDC_SAVESTATE 1006
#define IDC_SAVESTATE_ON_EXIT 1007

View file

@ -1,4 +1,4 @@
#define APPLEWIN_VERSION 1,29,8,0
#define APPLEWIN_VERSION 1,29,14,0
#define xstr(a) str(a)
#define str(a) #a

View file

@ -26,9 +26,7 @@
#include "StdAfx.h"
#include <windows.h>
#include <stdio.h>
#include <crtdbg.h>
#include "AY8910.h"
#include "Applewin.h" // For g_fh
@ -991,7 +989,7 @@ sound_beeper( int is_tape, int on )
#define SS_YAML_KEY_CHANGE "Change"
#define SS_YAML_VALUE_CHANGE_FORMAT "%d, %d, 0x%1X, 0x%02X"
void CAY8910::SaveSnapshot(YamlSaveHelper& yamlSaveHelper, std::string& suffix)
void CAY8910::SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const std::string& suffix)
{
std::string unit = std::string(SS_YAML_KEY_AY8910) + suffix;
YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", unit.c_str());
@ -1046,7 +1044,7 @@ void CAY8910::SaveSnapshot(YamlSaveHelper& yamlSaveHelper, std::string& suffix)
}
}
bool CAY8910::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, std::string& suffix)
bool CAY8910::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, const std::string& suffix)
{
std::string unit = std::string(SS_YAML_KEY_AY8910) + suffix;
if (!yamlLoadHelper.GetSubMap(unit))
@ -1201,7 +1199,7 @@ BYTE* AY8910_GetRegsPtr(UINT uChip)
return g_AY8910[uChip].GetAYRegsPtr();
}
UINT AY8910_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, UINT uChip, std::string& suffix)
UINT AY8910_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, UINT uChip, const std::string& suffix)
{
if (uChip >= MAX_8910)
return 0;
@ -1210,7 +1208,7 @@ UINT AY8910_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, UINT uChip, std::string
return 1;
}
UINT AY8910_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT uChip, std::string& suffix)
UINT AY8910_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT uChip, const std::string& suffix)
{
if (uChip >= MAX_8910)
return 0;

View file

@ -17,8 +17,8 @@ BYTE* AY8910_GetRegsPtr(UINT uChip);
void AY8910UpdateSetCycles();
UINT AY8910_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, UINT uChip, std::string& suffix);
UINT AY8910_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT uChip, std::string& suffix);
UINT AY8910_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, UINT uChip, const std::string& suffix);
UINT AY8910_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT uChip, const std::string& suffix);
//-------------------------------------
// FUSE stuff
@ -46,8 +46,8 @@ public:
void sound_frame( void );
BYTE* GetAYRegsPtr( void ) { return &sound_ay_registers[0]; }
static void SetCLK( double CLK ) { m_fCurrentCLK_AY8910 = CLK; }
void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, std::string& suffix);
bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, std::string& suffix);
void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const std::string& suffix);
bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, const std::string& suffix);
private:
void init( void );

View file

@ -82,9 +82,12 @@ AppMode_e g_nAppMode = MODE_LOGO;
static bool g_bLoadedSaveState = false;
static bool g_bSysClkOK = false;
std::string g_sStartDir; // NB. AppleWin.exe maybe relative to this! (GH#663)
std::string g_sProgramDir; // Directory of where AppleWin executable resides
std::string g_sDebugDir; // TODO: Not currently used
std::string g_sScreenShotDir; // TODO: Not currently used
std::string g_sConfigFile; // INI file to use instead of Registry
bool g_bCapturePrintScreenKey = true;
static bool g_bHookSystemKey = true;
static bool g_bHookAltTab = false;
@ -109,8 +112,10 @@ int g_nMemoryClearType = MIP_FF_FF_00_00; // Note: -1 = random MIP in Memory.c
CardManager g_CardMgr;
IPropertySheet& sg_PropertySheet = * new CPropertySheet;
HANDLE g_hCustomRomF8 = INVALID_HANDLE_VALUE; // Cmd-line specified custom ROM at $F800..$FFFF
static bool g_bCustomRomF8Failed = false; // Set if custom ROM file failed
HANDLE g_hCustomRomF8 = INVALID_HANDLE_VALUE; // Cmd-line specified custom F8 ROM at $F800..$FFFF
static bool g_bCustomRomF8Failed = false; // Set if custom F8 ROM file failed
HANDLE g_hCustomRom = INVALID_HANDLE_VALUE; // Cmd-line specified custom ROM at $C000..$FFFF(16KiB) or $D000..$FFFF(12KiB)
static bool g_bCustomRomFailed = false; // Set if custom ROM file failed
static bool g_bEnableSpeech = false;
#ifdef USE_SPEECH_API
@ -119,11 +124,51 @@ CSpeech g_Speech;
//===========================================================================
#ifdef LOG_PERF_TIMINGS
static UINT64 g_timeTotal = 0;
UINT64 g_timeCpu = 0;
UINT64 g_timeVideo = 0; // part of timeCpu
UINT64 g_timeMB_Timer = 0; // part of timeCpu
UINT64 g_timeMB_NoTimer = 0;
UINT64 g_timeSpeaker = 0;
static UINT64 g_timeVideoRefresh = 0;
void LogPerfTimings(void)
{
if (g_timeTotal)
{
UINT64 cpu = g_timeCpu - g_timeVideo - g_timeMB_Timer;
UINT64 video = g_timeVideo + g_timeVideoRefresh;
UINT64 spkr = g_timeSpeaker;
UINT64 mb = g_timeMB_Timer + g_timeMB_NoTimer;
UINT64 audio = spkr + mb;
UINT64 other = g_timeTotal - g_timeCpu - g_timeSpeaker - g_timeMB_NoTimer - g_timeVideoRefresh;
LogOutput("Perf breakdown:\n");
LogOutput(". CPU %% = %6.2f\n", (double)cpu / (double)g_timeTotal * 100.0);
LogOutput(". Video %% = %6.2f\n", (double)video / (double)g_timeTotal * 100.0);
LogOutput("... NTSC %% = %6.2f\n", (double)g_timeVideo / (double)g_timeTotal * 100.0);
LogOutput("... refresh %% = %6.2f\n", (double)g_timeVideoRefresh / (double)g_timeTotal * 100.0);
LogOutput(". Audio %% = %6.2f\n", (double)audio / (double)g_timeTotal * 100.0);
LogOutput("... Speaker %% = %6.2f\n", (double)spkr / (double)g_timeTotal * 100.0);
LogOutput("... MB %% = %6.2f\n", (double)mb / (double)g_timeTotal * 100.0);
LogOutput(". Other %% = %6.2f\n", (double)other / (double)g_timeTotal * 100.0);
LogOutput(". TOTAL %% = %6.2f\n", (double)(cpu+video+audio+other) / (double)g_timeTotal * 100.0);
}
}
#endif
//===========================================================================
static DWORD dwLogKeyReadTickStart;
static bool bLogKeyReadDone = false;
void LogFileTimeUntilFirstKeyReadReset(void)
{
#ifdef LOG_PERF_TIMINGS
LogPerfTimings();
#endif
if (!g_fh)
return;
@ -230,6 +275,10 @@ static bool g_uModeStepping_LastGetKey_ScrollLock = false;
static void ContinueExecution(void)
{
#ifdef LOG_PERF_TIMINGS
PerfMarker* pPerfMarkerTotal = new PerfMarker(g_timeTotal);
#endif
_ASSERT(g_nAppMode == MODE_RUNNING || g_nAppMode == MODE_STEPPING);
const double fUsecPerSec = 1.e6;
@ -348,6 +397,9 @@ static void ContinueExecution(void)
const UINT dwClksPerFrame = NTSC_GetCyclesPerFrame();
if (g_dwCyclesThisFrame >= dwClksPerFrame && !VideoGetVblBarEx(g_dwCyclesThisFrame))
{
#ifdef LOG_PERF_TIMINGS
PerfMarker perfMarkerVideoRefresh(g_timeVideoRefresh);
#endif
g_dwCyclesThisFrame -= dwClksPerFrame;
if (g_bFullSpeed)
@ -356,6 +408,10 @@ static void ContinueExecution(void)
VideoRefreshScreen(); // Just copy the output of our Apple framebuffer to the system Back Buffer
}
#ifdef LOG_PERF_TIMINGS
delete pPerfMarkerTotal; // Explicitly call dtor *before* SysClk_WaitTimer()
#endif
if ((g_nAppMode == MODE_RUNNING && !g_bFullSpeed) || bModeStepping_WaitTimer)
{
SysClk_WaitTimer();
@ -486,7 +542,8 @@ void EnterMessageLoop(void)
}
//===========================================================================
void GetProgramDirectory(void)
static void GetProgramDirectory(void)
{
TCHAR programDir[MAX_PATH];
GetModuleFileName((HINSTANCE)0, programDir, MAX_PATH);
@ -1086,19 +1143,27 @@ static std::string GetFullPath(LPCSTR szFileName)
}
else
{
// Rel pathname
char szCWD[_MAX_PATH] = {0};
if (!GetCurrentDirectory(sizeof(szCWD), szCWD))
return "";
strPathName = szCWD;
strPathName.append("\\");
// Rel pathname (GH#663)
strPathName = g_sStartDir;
strPathName.append(szFileName);
}
return strPathName;
}
static void SetCurrentDir(std::string pathname)
{
// Due to the order HDDs/disks are inserted, then s7 insertions take priority over s6 & s5; and d2 takes priority over d1:
// . if -s6[dN] and -hN are specified, then g_sCurrentDir will be set to the HDD image's path
// . if -s5[dN] and -s6[dN] are specified, then g_sCurrentDir will be set to the s6 image's path
// . if -[sN]d1 and -[sN]d2 are specified, then g_sCurrentDir will be set to the d2 image's path
// This is purely dependent on the current order of InsertFloppyDisks() & InsertHardDisks() - ie. very brittle!
// . better to use -current-dir to be explicit
std::size_t found = pathname.find_last_of("\\");
std::string path = pathname.substr(0, found);
SetCurrentImageDir(path);
}
static bool DoDiskInsert(const UINT slot, const int nDrive, LPCSTR szFileName)
{
Disk2InterfaceCard& disk2Card = dynamic_cast<Disk2InterfaceCard&>(g_CardMgr.GetRef(slot));
@ -1107,7 +1172,10 @@ static bool DoDiskInsert(const UINT slot, const int nDrive, LPCSTR szFileName)
if (strPathName.empty()) return false;
ImageError_e Error = disk2Card.InsertDisk(nDrive, strPathName.c_str(), IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE);
return Error == eIMAGE_ERROR_NONE;
bool res = (Error == eIMAGE_ERROR_NONE);
if (res)
SetCurrentDir(strPathName);
return res;
}
static bool DoHardDiskInsert(const int nDrive, LPCSTR szFileName)
@ -1116,7 +1184,10 @@ static bool DoHardDiskInsert(const int nDrive, LPCSTR szFileName)
if (strPathName.empty()) return false;
BOOL bRes = HD_Insert(nDrive, strPathName.c_str());
return bRes ? true : false;
bool res = (bRes == TRUE);
if (res)
SetCurrentDir(strPathName);
return res;
}
static void InsertFloppyDisks(const UINT slot, LPSTR szImageName_drive[NUM_DRIVES], bool& bBoot)
@ -1156,11 +1227,9 @@ static void InsertHardDisks(LPSTR szImageName_harddisk[NUM_HARDDISKS], bool& bBo
HD_SetEnabled(true);
DWORD dwTmp;
if (REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp))
{
if (!dwTmp)
REGSAVE(TEXT(REGVALUE_HDD_ENABLED), 1); // Config: HDD Enabled
}
BOOL res = REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp);
if (!res || !dwTmp)
REGSAVE(TEXT(REGVALUE_HDD_ENABLED), 1); // Config: HDD Enabled
//
@ -1189,11 +1258,9 @@ static void UnplugHardDiskControllerCard(void)
HD_SetEnabled(false);
DWORD dwTmp;
if (REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp))
{
if (dwTmp)
REGSAVE(TEXT(REGVALUE_HDD_ENABLED), 0); // Config: HDD Disabled
}
BOOL res = REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp);
if (!res || dwTmp)
REGSAVE(TEXT(REGVALUE_HDD_ENABLED), 0); // Config: HDD Disabled
}
static bool CheckOldAppleWinVersion(void)
@ -1251,6 +1318,7 @@ struct CmdLine
bSlot0LanguageCard = false;
bSlot7EmptyOnExit = false;
bSwapButtons0and1 = false;
bRemoveNoSlotClock = false;
bestWidth = 0;
bestHeight = 0;
szImageName_harddisk[HARDDISK_1] = NULL;
@ -1265,6 +1333,9 @@ struct CmdLine
newVideoRefreshRate = VR_NONE;
clockMultiplier = 0.0; // 0 => not set from cmd-line
model = A2TYPE_MAX;
rgbCard = RGB_Videocard_e::Apple;
rgbCardForegroundColor = 15;
rgbCardBackgroundColor = 0;
for (UINT i = 0; i < NUM_SLOTS; i++)
{
@ -1283,6 +1354,7 @@ struct CmdLine
bool bSlotEmpty[NUM_SLOTS];
bool bSlot7EmptyOnExit;
bool bSwapButtons0and1;
bool bRemoveNoSlotClock;
SS_CARDTYPE slotInsert[NUM_SLOTS];
UINT bestWidth;
UINT bestHeight;
@ -1298,15 +1370,25 @@ struct CmdLine
VideoRefreshRate_e newVideoRefreshRate;
double clockMultiplier;
eApple2Type model;
RGB_Videocard_e rgbCard;
int rgbCardForegroundColor;
int rgbCardBackgroundColor;
std::string strCurrentDir;
};
static CmdLine g_cmdLine;
int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
{
char startDir[_MAX_PATH];
GetCurrentDirectory(sizeof(startDir), startDir);
g_sStartDir = startDir;
if (*(g_sStartDir.end()-1) != '\\') g_sStartDir += '\\';
if (!ProcessCmdLine(lpCmdLine))
return 0;
LogFileOutput("g_sStartDir = %s\n", g_sStartDir.c_str());
GetAppleWinVersion();
OneTimeInitialization(passinstance);
@ -1368,6 +1450,12 @@ static bool ProcessCmdLine(LPSTR lpCmdLine)
const std::string strCmdLine(lpCmdLine); // Keep a copy for log ouput
std::string strUnsupported;
// If 1st param looks like an abs pathname then assume that an associated filetype has been double-clicked
// NB. Handled by WM_DDE_INITIATE & WM_DDE_EXECUTE msgs
if ((lpCmdLine[0] >= '\"' && lpCmdLine[1] >= 'A' && lpCmdLine[1] <= 'Z' && lpCmdLine[2] == ':') // always in quotes
|| strncmp("\\\\?\\", lpCmdLine, 4) == 0)
return true;
while (*lpCmdLine)
{
LPSTR lpNextArg = GetNextArg(lpCmdLine);
@ -1380,6 +1468,17 @@ static bool ProcessCmdLine(LPSTR lpCmdLine)
{
g_bRegisterFileTypes = false;
}
else if (strcmp(lpCmdLine, "-conf") == 0)
{
lpCmdLine = GetCurrArg(lpNextArg);
lpNextArg = GetNextArg(lpNextArg);
char buf[MAX_PATH];
DWORD res = GetFullPathName(lpCmdLine, MAX_PATH, buf, NULL);
if (res == 0)
LogFileOutput("Failed to open configuration file: %s\n", lpCmdLine);
else
g_sConfigFile = buf;
}
else if (strcmp(lpCmdLine, "-d1") == 0)
{
lpCmdLine = GetCurrArg(lpNextArg);
@ -1432,15 +1531,15 @@ static bool ProcessCmdLine(LPSTR lpCmdLine)
g_cmdLine.szImageName_drive[slot][drive] = lpCmdLine;
}
}
else if (strcmp(lpCmdLine, "-s7-empty-on-exit") == 0)
{
g_cmdLine.bSlot7EmptyOnExit = true;
}
else
{
LogFileOutput("Unsupported arg: %s\n", lpCmdLine);
}
}
else if (strcmp(lpCmdLine, "-s7-empty-on-exit") == 0)
{
g_cmdLine.bSlot7EmptyOnExit = true;
}
else if (strcmp(lpCmdLine, "-load-state") == 0)
{
lpCmdLine = GetCurrArg(lpNextArg);
@ -1535,6 +1634,18 @@ static bool ProcessCmdLine(LPSTR lpCmdLine)
if ((g_hCustomRomF8 == INVALID_HANDLE_VALUE) || (GetFileSize(g_hCustomRomF8, NULL) != 0x800))
g_bCustomRomF8Failed = true;
}
else if (strcmp(lpCmdLine, "-rom") == 0) // Use custom 16K at [$C000..$FFFF] or 12K ROM at [$D000..$FFFF]
{
lpCmdLine = GetCurrArg(lpNextArg);
lpNextArg = GetNextArg(lpNextArg);
if (g_hCustomRom != INVALID_HANDLE_VALUE) // Stop resource leak if -rom is specified twice!
CloseHandle(g_hCustomRom);
g_hCustomRom = CreateFile(lpCmdLine, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if ((g_hCustomRom == INVALID_HANDLE_VALUE) || ((GetFileSize(g_hCustomRom, NULL) != 0x4000) && (GetFileSize(g_hCustomRom, NULL) != 0x3000)))
g_bCustomRomFailed = true;
}
else if (strcmp(lpCmdLine, "-videorom") == 0) // Use 2K (for II/II+). Use 4K,8K or 16K video ROM (for Enhanced //e)
{
lpCmdLine = GetCurrArg(lpNextArg);
@ -1640,6 +1751,14 @@ static bool ProcessCmdLine(LPSTR lpCmdLine)
{
g_cmdLine.newVideoType = VT_COLOR_MONITOR_RGB;
}
else if (strcmp(lpCmdLine, "-video-mode=rgb-videocard") == 0)
{
g_cmdLine.newVideoType = VT_COLOR_VIDEOCARD_RGB;
}
else if (strcmp(lpCmdLine, "-video-mode=composite-monitor") == 0) // GH#763
{
g_cmdLine.newVideoType = VT_COLOR_MONITOR_NTSC;
}
else if (strcmp(lpCmdLine, "-video-style=vertical-blend") == 0) // GH#616
{
g_cmdLine.newVideoStyleEnableMask = VS_COLOR_VERTICAL_BLEND;
@ -1672,6 +1791,8 @@ static bool ProcessCmdLine(LPSTR lpCmdLine)
g_cmdLine.model = A2TYPE_APPLE2;
else if (strcmp(lpCmdLine, "apple2p") == 0)
g_cmdLine.model = A2TYPE_APPLE2PLUS;
else if (strcmp(lpCmdLine, "apple2jp") == 0)
g_cmdLine.model = A2TYPE_APPLE2JPLUS;
else if (strcmp(lpCmdLine, "apple2e") == 0)
g_cmdLine.model = A2TYPE_APPLE2E;
else if (strcmp(lpCmdLine, "apple2ee") == 0)
@ -1687,6 +1808,51 @@ static bool ProcessCmdLine(LPSTR lpCmdLine)
{
g_cmdLine.newVideoRefreshRate = VR_60HZ;
}
else if (strcmp(lpCmdLine, "-rgb-card-type") == 0)
{
// RGB video card valide types are: "apple", "sl7", "eve", "feline"
lpCmdLine = GetCurrArg(lpNextArg);
lpNextArg = GetNextArg(lpNextArg);
if (strcmp(lpCmdLine, "apple") == 0)
g_cmdLine.rgbCard = RGB_Videocard_e::Apple;
else if (strcmp(lpCmdLine, "sl7") == 0)
g_cmdLine.rgbCard = RGB_Videocard_e::Video7_SL7;
else if (strcmp(lpCmdLine, "eve") == 0)
g_cmdLine.rgbCard = RGB_Videocard_e::LeChatMauve_EVE;
else if (strcmp(lpCmdLine, "feline") == 0)
g_cmdLine.rgbCard = RGB_Videocard_e::LeChatMauve_Feline;
else
LogFileOutput("-rgb-card-type: unsupported type: %s\n", lpCmdLine);
}
else if (strcmp(lpCmdLine, "-rgb-card-foreground") == 0)
{
// Default hardware-defined Text foreground color, for some RGB cards only
lpCmdLine = GetCurrArg(lpNextArg);
lpNextArg = GetNextArg(lpNextArg);
g_cmdLine.rgbCardForegroundColor = atoi(lpCmdLine);
}
else if (strcmp(lpCmdLine, "-rgb-card-background") == 0)
{
// Default hardware-defined Text background color, for some RGB cards only
lpCmdLine = GetCurrArg(lpNextArg);
lpNextArg = GetNextArg(lpNextArg);
g_cmdLine.rgbCardBackgroundColor = atoi(lpCmdLine);
}
else if (strcmp(lpCmdLine, "-power-on") == 0)
{
g_cmdLine.bBoot = true;
}
else if (strcmp(lpCmdLine, "-current-dir") == 0)
{
lpCmdLine = GetCurrArg(lpNextArg);
lpNextArg = GetNextArg(lpNextArg);
g_cmdLine.strCurrentDir = lpCmdLine;
}
else if (strcmp(lpCmdLine, "-no-nsc") == 0)
{
g_cmdLine.bRemoveNoSlotClock = true;
}
else // unsupported
{
LogFileOutput("Unsupported arg: %s\n", lpCmdLine);
@ -1819,6 +1985,8 @@ static void RepeatInitialization(void)
if (g_cmdLine.model != A2TYPE_MAX)
SetApple2Type(g_cmdLine.model);
RGB_SetVideocard(g_cmdLine.rgbCard, g_cmdLine.rgbCardForegroundColor, g_cmdLine.rgbCardBackgroundColor);
if (g_cmdLine.newVideoType >= 0)
{
SetVideoType( (VideoType_e)g_cmdLine.newVideoType );
@ -1877,7 +2045,12 @@ static void RepeatInitialization(void)
FrameCreateWindow(); // g_hFrameWindow is now valid
LogFileOutput("Main: FrameCreateWindow() - post\n");
// Init palette color
VideoSwitchVideocardPalette(RGB_GetVideocard(), GetVideoType());
// Allow the 4 hardcoded slots to be configurated as empty
// NB. this state is not persisted to the Registry/conf.ini (just as '-s7 empty' isn't)
// TODO: support bSlotEmpty[] for slots: 0,4,5
if (g_cmdLine.bSlotEmpty[SLOT1])
g_CardMgr.Remove(SLOT1);
if (g_cmdLine.bSlotEmpty[SLOT2])
@ -1912,9 +2085,16 @@ static void RepeatInitialization(void)
g_cmdLine.szImageName_harddisk[HARDDISK_1] = g_cmdLine.szImageName_harddisk[HARDDISK_2] = NULL; // Don't insert on a restart
if (g_cmdLine.bSlotEmpty[7])
HD_SetEnabled(false);
HD_SetEnabled(false); // Disable HDD controller, but don't persist this to Registry/conf.ini (consistent with other '-sn empty' cmds)
}
// Set *after* InsertFloppyDisks() & InsertHardDisks(), which both update g_sCurrentDir
if (!g_cmdLine.strCurrentDir.empty())
SetCurrentImageDir(g_cmdLine.strCurrentDir);
if (g_cmdLine.bRemoveNoSlotClock)
MemRemoveNoSlotClock();
MemInitialize();
LogFileOutput("Main: MemInitialize()\n");
@ -1951,9 +2131,12 @@ static void RepeatInitialization(void)
g_cmdLine.bShutdown = true;
}
if (g_bCustomRomF8Failed)
if (g_bCustomRomF8Failed || g_bCustomRomFailed || (g_hCustomRomF8 != INVALID_HANDLE_VALUE && g_hCustomRom != INVALID_HANDLE_VALUE))
{
std::string msg = "Failed to load custom F8 rom (not found or not exactly 2KiB)\n";
std::string msg = g_bCustomRomF8Failed ? "Failed to load custom F8 rom (not found or not exactly 2KiB)\n"
: g_bCustomRomFailed ? "Failed to load custom rom (not found or not exactly 12KiB or 16KiB)\n"
: "Unsupported -rom and -f8rom being used at the same time\n";
LogFileOutput("%s", msg.c_str());
MessageBox(g_hFrameWindow, msg.c_str(), TEXT("AppleWin Error"), MB_OK);
g_cmdLine.bShutdown = true;
@ -2058,6 +2241,9 @@ static void Shutdown(void)
if (g_hCustomRomF8 != INVALID_HANDLE_VALUE)
CloseHandle(g_hCustomRomF8);
if (g_hCustomRom != INVALID_HANDLE_VALUE)
CloseHandle(g_hCustomRom);
if (g_cmdLine.bSlot7EmptyOnExit)
UnplugHardDiskControllerCard();
}

View file

@ -54,7 +54,8 @@ extern int g_nMemoryClearType; // Cmd line switch: use specific MIP (
extern class CardManager g_CardMgr;
extern HANDLE g_hCustomRomF8; // NULL if no custom rom
extern HANDLE g_hCustomRomF8; // INVALID_HANDLE_VALUE if no custom F8 rom
extern HANDLE g_hCustomRom; // INVALID_HANDLE_VALUE if no custom rom
#ifdef USE_SPEECH_API
class CSpeech;
@ -62,3 +63,27 @@ extern CSpeech g_Speech;
#endif
extern __interface IPropertySheet& sg_PropertySheet;
//
//#define LOG_PERF_TIMINGS
#ifdef LOG_PERF_TIMINGS
class PerfMarker
{
public:
PerfMarker(UINT64& globalCounter)
: counter(globalCounter)
{
QueryPerformanceCounter(&timeStart);
}
~PerfMarker()
{
QueryPerformanceCounter(&timeEnd);
counter += (UINT64)timeEnd.QuadPart - (UINT64)timeStart.QuadPart;
}
private:
UINT64& counter;
LARGE_INTEGER timeStart;
LARGE_INTEGER timeEnd;
};
#endif

View file

@ -1,9 +1,10 @@
include(FindPkgConfig)
add_library(appleii SHARED
linux/data.cpp
SaveState.cpp
Speaker.cpp
SoundCore.cpp
AY8910.cpp
Mockingboard.cpp
Pravets.cpp
Tape.cpp
YamlHelper.cpp
@ -27,6 +28,10 @@ add_library(appleii SHARED
NTSC_CharSet.cpp
CardManager.cpp
Disk2CardManager.cpp
SaveState.cpp # uses g_CardMgr in m_ConfigNew (reverse order)
Riff.cpp
Configuration/PropertySheetHelper.cpp
linux/windows/memory.cpp
linux/windows/handles.cpp
@ -37,9 +42,15 @@ add_library(appleii SHARED
linux/windows/stringcb.cpp
linux/windows/strings.cpp
linux/windows/misc.cpp
linux/windows/winbase.cpp
linux/windows/winuser.cpp
linux/windows/dsound.cpp
linux/windows/guiddef.cpp
linux/windows/dmusicc.cpp
linux/windows/winnls.cpp
linux/dummies.cpp
linux/state.cpp
linux/data.cpp
linux/benchmark.cpp
linux/paddle.cpp
linux/version.cpp
@ -48,11 +59,11 @@ add_library(appleii SHARED
linux/duplicates/Debug.cpp
linux/duplicates/Video.cpp
linux/duplicates/Mockingboard.cpp
linux/duplicates/Joystick.cpp
linux/duplicates/Frame.cpp
linux/duplicates/SerialComms.cpp
linux/duplicates/Applewin.cpp
linux/duplicates/IPropertySheet.cpp
linux/duplicates/Applewin.cpp # defines g_CardMgr (reverse order)
Z80VICE/z80.cpp
Z80VICE/z80mem.cpp
@ -74,3 +85,6 @@ target_link_libraries(appleii PRIVATE
${YAML_LIBRARIES}
${MINIZIP_LIBRARIES}
)
install(TARGETS appleii
DESTINATION lib)

View file

@ -98,6 +98,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#endif
#include "Video.h"
#include "NTSC.h"
#include "Log.h"
#include "z80emu.h"
#include "Z80VICE/z80.h"
@ -105,6 +106,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "YamlHelper.h"
#define LOG_IRQ_TAKEN_AND_RTI 0
// 6502 Accumulator Bit Flags
#define AF_SIGN 0x80
#define AF_OVERFLOW 0x40
@ -211,13 +214,8 @@ void SetMouseCardInstalled(bool installed)
//
#include "CPU/cpu_general.inl"
#include "CPU/cpu_instructions.inl"
// Break into debugger on invalid opcodes
//#define INV IsDebugBreakOnInvalid(AM_1);
#define INV
/****************************************************************************
*
* OPCODE TABLE
@ -243,6 +241,10 @@ static __forceinline void DoIrqProfiling(DWORD uCycles)
if(regs.ps & AF_INTERRUPT)
return; // Still in Apple's ROM
#if LOG_IRQ_TAKEN_AND_RTI
LogOutput("ISR-end\n\n");
#endif
g_nCycleIrqEnd = g_nCumulativeCycles + uCycles;
g_nCycleIrqTime = (UINT) (g_nCycleIrqEnd - g_nCycleIrqStart);
@ -268,18 +270,6 @@ static __forceinline void DoIrqProfiling(DWORD uCycles)
//===========================================================================
BYTE CpuRead(USHORT addr, ULONG uExecutedCycles)
{
return READ;
}
void CpuWrite(USHORT addr, BYTE a, ULONG uExecutedCycles)
{
WRITE(a);
}
//===========================================================================
#ifdef USE_SPEECH_API
const USHORT COUT = 0xFDED;
@ -442,6 +432,9 @@ static __forceinline void IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn,
regs.pc = * (WORD*) (mem+0xFFFE);
UINT uExtraCycles = 0; // Needed for CYC(a) macro
CYC(7)
#if defined(_DEBUG) && LOG_IRQ_TAKEN_AND_RTI
LogOutput("IRQ\n");
#endif
}
g_irqOnLastOpcodeCycle = false;
@ -477,18 +470,57 @@ void CpuAdjustIrqCheck(UINT uCyclesUntilInterrupt)
//===========================================================================
#define READ _READ
#define WRITE(value) _WRITE(value)
#define HEATMAP_X(address)
#include "CPU/cpu6502.h" // MOS 6502
#include "CPU/cpu65C02.h" // WDC 65C02
#include "CPU/cpu65d02.h" // Debug CPU Memory Visualizer
#undef READ
#undef WRITE
#undef HEATMAP_X
//-----------------
#define READ Heatmap_ReadByte(addr, uExecutedCycles)
#define WRITE(value) Heatmap_WriteByte(addr, value, uExecutedCycles);
#define HEATMAP_X(address) Heatmap_X(address)
#include "CPU/cpu_heatmap.inl"
#define Cpu6502 Cpu6502_debug
#include "CPU/cpu6502.h" // MOS 6502
#undef Cpu6502
#define Cpu65C02 Cpu65C02_debug
#include "CPU/cpu65C02.h" // WDC 65C02
#undef Cpu65C02
#undef READ
#undef WRITE
#undef HEATMAP_X
//===========================================================================
static DWORD InternalCpuExecute(const DWORD uTotalCycles, const bool bVideoUpdate)
{
if (GetMainCpu() == CPU_6502)
return Cpu6502(uTotalCycles, bVideoUpdate); // Apple ][, ][+, //e, Clones
if (g_nAppMode == MODE_RUNNING)
{
if (GetMainCpu() == CPU_6502)
return Cpu6502(uTotalCycles, bVideoUpdate); // Apple ][, ][+, //e, Clones
else
return Cpu65C02(uTotalCycles, bVideoUpdate); // Enhanced Apple //e
}
else
return Cpu65C02(uTotalCycles, bVideoUpdate); // Enhanced Apple //e
{
_ASSERT(g_nAppMode == MODE_STEPPING || g_nAppMode == MODE_DEBUG);
if (GetMainCpu() == CPU_6502)
return Cpu6502_debug(uTotalCycles, bVideoUpdate); // Apple ][, ][+, //e, Clones
else
return Cpu65C02_debug(uTotalCycles, bVideoUpdate); // Enhanced Apple //e
}
}
//
@ -497,6 +529,31 @@ static DWORD InternalCpuExecute(const DWORD uTotalCycles, const bool bVideoUpdat
//===========================================================================
// Called by z80_RDMEM()
BYTE CpuRead(USHORT addr, ULONG uExecutedCycles)
{
if (g_nAppMode == MODE_RUNNING)
{
return _READ;
}
return Heatmap_ReadByte(addr, uExecutedCycles);
}
// Called by z80_WRMEM()
void CpuWrite(USHORT addr, BYTE value, ULONG uExecutedCycles)
{
if (g_nAppMode == MODE_RUNNING)
{
_WRITE(value);
return;
}
Heatmap_WriteByte(addr, value, uExecutedCycles);
}
//===========================================================================
void CpuDestroy ()
{
if (g_bCritSectionValid)
@ -554,6 +611,11 @@ ULONG CpuGetCyclesThisVideoFrame(const ULONG nExecutedCycles)
DWORD CpuExecute(const DWORD uCycles, const bool bVideoUpdate)
{
#ifdef LOG_PERF_TIMINGS
extern UINT64 g_timeCpu;
PerfMarker perfMarker(g_timeCpu);
#endif
g_nCyclesExecuted = 0;
#ifdef _DEBUG

View file

@ -32,7 +32,7 @@ void CpuSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
void CpuLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT version);
BYTE CpuRead(USHORT addr, ULONG uExecutedCycles);
void CpuWrite(USHORT addr, BYTE a, ULONG uExecutedCycles);
void CpuWrite(USHORT addr, BYTE value, ULONG uExecutedCycles);
enum eCpuType {CPU_UNKNOWN=0, CPU_6502=1, CPU_65C02, CPU_Z80}; // Don't change! Persisted to Registry

View file

@ -52,270 +52,269 @@ static DWORD Cpu6502(DWORD uTotalCycles, const bool bVideoUpdate)
}
else
{
HEATMAP_X( regs.pc );
Fetch(iOpcode, uExecutedCycles);
//#define $ INV // INV = Invalid -> Debugger Break
#define $
switch (iOpcode)
{
case 0x00: BRK CYC(7) break;
case 0x01: idx ORA CYC(6) break;
case 0x02: $ HLT CYC(2) break;
case 0x03: $ idx ASO CYC(8) break;
case 0x04: $ ZPG NOP CYC(3) break;
case 0x05: ZPG ORA CYC(3) break;
case 0x06: ZPG ASLn CYC(5) break;
case 0x07: $ ZPG ASO CYC(5) break;
case 0x08: PHP CYC(3) break;
case 0x09: IMM ORA CYC(2) break;
case 0x0A: asl CYC(2) break;
case 0x0B: $ IMM ANC CYC(2) break;
case 0x0C: $ ABSX_OPT NOP CYC(4) break;
case 0x0D: ABS ORA CYC(4) break;
case 0x0E: ABS ASLn CYC(6) break;
case 0x0F: $ ABS ASO CYC(6) break;
case 0x10: REL BPL CYC(2) break;
case 0x11: INDY_OPT ORA CYC(5) break;
case 0x12: $ HLT CYC(2) break;
case 0x13: $ INDY_CONST ASO CYC(8) break;
case 0x14: $ zpx NOP CYC(4) break;
case 0x15: zpx ORA CYC(4) break;
case 0x16: zpx ASLn CYC(6) break;
case 0x17: $ zpx ASO CYC(6) break;
case 0x18: CLC CYC(2) break;
case 0x19: ABSY_OPT ORA CYC(4) break;
case 0x1A: $ NOP CYC(2) break;
case 0x1B: $ ABSY_CONST ASO CYC(7) break;
case 0x1C: $ ABSX_OPT NOP CYC(4) break;
case 0x1D: ABSX_OPT ORA CYC(4) break;
case 0x1E: ABSX_CONST ASLn CYC(7) break;
case 0x1F: $ ABSX_CONST ASO CYC(7) break;
case 0x20: ABS JSR CYC(6) break;
case 0x21: idx AND CYC(6) break;
case 0x22: $ HLT CYC(2) break;
case 0x23: $ idx RLA CYC(8) break;
case 0x24: ZPG BIT CYC(3) break;
case 0x25: ZPG AND CYC(3) break;
case 0x26: ZPG ROLn CYC(5) break;
case 0x27: $ ZPG RLA CYC(5) break;
case 0x28: PLP CYC(4) break;
case 0x29: IMM AND CYC(2) break;
case 0x2A: rol CYC(2) break;
case 0x2B: $ IMM ANC CYC(2) break;
case 0x2C: ABS BIT CYC(4) break;
case 0x2D: ABS AND CYC(4) break;
case 0x2E: ABS ROLn CYC(6) break;
case 0x2F: $ ABS RLA CYC(6) break;
case 0x30: REL BMI CYC(2) break;
case 0x31: INDY_OPT AND CYC(5) break;
case 0x32: $ HLT CYC(2) break;
case 0x33: $ INDY_CONST RLA CYC(8) break;
case 0x34: $ zpx NOP CYC(4) break;
case 0x35: zpx AND CYC(4) break;
case 0x36: zpx ROLn CYC(6) break;
case 0x37: $ zpx RLA CYC(6) break;
case 0x38: SEC CYC(2) break;
case 0x39: ABSY_OPT AND CYC(4) break;
case 0x3A: $ NOP CYC(2) break;
case 0x3B: $ ABSY_CONST RLA CYC(7) break;
case 0x3C: $ ABSX_OPT NOP CYC(4) break;
case 0x3D: ABSX_OPT AND CYC(4) break;
case 0x3E: ABSX_CONST ROLn CYC(6) break;
case 0x3F: $ ABSX_CONST RLA CYC(7) break;
case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break;
case 0x41: idx EOR CYC(6) break;
case 0x42: $ HLT CYC(2) break;
case 0x43: $ idx LSE CYC(8) break;
case 0x44: $ ZPG NOP CYC(3) break;
case 0x45: ZPG EOR CYC(3) break;
case 0x46: ZPG LSRn CYC(5) break;
case 0x47: $ ZPG LSE CYC(5) break;
case 0x48: PHA CYC(3) break;
case 0x49: IMM EOR CYC(2) break;
case 0x4A: lsr CYC(2) break;
case 0x4B: $ IMM ALR CYC(2) break;
case 0x4C: ABS JMP CYC(3) break;
case 0x4D: ABS EOR CYC(4) break;
case 0x4E: ABS LSRn CYC(6) break;
case 0x4F: $ ABS LSE CYC(6) break;
case 0x50: REL BVC CYC(2) break;
case 0x51: INDY_OPT EOR CYC(5) break;
case 0x52: $ HLT CYC(2) break;
case 0x53: $ INDY_CONST LSE CYC(8) break;
case 0x54: $ zpx NOP CYC(4) break;
case 0x55: zpx EOR CYC(4) break;
case 0x56: zpx LSRn CYC(6) break;
case 0x57: $ zpx LSE CYC(6) break;
case 0x58: CLI CYC(2) break;
case 0x59: ABSY_OPT EOR CYC(4) break;
case 0x5A: $ NOP CYC(2) break;
case 0x5B: $ ABSY_CONST LSE CYC(7) break;
case 0x5C: $ ABSX_OPT NOP CYC(4) break;
case 0x5D: ABSX_OPT EOR CYC(4) break;
case 0x5E: ABSX_CONST LSRn CYC(6) break;
case 0x5F: $ ABSX_CONST LSE CYC(7) break;
case 0x60: RTS CYC(6) break;
case 0x61: idx ADCn CYC(6) break;
case 0x62: $ HLT CYC(2) break;
case 0x63: $ idx RRA CYC(8) break;
case 0x64: $ ZPG NOP CYC(3) break;
case 0x65: ZPG ADCn CYC(3) break;
case 0x66: ZPG RORn CYC(5) break;
case 0x67: $ ZPG RRA CYC(5) break;
case 0x68: PLA CYC(4) break;
case 0x69: IMM ADCn CYC(2) break;
case 0x6A: ror CYC(2) break;
case 0x6B: $ IMM ARR CYC(2) break;
case 0x6C: IABS_NMOS JMP CYC(5) break; // GH#264
case 0x6D: ABS ADCn CYC(4) break;
case 0x6E: ABS RORn CYC(6) break;
case 0x6F: $ ABS RRA CYC(6) break;
case 0x70: REL BVS CYC(2) break;
case 0x71: INDY_OPT ADCn CYC(5) break;
case 0x72: $ HLT CYC(2) break;
case 0x73: $ INDY_CONST RRA CYC(8) break;
case 0x74: $ zpx NOP CYC(4) break;
case 0x75: zpx ADCn CYC(4) break;
case 0x76: zpx RORn CYC(6) break;
case 0x77: $ zpx RRA CYC(6) break;
case 0x78: SEI CYC(2) break;
case 0x79: ABSY_OPT ADCn CYC(4) break;
case 0x7A: $ NOP CYC(2) break;
case 0x7B: $ ABSY_CONST RRA CYC(7) break;
case 0x7C: $ ABSX_OPT NOP CYC(4) break;
case 0x7D: ABSX_OPT ADCn CYC(4) break;
case 0x7E: ABSX_CONST RORn CYC(6) break;
case 0x7F: $ ABSX_CONST RRA CYC(7) break;
case 0x80: $ IMM NOP CYC(2) break;
case 0x81: idx STA CYC(6) break;
case 0x82: $ IMM NOP CYC(2) break;
case 0x83: $ idx AXS CYC(6) break;
case 0x84: ZPG STY CYC(3) break;
case 0x85: ZPG STA CYC(3) break;
case 0x86: ZPG STX CYC(3) break;
case 0x87: $ ZPG AXS CYC(3) break;
case 0x88: DEY CYC(2) break;
case 0x89: $ IMM NOP CYC(2) break;
case 0x8A: TXA CYC(2) break;
case 0x8B: $ IMM XAA CYC(2) break;
case 0x8C: ABS STY CYC(4) break;
case 0x8D: ABS STA CYC(4) break;
case 0x8E: ABS STX CYC(4) break;
case 0x8F: $ ABS AXS CYC(4) break;
case 0x90: REL BCC CYC(2) break;
case 0x91: INDY_CONST STA CYC(6) break;
case 0x92: $ HLT CYC(2) break;
case 0x93: $ INDY_CONST AXA CYC(6) break;
case 0x94: zpx STY CYC(4) break;
case 0x95: zpx STA CYC(4) break;
case 0x96: zpy STX CYC(4) break;
case 0x97: $ zpy AXS CYC(4) break;
case 0x98: TYA CYC(2) break;
case 0x99: ABSY_CONST STA CYC(5) break;
case 0x9A: TXS CYC(2) break;
case 0x9B: $ ABSY_CONST TAS CYC(5) break;
case 0x9C: $ ABSX_CONST SAY CYC(5) break;
case 0x9D: ABSX_CONST STA CYC(5) break;
case 0x9E: $ ABSY_CONST XAS CYC(5) break;
case 0x9F: $ ABSY_CONST AXA CYC(5) break;
case 0xA0: IMM LDY CYC(2) break;
case 0xA1: idx LDA CYC(6) break;
case 0xA2: IMM LDX CYC(2) break;
case 0xA3: $ idx LAX CYC(6) break;
case 0xA4: ZPG LDY CYC(3) break;
case 0xA5: ZPG LDA CYC(3) break;
case 0xA6: ZPG LDX CYC(3) break;
case 0xA7: $ ZPG LAX CYC(3) break;
case 0xA8: TAY CYC(2) break;
case 0xA9: IMM LDA CYC(2) break;
case 0xAA: TAX CYC(2) break;
case 0xAB: $ IMM OAL CYC(2) break;
case 0xAC: ABS LDY CYC(4) break;
case 0xAD: ABS LDA CYC(4) break;
case 0xAE: ABS LDX CYC(4) break;
case 0xAF: $ ABS LAX CYC(4) break;
case 0xB0: REL BCS CYC(2) break;
case 0xB1: INDY_OPT LDA CYC(5) break;
case 0xB2: $ HLT CYC(2) break;
case 0xB3: $ INDY_OPT LAX CYC(5) break;
case 0xB4: zpx LDY CYC(4) break;
case 0xB5: zpx LDA CYC(4) break;
case 0xB6: zpy LDX CYC(4) break;
case 0xB7: $ zpy LAX CYC(4) break;
case 0xB8: CLV CYC(2) break;
case 0xB9: ABSY_OPT LDA CYC(4) break;
case 0xBA: TSX CYC(2) break;
case 0xBB: $ ABSY_OPT LAS CYC(4) break;
case 0xBC: ABSX_OPT LDY CYC(4) break;
case 0xBD: ABSX_OPT LDA CYC(4) break;
case 0xBE: ABSY_OPT LDX CYC(4) break;
case 0xBF: $ ABSY_OPT LAX CYC(4) break;
case 0xC0: IMM CPY CYC(2) break;
case 0xC1: idx CMP CYC(6) break;
case 0xC2: $ IMM NOP CYC(2) break;
case 0xC3: $ idx DCM CYC(8) break;
case 0xC4: ZPG CPY CYC(3) break;
case 0xC5: ZPG CMP CYC(3) break;
case 0xC6: ZPG DEC CYC(5) break;
case 0xC7: $ ZPG DCM CYC(5) break;
case 0xC8: INY CYC(2) break;
case 0xC9: IMM CMP CYC(2) break;
case 0xCA: DEX CYC(2) break;
case 0xCB: $ IMM SAX CYC(2) break;
case 0xCC: ABS CPY CYC(4) break;
case 0xCD: ABS CMP CYC(4) break;
case 0xCE: ABS DEC CYC(6) break;
case 0xCF: $ ABS DCM CYC(6) break;
case 0xD0: REL BNE CYC(2) break;
case 0xD1: INDY_OPT CMP CYC(5) break;
case 0xD2: $ HLT CYC(2) break;
case 0xD3: $ INDY_CONST DCM CYC(8) break;
case 0xD4: $ zpx NOP CYC(4) break;
case 0xD5: zpx CMP CYC(4) break;
case 0xD6: zpx DEC CYC(6) break;
case 0xD7: $ zpx DCM CYC(6) break;
case 0xD8: CLD CYC(2) break;
case 0xD9: ABSY_OPT CMP CYC(4) break;
case 0xDA: $ NOP CYC(2) break;
case 0xDB: $ ABSY_CONST DCM CYC(7) break;
case 0xDC: $ ABSX_OPT NOP CYC(4) break;
case 0xDD: ABSX_OPT CMP CYC(4) break;
case 0xDE: ABSX_CONST DEC CYC(7) break;
case 0xDF: $ ABSX_CONST DCM CYC(7) break;
case 0xE0: IMM CPX CYC(2) break;
case 0xE1: idx SBCn CYC(6) break;
case 0xE2: $ IMM NOP CYC(2) break;
case 0xE3: $ idx INS CYC(8) break;
case 0xE4: ZPG CPX CYC(3) break;
case 0xE5: ZPG SBCn CYC(3) break;
case 0xE6: ZPG INC CYC(5) break;
case 0xE7: $ ZPG INS CYC(5) break;
case 0xE8: INX CYC(2) break;
case 0xE9: IMM SBCn CYC(2) break;
case 0xEA: NOP CYC(2) break;
case 0xEB: $ IMM SBCn CYC(2) break;
case 0xEC: ABS CPX CYC(4) break;
case 0xED: ABS SBCn CYC(4) break;
case 0xEE: ABS INC CYC(6) break;
case 0xEF: $ ABS INS CYC(6) break;
case 0xF0: REL BEQ CYC(2) break;
case 0xF1: INDY_OPT SBCn CYC(5) break;
case 0xF2: $ HLT CYC(2) break;
case 0xF3: $ INDY_CONST INS CYC(8) break;
case 0xF4: $ zpx NOP CYC(4) break;
case 0xF5: zpx SBCn CYC(4) break;
case 0xF6: zpx INC CYC(6) break;
case 0xF7: $ zpx INS CYC(6) break;
case 0xF8: SED CYC(2) break;
case 0xF9: ABSY_OPT SBCn CYC(4) break;
case 0xFA: $ NOP CYC(2) break;
case 0xFB: $ ABSY_CONST INS CYC(7) break;
case 0xFC: $ ABSX_OPT NOP CYC(4) break;
case 0xFD: ABSX_OPT SBCn CYC(4) break;
case 0xFE: ABSX_CONST INC CYC(7) break;
case 0xFF: $ ABSX_CONST INS CYC(7) break;
// TODO-MP Optimization Note: ?? Move CYC(#) to array ??
case 0x00: BRK CYC(7) break;
case 0x01: idx ORA CYC(6) break;
case 0x02: HLT CYC(2) break; // invalid
case 0x03: idx ASO CYC(8) break; // invalid
case 0x04: ZPG NOP CYC(3) break; // invalid
case 0x05: ZPG ORA CYC(3) break;
case 0x06: ZPG ASLn CYC(5) break;
case 0x07: ZPG ASO CYC(5) break; // invalid
case 0x08: PHP CYC(3) break;
case 0x09: IMM ORA CYC(2) break;
case 0x0A: asl CYC(2) break;
case 0x0B: IMM ANC CYC(2) break; // invalid
case 0x0C: ABSX_OPT NOP CYC(4) break; // invalid
case 0x0D: ABS ORA CYC(4) break;
case 0x0E: ABS ASLn CYC(6) break;
case 0x0F: ABS ASO CYC(6) break; // invalid
case 0x10: REL BPL CYC(2) break;
case 0x11: INDY_OPT ORA CYC(5) break;
case 0x12: HLT CYC(2) break; // invalid
case 0x13: INDY_CONST ASO CYC(8) break; // invalid
case 0x14: zpx NOP CYC(4) break; // invalid
case 0x15: zpx ORA CYC(4) break;
case 0x16: zpx ASLn CYC(6) break;
case 0x17: zpx ASO CYC(6) break; // invalid
case 0x18: CLC CYC(2) break;
case 0x19: ABSY_OPT ORA CYC(4) break;
case 0x1A: NOP CYC(2) break; // invalid
case 0x1B: ABSY_CONST ASO CYC(7) break; // invalid
case 0x1C: ABSX_OPT NOP CYC(4) break; // invalid
case 0x1D: ABSX_OPT ORA CYC(4) break;
case 0x1E: ABSX_CONST ASLn CYC(7) break;
case 0x1F: ABSX_CONST ASO CYC(7) break; // invalid
case 0x20: ABS JSR CYC(6) break;
case 0x21: idx AND CYC(6) break;
case 0x22: HLT CYC(2) break; // invalid
case 0x23: idx RLA CYC(8) break; // invalid
case 0x24: ZPG BIT CYC(3) break;
case 0x25: ZPG AND CYC(3) break;
case 0x26: ZPG ROLn CYC(5) break;
case 0x27: ZPG RLA CYC(5) break; // invalid
case 0x28: PLP CYC(4) break;
case 0x29: IMM AND CYC(2) break;
case 0x2A: rol CYC(2) break;
case 0x2B: IMM ANC CYC(2) break; // invalid
case 0x2C: ABS BIT CYC(4) break;
case 0x2D: ABS AND CYC(4) break;
case 0x2E: ABS ROLn CYC(6) break;
case 0x2F: ABS RLA CYC(6) break; // invalid
case 0x30: REL BMI CYC(2) break;
case 0x31: INDY_OPT AND CYC(5) break;
case 0x32: HLT CYC(2) break; // invalid
case 0x33: INDY_CONST RLA CYC(8) break; // invalid
case 0x34: zpx NOP CYC(4) break; // invalid
case 0x35: zpx AND CYC(4) break;
case 0x36: zpx ROLn CYC(6) break;
case 0x37: zpx RLA CYC(6) break; // invalid
case 0x38: SEC CYC(2) break;
case 0x39: ABSY_OPT AND CYC(4) break;
case 0x3A: NOP CYC(2) break; // invalid
case 0x3B: ABSY_CONST RLA CYC(7) break; // invalid
case 0x3C: ABSX_OPT NOP CYC(4) break; // invalid
case 0x3D: ABSX_OPT AND CYC(4) break;
case 0x3E: ABSX_CONST ROLn CYC(7) break;
case 0x3F: ABSX_CONST RLA CYC(7) break; // invalid
case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break;
case 0x41: idx EOR CYC(6) break;
case 0x42: HLT CYC(2) break; // invalid
case 0x43: idx LSE CYC(8) break; // invalid
case 0x44: ZPG NOP CYC(3) break; // invalid
case 0x45: ZPG EOR CYC(3) break;
case 0x46: ZPG LSRn CYC(5) break;
case 0x47: ZPG LSE CYC(5) break; // invalid
case 0x48: PHA CYC(3) break;
case 0x49: IMM EOR CYC(2) break;
case 0x4A: lsr CYC(2) break;
case 0x4B: IMM ALR CYC(2) break; // invalid
case 0x4C: ABS JMP CYC(3) break;
case 0x4D: ABS EOR CYC(4) break;
case 0x4E: ABS LSRn CYC(6) break;
case 0x4F: ABS LSE CYC(6) break; // invalid
case 0x50: REL BVC CYC(2) break;
case 0x51: INDY_OPT EOR CYC(5) break;
case 0x52: HLT CYC(2) break; // invalid
case 0x53: INDY_CONST LSE CYC(8) break; // invalid
case 0x54: zpx NOP CYC(4) break; // invalid
case 0x55: zpx EOR CYC(4) break;
case 0x56: zpx LSRn CYC(6) break;
case 0x57: zpx LSE CYC(6) break; // invalid
case 0x58: CLI CYC(2) break;
case 0x59: ABSY_OPT EOR CYC(4) break;
case 0x5A: NOP CYC(2) break; // invalid
case 0x5B: ABSY_CONST LSE CYC(7) break; // invalid
case 0x5C: ABSX_OPT NOP CYC(4) break; // invalid
case 0x5D: ABSX_OPT EOR CYC(4) break;
case 0x5E: ABSX_CONST LSRn CYC(7) break;
case 0x5F: ABSX_CONST LSE CYC(7) break; // invalid
case 0x60: RTS CYC(6) break;
case 0x61: idx ADCn CYC(6) break;
case 0x62: HLT CYC(2) break; // invalid
case 0x63: idx RRA CYC(8) break; // invalid
case 0x64: ZPG NOP CYC(3) break; // invalid
case 0x65: ZPG ADCn CYC(3) break;
case 0x66: ZPG RORn CYC(5) break;
case 0x67: ZPG RRA CYC(5) break; // invalid
case 0x68: PLA CYC(4) break;
case 0x69: IMM ADCn CYC(2) break;
case 0x6A: ror CYC(2) break;
case 0x6B: IMM ARR CYC(2) break; // invalid
case 0x6C: IABS_NMOS JMP CYC(5) break; // GH#264
case 0x6D: ABS ADCn CYC(4) break;
case 0x6E: ABS RORn CYC(6) break;
case 0x6F: ABS RRA CYC(6) break; // invalid
case 0x70: REL BVS CYC(2) break;
case 0x71: INDY_OPT ADCn CYC(5) break;
case 0x72: HLT CYC(2) break; // invalid
case 0x73: INDY_CONST RRA CYC(8) break; // invalid
case 0x74: zpx NOP CYC(4) break; // invalid
case 0x75: zpx ADCn CYC(4) break;
case 0x76: zpx RORn CYC(6) break;
case 0x77: zpx RRA CYC(6) break; // invalid
case 0x78: SEI CYC(2) break;
case 0x79: ABSY_OPT ADCn CYC(4) break;
case 0x7A: NOP CYC(2) break; // invalid
case 0x7B: ABSY_CONST RRA CYC(7) break; // invalid
case 0x7C: ABSX_OPT NOP CYC(4) break; // invalid
case 0x7D: ABSX_OPT ADCn CYC(4) break;
case 0x7E: ABSX_CONST RORn CYC(7) break;
case 0x7F: ABSX_CONST RRA CYC(7) break; // invalid
case 0x80: IMM NOP CYC(2) break; // invalid
case 0x81: idx STA CYC(6) break;
case 0x82: IMM NOP CYC(2) break; // invalid
case 0x83: idx AXS CYC(6) break; // invalid
case 0x84: ZPG STY CYC(3) break;
case 0x85: ZPG STA CYC(3) break;
case 0x86: ZPG STX CYC(3) break;
case 0x87: ZPG AXS CYC(3) break; // invalid
case 0x88: DEY CYC(2) break;
case 0x89: IMM NOP CYC(2) break; // invalid
case 0x8A: TXA CYC(2) break;
case 0x8B: IMM XAA CYC(2) break; // invalid
case 0x8C: ABS STY CYC(4) break;
case 0x8D: ABS STA CYC(4) break;
case 0x8E: ABS STX CYC(4) break;
case 0x8F: ABS AXS CYC(4) break; // invalid
case 0x90: REL BCC CYC(2) break;
case 0x91: INDY_CONST STA CYC(6) break;
case 0x92: HLT CYC(2) break; // invalid
case 0x93: INDY_CONST AXA CYC(6) break; // invalid
case 0x94: zpx STY CYC(4) break;
case 0x95: zpx STA CYC(4) break;
case 0x96: zpy STX CYC(4) break;
case 0x97: zpy AXS CYC(4) break; // invalid
case 0x98: TYA CYC(2) break;
case 0x99: ABSY_CONST STA CYC(5) break;
case 0x9A: TXS CYC(2) break;
case 0x9B: ABSY_CONST TAS CYC(5) break; // invalid
case 0x9C: ABSX_CONST SAY CYC(5) break; // invalid
case 0x9D: ABSX_CONST STA CYC(5) break;
case 0x9E: ABSY_CONST XAS CYC(5) break; // invalid
case 0x9F: ABSY_CONST AXA CYC(5) break; // invalid
case 0xA0: IMM LDY CYC(2) break;
case 0xA1: idx LDA CYC(6) break;
case 0xA2: IMM LDX CYC(2) break;
case 0xA3: idx LAX CYC(6) break; // invalid
case 0xA4: ZPG LDY CYC(3) break;
case 0xA5: ZPG LDA CYC(3) break;
case 0xA6: ZPG LDX CYC(3) break;
case 0xA7: ZPG LAX CYC(3) break; // invalid
case 0xA8: TAY CYC(2) break;
case 0xA9: IMM LDA CYC(2) break;
case 0xAA: TAX CYC(2) break;
case 0xAB: IMM OAL CYC(2) break; // invalid
case 0xAC: ABS LDY CYC(4) break;
case 0xAD: ABS LDA CYC(4) break;
case 0xAE: ABS LDX CYC(4) break;
case 0xAF: ABS LAX CYC(4) break; // invalid
case 0xB0: REL BCS CYC(2) break;
case 0xB1: INDY_OPT LDA CYC(5) break;
case 0xB2: HLT CYC(2) break; // invalid
case 0xB3: INDY_OPT LAX CYC(5) break; // invalid
case 0xB4: zpx LDY CYC(4) break;
case 0xB5: zpx LDA CYC(4) break;
case 0xB6: zpy LDX CYC(4) break;
case 0xB7: zpy LAX CYC(4) break; // invalid
case 0xB8: CLV CYC(2) break;
case 0xB9: ABSY_OPT LDA CYC(4) break;
case 0xBA: TSX CYC(2) break;
case 0xBB: ABSY_OPT LAS CYC(4) break; // invalid
case 0xBC: ABSX_OPT LDY CYC(4) break;
case 0xBD: ABSX_OPT LDA CYC(4) break;
case 0xBE: ABSY_OPT LDX CYC(4) break;
case 0xBF: ABSY_OPT LAX CYC(4) break; // invalid
case 0xC0: IMM CPY CYC(2) break;
case 0xC1: idx CMP CYC(6) break;
case 0xC2: IMM NOP CYC(2) break; // invalid
case 0xC3: idx DCM CYC(8) break; // invalid
case 0xC4: ZPG CPY CYC(3) break;
case 0xC5: ZPG CMP CYC(3) break;
case 0xC6: ZPG DEC CYC(5) break;
case 0xC7: ZPG DCM CYC(5) break; // invalid
case 0xC8: INY CYC(2) break;
case 0xC9: IMM CMP CYC(2) break;
case 0xCA: DEX CYC(2) break;
case 0xCB: IMM SAX CYC(2) break; // invalid
case 0xCC: ABS CPY CYC(4) break;
case 0xCD: ABS CMP CYC(4) break;
case 0xCE: ABS DEC CYC(6) break;
case 0xCF: ABS DCM CYC(6) break; // invalid
case 0xD0: REL BNE CYC(2) break;
case 0xD1: INDY_OPT CMP CYC(5) break;
case 0xD2: HLT CYC(2) break; // invalid
case 0xD3: INDY_CONST DCM CYC(8) break; // invalid
case 0xD4: zpx NOP CYC(4) break; // invalid
case 0xD5: zpx CMP CYC(4) break;
case 0xD6: zpx DEC CYC(6) break;
case 0xD7: zpx DCM CYC(6) break; // invalid
case 0xD8: CLD CYC(2) break;
case 0xD9: ABSY_OPT CMP CYC(4) break;
case 0xDA: NOP CYC(2) break; // invalid
case 0xDB: ABSY_CONST DCM CYC(7) break; // invalid
case 0xDC: ABSX_OPT NOP CYC(4) break; // invalid
case 0xDD: ABSX_OPT CMP CYC(4) break;
case 0xDE: ABSX_CONST DEC CYC(7) break;
case 0xDF: ABSX_CONST DCM CYC(7) break; // invalid
case 0xE0: IMM CPX CYC(2) break;
case 0xE1: idx SBCn CYC(6) break;
case 0xE2: IMM NOP CYC(2) break; // invalid
case 0xE3: idx INS CYC(8) break; // invalid
case 0xE4: ZPG CPX CYC(3) break;
case 0xE5: ZPG SBCn CYC(3) break;
case 0xE6: ZPG INC CYC(5) break;
case 0xE7: ZPG INS CYC(5) break; // invalid
case 0xE8: INX CYC(2) break;
case 0xE9: IMM SBCn CYC(2) break;
case 0xEA: NOP CYC(2) break;
case 0xEB: IMM SBCn CYC(2) break; // invalid
case 0xEC: ABS CPX CYC(4) break;
case 0xED: ABS SBCn CYC(4) break;
case 0xEE: ABS INC CYC(6) break;
case 0xEF: ABS INS CYC(6) break; // invalid
case 0xF0: REL BEQ CYC(2) break;
case 0xF1: INDY_OPT SBCn CYC(5) break;
case 0xF2: HLT CYC(2) break; // invalid
case 0xF3: INDY_CONST INS CYC(8) break; // invalid
case 0xF4: zpx NOP CYC(4) break; // invalid
case 0xF5: zpx SBCn CYC(4) break;
case 0xF6: zpx INC CYC(6) break;
case 0xF7: zpx INS CYC(6) break; // invalid
case 0xF8: SED CYC(2) break;
case 0xF9: ABSY_OPT SBCn CYC(4) break;
case 0xFA: NOP CYC(2) break; // invalid
case 0xFB: ABSY_CONST INS CYC(7) break; // invalid
case 0xFC: ABSX_OPT NOP CYC(4) break; // invalid
case 0xFD: ABSX_OPT SBCn CYC(4) break;
case 0xFE: ABSX_CONST INC CYC(7) break;
case 0xFF: ABSX_CONST INS CYC(7) break; // invalid
}
#undef $
}
CheckInterruptSources(uExecutedCycles, bVideoUpdate);

View file

@ -25,9 +25,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
static DWORD Cpu65C02(DWORD uTotalCycles, const bool bVideoUpdate)
{
// Optimisation:
// . Copy the global /regs/ vars to stack-based local vars
// (Oliver Schmidt says this gives a performance gain, see email - The real deal: "1.10.5")
WORD addr;
BOOL flagc; // must always be 0 or 1, no other values allowed
BOOL flagn; // must always be 0 or 0x80.
@ -55,270 +52,269 @@ static DWORD Cpu65C02(DWORD uTotalCycles, const bool bVideoUpdate)
}
else
{
HEATMAP_X( regs.pc );
Fetch(iOpcode, uExecutedCycles);
//#define $ INV // INV = Invalid -> Debugger Break
#define $
switch (iOpcode)
{
case 0x00: BRK CYC(7) break;
case 0x01: idx ORA CYC(6) break;
case 0x02: $ IMM NOP CYC(2) break;
case 0x03: $ NOP CYC(1) break;
case 0x04: ZPG TSB CYC(5) break;
case 0x05: ZPG ORA CYC(3) break;
case 0x06: ZPG ASLc CYC(5) break;
case 0x07: $ NOP CYC(1) break;
case 0x08: PHP CYC(3) break;
case 0x09: IMM ORA CYC(2) break;
case 0x0A: asl CYC(2) break;
case 0x0B: $ NOP CYC(1) break;
case 0x0C: ABS TSB CYC(6) break;
case 0x0D: ABS ORA CYC(4) break;
case 0x0E: ABS ASLc CYC(6) break;
case 0x0F: $ NOP CYC(1) break;
case 0x10: REL BPL CYC(2) break;
case 0x11: INDY_OPT ORA CYC(5) break;
case 0x12: izp ORA CYC(5) break;
case 0x13: $ NOP CYC(1) break;
case 0x14: ZPG TRB CYC(5) break;
case 0x15: zpx ORA CYC(4) break;
case 0x16: zpx ASLc CYC(6) break;
case 0x17: $ NOP CYC(1) break;
case 0x18: CLC CYC(2) break;
case 0x19: ABSY_OPT ORA CYC(4) break;
case 0x1A: INA CYC(2) break;
case 0x1B: $ NOP CYC(1) break;
case 0x1C: ABS TRB CYC(6) break;
case 0x1D: ABSX_OPT ORA CYC(4) break;
case 0x1E: ABSX_OPT ASLc CYC(6) break;
case 0x1F: $ NOP CYC(1) break;
case 0x20: ABS JSR CYC(6) break;
case 0x21: idx AND CYC(6) break;
case 0x22: $ IMM NOP CYC(2) break;
case 0x23: $ NOP CYC(1) break;
case 0x24: ZPG BIT CYC(3) break;
case 0x25: ZPG AND CYC(3) break;
case 0x26: ZPG ROLc CYC(5) break;
case 0x27: $ NOP CYC(1) break;
case 0x28: PLP CYC(4) break;
case 0x29: IMM AND CYC(2) break;
case 0x2A: rol CYC(2) break;
case 0x2B: $ NOP CYC(1) break;
case 0x2C: ABS BIT CYC(4) break;
case 0x2D: ABS AND CYC(4) break;
case 0x2E: ABS ROLc CYC(6) break;
case 0x2F: $ NOP CYC(1) break;
case 0x30: REL BMI CYC(2) break;
case 0x31: INDY_OPT AND CYC(5) break;
case 0x32: izp AND CYC(5) break;
case 0x33: $ NOP CYC(1) break;
case 0x34: zpx BIT CYC(4) break;
case 0x35: zpx AND CYC(4) break;
case 0x36: zpx ROLc CYC(6) break;
case 0x37: $ NOP CYC(1) break;
case 0x38: SEC CYC(2) break;
case 0x39: ABSY_OPT AND CYC(4) break;
case 0x3A: DEA CYC(2) break;
case 0x3B: $ NOP CYC(1) break;
case 0x3C: ABSX_OPT BIT CYC(4) break;
case 0x3D: ABSX_OPT AND CYC(4) break;
case 0x3E: ABSX_OPT ROLc CYC(6) break;
case 0x3F: $ NOP CYC(1) break;
case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break;
case 0x41: idx EOR CYC(6) break;
case 0x42: $ IMM NOP CYC(2) break;
case 0x43: $ NOP CYC(1) break;
case 0x44: $ ZPG NOP CYC(3) break;
case 0x45: ZPG EOR CYC(3) break;
case 0x46: ZPG LSRc CYC(5) break;
case 0x47: $ NOP CYC(1) break;
case 0x48: PHA CYC(3) break;
case 0x49: IMM EOR CYC(2) break;
case 0x4A: lsr CYC(2) break;
case 0x4B: $ NOP CYC(1) break;
case 0x4C: ABS JMP CYC(3) break;
case 0x4D: ABS EOR CYC(4) break;
case 0x4E: ABS LSRc CYC(6) break;
case 0x4F: $ NOP CYC(1) break;
case 0x50: REL BVC CYC(2) break;
case 0x51: INDY_OPT EOR CYC(5) break;
case 0x52: izp EOR CYC(5) break;
case 0x53: $ NOP CYC(1) break;
case 0x54: $ zpx NOP CYC(4) break;
case 0x55: zpx EOR CYC(4) break;
case 0x56: zpx LSRc CYC(6) break;
case 0x57: $ NOP CYC(1) break;
case 0x58: CLI CYC(2) break;
case 0x59: ABSY_OPT EOR CYC(4) break;
case 0x5A: PHY CYC(3) break;
case 0x5B: $ NOP CYC(1) break;
case 0x5C: $ ABS NOP CYC(8) break;
case 0x5D: ABSX_OPT EOR CYC(4) break;
case 0x5E: ABSX_OPT LSRc CYC(6) break;
case 0x5F: $ NOP CYC(1) break;
case 0x60: RTS CYC(6) break;
case 0x61: idx ADCc CYC(6) break;
case 0x62: $ IMM NOP CYC(2) break;
case 0x63: $ NOP CYC(1) break;
case 0x64: ZPG STZ CYC(3) break;
case 0x65: ZPG ADCc CYC(3) break;
case 0x66: ZPG RORc CYC(5) break;
case 0x67: $ NOP CYC(1) break;
case 0x68: PLA CYC(4) break;
case 0x69: IMM ADCc CYC(2) break;
case 0x6A: ror CYC(2) break;
case 0x6B: $ NOP CYC(1) break;
case 0x6C: IABS_CMOS JMP CYC(6) break;
case 0x6D: ABS ADCc CYC(4) break;
case 0x6E: ABS RORc CYC(6) break;
case 0x6F: $ NOP CYC(1) break;
case 0x70: REL BVS CYC(2) break;
case 0x71: INDY_OPT ADCc CYC(5) break;
case 0x72: izp ADCc CYC(5) break;
case 0x73: $ NOP CYC(1) break;
case 0x74: zpx STZ CYC(4) break;
case 0x75: zpx ADCc CYC(4) break;
case 0x76: zpx RORc CYC(6) break;
case 0x77: $ NOP CYC(1) break;
case 0x78: SEI CYC(2) break;
case 0x79: ABSY_OPT ADCc CYC(4) break;
case 0x7A: PLY CYC(4) break;
case 0x7B: $ NOP CYC(1) break;
case 0x7C: IABSX JMP CYC(6) break;
case 0x7D: ABSX_OPT ADCc CYC(4) break;
case 0x7E: ABSX_OPT RORc CYC(6) break;
case 0x7F: $ NOP CYC(1) break;
case 0x80: REL BRA CYC(2) break;
case 0x81: idx STA CYC(6) break;
case 0x82: $ IMM NOP CYC(2) break;
case 0x83: $ NOP CYC(1) break;
case 0x84: ZPG STY CYC(3) break;
case 0x85: ZPG STA CYC(3) break;
case 0x86: ZPG STX CYC(3) break;
case 0x87: $ NOP CYC(1) break;
case 0x88: DEY CYC(2) break;
case 0x89: IMM BITI CYC(2) break;
case 0x8A: TXA CYC(2) break;
case 0x8B: $ NOP CYC(1) break;
case 0x8C: ABS STY CYC(4) break;
case 0x8D: ABS STA CYC(4) break;
case 0x8E: ABS STX CYC(4) break;
case 0x8F: $ NOP CYC(1) break;
case 0x90: REL BCC CYC(2) break;
case 0x91: INDY_CONST STA CYC(6) break;
case 0x92: izp STA CYC(5) break;
case 0x93: $ NOP CYC(1) break;
case 0x94: zpx STY CYC(4) break;
case 0x95: zpx STA CYC(4) break;
case 0x96: zpy STX CYC(4) break;
case 0x97: $ NOP CYC(1) break;
case 0x98: TYA CYC(2) break;
case 0x99: ABSY_CONST STA CYC(5) break;
case 0x9A: TXS CYC(2) break;
case 0x9B: $ NOP CYC(1) break;
case 0x9C: ABS STZ CYC(4) break;
case 0x9D: ABSX_CONST STA CYC(5) break;
case 0x9E: ABSX_CONST STZ CYC(5) break;
case 0x9F: $ NOP CYC(1) break;
case 0xA0: IMM LDY CYC(2) break;
case 0xA1: idx LDA CYC(6) break;
case 0xA2: IMM LDX CYC(2) break;
case 0xA3: $ NOP CYC(1) break;
case 0xA4: ZPG LDY CYC(3) break;
case 0xA5: ZPG LDA CYC(3) break;
case 0xA6: ZPG LDX CYC(3) break;
case 0xA7: $ NOP CYC(1) break;
case 0xA8: TAY CYC(2) break;
case 0xA9: IMM LDA CYC(2) break;
case 0xAA: TAX CYC(2) break;
case 0xAB: $ NOP CYC(1) break;
case 0xAC: ABS LDY CYC(4) break;
case 0xAD: ABS LDA CYC(4) break;
case 0xAE: ABS LDX CYC(4) break;
case 0xAF: $ NOP CYC(1) break;
case 0xB0: REL BCS CYC(2) break;
case 0xB1: INDY_OPT LDA CYC(5) break;
case 0xB2: izp LDA CYC(5) break;
case 0xB3: $ NOP CYC(1) break;
case 0xB4: zpx LDY CYC(4) break;
case 0xB5: zpx LDA CYC(4) break;
case 0xB6: zpy LDX CYC(4) break;
case 0xB7: $ NOP CYC(1) break;
case 0xB8: CLV CYC(2) break;
case 0xB9: ABSY_OPT LDA CYC(4) break;
case 0xBA: TSX CYC(2) break;
case 0xBB: $ NOP CYC(1) break;
case 0xBC: ABSX_OPT LDY CYC(4) break;
case 0xBD: ABSX_OPT LDA CYC(4) break;
case 0xBE: ABSY_OPT LDX CYC(4) break;
case 0xBF: $ NOP CYC(1) break;
case 0xC0: IMM CPY CYC(2) break;
case 0xC1: idx CMP CYC(6) break;
case 0xC2: $ IMM NOP CYC(2) break;
case 0xC3: $ NOP CYC(1) break;
case 0xC4: ZPG CPY CYC(3) break;
case 0xC5: ZPG CMP CYC(3) break;
case 0xC6: ZPG DEC CYC(5) break;
case 0xC7: $ NOP CYC(1) break;
case 0xC8: INY CYC(2) break;
case 0xC9: IMM CMP CYC(2) break;
case 0xCA: DEX CYC(2) break;
case 0xCB: $ NOP CYC(1) break;
case 0xCC: ABS CPY CYC(4) break;
case 0xCD: ABS CMP CYC(4) break;
case 0xCE: ABS DEC CYC(6) break;
case 0xCF: $ NOP CYC(1) break;
case 0xD0: REL BNE CYC(2) break;
case 0xD1: INDY_OPT CMP CYC(5) break;
case 0xD2: izp CMP CYC(5) break;
case 0xD3: $ NOP CYC(1) break;
case 0xD4: $ zpx NOP CYC(4) break;
case 0xD5: zpx CMP CYC(4) break;
case 0xD6: zpx DEC CYC(6) break;
case 0xD7: $ NOP CYC(1) break;
case 0xD8: CLD CYC(2) break;
case 0xD9: ABSY_OPT CMP CYC(4) break;
case 0xDA: PHX CYC(3) break;
case 0xDB: $ NOP CYC(1) break;
case 0xDC: $ ABS LDD CYC(4) break;
case 0xDD: ABSX_OPT CMP CYC(4) break;
case 0xDE: ABSX_CONST DEC CYC(7) break;
case 0xDF: $ NOP CYC(1) break;
case 0xE0: IMM CPX CYC(2) break;
case 0xE1: idx SBCc CYC(6) break;
case 0xE2: $ IMM NOP CYC(2) break;
case 0xE3: $ NOP CYC(1) break;
case 0xE4: ZPG CPX CYC(3) break;
case 0xE5: ZPG SBCc CYC(3) break;
case 0xE6: ZPG INC CYC(5) break;
case 0xE7: $ NOP CYC(1) break;
case 0xE8: INX CYC(2) break;
case 0xE9: IMM SBCc CYC(2) break;
case 0xEA: NOP CYC(2) break;
case 0xEB: $ NOP CYC(1) break;
case 0xEC: ABS CPX CYC(4) break;
case 0xED: ABS SBCc CYC(4) break;
case 0xEE: ABS INC CYC(6) break;
case 0xEF: $ NOP CYC(1) break;
case 0xF0: REL BEQ CYC(2) break;
case 0xF1: INDY_OPT SBCc CYC(5) break;
case 0xF2: izp SBCc CYC(5) break;
case 0xF3: $ NOP CYC(1) break;
case 0xF4: $ zpx NOP CYC(4) break;
case 0xF5: zpx SBCc CYC(4) break;
case 0xF6: zpx INC CYC(6) break;
case 0xF7: $ NOP CYC(1) break;
case 0xF8: SED CYC(2) break;
case 0xF9: ABSY_OPT SBCc CYC(4) break;
case 0xFA: PLX CYC(4) break;
case 0xFB: $ NOP CYC(1) break;
case 0xFC: $ ABS LDD CYC(4) break;
case 0xFD: ABSX_OPT SBCc CYC(4) break;
case 0xFE: ABSX_CONST INC CYC(7) break;
case 0xFF: $ NOP CYC(1) break;
// TODO-MP Optimization Note: ?? Move CYC(#) to array ??
case 0x00: BRK CYC(7) break;
case 0x01: idx ORA CYC(6) break;
case 0x02: IMM NOP CYC(2) break; // invalid
case 0x03: NOP CYC(1) break; // invalid
case 0x04: ZPG TSB CYC(5) break;
case 0x05: ZPG ORA CYC(3) break;
case 0x06: ZPG ASLc CYC(5) break;
case 0x07: NOP CYC(1) break; // invalid
case 0x08: PHP CYC(3) break;
case 0x09: IMM ORA CYC(2) break;
case 0x0A: asl CYC(2) break;
case 0x0B: NOP CYC(1) break; // invalid
case 0x0C: ABS TSB CYC(6) break;
case 0x0D: ABS ORA CYC(4) break;
case 0x0E: ABS ASLc CYC(6) break;
case 0x0F: NOP CYC(1) break; // invalid
case 0x10: REL BPL CYC(2) break;
case 0x11: INDY_OPT ORA CYC(5) break;
case 0x12: izp ORA CYC(5) break;
case 0x13: NOP CYC(1) break; // invalid
case 0x14: ZPG TRB CYC(5) break;
case 0x15: zpx ORA CYC(4) break;
case 0x16: zpx ASLc CYC(6) break;
case 0x17: NOP CYC(1) break; // invalid
case 0x18: CLC CYC(2) break;
case 0x19: ABSY_OPT ORA CYC(4) break;
case 0x1A: INA CYC(2) break;
case 0x1B: NOP CYC(1) break; // invalid
case 0x1C: ABS TRB CYC(6) break;
case 0x1D: ABSX_OPT ORA CYC(4) break;
case 0x1E: ABSX_OPT ASLc CYC(6) break;
case 0x1F: NOP CYC(1) break; // invalid
case 0x20: ABS JSR CYC(6) break;
case 0x21: idx AND CYC(6) break;
case 0x22: IMM NOP CYC(2) break; // invalid
case 0x23: NOP CYC(1) break; // invalid
case 0x24: ZPG BIT CYC(3) break;
case 0x25: ZPG AND CYC(3) break;
case 0x26: ZPG ROLc CYC(5) break;
case 0x27: NOP CYC(1) break; // invalid
case 0x28: PLP CYC(4) break;
case 0x29: IMM AND CYC(2) break;
case 0x2A: rol CYC(2) break;
case 0x2B: NOP CYC(1) break; // invalid
case 0x2C: ABS BIT CYC(4) break;
case 0x2D: ABS AND CYC(4) break;
case 0x2E: ABS ROLc CYC(6) break;
case 0x2F: NOP CYC(1) break; // invalid
case 0x30: REL BMI CYC(2) break;
case 0x31: INDY_OPT AND CYC(5) break;
case 0x32: izp AND CYC(5) break;
case 0x33: NOP CYC(1) break; // invalid
case 0x34: zpx BIT CYC(4) break;
case 0x35: zpx AND CYC(4) break;
case 0x36: zpx ROLc CYC(6) break;
case 0x37: NOP CYC(1) break; // invalid
case 0x38: SEC CYC(2) break;
case 0x39: ABSY_OPT AND CYC(4) break;
case 0x3A: DEA CYC(2) break;
case 0x3B: NOP CYC(1) break; // invalid
case 0x3C: ABSX_OPT BIT CYC(4) break;
case 0x3D: ABSX_OPT AND CYC(4) break;
case 0x3E: ABSX_OPT ROLc CYC(6) break;
case 0x3F: NOP CYC(1) break; // invalid
case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break;
case 0x41: idx EOR CYC(6) break;
case 0x42: IMM NOP CYC(2) break; // invalid
case 0x43: NOP CYC(1) break; // invalid
case 0x44: ZPG NOP CYC(3) break; // invalid
case 0x45: ZPG EOR CYC(3) break;
case 0x46: ZPG LSRc CYC(5) break;
case 0x47: NOP CYC(1) break; // invalid
case 0x48: PHA CYC(3) break;
case 0x49: IMM EOR CYC(2) break;
case 0x4A: lsr CYC(2) break;
case 0x4B: NOP CYC(1) break; // invalid
case 0x4C: ABS JMP CYC(3) break;
case 0x4D: ABS EOR CYC(4) break;
case 0x4E: ABS LSRc CYC(6) break;
case 0x4F: NOP CYC(1) break; // invalid
case 0x50: REL BVC CYC(2) break;
case 0x51: INDY_OPT EOR CYC(5) break;
case 0x52: izp EOR CYC(5) break;
case 0x53: NOP CYC(1) break; // invalid
case 0x54: zpx NOP CYC(4) break; // invalid
case 0x55: zpx EOR CYC(4) break;
case 0x56: zpx LSRc CYC(6) break;
case 0x57: NOP CYC(1) break; // invalid
case 0x58: CLI CYC(2) break;
case 0x59: ABSY_OPT EOR CYC(4) break;
case 0x5A: PHY CYC(3) break;
case 0x5B: NOP CYC(1) break; // invalid
case 0x5C: ABS NOP CYC(8) break; // invalid
case 0x5D: ABSX_OPT EOR CYC(4) break;
case 0x5E: ABSX_OPT LSRc CYC(6) break;
case 0x5F: NOP CYC(1) break; // invalid
case 0x60: RTS CYC(6) break;
case 0x61: idx ADCc CYC(6) break;
case 0x62: IMM NOP CYC(2) break; // invalid
case 0x63: NOP CYC(1) break; // invalid
case 0x64: ZPG STZ CYC(3) break;
case 0x65: ZPG ADCc CYC(3) break;
case 0x66: ZPG RORc CYC(5) break;
case 0x67: NOP CYC(1) break; // invalid
case 0x68: PLA CYC(4) break;
case 0x69: IMM ADCc CYC(2) break;
case 0x6A: ror CYC(2) break;
case 0x6B: NOP CYC(1) break; // invalid
case 0x6C: IABS_CMOS JMP CYC(6) break;
case 0x6D: ABS ADCc CYC(4) break;
case 0x6E: ABS RORc CYC(6) break;
case 0x6F: NOP CYC(1) break; // invalid
case 0x70: REL BVS CYC(2) break;
case 0x71: INDY_OPT ADCc CYC(5) break;
case 0x72: izp ADCc CYC(5) break;
case 0x73: NOP CYC(1) break; // invalid
case 0x74: zpx STZ CYC(4) break;
case 0x75: zpx ADCc CYC(4) break;
case 0x76: zpx RORc CYC(6) break;
case 0x77: NOP CYC(1) break; // invalid
case 0x78: SEI CYC(2) break;
case 0x79: ABSY_OPT ADCc CYC(4) break;
case 0x7A: PLY CYC(4) break;
case 0x7B: NOP CYC(1) break; // invalid
case 0x7C: IABSX JMP CYC(6) break;
case 0x7D: ABSX_OPT ADCc CYC(4) break;
case 0x7E: ABSX_OPT RORc CYC(6) break;
case 0x7F: NOP CYC(1) break; // invalid
case 0x80: REL BRA CYC(2) break;
case 0x81: idx STA CYC(6) break;
case 0x82: IMM NOP CYC(2) break; // invalid
case 0x83: NOP CYC(1) break; // invalid
case 0x84: ZPG STY CYC(3) break;
case 0x85: ZPG STA CYC(3) break;
case 0x86: ZPG STX CYC(3) break;
case 0x87: NOP CYC(1) break; // invalid
case 0x88: DEY CYC(2) break;
case 0x89: IMM BITI CYC(2) break;
case 0x8A: TXA CYC(2) break;
case 0x8B: NOP CYC(1) break; // invalid
case 0x8C: ABS STY CYC(4) break;
case 0x8D: ABS STA CYC(4) break;
case 0x8E: ABS STX CYC(4) break;
case 0x8F: NOP CYC(1) break; // invalid
case 0x90: REL BCC CYC(2) break;
case 0x91: INDY_CONST STA CYC(6) break;
case 0x92: izp STA CYC(5) break;
case 0x93: NOP CYC(1) break; // invalid
case 0x94: zpx STY CYC(4) break;
case 0x95: zpx STA CYC(4) break;
case 0x96: zpy STX CYC(4) break;
case 0x97: NOP CYC(1) break; // invalid
case 0x98: TYA CYC(2) break;
case 0x99: ABSY_CONST STA CYC(5) break;
case 0x9A: TXS CYC(2) break;
case 0x9B: NOP CYC(1) break; // invalid
case 0x9C: ABS STZ CYC(4) break;
case 0x9D: ABSX_CONST STA CYC(5) break;
case 0x9E: ABSX_CONST STZ CYC(5) break;
case 0x9F: NOP CYC(1) break; // invalid
case 0xA0: IMM LDY CYC(2) break;
case 0xA1: idx LDA CYC(6) break;
case 0xA2: IMM LDX CYC(2) break;
case 0xA3: NOP CYC(1) break; // invalid
case 0xA4: ZPG LDY CYC(3) break;
case 0xA5: ZPG LDA CYC(3) break;
case 0xA6: ZPG LDX CYC(3) break;
case 0xA7: NOP CYC(1) break; // invalid
case 0xA8: TAY CYC(2) break;
case 0xA9: IMM LDA CYC(2) break;
case 0xAA: TAX CYC(2) break;
case 0xAB: NOP CYC(1) break; // invalid
case 0xAC: ABS LDY CYC(4) break;
case 0xAD: ABS LDA CYC(4) break;
case 0xAE: ABS LDX CYC(4) break;
case 0xAF: NOP CYC(1) break; // invalid
case 0xB0: REL BCS CYC(2) break;
case 0xB1: INDY_OPT LDA CYC(5) break;
case 0xB2: izp LDA CYC(5) break;
case 0xB3: NOP CYC(1) break; // invalid
case 0xB4: zpx LDY CYC(4) break;
case 0xB5: zpx LDA CYC(4) break;
case 0xB6: zpy LDX CYC(4) break;
case 0xB7: NOP CYC(1) break; // invalid
case 0xB8: CLV CYC(2) break;
case 0xB9: ABSY_OPT LDA CYC(4) break;
case 0xBA: TSX CYC(2) break;
case 0xBB: NOP CYC(1) break; // invalid
case 0xBC: ABSX_OPT LDY CYC(4) break;
case 0xBD: ABSX_OPT LDA CYC(4) break;
case 0xBE: ABSY_OPT LDX CYC(4) break;
case 0xBF: NOP CYC(1) break; // invalid
case 0xC0: IMM CPY CYC(2) break;
case 0xC1: idx CMP CYC(6) break;
case 0xC2: IMM NOP CYC(2) break; // invalid
case 0xC3: NOP CYC(1) break; // invalid
case 0xC4: ZPG CPY CYC(3) break;
case 0xC5: ZPG CMP CYC(3) break;
case 0xC6: ZPG DEC CYC(5) break;
case 0xC7: NOP CYC(1) break; // invalid
case 0xC8: INY CYC(2) break;
case 0xC9: IMM CMP CYC(2) break;
case 0xCA: DEX CYC(2) break;
case 0xCB: NOP CYC(1) break; // invalid
case 0xCC: ABS CPY CYC(4) break;
case 0xCD: ABS CMP CYC(4) break;
case 0xCE: ABS DEC CYC(6) break;
case 0xCF: NOP CYC(1) break; // invalid
case 0xD0: REL BNE CYC(2) break;
case 0xD1: INDY_OPT CMP CYC(5) break;
case 0xD2: izp CMP CYC(5) break;
case 0xD3: NOP CYC(1) break; // invalid
case 0xD4: zpx NOP CYC(4) break; // invalid
case 0xD5: zpx CMP CYC(4) break;
case 0xD6: zpx DEC CYC(6) break;
case 0xD7: NOP CYC(1) break; // invalid
case 0xD8: CLD CYC(2) break;
case 0xD9: ABSY_OPT CMP CYC(4) break;
case 0xDA: PHX CYC(3) break;
case 0xDB: NOP CYC(1) break; // invalid
case 0xDC: ABS LDD CYC(4) break; // invalid
case 0xDD: ABSX_OPT CMP CYC(4) break;
case 0xDE: ABSX_CONST DEC CYC(7) break;
case 0xDF: NOP CYC(1) break; // invalid
case 0xE0: IMM CPX CYC(2) break;
case 0xE1: idx SBCc CYC(6) break;
case 0xE2: IMM NOP CYC(2) break; // invalid
case 0xE3: NOP CYC(1) break; // invalid
case 0xE4: ZPG CPX CYC(3) break;
case 0xE5: ZPG SBCc CYC(3) break;
case 0xE6: ZPG INC CYC(5) break;
case 0xE7: NOP CYC(1) break; // invalid
case 0xE8: INX CYC(2) break;
case 0xE9: IMM SBCc CYC(2) break;
case 0xEA: NOP CYC(2) break;
case 0xEB: NOP CYC(1) break; // invalid
case 0xEC: ABS CPX CYC(4) break;
case 0xED: ABS SBCc CYC(4) break;
case 0xEE: ABS INC CYC(6) break;
case 0xEF: NOP CYC(1) break; // invalid
case 0xF0: REL BEQ CYC(2) break;
case 0xF1: INDY_OPT SBCc CYC(5) break;
case 0xF2: izp SBCc CYC(5) break;
case 0xF3: NOP CYC(1) break; // invalid
case 0xF4: zpx NOP CYC(4) break; // invalid
case 0xF5: zpx SBCc CYC(4) break;
case 0xF6: zpx INC CYC(6) break;
case 0xF7: NOP CYC(1) break; // invalid
case 0xF8: SED CYC(2) break;
case 0xF9: ABSY_OPT SBCc CYC(4) break;
case 0xFA: PLX CYC(4) break;
case 0xFB: NOP CYC(1) break; // invalid
case 0xFC: ABS LDD CYC(4) break; // invalid
case 0xFD: ABSX_OPT SBCc CYC(4) break;
case 0xFE: ABSX_CONST INC CYC(7) break;
case 0xFF: NOP CYC(1) break; // invalid
}
#undef $
}
CheckInterruptSources(uExecutedCycles, bVideoUpdate);

View file

@ -1,426 +0,0 @@
/*
AppleWin : An Apple //e emulator for Windows
Copyright (C) 2010-2011, Tom Charlesworth, Michael Pohoreski
AppleWin 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.
AppleWin 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 AppleWin; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
typedef unsigned char u8; // TODO: change to <stdint.h> uint8_t
typedef unsigned short u16; // TODO: change to <stdint.h> uint16_t
// return (x < 255) ? (x+1) : 255;
inline u8 IncClamp8( u8 x )
{
u16 c = (~((x + 1) >> 8) & 1);
u8 r = x + c;
return r;
}
// return (x > 0) ? (x-1) : 0;
inline u8 DecClamp8( u8 x )
{
u16 c = (~((x - 1) >> 8) & 1);
u8 r = x - c;
return r;
}
// TODO: Verify: RGBA or BGRA (.bmp format)
// 0 A n/a
// 1 B Exec
// 2 G Read
// 3 R Write
//
// 0xAARRGGBB
// [0] B Exec
// [1] G Load
// [2] R Store
// [3] A n/a
// RGBA r = write, g = read, b = Program Counter
const int HEATMAP_W_MASK = 0x00FF0000; // Red Store
const int HEATMAP_R_MASK = 0x0000FF00; // Green Load
const int HEATMAP_X_MASK = 0x000000FF; // Blue Exec
// This is a memory heatmap
// FF = accessed on this clock cycle
// FE = accessed 1 clock cycles ago
// FD = accessed 2 clock cycles ago
// etc.
// Displayed as 256x256 64K memory access
int g_aMemoryHeatmap[ 65536 ]; // TODO: Change to <stdint.h> int32_t
#define HEATMAP_W(addr) g_aMemoryHeatmap[ addr ] |= HEATMAP_W_MASK
#define HEATMAP_R(addr) g_aMemoryHeatmap[ addr ] |= HEATMAP_R_MASK
#define HEATMAP_X(addr) g_aMemoryHeatmap[ addr ] |= HEATMAP_X_MASK
#undef READ
#define READ ReadByte( addr, uExecutedCycles )
inline u8 ReadByte( u16 addr, int uExecutedCycles )
{
// TODO: We should have a single g_bDebuggerActive so we can have a single implementation across ][+ //e
HEATMAP_R(addr);
return ((addr & 0xF000) == 0xC000)
? IORead[(addr>>4) & 0xFF](regs.pc,addr,0,0,uExecutedCycles)
: *(mem+addr);
}
#undef WRITE
#define WRITE(a) \
HEATMAP_W(addr); \
{ \
memdirty[addr >> 8] = 0xFF; \
LPBYTE page = memwrite[addr >> 8]; \
if (page) \
*(page+(addr & 0xFF)) = (BYTE)(a); \
else if ((addr & 0xF000) == 0xC000) \
IOWrite[(addr>>4) & 0xFF](regs.pc,addr,1,(BYTE)(a),uExecutedCycles); \
}
#include "CPU/cpu_instructions.inl"
//===========================================================================
// Michael's Real-Time Debugger/Visualizer CPU
// Based on Modified 65C02
static DWORD Cpu65D02(DWORD uTotalCycles, const bool bVideoUpdate)
{
// Optimisation:
// . Copy the global /regs/ vars to stack-based local vars
// (Oliver Schmidt says this gives a performance gain, see email - The real deal: "1.10.5")
WORD addr;
BOOL flagc; // must always be 0 or 1, no other values allowed
BOOL flagn; // must always be 0 or 0x80.
BOOL flagv; // any value allowed
BOOL flagz; // any value allowed
WORD temp;
WORD temp2;
WORD val;
AF_TO_EF
ULONG uExecutedCycles = 0;
WORD base;
do
{
UINT uExtraCycles = 0;
BYTE iOpcode;
// NTSC_BEGIN
ULONG uPreviousCycles = uExecutedCycles;
// NTSC_END
if (GetActiveCpu() == CPU_Z80)
{
const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles)
}
else
HEATMAP_X( regs.pc );
Fetch(iOpcode, uExecutedCycles);
// INV = Invalid -> Debugger Break
// MSVC C PreProcessor is BROKEN... #define @ INV
//#define # INV
//#define @ Read()
//#define $ Store()
//#define $ INV // INV = Invalid -> Debugger Break
#define $
switch (iOpcode)
{
// TODO Optimization Note: ?? Move CYC(#) to array ??
// Version 2 opcode: $ AM Instruction // $=DebugBreak AM=AddressingMode
//! ! ! ! ! ! // Tab-Stops
case 0x00: BRK CYC(7) break;
case 0x01: idx ORA CYC(6) break;
case 0x02: $ IMM NOP CYC(2) break;
case 0x03: $ NOP CYC(2) break;
case 0x04: ZPG TSB CYC(5) break;
case 0x05: ZPG ORA CYC(3) break;
case 0x06: ZPG ASLc CYC(5) break;
case 0x07: $ NOP CYC(2) break;
case 0x08: PHP CYC(3) break;
case 0x09: IMM ORA CYC(2) break;
case 0x0A: asl CYC(2) break;
case 0x0B: $ NOP CYC(2) break;
case 0x0C: ABS TSB CYC(6) break;
case 0x0D: ABS ORA CYC(4) break;
case 0x0E: ABS ASLc CYC(6) break;
case 0x0F: $ NOP CYC(2) break;
case 0x10: REL BPL CYC(2) break;
case 0x11: INDY_OPT ORA CYC(5) break;
case 0x12: izp ORA CYC(5) break;
case 0x13: $ NOP CYC(2) break;
case 0x14: ZPG TRB CYC(5) break;
case 0x15: zpx ORA CYC(4) break;
case 0x16: zpx ASLc CYC(6) break;
case 0x17: $ NOP CYC(2) break;
case 0x18: CLC CYC(2) break;
case 0x19: ABSY_OPT ORA CYC(4) break;
case 0x1A: INA CYC(2) break;
case 0x1B: $ NOP CYC(2) break;
case 0x1C: ABS TRB CYC(6) break;
case 0x1D: ABSX_OPT ORA CYC(4) break;
case 0x1E: ABSX_OPT ASLc CYC(6) break;
case 0x1F: $ NOP CYC(2) break;
case 0x20: ABS JSR CYC(6) break;
case 0x21: idx AND CYC(6) break;
case 0x22: $ IMM NOP CYC(2) break;
case 0x23: $ NOP CYC(2) break;
case 0x24: ZPG BIT CYC(3) break;
case 0x25: ZPG AND CYC(3) break;
case 0x26: ZPG ROLc CYC(5) break;
case 0x27: $ NOP CYC(2) break;
case 0x28: PLP CYC(4) break;
case 0x29: IMM AND CYC(2) break;
case 0x2A: rol CYC(2) break;
case 0x2B: $ NOP CYC(2) break;
case 0x2C: ABS BIT CYC(4) break;
case 0x2D: ABS AND CYC(2) break;
case 0x2E: ABS ROLc CYC(6) break;
case 0x2F: $ NOP CYC(2) break;
case 0x30: REL BMI CYC(2) break;
case 0x31: INDY_OPT AND CYC(5) break;
case 0x32: izp AND CYC(5) break;
case 0x33: $ NOP CYC(2) break;
case 0x34: zpx BIT CYC(4) break;
case 0x35: zpx AND CYC(4) break;
case 0x36: zpx ROLc CYC(6) break;
case 0x37: $ NOP CYC(2) break;
case 0x38: SEC CYC(2) break;
case 0x39: ABSY_OPT AND CYC(4) break;
case 0x3A: DEA CYC(2) break;
case 0x3B: $ NOP CYC(2) break;
case 0x3C: ABSX_OPT BIT CYC(4) break;
case 0x3D: ABSX_OPT AND CYC(4) break;
case 0x3E: ABSX_OPT ROLc CYC(6) break;
case 0x3F: $ NOP CYC(2) break;
case 0x40: RTI CYC(6) DoIrqProfiling(uExecutedCycles); break;
case 0x41: idx EOR CYC(6) break;
case 0x42: $ IMM NOP CYC(2) break;
case 0x43: $ NOP CYC(2) break;
case 0x44: $ ZPG NOP CYC(3) break;
case 0x45: ZPG EOR CYC(3) break;
case 0x46: ZPG LSRc CYC(5) break;
case 0x47: $ NOP CYC(2) break;
case 0x48: PHA CYC(3) break;
case 0x49: IMM EOR CYC(2) break;
case 0x4A: lsr CYC(2) break;
case 0x4B: $ NOP CYC(2) break;
case 0x4C: ABS JMP CYC(3) break;
case 0x4D: ABS EOR CYC(4) break;
case 0x4E: ABS LSRc CYC(6) break;
case 0x4F: $ NOP CYC(2) break;
case 0x50: REL BVC CYC(2) break;
case 0x51: INDY_OPT EOR CYC(5) break;
case 0x52: izp EOR CYC(5) break;
case 0x53: $ NOP CYC(2) break;
case 0x54: $ zpx NOP CYC(4) break;
case 0x55: zpx EOR CYC(4) break;
case 0x56: zpx LSRc CYC(6) break;
case 0x57: $ NOP CYC(2) break;
case 0x58: CLI CYC(2) break;
case 0x59: ABSY_OPT EOR CYC(4) break;
case 0x5A: PHY CYC(3) break;
case 0x5B: $ NOP CYC(2) break;
case 0x5C: $ ABSX_OPT NOP CYC(8) break;
case 0x5D: ABSX_OPT EOR CYC(4) break;
case 0x5E: ABSX_OPT LSRc CYC(6) break;
case 0x5F: $ NOP CYC(2) break;
case 0x60: RTS CYC(6) break;
case 0x61: idx ADCc CYC(6) break;
case 0x62: $ IMM NOP CYC(2) break;
case 0x63: $ NOP CYC(2) break;
case 0x64: ZPG STZ CYC(3) break;
case 0x65: ZPG ADCc CYC(3) break;
case 0x66: ZPG RORc CYC(5) break;
case 0x67: $ NOP CYC(2) break;
case 0x68: PLA CYC(4) break;
case 0x69: IMM ADCc CYC(2) break;
case 0x6A: ror CYC(2) break;
case 0x6B: $ NOP CYC(2) break;
case 0x6C: IABS_CMOS JMP CYC(6) break;
case 0x6D: ABS ADCc CYC(4) break;
case 0x6E: ABS RORc CYC(6) break;
case 0x6F: $ NOP CYC(2) break;
case 0x70: REL BVS CYC(2) break;
case 0x71: INDY_OPT ADCc CYC(5) break;
case 0x72: izp ADCc CYC(5) break;
case 0x73: $ NOP CYC(2) break;
case 0x74: zpx STZ CYC(4) break;
case 0x75: zpx ADCc CYC(4) break;
case 0x76: zpx RORc CYC(6) break;
case 0x77: $ NOP CYC(2) break;
case 0x78: SEI CYC(2) break;
case 0x79: ABSY_OPT ADCc CYC(4) break;
case 0x7A: PLY CYC(4) break;
case 0x7B: $ NOP CYC(2) break;
case 0x7C: IABSX JMP CYC(6) break;
case 0x7D: ABSX_OPT ADCc CYC(4) break;
case 0x7E: ABSX_OPT RORc CYC(6) break;
case 0x7F: $ NOP CYC(2) break;
case 0x80: REL BRA CYC(2) break;
case 0x81: idx STA CYC(6) break;
case 0x82: $ IMM NOP CYC(2) break;
case 0x83: $ NOP CYC(2) break;
case 0x84: ZPG STY CYC(3) break;
case 0x85: ZPG STA CYC(3) break;
case 0x86: ZPG STX CYC(3) break;
case 0x87: $ NOP CYC(2) break;
case 0x88: DEY CYC(2) break;
case 0x89: IMM BITI CYC(2) break;
case 0x8A: TXA CYC(2) break;
case 0x8B: $ NOP CYC(2) break;
case 0x8C: ABS STY CYC(4) break;
case 0x8D: ABS STA CYC(4) break;
case 0x8E: ABS STX CYC(4) break;
case 0x8F: $ NOP CYC(2) break;
case 0x90: REL BCC CYC(2) break;
case 0x91: INDY_CONST STA CYC(6) break;
case 0x92: izp STA CYC(5) break;
case 0x93: $ NOP CYC(2) break;
case 0x94: zpx STY CYC(4) break;
case 0x95: zpx STA CYC(4) break;
case 0x96: zpy STX CYC(4) break;
case 0x97: $ NOP CYC(2) break;
case 0x98: TYA CYC(2) break;
case 0x99: ABSY_CONST STA CYC(5) break;
case 0x9A: TXS CYC(2) break;
case 0x9B: $ NOP CYC(2) break;
case 0x9C: ABS STZ CYC(4) break;
case 0x9D: ABSX_CONST STA CYC(5) break;
case 0x9E: ABSX_CONST STZ CYC(5) break;
case 0x9F: $ NOP CYC(2) break;
case 0xA0: IMM LDY CYC(2) break;
case 0xA1: idx LDA CYC(6) break;
case 0xA2: IMM LDX CYC(2) break;
case 0xA3: $ NOP CYC(2) break;
case 0xA4: ZPG LDY CYC(3) break;
case 0xA5: ZPG LDA CYC(3) break;
case 0xA6: ZPG LDX CYC(3) break;
case 0xA7: $ NOP CYC(2) break;
case 0xA8: TAY CYC(2) break;
case 0xA9: IMM LDA CYC(2) break;
case 0xAA: TAX CYC(2) break;
case 0xAB: $ NOP CYC(2) break;
case 0xAC: ABS LDY CYC(4) break;
case 0xAD: ABS LDA CYC(4) break;
case 0xAE: ABS LDX CYC(4) break;
case 0xAF: $ NOP CYC(2) break;
case 0xB0: REL BCS CYC(2) break;
case 0xB1: INDY_OPT LDA CYC(5) break;
case 0xB2: izp LDA CYC(5) break;
case 0xB3: $ NOP CYC(2) break;
case 0xB4: zpx LDY CYC(4) break;
case 0xB5: zpx LDA CYC(4) break;
case 0xB6: zpy LDX CYC(4) break;
case 0xB7: $ NOP CYC(2) break;
case 0xB8: CLV CYC(2) break;
case 0xB9: ABSY_OPT LDA CYC(4) break;
case 0xBA: TSX CYC(2) break;
case 0xBB: $ NOP CYC(2) break;
case 0xBC: ABSX_OPT LDY CYC(4) break;
case 0xBD: ABSX_OPT LDA CYC(4) break;
case 0xBE: ABSY_OPT LDX CYC(4) break;
case 0xBF: $ NOP CYC(2) break;
case 0xC0: IMM CPY CYC(2) break;
case 0xC1: idx CMP CYC(6) break;
case 0xC2: $ IMM NOP CYC(2) break;
case 0xC3: $ NOP CYC(2) break;
case 0xC4: ZPG CPY CYC(3) break;
case 0xC5: ZPG CMP CYC(3) break;
case 0xC6: ZPG DEC CYC(5) break;
case 0xC7: $ NOP CYC(2) break;
case 0xC8: INY CYC(2) break;
case 0xC9: IMM CMP CYC(2) break;
case 0xCA: DEX CYC(2) break;
case 0xCB: $ NOP CYC(2) break;
case 0xCC: ABS CPY CYC(4) break;
case 0xCD: ABS CMP CYC(4) break;
case 0xCE: ABS DEC CYC(6) break;
case 0xCF: $ NOP CYC(2) break;
case 0xD0: REL BNE CYC(2) break;
case 0xD1: INDY_OPT CMP CYC(5) break;
case 0xD2: izp CMP CYC(5) break;
case 0xD3: $ NOP CYC(2) break;
case 0xD4: $ zpx NOP CYC(4) break;
case 0xD5: zpx CMP CYC(4) break;
case 0xD6: zpx DEC CYC(6) break;
case 0xD7: $ NOP CYC(2) break;
case 0xD8: CLD CYC(2) break;
case 0xD9: ABSY_OPT CMP CYC(4) break;
case 0xDA: PHX CYC(3) break;
case 0xDB: $ NOP CYC(2) break;
case 0xDC: $ ABSX_OPT NOP CYC(4) break;
case 0xDD: ABSX_OPT CMP CYC(4) break;
case 0xDE: ABSX_CONST DEC CYC(7) break;
case 0xDF: $ NOP CYC(2) break;
case 0xE0: IMM CPX CYC(2) break;
case 0xE1: idx SBCc CYC(6) break;
case 0xE2: $ IMM NOP CYC(2) break;
case 0xE3: $ NOP CYC(2) break;
case 0xE4: ZPG CPX CYC(3) break;
case 0xE5: ZPG SBCc CYC(3) break;
case 0xE6: ZPG INC CYC(5) break;
case 0xE7: $ NOP CYC(2) break;
case 0xE8: INX CYC(2) break;
case 0xE9: IMM SBCc CYC(2) break;
case 0xEA: NOP CYC(2) break;
case 0xEB: $ NOP CYC(2) break;
case 0xEC: ABS CPX CYC(4) break;
case 0xED: ABS SBCc CYC(4) break;
case 0xEE: ABS INC CYC(6) break;
case 0xEF: $ NOP CYC(2) break;
case 0xF0: REL BEQ CYC(2) break;
case 0xF1: INDY_OPT SBCc CYC(5) break;
case 0xF2: izp SBCc CYC(5) break;
case 0xF3: $ NOP CYC(2) break;
case 0xF4: $ zpx NOP CYC(4) break;
case 0xF5: zpx SBCc CYC(4) break;
case 0xF6: zpx INC CYC(6) break;
case 0xF7: $ NOP CYC(2) break;
case 0xF8: SED CYC(2) break;
case 0xF9: ABSY_OPT SBCc CYC(4) break;
case 0xFA: PLX CYC(4) break;
case 0xFB: $ NOP CYC(2) break;
case 0xFC: $ ABSX_OPT NOP CYC(4) break;
case 0xFD: ABSX_OPT SBCc CYC(4) break;
case 0xFE: ABSX_CONST INC CYC(7) break;
case 0xFF: $ NOP CYC(2) break;
}
#undef $
CheckInterruptSources(uExecutedCycles, bVideoUpdate);
NMI(uExecutedCycles, flagc, flagn, flagv, flagz);
IRQ(uExecutedCycles, flagc, flagn, flagv, flagz);
// NTSC_BEGIN
if (bVideoUpdate)
{
ULONG uElapsedCycles = uExecutedCycles - uPreviousCycles;
NTSC_VideoUpdateCycles( uElapsedCycles );
}
// NTSC_END
} while (uExecutedCycles < uTotalCycles);
EF_TO_AF // Emulator Flags to Apple Flags
return uExecutedCycles;
}

View file

@ -54,7 +54,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define PUSH(a) *(mem+regs.sp--) = (a); \
if (regs.sp < 0x100) \
regs.sp = 0x1FF;
#define READ ( \
#define _READ ( \
((addr & 0xF000) == 0xC000) \
? IORead[(addr>>4) & 0xFF](regs.pc,addr,0,0,uExecutedCycles) \
: *(mem+addr) \
@ -64,7 +64,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
flagz = !((a) & 0xFF); \
}
#define SETZ(a) flagz = !((a) & 0xFF);
#define WRITE(a) { \
#define _WRITE(a) { \
memdirty[addr >> 8] = 0xFF; \
LPBYTE page = memwrite[addr >> 8]; \
if (page) \

View file

@ -0,0 +1,60 @@
/*
AppleWin : An Apple //e emulator for Windows
Copyright (C) 1994-1996, Michael O'Brien
Copyright (C) 1999-2001, Oliver Schmidt
Copyright (C) 2002-2005, Tom Charlesworth
Copyright (C) 2006-2020, Tom Charlesworth, Michael Pohoreski
AppleWin 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.
AppleWin 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 AppleWin; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Description: 6502/65C02 emulation
*
* Author: Various
*/
/****************************************************************************
*
* RAM ACCESS MACROS (built-in debugger mode)
*
***/
inline void Heatmap_R(uint16_t address)
{
// todo
}
inline void Heatmap_W(uint16_t address)
{
// todo
}
inline void Heatmap_X(uint16_t address)
{
// todo
}
inline uint8_t Heatmap_ReadByte(uint16_t addr, int uExecutedCycles)
{
Heatmap_R(addr);
return _READ;
}
inline void Heatmap_WriteByte(uint16_t addr, uint16_t value, int uExecutedCycles)
{
Heatmap_W(addr);
_WRITE(value);
}

View file

@ -46,12 +46,12 @@ void CardManager::Insert(UINT slot, SS_CARDTYPE type)
switch (type)
{
case CT_Disk2:
m_slot[slot] = new Disk2InterfaceCard;
m_slot[slot] = new Disk2InterfaceCard(slot);
break;
case CT_SSC:
_ASSERT(m_pSSC == NULL);
if (m_pSSC) break; // Only support one SSC
m_slot[slot] = m_pSSC = new CSuperSerialCard;
m_slot[slot] = m_pSSC = new CSuperSerialCard(slot);
break;
case CT_MockingboardC:
m_slot[slot] = new DummyCard(type);

View file

@ -48,14 +48,15 @@ enum AppMode_e
// TODO: Move to StringTable.h
#define TITLE_APPLE_2 TEXT("Apple ][ Emulator")
#define TITLE_APPLE_2_PLUS TEXT("Apple ][+ Emulator")
#define TITLE_APPLE_2_JPLUS TEXT("Apple ][ J-Plus Emulator")
#define TITLE_APPLE_2E TEXT("Apple //e Emulator")
#define TITLE_APPLE_2E_ENHANCED TEXT("Enhanced Apple //e Emulator")
#define TITLE_APPLE_2C TEXT("Apple //e Emulator")
#define TITLE_APPLE_2D TEXT("Apple )(d Virtual Debug Hardware")
#define TITLE_PRAVETS_82 TEXT("Pravets 82 Emulator")
#define TITLE_PRAVETS_8M TEXT("Pravets 8M Emulator")
#define TITLE_PRAVETS_8A TEXT("Pravets 8A Emulator")
#define TITLE_TK3000_2E TEXT("TK3000 //e Emulator")
#define TITLE_BASE64A TEXT("Base64A Emulator")
#define TITLE_PAUSED TEXT("* PAUSED *")
#define TITLE_STEPPING TEXT("Stepping")
@ -152,15 +153,13 @@ enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE};
//e 10
//e+ 11
//c 20
//d 40
*/
#define APPLE2E_MASK 0x10
#define APPLE2C_MASK 0x20
#define APPLE2D_MASK 0x40
#define APPLECLONE_MASK 0x100
#define IS_APPLE2 ((g_Apple2Type & (APPLE2E_MASK|APPLE2C_MASK)) == 0)
#define IS_APPLE2E() (g_Apple2Type & APPLE2E_MASK)
//#define IS_APPLE2E() (g_Apple2Type & APPLE2E_MASK) // unused
#define IS_APPLE2C() (g_Apple2Type & APPLE2C_MASK)
#define IS_CLONE() (g_Apple2Type & APPLECLONE_MASK)
@ -168,16 +167,17 @@ enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE};
enum eApple2Type {
A2TYPE_APPLE2=0,
A2TYPE_APPLE2PLUS,
A2TYPE_APPLE2JPLUS,
A2TYPE_APPLE2E=APPLE2E_MASK,
A2TYPE_APPLE2EENHANCED,
A2TYPE_UNDEFINED,
A2TYPE_APPLE2C=APPLE2C_MASK,
A2TYPE_APPLE2D=APPLE2D_MASK,
// ][ clones start here:
A2TYPE_CLONE=APPLECLONE_MASK,
A2TYPE_PRAVETS8M, // Apple ][ clone
A2TYPE_PRAVETS82, // Apple ][ clone
A2TYPE_BASE64A, // Apple ][ clone
// (Gap for more Apple ][ clones)
A2TYPE_CLONE_A2_MAX,
@ -196,21 +196,31 @@ inline bool IsApple2Original(eApple2Type type) // Apple ][
return type == A2TYPE_APPLE2;
}
inline bool IsApple2Plus(eApple2Type type) // Apple ][,][+
inline bool IsApple2Plus(eApple2Type type) // Apple ][,][+,][J-Plus
{
return ((type & (APPLE2E_MASK|APPLE2C_MASK)) == 0) && !(type & APPLECLONE_MASK);
}
inline bool IsApple2JPlus(eApple2Type type) // Apple ][J-Plus
{
return type == A2TYPE_APPLE2JPLUS;
}
inline bool IsClone(eApple2Type type)
{
return (type & APPLECLONE_MASK) != 0;
}
inline bool IsApple2PlusOrClone(eApple2Type type) // Apple ][,][+ or clone ][,][+
inline bool IsApple2PlusOrClone(eApple2Type type) // Apple ][,][+,][J-Plus or clone ][,][+
{
return (type & (APPLE2E_MASK|APPLE2C_MASK)) == 0;
}
inline bool IsAppleIIeOrAbove(eApple2Type type) // Apple //e,Enhanced//e,//c or clone //e,Enhanced//e
{
return !IsApple2PlusOrClone(type);
}
extern eApple2Type g_Apple2Type;
inline bool IsEnhancedIIE(void)
{
@ -222,6 +232,11 @@ inline bool IsEnhancedIIEorIIC(void)
return ( (g_Apple2Type == A2TYPE_APPLE2EENHANCED) || (g_Apple2Type == A2TYPE_TK30002E) || IS_APPLE2C() );
}
inline bool IsCopamBase64A(eApple2Type type) // Copam Base64A
{
return type == A2TYPE_BASE64A;
}
enum eBUTTON {BUTTON0=0, BUTTON1};
enum eBUTTONSTATE {BUTTON_UP=0, BUTTON_DOWN};

View file

@ -33,12 +33,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
CPageAdvanced* CPageAdvanced::ms_this = 0; // reinit'd in ctor
enum CLONECHOICE {MENUITEM_CLONEMIN, MENUITEM_PRAVETS82=MENUITEM_CLONEMIN, MENUITEM_PRAVETS8M, MENUITEM_PRAVETS8A, MENUITEM_TK30002E, MENUITEM_CLONEMAX};
enum CLONECHOICE {MENUITEM_CLONEMIN, MENUITEM_PRAVETS82=MENUITEM_CLONEMIN, MENUITEM_PRAVETS8M, MENUITEM_PRAVETS8A, MENUITEM_TK30002E, MENUITEM_BASE64A, MENUITEM_CLONEMAX};
const TCHAR CPageAdvanced::m_CloneChoices[] =
TEXT("Pravets 82\0") // Bulgarian
TEXT("Pravets 8M\0") // Bulgarian
TEXT("Pravets 8A\0") // Bulgarian
TEXT("TK3000 //e\0"); // Brazilian
TEXT("TK3000 //e\0") // Brazilian
TEXT("Base 64A\0"); // Taiwanese
BOOL CALLBACK CPageAdvanced::DlgProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
{
@ -223,6 +225,7 @@ eApple2Type CPageAdvanced::GetCloneType(DWORD NewMenuItem)
case MENUITEM_PRAVETS8M: return A2TYPE_PRAVETS8M;
case MENUITEM_PRAVETS8A: return A2TYPE_PRAVETS8A;
case MENUITEM_TK30002E: return A2TYPE_TK30002E;
case MENUITEM_BASE64A: return A2TYPE_BASE64A;
default: return A2TYPE_PRAVETS82;
}
}
@ -250,6 +253,7 @@ int CPageAdvanced::GetCloneMenuItem(void)
case A2TYPE_PRAVETS8M: nMenuItem = MENUITEM_PRAVETS8M; break;
case A2TYPE_PRAVETS8A: nMenuItem = MENUITEM_PRAVETS8A; break;
case A2TYPE_TK30002E: nMenuItem = MENUITEM_TK30002E; break;
case A2TYPE_BASE64A: nMenuItem = MENUITEM_BASE64A; break;
default: // New clone needs adding here?
_ASSERT(0);
}

View file

@ -34,10 +34,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
CPageConfig* CPageConfig::ms_this = 0; // reinit'd in ctor
enum APPLEIICHOICE {MENUITEM_IIORIGINAL, MENUITEM_IIPLUS, MENUITEM_IIE, MENUITEM_ENHANCEDIIE, MENUITEM_CLONE};
enum APPLEIICHOICE {MENUITEM_IIORIGINAL, MENUITEM_IIPLUS, MENUITEM_IIJPLUS, MENUITEM_IIE, MENUITEM_ENHANCEDIIE, MENUITEM_CLONE};
const TCHAR CPageConfig::m_ComputerChoices[] =
TEXT("Apple ][ (Original)\0")
TEXT("Apple ][+\0")
TEXT("Apple ][ J-Plus\0")
TEXT("Apple //e\0")
TEXT("Enhanced Apple //e\0")
TEXT("Clone\0");
@ -182,12 +183,14 @@ BOOL CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPARAM
{
case A2TYPE_APPLE2: nCurrentChoice = MENUITEM_IIORIGINAL; break;
case A2TYPE_APPLE2PLUS: nCurrentChoice = MENUITEM_IIPLUS; break;
case A2TYPE_APPLE2JPLUS: nCurrentChoice = MENUITEM_IIJPLUS; break;
case A2TYPE_APPLE2E: nCurrentChoice = MENUITEM_IIE; break;
case A2TYPE_APPLE2EENHANCED:nCurrentChoice = MENUITEM_ENHANCEDIIE; break;
case A2TYPE_PRAVETS82: nCurrentChoice = MENUITEM_CLONE; break;
case A2TYPE_PRAVETS8M: nCurrentChoice = MENUITEM_CLONE; break;
case A2TYPE_PRAVETS8A: nCurrentChoice = MENUITEM_CLONE; break;
case A2TYPE_TK30002E: nCurrentChoice = MENUITEM_CLONE; break;
case A2TYPE_BASE64A: nCurrentChoice = MENUITEM_CLONE; break;
default: _ASSERT(0); break;
}
@ -380,6 +383,7 @@ eApple2Type CPageConfig::GetApple2Type(DWORD NewMenuItem)
{
case MENUITEM_IIORIGINAL: return A2TYPE_APPLE2;
case MENUITEM_IIPLUS: return A2TYPE_APPLE2PLUS;
case MENUITEM_IIJPLUS: return A2TYPE_APPLE2JPLUS;
case MENUITEM_IIE: return A2TYPE_APPLE2E;
case MENUITEM_ENHANCEDIIE: return A2TYPE_APPLE2EENHANCED;
case MENUITEM_CLONE: return A2TYPE_CLONE;

View file

@ -50,7 +50,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define ALLOW_INPUT_LOWERCASE 1
// See /docs/Debugger_Changelog.txt for full details
const int DEBUGGER_VERSION = MAKE_VERSION(2,9,0,15);
const int DEBUGGER_VERSION = MAKE_VERSION(2,9,1,0);
// Public _________________________________________________________________________________________
@ -440,10 +440,10 @@ bool DebugGetVideoMode(UINT* pVideoMode)
// File _______________________________________________________________________
int _GetFileSize( FILE *hFile )
size_t _GetFileSize( FILE *hFile )
{
fseek( hFile, 0, SEEK_END );
int nFileBytes = ftell( hFile );
size_t nFileBytes = ftell( hFile );
fseek( hFile, 0, SEEK_SET );
return nFileBytes;
@ -484,13 +484,17 @@ bool _Bookmark_Del( const WORD nAddress )
{
// g_aBookmarks.at( iBookmark ) = NO_6502_TARGET;
g_aBookmarks[ iBookmark ].bSet = false;
g_nBookmarks--;
bDeleted = true;
}
}
return bDeleted;
}
bool Bookmark_Find( const WORD nAddress )
// Returns:
// 0 if address does not have a bookmark set
// N+1 if there is an existing bookmark that has this address
int Bookmark_Find( const WORD nAddress )
{
// Ugh, linear search
// int nSize = g_aBookmarks.size();
@ -500,10 +504,10 @@ bool Bookmark_Find( const WORD nAddress )
if (g_aBookmarks[ iBookmark ].nAddress == nAddress)
{
if (g_aBookmarks[ iBookmark ].bSet)
return true;
return iBookmark + 1;
}
}
return false;
return 0;
}
@ -534,6 +538,8 @@ void _Bookmark_Reset()
{
g_aBookmarks[ iBookmark ].bSet = false;
}
g_nBookmarks = 0;
}
@ -598,15 +604,26 @@ Update_t CmdBookmarkAdd (int nArgs )
ConsoleDisplayPush( sText );
return ConsoleUpdate();
}
if ((iBookmark < MAX_BOOKMARKS) && (g_nBookmarks < MAX_BOOKMARKS))
// 2.9.0.16 Fixed: Replacing an existing bookmark incorrectly increased the total bookmark count.
int nOldBookmark = Bookmark_Find( nAddress );
if (nOldBookmark)
{
g_aBookmarks[iBookmark].bSet = true;
g_aBookmarks[iBookmark].nAddress = nAddress;
bAdded = true;
g_nBookmarks++;
iBookmark++;
_Bookmark_Del( nAddress );
}
// 2.9.0.17 Fixed: If all bookmarks were used then setting a new one wouldn't update an existing one to the new address.
if (g_aBookmarks[ iBookmark ].bSet)
{
g_aBookmarks[ iBookmark ].nAddress = nAddress;
bAdded = true;
}
else
if (g_nBookmarks < MAX_BOOKMARKS)
{
bAdded = _Bookmark_Add( iBookmark, nAddress );
iBookmark++;
}
}
if (!bAdded)
@ -632,11 +649,7 @@ Update_t CmdBookmarkClear (int nArgs)
{
if (! _tcscmp(g_aArgs[nArgs].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName))
{
for (iBookmark = 0; iBookmark < MAX_BOOKMARKS; iBookmark++ )
{
if (g_aBookmarks[ iBookmark ].bSet)
g_aBookmarks[ iBookmark ].bSet = false;
}
_Bookmark_Reset();
break;
}
@ -688,8 +701,6 @@ Update_t CmdBookmarkList (int nArgs)
//===========================================================================
Update_t CmdBookmarkLoad (int nArgs)
{
char sFilePath[ MAX_PATH ] = "";
if (nArgs == 1)
{
// strcpy( sMiniFileName, pFileName );
@ -978,7 +989,7 @@ Update_t CmdBreakInvalid (int nArgs) // Breakpoint IFF Full-speed!
return UPDATE_CONSOLE_DISPLAY;
_Help:
return HelpLastCommand();
return HelpLastCommand();
}
@ -1444,8 +1455,6 @@ Update_t CmdBreakpointAddPC (int nArgs)
g_aArgs[1].nValue = g_nDisasmCurAddress;
}
bool bHaveCmp = false;
// int iParamSrc;
int iParamCmp;
@ -1463,12 +1472,12 @@ Update_t CmdBreakpointAddPC (int nArgs)
{
switch (iParamCmp)
{
case PARAM_BP_LESS_EQUAL : iCmp = BP_OP_LESS_EQUAL ; bHaveCmp = true; break;
case PARAM_BP_LESS_THAN : iCmp = BP_OP_LESS_THAN ; bHaveCmp = true; break;
case PARAM_BP_EQUAL : iCmp = BP_OP_EQUAL ; bHaveCmp = true; break;
case PARAM_BP_NOT_EQUAL : iCmp = BP_OP_NOT_EQUAL ; bHaveCmp = true; break;
case PARAM_BP_GREATER_THAN : iCmp = BP_OP_GREATER_THAN ; bHaveCmp = true; break;
case PARAM_BP_GREATER_EQUAL: iCmp = BP_OP_GREATER_EQUAL; bHaveCmp = true; break;
case PARAM_BP_LESS_EQUAL : iCmp = BP_OP_LESS_EQUAL ; break;
case PARAM_BP_LESS_THAN : iCmp = BP_OP_LESS_THAN ; break;
case PARAM_BP_EQUAL : iCmp = BP_OP_EQUAL ; break;
case PARAM_BP_NOT_EQUAL : iCmp = BP_OP_NOT_EQUAL ; break;
case PARAM_BP_GREATER_THAN : iCmp = BP_OP_GREATER_THAN ; break;
case PARAM_BP_GREATER_EQUAL: iCmp = BP_OP_GREATER_EQUAL; break;
default:
break;
}
@ -1803,8 +1812,6 @@ Update_t CmdBreakpointSave (int nArgs)
//===========================================================================
Update_t _CmdAssemble( WORD nAddress, int iArg, int nArgs )
{
bool bHaveLabel = false;
// if AlphaNumeric
ArgToken_e iTokenSrc = NO_TOKEN;
ParserFindToken( g_pConsoleInput, g_aTokens, NUM_TOKENS, &iTokenSrc );
@ -1812,8 +1819,6 @@ Update_t _CmdAssemble( WORD nAddress, int iArg, int nArgs )
if (iTokenSrc == NO_TOKEN) // is TOKEN_ALPHANUMERIC
if (g_pConsoleInput[0] != CHAR_SPACE)
{
bHaveLabel = true;
// Symbol
char *pSymbolName = g_aArgs[ iArg ].sArg; // pArg->sArg;
SymbolUpdate( SYMBOLS_ASSEMBLY, pSymbolName, nAddress, false, true ); // bool bRemoveSymbol, bool bUpdateSymbol )
@ -3659,9 +3664,9 @@ Update_t CmdCursorPageUp4K (int nArgs)
}
//===========================================================================
Update_t CmdCursorSetPC( int nArgs) // TODO rename
Update_t CmdCursorSetPC(int)
{
regs.pc = nArgs; // HACK:
regs.pc = g_nDisasmCurAddress; // set PC to current cursor address
return UPDATE_DISASM;
}
@ -3768,7 +3773,8 @@ Update_t CmdDisk ( int nArgs)
goto _Help;
char buffer[200] = "";
ConsoleBufferPushFormat(buffer, "D%d at T$%s, phase $%s, offset $%X, mask $%02X, extraCycles %.2f, %s",
ConsoleBufferPushFormat(buffer, "FW%2d: D%d at T$%s, phase $%s, offset $%X, mask $%02X, extraCycles %.2f, %s",
diskCard.GetCurrentFirmware(),
diskCard.GetCurrentDrive() + 1,
diskCard.GetCurrentTrackString().c_str(),
diskCard.GetCurrentPhaseString().c_str(),
@ -4491,7 +4497,7 @@ Update_t CmdMemoryLoad (int nArgs)
FILE *hFile = fopen( sLoadSaveFilePath.c_str(), "rb" );
if (hFile)
{
int nFileBytes = _GetFileSize( hFile );
size_t nFileBytes = _GetFileSize( hFile );
if (nFileBytes > _6502_MEM_END)
nFileBytes = _6502_MEM_END + 1; // Bank-switched RAM/ROM is only 16-bit
@ -5364,7 +5370,7 @@ Update_t CmdNTSC (int nArgs)
*pDst++ = pTmp[3];
}
}
/*
// we duplicate phase 0 a total of 4 times
const size_t nBytesPerScanLine = 4096 * nBPP;
for( int iPhase = 1; iPhase < 4; iPhase++ )
@ -5925,11 +5931,6 @@ Update_t _CmdMemorySearch (int nArgs, bool bTextIsAscii = true )
return ConsoleDisplayError( TEXT("Error: Missing address seperator (comma or colon)" ) );
int iArgFirstByte = 4;
// S start,len #
int nMinLen = nArgs - (iArgFirstByte - 1);
bool bHaveWildCards = false;
int iArg;
MemorySearchValues_t vMemorySearchValues;
@ -6226,8 +6227,6 @@ Update_t CmdOutputCalc (int nArgs)
//===========================================================================
Update_t CmdOutputEcho (int nArgs)
{
TCHAR sText[ CONSOLE_WIDTH ] = TEXT("");
if (g_aArgs[1].bType & TYPE_QUOTED_2)
{
ConsoleDisplayPush( g_aArgs[1].sArg );
@ -6520,7 +6519,6 @@ Update_t CmdOutputRun (int nArgs)
if (script.Read( sFileName ))
{
int iLine = 0;
int nLine = script.GetNumLines();
Update_t bUpdateDisplay = UPDATE_NOTHING;
@ -6639,10 +6637,6 @@ bool ParseAssemblyListing( bool bBytesToMemory, bool bAddSymbols )
const DWORD INVALID_ADDRESS = _6502_MEM_END + 1;
bool bPrevSymbol = false;
bool bFourBytes = false;
BYTE nByte4 = 0;
int nLines = g_AssemblerSourceBuffer.GetNumLines();
for( int iLine = 0; iLine < nLines; iLine++ )
{
@ -6895,11 +6889,16 @@ Update_t CmdCyclesInfo(int nArgs)
else
{
if (strcmp(g_aArgs[1].sArg, "abs") == 0)
g_videoScannerDisplayInfo.isAbsCycle = true;
g_videoScannerDisplayInfo.cycleMode = VideoScannerDisplayInfo::abs;
else if (strcmp(g_aArgs[1].sArg, "rel") == 0)
g_videoScannerDisplayInfo.isAbsCycle = false;
g_videoScannerDisplayInfo.cycleMode = VideoScannerDisplayInfo::rel;
else if (strcmp(g_aArgs[1].sArg, "part") == 0)
g_videoScannerDisplayInfo.cycleMode = VideoScannerDisplayInfo::part;
else
return Help_Arg_1(CMD_CYCLES_INFO);
if (g_videoScannerDisplayInfo.cycleMode == VideoScannerDisplayInfo::part)
CmdCyclesReset(0);
}
TCHAR sText[CONSOLE_WIDTH];
@ -6909,6 +6908,12 @@ Update_t CmdCyclesInfo(int nArgs)
return UPDATE_ALL;
}
Update_t CmdCyclesReset(int /*nArgs*/)
{
g_videoScannerDisplayInfo.savedCumulativeCycles = g_nCumulativeCycles;
return UPDATE_ALL;
}
// View ___________________________________________________________________________________________
// See: CmdWindowViewOutput (int nArgs)
@ -8129,16 +8134,26 @@ Update_t ExecuteCommand (int nArgs)
//===========================================================================
void OutputTraceLine ()
{
if (!g_hTraceFile)
return;
DisasmLine_t line;
GetDisassemblyLine( regs.pc, line );
char sDisassembly[ CONSOLE_WIDTH ]; // DrawDisassemblyLine( 0,regs.pc, sDisassembly); // Get Disasm String
FormatDisassemblyLine( line, sDisassembly, CONSOLE_WIDTH );
char sFlags[ _6502_NUM_FLAGS + 1 ]; DrawFlags( 0, regs.ps, sFlags ); // Get Flags String
if (!g_hTraceFile)
return;
char sFlags[] = "........";
WORD nRegFlags = regs.ps;
int nFlag = _6502_NUM_FLAGS;
while (nFlag--)
{
int iFlag = (_6502_NUM_FLAGS - nFlag - 1);
bool bSet = (nRegFlags & 1);
if (bSet)
sFlags[nFlag] = g_aBreakpointSource[BP_SRC_FLAG_C + iFlag][0];
nRegFlags >>= 1;
}
if (g_bTraceHeader)
{
@ -8153,8 +8168,8 @@ void OutputTraceLine ()
else
{
fprintf( g_hTraceFile,
// "00 00 00 0000 -------- 0000:90 90 90 NOP"
"A: X: Y: SP: Flags Addr:Opcode Mnemonic\n");
// "00000000 00 00 00 0000 -------- 0000:90 90 90 NOP"
"Cycles A: X: Y: SP: Flags Addr:Opcode Mnemonic\n");
}
}
@ -8189,8 +8204,10 @@ void OutputTraceLine ()
}
else
{
const UINT cycles = (UINT)g_nCumulativeCycles;
fprintf( g_hTraceFile,
"%02X %02X %02X %04X %s %s\n",
"%08X %02X %02X %02X %04X %s %s\n",
cycles,
(unsigned)regs.a,
(unsigned)regs.x,
(unsigned)regs.y,
@ -8806,11 +8823,7 @@ void DebugDestroy ()
}
// TODO: DataDisassembly_Clear()
DeleteObject( g_hConsoleBrushFG );
DeleteObject( g_hConsoleBrushBG );
DeleteDC( g_hConsoleFontDC );
DeleteObject( g_hConsoleFontBitmap );
ReleaseConsoleFontDC();
}
@ -8853,67 +8866,13 @@ void DebugInitialize ()
#endif
// Must select a bitmap into the temp DC !
HDC hTmpDC = CreateCompatibleDC( FrameGetDC() );
// HDC hTmpDC = CreateCompatibleDC( FrameGetDC() );
#if _DEBUG
nError = GetLastError();
#endif
g_hConsoleFontDC = CreateCompatibleDC( FrameGetDC() );
#if _DEBUG
nError = GetLastError();
#endif
#if APPLE_FONT_NEW
// Pre-scaled bitmap
g_hConsoleFontBitmap = LoadBitmap(g_hInstance,TEXT("IDB_DEBUG_FONT_7x8"));
SelectObject( g_hConsoleFontDC, g_hConsoleFontBitmap );
#else
// Scale at run-time
// Black = Transparent
// White = Opaque
HBITMAP hTmpBitamp = LoadBitmap(g_hInstance,TEXT("CHARSET40"));
#if _DEBUG
nError = GetLastError();
#endif
SelectObject( hTmpDC ,hTmpBitamp);
#if _DEBUG
nError = GetLastError();
#endif
g_hConsoleFontBrush = GetStockBrush( WHITE_BRUSH );
SelectObject(g_hConsoleFontDC, g_hConsoleFontBrush );
// SelectObject(hTmpDC, g_hDebugFontBrush );
#if _DEBUG
nError = GetLastError();
#endif
g_hConsoleFontBitmap = CreateCompatibleBitmap(
hTmpDC,
APPLE_FONT_X_REGIONSIZE/2, APPLE_FONT_Y_REGIONSIZE/2
);
#if _DEBUG
nError = GetLastError();
#endif
SelectObject( g_hConsoleFontDC, g_hConsoleFontBitmap );
StretchBlt(
g_hConsoleFontDC, // HDC hdcDest, // handle to destination DC
0, 0, // int nXOriginDest, int nYOriginDest, // y-coord of destination upper-left corner
APPLE_FONT_X_REGIONSIZE/2, APPLE_FONT_Y_REGIONSIZE/2, // int nWidthDest, int nHeightDest,
hTmpDC, // HDC hdcSrc, // handle to source DC
0, APPLE_FONT_Y_APPLE_80COL, // int nXOriginSrc, int nYOriginSrc,
APPLE_FONT_X_REGIONSIZE, APPLE_FONT_Y_REGIONSIZE, // int nWidthSrc, int nHeightSrc,
SRCCOPY // DWORD dwRop // raster operation code
);
DeleteObject( hTmpBitamp );
DeleteObject( hTmpDC );
#endif
GetConsoleFontDC(); // Load font
ZeroMemory( g_aConsoleDisplay, sizeof( g_aConsoleDisplay ) ); // CONSOLE_WIDTH * CONSOLE_HEIGHT );
ConsoleInputReset();
@ -9609,7 +9568,7 @@ void DebuggerProcessKey( int keycode )
case VK_RIGHT:
if (KeybGetCtrlStatus())
bUpdateDisplay |= CmdCursorSetPC( g_nDisasmCurAddress );
bUpdateDisplay |= CmdCursorSetPC(0/*unused*/);
else
if (KeybGetShiftStatus())
bUpdateDisplay |= CmdCursorJumpPC( CURSOR_ALIGN_TOP );

View file

@ -135,7 +135,7 @@
// Prototypes _______________________________________________________________
// Bookmarks
bool Bookmark_Find( const WORD nAddress );
int Bookmark_Find( const WORD nAddress );
// Breakpoints
int CheckBreakpointsIO ();

View file

@ -787,8 +787,6 @@ bool _6502_GetTargetAddress ( const WORD & nAddress, WORD & nTarget_ )
iOpcode = _6502_GetOpmodeOpbyte( nAddress, iOpmode, nOpbytes );
// Composite string that has the target nAddress
// WORD nTarget = 0;
int nTargetOffset_ = 0;
if ((iOpmode != AM_IMPLIED) &&
(iOpmode != AM_1) &&
@ -796,10 +794,10 @@ bool _6502_GetTargetAddress ( const WORD & nAddress, WORD & nTarget_ )
(iOpmode != AM_3))
{
int nTargetPartial;
int nTargetPartial2;
int nTargetPointer;
WORD nTargetValue = 0; // de-ref
int nTargetBytes;
_6502_GetTargets( nAddress, &nTargetPartial, &nTargetPointer, &nTargetBytes, false );
_6502_GetTargets( nAddress, &nTargetPartial, &nTargetPartial2, &nTargetPointer, &nTargetBytes, false );
// if (nTargetPointer == NO_6502_TARGET)
// {
@ -870,9 +868,8 @@ int AssemblerHashMnemonic ( const TCHAR * pMnemonic )
const int NUM_MSK_BITS = 5; // 4 -> 5 prime
const Hash_t BIT_MSK_HIGH = ((1 << NUM_MSK_BITS) - 1) << NUM_LOW_BITS;
int nLen = strlen( pMnemonic );
#if DEBUG_ASSEMBLER
int nLen = strlen( pMnemonic );
static int nMaxLen = 0;
if (nMaxLen < nLen) {
nMaxLen = nLen;
@ -961,7 +958,7 @@ void _CmdAssembleHashDump ()
std::sort( vHashes.begin(), vHashes.end(), HashOpcode_t() );
Hash_t nPrevHash = vHashes.at( 0 ).m_nValue;
// Hash_t nPrevHash = vHashes.at( 0 ).m_nValue;
Hash_t nThisHash = 0;
for( iOpcode = 0; iOpcode < NUM_OPCODES; iOpcode++ )
@ -1097,7 +1094,7 @@ bool AssemblerGetArgs( int iArg, int nArgs, WORD nBaseAddress )
while (iArg < g_nArgRaw)
{
int iToken = pArg->eToken;
int iType = pArg->bType;
// int iType = pArg->bType;
if (iToken == TOKEN_HASH)
{

View file

@ -123,6 +123,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{TEXT("PAGEDOWN4K" ) , CmdCursorPageDown4K , CMD_CURSOR_PAGE_DOWN_4K , "Scroll down 4096 bytes" }, // Ctrl
// Cycles info
{TEXT("CYCLES") , CmdCyclesInfo , CMD_CYCLES_INFO, "Cycles display configuration" },
{TEXT("RCC") , CmdCyclesReset , CMD_CYCLES_RESET, "Reset cycles counter" },
// Disassembler Data
{TEXT("Z") , CmdDisasmDataDefByte1 , CMD_DISASM_DATA , "Treat byte [range] as data" },
{TEXT("X") , CmdDisasmDataDefCode , CMD_DISASM_CODE , "Treat byte [range] as code" },

View file

@ -354,7 +354,6 @@ void ConsoleBufferToDisplay ()
//===========================================================================
void ConsoleConvertFromText ( conchar_t * sText, const char * pText )
{
int x = 0;
const char *pSrc = pText;
conchar_t *pDst = sText;
while (pSrc && *pSrc)
@ -523,13 +522,6 @@ void ConsoleInputReset ()
g_aConsoleInput[0] = g_sConsolePrompt[0];
g_nConsolePromptLen = 1;
// int nLen = strlen( g_aConsoleInput );
#if CONSOLE_INPUT_CHAR16
int nLen = ConsoleLineLength( g_aConsoleInput );
#else
int nLen = strlen( g_aConsoleInput );
#endif
g_pConsoleInput = &g_aConsoleInput[ g_nConsolePromptLen ];
g_nConsoleInputChars = 0;
}

View file

@ -197,7 +197,7 @@ Update_t CmdDisasmDataList (int nArgs)
// Need to iterate through all blocks
DisasmData_t* pData = NULL;
while( pData = Disassembly_Enumerate( pData ) )
while( (pData = Disassembly_Enumerate( pData )) )
{
if (pData->iDirective != _NOP_REMOVED)
{

View file

@ -4,7 +4,8 @@ AppleWin : An Apple //e emulator for Windows
Copyright (C) 1994-1996, Michael O'Brien
Copyright (C) 1999-2001, Oliver Schmidt
Copyright (C) 2002-2005, Tom Charlesworth
Copyright (C) 2006-2014, Tom Charlesworth, Michael Pohoreski
Copyright (C) 2006-2019, Tom Charlesworth, Michael Pohoreski
Copyright (C) 2020, Tom Charlesworth, Michael Pohoreski, Cyril Lambin
AppleWin is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -23,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/* Description: Debugger
*
* Author: Copyright (C) 2006-2010 Michael Pohoreski
* Author: Copyright (C) 2006-2020 Michael Pohoreski, (C) 2020 Cyril Lambin
*/
#include "StdAfx.h"
@ -79,13 +80,23 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// Display - Win32
static HDC g_hDebuggerMemDC = NULL;
static HBITMAP g_hDebuggerMemBM = NULL;
static LPBITMAPINFO g_pDebuggerMemFramebufferinfo = NULL;
static bgra_t* g_pDebuggerMemFramebits = NULL;
HDC g_hConsoleFontDC = NULL;
HBRUSH g_hConsoleFontBrush = NULL;
HBITMAP g_hConsoleFontBitmap = NULL;
static HDC g_hConsoleFontDC = NULL;
static HBITMAP g_hConsoleFontBitmap = NULL;
static LPBITMAPINFO g_hConsoleFontFramebufferinfo = NULL;
static bgra_t* g_hConsoleFontFramebits;
HBRUSH g_hConsoleBrushFG = NULL;
HBRUSH g_hConsoleBrushBG = NULL;
char g_cConsoleBrushFG_r;
char g_cConsoleBrushFG_g;
char g_cConsoleBrushFG_b;
char g_cConsoleBrushBG_r;
char g_cConsoleBrushBG_g;
char g_cConsoleBrushBG_b;
static HBRUSH g_hConsoleBrushFG = NULL;
static HBRUSH g_hConsoleBrushBG = NULL;
// NOTE: Keep in sync ConsoleColors_e g_anConsoleColor !
COLORREF g_anConsoleColor[ NUM_CONSOLE_COLORS ] =
@ -164,7 +175,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
const int DISPLAY_MINIMEM_COLUMN = INFO_COL_3;
const int DISPLAY_VIDEO_SCANNER_COLUMN = INFO_COL_3;
#else
const int DISPLAY_CPU_INFO_LEFT_COLUMN = SCREENSPLIT1 // TC: SCREENSPLIT1 is not defined anywhere in the .sln!
const int DISPLAY_CPU_INFO_LEFT_COLUMN = SCREENSPLIT1; // TC: SCREENSPLIT1 is not defined anywhere in the .sln!
const int DISPLAY_REGS_COLUMN = DISPLAY_CPU_INFO_LEFT_COLUMN;
const int DISPLAY_FLAG_COLUMN = DISPLAY_CPU_INFO_LEFT_COLUMN;
@ -214,6 +225,7 @@ static char ColorizeSpecialChar( char * sText, BYTE nData, const MemoryView_e iV
void DrawSubWindow_Symbols (Update_t bUpdate);
void DrawSubWindow_ZeroPage (Update_t bUpdate);
void DrawWindowBottom ( Update_t bUpdate, int iWindow );
char* FormatCharCopy( char *pDst, const char *pSrc, const int nLen );
@ -541,7 +553,31 @@ HDC GetDebuggerMemDC(void)
{
HDC hFrameDC = FrameGetDC();
g_hDebuggerMemDC = CreateCompatibleDC(hFrameDC);
g_hDebuggerMemBM = CreateCompatibleBitmap(hFrameDC, GetFrameBufferWidth(), GetFrameBufferHeight());
// CREATE A BITMAPINFO STRUCTURE FOR THE FRAME BUFFER
g_pDebuggerMemFramebufferinfo = (LPBITMAPINFO)VirtualAlloc(
NULL,
sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD),
MEM_COMMIT,
PAGE_READWRITE);
ZeroMemory(g_pDebuggerMemFramebufferinfo, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
g_pDebuggerMemFramebufferinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
g_pDebuggerMemFramebufferinfo->bmiHeader.biWidth = 560;
g_pDebuggerMemFramebufferinfo->bmiHeader.biHeight = 384;
g_pDebuggerMemFramebufferinfo->bmiHeader.biPlanes = 1;
g_pDebuggerMemFramebufferinfo->bmiHeader.biBitCount = 32;
g_pDebuggerMemFramebufferinfo->bmiHeader.biCompression = BI_RGB;
g_pDebuggerMemFramebufferinfo->bmiHeader.biClrUsed = 0;
// CREATE THE FRAME BUFFER DIB SECTION
g_hDebuggerMemBM = CreateDIBSection(
hFrameDC,
g_pDebuggerMemFramebufferinfo,
DIB_RGB_COLORS,
(LPVOID*)&g_pDebuggerMemFramebits, 0, 0
);
SelectObject(g_hDebuggerMemDC, g_hDebuggerMemBM);
}
@ -557,10 +593,87 @@ void ReleaseDebuggerMemDC(void)
g_hDebuggerMemBM = NULL;
DeleteDC(g_hDebuggerMemDC);
g_hDebuggerMemDC = NULL;
FrameReleaseDC();
VirtualFree(g_pDebuggerMemFramebufferinfo, 0, MEM_RELEASE);
g_pDebuggerMemFramebufferinfo = NULL;
g_pDebuggerMemFramebits = NULL;
}
}
HDC GetConsoleFontDC(void)
{
if (!g_hConsoleFontDC)
{
HDC hFrameDC = FrameGetDC();
g_hConsoleFontDC = CreateCompatibleDC(hFrameDC);
// CREATE A BITMAPINFO STRUCTURE FOR THE FRAME BUFFER
g_hConsoleFontFramebufferinfo = (LPBITMAPINFO)VirtualAlloc(
NULL,
sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD),
MEM_COMMIT,
PAGE_READWRITE);
ZeroMemory(g_hConsoleFontFramebufferinfo, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
g_hConsoleFontFramebufferinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
g_hConsoleFontFramebufferinfo->bmiHeader.biWidth = CONSOLE_FONT_BITMAP_WIDTH;
g_hConsoleFontFramebufferinfo->bmiHeader.biHeight = CONSOLE_FONT_BITMAP_HEIGHT;
g_hConsoleFontFramebufferinfo->bmiHeader.biPlanes = 1;
g_hConsoleFontFramebufferinfo->bmiHeader.biBitCount = 32;
g_hConsoleFontFramebufferinfo->bmiHeader.biCompression = BI_RGB;
g_hConsoleFontFramebufferinfo->bmiHeader.biClrUsed = 0;
// CREATE THE FRAME BUFFER DIB SECTION
g_hConsoleFontBitmap = CreateDIBSection(
hFrameDC,
g_hConsoleFontFramebufferinfo,
DIB_RGB_COLORS,
(LPVOID*)&g_hConsoleFontFramebits, 0, 0
);
SelectObject(g_hConsoleFontDC, g_hConsoleFontBitmap);
// DRAW THE SOURCE IMAGE INTO THE SOURCE BIT BUFFER
HDC tmpDC = CreateCompatibleDC(hFrameDC);
// Pre-scaled bitmap
HBITMAP tmpFont = LoadBitmap(g_hInstance, TEXT("IDB_DEBUG_FONT_7x8")); // Bitmap must be 112x128 as defined above
SelectObject(tmpDC, tmpFont);
BitBlt(g_hConsoleFontDC, 0, 0, CONSOLE_FONT_BITMAP_WIDTH, CONSOLE_FONT_BITMAP_HEIGHT,
tmpDC, 0, 0,
SRCCOPY);
DeleteDC(tmpDC);
DeleteObject(tmpFont);
}
_ASSERT(g_hConsoleFontDC);
return g_hConsoleFontDC;
}
void ReleaseConsoleFontDC(void)
{
if (g_hConsoleFontDC)
{
DeleteDC( g_hConsoleFontDC );
g_hConsoleFontDC = NULL;
DeleteObject( g_hConsoleFontBitmap );
g_hConsoleFontBitmap = NULL;
VirtualFree(g_hConsoleFontFramebufferinfo, 0, MEM_RELEASE);
g_hConsoleFontFramebufferinfo = NULL;
g_hConsoleFontFramebits = NULL;
}
DeleteObject( g_hConsoleBrushFG );
g_hConsoleBrushFG = NULL;
DeleteObject( g_hConsoleBrushBG );
g_hConsoleBrushBG = NULL;
}
void StretchBltMemToFrameDC(void)
{
int nViewportCX, nViewportCY;
@ -594,7 +707,12 @@ void DebuggerSetColorFG( COLORREF nRGB )
g_hConsoleBrushFG = NULL;
}
g_hConsoleBrushFG = CreateSolidBrush( nRGB );
g_hConsoleBrushFG = CreateSolidBrush(nRGB);
g_cConsoleBrushFG_r = nRGB & 0xFF;
g_cConsoleBrushFG_g = (nRGB>>8) & 0xFF;
g_cConsoleBrushFG_b = (nRGB>>16) & 0xFF;
#else
SetTextColor( GetDebuggerMemDC(), nRGB );
#endif
@ -615,6 +733,12 @@ void DebuggerSetColorBG( COLORREF nRGB, bool bTransparent )
{
g_hConsoleBrushBG = CreateSolidBrush( nRGB );
}
// Transparency seems to be never used...
g_cConsoleBrushBG_r = nRGB & 0xFF;
g_cConsoleBrushBG_g = (nRGB >> 8) & 0xFF;
g_cConsoleBrushBG_b = (nRGB >> 16) & 0xFF;
#else
SetBkColor( GetDebuggerMemDC(), nRGB );
#endif
@ -622,31 +746,28 @@ void DebuggerSetColorBG( COLORREF nRGB, bool bTransparent )
// @param glyph Specifies a native glyph from the 16x16 chars Apple Font Texture.
//===========================================================================
void PrintGlyph( const int x, const int y, const char glyph )
static void PrintGlyph( const int xDst, const int yDst, const int glyph )
{
HDC hDstDC = GetDebuggerMemDC();
int xDst = x;
int yDst = y;
// 16x8 chars in bitmap
int xSrc = (glyph & 0x0F) * CONSOLE_FONT_GRID_X;
int ySrc = (glyph >> 4) * CONSOLE_FONT_GRID_Y;
int xSrc = (glyph % CONSOLE_FONT_NUM_CHARS_PER_ROW) * CONSOLE_FONT_GRID_X;
int ySrc = (glyph / CONSOLE_FONT_NUM_CHARS_PER_ROW) * CONSOLE_FONT_GRID_Y;
_ASSERT(ySrc < CONSOLE_FONT_BITMAP_HEIGHT);
// BUG #239 - (Debugger) Save debugger "text screen" to clipboard / file
// if( g_bDebuggerVirtualTextCapture )
//
{
#if _DEBUG
if ((x < 0) || (y < 0))
if ((xDst < 0) || (yDst < 0))
MessageBox( g_hFrameWindow, "X or Y out of bounds!", "PrintGlyph()", MB_OK );
#endif
int col = x / CONSOLE_FONT_WIDTH ;
int row = y / CONSOLE_FONT_HEIGHT;
int col = xDst / CONSOLE_FONT_WIDTH ;
int row = yDst / CONSOLE_FONT_HEIGHT;
// if( !g_bDebuggerCopyInfoPane )
// if( col < 50
if (x > DISPLAY_DISASM_RIGHT) // INFO_COL_2 // DISPLAY_CPU_INFO_LEFT_COLUMN
if (xDst > DISPLAY_DISASM_RIGHT) // INFO_COL_2 // DISPLAY_CPU_INFO_LEFT_COLUMN
col++;
if ((col < DEBUG_VIRTUAL_TEXT_WIDTH)
@ -654,74 +775,21 @@ void PrintGlyph( const int x, const int y, const char glyph )
g_aDebuggerVirtualTextScreen[ row ][ col ] = glyph;
}
#if !DEBUG_FONT_NO_BACKGROUND_CHAR
// Background color
if (g_hConsoleBrushBG)
// Manual print of character. A lot faster than BitBlt, which must be avoided.
int index_src = (CONSOLE_FONT_BITMAP_HEIGHT - 1 - ySrc) * CONSOLE_FONT_NUM_CHARS_PER_ROW * CONSOLE_FONT_GRID_X + xSrc; // font bitmap
int index_dst = (DISPLAY_HEIGHT - 1 - yDst) * DEBUG_VIRTUAL_TEXT_WIDTH * CONSOLE_FONT_GRID_X + xDst; // debugger bitmap
for (int yy = 0; yy < CONSOLE_FONT_GRID_Y; yy++)
{
SelectObject( hDstDC, g_hConsoleBrushBG );
// Draw Background (solid pattern)
BitBlt(
hDstDC, // hdcDest
xDst, yDst, // nXDest, nYDest
CONSOLE_FONT_WIDTH, CONSOLE_FONT_HEIGHT, // nWidth, nHeight
g_hConsoleFontDC, // hdcSrc
0, CONSOLE_FONT_GRID_Y * 2, // nXSrc, nYSrc // FontTexture[2][0] = Solid (Filled) Space
PATCOPY // dwRop
);
for (int xx = 0; xx < CONSOLE_FONT_GRID_X; xx++)
{
char fontpx = g_hConsoleFontFramebits[index_src + xx].g; // Should be same for R/G/B anyway (greyscale)
g_pDebuggerMemFramebits[index_dst + xx].r = (g_cConsoleBrushBG_r & ~fontpx) | (g_cConsoleBrushFG_r & fontpx);
g_pDebuggerMemFramebits[index_dst + xx].g = (g_cConsoleBrushBG_g & ~fontpx) | (g_cConsoleBrushFG_g & fontpx);
g_pDebuggerMemFramebits[index_dst + xx].b = (g_cConsoleBrushBG_b & ~fontpx) | (g_cConsoleBrushFG_b & fontpx);
}
index_src -= CONSOLE_FONT_NUM_CHARS_PER_ROW * CONSOLE_FONT_GRID_X;
index_dst -= DEBUG_VIRTUAL_TEXT_WIDTH * CONSOLE_FONT_GRID_X;
}
#endif
// SelectObject( hDstDC, GetStockBrush( WHITE_BRUSH ) );
// http://kkow.net/etep/docs/rop.html
// P 1 1 1 1 0 0 0 0 (Pen/Pattern)
// S 1 1 0 0 1 1 0 0 (Source)
// D 1 0 1 0 1 0 1 0 (Destination)
// =================
// 0 0 1 0 0 0 1 0 0x22 DSna
// 1 1 1 0 1 0 1 0 0xEA DPSao
// Black = Transparent (DC Background)
// White = Opaque (DC Text color)
#if DEBUG_FONT_ROP
SelectObject( hDstDC, g_hConsoleBrushFG );
BitBlt(
hDstDC,
xDst, yDst,
DEBUG_FONT_WIDTH, DEBUG_FONT_HEIGHT,
g_hDebugFontDC,
xSrc, ySrc,
aROP4[ iRop4 ]
);
#else
// Use inverted source as mask (AND)
// D & ~S -> DSna
BitBlt(
hDstDC,
xDst, yDst,
CONSOLE_FONT_WIDTH, CONSOLE_FONT_HEIGHT,
g_hConsoleFontDC,
xSrc, ySrc,
DSna
);
SelectObject( hDstDC, g_hConsoleBrushFG );
// Use Source as mask to make color Pattern mask (AND), then apply to dest (OR)
// D | (P & S) -> DPSao
BitBlt(
hDstDC,
xDst, yDst,
CONSOLE_FONT_WIDTH, CONSOLE_FONT_HEIGHT,
g_hConsoleFontDC,
xSrc, ySrc,
DPSao
);
#endif
SelectObject( hDstDC, GetStockObject(NULL_BRUSH) );
}
@ -814,7 +882,7 @@ int PrintText ( const char * pText, RECT & rRect )
int nLen = strlen( pText );
#if !DEBUG_FONT_NO_BACKGROUND_TEXT
FillRect( GetDebuggerMemDC(), &rRect, g_hConsoleBrushBG );
FillBackground(rRect.left, rRect.top, rRect.right, rRect.bottom);
#endif
DebuggerPrint( rRect.left, rRect.top, pText );
@ -825,12 +893,37 @@ int PrintText ( const char * pText, RECT & rRect )
void PrintTextColor ( const conchar_t *pText, RECT & rRect )
{
#if !DEBUG_FONT_NO_BACKGROUND_TEXT
FillRect( GetDebuggerMemDC(), &rRect, g_hConsoleBrushBG );
FillBackground(rRect.left, rRect.top, rRect.right, rRect.bottom);
#endif
DebuggerPrintColor( rRect.left, rRect.top, pText );
}
//===========================================================================
void FillBackground(long left, long top, long right, long bottom)
{
long index_dst = (384-bottom) * 80 * CONSOLE_FONT_GRID_X;
for (long x = left; x < right; x++)
{
g_pDebuggerMemFramebits[index_dst + x].r = g_cConsoleBrushBG_r;
g_pDebuggerMemFramebits[index_dst + x].g = g_cConsoleBrushBG_g;
g_pDebuggerMemFramebits[index_dst + x].b = g_cConsoleBrushBG_b;
}
if (top != bottom)
{
bgra_t* src = g_pDebuggerMemFramebits + (index_dst + left);
bgra_t* dst = src + (80 * CONSOLE_FONT_GRID_X);
size_t size = (right - left) * sizeof(bgra_t);
for (int i = 0; i < bottom - top - 1; i++)
{
memcpy((void*)dst, (void*)src, size);
dst += 80 * CONSOLE_FONT_GRID_X ;
}
}
}
// Updates the horizontal cursor
//===========================================================================
int PrintTextCursorX ( const char * pText, RECT & rRect )
@ -968,7 +1061,6 @@ char ColorizeSpecialChar( char * sText, BYTE nData, const MemoryView_e iView,
const int iCtrlBackground /*= BG_INFO_CHAR*/, const int iCtrlForeground /*= FG_INFO_CHAR_LO*/ )
{
bool bHighBit = false;
bool bAsciBit = false;
bool bCtrlBit = false;
int iTextBG = iAsciBackground;
@ -1061,7 +1153,6 @@ void DrawBreakpoints ( int line )
rect.right = DISPLAY_WIDTH;
rect.bottom = rect.top + g_nFontHeight;
const int MAX_BP_LEN = 16;
char sText[16] = "Breakpoints"; // TODO: Move to BP1
#if DISPLAY_BREAKPOINT_TITLE
@ -1406,7 +1497,7 @@ int GetDisassemblyLine ( WORD nBaseAddress, DisasmLine_t & line_ )
(iOpmode != AM_3))
{
// Assume target address starts after the opcode ...
// BUT in the Assembler Directve / Data Disassembler case for define addr/word
// BUT in the Assembler Directive / Data Disassembler case for define addr/word
// the opcode literally IS the target address!
if( pData )
{
@ -1670,10 +1761,10 @@ void FormatOpcodeBytes ( WORD nBaseAddress, DisasmLine_t & line_ )
void FormatNopcodeBytes ( WORD nBaseAddress, DisasmLine_t & line_ )
{
char *pDst = line_.sTarget;
const char *pSrc = 0;
const char *pSrc = 0;
DWORD nStartAddress = line_.pDisasmData->nStartAddress;
DWORD nEndAddress = line_.pDisasmData->nEndAddress ;
int nDataLen = nEndAddress - nStartAddress + 1 ;
// int nDataLen = nEndAddress - nStartAddress + 1 ;
int nDisplayLen = nEndAddress - nBaseAddress + 1 ; // *inclusive* KEEP IN SYNC: _CmdDefineByteRange() CmdDisasmDataList() _6502_GetOpmodeOpbyte() FormatNopcodeBytes()
int len = nDisplayLen;
@ -1827,7 +1918,7 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA))))
return 0;
int iOpcode;
// int iOpcode;
int iOpmode;
int nOpbyte;
DisasmLine_t line;
@ -1838,7 +1929,7 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
int bDisasmFormatFlags = GetDisassemblyLine( nBaseAddress, line );
const DisasmData_t *pData = line.pDisasmData;
iOpcode = line.iOpcode;
// iOpcode = line.iOpcode;
iOpmode = line.iOpmode;
nOpbyte = line.nOpbyte;
@ -1891,7 +1982,6 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
aTabs[ TS_IMMEDIATE ] -= 1;
}
#endif
const int OPCODE_TO_LABEL_SPACE = static_cast<int>( aTabs[ TS_INSTRUCTION ] - aTabs[ TS_LABEL ] );
int iTab = 0;
int nSpacer = 11; // 9
@ -1917,12 +2007,6 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
aTabs[ iTab ] *= nDefaultFontWidth;
}
#if USE_APPLE_FONT
const int DISASM_SYMBOL_LEN = 12;
#else
const int DISASM_SYMBOL_LEN = 9;
#endif
int nFontHeight = g_aFontConfig[ FONT_DISASM_DEFAULT ]._nLineHeight; // _nFontHeight; // g_nFontHeight
RECT linerect;
@ -1935,7 +2019,7 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
bool bBreakpointEnable;
GetBreakpointInfo( nBaseAddress, bBreakpointActive, bBreakpointEnable );
bool bAddressAtPC = (nBaseAddress == regs.pc);
bool bAddressIsBookmark = Bookmark_Find( nBaseAddress );
int bAddressIsBookmark = Bookmark_Find( nBaseAddress );
DebugColors_e iBackground = BG_DISASM_1;
DebugColors_e iForeground = FG_DISASM_MNEMONIC; // FG_DISASM_TEXT;
@ -2005,16 +2089,8 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
}
}
if (bAddressIsBookmark)
{
DebuggerSetColorBG( DebuggerGetColor( BG_DISASM_BOOKMARK ) );
DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_BOOKMARK ) );
}
else
{
DebuggerSetColorBG( DebuggerGetColor( iBackground ) );
DebuggerSetColorFG( DebuggerGetColor( iForeground ) );
}
DebuggerSetColorBG( DebuggerGetColor( iBackground ) );
DebuggerSetColorFG( DebuggerGetColor( iForeground ) );
// Address
if (! bCursorLine)
@ -2030,18 +2106,31 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
PrintTextCursorX( (LPCTSTR) line.sAddress, linerect );
}
if (bAddressIsBookmark)
{
DebuggerSetColorBG( DebuggerGetColor( iBackground ) );
DebuggerSetColorFG( DebuggerGetColor( iForeground ) );
}
// Address Seperator
if (! bCursorLine)
DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR ) );
if (g_bConfigDisasmAddressColon)
PrintTextCursorX( ":", linerect );
{
if (bAddressIsBookmark)
{
DebuggerSetColorBG( DebuggerGetColor( BG_DISASM_BOOKMARK ) );
DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_BOOKMARK ) );
// Can't use PrintTextCursorX() as that clamps chars > 0x7F to Mouse Text
// char bookmark_text[2] = { 0x7F + bAddressIsBookmark, 0 };
// PrintTextCursorX( bookmark_text, linerect );
FillRect( GetDebuggerMemDC(), &linerect, g_hConsoleBrushBG );
PrintGlyph( linerect.left, linerect.top, 0x7F + bAddressIsBookmark ); // Glyphs 0x80 .. 0x89 = Unicode U+24EA, U+2460 .. U+2468
linerect.left += g_aFontConfig[ FONT_DISASM_DEFAULT ]._nFontWidthAvg;
DebuggerSetColorBG( DebuggerGetColor( iBackground ) );
DebuggerSetColorFG( DebuggerGetColor( iForeground ) );
}
else
PrintTextCursorX( ":", linerect );
}
else
PrintTextCursorX( " ", linerect ); // bugfix, not showing "addr:" doesn't alternate color lines
@ -2335,9 +2424,8 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
}
// Optionally copy the flags to pText_
//===========================================================================
void DrawFlags ( int line, WORD nRegFlags, LPTSTR pFlagNames_)
static void DrawFlags ( int line, WORD nRegFlags )
{
if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA))))
return;
@ -2426,19 +2514,8 @@ void DrawFlags ( int line, WORD nRegFlags, LPTSTR pFlagNames_)
rect.top -= g_nFontHeight;
rect.bottom -= g_nFontHeight;
if (pFlagNames_)
{
if (!bSet)
sFlagNames[nFlag] = '.';
else
sFlagNames[nFlag] = g_aBreakpointSource[ BP_SRC_FLAG_C + iFlag ][0];
}
nRegFlags >>= 1;
}
if (pFlagNames_)
strcpy(pFlagNames_,sFlagNames);
}
//===========================================================================
@ -2477,7 +2554,6 @@ void DrawMemory ( int line, int iMemDump )
const int MAX_MEM_VIEW_TXT = 16;
char sText[ MAX_MEM_VIEW_TXT * 2 ];
char sData[ MAX_MEM_VIEW_TXT * 2 ];
char sType [ 6 ] = "Mem";
char sAddress[ 8 ] = "";
@ -2524,8 +2600,6 @@ void DrawMemory ( int line, int iMemDump )
rect.top = rect2.top;
rect.bottom = rect2.bottom;
sData[0] = 0;
WORD iAddress = nAddr;
int nLines = g_nDisplayMemoryLines;
@ -2562,9 +2636,6 @@ void DrawMemory ( int line, int iMemDump )
for (int iCol = 0; iCol < nCols; iCol++)
{
bool bHiBit = false;
bool bLoBit = false;
DebuggerSetColorBG( DebuggerGetColor( iBackground ));
DebuggerSetColorFG( DebuggerGetColor( iForeground ));
@ -2596,8 +2667,6 @@ void DrawMemory ( int line, int iMemDump )
BYTE nData = (unsigned)*(LPBYTE)(mem+iAddress);
sText[0] = 0;
char c = nData;
if (iView == MEM_VIEW_HEX)
{
if ((iAddress >= _6502_IO_BEGIN) && (iAddress <= _6502_IO_END))
@ -2626,7 +2695,6 @@ void DrawMemory ( int line, int iMemDump )
rect.top += g_nFontHeight;
rect.bottom += g_nFontHeight;
sData[0] = 0;
}
}
@ -2727,7 +2795,7 @@ void DrawRegisters ( int line )
DrawRegister( line++, sReg[ BP_SRC_REG_X ] , 1, regs.x , PARAM_REG_X );
DrawRegister( line++, sReg[ BP_SRC_REG_Y ] , 1, regs.y , PARAM_REG_Y );
DrawRegister( line++, sReg[ BP_SRC_REG_PC] , 2, regs.pc, PARAM_REG_PC );
DrawFlags ( line , regs.ps, NULL);
DrawFlags ( line , regs.ps);
line += 2;
DrawRegister( line++, sReg[ BP_SRC_REG_S ] , 2, regs.sp, PARAM_REG_SP );
}
@ -2771,7 +2839,6 @@ void _DrawSoftSwitchAddress( RECT & rect, int nAddress, int bg_default = BG_INFO
void _DrawSoftSwitch( RECT & rect, int nAddress, bool bSet, char *sPrefix, char *sOn, char *sOff, const char *sSuffix = NULL, int bg_default = BG_INFO )
{
RECT temp = rect;
char sText[ 4 ] = "";
_DrawSoftSwitchAddress( temp, nAddress, bg_default );
@ -3017,10 +3084,9 @@ void DrawSoftSwitches( int iSoftSwitch )
DebuggerSetColorBG( DebuggerGetColor( BG_INFO ));
DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE ));
char sText[16] = "";
#if SOFTSWITCH_OLD
char sText[16] = "";
// $C050 / $C051 = TEXTOFF/TEXTON = SW.TXTCLR/SW.TXTSET
// GR / TEXT
// GRAPH/TEXT
@ -3325,7 +3391,6 @@ void DrawWatches (int line)
PrintTextCursorX( ":", rect2 );
BYTE nTarget8 = 0;
BYTE nValue8 = 0;
nTarget8 = (unsigned)*(LPBYTE)(mem+g_aWatches[iWatch].nAddress);
sprintf(sText,"%02X", nTarget8 );
@ -3631,7 +3696,7 @@ void DrawSubWindow_Data (Update_t bUpdate)
rect.left = X_CHAR;
// Seperator
// Separator
DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR ));
PrintTextCursorX( " | ", rect );
@ -3647,12 +3712,12 @@ void DrawSubWindow_Data (Update_t bUpdate)
for (iByte = 0; iByte < nMaxOpcodes; iByte++ )
{
BYTE nImmediate = (unsigned)*(LPBYTE)(mem + iAddress);
int iTextBackground = iBackground;
/*int iTextBackground = iBackground;
if ((iAddress >= _6502_IO_BEGIN) && (iAddress <= _6502_IO_END))
{
iTextBackground = BG_INFO_IO_BYTE;
}
*/
ColorizeSpecialChar( sImmediate, (BYTE) nImmediate, eView, iBackground );
PrintTextCursorX( (LPCSTR) sImmediate, rect );
@ -3784,8 +3849,15 @@ void DrawVideoScannerInfo (int line)
PrintText("cycles:", rect);
rect.left += nameWidth * nFontWidth;
UINT cycles = 0;
if (g_videoScannerDisplayInfo.cycleMode == VideoScannerDisplayInfo::abs)
cycles = (UINT)g_nCumulativeCycles;
else if (g_videoScannerDisplayInfo.cycleMode == VideoScannerDisplayInfo::rel)
cycles = g_videoScannerDisplayInfo.cycleDelta;
else // "part"
cycles = (UINT)g_videoScannerDisplayInfo.lastCumulativeCycles - (UINT)g_videoScannerDisplayInfo.savedCumulativeCycles;
char sValue[10];
const UINT cycles = g_videoScannerDisplayInfo.isAbsCycle ? (UINT)g_nCumulativeCycles : g_videoScannerDisplayInfo.cycleDelta;
sprintf_s(sValue, sizeof(sValue), "%08X", cycles);
PrintText(sValue, rect);
}
@ -3882,7 +3954,6 @@ void DrawSubWindow_Source2 (Update_t bUpdate)
DebuggerSetColorFG( DebuggerGetColor( FG_SOURCE ));
int iSource = g_iSourceDisplayStart;
int nLines = g_nDisasmWinHeight;
int y = g_nDisasmWinHeight;
@ -4037,7 +4108,7 @@ void DrawWindowBackground_Info( int g_iWindowThis )
{
RECT rect;
rect.top = 0;
rect.left = DISPLAY_DISASM_RIGHT;
rect.left = DISPLAY_DISASM_RIGHT;
rect.right = DISPLAY_WIDTH;
int nTop = GetConsoleTopPixels( g_nConsoleDisplayLines - 1 );
rect.bottom = nTop;

View file

@ -7,19 +7,9 @@
#define DEBUG_APPLE_FONT 0
// Win32 Debugger Font
// 1 = Use Debugger_Font.BMP (7x8)
// 0 = Use CHARSET40.bmp (fg & bg colors aren't proper)
#define APPLE_FONT_NEW 1
#if APPLE_FONT_NEW
#define APPLE_FONT_BITMAP_PADDED 0
#else
#define APPLE_FONT_BITMAP_PADDED 1
#endif
enum ConsoleFontSize_e
{
#if APPLE_FONT_NEW
// Grid Alignment
CONSOLE_FONT_GRID_X = 7,
CONSOLE_FONT_GRID_Y = 8,
@ -27,23 +17,14 @@
// Font Char Width/Height in pixels
CONSOLE_FONT_WIDTH = 7,
CONSOLE_FONT_HEIGHT = 8,
#else
CONSOLE_FONT_GRID_X = 8,
CONSOLE_FONT_GRID_Y = 8,
// Font Char Width/Height in pixels
CONSOLE_FONT_WIDTH = 7,
CONSOLE_FONT_HEIGHT = 8,
#endif
CONSOLE_FONT_NUM_CHARS_PER_ROW = 16,
CONSOLE_FONT_NUM_ROWS = 16,
CONSOLE_FONT_BITMAP_WIDTH = CONSOLE_FONT_WIDTH * CONSOLE_FONT_NUM_CHARS_PER_ROW, // 112 pixels
CONSOLE_FONT_BITMAP_HEIGHT = CONSOLE_FONT_HEIGHT * CONSOLE_FONT_NUM_ROWS, // 128 pixels
};
extern HBRUSH g_hConsoleBrushFG;
extern HBRUSH g_hConsoleBrushBG;
extern HDC g_hConsoleFontDC;
extern HBRUSH g_hConsoleFontBrush;
extern HBITMAP g_hConsoleFontBitmap;
enum
{
DISPLAY_HEIGHT = 384,
@ -57,7 +38,8 @@
void DebuggerSetColorFG( COLORREF nRGB );
void DebuggerSetColorBG( COLORREF nRGB, bool bTransparent = false );
void PrintGlyph ( const int x, const int y, const int iChar );
void FillBackground(long left, long top, long right, long bottom);
int PrintText ( const char * pText, RECT & rRect );
int PrintTextCursorX( const char * pText, RECT & rRect );
int PrintTextCursorY( const char * pText, RECT & rRect );
@ -81,13 +63,13 @@
void FormatOpcodeBytes ( WORD nBaseAddress, DisasmLine_t & line_ );
void FormatNopcodeBytes ( WORD nBaseAddress, DisasmLine_t & line_ );
void DrawFlags ( int line, WORD nRegFlags, LPTSTR pFlagNames_);
//
extern HDC GetDebuggerMemDC(void);
extern void ReleaseDebuggerMemDC(void);
extern void StretchBltMemToFrameDC(void);
extern HDC GetConsoleFontDC(void);
extern void ReleaseConsoleFontDC(void);
enum DebugVirtualTextScreen_e
{
@ -102,15 +84,17 @@
class VideoScannerDisplayInfo
{
public:
VideoScannerDisplayInfo(void) : isDecimal(false), isHorzReal(false), isAbsCycle(false),
lastCumulativeCycles(0), cycleDelta(0) {}
void Reset(void) { lastCumulativeCycles = g_nCumulativeCycles; cycleDelta = 0; }
VideoScannerDisplayInfo(void) : isDecimal(false), isHorzReal(false), cycleMode(rel),
lastCumulativeCycles(0), savedCumulativeCycles(0), cycleDelta(0) {}
void Reset(void) { lastCumulativeCycles = savedCumulativeCycles = g_nCumulativeCycles; cycleDelta = 0; }
bool isDecimal;
bool isHorzReal;
bool isAbsCycle;
enum CYCLE_MODE {abs=0, rel, part};
CYCLE_MODE cycleMode;
unsigned __int64 lastCumulativeCycles;
unsigned __int64 savedCumulativeCycles;
UINT cycleDelta;
};

View file

@ -60,7 +60,6 @@ bool TestStringCat ( TCHAR * pDst, LPCSTR pSrc, const int nDstSize )
int nLenDst = _tcslen( pDst );
int nLenSrc = _tcslen( pSrc );
int nSpcDst = nDstSize - nLenDst;
int nChars = MIN( nLenSrc, nSpcDst );
bool bOverflow = (nSpcDst <= nLenSrc); // 2.5.6.25 BUGFIX
if (bOverflow)
@ -390,7 +389,6 @@ bool Colorize( char * pDst, const char * pSrc )
const char sExamples[] = "Examples:";
const int nExamples = sizeof( sExamples ) - 1;
int nLen = 0;
while (*pSrc)
{
if (strncmp( sUsage, pSrc, nUsage) == 0)
@ -1408,11 +1406,17 @@ Update_t CmdHelpSpecific (int nArgs)
break;
// Cycles
case CMD_CYCLES_INFO:
ConsoleColorizePrint(sText, " Usage: <abs|rel>");
ConsoleColorizePrint(sText, " Usage: <abs|rel|part>");
ConsoleBufferPush(" Where:");
ConsoleBufferPush(" <abs|rel> changes cycle output to absolute/relative");
ConsoleBufferPush(" abs = absolute number of cycles since power-on");
ConsoleBufferPush(" rel = number of cycles since last step or breakpoint");
ConsoleBufferPush(" part= number of cycles relative to current instruction");
break;
case CMD_CYCLES_RESET:
ConsoleBufferPush(" Use in conjunctioned with 'cycles part' to reset to current instruction");
break;
// Video-Scanner
case CMD_VIDEO_SCANNER_INFO:
ConsoleColorizePrint(sText, " Usage: <dec|hex|real|apple>");
ConsoleBufferPush(" Where:");
@ -1524,10 +1528,6 @@ Update_t CmdHelpList (int nArgs)
char sText[ nBuf ] = "";
int nLenLine = strlen( sText );
int y = 0;
int nLinesScrolled = 0;
int nMaxWidth = g_nConsoleDisplayWidth - 1;
int iCommand;
@ -1541,7 +1541,6 @@ Update_t CmdHelpList (int nArgs)
}
std::sort( g_vSortedCommands.begin(), g_vSortedCommands.end(), commands_functor_compare() );
}
int nCommands = g_vSortedCommands.size();
int nLen = 0;
// Colorize( sText, "Commands: " );

View file

@ -418,7 +418,6 @@ void ArgsRawParse ( void )
WORD nAddressArg;
WORD nAddressSymbol;
WORD nAddressValue;
int nParamLen = 0;
while (iArg <= nArg)
{
@ -869,8 +868,6 @@ const TCHAR * FindTokenOrAlphaNumeric ( const TCHAR *pSrc, const TokenTable_t *a
//===========================================================================
void TextConvertTabsToSpaces( TCHAR *pDeTabified_, LPCTSTR pText, const int nDstSize, int nTabStop )
{
int nLen = _tcslen( pText );
int TAB_SPACING = 8;
int TAB_SPACING_1 = 16;
int TAB_SPACING_2 = 21;
@ -881,7 +878,6 @@ void TextConvertTabsToSpaces( TCHAR *pDeTabified_, LPCTSTR pText, const int nDst
LPCTSTR pSrc = pText;
LPTSTR pDst = pDeTabified_;
int iTab = 0; // number of tabs seen
int nTab = 0; // gap left to next tab
int nGap = 0; // actual gap
int nCur = 0; // current cursor position

View file

@ -377,6 +377,7 @@
, CMD_CURSOR_PAGE_DOWN_4K // Down to nearest 4K boundary
// Cycles info
, CMD_CYCLES_INFO
, CMD_CYCLES_RESET
// Disassembler Data
, CMD_DISASM_DATA
, CMD_DISASM_CODE
@ -666,7 +667,8 @@
Update_t CmdCursorPageUp4K (int nArgs);
// Cycles info
Update_t CmdCyclesInfo (int nArgs);
Update_t CmdCyclesInfo (int nArgs);
Update_t CmdCyclesReset (int nArgs);
// Disk
Update_t CmdDisk (int nArgs);

View file

@ -53,17 +53,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// . if false && I/O ReadWrite($C0EC) && drive is spinning, then advance the track buffer's nibble index (to simulate spinning).
// Also m_enhanceDisk is persisted to the save-state, so it's an attribute of the DiskII interface card.
Disk2InterfaceCard::Disk2InterfaceCard(void) :
Card(CT_Disk2)
Disk2InterfaceCard::Disk2InterfaceCard(UINT slot) :
Card(CT_Disk2),
m_slot(slot)
{
ResetSwitches();
m_floppyLatch = 0;
m_saveDiskImage = true; // Save the DiskImage name to Registry
m_slot = 0;
m_diskLastCycle = 0;
m_diskLastReadLatchCycle = 0;
m_enhanceDisk = true;
m_is13SectorFirmware = false;
ResetLogicStateSequencer();
@ -228,33 +229,6 @@ void Disk2InterfaceCard::CheckSpinning(const ULONG uExecutedCycles)
//===========================================================================
Disk_Status_e Disk2InterfaceCard::GetDriveLightStatus(const int drive)
{
if (IsDriveValid( drive ))
{
FloppyDrive* pDrive = &m_floppyDrive[ drive ];
if (pDrive->m_spinning)
{
if (pDrive->m_disk.m_bWriteProtected)
return DISK_STATUS_PROT;
if (pDrive->m_writelight)
return DISK_STATUS_WRITE;
else
return DISK_STATUS_READ;
}
else
{
return DISK_STATUS_OFF;
}
}
return DISK_STATUS_OFF;
}
//===========================================================================
bool Disk2InterfaceCard::IsDriveValid(const int drive)
{
return (drive >= 0 && drive < NUM_DRIVES);
@ -282,6 +256,12 @@ void Disk2InterfaceCard::ReadTrack(const int drive, ULONG uExecutedCycles)
if (ImagePhaseToTrack(pFloppy->m_imagehandle, pDrive->m_phasePrecise, false) >= ImageGetNumTracks(pFloppy->m_imagehandle))
{
_ASSERT(0); // What can cause this? Add a comment to replace this assert.
// Boot with DOS 3.3 Master in D1
// Create a blank disk in D2
// INIT HELLO,D2
// RUN HELLO
// F2 to reboot DOS 3.3 Master
// RUN HELLO,D2
pFloppy->m_trackimagedata = false;
return;
}
@ -589,6 +569,31 @@ const std::string & Disk2InterfaceCard::DiskGetFullPathName(const int drive)
//===========================================================================
Disk_Status_e Disk2InterfaceCard::GetDriveLightStatus(const int drive)
{
if (IsDriveValid( drive ))
{
FloppyDrive* pDrive = &m_floppyDrive[ drive ];
if (pDrive->m_spinning)
{
if (pDrive->m_disk.m_bWriteProtected)
return DISK_STATUS_PROT;
if (pDrive->m_writelight)
return DISK_STATUS_WRITE;
else
return DISK_STATUS_READ;
}
else
{
return DISK_STATUS_OFF;
}
}
return DISK_STATUS_OFF;
}
void Disk2InterfaceCard::GetLightStatus(Disk_Status_e *pDisk1Status, Disk_Status_e *pDisk2Status)
{
if (pDisk1Status)
@ -613,8 +618,8 @@ ImageError_e Disk2InterfaceCard::InsertDisk(const int drive, LPCTSTR pszImageFil
pFloppy->clear();
const DWORD dwAttributes = GetFileAttributes(pszImageFilename);
if(dwAttributes == INVALID_FILE_ATTRIBUTES)
pFloppy->m_bWriteProtected = false; // Assume this is a new file to create
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
pFloppy->m_bWriteProtected = false; // Assume this is a new file to create (so it must be write-enabled to allow it to be formatted)
else
pFloppy->m_bWriteProtected = bForceWriteProtected ? true : (dwAttributes & FILE_ATTRIBUTE_READONLY);
@ -656,6 +661,9 @@ ImageError_e Disk2InterfaceCard::InsertDisk(const int drive, LPCTSTR pszImageFil
{
GetImageTitle(pszImageFilename, pFloppy->m_imagename, pFloppy->m_fullname);
Video_ResetScreenshotCounter(pFloppy->m_imagename);
if (g_nAppMode == MODE_LOGO)
InitFirmware(GetCxRomPeripheral());
}
else
{
@ -729,17 +737,6 @@ void Disk2InterfaceCard::NotifyInvalidImage(const int drive, LPCTSTR pszImageFil
pszImageFilename);
break;
case eIMAGE_ERROR_UNSUPPORTED_MULTI_ZIP:
StringCbPrintf(
szBuffer,
MAX_PATH + 128,
TEXT("Unable to use the file %s\nbecause the ")
TEXT("first file (%s) in this multi-zip archive is not recognized.\n")
TEXT("Try unzipping and using the disk images directly.\n"),
pszImageFilename,
m_floppyDrive[drive].m_disk.m_strFilenameInZip.c_str());
break;
case eIMAGE_ERROR_GZ:
case eIMAGE_ERROR_ZIP:
StringCbPrintf(
@ -984,24 +981,18 @@ void Disk2InterfaceCard::ResetLogicStateSequencer(void)
m_shiftReg = 0;
m_latchDelay = 0;
m_resetSequencer = true;
m_writeStarted = false;
m_dbgLatchDelayedCnt = 0;
}
void Disk2InterfaceCard::UpdateBitStreamPositionAndDiskCycle(const ULONG uExecutedCycles)
UINT Disk2InterfaceCard::GetBitCellDelta(const ULONG uExecutedCycles)
{
FloppyDisk& floppy = m_floppyDrive[m_currDrive].m_disk;
CpuCalcCycles(uExecutedCycles);
const UINT bitCellDelta = GetBitCellDelta(ImageGetOptimalBitTiming(floppy.m_imagehandle));
UpdateBitStreamPosition(floppy, bitCellDelta);
m_diskLastCycle = g_nCumulativeCycles;
}
UINT Disk2InterfaceCard::GetBitCellDelta(const BYTE optimalBitTiming)
{
FloppyDisk& floppy = m_floppyDrive[m_currDrive].m_disk;
const BYTE optimalBitTiming = ImageGetOptimalBitTiming(floppy.m_imagehandle);
// NB. m_extraCycles is needed to retain accuracy:
// . Read latch #1: 0-> 9: cycleDelta= 9, bitCellDelta=2, extraCycles=1
// . Read latch #2: 9->20: cycleDelta=11, bitCellDelta=2, extraCycles=3
@ -1010,9 +1001,9 @@ UINT Disk2InterfaceCard::GetBitCellDelta(const BYTE optimalBitTiming)
#if 0
if (optimalBitTiming == 32)
{
const ULONG cycleDelta = (ULONG)(g_nCumulativeCycles - m_diskLastCycle) + (BYTE) m_extraCycles;
const ULONG cycleDelta = (ULONG)(g_nCumulativeCycles - m_diskLastCycle) + (BYTE) floppy.m_extraCycles;
bitCellDelta = cycleDelta / 4; // DIV 4 for 4us per bit-cell
m_extraCycles = cycleDelta & 3; // MOD 4 : remainder carried forward for next time
floppy.m_extraCycles = cycleDelta & 3; // MOD 4 : remainder carried forward for next time
}
else
#endif
@ -1022,13 +1013,17 @@ UINT Disk2InterfaceCard::GetBitCellDelta(const BYTE optimalBitTiming)
bitCellDelta = (UINT) floor( cycleDelta / bitTime );
floppy.m_extraCycles = (double)cycleDelta - ((double)bitCellDelta * bitTime);
}
// NB. actual m_diskLastCycle for the last bitCell is minus floppy.m_extraCycles
// - but don't need this value; and it's correctly accounted for in this function.
m_diskLastCycle = g_nCumulativeCycles;
return bitCellDelta;
}
void Disk2InterfaceCard::UpdateBitStreamPosition(FloppyDisk& floppy, const ULONG bitCellDelta)
{
_ASSERT(floppy.m_bitCount); // Should never happen - ReadTrack() will handle this
if (floppy.m_bitCount == 0)
if (floppy.m_bitCount == 0) // Repro: Boot DOS3.3(WOZ), eject+reinsert disk, CALL-151, C0E9 N C0ED ; motor-on & LoadWriteProtect()
return;
floppy.m_bitOffset += bitCellDelta;
@ -1036,6 +1031,8 @@ void Disk2InterfaceCard::UpdateBitStreamPosition(FloppyDisk& floppy, const ULONG
floppy.m_bitOffset %= floppy.m_bitCount;
UpdateBitStreamOffsets(floppy);
m_resetSequencer = false;
}
void Disk2InterfaceCard::UpdateBitStreamOffsets(FloppyDisk& floppy)
@ -1045,8 +1042,28 @@ void Disk2InterfaceCard::UpdateBitStreamOffsets(FloppyDisk& floppy)
floppy.m_bitMask = 1 << remainder;
}
void __stdcall Disk2InterfaceCard::DataLatchReadWriteWOZ(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles)
__forceinline void Disk2InterfaceCard::IncBitStream(FloppyDisk& floppy)
{
floppy.m_bitMask >>= 1;
if (!floppy.m_bitMask)
{
floppy.m_bitMask = 1 << 7;
floppy.m_byte++;
}
floppy.m_bitOffset++;
if (floppy.m_bitOffset == floppy.m_bitCount)
{
floppy.m_bitMask = 1 << 7;
floppy.m_bitOffset = 0;
floppy.m_byte = 0;
}
}
void __stdcall Disk2InterfaceCard::DataLatchReadWriteWOZ(WORD pc, WORD addr, BYTE bWrite, ULONG uExecutedCycles)
{
_ASSERT(m_seqFunc.function != dataShiftWrite);
FloppyDrive& drive = m_floppyDrive[m_currDrive];
FloppyDisk& floppy = drive.m_disk;
@ -1067,14 +1084,11 @@ void __stdcall Disk2InterfaceCard::DataLatchReadWriteWOZ(WORD pc, WORD addr, BYT
if (!drive.m_spinning) // GH#599
return;
CpuCalcCycles(uExecutedCycles);
// Skipping forward a large amount of bitcells means the bitstream will very likely be out-of-sync.
// The first 1-bit will produce a latch nibble, and this 1-bit is unlikely to be the nibble's high bit.
// So we need to ensure we run enough bits through the sequencer to re-sync.
// NB. For Planetfall 13 bitcells(NG) / 14 bitcells(OK)
const UINT significantBitCells = 50; // 5x 10-bit sync FF nibbles
UINT bitCellDelta = GetBitCellDelta(ImageGetOptimalBitTiming(floppy.m_imagehandle));
UINT bitCellDelta = GetBitCellDelta(uExecutedCycles);
UINT bitCellRemainder;
if (bitCellDelta <= significantBitCells)
@ -1092,20 +1106,21 @@ void __stdcall Disk2InterfaceCard::DataLatchReadWriteWOZ(WORD pc, WORD addr, BYT
drive.m_headWindow = 0;
}
// NB. actual m_diskLastCycle for the last bitCell is minus floppy.m_extraCycles
// - but don't need this value; and it's correctly accounted for in GetBitCellDelta()
m_diskLastCycle = g_nCumulativeCycles;
if (!bWrite)
{
if (m_seqFunc.function != readSequencing)
{
_ASSERT(m_seqFunc.function == checkWriteProtAndInitWrite);
UpdateBitStreamPosition(floppy, bitCellRemainder);
return;
}
DataLatchReadWOZ(pc, addr, bitCellRemainder);
}
else
{
DataLatchWriteWOZ(pc, addr, d, bitCellRemainder);
_ASSERT(m_seqFunc.function == dataLoadWrite);
DataLoadWriteWOZ(pc, addr, bitCellRemainder);
}
// Show track status (GH#201) - NB. Prevent flooding of forcing UI to redraw!!!
@ -1147,20 +1162,7 @@ void Disk2InterfaceCard::DataLatchReadWOZ(WORD pc, WORD addr, UINT bitCellRemain
BYTE outputBit = (drive.m_headWindow & 0xf) ? (drive.m_headWindow >> 1) & 1
: (rand() < (RAND_MAX / 10 * 3)) ? 1 : 0; // ~30% chance of a 1 bit (Ref: WOZ-2.0)
floppy.m_bitMask >>= 1;
if (!floppy.m_bitMask)
{
floppy.m_bitMask = 1 << 7;
floppy.m_byte++;
}
floppy.m_bitOffset++;
if (floppy.m_bitOffset == floppy.m_bitCount)
{
floppy.m_bitMask = 1 << 7;
floppy.m_bitOffset = 0;
floppy.m_byte = 0;
}
IncBitStream(floppy);
if (m_resetSequencer)
{
@ -1238,17 +1240,64 @@ void Disk2InterfaceCard::DataLatchReadWOZ(WORD pc, WORD addr, UINT bitCellRemain
#endif
}
void Disk2InterfaceCard::DataLatchWriteWOZ(WORD pc, WORD addr, BYTE d, UINT bitCellRemainder)
void Disk2InterfaceCard::DataLoadWriteWOZ(WORD pc, WORD addr, UINT bitCellRemainder)
{
_ASSERT(m_seqFunc.writeMode);
_ASSERT(m_seqFunc.function == dataLoadWrite);
FloppyDrive& drive = m_floppyDrive[m_currDrive];
FloppyDisk& floppy = drive.m_disk;
if (!floppy.m_bWriteProtected)
if (floppy.m_bWriteProtected)
{
//TODO
_ASSERT(0); // Must be a bug in the 6502 code for this to occur!
UpdateBitStreamPosition(floppy, bitCellRemainder);
return;
}
if (!m_writeStarted)
UpdateBitStreamPosition(floppy, bitCellRemainder); // skip over bitCells before switching to write mode
m_writeStarted = true;
#if LOG_DISK_WOZ_LOADWRITE
LOG_DISK("load shiftReg with %02X (was: %02X)\n", m_floppyLatch, m_shiftReg);
#endif
m_shiftReg = m_floppyLatch;
}
void Disk2InterfaceCard::DataShiftWriteWOZ(WORD pc, WORD addr, ULONG uExecutedCycles)
{
_ASSERT(m_seqFunc.function == dataShiftWrite);
FloppyDrive& drive = m_floppyDrive[m_currDrive];
FloppyDisk& floppy = drive.m_disk;
const UINT bitCellRemainder = GetBitCellDelta(uExecutedCycles);
if (floppy.m_bWriteProtected)
{
_ASSERT(0); // Must be a bug in the 6502 code for this to occur!
UpdateBitStreamPosition(floppy, bitCellRemainder);
return;
}
#if LOG_DISK_WOZ_SHIFTWRITE
LOG_DISK("T$%02X, bitOffset=%04X: %02X (%d bits)\n", drive.m_phase/2, floppy.m_bitOffset, m_shiftReg, bitCellRemainder);
#endif
for (UINT i = 0; i < bitCellRemainder; i++)
{
BYTE outputBit = m_shiftReg & 0x80;
m_shiftReg <<= 1;
BYTE n = floppy.m_trackimage[floppy.m_byte];
n &= ~floppy.m_bitMask;
if (outputBit) n |= floppy.m_bitMask;
floppy.m_trackimage[floppy.m_byte] = n;
IncBitStream(floppy);
}
floppy.m_trackimagedirty = true;
}
//===========================================================================
@ -1316,19 +1365,18 @@ void Disk2InterfaceCard::DumpSectorWOZ(FloppyDisk floppy) // pass a copy of m_fl
// Dump nibbles from current position bitstream wraps to same position
void Disk2InterfaceCard::DumpTrackWOZ(FloppyDisk floppy) // pass a copy of m_floppy
{
#ifdef LOG_DISK_NIBBLES_READ
FormatTrack formatTrack;
#endif
FormatTrack formatTrack(true);
BYTE shiftReg = 0;
UINT zeroCount = 0;
UINT nibbleCount = 0;
floppy.m_bitMask = 1 << 7;
floppy.m_bitOffset = 0;
floppy.m_byte = 0;
const UINT startBitOffset = 0;
floppy.m_bitOffset = startBitOffset;
const UINT startBitOffset = floppy.m_bitOffset;
floppy.m_byte = floppy.m_bitOffset / 8;
const UINT remainder = 7 - (floppy.m_bitOffset & 7);
floppy.m_bitMask = 1 << remainder;
bool newLine = true;
@ -1381,19 +1429,36 @@ void Disk2InterfaceCard::DumpTrackWOZ(FloppyDisk floppy) // pass a copy of m_flo
if (zeroCount == 0) StringCbPrintf(str, sizeof(str), " %02X", shiftReg);
else StringCbPrintf(str, sizeof(str), "(%c)%02X", syncBits, shiftReg);
OutputDebugString(str);
formatTrack.DecodeLatchNibbleRead(shiftReg);
if ((nibbleCount % 32) == 0)
{
std::string strReadDetected = formatTrack.GetReadD5AAxxDetectedString();
if (!strReadDetected.empty())
{
OutputDebugString("\t; ");
OutputDebugString(strReadDetected.c_str());
}
OutputDebugString("\n");
newLine = true;
}
#ifdef LOG_DISK_NIBBLES_READ
formatTrack.DecodeLatchNibbleRead(shiftReg);
#endif
shiftReg = 0;
zeroCount = 0;
}
// Output any remaining "read D5AAxx detected"
if (nibbleCount % 32)
{
std::string strReadDetected = formatTrack.GetReadD5AAxxDetectedString();
if (!strReadDetected.empty())
{
OutputDebugString("\t; ");
OutputDebugString(strReadDetected.c_str());
}
OutputDebugString("\n");
}
}
#endif
@ -1421,6 +1486,9 @@ void Disk2InterfaceCard::Reset(const bool bIsPowerCycle)
FrameRefreshStatus(DRAW_LEDS, false);
}
InitFirmware(GetCxRomPeripheral());
FrameRefreshStatus(DRAW_TITLE, false);
}
void Disk2InterfaceCard::ResetSwitches(void)
@ -1485,7 +1553,9 @@ bool Disk2InterfaceCard::UserSelectNewDiskImage(const int drive, LPCSTR pszFilen
void __stdcall Disk2InterfaceCard::LoadWriteProtect(WORD, WORD, BYTE write, BYTE value, ULONG uExecutedCycles)
{
// NB. m_seqFunc.function == checkWriteProtAndInitWrite or shiftWrite (both OK)
// NB. Only reads in LOAD mode can issue the SR (shift write-protect) operation - UTAIIe page 9-20, fig 9.11
// But STA $C08D,X (no PX) does a read from $C08D+X, followed by the write to $C08D+X
// So just want to ignore: STA $C0ED or eg. STA $BFFF,X (PX, X=$EE)
// Don't change latch if drive off after 1 second drive-off delay (UTAIIe page 9-13)
// "DRIVES OFF forces the data register to hold its present state." (UTAIIe page 9-12)
@ -1500,20 +1570,28 @@ void __stdcall Disk2InterfaceCard::LoadWriteProtect(WORD, WORD, BYTE write, BYTE
// the write protect switch would still be read correctly" (UTAIIe page 9-21)
// . Sequencer "SR" (Shift Right) command only loads QA (bit7) of data register (UTAIIe page 9-21)
// . A read or write will shift 'write protect' in QA.
if (m_floppyDrive[m_currDrive].m_disk.m_bWriteProtected)
FloppyDisk& floppy = m_floppyDrive[m_currDrive].m_disk;
if (floppy.m_bWriteProtected)
m_floppyLatch |= 0x80;
else
m_floppyLatch &= 0x7F;
if (ImageIsWOZ(m_floppyDrive[m_currDrive].m_disk.m_imagehandle))
if (m_writeStarted) // Prevent ResetLogicStateSequencer() from resetting m_writeStarted
return;
if (ImageIsWOZ(floppy.m_imagehandle))
{
#if LOG_DISK_NIBBLES_READ
CpuCalcCycles(uExecutedCycles);
LOG_DISK("%08X: reset LSS: ~PC=%04X\r\n", (UINT32)g_nCumulativeCycles, regs.pc);
#endif
const UINT bitCellDelta = GetBitCellDelta(uExecutedCycles);
UpdateBitStreamPosition(floppy, bitCellDelta); // Fix E7-copy protection
// UpdateBitStreamPosition() must be done before ResetLSS, as the former clears m_resetSequencer (and the latter sets it).
// . Commando.woz is sensitive to this. EG. It can crash after pressing 'J' (1 failure in 20 reboot repeats)
ResetLogicStateSequencer(); // reset sequencer (UTAIIe page 9-21)
// m_latchDelay = 7; // TODO: Treat like a regular $C0EC latch load?
UpdateBitStreamPositionAndDiskCycle(uExecutedCycles); // Fix E7-copy protection
}
}
@ -1639,28 +1717,51 @@ bool Disk2InterfaceCard::DriveSwap(void)
//===========================================================================
// TODO: LoadRom_Disk_Floppy()
void Disk2InterfaceCard::Initialize(LPBYTE pCxRomPeripheral, UINT uSlot)
bool Disk2InterfaceCard::GetFirmware(LPCSTR lpName, BYTE* pDst)
{
const UINT DISK2_FW_SIZE = APPLE_SLOT_SIZE;
HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_DISK2_FW), "FIRMWARE");
HRSRC hResInfo = FindResource(NULL, lpName, "FIRMWARE");
if(hResInfo == NULL)
return;
return false;
DWORD dwResSize = SizeofResource(NULL, hResInfo);
if(dwResSize != DISK2_FW_SIZE)
return;
return false;
HGLOBAL hResData = LoadResource(NULL, hResInfo);
if(hResData == NULL)
return;
return false;
BYTE* pData = (BYTE*) LockResource(hResData); // NB. Don't need to unlock resource
if(pData == NULL)
if (!pData)
return false;
memcpy(pDst, pData, DISK2_FW_SIZE);
return true;
}
void Disk2InterfaceCard::InitFirmware(LPBYTE pCxRomPeripheral)
{
if (pCxRomPeripheral == NULL)
return;
memcpy(pCxRomPeripheral + uSlot*APPLE_SLOT_SIZE, pData, DISK2_FW_SIZE);
ImageInfo* pImage = m_floppyDrive[DRIVE_1].m_disk.m_imagehandle;
m_is13SectorFirmware = ImageIsBootSectorFormatSector13(pImage);
if (m_is13SectorFirmware)
memcpy(pCxRomPeripheral + m_slot*APPLE_SLOT_SIZE, m_13SectorFirmware, DISK2_FW_SIZE);
else
memcpy(pCxRomPeripheral + m_slot*APPLE_SLOT_SIZE, m_16SectorFirmware, DISK2_FW_SIZE);
}
// TODO: LoadRom_Disk_Floppy()
void Disk2InterfaceCard::Initialize(LPBYTE pCxRomPeripheral, UINT uSlot)
{
bool res = GetFirmware(MAKEINTRESOURCE(IDR_DISK2_13SECTOR_FW), m_13SectorFirmware);
_ASSERT(res);
res = GetFirmware(MAKEINTRESOURCE(IDR_DISK2_16SECTOR_FW), m_16SectorFirmware);
_ASSERT(res);
// Note: We used to disable the track stepping delay in the Disk II controller firmware by
// patching $C64C with $A9,$00,$EA. Now not doing this since:
@ -1669,9 +1770,12 @@ void Disk2InterfaceCard::Initialize(LPBYTE pCxRomPeripheral, UINT uSlot)
// . Patching the firmware breaks the ADC checksum used by "The CIA Files" (Tricky Dick)
// . In this case we can patch to compensate for an ADC or EOR checksum but not both (nickw)
_ASSERT(m_slot == uSlot);
RegisterIoHandler(uSlot, &Disk2InterfaceCard::IORead, &Disk2InterfaceCard::IOWrite, NULL, NULL, this, NULL);
m_slot = uSlot;
InitFirmware(pCxRomPeripheral);
}
//===========================================================================
@ -1688,6 +1792,9 @@ void Disk2InterfaceCard::SetSequencerFunction(WORD addr)
case 2: m_seqFunc.loadMode = 0; break; // $C08C,X (sequence addr A3 input)
case 3: m_seqFunc.loadMode = 1; break; // $C08D,X (sequence addr A3 input)
}
if (!m_seqFunc.writeMode)
m_writeStarted = false;
}
BYTE __stdcall Disk2InterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
@ -1698,6 +1805,9 @@ BYTE __stdcall Disk2InterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE
ImageInfo* pImage = pCard->m_floppyDrive[pCard->m_currDrive].m_disk.m_imagehandle;
bool isWOZ = ImageIsWOZ(pImage);
if (isWOZ && pCard->m_seqFunc.function == dataShiftWrite) // Occurs at end of sector write ($C0EE)
pCard->DataShiftWriteWOZ(pc, addr, nExecutedCycles); // Finish any previous write
pCard->SetSequencerFunction(addr);
switch (addr & 0xF)
@ -1723,8 +1833,8 @@ BYTE __stdcall Disk2InterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE
// only even addresses return the latch (UTAIIe Table 9.1)
if (!(addr & 1))
{
if (isWOZ)
pCard->DataLatchReadWriteWOZ(pc, addr, bWrite, d, nExecutedCycles);
if (isWOZ && pCard->m_seqFunc.function != dataShiftWrite)
pCard->DataLatchReadWriteWOZ(pc, addr, bWrite, nExecutedCycles);
return pCard->m_floppyLatch;
}
@ -1740,6 +1850,9 @@ BYTE __stdcall Disk2InterfaceCard::IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE
ImageInfo* pImage = pCard->m_floppyDrive[pCard->m_currDrive].m_disk.m_imagehandle;
bool isWOZ = ImageIsWOZ(pImage);
if (isWOZ && pCard->m_seqFunc.function == dataShiftWrite)
pCard->DataShiftWriteWOZ(pc, addr, nExecutedCycles); // Finish any previous write
pCard->SetSequencerFunction(addr);
switch (addr & 0xF)
@ -1763,13 +1876,12 @@ BYTE __stdcall Disk2InterfaceCard::IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE
}
// any address writes the latch via sequencer LD command (74LS323 datasheet)
// if (pCard->m_seqFunc.writeMode /* && m_seqFunc.loadMode */)
if (pCard->m_seqFunc.function == dataLoadWrite)
{
pCard->m_floppyLatch = d;
if (isWOZ)
pCard->DataLatchReadWriteWOZ(pc, addr, bWrite, d, nExecutedCycles);
pCard->DataLatchReadWriteWOZ(pc, addr, bWrite, nExecutedCycles);
}
return 0;

View file

@ -120,7 +120,7 @@ public:
class Disk2InterfaceCard : public Card
{
public:
Disk2InterfaceCard(void);
Disk2InterfaceCard(UINT slot);
virtual ~Disk2InterfaceCard(void);
virtual void Init(void) {};
@ -144,6 +144,7 @@ public:
void NotifyInvalidImage(const int drive, LPCTSTR pszImageFilename, const ImageError_e Error);
bool GetProtect(const int drive);
void SetProtect(const int drive, const bool bWriteProtect);
UINT GetCurrentFirmware(void) { return m_is13SectorFirmware ? 13 : 16; }
int GetCurrentDrive(void);
int GetCurrentTrack(void);
float GetCurrentPhase(void);
@ -185,15 +186,18 @@ private:
void WriteTrack(const int drive);
const std::string & DiskGetFullPathName(const int drive);
void ResetLogicStateSequencer(void);
void UpdateBitStreamPositionAndDiskCycle(const ULONG uExecutedCycles);
UINT GetBitCellDelta(const BYTE optimalBitTiming);
UINT GetBitCellDelta(const ULONG uExecutedCycles);
void UpdateBitStreamPosition(FloppyDisk& floppy, const ULONG bitCellDelta);
void UpdateBitStreamOffsets(FloppyDisk& floppy);
__forceinline void IncBitStream(FloppyDisk& floppy);
void DataLatchReadWOZ(WORD pc, WORD addr, UINT bitCellRemainder);
void DataLatchWriteWOZ(WORD pc, WORD addr, BYTE d, UINT bitCellRemainder);
void DataLoadWriteWOZ(WORD pc, WORD addr, UINT bitCellRemainder);
void DataShiftWriteWOZ(WORD pc, WORD addr, ULONG uExecutedCycles);
void SetSequencerFunction(WORD addr);
void DumpSectorWOZ(FloppyDisk floppy);
void DumpTrackWOZ(FloppyDisk floppy);
bool GetFirmware(LPCSTR lpName, BYTE* pDst);
void InitFirmware(LPBYTE pCxRomPeripheral);
void SaveSnapshotFloppy(YamlSaveHelper& yamlSaveHelper, UINT unit);
void SaveSnapshotDriveUnit(YamlSaveHelper& yamlSaveHelper, UINT unit);
@ -206,7 +210,7 @@ private:
void __stdcall ControlMotor(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles);
void __stdcall Enable(WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles);
void __stdcall ReadWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles);
void __stdcall DataLatchReadWriteWOZ(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles);
void __stdcall DataLatchReadWriteWOZ(WORD pc, WORD addr, BYTE bWrite, ULONG uExecutedCycles);
void __stdcall LoadWriteProtect(WORD, WORD, BYTE write, BYTE value, ULONG);
void __stdcall SetReadMode(WORD, WORD, BYTE, BYTE, ULONG);
void __stdcall SetWriteMode(WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles);
@ -217,6 +221,11 @@ private:
//
static const UINT DISK2_FW_SIZE = 256;
BYTE m_13SectorFirmware[DISK2_FW_SIZE];
BYTE m_16SectorFirmware[DISK2_FW_SIZE];
bool m_is13SectorFirmware;
WORD m_currDrive;
FloppyDrive m_floppyDrive[NUM_DRIVES];
BYTE m_floppyLatch;
@ -240,8 +249,9 @@ private:
BYTE m_shiftReg;
int m_latchDelay;
bool m_resetSequencer;
bool m_writeStarted;
enum SEQFUNC {readSequencing=0, checkWriteProtAndInitWrite, dataShiftWrite, dataLoadWrite}; // UTAIIe 9-14
enum SEQFUNC {readSequencing=0, dataShiftWrite, checkWriteProtAndInitWrite, dataLoadWrite}; // UTAIIe 9-14
union SEQUENCER_FUNCTION
{
struct

View file

@ -118,3 +118,17 @@ void Disk2CardManager::Destroy(void)
}
}
}
bool Disk2CardManager::IsAnyFirmware13Sector(void)
{
for (UINT i = 0; i < NUM_SLOTS; i++)
{
if (g_CardMgr.QuerySlot(i) == CT_Disk2)
{
// If any Disk2 card has 13-sector firmware then return true
if (dynamic_cast<Disk2InterfaceCard&>(g_CardMgr.GetRef(i)).GetCurrentFirmware() == 13)
return true;
}
}
return false;
}

View file

@ -13,4 +13,5 @@ public:
void SetEnhanceDisk(bool enhanceDisk);
void LoadLastDiskImage(void);
void Destroy(void);
bool IsAnyFirmware13Sector(void);
};

View file

@ -268,7 +268,13 @@ void FormatTrack::DecodeLatchNibble(BYTE floppylatch, bool bIsWrite, bool bIsSyn
if (!bIsWrite)
{
BYTE addrPrologue = m_bAddressPrologueIsDOS3_2 ? (BYTE)kADDR_PROLOGUE_DOS3_2 : (BYTE)kADDR_PROLOGUE_DOS3_3;
LOG_DISK("read D5AA%02X detected - Vol:%02X Trk:%02X Sec:%02X Chk:%02X %s\r\n", addrPrologue, m_VolTrkSecChk[0], m_VolTrkSecChk[1], m_VolTrkSecChk[2], m_VolTrkSecChk[3], chk?"":"(bad)");
char str[100];
sprintf_s(str, sizeof(str), "read D5AA%02X detected - Vol:%02X Trk:%02X Sec:%02X Chk:%02X %s", addrPrologue, m_VolTrkSecChk[0], m_VolTrkSecChk[1], m_VolTrkSecChk[2], m_VolTrkSecChk[3], chk?"":"(bad)");
m_strReadD5AAxxDetected = str;
if (!m_bSuppressReadD5AAxxDetected)
{
LOG_DISK("%s\r\n", str);
}
}
#endif
#if LOG_DISK_NIBBLES_WRITE

View file

@ -26,8 +26,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
class FormatTrack // Monitor for formatting of track
{
public:
FormatTrack(void)
FormatTrack(bool bSuppressOutput=false)
{
m_bSuppressReadD5AAxxDetected = bSuppressOutput;
Reset();
};
@ -39,6 +40,7 @@ public:
void DriveSwitchedToWriteMode(UINT uTrackIndex);
void DecodeLatchNibbleRead(BYTE floppylatch);
void DecodeLatchNibbleWrite(BYTE floppylatch, UINT uSpinNibbleCount, const class FloppyDisk* const pFloppy, bool bIsSyncFF);
std::string GetReadD5AAxxDetectedString(void) { std::string tmp = m_strReadD5AAxxDetected; m_strReadD5AAxxDetected = ""; return tmp; }
void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
void LoadSnapshot(class YamlLoadHelper& yamlLoadHelper);
@ -60,6 +62,9 @@ private:
BYTE m_VolTrkSecChk4and4[8];
UINT m_4and4idx;
std::string m_strReadD5AAxxDetected;
bool m_bSuppressReadD5AAxxDetected;
#if LOG_DISK_NIBBLES_WRITE_TRACK_GAPS
UINT m_DbgGap1Size;
UINT m_DbgGap2Size;

View file

@ -63,7 +63,7 @@ ImageError_e ImageOpen( const std::string & pszImageFilename,
ImageError_e Err = pImageInfo->pImageHelper->Open(pszImageFilename.c_str(), pImageInfo, bCreateIfNecessary, strFilenameInZip);
if (Err != eIMAGE_ERROR_NONE)
{
ImageClose(*ppImageInfo, true);
ImageClose(*ppImageInfo);
*ppImageInfo = NULL;
return Err;
}
@ -81,10 +81,7 @@ ImageError_e ImageOpen( const std::string & pszImageFilename,
if (!bExpectFloppy)
return eIMAGE_ERROR_UNSUPPORTED;
pImageInfo->uNumTracks = sg_DiskImageHelper.GetNumTracksInImage(pImageInfo->pImageType);
for (UINT uTrack = 0; uTrack < pImageInfo->uNumTracks; uTrack++)
pImageInfo->ValidTrack[uTrack] = (pImageInfo->uImageSize > 0) ? 1 : 0;
_ASSERT(pImageInfo->uNumTracks);
*pWriteProtected = pImageInfo->bWriteProtected;
@ -93,25 +90,9 @@ ImageError_e ImageOpen( const std::string & pszImageFilename,
//===========================================================================
void ImageClose(ImageInfo* const pImageInfo, const bool bOpenError /*=false*/)
void ImageClose(ImageInfo* const pImageInfo)
{
bool bDeleteFile = false;
if (!bOpenError)
{
for (UINT uTrack = 0; uTrack < pImageInfo->uNumTracks; uTrack++)
{
if (!pImageInfo->ValidTrack[uTrack])
{
// TODO: Comment using info from this URL:
// http://groups.google.de/group/comp.emulators.apple2/msg/7a1b9317e7905152
bDeleteFile = true;
break;
}
}
}
pImageInfo->pImageHelper->Close(pImageInfo, bDeleteFile);
pImageInfo->pImageHelper->Close(pImageInfo);
delete pImageInfo;
}
@ -162,7 +143,7 @@ void ImageReadTrack( ImageInfo* const pImageInfo,
const UINT track = pImageInfo->pImageType->PhaseToTrack(phase);
if (pImageInfo->pImageType->AllowRW() && pImageInfo->ValidTrack[track])
if (pImageInfo->pImageType->AllowRW())
{
pImageInfo->pImageType->Read(pImageInfo, phase, pTrackImageBuffer, pNibbles, pBitCount, enhanceDisk);
}
@ -190,7 +171,14 @@ void ImageWriteTrack( ImageInfo* const pImageInfo,
if (pImageInfo->pImageType->AllowRW() && !pImageInfo->bWriteProtected)
{
pImageInfo->pImageType->Write(pImageInfo, phase, pTrackImageBuffer, nNibbles);
pImageInfo->ValidTrack[track] = 1;
eImageType imageType = pImageInfo->pImageType->GetType();
if (imageType == eImageWOZ1 || imageType == eImageWOZ2)
{
DWORD dummy;
bool res = sg_DiskImageHelper.WOZUpdateInfo(pImageInfo, dummy);
_ASSERT(res);
}
}
}
@ -234,7 +222,7 @@ bool ImageIsWriteProtected(ImageInfo* const pImageInfo)
bool ImageIsMultiFileZip(ImageInfo* const pImageInfo)
{
return pImageInfo ? (pImageInfo->uNumEntriesInZip > 1) : false;
return pImageInfo ? (pImageInfo->uNumValidImagesInZip > 1) : false;
}
const std::string & ImageGetPathname(ImageInfo* const pImageInfo)
@ -258,6 +246,11 @@ BYTE ImageGetOptimalBitTiming(ImageInfo* const pImageInfo)
return pImageInfo ? pImageInfo->optimalBitTiming : 32;
}
bool ImageIsBootSectorFormatSector13(ImageInfo* const pImageInfo)
{
return pImageInfo ? pImageInfo->bootSectorFormat == CWOZHelper::bootSector13 : false;
}
UINT ImagePhaseToTrack(ImageInfo* const pImageInfo, const float phase, const bool limit/*=true*/)
{
if (!pImageInfo)

View file

@ -51,7 +51,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
eIMAGE_ERROR_GZ,
eIMAGE_ERROR_ZIP,
eIMAGE_ERROR_REJECTED_MULTI_ZIP,
eIMAGE_ERROR_UNSUPPORTED_MULTI_ZIP,
eIMAGE_ERROR_UNABLE_TO_OPEN,
eIMAGE_ERROR_UNABLE_TO_OPEN_GZ,
eIMAGE_ERROR_UNABLE_TO_OPEN_ZIP,
@ -66,7 +65,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
struct ImageInfo;
ImageError_e ImageOpen(const std::string & pszImageFilename, ImageInfo** ppImageInfo, bool* pWriteProtected, const bool bCreateIfNecessary, std::string& strFilenameInZip, const bool bExpectFloppy=true);
void ImageClose(ImageInfo* const pImageInfo, const bool bOpenError=false);
void ImageClose(ImageInfo* const pImageInfo);
BOOL ImageBoot(ImageInfo* const pImageInfo);
void ImageDestroy(void);
void ImageInitialize(void);
@ -85,5 +84,6 @@ bool ImageIsWOZ(ImageInfo* const pImageInfo);
BYTE ImageGetOptimalBitTiming(ImageInfo* const pImageInfo);
UINT ImagePhaseToTrack(ImageInfo* const pImageInfo, const float phase, const bool limit=true);
UINT ImageGetMaxNibblesPerTrack(ImageInfo* const pImageInfo);
bool ImageIsBootSectorFormatSector13(ImageInfo* const pImageInfo);
void GetImageTitle(LPCTSTR pPathname, std::string & pImageName, std::string & pFullName);

File diff suppressed because it is too large Load diff

View file

@ -31,12 +31,13 @@ struct ImageInfo
std::string szFilenameInZip;
zip_fileinfo zipFileInfo;
UINT uNumEntriesInZip;
UINT uNumValidImagesInZip;
// Floppy only
BYTE ValidTrack[TRACKS_MAX];
UINT uNumTracks;
BYTE* pImageBuffer;
BYTE* pTrackMap; // WOZ only
BYTE* pWOZTrackMap; // WOZ only (points into pImageBuffer)
BYTE optimalBitTiming; // WOZ only
BYTE bootSectorFormat; // WOZ only
UINT maxNibblesPerTrack;
ImageInfo();
@ -73,6 +74,7 @@ public:
virtual const char* GetCreateExtensions(void) = 0;
virtual const char* GetRejectExtensions(void) = 0;
bool WriteImageHeader(ImageInfo* pImageInfo, LPBYTE pHdr, const UINT hdrSize);
void SetVolumeNumber(const BYTE uVolumeNumber) { m_uVolumeNumber = uVolumeNumber; }
bool IsValidImageSize(const DWORD uImageSize);
@ -88,6 +90,7 @@ protected:
bool WriteTrack(ImageInfo* pImageInfo, const int nTrack, LPBYTE pTrackBuffer, const UINT uTrackSize);
bool ReadBlock(ImageInfo* pImageInfo, const int nBlock, LPBYTE pBlockBuffer);
bool WriteBlock(ImageInfo* pImageInfo, const int nBlock, LPBYTE pBlockBuffer);
bool WriteImageData(ImageInfo* pImageInfo, LPBYTE pSrcBuffer, const UINT uSrcSize, const long offset);
LPBYTE Code62(int sector);
void Decode62(LPBYTE imageptr);
@ -134,6 +137,10 @@ private:
#pragma pack(push)
#pragma pack(1) // Ensure Header2IMG & WOZ structs are packed
#pragma warning(push)
#pragma warning(disable: 4200) // Allow zero-sized array in struct
class C2IMGHelper : public CHdrHelper
{
public:
@ -200,10 +207,16 @@ public:
virtual ~CWOZHelper(void) {}
virtual eDetectResult DetectHdr(LPBYTE& pImage, DWORD& dwImageSize, DWORD& dwOffset) { _ASSERT(0); return eMismatch; }
virtual UINT GetMaxHdrSize(void) { return sizeof(WOZHeader); }
eDetectResult ProcessChunks(const LPBYTE pImage, const DWORD dwImageSize, DWORD& dwOffset, BYTE*& pTrackMap);
eDetectResult ProcessChunks(ImageInfo* pImageInfo, DWORD& dwOffset);
bool IsWriteProtected(void) { return m_pInfo->v1.writeProtected == 1; }
BYTE GetOptimalBitTiming(void) { return (m_pInfo->v1.version >= 2) ? m_pInfo->optimalBitTiming : CWOZHelper::InfoChunkv2::optimalBitTiming5_25; }
UINT GetMaxNibblesPerTrack(void) { return (m_pInfo->v1.version >= 2) ? m_pInfo->largestTrack*CWOZHelper::BLOCK_SIZE : CWOZHelper::WOZ1_TRACK_SIZE; }
BYTE GetOptimalBitTiming(void) { return (m_pInfo->v1.version >= 2) ? m_pInfo->optimalBitTiming : InfoChunkv2::optimalBitTiming5_25; }
UINT GetMaxNibblesPerTrack(void) { return (m_pInfo->v1.version >= 2) ? m_pInfo->largestTrack*CWOZHelper::BLOCK_SIZE : WOZ1_TRACK_SIZE; }
BYTE GetBootSectorFormat(void) { return (m_pInfo->v1.version >= 2) ? m_pInfo->bootSectorFormat : bootUnknown; }
void InvalidateInfo(void) { m_pInfo = NULL; }
BYTE* CreateEmptyDisk(DWORD& size);
#if _DEBUG
BYTE* CreateEmptyDiskv1(DWORD& size);
#endif
static const UINT32 ID1_WOZ1 = '1ZOW'; // 'WOZ1'
static const UINT32 ID1_WOZ2 = '2ZOW'; // 'WOZ2'
@ -217,10 +230,29 @@ public:
};
static const UINT32 MAX_TRACKS_5_25 = 40;
static const UINT32 MAX_QUARTER_TRACKS_5_25 = MAX_TRACKS_5_25 * 4;
static const UINT32 WOZ1_TRACK_SIZE = 6656; // 0x1A00
static const UINT32 WOZ1_TRK_OFFSET = 6646;
static const UINT32 EMPTY_TRACK_SIZE = 6400;
static const UINT32 EMPTY_TRACK_SIZE = 6400; // $C.5 blocks
static const UINT32 BLOCK_SIZE = 512;
static const BYTE TMAP_TRACK_EMPTY = 0xFF;
static const UINT16 TRK_DEFAULT_BLOCK_COUNT_5_25 = 13; // $D is default for TRKv2.blockCount
static const BYTE bootUnknown = 0;
static const BYTE bootSector16 = 1;
static const BYTE bootSector13 = 2;
static const BYTE bootSectorBoth = 3;
struct WOZChunkHdr
{
UINT32 id;
UINT32 size;
};
struct Tmap
{
BYTE tmap[MAX_QUARTER_TRACKS_5_25];
};
struct TRKv1
{
@ -239,17 +271,22 @@ public:
UINT32 bitCount;
};
struct Trks
{
TRKv2 trks[MAX_QUARTER_TRACKS_5_25];
BYTE bits[0]; // bits[] starts at offset 3 x BLOCK_SIZE = 1536
};
private:
static const UINT32 INFO_CHUNK_ID = 'OFNI'; // 'INFO'
static const UINT32 TMAP_CHUNK_ID = 'PAMT'; // 'TMAP'
static const UINT32 TRKS_CHUNK_ID = 'SKRT'; // 'TRKS'
static const UINT32 WRIT_CHUNK_ID = 'TIRW'; // 'WRIT' - WOZv2
static const UINT32 META_CHUNK_ID = 'ATEM'; // 'META'
static const UINT32 INFO_CHUNK_SIZE = 60; // Fixed size for both WOZv1 & WOZv2
struct InfoChunk
{
UINT32 id;
UINT32 size;
BYTE version;
BYTE diskType;
BYTE writeProtected; // 1 = Floppy is write protected
@ -273,17 +310,44 @@ private:
UINT16 requiredRAM; // in K (1024 bytes)
UINT16 largestTrack; // in blocks (512 bytes)
static const BYTE bootUnknown = 0;
static const BYTE bootSector16 = 1;
static const BYTE bootSector13 = 2;
static const BYTE bootSectorBoth = 3;
static const BYTE optimalBitTiming5_25 = 32;
};
InfoChunkv2* m_pInfo;
InfoChunkv2* m_pInfo; // NB. image-specific - only valid during Detect(), which calls InvalidateInfo() when done
//
struct WOZEmptyImage525 // 5.25"
{
WOZHeader hdr;
WOZChunkHdr infoHdr;
InfoChunkv2 info;
BYTE infoPadding[INFO_CHUNK_SIZE-sizeof(InfoChunkv2)];
WOZChunkHdr tmapHdr;
Tmap tmap;
WOZChunkHdr trksHdr;
Trks trks;
};
struct WOZv1EmptyImage525 // 5.25"
{
WOZHeader hdr;
WOZChunkHdr infoHdr;
InfoChunk info;
BYTE infoPadding[INFO_CHUNK_SIZE-sizeof(InfoChunk)];
WOZChunkHdr tmapHdr;
Tmap tmap;
WOZChunkHdr trksHdr;
};
};
#pragma warning(pop)
#pragma pack(pop)
//-------------------------------------
@ -304,7 +368,8 @@ public:
}
ImageError_e Open(LPCTSTR pszImageFilename, ImageInfo* pImageInfo, const bool bCreateIfNecessary, std::string& strFilenameInZip);
void Close(ImageInfo* pImageInfo, const bool bDeleteFile);
void Close(ImageInfo* pImageInfo);
bool WOZUpdateInfo(ImageInfo* pImageInfo, DWORD& dwOffset);
virtual CImageBase* Detect(LPBYTE pImage, DWORD dwSize, const TCHAR* pszExt, DWORD& dwOffset, ImageInfo* pImageInfo) = 0;
virtual CImageBase* GetImageForCreation(const TCHAR* pszExt, DWORD* pCreateImageSize) = 0;
@ -317,7 +382,7 @@ protected:
ImageError_e CheckNormalFile(LPCTSTR pszImageFilename, ImageInfo* pImageInfo, const bool bCreateIfNecessary);
void GetCharLowerExt(TCHAR* pszExt, LPCTSTR pszImageFilename, const UINT uExtSize);
void GetCharLowerExt2(TCHAR* pszExt, LPCTSTR pszImageFilename, const UINT uExtSize);
void SetImageInfo(ImageInfo* pImageInfo, FileType_e eFileGZip, DWORD dwOffset, CImageBase* pImageType, DWORD dwSize);
void SetImageInfo(ImageInfo* pImageInfo, FileType_e fileType, DWORD dwOffset, CImageBase* pImageType, DWORD dwSize);
UINT GetNumImages(void) { return m_vecImageTypes.size(); };
CImageBase* GetImage(UINT uIndex) { _ASSERT(uIndex<GetNumImages()); return m_vecImageTypes[uIndex]; }

View file

@ -10,6 +10,8 @@
#define LOG_DISK_NIBBLES_WRITE 1
#define LOG_DISK_NIBBLES_WRITE_TRACK_GAPS 1 // Gap1, Gap2 & Gap3 info when writing a track
#define LOG_DISK_NIBBLES_USE_RUNTIME_VAR 1
#define LOG_DISK_WOZ_LOADWRITE 1
#define LOG_DISK_WOZ_SHIFTWRITE 1
// __VA_ARGS__ not supported on MSVC++ .NET 7.x
#if (LOG_DISK_ENABLED)

View file

@ -169,6 +169,7 @@ static int g_win_fullscreen_offsetx = 0;
static int g_win_fullscreen_offsety = 0;
static bool g_bFrameActive = false;
static bool g_windowMinimized = false;
static std::string driveTooltip;
@ -256,12 +257,14 @@ static void GetAppleWindowTitle()
default:
case A2TYPE_APPLE2: g_pAppTitle = TITLE_APPLE_2 ; break;
case A2TYPE_APPLE2PLUS: g_pAppTitle = TITLE_APPLE_2_PLUS ; break;
case A2TYPE_APPLE2JPLUS: g_pAppTitle = TITLE_APPLE_2_JPLUS ; break;
case A2TYPE_APPLE2E: g_pAppTitle = TITLE_APPLE_2E ; break;
case A2TYPE_APPLE2EENHANCED: g_pAppTitle = TITLE_APPLE_2E_ENHANCED; break;
case A2TYPE_PRAVETS82: g_pAppTitle = TITLE_PRAVETS_82 ; break;
case A2TYPE_PRAVETS8M: g_pAppTitle = TITLE_PRAVETS_8M ; break;
case A2TYPE_PRAVETS8A: g_pAppTitle = TITLE_PRAVETS_8A ; break;
case A2TYPE_TK30002E: g_pAppTitle = TITLE_TK3000_2E ; break;
case A2TYPE_BASE64A: g_pAppTitle = TITLE_BASE64A ; break;
}
#if _DEBUG
@ -274,10 +277,12 @@ static void GetAppleWindowTitle()
g_pAppTitle += " - ";
if( IsVideoStyle(VS_HALF_SCANLINES) )
{
g_pAppTitle += " 50% ";
}
g_pAppTitle += g_apVideoModeDesc[ g_eVideoType ];
g_pAppTitle += VideoGetAppWindowTitle();
if (g_CardMgr.GetDisk2CardMgr().IsAnyFirmware13Sector())
g_pAppTitle += " (S6-13) ";
if (g_hCustomRomF8 != INVALID_HANDLE_VALUE)
g_pAppTitle += TEXT(" (custom rom)");
@ -384,6 +389,9 @@ static void CreateGdiObjects(void)
case A2TYPE_TK30002E:
buttonbitmap[BTN_RUN] = (HBITMAP)LOADBUTTONBITMAP(TEXT("RUN3000E_BUTTON"));
break;
case A2TYPE_BASE64A:
buttonbitmap[BTN_RUN] = (HBITMAP)LOADBUTTONBITMAP(TEXT("RUNBASE64A_BUTTON"));
break;
default:
buttonbitmap[BTN_RUN] = (HBITMAP)LOADBUTTONBITMAP(TEXT("RUN_BUTTON"));
break;
@ -765,6 +773,9 @@ void FrameDrawDiskStatus( HDC passdc )
if (g_nAppMode == MODE_LOGO)
return;
if (g_windowMinimized) // Prevent DC leaks when app window is minimised (GH#820)
return;
// We use the actual drive since probing from memory doesn't tell us anything we don't already know.
// DOS3.3 ProDOS
// Drive $B7EA $BE3D
@ -1090,6 +1101,21 @@ LRESULT CALLBACK FrameWndProc (
g_bAppActive = (wparam ? TRUE : FALSE);
break;
case WM_SIZE:
switch(wparam)
{
case SIZE_RESTORED:
case SIZE_MAXIMIZED:
g_windowMinimized = false;
break;
case SIZE_MINIMIZED:
g_windowMinimized = true;
break;
default: // SIZE_MAXSHOW, SIZE_MAXHIDE
break;
}
break;
case WM_CLOSE:
LogFileOutput("WM_CLOSE\n");
if (g_bIsFullScreen && g_bRestart)
@ -1286,7 +1312,7 @@ LRESULT CALLBACK FrameWndProc (
case WM_KEYDOWN:
KeybUpdateCtrlShiftStatus();
// Process is done in WM_KEYUP: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8
// Processing is done in WM_KEYUP for: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8
if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == -1))
{
SetUsingCursor(FALSE);
@ -1347,7 +1373,7 @@ LRESULT CALLBACK FrameWndProc (
}
else if (wparam == VK_F10)
{
if (g_Apple2Type == A2TYPE_APPLE2E || g_Apple2Type == A2TYPE_APPLE2EENHANCED)
if (g_Apple2Type == A2TYPE_APPLE2E || g_Apple2Type == A2TYPE_APPLE2EENHANCED || g_Apple2Type == A2TYPE_BASE64A)
{
SetVideoRomRockerSwitch( !GetVideoRomRockerSwitch() ); // F10: toggle rocker switch
NTSC_VideoInitAppleType();
@ -1420,7 +1446,6 @@ LRESULT CALLBACK FrameWndProc (
LogOutput("WM_KEYDOWN: %08X (scanCode=%04X)\n", wparam, (lparam>>16)&0xfff);
#endif
if (!IsJoyKey &&
!KeybGetAltStatus() && // GH#749 - AltGr also fakes CTRL being pressed!
(g_nAppMode != MODE_LOGO)) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard
{
// GH#678 Alternate key(s) to toggle max speed
@ -1428,7 +1453,9 @@ LRESULT CALLBACK FrameWndProc (
// . Ctrl-1: Speed = 1 MHz
// . Ctrl-3: Speed = Full-Speed
bool keyHandled = false;
if( KeybGetCtrlStatus() && wparam >= '0' && wparam <= '9' )
if( KeybGetCtrlStatus() &&
!KeybGetAltStatus() && // GH#749 - AltGr also fakes CTRL being pressed!
wparam >= '0' && wparam <= '9' )
{
switch (wparam)
{
@ -1487,7 +1514,6 @@ LRESULT CALLBACK FrameWndProc (
break;
case WM_KEYUP:
// Process is done in WM_KEYUP: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8
if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == (int)wparam-VK_F1))
{
buttondown = -1;
@ -1495,7 +1521,23 @@ LRESULT CALLBACK FrameWndProc (
EraseButton(wparam-VK_F1);
else
DrawButton((HDC)0,wparam-VK_F1);
ProcessButtonClick(wparam-VK_F1, true);
const int iButton = wparam-VK_F1;
if (KeybGetCtrlStatus() && (wparam == VK_F3 || wparam == VK_F4)) // Ctrl+F3/F4 for drive pop-up menu (GH#817)
{
POINT pt; // location of mouse click
pt.x = buttonx + BUTTONCX/2;
pt.y = buttony + BUTTONCY/2 + iButton * BUTTONCY;
const int iDrive = wparam - VK_F3;
ProcessDiskPopupMenu( window, pt, iDrive );
FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES);
DrawButton((HDC)0, iButton);
}
else
{
ProcessButtonClick(iButton, true);
}
}
else
{
@ -1766,7 +1808,6 @@ LRESULT CALLBACK FrameWndProc (
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
// Right Click on Drive Icon -- eject Disk
if ((buttonover == -1) && (message == WM_RBUTTONUP)) // HACK: BUTTON_NONE
{
int x = LOWORD(lparam);
@ -1776,18 +1817,10 @@ LRESULT CALLBACK FrameWndProc (
(y >= buttony) &&
(y <= buttony+BUTTONS*BUTTONCY))
{
int iButton = (y-buttony-1)/BUTTONCY;
int iDrive = iButton - BTN_DRIVE1;
const int iButton = (y-buttony-1)/BUTTONCY;
const int iDrive = iButton - BTN_DRIVE1;
if ((iButton == BTN_DRIVE1) || (iButton == BTN_DRIVE2))
{
/*
if (KeybGetShiftStatus())
DiskProtect( iDrive, true );
else
if (KeybGetCtrlStatus())
DiskProtect( iDrive, false );
else
*/
{
RECT rect; // client area
POINT pt; // location of mouse click
@ -1807,7 +1840,7 @@ LRESULT CALLBACK FrameWndProc (
}
FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES);
DrawButton((HDC)0,iButton);
DrawButton((HDC)0, iButton);
}
}
}
@ -2294,7 +2327,7 @@ void ResetMachineState ()
HD_Reset();
g_bFullSpeed = 0; // Might've hit reset in middle of InternalCpuExecute() - so beep may get (partially) muted
MemReset(); // calls CpuInitialize()
MemReset(); // calls CpuInitialize(), CNoSlotClock.Reset()
PravetsReset();
if (g_CardMgr.QuerySlot(SLOT6) == CT_Disk2)
dynamic_cast<Disk2InterfaceCard&>(g_CardMgr.GetRef(SLOT6)).Boot();
@ -2337,6 +2370,13 @@ void CtrlReset()
VideoResetState(); // Switch Alternate char set off
}
if (IsAppleIIeOrAbove(GetApple2Type()) || IsCopamBase64A(GetApple2Type()))
{
// For A][ & A][+, reset doesn't reset the annunciators (UTAIIe:I-5)
// Base 64A: on RESET does reset to ROM page 0 (GH#807)
MemAnnunciatorReset();
}
PravetsReset();
g_CardMgr.GetDisk2CardMgr().Reset();
HD_Reset();

View file

@ -650,6 +650,10 @@ BYTE __stdcall JoyReadPosition(WORD programcounter, WORD address, BYTE, BYTE, UL
BOOL nPdlCntrActive = g_nCumulativeCycles <= (g_nJoyCntrResetCycle + (unsigned __int64) ((double)nPdlPos * PDL_CNTR_INTERVAL));
// If no joystick connected, then this is always active (GH#778)
if (joyinfo[joytype[nJoyNum]] == DEVICE_NONE)
nPdlCntrActive = TRUE;
return MemReadFloatingBus(nPdlCntrActive, nExecutedCycles);
}

View file

@ -77,6 +77,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define SW_INTCXROM (memmode & MF_INTCXROM)
#define SW_WRITERAM (memmode & MF_WRITERAM)
#define SW_IOUDIS (memmode & MF_IOUDIS)
#define SW_ALTROM0 (memmode & MF_ALTROM0) // For Copam Base64A
#define SW_ALTROM1 (memmode & MF_ALTROM1) // For Copam Base64A
/*
MEMORY MANAGEMENT SOFT SWITCHES
@ -210,7 +212,9 @@ static LPBYTE g_pMemMainLanguageCard = NULL;
static DWORD memmode = LanguageCardUnit::kMemModeInitialState;
static BOOL modechanging = 0; // An Optimisation: means delay calling UpdatePaging() for 1 instruction
static CNoSlotClock g_NoSlotClock;
static UINT memrompages = 1;
static CNoSlotClock* g_NoSlotClock = new CNoSlotClock;
static LanguageCardUnit* g_pLanguageCard = NULL; // For all Apple II, //e and above
#ifdef RAMWORKS
@ -233,6 +237,15 @@ static SS_CARDTYPE g_MemTypeAppleIIPlus = CT_LanguageCard; // Keep a copy so it'
static SS_CARDTYPE g_MemTypeAppleIIe = CT_Extended80Col; // Keep a copy so it's not lost if machine type changes, eg: A//e -> A][ -> A//e
static UINT g_uSaturnBanksFromCmdLine = 0;
const UINT CxRomSize = 4 * 1024;
const UINT Apple2RomSize = 12 * 1024;
const UINT Apple2eRomSize = Apple2RomSize + CxRomSize;
//const UINT Pravets82RomSize = 12*1024;
//const UINT Pravets8ARomSize = Pravets82RomSize+CxRomSize;
const UINT MaxRomPages = 4; // For Copam Base64A
const UINT Base64ARomSize = MaxRomPages * Apple2RomSize;
// Called from MemLoadSnapshot()
void ResetDefaultMachineMemTypes(void)
{
@ -372,6 +385,11 @@ LanguageCardUnit* GetLanguageCard(void)
return g_pLanguageCard;
}
LPBYTE GetCxRomPeripheral(void)
{
return pCxRomPeripheral; // Can be NULL if at MODE_LOGO
}
//=============================================================================
static BYTE __stdcall IORead_C00x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
@ -480,8 +498,11 @@ static BYTE __stdcall IORead_C05x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG
case 0xC: return IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
case 0xD: return IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
case 0xE: // fall through...
case 0xF: return (!SW_IOUDIS) ? VideoSetMode(pc, addr, bWrite, d, nExecutedCycles)
: IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
case 0xF: if (IsApple2PlusOrClone(GetApple2Type()))
IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
else
return (!SW_IOUDIS) ? VideoSetMode(pc, addr, bWrite, d, nExecutedCycles)
: IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
}
return 0;
@ -506,8 +527,11 @@ static BYTE __stdcall IOWrite_C05x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULON
case 0xC: return IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
case 0xD: return IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
case 0xE: // fall through...
case 0xF: return (!SW_IOUDIS) ? VideoSetMode(pc, addr, bWrite, d, nExecutedCycles)
: IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
case 0xF: if (IsApple2PlusOrClone(GetApple2Type()))
IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
else
return (!SW_IOUDIS) ? VideoSetMode(pc, addr, bWrite, d, nExecutedCycles)
: IO_Annunciator(pc, addr, bWrite, d, nExecutedCycles);
}
return 0;
@ -681,9 +705,13 @@ BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYT
g_Annunciator[(address>>1) & 3] = (address&1) ? true : false;
if (address >= 0xC058 && address <= 0xC05B)
{
JoyportControl(address & 0x3); // AN0 and AN1 control
}
if (address >= 0xC058 && address <= 0xC05B && IsCopamBase64A(GetApple2Type()))
MemSetPaging(programcounter, address, write, value, nExecutedCycles);
if (address >= 0xC05C && address <= 0xC05D && IsApple2JPlus(GetApple2Type()))
NTSC_VideoInitAppleType(); // AN2 switches between Katakana & ASCII video rom chars (GH#773)
if (!write)
return MemReadFloatingBus(nExecutedCycles);
@ -818,17 +846,17 @@ static BYTE __stdcall IO_Cxxx(WORD programcounter, WORD address, BYTE write, BYT
}
}
if (IsPotentialNoSlotClockAccess(address))
if (g_NoSlotClock && IsPotentialNoSlotClockAccess(address))
{
if (!write)
{
int data = 0;
if (g_NoSlotClock.Read(address, data))
if (g_NoSlotClock->Read(address, data))
return (BYTE) data;
}
else
{
g_NoSlotClock.Write(address);
g_NoSlotClock->Write(address);
return 0;
}
}
@ -1118,12 +1146,17 @@ static void UpdatePaging(BOOL initialize)
: pCxRomInternal+uRomOffset; // C800..CFFF - Internal ROM
}
const int selectedrompage = (SW_ALTROM0 ? 1 : 0) | (SW_ALTROM1 ? 2 : 0);
#ifdef _DEBUG
if (selectedrompage) { _ASSERT(IsCopamBase64A(GetApple2Type())); }
#endif
const int romoffset = (selectedrompage % memrompages) * Apple2RomSize; // Only Copam Base64A has a non-zero romoffset
for (loop = 0xD0; loop < 0xE0; loop++)
{
int bankoffset = (SW_BANK2 ? 0 : 0x1000);
const int bankoffset = (SW_BANK2 ? 0 : 0x1000);
memshadow[loop] = SW_HIGHRAM ? SW_ALTZP ? memaux+(loop << 8)-bankoffset
: g_pMemMainLanguageCard+((loop-0xC0)<<8)-bankoffset
: memrom+((loop-0xD0) * 0x100);
: memrom+((loop-0xD0) * 0x100)+romoffset;
memwrite[loop] = SW_WRITERAM ? SW_HIGHRAM ? mem+(loop << 8)
: SW_ALTZP ? memaux+(loop << 8)-bankoffset
@ -1135,7 +1168,7 @@ static void UpdatePaging(BOOL initialize)
{
memshadow[loop] = SW_HIGHRAM ? SW_ALTZP ? memaux+(loop << 8)
: g_pMemMainLanguageCard+((loop-0xC0)<<8)
: memrom+((loop-0xD0) * 0x100);
: memrom+((loop-0xD0) * 0x100)+romoffset;
memwrite[loop] = SW_WRITERAM ? SW_HIGHRAM ? mem+(loop << 8)
: SW_ALTZP ? memaux+(loop << 8)
@ -1415,19 +1448,13 @@ bool MemIsAddrCodeMemory(const USHORT addr)
//===========================================================================
const UINT CxRomSize = 4*1024;
const UINT Apple2RomSize = 12*1024;
const UINT Apple2eRomSize = Apple2RomSize+CxRomSize;
//const UINT Pravets82RomSize = 12*1024;
//const UINT Pravets8ARomSize = Pravets82RomSize+CxRomSize;
void MemInitialize()
{
// ALLOCATE MEMORY FOR THE APPLE MEMORY IMAGE AND ASSOCIATED DATA STRUCTURES
memaux = (LPBYTE)VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE);
memmain = (LPBYTE)VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE);
memdirty = (LPBYTE)VirtualAlloc(NULL,0x100 ,MEM_COMMIT,PAGE_READWRITE);
memrom = (LPBYTE)VirtualAlloc(NULL,0x5000 ,MEM_COMMIT,PAGE_READWRITE);
memrom = (LPBYTE)VirtualAlloc(NULL,0x3000 * MaxRomPages ,MEM_COMMIT,PAGE_READWRITE);
memimage = (LPBYTE)VirtualAlloc(NULL,_6502_MEM_END+1,MEM_RESERVE,PAGE_NOACCESS);
pCxRomInternal = (LPBYTE) VirtualAlloc(NULL, CxRomSize, MEM_COMMIT, PAGE_READWRITE);
@ -1486,6 +1513,7 @@ void MemInitialize()
CreateLanguageCard();
MemInitializeROM();
MemInitializeCustomROM();
MemInitializeCustomF8ROM();
MemInitializeIO();
MemReset();
@ -1500,12 +1528,14 @@ void MemInitializeROM(void)
{
case A2TYPE_APPLE2: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2_ROM ), "ROM"); ROM_SIZE = Apple2RomSize ; break;
case A2TYPE_APPLE2PLUS: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2_PLUS_ROM ), "ROM"); ROM_SIZE = Apple2RomSize ; break;
case A2TYPE_APPLE2JPLUS: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2_JPLUS_ROM ), "ROM"); ROM_SIZE = Apple2RomSize ; break;
case A2TYPE_APPLE2E: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2E_ROM ), "ROM"); ROM_SIZE = Apple2eRomSize; break;
case A2TYPE_APPLE2EENHANCED:hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2E_ENHANCED_ROM), "ROM"); ROM_SIZE = Apple2eRomSize; break;
case A2TYPE_PRAVETS82: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_PRAVETS_82_ROM ), "ROM"); ROM_SIZE = Apple2RomSize ; break;
case A2TYPE_PRAVETS8M: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_PRAVETS_8M_ROM ), "ROM"); ROM_SIZE = Apple2RomSize ; break;
case A2TYPE_PRAVETS8A: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_PRAVETS_8C_ROM ), "ROM"); ROM_SIZE = Apple2eRomSize; break;
case A2TYPE_TK30002E: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_TK3000_2E_ROM ), "ROM"); ROM_SIZE = Apple2eRomSize; break;
case A2TYPE_BASE64A: hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_BASE_64A_ROM ), "ROM"); ROM_SIZE = Base64ARomSize; break;
}
if (hResInfo == NULL)
@ -1515,12 +1545,14 @@ void MemInitializeROM(void)
{
case A2TYPE_APPLE2: _tcscpy(sRomFileName, TEXT("APPLE2.ROM" )); break;
case A2TYPE_APPLE2PLUS: _tcscpy(sRomFileName, TEXT("APPLE2_PLUS.ROM" )); break;
case A2TYPE_APPLE2JPLUS: _tcscpy(sRomFileName, TEXT("APPLE2_JPLUS.ROM" )); break;
case A2TYPE_APPLE2E: _tcscpy(sRomFileName, TEXT("APPLE2E.ROM" )); break;
case A2TYPE_APPLE2EENHANCED:_tcscpy(sRomFileName, TEXT("APPLE2E_ENHANCED.ROM")); break;
case A2TYPE_PRAVETS82: _tcscpy(sRomFileName, TEXT("PRAVETS82.ROM" )); break;
case A2TYPE_PRAVETS8M: _tcscpy(sRomFileName, TEXT("PRAVETS8M.ROM" )); break;
case A2TYPE_PRAVETS8A: _tcscpy(sRomFileName, TEXT("PRAVETS8C.ROM" )); break;
case A2TYPE_TK30002E: _tcscpy(sRomFileName, TEXT("TK3000e.ROM" )); break;
case A2TYPE_BASE64A: _tcscpy(sRomFileName, TEXT("BASE64A.ROM" )); break;
default:
{
_tcscpy(sRomFileName, TEXT("Unknown type!"));
@ -1564,8 +1596,9 @@ void MemInitializeROM(void)
ROM_SIZE -= CxRomSize;
}
_ASSERT(ROM_SIZE == Apple2RomSize);
memcpy(memrom, pData, Apple2RomSize); // ROM at $D000...$FFFF
memrompages = MAX(MaxRomPages, ROM_SIZE / Apple2RomSize);
_ASSERT(ROM_SIZE % Apple2RomSize == 0);
memcpy(memrom, pData, ROM_SIZE); // ROM at $D000...$FFFF, one or several pages
}
void MemInitializeCustomF8ROM(void)
@ -1603,15 +1636,14 @@ void MemInitializeCustomF8ROM(void)
if (g_hCustomRomF8 != INVALID_HANDLE_VALUE)
{
BYTE OldRom[Apple2RomSize]; // NB. 12KB on stack
memcpy(OldRom, memrom, Apple2RomSize);
std::vector<BYTE> oldRom(memrom, memrom+Apple2RomSize); // range ctor: [first,last)
SetFilePointer(g_hCustomRomF8, 0, NULL, FILE_BEGIN);
DWORD uNumBytesRead;
BOOL bRes = ReadFile(g_hCustomRomF8, memrom+F8RomOffset, F8RomSize, &uNumBytesRead, NULL);
if (uNumBytesRead != F8RomSize)
{
memcpy(memrom, OldRom, Apple2RomSize); // ROM at $D000...$FFFF
memcpy(memrom, &oldRom[0], Apple2RomSize); // ROM at $D000...$FFFF
bRes = FALSE;
}
@ -1640,6 +1672,48 @@ void MemInitializeCustomF8ROM(void)
}
}
void MemInitializeCustomROM(void)
{
if (g_hCustomRom == INVALID_HANDLE_VALUE)
return;
SetFilePointer(g_hCustomRom, 0, NULL, FILE_BEGIN);
DWORD uNumBytesRead;
BOOL bRes = TRUE;
if (GetFileSize(g_hCustomRom, NULL) == Apple2eRomSize)
{
std::vector<BYTE> oldRomC0(pCxRomInternal, pCxRomInternal+CxRomSize); // range ctor: [first,last)
bRes = ReadFile(g_hCustomRom, pCxRomInternal, CxRomSize, &uNumBytesRead, NULL);
if (uNumBytesRead != CxRomSize)
{
memcpy(pCxRomInternal, &oldRomC0[0], CxRomSize); // ROM at $C000...$CFFF
bRes = FALSE;
}
}
if (bRes)
{
std::vector<BYTE> oldRom(memrom, memrom+Apple2RomSize); // range ctor: [first,last)
bRes = ReadFile(g_hCustomRom, memrom, Apple2RomSize, &uNumBytesRead, NULL);
if (uNumBytesRead != Apple2RomSize)
{
memcpy(memrom, &oldRom[0], Apple2RomSize); // ROM at $D000...$FFFF
bRes = FALSE;
}
}
// NB. If succeeded, then keep g_hCustomRom handle open - so that any next restart can load it again
if (!bRes)
{
MessageBox( g_hFrameWindow, "Failed to read custom rom", TEXT("AppleWin Error"), MB_OK );
CloseHandle(g_hCustomRom);
g_hCustomRom = INVALID_HANDLE_VALUE;
// Failed, so use default rom...
}
}
// Called by:
// . MemInitialize()
// . Snapshot_LoadState_v2()
@ -1705,19 +1779,17 @@ void MemInitializeIO(void)
if (g_CardMgr.QuerySlot(SLOT7) == CT_GenericHDD)
HD_Load_Rom(pCxRomPeripheral, SLOT7); // $C700 : HDD f/w
//
// Finally remove the cards' ROMs at $Csnn if internal ROM is enabled
// . required when restoring saved-state
if (SW_INTCXROM)
IoHandlerCardsOut();
}
// Called by:
// . Snapshot_LoadState_v2()
void MemInitializeCardExpansionRomFromSnapshot(void)
void MemInitializeCardSlotAndExpansionRomFromSnapshot(void)
{
// Remove all the cards' ROMs at $Csnn if internal ROM is enabled
if (IsAppleIIeOrAbove(GetApple2Type()) && SW_INTCXROM)
IoHandlerCardsOut();
// Potentially init a card's expansion ROM
const UINT uSlot = g_uPeripheralRomSlot;
if (ExpansionRom[uSlot] == NULL)
@ -1737,7 +1809,7 @@ inline DWORD getRandomTime()
//===========================================================================
// Called by:
// . MemInitialize()
// . MemInitialize() eg. on AppleWin start & restart (eg. h/w config changes)
// . ResetMachineState() eg. Power-cycle ('Apple-Go' button)
// . Snapshot_LoadState_v2()
void MemReset()
@ -1884,7 +1956,8 @@ void MemReset()
mem = memimage;
// INITIALIZE PAGING, FILLING IN THE 64K MEMORY IMAGE
ResetPaging(1); // Initialize=1
ResetPaging(TRUE); // Initialize=1, init memmode
MemAnnunciatorReset();
// INITIALIZE & RESET THE CPU
// . Do this after ROM has been copied back to mem[], so that PC is correctly init'ed from 6502's reset vector
@ -1892,6 +1965,9 @@ void MemReset()
//Sets Caps Lock = false (Pravets 8A/C only)
z80_reset(); // NB. Also called above in CpuInitialize()
if (g_NoSlotClock)
g_NoSlotClock->Reset(); // NB. Power-cycle, but not RESET signal
}
//===========================================================================
@ -1986,6 +2062,17 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE
}
}
if (IsCopamBase64A(GetApple2Type()))
{
switch (address)
{
case 0x58: SetMemMode(memmode & ~MF_ALTROM0); break;
case 0x59: SetMemMode(memmode | MF_ALTROM0); break;
case 0x5A: SetMemMode(memmode & ~MF_ALTROM1); break;
case 0x5B: SetMemMode(memmode | MF_ALTROM1); break;
}
}
if (MemOptimizeForModeChanging(programcounter, address))
return write ? 0 : MemReadFloatingBus(nExecutedCycles);
@ -2034,7 +2121,7 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE
bool MemOptimizeForModeChanging(WORD programcounter, WORD address)
{
if (IS_APPLE2E())
if (IsAppleIIeOrAbove(GetApple2Type()))
{
// IF THE EMULATED PROGRAM HAS JUST UPDATED THE MEMORY WRITE MODE AND IS
// ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL
@ -2071,6 +2158,18 @@ LPVOID MemGetSlotParameters(UINT uSlot)
//===========================================================================
void MemAnnunciatorReset(void)
{
for (UINT i=0; i<kNumAnnunciators; i++)
g_Annunciator[i] = 0;
if (IsCopamBase64A(GetApple2Type()))
{
SetMemMode(memmode & ~(MF_ALTROM0|MF_ALTROM1));
UpdatePaging(FALSE); // Initialize=FALSE
}
}
bool MemGetAnnunciator(UINT annunciator)
{
return g_Annunciator[annunciator];
@ -2078,6 +2177,26 @@ bool MemGetAnnunciator(UINT annunciator)
//===========================================================================
bool MemHasNoSlotClock(void)
{
return g_NoSlotClock != NULL;
}
void MemInsertNoSlotClock(void)
{
if (!MemHasNoSlotClock())
g_NoSlotClock = new CNoSlotClock;
g_NoSlotClock->Reset();
}
void MemRemoveNoSlotClock(void)
{
delete g_NoSlotClock;
g_NoSlotClock = NULL;
}
//===========================================================================
// NB. Don't need to save 'modechanging', as this is just an optimisation to save calling UpdatePaging() twice.
// . If we were to save the state when 'modechanging' is set, then on restoring the state, the 6502 code will immediately update the read memory mode.
// . This will work correctly.
@ -2394,3 +2513,17 @@ bool MemLoadSnapshotAux(YamlLoadHelper& yamlLoadHelper, UINT unitVersion)
return true;
}
void NoSlotClockSaveSnapshot(YamlSaveHelper& yamlSaveHelper)
{
if (g_NoSlotClock)
g_NoSlotClock->SaveSnapshot(yamlSaveHelper);
}
void NoSlotClockLoadSnapshot(YamlLoadHelper& yamlLoadHelper)
{
if (!g_NoSlotClock)
g_NoSlotClock = new CNoSlotClock;
g_NoSlotClock->LoadSnapshot(yamlLoadHelper);
}

View file

@ -16,6 +16,8 @@
#define MF_INTCXROM 0x00000200
#define MF_WRITERAM 0x00000400 // Language Card RAM is Write Enabled
#define MF_IOUDIS 0x00000800 // Disable IOU access for addresses $C058 to $C05F; enable access to DHIRES switch (0=on) (Enhanced //e only)
#define MF_ALTROM0 0x00001000 // Use alternate ROM for $D000 to $FFFF. Two bits for up to 4 pages
#define MF_ALTROM1 0x00002000 // Use alternate ROM, second bit to have four pages
#define MF_IMAGEMASK 0x000003F7
#define MF_LANGCARD_MASK (MF_WRITERAM|MF_HIGHRAM|MF_BANK2)
@ -72,21 +74,28 @@ bool MemOptimizeForModeChanging(WORD programcounter, WORD address);
bool MemIsAddrCodeMemory(const USHORT addr);
void MemInitialize ();
void MemInitializeROM(void);
void MemInitializeCustomROM(void);
void MemInitializeCustomF8ROM(void);
void MemInitializeIO(void);
void MemInitializeCardExpansionRomFromSnapshot(void);
void MemInitializeCardSlotAndExpansionRomFromSnapshot(void);
BYTE MemReadFloatingBus(const ULONG uExecutedCycles);
BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles);
void MemReset ();
void MemResetPaging ();
void MemUpdatePaging(BOOL initialize);
LPVOID MemGetSlotParameters (UINT uSlot);
void MemAnnunciatorReset(void);
bool MemGetAnnunciator(UINT annunciator);
bool MemHasNoSlotClock(void);
void MemInsertNoSlotClock(void);
void MemRemoveNoSlotClock(void);
std::string MemGetSnapshotUnitAuxSlotName(void);
void MemSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
bool MemLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT unitVersion);
void MemSaveSnapshotAux(class YamlSaveHelper& yamlSaveHelper);
bool MemLoadSnapshotAux(class YamlLoadHelper& yamlLoadHelper, UINT unitVersion);
void NoSlotClockSaveSnapshot(YamlSaveHelper& yamlSaveHelper);
void NoSlotClockLoadSnapshot(YamlLoadHelper& yamlLoadHelper);
BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles);
@ -103,3 +112,5 @@ UINT GetRamWorksActiveBank(void);
void SetSaturnMemorySize(UINT banks);
void SetMemMainLanguageCard(LPBYTE ptr, bool bMemMain=false);
class LanguageCardUnit* GetLanguageCard(void);
LPBYTE GetCxRomPeripheral(void);

View file

@ -87,11 +87,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Mockingboard.h"
#include "SoundCore.h"
#include "YamlHelper.h"
#include "Riff.h"
#include "AY8910.h"
#include "SSI263Phonemes.h"
#define LOG_SSI263 0
#define LOG_SSI263B 0 // Alternate SSI263 logging (use in conjunction with CPU.cpp's LOG_IRQ_TAKEN_AND_RTI)
#define SY6522_DEVICE_A 0
@ -187,7 +189,8 @@ static bool g_bMBAvailable = false;
static SS_CARDTYPE g_SoundcardType = CT_Empty; // Use CT_Empty to mean: no soundcard
static bool g_bPhasorEnable = false;
static BYTE g_nPhasorMode = 0; // 0=Mockingboard emulation, 1=Phasor native
enum PHASOR_MODE {PH_Mockingboard=0, PH_UNDEF1, PH_UNDEF2, PH_UNDEF3, PH_UNDEF4, PH_Phasor/*=5*/, PH_UNDEF6, PH_EchoPlus/*=7*/};
static PHASOR_MODE g_phasorMode = PH_Mockingboard;
static UINT g_PhasorClockScaleFactor = 1; // for save-state only
//-------------------------------------
@ -363,8 +366,7 @@ static void UpdateIFR(SY6522_AY8910* pMB, BYTE clr_ifr, BYTE set_ifr=0)
// NB. Mockingboard generates IRQ on both 6522s:
// . SSI263's IRQ (A/!R) is routed via the 2nd 6522 (at $Cx80) and must generate a 6502 IRQ (not NMI)
// . SC-01's IRQ (A/!R) is also routed via a (2nd?) 6522
// Phasor's SSI263 appears to be wired directly to the 6502's IRQ (ie. not via a 6522)
// . I assume Phasor's 6522s just generate 6502 IRQs (not NMIs)
// Phasor's SSI263 IRQ (A/!R) line is *also* wired directly to the 6502's IRQ (as well as the 6522's CA1)
if (bIRQ)
CpuIrqAssert(IS_6522);
@ -394,7 +396,7 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
if(g_bPhasorEnable)
{
int nAY_CS = (g_nPhasorMode & 1) ? (~(nValue >> 3) & 3) : 1;
int nAY_CS = (g_phasorMode == PH_Phasor) ? (~(nValue >> 3) & 3) : 1;
if(nAY_CS & 1)
AY8910_Write(nDevice, nReg, nValue, 0);
@ -446,7 +448,7 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
// Clear Timer2 Interrupt Flag.
UpdateIFR(pMB, IxR_TIMER2);
pMB->sy6522.TIMER2_LATCH.h = nValue;
pMB->sy6522.TIMER2_LATCH.h = nValue; // NB. Real 6522 doesn't have TIMER2_LATCH.h
pMB->sy6522.TIMER2_COUNTER.w = pMB->sy6522.TIMER2_LATCH.w;
StartTimer2(pMB);
@ -471,29 +473,14 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
// Clear those bits which are set in the lower 7 bits.
nValue ^= 0x7F;
pMB->sy6522.IER &= nValue;
UpdateIFR(pMB, 0);
// Check if active timer has been disabled:
if (((pMB->sy6522.IER & IxR_TIMER1) == 0) && pMB->bTimer1Active)
StopTimer1(pMB);
if (((pMB->sy6522.IER & IxR_TIMER2) == 0) && pMB->bTimer2Active)
StopTimer2(pMB);
}
else
{
// Set those bits which are set in the lower 7 bits.
nValue &= 0x7F;
pMB->sy6522.IER |= nValue;
UpdateIFR(pMB, 0);
// Check if a timer interrupt has been enabled (regardless of if there's an active timer or not): GH#567
if (pMB->sy6522.IER & IxR_TIMER1)
StartTimer1(pMB);
if (pMB->sy6522.IER & IxR_TIMER2)
StartTimer2(pMB);
}
UpdateIFR(pMB, 0);
break;
case 0x0f: // ORA_NO_HS
break;
@ -569,7 +556,7 @@ static BYTE SY6522_Read(BYTE nDevice, BYTE nReg)
//---------------------------------------------------------------------------
void SSI263_Play(unsigned int nPhoneme);
static void SSI263_Play(unsigned int nPhoneme);
#if 0
typedef struct
@ -605,52 +592,77 @@ const BYTE CONTROL_MASK = 0x80;
const BYTE ARTICULATION_MASK = 0x70;
const BYTE AMPLITUDE_MASK = 0x0F;
static BYTE SSI263_Read(BYTE nDevice, BYTE nReg)
#if LOG_SSI263B
static int ssiRegs[5]={-1,-1,-1,-1,-1};
void SSI_Output(void)
{
LogOutput("SSI: ");
for (int i=0; i<=4; i++)
{
char r[3]="--";
if (ssiRegs[i]>=0) sprintf(r,"%02X",ssiRegs[i]);
LogOutput("%s ", r);
ssiRegs[i] = -1;
}
LogOutput("\n");
}
#endif
static BYTE SSI263_Read(BYTE nDevice, ULONG nExecutedCycles)
{
SY6522_AY8910* pMB = &g_MB[nDevice];
// Regardless of register, just return inverted A/!R in bit7
// . A/!R is low for IRQ
return pMB->SpeechChip.CurrentMode << 7;
return MemReadFloatingBus(pMB->SpeechChip.CurrentMode & 1, nExecutedCycles);
}
static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
{
SY6522_AY8910* pMB = &g_MB[nDevice];
#if LOG_SSI263B
_ASSERT(nReg < 5);
if (nReg>4) nReg=4;
if (ssiRegs[nReg]>=0) SSI_Output(); // overwriting a reg
ssiRegs[nReg] = nValue;
#endif
switch(nReg)
{
case SSI_DURPHON:
#if LOG_SSI263
if(g_fh) fprintf(g_fh, "DUR = 0x%02X, PHON = 0x%02X\n\n", nValue>>6, nValue&PHONEME_MASK);
LogOutput("DUR = %d, PHON = 0x%02X\n", nValue>>6, nValue&PHONEME_MASK);
#endif
#if LOG_SSI263B
SSI_Output();
#endif
// Datasheet is not clear, but a write to DURPHON must clear the IRQ
if(g_bPhasorEnable)
{
CpuIrqDeassert(IS_SPEECH);
}
else
{
UpdateIFR(pMB, IxR_PERIPHERAL);
}
// Notes:
// . Phasor's text-to-speech playback has no CTL H->L
// - ISR just writes CTL=0 (and new ART+AMP values), and writes DUR=x (and new PHON)
// - since no CTL H->L, then DUR value doesn't take affect (so continue using previous)
// - so the write to DURPHON must clear the IRQ
// . Does a write of CTL=0 clear IRQ? (ie. CTL 0->0)
// . Does a write of CTL=1 clear IRQ? (ie. CTL 0->1)
// - SSI263 datasheet says: "Setting the Control bit (CTL) to a logic one puts the device into Power Down mode..."
// . Does phoneme output only happen when CTL=0? (Otherwise device is in PD mode)
// SSI263 datasheet is not clear, but a write to DURPHON must clear the IRQ.
// NB. For Mockingboard, A/!R is ack'ed by 6522's PCR handshake.
if (g_bPhasorEnable && g_phasorMode == PH_Phasor)
CpuIrqDeassert(IS_SPEECH);
pMB->SpeechChip.CurrentMode &= ~1; // Clear SSI263's D7 pin
pMB->SpeechChip.DurationPhoneme = nValue;
g_nSSI263Device = nDevice;
// Phoneme output not dependent on CONTROL bit
if(g_bPhasorEnable)
{
if(nValue || (g_nCurrentActivePhoneme<0))
SSI263_Play(nValue & PHONEME_MASK);
}
else
{
SSI263_Play(nValue & PHONEME_MASK);
}
SSI263_Play(nValue & PHONEME_MASK);
break;
case SSI_INFLECT:
#if LOG_SSI263
@ -658,6 +670,7 @@ static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
#endif
pMB->SpeechChip.Inflection = nValue;
break;
case SSI_RATEINF:
#if LOG_SSI263
if(g_fh) fprintf(g_fh, "RATE = 0x%02X, INF = 0x%02X\n", nValue>>4, nValue&0x0F);
@ -667,19 +680,44 @@ static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
case SSI_CTTRAMP:
#if LOG_SSI263
if(g_fh) fprintf(g_fh, "CTRL = %d, ART = 0x%02X, AMP=0x%02X\n", nValue>>7, (nValue&ARTICULATION_MASK)>>4, nValue&AMPLITUDE_MASK);
//
{
bool H2L = (pMB->SpeechChip.CtrlArtAmp & CONTROL_MASK) && !(nValue & CONTROL_MASK);
char newMode[20];
sprintf_s(newMode, sizeof(newMode), "(new mode=%d)", pMB->SpeechChip.DurationPhoneme>>6);
LogOutput("CTRL = %d->%d, ART = 0x%02X, AMP=0x%02X %s\n", pMB->SpeechChip.CtrlArtAmp>>7, nValue>>7, (nValue&ARTICULATION_MASK)>>4, nValue&AMPLITUDE_MASK, H2L?newMode:"");
}
#endif
#if LOG_SSI263B
if ( ((pMB->SpeechChip.CtrlArtAmp & CONTROL_MASK) && !(nValue & CONTROL_MASK)) || ((nValue&0xF) == 0x0) ) // H->L or amp=0
SSI_Output();
#endif
if((pMB->SpeechChip.CtrlArtAmp & CONTROL_MASK) && !(nValue & CONTROL_MASK)) // H->L
{
pMB->SpeechChip.CurrentMode = pMB->SpeechChip.DurationPhoneme & DURATION_MODE_MASK;
if (pMB->SpeechChip.CurrentMode == MODE_IRQ_DISABLED)
{
// "Disables A/!R output only; does not change previous A/!R response" (SSI263 datasheet)
// CpuIrqDeassert(IS_SPEECH);
}
}
pMB->SpeechChip.CtrlArtAmp = nValue;
// "Setting the Control bit (CTL) to a logic one puts the device into Power Down mode..." (SSI263 datasheet)
if (pMB->SpeechChip.CtrlArtAmp & CONTROL_MASK)
{
// CpuIrqDeassert(IS_SPEECH);
// pMB->SpeechChip.CurrentMode &= ~1; // Clear SSI263's D7 pin
}
break;
case SSI_FILFREQ:
case SSI_FILFREQ: // RegAddr.b2=1 (b1 & b0 are: don't care)
default:
#if LOG_SSI263
if(g_fh) fprintf(g_fh, "FFREQ = 0x%02X\n", nValue);
#endif
pMB->SpeechChip.FilterFreq = nValue;
break;
default:
break;
}
}
@ -777,7 +815,7 @@ static UINT64 g_uLastMBUpdateCycle = 0;
// Called by:
// . MB_UpdateCycles() - when g_nMBTimerDevice == {0,1,2,3}
// . MB_PeriodicUpdate() - when g_nMBTimerDevice == kTIMERDEVICE_INVALID
static void MB_Update(void)
static void MB_UpdateInt(void)
{
if (!MockingboardVoice.bActive)
return;
@ -984,8 +1022,59 @@ static void MB_Update(void)
#endif
}
static void MB_Update(void)
{
#ifdef LOG_PERF_TIMINGS
extern UINT64 g_timeMB_NoTimer;
extern UINT64 g_timeMB_Timer;
PerfMarker perfMarker(g_nMBTimerDevice == kTIMERDEVICE_INVALID ? g_timeMB_NoTimer : g_timeMB_Timer);
#endif
MB_UpdateInt();
}
//-----------------------------------------------------------------------------
// Called by SSI263Thread(), MB_LoadSnapshot & Phasor_LoadSnapshot
// Pre: g_bVotraxPhoneme, g_bPhasorEnable, g_phasorMode
static void SetSpeechIRQ(SY6522_AY8910* pMB)
{
if (!g_bVotraxPhoneme)
{
// Always set SSI263's D7 pin regardless of SSI263 mode (DR1:0), including MODE_IRQ_DISABLED
pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
if ((pMB->SpeechChip.CurrentMode & DURATION_MODE_MASK) != MODE_IRQ_DISABLED)
{
if (!g_bPhasorEnable || (g_bPhasorEnable && g_phasorMode == PH_Mockingboard))
{
if ((pMB->sy6522.PCR & 1) == 0) // CA1 Latch/Input = 0 (Negative active edge)
UpdateIFR(pMB, 0, IxR_PERIPHERAL);
if (pMB->sy6522.PCR == 0x0C) // CA2 Control = b#110 (Low output)
pMB->SpeechChip.CurrentMode &= ~1; // Clear SSI263's D7 pin (cleared by 6522's PCR CA1/CA2 handshake)
// NB. Don't set CTL=1, as Mockingboard(SMS) speech doesn't work (it sets MODE_IRQ_DISABLED mode during ISR)
//pMB->SpeechChip.CtrlArtAmp |= CONTROL_MASK; // 6522's CA2 sets Power Down mode (pin 18), which sets Control bit
}
else if (g_bPhasorEnable && g_phasorMode == PH_Phasor) // Phasor's SSI263 IRQ (A/!R) line is *also* wired directly to the 6502's IRQ (as well as the 6522's CA1)
{
CpuIrqAssert(IS_SPEECH);
}
}
}
//
if (g_bVotraxPhoneme && pMB->sy6522.PCR == 0xB0)
{
// !A/R: Time-out of old phoneme (signal goes from low to high)
UpdateIFR(pMB, 0, IxR_VOTRAX);
g_bVotraxPhoneme = false;
}
}
static DWORD WINAPI SSI263Thread(LPVOID lpParameter)
{
while(1)
@ -1016,41 +1105,15 @@ static DWORD WINAPI SSI263Thread(LPVOID lpParameter)
//if(g_fh) fprintf(g_fh, "IRQ: Phoneme complete (0x%02X)\n\n", g_nCurrentActivePhoneme);
#endif
if (g_nCurrentActivePhoneme < 0)
continue; // On CTRL+RESET or power-cycle (during phoneme playback): ResetState() is called, which set g_nCurrentActivePhoneme=-1
SSI263Voice[g_nCurrentActivePhoneme].bActive = false;
g_nCurrentActivePhoneme = -1;
// Phoneme complete, so generate IRQ if necessary
SY6522_AY8910* pMB = &g_MB[g_nSSI263Device];
if(g_bPhasorEnable)
{
if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED))
{
pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
// Phasor's SSI263.IRQ line appears to be wired directly to IRQ (Bypassing the 6522)
CpuIrqAssert(IS_SPEECH);
}
}
else
{
if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C))
{
UpdateIFR(pMB, 0, IxR_PERIPHERAL);
pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
}
}
//
if(g_bVotraxPhoneme && (pMB->sy6522.PCR == 0xB0))
{
// !A/R: Time-out of old phoneme (signal goes from low to high)
UpdateIFR(pMB, 0, IxR_VOTRAX);
g_bVotraxPhoneme = false;
}
SetSpeechIRQ(pMB);
}
return 0;
@ -1219,13 +1282,13 @@ static bool MB_DSInit()
FALSE, // bManualReset (FALSE = auto-reset)
FALSE, // bInitialState (FALSE = non-signaled)
NULL); // lpName
LogFileOutput("MB_DSInit: CreateEvent(), g_hSSI263Event[0]=0x%08X\n", (UINT32)g_hSSI263Event[0]);
LogFileOutput("MB_DSInit: CreateEvent(), g_hSSI263Event[0]=0x%08X\n", g_hSSI263Event[0]);
g_hSSI263Event[1] = CreateEvent(NULL, // lpEventAttributes
FALSE, // bManualReset (FALSE = auto-reset)
FALSE, // bInitialState (FALSE = non-signaled)
NULL); // lpName
LogFileOutput("MB_DSInit: CreateEvent(), g_hSSI263Event[1]=0x%08X\n", (UINT32)g_hSSI263Event[1]);
LogFileOutput("MB_DSInit: CreateEvent(), g_hSSI263Event[1]=0x%08X\n", g_hSSI263Event[1]);
if((g_hSSI263Event[0] == NULL) || (g_hSSI263Event[1] == NULL))
{
@ -1327,7 +1390,7 @@ static bool MB_DSInit()
NULL, // lpParameter
0, // dwCreationFlags : 0 = Run immediately
&dwThreadId); // lpThreadId
LogFileOutput("MB_DSInit: CreateThread(), g_hThread=0x%08X\n", (UINT32)g_hThread);
LogFileOutput("MB_DSInit: CreateThread(), g_hThread=0x%08X\n", g_hThread);
BOOL bRes2 = SetThreadPriority(g_hThread, THREAD_PRIORITY_TIME_CRITICAL);
LogFileOutput("MB_DSInit: SetThreadPriority(), bRes=%d\n", bRes2 ? 1 : 0);
@ -1448,7 +1511,7 @@ void MB_Initialize()
g_bCritSectionValid = true;
}
void MB_SetSoundcardType(SS_CARDTYPE NewSoundcardType);
static void MB_SetSoundcardType(SS_CARDTYPE NewSoundcardType);
// NB. Mockingboard voice is *already* muted because showing 'Select Load State file' dialog
// . and voice will be demuted when dialog is closed
@ -1505,7 +1568,7 @@ static void ResetState()
g_bMB_RegAccessedFlag = false;
g_bMB_Active = false;
g_nPhasorMode = 0;
g_phasorMode = PH_Mockingboard;
g_PhasorClockScaleFactor = 1;
g_uLastMBUpdateCycle = 0;
@ -1534,6 +1597,8 @@ void MB_Reset() // CTRL+RESET or power-cycle
//-----------------------------------------------------------------------------
// Echo+ mode - Phasor's 2nd 6522 is mapped to every 16-byte offset in $Cnxx (Echo+ has a single 6522 controlling two AY-3-8913's)
static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles)
{
if (g_bFullSpeed)
@ -1561,11 +1626,13 @@ static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULO
if(nMB != 0) // Slot4 only
return MemReadFloatingBus(nExecutedCycles);
int CS;
if(g_nPhasorMode & 1)
CS = ( ( nAddr & 0x80 ) >> 6 ) | ( ( nAddr & 0x10 ) >> 4 ); // 0, 1, 2 or 3
else // Mockingboard Mode
int CS = 0;
if (g_phasorMode == PH_Mockingboard)
CS = ( ( nAddr & 0x80 ) >> 7 ) + 1; // 1 or 2
else if (g_phasorMode == PH_Phasor)
CS = ( ( nAddr & 0x80 ) >> 6 ) | ( ( nAddr & 0x10 ) >> 4 ); // 0, 1, 2 or 3
else if (g_phasorMode == PH_EchoPlus)
CS = 2;
BYTE nRes = 0;
@ -1577,23 +1644,21 @@ static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULO
bool bAccessedDevice = (CS & 3) ? true : false;
if((nOffset >= SSI263_Offset) && (nOffset <= (SSI263_Offset+0x05)))
if ((g_phasorMode == PH_Phasor) && ((nAddr & 0xD0) == 0x40)) // $Cn4x and $Cn6x (Mockingboard mode: SSI263.bit7 not readable)
{
nRes |= SSI263_Read(nMB, nAddr&0xf);
_ASSERT(!bAccessedDevice);
nRes = SSI263_Read(nMB*2+1, nExecutedCycles); // SSI263 only drives bit7
bAccessedDevice = true;
}
return bAccessedDevice ? nRes : MemReadFloatingBus(nExecutedCycles);
}
if(nOffset <= (SY6522A_Offset+0x0F))
// NB. Mockingboard: SSI263.bit7 not readable (TODO: check this with real h/w)
if (nOffset < SY6522B_Offset)
return SY6522_Read(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_A, nAddr&0xf);
else if((nOffset >= SY6522B_Offset) && (nOffset <= (SY6522B_Offset+0x0F)))
return SY6522_Read(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_B, nAddr&0xf);
else if((nOffset >= SSI263_Offset) && (nOffset <= (SSI263_Offset+0x05)))
return SSI263_Read(nMB, nAddr&0xf);
else
return MemReadFloatingBus(nExecutedCycles);
return SY6522_Read(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_B, nAddr&0xf);
}
//-----------------------------------------------------------------------------
@ -1617,6 +1682,36 @@ static BYTE __stdcall MB_Write(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, UL
}
#endif
// Support 6502/65C02 false-reads of 6522 (GH#52)
if ( ((mem[(PC-2)&0xffff] == 0x91) && GetMainCpu() == CPU_6502) || // sta (zp),y - 6502 only (no-PX variant only) (UTAIIe:4-23)
(mem[(PC-3)&0xffff] == 0x99) || // sta abs16,y - 6502/65C02, but for 65C02 only the no-PX variant that does the false-read (UTAIIe:4-27)
(mem[(PC-3)&0xffff] == 0x9D) ) // sta abs16,x - 6502/65C02, but for 65C02 only the no-PX variant that does the false-read (UTAIIe:4-27)
{
WORD base;
WORD addr16;
if (mem[(PC-2)&0xffff] == 0x91)
{
BYTE zp = mem[(PC-1)&0xffff];
base = (mem[zp] | (mem[(zp+1)&0xff]<<8));
addr16 = base + regs.y;
}
else
{
base = mem[(PC-2)&0xffff] | (mem[(PC-1)&0xffff]<<8);
addr16 = base + ((mem[(PC-3)&0xffff] == 0x99) ? regs.y : regs.x);
}
if (((base ^ addr16) >> 8) == 0) // Only the no-PX variant does the false read (to the same I/O SELECT page)
{
_ASSERT(addr16 == nAddr);
if (addr16 == nAddr) // Check we've reverse looked-up the 6502 opcode correctly
{
if ( ((nAddr&0xf) == 4) || ((nAddr&0xf) == 8) ) // Only reading 6522 reg-4 or reg-8 actually has an effect
MB_Read(PC, nAddr, 0, 0, nExecutedCycles);
}
}
}
BYTE nMB = (nAddr>>8)&0xf - SLOT4;
BYTE nOffset = nAddr&0xff;
@ -1627,10 +1722,12 @@ static BYTE __stdcall MB_Write(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, UL
int CS;
if(g_nPhasorMode & 1)
CS = ( ( nAddr & 0x80 ) >> 6 ) | ( ( nAddr & 0x10 ) >> 4 ); // 0, 1, 2 or 3
else // Mockingboard Mode
if (g_phasorMode == PH_Mockingboard)
CS = ( ( nAddr & 0x80 ) >> 7 ) + 1; // 1 or 2
else if (g_phasorMode == PH_Phasor)
CS = ( ( nAddr & 0x80 ) >> 6 ) | ( ( nAddr & 0x10 ) >> 4 ); // 0, 1, 2 or 3
else if (g_phasorMode == PH_EchoPlus)
CS = 2;
if(CS & 1)
SY6522_Write(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_A, nAddr&0xf, nValue);
@ -1638,33 +1735,64 @@ static BYTE __stdcall MB_Write(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, UL
if(CS & 2)
SY6522_Write(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_B, nAddr&0xf, nValue);
if((nOffset >= SSI263_Offset) && (nOffset <= (SSI263_Offset+0x05)))
SSI263_Write(nMB*2+1, nAddr&0xf, nValue); // Second 6522 is used for speech chip
int CS_SSI263 = (g_phasorMode == PH_Mockingboard) ? (nAddr & 0xE0) == 0x40 // Mockingboard: $Cn4x
: (g_phasorMode == PH_Phasor) ? (nAddr & 0xC0) == 0x40 // Phasor: $Cn4x and $Cn6x
: 0; // Echo+
if (CS_SSI263)
{
// NB. Mockingboard mode: writes to $Cn4x/SSI263 also get written to 1st 6522 (have confirmed on real Phasor h/w)
_ASSERT( (g_phasorMode == PH_Mockingboard && (CS==0 || CS==1)) || (g_phasorMode == PH_Phasor && (CS==0)) );
SSI263_Write(nMB*2+1, nAddr&0x7, nValue); // Second 6522 is used for speech chip
}
return 0;
}
if(nOffset <= (SY6522A_Offset+0x0F))
if (nOffset < SY6522B_Offset)
SY6522_Write(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_A, nAddr&0xf, nValue);
else if((nOffset >= SY6522B_Offset) && (nOffset <= (SY6522B_Offset+0x0F)))
else
SY6522_Write(nMB*NUM_DEVS_PER_MB + SY6522_DEVICE_B, nAddr&0xf, nValue);
else if((nOffset >= SSI263_Offset) && (nOffset <= (SSI263_Offset+0x05)))
SSI263_Write(nMB*2+1, nAddr&0xf, nValue); // Second 6522 is used for speech chip
if ((nOffset >= SSI263_Offset) && (nOffset <= (SSI263_Offset+0x07)))
SSI263_Write(nMB*2+1, nAddr&0x7, nValue); // Second 6522 is used for speech chip -- TODO confirm with real MB h/w that writes go to 1st 6522
return 0;
}
//-----------------------------------------------------------------------------
// Phasor's DEVICE SELECT' logic:
// . if addr.[b3]==1, then clear the card's mode bits b2:b0
// . if any of addr.[b2:b0] are a logic 1, then set these bits in the card's mode
//
// Example DEVICE SELECT' accesses for Phasor in slot-4: (from empirical observations on real Phasor h/w)
// 1)
// . RESET -> Mockingboard mode (b#000)
// . $C0C5 -> Phasor mode (b#101)
// 2)
// . RESET -> Mockingboard mode (b#000)
// . $C0C1, then $C0C4 (or $C0C4, then $C0C1) -> Phasor mode (b#101)
// . $C0C2 -> Echo+ mode (b#111)
// . $C0C5 -> remaing in Echo+ mode (b#111)
// So $C0C5 seemingly results in 2 different modes.
//
static BYTE __stdcall PhasorIO(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles)
{
if(!g_bPhasorEnable)
if (!g_bPhasorEnable)
return MemReadFloatingBus(nExecutedCycles);
if(g_nPhasorMode < 2)
g_nPhasorMode = nAddr & 1;
UINT bits = (UINT) g_phasorMode;
if (nAddr & 8)
bits = 0;
bits |= (nAddr & 7);
g_phasorMode = (PHASOR_MODE) bits;
g_PhasorClockScaleFactor = (nAddr & 4) ? 2 : 1;
if (g_phasorMode == PH_Mockingboard || g_phasorMode == PH_EchoPlus)
g_PhasorClockScaleFactor = 1;
else if (g_phasorMode == PH_Phasor)
g_PhasorClockScaleFactor = 2;
AY8910_InitClock((int)(Get6502BaseClock() * g_PhasorClockScaleFactor));
@ -1800,7 +1928,7 @@ void MB_PeriodicUpdate(UINT executedCycles)
//-----------------------------------------------------------------------------
static bool CheckTimerUnderflowAndIrq(USHORT& timerCounter, int& timerIrqDelay, const USHORT nClocks, bool* pTimerUnderflow=NULL)
static bool CheckTimerUnderflowAndIrq(USHORT& timerCounter, int& timerIrqDelay, const USHORT nClocks)
{
if (nClocks == 0)
return false;
@ -1822,9 +1950,6 @@ static bool CheckTimerUnderflowAndIrq(USHORT& timerCounter, int& timerIrqDelay,
if (oldTimer >= 0 && timer < 0) // Underflow occurs for 0x0000 -> 0xFFFF
{
if (pTimerUnderflow)
*pTimerUnderflow = true; // Just for Willy Byte!
if (timer <= -2) // TIMER = 0xFFFE (or less)
timerIrq = true;
else // TIMER = 0xFFFF
@ -1860,40 +1985,26 @@ bool MB_UpdateCycles(ULONG uExecutedCycles)
{
SY6522_AY8910* pMB = &g_MB[i];
bool bTimer1Underflow = false; // Just for Willy Byte!
bool bTimer1Irq = false;
bool bTimer1IrqOnLastCycle = false;
if (isOpcode)
{
bTimer1Irq = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER1_COUNTER.w, pMB->sy6522.timer1IrqDelay, nClocks-1, &bTimer1Underflow);
bTimer1IrqOnLastCycle = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER1_COUNTER.w, pMB->sy6522.timer1IrqDelay, 1, &bTimer1Underflow);
bTimer1Irq = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER1_COUNTER.w, pMB->sy6522.timer1IrqDelay, nClocks-1);
bTimer1IrqOnLastCycle = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER1_COUNTER.w, pMB->sy6522.timer1IrqDelay, 1);
bTimer1Irq = bTimer1Irq || bTimer1IrqOnLastCycle;
}
else
{
bTimer1Irq = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER1_COUNTER.w, pMB->sy6522.timer1IrqDelay, nClocks, &bTimer1Underflow);
bTimer1Irq = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER1_COUNTER.w, pMB->sy6522.timer1IrqDelay, nClocks);
}
const bool bTimer2Irq = CheckTimerUnderflowAndIrq(pMB->sy6522.TIMER2_COUNTER.w, pMB->sy6522.timer2IrqDelay, nClocks);
if (!pMB->bTimer1Active && bTimer1Underflow)
{
if ( (g_nMBTimerDevice == kTIMERDEVICE_INVALID) // StopTimer1() has been called
&& (pMB->sy6522.IFR & IxR_TIMER1) // Counter underflowed
&& ((pMB->sy6522.ACR & RUNMODE) == RM_ONESHOT) ) // One-shot mode
{
// Fix for Willy Byte - need to confirm that 6522 really does this!
// . It never accesses IER/IFR/TIMER1 regs to clear IRQ
// . NB. Willy Byte doesn't work with Phasor.
UpdateIFR(pMB, IxR_TIMER1); // Deassert the TIMER IRQ
}
}
if (pMB->bTimer1Active && bTimer1Irq)
{
UpdateIFR(pMB, 0, IxR_TIMER1);
bIrqOnLastOpcodeCycle = true;
bIrqOnLastOpcodeCycle = bTimer1IrqOnLastCycle;
MB_Update();
@ -1901,7 +2012,6 @@ bool MB_UpdateCycles(ULONG uExecutedCycles)
{
// One-shot mode
// - Phasor's playback code uses one-shot mode
// - Willy Byte sets to one-shot to stop the timer IRQ
StopTimer1(pMB);
}
else
@ -1934,22 +2044,8 @@ bool MB_UpdateCycles(ULONG uExecutedCycles)
{
UpdateIFR(pMB, 0, IxR_TIMER2);
if((pMB->sy6522.ACR & RUNMODE) == RM_ONESHOT)
{
StopTimer2(pMB);
}
else
{
pMB->sy6522.TIMER2_COUNTER.w += pMB->sy6522.TIMER2_LATCH.w;
if (pMB->sy6522.TIMER2_COUNTER.w > pMB->sy6522.TIMER2_LATCH.w)
{
if (pMB->sy6522.TIMER2_LATCH.w)
pMB->sy6522.TIMER2_COUNTER.w %= pMB->sy6522.TIMER2_LATCH.w;
else
pMB->sy6522.TIMER2_COUNTER.w = 0;
}
StartTimer2(pMB);
}
// TIMER2 only runs in one-shot mode
StopTimer2(pMB);
}
}
@ -1979,7 +2075,7 @@ void MB_SetVolume(DWORD dwVolume, DWORD dwVolumeMax)
MockingboardVoice.nVolume = NewVolume(dwVolume, dwVolumeMax);
if(MockingboardVoice.bActive)
if (MockingboardVoice.bActive && !MockingboardVoice.bMute)
MockingboardVoice.lpDSBvoice->SetVolume(MockingboardVoice.nVolume);
}
@ -2021,7 +2117,10 @@ void MB_GetSnapshot_v1(SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot)
// 3: Added: Unit state - GH#320
// 4: Added: 6522 timerIrqDelay - GH#652
// 5: Added: Unit state-B (Phasor only) - GH#659
const UINT kUNIT_VERSION = 5;
// 6: Changed SS_YAML_KEY_PHASOR_MODE from (0,1) to (0,5,7)
// Added SS_YAML_KEY_VOTRAX_PHONEME
// Removed: redundant SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR
const UINT kUNIT_VERSION = 6;
const UINT NUM_MB_UNITS = 2;
const UINT NUM_PHASOR_UNITS = 2;
@ -2060,9 +2159,11 @@ const UINT NUM_PHASOR_UNITS = 2;
#define SS_YAML_KEY_SY6522_TIMER2_IRQ_DELAY "Timer2 IRQ Delay"
#define SS_YAML_KEY_PHASOR_UNIT "Unit"
#define SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR "Clock Scale Factor"
#define SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR "Clock Scale Factor" // Redundant from v6
#define SS_YAML_KEY_PHASOR_MODE "Mode"
#define SS_YAML_KEY_VOTRAX_PHONEME "Votrax Phoneme"
std::string MB_GetSnapshotCardName(void)
{
static const std::string name("Mockingboard C");
@ -2119,6 +2220,8 @@ void MB_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot)
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
yamlSaveHelper.SaveBool(SS_YAML_KEY_VOTRAX_PHONEME, g_bVotraxPhoneme);
for(UINT i=0; i<NUM_MB_UNITS; i++)
{
YamlSaveHelper::Label unit(yamlSaveHelper, "%s%d:\n", SS_YAML_KEY_MB_UNIT, i);
@ -2194,6 +2297,8 @@ bool MB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version)
if (version < 1 || version > kUNIT_VERSION)
throw std::string("Card: wrong version");
g_bVotraxPhoneme = (version >= 6) ? yamlLoadHelper.LoadBool(SS_YAML_KEY_VOTRAX_PHONEME) : false;
AY8910UpdateSetCycles();
const UINT nMbCardNum = slot - SLOT4;
@ -2245,19 +2350,15 @@ bool MB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version)
StartTimer1(pMB); // Attempt to start timer
}
// Crude - currently only support a single speech chip
// FIX THIS:
// . Speech chip could be Votrax instead
// . Is this IRQ compatible with Phasor?
if(pMB->SpeechChip.DurationPhoneme)
// FIXME: currently only support a single speech chip
// NB. g_bVotraxPhoneme is never true, as the phoneme playback completes in SSI263Thread() before this point in the save-state.
// NB. SpeechChip.DurationPhoneme will mostly be non-zero during speech playback, as this is the SSI263 register, not whether the phonene is active.
// FIXME: So possible race-condition between saving-state & SSI263Thread()
if (pMB->SpeechChip.DurationPhoneme || g_bVotraxPhoneme)
{
g_nSSI263Device = nDeviceNum;
if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C) && (pMB->sy6522.IER & IxR_PERIPHERAL))
{
UpdateIFR(pMB, 0, IxR_PERIPHERAL);
pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
}
g_bPhasorEnable = false;
SetSpeechIRQ(pMB);
}
nDeviceNum++;
@ -2283,8 +2384,8 @@ void Phasor_SaveSnapshot(YamlSaveHelper& yamlSaveHelper, const UINT uSlot)
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
yamlSaveHelper.SaveUint(SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR, g_PhasorClockScaleFactor);
yamlSaveHelper.SaveUint(SS_YAML_KEY_PHASOR_MODE, g_nPhasorMode);
yamlSaveHelper.SaveUint(SS_YAML_KEY_PHASOR_MODE, g_phasorMode);
yamlSaveHelper.SaveBool(SS_YAML_KEY_VOTRAX_PHONEME, g_bVotraxPhoneme);
for(UINT i=0; i<NUM_PHASOR_UNITS; i++)
{
@ -2317,8 +2418,21 @@ bool Phasor_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version
if (version < 1 || version > kUNIT_VERSION)
throw std::string("Card: wrong version");
g_PhasorClockScaleFactor = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR);
g_nPhasorMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_MODE);
if (version < 6)
yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_CLOCK_SCALE_FACTOR); // Consume redundant data
UINT phasorMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_PHASOR_MODE);
if (version < 6)
{
if (phasorMode == 0)
phasorMode = PH_Mockingboard;
else
phasorMode = PH_Phasor;
}
g_phasorMode = (PHASOR_MODE) phasorMode;
g_PhasorClockScaleFactor = (g_phasorMode == PH_Phasor) ? 2 : 1;
g_bVotraxPhoneme = (version >= 6) ? yamlLoadHelper.LoadBool(SS_YAML_KEY_VOTRAX_PHONEME) : false;
AY8910UpdateSetCycles();
@ -2373,19 +2487,12 @@ bool Phasor_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version
StartTimer1(pMB); // Attempt to start timer
}
// Crude - currently only support a single speech chip
// FIX THIS:
// . Speech chip could be Votrax instead
// . Is this IRQ compatible with Phasor?
if(pMB->SpeechChip.DurationPhoneme)
// FIXME: currently only support a single speech chip
if (pMB->SpeechChip.DurationPhoneme || g_bVotraxPhoneme)
{
g_nSSI263Device = nDeviceNum;
if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C) && (pMB->sy6522.IER & IxR_PERIPHERAL))
{
UpdateIFR(pMB, 0, IxR_PERIPHERAL);
pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
}
g_bPhasorEnable = true;
SetSpeechIRQ(pMB);
}
nDeviceNum += 2;

View file

@ -181,6 +181,7 @@ void CMouseInterface::Initialize(LPBYTE pCxRomPeripheral, UINT uSlot)
{
// m_bActive = true;
m_bEnabled = true;
_ASSERT(m_uSlot == uSlot);
SetSlotRom(); // Pre: m_bActive == true
RegisterIoHandler(uSlot, &CMouseInterface::IORead, &CMouseInterface::IOWrite, NULL, NULL, this, NULL);
}

View file

@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Applewin.h"
#include "CPU.h" // CpuGetCyclesThisVideoFrame()
#include "Frame.h"
#include "Memory.h" // MemGetMainPtr() MemGetAuxPtr()
#include "Memory.h" // MemGetMainPtr(), MemGetAuxPtr(), MemGetAnnunciator()
#include "Video.h" // g_pFramebufferbits
#include "RGBMonitor.h"
@ -441,6 +441,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
static void updateScreenSingleLores40( long cycles6502 );
static void updateScreenText40 ( long cycles6502 );
static void updateScreenText80 ( long cycles6502 );
static void updateScreenText40RGB ( long cycles6502 );
static void updateScreenText80RGB ( long cycles6502 );
static void updateScreenDoubleHires80Simplified(long cycles6502);
static void updateScreenDoubleHires80RGB(long cycles6502);
//===========================================================================
static void set_csbits()
@ -450,13 +454,15 @@ static void set_csbits()
{
case A2TYPE_APPLE2: csbits = &csbits_a2[0]; g_nVideoCharSet = 0; break;
case A2TYPE_APPLE2PLUS: csbits = &csbits_a2[0]; g_nVideoCharSet = 0; break;
case A2TYPE_APPLE2JPLUS: csbits = &csbits_a2j[MemGetAnnunciator(2) ? 1 : 0]; g_nVideoCharSet = 0; break;
case A2TYPE_APPLE2E: csbits = Get2e_csbits(); break;
case A2TYPE_APPLE2EENHANCED:csbits = Get2e_csbits(); break;
case A2TYPE_PRAVETS82: csbits = &csbits_pravets82[0]; g_nVideoCharSet = 0; break; // Apple ][ clone
case A2TYPE_PRAVETS8M: csbits = &csbits_pravets8M[0]; g_nVideoCharSet = 0; break; // Apple ][ clone
case A2TYPE_PRAVETS8A: csbits = &csbits_pravets8C[0]; break; // Apple //e clone
case A2TYPE_TK30002E: csbits = &csbits_enhanced2e[0]; break; // Enhanced Apple //e clone
default: csbits = &csbits_enhanced2e[0]; break;
case A2TYPE_BASE64A: csbits = &csbits_base64a[GetVideoRomRockerSwitch() ? 0 : 1]; g_nVideoCharSet = 0; break; // Apple ][ clone
default: _ASSERT(0); csbits = &csbits_enhanced2e[0]; break;
}
}
@ -689,7 +695,7 @@ void update7MonoPixels( uint16_t bits )
// NB. g_nLastColumnPixelNTSC = bits.b13 will be superseded by these parent funcs which use bits.b14:
// . updateScreenDoubleHires80(), updateScreenDoubleLores80(), updateScreenText80()
inline void updatePixels( uint16_t bits )
inline void updatePixels(uint16_t bits)
{
if (!GetColorBurst())
{
@ -806,6 +812,9 @@ inline void updateVideoScannerHorzEOL()
//===========================================================================
inline void updateVideoScannerAddress()
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED && GetVideoRefreshRate() == VR_50HZ) // GH#763
g_nColorBurstPixels = 0; // instantaneously kill color-burst!
g_pVideoAddress = g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY ? g_pScanLines[2*g_nVideoClockVert] : g_pScanLines[0];
// Adjust, as these video styles have 2x 14M pixels of pre-render
@ -821,8 +830,9 @@ inline void updateVideoScannerAddress()
if (((g_pFuncUpdateGraphicsScreen == updateScreenDoubleHires80) ||
(g_pFuncUpdateGraphicsScreen == updateScreenDoubleLores80) ||
(g_pFuncUpdateGraphicsScreen == updateScreenText80) ||
(g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED && g_pFuncUpdateTextScreen == updateScreenText80))
&& (g_eVideoType != VT_COLOR_MONITOR_RGB)) // Fix for "Ansi Story" (Turn the disk over) - Top row of TEXT80 is shifted by 1 pixel
(g_pFuncUpdateGraphicsScreen == updateScreenText80RGB) ||
(g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED && (g_pFuncUpdateTextScreen == updateScreenText80 || g_pFuncUpdateGraphicsScreen == updateScreenText80RGB)))
&& (g_eVideoType != VT_COLOR_MONITOR_RGB) && (g_eVideoType != VT_COLOR_VIDEOCARD_RGB)) // Fix for "Ansi Story" (Turn the disk over) - Top row of TEXT80 is shifted by 1 pixel
{
g_pVideoAddress -= 1;
}
@ -1141,24 +1151,28 @@ void updateMonochromeTables( uint16_t r, uint16_t g, uint16_t b )
static void updatePixelBnWMonitorSingleScanline (uint16_t compositeSignal)
{
updateFramebufferMonitorSingleScanline(compositeSignal, g_aBnWMonitorCustom);
updateColorPhase(); // Maintain color-phase, as could be switching graphics/text video modes mid-scanline
}
//===========================================================================
static void updatePixelBnWMonitorDoubleScanline (uint16_t compositeSignal)
{
updateFramebufferMonitorDoubleScanline(compositeSignal, g_aBnWMonitorCustom);
updateColorPhase(); // Maintain color-phase, as could be switching graphics/text video modes mid-scanline
}
//===========================================================================
static void updatePixelBnWColorTVSingleScanline (uint16_t compositeSignal)
{
updateFramebufferTVSingleScanline(compositeSignal, g_aBnWColorTVCustom);
updateColorPhase(); // Maintain color-phase, as could be switching graphics/text video modes mid-scanline
}
//===========================================================================
static void updatePixelBnWColorTVDoubleScanline (uint16_t compositeSignal)
{
updateFramebufferTVDoubleScanline(compositeSignal, g_aBnWColorTVCustom);
updateColorPhase(); // Maintain color-phase, as could be switching graphics/text video modes mid-scanline
}
//===========================================================================
@ -1223,7 +1237,41 @@ void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0
//===========================================================================
void updateScreenDoubleHires80Simplified (long cycles6502 ) // wsUpdateVideoDblHires
void updateScreenDoubleHires80Simplified(long cycles6502) // wsUpdateVideoDblHires
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
{
g_pFuncUpdateTextScreen(cycles6502);
return;
}
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = getVideoScannerAddressHGR();
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
g_nColorBurstPixels = 1024;
}
else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint16_t addr = getVideoScannerAddressHGR();
uint8_t a = *MemGetAuxPtr(addr);
uint8_t m = *MemGetMainPtr(addr);
UpdateDHiResCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, true, true);
g_pVideoAddress += 14;
}
}
updateVideoScannerHorzEOLSimple();
}
}
//===========================================================================
void updateScreenDoubleHires80RGB (long cycles6502 ) // wsUpdateVideoDblHires
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
{
@ -1258,31 +1306,16 @@ void updateScreenDoubleHires80Simplified (long cycles6502 ) // wsUpdateVideoDblH
int width = UpdateDHiRes160Cell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress);
g_pVideoAddress += width;
}
else if (RGB_Is560Mode() || (RGB_IsMixMode() && !((a | m) & 0x80)))
else if (RGB_Is560Mode())// || (RGB_IsMixMode() && !((a | m) & 0x80)))
{
update7MonoPixels(a);
update7MonoPixels(m);
}
else if (!RGB_IsMixMode() || (RGB_IsMixMode() && (a & m & 0x80)))
else
{
UpdateDHiResCell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, true, true);
UpdateDHiResCellRGB(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, RGB_IsMixMode(), RGB_IsMixModeInvertBit7());
g_pVideoAddress += 14;
}
else // RGB_IsMixMode() && ((a ^ m) & 0x80)
{
if (a & 0x80) // RGB color, then monochrome
{
UpdateDHiResCell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, true ,false);
g_pVideoAddress += 7;
update7MonoPixels(m);
}
else // monochrome, then RGB color
{
update7MonoPixels(a);
UpdateDHiResCell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, false, true);
g_pVideoAddress += 7;
}
}
}
}
updateVideoScannerHorzEOLSimple();
@ -1473,6 +1506,65 @@ static void updateScreenSingleHires40Simplified (long cycles6502)
}
}
//===========================================================================
static void updateScreenSingleHires40Duochrome(long cycles6502)
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
{
g_pFuncUpdateTextScreen(cycles6502);
return;
}
for (; cycles6502 > 0; --cycles6502)
{
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
g_nColorBurstPixels = 1024;
}
else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint16_t addr = getVideoScannerAddressHGR();
UpdateHiResDuochromeCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress);
g_pVideoAddress += 14;
}
}
updateVideoScannerHorzEOLSimple();
}
}
//===========================================================================
static void updateScreenSingleHires40RGB(long cycles6502)
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
{
g_pFuncUpdateTextScreen(cycles6502);
return;
}
for (; cycles6502 > 0; --cycles6502)
{
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
g_nColorBurstPixels = 1024;
}
else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint16_t addr = getVideoScannerAddressHGR();
UpdateHiResRGBCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress);
g_pVideoAddress += 14;
}
}
updateVideoScannerHorzEOLSimple();
}
}
//===========================================================================
void updateScreenSingleHires40 (long cycles6502)
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
@ -1599,13 +1691,46 @@ void updateScreenText40 (long cycles6502)
bits ^= g_nTextFlashMask;
updatePixels( bits );
}
}
updateVideoScannerHorzEOL();
}
}
//===========================================================================
void updateScreenText40RGB(long cycles6502)
{
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = getVideoScannerAddressTXT();
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
if (g_nColorBurstPixels > 0)
g_nColorBurstPixels -= 1;
}
else if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint8_t* pMain = MemGetMainPtr(addr);
uint8_t m = pMain[0];
uint8_t c = getCharSetBits(m);
if (0 == g_nVideoCharSet && 0x40 == (m & 0xC0)) // Flash only if mousetext not active
c ^= g_nTextFlashMask;
UpdateText40ColorCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, c, m);
g_pVideoAddress += 14;
}
}
updateVideoScannerHorzEOLSimple();
}
}
//===========================================================================
void updateScreenText80 (long cycles6502)
{
@ -1638,8 +1763,10 @@ void updateScreenText80 (long cycles6502)
aux ^= g_nTextFlashMask;
uint16_t bits = (main << 7) | (aux & 0x7f);
if (g_eVideoType != VT_COLOR_MONITOR_RGB) // No extra 14M bit needed for VT_COLOR_MONITOR_RGB
if ((g_eVideoType != VT_COLOR_MONITOR_RGB) // No extra 14M bit needed for VT_COLOR_MONITOR_RGB
&& (g_eVideoType != VT_COLOR_VIDEOCARD_RGB))
bits = (bits << 1) | g_nLastColumnPixelNTSC; // GH#555: Align TEXT80 chars with DHGR
updatePixels( bits );
g_nLastColumnPixelNTSC = (bits >> 14) & 1;
}
@ -1648,6 +1775,51 @@ void updateScreenText80 (long cycles6502)
}
}
//===========================================================================
void updateScreenText80RGB(long cycles6502)
{
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = getVideoScannerAddressTXT();
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
if (g_nColorBurstPixels > 0)
g_nColorBurstPixels -= 1;
}
else if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint8_t* pMain = MemGetMainPtr(addr);
uint8_t* pAux = MemGetAuxPtr(addr);
uint8_t m = pMain[0];
uint8_t a = pAux[0];
uint16_t main = getCharSetBits(m);
uint16_t aux = getCharSetBits(a);
if ((0 == g_nVideoCharSet) && 0x40 == (m & 0xC0)) // Flash only if mousetext not active
main ^= g_nTextFlashMask;
if ((0 == g_nVideoCharSet) && 0x40 == (a & 0xC0)) // Flash only if mousetext not active
aux ^= g_nTextFlashMask;
UpdateText80ColorCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, (uint8_t)aux, a);
g_pVideoAddress += 7;
UpdateText80ColorCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, (uint8_t)main, m);
g_pVideoAddress += 7;
uint16_t bits = (main << 7) | (aux & 0x7f);
g_nLastColumnPixelNTSC = (bits >> 14) & 1;
}
}
updateVideoScannerHorzEOL();
}
}
// Functions (Public) _____________________________________________________________________________
//===========================================================================
@ -1726,7 +1898,14 @@ uint16_t NTSC_VideoGetScannerAddressForDebugger(void)
//===========================================================================
void NTSC_SetVideoTextMode( int cols )
{
if( cols == 40 )
if (g_eVideoType == VT_COLOR_VIDEOCARD_RGB)
{
if (cols == 40)
g_pFuncUpdateTextScreen = updateScreenText40RGB;
else
g_pFuncUpdateTextScreen = updateScreenText80RGB;
}
else if( cols == 40 )
g_pFuncUpdateTextScreen = updateScreenText40;
else
g_pFuncUpdateTextScreen = updateScreenText80;
@ -1744,9 +1923,12 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
return;
}
g_nVideoMixed = uVideoModeFlags & VF_MIXED;
g_nVideoCharSet = VideoGetSWAltCharSet() ? 1 : 0;
RGB_DisableTextFB();
g_nTextPage = 1;
g_nHiresPage = 1;
if (uVideoModeFlags & VF_PAGE2)
@ -1760,10 +1942,99 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
}
}
if (uVideoModeFlags & VF_TEXT)
if (GetVideoRefreshRate() == VR_50HZ && g_pVideoAddress) // GH#763 / NB. g_pVideoAddress==NULL when called via VideoResetState()
{
if (uVideoModeFlags & VF_TEXT)
{
g_nColorBurstPixels = 0; // (For mid-line video mode change) Instantaneously kill color-burst! (not correct as TV's can take many lines)
// Switching mid-line from graphics to TEXT
if (g_eVideoType == VT_COLOR_MONITOR_NTSC &&
g_pFuncUpdateGraphicsScreen != updateScreenText40 && g_pFuncUpdateGraphicsScreen != updateScreenText40RGB
&& g_pFuncUpdateGraphicsScreen != updateScreenText80 && g_pFuncUpdateGraphicsScreen != updateScreenText80RGB)
{
*(uint32_t*)&g_pVideoAddress[0] = 0; // blank out any stale pixel data, eg. ANSI STORY (at end credits)
*(uint32_t*)&g_pVideoAddress[1] = 0;
g_pVideoAddress += 2; // eg. FT's TRIBU demo & ANSI STORY (at "turn the disk over!")
}
}
else
{
g_nColorBurstPixels = 1024; // (For mid-line video mode change)
// Switching mid-line from TEXT to graphics
if (g_eVideoType == VT_COLOR_MONITOR_NTSC &&
(g_pFuncUpdateGraphicsScreen == updateScreenText40 || g_pFuncUpdateGraphicsScreen == updateScreenText40RGB
|| g_pFuncUpdateGraphicsScreen == updateScreenText80 || g_pFuncUpdateGraphicsScreen == updateScreenText80RGB))
{
g_pVideoAddress -= 2; // eg. FT's TRIBU demo & ANSI STORY (at "turn the disk over!")
}
}
}
// Video7_SL7 extra RGB modes handling
if (g_eVideoType == VT_COLOR_VIDEOCARD_RGB
&& RGB_GetVideocard() == RGB_Videocard_e::Video7_SL7
// Exclude following modes (fallback through regular NTSC rendering with RGB text)
// VF_DHIRES = 1 -> regular Apple IIe modes
// VF_DHIRES = 0 and VF_TEXT=0, VF_DHIRES=1, VF_80COL=1 -> DHIRES modes, setup by F1/F2
&& !(!(uVideoModeFlags & VF_DHIRES) ||
((uVideoModeFlags & VF_DHIRES) && !(uVideoModeFlags & VF_TEXT) && (uVideoModeFlags & VF_DHIRES) && (uVideoModeFlags & VF_80COL))
)
)
{
RGB_EnableTextFB(); // F/B text only shows in 40col mode anyway
// ----- Video-7 SL7 extra modes ----- (from the videocard manual)
// AN3 TEXT HIRES 80COL
// 0 1 ? 0 F/B Text
// 0 1 ? 1 80 col Text
// 0 0 0 0 LoRes (mixed with F/B Text)
// 0 0 0 1 DLoRes (mixed with 80 col. Text)
// 0 0 1 0 F/B HiRes (mixed with F/B Text)
if (uVideoModeFlags & VF_TEXT)
{
if (uVideoModeFlags & VF_80COL)
{
// 80 col text
g_pFuncUpdateGraphicsScreen = updateScreenText80RGB;
}
else
{
g_pFuncUpdateGraphicsScreen = updateScreenText40RGB;
}
}
else if (uVideoModeFlags & VF_HIRES)
{
// F/B HiRes
g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40Duochrome;
g_pFuncUpdateTextScreen = updateScreenText40RGB;
}
else if (uVideoModeFlags & VF_80COL)
{
// DLoRes
g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores80Simplified;
g_pFuncUpdateTextScreen = updateScreenText80RGB;
}
else
{
// LoRes + F/B Text
g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40Simplified;
g_pFuncUpdateTextScreen = updateScreenText40RGB;
}
}
// Regular NTSC modes
else if (uVideoModeFlags & VF_TEXT)
{
if (uVideoModeFlags & VF_80COL)
g_pFuncUpdateGraphicsScreen = updateScreenText80;
{
if (g_eVideoType == VT_COLOR_VIDEOCARD_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenText80RGB;
else
g_pFuncUpdateGraphicsScreen = updateScreenText80;
}
else if (g_eVideoType == VT_COLOR_VIDEOCARD_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenText40RGB;
else
g_pFuncUpdateGraphicsScreen = updateScreenText40;
}
@ -1775,6 +2046,8 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80Simplified;
else if (g_eVideoType == VT_COLOR_VIDEOCARD_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80RGB;
else
g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80;
}
@ -1787,6 +2060,8 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40Simplified;
else if (g_eVideoType == VT_COLOR_VIDEOCARD_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40RGB;
else
g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40;
}
@ -1797,7 +2072,7 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
{
if (uVideoModeFlags & VF_80COL)
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
if ((g_eVideoType == VT_COLOR_MONITOR_RGB) || (g_eVideoType == VT_COLOR_VIDEOCARD_RGB))
g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores80Simplified;
else
g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores80;
@ -1809,7 +2084,7 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
}
else
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
if ((g_eVideoType == VT_COLOR_MONITOR_RGB) || (g_eVideoType == VT_COLOR_VIDEOCARD_RGB))
g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40Simplified;
else
g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40;
@ -1819,9 +2094,10 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
//===========================================================================
void NTSC_SetVideoStyle() // (int v, int s)
void NTSC_SetVideoStyle(void)
{
int half = IsVideoStyle(VS_HALF_SCANLINES);
const bool half = IsVideoStyle(VS_HALF_SCANLINES);
const VideoRefreshRate_e refresh = GetVideoRefreshRate();
uint8_t r, g, b;
switch ( g_eVideoType )
@ -1836,7 +2112,8 @@ void NTSC_SetVideoStyle() // (int v, int s)
g_pFuncUpdateBnWPixel = updatePixelBnWColorTVSingleScanline;
g_pFuncUpdateHuePixel = updatePixelHueColorTVSingleScanline;
}
else {
else
{
g_pFuncUpdateBnWPixel = updatePixelBnWColorTVDoubleScanline;
g_pFuncUpdateHuePixel = updatePixelHueColorTVDoubleScanline;
}
@ -1853,7 +2130,8 @@ void NTSC_SetVideoStyle() // (int v, int s)
g_pFuncUpdateBnWPixel = updatePixelBnWMonitorSingleScanline;
g_pFuncUpdateHuePixel = updatePixelHueMonitorSingleScanline;
}
else {
else
{
g_pFuncUpdateBnWPixel = updatePixelBnWMonitorDoubleScanline;
g_pFuncUpdateHuePixel = updatePixelHueMonitorDoubleScanline;
}
@ -1865,12 +2143,9 @@ void NTSC_SetVideoStyle() // (int v, int s)
b = 0xFF;
updateMonochromeTables( r, g, b ); // Custom Monochrome color
if (half)
{
g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWColorTVSingleScanline;
}
else {
else
g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWColorTVDoubleScanline;
}
break;
case VT_MONO_AMBER:
@ -1886,6 +2161,7 @@ void NTSC_SetVideoStyle() // (int v, int s)
goto _mono;
case VT_COLOR_MONITOR_RGB:
case VT_COLOR_VIDEOCARD_RGB:
case VT_MONO_WHITE:
r = 0xFF;
g = 0xFF;
@ -1904,13 +2180,9 @@ void NTSC_SetVideoStyle() // (int v, int s)
_mono:
updateMonochromeTables( r, g, b ); // Custom Monochrome color
if (half)
{
g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWMonitorSingleScanline;
}
else
{
g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWMonitorDoubleScanline;
}
break;
}
}
@ -2090,6 +2362,11 @@ static void VideoUpdateCycles( int cyclesLeftToUpdate )
//===========================================================================
void NTSC_VideoUpdateCycles( UINT cycles6502 )
{
#ifdef LOG_PERF_TIMINGS
extern UINT64 g_timeVideo;
PerfMarker perfMarker(g_timeVideo);
#endif
_ASSERT(cycles6502 && cycles6502 < g_videoScanner6502Cycles); // Use NTSC_VideoRedrawWholeScreen() instead
if (g_bDelayVideoMode)

View file

@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#include "Applewin.h"
#include "../resource/resource.h"
#include "Video.h"
#include "NTSC_CharSet.h"
@ -29,9 +30,12 @@ unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e (2732 4K video ROM)
static unsigned char csbits_2e_pal[2][256][8]; // PAL Original or Enhanced //e (2764 8K video ROM - low 4K) via rocker switch under keyboard
unsigned char csbits_2e[2][256][8]; // Original //e (no mousetext)
unsigned char csbits_a2[1][256][8]; // ][ and ][+
unsigned char csbits_a2j[2][256][8]; // ][J-Plus
unsigned char csbits_pravets82[1][256][8]; // Pravets 82
unsigned char csbits_pravets8M[1][256][8]; // Pravets 8M
unsigned char csbits_pravets8C[2][256][8]; // Pravets 8A & 8C
unsigned char csbits_base64a[2][256][8]; // Base 64A
//
@ -105,7 +109,7 @@ static void get_csbits(csbits_t csbits, const char* resourceName, const UINT cy0
// FLASH toggles every 16 VBLs, so alternates between selecting NORMAL control/special and INVERSE control/special
//
void userVideoRom4K(csbits_t csbits, const BYTE* pVideoRom)
static void userVideoRom4K(csbits_t csbits, const BYTE* pVideoRom)
{
int RA = 0; // rom address
int i = 0;
@ -154,7 +158,7 @@ void userVideoRom4K(csbits_t csbits, const BYTE* pVideoRom)
}
}
void userVideoRomForIIe(void)
static void userVideoRomForIIe(void)
{
const BYTE* pVideoRom;
UINT size = GetVideoRom(pVideoRom); // 2K or 4K or 8K
@ -177,32 +181,63 @@ void userVideoRomForIIe(void)
//-------------------------------------
void userVideoRom2K(csbits_t csbits, const BYTE* pVideoRom)
{
int RA = 0; // rom address
static void userVideoRom2K(csbits_t csbits, const BYTE* pVideoRom, const eApple2Type type = A2TYPE_APPLE2, const int AN2=0);
for (int i=0; i<256; i++, RA+=8)
static void userVideoRom2K(csbits_t csbits, const BYTE* pVideoRom, const eApple2Type type /*= A2TYPE_APPLE2*/, const int AN2/*=0*/)
{
for (int i=0; i<256; i++)
{
int RA = i*8; // rom address
if (type == A2TYPE_APPLE2JPLUS)
{
// AN2=0: $00-3F, $00-3F; $80-BF, $80-BF => KKAA (Repeat Katakana)
// AN2=1: $40-7F, $40-7F; $C0-FF, $C0-FF => AAAA (Repeat ASCII)
RA &= ~(1<<(6+3));
RA |= (AN2<<(6+3)); // AN2 controls A9 (UTAII 8-12, Fig 8.7)
}
for (int y=0; y<8; y++)
{
BYTE n = pVideoRom[RA+y];
// UTAII:8-30 "Bit 7 of your EPROM fonts will control flashing in the lower 1024 bytes of the EPROM"
// UTAII:8-31 "If you leave O7 (EPROM Output7) reset in these patterns, the resulting characters will be inversions..."
if (!(n & 0x80) && RA < 1024)
n = n ^ 0x7f;
// Apple II J-Plus: simplest logic is just invert if reading low 1K of video ROM
// Base64A: Bit 0 instead of bit 7
if (RA < 1024)
{
if (type == A2TYPE_BASE64A)
{
if (!(n & 0x01))
n = n ^ 0xfe;
}
else
{
if (!(n & 0x80) || (type == A2TYPE_APPLE2JPLUS))
n = n ^ 0x7f;
}
}
// UTAII:8-30 "TEXT ROM pattern is ... reversed"
BYTE d = 0;
for (BYTE j=0; j<7; j++, n >>= 1) // Just bits [0..6]
d = (d << 1) | (n & 1);
if (type == A2TYPE_BASE64A)
{
// On the Base 64A bits are ordered 1345672.
d = (n >> 2) | ((n & 2) >> 1) | ((n & 4) << 4);
}
else
{
// UTAII:8-30 "TEXT ROM pattern is ... reversed"
for (BYTE j = 0; j < 7; j++, n >>= 1) // Just bits [0..6]
d = (d << 1) | (n & 1);
}
csbits[0][i][y] = d;
}
}
}
void userVideoRomForIIPlus(void)
static void userVideoRomForIIPlus(void)
{
const BYTE* pVideoRom;
UINT size = GetVideoRom(pVideoRom); // 2K or 4K or 8K
@ -212,6 +247,53 @@ void userVideoRomForIIPlus(void)
userVideoRom2K(&csbits_a2[0], pVideoRom);
}
//-------------------------------------
static void VideoRomForIIJPlus(void)
{
HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2_JPLUS_VIDEO_ROM), "ROM");
if (hResInfo == NULL)
return;
DWORD dwResSize = SizeofResource(NULL, hResInfo);
if(dwResSize != kVideoRomSize2K)
return;
HGLOBAL hResData = LoadResource(NULL, hResInfo);
if(hResData == NULL)
return;
BYTE* pVideoRom = (BYTE*) LockResource(hResData); // NB. Don't need to unlock resource
if (pVideoRom == NULL)
return;
userVideoRom2K(&csbits_a2j[0], pVideoRom, A2TYPE_APPLE2JPLUS, 0);
userVideoRom2K(&csbits_a2j[1], pVideoRom, A2TYPE_APPLE2JPLUS, 1);
}
static void VideoRomForBase64A(void)
{
HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_BASE64A_VIDEO_ROM), "ROM");
if (hResInfo == NULL)
return;
DWORD dwResSize = SizeofResource(NULL, hResInfo);
if (dwResSize != kVideoRomSize4K)
return;
HGLOBAL hResData = LoadResource(NULL, hResInfo);
if (hResData == NULL)
return;
BYTE* pVideoRom = (BYTE*)LockResource(hResData); // NB. Don't need to unlock resource
if (pVideoRom == NULL)
return;
userVideoRom2K(&csbits_base64a[0], pVideoRom, A2TYPE_BASE64A, 0);
userVideoRom2K(&csbits_base64a[1], pVideoRom + kVideoRomSize2K, A2TYPE_BASE64A, 0);
}
//-------------------------------------
void make_csbits(void)
@ -228,6 +310,9 @@ void make_csbits(void)
memcpy(csbits_2e, csbits_enhanced2e, sizeof(csbits_enhanced2e));
memcpy(&csbits_2e[1][64], &csbits_2e[0][64], 32*8);
VideoRomForIIJPlus(); // GH#773
VideoRomForBase64A(); // GH#806
// Try to use any user-provided video ROM for Original/Enhanced //e
userVideoRomForIIe();

View file

@ -4,9 +4,12 @@ typedef unsigned char (*csbits_t)[256][8];
extern unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e (2732 4K video ROM)
extern unsigned char csbits_a2[1][256][8]; // ][ and ][+
extern unsigned char csbits_a2j[2][256][8]; // ][J-Plus
extern unsigned char csbits_pravets82[1][256][8]; // Pravets 82
extern unsigned char csbits_pravets8M[1][256][8]; // Pravets 8M
extern unsigned char csbits_pravets8C[2][256][8]; // Pravets 8A & 8C
extern unsigned char csbits_base64a[2][256][8]; // Base64A
void make_csbits(void);
csbits_t Get2e_csbits(void);

View file

@ -41,6 +41,7 @@ All the other drivers and utilities available to me don't define the DOW mapping
#include "StdAfx.h"
#include "NoSlotClock.h"
#include "YamlHelper.h"
CNoSlotClock::CNoSlotClock()
:
@ -166,6 +167,45 @@ void CNoSlotClock::PopulateClockRegister()
m_ClockRegister.WriteNibble(year / 10);
}
#define SS_YAML_KEY_CLOCK_REGISTER_ENABLED "Clock Register Enabled"
#define SS_YAML_KEY_WRITE_ENABLED "Write Enabled"
#define SS_YAML_KEY_CLOCK_REGISTER_MASK "Clock Register Mask"
#define SS_YAML_KEY_CLOCK_REGISTER "Clock Register"
#define SS_YAML_KEY_COMPARISON_REGISTER_MASK "Comparison Register Mask"
#define SS_YAML_KEY_COMPARISON_REGISTER "Comparison Register"
std::string CNoSlotClock::GetSnapshotStructName(void)
{
static const std::string name("No Slot Clock");
return name;
}
void CNoSlotClock::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
{
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", GetSnapshotStructName().c_str());
yamlSaveHelper.SaveBool(SS_YAML_KEY_CLOCK_REGISTER_ENABLED, m_bClockRegisterEnabled);
yamlSaveHelper.SaveBool(SS_YAML_KEY_WRITE_ENABLED, m_bWriteEnabled);
yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_CLOCK_REGISTER_MASK, m_ClockRegister.m_Mask);
yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_CLOCK_REGISTER, m_ClockRegister.m_Register);
yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_COMPARISON_REGISTER_MASK, m_ComparisonRegister.m_Mask);
yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_COMPARISON_REGISTER, m_ComparisonRegister.m_Register);
}
void CNoSlotClock::LoadSnapshot(YamlLoadHelper& yamlLoadHelper)
{
if (!yamlLoadHelper.GetSubMap(GetSnapshotStructName()))
return;
m_bClockRegisterEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_CLOCK_REGISTER_ENABLED);
m_bWriteEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_WRITE_ENABLED);
m_ClockRegister.m_Mask = yamlLoadHelper.LoadUint64(SS_YAML_KEY_CLOCK_REGISTER_MASK);
m_ClockRegister.m_Register = yamlLoadHelper.LoadUint64(SS_YAML_KEY_CLOCK_REGISTER);
m_ComparisonRegister.m_Mask = yamlLoadHelper.LoadUint64(SS_YAML_KEY_COMPARISON_REGISTER_MASK);
m_ComparisonRegister.m_Register = yamlLoadHelper.LoadUint64(SS_YAML_KEY_COMPARISON_REGISTER);
yamlLoadHelper.PopMap();
}
CNoSlotClock::RingRegister64::RingRegister64()
{
Reset();

View file

@ -57,6 +57,9 @@ public:
bool ClockRead(int& data);
void ClockWrite(int address);
void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
void LoadSnapshot(class YamlLoadHelper& yamlLoadHelper);
bool m_bClockRegisterEnabled;
bool m_bWriteEnabled;
RingRegister64 m_ClockRegister;
@ -64,6 +67,7 @@ public:
private:
void PopulateClockRegister();
std::string GetSnapshotStructName(void);
static const UINT64 kClockInitSequence = 0x5CA33AC55CA33AC5;
};

View file

@ -8,6 +8,14 @@
#include "RGBMonitor.h"
#include "YamlHelper.h"
// RGB videocards types
static RGB_Videocard_e g_RGBVideocard = RGB_Videocard_e::Apple;
static int g_nTextFBMode = 0; // F/B Text
static int g_nRegularTextFG = 15; // Default TEXT color
static int g_nRegularTextBG = 0; // Default TEXT background color
const int HIRES_COLUMN_SUBUNIT_SIZE = 16;
const int HIRES_COLUMN_UNIT_SIZE = (HIRES_COLUMN_SUBUNIT_SIZE)*2;
const int HIRES_NUMBER_COLUMNS = (1<<5); // 5 bits
@ -109,7 +117,9 @@ const BYTE DoubleHiresPalIndex[16] = {
#define SETRGBCOLOR(r,g,b) {b,g,r,0xFF}
static RGBQUAD PalIndex2RGB[] =
static RGBQUAD* g_pPaletteRGB;
static RGBQUAD PaletteRGB_NTSC[] =
{
// hires
#if DO_OPT_PALETTE
@ -120,6 +130,7 @@ static RGBQUAD PalIndex2RGB[] =
SETRGBCOLOR(/*HGR_BLACK, */ 0x00,0x00,0x00), // For TV emulation HGR Video Mode
SETRGBCOLOR(/*HGR_WHITE, */ 0xFF,0xFF,0xFF),
#else
// Note: this is a placeholder. This palette is overwritten by VideoInitializeOriginal()
SETRGBCOLOR(/*HGR_BLACK, */ 0x00,0x00,0x00), // For TV emulation HGR Video Mode
SETRGBCOLOR(/*HGR_WHITE, */ 0xFF,0xFF,0xFF),
SETRGBCOLOR(/*BLUE, */ 0x0D,0xA1,0xFF), // FC Linards Tweaked 0x00,0x00,0xFF -> 0x0D,0xA1,0xFF
@ -137,6 +148,7 @@ static RGBQUAD PalIndex2RGB[] =
SETRGBCOLOR(/*HGR_PINK, */ 0xFF,0x32,0xB5), // 0xD0,0x40,0xA0 -> 0xFF,0x32,0xB5
// lores & dhires
// Note: this is a placeholder. This palette is overwritten by VideoInitializeOriginal()
SETRGBCOLOR(/*BLACK,*/ 0x00,0x00,0x00), // 0
SETRGBCOLOR(/*DEEP_RED,*/ 0x9D,0x09,0x66), // 0xD0,0x00,0x30 -> Linards Tweaked 0x9D,0x09,0x66
SETRGBCOLOR(/*DARK_BLUE,*/ 0x2A,0x2A,0xE5), // 4 // Linards Tweaked 0x00,0x00,0x80 -> 0x2A,0x2A,0xE5
@ -155,6 +167,44 @@ static RGBQUAD PalIndex2RGB[] =
SETRGBCOLOR(/*WHITE,*/ 0xFF,0xFF,0xFF),
};
// Le Chat Mauve Feline's palette
// extracted from a white-balanced RGB video capture
static RGBQUAD PaletteRGB_Feline[] =
{
SETRGBCOLOR(/*HGR_BLACK, */ 0x00,0x00,0x00),
SETRGBCOLOR(/*HGR_WHITE, */ 0xFF,0xFF,0xFF),
SETRGBCOLOR(/*BLUE, */ 0x00,0x8A,0xB5),
SETRGBCOLOR(/*ORANGE, */ 0xFF,0x72,0x47),
SETRGBCOLOR(/*GREEN, */ 0x6F,0xE6,0x2C),
SETRGBCOLOR(/*MAGENTA, */ 0xAA,0x1A,0xD1),
// TV emu
SETRGBCOLOR(/*HGR_GREY1, */ 0x80,0x80,0x80),
SETRGBCOLOR(/*HGR_GREY2, */ 0x80,0x80,0x80),
SETRGBCOLOR(/*HGR_YELLOW,*/ 0x9E,0x9E,0x00),
SETRGBCOLOR(/*HGR_AQUA, */ 0x00,0xCD,0x4A),
SETRGBCOLOR(/*HGR_PURPLE,*/ 0x61,0x61,0xFF),
SETRGBCOLOR(/*HGR_PINK, */ 0xFF,0x32,0xB5),
// Feline
SETRGBCOLOR(/*BLACK,*/ 0x00,0x00,0x00),
SETRGBCOLOR(/*DEEP_RED,*/ 0xAC,0x12,0x4C),
SETRGBCOLOR(/*DARK_BLUE,*/ 0x00,0x07,0x83),
SETRGBCOLOR(/*MAGENTA,*/ 0xAA,0x1A,0xD1),
SETRGBCOLOR(/*DARK_GREEN,*/ 0x00,0x83,0x2F),
SETRGBCOLOR(/*DARK_GRAY,*/ 0x9F,0x97,0x7E),
SETRGBCOLOR(/*BLUE,*/ 0x00,0x8A,0xB5),
SETRGBCOLOR(/*LIGHT_BLUE,*/ 0x9F,0x9E,0xFF),
SETRGBCOLOR(/*BROWN,*/ 0x7A,0x5F,0x00),
SETRGBCOLOR(/*ORANGE,*/ 0xFF,0x72,0x47),
SETRGBCOLOR(/*LIGHT_GRAY,*/ 0x78,0x68,0x7F),
SETRGBCOLOR(/*PINK,*/ 0xFF,0x7A,0xCF),
SETRGBCOLOR(/*GREEN,*/ 0x6F,0xE6,0x2C),
SETRGBCOLOR(/*YELLOW,*/ 0xFF,0xF6,0x7B),
SETRGBCOLOR(/*AQUA,*/ 0x6C,0xEE,0xB2),
SETRGBCOLOR(/*WHITE,*/ 0xFF,0xFF,0xFF),
};
//===========================================================================
static void V_CreateLookup_DoubleHires ()
@ -493,8 +543,8 @@ static void CopyMixedSource(int x, int y, int sx, int sy, bgra_t *pVideoAddress)
}
else
{
_ASSERT( colormixbuffer[h] < (sizeof(PalIndex2RGB)/sizeof(PalIndex2RGB[0])) );
const RGBQUAD& rRGB = PalIndex2RGB[ colormixbuffer[h] ];
_ASSERT( colormixbuffer[h] < (sizeof(PaletteRGB_NTSC)/sizeof(PaletteRGB_NTSC[0])) );
const RGBQUAD& rRGB = g_pPaletteRGB[ colormixbuffer[h] ];
*(pDst+nBytes) = *reinterpret_cast<const UINT32 *>(&rRGB);
}
@ -525,8 +575,8 @@ static void CopySource(int w, int h, int sx, int sy, bgra_t *pVideoAddress, cons
{
for (int nBytes=0; nBytes<w; ++nBytes)
{
_ASSERT( *(pSrc+nBytes+nSrcAdjustment) < (sizeof(PalIndex2RGB)/sizeof(PalIndex2RGB[0])) );
const RGBQUAD& rRGB = PalIndex2RGB[ *(pSrc+nBytes+nSrcAdjustment) ];
_ASSERT( *(pSrc+nBytes+nSrcAdjustment) < (sizeof(PaletteRGB_NTSC)/sizeof(PaletteRGB_NTSC[0])) );
const RGBQUAD& rRGB = g_pPaletteRGB[ *(pSrc+nBytes+nSrcAdjustment) ];
*(pDst+nBytes) = *reinterpret_cast<const UINT32 *>(&rRGB);
}
}
@ -561,25 +611,25 @@ void UpdateHiResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress)
#define COLOR ((xpixel + PIXEL) & 3)
#define VALUE (dwordval >> (4 + PIXEL - COLOR))
void UpdateDHiResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress, bool updateAux, bool updateMain)
void UpdateDHiResCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, bool updateAux, bool updateMain)
{
const int xpixel = x*14;
const int xpixel = x * 14;
uint8_t *pAux = MemGetAuxPtr(addr);
uint8_t *pMain = MemGetMainPtr(addr);
uint8_t* pAux = MemGetAuxPtr(addr);
uint8_t* pMain = MemGetMainPtr(addr);
BYTE byteval1 = (x > 0) ? *(pMain-1) : 0;
BYTE byteval1 = (x > 0) ? *(pMain - 1) : 0;
BYTE byteval2 = *pAux;
BYTE byteval3 = *pMain;
BYTE byteval4 = (x < 39) ? *(pAux+1) : 0;
BYTE byteval4 = (x < 39) ? *(pAux + 1) : 0;
DWORD dwordval = (byteval1 & 0x70) | ((byteval2 & 0x7F) << 7) |
((byteval3 & 0x7F) << 14) | ((byteval4 & 0x07) << 21);
DWORD dwordval = (byteval1 & 0x70) | ((byteval2 & 0x7F) << 7) |
((byteval3 & 0x7F) << 14) | ((byteval4 & 0x07) << 21);
#define PIXEL 0
if (updateAux)
{
CopySource(7,2, SRCOFFS_DHIRES+10*HIBYTE(VALUE)+COLOR, LOBYTE(VALUE), pVideoAddress);
CopySource(7, 2, SRCOFFS_DHIRES + 10 * HIBYTE(VALUE) + COLOR, LOBYTE(VALUE), pVideoAddress);
pVideoAddress += 7;
}
#undef PIXEL
@ -587,11 +637,323 @@ void UpdateDHiResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress, bool
#define PIXEL 7
if (updateMain)
{
CopySource(7,2, SRCOFFS_DHIRES+10*HIBYTE(VALUE)+COLOR, LOBYTE(VALUE), pVideoAddress);
CopySource(7, 2, SRCOFFS_DHIRES + 10 * HIBYTE(VALUE) + COLOR, LOBYTE(VALUE), pVideoAddress);
}
#undef PIXEL
}
//===========================================================================
// RGB videocards HGR
void UpdateHiResRGBCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress)
{
const int xpixel = x * 14;
int xoffset = x & 1; // offset to start of the 2 bytes
addr -= xoffset;
uint8_t* pMain = MemGetMainPtr(addr);
// We need all 28 bits because each pixel needs a three bit evaluation
uint8_t byteval1 = (x < 2 ? 0 : *(pMain - 1));
uint8_t byteval2 = *pMain;
uint8_t byteval3 = *(pMain + 1);
uint8_t byteval4 = (x >= 38 ? 0 : *(pMain + 2));
// all 28 bits chained
DWORD dwordval = (byteval1 & 0x7F) | ((byteval2 & 0x7F) << 7) | ((byteval3 & 0x7F) << 14) | ((byteval4 & 0x7F) << 21);
// Extraction of 14 color pixels
UINT32 colors[14];
int color = 0;
DWORD dwordval_tmp = dwordval;
dwordval_tmp = dwordval_tmp >> 7;
bool offset = (byteval2 & 0x80) ? true : false;
for (int i = 0; i < 14; i++)
{
if (i == 7) offset = (byteval3 & 0x80) ? true : false;
color = dwordval_tmp & 0x3;
// Two cases because AppleWin's palette is in a strange order
if (offset)
colors[i] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[1 + color]);
else
colors[i] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[6 - color]);
if (i%2) dwordval_tmp >>= 2;
}
// Black and White
UINT32 bw[2];
bw[0] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[0]);
bw[1] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[1]);
DWORD mask = 0x01C0; // 00|000001 1|1000000
DWORD chck1 = 0x0140; // 00|000001 0|1000000
DWORD chck2 = 0x0080; // 00|000000 1|0000000
// HIRES render in RGB works on a pixel-basis (1-bit data in framebuffer)
// The pixel can be 'color', if it makes a 101 or 010 pattern with the two neighbour bits
// In all other cases, it's black if 0 and white if 1
// The value of 'color' is defined on a 2-bits basis
UINT32* pDst = (UINT32*)pVideoAddress;
if (xoffset)
{
// Second byte of the 14 pixels block
dwordval = dwordval >> 7;
xoffset = 7;
}
for (int i = xoffset; i < xoffset+7; i++)
{
if (((dwordval & mask) == chck1) || ((dwordval & mask) == chck2))
{
// Color pixel
*(pDst) = colors[i];
*(pDst + 1) = *(pDst);
pDst += 2;
}
else
{
// B&W pixel
*(pDst) = bw[(dwordval & chck2 ? 1 : 0)];
*(pDst + 1) = *(pDst);
pDst += 2;
}
// Next pixel
dwordval = dwordval >> 1;
}
const bool bIsHalfScanLines = IsVideoStyle(VS_HALF_SCANLINES);
// Second line
UINT32* pSrc = (UINT32*)pVideoAddress;
pDst = pSrc - GetFrameBufferWidth();
if (bIsHalfScanLines)
{
// Scanlines
std::fill(pDst, pDst + 14, 0);
}
else
{
for (int i = 0; i < 14; i++)
*(pDst + i) = *(pSrc + i);
}
}
static bool g_dhgrLastCellIsColor = true;
static int g_dhgrLastBit = 0;
void UpdateDHiResCellRGB(int x, int y, uint16_t addr, bgra_t* pVideoAddress, bool isMixMode, bool isBit7Inversed)
{
const int xpixel = x * 14;
int xoffset = x & 1; // offset to start of the 2 bytes
addr -= xoffset;
uint8_t* pAux = MemGetAuxPtr(addr);
uint8_t* pMain = MemGetMainPtr(addr);
// We need all 28 bits because one 4-bits pixel overlaps two 14-bits cells
uint8_t byteval1 = *pAux;
uint8_t byteval2 = *pMain;
uint8_t byteval3 = *(pAux + 1);
uint8_t byteval4 = *(pMain + 1);
// all 28 bits chained
DWORD dwordval = (byteval1 & 0x7F) | ((byteval2 & 0x7F) << 7) | ((byteval3 & 0x7F) << 14) | ((byteval4 & 0x7F) << 21);
// Extraction of 7 color pixels and 7x4 bits
int bits[7];
UINT32 colors[7];
int color = 0;
DWORD dwordval_tmp = dwordval;
for (int i = 0; i < 7; i++)
{
bits[i] = dwordval_tmp & 0xF;
color = ((bits[i] & 7) << 1) | ((bits[i] & 8) >> 3); // DHGR colors are rotated 1 bit to the right
colors[i] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[12 + color]);
dwordval_tmp >>= 4;
}
UINT32 bw[2];
bw[0] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[12 + 0]);
bw[1] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[12 + 15]);
if (isBit7Inversed)
{
// Invert mixed mode detection
byteval1 = ~byteval1;
byteval2 = ~byteval2;
byteval3 = ~byteval3;
byteval4 = ~byteval4;
}
// RGB DHGR is quite a mess:
// Color mode is a real 140x192 RGB mode with no color fringe (ref. patent US4631692, "THE 140x192 VIDEO MODE")
// BW mode is a real 560x192 monochrome mode
// Mixed mode seems easy but has a few traps since it's based on 4-bits cells coded into 7-bits bytes:
// - Bit 7 of each byte defines the mode of the following 7 bits (BW or Color);
// - BW pixels are 1 bit wide, color pixels are usually 4 bits wide;
// - A color pixel can be less than 4 bits wide if it crosses a byte boundary and falls into a BW byte;
// - If a 4-bit cell of BW bits crosses a byte boundary and falls into a Color byte, then the last BW bit is repeated until the next color pixel starts.
//
// (Tested on Le Chat Mauve IIc adapter, which was made under patent of Video-7)
UINT32* pDst = (UINT32*)pVideoAddress;
if (xoffset == 0) // First cell
{
if ((byteval1 & 0x80) || !isMixMode)
{
// Color
// Color cell 0
*(pDst++) = colors[0];
*(pDst++) = colors[0];
*(pDst++) = colors[0];
*(pDst++) = colors[0];
// Color cell 1
*(pDst++) = colors[1];
*(pDst++) = colors[1];
*(pDst++) = colors[1];
dwordval >>= 7;
g_dhgrLastCellIsColor = true;
}
else
{
// BW
for (int i = 0; i < 7; i++)
{
g_dhgrLastBit = dwordval & 1;
*(pDst++) = bw[g_dhgrLastBit];
dwordval >>= 1;
}
g_dhgrLastCellIsColor = false;
}
if ((byteval2 & 0x80) || !isMixMode)
{
// Remaining of color cell 1
if (g_dhgrLastCellIsColor)
{
*(pDst++) = colors[1];
}
else
{
// Repeat last BW bit once
*(pDst++) = bw[g_dhgrLastBit];
}
// Color cell 2
*(pDst++) = colors[2];
*(pDst++) = colors[2];
*(pDst++) = colors[2];
*(pDst++) = colors[2];
// Color cell 3
*(pDst++) = colors[3];
*(pDst++) = colors[3];
g_dhgrLastCellIsColor = true;
}
else
{
for (int i = 0; i < 7; i++)
{
g_dhgrLastBit = dwordval & 1;
*(pDst++) = bw[g_dhgrLastBit];
dwordval >>= 1;
}
g_dhgrLastCellIsColor = false;
}
}
else // Second cell
{
dwordval >>= 14;
if ((byteval3 & 0x80) || !isMixMode)
{
// Remaining of color cell 3
if (g_dhgrLastCellIsColor)
{
*(pDst++) = colors[3];
*(pDst++) = colors[3];
}
else
{
// Repeat last BW bit twice
*(pDst++) = bw[g_dhgrLastBit];
*(pDst++) = bw[g_dhgrLastBit];
}
// Color cell 4
*(pDst++) = colors[4];
*(pDst++) = colors[4];
*(pDst++) = colors[4];
*(pDst++) = colors[4];
// Color cell 5
*(pDst++) = colors[5];
dwordval >>= 7;
g_dhgrLastCellIsColor = true;
}
else
{
for (int i = 0; i < 7; i++)
{
g_dhgrLastBit = dwordval & 1;
*(pDst++) = bw[g_dhgrLastBit];
dwordval >>= 1;
}
g_dhgrLastCellIsColor = false;
}
if ((byteval4 & 0x80) || !isMixMode)
{
// Remaining of color cell 5
if (g_dhgrLastCellIsColor)
{
*(pDst++) = colors[5];
*(pDst++) = colors[5];
*(pDst++) = colors[5];
}
else
{
// Repeat last BW bit three times
*(pDst++) = bw[g_dhgrLastBit];
*(pDst++) = bw[g_dhgrLastBit];
*(pDst++) = bw[g_dhgrLastBit];
}
// Color cell 6
*(pDst++) = colors[6];
*(pDst++) = colors[6];
*(pDst++) = colors[6];
*(pDst++) = colors[6];
g_dhgrLastCellIsColor = true;
}
else
{
for (int i = 0; i < 7; i++)
{
g_dhgrLastBit = dwordval & 1;
*(pDst++) = bw[g_dhgrLastBit];
dwordval >>= 1;
}
g_dhgrLastCellIsColor = false;
}
}
const bool bIsHalfScanLines = IsVideoStyle(VS_HALF_SCANLINES);
// Second line
UINT32* pSrc = (UINT32*)pVideoAddress ;
pDst = pSrc - GetFrameBufferWidth();
if (bIsHalfScanLines)
{
// Scanlines
std::fill(pDst, pDst + 14, 0);
}
else
{
for (int i = 0; i < 14; i++)
*(pDst + i) = *(pSrc + i);
}
}
#if 1
// Squash the 640 pixel image into 560 pixels
int UpdateDHiRes160Cell (int x, int y, uint16_t addr, bgra_t *pVideoAddress)
@ -697,13 +1059,108 @@ void UpdateDLoResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress)
}
}
//===========================================================================
// Color TEXT (some RGB cards only)
// Default BG and FG are usually defined by hardware switches, defaults to black/white
void UpdateText40ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, uint8_t bits, uint8_t character)
{
uint8_t foreground = g_nRegularTextFG;
uint8_t background = g_nRegularTextBG;
if (g_nTextFBMode)
{
const BYTE val = *MemGetAuxPtr(addr); // RGB cards with F/B text use their own AUX memory!
foreground = val >> 4;
background = val & 0x0F;
}
else if (g_RGBVideocard == RGB_Videocard_e::Video7_SL7 && character < 0x80)
{
// in regular 40COL mode, the SL7 videocard renders inverse characters as B&W
foreground = 15;
background = 0;
}
UpdateDuochromeCell(2, 14, pVideoAddress, bits, foreground, background);
}
void UpdateText80ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, uint8_t bits, uint8_t character)
{
if (g_RGBVideocard == RGB_Videocard_e::Video7_SL7 && character < 0x80)
{
// in all 80COL modes, the SL7 videocard renders inverse characters as B&W
UpdateDuochromeCell(2, 7, pVideoAddress, bits, 15, 0);
}
else
UpdateDuochromeCell(2, 7, pVideoAddress, bits, g_nRegularTextFG, g_nRegularTextBG);
}
//===========================================================================
// Duochrome HGR (some RGB cards only)
void UpdateHiResDuochromeCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress)
{
BYTE bits = *MemGetMainPtr(addr);
BYTE val = *MemGetAuxPtr(addr);
const uint8_t foreground = val >> 4;
const uint8_t background = val & 0x0F;
UpdateDuochromeCell(2, 14, pVideoAddress, bits, foreground, background);
}
//===========================================================================
// Writes a duochrome cell
// 7 bits define a foreground/background pattern
// Used on many RGB cards but activated differently, depending on the card.
// Can be used in TEXT or HGR mode. The foreground & background colors could be fixed by hardware switches or data lying in AUX.
void UpdateDuochromeCell(int h, int w, bgra_t* pVideoAddress, uint8_t bits, uint8_t foreground, uint8_t background)
{
UINT32* pDst = (UINT32*)pVideoAddress;
const bool bIsHalfScanLines = IsVideoStyle(VS_HALF_SCANLINES);
const UINT frameBufferWidth = GetFrameBufferWidth();
RGBQUAD colors[2];
// use LoRes palette
background += 12;
foreground += 12;
// get bg/fg colors
colors[0] = g_pPaletteRGB[background];
colors[1] = g_pPaletteRGB[foreground];
int nbits = bits;
int doublepixels = (w == 14); // Double pixel (HiRes or Text40)
while (h--)
{
bits = nbits;
if (bIsHalfScanLines && !(h & 1))
{
// 50% Half Scan Line clears every odd scanline (and SHIFT+PrintScreen saves only the even rows)
std::fill(pDst, pDst + w, 0);
}
else
{
for (int nBytes = 0; nBytes < w; nBytes += (doublepixels?2:1))
{
int bit = (bits & 1);
bits >>= 1;
const RGBQUAD& rRGB = colors[bit];
*(pDst + nBytes) = *reinterpret_cast<const UINT32*>(&rRGB);
if (doublepixels)
{
*(pDst + nBytes + 1) = *reinterpret_cast<const UINT32*>(&rRGB);
}
}
}
pDst -= frameBufferWidth;
}
}
//===========================================================================
static LPBYTE g_pSourcePixels = NULL;
static void V_CreateDIBSections(void)
{
g_pSourcePixels = new BYTE[SRCOFFS_TOTAL * MAX_SOURCE_Y];
if (!g_pSourcePixels) // NB. Will be non-zero after a VM restart (GH#809)
g_pSourcePixels = new BYTE[SRCOFFS_TOTAL * MAX_SOURCE_Y];
// CREATE THE OFFSET TABLE FOR EACH SCAN LINE IN THE SOURCE IMAGE
for (int y = 0; y < MAX_SOURCE_Y; y++)
@ -724,15 +1181,29 @@ void VideoInitializeOriginal(baseColors_t pBaseNtscColors)
// CREATE THE SOURCE IMAGE AND DRAW INTO THE SOURCE BIT BUFFER
V_CreateDIBSections();
memcpy(&PalIndex2RGB[BLACK], *pBaseNtscColors, sizeof(RGBQUAD)*kNumBaseColors);
PalIndex2RGB[HGR_BLUE] = PalIndex2RGB[BLUE];
PalIndex2RGB[HGR_ORANGE] = PalIndex2RGB[ORANGE];
PalIndex2RGB[HGR_GREEN] = PalIndex2RGB[GREEN];
PalIndex2RGB[HGR_VIOLET] = PalIndex2RGB[MAGENTA];
// Replace the default palette with true NTSC-generated colors
memcpy(&PaletteRGB_NTSC[BLACK], *pBaseNtscColors, sizeof(RGBQUAD) * kNumBaseColors);
PaletteRGB_NTSC[HGR_BLUE] = PaletteRGB_NTSC[BLUE];
PaletteRGB_NTSC[HGR_ORANGE] = PaletteRGB_NTSC[ORANGE];
PaletteRGB_NTSC[HGR_GREEN] = PaletteRGB_NTSC[GREEN];
PaletteRGB_NTSC[HGR_VIOLET] = PaletteRGB_NTSC[MAGENTA];
}
//===========================================================================
// RGB videocards may use a different palette thant the NTSC-generated one
void VideoSwitchVideocardPalette(RGB_Videocard_e videocard, VideoType_e type)
{
g_pPaletteRGB = PaletteRGB_NTSC;
if (type==VideoType_e::VT_COLOR_VIDEOCARD_RGB && videocard == RGB_Videocard_e::LeChatMauve_Feline)
{
g_pPaletteRGB = PaletteRGB_Feline;
}
}
//===========================================================================
static UINT g_rgbFlags = 0;
static UINT g_rgbMode = 0;
static WORD g_rgbPrevAN3Addr = 0;
@ -745,13 +1216,14 @@ static bool g_rgbInvertBit7 = false;
// . NB. There's a final 5th AN3 transition to set DHGR mode
void RGB_SetVideoMode(WORD address)
{
if ((address&~1) == 0x0C) // 0x0C or 0x0D? (80COL)
if ((address & ~1) == 0x0C) // 0x0C or 0x0D? (80COL)
{
g_rgbSet80COL = true;
return;
}
if ((address&~1) != 0x5E) // 0x5E or 0x5F? (DHIRES)
if ((address & ~1) != 0x5E) // 0x5E or 0x5F? (DHIRES)
return;
// Precondition before toggling AN3:
@ -761,33 +1233,37 @@ void RGB_SetVideoMode(WORD address)
// . Apple II desktop sets DHGR B&W mode with HIRES off! (GH#631)
// Maybe there is no video-mode precondition?
// . After setting 80COL on/off then need a 0x5E->0x5F toggle. So if we see a 0x5F then reset (GH#633)
if ((g_uVideoMode & VF_MIXED) || (g_rgbSet80COL && address == 0x5F))
{
g_rgbMode = 0;
g_rgbPrevAN3Addr = 0;
g_rgbSet80COL = false;
return;
}
if (address == 0x5F && g_rgbPrevAN3Addr == 0x5E) // Check for AN3 clock transition
// From Video7 patent and Le Chat Mauve manuals (under patent of Video7), no precondition is needed.
// In Prince of Persia, in the game demo, the RGB card switches to BW DHIRES after the HGR animation with Jaffar.
// It's actually the same on real hardware (tested on IIc RGB adapter).
if (address == 0x5F)
{
g_rgbFlags = (g_rgbFlags<<1) & 3;
g_rgbFlags |= ((g_uVideoMode & VF_80COL) ? 0 : 1); // clock in !80COL
g_rgbMode = g_rgbFlags; // latch F2,F1
if ((g_rgbPrevAN3Addr == 0x5E) && g_rgbSet80COL)
{
g_rgbFlags = (g_rgbFlags << 1) & 3;
g_rgbFlags |= ((g_uVideoMode & VF_80COL) ? 0 : 1); // clock in !80COL
g_rgbMode = g_rgbFlags; // latch F2,F1
}
g_rgbSet80COL = false;
}
g_rgbPrevAN3Addr = address;
g_rgbSet80COL = false;
}
bool RGB_Is140Mode(void) // Extended 80-Column Text/AppleColor Card's Mode 2
{
return g_rgbMode == 0;
// Feline falls back to this mode instead of 160
return g_rgbMode == 0 || (g_RGBVideocard == RGB_Videocard_e::LeChatMauve_Feline && g_rgbMode == 1);
}
bool RGB_Is160Mode(void) // Extended 80-Column Text/AppleColor Card: N/A
{
return g_rgbMode == 1;
// Unsupported by Feline
return g_rgbMode == 1 && (g_RGBVideocard != RGB_Videocard_e::LeChatMauve_Feline);
}
bool RGB_IsMixMode(void) // Extended 80-Column Text/AppleColor Card's Mode 3
@ -856,3 +1332,50 @@ void RGB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT cardVersion)
yamlLoadHelper.PopMap();
}
RGB_Videocard_e RGB_GetVideocard(void)
{
return g_RGBVideocard;
}
void RGB_SetVideocard(RGB_Videocard_e videocard, int text_foreground, int text_background)
{
g_RGBVideocard = videocard;
// black & white text
RGB_SetRegularTextFG(15);
RGB_SetRegularTextBG(0);
if (videocard == RGB_Videocard_e::Video7_SL7 &&
(text_foreground == 6 || text_foreground == 9 || text_foreground == 12 || text_foreground == 15))
{
// SL7: Only Blue, Amber (Orange), Green, White are supported by hardware switches
RGB_SetRegularTextFG(text_foreground);
RGB_SetRegularTextBG(0);
}
}
void RGB_SetRegularTextFG(int color)
{
g_nRegularTextFG = color;
}
void RGB_SetRegularTextBG(int color)
{
g_nRegularTextBG = color;
}
void RGB_EnableTextFB()
{
g_nTextFBMode = 1;
}
void RGB_DisableTextFB()
{
g_nTextFBMode = 0;
}
int RGB_IsTextFB()
{
return g_nTextFBMode;
}

View file

@ -1,12 +1,30 @@
// Handling of RGB videocards
enum RGB_Videocard_e
{
Apple,
Video7_SL7,
LeChatMauve_EVE,
LeChatMauve_Feline
};
void UpdateHiResCell(int x, int y, uint16_t addr, bgra_t *pVideoAddress);
void UpdateDHiResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress, bool updateAux, bool updateMain);
void UpdateDHiResCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, bool updateAux, bool updateMain);
void UpdateDHiResCellRGB(int x, int y, uint16_t addr, bgra_t* pVideoAddress, bool isMixMode, bool isBit7Inversed);
int UpdateDHiRes160Cell (int x, int y, uint16_t addr, bgra_t *pVideoAddress);
void UpdateLoResCell(int x, int y, uint16_t addr, bgra_t *pVideoAddress);
void UpdateDLoResCell(int x, int y, uint16_t addr, bgra_t *pVideoAddress);
void UpdateText40ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, uint8_t bits, uint8_t character);
void UpdateText80ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, uint8_t bits, uint8_t character);
void UpdateHiResDuochromeCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress);
void UpdateDuochromeCell(int h, int w, bgra_t* pVideoAddress, uint8_t bits, uint8_t foreground, uint8_t background);
void UpdateHiResRGBCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress);
const UINT kNumBaseColors = 16;
typedef bgra_t (*baseColors_t)[kNumBaseColors];
void VideoInitializeOriginal(baseColors_t pBaseNtscColors);
void VideoSwitchVideocardPalette(RGB_Videocard_e videocard, VideoType_e type);
void RGB_SetVideoMode(WORD address);
bool RGB_Is140Mode(void);
@ -19,3 +37,11 @@ void RGB_SetInvertBit7(bool state);
void RGB_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
void RGB_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT cardVersion);
RGB_Videocard_e RGB_GetVideocard(void);
void RGB_SetVideocard(RGB_Videocard_e videocard, int text_foreground = -1, int text_background = -1);
void RGB_SetRegularTextFG(int color);
void RGB_SetRegularTextBG(int color);
void RGB_EnableTextFB();
void RGB_DisableTextFB();
int RGB_IsTextFB();

View file

@ -28,10 +28,30 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
extern std::string g_sConfigFile;
namespace _ini {
//===========================================================================
BOOL RegLoadString(LPCTSTR section, LPCTSTR key, BOOL peruser, LPTSTR buffer, DWORD chars)
{
DWORD n = GetPrivateProfileString(section, key, NULL, buffer, chars, g_sConfigFile.c_str());
return n > 0;
}
//===========================================================================
void RegSaveString(LPCTSTR section, LPCTSTR key, BOOL peruser, const std::string& buffer)
{
BOOL updated = WritePrivateProfileString(section, key, buffer.c_str(), g_sConfigFile.c_str());
_ASSERT(updated || GetLastError() == 0);
}
}
//===========================================================================
BOOL RegLoadString (LPCTSTR section, LPCTSTR key, BOOL peruser, LPTSTR buffer, DWORD chars)
{
if (!g_sConfigFile.empty())
return _ini::RegLoadString(section, key, peruser, buffer, chars);
TCHAR fullkeyname[256];
StringCbPrintf(fullkeyname, 256, TEXT("Software\\AppleWin\\CurrentVersion\\%s"), section);
@ -88,6 +108,9 @@ BOOL RegLoadValue (LPCTSTR section, LPCTSTR key, BOOL peruser, DWORD* value, DWO
//===========================================================================
void RegSaveString (LPCTSTR section, LPCTSTR key, BOOL peruser, const std::string & buffer) {
if (!g_sConfigFile.empty())
return _ini::RegSaveString(section, key, peruser, buffer);
TCHAR fullkeyname[256];
StringCbPrintf(fullkeyname, 256, TEXT("Software\\AppleWin\\CurrentVersion\\%s"), section);
@ -122,3 +145,4 @@ void RegSaveValue (LPCTSTR section, LPCTSTR key, BOOL peruser, DWORD value) {
StringCbPrintf(buffer, 32, "%d", value);
RegSaveString(section, key, peruser, buffer);
}

View file

@ -35,7 +35,7 @@ static DWORD dwDataOffset;
static DWORD g_dwTotalNumberOfBytesWritten = 0;
static unsigned int g_NumChannels = 2;
int RiffInitWriteFile(char* pszFile, unsigned int sample_rate, unsigned int NumChannels)
int RiffInitWriteFile(const char* pszFile, unsigned int sample_rate, unsigned int NumChannels)
{
g_hRiffFile = CreateFile(pszFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
@ -117,7 +117,7 @@ int RiffFinishWriteFile()
return CloseHandle(g_hRiffFile);
}
int RiffPutSamples(short* buf, unsigned int uSamples)
int RiffPutSamples(const short* buf, unsigned int uSamples)
{
if(g_hRiffFile == INVALID_HANDLE_VALUE)
return 1;

View file

@ -1,5 +1,5 @@
#pragma once
int RiffInitWriteFile(char* pszFile, unsigned int sample_rate, unsigned int NumChannels);
int RiffInitWriteFile(const char* pszFile, unsigned int sample_rate, unsigned int NumChannels);
int RiffFinishWriteFile();
int RiffPutSamples(short* buf, unsigned int uSamples);
int RiffPutSamples(const short* buf, unsigned int uSamples);

Some files were not shown because too many files have changed in this diff Show more