~arcachofo/simulide/1.1.0

« back to all changes in this revision

Viewing changes to src/gui/circuitwidget/components/outputs/displays/ks0108.cpp

  • Committer: arcachofo
  • Date: 2021-01-01 14:23:42 UTC
  • Revision ID: arcachofo@simulide.com-20210101142342-ozfljnll44g5lbl3
Initial Commit 0.5.15-RC3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (C) 2016 by santiago González                               *
 
3
 *   santigoro@gmail.com                                                   *
 
4
 *                                                                         *
 
5
 *   This program is free software; you can redistribute it and/or modify  *
 
6
 *   it under the terms of the GNU General Public License as published by  *
 
7
 *   the Free Software Foundation; either version 3 of the License, or     *
 
8
 *   (at your option) any later version.                                   *
 
9
 *                                                                         *
 
10
 *   This program is distributed in the hope that it will be useful,       *
 
11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
13
 *   GNU General Public License for more details.                          *
 
14
 *                                                                         *
 
15
 *   You should have received a copy of the GNU General Public License     *
 
16
 *   along with this program; if not, see <http://www.gnu.org/licenses/>.  *
 
17
 *                                                                         *
 
18
 ***************************************************************************/
 
19
 
 
20
#include "itemlibrary.h"
 
21
#include "connector.h"
 
22
#include "simulator.h"
 
23
#include "ks0108.h"
 
24
 
 
25
static const char* Ks0108_properties[] = {
 
26
    QT_TRANSLATE_NOOP("App::Property","CS Active Low")
 
27
};
 
28
 
 
29
 
 
30
Component* Ks0108::construct( QObject* parent, QString type, QString id )
 
31
{
 
32
    return new Ks0108( parent, type, id );
 
33
}
 
34
 
 
35
LibraryItem* Ks0108::libraryItem()
 
36
{
 
37
    return new LibraryItem(
 
38
        tr( "Ks0108" ),
 
39
        tr( "Displays" ),
 
40
        "ks0108.png",
 
41
        "Ks0108",
 
42
        Ks0108::construct );
 
43
}
 
44
 
 
45
Ks0108::Ks0108( QObject* parent, QString type, QString id )
 
46
      : Component( parent, type, id )
 
47
      , eElement( (id+"-eElement") )
 
48
      , m_pinRst( 270, QPoint(-56, 56), id+"-PinRst" , 0, this )
 
49
      , m_pinCs2( 270, QPoint(-48, 56), id+"-PinCs2" , 0, this )
 
50
      , m_pinCs1( 270, QPoint(-40, 56), id+"-PinCs1" , 0, this )
 
51
      , m_pinEn ( 270, QPoint( 32, 56), id+"-PinEn"  , 0, this )
 
52
      , m_pinRW ( 270, QPoint( 40, 56), id+"-PinRW"  , 0, this )
 
53
      , m_pinDC ( 270, QPoint( 48, 56), id+"-PinDC"  , 0, this )
 
54
{
 
55
    Q_UNUSED( Ks0108_properties );
 
56
 
 
57
    m_graphical = true;
 
58
    
 
59
    m_area = QRectF( -74, -52, 148, 100 );
 
60
    m_csActLow = false;
 
61
    
 
62
    m_pinRst.setLabelText( " RST" );
 
63
    m_pinCs1.setLabelText( " CS1" );
 
64
    m_pinCs2.setLabelText( " CS2" );
 
65
    m_pinDC.setLabelText(  " RS" );
 
66
    m_pinRW.setLabelText(  " RW" );
 
67
    m_pinEn.setLabelText(  " En" );
 
68
    
 
69
    m_dataPin.resize( 8 );
 
70
    m_dataeSource.resize( 8 );
 
71
    m_pin.resize( 14 );
 
72
    
 
73
    int pinY = 56;
 
74
    
 
75
    for( int i=0; i<8; i++ )
 
76
    {
 
77
        QString pinId = id+"-dataPin"+QString::number(i);
 
78
        m_dataPin[i] = new Pin( 270, QPoint(-32+(7-i)*8, pinY), pinId , 0, this );
 
79
        m_dataPin[i]->setLabelText( " D"+QString::number(i) );
 
80
 
 
81
        pinId.append(QString("-eSource"));
 
82
        m_dataeSource[i] = new eSource( pinId, m_dataPin[i] );
 
83
        m_dataeSource[i]->setVoltHigh( 5 );
 
84
        m_dataeSource[i]->setImp( high_imp );
 
85
 
 
86
        m_pin[i] = m_dataPin[i];
 
87
    }
 
88
    m_pin[8]  = &m_pinRst;
 
89
    m_pin[9]  = &m_pinCs2;
 
90
    m_pin[10] = &m_pinCs1;
 
91
    m_pin[11] = &m_pinEn;
 
92
    m_pin[12] = &m_pinRW;
 
93
    m_pin[13] = &m_pinDC;
 
94
    
 
95
    m_pdisplayImg = new QImage( 128, 64, QImage::Format_MonoLSB );
 
96
    m_pdisplayImg->setColor( 1, qRgb(0,0,0));
 
97
    m_pdisplayImg->setColor( 0, qRgb(200,215,180) );
 
98
    
 
99
    Simulator::self()->addToUpdateList( this );
 
100
    
 
101
    setLabelPos( -32,-68, 0);
 
102
    setShowId( true );
 
103
    
 
104
    initialize();
 
105
}
 
106
 
 
107
Ks0108::~Ks0108(){}
 
108
 
 
109
void Ks0108::stamp()
 
110
{
 
111
    eNode* enode = m_pinEn.getEnode();// Register for Scl changes callback
 
112
    if( enode ) enode->voltChangedCallback( this ); 
 
113
    
 
114
    enode = m_pinRst.getEnode();       // Register for Rst changes callback
 
115
    if( enode ) enode->voltChangedCallback( this ); 
 
116
}
 
117
 
 
118
void Ks0108::initialize()
 
119
{
 
120
    clearDDRAM();
 
121
    clearLcd();
 
122
    reset() ;
 
123
    updateStep();
 
124
}
 
125
 
 
126
void Ks0108::voltChanged()                 // Called when En Pin changes 
 
127
{
 
128
    if( m_pinRst.getVolt()<2.5 ) reset();            // Reset Pin is Low
 
129
    else                         m_reset = false;
 
130
    
 
131
    bool Write = ( m_pinRW.getVolt()<2.5 );             // Read or Write
 
132
    if( m_Write != Write )               // Set Read or Write Impedances
 
133
    {
 
134
        m_Write = Write;
 
135
        double imped;
 
136
        if( Write ) imped = high_imp;               // Data bus as Input
 
137
        else        imped = 40;                    // Data bus as Output
 
138
        
 
139
        for( int i=0; i<8; i++ ) 
 
140
        {
 
141
            m_dataeSource[i]->setOut( false );
 
142
            m_dataeSource[i]->setImp( imped );
 
143
        }
 
144
    }
 
145
    
 
146
    bool Scl = (m_pinEn.getVolt()>2.5);
 
147
    
 
148
    if    ( Scl && !m_lastScl )            // This is a clock Rising Edge
 
149
    {
 
150
        m_lastScl = true;  
 
151
        if( Write ) return;                  // Only Read in Rising Edge
 
152
    }
 
153
    else if( !Scl && m_lastScl )          // This is a clock Falling edge
 
154
    {
 
155
        m_lastScl = false;  
 
156
        if( !Write ) return;               // Only Write in Falling Edge
 
157
    }
 
158
    else
 
159
    {
 
160
        m_lastScl = Scl;
 
161
        return;
 
162
    }
 
163
    m_input = 0;
 
164
    if( Write )
 
165
    {
 
166
        //qDebug()<<"Reading "<<m_input;
 
167
        for( int pin=0; pin<8; pin++ )                     // Read input
 
168
            if( m_dataPin[pin]->getVolt()>2.5 )
 
169
            {
 
170
                //qDebug()<<pin<<pow( 2, pin );
 
171
                m_input += pow( 2, pin );
 
172
            }
 
173
            //qDebug()<<"Data =  "<<m_input;
 
174
    }
 
175
    
 
176
    m_Cs1 =  (m_pinCs1.getVolt()>2.5);               // Half 1 selected?
 
177
    m_Cs2 =  (m_pinCs2.getVolt()>2.5);               // Half 2 selected?
 
178
    if( !m_Cs1 & !m_Cs2 ) m_Cs2 = true;
 
179
    
 
180
    if( m_csActLow )
 
181
    {
 
182
        m_Cs1 = !m_Cs1;
 
183
        m_Cs2 = !m_Cs2;
 
184
    }
 
185
    
 
186
    if( (m_pinDC.getVolt()>2.5)               )                  // Data
 
187
    {
 
188
        if( m_reset ) return;            // Can't erite data while Reset
 
189
        if( Write ) writeData( m_input );                  // Write Data
 
190
        else        ReadData();                             // Read Data
 
191
    }
 
192
    else                                                      // Command
 
193
    {
 
194
        if( Write )proccessCommand( m_input );          // Write Command
 
195
        else       ReadStatus();                          // Read Status
 
196
    }
 
197
}
 
