Draw_VLc - Optimizations

Motivation

In this section I would like to demonstrate possible steps to optimize vectorlist drawing.

The shown possible steps are not ment to be "complete", exclusively right or particulary engenious.

Each scenario of ones own coding base provides grounds for other or more specific optimization technics.

I will show different versions of printing a vectorlist, which in each version step will be slightly more optimized in specific ways.

The demonstration program(s) will draw a vectorlist which represents a "hut" like:



Hut


(The hut is pretty small, but as you will see, drawing a "small" list is easier to optimize - also in many games drawing many small objects is the predominant scenario)

Version 1 - 3164 cycles - basis

Basis:

;*****************************************************
; DEFINE SECTION
;*****************************************************
; load vectrex bios routine definitions
          INCLUDE "VECTREX.I"          ; vectrex function includes

;*****************************************************
; Variable / RAM SECTION
;*****************************************************
; insert your variables (RAM usage) in the BSS section
; user RAM starts at $c880
          BSS     
          ORG     $c880                ; start of our ram space

;*****************************************************
; HEADER SECTION
;*****************************************************
; The cartridge ROM starts at address 0
          CODE     
          ORG     0
; the first few bytes are mandatory, otherwise the BIOS will not load
; the ROM file, and will start MineStorm instead
          DB     "g GCE 1998", $80     ; "g' is copyright sign
          DW     music1                ; music from the rom
          DB     $F8, $50, $20, -$80   ; hight, width, rel y, rel x (from 0,0)
          DB     "DRAW LINES V1", $80  ; some game information, ending with $80
          DB     0                     ; end of game header

;*****************************************************
; CODE SECTION
;*****************************************************
; here the cartridge program starts off
main:
          JSR     Wait_Recal           ; Vectrex BIOS recalibration
          JSR     Intensity_5F         ; Sets the intensity of the
                                       ; vector beam to $5f
          LDA     #$b0                 ; scalefactor
          STA     VIA_t1_cnt_lo
          LDA     #$00                 ; position relative Y
          LDB     #$00                 ; position relative X
          JSR     Moveto_d             ; sets up VIA control register after a wait recal

          LDX     #vData               ; address of string
          JSR     Draw_VLc             ; Vectrex BIOS print routine
          BRA     main                 ; and repeat forever


;*****************************************************
; DATA SECTION
;*****************************************************

vData = VectorList
VectorList:
          DB +$07                      ; number of lines to draw
          DB +$00, +$06                ; draw to y, x
          DB +$07, +$00                ; draw to y, x
          DB +$05, -$03                ; draw to y, x
          DB -$05, -$03                ; draw to y, x
          DB -$07, +$00                ; draw to y, x
          DB +$07, +$06                ; draw to y, x
          DB +$00, -$06                ; draw to y, x
          DB -$07, +$06                ; draw to y, x

Version 2 - 1637 cycles - scale factor!

In the above version (for demonstration purposes) I used a large scale factor and small vector strengths. Using a small scale factor and large vector strength results in huge optimization effects.

The scale factor and strength changes are not 1:1 - you have to experiment to get the same "sizes" of the resulting lists.

In the example I changed the scale factor from $b0 to $06, and multiplied each (original) strength by 18.

;*****************************************************
; DEFINE SECTION
;*****************************************************
; load vectrex bios routine definitions
          INCLUDE "VECTREX.I"          ; vectrex function includes

;*****************************************************
; Variable / RAM SECTION
;*****************************************************
; insert your variables (RAM usage) in the BSS section
; user RAM starts at $c880
          BSS     
          ORG     $c880                ; start of our ram space

;*****************************************************
; HEADER SECTION
;*****************************************************
; The cartridge ROM starts at address 0
          CODE     
          ORG     0
; the first few bytes are mandatory, otherwise the BIOS will not load
; the ROM file, and will start MineStorm instead
          DB     "g GCE 1998", $80     ; "g' is copyright sign
          DW     music1                ; music from the rom
          DB     $F8, $50, $20, -$80   ; hight, width, rel y, rel x (from 0,0)
          DB     "DRAW LINES V2", $80  ; some game information, ending with $80
          DB     0                     ; end of game header

