1 /*
2 * Written by Kent Palmkvist (kentp@isy.liu.se>, 2005.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
18 *
19 *
20 */
21
22 #include <sysdep.h>
23
24 #include <stdint.h>
25 #include <string.h>
26
27 #include <urjtag/log.h>
28 #include <urjtag/error.h>
29 #include <urjtag/bus.h>
30 #include <urjtag/flash.h>
31 #include <urjtag/jtag.h>
32
33 int
urj_bus_writemem(urj_bus_t * bus,FILE * f,uint32_t addr,uint32_t len)34 urj_bus_writemem (urj_bus_t *bus, FILE *f, uint32_t addr, uint32_t len)
35 {
36 uint32_t step;
37 uint64_t a;
38 size_t bc = 0;
39 int bidx = 0;
40 #define BSIZE 4096
41 uint8_t b[BSIZE];
42 urj_bus_area_t area;
43 uint64_t end;
44
45 if (!bus)
46 {
47 urj_error_set (URJ_ERROR_NO_BUS_DRIVER, _("Missing bus driver"));
48 return URJ_STATUS_FAIL;
49 }
50
51 URJ_BUS_PREPARE (bus);
52
53 if (URJ_BUS_AREA (bus, addr, &area) != URJ_STATUS_OK)
54 return URJ_STATUS_FAIL;
55
56 step = area.width / 8;
57
58 if (step == 0)
59 {
60 urj_error_set (URJ_ERROR_INVALID, _("Unknown bus width"));
61 return URJ_STATUS_FAIL;
62 }
63 if (BSIZE % step != 0)
64 {
65 urj_error_set (URJ_ERROR_INVALID, "step %lu must divide BSIZE %d",
66 (long unsigned) step, BSIZE);
67 return URJ_STATUS_FAIL;
68 }
69
70 addr = addr & (~(step - 1));
71 len = (len + step - 1) & (~(step - 1));
72
73 urj_log (URJ_LOG_LEVEL_NORMAL, _("address: 0x%08lX\n"),
74 (long unsigned) addr);
75 urj_log (URJ_LOG_LEVEL_NORMAL, _("length: 0x%08lX\n"),
76 (long unsigned) len);
77
78 if (len == 0)
79 {
80 urj_error_set (URJ_ERROR_INVALID, _("length is 0"));
81 return URJ_STATUS_FAIL;
82 }
83
84 a = addr;
85 end = a + len;
86 urj_log (URJ_LOG_LEVEL_NORMAL, _("writing:\n"));
87
88 for (; a < end; a += step)
89 {
90 uint32_t data;
91 int j;
92
93 /* Read one block of data */
94 if (bc == 0)
95 {
96 urj_log (URJ_LOG_LEVEL_NORMAL, _("addr: 0x%08llX\r"),
97 (long long unsigned) a);
98 bc = fread (b, 1, BSIZE, f);
99 if (bc != BSIZE)
100 {
101 urj_log (URJ_LOG_LEVEL_NORMAL, _("Short read: bc=0x%zX\n"), bc);
102 if (bc < step)
103 {
104 // Not even enough for one step. Something is wrong. Check
105 // the file state and bail out.
106 if (feof (f))
107 urj_error_set (URJ_ERROR_FILEIO,
108 _("Unexpected end of file; Addr: 0x%08llX\n"),
109 (long long unsigned) a);
110 else
111 {
112 urj_error_set (URJ_ERROR_FILEIO, "fread fails");
113 urj_error_state.sys_errno = ferror(f);
114 clearerr(f);
115 }
116
117 return URJ_STATUS_FAIL;
118 }
119 /* else, process what we have read, then return to fread() to
120 * meet the error condition (again) */
121 }
122 bidx = 0;
123 }
124
125 /* Write a word at a time */
126 data = 0;
127 for (j = step; j > 0 && bc > 0; j--)
128 {
129 if (urj_get_file_endian () == URJ_ENDIAN_BIG)
130 {
131 /* first shift doesn't matter: data = 0 */
132 data <<= 8;
133 data |= b[bidx++];
134 }
135 else
136 data |= (b[bidx++] << ((step - j) * 8));
137 bc--;
138 }
139
140 URJ_BUS_WRITE (bus, a, data);
141 }
142
143 urj_log (URJ_LOG_LEVEL_NORMAL, _("\nDone.\n"));
144
145 return URJ_STATUS_OK;
146 }
147