الحواشي تأتي في درجات متفاوتة من صعب. بعضها راض عن المحاكاة. البعض الآخر يفضل FPGAs ، لأنه بعد ذلك اتضح ليس مضاهاة ، ولكن الترفيه. وأخيرا ، خدمة المعالج الثالث.
لكن المعالج يحتاج إلى الكثير من العمل! مرة أخرى ، المعضلة: خذ شرائح حقيقية من نفس السنوات ، أو ضع كل شيء في FPGA ، وترك المعالج بالخارج؟ ومع ذلك ، لماذا FPGA ضروري؟ يعيش اتحاد اردوينو والمعالج الكلاسيكي!
امنح Arduino الخاص بك "دماغًا ثانيًا" واجعله أكثر ذكاءً.
يقوم المعالج الدقيق ذي الثمانية بت بتشغيل البرامج ، في حين يقوم Arduino بمحاكاة ROM وذاكرة الوصول العشوائي والأجهزة الطرفية البسيطة.
صمم الأجهزة الطرفية الافتراضية في Arduino IDE ، وقم بتشغيل رمز المجمّع على المعالج الدقيق. لا حاجة لتجميع الدوائر المعقدة وفلاش مدمجة متوازية.
المعالجات الدقيقة المدعومة: 6502 و 6809 و Z80 (18581) ، والبعض الآخر في الطريق.
لا يتداخل الدرع المزوَّد بمعالج دقيق في توصيل الدروع الأخرى: مع شاشات LCD وبطاقات الذاكرة ، إلخ.
بالإضافة إلى لغة التجميع الذاتي ، يمكنك محاولة تشغيل بعض التعليمات البرمجية الكلاسيكية على المعالج الدقيق.
صحيح أن المعالج الصغري سيعمل بتردد منخفض للغاية - حوالي 95 كيلو هرتز ، وتعتمد قيمته الدقيقة على تحسين شفرة مضاهاة الأجهزة الطرفية.
يتم تعيين توزيع مساحة العنوان برمجياً في رسم. يمكن تخصيص المعالج الدقيق من 4 إلى 6 كيلو بايت من 8 كيلو بايت من ذاكرة الوصول العشوائي المتاحة على Arduino Mega. يمكن ROM تخصيص أكثر من 200 كيلو بايت من 256 المتوفرة.
منفذ Arduino Mega التسلسلي يمكنه محاكاة UART.
تتوفر الدوائر ورسومات اللوحات وملفات جربر تحت CC-BY-SA 4.0
هنا . في الوقت نفسه ، هناك حاجة لإرفاق ملف README.md ، لأنه يحتوي على التحذير التالي:
لا تقم بتوصيل الدرع حتى يتم تحميل رسم محاكاة المضاهاة الطرفية! خلاف ذلك ، يمكن تقصير خطوط الإخراج من المعالج الصغري.
نعم ، وفي المخطط نفسه ، يجب إعادة صياغة شيء ما بعناية لنفس السبب.
مخطط الجهاز على 6502:

مخطط الجهاز على 6809:

مخطط الجهاز على Z80:

يمكنك بالفعل تشغيل:
على جهاز به 6502 -
Apple I ، Woz Monitor + ROM مع BASICعلى جهاز به 6809 -
تمثيلي لجهاز كمبيوتر محلي الصنع Simon6809 لنفس المطور ، وجهاز تدريب مع مجمِّع ومزيل تفكيكعلى جهاز به Z80 - حتى الآن فقط
اختبار صدى للمنفذ التسلسلي ، مما يتيح لك التحقق من أداء 8251 الظاهري (KR580VV51A).
البرامج الثابتة لمحاكاة الأجهزة الطرفية - بموجب ترخيص MIT.
وصف موجز لمبدأ العمل:
إلى 6502 جهازإلى الجهاز على 6809إلى الجهاز على Z80 - في التحضير.
يحاول المطور
بيع الأجهزة ، ولكن مع التسليم فقط في الولايات المتحدة. لا يوجد سبب محدد للشراء ، لأن المخطط بسيط للغاية ، يمكنك تكراره على قطعة من اللوح خلال ساعة.
من المخطط تطوير لوحات مماثلة على RCA1802 و 68008 و 8085 (18182185) و 8088 (18181088). حول K1801BM1 لا يقال ، ولكن يمكنك طرح مثل هذه الفكرة للمؤلف.
ملفات:
إلى الجهاز على 6502:
تعليمات التجميع ،
طباعة الشاشة الحريرية ،
الرسم التخطيطيإلى الجهاز على 6809:
تعليمات التجميع ،
طباعة الشاشة الحريرية ،
الرسم التخطيطيإلى الجهاز على Z80:
تعليمات التجميع ،
طباعة الشاشة الحريرية ،
الرسم التخطيطيضع في اعتبارك تفاعل Arduino وجهاز 6502. يغير Arduino بشكل دوري المستوى عند إدخال المعالج الدقيق المصمم لتزويد نبضات الساعة من صفر إلى واحد والعكس. في كل دورة ، يقوم بالتحقق مما يحدث على خطوط التحكم وحافلة العنوان ، وقراءة المعلومات من ناقل البيانات أو إرسالها إلى هناك تبعًا للموقف. يمكن أيضًا التحكم في Arduino خطوط IRQ و NMI ، مما تسبب في مقاطعة. يوضح الشكل أنواع البيانات واتجاهات نقلها:

يتم تكوين مراسلات منافذ Arduino ومخرجات المعالج الدقيق في المخطط:
/* 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
سنقسم كل قياس إلى الأحداث التالية:
تغير حالة CLK من واحد إلى صفر (انخفاض)
CLK في حالة الصفر
تغير حالة CLK من واحد إلى صفر (ارتفاع)
CLK في حالة الوحدة
CLK مرة أخرى يتغير الحالة من واحد إلى صفر ...
ماذا يحدث خلال لحظات انتقال الدولة؟
يستقبل 6502 نبضات الساعة عند إدخال CLK0 ، ويقوم بتخزينها مؤقتًا ويرسلها إلى مخرجات اثنين: CLK1 و CLK2. على الرغم من أن جميع الأحداث في المعالج الدقيق مرتبطة بـ CLK1 ، فإننا نفترض أن التأخير صغير ، وأنهم مرتبطون بـ CLK0 - الخط الذي يتلقى المعالج الدقيق عليه نبضات الساعة من Arduino. واتصل إشارة فقط CLK.

1. تتغير حالة CLK من واحد إلى صفر.
2. يقوم المعالج الدقيق بإخراج عنوان جديد إلى ناقل العنوان ، وإشارة التبديل بين القراءة والكتابة إلى إخراج R / W. لكنه ليس جاهزًا لتبادل البيانات بعد.
3. يذهب CLK إلى حالة الوحدة ، وهذا يعني أن تبادل البيانات قد بدأ. إذا كانت هذه عملية للقراءة ، فإن المعالج الدقيق ينقل مخرجات ناقل البيانات إلى حالة الإدخال ويتلقى البيانات ، وإذا كانت عملية الكتابة ، فإنها تنقلها إلى حالة الإخراج وترسل البيانات. وتقوم إشارة R / W بتبديل الجهاز الخارجي إلى وضع الكتابة أو القراءة ، على عكس الحالة المقابلة للمعالج الدقيق.
4. CLK يذهب إلى الصفر. الآن لا المعالج الدقيق ولا أجهزة الإدخال والإخراج إخراج أي شيء إلى ناقل البيانات. يمكن للمعالج الدقيق ضبط خط ناقل البيانات ودبوس R / W إلى حالة جديدة.
تفسير بسيط ومفهوم للطفل. الذي لا يفكر أبدا في هذه "وراء المؤامرات الكواليس" ، إذا كان سوف البرنامج فقط ميكروكنترولر. حتى في المجمع.
إذا كنت بحاجة إلى توصيل جهازك المحيطي ، فيجب أن يكون لديك وقت لإعداد البيانات قبل ظهور الوحدة (وقت الإعداد) على خط CLK ، وأثناء وجود الوحدة هناك ، لا تقم بتغييرها. إذا لم يكن لدى الجهاز المحيطي وقت لإعداد البيانات بينما CLK تساوي صفرًا ، أو قام بتغييرها عند وجود الوحدة ، فستتساءل عن سبب عدم عمل الكود الخاص بك لفترة طويلة. نظرًا لأن تردد ساعة المعالج الصغري يقل بمقدار عشر إلى خمسة عشر مرة عن التردد الاسمي ، فمن السهل الامتثال لهذا المطلب. لكن هذا ضروري.
لذلك ، نحن بحاجة إلى "تعليم" Arduino لتوليد نبضات على مدار الساعة ، والتحقق المستمر من ما يحدث على ناقل العنوان وخط R / W ، والتفاعل مع ناقل البيانات وفقًا لذلك. للقيام بذلك ، يستخدم المخطط مقاطعة مؤقت timer1 ، والذي يولد نبضات بتردد 95 كيلو هرتز. يعمل Arduino بشكل أسرع بكثير من المعالج الدقيق ، وبالتالي ، بين ساعاته ، يتمكن من قراءة وإعداد كل شيء. من المهم التأكد من استمرار تعديل هذا الشرط بعد تعديل المخطط.
فيما يلي مقتطف من المخطط ، والذي يوضح كيفية انتقال CLK من صفر إلى واحد ، وما يحدث بعد ذلك:
//////////////////////////////////////////////////////////////////// // 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; }
يمكن تخصيص مساحة العنوان بأي شكل من الأشكال ، في رسم غير معدّل ، كما هو الحال في Apple 1 مع 256 بايت من ذاكرة الوصول العشوائي و 8 كيلو بايت من ذاكرة ROM لـ BASIC و 4 كيلو بايت من ذاكرة الوصول العشوائي و 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 بواسطة صفيف RAM بايت [RAM_END-RAM_START + 1]. هناك حاجة إلى كلمتين PROGMEM بحيث يتم تخزين محتويات ROM مضاهاة في ذاكرة فلاش من متحكم.
يتم محاكاة 6821 بدرجة كافية بحيث تعمل لوحة المفاتيح الافتراضية والعرض من خلال "الجهاز الطرفي". Woz Monitor و BASIC العمل ، وهو ما سعى المؤلف.
لمضاهاة أي جهاز طرفي ، تحتاج إلى قراءة ورقة البيانات الخاصة بها بعناية ومعرفة السجلات التي لديها وما هي من أجلها. تكمن راحة المضاهاة في المرونة التي يمكنك من خلالها تكوين نظائر برمجية للمحيط.
توجد أجهزة الإدخال / الإخراج في مساحة العنوان الخاصة بالمعالج الدقيق ؛ ويتم الوصول إليها بنفس طريقة الوصول إلى خلايا الذاكرة. لاستخدام الأجهزة الطرفية "الحديد" ، مثل شاشة LCD وبطاقة ذاكرة وإخراج الصوت ، تحتاج إلى تخصيص مكان في مساحة العنوان.
المراجع:
www.6502.orgwww.callapple.org/soft/ap1/emul.htmlskilldrick.imtqy.com/easy6502searle.hostei.com/grant/6502/Simple6502.htmlwilsonminesco.com/6502primerSB-Assembler:
www.sbprojects.net/sbasmانتقل إلى 6809 ، ويحتوي على:
بطاريتان 8 بت A و B ، والتي يمكن دمجها في بطارية واحدة من ست بت
فهارس مكدس 16 بت
معالجة نسبة إلى عداد التعليمات
إضافة تلقائيا أو طرح 1 أو 2
الضرب من اثنين من أرقام غير موقعة من ثمانية أرقام
حساب 16 بت
نقل وتبادل البيانات بين جميع السجلات
كتابة وقراءة جميع السجلات وأي مجموعة منها
يحتاج المعالج الدقيق 6809E (خارجي) إلى ساعة خارجية ، بينما يحتوي المعالج 6809 على ساعة داخلية. في Hitachi ، يطلق عليهم ، على التوالي ، 6309E و 6309 ، ويختلفان عن المعتاد في أنهما يعملان في شكل 32 بت داخل العملية ، لكن من الممكن التبديل إلى وضع التوافق مع الإصدار الكلاسيكي.
في الواقع ، بدأ مشروع RetroShield بأكمله لأن المؤلف أراد ترقية جهاز الكمبيوتر الخاص به محليًا Simon6809 وتسمية النتيجة Simon6809 Turbo. لكن اتضح أن رقائق المنطق القياسية لكل شيء يريد تنفيذه هناك ستتطلب الكثير. لذلك ، صاغ المؤلف فكرة RetroShield لأول مرة على وجه التحديد فيما يتعلق 6809 ، وفقط عندها فكر: "ماذا لو أن الشيء نفسه مع المعالجات الأخرى تفعل الشيء نفسه؟".
يستخدم الجهاز ، بالطبع ، الموديل 6809E ، الذي يتطلب ساعة خارجية ، حتى يتمكن من مزامنة عمله من الخارج. تتم تسمية خطوط E و Q لكل من المعالجات على نفس المنوال ، فقط 6809 لديهم مخرجات ، و 6809E لديهم مدخلات.
يتفاعل Arduino مع 6809 بنفس طريقة تفاعله مع 6502 ، لكن لديه مدخلات على مدار الساعة: E و Q ، وثلاثة مدخلات مقاطعة: IRQ ، FIRQ و NMI.

هذه المرة ، يتم تكوين المراسلات بين منافذ Arduino ودبابيس المعالج الدقيق على النحو التالي:
/* 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
كما يتضح من الرسوم البيانية ، فإن الإشارة Q يتم إزاحتها بالنسبة إلى E بمقدار ربع الفترة:
بالكاد سننتبه إلى Q ، نظرًا لأن كل الأحداث مرتبطة بـ E. وكل شيء يحدث مثل هذا:

- ه التبديل إلى الصفر. يقوم المعالج بتعيين عنوان جديد على ناقل العنوان ويغير حالة خط R / W.
- E يتحول إلى واحد ، يصبح المعالج جاهزًا لتبادل البيانات.
- لا يهم ما يحدث لحافلة البيانات طالما أن E هو واحد ، الشيء الرئيسي هو أن البيانات المطلوبة موجودة هناك في الوقت E يعود إلى الصفر.
- عند قراءة البيانات ، يجب أن يوفر جهاز الإدخال / الإخراج البيانات المطلوبة إلى ناقل البيانات قبل أن يمر السطر E من واحد إلى صفر (يظهر الحد الأدنى للتأخير بالرقم 17 في الدائرة).
- عند التسجيل ، يجب أن يقوم جهاز الإدخال / الإخراج بإصلاح البيانات في بعض السجلات بالشكل الذي كانت عليه في الوقت الذي انتقلت فيه E من واحد إلى صفر. سيوفر المعالج هذه البيانات على الناقل حتى قبل ذلك - في لحظة انتقال Q إلى واحد (الرقم 20 في الدائرة).
- بعد انتقال E إلى الصفر ، يكرر كل شيء.
كل ما ذكر أعلاه حوالي 6502 حول الحاجة إلى جهاز طرفي (بما في ذلك واحد الظاهري) لتطوير جميع الإشارات في الوقت المحدد يتعلق 6809.
توليد الإشارات E و Q ، كما هو الحال في 6502 ، مع الفارق الوحيد أن هناك إشارات اثنين ، ويجب أن يتم تبديلها وفقا للرسوم البيانية. ومثل هذا ، يقوم روتين فرعي يسمى المقاطعة بإدخال البيانات أو إخراجها في اللحظات المطلوبة.
يتم توزيع مساحة العنوان في المخطط غير المعدل بنفس طريقة توزيعها في كمبيوتر
Simon6809 محلي الصنع:
// 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 };
يتم تخزين ذاكرة الوصول العشوائي وذاكرة القراءة فقط في صفائف بالطريقة نفسها كما هو الحال في البديل 6502 ، مع الاختلاف الوحيد هو أن هناك صفيف واحد فقط مع بيانات ROM.
يتم تخصيص أجهزة الإدخال / الإخراج أيضًا أجزاء من مساحة العنوان ، ويمكن أن تكون إما افتراضية أو حقيقية. نظرًا لأن Simon6809 عبارة عن آلة حديثة تعتمد على قاعدة عنصرية قديمة ، فإنها تتبادل البيانات عبر FTDI من جهاز الكمبيوتر الذي تعمل عليه "الجهاز الطرفي". هنا هو مقلد.
المراجع:
الكثير من المعلومات على 6809 على
صفحة Artoمقالة ويكيبيديا على 6809نظم SWTPc 6809مقالة ويكيبيديا على نظام التشغيل FLEX