Jump to content
IGNORED

Why the ripple upward?


tschak909

Recommended Posts

I am trying to do little exercises, to further my deeper understanding of writing kernels, and I've noticed something interesting, this particular listing causes the missiles/ball to shift one scanline upward in the middle of the screen... Why is this happening?

 

 

        LDX #ENABL              ; 3     3       16
        TXS                     ; 2     5       18
        LDA SCANLINE            ; 3     8       21
        EOR BALLY2              ; 3     11      24
        PHP                     ; 3     14      27
        LDA SCANLINE            ; 3     17      30
        EOR BALLY1              ; 3     20      33
        PHP                     ; 3     23      36
        LDA SCANLINE            ; 3     26      39
        EOR BALLY0              ; 3     29      42
        PHP                     ; 3     32      45
        STA WSYNC               ; 3     35 (---)48
        INC SCANLINE            ; 5     5
        LDA SCANLINE            ; 3     8
        CMP #232                ; 2     10
        BCC KERNloop            ; 3     13

 

SpiceWare: yes, I am MAKING myself write down cycle counts... (This was always the same problem I had in maths classes, wouldn't write down my intermediate steps, and drive my teachers crazy...)

 

binary attached.

 

-Thom

blip.bin

Link to comment
Share on other sites

This kernel seems to work better...




KERNloop:
LDX #ENABL ; 3 3 41
TXS ; 2 5 43
LDA SCANLINE ; 3 8 46
EOR BALLY2 ; 3 11 49
AND #$FE ; 2 13 51
STA WSYNC ; 3 16 54
PHP ; 3 3
LDA SCANLINE ; 3 6
EOR BALLY1 ; 3 9
AND #$FE ; 2 11
PHP ; 3 14
LDA SCANLINE ; 3 17
EOR BALLY0 ; 3 20
AND #$FE ; 2 22
PHP ; 3 25
INC SCANLINE ; 5 30
LDA SCANLINE ; 3 33
CMP #232 ; 2 35
BCC KERNloop ; 3 38




-Thom

working.bin

Link to comment
Share on other sites

I am trying to do little exercises, to further my deeper understanding of writing kernels, and I've noticed something interesting, this particular listing causes the missiles/ball to shift one scanline upward in the middle of the screen... Why is this happening?

That's because you're enabling/disabling missiles and ball in the visible area of the scanline. So if you enable them after their position, they will show up in the next line.

To avoid that glitch, you must ensure that all writes to ENAMx/ENABL (the 'php' instruction in your examples) happen during the horizontal blank, that is at most at cycle 22.

 

In your first example writes happen at cycle 26,35 and 44 (your calculations were off by 1 as "ldx IMM" takes 2 cycles, not 3) which correspond to pixel 10,37 and 64 respectively.

 

KERNloop:	;+1 if brach taken		13
        LDX #ENABL              ; 2     2       15
        TXS                     ; 2     4       17
        LDA SCANLINE            ; 3     7       20
        EOR BALLY2              ; 3     10      23
        PHP                     ; 3     13      26 <----- 
        LDA SCANLINE            ; 3     16      29
        EOR BALLY1              ; 3     19      32
        PHP                     ; 3     22      35 <-----
        LDA SCANLINE            ; 3     25      38
        EOR BALLY0              ; 3     28      41
        PHP                     ; 3     31      44 <-----
        STA WSYNC               ; 3     0       0
        INC SCANLINE            ; 5     5
        LDA SCANLINE            ; 3     8
        CMP #232                ; 2     10
        BCC KERNloop            ; 2*    12

In your second example, by putting the 'sta WSYNC' before the first write, things get better:

 

KERNloop:	;+1 if branch taken		38
        LDX #ENABL              ; 2     2       40
        TXS                     ; 2     4       42
        LDA SCANLINE            ; 3     7       45
        EOR BALLY2              ; 3     10      48
        AND #$FE                ; 2     12      50
        STA WSYNC               ; 3     0       0
        PHP                     ; 3     3		<-----
        LDA SCANLINE            ; 3     6
        EOR BALLY1              ; 3     9
        AND #$FE                ; 2     11
        PHP                     ; 3     14		<-----
        LDA SCANLINE            ; 3     17
        EOR BALLY0              ; 3     20
        AND #$FE                ; 2     22
        PHP                     ; 3     25		<-----
        INC SCANLINE            ; 5     30
        LDA SCANLINE            ; 3     33
        CMP #232                ; 2     35
        BCC KERNloop            ; 2*    37

Now, only the last write is in visible area (7 pixels from the left margin), so only missile0 is showing the glitch.

Edited by alex_79
Link to comment
Share on other sites

Yep, updating too late in the scanline results in shearing. I cover that at the start of Step 4 were I point out it occurs in Stay Frosty 2:

post-3056-0-75005500-1473005127_thumb.png

 

For SF2 I found it to be an acceptable compromise vs not having the snowball. As you've noticed, shear is rather easy to spot in objects that only travel horizontally. The snowball travels in an arc, so the sheering is less noticeable.

Link to comment
Share on other sites

How can I ensure that all my important register writes for all the objects occurs in the horizontal blank, without resorting to e.g. a 3LK? I'm trying to work my way through building a kernel that can update all six objects (playfield, players, missiles, ball)...and am to do this WITHOUT cribbing code...just need to understand what's going on.

 

ugh. I feel like i'm right on the edge of understanding, and that's always the most frustrating place to be :P :)

 

-Thom

Link to comment
Share on other sites

If you are running out of time in HBLANK then here is two approaches:

 

1) Prep everything you can in spare time elsewhere in the kernel, and then stuff the registers quickly in HBLANK. This might mean using a few more temp registers but that's okay.

2) Have two kernels in the case for one of the objects (your choice). Split the screen in half vertically, if the object is on the leftside update it before HBLANK starts, on the far right side of the screen. If the object is on the right side update it after HBLANK, before you reach the right side of the screen.

 

I have used both approaches in the past to solve kernel timing, and in some cases had to do a hybrid of both to get it done.

 

Other than that, there are other techniques for drawing objects. For example:

 

lda (player0Gfx),Y

and (playerDraw),Y

sta GRP0

 

That only takes 13 cycles to draw a player, provided your pointers aren't crossing over a page (+1 cycle penalty for each of those). The consequence is you must have a huge table for playerDraw, which is mostly comprised of 0's.

Link to comment
Share on other sites

Is player1 being updated on every scan line?

 

If so then turning on VDELP0 and VDELBL can prove to be very handy as they make it so you can update GRP0 and ENABL during the visible portion of the prior scan line as those updates are delayed until GRP1 is written to.

 

http://atariage.com/forums/blog/148/entry-10890-slick-kernel/

Link to comment
Share on other sites

I really...need to fuck around with VDELP0/P1/BL... I feel like I'm really missing how these registers work.... I feel so silly, seriously...how long did it take you guys to get a serious grip on writing kernels? I've been at this specific project since May (having never ever done a VCS title before), and I feel like I'm progressing...very....slowly....

 

am I just being too hard on myself?

 

My end goal is to do something that looks like the earliest launch titles (playfield updated every four lines), with the ability to position the players, missiles, and ball on each line...I thought this would be easier, because I'm not doing any weird VCS pet tricks...but... I guess I was a bit naive.

 

sigh.

 

-Thom

Link to comment
Share on other sites

Well, I've managed to get a bit closer, all the objects are on screen, no fun house mirror action happening, and the only rippling is with the PF....

 
KERNloop:
        LDX #ENABL              ; 2
        TXS                     ; 2
 
        LDA PLAYERY0
        SBC SCANLINE
        AND #$FE
        TAX
        AND #$F0
        BEQ VdoP0
        LDA #$00
        BEQ VnoP0
VdoP0:  LDA GRP,X
VnoP0:  STA WSYNC
        STA GRP0
 
        LDA SCANLINE            ; 3     3
        EOR BALLY2              ; 3     6
        AND #$FE                ; 2     8
        PHP                     ; 3     11
 
        LDA SCANLINE            ; 3
        LSR                     ; 2
        LSR                     ; 2
        LSR                     ; 2
        SEC
        SBC #$06                ; 2
        TAY                     ; 2
        STA TEMP
 
        INC SCANLINE
 
        LDA PF0_0,Y             ; 4     4
        STA PF0                 ; 3     7
        LDA PF1_0,Y             ; 4     11
        STA PF1                 ; 3     14
        LDA PF2_0,Y             ; 4     18
        STA PF2                 ; 3     21
 
        LDA PLAYERY1
        SBC SCANLINE
        AND #$FE
        TAX
        AND #$F0
        BEQ VdoP1
        LDA #$00
        BEQ VnoP1
VdoP1:  LDA GRP,X
VnoP1:
        STA GRP1
 
        LDA SCANLINE            ; 3     3
        EOR BALLY1              ; 3     6
        AND #$FE                ; 2     8
        PHP                     ; 3     11
 
        LDA SCANLINE            ; 3     3
        EOR BALLY0              ; 3     6
        AND #$FE                ; 2     8
        PHP                     ; 3     11
 
        INC SCANLINE            ; 5
        LDA SCANLINE            ; 3
        CMP #232                ; 2
        BCC KERNloop            ; 3
-Thom

dodgeball.asm

Link to comment
Share on other sites

Start counting from the WSYNC. Your cycle time listed is incorrect. PF writes are happening too late for all of them. To fix this, you could start calculating the value for Y in the available time someplace before WSYNC (there's 11 cycles remaining). Also, keep in mind that PF1 and PF2 writes can actually happen during the visible scanline with no consequence. PF1 needs to be written at cycle 27 or earlier, PF2 at cycle 38 or earlier.

 

KERNloop: ;39
LDX #ENABL ; 2 41
TXS ; 2 43
LDA PLAYERY0 ; 3 46
SBC SCANLINE ; 3 49
AND #$FE ; 2 51
TAX ; 2 53
AND #$F0 ; 2 55
BEQ VdoP0 ; 2 57
LDA #$00 ; 2 59
BEQ VnoP0 ; 3 jmp 62

VdoP0: ;58
LDA GRP,X ; 4 62
VnoP0: ;62
STA WSYNC ; 3
STA GRP0 ; 3 3
LDA SCANLINE ; 3 6
EOR BALLY2 ; 3 9
AND #$FE ; 2 11
PHP ; 3 14
LDA SCANLINE ; 3 17
LSR ; 2 19
LSR ; 2 21
LSR ; 2 23
SEC ; 2 25
SBC #$06 ; 2 27
TAY ; 2 29
STA TEMP ; 3 32
INC SCANLINE ; 5 37
LDA PF0_0,Y ; 4 41
STA PF0 ; 3 44
LDA PF1_0,Y ; 4 48
STA PF1 ; 3 51
LDA PF2_0,Y ; 4 55
STA PF2 ; 3 58
LDA PLAYERY1 ; 3 61
SBC SCANLINE ; 3 64
AND #$FE ; 2 66
TAX ; 2 68
AND #$F0 ; 2 70
BEQ VdoP1 ; 2 72
LDA #$00 ; 2 74
BEQ VnoP1 ; 3 jmp 01

VdoP1: ;73
LDA GRP,X ; 4 01
VnoP1: ;01
STA GRP1 ; 3 04
LDA SCANLINE ; 3 07
EOR BALLY1 ; 3 10
AND #$FE ; 2 12
PHP ; 3 15
LDA SCANLINE ; 3 18
EOR BALLY0 ; 3 21
AND #$FE ; 2 23
PHP ; 3 26
INC SCANLINE ; 5 31
LDA SCANLINE ; 3 34
CMP #232 ; 2 36
BCC KERNloop ; 2 38

 

Link to comment
Share on other sites

Try this...you can use X most of the time to hold the scanline count, Y for PF can be used for other purposes after playfield has been written - also 4 cycles saved by subtracting 6 from the PF data reads (locate tables at least 6 bytes from any page breaks).

 

KERNloop: ;33
LDX #ENABL ; 2 35
TXS ; 2 37
LDA SCANLINE ; 3 40
LSR ; 2 42
LSR ; 2 44
LSR ; 2 46
TAY ; 2 48 used for PF
LDA PLAYERY0 ; 3 51
SBC SCANLINE ; 3 54
AND #$FE ; 2 56
TAX ; 2 58
AND #$F0 ; 2 60
BEQ VdoP0 ; 2 62
LDA #$00 ; 2 64
BEQ VnoP0 ; 3 jmp 67

VdoP0: ;63
LDA GRP,X ; 4 67
VnoP0: ;67
;X register not needed for awhile,
;use it for the scanline value...
LDX SCANLINE ; 3 70
STA WSYNC ; 3
STA GRP0 ; 3 3
TXA ; 2 5
EOR BALLY2 ; 3 8
AND #$FE ; 2 10
PHP ; 3 13
LDA PF0_0-6,Y ; 4 17
STA PF0 ; 3 20
LDA PF1_0-6,Y ; 4 24
STA PF1 ; 3 27
LDA PF2_0-6,Y ; 4 31
STA PF2 ; 3 34
STY TEMP ; 3 37
INX ; 2 39 bump scanline
LDA PLAYERY1 ; 3 42
SBC SCANLINE ; 3 45
AND #$FE ; 2 47
TAY ; 2 49 use Y instead
AND #$F0 ; 2 51
BEQ VdoP1 ; 2 53
LDA #$00 ; 2 55
BEQ VnoP1 ; 3 jmp 58

VdoP1: ;54
LDA GRP,Y ; 4 58
VnoP1: ;58
STA WSYNC ; 3
STA GRP1 ; 3 03
TXA ; 2 05 scanline
EOR BALLY1 ; 3 08
AND #$FE ; 2 10
PHP ; 3 13
TXA ; 2 15 scanline
EOR BALLY0 ; 3 18
AND #$FE ; 2 20
PHP ; 3 23
INX ; 2 25 bump scanline
STX SCANLINE ; 3 28 store for later
CPX #232 ; 2 30
BCC KERNloop ; 2 32
Link to comment
Share on other sites

In a kernel, cycle counts are usually referred to the start of the scanline to know exactly where you can update TIA registers. since strobing WSYNC halts the CPU till the start of the next line, that's where you start you counts from. (nothing stops you from using a differernt position as '0', though, if it makes more sense in a specific kernel).

Note that in complex kernels you might not use WSYNC at all (Probably only Boulder Dash does that) and just rely on careful cycle counting to keep in sync with the TIA.

That's an extreme case, and you still have to strobe WSYNC at least once outside the kernel to start counting when the electron beam in the CRT (or it's emulation in a digital display) is in a known position.

Edit:

Corrected the post as I previously wrote VSYNC instead of WSYNC. Thanks enthusi (see post below) for pointing this out!.

Edited by alex_79
Link to comment
Share on other sites

Nifty! I need to study this. Thanks! ! :)

It's just a matter of shuffling the code you already have so it does not interfere with the registers you need to write at the short windows they need to be written to. This code could be further streamlined, but it's best to work at things slowly. The accumulator is a workhorse, but don't overlook the value of the X and Y registers to save time. BTW what is TEMP used for?

 

 

Nukey & others, so when cycle counting, take the last WSYNC in the loop, and use that as the starting point when counting cycles?

Not necessarily. Any WSYNC is just a point where you know to begin counting from zero...so it's easy to follow the number of cycles taken onward. As your kernel grows in complexity, you may find it necessary to abandon WSYNC writes oocasionally to pick up additional cycles.

Link to comment
Share on other sites

It's just a matter of shuffling the code you already have so it does not interfere with the registers you need to write at the short windows they need to be written to. This code could be further streamlined, but it's best to work at things slowly. The accumulator is a workhorse, but don't overlook the value of the X and Y registers to save time. BTW what is TEMP used for?

 

 

Not necessarily. Any WSYNC is just a point where you know to begin counting from zero...so it's easy to follow the number of cycles taken onward. As your kernel grows in complexity, you may find it necessary to abandon WSYNC writes oocasionally to pick up additional cycles.

 

Temp was an attempt to try to break things up into calculation and write phases.

 

And yeah, I see why you would need to abandon wsync cycles, the hardware simply does the HBLANK if you go over 76.

 

I can see that this is one of those arts that you just have to keep doing over and over to really truly understand.

 

-Thom

Link to comment
Share on other sites

Note that in complex kernels you might not use WSYNC at all (Probably only Boulder Dash does that)

That happens quite a bit, even in the simple kernel used in my Collect tutorial. From step 12:

 

One thing to notice about the revised 2LK is the 1st line uses exactly 76 cycles, so it no longer ends with a sta WSYNC.

Link to comment
Share on other sites

Note that in complex kernels you might not use WSYNC at all (Probably only Boulder Dash does that) and just rely on careful cycle counting to keep in sync with the TIA.

 

... and here it is!

    NEW_ROM_BANK ROM_SHADOW_KERNEL, "ROM_SHADOW_KERNEL", ROM_SEG_0

    DEFINE_SHADOW_RAM_BANK SHADOW_MAIN_KERNEL, "SHADOW_MAIN_KERNEL", RAM_SEG_0

DrawTheScreen SUBROUTINE

    ; Thomas Jentzsch strikes again.  And Andrew Davie too 
    ; A refactor of the kernel to improve the timing.
    ; TODO: use GRP1 and COLUP1 for higher resolution Rockford
    ; 15.07.2014: reverted to single kernel/bank since it simplyfies PF draws

.scanBLUE                                               ; 5         @61
        bpl     .scanBLUECont                           ; 3 =  3    @64     unconditional

.scanRED                                                ;           @60
SM_PF0_REDl
        lda     CHARACTERSHAPE_BLANK,y                  ; 4
        sta     PF0                                     ; 3         @67
        lda     ScreenBitmapRED   +0*LINES_PER_CHAR,y   ; 4
        sta     PF1                                     ; 3 = 14    @74
SELFMOD_PLAYERCOL_RED
        lda     SpriteColourRED,y                       ; 4
        sta     COLUP0                                  ; 3         @05
        sta     COLUP1                                  ; 3 = 10    @08
SELFMOD_RED
        lda     #0                                      ; 2
        sta     COLUPF                                  ; 3 =  5    @13
SELFMOD_PLAYER0_RED
        lda     ShapePlayerRED,y                        ; 4
        sta     GRP0                                    ; 3 =  7    @20

        lda     ScreenBitmapRED   +1*LINES_PER_CHAR,y   ; 4
        sta     PF2                                     ; 3 =  7    @27
SM_PF0_REDr
        lda     CHARACTERSHAPE_BLANK,y                  ; 4
        sta     PF0                                     ; 3         @34
        lda     ScreenBitmapRED   +2*LINES_PER_CHAR,y   ; 4
        sta     PF1                                     ; 3         @41
        lda     ScreenBitmapRED   +3*LINES_PER_CHAR,y   ; 4
        sta     PF2                                     ; 3 = 21    @48     must be >=48! :-)
SELFMOD_PLAYER1_RED
        lda     ShapePlayerRED,y                        ; 4
        sta.w   GRP1                                    ; 4 =  8    @56     VDELed!
        dey                                             ; 2
        bpl     .scanBLUE                               ; 2/3       --> 61 if taken
SELFMOD_X                                                   ;                   EXIT_RETURN_HERE
        inx                                             ; 2
;        ldx #0                                          ; 2                 TODO: fast vertical scrolling

    DEFINE_SUBROUTINE DrawTheScreenEntry                ;           @62     kernel entry point

        ldy     #LINES_PER_CHAR/3-1                     ; 2
.scanBLUECont                                           ;           @64
        STX_RAM_BANK                                    ; 3         @67     SWITCH TO CORRECT ROW BANK (OR EXIT BANK)

    ;------------------------------------------------------------------------------
SM_PF0_BLUEl
        lda     CHARACTERSHAPE_BLANK,y                  ; 4
        sta     PF0                                     ; 3 =  7    @74
SELFMOD_PLAYERCOL_BLUE
        lda     SpriteColourBLUE,y                      ; 4
        sta     COLUP1                                  ; 3         @05
        sta     COLUP0                                  ; 3 = 10    @08
SELFMOD_BLUE
        lda     #0                                      ; 2
        sta     COLUPF                                  ; 3 =  5    @13
SELFMOD_PLAYER0_BLUE
        lda     ShapePlayerBLUE,y                       ; 4
        sta     GRP0                                    ; 3 =  7    @20

        lda     ScreenBitmapBLUE   +0*LINES_PER_CHAR,y  ; 4
        sta     PF1                                     ; 3         @27     <=27! :-)
        lda     ScreenBitmapBLUE   +1*LINES_PER_CHAR,y  ; 4
        sta     PF2                                     ; 3 = 14    @34
SM_PF0_BLUEr
        lda     CHARACTERSHAPE_BLANK,y                  ; 4
        sta     PF0                                     ; 3         @41
        lda     ScreenBitmapBLUE   +2*LINES_PER_CHAR,y  ; 4
        sta     PF1                                     ; 3         @48
        lda     ScreenBitmapBLUE   +3*LINES_PER_CHAR,y  ; 4
        sta     PF2                                     ; 3 = 21    @55
SELFMOD_PLAYER1_BLUE
        lda     ShapePlayerBLUE,y                       ; 4
        sta     GRP1                                    ; 3 =  7    @62     VDELed!
    ;------------------------------------------------------------------------------
; scan GREEN                                            ;           @62
SM_PF0_GREENl
        lda     CHARACTERSHAPE_BLANK,y                  ; 4
        sta     PF0                                     ; 3 =  7    @69
SELFMOD_PLAYERCOL_GREEN
        lda     SpriteColourGREEN,y                     ; 4
        sta     COLUP1                                  ; 3         @00
        sta     COLUP0                                  ; 3 = 10    @03
SELFMOD_GREEN
        lda     #0                                      ; 2
        sta     COLUPF                                  ; 3 =  5    @08
SELFMOD_PLAYER0_GREEN
        lda     ShapePlayerGREEN,y                      ; 4
        sta     GRP0                                    ; 3 =  7    @15

        lda     ScreenBitmapGREEN   +0*LINES_PER_CHAR,y ; 4
        sta     PF1                                     ; 3         @22
        lda     ScreenBitmapGREEN   +1*LINES_PER_CHAR,y ; 4
        sta     PF2                                     ; 3 = 14    @29
SM_PF0_GREENr
        lda     CHARACTERSHAPE_BLANK,y                  ; 4
        sta     PF0                                     ; 3         @36
        lda     ScreenBitmapGREEN   +2*LINES_PER_CHAR,y ; 4
        sta     PF1                                     ; 3         @43
        lda     ScreenBitmapGREEN   +3*LINES_PER_CHAR,y ; 4
        sta     PF2                                     ; 3 = 21    @50
