News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
F

Horizontal scrolling, scoreboards and CRTC. [SOLVED]

Started by FatAgnus, 00:39, 31 March 11

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

FatAgnus

I don't know where I'm wrong or confused, but I'm very wrong:
Coding an interrupt routine to handle a very symple split for my scoreboard (1 char tall) under the scroll zone (22 chars tall).
As long as horizontal timings are unmodified, we must maintain a "global" VTOT  of 39 char lines, so: 22+17 (Vtot1=21, Vtot2=16) is this correct or not? (I know I'm wrong)
Please, I'm not asking about how to optimize it, this is only a skeleton-workbench for testings:
.INTCOUNT defb 0
.INT_VECTOR
push bc:push af
ld b,&f5:in a,(c):rra
ld a,(INTCOUNT):inc a
jr nc,noreset
xor a
.noreset
ld (INTCOUNT),a
cp 0:jp z,INT0
cp 1:jp z,INT1
cp 2:jp z,INT2
cp 3:jp z,INT3
cp 4:jp z,INT4
cp 5:jp z,INT5
;;ERROR: OUT OF SYNC EXIT!
pop af:pop bc:ei:ret
.INT0
ld bc,&bc07:out(c),c:ld bc,&bd00+255::out (c),c   ;;VSYNCPOS OVERFLOW
call set_scroll_ptr                                    ;;R3 R12 R13 for scrolling zone
pop af:pop bc:ei:ret
.INT1
ld bc,&bc04:out(c),c:ld bc,&bd00+22-1:out(c),c      ;;VTOT SCROLL
ld bc,&bc06:out(c),c:ld bc,&bd00+22::out(c),c           ;;VDISP SCROLL
pop af:pop bc:ei:ret
.INT2
pop af:pop bc:ei:ret
.INT3
call set_scoreboard_ptr                         ;;R12 R13 for scoreboard
pop af:pop bc:ei:ret
.INT4
ld bc,&bc04:out(c),c:ld bc,&bd00+17+0-1:out(c),c  ;;VTOT SCOREBOARD+BORDERS <<< +0/+4 LINE!
ld bc,&bc06:out(c),c:ld bc,&bd00+1::out(c),c           ;;VDISP SCOREBOARD
ld bc,&bc07:out(c),c:ld bc,&bd00+10::out (c),c   ;;VSYNCPOS
pop af:pop bc:ei:ret
.INT5
pop af:pop bc:ei:ret


Ok... this result in a scrolling zone with  4 char-rows lost!
But if I add +4 instead +0 (INT4 block) then it works nice! (BUT ONLY ON CRTC 1 and CRTC 3)
Please, WHERE AM I WRONG? WHICH CONCEPT I DON'T UNDERSTAND?
EDIT: After dummy tests, (+0+4) AND (+1+3) are fake-working combinations with CRTC 1-3, while (+2+2),(+3+1) eats the 4 rows again...

CRTC 1-3 AND "+4" (all char rows seems to be right)



ALL CRTC AND "+0" (four char rows lost at scroll bottom)

arnoldemu

Quote from: FatAgnus on 00:39, 31 March 11
I don't know where I'm wrong or confused, but I'm very wrong:
Coding an interrupt routine to handle a very symple split for my scoreboard (1 char tall) under the scroll zone (22 chars tall).
As long as horizontal timings are unmodified, we must maintain a "global" VTOT  of 39 char lines, so: 22+17 (Vtot1=21, Vtot2=16) is this correct or not? (I know I'm wrong)
Please, I'm not asking about how to optimize it, this is only a skeleton-workbench for testings:
.INTCOUNT defb 0
.INT_VECTOR
push bc:push af
ld b,&f5:in a,(c):rra
ld a,(INTCOUNT):inc a
jr nc,noreset
xor a
.noreset
ld (INTCOUNT),a
cp 0:jp z,INT0
cp 1:jp z,INT1
cp 2:jp z,INT2
cp 3:jp z,INT3
cp 4:jp z,INT4
cp 5:jp z,INT5
;;ERROR: OUT OF SYNC EXIT!
pop af:pop bc:ei:ret
.INT0
ld bc,&bc07:out(c),c:ld bc,&bd00+255::out (c),c   ;;VSYNCPOS OVERFLOW
call set_scroll_ptr                                    ;;R3 R12 R13 for scrolling zone
pop af:pop bc:ei:ret
.INT1
ld bc,&bc04:out(c),c:ld bc,&bd00+22-1:out(c),c      ;;VTOT SCROLL
ld bc,&bc06:out(c),c:ld bc,&bd00+22::out(c),c           ;;VDISP SCROLL
pop af:pop bc:ei:ret
.INT2
pop af:pop bc:ei:ret
.INT3
call set_scoreboard_ptr                         ;;R12 R13 for scoreboard
pop af:pop bc:ei:ret
.INT4
ld bc,&bc04:out(c),c:ld bc,&bd00+17+0-1:out(c),c  ;;VTOT SCOREBOARD+BORDERS <<< +0/+4 LINE!
ld bc,&bc06:out(c),c:ld bc,&bd00+1::out(c),c           ;;VDISP SCOREBOARD
ld bc,&bc07:out(c),c:ld bc,&bd00+10::out (c),c   ;;VSYNCPOS
pop af:pop bc:ei:ret
.INT5
pop af:pop bc:ei:ret


Ok... this result in a scrolling zone with  4 char-rows lost!
But if I add +4 instead +0 (INT4 block) then it works nice! (BUT ONLY ON CRTC 1 and CRTC 3)
Please, WHERE AM I WRONG? WHICH CONCEPT I DON'T UNDERSTAND?


CRTC 1-3 AND "+4" (all char rows seems to be right)



ALL CRTC AND "+0" (four char rows lost at scroll bottom)

I've not analysed the code yet, but it may be down to one of those crtc differences.
(To analyse it I would need to run it in an emu, and look at the vertical count, horizontal count and raster count to know if you've changed something "in the margins" of the timings).

So you'll possibly need to detect crtc and adjust your code to work with it.
It is the same with a lot of demos, detect crtc and modify code.

Offset's crtc testing code is the best if you need to do this.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

FatAgnus

This is a very simply task, I know a few CRTC differences implied... but "HALTED" versions of another coders works fine over all CRTC without further checks.
I'm doing things bad for sure (some knowledges badly adquired), but, after two days, I don't know where I'm wrong.


(Plz excuse my english, this is like a "TARZAN" movie  :laugh: )

arnoldemu

Quote from: FatAgnus on 09:33, 31 March 11
This is a very simply task, I know a few CRTC differences implied... but "HALTED" versions of another coders works fine over all CRTC without further checks.
I'm doing things bad for sure (some knowledges badly adquired), but, after two days, I don't know where I'm wrong.


(Plz excuse my english, this is like a "TARZAN" movie  :laugh: )
I'll take a closer look later.

Are you wanting a 1 char height status panel at the bottom?

I ask because I have code that does this at home ( I am currently at work).
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

FatAgnus

Yes.
But I need to understand WHY "I don't undestand this hardware trick well". If READING your code helps, nice...
but cut&copy are ok for Arkos Tracker, not for a basic CPC feature like this, it must be self-coded, "knowing what you are doing" (this is the reason for this "learning project")


(hard to explain myself in english, hopping you get the idea)


arnoldemu

Quote from: FatAgnus on 09:44, 31 March 11
Yes.
But I need to understand WHY "I don't undestand this hardware trick well". If READING your code helps, nice...
but cut&copy are ok for Arkos Tracker, not for a basic CPC feature like this, it must be self-coded, "knowing what you are doing" (this is the reason for this "learning project")


(hard to explain myself in english, hopping you get the idea)
Yes I understand. I will try and write an analysis of the code, but give me some time to do this.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

FatAgnus

#6
WEIRD! Today winApe plays well "+4" WITH EVERY CRTC!
MORE WEIRD! Arkos plays with "+4" slightly slowly, but not distorted, only a bit slowly (not as much as you can notice in a typical "50fps to 25fps falldown" - Arkos is called manually, assembled without user friendly/interrupts options, of course-).
I'm getting crazy.

EDIT: uhhhhmmmm... with "clock in hand over emulator", +0 does "perfect" 14 secs of scroll, and +4 does 16 secs. Theoretic time is EXACTLY 14 secs, so +0 displays bad but syncs well, and +4 displays well but syncs bad (2 secs more than expected)

arnoldemu

Quote from: FatAgnus on 11:13, 31 March 11
WEIRD! Today winApe plays well "+4" WITH EVERY CRTC!
MORE WEIRD! Arkos plays with "+4" slightly slowly, but not distorted, only a bit slowly (not as much as you can notice in a typical "50fps to 25fps falldown" - Arkos is called manually, assembled without user friendly/interrupts options, of course-).

But both +4 +0 gives 12 secs of  total scroll time when "running" from left to right map limits
I'm getting crazy.

Hint: Don't rely on emulators ;)
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

Timings added

.INT_VECTOR
push bc:push af                ;; [4], [4]
ld b,&f5:in a,(c):rra        ;; [2], [4], [1]
ld a,(INTCOUNT):inc a        ;; [3], [1]
jr nc,noreset                ;; [3]
xor a   
.noreset               
ld (INTCOUNT),a                ;; [3] = [25]
....

NOTE: I may have got some timings wrong, they are from memory, and my calculations may not be 100%, but if you understand
the analysis I did, this will help you to understand and solve your problems.

In the end, it's all about timing, not just CRTC, but Z80 and interrupt timing.


Long analysis:

First lets think about the interrupts.

The first interrupt is synchronised so that it occurs 2 HSYNCs after the START of the VSYNC signal
from the CRTC.

The time between each interrupt is 52 HSYNCs, which with standard R0 values, means, 52 scanlines.

So the interrupt  positions relative to start of vsync (in lines):

2
54
106
158
210
262

+52 (=314, -312 for height of frame = 2 - exactly 2 HSYNCs from the beginning of VSYNC).

About the HSYNC position because this effects interrupt timing:

HSYNCPOS = R2 = 46

HSYNCWIDTH = &86 or &85 (depends on scroll)

Hsync ends: 46+5 = 51, or 46+6 = 52

When Hsync ends, interrupt request will trigger, then you have 1 NOP for acknowledge, 4 or so for RST (jump to &0038),
then your code takes at least another 25 to get to where you do the outs.

So, taking this into account, your interrupt comes on the next raster line after the hsync has begun.
Using 25 as the base: 51+25-64 = 12 NOPs into the next line, or 12 chars horizontally. (HCC=12).
The timing varies because you do CP before you do our OUTs.

So *this* is important.

These are my namings for the following explanation:

VCC = internal char line counter in CRTC (goes up to R4 and resets back to 0)
RC = internal scanline counter within CRTC (goes up to R9 and resets back to 0)
HC = horizontal char counter within CRTC (goes up to R0 and resets back to 0)

so working from your code:

Your R7 (at int4  is set to 10), this and R4 decide the frames timing.
This means VSYNC will trigger on char line 10 (VCC=10, RC = 0).

(.INT4
ld bc,&bc04:out(c),c:ld bc,&bd00+17+0-1:out(c),c  ;;VTOT SCOREBOARD+BORDERS <<< +0/+4 LINE!
ld bc,&bc06:out(c),c:ld bc,&bd00+1::out(c),c           ;;VDISP SCOREBOARD
ld bc,&bc07:out(c),c:ld bc,&bd00+10::out (c),c   ;;VSYNCPOS
)

(R6 doesn't effect timing here)

So  the first interrupt, when vsync occurs, will be at VCC=10, RC=1, HC=HSYNCPOS+HSYNCLEN.
(First HSYNC was seen at VCC=10, RC=0, HC=HSYNCPOS).

After int acknowledge and some instructions, your OUT code will then trigger approx. on RC=2, HCC=12, VCC=10.

You see vsync, then set R7 to &FF to stop vsync.

You have R4 set to 16. Frame will end when VCC=16, RC=7.

So this means 6 char lines (and 7 scanlines) after this interrupt (55 scanlines total),
the CRTC "frame" will end, R4 will reset to 0, no VSYNC will occur.

When will the next interrupt trigger (after VCC=10, RC=1 position)?

52 hsyncs later (6 char lines and 4 scanlines later).

So next interrupt will occur when VCC=16, RC=5, HC=HSYNCPOS+HSYNCLEN.
You will see this when VCC=16, RC=6, HC=12.

CRTC "frame" is not over yet, it has 1 scanline left to run.
Your code probably triggers when RC=7 or so.

Now, you've got to one of those problem cases.

Some CRTCs will "latch" or remember RC=R9, VCC=R4, and you can then change any values safely and they will end the frame.
Others will not, and they will allow you to change R4 and they will continue to count.

So first recommendation:

delay this:

ld bc,&bc04:out(c),c:ld bc,&bd00+22-1:out(c),c      ;;VTOT SCROLL

add some more nops!
You want to set R4, when it has finished the current "frame" (e.g VCC resets back to 0).
*AND* you need to set the value before R=16 (your previous value) *AND* before the new value you want.
The safest is normally when VCC=0.

Do this and it'll work even with type 2.


My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

FatAgnus

#9
Still working on it (I need to understand perfectly all this dammed thing before continuing my pseudogame)


BUT, I assumed that all CRTC types ALWAYS CACHED INTERNALLY the values of R4! I only expected issues when modifiying R12-R13 
I can't be so much dependent of time while changing R4 value (the rest of the game don't allow me)


So this is the hardest and useless head-ache in two months of project!
(...useless for the game, but not as learning process...)

EDIT: after fixing this mess, I will reach to another problem: R9=0 is not valid for CRTC type 1 (thanks Syx for your advice!), so "filling" the scoreboard with linear-framebuffers will not be easy!
The accumulated lost of time will be too much for this game, so a different solution for lives-energy is a demand (the current one is ugly)


PS delays didn't work, but I understand what you are explaining.

arnoldemu

Quote from: FatAgnus on 13:49, 31 March 11
Still working on it (I need to understand perfectly all this dammed thing before continuing my pseudogame)


BUT, I assumed that all CRTC types ALWAYS CACHED INTERNALLY the values of R4! I only expected issues when modifiying R12-R13 
I can't be so much dependent of time while changing R4 value (the rest of the game don't allow me)


So the hardest and useless head-ache of this two months of project!
(...useless for the game, but not as learning process...)


PS delays didn't work, but I understand what you are explaining.
I am pleased you understand what i was writing, it really will help you to understand when things are happening and to understand how it all works together.

The values of the CRTC's registers are stored.

It's more the result of internal comparisons may not be stored.
e.g.
VCC=R4 comparison result may be stored on one crtc type, but not another.

The CRTC has some counters which I name VCC, HCC, RC, VSYNCCNT, HSYNCCNT. These increment and are compared with the current values of the registers.
VCC = Vertical char counter, compared with R4 (R7 to signal start of vsync, r6 to signal start of border).
HCC = horizontal char counter, compared with R0 (R2 to signal start of HSYNC, and R1 to signal start of border).
VSYNCCNT = vertical sync scanline counter, compared with R3 upper 4 bits.
HSYNCCNT = horizontal sync scanline counter, compared with R3 lower 4 bits.
RC = raster counter, compared with R9.

EDIT: I will explain one difference (it is an example to show how crtcs can be different):

On crtc type 0, type 2, type 3 and type 4 you must change R12, R13 before next CRTC frame begins for it to work.
On crtc type *1*, you can change R12,R13 at anytime when VCC=0 and it works!
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

#11
This is my code that does it, perhaps it may help.
I don't understand fully your last post, please can you describe it another way?


org &4000
nolist

start:
;; standard screen is 39 chars tall and vsync at 30
;; with 25 chars displayed
;;
;; we want to change this to 26 chars displayed with vsync at 31
;;
;; Char Lines to end of screen: 39-31 = 8
;; Scan Lines to end of screen: 8*8 = 64
;; Interrupt occurs two lines after VSYNC, so lines until end of screen when interrupt occurs: 64-2 = 62
;;
;; If we then wait for one interrupt, we will be 10 (62-52 = 10) lines into the next screen.
;;
;; Then interrupts are:
;; 10, 62, 114, 166, 218
;;
;; And we will then be 10 lines into second screen.


di
ld bc,&7f10
out (c),c
ld bc,&7f54
out (c),c

;; set new vsync we want
ld bc,&bc07
out (c),c
ld bc,&bd00+31
out (c),c

;; wait for 2 vsyncs to allow it to stabalise and so that we can sync with that
ld e,2
wait_two_vsyncs:
ld b,&f5
wait_vsync_end:
in a,(c)
rra
jr c,wait_vsync_end
wait_vsync_start:
in a,(c)
rra
jr nc,wait_vsync_start
dec e
jp nz,wait_two_vsyncs

;; synchronised with start of vsync and we are synchronised with CRTC too, and we have the
;; same number of lines to next screen as we want.

;; set initial interrupt routine
ld hl,int_rout1
ld (int_rout_ptr+1),hl

;; set interrupt
ld a,&c3
ld hl,int_start
ld (&0038),a
ld (&0039),hl
;; enable
ei

main_loop:
ld b,&f5
vsync:
in a,(c)
rra
jr nc,vsync

halt

jp main_loop

;;---------

int_start:
push bc
push hl
int_rout_ptr:
jp int_rout1


;;---------
;; first interrupt after vsync
int_rout1:
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f4b
;;out (c),c

;; set vsync position to turn it off
ld bc,&bc07
out (c),c
ld bc,&bdff
out (c),c

;; screen address for main part of screen
;; will not trigger until screen restarts
ld bc,&bc0c
out (c),c
ld bc,&bd00+&30
out (c),c

ld bc,&bc0d
out (c),c
ld bc,&bd00
out (c),c

;; set height of main part of screen
;; since we are already past the end of the previous screen
;; this will take no effect.
ld bc,&bc06
out (c),c
ld bc,&bd00+25
out (c),c

ld hl,int_rout2
jp int_end

;;---------
int_rout2:
;; 10 lines until end of screen
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f43
;;out (c),c

ld hl,int_rout3
jp int_end

;;---------
int_rout3:
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f42
;;out (c),c

;; now at line 42.
ld bc,&bc04
out (c),c
ld bc,&bd00+25-1
out (c),c


ld hl,int_rout4
jp int_end

;;---------
int_rout4:

;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f40
;;out (c),c


ld hl,int_rout5
jp int_end

;;---------
int_rout5:

;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f49
;;out (c),c


ld bc,&bc0c
out (c),c
ld bc,&bd00+&18
out (c),c
ld bc,&bc0d
out (c),c
ld bc,&bd00
out (c),c

ld hl,int_rout6
jp int_end

;;---------
int_rout6:

;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f53
;;out (c),c

;; 2 lines before end of screen

;; 128 cycles
ld b,42
int_delay:
djnz int_delay

;; set display height of screen
ld bc,&bc06
out (c),c
ld bc,&bd00+1
out (c),c

;; set height of screen
ld bc,&bc04
out (c),c
ld bc,&bd00+14-1
out (c),c

;; set vsync position
ld bc,&bc07
out (c),c
ld bc,&bd00+6
out (c),c

ld hl,int_rout1
jp int_end

int_end:
ld (int_rout_ptr+1),hl
pop hl
pop bc
ei
ret

;;end start


EDIT: One thing I did here, was I changed the border colour when the interrupt occured, so I knew where the crtc was at that time.
I could then adjust the timings if needed to avoid problems. In fact I have a delay loop in this code to do just that.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

FatAgnus

#12
a) Thankx for your code (and your patience)


b) AT LAST! Now I got it! (I hope so!  ::) )
The "lost chars" at first block WERE 5, instead 4...22-4=18<>17, the height of second block, but 22-5=...17...
yes, VTOT(+1, of course) OF LAST BLOCK! THE VTOT VALUE WAS NOT CHANGED AS I THOUGHT!


This confused me a lot all this time!


The secuence of a working split is
after VC=VTOT1 (first block), we reach again VC=0, but R7=overflow so no interrupt is launched, and THEN and only THEN we must change R4=VTOT2 for next block. So, after chosing the nearest interruption, I still need "NOPS" until we reach the char-row when VC resets to 0.

All this time I thought that the vtot change was realized, so all concepts messed up becoming incongruent.

arnoldemu

Quote from: FatAgnus on 21:20, 31 March 11
a) Thankx for your code (and your patience)


b) AT LAST! Now I got it! (I hope so!  ::) )
The "lost chars" at first block WERE 5, instead 4...22-4=18<>17, the height of second block, but 22-5=...17...
yes, VTOT(+1, of course) OF LAST BLOCK! THE VTOT VALUE WAS NOT CHANGED AS I THOUGHT!


This confused me a lot all this time!


The secuence of a working split is
after VC=VTOT1 (first block), we reach again VC=0, but R7=overflow so no interrupt is launched, and THEN and only THEN we must change R4=VTOT2 for next block. So, after chosing the nearest interruption, I still need "NOPS" until we reach the char-row when VC resets to 0.
YES!!!!! You got it!!!!! :)

EDIT: I played your game and really enjoyed it. I am looking forward to playing the final version!
Making games can sometimes be a slow and frustrating thing, but at the end the result is always good.


My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

FatAgnus

We enjoy doing things for a lovely machine of 1984...
We love frustration!!  ;D ;D

Executioner

I don't want to upset anyone or throw a spanner in the works as it seems you already have it working, but, you shouldn't need to be very accurate at all to do a simple screen split like this. So long as you set R4 between VCC = 0 and VCC = desired R4 - 1 it will be ok (no values are cached in the CRTC).

Similarly, as explained by arnoldemu, so long as you set registers 12 and 13 between VCC=1 and VCC=R4, the next frame start address will be set for all CRTC types. R7 should only be set to the correct value after the bottom frame has started, unless the top frame is smaller than the desired position (unlikely unless you have the status at the top).

The interrupt logic should be something like:

Int 0 (Frame flyback):
R7 = #ff, R4 = 17, R6=top screen displayed (22), R12,13 = base of top screen

Int 2 (part way through scrolling screen, before VCC=17, but after VCC=0):
R4=21, R12,13=base of scoreboard

Int 3 or 4 (adjusted to be inside scoreboard (ie.after previous screen VCC=21 and before VDISP (1))):
R6=1, R7=10

For the top screen, if R6=22 and R4=21, the scoreboard will be touching the scrolling screen.

FatAgnus

Quote from: Executioner on 03:15, 01 April 11
I don't want to upset anyone or throw a spanner in the works as it seems you already have it working, but, you shouldn't need to be very accurate at all to do a simple screen split like this.
Upset? Spanner? THANXS for your interest and help.
I didn't "had it working", I DISCARTED it, because I can't be so much time-dependent.
One more chance for it with your information in mind, I really hope it works!
QuoteInt 3 or 4 (adjusted to be inside scoreboard (ie.after previous screen VCC=21 and before VDISP (1))):
R6=1, R7=10
Before testings, this part is scaring me: "adjusted to be inside scoreboard" means (for my "spiki" head) adjusted to be inside "the row displayed" of scoreboard, no more, no less... 1 char of "margin" to do the R6 change. And the game CAN, AND WILL, push down INT3-INT4 1-2 chars in some situations, so I could lost sync (if that char resolution is really needed...)
IN FEW WORDS: R6=1 IS THE CRITICAL ONE, INSTEAD R4 CHANGES?
But let me try, if it does well the job, the next thread is waiting: LINEAR FRAMEBUFFER CRTC1-COMPATIBLE WITHOUT NOPS (any chance this time?)

