Browse code

Add source code of the XiPC emulator

Pawel Jablonski authored on 17/03/2023 16:46:08
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,604 @@
1
+/*
2
+ * Author: Pawel Jablonski
3
+ * E-mail: pj@xirx.net
4
+ * WWW: xirx.net
5
+ * GIT: git.xirx.net
6
+ *
7
+ * License: You can use this code however you like
8
+ * but leave information about the original author.
9
+ * Code is free for non-commercial and commercial use.
10
+ */
11
+
12
+#include "cpu.h"
13
+
14
+/**
15
+ * Constructor for the CPU class
16
+ *
17
+ * @param parent Parent object
18
+ */
19
+CPU::CPU(QObject *parent) : QObject(parent)
20
+{
21
+	this->urom0.data.fill(0);
22
+	this->urom1.data.fill(0);
23
+	this->rom.data.fill(0);
24
+
25
+	this->reset();
26
+
27
+	QObject::connect(&this->timer, SIGNAL(timeout()), this, SLOT(emulation()));
28
+}
29
+
30
+/**
31
+ * Set first uROM memory data
32
+ *
33
+ * @param urom uROM data
34
+ */
35
+void CPU::setUrom0(const CPU::Memory &urom)
36
+{
37
+	this->urom0 = urom;
38
+}
39
+
40
+/**
41
+ * Set second uROM memory data
42
+ *
43
+ * @param urom uROM data
44
+ */
45
+void CPU::setUrom1(const CPU::Memory &urom)
46
+{
47
+	this->urom1 = urom;
48
+}
49
+
50
+/**
51
+ * Set ROM memory data
52
+ *
53
+ * @param rom ROM data
54
+ */
55
+void CPU::setRom(const CPU::Memory &rom)
56
+{
57
+	this->rom = rom;
58
+}
59
+
60
+//! Run executing emulation
61
+void CPU::run()
62
+{
63
+	this->stepMode = false;
64
+
65
+	this->timer.setSingleShot(false);
66
+	this->timer.setInterval(INTERVAL);
67
+	this->timer.start();
68
+}
69
+
70
+//! Run only one CPU step of emulation
71
+void CPU::step()
72
+{
73
+	this->stepMode = true;
74
+
75
+	this->timer.setSingleShot(true);
76
+	this->timer.start(0);
77
+}
78
+
79
+//! Pause executing emulation
80
+void CPU::pause()
81
+{
82
+	this->timer.stop();
83
+}
84
+
85
+//! Stop executing emulation
86
+void CPU::stop()
87
+{
88
+	this->timer.stop();
89
+
90
+	this->reset();
91
+}
92
+
93
+/**
94
+ * Get register buffer
95
+ *
96
+ * @return Register buffer
97
+ */
98
+const CPU::Reg &CPU::getReg() const
99
+{
100
+	return(this->reg);
101
+}
102
+
103
+/**
104
+ * Get ticks counter value
105
+ *
106
+ * @return Tick counter value
107
+ */
108
+unsigned long long CPU::getTicks() const
109
+{
110
+	return(this->ticks);
111
+}
112
+
113
+/**
114
+ * Get ROM buffer
115
+ *
116
+ * @return ROM buffer
117
+ */
118
+const CPU::Memory &CPU::getRom() const
119
+{
120
+	return(this->rom);
121
+}
122
+
123
+/**
124
+ * Get lower RAM buffer
125
+ *
126
+ * @return Lower RAM buffer
127
+ */
128
+const CPU::Memory &CPU::getRamLow() const
129
+{
130
+	return(this->ramLow);
131
+}
132
+
133
+/**
134
+ * Get higher RAM buffer
135
+ *
136
+ * @return Higher RAM buffer
137
+ */
138
+const CPU::Memory &CPU::getRamHigh() const
139
+{
140
+	return(this->ramHigh);
141
+}
142
+
143
+//! Stop executing and reset data of emulation
144
+void CPU::reset()
145
+{
146
+	this->stepMode = false;
147
+	this->ticks = 0;
148
+
149
+	this->timer.stop();
150
+
151
+	this->ramLow.data.fill(0);
152
+	this->ramHigh.data.fill(0);
153
+
154
+	this->reg.i = 0;
155
+	this->reg.c = false;
156
+	this->reg.z = false;
157
+	this->reg.pch = 0;
158
+	this->reg.pcl = 0;
159
+	this->reg.sph = STACK_PAGE;
160
+	this->reg.spl = 0;
161
+	this->reg.maxSpl = 0;
162
+	this->reg.a = 0;
163
+	this->reg.b = 0;
164
+	this->reg.x = 0;
165
+	this->reg.y = 0;
166
+	this->reg.in = 0;
167
+	this->reg.out = 0;
168
+	this->reg.d = 0;
169
+	this->reg.t = 0;
170
+	this->reg.mah = 0;
171
+	this->reg.mal = 0;
172
+}
173
+
174
+/**
175
+ * Compute logic or arithmetic using ALU. It emulates functions of the 74181 chip.
176
+ *
177
+ * @param a First operant
178
+ * @param b Second operant
179
+ * @param s Operation type selector in range 0-15
180
+ * @param m Operatiom mode selector. "0" for arithmetic and "1" for logic mode.
181
+ * @param c Carry flag
182
+ * @param z Zero flag
183
+ *
184
+ * @return Computed value
185
+ */
186
+unsigned char CPU::alu(unsigned char a, unsigned char b, unsigned char s, bool m, bool &c, bool &z)
187
+{
188
+	QVector<bool> inA(4);
189
+	QVector<bool> inB(4);
190
+	QVector<bool> inS(4);
191
+
192
+	inA[0] = ((a & (1 << 0)) != 0);
193
+	inA[1] = ((a & (1 << 1)) != 0);
194
+	inA[2] = ((a & (1 << 2)) != 0);
195
+	inA[3] = ((a & (1 << 3)) != 0);
196
+
197
+	inB[0] = ((b & (1 << 0)) != 0);
198
+	inB[1] = ((b & (1 << 1)) != 0);
199
+	inB[2] = ((b & (1 << 2)) != 0);
200
+	inB[3] = ((b & (1 << 3)) != 0);
201
+
202
+	inS[0] = ((s & (1 << 0)) != 0);
203
+	inS[1] = ((s & (1 << 1)) != 0);
204
+	inS[2] = ((s & (1 << 2)) != 0);
205
+	inS[3] = ((s & (1 << 3)) != 0);
206
+
207
+	QVector<QVector<bool>> l1(4, QVector<bool>(5));
208
+
209
+	for(int i = 0; i < 4; i++)
210
+	{
211
+		l1[i][0] = inA[i];
212
+		l1[i][1] = (inB[i] & inS[0]);
213
+		l1[i][2] = ((!inB[i]) & inS[1]);
214
+		l1[i][3] = ((!inB[i]) & inA[i] & inS[2]);
215
+		l1[i][4] = (inA[i] & inB[i] & inS[3]);
216
+	}
217
+
218
+	QVector<QVector<bool>> l2(4, QVector<bool>(2));
219
+
220
+	for(int i = 0; i < 4; i++)
221
+	{
222
+		l2[i][0] = !(l1[i][0] | l1[i][1] | l1[i][2]);
223
+		l2[i][1] = !(l1[i][3] | l1[i][4]);
224
+	}
225
+
226
+	QVector<bool> l3(20);
227
+
228
+	l3[0] = !(c & (!m));
229
+
230
+	l3[1] = !(l2[0][0]);
231
+	l3[2] = ((!m) & l2[0][0]);
232
+	l3[3] = ((!m) & l2[0][1] & c);
233
+
234
+	l3[4] = !(l2[1][0]);
235
+	l3[5] = ((!m) & l2[1][0]);
236
+	l3[6] = ((!m) & l2[0][0] & l2[1][1]);
237
+	l3[7] = ((!m) & l2[0][1] & l2[1][1] & c);
238
+
239
+	l3[8] = !(l2[2][0]);
240
+	l3[9] = ((!m) & l2[2][0]);
241
+	l3[10] = ((!m) & l2[1][0] & l2[2][1]);
242
+	l3[11] = ((!m) & l2[0][0] & l2[1][1] & l2[2][1]);
243
+	l3[12] = ((!m) & l2[0][1] & l2[1][1] & l2[2][1] & c);
244
+
245
+	l3[13] = !(l2[3][0]);
246
+	l3[14] = !(l2[0][1] & l2[1][1] & l2[2][1] & l2[3][1]);
247
+	l3[15] = !(l2[0][1] & l2[1][1] & l2[2][1] & l2[3][1] & c);
248
+
249
+	l3[16] = (l2[0][0] & l2[1][1] & l2[2][1] & l2[3][1]);
250
+	l3[17] = (l2[1][0] & l2[2][1] & l2[3][1]);
251
+	l3[18] = (l2[2][0] & l2[3][1]);
252
+	l3[19] = (l2[3][0]);
253
+
254
+	QVector<bool> l4(8);
255
+
256
+	l4[0] = (l3[1] & l2[0][1]);
257
+	l4[1] = !(l3[2] | l3[3]);
258
+
259
+	l4[2] = (l3[4] & l2[1][1]);
260
+	l4[3] = !(l3[5] | l3[6] | l3[7]);
261
+
262
+	l4[4] = (l3[8] & l2[2][1]);
263
+	l4[5] = !(l3[9] | l3[10] | l3[11] | l3[12]);
264
+
265
+	l4[6] = (l3[13] & l2[3][1]);
266
+	l4[7] = !(l3[16] | l3[17] | l3[18] | l3[19]);
267
+
268
+	QVector<bool> f(4);
269
+
270
+	f[0] = (l3[0] ^ l4[0]);
271
+	f[1] = (l4[1] ^ l4[2]);
272
+	f[2] = (l4[3] ^ l4[4]);
273
+	f[3] = (l4[5] ^ l4[6]);
274
+
275
+	z = (f[0] & f[1] & f[2] & f[3]);
276
+	c = ((!l3[15]) | (!l4[7]));
277
+
278
+	unsigned char out = 0;
279
+
280
+	out += (f[0] ? 1 : 0);
281
+	out += (f[1] ? 2 : 0);
282
+	out += (f[2] ? 4 : 0);
283
+	out += (f[3] ? 8 : 0);
284
+
285
+	return(out);
286
+}
287
+
288
+/**
289
+ * Set Input register value
290
+ *
291
+ * @param in Input register value
292
+ */
293
+void CPU::inSlot(unsigned char in)
294
+{
295
+	if(this->ticks > 0)
296
+	{
297
+		this->reg.in = ((this->reg.in & (1 << 4)) | (in & ~(1 << 4)));
298
+	}
299
+}
300
+
301
+//! Process one step of the emulation
302
+void CPU::emulation()
303
+{
304
+	unsigned long long tick = 0;
305
+
306
+	unsigned char uromCycle = 0;
307
+	int uromAddress;
308
+	unsigned char urom0;
309
+	unsigned char urom1;
310
+
311
+	BusAR busAR;
312
+	BusAW busAW;
313
+	BusB busB;
314
+	BusC busC;
315
+
316
+	int address;
317
+
318
+	unsigned char aluS;
319
+	bool aluM;
320
+	bool aluC;
321
+
322
+	unsigned char busARregABXY;
323
+	unsigned char busAWregABXY;
324
+	unsigned char busBregAB;
325
+
326
+	unsigned char valueAR = 0;
327
+	unsigned char valueB = 0;
328
+
329
+	while(tick < TICKS_PER_INTERVAL)
330
+	{
331
+		do
332
+		{
333
+			uromAddress = (static_cast<int>(this->reg.i) << UROM_ADDRESS_INSTRUCTION_POSITION);
334
+			uromAddress += (static_cast<int>(uromCycle & UROM_ADDRESS_CYCLE_MASK) << UROM_ADDRESS_CYCLE_POSITION);
335
+			uromAddress += (static_cast<int>(this->reg.c ? 1 : 0) << UROM_ADDRESS_FLAG_C_POSITION);
336
+			uromAddress += (static_cast<int>(this->reg.z ? 1 : 0) << UROM_ADDRESS_FLAG_Z_POSITION);
337
+
338
+			urom0 = this->urom0.data[uromAddress];
339
+			urom1 = this->urom1.data[uromAddress];
340
+
341
+			uromCycle++;
342
+
343
+			busAR = static_cast<BusAR>((urom0 & UROM_0_BUS_AR_MASK) >> UROM_0_BUS_AR_POSITION);
344
+			busAW = static_cast<BusAW>((urom0 & UROM_0_BUS_AW_MASK) >> UROM_0_BUS_AW_POSITION);
345
+			busB = static_cast<BusB>((urom0 & UROM_0_BUS_B_MASK) >> UROM_0_BUS_B_POSITION);
346
+			busC = static_cast<BusC>((urom1 & UROM_1_BUS_C_MASK) >> UROM_1_BUS_C_POSITION);
347
+
348
+			aluS = ((urom1 & UROM_1_ALU_S_MASK) >> 2);
349
+			aluM = ((urom1 & UROM_1_ALU_M_MASK) != 0);
350
+			aluC = ((urom1 & UROM_1_ALU_C_MASK) != 0);
351
+
352
+			if((busAR == BusAR::ABXY) && (busAW == BusAW::ABXY))
353
+			{
354
+				busARregABXY = ((this->reg.i & INSTRUCTION_REG_ABXY_SECOND_MASK) >> INSTRUCTION_REG_ABXY_SECOND_OFFSET);
355
+			}
356
+			else
357
+			{
358
+				busARregABXY = ((this->reg.i & INSTRUCTION_REG_ABXY_FIRST_MASK) >> INSTRUCTION_REG_ABXY_FIRST_OFFSET);
359
+			}
360
+
361
+			busAWregABXY = (this->reg.i & INSTRUCTION_REG_ABXY_FIRST_MASK);
362
+			busBregAB = ((this->reg.i & INSTRUCTION_REG_AB_MASK) >> INSTRUCTION_REG_AB_OFFSET);
363
+
364
+			switch(busC)
365
+			{
366
+				case BusC::PC :
367
+					address = ((static_cast<int>(this->reg.pch) << 8) + static_cast<int>(this->reg.pcl));
368
+					break;
369
+
370
+				case BusC::MA :
371
+					address = ((static_cast<int>(this->reg.mah) << 8) + static_cast<int>(this->reg.mal));
372
+					break;
373
+
374
+				case BusC::SP :
375
+					address = ((static_cast<int>(this->reg.sph) << 8) + static_cast<int>(this->reg.spl));
376
+					break;
377
+
378
+				case BusC::XY :
379
+					address = ((static_cast<int>(this->reg.y) << 8) + static_cast<int>(this->reg.x));
380
+					break;
381
+			}
382
+
383
+			switch(busAR)
384
+			{
385
+				case BusAR::ABXY :
386
+					switch(busARregABXY)
387
+					{
388
+						case 0 :
389
+							valueAR = this->reg.a;
390
+							break;
391
+
392
+						case 1 :
393
+							valueAR = this->reg.b;
394
+							break;
395
+
396
+						case 2 :
397
+							valueAR = this->reg.x;
398
+							break;
399
+
400
+						case 3 :
401
+							valueAR = this->reg.y;
402
+							break;
403
+					}
404
+					break;
405
+
406
+				case BusAR::D :
407
+					valueAR = this->reg.d;
408
+					break;
409
+
410
+				case BusAR::IN :
411
+					valueAR = this->reg.in;
412
+					break;
413
+
414
+				case BusAR::T :
415
+					valueAR = this->reg.t;
416
+					break;
417
+
418
+				case BusAR::Ram :
419
+					if(address < MEMORY_SIZE)
420
+					{
421
+						valueAR = this->ramLow.data[address];
422
+					}
423
+					else
424
+					{
425
+						valueAR = this->ramHigh.data[address - MEMORY_SIZE];
426
+					}
427
+					break;
428
+
429
+				case BusAR::Flash :
430
+					if(address < MEMORY_SIZE)
431
+					{
432
+						valueAR = this->rom.data[address];
433
+					}
434
+					else
435
+					{
436
+						valueAR = this->ramHigh.data[address - MEMORY_SIZE];
437
+					}
438
+					break;
439
+
440
+				case BusAR::PCL :
441
+					valueAR = this->reg.pcl;
442
+					break;
443
+
444
+				case BusAR::PCH :
445
+					valueAR = this->reg.pch;
446
+					break;
447
+			}
448
+
449
+			switch(busB)
450
+			{
451
+				case BusB::AB :
452
+					switch(busBregAB)
453
+					{
454
+						case 0 :
455
+							valueB = this->reg.a;
456
+							break;
457
+
458
+						case 1 :
459
+							valueB = this->reg.b;
460
+							break;
461
+					}
462
+					break;
463
+
464
+				case BusB::D :
465
+					valueB = this->reg.d;
466
+					break;
467
+			}
468
+
469
+			switch(busAW)
470
+			{
471
+				case BusAW::None :
472
+					break;
473
+
474
+				case BusAW::ABXY :
475
+					switch(busAWregABXY)
476
+					{
477
+						case 0 :
478
+							this->reg.a = valueAR;
479
+							break;
480
+
481
+						case 1 :
482
+							this->reg.b = valueAR;
483
+							break;
484
+
485
+						case 2 :
486
+							this->reg.x = valueAR;
487
+							break;
488
+
489
+						case 3 :
490
+							this->reg.y = valueAR;
491
+							break;
492
+					}
493
+					break;
494
+
495
+				case BusAW::D :
496
+					this->reg.d = valueAR;
497
+					break;
498
+
499
+				case BusAW::OUT :
500
+					{
501
+						this->reg.out = valueAR;
502
+
503
+						emit outSignal(this->reg.out);
504
+					}
505
+					break;
506
+
507
+				case BusAW::ALU_T :
508
+					{
509
+						QVector<bool> z(2);
510
+						bool c = aluC;
511
+						unsigned char value = 0;
512
+
513
+						value = this->alu((valueAR & ALU_4BIT_MASK), (valueB & ALU_4BIT_MASK), aluS, aluM, c, z[0]);
514
+						value += (this->alu((valueAR >> ALU_4BIT_OFFSET), (valueB >> ALU_4BIT_OFFSET), aluS, aluM, c, z[1]) << ALU_4BIT_OFFSET);
515
+
516
+						this->reg.t = value;
517
+						this->reg.c = c;
518
+						this->reg.z = (z[0] & z[1]);
519
+					}
520
+					break;
521
+
522
+				case BusAW::RPC :
523
+					uromCycle = 0;
524
+					break;
525
+
526
+				case BusAW::I :
527
+					this->reg.i = valueAR;
528
+					break;
529
+
530
+				case BusAW::Ram :
531
+					if(address < MEMORY_SIZE)
532
+					{
533
+						this->ramLow.data[address] = valueAR;
534
+					}
535
+					else
536
+					{
537
+						this->ramHigh.data[address - MEMORY_SIZE] = valueAR;
538
+					}
539
+					break;
540
+
541
+				case BusAW::PCL :
542
+					this->reg.pcl = valueAR;
543
+					break;
544
+
545
+				case BusAW::PCH :
546
+					this->reg.pch = valueAR;
547
+					break;
548
+
549
+				case BusAW::MAL :
550
+					this->reg.mal = valueAR;
551
+					break;
552
+
553
+				case BusAW::MAH :
554
+					this->reg.mah = valueAR;
555
+					break;
556
+
557
+				case BusAW::PC_PLUS :
558
+					{
559
+						unsigned int pcAddress = ((static_cast<unsigned int>(this->reg.pch) << 8) + static_cast<unsigned int>(this->reg.pcl) + 1);
560
+
561
+						this->reg.pch = static_cast<unsigned char>(pcAddress >> 8);
562
+						this->reg.pcl = static_cast<unsigned char>(pcAddress & 0xff);
563
+					}
564
+					break;
565
+
566
+				case BusAW::SP_PLUS :
567
+					this->reg.spl++;
568
+					this->reg.maxSpl = qMax(this->reg.maxSpl, this->reg.spl);
569
+					break;
570
+
571
+				case BusAW::SP_MINUS :
572
+					this->reg.spl--;
573
+					break;
574
+
575
+				case BusAW::RPC_PLUS :
576
+					{
577
+						unsigned int pcAddress = ((static_cast<unsigned int>(this->reg.pch) << 8) + static_cast<unsigned int>(this->reg.pcl) + 1);
578
+
579
+						this->reg.pch = static_cast<unsigned char>(pcAddress >> 8);
580
+						this->reg.pcl = static_cast<unsigned char>(pcAddress & 0xff);
581
+
582
+						uromCycle = 0;
583
+					}
584
+					break;
585
+			}
586
+
587
+			tick++;
588
+			this->ticks++;
589
+
590
+			if((this->ticks % CLOCK_TICKS_PER_INTERVAL) == 0)
591
+			{
592
+				this->reg.in ^= IO::IN_CLOCK_BIT;
593
+			}
594
+		}
595
+		while(uromCycle > 0);
596
+
597
+		if(this->stepMode)
598
+		{
599
+			break;
600
+		}
601
+	}
602
+
603
+	emit updateSignal();
604
+}