1  /*
2   * UAE - The Un*x Amiga Emulator
3   *
4   * A "replacement" for a missing Kickstart
5   * Warning! Q&D
6   *
7   * (c) 1995 Bernd Schmidt
8   */
9 
10 #include "sysconfig.h"
11 #include "sysdeps.h"
12 
13 #include "options.h"
14 #include "uae.h"
15 #include "memory.h"
16 #include "custom.h"
17 #include "newcpu.h"
18 #include "cia.h"
19 #include "disk.h"
20 #include "ersatz.h"
21 
22 #define EOP_INIT     0
23 #define EOP_NIMP     1
24 #define EOP_SERVEINT 2
25 #define EOP_DOIO     3
26 #define EOP_OPENLIB  4
27 #define EOP_AVAILMEM 5
28 #define EOP_ALLOCMEM 6
29 #define EOP_ALLOCABS 7
30 #define EOP_LOOP 8
31 
32 static int already_failed = 0;
33 
init_ersatz_rom(uae_u8 * data)34 void init_ersatz_rom (uae_u8 *data)
35 {
36     write_log ("Trying to use Kickstart replacement.\n");
37     *data++ = 0x00; *data++ = 0x08; /* initial SP */
38     *data++ = 0x00; *data++ = 0x00;
39     *data++ = 0x00; *data++ = 0xF8; /* initial PC */
40     *data++ = 0x00; *data++ = 0x08;
41 
42     *data++ = 0xFF; *data++ = 0x0D;
43     *data++ = 0x00; *data++ = EOP_INIT;
44     *data++ = 0xFF; *data++ = 0x0D;
45     *data++ = 0x00; *data++ = EOP_NIMP;
46 
47     *data++ = 0xFF; *data++ = 0x0D;
48     *data++ = 0x00; *data++ = EOP_LOOP;
49     *data++ = 0xFF; *data++ = 0x0D;
50     *data++ = 0x00; *data++ = EOP_DOIO;
51 
52     *data++ = 0x4E; *data++ = 0x75;
53     *data++ = 0xFF; *data++ = 0x0D;
54     *data++ = 0x00; *data++ = EOP_SERVEINT;
55     *data++ = 0x4E; *data++ = 0x73;
56 
57     *data++ = 0xFF; *data++ = 0x0D;
58     *data++ = 0x00; *data++ = EOP_AVAILMEM;
59     *data++ = 0x4E; *data++ = 0x75;
60     *data++ = 0xFF; *data++ = 0x0D;
61 
62     *data++ = 0x00; *data++ = EOP_ALLOCMEM;
63     *data++ = 0x4E; *data++ = 0x75;
64     *data++ = 0xFF; *data++ = 0x0D;
65     *data++ = 0x00; *data++ = EOP_ALLOCABS;
66 
67     *data++ = 0x4E; *data++ = 0x75;
68 }
69 
ersatz_failed(void)70 static void ersatz_failed (void)
71 {
72     if (already_failed)
73 	return;
74     already_failed = 1;
75 #if 0
76     notify_user (NUMSG_KICKREPNO);
77     uae_restart (-1, NULL);
78 #endif
79     uae_quit ();
80 }
81 
ersatz_doio(void)82 static void ersatz_doio (void)
83 {
84     uaecptr request = m68k_areg (regs, 1);
85     switch (get_word (request + 0x1C)) {
86      case 9: /* TD_MOTOR is harmless */
87      case 2: case 0x8002: /* READ commands */
88 	break;
89 
90      default:
91 	write_log ("Only CMD_READ supported in DoIO()\n");
92 	ersatz_failed ();
93     }
94     {
95 	uaecptr dest = get_long (request + 0x28);
96 	int start = get_long (request + 0x2C) / 512;
97 	int nsecs = get_long (request + 0x24) / 512;
98 	int tr = start / 11;
99 	int sec = start % 11;
100 	while (nsecs--) {
101 	    DISK_ersatz_read (tr, sec, dest);
102 	    dest += 512;
103 	    if (++sec == 11)
104 		sec = 0, tr++;
105 	}
106     }
107 }
108 
ersatz_init(void)109 static void ersatz_init (void)
110 {
111     int f;
112     uaecptr request;
113     uaecptr a;
114 
115     if (disk_empty (0)) {
116 	write_log ("You need to have a diskfile in DF0 to use the Kickstart replacement!\n");
117 	uae_quit ();
118 	m68k_setpc (0xF80010);
119 	return;
120     }
121 
122     regs.s = 0;
123     /* Set some interrupt vectors */
124     for (a = 8; a < 0xC0; a += 4) {
125 	put_long (a, 0xF8001A);
126     }
127     regs.isp = regs.msp = regs.usp = 0x800;
128     m68k_areg (regs, 7) = 0x80000;
129     regs.intmask = 0;
130 
131     /* Build a dummy execbase */
132     put_long (4, m68k_areg (regs, 6) = 0x676);
133     put_byte (0x676 + 0x129, 0);
134     for (f = 1; f < 105; f++) {
135 	put_word (0x676 - 6*f, 0x4EF9);
136 	put_long (0x676 - 6*f + 2, 0xF8000C);
137     }
138     /* Some "supported" functions */
139     put_long (0x676 - 456 + 2, 0xF80014);
140     put_long (0x676 - 216 + 2, 0xF80020);
141     put_long (0x676 - 198 + 2, 0xF80026);
142     put_long (0x676 - 204 + 2, 0xF8002c);
143     put_long (0x676 - 210 + 2, 0xF8002a);
144 
145     /* Build an IORequest */
146     request = 0x800;
147     put_word (request + 0x1C, 2);
148     put_long (request + 0x28, 0x4000);
149     put_long (request + 0x2C, 0);
150     put_long (request + 0x24, 0x200 * 4);
151     m68k_areg (regs, 1) = request;
152     ersatz_doio ();
153     /* kickstart disk loader */
154     if (get_long (0x4000) == 0x4b49434b) {
155 	/* a kickstart disk was found in drive 0! */
156 	write_log ("Loading Kickstart rom image from Kickstart disk\n");
157 	/* print some notes... */
158 	write_log ("NOTE: if UAE crashes set CPU to 68000 and/or chipmem size to 512KB!\n");
159 
160 	/* read rom image from kickstart disk */
161 	put_word (request + 0x1C, 2);
162 	put_long (request + 0x28, 0xF80000);
163 	put_long (request + 0x2C, 0x200);
164 	put_long (request + 0x24, 0x200 * 512);
165 	m68k_areg (regs, 1) = request;
166 	ersatz_doio ();
167 
168 	/* read rom image once again to mirror address space.
169 	   not elegant, but it works... */
170 	put_word (request + 0x1C, 2);
171 	put_long (request + 0x28, 0xFC0000);
172 	put_long (request + 0x2C, 0x200);
173 	put_long (request + 0x24, 0x200 * 512);
174 	m68k_areg (regs, 1) = request;
175 	ersatz_doio ();
176 
177 	disk_eject (0);
178 
179 	m68k_setpc (0xFC0002);
180 	fill_prefetch_slow ();
181 	uae_reset (0);
182 	ersatzkickfile = 0;
183 	return;
184     }
185 
186     m68k_setpc (0x400C);
187     fill_prefetch_slow ();
188 
189     /* Init the hardware */
190     put_long (0x3000, 0xFFFFFFFEul);
191     put_long (0xDFF080, 0x3000);
192     put_word (0xDFF088, 0);
193     put_word (0xDFF096, 0xE390);
194     put_word (0xDFF09A, 0xE02C);
195     put_word (0xDFF09E, 0x0000);
196     put_word (0xDFF092, 0x0038);
197     put_word (0xDFF094, 0x00D0);
198     put_word (0xDFF08E, 0x2C81);
199     put_word (0xDFF090, 0xF4C1);
200     put_word (0xDFF02A, 0x8000);
201 
202     put_byte (0xBFD100, 0xF7);
203     put_byte (0xBFEE01, 0);
204     put_byte (0xBFEF01, 0x08);
205     put_byte (0xBFDE00, 0x04);
206     put_byte (0xBFDF00, 0x84);
207     put_byte (0xBFDD00, 0x9F);
208     put_byte (0xBFED01, 0x9F);
209 }
210 
ersatz_perform(uae_u16 what)211 void ersatz_perform (uae_u16 what)
212 {
213     switch (what) {
214      case EOP_INIT:
215 	ersatz_init ();
216 	break;
217 
218      case EOP_SERVEINT:
219 	/* Just reset all the interrupt request bits */
220 	put_word (0xDFF09C, get_word (0xDFF01E) & 0x3FFF);
221 	break;
222 
223      case EOP_DOIO:
224 	ersatz_doio ();
225 	break;
226 
227      case EOP_AVAILMEM:
228 	m68k_dreg (regs, 0) = m68k_dreg (regs, 1) & 4 ? 0 : 0x70000;
229 	break;
230 
231      case EOP_ALLOCMEM:
232 	m68k_dreg (regs, 0) = m68k_dreg (regs, 1) & 4 ? 0 : 0x0F000;
233 	break;
234 
235      case EOP_ALLOCABS:
236 	m68k_dreg (regs, 0) = m68k_areg (regs, 1);
237 	break;
238 
239      case EOP_NIMP:
240 	write_log ("Unimplemented Kickstart function called\n");
241 	ersatz_failed ();
242 	break;
243 
244 	/* fall through */
245      case EOP_LOOP:
246 	m68k_setpc (0xF80010);
247 	break;
248 
249      case EOP_OPENLIB:
250      default:
251 	write_log ("Internal error. Giving up.\n");
252 	ersatz_failed ();
253 	break;
254     }
255 }
256