BITS 32
ORG 0x1000

%define RAM_VIDEO 0xb8000
%define INTGATE  0x8E00	
%define IDTBASE  0x800	;addr. physique où doit resider la IDT
%define IDTSIZE  0xFF	;nombre max. de descripteurs dans la table

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Initialisation du PIC				;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
init_pic:
	mov al, 0x11  ; Initialisation de ICW1
	out 0x20, al  ; maître
	out 0xA0, al  ; esclave

	mov al, 0x20  ; Initialisation de ICW2
	out 0x21, al  ; maître, vecteur de départ = 32
	mov al, 0x70  
	out 0xA1, al  ; esclave, vecteur de départ = 96

	mov al, 0x04  ; initialisation de ICW3
	out 0x21, al
	mov al, 0x02 ; esclave
	out 0xA1, al

	mov al, 0x01  ; initialisation de ICW4
	out 0x21, al
	out 0xA1, al

	mov al, 0x0  ; masquage des interruptions
	out 0x21, al
	out 0xA1, al
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Fin de l'initialisation du PIC		;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Création d'une table des vecteurs d'interruption pointant sur un simple EOI (End Of Interrupt)	;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; IDT : Interrupt Descriptor Table
;;
;; Structure : http://fr.wikipedia.org/wiki/Interrupt_Descriptor_Table
;; mot : les 16 bits les plus faibles de l'offset de la fonction (gestionnaire d'interruption ou d'exception) associée à l'interruption
;; mot : le sélecteur du segment de code, donc l'adresse du descripteur de code dans la GDT
;; 1 bit : drapeau IF (sur "1" pour activer le masquage des interruptions masquables)
;; 2 bits : DPL, de 0 à 3 inclus, qui indique le niveau de privilèges requis pour appeler l'interruption (0 est le plus élevé)
;; 1 bit : doit être mis à 0
;; 4 bits : le type d'interruption (porte d'interruption, de trappe ou de tâche)
;; 8 bits : réservé pour un futur usage (doit être à 0)
;; mot : les 16 bits les plus hauts de l'offset de la fonction associée à l'interruption
;;
;;   7                           0
;;+---+---+---+---+---+---+---+---+
;;| P |  DPL  | S |    GateType   |
;;+---+---+---+---+---+---+---+---+
;;P 	7	 Present 	 can be set to 0 for unused interrupts or for Paging.
;;DPL 	6,5 	Descriptor Privilege Level 	Gate call protection. Specifies which privilege Level the calling Descriptor minimum should have. So hardware and CPU interrupts can be protected from beeing called out of userspace.
;;S 	4 	Storage Segment 	= 0 for interrupt gates.
;;Typ 	0..3 	Gate Type 0..3 	Possible IDT gate types :
;;0b0101 	0x5 	5 	80386 32 bit Task gate
;;0b0110 	0x6 	6 	80286 16-bit interrupt gate
;;0b0111 	0x7 	7 	80286 16-bit trap gate
;;0b1110 	0xE 	14 	80386 32-bit interrupt gate
;;0b1111 	0xF 	15 	80386 32-bit trap gate
;; Pour nous : les bits indiqués seront 00000000(forcément)10001110, à passer en bigendian
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	mov eax, IDTBASE ; Adresse de l'IDT
	mov ebx, interruptionParDefaut ; On va remplir toute la table avec l'interruption par défaut : bx contient les bits de poids faible
	mov edx, ebx
	shr edx, 16 ; et dx les bits de poids fort
	mov ecx, IDTSIZE	;Nombre de vecteurs d'interruption
remplitIDT:
	mov word [eax], bx
	add eax, 2
	mov word [eax], 0x08; dans "amorce.asm", c'est gtd_cs - gtd
	add eax, 2
	mov word [eax], INTGATE
	add eax, 2
	mov word [eax], dx;
	add eax, 2
	loop remplitIDT ; Un vecteur est écrit, et eax pointe sur le vecteur suivant.

