เหตุผลที่ชุดคำสั่ง 6502 เหมาะเป็นภาษาแอสเซมบลีตัวแรก
(nemanjatrifunovic.substack.com)- แอสเซมบลีเชื่อมโยงกับโครงสร้าง CPU โดยตรง จึงสำคัญมากว่าควรเริ่มเรียนกับอะไร และ 6502 ก็เป็นแพลตฟอร์มเริ่มต้นที่มีทั้ง โครงสร้างเรียบง่าย และระบบนิเวศที่ใช้งานได้จริง
- ด้วยรีจิสเตอร์เพียง 6 ตัวและชุดคำสั่งดั้งเดิมแค่ 56 คำสั่ง ผู้เรียนจึงทำความเข้าใจ แนวคิดพื้นฐาน อย่างรีจิสเตอร์ การโหลด/จัดเก็บ การคำนวณเชิงตรรกะและเลขคณิต และการแตกแขนงได้อย่างรวดเร็ว
- มันเป็น CPU ที่ถูกใช้จริงใน Apple II, Commodore VIC 20, Commodore 64, BBC micro ฯลฯ จึงเรียนแบบ ลงมือปฏิบัติจริง ได้ง่ายผ่านอีมูเลเตอร์ ฮาร์ดแวร์จำลอง และแหล่งข้อมูลฟรี
- Easy 6502 มี แอสเซมเบลอร์และซิมูเลเตอร์ ที่เขียนด้วย JavaScript ให้ลองเขียนโค้ดได้ทันทีบนเว็บ จึงเหมาะกับการจับทางในเวลาไม่นาน
- แม้ Z80, RISC สมัยใหม่ และ x86-x64 ก็มีคุณค่าในการเรียนรู้ แต่สำหรับก้าวแรก 6502 ที่ซับซ้อนน้อยกว่าจะช่วยลดภาระในการเรียน
เหตุผลที่ 6502 เหมาะสำหรับผู้เริ่มต้น
- การเขียนโปรแกรมแอสเซมบลีมี ความเชื่อมโยงกับฮาร์ดแวร์ มากกว่าภาษาระดับสูง ดังนั้น CPU ตัวแรกที่ได้สัมผัสจึงมีผลอย่างมากต่อความยากง่ายในการเรียน
- แอสเซมบลี 6502 ไม่ใช่สภาพแวดล้อมที่สะดวกสบายสำหรับการพัฒนาแอปพลิเคชันใช้งานจริงในปัจจุบัน
- ถ้าไม่ได้สนใจการเขียนโปรแกรมแนวเรโทรเป็นพิเศษ ก็ไม่จำเป็นต้องอยู่กับ 6502 นานนัก
- จุดแข็งในฐานะแพลตฟอร์มเริ่มต้นคือ ความเรียบง่าย และ ความมีตัวตนจริง
- ด้วยโครงสร้างที่ง่าย จึงเรียนรู้แนวคิดพื้นฐานได้รวดเร็ว
- มีทั้งเครื่องจริง อีมูเลเตอร์ หนังสือ และแหล่งข้อมูลออนไลน์จำนวนมาก ทำให้วางเส้นทางการเรียนได้ง่าย
-
รีจิสเตอร์และคำสั่งมีขนาดเล็กพอเหมาะ
- 6502 มีรีจิสเตอร์เพียง 6 ตัว
- แอคคูมูเลเตอร์ 1 ตัว
- อินเด็กซ์รีจิสเตอร์ 2 ตัว
- สถานะรีจิสเตอร์
- สแต็กรีจิสเตอร์
- โปรแกรมเคาน์เตอร์
- รีจิสเตอร์ 16 บิตเพียงตัวเดียวใน 6502 คือ โปรแกรมเคาน์เตอร์
- จำนวนรีจิสเตอร์ที่น้อยอาจเป็นข้อจำกัดเมื่อเขียนแอปพลิเคชันจริง แต่ช่วยให้เข้าใจบทบาทและการทำงานของรีจิสเตอร์ได้ดี
- ชุดคำสั่งดั้งเดิมของ 6502 มีเพียง 56 คำสั่ง
- แม้ชุดคำสั่งจะเล็ก แต่ก็เพียงพอให้เรียนรู้ประเภทคำสั่งสำคัญได้
- โหลด/จัดเก็บ
- การดำเนินการเชิงตรรกะ
- การคำนวณทางเลขคณิต
- การแตกแขนง
- คำสั่งประเภทเหล่านี้ยังคงมีอยู่ใน CPU สมัยใหม่ไม่ทางใดก็ทางหนึ่ง
- x86-x64 แค่จะนับจำนวนรีจิสเตอร์และคำสั่งก็ไม่ง่ายแล้ว ส่วนชุดคำสั่ง RISC สมัยใหม่อย่าง ARM ก็ยากจะเรียกว่าเล็กและเรียบง่าย
- 6502 มีรีจิสเตอร์เพียง 6 ตัว
ระบบนิเวศจริงและทางเลือกอื่น
-
ระบบนิเวศที่เก่าแต่ยังมีชีวิต
- 6502 ถูกนำเสนอในช่วงกลางทศวรรษ 1970 โดย MOS Technology ในฐานะเวอร์ชันที่ถูกกว่าและเรียบง่ายกว่าของ Motorola 6800
- ทีมเดียวกันนี้เคยพัฒนา Motorola 6800 มาก่อน
- หลังจากนั้นก็ได้รับความนิยมอย่างรวดเร็วและถูกใช้ในไมโครคอมพิวเตอร์ชื่อดังหลายรุ่น
- Apple II
- Commodore VIC 20
- Commodore 64
- BBC micro
- หา อีมูเลเตอร์ ของเครื่องเหล่านี้ได้ไม่ยาก และบางส่วนก็มีฮาร์ดแวร์จำลองสมัยใหม่ด้วย
- ผลิตภัณฑ์สืบทอดของ 6502 ยังมีการผลิตอยู่ในช่วงเวลาที่บทความนี้เขียน และอุปกรณ์ใหม่อย่าง Neo6502 ของ Olimex ก็ยังรันสายตระกูล 6502 ได้
- แหล่งเรียนรู้ฟรีมีอยู่มากบนอินเทอร์เน็ต และจำนวนไม่น้อยหาได้จาก 6502.org
- 6502 ถูกนำเสนอในช่วงกลางทศวรรษ 1970 โดย MOS Technology ในฐานะเวอร์ชันที่ถูกกว่าและเรียบง่ายกว่าของ Motorola 6800
-
สื่อการเรียนที่ลงมือทำได้ทันที
- Easy 6502 เป็นหนังสืออิเล็กทรอนิกส์ของ Nick Morgan ที่เหมาะกับผู้เรียนซึ่งอยากลองสัมผัส 6502 แบบสั้น ๆ
- ไม่ได้มีแค่ข้อความและภาพ แต่ยังรวมแอสเซมเบลอร์และซิมูเลเตอร์ 6502 ที่เขียนด้วย JavaScript ไว้ด้วย
- สามารถเขียนโค้ดแอสเซมบลี 6502 แบบง่าย ๆ ได้ทันทีบนหน้าเว็บ
- Visual6502.org ไม่ได้เป็นเครื่องมือเรียนแอสเซมบลีโดยตรงเท่าไรนัก แต่ใกล้เคียงกับการเป็นสื่อที่ แสดงให้เห็นความเรียบง่ายของ 6502 ในเชิงภาพ มากกว่า
-
ความต่างจากตัวเลือกเริ่มต้นอื่น
- CPU เสมือน ที่สร้างขึ้นเพื่อการศึกษาอาจมีชุดคำสั่งที่สะอาดและ “สมบูรณ์แบบ” แต่ยากจะมีทั้งสื่อการเรียนและชุมชนที่อุดมสมบูรณ์เท่า 6502
- CPU ยุคเรโทรอย่าง Z80, 6809 และ 68000 ก็เป็นตัวเลือกที่ดีเช่นกัน
- ทั้งสามตัวถูกมองว่าเหมาะกับการเขียนโปรแกรมจริงจังมากกว่า 6502
- แต่ในแง่การเรียนรู้แนวคิดพื้นฐาน ความเรียบง่ายของ 6502 ได้เปรียบกว่า
- Z80 มีรีจิสเตอร์มากกว่า 6502 อย่างมาก และยังมี ชุดรีจิสเตอร์สำรอง จึงเริ่มต้นได้ยากกว่า
- สถาปัตยกรรม RISC สมัยใหม่อย่าง ARM, MIPS และ RISC-V เป็นสิ่งที่โปรแกรมเมอร์แอสเซมบลีที่จริงจังควรเรียนในสักช่วงหนึ่ง
- เพียงแต่ไม่ได้เหมาะเป็นตัวเลือกเริ่มต้นนัก
- ความเรียบง่ายของพวกมันใกล้เคียงกับแง่มุมการออกแบบภายในชิปมากกว่าระดับชุดคำสั่ง
- ไมโครโปรเซสเซอร์สมัยใหม่ส่วนใหญ่ถูกโปรแกรมด้วยภาษาระดับสูง และประสบการณ์ของการเขียนคำสั่งแอสเซมบลีโดยตรงก็ไม่ได้เป็นลำดับความสำคัญสูงในการออกแบบ CPU
- หากต้องการโหลดค่าคงที่ 64 บิตลงรีจิสเตอร์บน ARM64 อาจต้องใช้ ถึง 4 คำสั่งรวมการเลื่อนบิต
- เมื่อเทียบกันแล้ว กระบวนการโหลดค่าคงที่ลงรีจิสเตอร์บน 6502 นั้นเรียบง่ายกว่า
- x86-x64 อาจถือเป็นชุดคำสั่งที่ได้รับความนิยมมากที่สุดบนเดสก์ท็อปและเซิร์ฟเวอร์สมัยใหม่ โดยมี ARM กำลังไล่ตาม
- มันไม่ติดข้อจำกัดขนาด 32 บิต และมีชุดคำสั่งที่หลากหลายพร้อมจำนวนโอเปอแรนด์ที่ยืดหยุ่น จึงมีบางแง่มุมที่เขียนโค้ดง่ายกว่า ARM
- แต่สำหรับผู้เริ่มต้นก็ยังซับซ้อนมากอยู่ดี และประวัติศาสตร์กว่า 40 ปีก็ไม่ได้ทำให้ x86-x64 เรียบง่ายขึ้น
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ยากที่จะเห็นด้วยว่าความเรียบง่ายของ 6502 ดีกว่า 68000
68000 มีรีจิสเตอร์มากกว่าและความกว้างของชนิดข้อมูลกว้างกว่า แต่โครงสร้างสม่ำเสมอ จริง ๆ แล้วเป็นรูปแบบที่รีจิสเตอร์สองชนิดคือ A และ D ถูกทำซ้ำเป็น D0~D7, A0~A7 ดังนั้นสิ่งที่ทำได้กับ D0 ก็ทำกับ D3 ได้เช่นกัน ความเรียบง่ายของโครงสร้างต้องสมดุลกับ ความเรียบง่ายในการเขียนโปรแกรม และพอเขียนโปรแกรมที่ซับซ้อนขึ้นนิดเดียว 6502 ก็จะชนข้อจำกัดอยู่เรื่อย ๆ
วิธีที่ดีที่สุดในการเรียนรู้การเลี่ยงข้อจำกัดของเครื่องขนาดเล็ก กลับเป็นการมองข้ามข้อจำกัดเหล่านั้นแล้วกลายเป็น วิศวกรซอฟต์แวร์ที่ชำนาญ มากกว่า ถ้าเป็นมือใหม่ ควรเริ่มจากฝั่งที่มีโหมดการอ้างแอดเดรสมากกว่า จัดการอาร์เรย์ขนาดใหญ่ได้ง่ายกว่า และมีรีจิสเตอร์กับความกว้างของจำนวนเต็มเหลือเฟือจะดีกว่า
มีการอ้างว่า 6502 เรียบง่ายเพราะมีรีจิสเตอร์ 6 ตัว แต่ถ้าได้จับ 6502 แค่สัปดาห์เดียวก็จะรู้ว่าโดยแท้จริงแล้วกำลังใช้งาน รีจิสเตอร์สามตัว อยู่ นั่นจึงเป็นที่มาของฉายา CPU เซมาฟอร์
6502 สนุกและสะอาดตา แต่ถ้าต้องการแนวทางแบบสมัยใหม่ก็ไม่เหมาะ หากอยากเดินตามเส้นทางรุ่งโรจน์แบบยุค 90 ก็ควรเริ่มจาก MIPS หรือไม่ก็เริ่มด้วย Neon ไปเลย แม้แต่ Z80 หากมองเรื่องรีจิสเตอร์และความซับซ้อน ก็ยังมีแง่ที่ใกล้เคียงกับสิ่งที่พบในปัจจุบันมากกว่า
Assembly สมัยใหม่เองไม่ได้ซับซ้อนโดยเนื้อแท้ เริ่มจาก FASM ก็ไม่ได้ยาก แต่การเข้าใกล้ระดับล่างมักซับซ้อนขึ้นอย่างรวดเร็วเสมอ แล้วก็จะเริ่มสร้างมาโคร และสุดท้ายก็จะวางอะไรสักอย่างที่คล้าย C เวอร์ชันยากจนของตัวเองทับลงไป
ข้อดีของระบบขนาดเล็กคือสามารถเข้าใจทั้งหมดได้อย่างสมบูรณ์ ตั้งแต่ซิลิคอนไปจนถึงระบบปฏิบัติการและซอฟต์แวร์
6809 เรียบง่ายกว่า 68K และทรงพลังกว่า 6502 อีกทั้งมี orthogonality ดี แต่ไม่มีฐานซอฟต์แวร์ในระดับเดียวกัน ผมมองว่า Motorola จับทิศทางได้ค่อนข้างดีในชุดคำสั่งและสถาปัตยกรรมจากมุมมองโปรแกรมเมอร์ของ 6809 และ 68K เท่าที่จำได้ PDP-11/VAX และ NS32K ก็มีลักษณะค่อนข้าง orthogonal คล้ายกัน
หากคิดถึงแพลตฟอร์มที่สมัยใหม่กว่า การสอน RISC-V มีน้ำหนักโน้มน้าวมากกว่า MC68k RISC-V เมื่อดูเฉพาะชุดคำสั่งจำนวนเต็มพื้นฐานแล้วเรียบง่ายและงดงามมาก ขณะเดียวกันก็คล้ายกับสถาปัตยกรรมสมัยใหม่อย่าง ARM, Aarch-64, MIPS มีทั้ง 32 บิตและ 64 บิต และเอกสารทางการก็เข้าถึงง่าย
MC68k มีลักษณะเฉพาะที่ไม่ค่อยเกี่ยวข้องกับปัจจุบันมากเกินไป ข้อดีก็คงมีเพียงถูกใช้ในแพลตฟอร์มฮาร์ดแวร์หลายตัว และยังมีชุมชนเรโทรที่คึกคักอยู่ แต่เรื่องนั้นใกล้เคียงกับปัจจัยด้านความน่าสนใจมากกว่า ไม่ใช่ความเกี่ยวข้องจริงในทางปฏิบัติ
68020 แทบจะเป็นจุดสูงสุดที่สถาปัตยกรรมชุดคำสั่งสามารถเข้าใกล้ C ได้ และให้ประสบการณ์ใช้งานดีมาก
อย่างไรก็ตาม การใช้ 65XX ในคอมพิวเตอร์ Commodore ยุคแรก ๆ ให้ความรู้สึกคุ้มค่ามาก เพราะไม่มีการป้องกันหน่วยความจำ จึงแก้หน่วยความจำวิดีโอโดยตรงได้ แตะต้องสไปรต์·ฟอนต์·ขอบจอ·อินเทอร์รัปต์ได้ และยังเขียน self-modifying code ได้ด้วย ส่วน Assembly ของ 68000 บน Amiga เป็นสภาพแวดล้อมที่ปลอดภัยกว่าและถูกควบคุมมากกว่า
ในฐานะชุดคำสั่งชุดแรกสำหรับเรียนแอสเซมบลี มองว่า 6502 ไม่เหมาะ ต้องใช้เวลามากไปกับการรับมือจุดประหลาดของสถาปัตยกรรมที่ฉลาดแต่มีข้อบกพร่องลึก ๆ
idiom แบบเลี่ยงปัญหาเหล่านั้นไม่ค่อยถ่ายทอดไปยังสถาปัตยกรรมที่ดีกว่า ซึ่งไม่ได้ถูกผูกมัดด้วยข้อจำกัดด้านเครื่องมือและงบประมาณของ MOS ในยุคนั้น
ถ้าอยากเรียนชุดคำสั่งที่เล็กแต่ทรงพลังและมีจุดประหลาดอยู่บ้าง ARM v6M ดีกว่า ทุกวันนี้ยังมีการผลิตอย่างมีนัยสำคัญ และ toolchain โอเพนซอร์สสมัยใหม่ก็รองรับดีทั้งดีบักเกอร์ คอมไพเลอร์ แอสเซมเบลอร์ และลิงเกอร์
ถ้าให้ความสำคัญกับความเปิดของสถาปัตยกรรม และรับแพลตฟอร์มที่ยังสุกงอมน้อยกว่าได้ ก็เลือก RISC-V MCU ถ้าตัดสินใจไม่ได้ก็เลือก RP2350
ชุดคำสั่ง ARMv6M มีขนาดเล็ก และการโหลดค่าคงที่ก็ไม่ต้องใช้ลำดับคำสั่งยาว ๆ น่าเบื่อ หากใช้การโหลดแบบสัมพันธ์กับ PC ตามเอกสาร ไม่ต้องใช้โค้ดที่แก้ไขตัวเองหรือใช้ zero page เพื่อทำดัชนีหน่วยความจำ และความกว้างของรีจิสเตอร์ก็เท่ากับพื้นที่แอดเดรส ด้วยความเป็น 32 บิต จึงกลับเรียนและสอนได้ง่ายกว่าชุดคำสั่ง 8/16 บิตส่วนใหญ่ด้วยซ้ำ ถ้าฟังดูน่าเบื่อก็ไม่ต้องกังวล ใน ARMv6 ก็มีจุดประหลาดพอให้ทำ code golf ได้อยู่แล้ว
เริ่มจาก PIC16 assembly และเคยแตะหลายสถาปัตยกรรมมาบ้าง แต่ถ้าวัดความเรียบร้อยแล้ว MIPS32 ถูกใจที่สุด
ขอเสริมเล็กน้อยว่า ตอนนี้ยังซื้อ 6502 รุ่นใหม่จาก Western Design Center, MCU ที่มีคอร์ 6502 และชิปพ่วงต่าง ๆ ได้อยู่ มีขายตามที่อย่าง Mouser ด้วย
https://www.mouser.com/c/?m=Western%20Design%20Center%20%28W...
แค่คูณเลข 16 บิตสองตัวก็ต้องใช้โค้ดเป็นก้อนแล้ว ดูไม่ค่อยมีประโยชน์ที่โปรแกรมเมอร์ใหม่จะต้องมาปลุกปล้ำกับเรื่องแบบนี้
อย่างที่ว่า ชุดคำสั่ง ARM ยุคแรกเป็นตัวเลือกที่ดี
แน่นอนว่านี่เป็นปัญหาที่พบได้ในภาษาแอสเซมบลีหลายแบบ แต่ตอนเริ่มต้นอยากให้เริ่มจากชุดคำสั่งที่ไม่มีปัญหาแบบนี้
[1] https://youtube.com/playlist?list=PLowKtXNTBypFbtuVMUVXNR0z1...
ในฐานะคนที่สอนแอสเซมบลีให้นักศึกษาปริญญาตรีมาหลายปี ขอบอกว่าเห็นด้วยว่า 6502 ดีสำหรับมือใหม่ แต่เหตุผลไม่ได้อยู่ที่ข้อดีของภาษา 6502 เองเท่านั้น
เคยสอน 68K, MIPS, ARM, x86 ฯลฯ และเหตุผลใหญ่ที่สุดที่นักศึกษาตอบรับดีเมื่อสอน 6502 คือบริบทรอบ ๆ CPU เราใช้ 6502 เขียนโปรแกรมให้เครื่องจริงที่เข้าใจง่าย นั่นคือ Nintendo Entertainment System
I/O แบบ memory-mapped พื้นฐาน ไม่มีระบบปฏิบัติการ ไม่มีคำสั่งแบบ pipeline ไม่มี delay slot ไม่มีเครือข่าย ไม่มีเสียงรบกวนที่ไม่จำเป็น ใกล้เคียงกับกล่องเรียบง่ายที่ข้างในมี clock, CPU, แอดเดรสหน่วยความจำไม่กี่ตำแหน่ง, ชิปช่วย และ I/O ที่แมปเข้ากับแอดเดรสหน่วยความจำ 6502 อาจไม่ใช่ชุดคำสั่งที่เรียบง่ายที่สุด แต่ ความเรียบง่ายของระบบนี้ ช่วยได้มาก
ข้อจำกัดของ 6502 ก็สำคัญต่อการช่วยให้นักศึกษาเข้าใจว่าทำไมคำสั่งถึงมีรูปร่างแบบนั้น CPU ถูกออกแบบและเดินสายภายใต้ข้อจำกัดของยุคนั้น และสิ่งนั้นก็สะท้อนอยู่ในวิธีเขียนโปรแกรม
การเลือก 6502 และ NES สำหรับการสอนมือใหม่ประสบความสำเร็จ ไม่ใช่เพราะเป็น 6502 แต่เพราะ 6502 บังคับให้ระบบที่ใช้ย้ายบิตนั้นเรียบง่าย
หลังจากนักศึกษาได้จับ 6502 และเห็น tile ของ NES เคลื่อนบนหน้าจอแล้ว ก็ขยายไปสู่การดูว่า 68000 จัดการต่างออกไปอย่างไร, MIPS เกิดขึ้นมาอย่างไร, ใช้ pipelining และ delay slot อย่างไร, และเปรียบเทียบความต่างระหว่าง RISC กับ CISC ได้อย่างเป็นธรรมชาติ เมื่อมีพื้นฐานแล้ว การต่อยอดจะง่ายมาก
ถ้าไม่ได้จะเรียนชุดคำสั่งที่ใช้งานอยู่ในปัจจุบัน ก็แปลกใจเล็กน้อยที่ PDP-11 assembler แทบไม่ถูกพูดถึงในฐานะจุดเริ่มต้นที่ดี
อาจเป็นเพราะสิ่งแรกที่ได้เรียนจริงจังคือ PDP-11 ก็ได้ แต่ไมโครโปรเซสเซอร์ยุคแรก ๆ ทั้งหมดรู้สึกเหมือนถอยหลังไปหนึ่งก้าว เคยใช้ Z80 assembly อยู่หลายปี แต่ตอนนี้ไม่แนะนำ มันไม่ใช่ชุดคำสั่งแบบ orthogonal และ 6502 มีรีจิสเตอร์น้อยเกินไป จนให้ความรู้สึกของการเขียนแอสเซมบลีได้ไม่เต็มที่
ถ้าชอบ PDP-11 ใน MSP430 จะได้ข้อดีคล้าย ๆ กันในรูปแบบที่จำกัดลงเล็กน้อย และใน 68000 จะได้ในรูปแบบที่เสริมขึ้นเล็กน้อย
แต่จริง ๆ แล้วควรลืมวัตถุโบราณพวกนั้นแล้วเรียน RISC-V ดีที่สุด ไม่ก็เลือกหนึ่งใน Arm หลาย ๆ แบบ ส่วนตัวแล้วรู้สึกผูกพันทางอารมณ์กับ ARM7TDMI ที่เคยแตะเยอะในช่วงกลางทศวรรษ 2000 โหมด Thumb อาจเรียนง่ายกว่าโหมด Arm เดิมเล็กน้อย แต่ทั้งคู่ก็ยังไม่น่าพอใจเท่า RISC-V
อาจเถียงได้ว่า addressing mode ซับซ้อนกว่า RISC ในเชิงแนวคิด แต่ในทางปฏิบัติ addressing mode ของ 6502 มีโอกาสเข้าใจยากกว่า PDP-11
แต่ DEC กลับเมินโอกาสนั้น และ IBM ก็เข้ามายึดตำแหน่งนั้นด้วยชุดคำสั่ง 8086 ที่เทอะทะ
ตอนนี้ไม่มีเหตุผลให้เรียน -11 อีกแล้ว
ไม่ค่อยเข้าใจว่าทำไมถึงสรุปแบบนั้นได้ ตอนนักเรียนเริ่มสัมผัสการเขียนโปรแกรมคอมพิวเตอร์ครั้งแรก การเริ่มจากภาษาของเล่น/ภาษาขนาดเล็กที่ไม่มีการใช้งานจริงก็อาจสมเหตุสมผลได้ แต่ Assembly ไม่ควรเป็นภาษาแรกที่เรียน
Assembly เป็นเครื่องมือที่ใช้งานได้จริงมาก และโดยทั่วไปมักใช้กับการดีบักและวิศวกรรมย้อนกลับ แล้วทำไมต้องเสียเวลากับ Assembly ของแพลตฟอร์มที่หายไปนานแล้วด้วย
วิธีที่ดีที่สุดในการเรียน Assembly คือการทดลอง เขียนโค้ดด้วยภาษาที่ชอบแล้วดูเอาต์พุต Assembly ระหว่างทาง หรือใช้ objdump หรือ gdb ส่องดูข้างในก็ได้ ลองแก้แล้วดูว่าเกิดอะไรขึ้นก็ได้
จะใช้เอมูเลเตอร์ของคอมพิวเตอร์เก่าก็ได้ แต่ยากกว่า แค่จะพิมพ์ข้อความหนึ่งบรรทัดบนหน้าจอ ก็ต้องเรียนรู้สถาปัตยกรรม ฮาร์ดแวร์ และฟังก์ชัน ROM ของคอมพิวเตอร์เครื่องนั้นแล้ว และความรู้นี้แทบเอาไปใช้กับ Linux หรือ Windows บน x86-64 ไม่ได้เลย
สำหรับมือใหม่จริง ๆ แนวคิดอย่าง pointer นั้นนามธรรมและเข้าใจยากเกินไป แต่พอเรียน indirect addressing ใน Assembly ก็เข้าใจขึ้นมาทันทีว่าทำไม C ถึงมี pointer และมันทำงานอย่างไร
ก่อนหน้านั้นผมใช้ Python เป็นหลัก ซึ่งถูกทำให้เป็นนามธรรมมากกว่ามาก คนมักลืมว่าฟีเจอร์อย่าง pointer มีอยู่เพราะข้อจำกัดด้านฮาร์ดแวร์และประสิทธิภาพ ถ้าไม่รู้ว่าภายใน CPU ทำอะไรจริง ๆ และทำไปทำไม ความเข้าใจเชิงสัญชาตญาณก็จะถูกจำกัด
ตั้งแต่จบมัธยมปลายมาก็ไม่ได้เขียน Assembly สักบรรทัด แต่ความเข้าใจพื้นฐานว่า operation ถูก execute อย่างไร และ register ทำงานอย่างไร ทำให้เข้าใจเหตุผล เงื่อนไข และข้อยกเว้นของการเขียนโปรแกรมกับการ optimize ได้ง่ายขึ้นมาก และยังเห็นคุณค่าของโค้ดที่สะอาดและมีประสิทธิภาพมากขึ้นด้วย
ถ้าอยากลองชิมบรรยากาศอดีตสักหน่อย ก็อยู่ที่นี่
https://www.atariarchives.org/
เพราะเรียนอิเล็กทรอนิกส์มา จึงเริ่มจาก Assembly (Motorola HC11) โดยธรรมชาติ พอใกล้จบคอร์ส ทุกคนก็สร้าง macro สำหรับสิ่งอย่าง for loop ได้เองโดยอิสระ และจากจุดนั้นก็ขยับไป C ได้อย่างเป็นธรรมชาติ พอจบคอร์ส C การทำ object-oriented แบบสไตล์ C ก็ปรากฏขึ้นเองตามธรรมชาติ และต่อไปยังคอร์ส C++ ถัดไป
ข้อเสียของแนวทางนี้คือไม่มีเส้นทางแบบค่อยเป็นค่อยไปไปสู่ functional paradigm หรือ paradigm ที่ไม่ใช่ imperative โดยทั่วไป อีกอย่างคือจะติดนิสัยคิดอยู่ตลอดว่าภาษาทำงานภายในอย่างไร ซึ่งบางครั้งก็ให้ผลเสียได้ ตอนพยายามเรียน Haskell สมองก็ยังเริ่มจากอยากเข้าใจก่อนว่า interpreter ทำงานอย่างไร
การเรียน Assembly ไม่ได้เป็นแค่การเรียนภาษา แต่เป็นการเข้าใจว่าเครื่องทำงานอย่างไร ทั้ง bus, memory-mapped peripherals และอื่น ๆ บนแพลตฟอร์มเก่า ๆ ส่วนนี้เรียบง่ายกว่ามาก ดังนั้นแม้คำสั่ง ARM จะเรียนง่ายกว่าคำสั่ง CISC ของ HC11 แต่ส่วนอื่นทั้งหมดนั้น HC11 เป็นมิตรกับมือใหม่มากกว่า
-vasmจะแสดง Assembly ที่สร้างขึ้นระหว่างการคอมไพล์ เคยถูกมองว่าไม่ค่อยมีประโยชน์ เพราะใช้ objdump หรือ-Sก็ได้ไม่ใช่หรือ แต่ถ้าได้ลองใช้จริงจะรู้ว่าทำไมมันสะดวก เพราะมัน พิมพ์ Assembly ออกมาทันที โดยไม่มี boilerplate จำนวนมหาศาลสำหรับสร้าง object fileตัวอย่างเช่น กำลังทำงานกับ code generator ของ AArch64 หรือให้เจาะจงกว่านั้นคือการสร้างโค้ด floating-point และมีฟังก์ชันแบบนี้
float test(float a, float b) { return a * b; }ถ้าคอมไพล์ด้วย
dmd -c test.c -arm -vasmจะได้เอาต์พุตเป็นที่อยู่ คำสั่งฐานสิบหก mnemonic ของคำสั่ง และ URL สเปกของคำสั่งรู้ว่าโค้ดยังไม่ถูกต้องทั้งหมด บอกแล้วว่ายังทำอยู่ :-)
สำหรับผม ชุดคำสั่ง 6502 เป็นภาษา Assembly ภาษาแรกที่ดี
ปี 1977 ผมอาศัยอยู่ในกระท่อมเล็ก ๆ ใน Oregon และซื้อ Apple II มาเล่นแก้เบื่อ ภายในหนึ่งปีผมก็ได้ทำโปรแกรมที่ภายหลังกลายเป็น Apple Writer และเขียนทั้งหมดด้วย Assembly
https://en.wikipedia.org/wiki/Apple_Writer
ที่นี่บอกว่า Assembly ของ 6502 ค่อนข้างดิบและเขียนยาก พอมองย้อนกลับไปก็เห็นด้วย แต่ในปี 1977 ไม่มีมาตรฐานอะไรให้เทียบ
เพราะ Apple II ไม่มีภาษาระดับสูงที่เร็ว โปรแกรมเล็ก ๆ ของผมเลยกลายเป็นผลิตภัณฑ์ของ Apple ได้เพราะไม่มีทางเลือกอื่น
ลองคิดดูแล้ว Apple Writer ใส่อยู่ใน RAM 8KB แต่ก็ทำงานได้จริง ถึงขั้นมีภาษา macro ที่คนใช้จัดการรายชื่อที่อยู่ด้วย
ช่วงหลังผมอัปเกรดระบบหลักเป็น RAM 96GB เพื่อให้รัน DeepSeek แบบโลคัลได้ง่ายขึ้น และยังมี RTX 4090 ด้วย อยู่ ๆ ก็รู้ตัวว่า RAM เท่านี้สามารถใส่ Apple Writer ได้เกือบ 12 ล้านชุด
ค่อนข้างเหนือจริง แต่ตั้งแต่ปี 1977 มาก็มีหลายครั้งที่ได้พูดอะไรทำนองนี้
ถ้าเป็นภาษา Assembly สำหรับเริ่มต้น ผมชอบ RISC-V มากกว่า เพราะออกแบบมาดีและเข้าใจได้ง่ายกว่า มีการรองรับภาษาและเครื่องมือสมัยใหม่อย่าง GCC, LLVM, Rust และรันได้ทั้งบน QEMU กับฮาร์ดแวร์ที่ซื้อได้จริง
ถึงขั้นทำงานได้ที่ 14MHz ด้วย
ประเด็นเรื่องความเรียบง่ายของชุดคำสั่ง 6502 เป็นจุดที่ส่วนตัวแล้วรู้สึกขัดใจ คนที่คิดว่าความเรียบง่ายแบบนั้นดี ดูเหมือนจะไม่เคยก้าวต่อไปหลังจาก Hello World
การเขียนโปรแกรมอะไรที่ซับซ้อนระดับกลางบน 6502 นั้นยาก 8 บิตมีข้อจำกัดมากเกินไป เช่น แค่การกำหนดแอดเดรสหน้าจอของ Commodore 64 ก็เห็นได้แล้ว การคูณและการหารต้องลงมือทำเอง ส่วนการบวก/ลบแบบ 16 บิตแม้จะเรียบง่าย แต่ถ้าจะทำให้มีประสิทธิภาพก็ไม่ใช่เรื่องเล็กน้อยเลย
ถ้าเป้าหมายคือการเรียนแอสเซมบลีพื้นฐาน แพลตฟอร์ม 8086+DOS เมื่อเทียบกันแล้วจัดการได้ง่ายกว่ามาก
การย้ายอัลกอริทึมการคูณ·การหารหลายแบบมาเขียนเป็นแอสเซมบลี เป็นวิธีเรียนที่ดีมาก
ในเมื่อสุดท้ายก็จะเรียนสิ่งที่ไม่เกี่ยวกับปัจจุบันซึ่งไม่ใช่ x86-64, RISC-V หรือ ARM อยู่แล้ว ผมก็ไม่ค่อยเห็นว่าข้อดีของ 8086 คืออะไร
ผมชอบทุกช่วงเวลา และ segment register ก็ไม่ได้กวนใจเท่าไร
ผมเรียนอยู่ที่โรงเรียนเทคนิคสายวิทยาการคอมพิวเตอร์ และอาจารย์สารสนเทศคนหนึ่งที่ชอบของเรโทรและชอบอวดเครื่องอาร์เคดของตัวเอง ได้โฟกัสที่ 6502 แทนแผนการสอนที่กำหนดไว้คือแอสเซมบลี 8808
พูดตรง ๆ นั่นเป็นหนึ่งในประสบการณ์การเรียนรู้ที่ดีที่สุดในชีวิต และผมไม่คิดว่าอยากให้เป็นแบบอื่นเลย โดยเฉพาะยังให้ทำคอมพิวเตอร์ breadboard ของ Ben Eater ด้วย ทำให้ได้ความรู้สึกลงมือจับต้องเองอย่างมาก และน่าสนใจจริง ๆ
ครั้งแรกที่ได้สัมผัสภาษาแอสเซมบลีคือ PDP-10 และสิ่งที่มีอยู่ก็มีแค่คู่มือโปรเซสเซอร์ DEC-10
ตอนนั้นสับสนไปหมด มีคำสั่งหลายร้อยคำสั่ง และคำอธิบายก็คลุมเครือ ไม่รู้เลยว่า register คืออะไร accumulator คืออะไร address คืออะไร stack คืออะไร David Rolfe ช่วยเขียนซับรูทีนบางตัวที่จำเป็นสำหรับ Empire เวอร์ชัน Fortran ของผมให้ ก็ช่วยได้นิดหน่อย แต่ก็ยังหลงทางอยู่ดี
วันหนึ่งผมถามเพื่อนชื่อ Shal Farley ว่า stack คืออะไร เขาตอบว่า “ลองนึกถึงกองจานสิ วางจานหนึ่งใบลงไป (push) แล้วหยิบออกมาหนึ่งใบ (pop)” ตอนนั้นเหมือนไฟสว่างขึ้นมา และเข้าใจทันที
หลังจากนั้นผมเริ่มทำงานกับ ไมโครโปรเซสเซอร์ 6800 บนบอร์ดเล็ก ๆ มีคำสั่งประมาณ 40 คำสั่ง และทั้งหมดใส่ได้ในบัตรใบเดียว คำสั่ง 40 คำสั่งนั้นเรียนง่าย แล้วจู่ ๆ ทุกอย่างก็เข้าใจขึ้นมา
พอกลับไปอ่านคู่มือ -10 อีกครั้ง เนื้อหาทุกอย่างก็เริ่มสมเหตุสมผล