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`
|
||||
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)
|
||||
- `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
|
||||
pour lancer la simulation:
|
||||
# Simulateur
|
||||
## pour lancer la simulation:
|
||||
- depuis ce dossier
|
||||
`cargo run --release -p simu fichierentre`
|
||||
- depuis le sous dossier simu
|
||||
`cargo run --release fichierentre`
|
||||
|
||||
Le mmio du clavier a les même scancode que la version python
|
||||
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)
|
||||
Pour rajouter le support de multiplication/division: rajouter --features=div_mul
|
||||
|
||||
### 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, 0b1100)
|
||||
| (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, 0b0001) => Self::Load(rd, rx, op2),
|
||||
(2, 0b0010) => Self::Push(op2),
|
||||
@@ -232,13 +234,13 @@ impl TryFrom<u32> for Instruction {
|
||||
(2, 0b1101) => Self::GetStack(rd),
|
||||
(2, 0b1110) => Self::SetStack(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 {
|
||||
@@ -396,7 +398,7 @@ impl Computer {
|
||||
if !addr.is_multiple_of(4) {
|
||||
self.serve_interupt(
|
||||
InteruptKind::IllegalLoadStore,
|
||||
[0, addr as u32, self[reg1]],
|
||||
[1, addr as u32, self[reg1]],
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -411,10 +413,7 @@ impl Computer {
|
||||
(&SHARED.external_enabled_interupts)
|
||||
.store(self[reg1], std::sync::atomic::Ordering::Relaxed);
|
||||
} else {
|
||||
self.serve_interupt(
|
||||
InteruptKind::IllegalLoadStore,
|
||||
[0, addr as u32, self[reg1]],
|
||||
);
|
||||
self.serve_interupt(InteruptKind::IllegalOpcode, [next_opcode]);
|
||||
}
|
||||
}
|
||||
Instruction::Load(reg, reg1, op2) => {
|
||||
@@ -446,10 +445,7 @@ impl Computer {
|
||||
_ => unsafe { unreachable_unchecked() },
|
||||
}
|
||||
} else {
|
||||
self.serve_interupt(
|
||||
InteruptKind::IllegalLoadStore,
|
||||
[1, addr as u32, reg.0 as u32],
|
||||
);
|
||||
self.serve_interupt(InteruptKind::IllegalOpcode, [next_opcode]);
|
||||
return;
|
||||
};
|
||||
}
|
||||
@@ -520,7 +516,12 @@ impl Computer {
|
||||
ret_index = Some(self.regs[0]);
|
||||
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 => {}
|
||||
}
|
||||
}
|
||||
@@ -573,12 +574,11 @@ impl Computer {
|
||||
}
|
||||
};
|
||||
}
|
||||
Err((kind, rx, ry, op2)) => {
|
||||
Err((kind, rx, ry, op2, opcode)) => {
|
||||
self.pc += 1;
|
||||
match kind {
|
||||
InteruptKind::UnsupportedOpcode => {
|
||||
self.serve_interupt(kind, [rx.0.into(), self[ry], self.resolve(op2)])
|
||||
}
|
||||
InteruptKind::UnsupportedOpcode => self
|
||||
.serve_interupt(kind, [rx.0.into(), self[ry], self.resolve(op2), opcode]),
|
||||
InteruptKind::IllegalOpcode => self.serve_interupt(kind, [next_opcode]),
|
||||
_ => unsafe { unreachable_unchecked() },
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user