strobe_rsp_f = `true;
exit_queuing_f = `true;
end // if
end
else begin : loop_queue //load from command memory
if ((num_non_immed_queued >= (pipeline_depth+1)) || (queue_overflow_f)) begin
exit_queuing_f = `true;
end
else begin
if (sequential_f) begin
//get next command from command file
bfm_msg("LOAD QUEUE: Reading command from command file; Sequential mode" ,`debug_int,msg_level);
$lmv_endfile(fh,endfile);
if (endfile) begin
bfm_msg("Syntax error in command file during sequential mode:\n The end of the command file was reached without properly terminating the program.\n Returning to embedded mode ",`warnings, msg_level);
curr_mem_addr = 0;
end
else begin
read_file; //sets temp_cmd
if (temp_cmd[fmcode1:fmcode2] !== `null_cmd) begin
queue(temp_cmd, end_of_queue);
if (lq_delete_cmd_code !== `null_cmd) begin
if (temp_cmd[fmcode1:fmcode2] > `max_user_immed_code) begin
if (temp_cmd[fmcode1:fmcode2] === lq_delete_cmd_code) begin
//must have first queued the command in question, 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;
end // if
end // if
end // if
if (queue_size === max_ctrl_queue_size) begin
queue_overflow_f = `true;
end // if
if (temp_cmd[fmcode1:fmcode2] === `func_end_cmd) begin
exe_func_end(temp_cmd[fmfunction_name1:fmfunction_name2], curr_mem_addr, cmd_src);
end // if
if (temp_cmd[fmcode1:fmcode2] === `call_cmd) begin
exe_call(temp_cmd[fmfunction_name1:fmfunction_name2], curr_mem_addr, cmd_src);
end // if
end // if
end // if
end
else begin
//get next command from command memory
bfm_msg("LOAD QUEUE: Retreiving command from command memory" ,`debug_int,msg_level);
get_mem_cmd(temp_cmd, curr_mem_addr, valid_get_f);
if (valid_get_f) begin
queue(temp_cmd, end_of_queue);
if (lq_delete_cmd_code !== `null_cmd) begin
if (temp_cmd[fmcode1:fmcode2] > `max_user_immed_code) begin
if (temp_cmd[fmcode1:fmcode2] === lq_delete_cmd_code) begin
//must have first queued the command in question, 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;
end // if
end // if
end // if
if (queue_size === max_ctrl_queue_size) begin
queue_overflow_f = `true;
end // if
if (temp_cmd[fmcode1:fmcode2] === `func_end_cmd) begin
exe_func_end(temp_cmd[fmfunction_name1:fmfunction_name2], curr_mem_addr, cmd_src);
end
else if (temp_cmd[fmcode1:fmcode2] === `sequential_cmd) begin
sequential_f = `true;
end
else begin
curr_mem_addr = curr_mem_addr + 1;
end // if
if (temp_cmd[fmcode1:fmcode2] === `call_cmd) begin
exe_call(temp_cmd[fmfunction_name1:fmfunction_name2], curr_mem_addr, cmd_src);
end // if
end
else begin
curr_mem_addr = 0;
end // if //invalid get warnings issued in get_mem_cmd
end // if
end // if
end // if
end // while
end // queuing
end
endtask // load_queue
//-------------
// DONE_CHKS --
//-------------
//Side effects
//dspch_data, dspch_data_f, temp_cmd
//dvalid_f, ret_data_ary, ret_data_ptr, ret_data_t, ret_val
task done_chks;
input [ctrl_store1:ctrl_store2] cmd;
reg [1:`slv_size] data_str;
reg [1:`slv_size] addr_str;
begin
// Status / Return Data
if (cmd[cbinitiator_id1:cbinitiator_id2] !== id_number) begin //command was received via Control Bus
//return status/data (if appl.)
if (cmd[cbnotify_f] || (dvalid_f && cmd[cbreturn_data_f])) begin
dspch_data[cbinitiator_id1:cbinitiator_id2] = id_number;
dspch_data[cbtarget_id1:cbtarget_id2] = cmd[cbinitiator_id1:cbinitiator_id2];
dspch_data[cbtransaction1:cbtransaction2] = `status_trans;
dspch_data[cbdone_f] = cmd[cbnotify_f];
if (dvalid_f && (cmd[cbreturn_data_f] === `true)) begin
dspch_data[cbdvalid_f] = `true;
data_str = ret_data_slv;
addr_str = ret_addr_slv;
dspch_data[cbmsg1:1126] = addr_str;
dspch_data[1127:cbmsg2] = data_str;
end
else begin
dspch_data[cbdvalid_f] = `false;
dspch_data[cbmsg1:cbmsg2] = "";
end // if
dspch_data[cbtag1:cbtag2] = cmd[cbtag1:cbtag2]; //return original tag
//call dispatcher to queue dspch_data for dispatching
dspch_data_f = `true;
dispatcher;
end // if
end
else begin //command was local command
if (dvalid_f) begin
//return data to top-level via ret_val
if (ret_data_t === $time) begin
//multiple return datum in same tick
//data always returned in same tick or different absolute time
if (ret_data_ptr < `ret_ary_len) begin
ret_data_ary_hold = ret_data_ary[ret_data_ptr];
ret_data_ary_hold[127:64] = ret_addr_slv;
ret_data_ary_hold[63:0] = ret_data_slv;
ret_data_ary[ret_data_ptr] = ret_data_ary_hold;
ret_data_ptr = ret_data_ptr + 1; //start appending at 1 (0 is for preceding non-immed)
end
else begin
ret_data_ptr = 0;
bfm_msg("Maximum number of elements in RET_VAL array has been exceeded.\n Remaining data to be returned will overwrite data already loaded ",`warnings, msg_level);
end
end
else begin
ret_data_t = $time;
ret_data_ary_hold = ret_data_ary[0];
ret_data_ary_hold[127:64] = ret_addr_slv;
ret_data_ary_hold[63:0] = ret_data_slv;
ret_data_ary[0] = ret_data_ary_hold;
ret_data_ptr = 1;
end // if
//pass data to top-level
if (ret_data_ptr === 0)
ret_val <= #(0) ret_data_ary[0];
else
ret_val <= #(0) ret_data_ary[ret_data_ptr-1];
end // if
end // if
// Compare Data (checks for "x" signifying no comparison)
if (dvalid_f) begin
if (cmd[fmcode1:fmcode2] !== `remote_cmd) begin //else return data was received via control bus
compare_data(cmd[fmexpected_data1:fmexpected_data2], ret_data_slv, ret_addr_slv);
end // if
end // if
// Generate Monitor Command
if (monitor_id !== 0) begin // 0 indicates no monitor model
dspch_data[cbinitiator_id1:cbinitiator_id2] = id_number;
dspch_data[cbtarget_id1:cbtarget_id2] = monitor_id;
dspch_data[cbtransaction1:cbtransaction2] = `cmd_trans;
dspch_data[cbbuffer_f] = `false;
dspch_data[cbnotify_f] = `false;
dspch_data[cbreturn_data_f] = `false;
dspch_data[cbmsg1:cbmsg2] = cmd[cbmsg1:cbmsg2]; //return original msg
if (dvalid_f) begin
end // if
dspch_data[cbtag1:cbtag2] = cmd[cbtag1:cbtag2]; //return original tag
//call dispatcher to queue dspch_data for dispatching
dspch_data_f = `true;
dispatcher;
end // if
dvalid_f = `false;
end
endtask // done_chks
//----------------
// EXE_FUNC_END --
//----------------
//Side effects
//returnto_stk
task exe_func_end;
input [1:`token_size*8] function_name;
inout [31:0] curr_mem_addr;
inout [31:0] cmd_src;
begin
pop_stack(curr_mem_addr);
if (curr_mem_addr === 0) begin
cmd_src = `embedded;
end // if
if (sequential_f) begin //function which contained sequential cmd has completed
//functions called while in seq mode reset this flag during exec. of function
sequential_f = `false;
end // if
if (function_name === seq_halt_func_name) begin
sequential_f = `true;
end // if
end
endtask // exe_func_end
//------------------------
// EXE_CALL DECLARATION --
//------------------------
//Side effects
//returnto_stk
task exe_call;
input [1:`token_size*8] function_name; // string
inout [31:0] curr_mem_addr;
inout [31:0] cmd_src;
reg found;
begin
found = `false;
if (first_call_f) begin
first_call_f = `false;
$lmv_openr(cmd_file, fh);
if (fh == 0) begin
if ((!(msg_level < `warnings))) begin
// $display("WARNING at time %t from %m",$time);
$display(" \"Cannot open COMMAND file %0s. No commands are preloaded!\"",cmd_file);
end // if
end
else begin
$lmv_endfile(fh,endfile);
read_file;
end // if
end // if
cmd_src = `cmd_memory;
push_stack(curr_mem_addr);
get_addr_tbl_elmnt(function_name, curr_mem_addr, found);
if (sequential_f) begin
seq_halt_func_name = function_name;
sequential_f = `false;
end // if
if (!found) begin
//return to previous addr
exe_func_end(function_name, curr_mem_addr,cmd_src);
if ((!(msg_level < `warnings))) begin
// $display("WARNING at %0t from %m", $time);
$write(" \"Illegal function call, function %0s not declared", function_name);
$display("\"");
end // if
end // if
end
endtask // exe_call
//------------------
// EXE_CTRL_IMMED --
//------------------
//Side effects
//dspch_data, dspch_data_f,
//excpt_f_ary
//msg_level
//wait_on_f, wait_on_val
//curr_mem_addr, load_mem_addr, cmd_src, tmp_str
task exe_ctrl_immed;
input [ctrl_store1:ctrl_store2] cmd;
reg tmp, ret_stat;
reg found;
reg valid_f;
begin
if ((!(msg_level < `debug_3))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"EXE_CTRL_IMMED: Executing = %0s", cmd2string(cmd[fmcode1:fmcode2]));
$display("\"");
end // if
valid_f = `false;
found = `false;
case (cmd[fmcode1:fmcode2])
`remote_cmd : begin
dspch_data[cbinitiator_id1:cbinitiator_id2] = id_number;
dspch_data[cbtarget_id1:cbtarget_id2] = cmd[fmtarget_id1:fmtarget_id2];
dspch_data[cbtransaction1:cbtransaction2] = `cmd_trans;
dspch_data[cbbuffer_f] = cmd[fmbuffer_f];
dspch_data[cbnotify_f] = cmd[fmnotify_f];
dspch_data[cbreturn_data_f] = cmd[fmreturn_data_f];
dspch_data[cbmsg1:cbmsg2] = cmd[fmmsg1:fmmsg2];
dspch_data[cbtag1:cbtag2] = cmd[cbtag1:cbtag2];
//holds orig tag if forwarding
//initialized to zero if not forwarding(dispatcher will assign)
//call dispatcher to queue dspch_data for dispatching
dspch_data_f = `true;
dispatcher;
if (cmd[fmnotify_f]) begin
wait_on_done_f = `true;
wait_on_done_tag = dspch_data[cbtag1:cbtag2]; //this is the value the dispatcher assigned to tag
end // if
end
`restart_cmd : begin
bfm_msg("Restart command not yet implemented" ,`warnings,msg_level);
end
`trigger_cmd : begin
if ((cmd[cbinitiator_id1:cbinitiator_id2] === id_number) && (cmd[cbtarget_id1:cbtarget_id2] === id_number)) begin //trigger originates in this model, broadcast trigger to others
dspch_data[cbinitiator_id1:cbinitiator_id2] = id_number;
dspch_data[cbtarget_id1:cbtarget_id2] = `cb_brdcst_id;
dspch_data[cbtransaction1:cbtransaction2] = `cmd_trans;
dspch_data[cbbuffer_f] = `false;
dspch_data[cbnotify_f] = `false;
dspch_data[cbreturn_data_f] = `false;
dspch_data[cbmsg1:cbmsg2] = {"trigger","(",cmd[fmtvalue1:fmtvalue2],")",";"};
dspch_data[cbtag1:cbtag2] = 0;
//holds orig tag if forwarding
//initialized to zero if not forwarding(dispatcher will assign)
//call dispatcher to queue dspch_data for dispatching
dspch_data_f = `true;
dispatcher;
end // if
end
`wait_on_cmd : begin
wait_on_f = `true;
wait_on_val = cmd[fmtvalue1:fmtvalue2]; //wait_on_f set when wait_on is dequeued
end
`print_msg_cmd : $display($time,,"%0s", cmd[fmmessage1:fmmessage2]);
`set_msg_level_cmd : msg_level = cmd[fmmlevel1:fmmlevel2];
`call_cmd : begin
end
`open_buffer_cmd : begin
//write func_beg_cmd, declare func_beg addr = load_mem_addr
build_cmd(tmp_cb[cbmsg1:cbmsg2],"func_beg",cmd[fmfunction_name1:fmfunction_name2]);
addelement(tmp_cb,load_mem_addr,valid_f);
if (!valid_f) begin
bfm_msg("Command memory FULL, New buffer can not be opened", `warnings, msg_level);
end // if
set_addr_tbl_elmnt(cmd[fmfunction_name1:fmfunction_name2],load_mem_addr,found); // addr_tbl
if (found) begin
bfm_msg("Duplicate function name already in command file:\nNewly declared buffer will be used for subsequent calls", `warnings, msg_level);
end // if
curr_func_name =cmd[fmfunction_name1:fmfunction_name2];
end
`close_buffer_cmd : begin
build_cmd(tmp_cb[cbmsg1:cbmsg2],"func_end",curr_func_name);
addelement(tmp_cb,load_mem_addr,valid_f);
if (!valid_f) begin
max_cmd_mem_size = max_cmd_mem_size + 1;
addelement(tmp_cb,load_mem_addr,valid_f);
end // if
end
`func_beg_cmd : begin
//sets local variables value to approp. tmp_var, and sets status to "passed_val"
//currently using only global variables, so this command is non-functional
end
`func_end_cmd : begin
//--return value, set status of local vars, return to parent addr
//--currently using only global variables, so this command only returns toparent addr
//command is executed when queued
end
`sequential_cmd : begin
end
`stop_sim_cmd : begin
$display("======================================================================");
$display("NOTE at time %t from %m",$time);
$display(" \" stop_sim command issued, simulation stopped immediately \"");
$display("======================================================================");
$finish;
end
`wait_on_node_cmd : begin
wait_on_node_dummy = 1'b0;
$lmv_wait_on(cmd[fmnode_name1:fmnode_name2],cmd[fmnode_value1:fmnode_value2],cmd[fmnode_mask1:fmnode_mask2],wait_on_node_dummy,ret_stat);
if (!ret_stat) begin // Change ret_stat non_zero, no_wait, event already occurred
wait_on_node_val = 1'b0;
wait_on_f = `true;
wait_on_node_f = `true;
end // if
end
default : begin
if ((!(msg_level < `warnings))) begin
$display("WARNING at %0t from %m", $time);
$write(" \"EXE_CTRL_IMMED: Received invalid command,code=%0s",cmd2string(cmd[fmcode1:fmcode2]));
$display("\"");
end // if
end
endcase
end
endtask // exe_ctrl_immed
//---------------
// CONTROLLER --
//---------------
//Operation
//this procedure performs controller operations other than:
// get_nxt_cmd, excpt_detected, return_data
//Side Effects
//ctrl_init
//curr_mem_addr
//rsp_strobe,strobe_rsp_f
//done_f_rcvd, wait_on_done_f, new_cmd_f
task controller;
begin
rsp_strobe_set = `false;
if (ctrl_init) begin
ctrl_init = `false;
load_queue(curr_mem_addr, `false);
if (strobe_rsp_f) begin
strobe_rsp_f = `false;
if (rsp_strobe_set != `true) begin
rsp_strobe_set = `true;
rsp_strobe = ~rsp_strobe;
fm_rsp.strobe <= #(0) rsp_strobe;
end // if
end // if
end // if
if (fm_cmd_strobe_event) begin
load_queue(curr_mem_addr,`true);
if (strobe_rsp_f) begin
strobe_rsp_f = `false;
if (rsp_strobe_set != `true) begin
rsp_strobe_set = `true;
rsp_strobe = ~rsp_strobe;
fm_rsp.strobe <= #(0) rsp_strobe;
end // if
end // if
end // if
if (done_f_rcvd) begin
done_f_rcvd = `false;
wait_on_done_f = `false;
suspend_exe_f = `false;
new_cmd_f = `true;
end // if
chk_for_trigger;
chk_wait_on_node;
if ((ctrl_queue_size === 0) && (! wait_on_done_f)) begin // empty and not waiting
if (exe_nxt_buf_pointer !== 0) begin
new_cmd_f = `true;
//only set flag here, queue using exe_nxt_buf data when get_nxt_cmd called
end // if
end // if
end
endtask // controller
//The following controller routines are called by the executer
//---------------
// GET_NXT_CMD --
//---------------
//Side Effects
//cmd_queue, ctrl_queue, num_non_immed_queued, queue_size
//new_cmd_f
//curr_cmd
task get_nxt_cmd;
integer i;
reg exit_f;
begin
exit_f = `false;
//peforms necessary end-of-command operations
//dispatches status,return data, and monitor commands
//removes completed command from queue
//checks the exe_nxt_buf buffer for a command
//loads queue as necessary
//executes next command if it is an immediate command,
//else exits get_nxt_cmd after updating curr_cmd
bfm_msg("GET_NXT_CMD" ,`debug_int,msg_level);
begin : get_nxt
while (!exit_f) begin
if ((!suspend_exe_f) && (ctrl_queue_size !== 0) &&
(lq_delete_cmd_code !== `null_cmd) && (num_non_immed_queued === 0)) begin
//time-consuming statements are among burst and queue contains zero-cycle commands
//which may be incorrectly executed
//set flag so load_queue can verify/warn
lq_vfyn_f = `true;
end // if
if ((!new_cmd_f) && (!suspend_exe_f) && (ctrl_queue_size !== 0)) begin
//This section of code is normally entered after execution of each command
//purpose is to perform end-of-command operations and delete command from queue
//not new_cmd_f ensures that the first command in the queue has been executed
//not suspende_exe_f ensures that command execution has not been suspended
// this could be due to either a wait_on command,
// a remote dispatched with notify_f set true or
// wait_on_node command
//ctrl_queue_size !== 0 ensures that the queue is not empty
//perform end-of-command operations
done_chks(ctrl_queue[ctrl_queue_pointer]);
//dispatches status,return data, and monitor commands
suspend_exe_f = (wait_on_f | wait_on_done_f);
//dequeue command(s)
//current command always deleted
//modeler may specify additional commands to be deleted through delete_cmd_code variable
//if delete_cmd_code != `null_cmd, all subsequent delete_cmd's are removed until a different
//multi-cycle command is reached. Any zero-cycle commands between delete_cmd's are removed
dequeue(delete_cmd_code);
if ((num_non_immed_queued === 0) && (delete_cmd_code !== `null_cmd)) begin
//load_queue should continue to delete incoming delete_cmd's
if (lq_delete_cmd_code !== `null_cmd) begin
//modeler has set delete_cmd again before controller reset lq_delete_cmd_code
//modeler may have called get_nxt_cmd multiple times in same time iteration
//(along with setting delete_cmd_code each time)
bfm_msg("Model has overlapping requests to delete burst sequences;\n New request only is serviced", `warnings, msg_level);
end // if
lq_delete_cmd_code = delete_cmd_code;
if ((ctrl_queue_size !== 0) && (num_non_immed_queued === 0)) begin
//time-consuming statement in embedded command sequence
//residual zero-cycle's in queue will be executed
//if next multi-cycle received from top is delete_cmd, a warning is issued from load_queue
//set flag here to notify load_queue of potential illegal condition
lq_vfyn_f = `true;
end
else begin
lq_vfyn_f = `false; //ensures that for external file mode, flag is reset
end // if
end // if
delete_cmd_code = `null_cmd;
end // if
//fill queue if necessary
load_queue(curr_mem_addr, `false);
//execute next command if immediate else exit procedure
ctrl_queue_hold = ctrl_queue[ctrl_queue_pointer];
if ((ctrl_queue_size !== 0) && (! wait_on_done_f) && (!suspend_exe_f)) begin
if (new_cmd_f) begin
new_cmd_f = `false;
end // if
if (ctrl_queue_hold[fmcode1:fmcode2] <= `max_ctrl_immed_code) begin
exe_ctrl_immed(ctrl_queue_hold); //in controller section
end else if (ctrl_queue_hold[fmcode1:fmcode2] <= `max_auto_immed_code) begin
exe_auto_immed(ctrl_queue_hold[fmfield1:fmfield2]); //in tool-gen m.s. section
end else if (ctrl_queue_hold[fmcode1:fmcode2] <= `max_user_immed_code) begin
exe_user_immed(ctrl_queue_hold[fmfield1:fmfield2]); //in executer section
end
else begin
//load pipeline commands
temp_cmd_ptr = ctrl_queue_pointer;
for (i = 0; i <= pipeline_depth-1; i = i + 1) begin
if (ctrl_queue_size !== 0) begin
ctrl_queue_hold = ctrl_queue[temp_cmd_ptr];
cmd_queue[i] = ctrl_queue_hold[fmfield1:fmfield2];
temp_cmd_ptr = temp_cmd_ptr + 1;
end
else begin
cmd_queue[i] = timing.fm_data_in_init;
end // if
end // loop
//copy cmd_queue(0) to curr_cmd
curr_cmd = cmd_queue[0];
exit_f = `true;
end // if
end
else begin //empty
for (i = 0; i <= pipeline_depth-1; i = i + 1) begin
cmd_queue[i] = timing.fm_data_in_init;
end // loop
curr_cmd = cmd_queue[0];
exit_f = `true;
end // if
end // while
end // get_nxt
if (strobe_rsp_f) begin
strobe_rsp_f = `false;
if (rsp_strobe_set != `true) begin
rsp_strobe_set = `true;
rsp_strobe = ~rsp_strobe;
fm_rsp.strobe <= #(0) rsp_strobe;
end // if
end // if
if ((!(msg_level < `debug_3))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"GET_NXT_CMD: Exiting, new command =%0s", cmd2string(curr_cmd[incode1:incode2]));
$display("\"");
end // if
end
endtask // get_nxt_cmd
//---------------
// RETURN_DATA --
//---------------
//Side Effects
//ret_data_slv
//dvalid_f
task return_data_b;
input rdata;
begin
if ((!(msg_level < `debug_3))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"RETURN_DATA: data = %H", rdata);
$display("\"");
end // if
ret_data_mask = 64'hffffffffffffffe;
ret_data_slv = 64'hxxxxxxxxxxxxxxxx;
ret_data_slv[0] = rdata;
dvalid_f = `true;
end
endtask // return_data_b
task return_data_v;
input [63:0] rdata;
begin
if ((!(msg_level < `debug_3))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"RETURN_DATA: data = %H", rdata);
$display("\"");
end // if
ret_data_mask = 64'h0;
ret_data_slv = rdata;
dvalid_f = `true;
end
endtask // return_data_v
task return_data_addrb;
input [63:0] addr;
input rdata;
begin
if ((!(msg_level < `debug_3))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"RETURN_DATA:\n");
$write(" address = %H\n", addr);
$write(" data = %H", rdata);
$display("\"");
end // if
ret_addr_slv = addr;
ret_data_mask = 64'hffffffffffffffe;
ret_data_slv = 64'hxxxxxxxxxxxxxxxx;
ret_data_slv[0] = rdata;
dvalid_f = `true;
end
endtask // return_data_addrb
task return_data_addrv;
input [63:0] addr;
input [63:0] rdata;
begin
if ((!(msg_level < `debug_3))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"RETURN_DATA:\n");
$write(" address = %H\n", addr);
$write(" data = %H", rdata);
$display("\"");
end // if
ret_addr_slv = addr;
ret_data_mask = 64'h0;
ret_data_slv = rdata;
dvalid_f = `true;
end
endtask // return_data_addrv
//====================================--
// END CONTROLLER SECTION --
//====================================--
//====================================--
// BEGIN DISPATCHER SECTION --
//====================================--
//-----------------------------
//Dispatcher Declarations -----
//-----------------------------
reg [cbfield1:cbfield2] dspch_queue
[0 : `dspch_queue_page_size-1]; // control_bus_type
reg [cbfield1:cbfield2] dspch_queue_hold
; // control_bus_type
integer in_dspch_q_ptr
; initial in_dspch_q_ptr
= 0; // first empty location
integer out_dspch_q_ptr
; initial out_dspch_q_ptr
= 0; // location to be output
reg dspch_q_empty
; initial dspch_q_empty
= `true;
integer dspch_tag
; initial dspch_tag
= 0;
integer active_target_id
; initial active_target_id
= 0;
integer ack_srch_ct
; initial ack_srch_ct
= 0; //num.of attempts to find cb_ack
reg check_cb_ack_f
; initial check_cb_ack_f
= `false;
reg wait_on_ack_f
; initial wait_on_ack_f
= `true;
reg released_cb_f
; initial released_cb_f
= `true;
integer wait_on_avail_t
; initial wait_on_avail_t
= 0 * `time_scale_multiplier;
reg driving_cb_f
; initial driving_cb_f
= `false;
reg check_cb_ack_event
;
always @(check_cb_ack) begin
check_cb_ack_event = `true;
check_cb_ack_event <= #(0) `false;
end
//---------------------------
// Dispatcher Procedures ----
//---------------------------
task queue_dspch;
input [cbfield1:cbfield2] dspch_data; // control_bus_type
begin : dspch_loop
if (in_dspch_q_ptr >= `dspch_queue_page_size) begin
if (out_dspch_q_ptr !== 0) begin
in_dspch_q_ptr = 0;
end
else begin
bfm_msg("Dispatcher Queue Overflow: Dispatch data not queued for output" ,`warnings,msg_level);
disable dspch_loop; // return
end // if
end // if
if ((!(msg_level < `debug_3))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"QUEUE_DSPCH: Initiator %0d", id_number);
$write(" : Storing data to be dispatched, location = %0d", in_dspch_q_ptr);
$display("\"");
end // if
dspch_queue[in_dspch_q_ptr] = dspch_data;
in_dspch_q_ptr = in_dspch_q_ptr + 1;
end // dspch_loop
endtask // queue_dspch
task dequeue_dspch;
begin
if (out_dspch_q_ptr !== in_dspch_q_ptr) begin
out_dspch_q_ptr = out_dspch_q_ptr + 1;
if (out_dspch_q_ptr === `dspch_queue_page_size) begin
out_dspch_q_ptr = 0;
if (in_dspch_q_ptr === `dspch_queue_page_size) begin
//in ptr hasn't been reset, but queue is empty
in_dspch_q_ptr = 0;
end // if
end // if
end
else begin
bfm_msg("DEQUEUE_DSPCH: Error in dispatcher's queue" ,`warnings,msg_level);
end // if
end
endtask // dequeue_dspch
//---------------
// Dispatcher --
//---------------
task dispatcher;
integer temp_time;
reg [cbfield1:cbfield2] t_dspch_queue;
begin
begin : loop_dispatcher
//queue dispatch data if necessary
if (dspch_data_f) begin
dspch_data_f = `false;
if ((dspch_data[cbtransaction1:cbtransaction2] === `cmd_trans) && (dspch_data[cbtag1:cbtag2] === 0)) begin
dspch_data[cbtag1:cbtag2] = dspch_tag;
dspch_tag = dspch_tag + 1;
end // if
queue_dspch(dspch_data);
disable loop_dispatcher; // return
end // if
//monitor Control Bus activity
if (cb_initiator_id_event) begin
if ((lmcver.cb[cbinitiator_id1:cbinitiator_id2] === id_number) && (driving_cb_f)) begin
//this model just became owner of Control Bus, release now so message is valid for 1 tick
driving_cb_f = `false;
lmcver.free_bus(id_number);
lmcver.cb[cbinitiator_id1:cbinitiator_id2] <= #(0) `cb_release_id;
check_cb_ack_f = `true;
active_target_id = lmcver.cb[cbtarget_id1:cbtarget_id2];
check_cb_ack <= #(0) ~check_cb_ack;
if ((!(msg_level < `debug_cb))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"DISPATCHER: Initiator %0d: Message on CB, Release CB",id_number);
$display("\"");
end // if
end // if
end // if
if ((check_cb_ack_event) && (check_cb_ack_f)) begin
t_dspch_queue = dspch_queue[out_dspch_q_ptr];
if ((!(msg_level < `debug_cb))) begin
$display("NOTE at %0t from %m", $time);
$write(" \"DISPATCHER: Initiator %0d: Check # %0d", id_number, (ack_srch_ct+1));
$write(" for response to message w/ TAG = %0d\n", t_dspch_queue[cbtag1:cbtag2]);
$display(" initiator_id = %0d", lmcver.cb_ack[ackinitiator_id1:ackinitiator_id2]);
$display(" target_id = %0d", lmcver.cb_ack[acktarget_id1:acktarget_id2]);
$write(" ack_val = %0s", cbackval2string(lmcver.cb_ack[ackack_val1:ackack_val2]));
$display("\"");
end // if
//check response
if (((lmcver.cb_ack[ackinitiator_id1:ackinitiator_id2] === id_number) && (lmcver.cb_ack[acktarget_id1:acktarget_id2] === active_target_id))
|| (active_target_id === `cb_brdcst_id)) begin
check_cb_ack_f = `false;
ack_srch_ct = 0;
//valid response (assumed for broadcast)
if ((lmcver.cb_ack[ackack_val1:ackack_val2] === `ack_rsp) || (active_target_id === `cb_brdcst_id)) begin
//message accepted (assumed for broadcast)
dequeue_dspch;
bfm_msg("Message was received by Target(s)" ,`debug_cb,msg_level);
end else if (lmcver.cb_ack[ackack_val1:ackack_val2] === `busy_rsp) begin
//save message for resending
wait_on_avail_f = `true;
dspch_queue_hold = dspch_queue[out_dspch_q_ptr];
wait_on_avail_id = dspch_queue_hold[cbtarget_id1:cbtarget_id2];
wait_on_avail_t = $time;
bfm_msg("Target responded with BUSY" ,`debug_cb,msg_level);
end else if (lmcver.cb_ack[ackack_val1:ackack_val2] === `unknown) begin
//error, for bus conflict, resolution outputs id's = 0, so target must have output `unknown'
if ((!(msg_level < `debug_cb))) begin
$display("WARNING at %0t from %m", $time);
$write(" \"DISPATCHER: Initiator %0d :Received UNKNOWN acknowledge",id_number);
$display("\"");
end // if
end else if (lmcver.cb_ack[ackack_val1:ackack_val2] === `Release) begin
//not a possible comb. due to resolution (if ack_val = release, id's = 0)
if ((!(msg_level < `debug_cb))) begin
$display("WARNING at %0t from %m", $time);
$write(" \"DISPATCHER: Initiator %0d :Received RELEASE acknowledge",id_number);
$display("\"");
end // if
end // if
end
else begin
//improper response, ignore and keep looking for ack upto max_ack_srch
if (ack_srch_ct >= (`max_ack_srch-1)) begin
if ((!(msg_level < `debug_cb))) begin
$display("WARNING at %0t from %m", $time);
$write(" \"DISPATCHER: CB_ACK check timeout expired, No valid response to message:\n");
$write(" Message deleted from dispatch queue");
$display("\"");
end // if
check_cb_ack_f = `false;
ack_srch_ct = 0;
dequeue_dspch;
end else begin
ack_srch_ct = ack_srch_ct + 1;
check_cb_ack <= #(0) ~check_cb_ack;
end // if
end // if
end // if
temp_time = ($time - wait_on_avail_t);
if ((wait_on_avail_f) && (temp_time >= `max_wait_on_avail_t)) begin
if ((!(msg_level < `debug_cb))) begin
$display("WARNING at %0t from %m", $time);
$write(" \"DISPATCHER: Wait_on_avail timeout expired, Target not available for message:\n");
$write(" Message deleted from dispatch queue");
$display("\"");
end // if
wait_on_avail_f = `false;
dequeue_dspch;
end // if
if (in_dspch_q_ptr === out_dspch_q_ptr) dspch_q_empty = `true;
else dspch_q_empty = `false;
if (ack_srch_ct !== 0) wait_on_ack_f = `true;
else wait_on_ack_f = `false;
//output dispatch data if possible
if ((!dspch_q_empty) && (lmcver.cb[cbinitiator_id1:cbinitiator_id2] === `cb_release_id) && (!driving_cb_f)
&& (!wait_on_avail_f) && (!wait_on_ack_f) && (!check_cb_ack_f)) begin
//attempt dispatch
driving_cb_f = `true;
lmcver.request_bus(id_number);
lmcver.cb[cbinitiator_id1:cbinitiator_id2] = lmcver.winner_id;
if (lmcver.cb[cbinitiator_id1:cbinitiator_id2] === id_number) begin
//?? lmcver.cb <= #(0) dspch_queue[out_dspch_q_ptr];
lmcver.cb = dspch_queue[out_dspch_q_ptr];
end else begin
driving_cb_f = `false;
end // if
if ((!(msg_level < `debug_cb))) begin
$display("WARNING at %0t from %m", $time);
$write(" \"Initiator %0d: Driving cb with dispatch queue location %0d",id_number,out_dspch_q_ptr);
$display("\"");
cb2string(dspch_queue[out_dspch_q_ptr]);
end // if
end // if
end // loop_dispatcher
end
endtask // dispatcher
//====================================--
// END DISPATCHER SECTION --
//====================================--
//====================================--
// BEGIN EXECUTER SECTION --
//====================================--
parameter cmd_queue_depth = pipeline_depth;
reg init
; initial init
= `true;
//**--**--**--**--**--**--**--**-- Executer Declarations USER CODE BEGIN
//-------------------------------
//-------------------------------
// Enter user variables here --
//-------------------------------
//-------------------------------
parameter max_commands = 30;
reg [31:0] new_cmd_buffer
[max_commands*5-1:0];
integer buffer_ptr
; initial buffer_ptr
= 0;
integer buffer_cnt
; initial buffer_cnt
= 0;
// type tm_event cmd_states
parameter sready = 0;
parameter terminate = 1;
parameter terminate_first = 2;
parameter d_delay = 3;
parameter ready_first = 4;
parameter ddelay_first = 5;
parameter abort = 6;
parameter abort_first = 7;
// type abort_state_type
//parameter abort = 0;
parameter waiting = 1;
// type snoop_states
parameter snp_standby = 0;
parameter snp_busy = 1;
parameter snp_clean = 2;
parameter snp_hit_mod = 3;
// type req_space_type
parameter io_space = 0;
parameter mem_space = 1;
parameter cfg_space = 2;
parameter iack_space = 3;
parameter spc_space = 4;
parameter no_space = 5;
// type dir_type
parameter write = 0;
parameter read = 1;
// type delay_cnt_type is array (`max_burst_len : 1) of integer range 0 : 15;
// type termination_style
parameter with_data = 0;
parameter without_data = 1;
// type slave_states
parameter sidle = 0;
This page: |
Created: | Thu Aug 19 12:02:00 1999 |
| From: |
../../../sparc_v8/system/lmc/rtl/pcislave_fm.v
|