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 */