سؤال

أنا جديد جدًا على لغة HDL. لدي سؤال حول كيفية برمجة سجل التحول. (أعلم أنني تحول إلى الاتجاه الآخر). لماذا يستخدم الكتاب wire[N-1:0] r_next؟ ما هو عيب تنفيذي؟ شكرًا

محاولتي الأولى على النحو التالي

module lesson04#(parameter N=8)(
    input wire clk, reset,
    input wire data,
    output wire out
);

reg [N-1: 0] r_reg;


always @(posedge clk or negedge reset)
begin
    if(!reset)
         r_reg =0;
    else 
        r_reg[0]=data;
        r_reg = r_reg<<1;
end

assign out =r_reg[N-1];
endmodule 

لكن الكتاب يعطي:

module lesson04#(parameter N=8)(
    input wire clk, reset,
    input wire data,
    output wire out
);

reg [N-1: 0] r_reg;
wire[N-1:0] r_next;

always @(posedge clk or negedge reset)
begin
    if(!reset)
         r_reg =0;
    else 
        r_reg <= r_next;
end

assign r_next= {data, r_reg[N-1:1]};
assign out =r_reg[N-1];
endmodule
هل كانت مفيدة؟

المحلول

بادئ ذي بدء ، لا تنسى begin-endS حول أقسام الكود:

else begin
     r_reg[0]=data;
     r_reg = r_reg<<1;
end

بدون هذا فقط r_reg[0]=data سيكون في else بند if بيان. سيعمل هذا ، ولكن يعتبر أسلوبًا سيئًا بسبب عبارات الحظر في وصف منطقي متسلسل ...

ثانياً ، لنمذجة الكتل المتسلسلة ، استخدم المهام غير المحظورة (<=) أو قد "تمر" حساباتك (Google Non Locklocking مقابل حظر مزيد من المعلومات). قد ينجح مثالك جيدًا (هل جربته في جهاز محاكاة؟) ولكن إذا أصبحت الأمور أكثر تعقيدًا وإضافة المزيد من المتغيرات التي يمكن أن تنكسرها الأشياء.

always @(posedge clk or negedge reset)
begin
    if(!reset)
         r_reg <= 0;
    else begin // This is horrible! Don't write code like this!
        r_reg[0] = data;     // blocking
        r_reg <= r_reg<<1;   // non-blocking
    end
end

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

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

أيضًا ، إذا كانت إعادة تعيينك منخفضة (أي LOW إعادة ضبط) يجب تسميتها على هذا النحو ، على سبيل المثال resetb أو reset_n.

نصائح أخرى

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

بالمناسبة لديك بادئة always كتلة ، لقد قادت إلى الاعتقاد بأنه ليس ما تريد. هذه هي الطريقة التي تتصرف بها كتلةك حقًا:

always @(posedge clk or negedge reset)
begin
    if(!reset) begin
         r_reg =0;
    end else begin
        r_reg[0]=data;
    end
    r_reg = r_reg<<1;
end

أنا دائما أستخدم صراحة begin/end الكلمات الرئيسية في if/else بيانات لتجنب هذا الالتباس.

الطريقة التي تحاكي بها r_reg دائمًا ما يكون 0 لأنك تعبر عن المهمة الأولى (r_reg[0]=data;) مع الثاني (r_reg = r_reg<<1;). فرق آخر هو أن الكتاب يعين data إلى MSB لسجل Shift ، لكنك تقوم بتعيينه إلى LSB.

إذا كنت تستخدم أدوات Licent Linting and Synthesis ، فمن المحتمل أن تحصل على مجموعة من التحذيرات لكودك. هذا من شأنه أن ينبهك لإجراء بعض التغييرات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top