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