1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4 *
5 * NMC93C46/NMC93C56 Serial EEPROM.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12
13 #include "nmc93cX6.h"
14
15 #define DEBUG_EEPROM 0
16
17 /* Internal states */
18 enum {
19 EEPROM_STATE_INACTIVE = 0,
20 EEPROM_STATE_WAIT_CMD,
21 EEPROM_STATE_DATAOUT,
22 };
23
24 /* Get command length for the specified group */
nmc94cX6_get_cmd_len(struct nmc93cX6_group * g)25 static u_int nmc94cX6_get_cmd_len(struct nmc93cX6_group *g)
26 {
27 switch(g->eeprom_type) {
28 case EEPROM_TYPE_NMC93C46:
29 return(NMC93C46_CMD_BITLEN);
30 case EEPROM_TYPE_NMC93C56:
31 return(NMC93C56_CMD_BITLEN);
32 default:
33 return(0);
34 }
35 }
36
37 /* Extract EEPROM data address */
nmc94cX6_get_addr(struct nmc93cX6_group * g,u_int cmd)38 static u_int nmc94cX6_get_addr(struct nmc93cX6_group *g,u_int cmd)
39 {
40 switch(g->eeprom_type) {
41 case EEPROM_TYPE_NMC93C46:
42 return((cmd >> 3) & 0x3f);
43 case EEPROM_TYPE_NMC93C56:
44 return(m_reverse_u8((cmd >> 3) & 0xff));
45 default:
46 return(0);
47 }
48 }
49
50 /* Check chip select */
nmc93cX6_check_cs(struct nmc93cX6_group * g,u_int old,u_int new)51 static void nmc93cX6_check_cs(struct nmc93cX6_group *g,u_int old,u_int new)
52 {
53 int i,res;
54
55 for(i=0;i<g->nr_eeprom;i++)
56 {
57 if (g->dout_status == EEPROM_DOUT_HIGH)
58 g->state[i].dataout_val = 1;
59
60 if (g->debug)
61 {
62 printf("EEPROM %s(%d): check_cs: check_bit(old,new,select_bit) "
63 "[%8.8x, %8.8x, %d (mask = %8.8x)] = %d\n",
64 g->description, i,
65 old, new, g->def[i]->select_bit, 1 << g->def[i]->select_bit,
66 check_bit(old,new,g->def[i]->select_bit));
67 }
68
69 if ((res = check_bit(old,new,g->def[i]->select_bit)) != 0) {
70 g->state[i].cmd_len = 0; /* no bit for command sent now */
71 g->state[i].cmd_val = 0;
72 //g->state[i].dataout_val = 1;
73
74 if (res == 2)
75 g->state[i].state = EEPROM_STATE_WAIT_CMD;
76 else
77 g->state[i].state = EEPROM_STATE_INACTIVE;
78 }
79 }
80 }
81
82 /* Check clock set for a specific group */
nmc93cX6_check_clk_group(struct nmc93cX6_group * g,int group_id,u_int old,u_int new)83 static void nmc93cX6_check_clk_group(struct nmc93cX6_group *g,int group_id,
84 u_int old,u_int new)
85 {
86 struct cisco_eeprom *eeprom;
87 u_int cmd,op,addr,pos;
88 u_int clk_bit, din_bit;
89 u_int cmd_len;
90
91 clk_bit = g->def[group_id]->clock_bit;
92 din_bit = g->def[group_id]->din_bit;
93
94 if (g->debug)
95 {
96 printf("EEPROM %s(%d): check_clk: check_bit(old,new,select_bit) "
97 "[%8.8x, %8.8x, %d (mask = %8.8x)] = %d\n",
98 g->description, group_id,
99 old, new, clk_bit, 1 << clk_bit, check_bit(old,new,clk_bit));
100 }
101
102 /* CLK bit set ? */
103 if (check_bit(old,new,clk_bit) != 2)
104 return;
105
106 switch(g->state[group_id].state)
107 {
108 case EEPROM_STATE_WAIT_CMD:
109 /* The first bit must be set to "1" */
110 if ((g->state[group_id].cmd_len == 0) && !(new & (1 << din_bit)))
111 break;
112
113 /* Read DATAIN bit */
114 if (new & (1 << din_bit))
115 g->state[group_id].cmd_val |= (1 << g->state[group_id].cmd_len);
116
117 g->state[group_id].cmd_len++;
118
119 cmd_len = nmc94cX6_get_cmd_len(g);
120
121 /* Command is complete ? */
122 if (g->state[group_id].cmd_len == cmd_len)
123 {
124 #if DEBUG_EEPROM
125 printf("nmc93cX6: %s(%d): command = %x\n",
126 g->description,group_id,g->state[group_id].cmd_val);
127 #endif
128 g->state[group_id].cmd_len = 0;
129
130 /* we have the command! extract the opcode */
131 cmd = g->state[group_id].cmd_val;
132 op = cmd & 0x7;
133
134 switch(op) {
135 case NMC93CX6_CMD_READ:
136 g->state[group_id].state = EEPROM_STATE_DATAOUT;
137 g->state[group_id].dataout_pos = 0;
138 break;
139 #if DEBUG_EEPROM
140 default:
141 printf("nmc93cX6: unhandled opcode %d\n",op);
142 #endif
143 }
144 }
145
146 break;
147
148 case EEPROM_STATE_DATAOUT:
149 /*
150 * user want to read data. we read 16-bits.
151 * extract address (6/9 bits) from command.
152 */
153
154 cmd = g->state[group_id].cmd_val;
155 addr = nmc94cX6_get_addr(g,cmd);
156
157 #if DEBUG_EEPROM
158 if (g->state[group_id].dataout_pos == 0) {
159 printf("nmc93cX6: %s(%d): "
160 "read addr=%x (%d), val=%4.4x [eeprom=%p]\n",
161 g->description,group_id,addr,addr,
162 g->state[group_id].cmd_val,
163 g->eeprom[group_id]);
164 }
165 #endif
166
167 pos = g->state[group_id].dataout_pos++;
168
169 if (g->reverse_data)
170 pos = 15 - pos;
171
172 eeprom = g->eeprom[group_id];
173
174 if (eeprom && eeprom->data && (addr < eeprom->len)) {
175 g->state[group_id].dataout_val = eeprom->data[addr] & (1 << pos);
176 } else {
177 /* access out of bounds */
178 g->state[group_id].dataout_val = (1 << pos);
179 }
180
181 if (g->state[group_id].dataout_pos == NMC93CX6_CMD_DATALEN) {
182 g->state[group_id].state = EEPROM_STATE_INACTIVE;
183 g->state[group_id].dataout_pos = 0;
184 }
185 break;
186
187 #if DEBUG_EEPROM
188 default:
189 printf("nmc93cX6: unhandled state %d\n",g->state[group_id].state);
190 #endif
191 }
192 }
193
194 /* Check clock set for all group */
nmc93cX6_check_clk(struct nmc93cX6_group * g,u_int old,u_int new)195 void nmc93cX6_check_clk(struct nmc93cX6_group *g,u_int old,u_int new)
196 {
197 int i;
198
199 for(i=0;i<g->nr_eeprom;i++)
200 nmc93cX6_check_clk_group(g,i,old,new);
201 }
202
203 /* Handle write */
nmc93cX6_write(struct nmc93cX6_group * g,u_int data)204 void nmc93cX6_write(struct nmc93cX6_group *g,u_int data)
205 {
206 u_int new = data, old = g->eeprom_reg;
207
208 nmc93cX6_check_cs(g,old,new);
209 nmc93cX6_check_clk(g,old,new);
210 g->eeprom_reg = new;
211 }
212
213 /* Returns the TRUE if the EEPROM is active */
nmc93cX6_is_active(struct nmc93cX6_group * g,u_int group_id)214 u_int nmc93cX6_is_active(struct nmc93cX6_group *g,u_int group_id)
215 {
216 return(g->eeprom_reg & (1 << g->def[group_id]->select_bit));
217 }
218
219 /* Returns the DOUT bit value */
nmc93cX6_get_dout(struct nmc93cX6_group * g,u_int group_id)220 u_int nmc93cX6_get_dout(struct nmc93cX6_group *g,u_int group_id)
221 {
222 if (g->state[group_id].dataout_val)
223 return(1 << g->def[group_id]->dout_bit);
224 else
225 return(0);
226 }
227
228 /* Handle read */
nmc93cX6_read(struct nmc93cX6_group * g)229 u_int nmc93cX6_read(struct nmc93cX6_group *g)
230 {
231 u_int res;
232 int i;
233
234 res = g->eeprom_reg;
235
236 for(i=0;i<g->nr_eeprom;i++) {
237 if (!(g->eeprom_reg & (1 << g->def[i]->select_bit)))
238 continue;
239
240 if (g->state[i].dataout_val)
241 res |= 1 << g->def[i]->dout_bit;
242 else
243 res &= ~(1 << g->def[i]->dout_bit);
244 }
245
246 return(res);
247 }
248
249