前言
主包在经历了两个月秋招受到面试手撕代码狠狠的拷打之后是在是受不了了,决定痛定思痛好好学习手撕,以及一些被狠狠拷打的八股等。本章作为提纲总结一下都需要学啥,希望能补救的及时,八股也得好好看
手撕代码
div_4
module div_4( input clk, input rst, output reg clk_div ); reg [1:0] cnt; always @(posedge clk) begin if (rst) begin cnt <= 2'd0; clk_div <= 1'b0; end else begin if (cnt == 2'd3) begin cnt <= 2'd0; clk_div <= ~clk_div; end else begin cnt <= cnt + 2'd1; end end end endmodulediv_5
module div_5( input clk, input rst_n, output wire clk_div ); reg [2:0] cnt; reg clk_pos, clk_neg; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin cnt <= 1'b0; end else begin if (cnt == 3'd4) begin cnt <= 1'b0; end else begin cnt <= cnt + 3'd1; end end end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin clk_pos <= 1'd0; end else begin if (cnt < 3'd2) begin clk_pos <= 1'd1; end else begin clk_pos <= 1'd0; end end end always @(negedge clk or negedge rst_n) begin if (!rst_n) begin clk_neg <= 1'd0; end else begin if (cnt < 3'd2) begin clk_neg <= 1'd1; end else begin clk_neg <= 1'd0; end end end assign clk_div = clk_pos | clk_neg; endmoduleseq_1011
module seq_1011( input clk, input rst_n, input din, output reg dout ); reg [1:0] state; reg [1:0] next_state; parameter IDLE = 2'd0, S1 = 2'd1, S10 = 2'd2, S101 = 2'd3; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin state <= IDLE; end else begin state <= next_state; end end always @(*) begin next_state = state; case (state) IDLE: begin if (din == 1) begin next_state = S1; end else begin next_state = IDLE; end end S1: begin if (din == 1) begin next_state = S1; end else begin next_state = S10; end end S10: begin if (din == 1) begin next_state = S101; end else begin next_state = IDLE; end end S101: begin if (din == 1) begin next_state = S1; end else begin next_state = S10; end end default: begin next_state = IDLE; end endcase end always @(*) begin dout = 0; if (state == S101 && din) begin dout = 1; end end endmodulesync_fifo
module sync_fifo( input wire clk, input wire rst_n, input wire wr_en, input wire [7:0] din, input wire rd_en, output reg [7:0] dout, output wire empty, output wire full ); reg [7:0] mem [0:7]; reg [2:0] wr_ptr; reg [2:0] rd_ptr; reg [3:0] count; assign full = (count == 3'd8); assign empty = (count == 3'd0); // Write always @(posedge clk or negedge rst_n) begin if (!rst_n) begin wr_ptr <= 3'd0; end else if (wr_en && !full) begin mem[wr_ptr] <= din; wr_ptr <= wr_ptr + 3'd1; end end // Read always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rd_ptr <= 3'd0; dout <= 8'd0; end else if (rd_en && !empty) begin dout <= mem[rd_ptr]; rd_ptr <= rd_ptr + 3'd1; end end // Counter always @(posedge clk or negedge rst_n) begin if (!rst_n) begin count <= 3'd0; end else begin case ({wr_en && !full, rd_en && !empty}) 2'd2: count <= count + 3'd1; 2'd1: count <= count - 3'd1; default: count <= count; endcase end end endmoduleasync_fifo
module async_fifo( input wr_clk, input rd_clk, input rst_n, input wr_en, input [7:0] din, input rd_en, output reg [7:0] dout, output reg full, output reg empty ); reg [8:0] wr_bin; reg [8:0] wr_bin_next; reg [8:0] wr_gray; reg [8:0] wr_gray_next; reg [8:0] wr_gray_sync1; reg [8:0] wr_gray_sync2; reg [8:0] rd_bin; reg [8:0] rd_bin_next; reg [8:0] rd_gray; reg [8:0] rd_gray_next; reg [8:0] rd_gray_sync1; reg [8:0] rd_gray_sync2; reg [7:0] mem [0:255]; wire full_next; wire empty_next; assign wr_bin_next = wr_bin + ((wr_en && !full) ? 1'b1 : 1'b0); assign wr_gray_next = (wr_bin_next >> 1) ^ wr_bin_next; assign rd_bin_next = rd_bin + ((rd_en && !empty) ? 1'b1 : 1'b0); assign rd_gray_next = (rd_bin_next >> 1) ^ rd_bin_next; // Write domain always @(posedge wr_clk or negedge rst_n) begin if (!rst_n) begin wr_bin <= 9'd0; wr_gray <= 9'd0; full <= 1'b0; end else begin if (wr_en && !full) begin mem[wr_bin[7:0]] <= din; end wr_bin <= wr_bin_next; wr_gray <= wr_gray_next; full <= full_next; end end // Read domain always @(posedge rd_clk or negedge rst_n) begin if (!rst_n) begin rd_bin <= 9'd0; rd_gray <= 9'd0; dout <= 8'd0; empty <= 1'b0; end else begin if (rd_en && !empty) begin dout <= mem[rd_bin[7:0]]; end rd_bin <= rd_bin_next; rd_gray <= rd_gray_next; empty <= empty_next; end end // Synchronize read Gray pointer into write clock domain always @(posedge wr_clk or negedge rst_n) begin if (!rst_n) begin rd_gray_sync1 <= 9'd0; rd_gray_sync2 <= 9'd0; end else begin rd_gray_sync1 <= rd_gray; rd_gray_sync2 <= rd_gray_sync1; end end // Synchronize write Gray pointer into read clock domain always @(posedge rd_clk or negedge rst_n) begin if (!rst_n) begin wr_gray_sync1 <= 9'd0; wr_gray_sync2 <= 9'd0; end else begin wr_gray_sync1 <= wr_gray; wr_gray_sync2 <= wr_gray_sync1; end end assign empty_next = (rd_gray_next == wr_gray_sync2); assign full_next = (wr_gray_next == {~rd_gray_sync2[8:7], rd_gray_sync2[6:0]}); endmodulecdc_handshake
module cdc_handshake ( input wire clk_src, input wire clk_dst, input wire rst_n, input wire src_pluse, output reg dst_pluse, output reg src_busy ); reg req_src; reg req_sync1; reg req_sync2; reg req_sync2_d; reg ack_dst; reg ack_sync1; reg ack_sync2; always @(posedge clk_dst or negedge rst_n)begin if(!rst_n)begin req_sync1 <= 1'd0; req_sync2 <= 1'd0; req_sync2_d <= 1'd0; end else begin req_sync1 <= req_src; req_sync2 <= req_sync1; req_sync2_d <= req_sync2; end end always @(posedge clk_src or negedge rst_n)begin if(!rst_n)begin ack_sync1 <= 1'd0; ack_sync2 <= 1'd0; end else begin ack_sync1 <= ack_dst; ack_sync2 <= ack_sync1; end end always @(posedge clk_src or negedge rst_n)begin if(!rst_n)begin req_src <= 1'd0; end else begin if(src_pluse && !src_busy)begin req_src <= 1'd1; end else if(ack_sync2) begin req_src <= 1'd0; end end end always @(posedge clk_dst or negedge rst_n)begin if(!rst_n)begin ack_dst <= 1'd0; end else begin if(req_sync2)begin ack_dst <= 1'd1; end else begin ack_dst <= 1'd0; end end end assign dst_pluse = req_sync2 & ~req_sync2_d; assign src_busy = req_src | ack_sync2; endmoduleround_robin_arbiter_2
module round_robin_arbiter_2( input wire clk, input wire rst_n, input wire req0, input wire req1, output reg gnt0, output reg gnt1 ); //req0 last_gnt 0 //req1 last_gnt 1 reg last_gnt; always@(*)begin gnt0 = 1'b0; gnt1 = 1'b0; case({req0,req1}) 2'b00:begin gnt0 = 1'b0; gnt1 = 1'b0; end 2'b10:begin gnt0 = 1'b1; gnt1 = 1'b0; end 2'b01:begin gnt0 = 1'b0; gnt1 = 1'b1; end 2'b11:begin if(last_gnt)begin gnt0 = 1'b1; gnt1 = 1'b0; end else begin gnt0 = 1'b0; gnt1 = 1'b1; end end default:begin gnt0 = 1'b0; gnt1 = 1'b0; end endcase end always@(posedge clk or negedge rst_n)begin if(!rst_n)begin last_gnt <= 1'b0; end else begin if(req0)begin last_gnt <= 1'b0; end else if(req1) begin last_gnt <= 1'b1; end end end endmoduleround_robin_arbiter_4
module round_robin_arbiter_4( input wire clk, input wire rst_n, input wire [3:0] req, output reg [3:0] gnt ); reg [3:0] last_gnt; always@(*)begin gnt = 4'b0000; case(last_gnt) 4'd0:begin if(req[1]) gnt = 4'b0010; else if(req[2]) gnt = 4'b0100; else if(req[3]) gnt = 4'b1000; else if(req[0]) gnt = 4'b0001; end 4'd1:begin if(req[2]) gnt = 4'b0100; else if(req[3]) gnt = 4'b1000; else if(req[0]) gnt = 4'b0001; else if(req[1]) gnt = 4'b0010; end 4'd2:begin if(req[3]) gnt = 4'b1000; else if(req[0]) gnt = 4'b0001; else if(req[1]) gnt = 4'b0010; else if(req[2]) gnt = 4'b0100; end 4'd3:begin if(req[0]) gnt = 4'b0001; else if(req[1]) gnt = 4'b0010; else if(req[2]) gnt = 4'b0100; else if(req[3]) gnt = 4'b1000; end default:begin gnt = 4'b0000; end endcase end always@(posedge clk or negedge rst_n)begin if(!rst_n)begin last_gnt <= 4'd3; end else begin if(gnt[0]) last_gnt <= 4'd0; else if(gnt[1]) last_gnt <= 4'd1; else if(gnt[2]) last_gnt <= 4'd2; else if(gnt[3]) last_gnt <= 4'd3; end end endmodulemod3
module mod3( input wire clk, input wire rst_n, input wire din, output reg dout ); reg [1:0] state; reg [1:0] next_state; parameter S0 = 2'd0, S1 = 2'd1, S2 = 2'd2; always@(posedge clk or negedge rst_n)begin if(!rst_n)begin state <= S0; end else begin state <= next_state; end end always@(*)begin next_state = state; case(state) S0:begin if(din)begin next_state = S1; end else begin next_state = S0; end end S1:begin if(din)begin next_state = S0; end else begin next_state = S2; end end S2:begin if(din)begin next_state = S2; end else begin next_state = S1; end end default:begin next_state = S0; end endcase end always@(*)begin if(state == S0)begin dout = 1'b1; end else begin dout = 1'b0; end end endmodule边沿检测器
module edge_detector ( input wire clk, input wire rst_n, input wire din, output wire pos_edge, output wire neg_edge, output wire both_edge ); reg din_d; always @(posedge clk or negedge rst_n) begin if (!rst_n) din_d <= 1'b0; else din_d <= din; end // Rising edge detection assign pos_edge = din & ~din_d; // Falling edge detection assign neg_edge = ~din & din_d; // Both-edge detection assign both_edge = din ^ din_d; endmodule单 bit CDC 两级同步器
module cdc_sync_2ff ( input wire clk_dst, input wire rst_n, input wire async_in, output wire sync_out ); reg sync_ff1; reg sync_ff2; // Two-flop synchronizer always @(posedge clk_dst or negedge rst_n) begin if (!rst_n) begin sync_ff1 <= 1'b0; sync_ff2 <= 1'b0; end else begin sync_ff1 <= async_in; sync_ff2 <= sync_ff1; end end assign sync_out = sync_ff2; endmodule慢时钟域 → 快时钟域脉冲同步
module pulse_sync_slow_to_fast ( input wire clk_dst, input wire rst_n, input wire pulse_src, output wire pulse_dst ); reg sync_ff1; reg sync_ff2; reg sync_ff2_d; always @(posedge clk_dst or negedge rst_n) begin if (!rst_n) begin sync_ff1 <= 1'b0; sync_ff2 <= 1'b0; sync_ff2_d <= 1'b0; end else begin sync_ff1 <= pulse_src; sync_ff2 <= sync_ff1; sync_ff2_d <= sync_ff2; end end // Generate one-cycle pulse assign pulse_dst = sync_ff2 & ~sync_ff2_d; endmodule快时钟域 → 慢时钟域:Toggle 同步
module pulse_sync_toggle ( input wire clk_src, input wire clk_dst, input wire rst_n, input wire pulse_src, output wire pulse_dst ); reg toggle_src; reg toggle_sync1; reg toggle_sync2; reg toggle_sync2_d; // Toggle the source bit for every source pulse always @(posedge clk_src or negedge rst_n) begin if (!rst_n) toggle_src <= 1'b0; else if (pulse_src) toggle_src <= ~toggle_src; end // Synchronize toggle bit into destination domain always @(posedge clk_dst or negedge rst_n) begin if (!rst_n) begin toggle_sync1 <= 1'b0; toggle_sync2 <= 1'b0; toggle_sync2_d <= 1'b0; end else begin toggle_sync1 <= toggle_src; toggle_sync2 <= toggle_sync1; toggle_sync2_d <= toggle_sync2; end end // Detect any toggle change assign pulse_dst = toggle_sync2 ^ toggle_sync2_d; endmodule脉冲展宽
module pulse_stretcher ( input wire clk, input wire rst_n, input wire pulse_in, output wire pulse_out ); reg [2:0] cnt; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin cnt <= 3'd0; end else begin if (pulse_in) begin cnt <= 3'd4; end else if (cnt != 3'd0) begin cnt <= cnt - 1'b1; end end end assign pulse_out = (cnt != 3'd0); endmodule串转并 SIPO
module sipo ( input wire clk, input wire rst_n, input wire serial_in, output reg [7:0] parallel_out, output reg data_valid ); reg [7:0] shift_reg; reg [2:0] bit_cnt; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin shift_reg <= 8'd0; parallel_out <= 8'd0; bit_cnt <= 3'd0; data_valid <= 1'b0; end else begin // Default value data_valid <= 1'b0; // Shift in one serial bit shift_reg <= {shift_reg[6:0], serial_in}; if (bit_cnt == 3'd7) begin parallel_out <= {shift_reg[6:0], serial_in}; bit_cnt <= 3'd0; data_valid <= 1'b1; end else begin bit_cnt <= bit_cnt + 1'b1; end end end endmodule并转串 PISO
module piso ( input wire clk, input wire rst_n, input wire load, input wire [7:0] parallel_in, output wire serial_out ); reg [7:0] shift_reg; assign serial_out = shift_reg[7]; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin shift_reg <= 8'd0; end else begin if (load) shift_reg <= parallel_in; else shift_reg <= {shift_reg[6:0], 1'b0}; end end endmodule模 N 计数器
module mod_n_counter #( parameter N = 10, parameter WIDTH = 4 )( input wire clk, input wire rst_n, input wire en, output reg [WIDTH-1:0] cnt ); always @(posedge clk or negedge rst_n) begin if (!rst_n) begin cnt <= 0; end else if (en) begin if (cnt == N - 1) cnt <= 0; else cnt <= cnt + 1'b1; end end endmodule加减计数器
module up_down_counter ( input wire clk, input wire rst_n, input wire en, input wire up_down, output reg [7:0] cnt ); always @(posedge clk or negedge rst_n) begin if (!rst_n) begin cnt <= 8'd0; end else if (en) begin if (up_down) cnt <= cnt + 1'b1; else cnt <= cnt - 1'b1; end end endmodule饱和计数器
module saturating_counter ( input wire clk, input wire rst_n, input wire en, input wire up_down, output reg [7:0] cnt ); always @(posedge clk or negedge rst_n) begin if (!rst_n) begin cnt <= 8'd0; end else if (en) begin if (up_down) begin // Saturate at maximum value if (cnt != 8'hFF) cnt <= cnt + 1'b1; end else begin // Saturate at minimum value if (cnt != 8'h00) cnt <= cnt - 1'b1; end end end endmodule找最低位第一个 1
module priority_encoder_8 ( input wire [7:0] din, output reg [2:0] pos, output reg valid ); always @(*) begin pos = 3'd0; valid = 1'b1; if (din[0]) pos = 3'd0; else if (din[1]) pos = 3'd1; else if (din[2]) pos = 3'd2; else if (din[3]) pos = 3'd3; else if (din[4]) pos = 3'd4; else if (din[5]) pos = 3'd5; else if (din[6]) pos = 3'd6; else if (din[7]) pos = 3'd7; else begin pos = 3'd0; valid = 1'b0; end end endmodule提取最低位的 1
module isolate_lowest_one ( input wire [7:0] din, output wire [7:0] dout ); assign dout = din & (~din + 1'b1); endmodulePWM
module pwm ( input wire clk, input wire rst_n, input wire [7:0] duty, output wire pwm_out ); reg [7:0] cnt; always @(posedge clk or negedge rst_n) begin if (!rst_n) cnt <= 8'd0; else cnt <= cnt + 1'b1; end assign pwm_out = (cnt < duty); endmodule