2026-08-30

amd64移植におけるテーブル構造

東大版Palo Alto Tiny BASICをWSL2のUbuntu環境に移植しようと作業を進めています。BASICというのは、プログラム編集機能とインタプリタ機能が統合されています。オリジナル版は、SDK-80のシリアルポートにASR-33が接続された環境を想定していますから、プログラム編集機能といっても簡単なものです。amd64移植にあたり、機能的な拡張は全くおこなわない方針です。今日の水準から見れば貧弱そのものですが、移植する過程を学ぶのが主目的なので、本格的な機能は求めないことにします。

 

ひとまず編集機能はできあがりましたので、次はインタプリタ機能です。ここで問題となるのが、入力された文字列を認識して、対応する機能に分岐するロジックです。オリジナル版は、i8080というものに強く依存しているので、そのままamd64に対応させるのはよくないと考えています。基本的な構造は「CASEマクロ」にあります。

CASE   .macro STR,ADRS
       DB    &STR
       DB    (&ADRS SHR 8)+80H
       DB    &ADRS AND 0FFH
       .endm

このマクロを使って次のようなテーブルが作られます。例えば「LIST」という文字列だったら、LISTルーチンに飛ぶことになります。

CMDKW: CASE  'LIST',LIST
       CASE  'RUN',RUN
       CASE  'NEW',NEW
STMKW: CASE  'NEXT',NEXT

ここで注目すべきは、文字列の終端を認識するために、ルーチンのアドレスのMSBをONにしている点です。しかもi8080はリトルエンディアンなのに、ビッグエンディアンのように逆転させて配置しています。これはi8080の事だけを考えて組み立てるのであれば、秀逸なアイディアと言えます。しかしamd64に移植しようとするなら、あまりよろしくありません。しかも、amd64への移植が済んだら、他の環境にも移植したいと考えているので、なおさらです。

 

どうしたらよいか、これから検討します。Geminiに相談してみようと思います。 

 

2026-08-28

sudo、doas、opendoas

最近購入したLet's note CF-SV8RDCVSにFreeBSD 15.1-RELEASEをインストールしました。個人で使用するだけですが、昨今のセキュリティ事情を踏まえると、いい加減な運用は避けた方が良いだろうと思います。rootの他に一般ユーザを作るのは当然ですが、その一般ユーザをwheelグループに入れるか否かは慎重に考える必要があります。一般ユーザがWheelグループに入れば「su」でrootになれますが、セキュリティ的には注意が必要です。 

 

最近はrootアカウントを使わず、「sudo」を使うのが一般的です。しかし「sudo」は、多機能すぎて肥大化していることが問題視されており、代替としてOpenBSD由来の「doas」があります。

 

FreeBSDにもdoasをインストールしようと思いましたが、doasの他にopendoasが存在することに気づきました。何が違うのかと言うと、「persist」オプションがあることです。これがあれば、sudoのように、またはOpenBSD上のdoasのように、いったん認証に成功したら一定時間は認証を省略できるようになります。

 

FreeBSDに限りませんが、一般ユーザが「su」で直接rootになれるのは、セキュリティ的には避け、sudoやdoasを用いるようにした方が良さそうです。 

2026-08-23

FreeBSD 15.1-RELEASEの無線LAN設定

Let's note CF-SV8RDCVSにFreeBSD/amd64 15.1-RELEASEをインストールしました。インストール中は有線でネットワークに繋ぎました。今後デスクトップ環境を入れていくつもりですが、その前に無線LANの設定を済ませておこうと思います。

 

『FreeBSD Handbook』では「7.4. Wireless Networks」として設定手順が説明されています。それに従って作業すると、次のようになります。

  1. 接続先となるSSIDとPSKを入手しておきます。
  2. 「/etc/wpa_supplicant.conf」を作成します。ひな形が示されているので、そこに入手したSSIDなどの情報を入れます。
  3. 「/etc/rc.conf」に無線LANの情報を追加します。これも示された手順のとおりです。ただし設定ファイルを直接編集せずに、「sysrc」というコマンドを使っているのを初めて知りました。
  4. 以上で設定が済んだので「service netif restart」とすれば、繋がるはずです。

 

ところが繋がりませんでした。これまではdynabook SS SX/15AのNetBSD/i386で接続できていたので、何が違うのか確認してみました。私の自宅ではステルスSSIDとしていたため、「network」の設定の中に「scan_ssid=1」を入れておく必要があるようです。これを追加したら、繋がるようになりました。しかしGeminiと相談した結果、ステルスSSIDはセキュリティ的に望ましくないという意見だったので、ステルスSSIDを止めて公開設定に変更しました。そうなると「scan_ssid=1」は不要です。

 

さらに「/etc/rc.conf」に「create_args_wlan0="country JP regdomain JAPAN"」という設定も追加しました。『FreeBSD Handbook』が英語版であるからなのか、日本特有の設定については記述がありません。これもまたGeminiとの相談の結果ですが、この設定は必須とのことでしたので、追加しました。

 

以上で無線LANが使えるようになりました。若干トラブルがありましたが、とても簡単でした。 

2026-08-21

「FreeBSD-15.1-RELEASE-amd64-memstick.img」に入っているのは「PkgBase」

最近入手したLet's note CF-SV8 RDCVSにFreeBSD/amd64 15.1-RELEASEをインストールしてみました。公式サイトから「FreeBSD-15.1-RELEASE-amd64-memstick.img」を入手し、RufusでUSBメモリに書き込みます。ハンドブックの「2.3.1. Prepare the Installation Media」に「-memstick.img: This file contains all of the files needed to install FreeBSD, its source, and the Ports Collection. 」と書かれているように、インストールに必要なファイルは全て入っています。つまりインストール中にネットワークアクセスは必要ありません。もし「-bootonly.iso」や「-mini-memstick.img」を使うと、必要なファイルをネットワーク越しに取得することになります。

 

インストール中の選択肢に「Select Installation Type」があります。これまでのFreeBSDで使われてきた「Distribution Sets」か、FreeBSD 16からデフォルトになると言われている「Packages (Tech Preview)」のどちらを使うか選ばなければなりません。PkgBaseがデフォルトになるのは次のバージョンからですので、今回は「Distribution Sets」でインストールしようと考えました。ところが、ネットワークへのアクセスは不要なはずなのに、ネットワークからファイルを取得しようとするのです。

 

ネットワークに接続せずにインストールを完了させたかったので、ネットワークへのアクセスが発生すると困ります。ここで気づきましたが、「-memstick.img」にはインストールに必要なファイルが全て入っているとは言っても、「Distribution Sets」と「Packages」の双方が入っているわけではないようです。入っているのは「Packages」の方だけで、「Distribution Sets」を選んでしまうと、ネットワーク越しに取得しにいくのでしょう。

 

案の定、「Packages (Tech Preview)」を選択したら、ネットワークへのアクセスする事なく、インストールが完了しました。インストール完了後に改めて起動させたところ、Let's note CF-SV8RDCVSでFreeBSD/amd64 15.1-RELEASEが無事に起動しました。 

2026-08-19

「LBUF EQU VTOP+0037H」が0036Hではない謎

共立出版の『マイクロコンピュータのプログラミング』に掲載された東大版Palo Alto Tiny BASICについて調査しています。アセンブラで書かれたプログラムの先頭では、以下のようにメモリ配置が定義されています。

;  MEMORY MAP
ITOP   EQU   0000H
ISIZE  EQU   0800H
LTOP   EQU   1000H
VTOP   EQU   5000H
LBUF   EQU   VTOP+0037H        ;0037H?
LBFSZ  EQU   80
MSTK   EQU   LBUF+LBFSZ
TMSTK  EQU   MSTK+30        ;30?
STACK  EQU   6000H

 

本文では「図3 メモリマップ」として説明されています。VTOPとLBUFの間は「変数エリア」になっています。Tiny BASICですから、プログラムで使える変数は「A」~「Z」と配列「@」の27個に制限されています。また変数に格納できるのは16ビット整数だけです。つまり27種類×2バイト=54バイトあれば良い計算になります。これは、16進数ならば0036Hです。

 

ところがLBUFは、「VTOP+0037H」として定義されています。何故「0036H」ではないのでしょうか。プログラムを解析してみると、ロジックの都合ではないかと思われます。

 

LBUFからLBFSZ(=80)は、「行バッファ」です。キー入力される文字列を格納する領域です。この処理は、次のようになっています。

EDITR: MVI   A,'>'
       CALL  GETL
       PUSH  D
       LXI   D,LBUF
       CALL  GINT
       CALL  SKPBL
       MOV   A,H
       ORA   L
       POP   B
       JZ    KWCPR
INSRT: DCX   D
       MOV   A,H
       STAX  D
       DCX   D
       MOV   A,L
       STAX  D

 

GETLルーチンで入力された文字列は、先頭に数字があるかをGINTルーチンで判断しています。つまり「10 PRINT A」のように入力すると、先頭の数字をバイナリに変換し、数字文字列と置き換えます。また空白も取り除くので、入力された行は、「<0A><00>PRINT A」としてメモリ上に置かれることになります。数字文字列をバイナリに変換した結果を格納しているのが、INSRTで始まる処理です。

 

このようなロジックになっているので、現代的な書き方であるインデントを使用としても、全て取り除かれてしまいます。「10         PRINT A」のように空白を入れても、内部構造は「<0A><00>PRINT A」になります。さらに当時の厳しいメモリ事情の為なのか、Tiny Trekのプログラムでわかるように、意味がとおるなら空白文字を省くことができます。つまり「10PRINT A」としてもエラーではありません。

 

ここで考えなければならないのは、数字文字列をバイナリに変換して格納している点です。バイナリは16bitなので、2バイト必要です。数字文字列が「10」であったり、例え一桁であったとしても「1 PRINT A」のように空白が入っていれば、2文字あるので、16bitのバイナリを格納することができます。ところが「1PRINT A」のような記述を認めているので、数字文字列が1文字しかない場合、16bitのバイナリを格納するには領域が不足してしまうのです。プログラムでは例外処理がありません。どうしているかというと、LBUFの直前にある「変数エリア」に踏み込んでしまうのです。これが「0036H」ではなくて「0037H」になっている理由と思われます。

 