; On remplace les vecteurs qui nous intéressent par leur vraie adresse de fonction.
	mov eax, IDTBASE
	add eax, 0x21*8 ; L'adresse dans la table est égale à AdresseDeBase + NuméroDeL'interruption * TailleD'unDescripteur.
	mov ebx, interruptionClavier
	mov edx, ebx
	shr edx, 16
	mov word [eax], bx
	add eax, 2
	add eax, 2
	add eax, 2
	mov word [eax], dx;
	
	lidt [idtptr]	; charge l'idt
	sti

	mov edi, clavier
	mov eax, 300
	mov ebx, 10
	mov cl, 1
	mov ch, 0
	call nombreVersChaine
	
	mov esi, clavier
	call afficheChaine
	
	mov edi, clavier
	call litChaine
fin:
	jmp $

interruptionParDefaut:
	mov al,0x20	; EOI (End Of Interrupt)
	out 0x20,al	; qu'on envoie au PIC
	iret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Gestion des interruptions clavier	;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
interruptionClavier:
	cli
	xor eax, eax
	xor ebx, ebx
.attendBuffer:
	in		al,		0x64	; lire statut
	test	byte al,1		; bus de sortie pret ?
	jz		.attendBuffer	; non => boucler

	in		al, 	0x60	;Lit la touche pressée
	cmp		al, 	224		;224 est un code spécial, ça veut dire qu'il y a autre chose derrière, mais pour l'instant on s'en fiche
	je		.attendBuffer	;On va donc lire la suite

	mov bl, al
	shr bl, 3; On divise le code par 8 pour savoir dans quel octet il se situe
	push eax	; On sauve le caractère dans la pile
	mov cl, 8
	div cl		; On le divise par 8
	mov cl, ah	; Pour une division par 8 bits, le reste est dans AH
	pop eax
	mov edx, 1
	shl dl, cl
	add ebx, touchesActives ;C'est l'adresse de l'octet contenant ce qui nous intéresse
	cmp		al,		128		;Les touches appuyées ont un code inférieur à 128, les touches relâchées, c'est le même code qu'appuyées plus 128
	jb		.stockeActif
	sub		al,		128
	sub		ebx,	128/8
	not dl
	and byte[ebx], dl
	jmp .suite
.stockeActif:
	or byte[ebx], dl	; Un OU met le bit à 1, un NOT AND le mettra à 0
	mov [derniereTouche], al

.suite:
	in 		al, 	0x61
	or		al, 	130
	out 	0x61, 	al		;Dit à l'ordi qu'une touche a été pressée

	and 	al,		127
	out 	0x61,	al		;Reinitialisation terminée
 
    sti
	jmp 	interruptionParDefaut

touchesActives: ;Il me faut 128 bits (à la louche) pour stocker les touches actives, soit, 128/8 = 16 octets, soit 4 doubles mots
	dd 0, 0, 0, 0
derniereTouche:
	db 0
traductionASCII:
	db '.','.','1','2','3','4','5','6','7','8','9','0','.','+','.','.','a','z','e','r','t','y','u','i','o','p','^','$',13,'.','q','s'
	db 'd','f','g','h','j','k','l','m','%','.','.','*','w','x','c','v','b','n',',',';',':','!';54 caratères gérés
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Fin gestion interruptions clavier	;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Synopsis: Affiche une chaîne de caractères se terminant par NULL	;;
; Entree:   SI -> pointe sur la chaîne à afficher					;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
afficheChaine:
	push	eax
	push	ebx
	push	ecx
	xor		eax, eax
	xor		ebx, ebx
	mov 	cx, [curseurX]
	mov		al, ch
	shl		al, 2
	add		al, ch
	shl		ax, 5	;	On vient de faire une multiplication par 160.
	mov		bl, cl
	shl		bl, 1
	add		ax, bx
	mov		bx, ax
	add		ebx, RAM_VIDEO
.caractereSuivant:
	lodsb			; ds:esi -> al
	or		al, al	; fin chaine ?
	jz		.fin
	cmp 	cl, 80	; Le curseur est en fin de chaîne
	jne		.continuer
	xor		cl, cl
	inc		ch
.continuer:
	cmp		al, 13
	jne 	.ligneOK
	mov 	al, cl
	shl		al, 1
	sub		ebx, eax
	mov		cl, 0
	inc		ch
	add		ebx, 160
	jmp		.caractereSuivant
