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