In DVD Spec commands, there are only 8 registers available to the author, if he or she is using an abstraction-layer authoring system such as DVD Studio Pro, or 16 if there is no abstraction layer, such as in Creator or Scenarist, or if you replace the abstraction layer and author from scratch in DVDAfterEdit.
To make better use of these registers, each register can be split up into individual "fields" to be treated individually. Since registers contain 16 bits, there could be 16 individual bit fields that each kept track of a single on/off state. (Binary bits are either on or off). Or it could be split up into 4 fields of 4 bits each. (It is quite often useful to do this).
Bit fields don't translate to decimal values very well. For example, the rightmost (lowest) bit in a register has a value of 1. The highest bit has a value of 32768. The next highest bit has a value of 16384. (Notice these are all powers of 2). Combining or doing arithmetic on groups of these bits in decimal would be very tedious and confusing. But good news! Once you understand hexadecimal, it becomes much easier.
Hexadecimal is base 16 arithmetic. This means that each digit in hex has 16 possible values, instead of 10 in decimal or 2 in binary. This is very good for three reasons:
These facts all combine to make it easy to work in hexadecimal, as you will discover as you continue reading this document. If you plan to do extensive DVD Spec "scripting", it would be a good idea to buy an inexpensive hex calculator.
In hexadecimal notation, each digit is commonly referred to as a "nibble". The possible nibble values are:
[inline:51_hex_nibbles.gif=hexadecimal nibble values]
The DVD Spec uses registers that are 16 bits long. This equates to four nibbles of four bits each. This means a register can hold a value from 0 to FFFF in hex, which is 65,535 in decimal.
Typically in the DVD Spec, all values are positive numbers only. But almost all microprocessors, including all of those in DVD players, use "two's complement" arithmetic, which essentially allows you to think of these values as negative values if you wish. In two's complement arithmetic -1 is represented as $FFFF (we will use $ to represent hexadecimal numbers from here on out).
As an exercise let us add one to 9999 (decimal). We add one to the lowest 9, and get 10. We write down the zero and carry the one. We add the carry to the next digit, also 9, and get a similar result. When we finish we have 10000.
Now let us add one to $FFFF. We add one to the lowest F and get $10 (16). We write down the zero and carry the one, etc. When we are finished we have $10000. But only four nibbles fit in our register, so the last carry is thrown away, and the result is zero.
So you can see that in two's complement arithmetic, -1 + 1 still equals zero. For scripting purposes, we don't really need to know much more than that, except that it would is possible to store a negative value in a register, and our good old hex calculator will tell us what that value should be, if we need to know.
The DVD Spec uses the Boolean operators "and", "or", and "exclusive or". These operators only make sense using binary notation. But hex is a good way to organize your binary data into manageable chunks. With a little practice it is very quick to translate a hex number into binary by drawing out the nibbles on a piece of scratch paper, thus:
$06FF:
0000 0110 1111 1111
$1ABC:
0001 1010 1011 1100
(Please refer to the table, above, to get each nibble of the 16-bit hexadecimal number).
Then you can isolate the piece of the GPRM or SPRM you are interested in by drawing a long vertical line between the appropriate bits (counting from the right as bit 0), and apply the Boolean logic to it. (I'll explain Boolean logic in a moment).
For example, button numbers are stored in SPRM's and referenced starting with button number one having a value of 1024, or $0400. Button two is $0800, button 3 $0C00, etc.
So my example of button number one would be drawn thus:
0000 01|00 0000 0000
(On paper you would make the vertical bar taller.) If you draw all of the possible buttons out you will see that the 10 bits to the right of the button number are always zero. This means that scripting can keep track of a button number and still have 10 more bits to play with in the same GPRM!
This concept is extremely powerful, and is what permits complicated navigation with only 16 GPRM's. Essentially, GPRM's are very expensive, and commands are cheap since you can have up to 128 of them in each PGC, and you can have tons of PGC's.
Boolean Logic
The three Boolean operators used in DVD Spec commands are "and", "or", and "exclusive or". These operands are usually represented by the operators "&", "|", and "^".
Boolean operators are applied one bit at a time to two operands, and each bit in an operand is compared to the same bit in the other operand. The result of the compare is stored in the destination operand. (In DVD commands, the destination is always a GPRM, or a "temporary value" (never stored) in an if statement).
"and": If both bits are true (1), the resulting bit is true.
"or": If either bit is true, the resulting bit is true.
"exclusive or": If either bit is true, but not both, the resulting bit is true.
Some examples:
$0010 & $0011 = $0010
$0011 & $1000 = $0000
$0001 | $0010 = $0011
$0000 | $abcd = $abcd
$8000 ^ $8000 = $0000
$e000 ^ $4000 = $a000
etc.
An abstraction layer example
Following is an abstraction layer example from DVDSP 1.5, which was written before DVDSP 2.0 was shipped. Although the abstraction layers for the two products are different, the principles are the same.
This example was also written before DVDAfterEdit supported the hexadecimal preference for commands. Here in this update we will show the hexadecimal. For those who have read the previous version of this document, you will see that this makes the code much easier to follow.
If you look at a typical DVDSP 1.5 project, at the Video Title Set Menus, you will see that the first 20 lines of PGC 2 are always identical.
1: Set r15 = r8
2: Set r15 ^= $E000
3: if r15 & $8000 then GoTo Line 7
4: Set r14 = r8
5: Set r14 &= 7
6: Set Stream Audio r14
7: if r15 & $4000 then GoTo Line 13
8: Set r14 = r8
9: Set r14 /= 8
10: Set r14 &= 63
11: if r14 != $3F then Set r14 |= 64
12: Set Stream Subpic r14
13: if r15 & $2000 then GoTo Line 18
14: Set r14 = r8
15: Set r14 /= 512
16: Set r14 &= 15
17: Set Stream Angle r14
18: Set r8 = 0
19: Set r15 = r13
20: if r15 == 0 then Link Resume
This code is using a single GPRM, r8, to hold three flag bits and three values. Before reading any further, notice that $E000 has three bits on, $8000 has one of those same bits on, $4000 has another, and $2000 has another. Gee, there must be a method to this madness!
Here is a picture of the bits as they are arranged in register 8:
[inline:51_bits_arranged_reg8.gif=center,bits as they are arranged in register 8]
Now to describe each command line and what it does:
From here on out, the individual menus "do their thing", usually testing r13 for particular values to go to particular places.
Notice that the abstraction layer coding isn't particularly efficient in the number of instructions used, but is very efficient in its use of the bits in general parameters.
For example, the abstraction layer designer could have reversed the meaning of the three high-order bits in register 8, which would have saved the instructions which had to move the bits to another register and invert them in order to test each bit. But this sort of optimization is unimportant in typical navigation, since commands themselves execute in microseconds and there is room for 128 of them in each PGC. It is only when we actually jump to other domains and areas that navigation slows down.