Merged in RASCSI version 1.47 and re-generated english PDF

This commit is contained in:
Tony Kuker
2020-07-04 09:57:44 -05:00
parent 497ff70eac
commit 00186fd77e
42 changed files with 5279 additions and 3010 deletions

View File

@@ -1,13 +1,19 @@
CC = gcc
CFLAGS = -DNDEBUG -O3
CFLAGS = -DNDEBUG -O3 -Wall
CXX = g++
CXXFLAGS = -DNDEBUG -O3
CXXFLAGS = -DNDEBUG -O3 -Wall
ifdef CONNECT_TYPE
CFLAGS += -DCONNECT_TYPE_$(CONNECT_TYPE)
CXXFLAGS += -DCONNECT_TYPE_$(CONNECT_TYPE)
endif
RASCSI = rascsi
RASCTL = rasctl
RASDUMP = rasdump
SASIDUMP = sasidump
BIN_ALL = $(RASCSI) $(RASCTL) $(RASDUMP)
BIN_ALL = $(RASCSI) $(RASCTL) $(RASDUMP) $(SASIDUMP)
SRC_RASCSI = \
rascsi.cpp \
@@ -29,23 +35,35 @@ SRC_RASDUMP = \
filepath.cpp \
fileio.cpp
OBJ_RASCSI := $(SRC_RASCSI:.cpp=.o)
OBJ_RASCTL := $(SRC_RASCTL:.c=.o)
OBJ_RASDUMP := $(SRC_RASDUMP:.c=.o)
SRC_SASIDUMP = \
sasidump.cpp \
scsi.cpp \
gpiobus.cpp \
filepath.cpp \
fileio.cpp
.cpp.o:
$(CXX) $(CXXFLAGS) -c $<
OBJ_RASCSI := $(SRC_RASCSI:%.cpp=%.o)
OBJ_RASCTL := $(SRC_RASCTL:%.cpp=%.o)
OBJ_RASDUMP := $(SRC_RASDUMP:%.cpp=%.o)
OBJ_SASIDUMP := $(SRC_SASIDUMP:%.cpp=%.o)
OBJ_ALL := $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_RASDUMP) $(OBJ_SASIDUMP)
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
ALL: $(BIN_ALL)
$(RASCSI): $(OBJ_RASCSI) $
$(RASCSI): $(OBJ_RASCSI)
$(CXX) -o $@ $(OBJ_RASCSI) -lpthread
$(RASCTL): $(OBJ_RASCTL) $
$(RASCTL): $(OBJ_RASCTL)
$(CXX) -o $@ $(OBJ_RASCTL)
$(RASDUMP): $(OBJ_RASDUMP) $
$(RASDUMP): $(OBJ_RASDUMP)
$(CXX) -o $@ $(OBJ_RASDUMP)
$(SASIDUMP): $(OBJ_SASIDUMP)
$(CXX) -o $@ $(OBJ_SASIDUMP)
clean:
rm -f *.o $(BIN_ALL)
rm -f $(OBJ_ALL) $(BIN_ALL)

View File

