├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── imgs ├── example_code.jpg └── example_run.jpg ├── include ├── byte_utils.h ├── config.h ├── hw_ide.h ├── hw_tty.h ├── hw_tty_client.h ├── hw_web.h ├── linkedlist.h ├── queue_ll.h ├── tasm_opcode.h ├── utils.h ├── z80.h ├── z80_exec_main_codes.h ├── z80_extended_code_CB.h ├── z80_extended_code_DD.h ├── z80_extended_code_ED.h ├── z80_extended_code_FD.h ├── z80_opcodes.h ├── z80_registers.h ├── z80cpm_keyboard.h ├── z80cpm_memory.h └── z80cpm_screen.h ├── rom.bin ├── src ├── hw_ide.cpp ├── hw_tty.cpp ├── hw_web.cpp ├── linkedlist.cpp ├── main.cpp ├── queue_ll.cpp ├── tasm_opcode.cpp ├── utils.cpp ├── z80.cpp ├── z80cpm_keyboard.cpp ├── z80cpm_memory.cpp └── z80cpm_screen.cpp ├── z80cpm_vc └── z80cpm_emul │ ├── z80cpm_emul.sln │ └── z80cpm_emul │ ├── data.dsk │ ├── packages.config │ ├── rom.bin │ ├── tasm80.tab │ ├── z80cpm_emul.vcxproj │ └── z80cpm_emul.vcxproj.filters ├── z80sbcFiles.zip └── z80sbcFiles ├── TASM.TXT ├── TASM80.TAB ├── TASM_RELNOTES.TXT ├── _ASSEMBLE.BAT ├── basic.asm ├── source ├── basic.asm ├── cbios128.asm ├── cbios64.asm ├── cbios64.lst ├── cpm22.asm ├── cpm22.lst ├── download.asm ├── download.lst ├── form128.asm ├── form64.asm ├── monitor.asm ├── monitor.lst └── putsys.asm ├── transientAppsPackage └── CPM211FilesPkg.txt └── windowsApp └── COMDLG32.OCX /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | ## Ignore Visual Studio temporary files, build results, and 55 | ## files generated by popular Visual Studio add-ons. 56 | ## 57 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 58 | 59 | # User-specific files 60 | *.rsuser 61 | *.suo 62 | *.user 63 | *.userosscache 64 | *.sln.docstates 65 | 66 | # User-specific files (MonoDevelop/Xamarin Studio) 67 | *.userprefs 68 | 69 | # Mono auto generated files 70 | mono_crash.* 71 | 72 | # Build results 73 | [Dd]ebug/ 74 | [Dd]ebugPublic/ 75 | [Rr]elease/ 76 | [Rr]eleases/ 77 | x64/ 78 | x86/ 79 | [Ww][Ii][Nn]32/ 80 | [Aa][Rr][Mm]/ 81 | [Aa][Rr][Mm]64/ 82 | bld/ 83 | [Bb]in/ 84 | [Oo]bj/ 85 | [Ll]og/ 86 | [Ll]ogs/ 87 | 88 | # Visual Studio 2015/2017 cache/options directory 89 | .vs/ 90 | # Uncomment if you have tasks that create the project's static files in wwwroot 91 | #wwwroot/ 92 | 93 | # Visual Studio 2017 auto generated files 94 | Generated\ Files/ 95 | 96 | # MSTest test Results 97 | [Tt]est[Rr]esult*/ 98 | [Bb]uild[Ll]og.* 99 | 100 | # NUnit 101 | *.VisualState.xml 102 | TestResult.xml 103 | nunit-*.xml 104 | 105 | # Build Results of an ATL Project 106 | [Dd]ebugPS/ 107 | [Rr]eleasePS/ 108 | dlldata.c 109 | 110 | # Benchmark Results 111 | BenchmarkDotNet.Artifacts/ 112 | 113 | # .NET Core 114 | project.lock.json 115 | project.fragment.lock.json 116 | artifacts/ 117 | 118 | # ASP.NET Scaffolding 119 | ScaffoldingReadMe.txt 120 | 121 | # StyleCop 122 | StyleCopReport.xml 123 | 124 | # Files built by Visual Studio 125 | *_i.c 126 | *_p.c 127 | *_h.h 128 | *.ilk 129 | *.meta 130 | *.obj 131 | *.iobj 132 | *.pch 133 | *.pdb 134 | *.ipdb 135 | *.pgc 136 | *.pgd 137 | *.rsp 138 | *.sbr 139 | *.tlb 140 | *.tli 141 | *.tlh 142 | *.tmp 143 | *.tmp_proj 144 | *_wpftmp.csproj 145 | *.log 146 | *.vspscc 147 | *.vssscc 148 | .builds 149 | *.pidb 150 | *.svclog 151 | *.scc 152 | 153 | # Chutzpah Test files 154 | _Chutzpah* 155 | 156 | # Visual C++ cache files 157 | ipch/ 158 | *.aps 159 | *.ncb 160 | *.opendb 161 | *.opensdf 162 | *.sdf 163 | *.cachefile 164 | *.VC.db 165 | *.VC.VC.opendb 166 | 167 | # Visual Studio profiler 168 | *.psess 169 | *.vsp 170 | *.vspx 171 | *.sap 172 | 173 | # Visual Studio Trace Files 174 | *.e2e 175 | 176 | # TFS 2012 Local Workspace 177 | $tf/ 178 | 179 | # Guidance Automation Toolkit 180 | *.gpState 181 | 182 | # ReSharper is a .NET coding add-in 183 | _ReSharper*/ 184 | *.[Rr]e[Ss]harper 185 | *.DotSettings.user 186 | 187 | # TeamCity is a build add-in 188 | _TeamCity* 189 | 190 | # DotCover is a Code Coverage Tool 191 | *.dotCover 192 | 193 | # AxoCover is a Code Coverage Tool 194 | .axoCover/* 195 | !.axoCover/settings.json 196 | 197 | # Coverlet is a free, cross platform Code Coverage Tool 198 | coverage*.json 199 | coverage*.xml 200 | coverage*.info 201 | 202 | # Visual Studio code coverage results 203 | *.coverage 204 | *.coveragexml 205 | 206 | # NCrunch 207 | _NCrunch_* 208 | .*crunch*.local.xml 209 | nCrunchTemp_* 210 | 211 | # MightyMoose 212 | *.mm.* 213 | AutoTest.Net/ 214 | 215 | # Web workbench (sass) 216 | .sass-cache/ 217 | 218 | # Installshield output folder 219 | [Ee]xpress/ 220 | 221 | # DocProject is a documentation generator add-in 222 | DocProject/buildhelp/ 223 | DocProject/Help/*.HxT 224 | DocProject/Help/*.HxC 225 | DocProject/Help/*.hhc 226 | DocProject/Help/*.hhk 227 | DocProject/Help/*.hhp 228 | DocProject/Help/Html2 229 | DocProject/Help/html 230 | 231 | # Click-Once directory 232 | publish/ 233 | 234 | # Publish Web Output 235 | *.[Pp]ublish.xml 236 | *.azurePubxml 237 | # Note: Comment the next line if you want to checkin your web deploy settings, 238 | # but database connection strings (with potential passwords) will be unencrypted 239 | *.pubxml 240 | *.publishproj 241 | 242 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 243 | # checkin your Azure Web App publish settings, but sensitive information contained 244 | # in these scripts will be unencrypted 245 | PublishScripts/ 246 | 247 | # NuGet Packages 248 | *.nupkg 249 | # NuGet Symbol Packages 250 | *.snupkg 251 | # The packages folder can be ignored because of Package Restore 252 | **/[Pp]ackages/* 253 | # except build/, which is used as an MSBuild target. 254 | !**/[Pp]ackages/build/ 255 | # Uncomment if necessary however generally it will be regenerated when needed 256 | #!**/[Pp]ackages/repositories.config 257 | # NuGet v3's project.json files produces more ignorable files 258 | *.nuget.props 259 | *.nuget.targets 260 | 261 | # Microsoft Azure Build Output 262 | csx/ 263 | *.build.csdef 264 | 265 | # Microsoft Azure Emulator 266 | ecf/ 267 | rcf/ 268 | 269 | # Windows Store app package directories and files 270 | AppPackages/ 271 | BundleArtifacts/ 272 | Package.StoreAssociation.xml 273 | _pkginfo.txt 274 | *.appx 275 | *.appxbundle 276 | *.appxupload 277 | 278 | # Visual Studio cache files 279 | # files ending in .cache can be ignored 280 | *.[Cc]ache 281 | # but keep track of directories ending in .cache 282 | !?*.[Cc]ache/ 283 | 284 | # Others 285 | ClientBin/ 286 | ~$* 287 | *~ 288 | *.dbmdl 289 | *.dbproj.schemaview 290 | *.jfm 291 | *.pfx 292 | *.publishsettings 293 | orleans.codegen.cs 294 | 295 | # Including strong name files can present a security risk 296 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 297 | #*.snk 298 | 299 | # Since there are multiple workflows, uncomment next line to ignore bower_components 300 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 301 | #bower_components/ 302 | 303 | # RIA/Silverlight projects 304 | Generated_Code/ 305 | 306 | # Backup & report files from converting an old project file 307 | # to a newer Visual Studio version. Backup files are not needed, 308 | # because we have git ;-) 309 | _UpgradeReport_Files/ 310 | Backup*/ 311 | UpgradeLog*.XML 312 | UpgradeLog*.htm 313 | ServiceFabricBackup/ 314 | *.rptproj.bak 315 | 316 | # SQL Server files 317 | *.mdf 318 | *.ldf 319 | *.ndf 320 | 321 | # Business Intelligence projects 322 | *.rdl.data 323 | *.bim.layout 324 | *.bim_*.settings 325 | *.rptproj.rsuser 326 | *- [Bb]ackup.rdl 327 | *- [Bb]ackup ([0-9]).rdl 328 | *- [Bb]ackup ([0-9][0-9]).rdl 329 | 330 | # Microsoft Fakes 331 | FakesAssemblies/ 332 | 333 | # GhostDoc plugin setting file 334 | *.GhostDoc.xml 335 | 336 | # Node.js Tools for Visual Studio 337 | .ntvs_analysis.dat 338 | node_modules/ 339 | 340 | # Visual Studio 6 build log 341 | *.plg 342 | 343 | # Visual Studio 6 workspace options file 344 | *.opt 345 | 346 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 347 | *.vbw 348 | 349 | # Visual Studio LightSwitch build output 350 | **/*.HTMLClient/GeneratedArtifacts 351 | **/*.DesktopClient/GeneratedArtifacts 352 | **/*.DesktopClient/ModelManifest.xml 353 | **/*.Server/GeneratedArtifacts 354 | **/*.Server/ModelManifest.xml 355 | _Pvt_Extensions 356 | 357 | # Paket dependency manager 358 | .paket/paket.exe 359 | paket-files/ 360 | 361 | # FAKE - F# Make 362 | .fake/ 363 | 364 | # CodeRush personal settings 365 | .cr/personal 366 | 367 | # Python Tools for Visual Studio (PTVS) 368 | __pycache__/ 369 | *.pyc 370 | 371 | # Cake - Uncomment if you are using it 372 | # tools/** 373 | # !tools/packages.config 374 | 375 | # Tabs Studio 376 | *.tss 377 | 378 | # Telerik's JustMock configuration file 379 | *.jmconfig 380 | 381 | # BizTalk build output 382 | *.btp.cs 383 | *.btm.cs 384 | *.odx.cs 385 | *.xsd.cs 386 | 387 | # OpenCover UI analysis results 388 | OpenCover/ 389 | 390 | # Azure Stream Analytics local run output 391 | ASALocalRun/ 392 | 393 | # MSBuild Binary and Structured Log 394 | *.binlog 395 | 396 | # NVidia Nsight GPU debugger configuration file 397 | *.nvuser 398 | 399 | # MFractors (Xamarin productivity tool) working folder 400 | .mfractor/ 401 | 402 | # Local History for Visual Studio 403 | .localhistory/ 404 | 405 | # BeatPulse healthcheck temp database 406 | healthchecksdb 407 | 408 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 409 | MigrationBackup/ 410 | 411 | # Ionide (cross platform F# VS Code tools) working folder 412 | .ionide/ 413 | 414 | # Fody - auto-generated XML schema 415 | FodyWeavers.xsd 416 | 417 | 418 | /zx80_vc/zx80_emul/zx80_emul/packages.config 419 | /.vscode 420 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(CMAKE_CXX_STANDARD 11) 4 | set(CMAKE_CXX_STANDARD_REQUIRED True) 5 | 6 | project(zx80_emul) 7 | 8 | find_package(SDL2 CONFIG REQUIRED) 9 | include_directories(${SDL2_INCLUDE_DIRS}) 10 | 11 | add_executable(zx80_emul 12 | src/main.cpp 13 | src/z80_memory.cpp 14 | src/z80.cpp 15 | src/zx80_keyboard.cpp 16 | src/zx80_screen.cpp 17 | ) 18 | 19 | target_include_directories(zx80_emul PUBLIC include) 20 | 21 | target_link_libraries(zx80_emul PRIVATE SDL2::SDL2 SDL2::SDL2main) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | INCLUDES= -I ./include 2 | FLAGS = -O3 -std=c++11 3 | #FLAGS2 = -g 4 | 5 | OBJECTS=./build/utils.o ./build/hw_tty.o ./build/queue_ll.o ./build/linkedlist.o ./build/hw_web.o ./build/hw_ide.o ./build/tasm_opcode.o ./build/z80cpm_memory.o ./build/z80cpm_keyboard.o ./build/z80cpm_screen.o ./build/z80.o 6 | 7 | all: ${OBJECTS} 8 | gcc ${FLAGS} ${INCLUDES} ./src/main.cpp ${OBJECTS} -L ./lib -lstdc++ -lm -lncurses -pthread -o ./bin/main.exe 9 | 10 | ./build/hw_tty.o:src/hw_tty.cpp 11 | gcc ${FLAGS} ${INCLUDES} ./src/hw_tty.cpp -c -o ./build/hw_tty.o 12 | 13 | ./build/hw_web.o:src/hw_web.cpp 14 | gcc ${FLAGS} ${INCLUDES} ./src/hw_web.cpp -c -o ./build/hw_web.o 15 | 16 | 17 | ./build/linkedlist.o:src/linkedlist.cpp 18 | gcc ${FLAGS} ${INCLUDES} ./src/linkedlist.cpp -c -o ./build/linkedlist.o 19 | 20 | ./build/queue_ll.o:src/queue_ll.cpp 21 | gcc ${FLAGS} ${INCLUDES} ./src/queue_ll.cpp -c -o ./build/queue_ll.o 22 | 23 | ./build/hw_ide.o:src/hw_ide.cpp 24 | gcc ${FLAGS} ${INCLUDES} ./src/hw_ide.cpp -c -o ./build/hw_ide.o 25 | 26 | 27 | ./build/z80cpm_memory.o:src/z80cpm_memory.cpp 28 | gcc ${FLAGS} ${INCLUDES} ./src/z80cpm_memory.cpp -c -o ./build/z80cpm_memory.o 29 | 30 | ./build/z80cpm_keyboard.o:src/z80cpm_keyboard.cpp 31 | gcc ${FLAGS} ${INCLUDES} ./src/z80cpm_keyboard.cpp -c -o ./build/z80cpm_keyboard.o 32 | 33 | ./build/z80cpm_screen.o:src/z80cpm_screen.cpp 34 | gcc ${FLAGS} ${INCLUDES} ./src/z80cpm_screen.cpp -c -o ./build/z80cpm_screen.o 35 | 36 | ./build/z80.o:src/z80.cpp 37 | gcc ${FLAGS} ${INCLUDES} ./src/z80.cpp -c -o ./build/z80.o 38 | 39 | ./build/tasm_opcode.o:src/tasm_opcode.cpp 40 | gcc ${FLAGS} ${INCLUDES} ./src/tasm_opcode.cpp -c -o ./build/tasm_opcode.o 41 | 42 | ./build/utils.o:src/utils.cpp 43 | gcc ${FLAGS} ${INCLUDES} ./src/utils.cpp -c -o ./build/utils.o 44 | 45 | 46 | clean: 47 | rm build/* 48 | rm bin/main 49 | 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Z80 CPM Emulator [![Hackaday.io](https://img.shields.io/badge/Hackaday.io--blue.svg)](https://hackaday.io/project/184235-60x25-minimal-terminal) 2 | This is a Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 3 | 4 | The emulator was the landmark for [Baffa-2 Homebrew Microcomputer Project](https://baffa-2.baffasoft.com.br) 5 | 6 | CP/M Disk Manager is available at https://github.com/abaffa/cpm_disk_manager 7 | 8 | Project may be compiled using GCC/Mingw and Microsoft Visual C++ 9 | 10 | . MSVC Project at /z80cpm_vc/ folder 11 | 12 | ![Listing Program](imgs/example_code.jpg?raw=true "Listing Basic Program") 13 | 14 | ![Running Program](imgs/example_run.jpg?raw=true "Running CPM") 15 | 16 | -----BEGIN LICENSE NOTICE----- 17 | 18 | Z80 CPM Emulator 19 | 20 | Copyright (C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 21 | 22 | This program is free software; you can redistribute it and/or 23 | modify it under the terms of the GNU General Public License 24 | as published by the Free Software Foundation; either version 2 25 | of the License, or (at your option) any later version. 26 | 27 | This program is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | GNU General Public License for more details. 31 | 32 | You should have received a copy of the GNU General Public License 33 | along with this program; if not, write to the Free Software 34 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 35 | 36 | -----END LICENSE NOTICE----- 37 | -------------------------------------------------------------------------------- /imgs/example_code.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaffa/z80cpm_emulator/7ed59c9e49bd4f223e174ea87746bfabe73761bf/imgs/example_code.jpg -------------------------------------------------------------------------------- /imgs/example_run.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaffa/z80cpm_emulator/7ed59c9e49bd4f223e174ea87746bfabe73761bf/imgs/example_run.jpg -------------------------------------------------------------------------------- /include/byte_utils.h: -------------------------------------------------------------------------------- 1 | #define WORD(l, h) (((h)<<8) | (l)) 2 | #define LSB(w) ((w) & 0xff) 3 | #define MSB(w) (((w) >> 8) & 0xff) 4 | #define SET_LSB(Rg, l) Rg = ((Rg & 0xFF00) | ((l) & 0xff)) 5 | #define SET_MSB(Rg, h) Rg = ((h)<<8) | (Rg & 0x00FF) 6 | #define SET_WORD(Rg, l, h) Rg = WORD(l, h) -------------------------------------------------------------------------------- /include/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define EMULATOR_WINDOW_TITLE "Z80CPM Emulator" 10 | 11 | #define DEBUG_OPCODE 0 12 | #define SERVER_WEB 0 13 | #define SERVER_TELNET 1 14 | 15 | #define Z80CPM_MEMORY_SIZE 0xFFFF //0x100 16 | #define Z80_PROGRAM_LOAD_ADDRESS 0X000 17 | #define Z80CPM_WIDTH 256 //32 x 8 18 | #define Z80CPM_HEIGHT 200 // 25 x 8 19 | #define Z80CPM_BORDER 40 20 | #define Z80CPM_WINDOW_MULTIPLIER 2 21 | 22 | 23 | #define Z80_TOTAL_DATA_REGISTERS 16 24 | #define Z80_TOTAL_STACK_DEPTH 16 25 | #define Z80CPM_TOTAL_KEYS 41 26 | #define Z80_CHARACTER_SET_LOAD_ADDRESS 0x00 27 | #define Z80_DEFAULT_SPRITE_HEIGHT 5 28 | 29 | #define Z80CPM_IDE_MEMORY_SIZE 6.4e+7 30 | 31 | #endif 32 | 33 | -------------------------------------------------------------------------------- /include/hw_ide.h: -------------------------------------------------------------------------------- 1 | // 2 | // hw_ide.h 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #ifndef HWIDE_H 19 | #define HWIDE_H 20 | 21 | #include 22 | #include "config.h" 23 | 24 | 25 | struct hw_ide { 26 | 27 | int gambi_ide_total; 28 | int gambi_ide_read; 29 | 30 | int lba_size; 31 | 32 | unsigned char data[8]; 33 | 34 | unsigned char* memory; 35 | 36 | int save; 37 | }; 38 | 39 | void hw_ide_init(struct hw_ide* hw_ide); 40 | void hw_ide_reset(struct hw_ide* hw_ide); 41 | 42 | void hw_ide_read(struct hw_ide* hw_ide); 43 | void hw_ide_write(struct hw_ide* hw_ide); 44 | 45 | void hw_ide_print(struct hw_ide* hw_ide, char *dir, int changed, char *print); 46 | 47 | 48 | void hw_ide_save_disk(unsigned char *data); 49 | void hw_ide_load_disk(unsigned char *data); 50 | #endif 51 | -------------------------------------------------------------------------------- /include/hw_tty.h: -------------------------------------------------------------------------------- 1 | // 2 | // hw_tty.h 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #ifndef HWTTY_H 19 | #define HWTTY_H 20 | 21 | #include "config.h" 22 | #include "hw_tty_client.h" 23 | #include 24 | 25 | #if defined(__linux__) || defined(__MINGW32__) 26 | #include 27 | #include 28 | #else 29 | #include 30 | #include 31 | #include 32 | 33 | // Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib 34 | #pragma comment (lib, "Ws2_32.lib") 35 | #pragma comment (lib, "Mswsock.lib") 36 | #pragma comment (lib, "AdvApi32.lib") 37 | 38 | #endif 39 | 40 | 41 | using namespace std; 42 | 43 | 44 | 45 | 46 | class HW_TTY { 47 | 48 | 49 | public: 50 | 51 | HW_TTY_CLIENT clients[10]; 52 | 53 | struct net_data { 54 | unsigned char data; 55 | }; 56 | 57 | unsigned char started; 58 | unsigned char debug_call; 59 | unsigned char console; 60 | 61 | //void init(struct hw_uart *hw_uart); 62 | void start_server(queue *keyboard_queue); 63 | 64 | queue tty_in; 65 | 66 | void send(unsigned char b); 67 | unsigned char receive(); 68 | 69 | void print(const char* s); 70 | 71 | void set_input(unsigned char b); 72 | 73 | char* gets(int max_value); 74 | char* getline(); 75 | char get_char(); 76 | 77 | HW_TTY() { 78 | started = 0; 79 | debug_call = 0; 80 | console = 0; 81 | } 82 | }; 83 | #endif -------------------------------------------------------------------------------- /include/hw_tty_client.h: -------------------------------------------------------------------------------- 1 | // 2 | // hw_tty_client.h 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #ifndef HWTTYCLIENT_H 19 | #define HWTTYCLIENT_H 20 | #include "config.h" 21 | #include 22 | 23 | #if defined(__linux__) || defined(__MINGW32__) 24 | #include 25 | #include 26 | #else 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | // Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib 33 | #pragma comment (lib, "Ws2_32.lib") 34 | #pragma comment (lib, "Mswsock.lib") 35 | #pragma comment (lib, "AdvApi32.lib") 36 | 37 | #endif 38 | 39 | using namespace std; 40 | 41 | 42 | class HW_TTY_CLIENT { 43 | 44 | public: 45 | int running; 46 | int index; 47 | #ifdef _MSC_VER 48 | SOCKET *client; 49 | mutex mtx_out; 50 | condition_variable cv_out; 51 | 52 | #else 53 | int *client; 54 | pthread_mutex_t mtx_out; 55 | #endif 56 | queue *keyboard_queue; 57 | queue tty_out; 58 | queue* tty_in; 59 | unsigned char* console; 60 | unsigned char* debug_call; 61 | 62 | HW_TTY_CLIENT() { 63 | tty_in = NULL; 64 | } 65 | }; 66 | 67 | #endif -------------------------------------------------------------------------------- /include/hw_web.h: -------------------------------------------------------------------------------- 1 | // 2 | // hw_web.h 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #ifndef HWWEB_H 19 | #define HWWEB_H 20 | 21 | #include 22 | 23 | #include "queue_ll.h" 24 | 25 | #if defined(__linux__) || defined(__MINGW32__) 26 | #include 27 | #include 28 | #else 29 | 30 | #include 31 | #include 32 | 33 | // Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib 34 | #pragma comment (lib, "Ws2_32.lib") 35 | #pragma comment (lib, "Mswsock.lib") 36 | #pragma comment (lib, "AdvApi32.lib") 37 | 38 | 39 | #endif 40 | 41 | #include 42 | using namespace std; 43 | 44 | struct hw_web_client { 45 | 46 | int running; 47 | int index; 48 | #ifdef _MSC_VER 49 | SOCKET *client; 50 | #else 51 | int *client; 52 | #endif 53 | queue* tty_in; 54 | Queue* web_out; 55 | 56 | }; 57 | 58 | class HW_WEB { 59 | 60 | public: 61 | 62 | 63 | std::string currentline; 64 | 65 | struct hw_web_client clients[10]; 66 | 67 | struct net_data { 68 | char data; 69 | }; 70 | 71 | HW_WEB() { 72 | this->currentline = ""; 73 | } 74 | //void init(SOL1_CPU& sol1_cpu, struct hw_uart *hw_uart); 75 | void new_char(char c); 76 | void start_server(queue* tty_in); 77 | 78 | }; 79 | #endif -------------------------------------------------------------------------------- /include/linkedlist.h: -------------------------------------------------------------------------------- 1 | // 2 | // linked_list.h 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | typedef struct linked_list 19 | { 20 | void* info; 21 | struct linked_list *next; 22 | } Linked_List; 23 | 24 | 25 | Linked_List* ll_create (void); 26 | 27 | Linked_List* ll_insert (Linked_List* ll, void* info); 28 | 29 | Linked_List* ll_insert_sorted (Linked_List* ll, void* info, int (*cmp)(void *, void *)); 30 | 31 | Linked_List* ll_remove_first (Linked_List* ll); 32 | 33 | Linked_List* ll_remove (Linked_List* ll, void* info, int (*cmp)(void *, void *)); 34 | 35 | void ll_print (Linked_List* ll, void (*print)(void *)); 36 | 37 | Linked_List* ll_find (Linked_List* ll, void* info, int (*cmp)(void *, void *)); 38 | 39 | int ll_equal (Linked_List* ll1, Linked_List* ll2, int (*cmp)(void *, void *)); 40 | 41 | int ll_empty (Linked_List* ll); 42 | 43 | void ll_free (Linked_List* ll, void (* ffree)(void *)); 44 | 45 | int ll_size(Linked_List* ll); -------------------------------------------------------------------------------- /include/queue_ll.h: -------------------------------------------------------------------------------- 1 | // 2 | // queue_ll.h 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #ifndef DEQUEUE_H 19 | #define DEQUEUE_H 20 | 21 | #include "linkedlist.h" 22 | 23 | typedef struct queue_ll Queue; 24 | 25 | 26 | Queue* queue_create (void); 27 | 28 | void queue_insert (Queue* f, void* info); 29 | 30 | void* queue_remove (Queue* f); 31 | 32 | int queue_empty (Queue* f); 33 | 34 | void queue_free (Queue* f, void (* ffree)(void *)); 35 | 36 | void queue_print (Queue* f, void (* fprint)(void *)); 37 | 38 | #endif -------------------------------------------------------------------------------- /include/tasm_opcode.h: -------------------------------------------------------------------------------- 1 | // 2 | // tasm_opcode.h 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #ifndef TASM_OPCODESOL1COMPUTER_H 19 | #define SOL1COMPUTER_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | using namespace std; 26 | 27 | class Tasm_Opcode 28 | { 29 | public: 30 | string opcode; 31 | string desc; 32 | int size; 33 | 34 | Tasm_Opcode() {}; 35 | Tasm_Opcode(string opcode, string desc, int size); 36 | }; 37 | 38 | #endif -------------------------------------------------------------------------------- /include/utils.h: -------------------------------------------------------------------------------- 1 | // 2 | // utils.h 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #ifndef UTILS_H 19 | #define UTILS_H 20 | 21 | #include "config.h" 22 | 23 | #ifdef __linux__ 24 | int getch(void); 25 | int kbhit(); 26 | char* itoa(int value, char* result, int base); 27 | #else 28 | #include "conio.h" 29 | #endif 30 | 31 | #define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" 32 | #define BYTE_TO_BINARY(byte) \ 33 | (byte & 0x80 ? '1' : '0'), \ 34 | (byte & 0x40 ? '1' : '0'), \ 35 | (byte & 0x20 ? '1' : '0'), \ 36 | (byte & 0x10 ? '1' : '0'), \ 37 | (byte & 0x08 ? '1' : '0'), \ 38 | (byte & 0x04 ? '1' : '0'), \ 39 | (byte & 0x02 ? '1' : '0'), \ 40 | (byte & 0x01 ? '1' : '0') 41 | 42 | #define INV_BYTE_TO_BINARY(byte) \ 43 | (byte & 0x01 ? '1' : '0'), \ 44 | (byte & 0x02 ? '1' : '0'), \ 45 | (byte & 0x04 ? '1' : '0'), \ 46 | (byte & 0x08 ? '1' : '0'), \ 47 | (byte & 0x10 ? '1' : '0'), \ 48 | (byte & 0x20 ? '1' : '0'), \ 49 | (byte & 0x40 ? '1' : '0'), \ 50 | (byte & 0x80 ? '1' : '0') 51 | 52 | #define NIBBLE_TO_BINARY(byte) \ 53 | (byte & 0x08 ? '1' : '0'), \ 54 | (byte & 0x04 ? '1' : '0'), \ 55 | (byte & 0x02 ? '1' : '0'), \ 56 | (byte & 0x01 ? '1' : '0') 57 | 58 | #define LSN(w) ((w) & 0x0f) 59 | #define MSN(w) (((w) >> 4) & 0x0f) 60 | 61 | #define WORD(l, h) (((h)<<8) | (l)) 62 | #define LSB(w) ((w) & 0xff) 63 | #define MSB(w) (((w) >> 8) & 0xff) 64 | #define SET_LSB(Rg, l) Rg = ((Rg & 0xFF00) | ((l) & 0xff)) 65 | #define SET_MSB(Rg, h) Rg = ((h)<<8) | (Rg & 0x00FF) 66 | #define SET_WORD(Rg, l, h) Rg = WORD(l, h) 67 | 68 | void print_word_bin(char *s, short n); 69 | void print_word_bin_nibbles(char *s, short n); 70 | 71 | void print_byte_bin(char *s, char b); 72 | 73 | void print_nibble_bin(char *s, char b); 74 | 75 | unsigned int toInt(char c); 76 | 77 | 78 | 79 | void leftpad(char *str1, char *str2, int pad); 80 | char* rightpad(const char *str1, int pad); 81 | 82 | unsigned int convert_hexstr_to_value(char *value); 83 | 84 | 85 | char* loadfile(char *s, char *filename, long *size); 86 | 87 | 88 | void save_to_log(char *s, FILE *fa, char *str); 89 | 90 | char* strlower(char* s); 91 | #endif -------------------------------------------------------------------------------- /include/z80.h: -------------------------------------------------------------------------------- 1 | #ifndef Z80_H 2 | #define Z80_H 3 | 4 | #include "config.h" 5 | #include "z80cpm_memory.h" 6 | #include "z80_registers.h" 7 | #include 8 | #include "hw_ide.h" 9 | 10 | #if SERVER_TELNET == 1 11 | #include "hw_tty.h" 12 | #endif 13 | 14 | #if SERVER_WEB == 1 15 | #include "hw_web.h" 16 | #endif 17 | 18 | #include 19 | using namespace std; 20 | /* LoopZ80() may return: */ 21 | #define INT_RST00 0x00C7 /* RST 00h */ 22 | #define INT_RST08 0x00CF /* RST 08h */ 23 | #define INT_RST10 0x00D7 /* RST 10h */ 24 | #define INT_RST18 0x00DF /* RST 18h */ 25 | #define INT_RST20 0x00E7 /* RST 20h */ 26 | #define INT_RST28 0x00EF /* RST 28h */ 27 | #define INT_RST30 0x00F7 /* RST 30h */ 28 | #define INT_RST38 0x00FF /* RST 38h */ 29 | #define INT_IRQ INT_RST38 /* Default IRQ opcode is FFh */ 30 | #define INT_NMI 0xFFFD /* Non-maskable interrupt */ 31 | #define INT_NONE 0xFFFF /* No interrupt required */ 32 | #define INT_QUIT 0xFFFE /* Exit the emulation */ 33 | 34 | /* Bits in Z80 F register: */ 35 | #define S_FLAG 0x80 /* 1: Result negative */ 36 | #define Z_FLAG 0x40 /* 1: Result is zero */ 37 | #define X2_FLAG 0x20 /* UNUSED BITS */ 38 | #define H_FLAG 0x10 /* 1: Halfcarry/Halfborrow */ 39 | #define X1_FLAG 0x08 /* UNUSED BITS */ 40 | #define P_FLAG 0x04 /* 1: Result is even */ 41 | #define V_FLAG 0x04 /* 1: Overflow occured */ 42 | #define N_FLAG 0x02 /* 1: Subtraction occured */ 43 | #define C_FLAG 0x01 /* 1: Carry/Borrow occured */ 44 | 45 | #define IFF_1 0x01 /* IFF1 flip-flop */ 46 | #define IFF_IM1 0x02 /* 1: IM1 mode */ 47 | #define IFF_IM2 0x04 /* 1: IM2 mode */ 48 | #define IFF_2 0x08 /* IFF2 flip-flop */ 49 | #define IFF_EI 0x20 /* 1: EI pending */ 50 | #define IFF_HALT 0x80 /* 1: CPU HALTed */ 51 | 52 | class Z80 53 | { 54 | public: 55 | //struct z80_memory memory; 56 | struct z80_registers registers; 57 | 58 | short IPeriod,ICount; /* Set IPeriod to number of CPU cycles */ 59 | /* between calls to LoopZ80() */ 60 | short IBackup; /* Private, don't touch */ 61 | unsigned short IRequest; /* Set to address of pending IRQ */ 62 | unsigned char IAutoReset; /* Set to 1 to autom. reset IRequest */ 63 | unsigned char TrapBadOps; /* Set to 1 to warn of illegal opcodes */ 64 | unsigned short Trap; /* Set Trap to address to trace from */ 65 | unsigned char Trace; /* Set Trace=1 to start tracing */ 66 | long User; /* Arbitrary user data (ID,RAM*,etc.) */ 67 | 68 | char last_op_desc[512]; 69 | 70 | 71 | unsigned char keyboard_int; 72 | unsigned char PORT_0002h;// = 0x0; 73 | 74 | unsigned char PORT_FEFEh;// = 0x0; 75 | unsigned char PORT_FDFEh;// = 0x0; 76 | unsigned char PORT_FBFEh;// = 0x0; 77 | unsigned char PORT_F7FEh;// = 0x0; 78 | unsigned char PORT_EFFEh;// = 0x0; 79 | unsigned char PORT_DFFEh;// = 0x0; 80 | unsigned char PORT_BFFEh;// = 0x0; 81 | unsigned char PORT_7FFEh;// = 0x0; 82 | 83 | struct z80cpm_memory *z80cpm_memory; 84 | struct hw_ide hw_ide; 85 | 86 | #if SERVER_TELNET == 1 87 | HW_TTY hw_tty; 88 | #endif 89 | 90 | #if SERVER_WEB == 1 91 | HW_WEB hw_web; 92 | #endif 93 | 94 | 95 | queue keyboard_queue; 96 | 97 | void z80_init(); 98 | void z80_exec(struct z80cpm_memory* z80cpm_memory); 99 | void z80_reset(); 100 | 101 | unsigned char RdZ80(struct z80cpm_memory* z80cpm_memory, unsigned short Address); 102 | void WrZ80(struct z80cpm_memory* z80cpm_memory, unsigned short Address, unsigned char V); 103 | 104 | void IntZ80(struct z80cpm_memory* z80cpm_memory, unsigned short Vector); 105 | void JumpZ80(unsigned short PC); 106 | 107 | unsigned char InZ80(unsigned short Port); 108 | 109 | //void OutZ80(unsigned short Port, unsigned char Value); 110 | void OutZ80(struct z80cpm_memory* z80cpm_memory, unsigned short Port, unsigned char Value); 111 | 112 | private: 113 | unsigned char OpZ80(struct z80cpm_memory* z80cpm_memory, unsigned short A); 114 | unsigned short LoopZ80(); 115 | 116 | void debug_opcode(char *op, char *desc); 117 | void debug_opcode_reg_word(struct z80cpm_memory* z80cpm_memory, char *op, char *desc); 118 | void debug_opcode_reg_byte(struct z80cpm_memory* z80cpm_memory, char *op, char *desc); 119 | void debug_opcode_reg_byte_byte(struct z80cpm_memory* z80cpm_memory, char *op, char *desc); 120 | void disassembly_current_opcode(struct z80cpm_memory* z80cpm_memory, unsigned char current_opcode); 121 | 122 | 123 | void z80_exec_main_code(unsigned char opcode, struct z80cpm_memory* z80cpm_memory); 124 | void z80_exec_extended_CB(struct z80cpm_memory* z80cpm_memory); 125 | void z80_exec_extended_DD(struct z80cpm_memory* z80cpm_memory); 126 | void z80_exec_extended_ED(struct z80cpm_memory* z80cpm_memory); 127 | void z80_exec_extended_FD(struct z80cpm_memory* z80cpm_memory); 128 | 129 | void z80_exec_extended_DDCB(struct z80cpm_memory* z80cpm_memory); 130 | void z80_exec_extended_FDCB(struct z80cpm_memory* z80cpm_memory); 131 | }; 132 | 133 | 134 | 135 | 136 | 137 | 138 | #endif -------------------------------------------------------------------------------- /include/z80_registers.h: -------------------------------------------------------------------------------- 1 | #ifndef Z80REGISTERS_H 2 | #define Z80REGISTERS_H 3 | 4 | #include "config.h" 5 | struct z80_registers 6 | { 7 | //General Purpose Registers 8 | unsigned short AF; // AH/FL(accumulator and flags) 8-bit accumulator (A) and flag bits (F) carry, zero, minus, parity/overflow, half-carry (used for BCD), and an Add/Subtract flag (usually called N) also for BCD 9 | unsigned short BC; // BH/CL 16-bit data/address register or two 8-bit registers 10 | unsigned short DE; // DH/EL 16-bit data/address register or two 8-bit registers 11 | unsigned short HL; // HH/LL(indirect address) 16-bit accumulator/address register or two 8-bit registers 12 | 13 | //Alternate registers 14 | unsigned short AFl; //AF': alternate (or shadow) accumulator and flags (toggled in and out with EX AF,AF' ) 15 | unsigned short BCl; //BC', DE' and HL': alternate (or shadow) registers (toggled in and out with EXX) 16 | unsigned short DEl; 17 | unsigned short HLl; 18 | 19 | //Index registers 20 | unsigned short IX; //IX(Index X) 16-bit index or base register for 8-bit immediate offsets 21 | unsigned short IY; //IYIndex Y) 16-bit index or base register for 8-bit immediate offsets 22 | unsigned short SP; //SP stack pointer, 16 bits 23 | 24 | //Program counter 25 | unsigned short PC; //PC - program counter, 16 bits 26 | 27 | //Other registers 28 | unsigned char IFF,I; //I: interrupt vector base register, 8 bits 29 | unsigned char R; //R: DRAM refresh counter, 8 bits (msb does not count) 30 | 31 | //Interrupt registers 32 | //IFF1 33 | //IFF2 34 | //IM 35 | 36 | 37 | //Status register(F) - flags 38 | //unsigned char S; /*flag S Result negative */ 39 | //unsigned char Z; /*flag Z Result is zero */ 40 | //unsigned char H; /*flag H Halfcarry/Halfborrow */ 41 | //unsigned char P; /*flag P Result is even */ 42 | //unsigned char V; /*flag V Overflow occured */ 43 | //unsigned char N; /*flag N Subtraction occured */ 44 | //unsigned char C; /*flag C Carry/Borrow occured */ 45 | 46 | }; 47 | 48 | #endif -------------------------------------------------------------------------------- /include/z80cpm_keyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef Z80CPMKEYBOARD_H 2 | #define Z80CPMKEYBOARD_H 3 | 4 | #include 5 | #include "config.h" 6 | struct z80cpm_keyboard 7 | { 8 | bool keyboard[Z80CPM_TOTAL_KEYS]; 9 | const unsigned int* keyboard_map; 10 | }; 11 | 12 | void z80cpm_keyboard_set_map(struct z80cpm_keyboard* keyboard, const unsigned int* map); 13 | int z80cpm_keyboard_map(struct z80cpm_keyboard* keyboard, int key); 14 | void z80cpm_keyboard_down(struct z80cpm_keyboard* keyboard, int key); 15 | void z80cpm_keyboard_up(struct z80cpm_keyboard* keyboard, int key); 16 | bool z80cpm_keyboard_is_down(struct z80cpm_keyboard* keyboard, int key); 17 | 18 | #endif -------------------------------------------------------------------------------- /include/z80cpm_memory.h: -------------------------------------------------------------------------------- 1 | #ifndef Z80CPMMEMORY_H 2 | #define Z80CPMMEMORY_H 3 | 4 | #include "config.h" 5 | struct z80cpm_memory 6 | { 7 | unsigned char* memory; //[z80cpm_MEMORY_SIZE]; 8 | unsigned char* rom; //[z80cpm_MEMORY_SIZE]; 9 | 10 | char rom_disabled; 11 | }; 12 | 13 | void z80cpm_memory_set(struct z80cpm_memory* memory, int index, unsigned char val); 14 | unsigned char z80cpm_memory_get(struct z80cpm_memory* memory,int index); 15 | unsigned short z80cpm_memory_get_short(struct z80cpm_memory* memory,int index); 16 | 17 | //unsigned char RdZ80(struct z80cpm_memory* z80cpm_memory, unsigned short Address); 18 | //void WrZ80(struct z80cpm_memory* z80cpm_memory, unsigned short Address, unsigned char V); 19 | #endif -------------------------------------------------------------------------------- /include/z80cpm_screen.h: -------------------------------------------------------------------------------- 1 | #ifndef Z80CPMSCREEN_H 2 | #define Z80CPMSCREEN_H 3 | 4 | #include 5 | #include "config.h" 6 | struct z80cpm_screen 7 | { 8 | bool pixels[Z80CPM_HEIGHT][Z80CPM_WIDTH]; 9 | }; 10 | 11 | void z80cpm_screen_set(struct z80cpm_screen* screen, int x, int y); 12 | void z80cpm_screen_clear(struct z80cpm_screen* screen); 13 | bool z80cpm_screen_is_set(struct z80cpm_screen* screen, int x, int y); 14 | bool z80cpm_screen_draw_sprite(struct z80cpm_screen* screen, int x, int y, const char* sprite, int num); 15 | #endif -------------------------------------------------------------------------------- /rom.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaffa/z80cpm_emulator/7ed59c9e49bd4f223e174ea87746bfabe73761bf/rom.bin -------------------------------------------------------------------------------- /src/hw_ide.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // hw_ide.cpp 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #include "hw_ide.h" 19 | #include 20 | #include 21 | #include 22 | 23 | void hw_ide_init(struct hw_ide* hw_ide) { 24 | 25 | int address = 0; 26 | hw_ide->lba_size = 512; 27 | hw_ide->save = 0; 28 | 29 | hw_ide->memory = (unsigned char*)malloc(Z80CPM_IDE_MEMORY_SIZE * sizeof(unsigned char)); 30 | 31 | for (address = 0; address < Z80CPM_IDE_MEMORY_SIZE; address++) { 32 | hw_ide->memory[address] = 0x00; 33 | } 34 | 35 | for (address = 0; address < 8; address++) { 36 | hw_ide->data[address] = 0x00; 37 | } 38 | 39 | hw_ide_reset(hw_ide); 40 | } 41 | 42 | void hw_ide_reset(struct hw_ide* hw_ide) { 43 | hw_ide->gambi_ide_total = 0; 44 | hw_ide->gambi_ide_read = 0; 45 | } 46 | 47 | 48 | 49 | int chs(int lba, int C = 1024, int H = 255, int S = 63) { 50 | /* 51 | 'lba' linearly addresses sector, indexing from zero. 52 | 'C', 'H', 'S' specify geometry - fixed for a given disk : 53 | 1 <= C <= 1024 (10 bits) 54 | 1 <= H <= 255 (8 bits) not 256 due to WD1010 quirk 55 | 1 <= S <= 63 (6 Bits) not 64 due to WD1010 quirk 56 | Returns address as c, h, s tuple : 57 | 0 <= c <= 1023 (10 bits) modulo C 58 | 0 <= h <= 255 (8 bits) modulo H 59 | 1 <= s <= 63 (6 Bits) not 64 due to WD1010 quirk 60 | */ 61 | 62 | 63 | if (C < 1 || H < 1 || S < 1 || C>1024 || H>255 || S>63) 64 | printf("Invalid (C,H,S) geometry: (%d,%d,%d)", C, H, S); 65 | 66 | int t, s = lba % S; 67 | s += 1; // tracks, sector offset 68 | int c, h = t % H; 69 | 70 | if (c >= C) 71 | printf("Unaddressable lba value: %d for (%d,%d,%d) geometry.", lba, C, H, S); 72 | return (c, h, s); 73 | } 74 | 75 | int lba(int c, int h, int s, int C = 1024, int H = 255, int S = 63) { 76 | /* 77 | 'C', 'H', 'S' specify geometry as for function 'chs'. 78 | 'c', 'h', 's' address a sector in this geometry. 79 | */ 80 | 81 | if (C < 1 || H < 1 || S < 1 || C>1024 || H>255 || S>63) 82 | printf("Invalid (C,H,S) geometry: (%d,%d,%d)", C, H, S); 83 | 84 | if (c < 0 || h < 0 || s<1 || c >= C || h >= H || s>S) 85 | printf("Unaddressable (c,h,s) value: (%d,%d,%d) for (%d,%d,%d) geometry.", c, h, s, C, H, S); 86 | 87 | 88 | 89 | return (c*H + h)*S + (s - 1); 90 | } 91 | 92 | void hw_ide_write(struct hw_ide* hw_ide) { 93 | if (hw_ide->data[7] == 0b00001000) { 94 | 95 | hw_ide->save = 1; 96 | 97 | hw_ide->gambi_ide_total = hw_ide->data[2]; 98 | 99 | unsigned long sec_address_lba = hw_ide->data[3]; 100 | sec_address_lba = sec_address_lba | ((unsigned long)hw_ide->data[4]) << 8; 101 | sec_address_lba = sec_address_lba | ((unsigned long)hw_ide->data[5]) << 16; 102 | sec_address_lba = sec_address_lba | ((unsigned long)(hw_ide->data[6] & 0b00001111)) << 24; 103 | 104 | unsigned long sec_address_byte = sec_address_lba * hw_ide->lba_size; 105 | 106 | if (sec_address_byte < Z80CPM_IDE_MEMORY_SIZE) { 107 | hw_ide->memory[sec_address_byte + hw_ide->gambi_ide_read] = hw_ide->data[0]; 108 | 109 | hw_ide->gambi_ide_read++; 110 | 111 | if (hw_ide->gambi_ide_read >= hw_ide->gambi_ide_total * hw_ide->lba_size) 112 | { 113 | hw_ide->data[7] = 0x00; 114 | hw_ide_reset(hw_ide); 115 | 116 | hw_ide_save_disk(hw_ide->memory); 117 | } 118 | } 119 | else { 120 | hw_ide->data[7] = 0x34; 121 | hw_ide_reset(hw_ide); 122 | } 123 | } 124 | 125 | } 126 | 127 | 128 | /* 129 | _IDE_R0.equ _IDE_BASE + 0; DATA PORT 130 | _IDE_R1.equ _IDE_BASE + 1; READ: ERROR CODE, WRITE : FEATURE 131 | _IDE_R2.equ _IDE_BASE + 2; NUMBER OF SECTORS TO TRANSFER 132 | _IDE_R3.equ _IDE_BASE + 3; SECTOR ADDRESS LBA 0[0:7] 133 | _IDE_R4.equ _IDE_BASE + 4; SECTOR ADDRESS LBA 1[8:15] 134 | _IDE_R5.equ _IDE_BASE + 5; SECTOR ADDRESS LBA 2[16:23] 135 | _IDE_R6.equ _IDE_BASE + 6; SECTOR ADDRESS LBA 3[24:27 (LSB)] 136 | _IDE_R7.equ _IDE_BASE + 7; READ: STATUS, WRITE : COMMAND 137 | */ 138 | void hw_ide_read(struct hw_ide* hw_ide) { 139 | 140 | if (hw_ide->data[7] == 0b00001000) { 141 | 142 | hw_ide->gambi_ide_total = hw_ide->data[2]; 143 | 144 | unsigned long sec_address_lba = hw_ide->data[3]; 145 | sec_address_lba = sec_address_lba | ((unsigned long)hw_ide->data[4]) << 8; 146 | sec_address_lba = sec_address_lba | ((unsigned long)hw_ide->data[5]) << 16; 147 | sec_address_lba = sec_address_lba | ((unsigned long)(hw_ide->data[6] & 0b00001111)) << 24; 148 | 149 | unsigned long sec_address_byte = sec_address_lba * hw_ide->lba_size; 150 | 151 | if (sec_address_byte < Z80CPM_IDE_MEMORY_SIZE) { 152 | hw_ide->data[0] = hw_ide->memory[sec_address_byte + hw_ide->gambi_ide_read]; 153 | 154 | hw_ide->gambi_ide_read++; 155 | 156 | if (hw_ide->gambi_ide_read >= hw_ide->gambi_ide_total * hw_ide->lba_size) 157 | { 158 | hw_ide->data[7] = 0x00; 159 | hw_ide_reset(hw_ide); 160 | } 161 | } 162 | else { 163 | hw_ide->data[7] = 0x24; 164 | hw_ide_reset(hw_ide); 165 | } 166 | } 167 | 168 | } 169 | 170 | 171 | 172 | void hw_ide_save_disk(unsigned char *data) { 173 | FILE *file = fopen("data.dsk", "wb"); 174 | if (file != NULL) { 175 | fwrite(data, sizeof(unsigned char), Z80CPM_IDE_MEMORY_SIZE, file); 176 | fclose(file); 177 | } 178 | } 179 | 180 | void hw_ide_load_disk(unsigned char *data) { 181 | FILE *file = fopen("data.dsk", "rb"); 182 | if (file != NULL) { 183 | fread(data, sizeof(unsigned char), Z80CPM_IDE_MEMORY_SIZE, file); 184 | fclose(file); 185 | } 186 | } 187 | 188 | 189 | 190 | 191 | void hw_ide_print(struct hw_ide* hw_ide, char *dir, int changed, char *print) { 192 | 193 | int i = 0; 194 | sprintf(print, ">>> IDE [%s]: ", dir); 195 | for (i = 0; i < 7; i++) { 196 | 197 | if (changed == i) 198 | sprintf(print + strlen(print), "[%02x(%d)", hw_ide->data[i], hw_ide->data[i]); 199 | else if (changed == i - 1) 200 | sprintf(print + strlen(print), "]%02x(%d)", hw_ide->data[i], hw_ide->data[i]); 201 | else 202 | sprintf(print + strlen(print), " %02x(%d)", hw_ide->data[i], hw_ide->data[i]); 203 | } 204 | 205 | if (changed == i) 206 | sprintf(print + strlen(print), "[%02x(%d)", hw_ide->data[i], hw_ide->data[i]); 207 | else if (changed == i - 1) 208 | sprintf(print + strlen(print), "]%02x(%d)", hw_ide->data[i], hw_ide->data[i]); 209 | else 210 | sprintf(print + strlen(print), " %02x(%d)", hw_ide->data[i], hw_ide->data[i]); 211 | 212 | if (changed == i) 213 | sprintf(print + strlen(print), "]\n"); 214 | else 215 | sprintf(print + strlen(print), "\n"); 216 | 217 | } -------------------------------------------------------------------------------- /src/hw_tty.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // hw_tty.cpp 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #include "hw_tty.h" 19 | #include "z80.h" 20 | #include 21 | #include 22 | 23 | #ifdef _MSC_VER 24 | #include 25 | #include 26 | #else 27 | #include 28 | #endif 29 | 30 | #define SERVER_PORT 1234 31 | 32 | #ifdef _MSC_VER 33 | DWORD WINAPI TelnetClientThread(LPVOID pParam) 34 | #else 35 | void *TelnetClientThread(void *pParam) 36 | #endif 37 | { 38 | 39 | HW_TTY_CLIENT *current_client = (HW_TTY_CLIENT*)pParam; 40 | 41 | 42 | char welm[512]; 43 | unsigned char buff[512]; 44 | int n; 45 | int x = 0; 46 | 47 | unsigned char lastchar = 0; 48 | unsigned char startCMD = 0x00; 49 | #ifdef _MSC_VER 50 | 51 | SOCKET client = *(current_client)->client; 52 | #else 53 | int client = *(current_client)->client; 54 | #endif 55 | 56 | //https://datatracker.ietf.org/doc/html/rfc1116 57 | //https://tools.ietf.org/html/rfc854 58 | //https://datatracker.ietf.org/doc/html/rfc854#page-14 59 | //https://tools.ietf.org/html/rfc855 60 | //https://datatracker.ietf.org/doc/html/rfc858 61 | //https://datatracker.ietf.org/doc/rfc930/ 62 | //https://en.wikipedia.org/wiki/Telnet#Related_RFCs 63 | //http://www.iana.org/assignments/telnet-options/telnet-options.xhtml 64 | //ByteString(-1, -5, 31, -1, -5, 32, -1, -5, 24, -1, -5, 39, -1, -3, 1, -1, -5, 3, -1, -3, 3), 65 | //ByteString(-1, -2, 31, -1, -2, 32, -1, -2, 24, -1, -2, 39, -1, -4, 1), 66 | //ByteString(-1, -5, 36), 67 | //ByteString(-1, -2, 36) 68 | //-1 -5 31 = IAC WILL NAWS 69 | //-1 -5 32 = IAC WILL TERMINAL-SPEED 70 | //-1 -5 24 = IAC WILL TERMINAL-TYPE 71 | //-1 -5 39 = IAC WILL NEW-ENVIRON 72 | //-1 -3 1 = IAC DO ECHO 73 | //-1 -5 3 = IAC WILL SUPPRESS-GO-AHEAD 74 | //-1 -3 3 = IAC DO SUPPRESS-GO-AHEAD 75 | //-1 -2 31 = IAC DONT NAWS 76 | //-1 -2 32 = IAC DONT TERMINAL-SPEED 77 | //-1 -2 24 = IAC DONT TERMINAL-TYPE 78 | //-1 -2 39 = IAC DONT NEW-ENVIRON 79 | //-1 -4 1 = IAC WONT ECHO 80 | //-1 -5 36 = IAC WILL ENVIRON 81 | //-1 -2 36 = IAC DONT ENVIRON 82 | //FFFD22 FFFB01 83 | sprintf(welm, "\377\375\042\377\373\001\r\n"); 84 | sprintf(welm + strlen(welm), "\377\373\037\377\373\040\377\373\030\377\373\047\377\375\001\377\373\003\377\375\003\r\n"); 85 | sprintf(welm + strlen(welm), "\377\376\037\377\376\040\377\376\030\377\376\047\377\374\001\r\n"); 86 | sprintf(welm + strlen(welm), "\377\373\044\r\n"); 87 | sprintf(welm + strlen(welm), "\377\376\044\r\n"); 88 | sprintf(welm + strlen(welm), "\377\375\042\377\373\001\r\n"); 89 | send(client, welm, (int)strlen(welm), 0); 90 | 91 | 92 | sprintf(welm, "Z80 CPM Emulator\r\n"); 93 | sprintf(welm + strlen(welm), "Version 0.01\r\n"); 94 | sprintf(welm + strlen(welm), "\r\n"); 95 | sprintf(welm + strlen(welm), "terminal-%d initialized\r\n", (current_client->index + 1)); 96 | send(client, welm, (int)strlen(welm), 0); 97 | 98 | //hw_uart_receive(current_client->hw_uart, 0x0d); 99 | //memset(welm, 0, 512 * (sizeof buff[0])); 100 | 101 | char lastSentChar = '\0'; 102 | 103 | while (true) 104 | { 105 | //sprintf("%02x -> %04x\n", current_client->index, current_client->client); 106 | 107 | 108 | 109 | if (!current_client->tty_out.empty()) { 110 | 111 | 112 | #ifdef _MSC_VER 113 | std::unique_lock lock(current_client->mtx_out); 114 | #else 115 | pthread_mutex_lock(¤t_client->mtx_out); 116 | #endif 117 | 118 | unsigned char data = current_client->tty_out.front(); current_client->tty_out.pop(); 119 | 120 | #ifdef _MSC_VER 121 | current_client->cv_out.notify_all(); 122 | #else 123 | pthread_mutex_unlock(¤t_client->mtx_out); 124 | #endif 125 | 126 | char buf_send[4]; 127 | buf_send[0] = data; 128 | buf_send[1] = '\0'; 129 | buf_send[2] = '\0'; 130 | buf_send[3] = '\0'; 131 | 132 | if (buf_send[0] == 0x08) { //CONVERT BS TO DEL 133 | buf_send[1] = 0x20; 134 | buf_send[2] = 0x08; 135 | } 136 | 137 | if (lastSentChar == '\r' && data != '\n') 138 | send(client, "\n", 1, 0); 139 | 140 | send(client, buf_send, (int)strlen(buf_send), 0); 141 | 142 | if (lastSentChar == '\n' && data != '\n') 143 | lastSentChar = '\0'; 144 | else 145 | lastSentChar = data; 146 | 147 | } 148 | //std::unique_lock unlock(current_client->mtx_out); 149 | 150 | 151 | 152 | 153 | if (x == 0) 154 | n = recv(client, (char *)buff, 1, 0);// MSG_WAITALL); 155 | 156 | 157 | 158 | if (n > 0) { 159 | //if (RecvBytes > 0) { 160 | 161 | if (x < n) { 162 | 163 | if (buff[x] == 0xFF) { 164 | startCMD = 0x01; 165 | lastchar = buff[x]; 166 | } 167 | else if (startCMD == 0x01 && buff[x] == 0xFA) { 168 | startCMD = 0x02; 169 | lastchar = buff[x]; 170 | } 171 | else if (startCMD == 0x02 && buff[x] == 0xF0) { 172 | startCMD = 0x00; 173 | lastchar = buff[x]; 174 | } 175 | else if (startCMD == 0x01 && lastchar == 0xFF) { 176 | lastchar = buff[x]; 177 | } 178 | else if (startCMD == 0x01) { 179 | startCMD = 0x00; 180 | lastchar = buff[x]; 181 | } 182 | else if (startCMD == 0x00 && buff[x] != 0x00 && buff[x] != 0x0a) { 183 | if (buff[x] == 0x7F) //CONVERT DEL TO BS 184 | buff[x] = 0x08; 185 | 186 | if (*(((HW_TTY_CLIENT*)pParam)->console) == 0) { 187 | if (buff[x] == 0x04) 188 | { 189 | *(((HW_TTY_CLIENT*)pParam)->debug_call) = 1; 190 | } 191 | else { 192 | 193 | current_client->keyboard_queue->push(buff[x]); 194 | //current_client->sol1_cpu.microcode.mccycle.int_request = 0x01; 195 | } 196 | } 197 | else if (*(((HW_TTY_CLIENT*)pParam)->console) == 1) { 198 | HW_TTY::net_data *net_data = (HW_TTY::net_data*)malloc(sizeof(HW_TTY::net_data)); 199 | current_client->tty_in->push(buff[x]); 200 | } 201 | } 202 | x++; 203 | } 204 | else { 205 | n = 0; 206 | x = 0; 207 | memset(buff, 0, 512 * (sizeof buff[0])); 208 | } 209 | 210 | } 211 | else if (n == 0) 212 | break; 213 | 214 | } 215 | 216 | #ifdef _MSC_VER 217 | closesocket(client); 218 | #else 219 | shutdown(client, 2); 220 | #endif 221 | current_client->running = 0; 222 | current_client->client = NULL; 223 | return 0; 224 | 225 | } 226 | 227 | 228 | 229 | #ifdef _MSC_VER 230 | DWORD WINAPI TelnetServerThread(LPVOID pParam) 231 | #else 232 | void *TelnetServerThread(void *pParam) 233 | #endif 234 | { 235 | 236 | HW_TTY_CLIENT* clients = (HW_TTY_CLIENT*)pParam; 237 | 238 | sockaddr_in local; 239 | #ifdef _MSC_VER 240 | SOCKET server; 241 | WSADATA wsaData; 242 | int wsaret = WSAStartup(MAKEWORD(2, 2), &wsaData); 243 | if (wsaret != 0) 244 | { 245 | return 0; 246 | } 247 | #else 248 | int server; 249 | #endif 250 | local.sin_family = AF_INET; 251 | local.sin_addr.s_addr = INADDR_ANY; 252 | local.sin_port = htons((u_short)SERVER_PORT); 253 | #ifdef _MSC_VER 254 | server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 255 | if (server == INVALID_SOCKET) 256 | { 257 | return 0; 258 | } 259 | #else 260 | if ((server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 261 | { 262 | return 0; 263 | } 264 | #endif 265 | if (::bind(server, (sockaddr*)&local, sizeof(local)) != 0) 266 | { 267 | return 0; 268 | } 269 | if (listen(server, 10) != 0) 270 | { 271 | return 0; 272 | } 273 | 274 | sockaddr_in from; 275 | #ifdef _MSC_VER 276 | SOCKET client; 277 | int fromlen = sizeof(from); 278 | #else 279 | int client; 280 | socklen_t fromlen = sizeof(from); 281 | #endif 282 | 283 | while (true) 284 | { 285 | client = accept(server, 286 | (struct sockaddr*)&from, &fromlen); 287 | 288 | #ifdef _MSC_VER 289 | u_long mode = 1; // 1 to enable non-blocking socket 290 | ioctlsocket(client, FIONBIO, &mode); 291 | #else 292 | fcntl(client, F_SETFL, O_NONBLOCK); 293 | #endif 294 | 295 | HW_TTY_CLIENT *new_client = NULL; 296 | int i = 0; 297 | for (i = 0; i < 10; i++) { 298 | if (clients[i].running == 0) { 299 | 300 | clients[i].client = &client; 301 | clients[i].running = 1; 302 | new_client = &clients[i]; 303 | break; 304 | } 305 | } 306 | if (new_client != NULL) { 307 | 308 | 309 | #ifdef _MSC_VER 310 | DWORD tid = 100 + new_client->index; 311 | HANDLE myHandle = CreateThread(0, 0, TelnetClientThread, new_client, 0, &tid); 312 | #else 313 | pthread_t tid = 100 + new_client->index; 314 | pthread_create(&tid, NULL, TelnetClientThread, (void *)new_client); 315 | #endif 316 | 317 | 318 | } 319 | else { 320 | 321 | char *buf_send = (char *)"No pool available.\n"; 322 | send(client, buf_send, (int)strlen(buf_send), 0); 323 | #ifdef _MSC_VER 324 | closesocket(client); 325 | #else 326 | shutdown(client, 2); 327 | #endif 328 | 329 | } 330 | } 331 | 332 | return 0; 333 | } 334 | 335 | 336 | 337 | void HW_TTY::start_server(queue *keyboard_queue) { 338 | 339 | 340 | int i; 341 | //this->tty_in = queue_create(); 342 | 343 | for (i = 0; i < 10; i++) { 344 | this->clients[i].client = NULL; 345 | this->clients[i].index = i; 346 | this->clients[i].running = 0; 347 | //this->clients[i].sol1_cpu = sol1_cpu; 348 | this->clients[i].keyboard_queue = keyboard_queue; 349 | //this->clients[i].tty_out = queue_create(); 350 | //this->clients[i].mtx = &this->mtx; 351 | this->clients[i].tty_in = &this->tty_in;//queue_create(); 352 | this->clients[i].console = &this->console; 353 | this->clients[i].debug_call = &this->debug_call; 354 | } 355 | 356 | #ifdef _MSC_VER 357 | DWORD tid; 358 | HANDLE myHandle = CreateThread(0, 0, TelnetServerThread, &this->clients, 0, &tid); 359 | #else 360 | pthread_t tid; 361 | pthread_create(&tid, NULL, TelnetServerThread, (void*)&this->clients); 362 | #endif 363 | 364 | this->started = 1; 365 | } 366 | 367 | 368 | 369 | void HW_TTY::send(unsigned char b) { 370 | 371 | if (this->started == 1) { 372 | int i; 373 | for (i = 0; i < 10; i++) { 374 | if (this->clients[i].running == 1) { // SEND TELNET 375 | unsigned char data = b; 376 | #ifdef _MSC_VER 377 | std::unique_lock lock(this->clients[i].mtx_out); 378 | #else 379 | pthread_mutex_lock(&this->clients[i].mtx_out); 380 | #endif 381 | this->clients[i].tty_out.push(data); 382 | 383 | #ifdef _MSC_VER 384 | this->clients[i].cv_out.notify_all(); 385 | #else 386 | pthread_mutex_unlock(&this->clients[i].mtx_out); 387 | #endif 388 | } 389 | } 390 | } 391 | } 392 | 393 | void HW_TTY::print(const char* s) { 394 | 395 | if (this->started == 1) { 396 | int i = 0; 397 | while (s[i] != '\0') { 398 | if (s[i] == '\n') { 399 | send('\r'); 400 | send(s[i]); 401 | } 402 | else 403 | send(s[i]); 404 | i++; 405 | } 406 | } 407 | printf("%s", s); 408 | } 409 | 410 | 411 | 412 | 413 | 414 | void HW_TTY::set_input(unsigned char b) { 415 | 416 | /* 417 | if (this->started == 1) { 418 | int i; 419 | for (i = 0; i < 10; i++) { 420 | if (clients[i].running == 1) { // SEND TELNET 421 | clients[i].console = b; 422 | } 423 | } 424 | } 425 | */ 426 | this->console = b; 427 | } 428 | 429 | char* HW_TTY::gets(int max_value) { 430 | 431 | char str_out[255]; 432 | char *input = (char*)malloc(sizeof(char) * 257); 433 | 434 | int i = 0; 435 | for (i = 0; i < 256 && i < max_value; ) { 436 | char cur_input = get_char(); 437 | if (cur_input == (char)8) { 438 | if (i > 0) { 439 | sprintf(str_out, "%c", cur_input); 440 | sprintf(str_out, " "); 441 | sprintf(str_out, "%c", cur_input); 442 | print(str_out); 443 | i--; 444 | } 445 | } 446 | else if (cur_input != '\n' && cur_input != '\r') { 447 | cur_input = toupper(cur_input); 448 | sprintf(str_out, "%c", cur_input); 449 | print(str_out); 450 | input[i] = cur_input; 451 | i++; 452 | } 453 | else { 454 | print("\r\n"); 455 | break; 456 | } 457 | } 458 | input[i] = '\0'; 459 | 460 | return input; 461 | } 462 | 463 | char* HW_TTY::getline() { 464 | char str_out[255]; 465 | char *input = (char*)malloc(sizeof(char) * 257); 466 | 467 | int i = 0; 468 | for (i = 0; i < 256; ) { 469 | char cur_input = get_char(); 470 | if (cur_input == (char)8) { 471 | if (i > 0) { 472 | sprintf(str_out, "%c", cur_input); 473 | sprintf(str_out, " "); 474 | sprintf(str_out, "%c", cur_input); 475 | print(str_out); 476 | i--; 477 | } 478 | } 479 | else if (cur_input != '\n' && cur_input != '\r') { 480 | cur_input = toupper(cur_input); 481 | sprintf(str_out, "%c", cur_input); 482 | print(str_out); 483 | input[i] = cur_input; 484 | i++; 485 | } 486 | else { 487 | print("\r\n"); 488 | break; 489 | } 490 | } 491 | input[i] = '\0'; 492 | 493 | return input; 494 | } 495 | 496 | 497 | unsigned char HW_TTY::receive() { 498 | 499 | unsigned char ch = 0x00; 500 | set_input(1); 501 | while (1) { 502 | if (kbhit()) { 503 | ch = getch(); 504 | break; 505 | } 506 | else if (!this->tty_in.empty()) { 507 | 508 | unsigned char data = this->tty_in.front(); this->tty_in.pop(); 509 | ch = data; 510 | break; 511 | } 512 | 513 | #ifdef _MSC_VER 514 | Sleep(10); 515 | #else 516 | int milliseconds = 10; 517 | struct timespec ts; 518 | ts.tv_sec = milliseconds / 1000; 519 | ts.tv_nsec = (milliseconds % 1000) * 1000000; 520 | nanosleep(&ts, NULL); 521 | 522 | #endif 523 | } 524 | set_input(0); 525 | 526 | return ch; 527 | } 528 | 529 | 530 | char HW_TTY::get_char() { 531 | 532 | char cur_input = receive(); 533 | return cur_input; 534 | } -------------------------------------------------------------------------------- /src/hw_web.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // hw_web.cpp 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #include "hw_web.h" 19 | #include 20 | #include 21 | 22 | #ifdef _MSC_VER 23 | #include 24 | #else 25 | #include 26 | #include 27 | #include 28 | #endif 29 | 30 | #include 31 | using std::cout; 32 | #include 33 | using std::ifstream; 34 | using std::getline; 35 | using std::string; 36 | 37 | 38 | 39 | 40 | size_t count_lines(const char *filename) 41 | { 42 | ifstream myfile(filename); 43 | string line; 44 | size_t count = 0; 45 | while (getline(myfile, line)) 46 | { 47 | ++count; 48 | } 49 | return count; 50 | } 51 | 52 | void clearfile() { 53 | ofstream fout; 54 | fout.open("html.cache");// , ios::app); 55 | 56 | fout.flush(); 57 | fout.close(); 58 | } 59 | 60 | int line(string newline, int append) 61 | { 62 | string newfile = ""; 63 | 64 | if (append == 0) { 65 | const char filename[] = "html.cache"; 66 | int i, count = (int)count_lines(filename); 67 | ifstream myfile(filename); 68 | if (!myfile.fail()) { 69 | string line; 70 | 71 | for (i = 0; i < count - 80; ++i) 72 | { 73 | getline(myfile, line); /* read and discard: skip line */ 74 | } 75 | while (getline(myfile, line)) 76 | { 77 | newfile = newfile + line; 78 | } 79 | 80 | myfile.close(); 81 | } 82 | } 83 | 84 | ofstream fout; 85 | if (append == 0) 86 | fout.open("html.cache");// , ios::app); 87 | else 88 | fout.open("html.cache", ios::app); 89 | 90 | if (append == 0) 91 | fout << newfile; 92 | fout << newline; 93 | 94 | //cout << "file saved" << endl; 95 | 96 | fout.flush(); 97 | fout.close(); 98 | 99 | return 0; 100 | } 101 | 102 | 103 | void HW_WEB::new_char(char c) { 104 | 105 | 106 | if (c == 0x0d) { 107 | this->currentline = c; 108 | line(this->currentline, 0); 109 | this->currentline = ""; 110 | } 111 | else if (c != 0x0a) { 112 | this->currentline = c; 113 | line(this->currentline, 1); 114 | this->currentline = ""; 115 | } 116 | 117 | //this->currentline = this->currentline + (char)c; 118 | } 119 | 120 | 121 | 122 | 123 | #ifdef _MSC_VER 124 | DWORD WINAPI WebClientThread(LPVOID pParam) 125 | #else 126 | void *WebClientThread(void *pParam) 127 | #endif 128 | { 129 | 130 | struct hw_web_client new_web_client = *(struct hw_web_client*)pParam; 131 | 132 | 133 | 134 | char buff[512]; 135 | int n; 136 | int x = 0; 137 | 138 | char lastchar = 0; 139 | char startCMD = 0x00; 140 | 141 | #ifdef _MSC_VER 142 | SOCKET client = *(new_web_client.client); 143 | #else 144 | int client = *(new_web_client.client); 145 | #endif 146 | 147 | while (true) 148 | { 149 | //sprintf("%02x -> %04x\n", new_computer_client->index, new_computer_client->client); 150 | 151 | n = recv(client, (char *)buff, 512, 0);// MSG_WAITALL); 152 | 153 | if (n > 0) { 154 | //if (RecvBytes > 0) { 155 | int i; 156 | 157 | string cmd = ""; 158 | for (i = 0; i < n; i++) 159 | { 160 | cmd = cmd + (char)buff[i]; 161 | /* 162 | if (buff[i] == 0x0d) { 163 | hw_uart_receive(new_web_client.hw_uart, buff[x]); 164 | break; 165 | } 166 | */ 167 | } 168 | 169 | if (cmd.find("cpu_command=") != std::string::npos) 170 | { 171 | string str3 = cmd.substr(12 + cmd.find("cpu_command="), cmd.length() - cmd.find("cpu_command=")); 172 | int lll = (int)str3.length(); 173 | if (lll > 0) { 174 | if (str3 == "tel") { 175 | int in = new_web_client.index; 176 | 177 | string rs = "terminal: " + to_string(in) + "\r\n"; 178 | line(rs, 1); 179 | cout << rs; 180 | 181 | } 182 | else if (str3 == "cls") { 183 | int in = new_web_client.index; 184 | 185 | clearfile(); 186 | string rs = "*** clearing screen\r\n"; 187 | line(rs, 0); 188 | 189 | } 190 | else { 191 | const char *ccc = str3.c_str(); 192 | 193 | for (i = 0; i < lll; i++) { 194 | new_web_client.tty_in->push(ccc[i]); 195 | //new_web_client.hw_uart->receive(ccc[i]); 196 | } 197 | new_web_client.tty_in->push('\r'); 198 | //new_web_client.hw_uart->receive('\r'); 199 | } 200 | } 201 | 202 | 203 | } 204 | 205 | 206 | n = 0; 207 | x = 0; 208 | memset(buff, 0, 512 * (sizeof buff[0])); 209 | 210 | string cur_response = ""; 211 | ifstream myfile("html.cache"); 212 | if (!myfile.fail()) { 213 | string line; 214 | while (getline(myfile, line)) 215 | { 216 | cur_response = cur_response + line; 217 | } 218 | 219 | myfile.close(); 220 | } 221 | cur_response = cur_response; 222 | 223 | string curline = ""; 224 | curline = "HTTP/1.1 200 OK"; 225 | send(client, curline.c_str(), (int)curline.length(), 0); 226 | 227 | curline = "Content-Type: text/html\r\n"; 228 | send(client, curline.c_str(), (int)curline.length(), 0); 229 | 230 | curline = "Content-Length: " + to_string(cur_response.length()) + "\r\n"; 231 | send(client, curline.c_str(), (int)curline.length(), 0); 232 | 233 | curline = "Connection: close\r\n\r\n"; 234 | send(client, curline.c_str(), (int)curline.length(), 0); 235 | 236 | 237 | send(client, cur_response.c_str(), (int)cur_response.length(), 0); 238 | //Content - Length: 12\r\n 239 | 240 | #ifdef _MSC_VER 241 | Sleep(1000); 242 | #else 243 | int milliseconds = 1000; 244 | struct timespec ts; 245 | ts.tv_sec = milliseconds / 1000; 246 | ts.tv_nsec = (milliseconds % 1000) * 1000000; 247 | nanosleep(&ts, NULL); 248 | 249 | #endif 250 | break; 251 | } 252 | else if (n == 0) 253 | break; 254 | 255 | } 256 | 257 | #ifdef _MSC_VER 258 | closesocket(client); 259 | #else 260 | shutdown(client, 2); 261 | close(client); 262 | #endif 263 | ((struct hw_web_client*)pParam)->running = 0; 264 | ((struct hw_web_client*)pParam)->client = NULL; 265 | return 0; 266 | 267 | } 268 | 269 | 270 | #ifdef _MSC_VER 271 | DWORD WINAPI WebServerThread(LPVOID pParam) 272 | #else 273 | void *WebServerThread(void *pParam) 274 | #endif 275 | { 276 | 277 | struct hw_web_client* clients = (struct hw_web_client*)pParam; 278 | sockaddr_in local; 279 | #ifdef _MSC_VER 280 | SOCKET server; 281 | WSADATA wsaData; 282 | int wsaret = WSAStartup(MAKEWORD(2, 2), &wsaData); 283 | if (wsaret != 0) 284 | { 285 | return 0; 286 | } 287 | #else 288 | int server; 289 | memset(&local, 0, sizeof(local)); 290 | #endif 291 | local.sin_family = AF_INET; 292 | local.sin_addr.s_addr = INADDR_ANY; 293 | local.sin_port = htons((u_short)20281); 294 | 295 | #ifdef _MSC_VER 296 | server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 297 | if (server == INVALID_SOCKET) 298 | { 299 | return 0; 300 | } 301 | #else 302 | if ((server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 303 | { 304 | return 0; 305 | } 306 | #endif 307 | if (::bind(server, (sockaddr*)&local, sizeof(local)) != 0) 308 | { 309 | return 0; 310 | } 311 | if (listen(server, 10) != 0) 312 | { 313 | return 0; 314 | } 315 | 316 | 317 | sockaddr_in from; 318 | #ifdef _MSC_VER 319 | SOCKET client; 320 | int fromlen = sizeof(from); 321 | #else 322 | int client; 323 | socklen_t fromlen = sizeof(from); 324 | #endif 325 | 326 | 327 | while (true) 328 | { 329 | client = accept(server, 330 | (struct sockaddr*)&from, &fromlen); 331 | 332 | //u_long mode = 1; // 1 to enable non-blocking socket 333 | //ioctlsocket(client, FIONBIO, &mode); 334 | 335 | 336 | struct hw_web_client *new_web_client = NULL; 337 | int i = 0; 338 | for (i = 0; i < 10; i++) { 339 | if (clients[i].running == 0) { 340 | 341 | clients[i].client = &client; 342 | clients[i].running = 1; 343 | new_web_client = &clients[i]; 344 | break; 345 | } 346 | } 347 | if (new_web_client != NULL) { 348 | #ifdef _MSC_VER 349 | DWORD tid = 100 + new_web_client->index; 350 | HANDLE myHandle = CreateThread(0, 0, WebClientThread, new_web_client, 0, &tid); 351 | #else 352 | pthread_t tid = 100 + new_web_client->index; 353 | pthread_create(&tid, NULL, WebClientThread, (void *)new_web_client); 354 | #endif 355 | } 356 | else { 357 | 358 | char *buf_send = (char*)"No pool available.\n"; 359 | send(client, buf_send, (int)strlen(buf_send), 0); 360 | #ifdef _MSC_VER 361 | closesocket(client); 362 | #else 363 | shutdown(client, 2); 364 | #endif 365 | 366 | } 367 | } 368 | return 0; 369 | } 370 | 371 | 372 | 373 | void HW_WEB::start_server(queue* tty_in) { 374 | 375 | int i; 376 | 377 | for (i = 0; i < 10; i++) { 378 | this->clients[i].client = NULL; 379 | this->clients[i].index = i; 380 | this->clients[i].running = 0; 381 | //this->clients[i].sol1_cpu = sol1_cpu; 382 | this->clients[i].tty_in = tty_in; 383 | this->clients[i].web_out = queue_create(); 384 | } 385 | 386 | #ifdef _MSC_VER 387 | DWORD tid; 388 | HANDLE myHandle = CreateThread(0, 0, WebServerThread, &this->clients, 0, &tid); 389 | #else 390 | // Ignore SIGCHLD to avoid zombie threads 391 | signal(SIGCHLD, SIG_IGN); 392 | 393 | pthread_t tid; 394 | pthread_create(&tid, NULL, WebServerThread, (void*)&this->clients); 395 | #endif 396 | 397 | remove("html.cache"); 398 | } 399 | 400 | -------------------------------------------------------------------------------- /src/linkedlist.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // linked_list.cpp 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #include 19 | #include 20 | #include "linkedlist.h" 21 | 22 | Linked_List* ll_create(void) 23 | { 24 | return NULL; 25 | } 26 | 27 | 28 | Linked_List* ll_insert (Linked_List* ll, void* info) 29 | { 30 | Linked_List* _new = (Linked_List*) malloc(sizeof(Linked_List)); 31 | _new->info = info; 32 | _new->next = ll; 33 | return _new; 34 | } 35 | 36 | 37 | Linked_List* ll_insert_sorted (Linked_List* ll, void* info, int(*cmp)(void *, void *)) 38 | { 39 | Linked_List* _new; 40 | Linked_List* a = NULL; 41 | Linked_List* p = ll; 42 | 43 | while (p != NULL && cmp(p->info, info) < 0){ 44 | a = p; 45 | p = p->next; 46 | } 47 | 48 | 49 | _new = (Linked_List*) malloc(sizeof(Linked_List)); 50 | _new->info = info; 51 | if (a == NULL){ 52 | _new->next = ll; 53 | ll = _new; 54 | } else { 55 | _new->next = a->next; 56 | a->next = _new; 57 | } 58 | return ll; 59 | } 60 | 61 | 62 | Linked_List* ll_remove_first(Linked_List* ll) 63 | { 64 | Linked_List* p = ll; 65 | 66 | ll = p->next; 67 | free(p); 68 | return ll; 69 | } 70 | 71 | Linked_List* ll_remove(Linked_List* ll, void* info, int(*cmp)(void *, void *)) 72 | { 73 | Linked_List* a = NULL; 74 | Linked_List* p = ll; 75 | 76 | while (p != NULL && cmp(p->info, info) != 0) { 77 | a = p; 78 | p = p->next; 79 | } 80 | 81 | if (p == NULL) 82 | return ll; 83 | 84 | if (a == NULL) 85 | ll = p->next; 86 | else 87 | a->next = p->next; 88 | free(p); 89 | return ll; 90 | } 91 | 92 | 93 | void ll_print(Linked_List* ll, void(*print)(void *)) 94 | { 95 | Linked_List* p; 96 | for (p = ll; p != NULL; p = p->next){ 97 | print(p->info); 98 | //sprintf("----------\n"); 99 | } 100 | } 101 | 102 | 103 | Linked_List* ll_find(Linked_List* ll, void* info, int(*cmp)(void *, void *)) 104 | { 105 | Linked_List* p; 106 | for (p = ll; p != NULL; p = p-> next) 107 | { 108 | if (cmp(p->info, info) == 0) 109 | return p; 110 | } 111 | return NULL; 112 | } 113 | 114 | 115 | 116 | int ll_equal(Linked_List* ll1, Linked_List* ll2, int(*cmp)(void *, void *)) { 117 | Linked_List* p1; 118 | Linked_List* p2; 119 | for (p1=ll1, p2=ll2; p1 != NULL && p2 != NULL; 120 | p1 = p1->next, p2 = p2->next) { 121 | if (cmp(p1->info, p2->info) != 0) 122 | return 0; 123 | } 124 | if (p1 == p2) 125 | return 1; 126 | else 127 | return 0; 128 | } 129 | 130 | 131 | int ll_empty(Linked_List* ll) 132 | { 133 | if (ll == NULL) 134 | return 1; 135 | else 136 | return 0; 137 | } 138 | 139 | 140 | 141 | void ll_free(Linked_List* ll, void(*ffree)(void *)) 142 | { 143 | Linked_List* p = ll; 144 | Linked_List* t; 145 | while (p != NULL) 146 | { 147 | t = p->next; 148 | ffree(p->info); 149 | free(p); 150 | p = t; 151 | } 152 | } 153 | 154 | 155 | int ll_size(Linked_List* ll) 156 | { 157 | Linked_List* p = ll; 158 | int count = 0; 159 | while (p != NULL) 160 | { 161 | p = p->next; 162 | count++; 163 | } 164 | return count; 165 | } -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "z80.h" 2 | #include "z80cpm_keyboard.h" 3 | #include "z80cpm_memory.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef _MSC_VER 10 | #include 11 | #include 12 | #endif 13 | 14 | 15 | #ifdef __MINGW32__ 16 | #include 17 | #endif 18 | 19 | #if defined(__linux__) || defined(__MINGW32__) 20 | #include 21 | #include 22 | #else 23 | #include 24 | #endif 25 | 26 | #if defined(__linux__) || defined(__MINGW32__) 27 | #include 28 | #else 29 | #include 30 | using namespace std::chrono; 31 | 32 | #endif 33 | 34 | const unsigned int keyboard_map[Z80CPM_TOTAL_KEYS] = { 35 | (int)'1', (int)'2', (int)'3', (int)'4', (int)'5', (int)'6', (int)'7', (int)'8', (int)'9', (int)'0', 36 | (int)'q', (int)'w', (int)'e', (int)'r', (int)'t', (int)'y', (int)'u', (int)'i', (int)'o', (int)'p', 37 | (int)'a', (int)'s', (int)'d', (int)'f', (int)'g', (int)'h', (int)'j', (int)'k', (int)'l', (int)'\n', 38 | (int)'T', (int)'z', (int)'x', (int)'c', (int)'v', (int)'b', (int)'n', (int)'m', (int)'.', (int)' ', 39 | (int)'E' 40 | }; 41 | 42 | typedef enum zx_keyboard { 43 | zxkey_n1, zxkey_n2, zxkey_n3, zxkey_n4, zxkey_n5, zxkey_n6, zxkey_n7, zxkey_n8, zxkey_n9, zxkey_n0, 44 | zxkey_q, zxkey_w, zxkey_e, zxkey_r, zxkey_t, zxkey_y, zxkey_u, zxkey_i, zxkey_o, zxkey_p, 45 | zxkey_a, zxkey_s, zxkey_d, zxkey_f, zxkey_g, zxkey_h, zxkey_j, zxkey_k, zxkey_l, zxkey_ret, 46 | zxkey_shift, zxkey_z, zxkey_x, zxkey_c, zxkey_v, zxkey_b, zxkey_n, zxkey_m, zxkey_period, zxkey_space, 47 | zxkey_backspace 48 | } ZX_Keyboard; 49 | 50 | 51 | int show_debug = 0; 52 | char state = 0; 53 | unsigned short mem_offset = 0x4000; 54 | int mem_follow = 0; 55 | 56 | #ifdef _MSC_VER 57 | mutex mtx_out; 58 | condition_variable cv_out; 59 | 60 | #else 61 | pthread_mutex_t mtx_out; 62 | #endif 63 | 64 | #ifdef _MSC_VER 65 | void cls(HANDLE hConsole) 66 | { 67 | COORD coordScreen = { 0, 0 }; // home for the cursor 68 | DWORD cCharsWritten; 69 | CONSOLE_SCREEN_BUFFER_INFO csbi; 70 | DWORD dwConSize; 71 | 72 | // Get the number of character cells in the current buffer. 73 | if (!GetConsoleScreenBufferInfo(hConsole, &csbi)) 74 | { 75 | return; 76 | } 77 | 78 | dwConSize = csbi.dwSize.X * csbi.dwSize.Y; 79 | 80 | // Fill the entire screen with blanks. 81 | if (!FillConsoleOutputCharacter(hConsole, // Handle to console screen buffer 82 | (TCHAR)' ', // Character to write to the buffer 83 | dwConSize, // Number of cells to write 84 | coordScreen, // Coordinates of first cell 85 | &cCharsWritten)) // Receive number of characters written 86 | { 87 | return; 88 | } 89 | 90 | // Get the current text attribute. 91 | if (!GetConsoleScreenBufferInfo(hConsole, &csbi)) 92 | { 93 | return; 94 | } 95 | 96 | // Set the buffer's attributes accordingly. 97 | if (!FillConsoleOutputAttribute(hConsole, // Handle to console screen buffer 98 | csbi.wAttributes, // Character attributes to use 99 | dwConSize, // Number of cells to set attribute 100 | coordScreen, // Coordinates of first cell 101 | &cCharsWritten)) // Receive number of characters written 102 | { 103 | return; 104 | } 105 | 106 | // Put the cursor at its home coordinates. 107 | SetConsoleCursorPosition(hConsole, coordScreen); 108 | } 109 | 110 | #endif 111 | 112 | #define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" 113 | #define BYTE_TO_BINARY(byte) \ 114 | (byte & 0x80 ? '1' : '0'), \ 115 | (byte & 0x40 ? '1' : '0'), \ 116 | (byte & 0x20 ? '1' : '0'), \ 117 | (byte & 0x10 ? '1' : '0'), \ 118 | (byte & 0x08 ? '1' : '0'), \ 119 | (byte & 0x04 ? '1' : '0'), \ 120 | (byte & 0x02 ? '1' : '0'), \ 121 | (byte & 0x01 ? '1' : '0') 122 | 123 | 124 | void cpu_exec(Z80& z80, struct z80cpm_memory* z80cpm_memory) { 125 | z80.z80_exec(z80cpm_memory); 126 | } 127 | 128 | #define LSB(w) ((w) & 0xff) 129 | #define MSB(w) (((w) >> 8) & 0xff) 130 | #define WORD(l, h) (((h)<<8) | (l)) 131 | void cpu_print(Z80& z80, struct z80cpm_memory* z80cpm_memory) { 132 | 133 | printf("\t ""%c%c%c%c%c%c%c%c""\n", BYTE_TO_BINARY(MSB(z80.registers.AF))); 134 | 135 | printf(" AF | BC | DE | HL || S | Z | H | P | V | N | C |\n"); 136 | printf(" %04x |", z80.registers.AF); 137 | printf(" %04x |", z80.registers.BC); 138 | printf(" %04x |", z80.registers.DE); 139 | printf(" %04x ||", z80.registers.HL); 140 | printf(" %01x |", (z80.registers.AF & S_FLAG) >> 7); 141 | printf(" %01x |", (z80.registers.AF & Z_FLAG) >> 6); 142 | printf(" %01x |", (z80.registers.AF & H_FLAG) >> 4); 143 | printf(" %01x |", (z80.registers.AF & P_FLAG) >> 2); 144 | printf(" %01x |", (z80.registers.AF & V_FLAG) >> 2); 145 | printf(" %01x |", (z80.registers.AF & N_FLAG) >> 1); 146 | printf(" %01x |", (z80.registers.AF & C_FLAG)); 147 | printf("FLAGS ""%c%c%c%c%c%c%c%c", BYTE_TO_BINARY(LSB(z80.registers.AF))); 148 | printf("\n\n"); 149 | 150 | printf(" AF' | BC' | DE' | HL' || PC | SP || IX | IY || I | R |\n"); 151 | printf(" %04x |", z80.registers.AFl); 152 | printf(" %04x |", z80.registers.BCl); 153 | printf(" %04x |", z80.registers.DEl); 154 | printf(" %04x ||", z80.registers.HLl); 155 | printf(" %04x |", z80.registers.PC); 156 | printf(" %04x ||", z80.registers.SP); 157 | printf(" %04x |", z80.registers.IX); 158 | printf(" %04x ||", z80.registers.IY); 159 | printf(" %02x |", z80.registers.I); 160 | printf(" %02x |", z80.registers.R); 161 | printf("\n\n"); 162 | printf("IFF ""%c%c%c%c%c%c%c%c", BYTE_TO_BINARY(z80.registers.IFF)); 163 | printf("\n\n"); 164 | 165 | if (mem_follow) 166 | mem_offset = (z80.registers.PC / 0x10) * 0x10; 167 | 168 | int i = 0; 169 | printf("offset: %04x\n", mem_offset); 170 | printf(" "); 171 | for (i = 0; i < 16; i++) 172 | printf("%02x ", i); 173 | printf("\n\n %04x ", mem_offset); 174 | 175 | for (i = 0 + mem_offset; i < 256 + mem_offset; i++) { 176 | if (i % 16 == 0) 177 | if (z80.registers.PC == i) 178 | printf(" #"); 179 | else 180 | printf(" "); 181 | if (z80.registers.PC == i || z80.registers.PC - 1 == i) 182 | printf("%02x#", z80.RdZ80(z80cpm_memory, i)); 183 | else 184 | printf("%02x ", z80.RdZ80(z80cpm_memory, i)); 185 | 186 | if ((i + 1) % 16 == 0 && i < 255 + mem_offset) 187 | printf("\n %04x ", i + 1); 188 | } 189 | printf("\n\n"); 190 | printf("Stack:"); 191 | for (i = 0; i < 16; i += 2) { 192 | if (i % 2 == 0) printf(" "); 193 | printf("%02x", z80.RdZ80(z80cpm_memory, z80.registers.SP + i + 1)); 194 | printf("%02x", z80.RdZ80(z80cpm_memory, z80.registers.SP + i)); 195 | } 196 | 197 | printf("\n\n"); 198 | 199 | } 200 | 201 | 202 | 203 | 204 | 205 | int do_steps = 0; 206 | #if _MSC_VER 207 | DWORD WINAPI run_thread(LPVOID vargp) 208 | #else 209 | void *run_thread(void *vargp) 210 | #endif 211 | { 212 | 213 | Z80& z80 = *reinterpret_cast(vargp); 214 | struct z80cpm_memory *z80cpm_memory = z80.z80cpm_memory; 215 | queue *keyboard_queue = &z80.keyboard_queue; 216 | 217 | #ifdef _MSC_VER 218 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 219 | cls(hConsole); 220 | #endif 221 | 222 | int oldc = 0; 223 | int oldd = 1; 224 | 225 | double deltaTime = 0; 226 | double frame = 0; 227 | double ide = 0; 228 | double keyboard = 0; 229 | double cpu_clk = 0; 230 | double cpu = 0; 231 | 232 | if (show_debug) { 233 | printf("0.0fMHz - 0\n"); 234 | printf("Opcode: \n\n\n"); 235 | cpu_print(z80, z80cpm_memory); 236 | } 237 | int iii = 0; 238 | double speed = 3.0769230769231E-20; 239 | //1.25E-7 240 | //3.0769230769231E-7; 241 | 242 | do_steps = 0; 243 | int step = 0; 244 | 245 | int wait = 0; 246 | 247 | int do_breakpoint = 0; 248 | unsigned char bp_opcode = 0xed; 249 | unsigned char bp_opcode2 = 0x78; 250 | unsigned short breakpoint = 0x65B; //0x194; //0x168; //0x0154; 143 // 141 251 | 252 | #if _MSC_VER 253 | auto tstart = high_resolution_clock::now(); 254 | auto tend = high_resolution_clock::now(); 255 | #else 256 | struct timespec tstart = { 0,0 }, tend = { 0,0 }; 257 | #endif 258 | while (1) { 259 | 260 | /* 261 | LAST = NOW; 262 | NOW = SDL_GetPerformanceCounter(); 263 | 264 | deltaTime = (double)((NOW - LAST)*1000 / (double)SDL_GetPerformanceFrequency() ); 265 | */ 266 | 267 | 268 | #if _MSC_VER 269 | tend = high_resolution_clock::now(); 270 | deltaTime = duration_cast(tend - tstart).count() * 1e-9; 271 | tstart = high_resolution_clock::now(); 272 | #else 273 | clock_gettime(CLOCK_MONOTONIC, &tend); 274 | deltaTime = ((double)tend.tv_sec + 1.0e-9*tend.tv_nsec) - ((double)tstart.tv_sec + 1.0e-9*tstart.tv_nsec); 275 | clock_gettime(CLOCK_MONOTONIC, &tstart); 276 | 277 | #endif 278 | 279 | frame += deltaTime; 280 | //keyboard += deltaTime; 281 | ide += deltaTime; 282 | cpu += deltaTime; 283 | cpu_clk += deltaTime; 284 | 285 | 286 | if ((z80.registers.IFF & IFF_HALT) == 0x0 && 287 | ((!do_steps && cpu >= speed) || (do_steps && step))) { 288 | 289 | /* 290 | if (oldd != z80.ICount) { 291 | printf("%x\t", z80.ICount); 292 | printf(BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(z80.ICount)); 293 | printf("\n"); 294 | oldd = z80.ICount; 295 | } 296 | 297 | */ 298 | 299 | 300 | if (wait == 0 && do_steps == 0 && z80.IRequest == INT_NONE && z80.PORT_0002h == 0xFF && !(z80.registers.IFF & IFF_EI) && (z80.registers.IFF & IFF_1) && (z80.registers.IFF & IFF_2) && !keyboard_queue->empty()) { 301 | ///if (z80.ICount < 0 && do_steps == 0 && z80.IRequest == INT_NONE && z80.PORT_0002h == 0xFF && ((z80.registers.IFF & 0b00001101) == 0b00001101) && !keyboard_queue->empty()) { 302 | 303 | 304 | #ifdef _MSC_VER 305 | std::unique_lock lock(mtx_out); 306 | #else 307 | pthread_mutex_lock(&mtx_out); 308 | #endif 309 | 310 | int key = keyboard_queue->front(); 311 | keyboard_queue->pop(); 312 | 313 | #ifdef _MSC_VER 314 | cv_out.notify_all(); 315 | #else 316 | pthread_mutex_unlock(&mtx_out); 317 | #endif 318 | 319 | 320 | //if (key != (int)'7' && key != (int)'8' && key != (int)'9') { 321 | 322 | z80.PORT_0002h = key; 323 | z80.IRequest = z80.keyboard_int; 324 | z80.registers.IFF |= IFF_IM1; 325 | //z80.registers.IFF &= ~IFF_1; 326 | //z80.registers.IFF |= IFF_EI; 327 | //IntZ80(z80, z80cpm_memory->memory, 0x60); 328 | wait = 1; 329 | //oldc = 0; 330 | } 331 | //else if (z80.ICount > 0 && z80.IRequest != INT_NONE && z80.PORT_0002h == 0xFF) { 332 | // z80.IRequest = INT_NONE; 333 | //} 334 | 335 | else if (wait < 700 && wait > 0 && do_steps == 0 && z80.IRequest == INT_NONE && z80.PORT_0002h == 0xFF && !(z80.registers.IFF & IFF_EI) && (z80.registers.IFF & IFF_1) && (z80.registers.IFF & IFF_2) && !keyboard_queue->empty()) 336 | wait++; 337 | else if (do_steps == 0 && z80.IRequest == INT_NONE && z80.PORT_0002h == 0xFF && !(z80.registers.IFF & IFF_EI) && (z80.registers.IFF & IFF_1) && (z80.registers.IFF & IFF_2) && !keyboard_queue->empty()) 338 | wait = 0; 339 | 340 | //keyboard = 0; 341 | /* 342 | if (wait == 1 && z80.registers.IFF == 0xd && oldc < 2) { 343 | oldc++; 344 | } 345 | 346 | else if (wait < 100 && wait > 0) 347 | wait++; 348 | else if (wait > 0){ 349 | wait = 0; 350 | } 351 | */ 352 | 353 | //} 354 | 355 | 356 | 357 | 358 | cpu_exec(z80, z80cpm_memory); iii++; 359 | cpu = 0; 360 | 361 | step = 0; 362 | //if(RdZ80(z80,0x4042) == 0x1c) 363 | //if(do_breakpoint && z80.registers.HL ==0x4042) 364 | // do_steps = 1; 365 | 366 | 367 | if (do_breakpoint && z80.registers.PC == breakpoint) 368 | do_steps = 1; 369 | 370 | //if(do_breakpoint && z80->RdZ80(RdZ80(z80, z80.registers.PC) == bp_opcode 371 | //&& z80->RdZ80(RdZ80(z80, z80.registers.PC+1) == bp_opcode2) 372 | // do_steps = 1; 373 | 374 | } 375 | else if (z80.registers.IFF & IFF_HALT) { 376 | cpu = 0; 377 | iii++; 378 | } 379 | 380 | 381 | if (frame >= 0.1) { 382 | /* 383 | if (key == (int)'b') { 384 | do_breakpoint = !do_breakpoint; 385 | } 386 | 387 | if (key == (int)'s') { 388 | do_steps = !do_steps; 389 | } 390 | 391 | if (key == (int)'r') { 392 | do_steps = 0; 393 | } 394 | 395 | if (key == (int)'n') { 396 | step = 1; 397 | } 398 | 399 | if (key == (int)'2') { 400 | if (mem_offset + 0x10 < Z80CPM_MEMORY_SIZE) 401 | mem_offset += 0x10; 402 | } 403 | if (key == (int)'1') { 404 | if (mem_offset - 0x10 > 0) 405 | mem_offset -= 0x10; 406 | } 407 | if (key == (int)'3') { 408 | if (mem_offset + 0x100 < Z80CPM_MEMORY_SIZE) 409 | mem_offset += 0x100; 410 | } 411 | if (key == (int)'4') { 412 | if (mem_offset - 0x100 > 0) 413 | mem_offset -= 0x100; 414 | } 415 | if (key == (int)'5') { 416 | if (mem_offset + 0x1000 < Z80CPM_MEMORY_SIZE) 417 | mem_offset += 0x1000; 418 | } 419 | if (key == (int)'6') { 420 | if (mem_offset - 0x1000 > 0) 421 | mem_offset -= 0x1000; 422 | } 423 | if (key == (int)'7') { 424 | speed /= 10; 425 | } 426 | if (key == (int)'8') { 427 | if (speed < 1) 428 | speed *= 10; 429 | else if (speed > 1) 430 | speed += 1; 431 | 432 | if (speed > 2) 433 | speed = 2; 434 | } 435 | if (key == (int)'9') { 436 | mem_follow = !mem_follow; 437 | } 438 | 439 | if (key == (int)'0') 440 | return NULL; 441 | */ 442 | 443 | 444 | //cls(hConsole); 445 | 446 | if (show_debug) { 447 | #if _MSC_VER 448 | COORD pos = { 0, 0 }; 449 | SetConsoleCursorPosition(hConsole, pos); 450 | #endif 451 | printf(" \r\n"); 452 | printf(" \n"); 453 | printf(" \n"); 454 | #if _MSC_VER 455 | SetConsoleCursorPosition(hConsole, pos); 456 | #endif 457 | printf("%.3fMHz - %g\n", ((float)iii) / 1000000, speed); 458 | printf("%s", z80.last_op_desc); 459 | cpu_print(z80, z80cpm_memory); 460 | } 461 | frame = 0; 462 | 463 | 464 | } 465 | 466 | if (z80.registers.IFF & IFF_HALT) { 467 | //printf("%s", z80.last_op_desc); 468 | //printf("HALT"); 469 | //return; 470 | 471 | 472 | //do_steps = 0; 473 | //do_steps = 1; 474 | z80.IntZ80(z80cpm_memory, INT_IRQ); iii++; 475 | z80.registers.IFF |= IFF_1; 476 | z80.IntZ80(z80cpm_memory, INT_IRQ); 477 | } 478 | 479 | 480 | if (cpu_clk >= 1) { 481 | iii = 0; 482 | cpu_clk = 0; 483 | } 484 | 485 | 486 | 487 | 488 | if (ide >= 10) { 489 | if (z80.hw_ide.save == 1) { 490 | hw_ide_save_disk(z80.hw_ide.memory); 491 | z80.hw_ide.save = 0; 492 | } 493 | 494 | ide = 0; 495 | } 496 | } 497 | 498 | return NULL; 499 | } 500 | 501 | 502 | int main(int argc, char** argv) 503 | { 504 | 505 | const char* filename; 506 | if (argc < 2) 507 | { 508 | printf("Loading Default Rom\n"); 509 | //return -1; 510 | filename = "rom.bin"; 511 | } 512 | else 513 | filename = argv[1]; 514 | 515 | printf("The filename to load is: %s\n", filename); 516 | 517 | FILE* f = fopen(filename, "rb"); 518 | if (!f) 519 | { 520 | printf("Failed to open the file\n"); 521 | printf("Press any key to continue"); 522 | getch(); 523 | return -1; 524 | } 525 | 526 | fseek(f, 0, SEEK_END); 527 | long size = ftell(f); 528 | fseek(f, 0, SEEK_SET); 529 | 530 | char* buf = (char*)malloc(size * sizeof(char)); 531 | 532 | int res = fread(buf, size, 1, f); 533 | if (res != 1) 534 | { 535 | printf("Failed to read from file"); 536 | return -1; 537 | } 538 | 539 | 540 | struct z80cpm_keyboard z80cpm_keyboard; 541 | struct z80cpm_memory z80cpm_memory; 542 | Z80 z80; 543 | z80.z80_init(); 544 | 545 | /////////////////////////////////////////////////////////////////////////// 546 | z80cpm_memory.memory = (unsigned char*)malloc(Z80CPM_MEMORY_SIZE * sizeof(unsigned char)); 547 | z80cpm_memory.rom = (unsigned char*)malloc(Z80CPM_MEMORY_SIZE * sizeof(unsigned char)); 548 | //memcpy(z80->RdZ80(memory.memory, z80_default_character_set, sizeof(z80_default_character_set)); 549 | 550 | int j = 0; 551 | for (j = 0; j < Z80CPM_MEMORY_SIZE; j++) { 552 | z80cpm_memory.memory[j] = 0x00; 553 | z80cpm_memory.rom[j] = 0x00; 554 | } 555 | z80cpm_memory.rom_disabled = 0; 556 | 557 | //assert(size + Z80_PROGRAM_LOAD_ADDRESS < Z80_MEMORY_SIZE); 558 | //memcpy(&z80->RdZ80(memory.z80cpm_memory->memory[Z80_PROGRAM_LOAD_ADDRESS], buf, size); 559 | 560 | //memcpy(z80->RdZ80(memory.memory, buf, size); 561 | memcpy(&z80cpm_memory.rom[0], buf, size); 562 | /////////////////////////////////////////////////////////////////////////// 563 | 564 | z80.z80_reset(); 565 | 566 | z80cpm_keyboard_set_map(&z80cpm_keyboard, keyboard_map); 567 | 568 | 569 | z80.z80cpm_memory = &z80cpm_memory; 570 | 571 | 572 | #if _MSC_VER 573 | DWORD tid; 574 | HANDLE myHandle = CreateThread(0, 0, run_thread, &z80, 0, &tid); 575 | #else 576 | pthread_t tid; 577 | pthread_create(&tid, NULL, run_thread, (void *)&z80); 578 | #endif 579 | 580 | 581 | 582 | int last_cold = 0; 583 | while (1) { 584 | //if (kbhit()) { 585 | int key = getch(); 586 | if (last_cold == 0 && key == 17) { 587 | last_cold = 1; 588 | 589 | #ifdef _MSC_VER 590 | std::unique_lock lock(mtx_out); 591 | #else 592 | pthread_mutex_lock(&mtx_out); 593 | #endif 594 | 595 | z80.keyboard_queue.push(key); 596 | 597 | #ifdef _MSC_VER 598 | cv_out.notify_all(); 599 | #else 600 | pthread_mutex_unlock(&mtx_out); 601 | #endif 602 | } 603 | else { 604 | 605 | if (last_cold == 1 && key == 3) { 606 | do_steps = 1; 607 | printf("\n"); 608 | printf("<< COLD RESET >>\n"); 609 | 610 | //free(z80cpm_memory.memory); 611 | 612 | /////////////////////////////////////////////////////////////////////////// 613 | z80cpm_memory.memory = (unsigned char*)malloc(Z80CPM_MEMORY_SIZE * sizeof(unsigned char)); 614 | //memcpy(z80->RdZ80(memory.memory, z80_default_character_set, sizeof(z80_default_character_set)); 615 | 616 | for (j = 0; j < Z80CPM_MEMORY_SIZE; j++) 617 | z80cpm_memory.memory[j] = 0x00; 618 | 619 | memcpy(&z80cpm_memory.rom[0], buf, size); 620 | /////////////////////////////////////////////////////////////////////////// 621 | 622 | z80.z80_reset(); 623 | z80cpm_memory.rom_disabled = 0; 624 | do_steps = 0; 625 | } 626 | else if (last_cold == 1 && key == 23) { 627 | do_steps = 1; 628 | printf("\n"); 629 | printf("<< WARM RESET >>\n"); 630 | 631 | z80.z80_reset(); 632 | //z80cpm_memory.rom_disabled = 0; 633 | 634 | queue empty; 635 | std::swap(z80.keyboard_queue, empty); 636 | 637 | do_steps = 0; 638 | } 639 | else { 640 | #ifdef _MSC_VER 641 | std::unique_lock lock(mtx_out); 642 | #else 643 | pthread_mutex_lock(&mtx_out); 644 | #endif 645 | 646 | z80.keyboard_queue.push(key); 647 | 648 | #ifdef _MSC_VER 649 | cv_out.notify_all(); 650 | #else 651 | pthread_mutex_unlock(&mtx_out); 652 | #endif 653 | } 654 | 655 | last_cold = 0; 656 | 657 | } 658 | //} 659 | 660 | /* 661 | if (key == (int)'2') { 662 | if (mem_offset + 0x10 < Z80CPM_MEMORY_SIZE) 663 | mem_offset += 0x10; 664 | } 665 | if (key == (int)'1') { 666 | if (mem_offset - 0x10 > 0) 667 | mem_offset -= 0x10; 668 | } 669 | if (key == (int)'3') { 670 | if (mem_offset + 0x100 < Z80CPM_MEMORY_SIZE) 671 | mem_offset += 0x100; 672 | } 673 | if (key == (int)'4') { 674 | if (mem_offset - 0x100 > 0) 675 | mem_offset -= 0x100; 676 | } 677 | if (key == (int)'5') { 678 | if (mem_offset + 0x1000 < Z80CPM_MEMORY_SIZE) 679 | mem_offset += 0x1000; 680 | } 681 | if (key == (int)'6') { 682 | if (mem_offset - 0x1000 > 0) 683 | mem_offset -= 0x1000; 684 | } 685 | 686 | if (key == (int)'9') { 687 | mem_follow = !mem_follow; 688 | } 689 | 690 | if (key == (int)'0') 691 | return NULL; 692 | */ 693 | } 694 | 695 | out: 696 | 697 | return 0; 698 | } 699 | -------------------------------------------------------------------------------- /src/queue_ll.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // queue_ll.cpp 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #include 19 | #include 20 | #include "queue_ll.h" 21 | 22 | struct queue_ll { 23 | Linked_List* begin; 24 | Linked_List* end; 25 | }; 26 | 27 | Queue* queue_create(void) { 28 | Queue* f = (Queue*)malloc(sizeof(Queue)); 29 | f->begin = NULL; 30 | f->end = NULL; 31 | return f; 32 | } 33 | 34 | 35 | void queue_insert(Queue* f, void* info) { 36 | 37 | Linked_List* n = ll_insert(NULL, info); 38 | 39 | 40 | if (f->end != NULL) 41 | f->end->next = n; 42 | else 43 | f->begin = n; 44 | f->end = n; 45 | } 46 | 47 | 48 | void* queue_remove(Queue* f) { 49 | 50 | void* info; 51 | 52 | if (queue_empty(f)) { 53 | return NULL; 54 | } 55 | 56 | if (f->begin == NULL){ 57 | f->end = NULL; 58 | return NULL; 59 | } 60 | else { 61 | info = f->begin->info; 62 | 63 | f->begin = ll_remove_first(f->begin); 64 | 65 | if (f->begin == NULL) 66 | f->end = NULL; 67 | } 68 | return info; 69 | } 70 | 71 | 72 | int queue_empty(Queue* f) 73 | { 74 | return ll_empty(f->begin) && ll_empty(f->end); 75 | } 76 | 77 | void queue_free(Queue* f, void(*ffree)(void *)) 78 | { 79 | ll_free(f->begin, ffree); 80 | 81 | free(f); 82 | } 83 | 84 | void queue_print(Queue* f, void(*fprint)(void *)) 85 | { 86 | 87 | Linked_List* q = f->begin; 88 | while (q != NULL) { 89 | fprint(q->info); 90 | q = q->next; 91 | } 92 | } -------------------------------------------------------------------------------- /src/tasm_opcode.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // tasm_opcode.cpp 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #include "tasm_opcode.h" 19 | 20 | Tasm_Opcode::Tasm_Opcode(string opcode, string desc, int size) { 21 | this->opcode = opcode; 22 | this->desc = desc; 23 | this->size = size; 24 | } 25 | -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // utils.cpp 3 | // 4 | ////// BEGIN LICENSE NOTICE////// 5 | // 6 | //Z80 CPM Emulator - based on CP/M on breadboard by Grant Searle (http://searle.x10host.com/cpm/index.html) 7 | // 8 | //Copyright(C) 2021 Augusto Baffa, (cpm.baffasoft.com.br) 9 | // 10 | //This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 11 | // 12 | //This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301, USA. 15 | // 16 | ////// END LICENSE NOTICE////// 17 | // 18 | #include "utils.h" 19 | #include 20 | 21 | #ifdef __linux__ 22 | #include 23 | #include 24 | #include 25 | 26 | 27 | int getch(void) 28 | { 29 | int ch = EOF; 30 | struct termios oldt, newt; 31 | int oldf; 32 | 33 | while (ch == EOF) { 34 | 35 | tcgetattr(STDIN_FILENO, &oldt); 36 | newt = oldt; 37 | newt.c_lflag &= ~(ICANON | ECHO); 38 | tcsetattr(STDIN_FILENO, TCSANOW, &newt); 39 | oldf = fcntl(STDIN_FILENO, F_GETFL, 0); 40 | fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); 41 | 42 | ch = getchar(); 43 | 44 | tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 45 | fcntl(STDIN_FILENO, F_SETFL, oldf); 46 | 47 | } 48 | 49 | return ch; 50 | } 51 | 52 | int kbhit(void) 53 | { 54 | struct termios oldt, newt; 55 | int ch; 56 | int oldf; 57 | 58 | tcgetattr(STDIN_FILENO, &oldt); 59 | newt = oldt; 60 | newt.c_lflag &= ~(ICANON | ECHO); 61 | tcsetattr(STDIN_FILENO, TCSANOW, &newt); 62 | oldf = fcntl(STDIN_FILENO, F_GETFL, 0); 63 | fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); 64 | 65 | ch = getchar(); 66 | 67 | tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 68 | fcntl(STDIN_FILENO, F_SETFL, oldf); 69 | 70 | if (ch != EOF) 71 | { 72 | ungetc(ch, stdin); 73 | return 1; 74 | } 75 | 76 | return 0; 77 | } 78 | 79 | char* itoa(int value, char* result, int base) { 80 | // check that the base if valid 81 | if (base < 2 || base > 36) { *result = '\0'; return result; } 82 | 83 | char* ptr = result, *ptr1 = result, tmp_char; 84 | int tmp_value; 85 | 86 | do { 87 | tmp_value = value; 88 | value /= base; 89 | *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)]; 90 | } while (value); 91 | 92 | // Apply negative sign 93 | if (tmp_value < 0) *ptr++ = '-'; 94 | *ptr-- = '\0'; 95 | while (ptr1 < ptr) { 96 | tmp_char = *ptr; 97 | *ptr-- = *ptr1; 98 | *ptr1++ = tmp_char; 99 | } 100 | return result; 101 | } 102 | #else 103 | 104 | #endif 105 | 106 | void print_word_bin(char *s, short n) { 107 | char h = MSB(n); 108 | char l = LSB(n); 109 | 110 | sprintf(s, "%02x ", h); 111 | sprintf(s + strlen(s), "%c%c%c%c%c%c%c%c", BYTE_TO_BINARY(h)); 112 | sprintf(s + strlen(s), " "); 113 | sprintf(s + strlen(s), "%02x ", l); 114 | sprintf(s + strlen(s), "%c%c%c%c%c%c%c%c", BYTE_TO_BINARY(l)); 115 | } 116 | 117 | void print_word_bin_nibbles(char *s, short n) { 118 | char bh = MSB(n); 119 | char bl = LSB(n); 120 | 121 | char bhnh = MSN(bh); 122 | char bhnl = LSN(bh); 123 | 124 | char blnh = MSN(bl); 125 | char blnl = LSN(bl); 126 | 127 | sprintf(s, "%01x ", bhnh); 128 | sprintf(s + strlen(s), "%c%c%c%c", NIBBLE_TO_BINARY(bhnh)); 129 | sprintf(s + strlen(s), " "); 130 | 131 | sprintf(s + strlen(s), "%01x ", bhnl); 132 | sprintf(s + strlen(s), "%c%c%c%c", NIBBLE_TO_BINARY(bhnl)); 133 | sprintf(s + strlen(s), " "); 134 | 135 | sprintf(s + strlen(s), "%01x ", blnh); 136 | sprintf(s + strlen(s), "%c%c%c%c", NIBBLE_TO_BINARY(blnh)); 137 | sprintf(s + strlen(s), " "); 138 | 139 | sprintf(s + strlen(s), "%01x ", blnl); 140 | sprintf(s + strlen(s), "%c%c%c%c", NIBBLE_TO_BINARY(blnl)); 141 | } 142 | 143 | 144 | void print_byte_bin(char *s, char b) { 145 | sprintf(s, "%02x ", b); 146 | sprintf(s + strlen(s), "%c%c%c%c%c%c%c%c", BYTE_TO_BINARY(b)); 147 | } 148 | 149 | void print_nibble_bin(char *s, char b) { 150 | sprintf(s, "%01x ", b); 151 | sprintf(s + strlen(s), "%c%c%c%c", NIBBLE_TO_BINARY(b)); 152 | } 153 | 154 | 155 | unsigned int toInt(char c) 156 | { 157 | if (c >= '0' && c <= '9') return c - '0'; 158 | if (c >= 'A' && c <= 'F') return 10 + c - 'A'; 159 | if (c >= 'a' && c <= 'f') return 10 + c - 'a'; 160 | return -1; 161 | } 162 | 163 | 164 | 165 | void leftpad(char *str1, char *str2, int pad) { 166 | 167 | size_t p = pad - strlen(str1); 168 | int i = 0; 169 | for (i = 0; i < pad; i++) { 170 | if (i < p) 171 | str2[i] = '0'; 172 | else 173 | str2[i] = str1[i - p]; 174 | } 175 | 176 | str2[i] = '\0'; 177 | 178 | } 179 | 180 | char* rightpad(const char *str1, int pad) { 181 | 182 | char *str2 = (char*)malloc(pad + 1); 183 | 184 | size_t p = strlen(str1); 185 | int i = 0; 186 | for (i = 0; i < pad; i++) { 187 | if (i < p) 188 | str2[i] = str1[i]; 189 | else 190 | str2[i] = ' '; 191 | 192 | } 193 | 194 | str2[i] = '\0'; 195 | 196 | return str2; 197 | } 198 | 199 | unsigned int convert_hexstr_to_value(char *value) { 200 | size_t numdigits = strlen(value) / 2; 201 | size_t i; 202 | unsigned int address = 0; 203 | for (i = 0; i != numdigits; ++i) 204 | { 205 | address = address << 8; 206 | 207 | unsigned char output = 16 * toInt(value[2 * i]) + toInt(value[2 * i + 1]); 208 | address += output; 209 | } 210 | return address; 211 | } 212 | 213 | char* loadfile(char *s, char *filename, long *size) { 214 | 215 | sprintf(s, "The filename to load is: %s", filename); 216 | 217 | FILE* f = fopen(filename, "rb"); 218 | if (!f) 219 | { 220 | sprintf(s + strlen(s), " | Failed to open the file.\n"); 221 | return NULL; 222 | } 223 | 224 | fseek(f, 0, SEEK_END); 225 | *size = ftell(f); 226 | fseek(f, 0, SEEK_SET); 227 | 228 | char* buf = (char*)malloc((*size) * sizeof(char)); 229 | 230 | size_t res = fread(buf, *size, 1, f); 231 | if (res != 1) 232 | { 233 | sprintf(s + strlen(s), " | Failed to read from file.\n"); 234 | return NULL; 235 | } 236 | 237 | sprintf(s + strlen(s), " | OK.\n"); 238 | return buf; 239 | } 240 | 241 | void save_to_log(char *s, FILE *fa, char *str) 242 | { 243 | 244 | //FILE *fa = fopen("File1.txt", "a"); 245 | if (fa == NULL) 246 | { 247 | if (s == NULL) 248 | printf("can not open target file\n"); 249 | else 250 | sprintf(s, "can not open target file\n"); 251 | exit(1); 252 | } 253 | 254 | fprintf(fa, "%s", str); 255 | fflush(fa); 256 | //fputc(str, fa); 257 | 258 | //fclose(fa); 259 | 260 | } 261 | 262 | 263 | 264 | char* strlower(char* s) 265 | { 266 | char* tmp = s; 267 | 268 | for (; *tmp; ++tmp) { 269 | *tmp = tolower((unsigned char)*tmp); 270 | } 271 | 272 | return s; 273 | } -------------------------------------------------------------------------------- /src/z80cpm_keyboard.cpp: -------------------------------------------------------------------------------- 1 | #include "z80cpm_keyboard.h" 2 | #include 3 | 4 | static void z80cpm_keyboard_ensure_in_bounds(int key){ 5 | assert(key >= 0 && key < Z80CPM_TOTAL_KEYS); 6 | } 7 | 8 | void z80cpm_keyboard_set_map(struct z80cpm_keyboard* keyboard, const unsigned int* map) 9 | { 10 | keyboard->keyboard_map = map; 11 | int i; 12 | for(i = 0; i < Z80CPM_TOTAL_KEYS; i++) 13 | keyboard->keyboard[i] = false; 14 | } 15 | 16 | int z80cpm_keyboard_map(struct z80cpm_keyboard* keyboard, int key) 17 | { 18 | 19 | int i; 20 | for(i = 0; i < Z80CPM_TOTAL_KEYS; i++) 21 | { 22 | if(keyboard->keyboard_map[i] == key) 23 | { 24 | return i; 25 | } 26 | } 27 | 28 | return -1; 29 | } 30 | 31 | void z80cpm_keyboard_down(struct z80cpm_keyboard* keyboard, int key) 32 | { 33 | keyboard->keyboard[key] = true; 34 | } 35 | 36 | void z80cpm_keyboard_up(struct z80cpm_keyboard* keyboard, int key) 37 | { 38 | keyboard->keyboard[key] = false; 39 | } 40 | 41 | bool z80cpm_keyboard_is_down(struct z80cpm_keyboard* keyboard, int key) 42 | { 43 | return keyboard->keyboard[key]; 44 | } -------------------------------------------------------------------------------- /src/z80cpm_memory.cpp: -------------------------------------------------------------------------------- 1 | #include "z80cpm_memory.h" 2 | #include 3 | #include 4 | 5 | static void z80cpm_is_memory_in_bounds(int index) 6 | { 7 | assert(index >= 0 && index < Z80CPM_MEMORY_SIZE); 8 | } 9 | 10 | void z80cpm_memory_set(struct z80cpm_memory* z80cpm_memory, int index, unsigned char val) 11 | { 12 | z80cpm_is_memory_in_bounds(index); 13 | z80cpm_memory->memory[index] = val; 14 | } 15 | 16 | unsigned char z80cpm_memory_get(struct z80cpm_memory* z80cpm_memory, int index) 17 | { 18 | z80cpm_is_memory_in_bounds(index); 19 | return z80cpm_memory->memory[index]; 20 | } 21 | 22 | unsigned short z80cpm_memory_get_short(struct z80cpm_memory* z80cpm_memory, int index) 23 | { 24 | unsigned char byte1 = z80cpm_memory_get(z80cpm_memory, index); 25 | unsigned char byte2 = z80cpm_memory_get(z80cpm_memory, index + 1); 26 | 27 | return byte1 << 8 | byte2; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/z80cpm_screen.cpp: -------------------------------------------------------------------------------- 1 | #include "z80cpm_screen.h" 2 | #include 3 | #include 4 | 5 | 6 | static void z80cpm_screen_check_bounds(int x, int y) 7 | { 8 | assert(x >= 0 && x < Z80CPM_WIDTH && y >= 0 && y < Z80CPM_HEIGHT); 9 | } 10 | 11 | void z80cpm_screen_set(struct z80cpm_screen* screen, int x, int y) 12 | { 13 | z80cpm_screen_check_bounds(x, y); 14 | screen->pixels[y][x] = true; 15 | } 16 | 17 | void z80cpm_screen_clear(struct z80cpm_screen* screen) 18 | { 19 | memset(screen->pixels, 0, sizeof(screen->pixels)); 20 | } 21 | 22 | bool z80cpm_screen_is_set(struct z80cpm_screen* screen, int x, int y) 23 | { 24 | z80cpm_screen_check_bounds(x, y); 25 | return screen->pixels[y][x]; 26 | } 27 | 28 | bool z80cpm_screen_draw_sprite(struct z80cpm_screen* screen, int x, int y, const char* sprite, int num) 29 | { 30 | bool pixel_collision = false; 31 | int lx, ly; 32 | for(ly = 0; ly < num; ly++){ 33 | char c = sprite[ly]; 34 | for(lx = 0; lx < 8; lx++) 35 | { 36 | if((c & (0b10000000 >> lx)) == 0) 37 | continue; 38 | 39 | if(screen->pixels[(ly+y) % Z80CPM_HEIGHT][(lx+x) % Z80CPM_WIDTH]) 40 | { 41 | pixel_collision = true; 42 | } 43 | 44 | screen->pixels[(ly+y) % Z80CPM_HEIGHT][(lx+x) % Z80CPM_WIDTH] ^= true; 45 | } 46 | } 47 | return pixel_collision; 48 | } -------------------------------------------------------------------------------- /z80cpm_vc/z80cpm_emul/z80cpm_emul.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "z80cpm_emul", "z80cpm_emul\z80cpm_emul.vcxproj", "{94AED0A7-E513-4A23-84DC-7C1F98107E42}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {94AED0A7-E513-4A23-84DC-7C1F98107E42}.Debug|x64.ActiveCfg = Debug|x64 17 | {94AED0A7-E513-4A23-84DC-7C1F98107E42}.Debug|x64.Build.0 = Debug|x64 18 | {94AED0A7-E513-4A23-84DC-7C1F98107E42}.Debug|x86.ActiveCfg = Debug|Win32 19 | {94AED0A7-E513-4A23-84DC-7C1F98107E42}.Debug|x86.Build.0 = Debug|Win32 20 | {94AED0A7-E513-4A23-84DC-7C1F98107E42}.Release|x64.ActiveCfg = Release|x64 21 | {94AED0A7-E513-4A23-84DC-7C1F98107E42}.Release|x64.Build.0 = Release|x64 22 | {94AED0A7-E513-4A23-84DC-7C1F98107E42}.Release|x86.ActiveCfg = Release|Win32 23 | {94AED0A7-E513-4A23-84DC-7C1F98107E42}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /z80cpm_vc/z80cpm_emul/z80cpm_emul/data.dsk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaffa/z80cpm_emulator/7ed59c9e49bd4f223e174ea87746bfabe73761bf/z80cpm_vc/z80cpm_emul/z80cpm_emul/data.dsk -------------------------------------------------------------------------------- /z80cpm_vc/z80cpm_emul/z80cpm_emul/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /z80cpm_vc/z80cpm_emul/z80cpm_emul/rom.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaffa/z80cpm_emulator/7ed59c9e49bd4f223e174ea87746bfabe73761bf/z80cpm_vc/z80cpm_emul/z80cpm_emul/rom.bin -------------------------------------------------------------------------------- /z80cpm_vc/z80cpm_emul/z80cpm_emul/tasm80.tab: -------------------------------------------------------------------------------- 1 | "TASM Z80 Assembler. " 2 | .ALTWILD 3 | 4 | ADC A,(HL) 8E 1 NOP 1 5 | ADC A,(IX*) 8EDD 3 ZIX 1 6 | ADC A,(IY*) 8EFD 3 ZIX 1 7 | ADC A,A 8F 1 NOP 1 8 | ADC A,B 88 1 NOP 1 9 | ADC A,C 89 1 NOP 1 10 | ADC A,D 8A 1 NOP 1 11 | ADC A,E 8B 1 NOP 1 12 | ADC A,H 8C 1 NOP 1 13 | ADC A,L 8D 1 NOP 1 14 | ADC A,* CE 2 NOP 1 15 | ADC HL,BC 4AED 2 NOP 1 16 | ADC HL,DE 5AED 2 NOP 1 17 | ADC HL,HL 6AED 2 NOP 1 18 | ADC HL,SP 7AED 2 NOP 1 19 | 20 | ADD A,(HL) 86 1 NOP 1 21 | ADD A,(IX*) 86DD 3 ZIX 1 22 | ADD A,(IY*) 86FD 3 ZIX 1 23 | ADD A,A 87 1 NOP 1 24 | ADD A,B 80 1 NOP 1 25 | ADD A,C 81 1 NOP 1 26 | ADD A,D 82 1 NOP 1 27 | ADD A,E 83 1 NOP 1 28 | ADD A,H 84 1 NOP 1 29 | ADD A,L 85 1 NOP 1 30 | ADD A,* C6 2 NOP 1 31 | ADD HL,BC 9 1 NOP 1 32 | ADD HL,DE 19 1 NOP 1 33 | ADD HL,HL 29 1 NOP 1 34 | ADD HL,SP 39 1 NOP 1 35 | ADD IX,BC 09DD 2 NOP 1 36 | ADD IX,DE 19DD 2 NOP 1 37 | ADD IX,IX 29DD 2 NOP 1 38 | ADD IX,SP 39DD 2 NOP 1 39 | ADD IY,BC 09FD 2 NOP 1 40 | ADD IY,DE 19FD 2 NOP 1 41 | ADD IY,IY 29FD 2 NOP 1 42 | ADD IY,SP 39FD 2 NOP 1 43 | 44 | AND (HL) A6 1 NOP 1 45 | AND (IX*) A6DD 3 ZIX 1 46 | AND (IY*) A6FD 3 ZIX 1 47 | AND A A7 1 NOP 1 48 | AND B A0 1 NOP 1 49 | AND C A1 1 NOP 1 50 | AND D A2 1 NOP 1 51 | AND E A3 1 NOP 1 52 | AND H A4 1 NOP 1 53 | AND L A5 1 NOP 1 54 | AND * E6 2 NOP 1 55 | 56 | BIT *,(HL) 46CB 2 ZBI T 1 57 | BIT *,(IX*) CBDD 4 ZBI T 1 0 4600 58 | BIT *,(IY*) CBFD 4 ZBI T 1 0 4600 59 | BIT *,A 47CB 2 ZBI T 1 60 | BIT *,B 40CB 2 ZBI T 1 61 | BIT *,C 41CB 2 ZBI T 1 62 | BIT *,D 42CB 2 ZBI T 1 63 | BIT *,E 43CB 2 ZBI T 1 64 | BIT *,H 44CB 2 ZBI T 1 65 | BIT *,L 45CB 2 ZBI T 1 66 | 67 | CALL C,* DC 3 NOP 1 68 | CALL M,* FC 3 NOP 1 69 | CALL NC,* D4 3 NOP 1 70 | CALL NZ,* C4 3 NOP 1 71 | CALL P,* F4 3 NOP 1 72 | CALL PE,* EC 3 NOP 1 73 | CALL PO,* E4 3 NOP 1 74 | CALL Z,* CC 3 NOP 1 75 | CALL * CD 3 NOP 1 76 | 77 | CCF "" 3F 1 NOP 1 78 | 79 | CP (HL) BE 1 NOP 1 80 | CP (IX*) BEDD 3 ZIX 1 81 | CP (IY*) BEFD 3 ZIX 1 82 | CP A BF 1 NOP 1 83 | CP B B8 1 NOP 1 84 | CP C B9 1 NOP 1 85 | CP D BA 1 NOP 1 86 | CP E BB 1 NOP 1 87 | CP H BC 1 NOP 1 88 | CP L BD 1 NOP 1 89 | CP * FE 2 NOP 1 90 | CPD "" A9ED 2 NOP 1 91 | CPDR "" B9ED 2 NOP 1 92 | CPIR "" B1ED 2 NOP 1 93 | CPI "" A1ED 2 NOP 1 94 | CPL "" 2F 1 NOP 1 95 | 96 | DAA "" 27 1 NOP 1 97 | 98 | DEC (HL) 35 1 NOP 1 99 | DEC (IX*) 35DD 3 ZIX 1 100 | DEC (IY*) 35FD 3 ZIX 1 101 | DEC A 3D 1 NOP 1 102 | DEC B 5 1 NOP 1 103 | DEC BC 0B 1 NOP 1 104 | DEC C 0D 1 NOP 1 105 | DEC D 15 1 NOP 1 106 | DEC DE 1B 1 NOP 1 107 | DEC E 1D 1 NOP 1 108 | DEC H 25 1 NOP 1 109 | DEC HL 2B 1 NOP 1 110 | DEC IX 2BDD 2 NOP 1 111 | DEC IY 2BFD 2 NOP 1 112 | DEC L 2D 1 NOP 1 113 | DEC SP 3B 1 NOP 1 114 | DI "" F3 1 NOP 1 115 | DJNZ * 10 2 R1 1 116 | 117 | EI "" FB 1 NOP 1 118 | EX (SP),HL E3 1 NOP 1 119 | EX (SP),IX E3DD 2 NOP 1 120 | EX (SP),IY E3FD 2 NOP 1 121 | EX AF,AF' 8 1 NOP 1 122 | EX DE,HL EB 1 NOP 1 123 | EXX "" D9 1 NOP 1 124 | HALT "" 76 1 NOP 1 125 | 126 | IM 0 46ED 2 NOP 1 127 | IM 1 56ED 2 NOP 1 128 | IM 2 5EED 2 NOP 1 129 | 130 | IN A,(C) 78ED 2 NOP 1 131 | IN B,(C) 40ED 2 NOP 1 132 | IN C,(C) 48ED 2 NOP 1 133 | IN D,(C) 50ED 2 NOP 1 134 | IN E,(C) 58ED 2 NOP 1 135 | IN H,(C) 60ED 2 NOP 1 136 | IN L,(C) 68ED 2 NOP 1 137 | 138 | IN A,(*) DB 2 NOP 1 139 | 140 | IN0 A,(*) 38ED 3 NOP 2 141 | IN0 B,(*) 00ED 3 NOP 2 142 | IN0 C,(*) 08ED 3 NOP 2 143 | IN0 D,(*) 10ED 3 NOP 2 144 | IN0 E,(*) 18ED 3 NOP 2 145 | IN0 H,(*) 20ED 3 NOP 2 146 | IN0 L,(*) 28ED 3 NOP 2 147 | 148 | INC (HL) 34 1 NOP 1 149 | INC (IX*) 34DD 3 ZIX 1 150 | INC (IY*) 34FD 3 ZIX 1 151 | INC A 3C 1 NOP 1 152 | INC B 4 1 NOP 1 153 | INC BC 3 1 NOP 1 154 | INC C 0C 1 NOP 1 155 | INC D 14 1 NOP 1 156 | INC DE 13 1 NOP 1 157 | INC E 1C 1 NOP 1 158 | INC H 24 1 NOP 1 159 | INC HL 23 1 NOP 1 160 | INC IX 23DD 2 NOP 1 161 | INC IY 23FD 2 NOP 1 162 | INC L 2C 1 NOP 1 163 | INC SP 33 1 NOP 1 164 | 165 | 166 | IND "" AAED 2 NOP 1 167 | INDR "" BAED 2 NOP 1 168 | INI "" A2ED 2 NOP 1 169 | INIR "" B2ED 2 NOP 1 170 | 171 | JP (HL) E9 1 NOP 1 172 | JP (IX) E9DD 2 NOP 1 173 | JP (IY) E9FD 2 NOP 1 174 | JP C,* DA 3 NOP 1 175 | JP M,* FA 3 NOP 1 176 | JP NC,* D2 3 NOP 1 177 | JP NZ,* C2 3 NOP 1 178 | JP P,* F2 3 NOP 1 179 | JP PE,* EA 3 NOP 1 180 | JP PO,* E2 3 NOP 1 181 | JP Z,* CA 3 NOP 1 182 | JP * C3 3 NOP 1 183 | 184 | JR C,* 38 2 R1 1 185 | JR NC,* 30 2 R1 1 186 | JR NZ,* 20 2 R1 1 187 | JR Z,* 28 2 R1 1 188 | JR * 18 2 R1 1 189 | 190 | LD (BC),A 2 1 NOP 1 191 | LD (DE),A 12 1 NOP 1 192 | LD (HL),A 77 1 NOP 1 193 | LD (HL),B 70 1 NOP 1 194 | LD (HL),C 71 1 NOP 1 195 | LD (HL),D 72 1 NOP 1 196 | LD (HL),E 73 1 NOP 1 197 | LD (HL),H 74 1 NOP 1 198 | LD (HL),L 75 1 NOP 1 199 | LD (HL),* 36 2 NOP 1 200 | LD (IX*),A 77DD 3 ZIX 1 201 | LD (IX*),B 70DD 3 ZIX 1 202 | LD (IX*),C 71DD 3 ZIX 1 203 | LD (IX*),D 72DD 3 ZIX 1 204 | LD (IX*),E 73DD 3 ZIX 1 205 | LD (IX*),H 74DD 3 ZIX 1 206 | LD (IX*),L 75DD 3 ZIX 1 207 | LD (IX*),* 36DD 4 ZIX 1 208 | LD (IY*),A 77FD 3 ZIX 1 209 | LD (IY*),B 70FD 3 ZIX 1 210 | LD (IY*),C 71FD 3 ZIX 1 211 | LD (IY*),D 72FD 3 ZIX 1 212 | LD (IY*),E 73FD 3 ZIX 1 213 | LD (IY*),H 74FD 3 ZIX 1 214 | LD (IY*),L 75FD 3 ZIX 1 215 | LD (IY*),* 36FD 4 ZIX 1 216 | LD (*),A 32 3 NOP 1 217 | LD (*),BC 43ED 4 NOP 1 218 | LD (*),DE 53ED 4 NOP 1 219 | LD (*),HL 22 3 NOP 1 220 | LD (*),IX 22DD 4 NOP 1 221 | LD (*),IY 22FD 4 NOP 1 222 | LD (*),SP 73ED 4 NOP 1 223 | LD A,(BC) 0A 1 NOP 1 224 | LD A,(DE) 1A 1 NOP 1 225 | LD A,(HL) 7E 1 NOP 1 226 | LD A,(IX*) 7EDD 3 ZIX 1 227 | LD A,(IY*) 7EFD 3 ZIX 1 228 | LD A,A 7F 1 NOP 1 229 | LD A,B 78 1 NOP 1 230 | LD A,C 79 1 NOP 1 231 | LD A,D 7A 1 NOP 1 232 | LD A,E 7B 1 NOP 1 233 | LD A,H 7C 1 NOP 1 234 | LD A,I 57ED 2 NOP 1 235 | LD A,L 7D 1 NOP 1 236 | LD A,R 5FED 2 NOP 1 237 | LD A,(*) 3A 3 NOP 1 238 | LD A,* 3E 2 NOP 1 239 | LD B,(HL) 46 1 NOP 1 240 | LD B,(IX*) 46DD 3 ZIX 1 241 | LD B,(IY*) 46FD 3 ZIX 1 242 | LD B,A 47 1 NOP 1 243 | LD B,B 40 1 NOP 1 244 | LD B,C 41 1 NOP 1 245 | LD B,D 42 1 NOP 1 246 | LD B,E 43 1 NOP 1 247 | LD B,H 44 1 NOP 1 248 | LD B,L 45 1 NOP 1 249 | LD B,* 6 2 NOP 1 250 | LD BC,(*) 4BED 4 NOP 1 251 | LD BC,* 1 3 NOP 1 252 | LD C,(HL) 4E 1 NOP 1 253 | LD C,(IX*) 4EDD 3 ZIX 1 254 | LD C,(IY*) 4EFD 3 ZIX 1 255 | LD C,A 4F 1 NOP 1 256 | LD C,B 48 1 NOP 1 257 | LD C,C 49 1 NOP 1 258 | LD C,D 4A 1 NOP 1 259 | LD C,E 4B 1 NOP 1 260 | LD C,H 4C 1 NOP 1 261 | LD C,L 4D 1 NOP 1 262 | LD C,* 0E 2 NOP 1 263 | LD D,(HL) 56 1 NOP 1 264 | LD D,(IX*) 56DD 3 ZIX 1 265 | LD D,(IY*) 56FD 3 ZIX 1 266 | LD D,A 57 1 NOP 1 267 | LD D,B 50 1 NOP 1 268 | LD D,C 51 1 NOP 1 269 | LD D,D 52 1 NOP 1 270 | LD D,E 53 1 NOP 1 271 | LD D,H 54 1 NOP 1 272 | LD D,L 55 1 NOP 1 273 | LD D,* 16 2 NOP 1 274 | LD DE,(*) 5BED 4 NOP 1 275 | LD DE,* 11 3 NOP 1 276 | LD E,(HL) 5E 1 NOP 1 277 | LD E,(IX*) 5EDD 3 ZIX 1 278 | LD E,(IY*) 5EFD 3 ZIX 1 279 | LD E,A 5F 1 NOP 1 280 | LD E,B 58 1 NOP 1 281 | LD E,C 59 1 NOP 1 282 | LD E,D 5A 1 NOP 1 283 | LD E,E 5B 1 NOP 1 284 | LD E,H 5C 1 NOP 1 285 | LD E,L 5D 1 NOP 1 286 | LD E,* 1E 2 NOP 1 287 | LD H,(HL) 66 1 NOP 1 288 | LD H,(IX*) 66DD 3 ZIX 1 289 | LD H,(IY*) 66FD 3 ZIX 1 290 | LD H,A 67 1 NOP 1 291 | LD H,B 60 1 NOP 1 292 | LD H,C 61 1 NOP 1 293 | LD H,D 62 1 NOP 1 294 | LD H,E 63 1 NOP 1 295 | LD H,H 64 1 NOP 1 296 | LD H,L 65 1 NOP 1 297 | LD H,* 26 2 NOP 1 298 | LD HL,(*) 2A 3 NOP 1 299 | LD HL,* 21 3 NOP 1 300 | LD I,A 47ED 2 NOP 1 301 | LD IX,(*) 2ADD 4 NOP 1 302 | LD IX,* 21DD 4 NOP 1 303 | LD IY,(*) 2AFD 4 NOP 1 304 | LD IY,* 21FD 4 NOP 1 305 | LD L,(HL) 6E 1 NOP 1 306 | LD L,(IX*) 6EDD 3 ZIX 1 307 | LD L,(IY*) 6EFD 3 ZIX 1 308 | LD L,A 6F 1 NOP 1 309 | LD L,B 68 1 NOP 1 310 | LD L,C 69 1 NOP 1 311 | LD L,D 6A 1 NOP 1 312 | LD L,E 6B 1 NOP 1 313 | LD L,H 6C 1 NOP 1 314 | LD L,L 6D 1 NOP 1 315 | LD L,* 2E 2 NOP 1 316 | LD R,A 4FED 2 NOP 1 317 | LD SP,(*) 7BED 4 NOP 1 318 | LD SP,HL F9 1 NOP 1 319 | LD SP,IX F9DD 2 NOP 1 320 | LD SP,IY F9FD 2 NOP 1 321 | LD SP,* 31 3 NOP 1 322 | LDD "" A8ED 2 NOP 1 323 | LDDR "" B8ED 2 NOP 1 324 | LDI "" A0ED 2 NOP 1 325 | LDIR "" B0ED 2 NOP 1 326 | NEG "" 44ED 2 NOP 1 327 | NOP "" 0 1 NOP 1 328 | 329 | MLT BC 4CED 2 NOP 2 330 | MLT DE 5CED 2 NOP 2 331 | MLT HL 6CED 2 NOP 2 332 | MLT SP 7CED 2 NOP 2 333 | 334 | OR (HL) B6 1 NOP 1 335 | OR (IX*) B6DD 3 ZIX 1 336 | OR (IY*) B6FD 3 ZIX 1 337 | OR A B7 1 NOP 1 338 | OR B B0 1 NOP 1 339 | OR C B1 1 NOP 1 340 | OR D B2 1 NOP 1 341 | OR E B3 1 NOP 1 342 | OR H B4 1 NOP 1 343 | OR L B5 1 NOP 1 344 | OR * F6 2 NOP 1 345 | 346 | OTDM "" 8BED 2 NOP 2 347 | OTDMR "" 9BED 2 NOP 2 348 | OTDR "" BBED 2 NOP 1 349 | OTIM "" 83ED 2 NOP 2 350 | OTIMR "" 93ED 2 NOP 2 351 | OTIR "" B3ED 2 NOP 1 352 | 353 | OUT (C),A 79ED 2 NOP 1 354 | OUT (C),B 41ED 2 NOP 1 355 | OUT (C),C 49ED 2 NOP 1 356 | OUT (C),D 51ED 2 NOP 1 357 | OUT (C),E 59ED 2 NOP 1 358 | OUT (C),H 61ED 2 NOP 1 359 | OUT (C),L 69ED 2 NOP 1 360 | OUT (*),A D3 2 NOP 1 361 | 362 | OUT0 (*),A 39ED 3 NOP 2 363 | OUT0 (*),B 01ED 3 NOP 2 364 | OUT0 (*),C 09ED 3 NOP 2 365 | OUT0 (*),D 11ED 3 NOP 2 366 | OUT0 (*),E 19ED 3 NOP 2 367 | OUT0 (*),H 21ED 3 NOP 2 368 | OUT0 (*),L 29ED 3 NOP 2 369 | 370 | OUTD "" ABED 2 NOP 1 371 | OUTI "" A3ED 2 NOP 1 372 | 373 | POP AF F1 1 NOP 1 374 | POP BC C1 1 NOP 1 375 | POP DE D1 1 NOP 1 376 | POP HL E1 1 NOP 1 377 | POP IX E1DD 2 NOP 1 378 | POP IY E1FD 2 NOP 1 379 | 380 | PUSH AF F5 1 NOP 1 381 | PUSH BC C5 1 NOP 1 382 | PUSH DE D5 1 NOP 1 383 | PUSH HL E5 1 NOP 1 384 | PUSH IX E5DD 2 NOP 1 385 | PUSH IY E5FD 2 NOP 1 386 | 387 | RES *,(HL) 86CB 2 ZBI T 1 388 | RES *,(IX*) CBDD 4 ZBI T 1 0 8600 389 | RES *,(IY*) CBFD 4 ZBI T 1 0 8600 390 | RES *,A 87CB 2 ZBI T 1 391 | RES *,B 80CB 2 ZBI T 1 392 | RES *,C 81CB 2 ZBI T 1 393 | RES *,D 82CB 2 ZBI T 1 394 | RES *,E 83CB 2 ZBI T 1 395 | RES *,H 84CB 2 ZBI T 1 396 | RES *,L 85CB 2 ZBI T 1 397 | 398 | RET "" C9 1 NOP 1 399 | RET C D8 1 NOP 1 400 | RET M F8 1 NOP 1 401 | RET NC D0 1 NOP 1 402 | RET NZ C0 1 NOP 1 403 | RET P F0 1 NOP 1 404 | RET PE E8 1 NOP 1 405 | RET PO E0 1 NOP 1 406 | RET Z C8 1 NOP 1 407 | RETI "" 4DED 2 NOP 1 408 | RETN "" 45ED 2 NOP 1 409 | 410 | RL (HL) 16CB 2 NOP 1 411 | RL (IX*) CBDD 4 ZIX 1 0 1600 412 | RL (IY*) CBFD 4 ZIX 1 0 1600 413 | RL A 17CB 2 NOP 1 414 | RL B 10CB 2 NOP 1 415 | RL C 11CB 2 NOP 1 416 | RL D 12CB 2 NOP 1 417 | RL E 13CB 2 NOP 1 418 | RL H 14CB 2 NOP 1 419 | RL L 15CB 2 NOP 1 420 | RLA "" 17 1 NOP 1 421 | 422 | RLC (HL) 06CB 2 NOP 1 423 | RLC (IX*) CBDD 4 ZIX 1 0 0600 424 | RLC (IY*) CBFD 4 ZIX 1 0 0600 425 | RLC A 07CB 2 NOP 1 426 | RLC B 00CB 2 NOP 1 427 | RLC C 01CB 2 NOP 1 428 | RLC D 02CB 2 NOP 1 429 | RLC E 03CB 2 NOP 1 430 | RLC H 04CB 2 NOP 1 431 | RLC L 05CB 2 NOP 1 432 | RLCA "" 7 1 NOP 1 433 | RLD "" 6FED 2 NOP 1 434 | 435 | RR (HL) 1ECB 2 NOP 1 436 | RR (IX*) CBDD 4 ZIX 1 0 1E00 437 | RR (IY*) CBFD 4 ZIX 1 0 1E00 438 | RR A 1FCB 2 NOP 1 439 | RR B 18CB 2 NOP 1 440 | RR C 19CB 2 NOP 1 441 | RR D 1ACB 2 NOP 1 442 | RR E 1BCB 2 NOP 1 443 | RR H 1CCB 2 NOP 1 444 | RR L 1DCB 2 NOP 1 445 | RRA "" 1F 1 NOP 1 446 | RRC (HL) 0ECB 2 NOP 1 447 | RRC (IX*) CBDD 4 ZIX 1 0 0E00 448 | RRC (IY*) CBFD 4 ZIX 1 0 0E00 449 | RRC A 0FCB 2 NOP 1 450 | RRC B 08CB 2 NOP 1 451 | RRC C 09CB 2 NOP 1 452 | RRC D 0ACB 2 NOP 1 453 | RRC E 0BCB 2 NOP 1 454 | RRC H 0CCB 2 NOP 1 455 | RRC L 0DCB 2 NOP 1 456 | RRCA "" 0F 1 NOP 1 457 | RRD "" 67ED 2 NOP 1 458 | 459 | RST 00H C7 1 NOP 1 460 | RST 08H CF 1 NOP 1 461 | RST 10H D7 1 NOP 1 462 | RST 18H DF 1 NOP 1 463 | RST 20H E7 1 NOP 1 464 | RST 28H EF 1 NOP 1 465 | RST 30H F7 1 NOP 1 466 | RST 38H FF 1 NOP 1 467 | 468 | SBC A,(HL) 9E 1 NOP 1 469 | SBC A,(IX*) 9EDD 3 ZIX 1 470 | SBC A,(IY*) 9EFD 3 ZIX 1 471 | SBC A,A 9F 1 NOP 1 472 | SBC A,B 98 1 NOP 1 473 | SBC A,C 99 1 NOP 1 474 | SBC A,D 9A 1 NOP 1 475 | SBC A,E 9B 1 NOP 1 476 | SBC A,H 9C 1 NOP 1 477 | SBC A,L 9D 1 NOP 1 478 | SBC HL,BC 42ED 2 NOP 1 479 | SBC HL,DE 52ED 2 NOP 1 480 | SBC HL,HL 62ED 2 NOP 1 481 | SBC HL,SP 72ED 2 NOP 1 482 | SBC A,* DE 2 NOP 1 483 | SCF "" 37 1 NOP 1 484 | 485 | SET *,(HL) C6CB 2 ZBI T 1 486 | SET *,(IX*) CBDD 4 ZBI T 1 0 C600 487 | SET *,(IY*) CBFD 4 ZBI T 1 0 C600 488 | SET *,A C7CB 2 ZBI T 1 489 | SET *,B C0CB 2 ZBI T 1 490 | SET *,C C1CB 2 ZBI T 1 491 | SET *,D C2CB 2 ZBI T 1 492 | SET *,E C3CB 2 ZBI T 1 493 | SET *,H C4CB 2 ZBI T 1 494 | SET *,L C5CB 2 ZBI T 1 495 | 496 | SLA (HL) 26CB 2 NOP 1 497 | SLA (IX*) CBDD 4 ZIX 1 0 2600 498 | SLA (IY*) CBFD 4 ZIX 1 0 2600 499 | SLA A 27CB 2 NOP 1 500 | SLA B 20CB 2 NOP 1 501 | SLA C 21CB 2 NOP 1 502 | SLA D 22CB 2 NOP 1 503 | SLA E 23CB 2 NOP 1 504 | SLA H 24CB 2 NOP 1 505 | SLA L 25CB 2 NOP 1 506 | 507 | SLP "" 76ED 2 NOP 2 508 | 509 | SRA (HL) 2ECB 2 NOP 1 510 | SRA (IX*) CBDD 4 ZIX 1 0 2E00 511 | SRA (IY*) CBFD 4 ZIX 1 0 2E00 512 | SRA A 2FCB 2 NOP 1 513 | SRA B 28CB 2 NOP 1 514 | SRA C 29CB 2 NOP 1 515 | SRA D 2ACB 2 NOP 1 516 | SRA E 2BCB 2 NOP 1 517 | SRA H 2CCB 2 NOP 1 518 | SRA L 2DCB 2 NOP 1 519 | 520 | SRL (HL) 3ECB 2 NOP 1 521 | SRL (IX*) CBDD 4 ZIX 1 0 3E00 522 | SRL (IY*) CBFD 4 ZIX 1 0 3E00 523 | SRL A 3FCB 2 NOP 1 524 | SRL B 38CB 2 NOP 1 525 | SRL C 39CB 2 NOP 1 526 | SRL D 3ACB 2 NOP 1 527 | SRL E 3BCB 2 NOP 1 528 | SRL H 3CCB 2 NOP 1 529 | SRL L 3DCB 2 NOP 1 530 | 531 | SUB (HL) 96 1 NOP 1 532 | SUB (IX*) 96DD 3 ZIX 1 533 | SUB (IY*) 96FD 3 ZIX 1 534 | SUB A 97 1 NOP 1 535 | SUB B 90 1 NOP 1 536 | SUB C 91 1 NOP 1 537 | SUB D 92 1 NOP 1 538 | SUB E 93 1 NOP 1 539 | SUB H 94 1 NOP 1 540 | SUB L 95 1 NOP 1 541 | SUB * D6 2 NOP 1 542 | 543 | TST A 3CED 2 NOP 2 544 | TST B 04ED 2 NOP 2 545 | TST C 0CED 2 NOP 2 546 | TST D 14ED 2 NOP 2 547 | TST E 1CED 2 NOP 2 548 | TST H 24ED 2 NOP 2 549 | TST L 2CED 2 NOP 2 550 | TST (HL) 34ED 2 NOP 2 551 | TST * 64ED 3 NOP 2 552 | 553 | TSTIO * 74ED 3 NOP 2 554 | 555 | XOR (HL) AE 1 NOP 1 556 | XOR (IX*) AEDD 3 ZIX 1 557 | XOR (IY*) AEFD 3 ZIX 1 558 | XOR A AF 1 NOP 1 559 | XOR B A8 1 NOP 1 560 | XOR C A9 1 NOP 1 561 | XOR D AA 1 NOP 1 562 | XOR E AB 1 NOP 1 563 | XOR H AC 1 NOP 1 564 | XOR L AD 1 NOP 1 565 | XOR * EE 2 NOP 1 566 | -------------------------------------------------------------------------------- /z80cpm_vc/z80cpm_emul/z80cpm_emul/z80cpm_emul.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | {94AED0A7-E513-4A23-84DC-7C1F98107E42} 63 | Win32Proj 64 | z80cpm_emul 65 | 10.0.17763.0 66 | 67 | 68 | 69 | Application 70 | true 71 | v140 72 | Unicode 73 | 74 | 75 | Application 76 | false 77 | v140 78 | true 79 | Unicode 80 | 81 | 82 | Application 83 | true 84 | v141 85 | Unicode 86 | 87 | 88 | Application 89 | false 90 | v141 91 | true 92 | Unicode 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | true 114 | 115 | 116 | true 117 | 118 | 119 | false 120 | 121 | 122 | false 123 | 124 | 125 | 126 | 127 | 128 | Level3 129 | Disabled 130 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 131 | ..\..\..\include;%(AdditionalIncludeDirectories) 132 | false 133 | Default 134 | 135 | 136 | Console 137 | true 138 | ..\..\..\lib\x86;%(AdditionalLibraryDirectories) 139 | SDL2.lib;SDL2main.lib;%(AdditionalDependencies) 140 | 141 | 142 | 143 | 144 | 145 | 146 | Level3 147 | Disabled 148 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 149 | ..\..\..\include;%(AdditionalIncludeDirectories) 150 | 151 | 152 | Console 153 | true 154 | %(AdditionalLibraryDirectories) 155 | %(AdditionalDependencies) 156 | 157 | 158 | 159 | 160 | Level3 161 | 162 | 163 | MaxSpeed 164 | true 165 | true 166 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 167 | 168 | 169 | Console 170 | true 171 | true 172 | true 173 | 174 | 175 | 176 | 177 | Level3 178 | 179 | 180 | MaxSpeed 181 | true 182 | true 183 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 184 | ..\..\..\include;%(AdditionalIncludeDirectories) 185 | 186 | 187 | Console 188 | true 189 | true 190 | true 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 201 | 202 | 203 | 204 | 205 | -------------------------------------------------------------------------------- /z80cpm_vc/z80cpm_emul/z80cpm_emul/z80cpm_emul.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | Header Files 79 | 80 | 81 | Header Files 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Header Files 91 | 92 | 93 | Header Files 94 | 95 | 96 | Header Files 97 | 98 | 99 | Header Files 100 | 101 | 102 | Header Files 103 | 104 | 105 | Header Files 106 | 107 | 108 | Header Files 109 | 110 | 111 | Header Files 112 | 113 | 114 | Header Files 115 | 116 | 117 | Header Files 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /z80sbcFiles.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaffa/z80cpm_emulator/7ed59c9e49bd4f223e174ea87746bfabe73761bf/z80sbcFiles.zip -------------------------------------------------------------------------------- /z80sbcFiles/TASM80.TAB: -------------------------------------------------------------------------------- 1 | "TASM Z80 Assembler. " 2 | /**************************************************************************** 3 | /* $Id: tasm80.tab 1.1 1993/07/31 01:12:40 toma Exp $ 4 | /**************************************************************************** 5 | /* This is the instruction set definition table 6 | /* for the Z80 version of TASM. 7 | /* Thomas N. Anderson, Speech Technology Incorporated 8 | /* This table authored and submitted by Carl A. Wall, VE3APY. 9 | /* 10 | /* Class bits assigned as follows: 11 | /* Bit-0 = Z80 (base instruction set) 12 | /* Bit-1 = HD64180 (extended instructions) 13 | /* See TASM manual for info on table structure. 14 | /* 15 | /*INSTR ARGS OP BYTES RULE CLASS SHIFT OR */ 16 | /*-------------------------------------------*/ 17 | 18 | ADC A,(HL) 8E 1 NOP 1 19 | ADC A,(IX*) 8EDD 3 ZIX 1 20 | ADC A,(IY*) 8EFD 3 ZIX 1 21 | ADC A,A 8F 1 NOP 1 22 | ADC A,B 88 1 NOP 1 23 | ADC A,C 89 1 NOP 1 24 | ADC A,D 8A 1 NOP 1 25 | ADC A,E 8B 1 NOP 1 26 | ADC A,H 8C 1 NOP 1 27 | ADC A,L 8D 1 NOP 1 28 | ADC A,* CE 2 NOP 1 29 | ADC HL,BC 4AED 2 NOP 1 30 | ADC HL,DE 5AED 2 NOP 1 31 | ADC HL,HL 6AED 2 NOP 1 32 | ADC HL,SP 7AED 2 NOP 1 33 | 34 | ADD A,(HL) 86 1 NOP 1 35 | ADD A,(IX*) 86DD 3 ZIX 1 36 | ADD A,(IY*) 86FD 3 ZIX 1 37 | ADD A,A 87 1 NOP 1 38 | ADD A,B 80 1 NOP 1 39 | ADD A,C 81 1 NOP 1 40 | ADD A,D 82 1 NOP 1 41 | ADD A,E 83 1 NOP 1 42 | ADD A,H 84 1 NOP 1 43 | ADD A,L 85 1 NOP 1 44 | ADD A,* C6 2 NOP 1 45 | ADD HL,BC 09 1 NOP 1 46 | ADD HL,DE 19 1 NOP 1 47 | ADD HL,HL 29 1 NOP 1 48 | ADD HL,SP 39 1 NOP 1 49 | ADD IX,BC 09DD 2 NOP 1 50 | ADD IX,DE 19DD 2 NOP 1 51 | ADD IX,IX 29DD 2 NOP 1 52 | ADD IX,SP 39DD 2 NOP 1 53 | ADD IY,BC 09FD 2 NOP 1 54 | ADD IY,DE 19FD 2 NOP 1 55 | ADD IY,IY 29FD 2 NOP 1 56 | ADD IY,SP 39FD 2 NOP 1 57 | 58 | AND (HL) A6 1 NOP 1 59 | AND (IX*) A6DD 3 ZIX 1 60 | AND (IY*) A6FD 3 ZIX 1 61 | AND A A7 1 NOP 1 62 | AND B A0 1 NOP 1 63 | AND C A1 1 NOP 1 64 | AND D A2 1 NOP 1 65 | AND E A3 1 NOP 1 66 | AND H A4 1 NOP 1 67 | AND L A5 1 NOP 1 68 | AND * E6 2 NOP 1 69 | 70 | BIT *,(HL) 46CB 2 ZBIT 1 71 | BIT *,(IX*) CBDD 4 ZBIT 1 0 4600 72 | BIT *,(IY*) CBFD 4 ZBIT 1 0 4600 73 | BIT *,A 47CB 2 ZBIT 1 74 | BIT *,B 40CB 2 ZBIT 1 75 | BIT *,C 41CB 2 ZBIT 1 76 | BIT *,D 42CB 2 ZBIT 1 77 | BIT *,E 43CB 2 ZBIT 1 78 | BIT *,H 44CB 2 ZBIT 1 79 | BIT *,L 45CB 2 ZBIT 1 80 | 81 | CALL C,* DC 3 NOP 1 82 | CALL M,* FC 3 NOP 1 83 | CALL NC,* D4 3 NOP 1 84 | CALL NZ,* C4 3 NOP 1 85 | CALL P,* F4 3 NOP 1 86 | CALL PE,* EC 3 NOP 1 87 | CALL PO,* E4 3 NOP 1 88 | CALL Z,* CC 3 NOP 1 89 | CALL * CD 3 NOP 1 90 | 91 | CCF "" 3F 1 NOP 1 92 | 93 | CP (HL) BE 1 NOP 1 94 | CP (IX*) BEDD 3 ZIX 1 95 | CP (IY*) BEFD 3 ZIX 1 96 | CP A BF 1 NOP 1 97 | CP B B8 1 NOP 1 98 | CP C B9 1 NOP 1 99 | CP D BA 1 NOP 1 100 | CP E BB 1 NOP 1 101 | CP H BC 1 NOP 1 102 | CP L BD 1 NOP 1 103 | CP * FE 2 NOP 1 104 | CPD "" A9ED 2 NOP 1 105 | CPDR "" B9ED 2 NOP 1 106 | CPIR "" B1ED 2 NOP 1 107 | CPI "" A1ED 2 NOP 1 108 | CPL "" 2F 1 NOP 1 109 | 110 | DAA "" 27 1 NOP 1 111 | 112 | DEC (HL) 35 1 NOP 1 113 | DEC (IX*) 35DD 3 ZIX 1 114 | DEC (IY*) 35FD 3 ZIX 1 115 | DEC A 3D 1 NOP 1 116 | DEC B 05 1 NOP 1 117 | DEC BC 0B 1 NOP 1 118 | DEC C 0D 1 NOP 1 119 | DEC D 15 1 NOP 1 120 | DEC DE 1B 1 NOP 1 121 | DEC E 1D 1 NOP 1 122 | DEC H 25 1 NOP 1 123 | DEC HL 2B 1 NOP 1 124 | DEC IX 2BDD 2 NOP 1 125 | DEC IY 2BFD 2 NOP 1 126 | DEC L 2D 1 NOP 1 127 | DEC SP 3B 1 NOP 1 128 | DI "" F3 1 NOP 1 129 | DJNZ * 10 2 R1 1 130 | 131 | EI "" FB 1 NOP 1 132 | EX (SP),HL E3 1 NOP 1 133 | EX (SP),IX E3DD 2 NOP 1 134 | EX (SP),IY E3FD 2 NOP 1 135 | EX AF,AF' 08 1 NOP 1 136 | EX DE,HL EB 1 NOP 1 137 | EXX "" D9 1 NOP 1 138 | HALT "" 76 1 NOP 1 139 | 140 | IM 0 46ED 2 NOP 1 141 | IM 1 56ED 2 NOP 1 142 | IM 2 5EED 2 NOP 1 143 | 144 | IN A,(C) 78ED 2 NOP 1 145 | IN B,(C) 40ED 2 NOP 1 146 | IN C,(C) 48ED 2 NOP 1 147 | IN D,(C) 50ED 2 NOP 1 148 | IN E,(C) 58ED 2 NOP 1 149 | IN H,(C) 60ED 2 NOP 1 150 | IN L,(C) 68ED 2 NOP 1 151 | 152 | IN A,(*) DB 2 NOP 1 153 | 154 | IN0 A,(*) 38ED 3 NOP 2 155 | IN0 B,(*) 00ED 3 NOP 2 156 | IN0 C,(*) 08ED 3 NOP 2 157 | IN0 D,(*) 10ED 3 NOP 2 158 | IN0 E,(*) 18ED 3 NOP 2 159 | IN0 H,(*) 20ED 3 NOP 2 160 | IN0 L,(*) 28ED 3 NOP 2 161 | 162 | INC (HL) 34 1 NOP 1 163 | INC (IX*) 34DD 3 ZIX 1 164 | INC (IY*) 34FD 3 ZIX 1 165 | INC A 3C 1 NOP 1 166 | INC B 04 1 NOP 1 167 | INC BC 03 1 NOP 1 168 | INC C 0C 1 NOP 1 169 | INC D 14 1 NOP 1 170 | INC DE 13 1 NOP 1 171 | INC E 1C 1 NOP 1 172 | INC H 24 1 NOP 1 173 | INC HL 23 1 NOP 1 174 | INC IX 23DD 2 NOP 1 175 | INC IY 23FD 2 NOP 1 176 | INC L 2C 1 NOP 1 177 | INC SP 33 1 NOP 1 178 | 179 | 180 | IND "" AAED 2 NOP 1 181 | INDR "" BAED 2 NOP 1 182 | INI "" A2ED 2 NOP 1 183 | INIR "" B2ED 2 NOP 1 184 | 185 | JP (HL) E9 1 NOP 1 186 | JP (IX) E9DD 2 NOP 1 187 | JP (IY) E9FD 2 NOP 1 188 | JP C,* DA 3 NOP 1 189 | JP M,* FA 3 NOP 1 190 | JP NC,* D2 3 NOP 1 191 | JP NZ,* C2 3 NOP 1 192 | JP P,* F2 3 NOP 1 193 | JP PE,* EA 3 NOP 1 194 | JP PO,* E2 3 NOP 1 195 | JP Z,* CA 3 NOP 1 196 | JP * C3 3 NOP 1 197 | 198 | JR C,* 38 2 R1 1 199 | JR NC,* 30 2 R1 1 200 | JR NZ,* 20 2 R1 1 201 | JR Z,* 28 2 R1 1 202 | JR * 18 2 R1 1 203 | 204 | LD (BC),A 02 1 NOP 1 205 | LD (DE),A 12 1 NOP 1 206 | LD (HL),A 77 1 NOP 1 207 | LD (HL),B 70 1 NOP 1 208 | LD (HL),C 71 1 NOP 1 209 | LD (HL),D 72 1 NOP 1 210 | LD (HL),E 73 1 NOP 1 211 | LD (HL),H 74 1 NOP 1 212 | LD (HL),L 75 1 NOP 1 213 | LD (HL),* 36 2 NOP 1 214 | LD (IX*),A 77DD 3 ZIX 1 215 | LD (IX*),B 70DD 3 ZIX 1 216 | LD (IX*),C 71DD 3 ZIX 1 217 | LD (IX*),D 72DD 3 ZIX 1 218 | LD (IX*),E 73DD 3 ZIX 1 219 | LD (IX*),H 74DD 3 ZIX 1 220 | LD (IX*),L 75DD 3 ZIX 1 221 | LD (IX*),* 36DD 4 ZIX 1 222 | LD (IY*),A 77FD 3 ZIX 1 223 | LD (IY*),B 70FD 3 ZIX 1 224 | LD (IY*),C 71FD 3 ZIX 1 225 | LD (IY*),D 72FD 3 ZIX 1 226 | LD (IY*),E 73FD 3 ZIX 1 227 | LD (IY*),H 74FD 3 ZIX 1 228 | LD (IY*),L 75FD 3 ZIX 1 229 | LD (IY*),* 36FD 4 ZIX 1 230 | LD (*),A 32 3 NOP 1 231 | LD (*),BC 43ED 4 NOP 1 232 | LD (*),DE 53ED 4 NOP 1 233 | LD (*),HL 22 3 NOP 1 234 | LD (*),IX 22DD 4 NOP 1 235 | LD (*),IY 22FD 4 NOP 1 236 | LD (*),SP 73ED 4 NOP 1 237 | LD A,(BC) 0A 1 NOP 1 238 | LD A,(DE) 1A 1 NOP 1 239 | LD A,(HL) 7E 1 NOP 1 240 | LD A,(IX*) 7EDD 3 ZIX 1 241 | LD A,(IY*) 7EFD 3 ZIX 1 242 | LD A,A 7F 1 NOP 1 243 | LD A,B 78 1 NOP 1 244 | LD A,C 79 1 NOP 1 245 | LD A,D 7A 1 NOP 1 246 | LD A,E 7B 1 NOP 1 247 | LD A,H 7C 1 NOP 1 248 | LD A,I 57ED 2 NOP 1 249 | LD A,L 7D 1 NOP 1 250 | LD A,R 5FED 2 NOP 1 251 | LD A,(*) 3A 3 NOP 1 252 | LD A,* 3E 2 NOP 1 253 | LD B,(HL) 46 1 NOP 1 254 | LD B,(IX*) 46DD 3 ZIX 1 255 | LD B,(IY*) 46FD 3 ZIX 1 256 | LD B,A 47 1 NOP 1 257 | LD B,B 40 1 NOP 1 258 | LD B,C 41 1 NOP 1 259 | LD B,D 42 1 NOP 1 260 | LD B,E 43 1 NOP 1 261 | LD B,H 44 1 NOP 1 262 | LD B,L 45 1 NOP 1 263 | LD B,* 06 2 NOP 1 264 | LD BC,(*) 4BED 4 NOP 1 265 | LD BC,* 01 3 NOP 1 266 | LD C,(HL) 4E 1 NOP 1 267 | LD C,(IX*) 4EDD 3 ZIX 1 268 | LD C,(IY*) 4EFD 3 ZIX 1 269 | LD C,A 4F 1 NOP 1 270 | LD C,B 48 1 NOP 1 271 | LD C,C 49 1 NOP 1 272 | LD C,D 4A 1 NOP 1 273 | LD C,E 4B 1 NOP 1 274 | LD C,H 4C 1 NOP 1 275 | LD C,L 4D 1 NOP 1 276 | LD C,* 0E 2 NOP 1 277 | LD D,(HL) 56 1 NOP 1 278 | LD D,(IX*) 56DD 3 ZIX 1 279 | LD D,(IY*) 56FD 3 ZIX 1 280 | LD D,A 57 1 NOP 1 281 | LD D,B 50 1 NOP 1 282 | LD D,C 51 1 NOP 1 283 | LD D,D 52 1 NOP 1 284 | LD D,E 53 1 NOP 1 285 | LD D,H 54 1 NOP 1 286 | LD D,L 55 1 NOP 1 287 | LD D,* 16 2 NOP 1 288 | LD DE,(*) 5BED 4 NOP 1 289 | LD DE,* 11 3 NOP 1 290 | LD E,(HL) 5E 1 NOP 1 291 | LD E,(IX*) 5EDD 3 ZIX 1 292 | LD E,(IY*) 5EFD 3 ZIX 1 293 | LD E,A 5F 1 NOP 1 294 | LD E,B 58 1 NOP 1 295 | LD E,C 59 1 NOP 1 296 | LD E,D 5A 1 NOP 1 297 | LD E,E 5B 1 NOP 1 298 | LD E,H 5C 1 NOP 1 299 | LD E,L 5D 1 NOP 1 300 | LD E,* 1E 2 NOP 1 301 | LD H,(HL) 66 1 NOP 1 302 | LD H,(IX*) 66DD 3 ZIX 1 303 | LD H,(IY*) 66FD 3 ZIX 1 304 | LD H,A 67 1 NOP 1 305 | LD H,B 60 1 NOP 1 306 | LD H,C 61 1 NOP 1 307 | LD H,D 62 1 NOP 1 308 | LD H,E 63 1 NOP 1 309 | LD H,H 64 1 NOP 1 310 | LD H,L 65 1 NOP 1 311 | LD H,* 26 2 NOP 1 312 | LD HL,(*) 2A 3 NOP 1 313 | LD HL,* 21 3 NOP 1 314 | LD I,A 47ED 2 NOP 1 315 | LD IX,(*) 2ADD 4 NOP 1 316 | LD IX,* 21DD 4 NOP 1 317 | LD IY,(*) 2AFD 4 NOP 1 318 | LD IY,* 21FD 4 NOP 1 319 | LD L,(HL) 6E 1 NOP 1 320 | LD L,(IX*) 6EDD 3 ZIX 1 321 | LD L,(IY*) 6EFD 3 ZIX 1 322 | LD L,A 6F 1 NOP 1 323 | LD L,B 68 1 NOP 1 324 | LD L,C 69 1 NOP 1 325 | LD L,D 6A 1 NOP 1 326 | LD L,E 6B 1 NOP 1 327 | LD L,H 6C 1 NOP 1 328 | LD L,L 6D 1 NOP 1 329 | LD L,* 2E 2 NOP 1 330 | LD R,A 4FED 2 NOP 1 331 | LD SP,(*) 7BED 4 NOP 1 332 | LD SP,HL F9 1 NOP 1 333 | LD SP,IX F9DD 2 NOP 1 334 | LD SP,IY F9FD 2 NOP 1 335 | LD SP,* 31 3 NOP 1 336 | LDD "" A8ED 2 NOP 1 337 | LDDR "" B8ED 2 NOP 1 338 | LDI "" A0ED 2 NOP 1 339 | LDIR "" B0ED 2 NOP 1 340 | NEG "" 44ED 2 NOP 1 341 | NOP "" 00 1 NOP 1 342 | 343 | MLT BC 4CED 2 NOP 2 344 | MLT DE 5CED 2 NOP 2 345 | MLT HL 6CED 2 NOP 2 346 | MLT SP 7CED 2 NOP 2 347 | 348 | OR (HL) B6 1 NOP 1 349 | OR (IX*) B6DD 3 ZIX 1 350 | OR (IY*) B6FD 3 ZIX 1 351 | OR A B7 1 NOP 1 352 | OR B B0 1 NOP 1 353 | OR C B1 1 NOP 1 354 | OR D B2 1 NOP 1 355 | OR E B3 1 NOP 1 356 | OR H B4 1 NOP 1 357 | OR L B5 1 NOP 1 358 | OR * F6 2 NOP 1 359 | 360 | OTDM "" 8BED 2 NOP 2 361 | OTDMR "" 9BED 2 NOP 2 362 | OTDR "" BBED 2 NOP 1 363 | OTIM "" 83ED 2 NOP 2 364 | OTIMR "" 93ED 2 NOP 2 365 | OTIR "" B3ED 2 NOP 1 366 | 367 | OUT (C),A 79ED 2 NOP 1 368 | OUT (C),B 41ED 2 NOP 1 369 | OUT (C),C 49ED 2 NOP 1 370 | OUT (C),D 51ED 2 NOP 1 371 | OUT (C),E 59ED 2 NOP 1 372 | OUT (C),H 61ED 2 NOP 1 373 | OUT (C),L 69ED 2 NOP 1 374 | OUT (*),A D3 2 NOP 1 375 | 376 | OUT0 (*),A 39ED 3 NOP 2 377 | OUT0 (*),B 01ED 3 NOP 2 378 | OUT0 (*),C 09ED 3 NOP 2 379 | OUT0 (*),D 11ED 3 NOP 2 380 | OUT0 (*),E 19ED 3 NOP 2 381 | OUT0 (*),H 21ED 3 NOP 2 382 | OUT0 (*),L 29ED 3 NOP 2 383 | 384 | OUTD "" ABED 2 NOP 1 385 | OUTI "" A3ED 2 NOP 1 386 | 387 | POP AF F1 1 NOP 1 388 | POP BC C1 1 NOP 1 389 | POP DE D1 1 NOP 1 390 | POP HL E1 1 NOP 1 391 | POP IX E1DD 2 NOP 1 392 | POP IY E1FD 2 NOP 1 393 | 394 | PUSH AF F5 1 NOP 1 395 | PUSH BC C5 1 NOP 1 396 | PUSH DE D5 1 NOP 1 397 | PUSH HL E5 1 NOP 1 398 | PUSH IX E5DD 2 NOP 1 399 | PUSH IY E5FD 2 NOP 1 400 | 401 | RES *,(HL) 86CB 2 ZBIT 1 402 | RES *,(IX*) CBDD 4 ZBIT 1 0 8600 403 | RES *,(IY*) CBFD 4 ZBIT 1 0 8600 404 | RES *,A 87CB 2 ZBIT 1 405 | RES *,B 80CB 2 ZBIT 1 406 | RES *,C 81CB 2 ZBIT 1 407 | RES *,D 82CB 2 ZBIT 1 408 | RES *,E 83CB 2 ZBIT 1 409 | RES *,H 84CB 2 ZBIT 1 410 | RES *,L 85CB 2 ZBIT 1 411 | 412 | RET "" C9 1 NOP 1 413 | RET C D8 1 NOP 1 414 | RET M F8 1 NOP 1 415 | RET NC D0 1 NOP 1 416 | RET NZ C0 1 NOP 1 417 | RET P F0 1 NOP 1 418 | RET PE E8 1 NOP 1 419 | RET PO E0 1 NOP 1 420 | RET Z C8 1 NOP 1 421 | RETI "" 4DED 2 NOP 1 422 | RETN "" 45ED 2 NOP 1 423 | 424 | RL (HL) 16CB 2 NOP 1 425 | RL (IX*) CBDD 4 ZIX 1 0 1600 426 | RL (IY*) CBFD 4 ZIX 1 0 1600 427 | RL A 17CB 2 NOP 1 428 | RL B 10CB 2 NOP 1 429 | RL C 11CB 2 NOP 1 430 | RL D 12CB 2 NOP 1 431 | RL E 13CB 2 NOP 1 432 | RL H 14CB 2 NOP 1 433 | RL L 15CB 2 NOP 1 434 | RLA "" 17 1 NOP 1 435 | 436 | RLC (HL) 06CB 2 NOP 1 437 | RLC (IX*) CBDD 4 ZIX 1 0 0600 438 | RLC (IY*) CBFD 4 ZIX 1 0 0600 439 | RLC A 07CB 2 NOP 1 440 | RLC B 00CB 2 NOP 1 441 | RLC C 01CB 2 NOP 1 442 | RLC D 02CB 2 NOP 1 443 | RLC E 03CB 2 NOP 1 444 | RLC H 04CB 2 NOP 1 445 | RLC L 05CB 2 NOP 1 446 | RLCA "" 07 1 NOP 1 447 | RLD "" 6FED 2 NOP 1 448 | 449 | RR (HL) 1ECB 2 NOP 1 450 | RR (IX*) CBDD 4 ZIX 1 0 1E00 451 | RR (IY*) CBFD 4 ZIX 1 0 1E00 452 | RR A 1FCB 2 NOP 1 453 | RR B 18CB 2 NOP 1 454 | RR C 19CB 2 NOP 1 455 | RR D 1ACB 2 NOP 1 456 | RR E 1BCB 2 NOP 1 457 | RR H 1CCB 2 NOP 1 458 | RR L 1DCB 2 NOP 1 459 | RRA "" 1F 1 NOP 1 460 | RRC (HL) 0ECB 2 NOP 1 461 | RRC (IX*) CBDD 4 ZIX 1 0 0E00 462 | RRC (IY*) CBFD 4 ZIX 1 0 0E00 463 | RRC A 0FCB 2 NOP 1 464 | RRC B 08CB 2 NOP 1 465 | RRC C 09CB 2 NOP 1 466 | RRC D 0ACB 2 NOP 1 467 | RRC E 0BCB 2 NOP 1 468 | RRC H 0CCB 2 NOP 1 469 | RRC L 0DCB 2 NOP 1 470 | RRCA "" 0F 1 NOP 1 471 | RRD "" 67ED 2 NOP 1 472 | 473 | RST 00H C7 1 NOP 1 474 | RST 08H CF 1 NOP 1 475 | RST 10H D7 1 NOP 1 476 | RST 18H DF 1 NOP 1 477 | RST 20H E7 1 NOP 1 478 | RST 28H EF 1 NOP 1 479 | RST 30H F7 1 NOP 1 480 | RST 38H FF 1 NOP 1 481 | 482 | SBC A,(HL) 9E 1 NOP 1 483 | SBC A,(IX*) 9EDD 3 ZIX 1 484 | SBC A,(IY*) 9EFD 3 ZIX 1 485 | SBC A,A 9F 1 NOP 1 486 | SBC A,B 98 1 NOP 1 487 | SBC A,C 99 1 NOP 1 488 | SBC A,D 9A 1 NOP 1 489 | SBC A,E 9B 1 NOP 1 490 | SBC A,H 9C 1 NOP 1 491 | SBC A,L 9D 1 NOP 1 492 | SBC HL,BC 42ED 2 NOP 1 493 | SBC HL,DE 52ED 2 NOP 1 494 | SBC HL,HL 62ED 2 NOP 1 495 | SBC HL,SP 72ED 2 NOP 1 496 | SBC A,* DE 2 NOP 1 497 | SCF "" 37 1 NOP 1 498 | 499 | SET *,(HL) C6CB 2 ZBIT 1 500 | SET *,(IX*) CBDD 4 ZBIT 1 0 C600 501 | SET *,(IY*) CBFD 4 ZBIT 1 0 C600 502 | SET *,A C7CB 2 ZBIT 1 503 | SET *,B C0CB 2 ZBIT 1 504 | SET *,C C1CB 2 ZBIT 1 505 | SET *,D C2CB 2 ZBIT 1 506 | SET *,E C3CB 2 ZBIT 1 507 | SET *,H C4CB 2 ZBIT 1 508 | SET *,L C5CB 2 ZBIT 1 509 | 510 | SLA (HL) 26CB 2 NOP 1 511 | SLA (IX*) CBDD 4 ZIX 1 0 2600 512 | SLA (IY*) CBFD 4 ZIX 1 0 2600 513 | SLA A 27CB 2 NOP 1 514 | SLA B 20CB 2 NOP 1 515 | SLA C 21CB 2 NOP 1 516 | SLA D 22CB 2 NOP 1 517 | SLA E 23CB 2 NOP 1 518 | SLA H 24CB 2 NOP 1 519 | SLA L 25CB 2 NOP 1 520 | 521 | SLP "" 76ED 2 NOP 2 522 | 523 | SRA (HL) 2ECB 2 NOP 1 524 | SRA (IX*) CBDD 4 ZIX 1 0 2E00 525 | SRA (IY*) CBFD 4 ZIX 1 0 2E00 526 | SRA A 2FCB 2 NOP 1 527 | SRA B 28CB 2 NOP 1 528 | SRA C 29CB 2 NOP 1 529 | SRA D 2ACB 2 NOP 1 530 | SRA E 2BCB 2 NOP 1 531 | SRA H 2CCB 2 NOP 1 532 | SRA L 2DCB 2 NOP 1 533 | 534 | SRL (HL) 3ECB 2 NOP 1 535 | SRL (IX*) CBDD 4 ZIX 1 0 3E00 536 | SRL (IY*) CBFD 4 ZIX 1 0 3E00 537 | SRL A 3FCB 2 NOP 1 538 | SRL B 38CB 2 NOP 1 539 | SRL C 39CB 2 NOP 1 540 | SRL D 3ACB 2 NOP 1 541 | SRL E 3BCB 2 NOP 1 542 | SRL H 3CCB 2 NOP 1 543 | SRL L 3DCB 2 NOP 1 544 | 545 | SUB (HL) 96 1 NOP 1 546 | SUB (IX*) 96DD 3 ZIX 1 547 | SUB (IY*) 96FD 3 ZIX 1 548 | SUB A 97 1 NOP 1 549 | SUB B 90 1 NOP 1 550 | SUB C 91 1 NOP 1 551 | SUB D 92 1 NOP 1 552 | SUB E 93 1 NOP 1 553 | SUB H 94 1 NOP 1 554 | SUB L 95 1 NOP 1 555 | SUB * D6 2 NOP 1 556 | 557 | TST A 3CED 2 NOP 2 558 | TST B 04ED 2 NOP 2 559 | TST C 0CED 2 NOP 2 560 | TST D 14ED 2 NOP 2 561 | TST E 1CED 2 NOP 2 562 | TST H 24ED 2 NOP 2 563 | TST L 2CED 2 NOP 2 564 | TST (HL) 34ED 2 NOP 2 565 | TST * 64ED 3 NOP 2 566 | 567 | TSTIO * 74ED 3 NOP 2 568 | 569 | XOR (HL) AE 1 NOP 1 570 | XOR (IX*) AEDD 3 ZIX 1 571 | XOR (IY*) AEFD 3 ZIX 1 572 | XOR A AF 1 NOP 1 573 | XOR B A8 1 NOP 1 574 | XOR C A9 1 NOP 1 575 | XOR D AA 1 NOP 1 576 | XOR E AB 1 NOP 1 577 | XOR H AC 1 NOP 1 578 | XOR L AD 1 NOP 1 579 | XOR * EE 2 NOP 1 580 | -------------------------------------------------------------------------------- /z80sbcFiles/TASM_RELNOTES.TXT: -------------------------------------------------------------------------------- 1 | TASM RELEASE NOTES 2 | 3 | RELEASE DATE/VERSION DESCRIPTION 4 | ----------------------------------------------------------------------- 5 | 10/01/85 Version 2.0 First version with external table def files. 6 | 7 | 01/01/86 Version 2.1 Added '*=' and '=' directives as 8 | alternatives to .ORG and .EQU (for 9 | more complete MOS Technology compatibility). 10 | Enhanced parsing algorithm so it can 11 | deal with more than one variable expression. 12 | Added -d option 13 | 14 | 02/14/86 Version 2.2 Modified so instruction set definition 15 | tables don't need to be compiled in. 16 | Added 8051 tables. 17 | Increased the number of labels allowed. 18 | 19 | 03/31/87 Version 2.3 Fixed bug that prevented location 0xffff 20 | from being used and written to object file. 21 | Most changes in wrtobj() and pr_hextab(). 22 | 23 | 05/01/87 Version 2.4 Added multiple byte opcode support. 24 | Added shift/or operation capability to 25 | args from instruction set definition table. 26 | Converted to MS C version 3.0 27 | Added hashing to instruction set table 28 | lookups to speed up. 29 | 30 | 11/01/87 Version 2.5 Added DB and DW directives. 31 | Added escape capability in TEXT strings. 32 | Fixed inst_lookup function to treat the 33 | multiple wild card case a little better 34 | Added 8080/8085 and Z80 tables. 35 | Added sorting on label table. 36 | Increased size of read buffer. 37 | Speed enhancements. 38 | Added DEFCONT (macro continuation) directive. 39 | Converted to Microsoft C 5.0 compiler. 40 | Added 6805 table (and related modops). 41 | Added Z80 bit modop. 42 | Minor speed up. 43 | Fixed bug that enters infinite loop 44 | when a macro invocation has no closing paren. 45 | Added some three arg MODOPs. 46 | 47 | 8/15/88 Version 2.6.1 Added CODES/NOCODES directives 48 | Fixed bug preventing directives in multiple 49 | statement lines. 50 | 2.6.2 Added COMB_NIBBLE and COMB_NIBBLE_SWAP MODOPS 51 | 52 | 2/1/89 Version 2.7 Removed ad hoc heap and now use malloc() 53 | Added MSFIRST and LSFIRST directives. 54 | Added EXPORT directive. 55 | Added symbol table file (-s flag). 56 | Added NSEG/CSEG/BSEG/DSEG/XSEG directives 57 | and the SYM/AVSYM directives to support 58 | the Avocet avsim51 simulator. 59 | Added support for TMS320. 60 | Added -r flag to set read buffer size. 61 | Converted expression evaluation from 62 | signed 16 bit to signed 32 bit (enabling 63 | apparent ability to use signed or unsigned 64 | 16 bit values). 65 | 66 | 4/20/89 Version 2.7.1 Return 0x20000 for undefined labels so that 67 | (label+x) type stuff won't confuse zero 68 | page addressing. 69 | Added duplicate label error message on pass 1. 70 | 71 | 6/20/89 Version 2.7.2 Improved macro expansion capability. 72 | No expansion in comments. 73 | Context sensitive identifiers. 74 | Revised exit codes. 75 | 76 | 6/27/89 Version 2.7.3 Added -a flag for strict error checking: 77 | (1) No outer parens around expressions. 78 | (2) Error message if unused argbytes remain 79 | (3) Duplicate labels 80 | Fixed so ']' can terminate expressions. 81 | Removed parse() from tasm.c 82 | 83 | 8/19/89 Version 2.7.4 Added Motorola hex object format. 84 | Fixed bug that complained when \ immediately 85 | followed a opcode with no args. 86 | Slightly improved error reporting (Errorbuf). 87 | 88 | 10/31/89 Version 2.7.5 Added TMS7000 support. 89 | Fixed argv[] bug (only dimensioned to 10 in pass1. 90 | 91 | 12/23/89 Version 2.7.6 Improved handling of % (modulo vs binary 92 | prefix ambiguity). 93 | Fixed list so lines with more than 94 | 6 bytes go on second line. 95 | 96 | 03/04/90 Version 2.7.7 Fixed bug that left off 2 bytes if ORG 97 | went backwards and all 64K was used. 98 | Added a command line option to ignore 99 | case on labels. 100 | Added a couple MODOP rules for TMS9900. 101 | Allow double quoted text strings for BYTE. 102 | 103 | 04/15/90 Version 2.7.8 Fixed expression evaluator bug (paren popping) 104 | and changed expression evaluator to a more 105 | conventional left to right evaluation order. 106 | Added TURBOC ifdef's (from Lance Jump). 107 | 108 | 08/20/90 Version 2.8 Primarily a documentation update. 109 | Added error check for AJMP/ACALL off of 110 | current 2K block (8051). 111 | 112 | 10/15/90 Version 2.8.1 Minor speed up in label searching. 113 | Fixed word addressing for TMS320 114 | Version 2.8.2 Local labels. 115 | More label table format options (long form 116 | suppress local labels). 117 | 118 | 11/30/90 Version 2.8.3 Turbo C conversion. 119 | DS directive added. 120 | 121 | 12/27/90 Version 2.8.4 Added COMMENTCHAR directive to change the 122 | comment indicator in the first column. 123 | This was done to support the assembly 124 | files from the small C compiler (sc11) 125 | for the 68CH11. 126 | 127 | 02/14/91 Version 2.8.5 Added LOCALLABELCHAR directive to 128 | override the default "_" as the 129 | prefix for local labels. 130 | 131 | 03/18/91 Version 2.8.6 Added some MODOPs in support of TMS320C25 132 | 133 | 04/20/91 Version 2.8.7 Fixed sign extend bug in CSWAP modop. 134 | Increased MAXLABS to 10000 for big version. 135 | 136 | 05/05/91 Version 2.8.8 Fixed pointer bug in debug output in sort_labels(). 137 | 138 | 05/20/91 Version 2.9 TMS320C25 table along with some MODOP enhancements 139 | for it. 140 | TASMTABS.DOC updated (but not TASM.DOC) 141 | 142 | 08/09/91 Version 2.9.1 Nested conditionals. 143 | 144 | 04/01/92 Version 2.9.2 Fixed long label clobber problem in 145 | find_label() and save_label. Syntax 146 | errors could result in a comment line 147 | after an instruction being lumped together 148 | with a label resulting in a long label. 149 | The label functions were not testing for 150 | labels that exceed the specified size. 151 | Added CHK directive. 152 | Added REL3 MODOD to support uPD75xxx. 153 | Delinting and more ANSIfication. 154 | Modifications due to feedback from B Provo: 155 | Added FILL directive. 156 | Allow multiple labels for EXPORT directive. 157 | Allow address with END directive. 158 | TASM.DOC update 159 | 160 | 11/25/92 Version 2.9.3 Improved error reporting for mismatched quotes. 161 | Disallow the single quote character constants. 162 | Convert to BCC++ 3.1 163 | Provide filename,linenum on all error messages. 164 | Modify format of error messages for compatibility 165 | with the Brief editor. 166 | Added ECHO directive to send output to console. 167 | Performance improvements in macro processing. 168 | "Type Safe" conversion (compatible with C++). 169 | Improved error reporting for imbalanced ifdefs. 170 | 171 | 172 | 01/29/93 Version 2.9.4 Added rules for 8096 (I1,I2,I3,I4,I5,I6). 173 | Generate error message on forward reference 174 | in EQUate statements. 175 | Eliminated -a option for enabling the detection 176 | of branches of 2K page for 8051. This 177 | is now built into the table. 178 | Allow white space in double quotes for BYTE 179 | directive. This previously worked for TEXT, 180 | but not BYTE. 181 | Fixed defect with Z80 4 byte indexed instructions. 182 | Fixed macro defect. If the macro definition has 183 | args but the invocation does not some garbage 184 | gets expanded into the source line. 185 | Z80 OTDR opcode was incorrect. 186 | Z80 IN0/OUT0/INA instructions did not require 187 | the parens around the args. 188 | Some experimental support for windows verson of TASM. 189 | 190 | 10/24/93 Version 3.0 Documentation update. TASM.DOC, TASMTABS.DOC 191 | and RELNOTES.DOC updated, but the functionality 192 | remains unchanged from version 2.9.4. 193 | 194 | 06/16/94 Version 3.0.1 SPR 1006: Multiple macros on the same line 195 | SPR 1007: -c with >8000h bytes used goes bonkers 196 | SPR 1009: waddr correction for BLOCK/DS 197 | SPR 1011: Escaped quotes in TEXT 198 | 199 |  -------------------------------------------------------------------------------- /z80sbcFiles/_ASSEMBLE.BAT: -------------------------------------------------------------------------------- 1 | tasm -80 source\basic.asm hexFiles\basic.hex 2 | tasm -80 source\monitor.asm hexFiles\monitor.hex 3 | tasm -80 source\cbios64.asm hexFiles\cbios64.hex 4 | tasm -80 source\cbios128.asm hexFiles\cbios128.hex 5 | tasm -80 source\cpm22.asm hexFiles\cpm22.hex 6 | tasm -80 source\form64.asm hexFiles\form64.hex 7 | tasm -80 source\form128.asm hexFiles\form128.hex 8 | tasm -80 source\putsys.asm hexFiles\putsys.hex 9 | tasm -80 source\download.asm hexFiles\download.hex 10 | 11 | pause 12 | -------------------------------------------------------------------------------- /z80sbcFiles/source/download.asm: -------------------------------------------------------------------------------- 1 | ;================================================================================== 2 | ; Contents of this file are copyright Grant Searle 3 | ; HEX routine from Joel Owens. 4 | ; 5 | ; You have permission to use this for NON COMMERCIAL USE ONLY 6 | ; If you wish to use it elsewhere, please include an acknowledgement to myself. 7 | ; 8 | ; http://searle.hostei.com/grant/index.html 9 | ; 10 | ; eMail: home.micros01@btinternet.com 11 | ; 12 | ; If the above don't work, please perform an Internet search to see if I have 13 | ; updated the web page hosting service. 14 | ; 15 | ;================================================================================== 16 | 17 | TPA .EQU 100H 18 | REBOOT .EQU 0H 19 | BDOS .EQU 5H 20 | CONIO .EQU 6 21 | CONINP .EQU 1 22 | CONOUT .EQU 2 23 | PSTRING .EQU 9 24 | MAKEF .EQU 22 25 | CLOSEF .EQU 16 26 | WRITES .EQU 21 27 | DELF .EQU 19 28 | SETUSR .EQU 32 29 | 30 | CR .EQU 0DH 31 | LF .EQU 0AH 32 | 33 | FCB .EQU 05CH 34 | BUFF .EQU 080H 35 | 36 | .ORG TPA 37 | 38 | 39 | LD A,0 40 | LD (buffPos),A 41 | LD (checkSum),A 42 | LD (byteCount),A 43 | LD (printCount),A 44 | LD HL,BUFF 45 | LD (buffPtr),HL 46 | 47 | 48 | WAITLT: CALL GETCHR 49 | CP 'U' 50 | JP Z,SETUSER 51 | CP ':' 52 | JR NZ,WAITLT 53 | 54 | 55 | LD C,DELF 56 | LD DE,FCB 57 | CALL BDOS 58 | 59 | LD C,MAKEF 60 | LD DE,FCB 61 | CALL BDOS 62 | 63 | GETHEX: 64 | CALL GETCHR 65 | CP '>' 66 | JR Z,CLOSE 67 | LD B,A 68 | PUSH BC 69 | CALL GETCHR 70 | POP BC 71 | LD C,A 72 | 73 | CALL BCTOA 74 | 75 | LD B,A 76 | LD A,(checkSum) 77 | ADD A,B 78 | LD (checkSum),A 79 | LD A,(byteCount) 80 | INC A 81 | LD (byteCount),A 82 | 83 | LD A,B 84 | 85 | LD HL,(buffPtr) 86 | 87 | LD (HL),A 88 | INC HL 89 | LD (buffPtr),HL 90 | 91 | LD A,(buffPos) 92 | INC A 93 | LD (buffPos),A 94 | CP 80H 95 | 96 | JR NZ,NOWRITE 97 | 98 | LD C,WRITES 99 | LD DE,FCB 100 | CALL BDOS 101 | LD A,'.' 102 | CALL PUTCHR 103 | 104 | ; New line every 8K (64 dots) 105 | LD A,(printCount) 106 | INC A 107 | CP 64 108 | JR NZ,noCRLF 109 | LD (printCount),A 110 | LD A,CR 111 | CALL PUTCHR 112 | LD A,LF 113 | CALL PUTCHR 114 | LD A,0 115 | noCRLF: LD (printCount),A 116 | 117 | LD HL,BUFF 118 | LD (buffPtr),HL 119 | 120 | LD A,0 121 | LD (buffPos),A 122 | NOWRITE: 123 | JR GETHEX 124 | 125 | 126 | CLOSE: 127 | 128 | LD A,(buffPos) 129 | CP 0 130 | JR Z,NOWRITE2 131 | 132 | LD C,WRITES 133 | LD DE,FCB 134 | CALL BDOS 135 | LD A,'.' 136 | CALL PUTCHR 137 | 138 | NOWRITE2: 139 | LD C,CLOSEF 140 | LD DE,FCB 141 | CALL BDOS 142 | 143 | ; Byte count (lower 8 bits) 144 | CALL GETCHR 145 | LD B,A 146 | PUSH BC 147 | CALL GETCHR 148 | POP BC 149 | LD C,A 150 | 151 | CALL BCTOA 152 | LD B,A 153 | LD A,(byteCount) 154 | SUB B 155 | CP 0 156 | JR Z,byteCountOK 157 | 158 | LD A,CR 159 | CALL PUTCHR 160 | LD A,LF 161 | CALL PUTCHR 162 | 163 | LD DE,countErrMess 164 | LD C,PSTRING 165 | CALL BDOS 166 | 167 | ; Sink remaining 2 bytes 168 | CALL GETCHR 169 | CALL GETCHR 170 | 171 | JR FINISH 172 | 173 | byteCountOK: 174 | 175 | ; Checksum 176 | CALL GETCHR 177 | LD B,A 178 | PUSH BC 179 | CALL GETCHR 180 | POP BC 181 | LD C,A 182 | 183 | CALL BCTOA 184 | LD B,A 185 | LD A,(checkSum) 186 | SUB B 187 | CP 0 188 | JR Z,checksumOK 189 | 190 | LD A,CR 191 | CALL PUTCHR 192 | LD A,LF 193 | CALL PUTCHR 194 | 195 | LD DE,chkErrMess 196 | LD C,PSTRING 197 | CALL BDOS 198 | JR FINISH 199 | 200 | checksumOK: 201 | LD A,CR 202 | CALL PUTCHR 203 | LD A,LF 204 | CALL PUTCHR 205 | 206 | LD DE,OKMess 207 | LD C,PSTRING 208 | CALL BDOS 209 | 210 | 211 | 212 | FINISH: 213 | LD C,SETUSR 214 | LD E,0 215 | CALL BDOS 216 | 217 | JP REBOOT 218 | 219 | 220 | SETUSER: 221 | CALL GETCHR 222 | CALL HEX2VAL 223 | LD E,A 224 | LD C,SETUSR 225 | CALL BDOS 226 | JP WAITLT 227 | 228 | 229 | ; Get a char into A 230 | ;GETCHR: LD C,CONINP 231 | ; CALL BDOS 232 | ; RET 233 | 234 | ; Wait for a char into A (no echo) 235 | GETCHR: 236 | LD E,$FF 237 | LD C,CONIO 238 | CALL BDOS 239 | CP 0 240 | JR Z,GETCHR 241 | RET 242 | 243 | ; Write A to output 244 | PUTCHR: LD C,CONOUT 245 | LD E,A 246 | CALL BDOS 247 | RET 248 | 249 | 250 | ;------------------------------------------------------------------------------ 251 | ; Convert ASCII characters in B C registers to a byte value in A 252 | ;------------------------------------------------------------------------------ 253 | BCTOA LD A,B ; Move the hi order byte to A 254 | SUB $30 ; Take it down from Ascii 255 | CP $0A ; Are we in the 0-9 range here? 256 | JR C,BCTOA1 ; If so, get the next nybble 257 | SUB $07 ; But if A-F, take it down some more 258 | BCTOA1 RLCA ; Rotate the nybble from low to high 259 | RLCA ; One bit at a time 260 | RLCA ; Until we 261 | RLCA ; Get there with it 262 | LD B,A ; Save the converted high nybble 263 | LD A,C ; Now get the low order byte 264 | SUB $30 ; Convert it down from Ascii 265 | CP $0A ; 0-9 at this point? 266 | JR C,BCTOA2 ; Good enough then, but 267 | SUB $07 ; Take off 7 more if it's A-F 268 | BCTOA2 ADD A,B ; Add in the high order nybble 269 | RET 270 | 271 | ; Change Hex in A to actual value in A 272 | HEX2VAL SUB $30 273 | CP $0A 274 | RET C 275 | SUB $07 276 | RET 277 | 278 | 279 | buffPos .DB 0H 280 | buffPtr .DW 0000H 281 | printCount .DB 0H 282 | checkSum .DB 0H 283 | byteCount .DB 0H 284 | OKMess .BYTE "OK$" 285 | chkErrMess .BYTE "======Checksum Error======$" 286 | countErrMess .BYTE "======File Length Error======$" 287 | .END 288 | -------------------------------------------------------------------------------- /z80sbcFiles/source/download.lst: -------------------------------------------------------------------------------- 1 | 0001 0000 ;================================================================================== 2 | 0002 0000 ; Contents of this file are copyright Grant Searle 3 | 0003 0000 ; HEX routine from Joel Owens. 4 | 0004 0000 ; 5 | 0005 0000 ; You have permission to use this for NON COMMERCIAL USE ONLY 6 | 0006 0000 ; If you wish to use it elsewhere, please include an acknowledgement to myself. 7 | 0007 0000 ; 8 | 0008 0000 ; http://searle.hostei.com/grant/index.html 9 | 0009 0000 ; 10 | 0010 0000 ; eMail: home.micros01@btinternet.com 11 | 0011 0000 ; 12 | 0012 0000 ; If the above don't work, please perform an Internet search to see if I have 13 | 0013 0000 ; updated the web page hosting service. 14 | 0014 0000 ; 15 | 0015 0000 ;================================================================================== 16 | 0016 0000 17 | 0017 0000 TPA .EQU 100H 18 | 0018 0000 REBOOT .EQU 0H 19 | 0019 0000 BDOS .EQU 5H 20 | 0020 0000 CONIO .EQU 6 21 | 0021 0000 CONINP .EQU 1 22 | 0022 0000 CONOUT .EQU 2 23 | 0023 0000 PSTRING .EQU 9 24 | 0024 0000 MAKEF .EQU 22 25 | 0025 0000 CLOSEF .EQU 16 26 | 0026 0000 WRITES .EQU 21 27 | 0027 0000 DELF .EQU 19 28 | 0028 0000 SETUSR .EQU 32 29 | 0029 0000 30 | 0030 0000 CR .EQU 0DH 31 | 0031 0000 LF .EQU 0AH 32 | 0032 0000 33 | 0033 0000 FCB .EQU 05CH 34 | 0034 0000 BUFF .EQU 080H 35 | 0035 0000 36 | 0036 0100 .ORG TPA 37 | 0037 0100 38 | 0038 0100 39 | 0039 0100 3E 00 LD A,0 40 | 0040 0102 32 6D 02 LD (buffPos),A 41 | 0041 0105 32 71 02 LD (checkSum),A 42 | 0042 0108 32 72 02 LD (byteCount),A 43 | 0043 010B 32 70 02 LD (printCount),A 44 | 0044 010E 21 80 00 LD HL,BUFF 45 | 0045 0111 22 6E 02 LD (buffPtr),HL 46 | 0046 0114 47 | 0047 0114 48 | 0048 0114 CD 39 02 WAITLT: CALL GETCHR 49 | 0049 0117 FE 55 CP 'U' 50 | 0050 0119 CA 2A 02 JP Z,SETUSER 51 | 0051 011C FE 3A CP ':' 52 | 0052 011E 20 F4 JR NZ,WAITLT 53 | 0053 0120 54 | 0054 0120 55 | 0055 0120 0E 13 LD C,DELF 56 | 0056 0122 11 5C 00 LD DE,FCB 57 | 0057 0125 CD 05 00 CALL BDOS 58 | 0058 0128 59 | 0059 0128 0E 16 LD C,MAKEF 60 | 0060 012A 11 5C 00 LD DE,FCB 61 | 0061 012D CD 05 00 CALL BDOS 62 | 0062 0130 63 | 0063 0130 GETHEX: 64 | 0064 0130 CD 39 02 CALL GETCHR 65 | 0065 0133 FE 3E CP '>' 66 | 0066 0135 28 61 JR Z,CLOSE 67 | 0067 0137 47 LD B,A 68 | 0068 0138 C5 PUSH BC 69 | 0069 0139 CD 39 02 CALL GETCHR 70 | 0070 013C C1 POP BC 71 | 0071 013D 4F LD C,A 72 | 0072 013E 73 | 0073 013E CD 4C 02 CALL BCTOA 74 | 0074 0141 75 | 0075 0141 47 LD B,A 76 | 0076 0142 3A 71 02 LD A,(checkSum) 77 | 0077 0145 80 ADD A,B 78 | 0078 0146 32 71 02 LD (checkSum),A 79 | 0079 0149 3A 72 02 LD A,(byteCount) 80 | 0080 014C 3C INC A 81 | 0081 014D 32 72 02 LD (byteCount),A 82 | 0082 0150 83 | 0083 0150 78 LD A,B 84 | 0084 0151 85 | 0085 0151 2A 6E 02 LD HL,(buffPtr) 86 | 0086 0154 87 | 0087 0154 77 LD (HL),A 88 | 0088 0155 23 INC HL 89 | 0089 0156 22 6E 02 LD (buffPtr),HL 90 | 0090 0159 91 | 0091 0159 3A 6D 02 LD A,(buffPos) 92 | 0092 015C 3C INC A 93 | 0093 015D 32 6D 02 LD (buffPos),A 94 | 0094 0160 FE 80 CP 80H 95 | 0095 0162 96 | 0096 0162 20 32 JR NZ,NOWRITE 97 | 0097 0164 98 | 0098 0164 0E 15 LD C,WRITES 99 | 0099 0166 11 5C 00 LD DE,FCB 100 | 0100 0169 CD 05 00 CALL BDOS 101 | 0101 016C 3E 2E LD A,'.' 102 | 0102 016E CD 45 02 CALL PUTCHR 103 | 0103 0171 104 | 0104 0171 ; New line every 8K (64 dots) 105 | 0105 0171 3A 70 02 LD A,(printCount) 106 | 0106 0174 3C INC A 107 | 0107 0175 FE 40 CP 64 108 | 0108 0177 20 0F JR NZ,noCRLF 109 | 0109 0179 32 70 02 LD (printCount),A 110 | 0110 017C 3E 0D LD A,CR 111 | 0111 017E CD 45 02 CALL PUTCHR 112 | 0112 0181 3E 0A LD A,LF 113 | 0113 0183 CD 45 02 CALL PUTCHR 114 | 0114 0186 3E 00 LD A,0 115 | 0115 0188 32 70 02 noCRLF: LD (printCount),A 116 | 0116 018B 117 | 0117 018B 21 80 00 LD HL,BUFF 118 | 0118 018E 22 6E 02 LD (buffPtr),HL 119 | 0119 0191 120 | 0120 0191 3E 00 LD A,0 121 | 0121 0193 32 6D 02 LD (buffPos),A 122 | 0122 0196 NOWRITE: 123 | 0123 0196 18 98 JR GETHEX 124 | 0124 0198 125 | 0125 0198 126 | 0126 0198 CLOSE: 127 | 0127 0198 128 | 0128 0198 3A 6D 02 LD A,(buffPos) 129 | 0129 019B FE 00 CP 0 130 | 0130 019D 28 0D JR Z,NOWRITE2 131 | 0131 019F 132 | 0132 019F 0E 15 LD C,WRITES 133 | 0133 01A1 11 5C 00 LD DE,FCB 134 | 0134 01A4 CD 05 00 CALL BDOS 135 | 0135 01A7 3E 2E LD A,'.' 136 | 0136 01A9 CD 45 02 CALL PUTCHR 137 | 0137 01AC 138 | 0138 01AC NOWRITE2: 139 | 0139 01AC 0E 10 LD C,CLOSEF 140 | 0140 01AE 11 5C 00 LD DE,FCB 141 | 0141 01B1 CD 05 00 CALL BDOS 142 | 0142 01B4 143 | 0143 01B4 ; Byte count (lower 8 bits) 144 | 0144 01B4 CD 39 02 CALL GETCHR 145 | 0145 01B7 47 LD B,A 146 | 0146 01B8 C5 PUSH BC 147 | 0147 01B9 CD 39 02 CALL GETCHR 148 | 0148 01BC C1 POP BC 149 | 0149 01BD 4F LD C,A 150 | 0150 01BE 151 | 0151 01BE CD 4C 02 CALL BCTOA 152 | 0152 01C1 47 LD B,A 153 | 0153 01C2 3A 72 02 LD A,(byteCount) 154 | 0154 01C5 90 SUB B 155 | 0155 01C6 FE 00 CP 0 156 | 0156 01C8 28 1A JR Z,byteCountOK 157 | 0157 01CA 158 | 0158 01CA 3E 0D LD A,CR 159 | 0159 01CC CD 45 02 CALL PUTCHR 160 | 0160 01CF 3E 0A LD A,LF 161 | 0161 01D1 CD 45 02 CALL PUTCHR 162 | 0162 01D4 163 | 0163 01D4 11 91 02 LD DE,countErrMess 164 | 0164 01D7 0E 09 LD C,PSTRING 165 | 0165 01D9 CD 05 00 CALL BDOS 166 | 0166 01DC 167 | 0167 01DC ; Sink remaining 2 bytes 168 | 0168 01DC CD 39 02 CALL GETCHR 169 | 0169 01DF CD 39 02 CALL GETCHR 170 | 0170 01E2 171 | 0171 01E2 18 3C JR FINISH 172 | 0172 01E4 173 | 0173 01E4 byteCountOK: 174 | 0174 01E4 175 | 0175 01E4 ; Checksum 176 | 0176 01E4 CD 39 02 CALL GETCHR 177 | 0177 01E7 47 LD B,A 178 | 0178 01E8 C5 PUSH BC 179 | 0179 01E9 CD 39 02 CALL GETCHR 180 | 0180 01EC C1 POP BC 181 | 0181 01ED 4F LD C,A 182 | 0182 01EE 183 | 0183 01EE CD 4C 02 CALL BCTOA 184 | 0184 01F1 47 LD B,A 185 | 0185 01F2 3A 71 02 LD A,(checkSum) 186 | 0186 01F5 90 SUB B 187 | 0187 01F6 FE 00 CP 0 188 | 0188 01F8 28 14 JR Z,checksumOK 189 | 0189 01FA 190 | 0190 01FA 3E 0D LD A,CR 191 | 0191 01FC CD 45 02 CALL PUTCHR 192 | 0192 01FF 3E 0A LD A,LF 193 | 0193 0201 CD 45 02 CALL PUTCHR 194 | 0194 0204 195 | 0195 0204 11 76 02 LD DE,chkErrMess 196 | 0196 0207 0E 09 LD C,PSTRING 197 | 0197 0209 CD 05 00 CALL BDOS 198 | 0198 020C 18 12 JR FINISH 199 | 0199 020E 200 | 0200 020E checksumOK: 201 | 0201 020E 3E 0D LD A,CR 202 | 0202 0210 CD 45 02 CALL PUTCHR 203 | 0203 0213 3E 0A LD A,LF 204 | 0204 0215 CD 45 02 CALL PUTCHR 205 | 0205 0218 206 | 0206 0218 11 73 02 LD DE,OKMess 207 | 0207 021B 0E 09 LD C,PSTRING 208 | 0208 021D CD 05 00 CALL BDOS 209 | 0209 0220 210 | 0210 0220 211 | 0211 0220 212 | 0212 0220 FINISH: 213 | 0213 0220 0E 20 LD C,SETUSR 214 | 0214 0222 1E 00 LD E,0 215 | 0215 0224 CD 05 00 CALL BDOS 216 | 0216 0227 217 | 0217 0227 C3 00 00 JP REBOOT 218 | 0218 022A 219 | 0219 022A 220 | 0220 022A SETUSER: 221 | 0221 022A CD 39 02 CALL GETCHR 222 | 0222 022D CD 65 02 CALL HEX2VAL 223 | 0223 0230 5F LD E,A 224 | 0224 0231 0E 20 LD C,SETUSR 225 | 0225 0233 CD 05 00 CALL BDOS 226 | 0226 0236 C3 14 01 JP WAITLT 227 | 0227 0239 228 | 0228 0239 229 | 0229 0239 ; Get a char into A 230 | 0230 0239 ;GETCHR: LD C,CONINP 231 | 0231 0239 ; CALL BDOS 232 | 0232 0239 ; RET 233 | 0233 0239 234 | 0234 0239 ; Wait for a char into A (no echo) 235 | 0235 0239 GETCHR: 236 | 0236 0239 1E FF LD E,$FF 237 | 0237 023B 0E 06 LD C,CONIO 238 | 0238 023D CD 05 00 CALL BDOS 239 | 0239 0240 FE 00 CP 0 240 | 0240 0242 28 F5 JR Z,GETCHR 241 | 0241 0244 C9 RET 242 | 0242 0245 243 | 0243 0245 ; Write A to output 244 | 0244 0245 0E 02 PUTCHR: LD C,CONOUT 245 | 0245 0247 5F LD E,A 246 | 0246 0248 CD 05 00 CALL BDOS 247 | 0247 024B C9 RET 248 | 0248 024C 249 | 0249 024C 250 | 0250 024C ;------------------------------------------------------------------------------ 251 | 0251 024C ; Convert ASCII characters in B C registers to a byte value in A 252 | 0252 024C ;------------------------------------------------------------------------------ 253 | 0253 024C 78 BCTOA LD A,B ; Move the hi order byte to A 254 | 0254 024D D6 30 SUB $30 ; Take it down from Ascii 255 | 0255 024F FE 0A CP $0A ; Are we in the 0-9 range here? 256 | 0256 0251 38 02 JR C,BCTOA1 ; If so, get the next nybble 257 | 0257 0253 D6 07 SUB $07 ; But if A-F, take it down some more 258 | 0258 0255 07 BCTOA1 RLCA ; Rotate the nybble from low to high 259 | 0259 0256 07 RLCA ; One bit at a time 260 | 0260 0257 07 RLCA ; Until we 261 | 0261 0258 07 RLCA ; Get there with it 262 | 0262 0259 47 LD B,A ; Save the converted high nybble 263 | 0263 025A 79 LD A,C ; Now get the low order byte 264 | 0264 025B D6 30 SUB $30 ; Convert it down from Ascii 265 | 0265 025D FE 0A CP $0A ; 0-9 at this point? 266 | 0266 025F 38 02 JR C,BCTOA2 ; Good enough then, but 267 | 0267 0261 D6 07 SUB $07 ; Take off 7 more if it's A-F 268 | 0268 0263 80 BCTOA2 ADD A,B ; Add in the high order nybble 269 | 0269 0264 C9 RET 270 | 0270 0265 271 | 0271 0265 ; Change Hex in A to actual value in A 272 | 0272 0265 D6 30 HEX2VAL SUB $30 273 | 0273 0267 FE 0A CP $0A 274 | 0274 0269 D8 RET C 275 | 0275 026A D6 07 SUB $07 276 | 0276 026C C9 RET 277 | 0277 026D 278 | 0278 026D 279 | 0279 026D 00 buffPos .DB 0H 280 | 0280 026E 00 00 buffPtr .DW 0000H 281 | 0281 0270 00 printCount .DB 0H 282 | 0282 0271 00 checkSum .DB 0H 283 | 0283 0272 00 byteCount .DB 0H 284 | 0284 0273 4F 4B 24 OKMess .BYTE "OK$" 285 | 0285 0276 3D 3D 3D 3D chkErrMess .BYTE "======Checksum Error======$" 286 | 0285 027A 3D 3D 43 68 287 | 0285 027E 65 63 6B 73 288 | 0285 0282 75 6D 20 45 289 | 0285 0286 72 72 6F 72 290 | 0285 028A 3D 3D 3D 3D 291 | 0285 028E 3D 3D 24 292 | 0286 0291 3D 3D 3D 3D countErrMess .BYTE "======File Length Error======$" 293 | 0286 0295 3D 3D 46 69 294 | 0286 0299 6C 65 20 4C 295 | 0286 029D 65 6E 67 74 296 | 0286 02A1 68 20 45 72 297 | 0286 02A5 72 6F 72 3D 298 | 0286 02A9 3D 3D 3D 3D 299 | 0286 02AD 3D 24 300 | 0287 02AF .END 301 | tasm: Number of errors = 0 302 | -------------------------------------------------------------------------------- /z80sbcFiles/source/form128.asm: -------------------------------------------------------------------------------- 1 | ;================================================================================== 2 | ; Contents of this file are copyright Grant Searle 3 | ; 4 | ; You have permission to use this for NON COMMERCIAL USE ONLY 5 | ; If you wish to use it elsewhere, please include an acknowledgement to myself. 6 | ; 7 | ; http://searle.hostei.com/grant/index.html 8 | ; 9 | ; eMail: home.micros01@btinternet.com 10 | ; 11 | ; If the above don't work, please perform an Internet search to see if I have 12 | ; updated the web page hosting service. 13 | ; 14 | ;================================================================================== 15 | 16 | numDrives .EQU 15 ; Not including A: 17 | 18 | 19 | ; CF registers 20 | CF_DATA .EQU $10 21 | CF_FEATURES .EQU $11 22 | CF_ERROR .EQU $11 23 | CF_SECCOUNT .EQU $12 24 | CF_SECTOR .EQU $13 25 | CF_CYL_LOW .EQU $14 26 | CF_CYL_HI .EQU $15 27 | CF_HEAD .EQU $16 28 | CF_STATUS .EQU $17 29 | CF_COMMAND .EQU $17 30 | CF_LBA0 .EQU $13 31 | CF_LBA1 .EQU $14 32 | CF_LBA2 .EQU $15 33 | CF_LBA3 .EQU $16 34 | 35 | ;CF Features 36 | CF_8BIT .EQU 1 37 | CF_NOCACHE .EQU 082H 38 | ;CF Commands 39 | CF_READ_SEC .EQU 020H 40 | CF_WRITE_SEC .EQU 030H 41 | CF_SET_FEAT .EQU 0EFH 42 | 43 | LF .EQU 0AH ;line feed 44 | FF .EQU 0CH ;form feed 45 | CR .EQU 0DH ;carriage RETurn 46 | 47 | ;==================================================================================== 48 | 49 | .ORG 5000H ; Format program origin. 50 | 51 | 52 | CALL printInline 53 | .TEXT "CP/M Formatter by G. Searle 2012" 54 | .DB CR,LF,0 55 | 56 | LD A,'A' 57 | LD (drvName),A 58 | 59 | CALL cfWait 60 | LD A,CF_8BIT ; Set IDE to be 8bit 61 | OUT (CF_FEATURES),A 62 | LD A,CF_SET_FEAT 63 | OUT (CF_COMMAND),A 64 | 65 | CALL cfWait 66 | LD A,CF_NOCACHE ; No write cache 67 | OUT (CF_FEATURES),A 68 | LD A,CF_SET_FEAT 69 | OUT (CF_COMMAND),A 70 | 71 | 72 | ; There are 512 directory entries per disk, 4 DIR entries per sector 73 | ; So 128 x 128 byte sectors are to be initialised 74 | ; The drive uses 512 byte sectors, so 32 x 512 byte sectors per disk 75 | ; require initialisation 76 | 77 | ;Drive 0 (A:) is slightly different due to reserved track, so DIR sector starts at 32 78 | LD A,(drvName) 79 | RST 08H ; Print drive letter 80 | INC A 81 | LD (drvName),A 82 | 83 | LD A,$20 84 | LD (secNo),A 85 | 86 | processSectorA: 87 | CALL cfWait 88 | 89 | LD A,(secNo) 90 | OUT (CF_LBA0),A 91 | LD A,0 92 | OUT (CF_LBA1),A 93 | LD A,0 94 | OUT (CF_LBA2),A 95 | LD a,$E0 96 | OUT (CF_LBA3),A 97 | LD A,1 98 | OUT (CF_SECCOUNT),A 99 | 100 | call writeDir 101 | 102 | LD A,(secNo) 103 | INC A 104 | LD (secNo),A 105 | CP $40 106 | JR NZ, processSectorA 107 | 108 | 109 | 110 | ;Drive 1 onwards (B: etc) don't have reserved tracks, so sector starts at 0 111 | 112 | LD DE,$0040 ; HL increment 113 | LD HL,$0040 ; H = LBA2, L=LBA1, initialise for drive 1 (B:) 114 | 115 | LD B,numDrives 116 | 117 | processDirs: 118 | 119 | LD A,(drvName) 120 | RST 08H ; Print drive letter 121 | INC A 122 | LD (drvName),A 123 | 124 | LD A,0 125 | LD (secNo),A 126 | 127 | processSector: 128 | CALL cfWait 129 | 130 | LD A,(secNo) 131 | OUT (CF_LBA0),A 132 | LD A,L 133 | OUT (CF_LBA1),A 134 | LD A,H 135 | OUT (CF_LBA2),A 136 | LD a,0E0H 137 | OUT (CF_LBA3),A 138 | LD A,1 139 | OUT (CF_SECCOUNT),A 140 | 141 | call writeDir 142 | 143 | LD A,(secNo) 144 | INC A 145 | LD (secNo),A 146 | CP $20 147 | JR NZ, processSector 148 | 149 | ADD HL,DE 150 | 151 | DEC B 152 | JR NZ,processDirs 153 | 154 | CALL printInline 155 | .DB CR,LF 156 | .TEXT "Formatting complete" 157 | .DB CR,LF,0 158 | 159 | RET 160 | 161 | ;================================================================================================ 162 | ; Write physical sector to host 163 | ;================================================================================================ 164 | 165 | writeDir: 166 | PUSH AF 167 | PUSH BC 168 | PUSH HL 169 | 170 | CALL cfWait 171 | 172 | LD A,CF_WRITE_SEC 173 | OUT (CF_COMMAND),A 174 | 175 | CALL cfWait 176 | 177 | LD c,4 178 | wr4secs: 179 | LD HL,dirData 180 | LD b,128 181 | wrByte: LD A,(HL) 182 | nop 183 | nop 184 | OUT (CF_DATA),A 185 | iNC HL 186 | dec b 187 | JR NZ, wrByte 188 | 189 | dec c 190 | JR NZ,wr4secs 191 | 192 | POP HL 193 | POP BC 194 | POP AF 195 | 196 | RET 197 | 198 | ;================================================================================================ 199 | ; Utilities 200 | ;================================================================================================ 201 | 202 | printInline: 203 | EX (SP),HL ; PUSH HL and put RET ADDress into HL 204 | PUSH AF 205 | PUSH BC 206 | nextILChar: LD A,(HL) 207 | CP 0 208 | JR Z,endOfPrint 209 | RST 08H 210 | INC HL 211 | JR nextILChar 212 | endOfPrint: INC HL ; Get past "null" terminator 213 | POP BC 214 | POP AF 215 | EX (SP),HL ; PUSH new RET ADDress on stack and restore HL 216 | RET 217 | 218 | ;================================================================================================ 219 | ; Wait for disk to be ready (busy=0,ready=1) 220 | ;================================================================================================ 221 | cfWait: 222 | PUSH AF 223 | cfWait1: 224 | in A,(CF_STATUS) 225 | AND 080H 226 | cp 080H 227 | JR Z,cfWait1 228 | POP AF 229 | RET 230 | 231 | secNo .db 0 232 | drvName .db 0 233 | 234 | 235 | ; Directory data for 1 x 128 byte sector 236 | dirData: 237 | .DB $E5,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$00,$00,$00,$00 238 | .DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 239 | 240 | .DB $E5,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$00,$00,$00,$00 241 | .DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 242 | 243 | .DB $E5,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$00,$00,$00,$00 244 | .DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 245 | 246 | .DB $E5,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$00,$00,$00,$00 247 | .DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 248 | 249 | .END 250 | -------------------------------------------------------------------------------- /z80sbcFiles/source/form64.asm: -------------------------------------------------------------------------------- 1 | ;================================================================================== 2 | ; Contents of this file are copyright Grant Searle 3 | ; 4 | ; You have permission to use this for NON COMMERCIAL USE ONLY 5 | ; If you wish to use it elsewhere, please include an acknowledgement to myself. 6 | ; 7 | ; http://searle.hostei.com/grant/index.html 8 | ; 9 | ; eMail: home.micros01@btinternet.com 10 | ; 11 | ; If the above don't work, please perform an Internet search to see if I have 12 | ; updated the web page hosting service. 13 | ; 14 | ;================================================================================== 15 | 16 | numDrives .EQU 7 ; Not including A: 17 | 18 | 19 | ; CF registers 20 | CF_DATA .EQU $10 21 | CF_FEATURES .EQU $11 22 | CF_ERROR .EQU $11 23 | CF_SECCOUNT .EQU $12 24 | CF_SECTOR .EQU $13 25 | CF_CYL_LOW .EQU $14 26 | CF_CYL_HI .EQU $15 27 | CF_HEAD .EQU $16 28 | CF_STATUS .EQU $17 29 | CF_COMMAND .EQU $17 30 | CF_LBA0 .EQU $13 31 | CF_LBA1 .EQU $14 32 | CF_LBA2 .EQU $15 33 | CF_LBA3 .EQU $16 34 | 35 | ;CF Features 36 | CF_8BIT .EQU 1 37 | CF_NOCACHE .EQU 082H 38 | ;CF Commands 39 | CF_READ_SEC .EQU 020H 40 | CF_WRITE_SEC .EQU 030H 41 | CF_SET_FEAT .EQU 0EFH 42 | 43 | LF .EQU 0AH ;line feed 44 | FF .EQU 0CH ;form feed 45 | CR .EQU 0DH ;carriage RETurn 46 | 47 | ;==================================================================================== 48 | 49 | .ORG 5000H ; Format program origin. 50 | 51 | 52 | CALL printInline 53 | .TEXT "CP/M Formatter by G. Searle 2012" 54 | .DB CR,LF,0 55 | 56 | LD A,'A' 57 | LD (drvName),A 58 | 59 | CALL cfWait 60 | LD A,CF_8BIT ; Set IDE to be 8bit 61 | OUT (CF_FEATURES),A 62 | LD A,CF_SET_FEAT 63 | OUT (CF_COMMAND),A 64 | 65 | CALL cfWait 66 | LD A,CF_NOCACHE ; No write cache 67 | OUT (CF_FEATURES),A 68 | LD A,CF_SET_FEAT 69 | OUT (CF_COMMAND),A 70 | 71 | 72 | ; There are 512 directory entries per disk, 4 DIR entries per sector 73 | ; So 128 x 128 byte sectors are to be initialised 74 | ; The drive uses 512 byte sectors, so 32 x 512 byte sectors per disk 75 | ; require initialisation 76 | 77 | ;Drive 0 (A:) is slightly different due to reserved track, so DIR sector starts at 32 78 | LD A,(drvName) 79 | RST 08H ; Print drive letter 80 | INC A 81 | LD (drvName),A 82 | 83 | LD A,$20 84 | LD (secNo),A 85 | 86 | processSectorA: 87 | CALL cfWait 88 | 89 | LD A,(secNo) 90 | OUT (CF_LBA0),A 91 | LD A,0 92 | OUT (CF_LBA1),A 93 | LD A,0 94 | OUT (CF_LBA2),A 95 | LD a,$E0 96 | OUT (CF_LBA3),A 97 | LD A,1 98 | OUT (CF_SECCOUNT),A 99 | 100 | call writeDir 101 | 102 | LD A,(secNo) 103 | INC A 104 | LD (secNo),A 105 | CP $40 106 | JR NZ, processSectorA 107 | 108 | 109 | 110 | ;Drive 1 onwards (B: etc) don't have reserved tracks, so sector starts at 0 111 | 112 | LD DE,$0040 ; HL increment 113 | LD HL,$0040 ; H = LBA2, L=LBA1, initialise for drive 1 (B:) 114 | 115 | LD B,numDrives 116 | 117 | processDirs: 118 | 119 | LD A,(drvName) 120 | RST 08H ; Print drive letter 121 | INC A 122 | LD (drvName),A 123 | 124 | LD A,0 125 | LD (secNo),A 126 | 127 | processSector: 128 | CALL cfWait 129 | 130 | LD A,(secNo) 131 | OUT (CF_LBA0),A 132 | LD A,L 133 | OUT (CF_LBA1),A 134 | LD A,H 135 | OUT (CF_LBA2),A 136 | LD a,0E0H 137 | OUT (CF_LBA3),A 138 | LD A,1 139 | OUT (CF_SECCOUNT),A 140 | 141 | call writeDir 142 | 143 | LD A,(secNo) 144 | INC A 145 | LD (secNo),A 146 | CP $20 147 | JR NZ, processSector 148 | 149 | ADD HL,DE 150 | 151 | DEC B 152 | JR NZ,processDirs 153 | 154 | CALL printInline 155 | .DB CR,LF 156 | .TEXT "Formatting complete" 157 | .DB CR,LF,0 158 | 159 | RET 160 | 161 | ;================================================================================================ 162 | ; Write physical sector to host 163 | ;================================================================================================ 164 | 165 | writeDir: 166 | PUSH AF 167 | PUSH BC 168 | PUSH HL 169 | 170 | CALL cfWait 171 | 172 | LD A,CF_WRITE_SEC 173 | OUT (CF_COMMAND),A 174 | 175 | CALL cfWait 176 | 177 | LD c,4 178 | wr4secs: 179 | LD HL,dirData 180 | LD b,128 181 | wrByte: LD A,(HL) 182 | nop 183 | nop 184 | OUT (CF_DATA),A 185 | iNC HL 186 | dec b 187 | JR NZ, wrByte 188 | 189 | dec c 190 | JR NZ,wr4secs 191 | 192 | POP HL 193 | POP BC 194 | POP AF 195 | 196 | RET 197 | 198 | ;================================================================================================ 199 | ; Utilities 200 | ;================================================================================================ 201 | 202 | printInline: 203 | EX (SP),HL ; PUSH HL and put RET ADDress into HL 204 | PUSH AF 205 | PUSH BC 206 | nextILChar: LD A,(HL) 207 | CP 0 208 | JR Z,endOfPrint 209 | RST 08H 210 | INC HL 211 | JR nextILChar 212 | endOfPrint: INC HL ; Get past "null" terminator 213 | POP BC 214 | POP AF 215 | EX (SP),HL ; PUSH new RET ADDress on stack and restore HL 216 | RET 217 | 218 | ;================================================================================================ 219 | ; Wait for disk to be ready (busy=0,ready=1) 220 | ;================================================================================================ 221 | cfWait: 222 | PUSH AF 223 | cfWait1: 224 | in A,(CF_STATUS) 225 | AND 080H 226 | cp 080H 227 | JR Z,cfWait1 228 | POP AF 229 | RET 230 | 231 | secNo .db 0 232 | drvName .db 0 233 | 234 | 235 | ; Directory data for 1 x 128 byte sector 236 | dirData: 237 | .DB $E5,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$00,$00,$00,$00 238 | .DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 239 | 240 | .DB $E5,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$00,$00,$00,$00 241 | .DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 242 | 243 | .DB $E5,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$00,$00,$00,$00 244 | .DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 245 | 246 | .DB $E5,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$00,$00,$00,$00 247 | .DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 248 | 249 | .END 250 | -------------------------------------------------------------------------------- /z80sbcFiles/source/putsys.asm: -------------------------------------------------------------------------------- 1 | ;================================================================================== 2 | ; Contents of this file are copyright Grant Searle 3 | ; 4 | ; You have permission to use this for NON COMMERCIAL USE ONLY 5 | ; If you wish to use it elsewhere, please include an acknowledgement to myself. 6 | ; 7 | ; http://searle.hostei.com/grant/index.html 8 | ; 9 | ; eMail: home.micros01@btinternet.com 10 | ; 11 | ; If the above don't work, please perform an Internet search to see if I have 12 | ; updated the web page hosting service. 13 | ; 14 | ;================================================================================== 15 | 16 | loadAddr .EQU 0D000h 17 | numSecs .EQU 24 ; Number of 512 sectors to be loaded 18 | 19 | 20 | ; CF registers 21 | CF_DATA .EQU $10 22 | CF_FEATURES .EQU $11 23 | CF_ERROR .EQU $11 24 | CF_SECCOUNT .EQU $12 25 | CF_SECTOR .EQU $13 26 | CF_CYL_LOW .EQU $14 27 | CF_CYL_HI .EQU $15 28 | CF_HEAD .EQU $16 29 | CF_STATUS .EQU $17 30 | CF_COMMAND .EQU $17 31 | CF_LBA0 .EQU $13 32 | CF_LBA1 .EQU $14 33 | CF_LBA2 .EQU $15 34 | CF_LBA3 .EQU $16 35 | 36 | ;CF Features 37 | CF_8BIT .EQU 1 38 | CF_NOCACHE .EQU 082H 39 | ;CF Commands 40 | CF_READ_SEC .EQU 020H 41 | CF_WRITE_SEC .EQU 030H 42 | CF_SET_FEAT .EQU 0EFH 43 | 44 | LF .EQU 0AH ;line feed 45 | FF .EQU 0CH ;form feed 46 | CR .EQU 0DH ;carriage RETurn 47 | 48 | ;================================================================================================ 49 | 50 | .ORG 5000H ; Loader origin. 51 | 52 | CALL printInline 53 | .TEXT "CP/M System Transfer by G. Searle 2012" 54 | .DB CR,LF,0 55 | 56 | CALL cfWait 57 | LD A,CF_8BIT ; Set IDE to be 8bit 58 | OUT (CF_FEATURES),A 59 | LD A,CF_SET_FEAT 60 | OUT (CF_COMMAND),A 61 | 62 | 63 | CALL cfWait 64 | LD A,CF_NOCACHE ; No write cache 65 | OUT (CF_FEATURES),A 66 | LD A,CF_SET_FEAT 67 | OUT (CF_COMMAND),A 68 | 69 | LD B,numSecs 70 | 71 | LD A,0 72 | LD (secNo),A 73 | LD HL,loadAddr 74 | LD (dmaAddr),HL 75 | processSectors: 76 | 77 | CALL cfWait 78 | 79 | LD A,(secNo) 80 | OUT (CF_LBA0),A 81 | LD A,0 82 | OUT (CF_LBA1),A 83 | OUT (CF_LBA2),A 84 | LD a,0E0H 85 | OUT (CF_LBA3),A 86 | LD A,1 87 | OUT (CF_SECCOUNT),A 88 | 89 | call write 90 | 91 | LD DE,0200H 92 | LD HL,(dmaAddr) 93 | ADD HL,DE 94 | LD (dmaAddr),HL 95 | LD A,(secNo) 96 | INC A 97 | LD (secNo),A 98 | 99 | djnz processSectors 100 | 101 | CALL printInline 102 | .DB CR,LF 103 | .TEXT "System transfer complete" 104 | .DB CR,LF,0 105 | 106 | RET 107 | 108 | 109 | ;================================================================================================ 110 | ; Write physical sector to host 111 | ;================================================================================================ 112 | 113 | write: 114 | PUSH AF 115 | PUSH BC 116 | PUSH HL 117 | 118 | 119 | CALL cfWait 120 | 121 | LD A,CF_WRITE_SEC 122 | OUT (CF_COMMAND),A 123 | 124 | CALL cfWait 125 | 126 | LD c,4 127 | LD HL,(dmaAddr) 128 | wr4secs: 129 | LD b,128 130 | wrByte: LD A,(HL) 131 | nop 132 | nop 133 | OUT (CF_DATA),A 134 | iNC HL 135 | dec b 136 | JR NZ, wrByte 137 | 138 | dec c 139 | JR NZ,wr4secs 140 | 141 | POP HL 142 | POP BC 143 | POP AF 144 | 145 | RET 146 | 147 | ;================================================================================================ 148 | ; Wait for disk to be ready (busy=0,ready=1) 149 | ;================================================================================================ 150 | cfWait: 151 | PUSH AF 152 | cfWait1: 153 | in A,(CF_STATUS) 154 | AND 080H 155 | cp 080H 156 | JR Z,cfWait1 157 | POP AF 158 | RET 159 | 160 | 161 | ;================================================================================================ 162 | ; Utilities 163 | ;================================================================================================ 164 | 165 | printInline: 166 | EX (SP),HL ; PUSH HL and put RET ADDress into HL 167 | PUSH AF 168 | PUSH BC 169 | nextILChar: LD A,(HL) 170 | CP 0 171 | JR Z,endOfPrint 172 | RST 08H 173 | INC HL 174 | JR nextILChar 175 | endOfPrint: INC HL ; Get past "null" terminator 176 | POP BC 177 | POP AF 178 | EX (SP),HL ; PUSH new RET ADDress on stack and restore HL 179 | RET 180 | 181 | dmaAddr .dw 0 182 | secNo .db 0 183 | 184 | .END 185 | -------------------------------------------------------------------------------- /z80sbcFiles/windowsApp/COMDLG32.OCX: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaffa/z80cpm_emulator/7ed59c9e49bd4f223e174ea87746bfabe73761bf/z80sbcFiles/windowsApp/COMDLG32.OCX --------------------------------------------------------------------------------