/* * Copyright (c) 2001-2020 Stephen Williams (steve@icarus.com) * */ EXECUTABLE INSTRUCTION OPCODES Instruction opcodes all start with a % character and have 0 or more operands. In no case are there more than 3 operands. This chapter describes the specific behavior of each opcode, in enough detail (I hope) that its complete effect can be predicted. General Principles of Arithmetic (current plan): The binary arithmetic instruction in general takes three parameters, the left operand, the right operand, and the base. The left operand is replaced with the result, which is the same width as the left and right operands. General Principles of Arithmetic (new plan): For strings, all arithmetic is stack based. That is, there is an abstract stack of strings from which operations pull their operands and push their results. This is somewhat like FORTH (or an HP calculator RPN notation) and spares the need to keep register addresses in operands. I may find this leads to a more compact form of instruction code, and may lead to more efficient operators overall, and in particular I may find improved efficiency overall; so after the experience of implementing it for strings, I'll want to change other types around to using this method as well. Keep this in mind whenever considering adding new instructions to vvp. FLAGS There are up to 16 bits in each thread that are available for flags. These are used as destinations for operations that return boolean values, for example comparisons. They are also used as inputs for test and branch opcodes. * %abs/wr This instruction calculates the absolute value of a real value. It uses the fabs() function in the run-time to do the work, and manipulates the top of the real-value stack. * %add * %addi , , This opcode pops and adds two vec4 values from the vec4 stack, adds them, and pushes the result back to the stack. The input values must have the same size, and the pushed result will have the same width. The %addi variant takes one operand from the stack, the other is an immediate value (See %pushi/vec4). See also the %sub instruction. * %add/wr This is the real valued version of the %add instruction. The arguments are popped from the stack, right operand then left, and the result pushed in place See also the %sub/wr instruction. * %alloc This instruction allocates the storage for a new instance of an automatically allocated scope. * %and Perform the bitwise AND of the two vectors popped from the vec4 stack, and push the result. Each bit is calculated independent of other bits. AND means the following: 0 and ? --> 0 ? and 0 --> 0 1 and 1 --> 1 otherwise x The input vectors must be the same width, and the output vector will be the width of the input. * %and/r Pop the top value from the vec4 stack, perform a reduction &, then return the single-bit result. * %assign/ar , * %assign/ar/d , * %assign/ar/e The %assign/ar instruction assigns a real value to a word in the labeled real array. The is the delay in simulation time to the assignment (0 for non-blocking assignment) and the value is popped from the real value stack. The memory word address is read from index register 3. The address is in canonical form. The %assign/ar/d variation reads the delay from an integer register that is given by the value. This should not be 3 or the index, of course, since these registers contain the word address and the value. The %assign/ar/e variation uses the information in the thread event control registers to determine when to perform the assign. %evctl is used to set the event control information. * %assign/v0 , , (XXXX Old description) * %assign/v0/d , , (XXXX Old description) * %assign/v0/e , (XXXX Old description) The %assign/v0 instruction is a vector version of non-blocking assignment. The is the number of clock ticks in the future where the assignment should be schedule, and the is the base of the vector to be assigned to the destination. The vector width is in index register 0. The %assign/v0/d variation gets the delay instead from an integer register that is given by the value. This should not be 0, of course, because integer 0 is taken with the vector width. The %assign/v0/e variation uses the information in the thread event control registers to determine when to perform the assign. %evctl is used to set the event control information. The references a .var object that can receive non-blocking assignments. For blocking assignments, see %set/v. * %assign/vec4 , * %assign/vec4/d , * %assign/vec4/e The %assign/vec4 instruction is a vec4 version of non-blocking assignment. The is the number of clock ticks in the future where the assignment should schedule, and the value to assign is pulled from the vec4 stack. The %assign/vec4/d instruction is the same, but gets its delay value from the index register instead. * %assign/vec4/a/d , , * %assign/vec4/a/e , This instruction implements delayed assignment to an array word. The value is popped from the vec4 stack; the width is taken from the popped value. The index register contains the canonical offset into the memory word for a part select, and the index register contains the delay for the assignment. Index register 3 contains the word address. The and index registers can be 0, which means a zero value instead of the contents of index register 0. If flag bit 4 is set, then the value will be popped from the stack, but it will not be assigned. This handles the case that the index values is undefined. * %assign/vec4/off/d , , This is for writing parts to the target variable. The is the variable to write, as usual. The selects an index register that holds the offset into the target variable, and the selects the index register that contains the delay. The offset is in canonical bits. The width that is written is taken from the width of the value on the stack. The actual assignment is suppressed if flags-4 is 1. This is so that calculations of offset can set the flag on errors. * %assign/wr , * %assign/wr/d , * %assign/wr/e This instruction provides a non-blocking assign of the real value given in to the real object addressed by the label after the given . The real value is popped from the stack. The %assign/wr/d variation gets the delay from integer register . The %assign/wr/e variation uses the information in the thread event control registers to determine when to perform the assign. %evctl is used to set the event control information. * %blend This instruction blends the bits of two vectors into a result in a manner line the expressions ('bx ? : ). The two source vectors are popped from the vec4 stack (and must have the same width) and the result pushed in their place. The truth table for each bit is: 1 1 --> 1 0 0 --> 0 z z --> z x x --> x .... --> x In other words, if the bits are identical, then take that value. Otherwise, the value is x. * %blend/wr This instruction blends real values for the ternary operator. If the values match return that otherwise return 0.0. Two values are popped from the stack, one is pushed back. * %breakpoint This instruction unconditionally breaks the simulator into the interactive debugger. The idea is to stop the simulator here and give the user a chance to display the state of the simulation using debugger commands. This may not work on all platforms. If run-time debugging is compiled out, then this function is a no-op. * %callf/obj , * %callf/real , * %callf/str , * %callf/vec4 , * %callf/void , More directly implement function calling. This subsumes the %fork and %join of the more general task and block calling, but is optimized for functions, which are threads of a special, constrained sort. The different variants reflect the different return types for the called function. For example, if the function returns a string, the %callf/str opcode is used, and will push the string return value into the caller's string stack. The %callf/void function is special in that is pushes no value onto any stack. * %cassign/vec4 * %cassign/vec4/off , Perform a continuous assign of a constant value to the target variable. This is similar to %set, but it uses the cassign port (port-1) of the signal functor instead of the normal assign, so the signal responds differently. See "VARIABLE STATEMENTS" in the README.txt file. The %cassign/vec4/off instruction will check the flags[4] flag, and if it is 1, it will suppress the assignment. This is so that failed index calculations can report the failure by setting the flag. * %cassign/wr Perform a continuous assign of a constant real value to the target variable. See %cassign/v above. The value is popped from the real value stack. * %cast2 Pop a value from the vec4 stack, convert it using Verilog rules to a vector2 (binary) value, and push the result. * %cast/vec2/dar Pop a dynamic array value from the object stack, convert it to a 2-state vector that is bits wide, and push the result to the vec4 stack. If the dynamic array does not fit exactly in bits, print an error message and stop the simulation. * %cast/vec4/dar Pop a dynamic array value from the object stack, convert it to a 4-state vector that is bits wide, and push the result to the vec4 stack. If the dynamic array does not fit exactly in bits, print an error message and stop the simulation. * %cast/vec4/str Pop a value from the string stack, convert it to a vector that is bits wide, and push the result to the vec4 stack. If the string does not fit exactly in bits, print an error message and stop the simulation. * %cmp/s * %cmp/u * %cmp/e * %cmp/ne * %cmpi/s , , * %cmpi/u , , * %cmpi/e , , * %cmpi/ne , , These instructions perform a generic comparison of two vectors of equal size. Two values are pulled from the top of the stack, and not replaced. The results are written into flag bits 4,5,6. The expressions (a, * %cmp/wu , [compare signed/unsigned integer words.] * %cmp/z * %cmp/x These instructions are for implementing the casez and casex comparisons. These work similar to the %cmp/u instructions, except only an eq bit is calculated. These comparisons both treat z values in the left or right operand as don't care positions. The %cmp/x instruction will also treat x values in either operand as don't care. Only bit 4 is set by these instructions. * %cmp/str This instruction pops the top two strings from the string stack and compares them. The results of the comparison go into bits 4 and 5: 4: eq (equal) 5: lt (less than) For the purposes of calculating the lt bit, the top string is the right operand and the string underneath is the left operand. This instruction removes two strings from the stack. * %concat/str * %concati/str Pop the top string, and concatenate it to the new top string. Or think of it as passing the tail, then the head, concatenating them, and pushing the result. The stack starts with two strings in the stack, and ends with one string in the stack. The %concati/str form pops only one value from the stack. The right part comes from the immediate value. * %concat/vec4 * %concati/vec4 , , Pop two vec4 vectors, concatenate them, and push the combined result. The top of the vec4 stack is the LSB of the result, and the next in this stack is the MSB bits of the result. The %concati/vec4 form takes an immediate value and appends it (lsb) to the value on the top of the stack. See the %pushi/vec4 instruction for how to describe the immediate value. * %cvt/sr * %cvt/ur Pop a word from the real-value stack, convert it to a signed or unsigned integer, and write it to the index register. Precision may be lost in the conversion. * %cvt/rv * %cvt/rv/s The %cvt/rv instruction pops a value from the thread vec4 stack and converts it to a real word. Push the result onto the real value stack. Precision may be lost in the conversion. The %cvt/rv/s instruction is the same as %cvt/rv, but treats the thread vector as a signed value. * %cvt/vr The %cvt/vr opcode converts a real word from the stack to a vec4 that is wide. Non-integer precision is lost in the conversion, and the real value is popped from the stack. The result is pushed to the vec4 stack. * %deassign , , Deactivate and disconnect a procedural continuous assignment to a variable. The identifies the affected variable. The and are used to determine what part of the signal will be deactivated. For a full deactivation the is 0 and is the entire signal width. * %deassign/wr The same as %deassign above except this is used for real variables. * %debug/thr These opcodes are aids for debugging the vvp engine. The vvp code generator should not generate these, and they should not alter code flow, data contents, etc. * %delay , This opcode pauses the thread, and causes it to be rescheduled for a time in the future. The amount is the number of the ticks in the future to reschedule, and is >= 0. If the %delay is zero, then the thread yields the processor for another thread, but will be resumed in the current time step. The delay amount is given as 2 32bit numbers, so that 64bit times may be represented. * %delayx This is similar to the %delay opcode, except that the parameter selects an index register, which contains the actual delay. This supports run-time calculated delays. * %delete/obj Arrange for the dynamic object at the target label to be deleted. This has no effect on the object or string stack. Note that this is the same as: %null ; %store/obj but that idiom is expected to be common enough that it warrants an optimized shorthand. * %disable This instruction terminates threads that are part of a specific scope. The label identifies the scope in question, and the threads are the threads that are currently within that scope. * %disable/fork This instruction terminates all the detached children for the current thread. There should not be any non-detached children. * %div , , * %div/s , , This instruction arithmetically divides the vector by the vector, and leaves the result in the vector. IF any of the bits in either vector are x or z, the entire result is x. The %div/s instruction is the same as %div, but does signed division. * %div/wr This opcode divides the left operand by the right operand. If the right operand is 0, then the result is NaN. * dup/real * dup/vec4 These opcodes duplicate the value on the top of the stack for the corresponding type. * %evctl * %evctl/c * %evctl/s * %evctl/i These instructions are used to put event and repetition information into the thread event control registers. These values are then used by the %assign/e instructions to do not blocking event control. The is the event to trigger on and the is an index register to read the repetition count from (signed or unsigned). %evctl/i sets the repetition to an immediate unsigned value. %evctl/c clears the event control information. This is needed if a %assign/e may be skipped since the %assign/e statements clear the event control information and the other %evctl statements assert that this information has been cleared. You can get an assert if this information is not managed correctly. * %event This instruction is used to send a pulse to an event object. The is an event variable. This instruction simply writes an arbitrary value to the event to trigger the event. * %file_line This command emits the provided file and line information along with the description when it is executed. The output is sent to stderr and the format of the output is: :: is the unsigned numeric file index. is the unsigned line number. is a string, if string is 0 then the following default message is used: "Procedural tracing.". * %flag_inv This instruct inverts a flag bit. * %flag_mov , This instruction copies the flag bit from to . * %flag_or , This instruction calculates the Verilog OR of the flag bits in and , and leaves the result in . * %flag_set/imm , This instruction sets an immediate value into a flag bit. This is a single bit, and the value is 0==0, 1==1, 2==z, 3==x. * %flag_get/vec4 * %flag_set/vec4 These instructions provide a means for accessing flag bits. The %flag_get/vec4 loads the numbered flag as a vec4 on top of the vec4 stack, and the %flag_set/vec4 pops the top of the vec4 stack and writes the LSB to the selected flag. * %force/vec4