WIP: optimized update function written in assembly

This commit is contained in:
Christophe Meneboeuf 2016-09-22 22:20:08 +02:00
parent d0f9aefac8
commit 45cb5b87b5
5 changed files with 516 additions and 40 deletions

View File

@ -2,4 +2,4 @@ Time to 50 iterations
50ef808 : 111:94
555db95 : 38:51
latest : 15:43
d0f9aef : 15:43

View File

@ -9,6 +9,8 @@
/******************* FUNCTION DEFINITIONS **************/
void __fastcall__ init_asm( uint8_t* p_cell, uint8_t* p_cells_future ); /* Inits the variables used in the ASM scope */
void init_display( void ); /* Inits displayed playfield */
void draw_cells( void ); /* Draws the actual cells */
void editor( void ); /* lets the user draw some starting cells */
@ -16,16 +18,16 @@ uint8_t toggle_cell( const uint8_t x, const uint8_t y ); /* toggles the cell at
Returns the cursor X position */
void run( void ); /* runs the simulation */
void update( void ); /* updates the simulation */
uint8_t __fastcall__ count_neighbours( uint8_t* cell ); /* counts nb neighbours of the cell */
void __fastcall__ update( void ); /* updates the simulation */
void __fastcall__ update_asm( void ); /* updates the simulation */
uint8_t __fastcall__ count_neighbours( uint8_t* cell ); /* counts nb neighbours of the cell */
void quit( void );
/******************* CUSTOM TYPES AND VALUES DEFINITIONS ****************/
#define NB_LINES 23
#define NB_COLUMNS 40
const uint8_t JUMP_BEGINNING_NEXT_LINE = NB_LINES - 2u;
#define NB_LINES 23u
#define NB_COLUMNS 40u
#define ALIVE 1u
#define DEAD 0u
@ -56,6 +58,14 @@ int main( int argc, char** argv )
(void)argc;
(void)argv;
//+ DEBUG
//gotoxy(0,0);
//printf("Cells:0x%x - Cells_future:0x%x",(uint16_t)(&Cells[0][0]),(uint16_t)(&Cells_Future[0][0]));
//cgetc();
//- DEBUG
init_asm( (uint8_t*)Cells, (uint8_t*)Cells_Future );
/* Running the state machine */
while( State != STATE_QUIT )
{
@ -81,7 +91,7 @@ int main( int argc, char** argv )
State = STATE_QUIT;
}
break;
default:
default:
printf("ERROR!");
State = STATE_QUIT;
break;
@ -128,7 +138,7 @@ void draw_cells( void ) {
cputcxy ( x, y, SPRITE_DEAD );
}
}
}
}
}
@ -140,7 +150,7 @@ void editor( void )
#define KEY_RIGHT 'l'
uint8_t quit, x, y;
gotoxy( 0u, NB_LINES );
printf("EDITOR (D)one");
@ -209,7 +219,7 @@ void run( void )
while( KeyPressed == NO_KEY)
{
/* Evolving the cells */
update();
update( );
/* Printing iterations */
gotoxy(10u, NB_LINES);
printf( itoa(nb_iterations++, str_nb_iteration, 10) );
@ -222,39 +232,38 @@ void run( void )
}
void update( void )
void __fastcall__ update( void )
{
uint8_t x, y;
uint8_t* cell_neighbourhoud = &Cells[0][0]; // cell_neighbourhoud = &Cells[0][0];
uint8_t* cell = cell_neighbourhoud + NB_LINES + 1u; // cell = &Cells[1][1];
uint8_t* cell_future = &Cells_Future[0][0] + NB_LINES + 1u; // cell_future = &Cells_Future[1][1];
uint8_t* cell_neighbourhoud = (uint8_t*)Cells; // cell_neighbourhoud = &Cells[0][0];
uint8_t* cell_line = cell_neighbourhoud + NB_LINES + 1u; // cell_line = &Cells[1][1];
uint8_t* cell_future = (uint8_t*)Cells_Future + NB_LINES + 1u; // cell_future = &Cells_Future[1][1];
for( y = 1u; y < NB_LINES - 1u; ++y )
{
uint8_t* cell_line = cell;
uint8_t* cell_curr = cell_line;
uint8_t* cell_neighbourhoud_line = cell_neighbourhoud;
uint8_t* cell_future_line = cell_future;
for( x = 1u; x < NB_COLUMNS - 1u; ++x)
{
uint8_t nb_neighbours = count_neighbours( cell_neighbourhoud_line );
if( *cell_line == ALIVE && \
if( *cell_curr == ALIVE && \
(nb_neighbours < 2u || nb_neighbours > 3u )
) {
*cell_future_line = DEAD;
cputcxy( x, y, SPRITE_DEAD );
}
else if( *cell_line == DEAD && nb_neighbours == 3u ) {
else if( *cell_curr == DEAD && nb_neighbours == 3u ) {
*cell_future_line = ALIVE;
cputcxy( x, y, SPRITE_ALIVE );
}
cell_line += NB_LINES;
cell_curr += NB_LINES;
cell_neighbourhoud_line += NB_LINES;
cell_future_line += NB_LINES;
}
++cell;
++cell_line;
++cell_neighbourhoud;
++cell_future;
}
memcpy( Cells, Cells_Future, sizeof(Cells) );
}

267
gol_apple2.c.bak Executable file
View File

@ -0,0 +1,267 @@
/* Standard headers */
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
/* Specific headers */
#include <conio.h>
/******************* FUNCTION DEFINITIONS **************/
void init_display( void ); /* Inits displayed playfield */
void draw_cells( void ); /* Draws the actual cells */
void editor( void ); /* lets the user draw some starting cells */
uint8_t toggle_cell( const uint8_t x, const uint8_t y ); /* toggles the cell at the given coordinates. \
Returns the cursor X position */
void run( void ); /* runs the simulation */
void __fastcall__ update( uint8_t* cells, uint8_t* cells_future ); /* updates the simulation */
void __fastcall__ update_asm( uint8_t* cells, uint8_t* cells_future ); /* updates the simulation */
uint8_t __fastcall__ count_neighbours( uint8_t* cell ); /* counts nb neighbours of the cell */
void quit( void );
/******************* CUSTOM TYPES AND VALUES DEFINITIONS ****************/
#define NB_LINES 23u
#define NB_COLUMNS 40u
#define ALIVE 1u
#define DEAD 0u
#define SPRITE_ALIVE '0'
#define SPRITE_DEAD ' '
#define STATE_INIT 0u
#define STATE_EDITOR 1u
#define STATE_RUN 2u
#define STATE_QUIT 3u
uint8_t State = STATE_INIT;
#define NO_KEY '\0'
char KeyPressed = NO_KEY;
/******************* STATIC GLOBAL VARIABLES ******************/
uint8_t Cells[ NB_COLUMNS ][ NB_LINES ];
uint8_t Cells_Future[ NB_COLUMNS ][ NB_LINES ];
uint8_t Cells_Initial[ NB_COLUMNS ][ NB_LINES ];
/******************** CODE ************************/
int main( int argc, char** argv )
{
(void)argc;
(void)argv;
/* Running the state machine */
while( State != STATE_QUIT )
{
switch (State) {
case STATE_INIT:
memset( Cells, DEAD, sizeof(Cells) );
init_display();
State = STATE_EDITOR;
break;
case STATE_EDITOR:
editor();
State = STATE_RUN;
break;
case STATE_RUN:
run();
if( KeyPressed == 'e' ) { /* Go back to editor */
State = STATE_EDITOR;
} else if( KeyPressed == 'r' ) { /* reset and rerun */
memcpy( Cells, Cells_Initial, sizeof(Cells) );
memcpy( Cells_Future, Cells_Initial, sizeof(Cells_Future) );
draw_cells();
} else if( KeyPressed == 'q' ) { /* quit */
State = STATE_QUIT;
}
break;
default:
printf("ERROR!");
State = STATE_QUIT;
break;
}
}
quit();
return 0;
}
void quit( void )
{
uint8_t x, y;
screensize (&x, &y);
gotoxy( 1u, y-1u );
printf("BYE BYE!");
exit(0);
}
void init_display( void )
{
clrscr();
chlinexy (1u, 0u, NB_COLUMNS-2u );
chlinexy (1u, NB_LINES-1u, NB_COLUMNS-2u );
cvlinexy (0u, 1u, NB_LINES-1u );
cvlinexy (NB_COLUMNS-1u, 1u, NB_LINES-1u );
cputcxy ( 0u, 0u, '+' );
cputcxy ( 0u , NB_LINES-1u,'+');
cputcxy ( NB_COLUMNS-1u, 0u,'+');
cputcxy ( NB_COLUMNS-1u, NB_LINES-1u,'+');
}
void draw_cells( void ) {
uint8_t x, y;
for( x = 1u; x < NB_COLUMNS - 1u; ++x )
{
for( y = 1u; y < NB_LINES - 1u; ++y )
{
if( Cells[x][y] == ALIVE ) {
cputcxy ( x, y, SPRITE_ALIVE );
} else {
cputcxy ( x, y, SPRITE_DEAD );
}
}
}
}
void editor( void )
{
#define KEY_LEFT 'j'
#define KEY_DOWN 'k'
#define KEY_UP 'i'
#define KEY_RIGHT 'l'
uint8_t quit, x, y;
gotoxy( 0u, NB_LINES );
printf("EDITOR (D)one");
x = NB_COLUMNS >> 1u;
y = NB_LINES >> 1u;
gotoxy(x,y);
quit = 0;
while ( quit == 0)
{
cursor(1);
KeyPressed = cgetc();
switch (KeyPressed) {
case KEY_LEFT:
if( x > 1u ) { gotoxy( --x, y ); }
break;
case KEY_DOWN:
if( y < NB_LINES-2u ) { gotoxy( x, ++y ); }
break;
case KEY_UP:
if( y > 1u ) { gotoxy( x, --y ); }
break;
case KEY_RIGHT:
if( x < NB_COLUMNS-2u ) { gotoxy( ++x, y ); }
break;
case ' ':
x = toggle_cell( x, y );
break;
case 'd':
quit = 1;
break;
}
}
/* Cells was updated by the calls to toggle() */
memcpy( Cells_Future, Cells, sizeof(Cells_Future) );
memcpy( Cells_Initial, Cells, sizeof(Cells_Initial) );
}
uint8_t toggle_cell( const uint8_t x, const uint8_t y )
{
char* cell;
if( x == 0u || x >= NB_COLUMNS-1u || y == 0u || y >= NB_LINES-1u ) { return x; }
cell = &Cells[x][y];
if( *cell == DEAD ) {
*cell = ALIVE;
cputc( SPRITE_ALIVE );
} else {
*cell = DEAD;
cputc( SPRITE_DEAD );
}
return wherex ();
}
void run( void )
{
char str_nb_iteration [5];
uint16_t nb_iterations = 2u;
KeyPressed = NO_KEY;
cursor(0);
//+ DEBUG
gotoxy(0,0);
printf("Cells:0x%x - Cells_future:0x%x",(uint16_t)(&Cells[0][0]),(uint16_t)(&Cells_Future[0][0]));
cgetc();
//- DEBUG
gotoxy( 0u, NB_LINES );
printf("Iteration:1 (R)eset (E)ditor (Q)uit");
while( KeyPressed == NO_KEY)
{
/* Evolving the cells */
update_asm( &Cells[0][0], &Cells_Future[0][0] );
/* Printing iterations */
gotoxy(10u, NB_LINES);
printf( itoa(nb_iterations++, str_nb_iteration, 10) );
/* Testing key pressed */
if( kbhit() ){
KeyPressed = cgetc();
break;
}
}
}
void __fastcall__ update( uint8_t* cells, uint8_t* cells_future )
{
uint8_t x, y;
uint8_t* cell_neighbourhoud = cells; // cell_neighbourhoud = &Cells[0][0];
uint8_t* cell = cell_neighbourhoud + NB_LINES + 1u; // cell = &Cells[1][1];
uint8_t* cell_future = cells_future + NB_LINES + 1u; // cell_future = &Cells_Future[1][1];
for( y = 1u; y < NB_LINES - 1u; ++y )
{
uint8_t* cell_line = cell;
uint8_t* cell_neighbourhoud_line = cell_neighbourhoud;
uint8_t* cell_future_line = cell_future;
for( x = 1u; x < NB_COLUMNS - 1u; ++x)
{
uint8_t nb_neighbours = count_neighbours( cell_neighbourhoud_line );
if( *cell_line == ALIVE && \
(nb_neighbours < 2u || nb_neighbours > 3u )
) {
*cell_future_line = DEAD;
cputcxy( x, y, SPRITE_DEAD );
}
else if( *cell_line == DEAD && nb_neighbours == 3u ) {
*cell_future_line = ALIVE;
cputcxy( x, y, SPRITE_ALIVE );
}
cell_line += NB_LINES;
cell_neighbourhoud_line += NB_LINES;
cell_future_line += NB_LINES;
}
++cell;
++cell_neighbourhoud;
++cell_future;
}
memcpy( cells, cells_future, sizeof(Cells) );
}

View File

@ -1,56 +1,169 @@
.include "apple2.inc"
.include "zeropage.inc"
.export _init_asm
.export _count_neighbours
.export _update_wip
.define NB_LINES 23
.define NB_COLUMNS 40
.define JUMP_BEGINNING_NEXT_LINE NB_LINES - 2
; ******************
;uint8_t __fastcall__ count_neighbours( uint8_t* cell )
;param: cell is in AX
; ! A, X, Y & PTR4 ARE OVERWRITTEN !
_count_neighbours:
;ASSUMPTIONS:
; -> A and Y (offset to starting ptr) won't overflow!
;alias
cell := ptr4
;init
STA ptr1
STX ptr1+1
STA cell
STX cell+1
LDA #0
LDY #0
CLC
;acc 1st row
ADC (ptr1),Y
ADC (cell),Y
INY
ADC (ptr1),Y
ADC (cell),Y
INY
ADC (ptr1),Y
;next row
ADC (cell),Y
;next row
STA tmp1
TYA
ADC #$15
ADC #JUMP_BEGINNING_NEXT_LINE
TAY
LDA tmp1
ADC (ptr1),Y
ADC (cell),Y
INY
INY
ADC (ptr1),Y
;next row
ADC (cell),Y
;next row
STA tmp1
TYA
ADC #$15
ADC #JUMP_BEGINNING_NEXT_LINE
TAY
LDA tmp1
ADC (ptr1),Y
ADC (cell),Y
INY
ADC (ptr1),Y
ADC (cell),Y
INY
ADC (ptr1),Y
ADC (cell),Y
;return
TAX
LDX #0
RTS
;************************* WORK IN PROGRESS **************************
.BSS
Cells: .word $0
Cells_Future: .word $0
cell_neighbourhoud: .word $0
cell_line: .word $0
cell_future: .word $0
.CODE
;16 bit addition of the content of an adress with a 16bit value
.macro add_16 addr_dst, addr_src, value_low, value_hi
CLC
LDA addr_src
ADC value_low
STA addr_dst
LDA addr_src+1
ADC value_hi
STA addr_dst+1
.endmacro
;16 bit copy from a memory location to another
.macro copy_16 addr_dst, addr_src
LDA addr_src
STA addr_dst
LDA addr_src+1
STA addr_dst+1
.endmacro
; ******************
; Initialize the variables used in ASM functions
;void __fastcall__ init_asm( uint8_t* p_cell, uint8_t* p_cells_future )
;param: p_cell is in AX
; p_cells_future in sreg
_init_asm:
STA Cells
STX Cells+1
;FIXME : clearly Cells_Future IS NOT in sreg!!!
LDA sreg
STA Cells_Future
LDA sreg+1
STX Cells_Future+1
RTS
; ******************
;void __fastcall__ update( void )
; ! A, X, Y & ALL PTRx ARE OVERWRITTEN !
_update_wip:
;aliases
cell_curr := ptr1
cell_neighbourhoud_line := ptr2
cell_future_line := ptr3
;preambule
; cell_neighbourhoud = Cells
copy_16 cell_neighbourhoud, Cells
; cell_line = cell_neighbourhoud + NB_LINES + 1u
add_16 cell_line, cell_neighbourhoud, #NB_LINES+1, #0
; cell_future = Cells_Future + NB_LINES + 1u
add_16 cell_future, Cells_Future, #NB_LINES+1, #0
; loop : for( y = 1u; y < NB_LINES - 1u; ++y )
LDY #1
loop_y:
CPY #NB_LINES-1
BEQ end_y
copy_16 cell_curr, cell_line
copy_16 cell_neighbourhoud_line, cell_neighbourhoud
copy_16 cell_future_line, cell_future
;PAS BESOIN DE CES POINTEURS: ADRESSE DE BASE + X ???
loop_x:
CPX #NB_LINES-1
BEQ end_x
;TODO
INX
CLC
BCC loop_x
end_x:
INY
CLC
BCC loop_y
end_y:
RTS

87
gol_apple2_optimized.asm.bak Executable file
View File

@ -0,0 +1,87 @@
.include "apple2.inc"
.include "zeropage.inc"
.export _count_neighbours
.export _update_asm
.import _Cells
.import _Cells_Future
.define NB_LINES 23
.define NB_COLUMNS 40
.define JUMP_BEGINNING_NEXT_LINE NB_LINES - 2
; ******************
;void __fastcall__ update( uint8_t* cells, uint8_t* cells_future )
;cells_future in sreg
;cells in ptr1
;cells in neighbourhoud in ptr2
;current cell in ptr3
;future cell in ptr4
_update_asm:
;preambule
STA ptr1
STX ptr1+1
STA ptr2
STX ptr2+1
RTS
; ******************
;uint8_t __fastcall__ count_neighbours( uint8_t* cell )
;param: cell is in AX
_count_neighbours:
;ASSUMPTIONS:
; -> A and Y (offset to starting ptr) won't overflow!
;init
STA ptr1
STX ptr1+1
LDA #0
LDY #0
CLC
;acc 1st row
ADC (ptr1),Y
INY
ADC (ptr1),Y
INY
ADC (ptr1),Y
;next row
STA tmp1
TYA
ADC #JUMP_BEGINNING_NEXT_LINE
TAY
LDA tmp1
ADC (ptr1),Y
INY
INY
ADC (ptr1),Y
;next row
STA tmp1
TYA
ADC #JUMP_BEGINNING_NEXT_LINE
TAY
LDA tmp1
ADC (ptr1),Y
INY
ADC (ptr1),Y
INY
ADC (ptr1),Y
;return
TAX
LDX #0
RTS