CPCWiki forum

General Category => Emulators => Topic started by: endangermice on 21:50, 28 September 16

Title: CRTC Question
Post by: endangermice on 21:50, 28 September 16
Having got the FDC controller initially working, I've been looking into some of the problems with the CRTC code in XNACPC. I've so far managed to fix a bug that prevented register 9 (the Maximum Raster Address) from, having the proper effect. I'm now working on a problem with the implementation of Register 4 (Vertical Total).


What I'd like to understand is what happens if the Vertical Total is set to a value that is less than the Vertical Sync Position. At the moment, my the screen drawing code is hanging becuase, if the Vertical Total is set less than the Vertical Sync Position, the counters are never going to reach the vertical sync position as they get reset once the Vertical Total has been reached. How is this scenario handled by a Real CPC / decent emulator. I have observed the behaviour in Arnold and WinApe and it appears that these emulators duplicate the part of the screen drawn up to the Vertical Total until the complete screen is drawn. Is my understanding correct or does something else happen here?


Many thanks,


Damien
Title: Re: CRTC Question
Post by: endangermice on 09:19, 29 September 16
Having looked at this a bit more, would I be right in saying that the Vertical Total affects the timing of the DISPEN state therefore the actual scan timings stay the same i.e. the counters scan from column 0 - 63 horizontal and columns 0 to 38 vertical regardless, only if we hit Vertical Total, we switch to DISPEN and draw the border. That would mean that VSync will always be hit regardless of the Vertical Total?


If also noticed that both Arnold and WinApe can lose picture sync if some CRTC registers are set to certain values (like on a real CPC). I believe that this has been achieved by simulating a Monitor with its own timings and having the Emulated CRTC sync up to this, with the monitor losing Sync if the timings of the CRTC no longer match the timings of the Monitor?
Title: Re: CRTC Question
Post by: PulkoMandy on 10:11, 29 September 16
The vertical total is the number of (character) lines the CRTC will generate in a screen. When the counter reaches vertical total, it starts over at 0 and a new screen begins (line 0, 1, 2, etc).


If the vertical sync position is out of that range, there will be no vertical blanking on that screen. This is not a problem. If the reg6 is higher than reg4, there will also be no vertical border. This is also not a problem.


Note that line 0 is the first one with characters. So, from the CRTC point of view, the top border of the screen is the end of frame N, and frame N+1 starts when it prints the first line of no-border.


The CTM display that comes with the CPC expects a vertical blanking to happen at every 50.01Hz (15625Hz/312 lines to be exact). This does not need to be related to the number of CRTC "screens" generated. for example, you could generate many screens of 1 character line. This is how the various "screen split" ("rupture") effects are achieved.


If there is no VBL in the expected time (a good test case for this is the Climax intro), the CTM has a built-in timeout and will start a new frame anyway. The timeout duration depends on the "vertical hold" potentiometer at the back of the display.
Title: Re: CRTC Question
Post by: endangermice on 11:23, 29 September 16

Thank you, that's a great explanation and makes a lot of sense.

If I understand correctly, the reason why I see the screen repeating (on a real CPC and the better Emulators) when I set a small Vertical Total e.g. 10 is because the CRTC finishes drawing the screen when it reaches character row 10, but the Monitor is at this stage only partially through a whole screen scan. When the CRTC starts drawing the next frame, the Monitor hasn't finished one entire screen scan so when the CRTC outputs the next screen it will appear on the monitor multiple times (depending on the height of the Vertical Total). While the image appears to be repeated, in reality it's actually drawing the next frame (impossible to tell if it's a static image like Basic).

I have noticed that on a real CPC, the screen rolls when the Vertical Total is less than the Vsync row. Is this because it's never reaching V-Sync so therefore no synchronisation signal is sent from the CRTC or is it because the timings are now out with what the monitor expects - perhaps both?

I have also found that if you set the VSync period within a shortened Vertical Total that the screen also rolls. I presume this is because the shorter screen draw and quicker VSync is no longer keeping in time with what the monitor expects.

It looks like both Arnold and WinApe simulate a monitor with its own timer. Both will show a loss of V-hold like on a real CPC though both show it in a slightly different way, which I suspect is due to the way they're simulating the v-hold.

The V-Hold makes sense too, that affects the TV's own internal timer which is used if no sync signal is found and is why you will see the screen rolling if no sync signal is produced by the CRTC, the TV cannot guarantee to sync its own timers  with the CRTC unless the CRTC sync signal is received.

I measured the VSync of the CPC yesterday with my multimeter to prove to myself it outputs at 15.6KHZ :) .
Title: Re: CRTC Question
Post by: PulkoMandy on 15:48, 29 September 16
If vertical total is less than vsync position, there is no VSync signal from the CRTC. The monitor does what it can to stay in sync (if you very carefully adjust the VHold, you can make the picture somewhat stable).


If the vertical total is less than the required number of lines, the VSync will happen more often. The monitor can compensate for that a little, but at some point it will give up and "skip" the synchronization signal, trying to sync again on the next one.


There aren't much details about the sync chip used in the CTM, but from observations of the horizontal sync behavior (and some weird code to exercise it), it is likely that the chip implements this with a PLL (https://en.wikipedia.org/wiki/Phase-locked_loop (https://en.wikipedia.org/wiki/Phase-locked_loop)), which is a bit more complex than a simple timer would be. But for the vertical sync, in most cases, a timer will be enough. For the horizontal sync however, there are some tricks which need a more careful implementation. I can think of Climax G "loading" screen, and many demos from the 80s with very weird timings and screen distortions.


If you happen to try such demos, setting the brightness of the CTM to a high level will allow you to see the slight difference between normal black, and synchronization areas, which are even darker (of course with sane timings this is invisible outside screen borders).
Title: Re: CRTC Question
Post by: endangermice on 08:24, 04 October 16
Thank you very much for all your help, it has enabled me to get to a point where I now have an initial emulation of the CRTC working - it's working with most standard games and a few CRTC effects are also working :).

I'm now working on implementing all of the correct results for the adjustment of the various registers. I'm currently working on getting the Display Address working properly for hardware character scrolling.

I'm trying to get my head around how it works. I understand the fundamentals i.e. that the address is used to determine where from memory to read the data to begin from column 0, row 0 but I'm not understanding how the correct area in memory is calculated.

The display start address (hight and low) is the address in memory where we satart to draw the screen i.e. where we read to display pixels in column 0, row 0. On the CPC the default screen address is 0xC000. The bit I don't understand is how this is derviced from the display start address. On startup, this is set to R12 (Display Start Address High) 0x30 and R13 (Display Start Address Low) 0x00 which makes a 16bit address of 0x3000.

In various emulators, the code to translate this to 0xC000 is a left bitshift by 2 places and then applying an & mask to remove all but the two highest bits. It appears to be converting a 14 bit number to a 16 bit number. What I don't understand is why this is neccessary when R12 and R13 combined would produce a 16 bit number. Why don't the combination of the two numbers produce 0xC000 instead of having to do the shift and mask too?

When the screen is scrolled i.e. say the start address for charcter 0, row 0 is changed to 0xC050, is the memory wrapped or will it read 0x50 bytes beyond the original end point of 0xFFFF? I'm assuming it wraps back to 0xC000 since anything beyond 0xFFFF would be outside of the maximum value addressable by the CPC's 16bit address bus.

I hope this all makes sense - I'm just a little unclear on one or two things here. I've been reading through the various documentation on this site and on Grimware along with the datasheets for the chips but I have't been able to find anything that clearly explains my queries - I may of course have missed something....
Title: Re: CRTC Question
Post by: PulkoMandy on 10:28, 04 October 16
You won't find the explanation in the datasheet, and not yet on grimware for this. You have to look very carefully at the CPC schematics.


The CRTC will increment its addresses internally starting from the R12:R13 setting. These generate the MA address. It is combined with the RA address which is generated from the pixel line inside each character (it goes from 0 to 7 in the default settings).


If you look at the CPC schematics, you will see that the RA and MA are wired to the RAM in a weird order:
- RA4 and RA5 are not used, so character heights above 7 will have strange results (looping over the first 8 lines of the character)
- MA9 and MA10 are also not wired, which are the two "ignored" bytes in R12
- The mapping of the other pins is in an unusual order which results on the unusual order of lines on the CPC display (add 0x800 to get to next pixel line, etc).
Title: Re: CRTC Question
Post by: endangermice on 21:27, 05 October 16
Ah yes I recall now the strange wiring of the CPC to the CRTC, which is why programming the screen is a lot harder than it should be, thank you for the explanation. I'm getting there with the hardware scrolling but I'm having a few calculation issues.

I understand that a CPC screen is 16,384 bytes in size (0x4000). However I cannot work out how that figure is calculated. Logic suggests it should be the size of a character scanline in bytes which is: 2 x number of characters in a row (40 by default) x number of columns in a row (25 by default) * number of scanlines in a character (8 by default). However this calculation produces a figure of 16,000. What's happened to the other 384 bytes? Are they ignored?

Similarly I cannot figure out how we get 2048 (0x800) as the offset for the next scanline row. Again logic says it should be the size of a scanline in bytes (80 by default) * the number of vertical columns (25 by default). However this arrives at 2000 not 2048, again 48 bytes have gone missing.

I believe I need to understand how to calculate the offset for the scanline row so that I can produce the correct behaviour when the number of displayed horizontal characters is different to the default. I would imagine that the offsets also change in this scenario.

Am I doing these calculations wrong or is there some other reason why I cannot arrive at the correct values is it perhaps because the result has to be the nearest value that's a power of 2...?


Thanks again for your help, I think I'm making progress - slowly!
Title: Re: CRTC Question
Post by: andycadley on 22:34, 05 October 16
The extra 384 bytes just aren't being displayed, because those addresses aren't currently being generated by the hardware. They tend to be lumped into the display memory simply because they're scattered around in a way that means they aren't convenient to use and also they'll be used as the screen is hardware scrolled (ignoring overscan addresses generated by the hardware will wrap within each 16K block)
Title: Re: CRTC Question
Post by: PulkoMandy on 08:41, 06 October 16
Again, this is all because of the way things are wired.


So yes, in the standard screen format there are 384 unused bytes. They start being used if you scroll the display (just press RETURN a few times in BASIC until the cursor reaches the bottom of the screen, it will change the R12/R13 value for scrolling).


The 0x800 bytes come from the way the CRTC is wired to the RAM.
Title: Re: CRTC Question
Post by: pelrun on 14:04, 06 October 16
Quote from: endangermice on 21:27, 05 October 16
Similarly I cannot figure out how we get 2048 (0x800) as the offset for the next scanline row. Again logic says it should be the size of a scanline in bytes (80 by default) * the number of vertical columns (25 by default). However this arrives at 2000 not 2048, again 48 bytes have gone missing.


This is a very common thing in image buffers, not just on the CPC, and it's called the "stride" of the array. The scanline is 2000 bytes wide, but the array stride is 2048, so you have to add 2048 to move to the next row. And it's precisely because it's easier to work with powers-of-two instead of an arbitrary image width, even if you lose a few bytes.
Title: Re: CRTC Question
Post by: PulkoMandy on 14:37, 06 October 16
Well, it gets a bit more tricky. The offset between two lines is always, no matter what you do, 0x800 bytes. Even if you change the display format. Even if you use 32K of video memory. It's just that the line address bits of the CRTC are wired to A10, A11, A12, etc. So, incrementing the line counter by 1 leads to incrementing the address by 0x800 bytes.
Title: Re: CRTC Question
Post by: endangermice on 00:32, 07 October 16
Hi Guys, thank you for all the clear explanations, I think I'm getting there. I created a monitor class last night that can sync to my CRTC code so now a lot more things look correct. However, there still seems to be a problem with the way I am generating screen addresses. It's working fine for all standard games, but anything like the Batman Forever demo is a complete mess and I'm not sure what the exact problem is.

(http://www.endangermice.co.uk/monogame/batmanscreen.png)

The main issue is that I still don't fully understand the correct procedure for generating the addresses which isn't helping me to figure out what's wrong. My code for calculating addresses is as follows:



int CalculateScreenMemoryAddress()
{
    int crtc_screen_address = (GetRegister(Register.DisplayStartAddressHigh) << + GetRegister(Register.DisplayStartAddressLow);

   //crtc_screen_address |= GetRegister(Register.DisplayStartAddressLow);
   int screen_memory_address = ((crtc_screen_address << 2) & (0xF000));
   //int screen_memory_address = (crtc_screen_address << 2);
   //screen_memory_address = 0xc0A0;

   int scroll_offset = (((GetRegister(Register.DisplayStartAddressHigh) & 0x03) * 256) + (GetRegister(Register.DisplayStartAddressLow) & 255)) * 2; // From http://www.cpctech.org.uk/docs.html for 16K screen

   int bytes_across = m_horizontal_character_counter * 2; // 2 bytes per character
   int bytes_down = m_vertical_character_counter * (GetRegister(Register.HorizontalDisplayed) * 2); // Whole row

   int scanline_offset = 0x800; // Regardless of the screen format or anything else, this is always the screen offset
   int memory_line_offset = ((m_vertical_scanline_counter % (GetRegister(Register.MaximumRasterAddress) + 1)) * scanline_offset); // This accounts for Amstrad's bizarre wiring of the CRTC

   return bytes_across + bytes_down + memory_line_offset + screen_memory_address + scroll_offset;
}


I'm not sure if anyone can see where I'm going wrong? A typical example of the difference between my emulation and WinApe or Arnold is if I set the DisplayAddressHigh to 44 on those emulators, the screen becomes a mash of lines (out &bc00,12, out &bd00,44). On my emulator, the first couple of lines in each character row are the same, but the rest are rendered out as normal. It is as if memory is not wrapping round correctly or something like that.

If anyone has any ideas, they would be most welcome :) .[/code]
Title: Re: CRTC Question
Post by: andycadley on 04:18, 07 October 16

I haven't followed your code entirely, but I don't see how it is taking into account things like the addresses within a scanline not necessarily being continuous - i.e. when the scroll offset is non-zero there can be a portion of the screen whose address cannot be calculated as simply start_address_of_line + (2 * characters_across)


I suspect it gets a lot easier if you stop thinking about "the screen" and treat the process as purely maths. Calculate the values for MA and RA first, then combine the bits as per: http://cpcwiki.eu/index.php/CRTC
Title: Re: CRTC Question
Post by: PulkoMandy on 08:03, 07 October 16
The code is a bit hard to follow this way indeed.


What is done in emulators I know is:
1) Implement the CRTC internal counters. The CRTC works by counting things from 0 up to some register value, and when the value equals the register, reset the counter to 0 and start over. This is important, because the register value can be changed while the counter is counting! It can lead to situations like that:



Counter Reg Result


0            7    !=
1            7    !=
2            7    !=
3            7    !=
(here, the z80 writes to the register)
3            2    !=
4            2    !=
5            2    !=
...
255        2    !=
(here, the CRTC register overflows without matching anything)
0            2    !=
1            2    !=
2            2    ==
(here, the counter matches, an event happens: DISPEN goes to 0, or a counter is reset, or...)



2) Once you have this, emulate the computation of MA and RA outputs from the CRTC. They are straightforward from the counter values: RA is from the line counter, MA is from the character line and character column counters
3) Map these MA and RA values to a RAM address according to the CPC wiring (did you see where it is in the CPC schematics?): A0 is generated from the 1MHz clock, A1 is MA0, etc.
4) Read the byte at the generated address and send it to the "Gate Array" (for palette and mode handling)
5) Output the pixels from the gate array into the CTM emulation, don't forget to also feed it the sync signals
6) At first a simple emulation of the CTM is enough: draw pixels from left to right on a line, when there is a HSYNC, move to next line, when there is a VSYNC, move to top of screen
7) Once you have this working, you can start working on a more realistic emulation of the CTM to handle cases where the HSYNC and VSYNC are not at the expected times or not present at all.
Title: Re: CRTC Question
Post by: endangermice on 09:18, 07 October 16
Yes you're both quite right my code isn't that easy to follow, basically some parts of it I have figured out from the datasheets for the CRTC other parts are taken from various other sites and some from the existing XNACPC emulator I've been working with. It isn't optimised in any way and is pretty cumbersome as it's really just experimental. Thank you both for having a go though, I know there's nothing worse than trying to understand someone else's work!

I remembered late last night when browsing the forum on setting the base address that it can only be set to 4 pages, 0x0000, 0x4000, 0x8000 and 0xC000. Fano wrote in another post how bit 4 & 5 of register 12 select which of the 4 pages is going to act as base address so now I can calculate this very easily - it seems the original code in XNACPC is wrong, I think the reason it makes no sense is becuase it's a bit of a stab in the dark that just happens to produce the correct results for standard games. Bearing this in mind, I'm now calculating the base address by simply doing the following:

int screen_memory_address = ((GetRegister(Register.DisplayStartAddressHigh) & 0x30) >> 4) * 0x4000;

& Mask off bits 4 & 5 (0x30), bit shift to the right by 4 and multiply the result by 0x4000. This works perfectly so now it's time to figure out and fix the rest of the code.

I will now study both your replies, thank you again for all the great detail. I'm tempted to write this all up if I finally get it all working, I think it would be useful to expand on what's currently in the wiki and I'd also like to give something back for all your efforts.

Andy you're right, I need to think in terms of the maths and get that right. Everything should then work. The display aspects have been a distraction I really should be concentrating on the timings and maths - good advice, thanks.

I'll let you know how I get on, thanks again,

Damien
Title: Re: CRTC Question
Post by: PulkoMandy on 15:33, 07 October 16
I don't get this "4 pages" thing. The CRTC can address the full 64K of central ram and start the display almost anywhere in it.


What happens is, 2 bits of the MA address are not wired to anything (as you said, they are "masked"). BUT, these two bits still play an important role. The CRTC still uses them, even if they have no effect. When it reaches the end of a "page", what happens is that these two bits will change.


In the usual setting, your addresses will be like:



00001111
00010000



But, if you have these two bits set to 1 in the initial address:




00111111
01000000



In that case, with the CPC wiring, the "next" page is displayed.
Title: Re: CRTC Question
Post by: andycadley on 17:15, 07 October 16

Quote from: PulkoMandy on 15:33, 07 October 16
I don't get this "4 pages" thing. The CRTC can address the full 64K of central ram and start the display almost anywhere in it.
Yes, it can, but as a result of the way things are wired up it will wrap within the current page (so a screen starting at &1000 will go to &3fff and then wrap back to &0000) and so people tend to think of it in that way.
Title: Re: CRTC Question
Post by: endangermice on 09:39, 08 October 16
Right, I think I have it, apart from one final thing...

Quote2) Once you have this, emulate the computation of MA and RA outputs from the CRTC. They are straightforward from the counter values: RA is from the line counter, MA is from the character line and character column counters
I understand that RA value comes from the current line within the character row, which on the CPC could be from 0-7, because only 3 bits are wired up. How is MA calculated from the line and character counters? I've been reading through the documentation and I can't seem to find a description of this. I may just not be able to interpret the information in there.

Also it says that address A0 is fed by the clock. Is this something I need to account for in the emulation too?

Update - I've found it! It was hiding in one of the PDF datasheets http://www.cpcwiki.eu/imgs/1/13/Um6845.umc.pdf (http://www.cpcwiki.eu/imgs/1/13/Um6845.umc.pdf) page 3-85

MA0 - MA7 = Character Column Counter bits 0-7
MA8 - MA13 = Character Row Counter bits 0-5


I think that looks right.
Title: Re: CRTC Question
Post by: PulkoMandy on 19:26, 08 October 16
Yes, that's it.


Regarding A0, well, what this means is that a "character" for the CRTC is the size of a "mode 1" character, that is, 2 bytes.


How you handle this depends on how precise you want your emulation to be. It probably has some effect when you change a CRTC register at just the right time to make it visible. But otherwise, as long as you manage to get the odd and even bytes to screen in order, it is not very important.
Title: Re: CRTC Question
Post by: endangermice on 16:03, 09 October 16
So I spent several hours yesterday trying to get this to work, but I'm still not getting the right result. I've generated the CRTC 16 bit address, I have then mapped this to the CPC layout, but the addressing isn't correct.

