Reading data from memory

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Post Reply
Atlantis
Posts: 122
Joined: 19 Jun 2018

Reading data from memory

Post 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?
John West
Posts: 383
Joined: 03 Sep 2002

Re: Reading data from memory

Post 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.
Last edited by John West on Mon Jul 26, 2021 6:00 pm, edited 1 time in total.
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: Reading data from memory

Post by BigEd »

In this case, with two byte-sized parameters, you could pass them in any two of A, X, Y.
teamtempest
Posts: 443
Joined: 08 Nov 2009
Location: Minnesota
Contact:

Re: Reading data from memory

Post 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)
   ....
User avatar
BB8
Posts: 57
Joined: 01 Nov 2020
Location: Tatooine

Re: Reading data from memory

Post 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.
Atlantis
Posts: 122
Joined: 19 Jun 2018

Re: Reading data from memory

Post 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. ;)
Attachments
6502.jpg
Post Reply