;*****************************************************
; CODE SECTION
;*****************************************************
; here the cartridge program starts off
main:
          JSR     Wait_Recal           ; Vectrex BIOS recalibration
          JSR     Intensity_5F         ; Sets the intensity of the
                                       ; vector beam to $5f
          LDA     #$06                 ; scalefactor
          STA     VIA_t1_cnt_lo
          LDA     #$00                 ; position relative Y
          LDB     #$00                 ; position relative X
          JSR     Moveto_d             ; sets up VIA control register after a wait recal

          LDX     #vData               ; address of string
          JSR     Draw_VLc             ; Vectrex BIOS print routine
          BRA     main                 ; and repeat forever


;*****************************************************
; DATA SECTION
;*****************************************************

BLOW UP = 18
vData = VectorList
VectorList:
          DB +$07                      ; number of lines to draw
          DB +$00*BLOW_UP, +$06*BLOW_UP; draw to y, x
          DB +$07*BLOW_UP, +$00*BLOW_UP; draw to y, x
          DB +$05*BLOW_UP, -$03*BLOW_UP; draw to y, x
          DB -$05*BLOW_UP, -$03*BLOW_UP; draw to y, x
          DB -$07*BLOW_UP, +$00*BLOW_UP; draw to y, x
          DB +$07*BLOW_UP, +$06*BLOW_UP; draw to y, x
          DB +$00*BLOW_UP, -$06*BLOW_UP; draw to y, x
          DB -$07*BLOW_UP, +$06*BLOW_UP; draw to y, x

Version 3 - 1630 cycles - macro!

This version is a step "in between". Nothing really changed, only the call of "JSR     Draw VLc" was replaced with a macro call of exactly the same routine.

;*****************************************************
; DEFINE SECTION
;*****************************************************
; load vectrex bios routine definitions
          INCLUDE "VECTREX.I"          ; vectrex function includes

DRAW_VLC macro
          direct  $d0                  ; following code uses d0
          LDA     ,X+
Draw_VL_a_macro?
          STA     $C823
          LDD     ,X
          STA     <VIA_port_a          ;Send Y to A/D
          CLR     <VIA_port_b          ;Enable mux
          LEAX    2,X                  ;Point to next coordinate pair
          NOP                          ;Wait a moment
          INC     <VIA_port_b          ;Disable mux
          STB     <VIA_port_a          ;Send X to A/D
          LDD     #$FF00               ;Shift reg=$FF (solid line), T1H=0
LF3ED\?:
          STA     <VIA_shift_reg       ;Put pattern in shift register
          STB     <VIA_t1 cnt_hi       ;Set T1H (scale factor?)
          LDD     #$0040               ;B-reg = T1 interrupt bit
LF3F4\?:
          BITB    <VIA_int_flags       ;Wait for T1 to time out
          BEQ     LF3F4\?
          NOP                          ;Wait a moment more
          STA     <VIA_shift_reg       ;Clear shift register (blank output)
          LDA     $C823                ;Decrement line count
          DECA    
          BPL     Draw_VL_a_macro\?    ;Go back for more points
          JSR     Check0Ref            ;Reset zero reference if necessary
          endm

;*****************************************************
; Variable / RAM SECTION
;*****************************************************
; insert your variables (RAM usage) in the BSS section
; user RAM starts at $c880
          BSS     
          ORG     $c880                ; start of our ram space

;*****************************************************
; HEADER SECTION
;*****************************************************
; The cartridge ROM starts at address 0
          CODE     
          ORG     0
; the first few bytes are mandatory, otherwise the BIOS will not load
; the ROM file, and will start MineStorm instead
          DB     "g GCE 1998", $80     ; "g' is copyright sign
          DW     music1                ; music from the rom
          DB     $F8, $50, $20, -$80   ; hight, width, rel y, rel x (from 0,0)
          DB     "DRAW LINES V3", $80  ; some game information, ending with $80
          DB     0                     ; end of game header

