VICE : Émulateur C64 sous Debian 13

Afin de préserver mon Commodore 64, j’ai installé l’émulateur VICE (version 3.9 sous Debian 13) : sudo apt-get install vice
Télécharger la ROM du C64 sur www.zimmers.net > Commodore > 8-bit Files > crossplatform > emulators > VICE > VICE 3.9 source code (vice-3.9.tar.gz).
Décompresser l’archive.

cd ~/Téléchargements
sudo cp -vR vice-3.9/data/* /usr/share/vice

Dans VICE, pour pouvoir sauvegarder ses programmes dans un répertoire personnel sous Debian, aller dans Preferences > Settings … > Peripheral devices > Drive puis cocher IEC Device. Dans Host file system Device, sélectionner le répertoire désiré en cliquant sur Browse. Puis cocher Save settings on exit.

Aide mémoire :
ALT D : Pour passer en plein écran et revenir en fenêtré.
ALT J : Pour inverser Joystick.
Pour lire un fichier .D64 :
Dans VICE, File > Attach disk image > Drive #8 > Choisir son fichier .D64 > Attach / Load
LOAD "*",8 puis éventuellement RUN.
RUN/STOP du C64 correspond à la touche ESC du PC.
Pour lire un fichier .TAP : LOAD

Commodore 64 : Guide de référence du programmeur


HELLO WORLD (1ère méthode)
Dans VICE, taper les lignes suivantes :

10 PRINT "HELLO WORLD"

Enregistrer le programme (le ,8 indique le lecteur de disquette – Drive 8):

SAVE "HELLO",8

Vider la mémoire de l’ordinateur :

NEW

Charger le programme, le lister et l’exécuter :

LOAD "HELLO",8
LIST
RUN

HELLO WORLD (2ème méthode) :
Passer par mon éditeur dans Debian (Geany) :

10 print "hello world"

C’est très important de tout taper en minuscules pour que la suite fonctionne correctement.

Dans la console :

petcat -w2 -o hello.prg -- hello.bas

Dans VICE :

LOAD "HELLO.PRG",8
RUN

Pour automatiser la compilation / l’exécution du fichier .bas dans Geany (je n’utilise pas FreeBasic) :

petcat -w2 -o "%e.prg" -- "%f"
x64sc "%e.prg"

Pour de la programmation en assembleur ACME (assembleur croisé multiplateforme pour les processeurs 6502/6510/65816):

sudo apt-get install acme

Pour automatiser la compilation / l’exécution du fichier .asm dans Geany (à la place de nasm) :

acme -f cbm -o "%e.prg" "%f"
x64sc "%e.prg"

; ============================================================
; Assembleur 6502/6510 pour Commodore 64
; Compilation : acme -f cbm -o hello.prg hello.asm
; ============================================================

; ------------------------------------------------------------
; Point d'entrée du programme (adresse $0801)
; ------------------------------------------------------------

* = $0801  ; Directive ACME (pas une instruction 6502) :
           ; place le code qui suit à l'adresse $0801,
           ; l'adresse standard où le C64 attend le début
           ; d'un programme BASIC (utilisée par LOAD/SAVE).

; ------------------------------------------------------------
; En-tête BASIC minimal, équivalent à la ligne : "10 SYS 2064"
; ------------------------------------------------------------

!byte $0c, $08, $0a, $00, $9e, $20, $32, $30, $36, $34, $00, $00, $00
            
; Résultat : un LIST sur ce mini-programme affiche "10 SYS 2064", et un RUN
; exécute cette ligne comme un SYS normal, qui saute en exécution machine
; à l'adresse 2064 (décimal) = $0810 (hexadécimal).

; ------------------------------------------------------------
; Code machine
; ------------------------------------------------------------

* = $0810  ; 2064 en décimal = $0810 : adresse ciblée par le
           ; SYS 2064 de l'en-tête ci-dessus. Entre $080d (fin
           ; de l'en-tête) et $0810, ACME insère automatiquement
           ; des octets de remplissage ($00), sans conséquence.

CHROUT = $FFD2  ; Routine KERNAL : afficher caractère

start:
        ldx #0         ; Initialise l'index x dans la chaine
loop:
        lda message,x  ; Charge le caractère
        beq done       ; Si caractère = 0, fin de chaîne
        jsr CHROUT     ; Affiche le caractère
        inx            ; Passe au caractère suivant
        jmp loop       ; Boucle
done:
        rts            ; Retour au BASIC

; ------------------------------------------------------------
; Données : la chaîne de caractères à afficher
; ------------------------------------------------------------

message:
        !text "HELLO WORLD"
        !byte 0

LIENS :

8-bit RetroProgramming : Chaine YouTube de Philippe Gianviti
RetroProgrammation : Chaine YouTube
Commodore Books
Demoscene TV – Playlist Commodore 64

Installation de l’émulateur NumWorks sous Debian

Article mis à jour le 08/07/2026

Télécharger et décompresser l’émulateur : https://www.numworks.com/fr/emulateur/graphique/telecharger/ (version 25.2.2)

À installer dans /home/$USER/.local/share/numworks/
$USER est à remplacer par un identifiant.

cd Téléchargements
wget https://entropie.org/3615/download/numworks.png

Fichier : /home/$USER/.local/share/applications/numworks.desktop
$USER est à remplacer par un identifiant (y compris ci-dessous).

[Desktop Entry]
Type=Application
Name=NumWorks
Comment=Calculatrice graphique
Exec=firefox /home/$USER/.local/share/numworks/numworks-graphing-emulator-25.2.2.html
Icon=/home/$USER/.local/share/numworks/numworks.png
Terminal=false
Categories=Education;
Hidden=false

Chiffrer un disque externe avec Debian

Attention, toutes les anciennes données seront effacées.
Le disque externe ne doit pour l’instant pas être monté.
Identifier le disque externe :

lsblk

Cela permet d’identifier le bon périphérique (/dev/sdb, /dev/sdc, etc.).
Le périphérique identifié est à utiliser ci-dessous.
Chiffrement avec LUKS :

sudo cryptsetup luksFormat /dev/sdX  (à adapter)
sudo cryptsetup luksOpen /dev/sdX disque_externe  (à adapter)
sudo dd if=/dev/zero of=/dev/mapper/disque_externe bs=64M status=progress
sudo mkfs.ext4 /dev/mapper/disque_externe

Après avoir répondu YES, il sera demandé une phrase secrète qui sera la clé du chiffrement.
Monter le disque externe :

udisksctl mount -b /dev/mapper/disque_externe

Pour récupérer le point de montage du disque externe dans une variable :

MOUNT=$(findmnt /dev/mapper/disque_externe -o TARGET -n)
echo "$MOUNT"

Le conteneur LUKS ne gère que le chiffrement. Une fois déverrouillé, le système de fichiers à l’intérieur conserve ses propriétaires et permissions. Pour voir le propriétaire (et le groupe) actuel :

ls -ld "$MOUNT"

On modifie le propriétaire (et le groupe) du système de fichiers monté :

sudo chown -R $USER:$USER "$MOUNT"
ls -ld "$MOUNT"

Démonter le disque externe :

udisksctl unmount -b /dev/mapper/disque_externe

Automatiser l’installation de logiciels sous Debian

Nom du fichier : install-paquets.sh
(autoriser l’exécution du fichier comme un programme)
Pour lancer le script : ./install-paquets.sh

#!/bin/bash
set -e

RED="\e[31m"
RESET="\e[0m"

# Mise à jour du système (Debian 13)
echo -e "${RED}Debian 13${RESET}"
echo -e "${RED}Mise à jour du système...${RESET}"
sudo apt-get update
sudo apt-get upgrade -y   # -y : ne pose pas de questions

# Installation des paquets supplémentaires
echo -e "${RED}Installation des paquets supplémentaires...${RESET}"
PAQUETS=(
#=================================================================
    # Accessoires
    gnome-disk-utility
    metadata-cleaner
    
    # Bureau
    pdfsam
    xournalpp
    
    # Graphisme
    inkscape
    xsane
    
    # Internet
    filezilla
    thunderbird thunderbird-l10n-fr
    chromium chromium-l10n
    
    # Outils système
    gparted
    hardinfo2
    gdebi
    
    # Programmation
    geany
    meld
    
    # Son et vidéo
    vlc
    
    # Préférences
    mozo
#==================================================================
)
sudo apt-get install -y "${PAQUETS[@]}"   # -y : ne pose pas de questions

# Nettoyage
echo -e "${RED}Nettoyage...${RESET}"
sudo apt-get autoremove -y   # -y : ne pose pas de questions
sudo apt-get autoclean

# Installation terminée
echo -e "${RED}Installation terminée !${RESET}"

Configuration de DOSBox-X

Dans la console :

nano ~/.config/dosbox-x/dosbox-x-2025.02.01.conf

à la ligne 217,

language                  = fr_FR.lng

à la ligne 1200,

keyboardlayout                  = auto => fr

à la ligne 501,

core               = auto => dynamic

à la ligne 506,

cycles             = auto => max

rajouter dans la section [autoexec], à la ligne 1349 :

mount c "/media/eric/Mes Fichiers/DOSBox-X" (à adapter)
c:
@ECHO OFF

### OPEN WATCOM 1.9 ###  (à installer)
# https://openwatcom.org/ftp/install/
SET WATCOM=C:\WATCOM
SET PATH=%WATCOM%\BINW;%PATH%
SET EDPATH=%WATCOM%\EDDAT
SET INCLUDE=%WATCOM%\H
REM SET LIB=
REM SET WWINHELP=D:\BINW

### NASM 3.02 ###  (à installer)
# https://www.nasm.us/pub/nasm/releasebuilds/3.02/
path=%path%;c:\nasm

### TURBO PASCAL 7.0 ###  (à installer)
# http://ftp-developpez.com/pascal/turbo-pascal/tp7.zip
path=%path%;c:\tp7\bin

à la ligne 236, (pour les captures écrans / vidéos / audios)

captures                  = capture => /media/eric/Mes Fichiers/DOSBox-X/Captures  (à adapter)

Découper et redimensionner une vidéo VirtualBox

Ma vidéo, enregistrée avec VirtualBox, est au format 1280×800 mais l’image est entourée de noir que je veux supprimer. La partie centrale qui m’intéresse est au format 640×400. Je fais donc un crop centré.

Pour automatiser (en Python) :
Usage : python3 convert.py input.webm 0 00:01:30

convert.py

import subprocess
import sys
import os

if len(sys.argv) < 4:
    print("Usage: python3 convert.py <input.webm> <start> <end>")
    print("Ex: python3 convert.py input.webm 0 00:01:30")
    sys.exit(1)

input_file = sys.argv[1]
start      = sys.argv[2]
end        = sys.argv[3]

output_name = "output"

# Filtre de crop/scale commun (la découpe se fait via -ss/-to en input)
# Remplacer "neighbor" par "lanczos" si la vidéo est réelle (non pixel art)
vf_base = "crop=640:400:320:200"
vf_hd   = "crop=640:400:320:200,scale=1280:800:flags=neighbor"

print("=== Export MP4 640x400 (H.264) ===")
subprocess.run([
    "ffmpeg",
    "-ss", start, "-to", end,
    "-i", input_file,
    "-vf", vf_base,
    "-c:v", "libx264",
    "-crf", "16",
    "-preset", "slow",
    "-pix_fmt", "yuv420p",
    "-c:a", "aac",
    "-b:a", "192k",
    "-movflags", "+faststart",
    f"{output_name}-640x400.mp4"
], check=True)

print("=== Export MP4 HD 1280x800 (H.264) ===")
subprocess.run([
    "ffmpeg",
    "-ss", start, "-to", end,
    "-i", input_file,
    "-vf", vf_hd,
    "-c:v", "libx264",
    "-crf", "10",
    "-preset", "veryslow",
    "-pix_fmt", "yuv420p",
    "-c:a", "aac",
    "-b:a", "192k",
    "-movflags", "+faststart",
    f"{output_name}-1280x800.mp4"
], check=True)

print("=== Export WEBM 640x400 (VP9) ===")
subprocess.run([
    "ffmpeg",
    "-ss", start, "-to", end,
    "-i", input_file,
    "-vf", vf_base,
    "-c:v", "libvpx-vp9",
    "-crf", "15",
    "-b:v", "0",
    "-c:a", "libopus",
    "-b:a", "192k",
    f"{output_name}-640x400.webm"
], check=True)

print("=== Export WEBM HD 1280x800 (VP9) ===")
subprocess.run([
    "ffmpeg",
    "-ss", start, "-to", end,
    "-i", input_file,
    "-vf", vf_hd,
    "-c:v", "libvpx-vp9",
    "-crf", "10",
    "-b:v", "0",
    "-deadline", "best",
    "-cpu-used", "0",
    "-c:a", "libopus",
    "-b:a", "192k",
    f"{output_name}-1280x800.webm"
], check=True)

print("=== Terminé ===")

Pour YouTube, il faut passer à 5120x3200 pour que la vidéo ne soit pas dégradée fortement.

convert5120.py

import subprocess
import sys
import os

if len(sys.argv) < 4:
    print("Usage: python3 convert5120.py <input.webm> <start> <end>")
    print("Ex: python3 convert5120.py input.webm 0 00:01:30")
    sys.exit(1)

input_file = sys.argv[1]
start      = sys.argv[2]
end        = sys.argv[3]

output_name = "output"

# Filtre de crop/scale commun (la découpe se fait via -ss/-to en input)
# Remplacer "neighbor" par "lanczos" si la vidéo est réelle (non pixel art)
vf_hd   = "crop=640:400:320:200,scale=5120:3200:flags=neighbor"

print("=== Export MP4 HD 5120x3200 (H.264) ===")
subprocess.run([
    "ffmpeg",
    "-ss", start, "-to", end,
    "-i", input_file,
    "-vf", vf_hd,
    "-c:v", "libx264",
    "-crf", "10",
    "-preset", "veryslow",
    "-pix_fmt", "yuv420p",
    "-c:a", "aac",
    "-b:a", "192k",
    "-movflags", "+faststart",
    f"{output_name}-5120x3200.mp4"
], check=True)

print("=== Terminé ===")

Afficher les connexions réseau actives et les ports ouverts sous Linux

ss -tulnp

La commande ss -tulnp est utilisée sous Linux pour afficher les connexions réseau actives et les ports ouverts sur sa machine. Voici ce que chaque option signifie :

-t : Affiche les connexions TCP.
-u : Affiche les connexions UDP.
-l : Affiche uniquement les ports en écoute (listening).
-n : Affiche les numéros de port au lieu de résoudre les noms de service (plus rapide).
-p : Affiche le processus (PID et nom) qui utilise le port.

À quoi ça sert ?

Vérifier quels ports sont ouverts sur sa machine.
Savoir quels services écoutent sur ces ports.
Identifier quel processus utilise un port (utile pour déboguer ou arrêter un service).
Diagnostiquer des problèmes réseau (ex : un service ne démarre pas à cause d’un port déjà utilisé).

Scanner son réseau local

Nom du fichier : ScanReseauLocal.sh

#!/bin/bash

# Si on n'est pas dans un terminal, se relancer dans mate-terminal
if ! [ -t 1 ]; then
    mate-terminal -- bash -c "sudo bash '$0'; exec bash"
    exit
fi

# =============================================================
#  ScanReseauLocal.sh — Scanner réseau local (Debian)
#  Dépendances : nmap       →  sudo apt install nmap
#  Optionnelles : avahi-utils →  sudo apt install avahi-utils (mDNS)
# =============================================================

# Utilisation :

# Scan automatique (détecte ton réseau tout seul)
# sudo ~/Bureau/ScanReseauLocal.sh

# Scan sur une plage personnalisée
# sudo ~/Bureau/ScanReseauLocal.sh 192.168.1.0/24

# Scan + ports ouverts d'un appareil précis
# sudo ~/Bureau/ScanReseauLocal.sh --ports 192.168.0.42

set -uo pipefail

# ── Couleurs ─────────────────────────────────────────────────
BOLD='\033[1m'
CYAN='\033[0;36m'
GREEN='\033[0;32m'
ORANGE='\033[38;5;214m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
NC='\033[0m'

# ── Vérifications préalables ─────────────────────────────────
check_deps() {
    local missing=()
    for cmd in nmap ip; do
        command -v "$cmd" &>/dev/null || missing+=("$cmd")
    done
    if [[ ${#missing[@]} -gt 0 ]]; then
        echo -e "${RED}Dépendances manquantes : ${missing[*]}${NC}"
        echo -e "Installe-les avec : ${ORANGE}sudo apt install nmap iproute2${NC}"
        exit 1
    fi

    # Avertissement si avahi-resolve manque
    if ! command -v avahi-resolve &>/dev/null; then
        echo -e "${YELLOW}⚠  avahi-resolve non installé : device name (mDNS) indisponible${NC}"
        echo -e "   ${ORANGE}sudo apt install avahi-utils${NC}"
        echo
    fi
}

# ── Détection automatique du réseau actif ────────────────────
detect_network() {
    local cidr
    cidr=$(ip -4 addr show scope global \
           | grep -oP '(?<=inet\s)\d+\.\d+\.\d+\.\d+/\d+' \
           | head -1)

    if [[ -z "$cidr" ]]; then
        echo -e "${RED}Impossible de détecter le réseau. Vérif ta connexion.${NC}"
        exit 1
    fi
    echo "$cidr"
}

# ── Résolution du device name via mDNS ───────────────────────
resolve_device_name() {
    local ip="$1"
    local name=""

    if command -v avahi-resolve &>/dev/null; then
        local mdns
        mdns=$(avahi-resolve -a "$ip" 2>/dev/null \
               | awk '{print $2}' \
               | sed 's/\.local\.$//')
        [[ -n "$mdns" ]] && name="$mdns (mDNS)"
    fi

    echo "$name"
}

# ── Scan principal ───────────────────────────────────────────
scan_network() {
    local cidr="$1"

    echo
    echo -e "${BOLD}${CYAN}══════════════════════════════════════════${NC}"
    echo -e "${BOLD}${CYAN}   🔍  SCAN RÉSEAU LOCAL                  ${NC}"
    echo -e "${BOLD}${CYAN}══════════════════════════════════════════${NC}"
    echo -e "  Plage cible : ${ORANGE}${cidr}${NC}"
    echo -e "  Démarré le  : $(date '+%d/%m/%Y %H:%M:%S')"
    echo -e "${BOLD}${CYAN}══════════════════════════════════════════${NC}"
    echo

    local raw
    raw=$(sudo nmap -sn -T4 \
        -PE -PP \
        -PS21,22,23,25,80,443,445,3389,8080 \
        -PA80,443 \
        -PR \
        "$cidr" 2>/dev/null)

    local count=0

    while IFS= read -r line; do
        if [[ "$line" =~ ^"Nmap scan report for " ]]; then
            local host="${line#Nmap scan report for }"
            local ip hostname
            local regex='\(([^)]+)\)$'
            if [[ "$host" =~ $regex ]]; then
                hostname="${host%% (*}"
                ip="${BASH_REMATCH[1]}"
            else
                ip="$host"
                hostname=""
            fi

            local mac vendor mac_line
            mac_line=$(echo "$raw" | grep -A3 "^Nmap scan report for ${host}$" \
                        | grep "MAC Address" || true)
            if [[ -n "$mac_line" ]]; then
                mac=$(echo "$mac_line" | awk '{print $3}')
                vendor=$(echo "$mac_line" | sed 's/.*(\(.*\))/\1/')
            else
                mac="N/A (machine locale ou accès limité)"
                vendor=""
            fi

            # Résolution du device name
            local device_name
            device_name=$(resolve_device_name "$ip")

            count=$(( count + 1 ))
            echo -e "  ${BOLD}${GREEN}▸ Appareil #${count}${NC}"
            echo -e "    IP          : ${ORANGE}${ip}${NC}"
            [[ -n "$hostname" ]] && \
                echo -e "    Hostname    : ${CYAN}${hostname}${NC}"
            [[ -n "$device_name" ]] && \
                echo -e "    Device name : ${YELLOW}${device_name}${NC}"
            echo -e "    MAC         : ${mac}"
            [[ -n "$vendor" ]] && \
                echo -e "    Fabricant   : ${vendor}"
            echo
        fi
    done <<< "$raw"

    echo -e "${BOLD}${CYAN}══════════════════════════════════════════${NC}"
    echo -e "  ${BOLD}${GREEN}${count} appareil(s) détecté(s)${NC}"
    echo -e "${BOLD}${CYAN}══════════════════════════════════════════${NC}"
    echo
}

# ── Optionnel : scan de ports sur un appareil ────────────────
scan_ports() {
    local ip="$1"
    echo
    echo -e "${BOLD}${CYAN}── Scan des ports ouverts sur ${ip} ─────────${NC}"
    sudo nmap -T4 --open --top-ports 100 "$ip" 2>/dev/null \
        | grep -E "^[0-9]+/(tcp|udp)|Nmap scan" \
        | sed "s/^/  /"
    echo
}

# ── Point d'entrée ───────────────────────────────────────────
main() {
    check_deps

    local cidr="${1:-}"
    local port_ip=""

    while [[ $# -gt 0 ]]; do
        case "$1" in
            --ports)
                port_ip="${2:-}"
                shift 2
                ;;
            *)
                cidr="$1"
                shift
                ;;
        esac
    done

    [[ -z "$cidr" ]] && cidr=$(detect_network)

    scan_network "$cidr"

    if [[ -n "$port_ip" ]]; then
        scan_ports "$port_ip"
    fi
}

main "$@"

Un fichier bash à mettre sur son bureau pour accéder rapidement à un répertoire

Nom du fichier : Mon_Répertoire.sh
(autoriser l’exécution du fichier comme un programme)

#!/bin/bash

COMMANDES="
    cd '/media/$USER/Mon Répertoire'
    exec bash
"

# Si on n'est pas dans un terminal, se relancer dans mate-terminal
if ! [ -t 1 ]; then
    mate-terminal -- bash -c "$COMMANDES"
    exit
fi

# Si on est déjà dans un terminal, exécution directe
eval "$COMMANDES"

Un fichier bash à mettre sur son bureau pour une mise à jour rapide de Debian

Nom du fichier : MAJ.sh
(autoriser l’exécution du fichier comme un programme)

#!/bin/bash

# ON AFFICHE LE CONTENU DU SCRIPT PAR MESURE DE SÉCURITÉ

COMMANDES="
    cat '$0'
    echo
    sudo apt-get update && sudo apt-get upgrade -y
    sudo apt-get autoremove -y && sudo apt-get autoclean
    exec bash
"

# Si on n'est pas dans un terminal, se relancer dans mate-terminal
if ! [ -t 1 ]; then
    mate-terminal -- bash -c "$COMMANDES"
    exit
fi

# Si on est déjà dans un terminal, exécution directe
eval "$COMMANDES"