1 /***************************************************************************/
2 /*                                                                         */
3 /*                      hard BIOS support source file                      */
4 /*                                                                         */
5 /* This file contain support for pc engine hudson cd bios without using    */
6 /* the standard routines with ports but simulating directly the function.  */
7 /*                                                                         */
8 /* You're welcome to help coding this piece of software, it's really       */
9 /* interesting to discover precise use of each function by hacking the     */
10 /* cd system and such ^^                                                   */
11 /***************************************************************************/
12 
13 #include "h6280.h"
14 #include "globals.h"
15 #include "utils.h"
16 #include "pce.h"
17 
18 #undef INLINED_ACCESSORS
19 
20 #if !defined(INLINED_ACCESSORS)
21 
22 #define get_8bit_addr(addr) Rd6502((UInt16)(addr))
23 
24 #define put_8bit_addr(addr,byte) Wr6502((addr),(byte))
25 
26 #endif
27 
28 /* CD related functions */
29 
30 #define CD_BOOT   0x00
31 #define CD_RESET  0x01
32 #define CD_BASE   0x02
33 #define CD_READ   0x03
34 #define CD_SEEK   0x04
35 #define CD_EXEC   0x05
36 #define CD_PLAY   0x06
37 #define CD_SEARCH 0x07
38 #define CD_PAUSE  0x08
39 #define CD_STAT   0x09
40 #define CD_SUBA   0x0A
41 #define CD_DINFO  0x0B
42 
43 #define CD_DINFO_NB_TRACKS 0
44 #define CD_DINFO_LENGTH 1
45 #define CD_DINFO_TRACK 2
46 
47 #define CD_CONTENTS 0x0C
48 #define CD_SUBRQ  0x0D
49 #define CD_PCMRD  0x0E
50 #define CD_FADE   0x0F
51 
52 /* ADPCM related functions */
53 
54 #define AD_RESET  0x10
55 #define AD_TRANS  0x11
56 #define AD_READ   0x12
57 #define AD_WRITE  0x13
58 #define AD_PLAY   0x14
59 #define AD_CPLAY  0x15
60 #define AD_STOP   0x16
61 #define AD_STAT   0x17
62 
63 /* BACKUP MEM related functions */
64 
65 #define BM_FORMAT 0x18
66 #define BM_FREE   0x19
67 #define BM_READ   0x1A
68 #define BM_WRITE  0x1B
69 #define BM_DELETE 0x1C
70 #define BM_FILES  0x1D
71 
72 /* Miscelanous functions */
73 
74 #define EX_GETVER 0x1E
75 #define EX_SETVEC 0x1F
76 #define EX_GETFNT 0x20
77 #define EX_JOYSNS 0x21
78 #define EX_JOYREP 0x22
79 #define EX_SCRSIZ 0x23
80 #define EX_DOTMOD 0x24
81 #define EX_SCRMOD 0x25
82 #define EX_IMODE  0x26
83 #define EX_VMOD   0x27
84 #define EX_HMOD   0x28
85 #define EX_VSYNC  0x29
86 #define EX_RCRON  0x2A
87 #define EX_RCROFF 0x2B
88 #define EX_IRQON  0x2C
89 #define EX_IRQOFF 0x2D
90 #define EX_BGON   0x2E
91 #define EX_BGOFF  0x2F
92 #define EX_SPRON  0x30
93 #define EX_SPROFF 0x31
94 #define EX_DSPON  0x32
95 #define EX_DSPOFF 0x33
96 #define EX_DMAMOD 0x34
97 #define EX_SPRDMA 0x35
98 #define EX_SATCLR 0x36
99 #define EX_SPRPUT 0x37
100 #define EX_SETRCR 0x38
101 #define EX_SETRED 0x39
102 #define EX_SETWRT 0x3A
103 #define EX_SETDMA 0x3B
104 #define EX_BINBCD 0x3C
105 #define EX_BCDBIN 0x3D
106 #define EX_RND    0x3E
107 
108 /* Math related functions */
109 
110 #define MA_MUL8U  0x3F
111 #define MA_MUL8S  0x40
112 #define MA_MUL16U 0x41
113 #define MA_DIV16U 0x42
114 #define MA_DIV16S 0x43
115 #define MA_SQRT   0x44
116 #define MA_SIN    0x45
117 #define MA_COS    0x46
118 #define MA_ATNI   0x47
119 
120 /* PSG BIOS functions */
121 
122 #define PSG_BIOS  0x48
123 #define GRP_BIOS  0x49
124 #define KEY_BIOS  0x4A
125 #define PSG_DRIVE 0x4B
126 #define EX_COLORC 0x4C
127 
128 
129 #define MA_MUL16S 0x4F
130 #define MA_CBASIS 0x50
131 
132 #define _al 0xF8
133 #define _ah 0xF9
134 #define _bl 0xFA
135 #define _bh 0xFB
136 #define _cl 0xFC
137 #define _ch 0xFD
138 #define _dl 0xFE
139 #define _dh 0xFF
140 
141 #define _ax 0xF8
142 #define _bx 0xFA
143 #define _cx 0xFC
144 #define _dx 0xFE
145 
146 
147 int testadpcm = 0;
148 
149 #ifdef CD_DEBUG
150 
cdbios_functions(int index)151 const char *cdbios_functions(int index)
152 {
153   switch(index) {
154     case CD_BOOT:
155       return "CD_BOOT";
156     case CD_RESET:
157       return "CD_RESET";
158     case CD_BASE:
159       return "CD_BASE";
160     case CD_READ:
161       return "CD_READ";
162     case CD_SEEK:
163       return "CD_SEEK";
164     case CD_EXEC:
165       return "CD_EXEC";
166     case CD_PLAY:
167       return "CD_PLAY";
168     case CD_SEARCH:
169       return "CD_SEARCH";
170     case CD_PAUSE:
171       return "CD_PAUSE";
172     case CD_STAT:
173       return "CD_STAT";
174     case CD_SUBA:
175       return "CD_SUBA";
176     case CD_DINFO:
177       return "CD_DINFO";
178     case CD_CONTENTS:
179       return "CD_CONTENTS";
180     case CD_SUBRQ:
181       return "CD_SUBRQ";
182     case CD_PCMRD:
183       return "CD_PCMRD";
184     case CD_FADE:
185       return "CD_FADE";
186 
187     case AD_RESET:
188       return "AD_RESET";
189     case AD_TRANS:
190       return "AD_TRANS";
191     case AD_READ:
192       return "AD_READ";
193     case AD_WRITE:
194       return "AD_WRITE";
195     case AD_PLAY:
196       return "AD_PLAY";
197     case AD_CPLAY:
198       return "AD_CPLAY";
199     case AD_STOP:
200       return "AD_STOP";
201     case AD_STAT:
202       return "AD_STAT";
203 
204     case BM_FORMAT:
205       return "BM_FORMAT";
206     case BM_FREE:
207       return "BM_FREE";
208     case BM_READ:
209       return "BM_READ";
210     case BM_WRITE:
211       return "BM_WRITE";
212     case BM_DELETE:
213       return "BM_DELETE";
214     case BM_FILES:
215       return "BM_FILES";
216 
217     case EX_GETVER:
218       return "EX_GETVER";
219     case EX_SETVEC:
220       return "EX_SETVEC";
221     case EX_GETFNT:
222       return "EX_GETFNT";
223     case EX_JOYSNS:
224       return "EX_JOYSNS";
225     case EX_JOYREP:
226       return "EX_JOYREP";
227 
228     case EX_SCRSIZ:
229       return "EX_SCRSIZ";
230     case EX_DOTMOD:
231       return "EX_DOTMOD";
232     case EX_SCRMOD:
233       return "EX_SCRMOD";
234     case EX_IMODE:
235       return "EX_IMODE";
236     case EX_VMOD:
237       return "EX_VMOD";
238     case EX_HMOD:
239       return "EX_HMOD";
240     case EX_VSYNC:
241       return "EX_VSYNC";
242     case EX_RCRON:
243       return "EX_RCRON";
244     case EX_RCROFF:
245       return "EX_RCROFF";
246     case EX_IRQON:
247       return "EX_IRQON";
248     case EX_IRQOFF:
249       return "EX_IRQOFF";
250     case EX_BGON:
251       return "EX_BGON";
252     case EX_BGOFF:
253       return "EX_BGOFF";
254     case EX_SPRON:
255       return "EX_SPRON";
256     case EX_SPROFF:
257       return "EX_SPROFF";
258     case EX_DSPON:
259       return "EX_DSPON";
260     case EX_DSPOFF:
261       return "EX_DSPOFF";
262     case EX_DMAMOD:
263       return "EX_DMAMOD";
264     case EX_SPRDMA:
265       return "EX_SPRDMA";
266     case EX_SATCLR:
267       return "EX_SATCLR";
268     case EX_SPRPUT:
269       return "EX_SPRPUT";
270     case EX_SETRCR:
271       return "EX_SETRCR";
272     case EX_SETRED:
273       return "EX_SETRED";
274     case EX_SETWRT:
275       return "EX_SETWRT";
276     case EX_SETDMA:
277       return "EX_SETDMA";
278     case EX_BINBCD:
279       return "EX_BINBCD";
280     case EX_BCDBIN:
281       return "EX_BCDBIN";
282     case EX_RND:
283       return "EX_RND";
284 
285     case MA_MUL8U:
286       return "MA_MUL8U";
287     case MA_MUL8S:
288       return "MA_MUL8S";
289     case MA_MUL16U:
290       return "MA_MUL16U";
291     case MA_DIV16S:
292       return "MA_DIV16S";
293     case MA_DIV16U:
294       return "MA_DIV16U";
295     case MA_SQRT:
296       return "MA_SQRT";
297     case MA_SIN:
298       return "MA_SIN";
299     case MA_COS:
300       return "MA_COS";
301     case MA_ATNI:
302       return "MA_ATNI";
303 
304     case PSG_BIOS:
305       return "PSG_BIOS";
306 
307     case GRP_BIOS:
308       return "GRP_BIOS";
309     case KEY_BIOS:
310       return "KEY_BIOS";
311     case PSG_DRIVE:
312       return "PSG_DRIVE";
313     case EX_COLORC:
314       return "EX_COLORC";
315 
316     default:
317       break;
318   }
319 
320   return "?UNKNOWN?";
321 }
322 
323 #endif
324 
325 
handle_bios(void)326 void handle_bios(void)
327 {
328 #ifdef CD_DEBUG
329   static int last_op = -1, last_ax = -1, last_bx = -1, last_cx = -1, last_dx = -1;
330   int this_op = imm_operand(reg_pc + 1), this_ax = get_16bit_zp(_ax), this_bx = get_16bit_zp(_bx),
331       this_cx = get_16bit_zp(_cx), this_dx = get_16bit_zp(_dx);
332 
333   /*
334    * Skip over polling functions to avoid the spam
335    */
336   if ((this_op != CD_PCMRD) && (this_op != CD_SUBA) && (this_op != EX_JOYSNS) && (this_op != AD_STAT)) {
337     if ((last_op != this_op) || (last_ax != this_ax) || (last_bx != this_bx) || (last_cx != this_cx) ||
338         (last_dx != this_dx)) {
339       fprintf(stderr, "\n%s: ax=%d ah=%d al=%d bx=%d bh=%d bl=%d\ncx=%d ch=%d cl=%d dx=%d dh=%d dl=%d",
340               cdbios_functions(imm_operand(reg_pc + 1)), get_16bit_zp(_ax), get_8bit_zp(_ah), get_8bit_zp(_al),
341               get_16bit_zp(_bx), get_8bit_zp(_bh), get_8bit_zp(_bl),
342               get_16bit_zp(_cx), get_8bit_zp(_ch), get_8bit_zp(_cl),
343               get_16bit_zp(_dx), get_8bit_zp(_dh), get_8bit_zp(_dl));
344       last_op = this_op;
345       last_ax = this_ax;
346       last_bx = this_bx;
347       last_cx = this_cx;
348       last_dx = this_dx;
349     } else {
350       fprintf(stderr, ".");
351     }
352   }
353 #endif
354 
355   switch(imm_operand((UInt16)(reg_pc + 1))) {
356     case CD_RESET:
357       switch(CD_emulation) {
358         case 1: /* true CD */
359           if (osd_cd_init(ISO_filename) != 0) {
360             Log("CD rom drive init error!\n");
361             exit(4);
362           }
363           break;
364         case 2: /* ISO */
365         case 3: /* ISQ */
366         case 4: /* BIN */
367           fill_cd_info();
368           break;
369           /* HCD : nothing to be done */
370       }
371 
372       put_8bit_addr(0x222D, 1);
373       // This byte is set to 1 if a disc if present
374 
375       rts();
376       break;
377 
378     case CD_READ:
379       {
380         UChar mode = get_8bit_zp(_dh);
381         UInt32 nb_to_read = get_8bit_zp(_al);
382         UInt16 offset = get_16bit_zp(_bx);
383 
384         pce_cd_sectoraddy = (get_8bit_zp(_cl) << 16) +
385                             (get_8bit_zp(_ch) << 8) +
386                             (get_8bit_zp(_dl));
387 
388         pce_cd_sectoraddy += (get_8bit_addr(0x2274 + 3 * get_8bit_addr(0x2273)) << 16) +
389                              (get_8bit_addr(0x2275 + 3 * get_8bit_addr(0x2273)) << 8) +
390                              (get_8bit_addr(0x2276 + 3 * get_8bit_addr(0x2273)));
391 
392         switch(mode) {
393 
394           case 0: // local, size in byte
395             nb_to_read = get_16bit_zp(_ax);
396 
397             while (nb_to_read >= 2048) {
398               int index;
399 
400               pce_cd_read_sector();
401               for (index = 0;index < 2048; index++)
402                 put_8bit_addr(offset++, cd_read_buffer[index]);
403               nb_to_read -= 2048;
404             }
405 
406             if (nb_to_read) {
407               UInt32 index;
408 
409               pce_cd_read_sector();
410               for (index = 0; index < nb_to_read; index++)
411                 put_8bit_addr(offset++, cd_read_buffer[index]);
412             }
413 
414             reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
415 
416             cd_sectorcnt = 0;
417             cd_read_buffer = NULL;
418             pce_cd_read_datacnt = 0;
419 
420             rts();
421             break;
422 
423 
424           case 1: // local, size in sector
425             while (nb_to_read) {
426               int index;
427 
428               pce_cd_read_sector();
429               for (index = 0; index < 2048; index++)
430                 put_8bit_addr(offset++, cd_read_buffer[index]);
431               nb_to_read--;
432             }
433             reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
434 
435             // TEST
436             io.cd_port_1800 |= 0xD0;
437             // TEST
438 
439             cd_sectorcnt = 0;
440             cd_read_buffer = NULL;
441             pce_cd_read_datacnt = 0;
442 
443             rts();
444             break;
445 
446           case 2:
447           case 3:
448           case 4:
449           case 5:
450           case 6:
451             {
452               UChar nb_bank_to_fill_completely = nb_to_read >> 2;
453               UChar remaining_block_to_write = nb_to_read & 3;
454               UChar bank_where_to_write = get_8bit_zp(_bl);
455               UInt16 offset_in_bank = 0;
456 
457               while (nb_bank_to_fill_completely--) {
458                 pce_cd_read_sector();
459                 memcpy(ROMMapW[bank_where_to_write], cd_read_buffer, 2048);
460 
461                 pce_cd_read_sector();
462                 memcpy(ROMMapW[bank_where_to_write] + 2048, cd_read_buffer, 2048);
463 
464                 pce_cd_read_sector();
465                 memcpy(ROMMapW[bank_where_to_write] + 2048 * 2, cd_read_buffer, 2048);
466 
467                 pce_cd_read_sector();
468                 memcpy(ROMMapW[bank_where_to_write] + 2048 * 3, cd_read_buffer, 2048);
469 
470                 bank_where_to_write++;
471               }
472 
473               offset_in_bank = 0;
474               while (remaining_block_to_write--) {
475                 pce_cd_read_sector();
476 #ifndef FINAL_RELEASE
477                 fprintf(stderr, "Writing quarter to ROMMap[0x%x] + 0x%x\n\n",
478                         bank_where_to_write,offset_in_bank);
479 #endif
480                 memcpy(ROMMapW[bank_where_to_write] + offset_in_bank, cd_read_buffer, 2048);
481                 offset_in_bank += 2048;
482               }
483             }
484 
485             cd_sectorcnt = 0;
486             cd_read_buffer = NULL;
487             pce_cd_read_datacnt = 0;
488 
489             reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
490             rts();
491             break;
492 
493           case 0xFE:
494             IO_write(0, 0);
495             IO_write(2, (UChar)(offset & 0xFF));
496             IO_write(3, (UChar)(offset >> 8));
497             IO_write(0, 2);
498             {
499               UInt32 nb_sector;
500               nb_to_read = get_16bit_zp(_ax);
501               nb_sector = (nb_to_read >> 11) + ((nb_to_read & 2047) ? 1 : 0);
502 
503               while (nb_sector) {
504                 int x, index = min(2048, (int)nb_to_read);
505 
506                 pce_cd_read_sector();
507 
508                 //memcpy(&VRAM[offset],cd_read_buffer,index);
509                 for (x = 0; x < index; x += 2) {
510                   IO_write(2, cd_read_buffer[x]);
511                   IO_write(3, cd_read_buffer[x + 1]);
512                 }
513 
514                 nb_to_read-=index;
515                 nb_sector--;
516               }
517 
518               cd_sectorcnt = 0;
519               cd_read_buffer = NULL;
520               pce_cd_read_datacnt = 0;
521 
522               reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
523               rts();
524 //              break;
525             }
526             break;
527 
528             case 0xFF:
529               if (!nb_to_read)
530                 reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0x22]);
531               else {
532                 IO_write(0, 0);
533                 IO_write(2, (UChar)(offset & 0xFF));
534                 IO_write(3, (UChar)(offset >> 8));
535                 IO_write(0, 2);
536 
537                 while (nb_to_read) {
538                   int index;
539 
540                   pce_cd_read_sector();
541 
542                   for (index = 0; index < 2048; index += 2) {
543                     IO_write(2, cd_read_buffer[index]);
544                     IO_write(3, cd_read_buffer[index + 1]);
545                   }
546 
547                   nb_to_read--;
548                 }
549 
550                 cd_sectorcnt = 0;
551                 cd_read_buffer = NULL;
552                 pce_cd_read_datacnt = 0;
553 
554                 reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
555               }
556               rts();
557               break;
558 
559             default :
560               /* the reading mode isn't supported and we simulate the
561                * behaviour of the 2 first byte opcode and keep going
562                * thus hooking further calls to this function
563                */
564               put_8bit_addr(0x2273, 0);
565               reg_pc += 2;
566 #ifdef CD_DEBUG
567               fprintf(stderr, "Reading mode not supported : %d\n_AX=0x%04x\n_BX=0x%04x\n_CX=0x%04x\n_DX=0x%04x\n",
568                       mode, get_16bit_zp(_ax), get_16bit_zp(_bx), get_16bit_zp(_cx), get_16bit_zp(_dx));
569 #endif
570         }
571       }
572       break;
573 
574     case CD_PAUSE:
575       switch(CD_emulation) {
576         case 1:
577           osd_cd_pause();
578           break;
579         case 2:
580         case 3:
581         case 4:
582           break;
583         case 5:
584           HCD_pause_playing();
585           break;
586       }
587       reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
588       rts();
589       break;
590 
591     case CD_STAT:
592       {
593       /* TODO : makes this function work for cd and hcd at least
594        * gives info on the status of playing music
595        */
596         int retval;
597 
598         osd_cd_status(&retval);
599 
600         reg_p = ((reg_p & (~(FL_N | FL_T | FL_Z))) | flnz_list[reg_a = 0]);
601       }
602       rts();
603       break;
604 
605     case CD_SUBA:
606       /* TODO : check the real functionality of this function
607        * seems to fill a whole buffer of 10 bytes but
608        * meaning of this array is mostly unknown
609        */
610       {
611         UInt16 offset = get_16bit_zp(_bx);
612 //        static UChar result = 3;
613 
614 //        result = 3 - result;
615 
616 //        Wr6502(offset, result); // TEST, for golden axe (3) and solid force (0)
617         osd_cd_subchannel_info(offset);
618       }
619 
620       reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
621       rts();
622       break;
623 
624     case CD_PCMRD:
625       // do almost nothing
626       // fake the audio player, maybe not other piece of code
627       reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = get_8bit_zp(0x41)]);
628       rts();
629       break;
630 
631     case CD_SEARCH:
632       /* unsure how this operates
633        * needed for playing audio discs with a system card
634        *
635        * _al contains the track we're "searching" for.
636        * If I'm not mistaken _bh is a flag with that 7th bit (128) set
637        * for SEEK_SET type behaviour, while if the 2nd bit (2) is set
638        * we play the track after searching for it.
639        */
640 {
641 //      if (get_8bit_zp(_bh) & 0x02) {
642 //          osd_cd_play_audio_track(bcdbin[get_8bit_zp(_al)]);
643 //      } else {
644         /* UInt16 bufaddr = get_16bit_zp(_bx); */
645         int min, sec, fra, con;
646 
647         osd_cd_stop_audio();
648 
649         osd_cd_track_info(bcdbin[get_8bit_zp(_al)], &min, &sec, &fra, &con);
650 
651 				/*
652         put_8bit_addr(bufaddr, min);
653         put_8bit_addr(bufaddr + 1, sec);
654         put_8bit_addr(bufaddr + 2, fra);
655         put_8bit_addr(bufaddr + 3, con);
656 				*/
657 
658         if (get_8bit_zp(_bh) & 0x02)
659           osd_cd_play_audio_track(bcdbin[get_8bit_zp(_al)]);
660 //        else
661 //          osd_cd_stop_audio();
662       }
663       reg_p = ((reg_p & (~(FL_N | FL_T | FL_Z))) | flnz_list[reg_a = 0]);
664       rts();
665       break;
666 
667     case AD_RESET:
668       // do nothing
669       // don't return any value
670 //      reg_p = ((reg_p & (~(FL_N | FL_T | FL_Z))) | flnz_list[reg_a = 0]);
671       rts();
672       break;
673 
674     case AD_TRANS:
675       {
676         UInt32 nb_to_read = get_8bit_zp(_al);
677         UInt16 ADPCM_offset = get_16bit_zp(_bx);
678 
679         pce_cd_sectoraddy = (get_8bit_zp(_cl) << 16) +
680                             (get_8bit_zp(_ch) << 8) +
681                             (get_8bit_zp(_dl));
682 
683         pce_cd_sectoraddy += (get_8bit_addr(0x2274 + 3 * get_8bit_addr(0x2273)) << 16) +
684                              (get_8bit_addr(0x2275 + 3 * get_8bit_addr(0x2273)) << 8) +
685                              (get_8bit_addr(0x2276 + 3 * get_8bit_addr(0x2273)));
686 
687         if (!get_8bit_zp(_dh))
688           io.adpcm_dmaptr = ADPCM_offset;
689         else
690           ADPCM_offset = io.adpcm_dmaptr;
691 
692         while (nb_to_read) {
693           pce_cd_read_sector();
694           memcpy(PCM + ADPCM_offset, cd_read_buffer, 2048);
695           ADPCM_offset += 2048;
696           nb_to_read--;
697         }
698 
699         io.adpcm_dmaptr = ADPCM_offset;
700 
701         reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
702       }
703       rts();
704       break;
705 
706     case AD_READ:
707       {
708         UInt16 ADPCM_buffer = get_16bit_zp(_cx);
709         UChar type = get_8bit_zp(_dh);
710         UInt16 address = get_16bit_zp(_bx);
711         UInt16 size = get_16bit_zp(_ax);
712 
713         switch(type) {
714           case 0: // memory write
715             io.adpcm_rptr = ADPCM_buffer;
716             while (size) {
717               put_8bit_addr(address++, PCM[io.adpcm_rptr++]);
718               size--;
719             }
720             break;
721           case 0xFF: // VRAM write
722             io.adpcm_rptr = ADPCM_buffer;
723 
724             IO_write(0, 0);
725             IO_write(2, (UChar)(address & 0xFF));
726             IO_write(3, (UChar)(address >> 8));
727 
728             IO_write(0, 2);
729 
730             while (size) {
731               IO_write(2, PCM[io.adpcm_rptr++]);
732               size--;
733 
734               if (size) {
735                 IO_write(3, PCM[io.adpcm_rptr++]);
736                 size--;
737               }
738             }
739             break;
740           case 2:
741           case 3:
742           case 4:
743           case 5:
744           case 6:
745             {
746               UChar bank_to_fill = get_8bit_zp(_bl);
747               UInt32 i;
748 
749               while (size >= 2048) {
750                 for (i = 0; i < 2048; i++)
751                   ROMMapW[bank_to_fill][i] = PCM[io.adpcm_rptr++];
752 
753                 bank_to_fill++;
754 
755                 size -= 2048;
756               }
757 
758               for (i = 0; i < size; i++)
759                 ROMMapW[bank_to_fill][i] = PCM[io.adpcm_rptr++];
760 
761             }
762             break;
763           default:
764             Log("Type reading not supported in AD_READ : %x\n", type);
765             exit(-2);
766         }
767         reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
768         rts();
769       }
770       break;
771 
772     case AD_PLAY:
773       io.adpcm_pptr = get_16bit_zp(_bx) << 1;
774 
775       io.adpcm_psize = get_16bit_zp(_ax) << 1;
776 
777       io.adpcm_rate = (UChar)(32 / (16 - (get_8bit_zp(_dh) & 15)));
778 
779       new_adpcm_play = 1;
780 
781       reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
782       rts();
783       break;
784 
785     case AD_STOP:
786       AdpcmFilledBuf = new_adpcm_play = 0;
787       rts();
788       break;
789 
790     case AD_STAT:
791       {
792 
793         if (AdpcmFilledBuf > (io.adpcm_psize / 2))
794           reg_x = 4;
795         else if (AdpcmFilledBuf == 0)
796           reg_x = 1;
797         else
798           reg_x = 0;
799 
800         reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = (UChar)(reg_x == 1 ? 0 : 1)]);
801       }
802       rts();
803       break;
804 
805     case CD_DINFO:
806       switch(get_8bit_zp(_al)) {
807         case CD_DINFO_TRACK:
808           {
809             UInt16 buf_offset = get_16bit_zp(_bx);
810             // usually 0x2256 in system 3.0
811             // _ah contain the number of the track
812 
813             switch(CD_emulation) {
814               case 2:
815               case 3:
816               case 4:
817               case 5:
818                 put_8bit_addr( (UInt16)buf_offset, CD_track[bcdbin[get_8bit_zp(_ah)]].beg_min);
819                 put_8bit_addr( (UInt16)(buf_offset + 1), CD_track[bcdbin[get_8bit_zp(_ah)]].beg_sec);
820                 put_8bit_addr( (UInt16)(buf_offset + 2), CD_track[bcdbin[get_8bit_zp(_ah)]].beg_fra);
821                 put_8bit_addr( (UInt16)(buf_offset + 3), CD_track[bcdbin[get_8bit_zp(_ah)]].type);
822                 break;
823               case 1:
824 		        {
825                   int Min, Sec, Fra, Ctrl;
826 
827                   osd_cd_track_info(bcdbin[get_8bit_zp(_ah)], &Min, &Sec, &Fra, &Ctrl);
828 
829                   put_8bit_addr( (UInt16)(buf_offset), binbcd[Min]);
830                   put_8bit_addr( (UInt16)(buf_offset + 1), binbcd[Sec]);
831                   put_8bit_addr( (UInt16)(buf_offset + 2), binbcd[Fra]);
832                   put_8bit_addr( (UInt16)(buf_offset + 3), (UChar)Ctrl);
833 
834                 }
835 		        break;
836 		    }
837             reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
838           }
839           rts();
840           break;
841 
842         case CD_DINFO_NB_TRACKS:
843           {
844             UInt16 buf_offset = get_16bit_zp(_bx);
845 
846             switch(CD_emulation) {
847               case 2:
848               case 3:
849               case 4:
850                 put_8bit_addr( (UInt16)(buf_offset), binbcd[01]); // Number of first track  (BCD)
851                 put_8bit_addr( (UInt16)(buf_offset + 1), binbcd[nb_max_track]); // Number of last track (BCD)
852                 break;
853               case 1:
854                 {
855                   int first_track, last_track;
856 
857                   osd_cd_nb_tracks(&first_track, &last_track);
858 
859                   put_8bit_addr( (UInt16)(buf_offset), binbcd[first_track]);
860                   put_8bit_addr( (UInt16)(buf_offset + 1), binbcd[last_track]);
861 		        }
862                 break;
863               case 5:
864                 put_8bit_addr( (UInt16)(buf_offset), binbcd[HCD_first_track]);
865                 put_8bit_addr( (UInt16)(buf_offset + 1), binbcd[HCD_last_track]);
866                 break;
867             }
868           }
869           reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
870           rts();
871           break;
872 
873         case CD_DINFO_LENGTH:
874           {
875             UInt16 buf_offset = get_16bit_zp(_bx);
876             int min, sec, frame;
877 
878             osd_cd_length(&min, &sec, &frame);
879 
880             put_8bit_addr( (UInt16)(buf_offset), binbcd[min]);
881             put_8bit_addr( (UInt16)(buf_offset + 1), binbcd[sec]);
882             put_8bit_addr( (UInt16)(buf_offset + 2), binbcd[frame]);
883 
884             reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
885           }
886           rts();
887           break;
888 
889         default:
890           Log("bios.c: Sub function 0X%02X from CD_DINFO not handled\n", get_8bit_zp(_al));
891           reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 1]);
892           rts();
893           break;
894       }
895       break;
896 
897     case CD_PLAY:
898 
899       if (get_8bit_zp(_bh) == 0x80) {
900         int status;
901 
902         // playing a whole track
903 
904         switch(CD_emulation) {
905           case 1:
906             osd_cd_status(&status);
907 
908             if (status == CDROM_AUDIO_PAUSED)
909               osd_cd_resume();
910             else if (status == CDROM_AUDIO_PLAY)
911               osd_cd_stop_audio();
912 
913             osd_cd_play_audio_track(bcdbin[get_8bit_zp(_al)]);
914             break;
915 
916           case 2:
917           case 3:
918           case 4:
919             // ignoring cd playing
920             break;
921           case 5:
922             HCD_play_track(bcdbin[get_8bit_zp(_al)], (char)(get_8bit_zp(_dh) & 1) );
923             break;
924         }
925       } else if (get_8bit_zp(_bh) == 192) { /* resume from pause if paused */
926         int status;
927 
928         osd_cd_status(&status);
929 
930         if (status == CDROM_AUDIO_PAUSED)
931           osd_cd_resume();
932         else
933           osd_cd_play_audio_track(bcdbin[get_8bit_zp(_al)]);
934 
935       } else {
936         int status;
937 
938         int min1 = bcdbin[get_8bit_zp(_al)];
939         int sec1 = bcdbin[get_8bit_zp(_ah)];
940         int fra1 = bcdbin[get_8bit_zp(_bl)];
941 
942         int min2 = bcdbin[get_8bit_zp(_cl)];
943         int sec2 = bcdbin[get_8bit_zp(_ch)];
944         int fra2 = bcdbin[get_8bit_zp(_dl)];
945 
946         switch(CD_emulation) {
947           case 1:
948             osd_cd_status(&status);
949             if ((status == CDROM_AUDIO_PLAY) || (status == CDROM_AUDIO_PAUSED))
950               osd_cd_stop_audio();
951             osd_cd_play_audio_range((UChar)min1, (UChar)sec1, (UChar)fra1, (UChar)min2, (UChar)sec2, (UChar)fra2);
952             break;
953           case 2:
954           case 3:
955           case 4:
956             // ignoring cd playing
957             break;
958           case 5:
959 //            HCD_play_sectors(begin_sect, sect_len, get_8bit_zp(_dh) & 1);
960             break;
961         }
962       }
963       reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
964       rts();
965       break;
966 
967     case EX_JOYSNS:
968       {
969         UChar dummy[5], index;
970 
971         for (index = 0; index < 5; index++) {
972           dummy[index] = get_8bit_addr(0x2228 + index);
973           put_8bit_addr( (UInt16)(0x2232 + index), dummy[index]);
974           put_8bit_addr( (UInt16)(0x2228 + index), io.JOY[index]);
975           put_8bit_addr( (UInt16)(0x222D + index), (io.JOY[index] ^ dummy[index]) & io.JOY[index]);
976         }
977       }
978       /* TODO : check if A <- 0 is needed here */
979       rts();
980       break;
981 
982     case BM_FREE:
983     {
984       SInt16 free_mem;
985 
986       free_mem = (SInt16)(WRAM[4] + (WRAM[5] << 8));
987       free_mem -= WRAM[6] + (WRAM[7] << 8);
988       free_mem -= 0x12; /* maybe the header */
989 
990       if (free_mem < 0)
991         free_mem = 0;
992 
993       put_8bit_zp(_cl, (UChar)(free_mem & 0xFF));
994       put_8bit_zp(_ch, (UChar)(free_mem >> 8));
995 
996       reg_p = ((reg_p & (~(FL_N|FL_T|FL_Z))) | flnz_list[reg_a = 0]);
997       rts();
998       break;
999     }
1000 
1001 #ifdef CD_DEBUG
1002     case MA_MUL8U:
1003     {
1004       UInt16 res;
1005 
1006       res = get_8bit_zp(_ax) * get_8bit_zp(_bx);
1007 
1008       put_8bit_zp(_cl, res & 0xFF);
1009       put_8bit_zp(_ch, res >> 8);
1010 
1011       rts();
1012       break;
1013     }
1014 
1015     case MA_MUL8S:
1016     {
1017       SInt16 res;
1018 
1019       res = get_8bit_zp(_ax) * get_8bit_zp(_bx);
1020 
1021       put_8bit_zp(_cl, res & 0xFF);
1022       put_8bit_zp(_ch, res >> 8);
1023 
1024       rts();
1025       break;
1026     }
1027 
1028     case MA_MUL16U:
1029     {
1030       UInt32 res;
1031 
1032       res = get_16bit_zp(_ax) * get_16bit_zp(_bx);
1033 
1034       put_8bit_zp(_cl, res & 0xFF);
1035       put_8bit_zp(_ch, (res >> 8) & 0xFF);
1036       put_8bit_zp(_dl, (res >> 16) & 0xFF);
1037       put_8bit_zp(_dh, (res >> 24) & 0xFF);
1038 
1039       rts();
1040       break;
1041     }
1042 
1043     case MA_DIV16U:
1044     {
1045       UInt16 res, rem;
1046 
1047       res = get_16bit_zp(_ax) / get_16bit_zp(_bx);
1048       rem = get_16bit_zp(_ax) % get_16bit_zp(_bx);
1049 
1050       put_8bit_zp(_cl, res & 0xFF);
1051       put_8bit_zp(_ch, res >> 8);
1052       put_8bit_zp(_dl, rem & 0xFF);
1053       put_8bit_zp(_dh, res >> 8);
1054 
1055       rts();
1056       break;
1057     }
1058 
1059     case MA_DIV16S:
1060     {
1061       SInt16 res, rem;
1062 
1063       res = get_16bit_zp(_ax) / get_16bit_zp(_bx);
1064       rem = get_16bit_zp(_ax) % get_16bit_zp(_bx);
1065 
1066       put_8bit_zp(_cl, res & 0xFF);
1067       put_8bit_zp(_ch, res >> 8);
1068       put_8bit_zp(_dl, rem & 0xFF);
1069       put_8bit_zp(_dh, rem >> 8);
1070 
1071       rts();
1072       break;
1073     }
1074 
1075     case MA_MUL16S:
1076     {
1077       SInt32 res;
1078 
1079       res = get_16bit_zp(_ax) * get_16bit_zp(_bx);
1080 
1081       put_8bit_zp(_cl, res & 0xFF);
1082       put_8bit_zp(_ch, (res >> 8) & 0xFF);
1083       put_8bit_zp(_dl, (res >> 16) & 0xFF);
1084       put_8bit_zp(_dh, (res >> 24) & 0xFF);
1085 
1086       rts();
1087       break;
1088     }
1089 #endif
1090 
1091     default:
1092       /* unhandled function, restoring initial behaviour */
1093       put_8bit_addr( (UInt16)(reg_pc), CDBIOS_replace[imm_operand( (UInt16)(reg_pc + 1))][0]);
1094       put_8bit_addr( (UInt16)(reg_pc + 1), CDBIOS_replace[imm_operand( (UInt16)(reg_pc + 1))][1]);
1095   }
1096 }
1097