Untitled
unknown
verilog
a year ago
12 kB
1
Indexable
Never
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 endmodule