Skip to content

Instantly share code, notes, and snippets.

@winny-
Last active September 12, 2018 05:03
Show Gist options
  • Save winny-/806a4db81d58748d01be to your computer and use it in GitHub Desktop.
Save winny-/806a4db81d58748d01be to your computer and use it in GitHub Desktop.
org 0x100
movzx cx, [0x80]
mov bx, 1 ; stdout
mov dx, 0x81
mov ah, 0x40
int 0x21
mov ax, 0x4c00
int 0x21
%macro WriteString 1
mov ah, 0x9 ; the "syscall" number
mov dx, %1 ; offset of the string, '$' terminated.
int 0x21 ; Call into DOS.
%endmacro
%macro Exit 1
mov ah, 0x4c ; the "syscall number"
mov al, %1 ; exit number, 0 = success.
int 0x21
%endmacro
; COM file starts at 0x100, the space before is used at runtime to set
; initial program state.
org 0x100
Start:
mov ax, 0x82 ; First char [0x81] is always a separator.
movzx cx, [0x80] ; Length of args string.
dec cx ; Account skipping 0x81.
call IsDigit
cmp ax, 0 ; Is our arg not digits?
jz .B1
WriteString haveDigits
mov ax, 0x82 ; First char [0x81] is always a separator.
movzx cx, [0x80] ; Length of the arguments string.
dec cx ; Account for skipping the first character.
call StringToInt
jmp .B2
.B1:
mov ax, [nummax] ; Otherwise set a sensible default.
.B2:
call FizzBuzz
Exit 0
nop ; Padding for readibility when debugging.
nop
haveDigits db 'Have digits',0xa,0xd,'$'
nummax dw 15
nop
nop
; Inputs: AX -- number to count up to
; Outputs: None.
; Writes to console.
FizzBuzz:
pusha
mov bp, sp
sub sp, 6 ; Reserve 6 bytes for local data.
mov bx, ax ; Copy num to count up to into bx.
mov cx, 1 ; Start at 1.
.L1:
xor si, si ; Using si as a flag, clear at start of loop.
mov ax, cx ; Set dividend.
xor dx, dx ; Clear upper half of dividend.
mov di, 3 ; Set divisor.
div di
cmp dx, 0 ; Is there a remainder?
jne .B1
inc si
WriteString fizzstr
.B1:
mov ax, cx
xor dx, dx
mov di, 5
div di
cmp dx, 0 ; Is there a remainder?
jne .B2
inc si
WriteString buzzstr
.B2:
cmp si, 0 ; Is si set?, then print the number.
jne .B3
mov ax, cx
push bx
lea bx, [bp-6] ; Load the address of local buffer.
call IntToString
WriteString bx
pop bx
.B3:
WriteString sepstr
inc cx
cmp cx, bx ; Are we still counting up?
jbe .L1
add sp, 6 ; Dismiss our local data.
popa
ret
nop
nop
fizzstr db 'Fizz','$'
buzzstr db 'Buzz','$'
sepstr db 0xa,0xd,'$'
nop
nop
; Inputs: AX -- the integer, BX -- the output string address
; Outputs: None.
; Assumes the output is wide enough for a 16-bit integer.
;
; May be a bit slow because it copies the string digits in a temp
; buffer, and then copies the temp buffer into [bx] in reverse.
; This way this code doesn't need to know in advance how many digits
; are in the output string.
IntToString:
pusha
mov bp, sp
sub sp, 5 ; Reserve 5 bytes for a buffer.
; Convert to base 10 and turn each digit into an ascii digit.
lea si, [bp-5] ; Load the address of buffer.
mov cx, si ; Copy into cx.
mov di, 10 ; Set the divisor only once.
.L1:
xor dx, dx ; Clear upper half of dividend.
div di
add dl, '0' ; Add constant '0' to the remainder.
mov [si], dl ; Copy into our buffer.
cmp ax, 0 ; Finished converting to base 10?
je .B1
inc si
jmp .L1
; Copy buffer in reverse order and add a '$'.
.B1:
.L2:
mov al, byte [si]
mov [bx], byte al
dec si
inc bx
cmp si, cx
jae .L2
mov [bx], byte '$'
add sp, 5
popa
ret
nop
nop
; Inputs: AX -- address of the string, CX -- number of bytes in string.
; Outputs: AX = 0 if not all bytes are ascii digits.
IsDigit:
push bx
push cx
mov bx, ax
.L1:
cmp [bx], byte '0'
jb .B2
cmp [bx], byte '9'
ja .B2
inc bx
loop .L1
.B1:
mov ax, 1
jmp .END
.B2:
xor ax, ax
.END:
pop cx
pop bx
ret
nop
nop
; Inputs: AX -- the string, CX -- the length of the string
; Outputs: AX -- the integer
StringToInt:
push bx
push cx
push di
push si
mov bx, ax
xor ax, ax
mov si, 10
.L1:
movzx di, byte [bx]
sub di, '0'
mul si
add ax, di
inc bx
loop .L1
pop si
pop di
pop cx
pop bx
ret
org 0x100
call sayhello
mov ax, winston
call greetname
call sayhello
mov ax, 0x4c00 ; ah = 0x4c (exit), al = 0x00 (success)
int 0x21
sayhello:
push ax
push dx
mov dx, hellostr
mov ah, 9
int 0x21
pop dx
pop ax
ret
greetname:
nameptr dw 0
push ax
push dx
mov [nameptr], ax
mov ah, 9
mov dx, hi
int 0x21
mov ah, 9
mov dx, [nameptr]
int 0x21
mov ah, 9
mov dx, crlf
int 0x21
pop dx
pop ax
ret
hellostr db 'Hello, world!',0xd,0xa,'$'
winston db 'Winston','$'
hi db 'Hi, ','$'
crlf db 0xd,0xa,'$'
org 0x100
xor dl, dl
mov si, buf2
mov ah, 0x47
int 0x21
xor al, al
mov di, buf2
cld
repnz scasb
mov [di-1], byte '$'
mov ah, 0x19
int 0x21
add al, 'A'
mov [buf], byte al
mov dx, buf
mov ah, 0x9
int 0x21
mov ax, 0x4c00
int 0x21
nop
nop
buf db 0,':\'
buf2 resb 64
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment