2008年5月7日 星期三

乘法器執行結果2


乘法器執行結果1

執行結果
Running...
70 r1= x r2= x pb=0 ready=1
170 r1= 9 r2= x pb=0 ready=1
270 r1= 9 r2= x pb=0 ready=1
370 r1= 9 r2= x pb=1 ready=1
470 r1= 9 r2= x pb=0 ready=0
570 r1= 9 r2= 0 pb=0 ready=0
670 r1= 8 r2= 0 pb=0 ready=0
770 r1= 8 r2= 7 pb=0 ready=0
870 r1= 7 r2= 7 pb=0 ready=0
970 r1= 7 r2= 14 pb=0 ready=0
1070 r1= 6 r2= 14 pb=0 ready=0
1170 r1= 6 r2= 21 pb=0 ready=0
1270 r1= 5 r2= 21 pb=0 ready=0
1370 r1= 5 r2= 28 pb=0 ready=0
1470 r1= 4 r2= 28 pb=0 ready=0
1570 r1= 4 r2= 35 pb=0 ready=0
1670 r1= 3 r2= 35 pb=0 ready=0
1770 r1= 3 r2= 42 pb=0 ready=0
1870 r1= 2 r2= 42 pb=0 ready=0
1970 r1= 2 r2= 49 pb=0 ready=0
2070 r1= 1 r2= 49 pb=0 ready=0
2170 r1= 1 r2= 56 pb=0 ready=0
2270 r1= 0 r2= 56 pb=0 ready=0
2370 r1= 0 r2= 63 pb=0 ready=1
ok
Stop at simulation time 2450000

乘法器的Verilog程式碼

`define NUM_STATE_BITS 2
`define IDLE 2'b00
`define INIT 2'b01
`define COMPUTE1 2'b10
`define COMPUTE2 2'b11

module cl(clk);
parameter TIME = 110000;
output clk;
reg clk;
initial
clk = 0;
always
#50 clk = ~clk;
always @(posedge clk)
if ($time > TIME) #70 $stop;
endmodule

module slow_div_system(pb,ready,x,y,r2,sysclk);
input pb,x,y,sysclk;
output ready,r2;
wire pb;
wire [11:0] x,y; //乘法器的輸入x、y皆有12個
reg ready;
reg [11:0] r1,r2;
reg [`NUM_STATE_BITS-1:0] present_state;
always
begin
@(posedge sysclk) enter_new_state(`IDLE);
r1 <= @(posedge sysclk) x;
r2 <= @(posedge sysclk) 0;
ready = 1;
if (pb)
begin
while (r1 > 0)
begin
@(posedge sysclk) enter_new_state(`COMPUTE1);
r1 <= @(posedge sysclk) r1 - 1;
@(posedge sysclk) enter_new_state(`COMPUTE2);
r2 <= @(posedge sysclk) r2 + y;
end
end
end

task enter_new_state;
input [`NUM_STATE_BITS-1:0] this_state;
begin
present_state = this_state;
#1 ready=0;
end
endtask

always @(posedge sysclk) #20
$display("%d r1=%d r2=%d pb=%b ready=%b", $time, r1,r2, pb,
ready);
endmodule

module top;
reg pb;
reg [11:0] x,y;
wire [11:0] accumulation;
wire ready;
integer s;
wire sysclk;

cl #20000 clock(sysclk);
slow_div_system slow_div_machine(pb,ready,x,y,accumulation,sysclk);
initial
begin
pb= 0;
x = 9;
y = 7;
#250;
@(posedge sysclk);
for (x=9; x<=9; x = x+1)
begin
@(posedge sysclk);
pb = 1;
@(posedge sysclk);
pb = 0;
@(posedge sysclk);
wait(ready);
@(posedge sysclk);
if (x*y === accumulation)
$display("ok");
else
$display("error x=%d y=%d x/y=%d accumulation=%d",x,y,x*y,
accumulation);
end
$stop;
end
endmodule

乘法器的ASM圖


說明:上圖為除法器的ASM圖,其作用如C語言的流程圖,主要是幫助程式的撰寫。其中的x和r1皆代表乘數、y為被乘數(x、y可互換,因為乘法有交換性)、r2為積、pb為按鈕狀態信號,而當READY=1時,就會等使用者按鈕,當READY=0時,機器正忙著計算積。此程序一開始先把r1設為x、r2設為0,當使用者按下按鈕後便執行下列動作,如果當r1大於0時,則r1-1的值儲存在r1、r2+y的值儲存在r2,而當r1小於等於0時,則得到答案,此計算方法有點類似建構式數學。

