OXYGENHUB
# 8799a5e4565e x16-emulator / src / i2c.c
8.2 KiB · C · last changed chore(): initial commit 15 days ago source blame history raw
03a3459e Andy McCall 1
// Commander X16 Emulator
2
// Copyright (c) 2021 Michael Steil
3
// All rights reserved. License: 2-clause BSD
4
5
#include <stdio.h>
6
#include <stdbool.h>
7
#include "i2c.h"
8
#include "smc.h"
9
#include "rtc.h"
10
11
#define LOG_LEVEL 0
12
13
#define DEVICE_SMC 0x42
14
#define DEVICE_RTC 0x6F
15
16
#define STATE_START 0
17
#define STATE_STOP -1
18
19
i2c_port_t i2c_port;
20
21
static int state = STATE_STOP;
22
static bool read_mode = false;
23
static uint8_t value = 0;
24
static int count = 0;
25
static uint8_t device;
26
27
#define KBD_SIZE 16
28
uint8_t kbd_buffer[KBD_SIZE];						//Ring buffer for key codes
29
30
#define MSE_SIZE 16
31
uint8_t mse_buffer[MSE_SIZE];						//Ring buffer for mouse movement data
32
33
void i2c_reset_state() {
34
	state = STATE_STOP;
35
	read_mode = false;
36
	value = 0;
37
	count = 0;
38
	smc_requested_reset = false;
39
	i2c_mse_buffer_flush();
40
	i2c_kbd_buffer_flush();
41
}
42
43
static void
44
i2c_data(uint8_t device, uint8_t v) {
45
	switch (device) {
46
		case DEVICE_SMC:
47
			smc_i2c_data(v);
48
			break;
49
		case DEVICE_RTC:
50
			rtc_i2c_data(v);
51
			break;
52
		default:
53
			break;
54
	}
55
#if LOG_LEVEL >= 1
56
	printf("I2C DATA($%02X) => $%02X\n", device, value);
57
#endif
58
}
59
60
static uint8_t
61
i2c_read(uint8_t device) {
62
	uint8_t value;
63
	switch (device) {
64
		case DEVICE_SMC:
65
			value = smc_read();
66
			break;
67
		case DEVICE_RTC:
68
			value = rtc_read();
69
			break;
70
		default:
71
			value = 0xff;
72
			break;
73
	}
74
#if LOG_LEVEL >= 1
75
	printf("I2C READ($%02X) = $%02X\n", device, value);
76
#endif
77
	return value;
78
}
79
80
static void
81
i2c_write(uint8_t device) {
82
	switch (device) {
83
		case DEVICE_SMC:
84
			smc_write();
85
			break;
86
		case DEVICE_RTC:
87
			rtc_write();
88
			break;
89
			//        default:
90
			// no-op
91
	}
92
#if LOG_LEVEL >= 1
93
	printf("I2C WRITE $%02X\n", device);
94
#endif
95
}
96
97
void
98
i2c_step()
99
{
100
	static i2c_port_t old_i2c_port;
101
102
	if (old_i2c_port.clk_in != i2c_port.clk_in || old_i2c_port.data_in != i2c_port.data_in) {
103
#if LOG_LEVEL >= 5
104
		printf("I2C(%d) C:%d D:%d\n", state, i2c_port.clk_in, i2c_port.data_in);
105
#endif
106
		if (state == STATE_STOP && i2c_port.clk_in == 0 && i2c_port.data_in == 0) {
107
#if LOG_LEVEL >= 2
108
			printf("I2C START\n");
109
#endif
110
			state = STATE_START;
111
		}
112
113
		if (state == 1 && i2c_port.clk_in == 1 &&i2c_port.data_in == 1 &&  old_i2c_port.data_in == 0) {
114
#if LOG_LEVEL >= 2
115
			printf("I2C STOP\n");
116
#endif
117
			state = STATE_STOP;
118
			count = 0;
119
			read_mode = false;
120
		}
121
122
		if (state != STATE_STOP && i2c_port.clk_in == 1 && old_i2c_port.clk_in == 0) {
123
			i2c_port.data_out = 1;
124
			if (state < 8) {
125
				if (read_mode) {
126
					if (state == 0) {
127
						value = i2c_read(device);
128
					}
129
					i2c_port.data_out = !!(value & 0x80);
130
					value <<= 1;
131
#if LOG_LEVEL >= 4
132
					printf("I2C OUT#%d: %d\n", state, i2c_port.data_out);
133
#endif
134
					state++;
135
				} else {
136
#if LOG_LEVEL >= 4
137
					printf("I2C BIT#%d: %d\n", state, i2c_port.data_in);
138
#endif
139
					value <<= 1;
140
					value |= i2c_port.data_in;
141
					state++;
142
				}
143
			} else { // state == 8
144
				if (read_mode) {
145
					bool nack = i2c_port.data_in;
146
					if (nack) {
147
#if LOG_LEVEL >= 3
148
					printf("I2C OUT DONE (NACK)\n");
149
#endif
150
						count = 0;
151
						read_mode = false;
152
					} else {
153
#if LOG_LEVEL >= 3
154
					printf("I2C OUT DONE (ACK)\n");
155
#endif
156
					}
157
				} else {
158
					bool ack = true;
159
					switch (count) {
160
						case 0:
161
							device = value >> 1;
162
							read_mode = value & 1;
163
							if (device != DEVICE_SMC && device != DEVICE_RTC) {
164
								ack = false;
165
							}
166
							break;
167
						case 1:
168
							i2c_data(device, value);
169
							break;
170
						default:
171
							i2c_data(device, value);
172
							i2c_write(device);
173
							break;
174
					}
175
					if (ack) {
176
#if LOG_LEVEL >= 3
177
						printf("I2C ACK(%d) $%02X\n", count, value);
178
#endif
179
						i2c_port.data_out = 0;
180
						count++;
181
					} else {
182
#if LOG_LEVEL >= 3
183
						printf("I2C NACK(%d) $%02X\n", count, value);
184
#endif
185
						count = 0;
186
						read_mode = false;
187
					}
188
				}
189
				state = STATE_START;
190
			}
191
		}
192
		old_i2c_port = i2c_port;
193
	}
194
}
195
196
197
/**
198
 * Keyboard buffer functions
199
 **/
