小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

學(xué)做8位計(jì)算機(jī)

 雅藏軒 2021-04-19

在B站上看到有大佬做了個(gè)8位計(jì)算機(jī),非常感興趣,同時(shí)想了解一下計(jì)算機(jī)底層到底是怎么運(yùn)作的,就跟著做了一個(gè)。以下是筆記,寫的比較細(xì)。

先show一下代碼

序號指令說明
0OUT顯示
1ADD 15加上地址15的值
2JC 4進(jìn)位跳轉(zhuǎn)到地址4
3JMP 0沒有進(jìn)位跳轉(zhuǎn)到地址0
4SUB 15減去地址15的值
5OUT顯示
6JZ 0為0跳轉(zhuǎn)到地址0
7JMP 4不為0跳轉(zhuǎn)到地址4

15地址設(shè)置成15;

代碼意思是:值自增15,如果到達(dá)進(jìn)位255就變成自減15,如果自薦到達(dá)0就自增。

基礎(chǔ)知識

二極管

單項(xiàng)導(dǎo)通器件

1874年,德國科學(xué)家發(fā)現(xiàn)晶體的整流功能

由半導(dǎo)體硅材料制成,硅本身是沒有電極的,在做晶體管的時(shí)候做了雜化處理,在一段加入了硼,一段加入了磷,硼這端會(huì)多出電子空穴,而磷這一端會(huì)多出自由電子,有意思的事情就發(fā)生了。

1593402180341

因?yàn)镾i是4個(gè)電子,P有3個(gè)電子,N有5個(gè)電子,所以單純的硅會(huì)形成4個(gè)共價(jià)鍵非常穩(wěn)定。

硅:

1593405655597

磷:N

1593405759705

硼:P

1593405791651

當(dāng)雜化之后,P端就會(huì)有很多電子空穴,N端會(huì)多出很多自由電子,在PN交界的地方,N端電子會(huì)自動(dòng)移動(dòng)到P端,形成一個(gè)耗盡區(qū),耗盡區(qū)的電壓為0.7V,所以大多5V的芯片低電壓為0.2V,如果超過0.7V則視為高電壓

1593402275121

1593402281081

如果加入正電壓會(huì)使耗盡區(qū)擴(kuò)大,造成正向偏壓,如果加入反向電壓,大于耗盡區(qū)0.7V電壓的時(shí)候,電子從N極向P極移動(dòng)沒有任何障礙。

1593402339330

繪出曲線,橫坐標(biāo)是電源電壓,縱坐標(biāo)是電流,負(fù)向電壓的時(shí)候幾乎沒有電流,負(fù)向電壓特別大的時(shí)候會(huì)擊穿,正向電壓大于0.7V的時(shí)候會(huì)很快獲得很大的電流。

1593402366314

1593402373161

二極管的這一特性可以做一個(gè)橋式整流電路

1593402782020

1593402800400

1593402818711

1593402920697

三極管

三極管就是二極管的升級,例如NPN型三極管

1593405830231

這樣在NP的交界處就會(huì)形成兩個(gè)耗盡區(qū),

1593405941816

可以看成兩個(gè)二極管背靠背相連,不管電源處于哪個(gè)狀態(tài)總有一個(gè)二極管處于反向加壓的狀態(tài),不導(dǎo)通。但是如果中間加一個(gè)電源(第二個(gè)電源),大量電子會(huì)從P端出來,通過電源到達(dá)N端形成通路

1593407386320

形成通路后,大量電子會(huì)到P端,形成反向偏壓,

如果整體來看,P端非常的窄,并不會(huì)存儲(chǔ)大量電子,大量電子在第一個(gè)電源的驅(qū)動(dòng)下回到電源,形成電流,因?yàn)榈谝粋€(gè)電源的電壓比較大,驅(qū)動(dòng)力比較大,第二個(gè)電源電壓比較小,驅(qū)動(dòng)力比較小

1593407646617

1593406938270

這種現(xiàn)象簡而言之就是

  1. 一個(gè)小電流被放大成一個(gè)大電流,

  2. 一個(gè)斷路變成一個(gè)通路

這種晶體管叫雙極結(jié)晶體管,

1593407944200

晶體管有兩種工作方式:

  1. 通過電流,將一個(gè)小電流放大成大電流,

1593409536983

  1. 通過電壓,只要基極和發(fā)射機(jī)有電勢差,集電極和發(fā)射極就會(huì)產(chǎn)生大電流,這種又叫場效應(yīng)管

1593409918451

1593416628720

1593408002200

雙極結(jié)型晶體管做的放大電路

1593408052033

1593408059414

1593408073722

門電路

晶體管的基本原理已經(jīng)知道了,門電路就是基于三極管構(gòu)成相關(guān)電路

非門電路:

1593419182677

1593444105431

與門電路:

1593444284919

或門電路

1593444422758

異或門

1593444497353

1593445197081

鎖存器

鎖存器用來做寄存器

將或門改造一下就可以就是SR鎖存器

1593483803191

SR鎖存器

1593485552948

1596789044301

1596789169949

再次進(jìn)階D鎖存器,D鎖存器是構(gòu)建寄存器的基礎(chǔ),本計(jì)算機(jī)種所有的寄存器都是由D鎖存器構(gòu)造

1596789454581

1596789543361

觸發(fā)器

觸發(fā)器是為了獲取極短時(shí)間內(nèi)的上升沿

第一種方法:

1593492156670

1593492224622

1593492248723

從0變成1的時(shí)候,非門需要幾個(gè)納秒的時(shí)候才能將狀態(tài)轉(zhuǎn)過來,所以在非常短的時(shí)候內(nèi)會(huì)出現(xiàn)都為1,這個(gè)時(shí)候與門輸出1,然后非門后的狀態(tài)0輸入,導(dǎo)致輸出變?yōu)?,這樣輸出只有幾個(gè)納秒是1。

第二種方法:

通過電容來實(shí)現(xiàn)

1593492619163

電容和電阻,當(dāng)信號來的時(shí)候電容充電,獲得輸出1,當(dāng)幾十納秒后,電容充滿電,信號就變成0了

1593492801580

計(jì)算時(shí)間

1593492862019

D觸發(fā)器,就是將之前的SR鎖存器的Enable改造一下

1593492909456

1593493025886

SR觸發(fā)器:

1593658845351

1596790932250

1596791041295

SR觸發(fā)器,在SR都為1的時(shí)候,處于一種無效的狀態(tài),沒有任何輸出。當(dāng)SR變成0的時(shí)候,誰慢一點(diǎn)誰就會(huì)被觸發(fā)。這是一種隨機(jī)狀態(tài)。

為了解決這個(gè)問題:

1593744836246

第一種情況 JK都為0,這是一種隨機(jī)狀態(tài),也成為不確定狀態(tài)

1596848606615

1596848685490

第二種狀態(tài)K=1,J=0的時(shí)候,處于reset狀態(tài),Q=0,反Q=1

1596849714250

第三種狀態(tài)K=0,J=1的時(shí)候,處于set狀態(tài)Q=1,反Q=0

1596849789639

最有意思的是第四種狀態(tài)K=1,J=1的時(shí)候,信號會(huì)發(fā)生一次對調(diào)

1596851913356

這樣會(huì)出現(xiàn)問題

在這個(gè)脈沖內(nèi)做了很多次轉(zhuǎn)換,也就是只要兩個(gè)輸入都是高電平,這個(gè)轉(zhuǎn)換就一直持續(xù)。

這種情況叫做搶先。

所以發(fā)現(xiàn)這個(gè)根本原因出現(xiàn)這個(gè)脈沖電路上,這個(gè)上升沿時(shí)間太多了。如果時(shí)間控制在100ns的時(shí)間內(nèi)就可以只完成1次轉(zhuǎn)換。

把1K電阻換成100電阻,已經(jīng)控制了100ns的時(shí)間,發(fā)現(xiàn)還是不行

1593661113782

1593662072289

因?yàn)樾盘栍卸秳?dòng),邊緣探測不銳利

用主從JK觸發(fā)器來解決這個(gè)問題

1593662291409

高電壓的時(shí)候使第一個(gè)鎖存器工作,在低電壓的時(shí)候使第二個(gè)鎖存器工作。

這樣就完全可以避免之前的問題

可以看到這有兩個(gè)鎖存器,這兩個(gè)鎖存器不可能同時(shí)工作,clock高電位第一個(gè)鎖存器工作,clock低電位第二個(gè)鎖存器工作,主從對應(yīng)的RS正好相反

如果高電壓,主鎖存器是SET,到低電壓的時(shí)候從鎖存器就是reset,

如果都是1的時(shí)候,那么主鎖存器執(zhí)行的操作是由從鎖存器的狀態(tài)決定的,而從鎖存器的狀態(tài)正好與主鎖存器狀態(tài)相反

這樣當(dāng)一個(gè)脈沖來的時(shí)候,set和reset會(huì)執(zhí)行一次交換。

基本模塊

計(jì)算機(jī)需要的模塊:1.主脈沖,2.計(jì)數(shù)器,3.計(jì)數(shù)器寄存器,4.寄存器A,5.寄存器B,6.ROM,7.指令寄存器,9.顯示模塊,9.控制模塊,10.標(biāo)志位寄存器。

主脈沖模塊

1593501552521

主脈沖

主脈沖使用555芯片

1593481876821

1593481909038

1593494846513

時(shí)許分析

開始的時(shí)候,沒有上電

1593493394039

開始上電的時(shí)候

1593493859502

1593494010715

通過電容放電和充電的時(shí)間來控制方波的占空比,

外界的電容和電阻決定了方波的長度

1593494184002

通過公式來計(jì)算

總的時(shí)間是0.139S

1593494323494

在5號引腳加入一個(gè)0.01uf的電容接地,可以降噪

1593496574101

1593494488980

1593497005669

當(dāng)有信號的時(shí)候,一堆晶體管需要獲取更多的電量,這個(gè)時(shí)候就會(huì)從電源端拉出更多的電流,就會(huì)形成電路中非常常見的過充的現(xiàn)象。

電線也會(huì)產(chǎn)生一些阻抗,也會(huì)阻止電流的變化,所以這個(gè)電壓就會(huì)跳上去,

直接的辦法給電路接一個(gè)非常短的線路

1593497249577

給正極和負(fù)極加一個(gè)電容,在電路需要電流的時(shí)候給電路提供更多的電流。

1593498098174

在四號引腳接入一個(gè)5V高電平,防止Reset鎖存器,這樣就不存在誤操作。

1593498182030

調(diào)整時(shí)鐘的速度,把100K換成可變電阻

1593498641896

單步脈沖

為了更好的測試電路,需要有一個(gè)單步脈沖,類似程序的單步執(zhí)行,按鈕按一下給一個(gè)脈沖

單步脈沖的意思是按1下產(chǎn)生1個(gè)脈沖,用555芯片來消除按鈕的抖動(dòng)

555芯片,消除抖動(dòng)電路,可以控制燈亮的時(shí)間

1593499451377

電阻是1M,電容是2uf,0.1uf,0.1S時(shí)間間隔,這邊要注意在電路不同的狀態(tài),6,7的電壓應(yīng)該是5V,

1593499651484

1593499743745

穩(wěn)態(tài)和單穩(wěn)態(tài)

1593568996652

1593569264958

切換電路

1593499976404

將兩個(gè)狀態(tài)的輸出型號添加到一個(gè)開關(guān)中,切換開關(guān)可以切換2個(gè)狀態(tài)、

但是開關(guān)會(huì)有一個(gè)新的問題,當(dāng)切換的時(shí)候有一個(gè)延遲的問題,這個(gè)時(shí)候需要一個(gè)新的555芯片來解決這個(gè)問題,其實(shí)是用到555芯片內(nèi)的SR鎖存器

1593500313308

開關(guān)有一個(gè)特性叫做先斷后連,

1593500510718

這個(gè)電路主要是解決開關(guān)彈跳的問題,

將這三個(gè)電路合并起來

1593500968557

這樣就可以在自動(dòng)和手動(dòng)切換

1593501039719

HLT作用是關(guān)閉定時(shí)器,接入低電平,

74LS04有6個(gè)非門

這樣一個(gè)電路需要用到三種芯片效率非常低,可以把電路給改一下

1593501323702

跟之前的效果一樣,只用到了與非門

最終效果

1593501552521

1596857262654

1596856290057

總線

BUS的工作原理:

1593502854512

這8條線沒有回路,可以跑1bit的數(shù)據(jù)這非常的靈活

Load:表示數(shù)據(jù)可以放到芯片中

Enable:表示數(shù)據(jù)從芯片放到Bus中

1593503069934

這里面邊上的藍(lán)色線就是控制線,可以看到這個(gè)控制線就是Clock,所有的部件同步Load

1593503208426

enable線來控制芯片將數(shù)據(jù)寫到總線中,這需要同時(shí)只有1個(gè)芯片進(jìn)行這樣的操作,不然就會(huì)造成混亂

三態(tài)門

在總線中有一個(gè)非常重要的事情,就是同一時(shí)間只有一個(gè)部件向總線中輸出數(shù)據(jù),每個(gè)部件的輸出端其實(shí)就是芯片內(nèi)部門電路的輸出端。

1593503744233

通常都會(huì)用兩個(gè)這樣輸出,

1593504156671

三態(tài)門:,0,1,和斷路三種狀態(tài)

1593504288469

1593504362712

74LS245 8路三態(tài)門芯片

1593504498768

每個(gè)模塊都接入一個(gè)Enable線,每個(gè)模塊都接入Bus中,

同1時(shí)刻只有一個(gè)模塊Enable線為true,就可以保證只有該數(shù)據(jù)寫入到總線中。

當(dāng)load為高電平的時(shí)候,它會(huì)在下一個(gè)時(shí)鐘周期高電平到來的時(shí)候?qū)⒖偩€中數(shù)據(jù)讀取到模塊中。

所有需要寫入總線的模塊都需要該245模塊

寄存器

整個(gè)計(jì)算機(jī)需要8位寄存器A,8位寄存器B,4位計(jì)數(shù)器寄存器,8位指令寄存器

寄存器的構(gòu)造是使用D鎖存器,有高信號就可以保存住高信號

可以通過D觸發(fā)器來構(gòu)建寄存器,同時(shí)加入一個(gè)Load控制,下面這種是Load為0的情況,輸出是什么輸入還是什么

1593508139683

Load為1的情況,輸入什么輸出還是什么

1593508299194

74LS74內(nèi)有2個(gè)D觸發(fā)器

1593508533578

1593508684418

1593508886879

通過搭建上面的電路可以實(shí)現(xiàn)

1593508936549

數(shù)據(jù)不可以直接輸出到總線中,需要在輸出中加入74LS245 三態(tài)門

74LS173由4個(gè)D觸發(fā)器,包含Load和Enable

1593587696438

1593587755157

因?yàn)樾枰饨有舨榭醇拇嫫髦械闹?,所?73芯片中的三態(tài)門一直處于打開狀態(tài),外界一個(gè)三態(tài)門來控制輸出。

1593588901927

1593589161836

1596857057836

1596897104838

1596897167154

本計(jì)算機(jī)種需要用到三個(gè)相同原理的寄存器模塊,寄存器A,寄存器B,指令寄存器。

指令寄存器就是與寄存器A的方向相反

1596897816078

ALU

補(bǔ)碼

編碼方式:

用最高位表示符號位,這樣-5和5相加得2是不對的

1593590788676

另一種編碼方式:得1補(bǔ)碼:用反碼表示負(fù)數(shù)

1593590880864

1593590946951

-5和5相加得到都是1,這就是得1補(bǔ)碼的原因

1593591051997

比正確的結(jié)果少1;如果將結(jié)果加1就可以得到正確的結(jié)果

第三種編碼方式:得2補(bǔ)碼,反碼+1表示負(fù)數(shù)

1593591153663

1593591276903

  • 每一位都有含義

    1593591514160

取反+1;

補(bǔ)碼:取反+1表示負(fù)數(shù),上面為解釋為什么取反+1比較好。

全加器

1位加法運(yùn)算,一共就8中情況,前四種不考慮前面的進(jìn)位,后四種情況考慮一下之前的進(jìn)位

結(jié)果有兩位,第一位表示結(jié)算結(jié)果,第二位表示是否有進(jìn)位

1593477274157

第一位前四種情況可以用異或門來表示

0,0 =》0

0,1=》1

1,0=》1

1,1=》0

1593477458141

第二位前四種情況可以用與門來表示

0,0=》0

0,1=》0

1,0=》0

1,1=》1

1593477943123

進(jìn)位4種情況:可以發(fā)現(xiàn)第一位進(jìn)位四種情況正好和之前的相反

那么進(jìn)位的第一位變化的四種情況就可以直接在之前的結(jié)果后面加如一個(gè)異或門。異或門可以控制結(jié)果取反,

1593477962067

1593477980633

1593477989360

有進(jìn)位的第二位四種情況,不僅要考慮本身有進(jìn)位還要考慮第一位出現(xiàn)進(jìn)位的情況

1593478123960

將進(jìn)位情況求和

1593478310218

這個(gè)電路叫做1位全加器

1593479377583

每個(gè)全加器需要2個(gè)異或門,2個(gè)與門,1一個(gè)或門

1個(gè)異或門需要2個(gè)晶體管

1個(gè)與門需要2個(gè)晶體管

1個(gè)或門需要2個(gè)晶體管

那么可以總結(jié)出1個(gè)全加器需要10個(gè)晶體管,也就是10個(gè)三極管,也就是10個(gè)晶體管可以計(jì)算出1位計(jì)算器。

4個(gè)全加器組合成4位加法器

需要的材料和電路圖

1593479516753

74LS86內(nèi)有4個(gè)異或門芯片

74LS08內(nèi)有4個(gè)與門芯片

74LS32內(nèi)有4個(gè)或門

2個(gè)四位撥叉開關(guān)

1個(gè)面包板

4個(gè)小燈顯示結(jié)果1個(gè)進(jìn)位

1593481046309

ALU

Arithmetic Logic Unit:算術(shù)邏輯單元

該模塊其實(shí)完全由全加器構(gòu)成

用寄存器A和寄存器B,中間加入ALU邏輯電路,這樣該模塊就可以計(jì)算出寄存器A和寄存器B的求和或相減。

對寄存器中的數(shù)據(jù)進(jìn)行操作

1593592572358

通過之前的全加器來構(gòu)建邏輯單元 ,

如何做減法,

現(xiàn)在全加器可以實(shí)現(xiàn)加法,是否可以將被減數(shù)變成負(fù)數(shù)然后執(zhí)行加法運(yùn)算

1593592935597

通過異或門,當(dāng)A為1的時(shí)候相當(dāng)于取反,當(dāng)A為0的時(shí)候原樣輸出

通過異或門獲取反碼

1593593651635

4位加法器有一個(gè)進(jìn)位,將這個(gè)1和控制器連接起來,如果如果控制器是減法的話,那正好需要進(jìn)位

這樣就實(shí)現(xiàn)了一個(gè)數(shù)補(bǔ)碼加1的操作。

