pico6502 デベロッパーズガイド

English

注記: 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_ptrpoll_ptrtask_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_addrm6502_data アドレスバス(A0–A15)、データバス(D0–D7)
PIO 1 m6502_cyclem6502_fetchm6502_readm6502_writem6502_irqm6502_nmim6502_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_busrq SM に相当するものはありません。
  • 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" フィールドがドライバー初期化関数にどのようにマッチングされるか。
  • VirtualFunc typedef と M6502CPU_getVirtualFunc() ルックアップ。
  • 二フェーズ初期化フロー(検証パスから設定パスへ)。
  • ドライバーライフサイクルコールバック:reset_ptrpoll_ptrtask_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 バスサイクルで:
  1. IRQ 0 を待つ(PHI1 でアドレス有効)。
  2. PIO 0 RX FIFO から 16 ビットアドレスを読み取る。
  3. _membankPtr[addr >> 9] を参照してブロックタイプ、バンク、ベースを取得する。
  4. 制御 PIO から RNW(リード/ノットライト)を判定する。
  5. ブロックタイプによってディスパッチ:PHYSICAL(ホストへパス)、RAM(PSRAM 読み書き)、ROM(PSRAM 読み取りのみ)、FUNC(memioPtr[addr] を呼び出す)、PTR(memPtr[addr] 経由でリダイレクト)。
  6. リードの場合:PIO 0 TX FIFO 経由でデータバスに結果を置く。IRQ 1 を待つ(データフェーズ)。ライトの場合:IRQ 1 の後に PIO 0 RX FIFO からデータを読み取る。
  7. 登録された各ドライバーの 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 つのステップは同じです:
  1. src/include/drivers/<Family>/MyDriver.h にヘッダーファイルを作成
  2. src/drivers/<Family>/MyDriver.c に実装ファイルを作成
  3. ソースファイルを src/CMakeLists.txt に追加
  4. #ifdef INCLUDE_<FAMILY>_DRIVERS ガードの下で M6502CPU.c にドライバーをインクルード
  5. M6502CPU.cvirtualFuncMap[] にドライバーを登録
  6. 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.cvirtualFuncMap[] テーブルにエントリーを追加します。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[] に移動してください。
  • ハンドラー内でブロックする。ハンドラー内から debugfsleep_msfopen を呼び出すと、コア 1 が停止して 6502 バスタイミングが破壊されます。すべてのブロッキング操作にはコア間キューを使用してください。
  • virtualFuncMap の名前のミスマッチ。JSON の "name" フィールドは M6502CPU.cvirtualFuncMap[] テーブルと大文字小文字を区別せずにマッチングされます。どちらかにタイポがあると、ドライバーが静かにスキップされます。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_ptrNULL にクリアしてください。そうしないと、コア 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)に基づき、デバイスが有害な干渉を引き起こさない限り、一般的に許可されています。
  • 規制要件は国によって異なります。米国外の製作者は、適用される規則について自国の無線周波数当局に確認してください。
製作者の責任
本設計に基づいて製作されたデバイスが、管轄区域内の適用されるすべての無線周波数規制に準拠することは、製作者の単独の責任です。著者は本設計を個人使用、教育、および趣味愛好家向けに提供しており、本設計から製作されたデバイスが商業的配布の規制要件を満たすことについて、いかなる表明も行いません。