Persatuan Arduino dan prosesor klasik


Retrocomputer datang dalam berbagai tingkat rewel. Beberapa puas dengan persaingan. Yang lain lebih suka FPGA, karena dengan demikian ternyata bukan persaingan, tetapi rekreasi. Akhirnya, sajikan prosesor ketiga.

Tetapi prosesor membutuhkan banyak hal untuk bekerja! Sekali lagi, dilema: mengambil chip nyata dari tahun yang sama, atau meletakkan semuanya di FPGA, meninggalkan prosesor di luar? Namun, mengapa FPGA diperlukan? Hidup penyatuan Arduino dan prosesor klasik!

Berikan Arduino Anda "otak kedua" dan membuatnya lebih pintar.

Sebuah mikroprosesor delapan bit yang benar menjalankan program, sementara Arduino mengemulasi ROM, RAM, dan periferal sederhana.

Desain periferal virtual di Arduino IDE, dan jalankan kode assembler pada mikroprosesor. Tidak perlu memasang sirkuit yang rumit dan mem-flash ROM paralel.

Mikroprosesor yang didukung: 6502, 6809 dan Z80 (18581), yang lain sedang dalam perjalanan.

Sebuah perisai dengan mikroprosesor tidak mengganggu menghubungkan perisai lain: dengan LCD, kartu memori, dll.

Selain bahasa self-assembly, Anda dapat mencoba menjalankan beberapa kode klasik pada mikroprosesor.

Benar, mikroprosesor akan beroperasi pada frekuensi yang sangat rendah - sekitar 95 kHz, nilai pastinya tergantung pada optimalisasi kode emulasi periferal.

Distribusi ruang alamat diatur secara program dalam sketsa. Mikroprosesor dapat dialokasikan dari 4 hingga 6 kB dari 8 kB RAM yang tersedia di Arduino Mega. ROM dapat mengalokasikan lebih dari 200 kB dari 256 yang tersedia.

Port serial Arduino Mega dapat meniru UART.

Sirkuit, gambar papan, file Gerber tersedia di bawah CC-BY-SA 4.0 di sini . Pada saat yang sama, ada persyaratan untuk melampirkan file README.md, karena berisi peringatan berikut:
Jangan hubungkan pelindung sampai sketsa emulasi perangkat diunggah! Jika tidak, mungkin mempersingkat jalur output mikroprosesor.
Ya, dan dalam sketsa itu sendiri, sesuatu perlu diulang dengan hati-hati untuk alasan yang sama.

Skema perangkat pada 6502:



Skema perangkat pada 6809:



Skema perangkat pada Z80:



Anda sudah dapat menjalankan:

Pada perangkat dengan 6502 - Apple I, Woz Monitor + ROM dengan BASIC

Pada perangkat dengan 6809 - Sebuah analog dari komputer buatan rumah Simon6809 dari pengembang yang sama, monitor pelatihan dengan assembler dan disassembler

Pada perangkat dengan Z80 - sejauh ini hanya tes gema port serial , memungkinkan Anda untuk memeriksa kinerja virtual 8251 (KR580VV51A).

Firmware untuk meniru periferal - di bawah lisensi MIT.

Deskripsi singkat tentang prinsip tindakan:

Ke 6502 perangkat

Ke perangkat pada 6809

Untuk perangkat pada Z80 - dalam persiapan.

Pengembang mencoba menjual perangkat, tetapi dengan pengiriman hanya di Amerika Serikat. Tidak ada alasan khusus untuk membeli, karena skema ini sangat sederhana, Anda dapat mengulanginya di selembar papan tempat memotong roti dalam satu jam.

Direncanakan untuk mengembangkan papan serupa di RCA1802, 68008, 8085 (182185), 8088 (181088). Tentang K1801BM1 tidak dikatakan, tetapi Anda dapat memberikan ide seperti itu kepada penulis.

File:

Ke perangkat pada 6502: instruksi perakitan , sablon sutra , diagram

Ke perangkat pada 6809: instruksi perakitan , sablon sutra , diagram

Ke perangkat pada Z80: instruksi perakitan , sablon sutra , diagram

Pertimbangkan interaksi perangkat Arduino dan 6502. Arduino secara berkala mengubah level input dari mikroprosesor yang dirancang untuk memasok pulsa clock dari nol ke satu dan sebaliknya. Pada setiap siklus, ia memeriksa apa yang terjadi pada jalur kontrol dan bus alamat, dan, tergantung pada situasinya, membaca informasi dari bus data atau mengirimkannya ke sana. Arduino juga dapat mengontrol jalur IRQ dan NMI, yang menyebabkan gangguan. Gambar tersebut menunjukkan jenis data dan arah transmisi mereka:



Korespondensi port Arduino dan output mikroprosesor dikonfigurasi dalam sketsa:

/* Digital Pin Assignments */ #define DATA_OUT PORTL #define DATA_IN PINL #define ADDR_H PINC #define ADDR_L PINA #define ADDR ((unsigned int) (ADDR_H << 8 | ADDR_L)) #define uP_RESET_N 38 #define uP_RW_N 40 #define uP_RDY 39 #define uP_SO_N 41 #define uP_IRQ_N 50 #define uP_NMI_N 51 #define uP_E 52 #define uP_GPIO 53 

Kami akan membagi masing-masing ukuran menjadi peristiwa berikut:

CLK mengubah status dari satu ke nol (tolak)
CLK dalam kondisi nol
CLK mengubah status dari satu ke nol (naik)
CLK dalam kondisi unit
CLK sekali lagi mengubah status dari satu ke nol ...

Apa yang terjadi selama masa transisi negara?

6502 menerima pulsa clock pada input CLK0, buffer mereka dan mengirimkannya ke dua output: CLK1 dan CLK2. Meskipun semua peristiwa dalam mikroprosesor terikat ke CLK1, kami menganggap bahwa penundaannya kecil, dan mereka terikat pada CLK0 - garis di mana mikroprosesor menerima pulsa clock dari Arduino. Dan sebut saja sinyal CLK saja.



1. CLK mengubah status dari satu ke nol.

2. Mikroprosesor mengeluarkan alamat baru ke bus alamat, dan sinyal sakelar antara membaca dan menulis ke keluaran R / W. Tapi dia belum siap untuk pertukaran data.

3. CLK masuk ke unit state, dan ini berarti bahwa pertukaran data telah dimulai. Jika ini adalah operasi baca, mikroprosesor mentransfer output bus data ke status input dan menerima data, dan jika operasi tulis, itu mentransfernya ke status output dan mengirim data. Dan sinyal R / W mengalihkan perangkat eksternal ke mode tulis atau baca, kebalikan dari kondisi mikroprosesor yang sesuai.

4. CLK pergi ke nol. Sekarang baik mikroprosesor maupun perangkat input-output tidak mengeluarkan apa pun ke bus data. Mikroprosesor dapat mengatur jalur bus data dan pin R / W ke status baru.

Penjelasan sederhana, dapat dimengerti oleh anak. Siapa yang tidak pernah berpikir tentang "intrik di balik layar" ini, jika ia hanya akan memprogram mikrokontroler. Bahkan di assembler.

Jika Anda perlu menghubungkan perangkat periferal Anda, ia harus memiliki waktu untuk menyiapkan data sebelum unit (waktu persiapan) muncul di jalur CLK, dan ketika unit ada di sana, jangan mengubahnya. Jika perangkat periferal tidak memiliki waktu untuk menyiapkan data saat CLK nol, atau mengubahnya ketika unit ada di sana, Anda akan bertanya-tanya dalam waktu lama mengapa kode Anda tidak berfungsi. Karena frekuensi clock mikroprosesor adalah sepuluh hingga lima belas kali lebih rendah dari frekuensi nominal, mudah untuk mematuhi persyaratan ini. Tapi itu perlu.

