Explained and finalized interrupts
This commit is contained in:
85
README.md
85
README.md
@@ -11,14 +11,89 @@ syntaxe supplémentaire supportée:
|
|||||||
- `D valeur`
|
- `D valeur`
|
||||||
rentre la donné brute égale à la valeur (immédiate ou addresse de label)
|
rentre la donné brute égale à la valeur (immédiate ou addresse de label)
|
||||||
(pour mettre des données dans le fichier et pas du code executable)
|
(pour mettre des données dans le fichier et pas du code executable)
|
||||||
|
- `eint` Active les interruptions
|
||||||
|
- `dint` Desactive les interruptions
|
||||||
|
- `swi` Active l'interruption swi
|
||||||
|
- `reti` Retourne depuis le handler d'interruption
|
||||||
|
- `umull` multiplication non signée usuelle
|
||||||
|
- `umulh` multiplication non signée, moitié haute du résultat 64 bits
|
||||||
|
- `smull` et `sumlh` versions signée de la multiplication
|
||||||
|
- `div` division non signée
|
||||||
|
- `mod` modulo non signé
|
||||||
|
|
||||||
# Simulateut
|
# Simulateur
|
||||||
pour lancer la simulation:
|
## pour lancer la simulation:
|
||||||
- depuis ce dossier
|
- depuis ce dossier
|
||||||
`cargo run --release -p simu fichierentre`
|
`cargo run --release -p simu fichierentre`
|
||||||
- depuis le sous dossier simu
|
- depuis le sous dossier simu
|
||||||
`cargo run --release fichierentre`
|
`cargo run --release fichierentre`
|
||||||
|
|
||||||
Le mmio du clavier a les même scancode que la version python
|
Pour rajouter le support de multiplication/division: rajouter --features=div_mul
|
||||||
Un horloge temps réèl a été ajoutée: lecture du nombre de millisecondes écoulés depuis la création de la simulation
|
|
||||||
a l'adresse 0x01200004 (clavier + 4)
|
### instruction spéciale:
|
||||||
|
halt (jump 0) met le programme en pause, mais on peut se reveiller par des interuptions
|
||||||
|
call 0 termine l'exécution du simulateur
|
||||||
|
|
||||||
|
## mmio:
|
||||||
|
- 0x01000000 à 0x0112c000 : Écran en lecture/écriture. un pixel par 32bits, de gauche a droite puis de bas en haut.
|
||||||
|
Format de pixel en 0BGR, 4 bits par couleur.
|
||||||
|
Passage au format RGBA (a pour alpha) avec la feature rgba
|
||||||
|
- 0x01200000 : Clavier (scancode) (lecture seule)
|
||||||
|
- 0x01200004 : Horloge (millisecondes écoulé depuis le début de la simulation, wrappe tout les 49 jours) (lecture seule)
|
||||||
|
- 0x01200008 : Boutons de la souris (OR des boutons préssés) Gauche = 1, Droit=2, Clic Molette = 3, Autres non testé (lecture seule)
|
||||||
|
- 0x0120000c : Position horizontale de la souris (en pixels, -1 si hors de l'écran) (lecture seule)
|
||||||
|
- 0x01200010 : Position verticale de la souris (en pixels, -1 si hors de l'écran) (lecture seule)
|
||||||
|
- 0x01201000 : Activation des Interupts de MMIO. Remis a zero par `dint`. Attention, Écrire ici sans activer les interruptions va bloquer les intéruptions et l'affichage (écriture seule)
|
||||||
|
|
||||||
|
## Interuptions:
|
||||||
|
Si les interruptions sont activées (avec eint), qu'il y a une raison de faire une interruption,
|
||||||
|
et qu'on n'est pas déjà dans une routine d'interruption de priorité >=,
|
||||||
|
alors le cpu effectue les actions suivantes:
|
||||||
|
|
||||||
|
Finis l'instruction en cours si c'est une interruption externe
|
||||||
|
si interruption a des arguments, les mets dans les registres par ordre croissant,
|
||||||
|
Mets PC a (priorité de l'intéruption)*4 (instruction n°priorité)
|
||||||
|
|
||||||
|
Cela veut dire que votre début de programme, si vous voulez utiliser les interruption, doit être une table de jump vers les handler correspondant
|
||||||
|
|
||||||
|
Pour sortir d'une interuption, utilisez `reti`
|
||||||
|
*Il FAUT sortir avec un reti*
|
||||||
|
|
||||||
|
*Les interuptions utilisent la stack, donc lorsque les interuptions sont activés, il est interdit de stocker des information au dessus du pointeur de stack.
|
||||||
|
de même, `reti` ne peut pas être appellé par une sous fonction appellée depuis l'interrupt handler*
|
||||||
|
|
||||||
|
Les intéruptions et leurs arguments, par priorité croissante:
|
||||||
|
### 0: Point d'entrée
|
||||||
|
C'est ici que le programme commence. Seul cas d'utilisation
|
||||||
|
### 1: MMIO
|
||||||
|
Doivent être activé par le MMIO a l'adresse 0x01201000, en y écrivant le OR des (1<<identifiant)
|
||||||
|
On toujours pour argument (r0) leur identifiant
|
||||||
|
Les mmio corespondant sont modifié avant d'entrer dans l'intéruption, et TOUT LES MMIO d'une interuption active sont bloqués tant qu'on n'est pas sorti
|
||||||
|
- 1 : Clavier
|
||||||
|
- 2 : Boutons de la souris
|
||||||
|
- 3 : Mouvements de la souris
|
||||||
|
- 4 : Écran (rien n'est modifié, attend la sortie de l'intéruption pour afficher une frame)
|
||||||
|
### 2: SWI
|
||||||
|
Pas d'argument
|
||||||
|
|
||||||
|
### 3: Division par zero
|
||||||
|
2 arguments: numéro de registre de sortie et valeur du dividende.
|
||||||
|
lors de l'appel a reti, attend que r0 n'ai pas été modifié et un retour dans r1.
|
||||||
|
la registre de destination prend la valeur retourné dans r1
|
||||||
|
### 4: Load/Store illégal
|
||||||
|
Un load store a été fait a une adresse non multiple de 4
|
||||||
|
3 aruments:
|
||||||
|
si c'est un load: 0, addresse, numéro de registre de retour
|
||||||
|
si c'est un store: 1, addresse, valeure a stocker
|
||||||
|
ne modifiez pas r0, et dans le cas des load, r2. (ou restaurez avant le reti)
|
||||||
|
Si c'est un load, le registre destination prendra la valeur de retour, attendue dans r1
|
||||||
|
### 5: Unsupported Opcode
|
||||||
|
Une division multiplication alors qu'elle ne sont pas activées
|
||||||
|
4 arguments:
|
||||||
|
indice de registre de retour, argument 1, argument 2, fonction
|
||||||
|
Même mode de retour que la division par zero
|
||||||
|
### 6: Instruction Illégale
|
||||||
|
Une instruction non légale, ou un load / store a une adresse non mappé.
|
||||||
|
1 argument: l'opcode de l'instruction associé
|
||||||
|
Il est fortement recommendé d'utiliser cette intéruption pour afficher du debug, puis de quitter le programme, mais il est possible
|
||||||
|
de continuer a l'instruction suivante à l'aide d'un `reti`
|
||||||
|
|||||||
@@ -214,7 +214,9 @@ impl TryFrom<u32> for Instruction {
|
|||||||
| (1, 0b1011)
|
| (1, 0b1011)
|
||||||
| (1, 0b1100)
|
| (1, 0b1100)
|
||||||
| (1, 0b1101)
|
| (1, 0b1101)
|
||||||
| (1, 0b1110) => return Err((InteruptKind::UnsupportedOpcode, rd, rx, op2)),
|
| (1, 0b1110) => {
|
||||||
|
return Err((InteruptKind::UnsupportedOpcode, rd, rx, op2, opcode));
|
||||||
|
}
|
||||||
(2, 0b0000) => Self::Store(rx, op2, rd),
|
(2, 0b0000) => Self::Store(rx, op2, rd),
|
||||||
(2, 0b0001) => Self::Load(rd, rx, op2),
|
(2, 0b0001) => Self::Load(rd, rx, op2),
|
||||||
(2, 0b0010) => Self::Push(op2),
|
(2, 0b0010) => Self::Push(op2),
|
||||||
@@ -232,13 +234,13 @@ impl TryFrom<u32> for Instruction {
|
|||||||
(2, 0b1101) => Self::GetStack(rd),
|
(2, 0b1101) => Self::GetStack(rd),
|
||||||
(2, 0b1110) => Self::SetStack(op2),
|
(2, 0b1110) => Self::SetStack(op2),
|
||||||
(3, skip) => Self::Skip(rd.0, (skip as u8).into(), rx, op2),
|
(3, skip) => Self::Skip(rd.0, (skip as u8).into(), rx, op2),
|
||||||
_ => return Err((InteruptKind::IllegalOpcode, rd, rx, op2)),
|
_ => return Err((InteruptKind::IllegalOpcode, rd, rx, op2, opcode)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type Error = (InteruptKind, Reg, Reg, Op2);
|
type Error = (InteruptKind, Reg, Reg, Op2, u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Computer {
|
pub struct Computer {
|
||||||
@@ -396,7 +398,7 @@ impl Computer {
|
|||||||
if !addr.is_multiple_of(4) {
|
if !addr.is_multiple_of(4) {
|
||||||
self.serve_interupt(
|
self.serve_interupt(
|
||||||
InteruptKind::IllegalLoadStore,
|
InteruptKind::IllegalLoadStore,
|
||||||
[0, addr as u32, self[reg1]],
|
[1, addr as u32, self[reg1]],
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -411,10 +413,7 @@ impl Computer {
|
|||||||
(&SHARED.external_enabled_interupts)
|
(&SHARED.external_enabled_interupts)
|
||||||
.store(self[reg1], std::sync::atomic::Ordering::Relaxed);
|
.store(self[reg1], std::sync::atomic::Ordering::Relaxed);
|
||||||
} else {
|
} else {
|
||||||
self.serve_interupt(
|
self.serve_interupt(InteruptKind::IllegalOpcode, [next_opcode]);
|
||||||
InteruptKind::IllegalLoadStore,
|
|
||||||
[0, addr as u32, self[reg1]],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instruction::Load(reg, reg1, op2) => {
|
Instruction::Load(reg, reg1, op2) => {
|
||||||
@@ -446,10 +445,7 @@ impl Computer {
|
|||||||
_ => unsafe { unreachable_unchecked() },
|
_ => unsafe { unreachable_unchecked() },
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.serve_interupt(
|
self.serve_interupt(InteruptKind::IllegalOpcode, [next_opcode]);
|
||||||
InteruptKind::IllegalLoadStore,
|
|
||||||
[1, addr as u32, reg.0 as u32],
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -520,7 +516,12 @@ impl Computer {
|
|||||||
ret_index = Some(self.regs[0]);
|
ret_index = Some(self.regs[0]);
|
||||||
ret_value = self.regs[1];
|
ret_value = self.regs[1];
|
||||||
}
|
}
|
||||||
InteruptKind::IllegalLoadStore => {}
|
InteruptKind::IllegalLoadStore => {
|
||||||
|
if self.regs[0] == 0 {
|
||||||
|
ret_value = self.regs[1];
|
||||||
|
ret_index = Some(self.regs[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
InteruptKind::IllegalOpcode => {}
|
InteruptKind::IllegalOpcode => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -573,12 +574,11 @@ impl Computer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Err((kind, rx, ry, op2)) => {
|
Err((kind, rx, ry, op2, opcode)) => {
|
||||||
self.pc += 1;
|
self.pc += 1;
|
||||||
match kind {
|
match kind {
|
||||||
InteruptKind::UnsupportedOpcode => {
|
InteruptKind::UnsupportedOpcode => self
|
||||||
self.serve_interupt(kind, [rx.0.into(), self[ry], self.resolve(op2)])
|
.serve_interupt(kind, [rx.0.into(), self[ry], self.resolve(op2), opcode]),
|
||||||
}
|
|
||||||
InteruptKind::IllegalOpcode => self.serve_interupt(kind, [next_opcode]),
|
InteruptKind::IllegalOpcode => self.serve_interupt(kind, [next_opcode]),
|
||||||
_ => unsafe { unreachable_unchecked() },
|
_ => unsafe { unreachable_unchecked() },
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user