半熟前端

軟體工程師 / 台灣人 / 在前端的路上一邊探索其他領域的可能性

雜談

2020 年尾聲,來聊聊電腦是什麼

2020 年尾聲,來聊聊電腦是什麼

背景

2020 年是個混亂的一年,同時也是讓我重新思考電腦本質的一年。在這一年我做了很多非自己擅長領域的嘗試,基本上都圍繞著一個主題:重新認識底層。

我在高中(正確來說是高職)是念電子科的,在升學為主流的時代,雖然有實習課,但更多的感覺是按表操課,然後大部分的時間都在唸書解題。唯一慶幸的是課業並不像一般高中繁重,不然我可能也考不上台科。

在高職有一點蠻可惜的是我對動手做的東西沒有太大興趣,而且有一大部分的時間是在教焊接、接麵包板、線不准重疊、不能跳線,對我這種手藝不巧的人來說其實很苦手。

其實在念電子科的時候本身也對電子沒有太大興趣,甚至也沒預料到後來會以寫程式維生。不過也因為如此,最近我開始對這些比較底層的東西開始感興趣。

回到這個問題本身,答案取決於你對電腦的掌握有多深。二極體與電晶體、暫存器、CPU 運作、作業系統,每一個領域的知識都是窮盡一生都不一定能夠探究完成。真的好深奧。

對我來說,今年就是好好理解電腦是什麼的一年,雖然自己並非專業,但是我在其中理解許多樂趣,同時也在公司找到對底層同樣有興趣的同事。

與電子科的重疊

在高職學電子科的相關知識時,我其實沒有預料到原來這些知識在後來派上那麼大用場。像是橋式整流、二極體、濾波、穩壓這些東西,就是在充電器時常用到的電路。這個東西考試不只算了好幾百遍,甚至實習課叫你接一個橋式整流電路實驗。

CPU 加法時需要實作一個加法器,其中又分為半加器、全加器,這些也是在課堂上一步步學真值表,用邏輯閘一步步在麵包板上實作出來的(當然也可以直接用 IC)。

CPU 工作需要時脈,一般會用石英震盪器,或者是另外接一個時脈產生器。哇,原來當初學得要死要活的 NE555 電路可以產生時脈讓 CPU 運作!(當然現在都是內建了)

當初覺得莫名其妙的正反器,原來就是實作暫存器的基礎。當我理解到越來越多基礎,我才發現原來這些東西我在高職時已經走過一回了,只是當時並沒有把這些知識串連在一起而已。

這些涉及底層的知識有種神秘感,一方面是進入門檻相對高,畢竟不會有人天天買 chip 差麵包板,而且需要對每個知識點都有一些了解;另一方面就是網路上實在太少資訊,關鍵字搜尋可能要找很久才發現答案在某個論壇底下的第 x 個留言,很多時候遇到問題要想辦法靠自己解決。

重新回歸基礎

有鑑於此,在 2020 年一個課題是我希望盡可能地接近底層,可以是硬體、可以是作業系統運作、可以是認識程式語言運作。總之可以讓我了解底層的東西都可以。

於是在今年年初我買了 Arduino。有些人可能覺得 Arduino 不就只是一個別人兜好的東西嗎?沒錯,但我想我可以先從這一步開始。某個 sensor 先不要用別人寫好的 Library,自己翻 datasheet 看看要怎麼用,如果真的不行再看看函式庫的實作。

在今年七月份,我用 Arduino 與 ESP32 實作了一個空氣品質監測應用,裡頭用到了 MQTT、DHT11 與 MH-Z14A,資料通訊的部分則是使用的 UART。比起套套函式庫,在 MH-Z14A 的部分還是扎實地看完了 datasheet 並且實作出來。雖然 wifi 跟 MQTT 的部分還是直接使用 library,不過對我來說還是學到很多東西。

這樣子還不夠,我不想要有一個 Arduino 的殼阻撓我。於是我在 Amazon 上找了傳說中的 MOS 6502。

