1 - سطح گیت
جلسه اول (ماژول ها) جلسه دوم (گیت ها) جلسه سوم (نوع سیگنال) جلسه چهارم (پایان فصل)2 - مقداردهی مداوم
جلسه پنجم (اُپراتور ها) جلسه ششم (آرایه ها) جلسه هفتم (شرط ها) جلسه هشتم (فراخوانی ماژول) جلسه نهم (تست بنچ) جلسه دهم (نگاشت حافظه)3 - سطح رفتاری (ترکیبی)
جلسه یازدهم (بلاک Always) جلسه دوازدهم (ابزار ها) جلسه سیزدهم (نوع پردازش) جلسه چهاردهم (نکات تکمیلی) جلسه پانزدهم (پایان فصل)4 - سطح رفتاری (ترتیبی)
جلسه شانزدهم (لبه ها) جلسه هفدهم (تست بنچ 2) جلسه هجدهم (شمارنده ها) جلسه نوزدهم (ضرب و شیفت) جلسه بیستم (استیت ماشین) جلسه بیست و یکم (کشف رشته) جلسه بیست و دوم (فرکانس) جلسه بیست و سوم (نان بلاک) جلسه بیست و چهارم (پایان)5 - جلسات تمرینی
جلسه تمرین اول (تاخیر ها) جلسه تمرین دوم (الحاق-منطق) جلسه تمرین سوم (شیفت ها) جلسه تمرین چهارم (استیت)6 - مثال های پروژه محور
پروژه طراحی پردازنده RTL پروژه پردازنده Maano پروژه پردازنده MIPS7 - ارتباط و گفتگو
ارتباط با نویسنده گروه تلگرام تبلیغات و آگهیآموزش وریلاگ آموزش Verilog
رسیدیم به آخرین و البته جذاب ترین فصل آموزش وریلاگ ، مدار های دیجیتالی معمولا یا ترکیبی هستن یا ترتیبی ، ترکیبی یعنی سیگنال های ما بصورت مداوم و همیشه باید مقداردهی بشن ، اما ترتیبی یعنی مداراتی که سیگنال های اون فقط در لبه های کلاک مقدار دهی میشن و تا وقتی کلاک بعدی نیومده ، مقدار سیگنال ها تغییری نمی کنه . این فصل میریم سراغ پیاده سازی یا توصیف مدارات ترتیبی .
به شکل بالا نگاه کنید ، یه سیگنال کلاک داریم که لبه های بالای کلاک با رنگ آبی مشخص شده ، ما توی وریلاگ می تونیم مشخص کنیم که سیگنال های ما ، هروقت لبه ی بالا کلاک اومد ، مقداردهی بشن .
همینطور توی این شکل لبه های پایین کلاک با رنگ آبی مشخص شده و می تونیم بگیم هرگاه لبه پایین کلاک رُخ داد ، سیگنال های ما مقادیر جدید رو بگیرند. البته این نکته هم بگم اینطور نیست که ما فقط با لبه های کلاک کار داشته باشیم گاهی وقتا یه سیگنال معمولی (مثلا Carry در یک جمع کننده ) هم میشه از لبه اش استفاده کرد. مثلا بگیم هر وقت لبه بالارونده Carry رخ داد (یعنی هر وقت سیگنال Carry از صفر یهو یک شد) ، یه سری کارها انجام بشه.
بی خیال ، اگه فهمیدین چیشد چه بهتر ، اگه نفهمیدین بریم توی مثال تا داستان روشن شه . شکل بالا یه شمارنده 16 بیتی هست که قراره از 0 تا 65535 بشماره . در واقع هم X و هم Y جفت شون قراره این شمارش رو انجام بدن ، ورودی مدار هم چیزی جز کلاک نیست .
1- 2- 3- 4- 5- 6- 7- 8- 9- 10- 11- 12- 13- 14- 15- 16- 17- 18- 19- 20- 21- 22- 23-
module Counter( input Clk, output reg [15:0] X, output reg [15:0] Y ); initial begin X=0; Y=0; end always begin X=X+1; end always @(posedge Clk) begin Y=Y+1; end endmodule
ورودی مدار رو مشخص میکنیم که Clk هست ، قراره وقتی مقدار کلاک 0 یا 1 باشه هیچ اتفاقی نیفته اما وقتی مقدار کلاک یهو از 0 به 1 میره ، توی اون لبه بالارونده یه واحد به شمارنده اضافه بشه . توی خط 7 مقدار اولیه X و Y رو صفر میکنیم تا شمارش ما از 0 آغاز بشه . حالا اینجا من از دوتا بلاک استفاده کردم ، یکی always که بصورت همیشگی میاد یدونه به X اضافه میکنه و اصلا با کلاک کاری نداره ، یه بلاک always دیگه هم داریم که گفتیم فقط در لبه بالارونده کلاک یدونه به Y اضافه کنه . چیزی که توی خروجی میبینیم اینه که ، سیگنال X مقدار نامشخصی خواهد داشت ، چرا ؟ چون با سرعت نور داره بهش یدونه یدونه اضافه میشه و ما اصلا نمیفهمیم هر لحظه چه مقداری داره ، با تمام قوا و توان در هر کلاک شاید میلیون ها بار به عدد X اضافه بشه . اما سیگنال Y فقط وقتی لبه کلاک بیاد ، یدونه بهش اضافه میشه ، مثلا اگه دوره تناوب کلاک ما 1 ثانیه باشه ، هر ثانیه یدونه به Y اضافه میشه .
به شکل بالا نگاه کنید ، تقریبا همون شمارنده قبلی هست ، با این تفاوت که یدونه حباب روی ورودی کلاک اضافه شده (دایره آبی رنگ) ، توی دیجیتال اگه دیدین روی سیگنالی حباب گذاشتن یعنی اون سیگنال وقتی صفر بود وظیفه شو انجام بده ، مثلا اگه سیگنال ریست بود یعنی وظیفه ریست شدن مدار باید وقتی انجام بشه که سیگنال ریست مقدارش 0 هست ، اگه حباب نبود وظیفه ریست شدن مدار وقتی رخ میداد که سیگنال ریست مقدارش 1 باشه . اما داستان این حباب برای ورودی های کلاک اینه که وقتی حباب دیدین یعنی مدار تون با لبه پایین رونده کلاک کار کنه ، اگه هم مثل مثال قبلی حباب نبود ، با لبه بالارونده کلاک کار کنه .
1- 2- 3- 4- 5- 6- 7- 8- 9- 10- 11- 12- 13- 14- 15- 16-
module Counter( input Clk, output reg [15:0] Y ); initial begin Y=0; end always @(negedge Clk) begin Y=Y+1; end endmodule
خب این هم کد وریلاگ این شمارنده ، فقط بجای posedge از negedge که بیانگر لبه پایین هست ، استفاده کردیم . یه نکته دیگه اینکه من بارها بهتون گفتم ، اصلا زیبا نیست توی کد مون از بلاک initial استفاده کنیم چون قابلیت پیاده سازی واقعی نداره و تو دنیای واقعی نمیشه همچین کاری کرد ، هرچند توی نرم افزار و شبیه سازی این کد شما ایراد نداره و بهتون خروجی میده اما بیاین واقعی تر کار کنیم . معمولا توی مدارات ترتیبی برای مشخص کردن مقادیر اولیه سیگنال های خروجی ، بجای اینکه از initial استفاده کنند ، میان یه سیگنال ورودی جدید تعریف میکنن به اسم ریست و میگن هر وقت ریست فعال بود مقادیر اولیه به سیگنال های خروجی داده بشه . پس ازین به بعد من توی مثال های بعدی همیشه یک سیگنال ریست توی مدار میذارم که تکلیف مقادیر اولیه رو روشن کنه .
به شکل بالا نگاه کنین یه دی فلیپ فلاپ هست ، کارش چیه ؟ هر بار که لبه کلاک میاد اگه ریست فعال باشه ، خروجی شو صفر میکنه ولی اگه ریست فعال نبود ، به ورودی D نگاه میکنه ، اگه D صفر بود ، خروجی Q رو صفر میکنه و اگه D یک بود خروجی Q رو یک میکنه . به عبارتی میشه گفت هر وقت لبه کلاک که میاد Q برابر با D میشه .البته یه خروجی دیگه هم داره به اسم Q پریم ، که مقدارش همیشه معکوسه Q هست.
1- 2- 3- 4- 5- 6- 7- 8- 9- 10- 11- 12- 13- 14- 15- 16- 17- 18- 19-
module DFF( input Clk, input Rst, input D, output reg Q, output Qp ); assign Qp=~Q; always @(posedge Clk) begin if (Rst==0) Q=0; else Q=D; end endmodule
طبق کد بالا ، هرگاه لبه بالارونده کلاک بیاد ، یک شرط بررسی میشه ، اگه ریست فعال باشه (یعنی صفر باشه ، چرا صفر ؟ چون حباب داره) خروجی ما 0 و اگه ریست غیر فعال ( مقدار 1 ) باشه خروجی ما برابر با ورودی D خواهد بود . توی خط 9 هم مشخص کردیم که خروجی Qپریم ، همیشه معکوسه Q باشه .
شکل بالا یه فلیپ فلاپ نوع JK هست که هنگام لبه کلاک با توجه به مقدار ورودی های J و K مشخص میشه که خروجی ما چه مقداری داشته باشه . اگه J و K هر دو صفر باشند خروجی ما برابر با خودش میشه (حفظ مقدار قبلی) ، اگه هر دو یک باشند ، خروجی ما معکوس (نات) میشه و اگه فقط J یک باشه خروجی ما یک میشه و اگه فقط K یک باشه خروجی ما صفر میشه .
1- 2- 3- 4- 5- 6- 7- 8- 9- 10- 11- 12- 13- 14- 15- 16- 17- 18- 19- 20- 21- 22- 23- 24- 25- 26- 27- 28- 29-
module JKFF( input Clk, input Rst, input J, input K, output reg Q, output Qp ); assign Qp=~Q; always @(posedge Clk) begin if (Rst==0) Q=0; else begin if (J==0 && K==0) Q=Q; else if (J==0 && K==1) Q=0; else if (J==1 && K==0) Q=1; else if (J==1 && K==1) Q=~Q; end end endmodule
کد وریلاگش توضیح خاصی نداره ، مثل کد فلیپ فلاپ D هست فقط چند تا شرط بهش اضافه شده که با کمک شرط ها مقدار خروجی تعیین میشه .
بیاین یه مبحث جدید رو بهتون بگم ، به قسمت ریست ها دقت کردین ؟ ما گفتیم هر بار که لبه کلاک میاد بررسی کن و ببین ریست فعال هست یا نه ، اگه فعال بود خروجی رو صفر کن . به این شیوه بررسی ریست ، میگن ریستِ سنکرون یا ریستِ همزمان ، یعنی اگه ریست فعال بشه باید صبر کنیم لبه کلاک بیاد تا خروجی رو صفر کنه . اما یه شیوه ریست دیگه داریم به اسم ریستِ آسنکرون یا غیرهمزمان ، به این صورت که هروقت سیگنال ریست فعال شد بلافاصله خروجی مدار صفر بشه و اصلا منتظر اومدنِ لبه کلاک نباشه . در واقع باید کاری کنیم که محتوای درون always فقط در لبه کلاک اجرا نشه ، بلکه هم در لبه کلاک و هم در لبه ریست اجرا بشه . برای اینکار فقط کافیه خط 12 کد مون رو مطابق زیر تغییر بدیم :
1- 2- 3- 4- 5- 6- 7- 8- 9- 10- 11- 12- 13- 14- 15- 16- 17- 18- 19- 20- 21- 22- 23- 24- 25- 26- 27- 28- 29-
module JKFF2( input Clk, input Rst, input J, input K, output reg Q, output Qp ); assign Qp=~Q; always @(posedge Clk , negedge Rst) begin if (Rst==0) Q=0; else begin if (J==0 && K==0) Q=Q; else if (J==0 && K==1) Q=0; else if (J==1 && K==0) Q=1; else if (J==1 && K==1) Q=~Q; end end endmodule
توی خط 12 گفتیم اجرای کد های درون always در دو هنگام رخ بده ، وقتی لبه بالای کلاک میاد و همچنین وقتی که لبه پایین ریست میاد ، چرا لبه پایین ؟ چون پایه ریست ما حباب داشت و این یعنی هروقت مقدارش صفر شد (لبه پایین) مدار ریست بشه . بنابراین هرگاه ورودی ریست صفر شد بلافاصله و بدون توجه به کلاک ، خروجی ما سریعا صفر میشه . نکته اینکه اگه احیانا پایه ریست تون حباب نداشت یعنی هروقت ریست تون یک شد خروجی ریست بشه پس باید بنویسید : always @( posedge Clk or posedge Rst) به همین راحتی . دانلود فیلم جلسه
رفتن به جلسه بعد ...
رضا
عالی