ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Verilog HDLコミュの教えてください!

  • mixiチェック
  • このエントリーをはてなブックマークに追加
現在、大学でMAX+Plus?を使っています。

signed 4bit CLAを利用し、unsigned 4bit掛け算のプログラムを作る課題がでました。


module MID_MULTI(A, B, S, clock, reset, overflow);

input [3:0] A, B; //A:Multiplicand, B:Muitiplier
input clock, reset;

output [8:0]S; //S:Sum, Result value
output overflow;
wire [8:0]s;
reg [3:0] w0, w1, w2, w3;

assign S = (reset == 0)? s:9'b0;

always @(posedge clock)
begin
if(B[0] == 1'b1)
w0 = A;
else
w0 = 4'b0;
if(B[1] == 1'b1)
w1 = A;
else
w1 = 4'b0;
if(B[2] == 1'b1)
w2 = A;
else
w2 = 4'b0;
if(B[3] == 1'b1)
w3 = A;
else
w3 = 4'b0;
end

CLA_ADDER c0(w0>>1, w1, 0, s);
CLA_ADDER c1(s>>1, w2, 0, s);
CLA_ADDER c2(s>>1, w3, 0, s);

endmodule


ソースが一部ではありますが、sの定義のところでエラーがでてしまいます涙
CLA_ADDERは、動作確認済みです。エラーもでません。
Sの9ビット目はoverflowかどうかを検出するためのものです。
どうすればエラーを解消できますか?助けてくださいたらーっ(汗)


ここで、質問して適切だったかどうか分かりませんが、分かる方お願いしまするんるん

コメント(38)

]s の間にスペースがないからじゃないですか?
>mshibaさん
返信ありがとうございます。それではないみたいです;;
エラー内容が、
Verilog HDL syntax error: variable "s" cannnot be assigned a value in more than one Always Construct or Continuous Assignment Statement in a Verilog Design File
とのことです。英語がよくわからないですけど・・・涙
sに2ヶ所以上で代入してるんでは。
CLA_ADDRのソースがないんでちがうかもしれませんが、たぶん
CLA_ADDER c0(w0>>1, w1, 0, s);
CLA_ADDER c1(s>>1, w2, 0, s);
CLA_ADDER c2(s>>1, w3, 0, s);
のsは、CLA_ADDRの出力に割り付けてますよね?

あと、always内の代入にblockingはあんまり使わんです。
FFの後ろにゲートを置いてゲート信号を出力に使うのも良くないです。
Syntax error を出す処理系(シミュレータ)がどれかがわからないのですが、CLA_ADDER のソースも拝見したいですね。

エラーの意味は mshiba さんが書かれたとおり、

「s への代入が、always ブロックと継続代入文の両方で行われている」

というものですが、これは、SystemVerilog の logic タイプの変数であればそういう制約がありますが、ここでは s は reg なので、そもそも reg に継続代入できませんので、やはり CLA_ADDER のソースを含めて、シミュレータで動作確認したいところです。


ここで聞くよりも課題を出題した講師に聞くのが一番だと思いますよ。

想像ですが、4bitのかけ算の課題を出すなら、組み合わせ回路で作るのを意図してると思うんですがねぇ。

あと、アドバイスできることは、ソフトウェアは先頭から順番にシーケンシャルに動作するが、RTLではそういう概念とは別物、ということですね。
sは一時変数ではなく、結線なので、光Ginjiさんのおっしゃるとおり複数箇所からドライブ(代入)できません。

CLA_ADDER c0(w0>>1, w1, 0, s);
CLA_ADDER c1(s>>1, w2, 0, s);
CLA_ADDER c2(s>>1, w3, 0, s);
assign S = (reset == 0)? s:9'b0;

この部分をs2,s3を定義した上で

CLA_ADDER c0(w0>>1, w1, 0, s);
CLA_ADDER c1(s>>1, w2, 0, s2);
CLA_ADDER c2(s2>>1, w3, 0, s3);
assign S = (reset == 0)? s3:9'b0;

と書き換えるととりあえずコンパイルは通ると思います。
やはり、全てのソース載せたほうがいいみたいですね^^;
写真を見ていただければ見やすいと思いますが、
コピペ用として・・・あせあせ

module XOR_GATE(A, B, Z);
input A,B;
output Z;

assign Z=A^B;
endmodule

module P_G(A, B, P, G);
input A, B;
output P, G;

assign P = A^B;
assign G = A&B;
endmodule

module S(P, G, Cin, S);
input P, G, Cin;
output S;

assign S=P^G^Cin;
endmodule

module COUT(P, G, Cin, Cout);
input P,G,Cin;
output Cout;

assign Cout=G+P&Cin;
endmodule

module CLA_ADDER(A, B, mode, S);
input [3:0]A, B;
input mode;

output [3:0] S;
wire [3:0] b, p, g, c;

XOR_GATE xor0(mode, B[0], b[0]);
P_G p0(A[0], b[0], p[0], g[0]);
COUT cout0(p[0], g[0], mode, c[0]);
S s0(p[0], g[0], c[0], S[0]);

XOR_GATE xor1(mode, B[1], b[1]);
P_G p1(A[1], b[1], p[1], g[1]);
COUT cout1(p[1], g[1], c[0], c[1]);
S s1(p[1], g[1], c[1], S[1]);

XOR_GATE xor2(mode, B[2], b[2]);
P_G p2(A[2], b[2], p[2], g[2]);
COUT cout2(p[2], g[2], c[1], c[2]);
S s2(p[2], g[2], c[2], S[2]);

XOR_GATE xor3(mode, B[3], b[3]);
P_G p3(A[3], b[3], p[3], g[3]);
COUT cout3(p[3], g[3], c[2], c[3]);
S s3(p[3], g[3], c[3], S[3]);

endmodule

module MID_MULTI(A, B, S, clock, reset, overflow);

input [3:0] A, B; //A:Multiplicand, B:Muitiplier
input clock, reset;

output [8:0] S; //S:Sum, Result value
output overflow;
wire [8:0] s;
reg [3:0] w0, w1, w2, w3;

assign S = (reset == 0)? s:9'b0;

always @(posedge clock)
begin
if(B[0] == 1'b1)
w0 <= A;
else
w0 <= 4'b0;
if(B[1] == 1'b1)
w1 <= A;
else
w1 <= 4'b0;
if(B[2] == 1'b1)
w2 <= A;
else
w2 <= 4'b0;
if(B[3] == 1'b1)
w3 <= A;
else
w3 <= 4'b0;
end
CLA_ADDER c0(w0>>1, w1, 0, s);
CLA_ADDER c1(s>>1, w2, 0, s);
CLA_ADDER c2(s>>1, w3, 0, s);

endmodule



>mshibaさん、光Ginjiさん
助言、ありがとうございます電球
sはwireにしたほうがいいのでしょうか??

コンパイルさえできれば、なんとか試行錯誤ができるのですが、エラーのために前に進めずにいます泣き顔


ちなみにソースは全て自作です。
学校から与えられているソースではないので全面的に変更可です。
>なべさん。さん
助言ありがとうございます。助教授の方には、一度メールを送ったのですが、
「答えられない・・・」との、なんとも冷たい返事をもらいましたたらーっ(汗)

コードをなべんさん。さんがおっしゃるとおりに変更してみましたが、やはりエラーがでます。
CLA_ADDERのほうに問題があるようですね涙
冷たい先生ですね・・・
s2,s3はちゃんと定義しましたか?それでも同じエラーが出るならちょっと原因がわかりません。
さっきも書きましたが、>>2 のエラー内容は

CLA_ADDER c0(w0>>1, w1, 0, s);
CLA_ADDER c1(s>>1, w2, 0, s);
CLA_ADDER c2(s>>1, w3, 0, s);

で、c0, c1, c2 の3つのモジュールから同じ結線sに書き込んでいるのがマズイので、
違う名前のwireを使えばとりあえずコンパイルはできると思ったんですけどねぇ。

今回のエラーは CLA_ADDER は関係ないと思いますよ。
ただ、CLA_ADDER が4ビットの加算器なのに出力が5ビットになってないのは乗算器を作る上で今後困ると思うんですけどね。
(MID_MULTIにも色々まずいところがありそうですが・・・)
>なべさん。さん
すみません、エラーの内容が違いました。

Can't find a pin in the design file that corresponds to pinstub/port 'overflow' in the symbol, Function Prototype, or other construct 'c0' that represents the file

と出るようになりました。
assign overflow = S[8];と定義しましたが同じ結果です。

明日もこの課題で潰れるのかと思うと・・・げっそり
他にもいっぱいあるのにーバッド(下向き矢印)

できるだけ自分でも頑張ってみますもみじ
そうですね。

CLA_ADDER c0(w0>>1, w1, 0, s);
CLA_ADDER c1(s>>1, w2, 0, s);
CLA_ADDER c2(s>>1, w3, 0, s);

とインスタンシエイトしている、s は wire [8:0] s; の9ビット信号なのですが、CLA_ADDER の定義側は

module CLA_ADDER(A, B, mode, S);
input [3:0]A, B;
input mode;
output [3:0] S;

と mode 以外は 4 ビットです。ここで

CLA_ADDER c0(w0>>1, w1, 0, s);

の s は右詰4ビットしか CLA_ADDER の S から値が返ってきませんし、

CLA_ADDER c1(s>>1, w2, 0, s);

の s>>1 シフト結果の右詰4ビットしかAに受け渡りません。また、CLA_ADDER の S から s に右詰4ビットしか値が返ってきません。

私はデザインの設計意図を把握していないので、シミュレータにかけたときのVerilog 文法に照らしたエラー/ウォーニングは上記のとおりである、としかご紹介できないのですけれども、このあたりについていちど、コードをレビューしてみると良いと思います。

#私はS社シミュレータ VCS の専門家です。
あ、あと、現状では output overflow; は誰からもドライブされていなくて、浮き端子です。

Can't find a pin in the design file that corresponds to pinstub/port 'overflow' in the symbol, Function Prototype, or other construct 'c0' that represents the file

は、それについてのエラーですかねきっと。

>光Ginjiさん
助言のほうありがとうございました^^ CLAのほうから直してみまするんるん
またわからないことがあれば、掲示板利用させて頂きますウッシッシ
すみません、まだできてないのですが、上のコードからは少し変更で、

A*B=Sの場合、
?Sを0で初期化。
?B=0なら終了。違う場合は?を実行。
?S=S+A;、Bを1ビットシフト。 ?を実行。

というアルゴリズムで行うように変更したいのですが、


現状が、

module CLA_ADDER(A, B, mode, S);
input [4:0] A;
input [4:0] B;
input mode;

output [8:0] S;
wire [8:0] b, p, g, c;

XOR_GATE xor0(mode, B[0], b[0]);
P_G p0(A[0], b[0], p[0], g[0]);
COUT cout0(p[0], g[0], mode, c[0]);
S s0(p[0], g[0], c[0], S[0]);

XOR_GATE xor1(mode, B[1], b[1]);
P_G p1(A[1], b[1], p[1], g[1]);
COUT cout1(p[1], g[1], c[0], c[1]);
S s1(p[1], g[1], c[1], S[1]);

XOR_GATE xor2(mode, B[2], b[2]);
P_G p2(A[2], b[2], p[2], g[2]);
COUT cout2(p[2], g[2], c[1], c[2]);
S s2(p[2], g[2], c[2], S[2]);

XOR_GATE xor3(mode, B[3], b[3]);
P_G p3(A[3], b[3], p[3], g[3]);
COUT cout3(p[3], g[3], c[2], c[3]);
S s3(p[3], g[3], c[3], S[3]);

XOR_GATE xor4(mode, B[4], b[4]);
P_G p4(A[4], b[4], p[4], g[4]);
COUT cout4(p[4], g[4], c[3], c[4]);
S s4(p[4], g[4], c[4], S[4]);

endmodule

module MID_MULTI(A, B, S, clock, reset, overflow);

input [4:0] A, B; //A:Multiplicand, B:Muitiplier
input clock, reset;

output [8:0] S; //S:Sum, Result value
output overflow;
wire [8:0] s = 9'b0;
reg [4:0] w0, w1, w2, w3;

assign S = (reset == 0)? s:9'b0;
assign overflow = S[8];


always @(posedge clock)
begin
while(B != 4'b0) begin
if(B[0] == 1){
CLA_ADDER c0(s, A, 0, s);
}else if(B[0] == 0){
CLA_ADDER c0(s, 0, 0, s);
}
assign B = B>>1;
end
end

endmodule

としているのですが、やはりエラーが出ます。
CLA_ADDERを呼び出すことはwhile文の中では行いのでしょうか?
すぐできそうな気はするのですが・・・うまくいかないものですね涙

提出期限が明日の夜8時までとなっています。
申し訳ないですが、助言のほうよろしくお願いいたしますダッシュ(走り出す様)
CLA_ADDER は子モジュールのインスタンスですから、initial / always ブロック内には置けません。

直接のエラーは文法エラー (begin-end ではなく { } の使用) ですが(^^、

while(B != 4'b0) begin
if(B[0] == 1){
CLA_ADDER c0(s, A, 0, s);
}else if(B[0] == 0){
CLA_ADDER c0(s, 0, 0, s);
}

は、Verilog HDL の構造上、まちがいです。

reg[4:0] t;
CLA_ADDER c0(s, t, 0, s);
...
...
while(B != 4'b0) begin
if(B[0] == 1)
t <= A;
else if(B[0] == 0){
t <= 0;


とでもするところでしょうが、

input [4:0] A, B; //A:Multiplicand, B:Muitiplier

のように、B は 入力なのに

assign B = B>>1;

とする意図がわからないです…。


>光Ginjiさん
早急なご返答、ご指摘ありがとうございます。

Bの入力が、もし「1011」であった場合、
最初に1ビット目である「1」だけを見比べて、処理し、
次にBをライトシフトして2ビット目の値を1ビット目に持ってきたかったのですが・・・冷や汗
それを繰り返し4ビット目「1」を見比べるまでの繰り返しをしたかったですあせあせ(飛び散る汗)

必要ないでしょうか?
なるほど。
それであれば、Bを操作するのではなく、あらたに B_temp を用意して

B_temp に B を代入。
B_temp をシフト操作。

などとするか、最初から B の LSB 〜 MSB を読みとってくる for ループで組むほうがいいと思います。

always@(posedge clock)  // ---> posedge clock で、
for (i=0 ; i < 4 ; i=i+1 ) // --> ここで B の各ビットを読み取って、処理する
B[i] = .....

みたいな。

>光Ginjiさん
あ、なるほど・・・C的な文法も使えるのですね^^;
これで何とかできそうな気がしますあせあせ
ご親切にありがとうございました!でも、また質問するかもしれませんたらーっ(汗)
while を使ったら普通は合成できませんよ(^^;
文法的に正しければOK、という課題ならそれでもいいんですけど・・・

HDLはあくまで回路を記述する言語ですよ。
ソフトウェアを書くときの考え方じゃだめなんです。
まずタイミングチャートを書いてみてアルゴリズムを整理してみることをおすすめします。
>なべさん。さん
すみません、とりあえず結果が正常に出ればOKという課題みたいなので^^;

初心者なので、なべさん。さんがおっしゃるとおりやるべきなのでしょうが、どうしても答えを探すほうにばかり執着してしまい・・・^^;

また問題発生して苦しんでますが、少し自分で悩んでみますあせあせ
結果が正常に出ればいい、なら 「*」 を使っちゃえば(^^;

冗談はさておき、私ならレジスタを使わずに加算器3つで作っちゃいますけどね。
かけ算の筆算を思い浮かべると、数字4つを足せば答えが出てくるので、
どう足せばいいか少し考えて加算器(今回はCLA_ADDER)に結線しちゃえば完成ですね。

まぁ、あと少しがんばってください。
>なべさん。さん
そうですね。4×4の掛け算なので結果が9桁用意すれば大丈夫だと思いますけど・・・
足し算するときに1ビットずつずらしていかないといけないのですが、それの指定さえできれば楽そうなのですが・・・たらーっ(汗)
4ビット同士のかけ算だと、積は8ビットですよ^^;

1ビットずらすのは、例えば
  assign a0 = {1'b0,A[3:1]};
という風に書けば簡単ですよ。

もう少し工夫して
  assign a0 = (B[0]==1'b1) ? {4'b0,A[3:0]} : 8'b0;
  assign a1 = (B[1]==1'b1) ? {3'b0,A[3:0],1'b0} : 8'b0;
という風にしておいて、
1段目の加算器には a0[4:1]とa1[4:1]を入力する感じでしょうかねぇ。
合ってるかどうかわかりませんけど。
>なべさん。さん
あ、すみません。9ビットと言ったのは、今回の課題で9ビット目をオーバーフロー検出用でした。
ありがとうございます!やってみますわーい(嬉しい顔)
そろそろ時間切れなので、最後のあがきとしての質問させて頂きますあせあせ

ソースのほうを少し変更しました。シフトするmoduleを別に作成してみました。(なべさん。さんごめんなさい。エラーがでてしまったので・・・^^;)

このソースでは、

reg [3:0] b;でエラーがでてしまいます。


module CLA_ADDER(A, B, Cin, mode, S);
input [3:0] A, B;
input mode;
input Cin;

output [3:0] S;
wire [3:0] b, p, g, c; //c:cout

XOR_GATE xor0(mode, B[0], b[0]);
P_G p0(A[0], b[0], p[0], g[0]);
COUT cout0(p[0], g[0], Cin, c[0]);
S s0(p[0], g[0], c[0], S[0]);

XOR_GATE xor1(mode, B[1], b[1]);
P_G p1(A[1], b[1], p[1], g[1]);
COUT cout1(p[1], g[1], c[0], c[1]);
S s1(p[1], g[1], c[1], S[1]);

XOR_GATE xor2(mode, B[2], b[2]);
P_G p2(A[2], b[2], p[2], g[2]);
COUT cout2(p[2], g[2], c[1], c[2]);
S s2(p[2], g[2], c[2], S[2]);

XOR_GATE xor3(mode, B[3], b[3]);
P_G p3(A[3], b[3], p[3], g[3]);
COUT cout3(p[3], g[3], c[2], c[3]);
S s3(p[3], g[3], c[3], S[3]);


endmodule


//4bit shift right
module SHIFT_4(A, B);
input [3:0] A;
output [3:0] B;

assign B[3] = 1'b0;
assign B[2:0] = A[3:1];

endmodule

//9bit shift right
module SHIFT_9(A, B);
input [3:0] A;
output [8:0] B;
//Ex)0 0100 1100->0 0010 0110
assign B[8:7] = 2'b0;
assign B[6:3] = A[3:0];
assign B[2:0] = 3'b0;

endmodule


module MID_MULTI(A, B, S, clock, reset, overflow);

input [3:0] A;
input [3:0] B; //A:Multiplicand, B:Muitiplier
input clock, reset;

output [8:0] S; //S:Sum, Result value
output overflow;
reg [3:0] b;
reg [8:0] t0;
reg [8:0] s0;

CLA_ADDER c0(s0[7:4], b, 0, 0, t0[7:4]);
SHIFT_4 s_4(B, b);
SHIFT_9 s_9(t0[7:4], s0);

always @(posedge clock or negedge reset)
begin
if(!reset)
s0 <= 0;
else if(b != 0) begin
if(B[0])
b <= A;
else
b <= 0;
end
end


assign S = s0;
assign overflow = S[8];

endmodule


説明不足かもしれませんが、解決策あれば教えてくださいたらーっ(汗)
お願い致します電球
b を reg ではなく、wire にしたらどうなりますか?

(今、出先なのでケータイからの投稿ですので、動作確認できないので恐縮です)
>光Ginjiさん
bをwireにすると、alwaysの中のAか0を代入するところで文法エラーになってしまいます泣き顔
忙しいところ、ありがとうございますあせあせ(飛び散る汗)
結線の方向を考慮する必要がありますね。

b に対し、SHIFT_4 でドライブしようとしています。ここに reg は置けません。

どの信号が A や 0 を受けて、どの信号をシフトしたいのか、値の伝搬の流れを整理する必要がありますね。
>光Ginjiさん
結線の方向・・・ですか・・・たらーっ(汗)
BではAや0を受けれないということですか?涙

CLAを利用しないでよければ、すでにできてる気もするのですが、やはりシフトに関する知識?使い方が理解できてないみたいです;;
少なくとも、MID_MULTI の B は input ですから、これに A の値や 0 を代入することはできないです。
>光Ginjiさん
あ・・・なるほど・・・とりあえず、CLAを利用しない方法で提出しましたあせあせ
お付き合いありがとうございました。学期末の最終課題でつまづいたらまたよろしくお願い致しますたらーっ(汗)
違う質問をしてもいいですか。
改訂 入門Verilog HDL記述を読んでいるのですが、そのP73。
下位モジュールの呼び出しに関して。

---ココカラ---ココカラ---ココカラ---ココカラ---ココカラ---
図3.16のbの

DEF DEF0( ck ,d[0] ,q[0]);
DEF DEF1( ck ,d[1] ,q[1]);
DEF DEF2( 省略 );
DEF DEF3( 省略 );

の場合は4個のモジュールを呼び出してるので、それぞれ個別のインスタンス名DEF0,DEF1などを付加しています.
同一のモジュールを複数呼び出す際には、
DEF DEF0( 省略 ),
DEF1( 省略 ),
DEF2( 省略 ),
DEF3( 省略 );
などと、コンマで区切って連続して記述できます.
---ココマデ---ココマデ---ココマデ---ココマデ---ココマデ---ココマデ---ココマデ---
とあります。

これは本の誤植でなく、正しいですか。
良かったら、教えてください、「正しい」のひとことだけでもいいです、後は自分で考えます。
よろしくお願いします。
うん、大丈夫みたい。
簡単な回路書いて合成してみたけど、問題なく完了しました。
そうなんですか、ありがとうございます。
合成までしていただいて。

私、31で書いた2つの例は、同じものに見えてましたが、
本の通り、
コンマで区切ってない方は「4個のモジュールを呼び出してる」になり、
区切って一行で書いたものは「同一のモジュールを複数呼び出す」に変わるのですね。
BNF だと、

<module_instantiation>
::= <name_of_module> <parameter_value_assignment>?
<module_instance> <,<module_instance>>* ;

こんな感じで。

http://www.verilog.com/VerilogBNF.html
BNFと言うものを初めて知りました、ありがとうございます。
まず、BNFのお作法を勉強して、書いて戴いたことを理解します。
インスタンス記述を、C言語なんかの関数の呼び出しと考えてしまうと混乱するかもしれませんね。
インスタンス記述は、モジュールをコンポーネント(データシート)、インスタンスを実体(回路上への配置)と考えるといいかもしれません。

モジュール(データシート)には動作が定義されていますが、ペラ紙は動きません。
そこでモジュール(データシート)を元に実体を回路上に配置します。
同じ物を何個も置けるので、1つ1つインスタンス名で区別します。

ルーシーさんの、
>コンマで区切ってない方は「4個のモジュールを呼び出してる」になり、
>区切って一行で書いたものは「同一のモジュールを複数呼び出す」に変わるのですね。
は誤りで、どちらもモジュール(DEFというモジュールを定義しているデータシート的なもの)はDEFという1つのモノを示しています。
ただし実体化するときは1個1個を区別するため一意な名前(インスタンス名)を付けているわけです。

まとめると、
「DEFという部品の定義を元に、DEF0〜DEF3という一意な名前で回路上に4個実装した」
という意味です。
単なる書き方の問題で、同じDEFを何度も書くのが面倒だからセミコロンで終わらせずにカンマでいっぺんに書き下したようなものです。

あまり上手い説明ではありませんが、こう考えてよいかと思います。
間違っていたら誰かつっこみよろしくお願いします。
BNFというよりそれが載ってるLRM(Language Reference Manual)を探すほうが良いかも…
IEEE1800-2012は正式版がタダで手に入りますよ。
http://standards.ieee.org/getieee/1800/download/1800-2012.pdf

ちなみに最も利用されているVerilog HDLのVerは IEEE 1364-2001 となります。
ググればPDFが落ちてますが、
このVerのLRMは有料なのでご注意をあせあせ

ログインすると、残り1件のコメントが見れるよ

mixiユーザー
ログインしてコメントしよう!

Verilog HDL 更新情報

Verilog HDLのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング