أول التجارب باستخدام بروتوكول الدفق على سبيل المثال من وحدة المعالجة المركزية والاتصالات المعالج في Redd FPGA



في المقالات السابقة ، التقينا بالفعل مع ناقل Avalon-MM ، حيث يرمز MM إلى الذاكرة المعينة ، أي المسقطة على الذاكرة. هذا الاطار متعدد الاستعمالات يمكن توصيل العديد من الأجهزة الرئيسية (الرئيسية) والعديد من أجهزة الرقيق بها. لقد قمنا بالفعل بتوصيل جهازين رائدين في نفس الوقت (Instruction Master و Data Master) ، نظرًا لأن معالج NIOS II بهندسة هارفارد ، وبالتالي فإن حافلات القيادة والبيانات الخاصة به مختلفة ، لكن العديد من المؤلفين يربطونهم بنفس الجهاز المشترك لتبسيط تطوير البرامج من الخارج إلى الحافلة.

إذا كانت إحدى الكتل الموجودة في الحافلة تحتوي على وظيفة الوصول المباشر للذاكرة (DMA) ، فستحتوي أيضًا على رسالة ماجستير للحافلة.

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



جميع مقالات الدورة:

  1. تطوير أبسط "البرامج الثابتة" لأجهزة FPGA المثبتة في Redd ، وتصحيح الأخطاء باستخدام اختبار الذاكرة كمثال
  2. تطوير أبسط "البرامج الثابتة" لأجهزة FPGA المثبتة في Redd. الجزء 2. رمز البرنامج
  3. تطوير جوهرها الخاص لتضمينها في نظام المعالج على أساس FPGA
  4. تطوير برامج للمعالج المركزي Redd على سبيل المثال من الوصول إلى FPGA

إن وثيقة Avalon Interface للمواصفات المعروفة بالفعل لدينا (بشكل عام ، لا أعطي روابط مباشرة ، حيث إنها تتغير دائمًا ، وبالتالي فإن الشبكة بأكملها مليئة بمقالات تحتوي على روابط ميتة ، من الأسهل العثور على الموضع الحالي من خلال دفع الاسم في محرك البحث) إلى أنه بالإضافة إلى ناقل Avalon-MM ، هناك أيضًا حافلة Avalon-ST ، حيث ST تعني Stream ، أي البث. والحقيقة هي أنه في كثير من الأحيان البيانات المرسلة لديها هيكل تيار. نعم ، حتى القطاع الكلاسيكي من القرص الصلب. لها حجم ثابت. يجب أن يتم تمريرها من البداية إلى النهاية. حتى إذا نظرنا إليها في المنطقة القابلة للعنونة ، فإن العناوين ستزيد خطيًا. وإذا كنت تستخدم كتلة FIFO للتخزين ، فإن العناوين الموجودة داخله تكون مخفية تمامًا عنا. هم ، لكن العمل معهم ليس شاغلنا.

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



وإليك الإشارات النموذجية لهذا الحافلة:



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

يتضح أيضًا من الوثائق أن هناك ثلاث إشارات أخرى ممكنة ، مما يضيف إلى الناقل خصائص نقل الحزم المحددة بوضوح:



بشكل عام ، يعد الإطار ممتعًا للغاية ، واليوم سنبدأ التجارب عليه. كما نعلم بالفعل ، يتم توصيل FPGA بحافلة USB في مجمع Redd عبر جسر FT2232H الذي يعمل في وضع FT245-SYNC . بالمعنى الدقيق للكلمة ، البيانات التي تمر عبر هذه الواجهة هي تدفق البيانات تماما. اليوم سوف نتعلم كيفية نقل هذه البيانات إلى نظام المعالج لدينا على أساس NIOS II. من المؤسف أن بروتوكول FT245-SYNC ، على الرغم من التدفق ، لا يتوافق تمامًا مع ناقل Avalon-ST . لحفظ أرجل الرقاقة ، تحتوي على ناقل بيانات ثنائي الاتجاه ، ويكون ناقل Avalon-ST أحادي الاتجاه. لذلك ، يتعين علينا إنشاء كتلة تنسق البروتوكولات بشكل وثيق ولكن لا تطابقها.

لقد تعرفنا بالفعل على بروتوكول FT245-SYNC في إحدى المقالات السابقة . اسمح لي أن أذكرك بأنه يمكن العثور على وصفه في المستند AN_130 FT2232H المستخدم في وضع FIFO المتزامن نمط FT245 . فيما يلي مخطط توقيت نموذجي للإرسال من جسر إلى FPGA



بشكل عام ، كمبرمج ، أنا مهتم جدًا بحقيقة أن الحزمة التي تم إرسالها كانت ستحدد بوضوح البداية والنهاية. حسنًا ، لجعله أكثر منطقية في منطق بروتوكول UDP ، لأنه إذا كان الإرسال في نمط TCP ، فسيتعين عليك إضافة بيانات مرجعية خاصة إلى البث ، والتي سيتم إنفاقها على البرمجة والجهد ودورات المعالج ... يبدو خط RXF يمكن أن تساعدنا في هذا. نحن نتحقق ... نحن نملأ "البرامج الثابتة" في FPGA لقياس الأداء ، المحرز في المقالة السابقة ، وربط مسبار الذبذبات بخط RXF. كبرنامج اختبار للمعالج Redd المركزي ، نستخدم القاعدة ، التي تستخدم أيضًا لقياس الأداء ، وبدلاً من إرسال كميات كبيرة من البيانات ، نرسل كتلة أحادية من 0x400 بايت.

uint8_t temp [maxBlockSize]; memset (temp,0,sizeof (temp)); uint32_t dwWritten; FT_Write(ftHandle0, temp, 0x400, &dwWritten); 

نحصل على الصورة التالية على خط RXF:



من الواضح أن الدائرة الصغيرة تستقبل 0x200 بايت من المخزن المؤقت (وهذا هو مقدار ما يمكن أن تأتي في حزمة واحدة USB2.0 HS) ، ثم يرسلها إلى القناة. بشكل عام ، هذا غريب ، حيث أن الوثائق تنص على أنه يتم استخدام اثنين من المخازن المؤقتة في كل اتجاه. أثناء الإرسال ، يجب أن يكون لدى المخزن المؤقت الثاني وقت لملء. للأسف. نهاية ملء لها متأخرة بشكل واضح. في الواقع ، يوضح هذا سبب عدم وصول الأداء إلى 52 ميجابايت نظريًا في الثانية: لا يتم نقل نسبة كبيرة من الوقت (وإن لم يكن 50٪).

لكن بطريقة أو بأخرى ، ووجدنا أنه من الممكن اكتشاف بداية الحزمة على حافة RXF سالبة فقط إذا كان حجم الحزمة لا يتجاوز 0x200 بايت. إذا أرسلنا أوامر فقط مع كمية صغيرة من البيانات إلى الجهاز ، فهذا أمر ممكن التحقيق. ولكن إذا أرسلنا تدفقات كبيرة من البيانات ، فسوف يتعين علينا استخدام قناة مستمرة ، على غرار منطقها لـ UART (أو ، على سبيل المثال ، قناة TCP) ، مع إبراز حدود الرزم بشكل برمجي بحت.

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



لقد بدأنا في تطوير آلية تلقائية ستنفذ المنطق الذي نحتاجه ببطء. بالطبع ، في هذا المقال سيتم تبسيط هذا المنطق إلى أقصى حد. لنبدأ بنقل البيانات من FPGA إلى جهاز الكمبيوتر ، لأن هذه العملية أبسط قليلاً (لا تحتاج إلى تبديل حالة خط OE ، التي تحدثنا عنها في المقال الأخير ). أي أننا ننفذ منفذ Sink.

من جانب حافلة Avalon-ST ، اخترت وضع التشغيل التالي (يوجد عدد كبير منهم في المستند ، ولكن هذا هو الأقرب إلى الواجهة مع FT245-SYNC ):



اسمحوا لي أن أذكرك اتجاه الإشارات:



وهذا هو ، نحن فقط ننتظر التأكيد على الحافلة ( صالح ) ، انقر على البيانات وبوابة هذه الحقيقة مع خط جاهز .

من الجانب FT245_FIFO ، يبدو البروتوكول كما يلي:



اتضح أننا يجب أن ننتظر إشارة TXE ونوصل البيانات بإشارة WR # (القطبية معكوسة لكلتا هاتين الإشارات).

يشبه TXE # في الأداء الوظيفي جاهز ، و WR # صالح . التفاصيل مختلفة بعض الشيء ، ولكن المنطق مشابه.

اتضح أننا نستطيع أن نحدد حالة واحدة منفردة toPC ، حيث سيتم تنفيذ أبسط عمليات تبديل لبعض الخطوط. شرط الدخول إلى هذه الحالة هو استعداد كلا الطرفين للإرسال ، أي (TXE # == 0) AND (صالح == 1). بمجرد اختفاء بعض الاستعداد ، نخرج مرة أخرى إلى الخمول.

لا يزال الرسم البياني الانتقالي للأوتوماتون بسيطًا:



يشبه جدول التبديل هذا (حيث تكون أسماء الإشارات غامضة ، وتضاف إليها مؤشرات ، حيث تكون الأسماء فريدة - لا توجد مؤشرات):

إشارةحالة ToPCشروط أخرى
WR #لا (صالح)1
readySinkلا (TXE #)0
DATAFT245_FIFODataSinkZ


الانتقال إلى نقل أكثر تعقيدًا قليلاً من المصدر إلى FT245_FIFO. كما رأينا في المقالة السابقة ، فإن المضاعفات هي تبديل الاتجاه بإشارة OE #:



بالنسبة إلى حافلة Avalon_ST ، كل شيء هو نفسه كما كان من قبل ، لذلك لا يتم عرض الصور مرة ثانية ، لكننا الآن في وضع المصدر.

هنا ، يتوافق سطر RXF # مع الخط الصحيح ، بينما يتوافق السطر RD # مع الخط الجاهز . حسنًا ، قم بإضافة بضع حالات إلى الجهاز:



والمنطق التالي للإشارات النشطة في هذه الحالة:

إشارةdropOEfromPCشروط أخرى
عمر الفاروق001
رقم RD1لا (جاهزة)1
مصدر بياناتأي قيمةDATAFT245_FIFOأي قيمة
مصدر صالح0لا (RXF #)0

من الواضح أن المخطط لم يكن الأكثر مثالية. هناك العديد من الفروق الدقيقة المرتبطة بتجاوزات المخزن المؤقت أو تجاوزات المخزن المؤقت. ولكن لا ينبغي أن يكون هناك أي نوع من فقدان البيانات ، ولكن بالنسبة إلى الأمثلية ، يجب أن تبدأ في مكان ما!

نبدأ في نقل النظرية المتقدمة إلى رمز SystemVerilog. صحيح ، لا يمكننا استخدام جميع ميزات SystemVerilog. كانت هناك حالة ، كتبت مقالة كبيرة ، حيث اختبرت التركيب العملي للميزات الجميلة لهذه اللغة مع بيئة تطوير حقيقية. هنا نطلب فقط استخدام واجهات ، لأن النظام سيكون له مثيلان من نوع Avalon-ST . للأسف وآه. هنا هو رمز الاختبار:
 interface AvalonST #(parameter width=8)(input clk); logic [width-1:0] data; logic ready; logic valid; modport source (input clk, ready, output data,valid); modport sink (input clk, data, valid, output ready); endinterface module FT245toAvalonST ( AvalonST.source source, AvalonST.sink sink ); //assign source.ready = sink.valid; assign sink.ready = source.valid; endmodule 

يتم توليفه بالكامل في برنامج التحويل البرمجي الرئيسي (يؤدي سطر التعليق عند حذف تعليق إلى حدوث خطأ في التأكد من أن برنامج المزج يفسر كل شيء بشكل صحيح) ، ولكن عند التحقق من زر تحليل ملفات التوليف لمكون لهذه الشفرة ، يتم إنشاء خطأ أن نوع AvalonST غير معروف. وهذا هو ، لا يوجد تحليل على SystemVerilog ، ولكن على Verilog النقي. ياله من المؤسف.



علاوة على ذلك ، يتم تحديد اللغة بشكل صحيح ، فقط المحلل لا يفهم الواجهات بين المنافذ.



بشكل عام ، يجب عليك استخدام بناء الجملة القديم القبيح.

باستخدام بناء الجملة هذا ، نحصل على واجهة الوحدة النمطية التالية:
 module FT245toAvalonST ( input clk, input reset, inout [7:0] ft245_data, input logic ft245_rxf, input logic ft245_txe, output logic ft245_rd, output logic ft245_wr, output logic ft245_oe, output logic ft245_siwu, input logic source_ready, output logic source_valid, output logic[7:0] source_data, output logic sink_ready, input logic sink_valid, input logic[7:0] sink_data ); 


وقح ، عتيقة ، ولكن ماذا يمكنك أن تفعل.

ندرك الرسم البياني انتقال الأوتوماتون دون أي زخرفة:
 //    enum {idle, toPC, dropOE, fromPC} state = idle; //     always_ff @(posedge clk,posedge reset) begin if (reset == 1) begin state <= idle; end else begin case (state) idle: begin if ((ft245_txe == 0) && (sink_valid == 1)) state <= toPC; else if ((ft245_rxf == 0)&&(source_ready == 1)) state <= dropOE; end toPC: begin if (!((ft245_txe == 0) && (sink_valid == 1))) state <= idle; end dropOE: begin state <= fromPC; end fromPC: begin if (!((ft245_rxf == 0)&&(source_ready == 1))) state <= idle; end endcase end end 


السيطرة على المخرجات ، ومع ذلك ، يتطلب بعض التفسير.

جزء من المنشآت يتم "على الجبهة":
 //    //   ,        , //  -    . always_comb begin ft245_oe <= 1; ft245_rd <= 1; ft245_wr <= 1; source_valid <= 0; sink_ready <= 0; //     , //     assign- case (state) idle: begin end toPC: begin ft245_wr <= !(sink_valid); sink_ready <= !(ft245_txe); end dropOE: begin ft245_oe <= 0; end fromPC: begin ft245_oe <= 0; ft245_rd <= !(source_ready); source_valid <= !(ft245_rxf); end endcase end 


ولكن ، على سبيل المثال ، بالنسبة لحافلة البيانات ثنائية الاتجاه ، يجب تطبيق حل نموذجي. كما نتذكر ، تم إعلانه في جزء الواجهة كما يلي:

  inout [7:0] ft245_data, 

والقراءة منه يمكن القيام به بالطريقة المعتادة. بالنسبة لحالتنا ، نحن ببساطة نلتف جميع البيانات على بيانات حافلة Avalon-ST الصادرة:

 //          assign source_data = ft245_data; 

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

 //      inout- assign ft245_data = (state == toPC) ? sink_data : 8'hzz; 

وإشارة أخرى ft245_siwu. لا نستخدمها أبدًا ، لذلك وفقًا للوثائق الموجودة على FT2232H ، اسحبه إلى الوحدة:

 //   FTDI : // Tie this pin to VCCIO if not used. assign ft245_siwu = 1; 

في الواقع ، هذا كل شيء.

الوحدة بأكملها تبدو مثل هذا:
 module FT245toAvalonST ( input clk, input reset, inout [7:0] ft245_data, input logic ft245_rxf, input logic ft245_txe, output logic ft245_rd, output logic ft245_wr, output logic ft245_oe, output logic ft245_siwu, input logic source_ready, output logic source_valid, output logic[7:0] source_data, output logic sink_ready, input logic sink_valid, input logic[7:0] sink_data ); //    enum {idle, toPC, dropOE, fromPC} state = idle; //     always_ff @(posedge clk,posedge reset) begin if (reset == 1) begin state <= idle; end else begin case (state) idle: begin if ((ft245_txe == 0) && (sink_valid == 1)) state <= toPC; else if ((ft245_rxf == 0)&&(source_ready == 1)) state <= dropOE; end toPC: begin if (!((ft245_txe == 0) && (sink_valid == 1))) state <= idle; end dropOE: begin state <= fromPC; end fromPC: begin if (!((ft245_rxf == 0)&&(source_ready == 1))) state <= idle; end endcase end end //    //   ,        , //  -    . always_comb begin ft245_oe <= 1; ft245_rd <= 1; ft245_wr <= 1; source_valid <= 0; sink_ready <= 0; //     , //     assign- case (state) idle: begin end toPC: begin ft245_wr <= !(sink_valid); sink_ready <= !(ft245_txe); end dropOE: begin ft245_oe <= 0; end fromPC: begin ft245_oe <= 0; ft245_rd <= !(source_ready); source_valid <= !(ft245_rxf); end endcase end // -  c  ,   ... //   FTDI : // Tie this pin to VCCIO if not used. assign ft245_siwu = 1; //      inout- assign ft245_data = (state == toPC) ? sink_data : 8'hzz; //          assign source_data = ft245_data; endmodule 


كيفية تضمين الوحدة النمطية في قائمة المتاحة للاستخدام في نظام المعالج ، درسنا بالتفصيل في واحدة من المقالات السابقة ، لذلك أنا فقط تظهر النتيجة في الشكل. أذكر أنه من أجل تحقيق ذلك ، اضطررت إلى إضافة حافلتين AVALON-ST ، حافلة واحدة Conduit ، وسحب إشارات من حافلة AVALON-MM محددة خطأ ، وعندما لا توجد إشارة واحدة متبقية في هذا الحافلة ، فقط احذفها. على طول الطريق ، يوضح الشكل الإعدادات التي اخترتها للحافلات AVALON-ST (8 بت لكل رمز ، بدون أخطاء ، الحد الأقصى للقناة هو صفر ، الكمون هو صفر).



مع تطوير وحدة نمطية لإطارات الإرساء - هذا كل شيء. ولكن للأسف ، آه. لتطوير ليست سوى بداية العمل. التنفيذ أصعب بكثير. كما يتبين من موضع سكرولر على الشاشة ، لا تزال نهاية المقالة بعيدة. لذلك ، بدأنا في إنشاء مشروع بسيط يستخدم وصلة ناقل FT245-SYNC مع حافلات AVALON-ST . هذا هو أبسط. لا يتناسب المشروع الجاد مع إطار مادة واحدة ذات حجم معقول. سأقوم الآن بالتبسيط بعد التبسيط ببساطة بحيث يكون انتباه القراء كافياً لبقية النص حتى لا يتوقفوا عن القراءة في كلمة واحدة. التبسيط الأول هو أن الساعات 60 MHz لشاشة FT245_SYNC يتم إنشاؤها بواسطة شريحة FT2232H نفسها . يمكنني إضافة خطين على مدار الساعة إلى النظام ، ولكن بمجرد أن يراه الجميع ، سيكون لدينا خيوط من الأسلاك لا تحزنها أمي. إذا كنت ما زلت أهتم بخطوط الساعة المختلفة ، فسوف نشعر بالارتباك. لذلك ، أعلن ببساطة أن نظام المعالج الخاص بنا سوف يعمل اليوم من شريحة FT2232H ، وليس من مولد عادي.

لماذا لا تستطيع أن تفعل ذلك دائما؟ بسيط للغاية: طالما أن FT2232H ليس في وضع 245_SYNC ، فإنه لا يحتوي على هذه النبضات في الإخراج. أي ، يجب عليك أولاً تشغيل البرنامج للمعالج المركزي ، وبعد ذلك فقط يتم تحميل كل شيء في FPGA. إذا أردنا إنشاء نظام لعميل خارجي ، فإن هذا الحل سيخلق الكثير من المشاكل. أعلم من التجربة أنهم سوف يتصلون بنا بانتظام ويقولون إنه لا يوجد شيء ناجح ، لكننا نود تذكيرك بالحانات ، لكن ذلك سيساعد لفترة من الوقت. لكننا نقوم بعمل داخلي ، وسوف نستخدمه فقط في ظروف المختبر. وهذا هو ، في إطار هذه المهمة ، وهذا مسموح به.

لكن هذا يجلب تحديات جديدة. لدينا تردد 60 MHz ، وترتبط كتلة ساعة SDRAM التي نستخدمها حاليًا بتردد 50 MHz. نعم ، لقد حددت ، يمكن إرسال 60 ، ولكن دعنا ندعي أننا نحاول عدم تجاوز الأوضاع المسموح بها. في المقالات التالية ، سأحاول إظهار كيفية استبدال هذه الكتلة الثابتة ، ولكن اليوم نقول فقط إنه نظرًا لأن وحدة الساعة لدينا من SDRAM لا يمكنها العمل على التردد المستخدم ، فإننا نستبعده من نظام معالج SDRAM. سيتم وضع البرنامج وبياناته بالكامل في الذاكرة الداخلية لـ FPGA. لقد وجد تجريبياً أنه في تهيئة اليوم ، يمكن أن يستغرق FPGAs ما يصل إلى 28 كيلوبايت كحد أقصى من ذاكرة الوصول العشوائي لهذا العمل. اتضح أنه يمكنك أن تأخذ مجلدات وليس قوى متعددة لاثنين ...

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

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



حيث تم ضبط التردد للساعة وكتلة إعادة الضبط:



وللذاكرة RAM - الحجم:



اليوم نحن بحاجة إلى عرض النص في المحطة. لذلك ، سوف نضيف هذه الكتلة المثيرة للاهتمام إلى النظام:



مع هذه الكتلة ، سنكون قادرين على استدعاء وظائف مشابهة لـ printf. بالإضافة إلى ناقل AVALON_MM ، يجب أيضًا توصيل إخراج طلب المقاطعة.



هذا كل شيء ، اكتمال المشتريات لنظام المعالج. حان الوقت لتضمين وحدتنا. أين سوف يرسل البيانات؟ من بين الكتل المتاحة لنا ، هناك ذاكرة FIFO مثيرة للاهتمام للغاية ذات منفذين. يكمن سحره في حقيقة أنه يمكن تهيئة منفذ واحد لوضع AVALON-ST وتوصيله بوحدتنا ، والثاني بوضع AVALON_MM والعمل معه باستخدام معالج NIOS II. تقع هذه الكتلة الرائعة هنا:



لدينا حافلتان Avalon-ST (واحدة للقراءة ، والآخر للكتابة) ، لذلك نحن بحاجة أيضًا إلى مربعين FIFO. الآن سوف أتطرق إلى أحدهم بتفصيل كبير ، نقوم بإعداد بضعة كيلومترات من الويب (ومجموعة من الشاشات النصية مع الصور) ، ونقول في الثانية عن ذلك "يمكن القيام بذلك عن طريق القياس" ، مع الإشارة إلى الاختلافات فقط. لذلك ، في الوقت الحالي ، نضيف كتلة واحدة فقط إلى النظام وننظر حوله إلى إعداداته. هناك الكثير من الإعدادات. قد يكون من الممكن الإشارة ببساطة إلى القيم المطلوبة بحيث يشير الجميع إلى المقالة كمرجع ، ولكن فجأة يصطدم شخص ما بموقف يحتاج إلى تهيئته ، ولكن لا يمكن الوصول إلى الشبكة (وبالتالي ، المقالة). لذلك ، سأضيف الإعدادات بشكل متكرر. من الواضح أولاً ، إذن - وفقًا لما يتطلبه النظام ، قم بإجراء الحوار مرارًا وتكرارًا. سيشعر الجميع بهذه العملية وسيكون بمقدورهم تكرارها في أي وقت. هكذا. بشكل افتراضي ، حصلنا على الإعدادات التالية:



سأفعل الآن FIFO ، التي تجمع البيانات من Avalon-ST ، وتحميلها إلى Avalon-MM . اتضح أن التعديل الأول سيكون مثل هذا:



حصلت على هذا التحذير المثير للاهتمام:



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



التالي هو القدرة. افترض أن قائمة الانتظار 256 كلمة (أي 1024 بايت):



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



وقبض على الخطأ:



حسنا اذن إضافة قطع مسافة السباق مزدوجة. ما عليك سوى توصيل كلا المدخلات بنفس خط الساعة ، نظرًا لأن لدينا واحدًا.
Ufff. المجموع لدينا:



ولكن من السابق لأوانه ربط هذا العمل بالنظام الموحد. كما اكتشفنا ، تترك الحافلة Avalon-ST ذات 8 بتات الكتلة التي قمنا بتطويرها ، ويجب أن تشمل الحافلة 32 بت. كيف نكون؟ إعادة تشكيل كتلة الخاص بك؟ لا! لقد تم كل شيء من قبلنا. هنا ما سوف يساعدنا:



إضافته إلى النظام. علاوة على ذلك ، نظرًا لأنها طبقة ، بحتة للجمال ، فنحن نضعها بين الكتلة والـ FIFO ، باستخدام السهم المقابل:



نقوم بالإعدادات التالية: عند الإدخال لدينا ناقل 8 بت ، على الإخراج 32 بت. لا تستخدم إشارات الحزمة ، وتستخدم إشارات جاهزة وصالحة .



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



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



حسنًا ... والآن ، وفقًا لنفس المبدأ ، نضيف FIFO لإصدار البيانات إلى FT245SYNC . هناك فقط ، تصل البيانات إلى FIFO من Avalon-MM في شكل 32 بت. إنهم يمرون عبر محول 32 في 8 ومن ثم يصلون إلى إدخال SINK الخاص بالكتلة الخاصة بنا ، وهو غير متصل في الدائرة الحالية ... نحصل على الجزء التالي من الدائرة النهائية (انتهت الذاكرة هناك مع ساعة واحدة):



مزيد من الإجراءات التي عملنا عليها بالفعل بشكل جيد في التجارب الموضحة في المقالات السابقة ( بالنسبة للجزء الأكبر - في هذا واحد ). نخصص المتجهات للمعالج. بالنسبة للنظام ، فإننا نسمي التعيين التلقائي لأرقام وعناوين المقاطعة. نقوم بحفظ النظام ... يتذكر الجميع أن اسم النظام المحفوظ يجب أن يتطابق مع اسم المشروع بحيث يكون النظام في المستوى الأعلى من التسلسل الهرمي؟ إضافة النظام إلى المشروع ، وجعل مشروع تقريبي للمشروع ، وتعيين الساقين. شخصيا ، لقد خدعت: لقد قمت بنسخ المهام من ملف * .qsf لمشروع المسودة إلى المرحلة النهائية الحالية (ويمكنك تنفيذ مشروعي ونسخ خطوط * .qsf المقابلة لك ، ولكن يمكنك ببساطة تعيين جميع الأرجل عبر واجهة المستخدم الرسومية). أود إيلاء اهتمام خاص لحقيقة أن إشارة clk متصلة الساق 23 ، وليس 25 ، كما هو الحال في المشاريع السابقة. أذكرك أننا هنا نقر من إخراج FT2232.



عظيم! الجهاز جاهز. نمر إلى البرنامج. من أين نبدأ؟ اليوم هذا السؤال لا يستحق كل هذا العناء. إذا بدأنا ببرنامج يعمل على معالج NIOS II ، فلن ينجح شيء بالنسبة لنا. أولاً ، يجب وضع FT2232 في وضع 245-SYNC ، وعندها فقط سيتلقى نظام المعالج نبضات الساعة. لذلك ، نبدأ برمز المعالج المركزي.

نحصل على شيء مثل هذا:
 #include <cstdio> #include <sys/time.h> #include <unistd.h> #include "ftd2xx.h" FT_HANDLE OpenFT2232H() { FT_HANDLE ftHandle0; static FT_DEVICE ftDevice; //      int nDevice = 0; while (true) { //     if (FT_Open(nDevice, &ftHandle0) != FT_OK) { printf("No FT2232 found\n"); //  ,      return 0; } //     ? if (FT_GetDeviceInfo(ftHandle0, &ftDevice, NULL, NULL, NULL, NULL) == FT_OK) { // ,    if (ftDevice == FT_DEVICE_2232H) { // ,     AN130 FT_SetBitMode(ftHandle0, 0xff, 0x00); usleep(1000000); //Sync FIFO mode FT_SetBitMode(ftHandle0, 0xff, 0x40); FT_SetLatencyTimer(ftHandle0, 2); FT_SetUSBParameters(ftHandle0, 0x10000, 0x10000); return ftHandle0; } } //    FT_Close(ftHandle0); //    nDevice += 1; } printf("No FT2232 found\n"); } int main() { FT_HANDLE ftHandle0 = OpenFT2232H(); if (ftHandle0 == 0) { printf("Cannot open device\n"); return -1; } int item; bool bWork = true; while (bWork) { printf("1 - Send 16 bytes\n"); printf("2 - Send 256 bytes\n"); printf("3 - Receive loop\n"); printf("0 - Exit\n"); scanf("%d", &item); switch (item) { case 0: bWork = false; break; case 1: { static const unsigned char data[0x10] = { 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; DWORD dwWritten; FT_Write(ftHandle0, (void*)data, sizeof(data), &dwWritten); } break; case 2: { unsigned char data[0x100]; for (size_t i = 0; i < sizeof(data); i++) { data[i] = (unsigned char)i; } DWORD dwWritten; FT_Write(ftHandle0, (void*)data, sizeof(data), &dwWritten); } break; case 3: { DWORD dwRxBytes; DWORD dwRead; DWORD buf[0x100]; while (true) { FT_GetQueueStatus(ftHandle0, &dwRxBytes); if (dwRxBytes != 0) { printf("Received %d bytes (%d DWORDs)\n", dwRxBytes, dwRxBytes / sizeof(buf[0])); if (dwRxBytes > sizeof(buf)) { dwRxBytes = sizeof(buf); } FT_Read(ftHandle0, buf, dwRxBytes, &dwRead); for (DWORD i = 0; i < dwRxBytes / sizeof(buf[0]);i++) { printf("0x%X, ",buf[i]); } printf("\n"); } } } break; } } // ,    FT_Close(ftHandle0); return 0; } 


وظيفة OpenFT2232H () مألوفة لنا من المادة الأخيرة . هي التي تفتح جهاز FT2232 وتضعه في الوضع الذي نحتاجه. مباشرة بعد الإطلاق الناجح للبرنامج ، نحصل على نبضات على مدار الساعة ، ومعهم القدرة على تصحيح البرنامج الخاص بـ NIOS II. حسنا ، وظيفة الوظيفة الرئيسية هي بسيطة مثل البراز. أرسل بعض البيانات (1) ، أرسل الكثير من البيانات (2) ، استقبل البيانات (3). يرجى ملاحظة أن جميع البيانات يتم إرسالها في كتل من مضاعفات أربعة بايت. هذا كله لأن لدينا محول 8 في 32. عند الخروج منه ، يجب أن تذهب البيانات بكلمات مزدوجة. خلاف ذلك ، كل شيء واضح.

NIOS II BSP. , Hello World Small. BSP ( BSP, ). , , , Settings, .



Generate BSP , , hello_world_small.c hello_world_small.cpp , , .

( , FIFO, — , , ). . — NIOS II. :

 extern "C" { #include "sys/alt_stdio.h" #include <system.h> #include <altera_avalon_fifo_util.h> } #include <stdint.h> int main() { while (1) { int level = IORD_ALTERA_AVALON_FIFO_LEVEL(FIFO_0_OUT_CSR_BASE); if (level != 0) { alt_printf("0x%x words received:\n",level); for (int i=0;i<level;i++) { alt_printf("0x%x,",IORD_ALTERA_AVALON_FIFO_DATA (FIFO_0_OUT_BASE)); } alt_printf("\n"); } } /* Event loop never exits. */ while (1); return 0; } 

FIFO. , .
. , . Redd «» , NIOS II. :



, . , . , , . FT2232, , . . : FT245-SYNC .

1. , :

0x2 words received:
0x3020100,0x7060504,
0x2 words received:
0xb0a0908,0xf0e0d0c,


:

0x3 words received:
0x3020100,0x7060504,0xb0a0908,
0x1 words received:
0xf0e0d0c,


, 1, 3 , . , , . , , JTAG — . , . , ( , ? ), (FIFO — , , ).

Little Endian. , :

 static const unsigned char data[0x10] = { 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; 

هذا صحيح. 2, ( , ):

 0x3 words received: 0x3020100,0x7060504,0xb0a0908, 0x3d words received: 0xf0e0d0c, 0x13121110,0x17161514,0x1b1a1918,0x1f1e1d1c, 0x23222120,0x27262524,0x2b2a2928,0x2f2e2d2c, 0x33323130,0x37363534,0x3b3a3938,0x3f3e3d3c, 0x43424140,0x47464544,0x4b4a4948,0x4f4e4d4c, 0x53525150,0x57565554,0x5b5a5958,0x5f5e5d5c, 0x63626160,0x67666564,0x6b6a6968,0x6f6e6d6c, 0x73727170,0x77767574,0x7b7a7978,0x7f7e7d7c, 0x83828180,0x87868584,0x8b8a8988,0x8f8e8d8c, 0x93929190,0x97969594,0x9b9a9998,0x9f9e9d9c, 0xa3a2a1a0,0xa7a6a5a4,0xabaaa9a8,0xafaeadac, 0xb3b2b1b0,0xb7b6b5b4,0xbbbab9b8,0xbfbebdbc, 0xc3c2c1c0,0xc7c6c5c4,0xcbcac9c8,0xcfcecdcc, 0xd3d2d1d0,0xd7d6d5d4,0xdbdad9d8,0xdfdedddc, 0xe3e2e1e0,0xe7e6e5e4,0xebeae9e8,0xefeeedec, 0xf3f2f1f0,0xf7f6f5f4,0xfbfaf9f8,0xfffefdfc, 

. . NIOS II :

  /*  -  2 */ uint32_t buf[] = {0x11223344,0x55667788,0x99aabbcc,0xddeeff00}; for (uint32_t i=0;i<sizeof(buf)/sizeof(buf[0]);i++) { IOWR_ALTERA_AVALON_FIFO_DATA (FIFO_1_IN_BASE,buf[i]); } 

3 NIOS II. :

Received 16 bytes (4 DWORDs)

0x11223344, 0x55667788, 0x99AABBCC, 0xDDEEFF00,


. - .

استنتاج


Avalon-ST . Redd , . . .

. , , Redd.

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


All Articles