198
 
 
199
void Ks0108::ReadData()
 
200
{
 
201
    int data = 0;
 
202
    if( m_Cs1 ) data = m_aDispRam[m_addrX1][m_addrY1];
 
203
    if( m_Cs2 ) data = m_aDispRam[m_addrX2][m_addrY2+64];
 
204
    //qDebug() << "Ks0108::ReadData()" << data;
 
205
    for( int i=0; i<8; i++ )
 
206
    {
 
207
        //qDebug() << "Ks0108::ReadData()" << i<<(data & 1)<<((data & 1)==1);
 
208
        m_dataeSource[i]->setOut( ((data & 1)==1) );
 
209
        m_dataeSource[i]->stampOutput();
 
210
        data >>= 1;
 
211
    }
 
212
}
 
213
 
 
214
void Ks0108::ReadStatus()
 
215
{
 
216
    for( int i=0; i<8; i++ ) 
 
217
    {
 
218
        bool out = false;
 
219
        
 
220
        if     ( i == 4 ) out = m_reset;
 
221
        else if( i == 5 ) out = !m_dispOn;
 
222
        
 
223
        m_dataeSource[i]->setOut( out );
 
224
        m_dataeSource[i]->stampOutput();
 
225
    }
 
226
}
 
227
 
 
228
void Ks0108::writeData( int data )
 
229
{
 
230
    //qDebug() << "Ks0108::writeData "<<data <<m_Cs1<<m_Cs2;
 
231
    if( m_Cs1 ) 
 
232
    {
 
233
        //qDebug() << "Ks0108::writeData 1  "<<m_addrX1 <<m_addrY1<<data;
 
234
        m_aDispRam[m_addrX1][m_addrY1]    = data;  // Write Half 1 
 
235
    }
 
236
    if( m_Cs2 ) 
 
237
    {
 
238
        //qDebug() << "Ks0108::writeData 2  "<<m_addrX2 <<m_addrY2<<data;
 
239
        m_aDispRam[m_addrX2][m_addrY2+64] = data;  // Write Half 2 
 
240
    }
 
241
    incrementPointer();
 
242
}
 
243
 
 
244
void Ks0108::proccessCommand( int command )
 
245
{
 
246
    //qDebug() << "Ks0108::proccessCommand: " << command;
 
247
    if( command<62 )  {                           return; }             // Not Valid
 
248
    if( command<64 )  { dispOn( command & 1 )   ; return; } //0011111.  // Display On/Off internal status &Ram not affected
 
249
    if( command<128 ) { setYaddr( command & 63 ); return; } //01......  // Set Y address
 
250
    if( command<184 ) {                           return; }             // Not Valid
 
251
    if( command<192 ) { setXaddr( command & 7 );  return; } //10111...  // Set X address     
 
252
    else              { startLin( command & 63 ); return; } //11......  // Set Display Start Line
 
253
}
 
254
void Ks0108::dispOn( int state )
 
255
{
 
256
    m_dispOn = (state > 0);
 
257
}
 
258
 
 
259
void Ks0108::setYaddr( int addr )
 
260
{
 
261
    //qDebug() << "Ks0108::setYaddr "<<addr <<m_Cs1<<m_Cs2;
 
262
    if( m_Cs1 ) m_addrY1  = addr ;
 
263
    if( m_Cs2 ) m_addrY2  = addr ;
 
264
}
 
265
 
 
266
void Ks0108::setXaddr( int addr )
 
267
{
 
268
    //qDebug() << "Ks0108::setXaddr "<<addr <<m_Cs1<<m_Cs2;
 
269
    if( m_Cs1 ) m_addrX1  = addr ;
 
270
    if( m_Cs2 ) m_addrX2  = addr ;
 
271
}
 
272
 
 
273
void Ks0108::startLin( int line )
 
274
{
 
275
    m_startLin = line;
 
276
}
 
277
 
 
278
void Ks0108::clearLcd() 
 
279
{
 
280
    m_pdisplayImg->fill(0);
 
281
}
 
282
 
 
283
void Ks0108::clearDDRAM() 
 
284
{
 
285
    for(int row=0;row<8;row++) 
 
286
        for( int col=0;col<128;col++ ) 
 
287
            m_aDispRam[row][col] = 0;
 
288
}
 
289
 
 
290
void Ks0108::incrementPointer() 
 
291
{
 
292
    if( m_Cs1 )
 
293
    {
 
294
        m_addrY1++;
 
295
        if( m_addrY1 > 63 )
 
296
        {
 
297
            m_addrY1 = 0;
 
298
            //m_addrX++;
 
299
        }
 
300
        /*if( m_addrX > 7 ) 
 
301
        {
 
302
            m_addrX = 0;
 
303
        }*/
 
304
    }
 
305
    if( m_Cs2 )
 
306
    {
 
307
        m_addrY2++;
 
308
        if( m_addrY2 > 63 )
 
309
        {
 
310
            m_addrY2 = 0;
 
311
            //m_addrX++;
 
312
        }
 
313
        /*if( m_addrX > 7 ) 
 
314
        {
 
315
            m_addrX = 0;
 
316
        }*/
 
317
    }
 
318
}
 
319
 
 
320
void Ks0108::reset() 
 
321
{
 
322
    m_addrX1  = 0;
 
323
    m_addrY1  = 0;
 
324
    m_addrX2  = 0;
 
325
    m_addrY2  = 0;
 
326
    m_startLin = 0;
 
327
    m_dispOn = false;
 
328
    m_reset = true;
 
329
}
 
330
 
 
331
void Ks0108::remove()
 
332
{
 
333
    for( int i=0; i<8; i++ ) delete m_dataeSource[i];
 
334
    
 
335
    delete m_pdisplayImg;
 
336
    Simulator::self()->remFromUpdateList( this );
 
337
    
 
338
    Component::remove();
 
339
}
 
340
 
 
341
void Ks0108::updateStep()
 
342
{
 
343
    if( !m_dispOn ) m_pdisplayImg->fill(0);               // Display Off
 
344
    else
 
345
    {
 
346
        for(int row=0;row<8;row++) 
 
347
        {
 
348
            for( int col=0;col<128;col++ ) 
 
349
            {
 
350
                char abyte = m_aDispRam[row][col];
 
351
                for( int bit=0; bit<8; bit++ ) 
 
352
                {
 
353
                    m_pdisplayImg->setPixel(col,row*8+bit,(abyte & 1) );
 
354
                    abyte >>= 1;
 
355
                }
 
356
            }
 
357
        }
 
358
    }
 
359
    update();
 
360
}
 
361
 
 
362
void Ks0108::paint( QPainter* p, const QStyleOptionGraphicsItem* option, QWidget* widget )
 
363
{
 
364
    Component::paint( p, option, widget );
 
365
 
 
366
    QPen pen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
 
367
    p->setPen( pen );
 
368
    
 
369
    p->setBrush( QColor(50, 70, 100) );
 
370
    p->drawRoundedRect( m_area,2,2 );
 
371
    p->setBrush( QColor(200, 220, 180) );
 
372
    p->drawRoundedRect( -70, -48, 140, 76, 8, 8 );
 
373
    p->drawImage(-64,-42,*m_pdisplayImg );
 
374
}
 
375
 
 
376
#include "moc_ks0108.cpp"