====== VASYL instructions ====== General remarks: bits, rasterlines and cycles are counted from 0. NTSC video display thus contains lines 0 to 261 (262 on 6567R56A VIC) , while PAL 0 to 311. The first cycle in a rasterline is 0, the last -- depending on VIC model -- is 62, 63 or 64. A "cycle" is understood to mean one 6510 CPU clock cycle. ==== BADLINE ==== ^ BADLINE ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VBADLINE** | 1 | 0 | 1 | 0 | 1 | X2 | X1 | X0 | | | | | | | | | X [0,7] | |Force a badline after **X** rasterlines. \\ \\ Make a badline occur after **X** rasterlines counting from the current one. If **X** is equal to "0", the current line becomes a badline. In other cases current line becomes non-badline (i.e. a regular line). |||||||||||||||||| ==== BRA ==== ^ BRA ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VBRA** | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | X7 | X6 | X5 | X4 | X3 | X2 | X1 | X0 | X [-128,127] | |Branch to a Display List location at offset **X**. \\ \\ The execution of Display List will continue from an address calculated by adding a signed offset **X** to the address of instruction immediately following the **BRA**. If the new address crosses the 64 KiB boundary, it wraps around, and remains in the same memory bank. |||||||||||||||||| ==== DECA ==== ^ DECA ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VDECA** | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | | | | | | | | | | |Decrease counter **A** or skip next instruction if zero. \\ \\ Internal VASYL counter **A** is first tested for equality with "0". If so, the display list execution omits the next __two bytes__ immediately following **DECA** instruction. Otherwise, the counter **A** is decreased by one and execution continues normally.|||||||||||||||||| ==== DECB ==== ^ DECB ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VDECB** | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | | | | | | | | | | |Decrease counter **B** or skip next instruction if zero. \\ \\ Internal VASYL counter **B** is first tested for equality with "0". If so, the display list execution omits the next __two bytes__ immediately following **DECB** instruction. Otherwise, the counter **B** is decreased by one and execution continues normally.|||||||||||||||||| ==== DELAYH==== ^ DELAYH ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VDELAYH** | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | V1 | V0 | H5 | H4 | H3 | H2 | H1 | H0 | V [0,3], H [0,63] | |Postpone execution for **H** cycles. \\ \\ The execution of the Display List is paused for **H** cycles. Values "0" and "1" both take one cycle and are indistinguishable from **NOP**. Non-zero **V** will additionally postpone Display List execution by **V** rasterlines. \\ \\ Note: since different VIC models execute different number of cycles per rasterline, using **H** value that crosses line boundary may lead to unexpected results - prefer first using **VDELAYV 1** to reach the exact beginning of the next line.|||||||||||||||||| ==== DELAYV==== ^ DELAYV ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VDELAYV** | 1 | 0 | 1 | 1 | 1 | 0 | 0 | V8 | V7 | V6 | V5 | V4 | V3 | V2 | V1 | V0 | V [0,511] | |Wait for rasterline **V** lines below. \\ \\ The execution of the Display List is paused until video beam reaches cycle 0 of rasterline which is **V** lines below the current one. With argument of "0" this instruction is a two-byte **NOP**. \\ \\ Note: the addition used to calculate target line does not saturate, and thus can wrap-around with large values and/or late in a frame, leading to undesired results. |||||||||||||||||| ==== END==== ^ END ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VEND** | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | None | |Wait until the end of current frame. \\ \\ This instruction is an alias for **WAIT 511, 63**. \\ \\ Note: same as **WAIT**, this instruction observes masks set by **SETMASK** family of instructions and thus can behave in unexpected ways if masks' values are other than default. |||||||||||||||||| ==== IRQ==== ^ IRQ ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VIRQ ** | 1 | 0 | 1 | 0 | 0 |0 | 1 | 0 | | | | | | | | | None | |Raise 6510 IRQ. \\ \\ If bit 4 of VIC-II IRQMASK register ($D01A) is set to “1”, this instruction will cause VASYL to pull down the 6510 IRQ line and set bit 4 and 7 in VICIRQ register ($D019). This will in turn cause the 6510 to start servicing interrupt request from the next available (i.e. when AEC line is not pulled low) cycle, unless IRQs have been disabled by SEI. The interrupt needs to be acknowledged by setting bit 4 in VICIRQ to "1", similar to how regular VIC-II IRQs are serviced.|||||||||||||||||| ==== MASKH==== ^ MASKH ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VMASKH** | 1 | 0 | 1 | 1 | 0 | 1 | P | 0 | 0 | 0 | H5 | H4 | H3 | H2 | H1 | H0 | P [0,1], H [0,63] | |Set horizontal mask for target comparison operations to **H**. \\ \\ Replaces the default horizontal mask of %111111 with **H**. The mask is used by all instructions that need to compare the current beam position with a target. When a comparison is made, as the first step a binary AND operation is performed between the mask and each side of the comparison (i.e. number of the current cycle and the horizontal target value). In result, the bits that should not be affecting the comparison's result can be turned off. The new mask is only effective on the first **WAIT**-type instruction that follows it, unless **P** (//permanent//) is equal to "1". In that case the mask remains in effect until the end of the frame. \\ \\ Note: Non-default mask can make the **END** instruction behave in undesirable ways.|||||||||||||||||| ==== MASKV==== ^ MASKV ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VMASKV** | 1 | 0 | 1 | 1 | 1 | 1 | P | V8 | V7 | V6 | V5 | V4 | V3 | V2 | V1 | V0 | P [0,1], V [0,511] | |Set vertical mask for target comparison operations to **V**. \\ \\ Replaces the default vertical mask of %111111111 with **V**. The mask is used by all instructions that need to compare the current beam position with a target. When a comparison is made, as the first step a binary AND operation is performed between the mask and each side of the comparison (i.e. number of the current rasterline and the vertical target value). In result, the bits that should not be affecting the comparison's result can be turned off. The new mask is only effective on the first **WAIT**-type instruction that follows it, unless **P** (//permanent//) is equal to "1". In that case the mask remains in effect until the end of the frame. \\ \\ Note: Non-default mask can make the **END** instruction behave in undesirable ways.|||||||||||||||||| ==== MOV==== ^ MOV ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VMOV** | 1 | 1 | R5 | R4 | R3 | R3 | R1 | R0 | X7 | X6 | X5 | X4 | X3 | X2 | X1 | X0 | R [0,63], X [0, 255] | |Move value **X** to bus-accessible register **R**. \\ \\ Value **X** is transferred to a register indicated by **R**. **R** from 0 to $2E correspond to VIC-II registers $D000 to $D02E. Values starting with $31 correspond to VASYL registers $D031-$D03E. **MOV**s to VASYL registers happen internally in the chip and are guaranteed to complete in one cycle. **MOV** to any VIC-II register uses the local bus that gets isolated from the main system bus for the duration of the move. **MOVs** to VIC-II registers are not possible at the time VIC is occupied with memory fetches during high phase of PHI2 cycle (e.g. during badlines). Such **MOVs** will be executed after VIC finishes accessing memory and releases the AEC line. |||||||||||||||||| ==== MOVI==== ^ MOVI ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VMOVI** | 1 | 0 | 0 | R4 | R3 | R3 | R1 | R0 | X7 | X6 | X5 | X4 | X3 | X2 | X1 | X0 | R [0,31], X [0, 255] | |Move value **X** to internal VASYL register **R** + $40. \\ \\ Value **X** is transferred to a register indicated by **R**, where **R** corresponds to VASYL registers $40-$5F. Transfers are done internally in the chip and complete in one cycle. \\ \\ Note: while **MOV** and **MOVI** are technically distinct, it makes sense for an assembler or macro to combine them into one mnemonic and to generate proper opcode based on the arguments. |||||||||||||||||| ==== SETA ==== ^ SETA ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VSETA** | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | X7 | X6 | X5 | X4 | X3 | X2 | X1 | X0 | X [0,255] | |Set counter A to value X. \\ \\ Load an unsigned byte-value to internal VASYL counter A.|||||||||||||||||| ==== SETB ==== ^ SETB ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VSETB** | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | X7 | X6 | X5 | X4 | X3 | X2 | X1 | X0 | X [0,255] | |Set counter B to value X. \\ \\ Load an unsigned byte-value to internal VASYL counter B.|||||||||||||||||| ==== SKIP==== ^ SKIP ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VSKIP** | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | | | | | | | | | None | |Make following **WAIT** skip an instruction if it reached or passed its target location. \\ \\ Modifies the behavior of the next **WAIT** instruction to be executed. Rather than waiting for its target, WAIT will compare it with the current video beam location, and if it determines that the target has been already reached or passed, the next two bytes of the Display List are skipped. Otherwise, WAIT does nothing and Display List execution proceeds normally. |||||||||||||||||| ==== VNOP==== ^ VNOP ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VNOP** | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | | | | | | | | | None | |Do nothing for one cycle. \\ \\ This is a single-byte no-operation instruction. Display List processing will continue from the next cycle. |||||||||||||||||| ==== WAIT==== ^ WAIT ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VWAIT** | 0 |H5| H4| H3| H2| H1| H0| V8 | V7 | V6 | V5 | V4 | V3 | V2 | V1 | V0 | V [0,511], H [0,63] | |Wait until cycle **H** in rasterline **V**. \\ \\ The execution of the Display List is paused until video beam reaches the position corresponding to the beginning of cycle **H** in rasterline **V**. If the video beam is already past the specified position, there will be no pause and Display List processing will continue in the next cycle. If the target position exceeds the range available in the current video mode (e.g. line number is higher than 261 in NTSC), the execution is paused until the start of the next video frame. Since only 6 bits are available to encode the cycle number, the last cycle of 65-cycle lines cannot be targeted. Simple workaround is to target the cycle before it and then issue a **NOP**. |||||||||||||||||| ==== WAITBAD ==== ^ WAITBAD ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VWAITBAD** | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | | | | | | | | | None | |Wait for the next badline. \\ \\ Execution of the Display List is paused until cycle 0 of a rasterline imediately __preceding__ the next badline, as indicated by rasterline number and contents of VIC-II SCROLY ($d011) register. The goal of early stop is to leave time for preparatory register setting before VIC-II switches to badline mode. To reach actual badline, rather than a line before it, use **WAITBAD** followed by **DELAYV 1**. \\ \\ Note: there is no guarantee that the badline will actually occur, as both VASYL and 6510 can modify SCROLY before the badline starts. |||||||||||||||||| ==== WAITREP ==== ^ WAITREP ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VWAITREP** | 1 | 0 | 1 | 1 | 1 | 0 | 1 | P | | | | | | | | | P [0,1] | |Wait until port P stops repeating writes. \\ \\ Display List execution is paused until the port **P** has a repeat count of 0, i.e. until it stops repeating the last transfer to VASYL memory initiated by write to register **REP** of respective port. If repeated transfer is currently not in progress in port **P**, Display List execution will continue from the next cycle. |||||||||||||||||| ==== XFER ==== ^ XFER ^ Byte 1 ^^^^^^^^ Byte 2 ^^^^^^^^ ^ ^ VBASIC ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^B7^ B6 ^ B5 ^B4 ^B3^ B2 ^B1 ^B0 ^ Args ^ | **VXFER** | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | P | R6 | R5 | R4 | R3 | R2 | R1 | R0 | R [0,127], P [0,1] | |Transfer value from port **P** to register **R**. \\ \\ A byte is read from port **P** (i.e. from a VASYL memory location pointed to by selected port's ADR(LH) register) and written to VIC-II or VASYL register **R**. Values of **R** ranging from $0 to $2E corresponds to VIC-II registers $D000 to $D02E. Values from $31 on correspond to VASYL registers $D031 and on. Values from $40 on correspond to VASYL internal registers, inaccessible through system bus (and thus without equivalents in $D0x0 IO space). \\ \\ As with **MOV**, transfers to VIC-II registers will stall VASYL if VIC is occupied by memory fetches in high phase of PHI2 cycle. ||||||||||||||||||