Two steps back, one step forward ....
So I wrote a simple monitor program in C with a bit of assembler startup code. Naturally your first attempt does not produce anything, so for debugging I went looking for a simulator and was very happy to find
https://github.com/sethm/symon, because it also simulates a 6551 chip! Then I run into a problem with understanding the assembler code that my toolchain (6502-gcc and ld65) produced. So I wrote a small python program that combines the annotated assembly produced by the gcc with the actual addresses created by the linker. That would result in something like
Code:
.export int4_to_hexchar
int4_to_hexchar:
; frame size 0, pretend size 0, outgoing size 0
;# firmware_v01_monitor_and_lcd_cc65.c:118: if(a>9)
C0DD A9 09 lda #$09 lda #$09 ;# tmp98,
C0DF C5 04 cmp $04 cmp _r0 ;# tmp98, a
C0E1 A9 00 lda #$00 lda #$00 ;# tmp98,
C0E3 E5 05 sbc $05 sbc _r1 ;# a
C0E5 50 02 bvc LC0E9 bvc L@9 ;#
C0E7 49 80 eor #$80 eor #$80 ; negate top bit
L@9:
;# firmware_v01_monitor_and_lcd_cc65.c:119: return('A'-9 + a);
C0E9 08 php php
C0EA A5 04 lda $04 lda _r0 ;# <retval>, a
C0EC 28 plp plp
;# firmware_v01_monitor_and_lcd_cc65.c:118: if(a>9)
C0ED 10 06 bpl LC0F5 bpl L@7 ;#
;# firmware_v01_monitor_and_lcd_cc65.c:119: return('A'-9 + a);
C0EF 18 clc clc
C0F0 69 38 adc #$38 adc #$38 ;#
L@10:
;# firmware_v01_monitor_and_lcd_cc65.c:121: return('0' + a);
C0F2 85 04 sta $04 sta _r0 ;# <retval>, <retval>
;# firmware_v01_monitor_and_lcd_cc65.c:122: }
C0F4 60 rts rts
L@7:
;# firmware_v01_monitor_and_lcd_cc65.c:121: return('0' + a);
C0F5 18 clc clc
C0F6 69 30 adc #$30 adc #$30 ;#
C0F8 4C F2 C0 jmp LC0F2 jmp L@10 ;#
for a simple c-code:
Code:
/* convert 4bit int to hex char */
const char int4_to_hexchar(int a)
{
if(a>9)
return('A'-9 + a);
else
return('0' + a);
}
Honestly, I had to swallow hard when I saw the overhead c created. Still I started to debug away, found a couple of minor errors in logic (for instance the compiler had optimized away "unnecessary" loops), until I hit a wall. Possibly I'm too stupid...but no matter what I did, the program simply did not echo back the characetrs I sent over serial. The c-code I thought was pretty straightforward:
Code:
const char acia_getc()
{
asm("\nwait_for_receive:\n\tlda " STR_ACIA_STATUS ";\n\tand #" XSTR(ACIA_STATUS_RX_FULL)";\n\tbeq wait_for_receive;");
return(ACIA_DATA[0]);
}
/* read a '\x0a' terminated string from ACIA1 */
void acia_gets()
{
char c;
*ACIA_INDEX=0;
while(c=acia_getc() != '\x0d')
{
RES[0] = c;
acia_putc(RES[0]);
.....
but the compiler gave me was
Code:
acia_getc:
wait_for_receive:
C238 AD 01 88 lda $8801 lda $8801;
C23B 29 08 and #$08 and #1 << 3;
C23D F0 F9 beq LC238 beq wait_for_receive;
;# firmware_v01_monitor_and_lcd_cc65.c:179: }
C23F AD 00 88 lda $8800 lda $8800
C242 85 04 sta $04 sta _r0
C244 60 rts rts
C269 20 38 C2 jsr LC238 jsr acia_getc
;# firmware_v01_monitor_and_lcd_cc65.c:186: while(c=acia_getc() != '\x0d')
C26C A5 04 lda $04 lda _r0
C26E C9 0D cmp #$0D cmp #$0d
C270 D0 49 bne LC2BB bne L@35
.....
L@35:
;# firmware_v01_monitor_and_lcd_cc65.c:188: RES[0] = c;
C2BB A9 01 lda #$01 lda #$01
C2BD 8D 00 03 sta $0300 sta $0300
;# firmware_v01_monitor_and_lcd_cc65.c:189: acia_putc(RES[0]);
C2C0 85 04 sta $04 sta _r0
C2C2 20 01 C2 jsr LC201 jsr acia_putc
So a character is received in $8800 (ACIA data port), stored in _r0 aka $0004, the subroutine returns, loads _r0 into the ACC, compares with $0d, jumps to L@35, then loads 1 into ACC and stores it into _r0 before echoing the character back? Do I understand that right??? (I think I do, I pondered over that for 2 hours....)
So I abandoned gcc at that point. I seemed easier to start learning 6502 assembly for real
3 days later I had a working monitor, that can display and modify memory locations. So back to the hardware now to layout my first parts of the VGA card!