Analysis model: gpt-5.5 xhigh, sol high

Last edited: 2026-08-26

TU Player V1.0 by The Untouchables - Technical Dissection

Release date: 25 December 1991

TU Player V1.0 is a small MS-DOS VGA intro by The Untouchables. Its one screen is economical rather than static: a 33-row Gothic text strip enters one four-pixel column per frame, a three-page planar ring lets the CRTC scroll that strip without moving the whole screen, and four 17-colour ramps animate the skull, eyes, bars, logo, and lettering. A custom packed-image decoder supplies both the font atlas and the skull/TU base picture. The final TU.DAT region is a complete four-channel ProTracker module, with direct-DAC Sound Blaster and Covox playback code in the restored executable.

Continuous direct TU Player runtime excerpt

This is a direct, continuous, silent DOSBox-X excerpt from graphics-stream 00:04.000..00:10.000, reduced from the emulator's exact 2x output to the logical 320x200 frame. It shows the top strip moving independently of the lower skull picture, the next Gothic columns entering at the right edge, the horizontal bars crossing the split, and the four offset palette pulses. It is not a slideshow or a public-screen reconstruction.

Identity and source chain

Demozoo records the release as an MS-DOS intro by The Untouchables on 25 December 1991. The archive's two payload timestamps are also Christmas Day 1991. This is not a shortened copy of the group's earlier Anti-svd: the executables, TU.DAT sizes, decoded pictures, scroll text, and module formats all differ.

tu_player_v1_0_intro.zip   131,975 bytes
INTRO.EXE                   11,513 bytes   1991-12-25 15:37:34
TU.DAT                     174,035 bytes   1991-12-25 15:37:24
9226a10f98eeae8f989dd5452aec0a80298e79790a626ad25c3971e9ec07b11f  archive
e303a84308dc15344653486808e0f6816e2d2b741130775564f52563e30d1957  INTRO.EXE
5518426aa66e81dfcbadb4c2ab0738c1cd1006d18b35452b869d2b0456bc6b6a  TU.DAT

Unmodified public Pouet screenshot

The unmodified 320x200 Pouet still catches the scroll phrase The Untouchables above the same skull and logo. The direct run reproduces that composition and shows what the still cannot: the words and bars belong to a moving CRTC strip, while the skull and emblem below it come from one decoded raster resource.

Runtime capture and normal exit

The release was run through its explicit fastest/no-sound command-line route:

emulator             DOSBox-X 2024.03.01, commit 02f36ba
machine / CPU        svga_s3, normal core, fixed 12,000 cycles
guest command        INTRO.EXE /speed:7 /sound:4
host audio           SDL dummy; guest no-sound branch
capture              DOSBox-X dx-capture /v /-a /-m
graphics stream      ZMBV 640x400, 70.0863 fps, 16.879189 seconds
exit input           one X11 Space event at host-run +15 seconds
timing zero          first frame of the 640x400 graphics stream

The first 13 seconds cover the running strip and palette phases. The injected Space request becomes visible as the final palette fade by about stream 00:14; the image is almost black at 00:16, BIOS mode 3 follows, and the capture closes normally. The host mixer was dummy and sound option 4 skips the module loader and all sample output. No soundtrack was monitored or auditioned.

DOSBox-X startup, SDL, XKB, and code-page diagnostics were redirected to an ignored log. The installed build has -silent, but that option also selects dummy video, so it is unsuitable for a visual capture; ordinary launch plus stdout/stderr redirection is the quiet capture path used here.

Two unpacking boundaries

The distributed 11,513-byte MZ contains a PKLITE Copr. 1990-91 signature. One UNP pass expands it to a 23,109-byte MZ that still contains the inner backward expander. A second pass restores the actual application:

first UNP result       23,109 bytes
SHA-256                b5203fa1524e9fde227480d90486fc610b9ea6cd02617a5ee6a3c9fe911f2bec

final restored MZ     252,672 bytes
SHA-256                09715545035d8a18c7b0a9c9ef96850e824e9ede274feab5a53c8a300a3cfc73
MZ header                  272 bytes (0011h paragraphs)
load image             252,400 bytes
relocations                 60
entry                    144A:0010
entry file offset          145C0h
stack                    3D9F:46B0

Addresses below are written as linked segment:offset values from this final image. Its principal file bases are 0589 -> 059A0h, 144A -> 145B0h, and 1581 -> 15920h; DOS adds the process load segment through the relocation table at runtime.

The MZ entry at 144A:0010 gets the PSP with INT 21h/AH=62h, saves it, checks four marker words (3412h,7856h,BC9Ah,F0DEh) at the load-image start, calls the application body at 144A:10AF, and exits through INT 21h/AX=4C00h. This explains why the application can use raw segment zero as shorthand for the relocated load segment: several zero immediates are relocation words, not references to physical low memory.

Startup dispatcher

144A:10AF first checks F000:FFFE; machine-model byte FCh enables REP OUTSB for DAC transfers, while other machines use an explicit LODSB/OUT loop. It then uppercases the PSP command tail and accepts:

/SPEED:1..7
/SOUND:1..4

The speed words are:

2000 26D7 2E9C 3E25 4295 4DAE 5D37

The selected word is reduced by 0500h. Sound values become zero-based: Sound Blaster, Covox LPT1, Covox LPT2, and no sound. Missing switches lead to the corresponding BIOS-keyboard menus.

The graphics path is then:

144A:00D9  install private INT 9 handler
144A:11B6  BIOS mode 13h
144A:0870  clear all 768 DAC components
144A:0954  unchain mode 13h
144A:0939  clear all four 64 KiB VGA planes
144A:0BD7  program CRTC split/start state
0589:014C  decode font atlas to segment 2DA1h
0589:014C  decode base image directly to planar A000h
144A:08EC  copy 768-byte release palette
144A:07D4  64-level palette fade-in
144A:12AC  enter the frame loop

The INT 9 handler at 144A:00B2 reads port 60h, recognizes only Space scan code 39h, writes exit state 1 unless shutdown has already reached state 6, pulses port 61h bit 7, acknowledges the master PIC, and returns without chaining the previous keyboard handler. Escape therefore does not end this intro.

Exact TU.DAT directory

The resource-loader segment starts with three little-endian dword offsets:

0589:0000  00000000h
0589:0004  00002BDDh
0589:0008  000054F1h

They divide TU.DAT exactly:

File range Bytes Proven role
00000h..02BDCh 11,229 packed 320x200 Gothic font atlas
02BDDh..054F0h 10,516 packed 320x200 skull/TU base picture
054F1h..2A7D2h 152,290 complete four-channel M.K. module

The first word of each picture is its compressed payload length:

block 0: 2BDBh + 2-byte length = 2BDDh bytes
block 1: 2912h + 2-byte length = 2914h bytes

The graphics loader at 0589:014C opens tu.DAT, seeks to the selected dword, requests EA60h (60,000) bytes into 0589:01AC, closes the handle, and calls one of two decoders. Those deliberately oversized reads overlap later regions, but each bitstream terminates through its exact final payload byte. The loader checks open failure, not a short read; open failure exits immediately with DOS status 1 instead of unwinding video and interrupt state.

The packed-image inner loop

Linear decoder 0589:0050 and planar decoder 0589:009F share the same token loop. Both start at packed offset 2 and stop when logical destination index DI reaches FA00h, exactly 64,000 pixels. Every token uses two overlapping big-endian byte windows even though the stream-length header is little-endian:

window = (source[si] << 8) | source[si+1]
window = RCL16(window, bit_position)
window = RCL16(window, 9)

carry clear: emit low_byte(window) once
carry set:   retain that byte as colour,
             extract another window with RCL16(...,10),
             emit colour (low_byte(second_window)+1) times

bit_position++
at bit_position 8: reset it and advance source one extra byte

The first stream consists of 557 literals and 4,988 repeated-value tokens; the second has 3,879 literals and 2,894 runs. A run can emit 1..256 pixels. Decoded indexed hashes are:

bb851194d3e850f22e214ae3da19c7440ff6ca95499488d6378b514d37a759de  font
aa310556183ca439d8305a94181e1a7cfe7c7f967a0ae3337cf8a336d32888af  base picture

The linear path writes ordinary bytes with STOSB. The planar store at 0589:002B turns logical pixel index p into:

SEQ map mask = 1 << (p & 3)
VGA byte address = (p >> 2) + plane_base

It then increments the original logical index. Recombining the four planes therefore recreates the normal 320x200 chunky order exactly.

Exact decoded Gothic font atlas

This is the first TU.DAT stream decoded by that loop and coloured with the exact 768-byte, 6-bit DAC palette at restored load offsets 0071h..0370h. It is not a font approximation: the renderer reads its columns directly from the 64,000-byte result in segment 2DA1h.

Exact decoded skull and TU background

This is the second stream under the same release palette. It owns the skull, eyes, logo, and tiny lower credits in both runtime images. The bars and top message are absent because those are the live strip inserted after this image has been decoded into planar VGA memory.

Scroll-message codec and glyph records

The restored load image contains 661 encoded message bytes at 0375h..0609h, followed by count 0295h. The frame code decodes one source byte at a time with feedback from the previous encoded byte:

x          = encoded[i] XOR encoded[i-1]       // encoded[-1] = 0
plain      = ROL8(x,4) XOR 3Eh
glyph_code = plain - 20h

plain is ordinary text. It begins:

Well Dudes.... You're watching at a new masterpiece from The Untouchables
Released On Christmas-Day 1991 (25 December 1991) ...

and closes with Christmas/New Year greetings and thanks to the composers of the included MOD material. The old board-name interval was inspected to close the stream but is not reproduced here.

For glyph code g, the supporting tables are:

width byte       load[0616h + g]
source offset    word load[06D8h + 2*g]
source x/y       offset % 320, offset / 320
glyph height     33 source rows

Only codes 0..89 occur. The width table is stored in pixels and the renderer uses width >> 2 as the number of four-pixel columns. Each source pointer lands directly in the decoded atlas shown above.

One complete scroller frame

The steady-state renderer begins at 144A:0A62 (restored file 15012h). Its active constants are:

logical source pitch       320 bytes
VGA pitch per plane         80 bytes
strip height                33 rows
one strip page         33*80 = 0A50h bytes
three-page ring        3*0A50h = 1EF0h bytes
ring base                  7D00h
new-column x byte             79

The visible top region is 32 logical rows; row 33 is the guard/source row used by the ring. Mode 13h scan doubling turns the split into about 64 physical scanlines. CRTC line compare is exactly 63.

Before drawing, the renderer advances the current glyph only after source phase reaches width[g] >> 2. It then feedback-decodes the next scroll byte, looks up that glyph's atlas pointer, and computes:

source = glyph_pointer[g] + 4*source_phase
dest   = 7D00h + scroll_offset + 79

The first nested loop writes the entering four-pixel column into a selected display page:

for plane = 0..3:
    SEQ.map_mask = 1 << plane
    SI = source + plane
    DI = dest + page_select

    repeat 33 rows:
        MOVSB                    // one source pixel into this VGA plane
        SI += 013Fh              // net source stride: 1+319 = 320
        DI += 004Fh              // net VGA stride:    1+79  = 80

This is 4 planes x 33 rows = 132 byte writes. 144A:0A10 then writes CRTC start address 7D00h + scroll_offset + page_select; page_select toggles between 0 and 0A50h.

After the retrace/palette handoff, the same four-plane, 33-row column is copied again at a two-page displacement. Each row compares DI with 7D00h + 3*0A50h; crossing it subtracts 0A50h three times. That second 132 writes keeps all aliases of the circular backing strip coherent. Finally:

scroll_offset++
if scroll_offset == 0A50h: scroll_offset = 0
source_phase++

One frame therefore performs only 264 planar video-byte writes. It does not copy or clear 64,000 pixels. The CRTC advances one plane byte—four logical pixels—through the ring, while the fixed lower picture restarts at line compare 63. This is the exact ownership split visible in the GIF.

VGA setup and presentation

144A:0954 derives unchained byte-addressed mode from BIOS mode 13h:

Sequencer 04h: clear bit 3, set bit 2      disable chain-4 / odd-even
Graphics  05h: clear bit 4
Graphics  06h: clear bit 1
CRTC      14h: clear bit 6
CRTC      17h: set bit 6

The initial presentation setup writes:

CRTC 18h = 3Fh       line compare 63
CRTC 09h = 80h       scan doubling retained
CRTC 07h = 01h
CRTC start = 7D00h

There is no mode probe or fallback. The all-plane clear selects sequencer map mask 0Fh and writes 32,768 words to A000:0000, covering every 64 KiB plane.

Palette baseline, dirty range, and four pulses

The direct picture is animated chiefly through palette memory. At 144A:0D38, each frame restores 01A4h (420) baseline bytes into the working palette and preserves the previous dirty endpoints. Four calls to 144A:0F87 then overlay 51 bytes—17 RGB entries—at staggered phase starts:

frame >= 0000h  ramp at load 0DEDh, phase byte 0F86h
frame >= 00C8h  ramp at load 0E20h, phase byte 0F85h
frame >= 01A4h  ramp at load 0E53h, phase byte 0F84h
frame >= 0280h  ramp at load 0E86h, phase byte 0F83h

Each phase advances through 0..198 and indexes the 200-byte triangular table at 144A:0F81. The destination is:

palette[010Bh + 3*phase_table_value : +51]

The routine records the affected palette-index interval. 144A:0D7C writes only the merged current/previous dirty span through DAC ports 03C8h/03C9h; when the computed upper endpoint is below the lower one, it emits nothing. Every fourth frame, 144A:0FE8 also oscillates another palette interval by one component step. This is why the skull eyes, logo, bars, and letters pulse without any corresponding pixel rewrite.

