1 /*
2  *  This file is part of x48, an emulator of the HP-48sx Calculator.
3  *  Copyright (C) 1994  Eddie C. Dost  (ecd@dressler.de)
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 /* $Log: actions.c,v $
21  * Revision 1.15  1995/01/11  18:20:01  ecd
22  * major update to support HP48 G/GX
23  *
24  * Revision 1.14  1994/12/07  20:20:50  ecd
25  * changed shutdown again: wake on TIMER1CTRL & XTRA
26  *
27  * Revision 1.14  1994/12/07  20:20:50  ecd
28  * changed shutdown again: wake on TIMER1CTRL & XTRA
29  *
30  * Revision 1.13  1994/11/28  02:00:51  ecd
31  * changed do_configure for internal debugging
32  *
33  * Revision 1.12  1994/11/02  14:40:38  ecd
34  * removed call to debug in do_shutdown()
35  *
36  * Revision 1.11  1994/10/09  20:29:47  ecd
37  * no real change, was just fiddling around with the display.
38  *
39  * Revision 1.10  1994/10/06  16:30:05  ecd
40  * added refresh_display()
41  *
42  * Revision 1.9  1994/10/05  08:36:44  ecd
43  * changed shutdown
44  *
45  * Revision 1.8  1994/10/01  10:12:53  ecd
46  * fixed bug in shutdown
47  *
48  * Revision 1.7  1994/09/30  12:37:09  ecd
49  * changed shutdown instruction
50  *
51  * Revision 1.6  1994/09/18  22:47:20  ecd
52  * fixed bug with overflow in timerdiff
53  *
54  * Revision 1.5  1994/09/18  15:29:22  ecd
55  * added SHUTDN implementation,
56  * started Real Time support.
57  *
58  * Revision 1.4  1994/09/13  16:57:00  ecd
59  * changed to plain X11
60  *
61  * Revision 1.3  1994/08/31  18:23:21  ecd
62  * changed memory read routines.
63  *
64  * Revision 1.2  1994/08/27  11:28:59  ecd
65  * changed keyboard interrupt handling.
66  *
67  * Revision 1.1  1994/08/26  11:09:02  ecd
68  * Initial revision
69  *
70  *
71  * $Id: actions.c,v 1.15 1995/01/11 18:20:01 ecd Exp ecd $
72  */
73 
74 /* #define DEBUG_INTERRUPT 1 */
75 /* #define DEBUG_KBD_INT 1 */
76 /* #define DEBUG_SHUTDOWN 1 */
77 /* #define DEBUG_CONFIG 1 */
78 /* #define DEBUG_ID 1 */
79 
80 #include "global.h"
81 
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include <unistd.h>
85 
86 #include "hp48.h"
87 #include "hp48_emu.h"
88 #include "device.h"
89 #include "x48_x11.h"
90 #include "timer.h"
91 #include "debugger.h"
92 #include "romio.h"
93 
94 static int	interrupt_called = 0;
95 extern long	nibble_masks[16];
96 
97 int		got_alarm;
98 
99 int		conf_bank1 = 0x00000;
100 int		conf_bank2 = 0x00000;
101 
102 void
103 #ifdef __FunctionProto__
do_in(void)104 do_in(void)
105 #else
106 do_in()
107 #endif
108 {
109   int i, in, out;
110 
111   out = 0;
112   for (i = 2; i >= 0; i--) {
113     out <<= 4;
114     out |= saturn.OUT[i];
115   }
116   in = 0;
117   for (i = 0; i < 9; i++)
118     if (out & (1 << i))
119       in |= saturn.keybuf.rows[i];
120 #ifdef DEBUG_INOUT
121   fprintf(stderr, "saturn.OUT=%.3x, saturn.IN=%.4x\n", out, in);
122 #endif
123 
124   for (i = 0; i < 4; i++) {
125     saturn.IN[i] = in & 0xf;
126     in >>= 4;
127   }
128 }
129 
130 void
131 #ifdef __FunctionProto__
clear_program_stat(int n)132 clear_program_stat(int n)
133 #else
134 clear_program_stat(n)
135 int n;
136 #endif
137 {
138   saturn.PSTAT[n] = 0;
139 }
140 
141 void
142 #ifdef __FunctionProto__
set_program_stat(int n)143 set_program_stat(int n)
144 #else
145 set_program_stat(n)
146 int n;
147 #endif
148 {
149   saturn.PSTAT[n] = 1;
150 }
151 
152 int
153 #ifdef __FunctionProto__
get_program_stat(int n)154 get_program_stat(int n)
155 #else
156 get_program_stat(n)
157 int n;
158 #endif
159 {
160   return saturn.PSTAT[n];
161 }
162 
163 void
164 #ifdef __FunctionProto__
register_to_status(unsigned char * r)165 register_to_status(unsigned char *r)
166 #else
167 register_to_status(r)
168 unsigned char *r;
169 #endif
170 {
171   int i;
172 
173   for (i = 0; i < 12; i++) {
174     saturn.PSTAT[i] = (r[i / 4] >> (i % 4)) & 1;
175   }
176 }
177 
178 void
179 #ifdef __FunctionProto__
status_to_register(unsigned char * r)180 status_to_register(unsigned char *r)
181 #else
182 status_to_register(r)
183 unsigned char *r;
184 #endif
185 {
186   int i;
187 
188   for (i = 0; i < 12; i++) {
189     if (saturn.PSTAT[i]) {
190       r[i / 4] |= 1 << (i % 4);
191     } else {
192       r[i / 4] &= ~(1 << (i % 4)) & 0xf;
193     }
194   }
195 }
196 
197 void
198 #ifdef __FunctionProto__
swap_register_status(unsigned char * r)199 swap_register_status(unsigned char *r)
200 #else
201 swap_register_status(r)
202 unsigned char *r;
203 #endif
204 {
205   int i, tmp;
206 
207   for (i = 0; i < 12; i++) {
208     tmp = saturn.PSTAT[i];
209     saturn.PSTAT[i] = (r[i / 4] >> (i % 4)) & 1;
210     if (tmp) {
211       r[i / 4] |= 1 << (i % 4);
212     } else {
213       r[i / 4] &= ~(1 << (i % 4)) & 0xf;
214     }
215   }
216 }
217 
218 void
219 #ifdef __FunctionProto__
clear_status(void)220 clear_status(void)
221 #else
222 clear_status()
223 #endif
224 {
225   int i;
226 
227   for (i = 0; i < 12; i++) {
228     saturn.PSTAT[i] = 0;
229   }
230 }
231 
232 void
233 #ifdef __FunctionProto__
set_register_nibble(unsigned char * reg,int n,unsigned char val)234 set_register_nibble(unsigned char *reg, int n, unsigned char val)
235 #else
236 set_register_nibble(reg, n, val)
237 unsigned char *reg;
238 int n;
239 unsigned char val;
240 #endif
241 {
242   reg[n] = val;
243 }
244 
245 unsigned char
246 #ifdef __FunctionProto__
get_register_nibble(unsigned char * reg,int n)247 get_register_nibble(unsigned char *reg, int n)
248 #else
249 get_register_nibble(reg, n)
250 unsigned char *reg;
251 int n;
252 #endif
253 {
254   return reg[n];
255 }
256 
257 void
258 #ifdef __FunctionProto__
set_register_bit(unsigned char * reg,int n)259 set_register_bit(unsigned char *reg, int n)
260 #else
261 set_register_bit(reg, n)
262 unsigned char *reg;
263 int n;
264 #endif
265 {
266   reg[n/4] |= (1 << (n%4));
267 }
268 
269 void
270 #ifdef __FunctionProto__
clear_register_bit(unsigned char * reg,int n)271 clear_register_bit(unsigned char *reg, int n)
272 #else
273 clear_register_bit(reg, n)
274 unsigned char *reg;
275 int n;
276 #endif
277 {
278   reg[n/4] &= ~(1 << (n%4));
279 }
280 
281 int
282 #ifdef __FunctionProto__
get_register_bit(unsigned char * reg,int n)283 get_register_bit(unsigned char *reg, int n)
284 #else
285 get_register_bit(reg, n)
286 unsigned char *reg;
287 int n;
288 #endif
289 {
290   return ((int)(reg[n/4] & (1 << (n%4))) > 0)?1:0;
291 }
292 
293 short conf_tab_sx[] = { 1, 2, 2, 2, 2, 0 };
294 short conf_tab_gx[] = { 1, 2, 2, 2, 2, 0 };
295 
296 void
297 #ifdef __FunctionProto__
do_reset(void)298 do_reset(void)
299 #else
300 do_reset()
301 #endif
302 {
303   int i;
304 
305   for (i = 0; i < 6; i++)
306     {
307       if (opt_gx)
308         saturn.mem_cntl[i].unconfigured = conf_tab_gx[i];
309       else
310         saturn.mem_cntl[i].unconfigured = conf_tab_sx[i];
311       saturn.mem_cntl[i].config[0] = 0x0;
312       saturn.mem_cntl[i].config[1] = 0x0;
313     }
314 
315 #ifdef DEBUG_CONFIG
316   fprintf(stderr, "%.5lx: RESET\n", saturn.PC);
317   for (i = 0; i < 6; i++)
318     {
319       if (saturn.mem_cntl[i].unconfigured)
320         fprintf(stderr, "MEMORY CONTROLLER %d is unconfigured\n", i);
321       else
322         fprintf(stderr, "MEMORY CONTROLLER %d is configured to %.5lx, %.5lx\n",
323                 i, saturn.mem_cntl[i].config[0], saturn.mem_cntl[i].config[1]);
324     }
325 #endif
326 }
327 
328 void
329 #ifdef __FunctionProto__
do_inton(void)330 do_inton(void)
331 #else
332 do_inton()
333 #endif
334 {
335   saturn.kbd_ien = 1;
336 }
337 
338 void
339 #ifdef __FunctionProto__
do_intoff(void)340 do_intoff(void)
341 #else
342 do_intoff()
343 #endif
344 {
345   saturn.kbd_ien = 0;
346 }
347 
348 void
349 #ifdef __FunctionProto__
do_return_interupt(void)350 do_return_interupt(void)
351 #else
352 do_return_interupt()
353 #endif
354 {
355   if (saturn.int_pending) {
356 #ifdef DEBUG_INTERRUPT
357     fprintf(stderr, "PC = %.5lx: RTI SERVICE PENDING INTERRUPT\n",
358             saturn.PC);
359 #endif
360     saturn.int_pending = 0;
361     saturn.intenable = 0;
362     saturn.PC = 0xf;
363   } else {
364 #ifdef DEBUG_INTERRUPT
365     fprintf(stderr, "PC = %.5lx: RETURN INTERRUPT to ", saturn.PC);
366 #endif
367     saturn.PC = pop_return_addr();
368 #ifdef DEBUG_INTERRUPT
369     fprintf(stderr, "%.5lx\n", saturn.PC);
370 #endif
371     saturn.intenable = 1;
372 
373     if (adj_time_pending) {
374       schedule_event = 0;
375       sched_adjtime = 0;
376     }
377 
378   }
379 }
380 
381 void
382 #ifdef __FunctionProto__
do_interupt(void)383 do_interupt(void)
384 #else
385 do_interupt()
386 #endif
387 {
388   interrupt_called = 1;
389   if (saturn.intenable) {
390 #ifdef DEBUG_INTERRUPT
391     fprintf(stderr, "PC = %.5lx: INTERRUPT\n", saturn.PC);
392 #endif
393     push_return_addr(saturn.PC);
394     saturn.PC = 0xf;
395     saturn.intenable = 0;
396   }
397 }
398 
399 void
400 #ifdef __FunctionProto__
do_kbd_int(void)401 do_kbd_int(void)
402 #else
403 do_kbd_int()
404 #endif
405 {
406   interrupt_called = 1;
407   if (saturn.intenable) {
408 #ifdef DEBUG_KBD_INT
409     fprintf(stderr, "PC = %.5lx: KBD INT\n", saturn.PC);
410 #endif
411     push_return_addr(saturn.PC);
412     saturn.PC = 0xf;
413     saturn.intenable = 0;
414   } else {
415 #ifdef DEBUG_KBD_INT
416     fprintf(stderr, "PC = %.5lx: KBD INT PENDING\n", saturn.PC);
417 #endif
418     saturn.int_pending = 1;
419   }
420 }
421 
422 void
423 #ifdef __FunctionProto__
do_reset_interrupt_system(void)424 do_reset_interrupt_system(void)
425 #else
426 do_reset_interrupt_system()
427 #endif
428 {
429   int i, gen_intr;
430 
431   saturn.kbd_ien = 1;
432   gen_intr = 0;
433   for (i = 0; i < 9; i++) {
434     if (saturn.keybuf.rows[i] != 0) {
435       gen_intr = 1;
436       break;
437     }
438   }
439   if (gen_intr) {
440     do_kbd_int();
441   }
442 }
443 
444 void
445 #ifdef __FunctionProto__
do_unconfigure(void)446 do_unconfigure(void)
447 #else
448 do_unconfigure()
449 #endif
450 {
451   int i;
452   unsigned int conf;
453 
454   conf = 0;
455   for (i = 4; i >= 0; i--) {
456     conf <<= 4;
457     conf |= saturn.C[i];
458   }
459 
460   for (i = 0; i < 6; i++)
461     {
462       if (saturn.mem_cntl[i].config[0] == conf)
463         {
464           if (opt_gx)
465             saturn.mem_cntl[i].unconfigured = conf_tab_gx[i];
466           else
467             saturn.mem_cntl[i].unconfigured = conf_tab_sx[i];
468           saturn.mem_cntl[i].config[0] = 0x0;
469           saturn.mem_cntl[i].config[1] = 0x0;
470           break;
471         }
472     }
473 
474 #ifdef DEBUG_CONFIG
475   fprintf(stderr, "%.5lx: UNCNFG %.5x:\n", saturn.PC, conf);
476   for (i = 0; i < 6; i++)
477     {
478       if (saturn.mem_cntl[i].unconfigured)
479         fprintf(stderr, "MEMORY CONTROLLER %d is unconfigured\n", i);
480       else
481         fprintf(stderr, "MEMORY CONTROLLER %d is configured to %.5lx, %.5lx\n",
482                 i, saturn.mem_cntl[i].config[0], saturn.mem_cntl[i].config[1]);
483     }
484 #endif
485 }
486 
487 void
488 #ifdef __FunctionProto__
do_configure(void)489 do_configure(void)
490 #else
491 do_configure()
492 #endif
493 {
494   int i;
495   unsigned long conf;
496 
497   conf = 0;
498   for (i = 4; i >= 0; i--) {
499     conf <<= 4;
500     conf |= saturn.C[i];
501   }
502 
503   for (i = 0; i < 6; i++)
504     {
505       if (saturn.mem_cntl[i].unconfigured)
506         {
507           saturn.mem_cntl[i].unconfigured--;
508           saturn.mem_cntl[i].config[saturn.mem_cntl[i].unconfigured] = conf;
509           break;
510         }
511     }
512 
513 #ifdef DEBUG_CONFIG
514   fprintf(stderr, "%.5lx: CONFIG %.5lx:\n", saturn.PC, conf);
515   for (i = 0; i < 6; i++)
516     {
517       if (saturn.mem_cntl[i].unconfigured)
518         fprintf(stderr, "MEMORY CONTROLLER %d is unconfigured\n", i);
519       else
520         fprintf(stderr, "MEMORY CONTROLLER %d at %.5lx, %.5lx\n",
521                 i, saturn.mem_cntl[i].config[0], saturn.mem_cntl[i].config[1]);
522     }
523 #endif
524 }
525 
526 int
527 #ifdef __FunctionProto__
get_identification(void)528 get_identification(void)
529 #else
530 get_identification()
531 #endif
532 {
533   int i;
534   static int chip_id[]
535              = { 0, 0, 0, 0, 0x05, 0xf6, 0x07, 0xf8, 0x01, 0xf2, 0, 0 };
536   int id;
537 
538   for (i = 0; i < 6; i++)
539     {
540       if (saturn.mem_cntl[i].unconfigured)
541         break;
542     }
543   if (i < 6)
544     id = chip_id[2 * i + (2 - saturn.mem_cntl[i].unconfigured)];
545   else
546     id = 0;
547 
548 #ifdef DEBUG_ID
549   fprintf(stderr, "%.5lx: C=ID, returning: %x\n", saturn.PC, id);
550   for (i = 0; i < 6; i++)
551     {
552       if (saturn.mem_cntl[i].unconfigured == 2)
553         fprintf(stderr, "MEMORY CONTROLLER %d is unconfigured\n", i);
554       else if (saturn.mem_cntl[i].unconfigured == 1)
555         {
556           if (i == 0)
557             fprintf(stderr, "MEMORY CONTROLLER %d unconfigured\n", i);
558           else
559             fprintf(stderr, "MEMORY CONTROLLER %d configured to ????? %.5lx\n",
560                 i, saturn.mem_cntl[i].config[1]);
561         }
562       else
563         fprintf(stderr, "MEMORY CONTROLLER %d configured to %.5lx, %.5lx\n",
564                 i, saturn.mem_cntl[i].config[0], saturn.mem_cntl[i].config[1]);
565     }
566 #endif
567 
568   for (i = 0; i < 3; i++)
569     {
570       saturn.C[i] = id & 0x0f;
571       id >>= 4;
572     }
573   return 0;
574 }
575 
576 void
577 #ifdef __FunctionProto__
do_shutdown(void)578 do_shutdown(void)
579 #else
580 do_shutdown()
581 #endif
582 {
583   int wake, alarms;
584   t1_t2_ticks ticks;
585 
586   if (device.display_touched) {
587     device.display_touched = 0;
588     update_display();
589 #ifdef HAVE_XSHM
590     if (disp.display_update) refresh_display();
591 #endif
592   }
593 
594   stop_timer(RUN_TIMER);
595   start_timer(IDLE_TIMER);
596 
597   if (is_zero_register(saturn.OUT, OUT_FIELD)) {
598 #ifdef DEBUG_SHUTDOWN
599     fprintf(stderr, "%.5lx: SHUTDN: PC = 0\n", saturn.PC);
600 #endif
601     saturn.intenable = 1;
602     saturn.int_pending = 0;
603   }
604 
605 #ifdef DEBUG_SHUTDOWN
606   fprintf(stderr, "%.5lx:\tSHUTDN: Timer 1 Control = %x, Timer 1 = %d\n",
607           saturn.PC, saturn.t1_ctrl, saturn.timer1);
608   fprintf(stderr, "%.5lx:\tSHUTDN: Timer 2 Control = %x, Timer 2 = %ld\n",
609           saturn.PC, saturn.t2_ctrl, saturn.timer2);
610 #endif
611 
612   if (in_debugger)
613     wake = 1;
614   else
615     wake = 0;
616 
617   alarms = 0;
618 
619   do {
620 
621     pause();
622 
623     if (got_alarm) {
624       got_alarm = 0;
625 
626 #ifdef HAVE_XSHM
627       if (disp.display_update) refresh_display();
628 #endif
629 
630       ticks = get_t1_t2();
631       if (saturn.t2_ctrl & 0x01) {
632         saturn.timer2 = ticks.t2_ticks;
633       }
634       saturn.timer1 = set_t1 - ticks.t1_ticks;
635       set_t1 = ticks.t1_ticks;
636 
637       interrupt_called = 0;
638       if (GetEvent()) {
639         if (interrupt_called)
640           wake = 1;
641       }
642 
643       if (saturn.timer2 <= 0)
644         {
645           if (saturn.t2_ctrl & 0x04)
646             {
647               wake = 1;
648             }
649           if (saturn.t2_ctrl & 0x02)
650             {
651               wake = 1;
652               saturn.t2_ctrl |= 0x08;
653               do_interupt();
654             }
655         }
656 
657       if (saturn.timer1 <= 0)
658         {
659           saturn.timer1 &= 0x0f;
660           if (saturn.t1_ctrl & 0x04)
661             {
662               wake = 1;
663             }
664           if (saturn.t1_ctrl & 0x03)
665             {
666               wake = 1;
667               saturn.t1_ctrl |= 0x08;
668               do_interupt();
669             }
670         }
671 
672       if (wake == 0) {
673         interrupt_called = 0;
674         receive_char();
675         if (interrupt_called)
676           wake = 1;
677       }
678 
679       alarms++;
680     }
681 
682     if (enter_debugger)
683       {
684         wake = 1;
685       }
686   } while (wake == 0);
687 
688   stop_timer(IDLE_TIMER);
689   start_timer(RUN_TIMER);
690 }
691 
692 void
693 #ifdef __FunctionProto__
set_hardware_stat(int op)694 set_hardware_stat(int op)
695 #else
696 set_hardware_stat(op)
697 int op;
698 #endif
699 {
700   if (op & 1) saturn.XM = 1;
701   if (op & 2) saturn.SB = 1;
702   if (op & 4) saturn.SR = 1;
703   if (op & 8) saturn.MP = 1;
704 }
705 
706 void
707 #ifdef __FunctionProto__
clear_hardware_stat(int op)708 clear_hardware_stat(int op)
709 #else
710 clear_hardware_stat(op)
711 int op;
712 #endif
713 {
714   if (op & 1) saturn.XM = 0;
715   if (op & 2) saturn.SB = 0;
716   if (op & 4) saturn.SR = 0;
717   if (op & 8) saturn.MP = 0;
718 }
719 
720 int
721 #ifdef __FunctionProto__
is_zero_hardware_stat(int op)722 is_zero_hardware_stat(int op)
723 #else
724 is_zero_hardware_stat(op)
725 int op;
726 #endif
727 {
728   if (op & 1) if (saturn.XM != 0) return 0;
729   if (op & 2) if (saturn.SB != 0) return 0;
730   if (op & 4) if (saturn.SR != 0) return 0;
731   if (op & 8) if (saturn.MP != 0) return 0;
732   return 1;
733 }
734 
735 void
736 #ifdef __FunctionProto__
push_return_addr(long addr)737 push_return_addr(long addr)
738 #else
739 push_return_addr(addr)
740 long addr;
741 #endif
742 {
743   int i;
744 
745   if (++saturn.rstkp >= NR_RSTK) {
746 #if 0
747     fprintf(stderr, "%.5lx: RSTK overflow !!!\n", saturn.PC);
748     for (i = saturn.rstkp - 1; i >= 0; i--) {
749       fprintf(stderr, "\tRSTK[%d] %.5lx\n", i, saturn.rstk[i]);
750     }
751 #endif
752     for (i = 1; i < NR_RSTK; i++)
753       saturn.rstk[i-1] = saturn.rstk[i];
754     saturn.rstkp--;
755   }
756   saturn.rstk[saturn.rstkp] = addr;
757 #ifdef DEBUG_RSTK
758   fprintf(stderr, "PUSH %.5x:\n", addr);
759   for (i = saturn.rstkp; i >= 0; i--) {
760     fprintf(stderr, "RSTK[%d] %.5x\n", i, saturn.rstk[i]);
761   }
762 #endif
763 }
764 
765 long
766 #ifdef __FunctionProto__
pop_return_addr(void)767 pop_return_addr(void)
768 #else
769 pop_return_addr()
770 #endif
771 {
772 #ifdef DEBUG_RSTK
773   int i;
774 
775   for (i = saturn.rstkp; i >= 0; i--) {
776     fprintf(stderr, "RSTK[%d] %.5x\n", i, saturn.rstk[i]);
777   }
778   fprintf(stderr, "POP %.5x:\n",
779           (saturn.rstkp >= 0) ? saturn.rstk[saturn.rstkp]:0);
780 #endif
781   if (saturn.rstkp < 0)
782     return 0;
783   return saturn.rstk[saturn.rstkp--];
784 }
785 
786 char *
787 #ifdef __FunctionProto__
make_hexstr(long addr,int n)788 make_hexstr(long addr, int n)
789 #else
790 make_hexstr(addr, n)
791 long addr;
792 int n;
793 #endif
794 {
795   static char str[44];
796   int i, t, trunc;
797 
798   trunc = 0;
799   if (n > 40) {
800     n = 40;
801     trunc = 1;
802   }
803   for (i = 0; i < n; i++) {
804     t = read_nibble(addr+i);
805     if (t <= 9)
806       str[i] = '0' + t;
807     else
808       str[i] = 'a' + (t - 10);
809   }
810   str[n] = '\0';
811   if (trunc) {
812     str[n] = '.';
813     str[n+1] = '.';
814     str[n+2] = '.';
815     str[n+3] = '\0';
816   }
817   return str;
818 }
819 
820 void
821 #ifdef __FunctionProto__
load_constant(unsigned char * reg,int n,long addr)822 load_constant(unsigned char *reg, int n, long addr)
823 #else
824 load_constant(reg, n, addr)
825 unsigned char *reg;
826 int n;
827 long addr;
828 #endif
829 {
830   int i, p;
831 
832   p = saturn.P;
833   for (i = 0; i < n; i++) {
834     reg[p] = read_nibble(addr + i);
835     p = (p + 1) & 0xf;
836   }
837 }
838 
839 void
840 #ifdef __FunctionProto__
load_addr(word_20 * dat,long addr,int n)841 load_addr(word_20 *dat, long addr, int n)
842 #else
843 load_addr(dat, addr, n)
844 word_20 *dat;
845 long addr;
846 int n;
847 #endif
848 {
849   int i;
850 
851   for (i = 0; i < n; i++) {
852     *dat &= ~nibble_masks[i];
853     *dat |= read_nibble(addr + i) << (i * 4);
854   }
855 }
856 
857 void
858 #ifdef __FunctionProto__
load_address(unsigned char * reg,long addr,int n)859 load_address(unsigned char *reg, long addr, int n)
860 #else
861 load_address(reg, addr, n)
862 unsigned char *reg;
863 long addr;
864 int n;
865 #endif
866 {
867   int i;
868 
869   for (i = 0; i < n; i++) {
870     reg[i] = read_nibble(addr + i);
871   }
872 }
873 
874 void
875 #ifdef __FunctionProto__
register_to_address(unsigned char * reg,word_20 * dat,int s)876 register_to_address(unsigned char *reg, word_20 *dat, int s)
877 #else
878 register_to_address(reg, dat, s)
879 unsigned char *reg;
880 word_20 *dat;
881 int s;
882 #endif
883 {
884   int i, n;
885 
886   if (s)
887     n = 4;
888   else
889     n = 5;
890   for (i = 0; i < n; i++) {
891     *dat &= ~nibble_masks[i];
892     *dat |= (reg[i] & 0x0f) << (i * 4);
893   }
894 }
895 
896 void
897 #ifdef __FunctionProto__
address_to_register(word_20 dat,unsigned char * reg,int s)898 address_to_register(word_20 dat, unsigned char *reg, int s)
899 #else
900 address_to_register(dat, reg, s)
901 word_20 dat;
902 unsigned char *reg;
903 int s;
904 #endif
905 {
906   int i, n;
907 
908   if (s)
909     n = 4;
910   else
911     n = 5;
912   for (i = 0; i < n; i++) {
913     reg[i] = dat & 0x0f;
914     dat >>= 4;
915   }
916 }
917 
918 long
919 #ifdef __FunctionProto__
dat_to_addr(unsigned char * dat)920 dat_to_addr(unsigned char *dat)
921 #else
922 dat_to_addr(dat)
923 unsigned char *dat;
924 #endif
925 {
926   int i;
927   long addr;
928 
929   addr = 0;
930   for (i = 4; i >= 0; i--) {
931     addr <<= 4;
932     addr |= (dat[i] & 0xf);
933   }
934   return addr;
935 }
936 
937 void
938 #ifdef __FunctionProto__
addr_to_dat(long addr,unsigned char * dat)939 addr_to_dat(long addr, unsigned char *dat)
940 #else
941 addr_to_dat(addr, dat)
942 long addr;
943 unsigned char *dat;
944 #endif
945 {
946   int i;
947 
948   for (i = 0; i < 5; i++) {
949     dat[i] = (addr & 0xf);
950     addr >>= 4;
951   }
952 }
953 
954 void
955 #ifdef __FunctionProto__
add_address(word_20 * dat,int add)956 add_address(word_20 *dat, int add)
957 #else
958 add_address(dat, add)
959 word_20 *dat;
960 int add;
961 #endif
962 {
963   *dat += add;
964   if (*dat & (word_20)0xfff00000) {
965     saturn.CARRY = 1;
966   } else {
967     saturn.CARRY = 0;
968   }
969   *dat &= 0xfffff;
970 }
971 
972 static int start_fields[] = {
973   -1,  0,  2,  0, 15,  3,  0,  0,
974   -1,  0,  2,  0, 15,  3,  0,  0,
975    0,  0,  0
976 };
977 
978 static int end_fields[] = {
979   -1, -1,  2,  2, 15, 14,  1, 15,
980   -1, -1,  2,  2, 15, 14,  1,  4,
981    3,  2,  0
982 };
983 
984 static inline int
985 #ifdef __FunctionProto__
get_start(int code)986 get_start(int code)
987 #else
988 get_start(code)
989 int code;
990 #endif
991 {
992   int s;
993 
994   if ((s = start_fields[code]) == -1) {
995     s = saturn.P;
996   }
997   return s;
998 }
999 
1000 static inline int
1001 #ifdef __FuntionProto__
get_end(int code)1002 get_end(int code)
1003 #else
1004 get_end(code)
1005 int code;
1006 #endif
1007 {
1008   int e;
1009 
1010   if ((e = end_fields[code]) == -1) {
1011     e = saturn.P;
1012   }
1013   return e;
1014 }
1015 
1016 void
1017 #ifdef __FunctionProto__
store(word_20 dat,unsigned char * reg,int code)1018 store(word_20 dat, unsigned char *reg, int code)
1019 #else
1020 store(dat, reg, code)
1021 word_20 dat;
1022 unsigned char *reg;
1023 int code;
1024 #endif
1025 {
1026   int i, s, e;
1027 
1028   s = get_start(code);
1029   e = get_end(code);
1030   for (i = s; i <= e; i++) {
1031     write_nibble(dat++, reg[i]);
1032   }
1033 }
1034 
1035 void
1036 #ifdef __FunctionProto__
store_n(word_20 dat,unsigned char * reg,int n)1037 store_n(word_20 dat, unsigned char *reg, int n)
1038 #else
1039 store_n(dat, reg, n)
1040 word_20 dat;
1041 unsigned char *reg;
1042 int n;
1043 #endif
1044 {
1045   int i;
1046 
1047   for (i = 0; i < n; i++) {
1048     write_nibble(dat++, reg[i]);
1049   }
1050 }
1051 
1052 void
1053 #ifdef __FunctionProto__
recall(unsigned char * reg,word_20 dat,int code)1054 recall(unsigned char *reg, word_20 dat, int code)
1055 #else
1056 recall(reg, dat, code)
1057 unsigned char *reg;
1058 word_20 dat;
1059 int code;
1060 #endif
1061 {
1062   int i, s, e;
1063 
1064   s = get_start(code);
1065   e = get_end(code);
1066   for (i = s; i <= e; i++) {
1067     reg[i] = read_nibble_crc(dat++);
1068   }
1069 }
1070 
1071 void
1072 #ifdef __FunctionProto__
recall_n(unsigned char * reg,word_20 dat,int n)1073 recall_n(unsigned char *reg, word_20 dat, int n)
1074 #else
1075 recall_n(reg, dat, n)
1076 unsigned char *reg;
1077 word_20 dat;
1078 int n;
1079 #endif
1080 {
1081   int i;
1082 
1083   for (i = 0; i < n; i++) {
1084     reg[i] = read_nibble_crc(dat++);
1085   }
1086 }
1087 
1088