Voting

Category

real language

Bookmarking

Del.icio.us Digg Diigo DZone Earthlink Google Kick.ie
Windows Live LookLater Ma.gnolia Reddit Rojo StumbleUpon Technorati

Language verilog

(synthesizable)

Date:09/14/06
Author:T
URL:n/a
Comments:0
Info:http://en.wikipedia.org/wiki/Verilog
Score: (2.85 in 13 votes)
/* 99 bottles of beer
 *
 * Inputs:  clock
 *          reset
 *
 * Outputs: ascii_out - one character per clock cycle
 *          done      - assert after last character sent
 *
 * Implemented in synthesizable verilog plus some test bench
 * code. I tested this with vbs verilog simulator. The output
 * matches one of the perl versions which I used as a
 * reference design.
 *
 * I plan to run this through physical synthesis to see what
 * timing looks like. On a 65 nm library, I'm expecting over
 * 1 GHz clock rate or 10 MB/s (million beers per second).
 *
 */


module test_bench;
wire [7:0] ascii_out;
wire       done;
reg        reset;
reg        clock;

bottles bottles99(ascii_out, done, reset, clock);

always@(clock)
  clock <= #5 ~clock;

always@(posedge clock)
  if(!reset && !done)
    $write("%s",ascii_out);

always@(done)
  if(done)
    $finish;

initial
begin
  clock = 1;
  reset = 1;
  #1;
  #10;
  reset = 0;
  #1000000;
  $finish; // Never reached.
end

endmodule


module bottles(ascii_out, done, reset, clock);
output [7:0] ascii_out;
output       done;
input        reset;
input        clock;

wire  [15:0] beer_count; // 2 digits of ascii.
wire         take_one_down;
wire   [6:0] index;

beer_counter beer_counter1(beer_count, take_one_down, reset, clock);

get_char get_char1(ascii_out, index, beer_count, done, reset);

beer_machine beer_sm1(index, done, take_one_down, beer_count, reset, clock);

endmodule


module beer_counter(beer_count, take_one_down, reset, clock);
output [15:0] beer_count; // 2 digits of ascii.
input         take_one_down;
input         reset;
input         clock;

reg    [15:0] beer_count;

always@(posedge clock)
begin
  if(reset)
    beer_count = "99";
  else
  begin
    if(take_one_down)
    begin
      if(beer_count == "01")
        beer_count = "No";
      else
      begin
        if(beer_count[15:8] == "0")
        begin
          beer_count[15:8] = "9";
          beer_count[ 7:0] = beer_count[ 7:0] - 1;
        end
        else
          beer_count[15:8] = beer_count[15:8] - 1;
      end
    end
  end
end

endmodule


module get_char(ascii_out, index, beer_count, done, reset);
output   [7:0] ascii_out;
input    [6:0] index;
input   [15:0] beer_count; // 2 digits of ascii.
input          done;
input          reset;

parameter NEWLINE = 8'h0a;

wire  [1023:0] message;
assign message[  15:   0] = beer_count;
assign message[ 247:  16] = " bottles of beer on the wall,";
assign message[ 255: 248] = NEWLINE;
assign message[ 271: 256] = beer_count;
assign message[ 407: 272] = " bottles of beer,";
assign message[ 415: 408] = NEWLINE;
assign message[ 655: 416] = "Take one down, pass it around,";
assign message[ 663: 656] = NEWLINE;
assign message[ 679: 664] = beer_count;
assign message[ 911: 680] = " bottles of beer on the wall.";
assign message[ 919: 912] = NEWLINE;
assign message[ 927: 920] = NEWLINE;

wire  [511:0] msg_l1;
wire  [255:0] msg_l2;
wire  [127:0] msg_l3;
wire   [63:0] msg_l4;
wire   [31:0] msg_l5;
wire   [15:0] msg_l6;
wire    [7:0] msg_l7;