1593593845194

1596859217576

1596859413998

1595080969662

中間的就是ALU

1593594182207

1596897448756

1593594254287

先要進(jìn)行測試,測試是有必要的,

如果出現(xiàn)故障需要先排除故障,先從最簡單的部分入手,然后慢慢縮小范圍。

先設(shè)置A寄存器是0,B寄存器是0

1593595254896

然后讓B存器器是0,然后讓A每一位依次置1,查看是否有問題,發(fā)現(xiàn)問題然后跟蹤這條線,

然后讓A寄存器是0,然后B依次置1;

出現(xiàn)問題需要刨根問底將其找出來。

不要慌,從第一步開始的第一個(gè)異常,首先分析可能出現(xiàn)這個(gè)現(xiàn)象的原因,大多數(shù)情況下都想不出,

查看接線是否正常,接線正常后查看所有輸出輸入,特定的輸入產(chǎn)生特定的輸出,通過萬用表量輸入和輸出電壓。

1593595967786

將ALU中產(chǎn)生的數(shù)據(jù)直連到總線中,每當(dāng)有脈沖的時(shí)候,A寄存器從總線中讀取值,ALU從A中讀值,從B中讀值進(jìn)行加操作,并將操作的結(jié)果放到總線中,1個(gè)脈沖實(shí)現(xiàn)加放到總線中讀取總線數(shù)據(jù)的操作。

ROM

本計(jì)算機(jī)構(gòu)建了16個(gè)字節(jié)的內(nèi)存;

內(nèi)存的構(gòu)建有兩種方式,

1.直接通過D鎖存器構(gòu)建

2.直接通過一個(gè)電容和一個(gè)晶體管構(gòu)建,然后有一個(gè)電容不停刷新這個(gè)電容的數(shù)據(jù)。

1593653512871

1word的寄存器,1個(gè)字節(jié)寄存器,輸入輸出,寫和讀

16個(gè)字節(jié)

1593653574645

哪個(gè)字節(jié)的Enable開,哪個(gè)字節(jié)的數(shù)據(jù)就被讀出來,

這樣需要對16個(gè)字節(jié)進(jìn)行編碼

第一步

需要對16個(gè)字節(jié)進(jìn)行編碼,每個(gè)字節(jié)有8個(gè)D鎖存器,也就是128個(gè)D鎖存器

0-16這16個(gè)數(shù)字表示地址,也就是4個(gè)bit位,這樣一個(gè)數(shù)字代表一個(gè)字節(jié)。

地址譯碼單元直接輸出這個(gè)地址,地址譯碼單元怎么構(gòu)造,首先需要有4個(gè)bit輸入,每個(gè)輸入有高低輸出,然后構(gòu)建一個(gè)有5個(gè)輸入的與門,1位標(biāo)識load,然后四位對應(yīng)地址,那么就有16個(gè)5位輸入與門,代表16個(gè)地址

1593652894450

這個(gè)地址電路應(yīng)該在內(nèi)存電路的前面,4個(gè)輸入就可以讓內(nèi)存電路輸出該地址的數(shù)據(jù)。

74LS189就是一個(gè)內(nèi)存芯片,是一個(gè)64bit的存儲(chǔ)器,有4個(gè)地址輸入,16個(gè)地址位每個(gè)地址位4個(gè)輸出,其使用的方式就是D寄存器的方式構(gòu)建的內(nèi)存

1595121792491

1593653727390

1593653794264

1596861778747

1596864742304

因?yàn)檫@邊189的輸出都是低電位有效,所以需要74LS04非門進(jìn)行反轉(zhuǎn),最后接入一個(gè)245三態(tài)門輸出到總線中

地址線需要處理,需求是:實(shí)現(xiàn)從總線中讀取,或者手動(dòng)設(shè)置。

通過4Bit寄存器來獲得輸入,地址寄存器。74LS173正好滿足條件

1596865074587

地址輸入

希望這個(gè)地址寄存器能切換模式手動(dòng)模式和自動(dòng)模式,自動(dòng)模式是從總線中讀取地址,手動(dòng)模式用撥碼開關(guān)來指定地址。

選擇電路

1593655740684

74LS157可以實(shí)現(xiàn)二選一電路

1596865534393

1596865575731

1596865914587

對撥碼開關(guān)的控制,可以獲得1個(gè)明確0,1信號

1593656371930

1596897597639

值輸入

希望可以手動(dòng)向內(nèi)存中寫入值,同時(shí)也可以選擇從總線中讀入值。

又是一個(gè)選擇電路,但是這邊又8Bit輸入,所以就用了2塊74LS157芯片

1596866871402

1596867094024

1596897700121

到這可以控制手動(dòng)輸入地址和值的ROM就做好了

計(jì)數(shù)器

一個(gè)計(jì)算機(jī)僅僅只有脈沖是不可能正常運(yùn)行的,必須還要有可以指示程序運(yùn)行的計(jì)數(shù)器,指示程序運(yùn)行到 了哪一步。

當(dāng)我們從計(jì)算機(jī)中運(yùn)行程序,這些程序放在內(nèi)存中,它是一條條指令,為了執(zhí)行這些指令需要從內(nèi)存中讀取它,在這個(gè)8位計(jì)算器中需要從地址0開始執(zhí)行。先執(zhí)行地址0的指令,然后執(zhí)行地址1的指令,需要確定當(dāng)前在哪個(gè)地址上執(zhí)行,所以我們需要程序計(jì)數(shù)器。

1596868379690

在上面我們由JK觸發(fā)器構(gòu)造了一個(gè)計(jì)數(shù)器,這個(gè)程序技術(shù)器也是由4位組成

,指向下一條需要指向的指令,需要能從總線中讀取數(shù)據(jù) ,這樣可以跳轉(zhuǎn)到別的地址。

程序計(jì)數(shù)器的功能:

第一個(gè)CO就是程序控制器的輸出,把值放到總線中

第二個(gè)J就是jump,從總線中讀取數(shù)據(jù),只獲取4位數(shù)據(jù),

第三個(gè)CE就是控制,控制計(jì)數(shù)器開始計(jì)數(shù)和停止計(jì)數(shù)。不一定每個(gè)脈沖都需要計(jì)數(shù),當(dāng)CE活動(dòng)的時(shí)候,將計(jì)數(shù)器開始計(jì)數(shù)

二分電路

怎么把脈沖變成明確的計(jì)數(shù)信號呢?

這就需要之前的基礎(chǔ)知識:主從觸發(fā)器

主從觸發(fā)器的特性,在一次脈沖來的時(shí)候會(huì)進(jìn)行Q和反Q的切換,如果構(gòu)建多個(gè)主從觸發(fā)器,將第一個(gè)主從觸發(fā)器的反Q接到下一個(gè)主從觸發(fā)器的Q,會(huì)發(fā)生什么呢?

DM7476就是使用主從觸發(fā)器來構(gòu)造了JK觸發(fā)器

1593665837408

可以發(fā)現(xiàn)這個(gè)JK觸發(fā)器在下降沿的時(shí)候觸發(fā)。

1596869990896

1596870028841

接了一個(gè)JK觸發(fā)器可以看的更清楚一些,在每個(gè)脈沖周期,JK觸發(fā)器交換了一次

1596870162055

當(dāng)去掉一個(gè)顯示的時(shí)候,可以發(fā)現(xiàn)這個(gè)Q亮到不亮再到亮用了2個(gè)脈沖周期

這個(gè)電路稱為二分電路,通過JK觸發(fā)器,將原來的主脈沖的周期擴(kuò)大了一倍。

在原來二分電路的基礎(chǔ)上再加一個(gè)二分JK觸發(fā)器,把第一個(gè)觸發(fā)器的輸出接到下一個(gè)JK觸發(fā)器的輸入

1596870430039

第二個(gè)JK的轉(zhuǎn)換速度是前一個(gè)的一半,是4倍的主脈沖周期

構(gòu)建4個(gè)JK觸發(fā)器,每一個(gè)都是前一個(gè)的周期的一半

1596870522435

這樣我們就獲得了一個(gè)2進(jìn)制的計(jì)數(shù)器,可以從0計(jì)數(shù)到15,

計(jì)數(shù)器

本計(jì)算機(jī)的計(jì)數(shù)器就是使用了這一原理構(gòu)建,這邊我們使用74LS161作為計(jì)數(shù)器

1593668897652

其有4個(gè)輸入,4個(gè)輸出,是否寫入控制線,CLock控制線,Enable輸入輸出控制線,清除控制線

這個(gè)芯片非常有用,它的Clock內(nèi)部加了一個(gè)非門,這樣上升沿變成下降沿,我們的JK觸發(fā)器也是下降沿觸發(fā)器

1593668916026

1596897924975

顯示

共陰極和共陽極數(shù)碼管

1593671218533

1593671296840

1593671307681

構(gòu)建真值表

1593671395685

通過這個(gè)真值表可以獲取a這個(gè)值什么時(shí)候亮

1593671381731

1593671495630

1593671522768

如果需要顯示真正的數(shù)據(jù),必須要建立一個(gè)真值表,將真值表轉(zhuǎn)化成電路,這樣的電路就是解析器,

EEPROM可以替代計(jì)算機(jī)中任何的組合邏輯。

組合邏輯:任何一個(gè)狀態(tài)的輸入對應(yīng)一個(gè)狀態(tài)的輸出

時(shí)序邏輯:寄存器,鎖存器,計(jì)數(shù)器,輸出不進(jìn)取決于當(dāng)前的狀態(tài)也取決于之前的狀態(tài)。

