specific address code

Here you can ask questions or provide insights about how to use efficiently 6502 assembly code on the Oric.
User avatar
Dbug
Site Admin
Posts: 5341
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: specific address code

Post by Dbug »

I tried to build the game, but I get errors:

Code: Select all

osdk = D:\Git\osdk\osdk\main\Osdk\_final_ osdkfile = main goyo_engine tables keyboard
Building the program CWADIASB at adress $600 [OSDK 1.20]
Assembling main.S
Assembling goyo_engine.S
Assembling tables.S
Assembling keyboard.S
Linking
Assembling
    ldx, mapx
D:\Git\goyo\cwadiasbook-master\goyo_engine.s(21):  0635:Syntax error
    ldy, mapy
D:\Git\goyo\cwadiasbook-master\goyo_engine.s(22):  0638:Syntax error
(.
D:\Git\goyo\cwadiasbook-master\goyo_engine.s(37):  0641:Syntax error
)
D:\Git\goyo\cwadiasbook-master\goyo_engine.s(63):  0666:Syntax error
D:\Git\goyo\cwadiasbook-master\goyo_engine.s(30):  0639:Label 'backscreen_width' not defined
Break after 5 errors
ERROR : Build failed.
Press any key to continue . . .
User avatar
goyo
Pilot Officer
Posts: 82
Joined: Sat Jan 12, 2019 10:16 am
Location: Chatenay-Malabry

Re: specific address code

Post by goyo »

Dbug wrote: Sun Dec 07, 2025 11:10 am I tried to build the game, but I get errors:

Code: Select all

osdk = D:\Git\osdk\osdk\main\Osdk\_final_ osdkfile = main goyo_engine tables keyboard
Building the program CWADIASB at adress $600 [OSDK 1.20]
Assembling main.S
Assembling goyo_engine.S
Assembling tables.S
Assembling keyboard.S
Linking
Assembling
    ldx, mapx
D:\Git\goyo\cwadiasbook-master\goyo_engine.s(21):  0635:Syntax error
    ldy, mapy
D:\Git\goyo\cwadiasbook-master\goyo_engine.s(22):  0638:Syntax error
(.
D:\Git\goyo\cwadiasbook-master\goyo_engine.s(37):  0641:Syntax error
)
D:\Git\goyo\cwadiasbook-master\goyo_engine.s(63):  0666:Syntax error
D:\Git\goyo\cwadiasbook-master\goyo_engine.s(30):  0639:Label 'backscreen_width' not defined
Break after 5 errors
ERROR : Build failed.
Press any key to continue . . .
I am sorry Debug, i made a branch for the c version and i sent to you the first par of the 100% asm version.

this is the good version :

https://github.com/gweg/cwadiasbook/tree/c_version
User avatar
Dbug
Site Admin
Posts: 5341
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: specific address code

Post by Dbug »

Ok, that one worked.

So I did a quick look, and there are things you should definitely not do, like that:

Code: Select all

      if  (keypress == 80 || keypress == 9 || keypress == 'P')
      {
      }
      if  ((keypress == 79 || keypress == 'O' || keypress == 8 ))
      {         
      }
Basically the code tests every single of the possible keys, one by one, all the time, just adding a "else" makes it so we can exit as soon as one case has matched:

Code: Select all

      if  (keypress == 80 || keypress == 9 || keypress == 'P')
      {
      }
      else
      if  ((keypress == 79 || keypress == 'O' || keypress == 8 ))
      {         
      }
But the most efficient code is to use switch/case, by far, because the compiler generates a table and jumps to the proper label directly.

