前回のGOWIN RUMBERのLチカは階層なしですべてをトップ階層に置くという乱暴なものでした。
これをTOP階層とCLK生成、LED信号生成に分けてみました。
まず、TOP階層(top.v)
/* デバイスは GW1N-4B(GW1N-UV4LQ144C6/I5) */
module top
(
input wire CLK_IN,
input wire RST_N,
input wire SW,
output wire [2:0] RGB_LED,
output wire [7:0] LED
);
wire SYSCLK;
wire SLWCLK;
clk clk1(
.RST_N(RST_N),
.CLK_G(CLK_IN),
.INTCLK(SYSCLK),
.SLWCLK(SLWCLK)
);
wire SW1;
reg SSW1; // 同期化したSW1
wire [2:0] RGBLED1 ;
reg dir;
reg [3:0] dsw ;
led led1(
.RST_N(RST_N),
.SYSCLK(SYSCLK),
.DIR(dir),
.RGB_LED(RGBLED1)
);
// SWのチャタリング除去
always @(posedge SLWCLK)begin
if(RST_N==0)begin
dsw = 4'b1;
end
else begin
dsw[3:1] <= dsw[2:0];
dsw[0] <= SW1;
end
end
always @(posedge SLWCLK)begin
if( dsw == 4'b1100 ) begin
SSW1 <= 1;
end
else begin
SSW1 <= 0;
end
end
always @(posedge SLWCLK)begin
if(SSW1 == 1)begin
dir <= dir ? 1'b0 : 1'b1 ;
end
else begin
dir <= dir ;
end
end
assign RGB_LED = RGBLED1;
assign SW1 = SW;
assign LED[0] = dir;
assign LED[1] = SW1;
assign LED[7:2] = 6'b0000000;
endmodule
次にクロック生成(clk.v)
module clk(
input wire RST_N,
input wire CLK_G,
output wire INTCLK,
output wire SLWCLK
);
reg [4:0] ckci; // 1MHz生成用カウンタ
reg cki;
reg [16:0] ckcs; // 100Hz生成用カウンタ
reg cks;
// 1MHz周期のクロック信号生成
// 12MHzクロックをカウントして1MHzのクロックを作る。
// 立ち上がりエッジしか使わないからデューティはどうでもよいので、
// 12MHzの1周期幅(=83ns)幅とする。
//
// _____|~|________|~|________|~|________
//
// 同様に12MHzクロックをカウントして100Hzのクロックを作る。
// (チャタリング防止用)
//
always @(posedge CLK_G)begin
if(RST_N==0)begin
ckci = 1'b1;
end
if(ckci == 5'd11)
begin
ckci <= 5'b0 ;
cki <= 1'b1;
end
else begin
ckci <= ckci + 1'b1;
cki <= 1'b0;
end
end
assign INTCLK = cki;
always @(posedge CLK_G)begin
if(RST_N==0)begin
ckcs = 1'b1;
end
if(ckcs == 17'd119999)
begin
ckcs <= 17'b0 ;
cks <= 1'b1;
end
else begin
ckcs <= ckcs + 1'b1;
cks <= 1'b0;
end
end
assign SLWCLK = cks;
endmodule
LED信号生成(led.v)
module led
(
input wire RST_N,
input wire SYSCLK,
input wire DIR,
output wire [2:0] RGB_LED
);
parameter time1 = 10'd1000 - 1'd1;
// parameter time2 = 10'd1000 - 1'd1; // 1秒周期
parameter time2 = 10'd500 - 1'd1; // 0.5秒周期
reg [2:0] rled;
reg [2:0] rledout;
reg [9:0] count1; // PWM DUTY用(1ms周期)
reg [9:0] count2; // PWM レベル用(1s周期)
reg [9:0] duty;
wire dir;
assign dir = DIR;
initial
begin
count1=10'b0;
count2=10'b0;
rled <= 3'b110;
end
always @(posedge SYSCLK)begin
if(RST_N==0)begin
count1 <= 10'b0;
count2 <= 10'b0;
rled <= 3'b110;
end
begin
if(count1 == time1)
begin
count1<= 10'd0;
end
else begin
count1 <= count1 + 1'b1;
end
end
// count1の1周期で0〜999(time2)までカウント
if(count1 == time1)
begin
if(count2 == time2)
begin
count2<= 10'd0;
rled <= dir ? {rled[1:0],rled[2]} : {rled[0],rled[2:1]} ;
end
else
count2 <= count2 + 1'b1;
end
// LEDを駆動するPWM信号生成
begin
if(count2 < time2/2)
duty = count2 * 2;
else
duty = (time2 - count2) * 2;
if(count1 < duty)
rledout = rled;
else
rledout = 3'b111;
end
end
assign RGB_LED[0] = rledout[0];
assign RGB_LED[1] = rledout[1];
assign RGB_LED[2] = rledout[2];
endmodule
初回の論理合成と端子の割付は前回と同様に実施しました。
今回はGowin Analyzer Oscilloscopeで内部信号をモニタしてみます。Designerでファイルの新規作成で「GAO Config File」を作成します。作成したら、作成したraoファイルをダブルクリックしてRTLで信号選択するのかNetListで信号選択するのかといったことや、対象信号、対象クロックを設定します。(Gowin Analyzer Oscilloscopeを使うのは2回目なので、前回ほど詳しく書きません)
設定したらファイルを保存して、論理合成・配置配線をし直します。
生成したら、Toolメニューの下かアイコンでGowin Analyzer Oscilloscopeを起動します。
(起動する前あたりで sudo modprobe -r ftdi_sio を実行しておきます)
Enable Programmerにチェックを入れます。
プログラマと同じ操作でDeviceやダウンロードするFsファイルを指定して、Enableにチェックを入れた後、プログラムします。
書き込みのプログレスバーが動かないのが気持ち悪いですが、動作が始まります。
Ready to acquire の右の再生ボタンをクリックするとキャプチャが始まり、メモリが埋まると無事に表示されました。