---
title: SwiftでプログラミングできるハードウェアをFPGAで自作してみた
tags: 
author: [Shinichiro Oba](https://docswell.com/user/bricklife)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/5JGLWYQY7L.jpg?width=480
description: iOSDC Japan 2026 LTの登壇資料です。 https://fortee.jp/iosdc-japan-2026/proposal/0688a16a-b469-4f00-9ddd-d8c14d7ff383  コード置き場 https://github.com/bricklife/embedded-swift-tangnano9k-console
published: September 13, 26
canonical: https://docswell.com/s/bricklife/Z6N8JV-embedded-swift-fpga-console
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/5JGLWYQY7L.jpg)

Swiftでプログラミングできる
ハードウェアをFPGAで自作して
みた
大庭 慎一郎 Shinichiro Oba
@ooba / @bricklife


# Page. 2

![Page Image](https://bcdn.docswell.com/page/47QY3MK6EP.jpg)

↑↑↑を見てEmbedded Swiftにハマった結果↓↓↓


# Page. 3

![Page Image](https://bcdn.docswell.com/page/KE4W1VPMJ1.jpg)

https://www.youtube.com/watch?v=0OcOFBe0jbQ
https://www.youtube.com/watch?v=mrEC1WIdW-A


# Page. 4

![Page Image](https://bcdn.docswell.com/page/L71YG39YJG.jpg)

マイコン系のMMIOは
ボタンを増やしたい
音鳴らすの大変すぎ
汎用的すぎて面倒
画面解像度を大きく
画面モードとか不要
したい
CPUをオープンな
RISC-Vにしたい
なるべくアセンブリ
言語を使いたくない
リフレッシュレート
を変えたい


# Page. 5

![Page Image](https://bcdn.docswell.com/page/G7WGKPQ1E2.jpg)

沸き起こる衝動…


# Page. 6

![Page Image](https://bcdn.docswell.com/page/4JZLZKWXE3.jpg)

ハードウェアも自分で
設計したい！


# Page. 7

![Page Image](https://bcdn.docswell.com/page/YE6WZQGPEV.jpg)

ハードウェアも自分で設計して、
それをSwiftで動かしたい！


# Page. 8

![Page Image](https://bcdn.docswell.com/page/GE5MWRVPE4.jpg)

これ作るの無理では…？
写真は全て https://www.ifixit.com/ より


# Page. 9

![Page Image](https://bcdn.docswell.com/page/9729QD3ZJR.jpg)

FPGA
Field Programmable Gate Array


# Page. 10

![Page Image](https://bcdn.docswell.com/page/DJY4W21N7M.jpg)

コンピュータのコアはデジタル回路
オーディオ RAM
CDデコーダー SPU
ROM
CDデジタル信号プロセッサ
この辺がデジタル回路
D/Aコンバーター
ビデオエンコーダー
VRAM
GPU
CPU
DRAM
https://jp.ifixit.com/Teardown/Sony+PlayStation%E3%81%AE%E5%88%86%E8%A7%A3/128089 より抜粋


# Page. 11

![Page Image](https://bcdn.docswell.com/page/V7NY982VE8.jpg)



# Page. 12

![Page Image](https://bcdn.docswell.com/page/YJ9P2K1V73.jpg)

FPGA


# Page. 13

![Page Image](https://bcdn.docswell.com/page/GJ8D5R44JD.jpg)

ハードウェア記述言語
Hardware Description Language (HDL)
Verilog
SystemVerilog
VHDL
// Toggle q after every CYCLES clocks of clk.
// Example: CYCLES = 13_500_000 at 27 MHz → q flips every 0.5 s.
module clk_toggle #(
parameter CYCLES = 13_500_000
) (
input wire clk,
input wire rst_n, // active-low
output reg q
);
localparam integer W = $clog2(CYCLES);
reg [W-1:0] cnt;
Chisel
Veryl
…
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt &lt;= {W{1&#039;b0}};
q
&lt;= 1&#039;b0;
end else if (cnt == CYCLES - 1) begin
cnt &lt;= {W{1&#039;b0}};
q
&lt;= ~q;
end else begin
cnt &lt;= cnt + 1&#039;b1;
end
end
endmodule


# Page. 14

![Page Image](https://bcdn.docswell.com/page/LJLMYK6VER.jpg)

VerilogによるLED点滅回路
// Two-LED blinker for Tang Nano 9K.
// LED0 and LED1 are opposite (on-board LEDs are active-low).
// Toggle q after every CYCLES clocks of clk.
// Example: CYCLES = 13_500_000 at 27 MHz → q flips every 0.5 s.
module blink_leds (
input wire
clk_osc, // 27 MHz
input wire
btn,
// S2, active-low reset
output wire [5:0] led
);
module clk_toggle #(
parameter CYCLES = 13_500_000
) (
input wire clk,
input wire rst_n, // active-low
output reg q
);
wire q;
// 27 MHz × 13_500_000 = 0.5 s per edge → 1 Hz blink.
clk_toggle #(
.CYCLES(13_500_000)
) u_toggle (
.clk (clk_osc),
.rst_n(btn),
.q
(q)
);
assign led[0] = ~q;
// on when q = 1
assign led[1] = q;
// on when q = 0
assign led[5:2] = 4&#039;b1111; // off
endmodule
localparam integer W = $clog2(CYCLES);
reg [W-1:0] cnt;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt &lt;= {W{1&#039;b0}};
q
&lt;= 1&#039;b0;
end else if (cnt == CYCLES - 1) begin
cnt &lt;= {W{1&#039;b0}};
q
&lt;= ~q;
end else begin
cnt &lt;= cnt + 1&#039;b1;
end
end
endmodule


# Page. 15

![Page Image](https://bcdn.docswell.com/page/47MYN25N7W.jpg)

AIコーディングエージェントが
使える！


# Page. 16

![Page Image](https://bcdn.docswell.com/page/P7R9DM34E9.jpg)

自作携帯ゲーム機
CPU：32-bit RISC-V 15MHz（RV32IMAC）
画面：480x272@50Hz（RGB565）
ボタン：10個
スプライト：最大16枚 1ライン4枚
音声：1ch 矩形波音階
デバッグ機能：JTAG、UART、LED×6
バッテリー未実装


# Page. 17

![Page Image](https://bcdn.docswell.com/page/PJXQ1V4Z7X.jpg)

中身
LCDパネル
Tang Nano 9K
FPGA: GW1NR-9
LUT4: 8640
値段: 秋月で3,780円（税込）
ボタン×10
圧電スピーカー


# Page. 18

![Page Image](https://bcdn.docswell.com/page/3JK92QZVJD.jpg)

全体構成
Tang Nano 9K
LCDコントローラ
LCD
SRAM
プログラム
スタック / ヒープ
スプライト/ 音
CPU
Hazard3
LED×6
ボタン×10
PSRAM
ビットマップ用VRAM
SDカードス
ロット
スピーカー
APB
USB-UART


# Page. 19

![Page Image](https://bcdn.docswell.com/page/LE3W4PXQE5.jpg)

MMIOの設計
Tang Nano 9K
アドレス
用途
0x0000_0000
ブートローダー
0x0000_2000
アプリ
SRAM
0x4000_0000
タイマ
プログラム
LCDコントローラ
LCD
スタック / ヒープ
0x4000_1000
CPU
Hazard3
LCD 制御（vcount / enable）
スプライト/ 音
LED×6
0x4000_2000
スプライト CTRL（ENABLE / STAT / INFO）
0x4000_4000
UART
0x4000_8000
ボタン×10
PSRAM
GPIO 出力（LED[5:0]、SDカードSPI）
SDカードス
ビットマップ用VRAM
0x4000_c000
GPIO 入力（btn_gpio[11:0]、SDカードSPI）
ロット
0x5000_0000
OBJ パレット（RGB565×16×16）
0x5000_1000
OBJ タイル（64×32B @4bpp）
APB
スピーカー
USB-UART
0x5000_4000
OAM（N=16 / 1ライン最大4）
0x6000_0000
VRAM ビットマップ（480x272 RGB565）


# Page. 20

![Page Image](https://bcdn.docswell.com/page/8EDKQL2W7G.jpg)

Embedded Swiftのサポートターゲット
% cd
~/Library/Developer/Toolchains/swift-6.3-RELEASE.xctoolchain/usr/lib/swift/embedded/Swift.swiftmodule/
% ls *.swiftmodule
aarch64-none-none-elf.swiftmodule
armv6-none-none-eabi.swiftmodule
i686-unknown-none-elf.swiftmodule
arm64-apple-ios.swiftmodule
armv6m-apple-none-macho.swiftmodule
riscv32-none-none-eabi.swiftmodule
arm64-apple-macos.swiftmodule
armv6m-none-none-eabi.swiftmodule
riscv64-none-none-eabi.swiftmodule
arm64-apple-none-macho.swiftmodule
armv7-apple-none-macho.swiftmodule
wasm32-unknown-none-wasm.swiftmodule
arm64e-apple-ios.swiftmodule
armv7-none-none-eabi.swiftmodule
wasm64-unknown-none-wasm.swiftmodule
arm64e-apple-macos.swiftmodule
armv7em-apple-none-macho.swiftmodule
x86_64-apple-macos.swiftmodule
arm64e-apple-none-macho.swiftmodule
armv7em-none-none-eabi.swiftmodule
x86_64-unknown-none-elf.swiftmodule
armv4t-none-none-eabi.swiftmodule
armv7m-apple-none-macho.swiftmodule
armv6-apple-none-macho.swiftmodule
avr-none-none-elf.swiftmodule
armv4t-none-none-eabi:
GBA (ARM7TDMI)
armv6m-none-none-eabi:
Raspberry Pi Pico (RP2040)
armv7em-none-none-eabi: Playdate (STM32F746)
riscv32-none-none-eabi: ESP32-C6 (RISC-V RV32IMAC)


# Page. 21

![Page Image](https://bcdn.docswell.com/page/V7PKL21XJ8.jpg)

Embedded Swiftによるプログラミング例
import _Volatile
let LCD_W = 480
let LCD_H = 272
let VCOUNT = VolatileMappedRegister&lt;UInt32&gt;(unsafeBitPattern: 0x4000_1000)
let LED
= VolatileMappedRegister&lt;UInt32&gt;(unsafeBitPattern: 0x4000_8000)
let KEY
= VolatileMappedRegister&lt;UInt32&gt;(unsafeBitPattern: 0x4000_c000)
@main
struct GameMain {
static func waitForVsync() {
while VCOUNT.load() &gt;= UInt32(LCD_H) {}
while VCOUNT.load() &lt; UInt32(LCD_H) {}
}
struct Key: OptionSet {
let rawValue: UInt32
static let left
static let up
static let down
static let right
static let select
static let start
static let y
static let x
static let b
static let a
= Self(rawValue: 1 &lt;&lt; 0)
= Self(rawValue: 1 &lt;&lt; 1)
= Self(rawValue: 1 &lt;&lt; 2)
= Self(rawValue: 1 &lt;&lt; 3)
= Self(rawValue: 1 &lt;&lt; 4)
= Self(rawValue: 1 &lt;&lt; 5)
= Self(rawValue: 1 &lt;&lt; 6)
= Self(rawValue: 1 &lt;&lt; 7)
= Self(rawValue: 1 &lt;&lt; 8)
= Self(rawValue: 1 &lt;&lt; 9)
static func poll() -&gt; Self {
return Self(rawValue: KEY.load() &amp; 0x03ff)
}
var isPressingAny: Bool {
rawValue != 0
}
}
static func main() {
while true {
waitForVsync()
let key = Key.poll()
if key.contains(.a) {
LED.store(0x07)
} else if key.contains(.b) {
LED.store(0x28)
} else {
LED.store(0x00)
}
}
}
}


# Page. 22

![Page Image](https://bcdn.docswell.com/page/2JVVQDY3JQ.jpg)

AIに少しずつ機能を実装してもらう
1. VRAM上のビットマップ（RGB565）
をラインバッファを介してLCDに表示
7. プログラムをSDカードやシリアル
ポートから読み込み（H/W実装）
マップをLCDに表示
8. 回路規模縮小のためにプログラム読み
込みをSwift製ブートローダに変更
3. GPIO出力（LED点滅）
9. パレット（16バンク×16色 RGB565）
4. GPIO入力（ボタン入力）
10.スプライト（最大16枚 1ライン4枚）
5. タイマー
11.音声（1ch 矩形波音階のみ）
2. CPUからVRAMに書き込んだビット
6. LCDのオンオフや水平同期


# Page. 23

![Page Image](https://bcdn.docswell.com/page/5EGLWY9YJL.jpg)

画面描画のデバッグが大変すぎた…


# Page. 24

![Page Image](https://bcdn.docswell.com/page/4JQY3MW67P.jpg)

ソフトウェアのデバッグはJTAGをAIが操作


# Page. 25

![Page Image](https://bcdn.docswell.com/page/K74W1VKME1.jpg)

画面描画のデバッグもAIにお願いできたかも
LCDのタイミングチャートとFPGA内部ロジックアナライザ


# Page. 26

![Page Image](https://bcdn.docswell.com/page/LJ1YG3XYEG.jpg)



# Page. 27

![Page Image](https://bcdn.docswell.com/page/GJWGKPN172.jpg)

また少しコンピュータと
仲良くなれた気がする


# Page. 28

![Page Image](https://bcdn.docswell.com/page/4EZLZK3X73.jpg)

ありがとうございました
プロジェクトのリポジトリ
https://github.com/bricklife/embedded-swift-tangnano9k-console
リポジトリ
気軽に話し
かけてね


