{"id":158,"date":"2024-04-19T03:49:00","date_gmt":"2024-04-19T03:49:00","guid":{"rendered":"https:\/\/thebrokenpipe.com\/blog\/?p=158"},"modified":"2026-04-26T12:15:14","modified_gmt":"2026-04-26T12:15:14","slug":"86-dos-0-11-from-scratch","status":"publish","type":"post","link":"https:\/\/thebrokenpipe.com\/blog\/86-dos-0-11-from-scratch\/","title":{"rendered":"86-DOS 0.11 from Scratch"},"content":{"rendered":"\n<p>At the end of last year, a <a href=\"https:\/\/archive.org\/details\/86-dos-version-0.1-c-serial-11-original-disk\">copy of 86-DOS 0.11 for the Cromemco 4FDC controller<\/a> surfaced. It is the earliest released version of 86-DOS, the earliest operating system for the x86 architecture. Having done some legacy work dealing with real mode x86 before, I thought I could maybe challenge myself and build a copy of 86-DOS 0.11 from scratch.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Source Code Reconstruction<\/h2>\n\n\n\n<p>Clearly, to build 86-DOS from scratch, we need the source code. While the original source code would be preferable, good luck finding a copy. Earlier this year, I began a project to <a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\">reconstruct the source code of 86-DOS 0.11<\/a> through disassembly, and I&#8217;ll briefly discuss it here. The goal of the source reconstruction project is to create source files that reassemble back to the original binaries and look indistinguishable from the original source code.<\/p>\n\n\n\n<p>Before I begin, I want to list all the components of 86-DOS 0.11, in case you&#8217;re not familiar with them.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Boot Record (<code>BOOT<\/code>)<\/li>\n\n\n\n<li>I\/O System (<code>DOSIO<\/code>)<\/li>\n\n\n\n<li>86-DOS Kernel (<code>86DOS<\/code>)<\/li>\n\n\n\n<li>Command Interpreter (<code>COMMAND<\/code>)<\/li>\n\n\n\n<li>8086 Assembler (<code>ASM<\/code>)<\/li>\n\n\n\n<li>Chess (<code>CHESS<\/code>)<\/li>\n\n\n\n<li>Line Editor (<code>EDLIN<\/code>)<\/li>\n\n\n\n<li>Intel HEX To Binary Conversion Utility (<code>HEX2BIN<\/code>)<\/li>\n\n\n\n<li>CP\/M Disk Reader (<code>RDCPM<\/code>)<\/li>\n\n\n\n<li>System Transfer Utility (<code>SYS<\/code>)<\/li>\n\n\n\n<li>Z80 to 8086 Source Code Translator (<code>TRANS<\/code>)<\/li>\n<\/ul>\n\n\n\n<!--more-->\n\n\n\n<p>Alright, now let&#8217;s dive into it. I disassembled <code>COMMAND<\/code> first because when I ran it under a later version of 86-DOS, it gave me garbled output, and I wanted to figure out why.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"720\" height=\"350\" src=\"https:\/\/thebrokenpipe.com\/blog\/wp-content\/uploads\/2024\/04\/monitor_1_20240415-195115-352.png\" alt=\"\" class=\"wp-image-178\" srcset=\"https:\/\/thebrokenpipe.com\/blog\/wp-content\/uploads\/2024\/04\/monitor_1_20240415-195115-352.png 720w, https:\/\/thebrokenpipe.com\/blog\/wp-content\/uploads\/2024\/04\/monitor_1_20240415-195115-352-300x146.png 300w\" sizes=\"auto, (max-width: 720px) 100vw, 720px\" \/><figcaption class=\"wp-element-caption\">86-DOS 0.11&#8217;s <code>COMMAND.COM<\/code> under 86-DOS 0.34, displaying a garbled directory listing.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>It turned out that the garbled output was caused by an API change between 86-DOS 0.11 and 86-DOS 0.34, where the Search First and Search Next functions in 0.11 returned the 16-byte directory entry of the found file, while 0.34 returned an unopened FCB.<\/p>\n\n\n\n<p>Next, I disassembled <code>SYS<\/code> and <code>HEX2BIN<\/code> &#8211; they are the two smallest utilities. It&#8217;s interesting that <code>SYS<\/code> has the number of system sectors to transfer at location 3, possibly to allow users to patch the binary for custom disk formats.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro padding-disabled\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:8;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#002339;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\tORG\t100H\n\tPUT\t100H\n\n\tJMP\tSTART\n\nSECS:\tDW\t52\t;Patch for different configs\n\nSTART:\n\tMOV\tAL,&#91;FCB&#93;<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki slack-ochin\" style=\"background-color: #FFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #002339\">\tORG\t<\/span><span style=\"color: #174781\">100H<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\tPUT\t<\/span><span style=\"color: #174781\">100H<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #7B30D0\">JMP<\/span><span style=\"color: #002339\">\tSTART<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">SECS:<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DW<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">52<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #357B42; font-style: italic\">;Patch for different configs<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">START:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #7B30D0\">MOV<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">AL<\/span><span style=\"color: #002339\">,&#91;FCB&#93;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>It&#8217;s also worth noting that <code>SYS<\/code>&#8216; bad drive specification message does not have a terminating dollar sign. This causes the program to spew out garbage when you specify an invalid drive.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro padding-disabled\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:8;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#002339;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>ERWRIT:\tDB\t\"Disk write error$\"\nDRVBAD:\tDB\t\"Bad drive specification\"\n\nEND:<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki slack-ochin\" style=\"background-color: #FFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #7EB233\">ERWRIT:<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DB<\/span><span style=\"color: #002339\">\t&quot;Disk write error$&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">DRVBAD:<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DB<\/span><span style=\"color: #002339\">\t&quot;Bad drive specification&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">END:<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Then I shared my progress and got in touch with <a href=\"http:\/\/cini.classiccmp.org\/\">Rich Cini<\/a>, <a href=\"https:\/\/github.com\/LucasBrooks\">Lucas Brooks<\/a> and starfrost, forming a group chat. With some help from Rich and Lucas, I managed to reconstruct the source code of the kernel. This kernel is interesting &#8211; I believe it is the only 86-DOS kernel that doesn&#8217;t use overlapping init code and data, a technique seen in later kernels to save a few bytes of memory. Something else worth mentioning is that, while I&#8217;m not 100% certain, I think the name QDOS was used in the header of the original <code>86DOS.A86<\/code>, like this:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro padding-disabled\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:8;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#002339;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>; QDOS  High-performance operating system for the 8086  version 0.11\n;\tby Tim Paterson<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki slack-ochin\" style=\"background-color: #FFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #357B42; font-style: italic\">; QDOS  High-performance operating system for the 8086  version 0.11<\/span><\/span>\n<span class=\"line\"><span style=\"color: #357B42; font-style: italic\">;\tby Tim Paterson<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Why? Because of this snippet from a court proceeding transcript:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-style-default has-small-font-size is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Q. As I understand your testimony earlier, this term QDOS was used only internally at Seattle Computer Products?<br>A. Right. Since it appeared in the source code, however, then when other people saw the source code, it had essentially leaked out the use of that term. It was after that that I realized I needed to adjust the source code title as well.<\/p>\n<cite><a href=\"https:\/\/casetext.com\/case\/paterson-v-little\">Paterson v. Little, Brown Co.<\/a> &#8211; Document 14 (Exhibit A)<\/cite><\/blockquote>\n\n\n\n<p>Who leaked it? I think Microsoft did, because Microsoft used the name QDOS in <a href=\"https:\/\/archive.org\/details\/orear-collection\/QDOS%20BIOS%20and%20Prototype%20IBM%20PC\/\">their internal documents<\/a>.<\/p>\n\n\n\n<p>Anyway, we&#8217;re sidetracked. Back to the source reconstruction, the next thing I tackled was <code>RDCPM<\/code>, followed by <code>EDLIN<\/code>. <code>RDCPM<\/code> is hard-coded to handle four 8&#8243; SSSD CP\/M 2.x disks, which does not match the configuration of two 8&#8243; drives and one 5.25&#8243; drive (<code>COMBCRO<\/code>) used by this copy of 86-DOS. Unlike later versions of <code>RDCPM<\/code>, it does not have support for custom drive tables, and it actually initialises the allocation bitmap fields of the DPT.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro padding-disabled\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:8;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#002339;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>IBM:\n\tDW\t26\t;Sectors per track\n\tDB\t3\t;Block shift\n\tDB\t7\t;Block mask\n\tDB\t0\t;Extent mask\n\tDW\t242\t;Disk size - 1\n\tDW\t63\t;Directory entries - 1\n\tDB\t0C0H\t;Directory allocation bitmap 0\n\tDB\t0\t;Directory allocation bitmap 1\n\tDW\t16\t;Directory check vector size\n\tDW\t2\t;Tracks to skip\n\tDW\tMOD6\t;Modulo-6 sector translate table<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki slack-ochin\" style=\"background-color: #FFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #7EB233\">IBM:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DW<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">26<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #357B42; font-style: italic\">;Sectors per track<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DB<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">3<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #357B42; font-style: italic\">;Block shift<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DB<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">7<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #357B42; font-style: italic\">;Block mask<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DB<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">0<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #357B42; font-style: italic\">;Extent mask<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DW<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">242<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #357B42; font-style: italic\">;Disk size - 1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DW<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">63<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #357B42; font-style: italic\">;Directory entries - 1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DB<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">0C0H<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #357B42; font-style: italic\">;Directory allocation bitmap 0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DB<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">0<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #357B42; font-style: italic\">;Directory allocation bitmap 1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DW<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">16<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #357B42; font-style: italic\">;Directory check vector size<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DW<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">2<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #357B42; font-style: italic\">;Tracks to skip<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DW<\/span><span style=\"color: #002339\">\tMOD6\t<\/span><span style=\"color: #357B42; font-style: italic\">;Modulo-6 sector translate table<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><code>EDLIN<\/code> is interesting in that it uses <code>INT 33<\/code> (<code>21H<\/code>) instead of the CP\/M-styled <code>CALL BDOS<\/code> (<code>5<\/code>). Given that <code>INT 21H<\/code> was implemented after <code>CALL 5<\/code>, it shows that <code>EDLIN<\/code> was indeed the newest utility, written from scratch in 8086 assembly for 86-DOS.<\/p>\n\n\n\n<p>If my memory serves me correctly, after <code>RDCPM<\/code> and <code>EDLIN<\/code>, I asked Rich to email Tim Paterson to see if he still had the original source code, but unfortunately, he didn&#8217;t. However, in his response, he said:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote has-small-font-size is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">The Chess program was Sargon. We had it running on my Z80 computer in college ca. 1978. I used the source code translator to port it to DOS.<\/p>\n<cite>Tim Paterson (email exchange)<\/cite><\/blockquote>\n\n\n\n<p>So, I obtained a copy of the Sargon Chess source code, translated it from Intel 8080 mnemonics to Zilog Z80, and then translated the Z80 source to 8086 using Paterson&#8217;s <code>TRANS<\/code> utility. It was a reasonably close match, and after a few hours of manual tweaking, I managed to produce matching binaries. However, the <code>ATTACK<\/code> routine and its subroutines didn&#8217;t match Sargon&#8217;s, and since I don&#8217;t know how to play chess, I didn&#8217;t assign meaningful label names and comments to them initially. Later, someone provided me with some pointers on the basic logic of those routines, and I finally managed to label and comment everything. Correctness? No guarantee! (If you know the x86 assembly language and how to play chess, you&#8217;re more than welcome to double-check my comments!)<\/p>\n\n\n\n<p>Anyway, <code>CHESS<\/code> was almost a direct translation of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Sargon_(chess)\">Dan and Kathleen&#8217;s work<\/a>, and the beginning of the original source code explicitly stated &#8220;No part of this publication may be reproduced without prior written permission,&#8221; so no wonder it was removed by the next release, hehe.<\/p>\n\n\n\n<p>After <code>CHESS<\/code>, I worked on the boot record and I\/O system. Existing code from 86-DOS &#8220;0.2&#8221; and 0.34 helped a lot, but the 0.11 boot record is completely different. The hundred or so bytes took me a few hours to fully understand, mostly because I had to read the manuals of the <a href=\"https:\/\/deramp.com\/downloads\/mfe_archive\/010-S100%20Computers%20and%20Boards\/00-Cromemco\/10-Cromemco%20S100%20Boards\/4FDC\/4fdc.pdf\">Cromemco 4FDC<\/a> and the <a href=\"https:\/\/bitsavers.org\/pdf\/tarbell\/Tarbell_Double_Density_Floppy_Disk_Interface_Jul81.pdf\">Tarbell DD<\/a> disk controller. Yes, I also tried to reconstruct the Tarbell-specific code. The I\/O system has a few differences compared to later I\/O systems &#8211; most importantly, the cluster count for the 5.25&#8243; format is wrong and it lacks support for fast-seek. The delays are also much longer compared to later versions of 86-DOS.<\/p>\n\n\n\n<p>Anyway, I then made a Tarbell DD copy which worked fine under emulation, and sent that to Rich to test on his physical SCP Gazelle. It failed spectacularly. Eventually, Rich managed to find the instruction where the code locked up &#8211; <code>INB DISK+4<\/code>. The culprit was that the I\/O port <code>DISK<\/code> works for both Tarbell and Cromemco, however <code>DISK+4<\/code> works only for Cromemco, and I forgot to change it from <code>DISK+4<\/code> to <code>DISK<\/code> when I reconstructed the Tarbell-specific code.<\/p>\n\n\n\n<p>Next came <code>TRANS<\/code>, Paterson&#8217;s Z80 to 8086 translator. It was the easiest component to disassemble because Microsoft open-sourced the code of a later version, and the two are virtually identical. Nothing interesting here, moving on.<\/p>\n\n\n\n<p>And we&#8217;re finally at the resident 8086 assembler, <code>ASM<\/code>. This bad boy took me an entire month because it&#8217;s huge, complex, and machine-translated. I thought it was going to be a walk in the park because the source code of a later version is available (like <code>TRANS<\/code>), but clearly, I was wrong. The open-sourced version is very different, and a lot of things have been rewritten. The version included with 86-DOS 0.11 is essentially a direct translation of the SCP 8086 Cross Assembler from Z80 to 8086, without too much clean-up or optimisation for the 8086 (this is actually a good thing, I&#8217;ll talk about it in the next section). Just to give you an idea, I worked with code like this:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro padding-disabled\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:8;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#002339;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>CODE:12E5 loc_112E5:                              ; CODE XREF: CODE:12B1\u2191p\nCODE:12E5                                         ; CODE:1304\u2193p ...\nCODE:12E5                 xchg    bx, dx\nCODE:12E7                 push    bx\nCODE:12E8                 mov     dl, &#91;bx&#93;\nCODE:12EA                 mov     dh, 0\nCODE:12EC                 lahf\nCODE:12ED                 inc     bx\nCODE:12EE                 sahf\nCODE:12EF                 lahf\nCODE:12F0                 add     bx, dx\nCODE:12F2                 rcr     si, 1\nCODE:12F4                 sahf\nCODE:12F5                 rcl     si, 1\nCODE:12F7                 mov     dl, &#91;bx&#93;\nCODE:12F9                 lahf\nCODE:12FA                 inc     bx\nCODE:12FB                 sahf\nCODE:12FC                 mov     dh, &#91;bx&#93;\nCODE:12FE                 mov     al, dl\nCODE:1300                 or      al, dh\nCODE:1302                 jz      short loc_11307\nCODE:1304                 call    loc_112E5<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki slack-ochin\" style=\"background-color: #FFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">12E5<\/span><span style=\"color: #002339\"> <\/span><span style=\"color: #7EB233\">loc_112E5:<\/span><span style=\"color: #002339\">                              <\/span><span style=\"color: #357B42; font-style: italic\">; CODE XREF: CODE:12B1\u2191p<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">12E5<\/span><span style=\"color: #002339\">                                         <\/span><span style=\"color: #357B42; font-style: italic\">; CODE:1304\u2193p ...<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">12E5<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">xchg<\/span><span style=\"color: #002339\">    <\/span><span style=\"color: #174781\">bx<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">dx<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">12E7<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">push<\/span><span style=\"color: #002339\">    <\/span><span style=\"color: #174781\">bx<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">12E8<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">mov<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">dl<\/span><span style=\"color: #002339\">, &#91;<\/span><span style=\"color: #174781\">bx<\/span><span style=\"color: #002339\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12EA                 <\/span><span style=\"color: #7B30D0\">mov<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">dh<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12EC                 <\/span><span style=\"color: #7B30D0\">lahf<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12ED                 <\/span><span style=\"color: #7B30D0\">inc<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">bx<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12EE                 <\/span><span style=\"color: #7B30D0\">sahf<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12EF                 <\/span><span style=\"color: #7B30D0\">lahf<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12F0                 <\/span><span style=\"color: #7B30D0\">add<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">bx<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">dx<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12F2                 <\/span><span style=\"color: #7B30D0\">rcr<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">si<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12F4                 <\/span><span style=\"color: #7B30D0\">sahf<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12F5                 <\/span><span style=\"color: #7B30D0\">rcl<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">si<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12F7                 <\/span><span style=\"color: #7B30D0\">mov<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">dl<\/span><span style=\"color: #002339\">, &#91;<\/span><span style=\"color: #174781\">bx<\/span><span style=\"color: #002339\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12F9                 <\/span><span style=\"color: #7B30D0\">lahf<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12FA                 <\/span><span style=\"color: #7B30D0\">inc<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">bx<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12FB                 <\/span><span style=\"color: #7B30D0\">sahf<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12FC                 <\/span><span style=\"color: #7B30D0\">mov<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">dh<\/span><span style=\"color: #002339\">, &#91;<\/span><span style=\"color: #174781\">bx<\/span><span style=\"color: #002339\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">12FE                 <\/span><span style=\"color: #7B30D0\">mov<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">al<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">dl<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1300<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">or<\/span><span style=\"color: #002339\">      <\/span><span style=\"color: #174781\">al<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">dh<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1302<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">jz<\/span><span style=\"color: #002339\">      short loc_11307<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1304<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">call<\/span><span style=\"color: #002339\">    loc_112E5<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro padding-disabled\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:8;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#002339;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>CODE:1367 loc_11367:                              ; CODE XREF: CODE:1381\u2193j\nCODE:1367                 lahf\nCODE:1368                 add     bx, bx\nCODE:136A                 rcr     si, 1\nCODE:136C                 sahf\nCODE:136D                 rcl     si, 1\nCODE:136F                 mov     al, dl\nCODE:1371                 adc     al, al\nCODE:1373                 daa\nCODE:1374                 mov     dl, al\nCODE:1376                 mov     al, dh\nCODE:1378                 adc     al, al\nCODE:137A                 daa\nCODE:137B                 mov     dh, al\nCODE:137D                 rcl     cl, 1\nCODE:137F                 dec     ch\nCODE:1381                 jnz     short loc_11367\nCODE:1383                 retn<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki slack-ochin\" style=\"background-color: #FFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1367<\/span><span style=\"color: #002339\"> <\/span><span style=\"color: #7EB233\">loc_11367:<\/span><span style=\"color: #002339\">                              <\/span><span style=\"color: #357B42; font-style: italic\">; CODE XREF: CODE:1381\u2193j<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1367<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">lahf<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1368<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">add<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">bx<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">bx<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">136A                 <\/span><span style=\"color: #7B30D0\">rcr<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">si<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">136C                 <\/span><span style=\"color: #7B30D0\">sahf<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">136D<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">rcl<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">si<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">136F                 <\/span><span style=\"color: #7B30D0\">mov<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">al<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">dl<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1371<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">adc<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">al<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">al<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1373<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">daa<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1374<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">mov<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">dl<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">al<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1376<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">mov<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">al<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">dh<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1378<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">adc<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">al<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">al<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">137A                 <\/span><span style=\"color: #7B30D0\">daa<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">137B                 <\/span><span style=\"color: #7B30D0\">mov<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">dh<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">al<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">137D<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">rcl<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">cl<\/span><span style=\"color: #002339\">, <\/span><span style=\"color: #174781\">1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #002339\">137F                 <\/span><span style=\"color: #7B30D0\">dec<\/span><span style=\"color: #002339\">     <\/span><span style=\"color: #174781\">ch<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1381<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">jnz<\/span><span style=\"color: #002339\">     short loc_11367<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">CODE:<\/span><span style=\"color: #174781\">1383<\/span><span style=\"color: #002339\">                 <\/span><span style=\"color: #7B30D0\">retn<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>If I just saw these snippets without any context, I would actually believe that they&#8217;re disassemblies of strings or random data rather than x86 machine code. So yeah, the story is they&#8217;re translated from Z80, so they have a lot of boilerplate and don&#8217;t make total&#8230; or, well, much sense at all. I have to admit that despite having written an 8086 assembler before and spending like a month on this thing, I still cannot fully understand Paterson&#8217;s code.<\/p>\n\n\n\n<p>You can find the source code reconstruction project on my GitHub: <a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\">https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Enter <s>CP\/M<\/s> Cromemco CDOS<\/h2>\n\n\n\n<p>Why am I talking about CP\/M when this is a post about 86-DOS? Well, we&#8217;re building 86-DOS from scratch, and as we all know, 86-DOS did not just magically appear out of nowhere. It was actually written and built by Paterson using the Cromemco CDOS operating system.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote has-small-font-size is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">My development process at SCP began, of course, using CP\/M tools. I wrote the 8086 assembler hosted on Cromemco CDOS. I used it to write the Monitor, which lived in ROM on the CPU Support board. I used MicroPro WordMaster (not WordStar) as my editor. When bringing up DOS, I would use CP\/M tools to write the binary to the first sectors of the disk, then boot it with the Monitor. The first working version of DOS was 0.10, but a bug was quickly found and 0.11 was, I think, the first released publicly. <\/p>\n\n\n\n<p class=\"has-small-font-size\">Once DOS was fully functional, I needed a better editor to use it. I used a good Z80 disassembler on WordMaster, verifying I could rebuild it for CP\/M. Then I set the translator loose on it and it was ported to DOS. So my ongoing development of DOS at SCP took place on an 8086 using my tools and the translated WordMaster. The translator was also how the assembler (and the translator) were originally ported. I\u2019ve often though that I may the only one who took advantage of translation compatibility.<\/p>\n<cite>Tim Paterson (email exchange)<\/cite><\/blockquote>\n\n\n\n<p>Before I talk about things in detail, let&#8217;s take a look at what we know so far.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>86-DOS was assembled under CDOS.<\/li>\n\n\n\n<li>The SCP assembler (hereinafter referred to as ASM86) was used to assemble the source code.<\/li>\n\n\n\n<li>A CP\/M tool was used to write the binaries to disk.<\/li>\n<\/ul>\n\n\n\n<p>And what do we have at the moment?<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Cromemco CDOS<\/li>\n<\/ul>\n\n\n\n<p>We&#8217;re missing <code>ASM86<\/code>, which ran under CDOS, and the CP\/M tool Paterson used to write the binaries! Luckily, from Paterson&#8217;s quote above and from my experience disassembling <code>ASM<\/code>, <code>ASM<\/code> is (almost) the direct output of running <code>TRANS<\/code> on <code>ASM86<\/code>, so theoretically, the translation can be undone to obtain a copy of <code>ASM86<\/code>. In practice, it was not that straightforward.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Back to Z80<\/h3>\n\n\n\n<p><code>TRANS<\/code> was written based on the <a href=\"http:\/\/www.bitsavers.org\/pdf\/intel\/ISIS_II\/9800642A_MCS-86_Assembly_Language_Converter_Operating_Instructions_for_ISIS-II_Users_Mar79.pdf\">translation rules published by Intel for the 8080 processor<\/a>, so I used that as the guide for my 8086 to Z80 translator &#8211; <code>CIS<\/code> (the name <code>CIS<\/code> comes from the Latin prefix <em>cis<\/em> used in cis-trans isomerism, where <em>cis<\/em> means &#8220;this side&#8221; and <em>trans<\/em> means &#8220;the other side&#8221;).<\/p>\n\n\n\n<p>It was a horrible experience doing the reverse of <code>TRANS<\/code> because multiple Z80 instructions can be translated into the same sequence of 8086 instructions. Therefore, the context needs to be analysed in order to determine which Z80 instruction to output. The simplest case is something like this:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro padding-disabled\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:8;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#002339;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\tJNZ\tL0002\n\tCALL\tGETSYM\t\t;If no tokens read yet, read first one\nL0002:\t<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki slack-ochin\" style=\"background-color: #FFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #7B30D0\">JNZ<\/span><span style=\"color: #002339\">\tL0002<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #7B30D0\">CALL<\/span><span style=\"color: #002339\">\tGETSYM\t\t<\/span><span style=\"color: #357B42; font-style: italic\">;If no tokens read yet, read first one<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">L0002:<\/span><span style=\"color: #002339\">\t<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>There are 2 possible translations:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NZ,L0002<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CALL&nbsp;&nbsp;&nbsp;&nbsp;GETSYM<br>L0002:<\/td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CALL&nbsp;&nbsp;&nbsp;&nbsp;Z,GETSYM<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>While the one on the left is more logical in the context of machine translation, as it&#8217;s a 1:1 mapping of 8086 instructions to Z80 instructions, the one on the right makes more sense. Should we use the left-hand side one because it&#8217;s easier? No, because we want the output Z80 code to be as readable as possible. Does that mean we use the right-hand side one? Not exactly, because in the event that some other code branches to <code>L0002<\/code>, we need to preserve the <code>L0002<\/code> label. So, we need to scan the source code to check the number of times <code>L0002<\/code> is referenced to determine whether the label should be kept. This is only the simplest case, there are more complex cases, and as you can imagine, the entire process wasn&#8217;t all that straightforward.<\/p>\n\n\n\n<p>The situation was exacerbated by Paterson manually optimising some 16-bit operations to use 8086-specific features and removing redundant boilerplate. I had to deal with things like 16-bit comparisons and string operations, which were not fun at all. Did I mention shadow registers being mapped into memory? How do you tell which memory address corresponds to which register?<\/p>\n\n\n\n<p>Look, if I wanted to delve into the details, I could probably write an entire article just on this boring stuff. So, I&#8217;m just going to end it here and say that in the end, I managed to obtain a Z80 source file that produces almost the same output as the original 8086 code when run through <code>TRANS<\/code> again. It runs and works great under CDOS.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CDOS version 02.36\nCromemco Disk Operating System\nCopyright (c) 1978, 1980 Cromemco, Inc.\n\nA.asm86 demo.bcz\n\nSeattle Computer Products 8086 Assembler Version 1.00\nCopyright 1979 by Seattle Computer Products, Inc.\n\n\n\nError Count =    0\n\nA.<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><code>DOSGEN<\/code><\/h3>\n\n\n\n<p>We&#8217;re also missing the program Paterson used to write 86-DOS binaries to disk. It&#8217;s clearly Paterson&#8217;s own program, and when Rich asked Paterson himself, he said he had forgotten the details.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote has-small-font-size is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">I don\u2019t remember how this was done, but I can tell you how I think I would do it. Clearly there was some CP\/M-based tool that let me write to absolute sectors of the disk. It wouldn\u2019t have been hard to create a memory image by hand for the FAT and directory entries for COMMAND. This would only have to be done once to allow any number of testing iterations (which would always be rewritten in the same spot). I can imagine that RDCPM quickly became a priority, and that it was added to the initial disk the same way. Or COPY could be used on command.com to make another directory entry and allocate that amount of space.<\/p>\n<cite>Tim Paterson (email exchange)<\/cite><\/blockquote>\n\n\n\n<p>So, a system transfer program from scratch it is. Based on what Paterson said, I designed it to have two modes &#8211; system transfer (similar to DOS&#8217; <code>SYS<\/code>) and filesystem creation. The system transfer mode, like <code>SYS<\/code>, simply copies <code>BOOT<\/code>, <code>DOSIO<\/code> and <code>86DOS<\/code> to the reserved system tracks of the destination disk, except it reads the system from the filesystem instead of the system area of an existing system disk. The filesystem creation mode additionally creates and writes a FAT image which includes the files <code>COMMAND.COM<\/code> and <code>RDCPM.COM<\/code>. This gives you the ability to create a fully bootable 86-DOS disk from scratch. <code>RDCPM<\/code> is required for transferring other files from CP\/M disks once 86-DOS is booted, so it is also added to the FAT image.<\/p>\n\n\n\n<p><code>DOSGEN<\/code> takes the following parameters: <code>[x:]DOSGEN y: [N]<\/code><\/p>\n\n\n\n<p>where<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>x<\/td><td>is an optional disk drive specifier indicating the location of the <code>DOSGEN.COM<\/code> file. This parameter is required only if the COM file is NOT located on either drive A or the current drive. Legal values are A, B, C, and D.<\/td><\/tr><tr><td>y<\/td><td>is a disk drive specifier indicating the disk upon which the 86-DOS system is to be written.<\/td><\/tr><tr><td><code>N<\/code><\/td><td>is an optional switch indicating that a new file system is to be put on the destination disk. If this switch is specified, a file system with the files <code>COMMAND.COM<\/code> and <code>RDCPM.COM<\/code> will be written alongside the system.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>To copy 86-DOS to a new floppy disk, you must have the files <code>BOOT.COM<\/code>, <code>DOSIO.COM<\/code> and <code>86DOS.COM<\/code> on the current drive. If a new file system is to be created, <code>COMMAND.COM<\/code> and <code>RDCPM.COM<\/code> must also exist.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Analysis of Uninitialised Data<\/h2>\n\n\n\n<p>We now have everything we need, but we&#8217;re still missing the build environment. Luckily, most 86-DOS 0.11 binaries have uninitialised data within them, and they contain information about the environment where the original copy of 86-DOS 0.11 was built.<a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#analysis-of-uninitialized-data\"><\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is Uninitialised Data<a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#what-is-uninitalized-data\"><\/a><\/h3>\n\n\n\n<p>SCP&#8217;s 8086 assembler (hereinafter referred to as ASM86) supports a <code>DS<\/code> (Define Storage) pseudo-op, similar to MASM&#8217;s <code>DB n DUP(?)<\/code>. Since ASM86 generates Intel HEX files, when it encounters a DS, it increments the program counter variable by the specified number of bytes, which, in turn, increases the address in the .HEX file. The same goes for specifying a custom put base, which literally tells the assembler to emit code at a specified address.<\/p>\n\n\n\n<p>When a <code>.HEX<\/code> file is loaded, the parser reads it line by line and copies the data to the address specified at the beginning of each line. This means that if there is a gap between the addresses of two lines, which would be the case when the put base is incremented by <code>DS<\/code> or <code>PUT<\/code>, the data inside the gap will be uninitialised and, therefore, undefined.<\/p>\n\n\n\n<p>Suppose that I originally have this data at address <code>0x100<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n\n00000100  54 68 69 73 20 66 69 6C 65 20 63 6F 6E 74 61 69  This file contai\n00000110  6E 73 20 6D 79 20 70 61 73 73 77 6F 72 64 2E 20  ns my password. \n00000120  4D 79 20 70 61 73 73 77 6F 72 64 20 69 73 20 61  My password is a\n00000130  62 63 31 32 33 2E 20 44 6F 20 6E 6F 74 20 6C 65  bc123. Do not le\n00000140  61 6B 20 74 68 69 73 21                          ak this!<\/code><\/pre>\n\n\n\n<p>Now, I load this Intel HEX file (notice the gap of 18 bytes between the second and third line):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  Len Addr Type Data                                                 Hash\n: 1A  0100 00   2CC3EB8233940FDC4C1C9507C82F8C88237F9602D154EC95F3C6 2F\n: 09  011A 00   041CA1DC8862B224C9                                   B6\n: 13  0135 00   74CFDA5478D2CCA5C79A6D8BD6CB32629EDE90               F1<\/code><\/pre>\n\n\n\n<p>The memory then becomes this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n\n00000100  2C C3 EB 82 33 94 0F DC 4C 1C 95 07 C8 2F 8C 88  ,\u00c3\u00eb\u201a3\u201d.\u00dcL.\u2022.\u00c8\/\u0152\u02c6\n00000110  23 7F 96 02 D1 54 EC 95 F3 C6 04 1C A1 DC 88 62  #.\u2013.\u00d1T\u00ec\u2022\u00f3\u00c6..\u00a1\u00dc\u02c6b\n00000120  B2 24 C9 70 61 73 73 77 6F 72 64 20 69 73 20 61  \u00b2$\u00c9password is a\n00000130  62 63 31 32 33 74 CF DA 54 78 D2 CC A5 C7 9A 6D  bc123t\u00cf\u00daTx\u00d2\u00cc\u00a5\u00c7\u0161m\n00000140  8B D6 CB 32 62 9E DE 90                          \u2039\u00d6\u00cb2b\u017e\u00de.<\/code><\/pre>\n\n\n\n<p>The 18-byte buffer at offset <code>0x123<\/code> is what we call uninitialised data, which in this case, happens to contain the leftover string <code>password is abc123<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Case Study: <code>CHESS.COM<\/code><a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#case-study-chesscom\"><\/a><\/h3>\n\n\n\n<p>Let&#8217;s take a look at this fragment of uninitialised data at offset <code>0x64<\/code> of <code>CHESS.COM<\/code>. It&#8217;s only 156 bytes, but you will be surprised by the amount of information that can be inferred from these bits.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n\n00000060              69 6C 65 20 6E 61 6D 65 0D 0A 24 02      ile name..$.\n00000070  01 43 48 45 53 53 20 20 20 48 45 58 00 00 B9 03  .CHESS   HEX..\u00b9.\n00000080  01 60 E4 0E 66 00 77 00 48 00 11 00 FF FF EB D4  .`\u00e4.f.w.H...\u00ff\u00ff\u00eb\u00d4\n00000090  48 00 50 52 49 4C 53 54 44 4C 20 20 20 00 00 00  H.PRILSTDL   ...\n000000A0  09 25 29 00 00 00 00 00 00 00 00 00 00 00 00 00  .%).............\n000000B0  00 00 53 55 50 43 48 45 53 53 48 45 58 00 00 00  ..SUPCHESSHEX...\n000000C0  47 7E 7F 81 82 83 84 85 86 87 00 00 00 00 00 00  G~..\u201a\u0192\u201e\u2026\u2020\u2021......\n000000D0  00 00 53 55 50 43 48 45 53 53 43 4F 4D 00 00 00  ..SUPCHESSCOM...\n000000E0  32 88 89 8A 8B 8C 8D 8E 00 00 00 00 00 00 00 00  2\u02c6\u2030\u0160\u2039\u0152.\u017d........\n000000F0  00 00 44 41 4E 20 20 20 20 20 20 20 20 00 00 00  ..DAN        ...<\/code><\/pre>\n\n\n\n<p>What we first see is a string <code>ile name\\r\\n$<\/code>. If we examine <code>RDCPM.COM<\/code>, we will see that it has the exact same string at offset <code>0x1D5<\/code>. So, we are probably looking at a partial memory dump of <code>RDCPM<\/code>. There is a 1-byte size difference between that copy of <code>RDCPM.COM<\/code> and 86-DOS 0.11&#8217;s <code>RDCPM.COM<\/code>, because the string ends at offset <code>0xE<\/code> of that paragraph instead of <code>0xF<\/code>. Since we have identified the origin of the data, we can take a look at the <code>RDCPM<\/code> source code to determine the meaning of the rest of the data.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro padding-disabled\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:8;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#002339;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>BADFN:\tDB\t13,10,\"Bad file name\",13,10,\"$\"\nDRIVE:\tDS\t1\nDSTFCB:\tDS\t32\n\tDB\t0\nDIRBUF:\tDS\t128<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki slack-ochin\" style=\"background-color: #FFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #7EB233\">BADFN:<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DB<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">13<\/span><span style=\"color: #002339\">,<\/span><span style=\"color: #174781\">10<\/span><span style=\"color: #002339\">,&quot;Bad file name&quot;,<\/span><span style=\"color: #174781\">13<\/span><span style=\"color: #002339\">,<\/span><span style=\"color: #174781\">10<\/span><span style=\"color: #002339\">,&quot;$&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">DRIVE:<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">DS<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">DSTFCB:<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">DS<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">32<\/span><\/span>\n<span class=\"line\"><span style=\"color: #002339\">\t<\/span><span style=\"color: #0991B6\">DB<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #7EB233\">DIRBUF:<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">DS<\/span><span style=\"color: #002339\">\t<\/span><span style=\"color: #174781\">128<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>The byte at <code>0x6F<\/code> is the <code>DRIVE<\/code> variable, which holds the drive ID of the CP\/M disk. A value of <code>0x02<\/code> signifies drive C. Next comes <code>DSTFCB<\/code>, the FCB of the destination file. We can see from the first 12 bytes that it&#8217;s the file <code>A:CHESS.HEX<\/code>. This gives us the <code>RDCPM<\/code> command line <code>RDCPM C:CHESS.HEX A:<\/code>.<\/p>\n\n\n\n<p>If we look further at <code>DSTFCB<\/code>, we will notice that it does not actually match up with the FCB format of 86-DOS 0.11. This strongly suggests that <code>RDCPM<\/code> was run under an earlier version of 86-DOS.<\/p>\n\n\n\n<p>After the FCB, we have <code>DIRBUF<\/code>, which holds a directory sector of the CP\/M disk. We can decode it:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Filename<\/th><th>Size<\/th><th>Blocks<\/th><th>Block List<\/th><\/tr><\/thead><tbody><tr><td><code>PRILSTDL<\/code><\/td><td>1152<\/td><td>2<\/td><td>37, 41<\/td><\/tr><tr><td><code>SUPCHESS.HEX<\/code><\/td><td>9088<\/td><td>9<\/td><td>126, 127, 129, 130, 131, 132, 133, 134, 135<\/td><\/tr><tr><td><code>SUPCHESS.COM<\/code><\/td><td>6400<\/td><td>7<\/td><td>136, 137, 138, 139, 140, 141, 142<\/td><\/tr><tr><td><code>DAN<\/code><\/td><td>?<\/td><td>?<\/td><td>?<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>I have no idea what <code>PRILSTDL<\/code> was; if I had to guess, it probably had something to do with the printing of assembly language listings. <code>SUPCHESS.HEX<\/code> had the exact same size as the <code>.HEX<\/code> file for 86-DOS 0.11&#8217;s <code>CHESS<\/code> program, and <code>SUPCHESS.COM<\/code> had the same size as <code>CHESS.COM<\/code>, so the <code>SUPCHESS<\/code> thing was just <code>CHESS<\/code>. I doubt anyone will ever be able to figure out what <code>DAN<\/code> was.<\/p>\n\n\n\n<p>The most crucial information we can infer from this directory fragment is the format of the CP\/M disk in drive C. <code>RDCPM<\/code> only ever supported 2 CP\/M disk formats out of the box &#8211; the standard 8&#8243; SSSD format with a sector skew of 6, and the 5&#8243; Cromemco format with a sector skew of 5. The largest block number for the 5&#8243; format is about 82, so based on this alone, we can deduce that this directory fragment belonged to an 8&#8243; disk.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Summary (TL;DR)<a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#summary-tldr\"><\/a><\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li>The file <code>CHESS.HEX<\/code> was converted to <code>CHESS.COM<\/code> under 86-DOS.<\/li>\n\n\n\n<li><code>RDCPM<\/code> was used to copy CHESS.HEX from a CP\/M disk.<\/li>\n\n\n\n<li>The <code>RDCPM<\/code> command was <code>RDCPM C:CHESS.HEX A:<\/code>.<\/li>\n\n\n\n<li>The disk in drive C was a standard 8&#8243; SSSD CP\/M disk.\n<ul class=\"wp-block-list\">\n<li>Given that drive C was 8&#8243;, the drive configuration was <code>LARGECRO<\/code>.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Case Study: <code>SYS.COM<\/code><a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#case-study-syscom\"><\/a><\/h3>\n\n\n\n<p><code>SYS.COM<\/code> also has some uninitialised data, this time only a partial directory sector.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n\n00000090                             20 41 38 36 00 00 00            A86...\n000000A0  2B 4C 4D 5C 68 69 6A 00 00 00 00 00 00 00 00 00  +LM\\hij.........\n000000B0  00 00 53 59 53 20 20 20 20 20 48 45 58 00 00 00  ..SYS     HEX...\n000000C0  04 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00  .#..............\n000000D0  00 00 53 59 53 20 20 20 20 20 42 41 4B 00 00 00  ..SYS     BAK...\n000000E0  05 26 00 00 00 00 00 00 00 00 00 00 00 00 00 00  .&amp;..............\n000000F0  00 00 43 4F 4D 4D 41 4E 44 20 48 45 58 00 00 00  ..COMMAND HEX...<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Filename<\/th><th>Size<\/th><th>Blocks<\/th><th>Block List<\/th><\/tr><\/thead><tbody><tr><td><code>?.A86<\/code><\/td><td>5504<\/td><td>6<\/td><td>76, 77, 92, 104, 105, 106<\/td><\/tr><tr><td><code>SYS.HEX<\/code><\/td><td>512<\/td><td>1<\/td><td>35<\/td><\/tr><tr><td><code>SYS.BAK<\/code><\/td><td>640<\/td><td>1<\/td><td>38<\/td><\/tr><tr><td><code>COMMAND.HEX<\/code><\/td><td>?<\/td><td>?<\/td><td>?<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>There&#8217;s nothing particularly interesting here, but <code>SYS.BAK<\/code> (presumably produced by editing <code>SYS.A86<\/code> with <code>EDIT<\/code> or WordMaster) had the exact same size as my reconstructed <code>SYS.A86<\/code>, so my <code>SYS<\/code> disassembly can&#8217;t be too far off the original. I&#8217;m not sure what that <code>.A86<\/code> file was, but my educated guess is it was <code>COMMAND.A86<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"file-sizes-and-rdcpm\">File Sizes and <code>RDCPM<\/code><\/h3>\n\n\n\n<p>The size of files copied off of CP\/M disks should always be multiples of the block size of the CP\/M disk, because <code>RDCPM<\/code> completely ignores the record count and uses only the block pointers to determine when to stop reading. For instance, if the record size is 1K and the file size is 128, when transferred to a DOS disk with <code>RDCPM<\/code>, it will be 1024 bytes long.<\/p>\n\n\n\n<p>Since none of the files on the original 86-DOS 0.11 distribution disk are exact multiples of 1K, none of them were directly transferred from CP\/M disks. This implies that all the <code>.COM<\/code> binaries were generated by <code>HEX2BIN<\/code> from <code>.HEX<\/code> files read from CP\/M disks. <code>CHESS.DOC<\/code> was either created from scratch under 86-DOS, or transferred from a CP\/M disk and then edited by <code>EDLIN<\/code> under 86-DOS.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Building 86-DOS<\/h2>\n\n\n\n<p>Finally, we&#8217;re building it!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"requirements\">Requirements<a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#requirements\"><\/a><\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Hardware<a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#hardware\"><\/a><\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li>A <a href=\"https:\/\/wikipedia.org\/wiki\/Cromemco_Z-2#Cromemco_Z-2D\">Cromemco Z-2D machine<\/a> with four 8&#8243; drives<sup>*<\/sup>.<\/li>\n\n\n\n<li>An <a href=\"https:\/\/archive.org\/details\/byte-magazine-1979-11\/page\/n168\/mode\/1up\">SCP 8086 S-100 machine<\/a> with the <a href=\"https:\/\/wikipedia.org\/wiki\/Cromemco_4FDC\">Cromemco 4FDC<\/a> disk controller and four 8&#8243; drives<sup>**<\/sup>.<\/li>\n<\/ol>\n\n\n\n<p><em><sup>*<\/sup><a href=\"https:\/\/www.sydneysmith.com\/wordpress\/run-cdos\/\">Greg Sydney-Smith&#8217;s fork of the Z80 simulator from z80pack<\/a> can be used instead of physical hardware.<\/em><br><em><sup>**<\/sup><a href=\"https:\/\/schorn.ch\/altair_2.php\">Peter Schorn&#8217;s fork of the AltairZ80 simulator<\/a> can be used instead of physical hardware.<\/em><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Software<a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#software\"><\/a><\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Disk%20Images\/Cromemco%20CDOS%20with%20Build%20Tools.img\">An 8&#8243; SSSD CDOS disk<\/a> containing:\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/wikipedia.org\/wiki\/Cromemco_DOS\">The Cromemco Disk Operating System (CDOS)<\/a>.<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/CPM%20Tools\/README.md#asm86\">SCP&#8217;s 8086 Cross Assembler (ASM86)<\/a>.<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/CPM%20Tools\/README.md#dosgen\">My DOSGEN program<\/a>.<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li>An <a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Disk%20Images\/86-DOS%200.11%20Source%20Code.img\">8&#8243; SSSD CDOS disk containing the 86-DOS 0.11 source code<\/a>.<\/li>\n\n\n\n<li>An earlier version of 86-DOS or <a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Disk%20Images\/Scratch%20LARGECRO%2086-DOS.img\">an existing copy of 86-DOS 0.11<\/a>, with <code>LARGECRO<\/code> drive config<sup>*<\/sup>.<\/li>\n<\/ol>\n\n\n\n<p><em><sup>*<\/sup>Any version of 86-DOS 0.x (including 0.11) will do. The disk controller must be Cromemco 4FDC and the drive configuration must be <code>LARGECRO<\/code>. To create a bootable copy of 86-DOS 0.11 yourself from scratch, see <a href=\"#first-egg\">The Chicken and Egg Problem :: The First Egg<\/a>.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Steps<a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#steps\"><\/a><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Power on the Z-2D machine and boot the CDOS disk.<\/li>\n\n\n\n<li>Insert the 86-DOS source code disk in drive B.<\/li>\n\n\n\n<li>Insert a blank formatted 8&#8243; SSSD disk in drive C.<\/li>\n\n\n\n<li>For each source (<code>.A86<\/code>) file on drive B:\n<ul class=\"wp-block-list\">\n<li>Assemble to <code>.HEX<\/code> object by running <code>ASM86 &lt;name&gt;.BCZ<\/code>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Copy <code>CHESS.DOC<\/code> from drive B to drive C.<\/li>\n\n\n\n<li>Power on the 8086 S-100 machine and boot the earlier version of 86-DOS.<\/li>\n\n\n\n<li>Remove the disk in drive C of the Z-2D machine and insert it into drive C of the S-100 machine.<\/li>\n\n\n\n<li>Insert a blank formatted 8&#8243; SSSD disk into drive B.<\/li>\n\n\n\n<li>For each <code>.HEX<\/code> file on drive C (except for <code>86DOS.HEX<\/code>, <code>BOOT.HEX<\/code> and <code>DOSIO.HEX<\/code>):\n<ul class=\"wp-block-list\">\n<li>Run <code>RDCPM C:&lt;name&gt;.HEX A:<\/code>.<\/li>\n\n\n\n<li>Run <code>HEX2BIN &lt;name&gt;<\/code>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Run <code>RDCPM C:CHESS.DOC A:<\/code>.<\/li>\n\n\n\n<li>Run <code>EDLIN CHESS.DOC<\/code> and exit with the command <code>E<\/code> (to remove extra bytes at the end of <code>CHESS.DOC<\/code>).<\/li>\n\n\n\n<li>Run <code>ERASE ????????.HEX<\/code> (to delete all <code>.HEX<\/code> files).<\/li>\n\n\n\n<li>Run <code>ERASE CHESS.BAK<\/code> (to delete <code>CHESS.BAK<\/code>).<\/li>\n\n\n\n<li>Run <code>CLEAR B:<\/code> and type <code>Y<\/code> (to put a filesystem on drive B).<\/li>\n\n\n\n<li>Copy all files from drive A to drive B (to create a &#8220;fresh&#8221; and &#8220;clean&#8221; disk).<\/li>\n\n\n\n<li>Remove the disk in drive B and insert it into drive D of the Z-2D machine.<\/li>\n\n\n\n<li>Remove the disk in drive C and insert it into drive C of the Z-2D machine.<\/li>\n\n\n\n<li>Go back to the Z-2D machine and change to drive C.<\/li>\n\n\n\n<li>For <code>86DOS<\/code>, <code>BOOT<\/code> and <code>DOSIO<\/code>:\n<ul class=\"wp-block-list\">\n<li>Run <code>DEBUG &lt;name&gt;.HEX<\/code>.<\/li>\n\n\n\n<li>Quit <code>DEBUG<\/code> and dump the correct number of pages by running <code>SAVE &lt;name&gt;.COM &lt;num-pages&gt;<\/code>. The number of pages is given by \u2308(<code>NEXT<\/code> &#8211; 0x100) \u00f7 0x100\u2309.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Run <code>DOSGEN D:<\/code>.<\/li>\n\n\n\n<li>The disk in drive D now contains a complete copy of 86-DOS 0.11.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"first-egg\">The Chicken and Egg Problem<a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#the-chicken-and-egg-problem\"><\/a><\/h2>\n\n\n\n<p>In order to create a working copy of 86-DOS 0.11 from scratch, we need an earlier version of 86-DOS. However, we don&#8217;t have that. Of course, we could simply use the original 0.11 distribution disk, but then we face a problem: How was that distribution disk made in the first place? Maybe with a copy of 86-DOS 0.10? But then this leads to another question: How was 86-DOS 0.10 built?<\/p>\n\n\n\n<p>You see, to build 86-DOS, you need 86-DOS, and to get 86-DOS, you need to build 86-DOS&#8230; so how was the very first copy of 86-DOS built?<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The First Egg<a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#the-first-egg\"><\/a><\/h3>\n\n\n\n<p>Now, I&#8217;ll guide you through creating a minimum build of 86-DOS 0.11 without the need of another copy of 86-DOS. I call this the first &#8220;egg&#8221;.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Requirements<a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#requirements-1\"><\/a><\/h4>\n\n\n\n<p><em>Same as <a href=\"#requirements\">Building 86-DOS :: Requirements<\/a>.<\/em><\/p>\n\n\n\n<details class=\"wp-block-details is-layout-flow wp-block-details-is-layout-flow\"><summary>Important<\/summary>\n<p>You will need to make a temporary copy of the source code disk, because you will be modifying <code>DOSIO.A86<\/code> to use <code>LARGECRO<\/code> instead of <code>COMBCRO<\/code>.<\/p>\n<\/details>\n\n\n\n<h4 class=\"wp-block-heading\">Steps<a href=\"https:\/\/github.com\/TheBrokenPipe\/86-DOS-0.11\/blob\/main\/Building.md#steps-1\"><\/a><\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Power on the Z-2D machine and boot the CDOS disk.<\/li>\n\n\n\n<li>Insert the 86-DOS source code disk (copy) in drive B.<\/li>\n\n\n\n<li>Insert a blank formatted 8&#8243; SSSD disk in drive C.<\/li>\n\n\n\n<li>Change to drive B and edit <code>DOSIO.A86<\/code> to use the <code>LARGECRO<\/code> drive configuration.<\/li>\n\n\n\n<li>For <code>86DOS<\/code>, <code>BOOT<\/code>, <code>COMMAND<\/code>, <code>DOSIO<\/code>, <code>HEX2BIN<\/code> and <code>RDCPM<\/code>:\n<ul class=\"wp-block-list\">\n<li>Assemble to <code>.HEX<\/code> object by running <code>ASM86 &lt;name&gt;.BCZ<\/code>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Change to drive C and for <code>86DOS<\/code>, <code>BOOT<\/code>, <code>COMMAND<\/code>, <code>DOSIO<\/code>, <code>HEX2BIN<\/code> and <code>RDCPM<\/code>:\n<ul class=\"wp-block-list\">\n<li>Load the <code>.HEX<\/code> object to memory by running <code>DEBUG &lt;name&gt;.HEX<\/code>.<\/li>\n\n\n\n<li>Quit <code>DEBUG<\/code> and dump the correct number of pages by running <code>SAVE &lt;name&gt;.COM &lt;num-pages&gt;<\/code>. The number of pages is given by \u2308(<code>NEXT<\/code> &#8211; 0x100) \u00f7 0x100\u2309.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Insert a blank formatted 8&#8243; SSSD disk into drive D.<\/li>\n\n\n\n<li>Run <code>DOSGEN D: N<\/code>.<\/li>\n\n\n\n<li>Pop out the disks in drives C and D, and insert them into drives C and A of the S-100 machine, respectively.<\/li>\n\n\n\n<li>Boot up the 8086 S-100 machine.<\/li>\n\n\n\n<li>Run <code>RDCPM C:HEX2BIN.COM A:<\/code> to copy <code>HEX2BIN.COM<\/code> over.<\/li>\n\n\n\n<li>The disk in drive A now contains a minimal build of 86-DOS 0.11, which can be used to facilitate the building of a complete copy of 86-DOS 0.11.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Building 86-DOS 0.11 from scratch was quite the ride! I&#8217;ve lost count of the hours I&#8217;ve poured into it, but trust me, it&#8217;s been a lot. This post barely scratches the surface, hitting just the highlights &#8211; maybe about 10% of the whole deal. The other 90%? Well, let&#8217;s just say it&#8217;s been a whole lot of boring, tedious stuff like research and reverse engineering.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>At the end of last year, a copy of 86-DOS 0.11 for the Cromemco 4FDC controller surfaced. It is the earliest released version of 86-DOS, the earliest operating system for the x86 architecture. Having done some legacy work dealing with real mode x86 before, I thought I could maybe challenge myself and build a copy [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,6],"tags":[],"class_list":["post-158","post","type-post","status-publish","format-standard","hentry","category-dos","category-reverse-engineering"],"_links":{"self":[{"href":"https:\/\/thebrokenpipe.com\/blog\/wp-json\/wp\/v2\/posts\/158","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thebrokenpipe.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thebrokenpipe.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thebrokenpipe.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/thebrokenpipe.com\/blog\/wp-json\/wp\/v2\/comments?post=158"}],"version-history":[{"count":41,"href":"https:\/\/thebrokenpipe.com\/blog\/wp-json\/wp\/v2\/posts\/158\/revisions"}],"predecessor-version":[{"id":260,"href":"https:\/\/thebrokenpipe.com\/blog\/wp-json\/wp\/v2\/posts\/158\/revisions\/260"}],"wp:attachment":[{"href":"https:\/\/thebrokenpipe.com\/blog\/wp-json\/wp\/v2\/media?parent=158"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thebrokenpipe.com\/blog\/wp-json\/wp\/v2\/categories?post=158"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thebrokenpipe.com\/blog\/wp-json\/wp\/v2\/tags?post=158"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}