Skip to main content
Commonmark migration
Source Link

#80386 machine code + DOS, 75 68 bytes

80386 machine code + DOS, 75 68 bytes

#80386 machine code + DOS, 75 68 bytes

80386 machine code + DOS, 75 68 bytes

cleanup based on comment feedback
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57

#80386 machine code + DOS, 75 69 68 bytes

NOTE: This is a reply to @anatolyg's really clever 2015 answer, with a few tweaks to reduce the score by 7 bytes. I'm only submitting this as a separate non-competing answer because it wouldn't be possible to explain fully in a comment.

Unassembled:

Per @Peter Cordes's request, instruction opcodes included in listing:

#80386 machine code + DOS, 75 69 68 bytes

NOTE: This is a reply to @anatolyg's really clever 2015 answer, with a few tweaks to reduce the score by 7 bytes. I'm only submitting this as a separate non-competing answer because it wouldn't be possible to explain fully in a comment.

Unassembled:

Per @Peter Cordes's request, instruction opcodes included in listing:

#80386 machine code + DOS, 75 68 bytes

NOTE: This is a reply to @anatolyg's really clever 2015 answer, with a few tweaks to reduce the score by 7 bytes. I'm only submitting this as a separate answer because it wouldn't be possible to explain fully in a comment.

Unassembled:

added 115 characters in body
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
  • Use SI to reset the BX pointer to 100H, since DOS sets SI initially to 100H (ref). Use that to reset BX instead of an imm. (-1 byte)
  • Instead of using a 3/5 counter in DXDH/DL, use AAM for modulo operations on counter. IMHO,   AAM is a really underrated2 byte instruction since it'sthat's effectively a byte-length DIV using only 2 bytes that can accept an imm value as the divisor and also sets ZF if AL mod n = 0. @Peter Cordes touches on this in his very brilliant post about FizzBuzz in assembly. (-5 bytes)
  • Instead of CR/LF, use LF/CR (the order doesn't matter to DOS). This translates to an instruction that does not modify the defaultstartup value of AX, thus (in fact it zeroes out AL) so we can eliminate the xor ax,ax and save two bytes. It does come at a cost because 0A 0D is only a two-byte instruction so the rest of the 24xx instruction needs to be padded with one more byte. (-1 bytesbyte)
0A 0D           or cl, [di]             ; LF and CR bytes (newline)
24 00           and al, 0               ; DOS string delim ('$') + pad byte
B1 64           mov cl, 100             ; set loop counter set to 100 
                 
            main_loop: 
8B DE           mov bx, si              ; init bx to 100h 
40              inc ax                  ; increment fizzfizzbuzz counter 
50              push ax                 ; save fizzfizzbuzz counter
                                     
50              push ax                 ; save ax from getting clobbered by AAM 
D4 05           aam 5                   ; AL = AL mod 5, ZF if AL = 0
58              pop ax                  ; restore ax 
75 0A           jnz short buzz_done     ; jump if not a 'Fizz'
83 EB 04        sub bx, 4               ; offset for output string 
66C707 7A7A7542 mov dword ptr [bx], 'zzuB' 
            buzz_done: 
                 
50              push ax 
D4 03           aam 3                   ; AL = AL mod 3, ZF if AL = 0
58              pop ax 
75 0A           jnz short fizz_done     ; jump if not a 'Buzz'
83 EB 04        sub bx, 4 
66C707 7A7A6946 mov dword ptr [bx], 'zziF' 

            fizz_done: 

84 FF           test bh, bh             ; either a Fizz or a Buzz? (BX not changed)
74 0C           jz short num_done       ; if so, do not display a digit
                 
            decimal_loop: 
D4 0A           aam;                    ; AL = AL mod 10
04 30           add al, '0'             ; convert to ASCII
4B              dec bx 
88 07           mov [bx], al 
C1 E8 08        shr ax, 8               ; 'mov al, ah', thatZF setsif ZFAL -= nice!0
75 F4           jnz decimal_loop 
                 
            num_done: 
8B D3           mov dx, bx              ; set dx to output string pointer
B4 09           mov ah, 9 
CD 21           int 21h 
58              pop ax                  ; restore fizzfizzbuzz counter
                 
E2 C3           loop main_loop 
C3              ret 
  • Use SI to reset the BX pointer to 100H, since DOS sets SI initially to 100H (ref). Use that to reset BX instead of an imm. (-1 byte)
  • Instead of using a 3/5 counter in DX, use AAM for modulo operations on counter. IMHO, AAM is a really underrated instruction since it's effectively a byte-length DIV using only 2 bytes that can accept an imm value as the divisor. @Peter Cordes touches on this in his very brilliant post about FizzBuzz in assembly. (-5 bytes)
  • Instead of CR/LF, use LF/CR (the order doesn't matter to DOS). This translates to an instruction that does not modify the default value of AX, thus we can eliminate the xor ax,ax and save two bytes. It does come at a cost because 0A 0D is only a two-byte instruction so the rest of the 24xx instruction needs to be padded with one more byte. (-1 bytes)
0A 0D           or cl, [di]             ; LF and CR bytes
24 00           and al, 0               ; DOS string delim + pad
B1 64           mov cl, 100             ; loop counter set to 100 
                 
            main_loop: 
8B DE           mov bx, si              ; init bx to 100h 
40              inc ax                  ; increment fizz counter 
50              push ax                 ; save fizz counter
                                     
50              push ax                 ; save ax from getting clobbered by AAM 
D4 05           aam 5                   ; AL = AL mod 5, ZF if AL = 0
58              pop ax                  ; restore ax 
75 0A           jnz short buzz_done 
83 EB 04        sub bx, 4               ; offset for output string 
66C707 7A7A7542 mov dword ptr [bx], 'zzuB' 
            buzz_done: 
                 
50              push ax 
D4 03           aam 3                   ; AL = AL mod 3, ZF if AL = 0
58              pop ax 
75 0A           jnz short fizz_done 
83 EB 04        sub bx, 4 
66C707 7A7A6946 mov dword ptr [bx], 'zziF' 

            fizz_done: 

84 FF           test bh, bh 
74 0C           jz short num_done 
                 
            decimal_loop: 
D4 0A           aam;                    ; AL = AL mod 10
04 30           add al, '0'             ; convert to ASCII
4B              dec bx 
88 07           mov [bx], al 
C1 E8 08        shr ax, 8               ; 'mov al, ah' that sets ZF - nice!
75 F4           jnz decimal_loop 
                 
            num_done: 
8B D3           mov dx, bx              ; set dx to output string pointer
B4 09           mov ah, 9 
CD 21           int 21h 
58              pop ax                  ; restore fizz counter
                 
E2 C3           loop main_loop 
C3              ret 
  • Use SI to reset BX since DOS sets SI initially to 100H (ref) instead of an imm. (-1 byte)
  • Instead of using a 3/5 counter in DH/DL, use AAM for modulo operations on counter.   AAM is a 2 byte instruction that's effectively a byte-length DIV that can accept an imm value as the divisor and also sets ZF if AL mod n = 0. @Peter Cordes touches on this in his very brilliant post about FizzBuzz in assembly. (-5 bytes)
  • Instead of CR/LF, use LF/CR (the order doesn't matter to DOS). This translates to an instruction that does not modify the startup value of AX (in fact it zeroes out AL) so we can eliminate the xor ax,ax and save two bytes. It does come at a cost because 0A 0D is only a two-byte instruction so the rest of the 24xx instruction needs to be padded with one more byte. (-1 byte)
0A 0D           or cl, [di]             ; LF and CR bytes (newline)
24 00           and al, 0               ; DOS string delim ('$') + pad byte
B1 64           mov cl, 100             ; set loop counter to 100 
                 
            main_loop: 
8B DE           mov bx, si              ; init bx to 100h 
40              inc ax                  ; increment fizzbuzz counter 
50              push ax                 ; save fizzbuzz counter
                                     
50              push ax                 ; save ax from getting clobbered by AAM 
D4 05           aam 5                   ; AL = AL mod 5, ZF if AL = 0
58              pop ax                  ; restore ax 
75 0A           jnz short buzz_done     ; jump if not a 'Fizz'
83 EB 04        sub bx, 4               ; offset for output string 
66C707 7A7A7542 mov dword ptr [bx], 'zzuB' 
            buzz_done: 
                 
50              push ax 
D4 03           aam 3                   ; AL = AL mod 3, ZF if AL = 0
58              pop ax 
75 0A           jnz short fizz_done     ; jump if not a 'Buzz'
83 EB 04        sub bx, 4 
66C707 7A7A6946 mov dword ptr [bx], 'zziF' 

            fizz_done: 

84 FF           test bh, bh             ; either a Fizz or a Buzz? (BX not changed)
74 0C           jz short num_done       ; if so, do not display a digit
                 
            decimal_loop: 
D4 0A           aam;                    ; AL = AL mod 10
04 30           add al, '0'             ; convert to ASCII
4B              dec bx 
88 07           mov [bx], al 
C1 E8 08        shr ax, 8               ; 'mov al, ah', ZF if AL = 0
75 F4           jnz decimal_loop 
                 
            num_done: 
8B D3           mov dx, bx              ; set dx to output string pointer
B4 09           mov ah, 9 
CD 21           int 21h 
58              pop ax                  ; restore fizzbuzz counter
                 
E2 C3           loop main_loop 
C3              ret 
-1 bytes, more fun with harmless opcodes
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
added 39 characters in body
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
added 14 characters in body
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading
Source Link
640KB
  • 11.9k
  • 2
  • 35
  • 57
Loading