Language verilog
(synthesizable)
| Date: | 09/14/06 |
| Author: | T |
| URL: | n/a |
| Comments: | 0 |
| Info: | http://en.wikipedia.org/wiki/Verilog |
| Score: |
/* 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
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!
Comments