Home > OS >  Saving and reusing register in C64 assembler?
Saving and reusing register in C64 assembler?

Time:10-04

I have this code:

        jsr cls
        ldx #$00    ;loads 0 into x
        stx tmp     ; stores x in tmp
        ldx #<scr1
        ldy #>scr1
printToScreen
        stx zpb 0
        sty zpb 1
        lda (zpb),y
        ldx tmp.       ; loads x from tmp
        beq done
        sta screen_start,x
        inx
        stx tmp        ; stores new x in tmp
        bne printToScreen
done
        rts

tmp = $C8
zpb = $fb
scr1 byte 'some text'
byte 0

I want to create routine which prints a string to the screen. The arguments are the address of the string and the X register, which is used as a counter. Since X is used inside the function as well I'm storing its value in the tmp variable.

But this code prints nothing. I'm totally new to assembly, so probably I don't understand how this is supposed to work. Please see code comments. What am I doing wrong here?

CodePudding user response:

            jsr cls
            ldy #$10    ; loads $10 into x as a string length
            lda #<scr1
            sta zpb 0
            lda #>scr1
            sta zpb 1
printToScreen
            lda (zpb),y
            sta screen_start,y
            dey
            bne printToScreen
            rts

I would do that way. To be honest I didn't test the code I've written above. I've changed it the way I think it should be done.

Concerning your code: It is not needed to overwrite zpb and zpb 1 in every loop iteration. You forgot to set Y index register before you do "lda (zpb),y" - and probably it should be zero. After "ldx tmp" you don't compare it wth anything (should be cpx #something) so as default you compare it with zero (beq done) and cpu quits the program because X==0. So your program writes one byte somewhere in the memory and just exits.

CodePudding user response:

Is .X supposed to be the length of the string that is being printed?

Your current code:

printToScreen
    stx zpb 0
    sty zpb 1
    lda (zpb),y
    ldx tmp.
    beq done
    sta screen_start,x
    inx
    stx tmp
    bne printToScreen

What I think you are trying to do is:

  1. Pass the address of the string in .X and .Y
  2. Store this in zpb
  3. Fetch the bytes using indirect addressing at zpb and store them to the screen at screen_start

A couple of problems:

  • lda (zpb),y is the correct addressing mode, but you never initialize the .Y register. So the .Y register at the first call is actually using the most significant byte of the address you passed to begin with
  • The combination of inx stx tmp bne printToScreen.. When you do the inx and bne you are saying "increase .X, save it, and if it is not equal to zero, branch to printToScreen". But that effectively looks like you are trying to copy 256 bytes.
  • Notwithstanding never initializing .Y, you also never change it, so it will effectively always get the same byte pointed to (indirectly) by zpb.
  • You are initialzing .X with #$00 and storing it in tmp, but that really doesn't need to be done with what I think you are trying to do.
  • If .X is supposed to be the length then you aren't actually defining that anywhere...you are effectively doing this for 256 bytes (unless that's what you want?)
  • You keep storing .X and .Y in zpb, but that precludes you from actually using .X and .Y

That said, what I think might work for you is:

    jsr cls     ; assuming this is a routine to clear the screen
    ldx #<scr1
    ldy #>scr1
    stx zpb 0
    sty zpb 1
    ldy #$00
printToScreen
    lda (zpb),y
    beq done
    sta screen_start,y
    iny
    bne printToScreen
done
    rts
scr1 .asc 'some text'
    .byt 0

What this will do is:

  • store the location of scr1 in zpb
  • loop through scr1 and store it at screen_start, and end if:
    • the current byte is the 0 byte (it checks this before doing the actual copy); or
    • .Y becomes zero (again, after initialization)
  • Related