LoginSignup
9
3

More than 3 years have passed since last update.

とある忍者ゲームをビルドしてみたでござる の巻

Last updated at Posted at 2020-01-18

はじめに

先日、ツイッターでとある忍者ゲームのソースがGitHubで公開されたことを知り、折角なのでビルドしてみることとしました。

作業方針

プログラムは 6502 のアセンブラで書かれており、オリジナルの開発環境では MS-DOS 上で CP/M エミュレータを介して ACT65 というアブソリュートアセンブラを使用してビルドをされたようですが、ACT65 は持っていないので別の方法を採ります。
CP/M 時代に良く使われたアセンブラに MS 社の MACRO-80 という製品があり、8080 と Z80 の両方のニモニックを受け付けるリロケータブルマクロアセンブラで優れものでした。これの MSX-DOS 用に販売されたものは MSX とは関係ない筈の 6502 のニモニックをなんでか受け付ける機能が製品仕様外に存在したことは御存知でない方以外には広く知られています。今回はこれを使用することとしました。実機を引っ張り出してきて使うのもしんどいので、『MSX MAGAZINE永久保存版3』に収録された公式MSXエミュレーターを使用しました。他、テキストの編集等に Windows 10 上 で Cygwin を使用しています。

作業の実際

先ず GitHub の件のリポジトリを Cygwin の作業フォルダに拾ってきます。
次に ACT65 と MACRO-80 で書式の違う部分があるので、それの修正を行います。
下記のパッチ

HAT.patch
HAT.patch
--- HAT.A65
+++ HAT.A65
@@ -4,5 +4,6 @@
 ;
    cpu '6502'
+   aseg
 ;
 ;
 adrchk equ 0   ;check memory location
@@ -254,7 +255,7 @@ jmpbtn
 bit7st ds  1
 ;
 ;------------------------------------------------------------
-EZ equ *
+EZ equ $
 ;---------------------  < $ed ======> $10f >--------------------------------
 ;                      debug board reserved !!!!!!
 ;----------------------------------------------------------------------------
@@ -528,7 +529,7 @@ snmy    ds  1
 ;
 ;-------------------------------------------------------------
 ;
-   if  * > $700
+   if  $ > $700
    err ;address $700
    endif
 ;
@@ -574,75 +575,76 @@ ALLPLU    MACRO
    ENDM
 ;
 PTRSET MACRO   DATA,PTR
-   lda #low %1
-   sta %2
-   lda #high %1
-   sta %2+1
+   lda #low DATA
+   sta PTR
+   lda #high DATA
+   sta PTR+1
    ENDM
 ;
 INCPTR MACRO   PTR
-   inc %1
-   bne *+4
-   inc %1+1
+   inc PTR
+   bne $+4
+   inc PTR+1
    ENDM
 ;
 DECPTR MACRO   PTR
    sec
-   lda %1
+   lda PTR
    sbc #1
-   sta %1
-   bcs *+4
-   dec %1+1
+   sta PTR
+   bcs $+4
+   dec PTR+1
    ENDM    
 ;
 PUSHM  MACRO   ADDR
-   lda %1
+   lda ADDR
    pha
    ENDM
 ;
 POPM   MACRO   ADDR
    pla
-   sta %1
+   sta ADDR
    ENDM
 ;
 JTBL   MACRO   DATA
-   dw  %1 - 1
+   dw  DATA - 1
    ENDM    
 ;
 INDCAL MACRO   JMPVEC,REG
-   lda #high ?%K
+   LOCAL   K
+   lda #high K
    pha
-   lda #low ?%K
+   lda #low K
    pha
-   lda %1+1,%2
+   lda JMPVEC+1,REG
    pha
-   lda %1+0,%2
+   lda JMPVEC+0,REG
    pha
-?%K:   rts
+K: rts
    ENDM
 ;
 INDJMP MACRO   JMPVEC,REG
-   lda %1+1,%2
+   lda JMPVEC+1,REG
    pha
-   lda %1+0,%2
+   lda JMPVEC+0,REG
    pha
    rts
    ENDM
 ;
 ;
 ANDDB  MACRO   ANDDAT,NOMAL
-   db  %1 and $fc,%2
+   db  ANDDAT and $fc,NOMAL
    ENDM
 ;
 CKIDB  MACRO   XLOW,XHIGH,YDATA
-   db  %1 and $f8,%2,%3 and $f8
+   db  XLOW and $f8,XHIGH,YDATA and $f8
    ENDM
 ;
 SPBDB  MACRO   XLOW,XHIGH,YDATA
-   db  %1 * 8,%2,%3 * 8 + $30
+   db  XLOW * 8,XHIGH,YDATA * 8 + $30
    ENDM
 BOSDB  MACRO   XCHR0,YCHR0
-   db  %1*8,%2*8+$30
+   db  XCHR0*8,YCHR0*8+$30
    ENDM
 ;
 ;------------  link files  --------------------
@@ -682,4 +684,5 @@ BOSDB   MACRO   XCHR0,YCHR0
    endif
 ;
 ;
+   END
 
\ No newline at end of file
--- HATMUS.A65
+++ HATMUS.A65
@@ -955,19 +955,19 @@ FRQTBL:   DW  $0000   ; REST
 ;
 ;
 ;
-MCTMPO MACRO   %1
+MCTMPO MACRO   _1
    ENDM
 ;
 MCREST MACRO
    DB  0
    ENDM
 ;
-MCTONE MACRO   %1,%2
-   DB  (%1-3)*12+%2+1-3
+MCTONE MACRO   _1,_2
+   DB  (_1-3)*12+_2+1-3
    ENDM
 ;
-MCLENG MACRO   %1
-   DB  %1+$80
+MCLENG MACRO   _1
+   DB  _1+$80
    ENDM
 ;
 MCEND  MACRO
@@ -978,8 +978,8 @@ MCDC    MACRO
    DB  $FE
    ENDM
 ;
-MCRPB  MACRO   %1
-   DB  $FD,%1
+MCRPB  MACRO   _1
+   DB  $FD,_1
    ENDM
 ;
 MCRPE  MACRO
@@ -994,7 +994,7 @@ MCTAIE  MACRO
    DB  $FA
    ENDM
 ;
-MCLEN  MACRO   %1
+MCLEN  MACRO   _1
    ENDM
 ;
 DATATP:
--- HMAIN.A65
+++ HMAIN.A65
@@ -324,6 +324,7 @@ vramon:
    lda #VRMOND
    jmp creg1s
 ;
+scrnoff:
 scrnof:    ;vram off & nmi off
    jsr nmioff
 vramof:
@@ -528,8 +529,8 @@ extinc:
    sta lfeodr
 extirt:    rts
 ;
-SCRDB  MACRO   df,dt,ds,df
-   db  %4,%3,%2,%1
+SCRDB  MACRO   df,dt,ds,df2
+   db  df2,ds,dt,df
    ENDM
 ;
 scrdat:
--- RECHAT.A65
+++ RECHAT.A65
@@ -191,8 +191,9 @@ clplop:
 ;
 ;
 CHRSFT MACRO
+   LOCAL   K
    DEC CHRBIT
-   BPL ?%K
+   BPL K
    PHA
    LDA #7
    STA CHRBIT
@@ -200,14 +201,15 @@ CHRSFT    MACRO
    STA CHRSFD
    PLA
    INY
-   BNE ?%K
+   BNE K
    INC CHRBP+1
-?%K:   ASL CHRSFD
+K: ASL CHRSFD
    ENDM
 ;
 MAPSFT MACRO
+   LOCAL   K
    DEC MAPBIT
-   BPL ?%K
+   BPL K
    PHA
    LDA #7
    STA MAPBIT
@@ -215,12 +217,13 @@ MAPSFT    MACRO
    STA MAPSFD
    PLA
    INY
-?%K:   ASL MAPSFD
+K: ASL MAPSFD
    ENDM
 ;
 COLSFT MACRO
+   LOCAL   K
    DEC COLBIT
-   BPL ?%K
+   BPL K
    PHA
    LDA #7
    STA COLBIT
@@ -228,7 +231,7 @@ COLSFT  MACRO
    STA COLSFD
    PLA
    INY
-?%K:   ASL COLSFD
+K: ASL COLSFD
    ENDM
 ;
 ;

を当て、

$ patch < HAT.patch
patching file HAT.A65
patching file HATMUS.A65
patching file HMAIN.A65
patching file RECHAT.A65

$

そして下記の

makefile
.SUFFIXES:
.SUFFIXES: .A65 .MAC .SCR .MAC

targets: HAT.MAC HATBOU.MAC HATENM.MAC HATMAP.MAC HATMOV.MAC HATMUS.MAC HATTIL.MAC HMAIN.MAC NINPOU.MAC RECHAT.MAC HTBGM.MAC HTBONUS.MAC HTCAT.MAC HTCLEAR.MAC HTCOMP.MAC HTFIRE.MAC HTOVER.MAC HTTOJO.MAC HTWARP.MAC

.A65.MAC:
     perl -f act652m80.pl $< > $@

.SCR.MAC:
     perl -f act652m80.pl $< > $@
act652m80.pl
#!/usr/bin/perl

