1 // Commander X16 Emulator
2 // Copyright (c) 2019 Michael Steil
3 // All rights reserved. License: 2-clause BSD
4 
5 #include <stdio.h>
6 #include <stdbool.h>
7 #include "ps2.h"
8 
9 #define HOLD 25 * 8 /* 25 x ~3 cycles at 8 MHz = 75µs */
10 
11 #define PS2_BUFFER_SIZE 32
12 
13 static struct {
14 	bool sending;
15 	bool has_byte;
16 	uint8_t current_byte;
17 	int bit_index;
18 	int data_bits;
19 	int send_state;
20 	struct
21 	{
22 		uint8_t data[PS2_BUFFER_SIZE];
23 		uint8_t read;
24 		uint8_t write;
25 	} buffer;
26 } state[2];
27 
28 ps2_port_t ps2_port[2];
29 
30 bool
ps2_buffer_can_fit(int i,int n)31 ps2_buffer_can_fit(int i, int n)
32 {
33 	// Math is hard. There's certainly a way to do this without a loop.
34 	for (int n2 = 1; n2 < n; n2++) {
35 		if ((state[i].buffer.write + n2) % PS2_BUFFER_SIZE == state[i].buffer.read) {
36 			return false;
37 		}
38 	}
39 	return true;
40 }
41 
42 void
ps2_buffer_add(int i,uint8_t byte)43 ps2_buffer_add(int i, uint8_t byte)
44 {
45 	if (!ps2_buffer_can_fit(i, 1)) {
46 		return;
47 	}
48 
49 	state[i].buffer.data[state[i].buffer.write] = byte;
50 	state[i].buffer.write = (state[i].buffer.write + 1) % PS2_BUFFER_SIZE;
51 }
52 
53 int
ps2_buffer_remove(int i)54 ps2_buffer_remove(int i)
55 {
56 	if (state[i].buffer.read == state[i].buffer.write) {
57 		return -1; // empty
58 	} else {
59 		uint8_t byte = state[i].buffer.data[state[i].buffer.read];
60 		state[i].buffer.read = (state[i].buffer.read + 1) % PS2_BUFFER_SIZE;
61 		return byte;
62 	}
63 }
64 
65 void
ps2_step(int i)66 ps2_step(int i)
67 {
68 	if (!ps2_port[i].clk_in && ps2_port[i].data_in) { // communication inhibited
69 		ps2_port[i].clk_out = 0;
70 		ps2_port[i].data_out = 0;
71 		state[i].sending = false;
72 //		printf("PS2[%d]: STATE: communication inhibited.\n", i);
73 		return;
74 	} else if (ps2_port[i].clk_in && ps2_port[i].data_in) { // idle state
75 //		printf("PS2[%d]: STATE: idle\n", i);
76 		if (!state[i].sending) {
77 			// get next byte
78 			if (!state[i].has_byte) {
79 				int current_byte = ps2_buffer_remove(i);
80 				if (current_byte < 0) {
81 					// we have nothing to send
82 					ps2_port[i].clk_out = 1;
83 					ps2_port[i].data_out = 0;
84 //					printf("PS2[%d]: nothing to send.\n", i);
85 					return;
86 				}
87 				state[i].current_byte = current_byte;
88 //				printf("PS2[%d]: current_byte: %x\n", i, state[i].current_byte);
89 				state[i].has_byte = true;
90 			}
91 
92 			state[i].data_bits = state[i].current_byte << 1 | (1 - __builtin_parity(state[i].current_byte)) << 9 | (1 << 10);
93 //			printf("PS2[%d]: data_bits: %x\n", i, state[i].data_bits);
94 			state[i].bit_index = 0;
95 			state[i].send_state = 0;
96 			state[i].sending = true;
97 		}
98 
99 		if (state[i].send_state <= HOLD) {
100 			ps2_port[i].clk_out = 0; // data ready
101 			ps2_port[i].data_out = state[i].data_bits & 1;
102 //			printf("PS2[%d]: [%d]sending #%d: %x\n", i, state[i].send_state, state[i].bit_index, state[i].data_bits & 1);
103 			if (state[i].send_state == 0 && state[i].bit_index == 10) {
104 				// we have sent the last bit, if the host
105 				// inhibits now, we'll send the next byte
106 				state[i].has_byte = false;
107 			}
108 			if (state[i].send_state == HOLD) {
109 				state[i].data_bits >>= 1;
110 				state[i].bit_index++;
111 			}
112 			state[i].send_state++;
113 		} else if (state[i].send_state <= 2 * HOLD) {
114 //			printf("PS2[%d]: [%d]not ready\n", i, state[i].send_state);
115 			ps2_port[i].clk_out = 1; // not ready
116 			ps2_port[i].data_out = 0;
117 			if (state[i].send_state == 2 * HOLD) {
118 //				printf("XXX bit_index: %d\n", state[i].bit_index);
119 				if (state[i].bit_index < 11) {
120 					state[i].send_state = 0;
121 				} else {
122 					state[i].sending = false;
123 				}
124 			}
125 			if (state[i].send_state) {
126 				state[i].send_state++;
127 			}
128 		}
129 	} else {
130 //		printf("PS2[%d]: Warning: unknown PS/2 bus state: CLK_IN=%d, DATA_IN=%d\n", i, ps2_port[i].clk_in, ps2_port[i].data_in);
131 		ps2_port[i].clk_out = 0;
132 		ps2_port[i].data_out = 0;
133 	}
134 }
135 
136 // fake mouse
137 
138 static uint8_t buttons;
139 static int16_t mouse_diff_x = 0;
140 static int16_t mouse_diff_y = 0;
141 
142 // byte 0, bit 7: Y overflow
143 // byte 0, bit 6: X overflow
144 // byte 0, bit 5: Y sign bit
145 // byte 0, bit 4: X sign bit
146 // byte 0, bit 3: Always 1
147 // byte 0, bit 2: Middle Btn
148 // byte 0, bit 1: Right Btn
149 // byte 0, bit 0: Left Btn
150 // byte 2:        X Movement
151 // byte 3:        Y Movement
152 
153 
154 static bool
mouse_send(int x,int y,int b)155 mouse_send(int x, int y, int b)
156 {
157 	if (ps2_buffer_can_fit(1, 3)) {
158 		uint8_t byte0 =
159 			((y >> 9) & 1) << 5 |
160 			((x >> 9) & 1) << 4 |
161 			1 << 3 |
162 			b;
163 		uint8_t byte1 = x;
164 		uint8_t byte2 = y;
165 //		printf("%02X %02X %02X\n", byte0, byte1, byte2);
166 
167 		ps2_buffer_add(1, byte0);
168 		ps2_buffer_add(1, byte1);
169 		ps2_buffer_add(1, byte2);
170 
171 		return true;
172 	} else {
173 //		printf("buffer full, skipping...\n");
174 		return false;
175 	}
176 }
177 
178 void
mouse_send_state()179 mouse_send_state()
180 {
181 	if (mouse_diff_x > 255) {
182 		mouse_send(255, 0, buttons);
183 		mouse_diff_x -= 255;
184 	}
185 	if (mouse_diff_x < -256) {
186 		mouse_send(-256, 0, buttons);
187 		mouse_diff_x -= -256;
188 	}
189 	if (mouse_diff_y > 255) {
190 		mouse_send(0, 255, buttons);
191 		mouse_diff_y -= 255;
192 	}
193 	if (mouse_diff_y < -256) {
194 		mouse_send(0, -256, buttons);
195 		mouse_diff_y -= -256;
196 	}
197 	if (mouse_send(mouse_diff_x, mouse_diff_y, buttons)) {
198 		mouse_diff_x = 0;
199 		mouse_diff_y = 0;
200 	}
201 }
202 
203 
204 void
mouse_button_down(int num)205 mouse_button_down(int num)
206 {
207 	buttons |= 1 << num;
208 	mouse_send_state();
209 }
210 
211 void
mouse_button_up(int num)212 mouse_button_up(int num)
213 {
214 	buttons &= (1 << num) ^ 0xff;
215 	mouse_send_state();
216 }
217 
218 void
mouse_move(int x,int y)219 mouse_move(int x, int y)
220 {
221 	mouse_diff_x += x;
222 	mouse_diff_y += y;
223 	mouse_send_state();
224 }
225 
226 uint8_t
mouse_read(uint8_t reg)227 mouse_read(uint8_t reg)
228 {
229 	return 0xff;
230 }
231 
232