giovedì 16 maggio 2019

Mandelbrot mat intera e shift bit

Questo e' un lavoro intermedio per vedere se riesco a ricreare l'insieme di Mandelbrot in Assembly x86 senza utilizzare i comandi del coprocessore matematico (come per esempio qui) ed utilizzando per le moltiplicazione e divisioni le operazioni di shift dei bit





Per prima cosa il moltplicatore e' impostato come una potenza di due (nell'esempio come 2^7)
Cio' permette di evitare il piu' possibile  moltiplicazioni e divisioni che possono essere sostituite da shift a destra per la divisione e shift a sinistra per la moltiplicazione (tipicamente per moltiplicare e dividere un numero per due e' sufficiente effettuare lo shift dei bit di una posizione)

Un altro trucco e' quello di utilizzare una tabella precalcolata dei quadrati dei primi 700 numeri.
Per la matrice deve essere gestita anche la possibilita' dei quadranti negativi... per simulare il comando abs di C e' stato usato il bit shit con la seguente formula

 int x_abs = (x^(x>>31))-(x>>31);



---------------------------------------------------------------------
#include <SDL/SDL.h>
#include <math.h>

#define SCREEN_WIDTH 159
#define SCREEN_HEIGHT 99

#define SCREEN_DEPTH 8

unsigned char iterazioni = 15; //byte
unsigned char keypress = 0; //byte
unsigned char k; //byte

short int a,b,nx,ny;  // dimensione word 16 bit
int t,limite,x,y;     // 32 bit

unsigned short int i,j,de,di; // dimensione word 16 bit

unsigned int inizio,fine = 0;

int main ()
{
SDL_Surface *screen;
Uint8  *p;


SDL_Init(SDL_INIT_VIDEO);
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, SDL_SWSURFACE);


//-------------------------------------------------------
unsigned int square[]={
0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100,
121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441,
484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024,
1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849,
1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916,
3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225,
4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776,
5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569,
7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604,
9801, 10000, 10201, 10404, 10609, 10816, 11025, 11236, 11449, 11664, 11881,
12100, 12321, 12544, 12769, 12996, 13225, 13456, 13689, 13924, 14161, 14400,
14641, 14884, 15129, 15376, 15625, 15876, 16129, 16384, 16641, 16900, 17161,
17424, 17689, 17956, 18225, 18496, 18769, 19044, 19321, 19600, 19881, 20164,
20449, 20736, 21025, 21316, 21609, 21904, 22201, 22500, 22801, 23104, 23409,
23716, 24025, 24336, 24649, 24964, 25281, 25600, 25921, 26244, 26569, 26896,
27225, 27556, 27889, 28224, 28561, 28900, 29241, 29584, 29929, 30276, 30625,
30976, 31329, 31684, 32041, 32400, 32761, 33124, 33489, 33856, 34225, 34596,
34969, 35344, 35721, 36100, 36481, 36864, 37249, 37636, 38025, 38416, 38809,
39204, 39601, 40000, 40401, 40804, 41209, 41616, 42025, 42436, 42849, 43264,
43681, 44100, 44521, 44944, 45369, 45796, 46225, 46656, 47089, 47524, 47961,
48400, 48841, 49284, 49729, 50176, 50625, 51076, 51529, 51984, 52441, 52900,
53361, 53824, 54289, 54756, 55225, 55696, 56169, 56644, 57121, 57600, 58081,
58564, 59049, 59536, 60025, 60516, 61009, 61504, 62001, 62500, 63001, 63504,
64009, 64516, 65025, 65536, 66049, 66564, 67081, 67600, 68121, 68644, 69169,
69696, 70225, 70756, 71289, 71824, 72361, 72900, 73441, 73984, 74529, 75076,
75625, 76176, 76729, 77284, 77841, 78400, 78961, 79524, 80089, 80656, 81225,
81796, 82369, 82944, 83521, 84100, 84681, 85264, 85849, 86436, 87025, 87616,
88209, 88804, 89401, 90000, 90601, 91204, 91809, 92416, 93025, 93636, 94249,
94864, 95481, 96100, 96721, 97344, 97969, 98596, 99225, 99856, 100489, 101124,
101761, 102400, 103041, 103684, 104329, 104976, 105625, 106276, 106929, 107584, 108241,
108900, 109561, 110224, 110889, 111556, 112225, 112896, 113569, 114244, 114921, 115600,
116281, 116964, 117649, 118336, 119025, 119716, 120409, 121104, 121801, 122500, 123201,
123904, 124609, 125316, 126025, 126736, 127449, 128164, 128881, 129600, 130321, 131044,
131769, 132496, 133225, 133956, 134689, 135424, 136161, 136900, 137641, 138384, 139129,
139876, 140625, 141376, 142129, 142884, 143641, 144400, 145161, 145924, 146689, 147456,
148225, 148996, 149769, 150544, 151321, 152100, 152881, 153664, 154449, 155236, 156025,
156816, 157609, 158404, 159201, 160000, 160801, 161604, 162409, 163216, 164025, 164836,
165649, 166464, 167281, 168100, 168921, 169744, 170569, 171396, 172225, 173056, 173889,
174724, 175561, 176400, 177241, 178084, 178929, 179776, 180625, 181476, 182329, 183184,
184041, 184900, 185761, 186624, 187489, 188356, 189225, 190096, 190969, 191844, 192721,
193600, 194481, 195364, 196249, 197136, 198025, 198916, 199809, 200704, 201601, 202500,
203401, 204304, 205209, 206116, 207025, 207936, 208849, 209764, 210681, 211600, 212521,
213444, 214369, 215296, 216225, 217156, 218089, 219024, 219961, 220900, 221841, 222784,
223729, 224676, 225625, 226576, 227529, 228484, 229441, 230400, 231361, 232324, 233289,
234256, 235225, 236196, 237169, 238144, 239121, 240100, 241081, 242064, 243049, 244036,
245025, 246016, 247009, 248004, 249001, 250000, 251001, 252004, 253009, 254016, 255025,
256036, 257049, 258064, 259081, 260100, 261121, 262144, 263169, 264196, 265225, 266256,
267289, 268324, 269361, 270400, 271441, 272484, 273529, 274576, 275625, 276676, 277729,
278784, 279841, 280900, 281961, 283024, 284089, 285156, 286225, 287296, 288369, 289444,
290521, 291600, 292681, 293764, 294849, 295936, 297025, 298116, 299209, 300304, 301401,
302500, 303601, 304704, 305809, 306916, 308025, 309136, 310249, 311364, 312481, 313600,
314721, 315844, 316969, 318096, 319225, 320356, 321489, 322624, 323761, 324900, 326041,
327184, 328329, 329476, 330625, 331776, 332929, 334084, 335241, 336400, 337561, 338724,
339889, 341056, 342225, 343396, 344569, 345744, 346921, 348100, 349281, 350464, 351649,
352836, 354025, 355216, 356409, 357604, 358801, 360000, 361201, 362404, 363609, 364816,
366025, 367236, 368449, 369664, 370881, 372100, 373321, 374544, 375769, 376996, 378225,
379456, 380689, 381924, 383161, 384400, 385641, 386884, 388129, 389376, 390625, 391876,
393129, 394384, 395641, 396900, 398161, 399424, 400689, 401956, 403225, 404496, 405769,
407044, 408321, 409600, 410881, 412164, 413449, 414736, 416025, 417316, 418609, 419904,
421201, 422500, 423801, 425104, 426409, 427716, 429025, 430336, 431649, 432964, 434281,
435600, 436921, 438244, 439569, 440896, 442225, 443556, 444889, 446224, 447561, 448900,
450241, 451584, 452929, 454276, 455625, 456976, 458329, 459684, 461041, 462400, 463761,
465124, 466489, 467856, 469225, 470596, 471969, 473344, 474721, 476100, 477481, 478864,
480249, 481636, 483025, 484416, 485809, 487204, 488601, 490000, 491401, 492804, 494209,
495616, 497025, 498436, 499849, 501264, 502681, 504100, 505521, 506944, 508369, 509796,
511225, 512656, 514089, 515524, 516961, 518400, 519841, 521284, 522729, 524176, 525625,
527076, 528529, 529984, 531441, 532900, 534361, 535824, 537289, 538756, 540225, 541696,
543169, 544644, 546121, 547600, 549081, 550564, 552049, 553536, 555025, 556516, 558009,
559504, 561001, 562500, 564001, 565504, 567009, 568516, 570025, 571536, 573049, 574564
};

  inizio = SDL_GetTicks();

  int bit = 7;

  a = -2<<bit;
  de = 2;
  di = 3;

  limite = 1<<(bit+2);

  for (i=0;i<SCREEN_WIDTH;i++)
  {
  a=a+de;
  b=-154;
  for (j=0;j<SCREEN_HEIGHT;j++)
    {
    b=b+di;
    x=0;
    y=0;
    for (k=1;k<iterazioni;k++)
        {
        int x_abs = (x^(x>>31))-(x>>31);
        int y_abs = (y^(y>>31))-(y>>31);
        nx = (square[x_abs]>>bit) - (square[y_abs]>>bit) + a;

        y = ((x*y)>>(bit-1))+b;

        int nx_abs = (nx^(nx>>31))-(nx>>31);
        y_abs = (y^(y>>31))-(y>>31);
        t = (square[nx_abs]>>bit) + (square[y_abs]>>bit);
        //t = (square[abs(nx)]>>bit) + (square[abs(y)]>>bit);
        //t = (nx*nx>>bit) + (y*y>>bit);
        if (t>limite)
            {
            //plot
            p = (Uint8 *)screen->pixels + j * screen->pitch + i * screen->format->BytesPerPixel;
            *p=255;
            k =26;
            }
        x=nx;
        }
  }
}
SDL_Flip(screen);

fine = SDL_GetTicks();
printf("Esecuzione 5: %d\n", fine-inizio);

bool done=false;
while (!done)
    {
        // message processing loop
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
            case SDL_QUIT:
                done = true;
                break;
            case SDL_KEYDOWN:
                {
                    // exit if ESCAPE is pressed
                    if (event.key.keysym.sym == SDLK_ESCAPE)
                        done = true;
                    break;
                }
            } // end switch
        } // end of message proc
}
//---------------------------------------------

