assemblyc64

Kick Assembly remove borders of C64 trick


I'm trying to conver this ACME asm script to Kick Assembler syntax.

This is what i've made:

    .macro Wait (v) {
        ldy #v
        dey
        bne *-1
    }
     
    * = $0801
    .byte $0c, $08, $00, $00, $9e, $32, $30, $36, $31, $00, $00, $00

    * = $080d
    lda #$01
    sta $3fff
    sei
start:
    lda #$30
    cmp $d012
    bne *-3
    lda #$00
    sta $d011 
    Wait(24)
    lda #$0b
    sta $d011
    lda #$31
    cmp $d012
    bne *-3
    lda #$1b
    sta $d011 
    Wait(8)
    bit $ea
    ldx #$00
loop1:
    txa
    sta $d020
    sta $d021 
    Wait(9)
    inx
    cpx #254
    bne loop1
    asl $3fff
    bne start
    inc $3fff
    jmp start

Unfortunately it displays:

enter image description here

I dont' understand actually 2 things:

Lastly: I've tried out of curiosity to remove the macro, and it shows screen without border, but in the upper part i got rasterlines: enter image description here

Hope it helps to clearify my question. Thanks for any advice!

EDIT - as per Emir advices:

this is my new code attempt, mixed with your first snippet, it's useful since the sprite can be moved with joystick to test (horizonthal on the right i still didn't fixed the 255 limit, so it will reapper on the left in case moving on the far right...). Actually tried to follow your suggestion but probably did something wrong so end up with this "almost" working result:

   * = $0801
    BasicUpstart($080d);

.label JOYSTICK_2 = $dc00

.label UP       = %00000001
.label DOWN     = %00000010
.label LEFT     = %00000100
.label RIGHT    = %00001000
.label FIRE     = %00010000

.label JOYSTICK_2_IDLE = %01111111

.label SCREEN_RAM = $0400
.label SCREEN_CLEAR = $e544
.label SCREEN_BORDER_COLOR = $d020


.macro WAIT(duration) {
        ldy #duration
        dey
        bne *-1
}

    * = $080d

    lda #150
    sta $d000 // X position of sprite 0

    lda #230
    sta $d001 // Y position of sprite 0

    lda #LIGHT_RED
    sta $d027 // Sprite 0 color

    lda #BLACK
    sta $d025 // Sprite extra color 1

    lda #WHITE
    sta $d026 // Sprite extra color 2

    lda #$80
    sta $07f8 // Sprite 0 sprite pointer index

    lda #%00000001 // Enable multicolor for sprite 0
    sta $d01c
    
    lda #%00000001 // Enable sprite 0
    sta $d015

        lda #$01
        sta $3fff
        sei
start:
    
        lda #$fa
        cmp $d012
        bne *-3
        lda #$00
        sta $d011
        WAIT(22)
        lda #$1b
        sta $d011   
        jsr gameLoop
/*
loop1:
        txa
        sta $d020
        sta $d021
        WAIT(9)
        inx
        cpx #254
        bne loop1
        asl $3fff
        bne start
        inc $3fff
        jmp start*/

gameLoop:

        ldx #0
        slowDownLoop:
            nop
            nop
            nop
            nop
            nop
            nop
            nop
            nop

            inx
            cpx #255
            bne slowDownLoop

        jsr readJoystick_2
        //jmp gameLoop
        //
        jsr start

    readJoystick_2:
        lda JOYSTICK_2 // $dc00
        cmp #JOYSTICK_2_IDLE // %01111111
        beq joy2_IDLE
                jmp checkJoy2_UP
            joy2_IDLE:

            checkJoy2_UP:
                lda JOYSTICK_2
                and #UP
                beq joy2_UP
                    jmp checkJoy2_DOWN
                joy2_UP:
                    dec $d001

            checkJoy2_DOWN:
                lda JOYSTICK_2
                and #DOWN
                beq joy2_DOWN
                    jmp checkJoy2_LEFT
                joy2_DOWN:
                    inc $d001
                
            checkJoy2_LEFT:
                lda JOYSTICK_2
                and #LEFT
                beq joy2_LEFT
                    jmp checkJoy2_RIGHT
                joy2_LEFT:
                    dec $d000
                
            checkJoy2_RIGHT:
                lda JOYSTICK_2
                and #RIGHT
                beq joy2_RIGHT
                    jmp checkJoy2_FIRE
                joy2_RIGHT:
                    inc $d000
                
            checkJoy2_FIRE:
                lda JOYSTICK_2
                and #FIRE
                beq joy2_FIRE
                    jmp doneReadJoystick_2
                joy2_FIRE:
                    inc SCREEN_BORDER_COLOR
                
        doneReadJoystick_2:
            rts