mux2 #(512) m1(msg_l1[511:0], index[6], message[1023:512], message[511:0]);
mux2 #(256) m2(msg_l2[255:0], index[5],  msg_l1[ 511:256],  msg_l1[255:0]);
mux2 #(128) m3(msg_l3[127:0], index[4],  msg_l2[ 255:128],  msg_l2[127:0]);
mux2 #( 64) m4(msg_l4[ 63:0], index[3],  msg_l3[ 127: 64],  msg_l3[ 63:0]);
mux2 #( 32) m5(msg_l5[ 31:0], index[2],  msg_l4[  63: 32],  msg_l4[ 31:0]);
mux2 #( 16) m6(msg_l6[ 15:0], index[1],  msg_l5[  31: 16],  msg_l5[ 15:0]);
mux2 #(  8) m7(msg_l7[  7:0], index[0],  msg_l6[  15:  8],  msg_l6[  7:0]);

always@(msg_l7 or done or reset)
  if(reset || done)
    ascii_out = 8'h00;
  else
    ascii_out = msg_l7;

endmodule


module mux2 (o, sel, i1, i0);
parameter width = 1;
output [width-1:0] o;
input              sel;
input  [width-1:0] i1;
input  [width-1:0] i0;

wire   [width-1:0] o;
assign o = ({width{sel}} & i1) | ({width{~sel}} & i0);
endmodule


module beer_machine(
           index, done, take_one_down, beer_count, reset, clock);
output  [6:0] index;
output        done;
output        take_one_down;
input  [15:0] beer_count; // 2 digits of ascii.
input         reset;
input         clock;

parameter FIRST_CHAR         = 7'h00,
          FIRST_CHAR_NO_TENS = 7'h01,
          SKIP_TENS_A        = 7'd31,
          SKIP_TENS_B        = 7'd82,
          SKIP_PLURAL_A      = 7'd08,
          SKIP_PLURAL_B      = 7'd40,
          SKIP_PLURAL_C      = 7'd91,
          TAKE_ONE_DOWN      = 7'd52,
          LAST_CHAR          = 7'd115;

reg  [6:0] current_state;
reg  [6:0] next_state;
reg done;
reg take_one_down;
wire [6:0] index = current_state;

always@(posedge clock)
  if(reset)
    current_state <= 0;
  else
    current_state <= next_state;

always@(current_state or beer_count or reset)
begin
  next_state    = current_state + 1;
  done          = 1'b0;
  take_one_down = 1'b0;

  case(current_state)
    LAST_CHAR: begin
        if(beer_count == "No") begin
          next_state = LAST_CHAR;
          done       = 1'b1;
        end
        else
          if(beer_count[7:0] == "0")
            next_state = FIRST_CHAR_NO_TENS;
          else
            next_state = FIRST_CHAR;
      end
    TAKE_ONE_DOWN: begin
        take_one_down = 1'b1;
      end
    SKIP_TENS_A: begin
        if(beer_count[7:0] == "0")
           next_state = SKIP_TENS_A + 2;
      end
    SKIP_TENS_B: begin
        if(beer_count[7:0] == "0")
           next_state = SKIP_TENS_B + 2;
      end
    SKIP_PLURAL_A: begin
        if(beer_count == "01")
          next_state = SKIP_PLURAL_A + 2;
      end
    SKIP_PLURAL_B: begin
        if(beer_count == "01")
          next_state = SKIP_PLURAL_B + 2;
      end
    SKIP_PLURAL_C: begin
        if(beer_count == "01")
          next_state = SKIP_PLURAL_C + 2;
      end
  endcase
end

endmodule

Download Source | Write Comment

Alternative Versions

VersionAuthorDateCommentsRate
1Danny Mulligan04/20/052

Comments

Download Source | Write Comment

Add Comment

Please provide a value for the fields Name, Comment and Security Code.
This is a gravatar-friendly website.
E-mail addresses will never be shown.
Enter your e-mail address to use your gravatar.

Please don't post large portions of code here! Use the form to submit new examples or updates instead!

Name:

eMail:

URL:

Security Code:
  
Comment: