SSブログ
English Version

Pic24MC68Kマイコン(その11)CP/M-68KでForth [68K]

 「Pic24MC68Kマイコン(その9)ehBASICの移植」の記事で書いたように MC68000 のチップサイズと同程度のサイズのプリント基板でCP/M-68Kが動き、ehBASIC も移植できたので CP/M-68K で動作する BASIC 以外のアプリケーションを探していたところ、Digital Reseaerch Binary Files のサイトに Forth があったことを思い出し、起動しようと試みましたが下記のエラーが発生して動きませんでした。orz

Forth83 起動時のエラー
P>f83
Insufficient memory or bad file header
P>a:dump f83.68k
0000 00 (000000):  601A 0000 70C4 0000 0000 0000 0000 0000 *`...pD..........*
0000 10 (000010):  0000 0000 0000 0000 0500 FFFF 4EF8 32D2 *............Nx2R*
0000 20 (000020):  4EF8 32C6 3E1D 2847 3E1C 2047 4ED0 1003 *Nx2F>.(G>. GNP..*
0000 30 (000030):  0000 8546 4F52 54C8 301E 7044 70BA 701E *...FORTH0.pDp:p.*
0000 40 (000040):  6FCC 0000 3D0D 2A4C 4EF8 0508 1004 0000 *oL..=.*LNx......*
0000 50 (000050):  8445 5849 54A0 053C 3E1E 2A47 4EF8 0508 *.EXIT .<>.*GNx..*
0000 60 (000060):  1004 0532 8655 4E4E 4553 54A0 053C 3D0D *...2.UNNEST .<=.*
0000 70 (000070):  2A5F 3F0C 4EF8 0508 1005 0546 8255 50A0 **_?.Nx.....F.UP *
0001 00 (000080):  0556 32EC 3F14 4EF8 0508 3014 D078 0566 *.V2l?.Nx..0.Px.f*
0001 10 (000090):  3F00 4EF8 0508 1005 0000 8528 4C49 54A9 *?.Nx.......(LIT)*
0001 20 (0000A0):  0586 3F1D 4EF8 0508 1009 0514 8642 5241 *..?.Nx.......BRA*
0001 30 (0000B0):  4E43 48A0 059A 3E15 2A47 4EF8 0508 1009 *NCH ..>.*GNx....*
0001 40 (0000C0):  0000 873F 4252 414E 43C8 05B0 4A5F 67E6 *...?BRA
P>


 実行ファイルの先頭部分をダンプしてみるとリロケーションビットは立っておらず(=リロケータブルでは無い)テキストセグメントの開始アドレスが 0x0500 になっています(ファイルヘッダの構造は下図を参照してください)
 今回開発した自作ボードでは CP/M 本体を 0x0400 からに配置しているので 0x0500 にアプリケーションを置くことはできません。

CP/M-68K の実行ファイルのヘッダ構造


 Forth83 にはソースが同梱されていなかったので他の Forth は無いか探したところ、CP/M-68K 用ではありませんが 68K 用の Fig-FORTH がソース付きで見つかりました。アセンブラソースのコンソール入出力部分を下記のように CP/M-68K 用に書き換え、また CP/M-68K のアセンブラ(as68)が通るように変更しました。

Fig-FORTH のコンソール入出力部分のCP/M対応へ変更
 233                           BDOS    EQU     2
 234                           
 235                           * putc
 236                           *  D0.B <- data
 237                           *
 238 00000004 48E7C000         XEMIT   MOVEM.L D0-D1,-(SP)     * save D0,D1
 239 00000008 2200                      MOVE.L D0,D1
 240 0000000A 7002                      MOVEQ  #2,D0
 241 0000000C 4E42                      TRAP   #BDOS
 242 0000000E 4CDF0003                  MOVEM.L        (SP)+,D0-D1
 243 00000012 4E75                     RTS
 244                           * getc
 245                           *  D0.W -> data
 246 00000014 2F01             XKEY    MOVE.L  D1,-(SP)        * save D1
 247 00000016 303C0006                  MOVE.W #6,D0
 248 0000001A 323C00FF                  MOVE.W #$FF,D1
 249 0000001E 4E42                      TRAP   #BDOS
 250 00000020 221F                      MOVE.L (SP)+,D1
 251 00000022 4E75                     RTS
 252                           *
 253 00000024 700D             XCR     MOVEQ   #ACR,D0
 254 00000026 61DC                     BSR     XEMIT
 255 00000028 700A                     MOVEQ   #LF,D0
 256 0000002A 61D8                     BSR     XEMIT
 257 0000002C 4E75                     RTS
 258                           *
 259                           * kbhit
 260                           *  D0.W -> 0:none
 261 0000002E 2F01             XQTERM  MOVE.L  D1,-(SP)        * save D1
 262 00000030 303C0006                  MOVE.W #6,D0
 263 00000034 323C00FE                  MOVE.W #$FE,D1
 264 00000038 4E42                      TRAP   #BDOS
 265 0000003A 221F                      MOVE.L (SP)+,D1
 266 0000003C 4E75                     RTS
 267                           *
 268 0000003E 4E75             XRSLW   RTS
 269                           *


 DDT を使って動作確認したところ、下図のように A0 レジスタ設定箇所が ワード指定のため符号拡張されてしまいアクセス違反が発生する状況でした。下記の例では A0 を修正してステップ動作を続行していますが、更にその先で A6 が符号拡張されてしまっています。

DDT で Fig-FORTH の動作確認
P>a:ddt f68k.rel

********************************************************
* DDT-68K        9/20/84                   Version 1.3 *
* Serial #XXXX-0000                All Rights Reserved *
* Copyright 1982,1983,1984,1985  Digital Research Inc. *
********************************************************

File is relocatable
text  base   = 00007000   data  base   = 00008758   bss  base   = 00008758
text  length = 00001758   data  length = 00000000   bss  length = 00000002
base page address = 00006F00       initial stack pointer = 000F55DE
-t
PC=00008696 USP=000F55D6 SSP=0000626C ST=0000=>IM=0
D  00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000000
A  00000000 00000000 00000000 00000000  00000000 00000000 00000000 000F55D6
movea.w  #$86E2,A0 .COLDUS
-l
  00008696      movea.w  #$86E2,A0 .COLDUS
  0000869A      move.w  (A0),$2F00
  000086A0      movea.w  $4(A0),A6
  000086A4      movea.w  A6,A1
  000086A6      move.w  #$A,D0
COLD1:
  000086AA      move.w  (A0)+,(A1)+
  000086AC      dbf  D0,86AA .COLD1
  000086B0      adda.w  #$1E,A1
  000086B4      move.w  #$D,D0
COLD2:
  000086B8      move.w  (A0)+,(A1)+
-t
PC=0000869A USP=000F55D6 SSP=0000626C ST=0000=>IM=0
D  00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000000
A  FFFF86E2 00000000 00000000 00000000  00000000 00000000 00000000 000F55D6
move.w  (A0),$2F00
-xa0
A0=FFFF86E2 86e2
-t
PC=000086A0 USP=000F55D6 SSP=0000626C ST=0008=>IM=0 NEG
D  00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000000
A  000086E2 00000000 00000000 00000000  00000000 00000000 00000000 000F55D6
movea.w  $4(A0),A6
-t
PC=000086A4 USP=000F55D6 SSP=0000626C ST=0008=>IM=0 NEG
D  00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000000
A  000086E2 00000000 00000000 00000000  00000000 00000000 FFFF9158 000F55D6
movea.w  A6,A1
-


 Fig-FORTHのソースではデータのポインタを全てワード(2バイト)で扱っているのでデータエリアが 0x8000 以降にあるとアドレス設定時に符号拡張されてしまいうまく動きません(MC68Kはメモリ空間が 16MB あるのに先頭の 32KB の範囲でしか動かせない)。orz

 また、コールドスタート時に下記のように $2F00 番地(何故ラベルでは無くイミーディエット値のアドレスなのか?)のメモリに書込みを行っているので CP/M を壊してしまいます。

Fig-FORTH のコールドスタート処理部分
3292 00001694 1696             COLD    DC.W    2+*
3293 00001696 307C16E2                 MOVE.W  #COLDUS,A0      * BOOTLIST
3294 0000169A 33D000002F00             MOVE.W  (A0),$2F00      * TOP NFA
3295 000016A0 3C680004                 MOVE.W  4(A0),A6        * SET USER POINTE
3296 000016A4 324E                     MOVE.W  A6,A1           * WORK COPY OF US
3297 000016A6 303C000A                 MOVE.W  #$0A,D0         * MOVE ELEVEN BOO
3298 000016AA 32D8             COLD1   MOVE.W  (A0)+,(A1)+     * ONE AT A TIME
3299 000016AC 51C8FFFC                 DBF     D0,COLD1        * UNTIL DONE,
3300 000016B0 D2FC001E                 ADD.W   #$1E,A1         * POINT TO BYTE U
3301 000016B4 303C000D                 MOVE.W  #$0D,D0         * MOVE 14 MORE BO


 結果としては Fig-FORTH と最初に書いた Forth83 が動かない原因は、今回開発したボードで CP/M 本体をメモリの先頭に配置したことが大きな原因であるいうことになってしまいました。ネットで入手できる CP/M-68K のアーカイブファイルに CP/M を 0400H に配置したサンプル(CPM400.SR)があり、CP/M の配置場所が実装メモリサイズに依存しない点が気に入り採用したのですが問題が発生する事例に出会ったので、CP/M 本体をメモリの後方に配置することで対応します。
 「3チップ構成Pic24CPM68Kマイコン(CP/M-68K起動までの作業まとめ)」の記事で公開している Pic24CPM68K ボード用の CP/M インストール用ファイルも メモリ上位に CP/M を配置するように修正しておきました。
 CP/M の Programmer's Guid にもメモリモデルについては下記のように書いてありました。

CP/M-69K Default Memory Model


 しかし、CP/M-68K には reloc コマンドが用意されていることや BIOS 内の memory region データで使用可能なメモリの先頭アドレスとサイズを複数設定できる仕様になっていることを考えると TPA が 0x0400 から始まる前提のアプリケーション側にも少し問題があると思います(今回の Fig-FORTH は CP/M 用ではないので当てはまりませんが)

 CP/M-68K のメモリ位置の変更は BIOS の memory region 部の値を変えるだけなので直ぐに対応できます(CP/M-68Kはbiosの変更時には A: ドライブのCPM.SYSを差換えるだけなので楽です)
 冒頭に書いた Forth83 は1983年に制定された規格で Forth の中では新しいみたいなので気を取り直してこれを動かしてみました。
 CP/M-68K 本体をメモリの後方に移動し 0x0400 から TPA として使えるようになったので想定通り Forth83 が動作するようになりました。
 ダウンロードしたアーカイブファイルには F83.68K が含まれていたので再構築する必要はないのですが、登録 word をカスタマイズする場合等のために README.TXT に書いてあった再構築手順を書いておきます。

 [セルフコンパイルの手順]
  1. KERNEL.68K の作成
     A: ドライブに F83.38K、B: ドライブに META68.BLK と KERNEL68.BLK を配置し、B:ドライブ上で次のコマンドを実行する。
    
      B>a:f83 meta68.blk
        1 load
        bye
      B>
    すると A: ドライブに KERNEL.68K が作成されます。

  2. F83.68K の作成
     A: ドライブに EXTEND68.BLK と CPU68000BLK を配置し次のコマンドを実行する。
    
      A>kernel extend68
        1 load
        bye
      A>
    
     すると F83.68K が作成されます。

 日本語のマニュアルがあるといいのですが見つからなかったので F83 TUTOR を参考にしました(まだ読んでいる途中ですが)
 動作確認のために hello 表示と階乗ではなく階和?のワードを作成した際のログを貼っておきます。

Forth83 での Hello表示例
P>f83

68000 Forth 83 Model
Version 2.1.0
Modified 03Jun84
: hel begin crlf ." Hello,world" 1- dup 0= until drop ;  ok
3 hel
Hello,world
Hello,world
Hello,world ok
.s Empty  ok
: sum dup begin 1- dup rot + swap dup 1 = until drop . ;  ok
10 sum 55  ok
bye
114 Pages
P>


 実は階和の方はWeb上のサービスである Try It Online の gForth 環境で適当に作ったものが動いたので Froth83 でも試して見たものです(まだ慣れていないので冗長な処理になっているかも)。こういう手軽な環境があると今更と言う感じもするのですが、やはり実際のボード上で CP/M-68K を使って動かすと格別な楽しさを感じますね ^^


★追記 2022/02/25 {
 Forth のソースファイルである BLK ファイルの作成と編集及び実行ファイルの作成方法について操作方法を確認しましたので操作サンプルを貼っておきます。

blkファイルと実行ファイル作成の操作例
P>f83

68000 Forth 83 Model
Version 2.1.0
Modified 03Jun84
10 create-file my.blk  ok
0 edit
Enter your ID: test blk ..

Scr # 0         MY.BLK
 0                                                                  0
 1                                                                  1
 2                                                                  2
 3                                                                  3
 4                                                                  4
 5                                                                  5
 6                                                                  6
 7                                                                  7
 8                                                                  8
 9                                                                  9
10                                                                  10
11                                                                  11
12                                                                  12
13                                                                  13
14                                                                  14
15                                                                  15
 0 ^

 ok
 0 ^
p \ test how to create block and execute file  ok
 0 ^\ test how to create block and execute file
done
0 modified ok
1 edit

Scr # 1         MY.BLK
 0                                                                  0
 1                                                                  1
 2                                                                  2
 3                                                                  3
 4                                                                  4
 5                                                                  5
 6                                                                  6
 7                                                                  7
 8                                                                  8
 9                                                                  9
10                                                                  10
11                                                                  11
12                                                                  12
13                                                                  13
14                                                                  14
15                                                                  15
 0 ^

 ok
 0 ^
p \ test block  ok
 0 ^\ test block
u : hel cr ." Hello, world" 0 0 bdos ;  ok
 1 ^: hel cr ." Hello, world" 0 0 bdos ;
done
1 modified ok
update  ok
see hel HEL  ?
1 load  ok
see hel
: HEL   CR (.") Hello, world 0 0 BDOS ;  ok
' hel is boot  ok
save-system hello.68k  ok
hel
Hello, world
P>a:stat hello.68k

 DRIVE P:                         USER :  0
 RECS  BYTES FCBS ATTRIBUTES      NAME
  227    30K    2 DIR RW        P:HELLO   .68K
----------------------------------------------
TOTAL:   30K    2
P: RW, FREE SPACE:       618K
P>hello

Hello, world
P>

}

★追記 2022/02/25 {
 Forth でリカーシブコールするためには WORD 定義中に WORD 自身の名前を書くのではなく、RECURSE という WORD を書くことで実現できます。上記で書いた階和をリカーシブコールで再定義したものを以下に示します。少し見易くなりましたね。
 同様のロジックで加算を乗算に変えれば階乗の WORD も定義できます。
 フィボナッチ数列も再帰呼出しで簡単に書けました。

Forth でのリカーシブコール例
P>f83

68000 Forth 83 Model
Version 2.1.0
Modified 03Jun84
: sum ( n -- sum ) dup 1 > if dup 1- RECURSE + then ;  ok
10 sum . 55  ok
  ok
: fact ( n -- fact ) dup 1 > if dup 1- RECURSE * then ;  ok
10 fact . 24320  ok
: fibo ( n -- fibo ) RECURSIVE dup 1 > if 1- dup fibo swap 1- fibo + then ;  ok
: fibo10 11 0 do cr i dup ." fibo( " . ." ) = " fibo . loop ;  ok
fibo10
fibo( 0 ) = 0
fibo( 1 ) = 1
fibo( 2 ) = 1
fibo( 3 ) = 2
fibo( 4 ) = 3
fibo( 5 ) = 5
fibo( 6 ) = 8
fibo( 7 ) = 13
fibo( 8 ) = 21
fibo( 9 ) = 34
fibo( 10 ) = 55  ok

}
★変更 2022/02/26
 再帰呼出しワードの定義はワード名直後に RECURSIVE と書けば定義内で自分自身を名前でコールできるのようなので上記のフィボナッチの定義では RECURSIVE を使うように変更しました。RECURSE という書き方は元々は定義部分のワード名を変更した場合に書き換える箇所を少なくするためのようですが、個人的には自身の名前を使って定義した方がしっくり来て見易いように感じます。

★追記 2022/03/06
 Forthでの変数宣言は ”variable 変数名” で可能ですが、配列の使い方について確かめてみました。
 create と allot のワードにより配列名に対して領域を確保し、"!" で配列要素に値を設定、"@" で配列要素の値をスタック上に置くことが出来ます。領域確保時のサイズの値はバイト単位で指定し、ディフォルトの整数サイズが2バイトなのでサイズは「要素数x2」の値で設定する必要があります。gForth 等では cells のワードで1ワードのバイト数を掛けることで領域を要素数で指定できるようですが F83 は対応していないようです。
 配列宣言、要素への値の設定と読み出しのサンプルを貼っておきます。

Forth83 での配列宣言と値の設定及び読み出し操作のサンプル
P>f83

68000 Forth 83 Model
Version 2.1.0
Modified 03Jun84
hex  ok
create abc 8 allot  ok
: setar ( -- ) 4 0 do i dup 2 * abc + ! loop ;  ok
: dspar ( -- ) 4 0 do i 2 * abc + @ . loop ;  ok
setar  ok
dspar 0 1 2 3  ok
abc 10 dump
       0  1  2  3  4  5  6  7   8  9  A  B  C  D \/  F  0123456789ABCDVF
70C0  54 D9 70 AC 00 00 70 BA  83 41 42 C3 05 56 00 00  TYp,..p:.ABC.V..
70D0  00 01 00 02 00 03 00 00  6F CC 85 53 45 54 41 D2  ........oL.SETAR ok
abc . 70CE  ok



[TOP] [ 前へ ] 連載記事 [ 次へ ]

nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。