As far as I’m able to repeat, something be pleased here is going on:
This complete things assumes positive mounted values of registers upon program entry. Targetting MS-DOS, here is rather cheap. The registers we want to verbalize ourselves with are:
AX = 0 CX = 0xff SI = 0x100 DI = 0xfffe BP = 0x091c DS = CS = ES
BP is a itsy-bitsy bit extra variable than the others, nonetheless now not by noteworthy.
adc al, 0x13 mov dx, 0x330 get outsb
OUTSB will output the worth of whatever is at reputation
DS: [SI] to the port whose number is in
DX and then increment
REP prefix will enact this
CX cases, decrementing
CX at any time when.
SI begins off pointing before all the pieces attach apart of our code, which formula that 255 bytes of stuff is readily shoved into port 0x330, beginning with the 64 byte binary itself. Port 0x330 is a MIDI port for Sound Blaster 16, nonetheless I’m roughly uncertain as to why it accepts this barrage of knowledge, or how it turns into the song/helicopter smatter. Both formula, here is the solely reputation within the code that offers with sound, so that is the “song” fragment handled.
clrscr: int 0x10 mov ax, 0xc4f out 0x40, al loop clrscr
AL to 0x13 above, the determination to interrupt 0x10 gadgets the correct conceal mode in the beginning of the first iteration of the loop. Surroundings
AX to 0x0c4f is for the next iterations, and might maybe maybe maybe make the next interrupt 0x10 utilize feature 0x0c to intention a pixel of color
AL to coordinates (
DX). One might maybe maybe maybe additionally purchase that since
DX by no formula changes, this is able to solely intention pixels on one row of the conceal. My guess is that the BIOS routine proper variety writes to address
DX * hres + CX, without be pleased overflow.
You might maybe maybe per chance maybe additionally surprise how this loop will loop the least bit, what with
CX being zero from the old section. The secret’s that the
CX and then assessments whether it’s far 0. The first decrement will thus spot off an underflow to 0xffff, making the loop stagger round 65 536 cases. This would per chance maybe additionally definite the conceal.
What’s extra, we additionally output
AL (0x4f) to port 0x40. That is a port for setting the timer divisor for the Programmable Interval Timer chip. To identify that impress, you send first the low and excessive bytes of a 16-bit impress to the port. Since we are spamming that port with the identical impress, the divisor shall be spot to 0x4f4f (20 303). The timer in demand makes utilize of this impress to study how in overall this might maybe occasionally per chance fireplace an interrupt 0x8, thru the ravishing formula 1 193 182 / 20 303 ~= 58.77 Hz (in overall 18.2 Hz). Interrupt 0x8, in turn, increments a counter at address
0040: 006c, thereby retaining a tally on how many such ticks devour occured since heart of the evening (?).
This would per chance maybe additionally be crucial for the animation.
Upon entry to a .COM file, a single zero note is pushed to stack, which formula this might maybe occasionally per chance spot
DS to 0.
push note 0xa500 pop es
Video memory for mode 0x13 begins at memory address
a000: 0000. Thru the magic joy of segmented memory, setting
ES to a impress 0x500 (1 280) bigger formula that we are 1 280 * 16 bytes additional along into video memory. Mode 0x13 has a determination of 320×200 so that formula
ES will demonstrate the first pixel on row 64. As good a reputation as any for a horizon.
mainloop: mov ax, 0xcccd mul di ; DX:AX = AX * DI = 0xcccd * DI
Any 16-bit multiplication on an x86 will effect a 32-bit result, which is saved in
DX:AX (excessive note in
DX, low note in
AX). This particular multiplication will automagically set apart the Y coordinate (relative to the horizon) in
DH and the X (rescaled to a host 0..255) coordinate in
mov ax, bp sub dh, 0xf6 div dh
BP begins with 0x091c (in DOSBox now not lower than, and shut ample on many versions of DOS), which makes the above equivalent to:
AX = 2 332 / (y + 10)
AX will now grasp some fashion of scale, having lower values the additional in the direction of the backside of the conceal we are.
xchg ax, dx ; swap (coordinates, scale) sub al, 0x7f ; Centers x coordinate round 0 imul dl ; Multiply coordinates by scale
DX (or scale and coordinates). Subtracting 0x7f from the X coordinate to make it centered round zero, then multiply with the scale. To be proper variety, I’m a itsy-bitsy hazy as to how the complete scaling enterprise works, nonetheless scales it does.
add dl, [0x46c] xor dh, al imul dh
Here is the meat of it all. First, we add the tick counter that our reprogrammed PIT produces 58.77 per second to the scale. Why? Be awake that the scale will get smaller the additional down on the conceal we are. Adding to this impress formula we are pretending to be a itsy-bitsy bit above the attach apart we indubitably are.
XOR? Not 100% definite, nonetheless devour a feeling it helps to effect the checkerboard sample.
Taking a glimpse forward, we spy:
; AH = AL / 9 (discarded) ; AL = AL % 9 aam 0x9 pushfw popfw sub al, 0x74 stosb ; [DI++] = AL
STOSB writes a pixel with a color of
AL, which became once constrained to a palette of 9 colors by
AAM 0x9 nonetheless which within the slay got here from our calculations above. For the reason that color of the present pixel depends on the scale, which depends on the attach apart we are on the conceal, that formula we acquire a checkerboard sample. However the scale is a itsy-bitsy bit altered by the tick counter, or to attach apart it another formula, by time passing. Adding to the scale is which capacity truth the identical as going a itsy-bitsy bit into the past. This form that if some small interval of time has handed, we are drawing the brand new pixel with a color that, adding the tick counter, comes from a itsy-bitsy bit above it within the checkerboard. This creates the form of colors flowing downwards (in the direction of us).
The percentual difference between scale and time-adjusted scale will enhance with Y, since the lower the scale, the bigger impression any preference of ticks will devour. This stretches things top-wise, producing point of view.
Ticks are noteworthy extra likely to occur right thru a conceal refresh, making that line and any subsequent one of that physique a itsy-bitsy wonky, nonetheless with a refresh rate of terminate to 60 fps, we’re now not going to ogle it.
scasw jmp mainloop
SCASW does literally nothing nonetheless approach
DI by 2. No opinion why. Some interleaving intention?
leave cmp [bx + di + 0x6746], bl push cx db 0x7f
This looks be pleased padding. Is by no formula executed. Is shovelled to the MIDI port, so per chance essential there?
There are things I’m uncertain of, comparable to the explicit nature of the sample producing, and the seemingly useless
PUSHFW / POPFW pair within the important thing loop (those might maybe maybe maybe additionally be for timing purposes… maaaybe). I even devour absolute confidence additionally devour misunderstood some parts of the code, nonetheless I feel here is the basic gist of it, now not lower than.
We hate SPAM and promise to keep your email address safe