📄 cordic_par_seq_apb_test_master_rtl.v
字号:
`timescale 1ns/1ns
module CORDIC_par_seq_bus_test_master_RTL
#(parameter
period = 10,
master_Tco = 2
)
(
APB.RTL_master apb,
output logic async_reset
);
always begin: ClockGenerator
apb.PCLK = 0;
apb.PCLK <= #(period/2) 1;
#period;
end // ClockGenerator
// _____________________________________________________ BFM ENTRY POINTS ___
// Non-synthesisable task-call interface for a testbench master
// so that it can exercise slaves on the bus without the need for
// a fully-functional model of a master device.
// Call these BFM tasks at the posedge of the clock right
// at the beginning of the cycle. They return just after
// the final posedge of the cycle.
// ______________________________________________________ reset() ___
//
task reset ( int n );
async_reset = 1;
idle(n);
ClockTcoSync;
async_reset = 0;
endtask // reset
// _______________________________________________________ read() ___
//
task read (
input T_APB_a adrs,
output T_APB_d data
);
// Get to Tco after the most recent possible clock
ClockTcoSync;
apb.PADDR = adrs;
apb.PWRITE = 1'b0;
apb.psel = 1'b1;
@(posedge apb.PCLK)
apb.PENABLE <= #master_Tco 1'b1;
@(posedge apb.PCLK)
data = apb.PRDATA;
apb.PADDR <= {$bits(apb.PADDR){1'bx}};
apb.psel <= 1'b0;
apb.PENABLE <= 1'b0;
endtask // read
// ______________________________________________________ write() ___
//
task write (
input T_APB_a adrs,
input T_APB_d data
);
// Get to Tco after the most recent possible clock
ClockTcoSync;
apb.PADDR = adrs;
apb.PWDATA = data;
apb.PWRITE = 1'b1;
apb.psel = 1'b1;
@(posedge apb.PCLK)
apb.PENABLE <= #master_Tco 1'b1;
@(posedge apb.PCLK)
apb.PWDATA <= {$bits(apb.PADDR){1'bx}};
apb.PADDR <= {$bits(apb.PADDR){1'bx}};
apb.psel <= 1'b0;
apb.PENABLE <= 1'b0;
endtask // write
// _______________________________________________________ idle() ___
//
task idle ( int n );
if (n > 0 ) begin
// Get to Tco after the most recent possible clock
ClockTcoSync;
repeat (n) @(posedge apb.PCLK);
end
endtask
// __________________________________________________________________________
// ____________________________________________ HELPER CODE FOR BFM TASKS ___
// As always with procedural entry points into a BFM, there is
// an issue about synchronisation between the moment of task call
// and the bus's clock. If the task is called at some random time,
// its activity must be resynchronised to the bus clock. However,
// if it's already synchronised, then we don't want a spurious
// additional clock wait. One possible solution to this problem is
// offered here: the BFM read and write tasks can be called at any
// time. If called at or just after a clock edge, BFM activity can
// proceed as from that clock edge (signals don't need to be set up
// until one clock-to-valid delay after the clock edge). If called
// at any other time, the task is stalled until just after the next
// clock edge.
// In order to make this approach work, we need to keep track of
// the time of the most recent active clock edge.
//
always @(posedge apb.PCLK) begin : ClockEdgeLogger
time LastClock;
LastClock = $time;
end // ClockEdgeLogger
// Now, when a BFM task is called, it uses the time-of-last-clock
// information to determine whether it can proceed immediately, or
// must wait until the next clock. Task ClockTcoSync encapsulates
// this behaviour; it not only enforces the clock wait if necessary,
// but also waits until the future time at which the BFM task must
// apply its valid bus signals.
//
// Note that this task will still work correctly even if
// parameter master_Tco is set to zero.
//
task ClockTcoSync;
time t;
// If this task was called as the result of a clock edge, we must
// be sure that the LastClock value has already been updated.
// That's why we need a #0 delay prefix here.
//
#0 t = $time - ClockEdgeLogger.LastClock;
// Are we too late to start the bus cycle on the current clock?
//
if (t > master_Tco) begin
// Yes, we're too late. Wait for the next clock.
@(posedge apb.PCLK) t = master_Tco;
end else begin
// No, we're in time. Calculate how long we need to wait
// before applying the right signals.
t = master_Tco - t;
end
// Finally, align to Tco after the chosen clock
#(t);
endtask
endmodule // CORDIC_par_seq_bus_test_master_RTL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -