伪随机序列发生器设计(HDL语言)

设计一个伪随机序列发生器,采用的生成多项式为1+x^3+X^7。要求: (1) 具有一个RESET端和两个控制端来调整寄存器初值(程序中设定好四种非零初值可选)。(2) 将生成的伪随机序列在数码管上显示。

基于Monster 组和GPT的调写:
以下是一个使用HDL语言设计的基本伪随机序列发生器,使用的生成多项式为 |+x~3+X^7。它包括一个RESET端和两个控制端,用于调整寄存器的初始值,并且可以将生成的伪随机序列显示在数码管上。

module pseudo_random_seq(
  input clk,
  input rst,
  input ctrl1,
  input ctrl2,
  output reg [7:0] display
);

reg [6:0] shift_reg;

always @(posedge clk or posedge rst) begin
  if (rst) begin
    shift_reg <= 7'b0000001;
  end else begin
    shift_reg <= {shift_reg[5:0], shift_reg[6]^shift_reg[3]};
    if (ctrl1) begin
      shift_reg <= 7'b0000011;
    end else if (ctrl2) begin
      shift_reg <= 7'b0000111;
    end
  end
end

assign display = shift_reg;

endmodule

这个模块具有一个时钟输入和一个重置输入,以及两个控制输入。使用时钟触发,模块会按照生成多项式进行伪随机序列的生成。在每个时钟上升沿的时候,序列会向左移动一位并且计算下一位的值。如果RESET为高电平,则寄存器被重置为初始值;如果ctrl1或ctrl2为高电平,则寄存器将被设置为四种预定义的非零初始值之一。

最后,将生成的伪随机序列输出到一个八位数码管上,以显示当前的序列值。在此示例中,使用display变量将移位寄存器中的当前值输出到数码管中。

参考GPT和自己的思路,下面是一个基于Verilog HDL语言实现的伪随机序列发生器,采用生成多项式1+x^3+x^7。该发生器具有RESET端和两个控制端,以设置寄存器的初始值,同时将生成的伪随机序列在数码管上显示。

module PRBS(
    input clk,         // 时钟信号
    input rst,         // 复位信号
    input ctrl1,       // 控制信号1
    input ctrl2,       // 控制信号2
    output reg [7:0] led // 数码管输出
);

reg [7:0] shift_reg;  // 移位寄存器
reg [2:0] control;    // 控制信号

always @(posedge clk, negedge rst) begin
    if(~rst) begin   // 复位信号
        shift_reg <= 8'h0;
        control <= 3'b0;
    end else begin
        if(ctrl1) begin    // 设置寄存器初值
            case(control)
                3'b000: shift_reg <= 8'h01;
                3'b001: shift_reg <= 8'h7E;
                3'b010: shift_reg <= 8'hAA;
                3'b011: shift_reg <= 8'h55;
                default: shift_reg <= 8'h0;
            endcase
            control <= control + 1;
        end else if(ctrl2) begin  // 反转寄存器初值
            shift_reg <= ~shift_reg;
        end else begin
            // 移位操作,生成伪随机序列
            shift_reg <= {shift_reg[6:0], shift_reg[7] ^ shift_reg[3] ^ shift_reg[0]};
        end
    end
end

// 数码管驱动模块,实现BCD码转换并在数码管上显示
display_7seg displayer(shift_reg, led);

endmodule

// 数码管驱动模块
module display_7seg(
    input [7:0] num,  // 要显示的数字
    output reg [7:0] seg   // 数码管输出
);

reg [3:0] bcd;    // BCD码

// BCD码转换
always @* begin
    case(num)
        8'h00: bcd = 4'b0000;
        8'h01: bcd = 4'b0001;
        8'h02: bcd = 4'b0010;
        8'h03: bcd = 4'b0011;
        8'h04: bcd = 4'b0100;
        8'h05: bcd = 4'b0101;
        8'h06: bcd = 4'b0110;
        8'h07: bcd = 4'b0111;
        8'h08: bcd = 4'b1000;
        8'h09: bcd = 4'b1001;
        8'h0A: bcd = 4'b1010;
        8'h0B: bcd = 4'b1011;
        8'h0C: bcd = 4'b1100;
        8'h0D: bcd = 4'b1101;
        8'h0E: bcd = 4'b1110;
        8'h0F: bcd = 4'b1111;
        default: bcd = 4'bXXXX; // 非法BCD码
        endcase
     end

// 显示BCD码
always @* begin
case(bcd)
4'b0000: display = 7'b1000000; // 显示0
4'b0001: display = 7'b1111001; // 显示1
4'b0010: display = 7'b0100100; // 显示2
4'b0011: display = 7'b0110000; // 显示3
4'b0100: display = 7'b0011001; // 显示4
4'b0101: display = 7'b0010010; // 显示5
4'b0110: display = 7'b0000010; // 显示6
4'b0111: display = 7'b1111000; // 显示7
4'b1000: display = 7'b0000000; // 显示8
4'b1001: display = 7'b0010000; // 显示9
4'b1010: display = 7'b0001000; // 显示A
4'b1011: display = 7'b0000011; // 显示B
4'b1100: display = 7'b1000110; // 显示C
4'b1101: display = 7'b0100001; // 显示D
4'b1110: display = 7'b0000110; // 显示E
4'b1111: display = 7'b0001110; // 显示F
default: display = 7'b1111111; // 不显示
endcase
end

// 伪随机序列发生器
reg [7:0] shift_reg = 8'h7F; // 初始值为7FH
always @(posedge clk or negedge reset) begin
if (!reset) begin
shift_reg <= 8'h7F;
end else begin
shift_reg <= {shift_reg[6]^shift_reg[0], shift_reg[7:1]};
end
end

// 选择控制信号
wire [1:0] ctrl = {sw[2], sw[1]};

// 设置初值
always @* begin
case(ctrl)
2'b00: shift_reg = 8'h7F; // 初始值为7FH
2'b01: shift_reg = 8'h3D; // 初始值为3DH
2'b10: shift_reg = 8'h5E; // 初始值为5EH
2'b11: shift_reg = 8'h6A; // 初始值为6AH
default: shift_reg = 8'h7F; // 默认初始值为7FH
endcase
end

// 数码管显示控制
reg [3:0] cnt = 4'b0000; // 显示计数器
reg [3:0] index = 4'b0000; // 数码管位选计数器
wire [6:0] segment = display; // 数码管段选信号
reg [3:0] buffer [0:3]; // 数码管缓存

