6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Wed Jul 03, 2024 9:17 am

All times are UTC




Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sat Jun 09, 2018 4:49 pm 
Offline

Joined: Sat Jun 09, 2018 4:34 pm
Posts: 5
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:
#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:
$ 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!


Top
 Profile  
Reply with quote  
PostPosted: Sat Jun 09, 2018 7:04 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
You'll probably find this documentation helpful: https://www.cc65.org/doc/ld65-5.html#ss5.6


Top
 Profile  
Reply with quote  
PostPosted: Sat Jun 09, 2018 7:26 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10838
Location: England
(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.)


Top
 Profile  
Reply with quote  
PostPosted: Sat Jun 09, 2018 7:28 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10838
Location: England
(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 )


Top
 Profile  
Reply with quote  
PostPosted: Sat Jun 09, 2018 8:14 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8462
Location: Southern California
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?


Top
 Profile  
Reply with quote  
PostPosted: Sat Jun 09, 2018 8:16 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10838
Location: England
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.)


Top
 Profile  
Reply with quote  
PostPosted: Sat Jun 09, 2018 10:21 pm 
Offline

Joined: Sat Jun 09, 2018 4:34 pm
Posts: 5
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:
        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...


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 10, 2018 1:30 am 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
Whatever's going on in that code, it doesn't look anything like what your source code should translate to:

Code:
lda #'H'
sta $5000
lda #'e'
sta $5000
lda #'l'
sta $5000
sta $5000
lda #'o'
sta $5000
bne *-2


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 10, 2018 1:36 am 
Offline

Joined: Sat Jun 09, 2018 4:34 pm
Posts: 5
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:
;
; ----------------------------------------------------------------------------
        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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 10, 2018 2:49 am 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 10, 2018 1:06 pm 
Offline

Joined: Sat Jun 09, 2018 4:34 pm
Posts: 5
You were right. Everything was shifted in addresses by 1. If I load the code into $01FF, everything works fine.

Cheers


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 10, 2018 2:09 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3366
Location: Ontario, Canada
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


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 10, 2018 3:32 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8462
Location: Southern California
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?


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 10, 2018 5:31 pm 
Offline

Joined: Sat Jun 09, 2018 4:34 pm
Posts: 5
The off by one error was simply related to the argument I passed into the dissassembler: I needed
Code:
-S 0x1FF
instead of
Code:
-S 0x200
. Putting
Code:
-S 0x200
shifted all the op codes by 1 address, so when the program counter reached the
Code:
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 10, 2018 7:01 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
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.


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

All times are UTC


Who is online

Users browsing this forum: No registered users and 5 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: