General Category => Programming => Topic started by: Manu on 19:47, 28 March 13
I have one question about CRTC. Let's have a look at this image from grimware:
I get that with the default register values, the right border is 6 chars, left border is 4 chars, bottom border is 5 chars, and top border is 6 chars (or maybe 7, because vsync "height" is 16 lines)... right?
But I've seen code that modifies R6 to 34 and R7 to 33. That means that vsync starts on the last visible char... and the bottom border is 0? The top border in this case is 4 chars?
I have some display problems in my emu in this case, because the bottom border was calculated as -1...
I don't know if i will say that correctly but...
On a "normal" screen with R4 at 38, the "vsync zone" is always physically at the same place on the monitor.
So when changing R7, everything is shifted relative to this vsync position (you can imagine it at the bottom of the monitor, or at the top like on grimware image, but "outside of it").
Just wondering if you ever solved your problem. If you're still stuck, I'll just explain what these numbers actually mean because if you actually truly understand what's going on, you'll be better placed to write your emulator...
R4 is the total number of character lines in a screen, including visible and non-visible lines. The important thing to remember is that (R4+1)*(R9+1)+R5=312. In other words, number of character lines * pixel lines per character line + adjustment = 312.
From the point of view of the CRTC, when all the registers reset to 0, it enables the output. It then cycles through each character line until it reaches R4, then adds R5 worth of spare lines (this is often 0 on the CPC except for in demos) and then resets again. For each character line, it similarly outputs a pixel line, increments the pixel line counter until it reaches R7, at which point it resets to 0 and moves to the next character line. For each pixel line, it does the same thing for character columns (R0 in this case).
So, the visible columns go from 0 to R1 and visible rows go from 0 to R6, and when the counter reaches either of these conditions the display is turned off, for the columns it's turned off until the column counter is reset to 0 and for the rows until the column counter is reset to 0.
Now, that's all fine and well, but as you know, the picture starts offset into the screen, so we now need to consider how the screen reacts to the signal.
The simplest case is actually the horizontal sync. When the monitor detects that the SYNC has gone low for more than about 4us, it starts the line flyback, i.e. the beam moves back to the left of the screen in the border. You'll see the HSYNC is actually 14us in that example picture. The monitor's PLL actually reacts to the SYNC by effectively averaging its idea of the HSYNC with the one the computer is sending and so this tends to react to the middle of the pulse. So, you can think that about 7us after the HSYNC, the beam is at its furthest left point. It then proceeds linearly across the screen, taking 64us to complete the line, and in the normal case where the HSYNC from the CPC is exactly 64us later, these will be exactly in sync again as you'd expect. Now look back at the picture, and you'll see that the middle of the HSYNC is actually after cell 52. So, there are another 11us before the CRTC resets back to character 0 (the left border) which roughly equals the 13us between the end of cell 39 and the end of cell 52 (the right border).
So, from that description, you should be able to understand how increasing R2 increases the size of the right border and decreases the size of the left border and decreasing has the opposite effect. You can even put the HSYNC in the middle of the visible region if you like which will given you a border in the middle and visible areas on either side.
The vertical sync is done very similarly, except it looks for a longer sync pulse than the horizontal sync, typically at least 8 pixel lines is needed.
So, for your emulator, if you want to do it accurately, you have to emulate each instruction's timing carefully, and after each instruction emulate the video signal for the correct number of cycles. It's probably easiest to emulate it at the signal level, so for each pixel you generate R,G,B,HS,VS signals and pass them to the video emulator which reconstructs the frame from that. This way, you'll correctly emulate palette changes and all the tricky scrolling effects... :)
If you want to do it more simply at first, you could render into an image where (0,0) represents the top left of the visible area and draw into that each pixel. When you come to draw it, you can then split that horizontally at (R0+1)*8+(R3&15)/2 and draw everything to the right of that line from 0 and everything to the left of that line next. Similarly vertically, you'd split at (R7+1)*(R9+1)+some_value and draw everything above that at the top and everything below at the bottom. You wouldn't correctly emulate scrolling and variable width screen tricks this way though.
Hope some of that helped!
This from an anonymous source, but with added display of coordinates.
It seems to fit in with what you're looking at and mess about.
10 ' *** use arrow keys to float about, can be messy
20 MODE 2:ON BREAK GOSUB 210
30 OUT &BC00,3:OUT &BD00,5
50 x=46:y=30:BORDER 2
60 IF INKEY(0)>-1 THEN y=y+1
70 IF INKEY(2)>-1 THEN y=y-1
80 IF INKEY(8)>-1 THEN x=x+1
90 IF INKEY(1)>-1 THEN x=x-1
100 IF x=64 THEN x=0
110 IF x=-1 THEN x=63
120 IF y=39 THEN y=0
130 IF y=-1 THEN y=38
140 OUT a,2:OUT b,x
150 OUT a,7:OUT b,y
160 LOCATE 2,2:PRINT "x=";x;:LOCATE 10,2:PRINT "y=";y;
170 LOCATE 65,2:PRINT "x=";x;:LOCATE 75,2:PRINT "y=";y;
180 LOCATE 2,24:PRINT "x=";x;:LOCATE 10,24:PRINT "y=";y;
190 LOCATE 65,24:PRINT "x=";x;:LOCATE 75,24:PRINT "y=";y;
200 GOTO 60
A child of five could understand this! Fetch me a child of five ;-)
Line 80 has two missing characters:
80 IF INKEY(8)>-1 THEN x=x+1
Thanks Morn, for picking that up :-)
Corrected now in the original code window.
The program and the text used for copying check out OK.
Do characters get dropped occasionally when pasting code, so that one should always double-check?
That could happen when using <xmp> to port basic code to html, but there seems nothing offensive here.
Will pay more attention anyways.
I'm resurrecting this "old" topic to say a few things. The first one is obviously "thanks" to everyone who replied. I didn't read the thread at the time (sorry!), because I left the development of the emulator some months ago, but now I've picked up the project again :P
Ralferoo, thanks for your long explanation, I think I've understood the basics of the CRTC. But I've tried the BASIC listing (thanks copychr$!), and my emulator is doing VERY weird things when I move the screen. I'm trying to fix that now :D
BTW, I've noticed another bug in my emulator: when I change the border in BASIC, it doesn't change... unless I switch modes. It works if I "out" the right values to the Gate Array (and the colors at the border change when I load a Turbo game from tape), but I think BASIC holds the colors, and it keeps changing them every VSYNC (and that's why border flashing works), right? Does anyone knows where's the routine that refreshes the colors? I've tried to follow &BC38 (SCR SET BORDER), but it's a bit... "convoluted" :P
I think interrupts are working, because events are working...