-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathslip.s
251 lines (237 loc) · 5.78 KB
/
slip.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
;
; SLIP driver for the Z80
; http://www.cosam.org/projects/z80/
;
; Implements Serial Line IP as per RFC 1055
;
; Steve Maddison, 04/01/2008
;
; The framing characters
slip_char_end: equ 0xc0 ; 0300
slip_char_esc: equ 0xdb ; 0333
slip_char_esc_end: equ 0xdc ; 0334
slip_char_esc_esc: equ 0xdd ; 0335
slip_dev_name: defm "sl0\0"
slip_driver: defw slip_datagram_rx
defw slip_datagram_tx
; Name: slip_check_datagram_size
; Desc: Check for maximum datagram size
; In: DE = size to test
; Out: CF = set if DE > maximum
slip_check_datagram_size:
push hl ; save
push bc ; save
push de
pop bc
and a ; clear CF (but keep A)
ld hl,slip_buffer_size
sbc hl,bc
pop bc ; restore
pop hl ; restore
ret
; Name: slip_intr_rx
; Desc: Receive data from SLIP interface on interrupt
slip_intr_rx:
push af
push hl
ld hl,(slip_buffer_ptr)
slip_intr_rx_loop:
; Check UART for data
call uart_rx_ready_no_block
jp z,slip_intr_rx_end
in a,(uart_rbr)
slip_intr_rx_check_end:
cp slip_char_end
jp nz,slip_intr_rx_check_esc_end
; Check for (over) full buffer
call slip_rx_buffer_full
jp nc,slip_intr_rx_discard
; Pass datagram to IP layer
ld hl,slip_internal_buffer
call ip_rx
slip_intr_rx_discard:
; Mark buffer as empty
ld hl,0
; We're done with this datagram, but there may be a new
; one waiting, so start again.
jp slip_intr_rx_loop
slip_intr_rx_check_esc_end:
cp slip_char_esc_end
jp nz,slip_intr_rx_check_esc_esc
ld a,(hl)
cp slip_char_esc
jp nz,slip_intr_rx_default
ld (hl),slip_char_end
jp slip_intr_rx_loop
slip_intr_rx_check_esc_esc:
cp slip_char_esc_esc
jp nz,slip_intr_rx_default
ld a,(hl)
cp slip_char_esc
jp nz,slip_intr_rx_default
ld (hl),slip_char_esc
jp slip_intr_rx_loop
slip_intr_rx_default:
; Is the buffer empty?
push af
ld a,h
or l
jp z,slip_intr_rx_write
pop af
; Is the buffer full?
call slip_rx_buffer_full
jp nc,slip_intr_rx_end
; Only now do we increment the pointer
inc hl
slip_intr_rx_write:
ld (hl),a
jp slip_intr_rx_loop
slip_intr_rx_end:
ld (slip_buffer_ptr),hl
pop hl
pop af
ret
; Name: slip_rx_buffer_full
; Desc: Check if buffer is full
; In: HL = buffer pointer
; Out: CF = clear if buffer full
slip_rx_buffer_full:
push de
push hl
ld de,slip_buffer_end
and a ; clear CF
sbc hl,de
pop hl
pop de
ret
; Name: slip_datagram_rx
; Desc: Receive a datagram from the serial port, de-framing on the fly.
; In: HL = input buffer address (or 0 for internal buffer)
; Out: DE = bytes written to buffer
; CF = set if datagram was too large
slip_datagram_rx:
call slip_set_buffer
ld d,0
ld e,0
slip_datagram_rx_loop:
call uart_rx
slip_datagram_rx_check_end:
cp slip_char_end
jp z,slip_datagram_rx_success
slip_datagram_rx_check_esc:
cp slip_char_esc
jp nz,slip_datagram_rx_default
; We got an escape, so fetch the escaped character
call uart_rx
slip_datagram_rx_check_esc_end:
cp slip_char_esc_end
jp nz,slip_datagram_rx_check_esc_esc
ld a,slip_char_end
slip_datagram_rx_check_esc_esc:
cp slip_char_esc_esc
jp nz,slip_datagram_rx_default
ld a,slip_char_esc
slip_datagram_rx_default:
; Checking for a too-large datagram can only be done after we know
; we actually want to write something to the buffer.
call slip_check_datagram_size
jp c,slip_datagram_rx_end
ld (hl),a
inc hl
inc de
jp slip_datagram_rx_loop
slip_datagram_rx_success:
xor a
slip_datagram_rx_end:
ret
; Name: slip_datagram_tx
; Desc: Send a datagram to the serial port, framing on the fly,
; including the terminating "end" character.
; In: HL = start of datagram
; DE = length of datagram
; Out: ZF = set on success, clear on error
; A = 0 on success, 1 if datagram too large
slip_datagram_tx:
call slip_check_datagram_size
jp nc,slip_datagram_tx_size_ok
ld a,1 ; clear zero flag
and a
jp slip_datagram_tx_end
slip_datagram_tx_size_ok:
call slip_tx_data
jp nz,slip_datagram_tx_end ; bail out
call slip_datagram_tx_terminate
xor a
slip_datagram_tx_end:
ret
; Name: slip_tx_data
; Desc: Send raw data to the serial port, framing on the fly,
; without the terminating end character.
; In: HL = start of data
; DE = length of data
; Out: ZF = set on success, clear on error
slip_tx_data:
slip_tx_data_loop:
ld a,d
or e
jp z,slip_tx_data_end
ld a,(hl)
slip_tx_data_check_end:
cp slip_char_end
jp nz,slip_tx_data_check_esc
ld a,slip_char_esc
call uart_tx
ld a,slip_char_esc_end
call uart_tx
jp slip_tx_data_sent
slip_tx_data_check_esc:
cp slip_char_esc
jp nz,slip_tx_data_default
ld a,slip_char_esc
call uart_tx
ld a,slip_char_esc_esc
call uart_tx
jp slip_tx_data_sent
slip_tx_data_default:
call uart_tx ; byte to send is still in A
slip_tx_data_sent:
inc hl
dec de
jp slip_tx_data_loop
slip_tx_data_end:
ret
; Name: slip_datagram_tx_terminate
; Desc: Send the terminating "end" character
slip_datagram_tx_terminate:
ld a,slip_char_end
call uart_tx
ret
; Name: slip_get_buffer
; Desc: Return address of internal buffer
; Out: HL = buffer address;
slip_get_buffer:
ld hl,slip_internal_buffer
ret
; Name: slip_init
; Desc: Initialise SLIP device
slip_init:
; Add a new device
ld a,0 ; ID
ld b,dev_flag_char ; Flags
ld de,slip_driver ; Driver
ld hl,slip_dev_name ; Name
call dev_add
ld hl,0
ld (slip_buffer_ptr),hl
ret
; Name: slip_set_buffer
; Desc: Check for magic buffer address (0)
; In: HL = proposed buffer address
; Out: HL = actual buffer address
slip_set_buffer:
ld a,h
or l
jp nz,slip_set_buffer_end
ld hl,slip_internal_buffer
slip_set_buffer_end:
ret