OXYGENHUB
◆ main enhanced-x16-emulator / src / vera_spi.c
2.3 KiB · C · last changed chore(): initial commit 25 days ago source blame history raw
9120e874 Andy McCall 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 "sdcard.h"
8
#include "vera_spi.h"
9
10
#define SPI_CLOCK_RATE_MHZ 12.5f
11
12
bool ss;
13
bool busy;
14
bool autotx;
15
uint8_t sending_byte, received_byte;
16
float outcounter;
17
18
void
19
vera_spi_init()
20
{
21
	ss = false;
22
	busy = false;
23
	autotx = false;
24
	received_byte = 0xff;
25
}
26
27
void
28
vera_spi_step(int mhz, int clocks)
29
{
30
	if (busy) {
31
		outcounter += (float)clocks * SPI_CLOCK_RATE_MHZ / (float)mhz;
32
		if (outcounter >= 10) { // A value of 9 here is closer to reality, but hardware
33
		                        // can take slightly longer depending on clock-alignment.
34
								// 10 cycles here should be safe and won't succeed in emulation
35
								// while failing on hardware.
36
			busy = false;
37
			if (sdcard_attached) {
38
				received_byte = sdcard_handle(sending_byte);
39
			} else {
40
				received_byte = 0xff;
41
			}
42
		}
43
	}
44
}
45
46
uint8_t
47
vera_spi_read(uint8_t reg)
48
{
49
	switch (reg) {
50
		case 0:
51
			if (autotx && ss && !busy) {
52
				// autotx mode will automatically send $FF after each read
53
				sending_byte = 0xff;
54
				busy = true;
55
				outcounter = 0;
56
			}
57
			return received_byte;
58
		case 1:
59
			return busy << 7 | autotx << 2 | ss;
60
	}
61
	return 0;
62
}
63
64
// The same registers, without the side effect. Reading $9F3E normally starts
65
// the next autotx transfer; a debugger showing memory must be able to look at
66
// it without taking a byte out of the transfer the machine is in the middle of.
67
uint8_t
68
vera_spi_peek(uint8_t reg)
69
{
70
	switch (reg) {
71
		case 0:
72
			return received_byte;
73
		case 1:
74
			return busy << 7 | autotx << 2 | ss;
75
	}
76
	return 0;
77
}
78
79
void
80
vera_spi_write(uint8_t reg, uint8_t value)
81
{
82
	switch (reg) {
83
		case 0:
84
			if (ss && !busy) {
85
				sending_byte = value;
86
				busy = true;
87
				outcounter = 0;
88
			}
89
			break;
90
		case 1:
91
			if (ss != (value & 1)) {
92
				ss = value & 1;
93
				if (ss) {
94
					sdcard_select(ss);
95
				}
96
			}
97
			autotx = !!(value & 4);
98
			break;
99
	}
100
}
101
102
// Side-effect-free snapshot of SPI state for the ImGui debugger.
103
void
104
vera_spi_debug_get_state(vera_spi_debug_state_t *out)
105
{
106
	out->ss            = ss;
107
	out->busy          = busy;
108
	out->autotx        = autotx;
109
	out->sending_byte  = sending_byte;
110
	out->received_byte = received_byte;
111
	out->outcounter    = outcounter;
112
}