pico6502 デベロッパーズガイド
注記: pico6502 プロジェクトは初期開発段階にあります。ドライバーフレームワークとメモリモデルは完全に実装されており、picoZ80 と同じアーキテクチャを共有しています。ただし、現時点ではプレースホルダーの BBC Model B ペルソナのみが存在します — このガイドはその基盤の上に独自のドライバーを追加する方法を説明します。pico6502 が picoZ80 と構造的に同一な箇所には、picoZ80 デベロッパーズガイドへのクロスリファレンスが示されています。
概要
pico6502 ファームウェアは picoZ80 ファームウェアと構造的に同一です。同じデュアルコア RP2350B アーキテクチャ、同じ PSRAM メモリモデル、同じ JSON 設定システム、同じドライバーフレームワークを使用しています。主な違いは:
- M6502CPU.c / M6502CPU.h が Z80CPU.c / Z80CPU.h に代わり、メインのディスパッチおよびドライバーフレームワークファイルとなっています。
- 6502 には独立した I/O アドレス空間がありません —
ioPtr[]配列はなく、iomapの JSON セクションもありません。すべてのペリフェラルは 64KB メモリマップ内のFUNCタイプのブロックとして仮想化されます。 - PIO バスインターフェース(
M6502.pio)は Z80 のシングルクロックモデルではなく、デュアルフェーズ PHI1/PHI2 クロッキングを実装しています。 - ビルドターゲットディレクトリは
BaseZ80ではなくBaseM6502です。 - JSON の CPU セクションキーは
"z80"ではなく"6502"です。
その他すべて — コア間キューパターン、ドライバーライフサイクルコールバック(
reset_ptr、poll_ptr、task_ptr)、virtualFuncMap[] 登録テーブル、メモリブロックタイプ定数、t_6502PSRAM 構造体、ESP32 コプロセッサープロトコル、ビルドシステム — は picoZ80 のコードベースと共有されています。
ソースツリー
すべてのソースコードはリポジトリルート内の
projects/tzpuPico/ 以下にあります。以下のレイアウトは pico6502 固有のファイルをハイライトしています:
tzpuPico/
├── CMakeLists.txt トップレベルビルドファイル
├── src/
│ ├── CMakeLists.txt ソースレベルビルドファイル — 新しいドライバーファイルをここに追加
│ ├── M6502CPU.c *** キーファイル: 6502 ディスパッチ、ドライバーフレームワーク、virtualFuncMap
│ ├── M6502CPU.h (レガシー — include/ 経由でインクルード)
│ ├── M6502.c PIO 初期化とバスサイクルエントリーポイント
│ ├── M6502.pio PIO プログラム: クロック、addr、data、サイクル、フェッチ、リード、ライト、irq、nmi、so
│ ├── Z80CPU.c / Z80CPU.h Z80 のカウンターパート(pico6502 ビルドでは不使用)
│ ├── FSPI.c / FSPI.h フラッシュ SPI インターフェース(共有)
│ ├── ESP.c / ESP.h ESP32 通信レイヤー(共有)
│ ├── psram.c / psram.h PSRAM 割り当てと管理(共有)
│ ├── cJSON.c / cJSON.h config.json 用 JSON パーサー(共有)
│ ├── include/
│ │ ├── M6502CPU.h *** キーファイル: すべての 6502 型定義とマクロ
│ │ ├── M6502.h PIO ヘルパー定義
│ │ └── drivers/
│ │ └── BBC/
│ │ └── ModelB.h BBC Model B ドライバーヘッダー(初期プレースホルダー)
│ ├── drivers/
│ │ └── BBC/
│ │ └── ModelB.c *** サンプル/プレースホルダードライバー(BBC Model B ペルソナ)
│ └── model/
│ ├── BaseM6502/
│ │ ├── CMakeLists.txt モデルごとのビルドターゲット
│ │ ├── main.c エントリーポイント(コア 0 + コア 1 起動)
│ │ ├── main_memmap_partition_1.ld スロット 1 用リンカースクリプト
│ │ └── main_memmap_partition_2.ld スロット 2 用リンカースクリプト
│ └── Bootloader/
│ ├── CMakeLists.txt
│ └── main.c 共有ブートローダー(picoZ80 と同一)
└── esp32/
├── CMakeLists.txt
└── main/
└── ... ESP32 ファームウェア(picoZ80 と共有)
picoZ80 との主な違い
独立した I/O アドレス空間がない
最も重要なアーキテクチャの違いは、6502 には
IN/OUT 命令も IORQ 信号もないことです。すべてのペリフェラルは 64KB メモリマップのどこかに配置しなければなりません。picoZ80 では、仮想デバイスは memioPtr[](メモリマップ)または ioPtr[](I/O マップ)のいずれかで登録できます。pico6502 では memioPtr[] のみです — ただし、すべてのペリフェラルアクセスはメモリバスを通じて来るため、これですべてのケースをカバーできます。
したがって
t_6502PSRAM 構造体には ioPtr[] 配列がありません。JSON 設定には "io" 配列がありません。M6502CPU.c のディスパッチループは _membankPtr[] 配列のみをチェックし、MEMBANK_TYPE_FUNC ブロックに対しては対応する memioPtr[] ハンドラーを呼び出します。
PIO バスインターフェースの違い
6502 は二相非重複クロックスキームを使用します。PHI0 は外部クロック入力で、RP2350 は専用の PIO 2 ステートマシン(
m6502_clock_6502)経由でそこから PHI1 と PHI2 を生成します。これは単一の CLK 信号を使用する Z80 とは異なります。
| PIO ブロック | ステートマシン | 目的 |
|---|---|---|
| PIO 0 | m6502_addr、m6502_data |
アドレスバス(A0–A15)、データバス(D0–D7) |
| PIO 1 | m6502_cycle、m6502_fetch、m6502_read、m6502_write、m6502_irq、m6502_nmi、m6502_so |
バスサイクルシーケンシングと制御信号監視 |
| PIO 2 | m6502_clock_6502 |
外部 PHI0 からの PHI1/PHI2 二相クロック生成 |
IRQ 規約は Z80 PIO インターフェースと若干異なります:
| IRQ フラグ | 信号 | 意味 |
|---|---|---|
| IRQ 0 | アドレス/サイクル開始 | 新しい 6502 バスサイクル — PHI1 立ち上がりエッジでアドレス有効 |
| IRQ 1 | データフェーズ | データバスアクティブ — RNW による読み取りまたは書き込み |
| IRQ 4 | NMI | ノンマスカブル割り込みアサート |
| IRQ 5 | IRQ | マスク可能割り込みアサート |
| IRQ 6 | SO | セットオーバーフローピンアサート |
| IRQ 7 | ループ終了 | コア 1 実行ループ終了リクエスト |
PIO プログラミング — C コードによるバスサイクルの駆動方法
pico6502 は picoZ80 と同じ
out exec メカニズムを動的命令インジェクションに使用しますが、16 ビットではなく 32 ビット命令(out exec, 32)を使用します。コア 1 の C コードはプリエンコード済み PIO 命令シーケンスをサイクル SM の TX FIFO にプッシュして各バストランザクションを制御します。
6502 メモリリードサイクルの連携フロー:
コア 1(C コード) PIO ステートマシン
────────────── ──────────────────
1. メモリマップから m6502_cycle: IRQ 0 セット
アドレスを解決 (PHI2 ロー待機中)
│
2. アドレス → TX FIFO プッシュ ────────────→ m6502_addr: アドレス受信
IRQ 0 クリア A0–A15 をピンに出力
│
3. サイクル命令プッシュ ──────────────────→ m6502_cycle: out exec, 32
(リードシーケンス) 実行: R/W̄ ハイ、SYNC ロー設定
サイクル SM TX FIFO へ 実行: PHI2 ハイ待機
│ 実行: RDY 確認
4. RX FIFO 待機 ←──────────────────────── m6502_data: D0–D7 サンプリング
(バスからのデータバイト) PHI2 立ち下がりエッジで
│
5. RX FIFO から m6502_cycle: JMP start_cycle
データ読み取り (次のサイクル準備完了)
│
6. PSRAM またはドライバー
ハンドラーにディスパッチ
ライトサイクルでは、コア 1 がアドレスの後にデータバイトを
m6502_data SM の TX FIFO にプッシュします。データ SM は PHI2 ハイフェーズ中に D0–D7 を駆動し、PHI2 が立ち下がるとデータバスをトライステートにします。サイクル SM は R/W̄ をローに設定してライトを示します。
PIO の基礎、out exec メカニズム、ステートマシンの連携パターンの詳細な説明は、picoZ80 テクニカルガイド — PIO アーキテクチャ詳解を参照してください。6502 固有の PIO の違い:
- 32 ビット
out exec— サイドセットと遅延フィールドを含む完全な PIO 命令エンコーディングが単一の FIFO プッシュで可能。 - クロックフェーズ同期 — サイクル SM は単一の CLK 信号ではなく PHI2 エッジ(
wait 0/1 gpio CLK2)に同期。 - BUSREQ/BUSACK なし — 6502 にはバスリクエストメカニズムがないため、Z80 の
z80_busrqSM に相当するものはありません。 - WAIT の代わりに RDY — ウェイトステートは Z80 の T2 立ち下がりエッジでの
/WAITピン確認ではなく、PHI2 立ち上がりエッジ後の RDY ピン確認で挿入。
t_6502PSRAM 構造体
picoZ80 の
t_Z80PSRAM に相当しますが、ioPtr[] 配列がありません:
// src/include/M6502CPU.h(簡略版)
typedef struct {
uint8_t RAM[MAX_MEMORY_BANKS * MEMORY_PAGE_SIZE]; // 64バンク × 64KB = 4MB RAM/ROM領域
MemoryFunc memPtr[MEMORY_PAGE_SIZE]; // 64K バイト単位リードリダイレクト(PTR タイプ)
MemoryFunc memioPtr[MEMORY_PAGE_SIZE]; // 64K メモリマップハンドラー配列(FUNC タイプ)
// 注: ioPtr[] なし — 6502 には独立した I/O 空間がない
} t_6502PSRAM;
ハンドラー関数シグネチャー
MemoryFunc typedef は picoZ80 と同じです:
// すべてのアクセスで MEMBANK_TYPE_FUNC ブロックに対して呼び出されるハンドラー typedef uint8_t (*MemoryFunc)(M6502CPU *cpu, bool read, uint16_t addr, uint8_t data); // パラメーター: // cpu — M6502CPU 構造体へのポインター(これを通じて PSRAM、状態、キューにアクセス) // read — 6502 リードサイクル(RNW=1)の場合 true、ライトサイクル(RNW=0)の場合 false // addr — このハンドラーをトリガーした 16 ビットアドレス // data — 書き込まれたバイト(read=false の場合のみ意味がある) // 戻り値: // データバスに置くバイト(read=true の場合のみ意味がある)
I/O 空間がないため、独立した
IOFunc typedef はありません — MemoryFunc がすべてのペリフェラルアクセスを処理します。
ドライバーフレームワーク
M6502CPU.c のドライバーフレームワークは picoZ80 のドライバーフレームワークと構造的に同一です。以下の完全な説明については picoZ80 デベロッパーズガイド — ドライバーフレームワークセクションを参照してください:
virtualFuncMap[]登録テーブルと、JSON の"name"フィールドがドライバー初期化関数にどのようにマッチングされるか。VirtualFunctypedef とM6502CPU_getVirtualFunc()ルックアップ。- 二フェーズ初期化フロー(検証パスから設定パスへ)。
- ドライバーライフサイクルコールバック:
reset_ptr、poll_ptr、task_ptr。
名称の違いのみ:
| picoZ80 | pico6502 | 備考 |
|---|---|---|
Z80CPU 構造体 |
M6502CPU 構造体 |
同じフィールド、同じレイアウト |
Z80CPU_getVirtualFunc() |
M6502CPU_getVirtualFunc() |
同じルックアップロジック |
Z80CPU_cpu() |
M6502CPU_cpu() |
コア 1 ホットループエントリーポイント |
Z80CPU_readMem() |
M6502CPU_readMem() |
メモリリードディスパッチ |
Z80CPU_writeMem() |
M6502CPU_writeMem() |
メモリライトディスパッチ |
Z80CPU_readIO() |
— | 相当なし — 6502 に I/O 空間なし |
Z80CPU_writeIO() |
— | 相当なし — 6502 に I/O 空間なし |
cpu->_z80PSRAM |
cpu->_6502PSRAM |
PSRAM 構造体ポインター |
コア 1 ディスパッチループ
M6502CPU_cpu() のコア 1 ホットループは picoZ80 と同じパターンに従います。各 6502 バスサイクルで:
- IRQ 0 を待つ(PHI1 でアドレス有効)。
- PIO 0 RX FIFO から 16 ビットアドレスを読み取る。
_membankPtr[addr >> 9]を参照してブロックタイプ、バンク、ベースを取得する。- 制御 PIO から RNW(リード/ノットライト)を判定する。
- ブロックタイプによってディスパッチ:PHYSICAL(ホストへパス)、RAM(PSRAM 読み書き)、ROM(PSRAM 読み取りのみ)、FUNC(
memioPtr[addr]を呼び出す)、PTR(memPtr[addr]経由でリダイレクト)。 - リードの場合:PIO 0 TX FIFO 経由でデータバスに結果を置く。IRQ 1 を待つ(データフェーズ)。ライトの場合:IRQ 1 の後に PIO 0 RX FIFO からデータを読み取る。
- 登録された各ドライバーの
poll_ptrを呼び出す(約 2048 サイクルごと)。
// M6502CPU_readMem / M6502CPU_writeMem ディスパッチの簡略版
uint8_t M6502CPU_readMem(M6502CPU *cpu, uint16_t addr)
{
uint32_t entry = cpu->_membankPtr[addr >> 9];
uint8_t type = (entry >> 24) & 0xFF;
uint8_t bank = (entry >> 16) & 0xFF;
uint32_t base = (entry & 0xFFFF) << 9;
switch(type)
{
case MEMBANK_TYPE_RAM:
case MEMBANK_TYPE_ROM:
return cpu->_6502PSRAM->RAM[(bank * MEMORY_PAGE_SIZE) + addr];
case MEMBANK_TYPE_FUNC:
if(cpu->_6502PSRAM->memioPtr[addr] != NULL)
return cpu->_6502PSRAM->memioPtr[addr](cpu, true, addr, 0);
return 0x00;
case MEMBANK_TYPE_PTR:
if(cpu->_6502PSRAM->memPtr[addr] != NULL)
return cpu->_6502PSRAM->memPtr[addr](cpu, true, addr, 0);
return 0x00;
case MEMBANK_TYPE_PHYSICAL:
default:
return 0xFF; // 実際のホストハードウェアへのパススルー
}
}
新しいドライバーの作成
pico6502 ドライバーを作成するプロセスは、picoZ80 デベロッパーズガイド — 新しいドライバーの作成で説明されている picoZ80 のプロセスと同一です。6 つのステップは同じです:
src/include/drivers/<Family>/MyDriver.hにヘッダーファイルを作成src/drivers/<Family>/MyDriver.cに実装ファイルを作成- ソースファイルを
src/CMakeLists.txtに追加 #ifdef INCLUDE_<FAMILY>_DRIVERSガードの下でM6502CPU.cにドライバーをインクルードM6502CPU.cのvirtualFuncMap[]にドライバーを登録config.jsonに JSON ドライバーエントリーを追加
主な違いは、すべての関数が
Z80CPU *cpu パラメーターの代わりに M6502CPU *cpu パラメーターを受け取り、cpu->_z80PSRAM ではなく cpu->_6502PSRAM 経由で PSRAM にアクセスすることです。インストールする ioPtr[] スロットはありません — すべての仮想ペリフェラルは memioPtr[] に登録されます。
最小ドライバーテンプレート
以下はアドレス
0xC000–0xC00F に仮想化された 6522 VIA(Versatile Interface Adapter)を示す最小限の 6502 ペリフェラルドライバーです:
// src/include/drivers/BBC/VIA6522.h #ifndef VIA6522_H #define VIA6522_H #include "M6502CPU.h" int VIA6522_Init(M6502CPU *cpu, t_drvConfig *drvConfig, int pass); #endif
// src/drivers/BBC/VIA6522.c
#include "../../include/M6502CPU.h"
#include "../../include/drivers/BBC/VIA6522.h"
// --- 内部状態 ---
typedef struct {
uint8_t regs[16]; // VIA 内部レジスター(ORB, ORA, DDRB, DDRA, T1CL, T1CH, ...)
bool irqPending;
} t_VIA6522State;
static t_VIA6522State ViaState = { .irqPending = false };
// --- メモリハンドラー(0xC000–0xC00F へのすべてのアクセスで呼び出される)---
static uint8_t VIA6522_Handler(M6502CPU *cpu, bool read, uint16_t addr, uint8_t data)
{
uint8_t reg = addr & 0x0F; // VIA は 16 の内部レジスターを持つ
if(read)
{
return ViaState.regs[reg];
}
else
{
ViaState.regs[reg] = data;
// TODO: 必要に応じてタイマー、シフトレジスター、ポートロジックを実装
return 0;
}
}
// --- リセットハンドラー(ホストシステムリセット時に呼び出される)---
static uint8_t VIA6522_Reset(M6502CPU *cpu)
{
memset(&ViaState.regs, 0, sizeof(ViaState.regs));
ViaState.irqPending = false;
return 0;
}
// --- 初期化関数(JSON 設定パース中に呼び出される)---
int VIA6522_Init(M6502CPU *cpu, t_drvConfig *drvConfig, int pass)
{
if(pass == 0)
{
// 検証パス — 名前が一致するかどうかを確認するだけ
return (strcasecmp(drvConfig->name, "via6522") == 0) ? 1 : 0;
}
// 設定パス — ハンドラーをインストール
// 0xC000–0xC00F のすべての 16 VIA レジスターにハンドラーをインストール
for(uint16_t addr = 0xC000; addr <= 0xC00F; addr++)
{
cpu->_6502PSRAM->memioPtr[addr] = VIA6522_Handler;
}
// リセットコールバックを登録
cpu->reset_ptr = VIA6522_Reset;
debugf("VIA6522: 0xC000–0xC00F で初期化済み\n");
return 1;
}
JSON 設定
VIA6522 ドライバーを有効化するには、メモリマップに
FUNC ブロックとドライバーエントリーを追加します:
{
"rp2350": {
"6502": {
"memory": [
{ "enable":1, "addr":"0x0000", "size":"0xC000",
"type":"RAM", "bank":0, "task":"", "file":"" },
{ "enable":1, "addr":"0xC000", "size":"0x0010",
"type":"FUNC", "bank":0, "task":"via6522", "file":"" },
{ "enable":1, "addr":"0xE000", "size":"0x2000",
"type":"ROM", "bank":0, "task":"", "file":"/ROM/bios.rom" }
],
"drivers": [
{ "enable":1, "name":"via6522" }
]
}
}
}
virtualFuncMap への登録
M6502CPU.c の virtualFuncMap[] テーブルにエントリーを追加します。name 文字列は JSON ドライバーの "name" フィールドと大文字小文字を区別せずにマッチングされます:
// M6502CPU.c — virtualFuncMap[] に追加
static const t_VirtualFuncMap virtualFuncMap[] = {
{ "BBCModelB", BBCModelB_Init }, // 既存エントリー
{ "via6522", VIA6522_Init }, // 新しいドライバー
{ NULL, NULL } // ターミネーター
};
CMakeLists.txt の変更
src/CMakeLists.txt に新しいソースファイルを追加してコンパイル定義で有効化します:
# src/CMakeLists.txt
target_sources(tzpuPico PRIVATE
...
drivers/BBC/ModelB.c # 既存
drivers/BBC/VIA6522.c # 新しいドライバー
)
target_compile_definitions(tzpuPico PRIVATE
INCLUDE_BBC_DRIVERS=1
)
ビルドとテスト
# プロジェクトルートから ./build_tzpuPico.sh # USB マスストレージ経由で書き込み cp build/bin/model/BaseM6502/BaseM6502_0x10020000.uf2 /media/$USER/RPI-RP2/ # または OTA: http://<device-ip>/ota-rp2350.htm 経由でアップロード
メモリフックパターン
6502 には I/O 空間がないため、すべてのフックパターンは
memioPtr[] を使用します。パターンは picoZ80 デベロッパーズガイド — メモリフックパターンで説明されているものと同じですが、I/O ポートハンドラーパターンが任意のアドレス範囲のメモリマップハンドラーに置き換えられています。6502 ドライバーの主要なパターンは:
FUNC ブロック — 仮想ペリフェラル
連続したアドレス範囲にハンドラーをインストールします。これはすべての 6502 ペリフェラルエミュレーションの標準パターンです:
// アドレス範囲 0xD000–0xD0FF(256 バイトペリフェラルブロック)にハンドラーをインストール
for(uint16_t addr = 0xD000; addr <= 0xD0FF; addr++)
{
cpu->_6502PSRAM->memioPtr[addr] = MyPeripheral_Handler;
}
RAM ライトインターセプト
PSRAM からのリードは許可しながら、RAM 領域へのライトをインターセプトします。ゼロページアクセスのシャドウイングや特定アドレスへのライト検出に有用です:
// ハンドラーはライトをインターセプト;リードは PSRAM に通す
static uint8_t ZeroPage_Intercept(M6502CPU *cpu, bool read, uint16_t addr, uint8_t data)
{
if(read)
{
// 通常通り PSRAM から読み取る
return cpu->_6502PSRAM->RAM[addr];
}
else
{
// PSRAM に書き込み、シャドウ状態を更新
cpu->_6502PSRAM->RAM[addr] = data;
MyDriver_OnZeroPageWrite(addr, data);
return 0;
}
}
// 初期化時:ブロックタイプを FUNC に設定してハンドラーをインストール
cpu->_membankPtr[0x0000 >> 9] = MEMBANK_ENCODE(MEMBANK_TYPE_FUNC, 0, 0x0000);
cpu->_6502PSRAM->memioPtr[0x0000] = ZeroPage_Intercept;
// ... 範囲内の各 512 バイトブロックに対して繰り返す
スパース/個別アドレス
より大きな領域内の特定のアドレスのみが重要なハードウェア(例:4 ビットアドレスデコーダー)では、それらの特定アドレスにのみハンドラーをインストールし、残りは
0xFF または PSRAM データを返すようにします:
// アドレス 0xFFFE と 0xFFFF(6502 リセットベクター)のみをインターセプト cpu->_6502PSRAM->memioPtr[0xFFFE] = ResetVector_Lo_Handler; cpu->_6502PSRAM->memioPtr[0xFFFF] = ResetVector_Hi_Handler;
BBC Model B ペルソナ(プレースホルダー)
pico6502 ファームウェアに現在含まれているドライバーは BBC Model B ペルソナのみです(
src/drivers/BBC/ModelB.c)。これはドライバー登録パターンを示す初期段階のプレースホルダーですが、BBC Micro の完全なハードウェアはまだ実装されていません — 6845 CRTC、6522 VIA、6850 ACIA、SAA5050 テレテキストチップ、ULA は仮想化されていません。
BBC Model B は pico6502 の最初のターゲットとして適切です。なぜなら、2MHz の標準 6502 を使用し、ハードウェアが十分に文書化されており、完全にメモリマップされたペリフェラルに依存しているためです。これは pico6502 の FUNC ベースのペリフェラルモデルと自然に一致します。ペルソナが完成するには、最低限以下を仮想化する必要があります:
| アドレス | 幅 | チップ | 機能 |
|---|---|---|---|
0xFC00–0xFCFF |
256B | 6845 CRTC | ビデオタイミング/メモリアドレスジェネレーター |
0xFE00–0xFE0F |
16B | 6522 VIA A | システム VIA(キーボード、サウンド、RTC) |
0xFE40–0xFE4F |
16B | 6522 VIA B | ユーザー VIA(パラレルポート、ユーザー I/O) |
0xFE60–0xFE6F |
16B | 6850 ACIA | シリアルインターフェース |
0xFC00–0xFCFF |
256B | SAA5050 / ULA | テレテキスト/ビデオ ULA |
0xFE30 |
1B | ROM セレクト | サイドウェイ ROM バンクセレクトレジスター |
コア 0 / コア 1 の相互作用
コア間キューパターンは picoZ80 と同一です。完全な説明とコード例については picoZ80 デベロッパーズガイド — コア 0 / コア 1 の相互作用を参照してください。唯一の名称の違いは、キューが
Z80CPU *cpu ではなく M6502CPU *cpu ポインター経由でアクセスされることです。
重要なルール:ハンドラーとポールコールバックはコア 1 で実行されます。ファイル I/O、ESP32 への UART コマンド、その他のブロッキング操作はすべて
cpu->requestQueue 経由でコア 0 に投稿しなければなりません。結果は cpu->responseQueue 経由で返され、task_ptr で処理されます。
よくある落とし穴
- memioPtr の代わりに ioPtr にハンドラーをインストールする。pico6502 には
ioPtr[]配列がありません。すべてのペリフェラルハンドラーはmemioPtr[]に入ります。ioPtr[]を使用しようとするとビルドエラーまたは未定義動作が発生します。 - I/O ディスパッチコールを期待する。
M6502CPU_readIO()もM6502CPU_writeIO()もありません。ioPtr[]を使用する Z80 ドライバーを移植する場合は、すべてのハンドラーを適切なメモリアドレスのmemioPtr[]に移動してください。 - ハンドラー内でブロックする。ハンドラー内から
debugf、sleep_ms、fopenを呼び出すと、コア 1 が停止して 6502 バスタイミングが破壊されます。すべてのブロッキング操作にはコア間キューを使用してください。 - virtualFuncMap の名前のミスマッチ。JSON の
"name"フィールドはM6502CPU.cのvirtualFuncMap[]テーブルと大文字小文字を区別せずにマッチングされます。どちらかにタイポがあると、ドライバーが静かにスキップされます。M6502CPU_getVirtualFunc()に一時的なdebugfを追加して診断してください。 - ハンドラー範囲のオフバイワン。
addr < endAddr + 1ではなくaddr <= endAddrを使用してください — 後者は0xFFFFで整数オーバーフローのリスクがあります。範囲がメモリの最上部まで延びる場合はuint32_tループ変数でaddr <= 0xFFFFを使用してください。 - ブロックタイプを FUNC に設定するのを忘れる。
memioPtr[]にハンドラーをインストールしても、対応する_membankPtr[]エントリーがまだMEMBANK_TYPE_RAMまたはMEMBANK_TYPE_ROMを示している場合は効果がありません。ハンドラー範囲内の各 512 バイトブロックに対して必ずMEMBANK_ENCODE(MEMBANK_TYPE_FUNC, ...)を呼び出してください。 - ドライバーシャットダウン時に reset_ptr をクリアしない。ドライバーが実行時に再設定され、リセットコールバックが無効になる場合は、再初期化の前に
cpu->reset_ptrをNULLにクリアしてください。そうしないと、コア 1 が次のリセット時に古い関数ポインターを呼び出してしまいます。
参考サイト
| リソース | リンク |
|---|---|
| pico6502 プロジェクトページ | /pico6502/ |
| pico6502 ユーザーマニュアル | /pico6502-usermanual/ |
| pico6502 テクニカルガイド | /pico6502-technicalguide/ |
| picoZ80 デベロッパーズガイド | /picoz80-developersguide/ |
| picoZ80 プロジェクトページ | /picoz80/ |
| RP2350 データシート | datasheets.raspberrypi.com |
| Pico SDK マルチコア API | raspberrypi.github.io/pico-sdk-doxygen |
| MOS 6502 データシート | archive.org |
| BBC Micro ハードウェアガイド | stardot.org.uk |
| cJSON ライブラリ | github.com/DaveGamble/cJSON |
無線規制に関する注意事項
本デバイスは 2.4 GHz ISM バンドで送信する ESP32-S3-PICO-1 無線モジュールを搭載しており、世界各国の無線周波数規制(米国の FCC Part 15 Subpart C、欧州連合の無線機器指令 2014/53/EU を含む)において意図的放射器に該当します。
ESP32-S3-PICO-1 モジュール自体は既存の規制認証(FCC、CE など)を取得していますが、そのモジュールレベルの認証は、モジュールを組み込んだ完成品に自動的に適用されるものではありません。事前認証モジュールの免除規定は、個人の趣味愛好家が個人使用、実験、または教育目的で少数のデバイスを製作する場合に、個別の機器認可を取得せずに行うことを許可するものです。
重要な制限事項
本設計に基づいて製作されたデバイスが、管轄区域内の適用されるすべての無線周波数規制に準拠することは、製作者の単独の責任です。著者は本設計を個人使用、教育、および趣味愛好家向けに提供しており、本設計から製作されたデバイスが商業的配布の規制要件を満たすことについて、いかなる表明も行いません。
- 組み立てられたデバイスは、完成品が独自にテストされ、該当する管轄区域で機器認可(例:FCC ID、認定機関による CE マーキング評価)を取得しない限り、第三者への販売、販売の申し出、贈与、またはその他の方法での配布を行ってはなりません。
- 個人使用のために少数を製作することは、趣味愛好家および実験使用の規定(例:FCC § 15.23)に基づき、デバイスが有害な干渉を引き起こさない限り、一般的に許可されています。
- 規制要件は国によって異なります。米国外の製作者は、適用される規則について自国の無線周波数当局に確認してください。
本設計に基づいて製作されたデバイスが、管轄区域内の適用されるすべての無線周波数規制に準拠することは、製作者の単独の責任です。著者は本設計を個人使用、教育、および趣味愛好家向けに提供しており、本設計から製作されたデバイスが商業的配布の規制要件を満たすことについて、いかなる表明も行いません。