MOS 6502 之所以經典是因為他足夠便宜而且效能方面又相對優秀,所以像是 Fami con、Apple II 都是採用這顆 8bit 的 CPU。再來就是比起現代的 CPU,他的指令集跟設計也相對簡單許多,所以可以更好理解 CPU 的運作。

起初我很興奮地下單並且等待它到來,後來才想到 MOS 6502 並沒有內建 EEPROM,你必須要將程式寫到 EEPROM 然後送給 MOS 6502 讀取才行。但是目前我在日本沒有一個比較好的管道買到我想要的 EEPROM,因此這條路暫時作罷。

取而代之的是 AVR,在目前住的地方附近剛好有電子零件行,裡頭有賣各種 atmega 系列的 micro controller。於是我隨便挑了幾個(ATMEGA328,剛好就是 Arduino UNO 使用的 MCU)。

用 ATMEGA328 的好處是第一他的體積剛好可以放到麵包板上,再來是他的指令集也相對簡單,另外就是一些 AVR 特有的優點,像是:

  • 32 個暫存器,比起其他架構多很多(x86: 8 個、ARM: 16 個)
  • 大部分的 instruction 都只要一個 clock
  • 大部分的 AVR chip 內建 flash 跟 EEPROM,不需要再準備 EEPROM,讀取上也會更有效率

認識組合語言、硬體邏輯

在硬體的世界裡頭一切變得很單純,也很不方便。假設你想讓某某 pin 腳輸出高電位,用純組合語言(AVR)可能要這樣寫:

ldi r16, 0x01
out DDRB, r16
out PORTB, r16

首先將 0x01 放到 r16 這個暫存器中,然後將 DDRB 暫存器(data direction)設為 0x01 ,然後將 PORTB 設為 0x01 其實在做的事情跟 digitalWrite 很像。

但意外的是組合語言並沒有想像中的那麼困難,不過我想要寫出業界等級的組合語言應該很難就是了。

更深層理解中斷(Interrupt)

我還沒有完全通透中斷機制是怎麼運作的(包含硬體電路等),但對於中斷(Interrupts)有更深層了解。

一般 CPU 當中會定義 Interrupt Vector,來描述當中斷發生時 CPU 應該要做什麼事,而中斷與否通常是靠 SREG 的 Global Interrupt Enable bit 來判斷。由於這需要對暫存器操作跟 bit shift 有足夠了解,在 AVR 當中通常有幾個函數對應(avr/interrupt.h)。

這部分很有趣,但也蠻容易出事情的,如果是玩具專案還好,但不知道大家在 production 上都是怎麼管理、debug 中斷機制的。

認識作業系統

在今年 3 ~ 4 月左右斷斷續續看的 Coursera 上的作業系統課程,從 PC(program counter)、IR(Instruction Counter)、kernel mode、user mode、atmoic、thread 一路理解到信號量(semaphore),對於實作什麼的還是完全霧煞煞。但至少有一個「比較」好的理解。最近剛好看到一本 30 天自製 OS,雖然說看起來很陽春,而且一定省略很多細節,不過我覺得感覺蠻有趣的,或許哪天有空會嘗試做做看。比起跑模擬器,我還是更喜歡直接在實機上測試啊!

operating system-30

程式語言

在今年年初我意外看到松本行弘寫的「まつもとゆきひろ 言語のしくみ」,在裡頭他從頭(yacc/lex)實作了一個程式語言,並且一一講解裡頭的原理跟實作方式。我還蠻驚訝他的完成度的,不是只有計算機加減乘除那麼簡單而已,而是包含字串、時間處理、數字、隨機、陣列、atmoic 等,一個程式語言該有的基本都算是實作好了。 雖然我也想做類似的事情,但是真的看不太懂 yacc/lex 的文件,等自己對 C 語言有更深一層掌握時再來挑戰。

另外一個是我在參加 IT 鐵人賽的時候有試著從頭實作一個簡易的 Svelte(沒有 reactive 功能),寫了一個簡單的 parser。算是稍微碰到程式語言的邊 XD

未來還有很多要學習的地方!大家一起努力走過這混亂的一年吧!