Page 1 of 1

Reading data from memory

Posted: Mon Jul 26, 2021 3:49 pm
by Atlantis
I returned to one of my old projects - homemade computer with 6502 and TMS9918 video controller.
Computer itself works with EhBasic, now I am going to write some code to add the TMS9918 support. I already done that with my other project utilizing 8080 CPU, so it is tested design. I also have 8080 code to base on. Unfortunately I came across some problems.

I was able to communicate with TMS9918 and initialize its registers. At this point I have garbage on screen, because VRAM wasn't initialized yet. I need to transfer character definitions stored in EPROM to VRAM.

In my 8080 computer I used following procedure for that:

Code: Select all

;RAM ADDRESS IN BC, VRAM ADDRES IN DE, DATA LENGTH IN HL        
VDPWVRAM:
MOV A, E
OUT VDP_MODE
MOV A, D
ORI 40H
OUT VDP_MODE
VDPWVRAML:
LDAX B
OUT VDP_DATA
INX B
DCX H
MOV A, H
ORA L          
JNZ VDPWVRAML
RET
I tried to translate it to the 6502 assembly, using following code:

Code: Select all

;RAM ADDRESS IN BLKIND, VRAM PASSED BY STACK (LSB FIRST), DATA LENGTH BLKLEN               
VDPWVRAM
PLA
STA VDP_MODE
PLA
ORA #$40
STA VDP_MODE
LDY #$00
VDPWVRAML
LDA (BLKIND), Y
STA VDP_DATA
INC BLKIND
BNE VDPWVRAML1
INC BLKIND+1
VDPWVRAML1
DEC BLKLEN
BNE VDPWVRAML
LDA BLKLEN+1
BEQ VDPWVRAMRET
DEC BLKLEN+1
BNE VDPWVRAML
VDPWVRAMRET:
RTS
Which is executed as follows:

Code: Select all

;INITiALIZE VRAM
LDA #<CHARS
STA BLKIND
LDA #>CHARS
STA BLKIND+1
;0000H + (32*8)
LDA #<(32*8)
PHA
LDA #>(32*8)
PHA
LDA #<(CHARS_END-CHARS)
STA BLKLEN
LDA #>(CHARS_END-CHARS)
STA BLKLEN+1
JSR VDPWVRAM
Unfortunately code freezes when I try to call VDPWVRAM procedure. What Am I doing wrong?

Re: Reading data from memory

Posted: Mon Jul 26, 2021 5:27 pm
by John West
The problem is that the JSR is pushing the return address, so that's going to be at the top of the stack when VDDWVRAM starts. And the RTS will be using the value pushed by the caller as the return address - which is not going to go well. The 6502 isn't great at manipulating the stack - if you need more parameters than will fit in memory (edit: I meant 'in registers', of course) it's more common to stick them in page 0, as you have with BLKIND and BLKLEN.

If you really want to use the stack, the cleanest is probably to use TSX; LDA $0103, X (I think it's $0103, but I've never used this method myself). Then the caller has to remove the data that it pushed.

Re: Reading data from memory

Posted: Mon Jul 26, 2021 5:46 pm
by BigEd
In this case, with two byte-sized parameters, you could pass them in any two of A, X, Y.

Re: Reading data from memory

Posted: Mon Jul 26, 2021 7:06 pm
by teamtempest
As has been pointed out, at entry to the routine the stack state is not what the routine expects. There are a number of ways to deal with that. One approach:

Code: Select all

;RAM ADDRESS IN BLKIND, VRAM PASSED BY STACK (LSB FIRST), DATA LENGTH BLKLEN               
VDPWVRAM

    pla                  ; remove return address
    tax
    pla
    tay

   PLA
   STA VDP_MODE
   PLA
   ORA #$40
   STA VDP_MODE

   tya                  ; put return address back
   pha
   txa                  ; (for 65C02, just use plx/phx and ply/phy)
   pha
   LDY #$00
   ldx blklen+1         ; (assumed non-zero; if it can be put a branch right after)

VDPWVRAML               ; whole pages...
    LDA (BLKIND), Y
    STA VDP_DATA
    iny
    BNE VDPWVRAML1
    INC BLKIND+1

VDPWVRAML1
    dex
    BNE VDPWVRAML
    ldx blklen
    beq VDPWVRAMRET

VDPWVRAML2               ; final partial page
    lda (BLKIND),y
    sta VDP_DATA
    iny
    dex
    bne VDPWVRAML2

VDPWVRAMRET:
    RTS
Or, as Ed suggests, instead of passing (32*8) in two stack bytes, load them into X and Y before calling the routine, then TXA and TYA to store them into VDP_MODE from there (or use STX and STY if you let the assembler -OR- the high byte for you at assembly time):

Code: Select all

   ...
    ldx #<(32*8)
    ldy #>(32*8)
   ....

Re: Reading data from memory

Posted: Tue Jul 27, 2021 5:23 pm
by BB8
In the comment you say "LSB first": if you pushed the low byte before the high one, maybe you're loading the VDP_MODE in the wrong order.

Re: Reading data from memory

Posted: Wed Jul 28, 2021 6:51 pm
by Atlantis
John West wrote:
The problem is that the JSR is pushing the return address, so that's going to be at the top of the stack when VDDWVRAM starts.
Thanks. It works now. I suspected it must have been something trivial, I was unable to notice. ;)