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