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