最近、新しいグループに入ってFPGAデビューするために、 とりあえず論理回路とかコンピュータアーキテクチャとかディジタル信号処理とかの講義は取ったんだけど、 やばい、マジでやばい、みんなの話題がころころ変わってついてけなくて、 FPGAといえばよく「並列に動く回路をHDLで書く」といううわさは聞いてて、 それからVHDLやVerilogの演習を受けた人たちがめげている様子をはたから見てて、 わたしにやれるの?と思ってます…。いやムリ!
とりあえずカウンタや状態遷移の書き方試して、 なんとなくSDRAMコントローラを作ってみようとしたんだけど、 なかなかFPGAで動かなくて。 困るのは、仕様はプログラミングみたいに順次動作が書いてあるけど、 これを並列に動く回路に書き換えるところで脳みその変なところを使っているような感じがして難しくて、 あと、いちいちリセットやクロックを書いたり、さんざんbeginとendでくくったりするのが地味に面倒! もうムリ!
そんな感じで見事にHDLに翻弄され疲れて屋上で休んでたら完全無欠のM1が 「脈は無さそうでもないな…。ある日はVerilog、ある日はNSL、そうやって交互に試してみるというのはどうだい?」って迫ってきて…。 いやムリでしょムリ~!
$ wget https://www.overtone.co.jp/files/nslcore-x86_64-linux-20250428-101.tar.gz
$ mkdir nslcore && tar zxf nslcore-x86_64-linux-20250428-101.tar.gz -C nslcore
$ sudo cp nslcore/linux/x86_64/* /usr/local/bin
$ nsl2vl
OPTIONS:
INPUT CONTROLS
...
Verilogだと一つのalwaysに各コマンドの各出力が書いてある感じなのかな。 これとか sdram_controller.v あとこれも sdram-controller.v アイドルが書いたり読んだりしてる…?(以下抜粋)
always @*
begin
if (state == IDLE)
else
if (!state_cnt)
case (state)
// INIT処理(省略)
INIT_NOP1:
...
// REFRESH処理(省略)
REF_PRE:
...
// WRITE
WRIT_ACT:
begin
next = WRIT_NOP1;
state_cnt_nxt = 4'd1;
end
WRIT_NOP1:
begin
next = WRIT_CAS;
command_nxt = CMD_WRIT;
end
WRIT_CAS:
begin
next = WRIT_NOP2;
state_cnt_nxt = 4'd1;
end
// READ
READ_ACT:
begin
next = READ_NOP1;
state_cnt_nxt = 4'd1;
end
READ_NOP1:
begin
next = READ_CAS;
command_nxt = CMD_READ;
end
READ_CAS:
begin
next = READ_NOP2;
state_cnt_nxt = 4'd1;
end
READ_NOP2:
begin
next = READ_READ;
end
default:
begin
next = IDLE;
end
endcase
else
begin
next = state;
end
end
func write write_proc(adrs, din);
proc write_proc seq{
label_name ACT;
ACT: if(~refresh){
com_ACT();
BA_reg := adrs_reg[21:20];
A_reg := adrs_reg[19:8];
DEn_reg := 0b0;
} else goto ACT;
{
com_WRITE();
A_reg := {0b0100, adrs_reg[7:0]}; // Auto Precharge
}
{
com_NOP();
DEn_reg := 0b1;
finish;
}
}
func read read_proc(adrs);
proc read_proc seq{
label_name ACT;
ACT: if(~refresh){
com_ACT();
BA_reg := adrs_reg[21:20];
A_reg := adrs_reg[19:8];
} else goto ACT;
{
com_READ();
A_reg := {0b0100, adrs_reg[7:0]}; // Auto Precharge
}
com_NOP();
com_NOP();
{
dout_reg := Dout;
finish;
}
}
NSLからVerilogへの変換は一瞬。
最適化できるらしい-O2を入れてみる。
renako@ubuntu-desktop:~/nsl_test$ nsl2vl sdram16_ctrl.nsl -O2
nslpp.exe sdram16_ctrl.nsl | nslc.exe -O2 -o sdram16_ctrl.v
NSL CORE (version=20250428, build=101)
Copyright (c) 2002-2025 IP ARCH, Inc. Naohiko Shimizu
All rights reserved.
No License file found
Licensed to evaluation user without license file.
You are allowed to compile up to 2000 lines or statements
You are EVALUATION USER
renako@ubuntu-desktop:~/nsl_test$ verilator --lint-only sdram16_ctrl.v --quiet-stats
renako@ubuntu-desktop:~/nsl_test$
…っていう感じで使ってみたんだけどどうかなってM1に見せてみたら…、だ。 「なんてことはなかっただろう?RN子ならすぐ慣れると思ったよ」 なんて言って誰からも否定されたことのないような目でまっすぐこっちを向いて、 いやいやこの人もピンと来てないけど見つめられても何にも出ないですよ…?
兎にも角にも、こうしてわたしとNSLの戦いが幕を開けたのだった!!