这次,我们说明的是,assign
语句实现的数据流建模,包含的是两个层面
- 建立联系
- 传输方向
assign A = B
的本质含义是
- A与B建立关联
- B的值传给A
这个传输方向至关重要,实际情况是什么,就必须按照顺序进行,不是单纯地连线,本质是数据的传输,是有方向的。
看看下面的CPU的例子,注意注释中的【关注点】
// reg_files_1 Inputs
wire [31:0] ALUresult; // 【关注点1】wire [4:0] rA = instruction[25:21];
wire [4:0] rB = instruction[20:16];
wire [4:0] rW = instruction[15:11];
wire [31:0] writeData = ALUresult; // 【关注点2】
wire RegWrite;// reg_files_1 Outputs
wire [31:0] A;
wire [31:0] B;reg_files_1 u_reg_files_1 (.clk ( clk ),.rst_n ( rst_n ),.rA ( rA ),.rB ( rB ),.rW ( rW ),.writeData ( writeData ),.RegWrite ( RegWrite ),.A ( A ),.B ( B ));/******** ALU ********/// ALU_1 Inputs
wire [3:0] ALUop;// ALU_1 Outputs
// wire [31:0] ALUresult = writeData; // 【关注点3】ALU_1 u_ALU_1 (.A ( A ),.B ( B ),.ALUop ( ALUop ),.ALUresult ( ALUresult ));
上面的例子是正确的,RTL优化的结果是
我们看看错误的示例
// reg_files_1 Inputs
// wire [31:0] ALUresult; // 【关注点1】wire [4:0] rA = instruction[25:21];
wire [4:0] rB = instruction[20:16];
wire [4:0] rW = instruction[15:11];
wire [31:0] writeData; // = ALUresult; // 【关注点2】
wire RegWrite;// reg_files_1 Outputs
wire [31:0] A;
wire [31:0] B;reg_files_1 u_reg_files_1 (.clk ( clk ),.rst_n ( rst_n ),.rA ( rA ),.rB ( rB ),.rW ( rW ),.writeData ( writeData ),.RegWrite ( RegWrite ),.A ( A ),.B ( B ));/******** ALU ********/// ALU_1 Inputs
wire [3:0] ALUop;// ALU_1 Outputs
wire [31:0] ALUresult = writeData; // 【关注点3】ALU_1 u_ALU_1 (.A ( A ),.B ( B ),.ALUop ( ALUop ),.ALUresult ( ALUresult ));
只是修改了关注点的部分,然而是错误的,但是,RTL优化结果看起来一样,行为仿真的时候writeData
确实Z 高阻抗
状态。
高阻抗是为什么?
通常就是不同的信号撞一起了。
对于同一个线路,同时输入0
和1
就产生了高阻抗。
我们看看之前的示例是为什么。
我们关注下面的部分
在正确的示例中,使用的是
wire [31:0] ALUresult;
wire [31:0] writeData = ALUresult;
也就是这样的,这是符合CPU的运算逻辑的,将ALU结果输出到寄存器写入。
错误的示例是
wire [31:0] writeData;
wire [31:0] ALUresult = writeData;
这个时候,我们设置的是红色箭头的方向,而实际上,CPU运算会输出橘色箭头的数据,两个不同的输出撞一起导致了Z
高阻抗状态!
小结
赋值语句是有方向的!代表了逻辑设计方向,代表了数据传输方向,不能错!
一般都是右值赋给左值,同时,说明了传输方向是B到A!
补充
如果两个信号的声明和赋值顺序是反着的,可以声明的时候不赋值,之后使用assign
语句就好了。
wire A;
wire B;
assign A = B;
等价于
wire B;
wire A = B;