1 /* SPIM S20 MIPS simulator.
2 Code to create, maintain and access memory.
3
4 Copyright (c) 1990-2010, James R. Larus.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without modification,
8 are permitted provided that the following conditions are met:
9
10 Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12
13 Redistributions in binary form must reproduce the above copyright notice,
14 this list of conditions and the following disclaimer in the documentation and/or
15 other materials provided with the distribution.
16
17 Neither the name of the James R. Larus nor the names of its contributors may be
18 used to endorse or promote products derived from this software without specific
19 prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33
34 #include "spim.h"
35 #include "string-stream.h"
36 #include "spim-utils.h"
37 #include "inst.h"
38 #include "reg.h"
39 #include "mem.h"
40
41 /* Exported Variables: */
42
43 reg_word R[R_LENGTH];
44 reg_word HI, LO;
45 int HI_present, LO_present;
46 mem_addr PC, nPC;
47 double *FPR; /* Dynamically allocate so overlay */
48 float *FGR; /* is possible */
49 int *FWR; /* is possible */
50 reg_word CCR[4][32], CPR[4][32];
51
52 instruction **text_seg;
53 int text_modified; /* Non-zero means text segment was written */
54 mem_addr text_top;
55 mem_word *data_seg;
56 int data_modified; /* Non-zero means a data segment was written */
57 short *data_seg_h; /* Points to same vector as DATA_SEG */
58 BYTE_TYPE *data_seg_b; /* Ditto */
59 mem_addr data_top;
60 mem_addr gp_midpoint; /* Middle of $gp area */
61 mem_word *stack_seg;
62 short *stack_seg_h; /* Points to same vector as STACK_SEG */
63 BYTE_TYPE *stack_seg_b; /* Ditto */
64 mem_addr stack_bot;
65 instruction **k_text_seg;
66 mem_addr k_text_top;
67 mem_word *k_data_seg;
68 short *k_data_seg_h;
69 BYTE_TYPE *k_data_seg_b;
70 mem_addr k_data_top;
71
72
73 /* Local functions: */
74
75 static mem_word bad_mem_read (mem_addr addr, int mask);
76 static void bad_mem_write (mem_addr addr, mem_word value, int mask);
77 static instruction *bad_text_read (mem_addr addr);
78 static void bad_text_write (mem_addr addr, instruction *inst);
79 static void free_instructions (instruction **inst, int n);
80 static mem_word read_memory_mapped_IO (mem_addr addr);
81 static void write_memory_mapped_IO (mem_addr addr, mem_word value);
82
83
84 /* Local variables: */
85
86 static int32 data_size_limit, stack_size_limit, k_data_size_limit;
87
88
89
90 /* Memory is allocated in five chunks:
91 text, data, stack, kernel text, and kernel data.
92
93 The arrays are independent and have different semantics.
94
95 text is allocated from 0x400000 up and only contains INSTRUCTIONs.
96 It does not expand.
97
98 data is allocated from 0x10000000 up. It can be extended by the
99 SBRK system call. Programs can only read and write this segment.
100
101 stack grows from 0x7fffefff down. It is automatically extended.
102 Programs can only read and write this segment.
103
104 k_text is like text, except its is allocated from 0x80000000 up.
105
106 k_data is like data, but is allocated from 0x90000000 up.
107
108 Both kernel text and kernel data can only be accessed in kernel mode.
109 */
110
111 /* The text segments contain pointers to instructions, not actual
112 instructions, so they must be allocated large enough to hold as many
113 pointers as there would be instructions (the two differ on machines in
114 which pointers are not 32 bits long). The following calculations round
115 up in case size is not a multiple of BYTES_PER_WORD. */
116
117 #define BYTES_TO_INST(N) (((N) + BYTES_PER_WORD - 1) / BYTES_PER_WORD * sizeof(instruction*))
118
119
120 void
make_memory(int text_size,int data_size,int data_limit,int stack_size,int stack_limit,int k_text_size,int k_data_size,int k_data_limit)121 make_memory (int text_size, int data_size, int data_limit,
122 int stack_size, int stack_limit, int k_text_size,
123 int k_data_size, int k_data_limit)
124 {
125 if (data_size <= 65536)
126 data_size = 65536;
127 data_size = ROUND_UP(data_size, BYTES_PER_WORD); /* Keep word aligned */
128
129 if (text_seg == NULL)
130 text_seg = (instruction **) xmalloc (BYTES_TO_INST(text_size));
131 else
132 {
133 free_instructions (text_seg, (text_top - TEXT_BOT) / BYTES_PER_WORD);
134 text_seg = (instruction **) realloc (text_seg, BYTES_TO_INST(text_size));
135 }
136 memclr (text_seg, BYTES_TO_INST(text_size));
137 text_top = TEXT_BOT + text_size;
138
139 data_size = ROUND_UP(data_size, BYTES_PER_WORD); /* Keep word aligned */
140 if (data_seg == NULL)
141 data_seg = (mem_word *) xmalloc (data_size);
142 else
143 data_seg = (mem_word *) realloc (data_seg, data_size);
144 memclr (data_seg, data_size);
145 data_seg_b = (BYTE_TYPE *) data_seg;
146 data_seg_h = (short *) data_seg;
147 data_top = DATA_BOT + data_size;
148 data_size_limit = data_limit;
149
150 stack_size = ROUND_UP(stack_size, BYTES_PER_WORD); /* Keep word aligned */
151 if (stack_seg == NULL)
152 stack_seg = (mem_word *) xmalloc (stack_size);
153 else
154 stack_seg = (mem_word *) realloc (stack_seg, stack_size);
155 memclr (stack_seg, stack_size);
156 stack_seg_b = (BYTE_TYPE *) stack_seg;
157 stack_seg_h = (short *) stack_seg;
158 stack_bot = STACK_TOP - stack_size;
159 stack_size_limit = stack_limit;
160
161 if (k_text_seg == NULL)
162 k_text_seg = (instruction **) xmalloc (BYTES_TO_INST(k_text_size));
163 else
164 {
165 free_instructions (k_text_seg,
166 (k_text_top - K_TEXT_BOT) / BYTES_PER_WORD);
167 k_text_seg = (instruction **) realloc(k_text_seg,
168 BYTES_TO_INST(k_text_size));
169 }
170 memclr (k_text_seg, BYTES_TO_INST(k_text_size));
171 k_text_top = K_TEXT_BOT + k_text_size;
172
173 k_data_size = ROUND_UP(k_data_size, BYTES_PER_WORD); /* Keep word aligned */
174 if (k_data_seg == NULL)
175 k_data_seg = (mem_word *) xmalloc (k_data_size);
176 else
177 k_data_seg = (mem_word *) realloc (k_data_seg, k_data_size);
178 memclr (k_data_seg, k_data_size);
179 k_data_seg_b = (BYTE_TYPE *) k_data_seg;
180 k_data_seg_h = (short *) k_data_seg;
181 k_data_top = K_DATA_BOT + k_data_size;
182 k_data_size_limit = k_data_limit;
183
184 text_modified = 1;
185 data_modified = 1;
186 }
187
188
189 /* Free the storage used by the old instructions in memory. */
190
191 static void
free_instructions(instruction ** inst,int n)192 free_instructions (instruction **inst, int n)
193 {
194 for ( ; n > 0; n --, inst ++)
195 if (*inst)
196 free_inst (*inst);
197 }
198
199
200 /* Expand the data segment by adding N bytes. */
201
202 void
expand_data(int addl_bytes)203 expand_data (int addl_bytes)
204 {
205 int delta = ROUND_UP(addl_bytes, BYTES_PER_WORD); /* Keep word aligned */
206 int old_size = data_top - DATA_BOT;
207 int new_size = old_size + delta;
208 BYTE_TYPE *p;
209
210 if ((addl_bytes < 0) || (new_size > data_size_limit))
211 {
212 error ("Can't expand data segment by %d bytes to %d bytes\n",
213 addl_bytes, new_size);
214 run_error ("Use -ldata # with # > %d\n", new_size);
215 }
216 data_seg = (mem_word *) realloc (data_seg, new_size);
217 if (data_seg == NULL)
218 fatal_error ("realloc failed in expand_data\n");
219
220 data_seg_b = (BYTE_TYPE *) data_seg;
221 data_seg_h = (short *) data_seg;
222 data_top += delta;
223
224 /* Zero new memory */
225 for (p = data_seg_b + old_size; p < data_seg_b + new_size; )
226 *p ++ = 0;
227 }
228
229
230 /* Expand the stack segment by adding N bytes. Can't use REALLOC
231 since it copies from bottom of memory blocks and stack grows down from
232 top of its block. */
233
234 void
expand_stack(int addl_bytes)235 expand_stack (int addl_bytes)
236 {
237 int delta = ROUND_UP(addl_bytes, BYTES_PER_WORD); /* Keep word aligned */
238 int old_size = STACK_TOP - stack_bot;
239 int new_size = old_size + MAX (delta, old_size);
240 mem_word *new_seg;
241 mem_word *po, *pn;
242
243 if ((addl_bytes < 0) || (new_size > stack_size_limit))
244 {
245 error ("Can't expand stack segment by %d bytes to %d bytes\n",
246 addl_bytes, new_size);
247 run_error ("Use -lstack # with # > %d\n", new_size);
248 }
249
250 new_seg = (mem_word *) xmalloc (new_size);
251 po = stack_seg + (old_size / BYTES_PER_WORD - 1);
252 pn = new_seg + (new_size / BYTES_PER_WORD - 1);
253
254 for ( ; po >= stack_seg ; ) *pn -- = *po --;
255 for ( ; pn >= new_seg ; ) *pn -- = 0;
256
257 free (stack_seg);
258 stack_seg = new_seg;
259 stack_seg_b = (BYTE_TYPE *) stack_seg;
260 stack_seg_h = (short *) stack_seg;
261 stack_bot -= (new_size - old_size);
262 }
263
264
265 /* Expand the kernel data segment by adding N bytes. */
266
267 void
expand_k_data(int addl_bytes)268 expand_k_data (int addl_bytes)
269 {
270 int delta = ROUND_UP(addl_bytes, BYTES_PER_WORD); /* Keep word aligned */
271 int old_size = k_data_top - K_DATA_BOT;
272 int new_size = old_size + delta;
273 BYTE_TYPE *p;
274
275 if ((addl_bytes < 0) || (new_size > k_data_size_limit))
276 {
277 error ("Can't expand kernel data segment by %d bytes to %d bytes\n",
278 addl_bytes, new_size);
279 run_error ("Use -lkdata # with # > %d\n", new_size);
280 }
281 k_data_seg = (mem_word *) realloc (k_data_seg, new_size);
282 if (k_data_seg == NULL)
283 fatal_error ("realloc failed in expand_k_data\n");
284
285 k_data_seg_b = (BYTE_TYPE *) k_data_seg;
286 k_data_seg_h = (short *) k_data_seg;
287 k_data_top += delta;
288
289 /* Zero new memory */
290 for (p = k_data_seg_b + old_size / BYTES_PER_WORD;
291 p < k_data_seg_b + new_size / BYTES_PER_WORD; )
292 *p ++ = 0;
293 }
294
295
296
297 /* Access memory */
298
299 void*
mem_reference(mem_addr addr)300 mem_reference(mem_addr addr)
301 {
302 if ((addr >= TEXT_BOT) && (addr < text_top))
303 return addr - TEXT_BOT + (char*) text_seg;
304 else if ((addr >= DATA_BOT) && (addr < data_top))
305 return addr - DATA_BOT + (char*) data_seg;
306 else if ((addr >= stack_bot) && (addr < STACK_TOP))
307 return addr - stack_bot + (char*) stack_seg;
308 else if ((addr >= K_TEXT_BOT) && (addr < k_text_top))
309 return addr - K_TEXT_BOT + (char*) k_text_seg;
310 else if ((addr >= K_DATA_BOT) && (addr < k_data_top))
311 return addr - K_DATA_BOT + (char*) k_data_seg;
312 else
313 {
314 run_error ("Memory address out of bounds\n");
315 return NULL;
316 }
317 }
318
319
320 instruction*
read_mem_inst(mem_addr addr)321 read_mem_inst(mem_addr addr)
322 {
323 if ((addr >= TEXT_BOT) && (addr < text_top) && !(addr & 0x3))
324 return text_seg [(addr - TEXT_BOT) >> 2];
325 else if ((addr >= K_TEXT_BOT) && (addr < k_text_top) && !(addr & 0x3))
326 return k_text_seg [(addr - K_TEXT_BOT) >> 2];
327 else
328 return bad_text_read (addr);
329 }
330
331
332 reg_word
read_mem_byte(mem_addr addr)333 read_mem_byte(mem_addr addr)
334 {
335 if ((addr >= DATA_BOT) && (addr < data_top))
336 return data_seg_b [addr - DATA_BOT];
337 else if ((addr >= stack_bot) && (addr < STACK_TOP))
338 return stack_seg_b [addr - stack_bot];
339 else if ((addr >= K_DATA_BOT) && (addr < k_data_top))
340 return k_data_seg_b [addr - K_DATA_BOT];
341 else
342 return bad_mem_read (addr, 0);
343 }
344
345
346 reg_word
read_mem_half(mem_addr addr)347 read_mem_half(mem_addr addr)
348 {
349 if ((addr >= DATA_BOT) && (addr < data_top) && !(addr & 0x1))
350 return data_seg_h [(addr - DATA_BOT) >> 1];
351 else if ((addr >= stack_bot) && (addr < STACK_TOP) && !(addr & 0x1))
352 return stack_seg_h [(addr - stack_bot) >> 1];
353 else if ((addr >= K_DATA_BOT) && (addr < k_data_top) && !(addr & 0x1))
354 return k_data_seg_h [(addr - K_DATA_BOT) >> 1];
355 else
356 return bad_mem_read (addr, 0x1);
357 }
358
359
360 reg_word
read_mem_word(mem_addr addr)361 read_mem_word(mem_addr addr)
362 {
363 if ((addr >= DATA_BOT) && (addr < data_top) && !(addr & 0x3))
364 return data_seg [(addr - DATA_BOT) >> 2];
365 else if ((addr >= stack_bot) && (addr < STACK_TOP) && !(addr & 0x3))
366 return stack_seg [(addr - stack_bot) >> 2];
367 else if ((addr >= K_DATA_BOT) && (addr < k_data_top) && !(addr & 0x3))
368 return k_data_seg [(addr - K_DATA_BOT) >> 2];
369 else
370 return bad_mem_read (addr, 0x3);
371 }
372
373
374 void
set_mem_inst(mem_addr addr,instruction * inst)375 set_mem_inst(mem_addr addr, instruction* inst)
376 {
377 text_modified = 1;
378 if ((addr >= TEXT_BOT) && (addr < text_top) && !(addr & 0x3))
379 text_seg [(addr - TEXT_BOT) >> 2] = inst;
380 else if ((addr >= K_TEXT_BOT) && (addr < k_text_top) && !(addr & 0x3))
381 k_text_seg [(addr - K_TEXT_BOT) >> 2] = inst;
382 else
383 bad_text_write (addr, inst);
384 }
385
386
387 void
set_mem_byte(mem_addr addr,reg_word value)388 set_mem_byte(mem_addr addr, reg_word value)
389 {
390 data_modified = 1;
391 if ((addr >= DATA_BOT) && (addr < data_top))
392 data_seg_b [addr - DATA_BOT] = (BYTE_TYPE) value;
393 else if ((addr >= stack_bot) && (addr < STACK_TOP))
394 stack_seg_b [addr - stack_bot] = (BYTE_TYPE) value;
395 else if ((addr >= K_DATA_BOT) && (addr < k_data_top))
396 k_data_seg_b [addr - K_DATA_BOT] = (BYTE_TYPE) value;
397 else
398 bad_mem_write (addr, value, 0);
399 }
400
401
402 void
set_mem_half(mem_addr addr,reg_word value)403 set_mem_half(mem_addr addr, reg_word value)
404 {
405 data_modified = 1;
406 if ((addr >= DATA_BOT) && (addr < data_top) && !(addr & 0x1))
407 data_seg_h [(addr - DATA_BOT) >> 1] = (short) value;
408 else if ((addr >= stack_bot) && (addr < STACK_TOP) && !(addr & 0x1))
409 stack_seg_h [(addr - stack_bot) >> 1] = (short) value;
410 else if ((addr >= K_DATA_BOT) && (addr < k_data_top) && !(addr & 0x1))
411 k_data_seg_h [(addr - K_DATA_BOT) >> 1] = (short) value;
412 else
413 bad_mem_write (addr, value, 0x1);
414 }
415
416
417 void
set_mem_word(mem_addr addr,reg_word value)418 set_mem_word(mem_addr addr, reg_word value)
419 {
420 data_modified = 1;
421 if ((addr >= DATA_BOT) && (addr < data_top) && !(addr & 0x3))
422 data_seg [(addr - DATA_BOT) >> 2] = (mem_word) value;
423 else if ((addr >= stack_bot) && (addr < STACK_TOP) && !(addr & 0x3))
424 stack_seg [(addr - stack_bot) >> 2] = (mem_word) value;
425 else if ((addr >= K_DATA_BOT) && (addr < k_data_top) && !(addr & 0x3))
426 k_data_seg [(addr - K_DATA_BOT) >> 2] = (mem_word) value;
427 else
428 bad_mem_write (addr, value, 0x3);
429 }
430
431
432 /* Handle the infrequent and erroneous cases in memory accesses. */
433
434 static instruction *
bad_text_read(mem_addr addr)435 bad_text_read (mem_addr addr)
436 {
437 RAISE_EXCEPTION (ExcCode_IBE, CP0_BadVAddr = addr);
438 return (inst_decode (0));
439 }
440
441
442 static void
bad_text_write(mem_addr addr,instruction * inst)443 bad_text_write (mem_addr addr, instruction *inst)
444 {
445 RAISE_EXCEPTION (ExcCode_IBE, CP0_BadVAddr = addr);
446 set_mem_word (addr, ENCODING (inst));
447 }
448
449
450 static mem_word
bad_mem_read(mem_addr addr,int mask)451 bad_mem_read (mem_addr addr, int mask)
452 {
453 mem_word tmp;
454
455 if ((addr & mask) != 0)
456 RAISE_EXCEPTION (ExcCode_AdEL, CP0_BadVAddr = addr)
457 else if (addr >= TEXT_BOT && addr < text_top)
458 switch (mask)
459 {
460 case 0x0:
461 tmp = ENCODING (text_seg [(addr - TEXT_BOT) >> 2]);
462 #ifdef BIGENDIAN
463 tmp = (unsigned)tmp >> (8 * (3 - (addr & 0x3)));
464 #else
465 tmp = (unsigned)tmp >> (8 * (addr & 0x3));
466 #endif
467 return (0xff & tmp);
468
469 case 0x1:
470 tmp = ENCODING (text_seg [(addr - TEXT_BOT) >> 2]);
471 #ifdef BIGENDIAN
472 tmp = (unsigned)tmp >> (8 * (2 - (addr & 0x2)));
473 #else
474 tmp = (unsigned)tmp >> (8 * (addr & 0x2));
475 #endif
476 return (0xffff & tmp);
477
478 case 0x3:
479 {
480 instruction *inst = text_seg [(addr - TEXT_BOT) >> 2];
481 if (inst == NULL)
482 return 0;
483 else
484 return (ENCODING (inst));
485 }
486
487 default:
488 run_error ("Bad mask (0x%x) in bad_mem_read\n", mask);
489 }
490 else if (addr > data_top
491 && addr < stack_bot
492 /* If more than 16 MB below stack, probably is bad data ref */
493 && addr > stack_bot - 16*K*K)
494 {
495 /* Grow stack segment */
496 expand_stack (stack_bot - addr + 4);
497 return (0);
498 }
499 else if (MM_IO_BOT <= addr && addr <= MM_IO_TOP)
500 return (read_memory_mapped_IO (addr));
501 else
502 /* Address out of range */
503 RAISE_EXCEPTION (ExcCode_DBE, CP0_BadVAddr = addr)
504 return (0);
505 }
506
507
508 static void
bad_mem_write(mem_addr addr,mem_word value,int mask)509 bad_mem_write (mem_addr addr, mem_word value, int mask)
510 {
511 mem_word tmp;
512
513 if ((addr & mask) != 0)
514 /* Unaligned address fault */
515 RAISE_EXCEPTION (ExcCode_AdES, CP0_BadVAddr = addr)
516 else if (addr >= TEXT_BOT && addr < text_top)
517 {
518 switch (mask)
519 {
520 case 0x0:
521 tmp = ENCODING (text_seg [(addr - TEXT_BOT) >> 2]);
522 #ifdef BIGENDIAN
523 tmp = ((tmp & ~(0xff << (8 * (3 - (addr & 0x3)))))
524 | (value & 0xff) << (8 * (3 - (addr & 0x3))));
525 #else
526 tmp = ((tmp & ~(0xff << (8 * (addr & 0x3))))
527 | (value & 0xff) << (8 * (addr & 0x3)));
528 #endif
529 break;
530
531 case 0x1:
532 tmp = ENCODING (text_seg [(addr - TEXT_BOT) >> 2]);
533 #ifdef BIGENDIAN
534 tmp = ((tmp & ~(0xffff << (8 * (2 - (addr & 0x2)))))
535 | (value & 0xffff) << (8 * (2 - (addr & 0x2))));
536 #else
537 tmp = ((tmp & ~(0xffff << (8 * (addr & 0x2))))
538 | (value & 0xffff) << (8 * (addr & 0x2)));
539 #endif
540 break;
541
542 case 0x3:
543 tmp = value;
544 break;
545
546 default:
547 run_error ("Bad mask (0x%x) in bad_mem_read\n", mask);
548 }
549
550 if (text_seg [(addr - TEXT_BOT) >> 2] != NULL)
551 {
552 free_inst (text_seg[(addr - TEXT_BOT) >> 2]);
553 }
554 text_seg [(addr - TEXT_BOT) >> 2] = inst_decode (tmp);
555
556 text_modified = 1;
557 }
558 else if (addr > data_top
559 && addr < stack_bot
560 /* If more than 16 MB below stack, probably is bad data ref */
561 && addr > stack_bot - 16*K*K)
562 {
563 /* Grow stack segment */
564 expand_stack (stack_bot - addr + 4);
565 if (addr >= stack_bot)
566 {
567 if (mask == 0)
568 stack_seg_b [addr - stack_bot] = (char)value;
569 else if (mask == 1)
570 stack_seg_h [(addr - stack_bot) >> 1] = (short)value;
571 else
572 stack_seg [(addr - stack_bot) >> 2] = value;
573 }
574 else
575 RAISE_EXCEPTION (ExcCode_DBE, CP0_BadVAddr = addr)
576
577 data_modified = 1;
578 }
579 else if (MM_IO_BOT <= addr && addr <= MM_IO_TOP)
580 write_memory_mapped_IO (addr, value);
581 else
582 /* Address out of range */
583 RAISE_EXCEPTION (ExcCode_DBE, CP0_BadVAddr = addr)
584 }
585
586
587
588 /* Memory-mapped IO routines. */
589
590 static int recv_control = 0; /* No input */
591 static int recv_buffer;
592 static int recv_buffer_full_timer = 0;
593
594 static int trans_control = TRANS_READY; /* Ready to write */
595 static int trans_buffer;
596 static int trans_buffer_full_timer = 0;
597
598
599 /* Check if input is available and output is possible. If so, update the
600 memory-mapped control registers and buffers. */
601
602 void
check_memory_mapped_IO()603 check_memory_mapped_IO ()
604 {
605 if (recv_buffer_full_timer > 0)
606 {
607 /* Do not check for more input until this interval expires. */
608 recv_buffer_full_timer -= 1;
609 }
610 else if (console_input_available ())
611 {
612 /* Read new char into the buffer and raise an interrupt, if interrupts
613 are enabled for device. */
614 /* assert(recv_buffer_full_timer == 0); */
615 recv_buffer = get_console_char ();
616 recv_control |= RECV_READY;
617 recv_buffer_full_timer = RECV_INTERVAL;
618 if (recv_control & RECV_INT_ENABLE)
619 {
620 RAISE_INTERRUPT (RECV_INT_LEVEL);
621 }
622 }
623
624 if (trans_buffer_full_timer > 0)
625 {
626 /* Do not allow output until this interval expires. */
627 trans_buffer_full_timer -= 1;
628 }
629 else if (!(trans_control & TRANS_READY))
630 {
631 /* Done writing: empty the buffer and raise an interrupt, if interrupts
632 are enabled for device. */
633 /* assert(trans_buffer_full_timer == 0); */
634 trans_control |= TRANS_READY;
635 if (trans_control & TRANS_INT_ENABLE)
636 {
637 RAISE_INTERRUPT (TRANS_INT_LEVEL);
638 }
639 }
640 }
641
642
643 /* Invoked on a write to the memory-mapped IO area. */
644
645 static void
write_memory_mapped_IO(mem_addr addr,mem_word value)646 write_memory_mapped_IO (mem_addr addr, mem_word value)
647 {
648 switch (addr)
649 {
650 case TRANS_CTRL_ADDR:
651 /* Program can only set the interrupt enable, not ready, bit. */
652 if ((value & TRANS_INT_ENABLE) != 0)
653 {
654 /* Enable interrupts: */
655 trans_control |= TRANS_INT_ENABLE;
656 if (trans_control & TRANS_READY)
657 {
658 /* Raise interrupt on enabling a ready transmitter */
659 RAISE_INTERRUPT (TRANS_INT_LEVEL);
660 }
661 }
662 else
663 {
664 /* Disable interrupts: */
665 trans_control &= ~TRANS_INT_ENABLE;
666 CLEAR_INTERRUPT (TRANS_INT_LEVEL); /* Clear IP bit in Cause */
667 }
668 break;
669
670 case TRANS_BUFFER_ADDR:
671 /* Ignore write if device is not ready. */
672 if ((trans_control & TRANS_READY) != 0)
673 {
674 /* Write char: */
675 trans_buffer = value & 0xff;
676 put_console_char ((char)trans_buffer);
677 /* Device is busy for a while: */
678 trans_control &= ~TRANS_READY;
679 trans_buffer_full_timer = TRANS_LATENCY;
680 CLEAR_INTERRUPT (TRANS_INT_LEVEL); /* Clear IP bit in Cause */
681 }
682 break;
683
684 case RECV_CTRL_ADDR:
685 /* Program can only set the interrupt enable, not ready, bit. */
686 if ((value & RECV_INT_ENABLE) != 0)
687 {
688 /* Enable interrupts: */
689 recv_control |= RECV_INT_ENABLE;
690 if (recv_control & RECV_READY)
691 {
692 /* Raise interrupt on enabling a ready receiver */
693 RAISE_INTERRUPT (RECV_INT_LEVEL);
694 }
695 }
696 else
697 {
698 /* Disable interrupts: */
699 recv_control &= ~RECV_INT_ENABLE;
700 CLEAR_INTERRUPT (RECV_INT_LEVEL); /* Clear IP bit in Cause */
701 }
702 break;
703
704 case RECV_BUFFER_ADDR:
705 /* Nop: program can't change buffer. */
706 break;
707
708 default:
709 run_error ("Write to unused memory-mapped IO address (0x%x)\n", addr);
710 }
711 }
712
713
714 /* Invoked on a read in the memory-mapped IO area. */
715
716 static mem_word
read_memory_mapped_IO(mem_addr addr)717 read_memory_mapped_IO (mem_addr addr)
718 {
719 switch (addr)
720 {
721 case TRANS_CTRL_ADDR:
722 return (trans_control);
723
724 case TRANS_BUFFER_ADDR:
725 return (trans_buffer & 0xff);
726
727 case RECV_CTRL_ADDR:
728 return (recv_control);
729
730 case RECV_BUFFER_ADDR:
731 recv_control &= ~RECV_READY; /* Buffer now empty */
732 recv_buffer_full_timer = 0;
733 CLEAR_INTERRUPT (RECV_INT_LEVEL); /* Clear IP bit in Cause */
734 return (recv_buffer & 0xff);
735
736 default:
737 run_error ("Read from unused memory-mapped IO address (0x%x)\n", addr);
738 return (0);
739 }
740 }
741
742
743
744 /* Misc. routines */
745
746 void
print_mem(mem_addr addr)747 print_mem (mem_addr addr)
748 {
749 mem_word value;
750
751 if ((addr & 0x3) != 0)
752 addr &= ~0x3; /* Address must be word-aligned */
753
754 if (TEXT_BOT <= addr && addr < text_top)
755 print_inst (addr);
756 else if (DATA_BOT <= addr && addr < data_top)
757 {
758 value = read_mem_word (addr);
759 write_output (message_out, "Data seg @ 0x%08x (%d) = 0x%08x (%d)\n",
760 addr, addr, value, value);
761 }
762 else if (stack_bot <= addr && addr < STACK_TOP)
763 {
764 value = read_mem_word (addr);
765 write_output (message_out, "Stack seg @ 0x%08x (%d) = 0x%08x (%d)\n",
766 addr, addr, value, value);
767 }
768 else if (K_TEXT_BOT <= addr && addr < k_text_top)
769 print_inst (addr);
770 else if (K_DATA_BOT <= addr && addr < k_data_top)
771 {
772 value = read_mem_word (addr);
773 write_output (message_out,
774 "Kernel Data seg @ 0x%08x (%d) = 0x%08x (%d)\n",
775 addr, addr, value, value);
776 }
777 else
778 error ("Address 0x%08x (%d) to print_mem is out of bounds\n", addr, addr);
779 }
780