0

How to do correct copying char to sprite ? Lets say 1st char is at $2000 second is at $2008 and copying to sprite at $2480. And with this we can copy 1 char to top left position of 1st sprite. But what if we add more chars or any from 0 to 255. How we will solve that regarding 2 sprites in left sideborders and two in right sideborders? Lets say with 30 chars which occupy 6 chars in 5 rows (so total 30 chars; assuming Y - rows X - columns) We can copy 3 x 2 chars to two left sprites but what about 3rd row char (21 is not divisible with 8). This routine copy 1 char to 1st sprite. How to copy 30 chars (6 chars in 5 rows) to 2 sprites which data are 1st $2480 2nd 24C0?

                    ldy #$00
               char lda $2000,y
                    sta $2480,x
                    inx
                    inx
                    inx
                    iny
                    cpy #$08
                    bne char           
                
18
  • 3
    What is your question? Dec 20, 2020 at 19:45
  • 2
    It is a debugging question. It is rare here, but it is imho clear.
    – peterh
    Dec 20, 2020 at 21:15
  • 2
    @peterh-ReinstateMonica Could you edit the question to clarify it for the rest of us please, if you understand it?
    – wizzwizz4
    Dec 20, 2020 at 23:09
  • 1
    @Raffzahn Not clear. You are right. If the op disappears, then the question is at least unclear. Sad, I would be so happy to debug 6502 asm after so many decades again.
    – peterh
    Dec 20, 2020 at 23:19
  • 1
    @simun9 This still doesn't explain what you intend to do and what is to be done. The new description makes even less sense, and I'm doing 6502 since a bit more than 42 years. Please do simply explain what it should do and what are the steps to be taken - after all, if this is just about copying then all of the above is way over the edge. Likewhat is that shifting about and so on. Please write a simple list what you want to do.
    – Raffzahn
    Dec 20, 2020 at 23:59

3 Answers 3

1

I still have no idea what the question is really about. So what follows is a wild guess from what the OP posted in question, edits and comments as well as what I think he could be about:

Blowing Up an 8x8 Char Into a 24x21 Sprite

[I have no idea if this is right, but I can't believe it's just about copying, as that would be way too simple]

A character is stored within the character generator as a sequence of 8 bytes each holding a line with bits set for each pixel to be set, high to low as left to right. Example

00011000 (18) ->    **   
00111100 (3C) ->   ****  
01100110 (66) ->  **  **
01111110 (7E) ->  ******
01100110 (66) ->  **  **
01100110 (66) ->  **  **
00000000 (00) ->

To turn this into a sprite each bit needs to be tripled within a line - and similar each line (*1) as sprites are simply 3 bytes per line and 21 lines.

00000000 01111110 00000000 (00 7E 00) ->          ******   
00000000 01111110 00000000 (00 7E 00) ->          ******   
00000000 01111110 00000000 (00 7E 00) ->          ******   
00000011 11111111 11000000 (03 FF C0) ->       ************  
00000011 11111111 11000000 (03 FF C0) ->       ************  
00000011 11111111 11000000 (03 FF C0) ->       ************  
00011111 10000001 11111000 (1F 81 F8) ->    ******      ******
00011111 10000001 11111000 (1F 81 F8) ->    ******      ******
00011111 10000001 11111000 (1F 81 F8) ->    ******      ******
00011111 11111111 11111000 (1F FF F8) ->    ******************
00011111 11111111 11111000 (1F FF F8) ->    ******************
00011111 11111111 11111000 (1F FF F8) ->    ******************
00011111 10000001 11111000 (1F 81 F8) ->    ******      ******
00011111 10000001 11111000 (1F 81 F8) ->    ******      ******
00011111 10000001 11111000 (1F 81 F8) ->    ******      ******
00011111 10000001 11111000 (1F 81 F8) ->    ******      ******
00011111 10000001 11111000 (1F 81 F8) ->    ******      ******
00011111 10000001 11111000 (1F 81 F8) ->    ******      ******
[No line 22..24]

The following routine is a straight implementation without much tricks to get the job done. There might be some optimization possible, but I'd prefer to get it working first, before playing with alternative/more compact solutions.

Also, unlike the code posed with the question, this is made with pointers, keeping it as independent from any environment as possible (and free of self modifying code, so ROMable). So again, later optimizations may change this and save some code ... but as before I'd put that way at the end of all development. Having Independent subroutines help a lot to minimize development issues.

It's not neccessary made for shortest possible code, but execution time should be fairly good.

; Generic subroutiene to convert a character definition
; (a bitmap stored in 8 consecutive bytes) into a sprite
; of 24x21 pixel

; Called at
;  convert

; In:
;  chrptr, word, holding address of char definition, will be modified
;  sptr, word, holding the address of a 63 byte area to be filled with sprite data

; Out:
;  63 bytes of sprite data processed from character data stored beginning at sptr
;  chrptr pointing to the last line (not converted) of the character.

