首页 > 解决方案 > 如何为以后的串行传输编写字符串?

问题描述

我真的不知道如何很好地表达这个问题,这是我在stackoverflow上的第一篇文章,所以我提前道歉。

这一切都在 Cyclone IV FPGA 上。

首先,我有一个名为 UART 的模块连接到两个物理引脚,TX 和 RX。UART 运行良好,具有参数化的传输速率、停止位、奇偶校验等。

该 UART 模块周围是一个控制器模块,其中包括两个 FIFO,一个用于传出数据,一个用于传入数据。它被称为 UART_System 并包括用于发送和接收数据的辅助端口:

input clock,
input [7:0] tx_data,
input tx_req,
output tx_buffer_full,
output [7:0] rx_data,
input rx_req,
output rx_buffer_empty

当 rx_buffer_empty 为低电平时,您断言 rx_req 一个时钟,并从 rx_data 读取数据。类似的方法用于传输。这还没有通过线路发送数据,它只是与 FIFO 交互,UART 稍后会从中提取并以较慢的时钟进行传输。FIFO 是双时钟 Quartus IP。这一切都很好。

我仍然是 Verilog 的新手......那么我如何在一个时钟周期内对整条消息进行排队?显然,你不能,所以这就是我想出的。

首先,一些存储:

    byte response_message [0:127];
    reg [6:0] response_message_start;
    reg [6:0] response_message_end;

在复位时,response_message_start设置response_message_end为 0。在每个时钟周期,

always @(negedge clock) 
...
    // Check for outgoing data
    if(response_message_start != response_message_end) begin
        tx_req <= 'b1;
        tx_data <= response_message[response_message_start];
        response_message_start <= response_message_start + 1;
    end else begin
        tx_req <= 'b0;
        response_message_start <= 0;
        response_message_end <= 0;
    end
...
end

(忽略它现在不能优雅地处理 tx_buffer_full 的事实)。我相信上述方法效果很好。

这是我的问题。假设有一些用户事件我想发送一条消息,比如“Button1 was press!”,我有:

always (negedge clock) begin
...
    if(~button0) begin
        response_message[response_message_end+0] <= "B";
        response_message[response_message_end+1] <= "u";
        response_message[response_message_end+2] <= "t";
        response_message[response_message_end+3] <= "t";
        response_message[response_message_end+4] <= "o";
        response_message[response_message_end+5] <= "n";
        response_message[response_message_end+6] <= " ";
        response_message[response_message_end+7] <= "0";
        response_message[response_message_end+8] <= "!";
        response_message[response_message_end+9] <= "\n";
        response_message_end <= response_message_end + 10;
    end
    if(~button1) begin
        response_message[response_message_end+0] <= "B";
        response_message[response_message_end+1] <= "u";
        response_message[response_message_end+2] <= "t";
        response_message[response_message_end+3] <= "t";
        response_message[response_message_end+4] <= "o";
        response_message[response_message_end+5] <= "n";
        response_message[response_message_end+6] <= " ";
        response_message[response_message_end+7] <= "1";
        response_message[response_message_end+8] <= "!";
        response_message[response_message_end+9] <= "\n";
        response_message_end <= response_message_end + 10;
    end
...
end

但是上面使用了大量的逻辑元素!几乎 70% 的 LE(“LC 组合”)来自该模块。更不用说一次分配一个字符是一种可怕的编程风格......我在其他编程语言方面有很强的背景,但 Verilog 开始挑战我。

  1. 以后如何将准备好的“字符串”复制到缓冲区中以通过串行接口发送?
  2. 存储这些字符串的最佳方法是什么?内部块 ROM 并将其中的字节输出到缓冲区中?常量,局部参数?
  3. 很明显,如果 button0 和 button1 都被按下,结果将是不可预测的!这让我认为“<=”不是这种情况的正确分配。

请帮忙!!干杯

标签: verilogsystem-verilog

解决方案


正如@Light 所建议的那样,您可以使用长压缩字符串代替添加,并在整个字符串上使用移位运算符,如下所示。

    reg [8 * 128 - 1:0] response_message, tmp;
    ...
    always @(negedge clk) begin
        response_message <=  response_message | ("Button 0!\n" << (response_message_end * 8));
        ...

此外,请确保在单个始终块中分配“开始”/“结束”值以避免多个驱动程序。


推荐阅读