1 /*  mp-s.c: SWTP MP-S serial I/O card emulator
2 
3     Copyright (c) 2005-2011, William Beech
4 
5     Permission is hereby granted, free of charge, to any person obtaining a
6     copy of this software and associated documentation files (the "Software"),
7     to deal in the Software without restriction, including without limitation
8     the rights to use, copy, modify, merge, publish, distribute, sublicense,
9     and/or sell copies of the Software, and to permit persons to whom the
10     Software is furnished to do so, subject to the following conditions:
11 
12     The above copyright notice and this permission notice shall be included in
13     all copies or substantial portions of the Software.
14 
15     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18     Willaim Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19     IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20     CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22     Except as contained in this notice, the name of William A. Beech shall not
23     be used in advertising or otherwise to promote the sale, use or other dealings
24     in this Software without prior written authorization from William A. Beech.
25 
26     These functions support a simulated SWTP MP-S interface card.
27     The card contains one M6850 ACIA.  The ACIA implements one complete
28     serial port.  It provides 7 or 8-bit ASCII RS-232 interface to Terminals
29     or 20 mA current loop interface to a model 33 or 37 Teletype.  It is not
30     compatible with baudot Teletypes.  Baud rates from 110 to 1200 are
31     switch selectable from S! on the MP-S. The ACIA ports appear at all
32     4 addresses.  This fact is used by SWTBUG to determine the presence of the
33     MP-S vice MP-C serial card.  The ACIA interrupt request line can be connected
34     to the IRQ or NMI interrupt lines by a jumper on the MP-S.
35 
36     All I/O is via either programmed I/O or interrupt controlled I/O.
37     It has a status port and a data port.  A write to the status port
38     can select some options for the device (0x03 will reset the port).
39     A read of the status port gets the port status:
40 
41     +---+---+---+---+---+---+---+---+
42     | I | P | O | F |CTS|DCD|TXE|RXF|
43     +---+---+---+---+---+---+---+---+
44 
45     RXF - A 1 in this bit position means a character has been received
46     	  on the data port and is ready to be read.
47     TXE - A 1 in this bit means the port is ready to receive a character
48     	  on the data port and transmit it out over the serial line.
49 
50     A read to the data port gets the buffered character, a write
51     to the data port writes the character to the device.
52 */
53 
54 #include    <stdio.h>
55 #include    <ctype.h>
56 #include    "swtp_defs.h"
57 
58 #define UNIT_V_TTY  (UNIT_V_UF)         // TTY or ANSI mode
59 #define UNIT_TTY   (1 << UNIT_V_TTY)
60 
61 /* local global variables */
62 
63 int32 ptr_stopioe = 0;                  // stop on error
64 int32 ptp_stopioe = 0;                  // stop on error
65 int32 odata;
66 int32 status;
67 
68 int32 ptp_flag = 0;
69 int32 ptr_flag = 0;
70 
71 /* function prototypes */
72 
73 t_stat sio_svc (UNIT *uptr);
74 t_stat ptr_svc (UNIT *uptr);
75 t_stat ptp_svc (UNIT *uptr);
76 t_stat sio_reset (DEVICE *dptr);
77 t_stat ptr_reset (DEVICE *dptr);
78 t_stat ptp_reset (DEVICE *dptr);
79 int32 sio0s(int32 io, int32 data);
80 int32 sio0d(int32 io, int32 data);
81 int32 sio1s(int32 io, int32 data);
82 int32 sio1d(int32 io, int32 data);
83 
84 /* sio data structures
85 
86    sio_dev        SIO device descriptor
87    sio_unit       SIO unit descriptor
88    sio_reg        SIO register list
89    sio_mod        SIO modifiers list */
90 
91 UNIT sio_unit = { UDATA (&sio_svc, 0, 0), KBD_POLL_WAIT
92 };
93 
94 REG sio_reg[] = {
95     { ORDATA (DATA, sio_unit.buf, 8) },
96     { ORDATA (STAT, sio_unit.u3, 8) },
97     { NULL }
98 };
99 
100 MTAB sio_mod[] = {
101     { UNIT_TTY, UNIT_TTY, "TTY", "TTY", NULL },
102     { UNIT_TTY, 0, "ANSI", "ANSI", NULL },
103     { 0 }
104 };
105 
106 DEVICE sio_dev = {
107     "MP-S", &sio_unit, sio_reg, sio_mod,
108     1, 10, 31, 1, 8, 8,
109     NULL, NULL, &sio_reset,
110     NULL, NULL, NULL
111 };
112 
113 /* paper tape reader data structures
114 
115    ptr_dev        PTR device descriptor
116    ptr_unit       PTR unit descriptor
117    ptr_reg        PTR register list
118    ptr_mod        PTR modifiers list */
119 
120 UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT
121 };
122 
123 DEVICE ptr_dev = {
124     "PTR", &ptr_unit, NULL, NULL,
125     1, 10, 31, 1, 8, 8,
126     NULL, NULL, &ptr_reset,
127     NULL, NULL, NULL
128 };
129 
130 /* paper tape punch data structures
131 
132    ptp_dev        PTP device descriptor
133    ptp_unit       PTP unit descriptor
134    ptp_reg        PTP register list
135    ptp_mod        PTP modifiers list */
136 
137 UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT
138 };
139 DEVICE ptp_dev = {
140     "PTP", &ptp_unit, NULL, NULL,
141     1, 10, 31, 1, 8, 8,
142     NULL, NULL, &ptp_reset,
143     NULL, NULL, NULL
144 };
145 
146 /* console input service routine */
147 
sio_svc(UNIT * uptr)148 int32 sio_svc (UNIT *uptr)
149 {
150     int32 temp;
151 
152     sim_activate (&sio_unit, sio_unit.wait); // continue poll
153     if ((temp = sim_poll_kbd ()) < SCPE_KFLAG)
154         return temp;                    // no char or error?
155     sio_unit.buf = temp & 0xFF;         // Save char
156     sio_unit.u3 |= 0x01;                // Set RXF flag
157     /* Do any special character handling here */
158     sio_unit.pos++;                     // step character count
159     return SCPE_OK;
160 }
161 
162 /* paper tape reader input service routine */
163 
ptr_svc(UNIT * uptr)164 int32 ptr_svc (UNIT *uptr)
165 {
166     int32 temp;
167 
168     sim_activate (&ptr_unit, ptr_unit.wait); // continue poll
169     if ((temp = sim_poll_kbd ()) < SCPE_KFLAG)
170         return temp;                    // no char or error?
171     ptr_unit.buf = temp & 0xFF;         // Save char
172     ptr_unit.u3 |= 0x01;                // Set RXF flag
173     /* Do any special character handling here */
174     ptr_unit.pos++;                     // step character count
175     return SCPE_OK;
176 }
177 
178 /* paper tape punch output service routine */
179 
ptp_svc(UNIT * uptr)180 int32 ptp_svc (UNIT *uptr)
181 {
182     return SCPE_OK;
183 }
184 
185 /* Reset console */
186 
sio_reset(DEVICE * dptr)187 int32 sio_reset (DEVICE *dptr)
188 {
189     sio_unit.buf = 0;                   // Data buffer
190     sio_unit.u3 = 0x02;                 // Status buffer
191     sim_activate (&sio_unit, sio_unit.wait); // activate unit
192     return SCPE_OK;
193 }
194 
195 /* Reset paper tape reader */
196 
ptr_reset(DEVICE * dptr)197 int32 ptr_reset (DEVICE *dptr)
198 {
199     ptr_unit.buf = 0;
200     ptr_unit.u3 = 0x02;
201     sim_activate (&ptr_unit, ptr_unit.wait); // activate unit
202 //    sim_cancel (&ptr_unit);             // deactivate unit
203     return SCPE_OK;
204 }
205 
206 /* Reset paper tape punch */
207 
ptp_reset(DEVICE * dptr)208 int32 ptp_reset (DEVICE *dptr)
209 {
210     ptp_unit.buf = 0;
211     ptp_unit.u3 = 0x02;
212     sim_activate (&ptp_unit, ptp_unit.wait); // activate unit
213 //    sim_cancel (&ptp_unit);             // deactivate unit
214     return SCPE_OK;
215 }
216 
217 /*  I/O instruction handlers, called from the MP-B2 module when a
218    read or write occur to addresses 0x8004-0x8007. */
219 
sio0s(int32 io,int32 data)220 int32 sio0s(int32 io, int32 data)
221 {
222     if (io == 0) {                      // control register read
223         if (ptr_flag) {                 // reader enabled?
224             if ((ptr_unit.flags & UNIT_ATT) == 0) { // attached?
225                 ptr_unit.u3 &= 0xFE;    // no, clear RXF flag
226                 ptr_flag = 0;           // clear reader flag
227                 printf("Reader not attached to file\n");
228             } else {                    // attached
229                 if (feof(ptr_unit.fileref)) { // EOF
230                     ptr_unit.u3 &= 0xFE; // clear RXF flag
231                     ptr_flag = 0;       // clear reader flag
232                 } else                  // not EOF
233                     ptr_unit.u3 |= 0x01; // set ready
234             }
235             return (status = ptr_unit.u3); // return ptr status
236         } else {
237             return (status = sio_unit.u3); // return console status
238         }
239     } else {                            // control register write
240         if (data == 0x03) {             // reset port!
241             sio_unit.u3 = 0x02;         // reset console
242             sio_unit.buf = 0;
243             sio_unit.pos = 0;
244             ptr_unit.u3 = 0x02;         // reset reader
245             ptr_unit.buf = 0;
246             ptr_unit.pos = 0;
247             ptp_unit.u3 = 0x02;         // reset punch
248             ptp_unit.buf = 0;
249             ptp_unit.pos = 0;
250         }
251     return (status = 0);                // invalid io
252     }
253 }
254 
sio0d(int32 io,int32 data)255 int32 sio0d(int32 io, int32 data)
256 {
257     if (io == 0) {                      // data register read
258         if (ptr_flag) {                 // RDR enabled?
259             if ((ptr_unit.flags & UNIT_ATT) == 0) // attached?
260                 return 0;               // no, done
261 //          printf("ptr_unit.u3=%02X\n", ptr_unit.u3);
262             if ((ptr_unit.u3 & 0x01) == 0) { // yes, more data?
263 //              printf("Returning old %02X\n", odata); // no, return previous byte
264                 return (odata & 0xFF);
265             }
266             if ((odata = getc(ptr_unit.fileref)) == EOF) { // end of file?
267 //              printf("Got EOF\n");
268                 ptr_unit.u3 &= 0xFE;    // clear RXF flag
269                 return (odata = 0);     // no data
270             }
271 //          printf("Returning new %02X\n", odata);
272             ptr_unit.pos++;             // step character count
273             ptr_unit.u3 &= 0xFE;        // clear RXF flag
274             return (odata & 0xFF);      // return character
275         } else {
276             sio_unit.u3 &= 0xFE;        // clear RXF flag
277             return (odata = sio_unit.buf); // return next char
278         }
279     } else {                            // data register write
280         if (isprint(data) || data == '\r' || data == '\n') { // printable?
281             sim_putchar(data);          // print character on console
282             if (ptp_flag && ptp_unit.flags & UNIT_ATT) { // PTP enabled & attached?
283                 putc(data, ptp_unit.fileref);
284                 ptp_unit.pos++;         // step character counter
285             }
286         } else {                        // DC1-DC4 control Reader/Punch
287             switch (data) {
288                 case 0x11:              // PTR on
289                     ptr_flag = 1;
290                     ptr_unit.u3 |= 0x01;
291 //                    printf("Reader on\n");
292                     break;
293                 case 0x12:              // PTP on
294                     ptp_flag = 1;
295                     ptp_unit.u3 |= 0x02;
296 //                    printf("Punch on\n");
297                     break;
298                 case 0x13:              // PTR off
299                     ptr_flag = 0;
300 //                    printf("Reader off-%d bytes read\n", ptr_unit.pos);
301                     break;
302                 case 0x14:              // PTP off
303                     ptp_flag = 0;
304 //                    printf("Punch off-%d bytes written\n", ptp_unit.pos);
305                     break;
306                 default:                // ignore all other characters
307                     break;
308             }
309         }
310     }
311     return (odata = 0);
312 }
313 
314 /*	because each port appears at 2 addresses and this fact is used
315 	to determine if it is a MP-C or MP-S repeatedly in the SWTBUG
316 	monitor, this code assures that reads of the high ports return
317 	the same data as was read the last time on the low ports.
318 */
319 
sio1s(int32 io,int32 data)320 int32 sio1s(int32 io, int32 data)
321 {
322     return status;
323 }
324 
sio1d(int32 io,int32 data)325 int32 sio1d(int32 io, int32 data)
326 {
327     return odata;
328 }
329 
330 /* end of mp-s.c */