Analysis model: gpt-5.5 xhigh

Cardiac by Infiny - Technical Dissection

Scope

This is a static and limited runtime dissection of Cardiac by Infiny, the third-place PC demo at The Party 1993. The demo is interesting because it is not one monolithic executable. The released CARDIAC.EXE is an LZEXE-packed outer program with a large overlay. Inside that overlay is a bank of independently packed MZ executables: picture/animation parts, a flat-real memory manager, Kroc's 3D/vector-ball code, KTrak music support, and the final information part.

Public references:

This is not a source reconstruction. The module scheduler, every data structure field, and every generated object table are not fully named. What is covered in detail is the packaging model, the outer LZEXE depacker, the command-line part selector, the embedded executable bank, the 386/XMS/flat-real setup, the raster-synchronized palette loop, Kroc's vector-ball object path, the planar Mode X span writer, page flipping, palette fading, picture/PBM helpers, and the main color/rectangle loops that could be identified from the unpacked code.

Offset notation:

Examined Files

The archive contains:

CARDIAC.EXE   3,706,263 bytes
CONFIG.NFO        1,431 bytes
DISTSITE.NFO      1,830 bytes
FILE_ID.DIZ         490 bytes

Hashes:

4aaeb05146d7a006865bdf9fc73e297136cefc1ec14e6094f9415328d74d1763  cardiac.zip
695ffd16b40d295817476b03c658522f3ec4c49313c1e7f9f3d4618b4e536be5  CARDIAC.EXE
a12cd474065e4147340842a1865fed87cc03c78298f7a710de9364d602e71094  CONFIG.NFO
5ccb3ccc8f9ad795e210f47df2f38db23ef46d378ca01e0bc26138e04aae02b8  DISTSITE.NFO
c21eec1a814c69b1c22392ffc980322850aede101dabe0a0d1716be16689212a  FILE_ID.DIZ

FILE_ID.DIZ identifies the production as Cardiac By INFINY, with VGA, Sound Blaster, and Gravis Ultrasound support. It says the demo was released on 10 April 1994 and placed third at The Party III. Demozoo's page records the same practical release story: made for The Party 1993, presented there, and not really released until 10 April 1994.

The official result file has the PC demo third-place line with title/group effectively swapped:

The Party 1993 PC Demo

 Rank  Score   Title                         Coder/Group
  1    2492    UNTITLED                      Dust
  2    2464    The good, the bad, the ugly   S!P
  3    1584    Infiny                        Cardiac

Pouet and Demozoo both identify the production as Cardiac by Infiny, which is also what the archive metadata says.

Runtime Requirements

CONFIG.NFO is unusually explicit about what the executable expects:

That matches the code. The demo uses 386 instructions, probes XMS through int 2f, and includes flat-real/protected-mode setup code. A V86 monitor would break assumptions about switching CR0 and loading descriptor tables.

A short DOSBox-X run entered graphics mode. The run did not extract temporary files, which supports the static finding: CARDIAC.EXE contains the parts and feeds them from its own overlay rather than acting like a plain self-extracting archive.

Outer Executable Layout

The released executable is an MZ file with a very small DOS load image and a large overlay:

file size:      3,706,263 bytes
MZ extent:         22,962 bytes
header:                32 bytes
load image:         22,930 bytes
overlay:         3,683,301 bytes
relocations:             0
CS:IP:            0565:000e
SS:SP:            0b38:0080
min/max alloc:    074a/078a paragraphs
entry file off:   0x567e

UNP identifies the outer program as LZEXE 0.91/1.00a. After unpacking:

outer unpacked file size: 3,729,941 bytes
MZ extent:                  46,640 bytes
header:                      1,824 bytes
load image:                 44,816 bytes
overlay:                 3,683,301 bytes
relocations:                   449
CS:IP:                    0000:2ff5
SS:SP:                    0c1f:0400
entry file off:             0x3715

The important point is that the overlay size is unchanged. LZEXE only expands the outer loader image. The big bank of embedded parts stays in the overlay.

Outer LZEXE Depacker

The original entry at CARDIAC.EXE+0x567e is the LZEXE bootstrap. It starts by copying the packed stub upward, using std so the overlapping move is safe:

CARDIAC.EXE+0x567e:
    push es
    push cs
    pop  ds
    mov  cx,[000ch]     ; byte count / packed-stub extent
    mov  si,cx
    dec  si
    mov  di,si
    mov  bx,ds
    add  bx,[000ah]     ; destination segment above current image
    mov  es,bx
    std
    rep  movsb
    push bx
    mov  ax,002bh
    push ax
    retf                ; continue in relocated depacker

After the far return, the main bit loop uses a 16-bit reservoir. BP holds bits and DX counts how many are left. A clear bit copies a literal. A set bit decodes a match or a long-control token:

CARDIAC.EXE+0x56d3:
    mov  dx,0010h

next_bit:
    lodsw
    mov  bp,ax

bit_loop:
    shr  bp,1
    dec  dx
    jne  have_bit
    lodsw
    mov  bp,ax
    mov  dl,10h

have_bit:
    jae  match_or_long
    movsb               ; literal: input byte to output byte
    jmp  bit_loop

The short match copy reads from the already expanded output. That means overlap is intentional and required: a run can be extended by bytes it is itself writing.

CARDIAC.EXE+0x572b:
    mov  al,es:[bx+di]  ; bx is negative/backward match base
    stosb
    loop 572bh

For long files the depacker cannot pretend the whole stream fits in one 64 KB segment. The continuation path around CARDIAC.EXE+0x5741 adjusts DS, ES, SI, and DI around paragraph boundaries so the bitstream can keep expanding across segment windows. This is why the code looks stranger than a tiny COM depacker: it has to relocate and stream a proper MZ image, not just inflate a small flat blob.

After decompression, LZEXE applies the relocation table. The loop reads compressed relocation deltas, adds the actual load segment, and patches words inside the new image:

CARDIAC.EXE+0x5771:
    pop  bx
    add  bx,0010h       ; actual image base
    xor  di,di

reloc_loop:
    lodsb
    or   al,al
    je   reloc_done_or_escape
    add  di,ax
    add  es:[di],bx
    jmp  reloc_loop

The final transfer restores the recovered program's stack and jumps to its real entry:

CARDIAC.EXE+0x57a6:
    mov  ax,bx
    mov  di,[0004h]     ; recovered SP
    mov  si,[0006h]     ; recovered SS
    add  si,ax
    add  [0002h],ax     ; recovered CS relocated by load base
    xor  bx,bx
    cli
    mov  ss,si
    mov  sp,di
    ljmp cs:[bx]        ; relocated CS:IP

At this point execution is in the unpacked outer loader at outer+0x3715.

Main Loader and Part Selection

The outer loader contains the visible configuration/usage text:

INFINY 1994 - CARDIAC DEMO
- Choose configuration -
Devices
Gravis Ultrasound
Sound Blaster
No sound
Sound quality
Good quality !
Medium quality !
The sound is poor
Save configuration
Quit without save
KTrak v2.99 - coded by KROC/Infiny
INFINY 1994 - CARDIAC v1.4
CARDIAC %(-) where % is a number in '1,2,3,4,5'.
or /L to loop the demo until reboot !
1. To run the demo from the INTRO.
2. To run the demo from the 3D PART.
3. To run the demo from the VECTOR BALLS.
4. To run the demo from the COLORS PART.
5. To run the demo from the END.
- after the number allows you to see only the checked part...
187 Secret Mode Activated...

The entry around outer+0x3715 is mostly a coordinator. It calls far runtime services, parses the PSP command tail, compares against 1, 2, 3, 4, 5, /L, and the hidden 187, then chooses where the demo script starts or whether it should stop after the selected part. The loader also owns the text mode fallback and configuration menu.

The useful architectural conclusion is that the release executable is a small script engine plus a bank of separately packed code modules. The command-line selector is not a DOS batch trick; it is part of the loader.

Embedded Executable Bank

After unpacking the outer LZEXE image, nine additional MZ executables can be carved from the overlay. The packed module offsets below are in the outer unpacked file:

module  offset      packed size
MOD01   0x34c3bd       44,884
MOD02   0x357311       68,524
MOD03   0x367ebd       31,172
MOD04   0x36f881       31,091
MOD05   0x3771f4        6,111
MOD06   0x3789d3       34,036
MOD07   0x380ec7       32,785
MOD08   0x388ed8       13,039
MOD09   0x38c1c7       10,318