SELFMOD_PLAYER1_GREEN
        lda     ShapePlayerGREEN,y                      ; 4
        sta     GRP1                                    ; 3 =  7    @57     VDELed!
        jmp     .scanRED                                ; 3         @60


    OPTIONAL_PAGEBREAK "SCREEN_BITMAP", SCREEN_BITMAP_SIZE

ScreenBitmap        ds SCREEN_BITMAP_SIZE,$0         ; character bitmap row (10 chars wide)
ScreenBitmapRED     = ScreenBitmap + NUM_PF_COLOR_GROUPS*0
ScreenBitmapGREEN   = ScreenBitmap + NUM_PF_COLOR_GROUPS*1
ScreenBitmapBLUE    = ScreenBitmap + NUM_PF_COLOR_GROUPS*2

ShapePlayer         = PLAYER_BLANK
ShapePlayerBLUE     = ShapePlayer   ; low adresses patched
ShapePlayerGREEN    = ShapePlayer   ; low adresses patched
ShapePlayerRED      = ShapePlayer   ; low adresses patched

    END_SHADOW_RAM_BANK ; SHADOW_MAIN_KERNEL

  • Like 3
Link to comment
Share on other sites

 

 

... and here it is!

 

 

I don't see a single WSYNC Andrew, does one of the other Kernel modules hold it that renders the next line?

 

I pulled one WSYNC out of the two line Kernel for large virtual worlds, but the WSYNC at the end of the second line remains - none of the lines in your Kernel calls the WSYNC function?

Link to comment
Share on other sites

 

I don't see a single WSYNC Andrew, does one of the other Kernel modules hold it that renders the next line?

 

I pulled one WSYNC out of the two line Kernel for large virtual worlds, but the WSYNC at the end of the second line remains - none of the lines in your Kernel calls the WSYNC function?

 

They've got other amazing things in their too. From what little I understand they put in task scheduling so if a particular action would go over-cycle it's delayed until next frame. O_O

Link to comment
Share on other sites

 

I don't see a single WSYNC Andrew, does one of the other Kernel modules hold it that renders the next line?

 

I pulled one WSYNC out of the two line Kernel for large virtual worlds, but the WSYNC at the end of the second line remains - none of the lines in your Kernel calls the WSYNC function?

 

That section shows the basic triplet colour lines being drawn, 21 scanlines by 8 character rows (total 168 scanlines) being drawn and no, there are no WSYNC for the whole kernel at this stage of the frame draw. There's a bit of bank magic happening; the same code resides in different banks, and the final bank has a difference: a RTS which lets the draw 'break out' of the loop. It means that there is no comparison needed for a loop counter as to how many character lines to draw. It just automatically finishes when it switches to the bank with the RTS. Neat :)

  • Like 2
Link to comment
Share on other sites

 

They've got other amazing things in their too. From what little I understand they put in task scheduling so if a particular action would go over-cycle it's delayed until next frame. O_O

 

Close. The delay is until the next bit of free time *within a frame*. A frame has a few places where stuff can be done (i.e., where it's using an INTIM wait). Each task has a known-time-to-complete, so the INTIM counter is used to determine if there's time enough to do that action. If not, then other actions which are less time consuming may or may not be executed instead, and the longer one will get a "look-in" ASAP when there's time to accomodate its needs.

  • Like 2
Link to comment
Share on other sites

 

That section shows the basic triplet colour lines being drawn, 21 scanlines by 8 character rows (total 168 scanlines) being drawn and no, there are no WSYNC for the whole kernel at this stage of the frame draw. There's a bit of bank magic happening; the same code resides in different banks, and the final bank has a difference: a RTS which lets the draw 'break out' of the loop. It means that there is no comparison needed for a loop counter as to how many character lines to draw. It just automatically finishes when it switches to the bank with the RTS. Neat :)

Pretty cool! :)

 

That 168 scanline block is most of the screen, where else do you find time for the task queue besides the top and bottom vertical blanks?

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...