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