Make ao_flight_test show AGL altitude and positive acceleration under boost
[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         _endasm;
36 }
37
38 void
39 ao_dbg_send_byte(uint8_t byte)
40 {
41         __xdata uint8_t b, d;
42
43         P0 |= DBG_DATA;
44         P0DIR |= DBG_DATA;
45         for (b = 0; b < 8; b++) {
46                 d = 0;
47                 if (byte & 0x80)
48                         d = DBG_DATA;
49                 byte <<= 1;
50                 ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, DBG_CLOCK|d);
51                 ao_dbg_send_bits(DBG_CLOCK|DBG_DATA,     0    |d);
52         }
53         P0DIR &= ~DBG_DATA;
54 }
55
56 uint8_t
57 ao_dbg_recv_byte(void)
58 {
59         __xdata uint8_t byte, b;
60
61         byte = 0;
62         for (b = 0; b < 8; b++) {
63                 byte = byte << 1;
64                 ao_dbg_send_bits(DBG_CLOCK, DBG_CLOCK);
65                 if (DBG_DATA_PIN)
66                         byte |= 1;
67                 ao_dbg_send_bits(DBG_CLOCK, 0);
68         }
69         return byte;
70 }
71
72 /* 8051 instructions
73  */
74 #define NOP                     0x00
75 #define MOV_direct_data         0x75
76 #define LJMP                    0x02
77 #define MOV_Rn_data(n)          (0x78 | (n))
78 #define DJNZ_Rn_rel(n)          (0xd8 | (n))
79 #define MOV_A_direct            0xe5
80 #define MOV_direct1_direct2     0x85
81 #define MOV_direct_A            0xf5
82 #define MOV_DPTR_data16         0x90
83 #define MOV_A_data              0x74
84 #define MOVX_atDPTR_A           0xf0
85 #define MOVX_A_atDPTR           0xe0
86 #define INC_DPTR                0xa3
87 #define TRAP                    0xa5
88 #define SJMP                    0x80
89 #define JB                      0x20
90
91 #define DEBUG_INSTR(l)          (0x54 | (l))
92
93 #define SFR_PSW                 0xD0
94 #define SFR_DPL0                0x82
95 #define SFR_DPH0                0x83
96 #define SFR_DPL1                0x84
97 #define SFR_DPH1                0x85
98
99 __xdata uint8_t save_acc;
100 __xdata uint8_t save_psw;
101 __xdata uint8_t save_dpl0;
102 __xdata uint8_t save_dph0;
103 __xdata uint8_t save_dpl1;
104 __xdata uint8_t save_dph1;
105
106 static uint8_t
107 ao_dbg_inst1(uint8_t a) __reentrant
108 {
109         ao_dbg_send_byte(DEBUG_INSTR(1));
110         ao_dbg_send_byte(a);
111         return ao_dbg_recv_byte();
112 }
113
114 static uint8_t
115 ao_dbg_inst2(uint8_t a, uint8_t b) __reentrant
116 {
117         ao_dbg_send_byte(DEBUG_INSTR(2));
118         ao_dbg_send_byte(a);
119         ao_dbg_send_byte(b);
120         return ao_dbg_recv_byte();
121 }
122
123 static uint8_t
124 ao_dbg_inst3(uint8_t a, uint8_t b, uint8_t c) __reentrant
125 {
126         ao_dbg_send_byte(DEBUG_INSTR(3));
127         ao_dbg_send_byte(a);
128         ao_dbg_send_byte(b);
129         ao_dbg_send_byte(c);
130         return ao_dbg_recv_byte();
131 }
132
133 void
134 ao_dbg_start_transfer(uint16_t addr)
135 {
136         save_acc  = ao_dbg_inst1(NOP);
137         save_psw  = ao_dbg_inst2(MOV_A_direct, SFR_PSW);
138         save_dpl0 = ao_dbg_inst2(MOV_A_direct, SFR_DPL0);
139         save_dph0 = ao_dbg_inst2(MOV_A_direct, SFR_DPH0);
140         save_dpl1 = ao_dbg_inst2(MOV_A_direct, SFR_DPL1);
141         save_dph1 = ao_dbg_inst2(MOV_A_direct, SFR_DPH1);
142         ao_dbg_inst3(MOV_DPTR_data16, addr >> 8, addr);
143 }
144
145 void
146 ao_dbg_end_transfer(void)
147 {
148         ao_dbg_inst3(MOV_direct_data, SFR_DPL0, save_dpl0);
149         ao_dbg_inst3(MOV_direct_data, SFR_DPH0, save_dph0);
150         ao_dbg_inst3(MOV_direct_data, SFR_DPL1, save_dpl1);
151         ao_dbg_inst3(MOV_direct_data, SFR_DPH1, save_dph1);
152         ao_dbg_inst3(MOV_direct_data, SFR_PSW, save_psw);
153         ao_dbg_inst2(MOV_A_data, save_acc);
154 }
155
156 void
157 ao_dbg_write_byte(uint8_t byte)
158 {
159         ao_dbg_inst2(MOV_A_data, byte);
160         ao_dbg_inst1(MOVX_atDPTR_A);
161         ao_dbg_inst1(INC_DPTR);
162 }
163
164 uint8_t
165 ao_dbg_read_byte(void)
166 {
167         ao_dbg_inst1(MOVX_A_atDPTR);
168         return ao_dbg_inst1(INC_DPTR);
169 }
170
171 static void
172 ao_dbg_set_pins(void)
173 {
174         /* Disable peripheral use of P0 */
175         ADCCFG = 0;
176         P0SEL = 0;
177         
178         
179         /* make P0_4 tri-state */
180         P0INP = DBG_DATA;
181         P2INP &= ~(P2INP_PDUP0_PULL_DOWN);
182         
183         /* Raise RESET_N and CLOCK */
184         P0 = DBG_RESET_N | DBG_CLOCK;
185
186         /* RESET_N and CLOCK are outputs now */
187         P0DIR = DBG_RESET_N | DBG_CLOCK;
188 }
189
190 static void
191 ao_dbg_long_delay(void)
192 {
193         uint8_t n;
194
195         for (n = 0; n < 20; n++)
196                 _asm nop _endasm;
197 }
198
199 void
200 ao_dbg_debug_mode(void)
201 {
202         ao_dbg_set_pins();
203         ao_dbg_long_delay();
204         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
205         ao_dbg_long_delay();
206         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|    0    );
207         ao_dbg_long_delay();
208         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
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|DBG_RESET_N);
215         ao_dbg_long_delay();
216 }
217
218 void
219 ao_dbg_reset(void)
220 {
221         ao_dbg_set_pins();
222         ao_dbg_long_delay();
223         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
224         ao_dbg_long_delay();
225         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
226         ao_dbg_long_delay();
227         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
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|DBG_RESET_N);
234         ao_dbg_long_delay();
235 }
236
237 static void
238 debug_enable(void)
239 {
240         ao_dbg_debug_mode();
241 }
242
243 static void
244 debug_reset(void)
245 {
246         ao_dbg_reset();
247 }
248
249 static void
250 debug_put(void)
251 {
252         for (;;) {
253                 ao_cmd_white ();
254                 if (ao_cmd_lex_c == '\n')
255                         break;
256                 ao_cmd_hex();
257                 if (ao_cmd_status != ao_cmd_success)
258                         break;
259                 ao_dbg_send_byte(ao_cmd_lex_i);
260         }
261 }
262
263 static void
264 debug_get(void)
265 {
266         __xdata uint16_t count;
267         __xdata uint16_t i;
268         __xdata uint8_t byte;
269         ao_cmd_hex();
270         if (ao_cmd_status != ao_cmd_success)
271                 return;
272         count = ao_cmd_lex_i;
273         if (count > 256) {
274                 ao_cmd_status = ao_cmd_syntax_error;
275                 return;
276         }
277         for (i = 0; i < count; i++) {
278                 if (i && (i & 7) == 0)
279                         putchar('\n');
280                 byte = ao_dbg_recv_byte();
281                 ao_cmd_put8(byte);
282                 putchar(' ');
283         }
284         putchar('\n');
285 }
286
287 static uint8_t
288 getnibble(void)
289 {
290         __xdata char    c;
291
292         c = getchar();
293         if ('0' <= c && c <= '9')
294                 return c - '0';
295         if ('a' <= c && c <= 'f')
296                 return c - ('a' - 10);
297         if ('A' <= c && c <= 'F')
298                 return c - ('A' - 10);
299         ao_cmd_status = ao_cmd_lex_error;
300         return 0;
301 }
302
303 static void
304 debug_input(void)
305 {
306         __xdata uint16_t count;
307         __xdata uint16_t addr;
308         __xdata uint8_t b;
309         __xdata uint8_t i;
310
311         ao_cmd_hex();
312         count = ao_cmd_lex_i;
313         ao_cmd_hex();
314         addr = ao_cmd_lex_i;
315         if (ao_cmd_status != ao_cmd_success)
316                 return;
317         ao_dbg_start_transfer(addr);
318         i = 0;
319         while (count--) {
320                 if (!(i++ & 7))
321                         putchar('\n');
322                 b = ao_dbg_read_byte();
323                 ao_cmd_put8(b);
324         }
325         ao_dbg_end_transfer();
326         putchar('\n');
327 }
328
329 static void
330 debug_output(void)
331 {
332         __xdata uint16_t count;
333         __xdata uint16_t addr;
334         __xdata uint8_t b;
335
336         ao_cmd_hex();
337         count = ao_cmd_lex_i;
338         ao_cmd_hex();
339         addr = ao_cmd_lex_i;
340         if (ao_cmd_status != ao_cmd_success)
341                 return;
342         ao_dbg_start_transfer(addr);
343         while (count--) {
344                 b = getnibble() << 4;
345                 b |= getnibble();
346                 if (ao_cmd_status != ao_cmd_success)
347                         return;
348                 ao_dbg_write_byte(b);
349         }
350         ao_dbg_end_transfer();
351 }
352
353 __code struct ao_cmds ao_dbg_cmds[7] = {
354         { 'D',  debug_enable,   "D                                  Enable debug mode" },
355         { 'G',  debug_get,      "G <count>                          Get data from debug port" },
356         { 'I',  debug_input,    "I <count> <addr>                   Input <count> bytes to target at <addr>" },
357         { 'O',  debug_output,   "O <count> <addr>                   Output <count> bytes to target at <addr>" },
358         { 'P',  debug_put,      "P <byte> ...                       Put data to debug port" },
359         { 'R',  debug_reset,    "R                                  Reset target" },
360         { 0, debug_reset,       0 },
361 };
362
363 void
364 ao_dbg_init(void)
365 {
366         ao_cmd_register(&ao_dbg_cmds[0]);
367 }