You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tang Nano 9K UART代码综合Slice资源超限问题求助

问题

基于Tang Nano 9K仓库的UART示例修改代码,实现接收5个字符后回发给主机的功能,使用256字节的memory存储数据。但代码无法综合,提示Slice资源占用超过100%;若注释tx_cnt <= tx_cnt + 8'd1;这一行,代码可正常编译。请问问题出在哪里?

代码如下:

module uart_test(
    input                        clk,
    input                        rst_n,
    input                        uart_rx,
    output                       uart_tx,
    output reg [5:0]             led
);

parameter                        CLK_FRE  = 27;         //MHz
parameter                        UART_FRE = 115200;     //bps
localparam                       IDLE =  0;
localparam                       SEND =  1;   
localparam                       WAIT =  2;   
localparam                       PROCESS_RX =  3;


parameter                        MSG_SIZE = 256;    

reg[7:0]                         tx_data;
reg[7:0]                         tx_str;
reg                              tx_data_valid;
wire                             tx_data_ready;
reg[7:0]                         tx_cnt;
wire[7:0]                        rx_data;
wire                             rx_data_valid;
wire                             rx_data_ready;
reg[31:0]                        wait_cnt;
reg[3:0]                         state;

reg [7:0]                        message [MSG_SIZE - 1:0];
reg [7:0]                        rx_index;   
integer                          i;        
localparam                      DATA_NUM2   = 3;    // just for testing

assign rx_data_ready = 1'b1;//always can receive data,

always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        led <= ~6'b100000;
        wait_cnt <= 32'd0;
        tx_data <= 8'd0;
        state <= IDLE;
        tx_cnt <= 8'd0;
        tx_data_valid <= 1'b0;
        rx_index <= 8'd0;
        for (i = 0; i < 256; i = i+1) begin
            message[i] <= 0;
        end
    end
    else
    case(state)
        IDLE:
        begin
            if(rx_data_valid == 1'b1)
            begin
                message[rx_index] <= rx_data;   // send uart received data
                if(rx_index >= 8'd4)
                begin
                    rx_index <= 8'd0;
                    tx_cnt <= 8'd0;
                    state <= PROCESS_RX;
                end
                else begin
                    led <= ~rx_data[5:0];
                    rx_index <= rx_index + 8'd1;
                end
            end
        end
        PROCESS_RX:
        begin
            tx_data <= tx_str;
            tx_data_valid <= 1'b1;
            state <= WAIT;
        end
        WAIT:
        begin
            if(tx_data_valid == 1'b1 && tx_data_ready == 1'b1) begin
                tx_data_valid <= 1'b0;
                tx_cnt <= tx_cnt + 8'd1; //Send data counter
                if(tx_cnt <= (DATA_NUM2 - 1)) begin
                    state <= PROCESS_RX;
                    led <= ~6'b000110;
                end
                else begin
                    led <= ~6'b000100;
                    state <= IDLE;
                end
            end
        end
        default:
            state <= IDLE;
    endcase
end


always@(tx_cnt)
    tx_str <= message[tx_cnt];

uart_rx#
(
    .CLK_FRE(CLK_FRE),
    .BAUD_RATE(UART_FRE)
) uart_rx_inst
(
    .clk                        (clk                      ),
    .rst_n                      (rst_n                    ),
    .rx_data                    (rx_data                  ),
    .rx_data_valid              (rx_data_valid            ),
    .rx_data_ready              (rx_data_ready            ),
    .rx_pin                     (uart_rx                  )
);

uart_tx#
(
    .CLK_FRE(CLK_FRE),
    .BAUD_RATE(UART_FRE)
) uart_tx_inst
(
    .clk                        (clk                      ),
    .rst_n                      (rst_n                    ),
    .tx_data                    (tx_data                  ),
    .tx_data_valid              (tx_data_valid            ),
    .tx_data_ready              (tx_data_ready            ),
    .tx_pin                     (uart_tx                  )
);
endmodule
原因分析

问题根源是组合逻辑环路+全译码资源浪费:

  1. 你用了组合逻辑块always@(tx_cnt)直接将message[tx_cnt]赋值给tx_str,而tx_cnt会被时序逻辑里的tx_cnt <= tx_cnt + 8'd1;动态修改,形成了隐藏的组合逻辑环路:tx_cnt变化→tx_str变化→tx_data在PROCESS_RX状态被赋值→后续逻辑连锁反应,综合器会生成大量冗余组合逻辑来处理即时反馈,直接导致Slice资源超标。
  2. 256字节的message寄存器数组,用组合逻辑直接索引时,综合器会生成全译码多路选择器,这本身就会占用大量Slice资源;加上组合逻辑环路的存在,资源消耗进一步放大。

注释掉tx_cnt <= tx_cnt + 8'd1;后,tx_cnt变为固定值,组合逻辑块没有动态输入,综合器会优化掉多余的译码逻辑,资源占用自然恢复正常。

解决方案

把组合逻辑改为时序逻辑,消除环路并优化资源使用:

  1. 移除单独的tx_str组合逻辑块,直接在时序逻辑中读取message数组;
  2. 若需要中间变量,将tx_str的赋值改为时钟沿触发的时序逻辑。

修改后的核心代码示例:

// 移除原来的always@(tx_cnt)组合逻辑块,直接读取message数组赋值给tx_data
PROCESS_RX:
begin
    tx_data <= message[tx_cnt]; // 直接读取,无需中间变量tx_str
    tx_data_valid <= 1'b1;
    state <= WAIT;
end

若保留中间变量,可改成时序逻辑:

// 将组合逻辑改为时钟沿触发的时序逻辑
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        tx_str <= 8'd0;
    else
        tx_str <= message[tx_cnt];
end

修改后,综合器会将message数组映射到FPGA的块RAM(BRAM)资源,而非用Slice搭建全译码多路选择器,同时消除了组合逻辑环路,资源占用会大幅降低,可顺利通过综合。

内容的提问来源于stack exchange,提问作者mhanuel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 19:33:09