dポイントプレゼントキャンペーン実施中!

ソースが長めなので、簡潔に書きます。ご無礼の段、ご容赦ください。
【目的】PC-9801本体のCバス(汎用拡張スロット)に挿したサウンドボード上の
ROM BIOSを読み出し、バイナリファイルに落としたい。既にエミュレータ用に実機からの
吸出しツールは存在するが、ソースが無いので、自作することにした。
その前段階としてアセンブラの修行も兼ねて、ROM BIOSの先頭3ワード(6バイト)を
メモリ上のバッファにコピーし、比較して値の合致を確認したい。
将来的にはSCSI ROM BIOSの解析等を試みたい。

【方針】8086のストリング命令でダイレクトにメモリtoメモリでブロック転送を
する。具体的にはrep movsbを用い、6バイトを転送する。

【備考】PC-9801-26K互換音源のROM BIOS(少なくとも先頭8バイト)は一意であり、
その並びは、0001h, 0000h, 00d2h である。例外はありません。
86音源でも同様で、下位互換性があることは、拙作ツール(OPNCHK.COM)にて確認済み。
なお、上記バイト列は、セグメントCC000h:オフセット2E00hから読み出し
可能である。
なお実行にあたり、所謂メモリマネージャの類(MELEMM.386等)は一切
組み込まない状態で行なう(EMSメモリマネージャ等との同居対応は将来の課題とします)。

【開発環境】PC-9801DA2(Cyrix Cx486DLC-25MHzに載せ換え; 13.6MB RAM; HA-55BS4 SCSIボード
+ 240MB SCSI HDD + SONY CPD-17SF9 CRT
+ NASM 2.06rc10 on NEC DOS 5.0A-H + Turbo Debugger v3.2 と、
秋葉で買ったジャンクFDに入ってたMASM ver 3.00;
予備機 VX41/RS21/EPSON 286VF/EPSON 486HX2/Xv13R16[K6-2 400MHz]/
AT互換機上のNekoIIエミュ/Cygwin上のnasmw.exe)

【参考書】PC-98、8086アセンブラ、テクニカルデータ、古雑誌等 定番本100冊ほど

【拙作コードの失敗点をご指南いただきたい。NASMコードですが、MASM/TASMでも構いません】
; PC-9801-26K compatible Sound ROM BIOS Copy Program (i/o address 0188h)
; Programmed by OrzHacker666
; Date 2009-07-13 for NASM 2.06rc10

[Bits 16]
org 100h ; COM program
section .text
start:
push es ; これを保存しないと、
push ds ; 画面がめちゃくちゃになる

mov ax, 0cc00h ; Sound ROM セグメントアドレス
mov es, ax
mov ds, ax ; DS:SI -> ES:DI 無意味か?
mov bx, 2e00h ; Sound ROM オフセットアドレス

lea si, [es:bx] ; ES:BX がSound ROMの開始点
lea di, [ds:sbuff] ; sbuffは仮に確保したバッファ。
; どこにあるかは、当たり前ですが、不明。そこら辺はCの変数宣言と同じですが。

mov cx, 8 ; とりあえず、アタマ8バイトをコピー
cld
rep movsb

CompareWithOriginal:
cmp word [es:bx+4], 00d2h ; これは通る。当たり前。
jne FailedCpyRom
cmp word [ds:sbuff+4], 00d2h ; ここで失敗判定。なぜ?
jne FailedCpyRom
; sbuffにes:bx~が正しく
; 転送されていないのか?
SuccessCpyRom: ; これを拝めれば…。
pop ds
pop es
mov ah, 9
lea dx, [SUCCESSMsg]
int 21h
mov ax, 4c00h
int 21h

FailedCpyRom: ; 見飽きましたOrz
pop ds
pop es
mov ah, 9
lea dx, [FAILEDMsg]
int 21h
mov ax, 4c00h
int 21h

