1 - سطح گیت
جلسه اول (ماژول ها) جلسه دوم (گیت ها) جلسه سوم (نوع سیگنال) جلسه چهارم (پایان فصل)2 - مقداردهی مداوم
جلسه پنجم (اُپراتور ها) جلسه ششم (آرایه ها) جلسه هفتم (شرط ها) جلسه هشتم (فراخوانی ماژول) جلسه نهم (تست بنچ) جلسه دهم (نگاشت حافظه)3 - سطح رفتاری (ترکیبی)
جلسه یازدهم (بلاک Always) جلسه دوازدهم (ابزار ها) جلسه سیزدهم (نوع پردازش) جلسه چهاردهم (نکات تکمیلی) جلسه پانزدهم (پایان فصل)4 - سطح رفتاری (ترتیبی)
جلسه شانزدهم (لبه ها) جلسه هفدهم (تست بنچ 2) جلسه هجدهم (شمارنده ها) جلسه نوزدهم (ضرب و شیفت) جلسه بیستم (استیت ماشین) جلسه بیست و یکم (کشف رشته) جلسه بیست و دوم (فرکانس) جلسه بیست و سوم (نان بلاک) جلسه بیست و چهارم (پایان)5 - جلسات تمرینی
جلسه تمرین اول (تاخیر ها) جلسه تمرین دوم (الحاق-منطق) جلسه تمرین سوم (شیفت ها) جلسه تمرین چهارم (استیت)6 - مثال های پروژه محور
پروژه طراحی پردازنده RTL پروژه پردازنده Maano پروژه پردازنده MIPS7 - ارتباط و گفتگو
ارتباط با نویسنده گروه تلگرام تبلیغات و آگهیآموزش وریلاگ آموزش Verilog
جلسه آخر این فصل جذاب خواهد بود ، میخوایم یک پروژه کاربردی رو توصیف کنیم البته فصل بعدی اینقدر جذابه که مطمئنا این جلسه رو فراموش خواهید کرد.
به شکل بالا نگاه کنید یه حافظه است که در جلسات قبلی یکبار کُد شو نوشته بودیم ، یه متغیر درونی داره که همون حافظه است و بعدش ورودی آدرس تعیین میکنه که توی کدوم خونه از حافظه بنویسیم یا بخونیم . اگه قرار به خوندن باشه ، محتوای خونه رو روی Dout میریزیم و اگه قرار به نوشتن باشه ، مقدار Din رو روی خونه مورد نظر میریزیم . کد شو ببینید :
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- 30- 31- 32- 33-
module Memory( input Read, input Write, input [7:0] Din, input [11:0] Address, output reg [7:0] Dout ); reg [7:0] MEM [4095:0]; initial begin MEM[0]=57; MEM[1]=12; MEM[2]=83; MEM[3]=66; // ... // ... // ... MEM[4095]=33; end always @(*) begin case ({Read,Write}) 2'b10 : begin Dout=MEM[Address]; end 2'b01 : begin MEM[Address]=Din; end default : begin Dout=8'bz; end endcase end endmodule
چون خروجی Dout در بلاک always مقدار دهی میشه باید نوع شو reg تعریف کنیم ، همینطور سیگنال داخلی یا متغیر داخلی MEM قراره توی بلاک initial مقداردهی بشه ، بنابراین این سیگنال هم باید reg تعریف بشه ، البته بصورت دو بُعدی تعریفش کردیم یعنی 4096 عدد داده ی 8 بیتی . توی بلاک initial به خونه های مختلف متغیر MEM مقدار دادیم ، می تونیم از 0 تا 4095 رو مقداردهی کنیم اما به دلیل کمبود وقت من فقط 5 تا خونه رو مقداردهی کردم و مابقی خونه ها مقدارشون نامشخص یا X خواهد بود. حافظه ها معمولا بدون کلاک پالس کار میکنند ، بنابراین میشه با مطالبی که این فصل خوندیم براحتی توصیف شون کنیم . همونطور که در خط 26 میبینید روی ورودی های Read و Write اومدیم case زدیم ، اگه مقدار این دو عبارت 10 باینری یعنی Read=1 و Write=0 بود ، محتوای آدرس موردنظر در حافظه به روی خروجی ریخته میشه و اصطلاحا عمل خواندن انجام میشه . حالا اگه مقدار عبارت case معادل 01 باینری یعنی Read=0 و Write=1 بود ، مقدار Din ریخته میشه توی آدرس مورد نظر در حافظه و اصطلاحا عمل نوشتن انجام میشه . در حالت پیشفرض اگه مقدار Read و Write جزء دو حالت بالا نبود ، مثلا 00 یا 11 بود در هیچ خونه ای از حافظه عمل نوشتن انجام نمیشه و همچنین خروجی حافظه "های-امپدانس" خواهد شد.
خب حالا بیایم سراغ شکل بالا ، یک ALU یا واحد محاسبه است که دو ورودی 8 بیتی میگیره ، و باتوجه به اینکه مقدار Opcode چی باشه خروجی رو مقداردهی میکنه . اگه Opcode صفر باشه ، خروجی ما جمع دو ورودی خواهد بود و اگه Opcode یک باشه خروجی ما تفریق دو ورودی است . اگه Opcode دو باشه خروجی ما ضرب دو ورودی و در نهایت اگه Opcode سه باشه خروجی ما برابر است با همون ورودی A که یک بیت به سمت چپ شیفت پیدا کرده . یه خروجی دیگه داریم به اسم ZFlag که یک بیتی هست ، این خروجی زمانی مقدارش یک میشه که جواب محاسبه ALU صفر باشه ، معمولا توی ALU ها یک سیگنال Z داریم که هروقت خروجی صفر بشه ، فعال میشه . حالا بیایم توصیفش کنیم :
1- 2- 3- 4- 5- 6- 7- 8- 9- 10- 11- 12- 13- 14- 15- 16- 17- 18- 19- 20- 21- 22- 23-
module ALU( input [7:0] A, input [7:0] B, input [1:0] OpCode, output reg [15:0] Result, output ZFlag ); assign ZFlag = (Result==0)? 1 : 0; always @(*) begin case (OpCode) 2'b00 : begin Result=A+B; end 2'b01 : begin Result=A-B; end 2'b10 : begin Result=A*B; end 2'b11 : begin Result=A<<1; end default : begin Result=16'bz; end endcase end endmodule
ورودی هارو تعریف کردیم بعدش یه خروجی تک بیتی از نوع wire که قراره توی assign بلاک مقداردهی بشه و یک خروجی 16 بیتی (چرا 16 بیتی ؟ چون وقتی قراره حاصل ضرب دو عدد 8 بیتی رو حساب کنیم به 16 بیت نیاز داریم) از نوع reg تعریف کردیم. در همون ابتدای کار مقدار ZFlag رو مشخص کردیم ، در صورتی که حاصل Result صفر باشه ZFlag یک خواهد شد در غیر اینصورت ZFlag صفر خواهد بود. بعدش در یک بلاک always اومدیم روی مقدار Opcode مون case زدیم ، با توجه به مقدار هایی که Opcode میتونه داشته باشه ، یک عمل محاسباتی (جمع-تفریق-ضرب-شیفت) انجام میشه . خب این کد تموم شد ، حالا میرسیم به بخش جذاب این جلسه ، شکل زیر رو ببینید فرض کنید ما یک کامپیوتر 2 واحدی داریم شامل واحد محاسبات و حافظه ، حالا کار این کامپیوتر چیه ؟ یک عدد (A) میگیره ، یک آدرس میگیره و یک آپکُد ، سپس آدرسی که بهش دادیم رو میبره توی حافظه و محتوای اون خونه رو میاره بیرون (B) و یک عمل ریاضی با عددی که بهش دادید (A) انجام میده.
البته یه نکته هم وجود داره ، ما ورودی Din حافظه رو به زمین متصل کردیم ، که هر وقت سیگنال Write فعال شد و قرار بود توی حافظه بنویسیم ، مقدار صفر در آدرس خونه مورد نظر نوشته بشه ، چرا صفر ؟ برای ساده تر شدن مسئله ، اگه میخواستیم حاصل عبارت ریاضی توی حافظه نوشته بشه به فلیپ فلاپ نیاز داشتیم که مبحث فصل بعدی ماست . حالا شما با این چیزا کاری نداشته باشید ، طراح سوال که من باشم دوست داشتم کامپیوترم این شکلی باشه ، هنگام نوشتن ، صفر نوشته بشه توی حافظه . هنگام خوندن هم که میره آدرس مورد نظر رو میخونه (B) و با عدد A یه عمل ریاضی انجام میده .
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- 30-
module Computer( input [7:0] A, input [11:0] Adr, input [1:0] Op, input Rd, input Wr, output [15:0] F, output Z ); wire [7:0] B; Memory Unit1 ( .Din(8'b0), .Adress(Adr), .Read(Rd), .Write(Wr), .Dout(B) ); ALU Unit2 ( .A(A), .B(B), .OpCode(Op), .Result(F), .ZFlag(Z) ); endmodule
طبق شکل سیگنال های آبی ورودی ، سیگنال های بنفش واسطه ای و سیگنال های صورتی خروجی ما هستن که تعریف شون کردیم . حالا میتونیم از صفر تا صد کامپیوتر رو توی همین ماژول توصیف کنیم ، اما چون ما قبلا توصیف ALU و حافظه رو انجام دادیم ، از روش فراخوانی استفاده میکنیم . همونطور که میبینید مثلا در خط 13 ، حافظه رو فراخوانی کردیم و به پایه Din اش زمین رو دادیم ، به پایه آدرسش سیگنال Adr رو دادیم و .... به سیگنال خروجی حافظه هم ، سیگنال B رو وصل کردیم . برای ماژول ALU هم کار مشابهی انجام دادیم . نکته اینکه چون از فراخوانی استفاده کردیم و از always استفاده نکردیم ، پس اینجا هیچ سیگنالی رو reg نمیذاریم. دانلود فیلم جلسه
رفتن به جلسه بعد ...این فصل تموم شد ، فصل بعدی وارد یه دنیای جذاب میشیم و تازه قدرت افسانه ای وریلاگ رو می فهمیم ، با یه استراحت کوتاه آماده بشید برای جلسه بعدی ، قبلش یه نکته رو بگم اگه دوست داشتید مطالعه کنید : برای تهیه این سایت علاوه بر صرف زمان ، مقداری هزینه اولیه (طراحی وبسایت بصورت اختصاصی) و همچنین هزینه های پیوسته ای برای نگهداری وبسایت (هزینه سرور و هاست) بصورت سالیانه پرداخت می شود که با حمایت نقدی شما ، میشه به پایداری وبسایت امیدوار بود. از طریق درگاه پرداخت زیر می تونید مبلغ دلخواه خودتون رو بصورت آنلاین واریز کنید :