2008年5月3日 星期六

除法器執行結果2


除法器執行結果1

Running...
70 r1= x r2= x r3= x pb=0 ready=1
170 r1= 36 r2= x r3= x pb=0 ready=1
270 r1= 36 r2= x r3= x pb=0 ready=1
370 r1= 36 r2= x r3= x pb=1 ready=1
470 r1= 36 r2= x r3= x pb=0 ready=0
570 r1= 36 r2= 0 r3= x pb=0 ready=0
670 r1= 29 r2= 0 r3= x pb=0 ready=0
770 r1= 29 r2= 1 r3= x pb=0 ready=0
870 r1= 29 r2= 1 r3= 1 pb=0 ready=0
970 r1= 22 r2= 1 r3= 1 pb=0 ready=0
1070 r1= 22 r2= 2 r3= 1 pb=0 ready=0
1170 r1= 22 r2= 2 r3= 2 pb=0 ready=0
1270 r1= 15 r2= 2 r3= 2 pb=0 ready=0
1370 r1= 15 r2= 3 r3= 2 pb=0 ready=0
1470 r1= 15 r2= 3 r3= 3 pb=0 ready=0
1570 r1= 8 r2= 3 r3= 3 pb=0 ready=0
1670 r1= 8 r2= 4 r3= 3 pb=0 ready=0
1770 r1= 8 r2= 4 r3= 4 pb=0 ready=0
1870 r1= 1 r2= 4 r3= 4 pb=0 ready=0
1970 r1= 1 r2= 5 r3= 4 pb=0 ready=0
2070 r1= 1 r2= 5 r3= 5 pb=0 ready=1
ok
Stop at simulation time 2150000

除法器的Verilog程式碼

`define NUM_STATE_BITS 3
`define IDLE 3'b000
`define INIT 3'b001
`define COMPUTE1 3'b010
`define COMPUTE2 3'b011
`define COMPUTE3 3'b100

module cl(clk);
parameter TIME_LIMIT = 110000;
output clk;
reg clk;
initial
clk = 0;
always #50 clk = ~clk;
always @(posedge clk)
if ($time > TIME_LIMIT) #70 $stop;
endmodule

module slow_div_system(pb,ready,x,y,r3,sysclk);
input pb,x,y,sysclk;
output ready,r3;
wire pb;
wire [11:0] x,y;
reg ready;
reg [11:0] r1,r2,r3;
reg [`NUM_STATE_BITS-2:0] present_state;
always
begin
@(posedge sysclk) enter_new_state(`IDLE);
r1 <= @(posedge sysclk) x;
r2 <= @(posedge sysclk) 0;
ready = 1;
if (pb)
begin
while (r1 >= y)
begin
@(posedge sysclk) enter_new_state(`COMPUTE1);
r1 <= @(posedge sysclk) r1 - y;
@(posedge sysclk) enter_new_state(`COMPUTE2);
r2 <= @(posedge sysclk) r2 + 1;
@(posedge sysclk) enter_new_state(`COMPUTE3);
r3 <= @(posedge sysclk) r2;
end
end
end

task enter_new_state;
input [`NUM_STATE_BITS-2:0] this_state;
begin
present_state = this_state;
#1 ready=0;
end
endtask

always @(posedge sysclk) #20
$display("%d r1=%d r2=%d r3=%d pb=%b ready=%b", $time, r1, r2, r3, pb,ready);
endmodule

module top;
reg pb;
reg [11:0] x,y;
wire [11:0] quotient;
wire ready;
integer s;
wire sysclk;
cl #20000 clock(sysclk);

slow_div_system slow_div_machine(pb,ready,x,y,quotient,sysclk);
initial
begin
pb= 0;
x = 36;
y = 7;
#250;
@(posedge sysclk);
for (x=36; x<=36; x = x+1)
begin
@(posedge sysclk);
pb = 1;
@(posedge sysclk);
pb = 0;
@(posedge sysclk);
wait(ready);
@(posedge sysclk);
if (x/y === quotient)
$display("ok");
else
$display("error x=%d y=%d x/y=%d quotient=%d",x,y,x/y,quotient);
end
$stop;
end
endmodule