Jadi, Anda perlu "mengajar" Arduino untuk menghasilkan pulsa clock, terus menerus memeriksa apa yang terjadi pada alamat dan jalur R / W, dan berinteraksi dengan bus data yang sesuai. Untuk melakukan ini, sketsa menggunakan timer1 timer interrupt, yang menghasilkan pulsa dengan frekuensi 95 kHz. Arduino bekerja lebih cepat daripada mikroprosesor, dan karenanya, di antara jam-jamnya, ia berhasil membaca dan menyiapkan segalanya. Penting untuk memastikan bahwa setelah memodifikasi sketsa, kondisi ini terus terpenuhi.

Berikut adalah kutipan dari sketsa, yang menunjukkan bagaimana CLK berubah dari nol menjadi satu, dan apa yang terjadi selanjutnya:

 //////////////////////////////////////////////////////////////////// // Processor Control Loop //////////////////////////////////////////////////////////////////// // This is where the action is. // it reads processor control signals and acts accordingly. // ISR(TIMER1_COMPA_vect) { // Drive CLK high CLK_E_HIGH; // Let's capture the ADDR bus uP_ADDR = ADDR; if (STATE_RW_N) ////////////////////////////////////////////////////////////////// // HIGH = READ transaction { // uP wants to read so Arduino to drive databus to uP: DATA_DIR = DIR_OUT; // Check what device uP_ADDR corresponds to: // ROM? if ( (ROM_START <= uP_ADDR) && (uP_ADDR <= ROM_END) ) DATA_OUT = pgm_read_byte_near(rom_bin + (uP_ADDR - ROM_START)); else if ( (BASIC_START <= uP_ADDR) && (uP_ADDR <= BASIC_END) ) DATA_OUT = pgm_read_byte_near(basic_bin + (uP_ADDR - BASIC_START)); else // RAM? if ( (uP_ADDR <= RAM_END) && (RAM_START <= uP_ADDR) ) DATA_OUT = RAM[uP_ADDR - RAM_START]; else // 6821? if ( KBD <=uP_ADDR && uP_ADDR <= DSPCR ) { // KBD? if (uP_ADDR == KBD) { ... // handle KBD register } else // KBDCR? if (uP_ADDR == KBDCR) { ... // handle KBDCR register } else // DSP? if (uP_ADDR == DSP) { ... // handle DSP register } else // DSPCR? if (uP_ADDR == DSPCR) { ... // handle DSPCR register } } } else ////////////////////////////////////////////////////////////////// // R/W = LOW = WRITE { // RAM? if ( (uP_ADDR <= RAM_END) && (RAM_START <= uP_ADDR) ) RAM[uP_ADDR - RAM_START] = DATA_IN; else // 6821? if ( KBD <=uP_ADDR && uP_ADDR <= DSPCR ) { // KBD? if (uP_ADDR == KBD) { ... // handle KBD register } else // KBDCR? if (uP_ADDR == KBDCR) { ... // handle KBDCR register } else // DSP? if (uP_ADDR == DSP) { ... // handle DSP register } else // DSPCR? if (uP_ADDR == DSPCR) { ... // handle DSPCR register } } } //////////////////////////////////////////////////////////////// // We are done with this cycle. // one full cycle complete clock_cycle_count ++; // start next cycle CLK_E_LOW; // If Arduino was driving the bus, no need anymore. // natural delay for DATA Hold time after CLK goes low (t_HR) DATA_DIR = DIR_IN; } 

