For nearly every program that you will do you will need somewhere variables where you store and change your data. Vectrex has dedicated user RAM beginning at $c880 and going up to about $cba0. The user RAM end is not clearly defined, since the next used address is actually $cbea, but that address is the user stack, which grows downward.
Since it “grows downward” during your program execution (subroutines, local variables etc…) the lowest position of the stack is not clearly visible nor a fixed position. When you grow more experienced programming Vectrex, you might explore the limits for your own personal program more closely.
Anyway, RAM and Variables (Vide/Kingswood assembler syntax).
There are different ways you can “declare” variables. My personal ranking:
(all versions below do exactly the same) (and yes – in my Vectrex programers life I used all three versions – so if you see old code of mine – you might encounter not so good versions 🙂 )
data1 = $c880 data2 = $c881 data3 = $c882 ...
a little better, but not good:
startRAM = $c880 data1 = startRAM data2 = data1+1 data3 = data2+1 ...
bss org $c880 data1 ds 1 data2 ds 1 data3 ds 1 ...
Don’t think about the names. (bss stands for “Block Started by Symbol” ???)
Basically it tells the assembler that the next section of the program is supposed to go to RAM, and is uninitialized. You can only “reserve” space in the bss (memory) segement for runtime usage, you can not initialize it beforehand (e.g. with information about objects, like position, life etc…).
The major advantage of the “good” version is, that apart from the first “org” statement – the complete definition is “relative”. If you want to insert a variable – you can do “anywhere” without thinking about the consequences (within reason).
If you decide you want to change a variable from byte to word size – you just put a “2” behind the “ds” instead of a “1”.
If you need to swap two lines – than you do just that – swap two lines – you do not need to touch anything else.
If you are used to “modern” languages, you may not have heard of “segments” before. But for better understanding a very short explanation.
In assembler (and other languages) the memory of a computer/device is (virtually) split into segements. Depending on the memory layout different segements are possible. The most common segments are:
code, data and bss (others might be: text, stack or io).
Our interest lies in code and bss.
The code segement in Vectrex relation is ROM space. The space the user uses to code his program and which will ultimately be on the cartridge that plugs into the Vectrex cartridge port. Usually this is the memory range from $0000 to $7fff. Once the eprom is “burned” this memory is immutable and stays the same – always!
The bss segment in Vectrex relation denotes the RAM. Memory which can be changed during runtime, and which MUST be initialized (by code and data in the code segment). The RAM of the Vectrex ranges from $c800 to $cbff (the user RAM starts at $c880, the first 128 bytes are reserved for BIOS usage). The bss is NOT part of the cartridge, it must be setup by the programmer/program during runtime!
The assembler in Vide (and any other assembler) makes use of so called pseudo opcodes. These opcodes are not specific to a microprocessor and do not result in instructions generated for the microprocessor – but rather tell the assembler how to behave.
Above you saw three of those pseudo opcodes (there are many more, please look at the help file).
Tells the assembler that the following instructions are ment for the bss segment. This holds true until the assembler is told otherwise!
The instruction (pseudo opcode) to change (back) to the code segment is:
Until told otherwise, every segments starts at address $0000. Since we know (I told you so!) that Vectrex bss (for user RAM) starts at $c880 we tell the assembler exactly that with:
The assemblers internal address counter is now put to exactly $c880.
The internal address counter is automatically increased with every instruction that takes up memory!
Each segment has its own address counter! So if after the above org, you put in another “code“, the internal address counter for code is used subsequentially – which at the moment is still at $0000 (unless you put in some assembler instructions or another “org”).
The last pseudo opcode for now, ds which I don’t know what it stands for, perhaps “data sequence” or “data storage”? The pseudo opcode reserves a block of memory (in the above example 1 byte). Which in case of the bss segment simply advances the internal address counter by one.
This pseudo opcode has also an alias “rmb” (reserve memory block).
The usage with above “variable” names in front of the “ds”, simply match the “label” (= variable name) to the address where the current internal address memory counter is located. The ds advances the address pointer and thus “reserves” the amount of memory at that address to the label.
A “ds 1” reserves space for a byte. A “ds 2” reseveres space for a word…
Variables in RAM
I guess it is very VERY human to order coordinates first X and than Y. We learn that in school, while geocaching and on many other occasions.
With Vectrex it is always the other way around. It is always y and than x.
Than there is the CPU, 6809. It has a 16 bit register called “D”. And there are two “other” registers, 8 bit registers A and B.
The tricky thing is that register D is the same as A*256 + B. In “C”/”PASCAL” we would call that a union.
In HARDWARE those three registers are joined, always. This even goes so far that if you write:
That register D THAN contains the value of $10ff. Which also means the above two lines could have been written as:
Which is slightly shorter (less memory usage) and faster (faster!).
Now… Y, X coordinates. If your coordinates are stored in RAM like:
man_x ds 1
man_y ds 1
And you want to load these values and access BIOS functions you have to do:
since A comes before B and Y always comes before X. The BIOS always expects the y coordinate in register A and the X coordinate in register B.
Right from the beginning, you can “speed” up and save memory, if you place your coordinate variables the other way around, like:
man_y ds 1
man_x ds 1
Than you can happily load both coordinates in one go with:
Or if you want to be really obvious you could also:
man_yx ds 0
man_y ds 1
man_x ds 1
I can only guess. The Vectrex hardware has its quirks. One of them being is, that it is utterly impossible to the set the x coordinate before the y coordinate to the internal vector hardware.
Both values have to be set using only one DAC (digital to analog converter) .
The value that is put into the DAC can be switched to different destinations:
– yx integrator offsets
– audio hardware (playing samples)
As you see, none of the four possible values says “x-integrator” (which translated would be the x coordinate, the above mentioned y-integrator being the y coordinate).
This is because the x-integrator ALWAYS receives the DAC value.
What you do when you set vector coordinates is:
– switch the selector to y-integrator
– put the y value to DAC
– switch the selector off (none of the four mentioned destinations receive DAC values)
– than only the x-integrator receives the DAC values
Than both values are set – and you are ready to draw. So for “Vectrex hardware” programmers it is logical – Y comes before X!
This is great stuff to know when starting out… and great as a reminder of things I have read before, forgotten and, as such, not used in my latest coding.
More please 🙂
Lovely, reclaimed over half a K of space in my game with a first pass of these techniques 🙂
I cover some of these topics / tricks in my Vectrex C programming class, but in C and from the C programmer’s point of view. I will use this here as a reference and recommend reading it to the students, as this explains it all from an assembly lanugae programmer’s point of view. It perfectly complements the things we do in class. Thanks for writing this up.