Subversion Repositories Spectranet

[/] [branches/] [gnubinutils/] [rom/] [w5100_buffer.asm] - Blame information for rev 384

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 24 winston
;The MIT License
2
;
3
;Copyright (c) 2008 Dylan Smith
4
;
5
;Permission is hereby granted, free of charge, to any person obtaining a copy
6
;of this software and associated documentation files (the "Software"), to deal
7
;in the Software without restriction, including without limitation the rights
8
;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
;copies of the Software, and to permit persons to whom the Software is
10
;furnished to do so, subject to the following conditions:
11
;
12
;The above copyright notice and this permission notice shall be included in
13
;all copies or substantial portions of the Software.
14
;
15
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
;THE SOFTWARE.
22 384 winston
.include        "w5100_defs.inc"
23
.include        "sysvars.inc"
24
.include        "sockdefs.inc"
25 24 winston
 
26
; Copy from rx buffer and copy into txbuffer.
27
; These routines assume 2K buffers for both tx and rx (so they don't bother
28
; ANDing the low order of RX_MASK and TX_MASK ... so if you've changed the
29
; buffer size, this is probably why it broke)
30
; The buffers get mapped into page area A (0x1000 - 0x1FFF). On entry
31
; it is assumed the register area is already mapped into page area A.
32
;
33
; These are low level routines and should really only be getting called by
34
; the socket library. Call directly at your own risk - the call address
35
; is likely to change with every firmware revision!
36
;
37
; Finally, a reminder: W5100 hardware registers are BIG endian.
38
;
39
; F_copyrxbuf:
40
; Copy the receive buffer to a location in memory.
41
; On entry:     H  = high order address of register area for socket.
42
;               DE = destination to move buffer contents
43
;               BC = size of destination buffer
44
; On return     BC = bytes copied
45
; Unchanged     IX, IY, shadow registers
46 384 winston
.text
47
.globl F_copyrxbuf
48
F_copyrxbuf:
49 143 winston
        ; check whether page A is being used.
50
        ; (note: will use page B if this is the case)
51
        call F_checkpageA
52
 
53 24 winston
        ; Set de to the number of bytes that have been received.
54
        push de
55 41 winston
 
56
        ; note that if the interrupt register has been checked,
57
        ; RX_RSR should logically be nonzero, but there seems to be
58
        ; a race condition in the W5100 where we can get here after
59
        ; checking the RX interrupt flag but RSR is still zero.
60
        ; The datasheet doesn't of course guarantee that the socket
61
        ; is actually ready to read even if the interrupt is set :-)
62 384 winston
.testzero1:
63 24 winston
        ld l, Sn_RX_RSR0 % 256  ; (hl) = RSR's MSB
64
        ld d, (hl)
65
        inc l
66
        ld e, (hl)
67 41 winston
        ld a, d
68
        or e
69 384 winston
        jr nz, .continue1
70 24 winston
 
71 316 winston
        ; note that if there's a buffer to unload, unload it. Only
72
        ; check for RST when there's no data pending.
73
        ld l, Sn_IR % 256       ; point hl at the IR, test for CONNRESET
74
        bit BIT_IR_DISCON, (hl)
75
        jp nz, J_resetbypeer_pop
76 384 winston
        jr .testzero1
77 316 winston
 
78 384 winston
.continue1:
79 24 winston
        ; check whether it exceeds the buffer. If so just use value of
80
        ; BC as number of bytes to copy. If not, use the RSR as number
81
        ; of bytes to copy.
82
        ld a, b                 ; MSB of length of our buffer
83
        cp d                    ; MSB of RSR
84 384 winston
        jr c, .findoffset1      ; RSR > buffer
85
        jr nz, .setlen1         ; RSR < buffer, set actual length to RSR
86 24 winston
        ld a, c                 ; LSB of RSR
87
        cp e                    ; LSB of length of our buffer
88 384 winston
        jr c, .findoffset1      ; RSR > buffer len
89 24 winston
 
90
        ; BC now should equal actual size to copy
91 384 winston
.setlen1:
92 24 winston
        ld b, d
93
        ld c, e
94
 
95
        ; de = offset when were are done here.
96 384 winston
.findoffset1:
97 24 winston
        ld l, Sn_RX_RD0 % 256   ; RX read pointer register for socket
98
        ld a, (hl)              ; MSB of RX offset
99
        and gSn_RX_MASK / 256   ; mask with 0x07
100
        ld d, a
101
        inc l
102
        ld e, (hl)
103
 
104
        ; page in the correct bit of W5100 buffer memory
105 384 winston
.setpage1:
106 24 winston
        ld (v_sockptr), hl      ; Save the current socket register pointer
107
        ld a, h
108
        sub Sn_MR / 256         ; derive socket number
109
        bit 1, a                ; upper page or lower page?
110 384 winston
        jr nz, .upperpage1
111 110 winston
        ld a, RX_LWRDATAPAGE    ; W5100 phys. address 0x6000
112 24 winston
        call F_setpageA
113 384 winston
        jr .willitblend1
114
.upperpage1:
115 110 winston
        ld a, RX_UPRDATAPAGE    ; W5100 phys. address 0x7000
116 24 winston
        call F_setpageA
117
 
118
        ; Does the circular buffer wrap around?
119 384 winston
.willitblend1:
120
        dec bc                  ; ...to1 check for >, not >=
121 24 winston
        ld h, d                 ; not ex hl, de because we need to preserve it
122
        ld l, e
123
        add hl, bc
124
        inc bc                  ; undo previous dec
125
        ld a, h
126
        cp 0x08                 ; Does copy go over 2k boundary?
127 384 winston
        jp p, .wrappedcopy1     ; The circular buffer wraps.
128 24 winston
 
129
        ; A straight copy from the W5100 buffer to our memory.
130 384 winston
.straightcopy1:
131 24 winston
        ld hl, (v_sockptr)      ; retrieve socket register pointer
132
        call F_getbaseaddr      ; hl now = source address
133
        pop de                  ; retrieve destination address
134
        ld (v_copylen), bc      ; preserve length
135
        ldir                    ; copy buffer contents
136
 
137 384 winston
.completerx1:
138 110 winston
        ld a, REGPAGE           ; Registers are in W5100 physmem 0x0000
139 24 winston
        call F_setpageA
140
        ld hl, (v_sockptr)      ; retrieve socket pointer
141
        ld l, Sn_RX_RD0 % 256   ; point it at MSB of bytes read register.
142
        ld d, (hl)              ; d = MSB
143
        inc l
144
        ld e, (hl)              ; e = LSB
145
        ld bc, (v_copylen)      ; retrieve length copied
146
        ex de, hl
147
        add hl, bc              ; hl = new RX_RD pointer
148
        ex de, hl
149
        ld (hl), e              ; copy LSB
150
        dec l
151
        ld (hl), d              ; copy MSB, RX_RD now set.
152
        ld l, Sn_CR % 256       ; (hl) = socket command register
153
        ld (hl), S_CR_RECV      ; tell hardware that receive is complete
154 143 winston
        ld a, (v_buf_pgb)       ; check to see whether to re-page area B
155
        and a                   ; zero?
156
        jp nz, F_setpageB       ; yes - restore page B and return.
157
        ret                     ; no, return.
158 24 winston
 
159
        ; The circular buffer wraps around, leading to a slightly
160
        ; more complicated copy.
161
        ; Stack contains the destination address
162
        ; BC contains length to copy
163
        ; DE contains offset
164 384 winston
.wrappedcopy1:
165 24 winston
        ld (v_copylen), bc      ; save length
166
        ld hl, 0x0800           ; the highest offset you can have
167
        sbc hl, de              ; hl = how many bytes before we hit the end
168
        ld (v_copied), hl       ; save it
169
        ld hl, (v_sockptr)      ; retrieve socket register ptr
170
        call F_getbaseaddr      ; hl is now source address
171
        pop de                  ; destination buffer now in DE
172
        ld bc, (v_copied)       ; first chunk length now in BC
173
        ldir                    ; copy chunk
174
        ld a, h                 ; roll HL back 0x0800
175
        sub 0x08
176
        ld h, a
177
        push hl                 ; save new address
178
        ld bc, (v_copied)       ; bytes copied so far
179
        ld hl, (v_copylen)      ; total bytes to copy
180
        sbc hl, bc              ; hl = remaining bytes
181
        ld b, h
182
        ld c, l
183
        pop hl                  ; retrieve address
184
        ldir                    ; transfer remainder
185 384 winston
        jr .completerx1         ; done
186 24 winston
 
187
;============================================================================
188
; F_copytxbuf:
189
; Copy the receive buffer to a location in memory, set hardware registers
190
; to send the buffer contents.
191
; On entry:     H  = high order address of register area for socket.
192
;               DE = source buffer to copy to hardware
193
;               BC = size of source buffer
194
; On return     BC = bytes copied
195
; Unchanged     IX, IY, shadow registers
196
;
197
; Notes: If sending >2k of data, data should only be fed into this routine
198
; in chunks of <=2k a time or it'll hang. The socket library's send()
199
; call should do this.
200 384 winston
.globl F_copytxbuf
201
F_copytxbuf:
202 144 winston
        ; check whether page A is being used.
203
        ; (note: will use page B if this is the case)
204
        call F_checkpageA
205
 
206 384 winston
.waitformsb2:
207 306 winston
        ld l, Sn_IR % 256       ; point hl at the IR, test for CONNRESET
208
        bit BIT_IR_DISCON, (hl)
209
        jp nz, J_resetbypeer
210 24 winston
        ld l, Sn_TX_FSR0 % 256  ; point hl at free space register
211
        ld a, b                 ; MSB of argment
212
        cp (hl)                 ; compare with FSR
213 384 winston
        jr c, .getoffset2       ; definitely enough free space
214
        jr nz, .waitformsb2     ; Buffer MSB > FSR MSB
215 24 winston
                                ; Buffer MSB = FSR MSB, check LSB value
216
        inc l                   ; (hl) = LSB of hw register
217 384 winston
.waitforlsb2:
218 306 winston
        ld l, Sn_IR % 256       ; point hl at the IR, test for CONNRESET
219
        bit BIT_IR_DISCON, (hl)
220
        jp nz, J_resetbypeer
221
        ld l, Sn_TX_FSR0 % 256  ; point hl at free space register
222 24 winston
        ld a, (hl)              ; get LSB of FSR
223
        cp c                    ; and compare with LSB of passed value
224 384 winston
        jr c, .waitforlsb2      ; if C > (hl) wait until it's not.
225 24 winston
 
226 384 winston
.getoffset2:
227 24 winston
        ld (v_sockptr), hl      ; save the socket register pointer
228
        ld (v_copylen), bc      ; save the buffer length
229
        push de                 ; save the source buffer pointer
230
        ld l, Sn_TX_WR0 % 256   ; (hl) = TX write register offset MSB
231
        ld a, (hl)
232
        and gSn_TX_MASK / 256   ; and 0x07 - 2k buffers
233
        ld d, a                 ; high order of offset in d
234
        inc l
235
        ld e, (hl)              ; de = offset
236
 
237
        ; page in the correct bit of W5100 buffer memory. TX buffer for
238
        ; socket 0 and 1 in page 0x0104 and for 2 and 3 in 0x0105, mapping
239
        ; socket 0 and 2 to 0x1000, 1 and 3 to 0x1800.
240 384 winston
.setpage2:
241 24 winston
        ld a, h
242
        sub Sn_MR / 256         ; derive socket number
243
        bit 1, a                ; upper page or lower page?
244 384 winston
        jr nz, .upperpage2
245 110 winston
        ld a, TX_LWRDATAPAGE    ; W5100 phys. address 0x4000
246 24 winston
        call F_setpageA
247 384 winston
        jr .willitblend2
248
.upperpage2:
249 110 winston
        ld a, TX_UPRDATAPAGE    ; W5100 phys. address 0x5000
250 24 winston
        call F_setpageA
251
 
252
        ; add de (offset) and bc (length) and see if it's >0x0800, in
253
        ; which case buffer copy needs to wrap.
254 384 winston
.willitblend2:
255
        dec bc                  ; ...to2 check for >, not >=
256 24 winston
        ld h, d                 ; not ex hl, de because we need to preserve it
257
        ld l, e
258
        add hl, bc
259
        inc bc                  ; undo previous dec
260
        ld a, h
261
        cp 0x08                 ; Does copy go over 2k boundary?
262 384 winston
        jp p, .wrappedcopy2     ; The circular buffer wraps.
263 24 winston
 
264 384 winston
.straightcopy2:
265 24 winston
        ld hl, (v_sockptr)      ; restore socket pointer
266
        call F_getbaseaddr
267
        ex de, hl               ; for LDIR
268
        pop hl                  ; get stacked source address
269
        ldir
270
 
271 384 winston
.completetx2:
272 110 winston
        ld a, REGPAGE           ; registers in W5100 phys. 0x0000
273 24 winston
        call F_setpageA
274
        ld hl, (v_sockptr)      ; get the socket pointer back
275
        ld l, Sn_TX_WR0 % 256   ; transmit register
276
        ld d, (hl)              ; get MSB of TX_WR0
277
        inc l
278
        ld e, (hl)              ; get LSB of TX_WR0
279
        ex de, hl               ; swap into hl
280
        ld bc, (v_copylen)      ; get length that was copied into the buffer
281
        add hl, bc              ; new value of TX_WR0
282
        ex de, hl               ; move to de
283
        ld (hl), e              ; copy into TX_WR0
284
        dec l
285
        ld (hl), d
286
        ld l, Sn_CR % 256       ; (hl) = command register
287
        ld (hl), S_CR_SEND      ; update command register
288 143 winston
        ld a, (v_buf_pgb)       ; check to see whether to re-page area B
289
        and a                   ; zero?
290
        jp nz, F_setpageB       ; yes - restore page B and return.
291
        ret                     ; no, return.
292 24 winston
 
293 384 winston
.wrappedcopy2:
294 24 winston
        ld hl, 0x0800           ; the highest offset you can have
295
        sbc hl, de              ; hl = how many bytes before we hit the end
296
        ld (v_copied), hl       ; save it
297
        ld hl, (v_sockptr)      ; retrieve socket register ptr
298
        call F_getbaseaddr      ; hl is now source address
299
        ex de, hl               ; swap for LDIR
300
        pop hl                  ; get source address off stack
301
        ld bc, (v_copied)       ; length of this chunk
302
        ldir                    ; transfer
303
        ld a, d                 ; roll de back
304
        sub 0x08                ; 0x0800 bytes
305
        ld d, a
306
        push hl                 ; save current source buffer ptr
307
        ld bc, (v_copied)       ; bytes copied so far
308
        ld hl, (v_copylen)      ; total bytes to copy
309
        sbc hl, bc              ; hl = remaining bytes
310
        ld b, h
311
        ld c, l
312
        pop hl                  ; retrieve source buffer ptr
313
        ldir                    ; transfer remainder
314 384 winston
        jr .completetx2         ; done
315 24 winston
 
316 384 winston
J_resetbypeer_pop:
317 316 winston
        pop de
318 384 winston
J_resetbypeer:
319 316 winston
        ld a, (v_buf_pgb)       ; check to see whether to re-page area B
320
        and a                   ; zero?
321
        call nz, F_setpageB     ; yes - restore page B and return.
322 306 winston
        ld a, ECONNRESET
323
        scf
324
        ret
325
 
326 24 winston
;============================================================================
327
; F_getbaseaddr:
328
; This routine sets HL to the base address.
329
; On entry:     de = offset
330
;               h  = high order of socket register address
331
; On exit:      hl = base address
332 384 winston
.globl F_getbaseaddr
333
F_getbaseaddr:
334 24 winston
        ld l, 0
335
        ld a, h
336
        sub Sn_BASE             ; a = 0x10 for skt 0, 0x11 for skt 1, 0x12 etc.
337
        and %00010001           ; mask out all but bits 4 and 1
338
 
339
        ; at this stage, a = 0x10 for skt 0, 0x11 for skt 1, 0x10 for skt 2
340
        ; and 0x11 for skt 3. The entire W5100 receive buffer area for
341
        ; all sockets is 8k, but we're only paging in 4k at at time at
342
        ; 0x1000-0x1FFF, so the physical address should either end up
343
        ; being 0x1000 (skt 0 and 2) or 0x1800 (skt 1 and 3)
344
        bit 0, a                ; bit 0 set = odd numbered socket at 0x1800
345 384 winston
        jr nz, .oddsock3
346 24 winston
        ld h, a
347
        add hl, de              ; hl = physical address
348
        ret
349 384 winston
.oddsock3:
350
        add a, 0x07             ; odd sockets are 0x18xx addresses
351 24 winston
        ld h, a
352
        add hl, de
353
        ret
354
 
355 143 winston
;=========================================================================
356
; F_checkpageA
357
; On entry: DE = buffer start
358 384 winston
.globl F_checkpageA
359
F_checkpageA:
360 143 winston
        ld a, d
361
        and 0xF0                ; mask off top 4 bits
362
        cp 0x10                 ; are we in 0x1000 - 0x1FFF?
363 384 winston
        jr z, .swappages4       ; yes, swap pages.
364 143 winston
        xor a                   ; reset the sysvar
365
        ld (v_buf_pgb), a
366
        ret
367 384 winston
.swappages4:
368 143 winston
        ld a, d
369
        xor 0x30                ; flip bits 4 and 5 to convert 0x1xxx to 0x2xxx
370
        ld d, a
371
        ld a, (v_pgb)           ; get current page B
372
        ld (v_buf_pgb),a        ; save it
373
        ld a, (v_buf_pga)       ; get page A value
374
        call F_setpageB         ; page it in
375
        ret
376 306 winston