1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "z80-cpu.h"
5 #include "z80-mon.h"
6
7 _uchar *io_address;
8 static _uchar memory[1<<16];
9
10 #define MEMORY_INIT_BYTE 0x0 /* also used for accessing unreadable memory */
11
12 static unsigned char empty = MEMORY_INIT_BYTE;
13
14 struct port_map {
15 bit virtuel;
16 unsigned short offset;
17 short port_no;
18 unsigned char mask;
19 unsigned short count;
20 unsigned char *bankids;
21 } ;
22
23 static struct {
24 unsigned char type; /* type=='-' means virtuel bank */
25 unsigned short log2_size;
26 unsigned char *back_up;
27 unsigned char mapped_from; /* relevant for virtuel bank only */
28 } bank[256];
29
30 static unsigned no_maps, delta;
31 static bit all_readable;
32 struct port_map *map;
33 static unsigned char **address_map; /* map of bank_id's in current memory */
34 static unsigned char *mapped_from; /* reverse map of bank_id's */
35 static unsigned long access_type; /* holds two bits for each possible bank */
36
37
38 #ifdef NEEDED
39 static void
set_bank_port(unsigned char port_id,unsigned char value)40 set_bank_port(unsigned char port_id, unsigned char value)
41 {
42 #ifdef OLD_STYLE
43 FILE *fp;
44 if (!(fp=fopen(Z80_PORTS,"r+b")))
45 return;
46 fseek(fp,port_id,SEEK_SET);
47 fwrite(&value,1,1,fp);
48 fclose(fp);
49 #endif
50 }
51 #endif
52
53 #define MAX_NEST 2 /* unbelievable hardware if greater than 2 **/
54
55 static unsigned char *
update_all_adress_maps(unsigned char bank_id)56 update_all_adress_maps(unsigned char bank_id)
57 {
58 unsigned i, j, t=0;
59 unsigned char id, end=0; /* to prevent compiler warning uninitialization */
60 bool first=1;
61 for (i=1<<16-delta;i--;)
62 { bool update=0;
63 if (address_map[i] == memory) continue;
64 id=mapped_from[i];
65 for (j=0; bank[id].type=='-' && (!first || j < MAX_NEST); j++)
66 { if (id == bank_id)
67 { update= 1;
68 if (!first) break;
69 }
70 id= bank[id].mapped_from;
71 }
72 if (update)
73 {
74 if (!first)
75 address_map[i]= bank[end=id].back_up;
76 else
77 address_map[i]= bank[end].back_up;
78 i *= 2;
79 access_type &= ~(3<<i);
80 if (!first)
81 access_type |= t<<i;
82 else if (bank[id].type == '+')
83 t=0;
84 else if (bank[id].type == 'r')
85 access_type |= (t=2)<<i;
86 else if (bank[id].type == 'w')
87 access_type |= (t=1)<<i;
88 else
89 access_type |= (t=3)<<i;
90 first=0;
91 }
92 else if (bank[id].type=='-')
93 return (unsigned char *)0;
94 }
95 return first ? (unsigned char *)0 : bank[end].back_up;
96 }
97 #undef MAX_NEST
98
99
100 static void
bank_switch(unsigned i,unsigned char id)101 bank_switch(unsigned i, unsigned char id)
102 {
103 if (map[i].virtuel)
104 { unsigned char bank_id= map[i].offset;
105 if (bank[bank_id].back_up=update_all_adress_maps(bank_id))
106 bank[bank_id].mapped_from= id;
107 }
108 else
109 {
110 unsigned index = map[i].offset>>delta;
111 #ifdef NEEDED
112 unsigned j;
113 for (j=0;j<no_maps;j++)
114 if (!map[j].virtuel && map[i].offset == map[j].offset)
115 { if (i != j && map[j].port_no >= 0)
116 /* different ports have equal offset!! */
117 set_bank_port((unsigned char)map[j].port_no,id);
118 }
119 #endif
120 mapped_from[index]= id;
121 address_map[index] = bank[id].back_up;
122 index *= 2;
123 access_type &= ~(3<<index);
124 if (bank[id].type == '+')
125 ;
126 else if (bank[id].type == 'r')
127 access_type |= 2<<index;
128 else if (bank[id].type == 'w')
129 access_type |= 1<<index;
130 else
131 access_type |= 3<<index;
132 }
133 }
134
135
set_default_byte(_uchar val)136 void set_default_byte(_uchar val)
137 {
138 empty= val;
139 }
140
141
142 void
switch_bank(_uchar val,unsigned map_no)143 switch_bank(_uchar val, unsigned map_no)
144 {
145 unsigned i, j;
146 unsigned short portno;
147 if (map_no > no_maps || !map_no || map[map_no-1].port_no < 0)
148 return;
149 portno= map[map_no-1].port_no;
150 for (i=0;i<no_maps;i++)
151 if (portno == map[i].port_no)
152 { unsigned char id= val & map[i].mask;
153 for (j=0;j<map[i].count;j++)
154 if (id == *(map[i].bankids+j))
155 bank_switch(i, id);
156 }
157 }
158
159
160 unsigned
bank_port_index(unsigned char id)161 bank_port_index(unsigned char id)
162 {
163 unsigned i;
164 for (i=0;i<no_maps;i++)
165 if (map[i].port_no == id)
166 return i+1;
167 return 0;
168 }
169
170
171 void
reset_banks(void)172 reset_banks(void)
173 {
174 unsigned i;
175 if (!no_maps) return;
176 for (i= 1<<(16-delta); i-- ; )
177 address_map[i]= memory;
178 for (i=0;i<no_maps;i++)
179 { if (!i || map[i].offset != map[i-1].offset)
180 bank_switch(i,*(map[i].bankids));
181 }
182 }
183
184
dealloc_banks_and_maps(void)185 void dealloc_banks_and_maps(void)
186 {
187 unsigned i;
188 for (i=0;i<256;i++)
189 if (bank[i].type && bank[i].back_up)
190 free(bank[i].back_up);
191 for (i=0;i<no_maps;i++)
192 free(map[i].bankids);
193 free(map);
194 free(address_map);
195 free(mapped_from);
196 no_maps=0;
197 }
198
199
200 #define ERROR_DESCR "desription ignored in line %u:"
201 #define ERROR_BANK "bank desription ignored in line %u:"
202 #define ERROR_MAP "map description ignored in line %u:"
203 int
init_banks(char * rom_path,char * bank_mapping_descr)204 init_banks(char *rom_path, char *bank_mapping_descr)
205 {
206 char buffer[800], filename[1024], err_line[64];
207 unsigned k, b, pre_id=0, pre_off=0;
208 short pre_port= -1;
209 FILE *fp;
210 if (!bank_mapping_descr || !*bank_mapping_descr)
211 { sprintf(err_line,"no bank_description file given");
212 error(0,err_line,"");
213 return -1;
214 }
215 else if (!(fp = fopen(bank_mapping_descr,"r")))
216 { sprintf(err_line,"can't open bank_description file: ");
217 error(0,err_line,bank_mapping_descr);
218 return -2;
219 }
220 delta=0;
221 no_maps=0;
222 map= (struct port_map *) 0;
223 all_readable=1;
224 if (rom_path && *rom_path)
225 { strcpy(filename,rom_path);
226 strcat(filename,"/");
227 b=strlen(filename);
228 }
229 else
230 b=0;
231 for (k=1; fgets(buffer,800,fp) ; k++)
232 {
233 char tok1[5], tok2[5], tok3[5], tok4[512];
234 unsigned i, offset, mask, id, log2;
235 FILE *rom_fp;
236 short portno;
237
238 for (i=0;buffer[i] && buffer[i] < ' '; i++);
239 if (!buffer[i] || buffer[i]=='#') continue;
240
241 if (4 != sscanf(buffer,"%4s %4s %4s %511s",tok1,tok2,tok3,tok4))
242 { sprintf(err_line,ERROR_DESCR,k);
243 error(0,err_line," not 4 entries or entry too long");
244 continue;
245 }
246 if (strlen(tok1) != 1 && !delta)
247 { sprintf(err_line,ERROR_DESCR,k);
248 error(0,err_line," bank description expected");
249 continue;
250 }
251 if (strlen(tok1) == 1 && no_maps)
252 { sprintf(err_line,ERROR_DESCR,k);
253 error(0,err_line," map description expected");
254 continue;
255 }
256 if (strlen(tok1) == 1) /* bank description line */
257 {
258 if (tok1[0] != '+' && tok1[0] != 'w' && tok1[0] != 'r' && tok1[0] != '-')
259 { sprintf(err_line,ERROR_BANK,k);
260 error(0,err_line," invalid access_type");
261 continue;
262 }
263 if (1 != sscanf(tok2,"%x",&id) || id >= 256)
264 { sprintf(err_line,ERROR_BANK,k);
265 error(0,err_line," invalid bank_id");
266 continue;
267 }
268 if (bank[id].type)
269 { sprintf(err_line,ERROR_BANK,k);
270 error(0,err_line," bank_id already defined");
271 continue;
272 }
273 if (delta && id < pre_id)
274 { sprintf(err_line,ERROR_BANK,k);
275 error(0,err_line," bank_id not ascending sorted");
276 continue;
277 }
278 if (1 != sscanf(tok3,"%u",&log2) || (log2 != 12 && log2 != 14))
279 { sprintf(err_line,ERROR_BANK,k);
280 error(0,err_line," invalid log2_size");
281 continue;
282 }
283 if (delta && log2 != delta)
284 { sprintf(err_line,ERROR_BANK,k);
285 error(0,err_line," different bank sizes");
286 continue;
287 }
288 strcpy(filename+b,tok4);
289 if (tok4[0] == '-' && tok4[1] == '\0')
290 rom_fp = NULL;
291 else if (tok1[0]=='-')
292 { sprintf(err_line,ERROR_BANK,k);
293 error(0,err_line," virtuel bank has bank file");
294 continue;
295 }
296 else if (!(rom_fp = fopen(filename,"r")))
297 { char err_msg[64];
298 sprintf(err_line,ERROR_BANK,k);
299 sprintf(err_msg," can't open bank file %63s", filename);
300 error(0,err_line,err_msg);
301 continue;
302 }
303 if (!(bank[id].back_up= (unsigned char *) malloc(1<<log2)))
304 { sprintf(err_line,ERROR_BANK,k);
305 error(0,err_line," insuffient memory");
306 continue;
307 }
308 if (rom_fp)
309 { fread(bank[id].back_up,1,1<<log2,rom_fp);
310 fclose(rom_fp);
311 }
312 delta=log2;
313 bank[id].log2_size = 1<<log2;
314 bank[id].type = tok1[0];
315 pre_id=id;
316 if (tok1[0] == 'w')
317 all_readable=0;
318 }
319 else /* page description line */
320 { unsigned h, j;
321 char *p;
322 struct port_map *mmm;
323 for (i=0;i<5;i++)
324 if (tok1[i] >= '0' && tok1[i] <= '9') continue;
325 else if (tok1[i] >= 'a' && tok1[i] <= 'f') continue;
326 else if (tok1[i] >= 'A' && tok1[i] <= 'F') continue;
327 else
328 break;
329 if (i != 2 && i != 4)
330 { sprintf(err_line,ERROR_MAP,k);
331 error(0,err_line," invalid offset or bank_id");
332 continue;
333 }
334 if (i == 2 && bank[i].type != '-')
335 { sprintf(err_line,ERROR_MAP,k);
336 error(0,err_line," offset is no virtuel bank_id");
337 continue;
338 }
339 sscanf(tok1,"%x",&offset);
340 if (no_maps && offset < pre_off)
341 { sprintf(err_line,ERROR_MAP,k);
342 error(0,err_line," offset/bank_id not ascending sorted");
343 continue;
344 }
345 if (i==4 && (offset & (1<<delta)-1))
346 { sprintf(err_line,ERROR_MAP,k);
347 error(0,err_line," offset not multiple of bank size");
348 continue;
349 }
350 if (tok2[0] == '-' && !tok2[1])
351 { portno= -1;
352 if (i==2)
353 { sprintf(err_line,ERROR_MAP,k);
354 error(0,err_line," map to virtuel bank without port");
355 continue;
356 }
357 }
358 else
359 { portno = strtoul(tok2,&p,0);
360 if (portno >= 256 || p && *p || tok2[0]=='-' || tok2[0]=='+')
361 { sprintf(err_line,ERROR_MAP,k);
362 error(0,err_line," invalid port_id");
363 continue;
364 }
365 }
366 if (no_maps && offset == pre_off && portno < pre_port)
367 { sprintf(err_line,ERROR_MAP,k);
368 error(0,err_line," offset/port_no not ascending sorted");
369 continue;
370 }
371 for (j=0;j<2;j++)
372 if (tok3[j] >= '0' && tok3[j] <= '9') continue;
373 else if (tok3[j] >= 'a' && tok3[j] <= 'f') continue;
374 else if (tok3[j] >= 'A' && tok3[j] <= 'F') continue;
375 else
376 break;
377 if (j != 2)
378 { sprintf(err_line,ERROR_MAP,k);
379 error(0,err_line," invalid mask");
380 continue;
381 }
382 sscanf(tok3,"%x",&mask);
383 for (j=0;tok4[j];j++)
384 if (j%3 == 2 && tok4[j]!=',')
385 break;
386 if (tok4[j] || j%3 != 2)
387 { sprintf(err_line,ERROR_MAP,k);
388 error(0,err_line," invalid format of bank_ids");
389 continue;
390 }
391 h= (j+1)/3;
392 pre_id= 0;
393 for (j=0;j<h;j++)
394 { id = strtoul(tok4+3*j,&p,16);
395 if (id >= 256 || (p && *p && *p != ',') || tok4[3*j]=='-' || tok4[3*j]=='+')
396 { char err_msg[32];
397 sprintf(err_line,ERROR_MAP,k);
398 sprintf(err_msg," invalid %u-th bank_id: %3s",j+1,tok4+3*j);
399 error(0,err_line,err_msg);
400 break;
401 }
402 if (j && id <= pre_id)
403 { sprintf(err_line,ERROR_MAP,k);
404 error(0,err_line," bank_ids not ascending ordered");
405 break;
406 }
407 if (!bank[id].type)
408 { char err_msg[32];
409 sprintf(err_line,ERROR_MAP,k);
410 sprintf(err_msg," bank_id %u not defined",id);
411 error(0,err_line,err_msg);
412 break;
413 }
414 pre_id=id;
415 }
416 if (j < h) continue;
417 if (!(mmm= (struct port_map *)realloc(map,(no_maps+1)*sizeof(struct port_map))))
418 { sprintf(err_line,ERROR_MAP,k);
419 error(0,err_line," insufficent memory");
420 continue;
421 }
422 map=mmm;
423 map[no_maps].virtuel= (i==2);
424 map[no_maps].offset= offset;
425 pre_off=offset;
426 map[no_maps].port_no = portno;
427 pre_port=portno;
428 map[no_maps].mask = mask;
429 map[no_maps].count = h;
430 if (!(map[no_maps].bankids= (unsigned char*)malloc(h*sizeof(_uchar))))
431 { sprintf(err_line,ERROR_MAP,k);
432 error(0,err_line," insufficent memory");
433 continue;
434 }
435 for (j=0;j<h;j++)
436 { sscanf(tok4+3*j,"%2x",&id);
437 *(map[no_maps].bankids+j) = id;
438 }
439 no_maps++;
440 }
441 }
442 fclose(fp);
443 if (no_maps)
444 { if (!(address_map = (unsigned char **) malloc(sizeof(unsigned char*)<<(16-delta))))
445 { error(0,"init_banks","bank mapping: insufficent memory");
446 dealloc_banks_and_maps();
447 }
448 else if (!(mapped_from = (unsigned char *) malloc(sizeof(unsigned char)<<(16-delta))))
449 { error(0,"init_banks","bank mapping: insufficent memory");
450 dealloc_banks_and_maps();
451 }
452 reset_banks();
453 }
454 return no_maps;
455 }
456 #undef ERROR_DESCR
457 #undef ERROR_MAP
458 #undef ERROR_BANK
459
460
memory_at(unsigned short index)461 _uchar memory_at(unsigned short index)
462 {
463 return !no_maps ? memory[index] :
464 !all_readable && (access_type>>(2*(index>>delta))&1) ?
465 empty : *(address_map[index>>delta]+index) ;
466 }
467
468
read_memo(unsigned short index)469 _uchar read_memo(unsigned short index)
470 {
471 if (cpu_pin[busrq]) acknowledge_bus_request();
472 if(!cpu_is_in_disassemble) ADDRESS=index;
473 set_cpu_pin(rd,1);
474 set_cpu_pin(mreq,1);
475 if(!cpu_is_in_disassemble) wait_tics(TICS_MEMO);
476 DATA= (!no_maps ? memory[index] :
477 !all_readable && (access_type>>(2*(index>>delta))&1) ?
478 empty : *(address_map[index>>delta]+index)) ;
479 set_cpu_pin(mreq,0);
480 set_cpu_pin(rd,0);
481 return DATA;
482 }
483
484
read_opcode(unsigned short index,bool set_m1)485 _uchar read_opcode(unsigned short index, bool set_m1)
486 {
487 if (cpu_pin[busrq]) acknowledge_bus_request();
488 if (set_m1) set_cpu_pin(m1,1);
489 if(!cpu_is_in_disassemble) ADDRESS=index;
490 set_cpu_pin(rd,1);
491 if (io_address)
492 {
493 DATA= *(io_address+index);
494 if(!cpu_is_in_disassemble) wait_tics(TICS_MEMO);
495 }
496 else
497 {
498 set_cpu_pin(mreq,1);
499 DATA= (!no_maps ? memory[index] :
500 !all_readable && (access_type>>(2*(index>>delta))&1) ?
501 empty : *(address_map[index>>delta]+index)) ;
502 if(!cpu_is_in_disassemble) wait_tics(TICS_MEMO);
503 set_cpu_pin(mreq,0);
504 }
505 set_cpu_pin(rd,0);
506 if (set_m1) set_cpu_pin(m1,0);
507 return DATA;
508 }
509
510
write_memo(unsigned short index,unsigned char data)511 void write_memo(unsigned short index, unsigned char data)
512 {
513 if (cpu_pin[busrq]) acknowledge_bus_request();
514 if(!cpu_is_in_disassemble) ADDRESS=index;
515 DATA=data;
516 set_cpu_pin(wr,1);
517 set_cpu_pin(mreq,1);
518 if(!cpu_is_in_disassemble) wait_tics(TICS_MEMO);
519 if (!no_maps)
520 memory[index]=DATA;
521 else if (!(access_type>>(2*(index>>delta))&2))
522 *(address_map[index>>delta]+index)=DATA;
523 set_cpu_pin(mreq,0);
524 set_cpu_pin(wr,0);
525 }
526
527
write_to_memory(_ushort index,_uchar data)528 _uchar write_to_memory(_ushort index, _uchar data)
529 {
530 _uchar previous;
531 set_cpu_pin(wr,1);
532 if (io_address)
533 { previous= *(io_address+index);
534 *(io_address+index) = data;
535 }
536 else
537 {
538 set_cpu_pin(mreq,1);
539 previous= (!no_maps ? memory[index] :
540 !all_readable && (access_type>>(2*(index>>delta))&1) ?
541 empty : *(address_map[index>>delta]+index)) ;
542 if (!no_maps)
543 memory[index]= data;
544 else if (!(access_type>>(2*(index>>delta))&2))
545 *(address_map[index>>delta]+index)= data;
546 set_cpu_pin(mreq,0);
547 }
548 set_cpu_pin(wr,0);
549 return previous;
550 }
551
552
553 void
clear_memory(void)554 clear_memory(void)
555 {
556 int i;
557 if (!no_maps)
558 memset(memory,empty,65536);
559 else
560 for (i=0;i<16;i++)
561 if (!(access_type>>(2*i)&2))
562 memset(memory+(i<<delta),empty,1<<delta);
563 }
564
565
dma_write(unsigned short offset,unsigned count,FILE * from)566 unsigned dma_write(unsigned short offset, unsigned count, FILE *from)
567 {
568 return fread(memory+offset,1,count+offset<65536U?count:65536U-offset,from);
569 }
570
571
dma_read(unsigned short offset,unsigned count,FILE * to)572 unsigned dma_read(unsigned short offset, unsigned count, FILE *to)
573 {
574 return fwrite(memory+offset,1,count+offset<65536U?count:65536U-offset,to);
575 }
576