
الهندسة العكسية للبرامج الثابتة لمولدات الدوال Philips PM5139 / PM5138A / PM5136: محاكيات 8051 المستخدمة كأجهزة قياس، و35 قسمًا من العتاد الموثّق، وبرنامج ثابت V2.0 مصحّح
مولّد دوال 20 ميجاهرتز من حوالي عام 1994، مُفكَّك على مستوى البرمجيات: نسختان من تفريغ EPROM، ومحاكي 8051 يُستخدم كأداة قياس، و35 قسمًا من التوثيق حيث كل ادعاء مدعوم بعنوان إدراج، أو قياس من المحاكي، أو المخطط الكهربائي.
في النهاية يوجد برنامج ثابت V2.0 يُصلح عيبًا شحنته Philips، وست موجات اعتباطية من صنعنا، ومحاكي متصفح يشغّل ROM الأصلي تعليمة بتعليمة.

كل جدول موجات في EPROM البرنامج، مرسوم مباشرة من الملف الثنائي. أسفل اليمين هو الجدول الذي بدأ الجزء الأكثر إثارة في هذا المشروع.
Philips PM5139 هو الطراز الأعلى بتردد 20 ميجاهرتز من عائلة من ثلاثة أجهزة (PM5136 / PM5138A / PM5139). في الداخل توجد PCB80C652 — نواة 8051 مع I²C عتادي — وEPROM برنامج من نوع 27512، وست تجميعات تماثلية معلّقة على ناقل تسلسلي.
لا يوجد دليل خدمة لـ PM5139. الناس يبحثون عنه في المنتديات منذ عام 2010. ما هو موجود هو دليل PM5138A، الطراز الشقيق بتردد 10 ميجاهرتز، وهو متطابق داخليًا تقريبًا.
لذا بدأ هذا المشروع من الطرف الآخر: تفريغ EPROM، ومعرفة ما يفعله الكود حتى يُفهم الجهاز جيدًا بما يكفي لتعديله.
كانت هناك نسختان من البرنامج الثابت متاحتان، V1.3 و V1.5، وكلتاهما من نوع M27512 بحجم 64 كيبي بايت.
| التفكيك | مكتمل لكلا الإصدارين، حوالي 23 000 سطر، مع إحالات مرجعية متقاطعة |
| الإدراج المشروح | 147 روتينًا مسمّى، 145 تعليق رأس، 3 826 سطرًا مشروحًا |
| التوثيق | 35 قسمًا، 4 600 سطر، كل ادعاء موثّق المصدر |
| مسار الإشارة | التردد، السعة، الإزاحة، AM، FM، النبضة، التناظر، المسح — كلها محسوبة ومتحقق منها مقابل الكود الأصلي |
| العتاد | جميع الـ 10 strobes، ناقل C، I²C مع كل مشارك، المنافذ، لوحة المفاتيح، المقبض الدوّار، خريطة العرض النقطية |
| بتات الحالة | 75 من 128 بتأثير موثّق |
| فرق الإصدارات | V1.3 مقابل V1.5 متطابقان بنيويًا بنسبة 91.4 %؛ كل تغيير مسمّى |
| المحاكيات | واحد بـ Python، وآخر بـ JavaScript (حوالي 8 ملايين تعليمة/ث)، بالإضافة إلى محاكي متصفح بملف واحد |
| برنامجنا الثابت | V2.0 — عيب مصنعي مُصلَح، checksum مُعالَج، متحقق منه في المحاكي وعلى العتاد الحقيقي |
| الموضع | النوع | الوظيفة |
|---|---|---|
| D301 | PCB80C652 | نواة 8051 مع I²C عتادي، 12 ميجاهرتز |
| D306 | 27512 | EPROM البرنامج — V1.3 يشغل 0000h–AC70h |
| D310 | X28C64 | EEPROM اعتباطي على ناقل MOVX |
| D305 | PCF8570 | 256 بايت من NVRAM مدعومة ببطارية على I²C (A0h) |
| D304-A | PCF8576 | مشغّل LCD على I²C (70h)، مخزن مؤقت 20 بايت |
| D302-A | SAA3007 | مُرمّز لوحة المفاتيح، مُرمّز بعرض النبضة على خط واحد |
| D307 | 74HCT4514 | مُفكّك strobe — رقم strobe هو بتات العنوان A8…A11 |
الجانب التماثلي هو ناقل C تسلسلي: يعمل UART الخاص بـ 8051 في وضع
سجل الإزاحة، TXD هو الساعة، RXD هو البيانات، وstrobe يقرر أي
من سجلات الإزاحة العشرة يلتقط البايتات. MOV DPH,#8nh متبوعًا بـ
MOVX @DPTR,A يُطلق strobe رقم n. هذا السطر الواحد هو مفتاح
القسم التماثلي بأكمله.
هذا هو الجزء الذي يستحق أن تسرقه لمشروعك الخاص.
قراءة ملف ثنائي 8051 بحجم 44 كيبي بايت بالعين توصلك ربما إلى ثلث الطريق. كل ما بعد ذلك جاء من تشغيل الكود الأصلي ومراقبة ما ينتج عنه:```python
c = CPU(rom) for w in test_values: set_amplitude(c, w) c.call(0x0AAC) # the original routine, untouched print(w, c.ram[0x1C]) # the byte that goes out on STR9
تنويع المدخلات، وقراءة المخرجات، والتحقق منها مقابل الفرضية. نجح ذلك مع التردد والسعة والإزاحة وعمق AM وانحراف FM وعدد النبضات والتماثل وخاصيتي المسح. كل صيغة في التوثيق تأتي مع نقاط العينة التي تم التحقق منها.
ثلاث تحسينات جعلته منتجًا فعليًا:
**راقب الناقل، لا الشاشة.** يقيس القسم 15 ما تفعله بتة الحالة بمخزن الشاشة، ويبدو أن 74 من 128 بتة لا تفعل شيئًا. لكن الكثير منها لا يقود الشاشة، بل يقود *التجميعات التناظرية* — وهذه لا تكون مرئية إلا كبرقيات على ناقل C. أدى تسجيل `MOV SBUF,…` و`MOVX @DPTR` المنهي إلى رفع عدد البتات الموثقة من 54 إلى 75.
**اضغط المفاتيح، لا تعبث بالذاكرة.** إعداد بايت ذاكرة يدويًا ينتج حالات لا يتخذها الجهاز أبدًا. كلفنا ذلك نتيجتين خاطئتين وانهيارًا واحدًا في جدول الأوامر. حقن رموز مفاتيح حقيقية عبر SAA3007 المحاكى يعطي حالات يصل إليها البرنامج الثابت فعليًا — وكان مسح القوة الغاشمة عبر جميع رموز المفاتيح الـ256 هو ما كشف أي مفتاح يفعّل أي معالج.
**اشك في المحاكي الخاص بك أولًا.** أنتجت ثلاثة أخطاء في نواتنا سلوكًا "غير قابل للتفسير" في البرنامج الثابت: تنفيذ `ACALL` كـ`AJMP`، وغياب علم الحمل المساعد (فأساء `DA A` التصرف وبدا البرنامج الثابت وكأنه يعد بالنظام الثنائي)، ومقاطعة لوحة مفاتيح مضاعفة. أُعيد قياس كل نتيجة من تلك الفترة بعد ذلك.
---
## الطريق إلى هنا
**الثابت أولًا.** مفكك شيفرة بجدول أكواد كامل، ثم النزول التكراري مع استدلالات جداول القفز. أنتج ذلك 30,508 بايت من الشيفرة وترك 13,637 بايت غير محسوبة.
**ثم الديناميكي.** تشغيل تتبع — بدء بارد، جميع مفاتيح اللوحة الأمامية الـ23، كلا اتجاهي المقبض، كل وضع تشغيل، 86 مليون دورة — مع تعليم كل عنوان نُفذ فعليًا. عند مقارنته بالتحليل الثابت، وجد بالضبط **منطقة واحدة** فاتت النزول، وتبين أن 10,686 من البايتات غير المفسرة هي خمس كتل جداول معروفة.
**ثم المخططات.** التعرف الضوئي على نص دليل الصيانة عديم الفائدة للمخططات، لكن صور الصفحات بدقة 400 نقطة في البوصة ممتازة. عند تقطيعها إلى بلاطات متداخلة، تصبح مقروءة حتى أرقام المنافذ. قُرئت ست صفحات بهذه الطريقة — وحيث تمتد خمسة مسارات متوازية بفاصل 90 بكسل، استُبدل الفحص البصري بسكربت (`lines.py`) يستخرج قطع الخطوط من الصورة النقطية.
**ثم الشريحتان المنتزعتان.** قُرئ 27C64 موسوم بـ"SINUS 1.1" وX28C64. وُضع كلاهما في المخطط وفُكّ محتواهما.
**ثم مقارنة الإصدارات.** تقطيع كلا الـROMين إلى رموز (مسافات القفز النسبي بدلًا من الأهداف المطلقة) وتشغيل `SequenceMatcher` عليهما يعطي تعيين عناوين يصمد أمام حركة الشيفرة — وهكذا تُنقل رموز V1.3 إلى V1.5.
---
## الأجزاء الجيدة
### Philips شحنت موجة مشوشة
تقع المنحنيات الثلاثة العشوائية المدمجة عند `A047h` و`A447h` و`A847h`. للثالث نفس شكل جدول موجود أصلًا في الـROM بصيغة محسوبة — لكن بـ**563 تغير اتجاه مقابل 13**، وانحراف معياري قدره 4.1 LSB.
أُخذت عيناتها من مصدر تناظري بدلًا من حسابها. متوسط الانحراف صفر، ونقطتان فقط من 1024 تنحرفان بأكثر من 10 — هذه ليست موجة مختلفة، بل هي الموجة *نفسها* مع ضجيج عليها.
### ذلك الجدول سلّم مستويات بـ30 dB
وُصفت النسخة النظيفة في مسودة سابقة بأنها "جيبية بعشرة أعماق AM"، وكان ذلك قراءة بصرية للرسم البياني، لا شيئًا تقوله الشيفرة. عند حسابها بالكامل، تنقسم النقاط الـ1024 إلى عشرة أقواس جيبية تمتد مسافاتها```
255 171 120 80 56 38 26 17 12 8
سلسلة هندسية بنسبة 0.681 = 10^(−1/6)، أي 3.33 dB لكل خطوة و30.1 dB إجمالاً. نموذج التنصيف يخطئ بما يصل إلى 56، ونموذج 3 dB بمقدار 10. إنه سلّم مستويات لوغاريتمي — نمط اختبار سعة أو تخفيف.