/[dynamips]/trunk/nmc93cX6.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/nmc93cX6.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations)
Sat Oct 6 16:45:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 6498 byte(s)
make working copy

1 dpavlin 8 /*
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 */
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 */
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 */
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 dpavlin 11 if (g->dout_status == EEPROM_DOUT_HIGH)
58     g->state[i].dataout_val = 1;
59 dpavlin 8
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 dpavlin 11 //g->state[i].dataout_val = 1;
73 dpavlin 8
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 */
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 dpavlin 11 old, new, clk_bit, 1 << clk_bit, check_bit(old,new,clk_bit));
100 dpavlin 8 }
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 dpavlin 11 /* 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 dpavlin 8 /* 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 dpavlin 11 if (g->state[group_id].cmd_len == cmd_len)
123 dpavlin 8 {
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 dpavlin 11
134 dpavlin 8 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 dpavlin 11 * extract address (6/9 bits) from command.
152 dpavlin 8 */
153    
154     cmd = g->state[group_id].cmd_val;
155     addr = nmc94cX6_get_addr(g,cmd);
156    
157     #if DEBUG_EEPROM
158 dpavlin 11 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 dpavlin 8 g->description,group_id,addr,addr,
162 dpavlin 11 g->state[group_id].cmd_val,
163     g->eeprom[group_id]);
164     }
165 dpavlin 8 #endif
166    
167     pos = g->state[group_id].dataout_pos++;
168 dpavlin 11
169     if (g->reverse_data)
170     pos = 15 - pos;
171    
172 dpavlin 8 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 */
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 */
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 dpavlin 11 /* Returns the TRUE if the EEPROM is active */
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 */
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 dpavlin 8 /* Handle read */
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    

  ViewVC Help
Powered by ViewVC 1.1.26