@@ -4,9 +4,10 @@
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2018 GIMONS
// Copyright (C) 2016-2020 GIMONS
//
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
// Imported sava's bugfix patch(in RASDRV DOS edition).
//
// [ ホストファイルシステム ]
//
@@ -18,6 +19,36 @@
#include "filepath.h"
#include "cfilesystem.h"
#ifdef BAREMETAL
//---------------------------------------------------------------------------
//
// FatFs用タイムスタンプ
//
//---------------------------------------------------------------------------
#define FF_NORTC_HOUR 6
#define FF_NORTC_MINUTE 8
#define FF_NORTC_SECOND 0
static DWORD fattime = (
(DWORD)(FF_NORTC_YEAR - 1980) << 25 |
(DWORD)FF_NORTC_MON << 21 |
(DWORD)FF_NORTC_MDAY << 16 |
(DWORD)(FF_NORTC_HOUR << 11) |
(DWORD)(FF_NORTC_MINUTE << 5) |
(DWORD)(FF_NORTC_SECOND)
);
DWORD get_fattime(void)
{
return fattime;
}
void set_fattime(DWORD n)
{
fattime = n;
}
#endif // BAREMETAL
//---------------------------------------------------------------------------
//
// 漢字コード変換
@@ -25,6 +56,7 @@
//---------------------------------------------------------------------------
#define IC_BUF_SIZE 1024
static char convert_buf[IC_BUF_SIZE];
#ifndef BAREMETAL
#ifndef __NetBSD__
// POSIX.1準拠iconv(3)を使用
#define CONVERT(src, dest, inbuf, outbuf, outsize) \
@@ -61,6 +93,18 @@ static void convert(char const *src, char const *dest,
iconv_close(cd);
*outbuf = '\0';
}
#else
// Newlibの中にiconvが含まれてなかったので無変換
// ベアメタルのFatFS上はSJISでもOKだと思うよ
#define CONVERT(src, dest, inbuf, outbuf, outsize) \
convert(src, dest, (char *)inbuf, outbuf, outsize)
static void convert(char const *src, char const *dest,
char *inbuf, char *outbuf, size_t outsize)
{
strcpy(outbuf, inbuf);
strcpy(convert_buf, inbuf);
}
#endif // BAREMETAL
//---------------------------------------------------------------------------
//
@@ -361,6 +405,56 @@ void CHostDrv::SetEnable(BOOL bEnable)
}
}
//---------------------------------------------------------------------------
//
/// メディア交換チェック
//
//---------------------------------------------------------------------------
BOOL CHostDrv::CheckMedia()
{
ASSERT(this);
// 状態更新
Update();
if (m_bEnable == FALSE)
CleanCache();
return m_bEnable;
}
//---------------------------------------------------------------------------
//
/// メディア状態更新
//
//---------------------------------------------------------------------------
void CHostDrv::Update()
{
ASSERT(this);
// メディア挿入とみなす
BOOL bEnable = TRUE;
// メディア状態反映
SetEnable(bEnable);
}
//---------------------------------------------------------------------------
//
/// イジェクト
//
//---------------------------------------------------------------------------
void CHostDrv::Eject()
{
ASSERT(this);
// メディア排出
CleanCache();
SetEnable(FALSE);
// 状態更新
Update();
}
//---------------------------------------------------------------------------
//
/// ボリュームラベルの取得
@@ -374,7 +468,12 @@ void CHostDrv::GetVolume(TCHAR* szLabel)
// ボリュームラベルの取得
#ifdef RASCSI
strcpy(m_szVolumeCache, m_szBase);
strcpy(m_szVolumeCache, "RASDRV ");
if (m_szBase[0]) {
strcat(m_szVolumeCache, m_szBase);
} else {
strcat(m_szVolumeCache, "/");
}
#else
m_szVolumeCache[0] = _T('\0');
#endif
@@ -578,15 +677,17 @@ CHostPath* CHostDrv::CopyCache(CHostFiles* pFiles)
// キャッシュ検索
CHostPath* pPath = FindCache(pFiles->GetHumanPath());
if (pPath == NULL)
if (pPath == NULL) {
return NULL; // エラー: キャッシュなし
}
// リング先頭へ移動
pPath->Insert(&m_cRing);
// キャッシュ更新チェック
if (pPath->isRefresh())
if (pPath->isRefresh()) {
return NULL; // エラー: キャッシュ更新が必要
}
// ホスト側のパス名を保存
pFiles->SetResult(pPath->GetHost());
@@ -676,6 +777,9 @@ CHostPath* CHostDrv::MakeCache(CHostFiles* pFiles)
// キャッシュ更新チェック
if (pPath->isRefresh()) {
// 更新
Update();
// 状態更新
pPath->Refresh();
}
@@ -1320,6 +1424,13 @@ int CHostPath::Compare(const BYTE* pFirst, const BYTE* pLast, const BYTE* pBufFi
if ('A' <= d && d <= 'Z')
d += 'a' - 'A'; // 小文字化
}
// バックスラッシュをスラッシュに統一して比較する
if (c == '\\') {
c = '/';
}
if (d == '\\') {
d = '/';
}
} else { // cだけが1バイト目
if ((0x80 <= c && c <= 0x9F) || 0xE0 <= c) { // 厳密には 0x810x9F 0xE00xEF
bSkip0 = TRUE;
@@ -1537,6 +1648,151 @@ BOOL CHostPath::isRefresh()
return m_bRefresh;
}
#ifdef BAREMETAL
//---------------------------------------------------------------------------
//
/// scandirエミュレーション
//
//---------------------------------------------------------------------------
struct dirent {
char d_name[_MAX_FNAME];
};
int scandir(const char *dirname,
dirent ***ret_namelist,
int(*select)(const dirent *),
int(*compar)(const dirent **, const dirent **))
{
FRESULT fr;
DIR dir;
FILINFO fno;
char dirpath[256];
int len;
dirent went;
int used;
int allocated;
dirent **namelist = NULL;
int i;
dirent *ent;
// NULLチェック
strcpy(dirpath, dirname);
if (dirpath[0] == '\0') {
return -1;
}
// '/'はOKだがそれ以外で最後が'/'だとディレクトリと認識されない)
if (dirpath[0] != '/' || dirpath[1] != '\0') {
len = strlen(dirpath);
if (dirpath[len - 1] == '/') {
dirpath[len - 1] = '\0';
}
}
// ディレクトリオープン
fr = f_opendir(&dir, dirpath);
if (fr != FR_OK) {
return -1;
}
// リストを初期値で確保(とりあえず32)
used = 0;
allocated = 32;
namelist = (dirent **)malloc(allocated * sizeof(dirent *));
if (!namelist) {
goto error;
}
// 配下のファイルまたはディレクトリを処理
i = 0;
while (TRUE) {
if (i == 0) {
// "."をFILINFOに見せかけて追加
strcpy(fno.fname, ".");
i++;
} else if (i == 1) {
// ".."をFILINFOに見せかけて追加
strcpy(fno.fname, "..");
i++;
} else if (f_readdir(&dir, &fno) != FR_OK) {
break;
}
// このケースがあるか不明
if (fno.fname[0] == 0) {
break;
}
// direntに見せかける
strcpy(went.d_name, fno.fname);
// 対象外のフィルタ処理
if (select != NULL && !select(&went)) {
continue;
}
// ファイル名の長さに調整したdirentの領域を確保
len = offsetof(dirent, d_name) + strlen(fno.fname) + 1;
if ((ent = (dirent *)malloc(len)) == NULL) {
goto error;
}
// ワーク用direntから返却用にコピー
memcpy(ent, &went, len);
// 使用量が越えそうならリストを再確保
if (used >= allocated) {
allocated *= 2;
namelist = (dirent **)realloc(namelist, allocated * sizeof(dirent *));
if (!namelist) {
goto error;
}
}
// リストに追加
namelist[used++] = ent;
}
// ディレクトリクローズ
f_closedir(&dir);
// ソート処理
if (compar) {
qsort(
namelist, used, sizeof(dirent *),
(int(*)(const void *, const void *)) compar);
}
// リストとエントリ数を返却
*ret_namelist = namelist;
return used;
error:
// ディレクトリクローズ
f_closedir(&dir);
// 途中まで確保したバッファをクローズ
if (namelist) {
while (used > 0) {
free(namelist[used - 1]);
used--;
}
free(namelist);
}
return -1;
}
#endif // BAREMETAL
//---------------------------------------------------------------------------
//
/// ASCIIソート関数
//
//---------------------------------------------------------------------------
int AsciiSort(const dirent **a, const dirent **b)
{
return strcmp((*a)->d_name, (*b)->d_name);
}
//---------------------------------------------------------------------------
//
/// ファイル再構成
@@ -1566,18 +1822,29 @@ void CHostPath::Refresh()
// ファイル名登録
/// @todo ファイル重複処理をホスト側APIを経由せずに全て自前で処理する。
BOOL bUpdate = FALSE;
DIR* pd = NULL;
for (DWORD i = 0; i < XM6_HOST_DIRENTRY_FILE_MAX; i++) {
struct dirent **pd = NULL;
int nument = 0;
int maxent = XM6_HOST_DIRENTRY_FILE_MAX;
for (int i = 0; i < maxent; i++) {
TCHAR szFilename[FILEPATH_MAX];
if (pd == NULL) {
pd = opendir(S2U(szPath));
if (pd == NULL)
nument = scandir(S2U(szPath), &pd, NULL, AsciiSort);
if (nument == -1) {
pd = NULL;
break;
}
maxent = nument;
}
// 最上位ディレクトリならカレントとパレントを対象外とする
struct dirent* pe = pd[i];
if (m_szHuman[0] == '/' && m_szHuman[1] == 0) {
if (strcmp(pe->d_name, ".") == 0 || strcmp(pe->d_name, "..") == 0) {
continue;
}
}
// ファイル名を獲得
struct dirent* pe = readdir(pd);
if (pe == NULL)
break;
strcpy(szFilename, U2S(pe->d_name));
// ファイル名領域確保
@@ -1617,8 +1884,12 @@ void CHostPath::Refresh()
// 一致するものがなければ、実ファイルが存在するか確認
strcpy(szPath, m_szHost);
strcat(szPath, (const char*)pFilename->GetHuman()); /// @warning Unicode時要修正 → 済
#ifndef BAREMETAL
struct stat sb;
if (stat(S2U(szPath), &sb))
#else
if (f_stat(S2U(szPath), NULL) != FR_OK)
#endif // BAREMETAL
break; // 利用可能パターンを発見
}
}
@@ -1634,6 +1905,7 @@ void CHostPath::Refresh()
strcpy(szPath, m_szHost);
strcat(szPath, U2S(pe->d_name));
#ifndef BAREMETAL
struct stat sb;
if (stat(S2U(szPath), &sb))
continue;
@@ -1660,6 +1932,27 @@ void CHostPath::Refresh()
}
pFilename->SetEntryDate(nHumanDate);
pFilename->SetEntryTime(nHumanTime);
#else
FILINFO fno;
if (f_stat(S2U(szPath), &fno) != FR_OK)
continue;
// 属性
BYTE nHumanAttribute = Human68k::AT_ARCHIVE;
if (fno.fattrib & AM_DIR)
nHumanAttribute = Human68k::AT_DIRECTORY;
if (fno.fattrib & AM_RDO)
nHumanAttribute |= Human68k::AT_READONLY;
pFilename->SetEntryAttribute(nHumanAttribute);
// サイズ
DWORD nHumanSize = (DWORD)fno.fsize;
pFilename->SetEntrySize(nHumanSize);
// 日付時刻
pFilename->SetEntryDate(fno.fdate);
pFilename->SetEntryTime(fno.ftime);
#endif // BAREMETAL
// クラスタ番号設定
pFilename->SetEntryCluster(0);
@@ -1679,7 +1972,13 @@ void CHostPath::Refresh()
pRing->r.InsertTail(&m_cRing);
}
closedir(pd);
// ディレクトリエントリを解放
if (pd) {
for (int i = 0; i < nument; i++) {
free(pd[i]);
}
free(pd);
}
// 残存するキャッシュ内容を削除
ring_t* p;
@@ -1701,6 +2000,7 @@ void CHostPath::Refresh()
//---------------------------------------------------------------------------
void CHostPath::Backup()
{
#ifndef BAREMETAL
ASSERT(this);
ASSERT(m_szHost);
ASSERT(strlen(m_szHost) < FILEPATH_MAX);
@@ -1718,6 +2018,29 @@ void CHostPath::Backup()
if (stat(S2U(szPath), &sb) == 0)
m_tBackup = sb.st_mtime;
}
#else
FILINFO fno;
ASSERT(this);
ASSERT(m_szHost);
ASSERT(strlen(m_szHost) < FILEPATH_MAX);
TCHAR szPath[FILEPATH_MAX];
strcpy(szPath, m_szHost);
size_t len = strlen(szPath);
m_tBackupD = 0;
m_tBackupT = 0;
if (len > 1) { // ルートディレクトリの場合は何もしない
len--;
ASSERT(szPath[len] == _T('/'));
szPath[len] = _T('\0');
if (f_stat(S2U(szPath), &fno) == FR_OK) {
m_tBackupD = fno.fdate;
m_tBackupT = fno.ftime;
}
}
#endif // BAREMETAL
}
//---------------------------------------------------------------------------
@@ -1727,6 +2050,7 @@ void CHostPath::Backup()
//---------------------------------------------------------------------------
void CHostPath::Restore() const
{
#ifndef BAREMETAL
ASSERT(this);
ASSERT(m_szHost);
ASSERT(strlen(m_szHost) < FILEPATH_MAX);
@@ -1746,6 +2070,28 @@ void CHostPath::Restore() const
ut.modtime = m_tBackup;
utime(szPath, &ut);
}
#else
FILINFO fno;
ASSERT(this);
ASSERT(m_szHost);
ASSERT(strlen(m_szHost) < FILEPATH_MAX);
TCHAR szPath[FILEPATH_MAX];
strcpy(szPath, m_szHost);
size_t len = strlen(szPath);
if (m_tBackupD) {
ASSERT(len);
len--;
ASSERT(szPath[len] == _T('/'));
szPath[len] = _T('\0');
fno.fdate = m_tBackupD;
fno.ftime = m_tBackupT;
f_utime(szPath, &fno);
}
#endif // BAREMETAL
}
//---------------------------------------------------------------------------
@@ -2007,6 +2353,34 @@ DWORD CHostEntry::GetStatus(DWORD nUnit) const
return m_pDrv[nUnit]->GetStatus();
}
//---------------------------------------------------------------------------
//
/// メディア交換チェック
//
//---------------------------------------------------------------------------
BOOL CHostEntry::CheckMedia(DWORD nUnit)
{
ASSERT(this);
ASSERT(nUnit < DriveMax);
ASSERT(m_pDrv[nUnit]);
return m_pDrv[nUnit]->CheckMedia();
}
//---------------------------------------------------------------------------
//
/// イジェクト
//
//---------------------------------------------------------------------------
void CHostEntry::Eject(DWORD nUnit)
{
ASSERT(this);
ASSERT(nUnit < DriveMax);
ASSERT(m_pDrv[nUnit]);
m_pDrv[nUnit]->Eject();
}
//---------------------------------------------------------------------------
//
/// ボリュームラベルの取得
@@ -2376,7 +2750,11 @@ void CHostFcb::Init()
ASSERT(this);
m_bUpdate = FALSE;
#ifndef BAREMETAL
m_pFile = NULL;
#else
memset(&m_File, 0x00, sizeof(FIL));
#endif
}
//---------------------------------------------------------------------------
@@ -2388,6 +2766,7 @@ BOOL CHostFcb::SetMode(DWORD nHumanMode)
{
ASSERT(this);
#ifndef BAREMETAL
switch (nHumanMode & Human68k::OP_MASK) {
case Human68k::OP_READ:
m_pszMode = "rb";
@@ -2401,6 +2780,21 @@ BOOL CHostFcb::SetMode(DWORD nHumanMode)
default:
return FALSE;
}
#else
switch (nHumanMode & Human68k::OP_MASK) {
case Human68k::OP_READ:
m_Mode = FA_READ;
break;
case Human68k::OP_WRITE:
m_Mode = FA_WRITE;
break;
case Human68k::OP_FULL:
m_Mode = FA_WRITE | FA_READ;
break;
default:
return FALSE;
}
#endif // BAREMETAL
m_bFlag = (nHumanMode & Human68k::OP_SPECIAL) != 0;
@@ -2442,8 +2836,9 @@ void CHostFcb::SetHumanPath(const BYTE* szHumanPath)
/// エラーの時はFALSEを返す。
//
//---------------------------------------------------------------------------
BOOL CHostFcb::Create(DWORD nHumanAttribute, BOOL bForce)
BOOL CHostFcb::Create(Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce)
{
#ifndef BAREMETAL
ASSERT(this);
ASSERT((nHumanAttribute & (Human68k::AT_DIRECTORY | Human68k::AT_VOLUME)) == 0);
ASSERT(strlen(m_szFilename) > 0);
@@ -2460,6 +2855,29 @@ BOOL CHostFcb::Create(DWORD nHumanAttribute, BOOL bForce)
m_pFile = fopen(S2U(m_szFilename), "w+b"); /// @warning 理想動作は属性ごと上書き
return m_pFile != NULL;
#else
FRESULT fr;
ASSERT(this);
ASSERT((nHumanAttribute & (Human68k::AT_DIRECTORY | Human68k::AT_VOLUME)) == 0);
ASSERT(strlen(m_szFilename) > 0);
// 重複チェック
if (bForce == FALSE) {
if (f_stat(S2U(m_szFilename), NULL) == FR_OK)
return FALSE;
}
// RPIのベアメタルではRTCが無いのでHuman側の時刻を反映させる
DWORD nHumanTime = ((DWORD)pFcb->date) << 16 | ((DWORD)pFcb->time);
set_fattime(nHumanTime);
// ファイル作成
fr = f_open(&m_File, S2U(m_szFilename), FA_CREATE_ALWAYS | FA_WRITE | FA_READ);
/// @warning 理想動作は属性ごと上書き
return fr == FR_OK;
#endif // BAREMETAL
}
//---------------------------------------------------------------------------
@@ -2471,8 +2889,9 @@ BOOL CHostFcb::Create(DWORD nHumanAttribute, BOOL bForce)
//---------------------------------------------------------------------------
BOOL CHostFcb::Open()
{
#ifndef BAREMETAL
struct stat st;
ASSERT(this);
ASSERT(strlen(m_szFilename) > 0);
@@ -2488,6 +2907,27 @@ BOOL CHostFcb::Open()
m_pFile = fopen(S2U(m_szFilename), m_pszMode);
return m_pFile != NULL || m_bFlag;
#else
FRESULT fr;
FILINFO fno;
ASSERT(this);
ASSERT(strlen(m_szFilename) > 0);
// ディレクトリなら失敗
if (f_stat(S2U(m_szFilename), &fno) == FR_OK) {
if (fno.fattrib & AM_DIR) {
return FALSE || m_bFlag;
}
}
// ファイルオープン
fr = FR_DISK_ERR;
if (m_File.obj.fs == NULL)
fr = f_open(&m_File, S2U(m_szFilename), m_Mode);
return fr == FR_OK || m_bFlag;
#endif // BAREMETAL
}
//---------------------------------------------------------------------------
@@ -2500,12 +2940,19 @@ BOOL CHostFcb::Open()
BOOL CHostFcb::Rewind(DWORD nOffset)
{
ASSERT(this);
#ifndef BAREMETAL
ASSERT(m_pFile);
if (fseek(m_pFile, nOffset, SEEK_SET))
return FALSE;
return ftell(m_pFile) != -1L;
#else
if (f_lseek(&m_File, nOffset))
return FALSE;
return f_tell(&m_File) != (DWORD)-1L;
#endif // BAREMETAL
}
//---------------------------------------------------------------------------
@@ -2518,6 +2965,7 @@ BOOL CHostFcb::Rewind(DWORD nOffset)
//---------------------------------------------------------------------------
DWORD CHostFcb::Read(BYTE* pBuffer, DWORD nSize)
{
#ifndef BAREMETAL
ASSERT(this);
ASSERT(pBuffer);
ASSERT(m_pFile);
@@ -2527,6 +2975,19 @@ DWORD CHostFcb::Read(BYTE* pBuffer, DWORD nSize)
nResult = (size_t)-1;
return (DWORD)nResult;
#else
FRESULT fr;
UINT nResult;
ASSERT(this);
ASSERT(pBuffer);
fr = f_read(&m_File, pBuffer, nSize, &nResult);
if (fr != FR_OK)
nResult = (UINT)-1;
return (DWORD)nResult;
#endif // BAREMETAL
}
//---------------------------------------------------------------------------
@@ -2539,6 +3000,7 @@ DWORD CHostFcb::Read(BYTE* pBuffer, DWORD nSize)
//---------------------------------------------------------------------------
DWORD CHostFcb::Write(const BYTE* pBuffer, DWORD nSize)
{
#ifndef BAREMETAL
ASSERT(this);
ASSERT(pBuffer);
ASSERT(m_pFile);
@@ -2548,6 +3010,19 @@ DWORD CHostFcb::Write(const BYTE* pBuffer, DWORD nSize)
nResult = (size_t)-1;
return (DWORD)nResult;
#else
FRESULT fr;
UINT nResult;
ASSERT(this);
ASSERT(pBuffer);
fr = f_write(&m_File, pBuffer, nSize, &nResult);
if (fr != FR_OK)
nResult = (UINT)-1;
return (DWORD)nResult;
#endif // BAREMETAL
}
//---------------------------------------------------------------------------
@@ -2560,9 +3035,13 @@ DWORD CHostFcb::Write(const BYTE* pBuffer, DWORD nSize)
BOOL CHostFcb::Truncate()
{
ASSERT(this);
#ifndef BAREMETAL
ASSERT(m_pFile);
return ftruncate(fileno(m_pFile), ftell(m_pFile)) == 0;
#else
return f_truncate(&m_File) == FR_OK;
#endif // BAREMETAL
}
//---------------------------------------------------------------------------
@@ -2574,6 +3053,7 @@ BOOL CHostFcb::Truncate()
//---------------------------------------------------------------------------
DWORD CHostFcb::Seek(DWORD nOffset, DWORD nHumanSeek)
{
#ifndef BAREMETAL
ASSERT(this);
ASSERT(nHumanSeek == Human68k::SK_BEGIN ||
nHumanSeek == Human68k::SK_CURRENT || nHumanSeek == Human68k::SK_END);
@@ -2596,6 +3076,30 @@ DWORD CHostFcb::Seek(DWORD nOffset, DWORD nHumanSeek)
return (DWORD)-1;
return (DWORD)ftell(m_pFile);
#else
FRESULT fr;
ASSERT(this);
ASSERT(nHumanSeek == Human68k::SK_BEGIN ||
nHumanSeek == Human68k::SK_CURRENT || nHumanSeek == Human68k::SK_END);
switch (nHumanSeek) {
case Human68k::SK_BEGIN:
fr = f_lseek(&m_File, nOffset);
break;
case Human68k::SK_CURRENT:
fr = f_lseek(&m_File, f_tell(&m_File) + nOffset);
break;
// case SK_END:
default:
fr = f_lseek(&m_File, f_size(&m_File) + nOffset);
break;
}
if (fr != FR_OK)
return (DWORD)-1;
return (DWORD)f_tell(&m_File);
#endif // BAREMETAL
}
//---------------------------------------------------------------------------
@@ -2607,6 +3111,7 @@ DWORD CHostFcb::Seek(DWORD nOffset, DWORD nHumanSeek)
//---------------------------------------------------------------------------
BOOL CHostFcb::TimeStamp(DWORD nHumanTime)
{
#ifndef BAREMETAL
ASSERT(this);
ASSERT(m_pFile || m_bFlag);
@@ -2614,7 +3119,7 @@ BOOL CHostFcb::TimeStamp(DWORD nHumanTime)
t.tm_year = (nHumanTime >> 25) + 80;
t.tm_mon = ((nHumanTime >> 21) - 1) & 15;
t.tm_mday = (nHumanTime >> 16) & 31;
t.tm_hour = (nHumanTime >> 11) & 15;
t.tm_hour = (nHumanTime >> 11) & 31;
t.tm_min = (nHumanTime >> 5) & 63;
t.tm_sec = (nHumanTime & 31) << 1;
time_t ti = mktime(&t);
@@ -2629,6 +3134,20 @@ BOOL CHostFcb::TimeStamp(DWORD nHumanTime)
fflush(m_pFile);
return utime(S2U(m_szFilename), &ut) == 0 || m_bFlag;
#else
FILINFO fno;
ASSERT(this);
ASSERT(m_bFlag);
// クローズ時に更新時刻が上書きされるのを防止するため
// タイムスタンプの更新前にフラッシュして同期させる
f_sync(&m_File);
fno.fdate = (WORD)(nHumanTime >> 16);
fno.ftime = (WORD)nHumanTime;
return f_utime(S2U(m_szFilename), &fno) == FR_OK || m_bFlag;
#endif // BAREMETAL
}
//---------------------------------------------------------------------------
@@ -2646,10 +3165,14 @@ BOOL CHostFcb::Close()
// ファイルクローズ
// Close→Free(内部で再度Close)という流れもあるので必ず初期化すること。
#ifndef BAREMETAL
if (m_pFile) {
fclose(m_pFile);
m_pFile = NULL;
}
#else
f_close(&m_File);
#endif // BAREMETAL
return bResult;
}
@@ -2813,6 +3336,9 @@ CFileSys::CFileSys()
m_nOptionDefault = 0;
m_nOption = 0;
ASSERT(g_nOption == 0);
// 登録したドライブ数は0
m_nUnits = 0;
}
//---------------------------------------------------------------------------
@@ -2974,7 +3500,11 @@ int CFileSys::MakeDir(DWORD nUnit, const Human68k::namests_t* pNamests)
f.AddFilename();
// ディレクトリ作成
#ifndef BAREMETAL
if (mkdir(S2U(f.GetPath()), 0777))
#else
if (f_mkdir(S2U(f.GetPath())) != FR_OK)
#endif // BAREMETAL
return FS_INVALIDPATH;
// キャッシュ更新
@@ -3025,7 +3555,11 @@ int CFileSys::RemoveDir(DWORD nUnit, const Human68k::namests_t* pNamests)
m_cEntry.DeleteCache(nUnit, szHuman);
// ディレクトリ削除
#ifndef BAREMETAL
if (rmdir(S2U(f.GetPath())))
#else
if (f_rmdir(S2U(f.GetPath())) != FR_OK)
#endif // BAREMETAL
return FS_CANTDELETE;
// キャッシュ更新
@@ -3082,7 +3616,11 @@ int CFileSys::Rename(DWORD nUnit, const Human68k::namests_t* pNamests, const Hum
char szTo[FILENAME_MAX];
SJIS2UTF8(f.GetPath(), szFrom, FILENAME_MAX);
SJIS2UTF8(fNew.GetPath(), szTo, FILENAME_MAX);
#ifndef BAREMETAL
if (rename(szFrom, szTo)) {
#else
if (f_rename(szFrom, szTo) != FR_OK) {
#endif // BAREMETAL
return FS_FILENOTFND;
}
@@ -3125,7 +3663,11 @@ int CFileSys::Delete(DWORD nUnit, const Human68k::namests_t* pNamests)
return FS_FILENOTFND;
// ファイル削除
#ifndef BAREMETAL
if (unlink(S2U(f.GetPath())))
#else
if (f_unlink(S2U(f.GetPath())) != FR_OK)
#endif // BAREMETAL
return FS_CANTDELETE;
// キャッシュ更新
@@ -3177,6 +3719,7 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
DWORD nAttribute = (nHumanAttribute & Human68k::AT_READONLY) |
(f.GetAttribute() & ~Human68k::AT_READONLY);
if (f.GetAttribute() != nAttribute) {
#ifndef BAREMETAL
struct stat sb;
if (stat(S2U(f.GetPath()), &sb))
return FS_FILENOTFND;
@@ -3189,6 +3732,17 @@ int CFileSys::Attribute(DWORD nUnit, const Human68k::namests_t* pNamests, DWORD
// 属性設定
if (chmod(S2U(f.GetPath()), m))
return FS_FILENOTFND;
#else
if (f_stat(S2U(f.GetPath()), NULL) != FR_OK)
return FS_FILENOTFND;
BYTE m = 0;
if (nAttribute & Human68k::AT_READONLY)
m = AM_RDO;
// 属性設定
if (f_chmod(S2U(f.GetPath()), m, AM_RDO))
return FS_FILENOTFND;
#endif // BAREMETAL
}
// キャッシュ更新
@@ -3398,7 +3952,7 @@ int CFileSys::Create(DWORD nUnit, DWORD nKey, const Human68k::namests_t* pNamest
}
// ファイル作成
if (pHostFcb->Create(nHumanAttribute, bForce) == FALSE) {
if (pHostFcb->Create(pFcb, nHumanAttribute, bForce) == FALSE) {
m_cFcb.Free(pHostFcb);
return FS_FILEEXIST;
}
@@ -4056,7 +4610,13 @@ int CFileSys::CheckMedia(DWORD nUnit)
return FS_INVALIDFUNC; // レジューム後に無効なドライブでmint操作時に白帯を出さないよう改良
// メディア交換チェック
m_cEntry.CleanCache(nUnit);
BOOL bResult = m_cEntry.CheckMedia(nUnit);
// メディア未挿入ならエラーとする
if (bResult == FALSE) {
return FS_INVALIDFUNC;
}
return 0;
}

View File

@@ -4,7 +4,7 @@
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2018 GIMONS
// Copyright (C) 2016-2020 GIMONS
// [ ホストファイルシステム ]
//
//---------------------------------------------------------------------------
@@ -12,6 +12,11 @@
#ifndef cfilesystem_h
#define cfilesystem_h
#ifdef BAREMETAL
#include "ffconf.h"
#include "ff.h"
#endif // BAREMETAL
//---------------------------------------------------------------------------
//
// ステータスコード定義
@@ -631,7 +636,12 @@ private:
///< 文字列比較 (ワイルドカード対応)
CRing m_cRing; ///< CHostFilename連結用
#ifndef BAREMETAL
time_t m_tBackup; ///< 時刻復元用
#else
WORD m_tBackupD; ///< 時刻復元用
WORD m_tBackupT; ///< 時刻復元用
#endif // BAREMETAL
BOOL m_bRefresh; ///< 更新フラグ
DWORD m_nId; ///< 識別ID (値が変化した場合は更新を意味する)
BYTE m_szHuman[HUMAN68K_PATH_MAX]; ///< 該当エントリのHuman68k内部名
@@ -795,7 +805,7 @@ public:
const BYTE* GetHumanPath() const { ASSERT(this); return m_szHumanPath; }
///< Human68kパス名を取得
BOOL Create(DWORD nHumanAttribute, BOOL bForce);
BOOL Create(Human68k::fcb_t* pFcb, DWORD nHumanAttribute, BOOL bForce);
///< ファイル作成
BOOL Open();
///< ファイルオープン
@@ -817,8 +827,13 @@ public:
private:
DWORD m_nKey; ///< Human68kのFCBバッファアドレス (0なら未使用)
BOOL m_bUpdate; ///< 更新フラグ
#ifndef BAREMETAL
FILE* m_pFile; ///< ホスト側のファイルオブジェクト
const char* m_pszMode; ///< ホスト側のファイルオープンモード
#else
FIL m_File; ///< ホスト側のファイルオブジェクト
BYTE m_Mode; ///< ホスト側のファイルオープンモード
#endif // BAREMETAL
bool m_bFlag; ///< ホスト側のファイルオープンフラグ
BYTE m_szHumanPath[HUMAN68K_PATH_MAX];
///< Human68kのパス名
@@ -889,6 +904,12 @@ public:
///< ドライブ状態の取得
void SetEnable(BOOL bEnable);
///< メディア状態設定
BOOL CheckMedia();
///< メディア交換チェック
void Update();
///< メディア状態更新
void Eject();
///< イジェクト
void GetVolume(TCHAR* szLabel);
///< ボリュームラベルの取得
BOOL GetVolumeCache(TCHAR* szLabel) const;
@@ -987,6 +1008,10 @@ public:
///< メディアバイトの取得
DWORD GetStatus(DWORD nUnit) const;
///< ドライブ状態の取得
BOOL CheckMedia(DWORD nUnit);
///< メディア交換チェック
void Eject(DWORD nUnit);
///< イジェクト
void GetVolume(DWORD nUnit, TCHAR* szLabel);
///< ボリュームラベルの取得
BOOL GetVolumeCache(DWORD nUnit, TCHAR* szLabel) const;

View File

@@ -1,68 +0,0 @@
//---------------------------------------------------------------------------
//
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2004 (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

View File

@@ -4,7 +4,7 @@
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2018 GIMONS
// Copyright (C) 2016-2020 GIMONS
//
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
//

View File

@@ -4,7 +4,7 @@
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2018 GIMONS
// Copyright (C) 2016-2020 GIMONS
//
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
//

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2018 GIMONS
// Copyright (C) 2014-2020 GIMONS
//
// XM6i
// Copyright (C) 2010-2015 isaki@NetBSD.org
@@ -319,6 +319,8 @@ public:
// サポートしていないコマンド
// その他
BOOL IsCacheWB() { return cache_wb; }
// キャッシュモード取得
void SetCacheWB(BOOL enable) { cache_wb = enable; }
// キャッシュモード設定
@@ -703,7 +705,9 @@ private:
// SCSI ホストブリッジ
//
//===========================================================================
#if defined(RASCSI) && !defined(BAREMETAL)
class CTapDriver;
#endif // RASCSI && !BAREMETAL
class CFileSys;
class SCSIBR : public Disk
{
@@ -725,6 +729,7 @@ public:
// SEND MESSAGE10コマンド
private:
#if defined(RASCSI) && !defined(BAREMETAL)
int FASTCALL GetMacAddr(BYTE *buf);
// MACアドレス取得
void FASTCALL SetMacAddr(BYTE *buf);
@@ -748,7 +753,7 @@ private:
// 受信パケットバッファ
BOOL packet_enable;
// 受信パケット有効
#endif // RASCSI && !BAREMETAL
int FASTCALL ReadFsResult(BYTE *buf);
// ファイルシステム読み込み(結果コード)
@@ -840,14 +845,13 @@ public:
UnitMax = 8
};
// フェーズタイミング(調整用)
#ifdef RASCSI
// タイミング調整用
enum {
Time_phase_bsy = 800,
Time_phase_before = 6000, // min 4000ns
Time_phase_before_data = 60000, // min 40000ns
Time_phase_after = 6000, // min 4000ns
Time_phase_after_status = 12000, // min 9000ns
min_exec_time_sasi = 100, // SASI BOOT/FORMAT 30:NG 35:OK
min_exec_time_scsi = 50
};
#endif // RASCSI
// 内部データ定義
typedef struct {
@@ -861,6 +865,11 @@ public:
DWORD status; // ステータスデータ
DWORD message; // メッセージデータ
#ifdef RASCSI
// 実行
DWORD execstart; // 実行開始時間
#endif // RASCSI
// 転送
BYTE *buffer; // 転送バッファ
int bufsize; // 転送バッファサイズ
@@ -919,6 +928,8 @@ public:
// 内部情報アドレス取得
virtual BOOL FASTCALL IsSASI() const {return TRUE;}
// SASIチェック
virtual BOOL FASTCALL IsSCSI() const {return FALSE;}
// SCSIチェック
Disk* FASTCALL GetBusyUnit();
// ビジー状態のユニットを取得
@@ -970,13 +981,25 @@ protected:
// データ転送
virtual void FASTCALL Send();
// データ送信
#ifndef RASCSI
virtual void FASTCALL SendNext();
// データ送信継続
#endif // RASCSI
virtual void FASTCALL Receive();
// データ受信
#ifndef RASCSI
virtual void FASTCALL ReceiveNext();
// データ受信継続
#endif // RASCSI
BOOL FASTCALL XferIn(BYTE* buf);
// データ転送IN
BOOL FASTCALL XferOut(BOOL cont);
// データ転送OUT
// 特殊
void FASTCALL FlushUnit();
// 論理ユニットフラッシュ
// ログ
void FASTCALL Log(Log::loglevel level, const char *format, ...);
// ログ出力
@@ -1010,7 +1033,7 @@ public:
// ATNメッセージ
BOOL atnmsg;
int msc;
BOOL msb[256];
BYTE msb[256];
} scsi_t;
public:
@@ -1035,6 +1058,8 @@ public:
// その他
BOOL FASTCALL IsSASI() const {return FALSE;}
// SASIチェック
BOOL FASTCALL IsSCSI() const {return TRUE;}
// SCSIチェック
private:
// フェーズ
@@ -1096,8 +1121,16 @@ private:
// データ転送
void FASTCALL Send();
// データ送信
#ifndef RASCSI
void FASTCALL SendNext();
// データ送信継続
#endif // RASCSI
void FASTCALL Receive();
// データ受信
#ifndef RASCSI
void FASTCALL ReceiveNext();
// データ受信継続
#endif // RASCSI
BOOL FASTCALL XferMsg(DWORD msg);
// データ転送MSG

View File

@@ -3,7 +3,7 @@
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2010-2018 GIMONS
// Copyright (C) 2010-2020 GIMONS
// [ ファイルI/O(RaSCSI用サブセット) ]
//
//---------------------------------------------------------------------------
@@ -19,6 +19,7 @@
//
//===========================================================================
#ifndef BAREMETAL
//---------------------------------------------------------------------------
//
// コンストラクタ
@@ -89,7 +90,7 @@ BOOL FASTCALL Fileio::Save(const Filepath& path, void *buffer, int size)
return FALSE;
}
// 読み込み
// 書き込み
if (!Write(buffer, size)) {
Close();
return FALSE;
@@ -106,8 +107,10 @@ BOOL FASTCALL Fileio::Save(const Filepath& path, void *buffer, int size)
// オープン
//
//---------------------------------------------------------------------------
BOOL FASTCALL Fileio::Open(LPCTSTR fname, OpenMode mode)
BOOL FASTCALL Fileio::Open(LPCTSTR fname, OpenMode mode, BOOL directIO)
{
mode_t omode;
ASSERT(this);
ASSERT(fname);
ASSERT(handle < 0);
@@ -118,16 +121,19 @@ BOOL FASTCALL Fileio::Open(LPCTSTR fname, OpenMode mode)
return FALSE;
}
// デフォルトモード
omode = directIO ? O_DIRECT : 0;
// モード別
switch (mode) {
// 読み込みのみ
case ReadOnly:
handle = open(fname, O_RDONLY);
handle = open(fname, O_RDONLY | omode);
break;
// 書き込みのみ
case WriteOnly:
handle = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0666);
handle = open(fname, O_CREAT | O_WRONLY | O_TRUNC | omode, 0666);
break;
// 読み書き両方
@@ -136,12 +142,12 @@ BOOL FASTCALL Fileio::Open(LPCTSTR fname, OpenMode mode)
if (access(fname, 0x06) != 0) {
return FALSE;
}
handle = open(fname, O_RDWR);
handle = open(fname, O_RDWR | omode);
break;
// アペンド
case Append:
handle = open(fname, O_CREAT | O_WRONLY | O_APPEND, 0666);
handle = open(fname, O_CREAT | O_WRONLY | O_APPEND | omode, 0666);
break;
// それ以外
@@ -154,6 +160,7 @@ BOOL FASTCALL Fileio::Open(LPCTSTR fname, OpenMode mode)
if (handle == -1) {
return FALSE;
}
ASSERT(handle >= 0);
return TRUE;
}
@@ -163,56 +170,11 @@ BOOL FASTCALL Fileio::Open(LPCTSTR fname, OpenMode mode)
// オープン
//
//---------------------------------------------------------------------------
BOOL FASTCALL Fileio::OpenDIO(LPCTSTR fname, OpenMode mode)
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 | 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;
return Open(fname, mode, FALSE);
}
//---------------------------------------------------------------------------
@@ -227,6 +189,24 @@ BOOL FASTCALL Fileio::Open(const Filepath& path, OpenMode mode)
return Open(path.GetPath(), mode);
}
//---------------------------------------------------------------------------
//
// オープン
//
//---------------------------------------------------------------------------
BOOL FASTCALL Fileio::OpenDIO(LPCTSTR fname, OpenMode mode)
{
ASSERT(this);
// O_DIRECT付きでオープン
if (!Open(fname, mode, TRUE)) {
// 通常モードリトライ(tmpfs等)
return Open(fname, mode, FALSE);
}
return TRUE;
}
//---------------------------------------------------------------------------
//
// オープン
@@ -276,7 +256,7 @@ BOOL FASTCALL Fileio::Write(const void *buffer, int size)
ASSERT(size > 0);
ASSERT(handle >= 0);
// 読み込み
// 書き込み
count = write(handle, buffer, size);
if (count != size) {
return FALSE;
@@ -365,3 +345,273 @@ void FASTCALL Fileio::Close()
handle = -1;
}
}
#else
//---------------------------------------------------------------------------
//
// コンストラクタ
//
//---------------------------------------------------------------------------
Fileio::Fileio()
{
// ワーク初期化
handle.obj.fs = 0;
}
//---------------------------------------------------------------------------
//
// デストラクタ
//
//---------------------------------------------------------------------------
Fileio::~Fileio()
{
ASSERT(!handle.obj.fs);
// Releaseでの安全策
Close();
}
//---------------------------------------------------------------------------
//
// ロード
//
//---------------------------------------------------------------------------
BOOL FASTCALL Fileio::Load(const Filepath& path, void *buffer, int size)
{
ASSERT(this);
ASSERT(buffer);
ASSERT(size > 0);
ASSERT(!handle.obj.fs);
// オープン
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.obj.fs);
// オープン
if (!Open(path, WriteOnly)) {
return FALSE;
}
// 書き込み
if (!Write(buffer, size)) {
Close();
return FALSE;
}
// クローズ
Close();
return TRUE;
}
//---------------------------------------------------------------------------
//
// オープン
//
//---------------------------------------------------------------------------
BOOL FASTCALL Fileio::Open(LPCTSTR fname, OpenMode mode)
{
FRESULT fr;
Filepath fpath;
ASSERT(this);
ASSERT(fname);
ASSERT(!handle.obj.fs);
// ヌル文字列からの読み込みは必ず失敗させる
if (fname[0] == _T('\0')) {
return FALSE;
}
// モード別
switch (mode) {
// 読み込みのみ
case ReadOnly:
fr = f_open(&handle, fname, FA_READ);
break;
// 書き込みのみ
case WriteOnly:
fr = f_open(&handle, fname, FA_CREATE_ALWAYS | FA_WRITE);
break;
// 読み書き両方
case ReadWrite:
fr = f_open(&handle, fname, FA_READ | FA_WRITE);
break;
// アペンド
case Append:
fr = f_open(&handle, fname, FA_OPEN_APPEND | FA_WRITE);
break;
// それ以外
default:
fr = FR_NO_PATH;
ASSERT(FALSE);
break;
}
// 結果評価
if (fr != FR_OK) {
return FALSE;
}
// オープン成功
return TRUE;
}
//---------------------------------------------------------------------------
//
// オープン
//
//---------------------------------------------------------------------------
BOOL FASTCALL Fileio::Open(const Filepath& path, OpenMode mode)
{
ASSERT(this);
ASSERT(!handle.obj.fs);
return Open(path.GetPath(), mode);
}
//---------------------------------------------------------------------------
//
// 読み込み
//
//---------------------------------------------------------------------------
BOOL FASTCALL Fileio::Read(void *buffer, int size)
{
FRESULT fr;
UINT count;
ASSERT(this);
ASSERT(buffer);
ASSERT(size > 0);
ASSERT(handle.obj.fs);
// 読み込み
fr = f_read(&handle, buffer, size, &count);
if (fr != FR_OK || count != (unsigned int)size) {
return FALSE;
}
return TRUE;
}
//---------------------------------------------------------------------------
//
// 書き込み
//
//---------------------------------------------------------------------------
BOOL FASTCALL Fileio::Write(const void *buffer, int size)
{
FRESULT fr;
UINT count;
ASSERT(this);
ASSERT(buffer);
ASSERT(size > 0);
ASSERT(handle.obj.fs);
// 書き込み
fr = f_write(&handle, buffer, size, &count);
if (fr != FR_OK || count != (unsigned int)size) {
return FALSE;
}
return TRUE;
}
//---------------------------------------------------------------------------
//
// シーク
//
//---------------------------------------------------------------------------
BOOL FASTCALL Fileio::Seek(off64_t offset, BOOL relative)
{
FRESULT fr;
ASSERT(this);
ASSERT(offset >= 0);
ASSERT(handle.obj.fs);
// 相対シークならオフセットに現在値を追加
if (relative) {
offset += f_tell(&handle);
}
fr = f_lseek(&handle, offset);
if (fr != FR_OK) {
return FALSE;
}
if (f_tell(&handle) != (DWORD)offset) {
return FALSE;
}
return TRUE;
}
//---------------------------------------------------------------------------
//
// ファイルサイズ取得
//
//---------------------------------------------------------------------------
off64_t FASTCALL Fileio::GetFileSize()
{
ASSERT(this);
ASSERT(handle.obj.fs);
return f_size(&handle);
}
//---------------------------------------------------------------------------
//
// ファイル位置取得
//
//---------------------------------------------------------------------------
off64_t FASTCALL Fileio::GetFilePos() const
{
ASSERT(this);
ASSERT(handle.obj.fs);
return f_tell(&handle);
}
//---------------------------------------------------------------------------
//
// クローズ
//
//---------------------------------------------------------------------------
void FASTCALL Fileio::Close()
{
ASSERT(this);
if (handle.obj.fs) {
f_close(&handle);
}
}
#endif //BAREMETAL

View File

@@ -3,7 +3,7 @@
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2005 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2013-2018 GIMONS
// Copyright (C) 2013-2020 GIMONS
// [ ファイルI/O(RaSCSI用サブセット) ]
//
//---------------------------------------------------------------------------
@@ -11,6 +11,10 @@
#if !defined(fileio_h)
#define fileio_h
#ifdef BAREMETAL
#include "ff.h"
#endif // BAREMETAL
//===========================================================================
//
// マクロ(Load,Save用)
@@ -53,12 +57,14 @@ public:
BOOL FASTCALL Open(LPCTSTR fname, OpenMode mode);
// オープン
BOOL FASTCALL OpenDIO(LPCTSTR fname, OpenMode mode);
// オープン
BOOL FASTCALL Open(const Filepath& path, OpenMode mode);
// オープン
#ifndef BAREMETAL
BOOL FASTCALL OpenDIO(LPCTSTR fname, OpenMode mode);
// オープン
BOOL FASTCALL OpenDIO(const Filepath& path, OpenMode mode);
// オープン
#endif // BAREMETAL
BOOL FASTCALL Seek(off64_t offset, BOOL relative = FALSE);
// シーク
BOOL FASTCALL Read(void *buffer, int size);
@@ -71,13 +77,22 @@ public:
// ファイル位置取得
void FASTCALL Close();
// クローズ
#ifndef BAREMETAL
BOOL FASTCALL IsValid() const { return (BOOL)(handle != -1); }
#else
BOOL FASTCALL IsValid() const { return (BOOL)(handle.obj.fs != 0); }
#endif // BAREMETAL
// 有効チェック
int FASTCALL GetHandle() const { return handle; }
// ハンドル取得
private:
#ifndef BAREMETAL
BOOL FASTCALL Open(LPCTSTR fname, OpenMode mode, BOOL directIO);
// オープン
int handle; // ファイルハンドル
#else
FIL handle; // ファイルハンドル
#endif // BAREMETAL
};
#endif // fileio_h

