6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 9:20 am

All times are UTC




Post new topic Reply to topic  [ 27 posts ]  Go to page Previous  1, 2
Author Message
 Post subject: Re: Orac Draughts.
PostPosted: Mon Jul 15, 2024 12:01 pm 
Online

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 336
llvm does considerably better if you ask for optimised code. With -O (I don't know what optimisation levels llvm-mos supports), it gives
Code:
showcharset():                       ; @showcharset()
        ldy     #0
        ldx     #30
        tya
.LBB0_1:                                ; =>This Inner Loop Header: Depth=1
        sta     __rc2
        stx     __rc3
        sta     (__rc2),y
        clc
        adc     #1
        cmp     #0
        bne     .LBB0_1
        rts

which is pretty good. If I had a lot of code to write and didn't need all of it to be the fastest possible, that's more than acceptable.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 15, 2024 3:42 pm 
Offline

Joined: Thu Apr 23, 2020 5:04 pm
Posts: 53
orac81 wrote:
Now the interesting(?) thing is - I cannot find any 6502 program that plays 10x10 International draughts! So I was trying to get the c99 text version of Dynamo to compile with cc65, but it keeps throwing out-of-memory, even targeting a plus4 or c64. Can anyone suggest a better 6502 (C89) C compiler?

It is unlikely that any compiler will get this down to fit onto a bare C64 without changes. The code is pretty big and uses a lot of replication. I could get it to compile using vbcc for a C64 with REU, distributing the code into several banks. The resulting binary draws the board and can display the help screen, but executing a move seems to throw an error. However, this also happens with a version compiled on Linux, so there may be additional problems. Perhaps I will have a more thorough look into this.

Quote:
I did start thinking in terms of pattern recognition within the intemediate code, so for example

#define VDU 0x1e00 /* C64 0x0400 etc */
void showcharset ()
{
register BYTE x;
x=0;
do {
*(VDU+x) = x;
x++;
} while (x);
}

Changing this code to be compilable and compiling it with vbcc gives:
Code:
$ cat l1.c
#define VDU ((BYTE*)0x1e00) /* C64 0x0400 etc */

typedef unsigned char BYTE;

void showcharset ()
{
register BYTE x;
x=0;
do {
*(VDU+x) = x;
x++;
} while (x);
}
$ vc +c64 -O -S l1.c
$ cat l1.asm
;vcprmin=10000
        section text
        global  _showcharset
_showcharset:
        lda     #0
        sta     r2
l6:
        lda     r2
        tay
        sta     7680,y ;am(r2)
        inc     r2
        lda     r2
        bne     l6
        rts


Using x as index as well as value to be written prevents vbcc from using the x register here. This code, for example, uses the x register:

Code:
$ cat l2.c
#define VDU ((BYTE*)0x1e00) /* C64 0x0400 etc */

typedef unsigned char BYTE;

extern BYTE src[];

void showcharset ()
{
register BYTE x;
x=0;
do {
*(VDU+x) = src[x];
x++;
} while (x);
}
$ vc +c64 -O -S l2.c
$ cat l2.asm
;vcprmin=10000
        section text
        global  _showcharset
_showcharset:
        ldx     #0
l6:
        lda     0+_src,x ;am(x)
        sta     7680,x ;am(x)
        inx
        bne     l6
        rts


Top
 Profile  
Reply with quote  
 Post subject: Re: Orac Draughts.
PostPosted: Wed Jul 17, 2024 1:42 pm 
Offline

Joined: Sat Apr 20, 2024 4:01 pm
Posts: 14
Thanks for all the input and comments, very useful! I will have to try the latest versions of LLVM and VBCC, and do a bit experimenting. Both those examples seem better than earlier compilers. I am impressed that VBCC is realising that it can use sta abs,x directly.
As for register vars, maybe a compiler directive could be implemented, something like:

//$$6502:PREFER_REG_X (tell compiler to prefer/try to use X for next var)
BYTE x;

//$$6502:PREFER_ABS_CONST (tell compiler to prefer lda/sta ABS[,x] mode for next constant PTR)
const BYTE *pVdu = 0x0400;
etc..

(PREFER_ZP_CONST or PREFER_REG_A might be alternative use cases.)

The source of DYNAMO is very untidy, my only excuse is that goes back to pre-web work with Turbo C and PCs with floppys. Did stdint exist then? There are probably bugs lurking in the code. Anyway I can improve the code with time. Also I can reduce the size of the arrays used, particularly if I set a limit to search depth. Some arrays can be BYTE rather than int, etc.
I should be able to make a 6502 compile work eventually.

_________________
Github: https://github.com/orac81


Top
 Profile  
Reply with quote  
 Post subject: Re: Orac Draughts.
PostPosted: Wed Jul 17, 2024 5:21 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8514
Location: Midwestern USA
orac81 wrote:
Thanks for all the input and comments, very useful! I will have to try the latest versions of LLVM and VBCC...

I’ve not done anything with either compiler—programming in C is low on my list of interests, but I have read plenty of positive commentary about VBCC in my travels around the Internet.  Developing a C compiler for the 6502/65C02 that emits reasonably succinct machine code is a significant programming challenge.  What I’ve read seems to indicate VBCC’s output is pretty efficient despite the challenges.  It also helps that the individual who developed VBCC is a member of this forum.  :)

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject: Re: Orac Draughts.
PostPosted: Sat Jul 20, 2024 1:31 am 
Offline

