Blame | Last modification | View Log | RSS feed
/* Name: usbdrvasm128.inc* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers* Author: Christian Starkjohann* Creation Date: 2008-10-11* Tabsize: 4* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)* This Revision: $Id$*//* Do not link this file! Link usbdrvasm.S instead, which includes the* appropriate implementation!*//*General Description:This file is the 12.8 MHz version of the USB driver. It is intended for usewith the internal RC oscillator. Although 12.8 MHz is outside the guaranteedcalibration range of the oscillator, almost all AVRs can reach this frequency.This version contains a phase locked loop in the receiver routine to cope withslight clock rate deviations of up to +/- 1%.See usbdrv.h for a description of the entire driver.LIMITATIONS===========Although it may seem very handy to save the crystal and use the internalRC oscillator of the CPU, this method (and this module) has some seriouslimitations:(1) The guaranteed calibration range of the oscillator is only 8.1 MHz.They typical range is 14.5 MHz and most AVRs can actually reach this rate.(2) Writing EEPROM and Flash may be unreliable (short data lifetime) sincethe write procedure is timed from the RC oscillator.(3) End Of Packet detection (SE0) should be in bit 1, bit it is only checkedif bits 0 and 1 both read as 0 on D- and D+ read as 0 in the middle. This maycause problems with old hubs which delay SE0 by up to one cycle.(4) Code size is much larger than that of the other modules.Since almost all of this code is timing critical, don't change unless youreally know what you are doing! Many parts require not only a maximum numberof CPU cycles, but even an exact number of cycles!Implementation notes:======================min frequency: 67 cycles for 8 bit -> 12.5625 MHzmax frequency: 69.286 cycles for 8 bit -> 12.99 MHznominal frequency: 12.77 MHz ( = sqrt(min * max))sampling positions: (next even number in range [+/- 0.5])cycle index range: 0 ... 66bits:.5, 8.875, 17.25, 25.625, 34, 42.375, 50.75, 59.125[0/1], [9], [17], [25/+26], [34], [+42/43], [51], [59]bit number: 0 1 2 3 4 5 6 7spare cycles 1 2 1 2 1 1 1 0operations to perform: duration cycle----------------eor fix, shift 1 -> 00andi phase, USBMASK 1 -> 08breq se0 1 -> 16 (moved to 11)st y+, data 2 -> 24, 25mov data, fix 1 -> 33ser data 1 -> 41subi cnt, 1 1 -> 49brcs overflow 1 -> 50layout of samples and operations:[##] = sample bit<##> = sample phase*##* = operation0: *00* [01] 02 03 04 <05> 06 071: *08* [09] 10 11 12 <13> 14 15 *16*2: [17] 18 19 20 <21> 22 233: *24* *25* [26] 27 28 29 <30> 31 324: *33* [34] 35 36 37 <38> 39 405: *41* [42] 43 44 45 <46> 47 486: *49* *50* [51] 52 53 54 <55> 56 57 587: [59] 60 61 62 <63> 64 65 66*****************************************************************************//* we prefer positive expressions (do if condition) instead of negative* (skip if condition), therefore use defines for skip instructions:*/#define ifioclr sbis#define ifioset sbic#define ifrclr sbrs#define ifrset sbrc/* The registers "fix" and "data" swap their meaning during the loop. Use* defines to keep their name constant.*/#define fix x2#define data x1#undef phase /* phase has a default definition to x4 */#define phase x3USB_INTR_VECTOR:;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt, r0push YL ;2 push only what is necessary to sync with edge ASAPin YL, SREG ;1push YL ;2;----------------------------------------------------------------------------; Synchronize with sync pattern:;----------------------------------------------------------------------------;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K];sync up with J to K edge during sync pattern -- use fastest possible loops;The first part waits at most 1 bit long since we must be in sync pattern.;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to;waitForJ, ensure that this prerequisite is met.waitForJ:inc YLsbis USBIN, USBMINUSbrne waitForJ ; just make sure we have ANY timeoutwaitForK:;The following code results in a sampling window of 1/4 bit which meets the spec.sbis USBIN, USBMINUSrjmp foundKsbis USBIN, USBMINUSrjmp foundKsbis USBIN, USBMINUSrjmp foundKsbis USBIN, USBMINUSrjmp foundKsbis USBIN, USBMINUS ;[0]rjmp foundK ;[1]#if USB_COUNT_SOFlds YL, usbSofCountinc YLsts usbSofCount, YL#endif /* USB_COUNT_SOF */#ifdef USB_SOF_HOOKUSB_SOF_HOOK#endifrjmp sofErrorfoundK:;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling];we have 1 bit time for setup purposes, then sample again. Numbers in brackets;are cycles from center of first sync (double K) bit after the instructionpush YH ;[2]lds YL, usbInputBufOffset;[4]clr YH ;[6]subi YL, lo8(-(usbRxBuf));[7]sbci YH, hi8(-(usbRxBuf));[8]sbis USBIN, USBMINUS ;[9] we want two bits K [we want to sample at 8 + 4 - 1.5 = 10.5]rjmp haveTwoBitsK ;[10]pop YH ;[11] undo the push from beforerjmp waitForK ;[13] this was not the end of sync, retryhaveTwoBitsK:;----------------------------------------------------------------------------; push more registers and initialize values while we sample the first bits:;----------------------------------------------------------------------------#define fix x2#define data x1push shift ;[12]push x1 ;[14]push x2 ;[16]ldi shift, 0x80 ;[18] prevent bit-unstuffing but init low bits to 0ifioset USBIN, USBMINUS ;[19] [01] <--- bit 0 [10.5 + 8 = 18.5]ori shift, 1<<0 ;[02]push x3 ;[03]push cnt ;[05]push r0 ;[07]ifioset USBIN, USBMINUS ;[09] <--- bit 1ori shift, 1<<1 ;[10]ser fix ;[11]ldi cnt, USB_BUFSIZE ;[12]mov data, shift ;[13]lsl shift ;[14]nop2 ;[15]ifioset USBIN, USBMINUS ;[17] <--- bit 2ori data, 3<<2 ;[18] store in bit 2 AND bit 3eor shift, data ;[19] do nrzi decodingandi data, 1<<3 ;[20]in phase, USBIN ;[21] <- phasebrne jumpToEntryAfterSet ;[22] if USBMINS at bit 3 was 1nop ;[23]rjmp entryAfterClr ;[24]jumpToEntryAfterSet:rjmp entryAfterSet ;[24];----------------------------------------------------------------------------; Receiver loop (numbers in brackets are cycles within byte after instr);----------------------------------------------------------------------------#undef fix#define fix x1#undef data#define data x2bit7IsSet:ifrclr phase, USBMINUS ;[62] check phase only if D- changedlpm ;[63]in phase, USBIN ;[64] <- phase (one cycle too late)ori shift, 1 << 7 ;[65]nop ;[66];;;;rjmp bit0AfterSet ; -> [00] == [67] moved block up to save jumpbit0AfterSet:eor fix, shift ;[00]#undef fix#define fix x2#undef data#define data x1 /* we now have result in data, fix is reset to 0xff */ifioclr USBIN, USBMINUS ;[01] <--- sample 0rjmp bit0IsClr ;[02]andi shift, ~(7 << 0) ;[03]breq unstuff0s ;[04]in phase, USBIN ;[05] <- phaserjmp bit1AfterSet ;[06]unstuff0s:in phase, USBIN ;[06] <- phase (one cycle too late)andi fix, ~(1 << 0) ;[07]ifioclr USBIN, USBMINUS ;[00]ifioset USBIN, USBPLUS ;[01]rjmp bit0IsClr ;[02] executed if first expr false or second truese0AndStore: ; executed only if both bits 0st y+, x1 ;[15/17] cycles after start of byterjmp se0 ;[17/19]bit0IsClr:ifrset phase, USBMINUS ;[04] check phase only if D- changedlpm ;[05]in phase, USBIN ;[06] <- phase (one cycle too late)ori shift, 1 << 0 ;[07]bit1AfterClr:andi phase, USBMASK ;[08]ifioset USBIN, USBMINUS ;[09] <--- sample 1rjmp bit1IsSet ;[10]breq se0AndStore ;[11] if D- was 0 in bits 0 AND 1 and D+ was 0 in between, we have SE0andi shift, ~(7 << 1) ;[12]in phase, USBIN ;[13] <- phasebreq unstuff1c ;[14]rjmp bit2AfterClr ;[15]unstuff1c:andi fix, ~(1 << 1) ;[16]nop2 ;[08]nop2 ;[10]bit1IsSet:ifrclr phase, USBMINUS ;[12] check phase only if D- changedlpm ;[13]in phase, USBIN ;[14] <- phase (one cycle too late)ori shift, 1 << 1 ;[15]nop ;[16]bit2AfterSet:ifioclr USBIN, USBMINUS ;[17] <--- sample 2rjmp bit2IsClr ;[18]andi shift, ~(7 << 2) ;[19]breq unstuff2s ;[20]in phase, USBIN ;[21] <- phaserjmp bit3AfterSet ;[22]unstuff2s:in phase, USBIN ;[22] <- phase (one cycle too late)andi fix, ~(1 << 2) ;[23]nop2 ;[16]nop2 ;[18]bit2IsClr:ifrset phase, USBMINUS ;[20] check phase only if D- changedlpm ;[21]in phase, USBIN ;[22] <- phase (one cycle too late)ori shift, 1 << 2 ;[23]bit3AfterClr:st y+, data ;[24]entryAfterClr:ifioset USBIN, USBMINUS ;[26] <--- sample 3rjmp bit3IsSet ;[27]andi shift, ~(7 << 3) ;[28]breq unstuff3c ;[29]in phase, USBIN ;[30] <- phaserjmp bit4AfterClr ;[31]unstuff3c:in phase, USBIN ;[31] <- phase (one cycle too late)andi fix, ~(1 << 3) ;[32]nop2 ;[25]nop2 ;[27]bit3IsSet:ifrclr phase, USBMINUS ;[29] check phase only if D- changedlpm ;[30]in phase, USBIN ;[31] <- phase (one cycle too late)ori shift, 1 << 3 ;[32]bit4AfterSet:mov data, fix ;[33] undo this move by swapping defines#undef fix#define fix x1#undef data#define data x2ifioclr USBIN, USBMINUS ;[34] <--- sample 4rjmp bit4IsClr ;[35]andi shift, ~(7 << 4) ;[36]breq unstuff4s ;[37]in phase, USBIN ;[38] <- phaserjmp bit5AfterSet ;[39]unstuff4s:in phase, USBIN ;[39] <- phase (one cycle too late)andi fix, ~(1 << 4) ;[40]nop2 ;[33]nop2 ;[35]bit4IsClr:ifrset phase, USBMINUS ;[37] check phase only if D- changedlpm ;[38]in phase, USBIN ;[39] <- phase (one cycle too late)ori shift, 1 << 4 ;[40]bit5AfterClr:ser data ;[41]ifioset USBIN, USBMINUS ;[42] <--- sample 5rjmp bit5IsSet ;[43]andi shift, ~(7 << 5) ;[44]breq unstuff5c ;[45]in phase, USBIN ;[46] <- phaserjmp bit6AfterClr ;[47]unstuff5c:in phase, USBIN ;[47] <- phase (one cycle too late)andi fix, ~(1 << 5) ;[48]nop2 ;[41]nop2 ;[43]bit5IsSet:ifrclr phase, USBMINUS ;[45] check phase only if D- changedlpm ;[46]in phase, USBIN ;[47] <- phase (one cycle too late)ori shift, 1 << 5 ;[48]bit6AfterSet:subi cnt, 1 ;[49]brcs jumpToOverflow ;[50]ifioclr USBIN, USBMINUS ;[51] <--- sample 6rjmp bit6IsClr ;[52]andi shift, ~(3 << 6) ;[53]cpi shift, 2 ;[54]in phase, USBIN ;[55] <- phasebrlt unstuff6s ;[56]rjmp bit7AfterSet ;[57]jumpToOverflow:rjmp overflowunstuff6s:andi fix, ~(1 << 6) ;[50]lpm ;[51]bit6IsClr:ifrset phase, USBMINUS ;[54] check phase only if D- changedlpm ;[55]in phase, USBIN ;[56] <- phase (one cycle too late)ori shift, 1 << 6 ;[57]nop ;[58]bit7AfterClr:ifioset USBIN, USBMINUS ;[59] <--- sample 7rjmp bit7IsSet ;[60]andi shift, ~(1 << 7) ;[61]cpi shift, 4 ;[62]in phase, USBIN ;[63] <- phasebrlt unstuff7c ;[64]rjmp bit0AfterClr ;[65] -> [00] == [67]unstuff7c:andi fix, ~(1 << 7) ;[58]nop ;[59]rjmp bit7IsSet ;[60]bit7IsClr:ifrset phase, USBMINUS ;[62] check phase only if D- changedlpm ;[63]in phase, USBIN ;[64] <- phase (one cycle too late)ori shift, 1 << 7 ;[65]nop ;[66];;;;rjmp bit0AfterClr ; -> [00] == [67] moved block up to save jumpbit0AfterClr:eor fix, shift ;[00]#undef fix#define fix x2#undef data#define data x1 /* we now have result in data, fix is reset to 0xff */ifioset USBIN, USBMINUS ;[01] <--- sample 0rjmp bit0IsSet ;[02]andi shift, ~(7 << 0) ;[03]breq unstuff0c ;[04]in phase, USBIN ;[05] <- phaserjmp bit1AfterClr ;[06]unstuff0c:in phase, USBIN ;[06] <- phase (one cycle too late)andi fix, ~(1 << 0) ;[07]ifioclr USBIN, USBMINUS ;[00]ifioset USBIN, USBPLUS ;[01]rjmp bit0IsSet ;[02] executed if first expr false or second truerjmp se0AndStore ;[03] executed only if both bits 0bit0IsSet:ifrclr phase, USBMINUS ;[04] check phase only if D- changedlpm ;[05]in phase, USBIN ;[06] <- phase (one cycle too late)ori shift, 1 << 0 ;[07]bit1AfterSet:andi shift, ~(7 << 1) ;[08] compensated by "ori shift, 1<<1" if bit1IsClrifioclr USBIN, USBMINUS ;[09] <--- sample 1rjmp bit1IsClr ;[10]breq unstuff1s ;[11]nop2 ;[12] do not check for SE0 if bit 0 was 1in phase, USBIN ;[14] <- phase (one cycle too late)rjmp bit2AfterSet ;[15]unstuff1s:in phase, USBIN ;[13] <- phaseandi fix, ~(1 << 1) ;[14]lpm ;[07]nop2 ;[10]bit1IsClr:ifrset phase, USBMINUS ;[12] check phase only if D- changedlpm ;[13]in phase, USBIN ;[14] <- phase (one cycle too late)ori shift, 1 << 1 ;[15]nop ;[16]bit2AfterClr:ifioset USBIN, USBMINUS ;[17] <--- sample 2rjmp bit2IsSet ;[18]andi shift, ~(7 << 2) ;[19]breq unstuff2c ;[20]in phase, USBIN ;[21] <- phaserjmp bit3AfterClr ;[22]unstuff2c:in phase, USBIN ;[22] <- phase (one cycle too late)andi fix, ~(1 << 2) ;[23]nop2 ;[16]nop2 ;[18]bit2IsSet:ifrclr phase, USBMINUS ;[20] check phase only if D- changedlpm ;[21]in phase, USBIN ;[22] <- phase (one cycle too late)ori shift, 1 << 2 ;[23]bit3AfterSet:st y+, data ;[24]entryAfterSet:ifioclr USBIN, USBMINUS ;[26] <--- sample 3rjmp bit3IsClr ;[27]andi shift, ~(7 << 3) ;[28]breq unstuff3s ;[29]in phase, USBIN ;[30] <- phaserjmp bit4AfterSet ;[31]unstuff3s:in phase, USBIN ;[31] <- phase (one cycle too late)andi fix, ~(1 << 3) ;[32]nop2 ;[25]nop2 ;[27]bit3IsClr:ifrset phase, USBMINUS ;[29] check phase only if D- changedlpm ;[30]in phase, USBIN ;[31] <- phase (one cycle too late)ori shift, 1 << 3 ;[32]bit4AfterClr:mov data, fix ;[33] undo this move by swapping defines#undef fix#define fix x1#undef data#define data x2ifioset USBIN, USBMINUS ;[34] <--- sample 4rjmp bit4IsSet ;[35]andi shift, ~(7 << 4) ;[36]breq unstuff4c ;[37]in phase, USBIN ;[38] <- phaserjmp bit5AfterClr ;[39]unstuff4c:in phase, USBIN ;[39] <- phase (one cycle too late)andi fix, ~(1 << 4) ;[40]nop2 ;[33]nop2 ;[35]bit4IsSet:ifrclr phase, USBMINUS ;[37] check phase only if D- changedlpm ;[38]in phase, USBIN ;[39] <- phase (one cycle too late)ori shift, 1 << 4 ;[40]bit5AfterSet:ser data ;[41]ifioclr USBIN, USBMINUS ;[42] <--- sample 5rjmp bit5IsClr ;[43]andi shift, ~(7 << 5) ;[44]breq unstuff5s ;[45]in phase, USBIN ;[46] <- phaserjmp bit6AfterSet ;[47]unstuff5s:in phase, USBIN ;[47] <- phase (one cycle too late)andi fix, ~(1 << 5) ;[48]nop2 ;[41]nop2 ;[43]bit5IsClr:ifrset phase, USBMINUS ;[45] check phase only if D- changedlpm ;[46]in phase, USBIN ;[47] <- phase (one cycle too late)ori shift, 1 << 5 ;[48]bit6AfterClr:subi cnt, 1 ;[49]brcs overflow ;[50]ifioset USBIN, USBMINUS ;[51] <--- sample 6rjmp bit6IsSet ;[52]andi shift, ~(3 << 6) ;[53]cpi shift, 2 ;[54]in phase, USBIN ;[55] <- phasebrlt unstuff6c ;[56]rjmp bit7AfterClr ;[57]unstuff6c:andi fix, ~(1 << 6) ;[50]lpm ;[51]bit6IsSet:ifrclr phase, USBMINUS ;[54] check phase only if D- changedlpm ;[55]in phase, USBIN ;[56] <- phase (one cycle too late)ori shift, 1 << 6 ;[57]bit7AfterSet:ifioclr USBIN, USBMINUS ;[59] <--- sample 7rjmp bit7IsClr ;[60]andi shift, ~(1 << 7) ;[61]cpi shift, 4 ;[62]in phase, USBIN ;[63] <- phasebrlt unstuff7s ;[64]rjmp bit0AfterSet ;[65] -> [00] == [67]unstuff7s:andi fix, ~(1 << 7) ;[58]nop ;[59]rjmp bit7IsClr ;[60]macro POP_STANDARD ; 14 cyclespop r0pop cntpop x3pop x2pop x1pop shiftpop YHendmmacro POP_RETI ; 5 cyclespop YLout SREG, YLpop YLendm#include "asmcommon.inc";----------------------------------------------------------------------------; Transmitting data;----------------------------------------------------------------------------txByteLoop:txBitloop:stuffN1Delay: ; [03]ror shift ;[-5] [11] [63]brcc doExorN1 ;[-4] [64]subi x3, 1 ;[-3]brne commonN1 ;[-2]lsl shift ;[-1] compensate ror after rjmp stuffDelaynop ;[00] stuffing consists of just waiting 8 cyclesrjmp stuffN1Delay ;[01] after ror, C bit is reliably clearsendNakAndReti:ldi cnt, USBPID_NAK ;[-19]rjmp sendCntAndReti ;[-18]sendAckAndReti:ldi cnt, USBPID_ACK ;[-17]sendCntAndReti:mov r0, cnt ;[-16]ldi YL, 0 ;[-15] R0 address is 0ldi YH, 0 ;[-14]ldi cnt, 2 ;[-13]; rjmp usbSendAndReti fallthrough; USB spec says:; idle = J; J = (D+ = 0), (D- = 1) or USBOUT = 0x01; K = (D+ = 1), (D- = 0) or USBOUT = 0x02; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles);usbSend:;pointer to data in 'Y';number of bytes in 'cnt' -- including sync byte;uses: x1...x3, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x3 = bitstuff cnt];Numbers in brackets are time since first bit of sync pattern is sent (start of instruction)usbSendAndReti:in x2, USBDDR ;[-10] 10 cycles until SOPori x2, USBMASK ;[-9]sbi USBOUT, USBMINUS ;[-8] prepare idle state; D+ and D- must have been 0 (no pullups)out USBDDR, x2 ;[-6] <--- acquire busin x1, USBOUT ;[-5] port mirror for tx loopldi shift, 0x40 ;[-4] sync byte is first byte sent (we enter loop after ror)ldi x2, USBMASK ;[-3]doExorN1:eor x1, x2 ;[-2] [06] [62]ldi x3, 6 ;[-1] [07] [63]commonN1:stuffN2Delay:out USBOUT, x1 ;[00] [08] [64] <--- set bitror shift ;[01]brcc doExorN2 ;[02]subi x3, 1 ;[03]brne commonN2 ;[04]lsl shift ;[05] compensate ror after rjmp stuffDelayrjmp stuffN2Delay ;[06] after ror, C bit is reliably cleardoExorN2:eor x1, x2 ;[04] [12]ldi x3, 6 ;[05] [13]commonN2:nop2 ;[06] [14]subi cnt, 171 ;[08] [16] trick: (3 * 171) & 0xff = 1out USBOUT, x1 ;[09] [17] <--- set bitbrcs txBitloop ;[10] [27] [44]stuff6Delay:ror shift ;[45] [53]brcc doExor6 ;[46]subi x3, 1 ;[47]brne common6 ;[48]lsl shift ;[49] compensate ror after rjmp stuffDelaynop ;[50] stuffing consists of just waiting 8 cyclesrjmp stuff6Delay ;[51] after ror, C bit is reliably cleardoExor6:eor x1, x2 ;[48] [56]ldi x3, 6 ;[49]common6:stuff7Delay:ror shift ;[50] [58]out USBOUT, x1 ;[51] <--- set bitbrcc doExor7 ;[52]subi x3, 1 ;[53]brne common7 ;[54]lsl shift ;[55] compensate ror after rjmp stuffDelayrjmp stuff7Delay ;[56] after ror, C bit is reliably cleardoExor7:eor x1, x2 ;[54] [62]ldi x3, 6 ;[55]common7:ld shift, y+ ;[56]nop ;[58]tst cnt ;[59]out USBOUT, x1 ;[60] [00]<--- set bitbrne txByteLoop ;[61] [01];make SE0:cbr x1, USBMASK ;[02] prepare SE0 [spec says EOP may be 15 to 18 cycles]lds x2, usbNewDeviceAddr;[03]lsl x2 ;[05] we compare with left shifted addresssubi YL, 2 + 0 ;[06] Only assign address on data packets, not ACK/NAK in r0sbci YH, 0 ;[07]out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:;set address only after data packet was sent, not after handshakebreq skipAddrAssign ;[01]sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longerskipAddrAssign:;end of usbDeviceAddress transferldi x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flagUSB_STORE_PENDING(x2) ;[04]ori x1, USBIDLE ;[05]in x2, USBDDR ;[06]cbr x2, USBMASK ;[07] set both pins to inputmov x3, x1 ;[08]cbr x3, USBMASK ;[09] configure no pullup on both pinslpm ;[10]lpm ;[13]out USBOUT, x1 ;[16] <-- out J (idle) -- end of SE0 (EOP signal)out USBDDR, x2 ;[17] <-- release bus nowout USBOUT, x3 ;[18] <-- ensure no pull-up resistors are activerjmp doReturn/*****************************************************************************The following PHP script generates a code skeleton for the receiver routine:<?phpfunction printCmdBuffer($thisBit){global $cycle;$nextBit = ($thisBit + 1) % 8;$s = ob_get_contents();ob_end_clean();$s = str_replace("#", $thisBit, $s);$s = str_replace("@", $nextBit, $s);$lines = explode("\n", $s);for($i = 0; $i < count($lines); $i++){$s = $lines[$i];if(ereg("\\[([0-9-][0-9])\\]", $s, $regs)){$c = $cycle + (int)$regs[1];$s = ereg_replace("\\[[0-9-][0-9]\\]", sprintf("[%02d]", $c), $s);}if(strlen($s) > 0)echo "$s\n";}}function printBit($isAfterSet, $bitNum){ob_start();if($isAfterSet){?>ifioclr USBIN, USBMINUS ;[00] <--- samplerjmp bit#IsClr ;[01]andi shift, ~(7 << #) ;[02]breq unstuff#s ;[03]in phase, USBIN ;[04] <- phaserjmp bit@AfterSet ;[05]unstuff#s:in phase, USBIN ;[05] <- phase (one cycle too late)andi fix, ~(1 << #) ;[06]nop2 ;[-1]nop2 ;[01]bit#IsClr:ifrset phase, USBMINUS ;[03] check phase only if D- changedlpm ;[04]in phase, USBIN ;[05] <- phase (one cycle too late)ori shift, 1 << # ;[06]<?php}else{?>ifioset USBIN, USBMINUS ;[00] <--- samplerjmp bit#IsSet ;[01]andi shift, ~(7 << #) ;[02]breq unstuff#c ;[03]in phase, USBIN ;[04] <- phaserjmp bit@AfterClr ;[05]unstuff#c:in phase, USBIN ;[05] <- phase (one cycle too late)andi fix, ~(1 << #) ;[06]nop2 ;[-1]nop2 ;[01]bit#IsSet:ifrclr phase, USBMINUS ;[03] check phase only if D- changedlpm ;[04]in phase, USBIN ;[05] <- phase (one cycle too late)ori shift, 1 << # ;[06]<?php}printCmdBuffer($bitNum);}$bitStartCycles = array(1, 9, 17, 26, 34, 42, 51, 59);for($i = 0; $i < 16; $i++){$bit = $i % 8;$emitClrCode = ($i + (int)($i / 8)) % 2;$cycle = $bitStartCycles[$bit];if($emitClrCode){printf("bit%dAfterClr:\n", $bit);}else{printf("bit%dAfterSet:\n", $bit);}ob_start();echo " ***** ;[-1]\n";printCmdBuffer($bit);printBit(!$emitClrCode, $bit);if($i == 7)echo "\n";}?>*****************************************************************************/