It is currently Sun Dec 10, 2017 5:08 pm

All times are UTC - 7 hours



Forum rules


Related:



Post new topic Reply to topic  [ 52 posts ]  Go to page Previous  1, 2, 3, 4
Author Message
PostPosted: Thu Aug 25, 2016 9:45 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6503
Location: Seattle
As far as I know the SPC700 always uses a 24576 kHz ceramic resonator. It should have standard ceramic resonator problems (Precision of 5‰; jitter of 100ppm; drift of 1‰).

I thought I had heard someone say that one of the later variants of the SNES used a ÷7 from the master clock, but I definitely saw a ceramic resonator next to the APU for everything I could find PCB photos of.


Top
 Profile  
 
PostPosted: Fri Aug 26, 2016 1:19 am 
Offline

Joined: Fri Jul 04, 2014 9:31 pm
Posts: 818
lidnariq wrote:
Precision of 5‰; jitter of 100ppm; drift of 1‰

Ouch. Is that a standard deviation or a guaranteed performance spec?

Does anyone have better numbers for this oscillator specifically? Or is it safest to just assume it's a cheap generic part?

Quote:
I thought I had heard someone say that one of the later variants of the SNES used a ÷7 from the master clock

I think ZSNES does that, or used to. In any case that's only -1.2‰ or so, which isn't an issue...

...

Anyone know for sure what the deal is with addw? It would be great if I could just use it without worrying about the flags...


Top
 Profile  
 
PostPosted: Fri Aug 26, 2016 5:14 am 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19322
Location: NE Indiana, USA (NTSC)
lidnariq wrote:
As far as I know the SPC700 always uses a 24576 kHz ceramic resonator. It should have standard ceramic resonator problems (Precision of 5‰; jitter of 100ppm; drift of 1‰).

And if anyone else is unfamiliar with the ‰ symbol, it means "parts per thousand": 0.5% precision, 0.01% jitter, 0.1% drift. That's why a (more expensive) crystal is used instead when oscillators need to stay in phase for a couple hundred cycles, such as the QAM encoder and decoder in NTSC and PAL.

Quote:
I thought I had heard someone say that one of the later variants of the SNES used a ÷7 from the master clock

Dunno if the 1CHIP or Mini actually uses that simplification, but I've long suggested that a clone could use it and remain within spec. And 93143 is right that 135/44 MHz (master÷7) is only 0.12% off from the expected 3.072 MHz.


Top
 Profile  
 
PostPosted: Fri Aug 26, 2016 5:47 am 
Offline

Joined: Sat Apr 25, 2015 1:47 pm
Posts: 336
Location: FL
93143 wrote:
1) What is the relationship between addw, carry, and half carry? Specifically, can I simply use addw without worrying about the flag values? From what I can tell, it sets them but doesn't use them...


