1 /*
2 Copyright (C) 2006 Roy R Rankin
3
4 This file is part of the libgpsim library of gpsim
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library 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 GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, see
18 <http://www.gnu.org/licenses/lgpl-2.1.html>.
19 */
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <iostream>
24 #include "../config.h"
25 #include "stimuli.h"
26 #include "psp.h"
27
28 //#define DEBUG
29 #if defined(DEBUG)
30 #define Dprintf(arg) {printf("%s:%d-%s() ",__FILE__,__LINE__,__FUNCTION__); printf arg; }
31 #else
32 #define Dprintf(arg) {}
33 #endif
34
35 //--------------------------------------------------
36 //
37 //--------------------------------------------------
38
39
40 class CS_SignalSink : public SignalSink {
41 public:
CS_SignalSink(PSP * _psp)42 explicit CS_SignalSink(PSP *_psp)
43 : m_psp(_psp)
44 {
45 assert(_psp);
46 }
release()47 virtual void release()
48 {
49 delete this;
50 }
51
setSinkState(char new3State)52 void setSinkState(char new3State)
53 {
54 m_psp->setCS_State(new3State);
55 }
56
57 private:
58 PSP *m_psp;
59 };
60
61
62 class RD_SignalSink : public SignalSink {
63 public:
RD_SignalSink(PSP * _psp)64 explicit RD_SignalSink(PSP *_psp)
65 : m_psp(_psp)
66 {
67 assert(_psp);
68 }
release()69 virtual void release()
70 {
71 delete this;
72 }
73
setSinkState(char new3State)74 void setSinkState(char new3State)
75 {
76 m_psp->setRD_State(new3State);
77 }
78
79 private:
80 PSP *m_psp;
81 };
82
83
84 class WR_SignalSink : public SignalSink {
85 public:
WR_SignalSink(PSP * _psp)86 explicit WR_SignalSink(PSP *_psp)
87 : m_psp(_psp)
88 {
89 assert(_psp);
90 }
release()91 virtual void release()
92 {
93 delete this;
94 }
95
setSinkState(char new3State)96 void setSinkState(char new3State)
97 {
98 m_psp->setWR_State(new3State);
99 }
100
101 private:
102 PSP *m_psp;
103 };
104
105
106 /*
107 * Some devices use high bits of a TRIS register, but others
108 * have a dedicated PSPCON register which is defined here
109 */
110
PSPCON(Processor * pCpu,const char * pName,const char * pDesc)111 PSPCON::PSPCON(Processor *pCpu, const char *pName, const char *pDesc)
112 : sfr_register(pCpu, pName, pDesc)
113 {
114 }
115
116
put(unsigned int new_value)117 void PSPCON::put(unsigned int new_value)
118 {
119 unsigned int mask = (PSP::OBF | PSP::IBF | 0x0f);
120 unsigned int fixed;
121 trace.raw(write_trace.get() | value.data);
122
123 if (!(new_value & PSP::PSPMODE)) {
124 fixed = 0;
125
126 } else {
127 fixed = value.data & mask;
128 }
129
130 value.data = (new_value & ~mask) | fixed;
131 }
132
133
put_value(unsigned int new_value)134 void PSPCON::put_value(unsigned int new_value)
135 {
136 trace.raw(write_trace.get() | value.data);
137 value.data = new_value;
138 }
139
140
141 //
142 // setup information for PSP module
143 //
initialize(PIR_SET * _pir_set,PicPSP_PortRegister * _port_set,PicTrisRegister * _port_tris,sfr_register * _pspcon,PinModule * pin_RD,PinModule * pin_WR,PinModule * pin_CS)144 void PSP::initialize(PIR_SET *_pir_set, PicPSP_PortRegister *_port_set,
145 PicTrisRegister *_port_tris, sfr_register *_pspcon,
146 PinModule *pin_RD, PinModule *pin_WR, PinModule *pin_CS)
147 {
148 if (verbose & 2) {
149 std::cout << "PSP::initialize called\n";
150 }
151
152 pir_set = _pir_set;
153 parallel_port = _port_set;
154 parallel_port->setPSP(this);
155 parallel_tris = _port_tris;
156 cntl_tris = _pspcon;
157
158 //
159 // The rest of this function allows catching of changes to PSP contol signals
160 //
161 if (!m_rd_sink) {
162 m_rd_sink = new RD_SignalSink(this);
163 Not_RD = pin_RD;
164
165 if (Not_RD) {
166 Not_RD->addSink(m_rd_sink);
167 }
168 }
169
170 if (!m_cs_sink) {
171 m_cs_sink = new CS_SignalSink(this);
172 Not_CS = pin_CS;
173
174 if (Not_CS) {
175 Not_CS->addSink(m_cs_sink);
176 }
177 }
178
179 if (!m_wr_sink) {
180 m_wr_sink = new WR_SignalSink(this);
181 Not_WR = pin_WR;
182
183 if (Not_WR) {
184 Not_WR->addSink(m_wr_sink);
185 }
186 }
187 }
188
189
190 //
191 // process changes on the control pins
192 //
state_control()193 void PSP::state_control()
194 {
195 if (! pspmode()) {
196 return;
197 }
198
199 if (verbose & 2) {
200 std::cout << "PSP state change cs=" << cs << " wr=" << wr << " rd=" << rd << '\n';
201 }
202
203 if (rd && wr && cs) { // this is an error condition
204 std::cerr << "PSP: Error CS, WR and RD must not all be low\n";
205 parallel_tris->put(0xff);
206 state = ST_INACTIVE;
207 return;
208
209 } else if (cs && rd) {
210 parallel_tris->put(0);
211 parallel_port->put_value(put_value);
212 cntl_tris->put_value(cntl_tris->get() & ~OBF);
213 state = ST_READ;
214
215 } else if (cs && wr) {
216 parallel_tris->put(0xff);
217 get_value = parallel_port->get_value();
218 state = ST_WRITE;
219
220 } else {
221 if (state != ST_INACTIVE) {
222 pir_set->set_pspif();
223 }
224
225 //
226 // On first bus write set IBF flag.
227 // if a second bus write occurs prior to read of pic port (portd)
228 // IBOV flag is also set.
229 //
230 if (state == ST_WRITE) {
231 unsigned int trise_val = cntl_tris->get();
232
233 if (trise_val & IBF) {
234 cntl_tris->put_value(trise_val | IBOV);
235
236 } else {
237 cntl_tris->put_value(trise_val | IBF);
238 }
239 }
240
241 parallel_tris->put(0xff);
242 state = ST_INACTIVE;
243 }
244 }
245
246
247 //
248 // The next three functions are called when their control pin change state
249 // The control pins are active low which is converted to active high signals
setRD_State(char new3State)250 void PSP::setRD_State(char new3State)
251 {
252 rd = new3State == '0';
253 state_control();
254 }
255
256
setCS_State(char new3State)257 void PSP::setCS_State(char new3State)
258 {
259 cs = new3State == '0';
260 state_control();
261 }
262
263
setWR_State(char new3State)264 void PSP::setWR_State(char new3State)
265 {
266 wr = new3State == '0';
267 state_control();
268 }
269
270
271 //
272 // psp_put is called on write to portd when pspmode is active
273 // set OBF register bit and save value for next bus read
274 //
psp_put(unsigned int new_value)275 void PSP::psp_put(unsigned int new_value)
276 {
277 cntl_tris->put_value(cntl_tris->get() | OBF);
278 put_value = new_value;
279 }
280
281
282 //
283 // psp_get is called on read of portd when pspmode is active so
284 // we can clear the IBF flag
285 //
psp_get()286 unsigned int PSP::psp_get()
287 {
288 cntl_tris->put_value(cntl_tris->get() & ~IBF);
289 return get_value;
290 }
291