;*****************************************************
; CODE SECTION
;*****************************************************
; here the cartridge program starts off
main:
          JSR     Wait_Recal           ; Vectrex BIOS recalibration
          JSR     Intensity_5F         ; Sets the intensity of the
                                       ; vector beam to $5f
          LDA     #$06                 ; scalefactor
          STA     VIA_t1_cnt_lo
          LDA     #$00                 ; position relative Y
          LDB     #$00                 ; position relative X
          JSR     Moveto_d             ; sets up VIA control register after a wait recal

          LDX     #vData               ; address of string
          DRAW_VLC                     ; Macro print routine
          BRA     main                 ; and repeat forever


;*****************************************************
; DATA SECTION
;*****************************************************

BLOW UP = 18
vData = VectorList
VectorList:
          DB +$07                      ; number of lines to draw
          DB +$00*BLOW_UP, +$06*BLOW_UP; draw to y, x
          DB +$07*BLOW_UP, +$00*BLOW_UP; draw to y, x
          DB +$05*BLOW_UP, -$03*BLOW_UP; draw to y, x
          DB -$05*BLOW_UP, -$03*BLOW_UP; draw to y, x
          DB -$07*BLOW_UP, +$00*BLOW_UP; draw to y, x
          DB +$07*BLOW_UP, +$06*BLOW_UP; draw to y, x
          DB +$00*BLOW_UP, -$06*BLOW_UP; draw to y, x
          DB -$07*BLOW_UP, +$06*BLOW_UP; draw to y, x

Version 4 - 1531 cycles - optimized macro!

The above introduced macro was changed to a manualy optimized version.

;*****************************************************
; DEFINE SECTION
;*****************************************************
; load vectrex bios routine definitions
          INCLUDE "VECTREX.I"        ; vectrex function includes

DRAW_VLC          macro
          direct  $d0                 ; following code uses d0
          LDD     ,X++                ;
          STA     $C823               ;
          CLRA
_DRAW_VLA\?:
          STD     VIA_port_b
          LDB     ,X+
          INC     VIA_port_b          ;Disable mux
          STB     VIA_port_a          ;Send X to A/D
          DEC     VIA_shift_reg       ;Put pattern in shift register
          STA     VIA_t1_cnt_hi       ;enable timer 1

          LDB     ,X+                 ; 6
          DEC     $C823               ; 7
          BEQ      DRAW_END\?         ; 3 Go back for more points
          LDA     #$40                ;B-reg = T1 interrupt bit
LF_1\?:
          BITA    VIA_int_flags       ;Wait for T1 to time out
          BEQ     LF_1\?              ;
          CLRA                        ;Wait a moment more
          STA     VIA_shift_reg       ;Clear shift register (blank output)
          BRA      DRAW_VLA\?         ; 3
_DRAW_END\?:
          LDA     #$40                ;B-reg = T1 interrupt bit
LF_2\?:
          BITA    VIA_int_flags       ;Wait for T1 to time out
          BEQ     LF_2\?              ;
          CLRA                        ;Wait a moment more
          STA     VIA_shift_reg
; one more round
          STD     VIA_port_b
          LDB     ,X+
          INC     VIA_port_b          ;Disable mux
          STB     VIA_port_a          ;Send X to A/D
          DEC     VIA_shift_reg       ;Put pattern in shift register
          STA     VIA_t1_cnt_hi       ;enable timer 1

          LDA     #$40                ;B-reg = T1 interrupt bit
LF_3?:
          BITA    VIA_int_flags       ;Wait for T1 to time out
          BEQ     LF_3\?
          CLR     VIA_shift_reg       ;Clear shift register (blank output)
          endm

;*****************************************************
; Variable / RAM SECTION
;*****************************************************
; insert your variables (RAM usage) in the BSS section
; user RAM starts at $c880
          BSS     
          ORG     $c880               ; start of our ram space