SDL_Quit();

return(0);
}


martedì 7 maggio 2019

Pdf ed Audiveris

Audiveris riesce ad importare in modo nativo i file pdf ma spesso ha problemi con le risoluzioni al di sotto dei 300 dpi



Un trucco e' quello di usare ImageMagick per convertire il pdf in png forzando una risoluzione di 300 dpi (anche se non e' nativa)

convert -density 300 ArchieGeneAmmonsC.pdf -quality 90 ArchieGeneAmmonsC300.png

sabato 4 maggio 2019

Commodore 64 Multi Diagnostic Card

Per imparare un po' di hardware Commodore 64 mi sono comprato su Ebay u C64 biscottone dichiarato come non funzionante. Per rendermi la vita un po' piu' facile mi sono comprato una scheda di diagnostica con montate 5 ROM selezionabili via switch



Il C64 acquistato e' effettivamente rotto e mostra schermo nero...il problema e' che pur inserendo la scheda diagnostica lo schermo rimane nero.
Ho preso quindi il mio C64 funzionante ......ed ho avuto una pessima notizia...la scheda di diagnostica mostra una seria di problemi sui due CIA (U1 ed U2) e sul SID (U18)

I CIA servono all'IO del computer e quindi cio' giustifica problema sulla cassetta, sulle control port e sulla seriale (oltre che sull'interrupt perche' i CIA gestiscono l'interrupt)....il SID e' inutile che descriva a cio' che serve









venerdì 3 maggio 2019

OCR di spartiti con Audiveris su Debian Testing

Per evitare di scrivere a mano gli spartiti con Musescore un sistema comodo (dopo essere riusciti ad installarlo....) e' quello di usare Audiveris come OCR musicale



il primo problema che si pone e' che Audiveris 5 non risulta compatibile con Tesseract 4 (la cosa e' subdola perche' Audiveris sembra funzionare ma di fatto non genera file di esportazione)
Per prima cosa si deve quindi compilare dai sorgenti Tesseract 3 partendo dalla dipendenza con la libreria Leptonica che si scarica da qui
./configure
./make
./make install
./ldconfig

si passa quindi a compilare Tesseract

git clone https://github.com/tesseract-ocr/tesseract.git
git checkout 3.04
./configure
./make
./make install
./make training
./make training-install

non e' finita...perche' devono essere aggiunti i file delle lingue (che sono differenti tra la versione 3 e la 4!!!!) e che si scaricano da qui. Io ho aggiunto solo l'inglese eng.traineddata

a questo punto si inizia l'installazione di Audiveris

git clone https://github.com/Audiveris/audiveris.git

attenzione: per usare OpenJDK 11 si deve fare il checkout del ramo Java11 altrimenti si deve usare JDK 7 od 8

git checkout java11

si lancia quindi il programma Audiveris indicando dove si trovano i file di training della lingua

TESSDATA_PREFIX=/home/luca/tesseract/tessdata/ ./gradlew run

Si carica quindi il file immagine di uno spartito, si clicca la doppia freccia blue (oppure Book/Transcribe Book) ed infine Book/Export Books As per salvare in formato mxl (Music XML)

A questo punto si puo' aprire Musescore ed importare il file e correggere eventuali problemi di interpretazione del software




giovedì 2 maggio 2019

4x4 Keypad su Arduino

Per connettere un keypad 4x4 ad una Arduino sono necessari 8 cavi di collegamento. In questo caso il pin piu' a sinistra del connettore della tasteria (colore blu) si collega al pin D9 di Arduino e cosi' via scendendo via al pin D2




http://osoyoo.com/2017/09/arduino-lesson-4x4-matrix-keypad/

---------------------------------------------------------------
#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
 {'1', '2', '3', 'A'},
 {'4', '5', '6', 'B'},
 {'7', '8', '9', 'C'},
 {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {9,8,7,6};//righe
byte colPins[COLS] = {5,4,3,2}; //colonne

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );


void setup(){
  Serial.begin(9600);
}
  
void loop(){
  char key = keypad.getKey();
  
  if (key){
    Serial.println(key);
  }
}

Oled 128x32 Display 0.91 Inch I2C

Mi sono comprato uno schermo Oled da circa un pollice che era venduto come un SSD1306 mentre in commenti su Amazon indicavano di usare la libreria U8G2

Usando lo sketch ssd1306-128x32_i2c degli esempi di Adafruit_SSD1306 il display funziona perfettamente


ma lo stesso si puo' dire se si usa la libreria U8G2
--------------------------------------------------------------------------------
#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
#include <Wire.h>

U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0); 

 void setup(void) {
   u8g2.begin();
   //u8g2.clear();
   u8g2.clearBuffer();
   u8g2.drawPixel(0,0);
   u8g2.drawPixel(127,31);
   u8g2.sendBuffer();
   delay(3000);
   u8g2.clearBuffer();         
   u8g2.setFont(u8g2_font_logisoso28_tr);  
   u8g2.drawStr(8,29,"Luca"); 
   u8g2.sendBuffer();         
   delay(3000);
}

  void loop(void) {
}




