Difference between revisions of "MELT.COM"
From SizeCoding
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 02: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