… | |
… | |
27 | shift, ($VT102 = 0), ($AVO = 0) if $ARGV[0] =~ /^-?-vt100$/; |
27 | shift, ($VT102 = 0), ($AVO = 0) if $ARGV[0] =~ /^-?-vt100$/; |
28 | shift, ($VT102 = 0) if $ARGV[0] =~ /^-?-vt100\+avo$/; |
28 | shift, ($VT102 = 0) if $ARGV[0] =~ /^-?-vt100\+avo$/; |
29 | shift if $ARGV[0] =~ /^-?-vt102$/; |
29 | shift if $ARGV[0] =~ /^-?-vt102$/; |
30 | shift, ($VT131 = 1) if $ARGV[0] =~ /^-?-vt131$/; |
30 | shift, ($VT131 = 1) if $ARGV[0] =~ /^-?-vt131$/; |
31 | |
31 | |
|
|
32 | # vt100 wps = word processing roms |
|
|
33 | # vt101 = vt102 - avo, but custom rom? really? |
|
|
34 | # vt103 = vt100 + tu58 tape drive |
|
|
35 | # vt125 = vt100 + gpo graphics processor |
|
|
36 | # vt132 = vt100 + avo, stp |
|
|
37 | # vt180 = vt100 + z80 cp/m |
|
|
38 | |
32 | if ($ARGV[0] =~ /^-/) { |
39 | if ($ARGV[0] =~ /^-/) { |
33 | die <<EOF; |
40 | die <<EOF; |
34 | |
41 | |
35 | VT102, A VT100/101/102/131 SIMULATOR |
42 | VT102, A VT100/102/131 SIMULATOR |
36 | |
43 | |
37 | Usage: |
44 | Usage: |
38 | |
45 | |
39 | $0 [option] [program [args]] |
46 | $0 [option] [program [args]] |
40 | |
47 | |
… | |
… | |
399 | $op[0xb0 + $_] = 'sf8 $A |= ' . $reg[$_] for 0..7; # ora |
406 | $op[0xb0 + $_] = 'sf8 $A |= ' . $reg[$_] for 0..7; # ora |
400 | $op[0xb8 + $_] = 'sf $x = $A - ' . $reg[$_] for 0..7; # cmp |
407 | $op[0xb8 + $_] = 'sf $x = $A - ' . $reg[$_] for 0..7; # cmp |
401 | # possible todo: optimize ora a, maybe xra a |
408 | # possible todo: optimize ora a, maybe xra a |
402 | |
409 | |
403 | $op[0xc6] = 'sf $A += IMM8'; # adi |
410 | $op[0xc6] = 'sf $A += IMM8'; # adi |
404 | # ce ADI NYI |
411 | # ce ACI NYI, apparently unused |
405 | $op[0xd6] = 'sf $A -= IMM8'; # sui |
412 | $op[0xd6] = 'sf $A -= IMM8'; # sui |
406 | # de SBI NYI |
413 | # de SBI NYI, apparently unused |
407 | $op[0xe6] = 'sf8 $A &= IMM8'; # ani |
414 | $op[0xe6] = 'sf8 $A &= IMM8'; # ani |
408 | $op[0xee] = 'sf8 $A ^= IMM8'; # xri |
415 | $op[0xee] = 'sf8 $A ^= IMM8'; # xri |
409 | $op[0xf6] = 'sf8 $A |= IMM8'; # ori |
416 | $op[0xf6] = 'sf8 $A |= IMM8'; # ori |
410 | $op[0xfe] = 'sf $A - IMM8'; # cpi |
417 | $op[0xfe] = 'sf $A - IMM8'; # cpi |
411 | |
418 | |
… | |
… | |
429 | $op[0xc9] = 'JMP POP + POP * 256'; # ret |
436 | $op[0xc9] = 'JMP POP + POP * 256'; # ret |
430 | |
437 | |
431 | $op[0xc7 + $_ * 8] = "JMP $_ * 8" for 0..7; # rst |
438 | $op[0xc7 + $_ * 8] = "JMP $_ * 8" for 0..7; # rst |
432 | |
439 | |
433 | $op[0xe9] = 'JMP $H * 256 + $L'; # pchl |
440 | $op[0xe9] = 'JMP $H * 256 + $L'; # pchl |
434 | # f9 SPHL NYI |
441 | # f9 SPHL NYI, apparently unused |
435 | |
442 | |
436 | $op[0x37] = '$FC = 1 '; # stc |
443 | $op[0x37] = '$FC = 1 '; # stc |
437 | $op[0x3f] = '$FC = !$FC'; # cmc |
444 | $op[0x3f] = '$FC = !$FC'; # cmc |
438 | |
445 | |
439 | $op[0xd3] = 'OUT'; # out |
446 | $op[0xd3] = 'OUT'; # out |
440 | $op[0xdb] = 'IN'; # in |
447 | $op[0xdb] = 'IN'; # in |
441 | |
448 | |
442 | $op[0xeb] = '($D, $E, $H, $L) = ($H, $L, $D, $E)'; # xchg |
449 | $op[0xeb] = '($D, $E, $H, $L) = ($H, $L, $D, $E)'; # xchg |
443 | |
450 | |
444 | # e3 xthl NYI # @ 917b, hl <-> (sp) |
451 | # e3 xthl NYI # @ 917b in e69, hl <-> (sp) |
445 | |
452 | |
446 | $op[0x20] = '$A = $INTPEND * 16 + $INTMASK + ($IFF && 8)'; # rim (incomplete) |
453 | $op[0x20] = '$A = $INTPEND * 16 + $INTMASK + ($IFF && 8)'; # rim (incomplete) |
447 | $op[0x30] = '$INTMASK = $A & 7 if $A & 8'; # sim (incomplete) |
454 | $op[0x30] = '$INTMASK = $A & 7 if $A & 8'; # sim (incomplete) |
448 | |
455 | |
449 | $op[0xf3] = '$IFF = 0'; # DI |
456 | $op[0xf3] = '$IFF = 0'; # DI |
… | |
… | |
683 | my $slave = $PTY->slave; |
690 | my $slave = $PTY->slave; |
684 | |
691 | |
685 | $PTY->set_winsize (24, 80); |
692 | $PTY->set_winsize (24, 80); |
686 | |
693 | |
687 | unless (fork) { |
694 | unless (fork) { |
|
|
695 | $ENV{LC_ALL} = "C"; |
688 | $ENV{TERM} = $VT102 ? "vt102" : "vt100"; |
696 | $ENV{TERM} = $VT102 ? "vt102" : "vt100"; |
689 | |
697 | |
690 | close $PTY; |
698 | close $PTY; |
691 | |
699 | |
692 | open STDIN , "<&", $slave; |
700 | open STDIN , "<&", $slave; |
… | |
… | |
706 | |
714 | |
707 | ############################################################################# |
715 | ############################################################################# |
708 | # the actual hardware simulator |
716 | # the actual hardware simulator |
709 | |
717 | |
710 | my @ICACHE; # compiled instruction cache |
718 | my @ICACHE; # compiled instruction cache |
|
|
719 | |
|
|
720 | my $POWERSAVE; # powersave counter |
|
|
721 | |
|
|
722 | my $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; |
711 | |
726 | |
712 | while () { |
727 | while () { |
713 | # execute extended basic blocks |
728 | # execute extended basic blocks |
714 | $PC = ($ICACHE[$PC] ||= do { |
729 | $PC = ($ICACHE[$PC] ||= do { |
715 | my $pc = $PC; |
730 | my $pc = $PC; |
… | |
… | |
751 | # things we do from time to time only |
766 | # things we do from time to time only |
752 | unless ($CLK & 0xf) { |
767 | unless ($CLK & 0xf) { |
753 | # do I/O |
768 | # do I/O |
754 | |
769 | |
755 | unless ($CLK & 0xfff) { |
770 | unless ($CLK & 0xfff) { |
756 | |
771 | if (select $x = $RIN, undef, undef, $POWERSAVE < 100 ? 0 : 0.2) { |
757 | # pty/serial I/O |
772 | # pty/serial I/O |
758 | unless ((@PUSARTRECV >= 128) || @KQUEUE || !$PTY) { |
773 | if ($PTY && (vec $x, fileno $PTY, 1) && (@PUSARTRECV < 128) && !@KQUEUE) { |
759 | my $rin = ""; (vec $rin, fileno $PTY, 1) = 1; |
774 | my $rin = ""; (vec $rin, fileno $PTY, 1) = 1; |
760 | |
775 | |
761 | if (select $rin, undef, undef, 0) { |
776 | if (select $rin, undef, undef, 0) { |
762 | 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. |
763 | push @PUSARTRECV, unpack "C*", $buf; |
781 | push @PUSARTRECV, grep { ($_ & 0x7f) != 0x13 } unpack "C*", $buf; |
|
|
782 | } |
764 | } |
783 | } |
765 | } |
|
|
766 | |
784 | |
767 | # keyboard input |
785 | # keyboard input |
768 | if ($KBD) { |
786 | if ($KBD && (vec $x, 0, 1)) { |
769 | while (select my $rin = "\x01", undef, undef, 0) { |
787 | while (select my $rin = "\x01", undef, undef, 0) { |
770 | sysread STDIN, $STDIN_BUF, 1, length $STDIN_BUF |
788 | sysread STDIN, $STDIN_BUF, 1, length $STDIN_BUF |
771 | or last; |
789 | or last; |
|
|
790 | } |
|
|
791 | |
|
|
792 | stdin_parse if length $STDIN_BUF; |
|
|
793 | $POWERSAVE = 0; |
772 | } |
794 | } |
773 | |
795 | |
774 | stdin_parse if length $STDIN_BUF; |
796 | $POWERSAVE = 0; |
|
|
797 | } else { |
|
|
798 | ++$POWERSAVE; |
775 | } |
799 | } |
776 | } |
800 | } |
777 | |
801 | |
778 | # kick off various interrupts |
802 | # kick off various interrupts |
779 | |
803 | |