Untitled
unknown
verilog
2 years ago
12 kB
6
Indexable
module lab4_1 (
input wire clk,
input wire rst,
input wire stop,
input wire start,
input wire direction,
output reg [3:0] DIGIT,
output reg [6:0] DISPLAY,
output reg [9:0] led
);
parameter INITIAL = 2'b00;
parameter PREPARE = 2'b01;
parameter COUNTING = 2'b10;
parameter RESULT = 2'b11;
wire clk_16;
wire clk_24;
wire clk_25;
wire clk_100hz;
wire clk_26;
wire clk_27;
wire clk_1hz;
wire [15:0] bcd_v;
reg [1:0] state = INITIAL;
reg [1:0] next_state;
reg [7:0] offset_cnt;
reg [7:0] next_offset_cnt;
reg [3:0] value;
reg [9:0] counter;
reg [9:0] next_counter;
reg [3:0] prepare_state_count;
reg [9:0] next_led;
reg [9:0] next_next_led;
reg [3:0] next_digit;
reg dir;
reg next_dir;
integer index;
integer j;
wire [3:0] bcd_0 = bcd_v[3:0];
wire [3:0] bcd_1 = bcd_v[7:4];
wire [3:0] bcd_2 = bcd_v[11:8];
wire [3:0] bcd_3 = bcd_v[15:12];
clock_divider #(.n(16)) c16 (.clk(clk), .clk_div(clk_16));
clock_divider_decimal #(.n(1000000)) c100hz (.clk(clk), .clk_div(clk_100hz));
clock_divider #(.n(24)) c24 (.clk(clk), .clk_div(clk_24));
clock_divider #(.n(25)) c25 (.clk(clk), .clk_div(clk_25));
clock_divider #(.n(26)) c26 (.clk(clk), .clk_div(clk_26));
clock_divider #(.n(27)) c27 (.clk(clk), .clk_div(clk_27));
clock_divider_decimal #(.n(100000000)) c1hz (.clk(clk), .clk_div(clk_1hz));
wire db_start;
debounce debounce_start (.clk(clk_100hz), .pb(start), .pb_debounced(db_start));
wire pause_start;
one_pulse op1 (.clk(clk_24), .pb_in(db_start), .pb_out(pause_start));
wire db_stop;
debounce debounce_stop (.clk(clk_100hz), .pb(stop), .pb_debounced(db_stop));
wire pause_stop;
one_pulse op2 (.clk(clk_24), .pb_in(db_stop), .pb_out(pause_stop));
wire db_direction;
debounce debounce_direction (.clk(clk_100hz), .pb(direction), .pb_debounced(db_direction));
wire pause_direction;
one_pulse op3 (.clk(clk_24), .pb_in(db_direction), .pb_out(pause_direction));
bin2bcd b2b (.bin(counter), .bcd(bcd_v));
//state transition
always @(posedge clk_24 or posedge rst) begin
if (rst) begin
state <= INITIAL;
end
else begin
state <= next_state;
end
end
always @(*) begin
if (rst) begin
next_state = INITIAL;
end
else begin
case (state)
INITIAL: begin
if (pause_start) begin
next_state = PREPARE;
end
else begin
next_state = INITIAL;
end
end
PREPARE: begin
if (offset_cnt == 2) begin
next_state = COUNTING;
end
else begin
next_state = PREPARE;
end
end
COUNTING: begin
if (pause_stop || (dir && counter == 10'd999) || (!dir && counter == 10'd0)) begin
next_state = RESULT;
end
else begin
next_state = COUNTING;
end
end
RESULT: begin
if (pause_start) begin
next_state = INITIAL;
end
else next_state = RESULT;
end
endcase
end
end
always@(posedge clk_1hz or posedge rst) begin
if (rst) begin
offset_cnt <= 8'd0;
end
else begin
offset_cnt <= next_offset_cnt;
end
end
always@(*) begin
case(state)
INITIAL: begin
next_offset_cnt = 0;
end
PREPARE: begin
if (next_state == PREPARE) begin
next_offset_cnt = offset_cnt + 1;
end
else begin
next_offset_cnt = 0;
end
end
COUNTING: begin
next_offset_cnt = 0;
end
RESULT: begin
if (next_state == RESULT) begin
next_offset_cnt = offset_cnt + 1;
end
else begin
next_offset_cnt = 0;
end
end
default: begin
next_offset_cnt = offset_cnt;
end
endcase
end
//led
always @(posedge clk_100hz or posedge rst) begin
if (rst) begin
led <= 16'b1111111111111111;
end
else begin
led <= next_led;
end
end
always @(*) begin
if (rst) begin
next_led = 16'b1111111111111111;
end
else begin
if (state == INITIAL) begin
if (next_state == PREPARE) next_led = 16'b0000000000000000;
else next_led = 16'b1111111111111111;
end
else if (state == PREPARE)
next_led = 16'b0000000000000000;
else if (state == COUNTING) begin
if (next_state == RESULT) next_led = 16'b1111111111111111;
else begin
index = bcd_2;
for (j = 0; j < 10; j = j + 1) begin
if (index == j)
next_led[j] = 1;
else
next_led[j] = 0;
end
end
end
else begin
if (offset_cnt == 0) next_led = 16'b1111111111111111;
else if (offset_cnt == 1) next_led = 16'b1111111111111111;
else if (offset_cnt == 2) next_led = 16'b0000000000000000;
else if (offset_cnt == 3) next_led = 16'b1111111111111111;
else if (offset_cnt == 4) next_led = 16'b0000000000000000;
else next_led = 16'b1111111111111111;
end
end
end
//counter
always @(posedge clk_100hz or posedge rst) begin
if (rst) begin
counter <= 0;
end
else begin
counter <= next_counter;
end
end
always @(*) begin
case (state)
INITIAL: begin
if (dir) next_counter = 10'b0000000000;
else next_counter = 10'b1111100111;
end
PREPARE: begin
next_counter = counter;
end
COUNTING: begin
if (dir) begin
if (counter == 10'd999) begin
next_counter = counter;
end
else
next_counter = counter + 1;
end
else begin
if (counter == 10'd0) begin
next_counter = counter;
end
else
next_counter = counter - 1;
end
end
RESULT: begin
next_counter = counter;
end
endcase
end
//dir
always @(posedge clk_24 or posedge rst) begin
if (rst) begin
dir <= 1;
end
else begin
dir <= next_dir;
end
end
always @(*) begin
case (state)
INITIAL: begin
next_dir = dir;
if (pause_direction) begin
next_dir = !dir;
end
end
PREPARE:
next_dir = dir;
COUNTING: begin
next_dir = dir;
if (pause_direction) begin
next_dir = !dir;
end
end
RESULT:
next_dir = dir;
default:
next_dir = dir;
endcase
end
//counter output
always @(posedge clk_16) begin
if (rst) begin
DIGIT <= next_digit;
end
else begin
DIGIT <= next_digit;
end
end
always @(*) begin
case (DIGIT)
4'b1110: begin
value = bcd_0;
next_digit = 4'b1101;
end
4'b1101: begin
value = bcd_1;
next_digit = 4'b1011;
end
4'b1011: begin
value = bcd_2;
next_digit = 4'b0111;
end
4'b0111: begin
if (dir)
value = 4'd10;
else
value = 4'd11;
next_digit = 4'b1110;
end
default: begin
value = bcd_0;
next_digit = 4'b1110;
end
endcase
end
always @(*) begin
if (state == INITIAL) begin
if (dir) begin
if (DIGIT == 4'b1110) DISPLAY = 7'b0111111;
else if (DIGIT == 4'b1101) DISPLAY = 7'b0111111;
else if (DIGIT == 4'b1011) DISPLAY = 7'b0111111;
else DISPLAY = 7'b1011100;
end
else begin
if (DIGIT == 4'b1110) DISPLAY = 7'b0111111;
else if (DIGIT == 4'b1101) DISPLAY = 7'b0111111;
else if (DIGIT == 4'b1011) DISPLAY = 7'b0111111;
else DISPLAY = 7'b1100011;
end
end
else if (state == PREPARE) begin
if (DIGIT == 4'b1110) DISPLAY = 7'b1111111;
else if (DIGIT == 4'b1101) DISPLAY = 7'b1111111;
else if (DIGIT == 4'b1011) DISPLAY = 7'b1111111;
else DISPLAY = 7'b0001100;
end
else begin
case (value) //gfedcba
4'd0 : DISPLAY = 7'b1000000;
4'd1 : DISPLAY = 7'b1111001;
4'd2 : DISPLAY = 7'b0100100;
4'd3 : DISPLAY = 7'b0110000;
4'd4 : DISPLAY = 7'b0011001;
4'd5 : DISPLAY = 7'b0010010;
4'd6 : DISPLAY = 7'b0000010;
4'd7 : DISPLAY = 7'b1111000;
4'd8 : DISPLAY = 7'b0000000;
4'd9 : DISPLAY = 7'b0010000;
4'd10 : DISPLAY = 7'b1011100;//up
4'd11 : DISPLAY = 7'b1100011;//down
4'd12 : DISPLAY = 7'b0111111;//-
4'd13 : DISPLAY = 7'b0001100;//P
4'd14 : DISPLAY = 7'b1111111;//
default : DISPLAY = 7'b1111111;
endcase
end
end
endmodule
module bin2bcd(
input [9:0] bin,
output reg [15:0] bcd
);
integer i;
always @(bin) begin
bcd = 0;
for (i = 0; i < 10; i = i + 1) begin
if (bcd[3:0] >= 5)
bcd[3:0] = bcd[3:0] + 3;
if (bcd[7:4] >= 5)
bcd[7:4] = bcd[7:4] + 3;
if (bcd[11:8] >= 5)
bcd[11:8] = bcd[11:8] + 3;
if (bcd[15:12] >= 5)
bcd[15:12] = bcd[15:12] + 3;
bcd = {bcd[14:0], bin[9 - i]};
end
end
endmodule
module clock_divider #(
parameter n = 27
)(
input wire clk,
output wire clk_div
);
reg [n-1:0] num;
wire [n-1:0] next_num;
always @(posedge clk) begin
num <= next_num;
end
assign next_num = num + 1;
assign clk_div = num[n-1];
endmodule
module debounce (
input wire clk,
input wire pb,
output wire pb_debounced
);
reg [3:0] shift_reg;
always @(posedge clk) begin
shift_reg[3:1] <= shift_reg[2:0];
shift_reg[0] <= pb;
end
assign pb_debounced = ((shift_reg == 4'b1111) ? 1'b1 : 1'b0);
endmodule
module one_pulse (
input wire clk,
input wire pb_in,
output reg pb_out
);
reg pb_in_delay;
always @(posedge clk) begin
if (pb_in == 1'b1 && pb_in_delay == 1'b0) begin
pb_out <= 1'b1;
end else begin
pb_out <= 1'b0;
end
end
always @(posedge clk) begin
pb_in_delay <= pb_in;
end
endmodule
module clock_divider_decimal #(
parameter n = 28'd2
)(
input clk,
output reg clk_div
);
reg [27:0] counter = 0;
always @(posedge clk) begin
counter <= counter + 1;
if(counter >= (n-1)) begin
counter <= 0;
end
clk_div <= (counter < n/2) ? 1'b1 : 1'b0;
end
endmoduleEditor is loading...