6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 11:51 am

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: Reading data from memory
PostPosted: Mon Jul 26, 2021 3:49 pm 
Offline

Joined: Tue Jun 19, 2018 8:28 am
Posts: 122
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:
;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:
;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:
;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?


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 26, 2021 5:27 pm 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 336
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.

Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 26, 2021 5:46 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
In this case, with two byte-sized parameters, you could pass them in any two of A, X, Y.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 26, 2021 7:06 pm 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 411
Location: Minnesota
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:
;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:
   ...
    ldx #<(32*8)
    ldy #>(32*8)
   ....


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 27, 2021 5:23 pm 
Offline
User avatar

Joined: Sun Nov 01, 2020 10:36 am
Posts: 37
Location: Tatooine
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.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 28, 2021 6:51 pm 
Offline

Joined: Tue Jun 19, 2018 8:28 am
Posts: 122
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
6502.jpg [ 121.12 KiB | Viewed 1131 times ]
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC


Who is online

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