CINEINST.TXT Description of the Cinematronics CPU and instruction set. Version: 1.0a Date: 05/20/98 Author: Zonn Moore E-mail: zonn @ zonn.com (without the spaces) 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 backwards). 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]'). Version 1.0a 05/20/98 Changed E-mail address. ----------------------------------------------------------------------------- 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. 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. -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 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 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. 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 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.) 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 pressed. 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 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 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 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 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 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 ; 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 'x0' 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 SAB ; 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 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 usb sub #1 ; set to 0, or FFF usb 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 clr 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 or, 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 Where: x - Don't care. CCCC - Intensity level. 0000 = Lowest intensity. 0001 = 2nd lowest intensity. 1111 = Highest intensity. ----- 64 levels of intensities: xxxx CCCC CCxx Where: x - Don't care. CCCC CC - Intensity level. 1111 11 = Lowest intensity. 1111 10 = 2nd lowest intensity. 0000 00 = Highest intensity. ----- 4096 colors: BBBB GGGG RRRR Where: 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.