section .data
SUCCESSMsg:
db 'Succeeded !!', 0dh, 0ah, '$'
FAILEDMsg:
db 'Failed(--;)', 0dh, 0ah, '$'

section .bss
sbuff:
resb 8 ; Cで書くと、差し詰め unsigned char sbuff[8]; であろうか…。

識者の方、よろしくお願いいたします。気になって夜も眠れません。

A 回答 (3件)

>回答中の、"cmp word es:[di-4], 00D2h"は


MOVSD×2でDIはsbuff+8を指しています。DI-4はsbuff+4のことです。
これくらいはアセンブラをやる以上、直ぐに分かってください。

>sbuff自体については、セグメント値は不定で、調べる意義は無い
ちょっと乱暴な話ですね。sbuffはbss(初期値なし静的領域)のよう
なので、実行時のDSです。

確実なのはtextセグメント(コードと同じ)に次のようにデータを
定義して使います。
LES  DI,CS:adr 'ES:DIにsbuffのセグメント:オフセットが入る
== 中略 ==
adr  DD sbuff 'sbuffのセグメント:オフセットが記録される

>DS=ESではダメです
だって、そうなっていますよ。AXをDSにもESにもMOVしてます。
前にも書いたんですが、セグメントの使い方が分かっていない?

前のサンプルは上記仮定(sbuffは実行時DSにある)で作っています。
PUSH DS、POP ES ES←DSにしています。(受け取り側が実行時DS)
この後で、DSに0CC00hを代入しています。

>[es:]のオーバーライドは必須です
CMP   WORD ES:[DI-4],00D2h
ちゃんと、ESでオーバライドしてるはずですけどね。

>ジレンマに陥ります
どこがでしょう?アセンブラで、セグメントレジスタを使う以上は
自分の自由に使えば良い訳で、適当に値を設定したり、戻したりすれば
済む話なのでは?
例:
REP  MOVSB
PUSH  DS
PUSH  ES
POP   DS
POP   ES
後の4命令で、DSは実行時DSに戻り、ESはROMセグメントを指します。
サンプルではこれをやっていないので、実行時DSはESにある状態です。
故にセグメントオーバーライドしています。
    • good
    • 0
この回答へのお礼

試行錯誤の後、完成しましたので、ソースを掲載いたしまして終了いたします。
なお、この後にSound BIOS ROM 16KB全部を
sbuff resw 8192
とした領域へ完全コピーすることに成功しました(別ソースですが)。
# あとは、DOSファンクションコールで、RAMからファイルへの
# 読み書きを付け加えれば当初の目的は達成可能となります。
# ご指南ありがとうございました。

; PC-9801 Sound BIOS Rom Copy Program(first 3 words(6 bytes) only)
; Programmed by OrzHacker666
; ver 1.04
; Date 2009-07-14
; for NASM 2.06rc10

[Bits 16]
org 100h ; COM program
section .text
start:
push ds

mov ax, 0cc00h; Sound BIOS Segment Address
mov ds, ax; DS=CC00H
mov bx, 2e00h; Sound BIOS Offset Address

lea si, [ds:bx]; DS:SI points the Sound BIOS Address
lea di, [sbuff]; and store them on ES:DI (sbuff)

mov cx, 3; copy first 6 bytes (3 words)
cld
rep movsw

CompareWithOriginal:
pop ds
cmp word [sbuff], 0001h
jne FailedCpyRom
cmp word [sbuff+2], 0000h
jne FailedCpyRom
cmp word [sbuff+4], 00d2h; Check if sbuff contains
jne FailedCpyRom; the original Sound BIOS Data

SuccessCpyRom:
mov dx, SUCCESSMsg
mov ah, 9
int 21h
mov ax, 4c00h
int 21h

FailedCpyRom:
mov dx, FAILEDMsg
mov ah, 9
int 21h
mov ax, 4c00h
int 21h

section .data
SUCCESSMsg:
db 'Succeeded !!', 0dh, 0ah, '$'
FAILEDMsg:
db 'Failed(--;)', 0dh, 0ah, '$'

section .bss
sbuffresw 3

以上

お礼日時:2009/07/15 00:44

>lea di, [ds:sbuff] ; sbuffは仮に確保したバッファ。


>; どこにあるかは、当たり前ですが、不明。そこら辺はCの変数宣言と同じですが。

いやcom programならcsと同じsegment上のオフセット値。なので、

>mov ax, 0cc00h ; Sound ROM セグメントアドレス
>mov es, ax
>mov ds, ax ; DS:SI -> ES:DI 無意味か?

これだとやっぱり(3)ということになります。

この回答への補足

ご回答ありがとうございます。

あれから数時間格闘したのですが、自作のデバッグコードを
仕込んだりしてみた結果、以下のような中間結果が出ました。
まず、
1)sbuff自体については、セグメント値は不定で、調べる意義は無い。
強いて言えば、お二方ご指摘の通り、ROM領域にぶち当たらないように
することでしょうか。ただし、ソース末尾に未定義領域として
sbuff: resb 8
として確保しており、また、割り込み禁止状態でmov word [sbuff+4], 00d2hと強制書込した上で、
cmp word [sbuff+4], 00d2hが一致することを確認したので、
sbuffは確実にRAM領域に確保されていると考えられる(なにより、resb擬似命令で
ROM領域にバイト列をリザーブするのは、NASMの仕様上あり得ないことなので。MASMでも同様でしょう)。
上記は、mov ds, axでES=DS=CC00Hとするのを止め、DS=初期値と
した結果、書込成功したということです。
ご指南の通りにmov ds, axを廃止したところ、mov word [ds:sbuff], 00d2h
でも
mov word [sbuff], 00d2h
でも、(バイト数の無駄の違いこそあれ)sbuffへの00d2hの値の書込みは正常に行なわれていることが確認されました。

2)コピー失敗時のセグメントレジスタおよびsbuffの値を追ったところ、
以下の通りであった:(DSは初期状態のままとした場合)
DS = 1322H
ES = CC22H
sbuff = 0222H
Q: DS/ES/sbuffともに、下1バイトが22Hとなっているが、これは
どこからきた値なのか?ESの上1バイトがCCHとなっているのは、
最初にAXから代入した際(mov ax, 0cc00h/mov es, ax)から理解できる。
sbuffの上1バイトについては起動毎に変わる(不定域ですから)。
DSの13xxHについては、org 100hでCOM宣言した際のオリジナル値であり、
SSも同じ値であると思われる。これも、不定だと思います。

いま、参考書をひっくり返して思案しています。すみません。

補足日時:2009/07/13 20:02
    • good
    • 0

セグメントオーバライドが間違っていますが、DS=ESなので、結果は


同じになります。
lea si, [es:bx] ; ES:BX がSound ROMの開始点 → MOV SI,BX
セグメントオーバライドは無意味、1バイトと数クロックの損
cmp word [es:bx+4], 00d2h ; これは通る。当たり前。→ES:は不要
セグメントオーバライドは無意味、1バイトと数クロックの損
DS:送り出し側、ES:受け取り側です。ここまではDS=ESなら問題は
ありません。送り出し側の+4と受け取り側の+4で内容が異なる
となると、次の点が可能性として考えられます。
(1)割り込みにより、内容が書き換えられる。
(2)送り出し側と受け取り側のアドレスが一部で重複する。
(3)受け取り側がROMで、内容が変化しない。

個人的な見解としては(3)ではないかと思います。
転送先(sbuff)のセグメントがROMと同じなのがどうもアヤシイ

PUSH  ES ;保存
PUSH  DS ;保存
PUSH  DS ;ES←DSのための第1ステップ
POP   ES ;ES←DSのための第2ステップ
MOV   AX,0CC00h
MOV   DS,AX
MOV   BX,2E00h
MOV   SI,BX
LEA   DI,sbuff
CLD
CLI ;念のため割り込み禁止にする
MOVSD ;ダブルワード(4バイト)転送
MOVSD ;ダブルワード(4バイト)転送
CMP   WORD ES:[DI-4],00D2h
STI ;割り込み許可
JNE   FailedCpyRom

上記は規定データセグメント上にsbuffがあるものと仮定しています。
もう一度、セグメントレジスタの使い方を見直してください。

この回答への補足

ご回答ありがとうございます。cli/sti対策をしてみました。
# 回答中の、"cmp word es:[di-4], 00D2h"は、sbuffのオフセットアドレスから
4バイト目の値と00d2hの比較の書き間違いでしょうか?
# 正しくは、"cmp word es:[sbuff+4], 00d2h"もしくは、push di/pop diを
movsbの前後に挟み込むしかないでしょうね。
# word [es:di+4]との比較ですと、さらに4バイト先まですっ飛んでしまいますので。

あれから数時間格闘したのですが、自作のデバッグコードを
仕込んだりしてみた結果、以下のような中間結果が出ました。
まず、
1)sbuff自体については、セグメント値は不定で、調べる意義は無い。
強いて言えば、お二方ご指摘の通り、ROM領域にぶち当たらないように
することでしょうか。ただし、ソース末尾に未定義領域として
sbuff: resb 8
として確保しており、また、割り込み禁止状態でmov word [sbuff+4], 00d2hと強制書込した上で、
cmp word [sbuff+4], 00d2hが一致することを確認したので、
sbuffは確実にRAM領域に確保されていると考えられる(なにより、resb擬似命令で
ROM領域にバイト列をリザーブするのは、NASMの仕様上あり得ないことなので。MASMでも同様でしょう)。
上記は、mov ds, axでES=DS=CC00Hとするのを止め、DS=初期値と
した結果、書込成功したということです。
ご指南の通りにmov ds, axを廃止したところ、mov word [ds:sbuff], 00d2h
でも
mov word [sbuff], 00d2h
でも、(バイト数の無駄の違いこそあれ)sbuffへの00d2hの値の書込みは正常に行なわれていることが確認されました。

2)コピー失敗時のセグメントレジスタおよびsbuffの値を追ったところ、
以下の通りであった:(DSは初期状態のままとした場合)
DS = 1322H
ES = CC22H
sbuff = 0222H
Q: DS/ES/sbuffともに、下1バイトが22Hとなっているが、これは
どこからきた値なのか?ESの上1バイトがCCHとなっているのは、
最初にAXから代入した際(mov ax, 0cc00h/mov es, ax)から理解できる。
sbuffの上1バイトについては起動毎に変わる(不定域ですから)。
DSの13xxHについては、org 100hでCOM宣言した際のオリジナル値であり、
SSも同じ値であると思われる。これも、不定だと思います。

いま、参考書をひっくり返して思案しています。すみません。

補足日時:2009/07/13 20:23
    • good
    • 0
この回答へのお礼

お礼の欄で釈明することをお許しください。

#1)DS=ESなので、結果は同じになります。
A. DS=ESではダメです。ESはSound ROM BIOSのセグメントアドレスを
示すために、0cc00hを代入する必要があります。
MOV SI,BX
としてしまうと、これは単にsiにbx(=2e00h)を代入するだけになってしまいます。ここで
lea si, [es:bx]としているのは、siレジスタに、CC00H:2E00Hのアドレスを代入したいということなのです。
[es:]のオーバーライドを取り払ってしまえば、Sound ROMと無関係なBX(アドレス)がSIに入ってしまいます。

#2)cmp word [es:bx+4], 00d2h ; これは通る。当たり前。→ES:は不要
A. 同上の理由で、[es:]のオーバーライドは必須です。無関係のBXと00d2hは
一致しません。

Q. 結局、DSは初期値のままでいてほしい、かつESはSound ROMのセグメントアドレスを
示して、常にBXと共に用いる必要がある、というジレンマに陥ります。

お礼日時:2009/07/13 20:53

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!