試しに「LBUF EQU VTOP+0036H」としてアセンブルしたプログラムで実験してみました。変数「Z」に何か値を代入しておいて、「1PRINT Z」を入力すると、変数「Z」の値が変わってしまいました。やはり変数「Z」の領域を壊してしまうのです。

 

こうならないようにするため、あえて「LBUF EQU VTOP+0037H」として1バイト分ずらして領域を確保しているのですが、極めて技巧的です。 

2026-08-18

東大版Palo Alto Tiny BASICのGETIルーチンをamd64に移植するとLEA命令を使う

SDK-80のシリアルポートにASR-33が接続された環境を想定している東大版Palo Alto Tiny BASICをWSL2Ubuntu環境に移植しています。Geminiと相談しながら作業しています。BASICというものは、編集環境と実行環境が統合されているところに真髄があるのですが、まず編集環境の方から移植を進めています。数字文字列を2進数に変換するために「GETI」というルーチンがあります。これをamd64にしてみます。

 

オリジナルは次のようになっています。

GINT:  LXI   H,0000H        ;GET INTEGER
       MOV   B,H
       CALL  SKPBL
GETI1: CPI   '0'
       RC                    ;RETURN INTEGER IN HL
       CPI   '9'+1
       RNC
       MVI   A,0F0H
       ANA   H                ;IF INTEGER>#0FFF ERHOW
       JNZ   ERHOW
       INR   B
       PUSH  B
       MOV   B,H            ;HL HL+10
       MOV   C,L
       DAD   H
       DAD   H
       DAD   B
       DAD   H
       LDAX  D                ;HL HL+(DE)&#0F
       INX   D
       ANI   0FH
       ADD   L
       MOV   L,A
       MVI   A,00H
       ADC   H
       MOV   H,A
       POP   B
       LDAX  D
       JM    ERHOW
       JMP   GETI1

 

Geminiの指導を受けながらamd64に移植したら、次のようになりました。

.equ    GINT_DIGIT_MAX,        (NINE-ZERO)
.equ    GINT_MAX_BEFORE_X10,    0x0FFF
gint:    xor    eax,eax
    xor    ecx,ecx
    call    skpbl
geti1:    movzx    edx,byte ptr [rdi]
    sub    edx,ZERO
    cmp    edx,GINT_DIGIT_MAX
    ja    geti9
    cmp    ax,GINT_MAX_BEFORE_X10
    ja    erhow
    inc    cx
    # amd64の真骨頂: LEA命令による AX = (AX * 10) + DX
    lea    eax,[rax + rax*4]
    lea    eax,[rdx + rax*2]
    inc    rdi
    test    ax,ax
    js    erhow
    jmp    geti1
geti9:    ret

amd64と比べるのは卑怯かもしれませんが、i8080は命令が貧弱です。レジスタの内容を10倍するのも、簡単にはできません。一方amd64は、IMUL命令で簡単に10倍できるはずですが、Geminiが提示してきたのはLEA命令を使う方法でした。なぜIMUL命令を使わないでLEA命令なのかとGeminiに問うと、内部処理の都合上この方が速いのだそうです。ここがボトルネックという訳ではないので、微妙に速くなっても全体としては速さを意識できないと思います。しかし、いかにもamd64チューニングされているという感じにはなりました。 

2026-08-14

セキュアブートとUSB起動

Let's note CF-SV8RDCVSを中古で購入しました。Windows11が入っていたので、HWiNFOやCrystalDiskInfoなどで、情報を収集しておきます。また自宅の無線LANに接続してみて、問題ないことを確認しました。これで、ひととおり初期状態の確認が済んだので、Windows11とはお別れして、BSD系OSに入れ換えてみようと思います。

 

これまで使っていたdynabook SS SX/15AではNetBSD/i386を使っていました。せっかくなので各BSDを試してみて、気に入ったものを選ぼうと思います。まずは、FreeBSD/amd64 15.1を試してみます。公式サイトからUSBのためのIMGファイルを取得し、RufusでUSBメモリに書き込みます。これを使って起動しようとしたら、ちょっと問題が発生しました。

 

dynabookの頃には存在しませんでしたが、最近は「セキュアブート」というものがあります。これが有効になっていると、FreeBSDのインストーラが起動しません。しかもLet's noteは、USBメディアの起動順位が低いので、ただ挿しただけでは起動してくれません。

 

「セキュアブート」を無効にするには、電源投入時にF2キーを押し、設定画面に入ります。「セキュアブート」の項目を「無効」に設定して、保存すれば完了です。

 

USBメディアの起動順位を上げるのも、同様に設定画面で出来そうに見えます。しかし設定しても、USBメディアを抜くと優先順位が最下位に戻ってしまうようです。これはセキュリティ上の考慮なのかしれません。USBメディアから勝手に起動できてしまうと、不審者が勝手に操作できてしまうのを避けようとしているのかもしれません。理由は定かではありませんが、できないものは仕方ないので、USBから起動させたい場合は、いちいち設定画面に入ることになりそうです。