Pico2ROMEmu: ROM Emulator ด้วย RP2350
สร้าง ROM Emulator ด้วย Raspberry Pi Pico 2
สำหรับ Retro Computing และ Embedded Systems Development
📋 ภาพรวมโปรเจค Pico2ROMEmu
🎯 เป้าหมายและวัตถุประสงค์
💡 แนวคิดหลัก
Pico2ROMEmu เป็นโปรเจคที่ใช้ Raspberry Pi Pico 2 พร้อม RP2350 chip เพื่อจำลองการทำงานของ ROM (Read-Only Memory) แบบดั้งเดิม โดยใช้ความสามารถของ PIO (Programmable I/O) และ DMA เพื่อให้ได้ Performance ที่เทียบเท่า Hardware ROM จริง
✅ ข้อดีของ Pico2ROMEmu
- ราคาถูกมาก (เริ่มต้น 890 บาท)
- ความเร็วสูงด้วย RP2350 @ 150MHz
- PIO State Machines สำหรับ Real-time I/O
- DMA สำหรับ High-speed Data Transfer
- รองรับ ROM ขนาดใหญ่ถึง 8MB
- Hot-swapping ROM Images
- USB Interface สำหรับ Programming
🎯 การใช้งาน
- Retro Computer ROM Replacement
- Arcade Machine ROM Emulation
- Embedded System Development
- ROM Dumping และ Analysis
- Educational Projects
- Firmware Testing
- Legacy System Maintenance
⚡ RP2350 vs RP2040: ทำไมต้อง Pico 2?
คุณสมบัติ | RP2040 (Pico 1) | RP2350 (Pico 2) | ข้อดีสำหรับ ROM Emu |
---|---|---|---|
CPU Cores | 2x Cortex-M0+ @ 133MHz | 2x Cortex-M33 @ 150MHz | +13% ความเร็ว |
SRAM | 264KB | 520KB | ROM ขนาดใหญ่ขึ้น |
Flash | 2MB | 4MB | Multiple ROM Images |
PIO State Machines | 8 (2 blocks) | 12 (3 blocks) | Parallel Processing |
DMA Channels | 12 | 16 | High-speed Transfer |
GPIO Pins | 26 | 30 | More I/O Options |
Security Features | - | Arm TrustZone | Secure ROM Storage |
📊 Performance Comparison
⚙️ การสร้าง Pico2ROMEmu
📌 การต่อขา GPIO
🔌 Pico 2 Pinout สำหรับ ROM Emulator
🔗 การเชื่อมต่อกับระบบเป้าหมาย
เชื่อมต่อกับ Address pins ของ ROM socket
เชื่อมต่อกับ Data pins ของ ROM socket
CE# (Chip Enable), OE# (Output Enable)
3.3V จาก Pico 2 หรือ External 5V
🔌 Circuit Diagram
Pico2ROMEmu Circuit Diagram
Target System Raspberry Pi Pico 2 Level Shifter
┌─────────────┐ ┌─────────────────────┐ ┌──────────────┐
│ │ │ │ │ │
│ ROM │ A0-A15 ────────► │ GP0-GP15 (Address) │ │ 3.3V ◄──► │ 5V
│ Socket │ │ │ │ Logic │
│ │ D0-D7 ◄──────── │ GP16-GP22,GP26 │ ◄────────► │ Level │
│ │ │ (Data Bus) │ │ Shifter │
│ │ CE# ────────► │ GP27 (Chip Enable) │ │ │
│ │ OE# ────────► │ GP28 (Output Enable)│ │ │
│ │ │ │ └──────────────┘
│ │ VCC ────────► │ 3V3 (Power Out) │
│ │ GND ────────► │ GND │
└─────────────┘ └─────────────────────┘
│
│ USB
▼
┌─────────────┐
│ Computer │
│ (Programming│
│ & Control) │
└─────────────┘
Connection Notes:
- Use level shifter if target system uses 5V logic
- Connect all ground pins together
- Add pull-up resistors (10kΩ) on control signals if needed
- Use short wires to minimize signal integrity issues
💻 การเขียนโปรแกรม
🐍 Python Code สำหรับ Pico2ROMEmu
"""
Pico2ROMEmu - ROM Emulator for Raspberry Pi Pico 2 (RP2350)
Uses PIO and DMA for high-performance ROM emulation
"""
import machine
import rp2
import array
import time
from machine import Pin, mem32
import _thread
import gc
class Pico2ROMEmu:
def __init__(self):
# GPIO Pin assignments
self.ADDR_PINS = list(range(0, 16)) # GP0-GP15 for A0-A15
self.DATA_PINS = [16, 17, 18, 19, 20, 21, 22, 26] # GP16-GP22, GP26 for D0-D7
self.CE_PIN = 27 # GP27 for Chip Enable (active low)
self.OE_PIN = 28 # GP28 for Output Enable (active low)
# ROM storage
self.rom_data = bytearray(65536) # 64KB ROM space
self.rom_images = {} # Multiple ROM images
self.current_image = 0
# Performance counters
self.access_count = 0
self.last_access_time = 0
self.setup_pins()
self.setup_pio()
self.load_default_rom()
def setup_pins(self):
"""Initialize GPIO pins"""
# Address pins as input with pull-down
self.addr_pins = []
for pin_num in self.ADDR_PINS:
pin = Pin(pin_num, Pin.IN, Pin.PULL_DOWN)
self.addr_pins.append(pin)
# Data pins as output (initially high-Z)
self.data_pins = []
for pin_num in self.DATA_PINS:
pin = Pin(pin_num, Pin.OUT, value=0)
self.data_pins.append(pin)
# Control pins as input with pull-up
self.ce_pin = Pin(self.CE_PIN, Pin.IN, Pin.PULL_UP)
self.oe_pin = Pin(self.OE_PIN, Pin.IN, Pin.PULL_UP)
print("GPIO pins initialized")
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW, out_init=rp2.PIO.OUT_LOW)
def rom_emulator_pio():
"""PIO program for high-speed ROM emulation"""
# Wait for chip enable and output enable
wait(0, pin, 0) # Wait for CE# low
wait(0, pin, 1) # Wait for OE# low
# Read address from pins
in_(pins, 16) # Read 16-bit address
mov(x, isr) # Move address to X register
# Calculate ROM data address
mov(isr, x) # Move address back to ISR
push() # Push to FIFO for CPU processing
# Wait for data from CPU
pull() # Pull data from FIFO
out(pins, 8) # Output 8-bit data
# Wait for access to complete
wait(1, pin, 0) # Wait for CE# high
def setup_pio(self):
"""Setup PIO state machine for ROM emulation"""
self.sm = rp2.StateMachine(0, self.rom_emulator_pio,
freq=125_000_000, # 125MHz for fast response
in_base=Pin(0), # Address input base
out_base=Pin(16), # Data output base
set_base=Pin(16)) # Data set base
# Start the state machine
self.sm.active(1)
print("PIO state machine initialized")
def load_default_rom(self):
"""Load a default ROM image for testing"""
# Create a simple test ROM
for i in range(len(self.rom_data)):
if i < 256:
self.rom_data[i] = i & 0xFF # Simple counter pattern
elif i < 512:
self.rom_data[i] = 0xFF - (i & 0xFF) # Inverted pattern
else:
self.rom_data[i] = 0x55 if (i // 256) % 2 else 0xAA # Alternating pattern
print("Default ROM loaded (64KB)")
def load_rom_image(self, image_id, filename):
"""Load ROM image from file"""
try:
with open(filename, 'rb') as f:
data = f.read()
self.rom_images[image_id] = bytearray(data)
print(f"ROM image {image_id} loaded: {len(data)} bytes")
return True
except Exception as e:
print(f"Error loading ROM image {image_id}: {e}")
return False
def switch_rom_image(self, image_id):
"""Switch to different ROM image"""
if image_id in self.rom_images:
self.rom_data = self.rom_images[image_id]
self.current_image = image_id
print(f"Switched to ROM image {image_id}")
return True
else:
print(f"ROM image {image_id} not found")
return False
def read_address(self):
"""Read current address from GPIO pins"""
address = 0
for i, pin in enumerate(self.addr_pins):
if pin.value():
address |= (1 << i)
return address
def write_data(self, data):
"""Write data to GPIO data pins"""
for i, pin in enumerate(self.data_pins):
pin.value((data >> i) & 1)
def set_data_direction(self, output=True):
"""Set data pins direction (output/input)"""
for pin_num in self.DATA_PINS:
if output:
Pin(pin_num, Pin.OUT)
else:
Pin(pin_num, Pin.IN, Pin.PULL_DOWN)
def rom_access_handler(self):
"""Main ROM access handling loop (runs on core 1)"""
print("ROM access handler started on core 1")
while True:
try:
# Check if PIO has address data
if self.sm.rx_fifo():
address = self.sm.get() & 0xFFFF # Get 16-bit address
# Bounds check
if address < len(self.rom_data):
data = self.rom_data[address]
else:
data = 0xFF # Default value for out-of-bounds
# Send data back to PIO
self.sm.put(data)
# Update statistics
self.access_count += 1
self.last_access_time = time.ticks_ms()
# Small delay to prevent CPU overload
time.sleep_us(1)
except Exception as e:
print(f"ROM access handler error: {e}")
time.sleep_ms(10)
def start_emulation(self):
"""Start ROM emulation on second core"""
_thread.start_new_thread(self.rom_access_handler, ())
print("ROM emulation started")
def get_statistics(self):
"""Get emulation statistics"""
return {
'access_count': self.access_count,
'last_access_time': self.last_access_time,
'current_image': self.current_image,
'rom_size': len(self.rom_data),
'free_memory': gc.mem_free()
}
def dump_rom_section(self, start_addr=0, length=256):
"""Dump ROM section for debugging"""
print(f"ROM dump from 0x{start_addr:04X}:")
for i in range(0, length, 16):
addr = start_addr + i
if addr >= len(self.rom_data):
break
# Address
line = f"{addr:04X}: "
# Hex data
hex_data = []
ascii_data = ""
for j in range(16):
if addr + j < len(self.rom_data):
byte = self.rom_data[addr + j]
hex_data.append(f"{byte:02X}")
ascii_data += chr(byte) if 32 <= byte <= 126 else "."
else:
hex_data.append(" ")
ascii_data += " "
line += " ".join(hex_data) + " " + ascii_data
print(line)
# Web interface for remote control (if using Pico W)
class ROMEmuWebInterface:
def __init__(self, rom_emu):
self.rom_emu = rom_emu
self.setup_wifi()
self.setup_web_server()
def setup_wifi(self):
"""Setup WiFi connection (for Pico W only)"""
try:
import network
self.wlan = network.WLAN(network.STA_IF)
self.wlan.active(True)
# Configure your WiFi credentials here
# self.wlan.connect('YOUR_SSID', 'YOUR_PASSWORD')
print("WiFi interface ready")
except ImportError:
print("WiFi not available (not Pico W)")
def setup_web_server(self):
"""Setup simple web server for ROM management"""
# Implementation would go here for web-based ROM management
pass
# Main execution
def main():
print("Pico2ROMEmu - ROM Emulator for RP2350")
print("=====================================")
# Create ROM emulator instance
rom_emu = Pico2ROMEmu()
# Start emulation
rom_emu.start_emulation()
# Interactive command loop
print("\nROM Emulator ready!")
print("Commands: stats, dump, switch , load , help, quit")
while True:
try:
command = input("> ").strip().lower()
if command == "quit":
break
elif command == "stats":
stats = rom_emu.get_statistics()
print("ROM Emulator Statistics:")
for key, value in stats.items():
print(f" {key}: {value}")
elif command == "dump":
rom_emu.dump_rom_section(0, 256)
elif command.startswith("switch "):
try:
image_id = int(command.split()[1])
rom_emu.switch_rom_image(image_id)
except (IndexError, ValueError):
print("Usage: switch ")
elif command.startswith("load "):
try:
parts = command.split()
image_id = int(parts[1])
filename = parts[2]
rom_emu.load_rom_image(image_id, filename)
except (IndexError, ValueError):
print("Usage: load ")
elif command == "help":
print("Available commands:")
print(" stats - Show emulation statistics")
print(" dump - Dump first 256 bytes of ROM")
print(" switch - Switch to ROM image ")
print(" load - Load ROM image from file")
print(" help - Show this help")
print(" quit - Exit emulator")
else:
print("Unknown command. Type 'help' for available commands.")
except KeyboardInterrupt:
print("\nShutting down...")
break
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()
🔧 การติดตั้งและใช้งาน
- ดาวน์โหลด MicroPython firmware สำหรับ Pico 2
- Flash firmware ลง Pico 2 ผ่าน USB
- Copy โค้ด Python ลงใน Pico 2
- เชื่อมต่อสายไฟตาม Circuit Diagram
- รัน main.py เพื่อเริ่ม ROM Emulation
- ทดสอบการทำงานด้วย Logic Analyzer
⚡ การปรับแต่ง Performance
🚀 เทคนิคเพิ่มความเร็ว
- ใช้ PIO State Machines สำหรับ I/O
- DMA สำหรับ Memory Transfer
- Dual Core Processing
- Overclock CPU เป็น 200MHz
- Cache ROM data ใน SRAM
- Optimize Memory Layout
⚠️ ข้อควรระวัง
- Signal Integrity ที่ความเร็วสูง
- Power Supply Noise
- Ground Loop และ EMI
- Temperature Rise จาก Overclocking
- Timing Constraints
- Memory Bandwidth Limits
🎯 การใช้งานจริง
🕹️ Retro Computing
เปลี่ยน ROM ใน Apple II เพื่อรัน Multiple OS
ทดสอบ Custom Kernal และ BASIC ROM
แทนที่ ROM ที่เสียหายใน Arcade Boards
ROM Cartridge Emulation สำหรับ MSX
🏭 Industrial & Development
ทดสอบ Firmware ก่อน Flash ลง Production
แทนที่ ROM ที่หาซื้อไม่ได้แล้ว
สอน Computer Architecture และ Memory Systems
วิเคราะห์และ Modify ROM Contents
🔬 Research & Testing
อ่านและสำรอง ROM จากระบบเก่า
ทดสอบ ROM Compatibility กับ Hardware ต่างๆ
วัด ROM Access Time และ Throughput
🚀 Advanced Applications
จำลอง ROM Bank Switching
เปลี่ยน ROM แบบ Real-time ผ่าน Network
บีบอัด ROM เพื่อประหยัดพื้นที่
🔧 การแก้ไขปัญหา
❌ ปัญหาที่พบบ่อย
• ตรวจสอบการต่อสาย Address/Data Bus
• ตรวจสอบ Control Signals (CE#, OE#)
• ตรวจสอบ Power Supply และ Ground
• ใช้ Level Shifter สำหรับ 5V Systems
• ตรวจสอบ Signal Integrity
• ลด Clock Speed หรือเพิ่ม Delay
• Enable PIO และ DMA
• Overclock Pico 2 เป็น 200MHz
• ใช้ Dual Core Processing
✅ วิธีแก้ไข
• ใช้ Logic Analyzer ตรวจสอบ Signals
• ทดสอบด้วย Simple ROM Pattern
• ตรวจสอบ Timing Diagram
• ใช้สาย Jumper สั้นๆ
• เพิ่ม Decoupling Capacitors
• ใช้ Ground Plane ที่ดี
• เพิ่ม Debug Output ใน Code
• ใช้ Serial Monitor
• ทดสอบทีละส่วน
🔮 การพัฒนาต่อยอด
🚀 แนวทางการพัฒนาต่อ
Remote ROM Management ผ่าน WiFi
Control ROM Emulator ผ่าน Smartphone
Real-time ROM Compression/Decompression
Encrypted ROM Storage และ Authentication
ROM Usage Statistics และ Performance Monitoring
Automatic ROM Updates จาก Repository
🛠️ Hardware Improvements
- Custom PCB Design สำหรับ Production
- Built-in Level Shifters และ Buffers
- LED Status Indicators
- External SRAM สำหรับ Large ROMs
- Multiple ROM Socket Support
- USB-C Power และ Data
💻 Software Enhancements
- GUI Application สำหรับ ROM Management
- ROM Format Auto-Detection
- Checksum Verification
- ROM Patching และ Modification Tools
- Performance Profiling
- Cloud ROM Repository Integration
🎯 สรุป: Pico2ROMEmu - ROM Emulator ยุคใหม่
Pico2ROMEmu เป็นโซลูชัน ROM Emulation ที่ทรงพลังและประหยัด ด้วย Raspberry Pi Pico 2 และ RP2350 chip จาก Global Byte Shop คุณสามารถสร้าง ROM Emulator ที่มี Performance เทียบเท่า Hardware ROM เริ่มต้นเพียง 1,190 บาท
⚡ Performance สูง
RP2350 @ 150MHz
PIO + DMA สำหรับ Real-time I/O
💰 ราคาประหยัด
เริ่มต้นเพียง 1,190 บาท
ถูกกว่า Hardware ROM หลายเท่า
🔄 ความยืดหยุ่น
Multiple ROM Images
Hot-swapping Support
⏰ จัดส่งฟรีทั่วไทย | 🔧 รับประกัน 1 ปี | 💬 Support 24/7
อ้างอิงจาก Hackaday.io
บทความนี้พัฒนาต่อยอดจากโปรเจค "Pico2ROMEmu - RP2350/Pico2 ROM Emulator" โดยเพิ่มเติมการอธิบายเทคนิค การใช้งาน และแนะนำอุปกรณ์ที่หาซื้อได้ในไทย
🎯 สิ่งที่เพิ่มเติมในบทความนี้:
- • อธิบายหลักการทำงานของ RP2350 PIO และ DMA
- • เปรียบเทียบ Pico 2 กับ Pico รุ่นแรก
- • รายการอุปกรณ์และราคาจาก Global Byte Shop
- • คู่มือการประกอบและเขียนโปรแกรม
- • ตัวอย่างการใช้งานกับระบบ Retro Computing
- • การ Troubleshooting และ Performance Tuning
- • แนวทางการพัฒนาต่อยอดและปรับปรุง