105 lines
2.7 KiB
Systemverilog
105 lines
2.7 KiB
Systemverilog
interface simple_bus (input logic clk); // Define the interface
|
|
logic req, gnt;
|
|
logic [7:0] addr, data;
|
|
logic [1:0] mode;
|
|
logic start, rdy;
|
|
int slaves = 0;
|
|
|
|
// tasks executed concurrently as a fork-join block
|
|
extern forkjoin task countSlaves();
|
|
extern forkjoin task Read (input logic [7:0] raddr);
|
|
extern forkjoin task Write (input logic [7:0] waddr);
|
|
|
|
modport slave (input req,addr, mode, start, clk,
|
|
output gnt, rdy,
|
|
ref data, slaves,
|
|
export Read, Write, countSlaves);
|
|
// export from module that uses the modport
|
|
|
|
modport master ( input gnt, rdy, clk,
|
|
output req, addr, mode, start,
|
|
ref data,
|
|
import task Read(input logic [7:0] raddr),
|
|
task Write(input logic [7:0] waddr));
|
|
// import requires the full task prototype
|
|
|
|
initial begin
|
|
slaves = 0;
|
|
countSlaves;
|
|
$display ("number of slaves = %d", slaves);
|
|
end
|
|
endinterface: simple_bus
|
|
|
|
module memMod #(parameter int minaddr=0, maxaddr=0) (interface a);
|
|
logic avail = 1;
|
|
logic [7:0] mem[255:0];
|
|
|
|
task a.countSlaves();
|
|
a.slaves++;
|
|
endtask
|
|
|
|
task a.Read(input logic [7:0] raddr); // Read method
|
|
if (raddr >= minaddr && raddr <= maxaddr) begin
|
|
avail = 0;
|
|
#10 a.data = mem[raddr];
|
|
avail = 1;
|
|
end
|
|
endtask
|
|
|
|
task a.Write(input logic [7:0] waddr); // Write method
|
|
if (waddr >= minaddr && waddr <= maxaddr) begin
|
|
avail = 0;
|
|
#10 mem[waddr] = a.data;
|
|
avail = 1;
|
|
end
|
|
endtask
|
|
endmodule
|
|
|
|
module cpuMod(interface b);
|
|
typedef enum {read, write} instr;
|
|
instr inst;
|
|
logic [7:0] raddr;
|
|
integer seed;
|
|
|
|
always @(posedge b.clk) begin
|
|
inst = instr'($dist_uniform(seed, 0, 1));
|
|
raddr = $dist_uniform(seed, 0, 3);
|
|
if (inst == read) begin
|
|
$display("%t begin read %h @ %h", $time, b.data, raddr);
|
|
callr:b.Read(raddr);
|
|
$display("%t end read %h @ %h", $time, b.data, raddr);
|
|
end
|
|
else begin
|
|
$display("%t begin write %h @ %h", $time, b.data, raddr);
|
|
b.data = raddr;
|
|
callw:b.Write(raddr);
|
|
$display("%t end write %h @ %h", $time, b.data, raddr);
|
|
end
|
|
end
|
|
endmodule
|
|
|
|
module top;
|
|
logic clk = 0;
|
|
|
|
function void interrupt();
|
|
disable mem1.a.Read; // task via module instance
|
|
disable sb_intf.Write; // task via interface instance
|
|
if (mem1.avail == 0) $display ("mem1 was interrupted");
|
|
if (mem2.avail == 0) $display ("mem2 was interrupted");
|
|
endfunction
|
|
|
|
always #5 clk++;
|
|
|
|
initial begin
|
|
#28 interrupt();
|
|
#10 interrupt();
|
|
#100 $finish;
|
|
end
|
|
|
|
simple_bus sb_intf(clk);
|
|
|
|
memMod #(0, 127) mem1(sb_intf.slave);
|
|
memMod #(128, 255) mem2(sb_intf.slave);
|
|
cpuMod cpu(sb_intf.master);
|
|
endmodule
|