-
Notifications
You must be signed in to change notification settings - Fork 15
/
DevJournal.txt
965 lines (801 loc) · 34.2 KB
/
DevJournal.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
-------------------------------------------- TO DO:
* Implement all 6502 opcodes.
STATUS: DONE. Testing passed.
* Implement memory write in external machine code monitor/control program.
STATUS: DONE.
* Implement extended opcodes to make VM easier for BASIC language implementation.
STATUS: Not started.
* Write BASIC compiler for my VM.
STATUS: Not started.
* Step by step debugging (do not rely on BRK).
STATUS: Done.
* In debugger, under Stack pointer display, display the contents of the stack from
the top (*SP) to bottom ($1FF).
Something like:
STOPPED at 46b
Registers:
Acc: $38 (%00111000)
X: $0
Y: $1
Addr: $46b
Acc16: $0
Ptr16: $0
Stack: $fd
[$34 $04]
Flags: NV-BDIZC
00101000
----------------------------------------
STATUS: DONE.
* In debugger add displaying of the decimal values.
STATUS: Not started.
* Add ability to set breakpoints.
This will also need a new execute or continue command variation that will stop
at the next breakpoint.
STATUS: Not started.
* Add basic character I/O emulation.
STATUS: DONE.
* Add displaying last executed op-code and argument.
STATUS: DONE.
* Implement disassembler in the debug console.
STATUS: DONE.
* Add "animation" mode, where in multi-step debugging mode the registers will
be displayed continuously at the fixed area of the screen.
STATUS: DONE.
* Implement time-scale and cycles emulation.
Note that the opcodes map contains only base # of cycles per opcode.
For accurate emulation, add 1 cycle if page boundary is crossed for select
opcodes and 1 cycle on branches taken.
Reference: http://www.oxyron.de/html/opcodes02.html
STATUS: IN PROGRESS.
Since cycle-accurate emulation was introduced, a step in debugger is
no longer a step but a cycle. It should be updated in documentation or
corrected in code so the step calls the MKCpu::Step until the # of
cycles left is 0. - DONE, Step() method is called until # of cycles
is 0.
VMachine::Run – correct so the virtual display is shown only at the
end of each instruction, not after each cycle. - DONE.
* Add ability to load binary 6502 code and hex formats.
Should be able to load from command line or debug console.
STATUS: DONE.
* Add fixed size header to binary image with emulator
* configuration data. Presence of the header will be detected
* by magic key at the beginning. Header should also include
* snapshot info, so the program can continue from the place
* where it was frozen/saved.
* Add hot-key to create snapshot/save memory image in binary file
* with header data including next execute address in memory.
STATUS: DONE.
The hot-key was not added. User must interrupt program
(CTRL-C, CTRL-Pause/Break) and then save snapshot from debugger console
menu (Y filename).
* Add ability to configure ROM range and I/O address as well as turn on/off
features in the memory image definition file.
Add keywords:
IOADDR for setting up I/O emulation address.
ENIO for I/O enabling.
ROMBEGIN, ROMEND for setting up ROM address range.
ENROM to enable ROM.
EXEC to automatically execute code at address.
STATUS: DONE.
* Refactor - MKCpu::ExecOpcode()
Replace huge switch/case statement with array of functions.
STATUS: DONE.
* Display emulation - method Display::ShowScr() works well only when console/DOS
window width matches exactly the emulated display width (currently hardcoded
80 characters). Make it work when console is wider. Automatically decrease
emulated display size when console is smaller.
STATUS: COMPLETED.
* Add Reset option in debug console, which will send the processor through its
initialization/reset procedure.
STATUS: DONE.
* Add public API methods to MKCpu class that will trigger IRQ, NMI and RESET.
According to MOS 6502 specs, when the ORQ signal comes, the execution of
current opcode is allowed to finished and then 7-cycle interrupt sequence
is executed.
STATUS: IN PROGRESS.
Reset() added to VMachine and MKCpu.
Interrupt() (IRQ) added to VMachine and MKCpu. Need to make it cycle
accurate.
Need to implement NMI.
* Add automatic recognition of memory image file format.
STATUS: DONE.
* Add graphical display device emulator.
STATUS: In progress.
Abstraction layer for memory mapped devices. - OK
Activate/deactivate graphics display from debugger console. - OK
Activate/deactivate graphics display in memory definition file
and binary header. - DONE.
NOTE: I did not reserve space for future
expansion in header section, therefore I have to recognize the older
version of header by old magic keyword: HDRMAGICKEY_OLD
New header is recognized by HDRMAGICKEY and this one has space for
future expansion (128 bytes of data vs 15 in older format) so there
will be no need to change header format if data are added up to 128
total bytes (currently only 18 bytes used).
Add line draw function/command. - DONE
Add line erase function/command. - DONE
Add rectangle draw/erase function/command. - NOT DONE
Add closed shape fill function/command. - NOT DONE
Add sprites. - NOT DONE.
Add text mode. - IN PROGRESS.
Add VM65 memory mapped raster buffer - NOT DONE.
Review all load/save methods in VMachine.cpp and correct where needed. - DONE.
[Either disable devices emulation facilities for the time of accessing memory
during load/save or skip the memory ranges assigned to active devices.
I can also introduce and use Peek8BitImg/Poke8BitImg methods that ignore memory
mapped devices.]
[Methods to review:
VMachine::SaveSnapshot,
VMachine::LoadRAMBin,
VMachine::LoadRAMHex,
VMachine::LoadMEM]
Implementing with SDL2.
I have a rudimentary graphical display class now which can clear
the screen, set bg/fg colors, set/unset pixel etc.
Now what is needed is some fake VIC chip emulation class
and some elegant way of introducing the device's registers into the
memory address space.
I designed an abstract layer between the memory and memory
mapped device. Any read/write operation on memory checks
the list of memory mapped devices. If the address falls in to the
range of any of these devices, the r/w operation is
redirected to appropriate class entry/handler method.
The devices implementations: MemMapDev.h/MemMapDev.cpp.
Text mode will require:
- the characters table base address (one of the 16 4 KB banks)
- characters table
- cursor and cursor position control/movement/mode
* Add mass storage device emulator.
STATUS: Started.
Created MassStorage.h, MassStorage.cpp for implementation of a disk-like
device. The device will emulate abstracts typical to disk surface, like
track, sector, block. It will be rather low level but will keep the images
of the emulated disk media on the hard drive.
This device will be then mapped to memory via MemMapDev class.
The memory registers will represent the functions of a low level disk
controller. E.g.: there will be a register to initiate a required data
access function (read, write, format) and registers for arguments.
There may be registers for byte-by-byte data transfer with handshaking
like protocol or a memory address register for DMA transfer mode.
Internally I will try to emulate Commodore 1541 disk format, compatible with
popular D64 image.
---------------------------------------------- TEXT TEMPLATES:
/*
*--------------------------------------------------------------------
* Method:
* Purpose:
* Arguments:
* Returns:
*--------------------------------------------------------------------
*/
/*
*--------------------------------------------------------------------
* Project: VM65 - Virtual Machine/CPU emulator programming
* framework.
*
* File:
*
* Purpose:
*
* Date:
*
* Copyright: (C) by Marek Karcz 2016. All rights reserved.
*
* Contact: [email protected]
*
* License Agreement and Warranty:
This software is provided with No Warranty.
I (Marek Karcz) will not be held responsible for any damage to
computer systems, data or user's health resulting from use.
Please proceed responsibly and apply common sense.
This software is provided in hope that it will be useful.
It is free of charge for non-commercial and educational use.
Distribution of this software in non-commercial and educational
derivative work is permitted under condition that original
copyright notices and comments are preserved. Some 3-rd party work
included with this project may require separate application for
permission from their respective authors/copyright owners.
*--------------------------------------------------------------------
*/
---------------------------------------------- LOG:
1/13/2016
Implemented ORA and ASL.
Need to test and verify proper functioning of ORA opcodes.
1/14/2016
Tested ORA opcodes.
Corrected bug in addressing mode: izy = ($00),Y
1/15/2016
Corrected problems with relative jump computation.
Implemented some new opcodes (PHP, JSR, CLC).
Optimized some code.
I rely on Piotr Kowalski's 6502 emulator/debugger to figure out some opcodes implementation.
This way I found I implemented incorrectly relative jump and also figured out how PC should
be pushed to stack during JSR.
1/18/2016
Implemented opcodes:
BIT, ROL, PLP, BMI, SEC, RTI, EOR, LSR.
1/21/2016
Implemented opcodes:
PHA, BVC, CLI.
Tested JSR, corrected bugs in JSR, RTI, RTS.
In process of implementing ADC opcodes (most difficult so far and must consider decimal
mode as well).
ADC opcodes implemented, not optimized, not tested.
1/22/2016
ADC being tested and optimized.
Still unsure how Overflow flag (V) should work.
I used this algorithm:
Logic:
t = A + M + P.C
P.V = (A.7!=t.7) ? 1:0
P.N = A.7
P.Z = (t==0) ? 1:0
IF (P.D)
t = bcd(A) + bcd(M) + P.C
P.C = (t>99) ? 1:0
ELSE
P.C = (t>255) ? 1:0
A = t & 0xFF
But Kowalski's emulator works differently.
ADC tested in IMM mode.
Implemented opcodes today:
ROR, BVS, BCC, BCS.
Improvements to debugger (step-by-step added, no need to rely on BRK only).
1/25/2016
Implemented opcodes:
CLV, TSX, CPY, CMP, DEC, DEX, CLD, CPX.
Created method MKCpu::SubWithCarry() (helper for SBC implementation).
To do:
Implement SBC and re-test ADC and SBC - compare to Kowalski's emulator results and
also to real MOS 6502 results.
2/2/2016
Finished implementing opcodes.
2/7/2016
Worknig on multiple steps function in debugger.
Testing opcodes.
2/9/2016
Testing opcodes, testing BCD mode.
I use Kowalski's emulator as my reference.
I fixed many bugs, but still something doesn't work near the end of the procedure (4k+ cycles in).
Code: testbcd.dat (TestBCD.65s).
2/10/2016
There is still problem with SBC opcode.
I get different results than Kowalski's emulator.
Around cycle 4969, address $04b7.
17:00
Still working on SBC opcode.
I may need to re-invent the whole BCD arithmetic thing and implement full internal BCD arithmetics
emulation.
2/12/2016
I finally gave up and shamelessly ripped ADC code from frodo emulator.
It almost works.
I still get unexpected sign flag result in one of the operations.
Frodo code:
/*
* Adc instruction
*/
inline void MOS6502_1541::do_adc(uint8 byte)
{
if (!d_flag) {
uint16 tmp;
// Binary mode
tmp = a + byte + (c_flag ? 1 : 0);
c_flag = tmp > 0xff;
v_flag = !((a ^ byte) & 0x80) && ((a ^ tmp) & 0x80);
z_flag = n_flag = a = tmp;
} else {
uint16 al, ah;
// Decimal mode
al = (a & 0x0f) + (byte & 0x0f) + (c_flag ? 1 : 0); // Calculate lower nybble
if (al > 9) al += 6; // BCD fixup for lower nybble
ah = (a >> 4) + (byte >> 4); // Calculate upper nybble
if (al > 0x0f) ah++;
z_flag = a + byte + (c_flag ? 1 : 0); // Set flags
n_flag = ah << 4; // Only highest bit used
v_flag = (((ah << 4) ^ a) & 0x80) && !((a ^ byte) & 0x80);
if (ah > 9) ah += 6; // BCD fixup for upper nybble
c_flag = ah > 0x0f; // Set carry flag
a = (ah << 4) | (al & 0x0f); // Compose result
}
}
/*
* Sbc instruction
*/
inline void MOS6502_1541::do_sbc(uint8 byte)
{
uint16 tmp = a - byte - (c_flag ? 0 : 1);
if (!d_flag) {
// Binary mode
c_flag = tmp < 0x100;
v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
z_flag = n_flag = a = tmp;
} else {
uint16 al, ah;
// Decimal mode
al = (a & 0x0f) - (byte & 0x0f) - (c_flag ? 0 : 1); // Calculate lower nybble
ah = (a >> 4) - (byte >> 4); // Calculate upper nybble
if (al & 0x10) {
al -= 6; // BCD fixup for lower nybble
ah--;
}
if (ah & 0x10) ah -= 6; // BCD fixup for upper nybble
c_flag = tmp < 0x100; // Set flags
v_flag = ((a ^ tmp) & 0x80) && ((a ^ byte) & 0x80);
z_flag = n_flag = tmp;
a = (ah << 4) | (al & 0x0f); // Compose result
}
}
I guess I am going to rip off the Frodo's code for now for ADC and SBC.
See what tests results will be.
OK, I ripped Frodo code for ADC/SBC and the results are good.
There is only one inconsistency compared to real 6502, where N-flag returned is wrong.
I fixed some minor issues and added help and memory write command.
I started to implement emulated console Display, class implementation for now.
2/15/2016
I/O emulation somewhat works.
Needs more testing.
NOTE:
* Fix BRK opcode (it is really 2-byte opcode, one padding by te must be added, also it alters the stack! - I didn't implement that).
* I compiled Tiny Basic for my emulator, but it doesn't work.
* Update help function (new commands were added).
17:40
I fixed BRK opcode.
I updated help function.
Corrected bug in I/O emulation (actually it was in memory, the array was too short).
Tiny BASIC - I think it doesn't work because it performs RAM test at the beginning to determine
where RAM ends by writing the memory and reading it back.
I must implement memory protection scheme so I can define addresses where writing is prohibited.
I think I will add keywords ROM_BEGIN and ROM_END to the memory definition file, which will define it at startup for now.
I also need to eliminate separate ROM image from VM. I will invent a different scheme, perhaps MMU-like.
18:25
Some success with Tiny Basic, but still some issues.
2/16/2016
0:10
TB works except it does not print numbers.
E.g.: program listing shows no line numbers, also unable to print integers.
This seems to be a problem with my emulator, because the same code works in Kowalski's emulator.
19:40
Some improvements to I/O (display) emulation.
Still no luck with emulation issue.
02/17/2016
$0F2C - RCCHR
$0F31 - SNDCHR
LBL010: sta $BD
stx $BC
jmp LBL069
JUMP22: ldx $C1 ; entry point to TBIL PN (print number) $07A7
lda $01,X
bpl LBL070
jsr LBL071
lda #$2D
jsr LBL042
LBL070: jsr LBL035
LBL069: lda #$1F
sta $B8
sta $BA
lda #$2A
sta $B9
sta $BB
ldx $BC
ldy $BD
sec
LBL072: inc $B8
txa
sbc #$10
tax
tya
sbc #$27
tay
bcs LBL072
LBL073: dec $B9
txa
adc #$E8
tax
tya
adc #$03
tay
bcc LBL073
txa
LBL074: sec
inc $BA
sbc #$64
bcs LBL074
dey
bpl LBL074
LBL075: dec $BB
adc #$0A
bcc LBL075
ora #$30
sta $BC
lda #$20
sta $BD
ldx #$FB
LBL199: stx $C3
lda $BD,X
ora $BD
cmp #$20
beq LBL076
ldy #$30
sty $BD
ora $BD
jsr LBL042
LBL076: ldx $C3
inx
bne LBL199
rts
4:50
Testing reveals that my addressing mode IZX (also called IDX), mnemonic (zpg,X) works incorrectly.
05:25
I corrected IZX addressing mode, the TESTALL.DAT now passes, but Tiny Basic still has issue with printing numbers.
17:05
I corrected addressing modes ZPX and ZPY and Tiny Basic issue with printing integers is corrected. Yeeey!
2/19/2016
I did some refactoring.
I still can't decide if I should set SoftIrq flag during BRK in RTI.
2/22/2016
Settled with SoftIrq set while emulating RTI opcode. This way user is returned to debugger console
when address counter is at address just after return from soft brk instead of in the IRQ routine.
I also made changes to Tiny Basic source code.
2/25/2016
Started implementing opcodes disassembler.
2/26/2016
Implemented animation for registers status when in multi-step mode.
Implementing disassembler.
2/27/2016
LINUX port.
Cont. disassembler implementation.
Displaying last executed opcode with argument (disassembled) in regs status - completed.
Added stack display to regs status.
Trapped all unidentified opcodes (illegal opcodes with undefined behavior).
2/28/2016
Added CTRL-Y key combination trap in I/O input mode.
Added new keywords to memory image definition file.
Created tbe.dat image that automatically enables character I/O at $E000 and auto-executes Tiny Basic.
2/29/2016
Added ROm emulation toggle switch to menu and ability to setup ROM address range.
Added new keywords to memory image definition file.
Corrected start/run address initialization, tb.dat and tbe.dat files.
Cosmetic changes to character input.
3/1/2016
Code refactoring.
Added signal handling to Windows version.
OPerator can interrupt running program from console (CTRL-C, CTRL-Break) and not only during
character input - it is not an interrupt/signal handled by OS and customized in code.
Needs testing on Linux.
3/2/2016
Added non-blocking mode to char I/O input.
3/7/2016
Corrected bugs in BRK, RTI and BIT opcodes.
EhBasic works!
The functional 6502 test now fails on ADC/SBC test at $35b5:
; binary ADC / SBC zp
3594 : 08 php ;save carry for subtract
3595 : a50d lda ad1
3597 : 650e adc ad2 ;perform add
3599 : 08 php
359a : c50f cmp adrl ;check result
trap_ne ;bad result
359c : d0fe > bne * ;failed not equal (non zero)
359e : 68 pla ;check flags
359f : 29c3 and #$c3 ;mask NV----ZC
35a1 : c511 cmp adrf
trap_ne ;bad flags
35a3 : d0fe > bne * ;failed not equal (non zero)
35a5 : 28 plp
35a6 : 08 php ;save carry for next add
35a7 : a50d lda ad1
35a9 : e512 sbc sb2 ;perform subtract
35ab : 08 php
35ac : c50f cmp adrl ;check result
trap_ne ;bad result
35ae : d0fe > bne * ;failed not equal (non zero)
35b0 : 68 pla ;check flags
35b1 : 29c3 and #$c3 ;mask NV----ZC
35b3 : c511 cmp adrf
trap_ne ;bad flags
35b5 : d0fe > bne * ;failed not equal (non zero)
18:05
Corrected ADC/SBC (setting flags).
Implemented execute/op-codes history.
Functional opcodes test passed!
3/8/2016
Added disassembler.
Refactored code.
3/9/2016
Fixed bugs in memory definition loading function.
Created tool hex2bin to convert binary file to memory definition.
Created configuration file for CL65 (CC65 package linker) and modified testall.asm
to be compiled by CL65/CA65.
Improvements to disassembler (now also see opcodes and arguments in hex, not only symbolic form).
Changes to registers UI appearance (more compact form, better readibility).
Added date/time to bin2hex tool.
3/10/2016
Improved Display/char IO emulation under Windows (DOS console) - now if the DOS console window
is wider than emulated display, extra NL is added so the lines are properly aligned.
Need to implement Linux port and also I need to implement what to do if the DOS/Linux shell
console width is too narrow for char IO emulated console width.
Added mingw makefile to compile project with standalone mingw (gcc for Windows) installation
outside Dev C++ IDE.
NOTE: I must install mingw at my home PC.
3/11/2016
Added microchess port to my emulator - need to contact Peter Jennings for permission to distribute
derivative work.
3/12/2016
Received permission from Peter Jennings.
Improved the Microchess port:
- the chessboard is not printed after each key press now but only after move
- echo entered characters
- copyright banner printed only once at the program start
Update ReadMe.txt file.
3/13/2016
Improvements to char I/O console emulation.
Now the width of the terminal/DOS session is detected at startup and the emulated console width
is adjusted accordingly:
- For terminal width < 80, the emulated console width is reduced.
- For terminal width > 80, extra NL character is added while showing the emulated console
contents (this was added already earlier).
Above was also implemented for Linux port.
Operator Interrupt flag - bug corrected.
3/14/2016
Improved performance of char I/O emulation (Display::ShowScr()).
Changed the way character I/O is emulated a bit.
In the execute mode now the char I/O from 6502 program is directly translated to stdio
of the user's DOS/shell console. Shadow copy of text screen is kept in Display device
so it has the same data. In the step-by-step mode, program is emulating the Display
by refreshing it on the user's console. Like before user can always call the contents
of the text display device in debug console by issuing 'T' command.
3/17/2016
Added reset option in debugger console and RESET sequence to the emulation.
Added RESET keyword to memory definition file.
Added command line arguments to the emulator. Now can load binary image from command line,
can also initialize CPU reset from command line.
Modified ReadMe file. Also added Debugger Console Command Reference section to ReadMe file.
4/4/2016
Implemented VM snapshot save.
4/10/2016
Refactoring (replace huge switch/case with array of pointers to methods).
4/11/2016
Refactoring (replace huge switch/case with array of pointers to methods) - completed.
IRQ added to API (MKCpu, VMachine).
4/12/2016
Working on cycle accurate emulation - DONE.
4/17/2016
Finished implementing various memory image formats.
Now program can load binary image, binary image with a header, Intel HEX format,
my own plain text memory image definition format and save binary snapshot (with header).
Also, bin2hex utility can now convert binary image (must have no VM65 header) to Intel HEX.
4/21/2016
Minor bug fixed.
4/22/2016
Automatic detection of input memory image file added.
5/23/2016
Adding SDL2 to project.
5/24/2016
Working on Graphic Display emulation.
5/26/2016
Memory mapped device.
5/27/2016
Separate class MemMapDev was a wrong idea.
Cross references between Memory and MemMapDev make it impractical to use.
Also it will be difficult to manipulate memory image directly.
I will move everything to Memory class.
5/31/2016
Working on memory mapped devices implementation.
6/1/2016
I got the memory mapped devices implementation working.
I fixed the cross references between Memory and MemMapDev classes.
Right now it is only one device - character I/O.
Shortly I will add raster display.
14:45 - raster display added. I am yet to write a test 6502 program using it
and also update the memory definition file format with new keywords to enable
or disable graphics display, setup base address etc. and also the binary
header format.
Also I need to create programmers reference guide how to program the device.
6/2/2016
I wrote a short BASIC demo program for graphics display which just draws the
diagonal line pixel by pixel.
The graphics display works somewhat, but there are problems.
The SDL window needs to be continuously refreshed and events need to be read
in a continuous loop. But the loop of my program stops when in debug
console and waits for input.
I cannot run it in a separate thread because I lose the event stream from the
main application thread. So I read events and update SDL window in handler
function for the display in MemMapDev class and I only read events in VMachine
in each step when op-code is executed.
But if no op-code is executed, the window becomes unresponsive.
When window becomes unresponsive, killing it kills my emulator.
A bit messy, I must improve upon this.
E.g: perhaps I should disable system icons on SDL window (minimize, close).
6/6/2016
Demo program now draws sinusoid and some horizontal and vertical lines.
I disabled DSL windows's title and system icons.
Tried to fix loosing alread drawn pixels when SDL window is resized, but
I failed (I tried blitting (copying) surface to temporary surface and back).
6/8/2016
Added line drawing capability to Graphics Device emulator.
6/9/2016
Added line erasing capability. Corrected scaling.
7/22/2016
Minor bug fixed.
Changes related to devices and saved images format.
7/24/2016
Finished code related to new header format, new keywords added to image
definition file (graphics display device).
7/27/2016
Correction to method VMachine::GetMemoryImageType() (not a bug, just match
additional keywords in file during file format detection process).
8/12/2016
Experimenting with code performance.
It turns out the SDL graphics device reduces performance of the emulator
significantly.
8/15/2016
Concerned about performance I added code measuring the speed of CPU emulation
using 1 MHz CPU as a reference point.
In the process I discovered that my Char I/O non-blocking input is not, well
quite non-blocking. It doesn't require CR, sure, but is still waiting for the
character to be entered from keyboard.
Reproducing:
Start EhBasic interpreter.
Interrupt to return to Debug Console.
Resume code (x addr).
Do not perform any keyboard action or run programs inside EhBasic.
Interrupt to return to Debug Console.
Note # of cycles when no keyboard actions are performed in EhBasic
is very low and always the same.
Debugging step by step shows the code stops at $FFC0 (LDA $FFE1).
Thus my performance measuring routine shows very low emulation speed.
8/16/2016
I fixed the problem with blocking/non-blocking char I/O.
Turns out I had a bug in MemMapDev::ReadCharKb() method.
Slightly optimized memory access methods (specifically memory mapped devices
iteration). Got a bit of performance boost when emmory mapped devices are
enabled (still a bottleneck though).
8/17/2016
Further performance optimizations in memory access routines.
Devices are synchronized (cached) locally to vector member in Memory class.
It turns out iterating through devices in MemMapDev class and creating
device object copy locally on stack (in the loop context) was slow.
Device object is not small enough structure to ignore cost associated with
object creation.
I also added an integer array of size equal to number of memory pages (256).
That array keeps device numbers under the indexes of memory page numbers
where there is any memory mapped device. Under the indexes of memory page
numbers where no device is present, the array has -1 value.
That value is used during memory access to decide if the memory mapped device
needs to be found and handled or not.
Note that the device number kept for given page is only one number, but
there may be more devices on given page. Therefore the values in this array
can only be used as a Y/N flag (is there device? - value >= 0
or not - value < 0) rather than the device number to obtain device handler.
If the value on given memory page is >= 0, then we know we need to query
devices and call corresponding methods that handle given device register
access.
8/18/2016
Updating benchmark results, documentation.
Major optimization in MKCpu::ExecOpcode(). The code disassembling previous
instruction to history was really slow, because I have been disassembling
to symbolic form at each op-code execution. I changed the code now in such
a way that:
- op-code execute history can be enabled/disabled
- during op-code execute I only add the last instruction op-code and other
parameters of the instruction and CPU status to the history, but I do not
parse/disassemble at this point.
- the history of op-codes execute is disassembled only when history is
requested via MKCpu::GetExecHistory().
The code is now 3 times faster with op-code execute history enabled and
about 4 times faster with op-code execute history disabled (crude estimate).
8/19/2016
Found and corrected bugs in Memory::AddDevice() and Memory::DeleteDevice().
Cosmetic changes: removed obsolete code and changes towards better code
readability.
8/22/2016
Experimenting with performance measuring code.
Added debug traces and ability to enable/disable perf. stats and debug traces.
Now the perf. stats are measured in time intervals but not more often than
predefined number of internal cycles (CPU clock ticks).
Also added proper PressEnter2Cont() function.
8/23/2016
After recent changes, the 'Last instr.' feature in Debug Console stopped
working. Since real-time disassembling is not performed now in
MKCpu::ExecOpcode() method, I have to explicitly call MKCpu::Disassemble()
to produce data for this feature.
8/26/2016
I want to move Display object from VMachine to MemMapDev. I started
coding but it is not all done.
There is experimental code that needs testing.
11:28
I almost finished this refactoring. Now Display object is maintained
inside MemMapDev. VMachine still keeps the pointer to Display object locally
since it is needed to perform few screen actions in Debug Console.
Also I found a bug in main.cpp where the ioaddr was not refreshed after
new memory image was loaded with 'L' command.
Added multitude of debug messages.
Removed 'cout' statements from memory image loading LoadMEM() and replaced
then with debug messages.
Moved Console IO specific functions from VMachine to a separate class
ConsoleIO.
Some testing done, but more testing recommended and pending for these changes.
Interesting idea:
- dump the debug log to file each time it is updated DBG_TRACE_SIZE times.
8/28/2016
Found and fixed few bugs in main.cpp (step-by-step execute).
Few cosmetic changes.
Documentation updates.
9/6/2016
Cosmetic changes. Documentation updates.
9/7/2016
Final touches before commit.
9/8/2016
I started a little research project if I will be able to do character I/O
on graphics device. I downloaded c64 character ROM and converted it to
c654_char.dat. This loads from $B000. I created new version of EhBasic
eh_basic_mk.asm which has RAM top at $AFFF, so I can use it with the
character ROM in $B000-$BFFF. EhBasic starts at $C000 as before.
I compile eh_basic_mk.asm with Kowalski's 6502 emulator built-in assembler
to pure binary ehbas.65b then convert with bin2hex to ehbas_xx.dat:
bin2hex -f ehbas.65b -o ehbas_xx.dat -w 49152 -x 49152
and modify to enable I/O.
What needs to happen:
- graphics device need to support memory mapped character data and text
mode
- character I/O routines in EhBasic must point to new char I/O device address.
9/9/2016
OK, the Linux portability (and older pre c++11 compiler compatibility)
was neglected for a long time, not to mention that I added SDL2 library
in the meantime. So I started to work on Linux. Code compiles now, but my
recent changes to character I/O left the char I/O not working on Linux.
I made some additional changes and hopefully when at home in the evening
char I/O will work on my Linux box.
21:39
Implemented 1-st working version of bitmap text mode in graphics device.
Now I am going to check the code to SVN, see if it works in Linux.
Tested on Linux - char I/O still not working. And there is a bug in local
echo mode.
9/13/2016
Wow! Many many hours to finally get it working on Linux.
I use ncurses for text and SDL2 for graphics.
Performance on Linux over XWindows is poor, but at least it works.
Huge refactoring, but better layering as a result.
Now I need to finish text mode in graphics device and update documentation.
9/14/2016
Working on a text mode in graphics display device.
To improve performance I added method
void GraphDisp::RenderChar8x8(unsigned char chdef[8], int x, int y, bool reversed);
Instead of rendering the 8x8 character definition pixel by pixel (and refreshing
the SDL surface each time) I now paint the whole character and then refresh the
surface. The performance boost is significant (at least 3-4 times faster).
Next step - copy the entire character ROM to the internal buffer of GraphDisp class
each time the address of character table changes. This way, there will be no more
VM RAM accesses when character is to be rendered.
Currently each time I render the character I copy the 8 bytes of character definition
from memory to internal 8 bytes buffer and then pass it to RenderChar8x8() method.
20:30 - I have done the internal buffer optimization. Performance was further improved
by nearly 2 times. Now method GraphDisp::RenderChar8x8() is private.
I added:
void PrintChar8x8(int code, int col, int row, bool reversed);
void CopyCharRom8x8(unsigned char *pchrom);
The 2-nd one copies characters table to internal buffer in GraphDisp class.
The 1-st one renders the character using data from internal buffer.
CopyCharRom8x8() must be called each time when address of character ROM changes.
Code snippet from MemMapDev class shows how its done:
[...]
} else if ((unsigned int)addr == mGraphDispAddr + GRAPHDEVREG_CHRTBL) {
// set new address of the character table, 2 kB bank #0-31
mGrDevRegs.mGraphDispChrTbl = (unsigned char)(val & 0x003F);
mCharTblAddr = mGrDevRegs.mGraphDispChrTbl * ((MAX_8BIT_ADDR+1) / 0x20);
unsigned char char_rom[CHROM_8x8_SIZE];
for (unsigned int i=0; i<CHROM_8x8_SIZE; i++) {
char_rom[i] = mpMem->Peek8bitImg((unsigned short)((mCharTblAddr + i) & 0xFFFF));
}
mpGraphDisp->CopyCharRom8x8(char_rom);
[...]
3/21/2017
Reactivated from long break.
I just studied the project to refresh my memory.
Replaced one macro with inline function.
3/22/2017
A small refactoring in main.cpp (replaced big if/else branch statement with switch/case).
7/28/2017
Update github repository.
5/9/2022
I have upgraded to MINGW 8.1.0