2009年3月10日 星期二

Bluespec Helloworld

Helloworld Version 1
一個Bluespec設計應該是多個packages的集合,但在這個範例程式中我們將只會有一個package。
因此我們先開始寫一個叫"FirstAttempt"的package,剛好這是一個練習加註解去解譯這個程式的好機會。
程式如下:
package FirstAttempt;
//My first design in the cool Bluespec language
endpackage

package名稱必需要跟檔名相同,因此我們將上面的程式儲存為"FirstAttempt.bsv"。
請使用下面的命令去編譯它:
bsc FirstAttempt.bsv
它應該可以很正確的被編譯成功,並且沒有任何的錯誤。

然而一個package至少應該包含了一些類型及常數的初使化定義,及一些module的定義。
比如下個範例,我們定義了一個字串,讓我們將來可以將它輸出到螢幕上。
package FirstAttempt;
//My first design in the cool Bluespec language
String s = "Hello world";
endpackage

接下來我們思考一下在這個範例裏的主要module。我們要思考的是它將如何和其它的硬體進行溝通呢?
不管這些硬體都設計在這個模組裏,或是和外部的硬體都需要進行溝通的。因此我們必需決定它的溝通介面。
但在我們這個範例中,是可以完全不理會溝通介面,因此我們並沒有去定義它。

為了方便起見,所有的modules的命名都以"mk"開始命令,並且將這個主要module宣告在package裏,
範例程式如下:
package FirstAttempt;
//My first design in the cool Bluespec language
String s = "Hello world";

module mkAttempt;
endmodule
endpackage

上面的範例就是最基本的一個package加一個module。

接下來我們要為這個module加入rules(規則),而這個rules將直接定義在module的內部。
(通常我們應該都會為module加入interface(界面)以提供跟外界互動,但在這個範例裏我們沒有這麼做)。
這個範例裏我們只有一條規則,規則名稱為"say_hello",它將會使用系統命令"$display"執行輸出文字訊息。
接著我們要將它合成,以進行模擬其執行結果。
範例程式如下:
package FirstAttempt;
//My first design in the cool Bluespec language
String s = "Hello world";

(* synthesize *)
module mkAttempt(Empty);
rule say_hello;
$display(s);
endrule
endmodule
endpackage

Simulation(模擬)
將我們的package轉成Verilog RTL:
bsc -verilog FirstAttempt.bsv
(產生)Verilog file created: mkAttempt.v

產生的verilog檔內容如下
`ifdef BSV_ASSIGNMENT_DELAY
`else
`define BSV_ASSIGNMENT_DELAY
`endif

module mkAttempt(CLK,
RST_N);
input CLK;
input RST_N;

// handling of system tasks

// synopsys translate_off
always@(negedge CLK)
begin
#0;
$display("Hello world");
end
// synopsys translate_on
endmodule // mkAttempt

將mkAttempt.v轉成可執行的模擬程式
bsc -o sim -e mkAttempt mkAttempt.v
./sim

mkAttempt指向我們所設計裏的top-level module。
請試看看它的執行結果,你將會看見每個clock cycle都會執行一次rule,所以會在螢幕上一直印出"Hello world"。

執行畫面如下:

Helloworld version 2
如果你有執行它,你應該發現了,程式並不會停止執行,如果想改成印一次Hello world然後停止程式,
修改程式碼如下:
package FirstAttempt;
String s = "Hello world";

(* synthesize *)
module mkAttempt(Empty);
rule say_hello;
$display(s);
$finish(0);
endrule
endmodule
endpackage


Helloworld version 3
接著我們再改個版本,使它可以執行"Hello world"的命令5次,為了這個目的,我們必需要有一個計數用的暫存器。將計數器宣告在在這module裏,在rule之前。這個計數器需要計數到5,因此3 bits就夠用了,所以我們可以用UInt#(3)來宣告,它的意思是使用無號的3位元整數。我們也指定了暫存器的初使值為0(它指的是一發生reset時就將0放回暫存器中)。
宣告使用計數器程式如下:
package FirstAttempt;
//My first design in the cool Bluespec language
String s = "Hello world";
(* synthesize *)
module mkAttempt(Empty);
Reg#(UInt#(3)) ctr <- mkReg(0);

rule say_hello;
$display(s);
$finish(0);
endrule
endmodule
endpackage

接著我們必需控制什麼時候數值,什麼時候結束。
package FirstAttempt;
//My first design in the cool Bluespec language
String s = "Hello world";
(* synthesize *)
module mkAttempt(Empty);
Reg#(UInt#(3)) ctr <- mkReg(0);

rule say_hello;
ctr <= ctr + 1;
$display(s);
if (ctr == 4) $finish(0);
endrule
endmodule
endpackage

Helloworld version 4
package FirstAttempt;
//My first design in the cool Bluespec language
String s = "Hello world";
(* synthesize *)
module mkAttempt(Empty);
Reg#(UInt#(3)) ctr <- mkReg(0);

rule end_run(ctr == 5);
$finish(0);
endrule

rule say_hello(ctr < 5);
ctr <= ctr + 1;
$display(s);
endrule
endmodule
endpackage

Helloworld version 5
package FirstAttempt;
//My first design in the cool Bluespec language
String s = "Hello world";
(* synthesize *)
module mkAttempt(Empty);
Reg#(UInt#(3)) ctr <- mkReg(0);

rule end_run(ctr == 5);
$finish(0);
endrule

rule say_hello(ctr < 5);
$display(s);
endrule

rule inc_ctr;
ctr <= ctr + 1;
endrule
endmodule
endpackage

自己比較一下version 3/4/5的差異性吧^^

原始官方文件:


資料來源:
Learning Bluespec Wiki
Learning Bluespec
MIT開放式課程

一個小故事讓我們明白資金流通的意義

“又是炎熱小鎮慵懶的一天。太陽高掛,街道無人,每個人都債台高築,靠信用度日。這時,從外地來了一位有錢的旅客,他進了一家旅館,拿出一張1000 元鈔票放在櫃檯,說想先看看房間,挑一間合適的過夜,就在此人上樓的時候---- 店主抓了這張1000 元鈔,跑到隔壁屠戶那裡支付了他欠的肉錢...