-
Notifications
You must be signed in to change notification settings - Fork 0
cpu hardware implementation
Yukio Oobuchi edited this page Nov 5, 2025
·
1 revision
- 1. CPU実装アーキテクチャ
- 2. Z80系CPU実装
- 3. Intel x86系CPU実装
- 4. Motorola 68xx系CPU実装
- 5. 支援チップセット実装
- 6. グラフィックス・サウンドチップ
- 7. メモリ・I/O管理チップ
- 8. タイミング・同期システム
- 9. デバッグ・プロファイリング
| CPU系統 | 実装CPUモデル | ベース | 特徴・用途 |
|---|---|---|---|
| Z80系 | Z80, NSC800 | MAME 0.145 | 8bitマイコン、高精度タイミング |
| Intel x86系 | 8086/8088/80186/V30 | MAME i286 core | リアルモード16bit、PC互換機 |
| Intel 80x86 | 80286/80386/80486 | MAME/Neko Project | プロテクトモード対応 |
| Motorola 68xx | 6800/6809 | MAME 0.142 | 8bit、条件コード最適化 |
| MOS 6502 | 6502 | MAME | ファミコン等のゲーム機 |
| TI系 | TMS9995 | MAME | 16bitマイコン |
| NEC系 | uPD7801/7810 | MAME/PockEmul | 8bitマイコン |
| Hudson | HuC6280 | MESS | PC Engine専用 |
// 全CPU共通の基本インターフェース
class CPU_DEVICE : public DEVICE
{
public:
virtual int run(int clock) = 0; // クロック実行
virtual void reset() = 0; // リセット
virtual void set_intr_line(bool line, bool pending, uint32_t bit) = 0; // 割り込み
virtual uint32_t get_pc() = 0; // プログラムカウンタ取得
virtual void set_extra_clock(int clock); // 外部待機時間
virtual int get_extra_clock(); // 追加クロック取得
};- サイクル精度: 命令レベルでの正確なクロック計算
- 待機時間対応: メモリ・I/O待機時間の考慮
- DMA調停: CPU停止・バス権委譲の実装
- 割り込み遅延: 実際のハードウェア遅延の再現
src/vm/z80.h:29 で定義されるZ80クラスは、MAME 0.145をベースとした高精度実装です。
// Z80レジスタセット (src/vm/z80.h:63-74)
pair32_t pc, sp, af, bc, de, hl, ix, iy, wz; // メインレジスタ
pair32_t af2, bc2, de2, hl2; // シャドウレジスタ
uint8_t I, R, R2; // 割り込みベクタ・リフレッシュレジスタ
uint32_t ea; // 実効アドレス
// 制御レジスタ
uint8_t im, iff1, iff2, icr; // 割り込みモード・フラグ
bool after_di, after_ei, prev_after_ei; // 割り込み制御状態
bool after_ldair; // LD A,I/R後のフラグ制御
uint32_t intr_req_bit, intr_pend_bit; // 割り込み要求・保留ビット// バス接続デバイス (src/vm/z80.h:36-46)
DEVICE *d_mem, *d_io, *d_pic; // メモリ・I/O・割り込みコントローラー
#ifdef Z80_PSEUDO_BIOS
DEVICE *d_bios; // 擬似BIOS (高速化用)
#endif
#ifdef SINGLE_MODE_DMA
DEVICE *d_dma; // DMAコントローラー
#endif
#ifdef USE_DEBUGGER
DEBUGGER *d_debugger; // デバッガインターフェース
DEVICE *d_mem_stored, *d_io_stored; // デバッグ時の元デバイス保存
#endif// 命令フェッチ・実行のプライベートメソッド (src/vm/z80.h:75-106)
inline uint8_t FETCHOP(); // オペコードフェッチ
inline uint8_t FETCH8(); // 8bitデータフェッチ
inline uint32_t FETCH16(); // 16bitデータフェッチ
inline uint8_t IN8(uint32_t addr); // I/Oポート入力
inline void OUT8(uint32_t addr, uint8_t val); // I/Oポート出力
// 算術論理演算
inline uint8_t INC(uint8_t value); // インクリメント
inline uint8_t DEC(uint8_t value); // デクリメント
// ビット操作・シフト
inline uint8_t RLC(uint8_t value); // 左回転シフト
inline uint8_t RRC(uint8_t value); // 右回転シフト
inline uint8_t RL(uint8_t value); // 左シフト(キャリー経由)
inline uint8_t RR(uint8_t value); // 右シフト(キャリー経由)
inline uint8_t SLA(uint8_t value); // 算術左シフト
inline uint8_t SRA(uint8_t value); // 算術右シフト
inline uint8_t SRL(uint8_t value); // 論理右シフト
// プリフィックス命令処理
void OP_CB(uint8_t code); // CBプリフィックス(ビット操作)
void OP_ED(uint8_t code); // EDプリフィックス(拡張命令)
void OP_DD(uint8_t code); // DDプリフィックス(IX命令)
void OP_FD(uint8_t code); // FDプリフィックス(IY命令)// 割り込み制御 (src/vm/z80.h:139-144)
void set_intr_line(bool line, bool pending, uint32_t bit)
{
uint32_t mask = 1 << bit;
intr_req_bit = line ? (intr_req_bit | mask) : (intr_req_bit & ~mask);
intr_pend_bit = pending ? (intr_pend_bit | mask) : (intr_pend_bit & ~mask);
}
void check_interrupt()
{
if(iff1 && (intr_req_bit & ~intr_pend_bit)) {
switch(im) {
case 0: // 割り込みモード0 (外部デバイスが命令供給)
break;
case 1: // 割り込みモード1 (RST 38h)
break;
case 2: // 割り込みモード2 (ベクタ割り込み)
break;
}
}
}// NSC800固有シグナル (src/vm/z80.h:18-23)
#ifdef HAS_NSC800
#define SIG_NSC800_INT 0 // 割り込み入力
#define SIG_NSC800_RSTA 1 // リスタートA
#define SIG_NSC800_RSTB 2 // リスタートB
#define SIG_NSC800_RSTC 3 // リスタートC
#endifNSC800の特徴:
- Intel 8085互換: 8085の上位互換としてのZ80
- 追加割り込み: RST5.5/6.5/7.5相当の割り込み
- SOD/SID: シリアルI/O機能
src/vm/i86.h:31 で定義されるI86クラスは、MAME i286 coreベースの実装です。
// サポートCPU種別 (src/vm/i86.h:24-29)
enum {
INTEL_8086 = 0, // 16bit CPU、16bitバス
INTEL_8088, // 16bit CPU、8bitバス
INTEL_80186, // 8086 + 内蔵周辺回路
NEC_V30, // NEC版8086互換、マイクロコード強化
};// i86系CPU接続デバイス (src/vm/i86.h:34-43)
DEVICE *d_mem, *d_io, *d_pic; // 基本バス接続
#ifdef I86_PSEUDO_BIOS
DEVICE *d_bios; // 擬似BIOS実装
#endif
#ifdef SINGLE_MODE_DMA
DEVICE *d_dma; // DMAコントローラー
#endif
void *opaque; // MAME内部状態へのポインタ// デバッガ機能 (src/vm/i86.h:69-100)
#ifdef USE_DEBUGGER
bool is_cpu() { return true; }
bool is_debugger_available() { return true; }
// アドレス空間マスク
uint32_t get_debug_prog_addr_mask() { return 0xfffff; } // 1MB
uint32_t get_debug_data_addr_mask() { return 0xfffff; } // 1MB
// デバッグ用メモリアクセス
void write_debug_data8/16(uint32_t addr, uint32_t data);
uint32_t read_debug_data8/16(uint32_t addr);
void write_debug_io8/16(uint32_t addr, uint32_t data);
uint32_t read_debug_io8/16(uint32_t addr);
// レジスタアクセス
bool write_debug_reg(const _TCHAR *reg, uint32_t data);
uint32_t read_debug_reg(const _TCHAR *reg);
bool get_debug_regs_info(_TCHAR *buffer, size_t buffer_len);
#endif高度なx86実装は src/vm/mame/emu/cpu/i386/ に配置され、MAMEの成熟したコアを使用しています。
- セグメンテーション: GDT/LDT/IDT管理
- ページング: 仮想メモリ管理 (i386以降)
- タスク切り替え: TSS (Task State Segment)
- 権限レベル: Ring 0-3 プロテクション
// NP21/W i386実装 (推定構造)
class I386_NP21 : public DEVICE
{
private:
void *np21_context; // NP21内部コンテキスト
public:
// NP21固有の最適化実装
void initialize_np21_core();
void sync_with_np21_timing();
};src/vm/mc6809.h:33 で定義されるMC6809クラスは、MAME 0.142ベースでArtane.氏による改良が加えられています。
// 実行フェーズ定義 (src/vm/mc6809.h:23-31)
enum {
MC6809_PHASE_RUN = 0, // 通常実行
MC6809_PHASE_PUSH_STACK, // スタックプッシュ
MC6809_PHASE_FETCH_VECTOR, // ベクタフェッチ
MC6809_PHASE_DEAD_CYCLE, // デッドサイクル
MC6809_PHASE_REQ_HALT, // 停止要求
MC6809_PHASE_DO_HALT, // 停止実行
};// フラグ計算テーブル (src/vm/mc6809.h:35-52)
// インクリメント用フラグテーブル
const uint8_t flags8i[256] = {
CC_Z, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ...
// 0x80でCC_N | CC_V (負数オーバーフロー)
CC_N | CC_V, CC_N, CC_N, CC_N, ...
};
// デクリメント用フラグテーブル
const uint8_t flags8d[256] = {
CC_Z, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ...
// 0x7FでCC_V (正数オーバーフロー)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, CC_V,
CC_N, CC_N, CC_N, CC_N, ...
};// インデックスサイクル数テーブル (src/vm/mc6809.h:75-80)
const int index_cycle_em[256] = {
// 0x0X - 0x1X: 定数オフセット(1サイクル)
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
// より複雑なアドレッシングモードは多サイクル
};MC6800は6809の前身で、より単純な8bitアーキテクチャです。
主要特徴:
- 累積器A/B: 8bit×2個の累積器
- インデックスレジスタX: 16bit
- 条件コードレジスタ: N,Z,V,C,H,I フラグ
- スタックポインタS: 16bit
class I8259 : public DEVICE
{
private:
uint8_t imr; // 割り込みマスクレジスタ
uint8_t irr; // 割り込み要求レジスタ
uint8_t isr; // 割り込みサービスレジスタ
uint8_t icw[4]; // 初期化コマンドワード
uint8_t ocw[4]; // 動作コマンドワード
bool ltim; // レベル/エッジトリガー
bool aeoi; // 自動EOI
bool nested; // ネストモード
bool rotate; // 回転優先度
public:
void write_io8(uint32_t addr, uint32_t data) override;
uint32_t read_io8(uint32_t addr) override;
void write_signal(int id, uint32_t data, uint32_t mask) override;
};// マスター/スレーブ構成
class I8259_MASTER : public I8259
{
private:
I8259* slave_pics[8]; // 最大8個のスレーブPIC
public:
void connect_slave(int irq, I8259* slave)
{
slave_pics[irq] = slave;
slave->set_master(this);
}
};class I8253 : public DEVICE
{
private:
struct channel_t {
uint16_t count; // カウント値
uint16_t latch; // ラッチ値
uint8_t mode; // 動作モード
bool gate; // ゲート入力
bool out; // 出力状態
bool bcd; // BCD/バイナリモード
// リード/ライト制御
uint8_t rw_mode; // R/Wモード
bool first_write; // 最初の書き込み
bool latch_enable; // ラッチ有効
} channels[3];
public:
void write_io8(uint32_t addr, uint32_t data) override;
uint32_t read_io8(uint32_t addr) override;
void update_timing();
};- モード0: 割り込み時カウント
- モード1: ハードウェア再トリガー単発
- モード2: レート発生器
- モード3: 方形波発生器
- モード4: ソフトウェアトリガー単発
- モード5: ハードウェアトリガー単発
class I8255 : public DEVICE
{
private:
uint8_t port[3]; // ポートA/B/C
uint8_t control; // 制御レジスタ
// モード設定
bool mode_a; // ポートAモード(0/1)
bool mode_b; // ポートBモード(0/1)
uint8_t dir_a, dir_b; // 方向設定
uint8_t dir_c_upper, dir_c_lower; // ポートC上位/下位方向
public:
void write_io8(uint32_t addr, uint32_t data) override;
uint32_t read_io8(uint32_t addr) override;
// ポートC個別ビット制御
void set_bit(int bit, bool value);
bool get_bit(int bit);
};- モード0: 基本入出力
- モード1: ストローブ入出力
- モード2: 双方向バス
class TMS9918A : public DEVICE
{
private:
uint8_t vram[16384]; // ビデオRAM 16KB
uint8_t regs[8]; // VDPレジスタ
// 描画関連
uint8_t color_table[32]; // カラーテーブル
uint8_t pattern_table[2048]; // パターンテーブル
uint8_t sprite_table[128]; // スプライトテーブル
// 制御状態
bool first_byte; // 最初のバイト
uint16_t addr_reg; // アドレスレジスタ
uint8_t status_reg; // ステータスレジスタ
public:
void write_io8(uint32_t addr, uint32_t data) override;
uint32_t read_io8(uint32_t addr) override;
void update_screen();
void draw_screen();
};class V9938 : public DEVICE
{
private:
uint8_t vram[131072]; // ビデオRAM 128KB
uint8_t regs[64]; // 拡張レジスタセット
// 高機能描画
struct {
uint16_t sx, sy, dx, dy, nx, ny; // VDP座標
uint8_t clr, arg, cmd; // VDPコマンド
bool ce, bd, tr; // 制御フラグ
} command;
public:
void execute_command(); // VDPコマンド実行
void draw_graphic4(); // SCREEN4描画
void draw_graphic5(); // SCREEN5描画
void draw_graphic6(); // SCREEN6描画
void draw_graphic7(); // SCREEN7描画
};class SN76489AN : public DEVICE
{
private:
struct channel_t {
uint16_t freq; // 周波数設定
uint8_t volume; // 音量
uint16_t counter; // カウンター
bool output; // 出力状態
} channels[4]; // 3音 + ノイズ
uint8_t noise_feedback; // ノイズフィードバック
uint16_t noise_shift; // ノイズシフトレジスタ
public:
void write_io8(uint32_t addr, uint32_t data) override;
void mix_audio(int32_t* buffer, int samples);
};class MSM5205 : public DEVICE
{
private:
int32_t signal, step; // ADPCM状態
uint8_t vclk; // VCLKレート
bool reset_signal; // リセット信号
bool vck, busy; // 制御信号
// ADPCM展開テーブル
static const int diff_table[49];
static const int step_table[16];
public:
void write_signal(int id, uint32_t data, uint32_t mask) override;
void update_adpcm();
int16_t decode_sample(uint8_t nibble);
};// fmgen統合クラス (推定実装)
class FMGEN_OPN : public DEVICE
{
private:
void* fmgen_chip; // fmgenチップインスタンス
public:
void write_io8(uint32_t addr, uint32_t data) override
{
// fmgenライブラリ呼び出し
fmgen_chip_write(fmgen_chip, addr, data);
}
void mix_audio(int32_t* buffer, int samples)
{
// fmgenミキシング
fmgen_chip_mix(fmgen_chip, buffer, samples);
}
};fmgen統合の利点:
- 高品質: 実機と遜色ない音質
- 豊富な対応: YM2203/YM2608/YM2610等
- 最適化: x86アセンブラレベル最適化
- 実績: M88等での長期実用実績
class UPD765A : public DEVICE
{
private:
enum {
PHASE_IDLE, // 待機状態
PHASE_COMMAND, // コマンド受信
PHASE_EXECUTION, // 実行
PHASE_RESULT, // 結果送信
} phase;
uint8_t command[9]; // コマンドバッファ
uint8_t result[7]; // 結果バッファ
int cmd_ptr, res_ptr; // ポインタ
// ドライブ状態
struct drive_t {
bool ready; // レディ状態
bool motor; // モーター状態
int track; // 現在トラック
int sector; // 現在セクタ
bool write_protected; // 書き込み保護
} drives[4];
public:
void write_io8(uint32_t addr, uint32_t data) override;
uint32_t read_io8(uint32_t addr) override;
void write_signal(int id, uint32_t data, uint32_t mask) override;
private:
void process_command();
void seek_command();
void read_data_command();
void write_data_command();
void format_command();
};特徴:
- 高精度タイミング: 実機相当のシーク・回転待ち時間
- 豊富なコマンド: READ/WRITE/FORMAT/SEEK/RECALIBRATE等
- エラー処理: CRC・セクタ不良・書き込み保護等の完全対応
- DMA連携: DMAコントローラーとの協調動作
class UPD71071 : public DEVICE
{
private:
struct channel_t {
uint32_t base_addr; // ベースアドレス
uint32_t base_count; // ベースカウント
uint32_t addr; // 現在アドレス
uint32_t count; // 現在カウント
uint8_t mode; // 転送モード
bool addr_dec; // アドレス減算
bool auto_init; // オートイニシャライズ
bool single_mode; // シングル転送
bool request; // 転送要求
bool mask; // マスク状態
} channels[4];
uint8_t command; // コマンドレジスタ
uint8_t status; // ステータスレジスタ
bool controller_disable; // コントローラー無効
public:
void write_io8(uint32_t addr, uint32_t data) override;
uint32_t read_io8(uint32_t addr) override;
void write_signal(int id, uint32_t data, uint32_t mask) override;
void do_dma_transfer(int channel);
bool is_dma_running();
};改良点:
- 高速転送: 最適化された転送ルーチン
- 拡張モード: オリジナル以上の機能
- デバッグ機能: 転送状況の詳細表示
class SCSI_HOST : public DEVICE
{
private:
enum {
SCSI_PHASE_BUS_FREE,
SCSI_PHASE_ARBITRATION,
SCSI_PHASE_SELECTION,
SCSI_PHASE_COMMAND,
SCSI_PHASE_DATA_IN,
SCSI_PHASE_DATA_OUT,
SCSI_PHASE_STATUS,
SCSI_PHASE_MESSAGE_IN,
SCSI_PHASE_MESSAGE_OUT,
} phase;
uint8_t scsi_bus; // SCSIバス状態
bool bsy, sel, cd, io, msg, req, ack, atn, rst; // SCSI信号
DEVICE* devices[8]; // 接続デバイス
public:
void write_signal(int id, uint32_t data, uint32_t mask) override;
uint32_t read_signal(int id) override;
void arbitration_phase();
void selection_phase();
void command_phase();
void data_phase();
void status_phase();
void message_phase();
};実装のポイント:
- 非同期転送: REQ/ACKハンドシェイク
- タイムアウト処理: バス占有時間管理
- エラー処理: パリティ・フェーズエラー等
- デバイス検出: SELECT時のID応答
class MULTI_CPU_MANAGER
{
private:
struct cpu_context_t {
DEVICE* cpu;
uint64_t base_clock; // ベースクロック周波数
uint64_t executed_clock; // 実行済みクロック
int remaining_clock; // 残りクロック
bool halted; // 停止状態
};
cpu_context_t cpus[MAX_CPU_COUNT];
int cpu_count;
uint64_t sync_clock; // 同期基準クロック
public:
void register_cpu(DEVICE* cpu, uint64_t base_clock);
void sync_all_cpus();
void execute_slice(int slice_clock);
};void MULTI_CPU_MANAGER::sync_all_cpus()
{
// 最も進んだCPUを基準とする
uint64_t max_clock = 0;
for(int i = 0; i < cpu_count; i++) {
if(cpus[i].executed_clock > max_clock) {
max_clock = cpus[i].executed_clock;
}
}
// 遅れているCPUを追いつかせる
for(int i = 0; i < cpu_count; i++) {
if(cpus[i].executed_clock < max_clock) {
uint64_t catch_up = max_clock - cpus[i].executed_clock;
cpus[i].remaining_clock += (int)catch_up;
cpus[i].executed_clock = max_clock;
}
}
}class WAIT_STATE_MANAGER
{
private:
struct wait_region_t {
uint32_t start_addr;
uint32_t end_addr;
int wait_clock;
bool enabled;
};
wait_region_t regions[MAX_WAIT_REGIONS];
int region_count;
public:
void add_wait_region(uint32_t start, uint32_t end, int wait);
int get_wait_clock(uint32_t addr);
void enable_region(int index, bool enable);
};
// CPU実装での使用例
int Z80::memory_access_wait(uint32_t addr)
{
return wait_manager->get_wait_clock(addr);
}class EVENT_SCHEDULER
{
private:
struct event_t {
DEVICE* device;
int event_id;
uint64_t trigger_clock;
bool periodic;
uint64_t period;
event_t* next;
};
event_t* event_queue;
uint64_t current_clock;
public:
void register_event(DEVICE* device, int id, uint64_t delay, bool loop = false, uint64_t period = 0);
void cancel_event(DEVICE* device, int id);
void process_events();
void advance_clock(uint64_t delta);
};class DEBUGGER
{
private:
DEVICE* target_cpu;
bool enabled;
// ブレークポイント
struct breakpoint_t {
uint32_t addr;
bool enabled;
int hit_count;
_TCHAR condition[256];
};
breakpoint_t breakpoints[MAX_BREAKPOINTS];
// 実行状態
bool single_step;
bool step_over;
uint32_t step_over_return_addr;
public:
void set_breakpoint(uint32_t addr, const _TCHAR* condition = NULL);
void clear_breakpoint(uint32_t addr);
void single_step_execute();
void step_over_execute();
void continue_execute();
bool check_breakpoint(uint32_t addr);
void update_registers();
void dump_memory(uint32_t start, uint32_t length);
};// Z80デバッガ実装例
class Z80_DEBUGGER : public DEBUGGER
{
public:
void show_registers() override
{
Z80* cpu = (Z80*)target_cpu;
_tprintf(_T("PC=%04X SP=%04X AF=%04X BC=%04X DE=%04X HL=%04X\n"),
cpu->get_pc(), cpu->get_sp(),
cpu->get_af(), cpu->get_bc(), cpu->get_de(), cpu->get_hl());
_tprintf(_T("IX=%04X IY=%04X I=%02X R=%02X IM=%d IFF1=%d IFF2=%d\n"),
cpu->get_ix(), cpu->get_iy(), cpu->get_i(), cpu->get_r(),
cpu->get_im(), cpu->get_iff1(), cpu->get_iff2());
}
void disassemble(uint32_t addr, int count) override
{
for(int i = 0; i < count; i++) {
_TCHAR mnemonics[256];
int length = disassemble_z80(addr, mnemonics);
_tprintf(_T("%04X: %s\n"), addr, mnemonics);
addr += length;
}
}
};class PERFORMANCE_PROFILER
{
private:
struct instruction_profile_t {
uint32_t opcode;
uint64_t execute_count;
uint64_t total_cycles;
uint32_t min_cycles, max_cycles;
};
instruction_profile_t profiles[256]; // 256種類の命令
uint64_t total_instructions;
uint64_t total_cycles;
public:
void record_instruction(uint32_t opcode, int cycles);
void show_profile();
void reset_profile();
// ホットスポット検出
void find_hotspots(int top_count = 10);
};class MEMORY_ACCESS_ANALYZER
{
private:
struct access_info_t {
uint32_t addr;
uint32_t access_count;
bool read, write;
uint64_t first_access;
uint64_t last_access;
};
std::map<uint32_t, access_info_t> access_map;
public:
void record_access(uint32_t addr, bool is_write);
void analyze_patterns();
void detect_memory_leaks();
void show_access_statistics();
};このCPU・ハードウェア実装は、MAME/MESS等の実績あるエミュレーションコアをベースとしながら、レトロPC固有の要求に対応した高度な実装となっています。
主要な技術的特徴:
- マルチCPU対応: 異なるアーキテクチャの統一管理
- 精密タイミング: サイクル単位の正確なシミュレーション
- デバイス統合: チップセット間の協調動作
- デバッグ支援: 強力な解析・診断機能
- 最適化: 実用的な実行速度の確保
各CPUとハードウェアコンポーネントは、オリジナルハードウェアの動作を可能な限り正確に再現しながら、現代的なデバッグ・解析機能を提供しています。
文書作成日: 2024年11月5日 対象コード: Common Source Code Project Mirror 文書バージョン: 1.0