; Assemblatore NASM 2.07
; calcola il numero di cifre decimali '2' presenti tra due numeri A e B
; compresi gli estremi. stampa anche la sequenza dei numeri.
; esempio tra i numeri 2001 e 20012 ci sono 14 cifre '2'
; usa registri a 16 bits
;
; 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
;

        global _start
 
section .data
        buffer  resb 16
	num_a	dw 2001
	num_b	dw 2012
 
section .text
 
_start:
	mov	si,[num_a]	; mette numero iniziale in SI
	mov	di,[num_b]	; mette il numero finale in DI
	mov	cx,0		; uso CX come contatore delle cifre '2'
loop1:
	mov	ax,si
	call	print_ax	; stampo il numero in AX
loop2:
	xor	dx,dx
	mov	bx,10
	div	bx
	cmp	dx,2
	jne	not_due
	inc	cx
not_due:
	cmp	ax,0
	jne	loop2
	inc	si
	cmp	si,di
	jbe	loop1	

	; ora in CX ho il numero di '2' e lo stampo
	mov	ax,cx
	call	print_ax
 
exit:
        mov             eax, 01h                ; exit()
        xor             ebx, ebx                ; errno
        int             80h
 


print_ax
	push	eax
	push	ecx
	push	edx
	mov	edx,buffer
	call	bin2dec16
	mov	byte [buffer+ecx],0ah	; aggiunge new-line
	mov	byte [buffer+ecx+1],0	; make ASCIIZ
	call	printasciiz
	pop	edx
	pop	ecx
	pop	eax
	ret





; FUNCTION: bin2dec16
; converte un numero binario a 16 bit in una stringa ASCII decimale
; Parametri:
;	AX  = numero da stampare
;	EDX = indirizzo del buffer ASCII (5 cifre)
; Return:
;	ECX = lunghezza della strinag
bin2dec16:
        push    eax
        push    ebx
        push    edx
        push    esi
        mov     esi,edx
        mov     ecx,0   ; contatore cifre significative
        mov     bx,10   ; divisore
.loop1
        xor     dx,dx	; DX:AX = dividendo
        div     bx      ; ax=quoziente, dx=resto
        add     dl,30h
        push    dx      ; salva il digit sullo stack
        inc     ecx     ; incrementa contatore cifre
        cmp     ax,0
        jne     .loop1

        mov     eax,ecx ; salva numero digits

.loop2:		;recupera i digit dallo stack in ordine inverso (almeno 1)
        pop     dx
        mov     [esi],dl
        inc     esi
        loop    .loop2
        mov     ecx,eax ; return ECX
        pop     esi
        pop     edx
        pop     ebx
        pop     eax
        ret


; FUNCTION: printasciiz
; stampa la stringa ASCIIZ in ingresso. La stringa è terminata da un NULL byte
; Parametri:
;	EDX = indirizzo della stringa ASCIIZ
; Return:
;	none
;
printasciiz:
	push	eax
	push	ecx
	push	edx
	mov	al,0
	call	strlen	; ecx=length
	mov	eax,ecx	; scambia ecx ed edx
	mov	ecx,edx	; indirizzo buffer in ecx
	mov	edx,eax	; length in edx
	call	write
	pop	edx
	pop	ecx
	pop	eax
	ret


; FUNCTION: strlen
; calcola la lunghezza della stringa terminata dal char AL
; Parametri:
;	AL  = carattere terminatore
;	EDX = indirizzo della stringa
; Return:
;	ECX = lunghezza stringa
strlen:
	push	eax
	push	edx
	push	esi
	mov	esi,edx	; EDX=start string
.loop1:
	mov	ah,[esi]
	cmp	ah,al
	je	.end
	inc	esi
	jmp	.loop1
.end:
	mov	ecx,esi		; ECX=end string
	sub	ecx,edx		; sottrae dalla fine del buffer l'inizio
	pop	esi
	pop	edx
	pop	eax
	ret


; FUNCTION: read
; legge un buffer da standard input
; Parametri:
;	ECX = indirizzo del buffer
;	EDX = lunghezza del buffer
;
read:
	push	eax
	push	ebx
	mov	eax, 03h		; read()
	mov	ebx, 00h		; stdin
	int	80h
	pop	ebx
	pop	eax
	ret

; FUNCTION: write
; scrive un buffer su standard input
; Parametri:
;	ECX = indirizzo del buffer
;	EDX = lunghezza del buffer
;
write:
	push	eax
	push	ebx
	mov	eax, 04h		; write()
	mov	ebx, 01h		; stdout
	int	80h
	pop	ebx
	pop	eax
	ret
