ZX Spectrum من الفيروس التاجي والعصي (في الواقع ، ليس في الحقيقة)

العزلة الذاتية هي آفة الإنسانية الحديثة. هنا ، على سبيل المثال ، في المدينة المجاورة ، يومي الجمعة والسبت ، بعد التصفيق التقليدي في الساعة 8 مساءً ، يقومون بتنظيم حفلات الشرفة. إنهم يشعرون بالرضا ، ومنازلهم طويلة وجيرانهم من الشباب. جيراننا كبار السن ، لا يريدون حفلات موسيقية. والبيوت منخفضة ولا تساهم أيضًا في الكسل. لذلك ، نحن مخلصون قدر الإمكان.

في فترة ما بعد الظهر ، على موقع بعيد ، ليس بهذا السوء. كما في المساء ، حتى ينام الأطفال. كما هو الحال في الأيام القليلة الأولى ، حتى تنفد الكتب والملل يشعر بالملل. ولكن يمر شهر ، يتبعه شهر آخر. تتطلب الروح الحديد القديم. ولكن ليس فقط ، ولكن مع الانحراف. وقمت بتفتيش صناديق القمامة ووجدت معالج Zilog Z80 هناك:

صورة

يجب أن أقول ، أنا حقا أحب هذا المعالج. ربما الشيء الوحيد الذي أحبه فيه هو الرقاقة 486 ، لكن يدي لن تصلهما قريبًا ، لأنه من الصعب وغير المجدي إدخالها في لوحة التوصيل. يجب أن اللحيم. لكني لا أريد اللحيم بعد. وحتى أكثر من Z80 نفسها ، فأنا أحب الكمبيوتر ZX Spectrum المبني على أساسه. لكن الطيف الأصلي يعاني من سوء الحظ في شكل شريحة منطق مخصصة ULA ، وليس من الصعب بشكل خاص بناء واستنساخ استنساخه على الجانب الفضفاض ، ولكن لا يزال غير مناسبًا لنموذج اللوح ، وفي الواقع ، لماذا الكثير من المخاوف عندما يكون هناك اردوينو؟

سيتوقف القارئ الذكي والمتوازن والملائم هنا عن القراءة أو يرمي شيئًا مثل "دائرة دقيقة واحدة FPGA ستلائم فئة كمبيوتر Spectrum" قبل التوقف. لست ذكية ، غير كافية ، على الرغم من التوازن ، لكنني أعرف فقط عن FPGA أنه رائع. يمكنني فقط أن أفعل اردوينو. لكنه يريد حقًا أن يقطع الأسلاك في Z80. عاليا.

لنبدأ

بالطبع ، لنبدأ. لكن أولاً ، إخلاء المسؤولية., , , . — . , , . , (, ?), , , , , . , , , , , .

بادئ ذي بدء ، ما هو جهاز كمبيوتر ملائم 8 بت. هذا ، في الواقع ، معالج متصل بذاكرة القراءة فقط (RAM) وذاكرة الوصول العشوائي (RAM) ، وعلى الجانب الآخر يوجد عدادات لعرضها على الشاشة المركبة. في بعض الأحيان ، توقيت لصرير. لا يختلف ZX Spectrum عن المخطط التقليدي ، باستثناء مخطط واحد ولكن. هناك ULA. هذه ، في الواقع ، هي "شرائح" الطيف. تدير ULA الأجهزة الطرفية ، مثل مسجل الشريط ومكبر الصوت ولوحة المفاتيح (جزئيًا) والإخراج على الشاشة (نعم ، نعم ، ظهرت بطاقة الفيديو المدمجة في شرائح Spectrum حتى قبل أن تصبح سائدة). كان هناك أيضًا نصب تذكاري مشترك ، أول 16 كيلوبايت من ذاكرة الوصول العشوائي (عناوين من 0x4000 إلى 0x5B00). من ذلك ، قامت ULA برسم مركب على الشاشة ، وبالتالي لن تتعثر Z80 هناك عندما لم يكن ذلك ضروريًا ، يمكن لـ ULA إيقاف المعالج ، إذا لزم الأمر ، لأن إشارة الساعة على Z80 جاءت منه. أي ، إذا عملت ULA مع الذاكرة ، واكتشفت ،أن المعالج يتسلل أيضًا إلى هذه الذاكرة (لهذا ، كان يراقب باستمرار خطوط MREQ و A15 و A14) ، وببساطة توقف المعالج عن تسجيل الوقت حتى انتهى من القيام بما يحتاجه. بالمناسبة ، لتجنب تلف البيانات في الحافلة ، تم تحديد أجزاء من الحافلة على جانب المعالج وعلى جانب ULA بواسطة مقاومات ... علاوة على ذلك ، كانت الذاكرة جالسة في الحافلة من جانب ULA ، وبالتالي ، في حالة حدوث تصادم ، تم تجاهل البيانات والعنوان من جانب المعالج تمامًا.تجاهل البيانات والعنوان من المعالج بالكامل.تجاهل البيانات والعنوان من المعالج بالكامل.

بالإضافة إلى ذلك ، كان الطيف يحتوي على ROM (عناوين 0x0000 - 0x3FFF) وذاكرة المعالج الخاصة به (0x8000 - 0xFFFF) ، والتي لم يكن لدى ULA الوصول إليها ، والتي عملت بشكل أسرع من 16 كيلوبايت من الذاكرة المشتركة ، حيث أن المعالج لم يتداخل مع ULA في هذه المنطقة . ولكن ذلك كان فقط على إصدار 48K من الكمبيوتر. في الإصدار الأساسي ، كان هناك فقط ROM و 16 KiB متوافق مع ULA. سنبدأ معها.

