# =============================================================================================================
# *
# * Copyright (c) Mike
# *
# * File Name: vgaGameOfLife.asm
# *
# * Version: V1.0
# *
# * Release Date:
# *
# * Author(s): M.Freeman
# *
# * Description: Game of Life 
# *
# * Conditions of Use: THIS CODE IS COPYRIGHT AND IS SUPPLIED "AS IS" WITHOUT WARRANTY OF ANY KIND, INCLUDING,
# *                    BUT NOT LIMITED TO, ANY IMPLIED WARRANTY OF MERCHANTABILITY AND FITNESS FOR A
# *                    PARTICULAR PURPOSE.
# *
# * Notes:
# *
# =============================================================================================================

start:
    move RA 0
    store RA round_count
    store RA round_count_flag   
      
	load RA random_value_offset
	add RA 1
	store RA random_value_offset
	
	clear_screen( 0 )
	
	run( title )
	run( clear_next_grid )
	run( clear_present_grid )

	run( init_present_grid )
	run( update_screen )
	
repeat:
	load RA round_count_flag
	and RA 0xFF
	jumpnz start

    move RA 1
    store RA x_position
    store RA y_position

loop_outer:
    move RA 0
    store RA row_count
    store RA col_count
    store RA cell_count

loop_inner:
    load RA x_position
    addm RA row_count
    move RB RA

    load RA y_position
    addm RA col_count

    call convert_xy_2_addr
    get_array_bit( present_grid )

    move RB RA
    addm RA cell_count
    store RA cell_count

    load RA col_count
    sub RA 1
    jumpnz loop_skip
    load RA row_count
    sub RA 1
    jumpnz loop_skip

    move RA RB
    store RA cell_middle_state

loop_skip:
    load RA row_count
    add RA 1
    store RA row_count
    sub RA 3
    jumpnz loop_inner

    move RA 0 
    store RA row_count
    load RA col_count
    add RA 1
    store RA col_count
    sub RA 3
    jumpnz loop_inner

    load RA x_position
    add RA 1
    move RB RA
    load RA y_position
    add RA 1
    call convert_xy_2_addr

    load RA cell_middle_state
    and RA 0xFF
    jumpz dead_cell_test

alive_cell_test:
    load RA cell_count
    sub RA 3
    jumpz alive
    load RA cell_count
    sub RA 4
    jumpz alive
    jump dead

dead_cell_test:
    load RA cell_count
    sub RA 3
    jumpz alive

dead:
    clr_array_bit( next_grid )   
    jump next

alive:
    set_array_bit( next_grid )      

next:
    load RA x_position
    add RA 1
    store RA x_position
    store RA PIXEL_X_REG
    subm RA x_max
    jumpnz loop_outer

    move RA 1
    store RA x_position
    load RA y_position
    add RA 1
    store RA y_position
    store RA PIXEL_Y_REG
    subm RA y_max
    jumpnz loop_outer

    movea( RD, present_grid )
    movea( RC, next_grid )
    movea( RA, present_grid_end )
    store RA present_grid_end

copy_next_grid:
    load RA (RC)
    store RA (RD)
    add RC 1
    add RD 1
    move RA RD
    subm RA present_grid_end
    jumpnz copy_next_grid

    call update_screen
    call inc_round_count

    jump repeat

trap: 
    jump trap

#######################
# GENERAL SUBROUTINES #
#######################

# --------------- 
# - GAME SCREEN -
# ---------------

# -----------------
# - Clear next grid
# -----------------

clear_next_grid:
	movea( RD, next_grid )
	movea( RA, next_grid_end )
	store RA next_grid_end

clear_next_grid_loop:
	move RA 0
	store RA (RD)
	add RD 1
	move RA RD
	subm RA next_grid_end
	jumpnz clear_next_grid_loop
	ret

# -----------------
# - Clear present grid
# -----------------

clear_present_grid:
	movea( RD, present_grid )
	movea( RA, present_grid_end )
	store RA present_grid_end

clear_present_grid_loop:
	move RA 0
	store RA (RD)
	add RD 1
	move RA RD
	subm RA present_grid_end
	jumpnz clear_present_grid_loop
	ret

# -----------------
# - Init present grid
# -----------------

init_present_grid:
	movea( RD, present_grid )
	movea( RA, present_grid_end )
	store RA present_grid_end

init_present_grid_loop:
	call random
	store RA (RD)
	add RD 1
	move RA RD
	subm RA present_grid_end
	jumpnz init_present_grid_loop
	ret

	movea( RA, present_grid )
	add RA 22
	move RB 7
	store RB (RA)
	ret
	
# -------------------------
# - Generate "RANDOM" value
# -------------------------	

random:
	load RA seed
	move RB RA
	movea( RA, random_data )
	add RB RA
	load RA (RB)
	store RA random_value
	
	load RA seed
	add RA 1
	store RA seed
	subm RA random_data_max
	jumpnz random_exit
	
	move RA 0
	store RA seed
	
random_exit:
	load RA random_value
	ret

	load RA seed
	rotate_left( RA, 3 )
	move RB RA
	and RA 0x3
	jumpz random_insert_1
	sub RB 3
	jumpz random_insert_1
	
random_insert_0:
	load RA seed
	asl RA
	add RA 2
	store RA seed
	ret
	
random_insert_1:
	load RA seed
	asl RA
	add RA 1
	store RA seed
	ret
	
# -----------------
# - draw title
# -----------------

