Full Library / Resource / Smart_Resource / Smart_Controller
Block Name: Smart_Controller
Code File Location: VisualSim/actor/lib/Smart_Controller
List of custom methods available in Smart_Controller: Smart_Controller_Methods
o This is a subset of the Smart_Controller and works in conjunction with the Queue Blocks.
o This provides the logic and arbitration to pop the Queue.
The Smart_Controller (SC) accepts data structures on the input ports, processes a sequence of C-like code and outputs an integer value on the pop_output to trigger the Queue. The Queue associated with this block is listed in the parameter called "Smart_Resource_Name". This parameter can be used in the code without entering the actual Queue name, thus enabling this block to be reused in multiple instances. The data structure can arrive at the ports or via virtual connections to the block. All the data structures are placed in an input queue in the order of arrival. The blocks are executed in order of arrival. When the data structure executing arrives at a TIMEQ, GTO (END) or completes the execution sequence, the next one is started up. Each arriving data structure is assigned the name of the arriving port or "virtual", if from a virutal connection. The name of the data structure is used to identify the port that it arrived at. In the code, the currently executing data structure is named "port_token".
The sequence of code can utilize the incoming data structures field, variable (local, global and variable-defined inside this block), RegEx language and parameter values. Using the virtual connection methodology, the VM can use the built-in RegEx functions to send the Data Structures to Virtual Connection, SystemResource and other Smart_Controller blocks. The block has a set of standard functions, a set of specific methods and resource definition, and the complete RegEx language.
To access the code, Right-click on the block and select "Open Block".
Note: Any Script block code located in the VS_AR/VisualSim/actor directory cannot be edited and saved. If you need to edit these files, save it in a different directory within the CLASSPATH and define it as a new Class.
Script, and Smart_Controller now support cancellation of TIMEQ and WAIT events. There are both Block commands (CANCEL()) and RegEx commands (cancelEvent()), which are similar in operation. Details below.
The block can be self-triggered (Self_Start = true as a block parameter) or triggered by an incoming data structure (either ports or virtual connections). The code then executes in sequence. A WAIT in the code creates a blocking operation and prevents any further execution of any data structure until the time has elapsed. One can add additional ports on the input/output. Smart_Controller now supports both local and global virtual input/output. The input ports will be processed using an "OR" approach, meaning one at a time. The SEND function will send the required values to the output ports.
Parameter_Name Parameter_Value Description
Path none path to block, can include "VS/" to be generic
Read_File none name of script.txt, using above path
Save_Files false save parsed script, using above path
Profile_File none profile file name, "MyProfile.txt", for example
Listen_to_File none output listen to block to a file, "MyListenToFile.txt", for example
Duplicate_Input true duplicate incoming data structure, if single input and output, can improve performance
Profile 0 profile script as an array of instructions executed by Virtual Machine, useful for estimating algorithm perf.
Maximum_Loops 10000000 maximum loops in a while loop, million default, some models may need a larger value.
Block_Reference Block_Name Block_Reference is used to define a unique Virtual_Machine block (Block_Path + Block_Name)
Port_Order_Array {"input"} VM block will add user added fields internally, else user can define order of reading here
Add_Scheduler_Times_to_DS false default is false, no scheduler times added, or stats. Set to true for all QUEUE, TIMEQ statistics
To learn the application, view the Smart_Controller working in conjunction with the Queue model.
The Smart Controller works like a function block in C programming or script. The simple logic expressions use a C/C++ syntax. Following are few differences:
Following are the coding functions:
The above mentioned codes are explained in detail as follows:
1. LABEL: An identifier to denote a specific address in the code. This can be used to send the DS to continue processing from a particular point in the code. The format is:
LABEL:Name and is used as GTO ("Name")
Virtual_Machine, Virtual_Machine_Untimed, Smart_Controller now sends to LABEL: by adding to the input queue, instead of generating a 0.0 event. The previous method would place multiple send to LABEL: data structures in correct order. This update improves performance, and in correct sequence for this use model.
2. If, else if, else: This is a traditional if condition. The format is:
if (<conditional statement>)
{
<true statements>
}
else if (<conditional statement>)
{
<true statements>
}
else
{
<false statements>
}
3. Single line if-else: This is a single line if-else statement. The format is:
<conditional statement> ? <true statement> : <false statement>
This is used where a field or memory is updated based on a condition or a data flow is routed based on a field at a threshold.
4. SWITCH, CASE Statement: This is similar to C format with some differences. The format is:
SWITCH (port_token.ID) { /* Decodes ID integer field of Transaction */
CASE: 0
<RegEx statements>
GTO (END) /* Exit from script */
CASE: DEFAULT /* Last CASE, unlike C code, must be DEFAULT */
<RegEx statements>
GTO (END) /* Exit from script */
}
5. While: This operates in a loop and terminates when a condition is reached. This is commonly used to conduct a repetitive search, or loop through a sequence of operation for each index in an array or fragment. The format is:
while (true) /* Loop */
{
Remain_Bytes = readField(port_token, Bytes_Remaining_Field) /* Down Counter */
WAIT (Time_Between_Fragments) /* Delay */
}
6. CALL, RETURN: This function is used to call a common piece of code. The port_token in the current flow, before the CALL, must be a data structure. It cannot be a Scalar, Boolean or String type. The format is CALL (Name). The NAME is a LABEL. At the end of the routine, the token must encounter a RETURN and this returns the control to the next line after the CALL in the calling code. Any actions within this routine that jumps out (example: GTO(END)), will prevent the token from returning to the original caller. This means that the lines following the CALL function will not be executed. If there is a TIMEQ within the called routine, the token used in the TIMEQ must be port_token, else an error will be generated. The CALL function stalls the current thread and start executing the called function. When a TIMEQ is encountered in the Called thread, the next item in the input queue starts executing. The code beyond the CALL function does not execute until the return from the called function.
6. CALL, RETURN: This function is used to call a common piece of code. The port_token in the current flow, before the CALL, must be a data structure. It cannot be a Scalar, Boolean or String type. The format is CALL (Name). The NAME is a LABEL. At the end of the routine, the token must encounter a RETURN and this returns the control to the next line after the CALL in the calling code. Any actions within this routine that jumps out (example: GTO (END)), will prevent the token from returning to the original caller. This means that the lines following the CALL function will not be executed. If there is a TIMEQ within the called routine, the token used in the TIMEQ must be port_token, else an error will be generated. The CALL function stalls the current thread and start executing the called function. When a TIMEQ is encountered in the Called thread, the next item in the input queue starts executing. The code beyond the CALL function does not execute until the return from the called function.
7. CANCEL: This function is used to cancel an event already scheduled. The following are supported for TIMEQ = “MyTimeq” in Virtual_Machine, Smart_Controller block:
result = CANCEL (“MyTimeq”) // cancels first event for MyTimeq
result = CANCEL (“MyTimeq”, Event_ID) // cancels event with Event_ID > 0, user can copy DSs in TIMEQ to obtain Event_ID field
result = CANCEL (“MyTimeq”, Time) // cancels first event with simulation Time = t, user needs to know when event fires. Event_Time field contains time.
If result from CANCEL is greater than 0.0, then event was successfully removed, else event not found. If an event is successfully removed, then it is removed from VM block event queue, TIMEQ by name, immediate Digital, and top Digital. Event_ID will delete a specific event by ID, Time will delete async events by time, equal to Event_Time field. All TIMEQ by name will use the same Event_ID mechanism, and all will be unique IDs.
The following are supported for WAIT, TIMEQ in another Virtual_Machine, Smart_Controller block:
result = CANCEL (“RemoteBlockName”, “wait”) // cancels first, only event for WAIT
result = CANCEL (“RemoteBlockName”, “MyTimeq”) // cancels first event for MyTimeq
result = CANCEL (“RemoteBlockName”, “MyTimeq”, Event_ID) // cancels event with EventID > 0, user can copy DSs in TIMEQ to obtain Event_ID field
result = CANCEL (“RemoteBlockName”, “MyTimeq”, Event_Time) // cancels first event with simulation Time = t, user needs to know when event fires.
LHS of expression can be block variable, or port token with a field. ‘result’ is the default variable, and if no ‘=’ sign then result of CANCEL will be placed in ‘result’. If result from CANCEL is greater than 0.0, then event was successfully removed, else event not found. There are three RegEx commands that can be executed from Processing, Decision, VM blocks:
public static double cancelEvent(String block_name, String name) { ... }
public static double cancelEvent(String block_name, String name, int evt_id) { ... }
public static double cancelEvent(String block_name, String name, double time) { ... }
User does need the name of the block for RegEx commands. In addition, user can schedule from an event from their own block by using this method to DEDirector:
public void fireAt(Actor actor, int evt_id, double time) { ... }
where user can provide a unique ID for this specific actor. This event can then be cancelled by using this method to DEDirector:
public boolean cancelAt(Object actor, int evt_id, double time) { ... }
If the return is true, then the event was cancelled, else it could not be found. If the id == 0, then the time will be used to delete the first event at ‘time’.
8. EXIT or GTO(END): These function are equivalent statements to end or exit a running Virtual_Machine thread.
In the Smart_Controller, convenience functions to facilitate delays, sending to specific ports, and block defined queues have been added. The following are functions specific to the Smart_Controller block. In addition, the entire RegEx language can be used in the code.
The above mentioned codes are explained in detail as follows:
WAIT: This is a delay and holds the Virtual_Machine from operating on any data structure until the time has expired. The WAIT is used for blocking delay, meaning no other statements will execute, till the WAIT() completes. If the WAIT refers to a string "MyEvent", then it will wait on an EVENT. If the WAIT refers to a clock_hertz as an integer or long, then it will wait for the specific clock time.
SEND: SEND (<port name>or <virtual_connection> or <label>, <token expression>)
o This method can send to a port, virtual connection, another Smart_Controller or to a LABEL. The first two are to send the data structure out of this block, the latter to create a thread.
o Port_name identifies the output destination.
o Token_expression is the value to be output. This can be a string, RegEx operation or a token.
o The send to LABEL creates a new Thread within the Smart_Controller that can be executed parallelly.
For Example:
SEND (output, port_token)
The <port name> can have the following options: port name of this block, port_token.field_name where the destination is in the field of the data structure, name of another Virtual Machine block in the model, Destination of a IN or MUX block and a LABEL of the current block.
The output value can be the port_token, any memory name, field in a memory or a data structure field.
The output value can be of any data type.
SEND: SEND (<port name>or <virtual_connection>, <token expression>, <delay>)
o This method can send to a port, virtual connection with a delay. Delay can be a double, block variable, or block variable with a field
SEND (output, port_token, 1.0)
SEND (output, port_token, delay)
SEND (output, port_token, BlkVar.field)
SEND supports (X.field, Y.field, Z.field) field arguments in a block variable.
o Port_name identifies the output destination.
o Token_expression is the value to be output. This can be a string, RegEx operation or a token.
QUEUE: QUEUE (<queue name>, <token>, <priority>, <queue operation>)
This stores the token in the Queue in a FIFO method. The queue is reordered based on the priority of the incoming token.
The format is "QUEUE (queue_one, port_token, 1, "put").
The attributes are:
o queue_name is an unique identifier. Every queue will have an unique name. This is a string.
o Token is the item that needs to be stored in the queue.
o Priority is used to reorder the queue. This can be a field, memory or a value. This is an integer.
o Queue_operation can be "put" or "pop". put puts the token into the queue and the pop takes it out. The item must be within " ".
The queue information is accessed with getBlockStatus:
getBlockStatus (Smart_Controller Name, QUEUE_name, <option>, int Index)
o Usage: wr_data = getBlockStatus (VM1, "Cache_Access", "stats", 0).
o The LHS is a memory that contains the result of the getBlockStatus operation.
o Smart_Controller_Name is the Block_Name of the Smart_Controller containing the QUEUE. This is a string in "".
o QUEUE_name is the queue for which the options are accessed. This is a string in "".
o The options are "copy" (based on the Index number), "stats" (to get the current stats if index=1 and reset stats if index=-1), "length" (to get the current queue length) and "take" (remove the position in the queue based on index value).
o Index is an integer value. For "copy", this is position in the queue. For "stats", this gets the stats (1) or resets the stats (-1). For length, this is not used but a value must be present. For "take", this is the position in the queue.
QUEUE does not require fixed formats, indicating that all the arguments are for the Just In Time (JIT) compiler. This simplifies script creation and reduces model construction time. The list of newly supported formats is given below:
QUEUE (“MyQueueName”, “copy”)
QUEUE (“MyQueueName”, “length”)
QUEUE (“MyQueueName”, “stats”)
QUEUE (“MyQueueName”, “get”)
QUEUE (“MyQueueName”, “pop”)
The QUEUE need not be declared before use, as the “length” will create a new QUEUE if one does not exist. In the short format, "copy" applies to the first element in the queue. Prior versions of the fixed formats are supported, and will not impact prior models. QUEUE "copy", "length", "get", "pop", "take" operations will also place the queue length in the block memory "length". This is useful if a "pop" is performed, the "length" is automatically available.
TIMEQ: TIMEQ (<queue name>, <token>, <priority>, <queue operation>, <delay expression>)
o This stores the token in a queue in a FIFO fashion, delays it when it comes to the head of the queue and then sends it to the next line to execute. The queue is reordered based on the priority of the incoming token.
o Events can be scheduled internal to the Smart_Controller using the TIMEQ much like a Timed Queue.
o Several TIMEQs can be executed in parallel without effecting the delay of other TIMEQs.
o The format is "TIMEQ (timequeue_one, port_token, 1, "non_block", port_token.A_Delay).
The attributes are:
o queue_name is an unique identifier. Every queue will have an unique name. This is a string.
o Token is the item that needs to be stored in the queue.
o Priority is used to reorder the queue. This can be a field, memory or a value. This is an integer.
o Queue_operation is "non_block". This is default and it means that the Smart_Controller can continue executing while the other items waiting in the Queue.
In the latest version of the block, "non_block" is the assumed mode of operation.
o Delay_expression is service time for the token when it reaches the head of the queue.
The queue information is accessed with getBlockStatus:
getBlockStatus (Smart_Controller Name, TIMEQ_name, <option>, int Index)
o Usage: wr_data = getBlockStatus (VM1, "Cache_Access", "stats", 0)
o The LHS is a memory that contains the result of the getBlockStatus operation.
o Smart_Controller_Name is the Block_Name of the Smart_Controller containing the TIMEQ. This is a string in "".
o TIMEQ_name is the queue for which the options are accessed. This is a string in "".
o The options are "copy" (based on the Index number), "stats" (to get the current stats if index=1 and reset stats if index= -1), "length" (to get the current queue length) and "take" (remove the position in the queue based on index value).
o Index is an integer value. For "copy", this is position in the queue. For "stats", this gets the stats (1) or resets the stats (-1). For length, this is not used but a value must be present. For "take", this is the position in the queue.
TIMEQ does not require fixed formats, indicating that all the arguments are for the Just In Time (JIT) compiler. This simplifies script creation and reduces model construction time. The list f newly supported formats is given below:
TIMEQ (“MyTimeqName”, “copy”)
TIMEQ (“MyTimeqName”, “length”)
TIMEQ (“MyTimeqName”, “stats”)
TIMEQ (“MyTimeqName”, port_token, 0, 1.0)
TIMEQ need not be declared before use, as the “length” will create a new TIMEQ if one does not exist. Note that the “non_block” argument is no longer needed for the last TIMEQ statement. Prior versions of the fixed formats are supported, and will not impact prior models. If the TIMEQ refers to a string "MyEvent", then it will wait on an EVENT. If the TIMEQ refers to a clock_hertz as an integer or long, then it will wait for the specific clock time. Refer to section Model Event. TIMEQ "copy", "length", "non_block", "set", "take" operations will also place the queue length in the block memory "length". This is useful if a "non_block" is performed, the "length" is automatically available.
TIMEQ (“MyEvent")
TIMEQ (“MyTimeqName”, port_token, 0, round (1.0E06 * Clock_Speed_Mhz))
TIMEQ should not precede LABEL: BEGIN as it will be interpretted as the earlier notation, and cause the TIMEQ to begin executing BEGIN. One can add GTO (END) before LABEL: BEGIN to cause the TIMEQ thread to exit.
(1) ++, -- applies to single variables only, not functions. Below are some ++ examples, which also apply to --:
++MyInt // integer
++MyLong // long
++MyDouble // double
++MyDS.MyIntField // data structure integer
++MyDS.MyLongField // data structure long
++MyDS.MyDoubleField // data structure double
++MyArr(index) // array with int, long, double elements
The most common use is for loop indexes. Here is an example:
This works:
Idx = 0
while (Idx < 10) {
SEND (output, Idx)
++Idx
}
This does not work:
Idx = 0
while (++Idx < 10) { // cannot have ++ increment inside a conditional
SEND (output, Idx) // or function, just single variables
}
(2) +=, -=, *=, /=, %= applies to single and double values only. Note: That this functional cannot have a expression on the RHS. If you do so, you will get erroneous results. Here are some += examples, which also apply to -=, *=, /=, %=:
MyInt += MyInt2 // integer
MyLong += MyLong2 // long
MyDouble += MyDouble2 // double
MyString += MyString2 // string
MyInt += MyInt2 + MyInt3 // integer (2)
MyLong += MyLong2 + MyLong3 // long (2)
MyDouble += MyDouble2 + MySouble3 // double (2)
MyString += MyString2 + MyString3 // string (2)
These expressions are used in loops, conditional statements. The RHS cannot contain functions, just single variables.
(3) Address is a keyword that will obtain the current script address and save as a variable. This is useful for executing Scheduler blocks from a Virtual_Machine by setting a field to address + 2, and computed GTO (port_token.Address). A scheduler will return to the port_name ‘scheduler’. With this mechanism one can process multiple Schedulers with returns in a single Virtual_Machine. Here is an example:
LABEL: BEGIN
if (port_name == scheduler) { // from Scheduler
GTO (port_token.Address)
}
else {
port_token.Address = address + 2
// to Scheduler, scheduleTask in RegEx documentation
result = scheduleTask(port_token,"MyRTOS",Cmd_In,Idx_In*Cycle_t,TNow,Pri_In,ID,false)
EXIT
LABEL: Return_Here
// continue
}
EXIT
The current executing data structure is called port_token. The data structure arriving on a port is identified by the port, while a virtual input is identified as "virtual". To access the field of a memory or port_token, use the standard format of port_token.field_name, memory_name.field_name and parameter.field_name. Port name is used for making a control decision. For example, the port_name could be used as the SWITCH (port_name). Port name can also be used in a if-else as a test to see the source or origination.
VM blocks updated to check if a Parameter is on LHS of an expression in VM JIT compiler. Also, applies to Optional_Parameters text window, a parameter as name of Optional_Parameter. Also added a check of parameters being written to during a simulation by placing in WARNING VisualSimConsoleLog.txt log file. Memory_Init also checks for paramters as names of Global or Local memories.
Script, Virtual_Machine_Untimed, Smart_Controller memory now supports a flag to indicate it is a parameter, and if the key is written to, meaning LHS of expression, then a warning is issued to the VisualSimConsoleLog.txt file. In addition, if a parameter is placed on the LHS of an expression, then it will throw an exception indicating one is trying to update a parameter, which should be constant throughout a simulation. Top Digital checks parameter conflicts with Global, Local memory and parameters after 1000 events, and if any conflicts are found, a warning is issued to the modelVisualSimConsoleLog.txt file.
There is a new RegEx function to enable tracing of Script, Smart_Controller, local and global variable. This update allows for turning on/off trace, where the flag set to true enables tracing, false turns it off. In UtilityFunctions:
public boolean setTrace (String trace_name, boolean flag) { ... }
The trace_name can be “memory” to trace global, local memory. So the user can selectively listen to memory by turning flag on or off. In the VM blocks, the flag sets:
Listen_to_File = flag;
So, user can selectively listen to file by turning flag on or off. Listen_to_File parameter works as before, if setTrace is not used. setTrace will send Listen_to_File to the VisualSimTraceLog.txt file. trace_name is the name of the specific VM block, useful for DI cases. If setTrace is not used, then the Optional_Parameters work as before defining Listen_to_File. User can send to this trace file without above setTrace, using RegEx myTrace (trace_name, trace) only, just like myWarning. readAndClearTrace() is another RegEx funtion that reads the current trace file, and clears the current one. This is useful for tracing specific areas, and obtaining the current trace and saving to a separate file, using writeFile(file_name, string) RegEx command.
In the Script, Virtual_Machine_Untimed, Smart_Controller, ExpressionList, Reference name to a variable (local or global) can be created. This capability is important where the name of the memory is composed of multiple strings concatenated together. In these blocks,
Ref_Mem = readMemory(“GlobalMemoryName”)
is a reference to the GlobalMemoryName location. When Ref_Mem is updated, GlobalMemoryName is updated. To access the memory in a new variable, use
Ref_Mem = newToken(readMemory(“GlobalMemoryName”)).
There are newly supported memory reference formats that are faster and have the ability to access local, global, and block level memory.
Ref_Mem = ("GlobalMemoryName").read()
port_token.MyField = port_token.get(Channel_Field_Name)
Ref_Mem = (local_memory + "LocalMemoryName").read()
Ref_Mem = ("BlockMemoryName").read("Block_Name")
("GlobalMemoryName").check()
(local_memory + "LocalMemoryName").check()
("BlockMemoryName").check("Block_Name")
The last three can be used to first check if the memory exists before reading it.
There are newly supported memory references for write operation for local, global, and block level memory. The variable local_memory is a keyword that references the local memory.
("GlobalMemoryName").write(MyToken)
(local_memory + "LocalMemoryName").write(MyToken)
("BlockMemoryName").write("Block_Name", MyToken)
Writing to these memory locations will alter any memory references previously executed.
Note: If you place the GlobalMemoryName or the Ref_Mem on the LHS of an equation and have an assignment on the RHS, the reference is lost and the two will behave like independent memory variables.
For example, this is correct:
Ref_Mem = readMemory (“GlobalMemoryName”)
Ref_Mem.incr()
Other_Memory = Ref_Mem + 2
This is incorrect and will delink the memory.
Ref_Mem = readMemory (“GlobalMemoryName”)
Ref_Mem = Ref_Mem.incr() /* This creates a new space and the reference is lost */
GlobalMemoryName = Ref_Mem + 2 /* This delinks the original reference *.
Most Smart Controller code operate as a single sequence or thread. It is possible to create model Threads that can execute in parallel. The process to create a Thread is to define a LABEL:”Name” followed by a sequence of code that stands by itself. This will be a continuous loop in most cases. The main thread flow will start this new thread by calling it using the SEND operation. The format is SEND (Label_Name, value). The port_token is normally the best value to be sent out. When the SEND function is called, it starts the new Thread but does not start executing it immediately. When the executing Thread goes to a TIMEQ or a GTO (END) or completes the code execution for a port_token, then the new Thread starts executing as a synchronous (0.0 time event).
Self_Start: If the user adds "Self_Start" to the block parameters and sets the value to true, then the Virtual_Machine will begin to execute at time 0.0. This mode does not require any input to arrive on the ports to begin execution. Use only LABEL:BEGIN or Self_Start but not both. If both are used that will result in two triggers to the block.
Initialize variables: All execution lines prior to the LABEL:BEGIN are considered as initialization and will execute once at the start of the simulation. They will not execute after that. You can use only LABEL:BEGIN or Self_Start but not both. If both are used, then you will get two triggers to the block.
Accessing statistics of Model Resources: The getBlockStatus is the easiest way to get access to the statistics, length, first token in the queue and remove the first item in a queue.
Format: getBlockStatus(Resource_Name, <option>, int Index)
Usage: wr_data = getBlockStatus(Sched_1, "stats", 0)
o The LHS is a memory that contains the result of the getBlockStatus operation.
o Resource_Name is the Scheduler or Smart_Resource Block_Name. This is a string in "".
o The options are "copy" (gets the head of the queue for the Queue and not available for the Scheduler), "stats" (current stats if index=1 and reset stats if index= -1for both the Queue and SystemResource), "length" (get the current queue length for the Queue and SystemResource) and "take" (remove the head of the queue for the Queue).
o Index is an integer value. For "copy", this is the queue for the Queue. For "stats", this gets stats (1) or resets the stats (-1) for both the Queue and SystemResource. For length, this is the queue number of the Queue and needs any value for the SystemResource. For "take", this is the is the queue number of the Queue.
The length of the Queue is an array of multiple queue and is accessed a lot within the Script to make a decision. To accelerate the access, the length of a specific queue inside the Queue can be accessed as
Smart_Resource_Name+"_"+Length(Queue Number)
You can get the entire array by
Smart_Resource_Name+"_"+Length
This will contain an extra value in index 0 which is not used. The queue number to index start at 1.
For example, this would be
Queue_Length = Smart_Resource_1_Length(10)
where Smart_Resource_1 is the name and we are looking for the 10th queue.
Some Parameters of the Virtual_Machine are not shown and must be added. These parameters are not normally modified in a model. The internal parameters include:
Max_Queue_Length (64): This applies to each QUEUE, TIMEQ, and Input_Queue and must be a binary value, 128, 256.
Number_of_Queues (256): This applies to number of individual QUEUE and TIMEQ.
Add_Scheduler_Times_to_DS (false): Used to add fields to incoming data structure: TIME_ACTIVATION, TIME_RELEASE, TIME_FINISH, TIME_RESPONSE, TIME_IN_SYSTEM. Refer to Scheduler documentation for more details on these field values.
Maximum_Loops (1000000): This applies to a while loop without a WAIT or TIMEQ function being encountered.
Read_File: This is a file name that contains the code when it needs to be read from a file. This approach is preferred when the code needs to be modified between simulation runs. The code is not in the block but is written in a separate text file. If the Path parameter is available, then block searches in the directory, else in $VS directory. This is file name with a .txt extension.
Save_Files: This is a boolean used to save the compiled file in a location specified by the Path parameter of this block or the $VS directory. This parameter used to speed up the compile time. This is used when there are 100's of instances of the Virtual Machine or Smart_Controller. If this value is true, then the file is saved. The first time the code is compiled, it is written to a file. The next time around the delta is compared and if there is no change, the code is not recompiled.
Profile_File: This is a file name that contains a profile of the script execution. It lists the number of times the statement executed and the average time per execution, plus the script statement. If a statement does not execute, then the number will be zero, the time will be zero. This provides a "code coverage" view of the script execution. If the Path is set, then this file will be found in the same path.
Listen_to_File: This is a file that is identical to the "Listen to Block" except it is written to a designated file name. If the Path is set, then this file will be found in the same path.
Path: This applies to the Read_File, Save_Files, Profile_File, and Listen_to_File options. This path is used to save the compiled files, profile file, listen to file; and for reading a code file.
For small scripts, less than 30 lines, right click the Virtual_Machine block and select Listen to Block. Checkout the RegEx statement while execution. To debug larger scripts enable the option Single_Cycle and set the block parameter Breakpoint to an expression that evaluates to true. The most common “Breakpoint” expression is TNow >= 1.0, or a user simulation time. One can also set the “Breakpoint” expression equal to a specific address, such as
TNow >= 1.0 && address == 10
This expression will stop on statement 10, if the Simulation time TNow >= 1.0. Everytime the Run/Resume is pushed, the next script line will execute. In addition, Block_Memories will be displayed prior to the execution of each Single_Cycle statement, so one can checkout the values.
Before each execution statement in Single_Cycle mode, one can see the following (typical) output:
Block Memories:
self_start : false
port_token : {BLOCK="Transaction_Source",DELTA=0.0,DS_NAME="Header_Only",ID=1,INDEX=0,TIME=1.0E-10}
port_name : input
local_memory : BEGIN_Thread_Model3.
length : 1
input : {BLOCK="Transaction_Source",DELTA=0.0,DS_NAME="Header_Only",ID=1,INDEX=0,TIME=1.0E-10}
address : 27
TStop : 10.0
TResolution : 1.0E-10
TNow : 1.0E-10
Expression (27 ) : LABEL: BEGIN
Result : "No Result for Expression"
The Script Profiler is embedded in the block execution and keeps track of the number of times a statement executes and also the average time the statement took to execute down to the nano-second level. This feature provides all users with the detailed execution information about his/her script. In addition, it provides the script address, and the script statement associated with that address. If the number of times executed equals 0, then this provides feedback on whether a certain function even executed. This may be useful information, sometimes referred to as code coverage in lower level verification testing.
Profile_File: The Script Profiler can be turned on by adding a parameter to the Virtual_Machine and Smart_Controller block called “Profile_File”. This identifies the name of the file to be generated by the profiler. If the parameter does not exist, or is set to “none”, then the Script Profiler will be turned off. A typical Profile_File, Block_Name + “_Profiler.txt”.
Path: One can place the entire path in “Profile_File” variable, or add the “Path” variable. A typical path, “C:/VisualSim/Profiles”.
The Listen to File is a text based version of listen to block, one just enters a parameter in the block.
Listen_to_File: The Listen to File can be turned on by adding a parameter to the Virtual_Machine and Smart_Controller block called “Listen_to_File”. This identifies the name of the file to be generated. If the parameter does not exist, or is set to “none”, then Listen to File will be turned off. A typical Listen_to_File value is Block_Name + “_Listen_to_File.txt”.
Path: One can place the entire path in “Listen_to_File” variable, or add the “Path” variable. A typical path is “C:/VisualSim/Listen_to_Files”.
Create a new Token from the VisualSim/data folder:
MyToken = newToken ("Processor_DS")
MyArray = newToken ("{100:0}")
Create a new Memory or Field:
port_token.A_New_Field = Field_Value
newMemory ("MyNewMemory", Memory_Value)
("MyNewMemory").write(Memory_Value)
where Field_Value or Memory_Value can be a parameter or block level memory.
Check if Data Structure contains field:
if (port_token.containsRecordTokenLabel("A_Command"))
{
port_token.RIO_Command = port_token.A_Command + "_" + Block_Name
}
Read a Memory or Field and insert into a field of port_token:
port_token.MyField = readField(port_token, Channel_Field_Name)
port_token.MyField = port_token.get(Channel_Field_Name)
port_token.MyField = readMemory("MyMemory", Memory_Field_Name)
port_token.MyField = (("MyMemory").read()).get(Memory_Field_Name)
where Channel_Field_Name or Memory_Field_Name can be a parameter or block level memory.
Throw a model exception, stop the simulation:
throwMyException (Block_Name + " has a Channel value that is inconsistent.")
Send statement to the Command Line (debug is block memory flag), do not stop the simulation:
debug ? sendToCommandLine (Block_Name + " next Cache Prefetch (" + C_Prefetch.ID + ") \t@ " + formatTime(TNow)) : Tnow
Array processing for 1D operations incrementing, decrementing values; removing head, tail; and searching.
(MyArray(index)).incr() or (MyArray(index)).decr() can be used for block level arrays, or references to local, global arrays. Returns updated value.
MyArray.removeHead() removes from position 0. MyArray.removeTail() removes from last position. Useful for queue-like operations.
MyArray.search(matching_token, starting_index) will return the index of the first matching token, whether integer, long, double, or string.
MyArray.firstGreaterThanZero(starting_index) will return the first index greater than zero, whether integer, long, double.
Array processing for 2D operations incrementing, decrementing values.
MyArrayArray.incrementArrayArrayElement(index, index2) increments the specific element.
MyArrayArray.decrementArrayArrayElement(index, index2) decrements the specific element.
Format Time:
formatTime(TNow)
------ 25.43410 us ------
Identify a Architectural Library Hello Message and add a new device to the Routing Table:
if (port_token.A_Destination == Architecture_Name)
{
addToRoutingTable(Architecture_Name, port_token.A_Source, Block_Name, port_token.A_Hop) /* Src, Des, Hop, Port */
}
using the Processor_DS or one might simply pass the hello message. If A_Destination != Architecture_Name (parameter), then this can be the non-hello message flow.
A Model Event is similar to a time event, except generated by the user, and can occur at any time between blocks. In other words, a model condition triggers a Model Event for synchronizing between blocks, or within clock-driven processes. The most common use is to generate clocks from a single block to multiple blocks waiting for a clock event. Model Events can be generated from any RegEx block using the following RegEx function:
newEvent (“MyEvent”)
A newly supported format that is faster than newEvent for any RegEx block:
("MyEvent").event()
One can also place it an expression, and it will return true if a WAIT() is pending, else false.
The argument of newEvent must evaluate to a string name. The string argument can be composed of newEvent(MyParameter + “_MyEvent”) notation for events inside a hierarchical block. This function can be applied in Processing, Decision, Virtual_Machine or Smart_Controller Blocks. The Virtual_Machine and Smart_Controller blocks also support the following syntax which executes locally on the Virtual_Machine or Smart_Controller block.
EVENT (“MyEvent”)
This notation is preferred over the newEvent() RegEx notation, since it is significantly faster. In a corresponding Virtual_Machine or Smart_Controller block, the user needs a matching syntax as follows:
WAIT (“MyEvent”)
This statement will continue processing on the next statement once it receives a newEvent() or EVENT(). If the newEvent() or EVENT() is generated before the WAIT() on event, characterized as a string argument, then the WAIT() will immediately go to the next statement. Finally, if two newEvent()’s or EVENT()’s are generated prior to a WAIT (“MyEvent”) only one will execute similar to an ‘OR’ of pending events. This is done to prevent the unintentional build up of events in a model, that may not execute as expected.
The Virtual_Machine (VM) blocks can now support blocking or non-blocking events. Blocking event WAIT() does not allow any other statements to execute, till the WAIT() continues. Non-blocking event TIMEQ does allow other statements to execute. A blocking event can be called by the following statement:
WAIT (“My_Event_Name”)
A non-blocking event can be called by the following statement:
TIMEQ (“My_Event_Name”)
The difference between the two types of events is that the blocking WAIT (“My_Event_Name”) will not allow any other actions in the block, until an EVENT(“My_Event_Name”) is called, whereas the non-blocking TIMEQ(“My_Event_Name”) will allow the block to process other inputs or events, prior
to receiving an EVENT (“My_Event_Name”).
The WAIT (time) function and TIMEQ (…,time) functions have been expanded to include a clock synchronization feature. Currently, the argument ‘time’ can be a double value, meaning the WAIT() or TIMEQ() will wait that amount of time, once it begins execution. If ‘time’ is represented as and integer or long, then these statements will interpret ‘time’ as the clock speed in Hertz. This means that the delay will be based on the current simulation time and when the next clock cycle occurs. If the ‘time’ argument is 1, then this means every 1.0 second a clock will occur. If the statement is executes at 0.0 sec, then the WAIT() or TIMEQ() will complete at 1.0 sec, or one clock cycle later. If the statement executes at 0.5 sec, then the WAIT() or TIMEQ() will complete at 1.0 sec, or the next clock time. In other words, the clock synchronization feature synchronizes execution with this clock rate.
The TIMEQ also supports the clock synchronization feature.
Here is an example script to generate clocks within a model, using Virtual_Machine blocks:
/* Clock_Generator_Block VM */
Speed_Hertz = round (1.0E06 * Speed_Mhz)
LABEL: Loop
WAIT (Speed_Hertz)
if (Block_A_Ready) { /* No clock if not ready */
EVENT (“Block_A_Clock”) /* Trigger Block_A_Clock */
}
if (Block_B_Ready) { /* No clock if not ready */
EVENT (“Block_B_Clock”) /* Trigger Block_B_Clock */
}
GTO (Loop)
LABEL: BEGIN
/* Block_A Script, Clock Loop portion VM */
LABEL: Clock_Loop
...
WAIT (“Block_A_Clock”) /* Event from Clock_Generator_Block */
...
GTO (“Clock_Loop”)
/* Block_B Script, Clock Loop portion VM */
LABEL: Clock_Loop
...
WAIT (“Block_B_Clock”) /* Event from Clock_Generator_Block */
...
GTO (“Clock_Loop”)
For example, Block_A_Ready and Block_B_Ready are user generated Boolean values in a model that can mimimize clock events for blocks that have nothing to process.
Another way to generate clocks for Block_A or Block_B may be to enable the clock when it needs to process some data. In this case, the WAIT (Next_Cycle) would appear in the functional blocks, while the enable would be generated from a newEvent() or EVENT() in the same block or external block.
/* Source_Block requesting processing */
....
EVENT (“Request_Processing_on_Next_Clock”) /* Trigger Block_A, Block_B */
....
/* Block_A Script, Clock Loop portion */
Speed_Hertz = round (1.0E06 * Speed_Mhz)
LABEL: Clock_Loop
WAIT ("Request_Processing_on_Next_Clock") /* Event from Source_Block */
WAIT (Speed_Hertz ) /* Proper Clock Boundary */
....
if (Processing_Not_Done) {
EVENT (“Request_Processing_on_Next_Clock”)
}
GTO (“Clock_Loop”)
/* Block_B Script, Clock Loop portion */
Speed_Hertz = round (1.0E06 * Speed_Mhz)
LABEL: Clock_Loop
WAIT ("Request_Processing_on_Next_Clock") /* Event from Source_Block */
WAIT (Speed_Hertz ) /* Proper Clock Boundary */
....
if (Processing_Not_Done) {
EVENT (“Request_Processing_on_Next_Clock”)
}
GTO (“Clock_Loop”)
The EVENT() shown in Block_A, Block_B Clock_Loop can sustain the processing until the task is complete. When the processing is complete “Processing_Not_Done” would be set false based on user conditions.
The Virtual Machine name can be local or global. If local, then the name is accessible from within the hierarchy window. In case of global, the access is from the whole model. This is similar to the local and global IN and OUT blocks.
Block Keywords:
port_name -- Name of input port, scheduler return, or virtual
virtual
scheduler
input, input2, input3, etc.
port_token -- Active data structure from any input, scheduler return, or virtual
TNow -- Current Simulation time
TStop -- Simulation stop time
TResolution -- Simulation resolution time
address -- address of executing statement used in Single_Cycle mode
local_memory -- User can construct Local memory prefix, contains "ModelName.HierarchicalName."
local memory name = local_memory + variable_name, contains "ModelName.HierarchicalName.VariableName"
Parameter |
Explanation |
Type |
Example |
Block_Name |
Block_Name is a Parameter that needs to be unique in modeling space. |
String |
"MyMachine" |
Optional_Parameters |
List of parameters that are used infrequently. Previously called Hidden Parameters. If the current block has these parameter listed in a separate field, those values get precedence over this list. for more details on these parameter,s look at the list below. |
String |
Parameter_Name Parameter_Value |
Single_Cycle |
This enables Single Cycle mode in conjunction with the setBreakpoints. Set to "Stop before Executing Timed Activity”. User can "Listen to Block" to see individual instructions executing. |
Boolean |
- |
Breakpoint |
User can set a breakpoint RegEx expression that can cause the script to pause based on block inputs, memory values, or left-hand side of expression. |
String |
"MySmartResource_Length > 10" |
Smart_Resource_Name |
This is the name of the Queue that is associated with this Controller. This has been provided as a conenience so that the user does not need to edit the code for every instance of this block. The top-level parameter alone can be modified. |
String |
"MySmartResource" |
Each parameter in this list has a value associated with it. The first line has Parameter_Name Parameter_Value. No suffix or line ending is required.
Path: This applies to the Read_File, Save_Files, Profile_File, and Listen_to_File options. This path is used to save the compiled files, profile file, listen to file; and for reading a code file.
Read_File: This is a file name that contains the code when it needs to be read from a file. This approach is preferred when the code needs to be modified between simulation runs. The code is not in the block but is written in a separate text file. If the Path parameter is available, then block searches in the directory, else in $VS directory. This is file name with a .txt extension.
Save_Files: This is a boolean used to save the compiled file in a location specified by the Path parameter of this block or the $VS directory. This parameter used to speed up the compile time. This is used when there are 100's of instances of the Virtual Machine or Smart_Controller. If this value is true, then the file is saved. The first time the code is compiled, it is written to a file. The next time around the delta is compared and if there is no change, the code is not recompiled.
Profile_File: This is a file name that contains a profile of the script execution. It lists the number of times the statement executed and the average time per execution, plus the script statement. If a statement does not execute, then the number will be zero, the time will be zero. This provides a "code coverage" view of the script execution. If the Path is set, then this file will be found in the same path.
Listen_to_File: This is a file that is identical to the "Listen to Block" except it is written to a designated file name. If the Path is set, then this file will be found in the same path.
Duplicate_Input(Default set to true): The transaction arriving on each input is duplicated and placed in the input_queue. If this is set to false, the transaction is not duplicated. This is used to speed up the simulation where the duplication is not required. The duplication is required if the same data structure has been sent to multiple blocks.
Profile: This is a Integer parameter and is the length of the profile generated array. The addition of this parameter to the Virtual Machine generates a array of Instruction Mnemonics associated with the execution of this Virtual Machine code. More information on the Profile can be seen in this explanation.
Maximum_Loops (Default value is 1000000): This applies to a while loop without a WAIT or TIMEQ function being encountered.
Block_Reference (Defaults to Block_Name): This enables the user to create a unique name for the block that allows it to be replicated multiple times in a model without any block parameter changes. A typical value could be the 'hierarchy sequence + Block_Name'.
Port_Order_Array(Example is {"input"}): Allows user to set the order of processing for transactions arriving at the same time at multiple input ports
Add_Scheduler_Times_to_DS(Default to false): Used to add fields to incoming data structure: TIME_ACTIVATION, TIME_RELEASE, TIME_FINISH, TIME_RESPONSE, TIME_IN_SYSTEM. Refer to Scheduler documentation for more details on these field values.
Self_Start: This parameter has been deprecated. All lines before LABEL: BEGIN will execute at initialize. If the user adds "Self_Start" to the block parameters and sets the value to true, then the Virtual_Machine will begin to execute at time 0.0. This mode does not require any input to arrive on the ports to begin execution. Use only LABEL:BEGIN or Self_Start but not both. If both are used that will result in two triggers to the block.
Port |
Explanation |
Type |
Input |
This is a default input port. |
General |
Output |
This is the default output port. |
General |
Created with the Personal Edition of HelpNDoc: Produce online help for Qt applications