diff --git a/README.md b/README.md index 065c0c1..376722a 100644 --- a/README.md +++ b/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< 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 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() }, }