diff --git a/Visual Studio Projects/Simh.ci.sln b/Visual Studio Projects/Simh.ci.sln
index a1d5c49b3..6b6b85bfd 100755
--- a/Visual Studio Projects/Simh.ci.sln
+++ b/Visual Studio Projects/Simh.ci.sln
@@ -59,6 +59,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swtp6800mp-a", "swtp6800mp-
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swtp6800mp-a2", "swtp6800mp-a2.vcxproj", "{A0BAF350-853E-4A8F-8435-B583E29FFACE}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swtp6809mp-09", "swtp6809mp-09.vcxproj", "{8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}"
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BuildROMs", "BuildROMs.vcxproj", "{D40F3AF1-EEE7-4432-9807-2AD287B490F8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VAX730", "VAX730.vcxproj", "{C526F7F2-9476-44BC-B1E9-9522B693BEA7}"
@@ -791,6 +793,14 @@ Global
{9B214A06-3727-44D4-99B7-2C3E44B86B32}.Release|ARM.Build.0 = Release|ARM
{9B214A06-3727-44D4-99B7-2C3E44B86B32}.Release|Win32.ActiveCfg = Release|Win32
{9B214A06-3727-44D4-99B7-2C3E44B86B32}.Release|Win32.Build.0 = Release|Win32
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}.Debug|ARM.ActiveCfg = Debug|ARM
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}.Debug|ARM.Build.0 = Debug|ARM
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}.Debug|Win32.Build.0 = Debug|Win32
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}.Release|ARM.ActiveCfg = Release|ARM
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}.Release|ARM.Build.0 = Release|ARM
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}.Release|Win32.ActiveCfg = Release|Win32
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Visual Studio Projects/Simh.sln b/Visual Studio Projects/Simh.sln
index 7c472fec6..26ea08e70 100755
--- a/Visual Studio Projects/Simh.sln
+++ b/Visual Studio Projects/Simh.sln
@@ -141,6 +141,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swtp6800mp-a2", "swtp6800mp
{D40F3AF1-EEE7-4432-9807-2AD287B490F8} = {D40F3AF1-EEE7-4432-9807-2AD287B490F8}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swtp6809mp-09", "swtp6809mp-09.vcproj", "{8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D40F3AF1-EEE7-4432-9807-2AD287B490F8} = {D40F3AF1-EEE7-4432-9807-2AD287B490F8}
+ EndProjectSection
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BuildROMs", "BuildROMs.vcproj", "{D40F3AF1-EEE7-4432-9807-2AD287B490F8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VAX730", "VAX730.vcproj", "{C526F7F2-9476-44BC-B1E9-9522B693BEA7}"
@@ -511,6 +516,10 @@ Global
{A0BAF350-853E-4A8F-8435-B583E29FFACE}.Debug|Win32.Build.0 = Debug|Win32
{A0BAF350-853E-4A8F-8435-B583E29FFACE}.Release|Win32.ActiveCfg = Release|Win32
{A0BAF350-853E-4A8F-8435-B583E29FFACE}.Release|Win32.Build.0 = Release|Win32
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}.Debug|Win32.Build.0 = Debug|Win32
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}.Release|Win32.ActiveCfg = Release|Win32
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}.Release|Win32.Build.0 = Release|Win32
{D40F3AF1-EEE7-4432-9807-2AD287B490F8}.Debug|Win32.ActiveCfg = Debug|Win32
{D40F3AF1-EEE7-4432-9807-2AD287B490F8}.Debug|Win32.Build.0 = Debug|Win32
{D40F3AF1-EEE7-4432-9807-2AD287B490F8}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/Visual Studio Projects/swtp6809mp-09.vcproj b/Visual Studio Projects/swtp6809mp-09.vcproj
new file mode 100644
index 000000000..6167bfc8a
--- /dev/null
+++ b/Visual Studio Projects/swtp6809mp-09.vcproj
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Visual Studio Projects/swtp6809mp-09.vcxproj b/Visual Studio Projects/swtp6809mp-09.vcxproj
new file mode 100755
index 000000000..b65e155a1
--- /dev/null
+++ b/Visual Studio Projects/swtp6809mp-09.vcxproj
@@ -0,0 +1,285 @@
+
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+
+ 17.0
+ {8E13D759-D7F9-4AFB-91CC-B7F8BA98F8F7}
+ swtp6809mp-09
+ Win32Proj
+
+
+
+ Application
+ v143
+ NotSet
+
+
+ Application
+ v143
+ NotSet
+
+
+ Application
+ v143
+ NotSet
+
+
+ Application
+ v143
+ NotSet
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>17.0.33015.44
+
+
+ ..\BIN\NT\$(Platform)-$(Configuration)\
+ ..\BIN\NT\Project\simh\$(ProjectName)\$(Platform)-$(Configuration)\
+ false
+
+
+ ..\BIN\NT\$(Platform)-$(Configuration)\
+ ..\BIN\NT\Project\simh\$(ProjectName)\$(Platform)-$(Configuration)\
+ false
+
+
+ ..\BIN\NT\$(Platform)-$(Configuration)\
+ ..\BIN\NT\Project\simh\$(ProjectName)\$(Platform)-$(Configuration)\
+ false
+
+
+ ..\BIN\NT\$(Platform)-$(Configuration)\
+ ..\BIN\NT\Project\simh\$(ProjectName)\$(Platform)-$(Configuration)\
+ false
+
+
+
+ Check for required build dependencies & git commit id
+ Pre-Build-Event.cmd "$(TargetDir)$(TargetName).exe" LIBPCRE
+
+
+ Disabled
+ ../swtp6809/swtp6809;./;../;../slirp;../slirp_glue;../slirp_glue/qemu;../slirp_glue/qemu/win32/include;../../windows-build/include;../../windows-build/include/SDL2;%(AdditionalIncludeDirectories)
+ _CRT_NONSTDC_NO_WARNINGS;SIM_BUILD_TOOL=simh-Visual-Studio-Project;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID;HAVE_PCRE_H;PCRE_STATIC;%(PreprocessorDefinitions)
+ false
+ Default
+ MultiThreadedDebug
+
+ Level3
+ true
+ ProgramDatabase
+ CompileAsC
+ false
+
+
+ libcmtd.lib;wsock32.lib;winmm.lib;Iphlpapi.lib;pcrestaticd.lib;SDL2-StaticD.lib;SDL2_ttf-StaticD.lib;freetype2412MT_D.lib;libpng16.lib;zlib.lib;dxguid.lib;Imm32.lib;Version.lib;Setupapi.lib;%(AdditionalDependencies)
+ ../../windows-build/lib/Debug/;%(AdditionalLibraryDirectories)
+ true
+ Console
+ 10485760
+ 10485760
+ false
+
+ MachineX86
+
+
+ Running Available Tests
+ Post-Build-Event.cmd swtp6809\swtp6809 "$(TargetDir)$(TargetName).exe"
+
+
+
+
+ Check for required build dependencies & git commit id
+ Pre-Build-Event.cmd "$(TargetDir)$(TargetName).exe" LIBPCRE
+
+
+ Disabled
+ ../swtp6809/swtp6809;./;../;../slirp;../slirp_glue;../slirp_glue/qemu;../slirp_glue/qemu/win32/include;../../windows-build/include;../../windows-build/include/SDL2;%(AdditionalIncludeDirectories)
+ _CRT_NONSTDC_NO_WARNINGS;SIM_BUILD_TOOL=simh-Visual-Studio-Project;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID;HAVE_PCRE_H;PCRE_STATIC;%(PreprocessorDefinitions)
+ false
+ Default
+ MultiThreadedDebug
+
+
+ Level3
+ true
+ ProgramDatabase
+ CompileAsC
+ false
+
+
+ libcmtd.lib;wsock32.lib;winmm.lib;Iphlpapi.lib;pcrestaticd.lib;SDL2-StaticD.lib;SDL2_ttf-StaticD.lib;freetype2412MT_D.lib;libpng16.lib;zlib.lib;dxguid.lib;Imm32.lib;Version.lib;Setupapi.lib;%(AdditionalDependencies)
+ ../../windows-build/lib/Debug/;%(AdditionalLibraryDirectories)
+ true
+ Console
+ 10485760
+ 10485760
+ true
+
+
+
+
+ Running Available Tests
+ Post-Build-Event.cmd swtp6809\swtp6809 "$(TargetDir)$(TargetName).exe"
+
+
+
+
+ Check for required build dependencies & git commit id
+ Pre-Build-Event.cmd "$(TargetDir)$(TargetName).exe" LIBPCRE
+
+
+ MaxSpeed
+ OnlyExplicitInline
+ true
+ true
+ ../swtp6809/swtp6809;./;../;../slirp;../slirp_glue;../slirp_glue/qemu;../slirp_glue/qemu/win32/include;../../windows-build/include;../../windows-build/include/SDL2;%(AdditionalIncludeDirectories)
+ _CRT_NONSTDC_NO_WARNINGS;SIM_BUILD_TOOL=simh-Visual-Studio-Project;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID;HAVE_PCRE_H;PCRE_STATIC;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ true
+
+ Level3
+ true
+ ProgramDatabase
+ CompileAsC
+
+
+ libcmt.lib;wsock32.lib;winmm.lib;Iphlpapi.lib;pcrestatic.lib;SDL2-Static.lib;SDL2_ttf-Static.lib;freetype2412MT.lib;libpng16.lib;zlib.lib;dxguid.lib;Imm32.lib;Version.lib;Setupapi.lib;%(AdditionalDependencies)
+ ../../windows-build/lib/Release/;%(AdditionalLibraryDirectories)
+ false
+ Console
+ 10485760
+ 10485760
+ true
+ true
+ UseLinkTimeCodeGeneration
+ false
+
+ MachineX86
+
+
+ Running Available Tests
+ Post-Build-Event.cmd swtp6809\swtp6809 "$(TargetDir)$(TargetName).exe"
+
+
+
+
+ Check for required build dependencies & git commit id
+ Pre-Build-Event.cmd "$(TargetDir)$(TargetName).exe" LIBPCRE
+
+
+ MaxSpeed
+ OnlyExplicitInline
+ true
+ true
+ ../swtp6809/swtp6809;./;../;../slirp;../slirp_glue;../slirp_glue/qemu;../slirp_glue/qemu/win32/include;../../windows-build/include;../../windows-build/include/SDL2;%(AdditionalIncludeDirectories)
+ _CRT_NONSTDC_NO_WARNINGS;SIM_BUILD_TOOL=simh-Visual-Studio-Project;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID;HAVE_PCRE_H;PCRE_STATIC;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ true
+
+
+ Level3
+ true
+ ProgramDatabase
+ CompileAsC
+
+
+ libcmt.lib;wsock32.lib;winmm.lib;Iphlpapi.lib;pcrestatic.lib;SDL2-Static.lib;SDL2_ttf-Static.lib;freetype2412MT.lib;libpng16.lib;zlib.lib;dxguid.lib;Imm32.lib;Version.lib;Setupapi.lib;%(AdditionalDependencies)
+ ../../windows-build/lib/Release/;%(AdditionalLibraryDirectories)
+ false
+ Console
+ 10485760
+ 10485760
+ true
+ true
+ UseLinkTimeCodeGeneration
+ true
+
+
+
+
+ Running Available Tests
+ Post-Build-Event.cmd swtp6809\swtp6809 "$(TargetDir)$(TargetName).exe"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {d40f3af1-eee7-4432-9807-2ad287b490f8}
+ false
+
+
+
+
+
+
diff --git a/Visual Studio Projects/swtp6809mp-09.vcxproj.filters b/Visual Studio Projects/swtp6809mp-09.vcxproj.filters
new file mode 100755
index 000000000..3d323384d
--- /dev/null
+++ b/Visual Studio Projects/swtp6809mp-09.vcxproj.filters
@@ -0,0 +1,120 @@
+
+
+
+
+ {1b3c9024-9ac5-45b2-a4d1-4d71fc8034a3}
+ cpp;c;cxx;def;odl;idl;hpj;bat;asm
+
+
+ {6c10d94a-a634-405c-bfa0-50d119e395e3}
+ h;hpp;hxx;hm;inl;inc
+
+
+ {f5b02d79-da6d-477f-8a9c-cb71863a90b7}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
diff --git a/cmake/simgen/packaging.py b/cmake/simgen/packaging.py
index 6f088a2c3..e22ce491b 100644
--- a/cmake/simgen/packaging.py
+++ b/cmake/simgen/packaging.py
@@ -226,6 +226,7 @@ def write_packaging(toplevel_dir) -> None:
package_info["ssem"] = SIMHPackaging(default_family)
package_info["swtp6800mp-a"] = SIMHPackaging(swtp_family)
package_info["swtp6800mp-a2"] = SIMHPackaging(swtp_family)
+package_info["swtp6809mp-09"] = SIMHPackaging(swtp_family)
package_info["tt2500"] = SIMHPackaging(default_family)
package_info["tx-0"] = SIMHPackaging(default_family)
package_info["uc15"] = SIMHPackaging(pdp11_family)
diff --git a/cmake/simgen/simulators.py b/cmake/simgen/simulators.py
index 71e8b4067..8bb54caac 100644
--- a/cmake/simgen/simulators.py
+++ b/cmake/simgen/simulators.py
@@ -59,6 +59,7 @@
"ssem"
"swtp6800mp-a"
"swtp6800mp-a2"
+"swtp6800mp-09"
"tt2500"
"tx-0"
"uc15"
@@ -72,4 +73,4 @@
"vaxstation3100m38"
"vaxstation3100m76"
"vaxstation4000m60"
-"vaxstation4000vlc"
\ No newline at end of file
+"vaxstation4000vlc"
diff --git a/cmake/simh-packaging.cmake b/cmake/simh-packaging.cmake
index fdcc14481..73ac623f7 100644
--- a/cmake/simh-packaging.cmake
+++ b/cmake/simh-packaging.cmake
@@ -1,103 +1,103 @@
-## The default runtime support component/family:
-cpack_add_component(runtime_support
- DISPLAY_NAME "Runtime support"
- DESCRIPTION "Required SIMH runtime support (documentation, shared libraries)"
- REQUIRED
-)
-
-## Basic documentation for SIMH
-install(FILES doc/simh.doc TYPE DOC COMPONENT runtime_support)
-
-cpack_add_component(altairz80_family
- DISPLAY_NAME "Altair Z80 simulator."
- DESCRIPTION "The Altair Z80 simulator with M68000 support. Simulators: altairz80"
-)
-cpack_add_component(att3b2_family
- DISPLAY_NAME "ATT&T 3b2 collection"
- DESCRIPTION "The AT&T 3b2 simulator family. Simulators: 3b2, 3b2-700"
-)
-cpack_add_component(b5500_family
- DISPLAY_NAME "Burroughs 5500"
- DESCRIPTION "The Burroughs 5500 system simulator. Simulators: b5500"
-)
-cpack_add_component(cdc1700_family
- DISPLAY_NAME "CDC 1700"
- DESCRIPTION "The Control Data Corporation's systems. Simulators: cdc1700"
-)
-cpack_add_component(decpdp_family
- DISPLAY_NAME "DEC PDP family"
- DESCRIPTION "Digital Equipment Corporation PDP systems. Simulators: pdp1, pdp15, pdp4, pdp6, pdp7, pdp8, pdp9"
-)
-cpack_add_component(default_family
- DISPLAY_NAME "Default SIMH simulator family."
- DESCRIPTION "The SIMH simulator collection of historical processors and computing systems that do not belong to
-any other simulated system family. Simulators: altair, besm6, ssem, tt2500, tx-0"
-)
-cpack_add_component(dgnova_family
- DISPLAY_NAME "DG Nova and Eclipse"
- DESCRIPTION "Data General NOVA and Eclipse system simulators. Simulators: eclipse, nova"
-)
-cpack_add_component(experimental
- DISPLAY_NAME "Experimental (work-in-progress) simulators"
- DESCRIPTION "Experimental or work-in-progress simulators not in the SIMH mainline simulator suite. Simulators: alpha, pdq3, sage"
-)
-cpack_add_component(gould_family
- DISPLAY_NAME "Gould simulators"
- DESCRIPTION "Gould Systems simulators. Simulators: sel32"
-)
-cpack_add_component(grisys_family
- DISPLAY_NAME "GRI Systems GRI-909"
- DESCRIPTION "GRI Systems GRI-909 system simulator. Simulators: gri"
-)
-cpack_add_component(honeywell_family
- DISPLAY_NAME "Honeywell H316"
- DESCRIPTION "Honeywell H-316 system simulator. Simulators: h316"
-)
-cpack_add_component(hp_family
- DISPLAY_NAME "HP 2100, 3000"
- DESCRIPTION "Hewlett-Packard H2100 and H3000 simulators. Simulators: hp2100, hp3000"
-)
-cpack_add_component(ibm_family
- DISPLAY_NAME "IBM"
- DESCRIPTION "IBM system simulators: i650. Simulators: i1401, i1620, i650, i701, i7010, i704, i7070, i7080, i7090, i7094, ibm1130, s3"
-)
-cpack_add_component(imlac_family
- DISPLAY_NAME "IMLAC"
- DESCRIPTION "IMLAC system simulators. Simulators: imlac"
-)
-cpack_add_component(intel_family
- DISPLAY_NAME "Intel"
- DESCRIPTION "Intel system simulators. Simulators: intel-mds, scelbi"
-)
-cpack_add_component(interdata_family
- DISPLAY_NAME "Interdata"
- DESCRIPTION "Interdata systems simulators. Simulators: id16, id32"
-)
-cpack_add_component(lgp_family
- DISPLAY_NAME "LGP"
- DESCRIPTION "Librascope systems. Simulators: lgp"
-)
-cpack_add_component(norsk_family
- DISPLAY_NAME "ND simulators"
- DESCRIPTION "Norsk Data systems simulator family. Simulators: nd100"
-)
-cpack_add_component(pdp10_family
- DISPLAY_NAME "DEC PDP-10 collection"
- DESCRIPTION "DEC PDP-10 architecture simulators and variants. Simulators: pdp10, pdp10-ka, pdp10-ki, pdp10-kl, pdp10-ks"
-)
-cpack_add_component(pdp11_family
- DISPLAY_NAME "DEC PDP-11 collection."
- DESCRIPTION "DEC PDP-11 and PDP-11-derived architecture simulators. Simulators: pdp11, uc15"
-)
-cpack_add_component(sds_family
- DISPLAY_NAME "SDS simulators"
- DESCRIPTION "Scientific Data Systems (SDS) systems. Simulators: sds, sigma"
-)
-cpack_add_component(swtp_family
- DISPLAY_NAME "SWTP simulators"
- DESCRIPTION "Southwest Technical Products (SWTP) system simulators. Simulators: swtp6800mp-a, swtp6800mp-a2"
-)
-cpack_add_component(vax_family
- DISPLAY_NAME "DEC VAX simulator collection"
- DESCRIPTION "The Digital Equipment Corporation VAX (plural: VAXen) simulator family. Simulators: infoserver100, infoserver1000, infoserver150vxt, microvax1, microvax2, microvax2000, microvax3100, microvax3100e, microvax3100m80, rtvax1000, vax, vax730, vax750, vax780, vax8200, vax8600, vaxstation3100m30, vaxstation3100m38, vaxstation3100m76, vaxstation4000m60, vaxstation4000vlc"
-)
+## The default runtime support component/family:
+cpack_add_component(runtime_support
+ DISPLAY_NAME "Runtime support"
+ DESCRIPTION "Required SIMH runtime support (documentation, shared libraries)"
+ REQUIRED
+)
+
+## Basic documentation for SIMH
+install(FILES doc/simh.doc TYPE DOC COMPONENT runtime_support)
+
+cpack_add_component(altairz80_family
+ DISPLAY_NAME "Altair Z80 simulator."
+ DESCRIPTION "The Altair Z80 simulator with M68000 support. Simulators: altairz80"
+)
+cpack_add_component(att3b2_family
+ DISPLAY_NAME "ATT&T 3b2 collection"
+ DESCRIPTION "The AT&T 3b2 simulator family. Simulators: 3b2, 3b2-700"
+)
+cpack_add_component(b5500_family
+ DISPLAY_NAME "Burroughs 5500"
+ DESCRIPTION "The Burroughs 5500 system simulator. Simulators: b5500"
+)
+cpack_add_component(cdc1700_family
+ DISPLAY_NAME "CDC 1700"
+ DESCRIPTION "The Control Data Corporation's systems. Simulators: cdc1700"
+)
+cpack_add_component(decpdp_family
+ DISPLAY_NAME "DEC PDP family"
+ DESCRIPTION "Digital Equipment Corporation PDP systems. Simulators: pdp1, pdp15, pdp4, pdp6, pdp7, pdp8, pdp9"
+)
+cpack_add_component(default_family
+ DISPLAY_NAME "Default SIMH simulator family."
+ DESCRIPTION "The SIMH simulator collection of historical processors and computing systems that do not belong to
+any other simulated system family. Simulators: altair, besm6, ssem, tt2500, tx-0"
+)
+cpack_add_component(dgnova_family
+ DISPLAY_NAME "DG Nova and Eclipse"
+ DESCRIPTION "Data General NOVA and Eclipse system simulators. Simulators: eclipse, nova"
+)
+cpack_add_component(experimental
+ DISPLAY_NAME "Experimental (work-in-progress) simulators"
+ DESCRIPTION "Experimental or work-in-progress simulators not in the SIMH mainline simulator suite. Simulators: alpha, pdq3, sage"
+)
+cpack_add_component(gould_family
+ DISPLAY_NAME "Gould simulators"
+ DESCRIPTION "Gould Systems simulators. Simulators: sel32"
+)
+cpack_add_component(grisys_family
+ DISPLAY_NAME "GRI Systems GRI-909"
+ DESCRIPTION "GRI Systems GRI-909 system simulator. Simulators: gri"
+)
+cpack_add_component(honeywell_family
+ DISPLAY_NAME "Honeywell H316"
+ DESCRIPTION "Honeywell H-316 system simulator. Simulators: h316"
+)
+cpack_add_component(hp_family
+ DISPLAY_NAME "HP 2100, 3000"
+ DESCRIPTION "Hewlett-Packard H2100 and H3000 simulators. Simulators: hp2100, hp3000"
+)
+cpack_add_component(ibm_family
+ DISPLAY_NAME "IBM"
+ DESCRIPTION "IBM system simulators: i650. Simulators: i1401, i1620, i650, i701, i7010, i704, i7070, i7080, i7090, i7094, ibm1130, s3"
+)
+cpack_add_component(imlac_family
+ DISPLAY_NAME "IMLAC"
+ DESCRIPTION "IMLAC system simulators. Simulators: imlac"
+)
+cpack_add_component(intel_family
+ DISPLAY_NAME "Intel"
+ DESCRIPTION "Intel system simulators. Simulators: intel-mds, scelbi"
+)
+cpack_add_component(interdata_family
+ DISPLAY_NAME "Interdata"
+ DESCRIPTION "Interdata systems simulators. Simulators: id16, id32"
+)
+cpack_add_component(lgp_family
+ DISPLAY_NAME "LGP"
+ DESCRIPTION "Librascope systems. Simulators: lgp"
+)
+cpack_add_component(norsk_family
+ DISPLAY_NAME "ND simulators"
+ DESCRIPTION "Norsk Data systems simulator family. Simulators: nd100"
+)
+cpack_add_component(pdp10_family
+ DISPLAY_NAME "DEC PDP-10 collection"
+ DESCRIPTION "DEC PDP-10 architecture simulators and variants. Simulators: pdp10, pdp10-ka, pdp10-ki, pdp10-kl, pdp10-ks"
+)
+cpack_add_component(pdp11_family
+ DISPLAY_NAME "DEC PDP-11 collection."
+ DESCRIPTION "DEC PDP-11 and PDP-11-derived architecture simulators. Simulators: pdp11, uc15"
+)
+cpack_add_component(sds_family
+ DISPLAY_NAME "SDS simulators"
+ DESCRIPTION "Scientific Data Systems (SDS) systems. Simulators: sds, sigma"
+)
+cpack_add_component(swtp_family
+ DISPLAY_NAME "SWTP simulators"
+ DESCRIPTION "Southwest Technical Products (SWTP) system simulators. Simulators: swtp6800mp-a, swtp6800mp-a2, swtp6809mp-09"
+)
+cpack_add_component(vax_family
+ DISPLAY_NAME "DEC VAX simulator collection"
+ DESCRIPTION "The Digital Equipment Corporation VAX (plural: VAXen) simulator family. Simulators: infoserver100, infoserver1000, infoserver150vxt, microvax1, microvax2, microvax2000, microvax3100, microvax3100e, microvax3100m80, rtvax1000, vax, vax730, vax750, vax780, vax8200, vax8600, vaxstation3100m30, vaxstation3100m38, vaxstation3100m76, vaxstation4000m60, vaxstation4000vlc"
+)
diff --git a/cmake/simh-simulators.cmake b/cmake/simh-simulators.cmake
index bd456fa5e..ba2d2a839 100644
--- a/cmake/simh-simulators.cmake
+++ b/cmake/simh-simulators.cmake
@@ -1,123 +1,126 @@
-##
-## This is an automagically generated file. Do NOT EDIT.
-## Any changes you make will be overwritten!!
-##
-## Make changes to the SIMH top-level makefile and then run the
-## "cmake/generate.py" script to regenerate these files.
-##
-## cd cmake; python -m generate --help
-##
-## ------------------------------------------------------------
-set(ALPHAD "${CMAKE_SOURCE_DIR}/alpha")
-set(ALTAIRD "${CMAKE_SOURCE_DIR}/ALTAIR")
-set(ALTAIRZ80D "${CMAKE_SOURCE_DIR}/AltairZ80")
-set(ATT3B2D "${CMAKE_SOURCE_DIR}/3B2")
-set(B5500D "${CMAKE_SOURCE_DIR}/B5500")
-set(BESM6D "${CMAKE_SOURCE_DIR}/BESM6")
-set(CDC1700D "${CMAKE_SOURCE_DIR}/CDC1700")
-set(GRID "${CMAKE_SOURCE_DIR}/GRI")
-set(H316D "${CMAKE_SOURCE_DIR}/H316")
-set(HP2100D "${CMAKE_SOURCE_DIR}/HP2100")
-set(HP3000D "${CMAKE_SOURCE_DIR}/HP3000")
-set(I1401D "${CMAKE_SOURCE_DIR}/I1401")
-set(I1620D "${CMAKE_SOURCE_DIR}/I1620")
-set(I650D "${CMAKE_SOURCE_DIR}/I650")
-set(I7000D "${CMAKE_SOURCE_DIR}/I7000")
-set(I7010D "${CMAKE_SOURCE_DIR}/I7000")
-set(I7094D "${CMAKE_SOURCE_DIR}/I7094")
-set(IBM1130D "${CMAKE_SOURCE_DIR}/Ibm1130")
-set(ID16D "${CMAKE_SOURCE_DIR}/Interdata")
-set(ID32D "${CMAKE_SOURCE_DIR}/Interdata")
-set(IMLACD "${CMAKE_SOURCE_DIR}/imlac")
-set(INTELSYSC "${CMAKE_SOURCE_DIR}/Intel-Systems/common")
-set(KA10D "${CMAKE_SOURCE_DIR}/PDP10")
-set(KI10D "${CMAKE_SOURCE_DIR}/PDP10")
-set(KL10D "${CMAKE_SOURCE_DIR}/PDP10")
-set(KS10D "${CMAKE_SOURCE_DIR}/PDP10")
-set(LGPD "${CMAKE_SOURCE_DIR}/LGP")
-set(ND100D "${CMAKE_SOURCE_DIR}/ND100")
-set(NOVAD "${CMAKE_SOURCE_DIR}/NOVA")
-set(PDP10D "${CMAKE_SOURCE_DIR}/PDP10")
-set(PDP11D "${CMAKE_SOURCE_DIR}/PDP11")
-set(PDP18BD "${CMAKE_SOURCE_DIR}/PDP18B")
-set(PDP1D "${CMAKE_SOURCE_DIR}/PDP1")
-set(PDP6D "${CMAKE_SOURCE_DIR}/PDP10")
-set(PDP8D "${CMAKE_SOURCE_DIR}/PDP8")
-set(PDQ3D "${CMAKE_SOURCE_DIR}/PDQ-3")
-set(S3D "${CMAKE_SOURCE_DIR}/S3")
-set(SAGED "${CMAKE_SOURCE_DIR}/SAGE")
-set(SDSD "${CMAKE_SOURCE_DIR}/SDS")
-set(SEL32D "${CMAKE_SOURCE_DIR}/SEL32")
-set(SIGMAD "${CMAKE_SOURCE_DIR}/sigma")
-set(SSEMD "${CMAKE_SOURCE_DIR}/SSEM")
-set(SWTP6800C "${CMAKE_SOURCE_DIR}/swtp6800/common")
-set(SWTP6800D "${CMAKE_SOURCE_DIR}/swtp6800/swtp6800")
-set(TT2500D "${CMAKE_SOURCE_DIR}/tt2500")
-set(TX0D "${CMAKE_SOURCE_DIR}/TX-0")
-set(UC15D "${CMAKE_SOURCE_DIR}/PDP11")
-set(VAXD "${CMAKE_SOURCE_DIR}/VAX")
-
-set(DISPLAYD "${CMAKE_SOURCE_DIR}/display")
-set(DISPLAY340 "${DISPLAYD}/type340.c")
-set(DISPLAYIII "${DISPLAYD}/iii.c")
-set(DISPLAYNG "${DISPLAYD}/ng.c")
-set(DISPLAYVT "${DISPLAYD}/vt11.c")
-
-set(INTELSYSD "${CMAKE_SOURCE_DIR}/Intel-Systems")
-set(INTEL_MDSD "${INTELSYSD}/Intel-MDS")
-set(SCELBIC "${INTELSYSD}/common")
-set(SCELBID "${INTELSYSD}/scelbi")
-
-## ----------------------------------------
-
-if (NOT WITH_VIDEO)
- ### Hack: Unset these variables so that they don't expand if
- ### not building with video:
- set(DISPLAY340 "")
- set(DISPLAYIII "")
- set(DISPLAYNG "")
- set(DISPLAYVT "")
-endif ()
-
-## ----------------------------------------
-
-add_subdirectory(3B2)
-add_subdirectory(ALTAIR)
-add_subdirectory(AltairZ80)
-add_subdirectory(B5500)
-add_subdirectory(BESM6)
-add_subdirectory(CDC1700)
-add_subdirectory(GRI)
-add_subdirectory(H316)
-add_subdirectory(HP2100)
-add_subdirectory(HP3000)
-add_subdirectory(I1401)
-add_subdirectory(I1620)
-add_subdirectory(I650)
-add_subdirectory(I7000)
-add_subdirectory(I7094)
-add_subdirectory(Ibm1130)
-add_subdirectory(Intel-Systems/Intel-MDS)
-add_subdirectory(Intel-Systems/scelbi)
-add_subdirectory(Interdata)
-add_subdirectory(LGP)
-add_subdirectory(ND100)
-add_subdirectory(NOVA)
-add_subdirectory(PDP1)
-add_subdirectory(PDP10)
-add_subdirectory(PDP11)
-add_subdirectory(PDP18B)
-add_subdirectory(PDP8)
-add_subdirectory(PDQ-3)
-add_subdirectory(S3)
-add_subdirectory(SAGE)
-add_subdirectory(SDS)
-add_subdirectory(SEL32)
-add_subdirectory(SSEM)
-add_subdirectory(TX-0)
-add_subdirectory(VAX)
-add_subdirectory(alpha)
-add_subdirectory(imlac)
-add_subdirectory(sigma)
-add_subdirectory(swtp6800/swtp6800)
-add_subdirectory(tt2500)
+##
+## This is an automagically generated file. Do NOT EDIT.
+## Any changes you make will be overwritten!!
+##
+## Make changes to the SIMH top-level makefile and then run the
+## "cmake/generate.py" script to regenerate these files.
+##
+## cd cmake; python -m generate --help
+##
+## ------------------------------------------------------------
+set(ALPHAD "${CMAKE_SOURCE_DIR}/alpha")
+set(ALTAIRD "${CMAKE_SOURCE_DIR}/ALTAIR")
+set(ALTAIRZ80D "${CMAKE_SOURCE_DIR}/AltairZ80")
+set(ATT3B2D "${CMAKE_SOURCE_DIR}/3B2")
+set(B5500D "${CMAKE_SOURCE_DIR}/B5500")
+set(BESM6D "${CMAKE_SOURCE_DIR}/BESM6")
+set(CDC1700D "${CMAKE_SOURCE_DIR}/CDC1700")
+set(GRID "${CMAKE_SOURCE_DIR}/GRI")
+set(H316D "${CMAKE_SOURCE_DIR}/H316")
+set(HP2100D "${CMAKE_SOURCE_DIR}/HP2100")
+set(HP3000D "${CMAKE_SOURCE_DIR}/HP3000")
+set(I1401D "${CMAKE_SOURCE_DIR}/I1401")
+set(I1620D "${CMAKE_SOURCE_DIR}/I1620")
+set(I650D "${CMAKE_SOURCE_DIR}/I650")
+set(I7000D "${CMAKE_SOURCE_DIR}/I7000")
+set(I7010D "${CMAKE_SOURCE_DIR}/I7000")
+set(I7094D "${CMAKE_SOURCE_DIR}/I7094")
+set(IBM1130D "${CMAKE_SOURCE_DIR}/Ibm1130")
+set(ID16D "${CMAKE_SOURCE_DIR}/Interdata")
+set(ID32D "${CMAKE_SOURCE_DIR}/Interdata")
+set(IMLACD "${CMAKE_SOURCE_DIR}/imlac")
+set(INTELSYSC "${CMAKE_SOURCE_DIR}/Intel-Systems/common")
+set(KA10D "${CMAKE_SOURCE_DIR}/PDP10")
+set(KI10D "${CMAKE_SOURCE_DIR}/PDP10")
+set(KL10D "${CMAKE_SOURCE_DIR}/PDP10")
+set(KS10D "${CMAKE_SOURCE_DIR}/PDP10")
+set(LGPD "${CMAKE_SOURCE_DIR}/LGP")
+set(ND100D "${CMAKE_SOURCE_DIR}/ND100")
+set(NOVAD "${CMAKE_SOURCE_DIR}/NOVA")
+set(PDP10D "${CMAKE_SOURCE_DIR}/PDP10")
+set(PDP11D "${CMAKE_SOURCE_DIR}/PDP11")
+set(PDP18BD "${CMAKE_SOURCE_DIR}/PDP18B")
+set(PDP1D "${CMAKE_SOURCE_DIR}/PDP1")
+set(PDP6D "${CMAKE_SOURCE_DIR}/PDP10")
+set(PDP8D "${CMAKE_SOURCE_DIR}/PDP8")
+set(PDQ3D "${CMAKE_SOURCE_DIR}/PDQ-3")
+set(S3D "${CMAKE_SOURCE_DIR}/S3")
+set(SAGED "${CMAKE_SOURCE_DIR}/SAGE")
+set(SDSD "${CMAKE_SOURCE_DIR}/SDS")
+set(SEL32D "${CMAKE_SOURCE_DIR}/SEL32")
+set(SIGMAD "${CMAKE_SOURCE_DIR}/sigma")
+set(SSEMD "${CMAKE_SOURCE_DIR}/SSEM")
+set(SWTP6800C "${CMAKE_SOURCE_DIR}/swtp6800/common")
+set(SWTP6800D "${CMAKE_SOURCE_DIR}/swtp6800/swtp6800")
+set(SWTP6809C "${CMAKE_SOURCE_DIR}/swtp6809/common")
+set(SWTP6809D "${CMAKE_SOURCE_DIR}/swtp6809/swtp6809")
+set(TT2500D "${CMAKE_SOURCE_DIR}/tt2500")
+set(TX0D "${CMAKE_SOURCE_DIR}/TX-0")
+set(UC15D "${CMAKE_SOURCE_DIR}/PDP11")
+set(VAXD "${CMAKE_SOURCE_DIR}/VAX")
+
+set(DISPLAYD "${CMAKE_SOURCE_DIR}/display")
+set(DISPLAY340 "${DISPLAYD}/type340.c")
+set(DISPLAYIII "${DISPLAYD}/iii.c")
+set(DISPLAYNG "${DISPLAYD}/ng.c")
+set(DISPLAYVT "${DISPLAYD}/vt11.c")
+
+set(INTELSYSD "${CMAKE_SOURCE_DIR}/Intel-Systems")
+set(INTEL_MDSD "${INTELSYSD}/Intel-MDS")
+set(SCELBIC "${INTELSYSD}/common")
+set(SCELBID "${INTELSYSD}/scelbi")
+
+## ----------------------------------------
+
+if (NOT WITH_VIDEO)
+ ### Hack: Unset these variables so that they don't expand if
+ ### not building with video:
+ set(DISPLAY340 "")
+ set(DISPLAYIII "")
+ set(DISPLAYNG "")
+ set(DISPLAYVT "")
+endif ()
+
+## ----------------------------------------
+
+add_subdirectory(3B2)
+add_subdirectory(ALTAIR)
+add_subdirectory(AltairZ80)
+add_subdirectory(B5500)
+add_subdirectory(BESM6)
+add_subdirectory(CDC1700)
+add_subdirectory(GRI)
+add_subdirectory(H316)
+add_subdirectory(HP2100)
+add_subdirectory(HP3000)
+add_subdirectory(I1401)
+add_subdirectory(I1620)
+add_subdirectory(I650)
+add_subdirectory(I7000)
+add_subdirectory(I7094)
+add_subdirectory(Ibm1130)
+add_subdirectory(Intel-Systems/Intel-MDS)
+add_subdirectory(Intel-Systems/scelbi)
+add_subdirectory(Interdata)
+add_subdirectory(LGP)
+add_subdirectory(ND100)
+add_subdirectory(NOVA)
+add_subdirectory(PDP1)
+add_subdirectory(PDP10)
+add_subdirectory(PDP11)
+add_subdirectory(PDP18B)
+add_subdirectory(PDP8)
+add_subdirectory(PDQ-3)
+add_subdirectory(S3)
+add_subdirectory(SAGE)
+add_subdirectory(SDS)
+add_subdirectory(SEL32)
+add_subdirectory(SSEM)
+add_subdirectory(TX-0)
+add_subdirectory(VAX)
+add_subdirectory(alpha)
+add_subdirectory(imlac)
+add_subdirectory(sigma)
+add_subdirectory(swtp6800/swtp6800)
+add_subdirectory(swtp6809/swtp6809)
+add_subdirectory(tt2500)
diff --git a/doc/swtp6809_doc.doc b/doc/swtp6809_doc.doc
new file mode 100644
index 000000000..05b1b7c5a
Binary files /dev/null and b/doc/swtp6809_doc.doc differ
diff --git a/makefile b/makefile
index 1167f83aa..31b667bc0 100644
--- a/makefile
+++ b/makefile
@@ -1957,6 +1957,15 @@ SWTP6800MP-A2 = ${SWTP6800C}/mp-a2.c ${SWTP6800C}/m6800.c ${SWTP6800C}/m6810.c \
${SWTP6800C}/mp-s.c ${SWTP6800C}/mp-b2.c
SWTP6800_OPT = -I ${SWTP6800D}
+
+SWTP6809D = ${SIMHD}/swtp6809/swtp6809
+SWTP6809C = ${SIMHD}/swtp6809/common
+SWTP6809MP-09 = ${SWTP6809C}/mp-09.c ${SWTP6809C}/m6809.c \
+ ${SWTP6809C}/bootrom.c ${SWTP6809C}/dc-4.c ${SWTP6809D}/mp-09_sys.c \
+ ${SWTP6809C}/mp-1m.c ${SWTP6809C}/mp-b3.c \
+ ${SWTP6809C}/mp-s.c
+SWTP6809_OPT = -I ${SWTP6809D}
+
INTELSYSD = ${SIMHD}/Intel-Systems
INTELSYSC = ${SIMHD}/Intel-Systems/common
@@ -2207,7 +2216,7 @@ ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \
microvax3100m80 vaxstation4000vlc infoserver1000 \
nd100 nova eclipse hp2100 hp3000 i1401 i1620 s3 altair altairz80 gri \
i7094 ibm1130 id16 id32 sds lgp h316 cdc1700 \
- swtp6800mp-a swtp6800mp-a2 tx-0 ssem b5500 intel-mds \
+ swtp6800mp-a swtp6800mp-a2 swtp6809mp-09 tx-0 ssem b5500 intel-mds \
scelbi 3b2 3b2-700 i701 i704 i7010 i7070 i7080 i7090 \
sigma uc15 pdp10-ka pdp10-ki pdp10-kl pdp10-ks pdp6 i650 \
imlac tt2500 sel32
@@ -2745,6 +2754,15 @@ ifneq (,$(call find_test,${SWTP6800D},swtp6800mp-a2))
$@ $(call find_test,${SWTP6800D},swtp6800mp-a2) ${TEST_ARG}
endif
+swtp6809mp-09 : ${BIN}swtp6809mp-09${EXE}
+
+${BIN}swtp6809mp-09${EXE} : ${SWTP6809MP-09} ${SIM} ${BUILD_ROMS}
+ ${MKDIRBIN}
+ ${CC} ${SWTP6809MP-09} ${SIM} ${SWTP6809_OPT} ${CC_OUTSPEC} ${LDFLAGS}
+ifneq (,$(call find_test,${SWTP6809D},swtp6809mp-09))
+ $@ $(call find_test,${SWTP6809D},swtp6809mp-09) ${TEST_ARG}
+endif
+
intel-mds: ${BIN}intel-mds${EXE}
${BIN}intel-mds${EXE} : ${INTEL_MDS} ${SIM} ${BUILD_ROMS}
diff --git a/swtp6809/common/bootrom.c b/swtp6809/common/bootrom.c
new file mode 100644
index 000000000..47a0dda1c
--- /dev/null
+++ b/swtp6809/common/bootrom.c
@@ -0,0 +1,346 @@
+/* bootrom.c: Boot ROM simulator for Motorola processors
+
+ Copyright (c) 2010-2012, William A. Beech
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of William A. Beech shall not be
+ used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from William A. Beech.
+
+ The following copyright notice applies to the SWTP 6809 source, binary, and documentation:
+
+ Original code published in 2024, written by Richard F Lukes
+ Copyright (c) 2024, Richard F Lukes
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the names of The Authors shall not be
+ used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from the Authors.
+
+ MODIFICATIONS:
+
+ 23 Apr 15 -- Modified to use simh_debug
+ 04 Apr 24 -- Richard Lukes - Modified for swtp6809 emulator
+
+ NOTES:
+
+ These functions support a single simulated 2704 to 2764 EPROM device on
+ an 8-bit computer system.. This device allows the buffer to be loaded from
+ a binary file containing the emulated EPROM code.
+
+ These functions support a simulated 2704(0.5KB), 2708(1KB), 2716(2KB), 2732(4KB) or 2764(8KB) EPROM
+ device at the top of the 16-bit address space. The base address of the ROM varies depends on the size.
+ For example, The 2764 BOOTROM is mapped from $E000 to $FFFF less the I/O range reserved by the MP-B3 motherboard.
+ The 2716 BOOTROM is mapped from $F800 to $FFFF.
+ The last byte of the ROM is always stored at $FFFF
+
+ The device type is stored as a binary number in the first three unit flag bits.
+
+ This device uses a statically allocated buffer to hold the EPROM image. All bytes are initialized to $FF.
+ A call to BOOTROM_attach will load the buffer with the EPROM image.
+
+*/
+
+#include
+#include "swtp_defs.h"
+
+#define UNIT_V_MSIZE (UNIT_V_UF + 0) /* ROM Size */
+#define UNIT_MSIZE (0x2F << UNIT_V_MSIZE)
+#define UNIT_NONE (0 << UNIT_V_MSIZE) /* No EPROM */
+#define UNIT_2704 (1 << UNIT_V_MSIZE) /* 2704 mode */
+#define UNIT_2708 (2 << UNIT_V_MSIZE) /* 2708 mode */
+#define UNIT_2716 (3 << UNIT_V_MSIZE) /* 2716 mode */
+#define UNIT_2732 (4 << UNIT_V_MSIZE) /* 2732 mode */
+#define UNIT_2764 (5 << UNIT_V_MSIZE) /* 2764 mode */
+
+/* Maximum size of bootrom is 8KB from $E000-$FFFF */
+#define MAX_BOOTROM_SIZE (8*1024)
+
+// this value is used when referencing BOOTROM memory that is not populated (i.e. not loaded by BOOTROM attach)
+#define DEFAULT_NO_ROM_BYTE_VALUE 0xFF
+
+/* function prototypes */
+
+t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr);
+t_stat BOOTROM_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches);
+t_stat BOOTROM_reset(DEVICE *dptr);
+
+int32 BOOTROM_get_mbyte(int32 address);
+
+/* SIMH Standard I/O Data Structures */
+
+UNIT BOOTROM_unit = {
+ UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0),
+ KBD_POLL_WAIT };
+
+MTAB BOOTROM_mod[] = {
+ { UNIT_MSIZE, UNIT_NONE, "NONE", "NONE", &BOOTROM_config },
+ { UNIT_MSIZE, UNIT_2704, "2704", "2704", &BOOTROM_config },
+ { UNIT_MSIZE, UNIT_2708, "2708", "2708", &BOOTROM_config },
+ { UNIT_MSIZE, UNIT_2716, "2716", "2716", &BOOTROM_config },
+ { UNIT_MSIZE, UNIT_2732, "2732", "2732", &BOOTROM_config },
+ { UNIT_MSIZE, UNIT_2764, "2764", "2764", &BOOTROM_config },
+ { 0 }
+};
+
+DEBTAB BOOTROM_debug[] = {
+ { "ALL", DEBUG_all, "Debug all"},
+ { "FLOW", DEBUG_flow, "Debug flow of control" },
+ { "READ", DEBUG_read, "Debug device reads" },
+ { "WRITE", DEBUG_write, "Debug device writes" },
+ { "LEV1", DEBUG_level1, "Debug level 1" },
+ { "LEV2", DEBUG_level2, "Debug level 2" },
+ { NULL }
+};
+
+DEVICE BOOTROM_dev = {
+ "BOOTROM", /* name */
+ &BOOTROM_unit, /* units */
+ NULL, /* registers */
+ BOOTROM_mod, /* modifiers */
+ 1, /* numunits */
+ 16, /* aradix */
+ 16, /* awidth */
+ 1, /* aincr */
+ 16, /* dradix */
+ 8, /* dwidth */
+ &BOOTROM_examine, /* examine */
+ NULL, /* deposit */
+ &BOOTROM_reset, /* reset */
+ NULL, /* boot */
+ &BOOTROM_attach, /* attach */
+ NULL, /* detach */
+ NULL, /* ctxt */
+ DEV_DEBUG, /* flags */
+ 0, /* dctrl */
+ BOOTROM_debug, /* debflags */
+ NULL, /* msize */
+ NULL, /* help */
+ NULL, /* attach help */
+ NULL, /* help context */
+ NULL /* device description */
+};
+
+/* global variables */
+
+/* MP-09 actually has 4 x 2KB EPROM sockets at $E000, $E800, $F000, $F800 */
+/* This will be emulated as a single BOOTROM having a high address of $FFFF and variable start address depending on size */
+/* Available sizes are None=0, 512B=2704, 1KB=2708, 2KB=2716, 4KB=2732, 8KB=2764 */
+
+/* Pre-allocate 8KB array of bytes to accomodate largest BOOTROM */
+uint8 BOOTROM_memory[MAX_BOOTROM_SIZE];
+
+/* BOOTROM_examine routine */
+t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches)
+{
+ sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_examine: addr=%08x\n", addr);
+
+ if (addr >= uptr->capac || addr >= MAX_BOOTROM_SIZE) {
+ return SCPE_NXM;
+ }
+ if (eval_array != NULL) {
+ *eval_array = BOOTROM_memory[addr];
+ }
+ return SCPE_OK;
+
+} /* BOOTROM_examine() */
+
+/* BOOTROM_attach - attach file to EPROM unit */
+t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr)
+{
+ t_stat r;
+ t_addr image_size;
+ int i,j;
+ FILE *fp;
+ uint8 byte_val;
+ size_t items_read;
+
+ if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */
+ BOOTROM_unit.filebuf = BOOTROM_memory;
+ }
+ if ((BOOTROM_unit.flags & UNIT_MSIZE) == 0) { /* if none selected */
+ BOOTROM_unit.capac = 0; /* set EPROM size to 0 */
+ return SCPE_OK;
+ }
+
+ sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: cptr=%s\n", cptr);
+ if ((r = attach_unit(uptr, cptr)) != SCPE_OK) {
+ sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Error %d\n", r);
+ return r;
+ }
+
+ image_size = (t_addr) sim_fsize_ex(uptr->fileref);
+ if (image_size <= 0) {
+ sim_printf("BOOTROM_attach: File error\n");
+ detach_unit(uptr);
+ return SCPE_IOERR;
+ } else {
+ if (image_size > MAX_BOOTROM_SIZE) {
+ sim_printf("BOOTROM_attach: Error. File size exceeds ROM capacity\n");
+ detach_unit(uptr);
+ return SCPE_ARG;
+ }
+ }
+
+ /* open EPROM file */
+ fp = fopen(BOOTROM_unit.filename, "rb");
+ if (fp == NULL) {
+ printf("Bootrom: Unable to open ROM file %s\n",BOOTROM_unit.filename);
+ printf("Bootrom: No ROM image loaded!!!\n");
+ return SCPE_OK;
+ }
+
+ /* load EPROM file */
+ j = 0;
+ items_read = sim_fread(&byte_val, (size_t)1, (size_t)1, fp);
+ while (items_read != 0) {
+ BOOTROM_memory[j++] = byte_val;
+ items_read = sim_fread(&byte_val, (size_t)1, (size_t)1,fp);
+ if (j > BOOTROM_unit.capac) {
+ printf("Bootrom: Image is too large - Load truncated!!!\n");
+ j--;
+ break;
+ }
+ }
+ fclose(fp);
+ printf("Bootrom: %d bytes of ROM image %s loaded\n", j, BOOTROM_unit.filename);
+
+ sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Done\n");
+ return SCPE_OK;
+
+} /* BOOTROM_attach() */
+
+/* BOOTROM_config = None, 2704, 2708, 2716, 2732 or 2764 */
+t_stat BOOTROM_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
+{
+
+ sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: val=%d\n", val);
+ if ((val < UNIT_NONE) || (val > UNIT_2764)) { /* valid param? */
+ sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Parameter error\n");
+ return SCPE_ARG;
+ }
+ if (val == UNIT_NONE) {
+ BOOTROM_unit.capac = 0; /* set EPROM size */
+ } else {
+ BOOTROM_unit.capac = 0x100 << (val >> UNIT_V_MSIZE); /* set EPROM size */
+ }
+
+ if (!BOOTROM_unit.filebuf) { /* point buffer to static array */
+ BOOTROM_unit.filebuf = BOOTROM_memory;
+ }
+
+ sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: BOOTROM_unit.capac=%d\n", BOOTROM_unit.capac);
+ sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Done\n");
+
+ return SCPE_OK;
+} /* BOOTROM config */
+
+/* BOOTROM reset */
+t_stat BOOTROM_reset (DEVICE *dptr)
+{
+ t_addr i;
+
+ sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_reset: \n");
+
+ /* allocate filebuf */
+ if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */
+ //BOOTROM_unit.filebuf = calloc(1, BOOTROM_unit.capac); /* allocate EPROM buffer */
+ BOOTROM_unit.filebuf = BOOTROM_memory;
+ if (BOOTROM_unit.filebuf == NULL) {
+ return SCPE_MEM;
+ }
+ }
+ return SCPE_OK;
+
+} /* BOOTROM_reset() */
+
+/* get a byte from memory - from specified memory address */
+int32 BOOTROM_get_mbyte(int32 address)
+{
+ int32 val;
+ uint8 *pa;
+
+ if (BOOTROM_unit.filebuf == NULL) {
+ sim_debug(DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM not configured\n");
+ return DEFAULT_NO_ROM_BYTE_VALUE;
+ }
+ sim_debug(DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: address=%04X\n", address);
+ if ((t_addr)(0xFFFF - address) > BOOTROM_unit.capac) {
+ sim_debug(DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM reference beyond ROM size\n");
+ return DEFAULT_NO_ROM_BYTE_VALUE;
+ }
+
+ pa = BOOTROM_unit.filebuf;
+ /* the following code is needed to calculate offsets so address $FFFF references the last byte of the ROM */
+ val = DEFAULT_NO_ROM_BYTE_VALUE;
+ switch (BOOTROM_unit.capac) {
+ /* 2764 - $E000-$FFFF */
+ case 0x2000:
+ val = pa[address - 0xE000];
+ break;
+ /* 2732 - $F000-$FFFF */
+ case 0x1000:
+ if (address >=0xF000) {
+ val = pa[address - 0xF000];
+ }
+ break;
+ /* 2716 - $F800-$FFFF */
+ case 0x0800:
+ if (address >= 0xF800) {
+ val = pa[address - 0xF800];
+ }
+ break;
+ /* 2708 - $FC00-$FFFF */
+ case 0x0400:
+ if (address >= 0xFC00) {
+ val = pa[address - 0xFC00];
+ }
+ break;
+ /* 2704 - $FE00-$FFFF*/
+ case 0x0200:
+ if (address >= 0xFE00) {
+ val = pa[address - 0xFE00];
+ }
+ break;
+ default:
+ break;
+ }
+ val &= 0xFF;
+ sim_debug(DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: Normal val=%02X\n", val);
+ return val;
+} /* BOOTROM_get_mbyte() */
+
+/* end of bootrom.c */
diff --git a/swtp6809/common/dc-4.c b/swtp6809/common/dc-4.c
new file mode 100644
index 000000000..1b02789ad
--- /dev/null
+++ b/swtp6809/common/dc-4.c
@@ -0,0 +1,956 @@
+/* dc4.c: SWTP DC-4 FDC Simulator
+
+ Copyright (c) 2005-2012, William A. Beech
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ WILLIAM A BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of William A. Beech shall not
+ be used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from William A. Beech.
+
+ MODIFICATIONS:
+
+ 23 Apr 15 -- Modified to use simh_debug
+ 04 Apr 24 -- Richard Lukes - Modified to work with swtp6809 emulator
+
+ NOTES:
+
+ The DC-4 is a 5-inch floppy controller which can control up
+ to 4 daisy-chained 5-inch floppy drives. The controller is based on
+ the Western Digital 1797 Floppy Disk Controller (FDC) chip. This
+ file only emulates the minimum DC-4 functionality to interface with
+ the virtual disk file.
+
+ The floppy controller is interfaced to the CPU by use of 5 memory addreses.
+ These are SS-30 slot numbers 5 and 6 (0xE014-0xE01B) on a SWTPC 6809 computer.
+ These are SS-30 slot numbers 5 and 6 (0x8014-0x801B) on a SWTPC 6800 computer.
+
+ Address Mode Function
+ ------- ---- --------
+
+ 0xE014 Read Returns FDC interrupt status
+ 0xE014 Write Selects the drive/head/motor control
+ 0xE018 Read Returns status of FDC
+ 0xE018 Write FDC command register
+ 0xE019 Read Returns FDC track register
+ 0xE019 Write Set FDC track register
+ 0xE01A Read Returns FDC sector register
+ 0xE01A Write Set FDC sector register
+ 0xE01B Read Read data
+ 0xE01B Write Write data
+
+ Drive Select Read (0xE014):
+
+ +---+---+---+---+---+---+----+----+
+ | I | D | X | X | X | X | d1 | d0 |
+ +---+---+---+---+---+---+----+----+
+
+ I = Set indicates an interrupt request from the FDC pending.
+ D = DRQ pending - same as bit 1 of FDC status register.
+ d1,d0 = current drive selected
+
+ Drive Select Write (0xE014):
+
+ +---+---+---+---+---+---+---+---+
+ | M | S | X | X | X | X | Device|
+ +---+---+---+---+---+---+---+---+
+
+ M = If this bit is 1, the one-shot is triggered/retriggered to
+ start/keep the motors on.
+ S = Side select. If set, side one is selected otherwise side zero
+ is selected.
+ X = not used
+ Device = value 0 thru 3, selects drive 0-3 to be controlled.
+
+ Drive Status Read (0xE018):
+
+ +---+---+---+---+---+---+---+---+
+ | R | P | H | S | C | L | D | B |
+ +---+---+---+---+---+---+---+---+
+
+ B - When 1, the controller is busy.
+ D - When 1, index mark detected (type I) or data request - read data
+ ready/write data empty (type II or III).
+ H - When 1, track 0 (type I) or lost data (type II or III).
+ C - When 1, crc error detected.
+ S - When 1, seek (type I) or RNF (type II or III) error.
+ H - When 1, head is currently loaded (type I) or record type/
+ write fault (type II or III).
+ P - When 1, indicates that diskette is write-protected.
+ R - When 1, drive is not ready.
+
+ Drive Control Write (0xE018) for type I commands:
+
+ +---+---+---+---+---+---+---+---+
+ | 0 | S2| S1| S0| H | V | R1| R0|
+ +---+---+---+---+---+---+---+---+
+
+ R0/R1 - Selects the step rate.
+ V - When 1, verify on destination track.
+ H - When 1, loads head to drive surface.
+ S0/S1/S2 = 000 - home.
+ 001 - seek track in data register.
+ 010 - step without updating track register.
+ 011 - step and update track register.
+ 100 - step in without updating track register.
+ 101 - step in and update track register.
+ 110 - step out without updating track register.
+ 111 - step out and update track register.
+
+ Drive Control Write (0xE018) for type II commands:
+
+ +---+---+---+---+---+---+---+---+
+ | 1 | 0 | T | M | S | E | B | A |
+ +---+---+---+---+---+---+---+---+
+
+ A - Zero for read, 1 on write deleted data mark else data mark.
+ B - When 1, shifts sector length field definitions one place.
+ E - When, delay operation 15 ms, 0 no delay.
+ S - When 1, select side 1, 0 select side 0.
+ M - When 1, multiple records, 0 for single record.
+ T - When 1, write command, 0 for read.
+
+ Drive Control Write (0xE018) for type III commands:
+
+ +---+---+---+---+---+---+---+---+
+ | 1 | 1 | T0| T1| 0 | E | 0 | 0 |
+ +---+---+---+---+---+---+---+---+
+
+ E - When, delay operation 15 ms, 0 no delay.
+ T0/T1 - 00 - read address command.
+ 10 - read track command.
+ 11 - write track command.
+
+ Tracks are numbered from 0 up to one minus the last track in the 1797!
+
+ Track Register Read (0xE019):
+
+ +---+---+---+---+---+---+---+---+
+ | Track Number |
+ +---+---+---+---+---+---+---+---+
+
+ Reads the current 8-bit value from the track position.
+
+ Track Register Write (0xE019):
+
+ +---+---+---+---+---+---+---+---+
+ | Track Number |
+ +---+---+---+---+---+---+---+---+
+
+ Writes the 8-bit value to the track register.
+
+ Sectors are numbers from 1 up to the last sector in the 1797!
+
+ Sector Register Read (0xE01A):
+
+ +---+---+---+---+---+---+---+---+
+ | Sector Number |
+ +---+---+---+---+---+---+---+---+
+
+ Reads the current 8-bit value from the sector position.
+
+ Sector Register Write (0xE01A):
+
+ +---+---+---+---+---+---+---+---+
+ | Sector Number |
+ +---+---+---+---+---+---+---+---+
+
+ Writes the 8-bit value to the sector register.
+
+ Data Register Read (0xE01B):
+
+ +---+---+---+---+---+---+---+---+
+ | Data |
+ +---+---+---+---+---+---+---+---+
+
+ Reads the current 8-bit value from the data register.
+
+ Data Register Write (0xE01B):
+
+ +---+---+---+---+---+---+---+---+
+ | Data |
+ +---+---+---+---+---+---+---+---+
+
+ Writes the 8-bit value to the data register.
+
+ A FLEX disk is defined as follows:
+
+ Track Sector Use
+ 0 1 Boot sector
+ 0 2 Boot sector (cont)
+ 0 3 Unused (doesn't exist)
+ 0 4 System Identity Record (explained below)
+ 0 5 Unused
+ 0 6-last Directory - 10 entries/sector (explained below)
+ 1 1 First available data sector
+ last-1 last Last available data sector
+
+ FLEX System Identity Record
+
+ Byte Use
+ 0x00 Two bytes of zeroes (Clears forward link)
+ 0x10 Volume name in ASCII(11 bytes)
+ 0x1B Volume number in binary (2 bytes)
+ 0x1D Address of first free data sector (Track-Sector) (2 bytes)
+ 0x1F Address of last free data sector (Track-Sector) (2 bytes)
+ 0x21 Total number of data sectors in binary (2 bytes)
+ 0x23 Current date (Month-Day-Year) in binary
+ 0x26 Highest track number on disk in binary (byte)
+ 0x27 Highest sector number on a track in binary (byte)
+
+ The following unit registers are used by this controller emulation:
+
+ dsk_unit[cur_drv].pos unit current sector byte index into file
+ dsk_unit[cur_drv].filebuf unit current sector buffer
+ dsk_unit[cur_drv].fileref unit current attached file reference
+ dsk_unit[cur_drv].capac capacity
+ dsk_unit[cur_drv].u3 unit current flags
+ dsk_unit[cur_drv].u4 unit current track
+ dsk_unit[cur_drv].u5 unit current sector
+ dsk_unit[cur_drv].u6 sectors per track
+ dsk_unit[cur_drv].up7 points to "Flex string" or NULL
+ dsk_unit[cur_drv].wait cylinder per disk
+*/
+
+#include
+#include "swtp_defs.h"
+
+/* Unit settings*/
+
+#define UNIT_V_DC4_READONLY (UNIT_V_UF + 0)
+#define UNIT_DC4_READONLY (0x1 << UNIT_V_DC4_READONLY)
+
+#define UNIT_V_DC4_SPT (UNIT_V_UF + 1)
+#define UNIT_DC4_SPT (0xF << UNIT_V_DC4_SPT)
+#define UNIT_DC4_SPT_UNKNOWN (0x1 << UNIT_V_DC4_SPT)
+#define UNIT_DC4_SPT_FLEX_SIR (0x2 << UNIT_V_DC4_SPT)
+#define UNIT_DC4_SPT_10SPT (0x3 << UNIT_V_DC4_SPT)
+#define UNIT_DC4_SPT_20SPT (0x4 << UNIT_V_DC4_SPT)
+#define UNIT_DC4_SPT_30SPT (0x5 << UNIT_V_DC4_SPT)
+#define UNIT_DC4_SPT_36SPT (0x6 << UNIT_V_DC4_SPT)
+#define UNIT_DC4_SPT_72SPT (0x8 << UNIT_V_DC4_SPT)
+#define UNIT_DC4_SPT_255SPT (0x9 << UNIT_V_DC4_SPT)
+
+/* maximum of 4 disks, sector size is fixed at SECTOR_SIZE bytes */
+
+#define NUM_DISK 4 /* standard 1797 maximum */
+#define SECTOR_SIZE 256 /* standard FLEX sector is 256 bytes */
+
+/* Flex OS SIR offsets */
+#define MAXCYL 0x26 /* last cylinder # */
+#define MAXSEC 0x27 /* last sector # */
+
+/* 1797 status bits */
+#define BUSY 0x01
+#define DRQ 0x02
+#define WRPROT 0x40
+#define NOTRDY 0x80
+
+/* drive register status bit */
+#define FDCDRV_INTRQ 0x80
+#define FDCDRV_DRQ 0x40
+#define FDCDRV_D1 0x02
+#define FDCDRV_D0 0x01
+
+/* function prototypes */
+
+t_stat dsk_reset(DEVICE *dptr);
+t_stat dsk_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+t_stat dsk_detach(UNIT *uptr);
+t_stat dsk_attach(UNIT *uptr, CONST char *cptr);
+
+/* SS-50 I/O address space functions */
+
+int32 fdcdrv(int32 io, int32 data);
+int32 fdccmd(int32 io, int32 data);
+int32 fdctrk(int32 io, int32 data);
+int32 fdcsec(int32 io, int32 data);
+int32 fdcdata(int32 io, int32 data);
+
+/* Local Variables */
+
+int32 fdc_data_byte; /* fdc data register */
+
+// this counter is used to emulate write sector VERIFY
+// a write sector VERIFY, re-reads the sector, but
+// only updates the CRC_ERROR and RECORD_NOT_FOUND flags
+// (which don't exist in the emulation)
+int32 read_w_drq_busy_counter = 0; /* if DRQ=1,BUSY=1 then increment counter else zero it. Also zero whenever reading from data register on sector read command */
+
+int32 cur_dsk; /* Currently selected drive */
+int32 prev_dsk; /* previously selected drive */
+
+char flex_flag_str[5] = { 'F', 'L', 'E', 'X', 0 };
+
+/* Floppy Disk Controller data structures
+
+ dsk_dev Mother Board device descriptor
+ dsk_unit Mother Board unit descriptor
+ dsk_reg Mother Board register list
+ dsk_mod Mother Board modifiers list
+*/
+
+UNIT dsk_unit[NUM_DISK] = {
+ //{ UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) },
+ //{ UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) },
+ //{ UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) },
+ //{ UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }
+ { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE, 0) },
+ { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE, 0) },
+ { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE, 0) },
+ { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE, 0) }
+};
+
+REG dsk_reg[] = {
+ { HRDATA (DISK, cur_dsk, 4) },
+ { NULL }
+};
+
+MTAB dsk_mod[] = {
+ { UNIT_DC4_READONLY, UNIT_DC4_READONLY, "RO", "RO", &dsk_config },
+ { UNIT_DC4_READONLY, 0, "RW", "RW", &dsk_config },
+ { UNIT_DC4_SPT, UNIT_DC4_SPT_UNKNOWN, "Unknown sectors per track", "UNKNOWN", &dsk_config },
+ { UNIT_DC4_SPT, UNIT_DC4_SPT_FLEX_SIR, "Read Flex SIR for disk info", "FLEX", &dsk_config },
+ { UNIT_DC4_SPT, UNIT_DC4_SPT_10SPT, "10 sectors per track", "10SPT", &dsk_config },
+ { UNIT_DC4_SPT, UNIT_DC4_SPT_20SPT, "20 sectors per track", "20SPT", &dsk_config },
+ { UNIT_DC4_SPT, UNIT_DC4_SPT_30SPT, "30 sectors per track", "30SPT", &dsk_config },
+ { UNIT_DC4_SPT, UNIT_DC4_SPT_36SPT, "36 sectors per track", "36SPT", &dsk_config },
+ { UNIT_DC4_SPT, UNIT_DC4_SPT_72SPT, "72 sectors per track", "72SPT", &dsk_config },
+ { UNIT_DC4_SPT, UNIT_DC4_SPT_255SPT, "255 sectors per track", "255SPT", &dsk_config },
+ { 0 }
+};
+
+DEBTAB dsk_debug[] = {
+ { "ALL", DEBUG_all, "Debug all" },
+ { "FLOW", DEBUG_flow, "Debug flow of control" },
+ { "READ", DEBUG_read, "Debug device reads" },
+ { "WRITE", DEBUG_write, "Debug device writes" },
+ { "LEV1", DEBUG_level1, "Debug level 1" },
+ { "LEV2", DEBUG_level2, "Debug level 2" },
+ { NULL }
+};
+
+DEVICE dsk_dev = {
+ "DC-4", //name
+ dsk_unit, //units
+ dsk_reg, //registers
+ dsk_mod, //modifiers
+ NUM_DISK, //numunits
+ 16, //aradix
+ 8, //awidth
+ 1, //aincr
+ 16, //dradix
+ 8, //dwidth
+ NULL, //examine
+ NULL, //deposit
+ &dsk_reset, //reset
+ NULL, //boot
+ &dsk_attach, //attach
+ &dsk_detach, //detach
+ NULL, //ctxt
+ DEV_DEBUG, //flags
+ 0, //dctrl
+ dsk_debug, /* debug flags defined in DEBTAB */
+ NULL, //msize
+ NULL, //help
+ NULL, //attach help
+ NULL, //help context
+ NULL //device description
+};
+
+/* Reset routine */
+
+t_stat dsk_reset(DEVICE *dptr)
+{
+ int i;
+
+ //sim_printf("dsk_reset: call to reset routine\n");
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_reset: call to reset routine\n");
+
+ cur_dsk = 0; /* force initial SIR read in FLEX mode, use a drive # that can't be selected */
+ prev_dsk = 5;
+
+ for (i=0; iunits[i].u3 = NOTRDY; /* clear current flags */
+ dptr->units[i].u4 = 0; /* clear current cylinder # */
+ dptr->units[i].u5 = 0; /* clear current sector # */
+ dptr->units[i].pos = 0; /* clear current byte ptr */
+
+ if (dptr->units[i].filebuf == NULL) {
+ dptr->units[i].filebuf = malloc(SECTOR_SIZE); /* allocate buffer */
+ if (dptr->units[i].filebuf == NULL) {
+ sim_printf("dc-4_reset: Malloc error\n");
+ return SCPE_MEM;
+ } else {
+ sim_debug(DEBUG_flow, dptr, "dsk_reset: allocated file buffer\n");
+ }
+ }
+ }
+
+ // initialize data register
+ fdc_data_byte = 0;
+
+ return SCPE_OK;
+
+} /* dsk_reset() */
+
+/* attach */
+t_stat dsk_attach(UNIT *uptr, CONST char *cptr)
+{
+ off_t fsize = 0; /* size of attached file */
+ int32 temp_cpd; /* cylinders per disk */
+ int32 temp_spt; /* sectors per track */
+ t_stat r;
+ int32 err;
+ int32 pos;
+
+ r = attach_unit(uptr, cptr);
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: attach returns %d\n", r);
+ if (r == SCPE_OK) {
+ /* determine the size of the attached file and populate the UNIT capac value (capacity) */
+ err = sim_fseek(uptr->fileref, 0, SEEK_END); /* seek to offset */
+ if (err == -1) {
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: fseek returns %d\n", err);
+ return (SCPE_IOERR);
+ }
+ fsize = sim_ftell(uptr->fileref);
+ uptr->capac = fsize;
+
+ if (uptr->up7 == flex_flag_str) {
+ sim_printf("dsk_attach: Reading disk geometry from SIR of Flex disk named %s\n", cptr);
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: Reading disk geometry from SIR of Flex disk name %d\n", cptr);
+
+ // whenever a new file is attached - re-read the SIR
+ pos = 0x200; /* Location of Flex System Information Record (SIR) */
+
+ sim_debug(DEBUG_read, &dsk_dev, "dsk_attach: Read pos = %ld ($%04X)\n", pos, (unsigned int) pos);
+ err = sim_fseek(uptr->fileref, pos, SEEK_SET); /* seek to offset */
+ if (err) {
+ sim_debug(DEBUG_read, &dsk_dev, "dsk_attach: Seek error read in SIR\n");
+ sim_printf("dsk_attach: Seek error read in SIR\n");
+ return SCPE_IOERR;
+ }
+ err = sim_fread(uptr->filebuf, SECTOR_SIZE, 1, uptr->fileref); /* read in buffer */
+ if (err != 1) {
+ sim_debug(DEBUG_read, &dsk_dev, "dsk_attach: Seek error read in SIR\n");
+ sim_printf("dsk_attach: File error read in SIR\n");
+ return SCPE_IOERR;
+ }
+
+ /* retrieve parameters from SIR */
+ temp_spt = *((uint8 *)(uptr->filebuf) + MAXSEC) & 0xFF;
+ temp_cpd = *((uint8 *)(uptr->filebuf) + MAXCYL) & 0xFF;
+
+ /* zero based track numbering */
+ temp_cpd++;
+
+ sim_printf("dsk_attach: SIR was read. SPT=%d. CPD=%d. Capacity=%d\n", temp_spt, temp_cpd, fsize);
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: SIR was read. SPT=%d. CPD=%d. Capacity=%d\n", temp_spt, temp_cpd, fsize);
+
+ /* confirm that geometry aligns with size */
+ if (fsize == (temp_cpd * temp_spt * SECTOR_SIZE)) {
+ uptr->u6 = temp_spt;
+ uptr->wait = temp_cpd;
+ sim_printf("dsk_attach: sectors per track is %d, cylinders per disk is %d\n", temp_spt, temp_cpd);
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: WARNING: sectors per track is %d, cylinders per disk is %d\n", temp_spt, temp_cpd);
+ } else {
+ sim_printf("dsk_attach: Disk geometry does not align with file size!\n");
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: WARNING: disk geometry does not align with file size!\n");
+ }
+ } else {
+ /* if sectors per track != 0, calculate cylinders per disk based on file capacity */
+ temp_spt = uptr->u6;
+ if (temp_spt != 0) {
+ temp_cpd = fsize / (temp_spt * SECTOR_SIZE);
+ if (fsize == (temp_cpd * temp_spt * SECTOR_SIZE)) {
+ uptr->wait = temp_cpd;
+ sim_printf("dsk_attach: cylinders per disk calculated as %d\n", temp_cpd);
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: WARNING: cylinders per disk calculated as %d\n", temp_cpd);
+ /* clear any pre-existing flags */
+ uptr->u3 = 0;
+ } else {
+ uptr->wait = 0;
+ sim_printf("dsk_attach: cylinders per disk could not be determined. %d\n", temp_cpd);
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: WARNING: cylinders per disk could not be determined. %d\n", temp_cpd);
+ }
+ }
+ }
+ }
+ return(r);
+
+} /* dsk_attach() */
+
+/* detach */
+t_stat dsk_detach(UNIT *uptr)
+{
+ t_stat r;
+
+ uptr->capac = 0;
+ r = detach_unit(uptr);
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_detach: detach return %d\n", r);
+ return(r);
+
+} /* dsk_detach */
+
+/* disk config */
+t_stat dsk_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
+{
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: val=%d\n", val);
+
+ if ((val & UNIT_DC4_READONLY) != 0) {
+ uptr->u3 |= WRPROT; /* set write protect */
+ } else {
+ uptr->u3 &= (~WRPROT & 0xFF); /* unset EPROM size */
+ }
+
+ if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_FLEX_SIR) {
+ uptr->up7 = flex_flag_str;
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: disk geometry to be determined from Flex disk\n");
+ }
+ if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_10SPT) {
+ uptr->u6 = 10;
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: sectors per track set to %d\n", uptr->u6);
+ }
+ if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_20SPT) {
+ uptr->u6 = 20;
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: sectors per track set to %d\n", uptr->u6);
+ }
+ if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_30SPT) {
+ uptr->u6 = 30;
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: sectors per track set to %d\n", uptr->u6);
+ }
+ if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_36SPT) {
+ uptr->u6 = 36;
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: sectors per track set to %d\n", uptr->u6);
+ }
+ if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_72SPT) {
+ uptr->u6 = 72;
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: sectors per track set to %d\n", uptr->u6);
+ }
+ if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_255SPT) {
+ uptr->u6 = 255;
+ sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: sectors per track set to %d\n", uptr->u6);
+ }
+ return(SCPE_OK);
+} /* dsk_config */
+
+/*
+ I/O instruction handlers, called from the MP-B3 module when a
+ read or write occur to addresses 0xE004-0xE007.
+*/
+
+/*
+ DC-4 drive select register routine - this register is not part of the 1797
+*/
+
+int32 fdcdrv(int32 io, int32 data)
+{
+ static long pos;
+ static int32 err;
+ int32 cpd;
+ int32 spt;
+ int32 temp_return;
+
+
+ sim_debug(DEBUG_flow, &dsk_dev, "fdcdrv: io=%02X, data=%02X\n", io, data);
+
+ if (io) {
+ /* write to DC-4 drive register */
+ cur_dsk = data & 0x03; /* only 2 drive select bits */
+ if (cur_dsk != prev_dsk) { /* did the disk change? */
+ prev_dsk = cur_dsk;
+ }
+ sim_debug(DEBUG_read, &dsk_dev, "fdcdrv: Drive selected %d cur_dsk=%d\n", data & 0x03, cur_dsk);
+ sim_debug(DEBUG_write, &dsk_dev, "fdcdrv: Drive set to %d\n", cur_dsk);
+
+ if ((dsk_unit[cur_dsk].flags & UNIT_DC4_READONLY) != 0) {
+ dsk_unit[cur_dsk].u3 |= WRPROT; /* RO - set 1797 WPROT */
+ sim_debug(DEBUG_write, &dsk_dev, "fdcdrv: Disk is write protected\n");
+ } else {
+ dsk_unit[cur_dsk].u3 &= ((~WRPROT) & 0xFF); /* RW - unset 1797 WPROT */
+ sim_debug(DEBUG_write, &dsk_dev, "fdcdrv: Disk is not write protected\n");
+ }
+ if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* device is not attached */
+ /* set NOTRDY flag */
+ dsk_unit[cur_dsk].u3 |= NOTRDY;
+ sim_debug(DEBUG_write, &dsk_dev, "fdcdrv: Drive is NOT READY\n");
+ }
+ } else {
+ /* read from DC-4 drive register */
+ /* least significant 2 bits are the selected drive */
+ temp_return = cur_dsk & 0x03;
+ if (((dsk_unit[cur_dsk].u3 & BUSY) != 0) && ((dsk_unit[cur_dsk].u3 & DRQ) == 0)) {
+ /* if BUSY indicates that there is a command and DRQ is unset, set DRQ now */
+ dsk_unit[cur_dsk].u3 |= DRQ; /* enable DRQ now */
+ }
+ sim_debug(DEBUG_read, &dsk_dev, "fdcdrv: Drive register read as %02X\n", temp_return );
+ return temp_return;
+ }
+ return SCPE_OK;
+} /* fdcdrv */
+
+/* WD 1797 FDC command register routine */
+
+int32 fdccmd(int32 io, int32 data)
+{
+ static int32 val = 0;
+ static long pos;
+ static int32 err;
+
+ sim_debug(DEBUG_flow, &dsk_dev, "fdccmd: io=%02X, data=%02X\n", io, data);
+
+ /* check for NOTRDY */
+ if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* not attached */
+ dsk_unit[cur_dsk].u3 |= NOTRDY; /* set not ready flag */
+ sim_debug(DEBUG_flow, &dsk_dev, "fdccmd: Drive %d is not attached\n", cur_dsk);
+ } else {
+ /* drive is attached */
+ dsk_unit[cur_dsk].u3 &= ~NOTRDY; /* clear not ready flag */
+ sim_debug(DEBUG_flow, &dsk_dev, "fdccmd: Drive %d is attached\n", cur_dsk);
+ }
+
+ /* check for WRPROT */
+ if ((dsk_unit[cur_dsk].flags & UNIT_DC4_READONLY) != 0) {
+ dsk_unit[cur_dsk].u3 |= WRPROT; /* RO - set write protect flag */
+ sim_debug(DEBUG_flow, &dsk_dev, "fdccmd: Drive %d is write protected\n", cur_dsk);
+ } else {
+ dsk_unit[cur_dsk].u3 &= ~WRPROT; /* RW - unset write protect flag */
+ sim_debug(DEBUG_flow, &dsk_dev, "fdccmd: Drive %d is not write protected\n", cur_dsk);
+ }
+
+ if (io) {
+
+ /* write command to fdc */
+ if ((dsk_unit[cur_dsk].u3 & BUSY) != 0) {
+ /* do not write to command register if device is BUSY */
+ sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Cannot write to command register, device is BUSY\n", cur_dsk);
+ return(SCPE_OK);
+ }
+ if ((dsk_unit[cur_dsk].u3 & NOTRDY) != 0) {
+ /* do not write to command register if device is NOTRDY */
+ sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Cannot write to command register, device is NOT READY\n", cur_dsk);
+ return(SCPE_OK);
+ }
+
+ switch(data) {
+ /* restore command - type I command */
+
+ /* ignored: head load flag, verify flag, stepping motor rate*/
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x09:
+ case 0x0A:
+ case 0x0B:
+ case 0x0C:
+ case 0x0D:
+ case 0x0E:
+ case 0x0F:
+
+ dsk_unit[cur_dsk].u4 = 0; /* home the drive, track = 0 */
+ dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */
+ sim_debug(DEBUG_write, &dsk_dev, "fdccmd: restore of drive %d\n", cur_dsk);
+ break;
+
+ /* seek command - type I command */
+
+ /* ignored: head load flag, verify flag, stepping motor rate*/
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1A:
+ case 0x1B:
+ case 0x1C:
+ case 0x1D:
+ case 0x1E:
+ case 0x1F:
+
+ /* set track */
+ dsk_unit[cur_dsk].u4 = fdc_data_byte;
+ dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */
+ sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Seek of disk %d, track %d\n", cur_dsk, fdc_data_byte);
+ break;
+
+ /* read sector command - type II command (m=0, SSO=0) */
+ case 0x80:
+ case 0x84:
+ case 0x88:
+ case 0x8C:
+ /* read sector command - type II command (m=0, SSO=1) */
+ case 0x82:
+ case 0x86:
+ case 0x8A:
+ case 0x8E:
+
+ /* only execute command if disk is READY */
+ if ((dsk_unit[cur_dsk].u3 & NOTRDY) != 0) {
+ sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Read sector command, but, disk is NOT READY\n");
+ } else {
+
+ sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Read of disk %d, track %d, sector %d\n",
+ cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5);
+
+ /* sectors for track 0 are numbered 0,1,3,4, ... 10 */
+ if (dsk_unit[cur_dsk].u4 == 0) {
+ /* Track 0 Sector 0 --> pos = 0 */
+ /* Track 0 Sector 1 --> pos = 256 */
+ if (dsk_unit[cur_dsk].u5 == 0) {
+ pos = 0;
+ } else {
+ if (dsk_unit[cur_dsk].u5 == 1) {
+ pos = 0;
+ } else {
+ pos = (SECTOR_SIZE * (dsk_unit[cur_dsk].u5 - 1));
+ }
+ }
+ } else {
+ /* calculate file offset. u4 is track. u5 is sector. u6 is sectors per track. */
+ pos = (dsk_unit[cur_dsk].u6 * SECTOR_SIZE) * dsk_unit[cur_dsk].u4;
+ pos += (SECTOR_SIZE * (dsk_unit[cur_dsk].u5 - 1));
+ }
+ sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Read pos = %ld ($%08X)\n",
+ pos, (unsigned int) pos);
+ err = sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */
+ if (err) {
+ sim_printf("fdccmd: sim_fseek error = %d\n", err);
+ sim_debug(DEBUG_write, &dsk_dev, "fdccmd: sim_fseek error = %d\n", err);
+ return SCPE_IOERR;
+ }
+ err = sim_fread(dsk_unit[cur_dsk].filebuf, SECTOR_SIZE, 1, dsk_unit[cur_dsk].fileref); /* read into sector buffer */
+ if (err != 1) {
+
+ /* display error information */
+ sim_printf("fdccmd: sim_fread error = %d\n", err);
+ sim_printf("fdccmd: errno = %d\n", errno);
+ sim_debug(DEBUG_write, &dsk_dev, "fdccmd: sim_fread error = %d\n", err);
+ return SCPE_IOERR;
+ }
+
+ /* set BUSY to indicate that type II command is in progress */
+ dsk_unit[cur_dsk].u3 |= BUSY; /* set BUSY */
+ dsk_unit[cur_dsk].u3 &= ~DRQ; /* unset DRQ */
+ dsk_unit[cur_dsk].pos = 0; /* clear buffer pointer */
+ }
+ break;
+
+ /* write sector command - type II command */
+ case 0xA8:
+ case 0xAC:
+
+ /* only execute command if disk is READY */
+ if ((dsk_unit[cur_dsk].u3 & NOTRDY) != 0) {
+ sim_debug (DEBUG_write, &dsk_dev, "fdccmd: Write sector command, but, disk is NOT READY\n");
+ } else {
+
+ sim_debug (DEBUG_write, &dsk_dev, "fdccmd: Write of disk %d, track %d, sector %d\n",
+ cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5);
+ if ((dsk_unit[cur_dsk].u3 & WRPROT) != 0) {
+ sim_printf("fdccmd: Drive %d is write-protected\n", cur_dsk);
+ } else {
+ /* calculate file offset. u4 is track. u5 is sector. u6 is sectors per track. */
+ pos = (dsk_unit[cur_dsk].u6 * SECTOR_SIZE) * dsk_unit[cur_dsk].u4;
+ pos += SECTOR_SIZE * (dsk_unit[cur_dsk].u5 - 1);
+ sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Write pos = %ld ($%08X)\n", pos, (unsigned int) pos);
+ err = sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */
+ if (err) {
+ sim_printf("fdccmd: sim_fseek error = %d\n", err);
+ sim_debug(DEBUG_write, &dsk_dev, "fdccmd: sim_fseek error = %d\n", err);
+ return SCPE_IOERR;
+ }
+ /* set BUSY to indicate that type II command is in progress */
+ dsk_unit[cur_dsk].u3 |= BUSY; /* set BUSY */
+ dsk_unit[cur_dsk].u3 &= ~DRQ; /* unset DRQ */
+ dsk_unit[cur_dsk].pos = 0; /* clear buffer pointer */
+ }
+ }
+ break;
+
+ default:
+ sim_printf("Unknown or unimplemented FDC command %02XH\n", data);
+ sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Unknown or unimplemented command %02X\n", cur_dsk, data);
+ }
+ return(SCPE_OK);
+
+ } else {
+ /* read status from fdc */
+
+ val = dsk_unit[cur_dsk].u3; /* set return value */
+
+ if (((val & BUSY) != 0) && ((val & DRQ) == 0)) {
+ /* if BUSY indicates that there is a command and DRQ is unset, set DRQ now */
+ dsk_unit[cur_dsk].u3 = val | DRQ; /* enable DRQ for next time */
+ }
+
+ /* handle write VERIFY - as done by Flex */
+ if (((val & BUSY) !=0) && ((val & DRQ) != 0)) {
+ /* Re-read the sector, with read sector command but don't read any data to update the CRC_ERROR and RECORD_NOT_FOUND flags (not emulated) */
+ read_w_drq_busy_counter++;
+ if (read_w_drq_busy_counter > 50) {
+ /* wait for enough status reads to be confident that this a VERIFY */
+ read_w_drq_busy_counter = 0;
+ /* reset BUSY and DRQ flags, we do not implement CRC_ERROR or RECORD_NOT_FOUND flags */
+ dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ);
+ val = dsk_unit[cur_dsk].u3;
+ sim_debug (DEBUG_write, &dsk_dev, "fdccmd: detected write verify\n");
+ }
+ } else {
+ read_w_drq_busy_counter = 0;
+ }
+ sim_debug (DEBUG_read, &dsk_dev, "fdccmd: Exit Drive %d status=%02X\n", cur_dsk, val);
+ return val;
+ }
+} /* fdccmd */
+
+/* WD 1797 FDC track register routine */
+
+int32 fdctrk(int32 io, int32 data)
+{
+//sim_printf("\nfdctrk: io=%d, data=%d\n", io, data);
+
+ sim_debug(DEBUG_flow, &dsk_dev, "fdctrk: io=%02X, data=%02X\n", io, data);
+
+ if (io) {
+ /* write to track register */
+ /* do not load when device is BUSY or NOT READY */
+ if (((dsk_unit[cur_dsk].u3 & BUSY) == 0) && ((dsk_unit[cur_dsk].u3 & NOTRDY) == 0)) {
+// RICHARD WAS HERE
+// SEEK ERROR!
+ if (data >= dsk_unit[cur_dsk].wait) {
+sim_printf("Seek error! cur_dsk=%d, tracks per disk is %d, requested track is %d\n", cur_dsk, dsk_unit[cur_dsk].wait, data);
+ }
+ dsk_unit[cur_dsk].u4 = data & 0xFF;
+ sim_debug (DEBUG_write, &dsk_dev, "fdctrk: Drive %d track set to %d\n", cur_dsk, dsk_unit[cur_dsk].u4);
+ }
+ return(SCPE_OK);
+ } else {
+ /* read from to track register */
+ sim_debug (DEBUG_read, &dsk_dev, "fdctrk: Drive %d track read as %d\n", cur_dsk, dsk_unit[cur_dsk].u4);
+ return(dsk_unit[cur_dsk].u4);
+ }
+} /* fdctrk */
+
+/* WD 1797 FDC sector register routine */
+
+int32 fdcsec(int32 io, int32 data)
+{
+ sim_debug(DEBUG_flow, &dsk_dev, "fdcsec: io=%02X, data=%02X\n", io, data);
+
+ if (io) {
+ /* write to sector register */
+ /* do not load when device is BUSY or NOT READY */
+ if (((dsk_unit[cur_dsk].u3 & BUSY) == 0) && ((dsk_unit[cur_dsk].u3 & NOTRDY) == 0)) {
+ dsk_unit[cur_dsk].u5 = data & 0xFF;
+ sim_debug(DEBUG_write, &dsk_dev, "fdcsec: Drive %d sector set to %d\n", cur_dsk, dsk_unit[cur_dsk].u5);
+ }
+ return(SCPE_OK);
+ } else {
+ /* read sector register */
+ sim_debug (DEBUG_read, &dsk_dev, "fdcsec: Drive %d sector read as %d\n", cur_dsk, dsk_unit[cur_dsk].u5);
+ return(dsk_unit[cur_dsk].u5);
+ }
+} /* fdcsec */
+
+/* WD 1797 FDC data register routine */
+
+int32 fdcdata(int32 io, int32 data)
+{
+ int32 val;
+ static int32 err;
+
+ sim_debug(DEBUG_flow, &dsk_dev, "fdcdata: io=%02X, data=%02X\n", io, data);
+
+ if (io) {
+ /* write byte to fdc */
+ if ((dsk_unit[cur_dsk].u3 & BUSY) == 0) {
+ /* NOT BUSY - write to data register fdc_data_byte */
+ sim_debug(DEBUG_write, &dsk_dev, "fdcdata: Writing %02X to data register\n", data);
+ fdc_data_byte = data;
+ } else {
+ /* BUSY - a command is being processed */
+ if (dsk_unit[cur_dsk].pos < SECTOR_SIZE) { /* copy bytes to buffer */
+
+ /* reset the counter used for write verify */
+ read_w_drq_busy_counter = 0;
+
+ sim_debug (DEBUG_flow, &dsk_dev, "fdcdata: Writing byte pos=%d val=%02X\n", dsk_unit[cur_dsk].pos, data);
+ *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) = data; /* byte into buffer */
+ dsk_unit[cur_dsk].pos++; /* increment buffer pointer */
+
+ /* if this is last byte in sector then update statuses */
+ if (dsk_unit[cur_dsk].pos >= SECTOR_SIZE) { /* done? */
+ err = sim_fwrite(dsk_unit[cur_dsk].filebuf, SECTOR_SIZE, 1, dsk_unit[cur_dsk].fileref); /* write it */
+ if (err != 1) {
+ /* display error information */
+ sim_printf("fdcdata: sim_fwrite error = %d\n", err);
+ sim_printf("fdcdata: errno = %d\n", errno);
+ sim_debug(DEBUG_write, &dsk_dev, "fdcdata: sim_fwrite error = %d\n", err);
+ return SCPE_IOERR;
+ }
+ dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* reset flags */
+ dsk_unit[cur_dsk].pos = 0; /* reset counter */
+ sim_debug(DEBUG_write, &dsk_dev, "fdcdata: Sector write complete\n");
+ }
+ }
+ }
+ return(SCPE_OK);
+ } else {
+ /* read byte from fdc */
+
+ if ((dsk_unit[cur_dsk].u3 & BUSY) == 0) {
+ /* NOT BUSY - read from data register fdc_data_byte */
+ val = fdc_data_byte;
+ sim_debug(DEBUG_read, &dsk_dev, "fdcdata: Reading data register value of %02X\n", val);
+ } else {
+ /* BUSY - a read command is being processed */
+ if (dsk_unit[cur_dsk].pos < SECTOR_SIZE) { /* copy bytes from buffer */
+
+ /* reset the counter used for write verify */
+ read_w_drq_busy_counter = 0;
+
+ /* read a byte into the sector buffer */
+ val = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) & 0xFF;
+ sim_debug(DEBUG_read, &dsk_dev, "fdcdata: Reading byte pos=%d val=%02X\n", dsk_unit[cur_dsk].pos, val);
+ dsk_unit[cur_dsk].pos++; /* step counter */
+
+ /* if this is last byte in sector then update statuses */
+ if (dsk_unit[cur_dsk].pos >= SECTOR_SIZE) { /* done? */
+ dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */
+ dsk_unit[cur_dsk].pos = 0; /* reset step counter */
+ sim_debug(DEBUG_read, &dsk_dev, "fdcdata: Sector read complete\n");
+ }
+ }
+ }
+ return(val);
+ }
+} /* fdcdata() */
+
+/* end of dc-4.c */
diff --git a/swtp6809/common/m6809.c b/swtp6809/common/m6809.c
new file mode 100644
index 000000000..9f4ffaee9
--- /dev/null
+++ b/swtp6809/common/m6809.c
@@ -0,0 +1,3617 @@
+/* 6809.c: SWTP 6809 CPU simulator^
+
+ Copyright (c) 2005-2012, William Beech
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ /opy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of William A. Beech shall not
+ be used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from William A. Beech.
+
+ The following copyright notice applies to the SWTP 6809 source, binary, and documentation:
+
+ Original code published in 2024, written by Richard F Lukes
+ Copyright (c) 2024, Richard F Lukes
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the names of The Authors shall not be
+ used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from the Authors.
+
+ MODIFICATIONS:
+
+ 23 Apr 15 -- Modified to use simh_debug
+ 21 Apr 20 -- Richard Brinegar numerous fixes for flag errors
+ 04 Apr 24 -- Richard Lukes - modified for 6809
+
+ NOTES:
+ cpu Motorola M6809 CPU
+
+ The register state for the M6809 CPU is:
+
+ A<0:7> Accumulator A
+ B<0:7> Accumulator B
+ IX<0:15> Index Register
+ IY<0:15> Index Register
+ CCR<0:7> Condition Code Register
+ EF Entire flag
+ FF FIRQ flag
+ HF half-carry flag
+ IF IRQ flag
+ NF negative flag
+ ZF zero flag
+ VF overflow flag
+ CF carry flag
+ PC<0:15> program counter
+ UP<0:15> User Stack Pointer
+ SP<0:15> Stack Pointer
+
+ The M6809 is an 8-bit CPU, which uses 16-bit registers to address
+ up to 64KB of memory.
+
+ The 72 basic instructions come in 1, 2, and 3-byte flavors.
+
+ This routine is the instruction decode routine for the M6809.
+ It is called from the CPU board simulator to execute
+ instructions in simulated memory, starting at the simulated PC.
+ It runs until 'reason' is set non-zero.
+
+ General notes:
+
+ 1. Reasons to stop. The simulator can be stopped by:
+
+ WAI instruction
+ I/O error in I/O simulator
+ Invalid OP code (if ITRAP is set on CPU)
+ Invalid mamory address (if MTRAP is set on CPU)
+
+ 2. Interrupts.
+ There are 4 types of interrupt, and in effect they do a
+ hardware CALL instruction to one of 4 possible high memory addresses.
+
+ 3. Non-existent memory.
+ On the SWTP 6809, reads to non-existent memory
+ return 0FFH, and writes are ignored.
+*/
+
+#include
+
+#include "swtp_defs.h"
+
+#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid Opcode */
+#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP)
+
+/* Flag values to set proper positions in CCR */
+#define EF 0x80
+#define FF 0x40
+#define HF 0x20
+#define IF 0x10
+#define NF 0x08
+#define ZF 0x04
+#define VF 0x02
+#define CF 0x01
+
+/* PSH/PUL Post Byte register positions */
+#define PSH_PUL_Post_Byte_PC 0x80
+#define PSH_PUL_Post_Byte_S_U 0x40
+#define PSH_PUL_Post_Byte_Y 0x20
+#define PSH_PUL_Post_Byte_X 0x10
+#define PSH_PUL_Post_Byte_DP 0x08
+#define PSH_PUL_Post_Byte_B 0x04
+#define PSH_PUL_Post_Byte_A 0x02
+#define PSH_PUL_Post_Byte_CC 0x01
+
+#define TFR_EXG_Post_Nybble_D 0
+#define TFR_EXG_Post_Nybble_X 1
+#define TFR_EXG_Post_Nybble_Y 2
+#define TFR_EXG_Post_Nybble_U 3
+#define TFR_EXG_Post_Nybble_S 4
+#define TFR_EXG_Post_Nybble_PC 5
+#define TFR_EXG_Post_Nybble_A 8
+#define TFR_EXG_Post_Nybble_B 9
+#define TFR_EXG_Post_Nybble_CC 10
+#define TFR_EXG_Post_Nybble_DP 11
+
+/* Exclusive OR macro for logical expressions */
+#define EXOR(a,b) (((a)!=0) != ((b)!=0))
+
+/* Macros to handle the flags in the CCR */
+#define CCR_MSK (EF|FF|HF|IF|NF|ZF|VF|CF)
+#define TOGGLE_FLAG(FLAG) (CCR ^= (FLAG))
+#define SET_FLAG(FLAG) (CCR |= (FLAG))
+#define CLR_FLAG(FLAG) (CCR &= ~(FLAG))
+#define GET_FLAG(FLAG) (CCR & (FLAG))
+
+#define COND_SET_FLAG(COND,FLAG) \
+ if (COND) SET_FLAG(FLAG); else CLR_FLAG(FLAG)
+
+#define COND_SET_FLAG_N(VAR) \
+ if ((VAR) & 0x80) SET_FLAG(NF); else CLR_FLAG(NF)
+#define COND_SET_FLAG_N_16(VAR) \
+ if ((VAR) & 0x8000) SET_FLAG(NF); else CLR_FLAG(NF)
+
+#define COND_SET_FLAG_Z(VAR) \
+ if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF)
+#define COND_SET_FLAG_Z_16(VAR) \
+ if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF)
+
+#define COND_SET_FLAG_C(VAR) \
+ if ((VAR) & 0x100) SET_FLAG(CF); else CLR_FLAG(CF)
+#define COND_SET_FLAG_C_16(VAR) \
+ if ((VAR) & 0x10000) SET_FLAG(CF); else CLR_FLAG(CF)
+
+/* local global variables */
+
+int32 A = 0; /* Accumulator A */
+int32 B = 0; /* Accumulator B */
+int32 D = 0; /* Accumulator D */
+int32 DP = 0; /* Direct Page Register */
+int32 IX = 0; /* Index register X */
+int32 IY = 0; /* Index register Y */
+int32 UP = 0; /* User Stack pointer */
+int32 SP = 0; /* Hardware Stack pointer */
+int32 CCR = EF|FF|IF; /* Condition Code Register */
+int32 saved_PC = 0; /* Saved Program counter */
+int32 previous_PC = 0; /* Previous previous Program counter */
+int32 last_PC = 0; /* Last Program counter */
+int32 PC; /* Program counter */
+int32 INTE = 0; /* Interrupt Enable */
+
+int32 int_req = 0; /* Interrupt request */
+int32 mem_fault = 0; /* memory fault flag */
+
+#define m6809_NAME "Motorola M6809 Processor Chip"
+
+/* function prototypes */
+
+t_stat m6809_reset(DEVICE *dptr);
+t_stat m6809_boot(int32 unit_num, DEVICE *dptr);
+t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches);
+t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches);
+static const char* m6809_desc(DEVICE *dptr) { return m6809_NAME; }
+
+
+void dump_regs(void);
+void dump_regs1(void);
+int32 fetch_byte(int32 flag);
+int32 fetch_word();
+uint8 pop_sp_byte(void);
+uint8 pop_up_byte(void);
+uint16 pop_sp_word(void);
+uint16 pop_up_word(void);
+void push_sp_byte(uint8 val);
+void push_up_byte(uint8 val);
+void push_sp_word(uint16 val);
+void push_up_word(uint16 val);
+void go_rel(int32 cond);
+void go_long_rel(int32 cond);
+int32 get_rel_addr(void);
+int32 get_long_rel_addr(void);
+int32 get_dir_byte_val(void);
+int32 get_dir_word_val(void);
+int32 get_imm_byte_val(void);
+int32 get_imm_word_val(void);
+int32 get_dir_addr(void);
+int32 get_indexed_byte_val(void);
+int32 get_indexed_word_val(void);
+int32 get_indexed_addr(void);
+int32 get_ext_addr(void);
+int32 get_ext_byte_val(void);
+int32 get_ext_word_val(void);
+int32 get_flag(int32 flag);
+void condevalVa(int32 op1, int32 op2);
+void condevalVa16(int32 op1, int32 op2);
+void condevalVs(int32 op1, int32 op2);
+void condevalVs16(int32 op1, int32 op2);
+void condevalHa(int32 op1, int32 op2);
+
+/* external routines */
+
+extern void CPU_BD_put_mbyte(int32 addr, int32 val);
+extern void CPU_BD_put_mword(int32 addr, int32 val);
+extern int32 CPU_BD_get_mbyte(int32 addr);
+extern int32 CPU_BD_get_mword(int32 addr);
+
+/* CPU data structures
+
+ m6809_dev CPU device descriptor
+ m6809_unit CPU unit descriptor
+ m6809_reg CPU register list
+ m6809_mod CPU modifiers list */
+
+UNIT m6809_unit = { UDATA (NULL, 0, 0) };
+
+REG m6809_reg[] = {
+ { HRDATA (PC, saved_PC, 16) },
+ { HRDATA (A, A, 8) },
+ { HRDATA (B, B, 8) },
+ { HRDATA (DP, DP, 8) },
+ { HRDATA (IX, IX, 16) },
+ { HRDATA (IY, IY, 16) },
+ { HRDATA (SP, SP, 16) },
+ { HRDATA (UP, UP, 16) },
+ { HRDATA (CCR, CCR, 8) },
+ { FLDATA (INTE, INTE, 16) },
+ { ORDATA (WRU, sim_int_char, 8) },
+ { NULL } };
+
+MTAB m6809_mod[] = {
+ { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL },
+ { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL },
+ { 0 } };
+
+DEBTAB m6809_debug[] = {
+ { "ALL", DEBUG_all },
+ { "FLOW", DEBUG_flow },
+ { "READ", DEBUG_read },
+ { "WRITE", DEBUG_write },
+ { "LEV1", DEBUG_level1 },
+ { "LEV2", DEBUG_level2 },
+ { "REG", DEBUG_reg },
+ { "ASM", DEBUG_asm },
+ { NULL }
+};
+
+DEVICE m6809_dev = {
+ "CPU", //name
+ &m6809_unit, //units
+ m6809_reg, //registers
+ m6809_mod, //modifiers
+ 1, //numunits
+ 16, //aradix
+ 16, //awidth
+ 1, //aincr
+ 16, //dradix
+ 8, //dwidth
+ &m6809_examine, //examine
+ &m6809_deposit, //deposit
+ &m6809_reset, //reset
+ &m6809_boot, //boot
+ NULL, //attach
+ NULL, //detach
+ NULL, //ctxt
+ DEV_DEBUG, //flags
+ 0, //dctrl
+ m6809_debug, //debflags
+ NULL, //msize
+ NULL, //lname
+ NULL, //help routine
+ NULL, //attach help routine
+ NULL, //help context
+ &m6809_desc //device description
+};
+
+static const char *opcode[] = {
+"NEG", "?01?", "?02?", "COM", //0x00
+"LSR", "?05?", "ROR", "ASR",
+"ASL", "ROL", "DEC", "???",
+"INC", "TST", "JMP", "CLR",
+"PG2", "PG3", "NOP", "SYNC", //0x10
+"?14?", "?15?", "LBRA", "LBSR",
+"?18?", "DAA", "ORCC", "?1B?",
+"ANDCC", "SEX", "EXG", "TFR",
+"BRA", "BRN", "BHI", "BLS", //0x20
+"BCC", "BCS", "BNE", "BEQ",
+"BVC", "BVS", "BPL", "BMI",
+"BGE", "BLT", "BGT", "BLE",
+"LEAX", "LEAY", "LEAS", "LEAU", //0x30
+"PSHS", "PULS", "PSHU", "PULU",
+"?38?", "RTS", "ABX", "RTI",
+"CWAI", "MUL", "?3E?", "SWI",
+"NEGA", "?41?", "?42?", "COMA", //0x40
+"LSRA", "?45?", "RORA", "ASRA",
+"ASLA", "ROLA", "DECA", "?4B?",
+"INCA", "TSTA", "?4E?", "CLRA",
+"NEGB", "?51?", "?52?", "COMB", //0x50
+"LSRB", "?55?", "RORB", "ASRB",
+"ASLB", "ROLB", "DECB", "?5B?",
+"INCB", "TSTB", "?5E?", "CLRB",
+"NEG", "?61?", "?62?", "COM", //0x60
+"LSR", "?65?", "ROR", "ASR",
+"ASL", "ROL", "DEC", "?6B?",
+"INC", "TST", "JMP", "CLR",
+"NEG", "?71?", "?72?", "COM", //0x70
+"LSR", "?75?", "ROR", "ASR",
+"ASL", "ROL", "DEC", "?7B?",
+"INC", "TST", "JMP", "CLR",
+"SUBA", "CMPA", "SBCA", "SUBD", //0x80
+"ANDA", "BITA", "LDA", "?87?",
+"EORA", "ADCA", "ORAA", "ADDA",
+"CMPX", "BSR", "LDX", "?8F?",
+"SUBA", "CMPA", "SBCA", "SUBD", //0x90
+"ANDA", "BITA", "LDA", "STA",
+"EORA", "ADCA", "ORA", "ADDA",
+"CMPX", "JSR", "LDX", "STX",
+"SUBA", "CMPA", "SBCA", "SUBD", //0xA0
+"ANDA", "BITA", "LDA", "STA",
+"EORA", "ADCA", "ORA", "ADDA",
+"CMPX", "JSR", "LDX", "STX",
+"SUBA", "CMPA", "SBCA", "SUBD", //0xB0
+"ANDA", "BITA", "LDA", "STA",
+"EORA", "ADCA", "ORA", "ADDA",
+"CMPX", "JSR", "LDX", "STX",
+"SUBB", "CMPB", "SBCB", "ADDD", //0xC0
+"ANDB", "BITB", "LDB", "?C7?",
+"EORB", "ADCB", "ORB", "ADDB",
+"LDD", "?CD?", "LDU", "?CF?",
+"SUBB", "CMPB", "SBCB", "ADDD", //0xD0
+"ANDB", "BITB", "LDB", "STB",
+"EORB", "ADCB", "ORB", "ADDB",
+"LDD", "STD", "LDU", "STU",
+"SUBB", "CMPB", "SBCB", "ADDD", //0xE0
+"ANDB", "BITB", "LDB", "STB",
+"EORB", "ADCB", "ORB", "ADDB",
+"LDD", "STD", "LDU", "STU",
+"SUBB", "CMPB", "SBCB", "ADDD", //0xF0
+"ANDB", "BITB", "LDB", "STB",
+"EORB", "ADCB", "ORB", "ADDB",
+"LDD", "STD", "LDU", "STU"
+};
+
+int32 oplen[256] = {
+2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, //0x00
+2,2,1,1,0,0,3,3,0,1,2,0,2,1,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,0,1,1,1,2,1,0,1,
+1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40
+1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1,
+2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2,
+3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3,
+2,2,2,3,2,2,2,0,2,2,2,2,3,2,3,0, //0x80
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+2,2,2,3,2,2,2,0,2,2,2,2,3,0,3,0, //0xC0
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
+};
+
+t_stat sim_instr (void)
+{
+ int32 reason;
+ int32 IR;
+ int32 OP;
+ int32 OP2; /* Used for 2-byte opcodes */
+
+ int32 hi; /* hi bit/nybble/byte */
+ int32 lo; /* lo bit/nybble/byte */
+ int32 op1; /* operand #1 */
+ int32 op2; /* operand #2 - used for CC evaluation */
+ int32 result; /* temporary value */
+ int32 addr; /* temporary address value */
+
+ /* used for 6809 instruction decoding - TFT, EXG, PSH, PUL*/
+ int32 Post_Byte = 0;
+ int32 Src_Nybble = 0;
+ int32 Dest_Nybble = 0;
+ int32 Src_Value = 0;
+ int32 Dest_Value = 0;
+
+ PC = saved_PC & ADDRMASK; /* load local PC */
+ reason = 0;
+
+ /* Main instruction fetch/decode loop */
+
+ while (reason == 0) { /* loop until halted */
+ if (sim_interval <= 0) /* check clock queue */
+ if ((reason = sim_process_event ())) {
+ break;
+ }
+ if (mem_fault != 0) { /* memory fault? */
+ mem_fault = 0; /* reset fault flag */
+ reason = STOP_MEMORY;
+ break;
+ }
+ if (int_req > 0) { /* interrupt? */
+ /* 6809 interrupts not implemented yet. None were used,
+ on a standard SWTP 6809. All I/O is programmed. */
+ reason = STOP_HALT; /* stop simulation */
+ break;
+
+ } /* end interrupt */
+ if (sim_brk_summ &&
+ sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
+ reason = STOP_IBKPT; /* stop simulation */
+ break;
+ }
+
+ sim_interval--;
+ last_PC = previous_PC;
+ previous_PC = PC;
+ IR = OP = fetch_byte(0); /* fetch instruction */
+
+ /* The Big Instruction Decode Switch */
+
+ switch (IR) {
+
+/* 0x00 - direct mode */
+ case 0x00: /* NEG dir */
+ addr = get_dir_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ COND_SET_FLAG(op1 != 0, CF);
+ COND_SET_FLAG(op1 == 0x80, VF);
+ result = 0 - op1;
+ result &= 0xFF;
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ break;
+
+ case 0x03: /* COM dir */
+ addr = get_dir_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (~op1) & 0xFF;
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ SET_FLAG(CF);
+ break;
+
+ case 0x04: /* LSR dir */
+ addr = get_dir_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = op1 >> 1;
+ CPU_BD_put_mbyte(addr, result);
+ CLR_FLAG(NF);
+ COND_SET_FLAG_Z(result);
+ /* H,V not affected */
+ COND_SET_FLAG(op1 & 0x01, CF);
+ break;
+
+ case 0x06: /* ROR dir */
+ addr = get_dir_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = op1 >> 1;
+ if (get_flag(CF)) {
+ result |= 0x80;
+ }
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ /* H,V unaffected */
+ COND_SET_FLAG(op1 & 0x01, CF);
+ break;
+
+ case 0x07: /* ASR dir */
+ addr = get_dir_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 >> 1) | (op1 & 0x80);
+ CPU_BD_put_mbyte(addr, result);
+ /* H undefined */
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ /* V unaffected */
+ COND_SET_FLAG(op1 & 0x01, CF);
+ break;
+
+ case 0x08: /* ASL dir */
+ addr = get_dir_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 << 1) & BYTEMASK;
+ CPU_BD_put_mbyte(addr, result);
+ /* H is undefined */
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ COND_SET_FLAG(op1 & 0x80, CF);
+ COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF);
+ break;
+
+ case 0x09: /* ROL dir */
+ addr = get_dir_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 << 1) & BYTEMASK;
+ if (get_flag(CF)) {
+ result |= 0x01;
+ }
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ COND_SET_FLAG(op1 & 0x80, CF);
+ COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF);
+ break;
+
+ case 0x0A: /* DEC dir */
+ addr = get_dir_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 - 1) & BYTEMASK;
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ COND_SET_FLAG(op1 == 0x80, VF);
+ /* C unaffected */
+ break;
+
+ case 0x0C: /* INC dir */
+ addr = get_dir_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 + 1) & BYTEMASK;
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ COND_SET_FLAG(op1 == 0x7F, VF);
+ /* C unaffected */
+ break;
+
+ case 0x0D: /* TST dir */
+ result = get_dir_byte_val();
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ /* C unaffected */
+ break;
+
+ case 0x0E: /* JMP dir */
+ PC = get_dir_addr();
+ break;
+
+ case 0x0F: /* CLR dir */
+ CPU_BD_put_mbyte(get_dir_addr(), 0);
+ /* H not affected */
+ CLR_FLAG(NF);
+ SET_FLAG(ZF);
+ CLR_FLAG(VF);
+ CLR_FLAG(CF);
+ break;
+
+/* 0x10 */
+ case 0x10: /* 2-byte opcodes */
+ /* fetch second byte of opcode */
+ OP2 = fetch_byte(1);
+ switch (OP2) {
+ case 0x21: /* LBRN rel */
+ /* Branch Never - essentially a NOP */
+ go_long_rel(0);
+ break;
+ case 0x22: /* LBHI rel */
+ go_long_rel(!(get_flag(CF) || get_flag(ZF)));
+ break;
+ case 0x23: /* LBLS rel */
+ go_long_rel(get_flag(CF) || get_flag(ZF));
+ break;
+ case 0x24: /* LBCC rel */
+ go_long_rel(!get_flag(CF));
+ break;
+ case 0x25: /* LBCS rel */
+ go_long_rel(get_flag(CF));
+ break;
+ case 0x26: /* LBNE rel */
+ go_long_rel(!get_flag(ZF));
+ break;
+ case 0x27: /* LBEQ rel */
+ go_long_rel(get_flag(ZF));
+ break;
+ case 0x28: /* LBVC rel */
+ go_long_rel(!get_flag(VF));
+ break;
+ case 0x29: /* LBVS rel */
+ go_long_rel(get_flag(VF));
+ break;
+ case 0x2A: /* LBPL rel */
+ go_long_rel(!get_flag(NF));
+ break;
+ case 0x2B: /* LBMI rel */
+ go_long_rel(get_flag(NF));
+ break;
+ case 0x2C: /* LBGE rel */
+ go_long_rel(get_flag(NF) == get_flag(VF));
+ break;
+ case 0x2D: /* LBLT rel */
+ go_long_rel(get_flag(NF) != get_flag(VF));
+ break;
+ case 0x2E: /* LBGT rel */
+ go_long_rel((get_flag(ZF) == 0) && (get_flag(NF) == get_flag(VF)));
+ break;
+ case 0x2F: /* LBLE rel */
+ go_long_rel(get_flag(ZF) || (get_flag(NF) != get_flag(VF)));
+ break;
+
+ case 0x3F: /* SWI2 */
+ SET_FLAG(EF);
+ push_sp_word(PC);
+ push_sp_word(UP);
+ push_sp_word(IY);
+ push_sp_word(IX);
+ push_sp_byte(DP);
+ push_sp_byte(B);
+ push_sp_byte(A);
+ push_sp_byte(CCR);
+ PC = CPU_BD_get_mword(0xFFF4);
+ break;
+
+ case 0x83: /* CMPD imm */
+ /* do not modify D|A|B */
+ D = (A << 8) | (B & BYTEMASK);
+ op2 = get_imm_word_val();
+ result = D - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(D, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0x8C: /* CMPY imm */
+ /* do not modify Y */
+ op2 = get_imm_word_val();
+ result = IY - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(IY, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0x8E: /* LDY imm */
+ IY = get_imm_word_val();
+ COND_SET_FLAG_N_16(IY);
+ COND_SET_FLAG_Z_16(IY);
+ CLR_FLAG(VF);
+ break;
+
+ case 0x93: /* CMPD dir */
+ /* do not modify D|A|B */
+ D = (A << 8) | (B & BYTEMASK);
+ op2 = get_dir_word_val();
+ result = D - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(D, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0x9C: /* CMPY dir */
+ /* do not modify Y */
+ op2 = get_dir_word_val();
+ result = IY - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(IY, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0x9E: /* LDY dir */
+ IY = get_dir_word_val();
+ COND_SET_FLAG_N_16(IY);
+ COND_SET_FLAG_Z_16(IY);
+ CLR_FLAG(VF);
+ break;
+
+ case 0x9F: /* STY dir */
+ CPU_BD_put_mword(get_dir_addr(), IY);
+ COND_SET_FLAG_N_16(IY);
+ COND_SET_FLAG_Z_16(IY);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xA3: /* CMPD ind */
+ /* do not modify D|A|B */
+ D = (A << 8) | (B & BYTEMASK);
+ op2 = get_indexed_word_val();
+ result = D - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(D, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0xAC: /* CMPY ind */
+ /* do not modify Y */
+ op2 = get_indexed_word_val();
+ result = IY - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(IY, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0xAE: /* LDY ind */
+ IY = get_indexed_word_val();
+ COND_SET_FLAG_N_16(IY);
+ COND_SET_FLAG_Z_16(IY);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xAF: /* STY ind */
+ CPU_BD_put_mword(get_indexed_addr(), IY);
+ COND_SET_FLAG_N_16(IY);
+ COND_SET_FLAG_Z_16(IY);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xB3: /* CMPD ext */
+ /* Do not modify D|A|B */
+ D = (A << 8) | (B & BYTEMASK);
+ op2 = get_ext_word_val();
+ result = D - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(D, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0xBC: /* CMPY ext */
+ /* Do not modify D|A|B */
+ op2 = get_ext_word_val();
+ result = IY - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(IY, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0xBE: /* LDY ext */
+ IY = get_ext_word_val();
+ COND_SET_FLAG_N_16(IY);
+ COND_SET_FLAG_Z_16(IY);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xBF: /* STY ext */
+ CPU_BD_put_mword(get_ext_addr(), IY);
+ COND_SET_FLAG_N_16(IY);
+ COND_SET_FLAG_Z_16(IY);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xCE: /* LDS imm */
+ SP = get_imm_word_val();
+ COND_SET_FLAG_N_16(SP);
+ COND_SET_FLAG_Z_16(SP);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xDE: /* LDS dir */
+ SP = get_dir_word_val();
+ COND_SET_FLAG_N_16(SP);
+ COND_SET_FLAG_Z_16(SP);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xDF: /* STS dir */
+ CPU_BD_put_mword(get_dir_addr(), SP);
+ COND_SET_FLAG_N_16(SP);
+ COND_SET_FLAG_Z_16(SP);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xEE: /* LDS ind */
+ SP = get_indexed_word_val();
+ COND_SET_FLAG_N_16(SP);
+ COND_SET_FLAG_Z_16(SP);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xEF: /* STS ind */
+ CPU_BD_put_mword(get_indexed_addr(), SP);
+ COND_SET_FLAG_N_16(SP);
+ COND_SET_FLAG_Z_16(SP);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xFE: /* LDS ext */
+ SP = get_ext_word_val();
+ COND_SET_FLAG_N_16(SP);
+ COND_SET_FLAG_Z_16(SP);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xFF: /* STS ext */
+ CPU_BD_put_mword(get_ext_addr(), SP);
+ COND_SET_FLAG_N_16(SP);
+ COND_SET_FLAG_Z_16(SP);
+ CLR_FLAG(VF);
+ break;
+ }
+ break;
+
+/* Ox11 */
+ case 0x11: /* 2-byte opcodes */
+ /* fetch second byte of opcode */
+ OP2 = fetch_byte(1);
+ switch (OP2) {
+
+ case 0x3F: /* SWI3 */
+ SET_FLAG(EF);
+ push_sp_word(PC);
+ push_sp_word(UP);
+ push_sp_word(IY);
+ push_sp_word(IX);
+ push_sp_byte(DP);
+ push_sp_byte(B);
+ push_sp_byte(A);
+ push_sp_byte(CCR);
+ PC = CPU_BD_get_mword(0xFFF2);
+ break;
+
+ case 0x83: /* CMPU imm */
+ /* Do not modify UP */
+ op2 = get_imm_word_val();
+ result = UP - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(UP, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0x8C: /* CMPS imm */
+ /* Do not modify SP */
+ op2 = get_imm_word_val();
+ result = SP - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(SP, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0x93: /* CMPU dir */
+ /* Do not modify UP */
+ op2 = get_dir_word_val();
+ result = UP - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(UP, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0x9C: /* CMPS dir */
+ /* Do not modify SP */
+ op2 = get_dir_word_val();
+ result = SP - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(SP, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0xA3: /* CMPU ind */
+ /* Do not modify UP */
+ op2 = get_indexed_word_val();
+ result = UP - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(UP, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0xAC: /* CMPS ind */
+ /* Do not modify SP */
+ op2 = get_indexed_word_val();
+ result = SP - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(SP, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0xB3: /* CMPU ext */
+ /* Do not modify UP */
+ op2 = get_ext_word_val();
+ result = UP - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(UP, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ case 0xBC: /* CMPS ext */
+ /* Do not modify SP */
+ op2 = get_ext_word_val();
+ result = SP - op2;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(SP, op2);
+ COND_SET_FLAG_C_16(result);
+ break;
+
+ default:
+ reason = STOP_OPCODE; /* stop simulation */
+ break;
+ }
+ break;
+
+ case 0x12: /* NOP */
+ break;
+
+ case 0x13: /* SYNC inherent*/
+ /* Interrupts are not implemented */
+ reason = STOP_HALT; /* stop simulation */
+ break;
+
+ case 0x16: /* LBRA relative */
+ go_long_rel(1);
+ break;
+
+ case 0x17: /* LBSR relative */
+ addr = get_long_rel_addr();
+ push_sp_word(PC);
+ PC = (PC + addr) & ADDRMASK;
+ break;
+
+ case 0x19: /* DAA inherent */
+ lo = A & 0x0F;
+ hi = (A >> 4) & 0x0F;
+ if ((lo > 9) || get_flag(HF)) {
+ /* add correction factor of 0x06 for lower nybble */
+ A += 0x06;
+ }
+ if ((hi > 9) || get_flag(CF) || ((hi > 8) && (lo > 9))) {
+ /* add correction factor of 0x60 for upper nybble */
+ A += 0x60;
+ A |= 0x100; /* set the C flag */
+ }
+ COND_SET_FLAG_C(A);
+ A = A & BYTEMASK;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ break;
+
+ case 0x1A: /* ORCC imm */
+ CCR = CCR | get_imm_byte_val();
+ break;
+
+ case 0x1C: /* ANDCC imm */
+ CCR = CCR & get_imm_byte_val();
+ break;
+
+ case 0x1D: /* SEX inherent */
+ if (B & 0x80) {
+ A = 0xFF;
+ } else {
+ A = 0;
+ }
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ break;
+
+ case 0x1E: /* EXG imm */
+ Post_Byte = get_imm_byte_val();
+ Src_Nybble = (Post_Byte >> 4) & 0x0F;
+ Dest_Nybble = Post_Byte & 0x0F;
+ if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) {
+ // EXG with unaligned register sizes
+ reason = STOP_OPCODE;
+ }
+ /* read register values */
+ if (Src_Nybble <= 5 && Dest_Nybble <= 5) {
+ /* 16-bit register */
+ /* read source register */
+ switch (Src_Nybble) {
+ case TFR_EXG_Post_Nybble_D: Src_Value = (A << 8) | (B & BYTEMASK); break;
+ case TFR_EXG_Post_Nybble_X: Src_Value = IX; break;
+ case TFR_EXG_Post_Nybble_Y: Src_Value = IY; break;
+ case TFR_EXG_Post_Nybble_U: Src_Value = UP; break;
+ case TFR_EXG_Post_Nybble_S: Src_Value = SP; break;
+ case TFR_EXG_Post_Nybble_PC: Src_Value = PC; break;
+ default: break;
+ }
+ /* read destination register */
+ switch (Dest_Nybble) {
+ case TFR_EXG_Post_Nybble_D: Dest_Value = (A << 8) | (B & BYTEMASK); break;
+ case TFR_EXG_Post_Nybble_X: Dest_Value = IX; break;
+ case TFR_EXG_Post_Nybble_Y: Dest_Value = IY; break;
+ case TFR_EXG_Post_Nybble_U: Dest_Value = UP; break;
+ case TFR_EXG_Post_Nybble_S: Dest_Value = SP; break;
+ case TFR_EXG_Post_Nybble_PC: Dest_Value = PC; break;
+ default: break;
+ }
+ }
+ if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) {
+ /* 8-bit register read */
+ /* read source register */
+ switch (Src_Nybble) {
+ case TFR_EXG_Post_Nybble_A: Src_Value = A; break;
+ case TFR_EXG_Post_Nybble_B: Src_Value = B; break;
+ case TFR_EXG_Post_Nybble_CC: Src_Value = CCR; break;
+ case TFR_EXG_Post_Nybble_DP: Src_Value = DP; break;
+ default: break;
+ }
+ /* read destination register */
+ switch (Dest_Nybble) {
+ case TFR_EXG_Post_Nybble_A: Dest_Value = A; break;
+ case TFR_EXG_Post_Nybble_B: Dest_Value = B; break;
+ case TFR_EXG_Post_Nybble_CC: Dest_Value = CCR; break;
+ case TFR_EXG_Post_Nybble_DP: Dest_Value = DP; break;
+ default: break;
+ }
+ }
+ /* write register values */
+ if (Src_Nybble <= 5 && Dest_Nybble <= 5) {
+ /* 16-bit register */
+ /* write source register */
+ switch (Src_Nybble) {
+ case TFR_EXG_Post_Nybble_D:
+ A = Dest_Value >> 8;
+ B = Dest_Value & 0XFF;
+ break;
+ case TFR_EXG_Post_Nybble_X: IX = Dest_Value; break;
+ case TFR_EXG_Post_Nybble_Y: IY = Dest_Value; break;
+ case TFR_EXG_Post_Nybble_U: UP = Dest_Value; break;
+ case TFR_EXG_Post_Nybble_S: SP = Dest_Value; break;
+ case TFR_EXG_Post_Nybble_PC: PC = Dest_Value; break;
+ default: break;
+ }
+ /* write destination register */
+ switch (Dest_Nybble) {
+ case TFR_EXG_Post_Nybble_D:
+ A = Src_Value >> 8;
+ B = Src_Value & 0XFF;
+ break;
+ case TFR_EXG_Post_Nybble_X: IX = Src_Value; break;
+ case TFR_EXG_Post_Nybble_Y: IY = Src_Value; break;
+ case TFR_EXG_Post_Nybble_U: UP = Src_Value; break;
+ case TFR_EXG_Post_Nybble_S: SP = Src_Value; break;
+ case TFR_EXG_Post_Nybble_PC: PC = Src_Value; break;
+ default: break;
+ }
+ }
+ if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) {
+ /* 8-bit register */
+ /* write source register */
+ switch (Src_Nybble) {
+ case TFR_EXG_Post_Nybble_A: A = Dest_Value; break;
+ case TFR_EXG_Post_Nybble_B: B = Dest_Value; break;
+ case TFR_EXG_Post_Nybble_CC: CCR = Dest_Value; break;
+ case TFR_EXG_Post_Nybble_DP: DP = Dest_Value; break;
+ default: break;
+ }
+ /* write destination register */
+ switch (Dest_Nybble) {
+ case TFR_EXG_Post_Nybble_A: A = Src_Value; break;
+ case TFR_EXG_Post_Nybble_B: B = Src_Value; break;
+ case TFR_EXG_Post_Nybble_CC: CCR = Src_Value; break;
+ case TFR_EXG_Post_Nybble_DP: DP = Src_Value; break;
+ default: break;
+ }
+ }
+ break;
+
+ case 0x1F: /* TFR imm */
+ Post_Byte = get_imm_byte_val();
+ Dest_Nybble = Post_Byte & 0x0F;
+ Src_Nybble = Post_Byte >> 4;
+ if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) {
+ // TFR with unaligned register sizes
+ // NOTE: Hitachi 6809 documentation does describe some scenarios for mis-matched register sizes!
+ reason = STOP_OPCODE;
+ }
+ if ((Src_Nybble <= 5) && (Dest_Nybble <= 5)) {
+ /* 16-bit registers */
+ /* read source register */
+ switch (Src_Nybble) {
+ case TFR_EXG_Post_Nybble_D: Src_Value = (A << 8) | (B & BYTEMASK); break;
+ case TFR_EXG_Post_Nybble_X: Src_Value = IX; break;
+ case TFR_EXG_Post_Nybble_Y: Src_Value = IY; break;
+ case TFR_EXG_Post_Nybble_U: Src_Value = UP; break;
+ case TFR_EXG_Post_Nybble_S: Src_Value = SP; break;
+ case TFR_EXG_Post_Nybble_PC: Src_Value = PC; break;
+ break;
+ }
+ /* write source register */
+ switch (Dest_Nybble) {
+ case TFR_EXG_Post_Nybble_D:
+ A = Src_Value >> 8;
+ B = Src_Value & 0XFF;
+ break;
+ case TFR_EXG_Post_Nybble_X: IX = Src_Value; break;
+ case TFR_EXG_Post_Nybble_Y: IY = Src_Value; break;
+ case TFR_EXG_Post_Nybble_U: UP = Src_Value; break;
+ case TFR_EXG_Post_Nybble_S: SP = Src_Value; break;
+ case TFR_EXG_Post_Nybble_PC: PC = Src_Value;; break;
+ break;
+ }
+ }
+ if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) {
+ /* 8-bit registers */
+ /* read the source register */
+ switch (Src_Nybble) {
+ case TFR_EXG_Post_Nybble_A: Src_Value = A; break;
+ case TFR_EXG_Post_Nybble_B: Src_Value = B; break;
+ case TFR_EXG_Post_Nybble_CC: Src_Value = CCR; break;
+ case TFR_EXG_Post_Nybble_DP: Src_Value = DP; break;
+ break;
+ }
+ /* write the destination register */
+ switch (Dest_Nybble) {
+ case TFR_EXG_Post_Nybble_A: A = Src_Value; break;
+ case TFR_EXG_Post_Nybble_B: B = Src_Value; break;
+ case TFR_EXG_Post_Nybble_CC: CCR = Src_Value; break;
+ case TFR_EXG_Post_Nybble_DP: DP = Src_Value; break;
+ break;
+ }
+ }
+ break;
+
+/* 0x20 - relative mode */
+ case 0x20: /* BRA rel */
+ go_rel(1);
+ break;
+ case 0x21: /* BRN rel */
+ /* Branch Never - essentially a NOP */
+ break;
+ case 0x22: /* BHI rel */
+ go_rel(!(get_flag(CF) || get_flag(ZF)));
+ break;
+ case 0x23: /* BLS rel */
+ go_rel(get_flag(CF) || get_flag(ZF));
+ break;
+ case 0x24: /* BCC rel */
+ go_rel(!get_flag(CF));
+ break;
+ case 0x25: /* BCS rel */
+ go_rel(get_flag(CF));
+ break;
+ case 0x26: /* BNE rel */
+ go_rel(!get_flag(ZF));
+ break;
+ case 0x27: /* BEQ rel */
+ go_rel(get_flag(ZF));
+ break;
+ case 0x28: /* BVC rel */
+ go_rel(!get_flag(VF));
+ break;
+ case 0x29: /* BVS rel */
+ go_rel(get_flag(VF));
+ break;
+ case 0x2A: /* BPL rel */
+ go_rel(!get_flag(NF));
+ break;
+ case 0x2B: /* BMI rel */
+ go_rel(get_flag(NF));
+ break;
+ case 0x2C: /* BGE rel */
+ go_rel(get_flag(NF) == get_flag(VF));
+ break;
+ case 0x2D: /* BLT rel */
+ go_rel(get_flag(NF) != get_flag(VF));
+ break;
+ case 0x2E: /* BGT rel */
+ go_rel((get_flag(ZF) == 0) && (get_flag(NF) == get_flag(VF)));
+ break;
+ case 0x2F: /* BLE rel */
+ go_rel(get_flag(ZF) || (get_flag(NF) != get_flag(VF)));
+ break;
+/* 0x30 */
+ case 0x30: /* LEAX ind */
+ IX = get_indexed_addr();
+ COND_SET_FLAG_Z_16(IX);
+ break;
+
+ case 0x31: /* LEAY ind */
+ IY = get_indexed_addr();
+ COND_SET_FLAG_Z_16(IY);
+ break;
+
+ case 0x32: /* LEAS ind */
+ SP = get_indexed_addr();
+ /* does not affect CCR */
+ break;
+
+ case 0x33: /* LEAU ind */
+ UP = get_indexed_addr();
+ /* does not affect CCR */
+ break;
+
+ case 0x34: /* PSHS */
+ Post_Byte = get_imm_byte_val();
+ if (Post_Byte & PSH_PUL_Post_Byte_PC) push_sp_word(PC);
+ if (Post_Byte & PSH_PUL_Post_Byte_S_U) push_sp_word(UP);
+ if (Post_Byte & PSH_PUL_Post_Byte_Y) push_sp_word(IY);
+ if (Post_Byte & PSH_PUL_Post_Byte_X) push_sp_word(IX);
+ if (Post_Byte & PSH_PUL_Post_Byte_DP) push_sp_byte(DP);
+ if (Post_Byte & PSH_PUL_Post_Byte_B) push_sp_byte(B);
+ if (Post_Byte & PSH_PUL_Post_Byte_A) push_sp_byte(A);
+ if (Post_Byte & PSH_PUL_Post_Byte_CC) push_sp_byte(CCR);
+ break;
+
+ case 0x35: /* PULS */
+ Post_Byte = get_imm_byte_val();
+ if (Post_Byte & PSH_PUL_Post_Byte_CC) CCR = pop_sp_byte();
+ if (Post_Byte & PSH_PUL_Post_Byte_A) A = pop_sp_byte();
+ if (Post_Byte & PSH_PUL_Post_Byte_B) B = pop_sp_byte();
+ if (Post_Byte & PSH_PUL_Post_Byte_DP) DP = pop_sp_byte();
+ if (Post_Byte & PSH_PUL_Post_Byte_X) IX = pop_sp_word();
+ if (Post_Byte & PSH_PUL_Post_Byte_Y) IY = pop_sp_word();
+ if (Post_Byte & PSH_PUL_Post_Byte_S_U) UP = pop_sp_word();
+ if (Post_Byte & PSH_PUL_Post_Byte_PC) PC = pop_sp_word();
+ break;
+
+ case 0x36: /* PSHU */
+ Post_Byte = get_imm_byte_val();
+ if (Post_Byte & PSH_PUL_Post_Byte_PC) push_up_word(PC);
+ if (Post_Byte & PSH_PUL_Post_Byte_S_U) push_up_word(SP);
+ if (Post_Byte & PSH_PUL_Post_Byte_Y) push_up_word(IY);
+ if (Post_Byte & PSH_PUL_Post_Byte_X) push_up_word(IX);
+ if (Post_Byte & PSH_PUL_Post_Byte_DP) push_up_byte(DP);
+ if (Post_Byte & PSH_PUL_Post_Byte_B) push_up_byte(B);
+ if (Post_Byte & PSH_PUL_Post_Byte_A) push_up_byte(A);
+ if (Post_Byte & PSH_PUL_Post_Byte_CC) push_up_byte(CCR);
+ break;
+
+ case 0x37: /* PULU */
+ Post_Byte = get_imm_byte_val();
+ if (Post_Byte & PSH_PUL_Post_Byte_CC) CCR = pop_up_byte();
+ if (Post_Byte & PSH_PUL_Post_Byte_A) A = pop_up_byte();
+ if (Post_Byte & PSH_PUL_Post_Byte_B) B = pop_up_byte();
+ if (Post_Byte & PSH_PUL_Post_Byte_DP) DP = pop_up_byte();
+ if (Post_Byte & PSH_PUL_Post_Byte_X) IX = pop_up_word();
+ if (Post_Byte & PSH_PUL_Post_Byte_Y) IY = pop_up_word();
+ if (Post_Byte & PSH_PUL_Post_Byte_S_U) SP = pop_up_word();
+ if (Post_Byte & PSH_PUL_Post_Byte_PC) PC = pop_up_word();
+ break;
+
+ case 0x39: /* RTS */
+ PC = pop_sp_word();
+ break;
+
+ case 0x3A: /* ABX */
+ /* this is an UNSIGNED operation! */
+ IX = (IX + B) & 0xFFFF;
+ /* no changes to CCR */
+ break;
+
+ case 0x3B: /* RTI */
+ CCR = pop_sp_byte();
+ if (get_flag(EF)) {
+ /* entire state flag */
+ A = pop_sp_byte();
+ B = pop_sp_byte();
+ DP = pop_sp_byte();
+ IX = pop_sp_word();
+ IY = pop_sp_word();
+ UP = pop_sp_word();
+ }
+ PC = pop_sp_word();
+ break;
+
+ case 0x3C: /* CWAI */
+ /* AND immediate byte with CCR
+ CCR &= get_imm_byte_val();
+ SET_FLAG(EF);
+ /* push register state */
+ push_sp_word(PC);
+ push_sp_word(UP);
+ push_sp_word(IY);
+ push_sp_word(IX);
+ push_sp_byte(DP);
+ push_sp_byte(B);
+ push_sp_byte(A);
+ push_sp_byte(CCR);
+ /* wait for an interrupt */
+ reason = STOP_HALT;
+ break;
+
+ case 0x3D: /* MUL */
+ D = A * B;
+ B = D & BYTEMASK;
+ A = D >> 8;
+ COND_SET_FLAG_Z_16(D);
+ COND_SET_FLAG(B & 0x80, CF);
+ break;
+
+ case 0x3F: /* SWI */
+ SET_FLAG(EF);
+ push_sp_word(PC);
+ push_sp_word(UP);
+ push_sp_word(IY);
+ push_sp_word(IX);
+ push_sp_byte(DP);
+ push_sp_byte(B);
+ push_sp_byte(A);
+ push_sp_byte(CCR);
+ SET_FLAG(FF);
+ SET_FLAG(IF);
+ PC = CPU_BD_get_mword(0xFFFA);
+ break;
+
+/* 0x40 - inherent mode */
+ case 0x40: /* NEGA */
+ COND_SET_FLAG(A != 0, CF);
+ COND_SET_FLAG(A == 0x80, VF);
+ A = 0 - A;
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ break;
+
+ case 0x43: /* COMA */
+ A = ~A;
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ SET_FLAG(CF);
+ break;
+
+ case 0x44: /* LSRA */
+ COND_SET_FLAG(A & 0x01, CF);
+ A = (A >> 1) & BYTEMASK;
+ CLR_FLAG(NF);
+ COND_SET_FLAG_Z(A);
+ /* H,V unaffected */
+ break;
+
+ case 0x46: /* RORA */
+ op1 = A;
+ A = A >> 1;
+ if (get_flag(CF)) {
+ A |= 0x80;
+ }
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ /* H,V unaffected */
+ COND_SET_FLAG(op1 & 0x01, CF);
+ break;
+
+ case 0x47: /* ASRA */
+ COND_SET_FLAG(A & 0x01, CF);
+ A = (A >> 1) | (A & 0x80);
+ /* H undefined */
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ /* V unaffected */
+ break;
+
+ case 0x48: /* ASLA */
+ op1 = A;
+ A = (A << 1) & BYTEMASK;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ COND_SET_FLAG(op1 & 0x80, CF);
+ COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF);
+ break;
+
+ case 0x49: /* ROLA */
+ op1 = A;
+ A = (A << 1) & BYTEMASK;
+ if (get_flag(CF)) {
+ A |= 0x01;
+ }
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ COND_SET_FLAG(op1 & 0x80, CF);
+ COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF);
+ break;
+
+ case 0x4A: /* DECA */
+ COND_SET_FLAG(A == 0x80, VF);
+ A = (A - 1) & BYTEMASK;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ /* C unaffected */
+ break;
+
+ case 0x4C: /* INCA */
+ COND_SET_FLAG(A == 0x7F, VF);
+ A = (A + 1) & BYTEMASK;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ /* C unaffected */
+ break;
+
+ case 0x4D: /* TSTA */
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ /* C unaffected */
+ break;
+
+ case 0x4F: /* CLRA */
+ A = 0;
+ CLR_FLAG(NF);
+ SET_FLAG(ZF);
+ CLR_FLAG(VF);
+ CLR_FLAG(CF);
+ break;
+
+/* 0x50 - inherent modes */
+ case 0x50: /* NEGB */
+ COND_SET_FLAG(B != 0, CF);
+ COND_SET_FLAG(B == 0x80, VF);
+ B = 0 - B;
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ break;
+
+ case 0x53: /* COMB */
+ B = ~B;
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ SET_FLAG(CF);
+ break;
+
+ case 0x54: /* LSRB */
+ COND_SET_FLAG(B & 0x01, CF);
+ B = (B >> 1) & BYTEMASK;
+ CLR_FLAG(NF);
+ COND_SET_FLAG_Z(B);
+ /* H,V unaffected */
+ break;
+
+ case 0x56: /* RORB */
+ op1 = B;
+ B = B >> 1;
+ if (get_flag(CF)) {
+ B |= 0x80;
+ }
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ /* H,V unaffected */
+ COND_SET_FLAG(op1 & 0x01, CF);
+ break;
+
+ case 0x57: /* ASRB */
+ COND_SET_FLAG(B & 0x01, CF);
+ B = (B >> 1) | (B & 0x80);
+ /* H undefined */
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ /* C unaffected */
+ break;
+
+ case 0x58: /* ASLB */
+ op1 = B;
+ B = (B << 1) & BYTEMASK;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ COND_SET_FLAG(op1 & 0x80, CF);
+ COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF);
+ break;
+
+ case 0x59: /* ROLB */
+ op1 = B;
+ B = (B << 1) & BYTEMASK;
+ if (get_flag(CF)) {
+ B |= 0x01;
+ }
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ COND_SET_FLAG(op1 & 0x80, CF);
+ COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF);
+ break;
+
+ case 0x5A: /* DECB */
+ COND_SET_FLAG(B == 0x80, VF);
+ B = (B - 1) & BYTEMASK;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ /* C unaffected */
+ break;
+
+ case 0x5C: /* INCB */
+ COND_SET_FLAG(B == 0x7F, VF);
+ B = (B + 1) & BYTEMASK;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ /* C unaffected */
+ break;
+
+ case 0x5D: /* TSTB */
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ /* C unaffected */
+ break;
+
+ case 0x5F: /* CLRB */
+ B = 0;
+ CLR_FLAG(NF);
+ SET_FLAG(ZF);
+ CLR_FLAG(VF);
+ CLR_FLAG(CF);
+ break;
+
+/* 0x60 - index mode */
+ case 0x60: /* NEG ind */
+ addr = get_indexed_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ COND_SET_FLAG(op1 != 0, CF);
+ COND_SET_FLAG(op1 == 0x80, VF);
+ result = (0 - op1) & BYTEMASK;
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ break;
+
+ case 0x63: /* COM ind */
+ addr = get_indexed_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (~op1) & 0xFF;
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ SET_FLAG(CF);
+ break;
+
+ case 0x64: /* LSR ind */
+ addr = get_indexed_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = op1 >> 1;
+ CPU_BD_put_mbyte(addr, result);
+ CLR_FLAG(NF);
+ COND_SET_FLAG_Z(result);
+ /* H,V unaffected */
+ COND_SET_FLAG(op1 & 0x01, CF);
+ break;
+
+ case 0x66: /* ROR ind */
+ addr = get_indexed_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = op1 >> 1;
+ if (get_flag(CF)) {
+ result |= 0x80;
+ }
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ /* H,V unaffected */
+ COND_SET_FLAG(op1 & 0x01, CF);
+ break;
+
+ case 0x67: /* ASR ind */
+ addr = get_indexed_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 >> 1) | (op1 & 0x80);
+ CPU_BD_put_mbyte(addr, result);
+ /* H undefined */
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ /* V unaffected */
+ COND_SET_FLAG(op1 & 0x01, CF);
+ break;
+
+ case 0x68: /* ASL ind */
+ addr = get_indexed_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 << 1) & BYTEMASK;
+ CPU_BD_put_mbyte(addr, result);
+ /* H is undefined */
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ COND_SET_FLAG(op1 & 0x80, CF);
+ COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF);
+ break;
+
+ case 0x69: /* ROL ind */
+ addr = get_indexed_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 << 1) & BYTEMASK;
+ if (get_flag(CF)) {
+ result |= 0x01;
+ }
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ COND_SET_FLAG(op1 & 0x80, CF);
+ COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF);
+ break;
+
+ case 0x6A: /* DEC ind */
+ addr = get_indexed_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 - 1) & BYTEMASK;
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ COND_SET_FLAG(op1 == 0x80, VF);
+ /* C unaffected */
+ break;
+
+ case 0x6C: /* INC ind */
+ addr = get_indexed_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 + 1) & BYTEMASK;
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ COND_SET_FLAG(op1 == 0x7F, VF);
+ /* C unaffected */
+ break;
+
+ case 0x6D: /* TST ind */
+ result = get_indexed_byte_val();
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ /* C unaffected */
+ break;
+
+ case 0x6E: /* JMP ind */
+ PC = get_indexed_addr();
+ break;
+
+ case 0x6F: /* CLR ind */
+ CPU_BD_put_mbyte(get_indexed_addr(), 0);
+ /* H not affected */
+ CLR_FLAG(NF);
+ SET_FLAG(ZF);
+ CLR_FLAG(VF);
+ CLR_FLAG(CF);
+ break;
+
+/* 0x70 - extended modes */
+ case 0x70: /* NEG ext */
+ addr= get_ext_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ COND_SET_FLAG(op1 != 0, CF);
+ COND_SET_FLAG(op1 == 0x80, VF) ;
+ result = (0 - op1) & BYTEMASK;
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ break;
+
+ case 0x73: /* COM ext */
+ addr = get_ext_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (~op1) & 0xFF;
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ SET_FLAG(CF);
+ break;
+
+ case 0x74: /* LSR ext */
+ addr = get_ext_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = op1 >> 1;
+ CPU_BD_put_mbyte(addr, result);
+ CLR_FLAG(NF);
+ COND_SET_FLAG_Z(result);
+ /* H,V unaffected */
+ COND_SET_FLAG(op1 & 0x01, CF);
+ break;
+
+ case 0x76: /* ROR ext */
+ addr = get_ext_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = op1 >> 1;
+ if (get_flag(CF)) {
+ result |= 0x80;
+ }
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ /* H,V unaffected */
+ COND_SET_FLAG(op1 & 0x01, CF);
+ break;
+
+ case 0x77: /* ASR ext */
+ addr = get_ext_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 >> 1) | (op1 & 0x80);
+ CPU_BD_put_mbyte(addr, result);
+ /* H undefined */
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ /* V unaffected */
+ COND_SET_FLAG(op1 & 0x01, CF);
+ break;
+
+ case 0x78: /* ASL ext */
+ addr = get_ext_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 << 1) & BYTEMASK;
+ CPU_BD_put_mbyte(addr, result);
+ /* H is undefined */
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ COND_SET_FLAG(op1 & 0x80, CF);
+ COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF);
+ break;
+
+ case 0x79: /* ROL ext */
+ addr = get_ext_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 << 1) & BYTEMASK;
+ if (get_flag(CF)) {
+ result |= 0x01;
+ }
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ COND_SET_FLAG(op1 & 0x80, CF);
+ COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF);
+ break;
+
+ case 0x7A: /* DEC ext */
+ addr = get_ext_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 - 1) & BYTEMASK;
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ COND_SET_FLAG(op1 == 0x80, VF);
+ /* C unaffected */
+ break;
+
+ case 0x7C: /* INC ext */
+ addr = get_ext_addr();
+ op1 = CPU_BD_get_mbyte(addr);
+ result = (op1 + 1) & BYTEMASK;
+ CPU_BD_put_mbyte(addr, result);
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ COND_SET_FLAG(op1 == 0x7F, VF);
+ /* C unaffected */
+ break;
+
+ /* C unaffected */
+ case 0x7D: /* TST ext */
+ result = get_ext_byte_val();
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ /* C unaffected */
+ break;
+
+ case 0x7E: /* JMP ext */
+ PC = get_ext_addr();
+ break;
+
+ case 0x7F: /* CLR ext */
+ CPU_BD_put_mbyte(get_ext_addr(), 0);
+ /* H not affected */
+ CLR_FLAG(NF);
+ SET_FLAG(ZF);
+ CLR_FLAG(VF);
+ CLR_FLAG(CF);
+ break;
+/* 0x80 - immediate mode (except for BSR) */
+ case 0x80: /* SUBA imm */
+ op1 = A;
+ op2 = get_imm_byte_val();
+ A = A - op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVs(op1, op2);
+ break;
+
+ case 0x81: /* CMPA imm */
+ /* Do not modify A */
+ op2 = get_imm_byte_val();
+ result = A - op2;
+ COND_SET_FLAG_C(result);
+ result &= 0xFF;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ condevalVs(A, op2);
+ break;
+
+ case 0x82: /* SBCA imm */
+ op1 = A;
+ op2 = get_imm_byte_val() + get_flag(CF);
+ A = A - op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVs(op1, op2);
+ break;
+
+ case 0x83: /* SUBD imm */
+ D = (A << 8) | (B & BYTEMASK);
+ op2 = get_imm_word_val();
+ result = D - op2;
+ COND_SET_FLAG_C_16(result);
+ result &= 0xFFFF;
+ A = result >> 8;
+ B = result & BYTEMASK;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(D, op2);
+ break;
+
+ case 0x84: /* ANDA imm */
+ A = (A & get_imm_byte_val()) & BYTEMASK;
+ CLR_FLAG(VF);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ break;
+
+ case 0x85: /* BITA imm */
+ /* Do not modify A */
+ result = (A & get_imm_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ break;
+
+ case 0x86: /* LDA imm */
+ A = get_imm_byte_val();
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0x88: /* EORA imm */
+ A = (A ^ get_imm_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0x89: /* ADCA imm */
+ op1 = A;
+ op2 = get_imm_byte_val() + get_flag(CF);
+ A = A + op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVa(op1, op2);
+ break;
+
+ case 0x8A: /* ORA imm */
+ A = A | get_imm_byte_val();
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0x8B: /* ADDA imm */
+ op1 = A;
+ op2 = get_imm_byte_val();
+ A = A + op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVa(op1, op2);
+ break;
+
+ case 0x8C: /* CMPX imm */
+ /* Do not modify X */
+ op2 = get_imm_word_val();
+ result = IX - op2;
+ COND_SET_FLAG_C_16(result);
+ result &= 0xFFFF;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(IX, op2);
+ break;
+
+ case 0x8D: /* BSR rel */
+ addr = get_rel_addr();
+ push_sp_word(PC);
+ PC = (PC + addr) & ADDRMASK;
+ break;
+
+ case 0x8E: /* LDX imm */
+ IX = get_imm_word_val();
+ COND_SET_FLAG_N_16(IX);
+ COND_SET_FLAG_Z_16(IX);
+ CLR_FLAG(VF);
+ break;
+
+/* 0x90 - direct mode */
+ case 0x90: /* SUBA dir */
+ op1 = A;
+ op2 = get_dir_byte_val();
+ A = A - op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVs(op1, op2);
+ break;
+
+ case 0x91: /* CMPA dir */
+ /* Do not modify A */
+ op2 = get_dir_byte_val();
+ result = A - op2;
+ COND_SET_FLAG_C(result);
+ result &= 0xFF;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ condevalVs(A, op2);
+ break;
+
+ case 0x92: /* SBCA dir */
+ op1 = A;
+ op2 = get_dir_byte_val() + get_flag(CF);
+ A = A - op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVs(op1, op2);
+ break;
+
+ case 0x93: /* SUBD dir */
+ D = (A << 8) | (B & BYTEMASK);
+ op2 = get_dir_word_val();
+ result = D - op2;
+ COND_SET_FLAG_C_16(result);
+ result &= 0xFFFF;
+ A = result >> 8;
+ B = result & BYTEMASK;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(D, op2);
+ break;
+
+ case 0x94: /* ANDA dir */
+ A = (A & get_dir_byte_val()) & BYTEMASK;
+ CLR_FLAG(VF);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ break;
+
+ case 0x95: /* BITA dir */
+ /* Do not modify A */
+ result = (A & get_dir_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ break;
+
+ case 0x96: /* LDA dir */
+ A = get_dir_byte_val();
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0x97: /* STA dir */
+ CPU_BD_put_mbyte(get_dir_addr(), A);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0x98: /* EORA dir */
+ A = (A ^ get_dir_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0x99: /* ADCA dir */
+ op1 = A;
+ op2 = get_dir_byte_val() + get_flag(CF);
+ A = A + op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVa(op1, op2);
+ break;
+
+ case 0x9A: /* ORA dir */
+ A = A | get_dir_byte_val();
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0x9B: /* ADDA dir */
+ op1 = A;
+ op2 = get_dir_byte_val();
+ A = A + op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVa(op1, op2);
+ break;
+
+ case 0x9C: /* CMPX dir */
+ /* Do not modify X */
+ op2 = get_dir_word_val();
+ result = IX - op2;
+ COND_SET_FLAG_C_16(result);
+ result &= 0xFFFF;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(IX, op2);
+ break;
+
+ case 0x9D: /* JSR dir */
+ addr = get_dir_addr();
+ push_sp_word(PC);
+ PC = addr;
+ break;
+
+ case 0x9E: /* LDX dir */
+ IX = get_dir_word_val();
+ COND_SET_FLAG_N_16(IX);
+ COND_SET_FLAG_Z_16(IX);
+ CLR_FLAG(VF);
+ break;
+
+ case 0x9F: /* STX dir */
+ CPU_BD_put_mword(get_dir_addr(), IX);
+ COND_SET_FLAG_N_16(IX);
+ COND_SET_FLAG_Z_16(IX);
+ CLR_FLAG(VF);
+ break;
+
+/* 0xA0 - indexed mode */
+ case 0xA0: /* SUBA ind */
+ op1 = A;
+ op2 = get_indexed_byte_val();
+ A = A - op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVs(op1, op2);
+ break;
+
+ case 0xA1: /* CMPA ind */
+ /* Do not modify A */
+ op2 = get_indexed_byte_val();
+ result = A - op2;
+ COND_SET_FLAG_C(result);
+ result &= 0xFF;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ condevalVs(A, op2);
+ break;
+
+ case 0xA2: /* SBCA ind */
+ op1 = A;
+ op2 = get_indexed_byte_val() + get_flag(CF);
+ A = A - op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVs(op1, op2);
+ break;
+
+ case 0xA3: /* SUBD ind */
+ D = (A << 8) | (B & BYTEMASK);
+ op2 = get_indexed_word_val();
+ result = D - op2;
+ COND_SET_FLAG_C_16(result);
+ result &= 0xFFFF;
+ A = result >> 8;
+ B = result & BYTEMASK;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(D, op2);
+ break;
+
+ case 0xA4: /* ANDA ind */
+ A = (A & get_indexed_byte_val()) & BYTEMASK;
+ CLR_FLAG(VF);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ break;
+
+ case 0xA5: /* BITA ind */
+ /* Do not modify A */
+ result = (A & get_indexed_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xA6: /* LDA ind */
+ A = get_indexed_byte_val();
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xA7: /* STA ind */
+ CPU_BD_put_mbyte(get_indexed_addr(), A);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xA8: /* EORA ind */
+ A = (A ^ get_indexed_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xA9: /* ADCA ind */
+ op1 = A;
+ op2 = get_indexed_byte_val() + get_flag(CF);
+ A = A + op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVa(op1, op2);
+ break;
+
+ case 0xAA: /* ORA ind */
+ A = A | get_indexed_byte_val();
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xAB: /* ADDA ind */
+ op1 = A;
+ op2 = get_indexed_byte_val();
+ A = A + op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVa(op1, op2);
+ break;
+
+ case 0xAC: /* CMPX ind */
+ /* Do not modify X */
+ op2 = get_indexed_word_val();
+ result = IX - op2;
+ COND_SET_FLAG_C_16(result);
+ result &= 0xFFFF;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(IX, op2);
+ break;
+
+ case 0xAD: /* JSR ind */
+ addr = get_indexed_addr();
+ push_sp_word(PC);
+ PC = addr;
+ break;
+
+ case 0xAE: /* LDX ind */
+ IX = get_indexed_word_val();
+ COND_SET_FLAG_N_16(IX);
+ COND_SET_FLAG_Z_16(IX);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xAF: /* STX ind */
+ CPU_BD_put_mword(get_indexed_addr(), IX);
+ COND_SET_FLAG_N_16(IX);
+ COND_SET_FLAG_Z_16(IX);
+ CLR_FLAG(VF);
+ break;
+
+/* 0xB0 - extended mode */
+ case 0xB0: /* SUBA ext */
+ op1 = A;
+ op2 = get_ext_byte_val();
+ A = A - op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVs(op1, op2);
+ break;
+
+ case 0xB1: /* CMPA ext */
+ /* Do not modify A */
+ op2 = get_ext_byte_val();
+ result = A - op2;
+ COND_SET_FLAG_C(result);
+ result &= 0xFF;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ condevalVs(A, op2);
+ break;
+
+ case 0xB2: /* SBCA ext */
+ op1 = A;
+ op2 = get_ext_byte_val() + get_flag(CF);
+ A = A - op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVs(op1, op2);
+ break;
+
+ case 0xB3: /* SUBD ext */
+ D = (A << 8) | (B & BYTEMASK);
+ op2 = get_ext_word_val();
+ result = D - op2;
+ COND_SET_FLAG_C_16(result);
+ result &= 0xFFFF;
+ A = result >> 8;
+ B = result & BYTEMASK;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(D, op2);
+ break;
+
+ case 0xB4: /* ANDA ext */
+ A = (A & get_ext_byte_val()) & BYTEMASK;
+ CLR_FLAG(VF);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ break;
+
+ case 0xB5: /* BITA ext */
+ /* Do not modify A */
+ result = (A & get_ext_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xB6: /* LDA ext */
+ A = get_ext_byte_val();
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xB7: /* STA ext */
+ CPU_BD_put_mbyte(get_ext_addr(), A);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xB8: /* EORA ext */
+ A = (A ^ get_ext_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xB9: /* ADCA ext */
+ op1 = A;
+ op2 = get_ext_byte_val() + get_flag(CF);
+ A = A + op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVa(op1, op2);
+ break;
+
+ case 0xBA: /* ORA ext */
+ A = A | get_ext_byte_val();
+ A &= 0xFF;
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xBB: /* ADDA ext */
+ op1 = A;
+ op2 = get_ext_byte_val();
+ A = A + op2;
+ COND_SET_FLAG_C(A);
+ A &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(A);
+ COND_SET_FLAG_Z(A);
+ condevalVa(op1, op2);
+ break;
+
+ case 0xBC: /* CMPX ext */
+ /* Do not modify X */
+ op2 = get_ext_word_val();
+ result = IX - op2;
+ COND_SET_FLAG_C_16(result);
+ result &= 0xFFFF;
+ COND_SET_FLAG_N_16(result);
+ COND_SET_FLAG_Z_16(result);
+ condevalVs16(IX, op2);
+ break;
+
+ case 0xBD: /* JSR ext */
+ addr = get_ext_addr();
+ push_sp_word(PC);
+ PC = addr;
+ break;
+
+ case 0xBE: /* LDX ext */
+ IX = get_ext_word_val();
+ COND_SET_FLAG_N_16(IX);
+ COND_SET_FLAG_Z_16(IX);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xBF: /* STX ext */
+ CPU_BD_put_mword(get_ext_addr(), IX);
+ COND_SET_FLAG_N_16(IX);
+ COND_SET_FLAG_Z_16(IX);
+ CLR_FLAG(VF);
+ break;
+
+/* 0xC0 - immediate mode */
+ case 0xC0: /* SUBB imm */
+ op1 = B;
+ op2 = get_imm_byte_val();
+ B = B - op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVs(op1, op2);
+ break;
+
+ case 0xC1: /* CMPB imm */
+ /* Do not modify B */
+ op2 = get_imm_byte_val();
+ result = B - op2;
+ COND_SET_FLAG_C(result);
+ result &= 0xFF;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ condevalVs(B, op2);
+ break;
+
+ case 0xC2: /* SBCB imm */
+ op1 = B;
+ op2 = get_imm_byte_val() + get_flag(CF);
+ B = B - op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVs(op1, op2);
+ break;
+
+ case 0xC3: /* ADDD imm */
+ op1 = (A << 8) | (B & BYTEMASK);
+ op2 = get_imm_word_val();
+ D = op1 + op2;
+ COND_SET_FLAG_C_16(D);
+ D &= 0xFFFF;
+ A = D >> 8;
+ B = D & BYTEMASK;
+ COND_SET_FLAG_N_16(D);
+ COND_SET_FLAG_Z_16(D);
+ condevalVa16(op1, op2);
+ break;
+
+ case 0xC4: /* ANDB imm */
+ B = (B & get_imm_byte_val()) & BYTEMASK;
+ CLR_FLAG(VF);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ break;
+
+ case 0xC5: /* BITB imm */
+ /* Do not modify B */
+ result = (B & get_imm_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xC6: /* LDB imm */
+ B = get_imm_byte_val();
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xC8: /* EORB imm */
+ B = (B ^ get_imm_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xC9: /* ADCB imm */
+ op1 = B;
+ op2 = get_imm_byte_val() + get_flag(CF);
+ B = B + op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVa(op1, op2);
+ break;
+
+ case 0xCA: /* ORB imm */
+ B = B | get_imm_byte_val();
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xCB: /* ADDB imm */
+ op1 = B;
+ op2 = get_imm_byte_val();
+ B = B + op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVa(op1, op2);
+ break;
+
+ case 0xCC: /* LDD imm */
+ D = get_imm_word_val();
+ B = D & BYTEMASK;
+ A = D >> 8;
+ COND_SET_FLAG_N_16(D);
+ COND_SET_FLAG_Z_16(D);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xCE: /* LDU imm */
+ UP = get_imm_word_val();
+ COND_SET_FLAG_N_16(UP);
+ COND_SET_FLAG_Z_16(UP);
+ CLR_FLAG(VF);
+ break;
+
+/* 0xD0 - direct modes */
+ case 0xD0: /* SUBB dir */
+ op1 = B;
+ op2 = get_dir_byte_val();
+ B = B - op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVs(op1, op2);
+ break;
+
+ case 0xD1: /* CMPB dir */
+ /* Do not modify B */
+ op2 = get_dir_byte_val();
+ result = B - op2;
+ COND_SET_FLAG_C(result);
+ result &= 0xFF;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ condevalVs(B, op2);
+ break;
+
+ case 0xD2: /* SBCB dir */
+ op1 = B;
+ op2 = get_dir_byte_val() + get_flag(CF);
+ B = B - op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVs(op1, op2);
+ break;
+
+ case 0xD3: /* ADDD dir */
+ op1 = (A << 8) | (B & BYTEMASK);
+ op2 = get_dir_word_val();
+ D = op1 + op2;
+ COND_SET_FLAG_C_16(D);
+ D &= 0xFFFF;
+ A = D >> 8;
+ B = D & BYTEMASK;
+ COND_SET_FLAG_N_16(D);
+ COND_SET_FLAG_Z_16(D);
+ condevalVa16(op1, op2);
+ break;
+
+ case 0xD4: /* ANDB dir */
+ B = (B & get_dir_byte_val()) & BYTEMASK;
+ CLR_FLAG(VF);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ break;
+
+ case 0xD5: /* BITB dir */
+ /* Do not modify B */
+ result = (B & get_dir_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xD6: /* LDB dir */
+ B = get_dir_byte_val();
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xD7: /* STB dir */
+ CPU_BD_put_mbyte(get_dir_addr(), B);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xD8: /* EORB dir */
+ B = (B ^ get_dir_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xD9: /* ADCB dir */
+ op1 = B;
+ op2 = get_dir_byte_val() + get_flag(CF);
+ B = B + op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVa(op1, op2);
+ break;
+
+ case 0xDA: /* ORB dir */
+ B = B | get_dir_byte_val();
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xDB: /* ADDB dir */
+ op1 = B;
+ op2 = get_dir_byte_val();
+ B = B + op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVa(op1, op2);
+ break;
+
+ case 0xDC: /* LDD dir */
+ D = get_dir_word_val();
+ B = D & BYTEMASK;
+ A = D >> 8;
+ COND_SET_FLAG_N_16(D);
+ COND_SET_FLAG_Z_16(D);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xDD: /* STD dir */
+ D = (A << 8) | (B & BYTEMASK);
+ CPU_BD_put_mword(get_dir_addr(), D);
+ COND_SET_FLAG_N_16(D);
+ COND_SET_FLAG_Z_16(D);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xDE: /* LDU dir */
+ UP = get_dir_word_val();
+ COND_SET_FLAG_N_16(UP);
+ COND_SET_FLAG_Z_16(UP);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xDF: /* STU dir */
+ CPU_BD_put_mword(get_dir_addr(), UP);
+ COND_SET_FLAG_N_16(UP);
+ COND_SET_FLAG_Z_16(UP);
+ CLR_FLAG(VF);
+ break;
+
+/* 0xE0 - indexed mode */
+ case 0xE0: /* SUBB ind */
+ op1 = B;
+ op2 = get_indexed_byte_val();
+ B = B - op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVs(op1, op2);
+ break;
+
+ case 0xE1: /* CMPB ind */
+ /* do not modify B */
+ op2 = get_indexed_byte_val();
+ result = B - op2;
+ COND_SET_FLAG_C(result);
+ result &= 0xFF;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ condevalVs(B, op2);
+ break;
+
+ case 0xE2: /* SBCB ind */
+ op1 = B;
+ op2 = get_indexed_byte_val() + get_flag(CF);
+ B = B - op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVs(op1, op2);
+ break;
+
+ case 0xE3: /* ADDD ind */
+ op1 = (A << 8) | (B & BYTEMASK);
+ op2 = get_indexed_word_val();
+ D = op1 + op2;
+ COND_SET_FLAG_C_16(D);
+ D &= 0xFFFF;
+ A = D >> 8;
+ B = D & BYTEMASK;
+ COND_SET_FLAG_N_16(D);
+ COND_SET_FLAG_Z_16(D);
+ condevalVa16(op1, op2);
+ break;
+
+ case 0xE4: /* ANDB ind */
+ B = (B & get_indexed_byte_val()) & BYTEMASK;
+ CLR_FLAG(VF);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ break;
+
+ case 0xE5: /* BITB ind */
+ /* Do not modify B */
+ result = (B & get_indexed_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xE6: /* LDB ind */
+ B = get_indexed_byte_val();
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xE7: /* STB ind */
+ CPU_BD_put_mbyte(get_indexed_addr(), B);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xE8: /* EORB ind */
+ B = (B ^ get_indexed_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xE9: /* ADCB ind */
+ op1 = B;
+ op2 = get_indexed_byte_val() + get_flag(CF);
+ B = B + op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVa(op1, op2);
+ break;
+
+ case 0xEA: /* ORB ind */
+ B = B | get_indexed_byte_val();
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xEB: /* ADDB ind */
+ op1 = B;
+ op2 = get_indexed_byte_val();
+ B = B + op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVa(op1, op2);
+ break;
+
+ case 0xEC: /* LDD ind */
+ D = get_indexed_word_val();
+ B = D & BYTEMASK;
+ A = D >> 8;
+ COND_SET_FLAG_N_16(D);
+ COND_SET_FLAG_Z_16(D);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xED: /* STD ind */
+ D = (A << 8) | (B & BYTEMASK);
+ CPU_BD_put_mword(get_indexed_addr(), D);
+ COND_SET_FLAG_N_16(D);
+ COND_SET_FLAG_Z_16(D);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xEE: /* LDU ind */
+ UP = get_indexed_word_val();
+ COND_SET_FLAG_N_16(UP);
+ COND_SET_FLAG_Z_16(UP);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xEF: /* STU ind */
+ CPU_BD_put_mword(get_indexed_addr(), UP);
+ COND_SET_FLAG_N_16(UP);
+ COND_SET_FLAG_Z_16(UP);
+ CLR_FLAG(VF);
+ break;
+
+/* 0xF0 - extended mode */
+ case 0xF0: /* SUBB ext */
+ op1 = B;
+ op2 = get_ext_byte_val();
+ B = B - op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVs(op1, op2);
+ break;
+
+ case 0xF1: /* CMPB ext */
+ /* Do not modify B */
+ op2 = get_ext_byte_val();
+ result = B - op2;
+ COND_SET_FLAG_C(result);
+ result &= 0xFF;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ condevalVs(B, op2);
+ break;
+
+ case 0xF2: /* SBCB ext */
+ op1 = B;
+ op2 = get_ext_byte_val() + get_flag(CF);
+ B = B - op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVs(op1, op2);
+ break;
+
+ case 0xF3: /* ADDD ext */
+ op1 = (A << 8) | (B & BYTEMASK);
+ op2 = get_ext_word_val();
+ D = op1 + op2;
+ COND_SET_FLAG_C_16(D);
+ D &= 0xFFFF;
+ A = D >> 8;
+ B = D & BYTEMASK;
+ COND_SET_FLAG_N_16(D);
+ COND_SET_FLAG_Z_16(D);
+ condevalVa16(op1, op2);
+ break;
+
+ case 0xF4: /* ANDB ext */
+ B = (B & get_ext_byte_val()) & BYTEMASK;
+ CLR_FLAG(VF);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ break;
+
+ case 0xF5: /* BITB ext */
+ /* Do not modify B */
+ result = (B & get_ext_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(result);
+ COND_SET_FLAG_Z(result);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xF6: /* LDB ext */
+ B = get_ext_byte_val();
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xF7: /* STB ext */
+ CPU_BD_put_mbyte(get_ext_addr(), B);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xF8: /* EORB ext */
+ B = (B ^ get_ext_byte_val()) & BYTEMASK;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xF9: /* ADCB ext */
+ op1 = B;
+ op2 = get_ext_byte_val() + get_flag(CF);
+ B = B + op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVa(op1, op2);
+ break;
+
+ case 0xFA: /* ORB ext */
+ B = B | get_ext_byte_val();
+ B &= 0xFF;
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xFB: /* ADDB ext */
+ op1 = B;
+ op2 = get_ext_byte_val();
+ B = B + op2;
+ COND_SET_FLAG_C(B);
+ B &= 0xFF;
+ condevalHa(op1, op2);
+ COND_SET_FLAG_N(B);
+ COND_SET_FLAG_Z(B);
+ condevalVa(op1, op2);
+ break;
+
+ case 0xFC: /* LDD ext */
+ D = get_ext_word_val();
+ B = D & BYTEMASK;
+ A = D >> 8;
+ COND_SET_FLAG_N_16(D);
+ COND_SET_FLAG_Z_16(D);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xFD: /* STD ext */
+ D = (A << 8) | (B & BYTEMASK);
+ CPU_BD_put_mword(get_ext_addr(), D);
+ COND_SET_FLAG_N_16(D);
+ COND_SET_FLAG_Z_16(D);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xFE: /* LDU ext */
+ UP = get_ext_word_val();
+ COND_SET_FLAG_N_16(UP);
+ COND_SET_FLAG_Z_16(UP);
+ CLR_FLAG(VF);
+ break;
+
+ case 0xFF: /* STU ext */
+ CPU_BD_put_mword(get_ext_addr(), UP);
+ COND_SET_FLAG_N_16(UP);
+ COND_SET_FLAG_Z_16(UP);
+ CLR_FLAG(VF);
+ break;
+
+ default: /* Unassigned opcode */
+ if (m6809_unit.flags & UNIT_OPSTOP) {
+ reason = STOP_OPCODE;
+ PC--;
+ }
+ break;
+ }
+ }
+ /* Simulation halted - lets dump all the registers! */
+ //dump_regs();
+ saved_PC = PC;
+ return reason;
+}
+
+/* dump the working registers */
+
+void dump_regs(void)
+{
+ printf("\r\nPC=%04X SP=%04X UP=%04X IX=%04X IY=%04X ", PC, SP, UP, IX, IY);
+ printf("A=%02X B=%02X DP=%02X CCR=%02X", A, B, DP, CCR);
+}
+
+void dump_regs1(void)
+{
+ printf("PC=%04X SP=%04X UP=%04X IX=%04X IY=%04X ", PC, SP, UP, IX, IY);
+ printf("A=%02X B=%02X DP=%02X CCR=%02X\n", A, B, DP, CCR);
+}
+
+/* fetch an instruction or byte */
+int32 fetch_byte(int32 flag)
+{
+ int32 val;
+
+ val = CPU_BD_get_mbyte(PC); /* fetch byte */
+ if (flag == 0) {
+ /* opcode fetch */
+ sim_debug(DEBUG_asm, &m6809_dev, "%04X: %s\n", PC, opcode[val]);
+ } else {
+ /* byte operand fetch */
+ sim_debug(DEBUG_asm, &m6809_dev, "%04X: 0x%02XH\n", PC, val);
+ }
+ PC = (PC + 1) & ADDRMASK; /* increment PC */
+ return val;
+}
+
+/* fetch a word - big endian */
+int32 fetch_word()
+{
+ int32 val;
+ int32 temp_pc = PC;
+
+ val = CPU_BD_get_mbyte(PC) << 8; /* fetch high byte */
+ PC = (PC + 1) & ADDRMASK;
+ val = val | CPU_BD_get_mbyte(PC); /* fetch low byte */
+ PC = (PC + 1) & ADDRMASK;
+
+ /* 2-byte operand fetch */
+ sim_debug(DEBUG_asm, &m6809_dev, "%04X: 0x%04XH\n", temp_pc, val);
+ return val;
+}
+
+/* push a byte using the hardware stack pointer (SP) */
+void push_sp_byte(uint8 val)
+{
+ SP = (SP - 1) & ADDRMASK;
+ CPU_BD_put_mbyte(SP, val & BYTEMASK);
+}
+
+/* push a byte using the user stack pointer (UP) */
+void push_up_byte(uint8 val)
+{
+ UP = (UP - 1) & ADDRMASK;
+ CPU_BD_put_mbyte(UP, val & BYTEMASK);
+}
+
+/* push a word using the hardware stack pointer (SP) */
+void push_sp_word(uint16 val)
+{
+ push_sp_byte(val & BYTEMASK);
+ push_sp_byte(val >> 8);
+}
+
+/* push a word using the user stack pointer (UP) */
+void push_up_word(uint16 val)
+{
+ push_up_byte(val & BYTEMASK);
+ push_up_byte(val >> 8);
+}
+
+/* pop a byte using the hardware stack pointer (SP) */
+uint8 pop_sp_byte(void)
+{
+ register uint8 res;
+
+ res = CPU_BD_get_mbyte(SP);
+ SP = (SP + 1) & ADDRMASK;
+ return res;
+}
+
+/* pop a byte using the user stack pointer (UP) */
+uint8 pop_up_byte(void)
+{
+ register uint8 res;
+
+ res = CPU_BD_get_mbyte(UP);
+ UP = (UP + 1) & ADDRMASK;
+ return res;
+}
+
+/* pop a word using the hardware stack pointer (SP) */
+uint16 pop_sp_word(void)
+{
+ register uint16 res;
+
+ res = pop_sp_byte() << 8;
+ res |= pop_sp_byte();
+ return res;
+}
+
+/* pop a word using the user stack pointer (UP) */
+uint16 pop_up_word(void)
+{
+ register uint16 res;
+
+ res = pop_up_byte() << 8;
+ res |= pop_up_byte();
+ return res;
+}
+
+/* this routine does the jump to relative offset if the condition is met. Otherwise, execution continues at the current PC. */
+void go_rel(int32 cond)
+{
+ int32 temp;
+
+ temp = get_rel_addr();
+ if (cond != 0) {
+ PC += temp;
+ PC &= ADDRMASK;
+ }
+}
+
+/* this routine does the jump to long relative offset if the condition is met. Otherwise, execution continues at the current PC. */
+void go_long_rel(int32 cond)
+{
+ int32 temp;
+
+ temp = get_long_rel_addr();
+ if (cond != 0) {
+ PC += temp;
+ PC &= ADDRMASK;
+ }
+}
+
+/* returns the relative offset sign-extended */
+int32 get_rel_addr(void)
+{
+ int32 temp;
+
+ temp = fetch_byte(1);
+ if (temp & 0x80)
+ temp |= 0xFF00;
+ return(temp & ADDRMASK);
+}
+
+/* returns the long relative offset sign-extended */
+int32 get_long_rel_addr(void)
+{
+ return(fetch_word());
+}
+
+/* returns the byte value at the direct address pointed to by PC */
+int32 get_dir_byte_val(void)
+{
+ return(CPU_BD_get_mbyte(get_dir_addr()));
+}
+
+/* returns the word value at the direct address pointed to by PC */
+int32 get_dir_word_val(void)
+{
+ return(CPU_BD_get_mword(get_dir_addr()));
+}
+
+/* returns the immediate byte value pointed to by PC */
+int32 get_imm_byte_val(void)
+{
+ return(fetch_byte(1));
+}
+
+/* returns the immediate word value pointed to by PC */
+int32 get_imm_word_val(void)
+{
+ return(fetch_word());
+}
+
+/* returns the direct address pointed to by PC */
+/* use the Direct Page register as the high byte of the address */
+int32 get_dir_addr(void)
+{
+ int32 temp;
+
+ temp = (DP << 8) + fetch_byte(1);
+ return(temp & ADDRMASK);
+}
+
+/* returns the byte value at the indexed address pointed to by PC */
+int32 get_indexed_byte_val(void)
+{
+ return(CPU_BD_get_mbyte(get_indexed_addr()));
+}
+
+/* returns the word value at the indexed address pointed to by PC */
+int32 get_indexed_word_val(void)
+{
+ return(CPU_BD_get_mword(get_indexed_addr()));
+}
+
+/* returns the indexed address. Note this also handles the indirect indexed mode */
+int32 get_indexed_addr(void)
+{
+ int32 temp;
+ int32 offset;
+ uint8 post_byte;
+
+ /* fetch the index mode post-byte */
+ post_byte = fetch_byte(1);
+
+ if ((post_byte & 0x80) == 0) {
+ /* R +- 4-bit offset (non indirect only) */
+ /* read register value */
+ switch (post_byte & 0x60) {
+ case 0b00000000: temp = IX; break;
+ case 0b00100000: temp = IY; break;
+ case 0b01000000: temp = UP; break;
+ case 0b01100000: temp = SP; break;
+ default: break;
+ }
+ /* add 4 bit signed offset */
+ if (post_byte & 0x10) {
+ temp += (post_byte | 0xFFF0);
+ } else {
+ temp += (post_byte & 0x0F);
+ }
+ } else {
+ switch ( post_byte & 0x0F ) {
+ case 0b0000:
+ /* .R+ post increment by 1 (non indirect) */
+ switch ( post_byte & 0x60 ) {
+ case 0b00000000: temp = IX++; IX &= 0xFFFF; break;
+ case 0b00100000: temp = IY++; IY &= 0xFFFF; break;
+ case 0b01000000: temp = UP++; UP &= 0xFFFF; break;
+ case 0b01100000: temp = SP++; SP &= 0xFFFF; break;
+ default: break;
+ };
+ break;
+ case 0b0001:
+ /* .R+ post increment by 2 (non indirect) */
+ switch ( post_byte & 0x60 ) {
+ case 0b00000000: temp = IX; IX=IX+2; IX &= 0xFFFF; break;
+ case 0b00100000: temp = IY; IY=IY+2; IY &= 0xFFFF; break;
+ case 0b01000000: temp = UP; UP=UP+2; UP &= 0xFFFF; break;
+ case 0b01100000: temp = SP; SP=SP+2; SP &= 0xFFFF; break;
+ default: break;
+ };
+ break;
+ case 0b0010:
+ /* .-R pre decrement by 1 (non indirect) */
+ switch ( post_byte & 0x60 ) {
+ case 0b00000000: temp = --IX; IX &= 0xFFFF; break;
+ case 0b00100000: temp = --IY; IY &= 0xFFFF; break;
+ case 0b01000000: temp = --UP; UP &= 0xFFFF; break;
+ case 0b01100000: temp = --SP; SP &= 0xFFFF; break;
+ default: break;
+ };
+ break;
+ case 0b0011:
+ /* .--R pre decrement by 2 (non indirect) */
+ switch ( post_byte & 0x60 ) {
+ case 0b00000000: IX-=2; temp = IX; IX &= 0xFFFF; break;
+ case 0b00100000: IY-=2; temp = IY; IY &= 0xFFFF; break;
+ case 0b01000000: UP-=2; temp = UP; UP &= 0xFFFF; break;
+ case 0b01100000: SP-=2; temp = SP; SP &= 0xFFFF; break;
+ default: break;
+ };
+ break;
+ case 0b0100:
+ /* R+0 zero offset (non indirect) */
+ switch ( post_byte & 0x60 ) {
+ case 0b00000000: temp = IX; break;
+ case 0b00100000: temp = IY; break;
+ case 0b01000000: temp = UP; break;
+ case 0b01100000: temp = SP; break;
+ default: break;
+ };
+ break;
+ case 0b0101:
+ /* R+-ACCB (non indirect)*/
+ switch ( post_byte & 0x60 ) {
+ case 0b00000000: temp = IX; break;
+ case 0b00100000: temp = IY; break;
+ case 0b01000000: temp = UP; break;
+ case 0b01100000: temp = SP; break;
+ default: break;
+ };
+ if (B & 0x80) {
+ offset = B | 0xFF80;
+ } else {
+ offset = B;
+ }
+ temp += offset;
+ break;
+ case 0b0110:
+ /* R+-ACCA (non indirect)*/
+ switch ( post_byte & 0x60 ) {
+ case 0b00000000: temp = IX; break;
+ case 0b00100000: temp = IY; break;
+ case 0b01000000: temp = UP; break;
+ case 0b01100000: temp = SP; break;
+ default: break;
+ };
+ if (A & 0x80) {
+ offset = A | 0xFF80;
+ } else {
+ offset = A;
+ }
+ temp += offset;
+ break;
+ case 0b1000:
+ /* R+- 8-bit offset */
+ switch ( post_byte & 0x60 ) {
+ case 0b00000000: temp = IX; break;
+ case 0b00100000: temp = IY; break;
+ case 0b01000000: temp = UP; break;
+ case 0b01100000: temp = SP; break;
+ default: break;
+ };
+ /* need to fetch 8-bit operand */
+ offset = fetch_byte(1);
+ /* add 7 bit signed offset */
+ if (offset & 0x80) {
+ temp += offset | 0xFF80;
+ } else {
+ temp += offset;
+ }
+ break;
+ case 0b1001:
+ /* R+- 16-bit offset */
+ switch ( post_byte & 0x60 ) {
+ case 0b00000000: temp = IX; break;
+ case 0b00100000: temp = IY; break;
+ case 0b01000000: temp = UP; break;
+ case 0b01100000: temp = SP; break;
+ default: break;
+ };
+ /* need to fetch 16-bit operand */
+ offset = fetch_word();
+ /* add 16 bit signed offset */
+ /* calculation is the same for negative or positive offset! */
+ temp += offset;
+ break;
+ case 0b1011:
+ /* R+- ACCD */
+ D = (A << 8) + (B & BYTEMASK);
+ switch ( post_byte & 0x60 ) {
+ case 0b00000000: temp = IX + D; break;
+ case 0b00100000: temp = IY + D; break;
+ case 0b01000000: temp = UP + D; break;
+ case 0b01100000: temp = SP + D; break;
+ default: break;
+ };
+ break;
+ case 0b1100:
+ /* PC+- 7-bit offset (non indirect) */
+ /* need to fetch 8-bit operand */
+ offset = fetch_byte(1);
+ // PC value updated after fetch!!!
+
+ /* add 7 bit signed offset */
+ if (offset & 0x80) {
+ temp = PC + (offset | 0xFF80);
+ } else {
+ temp = PC + offset;
+ }
+ break;
+ case 0b1101:
+ /* PC+- 15-bit offset (non indirect)*/
+ /* need to fetch 16-bit operand */
+ offset = fetch_word();
+ // PC value updated after fetch!!!
+
+ /* add 15 bit signed offset */
+ temp = PC + offset;
+ break;
+ case 0b1111:
+ // Extended indirect - fetch 16-bit address
+ temp = fetch_word();
+ break;
+ }
+ switch ( post_byte & 0x1F ) {
+ /* perform the indirection - 11 valid post-byte opcodes */
+ case 0b10001:
+ case 0b10011:
+ case 0b10100:
+ case 0b10101:
+ case 0b10110:
+ case 0b11000:
+ case 0b11001:
+ case 0b11011:
+ case 0b11100:
+ case 0b11101:
+ case 0b11111:
+ temp = temp & 0xFFFF;
+ temp = CPU_BD_get_mword(temp);
+ break;
+ default: break;
+ }
+ }
+ /* make sure to truncate to 16-bit value */
+ return(temp & 0xFFFF);
+}
+
+/* returns the value at the extended address pointed to by PC */
+int32 get_ext_byte_val(void)
+{
+ return CPU_BD_get_mbyte(get_ext_addr());
+}
+
+/* returns the value at the extended address pointed to by PC */
+int32 get_ext_word_val(void)
+{
+ return CPU_BD_get_mword(get_ext_addr());
+}
+
+/* returns the extended address pointed to by PC or immediate word */
+int32 get_ext_addr(void)
+{
+ int32 temp;
+
+ temp = fetch_word();
+ return temp;
+}
+
+/* return 1 for flag set or 0 for flag clear */
+inline int32 get_flag(int32 flg)
+{
+ if (CCR & flg) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+/* test and set V for 8-addition */
+void condevalVa(int32 op1, int32 op2)
+{
+ int32 temp;
+
+ /* op1 + op2 */
+ // If 2 Two's Complement numbers are added, and they both have the same sign (both positive or both negative),
+ // then overflow occurs if and only if the result has the opposite sign.
+ // Overflow never occurs when adding operands with different signs.
+ temp = op1 + op2;
+ if ( ((op1 & 0x80) == (op2 & 0x80)) && ((temp & 0x80) != (op1 & 0x80)) ) {
+ SET_FLAG(VF);
+ } else {
+ CLR_FLAG(VF);
+ }
+}
+
+/* test and set V for 16-bit addition */
+void condevalVa16(int32 op1, int32 op2)
+{
+ int32 temp;
+
+ /* op1 + op2 */
+ // If 2 Two's Complement numbers are added, and they both have the same sign (both positive or both negative),
+ // then overflow occurs if and only if the result has the opposite sign.
+ // Overflow never occurs when adding operands with different signs.
+ temp = op1 + op2;
+ if ( ((op1 & 0x8000) == (op2 & 0x8000)) && ((temp & 0x8000) != (op1 & 0x8000)) ) {
+ SET_FLAG(VF);
+ } else {
+ CLR_FLAG(VF);
+ }
+}
+
+/* test and set V for 8-bit subtraction */
+void condevalVs(int32 op1, int32 op2)
+{
+ int32 temp;
+
+ /* op1 - op2 */
+ // If 2 Two's Complement numbers are subtracted, and their signs are different,
+ // then overflow occurs if and only if the result has the same sign as the subtrahend (op2).
+ temp = op1 - op2;
+ if ( ((op1 & 0x80) != (op2 & 0x80)) && ((temp & 0x80) == (op2 & 0x80)) ) {
+ SET_FLAG(VF);
+ } else {
+ CLR_FLAG(VF);
+ }
+}
+
+/* test and set V for 16-bit subtraction */
+void condevalVs16(int32 op1, int32 op2)
+{
+ int32 temp;
+
+ /* op1 - op2 */
+ // If 2 Two's Complement numbers are subtracted, and their signs are different,
+ // then overflow occurs if and only if the result has the same sign as the subtrahend (op2).
+ temp = op1 - op2;
+ if ( ((op1 & 0x8000) != (op2 & 0x8000)) && ((temp & 0x8000) == (op2 & 0x8000)) ) {
+ SET_FLAG(VF);
+ } else {
+ CLR_FLAG(VF);
+ }
+}
+
+/* test and set H for addition (8-bit only) */
+void condevalHa(int32 op1, int32 op2)
+{
+ if (((op1 & 0x0F) + (op2 & 0x0F)) > 0x0F)
+ SET_FLAG(HF);
+ else
+ CLR_FLAG(HF);
+}
+
+/* calls from the simulator */
+
+/* Boot routine */
+t_stat m6809_boot(int32 unit_num, DEVICE *dptr)
+{
+ sim_debug(DEBUG_flow, &m6809_dev, "Call to m6809_boot()\n");
+
+ /* retrieve the reset vector at $FFFE */
+ saved_PC = CPU_BD_get_mword(0xFFFE);
+ if (saved_PC == 0xFFFF) {
+ ; // No BOOT ROM detected!
+ }
+ return SCPE_OK;
+}
+
+/* Reset routine */
+t_stat m6809_reset (DEVICE *dptr)
+{
+ sim_debug(DEBUG_flow, &m6809_dev, "Call to m6809_reset()\n");
+
+ CCR = EF | FF | IF;
+ DP = 0;
+ int_req = 0;
+ sim_brk_types = sim_brk_dflt = SWMASK ('E');
+
+ /* retrieve the reset vector at $FFFE */
+ saved_PC = CPU_BD_get_mword(0xFFFE);
+ if (saved_PC == 0xFFFF) {
+ ; // No BOOT ROM detected!
+ }
+ return SCPE_OK;
+}
+
+/* examine routine */
+t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches)
+{
+ sim_debug(DEBUG_flow, &m6809_dev, "Call to m6809_examine()\n");
+
+ if (addr > ADDRMASK) {
+ /* exceed 16-bit address space */
+ return SCPE_NXM;
+ } else {
+ if (eval_array != NULL) {
+ *eval_array = CPU_BD_get_mbyte(addr);
+ }
+ return SCPE_OK;
+ }
+}
+
+/* deposit routine */
+t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches)
+{
+ sim_debug(DEBUG_flow, &m6809_dev, "Call to m6809_deposit()\n");
+
+ if (addr > ADDRMASK) {
+ /* exceed 16-bit address space */
+ return SCPE_NXM;
+ } else {
+ CPU_BD_put_mbyte(addr, value);
+ return SCPE_OK;
+ }
+}
+
+
+/* This is the dumper/loader. This command uses the -h to signify a
+ hex dump/load vice a binary one. If no address is given to load, it
+ takes the address from the hex record or the current PC for binary.
+*/
+
+t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag)
+{
+ int32 i, addr = 0, cnt = 0;
+
+ sim_debug(DEBUG_flow, &m6809_dev, "Call to sim_load()\n");
+
+ if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
+ addr = saved_PC;
+ while ((i = getc (fileref)) != EOF) {
+ CPU_BD_put_mbyte(addr, i);
+ addr++;
+ cnt++;
+ } // end while
+ printf ("%d Bytes loaded.\n", cnt);
+ return (SCPE_OK);
+}
+
+/* Symbolic output
+
+ Inputs:
+ *of = output stream
+ addr = current PC
+ *val = pointer to values
+ *uptr = pointer to unit
+ sw = switches
+ Outputs:
+ status = error code
+ for M6809
+*/
+t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw)
+{
+ int32 i, inst;
+
+ sim_debug(DEBUG_flow, &m6809_dev, "Call to fprint_sym()\n");
+
+ if (sw & SWMASK ('D')) { // dump memory
+ for (i=0; i<16; i++)
+ fprintf(of, "%02X ", val[i]);
+ fprintf(of, " ");
+ for (i=0; i<16; i++)
+ if (isprint(val[i]))
+ fprintf(of, "%c", val[i]);
+ else
+ fprintf(of, ".");
+ return -15;
+ } else if (sw & SWMASK ('M')) { // dump instruction mnemonic
+ inst = val[0];
+ if (!oplen[inst]) { // invalid opcode
+ fprintf(of, "%02X", inst);
+ return 0;
+ }
+
+ /* lookup mnemonic in table */
+ fprintf (of, "%s", opcode[inst]); // mnemonic
+ if (strlen(opcode[inst]) == 3)
+ fprintf(of, " ");
+
+ /* display some potential operands - this is not exact! */
+ switch (oplen[inst]) {
+ case 0:
+ case 1:
+ break;
+ case 2:
+ fprintf(of, " $%02X", val[1]);
+ break;
+ case 3:
+ fprintf(of, " $%02X $%02X", val[1], val[2]);
+ break;
+ case 4:
+ fprintf(of, " $%02X $%02X $%02x", val[1], val[2], val[3]);
+ break;
+ }
+ return (-(oplen[inst] - 1));
+ } else {
+ return SCPE_ARG;
+ }
+}
+
+/* Symbolic input
+
+ Inputs:
+ *cptr = pointer to input string
+ addr = current PC
+ *uptr = pointer to unit
+ *val = pointer to output values
+ sw = switches
+ Outputs:
+ status = error status
+*/
+t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
+{
+ return (1);
+}
+
+/* end of m6809.c */
diff --git a/swtp6809/common/mp-09.c b/swtp6809/common/mp-09.c
new file mode 100644
index 000000000..ec9c52791
--- /dev/null
+++ b/swtp6809/common/mp-09.c
@@ -0,0 +1,296 @@
+/* mp-09.c: SWTP MP-09 M6809 CPU simulator
+
+ Copyright (c) 2011-2012, William Beech
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of William A. Beech shall not
+ be used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from William A. Beech.
+
+ The following copyright notice applies to the SWTP 6809 source, binary, and documentation:
+
+ Original code published in 2024, written by Richard F Lukes
+ Copyright (c) 2024, Richard F Lukes
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the names of The Authors shall not be
+ used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from the Authors.
+
+ MODIFICATIONS:
+
+ 24 Apr 15 -- Modified to use simh_debug
+ 04 Apr 24 -- Richard Lukes - modified SWTPC mp-a2 emulator to create mp-09 emulator.
+
+ NOTES:
+
+ The MP-09 CPU Board includes the SWTP Dynamic Address Translation (DAT) logic which
+ is used to create a 20-bit virtual address space (1MB of RAM).
+
+ The MP-09 CPU Board contains the following devices [mp-09.c]:
+ M6809 processor [m6809.c].
+ SWTPC SBUG-E, or custom boot ROM at top of 16-bit address space [bootrom.c].
+ Interface to the SS-50 bus and the MP-B3 Mother Board for I/O
+ and memory boards [mp-b3.c].
+*/
+
+#include
+#include "swtp_defs.h"
+
+#define UNIT_V_DAT (UNIT_V_UF) /* Dynamic Address Translation setting */
+#define UNIT_DAT (1 << UNIT_V_DAT)
+
+
+/* local global variables */
+unsigned char DAT_RAM[16];
+unsigned char DAT_RAM_CACHE[16];
+
+/* function prototypes */
+
+t_stat CPU_BD_reset (DEVICE *dptr);
+t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches);
+t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches);
+int32 DAT_Xlate(int32 logical_addr);
+int32 CPU_BD_get_mbyte(int32 addr);
+int32 CPU_BD_get_mword(int32 addr);
+void CPU_BD_put_mbyte(int32 addr, int32 val);
+void CPU_BD_put_mword(int32 addr, int32 val);
+
+/* external routines */
+
+/* MP-B3 bus routines */
+extern int32 MB_get_mbyte(int32 addr);
+extern int32 MB_get_mword(int32 addr);
+extern void MB_put_mbyte(int32 addr, int32 val);
+extern void MB_put_mword(int32 addr, int32 val);
+
+/* MP-09 data structures
+
+ CPU_BD_dev MP-09 device descriptor
+ CPU_BD_unit MP-09 unit descriptor
+ CPU_BD_reg MP-09 register list
+ CPU_BD_mod MP-09 modifiers list
+*/
+
+UNIT CPU_BD_unit = { UDATA (NULL, 0, 0) };
+
+REG CPU_BD_reg[] = {
+ { NULL }
+};
+
+MTAB CPU_BD_mod[] = {
+ { UNIT_DAT, UNIT_DAT, "DAT enabled", "DAT", NULL },
+ { UNIT_DAT, 0, "DAT disabled", "NODAT", NULL },
+ { 0 }
+};
+
+DEBTAB CPU_BD_debug[] = {
+ { "ALL", DEBUG_all },
+ { "FLOW", DEBUG_flow },
+ { "READ", DEBUG_read },
+ { "WRITE", DEBUG_write },
+ { "LEV1", DEBUG_level1 },
+ { "LEV2", DEBUG_level2 },
+ { NULL }
+};
+
+DEVICE CPU_BD_dev = {
+ "MP-09", //name
+ &CPU_BD_unit, //units
+ CPU_BD_reg, //registers
+ CPU_BD_mod, //modifiers
+ 1, //numunits
+ 16, //aradix
+ 8, //awidth
+ 1, //aincr
+ 16, //dradix
+ 8, //dwidth
+ &CPU_BD_examine, //examine
+ &CPU_BD_deposit, //deposit
+ &CPU_BD_reset, //reset
+ NULL, //boot
+ NULL, //attach
+ NULL, //detach
+ NULL, //ctxt
+ DEV_DEBUG, //flags
+ 0, //dctrl
+ CPU_BD_debug, /* debflags */
+ NULL, //msize
+ NULL //lname
+};
+
+/* reset */
+t_stat CPU_BD_reset (DEVICE *dptr)
+{
+ int32 i;
+
+ /* this is performed whether DAT is enabled or not */
+ // initialize DAT RAM
+ for (i=0; i<16; i++) {
+ DAT_RAM[i] = (~i) & 0x0F;
+ DAT_RAM_CACHE[i] = i;
+ }
+ return SCPE_OK;
+}
+
+/* Deposit routine */
+t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches)
+{
+ if (addr > ADDRMASK) {
+ return SCPE_NXM;
+ } else {
+ CPU_BD_put_mbyte(addr, val);
+ return SCPE_OK;
+ }
+}
+
+/* Examine routine */
+t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches)
+{
+ if (addr > ADDRMASK) {
+ return SCPE_NXM;
+ }
+ if (eval_array != NULL) {
+ *eval_array = CPU_BD_get_mbyte(addr);
+ }
+ return SCPE_OK;
+}
+
+/* Perform adress translation from 16-bit logical address to 20-bit physical address using DAT mapping RAM */
+int32 DAT_Xlate(int32 logi_addr)
+{
+
+ /* if DAT is enabled perform the Dynamic Address Translation */
+ if (CPU_BD_unit.flags & UNIT_DAT) {
+
+ int32 DAT_index; /* which of the 16 mapping registers to index */
+ int32 DAT_byte; /* the lookup value from DAT RAM */
+ int32 DAT_block; /* A13-A14-A15-A16 */
+
+ /* translation from 16-bit logical address to 20-bit physical address */
+ DAT_index = (logi_addr & 0xF000) >> 12;
+ DAT_byte = DAT_RAM_CACHE[DAT_index];
+ if (DAT_index >= 0xE) {
+ /* for logical addresses $E000-$FFFF */
+ // Bank address (A17-A20) is 0b0000
+ return((logi_addr & 0xFFF) + ((DAT_byte & 0x0F)<<12));
+ } else {
+ // Bank address (A17-A20) is the high order 4-bits of DAT_byte
+ return((logi_addr & 0xFFF) + (DAT_byte<<12));
+ }
+
+ } else {
+ /* DAT is disabled */
+ return(logi_addr);
+ }
+}
+
+/* get a byte from memory */
+int32 CPU_BD_get_mbyte(int32 addr)
+{
+ int32 val = 0;
+ int32 phy_addr;
+
+ sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: addr=%04X\n", addr);
+ switch(addr & 0xF000) {
+ case 0xE000:
+ case 0xF000:
+ /* ROM is mapped to logical address $E000-$FFFF at all times! Unaffected by DAT */
+ val = MB_get_mbyte(addr);
+ sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b3 val=%02X\n", val);
+ break;
+ default:
+ /* access the resources on the motherboard - 16-bit addressing */
+ /* 56K of RAM from 0000-DFFF */
+ /* 8K of I/O space from E000-EFFF */
+ /* 2K of scratchpad RAM from F000-F7FF ??? */
+ if (CPU_BD_unit.flags & UNIT_DAT) {
+ phy_addr = DAT_Xlate(addr);
+ } else {
+ phy_addr = addr;
+ }
+ val = MB_get_mbyte(phy_addr);
+ sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b3 val=%02X\n", val);
+ break;
+ }
+ return val;
+}
+
+/* get a word from memory */
+int32 CPU_BD_get_mword(int32 addr)
+{
+ int32 val;
+
+ sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mword: addr=%04X\n", addr);
+ val = (CPU_BD_get_mbyte(addr) << 8);
+ val |= CPU_BD_get_mbyte(addr+1);
+ val &= 0xFFFF;
+ sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mword: val=%04X\n", val);
+ return val;
+}
+
+/* put a byte to memory */
+void CPU_BD_put_mbyte(int32 addr, int32 val)
+{
+ int32 phy_addr;
+
+ sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mbyte: addr=%04X, val=%02X\n", addr, val);
+
+ if ((addr & 0xFFF0) == 0xFFF0) {
+ /* this is performed whether DAT is enabled or not */
+ DAT_RAM[addr & 0x0F] = val;
+ DAT_RAM_CACHE[addr & 0x0F] = (val & 0xF0) | (~val & 0x0F);
+ } else {
+ switch(addr & 0xF800) {
+ case 0xF800:
+ /* do not write to ROM area */
+ break;
+ default:
+ phy_addr = DAT_Xlate(addr);
+ MB_put_mbyte(phy_addr, val);
+ break;
+ }
+ }
+}
+
+/* put a word to memory */
+void CPU_BD_put_mword(int32 addr, int32 val)
+{
+ sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mword: addr=%04X, val=%04X\n", addr, val);
+ CPU_BD_put_mbyte(addr, val >> 8);
+ CPU_BD_put_mbyte(addr+1, val & 0xFF);
+}
+
+/* end of mp-09.c */
diff --git a/swtp6809/common/mp-1m.c b/swtp6809/common/mp-1m.c
new file mode 100644
index 000000000..89348535c
--- /dev/null
+++ b/swtp6809/common/mp-1m.c
@@ -0,0 +1,311 @@
+/* mp-1m.c: SWTP 1M Byte Memory Card emulator
+
+ Copyright (c) 2011-2012, William A. Beech
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS O
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of William A. Beech shall not be
+ used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from William A. Beech.
+
+ The following copyright notice applies to the SWTP 6809 source, binary, and documentation:
+
+ Original code published in 2024, written by Richard F Lukes
+ Copyright (c) 2024, Richard F Lukes
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the names of The Authors shall not be
+ used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from the Authors.
+
+ MODIFICATIONS:
+
+ 24 Apr 15 -- Modified to use simh_debug
+ 04 Apr 24 -- Richard Lukes - Modified mp-8m.c to use for 1MB memory for swtp6809 emulator
+
+ NOTES:
+
+ These functions support 1MB of memory on an SS-50 system as a single 1MB memory card.
+ Due to the way Dynamic Address Translation (DAT) works, the upper 8KB of each 64KB address space is allocated
+ to I/O ($E000) and ROM ($F000) space. Therefore, the maximum usable RAM is 16 x 56KB = 896KB.
+
+ The unit uses a statically allocated 1MB byte buffer. This makes for a fast implementation.
+ No effort was made to make available memory variable in size (e.g. limit to only 32KB, 64KB, 96KB, 128KB, etc.).
+*/
+
+#include
+#include "swtp_defs.h"
+
+/* this is the maximum size of the physical address space */
+#define ONE_MEGABYTE 0x100000
+
+/* this is the value returned when reading a byte of non-existant memory */
+#define BLANK_MEMORY_BYTE_VALUE 0xFF
+
+#define UNIT_V_MSIZE (UNIT_V_UF) /* user defined options */
+#define UNIT_MSIZE (0xFF << UNIT_V_MSIZE)
+#define UNIT_8KB (0x01 << UNIT_V_MSIZE) /* 8KB */
+#define UNIT_16KB (0x02 << UNIT_V_MSIZE) /* 16KB */
+#define UNIT_32KB (0x04 << UNIT_V_MSIZE) /* 32KB */
+#define UNIT_56KB (0x08 << UNIT_V_MSIZE) /* 56KB */
+#define UNIT_128KB (0x10 << UNIT_V_MSIZE) /* 128KB */
+#define UNIT_256KB (0x20 << UNIT_V_MSIZE) /* 256KB */
+#define UNIT_512KB (0x30 << UNIT_V_MSIZE) /* 512KB */
+#define UNIT_1024KB (0x40 << UNIT_V_MSIZE) /* 1024KB */
+
+/* prototypes */
+
+t_stat mp_1m_reset (DEVICE *dptr);
+t_stat mp_1m_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
+t_stat mp_1m_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches);
+t_stat mp_1m_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches);
+int32 mp_1m_get_mbyte(int32 addr);
+int32 mp_1m_get_mword(int32 addr);
+void mp_1m_put_mbyte(int32 addr, int32 val);
+void mp_1m_put_mword(int32 addr, int32 val);
+
+UNIT mp_1m_unit = {
+ UDATA (NULL, UNIT_FIX + UNIT_BUF + UNIT_BINK, ONE_MEGABYTE)
+};
+
+MTAB mp_1m_mod[] = {
+ { UNIT_MSIZE, UNIT_1024KB, "1MB of RAM", "1024KB", &mp_1m_config },
+ { UNIT_MSIZE, UNIT_512KB, "512KB of RAM", "512KB", &mp_1m_config },
+ { UNIT_MSIZE, UNIT_256KB, "256KB of RAM", "256KB", &mp_1m_config },
+ { UNIT_MSIZE, UNIT_128KB, "128KB of RAM", "128KB", &mp_1m_config },
+ { UNIT_MSIZE, UNIT_56KB, "56KB of RAM", "56KB", &mp_1m_config },
+ { UNIT_MSIZE, UNIT_32KB, "32KB of RAM", "32KB", &mp_1m_config },
+ { UNIT_MSIZE, UNIT_16KB, "16KB of RAM", "16KB", &mp_1m_config },
+ { UNIT_MSIZE, UNIT_8KB, "8KB of RAM", "8KB", &mp_1m_config },
+ { 0 }
+};
+
+DEBTAB mp_1m_debug[] = {
+ { "ALL", DEBUG_all },
+ { "FLOW", DEBUG_flow },
+ { "READ", DEBUG_read },
+ { "WRITE", DEBUG_write },
+ { "LEV1", DEBUG_level1 },
+ { "LEV2", DEBUG_level2 },
+ { NULL }
+};
+
+DEVICE mp_1m_dev = {
+ "MP-1M", //name
+ &mp_1m_unit, //units
+ NULL, //registers
+ mp_1m_mod, //modifiers
+ 1, //numunits
+ 16, //aradix
+ 20, //awidth
+ 1, //aincr
+ 16, //dradix
+ 8, //dwidth
+ &mp_1m_examine, //examine
+ &mp_1m_deposit, //deposit
+ &mp_1m_reset, //reset
+ NULL, //boot
+ NULL, //attach
+ NULL, //detach
+ NULL, //ctxt
+ DEV_DEBUG, //flags
+ 0, //dctrl
+ mp_1m_debug, //debflags
+ NULL, //msize
+ NULL //lname
+};
+
+/* Pre-allocate 1MB array of bytes */
+uint8 mp_1m_ram_memory_array[ONE_MEGABYTE];
+
+/* mp_1m_config */
+t_stat mp_1m_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
+{
+
+ sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_config: val=%d\n", val);
+ if ((val > UNIT_1024KB) || (val < UNIT_8KB)) { /* valid param? */
+ sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_config: Parameter error\n");
+ return SCPE_ARG;
+ }
+
+ /* set RAM size. All RAM starts with a base address of 00000H */
+ switch ( val ) {
+ case UNIT_8KB:
+ mp_1m_unit.capac = 8 * 1024;
+ break;
+ case UNIT_16KB:
+ mp_1m_unit.capac = 16 * 1024;
+ break;
+ case UNIT_32KB:
+ mp_1m_unit.capac = 32 * 1024;
+ break;
+ case UNIT_56KB:
+ mp_1m_unit.capac = 56 * 1024;
+ break;
+ case UNIT_128KB:
+ mp_1m_unit.capac = 128 * 1024;
+ break;
+ case UNIT_256KB:
+ mp_1m_unit.capac = 256 * 1024;
+ break;
+ case UNIT_512KB:
+ mp_1m_unit.capac = 512 * 1024;
+ break;
+ case UNIT_1024KB:
+ mp_1m_unit.capac = 1024 * 1024;
+ break;
+ default:
+ /* what to do? default to 1024KB */
+ mp_1m_unit.capac = 1024 * 1024;
+ }
+ sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_config: mp_1m_unit.capac=%d\n", mp_1m_unit.capac);
+ sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_config: Done\n");
+
+ return SCPE_OK;
+} /* mp-1m config */
+
+/* Deposit routine */
+t_stat mp_1m_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches)
+{
+ if (addr >= mp_1m_unit.capac) {
+ return SCPE_NXM;
+ } else {
+ mp_1m_ram_memory_array[addr] = val & 0xFF;
+ return SCPE_OK;
+ }
+}
+
+/* Examine routine */
+t_stat mp_1m_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches)
+{
+ if (addr >= mp_1m_unit.capac) {
+ return SCPE_NXM;
+ }
+ if (eval_array != NULL) {
+ *eval_array = mp_1m_ram_memory_array[addr];
+ }
+ return SCPE_OK;
+}
+
+/* Reset routine */
+
+t_stat mp_1m_reset (DEVICE *dptr)
+{
+ int32 i, j, val;
+ UNIT *uptr;
+
+ sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_reset: \n");
+ uptr = mp_1m_dev.units;
+ sim_debug (DEBUG_flow, &mp_1m_dev, "MP-1M %d unit.flags=%08X\n", i, uptr->flags);
+
+ // capacity
+ uptr->capac = ONE_MEGABYTE;
+ // starting address
+ uptr->u3 = 0;
+
+ if (uptr->filebuf == NULL) {
+ uptr->filebuf = &mp_1m_ram_memory_array;
+ if (uptr->filebuf == NULL) {
+ printf("mp_1m_reset: Malloc error\n");
+ return SCPE_MEM;
+ }
+ for (j=0; j < uptr->capac; j++) { /* populate memory with fill pattern */
+ i = j & 0xF;
+ val = (0xA0 | i) & BYTEMASK;
+ *((uint8 *)(uptr->filebuf) + j) = val;
+ }
+ sim_debug (DEBUG_flow, &mp_1m_dev, "MP-1M %d initialized at [%05X-%05XH]\n", i, uptr->u3, uptr->u3 + uptr->capac - 1);
+ }
+ sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_reset: Done\n");
+ return SCPE_OK;
+}
+
+/*
+ I/O instruction handlers, called from the mp-b3 module when an
+ external memory read or write is issued.
+*/
+
+/* get a byte from memory */
+
+int32 mp_1m_get_mbyte(int32 addr)
+{
+ //UNIT *uptr;
+ int32 val;
+
+ //uptr = mp_1m_dev.units;
+ sim_debug (DEBUG_read, &mp_1m_dev, "mp_1m_get_mbyte: addr=%05X", addr);
+ if (addr >= mp_1m_unit.capac) {
+ sim_debug (DEBUG_read, &mp_1m_dev, "mp_1m_get_mbyte: addr=%08X Out of range\n", addr);
+ return BLANK_MEMORY_BYTE_VALUE;
+ } else {
+ val = mp_1m_ram_memory_array[addr];
+ sim_debug (DEBUG_read, &mp_1m_dev, " addr=%05x val=%02X\n", addr, val);
+ return val;
+ }
+}
+
+/* get a word from memory */
+
+int32 mp_1m_get_mword(int32 addr)
+{
+ int32 val;
+
+ val = (mp_1m_get_mbyte(addr) << 8);
+ val |= mp_1m_get_mbyte(addr+1);
+ return val;
+}
+
+/* put a byte into memory */
+
+void mp_1m_put_mbyte(int32 addr, int32 val)
+{
+ sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: addr=%05X, val=%02X", addr, val);
+
+ if (addr >= mp_1m_unit.capac) {
+ sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: Address out of range, addr=%08x\n", addr);
+ } else {
+ mp_1m_ram_memory_array[addr] = val;
+ sim_debug (DEBUG_write, &mp_1m_dev, "\n");
+ }
+}
+
+/* put a word into memory */
+
+void mp_1m_put_mword(int32 addr, int32 val)
+{
+ mp_1m_put_mbyte(addr, val >> 8);
+ mp_1m_put_mbyte(addr+1, val & BYTEMASK);
+}
+
+/* end of mp-1m.c */
diff --git a/swtp6809/common/mp-b3.c b/swtp6809/common/mp-b3.c
new file mode 100644
index 000000000..5bbf91f27
--- /dev/null
+++ b/swtp6809/common/mp-b3.c
@@ -0,0 +1,326 @@
+/* mp-b3.c: SWTP SS-50/SS-30 MP-B3 Mother Board
+
+ Copyright (c) 2011-2012, William A. Beech
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of William A. Beech shall not be
+ used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from William A. Beech.
+
+ The following copyright notice applies to the SWTP 6809 source, binary, and documentation:
+
+ Original code published in 2024, written by Richard F Lukes
+ Copyright (c) 2024, Richard F Lukes
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the names of The Authors shall not be
+ used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from the Authors.
+
+ MODIFICATIONS:
+
+ 24 Apr 15 -- Modified to use simh_debug
+ 04 Apr 24 -- Richard Lukes - Modified to emulate MP-B3 motherboard for swtp6809 emulator
+
+ NOTES:
+
+*/
+
+#include
+#include "swtp_defs.h"
+
+
+#define UNIT_V_16BYTESPERSLOT (UNIT_V_UF) /* MP-1M board enable */
+#define UNIT_16BYTESPERSLOT (1 << UNIT_V_16BYTESPERSLOT)
+
+#define MASK_20BIT 0xFFFFF
+#define MASK_16BIT 0xFFFF
+
+/* function prototypes */
+
+/* empty I/O device routine */
+int32 nulldev(int32 io, int32 data);
+
+/* SS-50 bus routines */
+t_stat MB_reset (DEVICE *dptr);
+t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches);
+t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches);
+int32 MB_get_mbyte(int32 addr);
+int32 MB_get_mword(int32 addr);
+void MB_put_mbyte(int32 addr, int32 val);
+void MB_put_mword(int32 addr, int32 val);
+
+/* BOOTROM memory access routines */
+extern int32 BOOTROM_get_mbyte(int32 offset);
+
+/* MP-1M memory access routines */
+extern int32 mp_1m_get_mbyte(int32 addr);
+extern void mp_1m_put_mbyte(int32 addr, int32 val);
+
+/* SS-50 I/O address space functions */
+
+/* MP-S serial I/O routines */
+extern int32 sio0s(int32 io, int32 data);
+extern int32 sio0d(int32 io, int32 data);
+extern int32 sio1s(int32 io, int32 data);
+extern int32 sio1d(int32 io, int32 data);
+
+/* DC-4 FDC I/O routines */
+extern int32 fdcdrv(int32 io, int32 data);
+extern int32 fdccmd(int32 io, int32 data);
+extern int32 fdctrk(int32 io, int32 data);
+extern int32 fdcsec(int32 io, int32 data);
+extern int32 fdcdata(int32 io, int32 data);
+
+/*
+MP-B3 configured with 4 address per SS-30 slot (x8).
+
+This is the I/O configuration table. There are 32 possible
+device addresses, if a device is plugged into a port it's routine
+address is here, 'nulldev' means no device is available
+*/
+
+struct idev {
+ int32 (*routine)(int32, int32);
+};
+
+struct idev dev_table[32] = {
+ {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* Port 0 E000-E003 */
+ {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* Port 1 E004-E007 */
+/* sio1x routines just return the last value read on the matching
+ sio0x routine. SWTBUG tests for the MP-C with most port reads! */
+ {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 2 E008-E00B */
+ {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 3 E00C-E00F */
+ {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 4 E010-E013 */
+ {&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 5 E014-E017 */
+ {&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /* Port 6 E018-E01B */
+ {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* Port 7 E01C-E01F */
+};
+
+/* dummy i/o device */
+
+int32 nulldev(int32 io, int32 data)
+{
+ if (io == 0) {
+ return (0xFF);
+ } else {
+ return 0;
+ }
+}
+
+/* Mother Board data structures
+
+ MB_dev Mother Board device descriptor
+ MB_unit Mother Board unit descriptor
+ MB_reg Mother Board register list
+ MB_mod Mother Board modifiers list
+*/
+
+UNIT MB_unit = {
+ UDATA (NULL, 0, 0)
+};
+
+REG MB_reg[] = {
+ { NULL }
+};
+
+MTAB MB_mod[] = {
+ { UNIT_16BYTESPERSLOT, UNIT_16BYTESPERSLOT, "I/O port size of 16 bytes not implemented", "16BYTE", NULL, NULL },
+ { UNIT_16BYTESPERSLOT, 0, "I/O port size of 4 bytes", "4BYTE", NULL, NULL },
+ { 0 }
+};
+
+DEBTAB MB_debug[] = {
+ { "ALL", DEBUG_all },
+ { "FLOW", DEBUG_flow },
+ { "READ", DEBUG_read },
+ { "WRITE", DEBUG_write },
+ { "LEV1", DEBUG_level1 },
+ { "LEV2", DEBUG_level2 },
+ { NULL }
+};
+
+DEVICE MB_dev = {
+ "MP-B3", //name
+ &MB_unit, //units
+ MB_reg, //registers
+ MB_mod, //modifiers
+ 1, //numunits
+ 16, //aradix
+ 20, //awidth
+ 1, //aincr
+ 16, //dradix
+ 8, //dwidth
+ &MB_examine, //examine
+ &MB_deposit, //deposit
+ &MB_reset, //reset
+ NULL, //boot
+ NULL, //attach
+ NULL, //detach
+ NULL, //ctxt
+ DEV_DEBUG, //flags
+ 0, //dctrl
+ MB_debug, /* debflags */
+ NULL, //msize
+ NULL, //logical name
+ NULL, //help routine
+ NULL, //attach help routine
+ NULL, //help context
+ NULL //device description
+};
+
+/* reset */
+t_stat MB_reset (DEVICE *dptr)
+{
+ return SCPE_OK;
+}
+
+/* Deposit routine */
+t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches)
+{
+ if (addr > MASK_20BIT) {
+ /* exceed 20-bit address space */
+ return SCPE_NXM;
+ } else {
+ MB_put_mbyte(addr, val);
+ return SCPE_OK;
+ }
+}
+
+/* Examine routine */
+t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches)
+{
+ if (addr > MASK_20BIT) {
+ return SCPE_NXM;
+ }
+ if (eval_array != NULL) {
+ *eval_array = MB_get_mbyte(addr);
+ }
+ return SCPE_OK;
+}
+
+/* get a byte from memory */
+
+int32 MB_get_mbyte(int32 addr20)
+{
+ int32 val;
+ int32 addr16;
+
+ addr16 = addr20 & MASK_16BIT;
+
+ // 20-bit physical addresses
+ sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: addr=%05X\n", addr20);
+ switch (addr20 & 0x0F800) {
+ case 0x0E000:
+ /* reserved I/O space from $E000-$E01F */
+ /* read byte value from device */
+ if (addr16 < 0xE020) {
+ val = (dev_table[addr16 - 0xE000].routine(0, 0)) & 0xFF;
+ break;
+ }
+ case 0x0E800:
+ case 0x0F000:
+ case 0x0F800:
+ /* Up to 8KB of boot ROM from $E000-$FFFF */
+ val = BOOTROM_get_mbyte(addr16);
+ sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: EPROM=%02X\n", val);
+ break;
+ default:
+ /* all the rest is RAM */
+ val = mp_1m_get_mbyte(addr20);
+ if (MB_dev.dctrl & DEBUG_read) {
+ printf("MB_get_mbyte: mp_1m add=%05x val=%02X\n", addr20, val);
+ }
+ break;
+ }
+ sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: I/O addr=%05X val=%02X\n", addr20, val);
+ return val;
+}
+
+/* get a word from memory */
+
+int32 MB_get_mword(int32 addr20)
+{
+ int32 val;
+
+ sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: addr=%05X\n", addr20);
+ val = (MB_get_mbyte(addr20) << 8);
+ val |= MB_get_mbyte(addr20+1);
+ val &= MASK_16BIT;
+ sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: val=%05X\n", val);
+ return val;
+}
+
+/* put a byte to memory */
+
+void MB_put_mbyte(int32 addr20, int32 val)
+{
+ int32 retval;
+ int32 addr16;
+
+ addr16 = addr20 & MASK_16BIT;
+
+ // 20-bit physical addresses
+ sim_debug (DEBUG_write, &MB_dev, "MB_put_mbyte: addr=%05X, val=%02X\n", addr20, val);
+
+ switch(addr16 & 0xF000) {
+ case 0xE000:
+ /* I/O and ROM space */
+ if (addr16 < 0xE020) {
+ /* reserved I/O space from $E000-$E01F */
+ /* write byte value to device */
+ retval = dev_table[addr16 - 0xE000].routine(1, val);
+ }
+ break;
+ case 0xF000:
+ /* ROM space - READ ONLY! */
+ break;
+ default:
+ /* RAM */
+ mp_1m_put_mbyte(addr20, val);
+ break;
+ }
+}
+
+/* put a word to memory */
+
+void MB_put_mword(int32 addr20, int32 val)
+{
+ sim_debug (DEBUG_write, &MB_dev, "MB_ptt_mword: addr=%05X, val=%04X\n", addr20, val);
+ MB_put_mbyte(addr20, val >> 8);
+ MB_put_mbyte(addr20+1, val & 0xFF);
+}
+
+/* end of mp-b3.c */
diff --git a/swtp6809/common/mp-s.c b/swtp6809/common/mp-s.c
new file mode 100644
index 000000000..7267d1951
--- /dev/null
+++ b/swtp6809/common/mp-s.c
@@ -0,0 +1,381 @@
+/* mp-s.c: SWTP MP-S serial I/O card simulator
+
+ Copyright (c) 2005-2012, William Beech
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ Willaim Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of William A. Beech shall not
+ be used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from William A. Beech.
+
+ MODIFICATIONS:
+
+ 28 May 22 -- Roberto Sancho Villa (RSV) fixes for DEL and BS
+
+ NOTES:
+
+ These functions support a simulated SWTP MP-S interface card.
+ The card contains one M6850 ACIA. The ACIA implements one complete
+ serial port. It provides 7 or 8-bit ASCII RS-232 interface to Terminals
+ or 20 mA current loop interface to a model 33 or 37 Teletype. It is not
+ compatible with baudot Teletypes. Baud rates from 110 to 1200 are
+ switch selectable from S! on the MP-S. The ACIA ports appear at all
+ 4 addresses. This fact is used by SWTBUG to determine the presence of the
+ MP-S vice MP-C serial card. The ACIA interrupt request line can be connected
+ to the IRQ or NMI interrupt lines by a jumper on the MP-S.
+
+ All I/O is via either programmed I/O or interrupt controlled I/O.
+ It has a status port and a data port. A write to the status port
+ can select some options for the device (0x03 will reset the port).
+ A read of the status port gets the port status:
+
+ +---+---+---+---+---+---+---+---+
+ | I | P | O | F |CTS|DCD|TXE|RXF|
+ +---+---+---+---+---+---+---+---+
+
+ RXF - A 1 in this bit position means a character has been received
+ on the data port and is ready to be read.
+ TXE - A 1 in this bit means the port is ready to receive a character
+ on the data port and transmit it out over the serial line.
+
+ A read to the data port gets the buffered character, a write
+ to the data port writes the character to the device.
+*/
+
+#include
+#include
+#include "swtp_defs.h"
+
+#define UNIT_V_TTY (UNIT_V_UF) // TTY or ANSI mode
+#define UNIT_TTY (1 << UNIT_V_TTY)
+
+#define RXF 0x01
+#define TXE 0x02
+#define DCD 0x04
+#define CTS 0x08
+
+/* local global variables */
+
+int32 ptr_stopioe = 0; // stop on error
+int32 ptp_stopioe = 0; // stop on error
+int32 odata;
+int32 status;
+
+int32 ptp_flag = 0;
+int32 ptr_flag = 0;
+
+/* function prototypes */
+
+t_stat sio_svc (UNIT *uptr);
+t_stat ptr_svc (UNIT *uptr);
+t_stat ptp_svc (UNIT *uptr);
+t_stat sio_reset (DEVICE *dptr);
+t_stat ptr_reset (DEVICE *dptr);
+t_stat ptp_reset (DEVICE *dptr);
+int32 sio0s(int32 io, int32 data);
+int32 sio0d(int32 io, int32 data);
+int32 sio1s(int32 io, int32 data);
+int32 sio1d(int32 io, int32 data);
+
+/* sio data structures
+
+ sio_dev SIO device descriptor
+ sio_unit SIO unit descriptor
+ sio_reg SIO register list
+ sio_mod SIO modifiers list */
+
+UNIT sio_unit = {
+ UDATA (&sio_svc, 0, 0), KBD_POLL_WAIT
+};
+
+REG sio_reg[] = {
+ { ORDATA (DATA, sio_unit.buf, 8) },
+ { ORDATA (STAT, sio_unit.u3, 8) },
+ { NULL }
+};
+
+MTAB sio_mod[] = {
+ { UNIT_TTY, UNIT_TTY, "TTY", "TTY", NULL },
+ { UNIT_TTY, 0, "ANSI", "ANSI", NULL },
+ { 0 }
+};
+
+DEVICE sio_dev = {
+ "MP-S", //name
+ &sio_unit, //units
+ sio_reg, //registers
+ sio_mod, //modifiers
+ 1, //numunits
+ 10, //aradix
+ 31, //awidth
+ 1, //aincr
+ 8, //dradix
+ 8, //dwidth
+ NULL, //examine
+ NULL, //deposit
+ &sio_reset, //reset
+ NULL, //boot
+ NULL, //attach
+ NULL //detach
+};
+
+/* paper tape reader data structures
+
+ ptr_dev PTR device descriptor
+ ptr_unit PTR unit descriptor
+ ptr_reg PTR register list
+ ptr_mod PTR modifiers list */
+
+UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT
+};
+
+DEVICE ptr_dev = {
+ "PTR", //name
+ &ptr_unit, //units
+ NULL, //registers
+ NULL, //modifiers
+ 1, //numunits
+ 10, //aradix
+ 31, //awidth
+ 1, //aincr
+ 8, //dradix
+ 8, //dwidth
+ NULL, //examine
+ NULL, //deposit
+ &ptr_reset, //reset
+ NULL, //boot
+ NULL, //attach
+ NULL //detach
+};
+
+/* paper tape punch data structures
+
+ ptp_dev PTP device descriptor
+ ptp_unit PTP unit descriptor
+ ptp_reg PTP register list
+ ptp_mod PTP modifiers list */
+
+UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT
+};
+DEVICE ptp_dev = {
+ "PTP", //name
+ &ptp_unit, //units
+ NULL, //registers
+ NULL, //modifiers
+ 1, //numunits
+ 10, //aradix
+ 31, //awidth
+ 1, //aincr
+ 8, //dradix
+ 8, //dwidth
+ NULL, //examine
+ NULL, //deposit
+ &ptp_reset, //reset
+ NULL, //boot
+ NULL, //attach
+ NULL //detach
+};
+
+/* console input service routine */
+
+t_stat sio_svc (UNIT *uptr)
+{
+ int32 temp;
+
+ sim_activate (&sio_unit, sio_unit.wait); // continue poll
+ if ((temp = sim_poll_kbd ()) < SCPE_KFLAG)
+ return temp; // no char or error?
+ sio_unit.buf = temp & BYTEMASK; // Save char
+ if (sio_unit.buf==127) {
+ // convert BackSpace (ascii 127) so del char (ascii 8) for swtbug
+ sio_unit.buf=8;
+ }
+ sio_unit.u3 |= RXF; // Set RXF flag
+ /* Do any special character handling here */
+ sio_unit.pos++; // step character count
+ return SCPE_OK;
+}
+
+/* paper tape reader input service routine */
+
+t_stat ptr_svc (UNIT *uptr)
+{
+ int32 temp;
+
+ sim_activate (&ptr_unit, ptr_unit.wait); // continue poll
+ if ((temp = sim_poll_kbd ()) < SCPE_KFLAG)
+ return temp; // no char or error?
+ ptr_unit.buf = temp & BYTEMASK; // Save char
+ ptr_unit.u3 |= RXF; // Set RXF flag
+ /* Do any special character handling here */
+ ptr_unit.pos++; // step character count
+ return SCPE_OK;
+}
+
+/* paper tape punch output service routine */
+
+t_stat ptp_svc (UNIT *uptr)
+{
+ return SCPE_OK;
+}
+
+/* Reset console */
+
+t_stat sio_reset (DEVICE *dptr)
+{
+ sio_unit.buf = 0; //clear data buffer
+ sio_unit.u3 = TXE; //set TXE flag
+ sio_unit.wait = 10000;
+ sim_activate (&sio_unit, sio_unit.wait); // activate unit
+ return SCPE_OK;
+}
+
+/* Reset paper tape reader */
+
+t_stat ptr_reset (DEVICE *dptr)
+{
+ ptr_unit.buf = 0; //clear data buffer
+ ptr_unit.u3 = TXE; //set TXE flag
+ sim_cancel (&ptr_unit); // deactivate unit
+ return SCPE_OK;
+}
+
+/* Reset paper tape punch */
+
+t_stat ptp_reset (DEVICE *dptr)
+{
+ ptp_unit.buf = 0; //clear data buffer
+ ptp_unit.u3 = TXE; //set TXE flag
+ sim_cancel (&ptp_unit); // deactivate unit
+ return SCPE_OK;
+}
+
+/* I/O instruction handlers, called from the MP-B2 module when a
+ read or write occur to addresses 0x8004-0x8007. */
+
+int32 sio0s(int32 io, int32 data)
+{
+ if (io == 0) { // control register read
+ if (ptr_flag) { // reader enabled?
+ if ((ptr_unit.flags & UNIT_ATT) == 0) { // attached?
+ ptr_unit.u3 &= ~RXF; // no, clear RXF flag
+ ptr_flag = 0; // clear reader flag
+ printf("Reader not attached to file\n");
+ } else { // attached
+ if (feof(ptr_unit.fileref)) { // EOF
+ ptr_unit.u3 &= ~RXF; // clear RXF flag
+ ptr_flag = 0; // clear reader flag
+ } else // not EOF
+ ptr_unit.u3 |= RXF; // set ready
+ }
+ return (status = ptr_unit.u3); // return ptr status
+ } else {
+ return (status = sio_unit.u3); // return console status
+ }
+ } else { // control register write
+ if (data == 0x03) { // reset port!
+ sio_unit.u3 = TXE; // reset console
+ sio_unit.buf = 0;
+ sio_unit.pos = 0;
+ ptr_unit.u3 = TXE; // reset reader
+ ptr_unit.buf = 0;
+ ptr_unit.pos = 0;
+ ptp_unit.u3 = TXE; // reset punch
+ ptp_unit.buf = 0;
+ ptp_unit.pos = 0;
+ }
+ return (status = 0); // invalid io
+ }
+}
+
+int32 sio0d(int32 io, int32 data)
+{
+ if (io == 0) { // data register read
+ if (ptr_flag) { // RDR enabled?
+ if ((ptr_unit.flags & UNIT_ATT) == 0) // attached?
+ return 0; // no, done
+ if ((ptr_unit.u3 & RXF) == 0) // yes, more data?
+ return (odata & BYTEMASK);
+ if ((odata = getc(ptr_unit.fileref)) == EOF) { // end of file?
+ printf("Got EOF\n");
+ ptr_unit.u3 &= 0xFE; // clear RXF flag
+ return (odata = 0); // no data
+ }
+ ptr_unit.pos++; // step character count
+ ptr_unit.u3 &= ~RXF; // clear RXF flag
+ return (odata & BYTEMASK); // return character
+ } else {
+ sio_unit.u3 &= ~RXF; // clear RXF flag
+ return (odata = sio_unit.buf); // return next char
+ }
+ } else { // data register write
+ if (isprint(data) || data == '\r' || data == '\n') { // printable?
+ sim_putchar(data); // print character on console
+ if (ptp_flag && ptp_unit.flags & UNIT_ATT) { // PTP enabled & attached?
+ putc(data, ptp_unit.fileref);
+ ptp_unit.pos++; // step character counter
+ }
+ } else { // DC1-DC4 control Reader/Punch
+ switch (data) {
+ case 0x11: // PTR on
+ ptr_flag = 1;
+ ptr_unit.u3 |= RXF;
+ printf("Reader on\n");
+ break;
+ case 0x12: // PTP on
+ ptp_flag = 1;
+ ptp_unit.u3 |= TXE;
+ printf("Punch on\n");
+ break;
+ case 0x13: // PTR off
+ ptr_flag = 0;
+ if (ptr_unit.pos)
+ printf("Reader off-%d bytes read\n", ptr_unit.pos);
+ ptr_unit.pos = 0;
+ break;
+ case 0x14: // PTP off
+ ptp_flag = 0;
+ if (ptp_unit.pos)
+ printf("Punch off-%d bytes written\n", ptp_unit.pos);
+ ptp_unit.pos = 0;
+ break;
+ default: // ignore all other characters
+ break;
+ }
+ }
+ }
+ return (odata = 0);
+}
+
+/* because each port appears at 2 addresses and this fact is used
+ to determine if it is a MP-C or MP-S repeatedly in the SWTBUG
+ monitor, this code assures that reads of the high ports return
+ the same data as was read the last time on the low ports.
+*/
+
+int32 sio1s(int32 io, int32 data)
+{
+ return status;
+}
+
+int32 sio1d(int32 io, int32 data)
+{
+ return odata;
+}
+
+/* end of mp-s.c */
diff --git a/swtp6809/swtp6809/CMakeLists.txt b/swtp6809/swtp6809/CMakeLists.txt
new file mode 100644
index 000000000..187dc69d6
--- /dev/null
+++ b/swtp6809/swtp6809/CMakeLists.txt
@@ -0,0 +1,32 @@
+## swtp6809/swtp6809 simulator
+##
+## This is an automagically generated file. Do NOT EDIT.
+## Any changes you make will be overwritten!!
+##
+## Make changes to the SIMH top-level makefile and then run the
+## "cmake/generate.py" script to regenerate these files.
+##
+## cd cmake; python -m generate --help
+##
+## ------------------------------------------------------------
+
+if (HAVE_UNITY_FRAMEWORK AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/CMakeLists.txt")
+ add_subdirectory(unit-tests)
+endif ()
+
+add_simulator(swtp6809mp-09
+ SOURCES
+ ${SWTP6809C}/mp-09.c
+ ${SWTP6809C}/m6809.c
+ ${SWTP6809C}/bootrom.c
+ ${SWTP6809C}/dc-4.c
+ mp-09_sys.c
+ ${SWTP6809C}/mp-1m.c
+ ${SWTP6809C}/mp-b3.c
+ ${SWTP6809C}/mp-s.c
+ INCLUDES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ BUILDROMS
+ LABEL swtp6809
+ PKG_FAMILY swtp_family
+ TEST swtp6809mp-09)
diff --git a/swtp6809/swtp6809/mp-09_sys.c b/swtp6809/swtp6809/mp-09_sys.c
new file mode 100644
index 000000000..614f40d9c
--- /dev/null
+++ b/swtp6809/swtp6809/mp-09_sys.c
@@ -0,0 +1,115 @@
+/* mp09_sys.c: SWTP 6809 system interface
+
+ Copyright (c) 2005-2012, William Beech
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ WILLIAM A BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of William A. Beech shall not
+ be used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from William A. Beech.
+
+ The following copyright notice applies to the SWTP 6809 source, binary, and documentation:
+
+ Original code published in 2024, written by Richard F Lukes
+ Copyright (c) 2024, Richard F Lukes
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the names of The Authors shall not be
+ used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from the Authors.
+
+ MODIFICATIONS
+
+ 24 Feb 24 -- Richard Lukes - Modified mp-a2_sys.c for SWTP MP-09 emulation
+*/
+
+#include
+#include
+#include "swtp_defs.h"
+
+/* externals */
+
+extern REG m6809_reg[];
+
+extern DEVICE m6809_dev;
+extern DEVICE BOOTROM_dev;
+extern DEVICE CPU_BD_dev;
+extern DEVICE MB_dev;
+extern DEVICE mp_1m_dev;
+extern DEVICE dsk_dev;
+extern DEVICE sio_dev;
+extern DEVICE ptr_dev;
+extern DEVICE ptp_dev;
+
+/* SCP data structures
+
+ sim_name simulator name string
+ sim_PC pointer to saved PC register descriptor
+ sim_emax number of words needed for examine
+ sim_devices array of pointers to simulated devices
+ sim_stop_messages array of pointers to stop messages
+ sim_load binary loader
+*/
+
+char sim_name[] = "SWTP 6809, V1.0, MP-09 CPU Board";
+
+REG *sim_PC = &m6809_reg[0];
+
+// maximum number of words needed for examine
+int32 sim_emax = 4;
+
+DEVICE *sim_devices[] = {
+ &m6809_dev,
+ &CPU_BD_dev,
+ &BOOTROM_dev,
+ &MB_dev,
+ &mp_1m_dev,
+ &sio_dev,
+ &ptr_dev,
+ &ptp_dev,
+ &dsk_dev,
+ NULL
+};
+
+const char *sim_stop_messages[] = {
+ "Unknown error",
+ "RESERVED",
+ "Halt instruction",
+ "Breakpoint",
+ "Invalid opcode",
+ "Invalid memory",
+ "Unknown error"
+};
+
+/* end of mp09_sys.c */
diff --git a/swtp6809/swtp6809/sbuge.bin b/swtp6809/swtp6809/sbuge.bin
new file mode 100644
index 000000000..8c772c07a
Binary files /dev/null and b/swtp6809/swtp6809/sbuge.bin differ
diff --git a/swtp6809/swtp6809/swtp6809mp-09.ini b/swtp6809/swtp6809/swtp6809mp-09.ini
new file mode 100644
index 000000000..bcb1f6d10
--- /dev/null
+++ b/swtp6809/swtp6809/swtp6809mp-09.ini
@@ -0,0 +1,29 @@
+; swtp6809mp-09_test.ini
+; Boot SBUG-E and pass if the monitor prompt appears.
+
+cd %~p0
+
+set runlimit 20M instructions
+set on
+
+on error echof "\r\n*** FAILED - %SIM_NAME% SBUG-E monitor startup error ***\n"; exit 1
+on runtime echof "\r\n*** FAILED - %SIM_NAME% SBUG-E prompt timeout ***\n"; exit 1
+
+echof -n "** SWTP 6809: SBUG-E monitor prompt: "
+
+set mp-09 DAT
+set mp-1m 1024KB
+set cpu hex
+set cpu itrap
+set mp-s TTY
+set bootrom 2716
+attach -r bootrom ..\sbuge.bin
+
+reset
+
+expect [10] ">" echof "passed\r\n"; exit 0
+
+go -q
+
+echof "\r\n*** FAILED - SBUG-E monitor prompt not seen ***\n"
+exit 1
diff --git a/swtp6809/swtp6809/swtp_defs.h b/swtp6809/swtp6809/swtp_defs.h
new file mode 100644
index 000000000..0a9182c2f
--- /dev/null
+++ b/swtp6809/swtp6809/swtp_defs.h
@@ -0,0 +1,66 @@
+/* swtp_defs.h: SWTP 6809 simulator definitions
+
+ Copyright (c) 2005-2012, William Beech
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHAL
+ WILLIAM A BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR I
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of William A Beech shall not
+ be used in advertising or otherwise to promote the sale, use or other dealings
+ in this Software without prior written authorization from William A Beech.
+
+ MODIFICATIONS
+
+ 24 Feb 24 - Richard Lukes - Modified for swtp6809 emulator
+*/
+
+#include
+#include "sim_defs.h" // simulator defs
+
+/* Rename of global PC variable to avoid namespace conflicts on some platforms */
+
+#define PC PC_Global
+
+/* Memory */
+
+#define MAXMEMSIZE 65536 // max memory size
+#define MEMSIZE (m6809_unit.capac) // actual memory size
+#define ADDRMASK (MAXMEMSIZE - 1) // address mask
+#define BYTEMASK 0xFF
+#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE)
+
+/* debug definitions */
+
+#define DEBUG_flow 0x0001
+#define DEBUG_read 0x0002
+#define DEBUG_write 0x0004
+#define DEBUG_level1 0x0008
+#define DEBUG_level2 0x0010
+#define DEBUG_reg 0x0020
+#define DEBUG_asm 0x0040
+#define DEBUG_all 0x007F
+
+/* Simulator stop codes */
+
+#define STOP_UNKNOWN 0 // unknown error
+#define STOP_RSRV 1 // must be 1
+#define STOP_HALT 2 // HALT-really WAI
+#define STOP_IBKPT 3 // breakpoint
+#define STOP_OPCODE 4 // invalid opcode
+#define STOP_MEMORY 5 // invalid memory address
+#define STOP_UNKNOWN2 6 // unknown error
+
diff --git a/swtp6809/swtp6809/tests/swtp6809mp-09 b/swtp6809/swtp6809/tests/swtp6809mp-09
new file mode 100755
index 000000000..1a06e5c00
Binary files /dev/null and b/swtp6809/swtp6809/tests/swtp6809mp-09 differ
diff --git a/swtp6809/swtp6809/tests/swtp6809mp-09.ini b/swtp6809/swtp6809/tests/swtp6809mp-09.ini
new file mode 100644
index 000000000..398e85d34
--- /dev/null
+++ b/swtp6809/swtp6809/tests/swtp6809mp-09.ini
@@ -0,0 +1,29 @@
+:: swtp6809mp-09_test.ini
+:: Boot SBUG-E and pass if the monitor prompt appears.
+
+set runlimit 20M instructions
+set on
+set noon
+
+on error echof "\r\n*** FAILED - %SIM_NAME% SBUG-E monitor startup error ***\n"; exit 1
+on runtime echof "\r\n*** FAILED - %SIM_NAME% SBUG-E prompt timeout ***\n"; exit 1
+
+echof -n "** SWTP 6809: SBUG-E monitor prompt:\n\r"
+
+set mp-09 DAT
+set mp-1m 1024KB
+set cpu hex
+set cpu itrap
+set mp-s TTY
+set bootrom 2716
+attach -r bootrom ../sbuge.bin
+
+expect -p "S-BUG 1.8 - 56K\r\n\r\n>" echof "\n\rpassed\n\r"; exit 0
+
+reset
+
+go
+
+:: show expect
+echof "\r\n*** FAILED - SBUG-E monitor prompt not seen ***\r\n"
+exit 1
diff --git a/swtp6809/swtp6809/tests/swtp6809mp-09_test.ini b/swtp6809/swtp6809/tests/swtp6809mp-09_test.ini
new file mode 100644
index 000000000..2e0d4ac89
--- /dev/null
+++ b/swtp6809/swtp6809/tests/swtp6809mp-09_test.ini
@@ -0,0 +1,30 @@
+:: swtp6809mp-09_test.ini
+:: Boot SBUG-E and pass if the monitor prompt appears.
+
+cd %~p0
+
+set runlimit 20M instructions
+set on
+
+on error echof "\r\n*** FAILED - %SIM_NAME% SBUG-E monitor startup error ***\n"; exit 1
+on runtime echof "\r\n*** FAILED - %SIM_NAME% SBUG-E prompt timeout ***\n"; exit 1
+
+echof -n "** SWTP 6809: SBUG-E monitor prompt:\n\r"
+
+set mp-09 DAT
+set mp-1m 1024KB
+set cpu hex
+set cpu itrap
+set mp-s TTY
+set bootrom 2716
+attach -r bootrom ../sbuge.bin
+
+expect "S-BUG 1.8 - 56K\r\n\r\n>" echof "\n\rpassed\n\r"; exit 0
+
+reset
+
+go -q
+
+:: show expect
+echof "\r\n*** FAILED - SBUG-E monitor prompt not seen ***\r\n"
+exit 1