2011年5月21日 星期六
一個加了Waveform Dump的pipe例子
#include "systemc.h"
typedef sc_biguint<8> atom; // Value to be pipe delayed.
//==============================================================================
// dpipe - DELAY PIPELINE FOR AN ARBITRARY CLASS:
//==============================================================================
template
SC_MODULE(dpipe) {
typedef sc_export > in; // To pipe port type.
typedef sc_export > out; // From pipe port type.
SC_CTOR(dpipe)
{
m_in(m_pipe[0]);
m_out(m_pipe[N-1]);
SC_METHOD(rachet);
sensitive << m_clk.pos();
}
void rachet()
{
for ( int i = N-1; i > 0; i-- )
{
m_pipe[i].write(m_pipe[i-1].read());
}
}
sc_in_clk m_clk; // Pipe synchronization.
in m_in; // Input to delay pipe.
out m_out; // Output from delay pipe.
sc_signal m_pipe[N]; // Pipeline stages.
};
// Testbench reader of values from the pipe:
SC_MODULE(Reader)
{
public:
SC_CTOR(Reader)
{
SC_METHOD(extract)
//SC_THREAD(extract);
sensitive << m_clk.pos();
dont_initialize();
}
protected:
void extract()
{
read_out_data = m_from_pipe.read() ;
cout << "Time :" <<
sc_time_stamp().to_double() << ": " << m_from_pipe.read()
<< endl;
}
public:
sc_in_clk m_clk; // Module synchronization.
sc_in reset;
sc_in m_from_pipe; // Output from delay pipe.
sc_signal read_out_data;
};
// Testbench writer of values to the pipe:
SC_MODULE(Writer)
{
SC_CTOR(Writer)
{
SC_METHOD(insert)
sensitive << m_clk.pos();
m_counter = 0;
}
void insert()
{
//wait(2, SC_NS);
m_to_pipe.write(m_counter);
m_counter++;
cout << "Time :" << sc_time_stamp().to_double() <<
" write data => " << m_counter << endl;
}
sc_in_clk m_clk; // Module synchronization.
sc_in reset;
atom m_counter; // Write value.
sc_inout m_to_pipe; // Input for delay pipe.
};
// Main program
int sc_main(int argc, char* argv[])
{
//sc_clock clock(;
sc_signal reset;
sc_signal m_out_data;
sc_clock clock("clock", 3, SC_NS, 0.5, 7, SC_NS, 0);
sc_trace_file *wf = sc_create_vcd_trace_file("sc_cycle");
wf->set_time_unit(100, SC_PS);
sc_trace(wf, clock, "clock");
// sc_trace(wf, reset, "reset");
dpipe delay("pipe");
Reader reader("reader");
Writer writer("writer");
delay.m_clk(clock);
reader.m_clk(clock);
reader.m_from_pipe(delay.m_out);
writer.m_clk(clock);
writer.m_to_pipe(delay.m_in);
sc_trace(wf, reader.read_out_data, "fifo_out_data");
sc_trace(wf, writer.m_counter, "fifo_in_data");
sc_start(30, SC_NS);
sc_close_vcd_trace_file(wf);
return 0;
}
一個用SystemC寫的Power on reset
SC_MODULE (power_on) {
sc_signal reset;
void por() {
wait (3, SC_NS);
reset = sc_bit('1');
wait (5, SC_NS);
reset = sc_bit('0');
}
SC_CTOR(power_on) {
SC_THREAD(por);
}
};
int sc_main (int argc, char* argv[]) {
sc_clock clock ("my_clock", 1, 0.5, SC_NS);
power_on my_power_on("My_POWER_ON");
sc_trace_file *wf = sc_create_vcd_trace_file ("sc_test");
sc_trace(wf, clock, "clock");
sc_trace(wf, my_power_on.reset, "reset");
sc_start(50, SC_NS);
sc_close_vcd_trace_file(wf);
return 0;
}
已經加上了Waveform Dump,以方便觀察變化
參考網頁
http://www.dzwu.net/eda/07117292008.html
一個兩個function的SC_Module
SC_MODULE (first_counter) {
sc_in_clk clock ; // Clock input of the design
sc_in
sc_in
sc_out(sc_uint<4>); counter_out; // 4 bit vector output of the counter
//------------Local Variables Here---------------------
sc_uint<4> count;
//第一個function
// Below function implements actual counter logic
void incr_count () {
if (reset.read() == 1) {
count = 0;
counter_out.write(count);
// If enable is active, then we increment the counter
}
else if (enable.read() == 1) {
count = count + 1;
counter_out.write(count);
}
} // End of function incr_count
// Below functions prints value of count when ever it changes
void print_count () {
cout << "@" << sc_time_stamp() <<
" :: Counter Value " << counter_out.read() << endl;
}
SC_CTOR(first_counter) {
// Edge and level sensitive
SC_METHOD(incr_count);
sensitive << reset;
sensitive << clock.pos();
// Level Sensitive method
SC_METHOD(print_count);
sensitive << counter_out;
} // End of Constructor
}; // End of Module counter
SC_MODULE的設計範例
#include "systemc.h" SC_MODULE(dff) {
sc_indin; // Data input of FF
sc_inclk; // Clock input of FF
sc_outout; // Q output of FF
void implement() { // Process that implements DFF
dout = din;
}
SC_CTOR(dff) {
implement
cout << "Executing new" << endl;
SC_METHOD();
sensitive << reset;
// sensitive << clock.pos(); 兩種寫法皆可
sensitive_pos << clk; // Call implements() at every pos edge of clk
}
};
一個用SystemC寫的Counter
#include
SC_MODULE (counter) {
sc_in
sc_in
sc_out
sc_unit<4> cout;
void counter_in(){
if (reset)
cout = 0;
else
cout ++;
out_value.write(cout);
}
SC_CTOR(counter) {
SC_MODULE(counter_in);
sensitive << clock.pos();
sensitive << reset;
}
};
SC_MODULE (power_on) {
sc_signal
void por() {
wait (3, SC_NS);
reset = sc_bit('1');
wait (5, SC_NS);
reset = sc_bit('0');
}
SC_CTOR(power_on) {
SC_THREAD(por);
}
};
int sc_main (int argc, char* argv[]) {
sc_signal
sc_signal
sc_clock clock ("my_clock", 3, 0.5, SC_NS);
counter my_cnt("My_COUNTER");
power_on my_power_on("My_POWER_ON");
my_power_on.reset(reset);
my_cnt.clock (clock);
my_cnt.reset (reset);
my_cnt.out_value(cout_value);
sc_trace_file *wf = sc_create_vcd_trace_file ("sc_test");
sc_trace(wf, clock, "clock");
sc_trace(wf, reset, "reset");
sc_trace(wf, my_cnt.cout, "my_cnt_value");
sc_trace(wf, cout_value, "count_value");
sc_start(150, SC_NS);
sc_close_vcd_trace_file(wf);
return 0;
}
SystemC 時序控制的方法
我是從UserGuide上整理出來的
也就是我們可以有下面兩種產生clock的方法
或者說是任意的波形
第一種方法
For examples, assume you have defined a clock as:
sc_clock clk(“my clock”, 20, 0.5);
You can simulate the generation of clocks for 200 default time units by calling
sc_start(200);
第二種方法
sc_signal
sc_initialize(); //
for (int i = 0; i <= 200; i++)
clock = 1;
sc_cycle(10);
clock = 0;
sc_cycle(10);
}
另外關於非同步的時序
可參考我改寫的例子
此處可以寫出 VCD檔來
#include
int sc_main(int argc,char** argv){
// sc_clock clock;
sc_signal
sc_trace_file *wf = sc_create_vcd_trace_file("sc_cycle");
sc_trace(wf, clock, "clock");
sc_trace(wf, reset, "reset");
sc_initialize();
// Let the clock run for 10 cycles
for (int i = 0; i <= 200; i++) {
clock = 1;
sc_cycle(10);
clock = 0;
sc_cycle(10);
}
// Inject asynchronous reset
clock = 1;
sc_cycle(5);
reset = 1;
sc_cycle(5);
clock = 0;
sc_cycle(10);
clock = 1;
sc_cycle(5);
reset = 0;
sc_cycle(5);
clock = 0;
sc_cycle(10);
// Now let the clock run indefinitely
for (int i=0 ;i<300;i++) {
clock = 1;
sc_cycle(10);
clock = 0;
sc_cycle(10);
}
sc_close_vcd_trace_file(wf);
return 0;
}
Module Instanciating的兩種方法
refer web
#include "systemc.h"
#include "first_counter.cpp"
int sc_main (int argc, char* argv[]) {
sc_signal
sc_signal
sc_signal
sc_signal ( sc_uint<4> )counter_out;
int i = 0;
// Connect the DUT
first_counter counter("COUNTER");
// Here ports are connected by position
counter(clock,reset,enable,counter_out);
// Rest of the body of the testbench
return 0;// Terminate simulation
}
#include "systemc.h"
#include "first_counter.cpp"
int sc_main (int argc, char* argv[]) {
sc_signal
sc_signal
sc_signal
sc_signal
int i = 0;
// Connect the DUT
first_counter counter("COUNTER");
// Here ports are connected by name
counter.enable(enable);
counter.reset(reset);
counter.clock(clock);
counter.counter_out(counter_out);
// Rest of the body
return 0;// Terminate simulation
}
sc_bigint 及 sc_biguint
在实际设计中,有时候需要宽度大于64的整型数据类型,SystemC引入了sc_bigint和sc_biguint。sc_bigint和sc_biguint的宽度可以从1到任意值,与sc_int和sc_unit相比其仿真速度要慢的多,因此如果不是在实际设计中,有时候需要宽度大于64的整型数据类型,SystemC引入了sc_bigint和sc_biguint。sc_bigint和 sc_biguint的宽度可以从1到任意值,与sc_int和sc_unit相比其仿真速度要慢的多,因此如果不是必要,就不应该使用 sc_bigint和sc_biguint而是尽量使用sc_int和sc_unit。
由于要考虑任意精度,sc_bigint和sc_biguint仿真速度大大下降。在sc_constants.h中,用户可以根据自己的需要定义 SC_MAX_NBITS,以约束sc_bigint和sc_biguint的最大宽度,这样可以提供2~3倍的仿真速度增加,这个常量在默认的情况下是 没有定义的,用户可以根据自己的需要进行修改。SystemC推荐的SC_MAX_NBITS值应该为BITS_PER_DIGIT 的整数倍。BITS_PER_DIGIT在sc_nbdefs.h定义,它的值为30。
下面的代码将SC_MAX_NBITS定义为17倍的BITS_PER_DIGIT。
#define SC_MAX_NBITS 510 // 17 * BITS_PER_DIGIT
example
sc_biguint<128> b1;
sc_biguint<64> b2;
sc_biguint<152> b3;
b3 = b1*b2;
b1*b2运算的结果有192位,只有低152位被赋值给b3。
sc_bigint和sc_biguint、sc_int和sc_unit、C++固有整型数据可以混合使用。
下面是整理了例子
#include
int sc_main (int argc, char* argv[]) {
sc_bigint<128> large_size ;
// Shift operator
large_size = 1000 << 2;
cout <<"Value of large_size : " << large_size << endl;
large_size = 1000 << 31;
cout <<"Value of large_size : " << large_size << endl;
sc_biguint<128> a = 30000;
sc_biguint<128> b = 20000;
sc_biguint<256> c = 0;
sc_biguint<10> d = 0;
// multiplication operator
c = a * b*a*b*a*b*a*b*a*b;
d = a*b;
cout <<"Value of c : " << c << endl;
cout <<"Value of d : " << d << endl;
return 1;
}
Value of large_size : 4000 //放大四倍
Value of large_size : 0 ///雖然sc_bigint指定128bits,但是卻不能做operator運算超過32bits
Value of c : 77760000000000000000000000000000000000000000
Value of d : 512 //如果結果的bit數不足,則只會留存可記錄的bit結果
Example sc_uint
#include
int sc_main (int argc, char* argv[]) {
sc_uint<1> bit_size = 0;
sc_uint<4> nibble_size = 1;
sc_uint<8> byte_size = 2;
sc_uint<32> dword_size = 3;
//sc_int<128> addr; sc_int can not be more then 64
// Perform auto increment
dword_size ++;
cout <<"Value of dword_size : " << dword_size << endl;
// Terse method addition
byte_size += nibble_size;
cout <<"Value of byte_size : " << byte_size << endl;
// Bit selection
bit_size = dword_size[2];
cout <<"Value of bit_size : " << bit_size << endl;
// Range selection
nibble_size = dword_size.range(4,1); // 如果超過範圍只會影響到可用的bit
cout <<"Value of nibble_size: " << nibble_size << endl;
// Concatenated
dword_size = (byte_size,byte_size);
cout <<"Value of dword_size : " << dword_size << endl;
nibble_size.range(1,2) = nibble_size.range(2,1); //sc_uint不能反向使用
//此處要看IEEE1666-2005 page194
cout <<"Value of nibble_size: " << nibble_size << endl;
return 1;
}
SystemC 2.2.0 --- Mar 18 2011 18:40:28
Copyright (c) 1996-2006 by all Contributors
ALL RIGHTS RESERVED
Value of dword_size : 4
Value of byte_size : 3
Value of bit_size : 1
Value of nibble_size: 2
Value of dword_size : 771
Error: (E5) out of bounds: sc_uint[_base] part selection: left = 1, right = 2 violates 0 <= right <= left <= 3
example sc_int
另外可參考
http://www.fpgastudy.com/a/course/SystemC/707.html
#include "systemc.h"
int sc_main (int argc, char* argv[]) {
sc_int<1> bit_size = 0;
sc_int<4> nibble_size = 1;
sc_int<8> byte_size = 2;
sc_int<32> dword_size = 3;
//sc_int<128> addr; sc_int can not be more then 64
// Perform auto increment
dword_size ++;
cout <<"Value of dword_size : " << dword_size << endl;
dword_size(5,4) = dword_size(3,2);
cout <<"Value of dword_size : " << dword_size << endl;
// Terse method addition
byte_size += nibble_size;
cout <<"Value of byte_size : " << byte_size << endl;
// Bit selection
bit_size = dword_size[2]; //此處應該為1 可是結果為 -1 ???
cout <<"Value of bit_size : " << bit_size << endl;
// Range selection
nibble_size = dword_size.range(4,1); // Can not assign out of range
cout <<"Value of nibble_size: " << nibble_size << endl;
// Concatenated
dword_size = (byte_size,byte_size);
cout <<"Value of dword_size : " << dword_size << endl;
return 1;
}
Copyright (c) 1996-2006 by all Contributors
ALL RIGHTS RESERVED
Value of dword_size : 4 // 3++=4
Value of dword_size : 20 // 010100 =20
Value of byte_size : 3 //2 + 1 =3
Value of bit_size : -1 //
Value of nibble_size: 2
Value of dword_size : 771 // = 00000011_00000011
cout <<"Value of bit_size : " << bit_size << endl;
其結果都為-1
Arbitrary Width Logic Type
int sc_main (int argc, char* argv[]) {
sc_lv<8> data_bus (sc_logic ('z')); // All bits are Z 設定初值為Z
sc_lv<16> addr_bus ; // All bits are X 沒有設的為X
sc_logic parity ;
// Print Default value of data_bus
cout <<"Value of data_bus : " << data_bus << endl;
// Assign value to sc_bv
data_bus = "00001011";
cout <<"Value of data_bus : " << data_bus << endl;
// Use range operator
addr_bus.range(7,0) = data_bus;
cout <<"Value of addr_bus : " << addr_bus << endl;
// Assign reverse to addr bus using range operator
addr_bus.range(0,7) = data_bus;
cout <<"Value of addr_bus : " << addr_bus << endl;
// Use bit select to set the value
addr_bus[10] = "1";
cout <<"Value of addr_bus : " << addr_bus << endl;
// Use reduction operator
parity = data_bus.xor_reduce();
cout <<"Value of parity : " << parity << endl;
return 1;
}
SystemC 2.2.0 --- Mar 18 2011 18:40:28
Copyright (c) 1996-2006 by all Contributors
ALL RIGHTS RESERVED
Value of data_bus : ZZZZZZZZ
Value of data_bus : 00001011
Value of addr_bus : XXXXXXXX00001011
Value of addr_bus : XXXXXXXX11010000
Value of addr_bus : XXXXX1XX11010000
Value of parity : 1
Arbitrary Width Bit Type
可以了解bus形態的操作
#include
int sc_main (int argc, char* argv[]) {
sc_bv<8> data_bus ;
sc_bv<16> addr_bus ;
sc_bit parity ;
// Assign value to sc_bv
data_bus = "00001011";
cout <<"Value of data_bus : " << data_bus << endl;
// Use range operator
addr_bus.range(7,0) = data_bus;
cout <<"Value of addr_bus : " << addr_bus << endl;
// Assign reverse to addr bus using range operator
addr_bus.range(0,7) = data_bus;
cout <<"Value of addr_bus : " << addr_bus << endl;
// Use bit select to set the value
addr_bus[10] = "1";
cout <<"Value of addr_bus : " << addr_bus << endl;
// Use reduction operator
parity = data_bus.xor_reduce();
cout <<"Value of parity : " << parity << endl;
return 1;
}
結果
SystemC 2.2.0 --- Mar 18 2011 18:40:28
Copyright (c) 1996-2006 by all Contributors
ALL RIGHTS RESERVED
Info: (I804) /IEEE_Std_1666/deprecated: sc_bit is deprecated, use bool instead
Value of data_bus : 00001011
Value of addr_bus : 0000000000001011 // addr_bus.range(7,0) = data_bus;
Value of addr_bus : 0000000011010000 // addr_bus.range(0,7) = data_bus;
Value of addr_bus : 0000010011010000 // addr_bus[10] = "1";
Value of parity : 1 // parity = data_bus.xor_reduce();
sc width Bit 的相關method可查SystemC-1666-2005 Chapter 7. Data types
2011年5月20日 星期五
數位IC設計的基本元件(二) -- 倍頻器
它是可以合成的
但是要注意Delay Cell 要換成製程廠的Cell
因此在合成時必須要對這個部份使用dont_touch
應用在Chip 上 Delay Cell可以做成多段式的選擇項(register型式)
然後將輸出及輸入的clk轉輸出到 PAD端
因此在量測後就可用register 去做選擇
如此就可調整出Duty的比率 50-50或20-80
除了Duty外還有phase shift的現象
因此在Chip 上 clock1 與 clock2是有一個XOR cell 的delay
在應用上這也是要非常注意的
此設計是非常簡單的
如果不注重 Duty and phase shift是非常好用的
而且Area也很小
如果對Duty需要準確到50-50
像是 DDR Controller 之類的design
那還是用DLL比較好
當然如果用更多組的話
你要倍幾次都可以
但Duty就會非常難調
phase 也會差距較大
此時就必須用PLL來做比較好
/* simple example of double freq */
`timescale 1ns/100ps
module double_freq_tb();
reg clk;
reg rstn;
wire clk2;
/* Initial block to generate clock and reset */
initial begin
clk = 0; // rstn = 0; #10 rstn = 1;
end
always begin
#6 clk = !clk;
$display ("time = %t , clk = %b", $time, clk);
end
initial begin
#800;
$finish;
end
initial begin
$dumpfile("double_freq.vcd");
$dumpvars(0,double_freq_tb);
end
double_freq U_double_freq(
.in (clk),
.out (clk2)
);
always @(posedge clk2) begin
$display ("time = %t , clk2 is rising", $time);
end
always @(negedge clk2) begin
$display ("time = %t , clk2 is falling", $time);
end
endmodule
module double_freq(in,out);
input in;
output out;
wire a1;
wire out=a1^in;
delayx3 U_delayx3(
.in (in),
.out (a1)
);
endmodule
// use buf cell to replace, and don't touch in synthesis
module delay_cell(in,out);
input in;
output out;
assign #1 out=in;
endmodule
module delayx3(in,out);
input in;
output out;
wire in1, in2;
delay_cell delay_cell_1(
.in (in),
.out (in1)
);
delay_cell delay_cell_2(
.in (in1),
.out (in2)
);
delay_cell delay_cell_3(
.in (in2),
.out (out)
);
endmodule
2011年5月19日 星期四
Verdi 記錄目前的使用設定
有一個Save Session
它可以指定一個檔案來紀錄目前verdi的使用狀況
例如GUI開了那幾個,Net的顏色或是已經追蹤到那個Net了,等種種狀況
等儲存起來後,
下次再用Restore Session
就可以立刻恢復原有的設定使用情況了
這是方便要追蹤不同testpattern時,很方便的一種工具
2011年5月18日 星期三
數位IC設計的基本元件(一) -- Gray Code
想一想可以把一些基本設計的元件
整理一下給大家當個參考
如果大家想看更多基本元件的設計
可以參考網站 verilog example
基本上網站上有的我大概就不寫了
如果有寫就會寫上我在設計上遇到的做法
及特殊技法吧
先講一下gray code
這是用在讓Addr 的變化
在每一個cycle只變化一個bit
基本上這種設計會用在記憶體的讀寫
這樣做的好處在於省電
因為將address 轉成 gray 模式
所以一次只動到一個位址
這樣記憶體的位址變化最少
而可以稍稍省電一下
以下的例子是從網路上轉過來
在稍稍修改成比較好的例子
因為懶得重寫
從以前的設計抽出又太麻煩
改人家現成的例子較快
我將設計改成只變化最後四個最常變化的位址
有時設計不會全部位址都用gray去轉變
只對最常變化的位址作gray code
然後再將Gray的做法改成較簡單易懂的方法
此設計方法是可合成的(synthesizable)
而且面積也很小
需要的人可以參考看看
module binary2gray();
reg clk;
reg rstn;
reg [5:0] counter_binary, counter_binary_reg, counter_gray, counter_gray_reg;
integer count, file_wr;
/* Initial block to generate clock and reset */
initial begin
clk = 0; rstn = 0; #100 rstn = 1;
forever begin
#10 clk = !clk;
end end
initial begin
#800;
$finish;
end
/* Synchronous Logic for registering the data and incrementing the counter for binary data */
always @ (posedge clk or negedge rstn)
begin
if (!rstn) begin
counter_binary_reg <= 'b0;
counter_gray_reg <= 'b0; end
else begin
counter_binary_reg <= counter_binary + 1;
counter_gray_reg <= counter_gray;
$display("binary number= 6'b%b : gray en-coded binary number = 6'b%b", counter_binary_reg, counter_gray_reg);
end
end
/* Logic is to get Gray code from Binary code */
function[5:0] binary2gray ;
input[5:0] value;
integer i;
begin
binary2gray[5] = value[5];
binary2gray[4] = value[4];
for (i=0; i<=3; i=i+1)
binary2gray[i] = value[i] ^ value[i+1];
end
endfunction
/* Get gray encoded output */
always @(*)
begin
counter_gray = counter_gray_reg;
counter_binary = counter_binary_reg;
counter_gray = binary2gray(counter_binary_reg); end
endmodule
full_case parallel_case的使用時機
有詳細的說明
下面是我大概整理的簡述
"full" case statement
full_case indicates that all user-desired cases have been specified
Do not use default for one-hot encoding
// this is one fsm in SEL
always @(SEL or A or B or C) begin
case (SEL) //synopsys full_case
3’b001 : OUT <= A;
3’b010 : OUT <= B;
3’b100 : OUT <= C;
endcase
end
如果不用full_case去指定合成
會產生一個多餘的暫存器
請看文件第七頁
但是會有警告出現
因為有些case不能被cover到
但誤用時,如已經是full case
還用指定合成
反而會多出更多的latch
參考page14
Parallel case statement
parallel case一定要用在one-hot state上
其原因在parallel_case這個語法
強迫合成器去將case合成為mux形式
這樣每一個狀態輸入到輸出
為真正的平行
而不是if-else形態
也是因為如此
所以狀態如果可能重複
則可能會有錯誤的情形產生
此處可參考page 11
module intctl2a (int2, int1, int0, irq);
output int2, int1, int0;
input [2:0] irq;
reg int2, int1, int0;
always @(irq) begin
{int2, int1, int0} = 3'b0;
casez (irq)
3'b1??: int2 = 1'b1;
3'b01?: int1 = 1'b1;
3'b001: int0 = 1'b1;
endcase
end
endmodule
Non-parallel case statement with "parallel_case" directive
因為它不是one-hot
module intctl1b (int2, int1, int0, irq);
output int2, int1, int0;
input [2:0] irq;
reg int2, int1, int0;
always @(irq) begin
{int2, int1, int0} = 3'b0;
casez (irq) // synopsys parallel_case
3'b1??: int2 = 1'b1;
3'b?1?: int1 = 1'b1;
3'b??1: int0 = 1'b1;
endcase
end
endmodule
上面這個case為誤用
因為不是one-hot形態
合成時會出現警告
可能會有OVERLAP的情況產生
PRE/POST-SIM在此要注意啦
最後還是建議
有用到case就將所有可能的狀態都給它寫完吧
這樣就不需要用到full_case
如果很需要合成為mux形態
可以的話還是自己把code寫成mux吧
不然要將state改成one-hot
再用parallel_case來強迫合成
就要好好的看看warning 信號
這樣所花的時間精力不會比較省的
如果是別人寫的code
而且又強迫使用parallel_case
那麼pattern就要注意
如果遇到overlap的情形時
是否會有錯誤的輸出囉
test team 的人在此要注意啦
2011年5月17日 星期二
VCD waveform Dump的特殊用途
這種驅動狀態是沒有時間長度
而這種沒有時間長度的驅動狀態在fsdb會無法出現
可能是被濾掉而無法展示出來
這樣會造成無法debug
這時候就要使用VCD dump
這樣驅動的過程就會出現了
才有辦法找到驅動源'
常發生在非同步的設計中
將一個資料檔灌入兩個記憶體區塊
在模擬時要讀入資料檔就無法直接使用readmemh, readmemb了
這時候就必須自己處理,可參考我的作法如下
reg [15:0] mem1[0:31];
reg [15:0] mem2[0:31];
reg [15:0] mem_all[0:63];
initial begin
$readmemb(“test.bin”, mem_all,0,64);
#1;
// 此處 mem1, mem2要在1 timeunit之後才會有值進入
for (int i=0;i<=31;i++) begin
mem1[i] = mem_all[i];
end
for (int i=0;i<31;i++) begin
mem2[i] = mem_all[i+32];
end
end
Standard Co-Emulation Modeling Interface (SCE-MI)
以後HW/SW-cosimulation應該就會參考這個標準了
就像systemverilog以及後來的UVM一樣吧
請參考下面官網
可下載到標準參考文件
http://www.accellera.org/activities/itc
2011年5月16日 星期一
$value$plusargs 的測試例
// IUS
使用irun test.sv +TEST=5 +TESTNAME=test001 +TESTG1=test01 +FREQ+=9.33
//VCS
vcs test.sv
simv +TEST=5 +TESTNAME=test001 +TESTG01=tes01 +FREQ=9.33
`define STRING logic [1024 * 8:1]
module goodtasks;
`STRING str;
integer i1;
logic [31:0] vect;
real realvar;
real frequency;
logic [8*32:1] testname;
logic [64*8:1] pstring;
logic clk;
// vcs2009 logic 不支援,要改成reg才能用
initial begin
if ($value$plusargs("TEST=%d", i1))
$display("value was %d", i1);
else
$display("+TEST= not found");
if ($value$plusargs("TESTNAME=%s",testname)) begin
$display(" TESTNAME= %s.",testname);
$finish;
end
pstring = "TESTG%d";
// 此處IUS92及vcs2009.12未支援
if ($value$plusargs(pstring, testname))
$display("Running test number %0d.",testname);
// 此處IUS92及vcs2009.12未支援
if (!($value$plusargs("FREQ+%0F",frequency)))
frequency = 8.33333; // 166 MHz
$display("frequency = %f",frequency);
#100 $finish;
end
endmodule
支援的變數列表如下
%d decimal conversion
%o octal conversion
%h, %x hexadecimal conversion
%b binary conversion
%e real exponential conversion
%f real decimal conversion
%g real decimal or exponential conversion
%s string (no conversion)
2011年5月15日 星期日
一個可以美化Verilog code的程式
不過,如果本身的coding style沒有很好的話,透過這個工具可以讓你的Verilog程式不要看起來這麼亂。這種工具大概是你不幸的接手某個coding style很差的人的工作時比較有用吧!
下載網址
PS: 這個tools只能在Linux-like的環境中使用
參考自http://gary-digital.blogspot.com/2006/08/verilog-code.html