Changeset 214 in xtideuniversalbios


Ignore:
Timestamp:
Jan 18, 2012, 9:03:22 AM (12 years ago)
Author:
gregli@…
google:author:
gregli@hotmail.com
Message:

Rework of the serial write loop and read/write timeout code, resulting in significant throughput gains (increase from 8K bytes to 36K bytes, over a 460K baud link connected to a 4.77MHz 8088)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/XTIDE_Universal_BIOS/Src/Device/Serial/SerialCommand.asm

    r208 r214  
    111111;       Baud in CH until UART initialization is complete
    112112;
     113        mov     dh, ((DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT & 0f00h) >> (8+1))
     114        shl     dx, 1       ; port offset already x4, needs one more shift to be x8
    113115        mov     cl, dl
    114116
    115         and     cl, DEVICE_SERIAL_PACKEDPORTANDBAUD_BAUDMASK
    116         shl     cl, 1
     117        and     cl, (DEVICE_SERIAL_PACKEDPORTANDBAUD_BAUDMASK << 1)
    117118        mov     ch, SerialCommand_UART_divisorLow_startingBaud
    118119        shr     ch, cl
    119120        adc     ch, 0
    120121
    121         and     dl, DEVICE_SERIAL_PACKEDPORTANDBAUD_PORTMASK
    122         mov     dh, 0
    123         shl     dx, 1           ; port offset already x4, needs one more shift to be x8
    124         add     dx, DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT
    125 
    126 ;
    127 ; Buffer is referenced through ES:DI throughout, since we need to store faster than we read
    128 ;
    129         mov     di,si
     122        and     dl, ((DEVICE_SERIAL_PACKEDPORTANDBAUD_PORTMASK << 1) & 0ffh)
     123        add     dx, byte (DEVICE_SERIAL_PACKEDPORTANDBAUD_STARTINGPORT & 0ffh)
    130124
    131125        mov     al,[bp+IDEPACK.bSectorCount]
     
    145139; decided to reprogram the UART
    146140;
    147         push    dx
    148 
     141        mov     bl,dl           ; setup BL with proper values for read/write loops (BH comes later)
     142       
    149143        mov     al,83h
    150144        add     dl,SerialCommand_UART_lineControl
     
    152146
    153147        mov     al,ch
    154         pop     dx              ; divisor low
     148        mov     dl,bl           ; divisor low
    155149        out     dx,al
    156150
     
    172166        out     dx,al
    173167
     168        inc     dx              ;  linestatus (no output now, just setting up BH for later use)
     169        mov     bh,dl
     170
    174171        pop     dx              ; base, interrupts disabled
    175172        xor     ax,ax
    176173        out     dx,al
    177         dec     dx
    178 
    179 ;
    180 ; Start off with a normalized buffer pointer
    181 ;
    182         call    Registers_NormalizeESDI
    183174
    184175;----------------------------------------------------------------------
     
    189180;
    190181        push    es              ; save off real buffer location
    191         push    di
    192 
    193         mov     di,bp           ; point to IDEREGS for command dispatch;
     182        push    si
     183
     184        mov     si,bp           ; point to IDEREGS for command dispatch;
    194185        push    ss
    195186        pop     es
    196187
    197         xor     si,si           ; initialize checksum for write
    198         dec     si
    199         mov     bp,si
    200 
    201         mov     bl,03h      ; writing 3 words
    202 
    203         call    SerialCommand_WriteProtocol
    204 
    205         pop     di              ; restore real buffer location
     188        mov     di,0ffffh       ; initialize checksum for write
     189        mov     bp,di
     190
     191        mov     cx,4            ; writing 3 words (plus 1)
     192
     193        cli                     ; interrupts off...
     194
     195        call    SerialCommand_WriteProtocol.entry
     196
     197        pop     di              ; restore real buffer location (note change from SI to DI)
     198                                ; Buffer is primarily referenced through ES:DI throughout, since
     199                                ; we need to store (read sector) faster than we read (write sector)
    206200        pop     es
    207201
     202.nextSectorNormalize:           
     203
     204        call    Registers_NormalizeESDI
     205       
    208206        pop     ax              ; load command byte (done before call to .nextSector on subsequent iterations)
    209207        push    ax
     
    213211;
    214212.nextSector:
    215         xor     si,si           ; initialize checksum for read or write
    216         dec     si
     213        mov     si,0ffffh       ; initialize checksum for read or write
    217214        mov     bp,si
    218215
    219         mov     bx,0100h
     216        mov     cx,0101h        ; writing 256 words (plus 1)
    220217
    221218        shr     ah,1            ; command byte, are we doing a write?
    222         jnc     .readSector
    223         call    SerialCommand_WriteProtocol
    224 
    225         xor     bx,bx
    226 
    227 .readSector:
    228         mov     cx,bx
    229         inc     cx
    230 
    231         mov     bl,dl           ; setup bl with proper values for read loop (bh comes later)
     219        jnc     .readEntry
     220
     221        xchg    si,di
     222        call    SerialCommand_WriteProtocol.entry
     223        xchg    si,di
     224
     225        inc     cx              ; CX = 1 now (0 out of WriteProtocol)
     226        jmp     .readEntry
    232227
    233228;----------------------------------------------------------------------
     
    235230; Timeout
    236231;
    237 ; During read, we first poll in a tight loop, interrupts off, for the next character to come in
    238 ; If that loop completes, then we assume there is a long delay involved, turn interrupts back on
    239 ; and wait for a given number of timer ticks to pass.
    240 ;
    241232; To save code space, we use the contents of DL to decide which byte in the word to return for reading.
    242233;
    243234.readTimeout:
    244         push    cx
    245         xor     cx,cx
    246 .readTimeoutLoop:
    247         push    dx
    248         or      dl,SerialCommand_UART_lineStatus
    249         in      al,dx
    250         pop     dx
    251         shr     al,1
    252         jc      .readTimeoutComplete
    253         loop    .readTimeoutLoop
    254         sti
    255         mov     bh,1
    256         call    SerialCommand_WaitAndPoll_Init
    257         cli
    258 .readTimeoutComplete:
    259         mov     bh,bl
    260         or      bh,SerialCommand_UART_lineStatus
    261 
    262         pop     cx
     235        push    ax              ; not only does this push preserve AX (which we need), but it also
     236                                ; means the stack has the same number of bytes on it as when we are
     237                                ; sending a packet, important for error cleanup and exit
     238        mov     ah,1
     239        call    SerialCommand_WaitAndPoll_Read
     240        pop     ax
    263241        test    dl,1
    264242        jz      .readByte1Ready
    265         jmp     .readByte2Ready
     243        jmp     .readByte2Ready     
    266244
    267245;----------------------------------------------------------------------------
     
    282260        adc     si, 0
    283261
     262.readEntry:     
    284263        mov     dl,bh
    285264        in      al,dx
     
    317296        loop    .readLoop
    318297
    319         sti                     ; interrupts back on ASAP, if we turned them off
     298        sti                     ; interrupts back on ASAP, between packets
    320299
    321300;
     
    330309        jnz     SerialCommand_OutputWithParameters_Error
    331310
    332 ;
    333 ; Normalize buffer pointer for next go round, if needed
    334 ;
    335         test    di,di
    336         jns     .clearBuffer
    337         call    Registers_NormalizeESDI
    338 
    339311;----------------------------------------------------------------------
    340312;
     
    345317; taken care of this, but I have seen cases where this is not true.
    346318;
    347        
    348319.clearBuffer:
    349320        mov     dl,bh
     
    368339        out     dx,al           ; ACK with next sector number
    369340
    370         jmp     .nextSector     ; all is well, time for next sector
     341;
     342; Normalize buffer pointer for next go round, if needed
     343;
     344        test    di,di
     345        jns     short .nextSector
     346        jmp     short .nextSectorNormalize
    371347
    372348;---------------------------------------------------------------------------
     
    378354; Used in situations where a call is underway, such as with SerialCommand_WaitAndPoll
    379355;
    380 SerialCommand_OutputWithParameters_ErrorAndPop2Words:
    381         pop     ax
    382         pop     ax
    383 
     356ALIGN JUMP_ALIGN
     357SerialCommand_OutputWithParameters_ErrorAndPop4Words:
     358        add     sp,8
     359
     360ALIGN JUMP_ALIGN
    384361SerialCommand_OutputWithParameters_Error:
    385362        stc
    386363        mov     al,1
    387364
     365ALIGN JUMP_ALIGN
    388366SerialCommand_OutputWithParameters_ReturnCodeInALCF:
    389367        sti
    390368        mov     ah,al
    391369
    392         pop     bp              ;  recover ax from stack, throw away
     370        pop     bp              ;  recover ax (command and count) from stack, throw away
    393371
    394372        pop     es
     
    400378
    401379;--------------------------------------------------------------------
     380; SerialCommand_WriteProtocol
     381;
     382; NOTE: As with its read counterpart, this loop is very time sensitive. 
     383; Although it will still function, adding additional instructions will
     384; impact the write througput, especially on slower machines. 
     385;
     386;   Parameters:
     387;       ES:SI:  Ptr to buffer
     388;       CX:     Words to write, plus 1
     389;       BP/DI:  Initialized for Checksum (-1 in each)
     390;       DH:     I/O Port high byte
     391;       BX:     LineStatus Register address (BH) and Receive/Transmit Register address (BL)
     392;   Returns:
     393;       BP/DI:  Checksum for written bytes, compared against ACK from server in .readLoop
     394;       CX:     Zero
     395;       DL:     Receive/Transmit Register address
     396;   Corrupts registers:
     397;       AX
     398;--------------------------------------------------------------------
     399ALIGN JUMP_ALIGN
     400SerialCommand_WriteProtocol:
     401.writeLoop:
     402        es lodsw                ; fetch next word
     403
     404        out     dx,al           ; output first byte
     405
     406        add     bp,ax           ; update checksum
     407        adc     bp,0
     408        add     di,bp
     409        adc     di,0
     410
     411        mov     dl,bh           ; transmit buffer empty?
     412        in      al,dx
     413        test    al,20h
     414        jz      .writeTimeout2  ; nope, use our polling routine
     415
     416.writeByte2Ready:
     417        mov     dl,bl
     418        mov     al,ah           ; output second byte
     419        out     dx,al
     420
     421.entry:
     422        mov     dl,bh           ; transmit buffer empty?
     423        in      al,dx
     424        test    al,20h
     425        mov     dl,bl
     426        jz      .writeTimeout1  ; nope, use our polling routine
     427
     428.writeByte1Ready:
     429        loop    .writeLoop
     430
     431        mov     ax,di           ; fold Fletcher's checksum and output
     432        xor     al,ah
     433        out     dx,al           ; byte 1
     434
     435        call    SerialCommand_WaitAndPoll_Write
     436
     437        mov     ax,bp
     438        xor     al,ah
     439        out     dx,al           ; byte 2
     440
     441        ret
     442
     443.writeTimeout2:
     444        mov     dl,ah           ; need to preserve AH, but don't need DL (will be reset upon return)
     445        call    SerialCommand_WaitAndPoll_Write
     446        mov     ah,dl
     447        jmp     .writeByte2Ready
     448       
     449.writeTimeout1:
     450        mov     ax,.writeByte1Ready
     451        push    ax              ; return address for ret at end of SC_writeTimeout2
     452;;; fall-through
     453
     454;--------------------------------------------------------------------
    402455; SerialCommand_WaitAndPoll
    403456;
    404457;   Parameters:
    405 ;       BH:     UART_LineStatus bit to test (20h for write, or 1h for read)
     458;       AH:     UART_LineStatus bit to test (20h for write, or 1h for read)
     459;               One entry point fills in AH with 20h for write
    406460;       DX:     Port address (OK if already incremented to UART_lineStatus)
     461;       BX:   
    407462;       Stack:  2 words on the stack below the command/count word
    408463;   Returns:
     
    410465;       Jumps directly to error exit if timeout elapses (and cleans up stack)
    411466;   Corrupts registers:
    412 ;       CX, flags
     467;       AX
    413468;--------------------------------------------------------------------
    414469
     
    416471
    417472ALIGN JUMP_ALIGN
    418 SerialCommand_WaitAndPoll_Init:
     473SerialCommand_WaitAndPoll_Write:
     474        mov     ah,20h
     475;;; fall-through
     476
     477ALIGN JUMP_ALIGN
     478SerialCommand_WaitAndPoll_Read:
     479        push    cx
     480        push    dx
     481
     482;
     483; We first poll in a tight loop, interrupts off, for the next character to come in/be sent
     484;
     485        xor     cx,cx
     486.readTimeoutLoop:
     487        mov     dl,bh               
     488        in      al,dx
     489        test    al,ah
     490        jnz     .readTimeoutComplete
     491        loop    .readTimeoutLoop
     492
     493;
     494; If that loop completes, then we assume there is a long delay involved, turn interrupts back on
     495; and wait for a given number of timer ticks to pass.
     496;
     497        sti
    419498        mov     cl,SerialCommand_WaitAndPoll_SoftDelayTicks
    420499        call    Timer_InitializeTimeoutWithTicksInCL
    421 ; fall-through
    422 
    423 SerialCommand_WaitAndPoll:
     500.WaitAndPoll:
    424501        call    Timer_SetCFifTimeout
    425         jc      SerialCommand_OutputWithParameters_ErrorAndPop2Words
    426         push    dx
    427         push    ax
    428         or      dl,SerialCommand_UART_lineStatus
     502        jc      SerialCommand_OutputWithParameters_ErrorAndPop4Words
    429503        in      al,dx
    430         test    al,bh
    431         pop     ax
     504        test    al,ah
     505        jz      .WaitAndPoll
     506        cli
     507
     508.readTimeoutComplete:
    432509        pop     dx
    433         jz      SerialCommand_WaitAndPoll
    434 ; fall-through
    435 
    436 SerialCommand_WaitAndPoll_Done:
     510        pop     cx
    437511        ret
    438 
    439 ;--------------------------------------------------------------------
    440 ; SerialCommand_WriteProtocol
    441 ;
    442 ;   Parameters:
    443 ;       ES:DI:  Ptr to buffer
    444 ;       BL:     Words to write (1-255, or 0=256)
    445 ;       BP/SI:  Initialized for Checksum (-1 in each)
    446 ;       DX:     I/O Port
    447 ;   Returns:
    448 ;       BP/SI:  Checksum for written bytes, compared against ACK from server in .readLoop
    449 ;   Corrupts registers:
    450 ;       AX, BX, CX, DI
    451 ;--------------------------------------------------------------------
    452 ALIGN JUMP_ALIGN
    453 SerialCommand_WriteProtocol:
    454         mov     bh,20h
    455 
    456 .writeLoop:
    457         test    bh,1
    458         jnz     SerialCommand_WaitAndPoll_Done
    459 
    460         mov     ax,[es:di]      ; fetch next word
    461         inc     di
    462         inc     di
    463 
    464         add     bp,ax           ; update checksum
    465         adc     bp,0
    466         add     si,bp
    467         adc     si,0
    468 
    469 .writeLoopChecksum:
    470         call    SerialCommand_WaitAndPoll_Init
    471 
    472         out     dx,al           ; output first byte
    473 
    474         call    SerialCommand_WaitAndPoll
    475 
    476         mov     al,ah           ; output second byte
    477         out     dx,al
    478 
    479         dec     bl
    480         jnz     .writeLoop
    481 
    482         inc     bh
    483 
    484         mov     ax,bp           ; merge checksum for possible write (last loop)
    485         xor     ah,al
    486         mov     cx,si
    487         xor     cl,ch
    488         mov     al,cl
    489 
    490         jmp     .writeLoopChecksum
    491 
    492512
    493513;--------------------------------------------------------------------
Note: See TracChangeset for help on using the changeset viewer.