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