my $eof = 0;
while (<>) {
    s/[\r\n]//g;
    if (/\x1a/) {
        s/\x1a.*//;
        $eof = 1;
    }
    s/\tmsg/\t;msg/i;
    s/\tECHO/\tREPT/i;
    $_ = reverse $_;
    s/(.*;\t*)([^;]*)$/\2/i;
    my $comment = reverse $1;
    $_ = reverse $_;
    s/\$([a-f])_?([0-9a-f]*)_?([0-9a-f]*)_?([0-9a-f]*)_?([0-9a-f]*)_?([0-9a-f]*)_?([0-9a-f]*)_?([0-9a-f]*)/0\1\2\3\4\5\6\7\8H/ig;
    s/\$([0-9])_?([0-9a-f]*)_?([0-9a-f]*)_?([0-9a-f]*)_?([0-9a-f]*)_?([0-9a-f]*)_?([0-9a-f]*)_?([0-9a-f]*)/\1\2\3\4\5\6\7\8H/ig;
    s/%([01])_?([01]*)_?([01]*)_?([01]*)_?([01]*)_?([01]*)_?([01]*)_?([01]*)/\1\2\3\4\5\6\7\8B/ig;
    s/link\t([^.]+)\.(a65|scr)/include\t\1.mac/i;
    s/cpu\s+'6502'/.6502/i;
    y/[]/()/;
    s/=/EQ/;
    s/>/GT/;
    s/</LT/;
    $_ .= $comment;
    print $_ . "\r\n";
    if ($eof) {
        last;
    }
}
print "\x1a";

makefile と Perl スクリプトを使用してソースファイルを変換します。

$ make
perl -f act652m80.pl HAT.A65 > HAT.MAC
perl -f act652m80.pl HATBOU.A65 > HATBOU.MAC
perl -f act652m80.pl HATENM.A65 > HATENM.MAC
perl -f act652m80.pl HATMAP.A65 > HATMAP.MAC
perl -f act652m80.pl HATMOV.A65 > HATMOV.MAC
perl -f act652m80.pl HATMUS.A65 > HATMUS.MAC
perl -f act652m80.pl HATTIL.A65 > HATTIL.MAC
perl -f act652m80.pl HMAIN.A65 > HMAIN.MAC
perl -f act652m80.pl NINPOU.A65 > NINPOU.MAC
perl -f act652m80.pl RECHAT.A65 > RECHAT.MAC
perl -f act652m80.pl HTBGM.SCR > HTBGM.MAC
perl -f act652m80.pl HTBONUS.SCR > HTBONUS.MAC
perl -f act652m80.pl HTCAT.SCR > HTCAT.MAC
perl -f act652m80.pl HTCLEAR.SCR > HTCLEAR.MAC
perl -f act652m80.pl HTCOMP.SCR > HTCOMP.MAC
perl -f act652m80.pl HTFIRE.SCR > HTFIRE.MAC
perl -f act652m80.pl HTOVER.SCR > HTOVER.MAC
perl -f act652m80.pl HTTOJO.SCR > HTTOJO.MAC
perl -f act652m80.pl HTWARP.SCR > HTWARP.MAC

$

以上で ACT65 用のソースファイルを MACRO-80 用に変換できました。変換された MACRO-80 用のソースファイル *.MAC を公式MSXエミュレーター上の MSX-DOS2 へファイルコピーし、これらを MACRO-80 でアセンブルすることでリロケータブルバイナリとプリントファイルが得られます。公式MSXエミュレーター の turboR モードを使用して 10分近く掛かります。

hat1.png

プリントファイルは以下のような内容(一部抜粋)となってます。

HAT.PRN
  FFFA    8051           C          dw  nmivec          ; nmi vector
   MSX.M-80 2.00   18-Jan-20   PAGE    1-12


  FFFC    8000           C          dw  start           ; reset vector
  FFFE    80DA           C          dw  irqvec          ; irq vector
                         C      ;
                         C          ORG ROMSTR
                         C      ;
  8000    78             C      start:  sei
  8001    D8             C          cld
                         C      ;
  8002    A9 18          C          lda #18H
  8004    8D 2000        C          sta creg0
  8007    AD 2002        C          lda stareg
  800A    AD 2002        C      strlp0: lda stareg
  800D    10 FB          C          bpl strlp0
  800F    AD 2002        C      strlp1: lda stareg
  8012    10 FB          C          bpl strlp1
                         C      ;
                         C          endif
                         C      ;
  8014    A2 FF          C      gstart: ldx #0ffH
  8016    9A             C          txs
                         C      ;
  8017                   C      tstart:
  8017    A2 00          C          ldx #0
  8019    8A             C          txa
  801A    95 00          C      memcl0: sta 0H,x
  801C    E8             C          inx
  801D    E0 ED          C          cpx #0edH
  801F    D0 F9          C          bne memcl0
                         C      ;
  8021    A9 02          C          lda #2
  8023    85 01          C          sta 1H
  8025    A0 00          C          ldy #0
  8027    A2 06          C          ldx #6
                         C      
  8029    A9 00          C          lda #0
  802B    91 00          C      memcl1: sta (0H),y
  802D    C8             C          iny
  802E    D0 FB          C          bne memcl1
  8030    E6 01          C          inc 1H
  8032    CA             C          dex
  8033    D0 F6          C          bne memcl1
                         C      ;
                         C      ;   jmp starta
  8035                   C      starta:
  8035    20 8152        C          jsr init

さて、MACRO-80 はリロケータブルアセンブラなので実行ファイルを得るには通常はリンク作業が必要となります。HEX ファイルを得るべくリンカ LINK-80 を使用して下記コマンドを実行すると、

H>l80 hat,hat/x/e

hat2.png

エラーとなってしまいました。LINK-80 で扱えるファイルサイズを超えたのか、あるいはメモリ配置的な問題かは追いかけておりませんが LINK-80 では HEX ファイルを作成するのは難しい感じです。
仕方がないのでプリントファイル中に出力されたアドレスと内容を HEX ファイルに変換する方法を採ります。元がアブソリュートアセンブラ用のソースであり、プリントファイル中に存在するシンボルはアセンブル時に全て解決している筈なので問題はありません。
プリントファイル HAT.PRN を Cygwin の作業フォルダにコピーし、下記の Perl スクリプトを使用して HEX ファイルを生成します。

prn2hex.pl
#!/usr/bin/perl

my $eof = 0;
while (<>) {
    s/[\r\n]//g;
    if (/\x1a/) {
        s/\x1a.*//;
        $eof = 1;
    }
    if (/^  ([0-9A-F][0-9A-F][0-9A-F][0-9A-F])    ([0-9A-F][ 0-9A-F]+)'?  /) {
        my $sum = 0;
        my $addr = hex($1);
        my $data = $2;
        $data =~ s/([0-9A-F][0-9A-F])([0-9A-F][0-9A-F])/\2\1/g;
        $data =~ s/ //g;
        my $num = int(length($data) / 2);
        $sum += $num;
        $sum += $addr + ($addr >> 8);
        printf(":%02X%04X00", $num, $addr);
        for (my $i = 0; $i < $num; $i++) {
            my $byte = hex(substr($data, 2 * $i, 2)) & 0xff;
            printf("%02X", $byte);
            $sum += $byte;
        }
        printf("%02X\r\n", -$sum & 0xff);
    }
    if ($eof) {
        last;
    }
}
print ":00000001FF\r\n\x1a";
$ perl prn2hex.pl < HAT.PRN > HAT.HEX

$ 

生成された HEX ファイルは以下のような内容(一部抜粋)となってます。

:02FFFA00518034
:02FFFC00008083
:02FFFE00DA80A7
:018000007807
:01800100D8A6
:02800200A918BB
:038004008D0020CC
:03800700AD0220A7
:03800A00AD0220A4
:02800D0010FB66
:03800F00AD02209F
:0280120010FB61
:02801400A2FFC9
:018016009ACF
:02801700A200C5
:018019008ADC
:02801A009500CF
:01801C00E87B
:02801D00E0ED94
:02801F00D0F996
:02802100A902B2
:028023008501D5
:02802500A000B9
:02802700A206AF
:02802900A900AC
:02802B009100C2
:01802D00C88A
:02802E00D0FB85
:02803000E60167
:01803200CA83
:02803300D0F685
:0380350020528155

生成された HEX ファイルが書式的に正しいことの検証として、objcopy コマンドを使用してバイナリファイルへ変換してみます。

$ objcopy -I ihex HAT.HEX -O binary HAT.BIN

$ ls -l HAT.BIN
-rw-r--r-- 1 fujita なし 32768 Jan 18 22:20 HAT.BIN

$

問題ないようです。

ちょっと気になった点

今回はビルドをしてみることを主眼としておりプログラムの内容までは深く見ていないのですが、作業中に発生したアセンブルエラーで

HATENM.A65の651行目
        and     #$1111_0011

という箇所を見つけました。
A レジスタと直値の論理積を取っていますが、直値の値が 16進数 8桁となっており、8ビット CPU である 6502 のプログラムとしてはおかしい感じです。同ファイルの別の箇所では

HATENM.A65の567行目
        and     #%1111_0011

同じ数字の並びが使われていますが、こっちは 2進数なので問題はなさそうです。
これが不具合かは実際にプログラムの動作を理解しないと判断できません。最初は不具合だったが動きが面白かったのでそのまま修正されなかった可能性もゲームソフトではあり得ることであり、今後の課題といえるでしょう。

おわりに

おわりです。

9
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3