【verilog】如何一小时成为verilog高手(并非

xjtuse版面向bzhang的verilog学习


感谢来自同学推荐的一个 verilog oj .

(真是一款非常好玩的oj,使我枯燥的verilog半日速通学习变得有趣了起来。欢迎大家来玩!!)

(md没有verilog高亮......typst都有,不亏是typst,库太强大了

assign

assign 赋值目标 = 表达式

赋值目标必须是wire型。

连续赋值语句 assign 描述的是事物之间的关联,而不是将值从一个事物复制到另一个事物的操作。因此当代码中存在多个 assign 时,它们出现的顺序无关紧要。

复制代码
module top_module( output one );
    assign one = 1;
endmodule

不赋值默认为0.

复制代码
module top_module(
    output zero
);
endmodule

运算

c 复制代码
+ - * /
**   // 幂 (同python
&& || !   // 与 或 非 (同c
& | ~   // 按位与 按位或 按位非 (同c
^ ~^   // 异或 同或
<< <<< >> >>>    // 左移 算术左移 右移 算术右移
== !=    // 等于 不等于
=== !==   // 恒等于 恒不等于

缩减运算符 & | ^ 的使用:

实现四位输入的与 或 异或门

复制代码
module top_module( 
    input [3:0] in,
    output out_and,
    output out_or,
    output out_xor
);

    // &in 等价于 in[3] & in[2] & in[1] & in[0]
    assign out_and = &in;
    
    // |in 等价于 in[3] | in[2] | in[1] | in[0]
    assign out_or  = |in;
    
    // ^in 等价于 in[3] ^ in[2] ^ in[1] ^ in[0]
    assign out_xor = ^in;

endmodule

实用的连接运算符 {}

复制代码
{3'b111, 3'b000} => 6'b111000
{1'b1, 1'b0, 3'b101} => 5'b10101
{4'ha, 4'd10} => 8'b10101010 // 4'ha 和 4'd10 的二进制表示均为 4'b1010

{5{1'b1}} // 5'b11111(或 5'd31 或 5'h1f)
{2{a,b,c}} // 等同于 {a,b,c,a,b,c}
{3'd5, {2{3'd6}}} // 9'b101_110_110。它是 101 与 的连接。
                    // 第二个向量,即 3'b110 的两个副本。

assign {out[7:0], out[15:8]} = in; // 交换两个字节。左右两边都是 16 位向量。
assign out[15:0] = {in[7:0], in[15:8]}; // 这是同一件事。
assign out = {in[7:0], in[15:8]}; // 这有所不同。右侧的 16 位向量被扩展为
                                        // 与左侧的 24 位向量匹配,因此 out[23:16] 为零。
                                        // 在前两个示例中,out[23:16] 没有被赋值。

一些写法

Verilog 支持的 4 种进制简写

完整的格式是:<位宽>'<进制><数值>

简写 英文全称 中文含义 允许的字符 示例
'b'B Binary 2 进制 0, 1, x, z 4'b1010
'h'H Hexadecimal 16 进制 0-9, a-f, x, z 4'ha (等同于 4'b1010)
'd'D Decimal 10 进制 0-9 4'd10 (等同于 4'b1010)
'o'O Octal 8 进制 0-7, x, z 4'o12 (等同于 4'b1010)
  1. 如果不写进制,默认是 10 进制
    如果你写 assign a = 10;,编译器会把它当作 32 位的十进制数 10 处理(32'd10)。
  2. 下划线 _ 增强可读性
    可以随意在数字中间加下划线,编译器会忽略它。
    • 16'b1010_1010_1111_000016'b1010101011110000 容易看多了。
    • 32'hdead_beef 也是合法的。
  3. 特殊值 x 和 z
    • z:高阻态(悬空,不连线)。
    • x:未知状态(可能是0也可能是1)。
    • 比如:4'b10xz12'h3x0 都是合法的写法。

逻辑值

  • 1:逻辑1
  • 0:逻辑0
  • x:不确定
  • z:高阻态

wire&reg

不声明默认为wire类型,reg需显式标出。

创建一个具有 3 个输入和 4 个输出的模块,使其行为类似于导线,并建立以下连接:

复制代码
a -> w 
b -> x 
b -> y 
c -> z

module top_module( 
    input a,b,c,
    output w,x,y,z );
    assign {w,x,y,z} = {a,b,b,c};
endmodule

可以通过 wire 声明一个中间变量。实现以下示例:

复制代码
`default_nettype none
module top_module(
    input a,
    input b,
    input c,
    input d,
    output out,
    output out_n   ); 
    
    wire N1, N2, N3;
    assign {N1, N2} = {a & b, c & d};
    assign N3 = N1 | N2;
    assign {out ,out_n} = {N3, !N3};

endmodule

`default_nettype none (禁止创建隐式网络)的核心作用是:强迫必须先定义每一个信号,才能使用它。(一般情况下,如果在代码里突然写了一个从来没定义过的名字,编译器默认会把它当作一个 1-bit 的 wire 自动创建出来。)

复制代码
module top_module ( 
    input p1a, p1b, p1c, p1d, p1e, p1f,
    output p1y,
    input p2a, p2b, p2c, p2d,
    output p2y );

	wire n1, n2, n3, n4;
    assign {n1, n2, n3, n4} = {p1a&p1c&p1b, p2a&p2b, p1d&p1e&p1f, p2c&p2d};
    assign {p1y, p2y} = {n1|n3, n2|n4};
endmodule

向量

向量用于将相关的信号分组,并使用同一个名称,以便于操作。例如,wire [7:0] w;声明了一个名为w的 8 位向量,其功能等同于 8 条独立的 wire 线。

向量的声明时将维度放在向量名之前,调用的时候放在向量名之后。可以通过下标连续调用一段。

复制代码
wire [99:0] my_vector;    //Declare a 100-element vector
assign out = my_vector[10];  // Part-select one bit out of the vector
assign out_10 = my_vector[9:0];

eg1.

复制代码
module top_module ( 
    input wire [2:0] vec,
    output wire [2:0] outv,
    output wire o2,
    output wire o1,
    output wire o0  ); 
    assign outv[2:0] = vec[2:0];
    assign {o2, o1, o0} = {vec[2], vec[1], vec[0]};
endmodule

assign outv[2:0] = vec[2:0]; 可以直接写成 assign outv = vec;

assign {o2, o1, o0} = {vec[2], vec[1], vec[0]}; 可以直接写成 assign {o2, o1, o0} = vec;

eg2. Build a combinational circuit that splits an input half-word (16 bits, [15:0] ) into lower [7:0] and upper [15:8] bytes.

复制代码
module top_module( 
    input wire [15:0] in,
    output wire [7:0] out_hi,
    output wire [7:0] out_lo );
    assign {out_hi, out_lo} = {in[15:8], in[7:0]};
endmodule

Module

简单的端口连接

将已有模块a 实例化,并连接端口到顶层模块

复制代码
module mod_a ( input in1, input in2, output out );
    // Module body
endmodule

写法一:按名称连接(推荐)

复制代码
module top_module ( input a, input b, output out );

    // 语法:模块名 实例名 ( .端口名(信号名), ... );
    mod_a inst1 ( 
        .in1(a),   // 将外部信号 a 接到子模块端口 in1
        .in2(b),   // 将外部信号 b 接到子模块端口 in2
        .out(out)  // 将外部信号 out 接到子模块端口 out
    );

endmodule

写法二:按位置连接(By Position)

这种写法类似 C 语言函数调用,必须严格按照 mod_a 定义时的端口顺序来写。

复制代码
module top_module ( input a, input b, output out );

    // mod_a 的定义顺序是: in1, in2, out
    // 所以这里的括号里必须依次填入: a, b, out
    mod_a inst1 ( a, b, out );

endmodule

多个模块的端口连接

在 Verilog 的可综合设计中,模块之间的连接必须通过显示定义的信号(wire/reg)来完成。不能像在 C++ 或 Java 类的成员访问那样,直接在一个模块的实例化中去"读取"另一个实例内部的端口信号。

复制代码
module top_module ( input clk, input d, output q );
    wire q1, q2;
    my_dff ins1 (.clk(clk), .d(d), .q(q1));
    my_dff ins2 (.clk(clk), .d(q1), .q(q2));
    my_dff ins3 (.clk(clk), .d(q2), .q(q));
endmodule

always

复制代码
always @(敏感条件信号表)
	各类顺序语句

always中赋值目标必须为reg型

例如

复制代码
always @(posedge CLK)
	Q=D;

当CLK的上升沿来临的时候,将D的值赋给Q。@代表等待。

posedge 代表上升沿,negedge代表下降沿。如果没写则默认为电平敏感。

case

always 内部可以使用case语句

case类似于c里面的switch

复制代码
case (表达式)
    取值1: 语句1;
    取值2: 语句2;
    取值3: 语句3;
    ...
    ...
    default: 默认语句;
endcase

不要忘记写endcase!!!default可以不写,不过一般建议写。

复制代码
module top_module ( 
   input clk, 
   input [7:0] d, 
   input [1:0] sel, 
   output reg [7:0] q 
);

   wire [7:0] q1,q2,q3;
   my_dff8 ins1 (.clk(clk), .d(d), .q(q1));
   my_dff8 ins2 (.clk(clk), .d(q1), .q(q2));
   my_dff8 ins3 (.clk(clk), .d(q2), .q(q3));
   
   always @(*)
       case(sel)
           2'b00: q=d;
           2'b01: q=q1;
           2'b10: q=q2;
           2'b11: q=q3;
       endcase
endmodule

当sel的值分别为0,1,2,3的时候,q取对应的值。注意case后面没有冒号。

begin-end

当always中有多条赋值语句的时候,要用begin-end包裹起来,作用相当于c里的大括号

阻塞赋值与非阻塞赋值

组合电路常用阻塞赋值,时序电路常用非阻塞赋值,但不是绝对的。不可以在一个always块中同时使用阻塞赋值与非阻塞赋值。

阻塞赋值

复制代码
always @ (A,B)
begin
    M1=A;
    M2=B&M1;
    Q=M1|M2;
end

激活前 :M1=0,M2=0,Q=0
激活后

先计算A=1,马上赋值给M1

再计算B&M1=1,马上赋值给M2

再计算M1|M2=1,马上赋值给Q

非阻塞赋值

复制代码
always @ (A,B)
begin
    M1<=A;
    M2<=B&M1;
    Q<=M1|M2;
end

激活后执行过程

先计算A=1,(等待,不赋值)

再计算B&M1=0,(等待,不赋值)

再计算M1|M2=0,(等待,不赋值)

过程结束

先赋值给M1=1

再赋值给M2=0

再赋值给Q=0


一些例子

Dff D触发器

涉及到时序电路用非阻塞取值

复制代码
module top_module (
    input clk,
    input d,
    output reg q );

    always @(posedge clk)
        q<=d;
endmodule

带有同步复位的D触发器

复制代码
module top_module (
    input clk,
    input reset,            // Synchronous reset
    input [7:0] d,
    output [7:0] q
);
    always @(posedge clk) begin
        if (reset) q<=8'b0;        // 当复位信号为1时 q复位取0 注意位宽8
        else q<=d;
    end

endmodule

带有异步复位的D触发器

(XJTUSE超纲了 不学异步 但是bzhang的皮皮踢上出现了)

同步复位:复位信号像是一个排队的人,必须等到时钟上升沿(posedge clk)到来时,才会被处理。

异步复位:复位信号像是一个特权插队者,只要它变为高电平(areset = 1),电路会立即把输出 q 清零,完全不管时钟在哪。

复制代码
module top_module (
    input clk,
    input areset,   // 高电平有效的异步复位
    input [7:0] d,
    output reg [7:0] q
);

    // 关键点:敏感列表中包含了 clk 的上升沿 OR areset 的上升沿
    always @(posedge clk or posedge areset) begin
        if (areset) begin
            // 只要 areset 变为 1,立即执行这里,不看 clk
            q <= 8'b0;
        end
        else begin
            // 只有当 clk 上升沿到达,且 areset 为 0 时,才执行这里
            q <= d;
        end
    end

endmodule

计数器

Build a 4-bit binary counter that counts from 0 through 15, inclusive, with a period of 16. The reset input is synchronous, and should reset the counter to 0.

复制代码
module top_module (
    input clk,
    input reset,      // Synchronous active-high reset
    output [3:0] q);
    always @(posedge clk) begin
        if (reset) q <= 4'b0;
        else q <= q + 1'b1;   // 加到16溢出了会自动复位 所以不用写额外逻辑
    end
endmodule

用16位全加器实现32位全加器

add16按照下图所示连接各个模块。提供的模块add16具有以下声明:

module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );

在每个模块内部add16,会实例化 16 个全加器(模块add1未提供)来实际执行加法运算。您必须编写包含以下声明的全加器模块:

module add1 ( input a, input b, input cin, output sum, output cout );

注意wire的拆分与连接

复制代码
module top_module (
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire [15:0] s1, s2;
    wire c;
    add16 add16_1 (.a(a[15:0]), .b(b[15:0]), .sum(s1), .cout(c));
    add16 add16_2 (.a(a[31:16]), .b(b[31:16]), .cin(c), .sum(s2));
    assign sum =  {s2,s1};
endmodule

module add1 ( input a, input b, input cin,   output sum, output cout );

	assign sum = a^b^cin;
	assign cout = (a&b) | (a&cin) | (b&cin);
	// 呃其实完全没必要这么写 直接 assign {cout, sum} = {a+b+cin}; 就好了
endmodule

以下例子为真题或ppt出现过的

实现一个四位两输入的加法器(前年真题)

这题verilog太容易了 正文一行解决

复制代码
module top_module (
    input [3:0] a,      // 第一个 4 位输入
    input [3:0] b,      // 第二个 4 位输入
    output [3:0] sum,   // 4 位和输出
    output cout         // 进位输出
);

    // 使用拼接运算符 {cout, sum} 来接收 5 位的加法结果
    // 第 4 位(最高位)赋值给 cout,低 4 位赋值给 sum
    assign {cout, sum} = a + b;

endmodule

用一些2-4译码器实现一个4-16译码器(前年真题)

感觉这题还是电路图画比较好

复制代码
// 2-4 译码器子模块
module dec2_4 (
    input [1:0] in,
    input enable,
    output reg [3:0] out
);
    always @(*) begin
        if (enable) begin
            case (in)
                2'b00: out = 4'b0001;
                2'b01: out = 4'b0010;
                2'b10: out = 4'b0100;
                2'b11: out = 4'b1000;
                default: out = 4'b0000;
            endcase
        end else begin
            out = 4'b0000; // 不使能时,输出全 0
        end
    end
endmodule

// 顶层模块 4-16译码器
module dec4_16 (
    input [3:0] in,
    input enable,       // 整个 4-16 译码器的总使能
    output [15:0] out
);
    wire [3:0] select; // 用于连接第一级和第二级的使能信号

    // 第一级:控制层(处理高两位 in[3:2])
    // 根据高两位决定哪一个第二级译码器被激活
    dec2_4 master_dec (
        .in(in[3:2]),
        .enable(enable),
        .out(select)
    );

    // 第二级:输出层(处理低两位 in[1:0])
    // 译码输出 0-3
    dec2_4 slave_dec0 (
        .in(in[1:0]),
        .enable(select[0]),
        .out(out[3:0])
    );

    // 译码输出 4-7
    dec2_4 slave_dec1 (
        .in(in[1:0]),
        .enable(select[1]),
        .out(out[7:4])
    );

    // 译码输出 8-11
    dec2_4 slave_dec2 (
        .in(in[1:0]),
        .enable(select[2]),
        .out(out[11:8])
    );

    // 译码输出 12-15
    dec2_4 slave_dec3 (
        .in(in[1:0]),
        .enable(select[3]),
        .out(out[15:12])
    );

endmodule

4位优先编码器

四个优先级:r[3]、r[2]、r[1]和r[0]作为一组4位输入信号,输出是最高优先级的二进制代码

复制代码
module prio_encoder_if(
    input [3:0] r,
    output reg [2:0] y
);
    always @*
        if (r[3]==1'b1)  // 可以写成(r[3])
            y = 3'b100;
        else if (r[2]==1'b1)  // 可以写成(r[2])
            y = 3'b011;
        else if (r[1]==1'b1)  // 可以写成(r[1])
            y = 3'b010;
        else if (r[0]==1'b1)  // 可以写成(r[0])
            y = 3'b001;
        else
            y = 3'b000;
endmodule

2-4译码器

复制代码
module decoder_2_4_if(
    input [1:0] a,
    input en,
    output reg [3:0] y
);
    always @*
        if (en == 1'b0)
            y = 4'b0000;
        else if (a == 2'b00)
            y = 4'b0001;
        else if (a == 2'b01)
            y = 4'b0010;
        else if (a == 2'b10)
            y = 4'b0100;
        else
            y = 4'b1000;
endmodule

2个8位二进制数相乘

核心原理类似于列竖式乘法。

复制代码
module mult_for (
    input [8:1] op0,
    input [8:1] op1,
    output reg [16:1] result
);
    integer i;
    always @*
    begin
        result = 0;
        for(i=1; i<=8; i=i+1)
            if(op1[i])
                result = result + (op0 << (i-1));
    end
endmodule

4选1多路选择器

多路选择器其实就是进阶版的译码器。多一步将译码对应位的值传递输出而已。

复制代码
module mux41_case
(
    input in0, in1, in2, in3,
    input s0, s1,
    output reg out  // out声明为reg类型
);
    always @*
    begin
        case ({s1, s0})
            2'b00: out = in0;
            2'b01: out = in1;
            2'b10: out = in2;
            default: out = in0;
        endcase
    end
endmodule

1位二进制比较器

真值表

in0 in1 gt(in0>in1) eq(in0=in1) lt(in0<in1)
0 0 0 1 0
0 1 0 0 1
1 0 1 0 0
1 1 0 1 0
复制代码
module comp_1
(
input in0,in1,
output reg gt,eq,lt
);
always @*
    begin
        gt = 0;
        eq = 0;
        lt = 0;
        if(in0>in1)
            gt = 1;
        if(in0==in1)
            eq = 1;
        if(in0<in1)
            lt = 1;
    end
endmodule

always块内if语句之前,对gt,eq和lt都初始化赋值为0

这样做的重要性是保证每个输出都被分配一个值。如果没有这样做,Verilog会认为你不想让它们的值改变,系统将会自动生成一个锁存器,那么得到的电路就不再是一个组合电路了。

8-3 优先编码器

复制代码
module prio_encode_8_3
(
    input [7:0] in,
    output reg [2:0] encode_out
);
    always @*
    begin
        casez (in)
            8'b1???????: encode_out = 3'b000;
            8'b01??????: encode_out = 3'b001;
            8'b001?????: encode_out = 3'b010;
            8'b0001????: encode_out = 3'b011;
            8'b00001???: encode_out = 3'b100;
            8'b000001??: encode_out = 3'b101;
            8'b0000001?: encode_out = 3'b110;
            8'b00000001: encode_out = 3'b111;
        endcase
    end
endmodule

注意这里用的是casez。? 可以表示无关状态,可以用 z` 表示。

串并转换 8bit -> 32bit (前年真题)

原题:实现一个将串行数据(8bit宽)转换为并行数据(32bit 宽)的电路,功能是将有效输入(en=1)的 8bit 数据合并成 32bit 宽数据后输出,同时输出有效信号1,该电路输入输出信号包括:clk(时钟),rst(复位),en(输入有效),datain(输入数据),dout_en(输出有效),dataout(输出数据)。

涉及移位寄存器。其实就是将输入保存在一个中间值(寄存器),存够32bit就输出(dout_en=1).

复制代码
module s8_to_p32 (
    input wire clk,             // 时钟信号
    input wire rst,             // 复位信号 (高电平有效)
    input wire en,              // 输入有效信号
    input wire [7:0] datain,    // 输入数据 (8bit)
    
    output reg dout_en,         // 输出有效信号
    output reg [31:0] dataout   // 输出数据 (32bit)
);

    // 内部寄存器
    // 用于缓存前3次输入的8bit数据,共24bit。
    // 当然也可以定义为32bit,但逻辑上只需保存前24bit等待最后一次拼接。
    reg [23:0] data_buffer;     
    
    // 计数器,范围 0~3,需要2bit宽
    reg [1:0] cnt;              

    always @(posedge clk or posedge rst) begin
        if (rst) begin
            // 复位状态
            cnt         <= 2'd0;
            data_buffer <= 24'd0;
            dout_en     <= 1'b0;
            dataout     <= 32'd0;
        end 
        else begin
            // 默认拉低输出有效信号 (脉冲)
            dout_en <= 1'b0;

            if (en) begin
                if (cnt == 2'd3) begin
                    // ---- 第4个字节到达 ----
                    // 此时 data_buffer 中已经存了前3个字节
                    // 现在的 datain 是第4个字节
                    
                    dout_en <= 1'b1; // 输出有效
                    
                    // 拼接输出:{第1字节, 第2字节, 第3字节, 当前第4字节}
                    dataout <= {data_buffer, datain};
                    
                    // 计数器归零,准备下一轮
                    cnt <= 2'd0;
                    
                    // data_buffer 在此时其实不需要更新,或者清零均可,
                    // 因为下一轮的第1个字节会覆盖写入最低8位,随后移位。
                    // 为了逻辑统一,这里可以不做操作,或者复位 buffer
                    data_buffer <= 24'd0; 
                end 
                else begin
                    // ---- 第1, 2, 3个字节到达 ----
                    // 计数器累加
                    cnt <= cnt + 1'b1;
                    
                    // 移位逻辑:原有的数据左移8位,新数据补入低8位
                    // data_buffer[23:0] << 8 | datain
                    // 实际上只需保留 buffer 的低16位左移,并拼上新数据
                    data_buffer <= {data_buffer[15:0], datain};
                end
            end
        end
    end
endmodule

在oj上实现仿真

实现一个D触发器。呃写top_module有点麻烦,随便看看得了。

复制代码
module top_module ();
    //=========================================================
    // 1. [修改] 信号定义
    //    规则:输入给子模块的信号定义为 reg,从子模块输出的信号定义为 wire
    //=========================================================
    reg clk = 0;
    reg rst_n = 0; // 复位信号 (举例)
    reg data_in = 0; // 自定义输入 (举例)
    
    wire data_out; // 自定义输出 (举例)

    //=========================================================
    // 2. 时钟生成与波形启动 (通常不需要改)
    //=========================================================
    initial `probe_start;   // 启动波形工具
    always #5 clk = ~clk;   // 产生时钟 (周期=10个单位)
    
    //=========================================================
    // 3. [修改] 实例化你的模块 (DUT - Device Under Test)
    //    把下面的 my_custom_module 换成你写的模块名字
    //    把 .端口(信号) 对应连好
    //=========================================================
    my_custom_module u_dut (
        .clk(clk),
        .rst(rst_n),
        .in(data_in),
        .out(data_out)
    );

    //=========================================================
    // 4. [修改] 添加探针 (Probes)
    //    你想在波形图上看到哪个信号,就在这里加一行
    //=========================================================
    `probe(clk);
    `probe(rst_n);
    `probe(data_in);
    `probe(data_out);

    //=========================================================
    // 5. [修改] 测试流程 (Stimulus)
    //    在这里控制信号的变化,制造测试场景
    //=========================================================
    initial begin
        // --- 初始状态 ---
        rst_n = 0; 
        data_in = 0;
        
        // --- 开始测试 ---
        #10 rst_n = 1;      // 10单位时间后,复位拉高
        
        #10 data_in = 1;    // 又过10单位,输入变1
        #20 data_in = 0;    // 又过20单位,输入变0
        
        $display ("Current time: %0d ps", $time); // 打印时间看看
        
        #50 $finish;        // 结束仿真
    end

endmodule

//---------------------------------------------------------
// 下面这里放你自己的模块代码
//---------------------------------------------------------
module my_custom_module(
    input clk, rst, d,
    output reg q
);
    // 这里写你的逻辑
    always @(posedge clk or negedge rst) begin
        if(!rst) q <= 0;
        else     q <= d;
    end
endmodule
相关推荐
从此不归路16 小时前
FPGA 结构与 CAD 设计(第3章)上
ide·fpga开发
Aaron158818 小时前
基于VU13P在人工智能高速接口传输上的应用浅析
人工智能·算法·fpga开发·硬件架构·信息与通信·信号处理·基带工程
碎碎思19 小时前
在 FPGA 上实现并行脉冲神经网络(Spiking Neural Net)
人工智能·深度学习·神经网络·机器学习·fpga开发
集芯微电科技有限公司21 小时前
替代HT6310/KP3310离线式AC-DC无感线性稳压器
数据结构·人工智能·单片机·嵌入式硬件·fpga开发
minglie121 小时前
Zynq上UART/IIC/SPI的24个实验-第0课:目录
fpga开发
FPGA小c鸡1 天前
FPGA摄像头到屏幕完整链路:从OV5640采集到HDMI实时显示(附完整工程代码)
fpga开发
dai8910111 天前
使用紫光同创FPGA实现HSSTLP IP支持的线速率
fpga开发
s09071361 天前
XIlinx FPGA使用LVDS的电源与电平关键指南
fpga开发·xilinx·lvds
Joshua-a2 天前
FPGA基于计数器的分频器时序违例的解决方法
嵌入式硬件·fpga开发·fpga