Post by jmpff3d on Nov 29, 2018 6:27:09 GMT
The following text is presented in the hopes that, while from 1996AD, it may add to the investigative efforts on the VDC chip, as noted in this forum.
This text is from disC=overy, "The Journal of the Commodore Enthusiast"
Issue 1 : May 17, 1996
Reprinted with permission from the Editor-in-Chief.
This text is from disC=overy, "The Journal of the Commodore Enthusiast"
Issue 1 : May 17, 1996
Reprinted with permission from the Editor-in-Chief.
Some preliminary data on VDC timing by SLJ 1995/96 (comments -> sjudd@nwu.edu)
-----------------------------------
With some very helpful commentary from
Andreas Boose!
The 80-column VDC chip on the C128 is one of the least documented
features of the 128. All documentation I have found echoes the 128 PRG,
so that the general features and programming of the chip is well known,
but as far as I can tell there is zero information on timing, internal
operation of the VDC, etc. In an attempt to gain some insight into
the timing and operation of the VDC I wrote a series of simple experiments.
Later I received some helpful suggestions and comments from Andreas Boose:
any comments indented with a '>' are from him.
My personal interest is in using the VDC as a graphics coprocessor.
As anyone who has programmed the VDC knows, all communication with the
VDC is done through two memory locations, $D600 and $D601, and entails
the use of a busy-loop to determine when the VDC is ready to be read or
written to. My idea was to have the 8502 doing something useful instead
of sitting around waiting for the VDC, so that I could for instance do some
calculations while the screen is being cleared.
Attached are some simple programs I wrote to get a feel for VDC
timing. There is an ML program to do the VDC operations, and a BASIC
program to generate a little statistical analysis of data. Eight tests
are performed and timed using CIA #2 timer A. In retrospect some are
pretty naive, but I include them all for the sake of completeness:
Test 1: This is a simple calibration test to determine how many
cycles are used in starting/stopping the timer. It
simply starts the timer, executes 5 NOP instructions,
and stops the timer. By subtracting 10 cycles from the
time elapsed, you get the overhead.
Test 2: Load a register (Reg 18) -- This test simply times how
long it takes to tell the VDC which register you want
to operate on -- no reads or writes are performed. The
idea is to calculate how long it takes the VDC to find
a register. Note that the register is not loaded with
anything -- by "loading a register" I simply mean making
it read/write accessible.
Test 3: Load a single register twice. My idea here was to see
how 'smart' the VDC was, i.e. if it already had the
register loaded, would it spend any extra time reloading
it. In principle this should be twice Test 2 above.
Test 4: Load all registers. This test starts at register 36 and
goes down to zero. The idea here is to see if different
registers take different amounts of time to fetch, i.e.
will we just get 37 * Test 2 here?
Test 5: Two reads of register 18. The whole point of this test is
to see if _reading_ from a loaded VDC register affects
subsequent loads in any way (the expectation is that
it would not). In principle this test should be Test 3
plus an additional 8 cycles for the 2 LDA's.
Test 6: Read a single VDC memory location ($1919). This is a test
to see how long it takes to find and read a memory location
within the VDC RAM. Location $1919 was used simply because
the value $19 was already in the accumulator :). This one
should take a little more time than three register accesses.
Test 7: Loop memory fill. Using a loop on the 8502 side, this test
fills 256 bytes of VDC memory, starting at location 0,
using the auto-increment feature of the VDC.
Test 8: Block memory fill. This test uses the block-write feature
of the VDC to fill 256 bytes of VDC memory (0-255). Naturally
the idea is to compare it to Test 7.
Just to make sure the test 7 was doing what I wanted it to do I
stored the VDC memory location after the loop, to make sure it was $0100
(which it was :).
The BASIC program runs these tests a bunch of times (parameter N
in the program) and calculates a few averages. The data is all stored
in arrays so that it can be viewed, sorted, or whatever.
The first time I ran these experiments I did so in SLOW mode and in
FAST mode. In slow mode an extra 43 cycles would pop up from time to
time. As several people informed me,
>This has not anything to do with interrupts, it's the VIC-IIe's DMA which
>halts the 8502 on any bad-line for 40-43 cycles. To avoid this jitter
>switch off the screen before measuring, lda#$0b:sta$d011:lda$d012:bne*-3.
>Note the loop after switching the screen off. It's important to wait until
>the raster counter is out of the text area as switching off the screen
>doesn't affect the current screen. After measuring you can switch on the
>screen with lda#$1b:sta$d011.
These extra cycles disappear in 2MHz mode, however:
>Yes, switching to 2MHz forces the VIC-IIe to leave the phi1/2 DMA cycles
>(almost) untouched. This is a very brutal way to get rid of the 40-43 DMA
>cycles since the VIC's core doesn't know that you want him to leave these
>cycles untouched until you have switched off the screen. So it still tries
>to perform DMA. As this would mean a bus collision with the 8502 a
>protection circuit inside the VIC shuts down its address lines, AEC and BA
>on DMA times. The VIC never gets the data it wanted to display a picture,
>it gets the data the 8502 has accessed - this gives are real bogus screen.
>:-)
As a comparison, two runs follow; the second run is in SLOW mode, with VIC
turned off, and the first is in FAST mode. Both runs do 120 repetitions
(N=120):
FAST mode, N=120:
Test 1: Overhead = 1.4 (expected=1.5)
Test 2: Single register = 4.9 (expected=5)
Test 3: Single reg twice = 10.14166... (expected= 9.8)
Test 4: total time= 304.166...
minus loop overhead= 212.166...
div 37 BIT-loops = 27.166...
=> bit-loop repetions = 7.7619
Test 5: Two reads REG 18 = 14.36
Expected = 13.8 (twice Test 2)
Test 6: One memory fetch = 115.66...
Expected = 20.7 diff = 94.966...
Probable waits for VDC Reg 31 fetch = 27.133...
Test 7: Loop memory fill= 10755.766...
Extra VDC waits= 8347.866...
Avg BIT-loop repetitions = 9.3168
Test 8: Total block fill= 179.94166...
=> Approx VDC time spent on 256 byte block fill= 153.24166...
I include the above just for the sake of comparison; my 'expected'
values are very naive, and the numbers themselves are not terribly insightful.
SLOW mode, VIC disabled, N=120:
Test 1: Overhead = 3 (expected=3)
Test 2: Single register = 10 (expected=10)
Test 3: Single reg twice = 20
Test 4: total time= 554
minus loop overhead= 370
div 37 BIT-loops = 0
=> bit-loop repetions = 0
Test 5: Two reads REG 18 = 28
Expected = 28 (twice Test 2)
Test 6: One memory fetch = 118.766...
Expected = 42 diff = 76.766...
Probable waits for VDC Reg 31 fetch = 10.966...
Test 7: Loop memory fill= 11614.5333
Extra VDC waits= 6747.533...
Avg BIT-loop repetitions = 3.76536458
Test 8: Total block fill= 197
=> Approx VDC time spent on 256 byte block fill= 143
Comments: Tests six and seven are the only tests which showed variation;
all other tests stay constant throughout all trials, with one notable
exception:
Test #8 weirdness: _Very_ occasionally a spurious number will come up,
and always only on the first trial. It is possible to duplicate:
from the BASIC program, set N=5 say (so you don't have to wait
forever). When the first tests are reported and the program pauses
for input, hit run/stop -- the cursor should now be red. Then rerun
the program, and watch the last number printed. It will usually be
200, but sometimes numbers such as 1019, 1012, 592, and 963 pop up on
the first trial. If you break the program at other places, though,
these numbers don't come up. This is a mystery to me.
1MHz mode with VIC turned off is the most reliable indicator of
VDC's performance:
Test 3 is indeed just twice Test 2, which is not surprising for
register 18, since the BIT-loop is never executed. (Twice Test 2? Timid
termites tremble, eliciting tempting titilations. Temperance!)
Test 4 again suggests that no registers take longer to come up
than others. In effect, it doesn't seem to take up any time to set up
a register.
Test 5 verifies our intuition that reading $D601 doesn't alter
timings of subsequent operations.
Test 6 is an interesting one. A typical memory fetch takes a
fair amount of time! Test 4 tells us that just setting up the register
doesn't take any time; it is the write to the registers, which then
causes VDC to go and fetch the data, that slows everything down. This
will be discussed below.
Test 7 shows that memory writes are somewhat time consuming. Test 8
shows that the block-fill is a two order of magnitude improvement over
Test 7 though! 143 cycles versus 11000 -- wow! Also of interest is that
there were some BIT-loop repetitions; I expected them to not be necessary.
Andreas Boose provides a lot of insight into some of the issues
raised above:
>Stephen, 2MHz mode is not so easy as you might think. There are two facts
>you have to take in account:
>
>#1 In 2MHz mode a single raster line consists of 65 phi1 and 65 phi2
>cycles. But the 8502 doesn't get all cycles! During the last 5 phi1 cycles
>of any raster line the VIC-IIe must refresh the system's DRAM and so the
>8502 is switched to 1MHz on these cycles. Simply counting the cycles of
>the code and dividing them by 2 is not accurate. For a serious measurement
>you would have to synchronize the test loop to the VIC-IIe's refresh and
>to periodically count 120 cycles @2MHz and then 5 cycles @1MHz.
>
>#2 In 2MHz mode accessing VIC-IIe, SID, CIAs or $DE00-$DFFF forces the
>8502 back into 1MHz mode. But it is not simply done by counting these IO
>accesses as 2 2MHz mode cycles: It is different whether the IO access
>occurs during phi1 or phi2. If it happens on phi1 the VIC-IIe expands the
>cycle into phi2 and we get 2 2MHz cycles. If it hits on phi2 the VIC-IIe
>delays the IO request to phi1 and then the 1MHz mode access is performed.
>So this consumes 3 2MHz cycles instead the expected 2 cycles.
>
>For exact measurement 1MHz mode with switched off screen might be the
>best reference. But even with accurate 1MHz 8502 you will not get rid of
>odd values, the VDC has its own clocking frequency derived from a separate
>16MHz source which slides relatively to the 8502's system clock. Therefore
>there will be always some 1/2 or 1/4 cycle jitter on any $d6xx access.
>
>Also for exact measurement you have to align your routine to the VDC
>timing. In the moment you rely on the fact that the VDC can execute the
>same command in the same time regardless on what the VDC doing on the
>screen - but surely that matters. CBM engineers were 2MHz-DRAM-bandwidth-
>weenies and the VDC occupies lots of its RAM bandwidth for drawing the
>picture and refreshing the DRAM. So it must delay "foreign" RAM access of
>the 8502 to certain timing slots like the horizontal or vertical retrace
>or so.
Clearly, my experiments have just scratched the surface of the VDC.
We can make a few conclusions however:
- In many cases the usual BIT-loops are unnecessary. The things which
seem to make them necessary are the things which can tie VDC up,
namely any operations which need to talk to his memory (did I
mention that VDC is a 'he'?).
- Some operations, such as a fill, are not only efficient but take
a consistent amount of time to execute. Others, such as the
memory fetch, do not.
The VDC strikes me as being 'the final frontier' of the C= world, in that
it is not terribly well understood and there is still much to be explored.
There are two things which I think would be very nice to have, concerning
VDC: first an understanding into the internal operation of the chip, and
second a list of timings for various operations involving VDC, with the
goal of really utilizing VDC for the graphics coprocessor that he can be.
Source + 2 binaries to follow.
-------------------------------------------------------------------------
*
* vdctimes.s
*
* The purpose of this program is to gather some timing
* information on the VDC chip. It simply uses CIA #1
* timer A to measure the time to perform a series of VDC
* operations. A BASIC program will then statistically
* assemble the data.
*
* Stephen Judd
* 8/3/95
ORG $1300
TIMALO EQU $DD04 ;Timer A, CIA #2
TIMAHI EQU $DD05
CIACRA EQU $DD0E ;Control register A
* Now some macros
SETREG MAC ;Set a VDC register
STX $D600
L1 BIT $D600
BPL L1
<<<
ELAPSE MAC ;Calculate time elapsed
SEC
LDA #$FF
SBC TIMALO
STA ]1
LDA #$FF
SBC TIMAHI
STA ]1+1
<<<
SEI
INITTIM LDA #$FF ;Stick 65535 into
STA TIMALO ;timer latch
STA TIMAHI
LDA #%00011001 ;Start timer
LDY #%00001000 ;Stop timer
CALIBRAT STA CIACRA ;Figure out overhead in
NOP ;starting/stopping timer
NOP
NOP
NOP
NOP ;Elapse 10 cycles
STY CIACRA
LDA #$FF
SEC
SBC TIMALO
STA TEST
* First test: No OP; just load a register
REGTEST
LDX #18 ;Register 18
LDA #%00011001
STA CIACRA ;Start timer
>>> SETREG ;A single reg
STY CIACRA
>>> ELAPSE,REG1
LDA #%00011001
STA CIACRA
>>> SETREG ;Do it twice
>>> SETREG
STY CIACRA
>>> ELAPSE,REG2
LDX #36 ;Now we will do them all
LDA #%00011001
STA CIACRA
:LOOP >>> SETREG
DEX
BPL :LOOP ;Sub 5*37-1 cycles from total
STY CIACRA
>>> ELAPSE,ALLREG
READVDC ;Just a quick test to see if
LDX #18 ;anything weird happens by a
LDA #%00011001 ;read
STA CIACRA
>>> SETREG
LDA $DC01
>>> SETREG
LDA $DC01
STY CIACRA
>>> ELAPSE,READ18 ;This should be REG2+8
WRITEVDC ;Various tests of writing to
LDA #%00011001 ;the VDC
STA CIACRA
>>> SETREG ;Now read an actual memory
STA $D601 ;location
INX
>>> SETREG ;Three setregs total
STA $D601 ;Overhead: 6+6 cycles
LDX #31
>>> SETREG
STY CIACRA
>>> ELAPSE,READ31
LDX #18 ;Now test memory fills
LDA #00
>>> SETREG
STA $D601
>>> SETREG
STA $D601
LDA #%00011001
LDY #00
LDX #31
STA CIACRA
LDA #$66 ;Screen code 102
:LOOP >>> SETREG
STA $D601
INY
BNE :LOOP ;Overhead: 2+2+5*256-1
;(or 9*256 if sta is counted)
LDY #%00001000
STY CIACRA
>>> ELAPSE,FILLSLOW
LDX #18
LDA #00
>>> SETREG
STA $D601
INX
>>> SETREG
STA $D601
LDA #%00011001
LDX #31
STA CIACRA ;Here we go...
LDA #$66
>>> SETREG
STA $D601
LDX #24
LDA #%00000000
>>> SETREG
STA $D601
LDX #30
LDA #$FF ;Total of 256 writes
>>> SETREG
STA $D601 ;Off it goes!
LDX #18
>>> SETREG ;Hopefully this will wait until
STY CIACRA ;the fill is done!
LDA $D601 ;Just to make sure, check the
STA MEMADDR ;last address written to
INX
>>> SETREG
LDA $D601
STA MEMADDR+1
>>> ELAPSE,FILLFAST
CLI
RTS ;Whew!
TEST DS 1 ;Calibration test
REG1 DS 2 ;Single register test
REG2 DS 2 ;Same register twice
ALLREG DS 2 ;All 37 registers
READ18 DS 2 ;Two reads of register 18
READ31 DS 2 ;Three reads minus 12 cyceles
FILLSLOW DS 2 ;256 writes
MEMADDR DS 2 ;lo/hi of memory fill (a check)
FILLFAST DS 2 ;One block write of 256 chars
--
begin 644 time1.0f.uu
M 1P7' $ F2 BFY-0051)14Y#12XN+B( )1P" $ZR,3(P.D.R, !6' , _B8Z
M1K(Q.I<@-3,R-C4LPB@U,S(V-2D@KR R,SDZCR!455).($]&1B!624, 91P$
M (\@1D%35#I&/3( H1P% (8@5#$H3BDL5#(H3BDL5#,H3BDL5#0H3BDL5#4H
M3BDL5#8H3BDL5#<H3BDL5#DH3BDL058H."D ]AP* %1%4U2RT2@B,31#.2(I
M.E(QLE1%4U2J,3I2,K)2,:HR.D%2LE(RJC(Z4C.R05*J,CI2-+)2,ZHR.D93
MLE(TJC(Z34&R1E.J,CI&1K)-0:HR #H=# !!5B@Q*1H:&AH:&AH:&AH:&AH:
M&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:
M&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:
8&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:
end
begin 666 vdctest1.0d.o
M !-XJ?^-!-V-!=VI&: (C0[=ZNKJZNJ,#MVI_SCM!-V-R12B$JD9C0[=C@#6
M+ #6$/N,#MTXJ?_M!-V-RA2I_^T%W8W+%*D9C0[=C@#6+ #6$/N. -8L -80
M^XP.W3BI_^T$W8W,%*G_[07=C<T4HB2I&8T.W8X UBP UA#[RA#UC [=.*G_
M[03=C<X4J?_M!=V-SQ2B$JD9C0[=C@#6+ #6$/NM =R. -8L -80^ZT!W(P.
MW3BI_^T$W8W0%*G_[07=C=$4J1F-#MV. -8L -80^XT!UNB. -8L -80^XT!
MUJ(?C@#6+ #6$/N,#MTXJ?_M!-V-TA2I_^T%W8W3%*(2J0". -8L -80^XT!
MUHX UBP UA#[C0'6J1F@ *(?C0[=J6:. -8L -80^XT!ULC0\J (C [=.*G_
M[03=C=04J?_M!=V-U12B$JD C@#6+ #6$/N- =;HC@#6+ #6$/N- =:I&:(?
MC0[=J6:. -8L -80^XT!UJ(8J0". -8L -80^XT!UJ(>J?^. -8L -80^XT!
MUJ(2C@#6+ #6$/N,#MVM =:-UA3HC@#6+ #6$/NM =:-UQ0XJ?_M!-V-V!2I
M_^T%W8W9%%A@ :&AH:&AH:&AH:&AH:&AH:&AH:
1&AH:&AH:&AH:&AH:&AH:&AH
end
>> /S07 - "Some preliminary data on VDC timing"
>> $d600 by Stephen L. Judd
- At least one of the uuencoded files included in the original article
was found to be corrupt. Both have been verified and included below.
Note: 'vdc-explorer' is the basic portion, which loads (from drive 8)
the ML object file (vdc-explorer.o).
begin 644 vdc-explorer
M 1PP' H F2 BFY/6Q,,@Q5A03$]215(@0ED@TU1%4$A%3B#,+B#*541$(CK^
M"R Q $P<% "+(,(HT2@B,3,P,"(I*;(Q,C @IR T, !C'!X _A$B5D1#+458
M4$Q/4D52+D\B '$<* !.LC$R,#I#LC DQPR /XF.D:R,3J7(#4S,C8U+,(H
M-3,R-C4I(*\@,C,Y *(</ "/($9!4U0Z1CTR -X<1@"&(%0Q*$XI+%0R*$XI
M+%0S*$XI+%0T*$XI+%0U*$XI+%0V*$XI+%0W*$XI+%0Y*$XI+$%6*#@I #@=
M4 "9(I,B.E1%4U2RT2@B,31#.2(I.E(QLE1%4U2J,3I2,K)2,:HR.D%2LE(R
MJC(Z4C.R05*J,CI2-+)2,ZHR.D93LE(TJC(Z34&R1E.J,CI&1K)-0:HR 'P=
M6@!!5B@Q*;(P.D%6*#(ILC Z058H,RFR,#I!5B@T*;(P.D%6*#4ILC Z058H
M-BFR,#I!5B@W*;(P.D%6*#@ILC BAUD ($@2;(Q(*0@3@":'6X GB#1*"(Q
M,S P(BD PQUX %0Q*$DILL(H5$535"DZ058H,2FR058H,2FJ5#$H22FK,3"M
M1@#Q'8( 5#(H22FRPBA2,2FJ,C4VK,(H4C&J,2DZ058H,BFR058H,BFJ5#(H
M22D 'QZ, %0S*$DILL(H4C(IJC(U-JS"*%(RJC$I.D%6*#,ILD%6*#,IJE0S
M*$DI $T>E@!4-"A)*;+"*$%2*:HR-3:LPBA!4JHQ*3I!5B@T*;)!5B@T*:I4
M-"A)*0!['J 5#4H22FRPBA2,RFJ,C4VK,(H4C.J,2DZ058H-2FR058H-2FJ
M5#4H22D J1ZJ %0V*$DILL(H4C0IJC(U-JS"*%(TJC$I.D%6*#8ILD%6*#8I
MJE0V*$DI -<>M !4-RA)*;+"*$93*:HR-3:LPBA&4ZHQ*3I!5B@W*;)!5B@W
M*:I4-RA)*0#P'KX 5#BR,C4VK,(H34$IJL(H34&J,2D 'A_( %0Y*$DILL(H
M1D8IJC(U-JS"*$9&JC$I.D%6*#@ILD%6*#@IJE0Y*$DI %T?T@"9("(3$1$1
M$2)).U0Q*$DI.U0R*$DI.U0S*$DI.U0T*$DI.U0U*$DI.U0V*$DI.U0W*$DI
M.U0Y*$DI &,?W "" )D?Y@!/2+)!5B@Q*:U..IDBDP5415-4,3H@3U9%4DA%
M040](D]((B!%6%!%0U1%1#TB,ZU& +4?\ "9(AQ415-4,CH1G9V=G9V=HZ.C
MHZ,B.P#,'_H 4U*R*$%6*#(IJT%6*#$I*:U. .<?! &9+")324Y'3$4@4D5'
M25-415(](E-2 ,@#@&9+")%6%!%0U1%1"!604Q513TB,3"M1@ -(!@!C2 V
M,# *2 B 9DBGU1%4U0S.A&=G9V=G9VCHZ.CHR([ %<@+ &9+")324Y'3$4@
M4D5'25-415(@5%=)0T4](BA!5B@S*:M!5B@Q*2FM3@!S(#8!F2PB15A014-4
M140@5D%,544](E-2K#( ?2! 8T@-C P )D@2@&9(IQ415-4-#H1G9V=G9V=
MHZ.CHZ,B.P#"(%0!5%*R*$%6*#0IJT%6*#$I*:U..IDL(E1/5$%,(%1)344]
M(E12 /(@7@%44[)44JLH,S>L-:LQ*:U&.IDL(DU)3E53($Q/3U @3U9%4DA%
M040](E13 !0A: &9+")$258@,S<@0DE4+4Q/3U!3/2)44ZLS-S"M1@!#(7(!
MF2PB/3X@0DE4+4Q/3U @4D50151)5$E/3E,](BA44ZLS-S"M1BFL1JTW $TA
M? &-(#8P, !I(88!F2(>5$535#4Z$9V=G9V=G:.CHZ.C(CL DB&0 9DL(E17
M3R!214%$4R!214<@,3@](BA!5B@U*:M!5B@Q*2FM3@"R(9H!F2PB15A014-4
M140@5D%,544](E-2K#*J.*U& +PAI &-(#8P, #8(:X!F2(?5$535#8Z$9V=
MG9V=G:.CHZ.C(CL !R*X 4TQLBA!5B@V*:M!5B@Q*2FM3CJ9+")/3D4@345-
M3U)9($9%5$-(/2)-,0 [(L(!15:R4U*L,ZHQ,JU&.IDL(D584$5#5$5$(%9!
M3%5%/2)%5B(@1$E&1CTB33&K158 =B+, 9DL(E!23T(N($Y532!215!3(%1/
M(%=!250@1D]2(%9$0R!&151#2#TB*$TQJT56*:TH-ZU&*0" (M8!C2 V,#
MG"+@ 9DBGE1%4U0W.A&=G9V=G9VCHZ.CHR([ ,LBZ@%54K(H058H-RFK058H
M,2DIK4XZF2PB3$]/4"!-14U/4ED@1DE,3#TB55( _2+T 553LE52JS.M1JLR
M-3:L*%-2JCFM1BDZF2PB15A44D$@5D1#(%=!2513/2)54P O(_X!F2PB059%
M4D%'12!"250M3$]/4"!215!)5$E424].4SHB55.M*#(U-JPWK48I #DC" *-
M(#8P, !5(Q("F2*!5$535#@Z$9V=G9V=G:.CHZ.C(CL A",< E92LBA!5B@X
M*:M!5B@Q*2FM3CJ9+")43U1!3"!"3$]#2R!&24Q,/2)64@#$(R8"F2PB/3X@
M05!04D]8(%9$0R!424U%($9/4B R-38@0EE412!"3$]#2R!&24Q,/2)64JLR
M-*U&JS.L4U( RB,P CH X",Z HT@-C P.HL@0[(Q(*<@-3DP /,C1 +^)3I#
MLC$Z1K(R.HDX, ")$X"F2*?0EE%(2(Z@ 9)%@"H2!!)#J+($$DLB(B(*<@
,-C P !\D8@*.
end
begin 644 vdc-explorer.o
M !-XJ?^-!-V-!=VI&: (C0[=ZNKJZNJ,#MVI_SCM!-V-R12B$JD9C0[=C@#6
M+ #6$/N,#MTXJ?_M!-V-RA2I_^T%W8W+%*D9C0[=C@#6+ #6$/N. -8L -80
M^XP.W3BI_^T$W8W,%*G_[07=C<T4HB2I&8T.W8X UBP UA#[RA#UC [=.*G_
M[03=C<X4J?_M!=V-SQ2B$JD9C0[=C@#6+ #6$/NM =R. -8L -80^ZT!W(P.
MW3BI_^T$W8W0%*G_[07=C=$4J1F-#MV. -8L -80^XT!UNB. -8L -80^XT!
MUJ(?C@#6+ #6$/N,#MTXJ?_M!-V-TA2I_^T%W8W3%*(2J0". -8L -80^XT!
MUHX UBP UA#[C0'6J1F@ *(?C0[=J6:. -8L -80^XT!ULC0\J (C [=.*G_
M[03=C=04J?_M!=V-U12B$JD C@#6+ #6$/N- =;HC@#6+ #6$/N- =:I&:(?
MC0[=J6:. -8L -80^XT!UJ(8J0". -8L -80^XT!UJ(>J?^. -8L -80^XT!
MUJ(2C@#6+ #6$/N,#MVM =:-UA3HC@#6+ #6$/NM =:-UQ0XJ?_M!-V-V!2I
:_^T%W8W9%%A@ #6
end