1+ #include <string.h>
2+ #include <stdio.h>
3+
4+ #include "eeprom.h"
5+
6+ uint16_t default_data [32 ] = {
7+ 0x6D76 , 0x6361 , 0x3130 , 0x0207 ,
8+ 0x0000 , 0x0000 , 0x0000 , 0x0000 ,
9+ 0x0000 , 0x1000 , 0x0000 , 0x0000 ,
10+ 0x0000 , 0x0000 , 0x0000 , 0x0000 ,
11+ 0x0010 , 0x0000 , 0x0000 , 0x0000 ,
12+ 0x0000 , 0x0000 , 0x0000 , 0x0000 ,
13+ 0x1000 , 0x0000 , 0x0000 , 0x0000 ,
14+ 0x0000 , 0x0000 , 0x0000 , 0x0000
15+ };
16+
17+ struct ps2_eeprom * ps2_eeprom_create (void ) {
18+ return malloc (sizeof (struct ps2_eeprom ));
19+ }
20+
21+ void ps2_eeprom_init (struct ps2_eeprom * eeprom ) {
22+ memset (eeprom , 0 , sizeof (struct ps2_eeprom ));
23+
24+ memcpy (eeprom -> buf , default_data , 32 * sizeof (uint16_t ));
25+ }
26+
27+ void ps2_eeprom_load (struct ps2_eeprom * eeprom , const uint16_t * data ) {
28+ memcpy (eeprom -> buf , data , 32 * sizeof (uint16_t ));
29+ }
30+
31+ void ps2_eeprom_destroy (struct ps2_eeprom * eeprom ) {
32+ free (eeprom );
33+ }
34+
35+ uint64_t ps2_eeprom_read (struct ps2_eeprom * eeprom ) {
36+ return eeprom -> dout << PP_DOUT ;
37+ }
38+
39+ void eeprom_step (struct ps2_eeprom * eeprom ) {
40+ switch (eeprom -> state ) {
41+ case EEPROM_S_CMD_START : {
42+ eeprom -> sequence = 0 ;
43+
44+ if (eeprom -> din ) {
45+ eeprom -> state = EEPROM_S_CMD_READ ;
46+ }
47+ } break ;
48+
49+ case EEPROM_S_CMD_READ : {
50+ eeprom -> cmd |= eeprom -> din << (1 - eeprom -> sequence );
51+ eeprom -> sequence ++ ;
52+
53+ if (eeprom -> sequence == 2 ) {
54+ eeprom -> sequence = 0 ;
55+ eeprom -> state = EEPROM_S_ADDR_READ ;
56+ }
57+ } break ;
58+
59+ case EEPROM_S_ADDR_READ : {
60+ // Address read in from highest bit to lowest bit
61+ eeprom -> addr |= eeprom -> din << (5 - eeprom -> sequence );
62+
63+ // Don't know what the behaviour would be but lets prevent oob.
64+ eeprom -> addr = eeprom -> addr & 31 ;
65+
66+ eeprom -> sequence ++ ;
67+ if (eeprom -> sequence == 6 )
68+ {
69+ eeprom -> state = EEPROM_S_TRANSMIT ;
70+ eeprom -> sequence = 0 ;
71+ }
72+ } break ;
73+
74+ // fire away, bit position increments every pulse
75+ case EEPROM_S_TRANSMIT : {
76+ if (eeprom -> cmd == PP_OP_READ ) {
77+ eeprom -> dout = (eeprom -> buf [eeprom -> addr ] >> (15 - eeprom -> sequence )) & 1 ;
78+ }
79+
80+ if (eeprom -> cmd == PP_OP_WRITE ) {
81+ eeprom -> buf [eeprom -> addr ] = eeprom -> buf [eeprom -> addr ] | (eeprom -> din << (15 - eeprom -> sequence ));
82+ }
83+
84+ eeprom -> sequence ++ ;
85+
86+ if (eeprom -> sequence == 16 ) {
87+ eeprom -> sequence = 0 ;
88+
89+ // Let's prevent oob here too
90+ eeprom -> addr = (eeprom -> addr + 1 ) & 31 ;
91+ }
92+ } break ;
93+ }
94+ return ;
95+ }
96+
97+ void ps2_eeprom_write (struct ps2_eeprom * eeprom , uint64_t data ) {
98+ uint8_t csel = (data >> PP_CSEL ) & 1 ;
99+ uint8_t sclk = (data >> PP_SCLK ) & 1 ;
100+ uint8_t din = (data >> PP_DIN ) & 1 ;
101+
102+ if (!csel ) {
103+ eeprom -> sequence = 0 ;
104+ eeprom -> addr = 0 ;
105+ eeprom -> state = EEPROM_S_CMD_START ;
106+ eeprom -> clk = 0 ;
107+
108+ return ;
109+ }
110+
111+ eeprom -> din = din ;
112+
113+ if (sclk && !eeprom -> clk ) {
114+ eeprom_step (eeprom );
115+ }
116+
117+ eeprom -> clk = sclk ;
118+ }
0 commit comments