The addw instruction adds the low bytes without carry, then adds the high bytes with carry (in other words, you don't need to clrc first). The half carry flag might be set as a result, but doesn't affect the value.

(In other words, yes, you can use it without worrying about H/C)


Top
 Profile  
 
PostPosted: Fri Aug 26, 2016 11:13 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6503
Location: Seattle
93143 wrote:
lidnariq wrote:
Precision of 5‰; jitter of 100ppm; drift of 1‰
Ouch. Is that a standard deviation or a guaranteed performance spec?
The latter. But's not as much consolation as you'd hope, I fear.
More reading from muRata:
https://www.westfloridacomponents.com/m ... 00DETF.pdf ( page 6 contains drift characteristics, but not aging characteristics )
http://www.murata.com/~/media/webrenewa ... /p17e.ashx ( page 18 contains aging characteristics )
From Mobius:
http://web.eecs.umich.edu/~mmccorq/semi ... leUT07.pdf ( pages 32-35 show strong temperature relation )

Quote:
Does anyone have better numbers for this oscillator specifically? Or is it safest to just assume it's a cheap generic part?
muRata's only really been able to get initial as-vended precision to less than 1‰ in the past 15 years, so I think it's safe to assume that a "high precision ceramic resonator" would snarkily be called a quartz crystal.


Top
 Profile  
 
PostPosted: Fri Aug 26, 2016 3:06 pm 
Offline

Joined: Fri Jul 04, 2014 9:31 pm
Posts: 818
Revenant wrote:
The addw instruction adds the low bytes without carry, then adds the high bytes with carry (in other words, you don't need to clrc first). The half carry flag might be set as a result, but doesn't affect the value.

Awesome. That's what I figured from the docs, and from looking at higan's source code, but docs can be misleading and I don't trust myself to read someone else's C++, especially when it's so different from my own coding style...

Saves me two cycles on the tight end of the timing window. Or a lot more if you count not having to use clrv, which my code didn't do anyway...

lidnariq wrote:
93143 wrote:
Is that a standard deviation or a guaranteed performance spec?
The latter. But's not as much consolation as you'd hope, I fear.
More reading from muRata:
https://www.westfloridacomponents.com/m ... 00DETF.pdf ( page 6 contains drift characteristics, but not aging characteristics )
http://www.murata.com/~/media/webrenewa ... /p17e.ashx ( page 18 contains aging characteristics )
From Mobius:
http://web.eecs.umich.edu/~mmccorq/semi ... leUT07.pdf ( pages 32-35 show strong temperature relation )

Okay. So it's probably unwise to assume it never goes past ±6‰.

I think I can deal with that. It looks like most of the variation is manufacturing and history, and it should be possible to detect that at boot (or perhaps after a short warm-up period). I've already got two versions of the pickup loop to deal with the difference between NTSC and PAL scanline lengths, and I can do quarter-cycles as easily as half-cycles. As long as thermal drift by itself doesn't exceed 4‰ or so after the timing check, I should be fine, unless I've screwed up the cycle count...

If someone's been storing their SNES in the freezer, they shouldn't be surprised at a few audio glitches... alternately, I could retest every now and then and reupload the timing code if necessary - pretty sure I need regular sync checks anyway to schedule audio data, and if the streaming routine were double-buffered it could update itself...


Top
 Profile  
 
PostPosted: Fri Aug 26, 2016 5:52 pm 
Offline

Joined: Fri Jul 04, 2014 9:31 pm
Posts: 818
This probably feels more at home here than in the froyo thread...

The code below is supposed to be an APU-side HDMA streaming routine; it starts right after a "prepare to receive data" command is detected and processed, and ends right before jumping back to the main audio routine. Setup and communications protocols for managing streaming data requests, timing checks, etc. are out of scope for now...

As with the previous two versions, the HDMA streaming table format is as follows:
- one line containing a "prepare to receive data" command
- enough empty lines for the audio engine to notice the command and start listening for "data start" regardless of what it was doing when "prepare to receive data" was sent
- one line containing a "data start" command in byte 0, the stream ID number in byte 1, and the transfer size in scanlines in byte 2.
- the number of lines indicated by byte 2 above, containing data in all four bytes
- one line containing a "no instruction" command in at least one and possibly all four bytes
- maybe a couple of empty lines, to allow the audio engine to see the "no instruction" and go do something else
- back to top, if another transfer is desired - it should be easy to pack multiple transfers into a single indirect-addressed HDMA table
Alternately, the "no instruction" line can be replaced with a "prepare to receive data" line if back-to-back transfers are desired.

This time, I've dispensed with a layer of indirection. Instead of using the stream ID number to look up the direct-page address of the buffer pointer, I have decided that there is no reason the stream ID number can't be the direct-page address of the buffer pointer.

The result is that this version supports an effectively unlimited number of streaming buffers, without requiring the main streaming loop to be in direct page. It also dispenses with the stringent data format requirements of the second version; all that's necessary for this version is that (a) each transfer be less than 256 bytes, since X is used to increment the buffer position during the main pickup loop, and (b) the end of the buffer coincide with the end of a transfer - there's just not enough time during the pickup loop to detect and handle end-of-buffer in the middle of a transfer, so it's assumed to not happen.

As usual, I haven't tested this, so there may be errors. Does the basic concept look okay?

Code:
; BUFFER METADATA STRUCTURE (WIP):
; byte 0-1:  current buffer write position
; byte 2-3:  buffer start address
; byte 4-5:  buffer end address
; This data is stored in zero page.  More complex bookkeeping can be done elsewhere,
; so as not to waste space.

; HDMA STREAMING CODE:
data_incoming_HDMA:
   mov A, #data_start_HDMA      ; 2 cycles - load data start code value
-  cbne $F4, -                  ; 7 cycles - listen for the write
; TOTAL: roughly 3-9 cycles since data start code written to $2140

; Pick up transfer parameters written to $2141 and $2142:
   mov X, $F5                   ; 3 cycles - load direct-page address of buffer pointer
   mov temp, $F6                ; 5 cycles - load transfer size in scanlines
; TOTALS:  8 cycles since start code noticed in $F4, 11-17 cycles since $2140 written

; Now rewrite the pickup loop to target the current buffer position:
   mov A, (X)                   ; 3 cycles - get low byte of buffer address
   mov Y, $01+X                 ; 4 cycles - get high byte of buffer address
   mov !(get_data_HDMA+3), A    ; 5 cycles - write buffer address low byte
   mov !(get_data_HDMA+4), Y    ; 5 cycles - write buffer address high byte
   addw YA, one                 ; 5 cycles - "one" is a constant in zero page
   mov !(get_data_HDMA+8), A    ; 5 cycles
   mov !(get_data_HDMA+9), Y    ; 5 cycles
   addw YA, one                 ; 5 cycles
   mov !(get_data_HDMA+13), A   ; 5 cycles
   mov !(get_data_HDMA+14), Y   ; 5 cycles
   addw YA, one                 ; 5 cycles
   mov !(get_data_HDMA+18), A   ; 5 cycles
   mov !(get_data_HDMA+19), Y   ; 5 cycles
; TOTALS:  62 cycles since parameters loaded, 73-79 since start code written to $2140

; Set Y to the number of scanlines in the current transfer and set X to zero:
   mov Y, temp                  ; 3 cycles - pick up transfer size in scanlines
   mov temp, X                  ; 4 cycles - store buffer pointer address
   mov X, #$00                  ; 2 cycles - set X to zero
; TOTALS:  9 cycles since loop rewritten, 82-88 since start code written to $2140

; Ideally, one NTSC scanline should be almost exactly 65 cycles long.  The port reads
; are between cycles 3 and 30 past this point, putting them between ~18 cycles after
; the first HDMA write and about 13 cycles before the fourth one on the next line.
; That leaves room for about -6‰ to +9‰ worth of clock inaccuracy over 32 lines.
; Putting the buffer metadata in page one adds 4 cycles to the preceding code, which
; reduces the margin to about -4‰ on the slow side.

; STREAMING LOOP:
get_data_HDMA:
   mov A, $F4                   ; 3 cycles - get byte 0 of the data shot
   mov !buf+X, A                ; 6 cycles - write it to the current buffer position
   mov A, $F5                   ; 3 cycles - get byte 1
   mov !(buf+1)+X, A            ; 6 cycles - write it to the current buffer position plus one
   mov A, $F6                   ; 3 cycles - get byte 2
   mov !(buf+2)+X, A            ; 6 cycles
   mov A, $F7                   ; 3 cycles - get byte 3
   mov !(buf+3)+X, A            ; 6 cycles
   inc X                        ; 2 cycles - increment the current buffer position four times
   inc X                        ; 2 cycles
   inc X                        ; 2 cycles
   inc X                        ; 2 cycles
   [                                           ]
   [      INSERT TIME DELAY BLOCK HERE         ]
   [                                           ]
   dbnz Y, get_data_HDMA        ; 6/4 cycles - repeat for next scanline, or exit if done
; ITERATION TIME:  (50+delay) cycles if branch taken
; END STREAMING LOOP

; Allow dead space after this instruction, so the delay section can be hot-swapped
; without requiring uniform code size:
   jmp !data_finished_HDMA      ; 3 cycles

; Add X to the current buffer position and handle page rollover and end-of-buffer:
data_finished_HDMA:
   mov A, X                     ; 2 cycles - load the buffer address index into A
   mov X, temp                  ; 3 cycles - pick up the buffer pointer address
   clrc                         ; 2 cycles - clear carry
   adc A, (X)                   ; 3 cycles - add the index to the low byte of the buffer pointer
   mov (X), A                   ; 4 cycles - store the result back
   mov A, Y                     ; 2 cycles - Y should be zero after the main pickup loop
   adc A, $01+X                 ; 4 cycles - add zero to the high byte of the buffer pointer, with carry
   mov $01+X, A                 ; 5 cycles - store the result back
   cbne $05+X, done_HDMA        ; 8/6 cycles - check high byte against buffer end address
   mov A, (X)                   ; 0/3 cycles - pick up low byte
   cbne $04+X, done_HDMA        ; 0/8/6 cycles check low byte against buffer end address
   mov A, $02+X                 ; 0/0/4 cycles - if end of buffer reached, load buffer start address low byte
   mov (X)+, A                  ; 0/0/4 cycles - store to buffer pointer low byte and increment X
   mov A, $02+X                 ; 0/0/4 cycles - load buffer start address high byte
   mov (X), A                   ; 0/0/4 cycles - store to buffer pointer high byte
done_HDMA:
Code:
; TIME DELAY IN DATA PICKUP LOOP (proof of concept)
; very short - 14.5 cycles (APU oscillator -8.3‰ vs. NTSC nominal, or -17.6‰ vs. PAL nominal):
   mov A, Y                     ; 2 cycles
   and #$01                     ; 2 cycles - get bottom bit of scanline counter
   beq +                        ; 4/2 cycles (avg. 3)
   cmp A, (X)                   ; 0/3 cycles (avg. 1.5)
+  mov A, [$01+X]               ; 6 cycles

; short - 14.75 cycles (-4.4/-13.6):
   mov A, Y                     ; 2 cycles
   and #$03                     ; 2 cycles - get bottom two bits of scanline counter
   beq +                        ; 4/2 cycles (avg. 2.5)
   cmp A, (X)                   ; 0/3 cycles (avg. 2.25)
+  mov A, [$01+X]               ; 6 cycles

; NTSC - 15 cycles (-0.5/-9.7):
   cmp (X), (Y)                 ; 5 cycles
   cmp (X), (Y)                 ; 5 cycles
   cmp (X), (Y)                 ; 5 cycles

; intermediate - 15.25 cycles (+3.3/-5.9):
   mov A, Y                     ; 2 cycles
   and #$03                     ; 2 cycles
   bne +                        ; 4/2 cycles (avg. 3.5)
   cmp A, (X)                   ; 0/3 cycles (avg. 0.75)
+  nop                          ; 2 cycles
   cmp (X), (Y)                 ; 5 cycles

; PAL - 15.5 cycles (+7.2/-2.0):
   mov A, Y                     ; 2 cycles
   and #$01                     ; 2 cycles
   beq +                        ; 4/2 cycles (avg. 3)
   cmp A, (X)                   ; 0/3 cycles (avg. 1.5)
+  nop                          ; 2 cycles
   cmp (X), (Y)                 ; 5 cycles

; long - 15.75 cycles (+11.0/+1.8):
   mov A, Y                     ; 2 cycles
   and #$03                     ; 2 cycles
   beq +                        ; 4/2 cycles (avg. 2.5)
   cmp A, (X)                   ; 0/3 cycles (avg. 2.25)
+  nop                          ; 2 cycles
   cmp (X), (Y)                 ; 5 cycles

; very long - 16 cycles (+14.9/+5.6):
   cmp (X), (Y)                 ; 5 cycles
   cmp (X), (Y)                 ; 5 cycles
   mov A, [$01+X]               ; 6 cycles


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 52 posts ]  Go to page Previous  1, 2, 3, 4

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group