include "propeller.i" ' Defines some register names zero = OUTB ' This register is always 0 SERIALTIME = 70937904 / 38400 ' My system clock is 16 x 4.43 MHz ' ****** Cog 0 - Control ************************************************** org 0 jmp #entry byte XTAL1 + PLL16X byte 0 ' checksum word @progbase ' program base word @progend ' variable base word @progend + 8 ' stack base word @spincode ' spin entry point word @progend + 12 ' stack end progbase word @progend - @progbase ' object size byte 2, 0 word @spincode - @progbase ' pointer to first method word 0 ' number of variables spincode byte 0x35, 0x35, 0x35, 0x2c entry ' Set up the serial port mov DIRA, =1 << 30 mov OUTA, =1 << 30 ' Main (or Measurement) loop. mloop ' First, each cog runs a disturbance program, which holds ' off for a random interval of time, and then configures ' PLLA to run at a random frequency. ' The idea is, that if the PLLs need a couple of ' milliseconds to stabilize, as suggested by Chip ' Gracey's comments, then their previous configuration ' might linger across a coginit, and affect the ' synchronisation code. coginit ci_disturb1 coginit ci_disturb2 coginit ci_disturb3 coginit ci_disturb4 coginit ci_disturb5 coginit ci_disturb6 coginit ci_disturb7 ' Wait until all the disturbance programs have completed. call #awaitresult call #clearresult ' All cogs should start at the same system clock value, to ' eliminate hub synchronisation issues, which are outside ' the scope of this investigation (and well documented). ' Here, we prepare such a clock value and write it into ' the cog program. mov temp, CNT add temp, =512 * 16 + 200 wrlong temp, =@firstcnt ' Launch the sync program in seven instances. coginit ci_sync1 coginit ci_sync2 coginit ci_sync3 coginit ci_sync4 coginit ci_sync5 coginit ci_sync6 coginit ci_sync7 ' Wait for them to complete. call #awaitresult ' Loop through the results, which are stored in an array ' at "result", and report them as hexadecimal values ' over the serial port. These numbers indicate how much ' the system clock has advanced during the synchronisation, ' and should be no further apart than 1. mov count, #7 mov addr, #@result :report rdlong temp, addr add addr, #4 mov nibbles, #8 :nibble rol temp, #4 mov char, temp and char, #15 cmp char, #10 wc if_c add char, #$30 if_nc add char, #$61 - 10 call #putser djnz nibbles, #:nibble mov char, #$20 call #putser djnz count, #:report mov char, #$0a call #putser call #clearresult ' All done. Repeat the process indefinitely. jmp #mloop ' A subroutine for holding off execution until ' all values in the "result" array are non-zero. awaitresult mov count, #7 mov addr, #@result :loop rdlong temp, addr tjz temp, #awaitresult add addr, #4 djnz count, #:loop awaitresult_ret ret ' A subroutine for clearing the "result" array. clearresult mov count, #7 mov addr, #@result :loop wrlong zero, addr add addr, #4 djnz count, #:loop clearresult_ret ret ' This code transmits a byte over the serial interface. putser or char, #$100 shl char, #1 mov bits, #10 mov CNT, CNT add CNT, =SERIALTIME :bits shr char, #1 wc muxc OUTA, =1 << 30 waitcnt CNT, =SERIALTIME djnz bits, #:bits putser_ret ret ' Specification words for coginit. ci_sync1 long @sync >> 2 << 4 | (@result + 0) >> 2 << 18 | 1 ci_sync2 long @sync >> 2 << 4 | (@result + 4) >> 2 << 18 | 2 ci_sync3 long @sync >> 2 << 4 | (@result + 8) >> 2 << 18 | 3 ci_sync4 long @sync >> 2 << 4 | (@result + 12) >> 2 << 18 | 4 ci_sync5 long @sync >> 2 << 4 | (@result + 16) >> 2 << 18 | 5 ci_sync6 long @sync >> 2 << 4 | (@result + 20) >> 2 << 18 | 6 ci_sync7 long @sync >> 2 << 4 | (@result + 24) >> 2 << 18 | 7 ci_disturb1 long @disturb >> 2 << 4 | (@result + 0) >> 2 << 18 | 1 ci_disturb2 long @disturb >> 2 << 4 | (@result + 4) >> 2 << 18 | 2 ci_disturb3 long @disturb >> 2 << 4 | (@result + 8) >> 2 << 18 | 3 ci_disturb4 long @disturb >> 2 << 4 | (@result + 12) >> 2 << 18 | 4 ci_disturb5 long @disturb >> 2 << 4 | (@result + 16) >> 2 << 18 | 5 ci_disturb6 long @disturb >> 2 << 4 | (@result + 20) >> 2 << 18 | 6 ci_disturb7 long @disturb >> 2 << 4 | (@result + 24) >> 2 << 18 | 7 pool addr res 1 temp res 1 char res 1 count res 1 nibbles res 1 bits res 1 fit 496 ' ****** Hub memory variables ********************************************* shiftreg long 1 result long 0[7] ' ****** Cog 1..7 - Disturbance program *********************************** disturb org 0 ' Hold off for a random number of system clocks, then ' configure the PLL for a random frequency. Note that ' there are no hub operations between the delay and the ' configuration, as that would introduce an unwanted ' regularity. call #random mov freq, rand_out call #random and rand_out, =$7fffff ' 0..120 ms add rand_out, #8 ' avoid race condition add rand_out, CNT waitcnt rand_out, #0 mov FRQA, freq mov CTRA, =%0_00001_111_00000000_000000_000_000000 ' Signal to cog 0 that we are done. wrlong one, PAR :done jmp #:done ' Wait forever ' Lock zero protects a global LFSR which is used to ' generate a pseudo-random bit sequence. random :getlock lockset zero wc if_c jmp #:getlock rdlong rand_bits, #@shiftreg mov rand_count, #32 :loop test rand_bits, =$a0000003 wc rcr rand_bits, #1 wc rcl rand_out, #1 djnz rand_count, #:loop wrlong rand_bits, #@shiftreg lockclr zero random_ret ret one long 1 pool rand_bits res 1 rand_count res 1 rand_out res 1 freq res 1 fit 496 ' ****** Cog 1..7 - Synchronisation code ********************************** sync org 0 ' Make sure that all cogs start at exactly the same moment. waitcnt firstcnt, #0 ' ******************************************************** ' This is where we add the synchronisation code under test ' ******************************************************** ' At this point, the video generators should be synchronised, ' and we should be able to execute waitvid instructions ' with predictable timing... waitvid zero, #0 waitvid zero, #0 waitvid zero, #0 waitvid zero, #0 waitvid zero, #0 ' ...and always end up with a consistent value for the ' system clock here, apart from single-cycle jitter. mov timediff, CNT sub timediff, firstcnt wrlong timediff, PAR :done jmp #:done ' Wait forever firstcnt long 0 pool timediff res 1 fit 496 progend