من المريح أن يتمكن معالج Z80 من تجديد ذاكرة الوصول العشوائي (DRAM) ، ولكن بطريقة ما لا أريد أن أزعجها ، لأن العثور على ذاكرة الوصول العشوائي (SRAM) أسهل وليس لدي جهاز إرسال متعدد (أو لا يمكنني العثور عليه). لذا ، سنستخدم SRAM. بادئ ذي بدء ، سنقوم بتجميع الهيكل العظمي الرئيسي ، حيث يمكن تعليق كل شيء آخر. سيكون الهيكل العظمي عبارة عن معالج ، ROM مع برنامج ثابت ، تم تعيينه على عنوان ROM الخاص بـ Spectrum وذاكرة الوصول العشوائي ، وقد تم تعيينه لأول 16 KiB بعد ROM وبعض الرقائق لتغليف كل شيء ... يجب أن أقول أنه لفترة طويلة لم أرغب في التدوير ، لأن لدي تخطيطات صينية 1 دولار لقطعتين في ibee. ولكن بالنسبة لي ، فإن الضجة تستحق العناء. إذا كنت لا تريد أن تعبث لفترة طويلة ، خذ تنسيقات جيدة.

لذا ، قم بتثبيت Z80.

كما ترى من ورقة البيانات ،



يحتوي المعالج على 40 دبابيس مقسمة إلى مجموعات: ناقل العنوان ، ناقل البيانات ، التحكم في النظام ، التحكم في المعالج ، التحكم في ناقل المعالج ، البئر ، الطاقة والساعة. لا يتم استخدام جميع هذه الاستنتاجات في أنظمة حقيقية ، مثل ZX Spectrum ، كما يمكن رؤيته من الرسم التخطيطي.. من مجموعة "تحكم المعالج" في الطيف ، يتم استخدام إشارات INT و RESET فقط. لا يتم استخدام الإشارة M1 من مجموعة "التحكم في النظام" ، ولا يتم استخدام مجموعة "التحكم في الحافلات" على الإطلاق. هناك سبب لذلك. كانت أنظمة 8 بت القديمة بسيطة للغاية ، وتم إنشاء الطيف بفكرة كونه بسيطًا قدر الإمكان وتم تجاهل كل ما يمكن تجاهله. بالطبع ، يمكن للشركات المصنعة الطرفية استخدام المقاطعات (إشارات INT و NMI) ، وتم توجيهها إلى فتحة التوسيع ، ولكن لم يتم استخدام NMI في الطيف نفسه. كما يمكن رؤيته من الرسم البياني أعلاه ، يتم سحب إشارات NMI و WAIT و BUSREQ بواسطة مقاومات الطاقة ، نظرًا لأن هذه مدخلات نشطة منخفضة المستوى (يشار إليها بواسطة الشريط أعلى اسم الإشارة) ، ويجب أن تكون هناك وحدة منطقية (أي + 5 فولت) بحيث لا سمح الله للإشارة غير الضرورية لم تنجح. وهنا النتائج ، BUSACK ، HALT ، M1 ،وتعلق في الهواء ، غير متصل بأي شيء. بالمناسبة ، لاحظ أنه لا يوجد زر إعادة تعيين في الطيف. يتم توصيل دبوس إعادة الضبط عبرسلسلة RC إلى السلطة (يتم تنشيط RESET أيضًا بمستوى منخفض) ، نظرًا لأنه ، وفقًا لورقة البيانات ، بعد تشغيل RESET ، يجب أن تكون 3 دورات ساعة على الأقل نشطة حتى يدخل المعالج في وضع التشغيل. تحتفظ دائرة RC هذه بمستوى منخفض حتى يتم شحن المكثف إلى مستوى عال من خلال المقاوم.

دعنا نتناول بإيجاز بقية الإشارات:
M1. نحن لسنا بحاجة. وذكر أن المعالج بدأ في تنفيذ التعليمات التالية.
MREQ. أنا في حاجة إليه. تشير إلى أن المعالج يصل إلى الذاكرة. إذا أصبحت هذه الإشارة منخفضة (أي متصلة بأرض الطاقة) ، فسوف نحتاج إلى تنشيط الذاكرة المتصلة بالمعالج.
IOREQ . أنا في حاجة إليه. تشير إلى أن المعالج يصل إلى جهاز طرفي. على سبيل المثال ، إلى لوحة المفاتيح.
RD . أنا في حاجة إليه. يعلم أن المعالج سيقرأ البيانات من الذاكرة (إذا كانت MREQ نشطة) أو الأجهزة الطرفية (IOREQ).
Wr . أنا في حاجة إليه. تقارير تفيد بأن المعالج سوف يكتب البيانات إلى الذاكرة / الأجهزة الطرفية.
RFSH . أنا في حاجة إليه. بشكل عام ، هذه الإشارة مطلوبة للذاكرة الديناميكية (DRAM). لا أخطط لاستخدامه ، نظرًا لأن عنوانه أكثر صعوبة (مصفوفة ، وليست خطية ، أي أنه سيكون من الضروري تثبيت معدد إرسال) ، وبشكل عام ، في عصرنا ، من السهل الحصول على دوائر صغيرة ذات قدرة منخفضة SRAM. ولكن نظرًا لأن المعالج نفسه يُعيد إنشاء ذاكرة الوصول العشوائي الديناميكية (DRAM) من خلال فرز العناوين على ناقل الذاكرة ، فإن هذه الإشارة ستسمح لنا بتجاهل دورات التجديد وعدم تنشيط الذاكرة باستخدام RFSH النشط.
HALT . لا حاجة. يشير إلى توقف المعالج.
انتظر. لا حاجة. هذه الإشارة مطلوبة لتطلب من المعالج التوقف والانتظار قليلاً. تستخدم عادة من قبل الأجهزة الطرفية أو الذاكرة البطيئة. ولكن ليس في الطيف. عندما تقرر في الأجهزة الطرفية Spectrum (ULA) إيقاف المعالج ، يتوقف ببساطة عن إرسال إشارة ساعة إليه. هذا أكثر موثوقية ، لأنه بعد تلقي الانتظار ، لا يتوقف المعالج على الفور.
INT . يقطع. ليس من الواضح حتى الان. نفترض أنه ليس هناك حاجة بعد. ثم سنكتشف ذلك.
NMI . انقطاع لا يمكن إخفاؤه. مقاطعة فائقة. ليس من الضروري.
إعادة . بدونها ، لن تطير.
BUSREQ . لا حاجة. يطلب من المعالج قطع الاتصال عن ناقل البيانات / العنوان ، وكذلك إشارات التحكم. من الضروري إذا أراد بعض الأجهزة التحكم في الحافلة.
BUSACK. لا حاجة. يعمل على إبلاغ الجهاز الذي أجرى BUSREQ أن الحافلة مجانية.
الساعة . إشارة الساعة. من الواضح أنه مطلوب.
هناك حاجة أيضا وجبات . المجد للمطورين فقط +5 فولت / جي ان دي. لا 3 ضغوط عليك.
A0-A15 هو ناقل العنوان. يعرض عليه إما عنوان ذاكرة (MREQ نشط) أو عنوان منفذ I / O (IOREQ نشط) مع المكالمات المناسبة. كما ترى ، يبلغ عرض الحافلة 16 بت ، مما يسمح لك بمعالجة 64 كيلوبايت من الذاكرة مباشرة.
D0-D7 - ناقل البيانات. يخرج المعالج إليه (WR active) ، أو يقرأ منه (RD active) البيانات المطلوبة.

لذا ، سوف نضع المعالج على لوحة التوصيل. لذا فإن استنتاجاته تقع فعليًا:

صورة

قم بتوصيل الطاقة (دبوس 11 و 29). في هذه الحالة ، أضع أيضًا مكثف 10 pF بين هذه الأرجل. لكنه لم يساعدني في النهاية. قد تظل الدبابيس 27 و 23 و 18 غير متصلة بأي شيء. يتم توصيل الدبابيس 26 و 25 و 24 و 17 و 16 عبر المقاومات (استخدمت 10 كيلو أوم) إلى مصدر الطاقة. أحضرت ناقل العنوان (الدبابيس 1-5 و30-40) إلى الجانب الآخر من لوحة التوصيل ، وناقل البيانات (الدبابيس 7-10 و12-15) إلى ناقل بيانات منفصل مصنوع من حافلات الطاقة النموذجية.
يتم توصيل الدبابيس 6 (إشارة الساعة) و 26 (RESET) (لاحقًا) بـ Arduin حتى تتمكن من التحكم في المعالج منه.

اتضح مثل هذا:



حتى تنتبه إلى الأسلاك من الأعلى ، فإنها تنتقل من ROM ، وسوف ننتقل إليها لاحقًا. أيضا ، في الصورة بجانب المعالج ، تظهر شريحة أخرى. نحن بحاجة إليها لفك الأجزاء العليا من العنوان. كما قلت أعلاه ، هناك 3 أنواع من الذاكرة في الطيف. 16 كيلوبايت أقل من مساحة العنوان هي ROM. وفقًا لذلك ، إذا كانت المحطتان A14 و A15 في حالة منخفضة (0 فولت) ، فنحن بحاجة إلى فصل كل شيء باستثناء شريحة ROM من الناقل. التالي هو 16 كيلوبايت من الذاكرة المشتركة. وفقًا لذلك ، نحتاج إلى توصيل هذه الذاكرة بالحافلة (وفصل الباقي) إذا كان الإخراج A15 منخفضًا و A14 مرتفعًا (+5 فولت). حسنًا ، يأتي بعد ذلك 32 كيلوبايت من الذاكرة السريعة. سنقوم بإرفاق هذه الذاكرة لاحقًا ، وسنقوم بتنشيطها إذا كان الإخراج A15 في حالة عالية. بالإضافة إلى ذلك ، لا تنس أننا نقوم فقط بتنشيط الذاكرة عندما تكون نشطة (هنا ، نشطة - منخفضة ،0 فولت) MREQ وغير نشط (هنا ، غير نشط - مرتفع ، +5 فولت) RFSH. كل هذا سهل التنفيذ على المنطق القياسي ، على نفس NANDs ، مثل 74HC00 ، أو Orthodox K155LA3 ، وأنا أفهم أن هذه المهمة تقتصر على المجموعة التحضيرية لرياض الأطفال ، لكنني لا أستطيع التفكير إلا في جداول الحقيقة في الحرية ، ولكن في الأسرلدي مخطط Harlequin كامل هناك ، حيث يمكنك ببساطة أن تأخذ الجزء الذي يتم رسم U4 فيه (74HC138 ، لحسن الحظ لدي حوالي مائة منهم). سنتجاهل U11 من أجل الوضوح ، نظرًا لأن 32 كيلوبايت العلوي لا تهمنا حتى الآن.

الاتصال بسيط للغاية.



كما يتبين من الوصف الموجزتعد الدائرة المصغرة عبارة عن وحدة فك ترميز تتلقى أرقام ثنائية من 000 إلى 111 في المطاريف من 1 إلى 3 وتنشط أحد المخرجات 8 (الأرجل 7 و 9 إلى 15) المقابلة لهذا الرقم. نظرًا لأنه يمكن تخزين 8 أرقام مختلفة فقط في 3 بت ، فلا يوجد سوى ثمانية مخرجات. كما ترون ، يتم عكس الاستنتاجات ، أي أن الاستنتاج الذي سيتم تفعيله سيكون له مستوى 0V ، وجميع النتائج الأخرى + 5 فولت. بالإضافة إلى ذلك ، يتم تضمين مفتاح على شكل بوابة ذات 3 مدخلات من النوع "I" في الشريحة ، كما يتم عكس اثنين من المدخلات الثلاثة.

في حالتنا ، نقوم بتوصيل مفكك الشفرة نفسه على النحو التالي: البت الأكثر أهمية (المحطة الثالثة) على الأرض ، سيكون هناك دائمًا 0. البت الأوسط هو الخط A15. لن يكون هناك 1 إلا إذا وصل المعالج إلى 32 كيلوبايت من الذاكرة العليا (العناوين 0x8000 - 0xFFFF ، أو 1000000000000000 - 1111111111111111 في ثنائي ، عندما يتم تعيين البت الأكثر أهمية دائمًا إلى 1). نقوم بتوصيل البت الأقل أهمية بخط A14 ، حيث سيكون المستوى العالي في حالة الوصول إما إلى الذاكرة بعد أول 16 كيلوبايت ، ولكن حتى أعلى 32 كيلوبايت (العناوين 0x4000 - 0x7FFF ، أو 0100000000000000 - 0111111111111111 في شكل ثنائي) ، أو إلى أحدث 16 كيلوبايت من العنوان مسافات (عناوين 0xB000 - 0xFFFF ، أو 1100000000000000 - 1111111111111111 في شكل ثنائي).

دعونا نرى ما سيكون الناتج في كل من الحالات:

  • 14 15 , 16 , , 000, 0 ( ), Y0 (15 ). , .
  • 14 , 15 — , 16 , 32 , 001, 1 , Y1 (14 ). , 16 , .
  • 14 , 15 — , - 32 48 , 010, Y2 (13 ). , .
  • إذا كان كلا الخطين (A14 و A15) نشطين ، يصل المعالج إلى أعلى 16 كيلوبايت من الذاكرة ، من 48 إلى 64 كيلوبايت ، فنحن لا نمتلكها ، لذا فإن دبوس Y3 (دبوس 12) موجود أيضًا في الهواء.

بالإضافة إلى ذلك ، وبفضل عنصر آخر ، ستقوم الدائرة المصغرة بتفعيل نتائجها فقط إذا كانت المدخلات 4 و 5 منخفضة و 6 مرتفعة. يكون الإدخال الرابع دائمًا في الحالة المنخفضة (يتم توصيله مباشرة بالأرض) ، وسيكون الخامس منخفضًا فقط عندما يصل المعالج إلى الذاكرة (تذكر ، MREQ في الحالة المنخفضة يعني الوصول إلى الذاكرة) ، والسادس سيكون مرتفعًا عندما لا يقوم المعالج بدورة تحديث DRAM (لدينا SRAM ، لذا فإن دورات تحديث DRAM هي الطريقة الأكثر أمانًا للتجاهل فقط). اتضح عظيم.

بعد ذلك ، ضع ROM.

لقد أخذت W27C512 لأنها رخيصة ومبهجة ، وكل شيء يناسبك ، ويمكنك أيضًا التعامل مع البنك. 64 كيلوبايت! يمكن تحميل 4 البرامج الثابتة. حسنًا ، لدي حوالي مليون من هذه الدوائر المصغرة. قررت أنني سأخيط النصف العلوي فقط ، حيث أن الساق A15 في Harlequin مرتبطة بـ + 5V ، ويمكن تعديل A14 باستخدام وصلة مرور. وبالتالي ، يمكنني اختبار البرامج الثابتة على Harlequin حتى لا تعبث لفترة طويلة. ورقة بيانات سموريم . نضع الشريحة على اللوح. مرة أخرى ، أضعه في الزاوية اليمنى لوضع ناقل العنوان على اليسار. نقوم بسحب الساق A15 إلى السلطة ، وأسلاك A14 على الأرض. الأسلاك - هذا حتى تتمكن من تغيير بنوك الذاكرة. نظرًا لأن A15 ستكون دائمًا على مستوى عالٍ ، فلن تتوفر لنا سوى أفضل 32 محرك أقراص فلاش KiB. من بينها ، سيحدد خط A14 الجزء العلوي (+ 5 فولت) أو السفلي (الأرضي) 16 كيلو بايت. فيها ملأت صورة الاختبار بالمبرمجو 48 K BASIC البرامج الثابتة .

خطوط الأسطر الـ 14 المتبقية (A0 - A13) متصلة بناقل العنوان على اليسار. نقوم بتوصيل ناقل البيانات (Q0 - Q7) بحافلتنا المرتجلة في شكل حافلات كهربائية من طرازات اللوح. لا تنسى الطعام!

الآن إشارات التحكم. OE هو تمكين الإخراج. نحتاج إلى ROM لإرسال البيانات إلى ناقل البيانات عندما يقرأها المعالج. لذا نتصل مباشرة بإخراج معالج RD. بشكل ملائم ، كلا الدبابيس ، سواء OE على ROM و RD على المعالج ، نشطة في حالة منخفضة. هذا أمر مهم ، لست بحاجة إلى قلب أي شيء. بالإضافة إلى ذلك ، يحتوي ROM على إدخال CS ، نشط أيضًا في حالة منخفضة. إذا لم يكن هذا الإدخال نشطًا ، فسيتجاهل ROM جميع الإشارات الأخرى ولن يخرج أي شيء إلى ناقل البيانات. سنقوم بتوصيل هذا الإدخال إلى Y0 pin (15 pin) لشريحة 74HC138 ، والتي تكون نشطة أيضًا في الحالة المنخفضة. في دائرة Harlequin ، يتم توصيل هذه الإشارة ، لسبب ما ، من خلال المقاوم. ونحن سوف تفعل الشيء نفسه. لماذا لا اعرف. ربما يقول لي الأشخاص الأذكياء في التعليقات ... أخبروني

. شكراالستر:
. , «» . .




الكل.

الآن ذاكرة الوصول العشوائي.

