Jump to content
IGNORED

how does pokec/peekc and pokew/peekw go in kickc?


Recommended Posts

Like in every C implementation. You do know how to program in C, right?

 

 

Edit: sorry, that came out a bit harsh. I'm just a little annoyed by you posting several threads asking about basic language features.

 

Google for peek and poke in c

and the first hit is:

 

https://c-for-dummies.com/blog/?p=3065

 

Change char * to short * for words instead of bytes.

Edited by ivop
  • Like 1
Link to comment
Share on other sites

The kickC docs are at https://docs.google.com/document/d/1JE-Lt5apM-g4tZN3LS4TDbPKYgXuBz294enS9Oc4HXM/edit#

 

There's a section on types:

 

char/byte/unsigned char/unsigned byte = unsigned 8 bit

word/unsigned word/unsigned short/unsigned int = unsigned 16 bit

short/signed short/int/signed int/signed word = signed 16  bit

 

etc.

 

I've mostly been using "char" and "word" for 8/16 bits and haven't had to deal with signed types at all.

 

"peek" and "poke" in C are something like

char * ROWCRS = 0x54; // this is a pointer to a char, set to the address in memory at location 0x54

char rowValue = *ROWCRS; // this sets the char "rowValue" to the same as "PEEK(ROWCRS)" in basic.
*ROWCRS = 20;  // this sets the value at memory location 0x54 to 20, like POKE(ROWCRS, 20) in basic.

 

Edited by fenrock
Link to comment
Share on other sites

for peekw something like this would do

 

#include <stdio.h>

unsigned int peekw(char *address);

void main(void)
{
    unsigned int value;
    value=peekw((char *)560); // display list
    printf("Address = %u\n",value);
}

unsigned int peekw(char *address)
{
    unsigned int tmp,tmp1;
    tmp = *address;
    tmp1 =*(address+1)*256;
    return(tmp+tmp1);
}

Link to comment
Share on other sites

/*****************************************************************************/
/*                                                                           */
/*                                peekpoke.h                                 */
/*                                                                           */
/*     PEEK and POKE macros for those who want to write BASIC code in C      */
/*                                                                           */
/*                                                                           */
/*                                                                           */
/* (C) 2003      Ullrich von Bassewitz                                       */
/*               Römerstrasse 52                                             */
/*               D-70794 Filderstadt                                         */
/* EMail:        uz@cc65.org                                                 */
/*                                                                           */
/*                                                                           */
/* This software is provided 'as-is', without any expressed or implied       */
/* warranty.  In no event will the authors be held liable for any damages    */
/* arising from the use of this software.                                    */
/*                                                                           */
/* Permission is granted to anyone to use this software for any purpose,     */
/* including commercial applications, and to alter it and redistribute it    */
/* freely, subject to the following restrictions:                            */
/*                                                                           */
/* 1. The origin of this software must not be misrepresented; you must not   */
/*    claim that you wrote the original software. If you use this software   */
/*    in a product, an acknowledgment in the product documentation would be  */
/*    appreciated but is not required.                                       */
/* 2. Altered source versions must be plainly marked as such, and must not   */
/*    be misrepresented as being the original software.                      */
/* 3. This notice may not be removed or altered from any source              */
/*    distribution.                                                          */
/*                                                                           */
/*****************************************************************************/



#ifndef _PEEKPOKE_H
#define _PEEKPOKE_H



/*****************************************************************************/
/*                                  Macros                                   */
/*****************************************************************************/



#define POKE(addr,val)     (*(unsigned char*) (addr) = (val))
#define POKEW(addr,val)    (*(unsigned*) (addr) = (val))
#define PEEK(addr)         (*(unsigned char*) (addr))
#define PEEKW(addr)        (*(unsigned*) (addr))



/* End of peekpoke.h */
#endif


 

Link to comment
Share on other sites

Much better but would still encourage not using them ;) 

 

To qualify that...

 

looking at a listing that uses defines to do something like:

poke(COLPF1,peek(COLOR1));

just looks like quickly converted listing.

 

The cc65 platform headers have long provided the OS wrappers so that statements such as:

GTIA_WRITE.colpf0 = OS.color0;

can be used instead.

 

One question for @JesperGravgaard though is that in KickC, this has opted to use pointer notation instead:

GTIA->GRACTL = 0x01; /* enable missiles */

so wondered if the struct approach was considered? 

 

Edited by Wrathchild
added example
  • Like 1
Link to comment
Share on other sites

21 hours ago, fenrock said:

char/byte/unsigned char/unsigned byte = unsigned 8 bit

word/unsigned word/unsigned short/unsigned int = unsigned 16 bit

short/signed short/int/signed int/signed word = signed 16  bit

Is this what KickC implements or something else? I'm confused.

 

byte and word are no C keywords or types.

 

The default signedness of char, short, int, long, and long long is signed for an extremely large number of C compilers. So char != unsigned char. And short == signed short.

 

The opposite is also valid according to the C standard, but assume a lot of problems porting existing code if your default types are unsigned.

 

And int can be equal to short, but that's not a given. Not even on an 8-bit compiler. With gcc-6502, they are not equal IIRC. It's all compiler dependant. Therefore, you can better include <stdint.h> and use typedefs like uint8_t and int32_t, so you can be sure you get the right precision.

 

Link to comment
Share on other sites

 

1 minute ago, ivop said:

Is this what KickC implements or something else? I'm confused.

 

yes those types are the kickc definitions taken from the docs.

so to kickc, word is unsigned 16 bit, etc.

good point on using stdint.h, that's in the distribution with the expected uint8_t, int8_t etc. defined.

 

Link to comment
Share on other sites

10 minutes ago, fenrock said:

yes those types are the kickc definitions taken from the docs.

so to kickc, word is unsigned 16 bit, etc.

Okay, unsigned 16-bit WORD is standard in windows. DWORD is unsigned, too. But I really hope that KickC's default char is signed. And byte can be unsigned char (which it also is in windows, and they have UCHAR, too :) ).

 

Quote

good point on using stdint.h, that's in the distribution with the expected uint8_t, int8_t etc. defined.

Yes, that's a header that's not part of the C library, but of the compiler (like stdarg.h and some more), because only the compiler knows the exact types (and how it handles varargs).

 

Edited by ivop
Link to comment
Share on other sites

Better not rely on that, as all other 6502 C compiler I know of have a signed char. For example, the cc65 documentation recommends using unsigned chars for speed, but its default for an unspecified char is signed.

 

// C99
    for (char x=0; x<200; x++) {
        do_something();
        // and something else
    }

 

This will work for an unsigned default char, but a default of signed char will never finish.

 

Link to comment
Share on other sites

I rechecked. You are right. CC65's default char is indeed unsigned. That's quite uncommon, but allowed by the C specification. Guess I was confused by their coding hints about using unsigned types for speed, which seems not needed if the default is unsigned anyway. But that hint is more aimed at 16-bit math, where int is always signed. So use unsigned int for faster 16-bit math on a 6502.

 

Link to comment
Share on other sites

On 10/16/2020 at 10:38 PM, Wrathchild said:

 

One question for @JesperGravgaard though is that in KickC, this has opted to use pointer notation instead:


GTIA->GRACTL = 0x01; /* enable missiles */

so wondered if the struct approach was considered? 

 

 

The headers for the ATARI chipset included in the KickC release is based on pointers to structs.

// Atari GTIA write registers
struct ATARI_GTIA_WRITE * const GTIA = 0xd000;

The compiler recognizes that GTIA->GRACTL is in fact a static address and generates code poking directly to that.

 

The struct-based approach was primarily chosen because I prefer the registers of each chip grouped together and I like that is is clear that code is addressing a register a specific chip. Some editors also offer code completion after you have entered GTIA-> which helps find the register you are looking for.

 

The struct in the header-file also serves as a place to dump a little documentation describing each register. See 

https://gitlab.com/camelot/kickc/-/blob/master/src/main/kc/include/atari-gtia.h

 

If you prefer a different notation it is pretty easy to create another header-file supporting that.

 

 

Link to comment
Share on other sites

Taking CC65's PIA arrangement as an example (as its small):

atari.h

#include <_pia.h>
#define PIA (*(struct __pia*)0xD300)
_pia.h

struct __pia {
    unsigned char   porta;  /* port A data r/w */
    unsigned char   portb;  /* port B data r/w */
    unsigned char   pactl;  /* port A control */
    unsigned char   pbctl;  /* port B control */
};

Although a few regex expression replaces can fix up sources, I'm more thinking that ease of portability between the two would be handy.

E.g. you have GTIA for GTIA_READ and the register names are uppercase.

This is assuming that the resulting KickC code is the same as the current version. 

Link to comment
Share on other sites

On 10/17/2020 at 6:19 PM, fenrock said:

char is definitely unsigned in kickc, i've been relying on it even.

maybe @JesperGravgaard has some commentary on why.

 

The C standard is pretty clear that the signedness of char is implementation dependant. See for instance A.4.2 in https://xuron.com/uploads/Kernighan_Ritchie_Language_C.pdf

 

The 6502 CPU is better at performing unsigned numeric operations than is it at at signed numeric operations. This is especially true for comparisons. Try looking at section 5 in http://www.6502.org/tutorials/compare_beyond.html


This is the reason I decided that a C-compiler targetting the 6502 platform should have unsigned char as the default.

 

The aim of the compiler is to help people create C-code that runs as fast as possible on the 6502, and unsigned chars run faster than signed chars. So I felt unsigned was the best default. The authors of cc65 seems to have made the same choice.

/Jesper

Edited by JesperGravgaard
  • Like 1
Link to comment
Share on other sites

18 minutes ago, Wrathchild said:

Although a few regex expression replaces can fix up sources, I'm more thinking that ease of portability between the two would be handy.

I honestly did not really consider portability from cc65's library when creating the headers.

 

I made a quick check, and it seems the macro-based solution above generates the same ASM as the current pointer-to-struct solution.

 

So it would probably be possible to make the chipset headers more portable by using the same member names and using a macro instead the pointer-to-struct.

 

The lack of unions in the current version of kickc may result in some compatibility issues - if the cc65 structs utilize unions.

 

If anyone here in the forum want to have a go at creating the header-files I will gladly merge them into kickc. In any case I will add a TODO to my list.

 

 

 

  • Like 1
Link to comment
Share on other sites

58 minutes ago, JesperGravgaard said:

If anyone here in the forum want to have a go at creating the header-files I will gladly merge them into kickc. In any case I will add a TODO to my list.

I don't mind chasing this up, as it'll teach me the difference at the same time. If you've got a TODO/Issue raised, I'll start there. I'm not 100% sure what's required at the moment (I actually prefer the way you've done it as I find it more readable than the PIA example above), but if it makes it easier for cross use of code, then I'm all in.

Link to comment
Share on other sites

29 minutes ago, Wrathchild said:

do you mean the header files themselves or the post #9 use cases?

the thing with the headers is that you don't need to go into them, e.g. do you open stdio.h?

I mean I find this difficult to understand:

#define PIA (*(struct __pia*)0xD300)

compared to:

struct ATARI_GTIA_WRITE * const GTIA = 0xd000;

It's probably due to my propensity to code in JVM (kotlin/java etc) languages rather than C.

The brackets and stars in the first one leave me lost, but the latter I can more easily read as "this is an instance of an ATARI_GTIA_WRITE named GTIA located at d000."

I couldn't even begin to put the PIA definition into words, but it would probably involve the word pointer more than once :) 

 

I often go into the header files because I'm inexperienced at C and need to read the function signatures and values with hopefully explanations.

 

I'm not dissing the former, I just haven't learned it yet.

 

Link to comment
Share on other sites

Perhaps the assigning of an address in the manner that KickC is doing is more akin to embedded compilers?

 

Here's an example program:

struct PIA_READ {
    unsigned char   PORTA;  /* port A data r/w */
    unsigned char   PORTB;  /* port B data r/w */
    unsigned char   PACTL;  /* port A control */
    unsigned char   PBCTL;  /* port B control */
};

struct PIA_READ * const PIA_KICKC = 0xd300;

#define PIA_CC65 (*(struct PIA_READ*)0xD300)

unsigned char pb;

void main()
{
  pb = PIA_KICKC->PORTB;
  pb = PIA_CC65.PORTB;
}

 

In CC65 this produces the following assembly:
 

.segment    "RODATA"

_PIA_KICKC:
    .word    $D300

.segment    "BSS"

_pb:
    .res    1,$00

; ---------------------------------------------------------------
; void __near__ main (void)
; ---------------------------------------------------------------

.segment    "CODE"

.proc    _main: near

.segment    "CODE"

    lda     _PIA_KICKC
    ldx     _PIA_KICKC+1
    ldy     #$01
    jsr     ldauidx
    sta     _pb
    ldx     #$00
    lda     $D301
    sta     _pb
    rts

.endproc

 

So my interpretation of:

struct PIA_READ * const PIA_KICKC = 0xd300;

Is that PIA_KICKC is a pointer to a PIA_READ structure, initialised with the value $D300.
Because it is also declared as a constant value, it is placed into the Read-Only data segment.

(If the const keyword is placed at the start of the line then this now lives in the Data segment... meaning it can be modified.)

 

Now the code produced in having to take the value from the pointer and pass it to a function which will get the 2nd element within the struct (zero indexed and the first element is an unsigned char, so the offset is 1).

 

I had to adjust the listing by using the variable pb so that it didn't get optimized away. The output for this is:

  .const OFFSET_STRUCT_PIA_READ_PORTB = 1
  .label PIA_KICKC = $d300
  .label pb = 2

main: {
    lda PIA_KICKC+OFFSET_STRUCT_PIA_READ_PORTB
    sta.z pb
    lda $d300+OFFSET_STRUCT_PIA_READ_PORTB
    sta.z pb
    jsr fn
    rts
}

So it can be seen how the KickC implementation is able to treat the constant as fixed value assignment rather than a variable itself.

 

Hence I should think that the CC65 implementation uses the #define version of the structure access as it doesn't implement the optimization for this.

Edited by Wrathchild
submitted before I'd finished
  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...