First Commit of my working state
[simh.git] / AltairZ80 / flashwriter2.c
1 /*************************************************************************
2 * *
3 * $Id: flashwriter2.c 1753 2008-01-02 16:36:47Z 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 * Vector Graphic, Inc. FlashWriter II 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 #else
49 #include "sim_sock.h"
50 #endif
51
52 #include "sim_tmxr.h"
53
54 #ifdef DBG_MSG
55 #define DBG_PRINT(args) printf args
56 #else
57 #define DBG_PRINT(args)
58 #endif
59
60
61 extern int32 sio0s(const int32 port, const int32 io, const int32 data);
62 extern int32 sio0d(const int32 port, const int32 io, const int32 data);
63 extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
64 int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
65
66 static char ansibuf[10];
67
68 #define FW2_MAX_BOARDS 4
69 #define UNIT_V_FW2_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
70 #define UNIT_FW2_VERBOSE (1 << UNIT_V_FW2_VERBOSE)
71 #define FW2_CAPACITY (2048) /* FlashWriter II Memory Size */
72
73 typedef struct {
74 UNIT *uptr; /* UNIT pointer */
75 uint8 cur_FL_Row; /* Current Flashwriter Row */
76 uint8 cur_FL_Col; /* Current Flashwriter Column */
77 uint8 FL_Row;
78 uint8 FL_Col;
79 uint8 reversevideo; /* Flag set if reverse video is currently on */
80 uint8 M[FW2_CAPACITY]; /* FlashWriter 2K Video Memory */
81 } FW2_INFO;
82
83 static FW2_INFO *fw2_info[4];
84 static uint8 port_map[4] = { 0x11, 0x15, 0x17, 0x19 };
85
86 static int32 fw2dev(const int32 Addr, const int32 rw, const int32 data);
87 static t_stat fw2_reset(DEVICE *dptr);
88 static t_stat fw2_attach(UNIT *uptr, char *cptr);
89 static t_stat fw2_detach(UNIT *uptr);
90 static uint8 FW2_Read(const uint32 Addr);
91 static uint8 FW2_Write(const uint32 Addr, uint8 cData);
92 static t_stat get_base_address(char *cptr, uint32 *baseaddr);
93
94 static int32 FWIITrace = FALSE;
95
96 static UNIT fw2_unit[] = {
97 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, FW2_CAPACITY) },
98 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, FW2_CAPACITY) },
99 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, FW2_CAPACITY) },
100 { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, FW2_CAPACITY) }
101 };
102
103 static REG fw2_reg[] = {
104 { DRDATA (FWIITRACE, FWIITrace, 8), },
105 { NULL }
106 };
107
108 static MTAB fw2_mod[] = {
109 /* quiet, no warning messages */
110 { UNIT_FW2_VERBOSE, 0, "QUIET", "QUIET", NULL },
111 /* verbose, show warning messages */
112 { UNIT_FW2_VERBOSE, UNIT_FW2_VERBOSE, "VERBOSE", "VERBOSE", NULL },
113 { 0 }
114 };
115
116 DEVICE fw2_dev = {
117 "FWII", fw2_unit, fw2_reg, fw2_mod,
118 FW2_MAX_BOARDS, 10, 31, 1, FW2_MAX_BOARDS, FW2_MAX_BOARDS,
119 NULL, NULL, &fw2_reset,
120 NULL, &fw2_attach, &fw2_detach,
121 NULL, 0, 0,
122 NULL, NULL, NULL
123 };
124
125 /* Reset routine */
126 static t_stat fw2_reset(DEVICE *dptr)
127 {
128 return SCPE_OK;
129 }
130
131 /* Attach routine */
132 static t_stat fw2_attach(UNIT *uptr, char *cptr)
133 {
134 t_stat r;
135 unsigned int i = 0;
136 uint32 baseaddr;
137 char *tptr;
138
139 r = get_base_address(cptr, &baseaddr);
140 if(r != SCPE_OK) /* error?*/
141 return r;
142
143 DBG_PRINT(("%s\n", __FUNCTION__));
144
145 for(i = 0; i < FW2_MAX_BOARDS; i++) {
146 if(&fw2_dev.units[i] == uptr) {
147 if(uptr->flags & UNIT_FW2_VERBOSE) {
148 printf("Attaching unit %d\n at %04x", i, baseaddr);
149 }
150 break;
151 }
152 }
153
154 fw2_info[i] = calloc(1, sizeof(FW2_INFO));
155 fw2_info[i]->uptr = uptr;
156 fw2_info[i]->uptr->u3 = baseaddr;
157
158 if(sim_map_resource(baseaddr, FW2_CAPACITY, RESOURCE_TYPE_MEMORY, &fw2dev, FALSE) != 0) {
159 printf("%s: error mapping MEM resource at 0x%04x\n", __FUNCTION__, baseaddr);
160 return SCPE_ARG;
161 }
162
163 if(sim_map_resource(0x00, 1, RESOURCE_TYPE_IO, &sio0s, FALSE) != 0) {
164 printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, 0x00);
165 return SCPE_ARG;
166 }
167
168 if(sim_map_resource(0x01, 1, RESOURCE_TYPE_IO, &sio0d, FALSE) != 0) {
169 printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, 0x01);
170 return SCPE_ARG;
171 }
172
173 tptr = (char *) malloc (strlen (cptr) + 3); /* get string buf */
174 if (tptr == NULL) return SCPE_MEM; /* no more mem? */
175 sprintf(tptr, "0x%04x", baseaddr); /* copy base address */
176 uptr->filename = tptr; /* save */
177 uptr->flags = uptr->flags | UNIT_ATT;
178 return SCPE_OK;
179 }
180
181
182 /* Detach routine */
183 static t_stat fw2_detach(UNIT *uptr)
184 {
185 uint8 i;
186
187 DBG_PRINT(("%s\n", __FUNCTION__));
188
189 for(i = 0; i < FW2_MAX_BOARDS; i++) {
190 if(&fw2_dev.units[i] == uptr) {
191 break;
192 }
193 }
194
195 if (i >= FW2_MAX_BOARDS) return SCPE_ARG;
196
197 /* Disconnect FlashWriter2: unmap memory and I/O resources */
198 sim_map_resource(fw2_info[i]->uptr->u3, FW2_CAPACITY, RESOURCE_TYPE_MEMORY, &fw2dev, TRUE);
199 sim_map_resource(0x00, 1, RESOURCE_TYPE_IO, &sio0s, TRUE);
200 sim_map_resource(0x01, 1, RESOURCE_TYPE_IO, &sio0d, TRUE);
201
202 if(fw2_info[i]) {
203 free(fw2_info[1]);
204 }
205
206 free (uptr->filename); /* free base address string */
207 uptr->filename = NULL;
208 uptr->flags = uptr->flags & ~UNIT_ATT; /* not attached */
209 return SCPE_OK;
210 }
211
212 static t_stat get_base_address(char *cptr, uint32 *baseaddr) {
213 uint32 b;
214 sscanf(cptr, "%x", &b);
215 if(b & (FW2_CAPACITY-1)) {
216 printf("FWII must be on a %d-byte boundary.\n", FW2_CAPACITY);
217 return SCPE_ARG;
218 }
219 *baseaddr = b & ~(FW2_CAPACITY-1);
220 return SCPE_OK;
221 }
222
223 extern int32 getBankSelect(void);
224
225 /* This is the main entry point into the Flashwriter2 emulation. */
226 static int32 fw2dev(const int32 Addr, const int32 rw, const int32 data)
227 {
228 int32 bank = getBankSelect();
229 if(bank == 0) {
230 if(rw == 0) { /* Read */
231 return(FW2_Read(Addr));
232 } else { /* Write */
233 return(FW2_Write(Addr, data));
234 }
235 } else return 0xff;
236 }
237
238
239 static uint8 FW2_Write(const uint32 Addr, uint8 Value)
240 {
241 FW2_INFO *fw2 = NULL;
242 uint8 FL_Row;
243 uint8 FL_Col;
244 uint32 baseaddr = 0;
245 uint8 i;
246 uint8 outchar;
247 uint8 port;
248
249 for(i = 0; i < FW2_MAX_BOARDS; i++) {
250 if(fw2_info[i] != NULL) {
251 baseaddr = fw2_info[i]->uptr->u3;
252 if((Addr >= baseaddr) && (Addr < (baseaddr + FW2_CAPACITY))) {
253 break;
254 }
255 }
256 }
257
258 if(i == FW2_MAX_BOARDS) {
259 return 0;
260 }
261
262 fw2 = fw2_info[i];
263 port = port_map[i];
264
265 fw2->M[Addr - baseaddr] = Value;
266
267 /* Only print if it is in the visible part of the Flashwriter memory */
268 if((Addr >= baseaddr) && (Addr < (baseaddr + (80 * 24)))) {
269 FL_Col = ((Addr-baseaddr) % 80) + 1;
270 FL_Row = ((Addr-baseaddr) / 80) + 1;
271
272 if(Value & 0x80) { /* reverse video */
273 if(fw2->reversevideo == 0) {
274 fw2->reversevideo = 1;
275 sprintf(ansibuf, "\x1b[07m");
276 for(i=0;i<strlen(ansibuf);i++) {
277 sio0d(port, 1, ansibuf[i]);
278 }
279 }
280 } else {
281 if(fw2->reversevideo == 1) {
282 fw2->reversevideo = 0;
283 sprintf(ansibuf, "\x1b[00m");
284 for(i=0;i<strlen(ansibuf);i++) {
285 sio0d(port, 1, ansibuf[i]);
286 }
287 }
288 }
289
290 outchar = Value & 0x7F;
291 if(outchar < ' ') {
292 outchar = 'O';
293 }
294 if(outchar == 0x7F) { /* this is supposed to be a square Block character on FW2 */
295 outchar = 'X';
296 }
297
298 if((fw2->cur_FL_Row == FL_Row) && (FL_Col == fw2->cur_FL_Col + 1)) {
299 sio0d(port, 1, outchar);
300 } else {
301 /* ESC[#;#H */
302 sprintf(ansibuf, "\x1b[%d;%dH%c", FL_Row, FL_Col, outchar);
303 for(i=0;i<strlen(ansibuf);i++) {
304 sio0d(port, 1, ansibuf[i]);
305 }
306 }
307 fw2->cur_FL_Col = FL_Col;
308 fw2->cur_FL_Row = FL_Row;
309 }
310
311 return(1);
312 }
313
314
315 static uint8 FW2_Read(const uint32 Addr)
316 {
317 uint32 baseaddr = 0;
318 uint8 i;
319
320 for(i = 0; i < FW2_MAX_BOARDS; i++) {
321 if(fw2_info[i] != NULL) {
322 baseaddr = fw2_info[i]->uptr->u3;
323 if((Addr >= baseaddr) && (Addr < (baseaddr + FW2_CAPACITY))) {
324 break;
325 }
326 }
327 }
328
329 if(i == FW2_MAX_BOARDS) {
330 return 0xFF;
331 }
332
333 return(fw2_info[i]->M[Addr - baseaddr]);
334 }