1 /*  This file is part of UKNCBTL.
2     UKNCBTL is free software: you can redistribute it and/or modify it under the terms
3 of the GNU Lesser General Public License as published by the Free Software Foundation,
4 either version 3 of the License, or (at your option) any later version.
5     UKNCBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
6 without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 See the GNU Lesser General Public License for more details.
8     You should have received a copy of the GNU Lesser General Public License along with
9 UKNCBTL. If not, see <http://www.gnu.org/licenses/>. */
10 
11 /// \file Processor.h  KM1801VM2 processor class
12 
13 #pragma once
14 
15 #include "Defines.h"
16 #include "Memory.h"
17 
18 
19 class CMemoryController;
20 
21 //////////////////////////////////////////////////////////////////////
22 
23 /// \brief KM1801VM2 processor
24 class CProcessor
25 {
26 public:  // Constructor / initialization
27     CProcessor(LPCTSTR name);
28     /// \brief Link the processor and memory controller
AttachMemoryController(CMemoryController * ctl)29     void        AttachMemoryController(CMemoryController* ctl) { m_pMemoryController = ctl; }
SetHALTPin(bool value)30     void        SetHALTPin(bool value) { m_haltpin = value; }
31     void        SetDCLOPin(bool value);
32     void        SetACLOPin(bool value);
33     void        MemoryError();
34     /// \brief Get the processor name, assigned in the constructor
GetName()35     LPCTSTR     GetName() const { return m_name; }
36 
37 public:
38     static void Init();  ///< Initialize static tables
39     static void Done();  ///< Release memory used for static tables
40 protected:  // Statics
41     typedef void ( CProcessor::*ExecuteMethodRef )();
42     static ExecuteMethodRef* m_pExecuteMethodMap;
43 
44 protected:  // Processor state
45     TCHAR       m_name[5];          ///< Processor name (DO NOT use it inside the processor code!!!)
46     uint16_t    m_internalTick;     ///< How many ticks waiting to the end of current instruction
47     uint16_t    m_psw;              ///< Processor Status Word (PSW)
48     uint16_t    m_R[8];             ///< Registers (R0..R5, R6=SP, R7=PC)
49     uint16_t    m_savepc;           ///< CPC register
50     uint16_t    m_savepsw;          ///< CPSW register
51     bool        m_okStopped;        ///< "Processor stopped" flag
52     bool        m_stepmode;         ///< Read true if it's step mode
53     bool        m_buserror;         ///< Read true if occured bus error for implementing double bus error if needed
54     bool        m_haltpin;          ///< HALT pin
55     bool        m_DCLOpin;          ///< DCLO pin
56     bool        m_ACLOpin;          ///< ACLO pin
57     bool        m_waitmode;         ///< WAIT
58 
59 protected:  // Current instruction processing
60     uint16_t    m_instruction;      ///< Curent instruction
61     uint8_t     m_regsrc;           ///< Source register number
62     uint8_t     m_methsrc;          ///< Source address mode
63     uint16_t    m_addrsrc;          ///< Source address
64     uint8_t     m_regdest;          ///< Destination register number
65     uint8_t     m_methdest;         ///< Destination address mode
66     uint16_t    m_addrdest;         ///< Destination address
67 protected:  // Interrupt processing
68     bool        m_STRTrq;           ///< Start interrupt pending
69     bool        m_RPLYrq;           ///< Hangup interrupt pending
70     bool        m_ILLGrq;           ///< Illegal instruction interrupt pending
71     bool        m_RSVDrq;           ///< Reserved instruction interrupt pending
72     bool        m_TBITrq;           ///< T-bit interrupt pending
73     bool        m_ACLOrq;           ///< Power down interrupt pending
74     bool        m_HALTrq;           ///< HALT command or HALT signal
75     bool        m_EVNTrq;           ///< Timer event interrupt pending
76     bool        m_FIS_rq;           ///< FIS command interrupt pending
77     bool        m_BPT_rq;           ///< BPT command interrupt pending
78     bool        m_IOT_rq;           ///< IOT command interrupt pending
79     bool        m_EMT_rq;           ///< EMT command interrupt pending
80     bool        m_TRAPrq;           ///< TRAP command interrupt pending
81     uint16_t    m_virq[16];         ///< VIRQ vector
82     bool        m_ACLOreset;        ///< Power fail interrupt request reset
83     bool        m_EVNTreset;        ///< EVNT interrupt request reset;
84     uint8_t     m_VIRQreset;        ///< VIRQ request reset for given device
85 protected:
86     CMemoryController* m_pMemoryController;
87 
88 public:
GetMemoryController()89     CMemoryController* GetMemoryController() { return m_pMemoryController; }
90 
91 public:  // Register control
GetPSW()92     uint16_t    GetPSW() const { return m_psw; }  ///< Get the processor status word register value
GetCPSW()93     uint16_t    GetCPSW() const { return m_savepsw; }
GetLPSW()94     uint8_t     GetLPSW() const { return (uint8_t)(m_psw & 0xff); }  ///< Get PSW lower byte
95     void        SetPSW(uint16_t word);  ///< Set the processor status word register value
SetCPSW(uint16_t word)96     void        SetCPSW(uint16_t word) {m_savepsw = word; }
97     void        SetLPSW(uint8_t byte);
GetReg(int regno)98     uint16_t    GetReg(int regno) const { return m_R[regno]; }  ///< Get register value, regno=0..7
99     void        SetReg(int regno, uint16_t word);  ///< Set register value
GetLReg(int regno)100     uint8_t     GetLReg(int regno) const { return (uint8_t)(m_R[regno] & 0xff); }
101     void        SetLReg(int regno, uint8_t byte);
GetSP()102     uint16_t    GetSP() const { return m_R[6]; }
SetSP(uint16_t word)103     void        SetSP(uint16_t word) { m_R[6] = word; }
GetPC()104     uint16_t    GetPC() const { return m_R[7]; }
GetCPC()105     uint16_t    GetCPC() const { return m_savepc; }
106     void        SetPC(uint16_t word);
SetCPC(uint16_t word)107     void        SetCPC(uint16_t word) {m_savepc = word; }
108 
109 public:  // PSW bits control
110     void        SetC(bool bFlag);
GetC()111     uint16_t    GetC() const { return (m_psw & PSW_C) != 0; }
112     void        SetV(bool bFlag);
GetV()113     uint16_t    GetV() const { return (m_psw & PSW_V) != 0; }
114     void        SetN(bool bFlag);
GetN()115     uint16_t    GetN() const { return (m_psw & PSW_N) != 0; }
116     void        SetZ(bool bFlag);
GetZ()117     uint16_t    GetZ() const { return (m_psw & PSW_Z) != 0; }
118     void        SetHALT(bool bFlag);
GetHALT()119     uint16_t    GetHALT() const { return (m_psw & PSW_HALT) != 0; }
120 
121 public:  // Processor state
122     /// \brief "Processor stopped" flag
IsStopped()123     bool        IsStopped() const { return m_okStopped; }
124     /// \brief HALT flag (true - HALT mode, false - USER mode)
IsHaltMode()125     bool        IsHaltMode() const { return ((m_psw & 0400) != 0); }
126 public:  // Processor control
127     void        TickEVNT();  ///< EVNT signal
128     /// \brief External interrupt via VIRQ signal
129     void        InterruptVIRQ(int que, uint16_t interrupt);
GetVIRQ(int que)130     uint16_t    GetVIRQ(int que) { return m_virq[que]; }
131     /// \brief Execute one processor tick
132     void        Execute();
133     /// \brief Process pending interrupt requests
134     bool        InterruptProcessing();
135     /// \brief Execute next command and process interrupts
136     void        CommandExecution();
GetInternalTick()137     int         GetInternalTick() const { return m_internalTick; }
ClearInternalTick()138     void        ClearInternalTick() { m_internalTick = 0; }
139 
140 public:  // Saving/loading emulator status (pImage addresses up to 32 bytes)
141     void        SaveToImage(uint8_t* pImage) const;
142     void        LoadFromImage(const uint8_t* pImage);
143 
144 protected:  // Implementation
145     void        FetchInstruction();      ///< Read next instruction
146     void        TranslateInstruction();  ///< Execute the instruction
147 protected:  // Implementation - memory access
148     /// \brief Read word from the bus for execution
GetWordExec(uint16_t address)149     uint16_t    GetWordExec(uint16_t address) { return m_pMemoryController->GetWord(address, IsHaltMode(), true); }
150     /// \brief Read word from the bus
GetWord(uint16_t address)151     uint16_t    GetWord(uint16_t address) { return m_pMemoryController->GetWord(address, IsHaltMode(), false); }
SetWord(uint16_t address,uint16_t word)152     void        SetWord(uint16_t address, uint16_t word) { m_pMemoryController->SetWord(address, IsHaltMode(), word); }
GetByte(uint16_t address)153     uint8_t     GetByte(uint16_t address) { return m_pMemoryController->GetByte(address, IsHaltMode()); }
SetByte(uint16_t address,uint8_t byte)154     void        SetByte(uint16_t address, uint8_t byte) { m_pMemoryController->SetByte(address, IsHaltMode(), byte); }
155 
156 protected:  // PSW bits calculations
CheckForNegative(uint8_t byte)157     bool static CheckForNegative(uint8_t byte) { return (byte & 0200) != 0; }
CheckForNegative(uint16_t word)158     bool static CheckForNegative(uint16_t word) { return (word & 0100000) != 0; }
CheckForZero(uint8_t byte)159     bool static CheckForZero(uint8_t byte) { return byte == 0; }
CheckForZero(uint16_t word)160     bool static CheckForZero(uint16_t word) { return word == 0; }
161     bool static CheckAddForOverflow(uint8_t a, uint8_t b);
162     bool static CheckAddForOverflow(uint16_t a, uint16_t b);
163     bool static CheckSubForOverflow(uint8_t a, uint8_t b);
164     bool static CheckSubForOverflow(uint16_t a, uint16_t b);
165     bool static CheckAddForCarry(uint8_t a, uint8_t b);
166     bool static CheckAddForCarry(uint16_t a, uint16_t b);
167     bool static CheckSubForCarry(uint8_t a, uint8_t b);
168     bool static CheckSubForCarry(uint16_t a, uint16_t b);
169 
170 protected:  // Implementation - instruction execution
171     // No fields
172     uint16_t    GetWordAddr (uint8_t meth, uint8_t reg);
173     uint16_t    GetByteAddr (uint8_t meth, uint8_t reg);
174 
175     void        ExecuteUNKNOWN ();  ///< There is no such instruction -- just call TRAP 10
176     void        ExecuteHALT ();
177     void        ExecuteWAIT ();
178     void        ExecuteRCPC	();
179     void        ExecuteRCPS ();
180     void        ExecuteWCPC	();
181     void        ExecuteWCPS	();
182     void        ExecuteMFUS ();
183     void        ExecuteMTUS ();
184     void        ExecuteRTI ();
185     void        ExecuteBPT ();
186     void        ExecuteIOT ();
187     void        ExecuteRESET ();
188     void        ExecuteSTEP	();
189     void        ExecuteRSEL ();
190     void        Execute000030 ();
191     void        ExecuteFIS ();
192     void        ExecuteRUN	();
193     void        ExecuteRTT ();
194     void        ExecuteCCC ();
195     void        ExecuteSCC ();
196 
197     // One fiels
198     void        ExecuteRTS ();
199 
200     // Two fields
201     void        ExecuteJMP ();
202     void        ExecuteSWAB ();
203     void        ExecuteCLR ();
204     void        ExecuteCLRB ();
205     void        ExecuteCOM ();
206     void        ExecuteCOMB ();
207     void        ExecuteINC ();
208     void        ExecuteINCB ();
209     void        ExecuteDEC ();
210     void        ExecuteDECB ();
211     void        ExecuteNEG ();
212     void        ExecuteNEGB ();
213     void        ExecuteADC ();
214     void        ExecuteADCB ();
215     void        ExecuteSBC ();
216     void        ExecuteSBCB ();
217     void        ExecuteTST ();
218     void        ExecuteTSTB ();
219     void        ExecuteROR ();
220     void        ExecuteRORB ();
221     void        ExecuteROL ();
222     void        ExecuteROLB ();
223     void        ExecuteASR ();
224     void        ExecuteASRB ();
225     void        ExecuteASL ();
226     void        ExecuteASLB ();
227     void        ExecuteMARK ();
228     void        ExecuteSXT ();
229     void        ExecuteMTPS ();
230     void        ExecuteMFPS ();
231 
232     // Branchs & interrupts
233     void        ExecuteBR ();
234     void        ExecuteBNE ();
235     void        ExecuteBEQ ();
236     void        ExecuteBGE ();
237     void        ExecuteBLT ();
238     void        ExecuteBGT ();
239     void        ExecuteBLE ();
240     void        ExecuteBPL ();
241     void        ExecuteBMI ();
242     void        ExecuteBHI ();
243     void        ExecuteBLOS ();
244     void        ExecuteBVC ();
245     void        ExecuteBVS ();
246     void        ExecuteBHIS ();
247     void        ExecuteBLO ();
248 
249     void        ExecuteEMT ();
250     void        ExecuteTRAP ();
251 
252     // Three fields
253     void        ExecuteJSR ();
254     void        ExecuteXOR ();
255     void        ExecuteSOB ();
256     void        ExecuteMUL ();
257     void        ExecuteDIV ();
258     void        ExecuteASH ();
259     void        ExecuteASHC ();
260 
261     // Four fields
262     void        ExecuteMOV ();
263     void        ExecuteMOVB ();
264     void        ExecuteCMP ();
265     void        ExecuteCMPB ();
266     void        ExecuteBIT ();
267     void        ExecuteBITB ();
268     void        ExecuteBIC ();
269     void        ExecuteBICB ();
270     void        ExecuteBIS ();
271     void        ExecuteBISB ();
272 
273     void        ExecuteADD ();
274     void        ExecuteSUB ();
275 };
276 
SetPSW(uint16_t word)277 inline void CProcessor::SetPSW(uint16_t word)
278 {
279     m_psw = word & 0777;
280     if ((m_psw & 0600) != 0600) m_savepsw = m_psw;
281 }
SetLPSW(uint8_t byte)282 inline void CProcessor::SetLPSW(uint8_t byte)
283 {
284     m_psw = (m_psw & 0xFF00) | (uint16_t)byte;
285     if ((m_psw & 0600) != 0600) m_savepsw = m_psw;
286 }
SetReg(int regno,uint16_t word)287 inline void CProcessor::SetReg(int regno, uint16_t word)
288 {
289     m_R[regno] = word;
290     if ((regno == 7) && ((m_psw & 0600) != 0600))	m_savepc = word;
291 }
SetLReg(int regno,uint8_t byte)292 inline void CProcessor::SetLReg(int regno, uint8_t byte)
293 {
294     m_R[regno] = (m_R[regno] & 0xFF00) | (uint16_t)byte;
295     if ((regno == 7) && ((m_psw & 0600) != 0600))	m_savepc = m_R[7];
296 }
SetPC(uint16_t word)297 inline void CProcessor::SetPC(uint16_t word)
298 {
299     m_R[7] = word;
300     if ((m_psw & 0600) != 0600) m_savepc = word;
301 }
302 
303 // PSW bits control - implementation
SetC(bool bFlag)304 inline void CProcessor::SetC (bool bFlag)
305 {
306     if (bFlag) m_psw |= PSW_C; else m_psw &= ~PSW_C;
307     if ((m_psw & 0600) != 0600) m_savepsw = m_psw;
308 }
SetV(bool bFlag)309 inline void CProcessor::SetV (bool bFlag)
310 {
311     if (bFlag) m_psw |= PSW_V; else m_psw &= ~PSW_V;
312     if ((m_psw & 0600) != 0600) m_savepsw = m_psw;
313 }
SetN(bool bFlag)314 inline void CProcessor::SetN (bool bFlag)
315 {
316     if (bFlag) m_psw |= PSW_N; else m_psw &= ~PSW_N;
317     if ((m_psw & 0600) != 0600) m_savepsw = m_psw;
318 }
SetZ(bool bFlag)319 inline void CProcessor::SetZ (bool bFlag)
320 {
321     if (bFlag) m_psw |= PSW_Z; else m_psw &= ~PSW_Z;
322     if ((m_psw & 0600) != 0600) m_savepsw = m_psw;
323 }
324 
SetHALT(bool bFlag)325 inline void CProcessor::SetHALT (bool bFlag)
326 {
327     if (bFlag) m_psw |= PSW_HALT; else m_psw &= ~PSW_HALT;
328 }
329 
InterruptVIRQ(int que,uint16_t interrupt)330 inline void CProcessor::InterruptVIRQ(int que, uint16_t interrupt)
331 {
332     if (m_okStopped) return;  // Processor is stopped - nothing to do
333     m_virq[que] = interrupt;
334 }
335 
336 // PSW bits calculations - implementation
CheckAddForOverflow(uint8_t a,uint8_t b)337 inline bool CProcessor::CheckAddForOverflow (uint8_t a, uint8_t b)
338 {
339 #if defined(_M_IX86) && defined(_MSC_VER) && !defined(_MANAGED)
340     bool bOverflow = false;
341     _asm
342     {
343         pushf
344         push cx
345         mov cl, byte ptr [a]
346         add cl, byte ptr [b]
347         jno end
348         mov dword ptr [bOverflow], 1
349         end:
350         pop cx
351         popf
352     }
353     return bOverflow;
354 #else
355     //uint16_t sum = a < 0200 ? (uint16_t)a + (uint16_t)b + 0200 : (uint16_t)a + (uint16_t)b - 0200;
356     //return HIBYTE (sum) != 0;
357     uint8_t sum = a + b;
358     return ((~a ^ b) & (a ^ sum)) & 0200;
359 #endif
360 }
CheckAddForOverflow(uint16_t a,uint16_t b)361 inline bool CProcessor::CheckAddForOverflow (uint16_t a, uint16_t b)
362 {
363 #if defined(_M_IX86) && defined(_MSC_VER) && !defined(_MANAGED)
364     bool bOverflow = false;
365     _asm
366     {
367         pushf
368         push cx
369         mov cx, word ptr [a]
370         add cx, word ptr [b]
371         jno end
372         mov dword ptr [bOverflow], 1
373         end:
374         pop cx
375         popf
376     }
377     return bOverflow;
378 #else
379     //uint32_t sum =  a < 0100000 ? (uint32_t)a + (uint32_t)b + 0100000 : (uint32_t)a + (uint32_t)b - 0100000;
380     //return HIWORD (sum) != 0;
381     uint16_t sum = a + b;
382     return ((~a ^ b) & (a ^ sum)) & 0100000;
383 #endif
384 }
385 
CheckSubForOverflow(uint8_t a,uint8_t b)386 inline bool CProcessor::CheckSubForOverflow (uint8_t a, uint8_t b)
387 {
388 #if defined(_M_IX86) && defined(_MSC_VER) && !defined(_MANAGED)
389     bool bOverflow = false;
390     _asm
391     {
392         pushf
393         push cx
394         mov cl, byte ptr [a]
395         sub cl, byte ptr [b]
396         jno end
397         mov dword ptr [bOverflow], 1
398         end:
399         pop cx
400         popf
401     }
402     return bOverflow;
403 #else
404     //uint16_t sum = a < 0200 ? (uint16_t)a - (uint16_t)b + 0200 : (uint16_t)a - (uint16_t)b - 0200;
405     //return HIBYTE (sum) != 0;
406     uint8_t sum = a - b;
407     return ((a ^ b) & (~b ^ sum)) & 0200;
408 #endif
409 }
CheckSubForOverflow(uint16_t a,uint16_t b)410 inline bool CProcessor::CheckSubForOverflow (uint16_t a, uint16_t b)
411 {
412 #if defined(_M_IX86) && defined(_MSC_VER) && !defined(_MANAGED)
413     bool bOverflow = false;
414     _asm
415     {
416         pushf
417         push cx
418         mov cx, word ptr [a]
419         sub cx, word ptr [b]
420         jno end
421         mov dword ptr [bOverflow], 1
422         end:
423         pop cx
424         popf
425     }
426     return bOverflow;
427 #else
428     //uint32_t sum =  a < 0100000 ? (uint32_t)a - (uint32_t)b + 0100000 : (uint32_t)a - (uint32_t)b - 0100000;
429     //return HIWORD (sum) != 0;
430     uint16_t sum = a - b;
431     return ((a ^ b) & (~b ^ sum)) & 0100000;
432 #endif
433 }
CheckAddForCarry(uint8_t a,uint8_t b)434 inline bool CProcessor::CheckAddForCarry (uint8_t a, uint8_t b)
435 {
436     uint16_t sum = (uint16_t)a + (uint16_t)b;
437     return (uint8_t)((sum >> 8) & 0xff) != 0;
438 }
CheckAddForCarry(uint16_t a,uint16_t b)439 inline bool CProcessor::CheckAddForCarry (uint16_t a, uint16_t b)
440 {
441     uint32_t sum = (uint32_t)a + (uint32_t)b;
442     return (uint16_t)((sum >> 16) & 0xffff) != 0;
443 }
CheckSubForCarry(uint8_t a,uint8_t b)444 inline bool CProcessor::CheckSubForCarry (uint8_t a, uint8_t b)
445 {
446     uint16_t sum = (uint16_t)a - (uint16_t)b;
447     return (uint8_t)((sum >> 8) & 0xff) != 0;
448 }
CheckSubForCarry(uint16_t a,uint16_t b)449 inline bool CProcessor::CheckSubForCarry (uint16_t a, uint16_t b)
450 {
451     uint32_t sum = (uint32_t)a - (uint32_t)b;
452     return (uint16_t)((sum >> 16) & 0xffff) != 0;
453 }
454 
455 
456 //////////////////////////////////////////////////////////////////////
457