File: trs_io.c

package info (click to toggle)
xtrs 4.9c-3.4
  • links: PTS
  • area: contrib
  • in suites: jessie, jessie-kfreebsd, wheezy
  • size: 2,240 kB
  • ctags: 1,430
  • sloc: ansic: 19,941; makefile: 243; csh: 132; sh: 129
file content (413 lines) | stat: -rw-r--r-- 11,437 bytes parent folder | download | duplicates (5)
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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
/*
 * Copyright (C) 1992 Clarendon Hill Software.
 *
 * Permission is granted to any individual or institution to use, copy,
 * or redistribute this software, provided this copyright notice is retained. 
 *
 * This software is provided "as is" without any expressed or implied
 * warranty.  If this software brings on any sort of damage -- physical,
 * monetary, emotional, or brain -- too bad.  You've got no one to blame
 * but yourself. 
 *
 * The software may be modified for your own purposes, but modified versions
 * must retain this notice.
 */

/*
   Modified by Timothy Mann, 1996 and following.
*/

/*#define PORTDEBUG1 1*/
/*#define PORTDEBUG2 1*/

#include <time.h>

#include "z80.h"
#include "trs.h"
#include "trs_disk.h"
#include "trs_hard.h"
#include "trs_uart.h"

static int modesel = 0;     /* Model I */
static int modeimage = 0x8; /* Model III/4/4p */
static int ctrlimage = 0;   /* Model 4/4p */
static int rominimage = 0;  /* Model 4p */

/*ARGSUSED*/
void z80_out(int port, int value)
{
#if PORTDEBUG1
  debug("out (0x%02x), 0x%02x; pc 0x%04x\n", port, value, z80_state.pc.word);
#endif
  /* First, ports common to all models */
  switch (port) {
  case TRS_HARD_WP:       /* 0xC0 */
  case TRS_HARD_CONTROL:  /* 0xC1 */
  case TRS_HARD_DATA:     /* 0xC8 */ 
  case TRS_HARD_ERROR:    /* 0xC9 */ /*=TRS_HARD_PRECOMP*/ 
  case TRS_HARD_SECCNT:   /* 0xCA */
  case TRS_HARD_SECNUM:   /* 0xCB */
  case TRS_HARD_CYLLO:    /* 0xCC */
  case TRS_HARD_CYLHI:    /* 0xCD */
  case TRS_HARD_SDH:      /* 0xCE */
  case TRS_HARD_STATUS:   /* 0xCF */ /*=TRS_HARD_COMMAND*/
    trs_hard_out(port, value);
    break;
  case TRS_UART_RESET:    /* 0xE8 */
    trs_uart_reset_out(value);
    break;
  case TRS_UART_BAUD:     /* 0xE9 */
    trs_uart_baud_out(value);
    break;
  case TRS_UART_CONTROL:  /* 0xEA */
    trs_uart_control_out(value);
    break;
  case TRS_UART_DATA:     /* 0xEB */
    trs_uart_data_out(value);
    break;
  }

  if (trs_model == 1) {
    /* Next, Model I only */
    switch (port) {
    case 0x00: /* HRG off */
    case 0x01: /* HRG on */
      hrg_onoff(port);
      break;
    case 0x02: /* HRG write address low byte */
      hrg_write_addr(value, 0xff);
      break;
    case 0x03: /* HRG write address high byte */
      hrg_write_addr(value << 8, 0x3f00);
      break;
    case 0x05: /* HRG write data byte */
      hrg_write_data(value);
      break;
    case 0xB9: /* Orchestra-85 left channel */
      trs_orch90_out(1, value);
      break;
    case 0xB5: /* Orchestra-85 right channel */
      trs_orch90_out(2, value);
      break;
    case 0xFD:
      /* GENIE location of printer port */
      trs_printer_write(value);
      break;
    case 0xFE:
      /* Typical location for clock speedup kits */
      trs_timer_speed(value);
      break;
    case 0xFF:
      /* screen mode select is on D3 line */
      modesel = (value >> 3) & 1;
      trs_screen_expanded(modesel);
      /* do cassette emulation */
      trs_cassette_motor((value >> 2) & 1);
      trs_cassette_out(value & 0x3);
      break;
    default:
      break;
    }

  } else {
    /* Next, Models III/4/4P only */
    switch (port) {
    case 0x79: /* Orchestra-90 left channel */
      trs_orch90_out(1, value);
      break;
    case 0x75: /* Orchestra-90 right channel */
      trs_orch90_out(2, value);
      break;
    case 0x80:
      if (trs_model >= 3) grafyx_write_x(value);
      break;
    case 0x81:
      if (trs_model >= 3) grafyx_write_y(value);
      break;
    case 0x82:
      if (trs_model >= 3) grafyx_write_data(value);
      break;
    case 0x83:
      if (trs_model >= 3) grafyx_write_mode(value);
      break;
    case 0x84:
    case 0x85:
    case 0x86:
    case 0x87:
      if (trs_model >= 4) {
	int changes = value ^ ctrlimage;
	if (changes & 0x80) {
	  mem_video_page((value & 0x80) >> 7);
	}
	if (changes & 0x70) {
	  mem_bank((value & 0x70) >> 4);
	}
	if (changes & 0x08) {
	  trs_screen_inverse((value & 0x08) >> 3);
	}
	if (changes & 0x04) {
	  trs_screen_80x24((value & 0x04) >> 2);
	}
	if (changes & 0x03) {
	  mem_map(value & 0x03);
	}
	ctrlimage = value;
      }
      break;
    case 0x8c:
      if (trs_model >= 4) grafyx_write_xoffset(value);
      break;
    case 0x8d:
      if (trs_model >= 4) grafyx_write_yoffset(value);
      break;
    case 0x8e:
      if (trs_model >= 4) grafyx_write_overlay(value);
      break;
    case 0x90:
    case 0x91:
    case 0x92:
    case 0x93:
      trs_sound_out(value & 1);
      break;
    case 0x9C:
    case 0x9D: /* !!? */
    case 0x9E: /* !!? */
    case 0x9F: /* !!? */
      if (trs_model == 5 /*4p*/) {
	rominimage = value & 1;
	mem_romin(rominimage);
      }
      break;
    case 0xE0:
      trs_interrupt_mask_write(value);
      break;
    case TRSDISK3_INTERRUPT: /* 0xE4 */
    case 0xE5:
    case 0xE6:
    case 0xE7:
      trs_nmi_mask_write(value);
      break;
    case 0xEC:
    case 0xED:
    case 0xEE:
    case 0xEF:
      modeimage = value;
      /* cassette motor is on D1 */
      trs_cassette_motor((modeimage & 0x02) >> 1);
      /* screen mode select is on D2 */
      trs_screen_expanded((modeimage & 0x04) >> 2);
      /* alternate char set is on D3 */
      trs_screen_alternate(!((modeimage & 0x08) >> 3));
      /* clock speed is on D6; it affects timer HZ too */
      trs_timer_speed((modeimage & 0x40) >> 6);
      break;
    case TRSDISK3_COMMAND: /* 0xF0 */
      trs_disk_command_write(value);
      break;
    case TRSDISK3_TRACK: /* 0xF1 */
      trs_disk_track_write(value);
      break;
    case TRSDISK3_SECTOR: /* 0xF2 */
      trs_disk_sector_write(value);
      break;
    case TRSDISK3_DATA: /* 0xF3 */
      trs_disk_data_write(value);
      break;
    case TRSDISK3_SELECT: /* 0xF4 */
    case 0xF5:
    case 0xF6:
    case 0xF7:
      trs_disk_select_write(value);
      break;
    case 0xF8:
    case 0xF9:
    case 0xFA:
    case 0xFB:
      trs_printer_write(value);
      break;
    case 0xFC:
    case 0xFD:
    case 0xFE:
    case 0xFF:
      if (trs_model == 3 && (value & 0x20) && grafyx_get_microlabs()) {
	/* do Model III Micro Labs graphics card */
	grafyx_m3_write_mode(value);
      } else {
	/* do cassette emulation */
	trs_cassette_out(value & 3);
      }
      break;
    default:
      break;
    }
  }
  return;
}

