AI编程:Codex在有无知识库前提下生成verilog/SV代码对比测试

AI编程:Codex在有无知识库前提下生成verilog/SV代码对比测试
测试用例用verilog写一个兼容128, 256, 512, 1024点的FFT电路输入是1个时钟周期2个采样点采样点是顺序输入采样位宽10bit要求性能最优流水设计目标器件Xilinx K7系列FPGA。测试环境Codex with GPT-5.5 - HighgenRTL知识库(https://genrtl.com/knowledge)在没有知识库的情况下Codex的思考过程如下生成的代码片段如下integer init_i; initial begin state ST_IDLE; out_valid 1b0; out_last 1b0; out0_re {DATA_W{1b0}}; out0_im {DATA_W{1b0}}; out1_re {DATA_W{1b0}}; out1_im {DATA_W{1b0}}; frame_error 1b0; sample_cnt {MAX_LOG_N1{1b0}}; out_cnt {MAX_LOG_N1{1b0}}; logn_r 4d10; npoints_r 11d1024; stage 4d0; group_base {MAX_LOG_N1{1b0}}; j_idx {MAX_LOG_N1{1b0}}; for (init_i 0; init_i MAX_N; init_i init_i 1) begin mem_re[init_i] {DATA_W{1b0}}; mem_im[init_i] {DATA_W{1b0}}; end end最关键的是我要求的是1个时钟2个采样点输入意味着FFT的处理性能要支持2 sample/cycle但是在没有知识库的情况下Codex输出的代码是分时复用的FFT架构并不是流水设计always (posedge clk_sys or negedge rst_n) begin if (rst_n 1b0) begin state_q ST_IDLE; log2_q 4d6; len_m1_q 9d63; load_cnt_q 9d0; out_cnt_q 9d0; stage_q 4d1; group_base_q 9d0; bfly_j_q 9d0; end else begin case (state_q) ST_IDLE: begin load_cnt_q 9d0; out_cnt_q 9d0; stage_q 4d1; group_base_q 9d0; bfly_j_q 9d0; if ((cfg_start_i 1b1) (in_vld_i 1b1)) begin log2_q cfg_log2_i; len_m1_q cfg_len_m1; if ((in_last_i 1b1) || (cfg_len_m1 9d0)) begin state_q ST_COMP_READ; end else begin state_q ST_LOAD; load_cnt_q 9d1; end end end ST_LOAD: begin if (in_fire 1b1) begin if ((in_last_i 1b1) || (load_cnt_q len_m1_q)) begin state_q ST_COMP_READ; stage_q 4d1; group_base_q 9d0; bfly_j_q 9d0; end else begin load_cnt_q load_cnt_q 9d1; end end end ST_COMP_READ: begin state_q ST_COMP_WRITE; end ST_COMP_WRITE: begin if (last_bfly_in_stage 1b1) begin bfly_j_q 9d0; if (last_group_in_stage 1b1) begin group_base_q 9d0; if (last_stage 1b1) begin state_q ST_OUT_READ; out_cnt_q 9d0; end else begin stage_q stage_q 4d1; state_q ST_COMP_READ; end end else begin group_base_q group_base_q stage_size; state_q ST_COMP_READ; end end else begin bfly_j_q bfly_j_q 9d1; state_q ST_COMP_READ; end end ST_OUT_READ: begin state_q ST_OUT_SEND; end ST_OUT_SEND: begin if (out_fire 1b1) begin if (out_cnt_q len_m1_q) begin state_q ST_IDLE; out_cnt_q 9d0; end else begin out_cnt_q out_cnt_q 9d1; state_q ST_OUT_READ; end end end default: begin state_q ST_IDLE; end endcase end end总结一下在无知识库加持下Codex生成的代码问题1. 代码风格没有文件头代码风格随LLM在不同时间点漂移2. 功能缺陷复杂问题生成的代码甚至都不仅仅是功能缺陷的问题了架构上完全与要求的不一样3. 不可综合或综合成本高C语言风格实现memory用数组实现有些直接for语句循环代码里面有initiate等在有genRTL知识库加持下Codex的思考过程:首先Codex会根据Skill掌握genRTL有哪些知识库工具可以调用这个Skill不仅是MCP工具学习更进一步的这是一个资深专业的工程师面对一个FPGA/ASIC开发任务时所必须思考的流程然后Codex根据提示词分析要调用哪些MCP工具。例如上面的提示词Codex根据Skill就知道这个Spec在知识库中有没有参考方案甚至有没有现成的模块可以调用CBB库。例如这个案例中Codex调用了Spec2Plan和Spec2RTLSpec2Plan就命中了一项知识卡2并行MDC型FFT这样就保证了Codex不会根据自己已掌握的模糊的知识乱来。GPT在训练时能参考的RTL数据集非常有限并由于硬件属性通用的LLM在面对这种场景不如高阶语言和通用语言那么胜任同时在写代码之前已经加载了编码规范Coding style 通过调用genrtl_coding_style_search实现生成的顶层模块如下// //------------------------------------------------------------------------------ // Copyright (c) 2026. // // File Name : fft_2p_k7.v // Module Name : FFT_2P_K7 // Author : Codex // Created Date : 2026-06-28 // Version : v2.0 // // Description : // 2-parallel streaming fixed-point FFT datapath for Xilinx K7 FPGA. // The core accepts two adjacent real samples per clock in natural order and // implements a feed-forward MDC-style pipeline with one butterfly pair per // active stage. Runtime modes select 128/256/512/1024 points by bypassing the // unused leading stages. // // fft_len_sel_i encoding: // 2b00: 128 points, active stages 3..9 // 2b01: 256 points, active stages 2..9 // 2b10: 512 points, active stages 1..9 // 2b11: 1024 points, active stages 0..9 // // Interface assumptions: // - A frame is supplied as N/2 consecutive valid cycles. // - For maximum throughput, frames may be supplied back-to-back. // - out_rdy_i is a global pipeline clock enable. Deasserting it stalls the // full pipeline and deasserts in_rdy_o. // - Output order is the native MDC/DIF order, not natural-order reordered. // // Fixed-point notes: // - Input is unsigned pixel data by default. Set INPUT_SIGNED1 for signed // samples. // - Twiddles are Q1.15 constants. // - Each active butterfly scales by 1/2, so the total scale is 1/N. // // Modification History: // Date Version Author Description // ---------- ------- ------------ -------------------------------------- // 2026-06-22 v1.0 Codex Initial frame-iterative version. // 2026-06-22 v2.0 Codex Rewritten as 2P MDC streaming pipeline. //------------------------------------------------------------------------------ default_nettype none module FFT_2P_K7 #( parameter INPUT_W 10, parameter DATA_W 26, parameter TW_W 16, parameter TW_FRAC_W 15, parameter ADDR_W 10, parameter INPUT_SIGNED 0 ) ( input wire clk_sys, input wire rst_n, input wire [1:0] fft_len_sel_i, input wire in_vld_i, output wire in_rdy_o, input wire [INPUT_W-1:0] in0_data_i, input wire [INPUT_W-1:0] in1_data_i, output wire out_vld_o, input wire out_rdy_i, output wire out_last_o, output wire [ADDR_W-1:0] out_index0_o, output wire [ADDR_W-1:0] out_index1_o, output wire signed [DATA_W-1:0] out0_re_o, output wire signed [DATA_W-1:0] out0_im_o, output wire signed [DATA_W-1:0] out1_re_o, output wire signed [DATA_W-1:0] out1_im_o, output wire busy_o, output wire frame_done_o ); localparam STAGE_NUM 10; wire pipe_ce_w; wire [3:0] start_stage_w; wire [ADDR_W-1:0] half_points_w; reg [1:0] mode_q; reg [ADDR_W-1:0] pipe_pair_cnt_q; reg [ADDR_W-1:0] out_pair_cnt_q; reg frame_seen_q; reg frame_done_q; reg in_vld_q; wire signed [DATA_W-1:0] in0_re_w; wire signed [DATA_W-1:0] in1_re_w; wire signed [DATA_W-1:0] stage0_re_w [0:STAGE_NUM]; wire signed [DATA_W-1:0] stage0_im_w [0:STAGE_NUM]; wire signed [DATA_W-1:0] stage1_re_w [0:STAGE_NUM]; wire signed [DATA_W-1:0] stage1_im_w [0:STAGE_NUM]; wire stage_vld_w [0:STAGE_NUM]; wire [ADDR_W-1:0] stage_pos_w [0:STAGE_NUM]; genvar stage_idx; assign in_rdy_o out_rdy_i; assign pipe_ce_w out_rdy_i; assign start_stage_w start_stage_from_sel(mode_q); assign half_points_w half_points_from_sel(mode_q); assign busy_o frame_seen_q; assign frame_done_o frame_done_q; assign in0_re_w extend_input(in0_data_i); assign in1_re_w extend_input(in1_data_i); assign stage0_re_w[0] in0_re_w; assign stage0_im_w[0] {DATA_W{1b0}}; assign stage1_re_w[0] in1_re_w; assign stage1_im_w[0] {DATA_W{1b0}}; assign stage_vld_w[0] in_vld_i | frame_seen_q; assign stage_pos_w[0] pipe_pair_cnt_q; generate for (stage_idx 0; stage_idx 9; stage_idx stage_idx 1) begin : gen_mdc_stage FFT_2P_K7_MDC_STAGE #( .STAGE_ID (stage_idx), .DATA_W (DATA_W), .TW_W (TW_W), .TW_FRAC_W (TW_FRAC_W), .ADDR_W (ADDR_W) ) u_mdc_stage ( .clk_sys (clk_sys), .rst_n (rst_n), .ce_i (pipe_ce_w), .active_i (stage_idx[3:0] start_stage_w), .in_vld_i (stage_vld_w[stage_idx]), .in_pos_i (stage_pos_w[stage_idx]), .in0_re_i (stage0_re_w[stage_idx]), .in0_im_i (stage0_im_w[stage_idx]), .in1_re_i (stage1_re_w[stage_idx]), .in1_im_i (stage1_im_w[stage_idx]), .out_vld_o (stage_vld_w[stage_idx 1]), .out_pos_o (stage_pos_w[stage_idx 1]), .out0_re_o (stage0_re_w[stage_idx 1]), .out0_im_o (stage0_im_w[stage_idx 1]), .out1_re_o (stage1_re_w[stage_idx 1]), .out1_im_o (stage1_im_w[stage_idx 1]) ); end endgenerate FFT_2P_K7_LAST_STAGE #( .DATA_W (DATA_W), .ADDR_W (ADDR_W) ) u_last_stage ( .clk_sys (clk_sys), .rst_n (rst_n), .ce_i (pipe_ce_w), .active_i (4d9 start_stage_w), .in_vld_i (stage_vld_w[9]), .in_pos_i (stage_pos_w[9]), .in0_re_i (stage0_re_w[9]), .in0_im_i (stage0_im_w[9]), .in1_re_i (stage1_re_w[9]), .in1_im_i (stage1_im_w[9]), .out_vld_o (stage_vld_w[10]), .out_pos_o (stage_pos_w[10]), .out0_re_o (stage0_re_w[10]), .out0_im_o (stage0_im_w[10]), .out1_re_o (stage1_re_w[10]), .out1_im_o (stage1_im_w[10]) ); assign out_vld_o stage_vld_w[10]; assign out0_re_o stage0_re_w[10]; assign out0_im_o stage0_im_w[10]; assign out1_re_o stage1_re_w[10]; assign out1_im_o stage1_im_w[10]; assign out_index0_o {out_pair_cnt_q[ADDR_W-2:0], 1b0}; assign out_index1_o {out_pair_cnt_q[ADDR_W-2:0], 1b1}; assign out_last_o (out_vld_o 1b1) (out_pair_cnt_q (half_points_w - {{(ADDR_W-1){1b0}}, 1b1})) ? 1b1 : 1b0; always (posedge clk_sys or negedge rst_n) begin if (rst_n 1b0) begin mode_q 2b00; pipe_pair_cnt_q {ADDR_W{1b0}}; out_pair_cnt_q {ADDR_W{1b0}}; frame_seen_q 1b0; frame_done_q 1b0; in_vld_q 1b0; end else if (pipe_ce_w 1b1) begin frame_done_q 1b0; in_vld_q in_vld_i; if ((frame_seen_q 1b0) (in_vld_i 1b1)) begin mode_q fft_len_sel_i; frame_seen_q 1b1; end if (frame_seen_q 1b1) begin if (pipe_pair_cnt_q (half_points_w - {{(ADDR_W-1){1b0}}, 1b1})) begin pipe_pair_cnt_q {ADDR_W{1b0}}; if (in_vld_i 1b1) begin mode_q fft_len_sel_i; end end else begin pipe_pair_cnt_q pipe_pair_cnt_q {{(ADDR_W-1){1b0}}, 1b1}; end end if ((out_vld_o 1b1) (((in_vld_i 1b1) (in_vld_q 1b0)) 1b0)) begin if (out_last_o 1b1) begin out_pair_cnt_q {ADDR_W{1b0}}; frame_done_q 1b1; if (in_vld_i 1b0) begin frame_seen_q 1b0; pipe_pair_cnt_q {ADDR_W{1b0}}; end end else begin out_pair_cnt_q out_pair_cnt_q {{(ADDR_W-1){1b0}}, 1b1}; end end end end function signed [DATA_W-1:0] extend_input; input [INPUT_W-1:0] din; begin if (INPUT_SIGNED 1) begin extend_input {{(DATA_W-INPUT_W){din[INPUT_W-1]}}, din}; end else begin extend_input {{(DATA_W-INPUT_W){1b0}}, din}; end end endfunction function [3:0] start_stage_from_sel; input [1:0] sel; begin case (sel) 2b00: start_stage_from_sel 4d3; 2b01: start_stage_from_sel 4d2; 2b10: start_stage_from_sel 4d1; 2b11: start_stage_from_sel 4d0; default: start_stage_from_sel 4d3; endcase end endfunction function [ADDR_W-1:0] half_points_from_sel; input [1:0] sel; begin case (sel) 2b00: half_points_from_sel 10d64; 2b01: half_points_from_sel 10d128; 2b10: half_points_from_sel 10d256; 2b11: half_points_from_sel 10d512; default: half_points_from_sel 10d64; endcase end endfunction endmodule default_nettype wire是不是看着比前面没有知识库加持生成的代码看着正式多了并解决了上面几个问题1. 代码风格稳定受Coding style的约束生成的代码适配业界大厂专业的风格至少代码风格离可以commit很近了2. 功能正确参考2-P MDC FFT知识库Codex被限制在严格按知识库的参考方案设计减少了架构的反复和Codex的幻想当然Codex有时还是会幻觉这点Codex不如Claude稳定。3. 可综合在知识库的加持下生成的代码至少可综合没有上述哪些问题写完代码Codex还会在前面的Skill的作用下自动加载Lint规则完成语法Lint/CDC扫描由于本地没有装VCS/NC等仿真EDA以及Vivado没有对代码进行编译综合因此还有几项知识库待测Compiledebugverification等三类。总结一下面对复杂任务没有知识库的加持Codex在生成verilog代码时容易偏离方向几乎不可用有了知识库的加持Codex至少可以稳定的输出可用的代码当然这也取决于知识库的准确和专业程度经过多轮测试描述粗糙的知识项即使命中了Codex也会幻觉。另外还有三项知识库待测敬请关注本公众号ASIC FPGA的下次测试报告。另外genRTL正开放知识库免费公测可以登录后在个人中心的API Keys里面点击申请参加公测。