Emulatore CHIP-8 su Arduino Mega

Partendo dal precedente post ho portato il codice su Arduino

Per il progetto ho usato una Arduino Mega con un schermo Oled 0.91" di 128x32 pixels (il CHIP-8 aveva uno schermo 64x32 monocromatico basato su U8G2) ed un keypad a 16 pulsanti (CHIP-8 gestiva una tastiera a 16 tasti)






il primo passo e' stato quello di usare la classe chip8 per creare una libreria Arduino.
Si crea un sottodirectory chip8 in /libraries e si creano i file chip8.cpp e chip8.h

Rispetto alla versione NCurses sono stati rimossi dei comandi che hanno riscontro in Arduino (per esempio iostream o sizeof ) Credits James Griffin

chip8.cpp
-----------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
//#include <iostream>
//#include <random>
#include "time.h"


#include "chip8.h"

unsigned char chip8_fontset[80] =
{
    0xF0, 0x90, 0x90, 0x90, 0xF0, //0
    0x20, 0x60, 0x20, 0x20, 0x70, //1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, //2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, //3
    0x90, 0x90, 0xF0, 0x10, 0x10, //4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, //5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, //6
    0xF0, 0x10, 0x20, 0x40, 0x40, //7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, //8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, //9
    0xF0, 0x90, 0xF0, 0x90, 0x90, //A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, //B
    0xF0, 0x80, 0x80, 0x80, 0xF0, //C
    0xE0, 0x90, 0x90, 0x90, 0xE0, //D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, //E
    0xF0, 0x80, 0xF0, 0x80, 0x80  //F
};



Chip8::Chip8() {}
Chip8::~Chip8() {}

// Initialise
void Chip8::init() {
    pc      = 0x200;    // Set program counter to 0x200
    opcode  = 0;        // Reset op code
    I     = 0;          // Reset I
    sp      = 0;        // Reset stack pointer

    // Clear the display
    for (int i = 0; i < 2048; ++i) {
        gfx[i] = 0;
    }

    // Clear the stack, keypad, and V registers
    for (int i = 0; i < 16; ++i) {
        stack[i]    = 0;
        key[i]      = 0;
        V[i]        = 0;
    }

    // Clear memory
    for (int i = 0; i < 4096; ++i) {
        memory[i] = 0;
    }

    // Load font set into memory
    for (int i = 0; i < 80; ++i) {
        memory[i] = chip8_fontset[i];
    }

    // Reset timers
    delay_timer = 0;
    sound_timer = 0;

    // Seed rng
    srand (time(NULL));
}

// Initialise and load ROM into memory
bool Chip8::load(unsigned char programma[],int size) {
    // Initialise
    init();

    //long rom_size = sizeof(programma);
    int rom_size = size;
    // Copy buffer to memory
    if ((4096-512) > rom_size){
        for (int i = 0; i < rom_size; ++i) {
            memory[i + 512] = (uint8_t)programma[i];   // Load into memory starting
                                                        // at 0x200 (=512)
        }
    }
    else {
        //std::cerr << "ROM too large to fit in memory" << std::endl;
        return false;
    }

    return true;
}

// Emulate one cycle
void Chip8::emulate_cycle() {

    // Fetch op code
    opcode = memory[pc] << 8 | memory[pc + 1];   // Op code is two bytes

    switch(opcode & 0xF000){

        // 00E_
        case 0x0000:

            switch (opcode & 0x000F) {
                // 00E0 - Clear screen
                case 0x0000:
                    for (int i = 0; i < 2048; ++i) {
                        gfx[i] = 0;
                    }
                    drawFlag = true;
                    pc+=2;
                    break;

                // 00EE - Return from subroutine
                case 0x000E:
                    --sp;
                    pc = stack[sp];
                    pc += 2;
                    break;

                default:
                    //printf("\nUnknown op code: %.4X\n", opcode);
                    exit(3);
            }
            break;

        // 1NNN - Jumps to address NNN
        case 0x1000:
            pc = opcode & 0x0FFF;
            break;

        // 2NNN - Calls subroutine at NNN
        case 0x2000:
            stack[sp] = pc;
            ++sp;
            pc = opcode & 0x0FFF;
            break;

        // 3XNN - Skips the next instruction if VX equals NN.
        case 0x3000:
            if (V[(opcode & 0x0F00) >> 8] == (opcode & 0x00FF))
                pc += 4;
            else
                pc += 2;
            break;

        // 4XNN - Skips the next instruction if VX does not equal NN.
        case 0x4000:
            if (V[(opcode & 0x0F00) >> 8] != (opcode & 0x00FF))
                pc += 4;
            else
                pc += 2;
            break;

        // 5XY0 - Skips the next instruction if VX equals VY.
        case 0x5000:
            if (V[(opcode & 0x0F00) >> 8] == V[(opcode & 0x00F0) >> 4])
                pc += 4;
            else
                pc += 2;
            break;

        // 6XNN - Sets VX to NN.
        case 0x6000:
            V[(opcode & 0x0F00) >> 8] = opcode & 0x00FF;
            pc += 2;
            break;

        // 7XNN - Adds NN to VX.
        case 0x7000:
            V[(opcode & 0x0F00) >> 8] += opcode & 0x00FF;
            pc += 2;
            break;

        // 8XY_
        case 0x8000:
            switch (opcode & 0x000F) {

                // 8XY0 - Sets VX to the value of VY.
                case 0x0000:
                    V[(opcode & 0x0F00) >> 8] = V[(opcode & 0x00F0) >> 4];
                    pc += 2;
                    break;

                // 8XY1 - Sets VX to (VX OR VY).
                case 0x0001:
                    V[(opcode & 0x0F00) >> 8] |= V[(opcode & 0x00F0) >> 4];
                    pc += 2;
                    break;

                // 8XY2 - Sets VX to (VX AND VY).
                case 0x0002:
                    V[(opcode & 0x0F00) >> 8] &= V[(opcode & 0x00F0) >> 4];
                    pc += 2;
                    break;

                // 8XY3 - Sets VX to (VX XOR VY).
                case 0x0003:
                    V[(opcode & 0x0F00) >> 8] ^= V[(opcode & 0x00F0) >> 4];
                    pc += 2;
                    break;

                // 8XY4 - Adds VY to VX. VF is set to 1 when there's a carry,
                // and to 0 when there isn't.
                case 0x0004:
                    V[(opcode & 0x0F00) >> 8] += V[(opcode & 0x00F0) >> 4];
                    if(V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode & 0x0F00) >> 8]))
                        V[0xF] = 1; //carry
                    else
                        V[0xF] = 0;
                    pc += 2;
                    break;

                // 8XY5 - VY is subtracted from VX. VF is set to 0 when
                // there's a borrow, and 1 when there isn't.
                case 0x0005:
                    if(V[(opcode & 0x00F0) >> 4] > V[(opcode & 0x0F00) >> 8])
                        V[0xF] = 0; // there is a borrow
                    else
                        V[0xF] = 1;
                    V[(opcode & 0x0F00) >> 8] -= V[(opcode & 0x00F0) >> 4];
                    pc += 2;
                    break;

                // 0x8XY6 - Shifts VX right by one. VF is set to the value of
                // the least significant bit of VX before the shift.
                case 0x0006:
                    V[0xF] = V[(opcode & 0x0F00) >> 8] & 0x1;
                    V[(opcode & 0x0F00) >> 8] >>= 1;
                    pc += 2;
                    break;

                // 0x8XY7: Sets VX to VY minus VX. VF is set to 0 when there's
                // a borrow, and 1 when there isn't.
                case 0x0007:
                    if(V[(opcode & 0x0F00) >> 8] > V[(opcode & 0x00F0) >> 4]) // VY-VX
                        V[0xF] = 0; // there is a borrow
                    else
                        V[0xF] = 1;
                    V[(opcode & 0x0F00) >> 8] = V[(opcode & 0x00F0) >> 4] - V[(opcode & 0x0F00) >> 8];
                    pc += 2;
                    break;

                // 0x8XYE: Shifts VX left by one. VF is set to the value of
                // the most significant bit of VX before the shift.
                case 0x000E:
                    V[0xF] = V[(opcode & 0x0F00) >> 8] >> 7;
                    V[(opcode & 0x0F00) >> 8] <<= 1;
                    pc += 2;
                    break;

                default:
                    //printf("\nUnknown op code: %.4X\n", opcode);
                    exit(3);
            }
            break;

        // 9XY0 - Skips the next instruction if VX doesn't equal VY.
        case 0x9000:
            if (V[(opcode & 0x0F00) >> 8] != V[(opcode & 0x00F0) >> 4])
                pc += 4;
            else
                pc += 2;
            break;

        // ANNN - Sets I to the address NNN.
        case 0xA000:
            I = opcode & 0x0FFF;
            pc += 2;
            break;

        // BNNN - Jumps to the address NNN plus V0.
        case 0xB000:
            pc = (opcode & 0x0FFF) + V[0];
            break;

        // CXNN - Sets VX to a random number, masked by NN.
        case 0xC000:
            V[(opcode & 0x0F00) >> 8] = (rand() % (0xFF + 1)) & (opcode & 0x00FF);
            pc += 2;
            break;

        // DXYN: Draws a sprite at coordinate (VX, VY) that has a width of 8
        // pixels and a height of N pixels.
        // Each row of 8 pixels is read as bit-coded starting from memory
        // location I;
        // I value doesn't change after the execution of this instruction.
        // VF is set to 1 if any screen pixels are flipped from set to unset
        // when the sprite is drawn, and to 0 if that doesn't happen.
        case 0xD000:
        {
            unsigned short x = V[(opcode & 0x0F00) >> 8];
            unsigned short y = V[(opcode & 0x00F0) >> 4];
            unsigned short height = opcode & 0x000F;
            unsigned short pixel;

            V[0xF] = 0;
            for (int yline = 0; yline < height; yline++)
            {
                pixel = memory[I + yline];
                for(int xline = 0; xline < 8; xline++)
                {
                    if((pixel & (0x80 >> xline)) != 0)
                    {
                        if(gfx[(x + xline + ((y + yline) * 64))] == 1)
                        {
                            V[0xF] = 1;
                        }
                        gfx[x + xline + ((y + yline) * 64)] ^= 1;
                    }
                }
            }

            drawFlag = true;
            pc += 2;
        }
            break;

        // EX__
        case 0xE000:

            switch (opcode & 0x00FF) {
                // EX9E - Skips the next instruction if the key stored
                // in VX is pressed.
                case 0x009E:
                    if (key[V[(opcode & 0x0F00) >> 8]] != 0)
                        pc +=  4;
                    else
                        pc += 2;
                    break;

                // EXA1 - Skips the next instruction if the key stored
                // in VX isn't pressed.
                case 0x00A1:
                    if (key[V[(opcode & 0x0F00) >> 8]] == 0)
                        pc +=  4;
                    else
                        pc += 2;
                    break;

                default:
                    //printf("\nUnknown op code: %.4X\n", opcode);
                    exit(3);
            }
            break;

        // FX__
        case 0xF000:
            switch(opcode & 0x00FF)
            {
                // FX07 - Sets VX to the value of the delay timer
                case 0x0007:
                    V[(opcode & 0x0F00) >> 8] = delay_timer;
                    pc += 2;
                    break;

                // FX0A - A key press is awaited, and then stored in VX
                case 0x000A:
                {
                    bool key_pressed = false;

                    for(int i = 0; i < 16; ++i)
                    {
                        if(key[i] != 0)
                        {
                            V[(opcode & 0x0F00) >> 8] = i;
                            key_pressed = true;
                        }
                    }

                    // If no key is pressed, return and try again.
                    if(!key_pressed)
                        return;

                    pc += 2;
                }
                    break;

                // FX15 - Sets the delay timer to VX
                case 0x0015:
                    delay_timer = V[(opcode & 0x0F00) >> 8];
                    pc += 2;
                    break;

                // FX18 - Sets the sound timer to VX
                case 0x0018:
                    sound_timer = V[(opcode & 0x0F00) >> 8];
                    pc += 2;
                    break;

                // FX1E - Adds VX to I
                case 0x001E:
                    // VF is set to 1 when range overflow (I+VX>0xFFF), and 0
                    // when there isn't.
                    if(I + V[(opcode & 0x0F00) >> 8] > 0xFFF)
                        V[0xF] = 1;
                    else
                        V[0xF] = 0;
                    I += V[(opcode & 0x0F00) >> 8];
                    pc += 2;
                    break;

                // FX29 - Sets I to the location of the sprite for the
                // character in VX. Characters 0-F (in hexadecimal) are
                // represented by a 4x5 font
                case 0x0029:
                    I = V[(opcode & 0x0F00) >> 8] * 0x5;
                    pc += 2;
                    break;

                // FX33 - Stores the Binary-coded decimal representation of VX
                // at the addresses I, I plus 1, and I plus 2
                case 0x0033:
                    memory[I]     = V[(opcode & 0x0F00) >> 8] / 100;
                    memory[I + 1] = (V[(opcode & 0x0F00) >> 8] / 10) % 10;
                    memory[I + 2] = V[(opcode & 0x0F00) >> 8] % 10;
                    pc += 2;
                    break;

                // FX55 - Stores V0 to VX in memory starting at address I
                case 0x0055:
                    for (int i = 0; i <= ((opcode & 0x0F00) >> 8); ++i)
                        memory[I + i] = V[i];

                    // On the original interpreter, when the
                    // operation is done, I = I + X + 1.
                    I += ((opcode & 0x0F00) >> 8) + 1;
                    pc += 2;
                    break;

                case 0x0065:
                    for (int i = 0; i <= ((opcode & 0x0F00) >> 8); ++i)
                        V[i] = memory[I + i];

                    // On the original interpreter,
                    // when the operation is done, I = I + X + 1.
                    I += ((opcode & 0x0F00) >> 8) + 1;
                    pc += 2;
                    break;

                default:
break;
                    //printf ("Unknown opcode [0xF000]: 0x%X\n", opcode);
            }
            break;

        default:
            //printf("\nUnimplemented op code: %.4X\n", opcode);
            exit(3);
    }


    // Update timers
    if (delay_timer > 0)
        --delay_timer;

    if (sound_timer > 0)
        if(sound_timer == 1);
            // TODO: Implement sound
        --sound_timer;

}
-----------------------------------------------------------------


