FizzBuzz in Assembler
in Blog,
by Marnix Kok
last published on 02 December 2021
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