¡Che, pibe! Sentate a la mesa que hoy no vamos a hablar de la tablita del 8, ni de la selección de fútbol. Hoy vamos a desentrañar un misterio más denso que un mate cocido sin azúcar: el código máquina hecho por rosarigasinos en los noventa. Sí, señores, ese artefacto digital que, en lugar de una buena charla de café, te exigía un Intel 80286 y una placa VGA como si fueran una entrada a un show exclusivo de Les Luthiers. El código que nos ocupa no es un programa, sino una "demo". ¿Y qué es una demo? Mirá, si un programa es un delivery de pizza, la demo es la caja vacía de cartón que queda después: puro estilo, puro rinde, y con el olor a hazaña todavía flotando en el aire. La hizo la gente de TLH Group (The Last Hackers), con los capos de Maxi K, Marcelo V y Diego A. Estos muchachos de Rosario, en lugar de tomar el bondi a la playa, se pusieron a domar el silicio. Paréntesis Histórico: The Last Hackers no eran unos improvisados. Fue un grupo dedicado por años a la programación de intros y demos para la incipiente escena local. Su hito más grande, y digno de placa, es haber realizado la primer y única demo hecha en nuestro país en 1994. Es decir, antes de que existiera el Wi-Fi, estos pibes ya estaban empujando los límites del hardware con arte digital. Este engendro informático está escrito en lenguaje ensamblador (Assembly), usando el mítico TASM 2.0. El Ensamblador es la lengua madre de la computadora, el dialecto crudo y brutal con el que le decís al microprocesador: "Che, hacé esto, pero YA". Olvidate de que la máquina te interprete. Acá, si movés un bit mal, la PC te devuelve un error más seco que bizcocho viejo. El programa se carga como un archivo COM (ORG 100h). Esto significa que vive y muere en un solo segmento de memoria, como si fuera un hippie acampando en la RAM. El Corazón 80286: La directiva .286 ya te avisa que estos muchachos no tenían paciencia para esperar el 386. Iban a lo seguro, a las instrucciones que te permiten mover datos más rápido que un carterista en el centro. Modo VGA (La Lucha de Clases): Al principio, el programa te saluda con un mensaje de Max of The Last Hackers y luego, sin anestesia, chequea si tenés VGA. Si no la tenés, te tira un mensaje de error más dramático que una telenovela venezolana: Hardware Error #280819930825 Proc: _vgaprint. Es la dictadura del modo gráfico $13h$: 320 píxeles de ancho por 200 de alto, con 256 colores. ¡Una explosión visual que dejaba tu monitor más excitado que perro con dos colas! Aquí es donde la demo se convierte en arte, o al menos en una performance de alto rendimiento digital. Todo sucede dentro del bucle central llamado print_sinus_wave, una verdadera orquesta de instrucciones.  Los muchachos dibujan una onda senoidal con un color en el centro de la pantalla. ¿Cómo? Moviendo el índice de la tabla de senos (sinus_offset) de a dos pasos por frame. Es decir, a la máquina, en lugar de contarle un chiste, le dan un valor precalculado (sinus_line[bx]) y ella obedece, dibujando la curva. Y para que no quede como un garabato de chico de jardín de infantes, aprovechan para dejar un rastro de 12 píxeles de espesor. El famoso scrolling text de las demos, la nota al pie digital de la historia. Carga y Empuje: El código copia caracteres (rept 6 / movsw) desde la tabla de fuentes (font_now) a un buffer temporal (buffer_area). Desplazamiento a Torta Frita: Cada 12 frames se reinicia el contador (scroll_counter). Con la bandera de dirección en STD (Set Direction Flag), se invierte el sentido de los MOVSW (mover palabra), y se desplaza el búfer de texto hacia la izquierda, como si estuviera apurado por llegar al kiosko. Cuando se acaba la frase, ¡El texto empieza de nuevo! Un infinito de bits rosarinos. El efecto más hipnótico. En lugar de cambiar los gráficos, cambian los colores. El código toma la paleta de 256 colores (que en realidad son 256 entradas de 3 bytes RGB) y las rota. Es decir, el color Naranja pasa a ser Amarillo, el Amarillo pasa a ser Rojo, y así en un baile sin fin. El chiste es que esto se hace escribiendo directamente a los Puertos I/O del chip VGA (03c8h y 03c9h). Es como meterle mano al motor del Fiat 600 mientras vas a 80 km/h: pura adrenalina técnica. Para que todo fluya sin un solo glitch que arruine la performance, los Rosarigasinos esperan al Retraso Vertical (VBLANK). Esto es sincronizar el dibujo con la frecuencia de refresco del monitor, para que la pantalla no "se rompa" con líneas extrañas. Luego, el bucle stars_loop procesa 64 estrellas. Cada una tiene su posición y su velocidad (stars_data). El programa: Borra la estrella de la posición vieja (mov es:bx, byte ptr 0). Calcula la nueva posición y la mueve. Le asigna un color (add al, 0Ah) y la dibuja. Es un efecto de profundidad, donde las estrellas se mueven hacia el usuario, generando la ilusión de que tu PC con 1 MB de RAM es, en realidad, una nave espacial despegando desde La Florida. En resumen, aquel código de TLH Group no era solo un montón de bytes. Era la destilación de la creatividad argentina de los 90, la prueba viviente de que se podía hacer arte sin presupuesto, solo con conocimiento de Ensamblador y mucho aguante. Un verdadero homenaje a la eficiencia, donde cada registro (AX, BX, CX, DX) actuaba como un personaje en una obra de teatro absurda, pero perfectamente coreografiada. Y todo eso solo para mostrar una onda y unas estrellitas en pantalla. En su momento, aquello era una locura total. Si eso no era amor al código, entonces yo era el Indio Solari. ;Usar tasm 2.0!!! .286 assume cs:cseg,ds:cseg cseg segment org 100h mp proc near                                 cli                                 jmp startup_sequence                                 include font.inc                                 include wave.inc                                 include pal.inc                                 include ascii.inc                                 include stars.inc                                 include tlh.inc                                 include msg.inc print_tlh:                      mov si,offset tlh_graphic                                 mov di,5164                                 mov cx,114 print_scans:                    push cx                                 push di                                 mov cx,232/2                                 rep movsw                                 pop di                                 pop cx                                 add di,320                                 loop print_scans                                 ret buffer_area                     db 0ea4h dup (?) sinus_offset                    dw ? scroll_counter                  dw 00c0h text_offset                     dw offset message buffer_now                      dw offset buffer_area font_now                        dw offset font_area print_sinus_wave:               ;cli ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=                                ;PRINT SINUS WAVE ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=                                 mov si,offset buffer_area+0c0h                                 add si,scroll_counter                                 mov cx,280                                 xor al,al print_loop:                     mov bx,cx                                 add bx,sinus_offset                                 shl bx,1                                 mov di,sinus_line[bx]                                 add di,cx                                 add di,20                                 stosb                                 sub di,321                                 stosb                                 sub di,321                                 rept 12                                 movsb                                 sub di,321                                 endm                                 loop print_loop                                 add sinus_offset,2                                 cmp sinus_offset,180                                 jb scrolling_text                                 mov sinus_offset,0 ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=                                 ;SCROLLING TEXT ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= scrolling_text:                 mov ax,cs                                 mov es,ax                                 mov si,font_now                                 mov di,buffer_now                                 rept 6                                 movsw                                 endm                                 mov font_now,si                                 mov buffer_now,di                                 sub scroll_counter,00ch                                 jnz pallete_cycling                                 mov scroll_counter,0c0h                                 mov si,text_offset                                 inc text_offset                                 mov bl,[si]                                 or bl,bl                                 jnz no_text_end                                 mov bl,020h                                 mov text_offset,offset message no_text_end:                    sub bl,020h                                 xor bh,bh                                 shl bx,1                                 mov si,ascii[bx]                                 mov buffer_now,offset buffer_area                                 mov font_now,si                                 std                                 mov si,offset buffer_area+0de0h                                 mov di,offset buffer_area+0ea0h                                 mov cx,150 scrolling:                                 rept 00ch                                 movsw                                 endm                                 loop scrolling                                 cld ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=                                 ;PALLETE CY;;cliNG ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= pallete_cycling:                mov al,00h                                 inc byte ptr pallete_cycling+1                                 and al,01h                                 jnz skip_pallete                                 mov si,offset pallete+33h                                 mov di,offset pallete+30h                                 mov cx,[di]                                 mov dh,[di+2]                                 rept 16h                                 movsw                                 endm                                 movsb                                 mov [di],cx                                 mov [di+2],dh                                 mov si,offset pallete+30h                                 mov cx,010h                                 mov dx,03c8h                                 mov al,010h                                 out dx,al                                 inc dx send_rgb_to_vga:                mov al,[si]                                 out dx,al                                 mov al,[si+1]                                 out dx,al                                 mov al,[si+2]                                 out dx,al                                 add si,3                                 loop send_rgb_to_vga skip_pallete:                   mov ax,0a000h                                 mov es,ax ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=                                      ;STARS ;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=                                 mov dx,03dah                                 in al,dx                                 test al,08h                                 jz retrace_wait_on retrace_wait_off:               in al,dx                                 test al,08h                                 jnz retrace_wait_off retrace_wait_on:                in al,dx                                 test al,08h                                 jz retrace_wait_on stars_scroll:                   mov cx,040h                                 mov si,offset stars_data                                 xor ah,ah stars_loop:                     mov bx,[si]                                 add bx,[si+2]                                 mov dl,es:bx                                 cmp dl,0ah                                 jb  there_is_something                                 mov es:bx,byte ptr 0 there_is_something:             mov al,cl                                 and al,03h                                 inc al                                 sub [si+02],ax                                 sub bx,ax                                 add al,0Ah                                 mov dl,es:bx                                 or dl,dl                                 jz go_on                                 cmp dl,0ah                                 jb  something_ii go_on:                          mov es:bx,al something_ii:                   add si,4                                 loop stars_loop skip_stars:                     xor ax,ax                                 in al,060h                                 and al,03h                                 jnz go_out no_alt_x:                       jmp print_sinus_wave                                 sti go_out:                         ret startup_sequence:               cli                                 mov dx,offset guru_chief                                 mov ah,09h                                 int 21h                                 mov bx,05h pause_2:                        mov cx,0h pause_1:                        loop pause_1                                 dec bx                                 jnz pause_2                                 call detect_vga                                 jne no_hercules                                 mov dx,offset guru                                 mov ah,09h                                 int 21h                                 jmp skip_demonstration no_hercules:                    mov al,0ffh                                 out 21h,al                                 mov ax,0013h                                 int 10h                                 mov ax,01012h                                 xor bx,bx                                 mov cx,32                                 mov dx,offset pallete                                 int 10h                                 mov ax,0a000h                                 mov es,ax                                 call print_tlh                                 call print_sinus_wave                                 mov ax,0003h                                 int 10h skip_demonstration:             xor al,al                                 out 21h,al                                 sti                                 int 20h detect_vga:                     mov ax,0f00h                                 int 10h                                 xor ah,ah                                 push ax                                 mov ax,00013h                                 int 10h                                 push es                                 mov ax,0a000h                                 mov es,ax                                 mov es:[0],byte ptr 0f8h                                 cmp es:[0],byte ptr 0f8h                                 mov dx,0ffffh                                 jz its_vga                                 mov dx,00000h its_vga:                        mov es:[0],byte ptr 000h                                 pop es                                 pop ax                                 int 010h                                 or dx,dx                                 ret guru_chief                      db 0dh,0ah,'The Last Hackers Demo, Done by Max of The Last Hackers Group. ADN 52:801/200',0dh,0ah,'$' guru                            db 0dh,0ah                                 db 'Hardware Error #280819930825 Proc: _vgaprint ',0dh,0ah,0dh,0ah                                 db 'Error Description: Cant write memory at address: A000:0000',0dh,0ah,'$' mp endp cseg ends end mp
DMA Informática en la Galería Vía Florida  La Anatomía del Milagro de 320x200
2. Los Efectos Visuales: La Mística Rosarina del Demoscene
b) El Texto Desplazable (La Mensajería del Caos)
c) La Ciclotimia de la Paleta (pallete_cycling)
3. Conclusión: El Código Rosarino
“Cuando los bytes bailaban cumbia: Anatomía de una demo de los 90 de T.L.H.”
Publicado por
LU6FPJ
 | 
            	
Etiquetas:
TLH
Read User's Comments0
Publicado por
LU6FPJ
Suscribirse a:
Comentarios (Atom)

 