View File

@@ -3,7 +3,7 @@
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2012-2018 GIMONS
// Copyright (C) 2012-2020 GIMONS
// [ ファイルパス(サブセット) ]
//
//---------------------------------------------------------------------------
@@ -86,6 +86,80 @@ void FASTCALL Filepath::SetPath(LPCSTR path)
Split();
}
#ifdef BAREMETAL
//---------------------------------------------------------------------------
//
// 互換関数(dirname) 結果は直ぐにコピーせよ
//
//---------------------------------------------------------------------------
static char dirtmp[2];
char* dirname(char *path)
{
char *p;
if( path == NULL || *path == '\0' ) {
dirtmp[0] = '.';
dirtmp[1] = '\0';
return dirtmp;
}
p = path + strlen(path) - 1;
while( *p == '/' ) {
if( p == path )
return path;
*p-- = '\0';
}
while( p >= path && *p != '/' ) {
p--;
}
if (p < path) {
dirtmp[0] = '.';
dirtmp[1] = '\0';
return dirtmp;
}
if (p == path) {
dirtmp[0] = '/';
dirtmp[1] = '\0';
return dirtmp;
}
*p = 0;
return path;
}
//---------------------------------------------------------------------------
//
// 互換関数(basename) 結果は直ぐにコピーせよ
//
//---------------------------------------------------------------------------
static char basetmp[2];
char* basename(char *path)
{
char *p;
if( path == NULL || *path == '\0' ) {
basetmp[0] = '/';
basetmp[1] = '\0';
return basetmp;
}
p = path + strlen(path) - 1;
while( *p == '/' ) {
if( p == path ) {
return path;
}
*p-- = '\0';
}
while( p >= path && *p != '/' ) {
p--;
}
return p + 1;
}
#endif // BAREMETAL
//---------------------------------------------------------------------------
//
// パス分離
@@ -121,7 +195,6 @@ void FASTCALL Filepath::Split()
if (pExtName) {
strcpy(m_szExt, pExtName);
*pExtName = 0;
}
if (pBaseName) {

View File

@@ -3,7 +3,7 @@
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2012-2018 GIMONS
// Copyright (C) 2012-2020 GIMONS
// [ ファイルパス(サブセット) ]
//
//---------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2018 GIMONS
// Copyright (C) 2016-2020 GIMONS
// [ GPIO-SCSIバス ]
//
//---------------------------------------------------------------------------
@@ -19,7 +19,7 @@
// 接続方法定義の選択
//
//---------------------------------------------------------------------------
#define CONNECT_TYPE_STANDARD // 標準(SCSI論理,標準ピンアサイン)
//#define CONNECT_TYPE_STANDARD // 標準(SCSI論理,標準ピンアサイン)
//#define CONNECT_TYPE_FULLSPEC // フルスペック(SCSI論理,標準ピンアサイン)
//#define CONNECT_TYPE_AIBOM // AIBOM版(正論理,固有ピンアサイン)
//#define CONNECT_TYPE_GAMERNIUM // GAMERnium.com版(標準論理,固有ピンアサイン)
@@ -281,8 +281,12 @@
// 定数宣言(GPIO)
//
//---------------------------------------------------------------------------
#define GPIO_OFFSET 0x200000
#define PADS_OFFSET 0x100000
#define SYST_OFFSET 0x00003000
#define IRPT_OFFSET 0x0000B200
#define ARMT_OFFSET 0x0000B400
#define PADS_OFFSET 0x00100000
#define GPIO_OFFSET 0x00200000
#define QA7_OFFSET 0x01000000
#define GPIO_INPUT 0
#define GPIO_OUTPUT 1
#define GPIO_PULLNONE 0
@@ -304,7 +308,40 @@
#define GPIO_AFEN_0 34
#define GPIO_PUD 37
#define GPIO_CLK_0 38
#define GPIO_GPPINMUXSD 52
#define GPIO_PUPPDN0 57
#define GPIO_PUPPDN1 58
#define GPIO_PUPPDN3 59
#define GPIO_PUPPDN4 60
#define PAD_0_27 11
#define SYST_CS 0
#define SYST_CLO 1
#define SYST_CHI 2
#define SYST_C0 3
#define SYST_C1 4
#define SYST_C2 5
#define SYST_C3 6
#define ARMT_LOAD 0
#define ARMT_VALUE 1
#define ARMT_CTRL 2
#define ARMT_CLRIRQ 3
#define ARMT_RAWIRQ 4
#define ARMT_MSKIRQ 5
#define ARMT_RELOAD 6
#define ARMT_PREDIV 7
#define ARMT_FREERUN 8
#define IRPT_PND_IRQ_B 0
#define IRPT_PND_IRQ_1 1
#define IRPT_PND_IRQ_2 2
#define IRPT_FIQ_CNTL 3
#define IRPT_ENB_IRQ_1 4
#define IRPT_ENB_IRQ_2 5
#define IRPT_ENB_IRQ_B 6
#define IRPT_DIS_IRQ_1 7
#define IRPT_DIS_IRQ_2 8
#define IRPT_DIS_IRQ_B 9
#define QA7_CORE0_TINTC 16
#define GPIO_IRQ (32 + 20) // GPIO3
#define GPIO_INEDGE ((1 << PIN_BSY) | \
(1 << PIN_SEL) | \
@@ -316,6 +353,39 @@
(1 << PIN_CD) | \
(1 << PIN_IO))
//---------------------------------------------------------------------------
//
// 定数宣言(GIC)
//
//---------------------------------------------------------------------------
#define ARM_GICD_BASE 0xFF841000
#define ARM_GICC_BASE 0xFF842000
#define ARM_GIC_END 0xFF847FFF
#define GICD_CTLR 0x000
#define GICD_IGROUPR0 0x020
#define GICD_ISENABLER0 0x040
#define GICD_ICENABLER0 0x060
#define GICD_ISPENDR0 0x080
#define GICD_ICPENDR0 0x0A0
#define GICD_ISACTIVER0 0x0C0
#define GICD_ICACTIVER0 0x0E0
#define GICD_IPRIORITYR0 0x100
#define GICD_ITARGETSR0 0x200
#define GICD_ICFGR0 0x300
#define GICD_SGIR 0x3C0
#define GICC_CTLR 0x000
#define GICC_PMR 0x001
#define GICC_IAR 0x003
#define GICC_EOIR 0x004
//---------------------------------------------------------------------------
//
// 定数宣言(GIC IRQ)
//
//---------------------------------------------------------------------------
#define GIC_IRQLOCAL0 (16 + 14)
#define GIC_GPIO_IRQ (32 + 116) // GPIO3
//---------------------------------------------------------------------------
//
// 定数宣言(制御信号)
@@ -339,14 +409,10 @@
//---------------------------------------------------------------------------
//
// 定数宣言(ドライバ)
// 定数宣言(バス制御タイミング)
//
//---------------------------------------------------------------------------
#define DEVICE_NAME "rascsidrv"
#define DRIVER_PATH "/dev/" DEVICE_NAME
#define IOCTL_INIT 0x100
#define IOCTL_MODE 0x101
#define IOCTL_PADS 0x102
#define GPIO_DATA_SETTLING 100 // データバスが安定する時間(ns)
//---------------------------------------------------------------------------
//
@@ -371,6 +437,9 @@ public:
DWORD FASTCALL Aquire();
// 信号取り込み
void FASTCALL SetENB(BOOL ast);
// ENBシグナル設定
BOOL FASTCALL GetBSY();
// BSYシグナル取得
void FASTCALL SetBSY(BOOL ast);
@@ -420,24 +489,25 @@ public:
// データシグナル取得
void FASTCALL SetDAT(BYTE dat);
// データシグナル設定
BOOL FASTCALL GetDP();
// パリティシグナル取得
int FASTCALL CommandHandShake(BYTE *buf);
// コマンド受信ハンドシェイク
int FASTCALL ReceiveHandShake(BYTE *buf, int count);
// データ受信ハンドシェイク
int FASTCALL SendHandShake(BYTE *buf, int count);
// データ送信ハンドシェイク
// タイマ関係
void FASTCALL SleepNsec(DWORD nsec);
// ナノ秒単位のスリープ
#ifdef USE_SEL_EVENT_ENABLE
// SEL信号割り込み関係
int FASTCALL PollSelectEvent();
// SEL信号イベントポーリング
void FASTCALL ClearSelectEvent();
// SEL信号イベントクリア
#endif // USE_SEL_EVENT_ENABLE
private:
void FASTCALL DrvConfig(DWORD drive);
// GPIOドライブ能力設定
void FASTCALL PinConfig(int pin, int mode);
// GPIOピン機能設定(入出力設定)
void FASTCALL PullConfig(int pin, int mode);
// GPIOピン機能設定(プルアップ/ダウン)
void FASTCALL PinSetSignal(int pin, BOOL ast);
// GPIOピン出力信号設定
// SCSI入出力信号制御
void FASTCALL MakeTable();
// ワークテーブル作成
void FASTCALL SetControl(int pin, BOOL ast);
@@ -448,19 +518,66 @@ private:
// SCSI入力信号値取得
void FASTCALL SetSignal(int pin, BOOL ast);
// SCSI出力信号値設定
BOOL FASTCALL WaitSignal(int pin, BOOL ast);
// 信号変化待ち
// 割り込み制御
void FASTCALL DisableIRQ();
// IRQ禁止
void FASTCALL EnableIRQ();
// IRQ有効
// GPIOピン機能設定
void FASTCALL PinConfig(int pin, int mode);
// GPIOピン機能設定(入出力設定)
void FASTCALL PullConfig(int pin, int mode);
// GPIOピン機能設定(プルアップ/ダウン)
void FASTCALL PinSetSignal(int pin, BOOL ast);
// GPIOピン出力信号設定
void FASTCALL DrvConfig(DWORD drive);
// GPIOドライブ能力設定
mode_e actmode; // 動作モード
DWORD baseaddr; // ベースアドレス
int rpitype;
// ラズパイ種別
volatile DWORD *gpio; // GPIOレジスタ
volatile DWORD *pads; // PADSレジスタ
volatile DWORD *level; // GPIO入力レベル
volatile DWORD *irpctl; // 割り込み制御レジスタ
#ifndef BAREMETAL
volatile DWORD irptenb; // 割り込み有効状態
volatile DWORD *qa7regs; // QA7レジスタ
volatile int tintcore; // 割り込み制御対象CPU
volatile DWORD tintctl; // 割り込みコントロール
volatile DWORD giccpmr; // GICC 優先度設定
#endif // BAREMETAL
volatile DWORD *gicd; // GIC 割り込み分配器レジスタ
volatile DWORD *gicc; // GIC CPUインターフェースレジスタ
DWORD gpfsel[4]; // GPFSEL0-4バックアップ
DWORD signals; // バス全信号
#if defined(USE_SEL_EVENT_ENABLE) && !defined(BAREMETAL)
struct gpioevent_request selevreq; // SEL信号イベント要求
int epfd; // epollファイルディスクプリタ
#endif // USE_SEL_EVENT_ENABLE && !BAREMETAL
#if SIGNAL_CONTROL_MODE == 0
DWORD tblDatMsk[3][256]; // データマスク用テーブル
@@ -471,9 +588,35 @@ private:
DWORD tblDatSet[256]; // データ設定用テーブル
#endif
int drvfd; // カーネルドライバファイルディスクプリタ
static const int SignalTable[19]; // シグナルテーブル
};
//===========================================================================
//
// システムタイマ
//
//===========================================================================
class SysTimer
{
public:
static void FASTCALL Init(DWORD *syst, DWORD *armt);
// 初期化
static DWORD FASTCALL GetTimerLow();
// システムタイマ(LO)取得
static DWORD FASTCALL GetTimerHigh();
// システムタイマ(HI)取得
static void FASTCALL SleepNsec(DWORD nsec);
// ナノ秒単位のスリープ
static void FASTCALL SleepUsec(DWORD usec);
// μ秒単位のスリープ
private:
static volatile DWORD *systaddr;
// システムタイマアドレス
static volatile DWORD *armtaddr;
// ARMタイマアドレス
static volatile DWORD corefreq;
// コア周波数
};
#endif // gpiobus_h