; In/Out
chrptr  DW  0   ; A zp-pointer to an 8 byte character definition to be converted
sptr    DW  0   ; A zp-pointer to a 64 byte area to be filled with the expanded character

; Local variables
sptr1   DW  0   ; Support pointer (zp) to the second line (copy of first+3)
sptr2   DW  0   ; Support pointer (zp) to the third line (copy of first+6)
temp    DB  0   ; temporary value for conversion

; Entry
convert:

;Setup
        LDA  sptr        ; prepare the pointers to save later on
        LDX  sptr+1
        CLC
        ADC  #3
        BCC  nopage1
        INX
nopage1:
        STA  sptr1       ; Pointer for second sprite line
        STX  sptr1+1
        CLC
        ADC  #3
        BCC  nopage1
        INX
nopge2:
        STA  sptr2       ; Pointer for third sprite line
        STX  sptr2+1

        LDY  #0          ; Offset within the character definition
        LDX  #7          ; 7 lines to be converted (no room for the 8th

;Conversion loop
loop:
        LDA  chrptr      ; Load a character line and bring it into tmp
        ROL  A           ; But lets extract the first bit first  - saves 3 cycles and a byte :))
        STA  temp
        LDA  #0          ; Clear A
        BCC  J1A         ; Was the top bit set ? 
        LDA  #%11100000  ; Yes -> set the first 3 bits of the sprite
J1A:
        ROL  temp        ; Check second bit
        BCC  J1B         ; Was it set ?
        ORA  #%00011100  ; Yes -> set the second 3 bits of the sprite
J1B:
        ROL  temp        ; Check third bit
        BCC  J1C         ; Was it set?
        ORA  #%00000011  ; Yes -> set the third 3 bits of the sprite ... ups, there are only two left in this byte
J1C:
        STA  (sptr),Y    ; Store first byte of first line
        STA  (sptr1),Y   ; Store first byte of second line
        STA  (sptr2),Y   ; Store first byte of third line

        INY              ; Next byte of the sprite
        LDA  #0          ; Clear A
        ROR              ; Bring the remaining bit into the second sprite byte

        ROL  temp        ; Check bit 4
        BCC  J2A         ; Was it set?
        ORA  #%01110000  ; Yes -> set the 4th 3 bits of the sprite 
J2A:
        ROL  temp        ; Check bit 5
        BCC  J2B         ; Was it set?
        ORA  #%00001110  ; Yes -> set the 5th 3 bits of the sprite 
J2B:
        ROL  temp        ; Check bit 6
        BCC  J2C         ; Was it set?
        ORA  #%00000001  ; Yes -> set the 6th 3 bits of the sprite - again wraping into the next byte
J2C:
        STA  (sptr),Y    ; Store second byte of first line
        STA  (sptr1),Y   ; Store second byte of second line
        STA  (sptr2),Y   ; Store second byte of third line
 
        INY              ; Next byte of the sprite
        LDA  #0          ; Clear A
        BCC  J3A         ; Was bit 6 set?
        ORA  #%11000000  ; Yes -> set the remaining bits of the 6th group
J3A:
        BIT  temp        ; Check bit 7 (Now using BIT to save 2 cycles)
        BPL  J3B         ; Was it set?
        ORA  #%00111000  ; Yes -> set the 7th 3 bits of the sprite 
J3B:
        BIT  temp        ; Check bit 8 (Now using BIT to save 2 cycles)
        BVC  J3C         ; Was it set?
        ORA  #%00000111  ; Yes -> set the 8th 3 bits of the sprite 
J3C:
        STA  (sptr),Y    ; Store third byte of first line
        STA  (sptr1),Y   ; Store third byte of second line
        STA  (sptr2),Y   ; Store third byte of third line

        DEX                    ; All 7 done?
        BEQ  end               ; Yes -> end

; Adjust pointer(s)

; Y needs to skip three lines/9 bytes (which are already filled) minus the two INY that already happened. Doing it via A saves 2 bytes and 4 cycles. Also, writing so many INY just adds a chance of a miscount.
        TYA
        CLC
        ADC  #7                ; 9-2
        TAY

; select next line in character
        INC  chrptr            ; Select next line of character
        BNE  loop              ; Next round if no page carry
        INC  chrptr+1          ; handle page carry
        BNE  loop              ; next round (will fail if the character table wraps at $FFFF - not really likely)

end:
        RTS

Lets see if this is in any way related to the question :))

[... thinking of it, there would also be a way for a table driven solution thay may be shoter and faster ... though, not sure, as above is ~127 bytes, while the table base solution neds already 32 bytes of table... :)]


*1 - Yes, I know, this doesn't end well, as there is no room for the lowest line.

1
  • A reasonable guess, so let's see if OP can use it Dec 21, 2020 at 8:40
1

If you want a straight up copy, then what about reading the char's bitmap first, and then writing it to the sprite?

       ldy #$07
