DOSプログラムをクロス開発

PC-9801にファイルを送れるようになったので、FreeBSD/i386 12.2Rでクロス開発する方法を調べて見ました。

|OS|CPU|ARCH|SINCE|
|:--|:--|:--|:--|
|CP/M|8080,z80|COM8|1976|
|MS-DOS|8086-|DOS16|1981|
|MS-Windows 3.1|80286-|Win16|1990|
|MS-Windows 95|80486-|Win32|1995|

MS-DOSはPC9801FAのような80486 CPUでも動きましたが、16ビットで動作していました。

DOS環境は最大で640Kというメモリの制限があったり、実際それよりすくな実装のマシンがあったりで、Cなどの高級言語での開発はあまり現実的ではなく、アセンブラでの開発が主流でした。

なぜクロス開発するかといえば、いろいろ覚えるのが苦手で、勝手知ったるいつもの環境でやりたいというのと、ソースコードを管理できるgitなどが使えるからです。

古いマシンでセルフの開発環境を構築するのが結構面倒だったり、そのマシン自体が動かなくなりすべてが水の泡になる可能性もあります。

PC-9801エミュレーターやDOSBOXなどでのセルフのビルドも環境を作られている方もいますが、それ自体が大事だし使い方を忘れてしまいそうです。

マイコンの歴史はクロス開発で始まりました。

あとネットで検索して、コピペができるというのも重要だったりします。

当時のセルフの開発環境はほとんどが商用のもので、PC/AT用のものはフリーになってるものもありますが、PC-9801用のものは現在正式に入手する方法はありません。

x86系のアセンブラとして[NASM](https://www.nasm.us/)があります。これはpkgでも用意されていて、以下のようにして使えます。

```:hoge.asm
        org 100h
        mov dx,msg
        mov ah,9
        int 21h
        mov ah,4Ch
        int 21h

        msg db 'Hello, World!',0Dh,0Ah,'$'
```

```
% nasm -f bin -o hoge.com hoge.asm
```

hoge.comをPC-9801に送ると実行できます。

MS-DOSのプログラムは8ビット由来のCOM形式と拡張されたEXE形式があります。64Kで収まる場合はCOMで作れますが、収まらない場合はEXEで作る必要があります。

EXEファイルは先頭には16ビットのシグネチャーの"MZ"が入っています。

NASMは直接EXEを作ることはできません。

JWLinkというオープンソースを使うとNASMで作成したオブジェクトをリンクしてEXEを作成できるようです。しかしJWLinkのビルドにはOpen Watcomに含まれるwmakeが必要で、これを用意する事ができないのでビルドできません。

またCでの開発であれば2018年くらいにできたgcc-ia16を使えばできそうですが、ビルドが大変そうなので試していません。

16ビット時代にはオープンソースの文化がなかったので、たくさん作られたプログラムがあったにも関わらず、今日ほとんど目にする事ができません。国民機とまで言われたのに寂しい限りです。

# 追記

いろいろ調べたところJWasmというMASM互換のアセンブラがありました。こちらはEXEが作れました。JWasmはOpen Watcomからフォークしたプロジェクトのようです。JWasmはFreeBSDでもpkgで用意されています。

https://www.japheth.de/JWasm/Samples.html

```:Dos2.asm
;--- this is a 16bit sample for DOS. To create a simple DOS 16bit
;--- real-mode binary enter:
;---   JWasm -mz Dos2.asm
;--- or, if a linker is to be used:
;---   JWasm Dos2.asm
;---   wlink format dos file Dos2.obj

;--- To debug the sample with MS CodeView enter
;---   JWasm -Zi Dos2.asm
;---   link /CO Dos2.obj;
;---   cv Dos2.exe

;--- Optionally, the module can be linked as a DPMI 16bit protected-mode
;--- application. There are 2 ways to achieve this:
;--- 1. use Borland DOS extender:
;---   JWasm Dos2.asm
;---   tlink /Tx Dos2.obj;
;--- The resulting binary will need Borland's RTM.EXE and DPMI16BI.OVL.
;--- [To debug the application with TD run "JWasm /Zd Dos2.asm" and
;--- then run "tlink /Tx /v Dos2.obj".]
;--- 2. use HX DOS extender:
;---   JWasm Dos2.asm
;---   wlink format windows file Dos2.obj op stub=hdld16.bin
;---   patchne Dos2.exe
;--- The result is a 16bit DPMI application which includes a DPMI host.
;--- [To get files HDLD16.BIN and PATCHNE.EXE download HXDEV16.ZIP].

    .model small
    .stack 1024

    .data

text db 13,10,"Hello, world!",13,10,'$'

    .code

start:
    mov ax, @data
    mov ds, ax
    mov ah, 09h
    mov dx, offset text
    int 21h
    mov ax, 4c00h
    int 21h

    end start
```

```
% jwasm -mz Dos2.asm 
JWasm v2.13, Feb  6 2021, Masm-compatible assembler.
Portions Copyright (c) 1992-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.

Dos2.asm: 46 lines, 2 passes, 0 ms, 0 warnings, 0 errors
```

PC-9801に転送して実行できました。

```
A>DOS2

Hello, world!

```

サンプルのDos3.asm(DPMI32)はPC-9801のMS-DOS 5.0AでDPMI.EXEを実行した後に実行して正しく動作した。

Open WatcomにはCコンパイラーなどもあったが、それらはFreeBSDのpkgにはなっていない。

fasmというpkgもあって、これでもEXEファイル作れました。

```:fhello.asm
format MZ                   ; DOS executable format
stack 100h

entry code:main             ; Entry point is label main in code segment

segment text
msg db 'Hello, world!$'     ; DOS needs $ terminated string

segment code
main:
    mov   ax, text
    mov   ds, ax            ; set up the DS register and point it at
                            ; text segment containing our data
    mov   dx, msg
    mov   ah, 9
    int   21h               ; Write msg to standard output

    mov   ah, 4Ch
    int   21h               ; Exit DOS program
```

```
% fasm fhello.asm
flat assembler  version 1.73.25  (16384 kilobytes memory)
2 passes, 64 bytes.
```

fasm自体もアセンブラで書かれていて、ポータビリティーが低く、FreeBSD/i386では使えましたが、FreeBSD/amd64では使えなかったので、あまりお勧めしません。

Open Watcom本家に近い[open-watcom-v2](https://github.com/open-watcom/open-watcom-v2)がビルドできたので試してみました。

```
% bwcl Dos2.asm
Open Watcom C/C++ x86 16-bit Compile and Link Utility
Version 2.0 beta Feb 26 2021 09:16:07 (32-bit)
Copyright (c) 2002-2021 The Open Watcom Contributors. All Rights Reserved.
Portions Copyright (c) 1988-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
        bwasm Dos2.asm 
Open Watcom Assembler Version 2.0 beta Feb 26 2021 09:15:23 (32-bit)
Copyright (c) 2002-2021 The Open Watcom Contributors. All Rights Reserved.
Portions Copyright (c) 1992-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
Dos2.asm: 47 lines, 0 warnings, 0 errors
        bwlink @__wcl__.lnk
Open Watcom Linker Version 2.0 beta Feb 26 2021 09:11:12 (32-bit)
Copyright (c) 2002-2021 The Open Watcom Contributors. All Rights Reserved.
Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
loading object files
creating a DOS executable
```

# おまけ

open-watcom-v2はFreeBSDでビルドは通るものの正式なツールはビルドできません。しかし下記の方法で使うことができました。将来状況が変わるかもしれませんが、メモを残しておきます。

setvars.shを編集します。

```diff
diff --git a/setvars.sh b/setvars.sh
index 69650133c..c760ee327 100755
--- a/setvars.sh
+++ b/setvars.sh
@@ -17,7 +17,7 @@ export OWROOT=$(realpath `pwd`)
 
 # Set this entry to identify your toolchain used by build process
 # supported values are WATCOM GCC CLANG
-export OWTOOLS=GCC
+export OWTOOLS=CLANG
 
 # Build control related variables
 ##################################
@@ -63,7 +63,7 @@ export OWDISTRBUILD=0
 # if DOSBOX emulator is used then OWDOSBOX variable must be set
 # Uncoment and set OWDOSBOX variable bellow to point to DOSBOX emulator executable
 
-# export OWDOSBOX=dosbox
+export OWDOSBOX=dosbox
 
 ##################################
```

これでpkgでdosboxをインストールしておくとビルドが通ります。ビルドにはPentiumIIIだと4時間弱かかります。

```
% ./build.sh
% ./build.sh cprel
```

上記を行うとFreeBSDで実行可能なブートストラップのCやアセンブラのコマンドがbuild/binbuild/に作られます。またrel/の下にヘッダーやライブラリがコピーされます。本来はrel/binlなどにコマンドが用意されるのですが、Linux用のコマンドになっています。このためブートストラップのコマンドとrel/の下のファイルを利用する事でFreeBSDでのコンパイルが可能になります。

ブートストラップとは最終的なコンパイラーを作るためのコンパイラーです。

FreeBSD上でビルドするOpen Watcomはclangでbwcc(FreeBSDを用)作ってbwccでwcc(Linux用)を作るようになってるようです。

bwccにはLinuxのバイナリを作る機能もありますが、DOSやWindowsのバイナリも作れるので、実質的に使えるという状態です。

まずbuild/binbuildにパスを通します。またこのディレクトリにrel/binl/wlink.lnkをbwlink.lnkとしてコピーします。

これで下記のように実行するとコンパイルしてEXEが作れます。

```
% cat fm.c
#include <stdio.h>
#include <conio.h>

void main(void)
{

    // YM2203,YM2608,YMF288,YMF297
    int x;

    x = inp(0x0188);

    printf("0x0188 %02x\n", x);
}
% setenv WATCOM /home/hiroki/ow/open-watcom-v2/rel
% bwcl -I/home/hiroki/ow/open-watcom-v2/rel/h fm.c
Open Watcom C/C++ x86 16-bit Compile and Link Utility
Version 2.0 beta Mar  2 2021 10:57:54 (32-bit)
Copyright (c) 2002-2021 The Open Watcom Contributors. All Rights Reserved.
Portions Copyright (c) 1988-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
        bwcc fm.c  -I/home/hiroki/ow/open-watcom-v2/rel/h
Open Watcom C x86 16-bit Optimizing Compiler
Version 2.0 beta Mar  2 2021 11:09:36 (32-bit)
Copyright (c) 2002-2021 The Open Watcom Contributors. All Rights Reserved.
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
fm.c: 14 lines, included 911, 0 warnings, 0 errors
Code size: 24
        bwlink @__wcl__.lnk
Open Watcom Linker Version 2.0 beta Mar  2 2021 10:52:57 (32-bit)
Copyright (c) 2002-2021 The Open Watcom Contributors. All Rights Reserved.
Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
loading object files
searching libraries
creating a DOS executable
% file fm*
fm.c:   C source, ASCII text
fm.exe: MS-DOS executable
fm.o:   8086 relocatable (Microsoft), "/usr/home/hiroki/pc98/ow/fm.c"
```

bwccは-za99オプションでC99になるようです。

この方法は将来使えなくなる可能性が高く、FreeBSDのLinuxエミュレーションでLinuxのバイナリを使うことにしました。

https://qiita.com/yamori813/items/61885b8cb97d6d0a9ff0

# エミュレータで確認

NEKO PROJECT IIでも確認してみました。DOSのV98ディスクイメージをNDで開いてビルドしたコマンドをコピーしてNEKO PROJECT IIを起動します。

![neko_hello.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/1ef66168-c55f-7f8b-00a1-8dfe51df4cd6.png)