First Commit of my working state
[simh.git] / AltairZ80 / s100_mdriveh.c
1 /*************************************************************************
2 * *
3 * $Id: s100_mdriveh.c 1773 2008-01-11 05:46:19Z hharte $ *
4 * *
5 * Copyright (c) 2007-2008 Howard M. Harte. *
6 * http://www.hartetec.com *
7 * *
8 * Permission is hereby granted, free of charge, to any person obtaining *
9 * a copy of this software and associated documentation files (the *
10 * "Software"), to deal in the Software without restriction, including *
11 * without limitation the rights to use, copy, modify, merge, publish, *
12 * distribute, sublicense, and/or sell copies of the Software, and to *
13 * permit persons to whom the Software is furnished to do so, subject to *
14 * the following conditions: *
15 * *
16 * The above copyright notice and this permission notice shall be *
17 * included in all copies or substantial portions of the Software. *
18 * *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *
22 * NONINFRINGEMENT. IN NO EVENT SHALL HOWARD M. HARTE BE LIABLE FOR ANY *
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, *
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE *
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
26 * *
27 * Except as contained in this notice, the name of Howard M. Harte shall *
28 * not be used in advertising or otherwise to promote the sale, use or *
29 * other dealings in this Software without prior written authorization *
30 * Howard M. Harte. *
31 * *
32 * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. *
33 * *
34 * Module Description: *
35 * CompuPro M-DRIVE/H Controller module for SIMH. *
36 * *
37 * Environment: *
38 * User mode only *
39 * *
40 *************************************************************************/
41
42 /*#define DBG_MSG */
43
44 #include "altairz80_defs.h"
45
46 #if defined (_WIN32)
47 #include <windows.h>
48 #endif
49
50 #ifdef DBG_MSG
51 #define DBG_PRINT(args) printf args
52 #else
53 #define DBG_PRINT(args)
54 #endif
55
56 #define SEEK_MSG 0x01
57 #define RD_DATA_MSG 0x08
58 #define WR_DATA_MSG 0x10
59 #define VERBOSE_MSG 0x80
60
61 #define MDRIVEH_MAX_DRIVES 8
62
63 typedef struct {
64 PNP_INFO pnp; /* Plug and Play */
65 uint32 dma_addr; /* DMA Transfer Address */
66 UNIT uptr[MDRIVEH_MAX_DRIVES];
67 uint8 *storage[MDRIVEH_MAX_DRIVES];
68 } MDRIVEH_INFO;
69
70 static MDRIVEH_INFO mdriveh_info_data = { { 0x0, 0, 0xC6, 2 } };
71 static MDRIVEH_INFO *mdriveh_info = &mdriveh_info_data;
72
73 extern uint32 PCX;
74 extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
75 extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
76 extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
77 int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
78
79 extern REG *sim_PC;
80
81 #define UNIT_V_MDRIVEH_WLK (UNIT_V_UF + 0) /* write locked */
82 #define UNIT_MDRIVEH_WLK (1 << UNIT_V_MDRIVEH_WLK)
83 #define UNIT_V_MDRIVEH_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
84 #define UNIT_MDRIVEH_VERBOSE (1 << UNIT_V_MDRIVEH_VERBOSE)
85 #define MDRIVEH_CAPACITY (512 * 1000) /* Default M-DRIVE/H Capacity */
86 #define MDRIVEH_NONE 0
87
88 static t_stat mdriveh_reset(DEVICE *mdriveh_dev);
89 static int32 mdrivehdev(const int32 port, const int32 io, const int32 data);
90 static uint8 MDRIVEH_Read(const uint32 Addr);
91 static uint8 MDRIVEH_Write(const uint32 Addr, uint8 cData);
92
93 static int32 trace_level = 0; /* Disable all tracing by default */
94
95 static UNIT mdriveh_unit[] = {
96 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ROABLE, MDRIVEH_CAPACITY) },
97 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) },
98 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) },
99 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) },
100 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) },
101 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) },
102 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) },
103 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) }
104 };
105
106 static REG mdriveh_reg[] = {
107 { HRDATA (TRACELEVEL, trace_level, 16), },
108 { NULL }
109 };
110
111 static MTAB mdriveh_mod[] = {
112 { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
113 { UNIT_MDRIVEH_WLK, 0, "WRTENB", "WRTENB", NULL },
114 { UNIT_MDRIVEH_WLK, UNIT_MDRIVEH_WLK, "WRTLCK", "WRTLCK", NULL },
115 /* quiet, no warning messages */
116 { UNIT_MDRIVEH_VERBOSE, 0, "QUIET", "QUIET", NULL },
117 /* verbose, show warning messages */
118 { UNIT_MDRIVEH_VERBOSE, UNIT_MDRIVEH_VERBOSE, "VERBOSE", "VERBOSE", NULL },
119 { 0 }
120 };
121
122 DEVICE mdriveh_dev = {
123 "MDRIVEH", mdriveh_unit, mdriveh_reg, mdriveh_mod,
124 MDRIVEH_MAX_DRIVES, 10, 31, 1, MDRIVEH_MAX_DRIVES, MDRIVEH_MAX_DRIVES,
125 NULL, NULL, &mdriveh_reset,
126 NULL, NULL, NULL,
127 &mdriveh_info_data, (DEV_DISABLE | DEV_DIS), 0,
128 NULL, NULL, NULL
129 };
130
131
132 /* Reset routine */
133 static t_stat mdriveh_reset(DEVICE *dptr)
134 {
135 uint8 i;
136 PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;
137
138 if(dptr->flags & DEV_DIS) { /* Disconnect ROM and I/O Ports */
139 sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &mdrivehdev, TRUE);
140 } else {
141 /* Connect MDRIVEH at base address */
142 if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &mdrivehdev, FALSE) != 0) {
143 printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base);
144 return SCPE_ARG;
145 }
146 }
147
148 for(i=0; i<MDRIVEH_MAX_DRIVES; i++) {
149 mdriveh_info->uptr[i] = dptr->units[i];
150 if((dptr->flags & DEV_DIS) || (dptr->units[i].flags & UNIT_DIS)) {
151 if (dptr->units[i].flags & UNIT_MDRIVEH_VERBOSE)
152 printf("MDRIVEH: Unit %d disabled", i);
153 if(mdriveh_info->storage[i] != NULL) {
154 if (dptr->units[i].flags & UNIT_MDRIVEH_VERBOSE)
155 printf(", freed 0x%p\n", mdriveh_info->storage[i]);
156 free(mdriveh_info->storage[i]);
157 mdriveh_info->storage[i] = NULL;
158 } else if (dptr->units[i].flags & UNIT_MDRIVEH_VERBOSE) {
159 printf(".\n");
160 }
161 } else {
162 if(mdriveh_info->storage[i] == NULL) {
163 mdriveh_info->storage[i] = calloc(1, 524288);
164 }
165 if (dptr->units[i].flags & UNIT_MDRIVEH_VERBOSE)
166 printf("MDRIVEH: Unit %d enabled, 512K at 0x%p\n", i, mdriveh_info->storage[i]);
167 }
168 }
169
170 return SCPE_OK;
171 }
172
173 static int32 mdrivehdev(const int32 port, const int32 io, const int32 data)
174 {
175 DBG_PRINT(("MDRIVEH: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port));
176 if(io) {
177 MDRIVEH_Write(port, data);
178 return 0;
179 } else {
180 return(MDRIVEH_Read(port));
181 }
182 }
183
184 #define MDRIVEH_DATA 0 /* R=Drive Status Register / W=DMA Address Register */
185 #define MDRIVEH_ADDR 1 /* R=Unused / W=Motor Control Register */
186
187 static uint8 MDRIVEH_Read(const uint32 Addr)
188 {
189 uint8 cData;
190 uint8 unit;
191 uint32 offset;
192
193 cData = 0xFF; /* default is High-Z Data */
194
195 switch(Addr & 0x1) {
196 case MDRIVEH_ADDR:
197 TRACE_PRINT(VERBOSE_MSG, ("MDRIVEH: " ADDRESS_FORMAT " RD Addr = 0x%02x" NLP,
198 PCX, cData));
199 break;
200 case MDRIVEH_DATA:
201 unit = (mdriveh_info->dma_addr & 0x380000) >> 19;
202 offset = mdriveh_info->dma_addr & 0x7FFFF;
203
204 if(mdriveh_info->storage[unit] != NULL) {
205 cData = mdriveh_info->storage[unit][offset];
206 }
207
208 TRACE_PRINT(RD_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " RD Data [%x:%05x] = 0x%02x" NLP,
209 PCX, unit, offset, cData));
210
211 /* Increment M-DRIVE/H Data Address */
212 mdriveh_info->dma_addr++;
213 mdriveh_info->dma_addr &= 0x3FFFFF;
214 break;
215 }
216
217 return (cData);
218 }
219
220 static uint8 MDRIVEH_Write(const uint32 Addr, uint8 cData)
221 {
222 uint8 result = 0;
223 uint8 unit;
224 uint32 offset;
225
226 switch(Addr & 0x1) {
227 case MDRIVEH_ADDR:
228 mdriveh_info->dma_addr <<= 8;
229 mdriveh_info->dma_addr &= 0x003FFF00;
230 mdriveh_info->dma_addr |= cData;
231 TRACE_PRINT(SEEK_MSG, ("MDRIVEH: " ADDRESS_FORMAT " DMA Address=%06x" NLP,
232 PCX, mdriveh_info->dma_addr));
233 break;
234 case MDRIVEH_DATA:
235 unit = (mdriveh_info->dma_addr & 0x380000) >> 19;
236 offset = mdriveh_info->dma_addr & 0x7FFFF;
237
238 if(mdriveh_info->storage[unit] != NULL) {
239 if(mdriveh_info->uptr[unit].flags & UNIT_MDRIVEH_WLK) {
240 TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit Write Locked" NLP,
241 PCX, unit, offset));
242 } else {
243 TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = 0x%02x" NLP,
244 PCX, unit, offset, cData));
245 mdriveh_info->storage[unit][offset] = cData;
246 }
247 } else {
248 TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit OFFLINE" NLP,
249 PCX, unit, offset));
250 }
251
252 /* Increment M-DRIVE/H Data Address */
253 mdriveh_info->dma_addr++;
254 mdriveh_info->dma_addr &= 0x3FFFFF;
255 break;
256 }
257
258 return (result);
259 }
260