EDIT: Before trying to put a split into the game, I thought that INTx "resolution" was enough for R4-R6-R7-R12-R13 changes, only a matter of choosing a valid "interruption block". If  (for any of the CRTC registers-compatibility), I need "1 CHAR resolution" (scoreboard displayed=1 char), it isn't viable for me.
(I don't know if my english is enough to be readable, sorry again)

FatAgnus

Test done: first attempt, it works, it must not work! ("scoreboard" is the trash under scroll)

INT0: R7=overflow, R4=17-1, R6=22, R12&R13=scroll video memory
INT1: Empty
INT2: R4=22-1, R12&R13=scoreboard video memory *R6=1 HERE, WORKS TOO!!!??¿?¿?*
INT3: Border yellow, R6=1, R7=8-1 (for better screen-centering). *R6=1 can be raised to INT2*
INT4: Border default.
INT5: Empty
(blue, standard WinAPE int's highlight)
It seems to be steady.
It seems to work with all CRTCs
It seems to work with variable INT3 scan position (pushed by game's "di-ei" routines.
The change is done far away of the bottom of scroll zone, and far away of scoreboard start (WinAPE reports VCC values from 7 to 11, related to game's overload)
So IT WORKS, but then...
QuoteInt 3 or 4 (adjusted to be inside scoreboard (ie.after previous screen VCC=21 and before VDISP (1))):
R6=1, R7=10
... is confusing me (any news?  :laugh: ) because IT IS NOT RESPECTING THAT! CHANGES ARE DONE WITH INT3 FALLING INTO SCROLL, OUT OF SCOREBOARD!

P.S. When reaching the Big Boss scene (very very overloaded), some times, very sporadic, screen goes out of sync: BLACK SCREEN DISPLAYING ONLY THE SCOREBOARD CHAR-ROW... I don't use black for border, it seems to be a big VBL... It seems to be produced when INT1 is pushed by game too much down (reaching scroll area), fixable.

arnoldemu

Quote from: FatAgnus on 12:18, 01 April 11
Test done:

INT3: Border changed to yellow followed of R6=1 and R7=7 (for better screen-centering)
INT4: Border to default.
(blue, standard WinAPE int's highlight)
It seems to be steady.
It seems to work with all CRTCs
It seems to work with variable INT3 scan position (pushed by game's "di-ei" routines.
The change is done far away of the bottom of scroll zone, and far away of scoreboard start (WinAPE reports VCC values from 7 to 11, related to game's overload)
So IT WORKS, but then...... is confusing me (any news?  :laugh: ) because IT IS NOT RESPECTING THAT!


P.S. When reaching the Big Boss scene (very very overloaded), some times, very sporadic, screen goes out of sync: BLACK SCREEN DISPLAYING ONLY THE SCOREBOARD CHAR-ROW... I don't use black for border, it seems to be a big VBL.

do you need to use di/ei in your routines?
if you could avoid that, then it would be better.

The CPCs ints can't be any closer than 32 lines. If one is then it will push the next out of position.
So this explains why more cpu time can be used and it still works sometimes.


My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

FatAgnus

Quotedo you need to use di/ei in your routines?
if you could avoid that, then it would be better

The CPCs ints can't be any closer than 32 lines. If one is then it will push the next out of position.
So this explains why more cpu time can be used and it still works sometimes.
I don't understand arnoldemu, it works, changes are done so far away from the scoreboard itself that it "absorves" the interruption fluctuations. I discarted split because I need blocking interrupts some times, but this configuration seems to be very independent of it.
IT ALWAYS WORKS, BUT WATCHING THE "YELLOW STRIP" POSITION, I CAN'T UNDERSTAND WHY IT WORKS, I can see it moving up, moving down, shrinking, enlarging... but scoreboard's display is ok!
(eeehhhmmm..."scoreboard" is the trash under scroll)
MORE TESTS:
-) With lower R7 values (pushing scoreboard display fully into INT5, with changes still done at INT3) working perfectly.
-) With R6=1 DONE AT INT2, IT WORKS. ¿?¿??¿¿???

"TEST DONE" post edited, now showing what is done at each interruption:
QuoteTest done: first attempt, it works, it must not work! ("scoreboard" is the trash under scroll)

INT0: R7=overflow, R4=17-1, R6=22, R12&R13=scroll video memory
INT1: Empty
INT2: R4=22-1, R12&R13=scoreboard video memory *R6=1 HERE, WORKS TOO!!!??¿?¿?*
INT3: Border yellow, R6=1, R7=8-1 (for better screen-centering). *R6=1 can be raised to INT2*
INT4: Border default.
INT5: Empty
(blue, standard WinAPE int's highlight)
It seems to be steady.
It seems to work with all CRTCs
It seems to work with variable INT3 scan position (pushed by game's "di-ei" routines.
The change is done far away of the bottom of scroll zone, and far away of scoreboard start (WinAPE reports VCC values from 7 to 11, related to game's overload)
So IT WORKS, but then...
QuoteInt 3 or 4 (adjusted to be inside scoreboard (ie.after previous screen VCC=21 and before VDISP (1))):
R6=1, R7=10
... is confusing me (any news?  :laugh: ) because IT IS NOT RESPECTING THAT! CHANGES ARE DONE WITH INT3 FALLING INTO SCROLL, OUT OF SCOREBOARD!

P.S. When reaching the Big Boss scene (very very overloaded), some times, very sporadic, screen goes out of sync: BLACK SCREEN DISPLAYING ONLY THE SCOREBOARD CHAR-ROW... I don't use black for border, it seems to be a big VBL... It seems to be produced when INT1 is pushed by game too much down (reaching scroll area), fixable.

FatAgnus

OMG, this is pathetically simply...

R4(splitN) must be changed when VCC is into splitN (of course, if we want a new R4<VCC, we can't reach it!)
R6(splitN) must be changed before VCC reachs it (no matter if we are still into splitN-1 IF we are showing the "lower border" of splitN-1)


So simply?
Then all this mess only because my head thought these values were internally cached and "refreshed" when old ones were reached?
I was obsessed putting (and thinking) the new values "before" current split's end so CRTC could "take the new ones internally" for next split.


Thanks Arnoldemu and Executioner.
Please, If I misunderstand it again...
DI
.LOOP
HIT_MY_HEAD_WITH_A_STONE
JP LOOP




Executioner

Hi FatAgnus,

I never thought of that. Because your top screen displayed goes all the way to the end (R6 = R4 + 1), setting R6 to 1 when VCC > 1 means it will not stop displaying the current screen and match the next time VCC = 1 (ie. on the scoreboard). This is why R6=1 at Int 2 works fine so you don't need really accurate timing. Your don't want to disable interrupts for longer than a few scan lines at a time anyway, and there should be little reason to do so unless your graphics output is all done with PUSHes.

Cheers,
Richard

FatAgnus

Yes, now I can see it, I was very confused about how CRTC works internally.
Arnoldemu and you give me concise explanations of its working way...
...but CRTCmyhead "cached internally" the register Rconcept with a value "CRTC_store_registers_the_way_R12_R13", and, of course, VCCmyhead NEVER could reach that value so I was "out of sync".
Several times, after reading yours helping posts, I wrote the new value of "CRTC_DOESN'T_store_registers", to Rconcept, but, as old value was internally cached in my head and I was into a "out of sync" state, these new values never were cached internally by CRTCmyhead...
When my brain released the electron beam (too much time hold, some basic functions like breathing getting unstable), VCCmyhead REACHED Rconcept's update position so it could catch internally...

CRTC REGISTERS R4, R6, R7 ARE NOT CACHED INTERNALLY!!!!!

QuoteI don't know where I'm wrong or confused, but I'm very wrong
I was very wrong and confused when thinking as "chached" some registers' values

Axelay

I've been trying to follow this to see if i can "finally" get screen splits, but I'm still puzzled by the bit about where the interrupts seem to 'change' where they are occurring.  At least that's the impression I get from the comments in arnoldemu's sample code.  Does this just happen as a result of changing R7?  What does this have a bearing on?


I thought I'd try and take that sample and alter it to attempt an interrupt driven vertical scroll.  I thought if changing R7 so that the screen was higher (started earlier) altered where the interrupts were occurring in relation to vsync then it presumably wouldn't work, but as it stands it appears to be fine (only tried in winape so far).  Of course I also changed the other R4/6 values for the two halves to reflect the new dimensions, I just dont know why it appears to be happy with "just" that, or whether it's a good split?  Here's the modified code:


org &4000
nolist
run start

start:
;; standard screen is 39 chars tall and vsync at 30
;; with 25 chars displayed
;;
;; we want to change this to 26 chars displayed with vsync at 31
;;
;; Char Lines to end of screen: 39-31 = 8
;; Scan Lines to end of screen: 8*8 = 64
;; Interrupt occurs two lines after VSYNC, so lines until end of screen when interrupt occurs: 64-2 = 62
;;
;; If we then wait for one interrupt, we will be 10 (62-52 = 10) lines into the next screen.
;;
;; Then interrupts are:
;; 10, 62, 114, 166, 218
;;
;; And we will then be 10 lines into second screen.


di
ld bc,&7f10
out (c),c
ld bc,&7f54
out (c),c

; narrow the screen
ld bc,&bc01
out (c),c
ld bc,&bd00+32
out (c),c
; and centre it
ld bc,&bc02
out (c),c
ld bc,&bd00+42
out (c),c


;; set new vsync we want
ld bc,&bc07
out (c),c
ld bc,&bd00+31+4
out (c),c

;; wait for 2 vsyncs to allow it to stabalise and so that we can sync with that
ld e,2
wait_two_vsyncs:
ld b,&f5
wait_vsync_end:
in a,(c)
rra
jr c,wait_vsync_end
wait_vsync_start:
in a,(c)
rra
jr nc,wait_vsync_start
dec e
jp nz,wait_two_vsyncs

;; synchronised with start of vsync and we are synchronised with CRTC too, and we have the
;; same number of lines to next screen as we want.

;; set initial interrupt routine
ld hl,int_rout1
ld (int_rout_ptr+1),hl

;; set interrupt
ld a,&c3
ld hl,int_start
ld (&0038),a
ld (&0039),hl
;; enable
ei

main_loop:
ld b,&f5
vsync:
in a,(c)
rra
jr nc,vsync

halt

halt

call scroll_down

jp main_loop

;;---------

int_start:
push bc
push hl
push af
int_rout_ptr:
jp int_rout1


;;---------
;; first interrupt after vsync
int_rout1:
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f4b
;;out (c),c

;; set vsync position to turn it off
ld bc,&bc07
out (c),c
ld bc,&bdff
out (c),c

;; screen address for main part of screen
;; will not trigger until screen restarts
ld hl,(scroll_offset)
ld a,&30
or a,h
ld bc,&bc0c
out (c),c
inc b
out (c),a
ld bc,&bc0d
out (c),c
inc b
out (c),l

;; set height of main part of screen
;; since we are already past the end of the previous screen
;; this will take no effect.
ld bc,&bc06
out (c),c
ld bc,&bd00+25+4
out (c),c

ld bc,&bc05         ;; select vertical adjust register of CRTC
out (c),c
inc b
ld a,(scroll_fine_next)
out (c),a
ld (scroll_fine),a

ld hl,int_rout2
jp int_end

;;---------
int_rout2:
;; 10 lines until end of screen
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f43
;;out (c),c

ld hl,int_rout3
jp int_end

;;---------
int_rout3:
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f42
;;out (c),c

;; now at line 42.
ld bc,&bc04
out (c),c
ld bc,&bd00+25-1+4-1 ; less 1 because of R5 offset
out (c),c


ld hl,int_rout4
jp int_end

;;---------
int_rout4:

;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f40
;;out (c),c


ld hl,int_rout5
jp int_end

;;---------
int_rout5:

;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f49
;;out (c),c


ld bc,&bc0c
out (c),c
ld bc,&bd00+&18
out (c),c
ld bc,&bc0d
out (c),c
ld bc,&bd00
out (c),c

ld bc,&bc05         ;; select vertical adjust register of CRTC
out (c),c
inc b
ld a,(scroll_fine)
xor a,7
inc a
out (c),a

ld hl,int_rout6
jp int_end

;;---------
int_rout6:
;;ld bc,&7f10
;;out (c),c
;;ld bc,&7f53
;;out (c),c

;; 2 lines before end of screen

;; 128 cycles
ld b,42-1 ; need one less after addition of push af
int_delay:
djnz int_delay

;; set display height of screen
ld bc,&bc06
out (c),c
ld bc,&bd00+1+3
out (c),c

;; set height of screen
ld bc,&bc04
out (c),c
ld bc,&bd00+14-1-4
out (c),c

;; set vsync position
ld bc,&bc07
out (c),c
ld bc,&bd00+6
out (c),c

ld hl,int_rout1
jp int_end

int_end:
ld (int_rout_ptr+1),hl
pop af
pop hl
pop bc
ei
ret

;;end start

.scroll_down
;; check fine value first
    ld a,(scroll_fine_next)
    inc a
    and 7
    ld (scroll_fine_next),a
    or a
    ret nz

;; get the current scroll offset
    ld hl,(scroll_offset)
    ld bc,32
    or a
    sbc hl,bc

;; ensure scroll offset is in range &000-&3ff
    ld a,h
    and &3
    ld h,a

;; store new scroll offset. It is now ready to be written to the CRTC.
    ld (scroll_offset),hl
    ret

;; the scroll offset in CRTC character units
.scroll_offset
    defw 0
;; offset for fine scroll
.scroll_fine
    defb 0
.scroll_fine_next
    defb 0

FatAgnus

I can't understand well your post (my low english level hitting me again), but are you saying that you achieved to "move" the interruptions position handling CRTC registers??
I thought that:

-) After synchronized with the new screen configuration (supposing a correct new configuration), INT0 will always be on scan 2, INT1 on 54 and so on... 
-) The only way to cheat with int's pos is reseting internal "interruptions scan counter" (setting Gate Array RMR register with a bit 4 value of "1" )... or "di-ei"ng them.
-) R7 only allow us to decide WHEN vsync(->int0) will happen (when we go again to the very top of screen, can't explain myself better), but int0 will be anyway at scan 2.

Powered by SMFPacks Menu Editor Mod