mirror of
https://github.com/akuker/RASCSI.git
synced 2024-10-04 00:54:51 +00:00
first commit
This commit is contained in:
commit
35866cfb84
BIN
bin/raspberrypi/rascsi.tar.gz
Normal file
BIN
bin/raspberrypi/rascsi.tar.gz
Normal file
Binary file not shown.
BIN
bin/x68k/RASDRV.SYS
Normal file
BIN
bin/x68k/RASDRV.SYS
Normal file
Binary file not shown.
BIN
bin/x68k/RASETHER.SYS
Normal file
BIN
bin/x68k/RASETHER.SYS
Normal file
Binary file not shown.
158
doc/converter.txt
Normal file
158
doc/converter.txt
Normal file
@ -0,0 +1,158 @@
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
SCSI Target Emulator RaSCSI (*^..^*)
|
||||
version 1.33 for Raspberry Pi
|
||||
|
||||
Powered by XM6 TypeG Technology.
|
||||
Copyright (C) 2016-2018 GIMONS
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
□変換基板の必要性について
|
||||
SCSIはTTLレベルで5Vを220Ωと330Ωで分圧(パッシブターミネータの場合)する
|
||||
ことで各信号線に3V弱の電圧がかかった状態が定常状態(信号的にはネゲート)に
|
||||
なっています。
|
||||
|
||||
イニシエータ側もしくはターゲット側が信号をアサートする(=0V)にしようと
|
||||
すると両端のターミネータから合わせて5000÷220×2=45mAの電流が流れることに
|
||||
なります(X68000のSCSIコントローラであるMB89352のデータシートを見ればシンク
|
||||
電流としてIol48mAとなっています)。
|
||||
|
||||
RPIのGPIOはこのような大きなシンク電流は吸収できません。電気的に安全な接続
|
||||
を行うためには汎用ロジックIC等で変換基板を作る必要があります。汎用ロジック
|
||||
ICで48mAものシンク電流に耐えるのは74LS06とか07といったオープンコレクタで
|
||||
ハイパワータイプのものを使用します。
|
||||
|
||||
作者は74HC541×3,74HC126×1,74HC04×1で基本的なSCSIの方向制御を行い更に
|
||||
74LS07×3を使ってバスをドライブする回路を組んでみたところ問題なく動作する
|
||||
ことを確認しました。
|
||||
|
||||
他にも74LS641の派生版である74LS641-1を使用すると回路はシンプルに構成できる
|
||||
でしょう。ノーマル品と違ってシンク電流が48mA対応なので74LS07を使用する必要
|
||||
はありません。しかし入手性はそれほど良くありません。
|
||||
|
||||
□変換基板の回路図案
|
||||
同じフォルダに回路図案を入れています。
|
||||
|
||||
・target.png
|
||||
SCSIのターゲットモードを使用するための変換基板回路図です。基本機能である
|
||||
HDDやMOのエミュレーションを行うのであればこの回路図相当の物を作れば良い
|
||||
でしょう。使用するGPIOピンも最も少ない構成になります。
|
||||
|
||||
ピンアサインを変更しなければRaSCSIのstandardディレクトリに含まれる
|
||||
バイナリを使用することが可能です。
|
||||
|
||||
・initiator.png
|
||||
SCSIのターゲットモードに加えイニシエータモードを使用するための変換基板
|
||||
回路図です。基本機能に加えてRPIがイニシエータとなって物理HDDにコマンド
|
||||
を発行することが可能になります。モードの制御に追加で一つGPIOピンを消費
|
||||
します。このイニシエータモードを使用したサンプルプログラムとしてrasdump
|
||||
を用意しました。実HDDやMOからイメージファイルにダンプすることができます。
|
||||
オプションでリストア機能も使用できます。
|
||||
|
||||
ピンアサインのカスタマイズでPIN_INDに標準では7を設定してコンパイルする
|
||||
必要があります。ピンアサインのカスタマイズを参照してください。
|
||||
|
||||
・fullspec.png
|
||||
SCSIのターゲットモード、イニシエータモードに加えてSCSIの通信をモニター
|
||||
することができる変換基板回路図です。SCSIプロトコロルを解析する等の特殊
|
||||
要件がある場合はこの回路が最適です。全ての74LS641-1の方向制御をRaSCSI
|
||||
から行いますのでGPIOピンを三つ余分に使用してしまいます。SCSIの開発に
|
||||
興味があればこの回路を組んでみてはどうでしょうか。特徴としてGPIOピン
|
||||
を余分に使用する代わりに上のイニシエータモードが使用できる基板と比較
|
||||
して74LS86が必要にならないため基板がシンプルになるという恩恵があります。
|
||||
|
||||
ピンアサインのカスタマイズで、PIN_TAD,PIN_IND,PIN_DTDにそれぞれ標準
|
||||
では6,7,8を設定してコンパイルする必要があります。ピンアサインの
|
||||
カスタマイズを参照してください。
|
||||
|
||||
□既存のものを手に入れる方法
|
||||
最近では主にTwitter界隈を通じてRaSCSI用の変換基板を作成していただいて
|
||||
いる方々がいらっしゃいます。
|
||||
|
||||
また秋葉原で委託販売されてます。
|
||||
|
||||
家電のKENCHAN 同人ハード(キット)のページ等です。
|
||||
http://www.kadenken.com/shopbrand/ct76/"
|
||||
|
||||
現在のところ市販されているものとして
|
||||
|
||||
・BELさん開発のあいぼむ版
|
||||
・tomcatさん開発のGAMERnium版
|
||||
|
||||
があります。
|
||||
|
||||
□ピンアサインのカスタマイズ
|
||||
GPIOの信号制御論理やピンアサインはgpiobus.hとrascsidrv.cに定義があります。
|
||||
定義が分かれているのはrascsidrv.cだけGPLなので敢えて分離しています。
|
||||
御察し下さい。
|
||||
|
||||
カスタマイズ例としてgpiobus.hとrascsidrv.cに下記の二つの変換基板用定義例を
|
||||
用意しました。配布物の中にはコンパイル済みバイナリも含まれています。
|
||||
|
||||
・BELさん開発のあいぼむ版
|
||||
・tomcatさん開発のGAMERnium版
|
||||
|
||||
□カスタマイズ方法
|
||||
・RaSCSI起動時のメッセージです。
|
||||
CONNECT_DESC
|
||||
|
||||
・信号制御モードを選択します。
|
||||
SIGNAL_CONTROL_MODE
|
||||
|
||||
0:SCSI論理仕様
|
||||
直結またはHPに公開した74LS641-1等を使用する変換基板
|
||||
アーサート:0V
|
||||
ネゲート :オープンコレクタ出力(バスから切り離す)
|
||||
|
||||
1:負論理仕様(負論理->SCSI論理への変換基板を使用する場合)
|
||||
現時点でこの仕様による変換基板は存在しません
|
||||
アーサート:0V -> (CONVERT) -> 0V
|
||||
ネゲート :3.3V -> (CONVERT) -> オープンコレクタ出力
|
||||
|
||||
2:正論理仕様(正論理->SCSI論理への変換基板を使用する場合)
|
||||
RaSCSI Adapter Rev.C @132sync等
|
||||
|
||||
アーサート:3.3V -> (CONVERT) -> 0V
|
||||
ネゲート :0V -> (CONVERT) -> オープンコレクタ出力
|
||||
|
||||
・制御信号ピンアサイン
|
||||
PIN_ACT:SCSIコマンドを処理中の状態を示す信号のピン番号。
|
||||
PIN_ENB:起動から終了の間の有効信号を示す信号のピン番号。
|
||||
PIN_TAD:ターゲット信号(BSY,IO,CD,MSG,REG)の入出力方向を示す信号のピン番号。
|
||||
PIN_IND:イニシーエータ信号(SEL,ATN,RST,ACK)の入出力方向を示す信号のピン番号。
|
||||
PIN_DTD:データ信号(DT0...DT7,DP)の入出力方向を示す信号のピン番号。
|
||||
|
||||
・制御信号出力論理
|
||||
0V:FALSE 3.3V:TRUEで指定します。
|
||||
|
||||
ACT_ON:PIN_ACT信号の論理です。
|
||||
ENB_ON:PIN_ENB信号の論理です。
|
||||
TAD_IN:PIN_TAD入力方向時の論理です。
|
||||
IND_IN:PIN_ENB入力方向時の論理です。
|
||||
DTD_IN:PIN_ENB入力方向時の論理です。
|
||||
|
||||
・SCSI信号ピンアサイン
|
||||
PIN_DT0~PIN_SEL:それぞれSCSI信号のピン番号です。
|
||||
|
||||
□コンパイル方法
|
||||
|
||||
・実行ファイル(rascsi,rasctl)
|
||||
gpiobus.hを修正
|
||||
make clean
|
||||
make
|
||||
|
||||
・カーネルドライバ(rascsidrv.ko)
|
||||
①OS最新化(必要あれば)
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade
|
||||
sudo reboot
|
||||
|
||||
②カーネルヘッダー取得(必要あれば)
|
||||
sudo apt-get install raspberrypi-kernel-headers
|
||||
|
||||
③コンパイル
|
||||
cd kernelmodule
|
||||
rascsidrv.cの修正
|
||||
make
|
||||
[EOF]
|
BIN
doc/fullspec.png
Normal file
BIN
doc/fullspec.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 73 KiB |
BIN
doc/initiator.png
Normal file
BIN
doc/initiator.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
BIN
doc/pinassign.png
Normal file
BIN
doc/pinassign.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 335 KiB |
315
doc/rascsi.txt
Normal file
315
doc/rascsi.txt
Normal file
@ -0,0 +1,315 @@
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
SCSI Target Emulator RaSCSI (*^..^*)
|
||||
version 1.34 for Raspberry Pi
|
||||
|
||||
Powered by XM6 TypeG Technology.
|
||||
Copyright (C) 2016-2018 GIMONS
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
□RaSCSIとは
|
||||
RaSCSIはRaspberry Piで動作するSCSIデバイス(ハードディスク,MO,CD-ROM)を
|
||||
仮想的に再現するエミュレータです。SCSIを採用したSHARPのX68000で使用する
|
||||
ことを目的として開発しました。RaSCSIを導入したRaspberry PiをX68000のSCSI
|
||||
コネクタに接続するだけで物理的なSCSIデバイスとして認識されます。
|
||||
|
||||
X68000以外にもSCSIを採用したFM TOWNSやPC98等のレトロPCでも使用できるかも
|
||||
しれません。作者はFM TOWNSとPC9821Ceで動作するところまでは確認しています。
|
||||
|
||||
RaSCSIはSCSIデバイスをエミュレートするソフトウェアに加えてRaspberry Piの
|
||||
GPIOコネクタをSCSIコネクタに変換する機構の総称を指します。
|
||||
|
||||
□動作環境
|
||||
(1)Raspberry Pi
|
||||
Raspberry Pi 3 Model B を推奨します。
|
||||
|
||||
Raspberry Pi 2 Model BやZeroでも動作すると考えられます。
|
||||
ピンアサインを独自に変更しRaspberry Pi 1で動作させたという報告もあります。
|
||||
|
||||
(2)OS
|
||||
RASPBIAN STRETCHで開発およびテストしています。
|
||||
sudo apt-get update及びsudo apt-get upgradeで最新にしています。
|
||||
このドキュメントを記述している時点で"Linux raspberrypi 4.14.34-v7+"です。
|
||||
|
||||
RaSCSIはSCSI信号をGPIOを利用して制御しているので可能な限り低レイテンシー
|
||||
の状態で使用する必要があります。したがってCUIモードで利用することを推奨
|
||||
します。更に不要なサービスは極力停止して下さい。
|
||||
|
||||
□SCSIコネクタとの接続方法
|
||||
状況が複雑になってきましたのでRaSCSIのホームページ上で情報提供しています。
|
||||
このドキュメントの最後にある公式ホームページを参考にして下さい。
|
||||
|
||||
□配布物
|
||||
配布するアーカイブには実行ファイル、ドキュメント、ソースコードのそれぞれが
|
||||
ディレクトリで分かれて含まれています。
|
||||
|
||||
bin/ ・・・ 実行ファイル
|
||||
raspberrypi/ ・・・ RPI用のプログラム
|
||||
rascsi.tar.gz ・・・ 実行ファイルとカーネルモジュールをtar+gzipしたもの。
|
||||
|
||||
x68k/ ・・・ X68000用のプログラム
|
||||
RASDRV.SYS ・・・ ホストドライブドライバ
|
||||
RASETHER.SYS ・・・ イーサネットドライバ
|
||||
|
||||
doc/ ・・・ ドキュメント
|
||||
rascsi.txt ・・・ 当ドキュメント
|
||||
x68k.txt ・・・ X68000固有機能の説明
|
||||
converter.txt ・・・ 変換基板の説明
|
||||
pinassign.png ・・・ ピンアサイン図
|
||||
target.png ・・・ 変換基板回路図案(ターゲットモード)
|
||||
initiator.png ・・・ 変換基板回路図案(イニシエータサポート)
|
||||
fullspec.png ・・・ 変換基板回路図案(フルスペック)
|
||||
|
||||
src/ ・・・ ソースコード
|
||||
raspberrypi/ ・・・ RPI用のプログラムソース一式
|
||||
x68k/ ・・・ X68000用のプログラム一式
|
||||
|
||||
|
||||
RPIで使用するプログラムはrascsi.tar.gzですのでRPI上に転送してから解凍して
|
||||
下さい。パーミッション等を維持するためにRPI上で解凍することを推奨します。
|
||||
|
||||
rascsi.tar.gzにはstandard,fullspec,aibom,gamerniumのディレクトリが含まれ
|
||||
ています。通常はstandardディレクトリにある実行ファイルを使用して下さい。
|
||||
|
||||
aibom,gamerniumディレクトリのものは"あいぼむ版","GAMERnium版"の変換基板を
|
||||
使用する時のものです。
|
||||
|
||||
fullspecディレクトリのものは公開したフルスペック版変換基板の回路図案で
|
||||
変換基板を作成した時に使用する時のものです。
|
||||
|
||||
□RASCI本体の使用方法(rascsi)
|
||||
|
||||
sudo rascsi [-ID{01234567} FILE] ...
|
||||
|
||||
ルート権限が必要ですのでsudo等で起動する必要があります。
|
||||
オプションに-hを付けると簡単なHELPが表示されます
|
||||
|
||||
Usage: ./rascsi [-ID{0|1|2|3|4|5|6|7} FILE] ...
|
||||
|
||||
ID is SCSI identification number.
|
||||
FILE is disk image file.
|
||||
|
||||
Detected images type based on file extension.
|
||||
hdf : SASI HD image(XM6 SASI HD image)
|
||||
hds : SCSI HD image(XM6 SCSI HD image)
|
||||
hdn : SCSI HD image(NEC GENUINE)
|
||||
hdi : SCSI HD image(Anex86 HD image)
|
||||
nhd : SCSI HD image(T98Next HD image)
|
||||
hda : SCSI HD image(APPLE GENUINE)
|
||||
mos : SCSI MO image(XM6 SCSI MO image)
|
||||
iso : SCSI CD image(ISO 9660 image)
|
||||
|
||||
引数では-ID{01234567}とFILEの一組で一つのSCSIデバイスを指定できます。
|
||||
|
||||
-IDの後ろの番号はSCSI IDです。SCSI IDは0-7を指定できますが通常レトロPC本体
|
||||
がイニシエータとしてID7等を使用していると思います。その場合は0-6を指定する
|
||||
ことになります。
|
||||
|
||||
FILEは仮想ディスクイメージのファイルパスです。イメージファイル名には拡張子
|
||||
が必要です。拡張子によってHD,MO,CDの種別を判定しています。
|
||||
|
||||
例)SCSI ID0にHDIMAGE0.HDS,ID1にHDIMAGE1.HDSを指定して起動する場合、
|
||||
sudo rascsi -ID0 HDIMAGE0.HDS -ID1 HDIMAGE1.HDS
|
||||
|
||||
終了する場合はCTRL+Cで停止します。
|
||||
バックグラウンドで起動した場合にはkillコマンド該当プロセスにINTシグナルか
|
||||
HUPシグナルを送ることで終了します。
|
||||
|
||||
rascsiは起動後にソケット(6868ポート)を開いて外部からの管理コマンドを受け
|
||||
付ける状態になります。したがって既に別プロセスとしてrascsiが起動している
|
||||
場合はエラーメッセージとともに起動を中断します。
|
||||
|
||||
□管理ツールの使用方法(rasctl)
|
||||
バージョン1.10からrasctlという管理ツールを提供します。これはrascsiプロセス
|
||||
がバックグラウンドで起動(6868ポートで接続待ちの状態)している場合にディスク
|
||||
操作のコマンドを発行することが可能となります。コマンドラインは下記の通り。
|
||||
|
||||
rasctl -i ID [-c CMD] [-t TYPE] [-f FILE]
|
||||
|
||||
ID : SCSI ID
|
||||
CMD : 操作コマンド
|
||||
attach : ディスクを取り付ける
|
||||
detatch : ディスクを取り外す
|
||||
insert : メディアを挿入する(MOまたはCDのみ)
|
||||
eject : メディアを取り出す(MOまたはCDのみ)
|
||||
protect : メディアを書き込み禁止にする(MOのみ)
|
||||
TYPE : ディスク種別
|
||||
hd : ハードディスク(SASI/SCSI)
|
||||
mo : MO(光磁気ディスク)
|
||||
cd : CDROM(CDROMドライブ)
|
||||
bridge : ブリッジデバイス
|
||||
FILE : ディスクイメージファイルのパス
|
||||
|
||||
IDは必須です。CMDは省略時はattachと解釈します。TYPEはコマンドがattachの
|
||||
場合にはFILEの拡張子から自動判定します。FILEはTYPEを明示的に指定している
|
||||
場合は拡張子が異なっても構いません。基本的CMD,TYPEの解釈は大文字小文字を
|
||||
無視します。現在のところ最初の1文字でのみ判定しています。
|
||||
|
||||
コマンド例
|
||||
rascsi -i 0 -f HDIMAGE0.HDS
|
||||
|
||||
の場合はSCSI IDは0。CMDはデフォルトでattachでありTYPEは拡張子HDSから判断
|
||||
するのでhdと推測することになりrascsi起動時のオプション指定と同等です。
|
||||
|
||||
現在の状態を確認するにために-lオプションのみを指定するとデバイス一覧が表示
|
||||
されます。コマンドラインは下記の通り。
|
||||
|
||||
rasctl -l
|
||||
|
||||
rasctl自体の起動にはルート権限は必要ありません。
|
||||
|
||||
□ディスクダンプツールの使用方法(rasdump)
|
||||
直結もしくは直結基板、またはイニシエータ対応とした変換基板向けのサンプル
|
||||
プログラムです。現在のところ変換基板では"あいぼむ版"のみ対応してます。
|
||||
|
||||
名前の通りSCSI HDDやMOのイメージをダンプ(オプションでリストア)します。
|
||||
自身のIDはBIDで指定して下さい。省略時は7を使用します。
|
||||
|
||||
rasdump -i ID [-b BID] -f FILE [-r]
|
||||
ID : ターゲットデバイスのSCSI ID
|
||||
BID : RaSCSI自身のSCSI ID
|
||||
FILE : ダンプファイル名
|
||||
-r : リストアモード
|
||||
|
||||
サンプルなので必要最低限の処理しか実装していませんので改造するなりして
|
||||
ご使用下さい。
|
||||
|
||||
□カーネルモジュールの導入方法(rascsidrv.ko)
|
||||
version 1.24から安定化のためにGPIO制御の一部をカーネルモジュールで動作
|
||||
させる拡張を加えました。
|
||||
|
||||
カーネルモジュールを導入しなくても動作できますが、X68000シリーズのSASI
|
||||
を使用する場合や純正SCSIボードを増設した場合はカーネルモジュールの導入
|
||||
を行っていないと動作が不安定になります。
|
||||
|
||||
カーネルモジュールを有効にするには
|
||||
|
||||
sudo insmod rascsidrv.ko
|
||||
|
||||
を実行してください。
|
||||
|
||||
カーネルモジュールの起動を確認するにはdmesgコマンドで出力されるログの
|
||||
最後に次のような表示がされている筈です。
|
||||
|
||||
"RaSCSI GPIO Driver Loaded(STANDARD)"
|
||||
|
||||
注意!
|
||||
カーネルモジュールは使用中のOSのバージョンに依存します。
|
||||
|
||||
rascsiやrasctlと同じ階層にあるrascsidrv.koはRaspberry Pi 2/3用の
|
||||
"Linux raspberrypi 4.14.34-v7+"でコンパイルしたモジュールになります。
|
||||
|
||||
同じ階層のrpi1orZero/rascsidrv.koはRaspberry Pi 1/Zero用です。
|
||||
"Linux raspberrypi 4.14.34+"でコンパイルしたモジュールになります。
|
||||
|
||||
自身でカーネルモジュールをコンパイルする手順を簡単に記しておきます。
|
||||
|
||||
・OSの最新化
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade
|
||||
sudo reboot
|
||||
|
||||
・カーネルヘッダー取得
|
||||
sudo apt-get install raspberrypi-kernel-headers
|
||||
|
||||
・コンパイル
|
||||
cd kernelmodule
|
||||
make
|
||||
|
||||
□サポートするディスクイメージ
|
||||
(1)SCSI ハードディスク
|
||||
HDSファイル形式 (拡張子HDS/HDN/HDI/NHD/HDA)
|
||||
ファイルサイズは10MB以上4095MB以下の範囲で任意のサイズ(但し512バイト単位)
|
||||
|
||||
拡張子が"HDN"の場合はNEC純正55ボード(PC-9801-55)向けの純正ハードディスク
|
||||
エミュレーションを行います。INQUIRYで返却される情報やMODE SENSEのサイズに
|
||||
に違いがあります。
|
||||
|
||||
拡張子が"HDI","NHD"の場合はそれぞれPC98エミュレータであるAnex86及びT98Next
|
||||
のSCSIハードディスクイメージを使用するものです。HDNの時と同様に一部の情報
|
||||
がNEC用に変換されます。
|
||||
|
||||
拡張子が"HDA"の場合はAPPLE純正ハードディスクエミュレーションを行います。
|
||||
INQUIRY及びMODE SENSEで返却される情報に違いがあります。
|
||||
|
||||
(2)SASI ハードディスク
|
||||
HDFファイル形式 (拡張子HDF)
|
||||
ファイルサイズは10441728バイト、20748288バイト、41496576バイトのいずれか
|
||||
(それぞれ10MBドライブ、20MBドライブ、40MBドライブに対応)
|
||||
|
||||
(3)SCSI 光磁気(MO)ディスク
|
||||
MOSファイル形式 (拡張子MOS)
|
||||
ファイルサイズは次の4種類のいずれか:
|
||||
128MBタイプ (127398912バイト)
|
||||
230MBタイプ (228518400バイト)
|
||||
540MBタイプ (533248000バイト)
|
||||
640MBタイプ (635600896バイト)
|
||||
128MB,230MB,540MBは512バイト/セクタ、640MBは2048バイト/セクタになります。
|
||||
|
||||
(4)SCSI CD-ROMディスク
|
||||
ISOファイル形式 (拡張子ISO、ISO9660ベタイメージ)
|
||||
モード1(2048バイト/セクタ)で、データのみ格納されたファイルとRAW形式で記録
|
||||
されたファイルの両方に対応しています。
|
||||
|
||||
□ディスクイメージの作成
|
||||
RaSCSI自体がX68000エミュレータであるXM6 TypeGの派生物です。従ってディスク
|
||||
イメージの作成はXM6 TypeGの「ツール」メニューから行うことを前提としています。
|
||||
もちろん先に説明した仕様に従えばdd等で空のイメージファイルを作成することも
|
||||
可能です。
|
||||
|
||||
例)100MBのHDSイメージ(空ファイル)を作る場合
|
||||
|
||||
dd if=/dev/zero of=HARDDISK.HDS bs=512 count=204800
|
||||
|
||||
□動作実績
|
||||
作者の開発環境であるX68000 PRO(内蔵SASI/純正SCSIボード)、X68030 内蔵SCSI、
|
||||
XVI Compact 内蔵SCSIで動作確認しています。Mach-2でも動作しました。
|
||||
|
||||
他にも初代X68000,ACE,EXPERT,XVI,PRO2,SUPER等で動作報告がありましたので、
|
||||
X68000シリーズはほぼ問題ないでしょう。
|
||||
|
||||
その他のレトロPCではFM TOWNSシリーズ、PC98シリーズ、Apple Macintosh、
|
||||
MSX(MEGA-SCSI利用)で動作報告があります。
|
||||
|
||||
その他の機種でもちらほらと動作報告を頂いています。
|
||||
|
||||
□活用方法
|
||||
XM6等のX68000エミュレータを使用している場合はエミュレータで環境構築したHDD
|
||||
イメージをFTP等でRaspberry Piに転送することでX68000の実機に接続できます。
|
||||
またその逆も然りで実機上に存在するファイルを格納したHDDイメージをPCにFTP等
|
||||
で転送することでエミュレータで活用することができます。
|
||||
|
||||
□ライセンス
|
||||
RaSCSIはカーネルドライバを除きあるがまま"AS IS"で配布されるソフトウェアです。
|
||||
カーネルドライバのソースrascsidrv.cのみGPLです(御察っし下さい)。
|
||||
|
||||
つまり使用者が受けたあらゆる損害に対して一切責任を持ちません。またソフト
|
||||
ウェアに不備もしくは不具合があったとしてもそれを修正する責任もありません。
|
||||
|
||||
RaSCSIを利用することでRaspberry PiやレトロPCが故障するリスクがあります。
|
||||
あくまで自己責任でチャレンジしてください。
|
||||
|
||||
XM6 TypeG同様に実験成果公開という性質上私のHP以外での配布を認めておりません。
|
||||
|
||||
XM6のライセンス条項を継承していますので雑誌/書籍での紹介事前の許諾が必要です。
|
||||
そもそも2017年にもなってSCSIに反応するのは限られた人だけだと思います。
|
||||
|
||||
□変換基板の頒布について
|
||||
変換基板の頒布については作者に許諾を得る必要はありません。
|
||||
一応ご連絡いただければ何かとサポートできるかもしれません。
|
||||
|
||||
但しレトロPCのSCSI環境改善を応援するという趣旨から、
|
||||
有料の場合は
|
||||
|
||||
基板製作費 + パーツ費用 + 運送費 +(社会通念上一般的な)手数料
|
||||
|
||||
を大きく越えるような頒布についてはお止め下さい。
|
||||
|
||||
□公開ホームページ
|
||||
http://www.geocities.jp/kugimoto0715/rascsi/index.html
|
||||
|
||||
□連絡先
|
||||
twitter https://twitter.com/kugimoto0715
|
||||
e-mail kugimoto0715@yahoo.co.jp
|
||||
|
||||
[EOF]
|
BIN
doc/target.png
Normal file
BIN
doc/target.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
109
doc/x68k.txt
Normal file
109
doc/x68k.txt
Normal file
@ -0,0 +1,109 @@
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
SCSI Target Emulator RaSCSI (*^..^*)
|
||||
version 1.33 for Raspberry Pi
|
||||
|
||||
Powered by XM6 TypeG Technology.
|
||||
Copyright (C) 2016-2018 GIMONS
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
□X68000固有の機能について
|
||||
RaSCSIにはブリッジデバイスという仮想的なSCSIデバイスが実装されておりX68000と
|
||||
ホストであるRaspberry Piの橋渡しを行うことができます。このブリッジデバイスと
|
||||
X68000用の専用ドライバを使用して下記の機能を提供します。
|
||||
|
||||
・イーサーネット
|
||||
Neptune-Xと同様のイーサーネット機能を提供します。SCSI接続のイーサーネット
|
||||
BOXのようにRaSCSIが振舞います。Raspberry PiのTAPデバイスにパケットを中継
|
||||
することで実現しています。Ether+と似たものです。
|
||||
|
||||
・ホストファイルシステム
|
||||
X68000のエミュレーターでは標準的な機能であるWindrv相当の機能を提供します。
|
||||
Raspberry Pi上のファイルシステムをリモートドライブとしてマウントすること
|
||||
ができます。
|
||||
|
||||
□ブジッジデバイスの起動方法
|
||||
RaSCSI起動時にファイル名として"BRIDGE"というキーワードを設定するとそのIDに
|
||||
対してブジッリデバイスを生成します。
|
||||
|
||||
ex)
|
||||
sudo rascsi -ID0 HDIMAGE0.HDS -ID6 BRIDGE
|
||||
|
||||
□イーサーネット接続
|
||||
配布物に含まれるRASETHER.SYSを使用します。このデバイスドライバがブリッジ
|
||||
デバイスと連携してイーサーネットのパケット送受信を行うことができます。
|
||||
|
||||
以下、Raspberry Piの仮想アダプタ(TAP)のIPアドレスを「192.168.68.1」として、
|
||||
X68000側を「192.168.68.3」とするケースで説明します。
|
||||
|
||||
・X68000の設定
|
||||
RASETHER.SYSはNeptune-X用ドライバを改造して作ったものですので使用方法は
|
||||
全く同じです。X68000をネット接続するためには他に環境設定を行う必要があり
|
||||
ます。設定方法は自力で調べていただくようお願いします。
|
||||
|
||||
以下実際に使用しているCONFIG.SYSとAUTOEXEC.BATの抜粋です。
|
||||
|
||||
[CONFIG.SYS抜粋]
|
||||
PROCESS = 3 10 10
|
||||
DEVICE = \NETWORK\RASETHER.SYS
|
||||
|
||||
[AUTOEXEC.BAT抜粋]
|
||||
SET SYSROOT=A:/NETWORK/
|
||||
SET temp=A:\
|
||||
SET tmp=A:\
|
||||
SET HOME=A:/NETWORK/ETC/
|
||||
SET HOST=X68000
|
||||
XIP.X
|
||||
IFCONFIG.X lp0 up
|
||||
IFCONFIG.X en0 192.168.68.3 netmask 255.255.255.0 up
|
||||
INETDCONF.X +router 192.168.68.1 -rip
|
||||
INETDCONF.X
|
||||
|
||||
・Raspberry Piの設定
|
||||
TAPデバイスというものを利用していますのでTAPを有効にしてください。恐らく
|
||||
最近のJessieであれば最初から有効なはずです。確認方法は/dev/net/tunという
|
||||
ファイルが存在すれば有効となっていると判断できます。
|
||||
|
||||
仮想アダプタの作成方法は次の様に行います。
|
||||
|
||||
[/etc/rc.local等から設定]
|
||||
ip tuntap add ras0 mode tap user root
|
||||
ip link set ras0 up
|
||||
ifconfig ras0 inet 192.168.68.1/8 up
|
||||
route add -net 192.168.68.0 netmask 255.255.255.0 dev ras0
|
||||
|
||||
上記によってRaspberry Pi(192.168.68.1)とX68000(192.168.68.3)の間で通信が
|
||||
可能になります。
|
||||
|
||||
インターネット等と接続する場合はRaspberry Pi側でブリッジやルーティングの
|
||||
設定が必要になります。ご自身の環境に合わせて設定してください。無線LANの
|
||||
場合にブリッジ構成するには色々と課題があるようなのでフォワーディングと
|
||||
NAT構成等もお勧めです。作者はrc.localで次のような設定で使用しています。
|
||||
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
|
||||
|
||||
□ホストファイルシステム連携
|
||||
X68000エミュレータでよく利用されるWindrvやWindrvXMと同等の機能を提供します。
|
||||
専用のRASDRV.SYSというデバイスドライバを組み込めばRaspberri Piのファイル
|
||||
システムがX68000側のドライブに見えて操作できるということです。
|
||||
|
||||
デバイスドライバの登録は簡単です。
|
||||
例えば
|
||||
|
||||
DEVICE = \SYS\RASDRV.SYS
|
||||
|
||||
この場合はデフォルトでRaspberry Piのルートディレクトリをマウントします。
|
||||
デバイスドライバ起動時にどのドライブにマウントされたか表示されます。
|
||||
ルートを以外をマウントする場合はディレクトリを指定して下さい。/home/pi等を
|
||||
マウントするには
|
||||
|
||||
DEVICE = \SYS\RASDRV.SYS /home/pi
|
||||
|
||||
と指定します。複数のディレクトリを指定すれば別々のドライブとしてマウントする
|
||||
ことが可能です。
|
||||
|
||||
SUSIEをご利用の方はSUSIEより先にRASDRV.SYSを組み込んで下さい。後に組み込むと
|
||||
正しく認識できなくなると報告があります。
|
||||
|
||||
[EOF]
|
51
src/raspberrypi/Makefile
Normal file
51
src/raspberrypi/Makefile
Normal file
@ -0,0 +1,51 @@
|
||||
CC = gcc
|
||||
CFLAGS = -DNDEBUG -O3
|
||||
CXX = g++
|
||||
CXXFLAGS = -DNDEBUG -O3
|
||||
|
||||
RASCSI = rascsi
|
||||
RASCTL = rasctl
|
||||
RASDUMP = rasdump
|
||||
|
||||
BIN_ALL = $(RASCSI) $(RASCTL) $(RASDUMP)
|
||||
|
||||
SRC_RASCSI = \
|
||||
rascsi.cpp \
|
||||
scsi.cpp \
|
||||
disk.cpp \
|
||||
gpiobus.cpp \
|
||||
ctapdriver.cpp \
|
||||
cfilesystem.cpp \
|
||||
filepath.cpp \
|
||||
fileio.cpp
|
||||
|
||||
SRC_RASCTL = \
|
||||
rasctl.cpp
|
||||
|
||||
SRC_RASDUMP = \
|
||||
rasdump.cpp \
|
||||
scsi.cpp \
|
||||
gpiobus.cpp \
|
||||
filepath.cpp \
|
||||
fileio.cpp
|
||||
|
||||
OBJ_RASCSI := $(SRC_RASCSI:.cpp=.o)
|
||||
OBJ_RASCTL := $(SRC_RASCTL:.c=.o)
|
||||
OBJ_RASDUMP := $(SRC_RASDUMP:.c=.o)
|
||||
|
||||
.cpp.o:
|
||||
$(CXX) $(CXXFLAGS) -c $<
|
||||
|
||||
ALL: $(BIN_ALL)
|
||||
|
||||
$(RASCSI): $(OBJ_RASCSI) $
|
||||
$(CXX) -o $@ $(OBJ_RASCSI) -lpthread
|
||||
|
||||
$(RASCTL): $(OBJ_RASCTL) $
|
||||
$(CXX) -o $@ $(OBJ_RASCTL)
|
||||
|
||||
$(RASDUMP): $(OBJ_RASDUMP) $
|
||||
$(CXX) -o $@ $(OBJ_RASDUMP)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(BIN_ALL)
|
4228
src/raspberrypi/cfilesystem.cpp
Normal file
4228
src/raspberrypi/cfilesystem.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1157
src/raspberrypi/cfilesystem.h
Normal file
1157
src/raspberrypi/cfilesystem.h
Normal file
File diff suppressed because it is too large
Load Diff
68
src/raspberrypi/cqueue.h
Normal file
68
src/raspberrypi/cqueue.h
Normal file
@ -0,0 +1,68 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// X68000 EMULATOR "XM6"
|
||||
//
|
||||
// Copyright (C) 2001-2004 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// [ MFC キュー ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#if !defined(queue_h)
|
||||
#define queue_h
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// キュー
|
||||
//
|
||||
//===========================================================================
|
||||
class CQueue
|
||||
{
|
||||
public:
|
||||
// 内部データ定義
|
||||
typedef struct _QUQUEINFO {
|
||||
BYTE *pBuf; // バッファ
|
||||
DWORD dwSize; // サイズ
|
||||
DWORD dwMask; // マスク(サイズ-1)
|
||||
DWORD dwRead; // Readポインタ
|
||||
DWORD dwWrite; // Writeポインタ
|
||||
DWORD dwNum; // 個数
|
||||
DWORD dwTotalRead; // 合計Read
|
||||
DWORD dwTotalWrite; // 合計Write
|
||||
} QUEUEINFO, *LPQUEUEINFO;
|
||||
|
||||
// 基本ファンクション
|
||||
CQueue();
|
||||
// コンストラクタ
|
||||
virtual ~CQueue();
|
||||
// デストラクタ
|
||||
BOOL FASTCALL Init(DWORD dwSize);
|
||||
// 初期化
|
||||
|
||||
// API
|
||||
void FASTCALL Clear();
|
||||
// クリア
|
||||
BOOL FASTCALL IsEmpty() const { return (BOOL)(m_Queue.dwNum == 0); }
|
||||
// キューが空かチェック
|
||||
DWORD FASTCALL GetNum() const { return m_Queue.dwNum; }
|
||||
// キューのデータ数を取得
|
||||
DWORD FASTCALL Get(BYTE *pDest);
|
||||
// キュー内のデータをすべて取得
|
||||
DWORD FASTCALL Copy(BYTE *pDest) const;
|
||||
// キュー内のデータをすべて取得(キュー進めない)
|
||||
void FASTCALL Discard(DWORD dwNum);
|
||||
// キューを進める
|
||||
void FASTCALL Back(DWORD dwNum);
|
||||
// キューを戻す
|
||||
DWORD FASTCALL GetFree() const;
|
||||
// キューの空き個数を取得
|
||||
BOOL FASTCALL Insert(const BYTE *pSrc, DWORD dwLength);
|
||||
// キューに挿入
|
||||
void FASTCALL GetQueue(QUEUEINFO *pInfo) const;
|
||||
// キュー情報取得
|
||||
|
||||
private:
|
||||
QUEUEINFO m_Queue;
|
||||
// 内部ワーク
|
||||
};
|
||||
|
||||
#endif // queue_h
|
209
src/raspberrypi/ctapdriver.cpp
Normal file
209
src/raspberrypi/ctapdriver.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2018 GIMONS
|
||||
//
|
||||
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
|
||||
//
|
||||
// [ TAPドライバ ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "os.h"
|
||||
#include "xm6.h"
|
||||
#include "ctapdriver.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// コンストラクタ
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
CTapDriver::CTapDriver()
|
||||
{
|
||||
// 初期化
|
||||
m_hTAP = -1;
|
||||
memset(&m_MacAddr, 0, sizeof(m_MacAddr));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// 初期化
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#ifdef __linux__
|
||||
BOOL FASTCALL CTapDriver::Init()
|
||||
{
|
||||
char dev[IFNAMSIZ] = "ras0";
|
||||
struct ifreq ifr;
|
||||
int ret;
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
// TAPデバイス初期化
|
||||
if ((m_hTAP = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||
printf("Error: can't open tun\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// IFF_NO_PI for no extra packet information
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
|
||||
if ((ret = ioctl(m_hTAP, TUNSETIFF, (void *)&ifr)) < 0) {
|
||||
printf("Error: can't ioctl TUNSETIFF\n");
|
||||
close(m_hTAP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// MACアドレス取得
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if ((ret = ioctl(m_hTAP, SIOCGIFHWADDR, &ifr)) < 0) {
|
||||
printf("Error: can't ioctl SIOCGIFHWADDR\n");
|
||||
close(m_hTAP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// MACアドレス保存
|
||||
memcpy(m_MacAddr, ifr.ifr_hwaddr.sa_data, sizeof(m_MacAddr));
|
||||
return TRUE;
|
||||
}
|
||||
#endif // __linux__
|
||||
|
||||
#ifdef __NetBSD__
|
||||
BOOL FASTCALL CTapDriver::Init()
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct ifaddrs *ifa, *a;
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
// TAPデバイス初期化
|
||||
if ((m_hTAP = open("/dev/tap", O_RDWR)) < 0) {
|
||||
printf("Error: can't open tap\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// デバイス名取得
|
||||
if (ioctl(m_hTAP, TAPGIFNAME, (void *)&ifr) < 0) {
|
||||
printf("Error: can't ioctl TAPGIFNAME\n");
|
||||
close(m_hTAP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// MACアドレス取得
|
||||
if (getifaddrs(&ifa) == -1) {
|
||||
printf("Error: can't getifaddrs\n");
|
||||
close(m_hTAP);
|
||||
return FALSE;
|
||||
}
|
||||
for (a = ifa; a != NULL; a = a->ifa_next)
|
||||
if (strcmp(ifr.ifr_name, a->ifa_name) == 0 &&
|
||||
a->ifa_addr->sa_family == AF_LINK)
|
||||
break;
|
||||
if (a == NULL) {
|
||||
printf("Error: can't get MAC address\n");
|
||||
close(m_hTAP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// MACアドレス保存
|
||||
memcpy(m_MacAddr, LLADDR((struct sockaddr_dl *)a->ifa_addr),
|
||||
sizeof(m_MacAddr));
|
||||
freeifaddrs(ifa);
|
||||
|
||||
printf("Tap device : %s\n", ifr.ifr_name);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif // __NetBSD__
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// クリーンアップ
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void FASTCALL CTapDriver::Cleanup()
|
||||
{
|
||||
ASSERT(this);
|
||||
|
||||
// TAPデバイス解放
|
||||
if (m_hTAP != -1) {
|
||||
close(m_hTAP);
|
||||
m_hTAP = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// MACアドレス取得
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void FASTCALL CTapDriver::GetMacAddr(BYTE *mac)
|
||||
{
|
||||
ASSERT(this);
|
||||
ASSERT(mac);
|
||||
|
||||
memcpy(mac, m_MacAddr, sizeof(m_MacAddr));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// 受信
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int FASTCALL CTapDriver::Rx(BYTE *buf)
|
||||
{
|
||||
struct pollfd fds;
|
||||
DWORD dwReceived;
|
||||
|
||||
ASSERT(this);
|
||||
ASSERT(m_hTAP != -1);
|
||||
|
||||
// 受信可能なデータがあるか調べる
|
||||
fds.fd = m_hTAP;
|
||||
fds.events = POLLIN | POLLERR;
|
||||
fds.revents = 0;
|
||||
poll(&fds, 1, 0);
|
||||
if (!(fds.revents & POLLIN)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 受信
|
||||
dwReceived = read(m_hTAP, buf, ETH_FRAME_LEN);
|
||||
if (dwReceived == (DWORD)-1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 受信が有効であれば
|
||||
if (dwReceived > 0) {
|
||||
// FCSを除く最小フレームサイズ(60バイト)にパディング
|
||||
if (dwReceived < 60) {
|
||||
memset(buf + dwReceived, 0, 60 - dwReceived);
|
||||
dwReceived = 60;
|
||||
}
|
||||
|
||||
// ダミーのFCSを付加する
|
||||
memset(buf + dwReceived, 0, 4);
|
||||
dwReceived += 4;
|
||||
}
|
||||
|
||||
// バイト数を返却
|
||||
return dwReceived;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// 送信
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int FASTCALL CTapDriver::Tx(BYTE *buf, int len)
|
||||
{
|
||||
ASSERT(this);
|
||||
ASSERT(m_hTAP != -1);
|
||||
|
||||
// 送信開始
|
||||
return write(m_hTAP, buf, len);
|
||||
}
|
53
src/raspberrypi/ctapdriver.h
Normal file
53
src/raspberrypi/ctapdriver.h
Normal file
@ -0,0 +1,53 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2018 GIMONS
|
||||
//
|
||||
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
|
||||
//
|
||||
// [ TAPドライバ ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#if !defined(ctapdriver_h)
|
||||
#define ctapdriver_h
|
||||
|
||||
#ifndef ETH_FRAME_LEN
|
||||
#define ETH_FRAME_LEN 1514
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Tapドライバ
|
||||
//
|
||||
//===========================================================================
|
||||
class CTapDriver
|
||||
{
|
||||
public:
|
||||
// 基本ファンクション
|
||||
CTapDriver();
|
||||
// コンストラクタ
|
||||
BOOL FASTCALL Init();
|
||||
// 初期化
|
||||
void FASTCALL Cleanup();
|
||||
// クリーンアップ
|
||||
void FASTCALL GetMacAddr(BYTE *mac);
|
||||
// MACアドレス取得
|
||||
int FASTCALL Rx(BYTE *buf);
|
||||
// 受信
|
||||
int FASTCALL Tx(BYTE *buf, int len);
|
||||
// 送信
|
||||
|
||||
private:
|
||||
BYTE m_MacAddr[6];
|
||||
// MACアドレス
|
||||
BOOL m_bTxValid;
|
||||
// 送信有効フラグ
|
||||
int m_hTAP;
|
||||
// ディスクプリタ
|
||||
};
|
||||
|
||||
#endif // ctapdriver_h
|
9160
src/raspberrypi/disk.cpp
Normal file
9160
src/raspberrypi/disk.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1108
src/raspberrypi/disk.h
Normal file
1108
src/raspberrypi/disk.h
Normal file
File diff suppressed because it is too large
Load Diff
367
src/raspberrypi/fileio.cpp
Normal file
367
src/raspberrypi/fileio.cpp
Normal file
@ -0,0 +1,367 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// X68000 EMULATOR "XM6"
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2010-2018 GIMONS
|
||||
// [ ファイルI/O(RaSCSI用サブセット) ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "os.h"
|
||||
#include "xm6.h"
|
||||
#include "filepath.h"
|
||||
#include "fileio.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ファイルI/O
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// コンストラクタ
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
Fileio::Fileio()
|
||||
{
|
||||
// ワーク初期化
|
||||
handle = -1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// デストラクタ
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
Fileio::~Fileio()
|
||||
{
|
||||
ASSERT(handle == -1);
|
||||
|
||||
// Releaseでの安全策
|
||||
Close();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// ロード
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL FASTCALL Fileio::Load(const Filepath& path, void *buffer, int size)
|
||||
{
|
||||
ASSERT(this);
|
||||
ASSERT(buffer);
|
||||
ASSERT(size > 0);
|
||||
ASSERT(handle < 0);
|
||||
|
||||
// オープン
|
||||
if (!Open(path, ReadOnly)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// 読み込み
|
||||
if (!Read(buffer, size)) {
|
||||
Close();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// クローズ
|
||||
Close();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// セーブ
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL FASTCALL Fileio::Save(const Filepath& path, void *buffer, int size)
|
||||
{
|
||||
ASSERT(this);
|
||||
ASSERT(buffer);
|
||||
ASSERT(size > 0);
|
||||
ASSERT(handle < 0);
|
||||
|
||||
// オープン
|
||||
if (!Open(path, WriteOnly)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// 読み込み
|
||||
if (!Write(buffer, size)) {
|
||||
Close();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// クローズ
|
||||
Close();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// オープン
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL FASTCALL Fileio::Open(LPCTSTR fname, OpenMode mode)
|
||||
{
|
||||
ASSERT(this);
|
||||
ASSERT(fname);
|
||||
ASSERT(handle < 0);
|
||||
|
||||
// ヌル文字列からの読み込みは必ず失敗させる
|
||||
if (fname[0] == _T('\0')) {
|
||||
handle = -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// モード別
|
||||
switch (mode) {
|
||||
// 読み込みのみ
|
||||
case ReadOnly:
|
||||
handle = open(fname, O_RDONLY);
|
||||
break;
|
||||
|
||||
// 書き込みのみ
|
||||
case WriteOnly:
|
||||
handle = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0666);
|
||||
break;
|
||||
|
||||
// 読み書き両方
|
||||
case ReadWrite:
|
||||
// CD-ROMからの読み込みはRWが成功してしまう
|
||||
if (access(fname, 0x06) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
handle = open(fname, O_RDWR);
|
||||
break;
|
||||
|
||||
// アペンド
|
||||
case Append:
|
||||
handle = open(fname, O_CREAT | O_WRONLY | O_APPEND, 0666);
|
||||
break;
|
||||
|
||||
// それ以外
|
||||
default:
|
||||
ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
// 結果評価
|
||||
if (handle == -1) {
|
||||
return FALSE;
|
||||
}
|
||||
ASSERT(handle >= 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// オープン
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL FASTCALL Fileio::OpenDIO(LPCTSTR fname, OpenMode mode)
|
||||
{
|
||||
ASSERT(this);
|
||||
ASSERT(fname);
|
||||
ASSERT(handle < 0);
|
||||
|
||||
// ヌル文字列からの読み込みは必ず失敗させる
|
||||
if (fname[0] == _T('\0')) {
|
||||
handle = -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// モード別
|
||||
switch (mode) {
|
||||
// 読み込みのみ
|
||||
case ReadOnly:
|
||||
handle = open(fname, O_RDONLY | O_DIRECT);
|
||||
break;
|
||||
|
||||
// 書き込みのみ
|
||||
case WriteOnly:
|
||||
handle = open(fname, O_CREAT | O_WRONLY | O_TRUNC | O_DIRECT, 0666);
|
||||
break;
|
||||
|
||||
// 読み書き両方
|
||||
case ReadWrite:
|
||||
// CD-ROMからの読み込みはRWが成功してしまう
|
||||
if (access(fname, 0x06) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
handle = open(fname, O_RDWR | O_DIRECT);
|
||||
break;
|
||||
|
||||
// アペンド
|
||||
case Append:
|
||||
handle = open(fname, O_CREAT | O_WRONLY | O_APPEND | O_DIRECT, 0666);
|
||||
break;
|
||||
|
||||
// それ以外
|
||||
default:
|
||||
ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
// 結果評価
|
||||
if (handle == -1) {
|
||||
return FALSE;
|
||||
}
|
||||
ASSERT(handle >= 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// オープン
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL FASTCALL Fileio::Open(const Filepath& path, OpenMode mode)
|
||||
{
|
||||
ASSERT(this);
|
||||
|
||||
return Open(path.GetPath(), mode);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// オープン
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL FASTCALL Fileio::OpenDIO(const Filepath& path, OpenMode mode)
|
||||
{
|
||||
ASSERT(this);
|
||||
|
||||
return OpenDIO(path.GetPath(), mode);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// 読み込み
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL FASTCALL Fileio::Read(void *buffer, int size)
|
||||
{
|
||||
int count;
|
||||
|
||||
ASSERT(this);
|
||||
ASSERT(buffer);
|
||||
ASSERT(size > 0);
|
||||
ASSERT(handle >= 0);
|
||||
|
||||
// 読み込み
|
||||
count = read(handle, buffer, size);
|
||||
if (count != size) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// 書き込み
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL FASTCALL Fileio::Write(const void *buffer, int size)
|
||||
{
|
||||
int count;
|
||||
|
||||
ASSERT(this);
|
||||
ASSERT(buffer);
|
||||
ASSERT(size > 0);
|
||||
ASSERT(handle >= 0);
|
||||
|
||||
// 読み込み
|
||||
count = write(handle, buffer, size);
|
||||
if (count != size) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// シーク
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL FASTCALL Fileio::Seek(off64_t offset, BOOL relative)
|
||||
{
|
||||
ASSERT(this);
|
||||
ASSERT(handle >= 0);
|
||||
ASSERT(offset >= 0);
|
||||
|
||||
// 相対シークならオフセットに現在値を追加
|
||||
if (relative) {
|
||||
offset += GetFilePos();
|
||||
}
|
||||
|
||||
if (lseek(handle, offset, SEEK_SET) != offset) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// ファイルサイズ取得
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
off64_t FASTCALL Fileio::GetFileSize()
|
||||
{
|
||||
off64_t cur;
|
||||
off64_t end;
|
||||
|
||||
ASSERT(this);
|
||||
ASSERT(handle >= 0);
|
||||
|
||||
// ファイル位置を64bitで取得
|
||||
cur = GetFilePos();
|
||||
|
||||
// ファイルサイズを64bitで取得
|
||||
end = lseek(handle, 0, SEEK_END);
|
||||
|
||||
// 位置を元に戻す
|
||||
Seek(cur);
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// ファイル位置取得
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
off64_t FASTCALL Fileio::GetFilePos() const
|
||||
{
|
||||
off64_t pos;
|
||||
|
||||
ASSERT(this);
|
||||
ASSERT(handle >= 0);
|
||||
|
||||
// ファイル位置を64bitで取得
|
||||
pos = lseek(handle, 0, SEEK_CUR);
|
||||
return pos;
|
||||
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// クローズ
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void FASTCALL Fileio::Close()
|
||||
{
|
||||
ASSERT(this);
|
||||
|
||||
if (handle != -1) {
|
||||
close(handle);
|
||||
handle = -1;
|
||||
}
|
||||
}
|
83
src/raspberrypi/fileio.h
Normal file
83
src/raspberrypi/fileio.h
Normal file
@ -0,0 +1,83 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// X68000 EMULATOR "XM6"
|
||||
//
|
||||
// Copyright (C) 2001-2005 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2013-2018 GIMONS
|
||||
// [ ファイルI/O(RaSCSI用サブセット) ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#if !defined(fileio_h)
|
||||
#define fileio_h
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// マクロ(Load,Save用)
|
||||
//
|
||||
//===========================================================================
|
||||
#define PROP_IMPORT(f, p) \
|
||||
if (!f->Read(&(p), sizeof(p))) {\
|
||||
return FALSE;\
|
||||
}\
|
||||
|
||||
#define PROP_EXPORT(f, p) \
|
||||
if (!f->Write(&(p), sizeof(p))) {\
|
||||
return FALSE;\
|
||||
}\
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ファイルI/O
|
||||
//
|
||||
//===========================================================================
|
||||
class Fileio
|
||||
{
|
||||
public:
|
||||
enum OpenMode {
|
||||
ReadOnly, // 読み込みのみ
|
||||
WriteOnly, // 書き込みのみ
|
||||
ReadWrite, // 読み書き両方
|
||||
Append // アペンド
|
||||
};
|
||||
|
||||
public:
|
||||
Fileio();
|
||||
// コンストラクタ
|
||||
virtual ~Fileio();
|
||||
// デストラクタ
|
||||
BOOL FASTCALL Load(const Filepath& path, void *buffer, int size);
|
||||
// ROM,RAMロード
|
||||
BOOL FASTCALL Save(const Filepath& path, void *buffer, int size);
|
||||
// RAMセーブ
|
||||
|
||||
BOOL FASTCALL Open(LPCTSTR fname, OpenMode mode);
|
||||
// オープン
|
||||
BOOL FASTCALL OpenDIO(LPCTSTR fname, OpenMode mode);
|
||||
// オープン
|
||||
BOOL FASTCALL Open(const Filepath& path, OpenMode mode);
|
||||
// オープン
|
||||
BOOL FASTCALL OpenDIO(const Filepath& path, OpenMode mode);
|
||||
// オープン
|
||||
BOOL FASTCALL Seek(off64_t offset, BOOL relative = FALSE);
|
||||
// シーク
|
||||
BOOL FASTCALL Read(void *buffer, int size);
|
||||
// 読み込み
|
||||
BOOL FASTCALL Write(const void *buffer, int size);
|
||||
// 書き込み
|
||||
off64_t FASTCALL GetFileSize();
|
||||
// ファイルサイズ取得
|
||||
off64_t FASTCALL GetFilePos() const;
|
||||
// ファイル位置取得
|
||||
void FASTCALL Close();
|
||||
// クローズ
|
||||
BOOL FASTCALL IsValid() const { return (BOOL)(handle != -1); }
|
||||
// 有効チェック
|
||||
int FASTCALL GetHandle() const { return handle; }
|
||||
// ハンドル取得
|
||||
|
||||
private:
|
||||
int handle; // ファイルハンドル
|
||||
};
|
||||
|
||||
#endif // fileio_h
|
273
src/raspberrypi/filepath.cpp
Normal file
273
src/raspberrypi/filepath.cpp
Normal file
@ -0,0 +1,273 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// X68000 EMULATOR "XM6"
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
// Copyright (C) 2012-2018 GIMONS
|
||||
// [ ファイルパス(サブセット) ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "os.h"
|
||||
#include "xm6.h"
|
||||
#include "filepath.h"
|
||||
#include "fileio.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ファイルパス
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// コンストラクタ
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
Filepath::Filepath()
|
||||
{
|
||||
// クリア
|
||||
Clear();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// デストラクタ
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
Filepath::~Filepath()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// 代入演算子
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
Filepath& Filepath::operator=(const Filepath& path)
|
||||
{
|
||||
// パス設定(内部でSplitされる)
|
||||
SetPath(path.GetPath());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// クリア
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void FASTCALL Filepath::Clear()
|
||||
{
|
||||
ASSERT(this);
|
||||
|
||||
// パスおよび各部分をクリア
|
||||
m_szPath[0] = _T('\0');
|
||||
m_szDir[0] = _T('\0');
|
||||
m_szFile[0] = _T('\0');
|
||||
m_szExt[0] = _T('\0');
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// ファイル設定(ユーザ) MBCS用
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void FASTCALL Filepath::SetPath(LPCSTR path)
|
||||
{
|
||||
ASSERT(this);
|
||||
ASSERT(path);
|
||||
ASSERT(strlen(path) < _MAX_PATH);
|
||||
|
||||
// パス名コピー
|
||||
strcpy(m_szPath, (LPTSTR)path);
|
||||
|
||||
// 分離
|
||||
Split();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// パス分離
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void FASTCALL Filepath::Split()
|
||||
{
|
||||
LPTSTR pDir;
|
||||
LPTSTR pDirName;
|
||||
LPTSTR pBase;
|
||||
LPTSTR pBaseName;
|
||||
LPTSTR pExtName;
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
// パーツを初期化
|
||||
m_szDir[0] = _T('\0');
|
||||
m_szFile[0] = _T('\0');
|
||||
m_szExt[0] = _T('\0');
|
||||
|
||||
// 分離
|
||||
pDir = strdup(m_szPath);
|
||||
pDirName = dirname(pDir);
|
||||
pBase = strdup(m_szPath);
|
||||
pBaseName = basename(pBase);
|
||||
pExtName = strrchr(pBaseName, '.');
|
||||
|
||||
// 転送
|
||||
if (pDirName) {
|
||||
strcpy(m_szDir, pDirName);
|
||||
strcat(m_szDir, "/");
|
||||
}
|
||||
|
||||
if (pExtName) {
|
||||
strcpy(m_szExt, pExtName);
|
||||
*pExtName = 0;
|
||||
}
|
||||
|
||||
if (pBaseName) {
|
||||
strcpy(m_szFile, pBaseName);
|
||||
}
|
||||
|
||||
// 解放
|
||||
free(pDir);
|
||||
free(pBase);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// パス合成
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void FASTCALL Filepath::Make()
|
||||
{
|
||||
ASSERT(this);
|
||||
|
||||
// パス初期化
|
||||
m_szPath[0] = _T('\0');
|
||||
|
||||
// 合成
|
||||
strcat(m_szPath, m_szDir);
|
||||
strcat(m_szPath, m_szFile);
|
||||
strcat(m_szPath, m_szExt);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// クリアされているか
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL FASTCALL Filepath::IsClear() const
|
||||
{
|
||||
// Clear()の逆
|
||||
if ((m_szPath[0] == _T('\0')) &&
|
||||
(m_szDir[0] == _T('\0')) &&
|
||||
(m_szFile[0] == _T('\0')) &&
|
||||
(m_szExt[0] == _T('\0'))) {
|
||||