Revert to default

This commit is contained in:
Jeremy Shen
2026-05-18 13:54:11 +08:00
parent 44b40ab9e1
commit c5df01f33d
50 changed files with 4436 additions and 89 deletions
+3
View File
@@ -0,0 +1,3 @@
# Lattice Diamond 实现输出目录
# 根目录 .gitignore 已覆盖大部分 pattern,此处仅确保 impl1/ 被忽略
impl1/
+9
View File
@@ -0,0 +1,9 @@
[Runmanager]
Geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x1\0\0\0\0\0\0\0\0\x3\x30\0\0\x1!\0\0\x4\x11\0\0\0\0\0\0\0\0\xff\xff\xff\xff\xff\xff\xff\xff\0\0\0\0\0\0)
windowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\x1\0\0\0\0\0\0\0\x1\xff\xff\xff\xff\x3\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0)
headerState=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x16\0\xe0?\0\0\0\t\0\0\0\x10\0\0\0\x64\0\0\0\xf\0\0\0\x64\0\0\0\xe\0\0\0\x64\0\0\0\r\0\0\0\x64\0\0\0\x15\0\0\0\x64\0\0\0\x14\0\0\0\x64\0\0\0\x13\0\0\0\x64\0\0\0\x12\0\0\0\x64\0\0\0\x11\0\0\0\x64\0\0\x4\xd3\0\0\0\x16\x1\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x3\0\0\0#\0\0\0\x1\0\0\0\x2\0\0\x4\xb0\0\0\0\f\0\0\0\0\0\0\0\0\0\0\0\t\0\0\0\0)
[impl1%3CStrategy1%3E]
isChecked=false
isHidden=false
isExpanded=false
+2
View File
@@ -0,0 +1,2 @@
[General]
Export.auto_tasks=Bitgen, Jedecgen
+3
View File
@@ -0,0 +1,3 @@
[General]
COLUMN_POS_INFO_NAME_-1_0=Prioritize
COLUMN_POS_INFO_NAME_-1_1=PIO Register
+76
View File
@@ -0,0 +1,76 @@
[General]
pin_sort_type=0
pin_sort_ascending=true
sig_sort_type=0
sig_sort_ascending=true
active_Sheet=Pin Assignments
[Port%20Assignments]
Name="193,0"
Group%20By="88,1"
Pin="79,2"
BANK="60,3"
BANK_VCC="88,4"
VREF="60,5"
IO_TYPE="147,6"
PULLMODE="97,7"
DRIVE="67,8"
SLEWRATE="91,9"
CLAMP="67,10"
OPENDRAIN="95,11"
DIFFRESISTOR="116,12"
DIFFDRIVE="95,13"
HYSTERESIS="102,14"
Outload%20%28pF%29="116,15"
MaxSkew="81,16"
Clock%20Load%20Only="137,17"
SwitchingID="109,18"
Ground%20plane%20PCB%20noise%20%28mV%29="221,19"
Power%20plane%20PCB%20noise%20%28mV%29="214,20"
SSO%20Allowance%28%25%29="144,21"
sort_columns="Name,Ascending"
[Pin%20Assignments]
Pin="93,0"
Pad%20Name="88,1"
Dual%20Function="158,2"
Polarity="88,3"
BANK="0,4"
BANK_VCC="88,5"
IO_TYPE="147,6"
Signal%20Name="177,7"
Signal%20Type="115,8"
sort_columns="Pin,Ascending"
[Clock%20Resource]
Clock%20Type="100,ELLIPSIS"
Clock%20Name="100,ELLIPSIS"
Selection="100,ELLIPSIS"
[Global%20Preferences]
Preference%20Name="231,ELLIPSIS"
Preference%20Value="236,ELLIPSIS"
[Cell%20Mapping]
Type="100,ELLIPSIS"
Name="223,ELLIPSIS"
Din\Dout="83,ELLIPSIS"
PIO%20Register="100,ELLIPSIS"
[Route%20Priority]
Type="100,ELLIPSIS"
Name="100,ELLIPSIS"
Prioritize="100,ELLIPSIS"
[Timing%20Preferences]
Preference%20Name="129,ELLIPSIS"
Preference%20Value="111,ELLIPSIS"
Preference%20Unit="103,ELLIPSIS"
[Group]
Group%20Type\Name="134,ELLIPSIS"
Value="42,ELLIPSIS"
[Misc%20Preferences]
Preference%20Name="117,ELLIPSIS"
Preference%20Value="111,ELLIPSIS"
+215
View File
@@ -0,0 +1,215 @@
module BUS_Con (
input i_sys_clk,
input i_rst_n,
// SPI Interface
input i_sclk,
input i_mosi,
input i_cs,
output o_miso, // <-- MISO Logic added here
// Local Interface
output o_rvalid, // (Typo in original: o_rvalid)
input i_rvalid, // Valid signal from Backend (Data is ready)
input i_wvalid,
output o_wready,
input i_reg_busy,
input [23:0] i_rdata, // Data from Backend to send to Master
output o_wr,
output o_cmd_valid,
output [23:0] o_data,
output [6:0] o_addr,
output o_err
);
// --- 1. Synchronization ---
reg [1:0] cs_sync;
reg [1:0] sclk_sync;
reg [1:0] mosi_sync;
wire cs_active;
wire cs_rise;
wire sclk_rise; // For Sampling MOSI
wire sclk_fall; // For Shifting MISO
wire mosi_data;
always @(posedge i_sys_clk) begin
if (!i_rst_n) begin
cs_sync <= 2'b11;
sclk_sync <= 2'b00;
mosi_sync <= 2'b00;
end else begin
cs_sync <= {cs_sync[0], i_cs};
sclk_sync <= {sclk_sync[0], i_sclk};
mosi_sync <= {mosi_sync[0], i_mosi};
end
end
assign cs_active = ~cs_sync[1];
assign cs_rise = (!cs_sync[1] && cs_sync[0]);
// SPI Mode 0: Sample MOSI on Rising, Shift MISO on Falling
assign sclk_rise = (!sclk_sync[1] && sclk_sync[0]);
assign sclk_fall = (sclk_sync[1] && !sclk_sync[0]); // Logic for MISO
assign mosi_data = mosi_sync[1];
// --- 2. MOSI (Receive) Logic ---
reg [31:0] recv_reg;
reg [5:0] bit_cnt;
reg data_ready;
reg err_flag;
reg [1:0] state;
//
reg [31:0] tx_buffer; // Holds data waiting for the next CS Low
reg [31:0] miso_shift; // The actual shifter
// Output Registers
reg [6:0] addr_out;
reg [23:0] data_out;
reg wr_out;
reg cmd_valid_out;
//
localparam IDLE = 2'b00;
localparam CMD_SENT = 2'b01;
localparam WAIT_BUSY = 2'b10;
localparam DONE = 2'b11;
always @(posedge i_sys_clk) begin
if (!i_rst_n) begin
recv_reg <= 32'd0;
bit_cnt <= 6'd0;
data_ready <= 1'b0;
err_flag <= 1'b0;
end
else begin
data_ready <= 1'b0;
if (cs_active) begin
if (sclk_rise) begin
recv_reg <= {recv_reg[30:0], mosi_data};
bit_cnt <= bit_cnt + 1'b1;
end
else if (cs_rise) begin
if (bit_cnt == 6'd32) begin
data_ready <= 1'b1;
err_flag <= 1'b0;
bit_cnt <= 6'd0;
end
else if (bit_cnt != 0) begin
err_flag <= 1'b1;
bit_cnt <= 6'd0;
recv_reg <= 'd0;
end
end
end
if (state == DONE) begin
recv_reg <= 'd0;
end
end
end
// --- 3. MISO (Transmit) Logic ---
// Protocol: We shift out 32 bits.
// Format: [8 bit Status/Padding] + [24 bit i_rdata]
// Capture data from backend when valid
always @(posedge i_sys_clk) begin
if (!i_rst_n) begin
tx_buffer <= 32'd0;
end else begin
// If backend provides valid read data, store it.
// We pad the top 8 bits with Zeros (or you can put status flags here)
if (i_rvalid) begin
tx_buffer <= {8'h00, i_rdata};
end
end
end
// Shift data out
always @(posedge i_sys_clk) begin
if (!i_rst_n) begin
miso_shift <= 32'd0;
end else begin
if (!cs_active) begin
// Pre-load the shifter while CS is High
// This ensures Bit 31 is ready BEFORE the first clock edge
miso_shift <= tx_buffer;
end else begin
// Shift on Falling Edge (Master samples on Rising)
if (sclk_fall) begin
miso_shift <= {miso_shift[30:0], 1'b0};
end
end
end
end
// Tri-state MISO when CS is high (optional, usually good practice)
// If your board doesn't need tristate, just use: assign o_miso = miso_shift[31];
assign o_miso = (cs_active) ? miso_shift[31] : 1'bz;
// --- 4. Register Control FSM ---
always @(posedge i_sys_clk) begin
if (!i_rst_n) begin
state <= IDLE;
cmd_valid_out <= 1'b0;
addr_out <= 7'd0;
data_out <= 24'd0;
wr_out <= 1'b0;
end else begin
case (state)
IDLE: begin
if (data_ready) begin
addr_out <= recv_reg[30:24];
data_out <= recv_reg[23:0];
wr_out <= recv_reg[31];
if (!i_reg_busy) begin
cmd_valid_out <= 1'b1;
state <= CMD_SENT;
end else begin
state <= WAIT_BUSY;
end
end
end
WAIT_BUSY: begin
if (!i_reg_busy) begin
cmd_valid_out <= 1'b1;
state <= CMD_SENT;
end
end
CMD_SENT: begin
cmd_valid_out <= 1'b0;
state <= DONE;
end
DONE: begin
if (!i_reg_busy) begin
state <= IDLE;
addr_out <= 'd0;
data_out <= 'd0;
wr_out <= 'd0;
end
end
endcase
end
end
assign o_addr = addr_out;
assign o_data = data_out;
assign o_wr = wr_out;
assign o_cmd_valid = cmd_valid_out;
assign o_err = err_flag;
assign o_wready = (state == IDLE);
// Pass through unused signal or hook it up if needed
assign o_rvalid = 1'b0;
endmodule
+91
View File
@@ -0,0 +1,91 @@
module CPLD_Con (
input i_sys_clk,
input i_rst_n,
input i_con_exec,
input [23:0]i_freq_relay1,
input [23:0]i_freq_relay2,
input [23:0]i_freq_relay3,
input [23:0]i_freq_relay4,
output o_con_done,
output [3:0]o_PMU_RC,
output o_err
);
//Relay Reg
reg [3:0] PMU_RC;
//Flags
reg exec_flag;
reg err_flag;
reg [3:0]slot_exec_flag;
reg done_flag;
//Counter
reg [15:0]delay_cnt;
always @(posedge i_sys_clk) begin
if (i_rst_n == 1'b0) begin
delay_cnt <= 'd0;
end
else begin
if (exec_flag == 1'b1) begin
delay_cnt <= delay_cnt + 1'd1;
end
else begin
delay_cnt <= 'd0;
end
end
end
always @(posedge i_sys_clk) begin
if (i_rst_n == 1'b0) begin
exec_flag <= 1'b0;
err_flag <= 1'b0;
slot_exec_flag <= 'd0;
done_flag <= 'd1;
PMU_RC <= 4'b1111;
end
else begin
if ((i_con_exec == 1'b1) & (exec_flag == 1'b0)) begin
exec_flag <= 1'b1;
done_flag <= 1'b0;
//To DO: More Sanity Check?
if ( (i_freq_relay1[0] + i_freq_relay2[0] + i_freq_relay3[0] + i_freq_relay4[0]) > 2'd1 ) begin
err_flag <= 1'b1;
end
else begin
slot_exec_flag[0] <= i_freq_relay1[0];
slot_exec_flag[1] <= i_freq_relay2[0];
slot_exec_flag[2] <= i_freq_relay3[0];
slot_exec_flag[3] <= i_freq_relay4[0];
end
end
else if (exec_flag == 1'b1) begin
case (slot_exec_flag)
4'b0001: begin
PMU_RC <= 4'b1111;
end
4'b0010: begin
PMU_RC <= 4'b1100;
end
4'b0100: begin
PMU_RC <= 4'b1010;
end
4'b1000: begin
PMU_RC <= 4'b0110;
end
endcase
done_flag <= 1'b1;
end
end
if (done_flag == 1) begin
exec_flag <= 1'b0;
end
end
assign o_con_done = done_flag;
assign o_PMU_RC = PMU_RC;
assign o_err = err_flag;
endmodule
+1
View File
@@ -0,0 +1 @@
VERSION=20110520
+38
View File
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<BaliProject version="3.2" title="NewExtIns_CPLD3" device="LCMXO2-7000HC-4FG484C" default_implementation="impl1">
<Options/>
<Implementation title="impl1" dir="impl1" description="impl1" synthesis="synplify" default_strategy="Strategy1">
<Options def_top="RelayConTop" top="RelayConTop"/>
<Source name="RelayConTop.v" type="Verilog" type_short="Verilog">
<Options top_module="RelayConTop"/>
</Source>
<Source name="BUS_Con.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="Reg_file.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="tb_RelayConTop.sv" type="Verilog" type_short="Verilog" syn_sim="SimOnly">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="CPLD_Con.v" type="Verilog" type_short="Verilog">
<Options/>
</Source>
<Source name="CPLD3_Debug.rva" type="Reveal Analyzer Project File" type_short="RVA">
<Options/>
</Source>
<Source name="NewExtIns_CPLD3.lpf" type="Logic Preference" type_short="LPF">
<Options/>
</Source>
<Source name="debug.rvl" type="Reveal" type_short="Reveal">
<Options/>
</Source>
<Source name="impl1/impl1.xcf" type="Programming Project File" type_short="Programming">
<Options/>
</Source>
<Source name="tb_RelayConTop/tb_RelayConTop.spf" type="Simulation Project File" type_short="SPF">
<Options/>
</Source>
</Implementation>
<Strategy name="Strategy1" file="NewExtInsRelay1.sty"/>
</BaliProject>
+29
View File
@@ -0,0 +1,29 @@
rvl_alias "i_sys_clk" "i_sys_clk";
RVL_ALIAS "i_sys_clk" "i_sys_clk";
BLOCK RESETPATHS ;
BLOCK ASYNCPATHS ;
LOCATE COMP "i_sys_clk" SITE "B9" ;
LOCATE COMP "i_rst_n" SITE "Y14" ;
LOCATE COMP "i_sclk" SITE "AA10" ;
LOCATE COMP "i_cs" SITE "AB11" ;
LOCATE COMP "i_mosi" SITE "AB12" ;
LOCATE COMP "o_miso" SITE "AA14" ;
IOBUF PORT "i_cs" IO_TYPE=LVCMOS33 ;
IOBUF PORT "i_mosi" IO_TYPE=LVCMOS33 ;
IOBUF PORT "i_rst_n" IO_TYPE=LVCMOS33 ;
IOBUF PORT "i_sclk" IO_TYPE=LVCMOS33 ;
IOBUF PORT "o_miso" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=8 ;
IOBUF PORT "o_rvaild" IO_TYPE=LVCMOS33 PULLMODE=NONE ;
IOBUF PORT "o_wready" IO_TYPE=LVCMOS33 PULLMODE=NONE ;
IOBUF PORT "i_sys_clk" DRIVE=NA IO_TYPE=LVCMOS33 SLEWRATE=NA PULLMODE=DOWN ;
IOBUF PORT "o_err" IO_TYPE=LVCMOS33 ;
LOCATE COMP "o_err" SITE "AB16" ;
LOCATE COMP "o_PMU_RC[0]" SITE "V2" ;
LOCATE COMP "o_PMU_RC[1]" SITE "N18" ;
LOCATE COMP "o_PMU_RC[2]" SITE "P19" ;
LOCATE COMP "o_PMU_RC[3]" SITE "P18" ;
IOBUF PORT "o_PMU_RC[0]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "o_PMU_RC[1]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "o_PMU_RC[2]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "o_PMU_RC[3]" IO_TYPE=LVCMOS33 ;
BLOCK JTAGPATHS ;
+165
View File
@@ -0,0 +1,165 @@
module Reg_file (
input i_sys_clk,
input i_rst_n,
// Bus Interface
input i_wr_req,
input i_wr,
input [6:0] i_addr,
input [23:0] i_wdata,
output [23:0] o_rdata,
output o_rvalid,
output o_busy,
output o_err,
// Controller Interface
input i_con_done, // 1=IDLE/DONE, 0=BUSY
output o_exec,
// Direct Register Outputs
output [23:0] o_freq1,
output [23:0] o_freq2,
output [23:0] o_freq3,
output [23:0] o_freq4
);
// --- Parameters ---
localparam REG_COUNT = 16;
localparam [23:0]
IDENT = 24'h800000|| 12'b0001_0000_0000, //CPLD3==1,version=1.0.0
STATE_INIT = 24'h800000;
// State Machine Definition
localparam IDLE = 4'd0;
localparam BUSY = 4'd1;
localparam EXEC_ACK = 4'd2; // Wait for controller to go BUSY (Done=0)
localparam EXEC_WAIT = 4'd3; // Wait for controller to go DONE (Done=1)
// --- Internal Signals ---
reg [3:0] state;
reg [23:0] regtable [0:REG_COUNT - 1];
reg [23:0] rdata_reg;
reg busy_flag;
reg err_flag;
reg rvalid_flag;
integer i;
// Mapping Control Bits
wire exec_bit = regtable[1][0];
always @(posedge i_sys_clk or negedge i_rst_n) begin
if (!i_rst_n) begin
for (i = 0; i < REG_COUNT; i = i + 1) begin
regtable[i] <= 24'h0;
end
regtable[0] <= IDENT;
regtable[1] <= STATE_INIT;
rvalid_flag <= 1'b0;
busy_flag <= 1'b0;
err_flag <= 1'b0;
state <= IDLE;
end
else begin
case (state)
IDLE: begin
rvalid_flag <= 1'b0;
err_flag <= 1'b0;
// Priority Check: Did we crash/reset while EXEC bit was still 1?
if (exec_bit == 1'b1) begin
state <= EXEC_ACK;
busy_flag <= 1'b1;
end
else if (i_wr_req == 1'b1) begin
busy_flag <= 1'b1;
state <= BUSY;
// Addr Sanity Check
if ((i_wr && (i_addr == 'd0 || i_addr >= REG_COUNT)) ||
(!i_wr && (i_addr >= REG_COUNT)))
begin
err_flag <= 1'b1;
end
end
else begin
busy_flag <= 1'b0;
end
end
BUSY: begin
if (err_flag) begin
state <= IDLE;
end
else begin
if (i_wr == 1'b1) begin // --- WRITE ---
if (exec_bit == 1'b1) begin
// Cannot write if Controller is already running
err_flag <= 1'b1;
state <= IDLE;
end
else begin
regtable[i_addr] <= i_wdata;
// Check if this write is a "Start Command"
if (i_addr == 7'd1 && i_wdata[0] == 1'b1) begin
// Go to Handshake Start
state <= EXEC_ACK;
end else begin
state <= IDLE;
end
end
end
else begin // --- READ ---
rdata_reg <= regtable[i_addr];
rvalid_flag <= 1'b1;
state <= IDLE;
end
end
end
// --- EXEC PHASE 1: ACK ---
// Wait for Controller to register the command and pull 'done' LOW (Busy)
EXEC_ACK: begin
busy_flag <= 1'b1;
state <= EXEC_WAIT;
// Optional: Timeout counter here to prevent hanging if Controller is dead
end
// --- EXEC PHASE 2: WAIT ---
// Now wait for Controller to finish and pull 'done' HIGH (Idle/Ready)
EXEC_WAIT: begin
busy_flag <= 1'b1;
if (i_con_done == 1'b1) begin
// 1. Clear the Exec bit (Auto-Clear)
// 2. Set the Ready bit (Bit 23) if you wish
regtable[1] <= {1'b1, regtable[1][22:1], 1'b0};
busy_flag <= 1'b0;
state <= IDLE;
end
end
default: state <= IDLE;
endcase
end
end
assign o_rvalid = rvalid_flag;
assign o_rdata = rdata_reg;
assign o_busy = busy_flag;
assign o_err = err_flag;
// Output the control bit to the controller
// This stays HIGH during both EXEC_ACK and EXEC_WAIT
assign o_exec = exec_bit;
assign o_freq1 = regtable[2];
assign o_freq2 = regtable[3];
assign o_freq3 = regtable[4];
assign o_freq4 = regtable[5];
endmodule
+98
View File
@@ -0,0 +1,98 @@
module RelayConTop (
input i_sys_clk,
input i_rst_n,
input i_sclk,
input i_mosi,
input i_cs,
output o_miso,
output o_rvaild,
input i_rready,
input i_wvaild,
output o_wready,
output o_err,
output o_con_done,
output [3:0]o_PMU_RC
);
wire [3:0]PMU_RC ;
wire [23:0]r_data ;
wire [23:0]w_data ;
wire [6:0]reg_addr ;
wire cmd_vaild;
wire reg_busy;
wire wr_flag; //1=write,0=read
wire bus_err_flag;
wire reg_err_flag;
wire cpld_err_flag;
wire con_exec;
wire [23:0]freq1_relay ;
wire [23:0]freq2_relay ;
wire [23:0]freq3_relay ;
wire [23:0]freq4_relay ;
wire con_rvaild;
wire con_done;
BUS_Con Bus_Con_3(
.i_sys_clk(i_sys_clk),
.i_rst_n(i_rst_n),
.i_sclk(i_sclk),
.i_mosi(i_mosi),
.i_cs(i_cs),
.i_rvalid(con_rvalid),
.i_wvalid(i_wvalid),
.i_reg_busy(reg_busy),
.i_rdata(r_data),
.o_cmd_valid(cmd_vaild),
.o_wr(wr_flag),
.o_miso(o_miso),
.o_rvalid(o_rvalid),
.o_wready(o_wready),
.o_data(w_data),
.o_addr(reg_addr),
.o_err(bus_err_flag)
);
Reg_file CPLD_Reg_3(
.i_sys_clk(i_sys_clk),
.i_rst_n(i_rst_n),
.i_wr_req(cmd_vaild),
.i_wr(wr_flag),
.i_addr(reg_addr),
.i_wdata(w_data),
.i_con_done(con_done), //Controller Exec Done
.o_freq1(freq1_relay), //Freq_Slot1
.o_freq2(freq2_relay), //Freq_Slot2
.o_freq3(freq3_relay), //Freq_Slot3
.o_freq4(freq4_relay), //Freq_Slot4
.o_rvalid(con_rvalid),
.o_rdata(r_data),
.o_exec(con_exec), //Exec cmd
.o_busy(reg_busy),
.o_err(reg_err_flag)
);
CPLD_Con CPLD_Con_3(
.i_sys_clk(i_sys_clk),
.i_rst_n(i_rst_n),
.i_con_exec(con_exec),
.i_freq_relay1(freq1_relay),
.i_freq_relay2(freq2_relay),
.i_freq_relay3(freq3_relay),
.i_freq_relay4(freq4_relay),
.o_con_done(con_done),
.o_PMU_RC(PMU_RC),
.o_err(cpld_err_flag)
);
assign o_con_done = con_done;
assign o_PMU_RC = PMU_RC;
assign o_err = bus_err_flag || reg_err_flag ||cpld_err_flag;
endmodule
View File
+310
View File
@@ -0,0 +1,310 @@
`timescale 1ns/1ps
module tb_RelayConTop;
// 时钟和复位
reg i_sys_clk;
reg i_rst_n;
// SPI接口
reg i_sclk;
reg i_mosi;
reg i_cs;
// wire o_miso;
// 流控制接口
// wire o_rvaild;
// reg i_rready;
// reg i_wvaild;
// wire o_wready;
wire o_err;
// 继电器控制输出
wire [7:0] o_RC_F;
wire [15:0] o_RC_S;
wire [31:0] o_RC_T;
// 测试变量
reg [31:0] spi_data;
integer test_pass;
integer test_fail;
// 实例化被测模块
RelayConTop DUT (
.i_sys_clk(i_sys_clk),
.i_rst_n(i_rst_n),
.i_sclk(i_sclk),
.i_mosi(i_mosi),
.i_cs(i_cs),
// .o_miso(o_miso),
// .o_rvaild(o_rvaild),
// .i_rready(i_rready),
// .i_wvaild(i_wvaild),
// .o_wready(o_wready),
.o_err(o_err),
.o_RC_F(o_RC_F),
.o_RC_S(o_RC_S),
.o_RC_T(o_RC_T)
);
// 时钟生成
initial begin
i_sys_clk = 0;
forever #5 i_sys_clk = ~i_sys_clk; // 20MHz系统时钟
end
// SPI时钟生成(比系统时钟慢)
initial begin
i_sclk = 0;
forever #50 i_sclk = ~i_sclk; // 2MHz SPI时钟
end
// 主测试流程
initial begin
// 初始化
initialize();
// 测试计数器
test_pass = 0;
test_fail = 0;
$display("=== CPLD2 Controller Test Start ===");
// 测试1: 复位后寄存器读取
test_reset_registers();
// 测试2: 寄存器写入和读取
test_register_write_read();
// 测试3: EXEC命令执行测试
test_exec_command();
// 测试4: 错误条件测试
test_error_conditions();
// 测试5: SPI连续传输测试
test_spi_continuous();
// 测试6: 边界条件测试
test_boundary_conditions();
// 总结
$display("=== Test Done ===");
$display("PASS: %0d", test_pass);
$display("Failed: %0d", test_fail);
if (test_fail == 0) begin
$display("*** ALL TEST PASSED! ***");
end else begin
$display("*** TEST FAILED FOUND!! CHECK DESIGN ***");
end
#1000 $finish;
end
// 初始化任务
task initialize;
begin
i_rst_n = 1;
i_cs = 1;
i_mosi = 0;
#100;
i_rst_n = 0;
#200;
i_rst_n = 1;
i_cs = 1;
$display("Initialize DONE!");
end
endtask
// SPI发送任务
task spi_send;
input [31:0] data;
integer i;
begin
#50;
i_cs = 0; // 片选有效
for (i = 31; i >= 0 ; i--) begin
#50; // 在SCLK上升沿前设置数据
i_mosi = data[i];
#50; // 等待SCLK上升沿
end
#50
i_cs = 1; // 片选无效
#200;
end
endtask
// 测试1: 复位后寄存器读取
task test_reset_registers;
begin
$display("--- TEST1: REG READ AFTER RST ---");
// 读取芯片ID寄存器 (地址0)
spi_data = {1'b1,23'h0, 1'b0,7'h0}; // 读操作,地址0,TEST
spi_send(spi_data);
// 检查返回值(应该在MISO上看到0x400000
#1000;
check_result(1, "CPLD READ ID");
end
endtask
// 测试2: 寄存器写入和读取
task test_register_write_read;
begin
$display("--- TEST2: REG READ & WRITE ---");
// 写入频率槽1寄存器 (地址2)
spi_data = {24'h123456,1'b1,7'h2}; // 写操作,地址2,数据0x123456
spi_send(spi_data);
#500;
// 读取频率槽1寄存器验证
spi_data = {24'h0, 1'b0, 7'h2}; // 读操作,地址2
spi_send(spi_data);
#500;
check_result(1, "REG READ & WRITE");
end
endtask
// 测试3: EXEC命令执行测试
task test_exec_command;
begin
$display("--- TEST3: EXEC TEST ---");
// 设置EXEC位 (地址1的bit0)
spi_data = {24'h000001, 1'b1, 7'h1}; // 写操作,地址1,设置EXEC位
spi_send(spi_data);
#1000;
check_result(1, "EXEC TEST");
end
endtask
// 测试4: 错误条件测试
task test_error_conditions;
begin
$display("--- 测试4: ERR TEST ---");
// 测试4.1: 写入只读寄存器 (地址0)
spi_data = {24'hDEADBE,1'b1, 7'h0 }; // 尝试写入只读寄存器
spi_send(spi_data);
#500;
// 测试4.2: 访问超出范围的地址
spi_data = {24'h0, 1'b0, 7'h20}; // 读取地址32(超出范围)
spi_send(spi_data);
#500;
check_result(1, "ERR TEST");
end
endtask
// 测试5: SPI连续传输测试
task test_spi_continuous;
begin
$display("--- 测试5: SPI BATCH READ&WRITE ---");
// 连续写入多个寄存器
spi_data = {24'h111111, 7'h2, 1'b1};
spi_send(spi_data);
#300;
spi_data = {24'h222222, 7'h3, 1'b1};
spi_send(spi_data);
#300;
spi_data = {24'h333333, 7'h4, 1'b1};
spi_send(spi_data);
#300;
// 连续读取验证
spi_data = {24'h0, 7'h2, 1'b0};
spi_send(spi_data);
#300;
spi_data = {24'h0, 7'h3, 1'b0};
spi_send(spi_data);
#300;
spi_data = {24'h0, 7'h4, 1'b0};
spi_send(spi_data);
#300;
check_result(1, "SPI BATCH READ&WRITE");
end
endtask
// 测试6: 边界条件测试
task test_boundary_conditions;
begin
$display("--- TEST6: EDGE CASE TEST ---");
// 测试6.1: 复位期间的SPI访问
i_rst_n = 0;
spi_data = {24'h0, 7'h1, 1'b0};
spi_send(spi_data);
#200;
i_rst_n = 1;
#500;
// 测试6.2: CS信号异常
i_cs = 0;
#50;
i_cs = 1; // 短暂CS脉冲
#50;
i_cs = 0;
#1000;
i_cs = 1;
#500;
check_result(1, "EDGE CASE TEST");
end
endtask
// 结果检查任务
task check_result;
input expected;
input [120:1] test_name; // 字符数组存储测试名称
begin
if (expected) begin
test_pass = test_pass + 1;
$display("TEST %s - PASSED", test_name);
end else begin
test_fail = test_fail + 1;
$display("TEST %s - FAILED", test_name);
end
end
endtask
/*
// 监控关键信号
initial begin
$display("TIME | CS | SCLK | MOSI | MISO | ERR | RC_CON");
$display("-----|----|------|------|------|------|--------");
forever begin
#1000;
$display("%4t | %b | %b | %b | %b | %b | F:%h S:%h T:%h",
$time, i_cs, i_sclk, i_mosi, o_miso, o_err,
o_RC_F, o_RC_S, o_RC_T);
end
end
*/
// VCD文件生成(用于波形查看)
initial begin
$dumpfile("relay_con_top.vcd");
$dumpvars(0, tb_RelayConTop);
end
// 超时保护
initial begin
#5000000; // 5ms超时
$display("!!! TEST TIMEOUT !!!");
$finish;
end
endmodule