ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/vt102/vt102
(Generate patch)

Comparing vt102/vt102 (file contents):
Revision 1.11 by root, Wed Dec 3 02:09:49 2014 UTC vs.
Revision 1.22 by root, Wed Dec 3 10:35:59 2014 UTC

21#use common::sense; 21#use common::sense;
22 22
23my $VT102 = 1; 23my $VT102 = 1;
24my $VT131 = 0; 24my $VT131 = 0;
25my $AVO = 1; 25my $AVO = 1;
26my $KBD = 1;
27 26
28if ($ARGV[0] =~ /^-?-vt100$/) { 27shift, ($VT102 = 0), ($AVO = 0) if $ARGV[0] =~ /^-?-vt100$/;
29 shift; $VT102 = 0; $AVO = 0; 28shift, ($VT102 = 0) if $ARGV[0] =~ /^-?-vt100\+avo$/;
30} 29shift if $ARGV[0] =~ /^-?-vt102$/;
30shift, ($VT131 = 1) if $ARGV[0] =~ /^-?-vt131$/;
31 31
32if ($ARGV[0] =~ /^-?-vt100\+avo$/) { 32# vt100 wps = word processing roms
33 shift; $VT102 = 0; $AVO = 1; 33# vt101 = vt102 - avo, but custom rom? really?
34} 34# vt103 = vt100 + tu58 tape drive
35 35# vt125 = vt100 + gpo graphics processor
36if ($ARGV[0] =~ /^-?-vt102$/) { 36# vt132 = vt100 + avo, stp
37 shift; # default 37# vt180 = vt100 + z80 cp/m
38}
39
40if ($ARGV[0] =~ /^-?-vt131$/) {
41 shift; $VT131 = 1;
42}
43 38
44if ($ARGV[0] =~ /^-/) { 39if ($ARGV[0] =~ /^-/) {
45 die <<EOF; 40 die <<EOF;
46 41
47VT102, A VT100/101/102/131 SIMULATOR 42VT102, A VT100/102/131 SIMULATOR
48 43
49Usage: 44Usage:
50 45
51 $0 [option] [program [args]] 46 $0 [option] [program [args]]
52 47
84} 79}
85 80
86############################################################################# 81#############################################################################
87# ROM/hardware init 82# ROM/hardware init
88 83
84my $PTY; # the pty we allocated, if any
85my $KBD = 1;
86
89my $ROMS = do { 87my $ROMS = do {
90 binmode DATA; 88 binmode DATA;
91 local $/; 89 local $/;
92 <DATA> 90 <DATA>
93}; 91};
94 92
950x6801 == length $ROMS or die "corrupted rom image"; 930x6801 == length $ROMS or die "corrupted rom image";
96
97binmode STDOUT;
98 94
99my @M = (0xff) x 65536; # main memory, = (0xff) x 65536; 95my @M = (0xff) x 65536; # main memory, = (0xff) x 65536;
100 96
101# populate mem with rom contents 97# populate mem with rom contents
102if ($VT102) { 98if ($VT102) {
108} 104}
109 105
110############################################################################# 106#############################################################################
111# 8085 CPU registers and I/O support 107# 8085 CPU registers and I/O support
112 108
113my $PTY; # the pty we allocated, if any
114
115# 8080/8085 registers 109# 8080/8085 registers
116# b, c, d, e, h, l, a
117my ($A, $B, $C, $D, $E, $H, $L, $A); 110my ($A, $B, $C, $D, $E, $H, $L);
118my ($PC, $SP, $IFF, $FA, $FZ, $FS, $FP, $FC); 111my ($PC, $SP, $IFF, $FA, $FZ, $FS, $FP, $FC);
119 112
120my $RST = 0; # 8080 pending interrupts 113my $RST = 0; # 8080 pending interrupts
121my $INTMASK = 7; # 8085 half interrupts 114my $INTMASK = 7; # 8085 half interrupts
122my $INTPEND = 0; # 8085 half interrupts 115my $INTPEND = 0; # 8085 half interrupts
123
124my $x; # dummy temp for instructions
125 116
126my $CLK; # rather inexact clock 117my $CLK; # rather inexact clock
127 118
128############################################################################# 119#############################################################################
129# the dreaded NVR1400 chip. not needed to get it going, but provided anyway 120# the dreaded NVR1400 chip. not needed to get it going, but provided anyway
143 sub { $NVR[$_[0]] = 0x3fff; }, # 5 erase 134 sub { $NVR[$_[0]] = 0x3fff; }, # 5 erase
144 sub { $NVRDATA = $NVR[$_[0]]; }, # 6 read 135 sub { $NVRDATA = $NVR[$_[0]]; }, # 6 read
145 sub { }, # 7 standby 136 sub { }, # 7 standby
146); 137);
147 138
148my @bitidx; 139my @NVR_BITIDX;
149$bitidx[1 << $_] = 9 - $_ for 0..9; 140$NVR_BITIDX[1 << $_] = 9 - $_ for 0..9;
150 141
151# the nvr1400 state machine. what a monster 142# the nvr1400 state machine. what a monster
152sub nvr() { 143sub nvr() {
153 my $a1 = $bitidx[(~$NVRADDR ) & 0x3ff]; 144 my $a1 = $NVR_BITIDX[(~$NVRADDR ) & 0x3ff];
154 my $a0 = $bitidx[(~$NVRADDR >> 10) & 0x3ff]; 145 my $a0 = $NVR_BITIDX[(~$NVRADDR >> 10) & 0x3ff];
155 146
156# printf "NVR %02x A %020b %d %d D %02x\n", $NVRLATCH, $NVRADDR & 0xfffff, $a1, $a0, $NVRDATA; 147# printf "NVR %02x A %020b %d %d D %02x\n", $NVRLATCH, $NVRADDR & 0xfffff, $a1, $a0, $NVRDATA;
157 148
158 $NVRCMD[($NVRLATCH >> 1) & 7]($a1 * 10 + $a0, $NVRLATCH & 1) 149 $NVRCMD[($NVRLATCH >> 1) & 7]($a1 * 10 + $a0, $NVRLATCH & 1)
159} 150}
306sub in_1b { 0xff } # vt102 unknown 297sub in_1b { 0xff } # vt102 unknown
307 298
308############################################################################# 299#############################################################################
309# 8085 cpu opcodes and flag handling 300# 8085 cpu opcodes and flag handling
310 301
302my $x; # dummy scratchpad for opcodes
303
311sub sf { # set flags (ZSC - AP not implemented) 304sub sf { # set flags (ZSC - AP not implemented)
312 $FS = $_[0] & 0x080; 305 $FS = $_[0] & 0x080;
313 $FZ = !($_[0] & 0x0ff); 306 $FZ = !($_[0] & 0x0ff);
314 $FC = $_[0] & 0x100; 307 $FC = $_[0] & 0x100;
315 308
413$op[0xb0 + $_] = 'sf8 $A |= ' . $reg[$_] for 0..7; # ora 406$op[0xb0 + $_] = 'sf8 $A |= ' . $reg[$_] for 0..7; # ora
414$op[0xb8 + $_] = 'sf $x = $A - ' . $reg[$_] for 0..7; # cmp 407$op[0xb8 + $_] = 'sf $x = $A - ' . $reg[$_] for 0..7; # cmp
415# possible todo: optimize ora a, maybe xra a 408# possible todo: optimize ora a, maybe xra a
416 409
417$op[0xc6] = 'sf $A += IMM8'; # adi 410$op[0xc6] = 'sf $A += IMM8'; # adi
418# ce ADI NYI 411# ce ACI NYI, apparently unused
419$op[0xd6] = 'sf $A -= IMM8'; # sui 412$op[0xd6] = 'sf $A -= IMM8'; # sui
420# de SBI NYI 413# de SBI NYI, apparently unused
421$op[0xe6] = 'sf8 $A &= IMM8'; # ani 414$op[0xe6] = 'sf8 $A &= IMM8'; # ani
422$op[0xee] = 'sf8 $A ^= IMM8'; # xri 415$op[0xee] = 'sf8 $A ^= IMM8'; # xri
423$op[0xf6] = 'sf8 $A |= IMM8'; # ori 416$op[0xf6] = 'sf8 $A |= IMM8'; # ori
424$op[0xfe] = 'sf $A - IMM8'; # cpi 417$op[0xfe] = 'sf $A - IMM8'; # cpi
425 418
443$op[0xc9] = 'JMP POP + POP * 256'; # ret 436$op[0xc9] = 'JMP POP + POP * 256'; # ret
444 437
445$op[0xc7 + $_ * 8] = "JMP $_ * 8" for 0..7; # rst 438$op[0xc7 + $_ * 8] = "JMP $_ * 8" for 0..7; # rst
446 439
447$op[0xe9] = 'JMP $H * 256 + $L'; # pchl 440$op[0xe9] = 'JMP $H * 256 + $L'; # pchl
448# f9 SPHL NYI 441# f9 SPHL NYI, apparently unused
449 442
450$op[0x37] = '$FC = 1 '; # stc 443$op[0x37] = '$FC = 1 '; # stc
451$op[0x3f] = '$FC = !$FC'; # cmc 444$op[0x3f] = '$FC = !$FC'; # cmc
452 445
453$op[0xd3] = 'OUT'; # out 446$op[0xd3] = 'OUT'; # out
454$op[0xdb] = 'IN'; # in 447$op[0xdb] = 'IN'; # in
455 448
456$op[0xeb] = '($D, $E, $H, $L) = ($H, $L, $D, $E)'; # xchg 449$op[0xeb] = '($D, $E, $H, $L) = ($H, $L, $D, $E)'; # xchg
457 450
458# e3 xthl NYI # @ 917b, hl <-> (sp) 451# e3 xthl NYI # @ 917b in e69, hl <-> (sp)
459 452
460$op[0x20] = '$A = $INTPEND * 16 + $INTMASK + ($IFF && 8)'; # rim (incomplete) 453$op[0x20] = '$A = $INTPEND * 16 + $INTMASK + ($IFF && 8)'; # rim (incomplete)
461$op[0x30] = '$INTMASK = $A & 7 if $A & 8'; # sim (incomplete) 454$op[0x30] = '$INTMASK = $A & 7 if $A & 8'; # sim (incomplete)
462 455
463$op[0xf3] = '$IFF = 0'; # DI 456$op[0xf3] = '$IFF = 0'; # DI
498 $M[$PC], $op[$M[$PC]]; 491 $M[$PC], $op[$M[$PC]];
499} 492}
500 493
501############################################################################# 494#############################################################################
502# video emulation 495# video emulation
496
497binmode STDOUT;
503 498
504my @CHARMAP = ( 499my @CHARMAP = (
505 " " , "\x{29eb}", "\x{2592}", "\x{2409}", 500 " " , "\x{29eb}", "\x{2592}", "\x{2409}",
506 "\x{240c}", "\x{240d}", "\x{240a}", "\x{00b0}", 501 "\x{240c}", "\x{240d}", "\x{240a}", "\x{00b0}",
507 "\x{00b1}", "\x{2424}", "\x{240b}", "\x{2518}", 502 "\x{00b1}", "\x{2424}", "\x{240b}", "\x{2518}",
695my $slave = $PTY->slave; 690my $slave = $PTY->slave;
696 691
697$PTY->set_winsize (24, 80); 692$PTY->set_winsize (24, 80);
698 693
699unless (fork) { 694unless (fork) {
695 $ENV{LC_ALL} = "C";
700 $ENV{TERM} = $VT102 ? "vt102" : "vt100"; 696 $ENV{TERM} = $VT102 ? "vt102" : "vt100";
701 697
702 close $PTY; 698 close $PTY;
703 699
704 open STDIN , "<&", $slave; 700 open STDIN , "<&", $slave;
718 714
719############################################################################# 715#############################################################################
720# the actual hardware simulator 716# the actual hardware simulator
721 717
722my @ICACHE; # compiled instruction cache 718my @ICACHE; # compiled instruction cache
719
720my $POWERSAVE; # powersave counter
721
722my $RIN; # libev for the less well-off
723
724(vec $RIN, 0, 1) = 1 if $KBD;
725(vec $RIN, fileno $PTY, 1) = 1 if $PTY;
723 726
724while () { 727while () {
725 # execute extended basic blocks 728 # execute extended basic blocks
726 $PC = ($ICACHE[$PC] ||= do { 729 $PC = ($ICACHE[$PC] ||= do {
727 my $pc = $PC; 730 my $pc = $PC;
750 753
751 $insn .= "$op;\n"; 754 $insn .= "$op;\n";
752 } 755 }
753 756
754 757
755 $insn .= "$pc"; 758 $insn .= $pc;
756 $insn =~ s/\x00.*$//s; 759 $insn =~ s/\x00.*$//s;
757 760
758 eval "use integer; sub { $insn }" or die "$insn: $@" 761 eval "use integer; sub { $insn }" or die "$insn: $@"
759 })->(); 762 })->();
760 763
761 ++$CLK; 764 ++$CLK;
762 765
763 # things we do from time too time only 766 # things we do from time to time only
764 unless ($CLK & 0xf) { 767 unless ($CLK & 0xf) {
765 # do I/O 768 # do I/O
766 769
767 unless ($CLK & 0xfff) { 770 unless ($CLK & 0xfff) {
768 771 if (select $x = $RIN, undef, undef, $POWERSAVE < 100 ? 0 : 0.2) {
769 # pty/serial I/O 772 # pty/serial I/O
770 unless ((@PUSARTRECV >= 128) || @KQUEUE || !$PTY) { 773 if ($PTY && (vec $x, fileno $PTY, 1) && (@PUSARTRECV < 128) && !@KQUEUE) {
771 my $rin = ""; (vec $rin, fileno $PTY, 1) = 1; 774 my $rin = ""; (vec $rin, fileno $PTY, 1) = 1;
772 775
773 if (select $rin, undef, undef, 0) { 776 if (select $rin, undef, undef, 0) {
774 sysread $PTY, my $buf, 256; 777 sysread $PTY, my $buf, 256;
778
779 # linux don't do cs7 and/or parity anymore, so we need to filter
780 # out xoff characters to avoid freezes.
775 push @PUSARTRECV, unpack "C*", $buf; 781 push @PUSARTRECV, grep { ($_ & 0x7f) != 0x13 } unpack "C*", $buf;
782 }
776 } 783 }
777 }
778 784
779 # keyboard input 785 # keyboard input
780 if ($KBD) { 786 if ($KBD && (vec $x, 0, 1)) {
781 while (select my $rin = "\x01", undef, undef, 0) { 787 while (select my $rin = "\x01", undef, undef, 0) {
782 sysread STDIN, $STDIN_BUF, 1, length $STDIN_BUF 788 sysread STDIN, $STDIN_BUF, 1, length $STDIN_BUF
783 or last; 789 or last;
790 }
791
792 stdin_parse if length $STDIN_BUF;
793 $POWERSAVE = 0;
784 } 794 }
785 795
786 stdin_parse if length $STDIN_BUF; 796 $POWERSAVE = 0;
797 } else {
798 ++$POWERSAVE unless @PUSARTRECV || @KQUEUE;
787 } 799 }
788 } 800 }
789 801
790 # kick off various interrupts 802 # kick off various interrupts
791 803
812 # 6.5 vt125 mb7 read ready (something modem?) 824 # 6.5 vt125 mb7 read ready (something modem?)
813 # 7.5 vt125 mb7 vblank h(?) 825 # 7.5 vt125 mb7 vblank h(?)
814 # trap vt125 mbi init h(?) 826 # trap vt125 mbi init h(?)
815 my $vec; 827 my $vec;
816 828
817 $x = $INTPEND & ~$INTMASK; 829 my $pend = $INTPEND & ~$INTMASK;
818 830
819 if ($x & 1) { $vec = 0x2c; $INTPEND &= ~1; 831 if ($pend & 1) { $vec = 0x2c; $INTPEND &= ~1;
820 } elsif ($x & 2) { $vec = 0x34; $INTPEND &= ~2; 832 } elsif ($pend & 2) { $vec = 0x34; $INTPEND &= ~2;
821 } elsif ($x & 4) { $vec = 0x3c; $INTPEND &= ~4; 833 } elsif ($pend & 4) { $vec = 0x3c; $INTPEND &= ~4;
822# } elsif ($RST ) { $vec = $RST * 8; $RST = 0; # the vt102 firmware doesn't like combined interrupts 834# } elsif ($RST ) { $vec = $RST * 8; $RST = 0; # the vt102 firmware doesn't like combined interrupts
823 } elsif ($RST & 1) { $vec = 0x08; $RST &= ~1; # separate is better for vt102 835 } elsif ($RST & 1) { $vec = 0x08; $RST &= ~1; # separate is better for vt102
824 } elsif ($RST & 2) { $vec = 0x10; $RST &= ~2; 836 } elsif ($RST & 2) { $vec = 0x10; $RST &= ~2;
825 } elsif ($RST & 4) { $vec = 0x20; $RST &= ~4; 837 } elsif ($RST & 4) { $vec = 0x20; $RST &= ~4;
826 } else { 838 } else {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines