1 | #!/opt/bin/perl |
1 | #!/opt/bin/perl |
|
|
2 | |
|
|
3 | # |
|
|
4 | # Copyright(C) 2014 Marc Alexander Lehmann <vt102@schmorp.de> |
|
|
5 | # |
|
|
6 | # vt102 is free software; you can redistribute it and/or modify it under |
|
|
7 | # the terms of the GNU General Public License as published by the Free |
|
|
8 | # Software Foundation; either version 3, or (at your option) any later |
|
|
9 | # version. |
|
|
10 | # |
|
|
11 | # vt102 is distributed in the hope that it will be useful, but WITHOUT |
|
|
12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
|
13 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
|
14 | # for more details. |
|
|
15 | # |
|
|
16 | |
|
|
17 | # If this file contains embedded ROMs, the above copyright notice does |
|
|
18 | # not apply to them. |
2 | |
19 | |
3 | # this hack is not considered release ready in and way, shape, or form |
20 | # this hack is not considered release ready in and way, shape, or form |
4 | # ./vt102 bash |
21 | # ./vt102 bash |
5 | # ./vt102 telnet towel.blinkenlights.nl |
22 | # ./vt102 telnet towel.blinkenlights.nl |
6 | # ./vt102 curl http://artscene.textfiles.com/vt100/trekvid.vt |
23 | # ./vt102 curl http://artscene.textfiles.com/vt100/trekvid.vt |
7 | # ./vt102 curl http://artscene.textfiles.com/vt100/surf.vt # in 3d! |
24 | # ./vt102 curl http://artscene.textfiles.com/vt100/surf.vt # in 3d! |
|
|
25 | |
|
|
26 | # TODO: ctrl |
8 | |
27 | |
9 | use common::sense; |
28 | use common::sense; |
10 | |
29 | |
11 | $| = 1; |
30 | $| = 1; |
12 | |
31 | |
… | |
… | |
124 | |
143 | |
125 | sub out_00 { # pusartdata |
144 | sub out_00 { # pusartdata |
126 | # handle xon/xoff, but also pass it through |
145 | # handle xon/xoff, but also pass it through |
127 | if ($_[0] == 0x13) { |
146 | if ($_[0] == 0x13) { |
128 | $XON = 0; |
147 | $XON = 0; |
|
|
148 | return;#d# |
129 | } elsif ($_[0] == 0x11) { |
149 | } elsif ($_[0] == 0x11) { |
130 | $XON = 1; |
150 | $XON = 1; |
|
|
151 | return;#d# |
131 | } |
152 | } |
132 | |
153 | |
133 | syswrite $PTY, chr $_[0]; |
154 | syswrite $PTY, chr $_[0]; |
134 | |
155 | |
135 | $INTPEND |= 1; # 5.5 txrdy |
156 | $INTPEND |= 1; |
136 | } |
157 | } |
137 | |
158 | |
138 | sub out_01 { |
159 | sub out_01 { |
139 | $PUSARTCMD = shift; |
160 | $PUSARTCMD = shift; |
140 | |
161 | |
141 | $INTPEND |= 1 if $PUSARTCMD & 0x01; # VT102, 5.5 txrdy |
162 | $INTPEND |= 1 if $PUSARTCMD & 0x01; # VT102, 5.5 txrdy |
142 | $INTPEND |= 2 if $PUSARTCMD & 0x04; # VT102, 6.5 rxrdy |
163 | $INTPEND |= 2 if $PUSARTCMD & 0x04 && !@PUSARTRECV; # VT102, 6.5 rxrdy, needed for some reason |
143 | } |
164 | } |
144 | |
165 | |
145 | sub out_02 { } # baudrate generator |
166 | sub out_02 { } # baudrate generator |
146 | |
167 | |
147 | sub out_23 { } # unknown |
168 | sub out_23 { } # unknown |
… | |
… | |
198 | |
219 | |
199 | my $NVRBIT; |
220 | my $NVRBIT; |
200 | my $LBA; |
221 | my $LBA; |
201 | |
222 | |
202 | sub in_00 { # pusart data |
223 | sub in_00 { # pusart data |
203 | # print "READ PUSARTDATA (@PUSARTRECV)\n"; |
224 | # interrupt not generated here, because infinite |
204 | |
225 | # speed does not go well with the vt102. |
205 | # $RST |= 2 if $#PUSARTRECV && $XON; |
|
|
206 | # $INTPEND |= 2 if $#PUSARTRECV && $XON; |
|
|
207 | |
226 | |
208 | shift @PUSARTRECV |
227 | shift @PUSARTRECV |
209 | } |
228 | } |
210 | |
229 | |
211 | sub in_01 { # pusart status |
230 | sub in_01 { # pusart status |
… | |
… | |
220 | |
239 | |
221 | sub in_0f { } # unknown, connected to out 2f |
240 | sub in_0f { } # unknown, connected to out 2f |
222 | |
241 | |
223 | sub in_42 { # flag buffer |
242 | sub in_42 { # flag buffer |
224 | ++$LBA; |
243 | ++$LBA; |
225 | # ++$LBA; |
|
|
226 | # printf "%04x lba %04x, %04x\n", $PC, $LBA, $CLK; |
|
|
227 | |
244 | |
228 | $NVRBIT = nvr ? 0x20 : 0x00 if ($LBA & 0x3) == 0x2; |
245 | $NVRBIT = nvr ? 0x20 : 0x00 if ($LBA & 0x3) == 0x2; |
229 | |
246 | |
230 | # KBD_XMITEMPTY LBA7 NVRDATA ODDFIELD - OPTION !GFX !AVO PUSART_TXRDY |
247 | # KBD_XMITEMPTY LBA7 NVRDATA ODDFIELD - OPTION !GFX !AVO PUSART_TXRDY |
231 | |
248 | |
… | |
… | |
249 | sub in_17 { 0xff } # unknown, printer status clear by reading? |
266 | sub in_17 { 0xff } # unknown, printer status clear by reading? |
250 | sub in_1b { 0xff } # unknown |
267 | sub in_1b { 0xff } # unknown |
251 | |
268 | |
252 | ############################################################################# |
269 | ############################################################################# |
253 | |
270 | |
254 | sub sf { |
271 | sub sf { # set flags (ZSC - AP not implemented) |
255 | $FS = $_[0] & 0x080; |
272 | $FS = $_[0] & 0x080; |
256 | $FZ = ($_[0] & 0x0ff) == 0; |
273 | $FZ = ($_[0] & 0x0ff) == 0; |
257 | $FC = $_[0] & 0x100; |
274 | $FC = $_[0] & 0x100; |
258 | |
275 | |
259 | $_[0] & 0xff |
276 | $_[0] & 0xff |
260 | } |
277 | } |
261 | |
278 | |
262 | sub sf_nc { |
279 | sub sf_nc { # set flags except carry |
263 | $FS = $_[0] & 0x080; |
280 | $FS = $_[0] & 0x080; |
264 | $FZ = ($_[0] & 0x0ff) == 0; |
281 | $FZ = ($_[0] & 0x0ff) == 0; |
265 | |
282 | |
266 | $_[0] & 0xff |
283 | $_[0] & 0xff |
267 | } |
284 | } |
… | |
… | |
466 | "\x{2502}", |
483 | "\x{2502}", |
467 | "\x{2264}", |
484 | "\x{2264}", |
468 | "\x{2265}", |
485 | "\x{2265}", |
469 | "\x{03c0}", |
486 | "\x{03c0}", |
470 | "\x{2260}", |
487 | "\x{2260}", |
471 | "\x{0142}", |
488 | "\x{00a3}", |
472 | "\x{00b7}", |
489 | "\x{00b7}", |
473 | (map chr, 0x020 .. 0x7e), |
490 | (map chr, 0x020 .. 0x7e), |
474 | "?", |
491 | "?", |
475 | ); |
492 | ); |
476 | |
493 | |
… | |
… | |
532 | require IO::Pty; |
549 | require IO::Pty; |
533 | $PTY = IO::Pty->new; |
550 | $PTY = IO::Pty->new; |
534 | |
551 | |
535 | my $slave = $PTY->slave; |
552 | my $slave = $PTY->slave; |
536 | |
553 | |
|
|
554 | $PTY->set_winsize (24, 80); |
|
|
555 | |
537 | unless (fork) { |
556 | unless (fork) { |
538 | $ENV{TERM} = $VT102 ? "vt102" : "vt100"; |
557 | $ENV{TERM} = $VT102 ? "vt102" : "vt100"; |
539 | |
558 | |
540 | close $PTY; |
559 | close $PTY; |
541 | |
560 | |
542 | open STDIN , "<&", $slave; |
561 | open STDIN , "<&", $slave; |
543 | open STDOUT, ">&", $slave; |
562 | open STDOUT, ">&", $slave; |
544 | open STDERR, ">&", $slave; |
563 | open STDERR, ">&", $slave; |
545 | |
564 | |
|
|
565 | system "stty ixoff erase ^H"; |
|
|
566 | |
|
|
567 | $PTY->make_slave_controlling_terminal; |
546 | close $slave; |
568 | $PTY->close_slave; |
547 | |
569 | |
548 | exec @ARGV; |
570 | exec @ARGV; |
549 | } |
571 | } |
550 | |
572 | |
551 | close $slave; |
573 | $PTY->close_slave; |
|
|
574 | |
552 | } else { |
575 | } else { |
553 | open $PTY, "</dev/null" or die;#d |
576 | open $PTY, "</dev/null" or die;#d |
554 | } |
577 | } |
555 | |
578 | |
556 | ############################################################################# |
579 | ############################################################################# |
… | |
… | |
704 | eval "use integer; sub { $insn }" or die "$insn: $@" |
727 | eval "use integer; sub { $insn }" or die "$insn: $@" |
705 | })->(); |
728 | })->(); |
706 | |
729 | |
707 | ++$CLK; |
730 | ++$CLK; |
708 | |
731 | |
709 | #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 | |
710 | # the interrupt logic |
776 | # the interrupt logic |
711 | $x = $INTPEND & ~$INTMASK; |
777 | $x = $INTPEND & ~$INTMASK; |
712 | |
|
|
713 | if (($RST || $x) && $IFF) { |
778 | if (($RST || $x) && $IFF) { |
714 | # rst 1 kbd data available |
779 | # rst 1 kbd data available |
715 | # rst 2 pusart xmit+recv flag |
780 | # rst 2 pusart xmit+recv flag |
716 | # rst 4 vertical retrace |
781 | # rst 4 vertical retrace |
717 | # 5.5 vt125 mb7 trans ready (serial send?) |
782 | # 5.5 vt125 mb7 trans ready (serial send?) |
… | |
… | |
734 | $M[--$SP] = $PC >> 8; |
799 | $M[--$SP] = $PC >> 8; |
735 | $M[--$SP] = $PC & 0xff; |
800 | $M[--$SP] = $PC & 0xff; |
736 | $PC = $vec; |
801 | $PC = $vec; |
737 | |
802 | |
738 | $IFF = 0; |
803 | $IFF = 0; |
739 | } |
|
|
740 | |
|
|
741 | # things we do from time too time only |
|
|
742 | unless ($CLK & 0xf) { |
|
|
743 | # do I/O |
|
|
744 | |
|
|
745 | unless ($CLK & 0x7ff) { |
|
|
746 | |
|
|
747 | # pty/serial I/O |
|
|
748 | unless (@PUSARTRECV || @KQUEUE || !$PTY) { |
|
|
749 | my $rin = ""; (vec $rin, fileno $PTY, 1) = 1; |
|
|
750 | |
|
|
751 | if (select $rin, undef, undef, 0) { |
|
|
752 | sysread $PTY, my $buf, 256; |
|
|
753 | push @PUSARTRECV, unpack "C*", $buf; |
|
|
754 | } |
|
|
755 | } |
|
|
756 | |
|
|
757 | # keyboard input |
|
|
758 | if ($KBD) { |
|
|
759 | while (select my $rin = "\x01", undef, undef, 0) { |
|
|
760 | sysread STDIN, $STDIN_BUF, 1, length $STDIN_BUF |
|
|
761 | or last; |
|
|
762 | } |
|
|
763 | |
|
|
764 | stdin_parse if length $STDIN_BUF; |
|
|
765 | } |
|
|
766 | } |
|
|
767 | |
|
|
768 | # kick off various interrupts |
|
|
769 | |
|
|
770 | $RST |= 2 if @PUSARTRECV && $XON;# vt100, also works on vt102, probably by accident |
|
|
771 | #$INTPEND |= 2 if @PUSARTRECV && $XON;# real vt102 probably does it this way |
|
|
772 | |
|
|
773 | unless ($CLK & 0x3ff) { |
|
|
774 | $RST |= 4; # vertical retrace |
|
|
775 | } |
|
|
776 | |
|
|
777 | # handle video hardware |
|
|
778 | |
|
|
779 | unless ($CLK & 0x1fff) { |
|
|
780 | prscr; |
|
|
781 | } |
|
|
782 | } |
804 | } |
783 | } |
805 | } |
784 | |
806 | |
785 | __DATA__ |
807 | __DATA__ |
786 | 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 |