Difference between revisions of "MELT.COM"

From SizeCoding
Jump to: navigation, search
Line 43: Line 43:
 
                 int    21h            ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT)
 
                 int    21h            ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT)
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
There are some very quick wins right off the bat:
 +
 +
* AX is already 0, so set AX=B800 by setting AH=B8
 +
* Replace DOS exit sequence with RET, since this is a .COM file
 +
 +
This shaves 4 bytes down to 45 total:
 +
 +
<syntaxhighlight lang=nasm>
 +
                org 100h
 +
 +
                mov    ah, 0B8h
 +
                mov    es, ax          ; es now points to screen segment
 +
 +
doScreen:                             
 +
                mov    cx, 2000        ; Going to loop over all 2000 characters
 +
                                        ; (80 * 25 = 2000)
 +
                xor    bx, bx          ; bx = 0
 +
                                        ; bx is also our "num of altered chars" counter
 +
                mov    di, bx          ; es:di now points at the screen (b800:0000)
 +
 +
alterChars:                           
 +
                mov    ah, es:[di]    ; Retreive onscreen character
 +
                cmp    ah, 32          ; comp to a space character (#32)
 +
                jz      short nextChar  ; If already a space, do nothing
 +
                jl      short upToSpace ; If lower than a space, increase upward
 +
                dec    ah              ; If higher than a space, decrease downward
 +
                mov    es:[di], ah    ; Store altered character back to screen
 +
                inc    bx              ; increase "number of processed chars" counter
 +
                jmp    short nextChar  ; Keep processing characters
 +
; ---------------------------------------------------------------------------
 +
 +
upToSpace:                             
 +
                inc    ah              ; Increase character upwards towards a space
 +
                mov    es:[di], ah    ; Store altered character back to screen
 +
                inc    bx              ; increase "number of processed chars" counter
 +
 +
nextChar:                             
 +
                inc    di
 +
                inc    di              ; es:di now points to next character
 +
                loop    alterChars      ; Continue processing characters
 +
                cmp    bx, 0          ; Were any characters processed?
 +
                jnz    short doScreen  ; If so (bx != 0), keep processing
 +
                ret                    ; exit
 +
</syntaxhighlight>
 +
 +
At this point we can make some drastic choices that will shave bytes, but also make the program not behave ''exactly'' as it did before.  I chose to do the following:
 +
 +
2000 is 7D0 in hex.  Change MOV CX,2000 (decimal) to MOV CH,08 (hex) to shave a byte.  This could result in CX being anywhere in the range 0800 to 08FF but the difference is minimal at execution time.  It's also larger than the original area, but that is fine since there is

Revision as of 03:26, 7 August 2016

MELT.COM was written by an unknown author in the 1980s. Originally 49 bytes in size, it performs the following cute effect:

The original source is lost to history, but here's a quick commented disassembly:

                org 100h

                mov     ax, 0B800h
                mov     es, ax          ; es now points to screen segment

doScreen:                               
                mov     cx, 2000        ; Going to loop over all 2000 characters
                                        ; (80 * 25 = 2000)
                xor     bx, bx          ; bx = 0
                                        ; bx is also our "num of altered chars" counter
                mov     di, bx          ; es:di now points at the screen (b800:0000)

alterChars:                             
                mov     ah, es:[di]     ; Retreive onscreen character
                cmp     ah, 32          ; comp to a space character (#32)
                jz      short nextChar  ; If already a space, do nothing
                jl      short upToSpace ; If lower than a space, increase upward
                dec     ah              ; If higher than a space, decrease downward
                mov     es:[di], ah     ; Store altered character back to screen
                inc     bx              ; increase "number of processed chars" counter
                jmp     short nextChar  ; Keep processing characters
; ---------------------------------------------------------------------------

upToSpace:                              
                inc     ah              ; Increase character upwards towards a space
                mov     es:[di], ah     ; Store altered character back to screen
                inc     bx              ; increase "number of processed chars" counter

nextChar:                               
                inc     di
                inc     di              ; es:di now points to next character
                loop    alterChars      ; Continue processing characters
                cmp     bx, 0           ; Were any characters processed?
                jnz     short doScreen  ; If so (bx != 0), keep processing
                mov     ah, 4Ch         ; Otherwise, get ready to terminate
                int     21h             ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT)

There are some very quick wins right off the bat:

  • AX is already 0, so set AX=B800 by setting AH=B8
  • Replace DOS exit sequence with RET, since this is a .COM file

This shaves 4 bytes down to 45 total:

                org 100h

                mov     ah, 0B8h
                mov     es, ax          ; es now points to screen segment

doScreen:                               
                mov     cx, 2000        ; Going to loop over all 2000 characters
                                        ; (80 * 25 = 2000)
                xor     bx, bx          ; bx = 0
                                        ; bx is also our "num of altered chars" counter
                mov     di, bx          ; es:di now points at the screen (b800:0000)

alterChars:                             
                mov     ah, es:[di]     ; Retreive onscreen character
                cmp     ah, 32          ; comp to a space character (#32)
                jz      short nextChar  ; If already a space, do nothing
                jl      short upToSpace ; If lower than a space, increase upward
                dec     ah              ; If higher than a space, decrease downward
                mov     es:[di], ah     ; Store altered character back to screen
                inc     bx              ; increase "number of processed chars" counter
                jmp     short nextChar  ; Keep processing characters
; ---------------------------------------------------------------------------

upToSpace:                              
                inc     ah              ; Increase character upwards towards a space
                mov     es:[di], ah     ; Store altered character back to screen
                inc     bx              ; increase "number of processed chars" counter

nextChar:                               
                inc     di
                inc     di              ; es:di now points to next character
                loop    alterChars      ; Continue processing characters
                cmp     bx, 0           ; Were any characters processed?
                jnz     short doScreen  ; If so (bx != 0), keep processing
                ret                     ; exit

At this point we can make some drastic choices that will shave bytes, but also make the program not behave exactly as it did before. I chose to do the following:

2000 is 7D0 in hex. Change MOV CX,2000 (decimal) to MOV CH,08 (hex) to shave a byte. This could result in CX being anywhere in the range 0800 to 08FF but the difference is minimal at execution time. It's also larger than the original area, but that is fine since there is