; ================================================================= ; ; Usb_enum.ASM ; Firmware for the 8x930Ax. Ax2, Ax3 and Ax4 to perform USB ; enumeration. It is to be programmed into a 32 Kbyte EPROM ; of the Evaluation kit to be used as a USB Test Deivce ; ; rev 1.0 (3 Mar 97) ; ; ==================================================================== INCLUDE "8x930Ax.h" FIFO_SIZE equ 008h GET_COMMAND equ 080h SETUP_PHASE equ 000h DATA_PHASE equ 001h STATUS_PHASE equ 002h EP0_MAX_PACKET_SIZE equ 08h NULL_DATA_PACKET equ 000h org 0ff:7ff8H db 0D6h ;congifuration bytes ; Binary, Mode-Paged Mode, etc db 0EFh ;; org 00:4000H ; if use PLC and RISM org 0ff:0000H ljmp main ;; org 00:4043H org 0ff:0043H ljmp SOF_ISR ;; org 00:404BH org 0ff:004BH ljmp FUNCTION_ISR ;; org 00:4080H org 0ff:0080H ;================================================================= ; Main ; main: mov SP, #00h mov SPH, #01h ; Set the stack to start @ 00:0500h mov DPXL, #0ffh ; Set DPXL to point at the FLASH device ; to access constants Init_Variables: mov R0, #00h mov Beat1, R0 mov Beat1+1, R0 ; zeroing counter mov SetupRxFlag, R0 ; SetupSeq is set to mov SetupTxFlag, R0 ; Setup_PHASE mov ControlBuffLocation, R0 ; zeroing pointer mov ControlBuffLocation+1, R0 mov ControlBuffLocation+2, R0 mov ControlBuffBytesLeft, R0 ; zeroing counter mov WR0, #0 ; zeroing counter mov WR2, WR0 Init_Usb: ; configure endpoint 0 (EP0) mov EPINDEX, #00 ; select EP0 nop nop mov EPCON, #3Fh ; enables as control endpoint ; single packet mode, receive enabled ; and transmit enabled orl FIE, #03h ; enable EP0 TX & RX interrupts. setb IEN1.1 ; enable interrupts setb SOFIE ; enable SOF interrupt setb IEN1.0 ; enable SOF ISR setb EA ; enable glabal interrupts mov p1, #00H ; P1 is the LED indicator in eval kit CLR LC ; increase the CPU speed from 3 MHz to 12 MHz ljmp Idle_loop ;================================================================= ; Idel_loop ; device looping here awating interrupts ; Idle_loop: nop nop ; can implement user applications here ... nop LedBeat: mov WR0, Beat1 inc WR0, #1 mov Beat1, WR0 cmp WR0, #7FFFh jl ClrBit setb P1.0 ljmp Idle_loop ClrBit: clr P1.0 ljmp Idle_loop ; =================================================================== ; FUNCTION_ISR ; device jumps here when a receive done or transmit done interrupt ; occurs ; FUNCTION_ISR: push ACC push B push EPINDEX CheckInterruptSource: F_EP0_RX: jnb FRXD0, F_EP0_TX mov EPINDEX,#00 lCall SetupOutToken ; 930Ax has received a packet from host PC F_EP0_TX: jnb FTXD0, F_EP1_TX mov EPINDEX,#00 lCall InReceived ; 930Ax has sent a packet to host PC F_EP1_TX: EXIT_FUNCTION_ISR: pop EPINDEX pop B pop ACC reti ; =================================================================== ; SOF_ISR at every 1ms ; do nothing here for our example ; SOF_ISR: clr ASOF cpl p1.3 ; complement p1.3 as indication reti ; =================================================================== ; SetupOutToken ; check whether a Setup or an OUT token is received ; SetupOutToken: anl SBI, #EP0_RX_CLR ; Clear the interrupt bit. ljmp ProcCommand ProcCommand: mov A, RXSTAT jnb ACC.6, CheckOutStatusPhase ; check if this is a setup packet?? mov A, TXFLG anl A, #0C0h jZ NoEP0Error NoEP0Error: lCall SetupReceived ;; !!! moved setb RXFFRC ; Update receive FIFO state ;; !!! moved clr RXSETUP ljmp ReturnProcessOutToken CheckOutStatusPhase: mov A, SetupRxFlag cjne A, #STATUS_PHASE, OutReceived ; the status phase of a "GET" command? setb RXFFRC ; Update receive FIFO state setb TXCLR ; Flush the Transmit FIFOS in case ; a null packet is still left. mov A, #SETUP_PHASE ; Update the flag mov SetupRxFlag, A mov SetupTxFlag, A ljmp ReturnProcessOutToken ;--------------------------------------------------------------- ; Control Write Data Stage ; ; If this is a control write command with a datastage then this ; routine will be called on all data stages of the control write. ; When all the data has been collected(Bytes received=wLength) ; the actual routine is called. The size of data is limited to this ; buffer length. ; The code must then call SetUpControlWriteStatusStage to allow ; the status stage to continue. OutReceived: cjne A, #DATA_PHASE, ReturnProcessOutToken ; Are we processing a Control Write, i.e. Set Descriptor... ; Added to handle control writes with data stages. ; When a control Write with a data stage is detected ; the data is placed in the buffer 'CntlWriteDataBuffer' push R0 mov A, #CntlWriteDataBuffer ; Get location of buffer add A, CntlWriteDataPntr ; Add the offset mov R0, A ; R0 now contains the location to start storing the data. ; Update the data stored in memory mov A, RXCNT ; Get number of bytes to move add A, CntlWriteDataPntr ; Add number received mov CntlWriteDataPntr, A ; update memory variable mov A, RXCNT JZ RdDone ; If no data in the buffer, then exit. ReadData: mov @R0, RXDAT ; Get the data and store it. inc R0 djnz ACC, ReadData pop R0 RdDone: setb RXFFRC ; Update receive FIFO state ; Now check to see if this was the last ; read by checking if (Bytes received=wLength) mov A, CntlWriteDataPntr cjne A, wLength+1, NeedMoreData ; If this is not equal to the expected, then ljmp around. ProcessControlWriteData: push DPX ; Processing the jump table will ; corrupt DPX. Save it here lcall Ch9Decode ; proceed to process it pop DPX ; Restore DPX ljmp ReturnProcessOutToken NeedMoreData: CheckCommand2: ReturnProcessOutToken: Ret ; =================================================================== ; SetupReceived ; device braches here when a setup token received ; SetupReceived: mov A, RXCNT0 ; Get the no. of bytes clr CY subb A, #8 ; 8 is length of all setup packets. JNZ ReturnSetup ; If less than 8 bytes recd. ; Return clr EDOVW mov COMMAND_BUFFER, RXDAT0 ; bmRequestType mov COMMAND_BUFFER+1, RXDAT0 ; bRequest mov COMMAND_BUFFER+3, RXDAT0 ; wValue LSB mov COMMAND_BUFFER+2, RXDAT0 ; wValue MSB mov COMMAND_BUFFER+5, RXDAT0 ; wIndex LSB mov COMMAND_BUFFER+4, RXDAT0 ; wIndex MSB mov COMMAND_BUFFER+7, RXDAT0 ; wLength LSB mov COMMAND_BUFFER+6, RXDAT0 ; wLength MSB push DPX ; Processing the jump table will ; corrupt DPX. Save it here setb RXFFRC ;; !!! moved here for OHCI systems clr RXSETUP ;; !!! ditto lCall ProcessSetup pop DPX ; Restore DPX ReturnSetup: Ret ; =================================================================== ; Process Setup ; decode the setup packet received ; ProcessSetup: mov ControlBuffBytesLeft, #00h mov ControlBuffBytesLeft + 1, #00h mov A, bmRequestType jb ACC.7, SetupGetCommand SetupSetCommand: mov SetupRxFlag, #DATA_PHASE ; Advance flag to next state mov SetupTxFlag, #STATUS_PHASE ; Now check to see if this is a control write with a data stage. mov A, wLength orl A, wLength+1 jz Ch9Decode ; If this is a no data command then process it mov CntlWriteDataPntr, #0 ; Initilize the data pointer for future control write ; data stages. ret ; If we are expecting data then don't ; process the command yet. ret and wait ; for the rest of the data to come in SetupGetCommand: mov SetupRxFlag, #STATUS_PHASE ; Advance flag to next state mov SetupTxFlag, #DATA_PHASE ; ================================================= ; Ch9Decode ; to decode the bMRequestType according to chapter 9 of the USB spec ; we decode the bmRequestType first ; Ch9Decode: mov A, bmRequestType ; Get the value. ; check standards commands ?? jb ACC.6, OthersCommands jb ACC.5, OthersCommands ; divide into set or get commands jb ACC.7, GetCommands ljmp SetCommands GetCommands: anl ACC, #1FH ; ignore bit 5,6,7 bit since they have been decoded cjne A, #00H, next_c01 ljmp StandardGetDeviceCommand next_c01: cjne A, #01H, next_c02 ljmp StandardGetInterfaceCommand next_c02: cjne A, #02H, next_c03 ljmp StandardGetEndpointCommand next_c03: cjne A, #03H, next_c04 ljmp StandardGetOtherCommand next_c04: ljmp OthersCommands SetCommands: anl ACC, #1FH ; ignore bit 5,6,7 bit since they have been decoded cjne A, #00H, next_c11 ljmp StandardSetDeviceCommand next_c11: cjne A, #01H, next_c12 ljmp StandardSetInterfaceCommand next_c12: cjne A, #02H, next_c13 ljmp StandardSetEndpointCommand next_c13: cjne A, #03H, next_c14 ljmp StandardSetOtherCommand next_c14: OthersCommands: ; not implemented yet ret ; =================================================================== ; STANDARD COMMANDS ; further decode the standards commands ; StandardGetDeviceCommand: mov A, bRequest cjne A, #GET_DESCRIPTOR, CheckGetConfiguration mov A, bDescriptorType cjne A, #DEVICE_DESCR, CheckConfigDescriptor ; ---- GET DESCRIPTOR, DEVICE ------- mov ControlBuffLocation, #LOW HIGH16(BEGIN_DEVICE_DESCRIPTOR) mov ControlBuffLocation+1, #HIGH LOW16(BEGIN_DEVICE_DESCRIPTOR) mov ControlBuffLocation+2, #LOW LOW16(BEGIN_DEVICE_DESCRIPTOR) mov A, #12h mov B, #00h ljmp LoadBuffer CheckConfigDescriptor: cjne A, #CONFIG_DESCR, CheckStringDescriptor ; ----- GET DESCRIPTOR, CONFIGURATION ----- mov ControlBuffLocation, #LOW HIGH16(BEGIN_CONFIG_DESCRIPTOR) mov ControlBuffLocation+1, #HIGH LOW16(BEGIN_CONFIG_DESCRIPTOR) mov ControlBuffLocation+2, #LOW LOW16(BEGIN_CONFIG_DESCRIPTOR) mov A, #LOW (END_CONFIG_DESCRIPTOR - BEGIN_CONFIG_DESCRIPTOR) mov B, #HIGH (END_CONFIG_DESCRIPTOR - BEGIN_CONFIG_DESCRIPTOR) ljmp LoadBuffer CheckStringDescriptor: cjne A, #STRING_DESCR, ReturnBADSTDGetDeviceCommand ; -------- GET DESCRIPTOR, CONFIGURATION ------- mov ControlBuffLocation, #LOW HIGH16(STRING_1) mov ControlBuffLocation+1, #HIGH LOW16(STRING_1) mov ControlBuffLocation+2, #LOW LOW16(STRING_1) mov A, #LOW (STRING_2-STRING_1) mov B, #HIGH(STRING_2-STRING_1) ljmp LoadBuffer LoadBuffer: ; Compare to see which is shorter. ; The amount asked for or the amount ; availible. push ACC push B clr CY ; A=Actual-wLength=AskedFor subb A, wLength+1 mov A, B subb A, wLength jc AskedFor_IsLarger LengthsMatch: wLengthIsSmaller: ; If Asked for is smaller, replace ; actual with asked for. pop B pop ACC mov B, wLength mov A, wLength+1 ljmp LoadIt AskedFor_IsLarger: pop B pop ACC LoadIt: ; From now on, wLength = bytes remaining. mov ControlBuffBytesLeft, B mov ControlBuffBytesLeft+1, A lCall LoadControlTXFifo ljmp ReturnSTDGetDeviceCommand CheckGetConfiguration: cjne A, #GET_CONFIGURATION, CheckGetStatus ;------------------------------------------------ ;- GET CONFIGURATION ljmp ReturnSTDGetDeviceCommand CheckGetStatus: cjne A, #GET_STATUS, ReturnSTDGetDeviceCommand ;------------------------------------------------ ;- GET DEVICE STATUS ljmp ReturnSTDGetDeviceCommand ReturnBADSTDGetDeviceCommand: push EPINDEX mov EPINDEX, #01 mov TXDAT, #12h mov TXCNT, #01h pop EPINDEX orl EPCON0, #0C0h ; Stall EP0 ReturnSTDGetDeviceCommand: ret ; ============================================================= ; Standard Get Endpoint Commands ; StandardGetEndpointCommand: mov A, bRequest cjne A, #GET_STATUS, ReturnBadSTDGetEPCommand ;------------------------------------------------ ;- GET ENDPOINT STATUS mov A, wIndex + 1 anl A, #0Fh ; Mask off all but the endpoint value orl EPINDEX,A ; Point the Index register at the mov A, wIndex + 1 ; Start by clearing out R0 jb ACC.7, GetInStallStatus GetOutStallStatus: mov A, EPCON0 jnb ACC.6, NotStalled mov A, #01 ; Return Stalled ljmp DoneWithCommand GetInStallStatus: mov A, EPCON0 jnb ACC.7, NotStalled mov A, #01 DoneWithCommand: NotStalled: anl EPINDEX,#80h ; Point the index back to EP0 mov TXDAT0, A mov TXDAT0, #00h mov TXCNT0, #02 ReturnBadSTDGetEPCommand: push EPINDEX mov EPINDEX, #01 mov TXDAT, #13h mov TXCNT, #01h pop EPINDEX orl EPCON0, #0C0h ; Stall EP0 ReturnSTDGetEPCommand: Ret ; =================================================================== ; for single packer control read status ; SetUpSinglePacketControlReadStatusStage: mov wLength, #00 mov wLength+1, #00 mov SetupRxFlag, #STATUS_PHASE ; Advance flag to next state mov SetupTxFlag, #DATA_PHASE setb TXOE ; Enable data transmit Ret ; =================================================================== ; Standard Set Endpoint Command: ; StandardSetEndpointCommand: push EPINDEX mov A, wIndex+1 ; Get the endpoint of the stall to clear anl A, #0Fh ; Find out if this is an EP0 CLear Stall Command. orl EPINDEX,A ; Setup the EPINDEX to point at correct index. mov A, wValue+1 cjne A, #ENDPOINT_STALL, ReturnBadSTDSetEPCommand mov A, bRequest cjne A, #CLEAR_FEATURE, CheckSetEndpointFeature ClearEndpointFeature: ;------------------------------------------------ ;- CLEAR ENDPOINT STALL ClearEndpointStall: mov A, wIndex+1 ; Get the endpoint of the stall to clear anl A, #0Fh ; Find out if this is an EP0 CLear Stall Command. JNZ ClearNonEP0Stall anl EPCON, #03Fh ; For EP0 Clear both TX & RX stall bits ljmp ReturnSTDSetEPCommand ClearNonEP0Stall: mov A, wIndex+1 ; Get the endpoint of the stall to clear JB ACC.7, ClearInStall ; For Non EP0, examing the direction bit as well. ClearOutStall: anl EPCON0, #CLEAR_OUT_STALL_MASK ljmp ReturnSTDSetEPCommand ClearInStall: anl EPCON0, #CLEAR_IN_STALL_MASK ljmp ReturnSTDSetEPCommand CheckSetEndpointFeature: cjne A, #SET_FEATURE, ReturnBadSTDSetEPCommand SetEndpointFeature: ;------------------------------------------------ ;- SET ENDPOINT STALL SetEndpointStall: mov A, wIndex+1 ; Get the endpoint to stall JB ACC.7, SetInStall SetOutStall: orl EPCON0, #SET_OUT_STALL_MASK ljmp ReturnSTDSetEPCommand SetInStall: orl EPCON0, #SET_IN_STALL_MASK ljmp ReturnSTDSetEPCommand ReturnBadSTDSetEPCommand: push EPINDEX mov EPINDEX, #01 mov TXDAT, #14h mov TXCNT, #01h pop EPINDEX orl EPCON0, #0C0h ;Stall EP0 ReturnSTDSetEPCommand: pop EPINDEX ljmp SetUpControlWriteStatusStage ; ============================================================ ; for standard set device commands ; StandardSetDeviceCommand: mov A, bRequest cjne A, #SET_CONFIGURATION, CheckSetDeviceAddress SetDeviceConfiguration: ;------------------------------------------------ ;- SET DEVICE CONFIGURATION ljmp ReturnSTDSetDevice CheckSetDeviceAddress: cjne A, #SET_ADDRESS, ReturnBadSetDeviceCommand ;------------------------------------------------ ;- SET DEVICE CONFIGURATION ; special case: Set Address should just return. The command will be executed following ; the status stage ljmp ReturnSTDSetDevice ReturnSTDSetDevice: ljmp SetUpControlWriteStatusStage ReturnBadSetDeviceCommand: push EPINDEX mov EPINDEX, #01 mov TXDAT, #20h mov TXCNT, #01h pop EPINDEX orl EPCON0, #0C0h ; Stall Endpoint ret StandardSetInterfaceCommand: StandardGetInterfaceCommand: StandardSetOtherCommand: StandardGetOtherCommand: ret ; =================================================================== ; InReceived ; device branches here when IN token received ; InReceived: anl FIS, #EP0_TX_CLR ; clear the interrupt bit ljmp CheckInStatusPhase CheckInStatusPhase: mov A, SetupTxFlag ; read state variable cjne A, #STATUS_PHASE,SendDataBack ; Should this be the end to ; a setup sequence StatusPhaseDone: lCall CompleteSetCommand mov SetupTxFlag, #SETUP_PHASE ; Set state var. to expect setup. mov SetupRxFlag, #SETUP_PHASE ljmp ReturnProcessIn SendDataBack: cjne A, #DATA_PHASE, ReturnProcessIn lcall LoadControlTXFifo ReturnProcessIn: Ret ; =================================================================== ; CompleteSetCommand ; CompleteSetCommand: mov A, bRequest ; If this was not a Std. Set ; command then return. cjne A, #SET_ADDRESS, CheckNextCommand ;------------------------------------------------ ;- SET ADDRESS DoSetFuncAddress: mov FADDR, wValue+1 ; Set to new address ljmp ReturnCompleteSet CheckNextCommand: ReturnCompleteSet: ret ; =================================================================== ; SetUpControlWriteStatusStage ; SetUpControlWriteStatusStage: mov TXCNT0, #00 ; Setup Null Packet ; setb TXOE0 ; Enable data transmit Ret ; =================================================================== ; LoadControlTXFifo ; LoadControlTXFifo: push R0 push DPX mov DPXL, ControlBuffLocation ; Get location of data to send. mov DPH, ControlBuffLocation+1 mov DPL, ControlBuffLocation+2 mov A, ControlBuffBytesLeft ; First check to sei if any data is availble orl A, ControlBuffBytesLeft+1 ; to send. jnz CntlDataAvail mov R0, #0 ; if there is data do normal flow ljmp ControlArmTx ; if none, do null packet CntlDataAvail mov R0, #0 ; Number of bytes in FIFO- Awlays <=16 mov A, DPXL JZ DataInRAM ; =================================================================== ; Data is in ROM, use instrcutions to pull from ROM. ; DataInROM: mov A, #00h movc A, @A+DPTR ; Get Data to transmit mov TXDAT0, A inc DPTR inc R0 ; Increment the number of bytes in FIFO djnz ControlBuffBytesLeft+1, ROMCheckMaxPacket ; If not zero, the continue. ROMCheckUpper1: mov A, ControlBuffBytesLeft ; If upper byte of wLength is also zero, buffer is empty. jz ControlTxUpd ; Are we done with the buffer dec A ; If it's not zero dec. the upper byte as well. mov ControlBuffBytesLeft, A ; And store it. ROMCheckMaxPacket: cjne R0, #EP0_MAX_PACKET_SIZE, DataInROM ; Loop until FIFO is Full ljmp ControlTxUpd ; Done with this FIFO. ; =================================================================== ; Data is in RAM, use instrcutions to pull from RAM. ; DataInRAM: movx A, @DPTR ; Get Data to transmit mov TXDAT0, A inc DPTR inc R0 ; Increment the number of bytes in FIFO djnz ControlBuffBytesLeft+1, RAMCheckMaxPacket ; If not zero, the continue. RAMCheckUpper1: mov A, ControlBuffBytesLeft ; If upper byte of ControlBuffBytesLeft is also zero, buffer is empty. jz ControlTxUpd ; Are we done with the buffer dec A ; If it's not zero dec. the upper byte as well. mov ControlBuffBytesLeft, A ; And store it. RAMCheckMaxPacket: cjne R0, #EP0_MAX_PACKET_SIZE, DataInRAM ; Loop until FIFO is Full ControlTxUpd mov ControlBuffLocation+1, DPH ; Update read pointers. mov ControlBuffLocation+2, DPL ControlArmTx: mov TXCNT0, R0 ; Write count into TXCNT register setb TXOE ; Enable data transmit ReturnLoadCntl: pop DPX pop R0 Ret ; =================================================================== ; DEVICE DESCRIPTOR ; 8x930Ax is a Big Endian microcontroller. Words and DWords are stored with the ; LSB in the numerically higher address. ; FUNCTION DESCRIPTOR ; ; *** Users are required to change the descriptor accordingly *** ; BEGIN_DEVICE_DESCRIPTOR: gDevice_bLength: db 12h ;DEVICE_DESCRIPTOR_LENGTH gDevice_bDescriptorType: db DEVICE_DESCR gDevice_bcdUSB: dw 0001h ; Version 1.00 compliant ;; gDevice_bDeviceClass: db 00h gDevice_bDeviceClass: db 04h ; for testing gDevice_bDeviceSubClass: db 01h gDevice_bDeviceProtocol: db 00h gDevice_wMaxPacketSize0: db 08h ;8 byte max for EP0 gDevice_widVendor: dw 8680h ; Intel Vendor ID (8086) gDevice_widProduct: dw 4956h ; product ID ;; gDevice_widProduct: dw 8888h gDevice_bcdDevice: dw 0001h ;device version 1.00 gDevice_iManufacturer: db 0h ;These three fields are supposed gDevice_iProduct: db 0h ;to contain the index of strings gDevice_iSerialNumber: db 0h ;describing device. gDevice_bNumConfigurations: db 1 END_DEVICE_DESCRIPTOR: ;/*--------------- Initialize global Config descriptor ----------------*/ BEGIN_CONFIG_DESCRIPTOR: gConfig_bLength: db 09h gConfig_bDescriptorType: db CONFIG_DESCR gConfig_bTotalLength: db END_CONFIG_DESCRIPTOR - BEGIN_CONFIG_DESCRIPTOR gConfig_bCorrection: db 0 gConfig_bNumInterfaces: db 1 ; NUM_OF_INTERFACES; gConfig_bConfigurationValue: db 2 gConfig_iConfiguration: db 0 gConfig_bmAttributes: db 040h gConfig_MaxPower: db 025 ;50ma ; /*------------- Initialize global Interface descriptor ---------------*/ BEGIN_INTERFACE_DESCRIPTOR: gInterface_bLength: db END_INTERFACE_DESCRIPTOR - BEGIN_INTERFACE_DESCRIPTOR gInterface_bDescriptorType: db INTERFACE_DESCR gInterface_bInterfaceNumber: db 0 gInterface_bAlternateSetting: db 0 gInterface_bNumEndpoints: db 01h gInterface_bInterfaceClass: db 00h gInterface_bInterfaceSubClass: db 00h gInterface_bInterfaceProtocol: db 00h gInterface_iInterface: db 0 END_INTERFACE_DESCRIPTOR: END_CONFIG_DESCRIPTOR: STRING_LOC_TABLE: STRING_1: db LOW(STRING_2-STRING_1) db STRING_DESCR db "USB Test Firmware" STRING_2: ; =================================================================== ; RAM MEMORY MAP ;- Control varaibles need to be placed between 20h & 7fh for the addressing mode ;- If RISM is running, RISM needs 20h-3fH so be careful running RISM. ; DEFINE OUR_DATA_SEG, SPACE=DATA SEGMENT OUR_DATA_SEG ; ; Buffer and associated variables for Control Endpoint management ; SetupTxFlag: ds 1 SetupRxFlag: ds 1 COMMAND_BUFFER: StandardDeviceRequest: bmRequestType: ds 1 bRequest: ds 1 wValue: wFeatureSelector: bDescriptorType: ds 1 bDescriptorIndex: ds 1 wTargetSelector: wIndex: ds 2 wLength: ds 2 CntlWriteDataBuffer: ds 8 CntlWriteDataPntr: ds 1 ; Used to point into the CntlWriteDataBuffer. ControlBuffLocation ds 3 ControlBuffBytesLeft ds 2 Beat1: ds 2 END