Up: (dir)
• Program: | What is it - a Quirks program? | |
• Declarations: | Declarative elements of a module. | |
• Commands: | What are the commands. | |
• Debug: | Special commands for debug quirks programs. |
Next: Declarations, Up: Top
A Quirks program is a set of procedures splitted into modules. Each module consists from one or more procedures and type declarations (optional).
<module> ::= <module_item> { <module_item> } <module_item> ::= <procedure> | <type_declaration> <type_declaration> ::= type <type_name> is <descriptor> ; <procedure> ::= procedure <procedure_name> is <header> begin <body> end <procedure_name> ; <header> := { <prim_selector_decl> | <map_decl> } <prim_selector_decl> ::= <prim_selector> is <descriptor> ; <map_decl> ::= declare map <sec_selector_decl> { <sec_selector_decl> } map is { <map_pair> } end map ; <sec_selector_decl> ::= <sec_selector> is <descriptor> ; <map_pair> ::= '(' <cell> , <cell> ')' <body> ::= { <act_cmn> | <nop_cmn> | <block> | <mov_cmd> | <if_block> | <loop_block> | <exit_cmd> | <call_cmd> | <debug_cmd> } <block> ::= declare <header> begin <body> end ; <if_block> ::= if [not] <cell> then <body> [ else <body> ] end if ; <loop_block> ::= [<label_name> : ] <loop_start> <body> <loop_stop> ; <loop_start> ::= loop | while [not] <cell> loop <loop_stop> ::= end loop | until [not] <cell> <descriptor> ::= <atomic_type> [ / <cell_mode> ] | '<' <complex_type> '>' | <type_name> [ / <cell_mode> ] <atomic_type> ::= bit1 | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 <complex_type> ::= <structure> | <array> | <discriminated_type> <structure> ::= { <descriptor> } stu <array> ::= <descriptor> arr (<num> | * [ <num> ]) [.. (<num> | * [ <num> ]) ] <discriminated_type> ::= '(' <atomic_type> { <atomic_type> } ')' <complex_type> <cell_mode> ::= in | out | inout | na <act_cmd> ::= * <au_selector> ; <nop_cmd> ::= nop ; <mov_cmd> ::= <cell> <- <cell> ; <exit_cmd> ::= exit <loop_label> when [not] <cell> ; <call_cmd> ::= call [ <selector_name> , ] <procedure_name> ; <cell> ::= <selector_name> <order> <order> ::= '[' <num> { : <num> } ']' <debug_cmd> ::= <print_cmd> <print_cmd> ::= print <cell> ; | printn <cell> ; | print <string> ; | printn <string> ;
The terminals are:
lv4
; it
includes <au_selector_name>;
au2Sum
;
~T1
.
"
). If it is needed to insert double quote in this
string
backslash (\"
) should be used.
Each module can have type declarations in a form:
<type_declaration> ::= type <type_name> is <descriptor> ;
Such types can be used in any descriptor declarations that follows.
If the <type_name> is used with i/o mode (‘~T1/in’) such declaration
is restriction of the original i/o modes for the type ~T1
by
the new mode set. The table bellow shows how the original modes are
changed (the first column is the original mode for elements, the others
rows are mode restrictors):
Original | inout | in | out | na |
inout | inout | in | out | na |
in | in | in | na | na |
out | aout | na | in | na |
na | na | na | na | na |
Next: Debug, Previous: Declarations, Up: Top
We have 8 commands.
• nop: | ||
• block: | ||
• mov: | ||
• act: | ||
• call: | ||
• if_block: | ||
• loop_block: | ||
• exit: |
nop
<nop_cmd> ::= nop ;
Now it is like a tradition. Do nothing 1.
block
<block> ::= declare <header> begin <body> end ;
block
allocates new memory and defines new mapping relations. All
disappears after the block exits2.
The <header> specification contains a set of new selector
declarations. These selectors can be introduced in block
:
‘lv’, ‘dn’, ‘au’, ‘dx’, ‘dy’ (i.e. all
procedure-scoped selectors). The selectors in such declaration must not
cross existing selectors - all selectors must be new.
The introduction of ‘lv’ and ‘dn’ selectors cause an immediate memory allocations. The size of the needed memory is determined by the descriptors bonded with these selectors. <map_def> is not allowed for these selectors.
The ‘au’, ‘dx’, ‘dy’ selectors, in contrast, don’t make additional allocation (conceptually) but demand <map_def> specification. This specification defines where the storage for the cells is come from3.
The block
meaning is the same both for procedures and nested
blocks.
mov
<cell> <- <cell> ;
Move a value from the second cell to the first one. Check the cells modes before it.
act
* <selector_name> ;
The act
code call the function of the corresponding AU
module and all related modules (i.e. it cause a function in all AU
modules bounded by a mapping relation).
call
<call_cmd> ::= call [ <selector_name> , ] <procedure_name> ;
A procedure call is examined in details See The model of a procedure in Quirks UVM architecture overview. <selector_name> may be ommited if the callee doesn’t take any formal parameters and doesn’t return a result (except, may be, global variables changing), i.e. a parameter frame is not used.
Next: loop_block, Previous: call, Up: Commands
if_block
<if_block> ::= if [not] <cell> then <body> [ else <body> ] end if ;
Check the <cell>. If the <cell> is is from AU selector then perform
act on it before branching. Perform then or else part depending on
whether <cell> contains non zero vaule. If there is not
prefix
then performs then part when <cell> contains zero.
loop
<loop_block> ::= [<label_name> : ] <loop_start> <body> <loop_stop> ; <loop_start> ::= loop | while [not] <cell> loop <loop_stop> ::= end loop | until [not] <cell>
There are 3 types of loops: with precondition, with postcondition and
infinit loops. All are traditional. All types of loops can have labels
for use with exit
command.
If the <cell> is is from AU selector then perform act on it each time when check the condition.
Previous: loop_block, Up: Commands
exit
<exit_cmd> ::= exit <loop_label> when [not] <cell> ;
Exit from labelled loop of any type when condition is true
(i.e., <cell> is non zero and not
is not present or <cell> is
zero and not
is present). If the <cell> is is from AU selector then perform
act on it before jumping.
These commands intended for debugging. They are usually ignored, but if some key is given to ‘make instance’ then they are included in the code.
• print: | The debug printing. |
Up: Debug
print
and printn
print
prints some debug information (on standard
output). printn
do the same but doesn’t feed line after printing.
<print_cmd> ::= print <cell> ; | printn <cell> ; | print <string> ; | printn <string> ;
If the argument of this command is <cell> then print the cell contents. If the argument is <string> - print the string.
The use of nop
is not treated the same way as an absence of
commands at all. For example, there is some difference between
if <cell> then else <body> end if;
and
if <cell> then nop; else <body> end if;
In the first case (no then part) the code will be equivalent to
if not <cell> then <body> end if;
and probably will be natively translated as:
CHECK <cell> IF NOT ZERO THEN JUMP @L2 <body> @L2:
but in the secong case it will be treated as then part with no action, i.e., that leads to a typicall translation to a native code with jumps:
CHECK <cell> IF ZERO THEN JUMP @L1 JUMP @L2 @L1: <body> @L2:
Thus, nop
means "a command with no action" and not "an absence of
command."
It is true for the "Stack Sparing" (SS) model.
UVM also supports 2 addition models for controlled performance:
Which of these models will give a best performance is a question of underlying implementation of code execution/type_of_processor/program structure.
In the ‘au’ case - where the values come from also.