User Tools

Site Tools


vbasic

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 in order to provide correct information about available memory and enable seamless experience with all the standard behaviour for STOP, STOP/RESTORE etc. working as usual, while actively maintaining both the VBASIC extension and BeamRacer active.

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 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 DISPLAULIST 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 or 2)
    • 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 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 <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

  1. with no arguments
  2. with one argument
  3. 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 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)

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 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 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

  1. $00..$2e - VIC-II registers, accessible by CPU in the $d000..$d02e address range. Gets assembled as MOV
  2. $31..$3e - bus accessible VASYL registers. CPU can access them in the $d031..$d03e address range. Gets assembled as MOV
  3. $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:

See also VDECA and SETA for more information

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:

See also VDECB and SETB for more information

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

1)
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
vbasic.txt · Last modified: 2020/09/27 12:16 by silverdr