FizzBuzz in Assembler

Over the weekend there was a little coding challenge to make FizzBuzz in a variety of programming languages. Naturally I chose to implement it in 16-bit intel-style assembler.

Here's a screenshot of it working!

There are two version, jump to them here:

Original version, compiles to about 750 bytes; and

More optimised second version, compiles to 94 bytes.

 

Updated 2nd 3rd version

There is now a second version that is a bit more optimised, while the original version compiled to around 750 bytes as an EXE, this new version compiles to COM and is only 94 bytes in size.

Download the source here and find the code below.

									
									.model tiny
									.code
									
									    org 0100h
									
									start:
									
									    ; initialise counters
									    mov cl, 0
									
									restart:
									    mov si, offset circ
									
									next_number:
									    
									    ; load next relative pointer from [circ] into AL 
									    xor ax, ax
									    lodsb
									
									    ; before doing any printing, let's update the values in [number]
									    adjust_number:
									        mov di, offset number
									
									        ; add "offset number" to ax to point di to start of string
									        add ax, di
									
									        ; DX = AX (used for printing later)
									        mov dx, ax
									
									        ; increase because we're 1-based not 0-based
									        inc cx
									    
									    two_digits:
									        ; first digit
									        mov ax, cx
									        mov bl, 10
									        div bl
									
									        add ax, 3030h
									
									        ; first byte is '0'? replace with 'return'
									        cmp al, 30h
									        jne store_now
									
									        mov al, 13
									
									    store_now:
									
									        stosw
									
									    ; k, let's print whatever we're pointing at. 
									    start_printing:
									
									        mov ax, 0924h
									        int 21h
									
									        mov dx, offset newline
									        int 21h
									
									        cmp cl, 20
									        je done
									
									        cmp si, offset circ + 15
									        je restart
									
									    jmp next_number
									
									done:
									
									    ret
									
									
									;     ____        _        
									;    |  _ \  __ _| |_ __ _ 
									;    | | | |/ _` | __/ _` |
									;    | |_| | (_| | || (_| |
									;    |____/ \__,_|\__\__,_|
									;                          
									
									    ; relative offsets of strings we can print
									    number_start EQU 0
									    fizz_start EQU 3
									    buzz_start EQU 8
									    fizzbuzz_start EQU 13
									
									    number         db '  $'
									    fizz         db 'Fizz$'
									    buzz         db 'Buzz$'
									    fizzbuzz     db 'FizzBuzz$'
									
									    newline     db 13, 10, '$'
									
									    ; pattern of finding fizzbuzz combinations
									    circ:
									        db number_start, number_start, fizz_start, number_start, buzz_start
									         db fizz_start, number_start, number_start, fizz_start, buzz_start, number_start
									         db fizz_start, number_start, number_start, fizzbuzz_start
									
									END start
									
									
									

 

Original

Download the source here.

									.model tiny
									.stack 100h
									.data
									
									    number db '00', 13, 10, '$'
									    newline db 13, 10, '$'
									
									    fizz db 'Fizz.', 13, 10, '$'
									    buzz db 'Buzz.', 13, 10, '$'
									    fizzbuzz db 'FizzBuzz.', 13, 10, '$'
									
									.code
									
									    mov ax, @data
									    mov ds, ax
									    mov es, ax
									
									    ; initialise counters
									    mov ax, 15
									    mov bx, 5
									    mov cx, 3
									    mov dx, 1
									
									    start_loop:
									        ; decrease counters
									        dec ax
									        dec bx
									        dec cx
									
									        ; fizz buzz hit 0? print
									        cmp ax, 0
									        jne test2
									        jmp prt_fizzbuzz
									
									    test2:
									        ; buzz hit 0? print
									        cmp bx, 0
									        jne test3
									        jmp prt_buzz
									
									    test3:
									        ; fizz hit 0? print
									        cmp cx, 0
									        jne print_number
									        jmp prt_fizz
									
									     print_number:
									
									        mov di, offset number
									
									        ; larger than 10? print two digits
									        cmp dx, 10
									        jge two_digits
									
									        ; otherwise add ' ' and '0'+dl
									         push ax
									
									        mov al, ' '
									        stosb
									
									        mov al, dl
									        add al, '0'
									        stosb
									
									        pop ax
									
									        jmp print_now
									
									    two_digits:
									
									        push bx
									        push ax
									
									        ; first digit
									        mov ax, dx
									        mov bl, 10
									        div bl
									
									        add al, '0'
									        stosb
									
									        mov al, ah
									        add al, '0'
									        stosb
									
									        pop ax
									        pop bx
									
									    print_now:
									
									         push ax
									         push dx
									
									        mov dx, offset number
									        mov al, 24h
									        mov ah, 09h
									        int 21h
									
									        pop dx
									        pop ax
									
									    ; after printing we end up here
									    continue_loop:
									
									        ; try to reset counters if required
									        cmp ax, 0
									        jne cont2
									        mov ax, 15
									
									    cont2:
									        cmp bx, 0
									        jne cont3
									        mov bx, 5
									
									    cont3:
									        cmp cx, 0
									        jne cont4
									        mov cx, 3
									
									    cont4:
									        
									        ; increase overall counter (0 -> 100)
									        inc dx
									
									        ; < 101 goto loop
									        cmp dx, 100
									        jne start_loop
									
									        ; terminate
									        mov ah, 4ch
									        int 21h
									
									    prt_fizz:
									
									        push dx
									        push ax
									
									        mov dx, offset fizz
									        mov al, 24h
									        mov ah, 09h
									        int 21h
									
									        pop ax
									        pop dx
									
									        jmp continue_loop
									
									    prt_buzz:
									
									        push dx
									        push ax
									
									        mov dx, offset buzz
									        mov al, 24h
									        mov ah, 09h
									        int 21h
									
									        pop ax
									        pop dx
									
									        jmp continue_loop
									
									    prt_fizzbuzz:
									
									        push dx
									        push ax
									
									        mov dx, offset fizzbuzz
									        mov al, 24h
									        mov ah, 09h
									        int 21h
									
									        pop ax
									        pop dx
									
									        jmp continue_loop
									
									end
									 

Also Read

How AI fits into my development workflow

By Marnix Kok on 27 August 2024

Interpreting Sitemaps, harder than you think.

By Marnix Kok on 22 August 2024