The main phase counter starts at zero, increments once per loop, and at 2000h subtracts 1000h. It therefore traverses 1..8191 once and subsequently cycles through 4096..8191. The delayed ramp starts at frames 200, 420, and 640 occur only during that first traversal.

Retrace and IRQ pacing

The paced wait at 144A:011E first waits until 03DAh bit 3 is clear. It compares player IRQ count 1581:75AC with floor(selected_rate/60). If the count is not already above that budget, it waits for the next retrace start; if the renderer is late, it skips the extra wait. It then clears the count.

No-sound option 4 skips module loading, PIT reprogramming, and sample mixing. Its IRQ0 handler at 1581:6A19 performs only the stop handshake and PIC EOI, so the sample counter remains zero and normal VGA retrace controls the frame rate. The measured graphics stream is 70.0863 fps, matching the mode-13h-class refresh rather than a fixed 60 fps.

Static module and mixer audit

The soundtrack was not played, but the binary and module path are fully addressable. TU.DAT offset 54F1h begins a complete 152,290-byte ProTracker module and ends exactly at EOF:

title               SHAKIN
signature           M.K. at module +0438h / file 05929h
song length         17 orders
orders              1,1,0,2,3,4,5,5,6,6,6,7,8,8,3,0,0
patterns            9 x 1024 bytes
nonempty samples    13 of 31
sample bytes        141,990

Music loader 1581:79C5 opens the same tu.DAT, seeks to 54F1h, probes both the !Scream! and M.K. positions, and selects its 31-sample MOD loader. It reads 31 headers, the 128-position order table, 9 patterns, and 31 sample slots. Inactive branches support Scream Tracker and 15-sample MOD material; neither owns this release data.

For sound options 1..3, the selected speed word minus 0500h is a requested sample IRQ rate. At speed 7 that is 22,583 Hz; the player chooses PIT divisor floor(1193180/22583)=52, yielding about 22,945.8 IRQ/s. Tracker setup uses six ticks per row and a countdown near rate/49.

The mixer has four channel records with 16.16 nearest-neighbour sample stepping, sample end/loop pointers, volume, and a 65x256 signed-sample/volume lookup table at 1581:1D45. The IRQ alternates channel pairs (0,1) and (2,3), pipelines adjacent sums, adds 80h, and performs no separate clipping pass.

Sound Blaster output is deliberately primitive:

base ports      fixed 220h; BLASTER is not parsed
setup           reset through 226h, then send D1h speaker-on
each IRQ        poll 22Ch, send direct-DAC command 10h,
                mix one byte, poll 22Ch, send sample
DMA             none
SB IRQ          none; timing is PIT IRQ0

Covox output uses the LPT1/LPT2 data-port words at BIOS data addresses 0040:0008 and 0040:000A, with one OUT DX,AL and no control-port strobe. All playback modes replace INT 8 and acknowledge the master PIC without chaining the BIOS clock handler.

Space handshake and cleanup

When the keyboard ISR changes state to 1, main changes it to 2 and waits. The active IRQ0 handler notices state 2, calls the common stop helper at 1581:69DE, changes state to 6, and sends PIC EOI. Main then:

144A:0750  read the palette and perform 64 decrement passes
port 21h   force PIC mask 00h
port 40h   write FFh,FFh as PIT channel-0 divisor
1581:7566  restore saved INT 8 vector
144A:00FA  restore saved INT 9 vector
INT 10h    BIOS mode 3
RET        return to MZ exit

The fade reads all 768 DAC components in four 192-byte chunks and performs 64*4 paced writes, 261 paced waits including setup. Cleanup is functional but not a byte-for-byte hardware restore: the previous PIC mask and PIT mode/count are not saved, lost BIOS ticks are not compensated, the Sound Blaster never receives speaker-off D3h, and a Covox latch is not centred.

The common IRQ stop helper also runs a backwards XOR transform over part of the loaded image using the physical INT 2 vector offset as both starting/count material. Its instructions are verified; whether the original intent was anti-ripping, self-scrubbing, or another cleanup convention remains uncertain.

What the screen actually is

This production contains no vector-object, polygon, or generated-circle renderer. Its skull and TU emblem are packed indexed pixels. Its text is a packed raster font whose four-pixel columns are injected into a 33-row planar ring. Its apparent moving light is four palette overlays, not redrawn shading. The CRTC split and start-address updates make that narrow strip move while the lower raster remains fixed. The public still, exact resource decodes, direct runtime GIF, and restored inner loops all describe the same screen.