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