-
Notifications
You must be signed in to change notification settings - Fork 4
/
dma.c
226 lines (192 loc) · 4.49 KB
/
dma.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
220
221
222
223
224
225
#include "common.h"
#include "cpu.h"
#include "mmu.h"
#include "fdc.h"
#include "hdc.h"
#include "state.h"
#include "diag.h"
HANDLE_DIAGNOSTICS(dma);
#define DMABASE 0xff8600
#define DMASIZE 16
#define DMA_READ 0
#define DMA_WRITE 1
#define STATUS_ERROR 0
#define STATUS_NO_ERROR 1
#define STATUS_SEC_ZERO 0
#define STATUS_SEC_NOT_ZERO 2
#define STATUS_NO_FDC_DRQ 0
#define STATUS_FDC_DRQ 4
static BYTE dma_addr_low = 0;
static BYTE dma_addr_med = 0;
static BYTE dma_addr_high = 0;
static WORD dma_mode = 0;
static BYTE dma_sector_reg = 0;
static BYTE dma_status = 0;
static int dma_direction = DMA_READ;
#define MODE_FDCS ((~dma_mode)&(1<<3))
#define MODE_HDCS (dma_mode&(1<<3))
#define MODE_FDC ((~dma_mode)&(1<<4))
#define MODE_SEC (dma_mode&(1<<4))
#define MODE_HDRQ ((~dma_mode)&(1<<7))
#define MODE_FDRQ (dma_mode&(1<<7))
#define MODE_READ ((~dma_mode)&(1<<8))
#define MODE_WRITE (dma_mode&(1<<8))
#define MODE_FDC_REG (dma_mode&0x6)
#define MODE_FDC_STATUS 0
#define MODE_FDC_CONTROL 0
#define MODE_FDC_TRACK 0
#define MODE_FDC_SECTOR 0
#define MODE_HDC_CMDDATA (dma_mode&(1<<1))
#define FDC_REG_CONTROL 0
#define FDC_REG_SECTOR 2
LONG dma_address()
{
return (dma_addr_high<<16)|(dma_addr_med<<8)|dma_addr_low;
}
BYTE dma_sector_count()
{
return dma_sector_reg;
}
static void dma_set_address(LONG addr)
{
dma_addr_high = (addr>>16)&0xff;
dma_addr_med = (addr>>8)&0xff;
dma_addr_low = (addr)&0xff;
}
void dma_inc_address(LONG increment)
{
dma_set_address(dma_address() + increment);
}
void dma_set_error()
{
dma_status &= ~1;
}
void dma_clr_error()
{
dma_status |= 1;
}
static void dma_reset(int new_direction)
{
dma_direction = new_direction;
dma_sector_reg = 0;
dma_status = STATUS_NO_ERROR | STATUS_SEC_ZERO | STATUS_NO_FDC_DRQ;
}
static void dma_handle_mode()
{
if(dma_direction == DMA_READ && MODE_WRITE) {
TRACE("dma_reset: WRITE");
dma_reset(DMA_WRITE);
}
if(dma_direction == DMA_WRITE && MODE_READ) {
TRACE("dma_reset: READ");
dma_reset(DMA_READ);
}
}
BYTE dma_read_byte(LONG addr)
{
switch(addr) {
case 0xff8609:
return dma_addr_high;
case 0xff860b:
return dma_addr_med;
case 0xff860d:
return dma_addr_low;
}
return 0xff;
}
WORD dma_read_word(LONG addr)
{
WORD tmp;
TRACE("ReadWord: %06x", addr);
switch(addr) {
case 0xff8604:
if(MODE_SEC) {
return dma_sector_reg;
} else {
if(!mmu_print_state) {
if(MODE_HDCS) {
tmp = hdc_get_status();
DEBUG("HD Status: %02x", tmp);
return tmp;
} else {
tmp = fdc_get_register(MODE_FDC_REG>>1)|0xff00;
TRACE("Calling fdc_get_register(%d) == %04x", MODE_FDC_REG>>1, tmp);
return tmp;
}
}
return 0;
}
case 0xff8606:
return dma_status;
}
return 0xffff;
}
void dma_write_byte(LONG addr, BYTE data)
{
TRACE("WriteByte: %06x %02x", addr, data);
switch(addr) {
case 0xff8609:
dma_addr_high = data&0x3f; /* Top 2 bits unused */
TRACE("(HIGH) DMA address now == %06x", dma_address());
break;
case 0xff860b:
dma_addr_med = data;
TRACE("(MED) DMA address now == %06x", dma_address());
break;
case 0xff860d:
dma_addr_low = data;
TRACE("(LOW) DMA address now == %06x", dma_address());
break;
}
}
void dma_write_word(LONG addr, WORD data)
{
TRACE("WriteWord: %06x %04x", addr, data);
switch(addr) {
case 0xff8604:
if(MODE_SEC) {
TRACE("Setting dma_sector_reg == %d", data);
dma_sector_reg = data;
} else {
if(MODE_HDCS) {
if(MODE_HDC_CMDDATA) {
hdc_add_cmddata(data);
} else {
hdc_set_cmd(data);
}
} else {
TRACE("Calling fdc_set_register(%d, %02x)", MODE_FDC_REG>>1, data);
fdc_set_register(MODE_FDC_REG>>1, data);
}
}
break;
case 0xff8606:
dma_mode = data;
TRACE("DMAMode == %04x", dma_mode);
dma_handle_mode();
}
}
static int dma_state_collect(struct mmu_state *state)
{
state->size = 0;
return STATE_VALID;
}
static void dma_state_restore(struct mmu_state *state)
{
}
void dma_init()
{
struct mmu *dma;
dma = mmu_create("DMA0", "DMA");
dma->start = DMABASE;
dma->size = DMASIZE;
dma->read_byte = dma_read_byte;
dma->read_word = dma_read_word;
dma->write_byte = dma_write_byte;
dma->write_word = dma_write_word;
dma->state_collect = dma_state_collect;
dma->state_restore = dma_state_restore;
dma->diagnostics = dma_diagnostics;
dma_reset(DMA_READ);
mmu_register(dma);
}