Compare commits

...

2 Commits

5 changed files with 281 additions and 116 deletions

View File

@ -25,7 +25,7 @@ module digital_thermometer(
wire wd_cnt_vld;
reg [23:0] gap_cnt; // 上报间隔计数器
wire [23:0] cur_freq_khz;
reg signed [31:0] temp_scaled;
reg signed [23:0] temp_scaled;
assign cur_freq_khz = (wd_cnt_out * 1000) / win_us;
//我们将温度结果放大100倍
@ -33,8 +33,14 @@ module digital_thermometer(
if (!rst_n) begin
temp_scaled <= 0;
end else if (wd_cnt_vld) begin
// 线性插值计算
temp_scaled <= ((cur_freq_khz - temp_neg_40_fre_k) * 12500) / (temp_85_fre_k - temp_neg_40_fre_k) - 4000;
// 如果当前频率低于或等于 -40度对应的标定频率直接输出 -4000
if (cur_freq_khz <= temp_neg_40_fre_k) begin
temp_scaled <= -32'sd4000;
end
else begin
// 只有在频率大于下限时才进行插值计算避免减法溢出
temp_scaled <= ((cur_freq_khz - temp_neg_40_fre_k) * 12500) / (temp_85_fre_k - temp_neg_40_fre_k) - 4000;
end
end
end
@ -61,10 +67,10 @@ module digital_thermometer(
// 模式切换输出
case (out_mode)
2'd0: therm_out <= temp_scaled[23:0]; // 输出放大100倍的温度
2'd0: therm_out <= temp_scaled; // 输出放大100倍的温度
2'd1: therm_out <= cur_freq_khz; // 输出频率(kHz)
2'd2: therm_out <= wd_cnt_out; // 输出原始脉冲计数值
default: therm_out <= temp_scaled[23:0];
default: therm_out <= temp_scaled;
endcase
end
else begin

View File

@ -24,7 +24,8 @@ module digital_top(
input clk,
input rst_n,
input uart_rx,
output uart_tx
output uart_tx,
input sig_in
);
wire [31:0] w_wrdata; // DUT -> SRAM 写数据
@ -33,31 +34,63 @@ wire w_wren; // 写使能
wire w_rden; // 读使能
wire [31:0] w_rddata; // SRAM -> DUT 读数据
wire [23:0] win_us;
wire [1:0] out_mode;
wire [15:0] temp_85_fre_k;
wire [15:0] temp_neg_40_fre_k;
wire report_en;
wire [23:0] rep_gap_us;
wire therm_vld;
wire [23:0] therm_out;
// 例化待测模块 (DUT)
uart_ctrl_sysreg #(
.BAUD (115200),
.CLOCK_FREQ (50_000_000)
) u_uart_ctrl (
.clk (clk),
.rst_n (rst_n),
.uart_rx (uart_rx),
.uart_tx (uart_tx),
.o_wrdata (w_wrdata),
.o_addr (w_addr),
.o_wren (w_wren),
.o_rden (w_rden),
.i_rddata (w_rddata)
);
uart_ctrl_sysreg #(
.BAUD (115200),
.CLOCK_FREQ (50_000_000)
) u_uart_ctrl (
.clk (clk),
.rst_n (rst_n),
.uart_rx (uart_rx),
.uart_tx (uart_tx),
.o_wrdata (w_wrdata),
.o_addr (w_addr),
.o_wren (w_wren),
.o_rden (w_rden),
.i_rddata (w_rddata),
.i_report_data (therm_out),
.i_report_vld (therm_vld)
);
system_regfile u_system_regfile (
.clk (clk),
.rst_n (rst_n),
.wrdata (w_wrdata),
.wren (w_wren),
.rwaddr (w_addr),
.rden (w_rden),
.rddata (w_rddata)
);
system_regfile u_system_regfile (
.clk (clk),
.rst_n (rst_n),
.wrdata (w_wrdata),
.wren (w_wren),
.rwaddr (w_addr),
.rden (w_rden),
.rddata (w_rddata),
// digital_thermometer
.win_us(win_us),
.out_mode(out_mode),
.temp_85_fre_k(temp_85_fre_k),
.temp_neg_40_fre_k(temp_neg_40_fre_k),
.report_en(report_en),
.rep_gap_us(rep_gap_us),
.therm_out(therm_out),
.therm_vld(therm_vld)
);
digital_thermometer u_digital_thermometer (
.clk (clk),
.rst_n (rst_n),
.sig_in (sig_in),
.win_us (win_us),
.out_mode (out_mode),
.temp_85_fre_k (temp_85_fre_k),
.temp_neg_40_fre_k (temp_neg_40_fre_k),
.report_en (report_en),
.rep_gap_us (rep_gap_us),
.therm_out (therm_out),
.therm_vld (therm_vld)
);
endmodule

View File

@ -14,18 +14,24 @@
// SECTION G: reg_new 映射给模块的输出端口
//-FHDR--------------------------------------------------------------------------------------------------------
module system_regfile # (
parameter CHIPCODE = 32'hDA400801,
parameter MFDATE = 32'h20260510
)(
module system_regfile (
// [BLOCK 0] 系统与总线接口
input clk, // 时钟
input rst_n, // 异步复位 (低有效)
input [31:0] wrdata, // 总线写数据
input wren, // 写使能
input [24:0] rwaddr, // 地址 (Byte Address)
input rden, // 读使能
output [31:0] rddata // 总线读数据
input clk,
input rst_n,
input [31:0] wrdata,
input wren,
input [24:0] rwaddr,
input rden,
output [31:0] rddata,
output [23:0]win_us,
output [1:0]out_mode, //0输出对应温度 1输出对应的频率2单位窗口输出脉冲的个数
output [15:0]temp_85_fre_k, //85°对应的频率,默认为600khz
output [15:0]temp_neg_40_fre_k , //-40对应的频率默认为160khz,单位khz
output report_en,
output [23:0]rep_gap_us, //最小位win_us 小于就不上报了
input [23:0]therm_out,
input therm_vld
);
@ -33,6 +39,11 @@ module system_regfile # (
// [SECTION A] 地址偏移定义 (Localparams)
// =============================================================================
localparam TESTR = 16'h00, DATER = 16'h04;
localparam WIN_MODE_R = 16'h08; // 配置窗口时间与输出模式
localparam CALIB_R = 16'h0C; // 标定参数寄存器
localparam REPORT_R = 16'h10; // 上报使能与间隔
localparam RESULT_R = 16'h14; // 状态与结果寄存器 (只读)
// =============================================================================
@ -41,24 +52,32 @@ module system_regfile # (
// 寄存器选择信号 (Enable Wires)
wire sel_testr, sel_dater;
wire sel_win_mode, sel_calib, sel_report, sel_result;
// 写使能信号 (Write Enable Wires)
wire we_testr, we_dater;
wire we_win_mode, we_calib, we_report;
// 寄存器存储连线 (Storage Wires)
wire [31:0] testr, dater;
wire [31:0] win_mode_r, calib_r, report_r, result_r;
// =============================================================================
// [SECTION C] 译码逻辑 (Decoding)
// =============================================================================
assign sel_testr = (rwaddr[15:0] == TESTR );
assign sel_dater = (rwaddr[15:0] == DATER );
assign sel_testr = (rwaddr[15:0] == TESTR );
assign sel_dater = (rwaddr[15:0] == DATER );
assign sel_win_mode = (rwaddr[15:0] == WIN_MODE_R );
assign sel_calib = (rwaddr[15:0] == CALIB_R );
assign sel_report = (rwaddr[15:0] == REPORT_R );
assign sel_result = (rwaddr[15:0] == RESULT_R );
// 写使能分配
assign we_testr = sel_testr & wren;
assign we_dater = sel_dater & wren;
assign we_win_mode = sel_win_mode & wren;
assign we_calib = sel_calib & wren;
assign we_report = sel_report & wren;
// =============================================================================
@ -67,9 +86,17 @@ assign we_dater = sel_dater & wren;
// --- 通用与测试寄存器 ---
sirv_gnrl_dfflrd #(32) testr_dff (32'h01234567, we_testr, wrdata[31:0], testr, clk, rst_n);
sirv_gnrl_dfflrd #(32) sfrtr_dff (32'd20270403, we_dater, wrdata[31:0], dater, clk, rst_n);
sirv_gnrl_dfflrd #(32) sfrtr_dff (32'h20260406, we_dater, wrdata[31:0], dater, clk, rst_n);
// --- 温度计业务寄存器 ---
// win_mode_r: [25:24] out_mode, [23:0] win_us (默认窗口 1000us)
sirv_gnrl_dfflrd #(32) win_mode_dff (32'h0000_03E8, we_win_mode, wrdata, win_mode_r, clk, rst_n);
// calib_r: [31:16] 85度频率(默认600k), [15:0] -40度频率(默认160k)
sirv_gnrl_dfflrd #(32) calib_dff (32'h0258_00A0, we_calib, wrdata, calib_r, clk, rst_n);
// report_r: [31] report_en, [23:0] rep_gap_us (默认间隔 50ms)
sirv_gnrl_dfflrd #(32) report_dff (32'h0000_C350, we_report, wrdata, report_r, clk, rst_n);
sirv_gnrl_dffr #(32) result_dff ({8'b0,therm_out},result_r, clk, rst_n);
// =============================================================================
// [SECTION E] 特殊业务逻辑 (Business Logic)
@ -84,8 +111,12 @@ sirv_gnrl_dfflrd #(32) sfrtr_dff (32'd20270403, we_dater, wrdata[31:0], dater, c
reg [31:0] rddata_reg;
always @(*) begin
rddata_reg = 32'b0;
if (sel_testr) rddata_reg = testr;
else if (sel_dater) rddata_reg = dater;
if (sel_testr) rddata_reg = testr;
else if (sel_dater) rddata_reg = dater;
else if (sel_win_mode) rddata_reg = win_mode_r;
else if (sel_calib) rddata_reg = calib_r;
else if (sel_report) rddata_reg = report_r;
else if (sel_result) rddata_reg = result_r;
end
sirv_gnrl_dfflr #(32) rddata_out_dff (rden, rddata_reg, rddata, clk, rst_n);
@ -93,10 +124,11 @@ end
// =============================================================================
// [SECTION G] 输出映射 (Output Assignments)
// =============================================================================
// assign sys_soft_rstn = sys_soft_rstn_r;
// assign sync_oen = syncr[18];
// assign nco_clr = ncoctrlr[2];
// assign nco_en = ncoctrlr[1] & doselr[2];
// assign p2a_en = ncoctrlr[0] & doselr[2];
assign win_us = win_mode_r[23:0];
assign out_mode = win_mode_r[25:24];
assign temp_85_fre_k = calib_r[31:16];
assign temp_neg_40_fre_k = calib_r[15:0];
assign report_en = report_r[31];
assign rep_gap_us = report_r[23:0];
endmodule

View File

@ -15,6 +15,9 @@ module uart_ctrl_sysreg #(
,output reg o_wren //write enable sram
,output reg o_rden //rden enable sram
,input [31:0] i_rddata //read data from sram
//主动上报机制
,input [23:0] i_report_data
,input i_report_vld
);
// --- uart_top ---
@ -38,7 +41,6 @@ module uart_ctrl_sysreg #(
reg [63:0] cmd_reg;
reg [31:0]wr_data_buff;
reg [19:0] data_bytes_len;
// 状态机定义
reg [2:0] state;
@ -47,9 +49,26 @@ module uart_ctrl_sysreg #(
S_PARSE = 3'd2,
S_WAIT_RD = 3'd3,
S_RD_DATA = 3'd4,
S_WR_DATA = 3'd5;
S_WR_DATA = 3'd5,
S_REPORT = 3'd6; //主动上报状态
// --- 主动上报数据先锁存着 ---
reg [23:0] report_data_latch;
reg report_pending;
// 捕捉上报脉冲如果当前忙先存起来
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
report_pending <= 1'b0;
report_data_latch <= 24'd0;
end else if(i_report_vld) begin
report_pending <= 1'b1;
report_data_latch <= i_report_data;
end else if(state == S_REPORT) begin
report_pending <= 1'b0; // 进入上报状态后清除标志
end
end
always @(posedge clk or negedge rst_n) begin
@ -70,6 +89,9 @@ module uart_ctrl_sysreg #(
cmd_reg[63:32] <= uart_rx_data;
state <= S_RX_CMD_L;
end
else if(report_pending) begin
state <= S_REPORT;
end
end
S_RX_CMD_L : begin //1
if(uart_rx_done)begin
@ -109,15 +131,21 @@ module uart_ctrl_sysreg #(
else begin
state <= S_IDLE;
end
end
S_REPORT : begin //6
// 构造上报数据包例如[8'hAA (帧头) + 24'bit温度数据]
uart_tx_data <= {8'hAA, report_data_latch};
uart_tx_go <= 1'b1;
state <= S_IDLE;
end
default: state <= S_IDLE;
endcase
end
end

View File

@ -13,6 +13,7 @@ module TB_top();
reg rst_n;
reg uart_rx; // 对应 DUT 的 RX
wire uart_tx; // 对应 DUT 的 TX
reg sig_in;
// 时钟生成
initial clk = 0;
@ -25,75 +26,91 @@ module TB_top();
.clk (clk),
.rst_n (rst_n),
.uart_rx (uart_rx),
.uart_tx (uart_tx)
.uart_tx (uart_tx),
.sig_in (sig_in)
);
// ==========================================
// 任务:发送一个字节 (Serial TX)
// ==========================================
task automatic send_byte(input [7:0] data);
begin
uart_rx = 0; // 起始位
#(BIT_TIME);
for (int i = 0; i < 8; i++) begin
uart_rx = data[i]; // LSB First
#(BIT_TIME);
end
uart_rx = 1; // 停止位
#(BIT_TIME);
end
endtask
// 任务:发送 32/64 位数据
task automatic send_data(input [63:0] data, input int len_bits);
int bytes = len_bits / 8;
for (int i = bytes - 1; i >= 0; i--) begin // 从最高字节往下发
send_byte(data[i*8 +: 8]);
end
endtask
// ==========================================
// 流程控制TX 驱动 (从 case.txt 读取)
// ==========================================
// // ==========================================
// // 流程控制TX 驱动 (从 case.txt 读取)
// // ==========================================
// initial begin
// int file_h;
// int status;
// logic [63:0] val;
// // 初始化信号
// rst_n = 0;
// uart_rx = 1;
// #(CLK_PERIOD * 10);
// rst_n = 1;
// file_h = $fopen("case.txt", "r");
// if (!file_h) begin
// $display("[TX ERROR] Cannot open case.txt");
// $finish;
// end
// $display("[TX] Starting transmission...");
// while (!$feof(file_h)) begin
// // 假设文件中每行是一个 hex 数据
// status = $fscanf(file_h, "%h\n", val);
// if (status == 1) begin
// if (val > 64'hFFFF_FFFF) begin
// $display("[%t] TX CMD: %h", $time, val);
// send_data(val, 64);
// end else begin
// $display("[%t] TX DATA: %h", $time, val[31:0]);
// send_data(val[31:0], 32);
// end
// #(BIT_TIME * 5); // 帧间隙
// end
// end
// $fclose(file_h);
// $display("[TX] All cases sent.");
// // 等待一段时间观察 RX 是否还有回传,然后结束
// #(BIT_TIME * 500);
// $display("[SIM] Simulation finished.");
// $finish;
// end
initial begin
int file_h;
int status;
logic [63:0] val;
// 初始化信号
rst_n = 0;
uart_rx = 1;
#(CLK_PERIOD * 10);
// 1. 初始化
rst_n = 0; uart_rx = 1; sig_in = 0;
#(CLK_PERIOD * 20);
rst_n = 1;
file_h = $fopen("case.txt", "r");
if (!file_h) begin
$display("[TX ERROR] Cannot open case.txt");
$finish;
end
#(CLK_PERIOD * 100);
$display("[TX] Starting transmission...");
$display("------- Step 1: Configure Thermometer Regs -------");
send_data(64'h80000004_00000004,64);
send_data(64'h80000008_00000004,64);
send_data(64'h8000000c_00000004,64);
send_data(64'h80000010_00000004,64);
send_data(64'h80000014_00000004,64);
while (!$feof(file_h)) begin
// 假设文件中每行是一个 hex 数据
status = $fscanf(file_h, "%h\n", val);
if (status == 1) begin
if (val > 64'hFFFF_FFFF) begin
$display("[%t] TX CMD: %h", $time, val);
send_data(val, 64);
end else begin
$display("[%t] TX DATA: %h", $time, val[31:0]);
send_data(val[31:0], 32);
end
#(BIT_TIME * 5); // 帧间隙
$display("------- Step 2: Running Concurrent Tasks -------");
fork
// 进程 A: 模拟输入脉冲 (代表温度变化)
begin
gen_pulses(400, 10); // 100kHz 持续 10ms
end
end
$fclose(file_h);
$display("[TX] All cases sent.");
// 等待一段时间观察 RX 是否还有回传,然后结束
// 进程 B: 在上报期间,强行插口读取指令
begin
#(2_000000); // 等待第一个上报包可能发出
$display("[%t] TX: Sending Read Request during active reporting...", $time);
send_data(64'h80000014_00000004,64);
send_data(64'h00000010_00000004,64);send_data(32'h8000_06e8,32);
send_data(64'h00000010_00000004,64);send_data(32'h8000_06e8,32);
end
join
#(BIT_TIME * 500);
$display("[SIM] Simulation finished.");
$display("Test Done.");
$finish;
end
@ -150,4 +167,53 @@ module TB_top();
end
end
// --- Pulse Generation Task ---
// freq_khz: Target frequency (kHz)
// duration_ms: Test duration (ms)
task automatic gen_pulses(input int freq_khz, input int duration_ms);
int half_period_ns;
longint end_time_ns;
begin
if (freq_khz <= 0) begin
sig_in = 0;
#(duration_ms * 1000000);
end else begin
half_period_ns = 500000 / freq_khz;
end_time_ns = $time + (longint'(duration_ms) * 1000000);
$display("[%0t] Start generating signal: %0d kHz", $time, freq_khz);
while ($time < end_time_ns) begin
sig_in = 1;
#(half_period_ns);
sig_in = 0;
#(half_period_ns);
end
end
end
endtask
// ==========================================
// 任务:发送一个字节 (Serial TX)
// ==========================================
task automatic send_byte(input [7:0] data);
begin
uart_rx = 0; // 起始位
#(BIT_TIME);
for (int i = 0; i < 8; i++) begin
uart_rx = data[i]; // LSB First
#(BIT_TIME);
end
uart_rx = 1; // 停止位
#(BIT_TIME);
end
endtask
// 任务:发送 32/64 位数据
task automatic send_data(input [63:0] data, input int len_bits);
int bytes = len_bits / 8;
for (int i = bytes - 1; i >= 0; i--) begin // 从最高字节往下发
send_byte(data[i*8 +: 8]);
end
endtask
endmodule