This describes the PulseBlaster's Instruction set. See also the manual, pulseblaster.h and doc/vliw.txt OPCODES ======= These are the (idealised) pulseblaster opcodes, for the user-supplied program. This is what is required by pb_make_vliw(). I have re-named the opcodes and re-ordered the vliw instructions with respect to Spincore's defintions, because it seems more logical. See also doc/vliw.txt Other extensions are done by pb_parse - see pbsrc.txt VLIW instruction: OUTPUT OPCODE ARG LENGTH //comment This means: Set the outputs. Then do Instruction, taking LENGTH cycles to execute it. (An alternative way to visualise is: Set outputs. Update stack and program counter. Delay. Then jump to next pc) Addresses are all zero-based. Arguments and Lengths are compensated: give the value you want, and pb_make_vliw() will calculate what should actually be written to the hardware OUTPUT is the 24-bit wide signal to output. (Hex, or decimal) OPCODE is the (case-insensitive) instruction to perform AFTER the pulseblaster has delayed for LENGTH. It may be any of: CONT, LONGDELAY, LOOP, ENDLOOP, GOTO, CALL, RETURN, WAIT, STOP LENGTH is the length to delay in pulseblaster clock cycles (PB_TICK_NS). It must have a value of at least PB_MINIMUM_DELAY. (WAIT requires more) The .VLIW file should contain the value desired; pb_make_vliw() handles the abstraction/compenstation/check. [Note: see HARDWARE below.] ARG is the argument taken by some of the opcodes. For those that don't require it, it is ignored; specify it as "-" (or 0). ARG has a hexadecimal value upto 20 bits long (the same formats as for OUTPUT. It's used either for a counter, or an address. DETAILS ======= OpCode ARG Function Notes Spincore's Name. Value ------ --- -------- ----- ---------------------- CONT - Set outputs. - CONTINUE Continue to next instruction, taking length cycles 0 LONGDELAY n Set outputs. n > 1 LONG_DELAY Continue to next instruction, taking ARG * LEN cycles (n = 1 => cont) 7 LOOP n Set outputs. LOOP Unless already in this loop, start a loop of ARG counts. n > 0 2 Continue to next instruction, taking length cycles. Executed n times. ENDLOOP addr Set outputs. addr is matching loop. ENDLOOP Decrement counter. Either exit the loop or jump-back to Executed n times 3 address ARG, taking length cycles. Max nested loops: 8 GOTO addr Set outputs. - BRANCH Jump to instruction at ARG, taking length cycles. 6 CALL addr Set outputs. Max stack depth: 8 JSR Call subroutine at ARG, taking length cycles. 4 RETURN - Set outputs. - RTS Return to the address after the caller, taking length cycles. 5 WAIT - Set outputs. Not first instruction WAIT Wait for software or hardware trigger. If 2nd, 1st length >= 11 8 Then proceed, taking length cycles. Use pb_cont, not start. STOP - Ignore outputs. Just Halt. (Length is ignored) - STOP Need pb_start, or hw_reset;hw_trigger 1 DEBUG - For debugging purposes. - CONTINUE Interpreted as "CONT", triggers notice. 0 MARK - For simulation purposes. - CONTINUE Interpreted as "CONT", triggers mark in simulator. 0 NEVER - Unreached instruction, embedded by pb_parse Dead code. CONTINUE Treated as "CONT". See note. 0 NOTES ===== STOP does not honour the OUTPUT value. The *previous* state is retained. Output must be 0 or -. Likewise, the delay has no meaning, and must be 0 or -. WAIT does its delay *after* wakeup, NOT before "sleep". Some instructions eg CONT can actually take 1 tick less than the minimum required length, PB_MINIMUM_DELAY. This is experimentally true, but not documented, and this set of utilities does NOT support it. But future optimisation *might* be possible. Execution begins at line 0. Therefore, subroutines must be placed at the end of the address-space (or an initial GOTO should jump over them). LOOP instructions are a bit unusual - see loops.txt. In particular, for LOOP(n)...ENDLOOP, the loop's output/length is executed n times; also the endloop's output/length is executed n times. DEBUG instruction: this is basically syntactic sugar, to allow the programmer to vgrep. It is interpreted as a synonym of "CONT" by pb_asm. MARK instruction: this allows the simulator to print out a timestamp mark - useful for measuring (in simulation) the exact timestamps for places in complex code. It is interpreted as a synonym of "CONT" by pb_asm. NEVER instruction: this instruction is one that was identified as "dead code" by pb_parse, (eg by zeroloop), for example code that is skipped over by GOTO. It has to remain in the source to keep the address-numbering correct, and pb_asm converts this into a "CONT" opcode so that the pulseblaster's validation doesn't choke. But program flow never actually touches this instruction. HARDWARE ======== The opcodes as described above are for the 'idealised' pusleblaster, as supported by the vliw instructions, and by my pb_prog program. However, there are some quirks. 1. The pulseblaster has an inherent PB_INTERNAL_LATENCY cycle timing delay. This is dealt with later, by pb_make_vliw(). 2. The pulseblaster also has an extra latency for WAITS: PB_WAIT_LATENCY. This is dealt with later, by pb_make_vliw(). 3. The instruction which preceedes STOP has a minimum length requirement which is PB_BUG_PRESTOP_EXTRADELAY (i.e. 2 ticks) higher than normal. Otherwise, its outputs don't get applied. 4. In loops, PB_BUG_LOOP_OFFSET (i.e. 1) must be subtracted from the loop counter. This is dealt with later, by pb_make_vliw(). 5. In longdelays, PB_BUG_LONGDELAY_OFFSET (i.e. 2) must be subtracted from the longdelay arg. This is dealt with later, by pb_make_vliw(). See also: latencies.txt, longdelay.txt and loops.txt