{"id":16164706,"url":"https://github.com/johnsonjh/com-cpm","last_synced_at":"2025-03-18T23:30:34.053Z","repository":{"id":42125402,"uuid":"353271605","full_name":"johnsonjh/com-cpm","owner":"johnsonjh","description":"com-cpm: COM, a CP/M-80 simulator (in portable C and 68000 assembly flavors) by Jim Cathey","archived":false,"fork":false,"pushed_at":"2022-04-12T15:46:42.000Z","size":1146,"stargazers_count":19,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-28T12:46:53.366Z","etag":null,"topics":["68000","68k","8080","com","com80","cp-m","cpm","m68k","z-80","z80"],"latest_commit_sha":null,"homepage":"http://formicapeak.com/~jimc/","language":"Assembly","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johnsonjh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null}},"created_at":"2021-03-31T07:49:38.000Z","updated_at":"2024-12-26T22:56:49.000Z","dependencies_parsed_at":"2022-08-12T07:20:15.923Z","dependency_job_id":null,"html_url":"https://github.com/johnsonjh/com-cpm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnsonjh%2Fcom-cpm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnsonjh%2Fcom-cpm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnsonjh%2Fcom-cpm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnsonjh%2Fcom-cpm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johnsonjh","download_url":"https://codeload.github.com/johnsonjh/com-cpm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243955421,"owners_count":20374369,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["68000","68k","8080","com","com80","cp-m","cpm","m68k","z-80","z80"],"created_at":"2024-10-10T02:47:30.902Z","updated_at":"2025-03-18T23:30:33.476Z","avatar_url":"https://github.com/johnsonjh.png","language":"Assembly","readme":"# COM: A CP/M-80 Simulator\n\n---\n\nA CP/M-80 simulator (in portable C and 68000 assembly flavors)\n\n---\n\nSample \\'_screen shot_\\' from _**WordStar 3.00**_:\n\n\u003e                editing no file\n\u003e                      \u003c \u003c \u003c  N O - F I L E   M E N U  \u003e \u003e \u003e\n\u003e        ---Preliminary  Commands---   | --File  Commands-- | -System  Commands-\n\u003e      L  Changed logged disk drive    |                    |  R  Run a program\n\u003e      F  File directory    off (ON)   |  P  Print a file   |  X  EXIT to system\n\u003e      H  Set help level               |                    |\n\u003e       ---Commands to open a file---  |  E  RENAME a file  | -WordStar Options-\n\u003e         D  Open a  document  file    |  O  COPY   a file  |  M  Run MailMerge\n\u003e         N  Open a non-document file  |  Y  DELETE a file  |  S  Run SpellStar\n\u003e\n\u003e     DIRECTORY of disk A:\n\u003e      FFT.BAS      KEYCON.ASM   KEYCON.PRN   KEYCON.SYM   MORTGAGE.BAS PILOT.TXT\n\u003e      SPELSTAR.DCT SQRTSIM.BAS  THRASH.BAS   TUTORIAL.PIL ZORK1.DAT    ZORK2.DAT\n\u003e      ZORK3.DAT    KEYCON.HEX   CD.COM       FORTH.COM    INSTALL.COM  LOAD.COM\n\u003e      MAC.COM      MBASIC.COM   PILOT.COM    SARGON.COM   TESTPROG.COM WS.COM\n\u003e      WS.COM       ZORK1.COM    ZORK2.COM    ZORK3.COM    MAILMRGE.OVR MERGPRIN.OVR\n\u003e      SPELSTAR.OVR WIMSGS.OVR   WSMSGS.OVR   WSOVLY1.OVR\n\nAnd then running **Zork** (from within **WordStar**):\n\n\u003e     r          editing no file\n\u003e\n\u003e      Enter name of program you wish to Run,\n\u003e      optionally followed by appropriate arguments.\n\u003e         Example (shows disk space):     STAT\n\u003e\n\u003e      ^S=delete character   ^Y=delete entry   ^F=File directory\n\u003e      ^D=restore character  ^R=Restore entry  ^U=cancel command\n\u003e\n\u003e         COMMAND? zork1\n\u003e\n\u003e     ZORK I: The Great Underground Empire\n\u003e     Copyright (c) 1981, 1982, 1983 Infocom, Inc. All rights\n\u003e     reserved.\n\u003e     ZORK is a registered trademark of Infocom, Inc.\n\u003e     Revision 88 / Serial number 840726\n\u003e\n\u003e     West of House\n\u003e     You are standing in an open field west of a white house, with\n\u003e     a boarded front door.\n\u003e     There is a small mailbox here.\n\u003e\n\u003e     \u003e\n\n---\n\n## Update (2008)\n\nNow that the _PowerPC_ platforms are being left in the dust, I decided to port\nthe assembly-language synthetic CPU to them. Why? No good reason, mostly just\ncuriosity to see how much better than the C compiler I could do by careful\nhand-coding. (I also wished to use it as a vehicle for familiarizing myself with\nthe _PPC_ because we use it at work.)\n\nThe port is roughly a line-by-line translation of the original _680x0_ code.\nThis is probably sub-optimal with regards to what the _PPC_ could really do, but\nI just wasn\\'t up to the job of completely re-architecting it. The _PPC_\\'s flag\nregisters are sufficiently difficult to access, and weird enough once you do get\nthere, that I abandoned the original memory-thrifty architecture of converting\nthe native arithmetic flags to the target\\'s flags via small lookup tables in\nfavor of an approach where I look up the flags (and the sum/difference) directly\nvia large (128 KB) three-input tables. (I had considered this table-driven\napproach in the very beginning, but the original host machine had all of 128 KB\nof RAM in it, of which half was going to be dedicated to the target machine\nimage space, leaving the other half for the host OS _and_ the simulator, so that\nwas not possible.) This approach also enabled creation of a true half-carry\nflag, rather than recording all arguments to add/subtract instructions for later\nuse in recreating a half-carry in any subsequent DAA instructions.\n\nMy unfamiliarity with the _PPC_ has also no doubt resulted in less than optimal\nresults, even given this architecture, especially as pipeline and cache effects\nhave been ignored. I must say that I find the _PPC_ difficult to write assembly\nfor, but the bulk of that can be blamed on poor documentation. (Very few people\ndo this, after all. It\\'s a C compiler world now, so far as high-performance\ncode is concerned.)\n\nI also began a port to the _MIPS_, because we use those at work too, and this\n_is_ an excellent vehicle for learning a processor\\'s native instruction set.\nThe move away from using the host processor\\'s native condition-code flags\nproved to be a good one, because the _MIPS_ doesn\\'t even _have_ a condition\ncode register! However, though the resultant port compiles I was unable to get\nit to link properly so that it would actually execute. I have left finishing\nthis \\'til later, since my main objective (learning the _MIPS_) was accomplished\nand I was getting tired of working on it. The _PPC_ timing results imply that\nany improvement would hardly be worth the effort anyway.\n\nPerformance (_in seconds for the test run_):\n\n       MHz| 4     8     10    20    25    25    233     800     3000   2330\n       CPU| Z-80  68000 68010 68020 68030 68030 PPC G3  PPC G4  Pent-D iC2Duo\n       OS | CP/M  CP/M  DNIX  DNIX  NeXT  SVR4  OSX 2.8 OSX 3.5 XP/Cyg OSX 4.8\n       ===+ ====  ===== ===== ===== ===== ===== ======= ======= ====== =======\n       com   35*               19    20   18.5* 0.50    0.19\n       comt                    52    52         1.2     0.35\n       com10      82*     52   23    25\n       com10t            149   55    60\n       ccom              130   48    58         0.71    0.24    0.14   0.08\n       ccomt             260   91    92         1.3     0.38    0.17   0.13\n       comtest          2060  840   681         7.6     2.40\n       ccomtest                                 7.1     2.13    1.00   0.63\n\n     Note:  * Old numbers, not reproducible.  (Platforms long gone.)\n\nOf particular interest is that while for the _680x0_ platforms I could beat the\nC code by a substantial margin, for the _PPC_ it wasn\\'t worth the effort!\nModern C compilers seem to mate to modern RISC processors very well, imagine\nthat.\n\nWhat\\'s more, except for the large lookup table, the C version of the CPU is\nseveral kilobytes _smaller_! (This can be blamed on the assembly version\\'s\nin-line next macro, which doesn\\'t seem to make any speed difference when\nreplaced with a branch to a central next routine, which does make the assembly\nversion smaller.)\n\nMost instructive, though the results were not exactly what I had expected.\n(Which means this was a worthy exercise.)\n\nAlso note that the C-only version of the `comtest` runs _faster_ than the one\nthat includes assembly language, yet the simple assembler version runs faster\nthan the simple C version, though not by a huge margin. This tells me that the\nprocessor\\'s cache isn\\'t big enough, and that `comtest` is starting to thrash\nthe cache a bit more than `ccomtest` did, as it is larger. Interesting.\n\n(The `comtest` programs are for pitting the C and assembler versions of a\nsynthetic CPU against each other. Differences halt the simulation. _Both_ CPU\nmodels have gained by this procedure. The C-only test version is for debugging\nthe test harness itself, as it compares two identical CPU models, which can be\ntweaked to induce errors to ensure that they are caught by the harness.)\n\nTwo additional `Makefiles` have been added: `make.ppc` and `make.mips`. The\ndesired file should be linked to `Makefile`, as appropriate.\n\n## Update (2006)\n\nThe simulator has recently been ported to an all-C version, which runs not only\non the **UNIX** systems that the assembly-language version runs on (albeit\nslower), but also on much more modern machines. As one might imagine, hundreds\nto thousands of megahertz host machines really perk the old girl up, even with\nthe innate _2-3\\_\\_×_ reduction in efficiency of C versus the hand-tuned\nassembly language of the original.\n\nThe simulation environment has been enhanced to support **CP/M** drives `A:`\nthrough `P:`, the full set, though not to the associated 16 _USER_ spaces per\ndrive. These translate to directories (one each) under **UNIX**, and which are\nspecified on the command line. Also provided is a way to \\'bury\\' selected files\nwithin the simulator itself. This lets something like _WordStar_, which requires\noverlay files to always be available, edit files anywhere in the system, just\nlike any native editor.\n\nA `Makefile` for _Mac OS X_ has been added, named (obviously enough) `make.osx`,\nit should be linked to `Makefile` if appropriate. It\\'s the one to use for any\nnon-_680x0_ machine as it\\'s the one that\\'s C-only. Changing one `#define` at\nthe front specifies whether the target system is **DNIX**, **SVR4**, or **BSD**\nin flavor. It has been compiled and run unchanged (except for the flavor\nselector) on **OS X**, **Cygwin**, **FreeBSD**, and **Linux**.\n\nAs should be obvious, porting (to anything **UNIX**-ey) is now a nearly trivial\nexercise. The most system-specific code is in the directory listing logic,\nwhat\\'s there now is a choice of using the dirent package or a really nasty exec\nof find and sed. This could be converted to something else, the changes should\nbe localized. The next-most-system-specific code is the terminal handling code.\n(That\\'s the main reason for the flavor selector `#define` in the first place.)\n\nThe C simulation code was written from scratch, so it\\'s unrestricted.\n\n### Performance\n\nTimes (in seconds) largely collected with:\n\n    time ../com mac keycon\n\nA stopwatch was used for the host (_native_) **CP/M** platforms.\n\n            4     8     10    20    25    25    233     800     3000   2330\n            Z-80  68000 68010 68020 68030 68030 PPC G3  PPC G4  Pent-D iC2Duo\n            CP/M  CP/M  DNIX  DNIX  NeXT  SVR4  OSX 2.8 OSX 3.5 XP/Cyg OSX 4.8\n            ====  ===== ===== ===== ===== ===== ======= ======= ====== =======\n       com   35*               19    20   18.5*\n       comt                    52    52\n       com10      82*     52   23    25\n       com10t            149   55    60\n       ccom              130   48    58         0.67    0.24    0.14   0.08\n       ccomt             260   91    92         1.1     0.38    0.17   0.13\n       comtest          2060  840   681         6.0     2.13    1.00   0.63\n\n       Note: * Old numbers, not reproducible.  (Platforms long gone.)\n\nThis simulator is probably not the fastest one out there, nor is it particularly\ncomplete, nor is it feature-laden, and it is _far_ from the only one out there!\nWhat it _is_ is venerable, it has existed (in some form) since 1984, making it\none of the first, if not _the_ first, **CP/M** simulators designed for practical\nuse. (I won\\'t count any potential simulations that may have existed at chip\nmanufacturers.)\n\nI got it published in _Dr. Dobb\\'s Journal_ in 1986, my one and only\npublication.\n\n## Usage\n\nHere is a sample session in use. Like **WINE** (for _Microsoft Windows_\napplications under **UNIX**), you don\\'t ever actually run **CP/M** itself, only\nits applications.\n\n    $ ../com mbasic\n    BASIC-80 Rev. 5.21\n    [CP/M Version]\n    Copyright 1977-1981 (C) by Microsoft\n    Created: 28-Jul-81\n    39730 Bytes free\n    Ok\n    files\n    ZORK3   .DAT  ZORK3   .COM  ZORK2   .DAT  ZORK2   .COM  ZORK1   .DAT\n    ZORK1   .COM  WSOVLY1 .OVR  WSMSGS  .OVR  WS      .COM  WS      .COM\n    WIMSGS  .OVR  TUTORIAL.PIL  THRASH  .BAS  TESTPROG.COM  SQRTSIM .BAS\n    SPELSTAR.OVR  SPELSTAR.DCT  SARGON  .COM  PILOT   .TXT  PILOT   .COM\n    PARANOIA.BAS  MORTGAGE.BAS  MERGPRIN.OVR  MBASIC  .COM  MAILMRGE.OVR\n    MAC     .COM  LOAD    .COM  KEYCON  .ASM  JUNK    .COM  INSTALL .COM\n    FORTH   .COM  FFT     .BAS  CD      .COM\n    Ok\n    system\n    $\n\n## Introduction (1993)\n\nThis is a **CP/M** *2.2* Simulator that simulates an *8080* CPU and a\n**CP/M** *2.2* OS (if you can call it that) environment. The heart of the\nsimulator is written in _680x0_ assembly language for speed. It has been tested\nunder **DNIX** (a **SVR2** compatible with many **SVR3**, **BSD**, **Xenix**,\nand **Sun** extensions), on a _68030_ **NeXT**, and on a _68030_ **Amiga**\nrunning **SVR4**.\n\nOne \\'benchmark\\' shows that on machines of the _68020_/_68030_ class the\nsimulator performs about as well as a 7 MHz _Z-80_ would. Other tests indicate\nthat this is somewhat optimistic.\n\n## Why CP/M?\n\nWhy not? I updated this program (originally running under **CP/M-68K**, and\npublished in the _January 1986_ issue of _Dr._ _Dobb\\'s_ _Journal_ _\\[of_\n_Computer_ _Calisthenics_ _and_ _Orthodontia\\]_) out of curiosity to see how it\nwould run on something newer than the _68000_ it was originally running on in\n1984, and out of a perverse desire to make my colleagues sick.\n\n## What You Get\n\nThe simulator gives you a simple **CP/M** run-time environment with only one\ndrive (`A:`), which is the current directory when the simulator is invoked.\n\nThere is no _CCP_ (the command processor, analogous to the **UNIX** shell);\nprograms must be run individually under the simulator. The simulator can be\ninvoked so that the listing (printer) output goes to a file (otherwise it is\ndiscarded).\n\nIt normally converts **H19** escape sequences (and a couple of other oddballs)\nto **VT100** sequences, since much **CP/M** software doesn\\'t know what a\n**VT100** is, yet it is the current **UNIX** _\\'standard\\'_. If **CP/M** had any\n_\\'standard\\'_ (it didn\\'t, really) it was the **H19**. This feature can be\ndisabled, if needed.\n\nSimilarly, the simulation optionally maps `DEL` to `BS` on keyboard input, since\n`BS` is the **CP/M** _\\'standard\\'_, whereas `DEL` is many **UNIX** systems\\'\nstandard. The simulator maps all filenames to uppercase (for display by **CP/M**\nprograms), and converts them to lowercase when actually doing file I/O.\n\nSeveral of the more esoteric _BDOS_ calls are not supported.\n\nPlease remember that **CP/M** text files use both carriage returns and line\nfeeds (one each) to delimit lines, and the end-of-file character is an embedded\n_Control-Z_. The `EOF` character is needed because **CP/M** files are always\nmultiples of 128 bytes - there is no byte-level file length indication. **CP/M**\nprograms can get annoyed if files fed to them don\\'t conform to these\nexpectations.\n\n## Porting\n\nThe hardest part of porting this program is getting the synthetic CPU (assembly\nlanguage) module to assemble since in the infinite wisdom of the **UNIX** world\nno vendor seems to use Motorola\\'s standard mnemonics.\n\nThe module is written using the **DNIX** assembler syntax (supposedly MIT\nmnemonics with Motorola standard addressing syntax), and is sed\\'ed to whatever\nis necessary. (It actually started life in 1984 under **CP/M-68K**, using\nMotorola standard mnemonics, but I converted it to be most compatible with\n**DNIX**, since that\\'s what I use most of the time.) The C pre-processor is\nused on the assembly module, so some sed-ing is always needed to get things like\nthe octothorpe (\\#) character through it. If your cpp can\\'t hack it, or is\nnonexistent, more work will be required.\n\nI have left as an exercise for the reader the writing of the synthetic CPU\nmodule for non-_680x0_ systems. I considered writing one in C to serve as a\nmodel, but it would function so slowly on the systems I use (the ones I _did_\nget it working on) that I didn\\'t want to waste my time - it\\'s not like I\n_need_ a **CP/M** simulator for anything. The energetic could write one fairly\neasily (how hard can an _8080_ be after all?), but for real speed a new\nassembly-language module should be written.\n\nIt would be particularly efficient on an _x86_ machine, since the slowest part\nof the simulation is getting the flags right. The _x86_ and the _8080_ have the\nsame flags, so it\\'s probable that the _8080_ flags could just be taken straight\nout of the _x86_ flags register (i.e. no work at all). However, as I think that\nmost _x86_ machines are evil incarnate I refuse to take a stab at the project\n(except maybe with a wooden stake).\n\nThere are three `Makefiles` provided: one for **DNIX**, one for **NeXT**, and\none for vanilla (_?_) **System V**. The appropriate file should be linked to the\nname `Makefile`, then you should just be able to type \\'`make`\\'. If I were\nbetter at multi-system configuration programs this could probably have been made\nmore elegant, but it works well enough for me.\n\n## Terms\n\nAs was the case for its predecessor, this program is in the **Public**\n**Domain**. All I ask is that my name be left on the code if it is used\nelsewhere. (As if that\\'s likely at _this_ late date!)\n\nThe _Z-80_ simulation routines were taken from an independent Amiga\nport/enhancement of the original code done by _Charlie_ _Gibbs_ and _Willi_\n_Kusche_. Their code is slightly more restricted. I have placed their disclaimer\nat the front of `com.c`; their code is conditionally included in the simulator.\nIf it isn\\'t included, you get a plain _8080_ CPU with a few _Z-80_ instructions\n(as before, under **CP/M-68K**).\n\n\\*Enjoy**\\*!**\n\n## Background (1984)\n\nThis simulator was written in desperation in 1983 when I was working on an\n_S100_ bus **CP/M-68K** system and trying to integrate a hard disk controller.\nThe disk formatter I wrote according to the (expensive!) controller\\'s\ndocumentation simply did not work, yet the card was one that worked very well in\nregular **CP/M** systems, using a formatting program that came with the card.\n\nI had two options: either borrow one of the _EM-180_ emulators from work, _and_\na functioning _S100_ **CP/M** system, and trap how the card was being talked to,\nor write a simulator and do the same trapping in software. The latter seemed\nmore interesting, less bulky, and didn\\'t inconvenience anyone else. It also\noffered the possibility of running existing applications (like word processors\nor spreadsheets) on the new hardware. (Native applications of this sort were\nneither expected to be particularly available, nor inexpensive even if they\nwere.)\n\nThe choice was easy.\n\nBecause the host and target systems were both **CP/M**, potential problem areas\nlike terminal I/O or disk files didn\\'t need any special treatment or\ntranslation, requests could just be forwarded directly to the host OS. The\nentire thing could easily be written in assembly language, which was a necessity\nfor the synthetic CPU to have the best performance anyway.\n\nOnce the simulator worked well enough to host the hard disk formatter it became\nclear that the documentation for the controller card was wrong. One of the\nregisters required the 2\\'s-complement of the desired value to be written to it,\na fact the documentation didn\\'t see fit to mention. With this change my own\nformatter program worked correctly, and in short order my system then had a\nwhopping _ST-506_ **5MB** hard disk on it!\n\nShortly after that the simulator worked well enough to run **MBASIC**, etc. The\nsimulator was _8080_-only, all that was necessary to run 90% of **CP/M**\nprograms. Adding a couple of _Z-80_ instructions, the ones the _BDS C_ compiler\nwanted to use in its objects, brought that up to something like _**99%**_.\n\nThe final Version 1.0 simulator transformed this expensive system from\nlaboratory curiosity to practical computer, nearly overnight. (Although the\nsimulation ran at less than half the speed of the real thing. Native programs,\nthough, _were_ blazingly fast in comparison.)\n\n## Contact\n\n### Important Notice\n\n- **_NOTE_**: **PLEASE** just\n  **[open an issue here on GitHub](https://github.com/johnsonjh/com-cpm/issues)!**\n  - **Don't** bother Jim on the phone, please!\n- All fixes sent to me here **will** be sent upstream.\n\n### Original Author\n\n- [Jim Cathey](http://formicapeak.com/~jimc)\n- **Email**: [jim.cathey.pb@gmail.com](mailto:jim.cathey.pb@gmail.com)\n- **Phone**: `+1 (509) 926-7801` (_I prefer e-mail, where possible_.)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnsonjh%2Fcom-cpm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohnsonjh%2Fcom-cpm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnsonjh%2Fcom-cpm/lists"}