CPCWiki forum

General Category => Programming => Topic started by: RichTW on 18:21, 24 August 19

Title: CRTC detailed operation
Post by: RichTW on 18:21, 24 August 19
Hi all,


(Full disclosure: my interest is in BBC Micro development, but there's plenty of common ground CRTC-wise!)


I was wondering if the CPC community has put together a document with detailed descriptions of known CRTC behaviour?  I recently came across some unexpected behaviour involving setting R4 midframe.  Specifically, if you try setting it to a value on the scanline immediately before that value would be reached, it doesn't notice the change.


For example (this supposes R9=7 throughout):
Is this known behaviour?  And has anyone speculated as to what's going on here?  It's like R4 is latched when the scanline counter == R9, and uses that for comparison instead of the register itself.

I should add that the BBC Micro has a CRTC which seems to correspond with Type 0 in CPC parlance.
Title: Re: CRTC detailed operation
Post by: Bryce on 22:27, 24 August 19
You might want to mention exactly which version CRTC you have, as they tend to differ in their behaviour. You can find the types here: http://www.cpcwiki.eu/index.php/CRTC#CRTC_Differences

The Type No.s (0 to 4) are an invention of the CPC scene, they don't relate to any documented number associated with the actual chip, but they are the standard reference here.You might also find the answer to your question on that page too.


Bryce.
Title: Re: CRTC detailed operation
Post by: RichTW on 23:17, 24 August 19
Thanks!  I edited my post to add that it was a Type 0 CRTC.  So far I haven't seen this behaviour documented anywhere, but there seem to be a good few 6845 experts around here, so I wondered if it was a known issue all the same.
Title: Re: CRTC detailed operation
Post by: norecess464 on 23:53, 24 August 19
@RichTW (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1965) All 8-bit machines rulezz, you are more than welcomed here in this forum.

Due to the multiple CRTC configurations on Amstrad Machines, we (CPC demomakers) always update R4 or R9 when VCC=VLC=0 (cf. first scanline of first row, like you did for "R4=0 @ scanline 32"). This allows us to generate split-screens compatible with all CRTCs.
I can not bring more information about the specific behavior you are experiencing with the CRTC Type 0, but some other people around here may know (as an emulator creator, maybe @arnoldemu (http://www.cpcwiki.eu/forum/index.php?action=profile;u=122) could help ; or maybe @Rhino (http://www.cpcwiki.eu/forum/index.php?action=profile;u=174) too). I would suggest to stick to VCC=VLC=0 and instead focus on all the wonderful FXs you could achieve with that. :)

Now I'm very curious about BBC Machines. I'm going to look at the best entries listed on Pouet, to see how far the machine was pushed... :)
ps. On CPC, we use terms "VCC" and "VLC". "VCC" refers to internal counter of R4 (Chars), while "VLC" refers to internal counter of R9 (Lines). It's more natural to us to describe "Scanline 32" as "VCC=0 VLC=0". "Scanline 31" in your example would be "VCC=3 VLC=7" (with R9 kept to default value, 7).
EDIT: just watched the best-rated BBC Micro productions on Pouet. Interesting ! I don't know how much you can compete against our Z80 3.3Mhz, maybe you are more limited with the slower 6502. I saw some FX exploiting line splitting (R9=0), which is what we also use to create most of the  best FXs on Amstrad (ZoomScroller and such may be doable on BBC machines too).
Title: Re: CRTC detailed operation
Post by: RichTW on 00:08, 25 August 19
Thanks!  For background, the BBC Micro has a couple of 6522 VIAs which provide 1MHz timers with latches, so you can generate very precise IRQs to do CRTC things.  This discovery came from an attempted optimisation - trying to set up the next CRTC sub-screen at the end of the previous one, and then setting more new values once the new sub-screen had started - in order to save an IRQ.  But setting R4 at VLC=R9 just doesn't seem to work (VLC=R9-1 is fine however).


From an emulator writer's perspective, it's also interesting to contemplate why the 6845 might behave like this.  There must be an elegant model which describes the behaviour (if we assume that these things happen because the circuit designers took a shortcut, rather than to make things more complicated!).  I was surprised not to find any reference to this behaviour anywhere though!
Title: Re: CRTC detailed operation
Post by: norecess464 on 00:14, 25 August 19
To this day, the most accurate emulator writer on Amstrad is @OffseT (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1826) (registered but not really active on this forum). I suggest to try contacting him through his website, http://ace.cpcscene.net/en:introduction . I'm sure he has all the technical details for you to provide the best emulation possible for your emulator.
Title: Re: CRTC detailed operation
Post by: robcfg on 08:23, 25 August 19
As with any other 8-bit machine, good coders can do magic!


I'll let our friend @chinnyhill10 (http://www.cpcwiki.eu/forum/index.php?action=profile;u=984) illustrate the situation  :D


https://www.youtube.com/watch?v=vVAMrDciMwI
Title: Re: CRTC detailed operation
Post by: Longshot on 11:01, 25 August 19
Hola RichTW,
 
There are several documents and articles on the CRTCs.
The differences are fragmentary and the emulator authors are stingy on the subject. :-X
Several projects are being studied to achieve something more complete.

Personally, I use now the Cx notation instead of "winape notation" for the internal value of the counters and Rx for their programmed value.
The behavior that you describe on the CRTC 0 comes from its ignoring the updating of C4 when C9=R9 and R4 is modified with C4
In this situation, the R4 register update is ignored and C4 is incremented by 1. So it goes to 1.
And it counts to 127 then back to 0 (bit 7 of C4 is always 0)
This is commonly called the CRTC registry overflow.

There are other differences between the various CRTCs, some documented, and some not.

As for example the interdependencies between the registers.
For example, on a CRTC 0, if you modify R9 with the current value of C9, then C9 goes to 0, and C4 is incremented, even if C4 = R4
While on a CRTC 1 and 2, C9 goes to 0, but C4 returns to 0 if C4 was R4.
In this situation, change R9 with C9 on CRTC 0 when current C4 = R4 causes a C4 overflow.
(this kind of case is not handled by the Winape emulator, for example)

Here is a link that may interest you about other techniques that you may not have exploited yet on BBC
https://open.amstrad.info/2019/08/20/archive-rupture-verticale-31-aout-1992/
It's in French but I can translate it if it interests you.
Title: Re: CRTC detailed operation
Post by: RichTW on 13:15, 25 August 19
Merci beaucoup Longshot!

This is the first time I've seen the behaviour acknowledged, so it's nice to see that it's recognised elsewhere and not me misinterpreting the observations!

We know that there are two 'events' regarding the counters: one when the counter hits its corresponding register at N-1 (and the comparator goes high), and one when the counter gets reset on the following clock (where the comparator goes low again, generating a falling edge which clocks the next counter in the chain).

Simplistically, that would imply that setting Rn to Cn, no matter how late, would signal the comparator high, and the edge would fall on the next clock and trigger the next counter in the chain.

But, as you say, there seems to be something magic happening when C9=R9 which leads to some interesting effects.

This I never heard before:
QuoteFor example, on a CRTC 0, if you modify R9 with the current value of C9, then C9 goes to 0, and C4 is incremented, even if C4 = R4
But it seems related to:
Quoteignoring the updating of C4 when C9=R9 and R4 is modified with C4
In this situation, the R4 register update is ignored and C4 is incremented by 1. So it goes to 1.
The only difference each time is that, when it works correctly, the counters are equal to their respective registers at the start of the line.  It's as if there's some extra logic, which comes from the C0 reset signal, which is used to determine whether to start the 'end of screen / vertical adjust' logic.  The results of that determine whether C4 gets reset or not, so it's not such a straightforward check.  Do we know which value C4 has during the vertical adjust period?  Does it stay equal to R4, is it reset, or is it R4+1?

Quote
Here is a link that may interest you about other techniques that you may not have exploited yet on BBC
https://open.amstrad.info/2019/08/20/archive-rupture-verticale-31-aout-1992/
It's in French but I can translate it if it interests you.
Thanks!  I found a similar document on GitHub (also in French).  I can understand to a reasonable extent, but Google Translate helps immensely too!
Title: Re: CRTC detailed operation
Post by: RichTW on 14:04, 25 August 19
Quote from: norecess on 23:53, 24 August 19
EDIT: just watched the best-rated BBC Micro productions on Pouet. Interesting ! I don't know how much you can compete against our Z80 3.3Mhz, maybe you are more limited with the slower 6502. I saw some FX exploiting line splitting (R9=0), which is what we also use to create most of the  best FXs on Amstrad (ZoomScroller and such may be doable on BBC machines too).

The main problem with the BBC, to be honest, is the horrible 1-bit RGB colour palette.  The CPU is pretty good as it's clocked at 2MHz (double the normal 6502 speed) and there's no contention with the video hardware, but you have to be inventive to work around the lurid colours!  The CRTC has the curious ability to be clocked at either 1MHz or 2MHz, so it can do character-by-character horizontal scrolling.  Bitshifters have been releasing some nice BBC demos recently, making use of all sorts of rupture techniques.  Games-wise, the jewel in the crown is probably Exile (https://www.youtube.com/watch?v=vbLndV_f_vo).
Title: Re: CRTC detailed operation
Post by: Longshot on 23:11, 25 August 19
QuoteThis is the first time I've seen the behaviour acknowledged, so it's nice to see that it's recognised elsewhere and not me misinterpreting the observations!
You're welcome (De nada!)  ;D

What is the CRTC model used in the BBC?
Is it a Hitachi HD6845S ?

In general, when R4, R12 and R13 are modified, C4 goes to 0 when C9=R9 if C4 is equal to R4, and C12 / C13 = R12 / R13.
(CRTC 0, 1, 2, 3, 4) (The 3 and 4 are Crtc emulated cloned in an Asic)

The exceptions to this rule are:
On CRTC 0, if C9 = R9 while R4 has been modified with the value of C4, then C4 does not go back to 0 and counts to 127.
(and in this case, C12 / C13 is updated when C4 is back to 0 from 127)

On CRTC 2, if C9 = R9 while R4 has been modified with the value of C4, then C4 goes to 0 if C4 is equal to R4, but C12 / C13 is updated with previous R12 / R13.
This exception for updating C12 / C13 is true only if R4 has been modified on the last line of the character.
If R4 was not modified while C9 = R9, then C12/C13 are updated with R12 / R13 for the next line when C4=R4.

There are many well-known differences between CRTC for the simplest things.
On CRTC 1, C12 / C13 = R12 / R13 as long as C4 = 0, whatever the value of C9.
Note that on the Amstrad CPC, the bits 10,11,12 of the address always come from bits 0,1,2 of C9.

On CRTC 0 and 2, if C9 = 0 and C4 = 0, and R6 = 0, then a line is generated with 1 byte of "display off" (odd addresses) and 1 byte of Vram (even addresses)
Note that the Vram counter is not affected; thus, only the contents of even Vram addresses are displayed.

On CRTC 1, if R6 = 0, the display is OFF only if C9> 0 when another screen has been created. (i have to verify this)

QuoteDo we know which value does C4 have during the vertical adjust period? Does it stay equal to R4, is it reset, or is it R4 + 1?
On CRTC 0, C4=R4+1 if C5 > 0
To check it, you can put R5=1 and R7 = R4 + 1.
The screen will stay synchronized.

On CRTC 1 and 2, C4 is incremented each time C9=R9+1.
So if  you set R5=16 (R9=7 and R4=36 (for 37 chars)), then C4 will reach 38.

On CRTC 4, C4 is not incremented if C5>0
In the previous example, C4 will reach 36. You cannot set R7 to a value greater than 36.
Title: Re: CRTC detailed operation
Post by: robcfg on 05:52, 26 August 19
I wouldn't like to sound picky, but crtcs type 3 and 4 are not emulated, they are implemented on the asic rather than on a single chip.


You can see them in the "Gate array decapped" thread. Those are actual transistors, no emulation.


Now, which variant they decided to implement and why, that's another story...
Title: Re: CRTC detailed operation
Post by: RichTW on 06:43, 26 August 19

Hi Longshot,

Thank you for all that fantastic information!

Quote from: Longshot on 23:11, 25 August 19
What is the CRTC model used in the BBC?
Is it a Hitachi HD6845S ?

Most BBCs have a Hitachi HD6845SP, which is very much a Type 0 CRTC.

But some of the later models have a Samsung KS68C45S or a VLSI VL68C45S23PC, which I'm not even sure if they are covered by the CPC's "type" system.  They have subtly different behaviour of their own!  One thing I've noticed is the behaviour of R1=0 seems different in different versions.  Sometimes it causes a visible column on the left, the same address block repeated in each row.

Quote from: Longshot on 23:11, 25 August 19
The exceptions to this rule are:
On CRTC 0, if C9 = R9 while R4 has been modified with the value of C4, then C4 does not go back to 0 and counts to 127.
(and in this case, C12 / C13 is updated when C4 is back to 0 from 127)

So this is the rule which started the whole topic.  I'm trying to figure out a possible implementation which would lead to this result.

Quote from: Longshot on 23:11, 25 August 19
On CRTC 0 and 2, if C9 = 0 and C4 = 0, and R6 = 0, then a line is generated with 1 byte of "display off" (odd addresses) and 1 byte of Vram (even addresses)
Note that the Vram counter is not affected; thus, only the contents of even Vram addresses are displayed.

This is a weird one.  Not sure how this manifests on a BBC, as all of the address lines are used (as opposed to the CPC which gets the bottom address bit from the 2MHz clock).

Quote from: Longshot on 23:11, 25 August 19
On CRTC 0, C4=R4+1 if C5 > 0
To check it, you can put R5=1 and R7 = R4 + 1.
The screen will stay synchronized.

On CRTC 1 and 2, C4 is incremented each time C9=R9+1.
So if  you set R5=16 (R9=7 and R4=36 (for 37 chars)), then C4 will reach 38.

That's interesting.  That somehow implies to me, in terms of implementation, that CRTC 0 re-uses C9 to count vertical adjust lines, while CRTC 1 and 2 have a separate counter (C5) to do this!

Thanks again for all this great detail!
Title: Re: CRTC detailed operation
Post by: norecess464 on 12:48, 26 August 19
@Longshot (http://www.cpcwiki.eu/forum/index.php?action=profile;u=128) By giving so much details about CRTCs to @RichTW (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1965) , now I bet he is going to implement Amstrad emulation loll
Title: Re: CRTC detailed operation
Post by: chinnyhill10 on 12:48, 26 August 19
Quote from: robcfg on 08:23, 25 August 19
As with any other 8-bit machine, good coders can do magic!



Also helped by the fact the BBC runs twice as fast as the C64 and they can do clever stuff with the 128k memory in the Master,
Title: Re: CRTC detailed operation
Post by: Longshot on 21:16, 27 August 19
QuoteOne thing I have noticed the behavior of R1 = 0 seems different in different versions.
To my knowledge, on all CRTCs, setting R1 to 0 does not leave any visible columns.

On the other hand, when R1>R0, on CPC, the character lines are repeated on all the CRTCs.
Here is the general case:The CRTC can no longer add R1 to the address of the line it has displayed , so it repeats the previous line.
Note that the address of the repeated line therefore depends on the current Vram address when R1 is modified.
When C0 goes to 0 (after C0 = R0), the display is enabled.
When C0 = R1, the display is disabled.
However,
For CRTC 1, the first line starts at the address defined for R12 / R13, but not the others.
For CRTC 2 and 0, a border byte is displayed when C0 = R0 (127 bytes, and not 128, are displayed.)

QuoteI'm trying to figure out a possible implementation that would lead to this result.
The overflow of C4 via R4 is handled by most emulators including Winape.
(However, this is not the case for the overflow of C4 via R9).

I think there is a C5 counter independent of C9, at least on CRTCs 0,1 and 2.
In general, the address bits 10, 11, 12 of the displayed data always come from bits 0,1,2 of C9.
As long as C9 <> R9, the video pointer is not incremented by R1, and only the 3 least significant bits of C9 are used to build the Vram pointer.
Consequently, when the CRTC does not manage the vertical adjustment, if R9 = 15 is set, for example, then lines 0 to 7 are identical to lines 8 to 15.

When C4 = R4, C9 = R9 and C0=R0, then C5 = R5 and C9 = 0
If C5 <> 0, then a specific management system for the vertical adjustment takes over.
During this vertical adjustment, C9 is independent of C5.
For example, if R5=16, 2 different characters of 8 lines are displayed on CRTC 0,1,2.
This implies that C9 is managed independently from C5.
When C9 = R9 and C0=R1, R1 is used to update Vram address, and C9 goes back to 0.
(note that if R1>C0, then the address is not updated for the next character)

On CRTC 0, C4 is incremented once when C4 = R4.
On CRTC 1 & 2, C4 is incremented each time C9 = R9

Thus, if R9 < 7, the R5 lines displayed follow the rules reported for CRTCs 0, 1, 2.
Example: if you set R9=3 (4 lines per char) you need to double number of chars R4+1=312/4 (R4=77)
If R5=16 then you need to adjust R4 : R4+1=(312-16)/4 (R4=73)
On CRTC 0,1,2:  4 extra characters of R9+1 lines are displayed during the vertical adjustment period.
(and for CRTC 1 & 2, C4 reach 73+4=77, so R7=77 is ok)

However on CRTC 4, C4 is not incremented (its value remains R4) and R9 is not used.
The address bits 10,11,12 then come from the bits 0,1,2 of C5
Thus, if R9=3 and R5=16 (previous example), the characters displayed on the screen use R9, and those displayed during the vertical adjustment period use R5.
On CPC, this extra character uses all memory blocks in the vertical adjustment area.

Changing R5 during vertical adjustment period also has consequences :
If C5+1=R5 for the current scanline, then vertical adjustment is "finished" and C4=0 and C9=0 for the next scanline (whatever the value of R9)
But if R5 is modified with 0, then C4 is not zeroed, causing a C4 overflow (the CRTC vertical adjustment algorithm is no more effective) 

As for the R7 register, if you program a screen of 312 lines as follows:
R4 = 36, R9 = 7, R5 = 16 (((36 + 1) x (7 + 1)) + 16)=312 lines
CRTC 4: R7 <= 36 ok
CRTC 0: R7 <= 37 ok
CRTC 1 & 2: R7 <= 39 ok

The display is also conditioned by R6 > C4
CRTC 4: R6 = 37 displays up to the last "extra character" of 24 lines (8 lines for C4 = 36 and 16 lines for R5 = 16) (winape is wrong)
CRTC 0: R6 = 37 displays up to 37 characters; R6=38 additionally displays 2 different characters. (winape is wrong)
CRTC 1 & 2: R6 = 37, 38, 39 display up to the respective characters for C4 = 36, 37, 38

When you implement an emulator, you also have to reproduce some of the common behaviors in order to identify the CRTC built into the computer.
The behavior of R5 on C4 is one of the different methods to test the CRTCs.
It allows one to check whether the CRTC still sets its VSync signal by modifying R7.
The CRTC 2 can also lose its VSync signal with some specific values in the horizontal registers (R2+R3>R0).

out & bc00,2: out & bd00,49: out & bc00,3: out & bd00,15: ==> no more Vsync: CRTC 2  :o
out & bc00,4: out & bd00,36: out & bc00,5: out & bd00,16
out & bc00,7: out & bd00,37: ==> no more Vsync: CRTC 4 (or CRTC 3)
out & bd00,38: ==> no more Vsync: CRTC 0 
Vsync on : CRTC 1
Title: Re: CRTC detailed operation
Post by: RichTW on 15:53, 29 August 19
Quote from: Longshot on 21:16, 27 August 19
To my knowledge, on all CRTCs, setting R1 to 0 does not leave any visible columns.

This is definitely something I observed many years ago on my BBC Micro (and I remember it being distinct behaviour from the ones at school!), but it may be that the later model BBCs had 6845 variants not seen on the CPC (they were CMOS ones, like the Samsung one I mentioned earlier!).

Quote from: Longshot on 21:16, 27 August 19
On the other hand, when R1>R0, on CPC, the character lines are repeated on all the CRTCs.
Here is the general case:The CRTC can no longer add R1 to the address of the line it has displayed, so it repeats the previous line.
Note that the address of the repeated line therefore depends on the current Vram address when R1 is modified.

This is something I haven't heard before though.  My understanding of the address caching is that when C0==R1 and C9==R9, the current address pointer (C12/C13) is cached (remembering that this pointer is incremented every character clock, even when display is disabled: this can be observed directly if display skew is enabled in R8).  Every time C0==0, C12/C13 is set to the cached value.  (There will be some kind of special handling for the end of screen, when the cache first gets loaded from R12/R13).

I don't see why the address of the repeated line would depend on the current address when R1 was modified.  Note that the CRTC doesn't ever need to add R1 to any internal counter (which would be much more circuitry) as it can just remember the current address at the right moment!

In the case where R1>R0, the cached address is never updated, meaning that the same character row repeats.

Quote from: Longshot on 21:16, 27 August 19
For CRTC 2 and 0, a border byte is displayed when C0 = R0 (127 bytes, and not 128, are displayed.)

This is something I'd like to check on a BBC Micro.  You say a single border byte is displayed, which corresponds to a half character clock on the CPC, right?  So I'd expect to see only a half-character border on the BBC.  I wonder why the CRTC does that?  Perhaps so that R1=0 works correctly (maybe there'd be a race between enabling and disabling display otherwise, and enabling would win?).

Quote from: Longshot on 21:16, 27 August 19
If C5 <> 0, then a specific management system for the vertical adjustment takes over.
During this vertical adjustment, C9 is independent of C5.
For example, if R5=16, 2 different characters of 8 lines are displayed on CRTC 0,1,2.

I need to check this on real hardware.  Previously you said that C4 stays at R4+1 during vertical adjust (even for R5>R9), but yet it also displays different character rows if display is enabled!  That's a fascinating and unexpected insight into what's going on internally!

I'm going to digest the rest of what you wrote, and will reply later!
Title: Re: CRTC detailed operation
Post by: Longshot on 10:41, 30 August 19
Hi RichTW
QuoteIn the case where R1> R0, the cached address is never updated, meaning that the same character row repeats.
You are right. I made a shortcut. :-\
The current video pointer (MA and MA') are initially calculated from R12/R13 when C4=0 and C9=0
On CPC, the video pointer is calculated as follows:
Bit 0 is always 0
Bits 1 to 10 come from bits 0 to 9 of R12/R13
Bits 11 to 13 come from bits 0 to 2 of C9 (or C5 in vertical adjustment on CRTC 4)
Bits 14 and 15 come from bits 12 and 13 of R12

As long as C9<>R9, the current video pointer MA=MA' when C0=R1.
When C9=R9 (and C0=R1) the "latched" video pointer MA' is updated with MA.

When R1 is modified with a value of R1>R0, the video pointer MA' is updated in different ways according to the CRTC

On CRTC 0, MA=MA'=fnc(R12/R13). All the character lines displayed are identical and it is always the first one.

On CRTC 1, MA=R12/R13 on the first line but MA' is not modified. Depending on the cases (I think when R1 was changed, I have to investigate more)
a) MA' contains the value of a character line of the current screen.
b) MA' contains the value of a character line but with an overflow of the video pointer.
Example: R12/R13=0, R1=40 (80 bytes per line). When C4=0, MA=fnc (R12/R13)
With each new character, MA' is MA+R1. The pointer, in words, is 10 bits.
If MA' is not settled by MA when C4=0, then there may be an overflow of this 10-bits counter.
MA' is therefore 0, & 28, & 50, & 78, ...., & 3E8.
Since 40 is not a multiple of 1024, the next address is &410 : e.g. &10 on 10 bits ("overflow" of MA')

On CRTC 2, MA=MA'=R12/R13.
All the character lines displayed are identical, but i guess the address follow the same logic as for CRTC 1.
I have to see the conditions when MA' overflow or not overflow.

I think the memory refresh of a CPC use the current pointer MA.
This is to be confirmed but if bits of MA are no longer used, then the ram related to these bits is no longer refreshed.
And then the memory is corrupted after a while. (But it's not a CRTC subject)

QuoteYou say a single border byte is displayed, which corresponds to a half character clock on the CPC, right?
Yes

Quotemaybe there'd be a race between enabling and disabling display otherwise, and enabling would win?
This is not the only case where this type of conflict occurs.
On CRTC 0 and 2, if C9 = 0 and C4 = 0, and R6 = 0, then a line is generated with 1 byte of "display off" (odd addresses) and 1 byte of Vram (even addresses)
On CRTC 0, if R0 is modified (example R0 = 7), then 1 byte of "display off" is generated each time a new scanline occurs (but not on CRTC 1).(Very boring...)
QuoteThat's a fascinating and unexpected insight into what's going on internally!
It is possible that the different manufacturers assumed that the adjustment was not intended to display Vram but just to complete the lines if (R4+1) x (R9+1) did not correspond to the right monitor frequency.
I do not think they thought crazy people would change the register content in real time with values all close to 0... ;D
Title: Re: CRTC detailed operation
Post by: RichTW on 22:17, 22 September 19
Hi all!

Seeing a very unexpected CRTC effect while trying to get an RVI implementation working on the BBC.

On the BBC, we can set a 2MHz character clock for the CRTC, so a horizontal line has 128 characters instead of 64.

The idea here is to divide it like this:
With perfect timing, we set R0=97 at the beginning of the first block, and set R9 to thisRA+15-nextRA. Then at the beginning of the next block, we set R0=1, so that we have 15 small invisible blocks which will consume the rest of this frame, plus everything prior to nextRA on the next line:
          set R0=97, set R9 accordingly
          |                          set R0=1
          |                    hsync |
          v                      v   v
0 (RA=0) |.(set R9=8)..... 0 ....:.| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
1 (RA=7) |.(set R9=21).... 7 ....:.| 8 | 9 | 10| 11| 12| 13| 14| 15| 16| 17| 18| 19| 20| 21| 0 |
2 (RA=1) |.(set R9=12).... 1 ....:.| 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 0 | 1 | 2 | 3 |
3 (RA=4) |................ 4 ....:.|  etc


This fails on real hardware, because, for some reason, the CRTC is adding an extra scanline.  The solution is that we set R0=95 instead, and allow for 16 invisible blocks, like this:


          set R0=95, set R9 accordingly
          |                          set R0=1
          |                    hsync |
          v                      v   v
0 (RA=0) |.(set R9=8).... 0 ...:.| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ? | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
1 (RA=7) |.(set R9=21)... 7 ...:.| 8 | 9 | 10| 11| 12| 13| 14| 15| 16| 17| 18| 19| 20| 21| ? | 0 |
2 (RA=1) |.(set R9=12)... 1 ...:.| 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| ? | 0 | 1 | 2 | 3 |
3 (RA=4) |............... 4 ...:.|  etc


If we move hsync to 60ish so we can see all the "invisible" blocks.  It's not clear which RA the extra scanline corresponds to.  On the BBC, RA3 is connected to display disable, so we get gaps between character rows if we set R9>7.  But RA4 is not, so line 16 is a mirror of line 0.  If the mystery scanline were line 17, we'd expect to see it in blue (as a mirror of line 1), but we don't - so either it continues to have display disabled, or it's something else.

(https://i.imgur.com/kv7XmVK.jpg)

Has anyone in CPC land (@Longshot?) ever seen this weird behaviour?  Or are there any known explanations of how setting R0 can interact when C0=R0?  Effectively this seems to be confusing the decision to start the next frame.

Just thought I'd share this as it's possibly an interesting effect which hasn't been documented.  This is with a CRTC Type 0.  If we just accept that, in these conditions, the CRTC will go up to R9+1 for some reason, the effect works perfectly; but it'd be great to understand why it's happening as well!  I've pondered this for a few days and am stuck!
Title: Re: CRTC detailed operation
Post by: RichTW on 12:12, 07 November 19
In case anyone is interested, I have some more info on CRTC Type 0.  Using a stable raster setup, a fellow BBC Micro developer and emulator writer has been able to come up with some tests which demonstrate the exact cycle that the CRTC checks various things.




First of all: why does CRTC 0 add an extra scanline to a frame when R0=1?  Turns out that there are a couple of events which happen at the start of a new scanline.

One character after the beginning of a new scanline (normally when C0 is exactly 1), the CTRC latches the "end of frame pending" signal.  After this moment, the CRTC is committed to ending the current frame, regardless of changes to R4 or R9 after that.

Two characters after the beginning of a new scanline (normally when C0 is exactly 2 (!)), the CRTC decides whether it needs to enter vertical adjust as part of the end of frame sequence.  In other words, if R5=0, but you then change it any time after C0=2 when C9=R9 and C4=R4, it won't get noticed, and there will be no vertical adjust.  In the case where R0=1, it doesn't get to do that check by the supposed end of frame, so an extra scanline occurs with C9=0 and C4=R4+1, and it will then see that no vertical adjust is due and finish the frame at the end of the next scanline.

There is also a "dummy raster" which will be added to the end of the vertical adjust as an extra scanline on even interlace fields, if interlace is enabled.  This is tested when C0=R0, i.e. the very last character of the frame, when the signal specifying 'vertical adjust finished' is high (note that this needn't necessarily be C9=R9 or C4=R4 or R4+1!).

Hard to say exactly why the sequence had to be spread out over multiple clocks like that; presumably there was too much logic and propagation time to do everything at the same time, and 'end of frame' is one of the most complicated events in the CRTC state machine.  I expect that it's implemented as some kind of shift register internally.




The "frame counter" (which is used for cursor flash rate, and determining interlace field) is incremented off the end of vertical displayed (R6), surprisingly.  I would have expected it to come from vsync, but no.  You can test this by observing that the cursor stops flashing if you set R6>R4.

When R6=0, one single scanline remains visible - we don't really have a good model of the internals which explains this, other than maybe it being a result of trying to set and reset an SR latch at the same time.  After the first scanline, setting R6 to the current C4 takes effect immediately, even mid-scanline.




Regarding R7, it's possible to trigger a VSync signal immediately, even mid-scanline or mid-character row, by setting R7 to the current C4.  This is on the proviso that there hasn't already been one on this character row.  In the corner case of a VSync ending and starting at the same time, the VSync pulse continues uninterrupted - it will continue counting up and wrap at 16.




One thing that's still on the list to test is the exact moment that MA gets loaded with the contents of R12/R13.
This has in fact already been tested, and it is, as expected on the last character of the frame, when C0=R0.




Hope there's some interesting new information there; if it can help to improve the current batch of CPC emulators even more, it's worth it!  This logic is now implemented in the Javascript BBC Micro emulator (in this file (https://github.com/mattgodbolt/jsbeeb/blob/master/video.js)), and any demos we're working on which employ RVI type techniques now run perfectly in the emulator!  We haven't started to investigate the other common type of BBC Micro CRTC yet (and I'm not even quite sure if it's a Type 1 or even another variant which CPCs don't have), but they tend to be CMOS parts made by VLSI, and have a quite different behaviour.
Title: Re: CRTC detailed operation
Post by: andycadley on 21:04, 07 November 19
Sounds cool, always interesting to get more of these subtle details. It makes you wonder if it might be possible to swap CRTCs between Beebs and CPCs to determine other quirks that are harder to find on one platform or the other.
Title: Re: CRTC detailed operation
Post by: RichTW on 21:51, 07 November 19
Quote from: andycadley on 21:04, 07 November 19
Sounds cool, always interesting to get more of these subtle details. It makes you wonder if it might be possible to swap CRTCs between Beebs and CPCs to determine other quirks that are harder to find on one platform or the other.

A strange requirement of the Beeb CRTC variants is that they must have the display and cursor skew functionality (basically, the 'S' variants, e.g. the Hitachi HD6845S). The 'R' variants, without skew, as I believe the CPC has, won't work propertly with the Beeb's Teletext mode!

But otherwise, more or less, they ought to work in either machine for testing stuff.  The Beeb's timing is very simple as there's no video contention, so it's easy to perform these exact timing tests.  The way the CPC loses certain memory accesses to the Gate Array makes it all sound much more complicated to get fragile timing correct.

Does the CPC stretch the clock to 1MHz during access to the CRTC?  There's special circuitry in the Beeb to do that, so CRTC writes take 5 or 6 cycles instead of 4, but it's all predictable.
Powered by SMFPacks Menu Editor Mod