Commit | Line | Data |
---|---|---|
4f8d4a38 DD |
1 | /* mem.c --- memory for RX simulator. |
2 | ||
dc3cf14f | 3 | Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. |
4f8d4a38 DD |
4 | Contributed by Red Hat, Inc. |
5 | ||
6 | This file is part of the GNU simulators. | |
7 | ||
8 | This program is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 3 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | This program is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
20 | ||
21 | /* This slows down the simulator and we get some false negatives from | |
22 | gcc, like when it uses a long-sized hole to hold a byte-sized | |
23 | variable, knowing that it doesn't care about the other bits. But, | |
24 | if you need to track down a read-from-unitialized bug, set this to | |
25 | 1. */ | |
26 | #define RDCHECK 0 | |
27 | ||
28 | #include <stdio.h> | |
29 | #include <stdlib.h> | |
30 | #include <string.h> | |
31 | ||
32 | #include "mem.h" | |
33 | #include "cpu.h" | |
34 | #include "syscalls.h" | |
35 | #include "misc.h" | |
36 | #include "err.h" | |
37 | ||
38 | #define L1_BITS (10) | |
39 | #define L2_BITS (10) | |
40 | #define OFF_BITS (12) | |
41 | ||
42 | #define L1_LEN (1 << L1_BITS) | |
43 | #define L2_LEN (1 << L2_BITS) | |
44 | #define OFF_LEN (1 << OFF_BITS) | |
45 | ||
46 | static unsigned char **pt[L1_LEN]; | |
47 | static unsigned char **ptr[L1_LEN]; | |
48 | ||
49 | /* [ get=0/put=1 ][ byte size ] */ | |
50 | static unsigned int mem_counters[2][5]; | |
51 | ||
52 | #define COUNT(isput,bytes) \ | |
53 | if (verbose && enable_counting) mem_counters[isput][bytes]++ | |
54 | ||
55 | void | |
56 | init_mem (void) | |
57 | { | |
58 | int i, j; | |
59 | ||
60 | for (i = 0; i < L1_LEN; i++) | |
61 | if (pt[i]) | |
62 | { | |
63 | for (j = 0; j < L2_LEN; j++) | |
64 | if (pt[i][j]) | |
65 | free (pt[i][j]); | |
66 | free (pt[i]); | |
67 | } | |
68 | memset (pt, 0, sizeof (pt)); | |
69 | memset (ptr, 0, sizeof (ptr)); | |
70 | memset (mem_counters, 0, sizeof (mem_counters)); | |
71 | } | |
72 | ||
73 | enum mem_ptr_action | |
74 | { | |
75 | MPA_WRITING, | |
76 | MPA_READING, | |
77 | MPA_CONTENT_TYPE | |
78 | }; | |
79 | ||
80 | static unsigned char * | |
81 | mem_ptr (unsigned long address, enum mem_ptr_action action) | |
82 | { | |
83 | int pt1 = (address >> (L2_BITS + OFF_BITS)) & ((1 << L1_BITS) - 1); | |
84 | int pt2 = (address >> OFF_BITS) & ((1 << L2_BITS) - 1); | |
85 | int pto = address & ((1 << OFF_BITS) - 1); | |
86 | ||
87 | if (address == 0) | |
88 | execution_error (SIM_ERR_NULL_POINTER_DEREFERENCE, 0); | |
89 | ||
90 | if (pt[pt1] == 0) | |
91 | { | |
92 | pt[pt1] = (unsigned char **) calloc (L2_LEN, sizeof (char **)); | |
93 | ptr[pt1] = (unsigned char **) calloc (L2_LEN, sizeof (char **)); | |
94 | } | |
95 | if (pt[pt1][pt2] == 0) | |
96 | { | |
97 | if (action == MPA_READING) | |
98 | execution_error (SIM_ERR_READ_UNWRITTEN_PAGES, address); | |
99 | ||
100 | pt[pt1][pt2] = (unsigned char *) malloc (OFF_LEN); | |
101 | memset (pt[pt1][pt2], 0, OFF_LEN); | |
102 | ptr[pt1][pt2] = (unsigned char *) malloc (OFF_LEN); | |
103 | memset (ptr[pt1][pt2], MC_UNINIT, OFF_LEN); | |
104 | } | |
105 | else if (action == MPA_READING | |
106 | && ptr[pt1][pt2][pto] == MC_UNINIT) | |
107 | execution_error (SIM_ERR_READ_UNWRITTEN_BYTES, address); | |
108 | ||
109 | if (action == MPA_WRITING) | |
110 | { | |
111 | if (ptr[pt1][pt2][pto] == MC_PUSHED_PC) | |
112 | execution_error (SIM_ERR_CORRUPT_STACK, address); | |
113 | ptr[pt1][pt2][pto] = MC_DATA; | |
114 | } | |
115 | ||
116 | if (action == MPA_CONTENT_TYPE) | |
117 | return ptr[pt1][pt2] + pto; | |
118 | ||
119 | return pt[pt1][pt2] + pto; | |
120 | } | |
121 | ||
122 | static inline int | |
123 | is_reserved_address (unsigned int address) | |
124 | { | |
125 | return (address >= 0x00020000 && address < 0x00080000) | |
126 | || (address >= 0x00100000 && address < 0x01000000) | |
127 | || (address >= 0x08000000 && address < 0xff000000); | |
128 | } | |
129 | ||
130 | static void | |
131 | used (int rstart, int i, int j) | |
132 | { | |
133 | int rend = i << (L2_BITS + OFF_BITS); | |
134 | rend += j << OFF_BITS; | |
135 | if (rstart == 0xe0000 && rend == 0xe1000) | |
136 | return; | |
137 | printf ("mem: %08x - %08x (%dk bytes)\n", rstart, rend - 1, | |
138 | (rend - rstart) / 1024); | |
139 | } | |
140 | ||
141 | static char * | |
142 | mcs (int isput, int bytes) | |
143 | { | |
144 | return comma (mem_counters[isput][bytes]); | |
145 | } | |
146 | ||
147 | void | |
148 | mem_usage_stats () | |
149 | { | |
150 | int i, j; | |
151 | int rstart = 0; | |
152 | int pending = 0; | |
153 | ||
154 | for (i = 0; i < L1_LEN; i++) | |
155 | if (pt[i]) | |
156 | { | |
157 | for (j = 0; j < L2_LEN; j++) | |
158 | if (pt[i][j]) | |
159 | { | |
160 | if (!pending) | |
161 | { | |
162 | pending = 1; | |
163 | rstart = (i << (L2_BITS + OFF_BITS)) + (j << OFF_BITS); | |
164 | } | |
165 | } | |
166 | else if (pending) | |
167 | { | |
168 | pending = 0; | |
169 | used (rstart, i, j); | |
170 | } | |
171 | } | |
172 | else | |
173 | { | |
174 | if (pending) | |
175 | { | |
176 | pending = 0; | |
177 | used (rstart, i, 0); | |
178 | } | |
179 | } | |
180 | /* mem foo: 123456789012 123456789012 123456789012 123456789012 | |
181 | 123456789012 */ | |
182 | printf (" byte short 3byte long" | |
183 | " opcode\n"); | |
184 | if (verbose > 1) | |
185 | { | |
186 | /* Only use comma separated numbers when being very verbose. | |
187 | Comma separated numbers are hard to parse in awk scripts. */ | |
188 | printf ("mem get: %12s %12s %12s %12s %12s\n", mcs (0, 1), mcs (0, 2), | |
189 | mcs (0, 3), mcs (0, 4), mcs (0, 0)); | |
190 | printf ("mem put: %12s %12s %12s %12s\n", mcs (1, 1), mcs (1, 2), | |
191 | mcs (1, 3), mcs (1, 4)); | |
192 | } | |
193 | else | |
194 | { | |
195 | printf ("mem get: %12u %12u %12u %12u %12u\n", | |
196 | mem_counters[0][1], mem_counters[0][2], | |
197 | mem_counters[0][3], mem_counters[0][4], | |
198 | mem_counters[0][0]); | |
199 | printf ("mem put: %12u %12u %12u %12u\n", | |
200 | mem_counters [1][1], mem_counters [1][2], | |
201 | mem_counters [1][3], mem_counters [1][4]); | |
202 | } | |
203 | } | |
204 | ||
205 | unsigned long | |
206 | mem_usage_cycles (void) | |
207 | { | |
208 | unsigned long rv = mem_counters[0][0]; | |
209 | rv += mem_counters[0][1] * 1; | |
210 | rv += mem_counters[0][2] * 2; | |
211 | rv += mem_counters[0][3] * 3; | |
212 | rv += mem_counters[0][4] * 4; | |
213 | rv += mem_counters[1][1] * 1; | |
214 | rv += mem_counters[1][2] * 2; | |
215 | rv += mem_counters[1][3] * 3; | |
216 | rv += mem_counters[1][4] * 4; | |
217 | return rv; | |
218 | } | |
219 | ||
220 | static int tpr = 0; | |
221 | static void | |
222 | s (int address, char *dir) | |
223 | { | |
224 | if (tpr == 0) | |
225 | printf ("MEM[%08x] %s", address, dir); | |
226 | tpr++; | |
227 | } | |
228 | ||
229 | #define S(d) if (trace) s(address, d) | |
230 | static void | |
231 | e () | |
232 | { | |
233 | if (!trace) | |
234 | return; | |
235 | tpr--; | |
236 | if (tpr == 0) | |
237 | printf ("\n"); | |
238 | } | |
239 | ||
240 | static char | |
241 | mtypec (int address) | |
242 | { | |
243 | unsigned char *cp = mem_ptr (address, MPA_CONTENT_TYPE); | |
244 | return "udp"[*cp]; | |
245 | } | |
246 | ||
247 | #define E() if (trace) e() | |
248 | ||
249 | void | |
250 | mem_put_byte (unsigned int address, unsigned char value) | |
251 | { | |
252 | unsigned char *m; | |
253 | char tc = ' '; | |
254 | ||
255 | if (trace) | |
256 | tc = mtypec (address); | |
257 | m = mem_ptr (address, MPA_WRITING); | |
258 | if (trace) | |
259 | printf (" %02x%c", value, tc); | |
260 | *m = value; | |
261 | switch (address) | |
262 | { | |
263 | case 0x00e1: | |
264 | { | |
265 | static int old_led = -1; | |
266 | static char *led_on[] = | |
267 | { "\033[31m O ", "\033[32m O ", "\033[34m O " }; |