-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlink_hd.inc
More file actions
284 lines (218 loc) · 12.2 KB
/
link_hd.inc
File metadata and controls
284 lines (218 loc) · 12.2 KB
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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
nolist
#ifndef LINK_HD_INC
#define LINK_HD_INC
;**********************************************************************
; *
; Description: Half duplex data link macros. *
; *
; Author: Chris White (whitecf69@gmail.com) *
; *
; Copyright (C) 2018 by Monitor Computing Services Limited, licensed *
; under CC BY-NC-SA 4.0. To view a copy of this license, visit *
; https://creativecommons.org/licenses/by-nc-sa/4.0/ *
; *
; This program is distributed in the hope that it will be useful, but *
; WITHOUT ANY WARRANTY; without even the implied warranty of *
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
; *
;**********************************************************************
; *
; Switches: CLKD_LINK - 'Clocked link', no delay timing needed *
; *
; If CLKD_LINK then running of delays is done externally and *
; the link interface handlers are only invoked when these have *
; expired. *
; *
;**********************************************************************
#ifndef maxlwdefined
#define maxlwdefined
;**********************************************************************
; *
; Macro: MaxLw *
; *
; Utility to load W with numerically greater of arguments *
; *
;**********************************************************************
MaxLw macro arg1, arg2
#if (arg1 > arg2)
movlw arg1
#else
movlw arg2
#endif
endm
#endif
;**********************************************************************
; Constants *
;**********************************************************************
; lnkState - Link state register
; bits 0,1 - Current state
; 0 - Switching to Rx
; 1 - Receiving data
; 2 - Waiting for far end to turn around
; 3 - Transmiting data
; bits 2,3 - Unused
; bit 4 - Tx enabled
; bit 5 - Rx enabled
; bit 6 - Synchronise, Tx or Rx a break
; bit 7 - Required direction, set = Tx, clear = Rx
LNKSTTEMASK EQU B'00000011' ; Mask to isolate state value
LNKTXFLG EQU 4 ; Link Tx active status bit
LNKRXFLG EQU 5 ; Link Rx active status bit
LNKSYNFLG EQU 6 ; Synchronise Tx or Rx status bit
LNKDIRFLG EQU 7 ; Required direction bit, set = Tx, clear = Rx
;**********************************************************************
; *
; Macro: SrvcLink *
; *
; State machine macro to implement half duplex link *
; *
; Arguments: lnkState - Link's state machine state variable *
; dlyTmr - Link's delay timer *
; LINKDLYRX - Delay for when switching to Rx *
; LINKDLYTX - Delay, used twice, for when switching to Tx *
; LINKTMOUT - Delay value to timeout if no data received *
; EnableTx - Subroutine to enable physical Tx *
; InitTx - Subroutine to initialise physical Tx *
; SrvcTx - Subroutine to perform physical Tx *
; TxSynch - Subroutine to start physical Tx of a synch *
; EnableRx - Subroutine to enable physical Rx *
; InitRx - Subroutine to initialise physical Rx *
; SrvcRx - Subroutine to perform physical Rx *
; *
;**********************************************************************
SrvcLink macro lnkState, dlyTmr, LINKDLYRX, LINKDLYTX, EnableTx, InitTx, SrvcTx, TxSynch, EnableRx, InitRx, SrvcRx
local StateTable, State0, State1, State2, State3, SkipRxBreak, CheckRxDir, State4, State5, State6, State7, State8, State9, CheckTxDir, FlipToRx, LoadLinkTmr, SrvcLinkEnd
#ifndef CLKD_LINK
decf dlyTmr,W ; Decrement delay timing counter
btfss STATUS,Z ; Skip if delay expired ...
goto LoadLinkTmr ; ... else just update the delay timer
#endif
movlw high StateTable ; Load jump table address high byte ...
movwf PCLATH ; ... into PCLATH to make jump in same code block
movf lnkState,W ; Use current state value ...
andlw LNKSTTEMASK ; ... (after removing flag bits) ...
addwf PCL,F ; ... as offset into state jump table
StateTable
; Rx states
goto State0 ; State 0 - Switching to Rx
goto State1 ; State 1 - Receiving data
goto State2 ; State 2 - Waiting for far end to turn around
goto State3 ; State 3 - Transmiting data
#if (high StateTable) != (high $)
error "Link service state machine split across page boundary"
#endif
State0 ; State 0 - Switching to Rx
call EnableRx ; Enable Rx physical interface
call InitRx ; Initialise physical Rx
incf lnkState,F ; Next state = Receiving data
MaxLw LINKDLYRX, 1
goto LoadLinkTmr ; Load physical interface settle delay
State1 ; State 1 - Receiving data
bsf lnkState,LNKRXFLG ; Enable link Rx
call SrvcRx ; Service link serial reception
btfss lnkState,LNKDIRFLG ; Skip if required direction is Tx ...
goto SrvcLinkEnd ; ... else continue to receive
; Need to change direction to Tx
bcf lnkState,LNKRXFLG ; Disable link Rx (link is half duplex)
incf lnkState,F ; Next state = Waiting for far end to turn around
MaxLw LINKDLYTX, 1
goto LoadLinkTmr ; Load far end turn around delay
State2 ; State 2 - Waiting for far end to turn around
call EnableTx ; Enable Tx physical interface
call InitTx ; Initialise physical Tx
bsf lnkState,LNKTXFLG ; Enable link Tx
incf lnkState,F ; Next state = Transmiting data
MaxLw LINKDLYTX, 1
goto LoadLinkTmr ; Load physical interface settle delay
State3 ; State 3 - Transmiting data
call SrvcTx ; Service link serial transmission
xorlw TX_IDLE ; Test if transmit is idle ...
btfss STATUS,Z ; ... if so skip ...
goto SrvcLinkEnd ; ... else continue transmiting
btfsc lnkState,LNKSYNFLG ; Skip if synchronise not required ...
call TxSynch ; ... else trigger synchronise
bcf lnkState,LNKSYNFLG ; Clear synchronise required flag
btfsc lnkState,LNKDIRFLG ; Skip if required direction is Rx
goto SrvcLinkEnd ; ... else continue transmiting
; Change direction to Rx
bcf lnkState,LNKTXFLG ; Disable link Tx (link is half duplex)
movlw ~LNKSTTEMASK ; Mask out state value
andwf lnkState,F ; Next state = Switching to Rx
goto State0
LoadLinkTmr
#ifndef CLKD_LINK
movwf dlyTmr ; Update timing counter
#endif
SrvcLinkEnd
endm
;**********************************************************************
; *
; Macro: LinkRx *
; *
; Attempt to get an 'Rx' byte from the link *
; *
; Arguments: lnkState - Link's state machine state variable *
; PhysRx - Subroutine to attempt to get 'Rx' byte from *
; physical interface *
; *
; Returns : STATUS,Z - Set if got byte, clear if not *
; W - Rx byte, if any *
; *
;**********************************************************************
LinkRx macro lnkState, PhysRx
local QuitRx
bcf STATUS,Z ; Default return is no data received
btfss lnkState,LNKRXFLG ; Skip if in receiving data state ...
return ; ... else abandon check for received data
btfss lnkState,LNKSYNFLG ; Skip if waiting to synchronise ...
goto PhysRx ; ... else look for received data
return
endm
;**********************************************************************
; *
; Macro: LinkTx *
; *
; Attempt to send a 'Tx' byte to the link *
; *
; Arguments: FSR - Byte to send *
; lnkState - Link's state machine state variable *
; PhysRx - Subroutine to attempt to send 'Tx' byte to *
; physical interface *
; *
; Returns : STATUS,Z - Set if sent byte, clear if not *
; *
;**********************************************************************
LinkTx macro lnkState, PhysTx
bcf STATUS,Z ; Default return is no data sent
btfsc lnkState,LNKTXFLG ; Skip if not in sending data state ...
goto PhysTx ; ... else attempt to send data
return
endm
;**********************************************************************
; *
; Macro: SyncRx *
; *
; Schedule Rx synchronisation *
; *
; Arguments: lnkState - Link's state machine state variable *
; *
;**********************************************************************
SyncRx macro lnkState
bcf lnkState,LNKDIRFLG ; Ensure link direction is Rx
bsf lnkState,LNKSYNFLG ; Set synchronise required
endm
;**********************************************************************
; *
; Macro: SyncTx *
; *
; Schedule Tx synchronisation *
; *
; Arguments: lnkState - Link's state machine state variable *
; *
;**********************************************************************
SyncTx macro lnkState
bsf lnkState,LNKDIRFLG ; Ensure link direction is Tx
bsf lnkState,LNKSYNFLG ; Set synchronise required
endm
#endif
list