title:
	draw_box( LIME_GREEN, 20, 20, 136, 110 )
	draw_box( BLACK, 24, 24, 132, 106 )	

    draw_char( LIME_GREEN, eval( 30 + ( 8 * 0 ) ), 0, G_CHAR )
	draw_char( LIME_GREEN, eval( 30 + ( 8 * 1 ) ), 0, A_CHAR )
	draw_char( LIME_GREEN, eval( 30 + ( 8 * 2 ) ), 0, M_CHAR )
	draw_char( LIME_GREEN, eval( 30 + ( 8 * 3 ) ), 0, E_CHAR )

	draw_char( LIME_GREEN, eval( 30 + ( 8 * 5 ) ), 0, O_CHAR )
	draw_char( LIME_GREEN, eval( 30 + ( 8 * 6 ) ), 0, F_CHAR )

	draw_char( LIME_GREEN, eval( 30 + ( 8 *  8 ) ), 0, L_CHAR )
	draw_char( LIME_GREEN, eval( 30 + ( 8 *  9 ) ), 0, I_CHAR )
	draw_char( LIME_GREEN, eval( 30 + ( 8 * 10 ) ), 0, F_CHAR )
	draw_char( LIME_GREEN, eval( 30 + ( 8 * 11 ) ), 0, E_CHAR )
	
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 0 ) ), 9, R_CHAR )
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 1 ) ), 9, O_CHAR )		
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 2 ) ), 9, U_CHAR )
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 3 ) ), 9, N_CHAR )		
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 4 ) ), 9, D_CHAR )	
	
    draw_char( LIGHT_GREY, eval( 30 + ( 8 * 5 ) ), 9, colon_CHAR )
    
 	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 7 ) ), 9, zero_CHAR )
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 8 ) ), 9, zero_CHAR )		
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 9 ) ), 9, zero_CHAR )	   
    	
	ret
	
# -------------------
# - INC ROUND COUNT -
# -------------------

inc_round_count:
	load RA round_count
	add RA 1
	store RA round_count
	
	subm RA round_count_max
	jumpnz inc_round_count_conv

	move RA 0
	store RA round_count
	move RA 1
	store RA round_count_flag 
		
inc_round_count_conv:	
	load RA round_count	
	call bin_2_dec 

update_1s_digit:
	load RA bin_2_dec_1s_cnt
	and RA 0xFF
	jumpz inc_round_count_1s_0
	sub RA 1
	jumpz inc_round_count_1s_1
	sub RA 1
	jumpz inc_round_count_1s_2
	sub RA 1
	jumpz inc_round_count_1s_3
	sub RA 1
	jumpz inc_round_count_1s_4
	sub RA 1
	jumpz inc_round_count_1s_5
	sub RA 1
	jumpz inc_round_count_1s_6
	sub RA 1
	jumpz inc_round_count_1s_7
	sub RA 1
	jumpz inc_round_count_1s_8
	sub RA 1
	jumpz inc_round_count_1s_9

inc_round_count_1s_0:
#	1s 0
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 9 ) ), 9, zero_CHAR )
	jump update_10s_digit

inc_round_count_1s_1:
#	1s 1
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 9 ) ), 9, one_CHAR )
	jump update_10s_digit

inc_round_count_1s_2:
#	1s 2
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 9 ) ), 9, two_CHAR )
	jump update_10s_digit

inc_round_count_1s_3:
#	1s 3
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 9 ) ), 9, three_CHAR )
	jump update_10s_digit

inc_round_count_1s_4:
#	1s 4
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 9 ) ), 9, four_CHAR )
	jump update_10s_digit

inc_round_count_1s_5:
#	1s 5
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 9 ) ), 9, five_CHAR )
	jump update_10s_digit

inc_round_count_1s_6:
#	1s 6
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 9 ) ), 9, six_CHAR )
	jump update_10s_digit

inc_round_count_1s_7:
#	1s 7
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 9 ) ), 9, seven_CHAR )
	jump update_10s_digit

inc_round_count_1s_8:
#	1s 8
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 9 ) ), 9, eight_CHAR )
	jump update_10s_digit

inc_round_count_1s_9:
#	1s 9
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 9 ) ), 9, nine_CHAR )

update_10s_digit:
	load RA bin_2_dec_10s_cnt
	and RA 0xFF
	jumpz inc_round_count_10s_0
	sub RA 1
	jumpz inc_round_count_10s_1
	sub RA 1
	jumpz inc_round_count_10s_2
	sub RA 1
	jumpz inc_round_count_10s_3
	sub RA 1
	jumpz inc_round_count_10s_4
	sub RA 1
	jumpz inc_round_count_10s_5
	sub RA 1
	jumpz inc_round_count_10s_6
	sub RA 1
	jumpz inc_round_count_10s_7
	sub RA 1
	jumpz inc_round_count_10s_8
	sub RA 1
	jumpz inc_round_count_10s_9

inc_round_count_10s_0:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 8 ) ), 9, zero_CHAR )
	jump update_100s_digit

inc_round_count_10s_1:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 8 ) ), 9, one_CHAR )
	jump update_100s_digit

inc_round_count_10s_2:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 8 ) ), 9, two_CHAR )
	jump update_100s_digit

inc_round_count_10s_3:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 8 ) ), 9, three_CHAR )
	jump update_100s_digit

inc_round_count_10s_4:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 8 ) ), 9, four_CHAR )
	jump update_100s_digit

inc_round_count_10s_5:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 8 ) ), 9, five_CHAR )
	jump update_100s_digit

inc_round_count_10s_6:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 8 ) ), 9, six_CHAR )
	jump update_100s_digit

inc_round_count_10s_7:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 8 ) ), 9, seven_CHAR )
	jump update_100s_digit

inc_round_count_10s_8:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 8 ) ), 9, eight_CHAR )
	jump update_100s_digit

inc_round_count_10s_9:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 8 ) ), 9, nine_CHAR )

update_100s_digit:
	load RA bin_2_dec_100s_cnt
	and RA 0xFF
	jumpz inc_round_count_100s_0
	sub RA 1
	jumpz inc_round_count_100s_1
	sub RA 1
	jumpz inc_round_count_100s_2
	sub RA 1
	jumpz inc_round_count_100s_3
	sub RA 1
	jumpz inc_round_count_100s_4
	sub RA 1
	jumpz inc_round_count_100s_5
	sub RA 1
	jumpz inc_round_count_100s_6
	sub RA 1
	jumpz inc_round_count_100s_7
	sub RA 1
	jumpz inc_round_count_100s_8
	sub RA 1
	jumpz inc_round_count_100s_9

inc_round_count_100s_0:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 7 ) ), 9, zero_CHAR )
	jump inc_round_count_exit

inc_round_count_100s_1:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 7 ) ), 9, one_CHAR )
	jump inc_round_count_exit

inc_round_count_100s_2:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 7 ) ), 9, two_CHAR )
	jump inc_round_count_exit

inc_round_count_100s_3:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 7 ) ), 9, three_CHAR )
	jump inc_round_count_exit

inc_round_count_100s_4:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 7 ) ), 9, four_CHAR )
	jump inc_round_count_exit

inc_round_count_100s_5:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 7 ) ), 9, five_CHAR )
	jump inc_round_count_exit

inc_round_count_100s_6:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 7 ) ), 9, six_CHAR )
	jump inc_round_count_exit

inc_round_count_100s_7:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 7 ) ), 9, seven_CHAR )
	jump inc_round_count_exit

inc_round_count_100s_8:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 7 ) ), 9, eight_CHAR )
	jump inc_round_count_exit

inc_round_count_100s_9:
	draw_char( LIGHT_GREY, eval( 30 + ( 8 * 7 ) ), 9, nine_CHAR )
	jump inc_round_count_exit

inc_round_count_exit:
	ret

# -----------------
# - Update Screen -
# -----------------

update_screen:
	move RA 0
	 store RA x_position
	 store RA y_position
  
update_screen_loop: 
	 load RA x_position
	move RB RA
	addm RA x_position_offset
	store RA PIXEL_X_REG

	load RA y_position
	addm RA y_position_offset  
  	store RA PIXEL_Y_REG    
 	load RA y_position

	call convert_xy_2_addr
       get_array_bit( present_grid )
      	and RA 0xFF
   	 jumpnz update_screen_green

update_screen_black:
    move RA BLACK
    store RA CPU_COLOUR_REG
    jump update_screen_next

update_screen_green:
    move RA GREEN
    store RA CPU_COLOUR_REG

update_screen_next:
    move RA DRAW_PIXEL
    store RA CPU_CTL_REG

update_screen_wait:
    movea( RA, CPU_STATUS_REG )
    load RB (RA)
    and RB CTL_MASK
    jumpz update_screen_wait

update_screen_skip:
    load RA x_position
    add RA 1
    store RA x_position
	add RA 2
    subm RA x_max
    jumpnz update_screen_loop

    move RA 0
    store RA x_position
    load RA y_position
    add RA 1
    store RA y_position
	add RA 2
    subm RA y_max
    jumpnz update_screen_loop

    ret

# -------------------------
# - CONVERT XY TO ADDRESS -
# -------------------------

# 256 128 64 32 16 8 4 2 1
# 160 = 128 + 32
# 100 = 64 + 32 + 4
#
# RA - y
# RB - x

convert_xy_2_addr:
    asl RA 
    asl RA 
    move RC RA
    asl RA 
    asl RA 
    asl RA  
    add RC RA
    asl RA  
    add RC RA
    add RC RB
    move RA RC   
    store RA bit_array_index
    ret

convert_xy_2_addr_32:
    asl RA 
    asl RA 
    asl RA 
    asl RA 
    asl RA  
    add RA RB
    store RA bit_array_index
    ret

# ------------------
# - GET ARRAY BIT -
# ------------------

# RA - data
# RB - index
# RC - address

get_array_bit_subroutine:
    add RB 0x00
    jumpz get_array_bit_0
    sub RB 1
    jumpz get_array_bit_1
    sub RB 1
    jumpz get_array_bit_2   
    sub RB 1
    jumpz get_array_bit_3
    sub RB 1
    jumpz get_array_bit_4
    sub RB 1
    jumpz get_array_bit_5
    sub RB 1
    jumpz get_array_bit_6   
    sub RB 1
    jumpz get_array_bit_7
    sub RB 1
    jumpz get_array_bit_8
    sub RB 1
    jumpz get_array_bit_9   
    sub RB 1
    jumpz get_array_bit_A
    sub RB 1
    jumpz get_array_bit_B
    sub RB 1
    jumpz get_array_bit_C   
    sub RB 1
    jumpz get_array_bit_D
    sub RB 1
    jumpz get_array_bit_E   

get_array_bit_F:
    rotate_left( RA, 1 )
    and RA 0x01
    ret
get_array_bit_0:
    and RA 0x01
    ret   
get_array_bit_1:
    rotate_left( RA, 15 )
    and RA 0x01
    ret   
get_array_bit_2:
    rotate_left( RA, 14 )
    and RA 0x01
    ret   
get_array_bit_3:
    rotate_left( RA, 13 )
    and RA 0x01
    ret   
get_array_bit_4:
    rotate_left( RA, 12 )
    and RA 0x01
    ret   
get_array_bit_5:
    rotate_left( RA, 11 )
    and RA 0x01
    ret   
get_array_bit_6:
    rotate_left( RA, 10 )
    and RA 0x01
    ret   
get_array_bit_7:
    rotate_left( RA, 9 )
    and RA 0x01
    ret 
get_array_bit_8:
    rotate_left( RA, 8 )
    and RA 0x01
    ret   
get_array_bit_9:
    rotate_left( RA, 7 )
    and RA 0x01
    ret   
get_array_bit_A:
    rotate_left( RA, 6 )
    and RA 0x01
    ret   
get_array_bit_B:
    rotate_left( RA, 5 )
    and RA 0x01
    ret   
get_array_bit_C:
    rotate_left( RA, 4 )
    and RA 0x01
    ret   
get_array_bit_D:
    rotate_left( RA, 3 )
    and RA 0x01
    ret   
get_array_bit_E:
    rotate_left( RA, 2 )
    and RA 0x01
    ret   

# ------------------
# - SET ARRAY BIT -
# ------------------

# RA - data
# RB - index
# RC - address

set_array_bit_subroutine:
    add RB 0x00
    jumpz set_array_bit_0
    sub RB 1
    jumpz set_array_bit_1
    sub RB 1
    jumpz set_array_bit_2   
    sub RB 1
    jumpz set_array_bit_3
    sub RB 1
    jumpz set_array_bit_4
    sub RB 1
    jumpz set_array_bit_5
    sub RB 1
    jumpz set_array_bit_6   
    sub RB 1
    jumpz set_array_bit_7
    sub RB 1
    jumpz set_array_bit_8
    sub RB 1
    jumpz set_array_bit_9   
    sub RB 1
    jumpz set_array_bit_A
    sub RB 1
    jumpz set_array_bit_B
    sub RB 1
    jumpz set_array_bit_C   
    sub RB 1
    jumpz set_array_bit_D
    sub RB 1
    jumpz set_array_bit_E   

set_array_bit_F:
    rotate_left( RA, 1 )
    or RA 0x01
    rotate_left( RA, 15 )
    store RA (RC)
    ret
set_array_bit_0:
    or RA 0x01
    store RA (RC)
    ret  
set_array_bit_1:
    rotate_left( RA, 15 )
    or RA 0x01
    rotate_left( RA, 1 )
    store RA (RC)
    ret   
set_array_bit_2:
    rotate_left( RA, 14 )
    or RA 0x01
    rotate_left( RA, 2 )
    store RA (RC)
    ret   
set_array_bit_3:
    rotate_left( RA, 13 )
    or RA 0x01
    rotate_left( RA, 3 )
    store RA (RC)
    ret  
set_array_bit_4:
    rotate_left( RA, 12 )
    or RA 0x01
    rotate_left( RA, 4 )
    store RA (RC)
    ret  
set_array_bit_5:
    rotate_left( RA, 11 )
    or RA 0x01
    rotate_left( RA, 5 )
    store RA (RC)
    ret 
set_array_bit_6:
    rotate_left( RA, 10 )
    or RA 0x01
    rotate_left( RA, 6 )
    store RA (RC)
    ret  
set_array_bit_7:
    rotate_left( RA, 9 )
    or RA 0x01
    rotate_left( RA, 7 )
    store RA (RC)
    ret
set_array_bit_8:
    rotate_left( RA, 8 )
    or RA 0x01
    rotate_left( RA, 8 )
    store RA (RC)
    ret 
set_array_bit_9:
    rotate_left( RA, 7 )
    or RA 0x01
    rotate_left( RA, 9 )
    store RA (RC)
    ret   
set_array_bit_A:
    rotate_left( RA, 6 )
    or RA 0x01
    rotate_left( RA, 10 )
    store RA (RC)
    ret  
set_array_bit_B:
    rotate_left( RA, 5 )
    or RA 0x01
    rotate_left( RA, 11 )
    store RA (RC)
    ret  
set_array_bit_C:
    rotate_left( RA, 4 )
    or RA 0x01
    rotate_left( RA, 12 )
    store RA (RC)
    ret  
set_array_bit_D:
    rotate_left( RA, 3 )
    or RA 0x01
    rotate_left( RA, 13 )
    store RA (RC)
    ret  
set_array_bit_E:
    rotate_left( RA, 2 )
    or RA 0x01
    rotate_left( RA, 14 )
    store RA (RC)
    ret

# -----------------
# - CLR ARRAY BIT -
# -----------------

# RA - data
# RB - index
# RC - address

clr_array_bit_subroutine:
    add RB 0x00
    jumpz clr_array_bit_0
    sub RB 1
    jumpz clr_array_bit_1
    sub RB 1
    jumpz clr_array_bit_2   
    sub RB 1
    jumpz clr_array_bit_3
    sub RB 1
    jumpz clr_array_bit_4
    sub RB 1
    jumpz clr_array_bit_5
    sub RB 1
    jumpz clr_array_bit_6   
    sub RB 1
    jumpz clr_array_bit_7
    sub RB 1
    jumpz clr_array_bit_8
    sub RB 1
    jumpz clr_array_bit_9   
    sub RB 1
    jumpz clr_array_bit_A
    sub RB 1
    jumpz clr_array_bit_B
    sub RB 1
    jumpz clr_array_bit_C   
    sub RB 1
    jumpz clr_array_bit_D
    sub RB 1
    jumpz clr_array_bit_E   

clr_array_bit_F:
    move RB RA
    and RB 0xFF               
    rotate_left( RA, 8 )
    and RA 0x7F               # 0111 1111
    rotate_left( RA, 8 )  
    add RA RB 
    store RA (RC)
    ret
clr_array_bit_0:
    move RB RA
    rotate_left( RB, 8 )
    and RB 0xFF                  
    rotate_left( RB, 8 )      
    and RA 0xFE               # 1111 1110
    add RA RB 
    store RA (RC)
    ret
clr_array_bit_1:
    move RB RA
    rotate_left( RB, 8 )
    and RB 0xFF
    rotate_left( RB, 8 )      
    and RA 0xFD               # 1111 1101
    add RA RB 
    store RA (RC)
    ret 
clr_array_bit_2:
    move RB RA
    rotate_left( RB, 8 )
    and RB 0xFF
    rotate_left( RB, 8 )      
    and RA 0xFB               # 1111 1011
    add RA RB 
    store RA (RC)
    ret   
clr_array_bit_3:
    move RB RA
    rotate_left( RB, 8 )
    and RB 0xFF
    rotate_left( RB, 8 )      
    and RA 0xF7               # 1111 0111
    add RA RB 
    store RA (RC)
    ret  
clr_array_bit_4:
    move RB RA
    rotate_left( RB, 8 )
    and RB 0xFF
    rotate_left( RB, 8 )      
    and RA 0xEF               # 1110 1111
    add RA RB 
    store RA (RC)
    ret 
clr_array_bit_5:
    move RB RA
    rotate_left( RB, 8 )
    and RB 0xFF
    rotate_left( RB, 8 )      
    and RA 0xDF               # 1101 1111
    add RA RB 
    store RA (RC)
    ret
clr_array_bit_6:
    move RB RA
    rotate_left( RB, 8 )
    and RB 0xFF
    rotate_left( RB, 8 )      
    and RA 0xBF               # 1011 1111
    add RA RB 
    store RA (RC)
    ret
clr_array_bit_7:
    move RB RA
    rotate_left( RB, 8 )
    and RB 0xFF
    rotate_left( RB, 8 )      
    and RA 0x7F               # 0111 1111
    add RA RB 
    store RA (RC)
    ret
clr_array_bit_8:
    move RB RA
    and RB 0xFF              
    rotate_left( RA, 8 )
    and RA 0xFE               # 1111 1110
    rotate_left( RA, 8 )  
    add RA RB 
    store RA (RC)
    ret
clr_array_bit_9:
    move RB RA
    and RB 0xFF               
    rotate_left( RA, 8 )
    and RA 0xFD               # 1111 1101
    rotate_left( RA, 8 )  
    add RA RB 
    store RA (RC)
    ret
clr_array_bit_A:
    move RB RA
    and RB 0xFF                
    rotate_left( RA, 8 )
    and RA 0xFB               # 1111 1011
    rotate_left( RA, 8 )  
    add RA RB 
    store RA (RC)
    ret
clr_array_bit_B:
    move RB RA
    and RB 0xFF               
    rotate_left( RA, 8 )
    and RA 0xF7               # 1111 0111
    rotate_left( RA, 8 )  
    add RA RB 
    store RA (RC)
    ret
clr_array_bit_C:
    move RB RA
    and RB 0xFF             
    rotate_left( RA, 8 )
    and RA 0xEF               # 1110 1111
    rotate_left( RA, 8 )  
    add RA RB 
    store RA (RC)
    ret
clr_array_bit_D:
    move RB RA
    and RB 0xFF               
    rotate_left( RA, 8 )
    and RA 0xDF               # 1101 1111
    rotate_left( RA, 8 )  
    add RA RB 
    store RA (RC)
    ret
clr_array_bit_E:
    move RB RA
    and RB 0xFF               
    rotate_left( RA, 8 )
    and RA 0xBF               # 1011 1111
    rotate_left( RA, 8 )  
    add RA RB 
    store RA (RC)
    ret

###################
# VGA SUBROUTINES #
###################

# --------------------
# - READ XY POSITION -
# --------------------

get_xy_position:
#   tile_X_pos
    move RB RD
    add RB SPRITE_XYPOS_OFFSET
    load RA (RB)
    rotate_left( RA, SPRITE_XPOS_SHIFT )
    and RA SPRITE_XPOS_MASK
    store RA TILE_X_REG
	store RA sprite_x_pos

#   tile_Y_pos
    load RA (RB)
    and RA SPRITE_YPOS_MASK    
    store RA TILE_Y_REG
	store RA sprite_y_pos

    ret

# ------------------
# - READ XY LIMITS -
# ------------------

get_xy_limits:
#   tile_X_limits
    move RB RD
    add RB SPRITE_XLIMIT_OFFSET
    load RA (RB)
    rotate_left( RA, SPRITE_XLIMIT_MAX_SHIFT )
    and RA 0xFF
	store RA sprite_limit_x_max
    load RA (RB)
    and RA 0xFF
	store RA sprite_limit_x_min

#   tile_Y_limits
    move RB RD
    add RB SPRITE_YLIMIT_OFFSET
    load RA (RB)
    rotate_left( RA, SPRITE_YLIMIT_MAX_SHIFT )
    and RA 0xFF
	store RA sprite_limit_y_max
    load RA (RB)
    and RA 0xFF
	store RA sprite_limit_y_min
    ret

# ------------------
# - READ XY OFFSET -
# ------------------
#
# offset is a signed 8bit value

get_xy_offsets:
#   tile_X_offset
    move RB RD
    add RB SPRITE_XYOFFSET_OFFSET
    load RA (RB)
    rotate_left( RA, SPRITE_XOFFSET_SHIFT )
    and RA SPRITE_XOFFSET_MASK
	store RA sprite_x_offset
    and RA 0x80
	jumpz get_xy_offset_1

	load RA negative_sign_extend
	addm RA sprite_x_offset
	store RA sprite_x_offset 

get_xy_offset_1:
#   tile_Y_offset
    load RA (RB)
    and RA SPRITE_YOFFSET_MASK    
	store RA sprite_y_offset
    and RA 0x80
	jumpz get_xy_offset_exit

	load RA negative_sign_extend
	addm RA sprite_y_offset
	store RA sprite_y_offset

get_xy_offset_exit:
    ret

# --------------------------
# - READ FOREGROUND COLOUR -
# --------------------------

get_foreground_colour:
#   cpu_colour_reg
    move RB RD
    add RB SPRITE_FB_COLOUR_OFFSET
    load RA (RB)
    and RA SPRITE_FG_COLOUR_MASK  
    store RA CPU_COLOUR_REG
    ret

# --------------------------
# - READ BACKGROUND COLOUR -
# --------------------------

get_background_colour:
#   cpu_colour_reg
    move RB RD
    add RB SPRITE_FB_COLOUR_OFFSET
    load RA (RB)
    rotate_left( RA, SPRITE_BG_COLOUR_SHIFT )
    and RA SPRITE_FG_COLOUR_MASK  
    store RA CPU_COLOUR_REG
    ret

# --------------------
# - READ SPRITE TILE -
# --------------------

get_sprite_tile:
#   select tile 0 address
    move RB RD
    add RB SPRITE_TILE_OFFSET  

#   add tile offset  
    load RC (RD)
    and RC SPRITE_TILE_NUMBER_MASK    
    add RB RC

#   auto inc?
    load RA (RD)
    and RA SPRITE_AUTO_MASK
    jumpz get_sprite_tile_1
    
#   yes, inc tile number
    load RA (RD)
    and RA SPRITE_FLAG_MASK  
    add RC 1
    and RC SPRITE_TILE_NUMBER_MASK
    add RA RC
    store RA (RD)

get_sprite_tile_1:
#   cpu_addr_reg
    load RA (RB)
    store RA CPU_SRC_ADDR_REG
  	store RA sprite_tile
    ret

get_current_sprite_tile:
#   select tile 0 address
    move RB RD
    add RB SPRITE_TILE_OFFSET  

    load RC (RD)
    and RC SPRITE_TILE_NUMBER_MASK    
    add RB RC

#   cpu_addr_reg
    load RA (RB)
    store RA CPU_SRC_ADDR_REG
  	store RA sprite_tile
    ret

# ---------------
# - READ HITBOX -
# ---------------

get_hitbox:
#   get XHITBOX max min
    move RB RD
    add RB SPRITE_XHITBOX_OFFSET

    load RA (RB)
    and RA 0xFF
    store RA sprite_hitbox_x_min

    load RA (RB)
    rotate_left( RA, SPRITE_XHITBOX_MAX_SHIFT )
    and RA 0xFF
    store RA sprite_hitbox_x_max

#   get YHITBOX max min
    move RB RD
    add RB SPRITE_YHITBOX_OFFSET

    load RA (RB)
    and RA 0xFF
    store RA sprite_hitbox_y_min

    load RA (RB)
    rotate_left( RA, SPRITE_XHITBOX_MAX_SHIFT )
    and RA 0xFF
    store RA sprite_hitbox_y_max

get_hitbox_end
    ret

# ---------------
# - DRAW SPRITE -
# ---------------

# write FG and BG (assumed black) colours
# use XY pos

draw_sprite_subroutine:
    move RA DRAW_TILE
    store RA vga_command
    call get_foreground_colour
    call get_current_sprite_tile
    call sprite_operation
    ret

# --------------
# - DRAW PIXEL -
# --------------

# write FG and BG (assumed black) colours
# use XY pos

draw_pixel_subroutine:
    move RA DRAW_PIXEL
    store RA vga_command
    move RA GREEN
    store RA CPU_COLOUR_REG
    load RA x_position
    store RA PIXEL_X_REG
    load RA y_position
    store RA PIXEL_Y_REG    
    call sprite_operation
    ret

# ------------------
# - OVERLAY SPRITE -
# ------------------

# write only FG colour, if sprite pixel is no set do not write BG colour
# use XY pos

overlay_sprite_subroutine:
    move RA OVERLAY_TILE
    store RA vga_command
    call get_foreground_colour
    call get_current_sprite_tile
    call sprite_operation
    ret

# ----------------
# - CLEAR SPRITE -
# ----------------

# same as overlay sprite, but use background colour
# BG assumed black, through deletes previous FG pixels.

clear_sprite_subroutine:
    move RA OVERLAY_TILE
    store RA vga_command
    call get_background_colour
    call get_current_sprite_tile
    call sprite_operation
    ret

# --------------------
# - SPRITE OPERATION -
# --------------------

# used to display sprites in DRAW and OVERLAY 

sprite_operation:
#   test visibility
    load RC (RD)
    and RC SPRITE_VISIBLE_MASK   
    jumpz sprite_end

    call get_xy_position

#   ctl reg
    load RA vga_command
    store RA CPU_CTL_REG

sprite_operation_wait:
    movea( RA, CPU_STATUS_REG )
    load RB (RA)
    and RB CTL_MASK
    jumpz sprite_operation_wait
    ret

sprite_end:
    ret


#######################
# GENERAL SUBROUTINES #
#######################

# -------------
# - BIN 2 DEC -
# -------------

bin_2_dec:
	move RB RA

	move RA 0
	store RA bin_2_dec_1s_cnt
	store RA bin_2_dec_10s_cnt
	store RA bin_2_dec_100s_cnt

100s_loop:
	sub RB	100
	move RC RB
	rol RC
    and RC 1
	jumpnz 100s_loop_exit
	load RA bin_2_dec_100s_cnt
	add RA 1
	store RA bin_2_dec_100s_cnt
	jump 100s_loop

100s_loop_exit:
	add RB 100

10s_loop:
	sub RB	10
	move RC RB
	rol RC
    and RC 1
	jumpnz 10s_loop_exit
	load RA bin_2_dec_10s_cnt
	add RA 1
	store RA bin_2_dec_10s_cnt
	jump 10s_loop

10s_loop_exit:
	add RB 10

	move RA RB
	store RA bin_2_dec_1s_cnt
	ret

# -------------
# - DRAW CHAR -
# -------------

draw_char_subroutine:
#   cpu_colour_reg
    load RA block_colour
    store RA CPU_COLOUR_REG

#   xy_position:
    load RA block_x_top_pos
    store RA TILE_X_REG
    load RA block_y_top_pos   
    store RA TILE_Y_REG

#   set tile address
    move RA RD
    store RA CPU_SRC_ADDR_REG

#   ctl reg
    move RA DRAW_TILE
    store RA CPU_CTL_REG

draw_char_wait:
    movea( RA, CPU_STATUS_REG )
    load RB (RA)
    and RB CTL_MASK
    jumpz draw_char_wait
    ret

# ------------
# - DRAW BOX -
# ------------

# draw box directly to frame buffer
# 
# colour                  : block_colour
# top left x location     : block_x_top_pos
# bottom right x location : block_x_bottom_pos
# top left y location     : block_y_top_pos
# bottom right y location : block_y_bottom_pos

# uses block write subroutine
#  
# colour        : block_colour
# start address : block_start_address
# end address   : block_start_address + block_size
#

draw_box_subroutine:
#   calc start address

    load RA block_x_top_pos
    store RA TILE_X_REG
    load RA block_y_top_pos
    store RA TILE_Y_REG
    load RA TILE_POS
	store RA block_start_address

#   calc width
    load RA block_x_bottom_pos 
    subm RA block_x_top_pos
    rotate_left( RA, 15 )
    store RA block_size

#   draw line
    call block_write_subroutine

#   check if all rows drawn
    load RA block_y_bottom_pos
    subm RA block_y_top_pos
    jumpz draw_box_exit

#   increment Y
    load RA block_y_top_pos
    add RA 1
    store RA block_y_top_pos
    jump draw_box_subroutine

draw_box_exit:
    ret

# ---------------
# - BLOCK WRITE -
# ---------------

# write data directly to frame buffer
# colour        : block_colour
# start address : block_start_address
# end address   : block_start_address + block_size
#

block_write_subroutine:
#   cpu_colour_reg
    movea( RB, CPU_COLOUR_REG )
    load RA block_colour
    store RA (RB)

#   cpu_data_in_reg - end src addr
    movea( RB, CPU_DATA_IN_REG )
    load RA block_start_address
    addm RA block_size
    store RA (RB)

#   cpu_addr_reg
    movea( RB, CPU_DST_ADDR_REG )
    load RA block_start_address
    store RA (RB)

#   ctl reg 
    movea( RA, CPU_CTL_REG )
    move RB BLOCK_WRITE
    store RB (RA)

block_write_wait:
    movea( RA, CPU_STATUS_REG )
    load RB (RA)
    and RB CTL_MASK
    jumpz block_write_wait
    ret

# -----------------------
# - SOFTWARE TIME DELAY -
# -----------------------

delay:
    move RA 0x04
    store RA delay_high_count

delay_start:
    move RA 0x00
    store RA delay_low_count

delay_loop:
    load RA delay_low_count
    sub RA 1
    store RA delay_low_count
    jumpnz delay_loop

    load RA delay_high_count
    sub RA 1
    store RA delay_high_count
    jumpnz delay_loop
    ret

###########################
# VARIABLES AND CONSTANTS #
###########################

seed:
	.data 0
	
round_count: 
	.data 0
	
round_count_max: 
	.data 1000	
	
round_count_flag: 
	.data 0	
		
x_max:
    .data 100

y_max:
    .data 80

bit_array_data:
    .data 0

bit_array_offset:
    .data 0

bit_array_address:
    .data 0

bit_array_index:
    .data 0

x_position:
    .data 0

x_position_offset:
    .data 30

y_position:
    .data 0

y_position_offset:
    .data 25

row_count:
    .data 0

col_count:
    .data 0

vga_command:
    .data 0

cell_count:
    .data 0

cell_middle_state:
    .data 0

negative_sign_extend:
	.data 0xFF00

display_max_x_limit:
	.data MAX_X_LIMIT

display_max_y_limit:
	.data MAX_Y_LIMIT

bin_2_dec_1s_cnt:
	.data 0

bin_2_dec_10s_cnt:
	.data 0

bin_2_dec_100s_cnt:
	.data 0

delay_low_count:
	.data 0

delay_high_count:
	.data 0

block_start_address:
	.data 0

block_size:
	.data 0

block_colour:
	.data 0

block_x_top_pos:
	.data 0

block_x_bottom_pos:
	.data 0

block_y_top_pos:
	.data 0

block_y_bottom_pos:
	.data 0

sprite_command:
    .data 0

sprite_pntr:
    .data 0

sprite_pntr_1:
    .data 0

sprite_collision:
    .data 0

sprite_tile:
    .data 0

sprite_x_offset:
    .data 0

sprite_y_offset:
    .data 0

sprite_x_pos:
    .data 0

sprite_x_pos_1:
    .data 0

sprite_y_pos:
    .data 0

sprite_y_pos_1:
    .data 0

sprite_hitbox_x_min:
    .data 0

sprite_hitbox_x_min_1:
    .data 0

sprite_hitbox_x_max:
    .data 0

sprite_hitbox_x_max_1:
    .data 0

sprite_hitbox_y_min:
    .data 0

sprite_hitbox_y_min_1:
    .data 0

sprite_hitbox_y_max:
    .data 0

sprite_hitbox_y_max_1:
    .data 0

sprite_limit_x_min:
    .data 0

sprite_limit_x_max:
    .data 0

sprite_limit_y_min:
    .data 0

sprite_limit_y_max:
    .data 0

sprite_edge:
    .data 0

sprite_number:
    .data 0

present_grid:
    create_bit_array( eval( 101 * 81 ) )

present_grid_end:
    .data 0

next_grid:
    create_bit_array( eval( 101 * 81 ) )

next_grid_end:
    .data 0

random_value_offset:
	.data 0    
    
random_value:
	.data 0
	
random_data_max:
	.data 256	
    
