-
Notifications
You must be signed in to change notification settings - Fork 42
/
psxSPI.pio
153 lines (126 loc) · 5.23 KB
/
psxSPI.pio
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
153
; Author: Daniele Giuliani
; Interfaces with the modified SPI protocol used by
; PSX to communicate with controller/memory cards
.define PUBLIC PIN_DAT 5
.define PUBLIC PIN_CMD 6
.define PUBLIC PIN_SEL 7
.define PUBLIC PIN_CLK 8
.define PUBLIC PIN_ACK 9
.program cmd_reader
; Input pins mapping:
; 0 - CMD
; Program description:
; Samples CMD line during rising clock edges,
; waits for SEL low signal before starting execution
sel_high:
wait 0 gpio PIN_SEL ; wait for SEL to go low
set x, 7 ; set the bit counter
.wrap_target
wait 0 gpio PIN_CLK ; wait for clock to fall
wait 1 gpio PIN_CLK ; wait for rising clock edge
in pins 1 ; sample 1 bit from CMD line
.wrap
.program dat_reader
; Input pins mapping:
; 0 - DAT
; Program description:
; Samples DAT line during rising clock edges,
; waits for SEL pin to be low before starting execution.
; Can be used for sniffing DAT line used by other hardware.
sel_high:
wait 0 gpio PIN_SEL ; wait for SEL to go low
.wrap_target
wait 0 gpio PIN_CLK ; wait for clock to fall
wait 1 gpio PIN_CLK ; wait for rising clock edge
in pins 1 ; sample 1 bit form DAT line
.wrap
.program dat_writer
.side_set 1 pindirs
; Set pins mapping:
; 0 - DAT
; Output pins mapping:
; 0 - DAT
; Sideset pins mapping:
; 0 - ACK
; Program description:
; Asserts ACK (signaling that the memory card must send something)
; and outputs bits to the DAT line on falling clock edges.
; waits for SEL low signal before starting execution.
; Bits are outputted by changing pin direction:
; 0 -> set pin as input (Hi-Z) -> output a one
; 1 -> set pin as output low -> output a zero
set pindirs, 0 side 0 ; release DAT line (set pin as input = Hi-Z)
wait 0 gpio PIN_SEL side 0 ; wait for SEL to go low
.wrap_target
pull side 0 ; manual pull in order to stall SM if TX fifo is empty
nop side 1 [5] ; start ACK
set x, 7 side 0 [5] ; stop ACK delay and set bit counter
sendbit:
wait 1 gpio PIN_CLK side 0 ; stop ACK and check clock is high (sideset completes even if instruction stalls)
wait 0 gpio PIN_CLK side 0 ; wait for falling clock edge
out pindirs 1 side 0 ; output 1 bit
jmp x-- sendbit side 0 ; count and send 8 bits
.wrap
% c-sdk {
#define SLOW_CLKDIV 50 // 125MHz divided down to 2.5 MHz - we need this so we don't count clocks not meant for us on systems like the PS2
static inline void cmd_reader_program_init(PIO pio, uint sm, uint offset) {
pio_sm_config c = cmd_reader_program_get_default_config(offset);
/* Pin Configuration */
sm_config_set_in_pins(&c, PIN_CMD);
pio_sm_set_consecutive_pindirs(pio, sm, PIN_CMD, 1, false);
pio_sm_set_consecutive_pindirs(pio, sm, PIN_SEL, 1, false);
pio_sm_set_consecutive_pindirs(pio, sm, PIN_CLK, 1, false);
/* Fifo Configuration */
sm_config_set_in_shift(&c, true, true, 8); // shift ISR to right, autopush every 8 bits
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); // join RX FIFO
/* Clock configuration */
sm_config_set_clkdiv_int_frac(&c, SLOW_CLKDIV, 0x00);
/* Initialize SM */
pio_sm_init(pio, sm, offset, &c);
}
static inline void dat_reader_program_init(PIO pio, uint sm, uint offset) {
pio_sm_config c = dat_reader_program_get_default_config(offset);
/* Pin Configuration */
sm_config_set_in_pins(&c, PIN_DAT);
pio_sm_set_consecutive_pindirs(pio, sm, PIN_DAT, 1, false);
pio_sm_set_consecutive_pindirs(pio, sm, PIN_SEL, 1, false);
pio_sm_set_consecutive_pindirs(pio, sm, PIN_CLK, 1, false);
/* Fifo Configuration */
sm_config_set_in_shift(&c, true, true, 8); // shift ISR to right, autopush every 8 bits
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); // join RX FIFO
/* Clock configuration */
sm_config_set_clkdiv_int_frac(&c, SLOW_CLKDIV, 0x00);
/* Initialize SM */
pio_sm_init(pio, sm, offset, &c);
}
static inline void dat_writer_program_init(PIO pio, uint sm, uint offset) {
pio_sm_config c = dat_writer_program_get_default_config(offset);
/* Pin Configuration */
sm_config_set_out_pins(&c, PIN_DAT, 1); // set base OUT pin (DAT)
sm_config_set_set_pins(&c, PIN_DAT, 1); // set base SET pin (DAT)
sm_config_set_sideset_pins(&c, PIN_ACK); // set base SIDESET pin (ACK)
/* configure DAT pin for open drain (output low but set as input initially) */
pio_sm_set_pins_with_mask(pio, sm, 0, 1 << PIN_DAT);
pio_sm_set_consecutive_pindirs(pio, sm, PIN_DAT, 1, false);
pio_gpio_init(pio, PIN_DAT);
/* configure ACK pin for open drain (output low but set as input initially) */
pio_sm_set_pins_with_mask(pio, sm, 0, 1 << PIN_ACK);
pio_sm_set_consecutive_pindirs(pio, sm, PIN_ACK, 1, false);
pio_gpio_init(pio, PIN_ACK);
pio_sm_set_consecutive_pindirs(pio, sm, PIN_SEL, 1, false);
pio_sm_set_consecutive_pindirs(pio, sm, PIN_CLK, 1, false);
/* FIFO Configuration */
sm_config_set_out_shift(&c, true, true, 8); // shift OSR to right, autopull every 8 bits
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); // join TX FIFO
/* Clock configuration */
sm_config_set_clkdiv_int_frac(&c, SLOW_CLKDIV, 0x00);
/* Initialize SM */
pio_sm_init(pio, sm, offset, &c);
}
static inline uint8_t read_byte_blocking(PIO pio, uint sm) {
return (uint8_t) (pio_sm_get_blocking(pio, sm) >> 24);
}
static inline void write_byte_blocking(PIO pio, uint sm, uint32_t byte) {
pio_sm_put_blocking(pio, sm, ~byte & 0xFF); // invert bits (0 become 1 setting the output to low)
}
%}