إنه أكثر صعوبة ، لأنه ليس فقط المعالج ، ولكن أيضًا ULA ، أو ، في حالتنا ، Arduino ، يعمل مع ذاكرة الوصول العشوائي (مع 16 KiB). حيث أنه من الضروري قراءة شيء معروض على الشاشة. لذلك ، نحتاج إلى أن نكون قادرين على فصل إشارات التحكم وناقل عنوان RAM من المعالج. لن نفصل ناقل البيانات ، سنعمل كما في الطيف الأصلي (وفي Harlequin): سنقسم الحافلة بمقاومات (470-500 أوم). من ناحية ، ستكون المقاومات هي المعالج والروم ، من ناحية أخرى ، RAM و Arduino. وبالتالي ، في حالة وجود تعارض في ناقل البيانات ، ستعمل كحافلتين منفصلتين. لكن بالنسبة للبقية نستخدم 74HC245 ، كما في Harlequin (U43 ، U44 في الرسم التخطيطي) ، على الرغم من أن Speccy الحاليكانت هناك أيضًا مقاومات (بين IC1 من جهة ، هذه هي ULA ، و IC3 ، IC4 من ناحية أخرى).

74HC245 هو مخزن مؤقت للحافلات 8 بت. لدينا إشارتا تحكم (RD - في حالة القراءة من الذاكرة و CE لتفعيل ذاكرة الوصول العشوائي نفسها. سنتعامل مع WR في حالة الكتابة إلى الذاكرة لاحقًا) و 14 بت من العنوان: تذكر ، لقد قمنا بالفعل بإنشاء إشارة إلى الذاكرة باستخدام 74HC138 أعلاه في حالة قيام المعالج بتنشيط A14 مع عدم تنشيط A15 ، لذلك لا نحتاج إلى إجراء أي فك تشفير إضافي للعنوان ، ستعمل الذاكرة فقط عند الوصول إلى أول 16 كيلوبايت بعد ROM. حسنًا ، للتعامل مع 16 KiB ، تحتاج فقط إلى 14 سطر عنوان (A0-A13). في المجموع ، يتم الحصول على 16 إشارة ، لذلك نحتاج إلى دائرتين ميكرويتين 74HC245. نقوم بتوصيلها بلوح التوصيل على اليسار ، بدلاً من ناقل العنوان.

من ورقة البيانات الموجودة على 74HC245 ، من الواضح أنه بشكل عام ، لا يهم أي جانب لتوصيل الدوائر المصغرة ، ولكن منذ أن بدأت في إنشاء التخطيطات من الأسفل إلى الأعلى ، وتم تثبيت جميع الدوائر المصغرة الأخرى مع الدبوس الأول إلى اليسار ، سيرتبط ناقل العنوان بالجانب A (الاستنتاجات 2 -9 شرائح في ورقة البيانات تسمى A0-A7). يكون اتجاه النقل دائمًا من المعالج إلى ذاكرة الوصول العشوائي ، حيث إن ذاكرة الوصول العشوائي لا تقوم بتعيين العنوان مطلقًا ، ولكنها تستقبله فقط. في 74HC245 ، يكون الطرف 1 (DIR) مسؤولاً عن اتجاه الإرسال. وفقًا لورقة البياناتبحيث يكون على الجانب B ناتج يساوي المدخلات على الجانب A ، يجب تعيين DIR على HIGH. لذا قم بتوصيل الدبوس الأول من كلتا الدائرتين بـ + 5 فولت. يتم توصيل OE (دبوس 20 ، يتم تنشيطه بمستوى منخفض) باستخدام الأسلاك على الأرض بحيث يمكن تحويله بسرعة إلى + 5 فولت وفصله عن المعالج. أكثر بساطة. قم بتوصيل الطاقة لكلا الرقائق. ستكون الدبابيس الموجودة في أقصى اليمين من الدائرة الدقيقة اليمنى (الدبابيس 8 و 9 ، المدخلات A6 و A7) إشارات تحكم. لقد قمت بتوصيل A7 بطرف RD للمعالج ، و A6 بطرف Y1 لشريحة 74HC138 ، حيث سيكون هناك مستوى منخفض فقط عندما يصل المعالج إلى ذاكرة الوصول العشوائي الخاصة بنا. الاستنتاجات المتبقية من الجانب A لكلا من الدوائر المصغرة (الأرجل 2-9 لليسار والأرجل 2-7 لليمين) قمت بتوصيلها إلى ناقل العنوان ، المحطات A13-A0. لا نحتاج إلى البتتين العلويتين من العنوان ، لأنهما تم فك شفرتهما بالفعل في الإشارة من 74HC138.الآن عن ذاكرة الوصول العشوائي نفسها. بطبيعة الحال ، استخدمت ما كان لدي بالفعل: شريحة ذاكرة تخزين مؤقت من اللوحة الأم القديمة. جئت عبرIS61C256 عند 20 نانو ثانية ، لكن أيًا منها سيفعل. عملت سبيسي بتردد 3.5 ميغاهيرتز ، ولكن في الوقت الحالي سنتعامل مع أردوينكي بشكل عام. إذا خرج 100 كيلو هرتز ، ستكون هناك سعادة! لذا ، نحن نتواصل. بالطبع ، لا تنسى الطعام. الاستنتاجات I / O0 - I / O7 متصلة بلوح توصيل ناقل البيانات بعد المقاومات. كنت محظوظًا (في الواقع ، ليس) ، في نماذجي الصينية ، تم تقسيم حافلات الطاقة في الوسط بالضبط. لقد استخدمت هذه الميزة لفصل الحافلة مع المقاومات. إذا كانت تخطيطاتك خاطئة ، يجب أن تكون منحرفًاعمل ناقل بيانات ثان ، وربطه بالمقاومات إلى الأول. يتم طرح استنتاجات A0-A13 في استنتاجات B المقابلة لرقائق 74HC245 ، مع عدم نسيان أن أقصى اليمين متصل ليس بنقل البيانات ، ولكن بإشارات التحكم. A14 - عن طريق الاختيار ، إما على الأرض ، أو +5 فولت. شريحة 32 KiB ، لذا فإن هذا الاستنتاج سيحدد النصف الذي سنستخدمه. إذا وجدت 16 KiB SRAM ، فلن يكون هناك خط A14 فيه. المخرجات هي WE (تمكين الكتابة) و CE (تمكين الشريحة) و OE (تمكين الإخراج). يتم تنشيط جميع منخفضة. يجب أن يكون OE متصلاً ب RD المعالج ، ولكن ، بالطبع ، ليس بشكل مباشر ، ولكن من خلال 74HC245 الأيمن ، حيث يأتي RD إلى قدم A7 ، وبالتالي يخرج من B7 قدم (دبوس 11). هناك والاتصال. يجب توصيل CE بـ Y1 من 74HC138 ، الذي يقوم بفك تشفير العنوان. تأتي إشارتها لي على A6 من الشريحة اليمنى 74HC245 ، على التوالي ،يخرج من القدم B6 (12 دبابيس). قمنا بالاتصال مباشرة بإخراج معالج WR. لقد قمت أيضًا بتثبيت سلك توصيل من إشارة OE وتمسكه في الجزء غير المستخدم من لوحة التوصيل. من خلال توصيل هذا السلك بأرضية الطاقة ، يمكنني تنشيط RAM عند قراءتها من Arduinka. ومع ذلك ، قمت بسحب جميع إشارات التحكم في ذاكرة الوصول العشوائي إلى + 5 فولت باستخدام مقاومات 10 كيلو أوم. فقط في حالة. اتضح مثل هذا:



بشكل عام ، هنا ، وإذا كان الأمر على الإطلاق ، في البداية ، يجب أن يكون هناك برنامج تعليمي حول توقيت الإشارات على الإطارات. لن أفعل ذلك ، حيث تم إجراؤه مرات عديدة على الشبكة من قبل أشخاص أكثر ذكاء مني. للمهتمين ، يمكنني أن أوصي بهذا الفيديو:


بشكل عام ، إذا لم تكن مشتركًا في هذه القناة وكنت مهتمًا بالإلكترونيات بصفتك أحد الهواة ، وليس كمحترف ، فإنني أوصي بها بشدة. هذا محتوى عالي الجودة.

بشكل عام ، هذا كل شيء تقريبًا. الآن تحتاج فقط إلى فهم كيفية قراءة البيانات من ذاكرة الوصول العشوائي في Arduino. بادئ ذي بدء ، دعونا نحسب عدد استنتاجات Arduinki التي نحتاجها. نحتاج إلى إعطاء إشارة على مدار الساعة والتحكم في RESET ، وهما دبابيس. 8 بتات من ناقل البيانات - 8 دبابيس أخرى. بالإضافة إلى 13 بت من العنوان ، إجمالي 23 دبابيس. بالإضافة إلى ذلك ، نحن بحاجة إلى التواصل مع Arduinka ، سنقوم بذلك من خلال واجهتها التسلسلية ، وهذا هو دبابيس أخرى. لسوء الحظ ، لا يوجد سوى 20 استنتاجًا بشأن الحمض النووي الخاص بي.

حسنًا ، لا يهم. لا أعرف شخصًا واحدًا لديه أردوينو وليس لديه 74HC595. يبدو لي أنها تباع فقط في المجموعة. على الأقل لدي فقط رقائق 74HC00 أكثر من 595x. لذلك نستخدمها. علاوة على ذلك ، سأوفر مساحة في المقالة ، لأن عمل 595x مع اردوينو موصوف تمامًا هنا. 595mi سنقوم بإنشاء العنوان. ستحتاج الشريحة إلى قطعتين (نظرًا لأن لدينا 13 بتًا من العنوان ، و 595 تحتوي على 8 دبابيس). تم شرح كيفية توصيل عدة 595 مرة لتوسيع الناقل بالتفصيل على الرابط أعلاه. ألاحظ فقط أنه في الأمثلة على هذا الرابط يتم سحب OE (pin 13) 595x إلى الأرض. لن نقوم بذلك بشكل قاطع ، سنرسل إشارة من Arduinki هناك ، حيث سيتم توصيل دبابيس 595x مباشرة بناقل عنوان ذاكرة الوصول العشوائي ، ولا نحتاج إلى أي إشارة زائفة هناك. بعد توصيل دبابيس 595x بناقل عنوان ذاكرة الوصول العشوائي ، لا يوجد شيء آخر يجب القيام به على النماذج. حان الوقت لربط اردوينكا. لكن أولاً ، اكتب رسماً تخطيطياً:

// CPU defines
#define CPU_CLOCK_PIN 2
#define CPU_RESET_PIN 3

// RAM defines
#define RAM_OUTPUT_ENABLE_PIN 4
#define RAM_WRITE_ENABLE_PIN 5
#define RAM_CHIP_ENABLE_PIN 6
#define RAM_BUFFER_PIN 7

// Shift Register defines
#define SR_DATA_PIN 8
#define SR_OUTPUT_ENABLE_PIN 9
#define SR_LATCH_PIN 10
#define SR_CLOCK_PIN 11

//////////////////////////////////////////////////////////////////////////

void setup() {
  // All CPU and RAM control signals need to be configured as inputs by default
  // and only changed to outputs when used.
  // Shift register control signals may be preconfigured

  // CPU controls seetup
  DDRC = B00000000;
  pinMode(CPU_CLOCK_PIN, INPUT);
  pinMode(CPU_RESET_PIN, INPUT);

  // RAM setup
  pinMode(RAM_WRITE_ENABLE_PIN, INPUT);
  pinMode(RAM_OUTPUT_ENABLE_PIN, INPUT);
  pinMode(RAM_CHIP_ENABLE_PIN, INPUT);
  pinMode(RAM_BUFFER_PIN, OUTPUT);
  digitalWrite(RAM_BUFFER_PIN, LOW);

  // SR setup
  pinMode(SR_LATCH_PIN, OUTPUT);
  pinMode(SR_CLOCK_PIN, OUTPUT);
  pinMode(SR_DATA_PIN, OUTPUT);
  pinMode(SR_OUTPUT_ENABLE_PIN, OUTPUT);
  digitalWrite(SR_OUTPUT_ENABLE_PIN, HIGH); // active low

  // common setup
  Serial.begin(9600);
  Serial.println("Hello");
}// setup

//////////////////////////////////////////////////////////////////////////

void shiftReadValueFromAddress(uint16_t address, uint8_t *value) {
  // disable RAM output
  pinMode(RAM_WRITE_ENABLE_PIN, OUTPUT);
  digitalWrite(RAM_WRITE_ENABLE_PIN, HIGH); // active low
  pinMode(RAM_OUTPUT_ENABLE_PIN, OUTPUT);
  digitalWrite(RAM_OUTPUT_ENABLE_PIN, HIGH); // active low
  // set address
  digitalWrite(SR_LATCH_PIN, LOW);
  shiftOut(SR_DATA_PIN, SR_CLOCK_PIN, MSBFIRST, address>>8); 
  shiftOut(SR_DATA_PIN, SR_CLOCK_PIN, MSBFIRST, address);  
  digitalWrite(SR_LATCH_PIN, HIGH);
  digitalWrite(SR_OUTPUT_ENABLE_PIN, LOW); // active low
  // write value to RAM
  digitalWrite(RAM_OUTPUT_ENABLE_PIN, LOW); // active low
  delay(1);
  DDRC = B00000000;
  *value = PINC;
  digitalWrite(RAM_OUTPUT_ENABLE_PIN, HIGH); // active low
  // disable SR
  digitalWrite(SR_OUTPUT_ENABLE_PIN, HIGH); // active low
  pinMode(RAM_WRITE_ENABLE_PIN, INPUT);
  pinMode(RAM_OUTPUT_ENABLE_PIN, INPUT);
}// shiftWriteValueToAddress

//////////////////////////////////////////////////////////////////////////

void runClock(uint32_t cycles) {
  uint32_t currCycle = 0;
  pinMode(CPU_CLOCK_PIN, OUTPUT);
  while(currCycle < cycles) {
    digitalWrite(CPU_CLOCK_PIN, HIGH);
    digitalWrite(CPU_CLOCK_PIN, LOW);
    currCycle++;
  }
  pinMode(CPU_CLOCK_PIN, INPUT);
}// runClock

//////////////////////////////////////////////////////////////////////////

void trySpectrum() {
  pinMode(RAM_WRITE_ENABLE_PIN, INPUT);
  pinMode(RAM_OUTPUT_ENABLE_PIN, INPUT);
  pinMode(CPU_RESET_PIN, OUTPUT);
  digitalWrite(CPU_RESET_PIN, LOW);
  runClock(30);
  digitalWrite(CPU_RESET_PIN, HIGH);
  runClock(12500000);
}// trySpectrum

//////////////////////////////////////////////////////////////////////////

void readDisplayLines() {
  uint8_t value;
  digitalWrite(RAM_BUFFER_PIN, HIGH);
  pinMode(RAM_CHIP_ENABLE_PIN, OUTPUT);
  digitalWrite(RAM_CHIP_ENABLE_PIN, LOW);
  for(uint16_t i=16384; i<16384+6144;i++) {
    shiftReadValueFromAddress(i, &value);
    Serial.println(value);
  }
  pinMode(RAM_CHIP_ENABLE_PIN, INPUT);
}// readDisplayLines

//////////////////////////////////////////////////////////////////////////

void loop() {
  trySpectrum();
  Serial.println("Hope we are ok now. Please set up memory for reading");
  delay(40000);
  Serial.println("Reading memory");
  readDisplayLines();
  Serial.println("Done");
  delay(100000);
}// loop

كما ترون من الرسم (حسنا ، حقا ، فجأة ، قرأه شخص ما) ، قرأت ناقل البيانات إلى المنفذ C. كما يمكن أن يتذكر Arduischik ، في CID المنفذ C هو 6 دبابيس. أي ، قرأت 6 بت فقط. نعم ، من أجل بساطة العملية ، أتجاهل البتتين العاليتين في كل بايت من ذاكرة التخزين المؤقت للشاشة. سينتج عن ذلك حقيقة أنه كل 2 بكسل بعد 6 سيكون هناك دائمًا ألوان خلفية. أثناء الركوب ، ثم أصلحه. هذا هو الهيكل العظمي.

الآن للاتصال نفسه. من حيث المبدأ ، يتم رسم كل شيء في أعلى الرسم التخطيطي:

// CPU defines
#define CPU_CLOCK_PIN 2 -  2     6  ( )
#define CPU_RESET_PIN 3 -  3     26  (RESET)

// RAM defines
#define RAM_OUTPUT_ENABLE_PIN 4 -  4     22  (OE)
#define RAM_WRITE_ENABLE_PIN 5 -  5    .     .
#define RAM_CHIP_ENABLE_PIN 6 -  6     .        ,        .   - ,   -  .   ,   .
#define RAM_BUFFER_PIN 7 -  ,    6,    .

// Shift Register defines
#define SR_DATA_PIN 8   -  8     14 "" 595.        9 ,     .
#define SR_OUTPUT_ENABLE_PIN 9 -   13  595
#define SR_LATCH_PIN 10 -   12  595
#define SR_CLOCK_PIN 11 -   11  595.

كل شيء بسيط. إليك كيف يبدو أنني قد تم تجميعها جميعًا (تم قطع



Arduino في الصورة ، ولكن لا يوجد شيء خاص لمشاهدته): عند بدء التشغيل ، سيقول Arduino بمرحًا للمنفذ التسلسلي للكمبيوتر (وإن كان افتراضيًا) ، وسيبدأ في تعذيب المعالج. بعد أن عذبه تمامًا (بضع دقائق) ، سيوقف البرنامج المسكين وسيعرض عليك إعادة ترتيب القفزات مع الأقلام الموجودة على اللوح ، وفصل الذاكرة عن ناقل العنوان وإشارات التحكم في المعالج.

نحتاج الآن إلى استخدام المقابض لإعادة ترتيب الأسلاك المتصلة بالدبابيس 19 لكل من 74HC245 من الأرض إلى + 5 فولت. وبالتالي ، نقوم بفصل المعالج عن ذاكرة الوصول العشوائي. يجب توصيل دبوس 22 من شريحة ذاكرة الوصول العشوائي نفسها بالأرض (لقد كتبت أعلاه عن الأسلاك ، التي علقتها للتو في لوحة التوصيل حتى الآن ، في مكان غير مستخدم). وبالتالي ، نقوم بتشغيل ذاكرة الوصول العشوائي بالقوة.

بعد ذلك ، بعد الانتظار قليلاً ، سيبدأ Arduinka في قراءة محتويات الذاكرة وإخراجها في عمود إلى المنفذ التسلسلي. سيكون هناك العديد من الأرقام. الآن يمكنك نسخ هذه البيانات من هناك ولصقها ، على سبيل المثال ، في ملف نصي ، دون نسيان تنظيف جميع النصوص غير الضرورية (سطرين في الأعلى و "تم" في الأسفل) ، نحن بحاجة إلى أرقام فقط. هذا ما سجلته Speccy في ذاكرة الفيديو. يبقى فقط لمعرفة ما هو موجود في ذاكرة الفيديو. وذاكرة فيديو الطيف ليست سهلة ...

كما ترى ، يتم تخزين وحدات البكسل نفسها بشكل منفصل عن اللون. سنتجاهل اللون في الوقت الحالي ، فلنقرأ فقط وحدات البكسل نفسها. لكن ليس من السهل فك شفرتها. بعد الكثير من الألم في Visual Studio ، جئت إلى هذا الحل الأنيق:


#include "stdafx.h"
#include <windows.h>
#include <stdint.h>
#include <stdio.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
uint8_t *scrData;

VOID OnPaint(HDC hdc) {
	size_t arrSize = 6144;//sizeof(scrData) / sizeof(scrData[0]);
	//int currRow = 0, currX = 0, currBlock = 0, currY = 0, currBase = 0;
	for (size_t arrPos = 0; arrPos < arrSize; arrPos++) {
		int blockPos = arrPos % 2048;
		int currBase = (blockPos % 256) / 32;
		int currX = blockPos % 32;
		int currBlock = arrPos / 2048;
		int currRow = blockPos / 256;
		int currY = currBlock * 64 + currBase * 8 + currRow;
		for (int trueX = 0; trueX < 8; trueX++) {
			char r = ((scrData[arrPos] >> trueX) & 1)*255;
			SetPixel(hdc, currX * 8 + (8-trueX), currY, RGB(r, r, r));
		}
	}
}

void loadData() {
	FILE *file;
	errno_t err;
	if ((err = fopen_s(&file, "data.txt", "r"))) {
		MessageBox(NULL, L"Unable to oopen the file", L"Error", 1);
	}
	scrData = (uint8_t*)malloc(6144);
	int currDataPos = 0;
	char buffer[256];
	char currChar = 0;
	int currLinePos = 0;
	while (currChar != EOF) {
		currChar = getc(file);
		buffer[currLinePos++] = currChar;
		if (currChar == '\n') {
			buffer[currLinePos] = 0;
			scrData[currDataPos++] = (uint8_t)atoi(buffer);
			currLinePos = 0;
		}
	}
	fclose(file);
}

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow) {
	HWND                hWnd;
	MSG                 msg;
	WNDCLASS            wndClass;
	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = WndProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = hInstance;
	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = TEXT("GettingStarted");
	RegisterClass(&wndClass);
	hWnd = CreateWindow(
		TEXT("GettingStarted"),   // window class name
		TEXT("Getting Started"),  // window caption
		WS_OVERLAPPEDWINDOW,      // window style
		CW_USEDEFAULT,            // initial x position
		CW_USEDEFAULT,            // initial y position
		CW_USEDEFAULT,            // initial x size
		CW_USEDEFAULT,            // initial y size
		NULL,                     // parent window handle
		NULL,                     // window menu handle
		hInstance,                // program instance handle
		NULL);                    // creation parameters
	loadData();
	ShowWindow(hWnd, iCmdShow);
	UpdateWindow(hWnd);
	while (GetMessage(&msg, NULL, 0, 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}  // WinMain

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
	HDC          hdc;
	PAINTSTRUCT  ps;
	switch (message) {
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		OnPaint(hdc);
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
} // WndProc

يقوم البرنامج بفتح ملف data.txt من الدليل الخاص به. في هذا الملف ، إخراج النص من اردوينو (بعد حذف جميع الأسطر الإضافية ، كما هو مذكور أعلاه).

نحن نطعمه الملف الناتج ، ونتيجة لذلك:



نعم ، في حين أن النتيجة بعيدة جدًا عن المثالية ، لكنها بالتأكيد الإخراج على الشاشة. علاوة على ذلك ، ما هو مطلوب. من ROM مع البرامج الثابتة التشخيصية.

حسنًا ، هيكل الكمبيوتر جاهز. نعم ، من المستحيل استخدامه حتى الآن ، ولكن يمكنك أن ترى مدى بساطة ترتيب أجهزة الكمبيوتر القديمة ذات 8 بت. ما زلت أتغلب قليلاً على اللوح ، لكن الاستنتاج أصبح أسوأ. يبدو أن الخطوة التالية هي اللحام على لوحة توصيل عادية غير ملحومة ، بطاقة عادية.

لكن هل هو ضروري؟

All Articles