Extremely simple 6502 C program

Building your first 6502-based project? We'll help you get started here.
rdb9879
Posts: 5
Joined: 09 Jun 2018

Extremely simple 6502 C program

Post by rdb9879 »

Greetings. I am getting my feet wet with programming a 6502 in C. I have looked at some of the sample programs, but most of the resources online are trying to target an NES (including its GPU and "mappers"). I would like to break it down even more simply, just a simple bare bones 6502 processor with $FFFF bytes of RAM attached and a single memory mapped hardware register at $5000. This is all in simulation land so there's no risk if I screw anything up.

Anyway, my C code looks like this:

Code: Select all

#include <stdint.h>
#define UART_REG 0x5000
#define REG_DATA(x) ((volatile uint8_t*)(x))[0]

void main (void)
{
    REG_DATA(UART_REG) = 'H';
    REG_DATA(UART_REG) = 'e';
    REG_DATA(UART_REG) = 'l';
    REG_DATA(UART_REG) = 'l';
    REG_DATA(UART_REG) = 'o';

    while(1){};
}

So modifying the Makefile in the "samples" directory to use "sim6502" as the target, These commands were executed:

Code: Select all

$ make
../bin/cc65  -Ors --codesize 500 -T -g -t sim6502 hello.c
../bin/ca65 hello.s
../bin/ld65   -o hello -t sim6502 -m hello.map hello.o sim6502.lib
This worked in the sense that I got an assembler file, mapper file, and raw hex file. However, when I look at the raw hex file, There are only $CF bytes. If I understand the architecture correctly, there needs to be a reset vector placed at $FFFC and $FFFD in order for the processor to jump to the correct start routine.

What steps do I need to do in order to make the appropriate jump into my C program? Ideally, I would like to output a raw hex file that contains $FFFF bytes, so I can easily load the values into my simulated RAM.

Thanks!
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: Extremely simple 6502 C program

Post by Chromatix »

You'll probably find this documentation helpful: https://www.cc65.org/doc/ld65-5.html#ss5.6
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Extremely simple 6502 C program

Post by BigEd »

(Welcome rdb9879. I don't have an answer, but I expect we'll be able to figure this one out. I confess that my own cc65 usage is even simpler: see here.)
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Extremely simple 6502 C program

Post by BigEd »

(It looks as if cc65 doesn't have special support for the vectors: if you want to initialise them, you need to do it yourself. See https://www.cc65.org/doc/customizing-5.html )
User avatar
GARTHWILSON
Forum Moderator
Posts: 8774
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Extremely simple 6502 C program

Post by GARTHWILSON »

Welcome.

In any case, you don't need, and wouldn't want anyway, the file to have $FFFF bytes. It would take longer to transfer, it would take unnecessary room in storage, and what if you had other program material or data in the RAM that you didn't want to overwrite, like if you had material in another language as well, whether from an assembler or other compiler, and it all had to cooperate. The vectors are also normally in ROM so that at least the reset vector is available immediately upon power-up, before anything has run. The reset routine it points to is also normally in ROM. What some people have done is to have separate hardware to pre-load RAM from flash or ROM of some kind before letting the processor start up its normal way. There are a few different variations on this theme.
rdb9879 wrote:
Ideally, I would like to output a raw hex file that contains $FFFF bytes, so I can easily load the values into my simulated RAM.
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?
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Extremely simple 6502 C program

Post by BigEd »

Good point: for a physical machine, you'd aim for an 8k, 4k or 2k ROM and place your code at E000, F000, or F800 accordingly. (Although, if a simulator is set up to expect 64k bytes of initialisation, you might use a different tactic.)
rdb9879
Posts: 5
Joined: 09 Jun 2018

Re: Extremely simple 6502 C program

Post by rdb9879 »

Ah okay. Those are good points. I can always force the reset vectors to whatever I want, so no worries.

So I found the "sim6502.cfg" file and it indicates that the main start = $0200. I disassembled the binary file using the "-S 0x200" command (this may be the incorrect thing to do).

Here's what i'm seeing:

Code: Select all

        brk                                     ; 0200 00
        cld                                     ; 0201 D8
        ldx     #$FF                            ; 0202 A2 FF
        txs                                     ; 0204 9A
        lda     #$F0                            ; 0205 A9 F0
        ldx     #$FF                            ; 0207 A2 FF
        sta     $00                             ; 0209 85 00
        stx     $01                             ; 020B 86 01
        jsr     L0283                           ; 020D 20 83 02
        jsr     L021D                           ; 0210 20 1D 02
        jsr     L0246                           ; 0213 20 46 02
        pha                                     ; 0216 48
        jsr     L025D                           ; 0217 20 5D 02
        pla                                     ; 021A 68
        .byte   $4C                             ; 021B 4C
        .byte   $F1                             ; 021C F1
L021D:  .byte   $FF                             ; 021D FF
        ldy     #$00                            ; 021E A0 00
        beq     L0229                           ; 0220 F0 07
        lda     #$29                            ; 0222 A9 29
        ldx     #$02                            ; 0224 A2 02
        jmp     L02AA                           ; 0226 4C AA 02
...
L0283:  rts                                     ; 0283 60
So I'm walking through this code and I have a few questions:

1) Why is the first command a break opCode? What is the purpose of this?
2) At $020D, I see a JSR to $0283, but the opCode at $0283 is simply a RTS. Is there a point to that? Jump to a subroutine and then immediately return?
3) Once it RTS's from $0283, the next opCode at $0210 is to JSR into $021D. $021D doesn't even have a valid op-code ($FF)?

Seems like I am still doing something wrong or confused...
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: Extremely simple 6502 C program

Post by Chromatix »

Whatever's going on in that code, it doesn't look anything like what your source code should translate to:

Code: Select all

lda #'H'
sta $5000
lda #'e'
sta $5000
lda #'l'
sta $5000
sta $5000
lda #'o'
sta $5000
bne *-2
rdb9879
Posts: 5
Joined: 09 Jun 2018

Re: Extremely simple 6502 C program

Post by rdb9879 »

Well actually, the disassembly code that I posted in my previous post was incomplete. It was only the portion that I had questions about...I do, in fact, see my C code behavior later in the disassembly file:

Code: Select all

; 
; ----------------------------------------------------------------------------
        ldx     #$50                            ; 022A A2 50
        lda     #$00                            ; 022C A9 00
        sta     $08                             ; 022E 85 08
        stx     $09                             ; 0230 86 09
        lda     #$48                            ; 0232 A9 48
        ldy     #$00                            ; 0234 A0 00
        sta     ($08),y                         ; 0236 91 08
        lda     #$65                            ; 0238 A9 65
        sta     ($08),y                         ; 023A 91 08
        lda     #$6C                            ; 023C A9 6C
        sta     ($08),y                         ; 023E 91 08
        sta     ($08),y                         ; 0240 91 08
        lda     #$6F                            ; 0242 A9 6F
        sta     ($08),y                         ; 0244 91 08
L0246:  rts                                     ; 0246 60
I believe the previous post showed some startup routines.
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: Extremely simple 6502 C program

Post by Chromatix »

You might get something more informative by reading hello.s, which is the input to the assembler. In particular, you'll get more descriptive labels than from a disassembler.

However, I note that if you were to delete the initial zero byte (BRK) off the front, and shift the addresses and jump-target labels to match, then the startup code makes a lot more sense. The three ".byte" directives in the middle are a JMP instruction, whose disassembly has been suppressed because there's a jump apparently pointing to its final byte - it should point one byte further on.
rdb9879
Posts: 5
Joined: 09 Jun 2018

Re: Extremely simple 6502 C program

Post by rdb9879 »

You were right. Everything was shifted in addresses by 1. If I load the code into $01FF, everything works fine.

Cheers
User avatar
Dr Jefyll
Posts: 3526
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: Extremely simple 6502 C program

Post by Dr Jefyll »

Nicely spotted, Chromatix!

rdb9879, I think this qualifies as an "off by one" error, although maybe not in the usual sense. And it reminds me of earlier when you mentioned creating a file of $FFFF bytes. That, too, struck me as possibly being an off-by-one error, and now I wonder if there could be any connection. Did you mean a file that populates the address range $0000 to $FFFF inclusive? Such a file has $10000 bytes, not $FFFF bytes. Just checking! If I'm on the wrong track just ignore this. Glad you got the program working!

Jeff
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
User avatar
GARTHWILSON
Forum Moderator
Posts: 8774
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Extremely simple 6502 C program

Post by GARTHWILSON »

Dr Jefyll wrote:
I think this qualifies as an "off by one" error, although maybe not in the usual sense. And it reminds me of earlier when you mentioned creating a file of $FFFF bytes. That, too, struck me as possibly being an off-by-one error, and now I wonder if there could be any connection. Did you mean a file that populates the address range $0000 to $FFFF inclusive? Such a file has $10000 bytes, not $FFFF bytes.
I took it to mean the entire address range minus the one address for an output register. Interesting anyway.
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?
rdb9879
Posts: 5
Joined: 09 Jun 2018

Re: Extremely simple 6502 C program

Post by rdb9879 »

The off by one error was simply related to the argument I passed into the dissassembler: I needed

Code: Select all

-S 0x1FF
instead of

Code: Select all

-S 0x200
. Putting

Code: Select all

-S 0x200
shifted all the op codes by 1 address, so when the program counter reached the

Code: Select all

jsr     L0283
op-code, this was jumping to one address off from the intended op-code, sending the program into the weeds.

The whole thing about $FFFF was a combo of me misspeaking and misunderstanding: I did originally intend to have a hex file containing the entire program memory from $0000 to $FFFF (or $10000 bytes as you corrected). But as Garth pointed out, there's not a good reason to do this. Even in the context of my simple program, I stated that the address $5000 was a memory mapped hardware register, so even with that it would not make sense to have a program file with addresses $0000 to $FFFF, as $5000 falls within that range.

I think my next step should be to add a new section into the linker script to "reserve" some addresses for memory mapped hardware, just to be sure that the compiler doesn't accidentally target this address or do some kind of malloc on it.
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: Extremely simple 6502 C program

Post by Chromatix »

Most 6502 machines put the I/O addresses near the upper end of the address space. Low addresses (up to $1FF) are reserved for zero-page and hardware stack, while putting I/O space in the middle means you have to work around it. $5000 is a spectacularly awkward address.

The BBC Micro, for example, uses $FC00-$FEFF for the "FRED", "JIM", & "SHEILA" I/O pages. This is cut out from the MOS ROM mapping, leaving $FFxx page for MOS entry points and CPU vectors, and $C000-$FBFF for the rest of the 16KB MOS ROM. "SHEILA" alone is sufficient for all the hardware fitted to the machine (except the screen memory); the other two pages are routed to user expansion ports.
Post Reply