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