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