I've looked into it in detail and when I add in the Memory Base Address (in this case 0xC000), the addresses start generating correctly i.e. the first pixel on each row is:

0xC000
0xC800
0xD000
0xD800 etc.

However when the counter moves to the second row, instead of starting at 0xC050, it's starting at 0xC200. It seems the translation to the CPC addressing is not correct. I'm not sure what I am doing wrong, I have wired it all up exactly according to the docs but it's not generating the addresses correctly.

I've done the calculation by hand and I get the same results so it appears the wiring documentation is missing some vital information, maybe a bitshift or something.

I've been through all the CRTC counter code with a fine tooth comb and that all seems to be creating the correct values, so I'm confident the counters I'm reading in the address creation code are correct it's just the addressing code that is wrong somehow.

I'm working on the basis that the MA CRTC address is generated by taking the first 8 bits of the column address counter (which is the counter that counts horizintally from 0 - 63) and bits 0 - 5 of the row address counter (which is the counter that counts vertically from 0 - 39). Those are then combined to make the 14 bit MA address number (as detailed in http://www.cpcwiki.eu/imgs/1/13/Um6845.umc.pdf (http://www.cpcwiki.eu/imgs/1/13/Um6845.umc.pdf) page 3-85).

For example, if we are on column 0, row 1, raster row 0 - the column counter is 0 and the row counter is 1. Bits 0-7 of the column counter are therefor 00000000 (the column is 0). Bits 0-5 of the row counter will be 000001 (the row is 1). If I combine these to create the 14bit MA address I get

000001 00000000 or 0x100 in hex

if I then wire this according to the CPC with MA11, MA12 going to A15 and A14 and MA9 - MA0 going to A10 - A1 (I'm ignoring RA in this example since in this case it is 0 so will not have any effect on the generated address) I get:

00000100 00000000 or 0x200 which is the wrong offset, it should be 0x50 (00000000 01010000). I cannot see any way of getting that with the input numbers.

It seems this is the part of the calculation that I am getting wrong. As far as I can tell, I'm performing it correctly, but the result is not correct suggesting I'm missing something.

Hope this makes sense. Any ideas?
Title: Re: CRTC Question
Post by: andycadley on 21:00, 10 October 16

Quote from: endangermice on 16:03, 09 October 16I'm working on the basis that the MA CRTC address is generated by taking the first 8 bits of the column address counter (which is the counter that counts horizintally from 0 - 63) and bits 0 - 5 of the row address counter (which is the counter that counts vertically from 0 - 39). Those are then combined to make the 14 bit MA address number (as detailed in http://www.cpcwiki.eu/imgs/1/13/Um6845.umc.pdf (http://www.cpcwiki.eu/imgs/1/13/Um6845.umc.pdf) page 3-85).
The CPC operates the CRTC in "straight binary" mode, rather than row/column (indeed other CRTC variants only support that mode) - as indicated by the fact R8 contains 0 under normal circumstances.


In that mode the CRTC counts each displayed "character", so 0 to 39 on the first character row then 40 to 79 on the next. Putting that into CPC format should give you C000h, C050h etc
Title: Re: CRTC Question
Post by: endangermice on 21:41, 10 October 16
Andy, thank you, that's definitely what I'm missing. One further question, how is the straight binary counter converted into MA? If I'm using rows and columns, it's

MA0 - MA7 = Character Column Counter bits 0-7, MA8 - MA13 = Character Row Counter bits 0-5

However since we're only using a straightforward character counter when the Display is enabled I only have one number. Do I simply populate MA0 - MA7 with this value and ensure MA8 - MA13 are populated with 0's?
Title: Re: CRTC Question
Post by: andycadley on 22:14, 10 October 16
It's just a straight 14-bit counter, you just keep incrementing it and that value is MA.
Title: Re: CRTC Question
Post by: endangermice on 22:37, 10 October 16
Thanks Andy that's really helpful :).
Title: Re: CRTC Question
Post by: endangermice on 18:48, 11 October 16
The info on the 14bit counter was spot on, thank you. It's now working better than before - games like Xenophobe with an unusual screen width now display correctly for the first time :).

I'm now figuring out how to handle particularly unusual scenarios. I'm currently looking at the Horizontal sync widths. Sometimes, they are set in such a way that they extend beyond the maximum column count for a row. What happens in this scenario since it technically means that HSync is never deactivated as we can't reach the column number. How should this be handled. Should HSync be automatically reactivated at the start of the next row, or does something else happen?

Right now I'm encountering a scenario with the Batman Forever demo, the setup screen where the end of Horizontal Sync is beyond the 64 characters in a row. Therefore HSync never ends and the display goes blank.

Thanks again for all the help, I hope all my questions aren't too annoying.
Title: Re: CRTC Question
Post by: andycadley on 19:25, 11 October 16
Cool, good to hear you're making progress. I think I'll defer to the real experts like @arnoldemu (http://www.cpcwiki.eu/forum/index.php?action=profile;u=122) on what happens in the extreme edge cases though!
Title: Re: CRTC Question
Post by: PulkoMandy on 08:07, 12 October 16
You will also start to see differences between the CRTC types when going into such details.


for the HSync, as far as I know it is implemented with a "start" and a "width". This would mean it is implemented as a separate counter:
- When HCC (horizontal char counter) hits HSync start (Reg. 2 value), the HSync starts and the HSync counter (let's call it HSC) is reset.
- HSC is incremented at every new char
- When HSC reaches the hsync width value (from R3), the HSync stops


This leaves one open question: Is HSC reset when the HCC is reset? Or does it run independantly?
Title: Re: CRTC Question
Post by: endangermice on 09:42, 12 October 16
That's interesting, if HSync is driven by a separate counter then you could in theory set much longer widths than the screen size. Such a width would effectively run HSync out of sync with the resetting of the HSync character counter. In theory you might see a skewed screen as Hsync would start later than expected - that's assuming that the CRTC beam does not wait for the start of HSync like it does for VSync....

Hmmm I wonder if this is what's going on with the Batman Forever demo. Do you recall the section where it draws a kind of twisted cylinder. I wonder if that is using some clever real time adjustment of the HSync width in order to skew the image on a per line basis....?
Title: Re: CRTC Question
Post by: PulkoMandy on 11:34, 12 October 16
No, the HSync must always happen exactly every 64us and have the same width.


If you don't have it every 64us, the screen will distort as the monitor will slowly catch up with the sudden and unexpected change. Example of demo doing this: Plasma Pas Cher (going from 63 to 65 us between hsync which is reasonable). There are old demos from the 80s doing much weirder things.


If you shorten the HSync length, the screen will be slightly shifted to the left (not exactly a whole character, you can make it move by about a pixel). Axelay used this in his games to implement smooth scrolling. If you shorten it too much, at some point the blanking will not coverthe PAL color burst anymore. The CTM doesn't care about this, but if you use the CPC with another display (TV, video projector, Commodore 1084s, ...), the display will take the color of whatever is in the color burst area (usually border color). The result is usually a smooth gradient from border color to black over a few lines. There was a picture of a test demonstrating this during one of the ReSeT parties, but I can't locate it at the moment.


Most of Batman Forever distorsion effects are essentially line-to-line screen splitting (CRTC screens 1 line high, changing R12 and R13 value at each line) and clever palette changes.


The counter for the HSync length is probably only 4 bits wide, as is the R3 setting for HSync. So, you can't set a long width, it will count for at most 16 chars and that's the maximum HSync length.
Title: Re: CRTC Question
Post by: endangermice on 16:24, 12 October 16
That makes perfect sense - I can see how Batman Forever would work with a lot of 1 scanline CRTC screens - this will be fun to implement.


It shouldn't be possible to enter more than a 4 bit number for the Horizontal Sync width since the calculation of the value is

VVVVHHHH from register 14, so in theory it can't go any higher than 15. Of course in my debug dump code, it's showing the whole byte, not the individual values as extracted from bits 7-4 and 3-0. I'll amend that to show what's going on more accurately.
Title: Re: CRTC Question
Post by: endangermice on 17:42, 13 October 16
Is anyone able to explain how 32kb screens can be emulated? Due the the lack of an M11 connection, I'm, finding my emulated 32kb screens are wrapping back around to the beginning of the 16kb memory window. I understand that setting M11 can allow the CPC to access the additional memory, I believe this is possible because it can be set via R12 and R13 it just never gets read by the CPC but can be used internally. I'm a little unsure exactly how this works. I've read Kevin's http://www.cpctech.org.uk/docs.html (http://www.cpctech.org.uk/docs.html) article on this a few times but I not quite getting it.
Title: Re: CRTC Question
Post by: andycadley on 19:15, 13 October 16
As long as you're initialising your 14-bit MA counter correctly from the values provided to R12 and R13, it should "just work". It happens because by setting MA10 and MA11 to 1, they will overflow and change the upper two bits MA12/13 such that subsequent addresses end up coming from a different 16K page of memory.
Title: Re: CRTC Question
Post by: PulkoMandy on 21:12, 13 October 16
Yes, that's it exactly. With MA10 and MA11 in bold:


Last address for a 16K page:
00001111111111
+1
00010000000000

MA12 and MA13 are still 0, we are back at address 0xxx.

BUT, if your initial value for R12 is set with MA10 and MA11=1:

00111111111111
+1
01000000000000

Now MA12 changes, and we are at address 4xxx.

That's all there is to 16K/32K screens. It's just that the value for these two unused bits leads to an overflow, or not.

For this to work, you need to properly take MA10 and MA11 into account when computing your MA address, and only after the processing there is done, convert to CPC RAM space address (which does not use these two bits).
Title: Re: CRTC Question
Post by: endangermice on 21:28, 13 October 16
Guys,

Thanks again for all your help, it's invaluable!

I think I've just figured out what has been confusing me. I don't think the wiring table: http://www.cpcwiki.eu/index.php/CRTC (http://www.cpcwiki.eu/index.php/CRTC) is correct. It says A15 is wired to MA12 and A14 is wired to MA11. Looking at the 6128 schematics again, A15 should be wired to MA13 and A14 should be wired to MA12.

If calculate under that assumption, the startup address of MA - 0x3000 when translated to the Amstrad wiring is 0xC000 which is correct. I was thrown when I was getting 0x8000, but I believe that is due to the incorrect assignment of A15 and A14 in that table.
Title: Re: CRTC Question
Post by: andycadley on 21:47, 13 October 16
Er, yup, that looks like a mistake on the Wiki page all right. Well spotted. :-)
Title: Re: CRTC Question
Post by: endangermice on 22:01, 13 October 16
Yes that's had me going round in circles for more than a few hours! I think I'm very nearly there but I'm a bit stuck on the final piece of the puzzle....

I've now got MA running as a 14bit counter that simply increments by 1 each time I'm called by the clock signal and we draw to the screen i.e. display_enable is true. This will cause the number of bytes to jump by 2 due to the fact that the MA0 - MA9 are assigned to A1 to A10 - essentially a bitshift to the left which means the lowest number it can increase by is 2. MA is also reset to R12 and R13 at the beginning of the next frame.

The CPC addresses are almost correct. However, my memory offset counter is not resetting after a scanline so instead of getting

0xC000 ... 0xC04E ... 0xC800, I'm getting
0xC000 ... 0XC04E ... 0XC850

I figured that would happen automatically when I got the wiring correct but I guess it doesn't so is it not correct to simply increment the MA address by 1 on every clock cycle...?
Title: Re: CRTC Question
Post by: andycadley on 22:34, 13 October 16
You're basically there. The last bit of the puzzle is that, within a character row, each scanline needs to have the same MA values. So you need to store a copy at the start of a line and reset it back when the horizontal character count matches horizontal displayed, unless RA =R9(Max Raster). Or possibly RA >= R9, IIRC it may be CRTC dependent (and gets funkier on Plus machines!)
Title: Re: CRTC Question
Post by: endangermice on 09:38, 15 October 16
That was it! Andy thank you so much for this bit of information, I now finally have the addressing working correctly, the pages are scrolling and 32kb screens now display as eh... 32kb :).


So I now have decent memory mapping of the CPC screen - I guess it's time to work on those CRTC registers and the Monitor emulation - that should be fun - I think....
Powered by SMFPacks Menu Editor Mod