base:detect_pal_ntsc
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
base:detect_pal_ntsc [2016-12-27 02:39] – tww_ctr | base:detect_pal_ntsc [2020-11-11 01:49] (current) – [Very short full VIC-type detection] copyfault | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Detect PAL/NTSC ====== | + | ====== Detect |
- | + | ||
- | Since you cannot rely on $02a6 to detect PAL/NTSC, you better do the check yourself. The theory behind these checks is simply that PAL and NTSC systems have different ammounts of rasterlines, | + | |
+ | Since you cannot rely on $02a6 to detect NTSC/PAL, you better do the check yourself. The theory behind these checks is simply that PAL and NTSC systems have different amounts of rasterlines, | ||
===== J0x variant ===== | ===== J0x variant ===== | ||
Line 67: | Line 66: | ||
< | < | ||
+ | SEI | ||
LDX #$00 | LDX #$00 | ||
w0 LDA $D012 | w0 LDA $D012 | ||
Line 826: | Line 826: | ||
</ | </ | ||
+ | ===== When size really matters ===== | ||
+ | |||
+ | by Copyfault/ | ||
+ | |||
+ | In the following I'm going to present two routines for detecting PAL/NTSC: the first one is used for telling a EU-PAL-chip (with 63 cycles per line) apart from a "new NTSC" | ||
+ | |||
+ | The 2nd routine is capable of detecting any of the four VIC-types that have been mentioned earlier on this page (EU-PAL, NTSC old _and_ new and the one for the Drean-PAL-system). | ||
+ | |||
+ | ==== Short PAL/NTSC detection ==== | ||
+ | |||
+ | The basic idea is to constantly read the raster beam position and keeping it in a backup register until rasterline==0 (or rasterline==$100) is reached. Then the backup register holds the value of the last line that was read before reaching line 0 (or $100 resp.). | ||
+ | |||
+ | In case the last line was $ff, it does not tell much about the system at hand. Thus, the rasterline-read-and-backup-procedure is repeated until the backup value is not $ff afterwards. | ||
+ | |||
+ | The well-known table of VIC-specs now reveals that the backup value must be one of the following: | ||
+ | < | ||
+ | #$37 -> 312 rasterlines -> PAL | ||
+ | #$06 -> 263 rasterlines -> new NTSC | ||
+ | #$05 -> 262 rasterlines -> old NTSC | ||
+ | </ | ||
+ | |||
+ | It's even possible to tell new and old NTSC apart this way (not just PAL vs. NTSC as stated in the preface). The approach is NOT capable to distinguish between the different PAL-variants (PAL N as used in the Drean-systems and EU-PAL) since they have the same number of rasterlines per frame. | ||
+ | |||
+ | |||
+ | === Source Code === | ||
+ | < | ||
+ | chk: | ||
+ | ldx #$aa //$aa = TAX | ||
+ | lda $d012 | ||
+ | bne chk+1 | ||
+ | txa | ||
+ | bmi chk | ||
+ | </ | ||
+ | This routine continuously checks $D012==0 while saving the last read $D012-value in X and repeats the whole procedure when the value stored in X has the MSB set. This luckily suffices to distinguish the case "last line was $ff" from "last line was the last one of the frame", | ||
+ | |||
+ | Why that ['' | ||
+ | |||
+ | |||
+ | ==== Very short full VIC-type detection ==== | ||
+ | |||
+ | Another approach for detecting the VIC-type in the machine at hand was brought up by Krill: by a combination of waiting for a specific line and waiting for a specific number of cycles. | ||
+ | |||
+ | Before presenting a real 6510 code-snipplet, | ||
+ | < | ||
+ | wait_for_line($ff) | ||
+ | wait_for_no_of_cycles(63) | ||
+ | read_rasterline | ||
+ | </ | ||
+ | Waiting for line $ff is just an example, it could be any line, assuming we do not have badlines "in the way". Since we're going to do some cycle calculation in the following, let's also assume that no IRQs are active that might " | ||
+ | |||
+ | In the above pseudo-code we wait for line $ff and then wait for 63 cycles. | ||
+ | |||
+ | Simple question: in which raster line are we now? | ||
+ | |||
+ | Not-so-simple answer: depends on | ||
+ | - the cycle position in line $ff at which the wait_for_no_of_cycles(63) started and | ||
+ | - which VIC-type we have in our machine. | ||
+ | |||
+ | If the wait_for_line($ff) ended at cycle position 1 (not possible in reality, but let's stick to it for the moment), then after 63 cycles we are at cycle position 64 - IF it exists! Here the different no. of cycles per line come into play: on an NTSC-system, | ||
+ | |||
+ | What do we learn from this, how can we exploit this? The more cycles we wait, the bigger the difference between the cycle positions at which the wait-loop ends. One could think of the different values for no.of.cycles per frame as some kind of " | ||
+ | |||
+ | One aspect that needs extra care is the //dreaded jitter//! In reality, waiting for a specific line does not end at a fixed cycle position but rather in a certain cycle-interval (at least when performing a rasterline-wait with a simple CMP-BRANCH-loop). So we have to consider the max- and min-value of these cycle positions. The picture of the travel speed remains valid, but we have to keep in mind that not only the rasterbeam travels at a given speed but also the cycle-interval. The aim is to move this whole interval to different raster positions, depending on the VIC-type in use. | ||
+ | |||
+ | === A closer look at the wait_for_rasterline === | ||
+ | < | ||
+ | lda #$ff | ||
+ | waitraster: | ||
+ | cmp $d012 | ||
+ | bne waitraster | ||
+ | </ | ||
+ | While this is short and clean, it's not possible to completely possible to predict the cycle position of line $ff that we will find us at after the wait (the first '' | ||
+ | < | ||
+ | wait_line0: | ||
+ | lda $d012 | ||
+ | bne wait_line0 | ||
+ | lda #$ff | ||
+ | waitraster: | ||
+ | cmp $d012 | ||
+ | bne waitraster | ||
+ | </ | ||
+ | Line 0 (or $100) must be reached first before the wait-loop for line $ff starts. This ensures that the waitraster-loop starts outside of line $ff, thus running through all cycles until the desired rasterline is reached. Since a CMP $d012 takes 4 cycles and a (branching!) BNE takes 3, the best case is when the read-access of the CMP $D012 happens at cycle pos.1 of line $ff. Cycle positions 2 and 3 will be taken by the (not-taken!) branch, so the wait-loop ends at cycle pos.4. Worst case is when the read-access misses line $ff by one cycle, leading to the maximal possible delay ending at cycle pos.10. | ||
+ | |||
+ | This is the cycle-interval we have to deal with: cycle positions 4..10. Mind that these values describe the first " | ||
+ | |||
+ | === VIC-type detection via cycle-waiting - a first sketch === | ||
+ | Simplifying the line-wait a bit, let's take a closer look at the following code: | ||
+ | < | ||
+ | wait_line0: | ||
+ | ldx $d012 | ||
+ | bne wait_line0 | ||
+ | dex | ||
+ | waitraster: | ||
+ | cpx $d012 | ||
+ | bne waitraster | ||
+ | | ||
+ | ldy #$fc | ||
+ | cycle_wait_loop: | ||
+ | nop // 2 cycles | ||
+ | bit $ea // 3 cycles | ||
+ | dey // 2 cycles | ||
+ | bne cycle_wait_loop // 3 cycles (taken) | 2 cycles (not taken) | ||
+ | | ||
+ | lda $d012 // 4 cycles | ||
+ | </ | ||
+ | The waitraster-loop exits on line $ff at cycle pos.4..10. After the '' | ||
+ | |||
+ | Now we have that large loop. it runs for (2+3+2+3)*$fb + (2+3+2+2) = 10*252 - 1 = 2519 cycles. The rasterline is read four cycles later, so the read access of the lda $d012 happens 2523 cycles after the end of the waitraster-loop (cycle pos 6..12 in line $ff are the first " | ||
+ | |||
+ | Now it boils down to basic modulo-arithmetics, | ||
+ | < | ||
+ | min. cycle: | ||
+ | max. cycle: 11+2523 = 2534 = 40*63 + 14 = 39*64 + 38 = 38*65 + 64 | ||
+ | </ | ||
+ | This shows that the complete interval ends on the same rasterline: for PAL (63cyc/ | ||
+ | |||
+ | In consequence, | ||
+ | |||
+ | === Source Code === | ||
+ | The code above can be optimised at some spots. This has impact e.g. on the rasterline we start the cycle-wait in and consequently also on the rasterline that is read at the end. | ||
+ | < | ||
+ | chk_victype: | ||
+ | sei | ||
+ | ldy #$04 | ||
+ | ld_DEY: | ||
+ | ldx #DEY //DEY = $88 | ||
+ | waitline: | ||
+ | cpy $d012 | ||
+ | bne waitline | ||
+ | dex | ||
+ | bmi ld_DEY + 1 | ||
+ | cycle_wait_loop: | ||
+ | lda $d012 - $7f,x | ||
+ | dey | ||
+ | bne cycle_wait_loop | ||
+ | | ||
+ | and #$03 | ||
+ | rts | ||
+ | </ | ||
+ | Instead of having two seperate checks of a rasterline, there are several rasterline checks combined now, effectively shortening that part. The waitline ends on line $fc, which is also the starting line for the cycle-wait-loop. Since I put the '' | ||
+ | < | ||
+ | $00: EU-PAL | ||
+ | $01: NTSC old | ||
+ | $02: PAL-N | ||
+ | $03: NTSC-new | ||
+ | </ | ||
+ | Ofcourse these values depend on the rasterline that is reached after the whole wait-procedure, |
base/detect_pal_ntsc.txt · Last modified: 2020-11-11 01:49 by copyfault