;*****************************************************
; HEADER SECTION
;*****************************************************
; The cartridge ROM starts at address 0
          CODE     
          ORG     0
; the first few bytes are mandatory, otherwise the BIOS will not load
; the ROM file, and will start MineStorm instead
          DB     "g GCE 1998", $80     ; "g' is copyright sign
          DW     music1                ; music from the rom
          DB     $F8, $50, $20, -$80   ; hight, width, rel y, rel x (from 0,0)
          DB     "DRAW LINES V4", $80  ; some game information, ending with $80
          DB     0                     ; end of game header

;*****************************************************
; CODE SECTION
;*****************************************************
; here the cartridge program starts off
main:
          JSR     Wait_Recal           ; Vectrex BIOS recalibration
          JSR     Intensity_5F         ; Sets the intensity of the
                                       ; vector beam to $5f
          LDA     #$06                 ; scalefactor
          STA     VIA_t1_cnt_lo
          LDA     #$00                 ; position relative Y
          LDB     #$00                 ; position relative X
          JSR     Moveto_d             ; sets up VIA control register after a wait recal

          LDX     #vData               ; address of string
          DRAW_VLC                     ; Macro print routine
          BRA     main                 ; and repeat forever


;*****************************************************
; DATA SECTION
;*****************************************************

BLOW_UP = 18
vData = VectorList
VectorList:
          DB +$07                      ; number of lines to draw
          DB +$00*BLOW_UP, +$06*BLOW_UP; draw to y, x
          DB +$07*BLOW_UP, +$00*BLOW_UP; draw to y, x
          DB +$05*BLOW_UP, -$03*BLOW_UP; draw to y, x
          DB -$05*BLOW_UP, -$03*BLOW_UP; draw to y, x
          DB -$07*BLOW_UP, +$00*BLOW_UP; draw to y, x
          DB +$07*BLOW_UP, +$06*BLOW_UP; draw to y, x
          DB +$00*BLOW_UP, -$06*BLOW_UP; draw to y, x
          DB -$07*BLOW_UP, +$06*BLOW_UP; draw to y, x

Version 5 - 1416 cycles - loop unrolling and cycle specific!

The loop in the vector drawing was unrolled, and the actual drawing routine does not have a wait loop anymore, since we now that the length of the loop (= scalefactor) is 6. We can use the information, that we only draw for 6 cycles, to NOT wait for these 6 cycles to finish - we know how many cycles our instructions take.

To do the loop unrolling and some of the math involved (jump into a unrolled vector drawing routine) we changed the first parameter of the vectorlist to have a unrolled offset counter instead of the vectorlist length.

The maximum unrolled loop in this version is 11 vectors (maximum vectorlist size).

The size of the header (10) and one line (16) is manually computed, but could also be automatically gotten from address "math".

;*****************************************************
; DEFINE SECTION
;*****************************************************
; load vectrex bios routine definitions
          INCLUDE "VECTREX.I"         ; vectrex function includes

ONE_LINE_LENGTH   EQU 16
LENGTH_OF_HEADER  EQU (4+2+2+2)
MAX_LINE_NUM      EQU 23


ONE_LINE_DRAW macro                   ; cycles
          INC     VIA_port_b          ; [6] Disable mux
          STB     VIA_port_a          ; [6] Send X to A/D
          DEC     VIA_shift_reg       ; [6] Put pattern in shift register
          CLR     VIA_t1_cnt_hi       ; [4] enable timer 1
          LDD     ,X++                ; [8] load Y coordinate to A, X coordinate to B
          STA     VIA_port_a          ; [4] Send Y to A/D
          CLR     VIA_port_b          ; [4] enable mux, thus y integrators are set to Y
          CLR     VIA_shift_reg       ; [4] turn the lights off
          endm

MY_SPRITE_DRAW_VLC_UNLOOP_SMALL macro
          LDD      ,X++               ;(2)
          STA     VIA_port_a          ;(2) [4] Send Y to A/D
          CLR     VIA_port_b          ;(2) [4] enable mux, thus y integrators are set to Y
          JMP     [i_jump]            ;(4)
