📄 usbdrvasm128.inc
字号:
breq unstuff0c ;[04] in phase, USBIN ;[05] <- phase rjmp 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 true rjmp se0AndStore ;[03] executed only if both bits 0bit0IsSet: ifrclr phase, USBMINUS ;[04] check phase only if D- changed lpm ;[05] in phase, USBIN ;[06] <- phase (one cycle too late) ori shift, 1 << 0 ;[07]bit1AfterSet: andi phase, USBMASK ;[08] ifioclr USBIN, USBMINUS ;[09] <--- sample 1 rjmp bit1IsClr ;[10] andi shift, ~(7 << 1) ;[11] breq unstuff1s ;[12] in phase, USBIN ;[13] <- phase nop ;[14] rjmp bit2AfterSet ;[15]unstuff1s: in phase, USBIN ;[14] <- phase (one cycle too late) andi fix, ~(1 << 1) ;[15] nop2 ;[08] nop2 ;[10]bit1IsClr: ifrset phase, USBMINUS ;[12] check phase only if D- changed lpm ;[13] in phase, USBIN ;[14] <- phase (one cycle too late) breq se0AndStore ;[15] if we come from unstuff1s, Z bit is never set ori shift, 1 << 1 ;[16]bit2AfterClr: ifioset USBIN, USBMINUS ;[17] <--- sample 2 rjmp bit2IsSet ;[18] andi shift, ~(7 << 2) ;[19] breq unstuff2c ;[20] in phase, USBIN ;[21] <- phase rjmp 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- changed lpm ;[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 3 rjmp bit3IsClr ;[27] andi shift, ~(7 << 3) ;[28] breq unstuff3s ;[29] in phase, USBIN ;[30] <- phase rjmp 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- changed lpm ;[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 x2 ifioset USBIN, USBMINUS ;[34] <--- sample 4 rjmp bit4IsSet ;[35] andi shift, ~(7 << 4) ;[36] breq unstuff4c ;[37] in phase, USBIN ;[38] <- phase rjmp 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- changed lpm ;[38] in phase, USBIN ;[39] <- phase (one cycle too late) ori shift, 1 << 4 ;[40]bit5AfterSet: ser data ;[41] ifioclr USBIN, USBMINUS ;[42] <--- sample 5 rjmp bit5IsClr ;[43] andi shift, ~(7 << 5) ;[44] breq unstuff5s ;[45] in phase, USBIN ;[46] <- phase rjmp 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- changed lpm ;[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 6 rjmp bit6IsSet ;[52] andi shift, ~(3 << 6) ;[53] cpi shift, 2 ;[54] in phase, USBIN ;[55] <- phase brlt unstuff6c ;[56] rjmp bit7AfterClr ;[57]unstuff6c: andi fix, ~(1 << 6) ;[50] lpm ;[51]bit6IsSet: ifrclr phase, USBMINUS ;[54] check phase only if D- changed lpm ;[55] in phase, USBIN ;[56] <- phase (one cycle too late) ori shift, 1 << 6 ;[57]bit7AfterSet: ifioclr USBIN, USBMINUS ;[59] <--- sample 7 rjmp bit7IsClr ;[60] andi shift, ~(1 << 7) ;[61] cpi shift, 4 ;[62] in phase, USBIN ;[63] <- phase brlt unstuff7s ;[64] rjmp bit0AfterSet ;[65] -> [00] == [67]unstuff7s: andi fix, ~(1 << 7) ;[58] nop ;[59] rjmp bit7IsClr ;[60]macro POP_STANDARD ; 14 cycles pop r0 pop cnt pop x3 pop x2 pop x1 pop shift pop YH endmmacro POP_RETI ; 5 cycles pop YL out SREG, YL pop YL endm#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 stuffDelay nop ;[00] stuffing consists of just waiting 8 cycles rjmp 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 0 ldi 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 SOP ori x2, USBMASK ;[-9] sbi USBOUT, USBMINUS ;[-8] prepare idle state; D+ and D- must have been 0 (no pullups) out USBDDR, x2 ;[-6] <--- acquire bus in x1, USBOUT ;[-5] port mirror for tx loop ldi 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 bit ror shift ;[01] brcc doExorN2 ;[02] subi x3, 1 ;[03] brne commonN2 ;[04] lsl shift ;[05] compensate ror after rjmp stuffDelay rjmp 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 = 1 out USBOUT, x1 ;[09] [17] <--- set bit brcs 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 stuffDelay nop ;[50] stuffing consists of just waiting 8 cycles rjmp 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 bit brcc doExor7 ;[52] subi x3, 1 ;[53] brne common7 ;[54] lsl shift ;[55] compensate ror after rjmp stuffDelay rjmp 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 bit brne 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 address subi YL, 2 + 0 ;[06] Only assign address on data packets, not ACK/NAK in r0 sbci 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 handshake breq skipAddrAssign ;[01] sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longerskipAddrAssign:;end of usbDeviceAddress transfer ldi x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag USB_STORE_PENDING(x2) ;[04] ori x1, USBIDLE ;[05] in x2, USBDDR ;[06] cbr x2, USBMASK ;[07] set both pins to input mov x3, x1 ;[08] cbr x3, USBMASK ;[09] configure no pullup on both pins lpm ;[10] lpm ;[13] out USBOUT, x1 ;[16] <-- out J (idle) -- end of SE0 (EOP signal) out USBDDR, x2 ;[17] <-- release bus now out USBOUT, x3 ;[18] <-- ensure no pull-up resistors are active rjmp 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] <--- sample rjmp bit#IsClr ;[01] andi shift, ~(7 << #) ;[02] breq unstuff#s ;[03] in phase, USBIN ;[04] <- phase rjmp 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- changed lpm ;[04] in phase, USBIN ;[05] <- phase (one cycle too late) ori shift, 1 << # ;[06]<?php }else{?> ifioset USBIN, USBMINUS ;[00] <--- sample rjmp bit#IsSet ;[01] andi shift, ~(7 << #) ;[02] breq unstuff#c ;[03] in phase, USBIN ;[04] <- phase rjmp 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- changed lpm ;[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";}?>*****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -