请逐句解释以上的每一句代码的含义:
时间: 2024-11-15 11:26:52 浏览: 41
以下是《故障逻辑完整版.doc》中Verilog代码的逐句解释:
### 文件头和模块声明
```verilog
`timescale 1ns / 100ps
```
- 设置仿真时间单位为1纳秒(ns),精度为100皮秒(ps)。
```verilog
module soc_malfunction #(
parameter clk_freq = 24'd100_000 //kHz
)(
input clk,
input rstn,
input [1:0] ovcp, // -> 指向 psv [0]voltage over; [1] current over.
input WDT_Wout, // -> 指向 wdv pulse 1 -> reset system
input [31:0] CPUREG, // -> 指向 [31]cpuv, [30]cfl_fr, [29]SW_DPV_TX, [28]SW_DPV_TY, [23:0]PR_time.
output [31:0] FRAM_ID, // out to CPU
input [1:0] DPV_F, // -> 指向 DPV_FX, FY
output [3:0] CHV_T, // [0] 对应 CHV_T_MIO-A, [1] 对应 CHV_T_MIO-B, [2] 对应 CHV_TX, [3] 对应 CHV_TY
output [1:0] DPV_T, // [0] 对应 DPVV_TX, [1] 对应 DPVV_TY
output FRAM_CS, // Flash片选信号 Pin
output FRAM_CLK, // Flash时钟信号 Pin
output FRAM_MOSI, // Flash数据输出 Pin
input FRAM_MISO // Flash数据输入 Pin
);
```
- 定义一个名为`soc_malfunction`的模块,并设置参数`clk_freq`为100 kHz。
- 输入端口包括时钟信号`clk`、复位信号`rstn`、过压/过流检测信号`ovcp`、看门狗超时信号`WDT_Wout`、CPU寄存器值`CPUREG`以及DPV故障信号`DPV_F`。
- 输出端口包括闪存标识符`FRAM_ID`、充电电压状态`CHV_T`、DPV状态`DPV_T`以及闪存控制信号`FRAM_CS`、`FRAM_CLK`、`FRAM_MOSI`。
- 输入端口还包括闪存数据输入信号`FRAM_MISO`。
### 生成毫秒脉冲
```verilog
reg [23:0] MS_cnt;
always @(posedge clk, negedge rstn) begin
if (!rstn)
MS_cnt <= 24'd0;
else if (MS_cnt < clk_freq)
MS_cnt <= MS_cnt + 24'd1;
else
MS_cnt <= 24'd1;
end
wire pluse_ms = (MS_cnt == clk_freq) ? 1'b1 : 1'b0;
```
- 声明一个24位的计数器`MS_cnt`用于生成毫秒脉冲。
- 在每个时钟上升沿或复位下降沿,如果复位信号有效,则将计数器清零;否则,如果计数器小于`clk_freq`,则递增计数器;否则,将计数器重置为1。
- `pluse_ms`信号在计数器达到`clk_freq`时产生一个高电平脉冲。
### 保护时间计数
```verilog
reg [15:0] PR_time; // from FRAM 500~xxxx mS
reg [15:0] PR_num;
always @(posedge clk, negedge rstn) begin
if (!rstn)
PR_num <= 16'd0;
else if (PR_num < PR_time)
PR_num <= PR_num + 16'd1;
else
PR_num <= PR_time;
end
wire PORP = (PR_num >= PR_time) ? 1'b0 : 1'b1; // power on or system reset.
```
- 声明一个16位的寄存器`PR_time`用于存储从闪存读取的保护时间(默认500毫秒)。
- 声明一个16位的计数器`PR_num`用于计数保护时间。
- 在每个时钟上升沿或复位下降沿,如果复位信号有效,则将计数器清零;否则,如果计数器小于`PR_time`,则递增计数器;否则,将计数器重置为`PR_time`。
- `PORP`信号在计数器达到`PR_time`时变为低电平,表示系统已经完成上电或复位。
### 过压/过流检测和看门狗超时
```verilog
wire PSV = ovcp > 2'b00; // 1 power failed
reg WDV; // 1 watchdog time out.
always @(posedge clk, negedge rstn) begin
if (!rstn)
WDV <= 1'b0;
else if (PORP)
WDV <= 1'b0;
else
WDV <= WDT_Wout ? 1'b1 : 1'b0;
end
```
- `PSV`信号在`ovcp`大于00时变为高电平,表示电源故障。
- 声明一个寄存器`WDV`用于记录看门狗是否超时。
- 在每个时钟上升沿或复位下降沿,如果复位信号有效,则将`WDV`清零;否则,如果`PORP`信号为高电平,则将`WDV`清零;否则,如果`WDT_Wout`信号为高电平,则将`WDV`置为高电平,表示看门狗超时。
### 故障检测
```verilog
wire LCV = CPUREG[31] || PSV || WDV; // 1 fault.
wire DPV_Fxy = DPV_F > 2'b00; // 1 SOC x/y think fault.
wire PD_CHV = LCV && ((!PORP) || DPV_Fxy); // now assertion CHV.
```
- `LCV`信号在`CPUREG[31]`、`PSV`或`WDV`任一为高电平时变为高电平,表示系统故障。
- `DPV_Fxy`信号在`DPV_F`大于00时变为高电平,表示SOC检测到故障。
- `PD_CHV`信号在`LCV`为高电平且`PORP`为低电平或`DPV_Fxy`为高电平时变为高电平,表示当前断言充电电压。
### 闪存操作
```verilog
wire [127:0] FRAM_rdat;
reg [127:0] FRAM_wdat;
reg [23:0] FRAM_addr; // user 0.
reg [1:0] FRAM_OPEN;
wire FRAM_OPED;
FM25V_OPA #(.clk_freq(clk_freq)) uFRAM (
.clk(clk),
.rest_n(rstn),
.ID_num(FRAM_ID),
.W_data(FRAM_wdat),
.R_data(FRAM_rdat),
.FM_adr(24'd0),
.OPAlen(4'd15),
.OPA_EN(FRAM_OPEN),
.OPA_ED(FRAM_OPED),
.FRAM_CS(FRAM_CS),
.FRAM_CLK(FRAM_CLK),
.FRAM_MOSI(FRAM_MOSI),
.FRAM_MISO(FRAM_MISO)
);
```
- 声明闪存读数据寄存器`FRAM_rdat`、写数据寄存器`FRAM_wdat`、地址寄存器`FRAM_addr`和操作使能寄存器`FRAM_OPEN`。
- 实例化一个名为`uFRAM`的闪存模块`FM25V_OPA`,并连接其各个端口。
### CPU状态和故障处理
```verilog
reg rCPU_up, CPU_upFram, CPU_upAck;
always @(posedge clk, negedge rstn) begin
if (!rstn)
rCPU_up <= 1'b0;
else
rCPU_up <= CPUREG[30];
end
always @(posedge clk, negedge rstn) begin
if (!rstn)
CPU_upFram <= 1'b0;
else if (CPU_upAck)
CPU_upFram <= 1'b0;
else if ({rCPU_up, CPUREG[30]} == 2'b01)
CPU_upFram <= 1'b1;
else
CPU_upFram <= CPU_upFram;
end
reg [3:0] Fstu;
always @(posedge clk, negedge rstn) begin
if (!rstn) begin
FRAM_wdat <= 128'd0;
FRAM_OPEN <= 2'b00;
CPU_upAck <= 1'b0;
Fstu <= 4'd0;
end else begin
case (Fstu)
4'd0: begin // read FRAM
FRAM_wdat <= 128'd0;
FRAM_OPEN <= 2'b10;
CPU_upAck <= 1'b0;
Fstu <= FRAM_OPED ? 4'd1 : 4'd0;
end
4'd1: begin // check FRAM flag
FRAM_wdat <= 128'd0;
FRAM_OPEN <= 2'b00;
CPU_upAck <= 1'b0;
if (FRAM_rdat[31:0] == 32'h24485A58)
Fstu <= 4'd8;
else
Fstu <= 4'd2; // new or fault FRAM.
end
4'd2: begin // initialize FRAM
FRAM_wdat <= 128'h00000000_00000000_00007530_24485A58;
FRAM_OPEN <= 2'b01;
CPU_upAck <= 1'b0;
Fstu <= FRAM_OPED ? 4'd3 : 4'd2;
end
4'd3: begin // confirm initialization
FRAM_wdat <= 128'd0;
FRAM_OPEN <= 2'b10;
CPU_upAck <= 1'b0;
Fstu <= FRAM_OPED ? 4'd4 : 4'd3;
end
4'd4: begin // verify initialization
FRAM_wdat <= 128'd0;
FRAM_OPEN <= 2'b00;
CPU_upAck <= 1'b0;
if (FRAM_rdat[31:0] == 32'h24485A58)
Fstu <= 4'd8;
else
Fstu <= 4'd5; // fault FRAM.
end
4'd5: begin // handle fault
FRAM_wdat <= 128'd0;
FRAM_OPEN <= 2'b00;
CPU_upAck <= 1'b1;
Fstu <= 4'd5;
end
4'd8: begin // run idle
FRAM_wdat <= {71'd0, PD_CHV, CPUREG[23:0], 32'h24485A58};
FRAM_OPEN <= 2'b00;
CPU_upAck <= 1'b0;
Fstu <= CPU_upFram ? 4'd9 : 4'd8;
end
4'd9: begin // update PR_time
if (FRAM_wdat[55:32] < 24'd500)
FRAM_wdat <= {FRAM_wdat[127:56], 24'd500, 32'h24485A58};
else
FRAM_wdat <= FRAM_wdat;
FRAM_OPEN <= 2'b00;
CPU_upAck <= 1'b0;
Fstu <= 4'd10;
end
4'd10: begin // write new data to FRAM
FRAM_wdat <= FRAM_wdat;
FRAM_OPEN <= 2'b01;
CPU_upAck <= 1'b0;
Fstu <= FRAM_OPED ? 4'd11 : 4'd10;
end
4'd11: begin // complete write
FRAM_wdat <= FRAM_wdat;
FRAM_OPEN <= 2'b00;
CPU_upAck <= 1'b1;
Fstu <= 4'd8;
end
default: begin
FRAM_wdat <= 128'd0;
FRAM_OPEN <= 2'b00;
CPU_upAck <= 1'b0;
Fstu <= 4'd0;
end
endcase
end
end
wire FRAM_err = (Fstu == 4'd4) ? 1'b1 : 1'b0;
```
- 声明寄存器`rCPU_up`、`CPU_upFram`和`CPU_upAck`用于跟踪CPU状态。
- 使用两个`always`块分别更新`rCPU_up`和`CPU_upFram`。
- 声明一个4位的状态机寄存器`Fstu`用于管理闪存操作流程。
- 使用一个大的`always`块实现状态机,根据不同状态执行不同的闪存操作,如读取、初始化、验证等。
- `FRAM_err`信号在状态机处于4'd4时变为高电平,表示闪存错误。
### 充电电压输出
```verilog
reg CHVout;
always @(posedge clk, negedge rstn) begin
if (!rstn)
CHVout <= 1'b0; // fault
else if (PORP)
CHVout <= (Fstu >= 4'd8) ? FRAM_rdat[56] : 1'b0;
else if (CPU_upFram)
CHVout <= PD_CHV;
else
CHVout <= CHVout;
end
assign CHV_T = {!CHVout, !CHVout, !CHVout, !CHVout};
assign DPV_T = ~( {CHVout, CHVout} & CPUREG[29:28] );
```
- 声明一个寄存器`CHVout`用于控制充电电压输出。
- 使用一个`always`块更新`CHVout`,根据不同的条件设置其值。
- 将`CHVout`分配给`CHV_T`,所有四个输出均为`!CHVout`。
- 计算`DPV_T`,其值为`{CHVout, CHVout}`与`CPUREG[29:28]`按位与后的反码。
### ILA调试接口
```verilog
ILA ila_Fault (
.clk(clk), // input wire clk
.probe0(CPUREG), // input wire [31:0] probe0
.probe1(FRAM_ID), // input wire [31:0] probe1
.probe2(FRAM_rdat), // input wire [127:0] probe2
.probe3(FRAM_wdat), // input wire [127:0] probe3
.probe4({PORP, WDT_Wout, ovcp, DPV_F}), // input wire [5:0] probe4
.probe5({FRAM_OPEN, FRAM_OPED, Fstu}) // input wire [6:0] probe5
);
```
- 实例化一个名为`ila_Fault`的ILA调试接口模块,并连接其各个探针。
### 结束模块
```verilog
endmodule
```
- 结束模块定义。
阅读全文