File: lp20.c

package info (click to toggle)
ts10 0.8.021004-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 3,572 kB
  • ctags: 11,742
  • sloc: ansic: 68,289; makefile: 466
file content (301 lines) | stat: -rwxr-xr-x 8,963 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
// lp20.c - LP20 Line Printer Interface for KS10 machines
//
// Copyright (c) 2002, Timothy M. Stark
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// TIMOTHY M STARK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Except as contained in this notice, the name of Timothy M Stark shall not
// be used in advertising or otherwise to promote the sale, use or other 
// dealings in this Software without prior written authorization from
// Timothy M Stark.

#include "emu/defs.h"
#include "dev/defs.h"
#include "dev/dec/lp20.h"

#ifdef DEBUG
static cchar *regName[] = {
	"LPCSA",  "LPCSA",   // Control and Status Register #A
	"LPCSB",  "LPCSB",   // Control and Status Register #B
	"LPBA",   "LPBA",    // DMA Bus Address Register
	"LPBC",   "LPBC",    // DMA Byte Counter Register
	"LPPAGC", "LPPAGC",  // Page Count Register
	"LPRDTR", "LPRDTR",  // RAM Data Reguster
	"LPCBUF",            // Character Buffer Register (Low byte)
	          "LPCOLC",  // Column Count Register     (High byte)
	"LPPDAT",            // Printer Data Register     (Low byte)
	          "LPCSUM",  // Checksum Register         (High byte)
};
#endif /* DEBUG */

// Bus Initialization
void lp20_ResetDevice(LP20_DEVICE *lp20)
{
	// Discontinue print/DMA processing
	ts10_CancelTimer(&lp20->svcTimer);

	// Clear all LP20 registers.
	LPCSRA = CSA_DONE;
	LPCSRB = 0;
	LPBSAD = 0;
	LPBCTR = 0;
	LPPCTR = 0;
	LPRAMD = 0;
	LPCCTR = 0;
	LPCBUF = 0;
	LPCKSM = 0;
	LPTDAT = 0;

	lp20->dvptr = 0;
}

int lp20_ReadIO(void *dptr, uint32 pAddr, uint16 *data, uint32 acc)
{
	LP20_DEVICE *lp20 = (LP20_DEVICE *)dptr;
	uint32       reg  = pAddr & ((LP20_NREGS * 2) - 1);

	switch(reg >> 1) {
		case nLPCSRA: *data = LPCSRA;                 break;
		case nLPCSRB: *data = LPCSRB;                 break;
		case nLPBSAD: *data = LPBSAD;                 break;
		case nLPBCTR: *data = LPBCTR;                 break;
		case nLPPCTR: *data = LPPCTR;                 break;
		case nLPRAMD: *data = LPRAMD;                 break;
		case nLPCCTR: *data = (LPCCTR << 8) | LPCBUF; break;
		case nLPCKSM: *data = (LPCKSM << 8) | LPTDAT; break;

#ifdef DEBUG
		default:
			dbg_Printf("%s: *** Undefined Register %d (%06o) at line %d in file %s\n",
				lp20->Unit.devName, reg >> 1, pAddr & 0x1FFF, __LINE__, __FILE__);
			return UQ_NXM;
#endif /* DEBUG */
	}

#ifdef DEBUG
//	if (dbg_Check(DBG_IOREGS))
		dbg_Printf("%s: (R) %s (%o) => %06o (%04X) (Size: %d bytes)\n",
			lp20->Unit.devName, regName[reg], pAddr, *data, *data, acc);
#endif /* DEBUG */

	return UQ_OK;
}

