목차
도입 및 시연
하드웨어 구성 요소 및 사양
CPU의 내부 작동 원리
명령어 사이클과 파이프라인
하드웨어 제약과 클럭 속도
레지스터와 RAM의 구현과 최적화
소프트웨어 및 어셈블러 작동 방식
프로그램 시연:피보나치 수열
파일 시스템과 FactOS
깃헙 레포지토리
{주변 기기 상세
{Q&A
{번역 후기
주변 기기 상세
이제 CPU가 정상적으로 작동하는 것을 확인했으니, 팩토리오로 들어가서 CPU 자체에 대해 더 많은 것들을 확인해 봅시다.
몇 가지 예제를 살펴보겠습니다. 우리는 아까 이미 LS 명령*을 사용할 수 있다는 것을 보았습니다.
한 가지 중요한 점은 현재 작업 디렉토리(Current working directory)라는 개념이 없다는 것입니다. 그래서 예를 들어 루트 디렉토리 안에 무엇이 있는지 확인하고 싶다면 이 슬래시(/)를 추가하여 디렉토리가 무엇인지 말해줘야 합니다. 그러면 CHARS라는 파일 하나와 binary 디렉토리(DIR BIN), 데이터 디렉토리(DIR DATA)가 있는 것을 볼 수 있습니다. binary 디렉토리 아래에는 여러분이 보셨다시피 몇 가지 예제 프로그램들이 있고, 이를 살펴볼 수 있습니다.
프로그램을 실행하고 싶다면, 예를 들어 이 ALLCHARS 프로그램을 실행하기 위해 RUN을 쓰고 절대 경로를 입력해야 합니다.
이 과정이 조금 번거롭습니다. 제가 실수를 하기도 했고, 키보드가 그다지 좋지 않기 때문이기도 합니다. 하지만 팩토리오에서 이 정도면 최선이죠. 그리고 상대 경로가 없기 때문이기도 합니다. 네, 개선될 여지가 있는 부분이죠.
*리눅스에서 ls는 list의 줄임말로, 현재 위치나 특정 경로에 있는 디렉토리의 내용물을 리스트로 출력하는 명령어다.
하지만 지금 이것이 하는 일은 파일 시스템에서 프로그램을 로드하는 것입니다. 프로그램이 어딘가에 있다면, RAM에 로드한 다음 실행합니다.
이 프로그램이 하는 일은 기본적으로 모든 허용된 ASCII 심볼들을 출력하는 것입니다. ASCII 코드에 있는 기호들을 모두 볼 수 있고 그걸로 뭐라도 할 수 있겠죠, 잘 모르겠네요.
그리고 이 폰트는 기본적으로 제가 만든 겁니다. 여기 있는 모든 작은 기호들은 5x7 픽셀로 된 격자이며 모든 문자가 어떻게 보여야 하는지 정의하고 그것들을 일정 신호 조합기 내부에 넣었습니다. 어딘가에 있었던 것 같은데... 이건 아니고... 이것도 아니고... 아마 이거일 겁니다. 네.
기본적으로 이 숫자들은 이 5x7 신호가 어떻게 작동해야 하는지에 대한 코드일 뿐입니다. 그리고 5x7은 35입니다. 따라서 32비트 숫자는 당연히 그만큼의 정보를 담을 수 없는데, 모든 픽셀에 대해 켜져 있는지 꺼져 있는지에 대한 이진수 정보가 있어야 합니다. 램프가 켜져야 하는지 꺼져야 하는지를 나타내는 이진수요. 정보를 모두 넣기 위해 기본적으로 두 개의 숫자가 필요합니다. 그래서 여기 두 개의 조합기(사진 중간 MN 윗부분)가 있는 것이고 여기 있는 것들은 파이썬 코드를 사용해서 생성된 겁니다.
제가 직접 손으로 작성한 건 아니에요. 그랬으면 엄청 괴로웠을 거에요.
여기를 보시면 이것이 디스플레이 컨트롤러입니다. 커서 위치가 있고 거기에 ASCII 심볼을 쓸 수 있으며 그러면 그 위치의 화면에 글자가 기록됩니다. 여기 이 애니메이션은 그냥 꽉 찬 블록을 쓰고 난 뒤에 꽉찬 블록을 지우는 것입니다. 그래서 타이핑 애니메이션처럼 보이는 것이죠.
그 외에 여기 있는 다른 것들을 봅시다.
키보드 컨트롤러는 여기 있는 모든 버튼들이 이 71, 74와 같은 특정 키 코드를 보내도록 구현되었고 그건 그냥 ASCII 코드입니다. 1은 49고 0은 48이고, 이런 식으로, 아마 ASCII를 많이 사용하시는 분들은 이 숫자들을 알아볼 수 있을 겁니다.
제가 그것을 누르면 이 숫자가 버스를 통해 키보드 컨트롤러로 전송되고 여기 있는 링 버퍼(Ring buffer)에 저장됩니다.
그리고 CPU는 버퍼에 무언가 있는지 물어볼 수 있고 만약 무언가 있다면 특정 설정된 메모리 매핑된 주소로 반환하므로 다음 키를 요청하고 처리할 수 있습니다.
이건 여러분이 키를 연타할 수 있게 해줍니다. 매우 빠르게 칠 수도 있고, 원하신다면 제가 보여드릴 수도 있는데, 예를 들어 게임 속도를 매우 느리게 하면...
정상 속도에서 애니메이션이 얼마나 느린지 보십시오.
제가 O 키를 두 번 누르면 지금은 처리되지 않았지만 이제 첫 번째 O가 처리되고 버퍼에 여전히 무언가 남아 있는지 확인한 다음 두 번째 O를 처리합니다. 모든 키 입력이 링 버퍼에 저장되기 때문에 키 입력이 누락되는 일은 없습니다. 이것은 스네이크 게임에 좋은 점이고 중요합니다. 아래, 왼쪽, 아래, 왼쪽 같이 매우 빠른 상호작용을 할 때나 그냥 타이핑할 때도 갖추면 좋은 기능이라고 생각합니다.
네, 잘 작동하네요.
그게 키보드 컨트롤러였습니다.
다음으로는 난수 생성기(RNG)가 있습니다. 이것은 제가 기억하기로 그냥 피드백 시프트 레지스터(Feedback shift r.egister)입니다. 여기서 찾아보실 수 있고 이 버튼은 시작할 때만 누르는 용도여서 다시 누를 필요가 없습니다.
그리고 이야기하고 싶은 다른 것들 중에 컬러 디스플레이도 있습니다. 기본적으로 RGB 색상이 있고 픽셀 좌표를 준 다음 현재 색상으로 해당 픽셀에 현재 색상을 표시할 수 있습니다. 팩토리오는 16진수, 즉 압축된 정수 코드도 지원하기 때문에 뭐 그것도 사용할 수 있을 거고요. 화면을 지울 수도 있습니다. 컬러 디스플레이의 모든 정보는 이 네 개의 레지스터에 저장됩니다(우하단 ROLER 아래 조합기 16개).
각각은 256개의 픽셀 값, 즉 여기 있는 픽셀 하나의 색상값을 담고 있으며 32x32 디스플레이를 가지고 있고, 이것은 4x256이므로, 그래서 256개의 주소로 이루어진 블록이 네 개 있는 겁니다.
네, 여러분이 직접 가지고 놀고 싶으시다면 마음껏 하시고, 궁금한 점이 있으면 언제든지 알려주세요.
만약 여러분이 멋진 프로그램을 작성해서 실행할 수 있다면, 영상을 만들거나 저를 핑하거나 해 주세요. 누군가 여기서 멋진 것을 만드는 것을 보는 데 매우 관심이 많습니다.
예를 들어 MNIST 숫자 분류기*를 로드하는 것도 멋질 아이디어일 것 같습니다. 일반적인 파이썬 같은 환경에서 신경망을 훈련시킨 다음 가중치들을 CPU 내부로 내보내고, 저는 순방향 전파는 분명히 CPU 내부에서 합리적인 속도로 실행 가능할 것이라고 생각합니다. 그러면 여기에 작은 숫자를 그려서 컴퓨터에게 그것이 어떤 숫자인지 맞춰 보라고 시킬 수도 있겠죠. 분명히 가능할 것 같습니다. 누군가 프로젝트 아이디어를 찾고 있다면 좋은 프로젝트가 될 것 같아요.
*28x28 픽셀 크기의 흑백 손글씨 이미지 7만 개로 구성된 표준 데이터셋. 로지스틱 회귀, 신경망, 컨볼루션 네트워크 등 다양한 모델을 사용해 MNIST를 학습시키는 건 이 분야에서는 print(Hello, World)같은 연습문제 느낌이다.
네, 시청해 주셔서 감사합니다. 여기까지 보셨다면 여러분은 열렬한 시청자시겠군요.
설명란의 링크들을 확인해 주시고, 혹시 아이디어가 있으시면 언제든지 알려주세요.
감사합니다.
안녕히 계세요.
Q&A
https://www.reddit.com/r/factorio/comments/1q5ro90/i_built_a_5_staged_pipelined_cpu_in_factorio_ask/
Q. 와, 미쳤다. 맵 공유 가능함? 인상적인데
A. 당연하지. 어셈블러랑 어셈블리 코드도 있는 메인 레포에 있어.
https://github.com/PhilippDahlinger/byte_factory/blob/master/factoriscoV3_official.zip
Q. 영상 여기 있음: https://www.youtube.com/watch?v=QcQYEAr0Yos
독일어 원본이랑은 다른 버전이고 이건 영어판임
A. 일부러 메인 댓글에 바로 안 올렸음 링크 도배처럼 보일까 봐
내가 했던 독일어 발표의 공식 영어 버전임. 발표 며칠 뒤에 다시 녹화해서 영어권 아닌 사람들도 이해하게 만든 거임
Q. 와 이거 진짜 본인임? 발표 마지막 10분만 봤는데 전체 영상 기대된다
여기서 보게 돼서 반갑고 이 커뮤니티에서 제대로 터졌으면 좋겠다. 아무도 안 물어뜯고, 좋은 의미로만
A. 근데 궁금한데 왜 하필 마지막 10분부터 본 거임?
나는 그냥 진행 상황 보여주고 이걸로 컴퓨터 과학에 흥미 갖는 사람이 생기면 그걸로 만족함.
Q. 알고리즘에 떠서 눌렀는데 다음 일정까지 10분밖에 없었음. 그래서 요약이라도 보려고 끝으로 점프함
Q. 이거 공장겜 아니었냐? 씨발 CPU를 대체 어떻게 만드는데
A. 뭐… 약간 스스로를 학대해야 해야 하긴 함 ㅋㅋ 근데 진지하게 말하면 팩토리오 조합기는 생각보다 훨씬 강력함. 마크랑 비교하면 특히.
대학에서 배운 거를 써먹긴 했고 주로 참고한 건 "Computer Architecture: A Quantitative Approach" 이 책임 (무료로 구할 수 있음)
Q. (다른 사람)팩토리오 위키에 회로 튜토리얼 있음, Ctrl+F 눌러서 memory 검색해봐라. 기본적인 메모리 저장 원리 설명돼 있고 페이지 아래쪽 가면 회로템들 엮어서 좀 더 고급 메모리 셀 만드는 법도 나옴. 거기서부터는 “아 CPU 하나 만들겠네?”까지 한 두 다리만 건너면 됨
A. 그게 레지스터의 기본 블록이고, 나는 한 조합기 안에 여러 신호(256개)를 저장하는 방법을 만들어서 RAM에 쓸 만큼 충분히 큰 저장공간을 확보할 수 있었음. 이 방식 덕분에 좀 복잡한 프로그램도 쓰고 저장할 수 있었던 거고
Q. 팩토리오 유저의 두 부류: 아무것도 모르고 하는 사람들(나)이랑 너 같은 사람들
A. 사실 나 팩토리오 잘하는 편도 아님. 예를 들면 우주시대도 아직 못 깼고 바이터 켠 상태로 본편도 클리어 못함. 그런 의미에서는 나보다 훨씬 잘하는 사람 많음
도움 된 건 마인크래프트 경력임. 레드스톤 서버를 몇 년 한게 가장 컸고 그리고 뭐… 컴공 학위도 조금은 도움이 됐겠지
Q. 그럼 이제 컴파일러 만들어야지, 어셈블리 쓰기 싫으니까. C 컴파일러면 이제 둠 가능함
A. 이론상으로는 RISC-V 컴파일러 쓸 수 있음. 근데 현실적으로는 아직 안 되는게 RAM 바이트 단위 접근이라든가 몇몇 핵심 명령어가 빠져 있음. 그래서 진짜 RISC-V 호환되는 새 버전 만들 생각이고 그땐 컴파일러 활용이 가능함
이번 프로젝트에서는 CPU부터 코드까지 전부 내 손으로 쓰는 게 목표였음. 외부 컴파일러 안 쓰고 팩토리오에 맞게 CPU 설계 자유도도 챙겼고
Q. 이거 게임 안에서 직접 지은 거임? 아니면 다른 툴 써서 프로그래밍한 거임?
A. 좋은 질문이네. 메인 구조는 에디터를 사용하긴 했지만 전부 팩토리오 안에서 만듦
근데 RAM / ROM 주소 300개 넘게 수동으로 설정하는 건 사람 할 짓이 아니라 조합기 블루프린트 만든 다음 그걸 파이썬으로 열어서 주소 반복 처리함. 블루프린트 문자열은 압축된 JSON이라 수정하기도 쉬움
Q. 처음에 이거 얼마나 걸릴 거라 예상했고 실제로는 얼마나 걸림?
A. 2024년 11월 시작, 그 전에 한 달 정도 먼저 비파이프라인 CPU를 만들었고, 그 다음 2~3개월 동안 개선하다 좀 쉬고 2025년 10~11월에 프로그래밍 전부 함
어셈블리는 빨리 끝날 줄 알았는데 OS랑 파일시스템 구현이 CPU 만드는 거랑 비슷하게 오래 걸림 :D 근데 이미 컨퍼런스에 발표 설명 올려놔서 도망 못 갔음ㅋㅋ
Q. 자폐 진단 받음?
난 괜찮아 ;)
Q. 어셈블리… 롤러코스터 타이쿤 이식하려면 점프 명령 몇 개 필요함?
A. :D 그 사람은 진짜 괴물임. 근데 RISC-V 쓴건 아니라서… 뭐ㅋㅋ
Q. 프로그램을 로드하고 실행하는 컴퓨터라는 게 진짜 인상적임. 지금까지 본 건 전부 하드코딩이었는데 로더 있는 건 차원이 다름
근데 클럭 700Hz는 어떻게 냄? UPS 60이 최대 아니었음?
A. 고마워! 맞아, 사용자랑 상호작용되는 게 진짜 컴퓨터처럼 만드는 핵심임
클럭은 일반 게임 속도는 60 UPS가 맞는데 맵 에디터에선 최대 64배속이 가능함. 그래서 약 3700 UPS까지 나오고 5틱장 1클럭이니 초당 700명령어 정도 나옴
GIF도 배속 아니고 실시간 조작 가능함. (물론 회로가 커지면 64배속 못 버팀)
Q. 언제 둠 돌림?
A. 네가 코드 짜면 ;)
Q. 젠장.
Q. 전부 어셈블리로 작성했다고? 롤코타는 언제?
A. 그 게임이 어셈블리인 게 아직도 안 믿겨
근데 하드웨어가 너무 느림. 초당 700명령어로는 도저히 무리
Q. 난 존나 멍청해서 이게 뭔지 이해가 안 됨. 게임 요소만으로 돌아가는 거임? 이게 어떻게 가능한 건데?
A. ㅇㅇ조합기만 씀. 조합기는 논리 신호 제어하는 블록임. 이걸 복잡하게 엮으면 컴퓨터가 됨
네 컴퓨터도 원리는 비슷함, 차이점은 핵심 부품 이름이 트랜지스터라는 거
쓴 모드는 키보드용 버튼 모드랑 램프 그래픽 개선 모드뿐이고 CPU 구조를 더 보고 싶으면 영상도 있어
Q. 둠 되냐?
A. 네가 짜면 ;)
Q. 하고는 싶은데 어셈은 잘 몰라서 고민되네
Q. 질문은 없고, 함부르크에서 발표 들었는데 진짜 좋았다고
A. 와줘서 진짜 고마워! 이 주제로 사람 얼마나 올지 몰랐는데 현장에서 그렇게 많이 들어줘서 나도 감동받았음
Q. 대단하네. 내가 이걸 한다면 verilog -> 블루프린트 컴파일러를 써서 최소한의 RISC-V 코어를 만들고 써서 C로 코딩했을 듯
A. 그 방법도 맞음, 근데 이번 프로젝트 목표는 전부 혼자서 컴퓨터를 다시 만드는 거였음
이제 한 번 해봤으니 다음엔 100% RISC-V 호환 버전 만들고 컴파일러 쓰는 쪽으로 갈 생각임
Q. 현실에서 CPU 만드는 거나 게임 안에서 만드는 거나 둘 다 이해 안 됨 ㅋㅋ 거기다 지뢰찾기 코딩까지? 미친 거 아니냐
A. 파일시스템 코딩이 제일 오래 걸렸음. 어셈블리는 진짜 느림 (적어도 나한테는)
Q. 대충 명령어 하나에 몇 틱 걸림? 파이프라인이면 파이프라인 레지스터 클럭은 얼마고 버블 생기는 명령어 있음?
A. 좋은 질문이야
CPU는 5단 파이프라인이고 각 단계가 5틱 필요함. 버블이 없다고 치면 5틱마다 명령어 하나 처리되니, 즉 클럭은 5틱, 명령어 하나가 CPU 전체 통과하려면 25틱 필요
점프/분기는 실행 단계(3단계)에서 처리됨, 그래서 앞에 있던 2개 명령어가 플러시되니 점프 하나당 버블 2개
또 하나는 메모리 의존성
t0 = RAM[t1]
t2 = t0 + 1
이 경우 t0 값은 MEM 단계(4단계)에서 나오는데 다음 명령은 실행 단계(3단계)에서 이미 그 값이 필요함
시간여행을 하는 법은 아직 몰라서 두 번째 명령은 1클럭 대기
그래서 이거 알고 나서는 어셈 코드 짤 때 의존성 생기는 명령 사이에 다른 유용한 명령 하나 끼워 넣는 식으로 신경을 썼음. 그러면 일반 포워딩으로 충분해서 버블 없이 돌아감
Q. 여자 손은 잡아봤음?
A. 아내가 항상 내가 하는 걸 응원해 줌 :)
Q. (독일어 댓글)
너 그냥 할 짓 없었던 거 아냐? :D 유튜브에서 발표 다 봤는데 진짜 인상적이었음
나는 밸런서는 그럭저럭 만드는데 직업이 법 쪽이라 컴공은 아님 ㅋㅋ
어쨌든 리스펙
A. ㅋㅋ 컨그레스 전에 마감 맞추느라 진짜 땀 존나 뺐음
파일시스템이 생각보다 훨씬 오래 걸렸고 그리고 일반 팩토리오는 나도 잘 못함…
Q. verilog -> 블루프린트 컴파일러 써서 RISC-V 코어 박아라
A. 그런 툴이 있는 거는 앎. 이번 프로젝트는 "남이 만든 거 안 쓰기"(팩토리오랑 파이썬 제외) 룰이었는데 다음 버전에서는 도구 좀 써도 될 듯
Q. 키보드는 왜 qwerty가 아니라 qwertz임?
A. 독일 표준 키보드야. 프로젝트에 개인 취향 좀 넣고 싶어서 일부러 그렇게 함
Q. CPU만 만든 게 아니라 CLI랑 지뢰찾기까지? 뭐하는 놈이냐 진짜
A. 사실 그게 제일 재밌었음. 이 CPU로 뭔가 '쓸모 있는' 걸 만든 거거든. 간신히 그 경계에 있긴 하지만
Q. 이거 놓친 거 존나 아깝다 다음 CCC는 무조건 가야겠음 팩토리오 말고도 발표들 다 좋더라
A. ㄹㅇ 좋았음 강추함. 그리고 발표하면 티켓 공짜고 줄도 안 서도 됨
이제 다음 컨그레스에서 뭐 발표할지 생각해 봐라 ;)
Q. 이거 크래시 나면 어케 됨? 크래시가 날 수는 있나?
A. 허용되지 않은 명령이 실행되면 인터럽트 핸들러로 CPU가 종료됨. 메모리 제한도 넣고 싶었는데 시간 부족
그 외엔 크래시 개념 없음 그냥 계속 돌아감
Q. 어제 체험판 처음 해보고 서브레딧 들어왔는데 첫 글이 이거네
팩토리오에 어떻게 빠지게 됐고 비슷한 게임 추천 있음?
A. 마크 하다가 알게 됐던 것 같음. 단순한 걸 차곡차곡 쌓아서 복잡한 게 되는 구조가 내 취향에 딱임. CPU도 조합기 -> 명령어 -> 프로그램 구조라 똑같아
다른 게임으로는 굶지마(Don't starve) 추천 탐험 위주고 좀 어둡긴 한데 비슷한 매력이 있음
Q. 와 이거 진짜 겁나 멋있다. 난 나름 머리 괜찮다고 생각하고 살았는데 너네 같은 테크노맨서들은 대체 어디서 이런 숨겨진 지식들을 주워오는 거냐? 책에서 읽었다고 하는데 JSON 까보는 법도 알고 어셈으로 OS 짜는 것도 알고 어디서 이런 랜덤한 지식이 계속 튀어나오는 거임?
베리타시움에서 레이저로 녹은 주석 물방울 쏴서 광식각 한다는 영상 봤을 때도 "아 들으니까 알겠는데 저걸 어떻게 다 알아낸 거지?" 싶었음. 회로 배치가 도시 계획 수준이잖아. 영수증 프린터로 게임용 PC 만든 영상도 봤고. 개념은 이해하는데 필요한 지식이 너무 많아서 내가 뭔가 존나 당연한 걸 못 보고 바위 밑에서 살았던 기분 든다.
A. 고마워!
밖에서 보면 네가 말한 것처럼 딱 그렇게 보일 거라고 생각함. 근데 내 입장에서는 이게 전부 작은 단계들이 쌓인 결과임.
일단 어떤 프로젝트든 잘하려면 그냥 직접 해보는 수밖에 없음. 아주 간단한 거부터 시작해도 되는데, 무엇보다 중요한 건 자기가 진짜 흥미 있는 걸로 시작하는 거임. 나 같은 경우엔 10대 때 자바로 처음 프로그래밍 배웠고 그 다음에 수학이랑 컴공 전공하면서 알고리즘, 자료구조 같은 기본기랑 저수준 아키텍처 쪽도 배움(이게 취향이었음). 그러다 마인크래프트 레드스톤 서버 Open Redstone Engineers에서 몇 년 동안 미친 짓 하는 사람들 구경함. 거기서 “아 CPU도 만들 수 있겠네?” 하고 영감 받음. 그게 또 다음 단계로 이어지고… 그런 식임
JSON 관련도 별거 없음. 가끔은 그냥 남 코드 복붙해서 뜯어보고 고쳐 쓰는 거임. 처음에 도쉬도슁턴이 만든 조합기 튜토리얼 보다가 JSON 언패킹 코드 공유한 거 보고 그걸 내 프로젝트에 맞게 수정했음
어셈블리도 마찬가지임. 처음엔 CPU에서 돌아가는 아주 단순한 데모 프로그램부터 짰고, 그 다음에 “이것도 해볼까?” 하면서 점점 더 복잡한 코드로 넘어감. 중요한 건 처음부터 잘하려고 하지 말고 처음에 만든 게 완벽하지 않아도 그냥 받아들이는 거임. 그 과정이 없으면 아무것도 안 늘음.
Q. 어제 영상 봤다. 재밌으면서도 존나 힘들었을 듯; 리스펙
A. 버그 때문에 진짜 열받은 적 많았어. 예를 들면 ROM에서는 잘 도는 코드가 RAM에 넣으면 갑자기 맛이 감. 알고 보니까 RAM 어딘가에서 선 하나 빠져 있어서 전체가 이상해짐ㅋㅋ
파이프라인 맞추는 것도 시행착오가 엄청 많이 필요했음 :D
Q. 총 몇 시간 걸림?
A. 인게임 약 200시간, 어셈블리 + 어셈블러 짜는 데도 거의 비슷한 시간. 그리고 그 인게임 시간에는 이전 단계로 만들었던 더 단순한 CPU 실험들도 포함됨.
Q. 마지막으로 밖에 나가본 게 언제야?
A. 잘 모르겠네. 잔디가 분홍색이었던 것까지는 기억 나는데.
Q. 5-stage면 MIPS 구조임?
A. ㅇㅇ 교과서에 나오는 표준 파이프라인 구조임. Computer Architecture: A Quantitative Approach 부록 A 따라갔고 포워딩 로직도 거기서 배움
Q. 내년 AdventOfCode 나갈 생각 있음?
A. 올해 이미 해봄 팩토리오 CPU만 써서 별 4개 땄음
근데 AOC 입력이 64비트 정수라 64비트 연산 에뮬하기 싫어서 초반 문제들은 많이 못 풀었음. 그리고 파이썬으로 10~15분 걸릴 문제 하나가 어셈으로는 1~1.5시간 걸리니까 몇 문제 하다가 지치더라
Q. 팩토리오에서 회로 단계 하나마다 업데이트 1틱씩 먹는 거 어떻게 처리함?
현실 회로도 이런 제약이 있어? 난 이게 제일 어려웠음. 동시에 일어나야 할 게 동시에 일어나게 만드는 게 존나 힘듦.
A. ㅇㅇ 그게 제약 맞음. 그래서 파이프라인 5개를 전부 5게임틱 깊이 안에 우겨 넣는 게 핵심 과제였음.
Q. 언제 시작해서 언제 끝냄? 풀타임으로 함?
그리고 Doom in Factorio랑 뭐가 다름? 이건 튜링 완전한 CPU고 둠 팩토리오는 전용 컴퓨터인가?
Turing Complete 게임 해봄?
A. 2024년 11월 시작 2025년 여름에 잠깐 쉬고 11월에 발표 준비로 몰아서 함. 총합 팩토리오 200시간 어셈 200시간쯤
완벽하게 튜링 완전함. 둠 팩토리오 쪽은 잘 모름.
Turing Complete는 봤는데 직접 하진 않음. 완성도 높아지면 해볼 듯.
Q. 왜 게임에 시간 낭비함? 머리로 돈 벌 수 있을 텐데
A. 지금은 돈보다 재미가 더 중요함. 생활이 안정돼 있으니까. 평범한 직장 있고 다른 취미도 많음. 그냥 독일에서 평화롭고 정보 접근 가능한 환경에 있다는 점이 큼.
Q. (다른 사람)반도체 업계에서 일하는데 이런 거 그냥 재밌어서 하는 거임. 팩토리오, TIS-100 같은 거에 인생 갈아 넣는 사람 많음.
Q. 이거 이력서에 쓸 거임?
A. 이미 썼어ㅋㅋ
Q. 팩토리오 조합기에 더 잘 맞는 CPU 구조 생각해본 적 있음?
A. 파이프라인 없는 CPU는 충분히 가능함. RISC-V 참고했지만 팩토리오에 맞게 ISA 직접 만들어도 됨.
Q. 확장 뭐 있음? RV32F 붙일 수 있음?
A. 완전한 확장은 없음. RAM 바이트 접근 없고 논리 시프트 없는데(조합기는 산술 시프트만 있음) 곱셈/나눗셈은 있고 상위 32비트 곱셈만 없음.
다음 CPU에서는 RISC-V 베이스 + M 확장 완전 구현하고 싶은데 지금은 좀 쉬어야 함 ㅋㅋ
Q. 대단하네… 몇 개만 물어봐도 됨?
해저드는 어떻게 처리함? 클럭 사이클 조절함? 버블 넣음? 오퍼랜드 포워딩 씀?
그리고 왜 RISC-V임? 나중에 프로그래밍 편하려고 그런 거임?
내 생각엔 CPU 만드는 이유는 내 마음대로 명령어 집합 만들 수 있다는 자유도 포함이라고 보는데, 조합기에 더 잘 맞는 명령어들도 분명 있잖아. 예를 들면 덧셈은 0틱으로도 가능하고.
참고로 나도 작은 CPU 하나 만들었음. 자체 ISA 쓰고, 클럭당 1명령 이상 실행되고, 아주 기초적인 수준이긴 한데 추측 실행도 있음 (명령어 미리 디코딩해서 점프 1틱 처리 가능).
imgur.comDiscover the magic of the internet at Imgur, a community powered entertainment destination. Lift your spirits with funny jokes, trending memes, entertaining gifs, inspiring stories, viral videos, and so much more from users.imgur.com단점은 파이프라인이 아주 위험함. 그래서 지금 컴파일러 만드는 중임. ISA가 너무 괴랄해서 수동으로는 프로그래밍이 너무 힘듦.
A. 해저드는 거의 전부 포워딩으로 해결함. 딱 하나 예외가 있는데, 메모리 의존성임. 이건 어쩔 수 없어서 버블 하나 넣고 파이프라인 1사이클 스톨함. 점프의 경우엔 점프가 실제로 걸리면 파이프라인 플러시해야 해서 거기서 2사이클 손해 봄.
RISC-V를 고른 이유는 오픈소스 ISA라는 점이 마음에 들었고, 단순한데 개념적으로 되게 잘 만들어졌고, 왜 이런 명령어들이 있는지 이미 다 고민돼 있고, 문서도 잘 돼 있음
물론 완전한 RISC-V는 아님. 나는 모든 확장 신경 쓸 필요 없어서 opcode도 다르고 EXP 같은 명령어도 추가했음 (이건 산술 조합기로 구현 가능하니까)
내 ISA를 만드는 게 유리하지 않냐는 거에 동의함. 위에서 말했듯이 Factorio에 더 잘 맞게 많이 뜯어고쳤음. 나중에 목표는 RISC-V 표준을 완전히 만족하는 CPU 하나 더 만드는 거, 그러면 RISC 컴파일러 그대로 사용 가능해짐 (C로 코딩 > 어셈블리로 코딩)
네 CPU 설계도도 멋있더라. 클럭 속도 빠른 게 진짜 흥미롭네. 컴파일러 작업도 화이팅!
Q. 이거 만들면서 쉬울 줄 알았는데 생각보다 훨씬 어려웠던 부분 있음?
A. 어셈블러로 파일 시스템 프로그래밍하는 게 훨씬 쉬울 줄 알았는데 오래 걸렸음.
CPU 쪽은 크게 놀랄 건 없었음. 포워딩이랑 파이프라인 제어가 어려울 거라는 건 알고 시작했고 실제로도 존나 빡셌음 :D
Q. 근데 이런 건 도대체 어떻게 시작하는 거임…?
A. 대충 이런 순서임:
1. 논리 게이트 이해
2. 이진수 이해
3. 개별 부품 이해: ALU, 레지스터, RAM
4. CPU가 전반적으로 어떻게 도는지 이해, (안 했으면) 프로그래밍 언어 하나 배우기 나는 파이썬 씀
5. 아주 단순한 명령어 집합 생각해보기
6. 부품 조합해서 단순 CPU 하나 만들어보기
7. RISC-V 읽어보기
8. 파이프라이닝에 대해 존나 많이 읽기
9. 파이프라인 CPU 만들기
10. 주변 기기 만들기
11. 어셈블러 만들기
12. CPU용 프로그램 짜기
근데 이게 이렇게 깔끔한 루트는 아님. 그냥 새로운 거 배우는 거랑 새 프로젝트 파는 거 자체를 즐겨야 함.
그리고 중간 어딘가에서 마인크래프트 하고 레드스톤 좀 만져보는 걸 추천하고 :D
번역 후기
뭐 번역은 여기서 끝이다. 원본도 50분짜리 영상인데다 qna까지 번역하는거라 대충 대여섯시간정도 들건 각오했는데 그 두배가 걸려버렸다.
세 개 합쳐서 한글로 31,500자정도 되니 그 글레바 부패측정회로(18,000자 가량) 글의 거의 두 배 정도 된다.
그래도 내가 잘 모르는 분야인지라 공부하면서 하는 느낌이어서 지루하지는 않았던 것 같음
그리고 글 자체도 참 좋다. 차근차근 따라가면 그렇게 어렵지도 않은데다 완전히 이해하면 컴퓨터가 어떻게 작동하는지 대충 직관정도는 얻어갈 수 있으리라 생각되고...
예전에 갤에 올라온 글 중에 CPU 설계 글이 있었는데, 번역하다가 다시 읽어보니 확실히 그때보다는 훨씬 많이 보인다. 그것도 추천함.
지금 ^책한권만읽은놈^ 상태라 어셈블리어가 좀 만만해 보이고? 나도 CPU설계 해볼만 한거같고? 하는 그런 부작용이 있긴 하다.
아래는 내가 번역하면서 참고한 글들이랑 떠올린 질문(이랑 제미나이 답변)들 모음인데, 팩토리오랑은 별 관련 없으니 안 읽고 넘겨도 됨
39C3
https://news.hada.io/topic?id=25535
CPU 작동 방식과 어셈블리어
https://m.blog.naver.com/leeneer/222067722452
https://www.youtube.com/watch?v=16zrEPOsIcI
엔디안
https://en.wikipedia.org/wiki/Endianness
https://code-lab1.tistory.com/179
https://softtone-someday.tistory.com/20
RISC-V
https://danielmangum.com/posts/risc-v-bytes-intro-instruction-formats/
https://en.wikipedia.org/wiki/RISC-V
https://en.wikipedia.org/wiki/Opcode
Q. CPU가 ISA를 따라 명령어를 ALU로 보내는 건 이해했는데, 이 ALU라는게 물리적인 구조니 곱셈만 할 수 있는 부분, 덧셈만 할 수 있는 부분만 있을 텐데, 한 클럭 사이클당 하나의 연산만 시행 가능하면 너무 비효율적이지 않나? RISC-V는 수백 가지의 명령 이 있다고 하는데 그 중 하나를 실행하는 중이면 나머지 부분은 그냥 놀고 있나?
A. 질문하신 내용은 컴퓨터 공학의 역사에서 '어떻게 하면 이 비싼 트랜지스터들을 한순간도 놀리지 않고 굴릴 것인가?'라는 고민의 핵심을 찌르고 있습니다.
결론부터 말씀드리면, 초기 CPU는 말씀하신 대로 한 번에 하나만 처리하느라 나머지는 놀고 있었지만, 현대의 CPU는 세 가지 마법을 부려 이 문제를 해결했습니다.
1. 파이프라이닝 (Pipelining):
명령어 하나를 실행하려면 보통 *가져오기(Fetch) → 해석(Decode) → 실행(Execute) → 저장(Write)의 단계를 거칩니다.
옛날 방식: 1번 명령어가 '저장'까지 끝날 때까지 2번 명령어는 입구에서 기다립니다. 이때 실행 유닛(ALU)은 '가져오기'와 '해석' 단계 동안 아무것도 안 하고 놀게 됩니다.
현대 방식: 1번 명령어가 '해석' 단계로 넘어가면, '가져오기' 장치는 즉시 2번 명령어를 가져옵니다. 1번이 '실행(ALU)' 중일 때, 2번은 '해석' 중이고, 3번은 '가져오기' 중입니다.
이렇게 하면 ALU는 매 클럭 사이클마다 새로운 일을 끊임없이 받아서 처리하게 됩니다.
2. 슈퍼스칼라 (Superscalar):
"덧셈기랑 곱셈기가 따로 있는데, 덧셈할 때 곱셈기는 노는 거 아냐?"라는 의문이 드실 겁니다. 그래서 현대 CPU는 디코더를 여러 개 둡니다.
다중 발행(Multiple Issue): 디코더가 한 번에 명령어를 4~8개씩 읽어 들입니다.
만약 읽어온 명령어 중에 "덧셈"과 "곱셈"이 섞여 있다면, 디코더는 이를 동시에 각기 다른 유닛(ALU와 곱셈기)으로 쏴줍니다.
즉, 한 클럭 사이클에 덧셈과 곱셈이 동시에 일어납니다. 이를 '슈퍼스칼라' 구조라고 부릅니다.
3. 비순차 실행 (Out-of-Order Execution):
가장 똑똑한 기술입니다. 가끔 명령어가 앞의 계산 결과가 나올 때까지 기다려야 해서 멈추는 경우가 생깁니다(의존성).
이때 뒤에 상관없는 명령이 있다면, CPU는 순서를 바꿔서 그 명령을 먼저 실행 유닛에 집어넣습니다.
"노는 유닛이 생기지 않도록, 줄 서 있는 명령어 중 지금 당장 할 수 있는 걸 먼저 처리해버리는 것"입니다.
4. RISC-V의 수백 가지 명령이 다 물리적 장치인가?
그렇지는 않습니다. 수백 가지 명령어라고 해도 물리적인 핵심 유닛은 몇 가지로 압축됩니다.
기본 ALU: 덧셈, 뺄셈, AND, OR 같은 논리 연산을 처리합니다. (뺄셈은 2의 보수를 사용해 덧셈기를 쓰고, 비교연산도 뺄셈기를 활용합니다.)
시프터(Shifter): 비트를 옆으로 미는 연산을 전담합니다.
곱셈/나눗셈 유닛: 덩치가 커서 보통 별도로 존재합니다.
즉, 수백 개의 명령어가 수백 개의 기계인 게 아니라, 몇 개의 다목적 기계가 '모드'를 바꿔가며 작동하는 식입니다. 예를 들어 RISC-V의 ADDI(숫자 더하기)와 SUB(빼기)는 결국 똑같은 '덧셈기' 하드웨어를 공유해서 사용합니다.
Q. Cpu 코어의 핵심 부분이 alu가 빠르게 연산하게 하는 거라면 왜 트랜지스터가 수백억개씩 들어가야 하는 거지? 64비트 이진수들 간의 덧셈이나 곱셈이라 해 봐야 트랜지스터 수십만 개 정도 같던데. 빛의 속도 제한이 있으니 작아지는 건 이해가 가는데, 많아져야 하는 이유는?
A. 질문하신 내용은 현대 반도체 공학의 가장 핵심적인 역설을 짚고 계십니다.
64비트 덧셈기(Adder) 하나를 만드는 데는 트랜지스터가 대략 2,000~3,000개 정도면 충분하고, 아주 복잡한 곱셈기조차 수만 개 수준에서 끝납니다. 그런데 왜 최신 CPU에는 100억 개가 넘는 트랜지스터가 들어갈까요?
결론부터 말씀드리면, CPU는 이제 '계산기'라기보다 '거대한 데이터 물류 센터'가 되었기 때문입니다.
트랜지스터를 잡아먹는 장치들을 비중 순서대로 소개해 드립니다.
1. 최대 지분 점유자: 캐시 메모리
CPU 트랜지스터의 약 60~80%는 계산을 하지 않습니다. 오직 데이터를 '기억'하는 데 쓰입니다. ALU는 초당 수십억 번 계산할 준비가 되어 있는데, RAM에서 데이터를 가져오는 속도는 그보다 수백 배 느립니다. ALU가 놀지 않게 하려면 데이터를 코어 바로 옆에 쌓아둬야 합니다.
트랜지스터 소모량: 우리가 흔히 말하는 L2, L3 캐시는 SRAM이라는 소자로 만듭니다. 이 SRAM은 1비트(0 또는 1)를 저장하는 데 트랜지스터 6개가 필요합니다. 32MB 용량의 캐시 메모리 하나만 해도 15억 개 이상의 트랜지스터가 들어갑니다.
2. 관리 로직 (Control Logic)
질문자님이 이전에 언급하신 '나머지 부분은 놀고 있나?'라는 문제를 해결하기 위해 들어가는 장치들입니다.
분기 예측기 (Branch Predictor): 다음에 실행할 명령어가 무엇일지 미리 '때려 맞추는' 일종의 인공지능 회로입니다. 수만 개의 과거 기록을 저장하고 분석해야 하므로 엄청난 트랜지스터를 사용합니다.
비순차 실행 (Out-of-Order Execution): 명령어의 순서를 재배치하기 위해 수백 개의 명령어를 임시로 담아두는 창고(ROB, Reservation Station)와 이들의 우선순위를 정하는 복잡한 스케줄러가 필요합니다.
이 '관리직'들이 차지하는 비중이 실제 '현장직(ALU)'보다 훨씬 큽니다.
3. 멀티코어 (Multi-core)
질문에서 "왜 많아져야 하는지"에 대한 답 중 하나입니다. 빛의 속도 제한 때문에 단일 코어의 속도(클럭)를 높이는 데 한계가 오자, 엔지니어들은 "그냥 코어를 여러 개 박자"는 전략을 선택했습니다.
코어가 8개, 16개로 늘어나면 ALU뿐만 아니라 그 코어를 보조하는 모든 관리 회로와 캐시가 통째로 복사되어 들어갑니다. 트랜지스터 수가 배수로 뻥튀기되는 지점입니다.
4. 특화된 '전문가'들 (Specialized Units)
현대 CPU는 단순히 범용 연산만 하지 않습니다.
벡터 연산 유닛 (SIMD): 영상 편집이나 AI 연산을 위해 한 번에 512비트씩 계산하는 거대한 연산 장치들이 들어갑니다.
내장 그래픽 (GPU): 요즘 CPU(SoC) 안에는 화면을 그려주는 GPU가 포함되는데, GPU는 그 자체로 수천 개의 작은 ALU 덩어리라 엄청난 트랜지스터를 소모합니다.
보안 및 I/O: 데이터를 암호화하거나 외부 기기(USB, PCIe)와 통신하기 위한 전용 컨트롤러들이 수억 개씩 트랜지스터를 가져갑니다.
Q. I/O는 뭐길래 수억 개씩이나 들어가는지?
A. CPU 내부의 계산 속도는 초당 수십억 번(GHz)인데, 외부 장치들은 그보다 훨씬 느리고 전기적 신호도 불안정합니다. 이 격차를 메우기 위해 수억 개의 트랜지스터가 동원됩니다. 구체적으로 어디에 쓰이는지 살펴보겠습니다.
1. 메모리 컨트롤러 (The Memory Bridge)
CPU가 아무리 빨라도 데이터를 가져올 RAM(메모리)과의 통신이 끊기면 무용지물입니다.
복잡한 프로토콜: DDR5 같은 현대 메모리는 단순히 전기를 주고받는 게 아니라, 매우 복잡한 '대화 규칙'이 있습니다. 데이터를 언제 보낼지, 오류는 없는지, 전압은 적당한지를 실시간으로 관리하는 메모리 컨트롤러가 CPU 안에 들어있는데, 이 장치 자체가 웬만한 옛날 CPU보다 더 복잡한 회로를 가집니다.
데이터 정렬: 메모리에서 한 번에 64비트, 128비트씩 쏟아지는 데이터를 CPU 내부의 전선(Bus) 규격에 맞게 정렬하고 분배하는 데 엄청난 로직 게이트가 필요합니다.
2. SERDES: 고속 고속도로의 입출구
현대 I/O의 핵심 기술(Serializer/Deserializer)에 엄청난 트랜지스터가 들어갑니다.
병렬 -> 직렬 변환: CPU 내부에서는 데이터가 수백 개의 차선(병렬)으로 움직이지만, 외부(PCIe, USB 등)로 나갈 때는 선 개수를 줄이기 위해 아주 좁은 차선(직렬)으로 몰아서 보내야 합니다.
초고속 통신: PCIe 5.0/6.0 같은 규격은 초당 수십 기가비트(Gbps)를 전송합니다. 이 속도에서 신호가 뭉개지지 않게 전기 신호를 증폭하고, 노이즈를 제거하고, 타이밍을 1조 분의 1초 단위로 맞추는 아날로그-디지털 혼합 회로가 필요합니다. 이 정밀한 작업을 위해 수천만 개의 트랜지스터가 투입됩니다.
3. SoC(System on Chip)화:
요즘 나오는 CPU는 순수 계산기라기보다 컴퓨터 한 대를 칩 하나에 다 때려 넣은 형태(SoC)에 가깝습니다.
내장 컨트롤러: 예전에는 메인보드에 따로 있던 칩셋(Northbridge, Southbridge) 기능이 CPU 안으로 다 들어왔습니다.
USB 컨트롤러: USB 장치들을 인식하고 관리함.
NVMe 컨트롤러: SSD와 초고속으로 데이터를 주고받음.
디스플레이 엔진: 모니터에 화면 신호를 뿌려줌.
보안 프로세서: 해킹을 방지하기 위해 데이터를 암호화해서 내보내는 전용 보안 칩도 I/O 영역의 일부로 포함됩니다.
결국 "계산은 순식간인데, 그 데이터를 칩 밖으로 안전하고 빠르게 나르는 일이 훨씬 더 어렵고 복잡하기 때문"에 I/O에 수억 개의 트랜지스터가 들어가는 것입니다.
팩토리오로 98x3d 만들어주세요
이 댓글은 게시물 작성자가 삭제하였습니다.
크아악
음음 완벽히 이해했어
UPS 어케했는지 궁금했었는데 Q&A에 있네
시발 이거보고 구매욕 사라짐
이 댓글은 게시물 작성자가 삭제하였습니다.
정량적 접근 ㅅㅂ 대학원 교재를 쓰라뇨