ナイトライダーを作ってみる。

さてそれではナイトライダー…っぽいLED Flasherです。
どうやって作ろうか方針を練ります。

光が移動していく速度は、とりあえずLEDが8個なので片道1秒とすれば125msecになります。まずはその線でいってみましょう。
LEDの輝度は、1000と30と1くらいでいいかしら。8個中3個が同時点灯という形で。

制御方法ですが、16ステップのシーケンサを作ってしまえばいいかな。4bitのフラグレジスタを用意して、125msecごとにフラグ値の処理を行い、フラグを+1する、という感じ。
125msecごとに起動するのは50MHzのクロックだと50000000/8=6250000なので、24bitのカウンタを用意して5F5E10hと比較すればいいかな。フラグが立ったらカウンタをリセット。

パターンはオール0から始まって、

0000 0001
0000 0012
0000 0123
0000 1230

0001 2300
0012 3000
0123 0000
1230 0000

2300 0000
3000 0000
1000 0000
2100 0000

3210 0000
0321 0000
0032 1000
0003 2100

0000 3210
0000 0321
0000 0032
0000 0003

ん、20パターンですねぇ。ちょっと美しくないけれどこれでやってみましょうか。

最初の100行ほどが変わるだけなので、その部分だけ貼り付けます。


// vim: set fenc=utf-8 filetype=verilog expandtab ts=4 sts=4 sw=4:
//
// generate 1000Hz clock from 50MHz osc input.
//
module LED_TOP(clk, reset,
    LED1, LED2, LED3, LED4, LED5, LED6, LED7, LED8);
    input clk;
    input reset;
    output LED1, LED2, LED3, LED4, LED5, LED6, LED7, LED8;
    wire c1kout;

    reg [7:0] count1;
    reg [7:0] count2;
    reg [7:0] count3;
    reg [7:0] count4;
    reg [7:0] count5;
    reg [7:0] count6;
    reg [7:0] count7;
    reg [7:0] count8;

    reg [9:0] duty1 = 1000;
    reg [9:0] duty2 = 0;
    reg [9:0] duty3 = 0;
    reg [9:0] duty4 = 0;
    reg [9:0] duty5 = 0;
    reg [9:0] duty6 = 0;
    reg [9:0] duty7 = 0;
    reg [9:0] duty8 = 0;

    reg  _out1;
    reg  _out2;
    reg  _out3;
    reg  _out4;
    reg  _out5;
    reg  _out6;
    reg  _out7;
    reg  _out8;
    
assign LED1 = _out1;
assign LED2 = _out2;
assign LED3 = _out3;
assign LED4 = _out4;
assign LED5 = _out5;
assign LED6 = _out6;
assign LED7 = _out7;
assign LED8 = _out8;

 reg [23:0] seq; // sequence counter
 reg [4:0] step; // sequence step flag

CLK10000HZ c1k(
    .clk(clk),
    .reset(reset),
    .clk1m(c1kout));

// sequencer
always @ (posedge clk or negedge reset) begin
    if (reset == 0)
    begin
        seq <= 0;
        step <= 0;
    end else
    if (seq < 24'h5F5E10 - 1)
    begin
        seq <= seq + 1;
    end
    else
    begin
        seq <= 0;
        case (step)
            5'b00000 : begin duty1 <=  1000; duty2 <=  0; duty3 <=  0; duty4 <=  0; duty5 <=  0; duty6 <=  0; duty7 <=  0; duty8 <=  0; step <=  step + 1; end
            5'b00001 : begin duty1 <=  30; duty2 <=  1000; duty3 <=  0; duty4 <=  0; duty5 <=  0; duty6 <=  0; duty7 <=  0; duty8 <=  0; step <=  step + 1; end
            5'b00010 : begin duty1 <=  1; duty2 <=  30; duty3 <=  1000; duty4 <=  0; duty5 <=  0; duty6 <=  0; duty7 <=  0; duty8 <=  0; step <=  step + 1; end
            5'b00011 : begin duty1 <=  0; duty2 <=  1; duty3 <=  30; duty4 <=  1000; duty5 <=  0; duty6 <=  0; duty7 <=  0; duty8 <=  0; step <=  step + 1; end
            5'b00100 : begin duty1 <=  0; duty2 <=  0; duty3 <=  1; duty4 <=  30; duty5 <=  1000; duty6 <=  0; duty7 <=  0; duty8 <=  0; step <=  step + 1; end
            5'b00101 : begin duty1 <=  0; duty2 <=  0; duty3 <=  0; duty4 <=  1; duty5 <=  30; duty6 <=  1000; duty7 <=  0; duty8 <=  0; step <=  step + 1; end
            5'b00110 : begin duty1 <=  0; duty2 <=  0; duty3 <=  0; duty4 <=  0; duty5 <=  1; duty6 <=  30; duty7 <=  1000; duty8 <=  0; step <=  step + 1; end
            5'b00111 : begin duty1 <=  0; duty2 <=  0; duty3 <=  0; duty4 <=  0; duty5 <=  0; duty6 <=  1; duty7 <=  30; duty8 <=  1000; step <=  step + 1; end
            5'b01000 : begin duty1 <=  0; duty2 <=  0; duty3 <=  0; duty4 <=  0; duty5 <=  0; duty6 <=  0; duty7 <=  1; duty8 <=  30; step <=  step + 1; end
            5'b01001 : begin duty1 <=  0; duty2 <=  0; duty3 <=  0; duty4 <=  0; duty5 <=  0; duty6 <=  0; duty7 <=  0; duty8 <=  1; step <=  step + 1; end
            5'b01010 : begin duty1 <=  0; duty2 <=  0; duty3 <=  0; duty4 <=  0; duty5 <=  0; duty6 <=  0; duty7 <=  0; duty8 <=  1000; step <=  step + 1; end
            5'b01011 : begin duty1 <=  0; duty2 <=  0; duty3 <=  0; duty4 <=  0; duty5 <=  0; duty6 <=  0; duty7 <=  1000; duty8 <=  30; step <=  step + 1; end
            5'b01100 : begin duty1 <=  0; duty2 <=  0; duty3 <=  0; duty4 <=  0; duty5 <=  0; duty6 <=  1000; duty7 <=  30; duty8 <=  1; step <=  step + 1; end
            5'b01101 : begin duty1 <=  0; duty2 <=  0; duty3 <=  0; duty4 <=  0; duty5 <=  1000; duty6 <=  30; duty7 <=  1; duty8 <=  0; step <=  step + 1; end
            5'b01110 : begin duty1 <=  0; duty2 <=  0; duty3 <=  0; duty4 <=  1000; duty5 <=  30; duty6 <=  1; duty7 <=  0; duty8 <=  0; step <=  step + 1; end
            5'b01111 : begin duty1 <=  0; duty2 <=  0; duty3 <=  1000; duty4 <=  30; duty5 <=  1; duty6 <=  0; duty7 <=  0; duty8 <=  0; step <=  step + 1; end
            5'b10000 : begin duty1 <=  0; duty2 <=  1000; duty3 <=  30; duty4 <=  1; duty5 <=  0; duty6 <=  0; duty7 <=  0; duty8 <=  0; step <=  step + 1; end
            5'b10001 : begin duty1 <=  1000; duty2 <=  30; duty3 <=  1; duty4 <=  0; duty5 <=  0; duty6 <=  0; duty7 <=  0; duty8 <=  0; step <=  step + 1; end
            5'b10010 : begin duty1 <=  30; duty2 <=  1; duty3 <=  0; duty4 <=  0; duty5 <=  0; duty6 <=  0; duty7 <=  0; duty8 <=  0; step <=  step + 1; end
            5'b10011 : begin duty1 <=  1; duty2 <=  0; duty3 <=  0; duty4 <=  0; duty5 <=  0; duty6 <=  0; duty7 <=  0; duty8 <=  0; step <=  0; end
        endcase
    end
end

case文のところはわかりやすく記述したかったので、貼り付けたらかえって見辛くなってしまいましたが、1000のところだけを追いかければ「行って戻って」を繰り返すような記述になっているのがわかると思います。

撮影してみました。


両端での折り返しはこんな感じでいいんですかね。あと、肉眼だとわかるんですが、ビデオだと露出の関係かLEDの輝度の違いがわかりづらいですね。しかも撮影したビデオはフォーカスが合ってるのに、これはなんだかぼやけてしまっています。再エンコードされたからかしら。

明るさを変えてみる-その2。

シミュレーションではちゃんと波形が出ていたので、変だなぁ変だなぁと思いながらピンアサインを眺めたりしてたんですが。

なぜかいきなりパッとひらめきました。

出力端子の論理が逆じゃん!

指定した時間分だけ出力端子をHにするように書いていたんですが、LEDはLでドライブされるんですね。Brevia2の回路上もそうなってます。
ということで、コードを修正して試してみると、ちゃんと明るさが変わりました。が、変化の度合いが少ないため、クロックをさらに細かくしてデューティを0.01msec単位で変更できるようにしました。

twincle_led.v:

// vim: set fenc=utf-8 filetype=verilog expandtab ts=4 sts=0 sw=4:
//
// generate 1000Hz clock from 50MHz osc input.
//
module LED_TOP(clk, reset,
    LED1, LED2, LED3, LED4, LED5, LED6, LED7, LED8);
    input clk;
    input reset;
    output LED1, LED2, LED3, LED4, LED5, LED6, LED7, LED8;
    wire c1kout;

    reg [15:0] count1;
    reg [15:0] count2;
    reg [15:0] count3;
    reg [15:0] count4;
    reg [15:0] count5;
    reg [15:0] count6;
    reg [15:0] count7;
    reg [15:0] count8;

    reg [15:0] duty1 = 1;
    reg [15:0] duty2 = 5;
    reg [15:0] duty3 = 10;
    reg [15:0] duty4 = 30;
    reg [15:0] duty5 = 70;
    reg [15:0] duty6 = 100;
    reg [15:0] duty7 = 500;
    reg [15:0] duty8 = 1000;

    reg  _out1;
    reg  _out2;
    reg  _out3;
    reg  _out4;
    reg  _out5;
    reg  _out6;
    reg  _out7;
    reg  _out8;
    
assign LED1 = _out1;
assign LED2 = _out2;
assign LED3 = _out3;
assign LED4 = _out4;
assign LED5 = _out5;
assign LED6 = _out6;
assign LED7 = _out7;
assign LED8 = _out8;

CLK10000HZ c1k(
    .clk(clk),
    .reset(reset),
    .clk1m(c1kout));

// LED1
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out1 <= 0;
        count1 <= 0;
    end else
    if (count1 < 100 - 1) // 10msec周期
    begin
        count1 <= count1 + 1;
        if (count1 < duty1) // デューティ時間はONする
            _out1 <= 0;
        else
            _out1 <= 1;
    end
    else
    begin
        count1 <= 0;
    end
end

// LED2
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out2 <= 0;
        count2 <= 0;
    end else
    if (count2 < 100 - 1) // 10msec周期
    begin
        count2 <= count2 + 1;
        if (count2 < duty2) // デューティ時間はONする
            _out2 <= 0;
        else
            _out2 <= 1;
    end
    else
    begin
        count2 <= 0;
    end
end

// LED3
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out3 <= 0;
        count3 <= 0;
    end else
    if (count3 < 100 - 1) // 10msec周期
    begin
        count3 <= count3 + 1;
        if (count3 < duty3) // デューティ時間はONする
            _out3 <= 0;
        else
            _out3 <= 1;
    end
    else
    begin
        count3 <= 0;
    end
end

// LED4
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out4 <= 0;
        count4 <= 0;
    end else
    if (count4 < 100 - 1) // 10msec周期
    begin
        count4 <= count4 + 1;
        if (count4 < duty4) // デューティ時間はONする
            _out4 <= 0;
        else
            _out4 <= 1;
    end
    else
    begin
        count4 <= 0;
    end
end

// LED5
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out5 <= 0;
        count5 <= 0;
    end else
    if (count5 < 100 - 1) // 10msec周期
    begin
        count5 <= count5 + 1;
        if (count5 < duty5) // デューティ時間はONする
            _out5 <= 0;
        else
            _out5 <= 1;
    end
    else
    begin
        count5 <= 0;
    end
end

// LED6
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out6 <= 0;
        count6 <= 0;
    end else
    if (count6 < 100 - 1) // 10msec周期
    begin
        count6 <= count6 + 1;
        if (count6 < duty6) // デューティ時間はONする
            _out6 <= 0;
        else
            _out6 <= 1;
    end
    else
    begin
        count6 <= 0;
    end
end

// LED7
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out7 <= 0;
        count7 <= 0;
    end else
    if (count7 < 100 - 1) // 10msec周期
    begin
        count7 <= count7 + 1;
        if (count7 < duty7) // デューティ時間はONする
            _out7 <= 0;
        else
            _out7 <= 1;
    end
    else
    begin
        count7 <= 0;
    end
end

// LED8
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out8 <= 0;
        count8 <= 0;
    end else
    if (count8 < 100 - 1) // 10msec周期
    begin
        count8 <= count8 + 1;
        if (count8 < duty8) // デューティ時間はONする
            _out8 <= 0;
        else
            _out8 <= 1;
    end
    else
    begin
        count8 <= 0;
    end
end

endmodule

clk1000hz.vのほうは parameter CNT = 250; に変更。これでやってみたのが下の写真です。


ちゃんと輝度が変わってきていますね。一番上のLEDはフル点灯です。

これを動かしたらKnight 2000のLED Flasherみたいにできるかな、というのが先週のLチカの直後に思い浮かんだので、次はこれをやってみましょう。

ということで巫女さんと遊ぶのはもうちょっと後にしましょう。

明るさを変えてみる。

今まではクロックをカウンタに放り込んでそのままLEDに出力してましたが、これをPWMにしてデューティを変えてやったら輝度を調整できるんじゃないか、などという悪魔だか天使だかのささやきが。

テレビや8mmフィルムなどの映像では、昔から24Hzでコマが切り替わるようになっていました。そのくらいの速度であれば、脳がコマの切り替わりを認識できずに連続した映像だと錯覚するということなんですが、CRTの短残光モニタだと60Hzでは蛍光灯の周波数と干渉してちらつきがでたりするので、75Hz以上が普通にありました。LCDだと現在は60Hzくらいが普通です。

となると、100Hz程度あれば、フリッカーに気づかれずに細かい点滅ができるかもしれません。

100Hzだと、1周期は10msec。今回は1msecクロックを作っていますから、0msec(消灯)から10msec(点灯)までの間を1msecごとに区切れば、輝度を制御できるかもしれません。


// LED1
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out1 <= 0;
        count1 <= 0;
    end else
    if (count1 < 100 - 1)
    begin
        count1 <= count1 + 1;
    end
    else begin
        count1 <= 0;
        _out1 <= ~_out1;
    end
end

上はLED1の点滅回路部分です。
ここで周期を10msec固定にし、ON時間を0msecから10msecの間に設定できるようにレジスタを作れば、なんとなくできそうな気がします。


    reg [15:0] duty1 = 1;

// LED1
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out1 <= 0;
        count1 <= 0;
    end else
    if (count1 < 10 - 1) // 10msec周期
    begin
        count1 <= count1 + 1;
        if (count1 < duty1) // デューティ時間はONする
            _out1 <= 1;
        else
            _out1 <= 0;
    end
    else
    begin
        count1 <= 0;
    end
end

こんな感じにしてみました。
同じコトを他の7個のLEDにも行って、いざプログラム。


……。

微妙に明るさが変わっていっているのはわかりますが、あまり違いがわかりません。

なにか間違ったかなぁ。
このまま突き進んでも意味がないので、ちょっと頭を冷やしてシミュレーションしてみましょう。

たくさんLチカ。

Lチカはできたんですが、どうせなら8個あるLEDを全部、適当にばらばらな間隔で点滅させてみようか、などと思い立ち、ちょっと遠回り。巫女さんと遊ぶのはもうちょっと先にしましょう。

方針としては、1msecクロックはそのままで、カウンタを8個に増やし、それぞれのLEDごとに判定ループを作ります。

まずはCLK1000HZ.vを再掲。CNT - 1に修正してあります。


// vim: set fenc=utf-8 filetype=verilog expandtab ts=4 sts=0 sw=4:
//
// generate 1000Hz clock from 50MHz osc input.
//

module CLK1000HZ (clk, reset, clk1m);
    parameter CNT = 25000;

    input clk;
    input reset;
    output clk1m;
    reg clk1m;
    reg [15:0] count;

    always @ (posedge clk or negedge reset) begin
        if (reset == 0)
        begin
            count <= 0;
            clk1m <= 0;
        end else
        if (count < CNT - 1)
        begin
            count <= count + 1;
        end
        else begin
            count <= 0;
            clk1m <= ~clk1m;
        end
    end
endmodule
1行目の // vim: はvimで編集するときにこの設定でやってよね、というおまじないないので、vimを使わない人は不要です。
16行目の if (reset == 0) は if (!reset) でもいいかもです。

次はtwincle_led.vです。これがトップモジュールになり、LEDを駆動します。


// vim: set fenc=utf-8 filetype=verilog expandtab ts=4 sts=0 sw=4:
//
// generate 1000Hz clock from 50MHz osc input.
//
module LED_TOP(clk, reset,
    LED1, LED2, LED3, LED4, LED5, LED6, LED7, LED8);
    input clk;
    input reset;
    output LED1, LED2, LED3, LED4, LED5, LED6, LED7, LED8;
    wire c1kout;

    reg [15:0] count1;
    reg [15:0] count2;
    reg [15:0] count3;
    reg [15:0] count4;
    reg [15:0] count5;
    reg [15:0] count6;
    reg [15:0] count7;
    reg [15:0] count8;
    
    reg  _out1;
    reg  _out2;
    reg  _out3;
    reg  _out4;
    reg  _out5;
    reg  _out6;
    reg  _out7;
    reg  _out8;
    
assign LED1 = _out1;
assign LED2 = _out2;
assign LED3 = _out3;
assign LED4 = _out4;
assign LED5 = _out5;
assign LED6 = _out6;
assign LED7 = _out7;
assign LED8 = _out8;

CLK1000HZ c1k(
    .clk(clk),
    .reset(reset),
    .clk1m(c1kout));

// LED1
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out1 <= 0;
        count1 <= 0;
    end else
    if (count1 < 100 - 1)
    begin
        count1 <= count1 + 1;
    end
    else begin
        count1 <= 0;
        _out1 <= ~_out1;
    end
end

// LED2
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out2 <= 0;
        count2 <= 0;
    end else
    if (count2 < 50 - 1)
    begin
        count2 <= count2 + 1;
    end
    else begin
        count2 <= 0;
        _out2 <= ~_out2;
    end
end

// LED3
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out3 <= 0;
        count3 <= 0;
    end else
    if (count3 < 300 - 1)
    begin
        count3 <= count3 + 1;
    end
    else begin
        count3 <= 0;
        _out3 <= ~_out3;
    end
end

// LED4
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out4 <= 0;
        count4 <= 0;
    end else
    if (count4 < 1000 - 1)
    begin
        count4 <= count4 + 1;
    end
    else begin
        count4 <= 0;
        _out4 <= ~_out4;
    end
end

// LED5
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out5 <= 0;
        count5 <= 0;
    end else
    if (count5 < 20 - 1)
    begin
        count5 <= count5 + 1;
    end
    else begin
        count5 <= 0;
        _out5 <= ~_out5;
    end
end

// LED6
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out6 <= 0;
        count6 <= 0;
    end else
    if (count6 < 2500 - 1)
    begin
        count6 <= count6 + 1;
    end
    else begin
        count6 <= 0;
        _out6 <= ~_out6;
    end
end

// LED7
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out7 <= 0;
        count7 <= 0;
    end else
    if (count7 < 100 - 1)
    begin
        count7 <= count7 + 1;
    end
    else begin
        count7 <= 0;
        _out7 <= ~_out7;
    end
end

// LED8
always @ (posedge c1kout or negedge reset) begin
    if (reset == 0)
    begin
        _out8 <= 0;
        count8 <= 0;
    end else
    if (count8 < 720 - 1)
    begin
        count8 <= count8 + 1;
    end
    else begin
        count8 <= 0;
        _out8 <= ~_out8;
    end
end

endmodule
見てわかるとおり、LEDを1から8まで増やし、それに応じてカウンタと出力信号も増やしています。

ところでVerilogの記法って、なにかスタンダードがあるんでしょうかね。たとえばモジュール定義の信号名は大文字にするとかCamelCaseにするとか、モジュール名はどう書く、とか。ここらへん、今ひとつわかりませんでした。
そしてピン定義ファイル LED.lpf。

BLOCK RESETPATHS ;
BLOCK ASYNCPATHS ;
IOBUF ALLPORTS IO_TYPE=LVTTL33 ;
LOCATE COMP "LED1" SITE "46" ;
LOCATE COMP "LED2" SITE "45" ;
LOCATE COMP "LED3" SITE "44" ;
LOCATE COMP "LED4" SITE "43" ;
LOCATE COMP "LED5" SITE "40" ;
LOCATE COMP "LED6" SITE "39" ;
LOCATE COMP "LED7" SITE "38" ;
LOCATE COMP "LED8" SITE "37" ;
LOCATE COMP "clk" SITE "21" ;
LOCATE COMP "reset" SITE "19" ;
IOBUF PORT "clk" IO_TYPE=LVTTL33 PULLMODE=NONE ;
IOBUF PORT "reset" IO_TYPE=LVTTL33 PULLMODE=UP ;
なにやら大文字小文字が混ざっていて気持ち悪い部分がありますが、ここではキニシナイことにしましょう。

ソースの修正が終わったらコンパイルとプログラムです。
そうしたら、オレンジ色でこんなメッセージが表示されました。

@W: CL190 :"D:\Users\chiyo\lattice_projects\LED\twincle_led.v":45:0:45:5|Optimizing register bit count1[7] to a constant 0 @W: CL190 :"D:\Users\chiyo\lattice_projects\LED\twincle_led.v":45:0:45:5|Optimizing register bit count1[8] to a constant 0 @W: CL190 :"D:\Users\chiyo\lattice_projects\LED\twincle_led.v":45:0:45:5|Optimizing register bit count1[9] to a constant 0 @W: CL190 :"D:\Users\chiyo\lattice_projects\LED\twincle_led.v":45:0:45:5|Optimizing register bit count1[10] to a constant 0 @W: CL190 :"D:\Users\chiyo\lattice_projects\LED\twincle_led.v":45:0:45:5|Optimizing register bit count1[11] to a constant 0 @W: CL190 :"D:\Users\chiyo\lattice_projects\LED\twincle_led.v":45:0:45:5|Optimizing register bit count1[12] to a constant 0 @W: CL190 :"D:\Users\chiyo\lattice_projects\LED\twincle_led.v":45:0:45:5|Optimizing register bit count1[13] to a constant 0 @W: CL190 :"D:\Users\chiyo\lattice_projects\LED\twincle_led.v":45:0:45:5|Optimizing register bit count1[14] to a constant 0 @W: CL190 :"D:\Users\chiyo\lattice_projects\LED\twincle_led.v":45:0:45:5|Optimizing register bit count1[15] to a constant 0

カウンタループの中での判定値が16bit幅では余るため、上位ビットは0に固定しましたよ、というメッセージです。こんな最適化もしてくれるんですね。 

プログラムしてみると、8個のLEDがワザワサと動き始めました。

そしてLチカ。

シミュレーションでクロックの間引きがちゃんと動作することがわかりましたから、あとはその出力をポートにつなげればLEDがチカチカするはず。

それではトップモジュールを追加…の前にやっておくことがあります。

せっかく作ったテストベンチですが、これはシミュレーション用のモノなので、FPGAを作成するには不要です。なので、テストベンチのプロパティを変更しておきます。

clk1000hz_test.vを右クリックしてPropertiesを開くと、どの段階でインクルードするかの指定ができます。


そこでSimulationのみを指定してやると、シミュレーションの時には使用され、Synthesis、つまり実際の論理合成では使用しないという設定ができます。

トップモジュールの追加

さてそれではトップモジュールの追加です。英語では"a top level module"というようですが。

Diamondの左側のFile ListタブでInput Filesを右クリック、Add → New File...します。Verilogを選択してファイル名を入力します。ここではtwincle_ledとでもしましょう。


ファイルが追加されたら、Verilogを記述します。


// vim: set fenc=utf-8 filetype=verilog expandtab ts=4 sts=0 sw=4:
//
// twincle LED.
//
module Twincle(clk, reset, LED1);
 input clk;
 input reset;
 output LED1;
 wire out;
 
 reg [15:0] count; // clk1mを数えるためのカウンタ
 reg _out;
 
assign LED1 = _out;

CLK1000HZ clk(
  .clk(clk),
  .reset(reset),
  .clk1m(out));

always @ (posedge out or negedge reset) begin
    if (reset == 0)
    begin
        _out = 0;
        count <= 0;
    end else
    if (count < 100 - 1)
    begin
        count <= count + 1;
    end
    else begin
       count <= 0;
       _out <= ~_out;
    end
end
endmodule
LED1はボード上のLED1を制御するための出力です。それから1msecクロックを伝えるためのwire clk、1msecを数えるためのカウンタ、そしてLED1に直結するregの_outを定義します。 次に1msecクロックをインスタンス化し、最後にalwaysでリセット時の初期化とカウントループを作ってやります。


ここまでやったら一度コンパイルします。ここでコンパイルに通らないと、後のステップが通りません。

ピンを割り当てる

さて、無事コンパイルに通ったら、次は物理的なピンアサインです。

Brevia2ボードのピンアサインはBrevia2のユーザガイドに載ってますが、ここではSpreadsheet Viewから設定してみます。

ツールバーの左端、星形と鉛筆のアイコンをクリックするとSpreadsheet Viewが開きます。


親切なことに、この段階ですでにトップモジュールの入出力が表示されています。

Brevia2ボードはすでにできあがっているボードですから、ピンアサインはすでに決まっています。今回使用するピンは以下の通りです。
  • clk : 21ピン
  • reset : 19ピン
  • LED1 : 46ピン
さらにこれらは3.3VのTTLレベルです。ということでそれを設定していきます。
ここで先ほどのコンパイルが通っていないと、Spreadsheet Viewは編集できません。

入力が終われば次のようになります。


ちなみにピンアサインはlpfファイルを直接編集することでも指定できます。

プログラムしてRun!

それではいよいよ仕上げです。
左側のProcessペインで、一番下のJEDECファイルにチェックを入れます。その状態でRunボタンを押すと…


裏でごにょごにょやったあとで、ファイルが生成されます。ここで生成されたJEDECファイルをFPGAにプログラムすることで、ハードウェアを動かすことができるようになるのです。

さてそれではボードをminiUSBケーブルでPCに繋いで、いよいよプログラムボタンを押します。ちなみにProgrammerのボタンはツールバーの真ん中よりやや左にある、ICに下矢印のアイコンです。


このボタンを押すと、Programmerのケーブルを指定するダイアログが出ます。


OKを押すと、初回に限り次のようなダイアログが出ることがあります。


ここでは「アクセスを許可する」を押して先に進むとなにかを裏で始めてるようですが、少しすると戻ってきます。
そこであらためてProgrammerタブのプログラムボタンを押します。


Programmerの矢印がオレンジだったのに対して、プログラムボタンは緑です。


こんな感じのプログレスバーが出て、しばらくすると書き込み終了です。

すると自動的にLEDが点滅を始めます。

プログラムでは、100msec点灯したら100msec消灯、つまり1周期が200msecなので、1秒間に5回の点滅をしているはずです。

もしそうなっていなかったら…LEDが点きっぱなしに見えたら…。

clk1000hz.vのparameter CNTの値が10に変更したままになっていませんか。そうすると実際に点滅しているのに、あまりにも周期が速すぎて人間には点滅に見えません。

ということで、ながながと書いてきましたが、これでようやく第一歩が踏み出せた気がします。

Lチカ、終了~。

急がば回れのシミュレーション。

ひとつひとつ、ちゃんと確認しながら進んでいくのは大事よね。というのもあるし、Diamondってどうやって使うのというのにも慣れなくてはいけないので、シミュレーションをしてみます。

まず元のソースclk1000hz.vの7行目、CNT = 25000; を CNT = 10; くらいにしておきます。半周期で25000クロックも刻まれても困るので。

そうしたら、テストベンチファイルの作成です。
左ペインのFile Listタブを選択し、Input Filesで右クリック、Add → New File...でclk1000hz_test.vというファイルを作成します。



// vim: set fenc=utf-8 filetype=verilog expandtab ts=4 sts=0 sw=4:
//
// testbench for clk1000hz.
//
//

`timescale 1ns/1ns

module CLK_TEST;
reg clk, reset;
wire out;

parameter CYCLE = 20; // 20ns (50MHz)
CLK1000HZ c1k(
  .clk(clk),
  .reset(reset),
  .clk1m(out));

always #5 clk = ~clk;

initial begin
  $monitor("%t: clk=%b, reset=%b, out=%b", $time, clk, reset, out);

                clk = 0; reset = 1;
        #10     reset = 0;
        #10     reset = 1;
  #1000 
  $finish;
end
endmodule
そうしたら上記のようなソースを入力します。
いろいろ細かい作法やら考え方、キーワードなどはその手の本を見てもらうとして、テストベンチでは入力はreg、出力はwireだそうです。そして実行する内容はinitialブロックに記述、と。
ここでは初期化としてclk=0とreset=1を、10サイクル後にリセットをおろし、その10サイクル後にリセットを解除。そのまま1000サイクルまでシミュレーションしておしまい、ということにしておきます。

次にツールバーから波形と鉛筆のアイコンをクリックします。


Simulation Wizardというウィザードです。最初に説明ダイアログが出ますから、これはそのままNextをクリックします。
次に、Simulation Project Nameを入力するように求められます。


ここではSimulatorが選べるようになって…いません。無償版ですからね。Active-HDLしか選べません。なので、asimulなどという名前を適当につけてみました。すると、そんなプロジェクトはないけれど作りますかというメッセージが出るので、Yesをクリックします。

次にProcess Stageを選択するようになっていますが、ここも選択できるのはひとつだけなのでそのままNext。するとソースファイルを指定するように出てきますので、これもそのままNextです。


次はParse HDL files for simulationというダイアログ。ここではトップモジュールを指定できるようになっていますが、現在は一つしか選べません。ここもNext。


最後に諸設定を確認するダイアログが出ます。


左下のチェックボックスはすべてチェックした状態でFinishしてみます。
するとActive-HDL 9.2というのが立ち上がり、シミュレーションをして…


なにも波形が出てきません。左ペインの信号のところもステートが不明になっていたりします。それはそうです、テストベンチのコンパイルをしてないですから。

Active-HDLのDesignからCompile Allをクリックして再度シミュレータを走らせると、ちゃんと出ました。


波形も出ています。が、よくよく数えてみるとclkが11個でoutが切り替わっています。どうやらなにか間違っているようです。

よくよくソースを見てみれば、if (count < CNT)ではダメですね。ここはCNT-1でないと。
ソースを修正してコンパイルし、再度シミュレーションしてみました。


どうやらよさそうですね。やっぱり急がば回れは重要です。

先ずチュートリアルより始めよ。

なんで休日の昼間にこんなことやってるのかというと、今日は台風が近づいてきているので外は雨なんです。東京なんか大雨です。特別警報が出ちゃうかも、的な大雨のようです。ていうか京都とかそっちのほうは大変なことになってるようです。

それはさておき。

本来ならたぶんチュートリアルを利用して、そこから適当にいじっていくのが王道だとは思うんですが、どうもXP2を使ったBrevia2用ではずばりのチュートリアルはないようです。「先ず隗より始めよ」なんてのをもじってみたんですが、一筋縄ではいかないようで。

ということで方針を一部変更して、WEBにいろいろとある情報をつまみ食いしつつ進めていこうかと思います。ちなみにどんな感じで進めていくかというと、

  • Lチカ (LEDを点滅させてみる)
  • シミュレーションしてみる
  • UARTを組み込んでみる (巫女さん抜きで)
  • 巫女さんを組み込んでみる (Lチカ編)
  • 巫女さんを組み込んでみる (JTAG UART編)
  • 巫女さんを組み込んでみる (UART編)
  • TeraTermで巫女さんとお話ししてみる (UART応用編)
  • 巫女さんと無線でしゃべってみる (XBee編)
  • 巫女さんに温度を測ってもらう (温度センサ編)
なんてことを考えたりしてて。ぼちぼちやっていこうかと思ってますけど。

それでは始めましょう。

方針を決めます

まず、どうやってLチカさせようか考えてみます。

一定間隔で点いたり消えたりするわけですから、タイマもしくはカウンタが必要です。

Brevia2ボードのクロックは50MHzなので、使いやすくするために周波数を下げる必要もあります。ここは汎用的に1000Hz(1msec)を出力するようなクロックモジュールを作ってみましょう。ついでに1Hzクロックも作っておきましょうか。

このクロックモジュールは入力が原クロックとリセット、出力が低周波クロックになります。クリアや初期値ロード、アップダウンはとりあえず置いときます。このモジュールを複数並べれば複数個のLEDを別々にチカチカさせることもできるように考えます。

トップモジュールではこのクロックモジュールをインスタンス化して、さらにもう一段カウンタつけて点滅間隔を調節し、IOポートにアサインすればいいわけですね。

こうして考えてみると、実はそんなにむずかしくなさそうです。

プロジェクトにファイルを追加する

先般作ったプロジェクトに新しいファイルを追加します。


Input Filesの上で右クリックして、Add→New File...を選択するとダイアログが出ますから、そこでVerilog Filesを選択してファイル名を入力し、左下の"Add to implementation"にチェックを入れてNewを押します。ここではファイル名はclk1000hz.vとしています。


ファイルを追加したら編集用に開きます。
ちなみにファイルの上で右クリックし、"Open With"をクリックするとファイルを開く外部アプリケーションを設定できるようです。Diamond標準のSource Editorは今ひとつ残念なできなので、使い慣れているVimを指定しておきます。


OKを押すと外部エディタで開きます。まだ空っぽなのでなにもありません。


さて、50MHzというのは1秒間に5千万回振動するわけですから、これを1msecで切り替わるようにするにはこの1000分の1、つまり50,000の半周期、すなわち25,000ごとに出力が反転すればいいわけです。となるとカウンタのビット数は、16bitで65,535まで、15bitで32,767まで数えられるので、15bitあればいいわけですが、区切りが悪いので16bitにしてしまいましょう。

とりあえず書いてみたclk1000hz.vは以下のようなモノになります。


// vim: set fenc=utf-8 filetype=verilog expandtab ts=4 sts=0 sw=4:
//
// generate 1000Hz clock from 50MHz osc input.
//

module CLK1000HZ (clk, reset, clk1m);
    parameter CNT = 25000;

    input clk;
    input reset;
    output clk1m;
    reg clk1m;
    reg [15:0] count;

    always @ (posedge clk or negedge reset) begin
        if (reset == 0)
        begin
            count <= 0;
            clk1m <= 0;
        end else
        if (count < CNT)
        begin
            count <= count + 1;
        end
        else begin
            count <= 0;
            clk1m <= ~clk1m;
        end
    end
endmodule

moduleの定義はいいとして、clk1mがoutputとregで二回定義されていますが、これがミソ、のようです。17行目ではresetならカウンタのリセットをして、clk1mも0に初期化。あとはCNTと比較しつつcountを増やしていき、CNTになったらclk1mを反転、というだけです。


vimだとエラー行に飛ぶのに不都合があることがわかったので、泣く泣く標準のエディタに戻しました。

まだモジュールが一つだけですが、これを早速コンパイルしてみましょう。

コンパイルする

左ペインの下にあるタブのうち、Processをクリックします。すると下のようになっているので、


Translate DesignをハイライトしてからツールバーにあるRunボタンをクリックします。


するとTranslate Designのところまで緑色のチェックがつき、コンパイルが終了したことになります。

ここまできたら、次は急がば回れ、シミュレーションで動作を確認してみましょう。

もうひとつその前に。

次はVerilogソースを書いていく、というステップになるんですが、その前に。
Bloggerでソースコードを出すにはどうするかを解決せねば。

blogger source」でググってみると、SyntaxHighlighterというのが見つかりました。JavaScriptで書かれているそうです。WordPressだとGeSHiをラッピングして使うものがあるんですが、Bloggerで使うことを記した記事はほとんど見つからず、しかもちょっとトリッキーな方法で使うような感じ。

SyntaxHighlighterはいくつかインストール方法について記述したページがあるので、その通りにやってみました。

#include 

void main() {
    printf("Hello, world.\n");
}

ところがBloggerは勝手にタグを変換してしまうようで、どうにもうまくいきません。 記事の編集は左上のほうに「作成」ボタンと「HTML」ボタンがあるんですが、include文のあとの<stdio.h>を勝手に変換してしまったりして。ソースコードを貼り付ける際には<pre />ではダメかもですね。

なので、<pre />はあきらめて<script />タグで挟んでみることにしました。

こちらだとよさそうですね。

ただ、ソースコードを貼り付ける際にはいちいちHTMLモードに切り替えないとダメのようです。あるいは最初からHTMLモードで編集するように設定を変更する方法はあるのかしら。 それから…このSyntaxHighlighterはVerilogはサポートしていないようです。おろろ。 こちらのページにカスタムブラシを作成する方法が記載されているので、作ってみるというのもアリかもしれません。でもやっぱりGeSHiが使える方がうれしいなぁ。 一応今後のためにテンプレート貼っておこう。
<script class="brush: c" type="syntaxhighlighter"><![CDATA[
 ここにコードを貼り付ける
]]></script>

LEDプロジェクトを作成。

実は自分、Verilog初心者です。いや、ちょっと言い換えると、Verilog初心者です。
これまでは仕事でもプライベートでも、回路図引いたり基板作ったりプログラムしたりはいろいろとやったんですが、Verilogだけは縁がなくてやったことがありません。いや、それもちょっと正確じゃないですね。HDLはやったことがありません、というのが正確。したがってここからはいろいろと試しながらやっていく、という形になるかと思います。でもってこれからやる言語はVerilog HDLです。とりあえず。Active HDLとか興味はあるけれど、まずは基本を押さえておかないとね。

それはさておき。

さてまずはDiamondを起動してプロジェクトを作成しましょうか。


ハイライトされているのが新規プロジェクトを作成するメニューです。ここをクリックすると、New Projectダイアログが出てきます。


Nextをクリックするとプロジェクト名とプロジェクトのディレクトリを指定するダイアログになります。
Locationはプロジェクトのディレクトリのことで、このロケーションの直下にいろいろとファイルが作られます。なので、以下のように設定します。


Project NameはLED、Locationはこれからいろんなプロジェクトを入れていくことになる親ディレクトリの下にLEDというディレクトリを作り、さらにImplementation (実装)はさらにその下のLEDというディレクトリに置く、という指定です。Nextボタンをクリックします。
次のページは追加するソースの指定ですが、まだソースはないのでそのままNext。するとデバイスの指定ページになります。ここではBrevia2ボードを使うので、以下のように指定。


次のページではSynthesisツールを指定しますが、デフォルトのSynplify Proを指定しておきます。

最後に確認ページが出るので、内容を確認してFinishボタンをクリックします。


するとプロジェクトが作成され、Diamondが以下のような表示になります。


今ひとつディレクトリ指定が二重になっていてかっこわるい気もしますが、とりあえずこうしないとファイルがトップディレクトリにあふれてしまいますのでしかたないですね。

ついでに言えばこのDiamond、エディタがお世辞にもよくできているとは言い難いモノなので、一旦ソースを作成して保存し、以後の編集はvimを使いたいと思います。

そのまえにMicosysの設定を。

Micosysなんて略しちゃっていますが、正確にはLatticeMico Systemということになるのかな。

ちなみにたぶん英語読みするとマイコシステムになる気がしますが…キニシナイ。

先ほど作ったバッチファイルを起動すると、Micosysが起動するといいつつ実はEclipseが起動します。なので、まず最初にworkspaceを指定しなくてはなりません。

特に不都合がなければ、workspaceの場所はデフォルトでかまいません。何度も訊かれるのが鬱陶しければ"Use this as the default..."のチェックボックスをチェックしてOKをクリックします。するとEclipseが起動しますが、少々見慣れない画面です。


左上のツールバーのところにMSBとかC/C++とかありますが、ここらへんがカスタマイズされている部分なのでしょう。

ちなみに例のバッチファイルではJREとしてMicosysに付属のものを使用するように設定を変更しています。うちの環境では別にJREもインストールしているので、そちらを使うといろいろとやっかいなことになるため、ちゃんと切り替えるようにしているのです。

ともあれこれでMicosysが起動するところまでは確認できました。のでので。Lチカやってみましょう。


出しちゃって繋いじゃって。

ソフトウェアのインストールが終わったら、いよいよハードウェアを箱から出します。
箱といってもBrevia2ボードはブリスターパックに入っているだけなので、パックを開ければおしまい。

ちなみにパックの中には、ボードとゴム足、miniUSBケーブル、台紙とFTDIチップのペラ紙一枚。味も素っ気も化粧っ気もありません。さすが巫女さん。いや、まだ巫女さんはインストールしてないですけど。

早速添付のminiUSBケーブルでPCに接続すると、miniUSBコネクタ横の緑のLEDと、8つ並んだ赤いLEDが点灯し、なぜか01、02、07の赤LEDが消灯します。どういう理由でこうなるのかわかりませんが、まあそういうことにしておきましょう。

そうそう、実は載っているICにはMaximのMAX6818というOctal Debouncerが抜けていました。このICは±15kVのESD保護と、タクトスイッチのデバウンス(別の言い方をすればチャタリング除去)を行うICで、これを入れておけばスイッチのチャタリング除去のために1msecごとに3回読んで、というようなソフトウェア処理をしなくてもよいことになります。
要はメカ的なことは置いといて、単純なロジックデバイスとしてスイッチを利用できる、と。

まあむずかしいことは置いといて、Brevia2ボードをPCに接続すると自動的にドライバのインストールが始まります。ドライバの設定によっては下の図のようにUSB Serial Portが見つからない場合もありますが、Windows Updateから検索する設定にしてやってしばらくするとインストールは終わります。



端っこに1つだけ離れているタクトスイッチはリセットボタンです。これを押すとやっぱり赤LEDが全点灯したあとで3つだけ消灯します。うーん。

それでは次は定番のLチカですね!

…だってLEDとスイッチしか載ってないしできるのはそれぐらいしか…。

ソフトウェアのインストール。

ライセンスの取得

Lattice FPGAの開発ツールはDiamondという統合開発環境で、基本的には無償で利用できます。ただし、利用を開始するにはライセンスが必要です。

ライセンスの取得は無料ですが、そのためにはLattice WebサイトでのアカウントとDiamondを利用するPCのMACアドレスとが必要になります。

アカウントのほうはLatticeのトップページから上の方にあるRegisterをクリックすることで、必要事項を入力してやれば可能です。企業名を入力するフィールドがありますが、個人の場合にはPersonalとでも入れておけばいいのではないでしょうか。ウソではないし、ダメならあとで何か言ってくるでしょう。
郵便番号と電話番号は有効な表記法でないとダメなので、空欄にしておきます。必須ではないようですし。

入力を終えて一番下のボタンを押すと、確認用のメールが送られてきます。そのメールにある"Activate My Account"のリンクをクリックすると、ユーザ登録が終了です。

ユーザ登録が終われば、ライセンスの要求ができるようになります。上記Diamondのページから、Licensingのタブを表示すると"Click here to request your license"というリンクがありますから、そこをクリックします。するとNICのPhysical Addressを入力するフィールドが出てきますので、コマンドプロンプトを開いて "ipconfig /all" とすればNICの情報が表示されるので、そこから物理アドレスをコピー&ペーストして、それから一応注意書きを読んでからチェックボックスにチェックを入れて、"Generate License"をクリックします。

すぐにLatticeからメールが送られてくるので、そのメールに添付されているlicense.datファイルを保存しておきます。

ダウンロードとインストール

次にソフトをダウンロードしてインストールします。上記Diamondのページから、Downloadsタブを開くといくつか種類が出てきますから、自分の環境にあったのを選択してダウンロードします。
現在のバージョンはDiamond 2.2なので、自分の場合にはDiamond 2.2 64-bit for WindowsのZIPファイルと、ついでにLatticeMico System for Diamond 2.2 Windowsもダウンロードしておきます。

ダウンロードが終わったらZIPをほどいて、出てきたEXEファイルを実行してインストールします。インストール先はc:\lsccがデフォルトですが、パスにスペースや日本語を含んでなければどこでもいいはずです。ついでにMico Systemもインストールしてしまいましょう。

インストールが終わったら、先ほどのlicense.datファイルの置き場所を示す環境変数を設定します。
うちの場合はc:\lsccに置いておき、システムのプロパティ → 詳細設定 → 環境変数で指定してやります。


ちなみにシステムのプロパティは、スタートメニュー → コンピューターを右クリック → ポップアップメニューの一番下のプロパティをクリックすればシステムのコントロールパネルが出ますので、そこから「システムの詳細設定」をクリックすれば出てきます。

ライセンスファイルの置き場所は、Diamondがバージョンアップしても大丈夫なようにlsccの直下に置くようにしています。

さていよいよDiamondの起動です。
デスクトップのアイコンから起動すると、ちゃんと起動することを確認します。



Cygwinとの共存

ところでうちの環境にはcygwinがインストールされています。が、MicoSystemは自分用にcygwinをインストールしています。これが実は悪さをして、後々コンパイル時に意味不明のエラーに悩まされることになります。

そこで自分は起動用にバッチファイルを作ることにしました。ついでにJavaの環境変数も変更できるようにしておきます。自分の環境では、c:\cygwin64にcygwinがインストールされています。余談ですが、この夏からcygwinでは64bit版もリリースするようになりましたね。

diamond-startup.bat

@echo off
setlocal
set HOME=C:\Users\[自分のホームディレクトリ]
set PATH=%PATH:c:\cygwin64\bin;=%
set CYGPATH=
set JAVA_HOME=C:\lscc\diamond\2.2_x64\jre64
C:\lscc\diamond\2.2_x64\bin\nt64\pnmain.exe
endlocal

micosys-startup.bat
@echo off
setlocal
set HOME=C:\Users\[自分のホームディレクトリ]
set PATH=%PATH:c:\cygwin64\bin;=%
set CYGPATH=
set JAVA_HOME=C:\lscc\diamond\2.2_x64\jre64
C:\lscc\diamond\2.2_x64\micosystem\launchmicosystem.exe
endlocal

この2つのバッチファイルを、c:\lscc\diamondに置いて、エクスプローラからファイルを右クリック、「送る」でデスクトップにショートカットを作り、名前とアイコンを変更してわかりやすいようにしておきます。



アイコンはそれぞれpnmain.exeとlaunchmicosystem.exeのものを指定します。
これで一旦環境は整いました。

巫女さんて誰。

巫女さんとは、Lattice Semiconductorが提供している32bit マイクロプロセッサのソフトコアのことです。実在の人物とは関係…ないと思います。

さてさて。
いきなり始めてしまってどうしよう、なんて思っていたりもするんですが。

手元にあるものを適当に組み合わせて、あんまりお金をかけずに適当に遊んでみましょうか、くらいの気持ちで。もうちょっと白状してしまうと忘れっぽい自分用の備忘録代わりとして。巫女さんと遊んでみましょうか、という感じで。

能書きはこのくらいにして、巫女さんと遊ぶためのお道具についてざっと概観してみます。

Latticeが販売しているFPGAの開発キットBrevia2ボードは、digikeyなどで5,000円ちょっとで入手できるFPGAの開発ボードです。同様にAlteraが出しているDE0ボードと比べると値段は1/3程度。ただ、DE0ボードがいろいろと拡張を考えられた作りになっているのに対して、Brevia2はシンプルで素っ気ない作りになっています。4連のディップスイッチと4つのタクトスイッチ、8つのLEDと10ピンおよび40ピンの2.54mmピッチのヘッダくらいしかありません。なにかやりたければ自分で作ってね、というボードです。

ICとして載っているのはLatticeXP2 FPGAの中でも軽量級のLFXP2-5E-6TN144Cと50MHzの発振器、1MbitのSRAMに2MbitのSPI Flash、それからFTDIのUSB JTAGコントローラのみです。とてもシンプル。シンプルだから逆に萌えます。いや燃えます。

LFXP2-5E-6TN144Cは144ピンのTQFPパッケージで5K LUT、166kbitの組み込みRAMがあり、最近のFPGAと同様に外部IOではLVDSなどもサポートしています。

それでは早速始めてみましょうか。

Windowsでシンボリックリンクを試してみる。

きっかけは、1つのファイルを別の名前で起動したら違う動きになるようなスクリプトを書く、でした。  busybox なんかでは、同じ実行形式ファイルの名前を、lsにすればlsと同じ、cpとすればcpと同じ動作をするようにしてますが、Pythonスクリプトでそれと同じように argv...