C64汇编程序-试图在顶部和底部打印4行



我试图从顶部和底部打印一些字符行,第一行结果如预期,但下一行没有打印。我在";Currentline";让程序打印下一行,好吧——这就是我认为可行的。它不会打印,但如果我设置";Currentline";从开始到40,它打印在下一行。

我做错了什么?

/*
****************************************
* 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. .var指令不会执行您认为它会执行的操作(至少对于CurrentlineHowManyRows(。我认为这只是一个预处理指令,类似于C中的#define。您应该将.DB指令与内存标签一起使用
  2. 您不能在同一操作中进行加法和加载,因此(假设您进行了第1点中建议的更正(lda Currentline + 40不会执行您认为会执行的操作。它用Currentline指定的存储器地址的值加载累加器,偏移40字节
  3. 类似地,您不能在同一操作中进行加法和存储,所以,所以(假设您在第1点中进行了建议的更正(像sta ScreenCTop_Adress+Currentline,x这样的行将不起作用。它将把值存储在累加器中等于ScreenCTop_Adress的地址+Currentline地址加上X中的值

您的代码需要大量重写才能正常工作,而且由于屏幕RAM和彩色RAM各大于256字节,如果不在零页中使用指针和间接寻址,就无法正确地完成。然而,为了好玩,我将尝试重写使用零页面,因为我不知道零页面的哪一部分对您可用。我也会尽量让它与您的代码相似,但有很多地方需要更改。我警告你,结果将是丑陋的,决不是正确的解决方案。此外,我并没有对此进行测试。

; 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

编辑:在发布这个答案30秒后,我想到了一种更干净的方法,仍然不使用零页面。我意识到我可以在屏幕RAM和彩色RAM中使用行开头的内联指针。这大大缩短了代码。

.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

最新更新