/*ARGSUSED*/
int z80_in(int port)
{
  /* First, ports common to all models */
#if PORTDEBUG2
  debug("in (0x%02x); pc %04x\n", port, z80_state.pc.word);
#endif

  /* Support for a special HW real-time clock (TimeDate80?)
   * I used to have.  It was a small card-edge unit with a
   * battery that held the time/date with power off.
   * - Joe Peterson (joe@skyrush.com)
   *
   * According to the LDOS Quarterly 1-6, TChron1, TRSWatch, and
   * TimeDate80 are accessible at high ports 0xB0-0xBC, while
   * T-Timer is accessible at high ports 0xC0-0xCC.  It does
   * not say where the low ports were; Joe's code had 0x70-0x7C,
   * so I presume that's correct at least for the TimeDate80.
   * Note: 0xC0-0xCC conflicts with Radio Shack hard disk, so
   * clock access at these ports is disabled starting in xtrs 4.1.
   *
   * These devices were based on the MSM5832 chip, which returns only
   * a 2-digit year.  It's not clear what software will do with the
   * date in years beyond 1999.
   */

  if ((port >= 0x70 && port <= 0x7C)
      || (port >= 0xB0 && port <= 0xBC)
      /*|| (port >= 0xC0 && port <= 0xCC)*/) {
    struct tm *time_info;
    time_t time_secs;

    time_secs = time(NULL);
    time_info = localtime(&time_secs);

    switch (port & 0x0F) {
    case 0xC: /* year (high) */
      return (time_info->tm_year / 10) % 10;
    case 0xB: /* year (low) */
      return (time_info->tm_year % 10);
    case 0xA: /* month (high) */
      return ((time_info->tm_mon + 1) / 10);
    case 0x9: /* month (low) */
      return ((time_info->tm_mon + 1) % 10);
    case 0x8: /* date (high) and leap year (bit 2) */
      return ((time_info->tm_mday / 10) | ((time_info->tm_year % 4) ? 0 : 4));
    case 0x7: /* date (low) */
      return (time_info->tm_mday % 10);
    case 0x6: /* day-of-week */
      return time_info->tm_wday;
    case 0x5: /* hours (high) and PM (bit 2) and 24hr (bit 3) */
      return ((time_info->tm_hour / 10) | 8);
    case 0x4: /* hours (low) */
      return (time_info->tm_hour % 10);
    case 0x3: /* minutes (high) */
      return (time_info->tm_min / 10);
    case 0x2: /* minutes (low) */
      return (time_info->tm_min % 10);
    case 0x1: /* seconds (high) */
      return (time_info->tm_sec / 10);
    case 0x0: /* seconds (low) */
      return (time_info->tm_sec % 10);
    }
  }

  switch (port) {
  case 0x00:
    return trs_joystick_in();
  case TRS_HARD_WP:       /* 0xC0 */
  case TRS_HARD_CONTROL:  /* 0xC1 */
  case TRS_HARD_DATA:     /* 0xC8 */ 
  case TRS_HARD_ERROR:    /* 0xC9 */ /*=TRS_HARD_PRECOMP*/ 
  case TRS_HARD_SECCNT:   /* 0xCA */
  case TRS_HARD_SECNUM:   /* 0xCB */
  case TRS_HARD_CYLLO:    /* 0xCC */
  case TRS_HARD_CYLHI:    /* 0xCD */
  case TRS_HARD_SDH:      /* 0xCE */
  case TRS_HARD_STATUS:   /* 0xCF */ /*=TRS_HARD_COMMAND*/
    return trs_hard_in(port);
  case TRS_UART_MODEM:    /* 0xE8 */
    return trs_uart_modem_in();
  case TRS_UART_SWITCHES: /* 0xE9 */
    return trs_uart_switches_in();
  case TRS_UART_STATUS:   /* 0xEA */
    return trs_uart_status_in();
  case TRS_UART_DATA:     /* 0xEB */
    return trs_uart_data_in();
  default:
    break;
  }

  if (trs_model == 1) {
    /* Model I only */
    switch (port) {
    case 0x00: /* HRG off (undocumented) */
    case 0x01: /* HRG on (undocumented) */
      hrg_onoff(port);
      break;
    case 0x04: /* HRG read data byte */
      return hrg_read_data();
    case 0xFD:
      /* GENIE location of printer port */
      return trs_printer_read();
    case 0xFF:
      return (modesel ? 0x7f : 0x3f) | trs_cassette_in();
    default:
      break;
    }

  } else {
    /* Models III/4/4P only */
    switch (port) {
    case 0x82:
      if (trs_model >= 3) {
	return grafyx_read_data();
      }
      break;
    case 0x9C: /* !!? */
    case 0x9D: /* !!? */
    case 0x9E: /* !!? */
    case 0x9F: /* !!? */
      if (trs_model == 5 /*4p*/) {
	return rominimage;
      }
      break;
    case TRS_HARD_WP:      /* 0xC0 */
    case TRS_HARD_CONTROL: /* 0xC1 */
    case TRS_HARD_DATA:    /* 0xC8 */ 
    case TRS_HARD_ERROR:   /* 0xC9 */ /*=TRS_HARD_PRECOMP*/ 
    case TRS_HARD_SECCNT:  /* 0xCA */
    case TRS_HARD_SECNUM:  /* 0xCB */
    case TRS_HARD_CYLLO:   /* 0xCC */
    case TRS_HARD_CYLHI:   /* 0xCD */
    case TRS_HARD_SDH:     /* 0xCE */
    case TRS_HARD_STATUS:  /* 0xCF */ /*=TRS_HARD_COMMAND*/
      return trs_hard_in(port);
      break;
    case 0xE0:
      return trs_interrupt_latch_read();
    case 0xEC:
    case 0xED:
    case 0xEE:
    case 0xEF:
      trs_timer_interrupt(0); /* acknowledge */
      return 0xFF;
    case TRSDISK3_INTERRUPT: /* 0xE4 */
      return trs_nmi_latch_read();
    case TRSDISK3_STATUS: /* 0xF0 */
      return trs_disk_status_read();
    case TRSDISK3_TRACK: /* 0xF1 */
      return trs_disk_track_read();
    case TRSDISK3_SECTOR: /* 0xF2 */
      return trs_disk_sector_read();
    case TRSDISK3_DATA: /* 0xF3 */
      return trs_disk_data_read();
    case 0xF8:
      return trs_printer_read();
    case 0xFF:
      return (modeimage & 0x7e) | trs_cassette_in();
    default:
      break;
    }
  }

  /* other ports -- unmapped */
  return 0xFF;
}