// 数码管扫描
always @(posedge clk) begin
if (reset) begin // 复位
cnt <= 4'b0000;
index <= 4'b0000;
buffer <= 4'b0000;
end
else begin
cnt <= cnt + 1; // 显示计数器自增
if (cnt == 4'b1000) begin
cnt <= 4'b0000;
index <= index + 1; // 数码管位选计数器自增
if (index == 4'b0100) // 最后一位后回到第一位
index <= 4'b0000;
end
end
end

// 数码管数据缓存
always @(posedge clk) begin
if (reset) // 复位
buffer <= 4'b0000;
else begin
case (index) // 根据当前位选计数器的值更新相应的缓存值
4'b0000: buffer[0] <= num;
4'b0001: buffer[1] <= num;
4'b0010: buffer[2] <= num;
4'b0011: buffer[3] <= num;
endcase
end
end

// 数码管段选控制
assign display = segment[index] ? buffer[index] : 7'b111_1111; // 根据位选控制信号选择显示的数值或不显示

// 数码管共阴极控制
assign cathode = 4'b1110 - index; // 根据位选控制信号计算激活的共阴极,因为我们使用的是共阴极的数码管

always @(posedge clk) begin
if (rst) begin
cnt <= 4'b0000;
index <= 4'b0000;
buffer <= 4'b0000;
end
else begin
if (cnt == 4'b1000) begin // 8个时钟周期后更新显示
cnt <= 4'b0000;
index <= index + 1;
if (index == 4'b1000) // 四个数码管显示完毕后回到第一个
index <= 4'b0000;
end
else begin
cnt <= cnt + 1;
buffer[index] <= bcd_data;
end
end
end

assign display = { // 根据当前位选和缓存中的数据计算数码管段选信号
buffer[3][seg],
buffer[2][seg],
buffer[1][seg],
buffer[0][seg]
};

该回答引用ChatGPT
以下是完整的Verilog代码:


module prbs_generator (
    input wire clk,
    input wire reset,
    input wire [1:0] control,
    output reg [3:0] display
);

reg [7:0] state;

always @(posedge clk) begin
    if (reset) begin
        // 清零寄存器
        state <= 8'h00;
    end else begin
        // 选择初始值
        case (control)
            2'b00: state <= 8'h5F;
            2'b01: state <= 8'h3C;
            2'b10: state <= 8'h9A;
            2'b11: state <= 8'h1E;
        endcase

        // 生成新状态
        state <= {state[6]^state[3], state[7:1]};
    end
end

always @(*) begin
    case (state)
        8'h00: display = 4'b0111;
        8'h01: display = 4'b0001;
        8'h02: display = 4'b1011;
        8'h03: display = 4'b1000;
        8'h04: display = 4'b1100;
        8'h05: display = 4'b1001;
        8'h06: display = 4'b1111;
        8'h07: display = 4'b0000;
        8'h08: display = 4'b1110;
        8'h09: display = 4'b1001;
        8'h0A: display = 4'b1111;
        8'h0B: display = 4'b1101;
        8'h0C: display = 4'b0110;
        8'h0D: display = 4'b1111;
        8'h0E: display = 4'b1101;
        8'h0F: display = 4'b0111;
        default: display = 4'b1111;
    endcase
end

endmodule

在上面的代码中,我们首先定义了一个名为prbs_generator的模块,它有一个时钟端clk、一个清零端reset、两个控制端control和一个四位数码管输出display。接下来,我们定义了一个8位寄存器state,它用于保存当前的状态。在时钟上升沿时,如果reset为1,我们将寄存器清零。否则,我们根据control的值选择不同的初始值,并根据多项式1+x^3+x^7生成新的状态。最后,我们将状态映射到数码管上,然后将结果输出到display端口。

注意,我们在最后的always块中使用了@()来指示这是一个组合逻辑块。这意味着当state的值发生变化时,display的值将立即被更新。由于这个块没有时钟边沿触发,因此我们使用@()来防止产生无限循环的行为。


module PRNG(
    input clk,           // 时钟信号
    input reset,         // 复位信号
    input [1:0] ctrl,    // 控制信号,用于设置初始值
    output reg [7:0] out // 数码管输出信号
);

reg [7:0] reg;          // 寄存器
reg [7:0] poly = 8'b10000011;  // 生成多项式

always @(posedge clk or posedge reset) begin
    if (reset) begin   // 复位信号为1,将寄存器清零
        reg <= 0;
    end else begin
        case (ctrl)   // 根据控制信号设置寄存器的初始值
            2'b00: reg <= 8'h01;
            2'b01: reg <= 8'h07;
            2'b10: reg <= 8'h1F;
            2'b11: reg <= 8'h3F;
            default: reg <= 0;  // 默认值为0
        endcase

        for (int i = 0; i < 8; i++) begin
            reg <= {reg[6:0], reg[7]} ^ (reg & poly);
        end

        out <= reg;   // 将寄存器的值输出到数码管
    end
end

endmodule

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
设计思路:

  1. 定义生成多项式为1+x^3+x^7

  2. 采用7位寄存器来存储序列,即R7~R1

  3. 在每一个时钟上升沿,右移1位,并计算新的R1的值

  4. 计算R1的值:R1 = R7 xor R3 xor 1

  5. RESET置位时,将所有寄存器清零

  6. 启用控制端时,根据控制端的信号,选择四种非零的初值

  7. 将当前的R7数字通过数码管的方式进行显示

HDL代码如下:

module LFSR(
    input clk,
    input reset,
    input [1:0] control,
    output reg [6:0] out
    );

reg [6:0] register[0:7];
reg feedback;

always @ (posedge clk or posedge reset)
begin
    if (reset)
    begin
        for (int i = 0; i < 8; i = i+1)
            register[i] <= 0;
    end
    else
    begin
        feedback = register[7] ^ register[3] ^ 1;
        
        for (int i = 7; i > 0; i = i-1)
            register[i] <= register[i-1];
        
        register[0] <= feedback;  
    end
end

always @ (register[7])
begin
    case(register[7])
        2'b00: out <= 7'b0000011;  // 初始值为0
        2'b01: out <= 7'b0001100;  // 初始值为1
        2'b10: out <= 7'b0011000;  // 初始值为2
        2'b11: out <= 7'b0100100;  // 初始值为3
        default: out <= 7'b1111111; // 非法输入,将数码管全灭
    endcase
end

always @ (control)
begin
    case(control)
        2'b00: register <= 8'b00000001; // 初始值为1
        2'b01: register <= 8'b00000101; // 初始值为5
        2'b10: register <= 8'b00110011; // 初始值为51
        2'b11: register <= 8'b00000010; // 初始值为2
        default: register <= 8'b00000000; // 非法输入,所有寄存器清零
    endcase
end

endmodule

其中,out输出到数码管上,分别为abcdefg,按照顺序对应7到1位。 control[1:0]用于选择四种不同的初始值。 返回的序列是R7到R1。

需要注意的是,数码管的驱动程序应充分利用时序,以避免串行化延迟造成的错误。
如果我的回答解决了您的问题,请采纳!

本题需要设计一个基于LFSR的伪随机序列发生器。LFSR(线性反馈移位寄存器)是一个常用的伪随机序列发生器,它是由若干个寄存器以及一个带有反馈的多项式构成的。

根据题目要求,我们采用了一个三阶LFSR,生成多项式为/+x^3+X^7,即:

$r_n=r_{n-3}\oplus r_{n-7}$,其中$r_n$表示在时刻$n$时LFSR的寄存器状态。

下面是基于此多项式的设计思路:

  1. 确定LFSR的初始状态,即三个寄存器中存放的二进制数值。

考虑到题目要求有四种非零初值可选,我们可以将这四种初值分别存放在一个数组中,通过第一个控制端来选择其中一个。

  1. 根据多项式生成随机序列。

当一个时钟脉冲到来时,根据上述生成多项式,可知当前的$r_n$值为$r_{n-3}\oplus r_{n-7}$。因此,我们只需要将寄存器的值向左移动一位,然后在最低位进行异或操作即可得到新的寄存器状态。同时,将这个新状态输出至RBSBT端。

  1. 将随机序列转换为可显示的十进制数,并输出至数码管。

我们可以通过将十六进制数值转换成二进制,然后每四位转换成一个十进制数,得到一个长度为8的十进制数。将这个数输出至数码管即可。

下面是伪代码实现:

# 初始化
initial_state = [0b101, 0b110, 0b111]  # 四种非零初值可选
state = initial_state[0]   # 初始状态为第一个初值
clock_count = 0
display_count = 0
MAX_COUNT = 8   # 每8个时钟脉冲更新数码管一次
DISPLAY = [0, 0, 0, 0, 0, 0, 0, 0]
while True:
    # 根据多项式更新状态
    feedback = (state >> 4) ^ (state & 0b1)
    state = ((state << 1) & 0b111) | feedback
    
    # 将状态输出至RBSBT端
    RBSBT.write(state & 0b1)
    
    # 更新时钟脉冲计数器
    clock_count += 1
    
    # 根据计数器切换初始状态
    if control1.read() == 1:
        initial_index = (initial_index + 1) % 4
        state = initial_state[initial_index]
    
    # 根据计数器更新数码管显示
    if clock_count == MAX_COUNT:
        # 将状态转换成8位二进制数
        binary_state = bin(state)[2:].zfill(8)
        # 将二进制数每四位转换成一个十进制数
        for i in range(8):
            DISPLAY[i] = int(binary_state[4*i:4*(i+1)], 2)
        # 将更新后的数码管显示
        display.update(DISPLAY)
        
        # 更新计数器和状态
        clock_count = 0
        display_count += 1