電子書籍の厳選無料作品が豊富!

ステートマシンについて、
3カウンタ回路を以下の仕様でVerilogに記述し、シミュレーションにより動作を確認せよ。
モジュール名:fsm2
入力信号名とビット数:ck(1ビット) rst(1ビット) din(1ビット)
出力信号名とビット数:dout(1ビット)
動作
・クロック入力ckの立ち上がりに同期して動作する。
・3クロック連続してdinに1が入力されると、doutに1を出力する。それ以外のときは0を出力する。
・ rstはリセット入力であり、rstが1のときは即座にdoutに0を 出力する。rstが0になって以降3クロック連続してdinに1が 入力されるまで、0を出力し続ける。

・ dinの入力系列011110に対して、000100を出力する。
補足
・この回路は4つの状態を有する。
という問題で、実行結果を画像のようにしたいのですが中々上手くいきません。
どうしたら画像のようになるのでしょうか?解説お願いします。
補足に画像貼れなかったため、再投稿です。

途中までのコードです。
module fsm(ck,rst,din,dout);
input ck;
input rst;
input din;
output dout;
reg [1:0] cur;
reg [1:0] nxt;
parameter S0=2'b00, S1=2'b01, S2=2'b01, S3=2'b10;
always @(rst or din or cur)begin
if(rst)
nxt<=S0;
else
case(cur)
S0:nxt<=(din==1'b1)?S1:S0;
S1:nxt<=(din==1'b1)?S2:S0;
S2:nxt<=(din==1'b1)?S3:S0;
S3:nxt<=(din==1'b1)?S3:S0;
default:
nxt<=S0;
endcase
end
always @(posedge ck)begin
cur<=nxt;
end
function dout_func;
input rst;
input din;
input [1:0] cur;
if(rst)
dout_func=1'b0;
else
case(cur)
S0:dout_func=1'b0;
S1:dout_func=1'b0;
S2:dout_func=1'b0;
S3:dout_func=(din==1'b1) ? 1'b0:1'b0;
default:
dout_func=1'bx;
endcase
endfunction
assign dout=dout_func(rst,din,cur);
endmodule
`timescale 1ps/1ps
module fsm_tp;
reg ck,rst,din;
wire dout;
parameter STEP=1000;
fsm fsm(ck,rst,din,dout);
always begin
ck=1; #(STEP/2);
ck=0; #(STEP/2);
end
initial begin
#(STEP/2) rst=1; din=0;
#(STEP/2) rst=0;
#STEP din=1;
#STEP din=1;
#STEP din=0;
#STEP din=1;
#STEP din=1;
#STEP din=1;
#STEP din=1;
#STEP din=0;
#STEP din=0;
$finish;
end
initial $monitor($stime,"ck=%b rst=%b din=%b dout=%b",ck,rst,din,dout);
endmodule

「有限状態機械について」の質問画像

質問者からの補足コメント

  • 回答ありがとうございます。
    reg [1:0] nxt_st,st;
    の部分がエラーが出てしまうのですが、何か間違っているのでしょうか?

    No.3の回答に寄せられた補足コメントです。 補足日時:2021/06/15 16:43
  • ありがとうございました。
    上手くいきました。

    No.4の回答に寄せられた補足コメントです。 補足日時:2021/06/15 17:16
  • ちなみにこのときの状態遷移図はどのようになるのでしょうか?

    No.2の回答に寄せられた補足コメントです。 補足日時:2021/06/15 17:18
  • 何度もすみません。
    実行結果の
      3000ck=1 rst=0 din=1 dout=1
    3500ck=0 rst=0 din=1 dout=1
    6000ck=1 rst=0 din=1 dout=1
    6500ck=0 rst=0 din=1 dout=1
    の部分に1が出てしまいます。
    どうすれば7000と7500に1を出力できますか?

      補足日時:2021/06/15 17:29

A 回答 (6件)

解決できたかどうかわからないけど、もしまだならヒントだけ。


ステートマシンで、S0からS2までの3つの状態を使っているけど、これだとうまくいかない。S0からS3までの4つの状態をすべて使うとうまくいきます。どうコードを修正するかは自分で考えてください。

以下、コード修正後、VCSで実行してみた結果。

0 : ck=1 rst=x din=x dout=x
500 : ck=0 rst=1 din=0 dout=0
1000 : ck=1 rst=0 din=0 dout=0
1500 : ck=0 rst=0 din=0 dout=0
2000 : ck=1 rst=0 din=1 dout=0
2500 : ck=0 rst=0 din=1 dout=0
3000 : ck=1 rst=0 din=1 dout=0
3500 : ck=0 rst=0 din=1 dout=0
4000 : ck=1 rst=0 din=0 dout=0
4500 : ck=0 rst=0 din=0 dout=0
5000 : ck=1 rst=0 din=1 dout=0
5500 : ck=0 rst=0 din=1 dout=0
6000 : ck=1 rst=0 din=1 dout=0
6500 : ck=0 rst=0 din=1 dout=0
7000 : ck=1 rst=0 din=1 dout=1
7500 : ck=0 rst=0 din=1 dout=1
8000 : ck=1 rst=0 din=1 dout=0
8500 : ck=0 rst=0 din=1 dout=0
9000 : ck=1 rst=0 din=0 dout=0
9500 : ck=0 rst=0 din=0 dout=0
    • good
    • 0
この回答へのお礼

無事、解決しました。
ありがとうございました。

お礼日時:2021/06/16 11:31

>3000ck=1 rst=0 din=1 dout=1



これがすでにおかしい。
課題だろうから自分でデバッグすることを薦めます。まずは論理を理解して、タイミングチャートを書いてみることです。

今もうこっちは深夜なんで、明日時間があったらシミュレーションを流してみますが。
    • good
    • 0

>reg [1:0] nxt_st,st;の部分がエラーが出てしまうのですが、



たぶんだけど、下のポートリストの最後にセミコロンが抜けているとかいうことありませんか。

module fsm (
input clk, rst, din,
ouptut reg dout
)


ちなみにあなたが書いたもともとの論理が正常動作しないのは、always @(rst or din or cur)の中でノンブロッキング文をつかっていることが理由です。そういう書き方をすると、dinが変化すると即座にステートレジスタが更新されて、問題として与えられている、クロックの立ち上がりに同期という前提が崩れます。
この回答への補足あり
    • good
    • 0

いくつか訂正。




module fsm (
input clk, rst, din;
ouptut reg dout;
end


module fsm (
input clk, rst, din,
ouptut reg dout
)



S2 : begin
if(din) dout = 0;
nxt_st = S0;
end


S2 : begin
if(din) dout = 1'b1;
nxt_st = S0;
end
この回答への補足あり
    • good
    • 0

ノンブロッキング文はそういう使い方をすると、データでフリップフロップが駆動されることになるので、やめたほうがいい。

慣れないうちは、ノンブロッキング文はクロックと合わせて使いようにしたほうがいいと思います。

ステートマシンの書き方はいろいろあるけど、私はいつもこんな感じに書くことにしています。検証はしていないので、小さな間違いがあるかもしれません。自分で論理検証をやってみてください。

rst=1の時は、stが非同期リセットで即座にS0になり、その結果、always @(*)の中のデフォルトのdout = 1'b0が実行されるので、dinの値にかかわらず即座にdout=0となるはずです。

module fsm (
input clk, rst, din;
ouptut reg dout;
end

reg [1:0] nxt_st, st;

parameter S0=2'd0, S1=2'd1, S2=2'd2, S3=2'd3;

always @(posedge clk or posedge rst) begin
if(rst) st <= S0;
else st <= nxt_st;
end

always @(*) begin
nxt_st = st;
dout = 1'b0;
case(st)
S0 : if(din) nxt_st = S1;
else nxt_st = S0;
S1 : if(din) nxt_st = S2 ;
else nxt_st = S0;
S2 : begin
if(din) dout = 0;
nxt_st = S0;
end
default: begin
end
endcase

end

endmodule
この回答への補足あり
    • good
    • 0

Verilog 仕様経験ないけどここおかしいんじゃない


>parameter S0=2'b00, S1=2'b01, S2=2'b01, S3=2'b10;

ステートS1、S2 の両方とも同じ 'b01
になってる


>S0:nxt<=(din==1'b1)?S1:S0;
>S1:nxt<=(din==1'b1)?S2:S0;
>S2:nxt<=(din==1'b1)?S3:S0;
>S3:nxt<=(din==1'b1)?S3:S0;
これもおかしくない?状態が変わっていかないんじゃないの
「入力1が3回連続」をカウントしたいんでしょ?
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!