-
-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathcdc.c
219 lines (174 loc) · 5.9 KB
/
cdc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#include "cdc.h"
#include "log.h"
#define CDC_END(CDC) CC_COUNT_OF((CDC)->buffered_sectors[0])
static cc_u8f To2DigitBCD(const cc_u8f value)
{
const cc_u8f lower_digit = value % 10;
const cc_u8f upper_digit = (value / 10) % 10;
return (upper_digit << 4) | (lower_digit << 0);
}
static void GetCDSectorHeaderBytes(const CDC* const cdc, cc_u8l* const buffer)
{
buffer[0] = To2DigitBCD(cdc->current_sector / (75 * 60));
buffer[1] = To2DigitBCD((cdc->current_sector / 75) % 60);
buffer[2] = To2DigitBCD(cdc->current_sector % 75);
/* TODO: Is this byte correct? */
buffer[3] = 0x01;
}
/* TODO: De-duplicate this 'bytes to integer' logic. */
static cc_u16f BytesToU16(const cc_u8l* const bytes)
{
return (cc_u16f)bytes[0] << 8 | bytes[1];
}
static cc_u32f U16sToU32(const cc_u16l* const u16s)
{
return (cc_u32f)u16s[0] << 16 | u16s[1];
}
static cc_bool EndOfDataTransfer(CDC* const cdc)
{
return cdc->host_data_word_index >= CDC_END(cdc) - 1;
}
static cc_bool DataSetReady(CDC* const cdc)
{
return cdc->host_data_word_index != CDC_END(cdc);
}
static void RefillSectorBuffer(CDC* const cdc, const CDC_SectorReadCallback cd_sector_read, const void* const user_data)
{
if (!cdc->cdc_reading)
return;
/* TODO: Stop reading sectors instantaneously! */
while (cdc->buffered_sectors_total != CC_COUNT_OF(cdc->buffered_sectors))
{
cc_u8l header_bytes[4];
cc_u16l* const sector_words = cdc->buffered_sectors[cdc->buffered_sectors_write_index];
GetCDSectorHeaderBytes(cdc, header_bytes);
sector_words[0] = BytesToU16(&header_bytes[0]);
sector_words[1] = BytesToU16(&header_bytes[2]);
cd_sector_read((void*)user_data, §or_words[2]);
++cdc->current_sector;
++cdc->buffered_sectors_total;
++cdc->buffered_sectors_write_index;
if (cdc->buffered_sectors_write_index == CC_COUNT_OF(cdc->buffered_sectors))
cdc->buffered_sectors_write_index = 0;
if (cdc->sectors_remaining != 0 && --cdc->sectors_remaining == 0)
{
cdc->cdc_reading = cc_false;
break;
}
}
}
void CDC_Initialise(CDC* const cdc)
{
cdc->current_sector = 0;
cdc->sectors_remaining = 0;
cdc->host_data_word_index = CDC_END(cdc);
cdc->dma_address = 0;
cdc->host_data_buffered_sector_index = 0;
cdc->buffered_sectors_read_index = 0;
cdc->buffered_sectors_write_index = 0;
cdc->buffered_sectors_total = 0;
cdc->device_destination = CDC_DESTINATION_SUB_CPU_READ;
cdc->host_data_target_sub_cpu = cc_false;
cdc->cdc_reading = cc_false;
cdc->host_data_bound = cc_false;
}
void CDC_Start(CDC* const cdc, const CDC_SectorReadCallback callback, const void* const user_data)
{
cdc->cdc_reading = cc_true;
RefillSectorBuffer(cdc, callback, user_data);
}
void CDC_Stop(CDC* const cdc)
{
cdc->cdc_reading = cc_false;
}
cc_bool CDC_Stat(CDC* const cdc, const CDC_SectorReadCallback callback, const void* const user_data)
{
RefillSectorBuffer(cdc, callback, user_data);
return cdc->buffered_sectors_total != 0;
}
cc_bool CDC_Read(CDC* const cdc, const CDC_SectorReadCallback callback, const void* const user_data, cc_u32l* const header)
{
RefillSectorBuffer(cdc, callback, user_data);
if (cdc->buffered_sectors_total == 0)
return cc_false;
if (cdc->host_data_bound)
return cc_false;
/* TODO: Is this thing actually latched during 'CDCRead', or is it when the value is first written? */
switch (cdc->device_destination)
{
case CDC_DESTINATION_MAIN_CPU_READ:
cdc->host_data_target_sub_cpu = cc_false;
break;
case CDC_DESTINATION_SUB_CPU_READ:
case CDC_DESTINATION_PCM_RAM:
case CDC_DESTINATION_PRG_RAM:
case CDC_DESTINATION_WORD_RAM:
cdc->host_data_target_sub_cpu = cc_true;
break;
default:
LogMessage("CDCREAD called with invalid device destination (0x%" CC_PRIXLEAST8 ")", cdc->device_destination);
return cc_false;
}
cdc->host_data_buffered_sector_index = cdc->buffered_sectors_read_index;
cdc->host_data_word_index = 0;
*header = U16sToU32(cdc->buffered_sectors[cdc->host_data_buffered_sector_index]);
cdc->host_data_bound = cc_true;
return cc_true;
}
cc_u16f CDC_HostData(CDC* const cdc, const cc_bool is_sub_cpu)
{
cc_u16f value;
if (is_sub_cpu != cdc->host_data_target_sub_cpu)
{
/* TODO: What is actually returned when this is not the target CPU? */
value = 0;
}
else if (!cdc->host_data_bound)
{
/* TODO: What is actually returned in this case? */
value = 0;
}
else if (!DataSetReady(cdc))
{
/* According to Genesis Plus GX, this will repeat the final value indefinitely. */
/* TODO: Verify this on actual hardware. */
value = cdc->buffered_sectors[cdc->host_data_buffered_sector_index][cdc->host_data_word_index - 1];
}
else
{
value = cdc->buffered_sectors[cdc->host_data_buffered_sector_index][cdc->host_data_word_index++];
}
return value;
}
void CDC_Ack(CDC* const cdc)
{
if (!cdc->host_data_bound)
return;
cdc->host_data_bound = cc_false;
/* Advance the read index. */
--cdc->buffered_sectors_total;
++cdc->buffered_sectors_read_index;
if (cdc->buffered_sectors_read_index == CC_COUNT_OF(cdc->buffered_sectors))
cdc->buffered_sectors_read_index = 0;
}
void CDC_Seek(CDC* const cdc, const CDC_SectorReadCallback callback, const void* const user_data, const cc_u32f sector, const cc_u32f total_sectors)
{
cdc->current_sector = sector;
cdc->sectors_remaining = total_sectors;
RefillSectorBuffer(cdc, callback, user_data);
}
cc_u16f CDC_Mode(CDC* const cdc, const cc_bool is_sub_cpu)
{
if (is_sub_cpu != cdc->host_data_target_sub_cpu)
return 0x8000;
return EndOfDataTransfer(cdc) << 15 | DataSetReady(cdc) << 14;
}
void CDC_SetDeviceDestination(CDC* const cdc, const CDC_DeviceDestination device_destination)
{
cdc->device_destination = device_destination;
cdc->dma_address = 0;
}
void CDC_SetDMAAddress(CDC* const cdc, const cc_u16f dma_address)
{
cdc->dma_address = dma_address;
}