WC65C265SXB Monitor ROM problems

Programming the 6502 microprocessor and its relatives in assembly and other languages.
randrews
Posts: 20
Joined: 13 Mar 2019

WC65C265SXB Monitor ROM problems

Post by randrews »

I finally figured out how to get the C compiler working but I've hit another weird problem. I have the following code:

Code: Select all

void monitor_putchar(char ch);

void main() {
	const char *str = "\nHello there\n";
	int n;
	
	for(n = 0; n < 5; n++)
		monitor_putchar(str[n]);
}

void monitor_putchar(char ch) {
	asm {
		lda %%ch
		jsl $00:e04b
	}
}

void IRQHandler() {}
This prints out the first 5 bytes of that string to the console. It works fine as long as the limit of the for loop is 9 or less. If I make it 10 or more, the thing seems to go into an infinite loop or something as soon as I run it.

And it's not the loop either. If I unroll the loop, the first nine invocations of monitor_putchar work, the tenth breaks everything. Same if the assembly is inlined, same if it's outputting the same character each time.

Nine times it works. Ten it doesn't. I don't even know where to start.

(Except that I kind of want to smash this board with a hammer and go back to the Z80)
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: WC65C265SXB Monitor ROM problems

Post by BigEd »

Can you get an assembly listing of the resultant code? Can you disassemble the binary?

In your routine which contains inline assembly, where is the parameter value 'ch' to be found? What's the calling convention? It is certain that there's an implicit return and stack clearup at the end of the routine?
leepivonka
Posts: 168
Joined: 15 Apr 2016

Re: WC65C265SXB Monitor ROM problems

Post by leepivonka »

My 1st guess is that you have overlaid some monitor variables. How do you tell the C compiler & linker what memory is available for use?
The Mensch monitor uses $00..$c0 & $100..$1c0 & the return stack is in $1c0..$1ff. See the Mensch monitor listing (download from WDC) for more detail.
The 1st monitor variables starting at $00 are managing the serial I/O buffers & the default buffers are 10 bytes long.

I assume your program is running in 6502 emulation mode.
If sharing with the monitor is a problem, it is possible to relocate your direct page (zero page on the 6502) to some other place in zero bank. This isn't completely 6502 compatible though.

I assume IRQhandler() is not used. If you do replace an active interrupt routine & your routine doesn't service the source of the interrupt, when your routine returns, the interrupt request will still be active & your routine will be called again & again.

If you put the definition of monitor_putchar before main, the extra monitor_putchar template definition wouldn't be needed.
handyandy
Posts: 113
Joined: 14 Sep 2015
Location: Virginia USA

Re: WC65C265SXB Monitor ROM problems

Post by handyandy »

Hi randrews,

put_char() returns no errors but calls send_byte_to_pc() which will return carry set on error if I'm reading it right. And they are putting characters in a buffer while the monitor irq routines empty the buffer if that makes sense. See here for a text file of the monitor rom listing that I made:

viewtopic.php?f=4&t=4513

I think it's a little easier to read than the pdf.

Cheers,
Andy
whartung
Posts: 1004
Joined: 13 Dec 2003

Re: WC65C265SXB Monitor ROM problems

Post by whartung »

randrews wrote:
This prints out the first 5 bytes of that string to the console. It works fine as long as the limit of the for loop is 9 or less. If I make it 10 or more, the thing seems to go into an infinite loop or something as soon as I run it.
So, what you're suggesting is that if you call the jsl $00:e04b 10 times in a row, it goes in to a loop?

Code: Select all

    clc
    xce
    sep #$20
    LONGA OFF
    lda #$41   ; A
    jsl $00:e04b
    jsl $00:e04b
    jsl $00:e04b
    jsl $00:e04b
    jsl $00:e04b
    jsl $00:e04b
    jsl $00:e04b
    jsl $00:e04b
    jsl $00:e04b
    jsl $00:e04b
    lda #$42    ; B
    jsl $00:e04b
Not only will you not see the B printed, you'll only see 9 A's?

Edit: this may well be a handshake issue of some kind.
Quote:
LDX #10 ;SET BUFFER SIZES
STX SINCNT0
STX SINCNT1
STX SINCNT2
STX SINCNT3
STX SOUTCNT0
STX SOUTCNT1
STX SOUTCNT2
STX SOUTCNT3
All of the output buffers are set to 10.

I assume the monitor works? You can connect and dump memory (something that should readily use up more than 10 characters...)
randrews
Posts: 20
Joined: 13 Mar 2019

Re: WC65C265SXB Monitor ROM problems

Post by randrews »

whartung: Sorry, I didn't explain this well. In your example I wouldn't see anything, no As or B. If you remove the B then I'd see nine As. And yes, the monitor can print as many characters as it wants. In fact if I make a program that prints nine characters I can run it over and over again without a reset.

leepivonka: I don't think I'm overwriting anything it uses, nothing in my program ends up on that page, my code segment is at 2000 and data at 3000, and the startup code (which is from c0l.obj, I didn't write it) is 7d00. I have to include IRQHandler because if I don't it complains that the symbol is undefined. I can't find anything about what it should actually DO though.

handyandy: I am almost certain you've got the right answer. I tried this last night right after I posted my question, I replaced the calls with putchar with calls to send_byte_to_pc. Suddenly I was still seeing only 9 characters... but no crash, the remaining characters just didn't show up. So I bet what I have to do is, call send_byte_to_pc repeatedly until I get a call that returns with the carry bit clear. There's probably a 10-char buffer of stuff it's sending over serial and once it fills that buffer put_chr breaks until it clears.
randrews
Posts: 20
Joined: 13 Mar 2019

Re: WC65C265SXB Monitor ROM problems

Post by randrews »

And I spoke too soon. I replaced my monitor_putchar code with this:

Code: Select all

void monitor_putchar(char ch) {
	asm {
				lda %%ch
	send_loop:	jsl $00:e063
				bcs send_loop
	}
}
And now I have the exact same problem I had when using put_chr: try to output more than 9, and it outputs nothing. Output 9 or fewer, and it works fine.

Take out the bcs and the behavior is, try to output more than 9, the first 9 are output and that's it. But it doesn't freeze.

So I now think the problem is: if you fill up the output buffer then something is supposed to fire to empty it, only it's not. Does anyone have an example working C program for this thing?
handyandy
Posts: 113
Joined: 14 Sep 2015
Location: Virginia USA

Re: WC65C265SXB Monitor ROM problems

Post by handyandy »

send_byte_to_pc fills the buffer; irqat3, the ISR to transmit over UART port 3 is supposed to be emptying the buffer. Are you using hardware handshake or XON/XOFF?

I don't have an example working C program...
randrews
Posts: 20
Joined: 13 Mar 2019

Re: WC65C265SXB Monitor ROM problems

Post by randrews »

I don't have anything for a handshake, my entire code is above. I'm trying to use the USB serial thing hooked to the monitor ROM.

So if that interrupt handler is supposed to empty it, maybe the problem is that I'm implementing IRQHandler with an empty function. But I can't find anywhere what's actually supposed to go there, and nothing in lib/ seems to provide that symbol.
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Re: WC65C265SXB Monitor ROM problems

Post by BitWise »

Why not implement your own polled output routine for now and replace with something cleverer later?

In my SXB-Hacker I use this for UART output.

Code: Select all

; Wait until the last transmission has been completed then send the character
; in A.

                public  UartTx
UartTx:
                pha                             ; Save the character
                php                             ; Save register sizes
                short_a                         ; Make A 8-bits
                pha
                lda     #(1<<1)<<(2*UART)
TxWait:         bit     UIFR                    ; Has the timer finished?
                beq     TxWait
                pla
                sta     ARTD0+2*UART            ; Transmit the character
                plp                             ; Restore register sizes
                pla                             ; And callers A
                rts                             ; Done
You would need to the core of this in your C function.
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
randrews
Posts: 20
Joined: 13 Mar 2019

Re: WC65C265SXB Monitor ROM problems

Post by randrews »

I'm sorry, I don't know enough yet to understand what that code is doing. What are UIFR, UART, and ARTD0?
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Re: WC65C265SXB Monitor ROM problems

Post by BitWise »

UIFR and ARTD0 are constants for hardware register addresses. UART is a 0-3 value which determines which of the UARTs to use. I think the WDC monitor uses 3.

You could the routines in C, something like

Code: Select all

const far unsigned char *pUIFR = 0x00DF48;
const far unsigned char *pARTD3 = 0x00DF77;

void putchar (char ch)
{
  while ((*pUIFR & 0x80) == 0x00) ;
  *pARTD3 = ch;
}
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Re: WC65C265SXB Monitor ROM problems

Post by BitWise »

This seems to compile into reasonable looking code

Code: Select all

#define UIFR      ((volatile unsigned char * far) 0x00df48)
#define ARTD3     ((volatile unsigned char * far) 0x00df77)

void putchar (char ch)
{
  if (ch == '\n') putchar ('\r');

  while ((*UIFR & 0x80) == 0x00) ;
  *ARTD3 = ch;
}

void puts (const char *pStr)
{
  register char ch;

  while (ch = *pStr++) putchar (ch);
}

int main (int argc, char **argv)
{
    puts ("Hello World\n");

    return (0);
}
It could be more efficiently coded in assembler but that can always be done later.
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
randrews
Posts: 20
Joined: 13 Mar 2019

Re: WC65C265SXB Monitor ROM problems

Post by randrews »

Oh man, thank you so much, that's the first piece of example C code for this thing I've seen, and it worked!

I had to modify it a little bit, their compiler still doesn't link anything without me defining an IRQHandler function, but since that code doesn't use the IRQ handler (which I guess the monitor ROM does) then it works.

I think I'm going to return this board anyway though. The documentation is horrible, and if it took this much trouble to get a Hello World going then I'm expecting everything to be a hassle with this. I'll just use a normal 65c02 for my project.

Edit: except maybe not. The more I think about it the entire problem has been, well, anything that came out of WDC. If I use cc65 and don't try to call the monitor rom for anything, then writing code for this thing may be reasonable. I assume that stuff like the addresses you're poking in that code, you found by just reading the datasheet for the chip?
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Re: WC65C265SXB Monitor ROM problems

Post by BitWise »

Scott and I wrote some documentation for the 265SXB here:

https://github.com/scotws/265SXB-Guide

Neither of us program the board in C. We use assembler. I have a 1MB SRAM expansion card I designed plugged into mine.

I rather like the board. Its much easier to work with than the 816SXB.
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
Post Reply