MOS 6502 CPU emulator in C++

This is my C++ emulator of the MOS Technology 6502 CPU. The code emulates a fully functional 6502 CPU and it seems to be pretty fast too. Some minor tricks have been introduced to greatly reduce the overall execution time.

Interrupt and bus read/write operations are emulated as well.

Github repo: https://github.com/gianlucag/mos6502

6502-300x135

What’s a 6502???

Here a brief descrption: http://en.wikipedia.org/wiki/MOS_Technology_6502

Main features:

  • 100% coverage of legal opcodes
  • decimal mode implemented
  • read/write bus callback
  • jump table opcode selection

Still to implement

  • 100% cycle accuracy
  • illegal opcodes
  • hardware glitches, the known ones of course ūüôā

The emulator was extensively tested against this test suite:

https://github.com/Klaus2m5/6502_65C02_functional_tests

and in parallel emulation with fake6502 http://rubbermallet.org/fake6502.c

so expect nearly 100% compliance with the real deal… at least on the normal behavior: as I said stuff like illegal opcodes or hardware glitches are currently not implemented.

Why yet another 6502 emulator?
Just for fun :). This CPU (and its many derivatives) powered machines such as:

  • Apple II
  • Nintendo Entertainment system (NES)
  • Atari 2600
  • Commodore 64
  • BBC micro

and many other embedded devices still used today. You can use this emulator in your machine emulator project. However cycle accuracy is not yet implemented so mid-frame register update tricks cannot be reliably emulated.

Some theory behind emulators: emulator types
You can group all the CPU emulators out there in 4 main categories:

  • switch-case based
  • jump-table based
  • PLA or microcode emulation based
  • graph based

Graph based emulators are the most accurate as they emulate the connections between transistors inside the die of the CPU. They emulate even the unwanted glitches, known and still unknown. However the complexity of such emulators is non-linear with the number of transistors: in other word, you don’t want to emulate a modern Intel quad core using this approach!!!

for an example check this out: http://visual6502.org/JSSim/index.html

The PLA/microcode based are the best as they offer both speed and limited complexity. The switch-case based are the simpler ones but also the slowest: the opcode value is thrown inside a huge switch case which selects the code snippet to execute; compilers can optimize switch case to reach near O(log(n)) complexity but they hardly do it when dealing with sparse integers (like most of the CPU opcode tables).

Emulator features
My project is a simple jump-table based emulator: the actual value of the opcode (let’s say 0x80) is used to address a function pointer table, each entry of such table is a C++ function which emulates the behavior of the corresponding real instruction.

All the 13 addressing modes are emulated:

// addressing modes
uint16_t Addr_ACC(); // ACCUMULATOR
uint16_t Addr_IMM(); // IMMEDIATE
uint16_t Addr_ABS(); // ABSOLUTE
uint16_t Addr_ZER(); // ZERO PAGE
uint16_t Addr_ZEX(); // INDEXED-X ZERO PAGE
uint16_t Addr_ZEY(); // INDEXED-Y ZERO PAGE
uint16_t Addr_ABX(); // INDEXED-X ABSOLUTE
uint16_t Addr_ABY(); // INDEXED-Y ABSOLUTE
uint16_t Addr_IMP(); // IMPLIED
uint16_t Addr_REL(); // RELATIVE
uint16_t Addr_INX(); // INDEXED-X INDIRECT
uint16_t Addr_INY(); // INDEXED-Y INDIRECT
uint16_t Addr_ABI(); // ABSOLUTE INDIRECT

All the 151 opcodes are emulated. Since the 6502 CPU uses 8 bit to encode the opcode value it also has a lot of “illegal opcodes” (i.e. opcode values other than the designed 151). Such opcodes perform weird operations, write multiple registers at the same time, sometimes are the combination of two or more “valid” opcodes. Such illegals were used to enforce software copy protection or to discover the exact CPU type.

The illegals are not supported yet, so instead a simple NOP is executed.

Inner main loop
It’s a classic fetch-decode-execute loop:

while(start + n > cycles && !illegalOpcode)
{
   // fetch
   opcode = Read(pc++);

   // decode
   instr = InstrTable[opcode];

   // execute
   Exec(instr);
}

The next instruction (the opcode value) is retrieved from memory. Then it’s decoded (i.e. the opcode is used to address the instruction table) and the resulting code block is executed.

Public methods
The emulator comes as a single C++ class with five public methods:

  • mos6502(BusRead r, BusWrite w);
  • void NMI();
  • void IRQ();
  • void Reset();
  • void Run(uint32_t n);

mos6502(BusRead r, BusWrite w);

it’s the class constructor. It requires you to pass two external functions:

uint8_t MemoryRead(uint16_t address);
void MemoryWrite(uint16_t address, uint8_t value);
respectively to read/write from/to a memory location (16 bit address, 8 bit value). In such functions you can define your address decoding logic (if any) to address memory mapped I/O, external virtual devices and such.

void NMI();
triggers a Non-Mascherable Interrupt request, as done by the external pin of the real chip

void IRQ();
triggers an Interrupt ReQuest?, as done by the external pin of the real chip

void Reset();
performs an hardware reset, as done by the external pin of the real chip

void Run(uint32_t n);
It runs the CPU for the next ‘n’ machine instructions.

Links
Some useful stuff I used…

http://en.wikipedia.org/wiki/MOS_Technology_6502

http://www.6502.org/documents/datasheets/mos/

http://www.mdawson.net/vic20chrome/cpu/mos_6500_mpu_preliminary_may_1976.pdf

http://rubbermallet.org/fake6502.c

Telecomando universale per apricancelli a 433.92 MHz

Di recente ho dovuto comprare un set di telecomandi ¬†(parlo del telecomando universale, quelli ad autoapprendimento) per i cancelli di casa. La procedura di solito √® semplice, si prende il telecomando originale, lo si affianca a quello universale e si clona il segnale. Purtroppo nel mio caso non ha funzionato, probabilmente per una incompatibilit√† a livello di frequenze (433.92MHz degli universali e 433 MHz del’originale o viceversa). Il modello del telecomando originale √® Elvox ET2 ZX03.

Siccome i telecomandi originali Elvox sono alquanto costosi, una soluzione è stata quella di realizzare un circuito in grado di rendere comunque compatibili i cancelli con i telecomandi universali o qualsiasi altra marca di telecomandi. Questa soluzione richiede però la realizzazione di un circuito e non necessariamente potrebbe funzionare con altri tipi di telecomandi.

Ho trovato online invece¬†un’altra soluzione interessate,¬†per chi non avesse il tempo di realizzare il circuito da solo e che risolve in modo definitivo il problema legato alla duplicazione del telecomando, si chiama SHEDU

shedu

Si tratta di un prodotto che permette di usare lo smartphone in alternativa al telecomando.
Visto il costo equiparabile a quello di un paio di telecomandi e l’indubbia praticità, è una soluzione interessante sia per un uso personale che per le aziende.
Molto interessanti anche alcune funzioni aggiuntive come l’apertura per prossimità e la possibilità di condividere l’accesso ad altri utenti tramite l’app stessa in tutta sicurezza (utile ad esempio per concedere ai familiari la possibilità di aprire il cancello senza acquistare nuovi telecomandi).
Attualmente è in corso una promozione che permette di ottenere degli sconti sull’acquisto per chi si registra e condivide sui social tramite il link che vi viene inviato

SHEDU √® sicuramente la soluzione pi√Ļ pratica e risolve definitivamente il problema; per quanto riguarda invece la realizzazione di un circuito ad-hoc, occorrer√† prendere¬†un modulo ricevitore da collegare elettricamente al telecomando Elvox originale: il circuito riceve il segnale dai telecomandi universali e comanda il telecomando originale. Il telecomando originale a sua volta emette il segnale per i cancelli che quindi si aprono/chiudono come di consueto.

Il circuito scelto è RKAU2, un ricevitore con attacco molex in auto-apprendimento a 2 canali; è dotato di due relè non polarizzati (quindi semplici contatti) ideali per essere collegati ai 2 pulsanti del telecomando originale.

ricevitore

Il circuito ricevitore deve essere alimentato a 12V e non include l’antenna. L’alimentatore √® facilmente reperibile, qualsiasi 12V ad almeno 500mA va bene. Per l’antenna √® sufficiente un filo elettrico lungo esattamente 17.3 cm (la lunghezza d’onda a 433Mhz √® 69.3 cm, quindi 1/4 di lunghezza d’onda √® all’incirca 17.3 cm).

Questi sono i contatti del circuito ricevitore:

ricevitore_schema

I pulsanti P1 e P2 servono per la programmazione.

Ho quindi collegato il circuito ricevitore al telecomando, collegando tra loro i contatti dei 2 relè (CN1 e CN2) ai due pulsanti del telecomando Elvox originale. Sia il circuito ricevitore che il telecomando vengono alimentati dallo stessa fonte a 12V. Questo lo schema elettrico finale:

remote

Il circuito finale, una volta realizzati i collegamenti, si presenta cosi’:

20141002_084354

