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