Each is itself LZEXE-packed. After unpacking:

module  unpacked size  header  relocations  entry file off
MOD01         84,144      464          109       0x069a
MOD02        398,704       80           13       0x26e0
MOD03         60,160    2,032          499       0x75c0
MOD04         52,496      352           80       0x05fd
MOD05         12,800      288           62       0x0120
MOD06        176,442      112           18       0xc380
MOD07         63,648    1,264          308       0x4874
MOD08         27,680      720          172       0x1451
MOD09         19,056    1,216          295       0x38e2

The string map gives good part identities:

MOD01  Barti DEPAC-LBM/PBM picture helper, palette and Mode X support.
MOD02  Kroc flat-real library, Infiny32 memory manager, TinyFli, KTrak.
MOD03  color/rectangle visual part with direct A000 copy/fill loops.
MOD04  another Barti DEPAC-LBM/PBM picture module.
MOD05  LCA 32-bit memory manager and ANIM_X bridge; raster DAC loop.
MOD06  Kroc 3D/vector-ball code and VGA span/page/palette routines.
MOD07  Barti DEPAC-LBM/PBM picture/transition module.
MOD08  credits/end picture module with Barti/Kroc/Karl/Legend/Friends strings.
MOD09  information/end text module and production credits.

MOD09 is useful as a sanity check on authorship. It names Barti for code and graphics, Kroc for code, Karl for code, LCA for code, Moog and Shad for music, and Zeb/AJT for graphics. It also contains a note about the hidden part. The static code map aligns with those roles: Barti code clusters around picture unpacking and PBM/LBM display; Kroc appears in the flat-real/audio and 3D modules; LCA appears in the 32-bit memory manager / animation bridge.

Flat Real Mode and XMS Runtime

MOD02 and MOD05 explain the strict DOS setup in CONFIG.NFO.

MOD02 contains:

Flat Real Mode library v0.2
Infiny32 : Flat Real Mode Memory Manager
TinyFli v0.01
KTrak v2.99

The module checks for a 386, checks that the machine is not already in protected mode, probes HIMEM/XMS, and manages high memory. This is the infrastructure that lets the demo keep conventional memory free while still using large animation, music, and object data.

MOD05 is smaller but very revealing. Its entry at MOD05+0x120 shrinks the DOS allocation, masks interrupts around sensitive sections, sets up FS, and calls a 32-bit memory-manager service. The protected-mode hop is conventional but direct:

MOD05+0x633:
    pushad
    ...
    lgdt [054ch]        ; GDT for temporary protected-mode descriptors
    mov  eax,cr0
    or   al,1
    mov  cr0,eax
    jmp  08h:00000183h  ; flush prefetch, enter protected side

protected_side:
    ...
    mov  ax,0
    mov  ds,ax
    mov  es,ax
    mov  fs,ax
    mov  gs,ax
    mov  ss,ax
    mov  eax,cr0
    and  eax,0fffffffeh
    mov  cr0,eax
    jmp  0000h:000001aeh

The code is not trying to stay in protected mode as a DPMI client. It uses the protected-mode transition to load descriptors and arrange large addressability, then returns to real-mode style execution with 386 segment semantics. That is the classic "flat real" pattern: use protected mode briefly as a setup tool, then run most of the demo with BIOS/VGA friendliness and large-memory access.

The XMS detection path starts with the standard multiplex API:

MOD05+0x5c7:
    mov  ax,4300h
    int  2fh            ; XMS installed?
    cmp  al,80h
    jne  no_xms
    mov  ax,4310h
    int  2fh            ; ES:BX = XMS entry point
    mov  cs:[05a0h],bx
    mov  cs:[05a2h],es

So the NFO's "HIMEM yes, EMM386 no" instruction is not superstition. The code really wants XMS services while retaining control over the CPU mode.

Raster-Synchronized DAC Loop in MOD05

MOD05 also contains a small VGA trick that is easy to miss. It programs a tweaked VGA mode, sets CRTC/attribute registers, and then updates palette components synchronized to display-enable transitions on port 3DAh.

The core loop:

MOD05+0x26f:
    mov  dx,3c8h
    xor  al,al
    out  dx,al          ; DAC write index = 0
    inc  dx             ; dx = 3c9h

palette_loop:
    outsb               ; red or first component
    outsb               ; green or second component

    mov  dx,3dah
wait_display_enable:
    in   al,dx
    test al,1
    je   wait_display_enable

    mov  dx,3c9h
    outsb               ; third component

    mov  dx,3dah
wait_display_disable:
    in   al,dx
    test al,1
    jne  wait_display_disable

The significant bit is test al,1, not test al,8. Bit 3 is vertical retrace. Bit 0 is display enable. This code is not merely waiting for vblank; it is using the fine-grained active-display/blanking state to time when a DAC component is written. On a CRT-era VGA this can produce raster-colored bands or stabilize a mid-screen palette effect by slipping one component write into a specific display-enable phase.

In practical terms:

  1. Two DAC component bytes are emitted immediately.
  2. The code waits until active display is asserted.
  3. The third component is emitted.
  4. The code waits until display enable clears again.
  5. The next palette entry or raster step can be advanced.

This is exactly the sort of loop that makes the demo sensitive to emulators and VGA clones. It depends on I/O timing and the semantics of the input-status register, not just on memory writes.

MOD06: Kroc's 3D / Vector-Ball Part

MOD06 has the strongest identifiable 3D code. Its strings include:

Credits for this part : code by Kroc
3D routines coded by Kroc/Infiny (1992/1993)
Vector-Baballes v0.84 - INFINY 1993

The entry at MOD06+0xc380 is after a large block of data. It sets its own stack, calls runtime services through int 6b, initializes VGA/audio/support state, installs a keyboard interrupt, waits for vertical blank, and then enters the vector-ball sequence:

MOD06+0xc380:
    mov  ax,2a77h
    mov  ss,ax
    mov  sp,0640h
    ...
    int  6bh            ; runtime service calls
    call 0bb05h
    call 0bc7dh
    call 0c2e8h
    call 0b7eeh
    call 294eh
    call 0c343h         ; install keyboard IRQ
    call 0c186h         ; wait one retrace phase
    call 00f7h
    ...
    call 5b3ah          ; main vector-ball sequence

The keyboard hook reads port 60h and sets a flag when it sees the relevant escape scan code, then sends EOI to the PIC:

MOD06+0xc32a:
    in   al,60h
    cmp  al,81h
    jne  chain_or_exit
    mov  byte ptr cs:[0c303h],1
    mov  al,20h
    out  20h,al

The VGA setup is a Mode 13h to unchained/tweaked planar setup. It clears A000h with all planes enabled:

    int  10h
    call 0bcefh
    mov  dx,3c4h
    mov  ax,0604h
    out  dx,ax          ; Sequencer Memory Mode
    mov  dx,3d4h
    mov  ax,0014h
    out  dx,ax          ; CRTC underline/location tweak
    mov  ax,0e317h
    out  dx,ax          ; CRTC mode control tweak
    mov  dx,3c4h
    mov  ax,0f02h
    out  dx,ax          ; map mask = all four planes
    mov  es,0a000h
    xor  di,di
    mov  eax,51515151h
    mov  cx,4000h
    rep  stosd

The normal vblank wait uses bit 3 of input-status register 1:

MOD06+0xc186:
    mov  dx,3dah
wait_on:
    in   al,dx
    test al,8
    je   wait_on
wait_off:
    in   al,dx
    test al,8
    jne  wait_off
    ret

That is separate from the MOD05 display-enable DAC loop. MOD06 uses vblank for frame pacing; MOD05 uses display-enable timing for raster palette work.

Object Slot Allocator

The vector-ball part keeps a small table of active object slots. The table at 0640h has 50 word entries; 076ch holds the active count. Clearing the table is a compact rep stosw:

MOD06+0x29184:
    pusha
    mov  di,0640h
    mov  cx,0032h
    mov  ax,0ffffh
    rep  stosw          ; 50 free slots
    mov  word ptr [076ch],0
    popa
    ret

Freeing an object trusts the index stored in the object record at [bx+16]. If the index is valid and the table entry is live, it marks both sides free:

MOD06+0x29198:
    mov  ax,0ffffh
    push di
    mov  di,0640h
    cmp  word ptr [bx+16],0ffffh
    je   done
    mov  si,[bx+16]
    shl  si,1
    add  di,si
    cmp  word ptr [di],0ffffh
    je   done
    dec  word ptr [076ch]
    mov  word ptr [di],0ffffh
    mov  word ptr [bx+16],0ffffh
    xor  ax,ax
done:
    pop  di
    ret

Allocating scans linearly for the first free slot:

MOD06+0x291c1:
    cmp  word ptr [076ch],0032h
    jae  full
    mov  si,0640h
scan:
    lodsw
    cmp  ax,0ffffh
    jne  scan
    mov  [si-2],bx      ; slot points to object record
    inc  word ptr [076ch]
    sub  si,0640h
    shr  si,1
    dec  si
    mov  [bx+16],si     ; object remembers slot index
    xor  ax,ax
    ret
full:
    mov  ax,0ffffh
    ret

There is no heap sophistication here because the object count is small and fixed. The important feature is determinism: frame code can walk at most 50 slots, and allocation cost is bounded.

Projection and Visible-Object Sorting

The object walk at MOD06+0x291ea computes camera-relative deltas from object coordinates and tests a squared-distance threshold. The camera position appears at [079c], [07a0], and [07a4]; temporary deltas go to [07b0], [07b2], and [07b4].

The inner arithmetic is 386-style 32-bit multiply inside 16-bit code:

    mov  eax,[bp+00h]   ; object x, fixed/integer long
    sub  eax,[079ch]    ; camera x
    mov  [07b0h],ax
    imul eax            ; edx:eax = dx * dx
    mov  ecx,eax
    mov  ebx,edx

    mov  eax,[bp+04h]   ; object y
    sub  eax,[07a0h]
    mov  [07b2h],ax
    imul eax
    add  ecx,eax
    adc  ebx,edx

    mov  eax,[bp+08h]   ; object z
    sub  eax,[07a4h]
    mov  [07b4h],ax
    imul eax
    add  ecx,eax
    adc  ebx,edx

    shld ebx,ecx,16
    cmp  ebx,35a4h
    jge  skip_object

That is a distance cull. The exact unit scale is data-dependent, but the shape is clear: square X/Y/Z deltas, accumulate a high-range distance measure, reject objects beyond a threshold.

For visible objects it then projects/transforms the saved deltas and builds a sort list at 06a4h:

    movsx eax,word ptr [07b0h]
    movsx ebx,word ptr [07b2h]
    movsx ecx,word ptr [07b4h]
    call 2947ch         ; transform/project to screen/depth
    neg  ax
    mov  [di],ax        ; sort key
    mov  [di+2],bp      ; object pointer
    add  di,4
    inc  word ptr [076eh]

If more than one object survives, it calls a sort routine at 0x293bf, then draws in sorted order:

    cmp  word ptr [076eh],1
    jbe  no_sort
    call 293bfh

draw_sorted:
    mov  cx,[076eh]
    mov  si,06a4h
next_object:
    mov  bp,[si+2]
    add  si,4
    call 292bch         ; draw this object
    loop next_object

Inside the object draw routine, a bounds routine at 0x295e7 rejects objects that would fall outside the visible screen rectangle. Surviving polygon/ball records are converted into a secondary draw list at 04b0h, sorted again, then sent to the rasterizer. That two-level ordering is typical for this kind of 1993 engine: first sort whole objects, then sort faces or ball sprites inside an object.

Planar Span Filler Inner Loop

The most important low-level loop in MOD06 is the horizontal span writer around MOD06+0x2a268. It draws clipped spans in a planar VGA layout. In this mode, four adjacent pixels share one byte address, selected by the Sequencer map-mask register at port 3C4h/3C5h.

Inputs visible in the code:

[0da6]    first scanline / y0
[0da8]    last scanline / y1
[0da0]    fill color
[0a1c]    left-edge x table, one word per scanline
[0bac]    right-edge x table, one word per scanline
[5102]    current page segment, usually A000h or A400h

Setup:

