我目前正在使用verilog编写一个二十一点游戏,其中包括游戏逻辑和评分等几个模块。我的项目的目标是通过VGA和nexys3 FPGA板在二十一点游戏中显示在屏幕上。在设置VGA之前,我需要确保我的游戏逻辑正常工作并正确设置玩家手牌和玩家得分。不幸的是,玩家的手没有正确设置并显示X值应该是1。下面是我的所有模块和代码,底部是我正在运行的模拟:
这是调用我的其他模块的主要模块。
module blackJack(
input clk,
input btnhit, //deal card to player
input btnpass, //stay for player/pass to dealer
input btnreset, //reset game to 0 and redeal
output Hsync,
output Vsync,
output reg [2:0] vgaRed,
output reg [2:0] vgaGreen,
output reg [1:0] vgaBlue
);
wire [7:0] plscore;
wire [7:0] dlscore;
wire [7:0] plhand;
wire [7:0] dlhand;
wire [2:0] state;
wire [7:0] plcard;
wire [7:0] dlcard;
wire plbust;
wire dlbust;
wire plbj;
wire dlbj;
wire plhit;
wire dlhit;
wire plwin;
wire pllose;
reg vgaclk;
wire trigger;
clock vclk(
.clk(clk),
.vgaclk(vgaclk)
);
wire hit;
debouncer hitD(
.clk(clk),
.button_in(btnhit),
.button_out(hit)
);
wire pass;
debouncer passD(
.clk(clk),
.button_in(btnpass),
.button_out(pass)
);
wire reset;
debouncer resetD(
.clk(clk),
.button_in(btnreset),
.button_out(reset)
);
controller cntrl(
.clk(clk),
.trigger(trigger),
.state(state),
.curPlHand(plhand),
.curDlHand(dlhand),
.dlhit(dlhit),
.plhit(plhit),
.plwin(plwin),
.pllose(pllose),
.plscore(plscore),
.dlscore(dlscore)
);
randomGen gen(
.clk(clk),
.card1(plcard),
.card2(dlcard)
);
player pl(
.clk(clk),
.addCard(plhit),
.card(plcard),
.hand(plhand)
);
player dl(
.clk(clk),
.addCard(dlhit),
.card(dlcard),
.hand(dlhand)
);
checkBust chkpl(
.clk(clk),
.handTotal(plhand),
.bust(plbust),
.blackJack(plbj)
);
checkBust chkdl(
.clk(clk),
.handTotal(dlhand),
.bust(dlbust),
.blackJack(dlbj)
);
stateMonitor sm(
.clk(clk),
.reset(reset),
.hit(hit),
.pass(pass),
.plwin(plwin),
.pllose(pllose),
.state(state),
.trigger(trigger)
);
endmodule
以下是每个单独的模块。
module clock(
input clk,
output vgaclk
);
reg vgaclk;
reg [31:0] out = 0;
always @ (posedge clk) begin
if (out >= 3) begin
out <= 0;
end
if (out == 3) begin
vgaclk <= 1;
end
else begin
vgaclk <= 0;
end
out <= out + 1;
end
endmodule
播放器模块:
module player(
input clk,
input addCard,
input [7:0] card,
output [7:0] hand
);
reg [7:0] hand = 0;
always @(posedge clk) begin
if (addCard == 1)
hand <= hand + card;
end
endmodule
statemonitor模块:
module stateMonitor(
input clk,
input reset,
input hit,
input pass,
input plwin,
input pllose,
output [2:0] state,
output trigger
);
reg [2:0] currentState = 3'b000;
reg action = 1;
//modes
//000 = start of game. score = 0 and no hand dealt
//001 = player dealt first card
//010 = player dealt second card
//011 = dealer dealt first card - wait for player to hit or pass
//100 = player hits
//101 = player passes -> dealer hits
//110 = payer wins
//111 = player loses
always @ (posedge clk) begin
if (currentState == 3'b000 && action == 0) begin
currentState <= 3'b001;
action <= 1;
end
else if (currentState == 2'b001 && action == 0) begin
currentState <= 3'b010;
action <= 1;
end
else if (currentState == 3'b010 && action == 0) begin
currentState <= 3'b011;
action <= 1;
end
else if (currentState == 3'b011 && action == 0) begin
if (plwin == 1) begin
currentState <= 3'b110;
action <= 1;
end
else if (hit == 1) begin
currentState <= 3'b100;
action <= 1;
end
else if (pass == 1) begin
currentState <= 3'b101;
action <= 1;
end
else if (reset == 1) begin
currentState <= 3'b000;
action <= 1;
end
end
else if (currentState == 3'b100 && action == 0) begin
if (plwin == 1) begin
currentState <= 3'b110;
action <= 1;
end
else if (pllose == 1) begin
currentState <= 3'b111;
action <= 1;
end
else if (hit == 1) begin
currentState <= 3'b100;
action <= 1;
end
else if (pass == 1) begin
currentState <= 3'b101;
action <= 1;
end
else if (reset == 1) begin
currentState <= 3'b000;
action <= 1;
end
end
else if (currentState == 3'b101 && action == 0) begin
if (plwin == 1) begin
currentState <= 3'b110;
action <= 1;
end
else if (pllose == 1) begin
currentState <= 3'b111;
action <= 1;
end
else if (reset == 1) begin
currentState <= 3'b000;
action <= 1;
end
else
action <= 1;
end
else if (currentState == 3'b110 && action == 0) begin
if (hit == 1)
currentState <= 3'b000;
end
else if (currentState == 3'b111 && action == 0) begin
if (hit == 1)
currentState <= 3'b000;
end
else
action <= 0;
end
assign state = currentState;
assign trigger = action;
endmodule
控制器模块:
module controller(
input clk,
input trigger,
input reset,
input plbust,
input dlbust,
input plbj,
input [2:0] state,
output [7:0] curPlHand,
output [7:0] curDlHand,
output dlhit,
output plhit,
output plwin,
output pllose,
output [7:0] plscore,
output [7:0] dlscore
);
reg [7:0] curPlHand;
reg [7:0] curDlHand;
reg [7:0] plscore;
reg [7:0] dlscore;
//reg plbust;
//reg dlbust;
//reg plscore;
//reg dlscore;
reg plhit = 0;
reg dlhit = 0;
reg plwin = 0;
reg pllose = 0;
//modes
//000 = start of game. score = 0 and no hand dealt
//001 = player dealt first card
//010 = player dealt second card
//011 = dealer dealt first card - wait for player to hit or pass
//100 = player hits
//101 = player passes -> dealer hits
//110 = payer wins
//111 = player loses
always @(*) begin
if (plbust == 1)
pllose <= 1;
else if (plbj == 1)
plwin <= 1;
else if (dlbust == 1)
plwin <= 1;
end
always @(posedge clk) begin
plhit <= 0;
dlhit <= 0;
if (state == 3'b000 && trigger) begin
curPlHand <= 8'b00000000;
curDlHand <= 8'b00000000;
if (reset == 1) begin
plscore <= 8'b00000000;
dlscore <= 8'b00000000;
end
end
else if (state == 3'b001 && trigger) begin
plhit <= 1;
end
else if (state == 3'b010 && trigger) begin
plhit <= 1;
end
else if (state == 3'b011 && trigger) begin
if (plbj == 1)
plwin <= 1;
else
dlhit <= 1;
end
else if (state == 3'b100 && trigger) begin
if (plbust == 1)
pllose <= 1;
else if (plbj == 1)
plwin <= 1;
else
plhit <= 1;
end
else if (state == 3'b101 && trigger) begin
if (dlbust == 1)
plwin <= 1;
else if (plbust == 1)
pllose <= 1;
else if (plbj == 1)
plwin <= 1;
else
dlhit <= 1;
end
/*else if (state == 3'b110) begin
end
else if (state == 3'b111) begin
end
*/
end
endmodule
随机卡生成器模块:
module randomGen (
input clk,
output card1,
output card2
);
reg [7:0] card1;
reg [7:0] card2;
always @ (posedge clk) begin
card1 <= ({$random} % 51 >> 2) + 1;
card2 <= ({$random} % 51 >> 2) + 1;
end
endmodule
检查二十一点和胸围模块:
module checkBust (
input clk,
input handTotal,
output bust,
output blackJack
);
wire [7:0] handTotal;
reg blackJack;
reg bust;
always @(posedge clk) begin
if(handTotal == 8'd21) begin
bust <= 0;
blackJack <= 1;
end
else if(handTotal > 8'd21) begin
bust <= 1;
blackJack <= 0;
end
else begin
bust <= 0;
blackJack <= 0;
end
end
endmodule
按下FPGA按钮的debouncer:
module debouncer(
input clk,
input button_in,
output button_out
);
reg [1:0] button_buffer;
assign button_out = button_buffer[0];
always @(posedge clk or posedge button_in) begin
if (button_in)
button_buffer <= 2'b11;
else
button_buffer <= {1'b0, button_buffer[1]};
end
endmodule
这是我目前正在运行的测试平台:
module testBlackjack;
// Inputs
reg clk;
reg btnhit;
reg btnpass;
reg btnreset;
// Instantiate the Unit Under Test (UUT)
blackJack uut (
.clk(clk),
.btnhit(btnhit),
.btnpass(btnpass),
.btnreset(btnreset)
);
initial begin
// Initialize Inputs
clk = 0;
btnhit = 0;
btnpass = 0;
btnreset = 0;
// Wait 100 ns for global reset to finish
#1000;
$finish;
end
always #20 clk = ~clk;
endmodule
这是我的模拟图像,它只是通过向玩家分发2张牌和向经销商分发1张牌来测试游戏的初始设置:
从模拟中可以看出,当plhit = 1时,卡6被添加到玩家手中(这是播放器模块内的addcard)。应该在plhand中显示的正确值应该是00000110,而是1是X的。
我遇到的问题是,当我尝试将一张卡添加到玩家的总得分(8位)时,应该为1的位被设置为X.我已经尝试将plscore重新设置为reg并尝试了多次分配操作,但我没有运气。任何帮助将不胜感激,如果有任何信息需要,我将很乐意迅速作出回应。
答案 0 :(得分:1)
注意:这不是问题。有关详细信息,请参阅其他答案/评论。
在player
模块中,您无法在所有条件下正确设置hand
。具体做法是:
always @(posedge clk) begin
if (addCard == 1)
hand <= hand + card;
end
需要处理addCard != 1
。所以试试:
always @(posedge clk) begin
if (addCard == 1)
hand <= hand + card;
else
hand <= hand;
end
答案 1 :(得分:1)
你必须记住,verilog中的信号代表物理电路。我们将某些值设置为有线信号作为驱动程序。信号不允许有多个驱动器,因为这可能导致短路(一个驱动器希望将Vdd放在导线上,而另一个驱动器将其连接到地)。
在您的情况下,控制器和播放器都指定它们输出到plhand
,这使它们都成为驱动程序。因此,当玩家想要将1
写入plhand
时,控制器仍在编写0
,这会导致冲突。您应该收到错误或警告信号有多个驱动程序,这会让您知道您正在获得此行为。
简而言之,您可以根据需要在多个模块之间传递线路,但只有其中一个模块可以输出。因此,请考虑将curPlHand
从output
更改为input
。
答案 2 :(得分:1)
一对夫妇如果问题:
拳击头。您正在混合ANSI和非ANSI标头样式。这是非法的语法。一些模拟器/合成器允许它,但这是不好的做法。我已经在这里更深入地回答了与标题相关的问题&#34; object <name> is not declared in verlog&#34;和&#34; Issue with parameters in Modelsim&#34;所以我只是总结一下;遵循ANSI或非ANSI,不要在同一模块中混合标题样式。您可以对不同的模块使用不同的标题样式,但建议保持一致。我更喜欢ANSI风格。
例如:
module clock(
input clk,
output vgaclk
);
reg vgaclk; // <-- this is mixing styles
...
module checkBust (
input clk,
input handTotal,
output bust,
output blackJack
);
wire [7:0] handTotal; // <-- these are mixing styles too
reg blackJack;
reg bust;
...
应该是:
module clock(
input clk, reset,
output reg vgaclk
);
...
module checkBust (
input clk,
input [7:0] handTotal,
output reg bust,
output reg blackJack
);
...
某些信号(例如vgaclk
)未初始化。您可以将它们初始化为内联块或初始块,但建议在always块中重置它们。这样,您可以在不关闭设计的情况下恢复初始值。 FPGA具有有限数量的异步复位触发器,因此仅使用同步复位。 ASIC更喜欢使用异步复位触发器初始化所有值,并使用同步复位进行动态复位。例如:
always @(posedge clk) begin
if (reset) begin
hand <= 8'h0;
end
if (addCard == 1) begin
hand <= hand + card;
end
end
plhand
和dlhand
由controller
开始player
开始。根据代码,它应该只在播放器中分配。 controller
应向player
发送重置信号,以将值设置回0。
我能够快速发现的最后一个问题是,以下代码推断出对级别敏感的锁存器并在两个单独的始终块中分配。锁存器不一定是坏的,但它们具有更高的毛刺变化,并且只应在特别要求时使用。变量在两个不同的始终块中分配的事实将是合成错误。我相信你可以安全地删除锁存代码。
always @(*) begin
if (plbust == 1)
pllose <= 1;
else if (plbj == 1)
plwin <= 1;
else if (dlbust == 1)
plwin <= 1;
end