chip8.h
-----------------------------------------------------------------
#ifndef CHIP_8_H
#define CHIP_8_H

#include <stdint.h>

class Chip8 {
private:
    uint16_t stack[16];                 // Stack
    uint16_t sp;                        // Stack pointer

    uint8_t memory[4096];               // Memory (4k)
    uint8_t V[16];                      // V registers (V0-VF)

    uint16_t pc;                        // Program counter
    uint16_t opcode;                    // Current op code
    uint16_t I;                         // Index register

    uint8_t delay_timer;                // Delay timer
    uint8_t sound_timer;                // Sound timer

    void init();

public:
    uint8_t  gfx[64 * 32];              // Graphics buffer
    uint8_t  key[16];                   // Keypad
    bool drawFlag;                      // Indicates a draw has occurred

    Chip8();
    ~Chip8();

    void emulate_cycle();               // Emulate one cycle
    bool load(unsigned char programma[],int size);   // Load application
};

#endif // CHIP_8_H
-----------------------------------------------------------------

chip8_pong.ino
-----------------------------------------------------------------
#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
#include <Wire.h>

#include <Keypad.h>


#include <chip8.h>

U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0); 


Chip8 chip8 = Chip8();

unsigned char prg[] =
{
    0x6A,0x02, 0x6B, 0x0C, 0x6C, 0x3F, 0x6D, 0x0C,
    0xA2,0xEA, 0xDA, 0xB6, 0xDC, 0xD6, 0x6E, 0x00,
    0x22,0xD4, 0x66, 0x03, 0x68, 0x02, 0x60, 0x60,
    0xF0,0x15, 0xF0, 0x07, 0x30, 0x00, 0x12, 0x1A,
    0xC7,0x17, 0x77, 0x08,

    0x69,0xFF, 0xA2, 0xF0, 0xD6, 0x71, 0xA2, 0xEA,
    0xDA,0xB6, 0xDC, 0xD6, 0x60, 0x01, 0xE0, 0xA1,
    0x7B,0xFE, 0x60, 0x04, 0xE0, 0xA1, 0x7B, 0x02,
    0x60,0x1F, 0x8B, 0x02, 0xDA, 0xB6, 0x60, 0x0C,
    0xE0,0xA1, 0x7D, 0xFE,

    0x60,0x0D, 0xE0, 0xA1, 0x7D, 0x02, 0x60, 0x1F,
    0x8D,0x02, 0xDC, 0xD6, 0xA2, 0xF0, 0xD6, 0x71,
    0x86,0x84, 0x87, 0x94, 0x60, 0x3F, 0x86, 0x02,
    0x61,0x1F, 0x87, 0x12, 0x46, 0x02, 0x12, 0x78,
    0x46,0x3F, 0x12, 0x82,

    0x47,0x1F, 0x69, 0xFF, 0x47, 0x00, 0x69, 0x01,
    0xD6,0x71, 0x12, 0x2A, 0x68, 0x02, 0x63, 0x01,
    0x80,0x70, 0x80, 0xB5, 0x12, 0x8A, 0x68, 0xFE,
    0x63,0x0A, 0x80, 0x70, 0x80, 0xD5, 0x3F, 0x01,
    0x12,0xA2, 0x61, 0x02,

    0x80,0x15, 0x3F, 0x01, 0x12, 0xBA, 0x80, 0x15,
    0x3F,0x01, 0x12, 0xC8, 0x80, 0x15, 0x3F, 0x01,
    0x12,0xC2, 0x60, 0x20, 0xF0, 0x18, 0x22, 0xD4,
    0x8E,0x34, 0x22, 0xD4, 0x66, 0x3E, 0x33, 0x01,
    0x66,0x03, 0x68, 0xFE,

    0x33,0x01, 0x68, 0x02, 0x12, 0x16, 0x79, 0xFF,
    0x49,0xFE, 0x69, 0xFF, 0x12, 0xC8, 0x79, 0x01,
    0x49,0x02, 0x69, 0x01, 0x60, 0x04, 0xF0, 0x18,
    0x76,0x01, 0x46, 0x40, 0x76, 0xFE, 0x12, 0x6C,
    0xA2,0xF2, 0xFE, 0x33,

    0xF2,0x65, 0xF1, 0x29, 0x64, 0x14, 0x65, 0x00,
    0xD4,0x55, 0x74, 0x15, 0xF2, 0x29, 0xD4, 0x55,
    0x00,0xEE, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80,0x00, 0x00, 0x00, 0x00, 0x00

};


const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
 {'1', '2', '3', 'A'},
 {'4', '5', '6', 'B'},
 {'7', '8', '9', 'C'},
 {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {9,8,7,6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5,4,3,2}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup() {
    Serial.begin(9600);
    u8g2.begin();
    chip8.load(prg,246); // non c'e' la funzione sizeof

}

void loop() {
  chip8.emulate_cycle();
  char key = keypad.getKey();
  if (key){
    for (int f=0; f<16; f++)
          {
            chip8.key[f] = 0; 
          }

    Serial.println(key);
    switch(key)
        {
          case '1':
            chip8.key[1]=1;
            break;
          case '4':
            chip8.key[4]=1;
            break;
          case '7':
            chip8.key[7]=1;
            break;
          case '*':
            chip8.key[10]=1;
            break;
      /////////////////////////////////////
          case '2':
            chip8.key[2]=1;
            break;
          case '5':
            chip8.key[5]=1;
            break;
          case '8':
            chip8.key[8]=1;
            break;
          case '0':
            chip8.key[0]=1;
            break;
      /////////////////////////////////////
          case '3':
            chip8.key[3]=1;
            break;
          case '6':
            chip8.key[6]=1;
            break;
          case '9':
            chip8.key[9]=1;
            break;
          case '#':
            chip8.key[11]=1;
            break;
      
      /////////////////////////////////////
          case 'A':
            chip8.key[12]=1;
            break;
          case 'B':
            chip8.key[13]=1;
            break;
          case 'C':
            chip8.key[14]=1;
            break;
          case 'D':
            chip8.key[15]=1;
            break;
          default:
            break;
            
        }
  }
  
  if (chip8.drawFlag) {
            chip8.drawFlag = false;
            u8g2.clearBuffer();
            for (int i = 0; i < 2048; ++i) {
                uint8_t pixel = chip8.gfx[i];
                int k = (int)i/64;
                int j = i%64;
                if (pixel == 1)
                {
                  //u8g2.clearBuffer();
                  u8g2.drawPixel(j,k);
                  
                  //move(k,j);
                  //addch(ACS_CKBOARD);
                }
            }
            //refresh();
            //u8g2.clearBuffer();
            u8g2.sendBuffer();
        }
   delay(2);
}

Debugger integrato ESP32S3

Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede  nell'ID USB della porta Jtag. Nel modulo...