FPGAで蘇る486互換PC(第1回)
2025年11月10日
はじめに
x86系ソフトコアプロセッサの実装例を探していた際、Tang Console 138K 上で ao486 を動作させた記事を見つけました。構成がシンプルで実験に適していそうだったため、自身の環境でも検証を試みました。
Tang Console 138Kは 秋月電子通商で2万円弱で購入しました。
準備するモノ
- Tang Console 138K
- WSL(Windows Subsystem for Linux)
Tang Console 138K(Tang Mega 138k SOM搭載)のスペック
| FPGAデバイス | GW5AST-LV138PG484A |
| Logic Unit (LUT4) | 138240 |
| Memory | 1GB DDR3(512MB x 2) |
| Flash | 128/64Mbits |
| SSRAM | 1080kbits |
開発環境
GOWIN EDAのInstall 「gowin eda install」のキーワードでGoogle先生に教えてもらって下さい。
手順
-
486tangをgitから入手する
git clone https://github.com/nand2mario/486tang.git -
gowinをInstall
使用するにはアカウントとライセンスも必要なので作成しておきましょう。バージョンはV1.9.12を使用しました。
-
GOWIN EDAでFPGAの合成
GOWINでプロジェクトファイル(486tang_console138k.gprj)を開き、合成、配置配線を実行(Run All)を行う。
GOWIN V1.9.9では以下のエラーが出て合成に失敗したので、V1.9.12を使う必要がある。
ERROR (PA2078) : Invalid VCO frequency 'FCLKIN*FBDIV_SEL*(MDIV_SEL+MDIV_FRAC_SEL/8)/IDIV_SEL' to 'PLL_inst'(PLL) set by module 'pll_27_MOD', suitable range is from 800MHz to 2000MHz ERROR (PA2078) : Invalid VCO frequency 'FCLKIN*FBDIV_SEL*(MDIV_SEL+MDIV_FRAC_SEL/8)/IDIV_SEL' to 'PLL_inst'(PLL) set by module 'pll_hdmi_MOD', suitable range is from 800MHz to 2000MHz NOTE (PA0005) : Processing netlist completed with errorsちなみに、エラーの内容を見ると、VCO(Voltage Controlled Oscillator)の発振周波数が許容範囲外になっているようです。
src/pll/pll_27_mod.v を確認すると、以下のような設定になっていました。
defparam PLL_inst.FCLKIN = "50"; defparam PLL_inst.IDIV_SEL = 1; defparam PLL_inst.FBDIV_SEL = 2; defparam PLL_inst.MDIV_SEL = 27; defparam PLL_inst.MDIV_FRAC_SEL = 0;VCO周波数は次の式で求められます。
VCO = FCLKIN * FBDIV_SEL * (MDIV_SEL + MDIV_FRAC_SEL/8) / IDIV_SELこれを代入して計算すると:
VCO = 50 * 1 * (27 + 0/8) / 2 = 50 * 13.5 = 675 MHz→ 675 MHz < 800 MHz のため、VCOが低すぎてエラーとなっていました。
FBDIV_SEL を 2 に修正したところ、VCOが許容範囲(800〜2000 MHz)内に収まりました。
VCO = 50 * 2 * 27 / 2 = 1350 MHz ✅(OK)同様に、pll_hdmi_MOD 側の設定も修正することで、FPGAの合成が正常に完了しました。
-
Tang Console 138Kへビットストリームを書き込む
Tang Console 138KをUSBで接続した後、GOWIN EDAからGowin Programmerを起動します。
GOWIN Programmerが書き込み中に固まることがありました。環境依存のようで、USBケーブルを短いノイズ対策品に替えるか、別のPCで実行すると安定することが多いようです。
-
SDカードの作成
FreeDOSの起動イメージfreedos1.1.imgをダウンロードし、以下の手順でSDカードの起動イメージを作成します。
boot0.romとboot1.romは、gitのtoolsにあります。
cd 486tang/tools python3 ./mksdcard.py -h usage: mksdcard.py [-h] [-o OUTPUT] [--mem MEM] bios vga_bios hdd Create SD card image by combining BIOS, VGA BIOS, and HDD images positional arguments: bios BIOS image file (placed at offset 0) vga_bios VGA BIOS image file (placed at offset 64KB) hdd Hard disk image file (placed at offset 128KB) options: -h, --help show this help message and exit -o OUTPUT, --output OUTPUT Output SD card image file (default: sdcard.img) --mem MEM Extended memory size (MB) to write to CMOS (default: 2) python ./mksdcard.py boot0.rom boot1.rom freedos1.1.img -o out.img --mem=2作成した起動イメージをSDカードへ書き込みます。書き込みツールには『DD for Windows』を使用しました。
※python3をInstallすれば、mksdcard.pyはPowerShelでも実行できます。
-
486tang_toolboxのBuild
486tang_toolboxのBuildはWLSで、以下の手順でBuildしました。
pip install pyserial pip install pygame python .\build.py
動かしてみる
-
USBケーブルを接続
-
486tang_toolboxを実行
SerialPortの設定を行い、「Start Interactive Mode」を行うと、以下のウィンドウが表示されKeyボードとMouseがエミュレーションされます。
最後に
ao486 SoC(System on a Chip) は、FPGA(Field Programmable Gate Array)上にIntel 80486(i486)互換のPCシステムをハードウェアレベルで再現したプロジェクトです。CPUをはじめ、VGAコントローラ、PS/2インターフェース、PIT(Programmable Interval Timer)、RTC(Real-Time Clock)、HDDコントローラといった主要モジュールを実装し、実際に汎用OSを動作させることができるFPGAベースのSoCとなっています。
オープンソースとしてGitHubで公開されており、FPGA上でPCアーキテクチャを再現したいエンジニアやレトロPCファンにとって、非常に魅力的なプロジェクトです。
調べてみると、ao486 は MiSTer プロジェクト をベースにしているようで、PS/2 キーボードやマウスのインターフェースは UART 経由のエミュレーション で実装されています。これは手軽でシンプルな構成ですが、個人的にはやはり i8042 互換の PS/2 コントローラ を搭載して、実機のようにキーボードを直接接続できる方が「本物の486マシン感」があって好きです。
次回は、本来のPCアーキテクチャにより近い動作を目指し、実際のPS/2デバイスを直接扱える環境を構築するために、486Tangへのi8042 PS/2コントローラの組み込みにチャレンジします。
おまけ
Digilent社の Pmod PS/2の Pmod PS/2(Keyboard / Mouse Connector) を接続するために調査した、Tang Console 138K の PMODポートとFPGAピンのアサイン対応表 です。
PMOD0
| 3V3 | GND | 6(C22) | 4(F18) | 2(G21) | 0(V18) |
| 3V3 | GND | 7(B22) | 5(E18) | 3(G22) | 1(V19) |
PMOD1
| 3V3 | GND | 6(E21) | 4(E22) | 2(F19) | 0(W19) |
| 3V3 | GND | 7(D21) | 5(D22) | 3(F20) | 1(W20) |
Pmod PS/2
| 3V3 | GND | 6(Not used) | 4(Clock) | 2(Not used) | 0(Data) |