JUMP_INTO_ALL\?:
JUMP_INTO_11\?:
          ONE_LINE_DRAW
JUMP_INTO_10\?:
          ONE_LINE_DRAW
JUMP_INTO_09\?:
          ONE_LINE_DRAW
JUMP_INTO_08\?:
          ONE_LINE_DRAW
JUMP_INTO_07\?:
          ONE_LINE_DRAW
JUMP_INTO_06\?:
          ONE_LINE_DRAW
JUMP_INTO_05\?:
          ONE_LINE_DRAW
JUMP_INTO_04\?:
          ONE_LINE_DRAW
JUMP_INTO_03\?:
          ONE_LINE_DRAW
JUMP_INTO_02\?:
          ONE_LINE_DRAW
JUMP_INTO_01\?:
          INC     VIA_port_b            ; [6] Disable mux
          STB     VIA_port_a            ; [6] Send X to A/D
          DEC     VIA_shift_reg         ; [6] Put pattern in shift register
          CLR     VIA_t1_cnt_hi         ; [4] enable timer 1
          NOP     3
          endm

;*****************************************************
; Variable / RAM SECTION
;*****************************************************
; insert your variables (RAM usage) in the BSS section
; user RAM starts at $c880
          BSS     
          ORG     $c880                ; start of our ram space

;*****************************************************
; HEADER SECTION
;*****************************************************
; The cartridge ROM starts at address 0
          CODE     
          ORG     0
; the first few bytes are mandatory, otherwise the BIOS will not load
; the ROM file, and will start MineStorm instead
          DB     "g GCE 1998", $80     ; "g' is copyright sign
          DW     music1                ; music from the rom
          DB     $F8, $50, $20, -$80   ; hight, width, rel y, rel x (from 0,0)
          DB     "DRAW LINES V5", $80  ; some game information, ending with $80
          DB     0                     ; end of game header

;*****************************************************
; CODE SECTION
;*****************************************************
; here the cartridge program starts off
main:
          JSR     Wait_Recal           ; Vectrex BIOS recalibration
          JSR     Intensity_5F         ; Sets the intensity of the
                                       ; vector beam to $5f
          LDA     #$06                 ; scalefactor
          STA     VIA_t1_cnt_lo
          LDA     #$00                 ; position relative Y
          LDB     #$00                 ; position relative X
          JSR     Moveto_d             ; sets up VIA control register after a wait recal

          LDX     #vData               ; address of string
          LDD     ,X++                 ; load offset of vector list draw
          ADDD    #(unloop_start_address0+LENGTH_OF_HEADER-12*ONE_LINE_LENGTH); 4=JMP [], 2=LDD ,X++
          STD     i_jump
unloop_start_address0:
          MY_SPRITE_DRAW_VLC_UNLOOP_SMALL
          NOP     2
          CLR     VIA_shift_reg        ; [4] turn the lights off
          BRA     main                 ; and repeat forever


;*****************************************************
; DATA SECTION
;*****************************************************

BLOW UP = 18
vData = VectorList
VectorList:
          DW (MAX LINE NUM-(7+1))*ONE LINE LENGTH
          DB +$00*BLOW_UP, +$06*BLOW_UP; draw to y, x
          DB +$07*BLOW_UP, +$00*BLOW_UP; draw to y, x
          DB +$05*BLOW_UP, -$03*BLOW_UP; draw to y, x
          DB -$05*BLOW_UP, -$03*BLOW_UP; draw to y, x
          DB -$07*BLOW_UP, +$00*BLOW_UP; draw to y, x
          DB +$07*BLOW_UP, +$06*BLOW_UP; draw to y, x
          DB +$00*BLOW_UP, -$06*BLOW_UP; draw to y, x
          DB -$07*BLOW_UP, +$06*BLOW_UP; draw to y, x

Version 6 - 1376 cycles - tricking VIA!

- unfinished -