前两面是流程完全相同而面试官不同的技术面,三面为主管面。
一面 1h
纯项目,A4纸边画边讲,提问也针对项目细节不断往深挖掘
手撕:同步FIFO,同一周期内,写0-1个数据,读0-2个数据
verilog
module sync_fifo_ptr #(
parameter DATA_WIDTH = 8, // 数据位宽
parameter FIFO_DEPTH = 16 // FIFO深度(必须是2的幂)
)(
input wire clk, // 时钟
input wire rst_n, // 异步复位(低有效)
input wire wr_en, // 写使能(0或1)
input wire [DATA_WIDTH-1:0] wr_data, // 写数据
input wire [1:0] rd_en, // 读使能(0、1或2)
output wire [DATA_WIDTH-1:0] rd_data0, // 读数据0
output wire [DATA_WIDTH-1:0] rd_data1, // 读数据1
output wire empty, // 空标志
output wire full // 满标志
);
// 计算地址宽度
localparam ADDR_WIDTH = $clog2(FIFO_DEPTH);
// 存储器
reg [DATA_WIDTH-1:0] mem [0:FIFO_DEPTH-1];
// 读写指针(扩展一位用于空满判断)
reg [ADDR_WIDTH:0] wr_ptr = 0; // MSB用于区分绕回
reg [ADDR_WIDTH:0] rd_ptr = 0; // MSB用于区分绕回
// 读数据寄存器
reg [DATA_WIDTH-1:0] rd0_reg;
reg [DATA_WIDTH-1:0] rd1_reg;
// 空满判断
assign empty = (wr_ptr == rd_ptr);
assign full = ((wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0]) &&
(wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]));
// 读数据输出
assign rd_data0 = rd0_reg;
assign rd_data1 = rd1_reg;
// 写操作
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wr_ptr <= 0;
end else if (wr_en && !full) begin
mem[wr_ptr[ADDR_WIDTH-1:0]] <= wr_data;
wr_ptr <= wr_ptr + 1;
end
end
// 读操作
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rd_ptr <= 0;
rd0_reg <= 0;
rd1_reg <= 0;
end else begin
case (rd_en)
2'd1: begin // 读1个数据
if (!empty) begin
rd0_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr <= rd_ptr + 1;
rd1_reg <= 0;
end else begin
rd0_reg <= 0;
rd1_reg <= 0;
end
end
2'd2: begin // 读2个数据
if (!empty) begin
rd0_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
// 检查是否有第二个数据可读
if ((rd_ptr + 1) != wr_ptr) begin
rd1_reg <= mem[(rd_ptr + 1)[ADDR_WIDTH-1:0]];
rd_ptr <= rd_ptr + 2;
end else begin
rd1_reg <= 0;
rd_ptr <= rd_ptr + 1;
end
end else begin
rd0_reg <= 0;
rd1_reg <= 0;
end
end
default: begin // 不读
rd0_reg <= 0;
rd1_reg <= 0;
end
endcase
end
end
endmodule
二面 1h
纯项目,会问一面重点讲的哪一个,换另外的详细讲
手撕:深度32的SRAM,用两个拼成深度64
verilog
module sram_64xN #(
parameter DATA_WIDTH = 8 // 数据位宽
)(
input wire clk, // 时钟
input wire cen, // 片选信号(低有效)
input wire wen, // 写使能(低有效)
input wire [5:0] addr, // 6位地址(0-63)
input wire [DATA_WIDTH-1:0] wdata, // 写数据
output wire [DATA_WIDTH-1:0] rdata // 读数据
);
// 内部信号定义
wire sram0_cen; // SRAM0片选
wire sram1_cen; // SRAM1片选
wire [DATA_WIDTH-1:0] sram0_rdata; // SRAM0读数据
wire [DATA_WIDTH-1:0] sram1_rdata; // SRAM1读数据
// 地址最高位作为SRAM选择
// addr[5]=0: 选择SRAM0 (地址0-31)
// addr[5]=1: 选择SRAM1 (地址32-63)
// SRAM0片选逻辑:当cen有效且地址高位为0时选中
assign sram0_cen = cen | addr[5];
// SRAM1片选逻辑:当cen有效且地址高位为1时选中
assign sram1_cen = cen | ~addr[5];
// 实例化两个深度32的SRAM
sram_32xN #(
.DATA_WIDTH(DATA_WIDTH)
) sram0 (
.clk(clk),
.cen(sram0_cen),
.wen(wen),
.addr(addr[4:0]), // 低5位地址
.wdata(wdata),
.rdata(sram0_rdata)
);
sram_32xN #(
.DATA_WIDTH(DATA_WIDTH)
) sram1 (
.clk(clk),
.cen(sram1_cen),
.wen(wen),
.addr(addr[4:0]), // 低5位地址
.wdata(wdata),
.rdata(sram1_rdata)
);
// 输出数据选择
assign rdata = addr[5] ? sram1_rdata : sram0_rdata;
endmodule
// 深度32的SRAM模型
module sram_32xN #(
parameter DATA_WIDTH = 8
)(
input wire clk,
input wire cen, // 片选(低有效)
input wire wen, // 写使能(低有效)
input wire [4:0] addr, // 5位地址
input wire [DATA_WIDTH-1:0] wdata,
output reg [DATA_WIDTH-1:0] rdata
);
// 32xN存储器阵列
reg [DATA_WIDTH-1:0] mem [0:31];
// 写操作
always @(posedge clk) begin
if (!cen && !wen) begin
mem[addr] <= wdata;
end
end
// 读操作
always @(posedge clk) begin
if (!cen && wen) begin
rdata <= mem[addr];
end else begin
rdata <= {DATA_WIDTH{1'bz}}; // 高阻态当未选中时
end
end
endmodule
三面主管面 30min
都做过什么项目
比赛经历
比赛或项目中的合作
比赛或项目中较大的挫折或困难
如何看待华为的奋斗者文化
Tips:如果有笔试题,还需要把所有笔试题看一遍,技术面过程可能抽题问。