2
votes

I am currently programming a blackjack game in verilog with several modules including game logic and scoring. The goal of my project is to display onto a screen through VGA and a nexys3 FPGA board the blackjack game. Before I mess with setting up VGA, I need to make sure that my game logic is correctly working and setting the player hand and player score correctly. Unfortunately the player's hand is not being set correctly and is displaying X values where 1s should be. Below are all of my modules and code and at the bottom is the simulation I am running:

This is the main module that calls my other modules.

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

Here are each individual module.

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

player module:

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:

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

controller module:

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

random card generator module:

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

check for blackjack and bust module:

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

debouncer for FPGA button presses:

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

Here is the testbench I am currently running:

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

Here is a image of my simulation which is only testing the initial setup of the game by distributing 2 cards to the player and 1 card to the dealer:

enter image description here

As you can see from the simulation, the card 6 is being added to the players hand when plhit = 1 (this is addcard inside the player module). The correct value that should be displayed in plhand should be 00000110 but instead the 1's are X's.

The issue I am having is that when I am attempting to add a card to a player's total hand score (in 8 bits) the bits that should be a 1 are being set as X. I have tried restating plscore as a reg and tried multiple assigning operations however I have no luck. Any help would be greatly appreciated and if there is any information need I will be happy to respond quickly.

3
When you try to synthesize this, check the error logs for any messages about "latches" or other such problems.tonysdg
I don't see any "latch" error/warning messages. The only ones I am receiving are warnings about "redeclaration of ansi port ***** is not allowed" where ***** is many of the variables I am passing in. These warnings specifically are in the individual modules, such as randomGen, player, etc. but not in the main blackjack moduleDavid Scheibe
According to iverilog (I don't have the Xilinx tools installed right now, unfortunately), it looks like you've not declared card1 and card2 to be vectors in both randomGen, and the same problem with handTotal in checkBust. (In other words - in the module you say reg [7:0] xyz, but in the module declaration you skip the [7:0]).tonysdg
okay I will look into this as well. I haven't had any issues with this sort of syntax in previous projects, however if it removes the warnings than i'm sure it will help the program be stable.David Scheibe
I had a couple of warnings - that seems the most relevant, but I'll play with it later if I have time and see if I can help more. Best of luck!!tonysdg

3 Answers

2
votes

A couple if issue:

Fist off the header. You are mixing ANSI and non-ANSI header styles. This is illegal syntax. Some simulator/synthesizer is allowing it, but it is bad practice. I've already answered header related question in more depth here "object <name> is not declared in verlog" and "Issue with parameters in Modelsim" so I'll just summarize; follow ANSI or non-ANSI, don't blend header styles in the same module. You may use different header styles with different modules, but it is recommended to be consistent. I prefer ANSI style.

For example:

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;
...

should be:

module clock(
    input clk, reset,
    output reg vgaclk
    );
...

module checkBust (
    input clk,
    input [7:0] handTotal,
    output reg bust,
    output reg blackJack
);
...

Some signals (for example vgaclk) are not initialized. You could initialize them inline or an initial block, however it is recommended to reset them in an always block. This way you can restore the initial values without powering down the design. FPGAs have limited number of asynchronous reset flops, so use synchronous reset only. ASIC prefer using asynchronous reset flops to initialize all values and use synchronous reset for dynamic resets. Example:

always @(posedge clk) begin
    if (reset) begin
        hand <= 8'h0;
    end
    if (addCard == 1) begin
        hand <= hand + card;
    end
end

plhand and dlhand are begin driven by controller by player. Based on the code, it should only be assigned within player. controller should send a reset signal to player to set the value back to 0.

The last issue I can quickly spot is that following code is infers level-sensitive latches and assigned in two separate always blocks. Latches are not necessarily bad, but they have a higher change of glitching and should only be used when specifically requited. The fact the variables are assigned in two different always blocks will be a synthesis error. I believe you can safely delete the latching code.

always @(*) begin
    if (plbust == 1)
        pllose <= 1;
    else if (plbj == 1)
        plwin <= 1;
    else if (dlbust == 1)
        plwin <= 1;
end
1
votes

You have to remember that signals in verilog represent physical circuitry. We refer to something that sets a value to a wire signal as a driver. Signals aren't allowed to have multiple drivers, as this can cause shorts (one driver want to put Vdd on a wire, while another connects it to ground).

In your case, both the controller and the player specify that they output to plhand, which makes both of them drivers. So when player want to write a 1 to a bit of plhand, the controller is still writing a 0, which causes a conflict. You should've gotten an error or warning that a signal had multiple drivers, which would let you know that you were getting this behavior.

In short, you can pass a wire between as many modules as you want, but only one of those modules can output to it. So, consider changing curPlHand from an output to an input.

1
votes

NOTE: This is not the problem. See other answers/comments for more information.

In the player module, you don't set hand properly for all conditions. Specifically:

always @(posedge clk) begin
    if (addCard == 1)
        hand <= hand + card;
end

needs to handle addCard != 1. So try:

always @(posedge clk) begin
    if (addCard == 1)
        hand <= hand + card;
    else
        hand <= hand;
end