Table of Contents
Introduction
If you followed the 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 oneBYTE
(eight bit)W
- for oneWORD
(16 bit)L
- for oneLONG
(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 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 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 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 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 "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 [<START>[,<END>]]
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 <ADDRESS> in main computer address space
Synopsis: DPEEK(<ADDRESS>)
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 <VALUE> interpreted as 16-bit unsigned integer
Synopsis: LO(<VALUE>)
Where <VALUE> 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 <VALUE> interpreted as 16-bit unsigned integer
Synopsis: LO(<VALUE>)
Where <VALUE> is a number in the 16-bit unsigned int range: 0..65535
Examples:
PRINT LO(53280)&B
VDPEEK
FUNCTION: Returns “double peek” value from <ADDRESS> in currently selected bank of VASYL memory
Synopsis: VDPEEK(<ADDRESS>)
Examples:
PRINT VDPEEK($100)&W
VPEEK
FUNCTION: Returns 8-bit value from <ADDRESS> in currently selected bank of VASYL memory
Synopsis: VPEEK(<ADDRESS>)
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>, #<FROM>, <LENGTH>
- 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 <ports>, the third one extends this form of memory access to cover also the main computer RAM.
Conveyors:
- 0 - communicates with VASYL memory through PORT0
- 1 - communicates with VASYL memory through 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>,<VALUE>
- 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 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>,<ADDRESS>[,<STEP>[,<BANK>]]
- CONVEYOR is a valid number of the “conveyor” to be configured (
0
,1
or2
)- 0 - communicates with VASYL memory through PORT0
- 1 - communicates with VASYL memory through 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 <bank> (for
PORT
numbers0
and1
) or Commodore 64 memory (forPORT
number2
) - 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 <DATA>
in VASYL memory through currently configured PORT
Synopsis: VDATA <DATA>
- 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>,<VALUE>
- ADDRESS is a 16 bit value denoting memory address within currently selected VASYL memory <bank>
- VALUE is a 16 bit (two byte) value to be “poked” into ADDRESS. Bytes are stored in 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>[,<END>]]
- 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>,<VALUE>
- ADDRESS is a 16 bit value denoting memory address within currently 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 <BANK>
Synopsis: BANK <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 <NUM>
Synopsis: RACER <NUM>
Where <NUM> 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 BADLINE <RASTERLINES> and stores the result in memory
Synopsis: VBADLINE [<RASTERLINES>
- RASTERLINES is a 3-bit integer number in the range 0..7
Examples:
VBADLINE 3 : REM NEXT BADLINE THREE LINES LATER
FUNCTION: Returns assembled BADLINE <RASTERLINES>
Synopsis: VBADLINE(<RASTERLINES>)
- 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 <address>
STATEMENT: Assembles BRA <ADDRESS> and stores the result in memory
Synopsis: VBRA <ADDRESS>|*<OFFSET>
- 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 BRA <OFFSET>
Synopsis: VBRA(*<OFFSET>)
Examples:
A = VBRA(*+10): REM ASSEMBLE AND ASSIGN THE RESULT TO A VARIABLE
Discussion: While it is technically possible to use VBRA(<ADDRESS>) notation also in function mode, it is not very useful.
VDECA
DISPLAYLIST: Decrement counter A
or skip next instruction if zero reached
STATEMENT: Assembles 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 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 ''DECB'' and stores the result in memory
Synopsis: VDECB
Examples:
VDECB : REM DECREMENT COUNTER B
FUNCTION: Returns assembled DECB
Synopsis: VDECB()
Examples:
B = VDECB : REM ASSEMBLE AND ASSIGN THE RESULT TO A VARIABLE
VDELAYH
DISPLAYLIST: Delays displaylist execution for given number of <CYCLES>
STATEMENT: Assembles and stores DELAYH <CYCLES> in VASYL memory
Synopsis: VDELAYH <CYCLES>
- CYCLES is a 6-bit integer number in the range 0..63
Examples:
VDELAYH 3 : REM WAIT THREE CYCLES
FUNCTION: Returns assembled DELAYH <CYCLES>
Synopsis: VDELAYH(<CYCLES>)
- 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 <CYCLES>
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 DELAYH
VDELAYV
DISPLAYLIST: Delays displaylist execution for given number of <RASTERLINES>
STATEMENT: Assembles DELAYV <RASTERLINES> and stores the result in memory
Synopsis: VDELAYV <RASTERLINES>
- RASTERLINES is a 9-bit integer number in the range 0..511
Examples:
VDELAYV $28 : REM WAIT FORTY RASTERLINES
FUNCTION: Returns assembled DELAYV <RASTERLINES>
Synopsis: VDELAYV(<RASTERLINES>)
- 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 computer1).
VEND
DISPLAYLIST: Close displaylist program off
STATEMENT: Assembles END and stores the result in memory
Synopsis: VEND
Examples:
VEND : REM END OF DISPLAYLIST
FUNCTION: Returns assembled 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 IRQ in memory
Synopsis: VIRQ
Examples:
VIRQ : REM TRIGGER INTERRUPT REQUEST
FUNCTION: Returns assembled IRQ
Synopsis: VIRQ()
Examples:
?VIRQ() : REM PRINT IRQ AS 8-BIT NUMBER
Discussion:
Check also IRQ for more details
VMASKH
DISPLAYLIST: Set mask for next horizontal target comparison to <MASKVALUE>
STATEMENT: Assembles and stores MASKH <MASKVALUE> (P
bit cleared) in memory
Synopsis: VMASKH <MASKVALUE>
- 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 MASKH <MASKVALUE> assembled with P
bit cleared
Synopsis: VMASKH(<MASKVALUE>)
- 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 MASKH
VMASKPH
DISPLAYLIST: Set mask for all horizontal targets comparison to <MASKVALUE>
STATEMENT: Assembles and stores MASKH <MASKVALUE> (P
bit set) in memory
Synopsis: VMASKPH <MASKVALUE>
- 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 MASKH <MASKVALUE> assembled with P
bit set
Synopsis: VMASKPH(<MASKVALUE>)
- 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 MASKH
VMASKPV
DISPLAYLIST: Set mask for all vertical target comparison to «VALUE»
STATEMENT: Assembles MASKV with P
bit set and stores it in memory
Synopsis: VMASKPV <MASKVALUE>
- 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 MASKV assembled with P
bit set
Synopsis: VMASKPV(<MASKVALUE>)
- 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 MASKV
VMASKV
DISPLAYLIST: Set mask for next vertical target comparison to <MASKVALUE>
STATEMENT: Assembles MASKV with P
bit cleared and stores result in memory
Synopsis: VMASKV <MASKVALUE>
- 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 MASKV assembled with P
bit cleared
Synopsis: VMASKV(<MASKVALUE>)
- 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 MASKV
VMOV
DISPLAYLIST: Store <VALUE> in <REGISTER>
STATEMENT: Assembles MOV and stores the result in memory
Synopsis: VMOV <REGISTER>,<VALUE>
- 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 MOV
Synopsis: VMOV(<REGISTER>,<VALUE>)
- 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 MOV$31..$3e
- bus accessible VASYL registers. CPU can access them in the$d031..$d03e
address range. Gets assembled as 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 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 MOV and MOVI for additional information.
VNOP
DISPLAYLIST: Does nothing (other than using one cycle)
STATEMENT: Assembles VNOP and stores it in memory
Synopsis: VNOP
Examples:
VNOP : REM USE A CYCLE
FUNCTION: Returns assembled 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 <VALUE>
STATEMENT: Assembles SETA and stores the result in memory
Synopsis: VSETA <VALUE>
- 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 SETA
Synopsis: VSETA(<VALUE>)
- 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:
VSETB
DISPLAYLIST: Set counter B to «VALUE»
STATEMENT: Assemble SETB and store the result in memory
Synopsis: VSETB <VALUE>
- VALUE is an 8-bit integer number in the range of 0..255
Examples:
VSETB 210
FUNCTION: Returns assembled SETB
Synopsis: VSETB(<VALUE>)
- 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:
VSKIP
DISPLAYLIST: Make following WAIT
skip an instruction if past the target
STATEMENT: Assembles SKIP and stores the result in memory
Synopsis: VSKIP
Examples:
VSKIP : REM SKIP TWO BYTES AFTER NEXT WAIT IF PAST TARGET
FUNCTION: Returns assembled SKIP
Synopsis: VSKIP()
Examples:
?VSKIP() : REM PRINT ASSEMBLED SKIP VALUE
Discussion:
Check also SKIP
VWAIT
DISPLAYLIST: Wait until cycle <H> of rasterline <V>
STATEMENT: Assembles WAIT and stores the result in memory
Synopsis: VWAIT <V>,<H>
- 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 WAIT
Synopsis: VWAIT(<V>,<H>)
- 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 WAIT opcode description
VWAITBAD
DISPLAYLIST: Delays displaylist execution until beginning (cycle 0) of a rasterline immediately preceding the next badline.
STATEMENT: Assemble WAITBAD and store the result in memory
Synopsis: VWAITBAD
Examples:
VWAITBAD : REM WAIT FOR A LINE BEFORE NEXT BADLINE
FUNCTION: Return assembled WAITBAD
Synopsis: VWAITBAD()
Examples:
?VWAITBAD()
Discussion:
Check also notes at WAITBAD for more information
VWAITREP
DISPLAYLIST: Wait for VASYL's <PORT> to finish repeating writes
STATEMENT: Assemble WAITREP and store the result in memory
Synopsis: VWAITREP <PORT>
Examples:
VWAITREP 0 : REM WAIT FOR PORT 0 TO FINISH REPEATING WRITES
FUNCTION: Returns assembled WAITREP
Synopsis: VWAITREP(<PORT>)
Examples:
WR = VWAITREP(0) : REM ASSIGN ASSEMBLED WAITREP TO A VARIABLE
Discussion:
Check WAITREP for more details
VXFER
DISPLAYLIST: Transfer byte TO <REGISTER> from <PORT>
STATEMENT: Assembles XFER and stores the result in memory
Synopsis: VXFER <REGISTER>,<PORT>
- <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 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 XFER
Synopsis: VXFER(<REGISTER>,<PORT>)
- 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 XFER for more details
Program Examples
TBD