====== Introduction ====== If you followed the [[:introduction_to_programming_the_beamracer|other chapter]] you already know that BeamRacer is an extremely powerful new tool allowing you to explore the VIC-II and Commodore 64 graphics and visual effects in both old, well-known as well as new, completely uncharted ways. At the very core of BeamRacer lies a programmable coprocessor called VASYL with its own registers, instruction set and memory. Programming VASYL is definitely easy for seasoned Commodore 64 machine-language programmers who mastered their favourite development toolchain and can spawn another PRG in "no-time". But we wanted it to be even more accessible and enabling. Therefore an idea for BASIC extension was born and materialised shortly thereafter. How about some complex graphics effects and augmentation for BASIC programs? We all know that those are not possible without machine code routines stashed somewhere (typically at 49152 upwards) in available RAM. With BeamRacer installed you can still use the same methods. You can POKE or read from storage whatever you need. But you can also load "VBASIC" and have all the VASYL power at your BASIC programming fingertips with zero setup time. At least that was the idea that initially guided us. And yes - it's all there. But to be completely frank we have to admit that once VBASIC matured, we also found it an indispensable tool for developing, testing and debugging not only VASYL programming ideas but for example checking quickly how VIC behaves when treated one or another way, without all the boilerplate code needed to cycle-exactly trigger something. An eye opening and mouth corners rising experience :-) Summing up - you will appreciate VBASIC for: * all the additions aimed at helping in low-level programming * fast-turnaround, zero boilerplate verification of VIC programming ideas * immediate full access to VASYL's power from within BASIC programs * lowest barriers to entry into VASYL programming and programming techniques development * verifying/debugging of VASYL code and display lists ====== Installation ====== VBASIC is an integral part of BeamRacer support software. It is currently distributed in binary form of a BASIC loadable PRG file that needs to be RUN after loading. ====== Initialisation ====== As part of initialisation process VBASIC installs itself in the RAM area, address of which is normally occupied by BASIC ROM code, and adds additional routines at the very top of memory available for BASIC programs. It also verifies the presence of an installed BeamRacer card and activates it if found. Thanks to that your programs do not need to perform any additional steps to check and activate BeamRacer. Last but not least it adds helper routines and modifies several system variables and vectors. This allows to provide correct information about available memory and enables seamless BASIC programming experience. As a result all the standard behaviour for STOP, STOP/RESTORE etc. remains unchanged, while actively maintaining both the VBASIC extension and BeamRacer active at the same time. ====== Features ====== There's a lot to talk about here so let's begin without additional delays. ===== Hex all over and around ===== Before we go into BeamRacer specific stuff – first things first: hexadecimal numbers. BASIC programmers are usually used to having only decimal numbers at their disposal. We didn't want to leave it that way though. We know very well that the more one's skills grow, the more important an easy way of working with hexadecimal addresses and data becomes. Therefore hexadecimal numbers received first-class VBASIC citizenship from day one. ==== Hexadecimal entry ==== VBASIC allows up to 16 bit hexadecimal entry wherever appropriate: 10 POKE 53280,14 20 POKE $D021,$0E 30 PRINT PEEK($D012) 40 POKE $0400,16:REM P 50 POKE 1025,$11:REM Q 60 POKE $C000,96:REM RTS 70 SYS $C000 80 PRINT $D000/$10 etc. are all valid now. So are: 10 FOR I = $100 TO $1000 STEP $10 20 REM DO GREAT STUFF WITH I 30 NEXT I ==== Hexadecimal output ==== Hexadecimal input is one important thing, the other side of the coin is getting your numbers __output__ in hex. VBASIC has you covered there too. 10 PRINT 49152/16 : REM WE KNOW WE GET 3072 20 PRINT 49152/256 &W : REM HUH ? 30 PRINT HI(49152) &B : REM HUH^2 ? Any numeric expression can be passed to one of ''&'' modifiers: * ''B'' - for one ''BYTE'' (eight bit) * ''W'' - for one ''WORD'' (16 bit) * ''L'' - for one ''LONG'' (32 bit) hexadecimal output. Please note that there is no automatic promotion to higher number of bits. If you enter PRINT 49152 &B what you get is only the eight __least__ significant bits as a hexadecimal number. The same applies for ''&W'', obviously with the output being limited to 16 least significant bits in this case. Try PRINT 70000 &B PRINT 70000 &W PRINT 70000 &L and you'll get the idea. If you don't explicitly specify the modifier PRINT 255& PRINT 256& PRINT 53248& PRINT 16777215& the most appropriate one will be chosen automatically. Values up to 32-bit long are supported. ===== 16-bit PEEKs and POKEs ===== PEEKs and especially POKEs are inseparable part of every BASIC programs that strives for utilising graphics capabilities of the computer. Be it bitmapped graphics, be it the the first "up up and away" sprites experience or actually _anything_ beyond the blue-on-blue textual interface the machine powers up with. Built-in support for PEEK and POKE is limited to eight bit values though. VBASIC adds keywords for handling 16 bit values easily. Setting address vectors or pointers is as easy as DPOKE $C000,$0400 or DPOKE 49152,1024 which in both forms sets a pointer to address 1024 with its LO byte (0) located at 49152 and HI byte (4) at 49153. Obtaining the starting address of BASIC memory becomes as easy as PRINT DPEEK(43) Length of current BASIC program can be retrieved as PRINT DPEEK(45) - DPEEK(43) - 2 And the (in)famous 10 POKE 53280,0 20 POKE 53281,0 sequence becomes 10 DPOKE 53280,0 Basically everywhere, where dealing with "little endian" 16-bit values is needed, these come in handy and do all the LO/HI calculations for you. ===== HI and LO bytes ===== Speaking of HI and LO bytes of an address (or any 16-bit value for that matter) – VBASIC provides functions that simplify working with them too. And they are named… yeah, you guessed that already, didn't you? 10 PRINT HI(53281) 20 PRINT LO(53281) ===== VASYL access and programming ===== Even if the above mentioned features alone are noteworthy additions to BASIC programming environment, the most important part is the full-fledged support for BeamRacer, including displaylist programming. ==== Automatic BeamRacer activation ==== As explained in [[:introduction_to_programming_the_beamracer|Introduction to BeamRacer Programming]], to maintain highest possible compatibility, BeamRacer remains hidden on power-up and needs to be software activated with a "register knocking" technique before accessing any of its software accessible features. All programs that want to interact with VASYL or other BeamRacer features, like GreydotKilla™ for example, need to perform the init'n check sequence as described in [[:introduction_to_programming_the_beamracer#initialization|Initialisation section]]. VBASIC takes that responsibility on its shoulders and not only activates BeamRacer as part of its startup-sequence but also automatically reactivates it after every BRK/NMI/STOP-RESTORE combination. Breaking out of VASYL programs and disabling display list is therefore as easy as hitting the famous keys combination, without worries about disabling either VBASIC or BeamRacer on the way. All regular BASIC programming activities, short of directly overwriting values at any of vital memory locations or SW/HW resets/jams do not affect VBASIC and BeamRacer's availability. ==== VASYL programming ==== VBASIC enables and in some cases simplifies VASYL programming, debugging and testing directly from within BASIC. It is achieved in a few distinctive ways. === VASYL complex commands === Certain VASYL programming sequences can be simplified with VBASIC statements, which combine several low level accesses into a single high level directive. The most common and required for virtually every displaylist employing program is the configuration of VASYL PORT register(s), which act as proxy gateways between the CPU and VASYL memory. In order to transfer any displaylist code to where it can be executed, at least one of the two available PORT registers needs to be employed. Configuring them is therefore the first step of displaylist transfer. In contrast to [[:introduction_to_programming_the_beamracer#local_memory|how it is done in assembler]], when using VBASIC this can be done in one shot as: 10 VCFG 0,0 which configures * Conveyor #0 (connected to VASYL PORT #0) * to point to VASYL memory address 0 ($0000) * with the default step of 1 Other examples of such statements are: 1000 DLON : REM START DISPLAYLIST EXECUTION 1000 DLOFF : REM STOP DISPLAYLIST EXECUTION 1000 BANK 3 : REM SET VASYL MEMORY BANK TO 3 Full list and description can be found in the [[#reference]] section below. === VASYL inline displaylist assembler === VBASIC provides full support for all VASYL/displaylist [[:isa|opcodes]] in the form of BASIC statements and functions. In order to form them, assembly opcodes are prepended with letter "V". Thus ''WAIT'' becomes ''VWAIT'', ''MOV'' becomes ''VMOV'', ''END'' becomes ''VEND'' and so on. The way BASIC interprets those keywords is tuned for both flexibility and the easiest possible way of transferring displaylists into VASYL local memory. I. e. whenever such keyword is encountered, its arguments are parsed and assembled into appropriate VASYL binary code. The resulting bytes are then either immediately sent to previously configured [[#vcfg|"conveyor"]] (if invoked as statement) and no additional steps are necessary, or returned to be e. g. stored in a variable for later use (when invoked as funcion). === Displaylist disassembler === Even if creating simple to medium complexity blocks of VASYL programs (aka displaylists) is very easy, having a method for verifying the state of displaylist memory is a hard to overrate feature. Especially at times when things don't work as imagined. For this purpose we equipped VBASIC with a complete displaylist disassembler, allowing us to peek into what VASYL sees and executes while doing its hard work. Disassembler is invoked with ''VLIST'' statement: VLIST [[,]] ====== Reference ====== All VBASIC keywords grouped into three categories: * representing only statements * representing only functions * representing both statements and functions ===== Functions only ===== Tokens from this group require to be called as functions, with parentheses, even if no arguments are expected for some of them ==== ABOUT ==== FUNCTION: Returns detailed information about VBASIC and BeamRacer (if the latter is installed) versions __Synopsis__: ''ABOUT()'' __Examples__: PRINT ABOUT() AB$ = ABOUT() REM NOW DO SOMETHING WITH THE STRING ==== DPEEK ==== FUNCTION: Returns "double peek" value from
in main computer address space __Synopsis__: ''DPEEK(
)'' __Examples__: BL = DPEEK(45) - DPEEK(43) - 2 : REM GET CURRENT BASIC PROGRAM SIZE IN BYTES PRINT BL&W : REM PRINT IT AS 16-BIT HEXADECIMAL NUMBER ==== HI ==== FUNCTION: Returns "HI" byte (eight most significant bits) of interpreted as 16-bit unsigned integer __Synopsis__: ''LO()'' Where is a number in the 16-bit unsigned int range: 0..65535 __Examples__: PRINT HI(53281)&B ==== LO ==== FUNCTION: Returns "LO" byte (eight least significant bits) of interpreted as 16-bit unsigned integer __Synopsis__: ''LO()'' Where is a number in the 16-bit unsigned int range: 0..65535 __Examples__: PRINT LO(53280)&B ==== VDPEEK ==== FUNCTION: Returns "double peek" value from
in currently selected bank of VASYL memory __Synopsis__: ''VDPEEK(
)'' __Examples__: PRINT VDPEEK($100)&W ==== VPEEK ==== FUNCTION: Returns 8-bit value from
in currently selected bank of VASYL memory __Synopsis__: ''VPEEK(
)'' __Examples__: PRINT VPEEK($100) ===== Statements only ===== Tokens from this group require to be used as statements with arguments given without parentheses ==== COPY ==== ---- STATEMENT: Copy data between different VASYL RAM regions or between computer's main and VASYL's memory. __Synopsis__: ''COPY #, #, '' * TO is the number of configured destination "conveyor" * FROM is the number of configured source "conveyor" * LENGTH is the number of bytes to be copied __Discussion__: There are two "conveyors", which are used every time data needs to be shifted in or out of VASYL RAM. Every display list program employs at least one of them in order to find its way into VASYL accessible memory. VBASIC provides one more "conveyor" though. While the first two, numbered ''0'' and ''1'' are directly connected with two VASYL , the third one extends this form of memory access to cover also the main computer RAM. __Conveyors__: * 0 - communicates with VASYL memory through [[https://docs.beamracer.net/doku.php?id=registers#port0|PORT0]] * 1 - communicates with VASYL memory through [[https://docs.beamracer.net/doku.php?id=registers#port1|PORT1]] * 2 - communicates with computer's main memory. Please note that currently there are no protection mechanisms preventing accidental overwrite of vital memory ranges - use with caution, especially when employed as destination __Examples__: VCFG 2,49152,1 : REM ALWAYS CONFIGURE BEFORE USING VCFG 0,$1000,1 : REM ALWAYS CONFIGURE BEFORE USING COPY #0,#2,4096: REM STASH CONTENT OF $C000-$CFFF TO VASYL RAM AT $1000 VCFG 2,49152,1 : REM ALWAYS CONFIGURE BEFORE USING VCFG 0,$1000,1 : REM ALWAYS CONFIGURE BEFORE USING COPY #2,#0,4096: REM PULL 4KIB OF DATA FROM VASYL RAM AT $1000 TO MAIN RAM AT $C000 BANK 1 : REM SET VASYL RAM BANK TO 1 VCFG 1,0,1 : REM ALWAYS CONFIGURE BEFORE USING FOR L=0 TO 7 : REM WE NEED EIGHT CHUNKS by 1KIB VCFG 2,$4000+L,8 : REM ALWAYS CONFIGURE BEFORE USING COPY #1,#2,1024 : REM CONVERT 1KIB OF HIRES DATA TO LINEAR NEXT L : REM REPEAT UNTIL 8KIB TRANSFERRED ==== DLOFF ==== ---- STATEMENT: Turn off displaylist execution __Synopsis__: ''DLOFF'' __Examples__: 100 DLOFF : REM TURN DISPLAYLIST EXECUTION OFF ==== DLON ==== ---- STATEMENT: Turn on displaylist execution __Synopsis__: ''DLON'' __Examples__: 100 VCFG 0,0 : REM PORT0, ADDRESS0 110 VWAIT $83,0 120 VMOV $21,$14 130 VDELAYV $28 140 VMOV $21,6 999 VEND : REM END OF DISPLAYLIST 1000 DLON : REM START DISPLAYLIST EXECUTION __Discussion__: Turning displaylist execution on needs to be done ___after___ the displaylist program is transferred to VASYL memory. It is a common practice to put it right after the displaylist closing ''VEND'' statement. ==== DPOKE ==== ---- STATEMENT: Double POKE __Synopsis__: ''DPOKE
,'' * ADDRESS is a 16 bit value denoting memory address within Commodore 64 memory * VALUE is a 16 bit (two byte) value to be "poked" into ADDRESS. Bytes are stored in [[wp>Endianness|Little-Endian (first LO then HI byte)]] order __Examples__: DPOKE $1000,32768 : REM STORES $00 AT $1000 AND $80 AT $1001 DPOKE $10FE,$FF : REM STORES $00 AT $10FE AND $FF AT $10FF DPOKE $D020,$00 : REM STORES $00 AT $D020 AND $D021 ==== LABEL ==== ---- STATEMENT: Define a label in displaylist code __Synopsis__: ''LABEL X%'' * X is a valid integer variable name __Examples__: [...] 130 VSETA 10 140 LABEL A% 150 VMOV $20,0 160 VMOV $20,1 170 VDECA 180 VBRA A% 999 VEND __Discussion__: The variable after the ''LABEL'' statement needs to be declared (and later referred to) as //integer// variable – with percent (''%'') sign following the name. Declaration of this variable with ''LABEL'' statement must precede any reference to it ==== VCFG ==== ---- STATEMENT: Configure VBASIC's "conveyor" __Synopsis__: ''VCFG ,
[,[,]]'' * CONVEYOR is a valid number of the "conveyor" to be configured (''0'', ''1'' or ''2'') * 0 - communicates with VASYL memory through [[https://docs.beamracer.net/doku.php?id=registers#port0|PORT0]] * 1 - communicates with VASYL memory through [[https://docs.beamracer.net/doku.php?id=registers#port1|PORT1]] * 2 - communicates with computer's main memory. Please note that currently there are no protection mechanisms preventing accidental overwrite of vital memory ranges - use with caution, especially when employed as destination * ADDRESS is a 16 bit value denoting memory address within either currently selected VASYL memory (for ''PORT'' numbers ''0'' and ''1'') or Commodore 64 memory (for ''PORT'' number ''2'') * STEP is an optional, signed 8 bit value (-128..127) added to internal counter after each access. If omitted defaults to ''1'' * BANK is an optional number of VASYL memory bank. If omitted, defaults to currently selected VASYL memory bank. Ignored if given when configuring "conveyor" #2. __Examples__: VCFG 0,0 : REM CONFIGURE CONVEYOR 0 TO POINT TO ADDRESS $0000 WITH STEP 1 VCFG 0,0,1 : REM CONFIGURE CONVEYOR 0 TO POINT TO ADDRESS $0000 WITH STEP 1 VCFG 1,32768,-$80,3 : REM CONFIGURE CONVEYOR 1 TO POINT TO ADDRESS $8000 WITH STEP -128 IN BANK 3 VCFG 2,49152 : REM CONFIGURE CONVEYOR 2 TO POINT TO ADDRESS $C000 IN COMPUTER RAM WITH STEP 1 ==== VDATA ==== ---- STATEMENT: Stores '''' in VASYL memory through currently [[#vcfg|configured]] ''PORT'' __Synopsis__: ''VDATA '' * DATA is a stream of 8-bit byte values in form of * comma separated list of numbers in the range of 0..255 (or hexadecimal equivalents $00..$ff) * valid 8-bit hexadecimal numbers concatenated into single string __Examples__: 1000 VCFG 1,$200,2 1100 VDATA 12,$0d,1 : REM STORE 12 AT $0200, 13 AT $0202 AND 1 AT $0204 1000 VCFG 1,$200,2 1000 VDATA "0c0d01" : REM THE SAME AS PREVIOUS EXAMPLE __Discussion__: While CBM BASIC provides ''DATA'' and ''READ'' statements, which can be used to place binary data in VASYL memory 100 FOR I=0 TO 7 110 READ A 120 VPOKE $1000+I,A 130 NEXT I 140 DATA 0,6,14,15,1,15,14,6 this method is both inflexible and leaving much to be desired in terms of speed of execution. Both aspects become especially important when dealing with larger amounts of data. Using ''VDATA'' not only transfers the data much faster but also allows far greater flexibility 100 VCFG 1,$1000 110 VDATA 0,6,14,15,1,15,14,6 achieves the same results but requires no (slow) BASIC loop, no upfront knowledge of data stream length and moreover allows also a special "string" form 100 VCFG 1,$1000 110 VDATA "00060e0f010f0e06" ==== VDPOKE ==== ---- STATEMENT: Double POKE for VASYL memory __Synopsis__: ''VDPOKE
,'' * ADDRESS is a 16 bit value denoting memory address within currently selected VASYL memory * VALUE is a 16 bit (two byte) value to be "poked" into ADDRESS. Bytes are stored in [[wp>Endianness|Little-Endian]] order __Examples__: VDPOKE $1000,32768 : REM STORES $00 AT $1000 AND $80 AT $1001 VDPOKE $10FE,$FF : REM STORES $FF AT $10FE AND $00 AT $10FF ==== VLIST ==== ---- STATEMENT: Invoke displaylist disassembler __Synopsis__: ''VLIST [[,]]'' * START inclusive starting address of memory range to be disassembled * END exclusive end of memory address range to be disassembled __Examples__: VLIST VLIST 4096 VLIST $100 VLIST 256,512 __Discussion__: Disassembler can be invoked in three different ways - with no arguments - with one argument - with two arguments With no arguments disassembly begins from the next address after the last, previously disassembled one (or $0000 on the first invocation) and outputs full screen less one top and three bottom lines. This allows easy browsing of subsequent memory ranges by simply pressing ''HOME'' and ''RETURN'' to display next screen worth of disassembly VLIST When one argument is given, that argument determines the first VASYL memory address to be disassembled. Output is limited to one screen, the same as when no arguments are given VLIST $100 With two arguments, the second one determines the exclusive end of address range to be disassembled. Output is continuous and scrolling can be slowed down by holding ''CONTROL'' key depressed VLIST 256,512 ==== VPOKE ==== ---- STATEMENT: VASYL memory equivalent of the regular POKE statement. __Synopsis__: ''VPOKE
,'' * ADDRESS is a 16 bit value denoting memory address within currently [[#bank|selected]] VASYL memory bank * VALUE is an 8-bit byte value to be "poked" into ADDRESS __Examples__: VPOKE 4096,128 VPOKE $100,$FF ===== Both statements and functions ===== All the following keywords accept both statement (no parentheses) and function (with parentheses) methods of invocation. Obviously they behave differently depending on whether they are invoked as a statement or as a function ==== BANK ==== ---- STATEMENT: Set current VASYL RAM bank to __Synopsis__: ''BANK '' * BANK is an integer number in the range of 0...7, representing VASYL memory bank number to be selected __Examples__: BANK 1 FUNCTION: Returns currently selected VASYL RAM bank __Synopsis__: ''BANK()'' __Examples__: PRINT BANK() ==== RACER ==== ---- STATEMENT: Set BeamRacer status to __Synopsis__: ''RACER '' Where can be 0, 1, 2, 3 meaning * 0 - BeamRacer inactive * 1 - BeamRacer active but RUN/STOP-RESTORE combination deactivates it * 2 - BeamRacer active and automatically reactivated after every RUN/STOP-RESTORE (default) * 3 - Disable VBASIC without changing BeamRacer status (VBASIC V1.2 and higher) __Examples__: RACER 0 : REM DEACTIVATE BEAMRACER FUNCTION: Returns current status of BeamRacer Where returned value can be 0, 1, 2, 255 meaning * 0 - BeamRacer inactive * 1 - BeamRacer active but RUN/STOP-RESTORE combination deactivates it * 2 - BeamRacer active and automatically reactivated after every RUN/STOP-RESTORE (default) * 255 - BeamRacer not found __Synopsis__: ''RACER()'' __Examples__: 100 RS=RACER() 110 PRINT "BEAMRACER "; 120 IF RS=0 THEN PRINT "INACTIVE" 130 IF RS=1 THEN PRINT "TRANSIENT" 140 IF RS=2 THEN PRINT "ACTIVE" 150 IF RS=255 THEN PRINT "NOT FOUND" __Discussion__: When VBASIC is run, and BeamRacer is installed, the status of BeamRacer is set to ''2'', which means that it is activated and gets reactivated after every RUN/STOP-RESTORE combination. When BeamRacer is not installed, its status is set to ''255'' ==== VBADLINE ==== ---- DISPLAYLIST: Force a badline after ''RASTERLINES'' of rasterlines STATEMENT: Assembles [[:isa#badline|BADLINE ]] and stores the result in memory __Synopsis__: ''VBADLINE ['' * RASTERLINES is a 3-bit integer number in the range 0..7 __Examples__: VBADLINE 3 : REM NEXT BADLINE THREE LINES LATER FUNCTION: Returns assembled [[:isa#badline|BADLINE ]] __Synopsis__: ''VBADLINE()'' * RASTERLINES is a 3-bit integer number in the range 0..7 __Examples__: A = VBADLINE(3) : REM ASSEMBLE AND ASSIGN THE RESULT TO A VARIABLE __Discussion__: The command sets the vertical scroll bits in VIC-II ''SCROLY'' register to a calculated value that will trigger badline on requested positive, vertical offset from the current rasterline. It does NOT delay displaylist execution ==== VBRA ==== ---- DISPLAYLIST: Continue Display List execution at address
STATEMENT: Assembles [[:isa#bra|BRA
]] and stores the result in memory __Synopsis__: ''VBRA
|*'' * ADDRESS is a memory address within the -128..127 range from the current one * OFFSET is an 8-bit signed number from range -128..127 __Examples__: [...] 150 VSETA 12 160 LABEL A% [...] 190 VDECA 200 VBRA A% 999 VEND [...] 200 VBRA 100 : REM CONTINUE AT ADDRESS $64 999 VEND [...] 200 VBRA *-2 : REM INFINITE LOOP 999 VEND FUNCTION: Returns assembled [[:isa#bra|BRA ]] __Synopsis__: ''VBRA(*)'' __Examples__: A = VBRA(*+10): REM ASSEMBLE AND ASSIGN THE RESULT TO A VARIABLE __Discussion__: While it is technically possible to use VBRA(
) notation also in function mode, it is not very useful. ==== VDECA ==== ---- DISPLAYLIST: Decrement counter ''A'' or skip next instruction if zero reached STATEMENT: Assembles [[:isa#deca|DECA]] and stores the result in memory __Synopsis__: ''VDECA'' __Examples__: 100 VCFG 0,0 : REM ALWAYS CONFIGURE 110 VWAIT $33,0 : REM WAIT FOR FIRST PAPER LINE 120 VSETA 12 : REM TWELVE TIMES 130 LABEL A% : REM LOOP CODE BEGINS HERE 140 VMOV $21, 14 : REM LIGHT BLUE 150 VDELAYV 8 : REM DELAY EIGHT RASTERLINES 160 VMOV $21, 6 : REM DARK BLUE 170 VDELAYV 8 : REM DELAY EIGHT RASTERLINES 180 VDECA : REM DECREMENT COUNTER 190 VBRA A% : REM LOOP TO LABEL A% UNLESS COUNTER REACHED ZERO 999 VEND : REM ALWAYS CLOSE DISPLAYLIST OFF FUNCTION: Returns assembled [[:isa#deca|DECA]] __Synopsis__: ''VDECA()'' __Examples__: A = VDECA : REM ASSEMBLE AND ASSIGN THE RESULT TO A VARIABLE ==== VDECB ==== ---- DISPLAYLIST: Decrement counter ''B'' or skip next instruction if zero reached STATEMENT: Assembles [[:isa#decb|''DECB'']] and stores the result in memory __Synopsis__: ''VDECB'' __Examples__: VDECB : REM DECREMENT COUNTER B FUNCTION: Returns assembled [[:isa#decb|DECB]] __Synopsis__: ''VDECB()'' __Examples__: B = VDECB : REM ASSEMBLE AND ASSIGN THE RESULT TO A VARIABLE ==== VDELAYH ==== ---- DISPLAYLIST: Delays displaylist execution for given number of '''' STATEMENT: Assembles and stores [[:isa#delayh|DELAYH ]] in VASYL memory __Synopsis__: ''VDELAYH '' * CYCLES is a 6-bit integer number in the range 0..63 __Examples__: VDELAYH 3 : REM WAIT THREE CYCLES FUNCTION: Returns assembled [[:isa#delayh|DELAYH ]] __Synopsis__: ''VDELAYH()'' * CYCLES is a 6-bit integer number in the range 0..63 __Examples__: PRINT VDELAYH(3)&W : REM PRINT ASSEMBLED 3-CYCLE DELAYH AS HEX WORD __Discussion__: The '''' argument accepts values up to 63, which makes it easy to delay displaylist execution across rasterline boundary. While this is technically correct, please note that the number of cycles per rasterline varies between VIC variants. Crossing rasterline boundary with ''DELAYH'' leads therefore to VIC variant dependent code and should be avoided. Please see also note at [[:isa#delayh|DELAYH]] ==== VDELAYV ==== ---- DISPLAYLIST: Delays displaylist execution for given number of '''' STATEMENT: Assembles [[:isa#delayv|DELAYV ]] and stores the result in memory __Synopsis__: ''VDELAYV '' * RASTERLINES is a 9-bit integer number in the range 0..511 __Examples__: VDELAYV $28 : REM WAIT FORTY RASTERLINES FUNCTION: Returns assembled [[:isa#delayv|DELAYV ]] __Synopsis__: ''VDELAYV()'' * RASTERLINES is a 9-bit integer number in the range 0..511 __Examples__: PRINT VDELAYV(200)&W : REM PRINT ASSEMBLED 200-LINE DELAYV AS HEX WORD __Discussion__: Vertical delay AKA ''VDELAYV'' delays execution until the //beginning// (cycle 0) of the line coming specified number of lines later than the one this statement is executed. Please also note that on physical hardware the first cycles of each rasterline are located within "horizontal blanking interval", i. e. out of visible range. This means a program: VCFG 0,0 VWAIT $50,20 VDELAYV 10 VMOV $20,0 VMOV $20,14 VEND will NOT show the expected black dash, even if your display device is capable of showing all of the picture generated by the computer((Professional monitors are typically equipped with "underscan" function, which makes picture areas not normally visible to be displayed. Those cannot include horizontal and vertical "blanking intervals" though)). ==== VEND ==== ---- DISPLAYLIST: Close displaylist program off STATEMENT: Assembles [[:isa#end|END]] and stores the result in memory __Synopsis__: ''VEND'' __Examples__: VEND : REM END OF DISPLAYLIST FUNCTION: Returns assembled [[:isa#end|END]] __Synopsis__: ''VEND()'' __Examples__: A = VEND() : REM STORE ASSEMBLED END OF DISPLAYLIST BYTES IN A VARIABLE ==== VIRQ ==== ---- DISPLAYLIST: Send Interrupt Request (IRQ) STATEMENT: Assembles and stores [[:isa#irq|IRQ]] in memory __Synopsis__: ''VIRQ'' __Examples__: VIRQ : REM TRIGGER INTERRUPT REQUEST FUNCTION: Returns assembled [[:isa#irq|IRQ]] __Synopsis__: ''VIRQ()'' __Examples__: ?VIRQ() : REM PRINT IRQ AS 8-BIT NUMBER __Discussion__: Check also [[:isa#irq|IRQ]] for more details ==== VMASKH ==== ---- DISPLAYLIST: Set mask for next horizontal target comparison to STATEMENT: Assembles and stores [[:isa#maskh|MASKH ]] (''P'' bit cleared) in memory __Synopsis__: ''VMASKH '' * MASKVALUE is a 6-bit wide bit mask number in the range 0..63 __Examples__: VMASKH 7 : REM ONLY THREE LOWER BITS COUNT ON NEXT HORIZONTAL COMPARISON FUNCTION: Returns [[:isa#maskh|MASKH ]] assembled with ''P'' bit cleared __Synopsis__: ''VMASKH()'' * MASKVALUE is a 6-bit wide bit mask number in the range 0..63 __Examples__: ?VMASKH(7) : REM PRINT ASSEMBLED MASKH WITH P BIT CLEARED AND THREE LSB ACTIVE __Discussion__: Setting non-standard mask value right before ''VEND'' is highly discouraged as it may lead to undesirable results. For more information check also [[:isa#maskh|MASKH]] ==== VMASKPH ==== ---- DISPLAYLIST: Set mask for all horizontal targets comparison to STATEMENT: Assembles and stores [[:isa#maskh|MASKH ]] (''P'' bit set) in memory __Synopsis__: ''VMASKPH '' * MASKVALUE is a 6-bit wide bit mask number in the range 0..63 __Examples__: VMASKPH 7 : REM ONLY THREE LOWER BITS COUNT ON HORIZONTAL COMPARISONS FUNCTION: Returns [[:isa#maskh|MASKH ]] assembled with ''P'' bit set __Synopsis__: ''VMASKPH()'' * MASKVALUE is a 6-bit wide bit mask number in the range 0..63 __Examples__: ?VMASKPH(7) : REM PRINT ASSEMBLED MASKH P BIT SET AND THREE LSB ACTIVE __Discussion__: Setting non-standard mask value right before ''VEND'' is highly discouraged as it may lead to undesirable results. Check also [[:isa#maskh|MASKH]] ==== VMASKPV ==== ---- DISPLAYLIST: Set mask for all vertical target comparison to <> STATEMENT: Assembles [[:isa#maskv|MASKV]] with ''P'' bit set and stores it in memory __Synopsis__: ''VMASKPV '' * MASKVALUE is a 9-bit wide bit mask number in the range 0..511 __Examples__: VMASKPV 127 : REM SEVEN LOWER BITS COUNT ON VERTICAL COMPARISONS FUNCTION: Returns [[:isa#maskv|MASKV]] assembled with ''P'' bit set __Synopsis__: ''VMASKPV()'' * MASKVALUE is a 9-bit wide bit mask number in the range 0..511 __Examples__: PV = VMASKPV(127) : REM SEVEN LOWER BITS COUNT ON VERTICAL COMPARISONS __Discussion__: Setting non-standard mask value right before ''VEND'' is highly discouraged as it may lead to undesirable results. For more information see also [[:isa#maskv|MASKV]] ==== VMASKV ==== ---- DISPLAYLIST: Set mask for next vertical target comparison to STATEMENT: Assembles [[:isa#maskv|MASKV]] with ''P'' bit cleared and stores result in memory __Synopsis__: ''VMASKV '' * MASKVALUE is a 9-bit wide bit mask number in the range 0..511 __Examples__: VMASKV 127 : REM SEVEN LOWER BITS COUNT ON NEXT VERTICAL COMPARISON FUNCTION: Returns [[:isa#maskv|MASKV]] assembled with ''P'' bit cleared __Synopsis__: ''VMASKV()'' * MASKVALUE is a 9-bit wide bit mask number in the range 0..511 __Examples__: V = VMASKV(127) : REM SEVEN LOWER BITS COUNT ON NEXT VERTICAL COMPARISON __Discussion__: Setting non-standard mask value right before ''VEND'' is highly discouraged as it may lead to undesirable results. For more information check also [[:isa#maskv|MASKV]] ==== VMOV ==== ---- DISPLAYLIST: Store in STATEMENT: Assembles [[:isa#mov|MOV]] and stores the result in memory __Synopsis__: ''VMOV ,'' * REGISTER is a 6-bit number in the range 0..63 * VALUE is an 8-bit number in the range of 0..255 __Examples__: VMOV $20,3 : REM SET BORDER COLOUR TO CYAN VMOV $43,128 : REM STROBE DISPLAYLIST EXECUTION IN ANOTHER BANK FUNCTION: Returns assembled [[:isa#mov|MOV]] __Synopsis__: ''VMOV(,)'' * REGISTER is a 6-bit number in the range 0..63 * VALUE is an 8-bit number in the range of 0..255 __Examples__: BR = VMOV($20,3) : REM STORE ASSEMBLED VMOV TO A VARIABLE SR = VMOV($43,128) : REM STROBE DISPLAYLIST EXECUTION IN ANOTHER BANK __Discussion__: REGISTER can refer to either VIC-II or VASYL register. Depending on REGISTER value falling into one of the three possible ranges it can refer to - ''$00..$2e'' - VIC-II registers, accessible by CPU in the ''$d000..$d02e'' address range. Gets assembled as [[:isa#mov|MOV]] - ''$31..$3e'' - bus accessible VASYL registers. CPU can access them in the ''$d031..$d03e'' address range. Gets assembled as [[:isa#mov|MOV]] - ''$40..$4c'' - VASYL internal registers. Not available for the CPU. Can only be acessed by VASYL himself, while executing displaylist programs. Gets assembled as [[:isa#movi|MOVI]] Please note that writing to VIC-II and VASYL registers from within a displaylist program differs substantially in the way it is technically executed. Writing to VIC-II registers requires bus access and cannot happen during time periods when VIC occupies the bus completely (e. g. during "badlines"). Writing to VASYL registers on the other hand can be done internally and is therefore not restricted by bus availability. Please also check notes at [[:isa#mov|MOV]] and [[:isa#movi|MOVI]] for additional information. ==== VNOP ==== ---- DISPLAYLIST: Does nothing (other than using one cycle) STATEMENT: Assembles [[:isa#vnop|VNOP]] and stores it in memory __Synopsis__: ''VNOP'' __Examples__: VNOP : REM USE A CYCLE FUNCTION: Returns assembled [[:isa#vnop|VNOP]] __Synopsis__: ''VNOP()'' __Examples__: NP = VNOP() : REM ASSIGN ASSEMBLED VNOP TO A VARIABLE __Discussion__: As useless as it looks, among other uses: * cheap yet precise fine-tuning of displaylist program timing * displaylist program space reservations * address alignment of displaylist program sections * … can be achieved by careful placement of VNOP opcodes in the displaylist programs. ==== VSETA ==== ---- DISPLAYLIST: Set counter A to STATEMENT: Assembles [[:isa#seta|SETA]] and stores the result in memory __Synopsis__: ''VSETA '' * VALUE is an 8-bit integer number in the range of 0..255 __Examples__: VSETA 12 : REM TWELVE TIMES 100 VCFG 0,0 : REM ALWAYS CONFIGURE 110 VWAIT $33,0 : REM WAIT FOR FIRST PAPER LINE 120 VSETA 12 : REM TWELVE TIMES 130 VLABEL A% : REM LOOP CODE BEGINS HERE 140 VMOV $21, 14 : REM LIGHT BLUE 150 VDELAYV 8 : REM DELAY EIGHT RASTERLINES 160 VMOV $21, 6 : REM DARK BLUE 170 VDELAYV 8 : REM DELAY EIGHT RASTERLINES 180 VDECA : REM DECREMENT COUNTER 190 VBRA A% : REM LOOP TO LABEL A% UNLESS COUNTER REACHED ZERO 999 VEND : REM ALWAYS CLOSE DISPLAYLIST OFF FUNCTION: Returns assembled [[:isa#seta|SETA]] __Synopsis__: ''VSETA()'' * VALUE is an 8-bit integer number in the range of 0..255 __Examples__: ?VSETA(12)&W : REM PRINT ASSEMBLED SETA VALUE AS HEX WORD __Discussion__: See also [[#vdeca|VDECA]] and [[:isa#seta|SETA]] for more information ==== VSETB ==== ---- DISPLAYLIST: Set counter B to <> STATEMENT: Assemble [[:isa#setb|SETB]] and store the result in memory __Synopsis__: ''VSETB '' * VALUE is an 8-bit integer number in the range of 0..255 __Examples__: VSETB 210 FUNCTION: Returns assembled [[:isa#setb|SETB]] __Synopsis__: ''VSETB()'' * VALUE is an 8-bit integer number in the range of 0..255 __Examples__: CNT = VSETB(48) : REM ASSIGN ASSEMBLED SETB TO A VARIABLE __Discussion__: See also [[#vdecb|VDECB]] and [[:isa#setb|SETB]] for more information ==== VSKIP ==== ---- DISPLAYLIST: Make following ''WAIT'' skip an instruction if past the target STATEMENT: Assembles [[:isa#skip|SKIP]] and stores the result in memory __Synopsis__: ''VSKIP'' __Examples__: VSKIP : REM SKIP TWO BYTES AFTER NEXT WAIT IF PAST TARGET FUNCTION: Returns assembled [[:isa#skip|SKIP]] __Synopsis__: ''VSKIP()'' __Examples__: ?VSKIP() : REM PRINT ASSEMBLED SKIP VALUE __Discussion__: Check also [[:isa#skip|SKIP]] ==== VWAIT ==== ---- DISPLAYLIST: Wait until cycle of rasterline STATEMENT: Assembles [[:isa#wait|WAIT]] and stores the result in memory __Synopsis__: ''VWAIT ,'' * H is a 6-bit integer number in the range 0..63 * V is a 9-bit integer number in the 0..511 range __Examples__: VWAIT $26,$0A : REM WAIT UNTIL FIRST VISIBLE CYCLE OF RASTERLINE $26 FUNCTION: Returns assembled [[:isa#wait|WAIT]] __Synopsis__: ''VWAIT(,)'' * H is a 6-bit integer number in the range 0..63 * V is a 9-bit integer number in the 0..511 range __Examples__: WT = VWAIT($26,$0A) : REM ASSIGN ASSEMBLED WAIT TO A VARIABLE __Discussion__: More information available in the [[:isa#wait|WAIT]] opcode description ==== VWAITBAD ==== ---- DISPLAYLIST: Delays displaylist execution until beginning (cycle 0) of a rasterline immediately __preceding__ the next badline. STATEMENT: Assemble [[:isa#waitbad|WAITBAD]] and store the result in memory __Synopsis__: ''VWAITBAD'' __Examples__: VWAITBAD : REM WAIT FOR A LINE BEFORE NEXT BADLINE FUNCTION: Return assembled [[:isa#waitbad|WAITBAD]] __Synopsis__: ''VWAITBAD()'' __Examples__: ?VWAITBAD() __Discussion__: Check also notes at [[:isa#waitbad|WAITBAD]] for more information ==== VWAITREP ==== ---- DISPLAYLIST: Wait for VASYL's to finish repeating writes STATEMENT: Assemble [[:isa#waitrep|WAITREP]] and store the result in memory __Synopsis__: ''VWAITREP '' __Examples__: VWAITREP 0 : REM WAIT FOR PORT 0 TO FINISH REPEATING WRITES FUNCTION: Returns assembled [[:isa#waitrep|WAITREP]] __Synopsis__: ''VWAITREP()'' __Examples__: WR = VWAITREP(0) : REM ASSIGN ASSEMBLED WAITREP TO A VARIABLE __Discussion__: Check [[:isa#waitrep|WAITREP]] for more details ==== VXFER ==== ---- DISPLAYLIST: Transfer byte TO from STATEMENT: Assembles [[:isa#xfer|XFER]] and stores the result in memory __Synopsis__: ''VXFER ,'' * is a 7-bit unsigned integer in the range 0..127 * is a 1-bit unsigned value in the range 0..1 __Examples__: VXFER $20,1 : REM READ BYTE FROM PORT1 WRITE TO EXTCOL ($D020) 100 REM PREPARE DATA - STORE $00 TO $0F STARTING AT $100 110 FOR I=0 TO 15:POKE $100+I,I:NEXT I 120 VCFG 0,0 : REM CONFIGURE PORT0 130 REM CONFIGURE PORT1 FROM WITHIN THE DISPLAYLIST 140 VMOV $38,15:VMOV $39,1 : REM POINT IT TO $10F 150 VMOV $3A,255 : REM WITH STEP -1 160 VSETA 15 : REM OUR COLOUR COUNTER 170 VWAIT $26,$0A : REM WAIT UNTIL FIRST VISIBLE CYCLE OF RASTERLINE $26 180 LABEL A% : REM LOOP TARGET 190 VXFER $20,1 : REM TRANSFER TO EXTCOL REGISTER FROM PORT1 200 VDECA 210 VBRA A% : REM BRANCH TO PREVIOUSLY DEFINED LABEL 999 VEND 1000 DLON FUNCTION: Returns assembled [[:isa#xfer|XFER]] __Synopsis__: ''VXFER(,)'' * REGISTER is a 7-bit unsigned integer in the range 0..127 * PORT is a 1-bit unsigned value in the range 0..1 __Examples__: ?VXFER($20,1) : REM PRINT VALUE OF ASSEMBLED XFER $20,1 __Discussion__: There are seven bits reserved for REGISTER value, even if currently only numbers in the range of $00..$4e are valid. XFER does not require port to be set for reading. See also [[:isa#xfer|XFER]] for more details ====== Program Examples ====== TBD