Disclaimer: This information is provided as is. There may be errors in this information. You may use this information only if you agree that Minimalist / Coinop.org, its employees, and noted authors will never be held responsible for any damage, injury, death, mayhem, etc. caused by errors in the information. When working with high voltage, never work alone and always follow safety precautions.

Document Title: [cineinst.txt (text file)]

CINEINST.TXT

Preliminary description of the Cinematronics CPU and instruction set.

Version: 0.1
Date:    01/31/97
Author:  Zonn Moore
E-mail:  zonn@concentric.net  (as of the above date)

Released to the public domain by the author, distribute freely.
-----------------------------------------------------------------------------
                                  PREFACE

This information was gathered solely through the use of the program
'cinesim.c' and few digital data books, (and, well of course, a schematic
of the Cinematronics CPU.)  Any behavior left unanswered by this document
will most likely be answered by running CINESIM.EXE and carefully watching
the simulation, and a few hours glazing over data books.

This document was typed up 'very quickly' and I'm sure there are many
grammatical errors.  I don't believe the current layout is the most
logical way to describe the C-CPU.  My goal is to eventually type this up
in a nice WORD.DOC format, sometime in the future, but who knows when that
will be.  For now I hope this helps in C-CPU repair / program hacking /
writing diagnostic programs, etc.

The instruction set vaguely reminds me of the AB = D register of the 6803,
and 6809 CPUs.  And it just seemed that a Motorola type assembler would be
easiest to implement on this processor, so a Motorola type syntax is what
I used to describe the instructions.

For those not familiar with this syntax:

   All hex values are proceeded with a '$'.

   All immediate values are proceeded with a '#', otherwise Direct page
   is assumed.

   LDA and STA are used to load and store the Accumulator respectively.
   LDA = Load Accumulator, *NOT* Load A-reg.  An assembler that allowed
   you to specify which register to load would use the mnemonics 'LDAA'
   to load the 'A' register, and 'LDAB' to load the 'B' register.

I haven't written any programs to verify any of the following, so if you
find any blatant (or not so blatant) errors, please let me know.

An obvious omission is: How to draw vectors using the variable
intensities allowed in Solar Quest, Sundance (I wish!), and the colors
of Boxing Bugs.  I haven't yet documented these features (for lack of
time/hardware) and, they'll just have to wait for the next update of
this document.

Oh yeah, also missing is the coin counter operation (pretty simple, but
once again, it'll have to wait for the next update).

Enjoy!

-Zonn

************************ Cinematronic's CPU layout **************************

The C-CPU is a (mostly) Harvard Architecture design.  It runs on a four
phase 5 mhz clock, doing 99% of it's clocking on phase 03.  It consists of
two 12 bit accumulators, 24 input lines, 8 output lines, and 24 bits of
vector position outputs.  Also included is a timer/watchdog counter.

The standard unmodified (Rev. K) board uses 8k of ROM and 256 12-bit words
of RAM.

ROM memory cycles are limited to a minimum of three cycles per access,
allowing for use of 600ns (worst case) memory.  This allows for the use
of 450 to 500ns memories that were readily available at the time of the
CPU's design.

While the ROMs are accessed 16 bits at a time, the ROM data bus is only
8 bits wide.  8 bits of the ROM is latched for later use, this allows for
better throughput, while still maintaining a 600ns memory cycle time.

The RAM data bus is 12 bits wide.

The C-CPU consists of five software accessible registers:

   A = 12 bits, Primary accumulator
   B = 12 bits, Secondary accumulator
   P =  4 bits, Page register (holds RAM bank, and Jump to new page value)
   I =  8 bits, Points to last accessed RAM location
   J = 12 bits, Jump register.  Holds the destination of a 'JMP' instruction.

There are also two 12 bit line draw registers and a vector timer register
that are accessible through the accumulators.  These register are not
directly accessible but are mentioned here for later reference.

   X = 12 bits, X position of either the start or end of a vector.
   Y = 12 bits, Y position of either the start or end of a vector.
   T = 12 bits, Timer used to time the length of a vector draw.

There are six testable flags:

   MI or EI = Minus flag or External Input (depending upon hardware jumper)
   DR       = Drawing flag. Set if line being drawn.
   LT       = Compared value was less than the Accumulator.
   EQ       = Compared value was equal to the Accumulator.
   NC       = Set if last arithmetic function did not generate a carry
   A0       = Bit zero of the 'A' register was a '1' before last Acc access.

*************************** Addressing Modes ********************************

The C-CPU can have its instruction divided into five addressing modes:

   IMP = Implied.
   IMM = Immediate.
   DIR = Direct Page, using 'P' register.
   IND = Indirect through 'I' register.
   XLT = Translated through the Accumulators.

There are also two I/O instructions 'INP' and 'OUT'.

There are two addressing modes used to transfer memory in and out of the
accumulators.

   DIR = DIRECT PAGE.  A four bit value is given as part of the instructions
   opcode, this is used as the lower 4 bits of the memory's address.
   The upper 4 bits are taken from the 'P' register.  Together they make
   up the 8 bit address of RAM.

   IND = 'I' REGISTER ACCESS.  The 'I' register is an 8 bit register.
   Memory can be read/written using the value in the 'I' register as the
   address of RAM.

There are an additional three ways to manipulate/load the accumulators.

   IMM = LOAD IMMEDIATE.  A four bit value as part of the instructions
   opcode or an 8 bit value following the instruction can be
   loaded/added/subtracted from the accumulators.

   IMP = IMPLIED.  An action performed on an accumulator needs no external
   data.  This consists of the shift instructions.

   XLT = TRANSLATED.  For the most part the C-CPU is a harvard architecture,
   yet there is one instruction that allows access to the program code as
   data. The 'XLT' instruction uses the address in the accumulator as an
   address into the ROM area.  It loads the accumulator with the byte value
   located at that address.

   NOTE: Because of a side effect of the look ahead program counter, used
   to access ROM (in an attempt to speed up throughput), the instruction
   immediately following a 'XLT' instruction will be skipped (ignored).

Two other instructions that deal with Accumulator values are the I/O
instructions.

   The INP instruction is used to read a single input bit pointed to by the
   lower 4 bits of the INP opcode.  The bit is read into the 'A'
   accumulator's bit 0.  All other bits of the accumulator are set to zero.

   The INP instruction is also used to read the switch options.  This is
   done by using the 'B' accumulator.  In which case the switch referenced
   by the opcode will be read into bit-0 of the B-reg, all other bits being
   set to zero.  (See below for accessing the 'B' register.)

   The OUT instruction set the referenced output line to the *inverted*
   value of bit-0 of the accumulator.  Accumulator 'A' or 'B' can be used.

************************* Program Memory Layout *****************************

The program (ROM) consist of 2 to 8 4096 byte banks, depending upon board
configurations.

All banks start at address 000h and run through address FFFh.

Banking is done using the 'P' register, which is loaded with the new bank
address and a 'JPP' instruction is executed.  Program control will be
transferred to the page given in the 'P' register at the address given in
the 'J' register.

In a Star Castle (8k) type board the 'P' register values are:

   01 = Page 0
   02 = Page 1

For 16k (Solar Quest) boards the 'P' register values are:

   00 = Page 0
   01 = Page 1
   02 = Page 2
   03 = Page 3

I haven't looked at the Boxing Bugs schematic, but my initial guess is
the 'P' values would be an extension of the 16k values.

The mapping of ROM chips to memory is a bit unusual, and also changes per
board configurations.

The 'normal' EPROM configurations is:

Address 000 starts at socket T7 and the next address 001 is at
socket P7.  Address 002 is back in socket T7.  This continues for the
first bank of an 8k CPU board, or the first two banks of a 16k CPU board.
Addresses then continue in the same fashion throughout sockets U7 (even
addresses) and R7 (odd addresses).

Because PROMs can have their address/selection lines inverted from the
normal EPROM configuration, these can have their start address in either
the T7/P7 or U7/R7 pair.  I've seen both.

***************************** RAM memory Layout *****************************

The C-CPU's RAM is laid out in 16 banks of 16 registers, for 256 12 bit
RAM registers.

When using 'DIR' addressing the upper 'BANK' value is read from the 'P'
register, while the lower 4 bits are given as part of the opcode.  To
access RAM register 4 on bank 3 one would:

        LDP     #3      ; Load 'P' register to point to page 3
        LDA     4       ; Load accumulator 'A' with the value
                        ; at RAM location $34

When using the IND '[i]' address mode, then 'P' is not used.  The value
read is the value pointed at by the 8 bits in the 'I' register.

*************************** Register Descriptions ***************************

'A' and 'B' registers
---------------------

The CPU has two 12 bit Acc's A and B.  They can be linked together to form
a D register, B becomes the high order 12 bits, and A the low order.

 <------------ D-reg ----------->
       B-reg           A-reg
 [xxxx xxxx xxxx][xxxx xxxx xxxx]

The linkage is not perfect.  The low order bit of the B-reg can be shifted
into the high order bit of the A-reg using an 'ASRD' instruction.  On the
other hand the high order bit of the A-reg does not shift into the low
order bit of the B-reg during a 'LSLD' instruction.

When the B-reg is shifted right ('ASR' and 'LSR'), the sign bit is
always extended into the shift.  When referring to the B-reg, 'ASR' and
'LSR' perform the same function.

The A-reg can be logically or arithmetically shifted.  An 'ASR'
instruction when performed on the A-reg, will do a sign extended right
shift.  A 'LSR' instruction will cause the A-reg to be shifted right
with a zero being shifted into the high order bit.

The B and A registers combined hold the results of the 'MUL' instruction.
The 'MUL' performs one shift/add cycle of a full binary multiply. (Described
later.)


'B' register access
-------------------

All 'A' and 'B' accumulator instructions share them same opcodes.  To access
the 'B' register, a prefix instruction 'USB' must be executed. 

Any accumulator related instruction, immediately following a 'USB'
instruction, will use the 'B' register as its accumulator.  The 'USB'
prefix has no effect on non-accumulator instructions.

After the instruction following a 'USB' instruction has been executed,
the default accumulator will return to the 'A' register.

The 'USB' instruction is the instruction of choice to switch between 
accumulators.  But it should be noted that as a side effect of how the'
C-CPU was designed, any JMP instruction with bit-3 of its opcode cleared,
will setup the next instruction to use the 'B' register.  Close inspection
will show the 'JPP' instruction has it's bit-3 cleared.

NOTE: The 'JPP' instruction will setup the next instruction to use the
'B' accumulator.  Close inspection of disassembled shows that target
instruction of 'JPP's is usually a 'NOP' instruction, which does
nothing, but allows the 'A' register to be reset as the default accumulator.


'P' register
------------

The 'P' register is used to hold the current RAM memory bank, and the ROM
banked to be jumped to via the 'JPP' instruction.  (See program memory
layout.)

The 'P' can only be loaded using an immediate instruction 'LDP #x'.
(See RAM memory layout.)


'I' register
------------

The 'I' register is a special register that can only be used as an address.

It is always loaded by the use of any 'DIR' address mode instruction, and
continues to point to the last RAM location addressed until a new 'DIR'
address mode instruction is executed.  Ex:

        LDP     #$2     ; Point to bank 2 of RAM
        LDA     $7      ; Read RAM location $27 into 'A' register
        ADD     #1      ; Increment 'A' register
        STA     [i]     ; Write new value back to location $27

A simple way to load the 'I' register with an absolute location
is to use the 'CMP' instruction.  The 'I' register can also be loaded
from RAM, by reading the value pointed to by the 'I' register, into the
'I' register.  Ex:

        ; Routine for storing the B-reg at the address in RAM location $F5

        LDP     #$F     ; Point to bank $F of RAM
        CMP     $5      ; Set 'I' register to point to $F5
        LDI     [i]     ; Read value at $F5 into 'I' register
        USB             ; Use the B-reg
        STA     [i]     ; Store accumulator 'B' at RAM location [$F5]


'J' register
------------

The C-CPU's jump opcodes do not, in themselves, contain the destination
address of the jumps.  Instead all jumps jump to the address contained in
the 'J' register, which must be loaded previously to the execution of a
jump instruction.  Ex:

        ; Jump to location $125

        LDJ     #$125   ; Load 'J' register with destination
        JMP     [j]     ; Jump to address $125

Conditional jumps either jump to the value in 'J' or skip to the next
instruction, depending upon the value of the flag being tested.  Ex:

        ; Jump if 'ADD' does not overflow...

        LDJ     #$372   ; point to location $372
        LDP     #0      ; Point to bank 0
        LDA     $3      ; Get value at $03
        ADD     #$1A    ; Add $1A to value
        JNC     [j]     ; If no carry, jump to $372

        ; Else fall through to next instruction...

There is not 'CALL' instruction on a C-CPU, yet an effective subroutine
can still be written, if the proper use of RAM is enforced.  This is
possible because the 'J' register can be loaded from RAM using the
'I' register.  Assuming RAM location $00 is used as the "return"
address, a subroutine that adds 5 to RAM location $03 can be written as:

0100:   CLR             ; Clear the A-reg
0101:   ADD     #5      ; Load A-reg with 5
0102:   LDP     #0      ; Point to BANK 0
0103:   ADD     $3      : Add value at location $3
0104:   STA     [i]     ; Write new value to location $3
0105:   CMP     $0      ; Load the 'I' register with $00
0106:   LDJ     [i]     ; Load the return address into the 'J' register
0107:   JMP     [j]     : Return to calling routine

And a call to the above routine could be written as:

0300:   LDA     #$300   ; Load A-reg with $300
0301:   ADD     #$7     ; Load A-reg with $307 -- Return address
0302:   LDP     #0      ; Point to BANK 0
0303:   STA     $0      ; Set $00 to return address
0304:   LDJ     #$100   ; Point to subroutine
0306:   JMP     [j]     ; Jump to subroutine
0307:   ...             ; Subroutine returns here

The 'P' can be combined with the 'J' to create an address that extends
beyond the 12-bits used in one ROM bank.  Once program is running in a
new bank, all jump are local to that bank.  Ex:

        ; Jump to address $450 on ROM bank 2 (on a Solar Quest board)

        LDP     #2      ; Point to Bank 2
        LDJ     #$450   ; Point to address $450
        JPP     [j]     ; Jump with page extension to $2450

Flags
-----

Six flags are available to be used as condition jumps.

MI or EI flag.  These two flags are one of the same, depending upon the
the 'JMI' jumper on the Rev K. boards.  If the 'JMI' jumper is installed
then the CPU can jump on the value of Bit-11 of accumulator A or B.

EI flag. If 'JMI' not installed, then the EI flag is set depending upon
the external input on pin 10 of J4.  If this pin is High, the jump will
be taken. If Low, program execution continues with the next instruction
following the 'JEI'.

MI Flag.  Since the 'JMI' instruction was a bit of an after thought on
Cinematronic's part, this flag acts a little strangely, being delay by
one instruction.  This flag reflect the state of Bit-11 of the register
accessed two instructions ago.  Ex:

        LDJ     #$125   ; Point to location $125
        LDA     #$800   ; Set A reg to $800
        SUB     #1      ; subtract 1
        NOP             ; At this point the MI flag is still set
        JMI     [j]     ; The MI flag is reset at this point and this jmp
                        ; is not taken.

DR flag.  This flag indicates a vector is currently being drawn, and is 
set 11 cycles after the 'VDR' instruction is executed.  This flag should
be checked before each 'VIN' instruction to verify the previous vector is
finished drawing before starting a new one.

LT flag.  This flag is set/reset every time a Acc instruction is executed.
For many of the instructions this flag is rather meaningless.  When checked
after a 'CMP', it indicates the value compared with the accumulator is
less than value of the accumulator.  An unsigned compare is performed.

EQ flag.  This flag is set/reset every time a Acc instruction is executed.
For many of the instructions this flag is rather meaningless.  When checked
after a 'CMP', it indicates the value compared with the accumulator is
equal to value of the accumulator.

NC flag.  This flag is set/reset every time a Acc instruction is executed.
For many of the instructions this flag is rather meaningless.  When checked
after any accumulator arithmetic instruction, it indicates the arithmetic
instruction did not generate a Carry.  Subtract instructions are performed
using an 1's compliment addition, plus 1.  This might not always set the
C-flg as one would expect.  Ex:

        LDJ     #$125   ; Point to address $125
        CLR             ; Zero the A-register
        SUB     #1      ; Subtract 1 from A-register
        JNC     [j]     ; Program jumps to address $125

The above program will jump to address $125 because what it is actually
doing is:

   Adding the value $FFE (one's compliment of 1) to 0, then incrementing by
   one to get $FFF, since no overflow is generated, the carry flag is
   not set.

A0 flag.  This flag is set/reset every time a Acc instruction is executed.
For many of the instructions this flag is rather meaningless.  When checked
after any accumulator instruction it reflects the value of the 'A'
accumulator's bit 0 prior to the execution of the instruction.  Regardless
whether the A or B register was accessed, it always reflects the state
of accumulator 'A's bit 0 before the instruction was executed.


********************** Cinematronic's Instruction Set ***********************

The following is a description of the instructions available on the C-CPU.

For each instruction the Object code is given, followed by the Mnemonic,
followed by the number of 5mhz cycles used by the instruction, followed
by a brief description.

NOTE 1: On the jump instructions two cycle times are given.  The first is
the number of cycles used if the jump is not taken, the second is the
number of cycles used if the jump is taken.

NOTE 2: The number of cycles taken by the 'LLT' instruction is dependent
upon the values loaded into the A and B registers.

NOTE 3: The wait for timer instruction 'WAI' uses as many instructions as
are needed for the timer to tick.

NOTE 4: Many of the Opcodes between the E0-FF range are repeated.  Both
instructions perform the same function.

NOTE 5: Regardless of the number of cycles indicated by the instruction
the ROMs can not be accessed any faster than 600ns, therefore if too many
single cycle instruction are executed in a row, wait states will be
inserted to enforce the "3 cycles per ROM access" rule.

Object  Mnemonic        ; Cycles, Description

00      CLR             ; 1~ Clear Acc ('LDA #000')
0x      LDA     #x      ; 1~ Load Acc with 'x00'
1x      INP     x       ; 1~ Read bit 'x' into Bit-0 of Acc, clear upper bits
20 xx   ADD     #xx     ; 3~ Add 'xx' to Acc
2x      ADD     #x      ; 1~ Add 'x' to Acc
30 xx   SUB     #xx     ; 3~ Subtract 'xx' from Acc
3x      SUB     #x      ; 1~ Subtract 'x' from Acc
4c ba   LDJ     #abc    ; 3~ Load J register with immediate value 'abc'

; Any of the following jumps will setup the processor to use the B Acc
; if the next instruction uses the Acc.

50      JPP             ; 4~ Jmp to J-reg on P page, next inst uses B Acc
51      JMIB            ; 2/4~ Jump if Acc minus (if JMI jumper installed)
51      JEIB            ; 2/4~ Jump if Ext Input high (if JMI not installed)
52      JDRB            ; 2/4~ Jump if Drawing a vector
53      JLTB            ; 2/4~ Jump if last compare Less Than Acc
54      JEQB            ; 2/4~ Jump if last compare Equal to Acc
55      JNCB            ; 2/4~ Jump if C-flg cleared
56      JA0B            ; 2/4~ Jump if Bit0 of A-reg was set
57      USB             ; 2~ NOP, next instruction uses B Acc

; Any of the following jumps do not effect the B Acc usage (except to
; reset usage to the A accumulator, as any other instruction)

58      JMP             ; 4~ Jump to J register (All jumps jump to J-reg)
59      JMI             ; 2/4~ Jump if Acc minus (if JMI jumper installed)
59      JEI             ; 2/4~ Jump if Ext Input high (if JMI not installed)
5A      JDR             ; 2/4~ Jump if Line Draw true
5B      JLT             ; 2/4~ Jump if last compare Less Than Acc
5C      JEQ             ; 2/4~ Jump if last compare Equal to Acc
5D      JNC             ; 2/4~ Jump if C-flg cleared
5E      JA0             ; 2/4~ Jump if Bit0 of A-reg was set
5F      NOP             ; 2~ NOP, Jump never

6x      ADD     x       ; 3~ Add to Acc value at address 'Px'
7x      SUB     x       ; 3~ Subtract from Acc value at address 'Px'
8x      LDP     #x      ; 1~ Load P-reg with 'x'
9x      OUT     x       ; 1~ Set external bit 'x' to inversion of Bit0 of Acc
Ax      LDA     x       ; 3~ Load Acc with value at 'Px'
Bx      CMP     x       ; 3~ Compare Acc with value at 'Px'
Cx      LDI     x       ; 3~ Load I-reg with value at 'Px'
Dx      STA     x       ; 2~ Store value in Acc at 'Px'

E0      VDR             ; 1~ Set end positions, draw vector

E1      LDJ     [I]     ; 2~ Load J-reg with value pointed to by I-reg

E2 xx   XLT             ; 7~ Load Acc with value from ROM at address in Acc (xx ignored)

E3      MUL     [I]     ; 2~ Shift D right, if A-reg Bit0 set, add [I] to B

E4      LLT             ; n~ Load line length timer with length of line

E5      WAI             ; n~ Wait for next tick of WDT clock (2 ticks resets)

E6      STA     [I]     ; 2~ Store Acc at [I]
E7      ADD     [I]     ; 2~ Add Acc with value pointed to by [I]
E8      SUB     [I]     ; 2~ Sub value at '[I]' from Acc
E9      AND     [I]     ; 2~ And value at '[I]' with Acc
EA      LDA     [I]     ; 2~ Load Acc with value at '[I]'

EB      LSR             ; 1~ Logical Shift Right (B-reg sign extends)
EC      LSL             ; 1~ Logical Shift Left
ED      ASR             ; 1~ Arithmetic Shift Right (Extends sign flag in Acc)
EE      ASRD            ; 1~ Shift Right Double (Sign extended, pri->sec)
EF      LSLD            ; 1~ Shift Left Double (No carry from pri to sec)

F0      VIN             ; 1~ Set initial vector position at Ext Acc's address

E1      LDJ     [I]     ; 2~ Load J-reg with value pointed to by I-reg

F2 xx   XLT             ; 7~ Load Acc with value from ROM at address in Acc (xx ignored)

F3      MUL     [I]     ; 2~ Shift D right, if A-reg Bit0 set, add [I] to B

F4      LLT             ; n~ Load line length timer with length of line

F5      WAI             ; n~ Wait for one tick of WDT clock (2 ticks resets)

F6      STA     [I]     ; 2~ Store Acc at [I]
F7      AWD     [I]     ; 2~ Same as 'ADD [I]', but resets Watch dog timer
F8      SUB     [I]     ; 2~ Sub value at '[I]' from Acc
F9      AND     [I]     ; 2~ And value at '[I]' with Acc
FA      LDA     [I]     ; 2~ Load Acc with value at '[I]'

FB      LSR             ; 1~ Logical Shift Right (B-reg sign extends)
FC      LSL             ; 1~ Logical Shift Left
FD      ASR             ; 1~ Arithmetic Shift Right (Extends sign flag in Acc)
FE      ASRD            ; 1~ Shift Right Double (Sign extended, pri->sec)
FF      LSLD            ; 1~ Shift Left Double (No carry from pri to sec)


Multiply
________

The multiply instruction performs one cycle of a binary shift and add
multiply algorithm.  To perform a 12 x 12 bit multiply 12 instructions
in a row must be executed.  Ex:

        ; Multiply the values $784 by $200

        LDP     #0      ; Use bank zero
        LDA     #$700   ; Load A-reg with $700
        ADD     #$84    ; Load A-reg with $784
        STA     3       ; Store at RAM location 3
        LDA     #$200   ; Load A-reg with $200
        USB             : use B-reg
        CLR             ; Clear the B-reg

        MUL     [i]     ; Multiply the value in the A-reg with [i]
        MUL     [i]
        MUL     [i]
        MUL     [i]

        MUL     [i]
        MUL     [i]
        MUL     [i]
        MUL     [i]

        MUL     [i]
        MUL     [i]
        MUL     [i]
        MUL     [i]

        ; The resultant value in the 'D' ('B' combined with 'A') register
        ; is: D = $784 * $200


Watch Dog Timer
---------------

The watch dog / tick timers runs at a 38hz rate.  The instruction 'WAI'
will stop the processor and wait for the tick timer to tick once.

If the tick timer ticks twice without a subsequent 'AWD' instruction being
executed, a watch dog time-out will result.  The C-CPU will reset itself
and execution will restart at address 0000h.


Drawing Vectors
---------------

The responsibility of refreshing the vector screen lies completely on the
C-CPU processor.  There is no "vector refresh engine" like that which exists
on the Atari and Sega X/Y hardware.  Instead all refreshing is the
responsibility of the software and all vector refreshes must be intermingled
with game logic, similar to a program written for the Vectrex home arcade.

Drawing a vector can be broken down into 4 steps:

Step 1 - Set the intensity bit accessed by using the 'OUT 6' instruction.
To set a vector to BRIGHT, the output bit 6 must be at logic zero.  Since
the 'OUT' instruction uses the inversion of bit 0 of the Acc, to set
vector draws to BRIGHT, load the Acc with 1, and execute an 'OUT 6'
instruction.  Ex:

        CLR             ; Reset bit zero of A-reg
        OUT     6       ; Set vector draws to LOW intensity
or:
        CLR             ; Clear A-reg
        ADD     #1      ; Set A-reg to 1
        OUT     6       ; Set vector draws to BRIGHT (high) intensity

Step 2 - Verify that the previous vector is done drawing.  This is done
using the 'JDR' instruction.  Usually the 'JDR' loops back on itself until
the current vector is done being drawn.  Though this is a good time to steal
some cycles if the vector being drawn is known to be a long one.

Step 3 - Load the X and Y starting positions.  This is done by loading the
X position into the B-reg and the Y position into the A-reg.  And then
executing a 'VIN' instruction.  This initializes the line draw sequence
by loading the DACs on the monitor with the starting X and Y values and
charging the integration capacitors to this starting value.  This
instruction also resets the Line Length counter.

Step 4 - Load the length of the Vector into the Line Length Timer.  This is
done by subtracting the Start positions of the vectors from the End
positions, to calculate vector length, and then executing a 'LLT'
instruction.  This instruction shifts the A and B registers left until
bit-11 of the A-reg does not match bit-9 of the A-reg, or bit-11 of the
B-reg does not match bit-9 of the B-reg.  Each shift also clocks a new
value into the Line Length register.  The proper values for the Line
Length register have been stored in PROM E8, saving the programmer the
work of performing a table lookup in software.

Note 1: Before executing the 'LLT' instruction some time must be wasted
to allow the hardware to charge the capacitor and stabilize.  This is done
with a small software timing loop.

Note 2: If both the A-reg and B-reg contain 0 at the execution of the 'LLT'
instruction the C-CPU will hang, and eventually reset do to the timing out
of the watch dog timer.  To draw a point, place a 1 into the A-reg, clear
the B-reg, execute the 'LLT', then use the same ending positions as your
starting positions when executing the 'VDR'.  Placing a 2, 4, 8 etc. in
the A-reg would allow the CRT beam to be held longer on one spot, allowing
for more than just the two intensities afforded line vectors.

Step 4 - Set ending points and draw vector.  This is done by placing the
ending X position into the B-reg and the ending Y position into the A-reg
and executing a 'VDR' instruction.  The drawing of the line begins 11
cycles after the execution of the 'VDR' instruction, and before this time
a 'JDR' instruction would indicate the previous line is done being drawn.

Perhaps an example is in order:

              ; $4 = Start Y position of vector to be drawn
              ; $5 = End Y position of vector to be drawn
              ; $6 = Start X position of vector to be drawn
              ; $7 = End X position of vector to be drawn
              ;
              ; $F = Return address
              ;
              ; All addresses are located in the current bank
              ; and the 'P' register is left unchanged.
              ;
              ; It is assumed the intensity of the line has already
              ; been set using the 'OUT 6' instruction.

00F0: A4      lda     $4       ; Get Start Y in A-reg
00F1: 57      usb
00F2: A6      lda     $6       ; Get start X in B-reg
00F4: 45 F0   ldj     #$0F5    ; Point to next instruction
00F5: 5A      jdr     [j]      ; Loop until previous draw in done
00F6: F0      vin              ; Set starting address, reset Line Length reg
00F7: 08      lda     #$800    ; Setup A-reg for timing loop
00F8: 20 41   add     #$41     ; $841 = Loop $41 times
00FA: 4C F0   ldj     #$0FC    ; Point to next instruction
00FC: 31      sub     #$1      ; Decrement timing loop counter
00FD: 5F      nop              ; MI flag not set until next instruction
00FE: 59      jmi     [j]      ; If A-reg still negative, loop
00FF: A5      lda     $5       ; Get Y end position in A-reg
0100: 74      sub     $4       ; Subtract start to get length
0101: 57      usb
0102: A7      lda     $7       ; Get X end position in B-reg
0103: 57      usb
0104: 76      sub     $6       ; Subtract start to get length
0105: E4      llt              ; Load the Line Length Timer
0106: 64      add     $4       ; Add Y start to A-reg to get Y end
0107: 57      usb
0108: 66      add     $6       ; Add X start to B-reg to get X end
0109: E0      vdr              ; Start vector drawing
010A: BF      cmp     $F       ; Set I-reg to point to return address
010B: E1      ldj     [i]      ; Load J-reg with return address
010C: 58      jmp     [j]      ; Return to caller
}