Alokasi ruang alamat dapat dilakukan dengan cara apa pun, dalam sketsa yang tidak dimodifikasi sama dengan di Apple 1 dengan 256 byte ROM, 8 kilobyte ROM untuk BASIC, 4 kilobyte RAM dan perangkat input-output 6821.

 // MEMORY LAYOUT // 4K MEMORY #define RAM_START 0x0000 #define RAM_END 0x0FFF byte RAM[RAM_END-RAM_START+1]; // ROMs (Monitor + Basic) #define ROM_START 0xFF00 #define ROM_END 0xFFFF #define BASIC_START 0xE000 #define BASIC_END 0xEFFF //////////////////////////////////////////////////////////////////// // Woz Monitor Code //////////////////////////////////////////////////////////////////// // PROGMEM const unsigned char rom_bin[] = { 0xd8, 0x58, 0xa0, 0x7f, 0x8c, 0x12, 0xd0, 0xa9, 0xa7, 0x8d, 0x11, 0xd0, ... 0x00, 0xff, 0x00, 0x00 }; // BASIC ROM starts at E000 PROGMEM const unsigned char basic_bin[] = { 0x4C, 0xB0, 0xE2, 0xAD, 0x11, 0xD0, 0x10, 0xFB, ... 0xE0, 0x80, 0xD0, 0x01, 0x88, 0x4C, 0x0C, 0xE0 }; 

RAM ditiru oleh array RAM byte [RAM_END-RAM_START + 1]. Dibutuhkan dua kata kunci PROGMEM sehingga isi dari emulasi ROM disimpan dalam memori flash mikrokontroler.

6821 cukup ditiru sehingga keyboard dan tampilan virtual bekerja melalui "terminal". Woz Monitor dan BASIC bekerja, itulah yang dicari penulis.

Untuk meniru perangkat periferal apa pun, Anda perlu membaca lembar datanya dengan hati-hati dan mencari tahu apa yang dimiliki register dan untuk apa mereka. Kemudahan emulasi terletak pada fleksibilitas yang dengannya Anda dapat membuat analog perangkat lunak periferal.

Perangkat I / O terletak di ruang alamat mikroprosesor, mereka diakses dengan cara yang sama seperti sel memori. Untuk menggunakan periferal "besi", seperti layar LCD, kartu memori, output suara, Anda perlu mengalokasikan tempat di ruang alamat.

Referensi:

www.6502.org
www.callapple.org/soft/ap1/emul.html
skilldrick.imtqy.com/easy6502
searle.hostei.com/grant/6502/Simple6502.html
wilsonminesco.com/6502primer
SB-Assembler: www.sbprojects.net/sbasm

Pergi ke 6809, ini berisi:

Dua baterai delapan-bit A dan B, yang dapat digabungkan menjadi satu baterai enam-bit
Dua indeks tumpukan 16-bit
Mengatasi relatif ke konter instruksi
Secara otomatis menambah atau mengurangi 1 atau 2
Perkalian dua angka tanpa tanda delapan digit
Aritmatika 16-bit
Transfer dan pertukaran data antara semua register
Menulis dan membaca semua register dan kombinasi mereka

Mikroprosesor 6809E (eksternal) membutuhkan jam eksternal, sedangkan 6809 memiliki jam internal. Di Hitachi, mereka dipanggil, masing-masing, 6309E dan 6309, mereka berbeda dari yang biasa di mana mereka beroperasi dalam bentuk 32-bit di dalam operasi, tetapi dimungkinkan untuk beralih ke mode kompatibilitas dengan versi klasik.

Sebenarnya, seluruh proyek RetroShield dimulai karena penulis ingin memutakhirkan komputer buatannya Simon6809 dan beri nama hasil Simon6809 Turbo. Tetapi ternyata chip logika standar untuk semua yang ingin dia implementasikan di sana akan membutuhkan banyak. Oleh karena itu, penulis merumuskan ide RetroShield untuk pertama kalinya dalam kaitannya dengan 6809, dan hanya kemudian berpikir: "bagaimana jika yang sama dengan prosesor lain melakukan hal yang sama?".

Perangkat, tentu saja, menggunakan 6809E, yang membutuhkan jam eksternal, sehingga dapat menyinkronkan kerjanya dari luar. Garis E dan Q untuk kedua prosesor diberi nama yang sama, hanya 6809 yang memiliki keluaran, dan 6809E yang memiliki input.

Arduino berinteraksi dengan 6809 dengan cara yang sama seperti dengan 6502, tetapi memiliki dua input jam: E dan Q, dan tiga input interupsi: IRQ, FIRQ dan NMI.



Kali ini, korespondensi antara port Arduino dan pin mikroprosesor dikonfigurasi sebagai berikut:

 /* Digital Pin Assignments */ #define DATA_OUT PORTL #define DATA_IN PINL #define ADDR_H PINC #define ADDR_L PINA #define ADDR ((unsigned int) (ADDR_H << 8 | ADDR_L)) #define uP_RESET_N 38 #define uP_E 52 #define uP_Q 53 #define uP_RW_N 40 #define uP_FIRQ_N 41 #define uP_IRQ_N 50 #define uP_NMI_N 51 #define uP_GPIO 39 

Seperti dapat dilihat dari grafik, sinyal Q bergeser relatif terhadap E dengan seperempat periode:

Kami hampir tidak akan memperhatikan Q, karena semua acara terkait dengan E. Dan semuanya terjadi seperti ini:



  1. E beralih ke nol. Prosesor menetapkan alamat baru pada bus alamat dan mengubah status jalur R / W.
  2. E beralih ke satu, prosesor menjadi siap untuk pertukaran data.
  3. Tidak masalah apa yang terjadi pada bus data selama E adalah satu, hal utama adalah bahwa data yang diperlukan ada di sana pada saat E kembali ke nol.
  4. Saat membaca data, perangkat I / O harus memasok data yang diperlukan ke bus data sebelum garis E melewati dari satu ke nol (penundaan minimum ditunjukkan oleh angka 17 dalam lingkaran).
  5. Saat merekam, perangkat I / O harus memperbaiki data dalam beberapa register dalam bentuk yang pada saat itu E berubah dari satu ke nol. Prosesor akan memberikan data ini pada bus bahkan lebih awal - pada saat transisi dari Q ke satu (nomor 20 dalam lingkaran).
  6. Setelah transisi E ke nol, semuanya terulang.

Semua yang dikatakan di atas sekitar 6502 tentang perlunya perangkat periferal (termasuk yang virtual) untuk mengembangkan semua sinyal tepat waktu 6809.

Generasi sinyal E dan Q, seperti dalam kasus 6502, dengan satu-satunya perbedaan bahwa ada dua sinyal, dan mereka harus diaktifkan sesuai dengan grafik. Dan seperti itu, subrutin yang dipanggil untuk melakukan interupsi melakukan input atau output data pada saat-saat yang diperlukan.

Ruang alamat di sketsa yang tidak dimodifikasi didistribusikan dengan cara yang sama seperti di komputer Simon6809 buatan rumah :

 // MEMORY #define RAM_START 0x0000 #define RAM_END 0x0FFF #define ROM_START 0xE000 #define ROM_END 0xFFFF byte RAM[RAM_END-RAM_START+1]; //////////////////////////////////////////////////////////////////// // Monitor Code //////////////////////////////////////////////////////////////////// // static const unsigned char PROGMEM const unsigned char simon09_bin[] = { 0x1a, 0xff, 0x4f, 0x1f, 0x8b, 0x0f, 0x36, 0x7f, 0x01, 0xa5, 0x10, 0xce, ... 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0f, 0xe0, 0x00 }; 

RAM dan ROM disimpan dalam array dengan cara yang sama seperti pada varian 6502, dengan satu-satunya perbedaan adalah bahwa hanya ada satu array dengan data ROM.

Perangkat I / O juga dialokasikan bagian dari ruang alamat, dan mereka bisa berupa virtual atau nyata. Karena Simon6809 adalah mesin modern yang didasarkan pada basis elemen vintage, ia bertukar data melalui FTDI dari PC yang menjalankan β€œterminal”. Ini ditiru.

Referensi:

Banyak informasi tentang 6809 pada Halaman Arto
Artikel Wikipedia pada 6809
Sistem SWTPc 6809
Artikel Wikipedia tentang sistem operasi FLEX

Source: https://habr.com/ru/post/id446048/


All Articles