; ; ; Calculate PLL setting ; ; on entry: eax = input frequency in Hz ; ebx = desired output frequency in Hz ; ecx = max allowable error in Hz ; ; on exit: eax = PLL mode with crystal bits cleared (eax[3:2]=0) ; ebx = actual output frequency in Hz ; c = 1 if setting found ; pll_calc: mov [@@xinfreq],eax mov [@@clkfreq],ebx mov [@@errfreq],ecx mov [@@found],0 ;clear the found flag in case no success mov [@@error],ecx ;set initial error allowance mov [@@pppp],0 ;sweep post divider from 1,2,4,6,..30 @@loop1: mov eax,[@@pppp] ;determine post divider value shl eax,1 jnz @@notzero inc eax @@notzero: mov [@@post],eax mov [@@divd],64 ;sweep xin divider from 64 to 1 @@loop2: mov eax,[@@xinfreq] ;fpfd = round(xinfreq / divd) mov edx,0 shl eax,1 ;x2 for later rounding rcl edx,1 div [@@divd] ;divide edx:eax by divd inc eax ;round quotient shr eax,1 mov [@@fpfd],eax mov eax,[@@clkfreq] ;mult = round(clkfreq * post / fpfd) shl eax,1 ;x2 for later rounding mul [@@post] ;multiply clkfreq by post --> edx:eax div [@@fpfd] ;divide edx:eax by fpfd inc eax ;round quotient shr eax,1 mov [@@mult],eax mov eax,[@@fpfd] ;fvco = fpfd * mult mul [@@mult] mov [@@fvco],eax mov eax,[@@fvco] ;fout = round(fvco / post) mov edx,0 shl eax,1 ;x2 for later rounding rcl edx,1 div [@@post] inc eax ;round quotient shr eax,1 mov [@@fout],eax mov eax,[@@fout] ;abse = absolute(fout - clkfreq) sub eax,[@@clkfreq] jnc @@pos neg eax @@pos: mov [@@abse],eax cmp eax,[@@error] ;does this setting have lower or same error? ja @@nope cmp [@@fpfd],250000 ;is fpfd at least 250KHz? jb @@nope cmp [@@mult],1024 ;is mult 1024 or less? ja @@nope cmp [@@fvco],99000000 ;is fvco at least 99MHz? jb @@nope cmp [@@fvco],201000000 ;is fvco no more than 201MHz? jbe @@yep mov eax,[@@clkfreq] ;is fvco no more than clkfreq + errfreq? add eax,[@@errfreq] cmp [@@fvco],eax ja @@nope @@yep: mov [@@found],1 ;found the best setting so far, set flag mov eax,[@@abse] ;update error to abse mov [@@error],eax mov eax,[@@divd] ;set the divider field dec eax shl eax,18 mov [@@mode],eax mov eax,[@@mult] ;set the multiplier field dec eax shl eax,8 or [@@mode],eax mov eax,[@@pppp] ;set the post divider field dec eax and eax,1111b shl eax,4 or [@@mode],eax or [@@mode],01000003h ;set the pll-enable bit and select the pll mov eax,[@@fout] ;save the pll frequency mov [@@freq],eax @@nope: dec [@@divd] ;decrement divd and loop if not 0 jnz @@loop2 inc [@@pppp] ;increment pppp and loop if under 16 cmp [@@pppp],16 jb @@loop1 mov eax,[@@mode] ;get mode into eax mov ebx,[@@freq] ;get freq into ebx shr [@@found],1 ;get found flag into c ret ddx @@xinfreq ddx @@clkfreq ddx @@errfreq ddx @@found ddx @@error ddx @@abse ddx @@pppp ddx @@post ddx @@divd ddx @@fpfd ddx @@mult ddx @@fvco ddx @@fout ddx @@mode ddx @@freq