200
uint8_t kbd_head=0;
201
uint8_t kbd_tail=0;
202
203
/**
204
 * Adds value to the keyboard ring buffer; the value is discarded if the buffer is full
205
 **/
206
void i2c_kbd_buffer_add(uint8_t value) {
207
	uint8_t next = (kbd_head + 1) & (KBD_SIZE - 1);		//Next available index
208
    if (next != kbd_tail) {								//next = tail => buffer full
209
    	kbd_buffer[kbd_head] = value;					//Set new value
210
        kbd_head = next;								//Update buffer head pointer
211
    }
212
}
213
214
/**
215
 * Returns the tail value from the keyboard ring buffer; if the buffer is empty, it returns 0
216
 **/
217
uint8_t i2c_kbd_buffer_next() {
218
	uint8_t value = 0;									//Prepare to return 0 of buffer is empty
219
	if (kbd_head != kbd_tail) {							//head = tail => empty
220
    	value = kbd_buffer[kbd_tail];					//Get value
221
        kbd_tail = (kbd_tail + 1) & (KBD_SIZE - 1);		//Update buffer tail pointer
222
    }
223
	return value;
224
}
225
226
/**
227
 * Clears the keyboard ring buffer
228
 **/
229
void i2c_kbd_buffer_flush() {
230
	kbd_tail = kbd_head = 0;
231
}
232
233
/**
234
 * Mouse buffer functions
235
 **/
236
uint8_t mse_head=0;
237
uint8_t mse_tail=0;
238
239
/**
240
 * Adds value to the mouse ring buffer; discards the value if the buffer is full
241
 **/
242
void i2c_mse_buffer_add(uint8_t value) {
243
	uint8_t next = (mse_head + 1) & (MSE_SIZE - 1);				//Next available index
244
    if (next != mse_tail) {										//next = tail => buffer full
245
    	mse_buffer[mse_head] = value;							//Set value
246
        mse_head = next;										//Update head pointer
247
    }
248
}
249
250
/**
251
 * Returns the tail value from the mouse ring buffer; if the buffer is empty, it returns 0
252
 **/
253
uint8_t i2c_mse_buffer_next() {
254
	uint8_t value = 0;											//Prepare to return 0 if buffer empty
255
	if (mse_head != mse_tail) {									//head = tail => buffer empty
256
    	value = mse_buffer[mse_tail];							//Get tail value
257
        mse_tail = (mse_tail + 1) & (MSE_SIZE - 1);				//Update tail pointer
258
    }
259
	return value;
260
}
261
262
/**
263
 * Clears the mouse ring buffer
264
 **/
265
void i2c_mse_buffer_flush() {
266
	mse_tail = mse_head = 0;
267
}
268
269
/**
270
 * Returns number of values currently stored in the ring buffer
271
 **/
272
uint8_t i2c_mse_buffer_count() {
273
    return (MSE_SIZE + mse_head - mse_tail) & (MSE_SIZE - 1);
274
}
275
276
277
/**
278
 *  fake mouse
279
 **/
280
281
static uint8_t buttons;
282
static int16_t mouse_diff_x = 0;
283
static int16_t mouse_diff_y = 0;
284
static int8_t wheel = 0;
285
static uint8_t mouse_device_id = 3;
286
287
// byte 0, bit 7: Y overflow
288
// byte 0, bit 6: X overflow
289
// byte 0, bit 5: Y sign bit
290
// byte 0, bit 4: X sign bit
291
// byte 0, bit 3: Always 1
292
// byte 0, bit 2: Middle Btn
293
// byte 0, bit 1: Right Btn
294
// byte 0, bit 0: Left Btn
295
// byte 2:        X Movement
296
// byte 3:        Y Movement
297
298
static bool
299
mouse_send(int x, int y, int b, uint8_t w)
300
{
301
	uint8_t psize;
302
	if (mouse_device_id == 3 || mouse_device_id == 4) {
303
		psize = 4;
304
	}
305
	else {
306
		psize  = 3;
307
	}
308
309
	if (i2c_mse_buffer_count() < MSE_SIZE-psize) {
310
		uint8_t byte0 =
311
		    ((y >> 9) & 1) << 5 |
312
		    ((x >> 9) & 1) << 4 |
313
		    1 << 3 |
314
		    b;
315
		i2c_mse_buffer_add(byte0);
316
		i2c_mse_buffer_add(x);
317
		i2c_mse_buffer_add(y);
318
319
		if (mouse_device_id == 3 || mouse_device_id == 4) {
320
			i2c_mse_buffer_add(w);
321
		}
322
323
		return true;
324
	} else {
325
		return false;
326
	}
327
}
328
329
void
330
mouse_send_state(void)
331
{
332
	do {
333
		int send_diff_x = mouse_diff_x > 255 ? 255 : (mouse_diff_x < -256 ? -256 : mouse_diff_x);
334
		int send_diff_y = mouse_diff_y > 255 ? 255 : (mouse_diff_y < -256 ? -256 : mouse_diff_y);
335
336
		mouse_send(send_diff_x, send_diff_y, buttons, wheel);
337
338
		mouse_diff_x -= send_diff_x;
339
		mouse_diff_y -= send_diff_y;
340
		wheel = 0;
341
	} while (mouse_diff_x != 0 || mouse_diff_y != 0);   /* flush BOTH axes (was &&:
342
	                              a single-axis residual was left undelivered) */
343
}
344
345
void
346
mouse_button_down(int num)
347
{
348
	buttons |= 1 << num;
349
}
350
351
void
352
mouse_button_up(int num)
353
{
354
	buttons &= (1 << num) ^ 0xff;
355
}
356
357
uint8_t
358
mouse_get_buttons(void)
359
{
360
	return buttons;   /* bit0 = left/primary, bit1 = right/secondary, bit2 = middle */
361
}
362
363
void
364
mouse_move(int x, int y)
365
{
366
	mouse_diff_x += x;
367
	mouse_diff_y -= y;
368
}
369
370
uint8_t
371
mouse_read(uint8_t reg)
372
{
373
	return 0xff;
374
}
375
376
void 
377
mouse_set_wheel(int8_t y)
378
{
379
	if (mouse_device_id == 3 || mouse_device_id == 4) {
380
		if (y < -7) {
381
			wheel = 7;
382
		}
383
		else if (y > 8) {
384
			wheel = -8;
385
		}
386
		else {
387
			wheel = -y;
388
		}
389
	}
390
}
391
392
uint8_t 
393
mouse_get_device_id() {
394
	return mouse_device_id;
395
}
396
397
void 
398
mouse_set_device_id(uint8_t d) {
399
	switch(d) {
400
		case 0:
401
		case 3:
402
			mouse_device_id = d;
403
			break;
404
		case 4:
405
			mouse_device_id =3;
406
			break;
407
		default:
408
			mouse_device_id = 0;
409
			break;
410
	}
411
	i2c_mse_buffer_flush();
412
}