Il cavetto nero √® l’alimentazione, il filo in alto l’antenna. Il circuito a sinistra √® il telecomando Elvox originale, quello a destra il circuito ricevente.

Tutto l’insieme √® stato inserito in una cassetta plastica per esterni opportunamente alimentata. Programmando il circuito ricevente √® possibile aprire/chiudere i cancelli utilizzando qualsiasi telecomando (ovviamente compatibile con il ricevitore), da quelli universali ai cloni pi√Ļ economici.

In questo modo √® possibile comandare i cancelli sia con gli eventuali altri telecomandi originali (ne abbiamo sacrificato solo uno) che con i nuovi. In pi√Ļ non abbiamo dovuto modificare o sostituire i circuiti dei singoli motori dei cancelli.

MioComm – caricare tracce GPS sul ciclocomputer Mio 105 H/HC

MioComm √® un piccolo tool sviluppato in C# per l’importazione di tracce GPS arbitrarie (in formato Google Earth .kml) sul ciclocomputer Mio 105 H/HC. Le tracce importate possono poi essere ripercorse grazie alla modalit√† navi del Mio.

1348067046-Cyclo105_zoom

Ho deciso di sviluppare questo software per colmare quello che secondo me (e anche per molti altri utenti) √® il pi√Ļ grande difetto di questo dispositivo ossia l’impossibilit√† di importare tracce GPS esterne.

Il software originale a corredo permette infatti solo l’esportazione delle tracce dal Mio al computer, la loro pubblicazione sul network ¬†mioshare.com e la condivisione con gli altri utenti. I progettisti hanno dimenticato (?) o non hanno voluto prendere in considerazione il classico caso d’uso del GPS da bici: ¬†prendere una traccia GPS scaricata da internet, caricarla sul dispositivo e ripercorrerla.

Il tool è frutto di un lungo lavoro di reverse engineering del protocollo seriale di comunicazione, fortunatamente abbastanza semplice e lineare: il classico protocollo half-duplex (botta e risposta) con pacchetto della forma command+size+payload+crc

Screen shot 2014-09-14 at 12.44.47 AM

Il tool permette fondamentalmente 3 operazioni:

  • Importazione di una traccia GPS arbitraria in formato Google Earth .kml
  • Elenco delle tracce memorizzate nel dispositivo
  • Esportazione in formato .kml delle tracce memorizzate

Screen shot 2014-09-14 at 12.15.35 AM

L’utilizzo √® abbastanza semplice: basta collegare il Mio al PC tramite cavetto USB e premere “connect”. Il software inizier√† il discovery del device su tutte le porte COM presenti (virtuali USB e non) e poi scaricher√† e mostrer√† l’elenco delle tracce correntemente in memoria. Il tasto “export” permette di esportare un traccia (selezionata dall’elenco), il tasto “import” permette invece di importare una.

Download

Download link: MioComm_ver1.1

Per il corretto funzionamento del tool sono necessari i driver STMicroelectronics della porta seriale virtuale scaricabili qui.

Per il momento il tool supporta solo il formato .kml (e anche .kmz: basti sapere che un file .kmz non √® altro che una versione zippata di un kml). In futuro √® prevista l’introduzione del formato Garmin .gpx e l’esportazione dei parametri non GPS della traccia (velocit√†, potenza, cadenza, battiti etc..).

Per chiarimenti, bug dell’ultimo minuto o miglioramenti non esitate a contattarmi!

Protocollo seriale – pacchetto

Una breve descrizione del protocollo seriale di comunicazione, per le persone interessate. Il protocollo √® stato parizialmente reversato sniffando il traffico da e verso il Mio 105 H/HC. La comunicazione avviene ovviamente in half-duplex, il master (l’applicativo desktop) interroga il dispositivo, il dispositvo risponde. Se il dispositivo non risponde entro un certo timeout lo si considera assente o spento e la richiesta viene annullata. Ho notato alcune incongruenze nella codifica dei valori numerici, ad esempio il campo LENGTH e le coordinate GPS sono codificate big-endian mentre tutti gli altri valori numerici in little-endian.

A livello link il pacchetto si presenta nella classica forma CMD+LENGTH+PAYLOAD+CRC, pi√Ļ nello specifico:

packet

  • CMD: 1 byte, indica il codice comando del pacchetto.
  • L0 e L1, 2 byte in tutto. Indicano la dimensione del payload, espressa in bytes. Campo big-endian.
  • P0,P1…,PN-1: payload
  • CHECK: 1 byte. Non propriamente un codice ciclico CRC ma un semplice XOR di tutti i byte precedenti, escluso il byte CMD