cpch:  lda (chptr),y
       pha
       dey
       bpl cpch

       ldy #$17
       ldx #$07
cpspr: pla
       sta (sprptr),y
       dey
       dey
       dey
       dex
       bpl cpspr

Something like that?

4
  • BTW, you could shave of the first and last :)
    – Raffzahn
    Dec 21, 2020 at 9:37
  • @Raffzahn what do you mean Dec 21, 2020 at 9:48
  • Well, the first character can be transfered straight from chptr to sprptr without pushing while the last can be kept in A between both loops, so again saving an expensive PHA/PLA combination. But that was just a sidenote when thinking about the way you move it.
    – Raffzahn
    Dec 21, 2020 at 10:48
  • @Raffzahn That makes sense. It's a perfect optimisation for OP, who is a C64 democoder, to attempt. Dec 21, 2020 at 11:19
1

Alternative solution

With the last edit it seams as if it could be not about blowing up a char, but filling 6 char definitions located in sequence in into 6 sprites, again located in sequence. As before, it's just a guess due the rather unclear wording.

A routine to copy one char into one sprite (pre cleaned) might look like this:

; Generic subroutiene to convert a character definition
; (a bitmap stored in 8 consecutive bytes) into a sprite
; of 8x8 pixel

; Called at
;  convert

; In:
;  chrptr, word, holding address of char definition, will be modified
;                character data is assumed not to spread over a page boundry
;  sprptr, word, holding the address of a 63 byte area to be filled with sprite data
;                sprite area is assumed not to spread over a page boundry
;                sprite area is assumed not to be zeroed out

; Out:
;  sprite data processed from character data stored beginning at sprptr
;  chrptr pointing after the last line of the character.


chrptr  DW   0
sprptr  DW   0

convert:

;Setup
        LDY  #0          ; Sprite index
        LDX  #0
moveit:                  ; well, moveit!
        LDA  (chrptr,X)  ; Same as (chrptr), but that's only available on a C02
        STA  (sprptr),Y 

        CPY  #3*7        ; Last line done?
        BEQ  done        ; Yes -> return
        INC  chrptr      ; Next character line
        INY              ; Next sprite line
        INY
        INY
        JMP  moveit      ; Moveit :))

done:
        RTS

A routine doing calling above for 6 consecutive character definitions into 6 consecutive sprites may look like this:

chrcnt  DB  0            ; Temporary counter, preferable in ZP

entry:
        LDA #>charlist   ; Set Pointer to list of character definitions
        STA chrptr
        LDA #<charlist
        STA chrptr+1

        LDA #>spritearea ; Set Pointer to sprite area
        STA sprptr
        LDA #<spritearea
        STA sprptr+1

        LDA #6           ; Doing 6 chars
        STA chrcnt

cvtlp:
        JSR convert      ; Convert a char to sprite
        DEC chrcnt
        BEQ end          ; Last char -> exit
                         ; Character pointer is already advanced by convert
        LDA sprptr       ; Move pointer to next sprite
        CLC
        ADC #64          ; Length of a sprite entry
        STC sprptr
        BCC cvtlp        ; No carry -> Next round
        INC sprptr+1
        BCC cvtlp        ; Always -> Next round

end: 

Of course there are many more variations possible, like

  • using an ASCII string as input and getting the character bitmap from the character generator,

Which would simply requite locating the character definition from it's character code and hand over that address as pointer.

  • packing them in two sprites (row of 3 characters per sprite) if it's supposed to be a horizontal scrolling text

This can be done much like before, but after setting up the pointers we need to move them into the same sprite ofsetted by one:

        LDA #3           ; Doing 3 chars
        STA chrcnt

cvtlp:
        JSR convert      ; Convert a char to sprite
        DEC chrcnt
        BEQ end          ; Last char -> exit
                         ; Character pointer is already advanced by convert
        INC sprptr       ; Move pointer to next character position within sprite
        BCC cvtlp        ; Always -> Next round

end: 

[Obvious why I prefer routines that can be reused over premature optimized code?]

  • packing them in three sprites (column of 2 characters per sprite) if it's supposed to be a vertical scrolling text

Like above, but after setting up the pointers simply inserting the two characters:

        JSR convert      ; Convert first char into sprite
        LDA sprptr       ; Avance sprite pointer within the sprite to the next row
        CLC
        ADC #8*3         ; Skip 8 rows of 3 bytes
        STC sprptr       ; Correction of high-byte is not needed as sprites
                         ; are always aligned to $40 boundaries
        JSR convert      ; Convert second char into sprite
  • packing all 6 characters into a single sprite forming a two lines of 3 characters sprite

I guess, by now, the picture is clear: Rinse and repeat.

  • ... and so on ...

So, again, possibilities are endless with the unclear information given. There is no chance to give a definitive answer without a clear definition of the intended layout/usage.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .