C64 assembler - Trying to print 4 rows at the top and the bottom

129 Views Asked by At

I'm trying to print some rows of a char from the top and bottom, first row turns out as expected but next one doesn't print. I add 40 chars to "Currentline" to get the prog to print the next row, well - that was what I thought would work. It won't print, but if I set "Currentline" to 40 from the start it prints on the next row.

What am I doing wrong?

/*
****************************************
* Really awesome code by Cri33e - 2022 * 
****************************************
*/

*=$2000                             // Startas med sys8192


.var ScreenCTop_Adress = $d7ff
.var ScreenCBottom_Adress = $dbbf
.var ScreenTop_Adress = $03ff
.var ScreenBottom_Adress = $07bf

.var Currentline = 0
.var Char_color = 3
.var HowManyRows = 4

Next_row:              
                lda #Char_color
                ldy #20             
                ldx #40             

 loop1:          
                sta ScreenCTop_Adress+Currentline,x     
                sta ScreenCBottom_Adress-Currentline,x 
                tya
                sta ScreenTop_Adress+Currentline,x       
                sta ScreenBottom_Adress-Currentline,x   
                lda #Char_color
                dex
                bne loop1

                lda Currentline + 40  
                sta Currentline        

                ldx HowManyRows       
                dex
                stx HowManyRows
                bne Next_row

rts


enter code here
1

There are 1 best solutions below

0
ge97aa On

I see the following problems:

  1. The .var directive does not do what you think it does (at least for Currentline and HowManyRows). I think it's just a preprocessing directive similar to #define in C. You should use the .DB directive along with a memory label.
  2. You cannot do an addition-and-load in the same operation, so (assuming you make the correction suggested in point 1) lda Currentline + 40 will not do what you think it will. It loads the accumulator with the value from the memory address specified by Currentline offset by 40 bytes.
  3. Similarly, you cannot do an addition-and-store in the same operation, so , so (assuming you make the correction suggested in point 1) lines like sta ScreenCTop_Adress+Currentline,x will not work. It will store the value in the accumulator at the address equal to the ScreenCTop_Adress + the address of Currentline plus the value in X.

Your code needs a significant rewrite in order to make it work, and because screen RAM and colour RAM are larger than 256 bytes each, it can't be done properly without using pointers in the zero-page and indirect addressing. However, just for the fun of it I'll attempt a rewrite that doesn't use the zero-page, since I don't know what portion of the zero-page is available to you. I'll also try to make it as similar to your code as possible, but a LOT needs to be changed. I warn you, the result will be ugly and by no means the right solution. Also, I'm not testing this.

; Color RAM base addresses for groups of six character rows
; (i.e. what can be fully addressed with an 8-bit index)
.VAR ScreenC_Address_0_5 = $D800    ; rows 0-5
.VAR ScreenC_Address_6_11 = $D8F0   ; rows 6-11
.VAR ScreenC_Address_12_17 = $D9E0  ; rows 12-17
.VAR ScreenC_Address_18_23 = $DAD0  ; rows 18-23
.VAR ScreenC_Address_24 = $DBC0     ; row 24
                                  
; Screen RAM base addresses for groups of six character rows
; (i.e. what can be fully addressed with an 8-bit index)                 
.VAR Screen_Address_0_5 = $0400    ; rows 0-5
.VAR Screen_Address_6_11 = $04F0   ; rows 6-11
.VAR Screen_Address_12_17 = $05E0  ; rows 12-17
.VAR Screen_Address_18_23 = $06D0  ; rows 18-23
.VAR Screen_Address_24 = $07C0     ; row 24

; this is what you are filling your line with
; these are constants - you need to reassemble to change them
; an alternative is to store these in memory and set then set 
; them in code before calling the function   
.VAR Char_color = 3                ; color constant (cyan)
.VAR CharVal = $20                 ; fill character display code (space)

CurrentLine:    .DB 0                      ; first row number to fill
HowManyRows:    .DB 4                      ; count of rows to fill at top and bottom
MirrorCount:    .DB                        ; so code doesn't have to be duplicated for top/bottom halves

Next_row:       LDA #2
                STA MirrorCount            ; two line fills per row (one at the top, one at the bottom)
MirrorWrite:    LDA CurrentLine            ; get the row number to fill next
                LDX #$FF
FindBankLoop:   INX
                SEC
                SBC #6
                BCS FindBankLoop           ; find which bank of 6 rows the target row resides in

                ADC #6
                TAY                        ; calculate the row number relative to the start of the bank
                CLC
RowIdxLoop:     ADC #40
                DEY
                BPL RowIdxLoop
                TAY                        ; get an index to the end of the row (actually start of subsequent row)

FillLine:       DEX
                BPL TryBank1               ; continue if row is not in first bank

                TAX                        ; get index to the end of the row
                LDA #Char_color

LineColorBank0: DEX
                STA ScreenC_Address_0_5,X  ; set a character colour
                BNE LineColorBank0         ; fill the line with the desired colour

                LDA #CharVal
                
LineTextBank0:  DEY 
                STA Screen_Address_0_5,Y   ; write the screen code to screen RAM
                BNE LineTextBank0          ; fill the line with the character
                BEQ EndLineFill            ; absolute branch - finish with the current line

; same thing but in the second bank of six character rows
TryBank1:       DEX
                BPL TryBank2

                TAX
                LDA #Char_color

LineColorBank1: DEX
                STA ScreenC_Address_6_11,X
                BNE LineColorBank1

                LDA #CharVal
                
LineTextBank1:  DEY 
                STA Screen_Address_6_11,Y
                BNE LineTextBank1
                BEQ EndLineFill
   
; same thing but in the third bank of six character rows             
TryBank2:       DEX
                BPL TryBank3

                TAX
                LDA #Char_color

LineColorBank2: DEX
                STA ScreenC_Address_12_17,X
                BNE LineColorBank2

                LDA #CharVal
                
LineTextBank2:  DEY 
                STA Screen_Address_12_17,Y
                BNE LineTextBank2
                BEQ EndLineFill
      
; same thing but in the fourth bank of six character rows      
TryBank3:       DEX
                BPL DoLine24

                TAX
                LDA #Char_color

LineColorBank3: DEX
                STA ScreenC_Address_18_23,X
                BNE LineColorBank3

                LDA #CharVal
                
LineTextBank3:  DEY 
                STA Screen_Address_18_23,Y
                BNE LineTextBank3
                BEQ EndLineFill

; same thing but in the fifth bank of six character rows
DoLine24:       TAX
                LDA #Char_color

Line24Color:    DEX
                STA ScreenC_Address_24,X
                BNE Line24Color

                LDA #CharVal
                
Line24Text:     DEY 
                STA Screen_Address_24,Y
                BNE Line24Text

EndLineFill:    SEC
                LDA #24
                SBC CurrentLine
                STA CurrentLine        ; mirror the current line in the bottom half of the screen (or switch back to the top half)
                DEC MirrorCount
                BEQ Cont1
                JMP MirrorWrite        ; fill the line in the bottom half of the screen
Cont1:          INC CurrentLine        ; move to the next row
                DEC HowManyRows
                BEQ Cont2
                JMP Next_row           ; fill the specified number of rows
Cont2:          RTS

EDIT: Thirty seconds after posting this answer, I thought of a much cleaner way of doing this, still without using the zero-page. I realized I could use inline pointers to the start of the row in screen RAM and colour RAM. This shortens the code considerably.

.VAR ScreenC_Address = $D8            ; color RAM base page
.VAR Screen_Address = $04             ; screen RAM base page

; this is what you are filling your line with
; these are constants - you need to reassemble to change them
; an alternative is to store these in memory and set then set 
; them in code before calling the function   
.VAR Char_color = 3                    ; color constant (cyan)
.VAR CharVal = $20                     ; fill character display code (space)

; set these values to whatever you want before calling the function
CurrentLine:    .DB 0                  ; first row number to fill (0 – 24)
HowManyRows:    .DB 4                  ; count of rows to fill at top and bottom

MirrorCount:    .DB                    ; so code doesn't have to be duplicated for top/bottom halves

Next_row:       LDA #2
                STA MirrorCount        ; two line fills per row (one at the top, one at the bottom)
MirrorWrite:    LDA #0
                TAY
                LDX CurrentLine
                CLC
                BEQ SetPointers
PtrAdjLoop:     ADC #40
                BCC SkipHigh
                INY
                CLC
SkipHigh:       DEX
                BNE PtrAdjLoop         ; calculate 16-bit index to start of row in YA
SetPointers:    STA InlPtrColor+1
                STY InlPtrColor+2
                STA InlPtrScreen+1
                STY InlPtrScreen+2

                LDA #ScreenC_Address
                ADC InlPtrColor+2
                STA InlPtrColor+2      ; set inline color RAM pointer to start of row

                LDA #Screen_Address
                ADC InlPtrScreen+2
                STA InlPtrScreen+2     ; set inline screen RAM pointer to start of row

                LDA #Char_color
                LDY #39
InlPtrColor:    STA $FFFF,Y            ; $FFFF is arbitrary default value for color RAM pointer
                DEY
                BPL InlPtrColor

                LDA #CharVal
                LDY #39
InlPtrScreen:   STA $FFFF,Y            ; $FFFF is arbitrary default value for screen RAM pointer
                DEY
                BPL InlPtrScreen

                SEC
                LDA #24
                SBC CurrentLine
                STA CurrentLine        ; mirror the current line in the bottom half of the screen (or switch back to the top half)
                DEC MirrorCount
                BNE MirrorWrite        ; fill the line in the bottom half of the screen
                INC CurrentLine        ; move to the next row
                DEC HowManyRows
                BNE Next_row           ; fill the specified number of rows
                RTS