有許多種ROM芯片,這個(gè)芯片是只讀的,還有一種可以變成的只讀芯片的就叫做PROM,提供了一個(gè)空白的芯片,只能寫入一次,寫入之后就不能改變了。EPROM可以重復(fù)寫入,在紫外線的作用下可以擦除內(nèi)部的數(shù)據(jù)

1593672678388

EEPROM是電可擦寫存儲(chǔ)器,用電就可以擦除。

AT28C16可擦寫只讀存儲(chǔ)器,可以存2K個(gè)字節(jié)

1593673132260

有兩種封裝形式,直插和貼片,

8條IO引腳,數(shù)據(jù)引腳

11條地址引線,接地線和電源

反CE,反OE和反WE

1593673671134

需要給WE 一個(gè)100ns-1000ns的時(shí)間,

1593673640992

用一個(gè)電容和一個(gè)電阻來實(shí)現(xiàn)。RC震蕩電路,

1nf,和680歐姆電阻。

1593673882492

1593673978192

通過EEPROM來實(shí)現(xiàn)真值表,左邊是地址,右邊的值。

Arduino寫入數(shù)據(jù)

在這里插入圖片描述

在這里插入圖片描述

看以下Arduino Nano的引腳數(shù)根本不夠,因?yàn)榈刂肪€11根,數(shù)據(jù)線8根

需要另選一個(gè)方案來向EPROM中寫入數(shù)據(jù)。

通過一個(gè)引腳輸出地址,8根引腳輸出數(shù)據(jù),1根引腳怎么輸出數(shù)據(jù)呢

這邊用到了8個(gè)D觸發(fā)器,思路基本和計(jì)數(shù)器一樣,只不過計(jì)數(shù)的Enable線就是脈沖線,這樣脈沖來一次就+1;

這邊的enable線是通過按鈕輸入,按下為1不按為0

這邊用74LS74來構(gòu)建,其有兩個(gè)D觸發(fā)器

1596899709888

1596899730900

用4個(gè)74芯片的D觸發(fā)器輸出連接到輸入,構(gòu)建了一個(gè)8位寄存器來獲得8個(gè)連續(xù)的輸入。

當(dāng)脈沖來的時(shí)候按鈕按下為輸入1,不按為輸入0

1596899208059

Arduino一根數(shù)據(jù)線輸入數(shù)據(jù)問題解決就可以運(yùn)用上面的思路,找到74HC595這個(gè)芯片

1596900171115

1596900195303

那么現(xiàn)在只需要3根線來控制數(shù)據(jù)輸入,數(shù)據(jù)輸入線DS,時(shí)鐘線SH_CP,和控制輸出線ST_CP

1596900574532

地址線有11條,所以需要2個(gè)595芯片

1596901226289

1596901745266

這樣我們的Arduino寫入EEPRom模塊就做好了

現(xiàn)在來寫程序吧;

//定義好各個(gè)引腳的標(biāo)志
#define SHIFT_DATA 2  
#define SHIFT_CLK 3
#define SHIFT_LATCH 4
#define EEPROM_D0 5
#define EEPROM_D7 12
#define WRITE_EN 13
/*
 * 使用移位寄存器將地址數(shù)據(jù)輸出
 */
void setAddress(int address, bool outputEnable) {
  shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, (address >> 8) | (outputEnable ? 0x00 : 0x80));//將地址寫入到595中,高8位
  shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, address);//將地址寫入到595中,低8位
//設(shè)置595輸出地址
  digitalWrite(SHIFT_LATCH, LOW);
  digitalWrite(SHIFT_LATCH, HIGH);
  digitalWrite(SHIFT_LATCH, LOW);
}


/*
 * 從指定地址的EEPROM讀取一個(gè)字節(jié)
 */
byte readEEPROM(int address) {
  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin++) {
    pinMode(pin, INPUT);
  }
  setAddress(address, /*outputEnable*/ true);

  byte data = 0;
  for (int pin = EEPROM_D7; pin >= EEPROM_D0; pin--) {
    data = (data << 1) + digitalRead(pin);
  }
  return data;
}


/*
 * 將字節(jié)寫入指定地址的EEPROM。
 */
void writeEEPROM(int address, byte data) {
  setAddress(address, /*outputEnable*/ false);//設(shè)置地址到595中并輸出地址
  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin++) {
    pinMode(pin, OUTPUT);//設(shè)置引腳
  }

  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin++) {
    digitalWrite(pin, data & 1);//將數(shù)據(jù)寫到引腳中,只取最后一位
    data = data >> 1;
  }
  digitalWrite(WRITE_EN, LOW);//寫入EMROM
  delayMicroseconds(1);
  digitalWrite(WRITE_EN, HIGH);
  delay(10);
}


/*
 * 讀取EEPROM的內(nèi)容并將其打印到串行監(jiān)視器。
 */
void printContents() {
  for (int base = 0; base <= 255; base += 16) {
    byte data[16];
    for (int offset = 0; offset <= 15; offset++) {
      data[offset] = readEEPROM(base + offset);
    }

    char buf[80];
    sprintf(buf, "%03x:  %02x %02x %02x %02x %02x %02x %02x %02x   %02x %02x %02x %02x %02x %02x %02x %02x",
            base, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
            data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]);

    Serial.println(buf);
  }
}


// 用于共陽極7段顯示的4位十六進(jìn)制解碼器
//byte data[] = { 0x81, 0xcf, 0x92, 0x86, 0xcc, 0xa4, 0xa0, 0x8f, 0x80, 0x84, 0x88, 0xe0, 0xb1, 0xc2, 0xb0, 0xb8 };

// 用于共陰極7段顯示的4位十六進(jìn)制解碼器
 byte data[] = { 0x7e, 0x30, 0x6d, 0x79, 0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b, 0x77, 0x1f, 0x4e, 0x3d, 0x4f, 0x47 };


void setup() {
  // put your setup code here, to run once:
  pinMode(SHIFT_DATA, OUTPUT);
  pinMode(SHIFT_CLK, OUTPUT);
  pinMode(SHIFT_LATCH, OUTPUT);
  digitalWrite(WRITE_EN, HIGH);//寫低電平有效
  pinMode(WRITE_EN, OUTPUT);
  Serial.begin(57600);

  // Erase entire EEPROM
  Serial.print("擦除 EEPROM");
  for (int address = 0; address <= 2047; address ++) {
    writeEEPROM(address, 0x55);
    if (address % 64 == 0) {
       writeEEPROM(address, 0x55);
      Serial.print(".");
    }
  }
  Serial.println(" done");


  // 寫入數(shù)據(jù)
  Serial.print("編輯 EEPROM");
  
  for (int address = 0; address < sizeof(data); address ++ ) {//sizeof(data)=16
    writeEEPROM(address, data[address]);

    if (address % 64 == 0) {//數(shù)據(jù)一共64Bit,
       writeEEPROM(address, data[address]);
      Serial.print(".");
    }
  }
  Serial.println(" 完成");


  // 讀EEPROM中的值
  Serial.println("讀.... EEPROM");
  printContents();
}


void loop() {
  // put your main code here, to run repeatedly:

}

1596902199407

1596902279049

1596902472107

重點(diǎn)看一下

/*
 * 使用移位寄存器將地址數(shù)據(jù)輸出
 */
void setAddress(int address, bool outputEnable) {
  shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, (address >> 8) | (outputEnable ? 0x00 : 0x80));
  shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, address);

  digitalWrite(SHIFT_LATCH, LOW);
  digitalWrite(SHIFT_LATCH, HIGH);
  digitalWrite(SHIFT_LATCH, LOW);
}

shiftout:一次將數(shù)據(jù)字節(jié)移出一位。從最高(即最左邊)或最低(最右邊)有效位開始。每個(gè)位依次寫入數(shù)據(jù)引腳,然后向時(shí)鐘引腳脈沖(先變高,然后變低),以指示該位可用。

MSBFIRST:最高位有效在先

至此EEPEOM的真值表寫入完畢,我們只使用了16個(gè)地址的數(shù)據(jù),真是極大的浪費(fèi)呢

如何顯示數(shù)據(jù)

第一種方案是用三個(gè)EEPROM來表示百,十,個(gè)三個(gè)位的數(shù)據(jù)

1596904702816

這種方案顯然造成EEPROM的極大浪費(fèi)

第二種方案:復(fù)雜一點(diǎn)點(diǎn),將選擇這種方案,就是順序讓每一個(gè)數(shù)碼管顯示,當(dāng)速度非常塊的時(shí)候,數(shù)碼管看上去就像一直顯示的一樣,怎么才能讓數(shù)碼管順序顯示

這邊我們就用到了上面計(jì)數(shù)器的原理,構(gòu)建一個(gè)單獨(dú)的顯示脈沖,然后通過2個(gè)JK觸發(fā)器就可以獲得4種不同的編碼狀態(tài),00,01,10,11

這邊用74LS76,其正好有兩個(gè)JK觸發(fā)器

1596905786007

同時(shí)需要將00,01,10,11進(jìn)行解碼,將其變成0001,0010,0100,1000,這樣將這四條線連接到4個(gè)數(shù)碼管,數(shù)碼管就會(huì)順序顯示,這邊我們用到了74LS139

1596905987400

1596906020693

可以看到該編碼器完美滿足我們的需求。

1596906109499

構(gòu)建公用真值表

1596904888088

就是用A10,A9,A8,來表示個(gè)位十位百位

這樣真值表就比較復(fù)雜了

舉個(gè)例子321這個(gè)值的真值表:

1596905121518

改進(jìn)程序

#define SHIFT_DATA 2
#define SHIFT_CLK 3
#define SHIFT_LATCH 4
#define EEPROM_D0 5
#define EEPROM_D7 12
#define WRITE_EN 13

/*
   使用移位寄存器輸出地址位和outputEnable信號。
*/
void setAddress(int address, bool outputEnable) {
  shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, (address >> 8) | (outputEnable ? 0x00 : 0x80));
  shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, address);

  digitalWrite(SHIFT_LATCH, LOW);
  digitalWrite(SHIFT_LATCH, HIGH);
  digitalWrite(SHIFT_LATCH, LOW);
}


/*
   從指定地址的EEPROM讀取一個(gè)字節(jié)。
*/
byte readEEPROM(int address) {
  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
    pinMode(pin, INPUT);
  }
  setAddress(address, /*outputEnable*/ true);

  byte data = 0;
  for (int pin = EEPROM_D7; pin >= EEPROM_D0; pin -= 1) {
    data = (data << 1) + digitalRead(pin);
  }
  return data;
}


/*
   將字節(jié)寫入指定地址的EEPROM。
*/
void writeEEPROM(int address, byte data) {
  setAddress(address, /*outputEnable*/ false);
  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
    pinMode(pin, OUTPUT);
  }

  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
    digitalWrite(pin, data & 1);
    data = data >> 1;
  }
  digitalWrite(WRITE_EN, LOW);
  delayMicroseconds(1);
  digitalWrite(WRITE_EN, HIGH);
  delay(10);
}


/*
   讀取EEPROM的內(nèi)容并將其打印到串行監(jiān)視器。
*/
void printContents() {
  for (int base = 0; base <= 255; base += 16) {
    byte data[16];
    for (int offset = 0; offset <= 15; offset += 1) {
      data[offset] = readEEPROM(base + offset);
    }

    char buf[80];
    sprintf(buf, "%03x:  %02x %02x %02x %02x %02x %02x %02x %02x   %02x %02x %02x %02x %02x %02x %02x %02x",
            base, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
            data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]);

    Serial.println(buf);
  }
}


void setup() {
  // put your setup code here, to run once:
  pinMode(SHIFT_DATA, OUTPUT);
  pinMode(SHIFT_CLK, OUTPUT);
  pinMode(SHIFT_LATCH, OUTPUT);
  digitalWrite(WRITE_EN, HIGH);
  pinMode(WRITE_EN, OUTPUT);
  Serial.begin(57600);


  // Bit patterns for the digits 0..9
  byte digits[] = { 0x7e, 0x30, 0x6d, 0x79, 0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b };
   writeEEPROM(0,0);
  Serial.println("寫入個(gè)位 ");
  
  for (int value = 0; value <= 255; value += 1) {
    writeEEPROM(value, digits[value % 10]);
  }
  Serial.println("寫入十位");
  for (int value = 0; value <= 255; value += 1) {
    writeEEPROM(value + 256, digits[(value / 10) % 10]);
  }
  Serial.println("寫入百位");
  for (int value = 0; value <= 255; value += 1) {
    writeEEPROM(value + 512, digits[(value / 100) % 10]);
  }
  Serial.println("寫入符號位");
  for (int value = 0; value <= 255; value += 1) {
    writeEEPROM(value + 768, 0);
  }

  Serial.println("寫入個(gè)位 (后半部)");
  for (int value = -128; value <= 127; value += 1) {
    writeEEPROM((byte)value + 1024, digits[abs(value) % 10]);
  }
  Serial.println("寫入十位 (后半部)");
  for (int value = -128; value <= 127; value += 1) {
    writeEEPROM((byte)value + 1280, digits[abs(value / 10) % 10]);
  }
  Serial.println("寫入百位 (后半部)");
  for (int value = -128; value <= 127; value += 1) {
    writeEEPROM((byte)value + 1536, digits[abs(value / 100) % 10]);
  }
  Serial.println("寫入符號位 (后半部)");
  for (int value = -128; value <= 127; value += 1) {
    if (value < 0) {
      writeEEPROM((byte)value + 1792, 0x01);
    } else {
      writeEEPROM((byte)value + 1792, 0);
    }
  }

  // Read and print out the contents of the EERPROM
  Serial.println("讀..... EEPROM");
  printContents();
}


void loop() {
  // put your main code here, to run repeatedly:

}

控制數(shù)據(jù)顯示

現(xiàn)在數(shù)據(jù)顯示的問題已經(jīng)解決了,下面怎么控制其從Bus種讀取數(shù)據(jù)顯示,這邊肯定不能直接顯示總線的數(shù)據(jù),因?yàn)榭偩€的數(shù)據(jù)是不斷變化的,所以需要一個(gè)8bit寄存器控制讀取總線中的數(shù)據(jù),然后控制其顯示,

這邊使用不同的芯片74LS273

1596937226761

1596937288930

1596937298968

這邊有8個(gè)輸入,8個(gè)輸出,一個(gè)脈沖引腳,一個(gè)重置線

這邊有一個(gè)問題,這個(gè)芯片沒有IEnable線,如果主脈沖接進(jìn)來,每次脈沖變化都會(huì)讀取值,這個(gè)問題可以通過一個(gè)與門來解決,通過與門接入脈沖和控制線,控制線為1的時(shí)候,脈沖變化才有效

1596937862295

做個(gè)簡單的總結(jié),將已經(jīng)做好的部件連接到總線

1596938308943

1596938572688

控制器

現(xiàn)在這個(gè)部件就缺少一個(gè)控制邏輯就可以正常工作了,來看看有多少個(gè)控制線

1596938678177

目前有14根控制線,還要做一個(gè)HTL停機(jī)線,在主脈沖中

1596939236718

如何控制

現(xiàn)在我們寫一個(gè)程序,來手動(dòng)運(yùn)行這個(gè)程序

LDA 14   //將內(nèi)存地址14中內(nèi)容讀取到A寄存器
ADD 15   //把內(nèi)存地址15中內(nèi)容與A寄存器中值相加放到寄存器
OUT      //把A寄存器中的內(nèi)容放到輸出模塊

這會(huì)很奇怪,這些命令是哪里來的,在之前的計(jì)算機(jī)構(gòu)造中沒有構(gòu)造任何與命令有關(guān)的內(nèi)容,實(shí)際上這些是我們自己定義的,你可以定義任何想做的命令,這是不是非???。

下面我們來定義

LDA:0001

ADD:0010

OUT:1110

那么程序就被翻譯成機(jī)器語言了

LADA 14   // 0001 1110
ADD  15   // 0010 1111
OUT       // 1110 xxxx

這個(gè)程序一共三行,我們在加上行號

LADA 14   // 0000 0001 1110
ADD  15   // 0001 0010 1111
OUT       // 0010 1110 xxxx

所以想要運(yùn)行這個(gè)程序我們需要將值寫到ROM中,進(jìn)入手動(dòng)模式輸入ROM值

地址
00000001 1110
00010010 1111
00101110 0000


11100001 1100(28)
11110000 1110(14)

這個(gè)代碼翻譯成高級語言就是28+14=?

現(xiàn)在我們需要手動(dòng)控制程序的運(yùn)行

首先將指令從內(nèi)存中讀出來放到指令寄存器中,指令寄存器告訴我們數(shù)據(jù)將怎么解析。

取址周期就是將指令從內(nèi)存中取出來放到指令寄存器中。

計(jì)算器中所有的組件都是由程序計(jì)數(shù)器來協(xié)調(diào),計(jì)數(shù)器記錄了當(dāng)前執(zhí)行到哪條指令。計(jì)數(shù)器是從0開始的。

一開始0000

  1. 首先將計(jì)數(shù)器的值放到內(nèi)存地址寄存器中,

    1596941320469

    可以看到這邊計(jì)數(shù)器和內(nèi)存地址寄存器都是0,

    而0地址上ROM的值就是0001 1110

    1. 計(jì)數(shù)器輸出+ CO

    2. 內(nèi)存地址寄存器輸入+ MI

    3. 給一個(gè)脈沖

  2. 將內(nèi)存地址中的值放到指令寄存器中

    1596941570068

    可以看到ROM中數(shù)據(jù)給了指令寄存器

    1. 將內(nèi)存輸出打開+ RO

    2. 指令寄存器輸入+ II

    3. 給一個(gè)脈沖

這兩步操作取址的操作就完成了,要執(zhí)行下一個(gè)代碼,計(jì)數(shù)器加一

  1. 計(jì)數(shù)器加1 CE+

    1596941697583

    計(jì)數(shù)器加一

    1. 給一個(gè)脈沖,計(jì)數(shù)器加一變成0001

執(zhí)行任何的代碼都需要上面的三步,上面三步又稱取址周期,其實(shí)就是將計(jì)數(shù)器對應(yīng)的ROM中的值放到指令寄存器中,然后計(jì)數(shù)器加1。下面來解析命令和執(zhí)行命令,這才是與命令相關(guān)的控制邏輯

LDA指令 LDA 14 ,控制器看到指令寄存器的高四位是0001,就知道這是對應(yīng)LDA的操作,就會(huì)執(zhí)行LDA的控制,這是由控制器完成的,我們稍后構(gòu)建它,現(xiàn)在還是手動(dòng)操作,假設(shè)自己的控制器

  1. 將指令寄存器后4BIt 輸入到內(nèi)存地址寄存器中 ,以獲得內(nèi)存地址14中的內(nèi)容

    1596942075100

    因?yàn)橹噶罴拇嫫髦挥械谒奈唤尤氲娇偩€中,所以地址寄存器獲取第四位的地址數(shù)據(jù),ROM中顯示了該地址中的值,也就是0001 1100其值為28

    1. 指令寄存器輸出 + IO

    2. 內(nèi)存地址寄存器輸入 + MI

    3. 給一個(gè)脈沖

  2. 將內(nèi)存地址中的值輸出到寄存器A

    1596942293927

    可以看到內(nèi)存中的值給了寄存器A,同時(shí)因?yàn)榧拇嫫鰾位0,ALU就顯示了A+0的值,

    至此完成了LDA的命令,將地址14中的值放到寄存器A中。下面執(zhí)行第二個(gè)命令

    1. 內(nèi)存輸出+ RO

    2. 寄存器A輸入+ AI

    3. 給一個(gè)脈沖

