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