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.html (html file)]

Cinematronics CPU and instruction set.

Version: 1.0

Date:    07/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.

Revision History:


Version 0.1, 01/31/97

   Initial release.

Version 1.0, 07/31/97

   Added Color and Intensity descriptions.

   Added Description of the Coin Counter.

   Fixed some bugs in the Vector Draw description (I had the registers


   Removed the '[j]' operand from the jump instruction, it was misleading

   and redundant, since the only thing a jump instruction can do is jump

   to the address in the 'j'.  (And certainly not the address that 'j' is

   pointing to, ie: '[j]').



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.

My hope is this document 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 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.


************************ 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 page, and Jump to new ROM bank 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 not directly accessible, though can be set through the use of

the vector instructions.  They 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'.

Two addressing modes are used to transfer memory in and out of the


   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.  These 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 side effects 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


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

   All DIP switches and control panel switches are normally high, and go low

   when the DIP switch is switched on, or the control panel switch is


   The OUT instruction sets 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.

ROM Banking is done by setting the 'P' register, which is loaded with the

new bank address and then a 'JPP' instruction is executed.  Program control will be

transferred to the bank 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 = Bank 0

   02 = Bank 1

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

   00 = Bank 0

   01 = Bank 1

   02 = Bank 2

   03 = Bank 3

For the 32k Boxing Bugs schematic the 'P' register value are:

   00 = Bank 0

   01 = Bank 1

   02 = Bank 2

   03 = Bank 3

   04 = Bank 4

   05 = Bank 5

   06 = Bank 6

   07 = Bank 7

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

board configurations.

The 'normal' EPROM configurations is:

Even address are all contained in sockets T7 and U7, odd addresses are in

sockets P7 and R7.

Bank 0 usually starts in sockets T7 and P7, then continues through sockets

U7 and R7.

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 pages of 16 registers, for 256 12 bit

RAM registers.

When using 'DIR' addressing the upper 'PAGE' 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 page 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


'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 code 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 page, and the ROM

banked to be jumped to via the 'JPP' instruction.  (See program memory


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 page 2 of RAM

        lda     $7      ; Read RAM location $27 into 'A', loads 'I' with $27

        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 page $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             ; 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 page 0

        lda     $3      ; Get value at $03

        add     #$1A    ; Add $1A to value

        jnc             ; 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 page 0

0103:   add     $3      : Add value at location $3

0104:   sta     [i]     ; Write new value back to location $3

0105:   cmp     $0      ; Load the 'I' register with address $00

0106:   ldj     [i]     ; Load the return address into the 'J' register

0107:   jmp             ; 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 page 0

0303:   sta     $0      ; Set $00 to return address

0304:   ldj     #$100   ; Point to subroutine

0306:   jmp             ; Jump to the 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 jumps become 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             ; Jump using 'P' as bank extension to $2450



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             ; 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             ; Program jumps to address $125

The value in the 'A' register will be $FFF as expected, yet the carry

flag (indicating a borrow in this case) will not be set.

What was actually performed by the above code is:

   The value $FFE (one's compliment of 1) is added to 0, then to create a

   two's compliment value, the value is incrementing by one, resulting in

   $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 using P-reg as new bank, 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)



The multiply instruction performs one cycle of an unsigned 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 $725 by $200

        ldp     #0      ; Use page zero

        lda     #$700   ; Load A-reg with $700

        add     #$25    ; Load A-reg with $725

        sta     3       ; Store at RAM location 3

        lda     #$200   ; Load A-reg with $200

        ; Anything loaded into the B-reg at this point will automatically

        ; be added to the results, for this example we just set the register

        ; to zero.

        usb             : use B-reg

        clr             ; Clear the B-reg

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

        mul     [i]     ; the I-reg is still pointing at RAM $03

        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 = $725 * $200

Watch Dog Timer


The watch dog / tick timers runs at a 76hz rate.  The instruction 'WAI'

will stop the processor and wait for the tick timer to tick once.

If the tick timer ticks thrice 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.

Coin Counter


The coin counter consists of a SET/RESET latch the is set by the dropping

of a coin through the coin shute, and reset by the CPU.  The coin counter

latch (like all other switches) reads high when inactive (no quarter read),

and goes low when a quarter is dropped into the chute.

The coin counter latch is read by reading dummy DIP switch 7, and is reset

by toggling output bit-5 low, then high (remembering that OUT writes

the *inverted* value of the accumulator's bit-0).

        ldj     #noCoin

        usb                     ; DIP switches must be read into B-reg

        inp     7               ; read coin latch


        sub     #1              ; set to 0, or FFF


        add     #1              ; set to 1, or 000 - with C-flg  

        jnc                     ; jump to 'noCoin'

        lda     $0              ; get coin count

        add     #1              ; increment coin counter

        sta     [i]             ; save new count


        add     #1              ; set bit-0

        out     5               ; reset coin latch by clear output 5

        clr                     ; reset bit-0

        out     5               ; setup for new coin

noCoin: ...


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


        clr             ; Clear A-reg

        add     #1      ; Set A-reg to 1

        out     6       ; Set vector draws to BRIGHT (high) intensity

For multi-intensity monitors and Colors, see the following

"Colors and Intesities" section.

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 A-reg and the Y position into the B-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 adding the

starting values to the values that resulted from the 'LLT' instruction

and placing the ending X position into the A-reg and the ending Y position

into the B-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 X position of vector to be drawn

              ; $5 = End X position of vector to be drawn

              ; $6 = Start Y position of vector to be drawn

              ; $7 = End Y position of vector to be drawn


              ; $F = Return address


              ; All RAM addresses are located in the current page

              ; 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 X in A-reg

00F1: 57      usb              ; point to B accumulator

00F2: A6      lda     $6       ; Get start Y in B-reg

00F4: 45 F0   ldj     #$0F5    ; Point to next instruction

00F5: 5A      jdr              ; 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              ; If A-reg still negative, loop

00FF: A5      lda     $5       ; Get X end position in A-reg

0100: 74      sub     $4       ; Subtract start to get length

0101: 57      usb

0102: A7      lda     $7       ; Get Y 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 X start to A-reg to get X end

0107: 57      usb

0108: 66      add     $6       ; Add Y start to B-reg to get Y 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              ; Return to caller

Colors & Intensities


*** Bi-Level display ***

As mentioned earlier the brightness of the Bi-Level display is set by using

the OUT instruction to turn on and off bit-6, an 'OUT 6' instruction with

bit-0 of the A-reg set to 1, will cause all following vectors to be drawn

"bright".  If bit-0 if the A-reg was set to 0, then all vectors will be

drawn "normal" intensity.

*** 16 level, 64 level and Color displays ***

The X register (the register used to hold the X position of a vector) is

used as a temperary register to hold the color/intensity of a vector.  The

color/intensity register is loaded by placing a value in the A-reg and

executing a 'VIN' instruction.  This sets the color value into the X

register.  Output Bit-6 is now toggled using the 'OUT' instruction.

This latches the color/intensity into the color/intensity register on the

CRT or Color Conversion board.  Output bit-6 is always left in the SET state.

CAUTION!!!!  The 'VIN' register always moves the CRT trace to the X and Y

positions given in the A and B registers.  And the trace will stay there

until it is moved elsewhere, or a vector is drawn.  If the trace is left

too far from center for too long a time, damage to the monitor can result!

It is *very* important to set the Y value pointing to the center of the

screen before executing the 'VIN' instruction (when using the instruction

to set the color/intensity of a vector) and to reset the X and Y position

to the center of the screen after the color/intensity has been set!

The following code will safely set a value into the color/intensity register

without damage to the CRT deflection circuits:

        lda     #color                  ; get color/intensity value

        ; Be sure B-reg points to the center of the screen

        usb                             ; use the B accumulator

        lda     #3                      ; load maximum Y-value (768)

        usb                             ; use the B accumulator

        lsr                             ; get Y-value's center of screen (768/2)

        vin                             ; set color into CRT's X-reg

        ; Now latch color/intensity into color/intensity register

        clr		                ; RESET bit

        out     6                       ; reset OUT bit-6

        add     #1                      ; SET bit

        out     6                       ; set OUT bit-6

        ; Set monitors deflection back to the center of the screen

        lda     #4                      ; load maximum X-value (1024)

        usb                             ; use the B accumulator

        lda     #3                      ; load maximum Y-value (768)

        lsrd                            ; set to center of screen (1024/2,768/2)

        vin                             ; set CRT to point to the center of screen

Bit mapping of the 12 bit color/intensity words are as follows:

16 levels of intensities:

   xxxx xxxx CCCC


   x    - Don't care.

   CCCC - Intensity level.

           0000 = Lowest intensity.

           0001 = 2nd lowest intensity.

           1111 = Highest intensity.


64 levels of intensities:

   xxxx CCCC CCxx


   x       - Don't care.

   CCCC CC - Intensity level.

              1111 11 = Lowest intensity.

              1111 10 = 2nd lowest intensity.

              0000 00 = Highest intensity.


4096 colors:



   BBBB - Blue intensity level.

           1111 = No blue.

           1110 = Dimmest blue.

           0000 = Maximum blue level.


   GGGG - Green intensity level.

           1111 = No green.

           1110 = Dimmest green.

           0000 = Maximum green level.

   RRRR - Red intensity level.

           1111 = No red.

           1110 = Dimmest red.

           0000 = Maximum red level.

   1111 1111 1111 = Black.

   1110 1111 1111 = Lowest intensity blue.

   1111 1110 1111 = Lowest intensity green.

   1111 1111 1110 = Lowest intensity red.

   0000 0000 0000 = Brightest white.