… | |
… | |
21 | # ./vt102 bash |
21 | # ./vt102 bash |
22 | # ./vt102 telnet towel.blinkenlights.nl |
22 | # ./vt102 telnet towel.blinkenlights.nl |
23 | # ./vt102 curl http://artscene.textfiles.com/vt100/trekvid.vt |
23 | # ./vt102 curl http://artscene.textfiles.com/vt100/trekvid.vt |
24 | # ./vt102 curl http://artscene.textfiles.com/vt100/surf.vt # in 3d! |
24 | # ./vt102 curl http://artscene.textfiles.com/vt100/surf.vt # in 3d! |
25 | |
25 | |
|
|
26 | # TODO: ctrl |
|
|
27 | |
26 | use common::sense; |
28 | use common::sense; |
27 | |
29 | |
28 | $| = 1; |
30 | $| = 1; |
29 | |
31 | |
30 | my $VT102 = 0; |
32 | my $VT102 = 1; |
31 | my $AVO = $VT102 || 1; |
33 | my $AVO = $VT102 || 1; |
32 | my $KBD = 1; |
34 | my $KBD = 1; |
33 | |
35 | |
34 | ############################################################################# |
36 | ############################################################################# |
35 | |
37 | |
… | |
… | |
141 | |
143 | |
142 | sub out_00 { # pusartdata |
144 | sub out_00 { # pusartdata |
143 | # handle xon/xoff, but also pass it through |
145 | # handle xon/xoff, but also pass it through |
144 | if ($_[0] == 0x13) { |
146 | if ($_[0] == 0x13) { |
145 | $XON = 0; |
147 | $XON = 0; |
|
|
148 | return;#d# |
146 | } elsif ($_[0] == 0x11) { |
149 | } elsif ($_[0] == 0x11) { |
147 | $XON = 1; |
150 | $XON = 1; |
|
|
151 | return;#d# |
148 | } |
152 | } |
149 | |
153 | |
150 | syswrite $PTY, chr $_[0]; |
154 | syswrite $PTY, chr $_[0]; |
151 | |
155 | |
152 | $INTPEND |= 1; # 5.5 txrdy |
156 | $INTPEND |= 1; |
153 | } |
157 | } |
154 | |
158 | |
155 | sub out_01 { |
159 | sub out_01 { |
156 | $PUSARTCMD = shift; |
160 | $PUSARTCMD = shift; |
157 | |
161 | |
158 | $INTPEND |= 1 if $PUSARTCMD & 0x01; # VT102, 5.5 txrdy |
162 | $INTPEND |= 1 if $PUSARTCMD & 0x01; # VT102, 5.5 txrdy |
159 | $INTPEND |= 2 if $PUSARTCMD & 0x04; # VT102, 6.5 rxrdy |
163 | $INTPEND |= 2 if $PUSARTCMD & 0x04 && !@PUSARTRECV; # VT102, 6.5 rxrdy, needed for some reason |
160 | } |
164 | } |
161 | |
165 | |
162 | sub out_02 { } # baudrate generator |
166 | sub out_02 { } # baudrate generator |
163 | |
167 | |
164 | sub out_23 { } # unknown |
168 | sub out_23 { } # unknown |
… | |
… | |
215 | |
219 | |
216 | my $NVRBIT; |
220 | my $NVRBIT; |
217 | my $LBA; |
221 | my $LBA; |
218 | |
222 | |
219 | sub in_00 { # pusart data |
223 | sub in_00 { # pusart data |
220 | # print "READ PUSARTDATA (@PUSARTRECV)\n"; |
224 | # interrupt not generated here, because infinite |
221 | |
225 | # speed does not go well with the vt102. |
222 | # $RST |= 2 if $#PUSARTRECV && $XON; |
|
|
223 | # $INTPEND |= 2 if $#PUSARTRECV && $XON; |
|
|
224 | |
226 | |
225 | shift @PUSARTRECV |
227 | shift @PUSARTRECV |
226 | } |
228 | } |
227 | |
229 | |
228 | sub in_01 { # pusart status |
230 | sub in_01 { # pusart status |
… | |
… | |
237 | |
239 | |
238 | sub in_0f { } # unknown, connected to out 2f |
240 | sub in_0f { } # unknown, connected to out 2f |
239 | |
241 | |
240 | sub in_42 { # flag buffer |
242 | sub in_42 { # flag buffer |
241 | ++$LBA; |
243 | ++$LBA; |
242 | # ++$LBA; |
|
|
243 | # printf "%04x lba %04x, %04x\n", $PC, $LBA, $CLK; |
|
|
244 | |
244 | |
245 | $NVRBIT = nvr ? 0x20 : 0x00 if ($LBA & 0x3) == 0x2; |
245 | $NVRBIT = nvr ? 0x20 : 0x00 if ($LBA & 0x3) == 0x2; |
246 | |
246 | |
247 | # KBD_XMITEMPTY LBA7 NVRDATA ODDFIELD - OPTION !GFX !AVO PUSART_TXRDY |
247 | # KBD_XMITEMPTY LBA7 NVRDATA ODDFIELD - OPTION !GFX !AVO PUSART_TXRDY |
248 | |
248 | |
… | |
… | |
266 | sub in_17 { 0xff } # unknown, printer status clear by reading? |
266 | sub in_17 { 0xff } # unknown, printer status clear by reading? |
267 | sub in_1b { 0xff } # unknown |
267 | sub in_1b { 0xff } # unknown |
268 | |
268 | |
269 | ############################################################################# |
269 | ############################################################################# |
270 | |
270 | |
271 | sub sf { |
271 | sub sf { # set flags (ZSC - AP not implemented) |
272 | $FS = $_[0] & 0x080; |
272 | $FS = $_[0] & 0x080; |
273 | $FZ = ($_[0] & 0x0ff) == 0; |
273 | $FZ = ($_[0] & 0x0ff) == 0; |
274 | $FC = $_[0] & 0x100; |
274 | $FC = $_[0] & 0x100; |
275 | |
275 | |
276 | $_[0] & 0xff |
276 | $_[0] & 0xff |
277 | } |
277 | } |
278 | |
278 | |
279 | sub sf_nc { |
279 | sub sf_nc { # set flags except carry |
280 | $FS = $_[0] & 0x080; |
280 | $FS = $_[0] & 0x080; |
281 | $FZ = ($_[0] & 0x0ff) == 0; |
281 | $FZ = ($_[0] & 0x0ff) == 0; |
282 | |
282 | |
283 | $_[0] & 0xff |
283 | $_[0] & 0xff |
284 | } |
284 | } |
… | |
… | |
549 | require IO::Pty; |
549 | require IO::Pty; |
550 | $PTY = IO::Pty->new; |
550 | $PTY = IO::Pty->new; |
551 | |
551 | |
552 | my $slave = $PTY->slave; |
552 | my $slave = $PTY->slave; |
553 | |
553 | |
|
|
554 | $PTY->set_winsize (24, 80); |
|
|
555 | |
554 | unless (fork) { |
556 | unless (fork) { |
555 | $ENV{TERM} = $VT102 ? "vt102" : "vt100"; |
557 | $ENV{TERM} = $VT102 ? "vt102" : "vt100"; |
556 | |
558 | |
557 | close $PTY; |
559 | close $PTY; |
558 | |
560 | |
559 | open STDIN , "<&", $slave; |
561 | open STDIN , "<&", $slave; |
560 | open STDOUT, ">&", $slave; |
562 | open STDOUT, ">&", $slave; |
561 | open STDERR, ">&", $slave; |
563 | open STDERR, ">&", $slave; |
562 | |
564 | |
|
|
565 | system "stty ixoff erase ^H"; |
|
|
566 | |
|
|
567 | $PTY->make_slave_controlling_terminal; |
563 | close $slave; |
568 | $PTY->close_slave; |
564 | |
569 | |
565 | exec @ARGV; |
570 | exec @ARGV; |
566 | } |
571 | } |
567 | |
572 | |
568 | close $slave; |
573 | $PTY->close_slave; |
|
|
574 | |
569 | } else { |
575 | } else { |
570 | open $PTY, "</dev/null" or die;#d |
576 | open $PTY, "</dev/null" or die;#d |
571 | } |
577 | } |
572 | |
578 | |
573 | ############################################################################# |
579 | ############################################################################# |
… | |
… | |
721 | eval "use integer; sub { $insn }" or die "$insn: $@" |
727 | eval "use integer; sub { $insn }" or die "$insn: $@" |
722 | })->(); |
728 | })->(); |
723 | |
729 | |
724 | ++$CLK; |
730 | ++$CLK; |
725 | |
731 | |
726 | #TODO: just check on ret instructions or so |
732 | # things we do from time too time only |
|
|
733 | unless ($CLK & 0xf) { |
|
|
734 | # do I/O |
|
|
735 | |
|
|
736 | unless ($CLK & 0x7ff) { |
|
|
737 | |
|
|
738 | # pty/serial I/O |
|
|
739 | unless (@PUSARTRECV || @KQUEUE || !$PTY) { |
|
|
740 | my $rin = ""; (vec $rin, fileno $PTY, 1) = 1; |
|
|
741 | |
|
|
742 | if (select $rin, undef, undef, 0) { |
|
|
743 | sysread $PTY, my $buf, 256; |
|
|
744 | push @PUSARTRECV, unpack "C*", $buf; |
|
|
745 | } |
|
|
746 | } |
|
|
747 | |
|
|
748 | # keyboard input |
|
|
749 | if ($KBD) { |
|
|
750 | while (select my $rin = "\x01", undef, undef, 0) { |
|
|
751 | sysread STDIN, $STDIN_BUF, 1, length $STDIN_BUF |
|
|
752 | or last; |
|
|
753 | } |
|
|
754 | |
|
|
755 | stdin_parse if length $STDIN_BUF; |
|
|
756 | } |
|
|
757 | } |
|
|
758 | |
|
|
759 | # kick off various interrupts |
|
|
760 | |
|
|
761 | $RST |= 2 if @PUSARTRECV && $XON; # VT100, but works on vt102, too (probably not used on real hardware though) |
|
|
762 | #$INTPEND |= 2 if @PUSARTRECV && $XON; # VT102, 6.5 rxrdy |
|
|
763 | |
|
|
764 | # kick off vertical retrace form time to time |
|
|
765 | unless ($CLK & 0x3ff) { |
|
|
766 | $RST |= 4; # vertical retrace |
|
|
767 | } |
|
|
768 | |
|
|
769 | # handle video hardware |
|
|
770 | |
|
|
771 | unless ($CLK & 0x1fff) { |
|
|
772 | prscr; |
|
|
773 | } |
|
|
774 | } |
|
|
775 | |
727 | # the interrupt logic |
776 | # the interrupt logic |
728 | $x = $INTPEND & ~$INTMASK; |
777 | $x = $INTPEND & ~$INTMASK; |
729 | |
|
|
730 | if (($RST || $x) && $IFF) { |
778 | if (($RST || $x) && $IFF) { |
731 | # rst 1 kbd data available |
779 | # rst 1 kbd data available |
732 | # rst 2 pusart xmit+recv flag |
780 | # rst 2 pusart xmit+recv flag |
733 | # rst 4 vertical retrace |
781 | # rst 4 vertical retrace |
734 | # 5.5 vt125 mb7 trans ready (serial send?) |
782 | # 5.5 vt125 mb7 trans ready (serial send?) |
… | |
… | |
751 | $M[--$SP] = $PC >> 8; |
799 | $M[--$SP] = $PC >> 8; |
752 | $M[--$SP] = $PC & 0xff; |
800 | $M[--$SP] = $PC & 0xff; |
753 | $PC = $vec; |
801 | $PC = $vec; |
754 | |
802 | |
755 | $IFF = 0; |
803 | $IFF = 0; |
756 | } |
|
|
757 | |
|
|
758 | # things we do from time too time only |
|
|
759 | unless ($CLK & 0xf) { |
|
|
760 | # do I/O |
|
|
761 | |
|
|
762 | unless ($CLK & 0x7ff) { |
|
|
763 | |
|
|
764 | # pty/serial I/O |
|
|
765 | unless (@PUSARTRECV || @KQUEUE || !$PTY) { |
|
|
766 | my $rin = ""; (vec $rin, fileno $PTY, 1) = 1; |
|
|
767 | |
|
|
768 | if (select $rin, undef, undef, 0) { |
|
|
769 | sysread $PTY, my $buf, 256; |
|
|
770 | push @PUSARTRECV, unpack "C*", $buf; |
|
|
771 | } |
|
|
772 | } |
|
|
773 | |
|
|
774 | # keyboard input |
|
|
775 | if ($KBD) { |
|
|
776 | while (select my $rin = "\x01", undef, undef, 0) { |
|
|
777 | sysread STDIN, $STDIN_BUF, 1, length $STDIN_BUF |
|
|
778 | or last; |
|
|
779 | } |
|
|
780 | |
|
|
781 | stdin_parse if length $STDIN_BUF; |
|
|
782 | } |
|
|
783 | } |
|
|
784 | |
|
|
785 | # kick off various interrupts |
|
|
786 | |
|
|
787 | $RST |= 2 if @PUSARTRECV && $XON;# vt100, also works on vt102, probably by accident |
|
|
788 | #$INTPEND |= 2 if @PUSARTRECV && $XON;# real vt102 probably does it this way |
|
|
789 | |
|
|
790 | unless ($CLK & 0x3ff) { |
|
|
791 | $RST |= 4; # vertical retrace |
|
|
792 | } |
|
|
793 | |
|
|
794 | # handle video hardware |
|
|
795 | |
|
|
796 | unless ($CLK & 0x1fff) { |
|
|
797 | prscr; |
|
|
798 | } |
|
|
799 | } |
804 | } |
800 | } |
805 | } |
801 | |
806 | |
802 | __DATA__ |
807 | __DATA__ |
803 | 1N ; 0 >b/BWog<Gӂ,O $
O [ xI,ڥ # yOt ͤ[ zW>/2!b>>g$>%
!h w-!h >-4!j pO:{ y:! u:x!_yA[>y
>yA[>?y@
:x!yA[P>>O[>>[Î:!ʵyA>>OlyAPÇ!:!S!h ~ ~ : O͓: Ô!20!2!!!yAG~"&=w< w:!/!!A:!Ey2!~1N ! ~eBi<2!͢:P =2S!~6ʘ!!6 |
808 | 1N ; 0 >b/BWog<Gӂ,O $
O [ xI,ڥ # yOt ͤ[ zW>/2!b>>g$>%
!h w-!h >-4!j pO:{ y:! u:x!_yA[>y
>yA[>?y@
:x!yA[P>>O[>>[Î:!ʵyA>>OlyAPÇ!:!S!h ~ ~ : O͓: Ô!20!2!!!yAG~"&=w< w:!/!!A:!Ey2!~1N ! ~eBi<2!͢:P =2S!~6ʘ!!6 |