Clean up telemetry now that all packets are the same
[fw/altos] / ao_dbg.c
1 /*
2  * Copyright © 2009 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "ao.h"
19
20 #define DBG_CLOCK       (1 << 3)
21 #define DBG_DATA        (1 << 4)
22 #define DBG_RESET_N     (1 << 5)
23
24 #define DBG_CLOCK_PIN   (P0_3)
25 #define DBG_DATA_PIN    (P0_4)
26 #define DBG_RESET_N_PIN (P0_5)
27
28 static void
29 ao_dbg_send_bits(uint8_t msk, uint8_t val)
30 {
31         P0 = (P0 & ~msk) | (val & msk);
32         _asm
33                 nop
34                 nop
35                 nop
36                 nop
37                 nop
38                 nop
39         _endasm;
40 }
41
42 void
43 ao_dbg_send_byte(uint8_t byte)
44 {
45         __xdata uint8_t b, d;
46
47         P0 |= DBG_DATA;
48         P0DIR |= DBG_DATA;
49         for (b = 0; b < 8; b++) {
50                 d = 0;
51                 if (byte & 0x80)
52                         d = DBG_DATA;
53                 byte <<= 1;
54                 ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, DBG_CLOCK|d);
55                 ao_dbg_send_bits(DBG_CLOCK|DBG_DATA,     0    |d);
56         }
57         P0DIR &= ~DBG_DATA;
58 }
59
60 uint8_t
61 ao_dbg_recv_byte(void)
62 {
63         __xdata uint8_t byte, b;
64
65         byte = 0;
66         for (b = 0; b < 8; b++) {
67                 byte = byte << 1;
68                 ao_dbg_send_bits(DBG_CLOCK, DBG_CLOCK);
69                 if (DBG_DATA_PIN)
70                         byte |= 1;
71                 ao_dbg_send_bits(DBG_CLOCK, 0);
72         }
73         return byte;
74 }
75
76 /* 8051 instructions
77  */
78 #define NOP                     0x00
79 #define MOV_direct_data         0x75
80 #define LJMP                    0x02
81 #define MOV_Rn_data(n)          (0x78 | (n))
82 #define DJNZ_Rn_rel(n)          (0xd8 | (n))
83 #define MOV_A_direct            0xe5
84 #define MOV_direct1_direct2     0x85
85 #define MOV_direct_A            0xf5
86 #define MOV_DPTR_data16         0x90
87 #define MOV_A_data              0x74
88 #define MOVX_atDPTR_A           0xf0
89 #define MOVX_A_atDPTR           0xe0
90 #define INC_DPTR                0xa3
91 #define TRAP                    0xa5
92 #define SJMP                    0x80
93 #define JB                      0x20
94
95 #define DEBUG_INSTR(l)          (0x54 | (l))
96
97 #define SFR_PSW                 0xD0
98 #define SFR_DPL0                0x82
99 #define SFR_DPH0                0x83
100 #define SFR_DPL1                0x84
101 #define SFR_DPH1                0x85
102
103 __xdata uint8_t save_acc;
104 __xdata uint8_t save_psw;
105 __xdata uint8_t save_dpl0;
106 __xdata uint8_t save_dph0;
107 __xdata uint8_t save_dpl1;
108 __xdata uint8_t save_dph1;
109
110 static uint8_t
111 ao_dbg_inst1(uint8_t a) __reentrant
112 {
113         ao_dbg_send_byte(DEBUG_INSTR(1));
114         ao_dbg_send_byte(a);
115         return ao_dbg_recv_byte();
116 }
117
118 static uint8_t
119 ao_dbg_inst2(uint8_t a, uint8_t b) __reentrant
120 {
121         ao_dbg_send_byte(DEBUG_INSTR(2));
122         ao_dbg_send_byte(a);
123         ao_dbg_send_byte(b);
124         return ao_dbg_recv_byte();
125 }
126
127 static uint8_t
128 ao_dbg_inst3(uint8_t a, uint8_t b, uint8_t c) __reentrant
129 {
130         ao_dbg_send_byte(DEBUG_INSTR(3));
131         ao_dbg_send_byte(a);
132         ao_dbg_send_byte(b);
133         ao_dbg_send_byte(c);
134         return ao_dbg_recv_byte();
135 }
136
137 void
138 ao_dbg_start_transfer(uint16_t addr)
139 {
140         save_acc  = ao_dbg_inst1(NOP);
141         save_psw  = ao_dbg_inst2(MOV_A_direct, SFR_PSW);
142         save_dpl0 = ao_dbg_inst2(MOV_A_direct, SFR_DPL0);
143         save_dph0 = ao_dbg_inst2(MOV_A_direct, SFR_DPH0);
144         save_dpl1 = ao_dbg_inst2(MOV_A_direct, SFR_DPL1);
145         save_dph1 = ao_dbg_inst2(MOV_A_direct, SFR_DPH1);
146         ao_dbg_inst3(MOV_DPTR_data16, addr >> 8, addr);
147 }
148
149 void
150 ao_dbg_end_transfer(void)
151 {
152         ao_dbg_inst3(MOV_direct_data, SFR_DPL0, save_dpl0);
153         ao_dbg_inst3(MOV_direct_data, SFR_DPH0, save_dph0);
154         ao_dbg_inst3(MOV_direct_data, SFR_DPL1, save_dpl1);
155         ao_dbg_inst3(MOV_direct_data, SFR_DPH1, save_dph1);
156         ao_dbg_inst3(MOV_direct_data, SFR_PSW, save_psw);
157         ao_dbg_inst2(MOV_A_data, save_acc);
158 }
159
160 void
161 ao_dbg_write_byte(uint8_t byte)
162 {
163         ao_dbg_inst2(MOV_A_data, byte);
164         ao_dbg_inst1(MOVX_atDPTR_A);
165         ao_dbg_inst1(INC_DPTR);
166 }
167
168 uint8_t
169 ao_dbg_read_byte(void)
170 {
171         ao_dbg_inst1(MOVX_A_atDPTR);
172         return ao_dbg_inst1(INC_DPTR);
173 }
174
175 static void
176 ao_dbg_set_pins(void)
177 {
178         /* Disable peripheral use of P0 */
179         ADCCFG = 0;
180         P0SEL = 0;
181         
182         
183         /* make P0_4 tri-state */
184         P0INP = DBG_DATA;
185         P2INP &= ~(P2INP_PDUP0_PULL_DOWN);
186         
187         /* Raise RESET_N and CLOCK */
188         P0 = DBG_RESET_N | DBG_CLOCK;
189
190         /* RESET_N and CLOCK are outputs now */
191         P0DIR = DBG_RESET_N | DBG_CLOCK;
192 }
193
194 static void
195 ao_dbg_long_delay(void)
196 {
197         uint8_t n;
198
199         for (n = 0; n < 20; n++)
200                 _asm nop _endasm;
201 }
202
203 void
204 ao_dbg_debug_mode(void)
205 {
206         ao_dbg_set_pins();
207         ao_dbg_long_delay();
208         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
209         ao_dbg_long_delay();
210         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|    0    );
211         ao_dbg_long_delay();
212         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
213         ao_dbg_long_delay();
214         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|    0    );
215         ao_dbg_long_delay();
216         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
217         ao_dbg_long_delay();
218         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|DBG_RESET_N);
219         ao_dbg_long_delay();
220 }
221
222 void
223 ao_dbg_reset(void)
224 {
225         ao_dbg_set_pins();
226         ao_dbg_long_delay();
227         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
228         ao_dbg_long_delay();
229         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
230         ao_dbg_long_delay();
231         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
232         ao_dbg_long_delay();
233         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
234         ao_dbg_long_delay();
235         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
236         ao_dbg_long_delay();
237         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
238         ao_dbg_long_delay();
239 }
240
241 static void
242 debug_enable(void)
243 {
244         ao_dbg_debug_mode();
245 }
246
247 static void
248 debug_reset(void)
249 {
250         ao_dbg_reset();
251 }
252
253 static void
254 debug_put(void)
255 {
256         for (;;) {
257                 ao_cmd_white ();
258                 if (ao_cmd_lex_c == '\n')
259                         break;
260                 ao_cmd_hex();
261                 if (ao_cmd_status != ao_cmd_success)
262                         break;
263                 ao_dbg_send_byte(ao_cmd_lex_i);
264         }
265 }
266
267 static void
268 debug_get(void)
269 {
270         __xdata uint16_t count;
271         __xdata uint16_t i;
272         __xdata uint8_t byte;
273         ao_cmd_hex();
274         if (ao_cmd_status != ao_cmd_success)
275                 return;
276         count = ao_cmd_lex_i;
277         if (count > 256) {
278                 ao_cmd_status = ao_cmd_syntax_error;
279                 return;
280         }
281         for (i = 0; i < count; i++) {
282                 if (i && (i & 7) == 0)
283                         putchar('\n');
284                 byte = ao_dbg_recv_byte();
285                 ao_cmd_put8(byte);
286                 putchar(' ');
287         }
288         putchar('\n');
289 }
290
291 static uint8_t
292 getnibble(void)
293 {
294         __xdata uint8_t c;
295
296         c = getchar();
297         if ('0' <= c && c <= '9')
298                 return c - '0';
299         if ('a' <= c && c <= 'f')
300                 return c - ('a' - 10);
301         if ('A' <= c && c <= 'F')
302                 return c - ('A' - 10);
303         ao_cmd_status = ao_cmd_lex_error;
304         return 0;
305 }
306
307 static void
308 debug_input(void)
309 {
310         __xdata uint16_t count;
311         __xdata uint16_t addr;
312         __xdata uint8_t b;
313         __xdata uint8_t i;
314
315         ao_cmd_hex();
316         count = ao_cmd_lex_i;
317         ao_cmd_hex();
318         addr = ao_cmd_lex_i;
319         if (ao_cmd_status != ao_cmd_success)
320                 return;
321         ao_dbg_start_transfer(addr);
322         i = 0;
323         while (count--) {
324                 if (!(i++ & 7))
325                         putchar('\n');
326                 b = ao_dbg_read_byte();
327                 ao_cmd_put8(b);
328         }
329         ao_dbg_end_transfer();
330         putchar('\n');
331 }
332
333 static void
334 debug_output(void)
335 {
336         __xdata uint16_t count;
337         __xdata uint16_t addr;
338         __xdata uint8_t b;
339
340         ao_cmd_hex();
341         count = ao_cmd_lex_i;
342         ao_cmd_hex();
343         addr = ao_cmd_lex_i;
344         if (ao_cmd_status != ao_cmd_success)
345                 return;
346         ao_dbg_start_transfer(addr);
347         while (count--) {
348                 b = getnibble() << 4;
349                 b |= getnibble();
350                 if (ao_cmd_status != ao_cmd_success)
351                         return;
352                 ao_dbg_write_byte(b);
353         }
354         ao_dbg_end_transfer();
355 }
356
357 __code struct ao_cmds ao_dbg_cmds[7] = {
358         { 'D',  debug_enable,   "D                                  Enable debug mode" },
359         { 'G',  debug_get,      "G <count>                          Get data from debug port" },
360         { 'I',  debug_input,    "I <count> <addr>                   Input <count> bytes to target at <addr>" },
361         { 'O',  debug_output,   "O <count> <addr>                   Output <count> bytes to target at <addr>" },
362         { 'P',  debug_put,      "P <byte> ...                       Put data to debug port" },
363         { 'R',  debug_reset,    "R                                  Reset target" },
364         { 0, debug_reset,       0 },
365 };
366
367 void
368 ao_dbg_init(void)
369 {
370         ao_cmd_register(&ao_dbg_cmds[0]);
371 }