MOD06+0x2a268:
    mov  cx,[0da8h]
    mov  si,[0da6h]
    sub  cx,si
    inc  cx             ; number of scanlines

    shl  si,1
    mov  bp,si
    add  si,0a1ch       ; SI -> left-edge table row

    ; compute initial row base in BP, effectively y * 80
    ; after shifts/adds, next rows add 50h bytes.

    mov  es,[5102h]     ; active draw page
    mov  dx,3c4h
    mov  al,2
    out  dx,al
    inc  dx             ; dx = 3c5h, sequencer map mask data port
    mov  ah,[0da0h]     ; AH = color

Per scanline it loads the two edge X values, orders them, clips them, converts the first X to a byte offset and starting plane, and writes three possible regions: leading partial byte, full middle bytes, trailing partial byte.

The ordered/clipped part:

span_line:
    push cx
    mov  cx,[si]        ; x0
    mov  bx,[si+0190h]  ; x1, second edge table

    cmp  cx,bx
    jle  ordered
    xchg cx,bx
ordered:
    cmp  bx,0
    jl   next_line      ; fully left of screen
    cmp  cx,319
    jg   next_line      ; fully right of screen
    cmp  cx,0
    jge  left_ok
    xor  cx,cx
left_ok:
    cmp  bx,319
    jle  right_ok
    mov  bx,319
right_ok:
    sub  bx,cx
    inc  bx             ; BX = pixel count

Address and plane setup:

    mov  di,cx
    shr  di,2           ; byte column = x / 4
    add  di,bp          ; add row base
    and  cx,3           ; starting plane = x & 3
    je   middle

If the span does not begin on plane 0, a leading partial byte is needed. For example, starting at plane 2 means only planes 2 and 3 of the first byte should change. The map-mask byte is built from 0x0f << starting_plane:

leading_partial:
    add  bx,cx
    sub  bx,4
    js   one_byte_span

    mov  al,0fh
    shl  al,cl
    out  dx,al          ; enable planes from start plane through plane 3
    mov  al,ah
    stosb               ; one byte address, selected planes only

Then come the full bytes. These represent groups of four pixels, so all four planes are enabled and rep stosb is enough:

middle:
    mov  al,0fh
    out  dx,al          ; all planes enabled
    mov  al,ah
    mov  cx,bx
    and  bx,3           ; BX = tail pixels after full bytes
    shr  cx,2           ; CX = number of full byte columns
    rep  stosb

The trailing partial byte is the mirror image of the leading partial. If one, two, or three pixels remain, it shifts 0x0f right to keep only the low planes:

tail:
    mov  cx,4
    sub  cx,bx
    mov  al,0fh
    shr  al,cl          ; mask for low tail planes
    je   next_line
    out  dx,al
    mov  al,ah
    mov  es:[di],al

Finally it advances to the next scanline:

next_line:
    add  bp,0050h       ; 80 bytes per 320-pixel planar row
    add  si,2
    pop  cx
    loop span_line

What this loop is doing, in plain terms:

  1. A filled polygon or ball silhouette has already generated left and right X edges for each scanline.
  2. The span writer clips each horizontal line to 0..319.
  3. Because unchained VGA stores pixels by plane, it cannot simply write a byte per pixel.
  4. It writes a first partial byte if the span starts mid-byte.
  5. It writes as many full four-pixel byte columns as possible.
  6. It writes a final partial byte if the span ends mid-byte.

This is a classic VGA performance compromise. The CPU avoids per-pixel branches inside the middle of the span. The expensive out dx,al map-mask changes only happen at the edges and at the transition to the full middle run.

There is a related unclipped path around MOD06+0x2a324. It has the same planar-mask idea but assumes the caller already produced safe X ranges.

Page Flipping and Clears

The vector-ball code flips between two 64 KB-ish page windows by changing both the CRTC start address and the segment it uses for drawing. The state byte at [510c] selects which page is visible/drawn:

MOD06+0x2a443:
    cmp  byte ptr [510ch],0
    jne  page_b

page_a:
    mov  word ptr [5102h],0a000h
    mov  dx,3d4h
    mov  ax,000dh
    out  dx,ax
    mov  ax,400ch
    out  dx,ax
    mov  byte ptr [510ch],1
    ret

page_b:
    mov  word ptr [5102h],0a400h
    mov  dx,3d4h
    mov  ax,000dh
    out  dx,ax
    mov  ax,000ch
    out  dx,ax
    mov  byte ptr [510ch],0
    ret

The clear routine writes both pages with all four planes enabled:

MOD06+0x2a4af:
    mov  dx,3c4h
    mov  ax,0f02h
    out  dx,ax

    mov  es,0a000h
    xor  di,di
    xor  ax,ax
    mov  cx,1f40h
    rep  stosw

    mov  es,0a400h
    xor  di,di
    xor  ax,ax
    mov  cx,1f40h
    rep  stosw

1f40h words is 16,000 bytes. With all four planes enabled, that covers 64,000 pixels, i.e. a 320x200 display. Again, the code is exploiting planar VGA instead of treating A000h as a simple chunky framebuffer.

The full mode initializer first sets BIOS mode 13h, then reprograms the VGA into the unchained layout the span code expects:

MOD06+0x2a4e5:
    call black_palette
    mov  ax,0013h
    int  10h
    mov  dx,3c4h
    mov  ax,0604h
    out  dx,ax
    mov  dx,3d4h
    mov  ax,0014h
    out  dx,ax
    mov  ax,0e317h
    out  dx,ax
    mov  dx,3c2h
    mov  al,83h
    out  dx,al
    mov  dx,3c4h
    mov  ax,0f02h
    out  dx,ax
    mov  es,0a000h
    xor  di,di
    xor  ax,ax
    mov  cx,8000h
    rep  stosw

The apparent mismatch between "Mode 13h" and the planar span code is resolved by those sequencer/CRTC writes. BIOS mode 13h provides a known VGA baseline; the demo then turns it into the tweaked planar mode it actually uses.

Palette Fades

MOD06 does not just upload a fixed palette. It has small integer fade loops that scale or bias 256 RGB triples before writing them to the VGA DAC.

The fade-in loop uses [3e6c] as a factor, increments it by 3, and writes the high byte of each 8x8 multiply as the scaled VGA component:

MOD06+0x2a553:
    mov  bl,[3e6ch]
    add  byte ptr [3e6ch],3
    mov  es,2adch       ; palette table segment
    mov  si,000ah
    mov  dx,3c8h
    xor  al,al
    out  dx,al
    inc  dx             ; 3c9h
    mov  cx,0100h

fade_entry:
    mov  al,es:[si+0]
    mul  bl
    mov  al,ah
    out  dx,al
    mov  al,es:[si+1]
    mul  bl
    mov  al,ah
    out  dx,al
    mov  al,es:[si+2]
    mul  bl
    mov  al,ah
    out  dx,al
    add  si,3
    loop fade_entry

The fade-to-white path starts with a small factor and moves each component toward 0x3f, the VGA DAC maximum:

    mov  al,3fh
    sub  al,es:[si+n]   ; distance from current component to white
    mul  bl
    add  al,es:[si+n]   ; current + scaled distance
    out  3c9h,al

This is cheap and visually useful. It avoids divisions, uses only 8-bit multiplies, and lets the script fade the whole vector-ball palette in, through white, or down without recomputing palette tables offline.

MOD03 Color and Rectangle Loops

MOD03 appears to be one of the color/visual modules. Two inner loops are especially clear.

The first copies a 120-line rectangle into A000h. One path uses per-line source offset tables, so the image can be warped or scrolled by varying source and destination offsets per scanline:

MOD03+0x13d1:
    ; for y = 0..119
    ; DS = source segment [555e]
    ; ES = A000h
    mov  si,table_value
    add  si,005ah
    mov  di,311ah
    add  di,x_or_phase_offset
    add  di,row_offset
    mov  cx,0046h
    rep  movsw          ; 70 words = 140 bytes

The alternate path is a fixed rectangle copy:

    mov  es,0a000h
    mov  di,311ah
    add  di,phase_offset
    mov  si,005ah
    mov  dl,78h         ; 120 lines

row:
    mov  cx,0046h       ; 140 bytes
    rep  movsw
    add  di,00b4h       ; 320 - 140 bytes to next destination line
    dec  dl
    jne  row

The second clear/fill loop at MOD03+0x2a50 is a planar-gradient or box-fill path. It enables all planes, chooses an A000h address, then writes rows while changing the fill byte:

MOD03+0x2a50:
    mov  dx,3c4h
    mov  ax,0f02h
    out  dx,ax          ; all planes enabled
    mov  es,0a000h
    mov  di,[6956h]
    add  di,0059h
    mov  ah,0bfh
    mov  al,0bfh
    mov  dl,3eh

upper:
    dec  ah
    dec  al
    push di
    mov  cx,001fh
    rep  stosw          ; 62 bytes, four planes at a time
    pop  di
    add  di,0050h       ; next planar scanline
    dec  dl
    jne  upper

Because all four VGA planes are selected, each byte/word store affects multiple pixels in the planar image. The loop is short, branch-light, and exactly shaped for a rectangular band: write a run, step by 80 bytes, repeat.

Barti PBM/LBM Picture Helpers

MOD01, MOD04, MOD07, and MOD08 share Barti picture/unpacking code. They contain strings such as:

BARTI! DEPAC-LBM BARTI! V92.235
FORM
PBM
BMHD
CMAP
BODY
TINY
CRNG

The code is an IFF/PBM/LBM-style image loader and display helper. It parses chunks, uploads palettes, sets the VGA mode, clears display memory, and waits for vblank.

The palette upload in MOD01 is the straight DAC path:

MOD01+0x130c3:
    push ds
    mov  si,[bp+6]
    mov  ds,[bp+8]
    mov  dx,3c8h
    mov  cx,0300h       ; 256 * 3 RGB bytes
    xor  al,al
    out  dx,al          ; DAC index 0
    inc  dx             ; DAC data
    rep  outsb
    pop  ds
    retf 4

The mode tweak is the same broad family as the vector-ball code:

MOD01+0x13159:
    mov  dx,3c4h
    mov  ax,0604h
    out  dx,ax
    mov  dx,3d4h
    mov  ax,0014h
    out  dx,ax
    mov  ax,0e317h
    out  dx,ax

The clear loop:

MOD01+0x1316f:
    mov  es,0a000h
    mov  cx,7d00h
    xor  di,di
    xor  ax,ax
    rep  stosw

And the simple vblank wait:

MOD01+0x1317f:
    mov  dx,3dah
wait_on:
    in   al,dx
    and  al,8
    je   wait_on
wait_off:
    in   al,dx
    and  al,8
    jne  wait_off
    retf

There are also Pascal-style string and memory helpers in MOD01. A length-prefixed string copy is literally:

    lodsb               ; AL = length
    stosb               ; store length
    mov  cl,al
    rep  movsb          ; copy payload

The overlap-safe memory move at MOD01+0x14813 chooses backward copying when the destination is inside the source range:

    cmp  si,di
    jae  forward
    add  si,cx
    add  di,cx
    dec  si
    dec  di
    std
    rep  movsb
    cld
    ret
forward:
    rep  movsb

That kind of support code is boring only until you remember that this demo is loading and animating many packed image chunks in a 16-bit environment. Robust chunk parsing and overlap-safe moves matter.

What the Parts Add Up To

Cardiac is structured like a small demo operating system:

  1. The released MZ starts as a compact LZEXE-packed loader.
  2. The unpacked outer program handles configuration, command-line part selection, looping, and hidden mode dispatch.
  3. The overlay contains multiple packed MZ modules rather than one flat asset blob.
  4. The memory system uses XMS and flat-real/protected-mode setup to escape the normal conventional-memory ceiling.
  5. Picture parts use Barti's PBM/LBM depacker and familiar VGA palette/mode helpers.
  6. Kroc's 3D part uses a fixed active-object table, distance culling, sorted draw lists, and a real planar Mode X span filler.
  7. The raster and palette code uses both vertical-retrace waits and the finer display-enable bit, depending on the effect.

The planar span filler is the most "classic inner loop" recovered here. It is not abstract polygon code; it is hand-shaped for 320-pixel VGA: convert X to x >> 2, choose planes with x & 3, do at most two partial-byte map-mask writes, and blast the middle with rep stosb. That is the exact kind of code that made early PC demos feel closer to hardware programming than to a graphics library.

Remaining Unknowns

The main uncertainties are in orchestration and data naming:

Those gaps do not change the main technical picture: Cardiac is a multi-module 386 VGA demo with a serious loader, high-memory runtime, image/animation subsystems, and a hand-written planar 3D rasterizer.