1 /*
2    Copyright (C) 2015 Roy R Rankin
3 
4 This file is part of gpsim.
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20 
21 /*
22     This module simulates a 7 bit address slave I2C device with an 8 bit
23     I/O bus. The direction of the 8 bit bus is controlled by the R/W bit
24     sent from the master.
25 
26     This module allows multi-pin devices such as LCD displays to be
27     connected to the processor via the 2 pin I2C bus.
28 */
29 
30 #include <cstdio>
31 
32 //#define DEBUG
33 #if defined(DEBUG)
34 #define Dprintf(arg) {printf("%s:%d ",__FILE__,__LINE__); printf arg; }
35 #else
36 #define Dprintf(arg) {}
37 #endif
38 
39 #include "config.h"    // get the definition for HAVE_GUI
40 #ifdef HAVE_GUI
41 #include <gtk/gtk.h>
42 #endif
43 
44 #include "src/gpsim_time.h"
45 #include "src/stimuli.h"
46 #include "src/ioports.h"
47 #include "src/symbol.h"
48 #include "src/value.h"
49 #include "src/packages.h"
50 #include "src/gpsim_interface.h"
51 #include "i2c2par.h"
52 
53 
54 class AddAttribute : public Integer {
55 public:
56   I2C2PAR_Modules::i2c2par *i2cpt;
57 
AddAttribute(I2C2PAR_Modules::i2c2par * _i2cpt)58   explicit AddAttribute(I2C2PAR_Modules::i2c2par *_i2cpt) :
59     Integer("Slave_Address", 0x27, "I2C Slave Address"), i2cpt(_i2cpt)
60   {
61     gint64 v;
62     Integer::get(v);
63     set(v);
64   }
set(gint64 v)65   virtual void set(gint64 v)
66   {
67     Integer::set(v);
68 
69     if (i2cpt) {
70       i2cpt->i2c_slave_address = (v << 1);
71     }
72   }
73 };
74 
75 
76 class IOPort : public PortModule
77 //class IOPort : public PortRegister
78 {
79 public:
80   unsigned int direction;
81 
82   //    virtual void put(unsigned int new_value);
83   explicit IOPort(unsigned int _num_iopins = 8);
84   void update_pin_directions(unsigned int);
85   void put(unsigned int);
86   unsigned int get();
87 };
88 
89 
90 //IOPort::IOPort(unsigned int _num_iopins) : PortRegister(_num_iopins, "P", "")
IOPort(unsigned int _num_iopins)91 IOPort::IOPort(unsigned int _num_iopins)
92   : PortModule(_num_iopins), direction(0)
93 {
94 }
95 
96 
put(unsigned int value)97 void IOPort::put(unsigned int value)
98 {
99   for (int i = 0; i < 8; i++) {
100     IOPIN *m_pin;
101 
102     unsigned int bit = 1 << i;
103 
104     if ((m_pin = getPin(i))) {
105       m_pin->putState((value & bit) == bit);
106     }
107   }
108 }
109 
110 
get()111 unsigned int IOPort::get()
112 {
113   unsigned int value = 0;
114 
115   for (int i = 0; i < 8; i++) {
116     IOPIN *m_pin;
117 
118     unsigned int bit = 1 << i;
119 
120     if ((m_pin = getPin(i))) {
121       if (m_pin->getState()) {
122         value |= bit;
123       }
124     }
125   }
126 
127   return value;
128 }
129 
130 
update_pin_directions(unsigned int new_direction)131 void IOPort::update_pin_directions(unsigned int new_direction)
132 {
133   if ((new_direction ^ direction) & 1) {
134     direction = new_direction & 1;
135 
136     for (int i = 0; i < 8; i++) {
137       IOPIN *m_pin;
138 
139       if ((m_pin = getPin(i))) {
140         m_pin->update_direction(direction, true);
141 
142         if (m_pin->snode) {
143           m_pin->snode->update();
144         }
145       }
146     }
147   }
148 }
149 
150 
151 namespace I2C2PAR_Modules {
152 
i2c2par(const char * _name)153 i2c2par::i2c2par(const char *_name)
154   : i2c_slave(), Module(_name, "i2c2par")
155 {
156   io_port = new IOPort(8);
157   Addattr = new AddAttribute(this);
158   addSymbol(Addattr);
159   //Addattr->set(0x27);
160 }
161 
162 
~i2c2par()163 i2c2par::~i2c2par()
164 {
165   delete io_port;
166   delete Addattr;
167 
168   for (int i = 0; i < 8; i++) {
169     removeSymbol(pins[i]);
170   }
171 
172   delete [] pins;
173   removeSymbol((IOPIN *)scl);
174   removeSymbol((IOPIN *)sda);
175   // set sda, scl to zero as package deletes them,
176   // thus stopping ~i2c_slave from trying to delete them also
177   sda = nullptr;
178   scl = nullptr;
179 }
180 
181 
put_data(unsigned int data)182 void i2c2par::put_data(unsigned int data)
183 {
184   Dprintf(("i2c2par::put_data() 0x%x\n", data));
185   io_port->put(data);
186 }
187 
188 
get_data()189 unsigned int i2c2par::get_data()
190 {
191   Dprintf(("i2c2par::get_data() 0x%x\n", io_port->get()));
192   return io_port->get();
193 }
194 
195 
slave_transmit(bool input)196 void i2c2par::slave_transmit(bool input)
197 {
198   io_port->update_pin_directions(input == false);
199 }
200 
201 
match_address()202 bool i2c2par::match_address()
203 {
204   Dprintf(("i2c2par::match_address() 0x%x\n", xfr_data));
205   return ((xfr_data & 0xfe) == i2c_slave_address);
206 }
207 
208 
construct(const char * _new_name)209 Module *i2c2par::construct(const char *_new_name)
210 {
211   std::string att_name = _new_name;
212   i2c2par *pEE = new i2c2par(_new_name);
213   pEE->create_iopin_map();
214   return pEE;
215 }
216 
217 
create_iopin_map()218 void i2c2par::create_iopin_map()
219 {
220   pins = new IO_bi_directional_pu *[8];
221   char pin_name[] = "p0";
222   addSymbol((IOPIN *)sda);
223   addSymbol((IOPIN *)scl);
224   package = new Package(10);
225 
226   for (int i = 0; i < 8; i++) {
227     pin_name[1] = '0' + i;
228     pins[i] = new IO_bi_directional_pu(pin_name);
229     package->assign_pin(i < 4 ? i + 1 : i + 3, io_port->addPin(pins[i], i));
230     addSymbol(pins[i]);
231   }
232 
233   package->assign_pin(5, (IOPIN *)(sda));
234   package->assign_pin(6, (IOPIN *)(scl));
235 }
236 
237 
238 } // end of namespace I2C2PAR_Modules
239