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
原因分析
问题根源是组合逻辑环路+全译码资源浪费:
- 你用了组合逻辑块
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资源超标。 - 256字节的
message寄存器数组,用组合逻辑直接索引时,综合器会生成全译码多路选择器,这本身就会占用大量Slice资源;加上组合逻辑环路的存在,资源消耗进一步放大。
注释掉tx_cnt <= tx_cnt + 8'd1;后,tx_cnt变为固定值,组合逻辑块没有动态输入,综合器会优化掉多余的译码逻辑,资源占用自然恢复正常。
解决方案
把组合逻辑改为时序逻辑,消除环路并优化资源使用:
- 移除单独的
tx_str组合逻辑块,直接在时序逻辑中读取message数组; - 若需要中间变量,将
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
相关产品推荐
相关产品推荐

