summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/f8/f3853.c
blob: 4aa0d9dc908dcceec3f4ed8706ecbcd9150b1beb (plain) (blame)
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
/*
  fairchild f3853 smi static ram interface
  with integrated interrupt controller and timer

  databook found at www.freetradezone.com
*/

#include "f3853.h"

/*
  the smi does not have DC0 and DC1, only DC0
  it is not reacting to the cpus DC0/DC1 swap instruction
  --> might lead to 2 devices having reacting to the same DC0 address
  and placing their bytes to the databus!
*/

/*
   8 bit shift register
   feedback in0 = not ( (out3 xor out4) xor (out5 xor out7) )
   interrupt at 0xfe
   0xff stops register (0xfe never reached!)
*/
static UINT8 f3853_value_to_cycle[0x100];

static struct {
    F3853_CONFIG config;

    UINT8 high,low; // bit 7 set to 0 for timer interrupt, to 1 for external interrupt
    int external_enable;
    int timer_enable;

    int request_flipflop;

    int priority_line; /* inverted level*/
    int external_interrupt_line;/* inverted level */

    emu_timer *timer;
} f3853= { { 0 } };
#define INTERRUPT_VECTOR(external) (external?f3853.low|(f3853.high<<8)|0x80 \
					:(f3853.low|(f3853.high<<8))&~0x80)

static void f3853_set_interrupt_request_line(void)
{
    if (!f3853.config.interrupt_request)
		return;

	if (f3853.external_enable&&!f3853.priority_line)
		f3853.config.interrupt_request(INTERRUPT_VECTOR(TRUE), TRUE);
	else if (f3853.timer_enable&&!f3853.priority_line&&f3853.request_flipflop)
		f3853.config.interrupt_request(INTERRUPT_VECTOR(FALSE), TRUE);
	else
		f3853.config.interrupt_request(0, FALSE);
}

static TIMER_CALLBACK( f3853_timer_callback );

static void f3853_timer_start(UINT8 value)
{
	attotime period = (value != 0xff) ? attotime_mul(ATTOTIME_IN_HZ(f3853.config.frequency), f3853_value_to_cycle[value]*31) : attotime_never;

	timer_adjust(f3853.timer, period, 0, attotime_never);
}

static TIMER_CALLBACK( f3853_timer_callback )
{
    if (f3853.timer_enable)
	{
		f3853.request_flipflop = TRUE;
		f3853_set_interrupt_request_line();
    }
    f3853_timer_start(0xfe);
}


void f3853_init(F3853_CONFIG *config)
{
	UINT8 reg=0xfe;
	int i;

	for (i=254/*known to get 0xfe after 255 cycles*/; i>=0; i--)
	{
		int o7=reg&0x80?TRUE:FALSE, o5=reg&0x20?TRUE:FALSE,
			o4=reg&0x10?TRUE:FALSE, o3=reg&8?TRUE:FALSE;
		f3853_value_to_cycle[reg]=i;
		reg<<=1;
		if (!((o7!=o5)!=(o4!=o3))) reg|=1;
	}

	f3853.config=*config;

	f3853.priority_line=FALSE;
	f3853.external_interrupt_line=TRUE;
	f3853.timer = timer_alloc(f3853_timer_callback);
}

void f3853_reset(void)
{
    // registers indeterminate
}

void f3853_set_external_interrupt_in_line(int level)
{
    if (f3853.external_interrupt_line&&!level&& f3853.external_enable)
	f3853.request_flipflop = TRUE;
    f3853.external_interrupt_line = level;
    f3853_set_interrupt_request_line();
}

void f3853_set_priority_in_line(int level)
{
    f3853.priority_line=level;
    f3853_set_interrupt_request_line();
}

 READ8_HANDLER(f3853_r)
{
    UINT8 data=0;
    switch (offset) {
    case 0:
		data=f3853.high;
		break;
    case 1:
		data=f3853.low;
		break;
    case 2: // interrupt control; not readable
    case 3: // timer; not readable
		break;
    }
    return data;
}

WRITE8_HANDLER(f3853_w)
{
	switch (offset) {
	case 0:
		f3853.high=data;
		break;
	case 1:
		f3853.low=data;
		break;
	case 2: //interrupt control
		f3853.external_enable = ((data&3)==1);
		f3853.timer_enable = ((data&3)==3);
		f3853_set_interrupt_request_line();
		break;
	case 3: //timer
		f3853.request_flipflop=FALSE;
		f3853_set_interrupt_request_line();
		f3853_timer_start(data);
		break;
	}
}