View File

@@ -1,9 +0,0 @@
KERNEL_HEADERS=/lib/modules/$(shell uname -r)/build
obj-m := rascsidrv.o
ccflags-y := -O3
all:
$(MAKE) -C $(KERNEL_HEADERS) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNEL_HEADERS) M=$(PWD) clean

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2018 GIMONS
// Copyright (C) 2016-2020 GIMONS
// [ ログ ]
//
//---------------------------------------------------------------------------

View File

@@ -4,7 +4,7 @@
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2018 GIMONS
// Copyright (C) 2016-2020 GIMONS
//
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
//
@@ -48,18 +48,29 @@
#include <stdarg.h>
#include <string.h>
#include <sched.h>
#include <poll.h>
#include <pthread.h>
#include <dirent.h>
#include <iconv.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifndef BAREMETAL
#include <poll.h>
#include <dirent.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <linux/gpio.h>
#else
#include <machine/endian.h>
#define htonl(_x) __htonl(_x)
#define htons(_x) __htons(_x)
#define ntohl(_x) __ntohl(_x)
#define ntohs(_x) __ntohs(_x)
#endif // BAREMETAL
#if defined(__linux__)
#include <linux/if.h>
@@ -71,8 +82,6 @@
#include <net/if_dl.h>
#include <net/if_tap.h>
#include <ifaddrs.h>
#else
#error unsupported platform
#endif
//---------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2018 GIMONS
// Copyright (C) 2016-2020 GIMONS
// [ 制御コマンド送信 ]
//
//---------------------------------------------------------------------------
@@ -65,6 +65,7 @@ int main(int argc, char* argv[])
{
int opt;
int id;
int un;
int cmd;
int type;
char *file;
@@ -74,6 +75,7 @@ int main(int argc, char* argv[])
char buf[BUFSIZ];
id = -1;
un = 0;
cmd = -1;
type = -1;
file = NULL;
@@ -83,10 +85,11 @@ int main(int argc, char* argv[])
if (argc < 2) {
fprintf(stderr, "SCSI Target Emulator RaSCSI Controller\n");
fprintf(stderr,
"Usage: %s -i ID [-c CMD] [-t TYPE] [-f FILE]\n",
"Usage: %s -i ID [-u UNIT] [-c CMD] [-t TYPE] [-f FILE]\n",
argv[0]);
fprintf(stderr, " where ID := {0|1|2|3|4|5|6|7}\n");
fprintf(stderr, " CMD := {attach|detatch|insert|eject|protect}\n");
fprintf(stderr, " UNIT := {0|1} default setting is 0.\n");
fprintf(stderr, " CMD := {attach|detach|insert|eject|protect}\n");
fprintf(stderr, " TYPE := {hd|mo|cd|bridge}\n");
fprintf(stderr, " FILE := image file path\n");
fprintf(stderr, " CMD is 'attach' or 'insert' and FILE parameter is required.\n");
@@ -97,12 +100,16 @@ int main(int argc, char* argv[])
// 引数解析
opterr = 0;
while ((opt = getopt(argc, argv, "i:c:t:f:l")) != -1) {
while ((opt = getopt(argc, argv, "i:u:c:t:f:l")) != -1) {
switch (opt) {
case 'i':
id = optarg[0] - '0';
break;
case 'u':
un = optarg[0] - '0';
break;
case 'c':
switch (optarg[0]) {
case 'a': // ATTACH
@@ -174,6 +181,12 @@ int main(int argc, char* argv[])
exit(EINVAL);
}
// ユニットチェック
if (un < 0 || un > 1) {
fprintf(stderr, "Error : Invalid UNIT\n");
exit(EINVAL);
}
// コマンドチェック
if (cmd < 0) {
cmd = 0; // デフォルトはATTATCHとする
@@ -231,7 +244,7 @@ int main(int argc, char* argv[])
}
// 送信コマンド生成
sprintf(buf, "%d %d %d %s\n", id, cmd, type, file ? file : "-");
sprintf(buf, "%d %d %d %d %s\n", id, un, cmd, type, file ? file : "-");
if (!SendCommand(buf)) {
exit(ENOTCONN);
}

View File

@@ -4,7 +4,7 @@
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2018 GIMONS
// Copyright (C) 2016-2020 GIMONS
// [ HDDダンプユーティリティ(イニシーエタモード) ]
//
//---------------------------------------------------------------------------
@@ -207,29 +207,15 @@ BOOL ParseArgument(int argc, char* argv[])
//---------------------------------------------------------------------------
BOOL WaitPhase(BUS::phase_t phase)
{
int count;
DWORD now;
// REQを待つ(6秒)
count = 30000;
do {
usleep(200);
// タイムアウト(3000ms)
now = SysTimer::GetTimerLow();
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
bus.Aquire();
if (bus.GetREQ()) {
break;
if (bus.GetREQ() && bus.GetPhase() == phase) {
return TRUE;
}
} while (count--);
// フェーズが一致すればOK
bus.Aquire();
if (bus.GetPhase() == phase) {
return TRUE;
}
// フェーズが一致すればOK(リトライ)
usleep(1000 * 1000);
bus.Aquire();
if (bus.GetPhase() == phase) {
return TRUE;
}
return FALSE;
@@ -242,6 +228,7 @@ BOOL WaitPhase(BUS::phase_t phase)
//---------------------------------------------------------------------------
void BusFree()
{
// バスリセット
bus.Reset();
}
@@ -312,8 +299,6 @@ BOOL Command(BYTE *buf, int length)
//---------------------------------------------------------------------------
int DataIn(BYTE *buf, int length)
{
int count;
// フェーズ待ち
if (!WaitPhase(BUS::datain)) {
return -1;
@@ -330,8 +315,6 @@ int DataIn(BYTE *buf, int length)
//---------------------------------------------------------------------------
int DataOut(BYTE *buf, int length)
{
int count;
// フェーズ待ち
if (!WaitPhase(BUS::dataout)) {
return -1;
@@ -444,6 +427,7 @@ int RequestSense(int id, BYTE *buf)
// 結果コード初期化
result = 0;
count = 0;
// SELECTION
if (!Selection(id)) {
@@ -461,7 +445,7 @@ int RequestSense(int id, BYTE *buf)
}
// DATAIN
memset(buf, 0x00, sizeof(buf));
memset(buf, 0x00, 256);
count = DataIn(buf, 256);
if (count <= 0) {
result = -3;
@@ -504,6 +488,7 @@ int ModeSense(int id, BYTE *buf)
// 結果コード初期化
result = 0;
count = 0;
// SELECTION
if (!Selection(id)) {
@@ -522,7 +507,7 @@ int ModeSense(int id, BYTE *buf)
}
// DATAIN
memset(buf, 0x00, sizeof(buf));
memset(buf, 0x00, 256);
count = DataIn(buf, 256);
if (count <= 0) {
result = -3;
@@ -565,6 +550,7 @@ int Inquiry(int id, BYTE *buf)
// 結果コード初期化
result = 0;
count = 0;
// SELECTION
if (!Selection(id)) {
@@ -582,8 +568,8 @@ int Inquiry(int id, BYTE *buf)
}
// DATAIN
memset(buf, 0x00, sizeof(buf));
count = DataIn(buf, 255);
memset(buf, 0x00, 256);
count = DataIn(buf, 256);
if (count <= 0) {
result = -3;
goto exit;
@@ -625,6 +611,7 @@ int ReadCapacity(int id, BYTE *buf)
// 結果コード初期化
result = 0;
count = 0;
// SELECTION
if (!Selection(id)) {
@@ -641,7 +628,7 @@ int ReadCapacity(int id, BYTE *buf)
}
// DATAIN
memset(buf, 0x00, sizeof(buf));
memset(buf, 0x00, 8);
count = DataIn(buf, 8);
if (count <= 0) {
result = -3;
@@ -684,6 +671,7 @@ int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
// 結果コード初期化
result = 0;
count = 0;
// SELECTION
if (!Selection(id)) {
@@ -748,6 +736,7 @@ int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
// 結果コード初期化
result = 0;
count = 0;
// SELECTION
if (!Selection(id)) {
@@ -815,7 +804,6 @@ int main(int argc, char* argv[])
DWORD duni;
DWORD dsiz;
DWORD dnum;
DWORD rest;
Fileio fio;
Fileio::OpenMode omode;
off64_t size;
@@ -918,18 +906,21 @@ int main(int argc, char* argv[])
(buffer[0] << 24) | (buffer[1] << 16) |
(buffer[2] << 8) | buffer[3];
bnum++;
printf("Number of blocks : %d Blocks\n", bnum);
printf("Block length : %d Bytes\n", bsiz);
printf("Number of blocks : %d Blocks\n", (int)bnum);
printf("Block length : %d Bytes\n", (int)bsiz);
printf("Unit Capacity : %d MBytes %d Bytes\n",
bsiz * bnum / 1024 / 1024,
bsiz * bnum);
(int)(bsiz * bnum / 1024 / 1024),
(int)(bsiz * bnum));
// リストアファイルサイズの取得
if (restore) {
size = fio.GetFileSize();
printf("Restore file size : %d bytes", (int)size);
if (size != (off64_t)(bsiz * bnum)) {
printf("(WARNING : File size isn't equal to disk size)");
if (size > (off64_t)(bsiz * bnum)) {
printf("(WARNING : File size is larger than disk size)");
} else if (size < (off64_t)(bsiz * bnum)) {
printf("(ERROR : File size is smaller than disk size)\n");
goto cleanup_exit;
}
printf("\n");
}
@@ -947,12 +938,15 @@ int main(int argc, char* argv[])
printf("Dump progress : ");
}
for (i = 0; i < dnum; i++) {
for (i = 0; i < (int)dnum; i++) {
if (i > 0) {
printf("\033[21D");
printf("\033[0K");
}
printf("%3d\%(%7d/%7d)", (i + 1) * 100 / dnum, i * duni, bnum);
printf("%3d%%(%7d/%7d)",
(int)((i + 1) * 100 / dnum),
(int)(i * duni),
(int)bnum);
fflush(stdout);
if (restore) {
@@ -974,13 +968,18 @@ int main(int argc, char* argv[])
goto cleanup_exit;
}
if (dnum > 0) {
printf("\033[21D");
printf("\033[0K");
}
// 容量上の端数処理
dnum = bnum % duni;
dsiz = dnum * bsiz;
if (dnum > 0) {
if (restore) {
if (fio.Read(buffer, dsiz)) {
Write10(targetid, i * duni, duni, dsiz, buffer);
Write10(targetid, i * duni, dnum, dsiz, buffer);
}
} else {
if (Read10(targetid, i * duni, dnum, dsiz, buffer) >= 0) {
@@ -990,9 +989,7 @@ int main(int argc, char* argv[])
}
// 完了メッセージ
printf("\033[21D");
printf("\033[0K");
printf("%3d\%(%7d/%7d)\n", 100, bnum, bnum);
printf("%3d%%(%7d/%7d)\n", 100, (int)bnum, (int)bnum);
cleanup_exit:
// ファイルクローズ

View File

@@ -0,0 +1,819 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
// [ HDDダンプユーティリティ(イニシーエタモード/SASI Version) ]
//
// SASI IMAGE EXAMPLE
// X68000
// 10MB(10441728 BS=256 C=40788)
// 20MB(20748288 BS=256 C=81048)
// 40MB(41496576 BS=256 C=162096)
//
// MZ-2500/MZ-2800 MZ-1F23
// 20MB(22437888 BS=1024 C=21912)
//
//---------------------------------------------------------------------------
#include "os.h"
#include "xm6.h"
#include "fileio.h"
#include "filepath.h"
#include "gpiobus.h"
//---------------------------------------------------------------------------
//
// 定数宣言
//
//---------------------------------------------------------------------------
#define BUFSIZE 1024 * 64 // 64KBぐらいかなぁ
//---------------------------------------------------------------------------
//
// 変数宣言
//
//---------------------------------------------------------------------------
GPIOBUS bus; // バス
int targetid; // ターゲットデバイスID
int unitid; // ターゲットユニットID
int bsiz; // ブロックサイズ
int bnum; // ブロック数
Filepath hdffile; // HDFファイル
BOOL restore; // リストアフラグ
BYTE buffer[BUFSIZE]; // ワークバッファ
int result; // 結果コード
//---------------------------------------------------------------------------
//
// 関数宣言
//
//---------------------------------------------------------------------------
void Cleanup();
//---------------------------------------------------------------------------
//
// シグナル処理
//
//---------------------------------------------------------------------------
void KillHandler(int sig)
{
// 停止指示
Cleanup();
exit(0);
}
//---------------------------------------------------------------------------
//
// バナー出力
//
//---------------------------------------------------------------------------
BOOL Banner(int argc, char* argv[])
{
printf("RaSCSI hard disk dump utility(SASI HDD) ");
printf("version %01d.%01d%01d\n",
(int)((VERSION >> 8) & 0xf),
(int)((VERSION >> 4) & 0xf),
(int)((VERSION ) & 0xf));
if (argc < 2 || strcmp(argv[1], "-h") == 0) {
printf("Usage: %s -i ID [-u UT] [-b BSIZE] -c COUNT -f FILE [-r]\n", argv[0]);
printf(" ID is target device SASI ID {0|1|2|3|4|5|6|7}.\n");
printf(" UT is target unit ID {0|1}. Default is 0.\n");
printf(" BSIZE is block size {256|512|1024}. Default is 256.\n");
printf(" COUNT is block count.\n");
printf(" FILE is HDF file path.\n");
printf(" -r is restore operation.\n");
return FALSE;
}
return TRUE;
}
//---------------------------------------------------------------------------
//
// 初期化
//
//---------------------------------------------------------------------------
BOOL Init()
{
// 割り込みハンドラ設定
if (signal(SIGINT, KillHandler) == SIG_ERR) {
return FALSE;
}
if (signal(SIGHUP, KillHandler) == SIG_ERR) {
return FALSE;
}
if (signal(SIGTERM, KillHandler) == SIG_ERR) {
return FALSE;
}
// GPIO初期化
if (!bus.Init(BUS::INITIATOR)) {
return FALSE;
}
// ワーク初期化
targetid = -1;
unitid = 0;
bsiz = 256;
bnum = -1;
restore = FALSE;
return TRUE;
}
//---------------------------------------------------------------------------
//
// クリーンアップ
//
//---------------------------------------------------------------------------
void Cleanup()
{
// バスをクリーンアップ
bus.Cleanup();
}
//---------------------------------------------------------------------------
//
// リセット
//
//---------------------------------------------------------------------------
void Reset()
{
// バス信号線をリセット
bus.Reset();
}
//---------------------------------------------------------------------------
//
// 引数処理
//
//---------------------------------------------------------------------------
BOOL ParseArgument(int argc, char* argv[])
{
int opt;
char *file;
// 初期化
file = NULL;
// 引数解析
opterr = 0;
while ((opt = getopt(argc, argv, "i:u:b:c:f:r")) != -1) {
switch (opt) {
case 'i':
targetid = optarg[0] - '0';
break;
case 'u':
unitid = optarg[0] - '0';
break;
case 'b':
bsiz = atoi(optarg);
break;
case 'c':
bnum = atoi(optarg);
break;
case 'f':
file = optarg;
break;
case 'r':
restore = TRUE;
break;
}
}
// TARGET IDチェック
if (targetid < 0 || targetid > 7) {
fprintf(stderr,
"Error : Invalid target id range\n");
return FALSE;
}
// UNIT IDチェック
if (unitid < 0 || unitid > 1) {
fprintf(stderr,
"Error : Invalid unit id range\n");
return FALSE;
}
// BSIZチェック
if (bsiz != 256 && bsiz != 512 && bsiz != 1024) {
fprintf(stderr,
"Error : Invalid block size\n");
return FALSE;
}
// BNUMチェック
if (bnum < 0) {
fprintf(stderr,
"Error : Invalid block count\n");
return FALSE;
}
// ファイルチェック
if (!file) {
fprintf(stderr,
"Error : Invalid file path\n");
return FALSE;
}
hdffile.SetPath(file);
return TRUE;
}
//---------------------------------------------------------------------------
//
// フェーズ待ち
//
//---------------------------------------------------------------------------
BOOL WaitPhase(BUS::phase_t phase)
{
DWORD now;
// タイムアウト(3000ms)
now = SysTimer::GetTimerLow();
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
bus.Aquire();
if (bus.GetREQ() && bus.GetPhase() == phase) {
return TRUE;
}
}
return FALSE;
}
//---------------------------------------------------------------------------
//
// バスフリーフェーズ実行
//
//---------------------------------------------------------------------------
void BusFree()
{
// バスリセット
bus.Reset();
}
//---------------------------------------------------------------------------
//
// セレクションフェーズ実行
//
//---------------------------------------------------------------------------
BOOL Selection(int id)
{
BYTE data;
int count;
// ID設定とSELアサート
data = 0;
data |= (1 << id);
bus.SetDAT(data);
bus.SetSEL(TRUE);
// BSYを待つ
count = 10000;
do {
usleep(20);
bus.Aquire();
if (bus.GetBSY()) {
break;
}
} while (count--);
// SELネゲート
bus.SetSEL(FALSE);
// ターゲットがビジー状態なら成功
return bus.GetBSY();
}
//---------------------------------------------------------------------------
//
// コマンドフェーズ実行
//
//---------------------------------------------------------------------------
BOOL Command(BYTE *buf, int length)
{
int count;
// フェーズ待ち
if (!WaitPhase(BUS::command)) {
return FALSE;
}
// コマンド送信
count = bus.SendHandShake(buf, length);
// 送信結果が依頼数と同じなら成功
if (count == length) {
return TRUE;
}
// 送信エラー
return FALSE;
}
//---------------------------------------------------------------------------
//
// データインフェーズ実行
//
//---------------------------------------------------------------------------
int DataIn(BYTE *buf, int length)
{
// フェーズ待ち
if (!WaitPhase(BUS::datain)) {
return -1;
}
// データ受信
return bus.ReceiveHandShake(buf, length);
}
//---------------------------------------------------------------------------
//
// データアウトフェーズ実行
//
//---------------------------------------------------------------------------
int DataOut(BYTE *buf, int length)
{
// フェーズ待ち
if (!WaitPhase(BUS::dataout)) {
return -1;
}
// データ受信
return bus.SendHandShake(buf, length);
}
//---------------------------------------------------------------------------
//
// ステータスフェーズ実行
//
//---------------------------------------------------------------------------
int Status()
{
BYTE buf[256];
// フェーズ待ち
if (!WaitPhase(BUS::status)) {
return -2;
}
// データ受信
if (bus.ReceiveHandShake(buf, 1) == 1) {
return (int)buf[0];
}
// 受信エラー
return -1;
}
//---------------------------------------------------------------------------
//
// メッセージインフェーズ実行
//
//---------------------------------------------------------------------------
int MessageIn()
{
BYTE buf[256];
// フェーズ待ち
if (!WaitPhase(BUS::msgin)) {
return -2;
}
// データ受信
if (bus.ReceiveHandShake(buf, 1) == 1) {
return (int)buf[0];
}
// 受信エラー
return -1;
}
//---------------------------------------------------------------------------
//
// TEST UNIT READY実行
//
//---------------------------------------------------------------------------
int TestUnitReady(int id)
{
BYTE cmd[256];
// 結果コード初期化
result = 0;
// SELECTION
if (!Selection(id)) {
result = -1;
goto exit;
}
// COMMAND
memset(cmd, 0x00, 6);
cmd[0] = 0x00;
cmd[1] = unitid << 5;
if (!Command(cmd, 6)) {
result = -2;
goto exit;
}
// STATUS
if (Status() < 0) {
result = -4;
goto exit;
}
// MESSAGE IN
if (MessageIn() < 0) {
result = -5;
goto exit;
}
exit:
// バスフリー
BusFree();
return result;
}
//---------------------------------------------------------------------------
//
// REQUEST SENSE実行
//
//---------------------------------------------------------------------------
int RequestSense(int id, BYTE *buf)
{
BYTE cmd[256];
int count;
// 結果コード初期化
result = 0;
count = 0;
// SELECTION
if (!Selection(id)) {
result = -1;
goto exit;
}
// COMMAND
memset(cmd, 0x00, 6);
cmd[0] = 0x03;
cmd[1] = unitid << 5;
cmd[4] = 4;
if (!Command(cmd, 6)) {
result = -2;
goto exit;
}
// DATAIN
memset(buf, 0x00, 256);
count = DataIn(buf, 256);
if (count <= 0) {
result = -3;
goto exit;
}
// STATUS
if (Status() < 0) {
result = -4;
goto exit;
}
// MESSAGE IN
if (MessageIn() < 0) {
result = -5;
goto exit;
}
exit:
// バスフリー
BusFree();
// 成功であれば転送数を返す
if (result == 0) {
return count;
}
return result;
}
//---------------------------------------------------------------------------
//
// READ6実行
//
//---------------------------------------------------------------------------
int Read6(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
{
BYTE cmd[256];
int count;
// 結果コード初期化
result = 0;
count = 0;
// SELECTION
if (!Selection(id)) {
result = -1;
goto exit;
}
// COMMAND
memset(cmd, 0x00, 10);
cmd[0] = 0x8;
cmd[1] = (BYTE)(bstart >> 16);
cmd[1] &= 0x1f;
cmd[1] = unitid << 5;
cmd[2] = (BYTE)(bstart >> 8);
cmd[3] = (BYTE)bstart;
cmd[4] = (BYTE)blength;
if (!Command(cmd, 6)) {
result = -2;
goto exit;
}
// DATAIN
count = DataIn(buf, length);
if (count <= 0) {
result = -3;
goto exit;
}
// STATUS
if (Status() < 0) {
result = -4;
goto exit;
}
// MESSAGE IN
if (MessageIn() < 0) {
result = -5;
goto exit;
}
exit:
// バスフリー
BusFree();
// 成功であれば転送数を返す
if (result == 0) {
return count;
}
return result;
}
//---------------------------------------------------------------------------
//
// WRITE6実行
//
//---------------------------------------------------------------------------
int Write6(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
{
BYTE cmd[256];
int count;
// 結果コード初期化
result = 0;
count = 0;
// SELECTION
if (!Selection(id)) {
result = -1;
goto exit;
}
// COMMAND
memset(cmd, 0x00, 10);
cmd[0] = 0xa;
cmd[1] = (BYTE)(bstart >> 16);
cmd[1] &= 0x1f;
cmd[1] = unitid << 5;
cmd[2] = (BYTE)(bstart >> 8);
cmd[3] = (BYTE)bstart;
cmd[4] = (BYTE)blength;
if (!Command(cmd, 6)) {
result = -2;
goto exit;
}
// DATAOUT
count = DataOut(buf, length);
if (count <= 0) {
result = -3;
goto exit;
}
// STATUS
if (Status() < 0) {
result = -4;
goto exit;
}
// MESSAGE IN
if (MessageIn() < 0) {
result = -5;
goto exit;
}
exit:
// バスフリー
BusFree();
// 成功であれば転送数を返す
if (result == 0) {
return count;
}
return result;
}
//---------------------------------------------------------------------------
//
// 主処理
//
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
int i;
int count;
DWORD duni;
DWORD dsiz;
DWORD dnum;
Fileio fio;
Fileio::OpenMode omode;
off64_t size;
// バナー出力
if (!Banner(argc, argv)) {
exit(0);
}
// 初期化
if (!Init()) {
fprintf(stderr, "Error : Initializing\n");
// 恐らくrootでは無い
exit(EPERM);
}
// 構築
if (!ParseArgument(argc, argv)) {
// クリーンアップ
Cleanup();
// 引数エラーで終了
exit(EINVAL);
}
// リセット
Reset();
// ファイルオープン
if (restore) {
omode = Fileio::ReadOnly;
} else {
omode = Fileio::WriteOnly;
}
if (!fio.Open(hdffile.GetPath(), omode)) {
fprintf(stderr, "Error : Can't open hdf file\n");
// クリーンアップ
Cleanup();
exit(EPERM);
}
// バスフリー
BusFree();
// RESETシグナル発行
bus.SetRST(TRUE);
usleep(1000);
bus.SetRST(FALSE);
// ダンプ開始
printf("TARGET ID : %d\n", targetid);
printf("UNIT ID : %d\n", unitid);
// TEST UNIT READY
count = TestUnitReady(targetid);
if (count < 0) {
fprintf(stderr, "TEST UNIT READY ERROR %d\n", count);
goto cleanup_exit;
}
// REQUEST SENSE(for CHECK CONDITION)
count = RequestSense(targetid, buffer);
if (count < 0) {
fprintf(stderr, "REQUEST SENSE ERROR %d\n", count);
goto cleanup_exit;
}
// ブロックサイズとブロック数の表示
printf("Number of blocks : %d Blocks\n", bnum);
printf("Block length : %d Bytes\n", bsiz);
// データサイズの表示
printf("Total length : %d MBytes %d Bytes\n",
(bsiz * bnum / 1024 / 1024),
(bsiz * bnum));
// リストアファイルサイズの取得
if (restore) {
size = fio.GetFileSize();
printf("Restore file size : %d bytes", (int)size);
if (size > (off64_t)(bsiz * bnum)) {
printf("(WARNING : File size is larger than disk size)");
} else if (size < (off64_t)(bsiz * bnum)) {
printf("(ERROR : File size is smaller than disk size)\n");
goto cleanup_exit;
}
printf("\n");
}
// バッファサイズ毎にダンプする
duni = BUFSIZE;
duni /= bsiz;
dsiz = BUFSIZE;
dnum = bnum * bsiz;
dnum /= BUFSIZE;
if (restore) {
printf("Restore progress : ");
} else {
printf("Dump progress : ");
}
for (i = 0; i < (int)dnum; i++) {
if (i > 0) {
printf("\033[21D");
printf("\033[0K");
}
printf("%3d%%(%7d/%7d)",
(int)((i + 1) * 100 / dnum),
(int)(i * duni),
bnum);
fflush(stdout);
if (restore) {
if (fio.Read(buffer, dsiz)) {
if (Write6(targetid, i * duni, duni, dsiz, buffer) >= 0) {
continue;
}
}
} else {
if (Read6(targetid, i * duni, duni, dsiz, buffer) >= 0) {
if (fio.Write(buffer, dsiz)) {
continue;
}
}
}
printf("\n");
printf("Error occured and aborted... %d\n", result);
goto cleanup_exit;
}
if (dnum > 0) {
printf("\033[21D");
printf("\033[0K");
}
// 容量上の端数処理
dnum = bnum % duni;
dsiz = dnum * bsiz;
if (dnum > 0) {
if (restore) {
if (fio.Read(buffer, dsiz)) {
Write6(targetid, i * duni, dnum, dsiz, buffer);
}
} else {
if (Read6(targetid, i * duni, dnum, dsiz, buffer) >= 0) {
fio.Write(buffer, dsiz);
}
}
}
// 完了メッセージ
printf("%3d%%(%7d/%7d)\n", 100, bnum, bnum);
cleanup_exit:
// ファイルクローズ
fio.Close();
// クリーンアップ
Cleanup();
// 終了
exit(0);
}

View File

@@ -3,7 +3,7 @@
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2018 GIMONS
// Copyright (C) 2014-2020 GIMONS
//
// [ SCSI共通 ]
//

View File

@@ -3,7 +3,7 @@
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2018 GIMONS
// Copyright (C) 2014-2020 GIMONS
//
// [ SCSI共通 ]
//
@@ -111,15 +111,16 @@ public:
// データシグナル取得
virtual void FASTCALL SetDAT(BYTE dat) = 0;
// データシグナル設定
virtual BOOL FASTCALL GetDP() = 0;
// パリティシグナル取得
virtual int FASTCALL CommandHandShake(BYTE *buf) = 0;
// コマンド受信ハンドシェイク
virtual int FASTCALL ReceiveHandShake(BYTE *buf, int count) = 0;
// データ受信ハンドシェイク
virtual int FASTCALL SendHandShake(BYTE *buf, int count) = 0;
// データ送信ハンドシェイク
virtual void FASTCALL SleepNsec(DWORD nsec) = 0;
// ナノ秒単位のスリープ
private:
static const phase_t phase_table[8];
// フェーズテーブル

View File

@@ -4,7 +4,7 @@
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2018 GIMONS
// Copyright (C) 2016-2020 GIMONS
//
// [ 共通定義 ]
//
@@ -18,7 +18,7 @@
// VERSION
//
//---------------------------------------------------------------------------
#define VERSION 0x0134
#define VERSION 0x0147
//---------------------------------------------------------------------------
//
@@ -34,6 +34,15 @@
//---------------------------------------------------------------------------
#define MAKEID(a, b, c, d) ((DWORD)((a<<24) | (b<<16) | (c<<8) | d))
//---------------------------------------------------------------------------
//
// 各種動作設定
//
//---------------------------------------------------------------------------
#define USE_SEL_EVENT_ENABLE // SEL信号をイベントでチェックする
#define REMOVE_FIXED_SASIHD_SIZE // SASIHDのサイズ制限を解除する
#define USE_MZ1F23_1024_SUPPORT // MZ-1F23(SASI 20M/セクタサイズ1024)
//---------------------------------------------------------------------------
//
// クラス宣言