tangled
alpha
login
or
join now
jcs.org
/
pce
0
fork
atom
fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
0
fork
atom
overview
issues
pulls
pipelines
chipset: Add support for the 80186 timer / counter
Hampa Hug
13 years ago
7bbfa5f5
d7c59fd7
+411
-1
4 changed files
expand all
collapse all
unified
split
Makefile.dep
src
chipset
80186
Makefile.inc
tcu.c
tcu.h
+3
Makefile.dep
reviewed
···
1221
1221
src/chipset/80186/icu.o: src/chipset/80186/icu.c \
1222
1222
src/chipset/80186/icu.h
1223
1223
1224
1224
+
src/chipset/80186/tcu.o: src/chipset/80186/tcu.c \
1225
1225
+
src/chipset/80186/tcu.h
1226
1226
+
1224
1227
src/chipset/82xx/e8237.o: src/chipset/82xx/e8237.c \
1225
1228
src/chipset/82xx/e8237.h
1226
1229
+2
-1
src/chipset/80186/Makefile.inc
reviewed
···
5
5
DIRS += $(rel)
6
6
DIST += $(rel)/Makefile.inc
7
7
8
8
-
CS_80186_BAS := dma icu
8
8
+
CS_80186_BAS := dma icu tcu
9
9
CS_80186_SRC := $(foreach f,$(CS_80186_BAS),$(rel)/$(f).c)
10
10
CS_80186_OBJ := $(foreach f,$(CS_80186_BAS),$(rel)/$(f).o)
11
11
CS_80186_HDR := $(foreach f,$(CS_80186_BAS),$(rel)/$(f).h)
···
15
15
16
16
$(rel)/dma.o: $(rel)/dma.c $(rel)/dma.h
17
17
$(rel)/icu.o: $(rel)/icu.c $(rel)/icu.h
18
18
+
$(rel)/tcu.o: $(rel)/tcu.c $(rel)/tcu.h
+330
src/chipset/80186/tcu.c
reviewed
···
1
1
+
/*****************************************************************************
2
2
+
* pce *
3
3
+
*****************************************************************************/
4
4
+
5
5
+
/*****************************************************************************
6
6
+
* File name: src/chipset/80186/tcu.c *
7
7
+
* Created: 2012-06-30 by Hampa Hug <hampa@hampa.ch> *
8
8
+
* Copyright: (C) 2012 Hampa Hug <hampa@hampa.ch> *
9
9
+
*****************************************************************************/
10
10
+
11
11
+
/*****************************************************************************
12
12
+
* This program is free software. You can redistribute it and / or modify it *
13
13
+
* under the terms of the GNU General Public License version 2 as published *
14
14
+
* by the Free Software Foundation. *
15
15
+
* *
16
16
+
* This program is distributed in the hope that it will be useful, but *
17
17
+
* WITHOUT ANY WARRANTY, without even the implied warranty of *
18
18
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19
19
+
* Public License for more details. *
20
20
+
*****************************************************************************/
21
21
+
22
22
+
23
23
+
#include "tcu.h"
24
24
+
25
25
+
#include <stdio.h>
26
26
+
#include <stdlib.h>
27
27
+
28
28
+
29
29
+
#define TCON_EN 0x8000
30
30
+
#define TCON_INH 0x4000
31
31
+
#define TCON_INT 0x2000
32
32
+
#define TCON_RIU 0x1000
33
33
+
#define TCON_MC 0x0020
34
34
+
#define TCON_RTG 0x0010
35
35
+
#define TCON_P 0x0008
36
36
+
#define TCON_EXT 0x0004
37
37
+
#define TCON_ALT 0x0002
38
38
+
#define TCON_CONT 0x0001
39
39
+
40
40
+
41
41
+
#ifndef DEBUG_TCU
42
42
+
#define DEBUG_TCU 0
43
43
+
#endif
44
44
+
45
45
+
46
46
+
static
47
47
+
void e80186_tcu_init_cntr (e80186_tcu_t *tcu, unsigned idx)
48
48
+
{
49
49
+
e80186_tcu_cntr_t *cnt;
50
50
+
51
51
+
cnt = &tcu->cntr[idx];
52
52
+
53
53
+
cnt->control = 0;
54
54
+
cnt->count = 0;
55
55
+
cnt->max_count_a = 0;
56
56
+
cnt->max_count_b = 0;
57
57
+
cnt->last_input = 0;
58
58
+
cnt->current_input = 0;
59
59
+
cnt->mc = 0;
60
60
+
61
61
+
cnt->intr_val = 0;
62
62
+
cnt->intr_ext = NULL;
63
63
+
cnt->intr = NULL;
64
64
+
65
65
+
cnt->out_val = 0;
66
66
+
cnt->out_ext = NULL;
67
67
+
cnt->out = NULL;
68
68
+
}
69
69
+
70
70
+
void e80186_tcu_init (e80186_tcu_t *tcu)
71
71
+
{
72
72
+
e80186_tcu_init_cntr (tcu, 0);
73
73
+
e80186_tcu_init_cntr (tcu, 1);
74
74
+
e80186_tcu_init_cntr (tcu, 2);
75
75
+
76
76
+
tcu->clock = 0;
77
77
+
}
78
78
+
79
79
+
void e80186_tcu_free (e80186_tcu_t *tcu)
80
80
+
{
81
81
+
}
82
82
+
83
83
+
void e80186_tcu_set_int_fct (e80186_tcu_t *tcu, unsigned idx, void *ext, void *fct)
84
84
+
{
85
85
+
tcu->cntr[idx].intr_ext = ext;
86
86
+
tcu->cntr[idx].intr = fct;
87
87
+
}
88
88
+
89
89
+
void e80186_tcu_set_out_fct (e80186_tcu_t *tcu, unsigned idx, void *ext, void *fct)
90
90
+
{
91
91
+
tcu->cntr[idx].out_ext = ext;
92
92
+
tcu->cntr[idx].out = fct;
93
93
+
}
94
94
+
95
95
+
static
96
96
+
void e80186_tcu_set_int (e80186_tcu_t *tcu, unsigned idx, unsigned char val)
97
97
+
{
98
98
+
e80186_tcu_cntr_t *cnt;
99
99
+
100
100
+
cnt = &tcu->cntr[idx];
101
101
+
102
102
+
val = (val != 0);
103
103
+
104
104
+
if (cnt->intr_val == val) {
105
105
+
return;
106
106
+
}
107
107
+
108
108
+
cnt->intr_val = val;
109
109
+
110
110
+
if (cnt->intr != NULL) {
111
111
+
cnt->intr (cnt->intr_ext, val);
112
112
+
}
113
113
+
}
114
114
+
115
115
+
static
116
116
+
void e80186_tcu_set_out (e80186_tcu_t *tcu, unsigned idx, unsigned char val)
117
117
+
{
118
118
+
e80186_tcu_cntr_t *cnt;
119
119
+
120
120
+
cnt = &tcu->cntr[idx];
121
121
+
122
122
+
val = (val != 0);
123
123
+
124
124
+
if (cnt->out_val == val) {
125
125
+
return;
126
126
+
}
127
127
+
128
128
+
cnt->out_val = val;
129
129
+
130
130
+
if (cnt->out != NULL) {
131
131
+
cnt->out (cnt->out_ext, val);
132
132
+
}
133
133
+
}
134
134
+
135
135
+
unsigned short e80186_tcu_get_control (const e80186_tcu_t *tcu, unsigned idx)
136
136
+
{
137
137
+
return (tcu->cntr[idx].control);
138
138
+
}
139
139
+
140
140
+
void e80186_tcu_set_control (e80186_tcu_t *tcu, unsigned idx, unsigned short val)
141
141
+
{
142
142
+
e80186_tcu_cntr_t *cnt;
143
143
+
144
144
+
cnt = &tcu->cntr[idx];
145
145
+
146
146
+
if ((val & TCON_INH) == 0) {
147
147
+
val = (val & ~TCON_EN) | (cnt->control & TCON_EN);
148
148
+
}
149
149
+
150
150
+
val = (val & ~TCON_RIU) | (cnt->control & TCON_RIU);
151
151
+
152
152
+
cnt->control = val;
153
153
+
154
154
+
#if DEBUG_TCU >= 1
155
155
+
if (cnt->control & TCON_EN) {
156
156
+
fprintf (stderr, "TCU: TIMER %u ENABLE (%04X)\n", idx, cnt->control);
157
157
+
}
158
158
+
#endif
159
159
+
}
160
160
+
161
161
+
unsigned short e80186_tcu_get_count (const e80186_tcu_t *tcu, unsigned idx)
162
162
+
{
163
163
+
return (tcu->cntr[idx].count);
164
164
+
}
165
165
+
166
166
+
void e80186_tcu_set_count (e80186_tcu_t *tcu, unsigned idx, unsigned short val)
167
167
+
{
168
168
+
tcu->cntr[idx].count = val;
169
169
+
}
170
170
+
171
171
+
unsigned short e80186_tcu_get_max_count_a (const e80186_tcu_t *tcu, unsigned idx)
172
172
+
{
173
173
+
return (tcu->cntr[idx].max_count_a);
174
174
+
}
175
175
+
176
176
+
void e80186_tcu_set_max_count_a (e80186_tcu_t *tcu, unsigned idx, unsigned short val)
177
177
+
{
178
178
+
tcu->cntr[idx].max_count_a = val;
179
179
+
}
180
180
+
181
181
+
unsigned short e80186_tcu_get_max_count_b (const e80186_tcu_t *tcu, unsigned idx)
182
182
+
{
183
183
+
return (tcu->cntr[idx].max_count_b);
184
184
+
}
185
185
+
186
186
+
void e80186_tcu_set_max_count_b (e80186_tcu_t *tcu, unsigned idx, unsigned short val)
187
187
+
{
188
188
+
tcu->cntr[idx].max_count_b = val;
189
189
+
}
190
190
+
191
191
+
void e80186_tcu_set_input (e80186_tcu_t *tcu, unsigned idx, unsigned char val)
192
192
+
{
193
193
+
tcu->cntr[idx].current_input = (val != 0);
194
194
+
}
195
195
+
196
196
+
static
197
197
+
void e80186_tcu_reset_cntr (e80186_tcu_t *tcu, unsigned idx)
198
198
+
{
199
199
+
e80186_tcu_cntr_t *cnt;
200
200
+
201
201
+
cnt = &tcu->cntr[idx];
202
202
+
203
203
+
cnt->control = 0;
204
204
+
cnt->count = 0;
205
205
+
cnt->max_count_a = 0;
206
206
+
cnt->max_count_b = 0;
207
207
+
cnt->mc = 0;
208
208
+
}
209
209
+
210
210
+
void e80186_tcu_reset (e80186_tcu_t *tcu)
211
211
+
{
212
212
+
e80186_tcu_reset_cntr (tcu, 0);
213
213
+
e80186_tcu_reset_cntr (tcu, 1);
214
214
+
e80186_tcu_reset_cntr (tcu, 2);
215
215
+
}
216
216
+
217
217
+
static
218
218
+
void e80186_tcu_clock_cntr (e80186_tcu_t *tcu, unsigned idx)
219
219
+
{
220
220
+
e80186_tcu_cntr_t *cnt;
221
221
+
unsigned char inp0, inp1;
222
222
+
unsigned short ctl;
223
223
+
224
224
+
cnt = &tcu->cntr[idx];
225
225
+
226
226
+
ctl = cnt->control;
227
227
+
228
228
+
inp0 = cnt->last_input;
229
229
+
inp1 = cnt->current_input;
230
230
+
231
231
+
cnt->last_input = cnt->current_input;
232
232
+
233
233
+
cnt->mc = 0;
234
234
+
235
235
+
if ((ctl & TCON_EN) == 0) {
236
236
+
return;
237
237
+
}
238
238
+
239
239
+
if (ctl & TCON_EXT) {
240
240
+
if ((inp0 != 0) || (inp1 == 0)) {
241
241
+
return;
242
242
+
}
243
243
+
}
244
244
+
else {
245
245
+
if (ctl & TCON_RTG) {
246
246
+
if ((inp0 == 0) && (inp1 != 0)) {
247
247
+
cnt->count = 0;
248
248
+
return;
249
249
+
}
250
250
+
}
251
251
+
else {
252
252
+
if (inp1 == 0) {
253
253
+
return;
254
254
+
}
255
255
+
}
256
256
+
257
257
+
if (ctl & TCON_P) {
258
258
+
if (tcu->cntr[2].mc == 0) {
259
259
+
return;
260
260
+
}
261
261
+
}
262
262
+
}
263
263
+
264
264
+
cnt->count = (cnt->count + 1) & 0xffff;
265
265
+
266
266
+
if (ctl & TCON_ALT) {
267
267
+
if (ctl & TCON_RIU) {
268
268
+
if (cnt->count != cnt->max_count_b) {
269
269
+
return;
270
270
+
}
271
271
+
272
272
+
cnt->control &= ~TCON_RIU;
273
273
+
274
274
+
e80186_tcu_set_out (tcu, idx, 1);
275
275
+
276
276
+
if ((ctl & TCON_CONT) == 0) {
277
277
+
cnt->control &= ~TCON_EN;
278
278
+
}
279
279
+
}
280
280
+
else {
281
281
+
if (cnt->count != cnt->max_count_a) {
282
282
+
return;
283
283
+
}
284
284
+
285
285
+
cnt->control |= TCON_RIU;
286
286
+
287
287
+
e80186_tcu_set_out (tcu, idx, 0);
288
288
+
}
289
289
+
}
290
290
+
else {
291
291
+
if (cnt->count != cnt->max_count_a) {
292
292
+
return;
293
293
+
}
294
294
+
295
295
+
e80186_tcu_set_out (tcu, idx, 0);
296
296
+
e80186_tcu_set_out (tcu, idx, 1);
297
297
+
298
298
+
if ((ctl & TCON_CONT) == 0) {
299
299
+
cnt->control &= ~TCON_EN;
300
300
+
}
301
301
+
}
302
302
+
303
303
+
cnt->count = 0;
304
304
+
cnt->control |= TCON_MC;
305
305
+
cnt->mc = 1;
306
306
+
307
307
+
if (ctl & TCON_INT) {
308
308
+
#if DEBUG_TCU >= 1
309
309
+
fprintf (stderr, "TCU: TIMER %u INTERRUPT\n", idx);
310
310
+
#endif
311
311
+
e80186_tcu_set_int (tcu, idx, 0);
312
312
+
e80186_tcu_set_int (tcu, idx, 1);
313
313
+
}
314
314
+
}
315
315
+
316
316
+
void e80186_tcu_clock (e80186_tcu_t *tcu, unsigned cnt)
317
317
+
{
318
318
+
unsigned idx;
319
319
+
320
320
+
while (cnt > 0) {
321
321
+
idx = tcu->clock & 3;
322
322
+
323
323
+
if (idx < 3) {
324
324
+
e80186_tcu_clock_cntr (tcu, idx);
325
325
+
}
326
326
+
327
327
+
tcu->clock += 1;
328
328
+
cnt -= 1;
329
329
+
}
330
330
+
}
+76
src/chipset/80186/tcu.h
reviewed
···
1
1
+
/*****************************************************************************
2
2
+
* pce *
3
3
+
*****************************************************************************/
4
4
+
5
5
+
/*****************************************************************************
6
6
+
* File name: src/chipset/80186/tcu.h *
7
7
+
* Created: 2012-06-30 by Hampa Hug <hampa@hampa.ch> *
8
8
+
* Copyright: (C) 2012 Hampa Hug <hampa@hampa.ch> *
9
9
+
*****************************************************************************/
10
10
+
11
11
+
/*****************************************************************************
12
12
+
* This program is free software. You can redistribute it and / or modify it *
13
13
+
* under the terms of the GNU General Public License version 2 as published *
14
14
+
* by the Free Software Foundation. *
15
15
+
* *
16
16
+
* This program is distributed in the hope that it will be useful, but *
17
17
+
* WITHOUT ANY WARRANTY, without even the implied warranty of *
18
18
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19
19
+
* Public License for more details. *
20
20
+
*****************************************************************************/
21
21
+
22
22
+
23
23
+
#ifndef PCE_CHIPSET_80186_TCU_H
24
24
+
#define PCE_CHIPSET_80186_TCU_H 1
25
25
+
26
26
+
27
27
+
typedef struct {
28
28
+
unsigned short control;
29
29
+
unsigned short count;
30
30
+
unsigned short max_count_a;
31
31
+
unsigned short max_count_b;
32
32
+
unsigned char current_input;
33
33
+
unsigned char last_input;
34
34
+
unsigned char mc;
35
35
+
36
36
+
unsigned char intr_val;
37
37
+
void *intr_ext;
38
38
+
void (*intr) (void *ext, unsigned char val);
39
39
+
40
40
+
unsigned char out_val;
41
41
+
void *out_ext;
42
42
+
void (*out) (void *ext, unsigned char val);
43
43
+
} e80186_tcu_cntr_t;
44
44
+
45
45
+
typedef struct {
46
46
+
e80186_tcu_cntr_t cntr[3];
47
47
+
unsigned clock;
48
48
+
} e80186_tcu_t;
49
49
+
50
50
+
51
51
+
void e80186_tcu_init (e80186_tcu_t *tcu);
52
52
+
void e80186_tcu_free (e80186_tcu_t *tcu);
53
53
+
54
54
+
void e80186_tcu_set_int_fct (e80186_tcu_t *tcu, unsigned idx, void *ext, void *fct);
55
55
+
void e80186_tcu_set_out_fct (e80186_tcu_t *tcu, unsigned idx, void *ext, void *fct);
56
56
+
57
57
+
unsigned short e80186_tcu_get_control (const e80186_tcu_t *tcu, unsigned idx);
58
58
+
void e80186_tcu_set_control (e80186_tcu_t *tcu, unsigned idx, unsigned short val);
59
59
+
60
60
+
unsigned short e80186_tcu_get_count (const e80186_tcu_t *tcu, unsigned idx);
61
61
+
void e80186_tcu_set_count (e80186_tcu_t *tcu, unsigned idx, unsigned short val);
62
62
+
63
63
+
unsigned short e80186_tcu_get_max_count_a (const e80186_tcu_t *tcu, unsigned idx);
64
64
+
void e80186_tcu_set_max_count_a (e80186_tcu_t *tcu, unsigned idx, unsigned short val);
65
65
+
66
66
+
unsigned short e80186_tcu_get_max_count_b (const e80186_tcu_t *tcu, unsigned idx);
67
67
+
void e80186_tcu_set_max_count_b (e80186_tcu_t *tcu, unsigned idx, unsigned short val);
68
68
+
69
69
+
void e80186_tcu_set_input (e80186_tcu_t *tcu, unsigned idx, unsigned char val);
70
70
+
71
71
+
void e80186_tcu_reset (e80186_tcu_t *tcu);
72
72
+
73
73
+
void e80186_tcu_clock (e80186_tcu_t *tcu, unsigned cnt);
74
74
+
75
75
+
76
76
+
#endif