632ea0cc |
1 | /* Memory-access and commands for inferior process, for GDB. |
4187119d |
2 | Copyright (C) 1988, 1989 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GDB. |
5 | |
6 | GDB is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 1, or (at your option) |
9 | any later version. |
10 | |
11 | GDB is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | GNU General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GDB; see the file COPYING. If not, write to |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
632ea0cc |
19 | |
20 | /* Remote communication protocol. |
21 | All values are encoded in ascii hex digits. |
22 | |
23 | Request Packet |
24 | |
25 | read registers g |
26 | reply XX....X Each byte of register data |
27 | is described by two hex digits. |
28 | Registers are in the internal order |
29 | for GDB, and the bytes in a register |
30 | are in the same order the machine uses. |
31 | or ENN for an error. |
32 | |
33 | write regs GXX..XX Each byte of register data |
34 | is described by two hex digits. |
35 | reply OK for success |
36 | ENN for an error |
37 | |
38 | read mem mAA..AA,LLLL AA..AA is address, LLLL is length. |
39 | reply XX..XX XX..XX is mem contents |
40 | or ENN NN is errno |
41 | |
42 | write mem MAA..AA,LLLL:XX..XX |
43 | AA..AA is address, |
44 | LLLL is number of bytes, |
45 | XX..XX is data |
46 | reply OK for success |
47 | ENN for an error |
48 | |
49 | cont cAA..AA AA..AA is address to resume |
50 | If AA..AA is omitted, |
51 | resume at same address. |
52 | |
53 | step sAA..AA AA..AA is address to resume |
54 | If AA..AA is omitted, |
55 | resume at same address. |
56 | |
4187119d |
57 | last signal ? Reply the current reason for stopping. |
58 | This is the same reply as is generated |
59 | for step or cont : SAA where AA is the |
60 | signal number. |
61 | |
632ea0cc |
62 | There is no immediate reply to step or cont. |
63 | The reply comes when the machine stops. |
64 | It is SAA AA is the "signal number" |
65 | |
66 | kill req k |
67 | */ |
68 | |
7a67dd45 |
69 | #include <stdio.h> |
632ea0cc |
70 | #include "defs.h" |
632ea0cc |
71 | #include "param.h" |
72 | #include "frame.h" |
73 | #include "inferior.h" |
74 | |
3bf57d21 |
75 | #include "wait.h" |
e91b87a3 |
76 | |
77 | #ifdef USG |
78 | #include <sys/types.h> |
79 | #include <fcntl.h> |
80 | #endif |
81 | |
e91b87a3 |
82 | #include <signal.h> |
632ea0cc |
83 | #include <sys/ioctl.h> |
632ea0cc |
84 | #include <sys/file.h> |
3bf57d21 |
85 | |
86 | #ifdef HAVE_TERMIO |
87 | #include <termio.h> |
88 | #undef TIOCGETP |
89 | #define TIOCGETP TCGETA |
90 | #undef TIOCSETN |
91 | #define TIOCSETN TCSETA |
92 | #undef TIOCSETP |
93 | #define TIOCSETP TCSETAF |
94 | #define TERMINAL struct termio |
95 | #else |
632ea0cc |
96 | #include <sgtty.h> |
3bf57d21 |
97 | #define TERMINAL struct sgttyb |
98 | #endif |
632ea0cc |
99 | |
4187119d |
100 | static int kiodebug; |
101 | static int timeout = 5; |
632ea0cc |
102 | |
4187119d |
103 | #if 0 |
632ea0cc |
104 | int icache; |
4187119d |
105 | #endif |
632ea0cc |
106 | |
4187119d |
107 | /* Descriptor for I/O to remote machine. Initialize it to -1 so that |
108 | remote_open knows that we don't have a file open when the program |
109 | starts. */ |
110 | int remote_desc = -1; |
632ea0cc |
111 | |
e91b87a3 |
112 | #define PBUFSIZ 400 |
632ea0cc |
113 | |
4187119d |
114 | /* Maximum number of bytes to read/write at once. The value here |
115 | is chosen to fill up a packet (the headers account for the 32). */ |
116 | #define MAXBUFBYTES ((PBUFSIZ-32)/2) |
117 | |
632ea0cc |
118 | static void remote_send (); |
119 | static void putpkt (); |
120 | static void getpkt (); |
4187119d |
121 | #if 0 |
632ea0cc |
122 | static void dcache_flush (); |
4187119d |
123 | #endif |
632ea0cc |
124 | |
632ea0cc |
125 | \f |
4187119d |
126 | /* Called when SIGALRM signal sent due to alarm() timeout. */ |
127 | #ifndef HAVE_TERMIO |
128 | void |
129 | remote_timer () |
130 | { |
131 | if (kiodebug) |
132 | printf ("remote_timer called\n"); |
133 | |
134 | alarm (timeout); |
135 | } |
136 | #endif |
137 | |
632ea0cc |
138 | /* Open a connection to a remote debugger. |
139 | NAME is the filename used for communication. */ |
140 | |
141 | void |
142 | remote_open (name, from_tty) |
143 | char *name; |
144 | int from_tty; |
145 | { |
3bf57d21 |
146 | TERMINAL sg; |
632ea0cc |
147 | |
4187119d |
148 | if (remote_desc >= 0) |
149 | close (remote_desc); |
150 | |
632ea0cc |
151 | remote_debugging = 0; |
4187119d |
152 | #if 0 |
632ea0cc |
153 | dcache_init (); |
4187119d |
154 | #endif |
632ea0cc |
155 | |
156 | remote_desc = open (name, O_RDWR); |
157 | if (remote_desc < 0) |
158 | perror_with_name (name); |
159 | |
160 | ioctl (remote_desc, TIOCGETP, &sg); |
3bf57d21 |
161 | #ifdef HAVE_TERMIO |
4187119d |
162 | sg.c_cc[VMIN] = 0; /* read with timeout. */ |
163 | sg.c_cc[VTIME] = timeout * 10; |
164 | sg.c_lflag &= ~(ICANON | ECHO); |
3bf57d21 |
165 | #else |
632ea0cc |
166 | sg.sg_flags = RAW; |
3bf57d21 |
167 | #endif |
632ea0cc |
168 | ioctl (remote_desc, TIOCSETP, &sg); |
169 | |
170 | if (from_tty) |
171 | printf ("Remote debugging using %s\n", name); |
172 | remote_debugging = 1; |
4187119d |
173 | |
174 | #ifndef HAVE_TERMIO |
175 | #ifndef NO_SIGINTERRUPT |
176 | /* Cause SIGALRM's to make reads fail. */ |
177 | if (siginterrupt (SIGALRM, 1) != 0) |
178 | perror ("remote_open: error in siginterrupt"); |
179 | #endif |
180 | |
181 | /* Set up read timeout timer. */ |
182 | if ((void (*)) signal (SIGALRM, remote_timer) == (void (*)) -1) |
183 | perror ("remote_open: error in signal"); |
184 | #endif |
185 | |
186 | putpkt ("?"); /* initiate a query from remote machine */ |
632ea0cc |
187 | } |
188 | |
4187119d |
189 | /* Close the open connection to the remote debugger. |
190 | Use this when you want to detach and do something else |
191 | with your gdb. */ |
192 | void |
193 | remote_close (from_tty) |
194 | int from_tty; |
195 | { |
196 | if (!remote_debugging) |
197 | error ("Can't close remote connection: not debugging remotely."); |
198 | |
199 | close (remote_desc); /* This should never be called if |
200 | there isn't something valid in |
201 | remote_desc. */ |
202 | |
203 | /* Do not try to close remote_desc again, later in the program. */ |
204 | remote_desc = -1; |
205 | |
206 | if (from_tty) |
207 | printf ("Ending remote debugging\n"); |
208 | |
209 | remote_debugging = 0; |
210 | } |
211 | |
632ea0cc |
212 | /* Convert hex digit A to a number. */ |
213 | |
214 | static int |
215 | fromhex (a) |
216 | int a; |
217 | { |
218 | if (a >= '0' && a <= '9') |
219 | return a - '0'; |
220 | else if (a >= 'a' && a <= 'f') |
221 | return a - 'a' + 10; |
222 | else |
223 | error ("Reply contains invalid hex digit"); |
224 | } |
225 | |
226 | /* Convert number NIB to a hex digit. */ |
227 | |
228 | static int |
229 | tohex (nib) |
230 | int nib; |
231 | { |
232 | if (nib < 10) |
233 | return '0'+nib; |
234 | else |
235 | return 'a'+nib-10; |
236 | } |
237 | \f |
238 | /* Tell the remote machine to resume. */ |
239 | |
240 | int |
241 | remote_resume (step, signal) |
242 | int step, signal; |
243 | { |
244 | char buf[PBUFSIZ]; |
245 | |
4187119d |
246 | #if 0 |
632ea0cc |
247 | dcache_flush (); |
4187119d |
248 | #endif |
632ea0cc |
249 | |
250 | strcpy (buf, step ? "s": "c"); |
251 | |
252 | putpkt (buf); |
253 | } |
254 | |
255 | /* Wait until the remote machine stops, then return, |
256 | storing status in STATUS just as `wait' would. */ |
257 | |
258 | int |
259 | remote_wait (status) |
3bf57d21 |
260 | WAITTYPE *status; |
632ea0cc |
261 | { |
4187119d |
262 | unsigned char buf[PBUFSIZ]; |
632ea0cc |
263 | |
3bf57d21 |
264 | WSETEXIT ((*status), 0); |
632ea0cc |
265 | getpkt (buf); |
266 | if (buf[0] == 'E') |
267 | error ("Remote failure reply: %s", buf); |
268 | if (buf[0] != 'S') |
269 | error ("Invalid remote reply: %s", buf); |
3bf57d21 |
270 | WSETSTOP ((*status), (((fromhex (buf[1])) << 4) + (fromhex (buf[2])))); |
632ea0cc |
271 | } |
272 | |
273 | /* Read the remote registers into the block REGS. */ |
274 | |
275 | void |
276 | remote_fetch_registers (regs) |
277 | char *regs; |
278 | { |
279 | char buf[PBUFSIZ]; |
280 | int i; |
281 | char *p; |
282 | |
283 | sprintf (buf, "g"); |
284 | remote_send (buf); |
285 | |
286 | /* Reply describes registers byte by byte, |
287 | each byte encoded as two hex characters. */ |
288 | |
289 | p = buf; |
290 | for (i = 0; i < REGISTER_BYTES; i++) |
291 | { |
292 | if (p[0] == 0 || p[1] == 0) |
293 | error ("Remote reply is too short: %s", buf); |
294 | regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); |
295 | p += 2; |
296 | } |
297 | } |
298 | |
299 | /* Store the remote registers from the contents of the block REGS. */ |
300 | |
301 | void |
302 | remote_store_registers (regs) |
303 | char *regs; |
304 | { |
305 | char buf[PBUFSIZ]; |
306 | int i; |
307 | char *p; |
308 | |
309 | buf[0] = 'G'; |
310 | |
311 | /* Command describes registers byte by byte, |
312 | each byte encoded as two hex characters. */ |
313 | |
314 | p = buf + 1; |
315 | for (i = 0; i < REGISTER_BYTES; i++) |
316 | { |
e91b87a3 |
317 | *p++ = tohex ((regs[i] >> 4) & 0xf); |
318 | *p++ = tohex (regs[i] & 0xf); |
632ea0cc |
319 | } |
4187119d |
320 | *p = '\0'; |
632ea0cc |
321 | |
322 | remote_send (buf); |
323 | } |
324 | |
4187119d |
325 | #if 0 |
632ea0cc |
326 | /* Read a word from remote address ADDR and return it. |
327 | This goes through the data cache. */ |
328 | |
329 | int |
330 | remote_fetch_word (addr) |
331 | CORE_ADDR addr; |
332 | { |
333 | if (icache) |
334 | { |
335 | extern CORE_ADDR text_start, text_end; |
336 | |
337 | if (addr >= text_start && addr < text_end) |
338 | { |
339 | int buffer; |
340 | xfer_core_file (addr, &buffer, sizeof (int)); |
341 | return buffer; |
342 | } |
343 | } |
344 | return dcache_fetch (addr); |
345 | } |
346 | |
347 | /* Write a word WORD into remote address ADDR. |
348 | This goes through the data cache. */ |
349 | |
350 | void |
351 | remote_store_word (addr, word) |
352 | CORE_ADDR addr; |
353 | int word; |
354 | { |
355 | dcache_poke (addr, word); |
356 | } |
4187119d |
357 | #else /* not 0 */ |
358 | void remote_fetch_word (addr) |
359 | CORE_ADDR addr; |
360 | { |
361 | error ("Internal error: remote_fetch_word is obsolete.\n"); |
362 | } |
363 | void remote_store_word (addr) |
364 | CORE_ADDR addr; |
365 | { |
366 | error ("Internal error: remote_store_word is obsolete.\n"); |
367 | } |
368 | #endif /* not 0 */ |
632ea0cc |
369 | \f |
370 | /* Write memory data directly to the remote machine. |
371 | This does not inform the data cache; the data cache uses this. |
372 | MEMADDR is the address in the remote memory space. |
373 | MYADDR is the address of the buffer in our space. |
374 | LEN is the number of bytes. */ |
375 | |
376 | void |
377 | remote_write_bytes (memaddr, myaddr, len) |
378 | CORE_ADDR memaddr; |
379 | char *myaddr; |
380 | int len; |
381 | { |
382 | char buf[PBUFSIZ]; |
383 | int i; |
384 | char *p; |
385 | |
386 | if (len > PBUFSIZ / 2 - 20) |
387 | abort (); |
388 | |
389 | sprintf (buf, "M%x,%x:", memaddr, len); |
390 | |
391 | /* Command describes registers byte by byte, |
392 | each byte encoded as two hex characters. */ |
393 | |
394 | p = buf + strlen (buf); |
395 | for (i = 0; i < len; i++) |
396 | { |
e91b87a3 |
397 | *p++ = tohex ((myaddr[i] >> 4) & 0xf); |
398 | *p++ = tohex (myaddr[i] & 0xf); |
632ea0cc |
399 | } |
4187119d |
400 | *p = '\0'; |
632ea0cc |
401 | |
402 | remote_send (buf); |
403 | } |
404 | |
405 | /* Read memory data directly from the remote machine. |
406 | This does not use the data cache; the data cache uses this. |
407 | MEMADDR is the address in the remote memory space. |
408 | MYADDR is the address of the buffer in our space. |
409 | LEN is the number of bytes. */ |
410 | |
411 | void |
412 | remote_read_bytes (memaddr, myaddr, len) |
413 | CORE_ADDR memaddr; |
414 | char *myaddr; |
415 | int len; |
416 | { |
417 | char buf[PBUFSIZ]; |
418 | int i; |
419 | char *p; |
420 | |
421 | if (len > PBUFSIZ / 2 - 1) |
422 | abort (); |
423 | |
424 | sprintf (buf, "m%x,%x", memaddr, len); |
425 | remote_send (buf); |
426 | |
427 | /* Reply describes registers byte by byte, |
428 | each byte encoded as two hex characters. */ |
429 | |
430 | p = buf; |
e91b87a3 |
431 | for (i = 0; i < len; i++) |
632ea0cc |
432 | { |
433 | if (p[0] == 0 || p[1] == 0) |
434 | error ("Remote reply is too short: %s", buf); |
435 | myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]); |
436 | p += 2; |
437 | } |
438 | } |
439 | \f |
4187119d |
440 | /* Read LEN bytes from inferior memory at MEMADDR. Put the result |
441 | at debugger address MYADDR. Returns errno value. */ |
442 | int |
443 | remote_read_inferior_memory(memaddr, myaddr, len) |
444 | CORE_ADDR memaddr; |
445 | char *myaddr; |
446 | int len; |
447 | { |
448 | int xfersize; |
449 | while (len > 0) |
450 | { |
451 | if (len > MAXBUFBYTES) |
452 | xfersize = MAXBUFBYTES; |
453 | else |
454 | xfersize = len; |
455 | |
456 | remote_read_bytes (memaddr, myaddr, xfersize); |
457 | memaddr += xfersize; |
458 | myaddr += xfersize; |
459 | len -= xfersize; |
460 | } |
461 | return 0; /* no error */ |
462 | } |
463 | |
464 | /* Copy LEN bytes of data from debugger memory at MYADDR |
465 | to inferior's memory at MEMADDR. Returns errno value. */ |
466 | int |
467 | remote_write_inferior_memory (memaddr, myaddr, len) |
468 | CORE_ADDR memaddr; |
469 | char *myaddr; |
470 | int len; |
471 | { |
472 | int xfersize; |
473 | while (len > 0) |
474 | { |
475 | if (len > MAXBUFBYTES) |
476 | xfersize = MAXBUFBYTES; |
477 | else |
478 | xfersize = len; |
479 | |
480 | remote_write_bytes(memaddr, myaddr, xfersize); |
481 | |
482 | memaddr += xfersize; |
483 | myaddr += xfersize; |
484 | len -= xfersize; |
485 | } |
486 | return 0; /* no error */ |
487 | } |
488 | \f |
632ea0cc |
489 | /* |
490 | |
491 | A debug packet whose contents are <data> |
492 | is encapsulated for transmission in the form: |
493 | |
494 | $ <data> # CSUM1 CSUM2 |
495 | |
496 | <data> must be ASCII alphanumeric and cannot include characters |
497 | '$' or '#' |
498 | |
499 | CSUM1 and CSUM2 are ascii hex representation of an 8-bit |
500 | checksum of <data>, the most significant nibble is sent first. |
501 | the hex digits 0-9,a-f are used. |
502 | |
503 | Receiver responds with: |
504 | |
505 | + - if CSUM is correct and ready for next packet |
506 | - - if CSUM is incorrect |
507 | |
508 | */ |
509 | |
4187119d |
510 | static int |
511 | readchar () |
512 | { |
513 | char buf; |
514 | |
515 | buf = '\0'; |
516 | #ifdef HAVE_TERMIO |
517 | /* termio does the timeout for us. */ |
518 | read (remote_desc, &buf, 1); |
519 | #else |
520 | alarm (timeout); |
521 | read (remote_desc, &buf, 1); |
522 | alarm (0); |
523 | #endif |
524 | |
525 | return buf & 0x7f; |
526 | } |
527 | |
632ea0cc |
528 | /* Send the command in BUF to the remote machine, |
529 | and read the reply into BUF. |
530 | Report an error if we get an error reply. */ |
531 | |
532 | static void |
533 | remote_send (buf) |
534 | char *buf; |
535 | { |
536 | int i; |
537 | putpkt (buf); |
538 | getpkt (buf); |
539 | |
540 | if (buf[0] == 'E') |
541 | error ("Remote failure reply: %s", buf); |
542 | } |
543 | |
544 | /* Send a packet to the remote machine, with error checking. |
545 | The data of the packet is in BUF. */ |
546 | |
547 | static void |
548 | putpkt (buf) |
549 | char *buf; |
550 | { |
551 | int i; |
4187119d |
552 | unsigned char csum = 0; |
632ea0cc |
553 | char buf2[500]; |
554 | char buf3[1]; |
555 | int cnt = strlen (buf); |
4187119d |
556 | char ch; |
632ea0cc |
557 | char *p; |
558 | |
632ea0cc |
559 | /* Copy the packet into buffer BUF2, encapsulating it |
560 | and giving it a checksum. */ |
561 | |
562 | p = buf2; |
563 | *p++ = '$'; |
564 | |
565 | for (i = 0; i < cnt; i++) |
566 | { |
567 | csum += buf[i]; |
568 | *p++ = buf[i]; |
569 | } |
570 | *p++ = '#'; |
571 | *p++ = tohex ((csum >> 4) & 0xf); |
572 | *p++ = tohex (csum & 0xf); |
573 | |
574 | /* Send it over and over until we get a positive ack. */ |
575 | |
576 | do { |
4187119d |
577 | if (kiodebug) |
578 | { |
579 | *p = '\0'; |
580 | printf ("Sending packet: %s (%s)\n", buf2, buf); |
581 | } |
632ea0cc |
582 | write (remote_desc, buf2, p - buf2); |
632ea0cc |
583 | |
4187119d |
584 | /* read until either a timeout occurs (\0) or '+' is read */ |
585 | do { |
586 | ch = readchar (); |
587 | } while ((ch != '+') && (ch != '\0')); |
588 | } while (ch != '+'); |
632ea0cc |
589 | } |
590 | |
591 | /* Read a packet from the remote machine, with error checking, |
592 | and store it in BUF. */ |
593 | |
594 | static void |
595 | getpkt (buf) |
596 | char *buf; |
597 | { |
598 | char *bp; |
e91b87a3 |
599 | unsigned char csum; |
4187119d |
600 | int c; |
601 | unsigned char c1, c2; |
632ea0cc |
602 | extern kiodebug; |
603 | |
4187119d |
604 | /* allow immediate quit while reading from device, it could be hung */ |
605 | immediate_quit++; |
606 | |
632ea0cc |
607 | while (1) |
608 | { |
e91b87a3 |
609 | /* Force csum to be zero here because of possible error retry. */ |
610 | csum = 0; |
611 | |
632ea0cc |
612 | while ((c = readchar()) != '$'); |
613 | |
614 | bp = buf; |
615 | while (1) |
616 | { |
617 | c = readchar (); |
618 | if (c == '#') |
619 | break; |
620 | *bp++ = c; |
621 | csum += c; |
622 | } |
623 | *bp = 0; |
624 | |
625 | c1 = fromhex (readchar ()); |
626 | c2 = fromhex (readchar ()); |
4187119d |
627 | if ((csum & 0xff) == (c1 << 4) + c2) |
632ea0cc |
628 | break; |
629 | printf ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", |
4187119d |
630 | (c1 << 4) + c2, csum & 0xff, buf); |
632ea0cc |
631 | write (remote_desc, "-", 1); |
632 | } |
633 | |
4187119d |
634 | immediate_quit--; |
635 | |
632ea0cc |
636 | write (remote_desc, "+", 1); |
637 | |
638 | if (kiodebug) |
639 | fprintf (stderr,"Packet received :%s\n", buf); |
640 | } |
641 | \f |
4187119d |
642 | /* The data cache leads to incorrect results because it doesn't know about |
643 | volatile variables, thus making it impossible to debug functions which |
644 | use hardware registers. Therefore it is #if 0'd out. Effect on |
645 | performance is some, for backtraces of functions with a few |
646 | arguments each. For functions with many arguments, the stack |
647 | frames don't fit in the cache blocks, which makes the cache less |
648 | helpful. Disabling the cache is a big performance win for fetching |
649 | large structures, because the cache code fetched data in 16-byte |
650 | chunks. */ |
651 | #if 0 |
632ea0cc |
652 | /* The data cache records all the data read from the remote machine |
653 | since the last time it stopped. |
654 | |
655 | Each cache block holds 16 bytes of data |
656 | starting at a multiple-of-16 address. */ |
657 | |
658 | #define DCACHE_SIZE 64 /* Number of cache blocks */ |
659 | |
660 | struct dcache_block { |
661 | struct dcache_block *next, *last; |
662 | unsigned int addr; /* Address for which data is recorded. */ |
663 | int data[4]; |
664 | }; |
665 | |
666 | struct dcache_block dcache_free, dcache_valid; |
667 | |
668 | /* Free all the data cache blocks, thus discarding all cached data. */ |
669 | |
670 | static void |
671 | dcache_flush () |
672 | { |
673 | register struct dcache_block *db; |
674 | |
675 | while ((db = dcache_valid.next) != &dcache_valid) |
676 | { |
677 | remque (db); |
678 | insque (db, &dcache_free); |
679 | } |
680 | } |
681 | |
682 | /* |
683 | * If addr is present in the dcache, return the address of the block |
684 | * containing it. |
685 | */ |
686 | |
687 | struct dcache_block * |
688 | dcache_hit (addr) |
689 | { |
690 | register struct dcache_block *db; |
691 | |
692 | if (addr & 3) |
693 | abort (); |
694 | |
695 | /* Search all cache blocks for one that is at this address. */ |
696 | db = dcache_valid.next; |
697 | while (db != &dcache_valid) |
698 | { |
699 | if ((addr & 0xfffffff0) == db->addr) |
700 | return db; |
701 | db = db->next; |
702 | } |
703 | return NULL; |
704 | } |
705 | |
706 | /* Return the int data at address ADDR in dcache block DC. */ |
707 | |
708 | int |
709 | dcache_value (db, addr) |
710 | struct dcache_block *db; |
711 | unsigned int addr; |
712 | { |
713 | if (addr & 3) |
714 | abort (); |
715 | return (db->data[(addr>>2)&3]); |
716 | } |
717 | |
718 | /* Get a free cache block, put it on the valid list, |
719 | and return its address. The caller should store into the block |
720 | the address and data that it describes. */ |
721 | |
722 | struct dcache_block * |
723 | dcache_alloc () |
724 | { |
725 | register struct dcache_block *db; |
726 | |
727 | if ((db = dcache_free.next) == &dcache_free) |
728 | /* If we can't get one from the free list, take last valid */ |
729 | db = dcache_valid.last; |
730 | |
731 | remque (db); |
732 | insque (db, &dcache_valid); |
733 | return (db); |
734 | } |
735 | |
736 | /* Return the contents of the word at address ADDR in the remote machine, |
737 | using the data cache. */ |
738 | |
739 | int |
740 | dcache_fetch (addr) |
741 | CORE_ADDR addr; |
742 | { |
743 | register struct dcache_block *db; |
744 | |
745 | db = dcache_hit (addr); |
746 | if (db == 0) |
747 | { |
748 | db = dcache_alloc (); |
749 | remote_read_bytes (addr & ~0xf, db->data, 16); |
750 | db->addr = addr & ~0xf; |
751 | } |
752 | return (dcache_value (db, addr)); |
753 | } |
754 | |
755 | /* Write the word at ADDR both in the data cache and in the remote machine. */ |
756 | |
757 | dcache_poke (addr, data) |
758 | CORE_ADDR addr; |
759 | int data; |
760 | { |
761 | register struct dcache_block *db; |
762 | |
763 | /* First make sure the word is IN the cache. DB is its cache block. */ |
764 | db = dcache_hit (addr); |
765 | if (db == 0) |
766 | { |
767 | db = dcache_alloc (); |
768 | remote_read_bytes (addr & ~0xf, db->data, 16); |
769 | db->addr = addr & ~0xf; |
770 | } |
771 | |
772 | /* Modify the word in the cache. */ |
773 | db->data[(addr>>2)&3] = data; |
774 | |
775 | /* Send the changed word. */ |
776 | remote_write_bytes (addr, &data, 4); |
777 | } |
778 | |
779 | /* Initialize the data cache. */ |
780 | |
781 | dcache_init () |
782 | { |
783 | register i; |
784 | register struct dcache_block *db; |
785 | |
786 | db = (struct dcache_block *) xmalloc (sizeof (struct dcache_block) * |
787 | DCACHE_SIZE); |
788 | dcache_free.next = dcache_free.last = &dcache_free; |
789 | dcache_valid.next = dcache_valid.last = &dcache_valid; |
790 | for (i=0;i<DCACHE_SIZE;i++,db++) |
791 | insque (db, &dcache_free); |
792 | } |
4187119d |
793 | #endif /* 0 */ |