.ligneOK:
	cmp		ch, 25
	jb		.scrollOK
	push	esi
	mov		esi, RAM_VIDEO + 160;On décale tout d'une ligne
	mov		edi, RAM_VIDEO
	push 	ecx
	mov		ecx, 160*24/4
	rep		movsd
	mov 	ecx, 40;On vide la dernière ligne
	push 	eax
	xor 	eax, eax
	rep		stosd
	pop		eax
	pop		ecx
	pop		esi
	dec		ch
	sub 	ebx, 160
	jmp .ligneOK
.scrollOK:
	mov 	byte [ebx], al
	inc 	ebx
	mov 	byte [ebx], 0x07
	inc 	ebx
	inc 	cl
    jmp 	.caractereSuivant

.fin:
	mov		[curseurX], cx; Sauvegarde de la position du curseur
	pop 	ecx
	pop 	ebx
	pop 	eax
	ret
curseurX:
	db 0
curseurY:
	db 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; nombreVersChaine													;;
;;------------------------------------------------------------------;;
;; Ecrit dans la chaîne pointée par EDI le nombre contenu dans EAX	;;
;; si CL est à un, on écrit un caractère terminal					;;
;; CH contient le nombre minimal de caractères à utiliser			;;
;; EBX contient la base												;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
nombreVersChaine:
	push 	edx
	push 	ecx
	xor		cl, cl
.stocke_digit:
	xor 	edx, edx
	div 	ebx
	push 	edx 			; Sauve le reste dans la pile
	inc 	cl
	or 		eax, eax		; Si le quotient n'est pas nul
	jne 	.stocke_digit	; on recommence
;Les digits sont stockés dans la pile
.ajout_zero:
	cmp 	ch, cl
	jbe		.clearCH
	push 	' '-'A'+10		; Nombre magique permettant de remplir avec des espaces
	inc 	cl
	jmp 	.ajout_zero
.clearCH:
	xor 	ch, ch
;Affichage du chiffre : On en affiche au moins un : zéro
.affiche_digit:
	pop 	eax
	cmp 	al, 10
	jae 	.dixPlus
	add 	al, '0'
	stosb 					; met AL dans l'octet pointé par EDI et incrémente EDI
	jmp 	.boucle_digit
.dixPlus:					; Pour les bases à plus de 10 chiffres, on utilise l'alphabet
	add 	al, 'A' - 10
	stosb
	jmp 	.boucle_digit
.boucle_digit:
	loop 	.affiche_digit
	pop 	ecx 			; on récupère le paramètre cx
	test 	cl, 0b1 		; s'il est à 1, on écrit un caractère terminal
	jz 		.depile
	mov 	byte [edi], 0
.depile:
	pop 	edx
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;	Fin nombreVersChaine											;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; litChaine														;;
;;------------------------------------------------------------------;;
;; Ecrit dans la chaîne pointée par EDI les caractères écrits au 	;;
;; clavier, jusqu'à un retour chariot. 								;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
litChaine:
	push eax
	push ebx
	xor eax, eax
	mov byte [derniereTouche], 0
	mov esi, edi
.attend_clavier:
	cmp byte [derniereTouche], 0
	jz .attend_clavier
	mov al, [derniereTouche]
	mov byte [derniereTouche], 0

	mov ebx, traductionASCII
	add ebx, eax
	mov al, [ebx]
	stosb
	cmp al, 13
    je .fin_attend_clavier
	mov al, 0
	stosb
	call afficheChaine
	dec edi
	dec esi
    jmp .attend_clavier
.fin_attend_clavier:
    pop ebx
    pop eax
    ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Fin litChaine													;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;--------------------------------------------------------------------
idtptr:
	dw	IDTSIZE << 3			; limite
	dd	IDTBASE					; base

chaine:
	db 	"J'ai ici une superbe fonction d'affichage de texte qui ne saurait planter sur un malheureux saut ", 13, "de ligne", 13, 0
clavier:
	db	"12345678 ", 0
;horloge:
;	db	"tic ", 0
times 1024-($-$$) db 0
