3ccfa0528aa70b5adc9ebcb467d45c48c6ea43ff
[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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "ao.h"
20
21 #define DBG_CLOCK       (1 << 3)
22 #define DBG_DATA        (1 << 4)
23 #define DBG_RESET_N     (1 << 5)
24
25 #define DBG_CLOCK_PIN   (P0_3)
26 #define DBG_DATA_PIN    (P0_4)
27 #define DBG_RESET_N_PIN (P0_5)
28
29 static void
30 ao_dbg_send_bits(uint8_t msk, uint8_t val)
31 {
32         P0 = (P0 & ~msk) | (val & msk);
33 }
34
35 #define ao_dbg_pause() do { _asm nop; nop; nop _endasm; } while (0);
36
37 void
38 ao_dbg_send_byte(uint8_t byte)
39 {
40         __xdata uint8_t b, d;
41
42         P0 |= DBG_DATA;
43         P0DIR |= DBG_DATA;
44         for (b = 0; b < 8; b++) {
45                 d = 0;
46                 if (byte & 0x80)
47                         d = DBG_DATA;
48                 byte <<= 1;
49                 ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, DBG_CLOCK|d);
50                 ao_dbg_pause();
51                 ao_dbg_send_bits(DBG_CLOCK|DBG_DATA,     0    |d);
52                 ao_dbg_pause();
53         }
54         P0DIR &= ~DBG_DATA;
55 }
56
57 uint8_t
58 ao_dbg_recv_byte(void)
59 {
60         __xdata uint8_t byte, b;
61
62         byte = 0;
63         for (b = 0; b < 8; b++) {
64                 byte = byte << 1;
65                 ao_dbg_send_bits(DBG_CLOCK, DBG_CLOCK);
66                 ao_dbg_pause();
67                 if (DBG_DATA_PIN)
68                         byte |= 1;
69                 ao_dbg_send_bits(DBG_CLOCK, 0);
70                 ao_dbg_pause();
71         }
72         return byte;
73 }
74
75 /* 8051 instructions
76  */
77 #define NOP                     0x00
78 #define MOV_direct_data         0x75
79 #define LJMP                    0x02
80 #define MOV_Rn_data(n)          (0x78 | (n))
81 #define DJNZ_Rn_rel(n)          (0xd8 | (n))
82 #define MOV_A_direct            0xe5
83 #define MOV_direct1_direct2     0x85
84 #define MOV_direct_A            0xf5
85 #define MOV_DPTR_data16         0x90
86 #define MOV_A_data              0x74
87 #define MOVX_atDPTR_A           0xf0
88 #define MOVX_A_atDPTR           0xe0
89 #define INC_DPTR                0xa3
90 #define TRAP                    0xa5
91 #define SJMP                    0x80
92 #define JB                      0x20
93
94 #define DEBUG_INSTR(l)          (0x54 | (l))
95
96 #define SFR_PSW                 0xD0
97 #define SFR_DPL0                0x82
98 #define SFR_DPH0                0x83
99 #define SFR_DPL1                0x84
100 #define SFR_DPH1                0x85
101
102 __xdata uint8_t save_acc;
103 __xdata uint8_t save_psw;
104 __xdata uint8_t save_dpl0;
105 __xdata uint8_t save_dph0;
106 __xdata uint8_t save_dpl1;
107 __xdata uint8_t save_dph1;
108
109 static uint8_t
110 ao_dbg_inst1(uint8_t a)
111 {
112         ao_dbg_send_byte(DEBUG_INSTR(1));
113         ao_dbg_send_byte(a);
114         return ao_dbg_recv_byte();
115 }
116
117 static uint8_t
118 ao_dbg_inst2(uint8_t a, uint8_t b)
119 {
120         ao_dbg_send_byte(DEBUG_INSTR(2));
121         ao_dbg_send_byte(a);
122         ao_dbg_send_byte(b);
123         return ao_dbg_recv_byte();
124 }
125
126 static uint8_t
127 ao_dbg_inst3(uint8_t a, uint8_t b, uint8_t c)
128 {
129         ao_dbg_send_byte(DEBUG_INSTR(3));
130         ao_dbg_send_byte(a);
131         ao_dbg_send_byte(b);
132         ao_dbg_send_byte(c);
133         return ao_dbg_recv_byte();
134 }
135
136 void
137 ao_dbg_start_transfer(uint16_t addr)
138 {
139         save_acc  = ao_dbg_inst1(NOP);
140         save_psw  = ao_dbg_inst2(MOV_A_direct, SFR_PSW);
141         save_dpl0 = ao_dbg_inst2(MOV_A_direct, SFR_DPL0);
142         save_dph0 = ao_dbg_inst2(MOV_A_direct, SFR_DPH0);
143         save_dpl1 = ao_dbg_inst2(MOV_A_direct, SFR_DPL1);
144         save_dph1 = ao_dbg_inst2(MOV_A_direct, SFR_DPH1);
145         ao_dbg_inst3(MOV_DPTR_data16, addr >> 8, addr);
146 }
147
148 void
149 ao_dbg_end_transfer(void)
150 {
151         ao_dbg_inst3(MOV_direct_data, SFR_DPL0, save_dpl0);
152         ao_dbg_inst3(MOV_direct_data, SFR_DPH0, save_dph0);
153         ao_dbg_inst3(MOV_direct_data, SFR_DPL1, save_dpl1);
154         ao_dbg_inst3(MOV_direct_data, SFR_DPH1, save_dph1);
155         ao_dbg_inst3(MOV_direct_data, SFR_PSW, save_psw);
156         ao_dbg_inst2(MOV_A_data, save_acc);
157 }
158
159 void
160 ao_dbg_write_byte(uint8_t byte)
161 {
162         ao_dbg_inst2(MOV_A_data, byte);
163         ao_dbg_inst1(MOVX_atDPTR_A);
164         ao_dbg_inst1(INC_DPTR);
165 }
166
167 uint8_t
168 ao_dbg_read_byte(void)
169 {
170         ao_dbg_inst1(MOVX_A_atDPTR);
171         return ao_dbg_inst1(INC_DPTR);
172 }
173
174 static void
175 ao_dbg_set_pins(void)
176 {
177         /* Disable peripheral use of P0 */
178         ADCCFG = 0;
179         P0SEL = 0;
180         
181         
182         /* make P0_4 tri-state */
183         P0INP = DBG_DATA;
184         P2INP &= ~(P2INP_PDUP0_PULL_DOWN);
185         
186         /* Raise RESET_N and CLOCK */
187         P0 = DBG_RESET_N | DBG_CLOCK;
188
189         /* RESET_N and CLOCK are outputs now */
190         P0DIR = DBG_RESET_N | DBG_CLOCK;
191 }
192
193 void
194 ao_dbg_debug_mode(void)
195 {
196         ao_dbg_set_pins();
197         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
198         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|    0    );
199         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
200         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|    0    );
201         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    );
202         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|DBG_RESET_N);
203 }
204
205 void
206 ao_dbg_reset(void)
207 {
208         ao_dbg_set_pins();
209         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
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|    0    );
214         ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N);
215 }
216