int lp20_WriteIO(void *dptr, uint32 pAddr, uint16 data, uint32 acc)
{
	LP20_DEVICE *lp20 = (LP20_DEVICE *)dptr;
	uint32       reg  = pAddr & ((LP20_NREGS * 2) - 1);

	switch(reg >> 1) {
		case nLPCSRA: // Control and Status Register A
			// If byte access, merge data with CSRA.
			if (acc == ACC_BYTE) data = (pAddr & 1) ?
				((LPCSRA & 0377)  | (data << 8)) :
				((LPCSRA & ~0377) | (data & 0377));

			// Clear all errors.
			if (data & CSA_RESET) {
				ts10_CancelTimer(&lp20->svcTimer);
				LPCSRA  = (LPCSRA & CSA_DONE) & ~CSA_GO;
				LPCSRB &= ~CSB_ECLR;
			}

			// Initialize LP20 interface.
			if (data & CSA_INIT)
				lp20_ResetDevice(lp20);

			// Start printing now. (Start DMA)
			if (data & CSA_GO) {
				if ((LPCSRA & CSA_GO) == 0) {
					if (LPCSRB & CSB_ERR)
						LPCSRB |= CSB_GOE;
					LPCKSM = 0; // Clear checksum.
					ts10_SetTimer(&lp20->svcTimer);
				}
			} else {
				// Stop printing now. (Stop DMA)
				ts10_CancelTimer(&lp20->svcTimer);
			}

			// Finally, load data into CSRA register.
			LPCSRA = (data & CSA_RW) | (LPCSRA & ~CSA_RW);
			break;

		case nLPCSRB: // Control and Status Register B
			break;

		case nLPBSAD: // DMA Bus Address Register
			// If byte access, merge data with LPBSAD.
			if (acc == ACC_BYTE) data = (pAddr & 1) ?
				((LPBSAD & 0377)  | (data << 8)) :
				((LPBSAD & ~0377) | (data & 0377));
			LPBSAD = data;
			break;

		case nLPBCTR: // DMA Byte Counter Register
			// If byte access, merge data with LPBCTR.
			if (acc == ACC_BYTE) data = (pAddr & 1) ?
				((LPBCTR & 0377)  | (data << 8)) :
				((LPBCTR & ~0377) | (data & 0377));
			LPBCTR = data & BCTR_MASK;
			LPCSRA &= ~CSA_DONE;
			break;

		case nLPPCTR: // Page Counter Register
			// If byte access, merge data with LPPCTR.
			if (acc == ACC_BYTE) data = (pAddr & 1) ?
				((LPPCTR & 0377)  | (data << 8)) :
				((LPPCTR & ~0377) | (data & 0377));
			LPPCTR = data & PCTR_MASK;
			break;

		case nLPRAMD: // RAM Data Register
			// If byte access, merge data with LPRAMD.
			if (acc == ACC_BYTE) data = (pAddr & 1) ?
				((LPRAMD & 0377)  | (data << 8)) :
				((LPRAMD & ~0377) | (data & 0377));
			LPRAMD = data & RDAT_MASK;

			// Load RAM data
			TXRAM(LPCBUF & TX_AMASK) = LPRAMD;
			break;

		case nLPCCTR: // LPCCTR/LPCBUF Register
			if (acc == ACC_BYTE) {
				// Byte Access
				if (pAddr & 1) LPCCTR = data;
				else           LPCBUF = data;
			} else {
				// Word Access
				LPCCTR = data >> 8;
				LPCBUF = data;
			}
			break;

		case nLPCKSM:
			// Do nothing - Read Only Register
			break;

#ifdef DEBUG
		default:
			dbg_Printf("%s: *** Undefined Register %d (%06o) at line %d in file %s\n",
				lp20->Unit.devName, reg >> 1, pAddr & 0x1FFF, __LINE__, __FILE__);
			return UQ_NXM;
#endif /* DEBUG */
	}

#ifdef DEBUG
//	if (dbg_Check(DBG_IOREGS))
		dbg_Printf("%s: (W) %s (%o) <= %06o (%04X) (Size: %d bytes)\n",
			lp20->Unit.devName, regName[reg], pAddr, data, data, acc);
#endif /* DEBUG */

	return UQ_OK;
}

// Bus Initialization
void lp20_ResetIO(void *dptr)
{
	lp20_ResetDevice(dptr);
#ifdef DEBUG
	if (dbg_Check(DBG_IOREGS))
		dbg_Printf("Done.\n");
#endif /* DEBUG */
}

// **************************************************************

void *lp20_Create(MAP_DEVICE *newMap, int argc, char **argv)
{
	LP20_DEVICE *lp20 = NULL;
	MAP_IO      *io;

	if (lp20 = (LP20_DEVICE *)calloc(1, sizeof(LP20_DEVICE))) {
		// First, set up its description and
		// link it to its parent device.
		lp20->Unit.devName    = newMap->devName;
		lp20->Unit.keyName    = newMap->keyName;
		lp20->Unit.emuName    = newMap->emuName;
		lp20->Unit.emuVersion = newMap->emuVersion;
		lp20->Device          = newMap->devParent->Device;
		lp20->Callback        = newMap->devParent->Callback;
		lp20->System          = newMap->devParent->sysDevice;

		// Set up an I/O space.
		io               = &lp20->ioMap;
		io->devName      = lp20->Unit.devName;
		io->keyName      = lp20->Unit.keyName;
		io->emuName      = lp20->Unit.emuName;
		io->emuVersion   = lp20->Unit.emuVersion;
		io->Device       = lp20;
		io->csrAddr      = LP20_CSRADDR; /* lp20->csrAddr; */
		io->nRegs        = LP20_NREGS;
		io->intLevel[0]  = LP20_INT;
		io->intMask[0]   = (1u << LP20_INT);
		io->intVector[0] = LP20_VEC;
		io->ReadIO       = lp20_ReadIO;
		io->WriteIO      = lp20_WriteIO;
		io->ResetIO      = lp20_ResetIO;

		// Assign that registers to QBA's I/O space.
		lp20->Callback->SetMap(lp20->Device, io);

		// Finally, link it to its mapping device and return.
		newMap->Device = lp20;
	}

	return lp20;
}

//int lp20_Reset(MAP_DEVICE *map)
int lp20_Reset(void *dptr)
{
//	LP20_DEVICE *lp20 = (LP20_DEVICE *)map->Device;
	LP20_DEVICE *lp20 = (LP20_DEVICE *)dptr;

	lp20_ResetDevice(lp20);
}

DEVICE lp20_Device =
{
	LP20_KEY,         // Key Name
	LP20_NAME,        // Emulator Name
	LP20_VERSION,     // Emulator Version
	NULL,             // Listing of slave devices
	DF_SYSMAP,        // Device Flags
	DT_TERMINAL,      // Device Type

	// Device Commands
	NULL,             // Commands
	NULL,             // Set Commands
	NULL,             // Show Commands

	// Function Calls
	lp20_Create,      // Create Routine
	NULL,             // Configure Routine
	NULL,             // Delete Routine
	lp20_Reset,       // Reset Routine
	NULL,             // Attach Routine
	NULL,             // Detach Routine
	NULL,             // Info Device
	NULL,             // Boot Routine
	NULL,             // Execute Routine
#ifdef DEBUG
	NULL,             // Debug Routine
#endif /* DEBUG */
};