1
+ --- avr.c
2
+ +++ avr.c
3
+ @@ -1058,6 +1058,33 @@ int avr_signature(PROGRAMMER * pgm, AVRPART * p)
4
+ return 0;
5
+ }
6
+
7
+ + uint8_t get_fuse_bitmask(AVRMEM * m) {
8
+ + uint8_t bitmask_r = 0;
9
+ + uint8_t bitmask_w = 0;
10
+ + int i, j;
11
+ + for (i=0; i<AVR_OP_MAX; i++) {
12
+ + if (m->op[i] && strcmp(avr_op_str(i),"READ") == 0) {
13
+ + for (j=7; j>=0; j--) {
14
+ + bitmask_r |= (strcmp(bittype(m->op[i]->bit[j].type), "IGNORE") != 0) << j;
Collapse comment Comment on line R14
Why use bittype here? You can just compare .type with one of the AVR_CMDBIT_* constants AFAICS?
Code has comments. Press enter to view.
15
+ + }
16
+ + }
17
+ + if (m->op[i] && strcmp(avr_op_str(i),"WRITE") == 0) {
18
+ + for (j=7; j>=0; j--) {
19
+ + bitmask_w |= (strcmp(bittype(m->op[i]->bit[j].type), "VALUE") != 0 &&
20
+ + strcmp(bittype(m->op[i]->bit[j].type), "IGNORE") != 0) << j;
21
+ + }
22
+ + }
23
+ + }
24
+ + return bitmask_r & bitmask_w;
25
+ + }
26
+ +
27
+ + int skip_fuse_memory_masked(AVRMEM * m, unsigned char buf1, unsigned char buf2) {
28
+ + if (m->size > 1) {
29
+ + return 1;
30
+ + }
31
+ + uint8_t bitmask = get_fuse_bitmask(m);
32
+ + return ((buf1 & bitmask) != (buf2 & bitmask));
33
+ + }
34
+
35
+ /*
36
+ * Verify the memory buffer of p with that of v. The byte range of v,
37
+ @@ -1103,7 +1130,7 @@ int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size)
38
+
39
+ for (i=0; i<size; i++) {
40
+ if ((b->tags[i] & TAG_ALLOCATED) != 0 &&
41
+ - buf1[i] != buf2[i]) {
42
+ + (buf1[i] != buf2[i]) && (skip_fuse_memory_masked(a , buf1[i], buf2[i]))) {
Collapse comment Comment on line R42
This actually compares the buffers twice. Why not just let get_fuse_bitmask() return 0xff for all non-fuse memories and always apply it? No need for a separate skip_fuse_memory_masked function then either.
Code has comments. Press enter to view.
43
+ avrdude_message(MSG_INFO, "%s: verification error, first mismatch at byte 0x%04x\n"
44
+ "%s0x%02x != 0x%02x\n",
45
+ progname, i,
46
+ --- avrpart.c
47
+ +++ avrpart.c
48
+ @@ -205,7 +205,7 @@ int avr_get_output_index(OPCODE * op)
49
+ }
50
+
51
+
52
+ - static char * avr_op_str(int op)
53
+ + char * avr_op_str(int op)
54
+ {
55
+ switch (op) {
56
+ case AVR_OP_READ : return "READ"; break;
57
+ @@ -225,7 +225,7 @@ static char * avr_op_str(int op)
58
+ }
59
+
60
+
61
+ - static char * bittype(int type)
62
+ + char * bittype(int type)
63
+ {
64
+ switch (type) {
65
+ case AVR_CMDBIT_IGNORE : return "IGNORE"; break;
66
+ @@ -405,7 +405,7 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, int type,
67
+ m->readback[1]);
68
+ if (verbose > 4) {
69
+ avrdude_message(MSG_TRACE2, "%s Memory Ops:\n"
70
+ - "%s Oeration Inst Bit Bit Type Bitno Value\n"
71
+ + "%s Operation Inst Bit Bit Type Bitno Value\n"
Collapse comment Comment on line R71
Does this line really belong here? Better just submit this as a fix separately upstream? Better to not change the avrdude output if not needed, in case tools want to parse it perhaps.
Code has comments. Press enter to view.
72
+ "%s ----------- -------- -------- ----- -----\n",
73
+ prefix, prefix, prefix);
74
+ for (i=0; i<AVR_OP_MAX; i++) {
75
+ --- libavrdude.h
76
+ +++ libavrdude.h
77
+ @@ -297,6 +297,7 @@ typedef struct avrmem {
78
+
79
+ unsigned char * buf; /* pointer to memory buffer */
80
+ unsigned char * tags; /* allocation tags */
81
+ + unsigned char * mask; /* mask tags */
Collapse comment Comment on line R81
Is this field even used? I can't find any use of it.
Code has comments. Press enter to view.
82
+ OPCODE * op[AVR_OP_MAX]; /* opcodes */
83
+ } AVRMEM;
84
+
85
+ @@ -337,6 +338,12 @@ typedef void (*walk_avrparts_cb)(const char *name, const char *desc,
86
+ void *cookie);
87
+ void walk_avrparts(LISTID avrparts, walk_avrparts_cb cb, void *cookie);
88
+ void sort_avrparts(LISTID avrparts);
89
+ +
90
+ +
91
+ + char * avr_op_str(int op);
92
+ + char * bittype(int type);
93
+ + uint8_t get_fuse_bitmask(AVRMEM * m);
94
+ +
95
+ #ifdef __cplusplus
96
+ }
97
+ #endif
98
+ @@ -818,7 +825,7 @@ amount of times before giving up */
99
+ int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm, AVRPART * p, int tries);
100
+
101
+ /* Reads the fuses three times, checking that all readings are the same. This will ensure that the before values aren't in error! */
102
+ - int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse, PROGRAMMER * pgm, AVRPART * p);
103
+ + int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse, unsigned char * efuse_mask, PROGRAMMER * pgm, AVRPART * p);
104
+
105
+ /* This routine will store the current values pointed to by lfuse, hfuse, and efuse into an internal buffer in this routine
106
+ when save is set to 1. When save is 0 (or not 1 really) it will copy the values from the internal buffer into the locations
107
+ --- main.c
108
+ +++ main.c
109
+ @@ -344,6 +344,7 @@ int main(int argc, char * argv [])
110
+ unsigned char safemode_lfuse = 0xff;
111
+ unsigned char safemode_hfuse = 0xff;
112
+ unsigned char safemode_efuse = 0xff;
113
+ + unsigned char safemode_efuse_mask = 0xff;
114
+ unsigned char safemode_fuse = 0xff;
115
+
116
+ char * safemode_response;
117
+ @@ -1131,7 +1132,7 @@ int main(int argc, char * argv [])
118
+ and extended fuse bytes as needed */
119
+
120
+ rc = safemode_readfuses(&safemode_lfuse, &safemode_hfuse,
121
+ - &safemode_efuse, &safemode_fuse, pgm, p);
122
+ + &safemode_efuse, &safemode_fuse, &safemode_efuse_mask, pgm, p);
123
+
124
+ if (rc != 0) {
125
+
126
+ @@ -1239,6 +1240,7 @@ int main(int argc, char * argv [])
127
+ unsigned char safemodeafter_lfuse = 0xff;
128
+ unsigned char safemodeafter_hfuse = 0xff;
129
+ unsigned char safemodeafter_efuse = 0xff;
130
+ + unsigned char safemodeafter_efuse_mask = 0xff;
Collapse comment Comment on line R130
Why only efuse? Can't the problem occur for other fuses as well, perhaps for other atmegas that Arduino doesn't currently use?
Code has comments. Press enter to view.
131
+ unsigned char safemodeafter_fuse = 0xff;
132
+ unsigned char failures = 0;
133
+ char yes[1] = {'y'};
134
+ @@ -1252,16 +1254,15 @@ int main(int argc, char * argv [])
135
+
136
+ /* Try reading back fuses, make sure they are reliable to read back */
137
+ if (safemode_readfuses(&safemodeafter_lfuse, &safemodeafter_hfuse,
138
+ - &safemodeafter_efuse, &safemodeafter_fuse, pgm, p) != 0) {
139
+ + &safemodeafter_efuse, &safemodeafter_fuse, &safemodeafter_efuse_mask, pgm, p) != 0) {
140
+ /* Uh-oh.. try once more to read back fuses */
141
+ if (safemode_readfuses(&safemodeafter_lfuse, &safemodeafter_hfuse,
142
+ - &safemodeafter_efuse, &safemodeafter_fuse, pgm, p) != 0) {
143
+ + &safemodeafter_efuse, &safemodeafter_fuse, &safemodeafter_efuse_mask, pgm, p) != 0) {
144
+ avrdude_message(MSG_INFO, "%s: safemode: Sorry, reading back fuses was unreliable. "
145
+ "I have given up and exited programming mode\n",
146
+ progname);
147
+ exitrc = 1;
148
+ - goto main_exit;
149
+ - }
150
+ + goto main_exit; }
151
+ }
152
+
153
+ /* Now check what fuses are against what they should be */
154
+ @@ -1346,7 +1347,7 @@ int main(int argc, char * argv [])
155
+ }
156
+
157
+ /* Now check what fuses are against what they should be */
158
+ - if (safemodeafter_efuse != safemode_efuse) {
159
+ + if ((safemodeafter_efuse & safemodeafter_efuse_mask) != (safemode_efuse & safemodeafter_efuse_mask)) {
160
+ fuses_updated = 1;
161
+ avrdude_message(MSG_INFO, "%s: safemode: efuse changed! Was %x, and is now %x\n",
162
+ progname, safemode_efuse, safemodeafter_efuse);
163
+ --- safemode.c
164
+ +++ safemode.c
165
+ @@ -75,7 +75,7 @@ int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm,
166
+ * same. This will ensure that the before values aren't in error!
167
+ */
168
+ int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse,
169
+ - unsigned char * efuse, unsigned char * fuse,
170
+ + unsigned char * efuse, unsigned char * fuse, unsigned char * efuse_mask,
171
+ PROGRAMMER * pgm, AVRPART * p)
172
+ {
173
+
174
+ @@ -85,12 +85,14 @@ int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse,
175
+ unsigned char safemode_lfuse;
176
+ unsigned char safemode_hfuse;
177
+ unsigned char safemode_efuse;
178
+ + unsigned char safemode_efuse_mask;
179
+ unsigned char safemode_fuse;
180
+ AVRMEM * m;
181
+
182
+ safemode_lfuse = *lfuse;
183
+ safemode_hfuse = *hfuse;
184
+ safemode_efuse = *efuse;
185
+ + safemode_efuse_mask = *efuse_mask;
186
+ safemode_fuse = *fuse;
187
+
188
+
189
+ @@ -229,8 +231,10 @@ int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse,
190
+ /* Read efuse three times */
191
+ fusegood = 2; /* If AVR device doesn't support this fuse, don't want
192
+ to generate a verify error */
193
+ +
194
+ m = avr_locate_mem(p, "efuse");
195
+ if (m != NULL) {
196
+ + safemode_efuse_mask = get_fuse_bitmask(m);
Collapse comment Comment on line R196
Why does this happen in safemode_readfuses? Can't the caller (main) just call get_fuse_bitmask() instead?
Code has comments. Press enter to view.
197
+ fusegood = 0; /* By default fuse is a failure */
198
+ if (pgm->read_byte(pgm, p, m, 0, &safemode_efuse) != 0)
199
+ {
200
+ @@ -272,6 +276,7 @@ int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse,
201
+ *lfuse = safemode_lfuse;
202
+ *hfuse = safemode_hfuse;
203
+ *efuse = safemode_efuse;
204
+ + *efuse_mask = safemode_efuse_mask;
205
+ *fuse = safemode_fuse;
206
+
207
+ return 0;
0 commit comments