*=$2000
.import binary "testGuy.bin"

The "testGuy.bin" is a trivial sprite (i'll link here for complete test anyways).

Anyways the sprite is capable to overlap upper\lower borders, but there are black vertical lines artifacts:

here

Can u help me solve this? Regards!

EDIT 2: this finally did the trick!

 lda #$00
  sta $3fff

Case closed!


Solution

  • The script you are trying disables the screen without opening the borders. Benefit is having stable timing and not dealing with DMA lines. You can use border/screen colors, sprites and ghost byte ($3fff in this code example) to draw things even if screen seems to be disabled.

    If you want to open borders, the code you need is very similar (you can find it below the answers). I removed unnecessary parts to have stable raster timings since raster timings are harder to deal with when the screen is open. You will notice raster flickering. They are easy to avoid using timing tables and stable raster IRQ tricks. But i'll focus on your questions.

    1. How to fix?

    There is nothing to fix. It's supposed to work like this. The version i shared below opens upper/lower borders with a very similar method but at bottom border position instead of top border (which are top=$32, bottom=$fa). You'll notice that ghost byte is now shown in upper and lower borders only. Since we don't disable the inner screen now (we still could), inner screen doesn't show ghost byte. You can put sprites to upper/lower borders or inner screen area if you want.

    1. Where exactly i could insert entry point of my code to benefit of having cleared the screen?

    $080d is your code entry point. You can of course change it to any address, use labels for start address etc. Only static address in this case is $0801, which is default basic startup address. You don't need $0801 at all. You can load the PRG file and run your code with a SYS command. $0801 is only there to make things easier and serves you as an autorun mechanism, nothing else.

    1. Lastly: I've tried out of curiosity to remove the macro, and it shows screen without border, but in the upper part i got rasterlines;

    What that macro does is just to wait, spend cycles while screen is being drawn. When you skip waiting, code runs as fast as it can and you see shorter splitted raster colors. Every 8 pixel character area equivalent to a CPU cycle. So, let's say we started changing colors using back to back STA/STX opcodes like STA $d021, STX $d021, STA $d021, STX $d021 while A and X registers are having two different color codes. Screen color will change every four character wide area, in other words every 32 pixels. This is why STA/STX opcodes take 4 cycles to operate. This is how things work. That WAIT macro waits for correct raster positions to operate things at the right place.

    That WAIT macro is not required. You can simply inline the same code (LDY, DEY, BNE opcodes) to the places where macro is used. Macros just helps us with repeating codes, very similar to inlined functions. If it's a distraction for you, just ignore them, inline the codes, get rid of macro usage.

    Here is the modified code which opens the upper/lower borders and doesn't disable inner screen.

        * = $0801
        BasicUpstart($080d);
    
    .macro WAIT(duration) {
            ldy #duration
            dey
            bne *-1
    }
    
        * = $080d
            lda #$01
            sta $3fff
            sei
    start:
            lda #$fa
            cmp $d012
            bne *-3
            lda #$00
            sta $d011
            WAIT(22)
            lda #$1b
            sta $d011
    loop1:
            txa
            sta $d020
            sta $d021
            WAIT(9)
            inx
            cpx #254
            bne loop1
            asl $3fff
            bne start
            inc $3fff
            jmp start
    

    Here is another alternative version with open borders and closed inner screen with stable timings.

        * = $0801
        BasicUpstart($080d);
    
    .macro WAIT(duration) {
            ldy #duration
            dey
            bne *-1
    }
    
            * = $080d
            lda #$01
            sta $3fff
            sei
    start:
            lda #$fa
            cmp $d012
            bne *-3
            lda #$00
            sta $d011
            WAIT(22)
            lda #$0b
            sta $d011
    loop1:
            txa
            sta $d020
            sta $d021
            WAIT(9)
            inx
            cpx #254
            bne loop1
            asl $3fff
            bne start
            inc $3fff
            jmp start