Joined: Thu Apr 23, 2020 5:04 pm
Posts: 53
orac81 wrote:
The source of DYNAMO is very untidy, my only excuse is that goes back to pre-web work with Turbo C and PCs with floppys. Did stdint exist then? There are probably bugs lurking in the code. Anyway I can improve the code with time. Also I can reduce the size of the arrays used, particularly if I set a limit to search depth. Some arrays can be BYTE rather than int, etc.
I should be able to make a 6502 compile work eventually.

Out of curiosity I compiled it with my work-in-progress vbcc65816 which obviously has no problem with the memory requirements. I can have the computer make moves and (when deactivating randomization) it seems to give the same results as the linux version. However, I always get "Bad move!" whenever I try to make a manual move (even when using the same move the computer would choose). The same behaviour with the linux version. I did not investigate it further. Is this a bug or am I missing something?


Top
 Profile  
Reply with quote  
 Post subject: Re: Orac Draughts.
PostPosted: Mon Jul 22, 2024 5:48 pm 
Offline

Joined: Sat Apr 20, 2024 4:01 pm
Posts: 14
Well I have been experimenting with VBCC, and I am impressed, it is fast! Using a connect4 program I have written, it seems about twice as fast as cc65. This program is deliberately written in old k&r C so I can also test with really old compilers like Aztec c on the apple 2 or super C on c64, etc.
Other alpha beta type search progs also show VBCC to be fast. I am trying to make a version of DYNAMO compile for the c64. I will post some examples up at some stage.
One thing that really helps with these sorts of programs is moving the board array and some frequently used vars to zero page. On most 6502 machines about halve of zero page is used by basic, and can be reused. In fact nearly all of it can be reused if you make your own routines for key scans, printing to screen etc. As a guide ORAC speed up by 10% with the board in zero page, and also was smaller..

Quote:
Out of curiosity I compiled it with my work-in-progress vbcc65816 which obviously has no problem with the memory requirements. I can have the computer make moves and (when deactivating randomization) it seems to give the same results as the linux version. However, I always get "Bad move!" whenever I try to make a manual move (even when using the same move the computer would choose). The same behaviour with the linux version. I did not investigate it further. Is this a bug or am I missing something?


It's possibly a bug, the text version is nowhere near complete/fully tested. I will check it.
Thanks for making VBCC, it is very good!

_________________
Github: https://github.com/orac81


Top
 Profile  
Reply with quote  
 Post subject: Re: Orac Draughts.
PostPosted: Wed Jul 24, 2024 11:54 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
> about twice as fast as cc65

interesting finding!


Top
 Profile  
Reply with quote  
 Post subject: Re: Orac Draughts.
PostPosted: Wed Jul 24, 2024 5:12 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
orac81 wrote:
it seems about twice as fast as cc65.

That would concur with the comparison posted at https://www.videogamesage.com/forums/to ... ent-163145

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: Orac Draughts.
PostPosted: Wed Jul 24, 2024 10:46 pm 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1043
Location: near Heidelberg, Germany
GARTHWILSON wrote:
orac81 wrote:
it seems about twice as fast as cc65.

That would concur with the comparison posted at https://www.videogamesage.com/forums/to ... ent-163145


Does vbcc still have that closed source license mentioned in the linked article? Would be a no go for me.

Is there a speed comparison with llvm-mos?

André

_________________
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/


Top
 Profile  
Reply with quote  
 Post subject: Re: Orac Draughts.
PostPosted: Thu Jul 25, 2024 2:21 pm 
Offline

Joined: Thu Apr 23, 2020 5:04 pm
Posts: 53
GARTHWILSON wrote:
That would concur with the comparison posted at https://www.videogamesage.com/forums/to ... ent-163145
Unfortunately these benchmarks seem a bit dubious to me. It seems to be using its own framework and emulator, so it is a bit cumbersome to verify. Therefore I just looked at some points that seemed suprising to me.

Many of the tests have been written for or optimized/adapted to certain compilers. Obviously this can make a difference compared to neutral code. For example, the RLE/unzip benchmark for kickc has been adapted, so that the compiler sees the entire input data as a constant C array, whereas the unmodified version just gets an external reference to data from an assembly file.

Also, the declarations do not seem to match and probably random data will be decompressed:
Code:
kickc_unzip.c:
extern const uint8_t* zipped_data;

kickc_unzip_data.c:
const uint8_t zipped_data[] = { ...
Not sure how much of a difference that makes, but it does not raise confidence.

Then I had a look at the RPG example, because the gcc results were so much better. I did not reproduce his tests or the gcc results, but I had a look at the code generated by vbcc:
Code:
$ cat rpg.c
#include <stdint.h>

//
// Your typical RPG foo
//

typedef struct {
        uint8_t pv;
        uint8_t attack;
} Monster;

static void monster_init(Monster* monster) {
        monster->pv = 10;
        monster->attack = 2;
}

static void monster_take_hit(Monster* monster, uint8_t attack) {
        if (monster->pv > attack) {
                monster->pv -= attack;
        }else {
                monster->pv = 0;
        }
}

//
// A hero wielding his weapon
//

typedef struct {
        uint8_t attack;
        uint8_t durability;
} Weapon;

typedef struct {
        uint8_t pv;
        uint8_t mana;
        Weapon weapon;
} Hero;

static void hero_init(Hero* hero);
static void hero_change_weapon(Hero* hero, Weapon new_weapon);
static void hero_hit_monster(Hero* hero, Monster* monster);

static const Weapon fist = {.attack = 1, .durability = 255};
static const Weapon sword = {.attack = 3, .durability = 10};

static void hero_init(Hero* hero) {
        hero->pv = 10;
        hero->mana = 10;
        hero_change_weapon(hero, fist);
}

static void hero_change_weapon(Hero* hero, Weapon new_weapon) {
        hero->weapon = new_weapon;
}

static void hero_hit_monster(Hero* hero, Monster* monster) {
        monster_take_hit(monster, hero->weapon.attack);
        --hero->weapon.durability;
        if (hero->weapon.durability == 0) {
                hero_change_weapon(hero, fist);
        }
}

//
// Benched routine: initialize things and begin a fight!
//

void benched_routine() {
        // Game state:
        //  hero is in zero page,
        //  There is 3 monsters at the begining of page 4xx
        Hero* hero = (Hero*)0x0080;
        Monster* monsters = (Monster*)0x0400;
        const uint8_t NB_MONSTERS = 3;

        // Initialize gamestate
        hero_init(hero);
        hero_change_weapon(hero, sword);

        for (uint8_t monster_num = 0; monster_num < NB_MONSTERS; ++monster_num) {
                monster_init(&monsters[monster_num]);
        }

        // Fight!
        hero_hit_monster(hero, monsters + 1);
}
$ vc +c64 -O3 -S rpg.c
$ cat rpg.asm
;vcprmin=10000
        section text
        global  _benched_routine
_benched_routine:
        ldx     #10
        stx     128
        stx     129
        lda     #1
        sta     130
        lda     #255
        sta     131
        lda     #3
        sta     130
        stx     131
        stx     1024
        lda     #2
        sta     1025
        stx     1026
        sta     1027
        stx     1028
        sta     1029
        lda     130
        sta     r0
        lda     1026
        cmp     r0
        bcc     l47
        beq     l47
        lda     1026
        sec
        sbc     r0
        sta     1026
        jmp     l48
l47:
        lda     #0
        sta     1026
l48:
        dec     131
        lda     131
        bne     l49
        lda     #1
        sta     130
        lda     #255
        sta     131
l49:
        rts
For the life of me I do not see how gcc could generate code several times faster than that. So I kind of doubt that vbcc was used correctly.

As a problem was mentioned with vbcc and the cc65-optimized game code (which apparently was the reason to call vbcc "buggy" in the summary), I tried to look into that and found this in the code:
Code:
#define SCREEN_ADDR ((unsigned char*)0x300)
and this in the linker file:
Code:
  ram:     org=0x0300, len=0x0500
Now obviously that is not going to work. So I would take those results with a few pounds of salt.


Top
 Profile  
Reply with quote  
 Post subject: Re: Orac Draughts.
PostPosted: Thu Jul 25, 2024 2:36 pm 
Offline

Joined: Thu Apr 23, 2020 5:04 pm
Posts: 53
fachat wrote:
Does vbcc still have that closed source license mentioned in the linked article?
There has been no change to the license. The source is available, but modified versions must not be distributed. Non-commercial use is free, but commercial use is free only for Mega65 and Amiga68k due to sponsorships.

Quote:
Is there a speed comparison with llvm-mos?
I am aware of those 6502 compiler benchmarks:
https://raxiss.com/article/id/30-MOS650 ... -benchmark
https://gglabs.us/node/2293


Top
 Profile  
Reply with quote  
 Post subject: Re: Orac Draughts.
PostPosted: Fri Jul 26, 2024 2:15 pm 
Offline

Joined: Sat Apr 20, 2024 4:01 pm
Posts: 14
vbc wrote:
Out of curiosity I compiled it with my work-in-progress vbcc65816 which obviously has no problem with the memory requirements. I can have the computer make moves and (when deactivating randomization) it seems to give the same results as the linux version. However, I always get "Bad move!" whenever I try to make a manual move (even when using the same move the computer would choose). The same behaviour with the linux version. I did not investigate it further. Is this a bug or am I missing something?


This is a bug in that version of DYNAMO. In routine do_human_move, line 3326 change:

If (doamove(src, dest, 1)) {

To:

If (doamove(sqpos[src], sqpos[dest], 1)) {

And that should work for square numbering for 10x10, so from new you can type 31-27 <ENTER>. etc. (I had changed if for internal numbering testing and forgot to change back) I will release an update sometime, and some benchmarks/examples on 6502 compilers.
As for a 6502 version of DYNAMO, I was thinking it may be easier to rewrite a neater version, I'm looking at old code and thinking "what the heck was I doing?".. I used large arrays and unrolled code macros to make faster move generator under turbo c, which doesn't suit the 6502.

I think a (relatively) strongish 10x10 program should be possible in pure 6502 asm in less than 8k, obviously more in C. The unexpanded vic20 version of ORAC (with front-end) playing simpler 8x8 checkers is just 3300 bytes.

As for choice of compiler it's worth noting that it's often possible with a few #if and #define macros to make code that builds on a range of compilers..


EDIT: I have added an update to DYNAMO that corrects the above bug.
download: https://github.com/orac81/Orac-Draughts/raw/main/dyna920a.zip

_________________
Github: https://github.com/orac81


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 27 posts ]  Go to page Previous  1, 2

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: