Untitled

mail@pastecode.io avatar
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