ADD指令解析 ADD 15, 要執(zhí)行到該指令現(xiàn)到取到該指令,跟之前的三部取址周期一樣

1596942563558

指令計(jì)數(shù)器的值給地址寄存器

1596942622042

內(nèi)存地址中的值給指令寄存器

1596942689773

計(jì)數(shù)器加1,這個(gè)時(shí)候控制器通過指令寄存器高四位0010分析出執(zhí)行ADD控制

  1. 將指令寄存器后4bit輸入到內(nèi)存地址寄存器中

    1596942802043

    將指令寄存器中的低四位放到地址寄存器中,這個(gè)時(shí)候ROM顯示該地址中的值 0000 1110 其值位14

    1. 指令寄存器輸出+ IO

    2. 內(nèi)存地址寄存器輸入+ MI

    3. 給一個(gè)脈沖

  2. 將內(nèi)存地址15中的值放到B寄存器中,ALU會(huì)自動(dòng)計(jì)算出值

    1596942944799

    可以看到ALU自動(dòng)算出求和的值

    1. 內(nèi)存輸出+ RO

    2. 寄存器B輸入+ BI

    3. 給一個(gè)脈沖

  3. 將ALU中的值輸出到寄存器A中

    1596943047179

    這邊寄存器A獲得ALU的值,同時(shí)ALU更新了,這邊非常酷,鎖操作只發(fā)生在脈沖的上升沿,

    1. ALU的輸出 +EO

    2. 寄存器A輸入+AI

    3. 給一個(gè)脈沖

OUT命令 OUT,前3步是一樣的

1596943163560

1596943188827

1596943211095

  1. 將A寄存器中的值顯示出來

    1596943388471

    1. 將A寄存器輸出+ AO

    2. output寄存器輸入 OI

    3. 給一個(gè)脈沖

到這程序執(zhí)行完了

總結(jié)一下

1596943438035

這些小的指令稱為微指令,這些微指令的前三步都是相同的,之后的操作是不同的,

所以需要控制位對每個(gè)指令構(gòu)造控制邏輯

反正我控制位按照一定的順序排序

每一種微指令對應(yīng)一種控制序列。

真正的微指令會(huì)占用余下的時(shí)間片,實(shí)際上我們需要一個(gè)獨(dú)立的計(jì)數(shù)器,所以需要一個(gè)獨(dú)立的計(jì)數(shù)器

上面通過手動(dòng)的方式設(shè)置控制位,然后手動(dòng)發(fā)送一次主脈沖,在兩個(gè)主脈沖之間改變它的控制位,,所以我們實(shí)際上還需要另一個(gè)脈沖來控制 ,這邊可以用主脈沖的倒轉(zhuǎn),通過非門開獲得另一個(gè)脈沖

這邊還要將各個(gè)指令分步,才能夠讓控制器知道執(zhí)行到了哪一步,可以看到每個(gè)指令最多5步,有些步數(shù)可以合并就合并了。從T0-T4,而有些指令用不到4步,那么多余的步數(shù)計(jì)算機(jī)什么也不做就浪費(fèi)了。這是無法避免的

1596943665929

現(xiàn)在脈沖有了,步數(shù)分解有了,需要將脈沖變成步數(shù),這和程序計(jì)數(shù)器是一樣的,使用74LS161,這是一個(gè)四位的計(jì)數(shù)器,

1596944835708

1596944992084

1596945315281

計(jì)數(shù)器有了,現(xiàn)在要將計(jì)數(shù)器解碼,這邊用到了74LS138芯片,

1596946104190

1596946117754

可以看到其轉(zhuǎn)換成明確信號,這邊和顯示部分用到的139解碼是一樣的邏輯

1596946666073

1596946961129

這邊我們可以可以清晰的看到程序走到了哪個(gè)時(shí)間片,哪一步

下面我們構(gòu)建非??岬氖虑椋簿褪强刂破鞯恼嬷当?/p>

1596947212731

第一個(gè)取址,可以看到前兩步,

第二個(gè)LDA用了剩余的三步,最后一步什么也沒做。

第三個(gè)ADD也是三部

1596947378724

用兩個(gè)28C16就可以完成其組合邏輯,其有11條地址線,8個(gè)輸出線。

1596947463538

將真值表輸入到28C16中就可以完成控制

Reset

1596949153296

這邊如果程序執(zhí)行完成,需要將所有的寄存器清空,這邊我們構(gòu)建這樣一個(gè)reset電路用來一個(gè)74LS00來構(gòu)建

1596949310054

將reset和~reset接到所有的寄存器

1596949536837

到目前為止,計(jì)算機(jī)的主體部分就做好了

Arduino寫入指令

Arduino的接線方式和之前的顯示解碼器的方式相同,這邊就不過多說了。

直接上程序

#define SHIFT_DATA 2
#define SHIFT_CLK 3
#define SHIFT_LATCH 4
#define EEPROM_D0 5         
#define EEPROM_D7 12
#define WRITE_EN 13

#define HLT 0b1000000000000000  // Halt clock                   HLT信號
#define MI  0b0100000000000000  // Memory address register in   內(nèi)存地址輸入
#define RI  0b0010000000000000  // RAM data in                  內(nèi)存數(shù)據(jù)輸入
#define RO  0b0001000000000000  // RAM data out                 內(nèi)存數(shù)據(jù)輸出
#define IO  0b0000100000000000  // Instruction register out     指令寄存器輸出
#define II  0b0000010000000000  // Instruction register in      指令寄存器輸入
#define AI  0b0000001000000000  // A register in                A寄存器輸入
#define AO  0b0000000100000000  // A register out               A寄存器輸出
#define EO  0b0000000010000000  // ALU out                      ALU輸出
#define SU  0b0000000001000000  // ALU subtract                 減法
#define BI  0b0000000000100000  // B register in                B寄存器輸入
#define OI  0b0000000000010000  // Output register in           輸出寄存器輸入
#define CE  0b0000000000001000  // Program counter enable       程序計(jì)數(shù)允許
#define CO  0b0000000000000100  // Program counter out          程序計(jì)數(shù)器輸出
#define J   0b0000000000000010  // Jump (program counter in)    程序計(jì)數(shù)器輸入(JUMP)

uint16_t data[] = {             // 列是步數(shù),行是不同的指令
  MI|CO,  RO|II|CE,  0,      0,      0,         0, 0, 0,   // 0000 - NOP
  MI|CO,  RO|II|CE,  IO|MI,  RO|AI,  0,         0, 0, 0,   // 0001 - LDA 加載
  MI|CO,  RO|II|CE,  IO|MI,  RO|BI,  EO|AI,     0, 0, 0,   // 0010 - ADD 加法
  MI|CO,  RO|II|CE,  IO|MI,  RO|BI,  EO|AI|SU,  0, 0, 0,   // 0011 - SUB 減法
  MI|CO,  RO|II|CE,  IO|MI,  AO|RI,  0,         0, 0, 0,   // 0100 - STA 將寄存器A中值寫入ROM中
  MI|CO,  RO|II|CE,  IO|AI,  0,      0,         0, 0, 0,   // 0101 - LDI 將指令寄存器中值寫入寄存器A
  MI|CO,  RO|II|CE,  IO|J,   0,      0,         0, 0, 0,   // 0110 - JMP 跳轉(zhuǎn)到指令寄存器第四位的計(jì)數(shù)
  MI|CO,  RO|II|CE,  0,      0,      0,         0, 0, 0,   // 0111
  MI|CO,  RO|II|CE,  0,      0,      0,         0, 0, 0,   // 1000
  MI|CO,  RO|II|CE,  0,      0,      0,         0, 0, 0,   // 1001
  MI|CO,  RO|II|CE,  0,      0,      0,         0, 0, 0,   // 1010
  MI|CO,  RO|II|CE,  0,      0,      0,         0, 0, 0,   // 1011
  MI|CO,  RO|II|CE,  0,      0,      0,         0, 0, 0,   // 1100
  MI|CO,  RO|II|CE,  0,      0,      0,         0, 0, 0,   // 1101
  MI|CO,  RO|II|CE,  AO|OI,  0,      0,         0, 0, 0,   // 1110 - OUT 輸出
  MI|CO,  RO|II|CE,  HLT,    0,      0,         0, 0, 0,   // 1111 - HLT 停機(jī)
};


/*
 *使用移位寄存器輸出地址位和outputEnable信號。
 */
void setAddress(int address, bool outputEnable) {
  shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, (address >> 8) | (outputEnable ? 0x00 : 0x80));
  shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, address);

  digitalWrite(SHIFT_LATCH, LOW);
  digitalWrite(SHIFT_LATCH, HIGH);
  digitalWrite(SHIFT_LATCH, LOW);
  
}


/*
 * 從指定地址的EEPROM讀取一個(gè)字節(jié)。
 */
byte readEEPROM(int address) {
  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
    pinMode(pin, INPUT);
  }
  setAddress(address, /*outputEnable*/ true);

  byte data = 0;
  for (int pin = EEPROM_D7; pin >= EEPROM_D0; pin -= 1) {
    data = (data << 1) + digitalRead(pin);
  }
  return data;
}


/*
 * 將字節(jié)寫入指定地址的EEPROM。
 */
void writeEEPROM(int address, byte data) {
  setAddress(address, /*outputEnable*/ false);//設(shè)置地址
  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
    pinMode(pin, OUTPUT);//設(shè)置數(shù)據(jù)輸出引腳
  }

  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
    digitalWrite(pin, data & 1);//每個(gè)數(shù)據(jù)引腳賦值
    data = data >> 1;
  }
  digitalWrite(WRITE_EN, LOW);//設(shè)置脈沖
  delayMicroseconds(1);
  digitalWrite(WRITE_EN, HIGH);
  delay(10);
}


/*
 * 讀取EEPROM的內(nèi)容并將其打印到串行監(jiān)視器。
 */
void printContents() {
  for (int base = 0; base <= 255; base += 16) {
    byte data[16];
    for (int offset = 0; offset <= 15; offset += 1) {
      data[offset] = readEEPROM(base + offset);
    }

    char buf[80];
    sprintf(buf, "%03x:  %02x %02x %02x %02x %02x %02x %02x %02x   %02x %02x %02x %02x %02x %02x %02x %02x",
            base, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
            data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]);

    Serial.println(buf);
  }
}


void setup() {
  // put your setup code here, to run once:
  pinMode(SHIFT_DATA, OUTPUT);
  pinMode(SHIFT_CLK, OUTPUT);
  pinMode(SHIFT_LATCH, OUTPUT);
  digitalWrite(WRITE_EN, HIGH);
  pinMode(WRITE_EN, OUTPUT);
  Serial.begin(57600);

  // 寫數(shù)據(jù)
  Serial.print("寫 EEPROM");
  writeEEPROM(0, 0);        
  // 將微碼的8個(gè)高位寫到EEPROM的前128個(gè)字節(jié)中
  for (int address = 0; address < sizeof(data)/sizeof(data[0]); address += 1) {
    writeEEPROM(address, data[address] >> 8);

    if (address % 64 == 0) {
       writeEEPROM(address, data[address] >> 8);
      Serial.print(".");
    }
  }

  // 將微碼的8個(gè)低位寫到EEPROM的前128個(gè)字節(jié)中
  for (int address = 0; address < sizeof(data)/sizeof(data[0]); address += 1) {
    writeEEPROM(address + 128, data[address]);

    if (address % 64 == 0) {
      writeEEPROM(address + 128, data[address]);
      Serial.print(".");
    }
  }

  Serial.println(" done");


  // 讀并打印出EERPROM的內(nèi)容
  Serial.println("讀 EEPROM");
  printContents();
}


void loop() {
  // put your main code here, to run repeatedly:

}

添加了更多的指令 ,SUB,STA,LDI,JMP

這時(shí)候計(jì)算機(jī)可以做更多的功能了。

標(biāo)志跳轉(zhuǎn)

現(xiàn)在討論一個(gè)問題:

這是不是計(jì)算機(jī)

這是不是計(jì)算機(jī),還只是一個(gè)計(jì)算器

這個(gè)計(jì)算機(jī)的頻率只有300HZ左右

是否需要乘法,指數(shù),對數(shù),三角函數(shù)等指令,這些指令肯定是做不出來的,那么問題就回來了我們真正需要什么樣的指令,什么樣的指令才能稱為計(jì)算機(jī),計(jì)算機(jī)是什么?

計(jì)算機(jī):

可以完成任何的指令

可以完成任何的可計(jì)算的問題

什么是可計(jì)算的什么是不可計(jì)算的

這不是計(jì)算機(jī)性能的問題,是通過算法能完成的問題

那么問題就變成了我們需要完成什么樣的算法。

1596950967140

這個(gè)問題在計(jì)算機(jī)早期圖靈就進(jìn)行研究過

1936年 他寫了關(guān)于這個(gè)問題的一篇論文。這篇論文得出的結(jié)論是,他可以發(fā)明一種機(jī)器,可以完成任何計(jì)算序列

他是這樣描述的:

1596951099319

有一個(gè)無限長的紙帶,上面有方格,有1和0兩種狀態(tài),有一個(gè)小旗子可以指向這些方格,小旗子有一個(gè)狀態(tài)A,一次只能移動(dòng)一個(gè)。

有一個(gè)小旗子和其狀態(tài)的真值表

現(xiàn)在這個(gè)狀態(tài),A ,瀏覽狀態(tài)是1,就將1寫到袋子上,然后向左移動(dòng)一格,自身的狀態(tài)變成C,就變成了下面的狀態(tài)

1596951323841

根據(jù)這個(gè)真值表進(jìn)行一直不停的循環(huán)做,一旦停止到Halt,紙帶上就是結(jié)果,

這個(gè)機(jī)器就能完成任何的數(shù)學(xué)算法。只需要設(shè)置好這個(gè)指令表就好了

實(shí)際上圖靈還提高一個(gè)更好的計(jì)算機(jī),稱為通用計(jì)算機(jī),這個(gè)機(jī)器上有一個(gè)指令表,是一個(gè)最基本的狀態(tài),其他計(jì)算機(jī)可以通過編碼的方法將算法映射到這個(gè)指令表上

1596951496917

到這邊就知道了任何可計(jì)算的問題都可以變成一個(gè)可計(jì)算的序列

在同一個(gè)時(shí)期邱奇也思考了相同的問題

1596951629710

他寫了一篇論文關(guān)于什么是計(jì)算能力的定義,從完全不同的角度切入這個(gè)問題,他提出新的數(shù)學(xué)系統(tǒng)稱為論的演算。

1596951770800

這便有一些變量,有一些函數(shù),還有一些函數(shù)的結(jié)果

1596951837610

在論文的后面,他定義了一些函數(shù),他用這個(gè)方法表達(dá)計(jì)算機(jī),有點(diǎn)像現(xiàn)在的Lambda表達(dá)式

這篇論文的結(jié)論是:不是所有的問題都可以通過計(jì)算解決,有些可以,有些不可以,

在1936年兩個(gè)人從兩種不同的角度思考了這個(gè)問題

當(dāng)圖靈在8月份讀到邱奇的論文,將邱奇的論文放到了附錄中,任何問題可以轉(zhuǎn)換成論的計(jì)算的問題都可以轉(zhuǎn)化成一個(gè)可計(jì)算的問題

1596952089932

我們計(jì)算機(jī)和圖靈機(jī)比較還缺少什么呢,圖靈機(jī)有一個(gè)操作我們做不到,同一個(gè)指令可以有不同的操作

1596952196605

如果紙帶是空格向右移動(dòng)如果紙帶為1向左移動(dòng),

有一種指令叫做有條件跳轉(zhuǎn)指令可以做到這一點(diǎn),它和我們的跳轉(zhuǎn)指令有一點(diǎn)像,現(xiàn)在的跳轉(zhuǎn)指令只能跳轉(zhuǎn)到固定的地址

1596952407072

1596952609827

左右等價(jià)

根據(jù)不同的值來進(jìn)行不同的行為

所以我們可以說如果實(shí)現(xiàn)條件跳轉(zhuǎn)指令我們就可以模擬任何圖靈機(jī)

1596952687837

條件跳轉(zhuǎn)

準(zhǔn)備實(shí)現(xiàn)兩個(gè)條件跳轉(zhuǎn)指令,為0跳轉(zhuǎn)和進(jìn)位跳轉(zhuǎn)0

為0跳轉(zhuǎn),這個(gè)跳轉(zhuǎn)需要計(jì)算ALU中所有的值是否為0 ,

1596952884977

1596953419345

使用這個(gè)電路我們就可以判斷是否為0

74LS08有4個(gè)與門和74LS02有4個(gè)Nor門

1596953519894

1596953553123

進(jìn)位跳轉(zhuǎn)

ALU中高4位芯片有一個(gè)進(jìn)位引腳,我們很容易就可以判斷出是否進(jìn)位了。

1596953063355

1596953205213

這邊就搭建好了2個(gè)標(biāo)識,但是有一個(gè)問題,

1596953868102

在獲得這個(gè)標(biāo)識后,加命令還有一步就是將ALU中的值放到寄存器A中,這樣在進(jìn)行跳轉(zhuǎn)指令的時(shí)候標(biāo)識就沒有了,

所以這邊需要將進(jìn)位標(biāo)識存起來,這邊我們需要一個(gè)173芯片

其實(shí)Internal x86也有進(jìn)位標(biāo)識計(jì)數(shù)器

1596953993712

一共32位

1596954106259

這樣就多了一個(gè)控制線,F(xiàn)I:標(biāo)識Flag的輸入,

1596954530834

這是新的真值表,用了10個(gè)地址位,非常棒

直接用Arduino寫入真值表

#define SHIFT_DATA 2
#define SHIFT_CLK 3
#define SHIFT_LATCH 4
#define EEPROM_D0 5
#define EEPROM_D7 12
#define WRITE_EN 13

#define HLT 0b1000000000000000  // Halt clock                   HLT信號
#define MI  0b0100000000000000  // Memory address register in   內(nèi)存地址輸入
#define RI  0b0010000000000000  // RAM data in                  內(nèi)存數(shù)據(jù)輸入
#define RO  0b0001000000000000  // RAM data out                 內(nèi)存數(shù)據(jù)輸出
#define IO  0b0000100000000000  // Instruction register out     指令寄存器輸出
#define II  0b0000010000000000  // Instruction register in      指令寄存器輸入
#define AI  0b0000001000000000  // A register in                A寄存器輸入
#define AO  0b0000000100000000  // A register out               A寄存器輸出
#define EO  0b0000000010000000  // ALU out                      ALU輸出
#define SU  0b0000000001000000  // ALU subtract                 減法
#define BI  0b0000000000100000  // B register in                B寄存器輸入
#define OI  0b0000000000010000  // Output register in           輸出寄存器輸入
#define CE  0b0000000000001000  // Program counter enable       程序計(jì)數(shù)允許
#define CO  0b0000000000000100  // Program counter out          程序計(jì)數(shù)器輸出
#define J   0b0000000000000010  // Jump (program counter in)    程序計(jì)數(shù)器輸入(JUMP)
#define FI  0b0000000000000001  // Flags in                     Flags 標(biāo)志位輸入    

#define FLAGS_Z0C0 0
#define FLAGS_Z0C1 1
#define FLAGS_Z1C0 2
#define FLAGS_Z1C1 3

#define JC  0b0111
#define JZ  0b1000

uint16_t UCODE_TEMPLATE[16][8] = {
  { MI|CO,  RO|II|CE,  0,      0,      0,           0, 0, 0 },   // 0000 - NOP
  { MI|CO,  RO|II|CE,  IO|MI,  RO|AI,  0,           0, 0, 0 },   // 0001 - LDA
  { MI|CO,  RO|II|CE,  IO|MI,  RO|BI,  EO|AI|FI,    0, 0, 0 },   // 0010 - ADD
  { MI|CO,  RO|II|CE,  IO|MI,  RO|BI,  EO|AI|SU|FI, 0, 0, 0 },   // 0011 - SUB
  { MI|CO,  RO|II|CE,  IO|MI,  AO|RI,  0,           0, 0, 0 },   // 0100 - STA
  { MI|CO,  RO|II|CE,  IO|AI,  0,      0,           0, 0, 0 },   // 0101 - LDI
  { MI|CO,  RO|II|CE,  IO|J,   0,      0,           0, 0, 0 },   // 0110 - JMP
  { MI|CO,  RO|II|CE,  0,      0,      0,           0, 0, 0 },   // 0111 - JC
  { MI|CO,  RO|II|CE,  0,      0,      0,           0, 0, 0 },   // 1000 - JZ
  { MI|CO,  RO|II|CE,  0,      0,      0,           0, 0, 0 },   // 1001
  { MI|CO,  RO|II|CE,  0,      0,      0,           0, 0, 0 },   // 1010
  { MI|CO,  RO|II|CE,  0,      0,      0,           0, 0, 0 },   // 1011
  { MI|CO,  RO|II|CE,  0,      0,      0,           0, 0, 0 },   // 1100
  { MI|CO,  RO|II|CE,  0,      0,      0,           0, 0, 0 },   // 1101
  { MI|CO,  RO|II|CE,  AO|OI,  0,      0,           0, 0, 0 },   // 1110 - OUT
  { MI|CO,  RO|II|CE,  HLT,    0,      0,           0, 0, 0 },   // 1111 - HLT
};

uint16_t ucode[4][16][8];//主要把指令根據(jù)進(jìn)位劃分一下

void initUCode() {
  // ZF = 0, CF = 0
  memcpy(ucode[FLAGS_Z0C0], UCODE_TEMPLATE, sizeof(UCODE_TEMPLATE));

  // ZF = 0, CF = 1
  memcpy(ucode[FLAGS_Z0C1], UCODE_TEMPLATE, sizeof(UCODE_TEMPLATE));
  ucode[FLAGS_Z0C1][JC][2] = IO|J;

  // ZF = 1, CF = 0
  memcpy(ucode[FLAGS_Z1C0], UCODE_TEMPLATE, sizeof(UCODE_TEMPLATE));
  ucode[FLAGS_Z1C0][JZ][2] = IO|J;

  // ZF = 1, CF = 1
  memcpy(ucode[FLAGS_Z1C1], UCODE_TEMPLATE, sizeof(UCODE_TEMPLATE));
  ucode[FLAGS_Z1C1][JC][2] = IO|J;
  ucode[FLAGS_Z1C1][JZ][2] = IO|J;
}

/*
 * 使用移位寄存器輸出地址位和outputEnable信號。
 */
void setAddress(int address, bool outputEnable) {
  shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, (address >> 8) | (outputEnable ? 0x00 : 0x80));
  shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, address);

  digitalWrite(SHIFT_LATCH, LOW);
  digitalWrite(SHIFT_LATCH, HIGH);
  digitalWrite(SHIFT_LATCH, LOW);
}


/*
 * 從指定地址的EEPROM讀取一個(gè)字節(jié)。
 */
byte readEEPROM(int address) {
  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
    pinMode(pin, INPUT);
  }
  setAddress(address, /*outputEnable*/ true);

  byte data = 0;
  for (int pin = EEPROM_D7; pin >= EEPROM_D0; pin -= 1) {
    data = (data << 1) + digitalRead(pin);
  }
  return data;
}


/*
 * 將字節(jié)寫入指定地址的EEPROM。
 */
void writeEEPROM(int address, byte data) {
  setAddress(address, /*outputEnable*/ false);
  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
    pinMode(pin, OUTPUT);
  }

  for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) {
    digitalWrite(pin, data & 1);
    data = data >> 1;
  }
  digitalWrite(WRITE_EN, LOW);
  delayMicroseconds(1);
  digitalWrite(WRITE_EN, HIGH);
  delay(10);
}


/*
 *讀取EEPROM的內(nèi)容并將其打印到串行監(jiān)視器。
 */
void printContents(int start, int length) {
  for (int base = start; base < length; base += 16) {
    byte data[16];
    for (int offset = 0; offset <= 15; offset += 1) {
      data[offset] = readEEPROM(base + offset);
    }

    char buf[80];
    sprintf(buf, "%03x:  %02x %02x %02x %02x %02x %02x %02x %02x   %02x %02x %02x %02x %02x %02x %02x %02x",
            base, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
            data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]);

    Serial.println(buf);
  }
}


void setup() {
  // put your setup code here, to run once:
  initUCode();

  pinMode(SHIFT_DATA, OUTPUT);
  pinMode(SHIFT_CLK, OUTPUT);
  pinMode(SHIFT_LATCH, OUTPUT);
  digitalWrite(WRITE_EN, HIGH);
  pinMode(WRITE_EN, OUTPUT);
  Serial.begin(57600);

  // Program data bytes
  Serial.print("寫 EEPROM");

 // 將微碼的8個(gè)高位寫到EEPROM的前128個(gè)字節(jié)中
  writeEEPROM(0,0);
  for (int address = 0; address < 1024; address += 1) {
    int flags       = (address & 0b1100000000) >> 8;//flag標(biāo)識
    int byte_sel    = (address & 0b0010000000) >> 7;//高低位標(biāo)識
    int instruction = (address & 0b0001111000) >> 3;//指令
    int step        = (address & 0b0000000111);//步數(shù)

    if (byte_sel) {//高低位
      writeEEPROM(address, ucode[flags][instruction][step]);
    } else {
      writeEEPROM(address, ucode[flags][instruction][step] >> 8);
    }

    if (address % 64 == 0) {
       if (byte_sel) {
          writeEEPROM(address, ucode[flags][instruction][step]);
       } else {
         writeEEPROM(address, ucode[flags][instruction][step] >> 8);
       }
      Serial.print(".");
    }
  }

  Serial.println(" done");


  // Read and print out the contents of the EERPROM
  Serial.println("讀 EEPROM");
  printContents(0, 1024);
}


void loop() {
  // put your main code here, to run repeatedly:

}

到這就做好了。

總結(jié)

我收獲了什么:

計(jì)算機(jī)底層是怎么運(yùn)行,控制器是怎么控制

調(diào)試的時(shí)候也遇到一些坑

寄存器沒有正常工作

指令計(jì)數(shù)器工作正常,寄存器A和寄存器B工作不正常,這三個(gè)模塊是同一個(gè)脈沖線接過來的,先接入指令計(jì)數(shù)器,再接入寄存器A和寄存器B,

一開始并沒有懷疑脈沖線的問題,因?yàn)橹噶钣?jì)數(shù)器正常工作,寄存器沒有正常工作,檢查了寄存器的接線發(fā)現(xiàn)沒有問題,量了電壓發(fā)現(xiàn)脈沖電壓非常小0.02V波動(dòng),這也太不正常了,量了下指令計(jì)數(shù)器的電壓是正常的,這就很奇怪了,后來發(fā)現(xiàn)最后寄存器脈沖線短路接地了,導(dǎo)致一直沒有脈沖,

控制器沒有正常工作

發(fā)現(xiàn)控制器是輸出不正常,做了個(gè)簡單的測試電路,手動(dòng)檢查控制器的eprom內(nèi)存的值,發(fā)現(xiàn)確實(shí)沒有輸出正確的值,檢查Arduino nano的寫入接線和視頻中接線不同,導(dǎo)致寫入數(shù)據(jù)地址也不相同,調(diào)整Arduino nano和控制線,輸出正常,

經(jīng)驗(yàn)

  1. 每個(gè)模塊先用跳線接一下再進(jìn)行測試,如果發(fā)現(xiàn)測試沒有問題再用標(biāo)準(zhǔn)接線將其接通,

  2. 正常調(diào)試需要一步步執(zhí)行,當(dāng)出現(xiàn)異常了先解決出現(xiàn)的第一個(gè)異常,然后再解決剩余的異常,遇到異常不要慌,一步步解決,不要跳過問題進(jìn)行下一個(gè)問題。

引用

大佬的視頻教程,截圖基本都源自于該大佬,并稍加改動(dòng)

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多