Remove circular dependencies between libs, use callback function pointers instead
[mercenary-reloaded.git] / src / libdisk / disk.c
1 /* disk access emulation
2  *
3  * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
4  * All Rights Reserved
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include "disk.h"
24
25 //#define DEBUG_DISK
26
27 #define CIAAPRA         0xbfe000
28 #define CIABPRB         0xbfd100
29 #define DSKPTH          0xdff020
30 #define DSKPTL          0xdff022
31 #define DSKLEN          0xdff024
32 #define INTREQR         0xdff01e
33
34 static uint16_t ciabprb = 0xffff;
35 static int track = 0;
36 static uint32_t dskptr = 0;
37 static uint16_t dsklen = 0;
38 static void (*disk_read)(int track, int side, uint32_t data, uint16_t length) = NULL;
39 static void (*disk_write)(int track, int side, uint32_t data, uint16_t length) = NULL;
40
41 /* NOTE: all CIA access is WORD access, so we use bits 8..15 for CIA-B */
42
43 void disk_init(void (*_disk_read)(int track, int side, uint32_t data, uint16_t length), void (*_disk_write)(int track, int side, uint32_t data, uint16_t length))
44 {
45         disk_read = _disk_read;
46         disk_write = _disk_write;
47 }
48
49 uint16_t emulate_disk_read(uint32_t address)
50 {
51         uint16_t value = 0xffff;
52
53         switch (address) {
54         case CIAAPRA:
55                 /* /RDY (bit 5) is always 0, so disk is ready! */
56                 value &= 0xffdf;
57                 if (track == 0)
58                         value &= 0xffef;
59                 break;
60         case CIABPRB:
61                 /* return current bits from CIA-A PRB */
62                 value &= ciabprb;
63                 break;
64         case INTREQR:
65                 /* if disk dma is not on, don't process read/write */
66                 if (!(dsklen & 0x8000))
67                         break;
68
69                 if ((dsklen & 0x4000))
70                         disk_write(track, (ciabprb >> 10) & 1, dskptr, (dsklen & 0x3fff) << 1);
71                 else
72                         disk_read(track, (ciabprb >> 10) & 1, dskptr, (dsklen & 0x3fff) << 1);
73 #ifdef DEBUG_DISK
74                 printf("read from INTREQR: game asks for finished read/write\n");
75 #endif
76                 /* keep bit 2 set, so it indicated finished read/write */
77                 value &= 0xffff;
78                 break;
79         }
80
81         return value;
82 }
83
84 void emulate_disk_write(uint32_t address, uint16_t value)
85 {
86         switch (address) {
87         case CIABPRB:
88 #ifdef DEBUG_DISK
89                 printf("selected side %d\n", (value >> 10) & 1);
90 #endif
91                 if (((ciabprb >> 8) & 1) && !((value >> 8) & 1)) {
92                         if (!((value >> 9) & 1)) {
93                                 track++;
94                                 if (track > 84)
95                                         track = 84;
96 #ifdef DEBUG_DISK
97                                 printf("step forward to track %d\n", track);
98 #endif
99                         } else {
100                                 track--;
101                                 if (track < 0)
102                                         track = 0;
103 #ifdef DEBUG_DISK
104                                 printf("step backwards to track %d\n", track);
105 #endif
106                         }
107                 }
108                 ciabprb = value;
109                 break;
110         case DSKPTH:
111                 dskptr = (dskptr & 0x0000ffff) | (value << 16);
112                 break;
113         case DSKPTL:
114                 dskptr = (dskptr & 0xffff0000) | value;
115 #ifdef DEBUG_DISK
116                 printf("disk pointer set to 0x%06x\n", dskptr);
117 #endif
118                 break;
119         case DSKLEN:
120                 dsklen = value;
121 #ifdef DEBUG_DISK
122                 printf("DSKLEN: disk length set to 0x%04x, mode set to '%s', dma set to '%s'\n", dsklen & 0x3fff, (dsklen & 0x4000) ? "write" : "read", (dsklen & 0x8000) ? "on" : "off");
123 #endif
124                 break;
125         }
126 }
127
128 int get_disk_track(void)
129 {
130 #ifdef DEBUG_DISK
131         printf("disk drive is at track %d\n", track);
132 #endif
133         return track;
134 }
135