random_data:
	.data 0x80C2
	.data 0x868C
	.data 0x4397
	.data 0x040E
	.data 0x0EEA
	.data 0x2657
	.data 0x3E0D
	.data 0x68E8
	.data 0x0F22
	.data 0xE770
	.data 0x0F91
	.data 0xA1E0
	.data 0x50AC
	.data 0xF3C2
	.data 0xECBC
	.data 0x72DA
	.data 0xC010
	.data 0x0675
	.data 0x71F9
	.data 0x25B5
	.data 0xCCC7
	.data 0xE6AB
	.data 0x78D1
	.data 0x028D
	.data 0xB8DC
	.data 0x2844
	.data 0x5B12
	.data 0x4F0E
	.data 0x49CB
	.data 0x9748
	.data 0xD90C
	.data 0x5BB0
	.data 0x7AC2
	.data 0x8083
	.data 0xA623
	.data 0x9A76
	.data 0xB357
	.data 0x0878
	.data 0x11E2
	.data 0x8579
	.data 0x9440
	.data 0x7AAB
	.data 0xF384
	.data 0x69D3
	.data 0xC105
	.data 0xDECD
	.data 0x1D51
	.data 0xCD34
	.data 0x20B7
	.data 0xAB2C
	.data 0xD2BD
	.data 0x63C0
	.data 0xBAD9
	.data 0x78CE
	.data 0x3E44
	.data 0xCFD2
	.data 0x2670
	.data 0xE04E
	.data 0x992E
	.data 0x479E
	.data 0x9015
	.data 0xBB46
	.data 0x0346
	.data 0x69EC
	.data 0x79EF
	.data 0x7972
	.data 0xFC8C
	.data 0x423C
	.data 0xA2FA
	.data 0xAB44
	.data 0xA052
	.data 0x562F
	.data 0xD557
	.data 0x761C
	.data 0xEB52
	.data 0xA6C0
	.data 0xD2B5
	.data 0x35D2
	.data 0xD4F3
	.data 0x15EF
	.data 0xFB70
	.data 0x449D
	.data 0x421A
	.data 0x2A3F
	.data 0x88F3
	.data 0xCA84
	.data 0x6F46
	.data 0x4896
	.data 0xBA91
	.data 0x9902
	.data 0x8BDE
	.data 0xB2D4
	.data 0x087D
	.data 0xE05F
	.data 0x907E
	.data 0x3150
	.data 0x3C0A
	.data 0x9E99
	.data 0x2C4F
	.data 0x1674
	.data 0xDCFF
	.data 0xF1B7
	.data 0xE967
	.data 0xCABE
	.data 0x0C22
	.data 0x347F
	.data 0xDAD2
	.data 0x4E6E
	.data 0xA412
	.data 0x1981
	.data 0xFF89
	.data 0xACE3
	.data 0x02BB
	.data 0xDF2B
	.data 0x341A
	.data 0x1D8B
	.data 0x16E7
	.data 0xEE95
	.data 0x9E69
	.data 0x154B
	.data 0xE2B0
	.data 0x09B4
	.data 0xC2A4
	.data 0xEA41
	.data 0x6426
	.data 0xB5F3
	.data 0x3BA7
	.data 0x509B
	.data 0x713E
	.data 0x13BB
	.data 0x6AF4
	.data 0xDA5B
	.data 0xF19F
	.data 0xE925
	.data 0xEA68
	.data 0x2D5A
	.data 0x1564
	.data 0xA790
	.data 0x64B1
	.data 0xE940
	.data 0xA726
	.data 0x89AE
	.data 0x2750
	.data 0x679F
	.data 0x15AF
	.data 0xAAEE
	.data 0x3395
	.data 0xABB1
	.data 0x774A
	.data 0xF049
	.data 0x5D81
	.data 0x91BE
	.data 0x9088
	.data 0x9190
	.data 0x2195
	.data 0xA4F0
	.data 0x34DA
	.data 0x4EA1
	.data 0xD945
	.data 0x289A
	.data 0xB13A
	.data 0x2B6E
	.data 0x1CAB
	.data 0x858B
	.data 0x82BA
	.data 0xC89C
	.data 0xAA6A
	.data 0x578D
	.data 0xB768
	.data 0x7161
	.data 0x6E6B
	.data 0xD6B6
	.data 0xC9B0
	.data 0x87A2
	.data 0xF135
	.data 0x88D6
	.data 0xF8FE
	.data 0x8E3F
	.data 0xB519
	.data 0x5369
	.data 0x98A4
	.data 0x1785
	.data 0x2F3B
	.data 0x8830
	.data 0xBA42
	.data 0x467C
	.data 0xE1D3
	.data 0x9492
	.data 0x3AFD
	.data 0x4A99
	.data 0xC6C2
	.data 0xCF02
	.data 0x8253
	.data 0x389B
	.data 0x4039
	.data 0xD371
	.data 0x64C4
	.data 0xE0E6
	.data 0x5FDA
	.data 0x2926
	.data 0xB8B1
	.data 0xD016
	.data 0x32DD
	.data 0x16BC
	.data 0xAC94
	.data 0xA784
	.data 0xAEE2
	.data 0xE78F
	.data 0x5576
	.data 0xFA4C
	.data 0x5575
	.data 0xDA02
	.data 0xD3F6
	.data 0x2FA9
	.data 0xE738
	.data 0xB3BD
	.data 0x0B70
	.data 0x8D17
	.data 0x5D04
	.data 0x31F9
	.data 0x3FD2
	.data 0x6982
	.data 0xCE38
	.data 0x327A
	.data 0x8136
	.data 0xDF91
	.data 0x2886
	.data 0xD183
	.data 0xED8E
	.data 0x3E0E
	.data 0xD89C
	.data 0xFD73
	.data 0x9D45
	.data 0x49E1
	.data 0xE327
	.data 0x1DF5
	.data 0x1D0C
	.data 0xF779
	.data 0x9967
	.data 0x250E
	.data 0x401A
	.data 0xF190
	.data 0x4B96
	.data 0x046D
	.data 0xCFEA
	.data 0x149E
	.data 0xDF69
	.data 0xA90E
	.data 0x719E
	.data 0xAEB0
	.data 0x5205
	.data 0xBB74
	.data 0x005D
	.data 0xEA2E
	.data 0x2AE5
	.data 0x085C

