Saya sedang mengerjakan sirkuit digital menggunakan komponen diskrit untuk menggerakkan layar 640x480 VGA dalam mode teks 80x30.
Untuk tampilan 640x480, clock pixel adalah 25.175MHz, yang memiliki periode sekitar 40ns. Saya tidak mengerti bagaimana saya seharusnya bisa menyediakan pixel baru untuk tampilan ini sesering mungkin.
Arsitektur dasar untuk sirkuit saya adalah sebagai berikut:
Penghitung biner untuk piksel horizontal dihitung pada 25.175MHz hingga 800 (640 piksel yang terlihat + 160 untuk teras depan, sinkronisasi, teras belakang). Pada 800, kenaikan penghitung garis vertikal (dan reset pada 525 baris)
Dengan menggunakan posisi horizontal dan vertikal, dapatkan koordinat x, y dari karakter saat ini.
Menggunakan koordinat karakter x, y, indeks ke dalam memori video untuk mengambil karakter ASCII.
Gunakan karakter ASCII untuk mengindeks dalam ROM karakter untuk mendapatkan pola bit untuk karakter
Gunakan register geser paralel ke serial untuk mengonversi 8 piksel garis karakter ke bit individu pada frekuensi jam piksel
Jika Anda mengikuti rantai, ia berbunyi: Counter -> RAM -> ROM -> Parallel to Serial Shift Register
Menggunakan komponen tercepat yang dapat saya temukan, penundaan propagasi dan waktu akses bertambah hingga sekitar 15ns + 20ns + 70ns + 15ns = 120ns, jauh lebih besar dari periode 40ns untuk 25MHz.
Pada resolusi dan kecepatan refresh yang lebih tinggi, Anda dapat memiliki jam piksel di atas 100MHz yang akan menjadi periode 10ns.
Bagaimana mungkin untuk memberikan piksel baru ke layar setiap 10ns ketika waktu akses untuk RAM / ROM sudah jauh di atasnya, bahkan tidak mempertimbangkan semua sinyal lain di sistem Anda?
sumber
Jawaban:
Ada dua alasan utama Anda menemukan tantangan ini.
Pertama, Anda menggunakan bagian yang lebih tua dan lebih diskrit (integrasi skala lebih rendah) daripada yang seharusnya digunakan untuk melakukan ini di era VGA.
Tetapi selanjutnya, Anda menggunakannya dengan cara yang tidak lazim. Secara khusus, pendekatan Anda bukan
pipelined
yang berarti bahwa Anda harus menambahkan beberapa penundaan saat menentukan interval Anda, dan dengan demikian menilai.Sebaliknya, desain digital sinkron yang berupaya mencapai kecepatan mencoba melakukan sesedikit mungkin di antara register.
Walaupun detailnya mungkin akan sedikit berbeda, secara kasar itu akan bekerja seperti ini:
Ketika Anda memecah tugas seperti ini, Anda hanya mendapatkan satu penundaan kombinatorial ditambah beberapa penundaan propagasi dan mendaftarkan pengaturan dan menahan waktu yang diperlukan agar sesuai antara jam.
Sebuah desain yang dibangun dengan cara ini akan membutuhkan banyak jam untuk menghasilkan output - latensi sebenarnya akan lebih tinggi daripada desain yang murni kombinasi. Tetapi menghasilkan output yang benar baru pada setiap siklus jam yang jauh lebih cepat.
Dan hei, ini video, tidak masalah jika CRT menggambar selusin piksel di belakang penghitung piksel - Anda tentu saja memperhitungkannya dalam waktu sinyal sinkronisasi sehingga mereka benar dibandingkan dengan saat data sebenarnya keluar dari DAC.
Dalam praktiknya, hampir semua sistem digital yang kompleks bekerja dengan cara ini, karena ini adalah ide yang bagus - hingga CPU yang dipipihkan menyentuh ketergantungan pada hasil komputasi sebelumnya atau cabang bersyarat ... Kemudian semuanya menjadi menarik, karena mereka akan berbicara tentang dalam kuliah berikutnya tentang kelas sistem digital - tetapi untungnya situasi VGA Anda jauh lebih sederhana, terutama jika Anda belum khawatir tentang efek sobek jika buffer karakter berubah saat layar sedang diambil.
Sebagai hal praktis jika Anda ingin membangun ini, lakukan dalam FPGA. Itu akan cukup banyak memaksa memori sinkron pada Anda jika Anda menggunakan yang internal, atau register IO sinkron jika Anda menggunakan memori eksternal. Anda akan mendapatkan banyak dorongan ke arah desain yang tepat, kain itu sendiri akan lebih cepat daripada bagian-bagian terpisah Anda, dan tentu saja jika Anda membuat kesalahan, Anda hanya perlu memutar-mutar ibu jari Anda saat mengkompilasi daripada menghabiskan hari yang panjang untuk melakukan pengkabelan kembali. .
sumber
Anda lupa bahwa adaptor grafis tidak akan pernah hanya menggambar satu piksel - tetapi setidaknya garis pindai penuh. Dengan demikian, ini akan menjadi masalah yang sepenuhnya dapat disalurkan melalui pipa.
Juga, jangan lupa bahwa ada lima dekade perangkat keras penghasil video sejauh ini. Masalah Anda biasanya akan diselesaikan dengan jenis RAM khusus, di mana Anda membuat surat-surat Anda pada satu port, dan yang secara berurutan dibacakan ke sinyal video DAC. Perangkat keras itu jalan, jauh lebih cepat dari apa yang Anda lihat.
Tidak, mengapa kamu melakukan itu? Anda cukup meletakkan piksel baris Anda ke area memori yang berdekatan dan secara linear meletakkannya ke DAC Anda - jika ini adalah tentang implementasi CPU / MCU, Anda bahkan tidak akan membiarkan CPU Anda melakukan itu, tetapi unit DMA, diprogram untuk tidak melakukan apa pun selain mengambil satu nilai setelah yang lain dan menaruhnya ke misalnya port data paralel, tanpa interaksi inti CPU.
Ah, Anda ingin membuat dengan cepat - pilihan yang baik, tetapi tidak biasa dengan biaya modern RAM. Alih-alih, Anda hanya akan merender karakter menjadi penyangga bingkai sebelumnya, atau jika perangkat Anda sangat ramping, langsung keluar (lihat penjelasan DMA saya di atas) baris karakter ke DAC.
sumber
Terlepas dari pipelining (yang sangat banyak yang harus Anda lakukan), Anda kehilangan sesuatu yang besar ....
Paralel masuk, register geser keluar secara serial memberikan titik pada 25 ganjil Mhz, tentu saja, tetapi jika karakter Anda memiliki lebar 8 piksel, inputnya hanya ~ 3.2MHz yang mudah dijangkau untuk seri LS era VGA, untuk semua itu Anda harus memiliki byte berikutnya yang siap ketika register geser selesai dengan yang sekarang (ini adalah tempat pipa masuk).
Hasilkan jam piksel pada ~ 25MHz dan jam memori pada 1/8 dari itu untuk mendorong buffer teks dan CG ROM, kemudian pipeline memori itu dan hal-hal akses CG ROM.
Satu trik lebih lanjut, output buffer teks akan diulang untuk setiap baris dalam setiap baris teks, jadi mungkin Anda bisa clock 80 byte teks ke buffer cincin dan kemudian berhenti membaca ram untuk 7 baris berikutnya (dengan asumsi 8 karakter garis), ini memungkinkan Anda membebaskan memori untuk digunakan CPU, dengan biaya membutuhkan 80 byte ram yang tergantung di sampingnya.
sumber
Jadi jelas itu tidak berhasil; Anda membutuhkan saluran pipa.
1) Simpan karakter secara bersebelahan dalam memori. Mulai dari kiri atas.
2) Ambil karakter selama interval pengosongan. Lanjutkan untuk mengambil karakter dalam urutan memori.
3) Pipeline setiap karakter yang diterjemahkan dan indeks baris ke dalam ROM.
4) Pipeline output ROM ke buffer.
5) Pipeline buffer ke register geser. Bacakan piksel secara terus-menerus pada interval 40ns dari ini.
(Itu menyiratkan Anda perlu memuat karakter baru ke register geser setiap 320ns, yang bahkan mungkin bisa dilakukan tanpa pipelining seluruh sistem.)
6) Selama pengosongan horizontal, kembali ke awal baris atau maju ke karakter berikutnya (yaitu mulai dari baris berikutnya.)
Fitur bonus: karena Anda hanya memerlukan satu karakter setiap 320ns, Anda juga bisa membaca pasangan karakter + warna dan melakukan karakter warna MSDOS-style atau Spectrum-Style.
sumber