Code: Select all

      switch (keypress)
      {
      case 9:
      case 'P':
         {
         }
         break;
      case 'O':
      case 8:
         {  
         }
         break;
User avatar
Dbug
Site Admin
Posts: 5341
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: specific address code

Post by Dbug »

Second thing: The compiler is crap, you must check the generated code either by looking in the Oricutron debugger, or by looking in %OSDK%/TMP/Linked.s.

Example:

Code: Select all

void backScreenClear()
{  
   unsigned char paper=current_paper_color;
   unsigned char ink =current_ink_color;

   (...)	
   poke(backscreenaddress+80,paper);
   poke(backscreenaddress+120,paper);
   (...)
   poke(backscreenaddress+1120,paper);
   
   poke(backscreenaddress+81,ink);
   poke(backscreenaddress+121,ink);
   (...)
   poke(backscreenaddress+1121,ink);
}
This compiles to that:
image_2025-12-07_201239573.png
There was an obvious way to optimize, but it exploded in my face because you are doing things you really should not be doing: Don't have the same symbol defined differently in different modules:

Code: Select all

main.c
#define backscreenaddress  0x9fff // 0xa000 ,  0xBBa8 - 80 = 0xbb58

asm.s
#define BACK_SCREEN_ADDRESS $9FFF ; A000
backscreenaddress .byt <(BACK_SCREEN_ADDRESS),>(BACK_SCREEN_ADDRESS)
Basically depending if the preprocessor has been running or not, backscreen address will either be the value 0x9fff or the address of a 16bit value containing the value 0x9fff. This is definitely going to blow in your face when you move code around.

So when I tried to optimize the code like that:

Code: Select all

   asm(
      "lda _current_paper_color;"
      "sta backscreenaddress+80;
    )
I was not actually modifying the value at $9000+80, I was instead modifying the data after backscreenaddress, basically trashing memory.

So after replacing the poke by just a single lda followed by sta, the code looks like that:
image_2025-12-07_203856895.png
As you can see the right side is significantly shorter than the left side.

So basically before thinking of optimizing the important routines, you need to do a global cleaning pass on the code, remove all the stuff which is suggested by modern programmers because they will make the performance worse: Use the processor, use defines, use global variables, don't pass parameters by the stack if the code is not supposed to be recursive, don't copy values in temporary variables, etc... and more importantly: Look at the generated code, trace the code, use the Oricutron clock cycle counter to know how long a routine takes.

Also don't do work in double: If you have validate that a collision to the left happened, do not check if you collided to the right. Use the knowledge of what the game logic does to avoid doing work that is not necessary.

As often said, the fastest code is the one that does not run at all :D
You do not have the required permissions to view the files attached to this post.
User avatar
goyo
Pilot Officer
Posts: 82
Joined: Sat Jan 12, 2019 10:16 am
Location: Chatenay-Malabry

Re: specific address code

Post by goyo »

Thank you very much professor Dbug, for this personal lesson. I think I should go back to school :? since I never really went in the first place! I’m missing an engineer’s discipline :cry: — I tend to do things too from scratch, and then debugging becomes complicated. :roll:
With your advice, I realize more than ever that there is still so much to learn in programming. :o
User avatar
Dbug
Site Admin
Posts: 5341
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: specific address code

Post by Dbug »

goyo wrote: Tue Dec 09, 2025 7:19 pm Thank you very much professor Dbug, for this personal lesson. I think I should go back to school :? since I never really went in the first place! I’m missing an engineer’s discipline :cry: — I tend to do things too from scratch, and then debugging becomes complicated. :roll:
With your advice, I realize more than ever that there is still so much to learn in programming. :o
There's nothing wrong with making things from scratch, but what's important is to keep the code maintainable, which means:

- Be consistent with the formatting and the conventions: Keep the same style of naming for things that are similar, keep spaces/tabs consistent from function to function, etc... which means that if at some point you decide it's better (for you) to do something differently, it's worth spending the time fixing the existing code (ie: "refactoring") so it matches the new way of doing things.

- Make the code "searchable". I'm not sure which editor you are using, but for example in VSCode it's trivial to find all the occurrences of a word in the entire project, that makes it very quick to find where something is... assuming things are named properly :)

- Embrace revision control: Don't keep "main.old" or "file_v2" or "test_2025_12_09", make sure that each file in your project is useful and at the right version. If you need to go back to a previous version it's available in git... which means that every time you have a working version, commit the change with a comment. And whatever is in the repository should be working at any time: Never commit broken code, if you need, create a branch.

- Use the zero page for things you often use, like parameters passing for example, instead of using the stack, but make sure to clearly document what each variable is for so you avoid reusing one in multiple places.

- Use the .bss to define buffers at specific locations: I'm using that in Encounter for example to partition the overlay memory and the various memory areas in the video/charset memory.

- Remove unused code

- Use the map file viewer to track the size of the code and the variables, it's also a practical way to know where you are in the code when using the debugger.
image_2025-12-09_200904793.png
You do not have the required permissions to view the files attached to this post.
User avatar
Dbug
Site Admin
Posts: 5341
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: specific address code

Post by Dbug »

Looking at the code, I saw that one of the large functions was "_sprite" which took 1663 bytes. Found out that the main culprit was the *40 repeated on every line: The compiler in the OSDK does not do this type of optimisation, so each of the calls actually calls the "mul16u" function, that takes a lot of room and a lot of CPU time.
image_2025-12-09_202843516.png
The version on the right just precalculated two pointers with the "invariants" and that was enough to reduce the size to 1349 bytes and only keep the first *40 for the first entry.

A proper optimization would be to have a table to target the scanline, like you have for the screen location.

The next candidate for optimization would be the "drawtiles()" function which calls sub functions to draw each tile: Since the tile order never changes (contrarily to sprites), the entire routine should be just one function that draws all the tiles in one go so you don't have to recompute the screen address or the X position: Just draw from left to right and top to bottom updating the current position, and you can remove pretty much all the parameters of the function.

Like in this code:

Code: Select all

   for (iy=0;iy<11;iy++)
   {
         iy_map_width= map_width_index_y_lookup_table[iy+1];
         map_y_index = map_y_index_lookup_table[mapy]; 
         drawtile(0,iy,mapdx,mapdy,map[mapx+iy_map_width+0+map_y_index],inv);
         drawtile(1,iy,mapdx,mapdy,map[mapx+iy_map_width+1+map_y_index],inv);
         drawtile(2,iy,mapdx,mapdy,map[mapx+iy_map_width+2+map_y_index],inv);
         drawtile(3,iy,mapdx,mapdy,map[mapx+iy_map_width+3+map_y_index],inv);
         drawtile(4,iy,mapdx,mapdy,map[mapx+iy_map_width+4+map_y_index],inv);
         drawtile(5,iy,mapdx,mapdy,map[mapx+iy_map_width+5+map_y_index],inv);
         drawtile(6,iy,mapdx,mapdy,map[mapx+iy_map_width+6+map_y_index],inv);
         drawtile(7,iy,mapdx,mapdy,map[mapx+iy_map_width+7+map_y_index],inv);
         drawtile(8,iy,mapdx,mapdy,map[mapx+iy_map_width+8+map_y_index],inv);
         drawtile(9,iy,mapdx,mapdy,map[mapx+iy_map_width+9+map_y_index],inv);
         drawtile(10,iy,mapdx,mapdy,map[mapx+iy_map_width+10+map_y_index],inv);
         drawtile(11,iy,mapdx,mapdy,map[mapx+iy_map_width+11+map_y_index],inv);
         drawtile(12,iy,mapdx,mapdy,map[mapx+iy_map_width+12+map_y_index],inv);
         drawtile(13,iy,mapdx,mapdy,map[mapx+iy_map_width+13+map_y_index],inv);
   }
you push on the stack iy,mapdx,mapdy,inv to each of the 14 calls... despite none of these values ever changing in a scanline.
If instead you use some zero page variable for these values, you can just use it directly instead of passing it.
You do not have the required permissions to view the files attached to this post.
Post Reply