Subversion Repositories Spectranet

[/] [branches/] [gnubinutils/] [rom/] [w5100_buffer.asm] - Diff between revs 371 and 384

Show entire file | Details | Blame | View Log

Rev 371 Rev 384
Line 17... Line 17...
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
;THE SOFTWARE.
;THE SOFTWARE.
 
.include        "w5100_defs.inc"
 
.include        "sysvars.inc"
 
.include        "sockdefs.inc"
 
 
; Copy from rx buffer and copy into txbuffer.
; Copy from rx buffer and copy into txbuffer.
; These routines assume 2K buffers for both tx and rx (so they don't bother
; These routines assume 2K buffers for both tx and rx (so they don't bother
; ANDing the low order of RX_MASK and TX_MASK ... so if you've changed the
; ANDing the low order of RX_MASK and TX_MASK ... so if you've changed the
; buffer size, this is probably why it broke)
; buffer size, this is probably why it broke)
Line 39... Line 41...
; On entry:     H  = high order address of register area for socket.
; On entry:     H  = high order address of register area for socket.
;               DE = destination to move buffer contents
;               DE = destination to move buffer contents
;               BC = size of destination buffer
;               BC = size of destination buffer
; On return     BC = bytes copied
; On return     BC = bytes copied
; Unchanged     IX, IY, shadow registers
; Unchanged     IX, IY, shadow registers
F_copyrxbuf
.text
 
.globl F_copyrxbuf
 
F_copyrxbuf:
        ; check whether page A is being used.
        ; check whether page A is being used.
        ; (note: will use page B if this is the case)
        ; (note: will use page B if this is the case)
        call F_checkpageA
        call F_checkpageA
 
 
        ; Set de to the number of bytes that have been received.
        ; Set de to the number of bytes that have been received.
Line 53... Line 57...
        ; RX_RSR should logically be nonzero, but there seems to be
        ; RX_RSR should logically be nonzero, but there seems to be
        ; a race condition in the W5100 where we can get here after
        ; a race condition in the W5100 where we can get here after
        ; checking the RX interrupt flag but RSR is still zero.
        ; checking the RX interrupt flag but RSR is still zero.
        ; The datasheet doesn't of course guarantee that the socket
        ; The datasheet doesn't of course guarantee that the socket
        ; is actually ready to read even if the interrupt is set :-)
        ; is actually ready to read even if the interrupt is set :-)
.testzero
.testzero1:
        ld l, Sn_RX_RSR0 % 256  ; (hl) = RSR's MSB
        ld l, Sn_RX_RSR0 % 256  ; (hl) = RSR's MSB
        ld d, (hl)
        ld d, (hl)
        inc l
        inc l
        ld e, (hl)
        ld e, (hl)
        ld a, d
        ld a, d
        or e
        or e
        jr nz, .continue
        jr nz, .continue1
 
 
        ; note that if there's a buffer to unload, unload it. Only
        ; note that if there's a buffer to unload, unload it. Only
        ; check for RST when there's no data pending.
        ; check for RST when there's no data pending.
        ld l, Sn_IR % 256       ; point hl at the IR, test for CONNRESET
        ld l, Sn_IR % 256       ; point hl at the IR, test for CONNRESET
        bit BIT_IR_DISCON, (hl)
        bit BIT_IR_DISCON, (hl)
        jp nz, J_resetbypeer_pop
        jp nz, J_resetbypeer_pop
        jr .testzero
        jr .testzero1
 
 
.continue
.continue1:
        ; check whether it exceeds the buffer. If so just use value of
        ; check whether it exceeds the buffer. If so just use value of
        ; BC as number of bytes to copy. If not, use the RSR as number
        ; BC as number of bytes to copy. If not, use the RSR as number
        ; of bytes to copy.
        ; of bytes to copy.
        ld a, b                 ; MSB of length of our buffer
        ld a, b                 ; MSB of length of our buffer
        cp d                    ; MSB of RSR
        cp d                    ; MSB of RSR
        jr c, .findoffset       ; RSR > buffer
        jr c, .findoffset1      ; RSR > buffer
        jr nz, .setlen          ; RSR < buffer, set actual length to RSR
        jr nz, .setlen1         ; RSR < buffer, set actual length to RSR
        ld a, c                 ; LSB of RSR
        ld a, c                 ; LSB of RSR
        cp e                    ; LSB of length of our buffer
        cp e                    ; LSB of length of our buffer
        jr c, .findoffset       ; RSR > buffer len
        jr c, .findoffset1      ; RSR > buffer len
 
 
        ; BC now should equal actual size to copy
        ; BC now should equal actual size to copy
.setlen
.setlen1:
        ld b, d
        ld b, d
        ld c, e
        ld c, e
 
 
        ; de = offset when were are done here.
        ; de = offset when were are done here.
.findoffset
.findoffset1:
        ld l, Sn_RX_RD0 % 256   ; RX read pointer register for socket
        ld l, Sn_RX_RD0 % 256   ; RX read pointer register for socket
        ld a, (hl)              ; MSB of RX offset
        ld a, (hl)              ; MSB of RX offset
        and gSn_RX_MASK / 256   ; mask with 0x07
        and gSn_RX_MASK / 256   ; mask with 0x07
        ld d, a
        ld d, a
        inc l
        inc l
        ld e, (hl)
        ld e, (hl)
 
 
        ; page in the correct bit of W5100 buffer memory
        ; page in the correct bit of W5100 buffer memory
.setpage
.setpage1:
        ld (v_sockptr), hl      ; Save the current socket register pointer
        ld (v_sockptr), hl      ; Save the current socket register pointer
        ld a, h
        ld a, h
        sub Sn_MR / 256         ; derive socket number
        sub Sn_MR / 256         ; derive socket number
        bit 1, a                ; upper page or lower page?
        bit 1, a                ; upper page or lower page?
        jr nz, .upperpage
        jr nz, .upperpage1
        ld a, RX_LWRDATAPAGE    ; W5100 phys. address 0x6000
        ld a, RX_LWRDATAPAGE    ; W5100 phys. address 0x6000
        call F_setpageA
        call F_setpageA
        jr .willitblend
        jr .willitblend1
.upperpage
.upperpage1:
        ld a, RX_UPRDATAPAGE    ; W5100 phys. address 0x7000
        ld a, RX_UPRDATAPAGE    ; W5100 phys. address 0x7000
        call F_setpageA
        call F_setpageA
 
 
        ; Does the circular buffer wrap around?
        ; Does the circular buffer wrap around?
.willitblend
.willitblend1:
        dec bc                  ; ...to check for >, not >=
        dec bc                  ; ...to1 check for >, not >=
        ld h, d                 ; not ex hl, de because we need to preserve it
        ld h, d                 ; not ex hl, de because we need to preserve it
        ld l, e
        ld l, e
        add hl, bc
        add hl, bc
        inc bc                  ; undo previous dec
        inc bc                  ; undo previous dec
        ld a, h
        ld a, h
        cp 0x08                 ; Does copy go over 2k boundary?
        cp 0x08                 ; Does copy go over 2k boundary?
        jp p, .wrappedcopy      ; The circular buffer wraps.
        jp p, .wrappedcopy1     ; The circular buffer wraps.
 
 
        ; A straight copy from the W5100 buffer to our memory.
        ; A straight copy from the W5100 buffer to our memory.
.straightcopy
.straightcopy1:
        ld hl, (v_sockptr)      ; retrieve socket register pointer
        ld hl, (v_sockptr)      ; retrieve socket register pointer
        call F_getbaseaddr      ; hl now = source address
        call F_getbaseaddr      ; hl now = source address
        pop de                  ; retrieve destination address
        pop de                  ; retrieve destination address
        ld (v_copylen), bc      ; preserve length
        ld (v_copylen), bc      ; preserve length
        ldir                    ; copy buffer contents
        ldir                    ; copy buffer contents
 
 
.completerx
.completerx1:
        ld a, REGPAGE           ; Registers are in W5100 physmem 0x0000
        ld a, REGPAGE           ; Registers are in W5100 physmem 0x0000
        call F_setpageA
        call F_setpageA
        ld hl, (v_sockptr)      ; retrieve socket pointer
        ld hl, (v_sockptr)      ; retrieve socket pointer
        ld l, Sn_RX_RD0 % 256   ; point it at MSB of bytes read register.
        ld l, Sn_RX_RD0 % 256   ; point it at MSB of bytes read register.
        ld d, (hl)              ; d = MSB
        ld d, (hl)              ; d = MSB
Line 155... Line 159...
        ; The circular buffer wraps around, leading to a slightly
        ; The circular buffer wraps around, leading to a slightly
        ; more complicated copy.
        ; more complicated copy.
        ; Stack contains the destination address
        ; Stack contains the destination address
        ; BC contains length to copy
        ; BC contains length to copy
        ; DE contains offset
        ; DE contains offset
.wrappedcopy
.wrappedcopy1:
        ld (v_copylen), bc      ; save length
        ld (v_copylen), bc      ; save length
        ld hl, 0x0800           ; the highest offset you can have
        ld hl, 0x0800           ; the highest offset you can have
        sbc hl, de              ; hl = how many bytes before we hit the end
        sbc hl, de              ; hl = how many bytes before we hit the end
        ld (v_copied), hl       ; save it
        ld (v_copied), hl       ; save it
        ld hl, (v_sockptr)      ; retrieve socket register ptr
        ld hl, (v_sockptr)      ; retrieve socket register ptr
Line 176... Line 180...
        sbc hl, bc              ; hl = remaining bytes
        sbc hl, bc              ; hl = remaining bytes
        ld b, h
        ld b, h
        ld c, l
        ld c, l
        pop hl                  ; retrieve address
        pop hl                  ; retrieve address
        ldir                    ; transfer remainder
        ldir                    ; transfer remainder
        jr .completerx          ; done
        jr .completerx1         ; done
 
 
;============================================================================
;============================================================================
; F_copytxbuf:
; F_copytxbuf:
; Copy the receive buffer to a location in memory, set hardware registers
; Copy the receive buffer to a location in memory, set hardware registers
; to send the buffer contents.
; to send the buffer contents.
Line 191... Line 195...
; Unchanged     IX, IY, shadow registers
; Unchanged     IX, IY, shadow registers
;
;
; Notes: If sending >2k of data, data should only be fed into this routine
; Notes: If sending >2k of data, data should only be fed into this routine
; in chunks of <=2k a time or it'll hang. The socket library's send()
; in chunks of <=2k a time or it'll hang. The socket library's send()
; call should do this.
; call should do this.
F_copytxbuf
.globl F_copytxbuf
 
F_copytxbuf:
        ; check whether page A is being used.
        ; check whether page A is being used.
        ; (note: will use page B if this is the case)
        ; (note: will use page B if this is the case)
        call F_checkpageA
        call F_checkpageA
 
 
.waitformsb
.waitformsb2:
        ld l, Sn_IR % 256       ; point hl at the IR, test for CONNRESET
        ld l, Sn_IR % 256       ; point hl at the IR, test for CONNRESET
        bit BIT_IR_DISCON, (hl)
        bit BIT_IR_DISCON, (hl)
        jp nz, J_resetbypeer
        jp nz, J_resetbypeer
        ld l, Sn_TX_FSR0 % 256  ; point hl at free space register
        ld l, Sn_TX_FSR0 % 256  ; point hl at free space register
        ld a, b                 ; MSB of argment
        ld a, b                 ; MSB of argment
        cp (hl)                 ; compare with FSR
        cp (hl)                 ; compare with FSR
        jr c, .getoffset        ; definitely enough free space
        jr c, .getoffset2       ; definitely enough free space
        jr nz, .waitformsb      ; Buffer MSB > FSR MSB
        jr nz, .waitformsb2     ; Buffer MSB > FSR MSB
                                ; Buffer MSB = FSR MSB, check LSB value
                                ; Buffer MSB = FSR MSB, check LSB value
        inc l                   ; (hl) = LSB of hw register
        inc l                   ; (hl) = LSB of hw register
.waitforlsb
.waitforlsb2:
        ld l, Sn_IR % 256       ; point hl at the IR, test for CONNRESET
        ld l, Sn_IR % 256       ; point hl at the IR, test for CONNRESET
        bit BIT_IR_DISCON, (hl)
        bit BIT_IR_DISCON, (hl)
        jp nz, J_resetbypeer
        jp nz, J_resetbypeer
        ld l, Sn_TX_FSR0 % 256  ; point hl at free space register
        ld l, Sn_TX_FSR0 % 256  ; point hl at free space register
        ld a, (hl)              ; get LSB of FSR
        ld a, (hl)              ; get LSB of FSR
        cp c                    ; and compare with LSB of passed value
        cp c                    ; and compare with LSB of passed value
        jr c, .waitforlsb       ; if C > (hl) wait until it's not.
        jr c, .waitforlsb2      ; if C > (hl) wait until it's not.
 
 
.getoffset
.getoffset2:
        ld (v_sockptr), hl      ; save the socket register pointer
        ld (v_sockptr), hl      ; save the socket register pointer
        ld (v_copylen), bc      ; save the buffer length
        ld (v_copylen), bc      ; save the buffer length
        push de                 ; save the source buffer pointer
        push de                 ; save the source buffer pointer
        ld l, Sn_TX_WR0 % 256   ; (hl) = TX write register offset MSB
        ld l, Sn_TX_WR0 % 256   ; (hl) = TX write register offset MSB
        ld a, (hl)
        ld a, (hl)
Line 230... Line 235...
        ld e, (hl)              ; de = offset
        ld e, (hl)              ; de = offset
 
 
        ; page in the correct bit of W5100 buffer memory. TX buffer for
        ; page in the correct bit of W5100 buffer memory. TX buffer for
        ; socket 0 and 1 in page 0x0104 and for 2 and 3 in 0x0105, mapping
        ; socket 0 and 1 in page 0x0104 and for 2 and 3 in 0x0105, mapping
        ; socket 0 and 2 to 0x1000, 1 and 3 to 0x1800.
        ; socket 0 and 2 to 0x1000, 1 and 3 to 0x1800.
.setpage
.setpage2:
        ld a, h
        ld a, h
        sub Sn_MR / 256         ; derive socket number
        sub Sn_MR / 256         ; derive socket number
        bit 1, a                ; upper page or lower page?
        bit 1, a                ; upper page or lower page?
        jr nz, .upperpage
        jr nz, .upperpage2
        ld a, TX_LWRDATAPAGE    ; W5100 phys. address 0x4000
        ld a, TX_LWRDATAPAGE    ; W5100 phys. address 0x4000
        call F_setpageA
        call F_setpageA
        jr .willitblend
        jr .willitblend2
.upperpage
.upperpage2:
        ld a, TX_UPRDATAPAGE    ; W5100 phys. address 0x5000
        ld a, TX_UPRDATAPAGE    ; W5100 phys. address 0x5000
        call F_setpageA
        call F_setpageA
 
 
        ; add de (offset) and bc (length) and see if it's >0x0800, in
        ; add de (offset) and bc (length) and see if it's >0x0800, in
        ; which case buffer copy needs to wrap.
        ; which case buffer copy needs to wrap.
.willitblend
.willitblend2:
        dec bc                  ; ...to check for >, not >=
        dec bc                  ; ...to2 check for >, not >=
        ld h, d                 ; not ex hl, de because we need to preserve it
        ld h, d                 ; not ex hl, de because we need to preserve it
        ld l, e
        ld l, e
        add hl, bc
        add hl, bc
        inc bc                  ; undo previous dec
        inc bc                  ; undo previous dec
        ld a, h
        ld a, h
        cp 0x08                 ; Does copy go over 2k boundary?
        cp 0x08                 ; Does copy go over 2k boundary?
        jp p, .wrappedcopy      ; The circular buffer wraps.
        jp p, .wrappedcopy2     ; The circular buffer wraps.
 
 
.straightcopy
.straightcopy2:
        ld hl, (v_sockptr)      ; restore socket pointer
        ld hl, (v_sockptr)      ; restore socket pointer
        call F_getbaseaddr
        call F_getbaseaddr
        ex de, hl               ; for LDIR
        ex de, hl               ; for LDIR
        pop hl                  ; get stacked source address
        pop hl                  ; get stacked source address
        ldir
        ldir
 
 
.completetx
.completetx2:
        ld a, REGPAGE           ; registers in W5100 phys. 0x0000
        ld a, REGPAGE           ; registers in W5100 phys. 0x0000
        call F_setpageA
        call F_setpageA
        ld hl, (v_sockptr)      ; get the socket pointer back
        ld hl, (v_sockptr)      ; get the socket pointer back
        ld l, Sn_TX_WR0 % 256   ; transmit register
        ld l, Sn_TX_WR0 % 256   ; transmit register
        ld d, (hl)              ; get MSB of TX_WR0
        ld d, (hl)              ; get MSB of TX_WR0
Line 283... Line 288...
        ld a, (v_buf_pgb)       ; check to see whether to re-page area B
        ld a, (v_buf_pgb)       ; check to see whether to re-page area B
        and a                   ; zero?
        and a                   ; zero?
        jp nz, F_setpageB       ; yes - restore page B and return.
        jp nz, F_setpageB       ; yes - restore page B and return.
        ret                     ; no, return.
        ret                     ; no, return.
 
 
.wrappedcopy
.wrappedcopy2:
        ld hl, 0x0800           ; the highest offset you can have
        ld hl, 0x0800           ; the highest offset you can have
        sbc hl, de              ; hl = how many bytes before we hit the end
        sbc hl, de              ; hl = how many bytes before we hit the end
        ld (v_copied), hl       ; save it
        ld (v_copied), hl       ; save it
        ld hl, (v_sockptr)      ; retrieve socket register ptr
        ld hl, (v_sockptr)      ; retrieve socket register ptr
        call F_getbaseaddr      ; hl is now source address
        call F_getbaseaddr      ; hl is now source address
Line 304... Line 309...
        sbc hl, bc              ; hl = remaining bytes
        sbc hl, bc              ; hl = remaining bytes
        ld b, h
        ld b, h
        ld c, l
        ld c, l
        pop hl                  ; retrieve source buffer ptr
        pop hl                  ; retrieve source buffer ptr
        ldir                    ; transfer remainder
        ldir                    ; transfer remainder
        jr .completetx          ; done
        jr .completetx2         ; done
 
 
J_resetbypeer_pop
J_resetbypeer_pop:
        pop de
        pop de
J_resetbypeer
J_resetbypeer:
        ld a, (v_buf_pgb)       ; check to see whether to re-page area B
        ld a, (v_buf_pgb)       ; check to see whether to re-page area B
        and a                   ; zero?
        and a                   ; zero?
        call nz, F_setpageB     ; yes - restore page B and return.
        call nz, F_setpageB     ; yes - restore page B and return.
        ld a, ECONNRESET
        ld a, ECONNRESET
        scf
        scf
Line 322... Line 327...
; F_getbaseaddr:
; F_getbaseaddr:
; This routine sets HL to the base address.
; This routine sets HL to the base address.
; On entry:     de = offset
; On entry:     de = offset
;               h  = high order of socket register address
;               h  = high order of socket register address
; On exit:      hl = base address
; On exit:      hl = base address
F_getbaseaddr
.globl F_getbaseaddr
 
F_getbaseaddr:
        ld l, 0
        ld l, 0
        ld a, h
        ld a, h
        sub Sn_BASE             ; a = 0x10 for skt 0, 0x11 for skt 1, 0x12 etc.
        sub Sn_BASE             ; a = 0x10 for skt 0, 0x11 for skt 1, 0x12 etc.
        and %00010001           ; mask out all but bits 4 and 1
        and %00010001           ; mask out all but bits 4 and 1
 
 
Line 334... Line 340...
        ; and 0x11 for skt 3. The entire W5100 receive buffer area for
        ; and 0x11 for skt 3. The entire W5100 receive buffer area for
        ; all sockets is 8k, but we're only paging in 4k at at time at
        ; all sockets is 8k, but we're only paging in 4k at at time at
        ; 0x1000-0x1FFF, so the physical address should either end up
        ; 0x1000-0x1FFF, so the physical address should either end up
        ; being 0x1000 (skt 0 and 2) or 0x1800 (skt 1 and 3)
        ; being 0x1000 (skt 0 and 2) or 0x1800 (skt 1 and 3)
        bit 0, a                ; bit 0 set = odd numbered socket at 0x1800
        bit 0, a                ; bit 0 set = odd numbered socket at 0x1800
        jr nz, .oddsock
        jr nz, .oddsock3
        ld h, a
        ld h, a
        add hl, de              ; hl = physical address
        add hl, de              ; hl = physical address
        ret
        ret
.oddsock
.oddsock3:
        add 0x07                ; odd sockets are 0x18xx addresses
        add a, 0x07             ; odd sockets are 0x18xx addresses
        ld h, a
        ld h, a
        add hl, de
        add hl, de
        ret
        ret
 
 
;=========================================================================
;=========================================================================
; F_checkpageA
; F_checkpageA
; On entry: DE = buffer start
; On entry: DE = buffer start
F_checkpageA
.globl F_checkpageA
 
F_checkpageA:
        ld a, d
        ld a, d
        and 0xF0                ; mask off top 4 bits
        and 0xF0                ; mask off top 4 bits
        cp 0x10                 ; are we in 0x1000 - 0x1FFF?
        cp 0x10                 ; are we in 0x1000 - 0x1FFF?
        jr z, .swappages        ; yes, swap pages.
        jr z, .swappages4       ; yes, swap pages.
        xor a                   ; reset the sysvar
        xor a                   ; reset the sysvar
        ld (v_buf_pgb), a
        ld (v_buf_pgb), a
        ret
        ret
.swappages
.swappages4:
        ld a, d
        ld a, d
        xor 0x30                ; flip bits 4 and 5 to convert 0x1xxx to 0x2xxx
        xor 0x30                ; flip bits 4 and 5 to convert 0x1xxx to 0x2xxx
        ld d, a
        ld d, a
        ld a, (v_pgb)           ; get current page B
        ld a, (v_pgb)           ; get current page B
        ld (v_buf_pgb),a        ; save it
        ld (v_buf_pgb),a        ; save it