Aller au contenu

EX04 - Systèmes de nombres

Exercice 1 : Les nombres entiers non-signés

Convertir en binaire les nombres suivants :

  • \(125_{10}\) (Base 10)
  • \(0377_8\) (Base 8)
  • \(0x\mathrm{ADE}1_{16}\) (Base 16)

Convertir en décimal les nombres suivants :

  • \(0b10011000_2\) (Base 2)
  • \(0177_8\) (Base 8)
  • \(0x25\mathrm{E}1_{16}\) (Base 16)

Additionner les nombres binaires suivants et donner le résultat ainsi que l’état des flags C et Z. On considère des nombres sur 8 bits :

  • \(0b10011000_2 + 0b10011000_2\)
  • \(0b11111101_2 + 0b00000011_2\)
  • \(0b00011000_2 + 0b10011100_2\)

Soustraire les nombres binaires suivants et donner le résultat ainsi que l’état des flags C et Z :

  • \(0b10011000_2 - 0b10011000_2\)
  • \(0b11111101_2 - 0b00000011_2\)
  • \(0b00011000_2 - 0b10011100_2\)

Donner le résultat ainsi que l’état des flags C et Z pour les soustractions suivantes :

  • \(125 - 128\)
  • \(77 - 26\)
  • \(254 - 254\)
  • \(255 - 0\)

Exercice 2 : Les nombres entiers signés

Convertir en binaire les nombres suivants et indiquer l’état du flag N :

  • \(-125_{10}\) (Base 10)
  • \(0271_8\) (Base 8)
  • \(0x50\mathrm{F}1_{16}\) (Base 16)

Convertir en décimal les nombres suivants :

  • \(0b10011000_2\) (Base 2)
  • \(0177_8\) (Base 8)
  • \(0x85\mathrm{E}1_{16}\) (Base 16)

Additionner les nombres binaires suivants et donner le résultat ainsi que l’état des flags V, N et Z :

  • \(0b10011000_2 + 0b10011000_2\)
  • \(0b11111101_2 + 0b00000011_2\)
  • \(0b00011000_2 + 0b10011100_2\)

Soustraire les nombres binaires suivants et donner le résultat ainsi que l’état des flags V, N et Z :

  • \(0b10011000_2 - 0b10011000_2\)
  • \(0b11111101_2 - 0b00000011_2\)
  • \(0b00011000_2 - 0b10011100_2\)

Donner le résultat ainsi que l’état des flags V et N et Z pour les soustractions suivantes :

  • \(127 - (-125)\)
  • \(77 - (-26)\)
  • \(-30 - (-34)\)
  • \(55 - 66\)

Exercice 3 : Evaluation des flags

Pour les opérations suivantes, calculez :

  • l’état des flags N, Z, C et V
  • le résultat de l’opération si on interprète ce résultat comme un nombre signé
  • le résultat de l’opération si on interprète ce résultat comme un nombre non signé

On considère des nombres sur 8 bits.

  • \(128 - (-128)\)
  • \(64 + (-128)\)
  • \(228 - 128\)
  • \(240 - (-16)\)
  • \(0 - 0\)
  • \(-7 + 249\)
  • \(248 + (-128)\)
  • \(128 + 0\)
  • \(62 - 200\)
  • \(-8 - (-96)\)

Exercice 4 : CPU à Accumulateur

Dans un exercice précédent vous aviez dévéloppé une CPU à accumulateur permettant d’effectuer des opérations arithmetiques simples. A présent vous devrez l’étendre pour qu’elle soit capable de calculer les flags Z, C, N et V ainsi qu’afficher le résultat de l’opération sous forme signée et non-signée.

La classe doit avoir les éléments suivants :

  • Une variable membre représentant l’accumulateur occupant 32 bits.
  • Plusieurs variables représentant Z, C, N et V.
  • Des méthodes pour les opérations suivantes :
    • load (pour charger une valeur dans l’accumulateur),
    • add et subtract (pour effectuer ces opérations avec l’accumulateur et un autre opérande), et
    • store (pour stocker la valeur de l’accumulateur dans une variable donnée).
  • Une méthode display pour afficher la valeur actuelle de l’accumulateur, de la taille des registres, les valeurs maximales/minimales, les flags ainsi que le résultat (sous forme signée et non-signée).

Assurez-vous que votre classe encapsule correctement l’accumulateur et fournit des méthodes d’accès appropriées. Vous pouvez également inclure une fonction principale simple pour démontrer l’utilisation de votre classe AccumulatorCpu.

Exemple d’utilisation :

#include <stdio.h>
#include <stdint.h>

int main() {
    AccumulatorCpu acccpu(AccumulatorCpu::kRegister8bits);
    printf("\n=============================== \n");
    printf("Accumulator Computation results \n");
    printf("=============================== \n");
    acccpu.load(-7);
    acccpu.add(207);
    acccpu.display();

    uint32_t uintResult;
    acccpu.store(uintResult);

    return 0;
}
Dans cet exemple, la classe AccumulatorCpu est utilisée pour effectuer des opérations arithmétiques de base et stocker les résultats. Le résultat obtenu est le suivant :
=============================== 
Accumulator Computation results 
=============================== 
Accumulator value: 0x00c8
Flags: N=1, Z=0, C=1, V=0
Accumulator value is (uint) : 200
Accumulator value is (int) : -56
Register Size = 8, Max Unsigned Value = 255, Max Signed Value = 127, Min Signed Value = -128

Ci-dessous vous trouverez une base avec laquelle vous pourrez démarrer votre implémentation.

class AccumulatorCpu {

public:
    /* The supported register widths are 8 and 16 bits */
    enum regSize {kRegister8bits = 8, kRegister16bits = 16};

    AccumulatorCpu(regSize size) : accumulator(0), kMaxRegSize(size), 
                                   kUnsignMaxValue(1u << kMaxRegSize - 1), 
                                   kSignMaxValue ((1u << kMaxRegSize - 1) - 1), 
                                   kSignMinValue(-(1u << kMaxRegSize - 1))
    {}

    void load(uint32_t value) {
        accumulator = value;
        updateFlags();
    }

    void add(uint32_t value) {

        // Set carry flag (C) if overflow occurs (i.e., sum exceeds 255) for
        // 8-bit registers

        // Check for overflow (V) in signed addition

        accumulator = result;
        updateFlags();        
    }

    void substract(uint32_t value) {
        uint32_t unsigned_x      = unsignedValue(accumulator);
        uint32_t unsigned_y      = unsignedValue(value);
        uint32_t unsigned_result = unsignedValue(x - y);

        // Set carry flag (C) if no borrow occurs (i.e., result is non-negative)

        // Check for overflow (V) in signed subtraction

        accumulator = result;
        updateFlags();    

    }

    void store(uint32_t &target) const {
        target = accumulator;
    }

    void display() const {
        // You implementation here
    }
private:

    // Helper method to get the unsigned value in the 0-255 range (modulo 256)
    // for 8-bit registers
    uint32_t unsignedValue(uint32_t value) const {
        return value % kUnsignMaxValue;
    }

    // Helper method to get the signed value, wrapping into the -128 to 127 range for an 8-bit size
    int32_t signedValue(uint32_t value) const {
        return (value < kSignMaxValue) ? static_cast<int32_t>(value) : 
               static_cast<int32_t>(value) - kUnsignMaxValue;
    }

    void updateFlags() {
        // Update Zero flag (Z)
        Z = (accumulator == 0) ? 1 : 0;

        // Update Negative flag (N)
        N = (accumulator & 1 << (kMaxRegSize - 1)) ? 1 : 0;  // Check if the sign bit (bit 7) is set for 8-bit registers
    }

    uint32_t accumulator;
    const uint32_t kMaxRegSize;
    const uint32_t kUnsignMaxValue;
    const uint32_t kSignMaxValue;
    const int32_t  kSignMinValue;    
    bool N, Z, C, V;
    // whatever you need more...
};

Exercice 5 : Nombres réels

Représenter en hexadécimal sur 32 bits (simple précision) les valeurs réelles suivantes :

  • \(1\,048\,576\)
  • \(2048\)
  • \(55.75\)
  • \(5 \div 4096\)
  • \(-25 \div 2\)