reg cb_ack_event
;
always @(lmcver.cb_ack) begin
cb_ack_event = `true;
cb_ack_event <= #(0) `false;
end
reg cb_initiator_id_event
;
always @(lmcver.cb[cbinitiator_id1:cbinitiator_id2]) begin
cb_initiator_id_event = `true;
cb_initiator_id_event <= #(0) `false;
end
//------------
// RECEIVER --
//------------
task receiver;
reg [1:`slv_size] addr_str;
reg [1:`slv_size] data_str;
reg [`slv_size-1:0] addr_slv;
reg [`slv_size-1:0] data_slv;
reg valid_f;
integer i;
begin
valid_f = `false;
if (cb_ack_event) begin
if (driving_cb_ack_f) begin
driving_cb_ack_f = `false;
lmcver.cb_ack[ackack_val1:ackack_val2] <= #(0) `Release;
end // if
end // if
if (cb_initiator_id_event && (lmcver.cb[cbinitiator_id1:cbinitiator_id2] !== `cb_release_id) && (lmcver.cb[cbinitiator_id1:cbinitiator_id2] !== id_number)) begin
if ((lmcver.cb[cbtarget_id1:cbtarget_id2] === id_number) || (lmcver.cb[cbtarget_id1:cbtarget_id2] === `cb_brdcst_id)) begin
if ((!(msg_level < `debug_cb))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"Target %0d : Receiving", id_number);
$display("\"");
end // if
busy_f = `false;
//receive message if valid
case (lmcver.cb[cbtransaction1:cbtransaction2])
`cmd_trans : begin
temp_cmd[cbfield1:cbfield2] = lmcver.cb;
timing.to_fm_data_in(lmcver.cb[cbmsg1:cbmsg2], msg_level); //prechecks, issues syntax warnings
temp_cmd[fmfield1:fmfield2] = timing.wk_cmd;
if (temp_cmd[fmcode1:fmcode2] !== `null_cmd) begin
if (temp_cmd[cbbuffer_f]) begin
//store command in cmd_mem
addelement(temp_cmd[cbfield1:cbfield2],load_mem_addr,valid_f);
if (valid_f) begin
bfm_msg("Target stored buffer type command" ,`debug_cb,msg_level);
end
else begin
build_cmd(temp_cmd[cbmsg1:cbmsg2],"func_end"," "); // currently function name does not matter for end
max_cmd_mem_size = max_cmd_mem_size + 1;
addelement(temp_cmd[cbfield1:cbfield2],load_mem_addr,valid_f);
end // if
end
else begin
//verify legal execute type command
if (temp_cmd[fmcode1:fmcode2] !== `call_cmd) begin
//store command in exe_nxt_buf if empty??
if (exe_nxt_buf_pointer === 0) begin
exe_nxt_buf[exe_nxt_buf_pointer + 1] = temp_cmd;
exe_nxt_buf_pointer = exe_nxt_buf_pointer + 1;
bfm_msg("Target stored execute type command in exe_nxt_buf buffer" ,`debug_cb,msg_level);
end
else begin
busy_f = `true;
//set issued_busy_f so can broadcast a ready message
issued_busy_f = `true;
bfm_msg("Execute command buffer full, command not accepted" ,`debug_cb,msg_level);
end // if
end // if
else begin
bfm_msg("CALL_CMD Not allowed as remote/execute type command" ,`warnings,msg_level);
end // if
end // if
end // if
end
`status_trans : begin
if ((lmcver.cb[cbbuffer_avail_f]) && (lmcver.cb[cbinitiator_id1:cbinitiator_id2] === wait_on_avail_id)) begin
wait_on_avail_f = `false;
if ((!(msg_level < `debug_cb))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"BUFFER_AVAILABLE Status received from id_number =%0d", lmcver.cb[cbinitiator_id1:cbinitiator_id2]);
$display("\"");
end // if
end // if
if (lmcver.cb[cbdone_f]) begin
if ((wait_on_done_f) && (lmcver.cb[cbtag1:cbtag2] === wait_on_done_tag)) begin
done_f_rcvd = `true;
if ((!(msg_level < `debug_cb))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"DONE Status received from id_number =%0d\n", lmcver.cb[cbinitiator_id1:cbinitiator_id2]);
$write(" Received TAG =%0d\n", lmcver.cb[cbtag1:cbtag2]);
$write(" WAIT_ON_TAG =%0d", wait_on_done_tag);
$display("\"");
end // if
end
else begin
if ((!(msg_level < `debug_cb))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"DONE Status received from id_number = %0d\n", lmcver.cb[cbinitiator_id1:cbinitiator_id2]);
$write(" Received TAG = %0d\n", lmcver.cb[cbtag1:cbtag2]);
$write(" WAIT_ON_TAG = %0d", wait_on_done_tag);
$display("\"");
end // if
end // if
end // if
if (lmcver.cb[cbdvalid_f]) begin
if ((!(msg_level < `debug_cb))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"DVALID Status received from id_number = %0d\n", lmcver.cb[cbinitiator_id1:cbinitiator_id2]);
$display("\"");
end // if
addr_str = lmcver.cb[cbmsg1:1126];
data_str = lmcver.cb[1127:cbmsg2];
addr_slv = addr_str;
data_slv = data_str;
return_data_addrv(addr_slv,data_slv);
end // if
end
endcase
if (!busy_f)
lmcver.cb_ack[ackack_val1:ackack_val2] <= #(0) `ack_rsp;
else
lmcver.cb_ack[ackack_val1:ackack_val2] <= #(0) `busy_rsp;
lmcver.cb_ack[ackinitiator_id1:ackinitiator_id2] <= #(0) lmcver.cb[cbinitiator_id1:cbinitiator_id2];
lmcver.cb_ack[acktarget_id1:acktarget_id2] <= #(0) lmcver.cb[cbtarget_id1:cbtarget_id2];
driving_cb_ack_f = `true;
end // if
end // if
end
endtask // receiver
//====================================--
// BEGIN CONTROLLER SECTION --
//====================================--
reg ctrl_init
; initial ctrl_init
= `true;
reg first_call_f
; initial first_call_f
= `true;
integer nest_level
; initial nest_level
= 0;
integer for_nest_level
; initial for_nest_level
= 0;
integer fh
;
integer endfile
;
reg rsp_strobe
; initial rsp_strobe
= 1'b0;
reg strobe_rsp_f
; initial strobe_rsp_f
= `false;
reg rsp_strobe_set
; initial rsp_strobe_set
= `false;
reg suspend_exe_f
; initial suspend_exe_f
= `false;
reg queue_overflow_f
; initial queue_overflow_f
= `false;
reg [1:1*8] curr_loop_var
; initial curr_loop_var
= "";
integer init_loop_val
; initial init_loop_val
= 0;
integer curr_loop_val
; initial curr_loop_val
= 0;
integer exit_val
; initial exit_val
= 0;
integer step_val
; initial step_val
= 0;
integer beg_loop_addr
; initial beg_loop_addr
= 0;
integer end_loop_addr
; initial end_loop_addr
= 0;
reg for_f
; initial for_f
= `false;
reg sequential_f
; initial sequential_f
= `false;
integer monitor_id
; initial monitor_id
= 0;
reg wait_on_f
; initial wait_on_f
= `false;
integer wait_on_val
; initial wait_on_val
= 0;
reg wait_on_node_f
; initial wait_on_node_f
= `false;
reg wait_on_node_val
; initial wait_on_node_val
= 1'b0;
reg wait_on_node_dummy
;
reg [1 : `token_size*8] exe_func_name
; initial exe_func_name
= "";
reg [1 : `token_size*8] curr_func_name
; initial curr_func_name
= "";
reg [1 : `token_size*8] seq_halt_func_name
; initial seq_halt_func_name
= "";
reg [1 : `max_cmd_size*8] tmp_str
; initial tmp_str
= "";
// type data_status_type is
parameter inactive = 0;
parameter active = 1;
parameter passed_val = 2;
// type data_table_element, [1:1088] = ([1:1024] name, [1025:1056] val, [1057:1088] status)
//type data_table_type is array(1 to 100) of data_table_element;
parameter addr_tbl_size = 100;
parameter var_tbl_size = 100;
integer var_tbl_counter
; initial var_tbl_counter
= 1;
integer addr_tbl_counter
; initial addr_tbl_counter
= 1;
reg [1 : 1088] var_tbl
[1 : var_tbl_size];
reg [1 : 1088] addr_tbl
[1 : addr_tbl_size];
initial begin
for (i = 1; i <= addr_tbl_size; i = i + 1) begin
var_tbl[i] = {nul_token,32'h0,32'h0};
addr_tbl[i] = {nul_token,32'h0,32'h0};
end // for
end
parameter stack_size = 20;
reg [31:0] returnto_stk
[1 : stack_size];
integer stack_pointer
; initial stack_pointer
= 0;
always @(posedge (wait_on_node_dummy === 1'b1)) begin
wait_on_node_val <= 1'b1;
end
//--------------------
// STACK PROCEDURES --
//--------------------
task push_stack;
input [31:0] stk_addr;
begin : loop_push
if (stack_pointer > stack_size) begin
$display("WARNING at %0t from %m", $time);
$display(" STACK IS FULL, CANNOT PUSH MORE THAN %0d", stack_size);
$display(" INCREASE \" stack_aize \"");
disable loop_push;
end // if
returnto_stk[stack_pointer+1] = stk_addr;
stack_pointer = stack_pointer + 1;
end
endtask // push_stack
task pop_stack;
output [31:0] stk_addr;
begin : loop_pop
if (stack_pointer < 1) begin
$display("WARNING at %0t from %m", $time);
$display(" STACK IS EMPTY, NOTHING TO POP OUT");
disable loop_pop;
end // if
stk_addr = returnto_stk[stack_pointer];
stack_pointer = stack_pointer - 1;
end
endtask // pop_stack
//-----------------------------
// Command Memory Procedures --
//-----------------------------
task build_cmd;
output [1:`max_cmd_size*8] ret_str;
input [1:`token_size*8] cmd_str;
input [1:`token_size*8] orig_str;
begin
case (cmd_str)
"func_end" : ret_str = {"func_end","(",orig_str,")",";"};
"declare_var" : ret_str = {"declare_var","(",orig_str,")",";"};
"call" : ret_str = {"call","(",orig_str,")",";"};
"assign_var" : ret_str = {"assign_var","(",orig_str,")",";"};
"func_beg" : ret_str = {"func_beg","(",orig_str,")",";"};
endcase
if ((!(msg_level < `debug_cmd_mem))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"BUILD_CMD: ret_str = %0s", ret_str);
$display("\"");
end // if
end
endtask // build_cmd
task set_addr_tbl_elmnt;
input [1:`token_size*8] name;
input [31:0] val;
output found;
integer i;
reg [1:`token_size*8] tmpname;
reg [1:1088] tmp_elmnt;
begin
tmpname = name;
begin : loop_set
if (addr_tbl_counter > addr_tbl_size) begin
$display("WARNING at %0t from %m", $time);
$write(" \"SET_ADDR_TBL_ELMNT: Array \"addr_tbl\" is full, increase \"addr_tbl_size\" parameter ");
$display("\"");
disable loop_set;
end // if
for (i = 1; i <= addr_tbl_size; i = i + 1) begin
tmp_elmnt = addr_tbl[i];
if (tmp_elmnt[1:1024] === tmpname) begin
if (tmp_elmnt[1057:1088] !== active) begin
bfm_msg("SET_ADDR_TBL_ELMNT: status of element is not active" ,`warnings,msg_level);
end // if
tmp_elmnt[1025 : 1056] = val;
found = `true;
addr_tbl[i] = tmp_elmnt;
disable loop_set;
end
else if (tmp_elmnt[1:1024] === nul_token) begin
//first empty location
tmp_elmnt[1:1024] = tmpname;
tmp_elmnt[1025:1056] = val;
tmp_elmnt[1057:1088] = active;
addr_tbl[i] = tmp_elmnt;
addr_tbl_counter = i;
found = `false;
disable loop_set;
end // if
end // loop
end // loop_set
end
endtask // set_addr_tbl_elmnt
task get_addr_tbl_elmnt;
//-- input addr_tbl
input [1:`token_size*8] name;
inout [31:0] val;
output found;
integer i;
reg [1:`token_size*8] tmpname;
reg [1:1088] tmp_elmnt;
begin
tmpname = name;
found = `false;
begin : loop_get
for (i = 1; i <= addr_tbl_size; i = i + 1) begin
tmp_elmnt = addr_tbl[i];
if (tmp_elmnt[1:1024] === tmpname) begin
if (tmp_elmnt[1057:1088] !== active) begin
bfm_msg("GET_ADDR_TBL_ELMNT: status of element is not active" ,`warnings,msg_level);
end // if
val = tmp_elmnt[1025:1056];
found = `true;
disable loop_get;
end // if
end // loop
if ((!(msg_level < `warnings))) begin
$display("WARNING at %0t from %m", $time);
$write(" \"GET_ADDR_TBL_ELMNT: %0s not found in table",tmpname);
$display("\"");
end // if
end // loop_get
end
endtask // get_addr_tbl_elmnt
task set_var_tbl_elmnt;
input [1:`token_size*8] name;
input [31:0] val;
output found;
integer i;
reg [1:`token_size*8] tmpname;
reg [1:1088] tmp_elmnt;
begin
tmpname = name;
begin : loop_set
if (var_tbl_counter > var_tbl_size) begin
$display("WARNING at %0t from %m", $time);
$write(" \"SET_VAR_TBL_ELMNT: Array \"var_tbl\" is full, increase \"var_tbl_size\" parameter ");
$display("\"");
disable loop_set;
end // if
for (i = 1; i <= var_tbl_size; i = i + 1) begin
tmp_elmnt = var_tbl[i];
if (tmp_elmnt[1:1024] === tmpname) begin
if (tmp_elmnt[1057:1088] !== active) begin
bfm_msg("SET_VAR_TBL_ELMNT: status of element is not active" ,`warnings,msg_level);
end // if
tmp_elmnt[1025:1056] = val;
found = `true;
var_tbl[i] = tmp_elmnt;
disable loop_set;
end
else if (tmp_elmnt[1:1024] === nul_token) begin
//first empty location
tmp_elmnt[1:1024] = tmpname;
tmp_elmnt[1025:1056] = val;
tmp_elmnt[1057:1088] = active;
addr_tbl[i] = tmp_elmnt;
var_tbl_counter = i;
found = `false;
disable loop_set;
end // if
end // loop
end // loop_set
end
endtask // set_var_tbl_elmnt
task get_var_tbl_elmnt;
//-- input var_tbl
input [1:`token_size*8] name;
inout [31:0] val;
output found;
integer i;
reg [1:`token_size*8] tmpname;
reg [1:1088] tmp_elmnt;
begin
tmpname = name;
found = `false;
begin : loop_get
for (i = 1; i <= var_tbl_size; i = i + 1) begin
tmp_elmnt = var_tbl[i];
if (tmp_elmnt[1:1024] === tmpname) begin
if (tmp_elmnt[1057:1088] !== active) begin
bfm_msg("GET_VAR_TBL_ELMNT: status of element is not active" ,`warnings,msg_level);
end // if
val = tmp_elmnt[1025:1056];
found = `true;
disable loop_get;
end // if
end // loop
if ((!(msg_level < `warnings))) begin
$display("WARNING at %0t from %m", $time);
$write(" \"GET_VAR_TBL_ELMNT: %0s not found in table",tmpname);
$display("\"");
end // if
end // loop_get
end
endtask // get_var_tbl_elmnt
task addelement;
//--inout cmd_mem
input [cbfield1:cbfield2] value;
output [31:0] idx;
output valid_f;
begin
valid_f = `true;
begin : loop_add
// check, whether we have space in the array
if ((cmd_mem_counter > initial_max_cmd_mem_size) && (!(msg_level < `warnings))) begin
$display("WARNING at %0t from %m", $time);
$display(" \"Internal Command Memory overflow while reading in command file/buffering remote commands;");
$display(" Internal memory size may be increased using the \" initial_max_cmd_mem_size \" parameter,");
$display(" Command file/buffer truncated, continuing simulation ...\"");
valid_f = `false;
disable loop_add;
end // if
cmd_mem[cmd_mem_counter + 1] = value;
cmd_mem_counter = cmd_mem_counter + 1;
idx = cmd_mem_counter;
end // loop_add
end
endtask // addelement
task get_mem_cmd;
output [ctrl_store1:ctrl_store2] retcmd;
input [31:0] cmd_addr;
output valid_get_f;
reg [cbfield1:cbfield2] tmp_msg;
begin
//get string at addr
//convert variables(compare to names in var_tbl) to actuals of current value
//call to_fm_data_in
valid_get_f = `false;
if ((cmd_addr <= max_cmd_mem_size) && (cmd_addr >= 1)) begin
tmp_msg = cmd_mem[cmd_addr];
if (tmp_msg[cbmsg1:cbmsg2] !== "") begin
valid_get_f = `true;
retcmd[cbfield1:cbfield2] = cmd_mem[cmd_addr];
cmd_mem_hold = cmd_mem[cmd_addr];
timing.to_fm_data_in(cmd_mem_hold[cbmsg1:cbmsg2], msg_level);
retcmd[fmfield1:fmfield2] = timing.wk_cmd;
end
else begin
bfm_msg("Attempted read of empty location in Command Memory, return to embedded mode" ,`warnings,msg_level);
end // if
end
else begin
if ((!(msg_level < `warnings))) begin
$display("WARNING at %0t from %m", $time);
$write(" \"Command Memory Address Out of Range, returning to embedded mode:\n");
$write(" Last Valid Address = %0d\n", max_cmd_mem_size);
$write(" Attempted Address = %0d", cmd_addr);
$display("\"");
end // if
end // if
end
endtask // get_mem_cmd
function exit_cond;
input [31:0] exit_val;
input [31:0] step_val;
input [31:0] curr_loop_val;
begin
if (step_val >= 0) begin
if (curr_loop_val > exit_val) exit_cond = `true;
else exit_cond = `false;
end else begin
if (curr_loop_val < exit_val) exit_cond = `true;
else exit_cond = `false;
end // if
end
endfunction // exit_cond
//-------------
// READ_FILE --
//-------------
//Side effects
//cmd_mem, load_mem_addr
//temp_cmd, tmp_str, curr_func_name
task read_file;
integer linen;
reg [1:`token_size*8] inline;
reg [1:`token_size*8] tmp_inline;
reg [(`token_size-1)*8:0] token_1;
reg status_f;
reg error_f;
integer plitype;
integer plisize;
reg found;
reg valid_f;
begin
linen = 0;
inline = "";
valid_f = `false;
found = `false;
if (!endfile) begin
begin : preload
while (!endfile) begin
inline = "";
tmp_inline = "";
$lmv_fgetcmd(fh, inline, error_f);
linen = linen + 1;
tmp_inline = (inline >> 4);
tmp_cb[cbmsg1:cbmsg2] = "";
tmp_cb[cbmsg1:cbmsg2] = (inline >> 4);
plitype = 3;
plisize = 0;
token_1 = "";
$lmv_tokenize(tmp_inline, 3, 0, token_1, status_f);
if (token_1 !== "") begin
if (nest_level === 0) begin
if (token_1 === "{") begin
nest_level = nest_level + 1;
end else begin
//build FUNC_BEGIN command
build_cmd(tmp_cb[cbmsg1:cbmsg2],"func_beg",token_1);
addelement(tmp_cb,load_mem_addr,valid_f);
if (!valid_f) begin
disable preload; //exit preload
end // if
set_addr_tbl_elmnt(token_1,load_mem_addr,found);
if (found) begin
bfm_msg("Duplicate function names in command file:\nOnly the last declared will be used", `warnings, msg_level);
end // if
curr_func_name = token_1;
end // if
end
else if (nest_level > 0 || sequential_f) begin
if (token_1 === "{") begin
nest_level = nest_level + 1;
end else if (token_1 === "}") begin
nest_level = nest_level - 1;
if (nest_level === 0) begin
build_cmd(tmp_cb[cbmsg1:cbmsg2],"func_end",curr_func_name);
if (! sequential_f) begin
addelement(tmp_cb,load_mem_addr,valid_f);
if (!valid_f) begin
disable preload; //exit preload
end // if
end
else begin
timing.to_fm_data_in(tmp_cb[cbmsg1:cbmsg2], msg_level);
temp_cmd[fmfield1:fmfield2] = timing.wk_cmd;
end // if
end // if
end else if (timing.is_command(token_1)) begin
timing.to_fm_data_in(tmp_cb[cbmsg1:cbmsg2], msg_level);
temp_cmd[fmfield1:fmfield2] = timing.wk_cmd;
if (! sequential_f) begin
if (temp_cmd[fmcode1:fmcode2] !== `null_cmd) begin //syntax okay
//store string
addelement(tmp_cb,load_mem_addr,valid_f);
if (!valid_f) begin
disable preload; //exit preload
end // if
if (temp_cmd[fmcode1:fmcode2] === `sequential_cmd) begin
disable preload; //exit preload;
end // if
end // if
end // if
end else begin
build_cmd(tmp_cb[cbmsg1:cbmsg2],"call",token_1);
if (! sequential_f) begin
addelement(tmp_cb,load_mem_addr,valid_f);
if (!valid_f) begin
disable preload; //exit preload
end // if
end
else begin
timing.to_fm_data_in(tmp_cb[cbmsg1:cbmsg2], msg_level);
temp_cmd[fmfield1:fmfield2] = timing.wk_cmd;
end // if
end // if
end // if
end // if
if (sequential_f) begin
disable preload; //exit preload;
end // if
$lmv_endfile(fh,endfile);
end // while
end // preload
if (nest_level !== 0) begin
if (! (sequential_f || (temp_cmd[fmcode1:fmcode2] === `sequential_cmd))) begin
bfm_msg("Syntax error in command file: Unmatched `{': Attempting to recover", `warnings, msg_level);
//attempt to recover by adding func_end command so sim won't blow up
max_cmd_mem_size = max_cmd_mem_size + 1;
//build FUNC_END command
build_cmd( tmp_cb[cbmsg1:cbmsg2],"func_end",curr_func_name);
addelement(tmp_cb,load_mem_addr,valid_f);
end // if
end // if
end // if
if (! (sequential_f || temp_cmd[fmcode1:fmcode2] === `sequential_cmd)) begin
if (msg_level >= `debug_cmd_mem) begin
bfm_msg("Command Memory Loaded, Contents = ", `debug_cmd_mem, msg_level);
begin: print_mem
integer i;
for (i=0; i<=cmd_mem_counter; i=i+1) begin
cmd_mem_hold = cmd_mem[i];
$display("%0s", cmd_mem_hold[cbmsg1:cbmsg2]);
end // loop
end // print_mem
end // if
end // if
end
endtask // read_file
// End Read File Declarations --
//=========================
// DEALLOCATE_CTRL_QUEUE ==
//=========================
task deallocate_ctrl_queue;
input [31:0] pointer;
input [31:0] size;
integer i;
begin
for (i = pointer; i <= size; i = i +1) begin
ctrl_queue[i] = ctrl_queue[i+1];
end // loop
ctrl_queue_size = ctrl_queue_size - 1;
end
endtask // deallocate_ctrl_queue
//---------
// QUEUE --
//---------
//Side effects
//queue_size, ctrl_queue_end
//new_cmd_f
task queue;
input [ctrl_store1:ctrl_store2] cmd; // ctrl_store_data
input [31:0] which_end; // default = end_of_queue
integer i;
begin
if (ctrl_queue_size === 0) begin //empty queue
new_cmd_f = `true;
ctrl_queue[ctrl_queue_size + 1] = cmd; // ctrl_queue[1]
ctrl_queue_size = ctrl_queue_size + 1; // ctrl_queue_size = 1
end
else begin //neither _end or _beg is null
if (which_end == end_of_queue) begin
ctrl_queue[ctrl_queue_size + 1] = cmd;
ctrl_queue_size = ctrl_queue_size + 1;
end
else begin
for (i = ctrl_queue_size; i >= 1; i = i - 1) begin // shift queue one location down
ctrl_queue[i+1] = ctrl_queue[i];
end // loop
ctrl_queue_size = ctrl_queue_size + 1;
ctrl_queue[1] = cmd;
end // if
end // if
if (cmd[fmcode1:fmcode2] > `max_user_immed_code) begin //must be "user_cycle" command
num_non_immed_queued = num_non_immed_queued + 1;
end // if
queue_size = queue_size + 1;
if ((!(msg_level < `debug_int))) begin
$display("NOTE at %0t from %m", $time);
$display(" \"QUEUE: cmd =%0d", (cmd[fmcode1:fmcode2]));
$write(" QUEUE: queue_size = %0d", queue_size);
$display("\"");
end // if
end
endtask // queue
task dequeue;
input [31:0] delete_cmd_code;
//Always dequeues at least the first command in queue
//Additionally, if delete_cmd_code /= null_cmd
//count number of occurances of delete_cmd in ctrl_queue,
//stop counting if a multi-cycle command (which is not delete_cmd) is reached
//if first location in queue has multi-cycle, ignore it to ensure its deletion
//this is for case where delete_cmd_code is set to read_continue during a read_cycle
//both the read_cycle and subsequent read_continue's should be deleted
//then loop through dequeue loop until this number of delete_cmd's are removed
//any zero-cycle commands between delete_cmd's will be removed
//At this point, three conditions may exist;
//if the queue contained only delete_cmd's and zero-cycle commands,
//the queue will be empty except for zero-cycle commands following the last delete_cmd
//if the queue contained a multi-cycle command (non-delete_cmd)
//the queue will maintain zero-cycle commands between the last delete_cmd
//and the multi-cycle command
reg [ctrl_store1:ctrl_store2] cmd_reg; //ctrl_queue_ptr
integer num_delete_cmds;
reg first_f;
integer tmp_queue_size;
integer tmp_ptr;
reg exit_search_f, exit_remove_cmd_f;
begin
num_delete_cmds = 0;
first_f = `true;
tmp_queue_size = ctrl_queue_size;
tmp_ptr = ctrl_queue_pointer;
exit_search_f = `false;
exit_remove_cmd_f = `false;
if (delete_cmd_code !== `null_cmd) begin
cmd_reg = ctrl_queue[tmp_ptr]; // ctrl_queue[1]
num_delete_cmds = 0;
begin: search
while (!exit_search_f) begin
if (tmp_queue_size === 0) begin
exit_search_f = `true; //exit search
end
else if (cmd_reg[fmcode1:fmcode2] > `max_user_immed_code) begin
if (cmd_reg[fmcode1:fmcode2] === delete_cmd_code) begin
num_delete_cmds = num_delete_cmds + 1;
end
else if (! first_f) begin
exit_search_f = `true; //exit search
end // if
end // if
cmd_reg = ctrl_queue[tmp_ptr+1];
first_f = `false;
tmp_ptr = tmp_ptr + 1;
tmp_queue_size = tmp_queue_size - 1;
end // while
end // search
end // if
begin: remove_cmd
while (!exit_remove_cmd_f) begin
ctrl_queue_hold = ctrl_queue[ctrl_queue_pointer];
if (ctrl_queue_hold[fmcode1:fmcode2] > `max_user_immed_code) begin //must be "user_cycle" command
num_non_immed_queued = num_non_immed_queued - 1;
if (ctrl_queue_hold[fmcode1:fmcode2] === delete_cmd_code) begin
num_delete_cmds = num_delete_cmds - 1;
end // if
end // if
if (ctrl_queue_size !== 0) begin //queue has at least 1 more command
deallocate_ctrl_queue(ctrl_queue_pointer, ctrl_queue_size);
end
else begin //no more commands
deallocate_ctrl_queue(ctrl_queue_pointer, ctrl_queue_size); //also deallocates _end "dangling"
end // if
queue_size = queue_size - 1;
if ((queue_size < max_ctrl_queue_size/2) && queue_overflow_f) begin
queue_overflow_f = `false;
end // if
if ((!(msg_level < `debug_int))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"DEQUEUE: removing command, queue_size = %0d", queue_size);
$display("\"");
end // if
if ((ctrl_queue_size === 0) || (num_delete_cmds <= 0))
exit_remove_cmd_f = `true; //exit remove_cmd when ctrl_queue_beg = null
// or num_delete_cmds <= 0;
//loop will execute once if delete_cmd = null_cmd, because num_delete_cmds will be 0
end // while
end // remove_cmd
end
endtask // dequeue
//----------------
// CLEAR_BUSY_F --
//----------------
//Side effects
//dspch_data, dspch_data_f,
//issued_busy_f
task clear_busy_f;
begin
if (issued_busy_f) begin
issued_busy_f = `false;
//signal dispatcher to broadcast ready message
dspch_data[cbinitiator_id1:cbinitiator_id2] = id_number;
dspch_data[cbtarget_id1:cbtarget_id2] = `cb_brdcst_id;
dspch_data[cbtransaction1:cbtransaction2] = `status_trans;
dspch_data[cbdone_f] = `false;
dspch_data[cbdvalid_f] = `false;
dspch_data[cbbuffer_avail_f] = `true;
dspch_data[cbmsg1:cbmsg2] = "";
dspch_data[cbtag1:cbtag2] = 0; //0 since broadcasting
//call dispatcher to queue dspch_data for dispatching
dspch_data_f = `true;
dispatcher;
end // if
end
endtask // clear_busy_f
//-------------------
// CHK_FOR_TRIGGER --
//-------------------
//Side effects
//exe_nxt_buf
//dspch_data, dspch_data_f,
//wait_on_f,suspend_exe_f,new_cmd_f
task chk_for_trigger;
begin
if (exe_nxt_buf_pointer !== 0) begin
exe_nxt_buf_hold = exe_nxt_buf[exe_nxt_buf_pointer];
if (wait_on_f) begin
if (exe_nxt_buf_hold[fmcode1:fmcode2] ===`trigger_cmd) begin
if ((exe_nxt_buf_hold[fmtvalue1:fmtvalue2] === wait_on_val) || (exe_nxt_buf_hold[fmtvalue1:fmtvalue2] === `blanket_tvalue)) begin
wait_on_f = `false;
suspend_exe_f = `false;
new_cmd_f = `true;
end else begin
if ((!(msg_level < `debug_3))) begin
$display("NOTE at %0t from %m", $time);
$display(" \"TRIGGER with incorrect TVALUE received during WAIT_ON execution,");
$display(" deleting command from exe_nxt_buf to avoid locking model\"");
cb2string(exe_nxt_buf_hold[cbfield1:cbfield2]);
end // if
end // if
end else begin
if ((!(msg_level < `debug_3))) begin
$display("NOTE at %0t from %m", $time);
$display(" \"non-TRIGGER command received during WAIT_ON execution");
$display(" deleting command from exe_nxt_buf to avoid locking model\"");
cb2string(exe_nxt_buf_hold[cbfield1:cbfield2]);
end // if
end //if
exe_nxt_buf_pointer = 0;
clear_busy_f;
end else begin
if (exe_nxt_buf_hold[fmcode1:fmcode2] === `trigger_cmd) begin
exe_nxt_buf_pointer = 0;
clear_busy_f;
bfm_msg("Model not waiting: Deleting TRIGGER from exe_nxt_buf buffer",`debug_3,msg_level);
end // if
end // if
end // if
end
endtask // chk_for_trigger
//-------------------
// CHK_EXE_NXT_BUF --
//-------------------
//Side effects
//exe_nxt_buf, ctrl_queue
//dspch_data, dspch_data_f,
//issued_busy_f, stop_queuing_f
task chk_exe_nxt_buf;
begin
if (exe_nxt_buf_pointer !== 0) begin
queue(exe_nxt_buf[exe_nxt_buf_pointer], beg_of_queue);
exe_nxt_buf_pointer = 0;
end // if
clear_busy_f;
end
endtask // chk_exe_nxt_buf
//-------------------
// CHK_WAIT_ON_NODE --
//-------------------
//Side effects
//wait_on_node_f,wait_on_node_val
//wait_on_f,suspend_exe_f,new_cmd_f
task chk_wait_on_node;
begin
if (wait_on_node_f) begin
if (wait_on_node_val === 1'b1) begin
wait_on_node_f = `false;
wait_on_f = `false;
suspend_exe_f = `false;
new_cmd_f = `true;
end // if
end // if
end
endtask // chk_wait_on_node
//---------------
// LOAD_QUEUE --
//---------------
//Side effects
//fm_rsp, rsp_strobe, strobe_rsp_f
//cmd_mem
task load_queue;
inout [31:0] curr_mem_addr;
input top_cmd_f; // default = `false
reg valid_get_f;
reg found;
reg new_top_cmd_f;
reg [ctrl_store1:ctrl_store2] lq_temp_cmd; // ctrl_store_data
reg exit_queuing_f;
begin
valid_get_f = `false;
found = `false;
new_top_cmd_f = top_cmd_f;
exit_queuing_f = `false;
bfm_msg("LOAD QUEUE" ,`debug_int,msg_level);
if ((!new_top_cmd_f) && (!wait_on_done_f) && (!wait_on_f)) begin
chk_exe_nxt_buf;
end // if
begin: queuing
while (!exit_queuing_f) begin
if (curr_mem_addr === 0 || new_top_cmd_f) begin //load commands from embedded (top-level entity)
if (new_top_cmd_f) begin
new_top_cmd_f = `false;
if (curr_mem_addr !== 0) begin
bfm_msg("Controller not expecting command from embedded" ,`warnings,msg_level);
end // if
//top is sending cmd - always accept,
//load_queue was called when fm_cmd.strobe'event
bfm_msg("LOAD QUEUE: Receiving command from top-level" ,`debug_int,msg_level);
lq_temp_cmd[cbfield1:cbfield2] = cb_field_local_cmd;
lq_temp_cmd[fmfield1:fmfield2] = fm_cmd;
queue(lq_temp_cmd, end_of_queue);
if (lq_delete_cmd_code !== `null_cmd) begin
if (lq_temp_cmd[fmcode1:fmcode2] > `max_user_immed_code) begin
if (lq_temp_cmd[fmcode1:fmcode2] === lq_delete_cmd_code) begin
//check for illegal condition signalled by get_nxt_cmd
if (lq_vfyn_f) begin
lq_vfyn_f = `false;
bfm_msg("LOAD_QUEUE: Illegal command sequence: Time-consuming statements within burst sequence;\n Some zero-cycle commands may have been incorrectly executed", `warnings, msg_level);
end // if
//command that was just queued should be deleted,
//command was queued prior to checking so that
//num_delete_cmds is counted properly in dequeue();
dequeue(lq_delete_cmd_code); //also deletes any previously queued zero-cycle commands
end
else begin
lq_delete_cmd_code = `null_cmd;
lq_vfyn_f = `false;
end // if
end // if
end // if
if (lq_temp_cmd[fmcode1:fmcode2] === `call_cmd) begin
exe_call(lq_temp_cmd[fmfunction_name1:fmfunction_name2], curr_mem_addr, cmd_src);
//if successful, changes curr_mem_addr, so signal not ready to top-level
end // if
end // if
if ((num_non_immed_queued < (pipeline_depth + 1)) && (queue_size < max_ctrl_queue_size)) begin
if (curr_mem_addr === 0) begin
//request next command from top
fm_rsp.ready <= #(0) `true;
bfm_msg("LOAD QUEUE: Signalling ready to top-level" ,`debug_int,msg_level);
strobe_rsp_f = `true;
exit_queuing_f = `true;
end
else begin
fm_rsp.ready <= #(0) `false;
bfm_msg("LOAD QUEUE: Signalling NOT ready to top-level" ,`debug_int,msg_level);
strobe_rsp_f = `true;
//(no exit, load from command memory)
end // if
end
else begin
fm_rsp.ready <= #(0) `false;
bfm_msg("LOAD QUEUE: Signalling NOT ready to top-level" ,`debug_int,msg_level);
This page: |
Created: | Thu Aug 19 12:01:57 1999 |
| From: |
../../../sparc_v8/system/lmc/rtl/pcislave_fm.v
|